Add icu 4.6.1 to deps.
diff --git a/APIChangeReport.html b/APIChangeReport.html
new file mode 100644
index 0000000..81baf40
--- /dev/null
+++ b/APIChangeReport.html
@@ -0,0 +1,2937 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html><!--
+	 Copyright (C)  2010, International Business Machines Corporation, All Rights Reserved. 
+	-->
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>ICU4C API Comparison: 4.4.2 with 4.6 r29058</title>
+<link type="text/css" href="icu4c.css" rel="stylesheet">
+</head>
+<body>
+<a name="#_top"></a>
+<h1>ICU4C API Comparison: 4.4.2 with 4.6 (r29058)</h1>
+<div id="toc">
+<ul>
+<li>
+<a href="#removed">Removed from 4.4.2</a>
+</li>
+<li>
+<a href="#deprecated">Deprecated or Obsoleted in 4.6</a>
+</li>
+<li>
+<a href="#changed">Changed in  4.6</a>
+</li>
+<li>
+<a href="#promoted">Promoted to stable in 4.6</a>
+</li>
+<li>
+<a href="#added">Added in 4.6</a>
+</li>
+<li>
+<a href="#other">Other existing drafts in 4.6</a>
+</li>
+</ul>
+<hr>
+</div>
+<a name="removed"></a>
+<h2>Removed from 4.4.2</h2>
+<table BORDER="1" class="genTable">
+<THEAD>
+<tr>
+<th>File</th><th>API</th><th>4.4.2</th><th>4.6</th>
+</tr>
+</THEAD>
+<tr class="row1">
+<td class="file">dcfmtsym.h</td><td class="proto">void DecimalFormatSymbols::setSymbol(ENumberFormatSymbol, const UnicodeString&amp;)</td><td class="stabchange">Stable<br>2.0</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">format.h</td><td class="proto">UClassID Format::getDynamicClassID() const =0</td><td class="stabchange">Stable<br>2.0</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">fpositer.h</td><td class="proto">UClassID FieldPositionIterator::getDynamicClassID() const</td><td class="">Draft<br>4.4</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">fpositer.h</td><td class="proto"><tt>static</tt> UClassID FieldPositionIterator::getStaticClassID()</td><td class="">Draft<br>4.4</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">LESwaps.h</td><td class="proto"><tt>static</tt> le_uint16 LESwaps::swapWord(const le_uint16&amp;)</td><td class="stabchange">Stable<br>2.8</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">LESwaps.h</td><td class="proto"><tt>static</tt> le_uint32 LESwaps::swapLong(const le_uint32&amp;)</td><td class="stabchange">Stable<br>2.8</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">locdspnm.h</td><td class="proto"><tt>static</tt> UClassID LocaleDisplayNames::getStaticClassID()</td><td class="">Internal<br>4.4 // TODO</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">locid.h</td><td class="proto"><tt>static</tt> const char* const* Locale::getISOCountries()</td><td class="stabchange">Stable<br>2.0</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">locid.h</td><td class="proto"><tt>static</tt> const char* const* Locale::getISOLanguages()</td><td class="stabchange">Stable<br>2.0</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">UClassID FilteredNormalizer2::getDynamicClassID() const</td><td class="">Draft<br>4.4</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UClassID Normalizer2::getDynamicClassID() const =0</td><td class="">Draft<br>4.4</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto"><tt>static</tt> UClassID FilteredNormalizer2::getStaticClassID()</td><td class="">Draft<br>4.4</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto"><tt>static</tt> UClassID Normalizer2::getStaticClassID()</td><td class="">Draft<br>4.4</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">RegexMatcher&amp; RegexMatcher::region(int32_t, int32_t, UErrorCode&amp;)</td><td class="stabchange">Stable<br>4.0</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">RegexMatcher&amp; RegexMatcher::reset(int32_t, UErrorCode&amp;)</td><td class="stabchange">Stable<br>2.8</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">UBool RegexMatcher::find(int32_t, UErrorCode&amp;)</td><td class="stabchange">Stable<br>2.4</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">UBool RegexMatcher::lookingAt(int32_t, UErrorCode&amp;)</td><td class="stabchange">Stable<br>2.8</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">UBool RegexMatcher::matches(int32_t, UErrorCode&amp;)</td><td class="stabchange">Stable<br>2.8</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">UText* RegexMatcher::appendTail(UText*)</td><td class="">Internal<br>4.4 technology preview</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">UText* RegexMatcher::getInput(UText*) const</td><td class="">Internal<br>4.4 technology preview</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">UText* RegexMatcher::group(UText*, MatcherDestIsUTextFlag, UErrorCode&amp;) const</td><td class="">Internal<br>4.4 technology preview</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">UText* RegexPattern::patternText() const</td><td class="">Internal<br>4.4 technology preview</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto"><tt>enum</tt> 
+							RegexMatcher::MatcherDestIsUTextFlag {}</td><td class="">Internal<br>.</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto"><tt>enum</tt> 
+							RegexMatcher::MatcherDestIsUTextFlag::MATCHER_DEST_IS_UTEXT</td><td class="">Internal<br>.</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uidna.h</td><td class="proto"><tt>#define</tt> UIDNA_ALLOW_UNASSIGNED</td><td class="stabchange">Stable<br>2.6</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto"><tt>#define</tt> UIDNA_DEFAULT</td><td class="stabchange">Stable<br>2.6</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uidna.h</td><td class="proto"><tt>#define</tt> UIDNA_USE_STD3_RULES</td><td class="stabchange">Stable<br>2.6</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uloc.h</td><td class="proto">const char* const* uloc_getISOCountries()</td><td class="stabchange">Stable<br>2.0</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uloc.h</td><td class="proto">const char* const* uloc_getISOLanguages()</td><td class="stabchange">Stable<br>2.0</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">unifilt.h</td><td class="proto">UClassID UnicodeFilter::getDynamicClassID() const =0</td><td class="stabchange">Stable<br>2.2</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uregex.h</td><td class="proto">UText* uregex_appendTailUText(URegularExpression*, UText*)</td><td class="">Internal<br>4.4 technology preview</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uregex.h</td><td class="proto">UText* uregex_groupUText(URegularExpression*, int32_t, UText*, UErrorCode*)</td><td class="">Internal<br>4.4 technology preview</td><td>None<br>
+<span class=""><span></span></span></td>
+</tr>
+</table>
+<P></P>
+<a href="#_top">(jump back to top)</a>
+<hr>
+<a name="deprecated"></a>
+<h2>Deprecated or Obsoleted in 4.6</h2>
+<table BORDER="1" class="genTable">
+<THEAD>
+<tr>
+<th>File</th><th>API</th><th>4.4.2</th><th>4.6</th>
+</tr>
+</THEAD>
+</table>
+<P></P>
+<a href="#_top">(jump back to top)</a>
+<hr>
+<a name="changed"></a>
+<h2>Changed in  4.6 (old, new)</h2>
+<table BORDER="1" class="genTable">
+<THEAD>
+<tr>
+<th>File</th><th>API</th><th>4.4.2</th><th>4.6</th>
+</tr>
+</THEAD>
+<tr class="row1">
+<td class="file">calendar.h</td><td class="proto">UBool Calendar::isWeekend()const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">calendar.h</td><td class="proto">UBool Calendar::isWeekend(UDate, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">calendar.h</td><td class="proto">UCalendarWeekdayType Calendar::getDayOfWeekType(UCalendarDaysOfWeek, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">calendar.h</td><td class="proto">int32_t Calendar::getWeekendTransition(UCalendarDaysOfWeek, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">datefmt.h</td><td class="proto">UnicodeString&amp; DateFormat::format(Calendar&amp;, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">datefmt.h</td><td class="proto">UnicodeString&amp; DateFormat::format(UDate, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">datefmt.h</td><td class="proto">UnicodeString&amp; DateFormat::format(const Formattable&amp;, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">decimfmt.h</td><td class="proto">UnicodeString&amp; DecimalFormat::format(const StringPiece&amp;, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">decimfmt.h</td><td class="proto">UnicodeString&amp; DecimalFormat::format(double, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">decimfmt.h</td><td class="proto">UnicodeString&amp; DecimalFormat::format(int32_t, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">decimfmt.h</td><td class="proto">UnicodeString&amp; DecimalFormat::format(int64_t, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">dtptngen.h</td><td class="proto">UnicodeString DateTimePatternGenerator::getBestPattern(const UnicodeString&amp;, UDateTimePatternMatchOptions, UErrorCode&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">dtptngen.h</td><td class="proto">UnicodeString DateTimePatternGenerator::replaceFieldTypes(const UnicodeString&amp;, const UnicodeString&amp;, UDateTimePatternMatchOptions, UErrorCode&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">errorcode.h</td><td class="proto">const char* ErrorCode::errorName() const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">errorcode.h</td><td class="proto">void ErrorCode::assertSuccess() const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">fmtable.h</td><td class="proto">Formattable::Formattable(const StringPiece&amp;, UErrorCode&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">fmtable.h</td><td class="proto">StringPiece Formattable::getDecimalNumber(UErrorCode&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">fmtable.h</td><td class="proto">void Formattable::setDecimalNumber(const StringPiece&amp;, UErrorCode&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">format.h</td><td class="proto">UnicodeString&amp; Format::format(const Formattable&amp;, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">fpositer.h</td><td class="proto">FieldPositionIterator::FieldPositionIterator()</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">fpositer.h</td><td class="proto">FieldPositionIterator::FieldPositionIterator(const FieldPositionIterator&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">fpositer.h</td><td class="proto">FieldPositionIterator::~FieldPositionIterator()</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">fpositer.h</td><td class="proto">UBool FieldPositionIterator::next(FieldPosition&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">fpositer.h</td><td class="proto">UBool FieldPositionIterator::operator!=(const FieldPositionIterator&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">fpositer.h</td><td class="proto">UBool FieldPositionIterator::operator==(const FieldPositionIterator&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::bamuScriptCode</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">locdspnm.h</td><td class="proto">LocaleDisplayNames::~LocaleDisplayNames()</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">locdspnm.h</td><td class="proto">UDialectHandling LocaleDisplayNames::getDialectHandling() const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">locdspnm.h</td><td class="proto">UnicodeString&amp; LocaleDisplayNames::keyDisplayName(const char*, UnicodeString&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">locdspnm.h</td><td class="proto">UnicodeString&amp; LocaleDisplayNames::keyValueDisplayName(const char*, const char*, UnicodeString&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">locdspnm.h</td><td class="proto">UnicodeString&amp; LocaleDisplayNames::languageDisplayName(const char*, UnicodeString&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">locdspnm.h</td><td class="proto">UnicodeString&amp; LocaleDisplayNames::localeDisplayName(const Locale&amp;, UnicodeString&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">locdspnm.h</td><td class="proto">UnicodeString&amp; LocaleDisplayNames::localeDisplayName(const char*, UnicodeString&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">locdspnm.h</td><td class="proto">UnicodeString&amp; LocaleDisplayNames::regionDisplayName(const char*, UnicodeString&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">locdspnm.h</td><td class="proto">UnicodeString&amp; LocaleDisplayNames::scriptDisplayName(UScriptCode, UnicodeString&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">locdspnm.h</td><td class="proto">UnicodeString&amp; LocaleDisplayNames::scriptDisplayName(const char*, UnicodeString&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">locdspnm.h</td><td class="proto">UnicodeString&amp; LocaleDisplayNames::variantDisplayName(const char*, UnicodeString&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">locdspnm.h</td><td class="proto">const Locale&amp; LocaleDisplayNames::getLocale() const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">locdspnm.h</td><td class="proto"><tt>static</tt> LocaleDisplayNames* LocaleDisplayNames::createInstance(const Locale&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">locdspnm.h</td><td class="proto"><tt>static</tt> LocaleDisplayNames* LocaleDisplayNames::createInstance(const Locale&amp;, UDialectHandling)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">locid.h</td><td class="proto"><tt>static</tt> const Locale&amp; Locale::getRoot()</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">FilteredNormalizer2::FilteredNormalizer2(const Normalizer2&amp;, const UnicodeSet&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UBool FilteredNormalizer2::hasBoundaryAfter(UChar32) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">UBool FilteredNormalizer2::hasBoundaryBefore(UChar32) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UBool FilteredNormalizer2::isInert(UChar32) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">UBool FilteredNormalizer2::isNormalized(const UnicodeString&amp;, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UBool Normalizer2::hasBoundaryAfter(UChar32) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">UBool Normalizer2::hasBoundaryBefore(UChar32) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UBool Normalizer2::isInert(UChar32) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">UBool Normalizer2::isNormalized(const UnicodeString&amp;, UErrorCode&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UNormalizationCheckResult FilteredNormalizer2::quickCheck(const UnicodeString&amp;, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">UNormalizationCheckResult Normalizer2::quickCheck(const UnicodeString&amp;, UErrorCode&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UnicodeString Normalizer2::normalize(const UnicodeString&amp;, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">UnicodeString&amp; FilteredNormalizer2::append(UnicodeString&amp;, const UnicodeString&amp;, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UnicodeString&amp; FilteredNormalizer2::normalize(const UnicodeString&amp;, UnicodeString&amp;, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">UnicodeString&amp; FilteredNormalizer2::normalizeSecondAndAppend(UnicodeString&amp;, const UnicodeString&amp;, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UnicodeString&amp; Normalizer2::append(UnicodeString&amp;, const UnicodeString&amp;, UErrorCode&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">UnicodeString&amp; Normalizer2::normalize(const UnicodeString&amp;, UnicodeString&amp;, UErrorCode&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UnicodeString&amp; Normalizer2::normalizeSecondAndAppend(UnicodeString&amp;, const UnicodeString&amp;, UErrorCode&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">int32_t FilteredNormalizer2::spanQuickCheckYes(const UnicodeString&amp;, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">int32_t Normalizer2::spanQuickCheckYes(const UnicodeString&amp;, UErrorCode&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto"><tt>static</tt> const Normalizer2* Normalizer2::getInstance(const char*, const char*, UNormalization2Mode, UErrorCode&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">numfmt.h</td><td class="proto">UnicodeString&amp; NumberFormat::format(const Formattable&amp;, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">numfmt.h</td><td class="proto">UnicodeString&amp; NumberFormat::format(const StringPiece&amp;, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">numfmt.h</td><td class="proto">UnicodeString&amp; NumberFormat::format(double, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">numfmt.h</td><td class="proto">UnicodeString&amp; NumberFormat::format(int32_t, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">numfmt.h</td><td class="proto">UnicodeString&amp; NumberFormat::format(int64_t, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">platform.h</td><td class="proto"><tt>#define</tt> UCLN_NO_AUTO_CLEANUP</td><td class="">Draft<br>4.4</td><td>Internal<br>
+<span class="verchange"><span>.</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">platform.h</td><td class="proto"><tt>#define</tt> U_CHECK_DYLOAD</td><td class="">Draft<br>4.4</td><td>Internal<br>
+<span class="verchange"><span>.</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">platform.h</td><td class="proto"><tt>#define</tt> U_ENABLE_DYLOAD</td><td class="">Draft<br>4.4</td><td>Internal<br>
+<span class="verchange"><span>.</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">platform.h</td><td class="proto"><tt>#define</tt> U_HAVE_STD_STRING</td><td class="">Draft<br>4.2</td><td>Internal<br>
+<span class="verchange"><span>.</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">RegexMatcher&amp; RegexMatcher::appendReplacement(UText*, UText*, UErrorCode&amp;)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">RegexMatcher&amp; RegexMatcher::reset(UText*)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">RegexMatcher* RegexPattern::matcher(UText*, PatternIsUTextFlag, UErrorCode&amp;) const</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">RegexMatcher::RegexMatcher(UText*, UText*, uint32_t, UErrorCode&amp;)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">RegexMatcher::RegexMatcher(UText*, uint32_t, UErrorCode&amp;)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">UText* RegexMatcher::inputText() const</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">UText* RegexMatcher::replaceAll(UText*, UText*, UErrorCode&amp;)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">UText* RegexMatcher::replaceFirst(UText*, UText*, UErrorCode&amp;)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto"><tt>enum</tt> 
+							RegexPattern::PatternIsUTextFlag {}</td><td class="">Internal<br>.</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto"><tt>enum</tt> 
+							RegexPattern::PatternIsUTextFlag::PATTERN_IS_UTEXT</td><td class="">Internal<br>.</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">int32_t RegexMatcher::split(UText*, UText*dest[], int32_t, UErrorCode&amp;)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">int32_t RegexPattern::split(UText*, UText*dest[], int32_t, UErrorCode&amp;) const</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto"><tt>static</tt> RegexPattern* RegexPattern::compile(UText*, UParseError&amp;, UErrorCode&amp;)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto"><tt>static</tt> RegexPattern* RegexPattern::compile(UText*, uint32_t, UErrorCode&amp;)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto"><tt>static</tt> RegexPattern* RegexPattern::compile(UText*, uint32_t, UParseError&amp;, UErrorCode&amp;)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto"><tt>static</tt> UBool RegexPattern::matches(UText*, UText*, UParseError&amp;, UErrorCode&amp;)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">selfmt.h</td><td class="proto">Format* SelectFormat::clone()const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">selfmt.h</td><td class="proto">SelectFormat&amp; SelectFormat::operator=(const SelectFormat&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">selfmt.h</td><td class="proto">SelectFormat::SelectFormat(const SelectFormat&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">selfmt.h</td><td class="proto">SelectFormat::SelectFormat(const UnicodeString&amp;, UErrorCode&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">selfmt.h</td><td class="proto">SelectFormat::~SelectFormat()</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">selfmt.h</td><td class="proto">UBool SelectFormat::operator!=(const Format&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">selfmt.h</td><td class="proto">UBool SelectFormat::operator==(const Format&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">selfmt.h</td><td class="proto">UClassID SelectFormat::getDynamicClassID() const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">selfmt.h</td><td class="proto">UnicodeString&amp; SelectFormat::format(const Formattable&amp;, UnicodeString&amp;, FieldPosition&amp;, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">selfmt.h</td><td class="proto">UnicodeString&amp; SelectFormat::format(const UnicodeString&amp;, UnicodeString&amp;, FieldPosition&amp;, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">selfmt.h</td><td class="proto">UnicodeString&amp; SelectFormat::toPattern(UnicodeString&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">selfmt.h</td><td class="proto"><tt>static</tt> UClassID SelectFormat::getStaticClassID()</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">selfmt.h</td><td class="proto">void SelectFormat::applyPattern(const UnicodeString&amp;, UErrorCode&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">selfmt.h</td><td class="proto">void SelectFormat::parseObject(const UnicodeString&amp;, Formattable&amp;, ParsePosition&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">smpdtfmt.h</td><td class="proto">UnicodeString&amp; SimpleDateFormat::format(Calendar&amp;, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">smpdtfmt.h</td><td class="proto">UnicodeString&amp; SimpleDateFormat::format(UDate, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">smpdtfmt.h</td><td class="proto">UnicodeString&amp; SimpleDateFormat::format(const Formattable&amp;, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">std_string.h</td><td class="proto"><tt>#define</tt> U_HAVE_STD_STRING</td><td class="">Draft<br>4.2</td><td>Internal<br>
+<span class="verchange"><span>.</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">timezone.h</td><td class="proto"><tt>enum</tt> 
+							TimeZone::EDisplayType::GENERIC_LOCATION</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">timezone.h</td><td class="proto"><tt>enum</tt> 
+							TimeZone::EDisplayType::LONG_GENERIC</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">timezone.h</td><td class="proto"><tt>enum</tt> 
+							TimeZone::EDisplayType::LONG_GMT</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">timezone.h</td><td class="proto"><tt>enum</tt> 
+							TimeZone::EDisplayType::SHORT_COMMONLY_USED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">timezone.h</td><td class="proto"><tt>enum</tt> 
+							TimeZone::EDisplayType::SHORT_GENERIC</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">timezone.h</td><td class="proto"><tt>enum</tt> 
+							TimeZone::EDisplayType::SHORT_GMT</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">ucal.h</td><td class="proto">UBool ucal_isWeekend(const UCalendar*, UDate, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">ucal.h</td><td class="proto">UCalendarWeekdayType ucal_getDayOfWeekType(const UCalendar*, UCalendarDaysOfWeek, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">ucal.h</td><td class="proto"><tt>enum</tt> UCalendarType::UCAL_DEFAULT</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ucal.h</td><td class="proto"><tt>enum</tt> UCalendarWeekdayType {}</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>
+</td>
+</tr>
+<tr class="row0">
+<td class="file">ucal.h</td><td class="proto"><tt>enum</tt> UCalendarWeekdayType::UCAL_WEEKDAY</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">ucal.h</td><td class="proto"><tt>enum</tt> UCalendarWeekdayType::UCAL_WEEKEND_CEASE</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">ucal.h</td><td class="proto"><tt>enum</tt> UCalendarWeekdayType::UCAL_WEEKEND_ONSET</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">ucal.h</td><td class="proto"><tt>enum</tt> UCalendarWeekdayType::UCAL_WEEKEND</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">ucal.h</td><td class="proto">int32_t ucal_getWeekendTransition(const UCalendar*, UCalendarDaysOfWeek, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_AVESTAN</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_BAMUM</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_COMMON_INDIC_NUMBER_FORMS</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_DEVANAGARI_EXTENDED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_EGYPTIAN_HIEROGLYPHS</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_ENCLOSED_ALPHANUMERIC_SUPPLEMENT</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_ENCLOSED_IDEOGRAPHIC_SUPPLEMENT</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_HANGUL_JAMO_EXTENDED_A</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_HANGUL_JAMO_EXTENDED_B</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_IMPERIAL_ARAMAIC</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_INSCRIPTIONAL_PAHLAVI</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_INSCRIPTIONAL_PARTHIAN</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_JAVANESE</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_KAITHI</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_LISU</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_MEETEI_MAYEK</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_MYANMAR_EXTENDED_A</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_OLD_SOUTH_ARABIAN</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_OLD_TURKIC</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_RUMI_NUMERAL_SYMBOLS</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_SAMARITAN</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_TAI_THAM</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_TAI_VIET</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_VEDIC_EXTENSIONS</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UCharNameChoice::U_CHAR_NAME_ALIAS</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UJoiningGroup::U_JG_FARSI_YEH</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UJoiningGroup::U_JG_NYA</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_CASED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_CASE_IGNORABLE</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_CHANGES_WHEN_CASEFOLDED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_CHANGES_WHEN_CASEMAPPED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_CHANGES_WHEN_LOWERCASED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_CHANGES_WHEN_NFKC_CASEFOLDED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_CHANGES_WHEN_TITLECASED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_CHANGES_WHEN_UPPERCASED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">udat.h</td><td class="proto">UCalendarDateFields udat_toCalendarDateField(UDateFormatField)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">udatpg.h</td><td class="proto"><tt>enum</tt> UDateTimePatternMatchOptions {}</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>
+</td>
+</tr>
+<tr class="row0">
+<td class="file">udatpg.h</td><td class="proto"><tt>enum</tt> UDateTimePatternMatchOptions::UDATPG_MATCH_ALL_FIELDS_LENGTH</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">udatpg.h</td><td class="proto"><tt>enum</tt> UDateTimePatternMatchOptions::UDATPG_MATCH_HOUR_FIELD_LENGTH</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">udatpg.h</td><td class="proto"><tt>enum</tt> UDateTimePatternMatchOptions::UDATPG_MATCH_NO_OPTIONS</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">udatpg.h</td><td class="proto">int32_t udatpg_getBestPatternWithOptions(UDateTimePatternGenerator*, const UChar*, int32_t, UDateTimePatternMatchOptions, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">udatpg.h</td><td class="proto">int32_t udatpg_replaceFieldTypesWithOptions(UDateTimePatternGenerator*, const UChar*, int32_t, const UChar*, int32_t, UDateTimePatternMatchOptions, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uldnames.h</td><td class="proto">UDialectHandling uldn_getDialectHandling(const ULocaleDisplayNames*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uldnames.h</td><td class="proto">ULocaleDisplayNames* uldn_open(const char*, UDialectHandling, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uldnames.h</td><td class="proto">const char* uldn_getLocale(const ULocaleDisplayNames*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uldnames.h</td><td class="proto"><tt>enum</tt> UDialectHandling {}</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>
+</td>
+</tr>
+<tr class="row1">
+<td class="file">uldnames.h</td><td class="proto"><tt>enum</tt> UDialectHandling::ULDN_DIALECT_NAMES</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uldnames.h</td><td class="proto"><tt>enum</tt> UDialectHandling::ULDN_STANDARD_NAMES</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uldnames.h</td><td class="proto">int32_t uldn_keyDisplayName(const ULocaleDisplayNames*, const char*, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uldnames.h</td><td class="proto">int32_t uldn_keyValueDisplayName(const ULocaleDisplayNames*, const char*, const char*, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uldnames.h</td><td class="proto">int32_t uldn_languageDisplayName(const ULocaleDisplayNames*, const char*, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uldnames.h</td><td class="proto">int32_t uldn_localeDisplayName(const ULocaleDisplayNames*, const char*, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uldnames.h</td><td class="proto">int32_t uldn_regionDisplayName(const ULocaleDisplayNames*, const char*, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uldnames.h</td><td class="proto">int32_t uldn_scriptCodeDisplayName(const ULocaleDisplayNames*, UScriptCode, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uldnames.h</td><td class="proto">int32_t uldn_scriptDisplayName(const ULocaleDisplayNames*, const char*, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uldnames.h</td><td class="proto">int32_t uldn_variantDisplayName(const ULocaleDisplayNames*, const char*, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uldnames.h</td><td class="proto">void uldn_close(ULocaleDisplayNames*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uniset.h</td><td class="proto">int32_t UnicodeSet::span(const UnicodeString&amp;, int32_t, USetSpanCondition) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uniset.h</td><td class="proto">int32_t UnicodeSet::spanBack(const UnicodeString&amp;, int32_t, USetSpanCondition) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unistr.h</td><td class="proto">UnicodeString UnicodeString::tempSubString(int32_t start=, int32_t length=) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">unistr.h</td><td class="proto">UnicodeString UnicodeString::tempSubStringBetween(int32_t, int32_t limit=) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unistr.h</td><td class="proto">UnicodeString&amp; UnicodeString::retainBetween(int32_t, int32_t limit=)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">unorm2.h</td><td class="proto">UBool unorm2_hasBoundaryAfter(const UNormalizer2*, UChar32)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unorm2.h</td><td class="proto">UBool unorm2_hasBoundaryBefore(const UNormalizer2*, UChar32)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">unorm2.h</td><td class="proto">UBool unorm2_isInert(const UNormalizer2*, UChar32)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unorm2.h</td><td class="proto">UBool unorm2_isNormalized(const UNormalizer2*, const UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">unorm2.h</td><td class="proto">UNormalizationCheckResult unorm2_quickCheck(const UNormalizer2*, const UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unorm2.h</td><td class="proto">UNormalizer2* unorm2_openFiltered(const UNormalizer2*, const USet*, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">unorm2.h</td><td class="proto">const UNormalizer2* unorm2_getInstance(const char*, const char*, UNormalization2Mode, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unorm2.h</td><td class="proto"><tt>enum</tt> UNormalization2Mode {}</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>
+</td>
+</tr>
+<tr class="row1">
+<td class="file">unorm2.h</td><td class="proto"><tt>enum</tt> UNormalization2Mode::UNORM2_COMPOSE_CONTIGUOUS</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unorm2.h</td><td class="proto"><tt>enum</tt> UNormalization2Mode::UNORM2_COMPOSE</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">unorm2.h</td><td class="proto"><tt>enum</tt> UNormalization2Mode::UNORM2_DECOMPOSE</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unorm2.h</td><td class="proto"><tt>enum</tt> UNormalization2Mode::UNORM2_FCD</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">unorm2.h</td><td class="proto">int32_t unorm2_append(const UNormalizer2*, UChar*, int32_t, int32_t, const UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unorm2.h</td><td class="proto">int32_t unorm2_normalize(const UNormalizer2*, const UChar*, int32_t, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">unorm2.h</td><td class="proto">int32_t unorm2_normalizeSecondAndAppend(const UNormalizer2*, UChar*, int32_t, int32_t, const UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unorm2.h</td><td class="proto">int32_t unorm2_spanQuickCheckYes(const UNormalizer2*, const UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">unorm2.h</td><td class="proto">void unorm2_close(UNormalizer2*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unum.h</td><td class="proto"><tt>enum</tt> UNumberFormatStyle::UNUM_NUMBERING_SYSTEM</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">unum.h</td><td class="proto">int32_t unum_formatDecimal(const UNumberFormat*, const char*, int32_t, UChar*, int32_t, UFieldPosition*, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unum.h</td><td class="proto">int32_t unum_parseDecimal(const UNumberFormat*, const UChar*, int32_t, int32_t*, char*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uregex.h</td><td class="proto">URegularExpression* uregex_openUText(UText*, uint32_t, UParseError*, UErrorCode*)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uregex.h</td><td class="proto">UText* uregex_getUText(URegularExpression*, UText*, UErrorCode*)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uregex.h</td><td class="proto">UText* uregex_patternUText(const URegularExpression*, UErrorCode*)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uregex.h</td><td class="proto">UText* uregex_replaceAllUText(URegularExpression*, UText*, UText*, UErrorCode*)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uregex.h</td><td class="proto">UText* uregex_replaceFirstUText(URegularExpression*, UText*, UText*, UErrorCode*)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uregex.h</td><td class="proto">int32_t uregex_splitUText(URegularExpression*, UText*destFields[], int32_t, UErrorCode*)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uregex.h</td><td class="proto">void uregex_appendReplacementUText(URegularExpression*, UText*, UText*, UErrorCode*)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uregex.h</td><td class="proto">void uregex_setUText(URegularExpression*, UText*, UErrorCode*)</td><td class="">Internal<br>4.4 technology preview</td><td>Draft<br>
+<span class="verchange"><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_MANDAEAN</td><td class="stabchange">Stable<br>2.2</td><td>Stable<br>
+<span class="verchange"><span>3.6</span>
+<br>
+<b class="bigwarn" title="A stable API changed version.">(changed)</b></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_MEROITIC</td><td class="stabchange">Stable<br>2.2</td><td>Stable<br>
+<span class="verchange"><span>3.6</span>
+<br>
+<b class="bigwarn" title="A stable API changed version.">(changed)</b></span></td>
+</tr>
+<tr class="row1">
+<td class="file">usearch.h</td><td class="proto"><tt>enum</tt> USearchAttribute::USEARCH_ELEMENT_COMPARISON</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">usearch.h</td><td class="proto"><tt>enum</tt> USearchAttributeValue::USEARCH_ANY_BASE_WEIGHT_IS_WILDCARD</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">usearch.h</td><td class="proto"><tt>enum</tt> USearchAttributeValue::USEARCH_PATTERN_BASE_WEIGHT_IS_WILDCARD</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">usearch.h</td><td class="proto"><tt>enum</tt> USearchAttributeValue::USEARCH_STANDARD_ELEMENT_COMPARISON</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_LAMALEF_AUTO</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_LAMALEF_BEGIN</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_LAMALEF_END</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_LAMALEF_MASK</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_LAMALEF_NEAR</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_LAMALEF_RESIZE</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_SEEN_MASK</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_SEEN_TWOCELL_NEAR</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_SPACES_RELATIVE_TO_TEXT_BEGIN_END</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_SPACES_RELATIVE_TO_TEXT_MASK</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_TASHKEEL_BEGIN</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_TASHKEEL_END</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_TASHKEEL_MASK</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_TASHKEEL_REPLACE_BY_TATWEEL</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_TASHKEEL_RESIZE</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_TEXT_DIRECTION_VISUAL_RTL</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_YEHHAMZA_MASK</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_YEHHAMZA_TWOCELL_NEAR</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ustdio.h</td><td class="proto">UFILE* u_fadopt(FILE*, const char*, const char*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">ustring.h</td><td class="proto">UChar* u_strFromJavaModifiedUTF8WithSub(UChar*, int32_t, int32_t*, const char*, int32_t, UChar32, int32_t*, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">ustring.h</td><td class="proto">char* u_strToJavaModifiedUTF8(char*, int32_t, int32_t*, const UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">utf.h</td><td class="proto"><tt>#define</tt> U_IS_SURROGATE_TRAIL</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">utf16.h</td><td class="proto"><tt>#define</tt> U16_IS_SURROGATE_TRAIL</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">utypes.h</td><td class="proto"><tt>#define</tt> U_CHARSET_IS_UTF8</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">uvernum.h</td><td class="proto"><tt>#define</tt> U_ICU_ENTRY_POINT_RENAME</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+</table>
+<P></P>
+<a href="#_top">(jump back to top)</a>
+<hr>
+<a name="promoted"></a>
+<h2>Promoted to stable in 4.6</h2>
+<table BORDER="1" class="genTable">
+<THEAD>
+<tr>
+<th>File</th><th>API</th><th>4.4.2</th><th>4.6</th>
+</tr>
+</THEAD>
+<tr class="row1">
+<td class="file">calendar.h</td><td class="proto">UBool Calendar::isWeekend()const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">calendar.h</td><td class="proto">UBool Calendar::isWeekend(UDate, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">calendar.h</td><td class="proto">UCalendarWeekdayType Calendar::getDayOfWeekType(UCalendarDaysOfWeek, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">calendar.h</td><td class="proto">int32_t Calendar::getWeekendTransition(UCalendarDaysOfWeek, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">datefmt.h</td><td class="proto">UnicodeString&amp; DateFormat::format(Calendar&amp;, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">datefmt.h</td><td class="proto">UnicodeString&amp; DateFormat::format(UDate, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">datefmt.h</td><td class="proto">UnicodeString&amp; DateFormat::format(const Formattable&amp;, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">dcfmtsym.h</td><td class="proto">void DecimalFormatSymbols::setSymbol(ENumberFormatSymbol, const UnicodeString&amp;, const UBool)</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.0</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">decimfmt.h</td><td class="proto">UnicodeString&amp; DecimalFormat::format(const StringPiece&amp;, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">decimfmt.h</td><td class="proto">UnicodeString&amp; DecimalFormat::format(double, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">decimfmt.h</td><td class="proto">UnicodeString&amp; DecimalFormat::format(int32_t, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">decimfmt.h</td><td class="proto">UnicodeString&amp; DecimalFormat::format(int64_t, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">dtptngen.h</td><td class="proto">UnicodeString DateTimePatternGenerator::getBestPattern(const UnicodeString&amp;, UDateTimePatternMatchOptions, UErrorCode&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">dtptngen.h</td><td class="proto">UnicodeString DateTimePatternGenerator::replaceFieldTypes(const UnicodeString&amp;, const UnicodeString&amp;, UDateTimePatternMatchOptions, UErrorCode&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">errorcode.h</td><td class="proto">const char* ErrorCode::errorName() const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">errorcode.h</td><td class="proto">void ErrorCode::assertSuccess() const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">fmtable.h</td><td class="proto">Formattable::Formattable(const StringPiece&amp;, UErrorCode&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">fmtable.h</td><td class="proto">StringPiece Formattable::getDecimalNumber(UErrorCode&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">fmtable.h</td><td class="proto">void Formattable::setDecimalNumber(const StringPiece&amp;, UErrorCode&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">format.h</td><td class="proto">UnicodeString&amp; Format::format(const Formattable&amp;, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">fpositer.h</td><td class="proto">FieldPositionIterator::FieldPositionIterator()</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">fpositer.h</td><td class="proto">FieldPositionIterator::FieldPositionIterator(const FieldPositionIterator&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">fpositer.h</td><td class="proto">FieldPositionIterator::~FieldPositionIterator()</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">fpositer.h</td><td class="proto">UBool FieldPositionIterator::next(FieldPosition&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">fpositer.h</td><td class="proto">UBool FieldPositionIterator::operator!=(const FieldPositionIterator&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">fpositer.h</td><td class="proto">UBool FieldPositionIterator::operator==(const FieldPositionIterator&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::bamuScriptCode</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::bassScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row1">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::duplScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::elbaScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::granScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::kpelScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::lomaScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::mendScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::mercScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::narbScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::nbatScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::palmScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::sindScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::waraScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">LESwaps.h</td><td class="proto"><tt>static</tt> le_uint16 LESwaps::swapWord(le_uint16)</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.8</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">LESwaps.h</td><td class="proto"><tt>static</tt> le_uint32 LESwaps::swapLong(le_uint32)</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.8</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">locdspnm.h</td><td class="proto">LocaleDisplayNames::~LocaleDisplayNames()</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">locdspnm.h</td><td class="proto">UDialectHandling LocaleDisplayNames::getDialectHandling() const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">locdspnm.h</td><td class="proto">UnicodeString&amp; LocaleDisplayNames::keyDisplayName(const char*, UnicodeString&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">locdspnm.h</td><td class="proto">UnicodeString&amp; LocaleDisplayNames::keyValueDisplayName(const char*, const char*, UnicodeString&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">locdspnm.h</td><td class="proto">UnicodeString&amp; LocaleDisplayNames::languageDisplayName(const char*, UnicodeString&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">locdspnm.h</td><td class="proto">UnicodeString&amp; LocaleDisplayNames::localeDisplayName(const Locale&amp;, UnicodeString&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">locdspnm.h</td><td class="proto">UnicodeString&amp; LocaleDisplayNames::localeDisplayName(const char*, UnicodeString&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">locdspnm.h</td><td class="proto">UnicodeString&amp; LocaleDisplayNames::regionDisplayName(const char*, UnicodeString&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">locdspnm.h</td><td class="proto">UnicodeString&amp; LocaleDisplayNames::scriptDisplayName(UScriptCode, UnicodeString&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">locdspnm.h</td><td class="proto">UnicodeString&amp; LocaleDisplayNames::scriptDisplayName(const char*, UnicodeString&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">locdspnm.h</td><td class="proto">UnicodeString&amp; LocaleDisplayNames::variantDisplayName(const char*, UnicodeString&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">locdspnm.h</td><td class="proto">const Locale&amp; LocaleDisplayNames::getLocale() const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">locdspnm.h</td><td class="proto"><tt>static</tt> LocaleDisplayNames* LocaleDisplayNames::createInstance(const Locale&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">locdspnm.h</td><td class="proto"><tt>static</tt> LocaleDisplayNames* LocaleDisplayNames::createInstance(const Locale&amp;, UDialectHandling)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">locid.h</td><td class="proto"><tt>static</tt> const Locale&amp; Locale::getRoot()</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">locid.h</td><td class="proto"><tt>static</tt> const char* const Locale::getISOCountries()</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.0</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">locid.h</td><td class="proto"><tt>static</tt> const char* const Locale::getISOLanguages()</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.0</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">FilteredNormalizer2::FilteredNormalizer2(const Normalizer2&amp;, const UnicodeSet&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UBool FilteredNormalizer2::hasBoundaryAfter(UChar32) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">UBool FilteredNormalizer2::hasBoundaryBefore(UChar32) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UBool FilteredNormalizer2::isInert(UChar32) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">UBool FilteredNormalizer2::isNormalized(const UnicodeString&amp;, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UBool Normalizer2::hasBoundaryAfter(UChar32) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">UBool Normalizer2::hasBoundaryBefore(UChar32) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UBool Normalizer2::isInert(UChar32) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">UBool Normalizer2::isNormalized(const UnicodeString&amp;, UErrorCode&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UNormalizationCheckResult FilteredNormalizer2::quickCheck(const UnicodeString&amp;, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">UNormalizationCheckResult Normalizer2::quickCheck(const UnicodeString&amp;, UErrorCode&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UnicodeString Normalizer2::normalize(const UnicodeString&amp;, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">UnicodeString&amp; FilteredNormalizer2::append(UnicodeString&amp;, const UnicodeString&amp;, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UnicodeString&amp; FilteredNormalizer2::normalize(const UnicodeString&amp;, UnicodeString&amp;, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">UnicodeString&amp; FilteredNormalizer2::normalizeSecondAndAppend(UnicodeString&amp;, const UnicodeString&amp;, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UnicodeString&amp; Normalizer2::append(UnicodeString&amp;, const UnicodeString&amp;, UErrorCode&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">UnicodeString&amp; Normalizer2::normalize(const UnicodeString&amp;, UnicodeString&amp;, UErrorCode&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UnicodeString&amp; Normalizer2::normalizeSecondAndAppend(UnicodeString&amp;, const UnicodeString&amp;, UErrorCode&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">int32_t FilteredNormalizer2::spanQuickCheckYes(const UnicodeString&amp;, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">int32_t Normalizer2::spanQuickCheckYes(const UnicodeString&amp;, UErrorCode&amp;) const =0</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto"><tt>static</tt> const Normalizer2* Normalizer2::getInstance(const char*, const char*, UNormalization2Mode, UErrorCode&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">numfmt.h</td><td class="proto">UnicodeString&amp; NumberFormat::format(const Formattable&amp;, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">numfmt.h</td><td class="proto">UnicodeString&amp; NumberFormat::format(const StringPiece&amp;, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">numfmt.h</td><td class="proto">UnicodeString&amp; NumberFormat::format(double, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">numfmt.h</td><td class="proto">UnicodeString&amp; NumberFormat::format(int32_t, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">numfmt.h</td><td class="proto">UnicodeString&amp; NumberFormat::format(int64_t, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">RegexMatcher&amp; RegexMatcher::region(int64_t, int64_t, UErrorCode&amp;)</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.0</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">RegexMatcher&amp; RegexMatcher::reset(int64_t, UErrorCode&amp;)</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.8</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">UBool RegexMatcher::find(int64_t, UErrorCode&amp;)</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.4</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">UBool RegexMatcher::lookingAt(int64_t, UErrorCode&amp;)</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.8</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">UBool RegexMatcher::matches(int64_t, UErrorCode&amp;)</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.8</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">selfmt.h</td><td class="proto">Format* SelectFormat::clone()const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">selfmt.h</td><td class="proto">SelectFormat&amp; SelectFormat::operator=(const SelectFormat&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">selfmt.h</td><td class="proto">SelectFormat::SelectFormat(const SelectFormat&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">selfmt.h</td><td class="proto">SelectFormat::SelectFormat(const UnicodeString&amp;, UErrorCode&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">selfmt.h</td><td class="proto">SelectFormat::~SelectFormat()</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">selfmt.h</td><td class="proto">UBool SelectFormat::operator!=(const Format&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">selfmt.h</td><td class="proto">UBool SelectFormat::operator==(const Format&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">selfmt.h</td><td class="proto">UClassID SelectFormat::getDynamicClassID() const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">selfmt.h</td><td class="proto">UnicodeString&amp; SelectFormat::format(const Formattable&amp;, UnicodeString&amp;, FieldPosition&amp;, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">selfmt.h</td><td class="proto">UnicodeString&amp; SelectFormat::format(const UnicodeString&amp;, UnicodeString&amp;, FieldPosition&amp;, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">selfmt.h</td><td class="proto">UnicodeString&amp; SelectFormat::toPattern(UnicodeString&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">selfmt.h</td><td class="proto"><tt>static</tt> UClassID SelectFormat::getStaticClassID()</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">selfmt.h</td><td class="proto">void SelectFormat::applyPattern(const UnicodeString&amp;, UErrorCode&amp;)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">selfmt.h</td><td class="proto">void SelectFormat::parseObject(const UnicodeString&amp;, Formattable&amp;, ParsePosition&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">smpdtfmt.h</td><td class="proto">UnicodeString&amp; SimpleDateFormat::format(Calendar&amp;, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">smpdtfmt.h</td><td class="proto">UnicodeString&amp; SimpleDateFormat::format(UDate, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">smpdtfmt.h</td><td class="proto">UnicodeString&amp; SimpleDateFormat::format(const Formattable&amp;, UnicodeString&amp;, FieldPositionIterator*, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">timezone.h</td><td class="proto"><tt>enum</tt> 
+							TimeZone::EDisplayType::GENERIC_LOCATION</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">timezone.h</td><td class="proto"><tt>enum</tt> 
+							TimeZone::EDisplayType::LONG_GENERIC</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">timezone.h</td><td class="proto"><tt>enum</tt> 
+							TimeZone::EDisplayType::LONG_GMT</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">timezone.h</td><td class="proto"><tt>enum</tt> 
+							TimeZone::EDisplayType::SHORT_COMMONLY_USED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">timezone.h</td><td class="proto"><tt>enum</tt> 
+							TimeZone::EDisplayType::SHORT_GENERIC</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">timezone.h</td><td class="proto"><tt>enum</tt> 
+							TimeZone::EDisplayType::SHORT_GMT</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">ucal.h</td><td class="proto">UBool ucal_isWeekend(const UCalendar*, UDate, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">ucal.h</td><td class="proto">UCalendarWeekdayType ucal_getDayOfWeekType(const UCalendar*, UCalendarDaysOfWeek, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">ucal.h</td><td class="proto"><tt>enum</tt> UCalendarType::UCAL_DEFAULT</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ucal.h</td><td class="proto"><tt>enum</tt> UCalendarWeekdayType {}</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>
+</td>
+</tr>
+<tr class="row0">
+<td class="file">ucal.h</td><td class="proto"><tt>enum</tt> UCalendarWeekdayType::UCAL_WEEKDAY</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">ucal.h</td><td class="proto"><tt>enum</tt> UCalendarWeekdayType::UCAL_WEEKEND_CEASE</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">ucal.h</td><td class="proto"><tt>enum</tt> UCalendarWeekdayType::UCAL_WEEKEND_ONSET</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">ucal.h</td><td class="proto"><tt>enum</tt> UCalendarWeekdayType::UCAL_WEEKEND</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">ucal.h</td><td class="proto">int32_t ucal_getWeekendTransition(const UCalendar*, UCalendarDaysOfWeek, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_ALCHEMICAL_SYMBOLS</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_AVESTAN</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_BAMUM_SUPPLEMENT</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_BAMUM</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_BATAK</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_BRAHMI</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_COMMON_INDIC_NUMBER_FORMS</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_DEVANAGARI_EXTENDED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_EGYPTIAN_HIEROGLYPHS</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_EMOTICONS</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_ENCLOSED_ALPHANUMERIC_SUPPLEMENT</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_ENCLOSED_IDEOGRAPHIC_SUPPLEMENT</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_ETHIOPIC_EXTENDED_A</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_HANGUL_JAMO_EXTENDED_A</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_HANGUL_JAMO_EXTENDED_B</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_IMPERIAL_ARAMAIC</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_INSCRIPTIONAL_PAHLAVI</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_INSCRIPTIONAL_PARTHIAN</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_JAVANESE</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_KAITHI</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_KANA_SUPPLEMENT</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_LISU</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_MANDAIC</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_MEETEI_MAYEK</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_MYANMAR_EXTENDED_A</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_OLD_SOUTH_ARABIAN</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_OLD_TURKIC</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_PLAYING_CARDS</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_RUMI_NUMERAL_SYMBOLS</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_SAMARITAN</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_TAI_THAM</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_TAI_VIET</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_TRANSPORT_AND_MAP_SYMBOLS</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_VEDIC_EXTENSIONS</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UCharNameChoice::U_CHAR_NAME_ALIAS</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UJoiningGroup::U_JG_FARSI_YEH</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UJoiningGroup::U_JG_NYA</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UJoiningGroup::U_JG_TEH_MARBUTA_GOAL</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_CASED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_CASE_IGNORABLE</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_CHANGES_WHEN_CASEFOLDED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_CHANGES_WHEN_CASEMAPPED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_CHANGES_WHEN_LOWERCASED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_CHANGES_WHEN_NFKC_CASEFOLDED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_CHANGES_WHEN_TITLECASED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_CHANGES_WHEN_UPPERCASED</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">udat.h</td><td class="proto">UCalendarDateFields udat_toCalendarDateField(UDateFormatField)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">udatpg.h</td><td class="proto"><tt>enum</tt> UDateTimePatternMatchOptions {}</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>
+</td>
+</tr>
+<tr class="row1">
+<td class="file">udatpg.h</td><td class="proto"><tt>enum</tt> UDateTimePatternMatchOptions::UDATPG_MATCH_ALL_FIELDS_LENGTH</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">udatpg.h</td><td class="proto"><tt>enum</tt> UDateTimePatternMatchOptions::UDATPG_MATCH_HOUR_FIELD_LENGTH</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">udatpg.h</td><td class="proto"><tt>enum</tt> UDateTimePatternMatchOptions::UDATPG_MATCH_NO_OPTIONS</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">udatpg.h</td><td class="proto">int32_t udatpg_getBestPatternWithOptions(UDateTimePatternGenerator*, const UChar*, int32_t, UDateTimePatternMatchOptions, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">udatpg.h</td><td class="proto">int32_t udatpg_replaceFieldTypesWithOptions(UDateTimePatternGenerator*, const UChar*, int32_t, const UChar*, int32_t, UDateTimePatternMatchOptions, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_ALLOW_UNASSIGNED</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_DEFAULT</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_USE_STD3_RULES</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uldnames.h</td><td class="proto">UDialectHandling uldn_getDialectHandling(const ULocaleDisplayNames*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uldnames.h</td><td class="proto">ULocaleDisplayNames* uldn_open(const char*, UDialectHandling, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uldnames.h</td><td class="proto">const char* uldn_getLocale(const ULocaleDisplayNames*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uldnames.h</td><td class="proto"><tt>enum</tt> UDialectHandling {}</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>
+</td>
+</tr>
+<tr class="row1">
+<td class="file">uldnames.h</td><td class="proto"><tt>enum</tt> UDialectHandling::ULDN_DIALECT_NAMES</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uldnames.h</td><td class="proto"><tt>enum</tt> UDialectHandling::ULDN_STANDARD_NAMES</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uldnames.h</td><td class="proto">int32_t uldn_keyDisplayName(const ULocaleDisplayNames*, const char*, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uldnames.h</td><td class="proto">int32_t uldn_keyValueDisplayName(const ULocaleDisplayNames*, const char*, const char*, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uldnames.h</td><td class="proto">int32_t uldn_languageDisplayName(const ULocaleDisplayNames*, const char*, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uldnames.h</td><td class="proto">int32_t uldn_localeDisplayName(const ULocaleDisplayNames*, const char*, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uldnames.h</td><td class="proto">int32_t uldn_regionDisplayName(const ULocaleDisplayNames*, const char*, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uldnames.h</td><td class="proto">int32_t uldn_scriptCodeDisplayName(const ULocaleDisplayNames*, UScriptCode, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uldnames.h</td><td class="proto">int32_t uldn_scriptDisplayName(const ULocaleDisplayNames*, const char*, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uldnames.h</td><td class="proto">int32_t uldn_variantDisplayName(const ULocaleDisplayNames*, const char*, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uldnames.h</td><td class="proto">void uldn_close(ULocaleDisplayNames*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">uloc.h</td><td class="proto">const char* const uloc_getISOCountries()</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.0</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uloc.h</td><td class="proto">const char* const uloc_getISOLanguages()</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.0</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uniset.h</td><td class="proto">int32_t UnicodeSet::span(const UnicodeString&amp;, int32_t, USetSpanCondition) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uniset.h</td><td class="proto">int32_t UnicodeSet::spanBack(const UnicodeString&amp;, int32_t, USetSpanCondition) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unistr.h</td><td class="proto">UnicodeString UnicodeString::tempSubString(int32_t start=, int32_t length=) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">unistr.h</td><td class="proto">UnicodeString UnicodeString::tempSubStringBetween(int32_t, int32_t limit=) const</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unistr.h</td><td class="proto">UnicodeString&amp; UnicodeString::retainBetween(int32_t, int32_t limit=)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">unorm2.h</td><td class="proto">UBool unorm2_hasBoundaryAfter(const UNormalizer2*, UChar32)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unorm2.h</td><td class="proto">UBool unorm2_hasBoundaryBefore(const UNormalizer2*, UChar32)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">unorm2.h</td><td class="proto">UBool unorm2_isInert(const UNormalizer2*, UChar32)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unorm2.h</td><td class="proto">UBool unorm2_isNormalized(const UNormalizer2*, const UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">unorm2.h</td><td class="proto">UNormalizationCheckResult unorm2_quickCheck(const UNormalizer2*, const UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unorm2.h</td><td class="proto">UNormalizer2* unorm2_openFiltered(const UNormalizer2*, const USet*, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">unorm2.h</td><td class="proto">const UNormalizer2* unorm2_getInstance(const char*, const char*, UNormalization2Mode, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unorm2.h</td><td class="proto"><tt>enum</tt> UNormalization2Mode {}</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>
+</td>
+</tr>
+<tr class="row1">
+<td class="file">unorm2.h</td><td class="proto"><tt>enum</tt> UNormalization2Mode::UNORM2_COMPOSE_CONTIGUOUS</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unorm2.h</td><td class="proto"><tt>enum</tt> UNormalization2Mode::UNORM2_COMPOSE</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">unorm2.h</td><td class="proto"><tt>enum</tt> UNormalization2Mode::UNORM2_DECOMPOSE</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unorm2.h</td><td class="proto"><tt>enum</tt> UNormalization2Mode::UNORM2_FCD</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">unorm2.h</td><td class="proto">int32_t unorm2_append(const UNormalizer2*, UChar*, int32_t, int32_t, const UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unorm2.h</td><td class="proto">int32_t unorm2_normalize(const UNormalizer2*, const UChar*, int32_t, UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">unorm2.h</td><td class="proto">int32_t unorm2_normalizeSecondAndAppend(const UNormalizer2*, UChar*, int32_t, int32_t, const UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unorm2.h</td><td class="proto">int32_t unorm2_spanQuickCheckYes(const UNormalizer2*, const UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">unorm2.h</td><td class="proto">void unorm2_close(UNormalizer2*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unum.h</td><td class="proto"><tt>enum</tt> UNumberFormatStyle::UNUM_NUMBERING_SYSTEM</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">unum.h</td><td class="proto">int32_t unum_formatDecimal(const UNumberFormat*, const char*, int32_t, UChar*, int32_t, UFieldPosition*, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">unum.h</td><td class="proto">int32_t unum_parseDecimal(const UNumberFormat*, const UChar*, int32_t, int32_t*, char*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_BASSA_VAH</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_DUPLOYAN_SHORTAND</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_ELBASAN</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_GRANTHA</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_KPELLE</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_LOMA</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_MANDAIC</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row0">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_MENDE</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_MEROITIC_CURSIVE</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_MEROITIC_HIEROGLYPHS</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row1">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_NABATAEAN</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_OLD_NORTH_ARABIAN</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_PALMYRENE</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_SINDHI</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_WARANG_CITI</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">usearch.h</td><td class="proto"><tt>enum</tt> USearchAttribute::USEARCH_ELEMENT_COMPARISON</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">usearch.h</td><td class="proto"><tt>enum</tt> USearchAttributeValue::USEARCH_ANY_BASE_WEIGHT_IS_WILDCARD</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">usearch.h</td><td class="proto"><tt>enum</tt> USearchAttributeValue::USEARCH_PATTERN_BASE_WEIGHT_IS_WILDCARD</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">usearch.h</td><td class="proto"><tt>enum</tt> USearchAttributeValue::USEARCH_STANDARD_ELEMENT_COMPARISON</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_LAMALEF_AUTO</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_LAMALEF_BEGIN</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_LAMALEF_END</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_LAMALEF_MASK</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_LAMALEF_NEAR</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_LAMALEF_RESIZE</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_SEEN_MASK</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_SEEN_TWOCELL_NEAR</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_SPACES_RELATIVE_TO_TEXT_BEGIN_END</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_SPACES_RELATIVE_TO_TEXT_MASK</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_TASHKEEL_BEGIN</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_TASHKEEL_END</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_TASHKEEL_MASK</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_TASHKEEL_REPLACE_BY_TATWEEL</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_TASHKEEL_RESIZE</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_TEXT_DIRECTION_VISUAL_RTL</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_YEHHAMZA_MASK</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> U_SHAPE_YEHHAMZA_TWOCELL_NEAR</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ustdio.h</td><td class="proto">UFILE* u_fadopt(FILE*, const char*, const char*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">ustring.h</td><td class="proto">UChar* u_strFromJavaModifiedUTF8WithSub(UChar*, int32_t, int32_t*, const char*, int32_t, UChar32, int32_t*, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row0">
+<td class="file">ustring.h</td><td class="proto">char* u_strToJavaModifiedUTF8(char*, int32_t, int32_t*, const UChar*, int32_t, UErrorCode*)</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.4</td>
+</tr>
+<tr class="row1">
+<td class="file">utf.h</td><td class="proto"><tt>#define</tt> U_IS_SURROGATE_TRAIL</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">utf16.h</td><td class="proto"><tt>#define</tt> U16_IS_SURROGATE_TRAIL</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">utypes.h</td><td class="proto"><tt>#define</tt> U_CHARSET_IS_UTF8</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">uvernum.h</td><td class="proto"><tt>#define</tt> U_ICU_ENTRY_POINT_RENAME</td><td class="" colspan="2" align="center">Draft&raquo;Stable<br>4.2</td>
+</tr>
+</table>
+<P></P>
+<a href="#_top">(jump back to top)</a>
+<hr>
+<a name="added"></a>
+<h2>Added in 4.6</h2>
+<table BORDER="1" class="genTable">
+<THEAD>
+<tr>
+<th>File</th><th>API</th><th>4.4.2</th><th>4.6</th>
+</tr>
+</THEAD>
+<tr class="row1">
+<td class="file">bytestream.h</td><td class="proto">CheckedArrayByteSink&amp; CheckedArrayByteSink::Reset()</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">bytestream.h</td><td class="proto">int32_t CheckedArrayByteSink::NumberOfBytesAppended() const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">coll.h</td><td class="proto">int32_t Collator::getReorderCodes(int32_t*, int32_t, UErrorCode&amp;) const</td><td class="">None<br>
+</td><td>Internal<br>
+<span class=""><span>.</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">coll.h</td><td class="proto">void Collator::setReorderCodes(const int32_t*, int32_t, UErrorCode&amp;)</td><td class="">None<br>
+</td><td>Internal<br>
+<span class=""><span>.</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">dcfmtsym.h</td><td class="proto"><tt>enum</tt> 
+							DecimalFormatSymbols::ENumberFormatSymbol::kEightDigitSymbol</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">dcfmtsym.h</td><td class="proto"><tt>enum</tt> 
+							DecimalFormatSymbols::ENumberFormatSymbol::kFiveDigitSymbol</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">dcfmtsym.h</td><td class="proto"><tt>enum</tt> 
+							DecimalFormatSymbols::ENumberFormatSymbol::kFourDigitSymbol</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">dcfmtsym.h</td><td class="proto"><tt>enum</tt> 
+							DecimalFormatSymbols::ENumberFormatSymbol::kNineDigitSymbol</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">dcfmtsym.h</td><td class="proto"><tt>enum</tt> 
+							DecimalFormatSymbols::ENumberFormatSymbol::kOneDigitSymbol</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">dcfmtsym.h</td><td class="proto"><tt>enum</tt> 
+							DecimalFormatSymbols::ENumberFormatSymbol::kSevenDigitSymbol</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">dcfmtsym.h</td><td class="proto"><tt>enum</tt> 
+							DecimalFormatSymbols::ENumberFormatSymbol::kSixDigitSymbol</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">dcfmtsym.h</td><td class="proto"><tt>enum</tt> 
+							DecimalFormatSymbols::ENumberFormatSymbol::kThreeDigitSymbol</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">dcfmtsym.h</td><td class="proto"><tt>enum</tt> 
+							DecimalFormatSymbols::ENumberFormatSymbol::kTwoDigitSymbol</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">dcfmtsym.h</td><td class="proto">void DecimalFormatSymbols::setSymbol(ENumberFormatSymbol, const UnicodeString&amp;, const UBool)</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.0</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">idna.h</td><td class="proto">IDNAInfo::IDNAInfo()</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">idna.h</td><td class="proto">UBool IDNAInfo::hasErrors() const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">idna.h</td><td class="proto">UBool IDNAInfo::isTransitionalDifferent() const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">idna.h</td><td class="proto">UnicodeString&amp; IDNA::labelToASCII(const UnicodeString&amp;, UnicodeString&amp;, IDNAInfo&amp;, UErrorCode&amp;) const =0</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">idna.h</td><td class="proto">UnicodeString&amp; IDNA::labelToUnicode(const UnicodeString&amp;, UnicodeString&amp;, IDNAInfo&amp;, UErrorCode&amp;) const =0</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">idna.h</td><td class="proto">UnicodeString&amp; IDNA::nameToASCII(const UnicodeString&amp;, UnicodeString&amp;, IDNAInfo&amp;, UErrorCode&amp;) const =0</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">idna.h</td><td class="proto">UnicodeString&amp; IDNA::nameToUnicode(const UnicodeString&amp;, UnicodeString&amp;, IDNAInfo&amp;, UErrorCode&amp;) const =0</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">idna.h</td><td class="proto"><tt>static</tt> IDNA* IDNA::createUTS46Instance(uint32_t, UErrorCode&amp;)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">idna.h</td><td class="proto">uint32_t IDNAInfo::getErrors() const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">idna.h</td><td class="proto">void IDNA::labelToASCII_UTF8(const StringPiece&amp;, ByteSink&amp;, IDNAInfo&amp;, UErrorCode&amp;) const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">idna.h</td><td class="proto">void IDNA::labelToUnicodeUTF8(const StringPiece&amp;, ByteSink&amp;, IDNAInfo&amp;, UErrorCode&amp;) const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">idna.h</td><td class="proto">void IDNA::nameToASCII_UTF8(const StringPiece&amp;, ByteSink&amp;, IDNAInfo&amp;, UErrorCode&amp;) const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">idna.h</td><td class="proto">void IDNA::nameToUnicodeUTF8(const StringPiece&amp;, ByteSink&amp;, IDNAInfo&amp;, UErrorCode&amp;) const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::bassScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row1">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::duplScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::elbaScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::granScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::kpelScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::lomaScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::mendScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::mercScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::narbScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::nbatScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::palmScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::sindScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">LEScripts.h</td><td class="proto"><tt>enum</tt> ScriptCodes::waraScriptCode</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">LESwaps.h</td><td class="proto"><tt>static</tt> le_uint16 LESwaps::swapWord(le_uint16)</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.8</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">LESwaps.h</td><td class="proto"><tt>static</tt> le_uint32 LESwaps::swapLong(le_uint32)</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.8</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">locid.h</td><td class="proto"><tt>static</tt> const char* const Locale::getISOCountries()</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.0</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">locid.h</td><td class="proto"><tt>static</tt> const char* const Locale::getISOLanguages()</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.0</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">normalizer2.h</td><td class="proto">UBool FilteredNormalizer2::getDecomposition(UChar32, UnicodeString&amp;) const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">normalizer2.h</td><td class="proto">UBool Normalizer2::getDecomposition(UChar32, UnicodeString&amp;) const =0</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">numsys.h</td><td class="proto"><tt>#define</tt> NUMSYS_NAME_CAPACITY</td><td class="">None<br>
+</td><td>Internal<br>
+<span class=""><span>.</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">numsys.h</td><td class="proto">const char* NumberingSystem::getName()</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">RegexMatcher&amp; RegexMatcher::region(int64_t, int64_t, UErrorCode&amp;)</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.0</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">RegexMatcher&amp; RegexMatcher::region(int64_t, int64_t, int64_t, UErrorCode&amp;)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">RegexMatcher&amp; RegexMatcher::reset(int64_t, UErrorCode&amp;)</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.8</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">UBool RegexMatcher::find(int64_t, UErrorCode&amp;)</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.4</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">UBool RegexMatcher::lookingAt(int64_t, UErrorCode&amp;)</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.8</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">UBool RegexMatcher::matches(int64_t, UErrorCode&amp;)</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.8</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">UText* RegexMatcher::appendTail(UText*, UErrorCode&amp;)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">UText* RegexMatcher::getInput(UText*, UErrorCode&amp;) const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">UText* RegexMatcher::group(UText*, int64_t&amp;, UErrorCode&amp;) const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">UText* RegexMatcher::group(int32_t, UText*, int64_t&amp;, UErrorCode&amp;) const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">UText* RegexPattern::patternText(UErrorCode&amp;) const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">int64_t RegexMatcher::end64(UErrorCode&amp;) const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">int64_t RegexMatcher::end64(int32_t, UErrorCode&amp;) const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">int64_t RegexMatcher::regionEnd64() const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">int64_t RegexMatcher::regionStart64() const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">int64_t RegexMatcher::start64(UErrorCode&amp;) const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">int64_t RegexMatcher::start64(int32_t, UErrorCode&amp;) const</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">regex.h</td><td class="proto">void RegexMatcher::getFindProgressCallback(URegexFindProgressCallback*&amp;, const void*&amp;, UErrorCode&amp;)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">regex.h</td><td class="proto">void RegexMatcher::setFindProgressCallback(URegexFindProgressCallback*, const void*, UErrorCode&amp;)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">tblcoll.h</td><td class="proto">int32_t RuleBasedCollator::getReorderCodes(int32_t*, int32_t, UErrorCode&amp;) const</td><td class="">None<br>
+</td><td>Internal<br>
+<span class=""><span>.</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">tblcoll.h</td><td class="proto">void RuleBasedCollator::setReorderCodes(const int32_t*, int32_t, UErrorCode&amp;)</td><td class="">None<br>
+</td><td>Internal<br>
+<span class=""><span>.</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">ubidi.h</td><td class="proto">UBiDiDirection ubidi_getBaseDirection(const UChar*, int32_t)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">ubidi.h</td><td class="proto"><tt>enum</tt> UBiDiDirection::UBIDI_NEUTRAL</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_ALCHEMICAL_SYMBOLS</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_BAMUM_SUPPLEMENT</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_BATAK</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_BRAHMI</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_EMOTICONS</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_ETHIOPIC_EXTENDED_A</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_KANA_SUPPLEMENT</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_MANDAIC</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_PLAYING_CARDS</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UBlockCode::UBLOCK_TRANSPORT_AND_MAP_SYMBOLS</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UJoiningGroup::U_JG_TEH_MARBUTA_GOAL</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_OTHER_PROPERTY_LIMIT</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_OTHER_PROPERTY_START</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uchar.h</td><td class="proto"><tt>enum</tt> UProperty::UCHAR_SCRIPT_EXTENSIONS</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">ucol.h</td><td class="proto"><tt>enum</tt> UColReorderCode {}</td><td class="">None<br>
+</td><td>Internal<br>
+<span class=""><span></span>
+<br>
+<b class="bigwarn" title="A new API was introduced that was not tagged.">(untagged)</b></span></td>
+</tr>
+<tr class="row1">
+<td class="file">ucol.h</td><td class="proto"><tt>enum</tt> UColReorderCode::UCOL_REORDER_CODE_CURRENCY</td><td class="">None<br>
+</td><td>Internal<br>
+<span class=""><span>.</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">ucol.h</td><td class="proto"><tt>enum</tt> UColReorderCode::UCOL_REORDER_CODE_DIGIT</td><td class="">None<br>
+</td><td>Internal<br>
+<span class=""><span>.</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">ucol.h</td><td class="proto"><tt>enum</tt> UColReorderCode::UCOL_REORDER_CODE_FIRST</td><td class="">None<br>
+</td><td>Internal<br>
+<span class=""><span>.</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">ucol.h</td><td class="proto"><tt>enum</tt> UColReorderCode::UCOL_REORDER_CODE_LIMIT</td><td class="">None<br>
+</td><td>Internal<br>
+<span class=""><span>.</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">ucol.h</td><td class="proto"><tt>enum</tt> UColReorderCode::UCOL_REORDER_CODE_PUNCTUATION</td><td class="">None<br>
+</td><td>Internal<br>
+<span class=""><span>.</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">ucol.h</td><td class="proto"><tt>enum</tt> UColReorderCode::UCOL_REORDER_CODE_SPACE</td><td class="">None<br>
+</td><td>Internal<br>
+<span class=""><span>.</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">ucol.h</td><td class="proto"><tt>enum</tt> UColReorderCode::UCOL_REORDER_CODE_SYMBOL</td><td class="">None<br>
+</td><td>Internal<br>
+<span class=""><span>.</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">ucol.h</td><td class="proto">int32_t ucol_getReorderCodes(const UCollator*, int32_t*, int32_t, UErrorCode*)</td><td class="">None<br>
+</td><td>Internal<br>
+<span class=""><span>.</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">ucol.h</td><td class="proto">void ucol_setReorderCodes(UCollator*, const int32_t*, int32_t, UErrorCode*)</td><td class="">None<br>
+</td><td>Internal<br>
+<span class=""><span>.</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto"><tt>#define</tt> UIDNA_INFO_INITIALIZER</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uidna.h</td><td class="proto">UIDNA* uidna_openUTS46(uint32_t, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_ALLOW_UNASSIGNED</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_CHECK_BIDI</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_CHECK_CONTEXTJ</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_DEFAULT</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_ERROR_BIDI</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_ERROR_CONTEXTJ</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_ERROR_DISALLOWED</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_ERROR_DOMAIN_NAME_TOO_LONG</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_ERROR_EMPTY_LABEL</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_ERROR_HYPHEN_3_4</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_ERROR_INVALID_ACE_LABEL</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_ERROR_LABEL_HAS_DOT</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_ERROR_LABEL_TOO_LONG</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_ERROR_LEADING_COMBINING_MARK</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_ERROR_LEADING_HYPHEN</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_ERROR_PUNYCODE</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_ERROR_TRAILING_HYPHEN</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_NONTRANSITIONAL_TO_ASCII</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_NONTRANSITIONAL_TO_UNICODE</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uidna.h</td><td class="proto"><tt>enum</tt> (anonymous)::UIDNA_USE_STD3_RULES</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto">int32_t uidna_labelToASCII(const UIDNA*, const UChar*, int32_t, UChar*, int32_t, UIDNAInfo*, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uidna.h</td><td class="proto">int32_t uidna_labelToASCII_UTF8(const UIDNA*, const char*, int32_t, char*, int32_t, UIDNAInfo*, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto">int32_t uidna_labelToUnicode(const UIDNA*, const UChar*, int32_t, UChar*, int32_t, UIDNAInfo*, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uidna.h</td><td class="proto">int32_t uidna_labelToUnicodeUTF8(const UIDNA*, const char*, int32_t, char*, int32_t, UIDNAInfo*, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto">int32_t uidna_nameToASCII(const UIDNA*, const UChar*, int32_t, UChar*, int32_t, UIDNAInfo*, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uidna.h</td><td class="proto">int32_t uidna_nameToASCII_UTF8(const UIDNA*, const char*, int32_t, char*, int32_t, UIDNAInfo*, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto">int32_t uidna_nameToUnicode(const UIDNA*, const UChar*, int32_t, UChar*, int32_t, UIDNAInfo*, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uidna.h</td><td class="proto">int32_t uidna_nameToUnicodeUTF8(const UIDNA*, const char*, int32_t, char*, int32_t, UIDNAInfo*, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uidna.h</td><td class="proto">void uidna_close(UIDNA*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uloc.h</td><td class="proto"><tt>#define</tt> ULOC_KEYWORD_ASSIGN_UNICODE</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uloc.h</td><td class="proto"><tt>#define</tt> ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uloc.h</td><td class="proto"><tt>#define</tt> ULOC_KEYWORD_SEPARATOR_UNICODE</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uloc.h</td><td class="proto">const char* const uloc_getISOCountries()</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.0</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uloc.h</td><td class="proto">const char* const uloc_getISOLanguages()</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.0</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">unorm2.h</td><td class="proto">int32_t unorm2_getDecomposition(const UNormalizer2*, UChar32, UChar*, int32_t, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">unum.h</td><td class="proto"><tt>enum</tt> UNumberFormatSymbol::UNUM_EIGHT_DIGIT_SYMBOL</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">unum.h</td><td class="proto"><tt>enum</tt> UNumberFormatSymbol::UNUM_FIVE_DIGIT_SYMBOL</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">unum.h</td><td class="proto"><tt>enum</tt> UNumberFormatSymbol::UNUM_FOUR_DIGIT_SYMBOL</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">unum.h</td><td class="proto"><tt>enum</tt> UNumberFormatSymbol::UNUM_NINE_DIGIT_SYMBOL</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">unum.h</td><td class="proto"><tt>enum</tt> UNumberFormatSymbol::UNUM_ONE_DIGIT_SYMBOL</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">unum.h</td><td class="proto"><tt>enum</tt> UNumberFormatSymbol::UNUM_SEVEN_DIGIT_SYMBOL</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">unum.h</td><td class="proto"><tt>enum</tt> UNumberFormatSymbol::UNUM_SIX_DIGIT_SYMBOL</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">unum.h</td><td class="proto"><tt>enum</tt> UNumberFormatSymbol::UNUM_THREE_DIGIT_SYMBOL</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">unum.h</td><td class="proto"><tt>enum</tt> UNumberFormatSymbol::UNUM_TWO_DIGIT_SYMBOL</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uobject.h</td><td class="proto"><tt>#define</tt> UOBJECT_DEFINE_NO_RTTI_IMPLEMENTATION</td><td class="">None<br>
+</td><td>Internal<br>
+<span class=""><span>.</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uregex.h</td><td class="proto">UBool uregex_find64(URegularExpression*, int64_t, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uregex.h</td><td class="proto">UBool uregex_lookingAt64(URegularExpression*, int64_t, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uregex.h</td><td class="proto">UBool uregex_matches64(URegularExpression*, int64_t, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uregex.h</td><td class="proto">UText* uregex_appendTailUText(URegularExpression*, UText*, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uregex.h</td><td class="proto">UText* uregex_groupUText(URegularExpression*, int32_t, UText*, int64_t*, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uregex.h</td><td class="proto">UText* uregex_groupUTextDeep(URegularExpression*, int32_t, UText*, UErrorCode*)</td><td class="">None<br>
+</td><td>Internal<br>
+<span class=""><span>4.4 technology preview</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uregex.h</td><td class="proto">int64_t uregex_end64(URegularExpression*, int32_t, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uregex.h</td><td class="proto">int64_t uregex_regionEnd64(const URegularExpression*, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uregex.h</td><td class="proto">int64_t uregex_regionStart64(const URegularExpression*, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uregex.h</td><td class="proto">int64_t uregex_start64(URegularExpression*, int32_t, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uregex.h</td><td class="proto">void uregex_getFindProgressCallback(const URegularExpression*, URegexFindProgressCallback**, const void**, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uregex.h</td><td class="proto">void uregex_reset64(URegularExpression*, int64_t, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uregex.h</td><td class="proto">void uregex_setFindProgressCallback(URegularExpression*, URegexFindProgressCallback*, const void*, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uregex.h</td><td class="proto">void uregex_setRegion64(URegularExpression*, int64_t, int64_t, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uregex.h</td><td class="proto">void uregex_setRegionAndStart(URegularExpression*, int64_t, int64_t, int64_t, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uscript.h</td><td class="proto">UBool uscript_hasScript(UChar32, UScriptCode)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_BASSA_VAH</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_DUPLOYAN_SHORTAND</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_ELBASAN</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_GRANTHA</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_KPELLE</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_LOMA</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_MANDAIC</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row0">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_MENDE</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_MEROITIC_CURSIVE</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_MEROITIC_HIEROGLYPHS</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>4.6</span></span></td><td class="bornstable"><b class="bigwarn" title="A new API was introduced as stable in $rightVer.">(Born Stable)</b></td>
+</tr>
+<tr class="row1">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_NABATAEAN</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_OLD_NORTH_ARABIAN</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_PALMYRENE</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_SINDHI</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">uscript.h</td><td class="proto"><tt>enum</tt> UScriptCode::USCRIPT_WARANG_CITI</td><td class="">None<br>
+</td><td>Stable<br>
+<span class=""><span>2.2</span></span></td>
+</tr>
+<tr class="row0">
+<td class="file">uscript.h</td><td class="proto">int32_t uscript_getScriptExtensions(UChar32, UScriptCode*, int32_t, UErrorCode*)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+<tr class="row1">
+<td class="file">vtzone.h</td><td class="proto"><tt>static</tt> VTimeZone* VTimeZone::createVTimeZoneFromBasicTimeZone(const BasicTimeZone&amp;, UErrorCode&amp;)</td><td class="">None<br>
+</td><td>Draft<br>
+<span class=""><span>4.6</span></span></td>
+</tr>
+</table>
+<P></P>
+<a href="#_top">(jump back to top)</a>
+<hr>
+<a name="other"></a>
+<h2>Other existing drafts in 4.6</h2>
+<div class="other">
+<table BORDER="1" class="genTable">
+<THEAD>
+<tr>
+<th>File</th><th>API</th><th>4.4.2</th><th>4.6</th>
+</tr>
+</THEAD>
+<tr class="row1">
+<td class="file">dcfmtsym.h</td><td class="proto">const UnicodeString&amp; DecimalFormatSymbols::getPatternForCurrencySpacing(ECurrencySpacing, UBool, UErrorCode&amp;) const</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">dcfmtsym.h</td><td class="proto"><tt>enum</tt> 
+							DecimalFormatSymbols::ECurrencySpacing {}</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">dcfmtsym.h</td><td class="proto"><tt>enum</tt> 
+							DecimalFormatSymbols::ECurrencySpacing::kCurrencyMatch</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">dcfmtsym.h</td><td class="proto"><tt>enum</tt> 
+							DecimalFormatSymbols::ECurrencySpacing::kCurrencySpacingCount</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">dcfmtsym.h</td><td class="proto"><tt>enum</tt> 
+							DecimalFormatSymbols::ECurrencySpacing::kInsert</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">dcfmtsym.h</td><td class="proto"><tt>enum</tt> 
+							DecimalFormatSymbols::ECurrencySpacing::kSurroundingMatch</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">dcfmtsym.h</td><td class="proto">void DecimalFormatSymbols::setPatternForCurrencySpacing(ECurrencySpacing, UBool, const UnicodeString&amp;)</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">numfmt.h</td><td class="proto"><tt>enum</tt> 
+							NumberFormat::EStyles {}</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">numfmt.h</td><td class="proto"><tt>enum</tt> 
+							NumberFormat::EStyles::kCurrencyStyle</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">numfmt.h</td><td class="proto"><tt>enum</tt> 
+							NumberFormat::EStyles::kIsoCurrencyStyle</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">numfmt.h</td><td class="proto"><tt>enum</tt> 
+							NumberFormat::EStyles::kNumberStyle</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">numfmt.h</td><td class="proto"><tt>enum</tt> 
+							NumberFormat::EStyles::kPercentStyle</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">numfmt.h</td><td class="proto"><tt>enum</tt> 
+							NumberFormat::EStyles::kPluralCurrencyStyle</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">numfmt.h</td><td class="proto"><tt>enum</tt> 
+							NumberFormat::EStyles::kScientificStyle</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">numfmt.h</td><td class="proto"><tt>enum</tt> 
+							NumberFormat::EStyles::kStyleCount</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">numfmt.h</td><td class="proto"><tt>static</tt> NumberFormat* NumberFormat::createInstance(const Locale&amp;, EStyles, UErrorCode&amp;)</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">tmutfmt.h</td><td class="proto">TimeUnitFormat::TimeUnitFormat(const Locale&amp;, EStyle, UErrorCode&amp;)</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">tmutfmt.h</td><td class="proto"><tt>enum</tt> 
+							TimeUnitFormat::EStyle {}</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">tmutfmt.h</td><td class="proto"><tt>enum</tt> 
+							TimeUnitFormat::EStyle::kAbbreviate</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">tmutfmt.h</td><td class="proto"><tt>enum</tt> 
+							TimeUnitFormat::EStyle::kFull</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">tmutfmt.h</td><td class="proto"><tt>enum</tt> 
+							TimeUnitFormat::EStyle::kTotal</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">uloc.h</td><td class="proto">int32_t uloc_forLanguageTag(const char*, char*, int32_t, int32_t*, UErrorCode*)</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row1">
+<td class="file">uloc.h</td><td class="proto">int32_t uloc_toLanguageTag(const char*, char*, int32_t, UBool, UErrorCode*)</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">uregex.h</td><td class="proto"><tt>enum</tt> URegexpFlag::UREGEX_CANON_EQ</td><td class="" colspan="2" align="center">Draft<br>2.4</td>
+</tr>
+<tr class="row1">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> SHAPE_TAIL_NEW_UNICODE</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+<tr class="row0">
+<td class="file">ushape.h</td><td class="proto"><tt>#define</tt> SHAPE_TAIL_TYPE_MASK</td><td class="" colspan="2" align="center">Draft<br>4.2</td>
+</tr>
+</table>
+</div>
+<P></P>
+<a href="#_top">(jump back to top)</a>
+<hr>
+<p>
+<i><font size="-1">Contents generated by StableAPI (r28926:28990M) tool on Tue Nov 16 14:28:50 PST 2010<br>Copyright (C) 2010, International Business Machines Corporation, All Rights Reserved.</font></i>
+</p>
+</body>
+</html>
diff --git a/as_is/os390/unpax-icu.sh b/as_is/os390/unpax-icu.sh
new file mode 100755
index 0000000..f13d8c1
--- /dev/null
+++ b/as_is/os390/unpax-icu.sh
@@ -0,0 +1,102 @@
+#!/bin/sh
+# Copyright (C) 2001-2010, International Business Machines
+#   Corporation and others.  All Rights Reserved.
+#
+# Authors:
+# Ami Fixler
+# Steven R. Loomis
+# George Rhoten
+#
+# Shell script to unpax ICU and convert the files to an EBCDIC codepage.
+# After extracting to EBCDIC, binary files are re-extracted without the
+# EBCDIC conversion, thus restoring them to original codepage.
+#
+# Set the following variable to the list of binary file suffixes (extensions)
+
+#binary_suffixes='ico ICO bmp BMP jpg JPG gif GIF brk BRK'
+#ICU specific binary files
+binary_suffixes='brk BRK bin BIN res RES cnv CNV dat DAT icu ICU spp SPP xml XML nrm NRM'
+
+usage()
+{
+    echo "Enter archive filename as a parameter: $0 icu-archive.tar"
+}
+# first make sure we at least one arg and it's a file we can read
+if [ $# -eq 0 ]; then
+    usage
+    exit
+fi
+tar_file=$1
+if [ ! -r $tar_file ]; then
+    echo "$tar_file does not exist or cannot be read."
+    usage
+    exit
+fi
+
+echo ""
+echo "Extracting from $tar_file ..."
+echo ""
+# extract files while converting them to EBCDIC
+pax -rvf $tar_file -o to=IBM-1047,from=ISO8859-1 -o setfiletag
+
+echo ""
+echo "Determining binary files ..."
+echo ""
+
+# When building in ASCII mode, text files are converted as ASCII
+if [ "${ICU_ENABLE_ASCII_STRINGS}" -eq 1 ]; then
+    binary_suffixes="$binary_suffixes txt TXT ucm UCM"
+else
+	for file in `find ./icu \( -name \*.txt -print \) | sed -e 's/^\.\///'`; do
+		bom8=`head -c 3 $file|\
+			od -t x1|\
+			head -n 1|\
+			sed 's/  */ /g'|\
+			cut -f2-4 -d ' '|\
+			tr 'A-Z' 'a-z'`;
+		#Find a converted UTF-8 BOM
+		if [ "$bom8" = "57 8b ab" ]
+		then
+			binary_files="$binary_files $file";
+		fi
+	done
+fi
+
+for i in $(pax -f $tar_file 2>/dev/null)
+do
+	case $i in
+	*/) ;;		# then this entry is a directory
+	*.*)		# then this entry has a dot in the filename
+		for j in $binary_suffixes
+		do
+			# We substitute the suffix more than once
+			# to handle files like NormalizationTest-3.2.0.txt
+			suf=${i#*.*}
+			suf=${suf#*.*}
+			suf=${suf#*.*}
+			if [ "$suf" = "$j" ]
+			then
+				binary_files="$binary_files $i"
+				break
+			fi
+		done
+		;;
+	*) ;;		# then this entry does not have a dot in it
+    esac
+done
+
+# now see if a re-extract of binary files is necessary
+if [ ${#binary_files} -eq 0 ]; then
+    echo ""
+    echo "There are no binary files to restore."
+else
+    echo "Restoring binary files ..."
+    echo ""
+    rm $binary_files
+    pax -rvf $tar_file $binary_files
+    # Tag the files as binary for proper interaction with the _BPXK_AUTOCVT
+    # environment setting
+    chtag -b $binary_files
+fi
+echo ""
+echo "$0 has completed extracting ICU from $tar_file."
diff --git a/as_is/os400/convertConfigure.sed b/as_is/os400/convertConfigure.sed
new file mode 100644
index 0000000..6231958
--- /dev/null
+++ b/as_is/os400/convertConfigure.sed
@@ -0,0 +1,32 @@
+# Copyright (C) 2006-2009, International Business Machines Corporation
+# and others.  All Rights Reserved.
+#
+# Use "test -x" instead of "test -f" most of the time.
+# due to how executables are created in a different file system.
+s/as_executable_p="test -f"/as_executable_p="test -x"/g
+s/test -f "$ac_file"/test -x "$ac_file"/g
+s/test -f $ac_dir\/install-sh/test -x $ac_dir\/install-sh/g
+s/test -f $ac_dir\/install.sh/test -x $ac_dir\/install.sh/g
+s/test -f $ac_dir\/shtool/test -x $ac_dir\/shtool/g
+# Use the more efficient del instead of rm command.
+s/rm[ ]*-r[ ]*-f/del -f/g
+s/rm[ ]*-f[ ]*-r/del -f/g
+s/rm[ ]*-rf/del -f/g
+s/rm[ ]*-fr/del -f/g
+s/rm[ ]*-f/del -f/g
+##don't clean up some awks for debugging
+#s/[ ]*del -f [^ ]*.awk/#&/
+# Borne shell isn't always available on i5/OS
+s/\/bin\/sh/\/usr\/bin\/qsh/g
+# no diff in qsh the equivalent is cmp
+s/ diff / cmp -s /g
+## srl
+# trouble w/ redirects.
+s% >&$3%%g
+s%^ac_cr=%# AWK reads ASCII, not EBCDIC\
+touch -C 819 $tmp/defines.awk $tmp/subs.awk $tmp/subs1.awk conf$$subs.awk\
+\
+&%
+##OBSOLETE
+#(REPLACED BY CPP in runConfigureICU) Use -c qpponly instead of -E to enable the preprocessor on the compiler
+#s/\$CC -E/\$CC -c -qpponly/g
diff --git a/as_is/os400/unpax-icu.sh b/as_is/os400/unpax-icu.sh
new file mode 100755
index 0000000..b58308f
--- /dev/null
+++ b/as_is/os400/unpax-icu.sh
@@ -0,0 +1,195 @@
+#!/usr/bin/qsh
+#   Copyright (C) 2000-2010, International Business Machines
+#   Corporation and others.  All Rights Reserved.
+#
+# Authors:
+# Ami Fixler
+# Barry Novinger
+# Steven R. Loomis
+# George Rhoten
+# Jason Spieth
+#
+# Shell script to unpax ICU and convert the files to an EBCDIC codepage.
+# After extracting to EBCDIC, binary files are re-extracted without the
+# EBCDIC conversion, thus restoring them to original codepage.
+
+if [ -z "$QSH_VERSION" ];
+then
+	QSH=0
+    echo "QSH not detected (QSH_VERSION not set) - just testing."
+else
+	QSH=1
+	#echo "QSH version $QSH_VERSION"
+fi
+export QSH
+
+# Set the following variable to the list of binary file suffixes (extensions)
+
+
+#****************************************************************************
+#binary_suffixes='ico ICO bmp BMP jpg JPG gif GIF brk BRK'
+#ICU specific binary files
+#****************************************************************************
+binary_suffixes='brk BRK bin BIN res RES cnv CNV dat DAT icu ICU spp SPP xml XML nrm NRM'
+data_files='icu/source/data/brkitr/* icu/source/data/locales/* icu/source/data/coll/* icu/source/data/rbnf/* icu/source/data/mappings/* icu/source/data/misc/* icu/source/data/translit/* icu/source/data/unidata/* icu/source/test/testdata/*'
+
+#****************************************************************************
+# Function:     usage
+# Description:  Prints out text that describes how to call this script
+# Input:        None
+# Output:       None
+#****************************************************************************
+usage()
+{
+  echo "Enter archive filename as a parameter: $0 icu-archive.tar"
+}
+
+#****************************************************************************
+# first make sure we at least one arg and it's a file we can read
+#****************************************************************************
+
+# check for no arguments
+if [ $# -eq 0 ]; then
+  usage
+  exit
+fi
+
+# tar file is argument 1
+tar_file=$1
+
+# check that the file is valid
+if [ ! -r $tar_file ]; then
+  echo "$tar_file does not exist or cannot be read."
+  usage
+  exit
+fi
+
+#****************************************************************************
+# Determine which directories in the data_files list
+# are included in the provided archive
+#****************************************************************************
+echo "Finding data_files ..."
+for data_dir in $data_files
+do
+   if (pax -f $tar_file $data_dir >/dev/null 2>&1)
+   then
+       ebcdic_data="$ebcdic_data `echo $data_dir`";
+   fi
+done
+
+#****************************************************************************
+# Extract files.  We do this in two passes.  One pass for 819 files and a
+# second pass for 37 files
+#****************************************************************************
+echo ""
+echo "Extracting from $tar_file ..."
+echo ""
+
+# extract everything as iso-8859-1 except these directories
+pax -C 819 -rcvf $tar_file $ebcdic_data
+
+# extract files while converting them to EBCDIC
+echo ""
+echo "Extracting files which must be in ibm-37 ..."
+echo ""
+pax -C 37 -rvf $tar_file $ebcdic_data
+
+#****************************************************************************
+# For files we have restored as CCSID 37, check the BOM to see if they    
+# should be processed as 819.  Also handle files with special paths. Files
+# that match will be added to binary files lists.  The lists will in turn
+# be processed to restore files as 819.
+#****************************************************************************
+echo ""
+echo "Determining binary files by BOM ..."
+echo ""
+bin_count=0
+# Process BOMs
+for file in `find ./icu \( -name \*.txt -print \)`; do
+    bom8=`head -n 1 $file|\
+          od -t x1|\
+          head -n 1|\
+          sed 's/  */ /g'|\
+          cut -f2-4 -d ' '|\
+          tr 'A-Z' 'a-z'`;
+    #Find a converted UTF-8 BOM
+    if [ "$bom8" = "057 08b 0ab" -o "$bom8" = "57 8b ab" ]
+    then
+        file="`echo $file | cut -d / -f2-`"
+
+        if [ `echo $binary_files | wc -w` -lt 200 ]
+        then
+            bin_count=`expr $bin_count + 1`
+            binary_files="$binary_files $file";
+        else
+            echo "Restoring binary files by BOM ($bin_count)..."
+            rm $binary_files;
+            pax -C 819 -rvf $tar_file $binary_files;
+            echo "Determining binary files by BOM ($bin_count)..."
+            binary_files="$file";
+            bin_count=`expr $bin_count + 1`
+        fi
+    fi
+done
+
+# Process special paths
+for i in $(pax -f $tar_file 2>/dev/null)
+do
+  case $i in
+    */)
+#    then this entry is a directory
+     ;;
+    *.*)
+#    then this entry has a dot in the filename
+     for j in $binary_suffixes
+     do
+       suf=${i#*.*}
+       if [ "$suf" = "$j" ]
+       then
+
+         if [ `echo $binary_files | wc -w` -lt 200 ]
+         then
+            binary_files="$binary_files $i";
+            bin_count=`expr $bin_count + 1`
+         else
+            echo "Restoring binary files by special paths ($bin_count) ..."
+            rm $binary_files;
+            pax -C 819 -rvf $tar_file $binary_files;
+            echo "Determining binary files by special paths ($bin_count) ..."
+            binary_files="$i";
+            bin_count=`expr $bin_count + 1`
+         fi
+         break
+       fi
+     done
+     ;;
+    *)
+#    then this entry does not have a dot in it
+     ;;
+  esac
+done
+
+# now see if a re-extract of binary files is necessary
+if [ `echo $binary_files | wc -w` -gt 0 ]
+then
+  echo "Restoring binary files ($bin_count) ..."
+  rm $binary_files
+  pax -C 819 -rvf $tar_file $binary_files
+fi
+
+#****************************************************************************
+# Generate and run the configure script
+#****************************************************************************
+
+echo ""
+echo "Generating qsh compatible configure ..."
+echo ""
+
+sed -f icu/as_is/os400/convertConfigure.sed icu/source/configure > icu/source/configureTemp
+del -f icu/source/configure
+mv icu/source/configureTemp icu/source/configure
+chmod 755 icu/source/configure
+
+echo ""
+echo "$0 has completed extracting ICU from $tar_file - $bin_count binary files extracted."
+
diff --git a/icu4c.css b/icu4c.css
new file mode 100644
index 0000000..1594c65
--- /dev/null
+++ b/icu4c.css
@@ -0,0 +1,472 @@
+/*
+ * Default CSS style sheet for the ICU4C Open Source readme
+ * Copyright (C) 2005-2010, International Business Machines
+ * Corporation and others.  All Rights Reserved.
+ */
+
+/* Global styles */
+
+body,p,li,ol,ul,th,td {
+	font-size: 1em;
+	font-family: "Arial", "Helvetica", sans-serif;
+}
+
+body {
+	margin: 1em;
+}
+
+body.draft {
+	background-image: url(images/draftbg.png);
+}
+
+.mainbody {
+	padding: 1em;
+}
+
+/*
+ * Customize the headers to have less space around them than usual
+ */
+
+h1 {
+	margin-bottom: .5em;
+	margin-top: .5em;
+	padding-bottom: .5em;
+	padding-top: .5em;
+	font-weight: 700;
+	font-size: 20pt;
+	font-family: Georgia, "Times New Roman", Times, serif;
+	border-width: 2px;
+	border-style: solid;
+	text-align: center;
+	width: 100%;
+	font-size: 200%;
+	font-weight: bold;
+}
+
+h2 {
+	border-top: 2px solid #22d;
+	border-left: 2px solid #22d;
+	margin-bottom: 0.5em;
+	padding-left: 4px;
+	margin-top: 12pt;
+	font-weight: 700;
+	font-size: 2em;
+	font-family: Georgia, "Times New Roman", Times, serif;
+	background-color: #eee;
+	page-break-before: always;
+}
+
+h2 a {
+	text-decoration: none;
+	color: black;
+}
+
+h2 a:hover {
+	color: blue;
+	text-decoration: underline;
+}
+
+h3 {
+	border-top: 1px solid gray;
+	color: #1e1c46;
+	margin-bottom: 0pt;
+	margin-top: 12pt;
+	padding-left: 0;
+	margin-left: 1em;
+	margin-top: 0.2em;
+	padding-bottom: 0.4em;
+	font-size: 1.5em;
+	font-family: Georgia, "Times New Roman", Times, serif;
+}
+
+h3 a {
+	text-decoration: none;
+	color: black;
+}
+
+h3 a:hover {
+	color: blue;
+	text-decoration: underline;
+}
+
+h4 {
+	margin-left: 1.5em;
+	margin-bottom: 0pt;
+	margin-top: 12pt;
+	font-size: 1.0em;
+	font-weight: bolder;
+	font-family: Georgia, "Times New Roman", Times, serif;
+}
+
+h4 a {
+	text-decoration: none;
+	color: black;
+}
+
+h4 a:hover {
+	color: blue;
+	text-decoration: underline;
+}
+
+h5, h6 {
+	margin-left: 1.8em;
+	margin-bottom: 0pt;
+	margin-top: 12pt;
+	padding-left: 0.75em;
+	font-size: x-small;
+	font-family: Georgia, "Times New Roman", Times, serif;
+}
+
+p,pre,table,ul,ol,dl {
+	margin-left: 2em;
+}
+
+/*
+ * Navigation sidebar on the left hand of most pages
+ */
+
+td.sidebar1 {
+	background-color: #99CCFF;
+	font-weight: 700;
+	margin-top: 0px;
+	margin-bottom: 0px;
+	padding-top: 1em;
+	padding-left: 0.2em;
+	white-space: nowrap;
+}
+
+td.sidebar2 {
+	background-color: #99CCFF;
+	margin-top: 0px;
+	margin-bottom: 0px;
+	margin-left: 0px;
+	padding-top: 1px;
+	padding-bottom: 1px;
+	padding-left: 1px;
+	padding-right: 0.5em;
+	white-space: nowrap;
+	text-decoration: none;
+	display: block;
+}
+
+td.sidebar2:hover {
+	background-color: #EEEEFF;
+	padding-top: 1px;
+	padding-bottom: 1px;
+	padding-left: 1px;
+	padding-right: 0.5em;
+}
+
+a.sidebar2 {
+	text-decoration: none;
+	display: block;
+	width: 100%;
+}
+
+a.sidebar2:link {
+	color: #000099;
+	display: block;
+}
+
+a.sidebar2:hover {
+	background-color: #EEEEFF;
+	display: block;
+}
+
+.underlinehover:hover {
+	background-color: #EEEEFF;
+	text-decoration: underline;
+}
+
+/* This is the faded header at the top */
+
+td.fadedtop {
+	background-color: #006699;
+	background-image: url(http://www.icu-project.org/images/gr100.gif);
+}
+
+/* Related site on the left */
+
+p.relatedsite {
+	color: White;
+	font-weight: 700;
+	font-size: 10pt;
+	margin-top: 1em;
+	margin-bottom: 0;
+	padding-left: 0.2em;
+	white-space: nowrap;
+}
+
+/* Related site on the left */
+
+p.sidebar3 {
+	margin-top: 0.75em;
+	margin-bottom: 0;
+	padding-left: 0.8em;
+}
+
+a.sidebar3 {
+	font-size: 0.9em;
+	text-decoration: none;
+}
+
+a.sidebar3:link {
+	text-decoration: none;
+	color: White;
+}
+
+a.sidebar3:hover {
+	text-decoration: underline;
+}
+
+/* FAQ */
+
+li.faq_contents {
+	font-weight: 500;
+}
+
+p.faq_q {
+	font-weight: 700;
+	margin-bottom: 0px;
+}
+
+p.faq_a {
+	margin-top: 0px;
+}
+
+/* News items */
+
+table.newsItem {
+	padding-left: 1em;
+	padding-right: 1em;
+	border-width: medium;
+}
+
+th.newsItem {
+	background-color: #666666;
+	color: White;
+}
+
+td.newsItem {
+	background-color: #CCCCCC;
+}
+
+td.release-line,th.release-line {
+	padding-left: 0.5em;
+	padding-right: 0.5em;
+	white-space: nowrap;
+	border: 1px;
+}
+
+.note {
+	font-style: italic;
+	font-size: small;
+	margin-left: 1em;
+}
+
+samp {
+	margin-left: 1em;
+	margin-right: 2em;
+	border-style: groove;
+	padding: 1em;
+	display: block;
+	background-color: #EEEEEE
+}
+
+table.rtable caption {
+	margin-left: 2px;
+	margin-right: 2px;
+	padding: 3px;
+	font-weight: bold;
+	background-color: #dee2ff;
+	text-align: left;
+}
+
+table.rtable tr th {
+	background-color: #dee2ff;
+	text-align: left;
+}
+
+table.rtable tr td {
+	background-color: #c0c0fd;
+	padding: 3px;
+}
+
+table.rtable tr.broken td {
+	background-color: #fbb;
+	border: 1px dashed gray;
+	padding: 3px;
+	font-weight: bold;
+}
+
+table.rtable tr.rarely td {
+	background-color: #efe9c2;
+	padding: 3px;
+	font-style: italic;
+}
+
+/*  APIChangeReport specific things */
+
+.row0 {
+	background-color: white;
+}
+
+.row1 {
+	background-color: #dfd;
+}
+
+.verchange {
+	color: red;
+	font-weight: bold;
+	font-size: large;
+}
+
+.stabchange {
+	color: red;
+	font-size: large;
+}
+
+.bigwarn {
+	color: red;
+	background-color: white;
+	font-size: large;
+	margin: 0.5 em;
+}
+
+
+td.bornstable {
+	
+}
+td.bornstable .bigwarn {
+	font-size: small;
+	white-space: nowrap;
+}
+
+table.genTable {
+	border-collapse: collapse;
+	border: 1px solid black;
+}
+
+/* 'everything inc version */
+
+table.gentable td {
+	border: 1px solid gray;
+	padding: 0.25em;
+	font-size: small;
+}
+
+/* not version */
+
+table.genTable td.file,
+table.genTable td.proto {
+	border: none;
+	font-size: medium;
+}
+
+table.genTable td.file {
+	font-family: monospace;
+	font-weight: bold;
+}
+
+div.other .row0 {
+	background-color: white;
+}
+
+div.other .row1 {
+	background-color: #ddf;
+}
+
+table.docTable {
+	border-collapse: collapse;
+	border: 1px solid black;
+}
+
+/* 'everything inc version */
+
+table.docTable td,
+table.docTable th {
+	border: 1px solid gray;
+	padding: 0.25em;
+	font-size: small;
+}
+
+/* not version */
+
+table.docTable td.file,
+table.docTable td.proto {
+	border: none;
+	font-size: medium;
+}
+
+table.docTable td.file {
+	font-family: monospace;
+	font-weight: bold;
+}
+
+abbr {
+	border-bottom: 1px dashed #0B0;
+}
+
+h2.TOC {
+	page-break-before: auto;
+}
+
+body.readme {
+	
+}
+
+caption {
+	font-weight: bold;
+	text-align: left
+}
+
+div.indent {
+	margin-left: 2em
+}
+
+ul.TOC {
+	list-style-type: none;
+	padding-left: 1em;
+	font-size: larger;
+}
+
+ul.TOC li a {
+	font-weight: bold;
+}
+
+ul.TOC li ul li a {
+	font-weight: normal;
+	list-style-type: none;
+	font-size: small;
+}
+
+ul.TOC li ul {
+	margin-left: 0;
+	padding-left: 2em;
+	font-weight: normal;
+	list-style-type: none;
+}
+
+pre.samp,samp {
+	margin-left: 1em;
+	border-style: groove;
+	padding: 1em;
+	display: block;
+	background-color: #EEEEEE
+}
+
+td.proto {
+	font-size: smaller;
+}
+
+
+
+@media print {
+	div#toc {
+		display: none;
+	}
+	
+	table,tr,td,div {
+		page-break-inside: auto;
+	}
+}
diff --git a/license.html b/license.html
new file mode 100644
index 0000000..1e2b1ab
--- /dev/null
+++ b/license.html
@@ -0,0 +1,51 @@
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii"></meta>
+<title>ICU License - ICU 1.8.1 and later</title>
+</head>
+
+<body BGCOLOR="#ffffff">
+<h2>ICU License - ICU 1.8.1 and later</h2>
+
+<p>COPYRIGHT AND PERMISSION NOTICE</p>
+
+<p>
+Copyright (c) 1995-2011 International Business Machines Corporation and others
+</p>
+<p>
+All rights reserved.
+</p>
+<p>
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, and/or sell
+copies of the Software, and to permit persons
+to whom the Software is furnished to do so, provided that the above
+copyright notice(s) and this permission notice appear in all copies
+of the Software and that both the above copyright notice(s) and this
+permission notice appear in supporting documentation.
+</p>
+<p>
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL
+THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM,
+OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
+USE OR PERFORMANCE OF THIS SOFTWARE.
+</p>
+<p>
+Except as contained in this notice, the name of a copyright holder shall not be
+used in advertising or otherwise to promote the sale, use or other dealings in
+this Software without prior written authorization of the copyright holder.
+</p>
+
+<hr>
+<p><small>
+All trademarks and registered trademarks mentioned herein are the property of their respective owners.
+</small></p>
+</body>
+</html>
diff --git a/packaging/PACKAGES b/packaging/PACKAGES
new file mode 100644
index 0000000..12b3523
--- /dev/null
+++ b/packaging/PACKAGES
@@ -0,0 +1,159 @@
+Copyright (C) 2000-2003, International Business Machines
+Corporation and others.  All Rights Reserved.
+ICU is packaged into a number of small, interdependent packages. This
+file describes what these packages are, what their name should be
+like, and what their contents are. It is useful as a reference and a
+guide when packaging ICU on a new system.
+
++ List of ICU packages.
+
+ICU is distributed as the following packages:
+
+- ICU libraries. This package contains the runtime libraries needed by
+applications that use ICU. All the other packages require this package
+to be installed.
+- ICU. This package contains the converters data, the timezones data,
+and all the ICU tools.
+- ICU locales. This package adds locales and break data.
+- ICU development. This package contains the files necessary to build
+applications that use ICU, i.e. header files, links to shared
+libraries used by the linker, static libraries, etc... It also
+contains sample applications and documentation.
+- ICU docs. This package contains further documentation for ICU,
+including a complete API reference.
+- ICU data. This package contains the source for the compiled data
+contained by the ICU package.
+- ICU international data. This package contains the source for the
+compiled data contained by the ICU locales package.
+
+In this file, we will refer to Autoconf variables as in $(bindir). In
+addition to these, we will use the following variables to denote
+ICU-specific directories or information:
+
+  VERSION       ICU's dotted version number, e.g. 1.6.0.1 as of this
+		writing.
+
+  ICUDATADIR	The directory where portable ICU data are. This is
+	        defined as $(datadir)/icu/$(VERSION).
+  ICULIBDIR	The directory where platform-specific ICU data
+		are. This is defined as $(libdir)/icu/$(VERSION).
+  ICUSYSCONFDIR	The directory where ICU configuration files are. This
+		is defined as $(sysconfdir)/icu.
+
+When referring to libraries, .so will be used to denote the extension
+of a shared library, and .a to denote the extension of a static
+library. These extensions will actually be different on some platforms.
+
++ Configuration and compilation of ICU
+
+ICU should be configured with the following options:
+
+  --with-data-packaging=files
+  --disable-rpath
+  --enable-shared
+  --enable-static
+  --without-samples
+
+in addition to platform-specific settings (like a specific mandir or
+sysconfdir). Note that the use of --disable-rpath assumes that the
+packaging is made for a standard location, or that the package
+installation/deinstallation will correctly manage the configuration
+of the system's dyanmic loader. This is the right way of doing things.
+
+The configure script invokation should also be done with
+
+  CFLAGS="-O2"
+
+set, as in:
+
+  $ CFLAGS="-O2" ./configure ...
+
+The files packaging mode is chosen because it offers the maximum
+flexibility. Packages can be split easily, and system administrators
+can add converters, aliases, and other resources with little
+effort. Ideally, the ICU build will be modified to allow for distributing a
+libicudata.so with all the converters and locales, but indexes and aliases
+as separate files. But for now, this is the easiest way to get started.
+
++ The ICU libraries package
+
+The ICU libraries package is typically named `libicuXX' where XX is
+the major number of ICU's libraries. This number is ICU's version
+number multiplied by 10 and rounded down to the nearest integer (it is
+also the value of the LIB_VERSION_MAJOR configure substitution
+variable). For example, for ICU 1.6.0.1, it is 16, so the package name
+is `libicu16'. The major version is part of the package name to allow
+for the simultaneous installation of different ICU releases.
+
+This package contains:
+
+- All the shared libraries, and their major number symbolic link, but
+not the .so symbolic link that is only used at link time (this one is
+part of the development package). These are $(libdir)/libicu*.so.* and
+$(libdir)/libustdio.so.* at the time of this writing.
+
++ The ICU package
+
+The ICU package is simply named `icu'.  It provides data used by the ICU
+libraries package and commands to create and manipulate that data.
+
+This package contains:
+
+- The Unicode data files (uprops.dat and unames.dat as of this writing).
+- The time zones data files (tz.dat).
+- All the binary data files for converters (.cnv files).
+- All the ICU commands.
+- The manual pages for ICU commands and file formats.
+
++ The ICU locales package
+
+The ICU locales package is named `icu-locales'. It provides data used by
+internationalization support in ICU.
+
+This package contains:
+
+- All the data for locales in ICU (.dat files).
+- All the break data for specific locales (.brk files).
+
++ The ICU development package
+
+The ICU developpment package is named `libicu-dev'. It provides all
+the files necessary to write applications that use ICU, along with
+examples and some documentation.
+
+This package contains:
+
+- The /usr/include/unicode directory which contains all the ICU
+headers.
+- The .so symbolic links used by the linker to link against the
+latest version of the libraries.
+- A sample Makefile fragment that can be included by applications
+using ICU, to faciliate their building, along with a platform-specific
+configuration file included by this fragment.
+- The sample applications from the ICU source tree, in an appropriate
+location for the system that the package is installed on (for example,
+on Debian, in /usr/share/doc/libicu-dev/examples).
+
+This package depends on the ICU libraries package with the exact same
+version, since it provides .so symbolic links to the latest libraries.
+
++ The ICU docs package
+
+The ICU docs package is named `libicu-doc'. It contains the files
+generated by doxygen when the `make doc' command is executed, in a
+location appropriate for the system that the package is installed on.
+
++ The ICU data package
+
+The ICU data package is named `icu-data'. It contains source files for
+the data found in the ICU package. These files are installed in
+$(ICUDATADIR).
+
++ The ICU international data package
+
+The ICU data package is named `icu-i18ndata'. It contains source files for
+the dat founf in the ICU locales package. These files are installed in
+$(ICUDATADIR).
+
+----
+Yves Arrouye <yves@realnames.com>
diff --git a/packaging/README b/packaging/README
new file mode 100644
index 0000000..1bfe85a
--- /dev/null
+++ b/packaging/README
@@ -0,0 +1,13 @@
+Copyright (C) 2000-2003, International Business Machines
+Corporation and others.  All Rights Reserved.
+
+This directory contains information, input files and scripts for
+packaging ICU using specific packaging tools. We assume that the
+packager is familiar with the tools and procedures needed to build a
+package for a given packaging method (for example, how to use
+dpkg-buildpackage(1) on Debian GNU/Linux, or rpm(8) on distributions that
+use RPM packages).
+
+Please read the file PACKAGES if you are interested in packaging ICU
+yourself. It describes what the different packages should be, and what
+their contents are.
diff --git a/packaging/rpm/icu.spec b/packaging/rpm/icu.spec
new file mode 100644
index 0000000..6a1e63b
--- /dev/null
+++ b/packaging/rpm/icu.spec
@@ -0,0 +1,228 @@
+#   Copyright (C) 2000-2005, International Business Machines
+#   Corporation and others.  All Rights Reserved.
+#
+# RPM specification file for ICU.
+#
+# Neal Probert <nprobert@walid.com> is the current maintainer.
+# Yves Arrouye <yves@realnames.com> is the original author.
+
+# This file can be freely redistributed under the same license as ICU.
+
+Name: icu
+Version: 3.4
+Release: 1
+Requires: libicu34 >= %{version}
+Summary: International Components for Unicode
+Packager: Ian Holsman (CNET Networks) <ianh@cnet.com>
+Copyright: X License
+Group: System Environment/Libraries
+Source: icu-%{version}.tgz
+BuildRoot: /var/tmp/%{name}-%{version}
+%description
+ICU is a set of C and C++ libraries that provides robust and full-featured
+Unicode and locale support. The library provides calendar support, conversions
+for many character sets, language sensitive collation, date
+and time formatting, support for many locales, message catalogs
+and resources, message formatting, normalization, number and currency
+formatting, time zones support, transliteration, word, line and
+sentence breaking, etc.
+
+This package contains the Unicode character database and derived
+properties, along with converters and time zones data.
+
+This package contains the runtime libraries for ICU. It does
+not contain any of the data files needed at runtime and present in the
+`icu' and `icu-locales` packages.
+
+%package -n libicu34
+Summary: International Components for Unicode (libraries)
+Group: Development/Libraries
+%description -n libicu34
+ICU is a set of C and C++ libraries that provides robust and full-featured
+Unicode support. This package contains the runtime libraries for ICU. It does
+not contain any of the data files needed at runtime and present in the
+`icu' and `icu-locales` packages.
+
+%package -n libicu-devel
+Summary: International Components for Unicode (development files)
+Group: Development/Libraries
+Requires: libicu34 = %{version}
+%description -n libicu-devel
+ICU is a set of C and C++ libraries that provides robust and full-featured
+Unicode support. This package contains the development files for ICU.
+
+%package locales
+Summary: Locale data for ICU
+Group: System Environment/Libraries
+Requires: libicu34 >= %{version}
+%description locales
+The locale data are used by ICU to provide localization (l10n), 
+internationalization (i18n) and timezone support to ICU applications.
+This package also contains break data for various languages,
+and transliteration data.
+
+%post
+# Adjust the current ICU link in /usr/lib/icu
+
+icucurrent=`2>/dev/null ls -dp /usr/lib/icu/* | sed -n 's,.*/\([^/]*\)/$,\1,p'| sort -rn | head -1`
+cd /usr/lib/icu
+rm -f /usr/lib/icu/current
+if test x"$icucurrent" != x
+then
+    ln -s "$icucurrent" current
+fi
+
+#ICU_DATA=/usr/share/icu/%{version}
+#export ICU_DATA
+
+%preun
+# Adjust the current ICU link in /usr/lib/icu
+
+icucurrent=`2>/dev/null ls -dp /usr/lib/icu/* | sed -n -e '/\/%{version}\//d' -e 's,.*/\([^/]*\)/$,\1,p'| sort -rn | head -1`
+cd /usr/lib/icu
+rm -f /usr/lib/icu/current
+if test x"$icucurrent" != x
+then
+    ln -s "$icucurrent" current
+fi
+
+%post -n libicu34
+ldconfig
+
+# Adjust the current ICU link in /usr/lib/icu
+
+icucurrent=`2>/dev/null ls -dp /usr/lib/icu/* | sed -n 's,.*/\([^/]*\)/$,\1,p'| sort -rn | head -1`
+cd /usr/lib/icu
+rm -f /usr/lib/icu/current
+if test x"$icucurrent" != x
+then
+    ln -s "$icucurrent" current
+fi
+
+%preun -n libicu34
+# Adjust the current ICU link in /usr/lib/icu
+
+icucurrent=`2>/dev/null ls -dp /usr/lib/icu/* | sed -n -e '/\/%{version}\//d' -e 's,.*/\([^/]*\)/$,\1,p'| sort -rn | head -1`
+cd /usr/lib/icu
+rm -f /usr/lib/icu/current
+if test x"$icucurrent" != x
+then
+    ln -s "$icucurrent" current
+fi
+
+%prep
+%setup -q -n icu
+
+%build
+cd source
+chmod a+x ./configure
+CFLAGS="-O3" CXXFLAGS="-O" ./configure --prefix=/usr --sysconfdir=/etc --with-data-packaging=files --enable-shared --enable-static --disable-samples
+echo 'CPPFLAGS += -DICU_DATA_DIR=\"/usr/share/icu/%{version}\"' >> icudefs.mk
+make RPM_OPT_FLAGS="$RPM_OPT_FLAGS"
+
+%install
+rm -rf $RPM_BUILD_ROOT
+cd source
+make install DESTDIR=$RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+%doc readme.html
+%doc license.html
+/usr/share/icu/%{version}/license.html
+/usr/share/icu/%{version}/icudt34l/*.cnv
+/usr/share/icu/%{version}/icudt34l/*.icu
+/usr/share/icu/%{version}/icudt34l/*.spp
+
+/usr/bin/derb
+/usr/bin/genbrk
+/usr/bin/gencnval
+/usr/bin/genrb
+/usr/bin/icu-config
+/usr/bin/makeconv
+/usr/bin/pkgdata
+/usr/bin/uconv
+
+/usr/sbin/decmn
+/usr/sbin/genccode
+/usr/sbin/gencmn
+/usr/sbin/gensprep
+/usr/sbin/genuca
+/usr/sbin/icuswap
+/usr/share/icu/%{version}/mkinstalldirs
+
+/usr/man/man1/derb.1.*
+/usr/man/man1/gencnval.1.*
+/usr/man/man1/genrb.1.*
+/usr/man/man1/icu-config.1.*
+/usr/man/man1/makeconv.1.*
+/usr/man/man1/pkgdata.1.*
+/usr/man/man1/uconv.1.*
+/usr/man/man8/decmn.8.*
+/usr/man/man8/genccode.8.*
+/usr/man/man8/gencmn.8.*
+/usr/man/man8/gensprep.8.*
+/usr/man/man8/genuca.8.*
+
+%files -n icu-locales
+/usr/share/icu/%{version}/icudt34l/*.brk
+/usr/share/icu/%{version}/icudt34l/*.res
+/usr/share/icu/%{version}/icudt34l/coll/*.res
+/usr/share/icu/%{version}/icudt34l/rbnf/*.res
+/usr/share/icu/%{version}/icudt34l/translit/*.res
+
+%files -n libicu34
+%doc license.html
+/usr/lib/libicui18n.so.34
+/usr/lib/libicui18n.so.34.0
+/usr/lib/libicutu.so.34
+/usr/lib/libicutu.so.34.0
+/usr/lib/libicuuc.so.34
+/usr/lib/libicuuc.so.34.0
+/usr/lib/libicudata.so.34
+/usr/lib/libicudata.so.34.0
+/usr/lib/libicuio.so.34
+/usr/lib/libicuio.so.34.0
+/usr/lib/libiculx.so.34
+/usr/lib/libiculx.so.34.0
+/usr/lib/libicule.so.34
+/usr/lib/libicule.so.34.0
+
+%files -n libicu-devel
+%doc readme.html
+%doc license.html
+/usr/lib/libicui18n.so
+/usr/lib/libsicui18n.a
+/usr/lib/libicuuc.so
+/usr/lib/libsicuuc.a
+/usr/lib/libicutu.so
+/usr/lib/libsicutu.a
+/usr/lib/libicuio.so
+/usr/lib/libsicuio.a
+/usr/lib/libicudata.so
+/usr/lib/libsicudata.a
+/usr/lib/libicule.so
+/usr/lib/libsicule.a
+/usr/lib/libiculx.so
+/usr/lib/libsiculx.a
+/usr/include/unicode/*.h
+/usr/include/layout/*.h
+/usr/lib/icu/%{version}/Makefile.inc
+/usr/lib/icu/Makefile.inc
+/usr/share/icu/%{version}/config
+/usr/share/doc/icu-%{version}/*
+
+%changelog
+* Mon Jun 07 2004 Alexei Dets <adets@idsk.com>
+- update to 3.0
+* Tue Aug 16 2003 Steven Loomis <srl@jtcsv.com>
+- update to 2.6.1 - include license
+* Thu Jun 05 2003 Steven Loomis <srl@jtcsv.com>
+- Update to 2.6
+* Fri Dec 27 2002 Steven Loomis <srl@jtcsv.com>
+- Update to 2.4 spec
+* Fri Sep 27 2002 Steven Loomis <srl@jtcsv.com>
+- minor updates to 2.2 spec. Rpath is off by default, don't pass it as an option.
+* Mon Sep 16 2002 Ian Holsman <ian@holsman.net> 
+- update to icu 2.2
+
diff --git a/readme.html b/readme.html
new file mode 100644
index 0000000..78d1e06
--- /dev/null
+++ b/readme.html
@@ -0,0 +1,1676 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html lang="en-US" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+  <head>
+
+    <title>ReadMe for ICU 4.6.1</title>
+    <meta name="COPYRIGHT" content=
+    "Copyright (c) 1997-2011 IBM Corporation and others. All Rights Reserved." />
+    <meta name="KEYWORDS" content=
+    "ICU; International Components for Unicode; ICU4C; what's new; readme; read me; introduction; downloads; downloading; building; installation;" />
+    <meta name="DESCRIPTION" content=
+    "The introduction to the International Components for Unicode with instructions on building, installation, usage and other information about ICU." />
+    <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
+	<link type="text/css" href="./icu4c.css" rel="stylesheet"/>
+  </head>
+
+  <body class="draft">
+    <h1>International Components for Unicode<br />
+     <abbr title="International Components for Unicode">ICU</abbr> 4.6.1 ReadMe</h1>
+
+    <p>Last updated: 2011-Mar-08<br />
+     Copyright &copy; 1997-2011 International Business Machines Corporation and
+    others. All Rights Reserved.</p>
+    <!-- Remember that there is a copyright at the end too -->
+    <hr />
+
+    <h2 class="TOC">Table of Contents</h2>
+
+    <ul class="TOC">
+      <li><a href="#Introduction">Introduction</a></li>
+
+      <li><a href="#GettingStarted">Getting Started</a></li>
+
+      <li><a href="#News">What Is New In This release?</a></li>
+
+      <li><a href="#Download">How To Download the Source Code</a></li>
+
+      <li><a href="#SourceCode">ICU Source Code Organization</a></li>
+
+      <li>
+        <a href="#HowToBuild">How To Build And Install ICU</a> 
+
+        <ul >
+          <li><a href="#RecBuild">Recommended Build Options</a></li>
+
+          <li><a href="#HowToBuildWindows">Windows</a></li>
+
+          <li><a href="#HowToBuildCygwin">Cygwin</a></li>
+
+          <li><a href="#HowToBuildUNIX">UNIX</a></li>
+
+          <li><a href="#HowToBuildZOS">z/OS (os/390)</a></li>
+
+          <li><a href="#HowToBuildOS400">IBM i family (IBM i, i5/OS, OS/400)</a></li>
+
+		  <li><a href="#HowToCrossCompileICU">How to Cross Compile ICU</a></li>
+        </ul>
+      </li>
+
+
+      <li><a href="#HowToPackage">How To Package ICU</a></li>
+
+      <li>
+        <a href="#ImportantNotes">Important Notes About Using ICU</a> 
+
+        <ul >
+          <li><a href="#ImportantNotesMultithreaded">Using ICU in a Multithreaded
+          Environment</a></li>
+
+          <li><a href="#ImportantNotesWindows">Windows Platform</a></li>
+
+          <li><a href="#ImportantNotesUNIX">UNIX Type Platforms</a></li>
+        </ul>
+      </li>
+
+      <li>
+        <a href="#PlatformDependencies">Platform Dependencies</a> 
+
+        <ul >
+          <li><a href="#PlatformDependenciesNew">Porting To A New
+          Platform</a></li>
+
+          <li><a href="#PlatformDependenciesImpl">Platform Dependent
+          Implementations</a></li>
+        </ul>
+      </li>
+    </ul>
+    <hr />
+
+    <h2><a name="Introduction" href="#Introduction" id=
+    "Introduction">Introduction</a></h2>
+
+    <p>Today's software market is a global one in which it is desirable to
+    develop and maintain one application (single source/single binary) that
+    supports a wide variety of languages. The International Components for
+    Unicode (ICU) libraries provide robust and full-featured Unicode services on
+    a wide variety of platforms to help this design goal. The ICU libraries
+    provide support for:</p>
+
+    <ul>
+      <li>The latest version of the Unicode standard</li>
+
+      <li>Character set conversions with support for over 220 codepages</li>
+
+      <li>Locale data for more than 250 locales</li>
+
+      <li>Language sensitive text collation (sorting) and searching based on the
+      Unicode Collation Algorithm (=ISO 14651)</li>
+
+      <li>Regular expression matching and Unicode sets</li>
+
+      <li>Transformations for normalization, upper/lowercase, script
+      transliterations (50+ pairs)</li>
+
+      <li>Resource bundles for storing and accessing localized information</li>
+
+      <li>Date/Number/Message formatting and parsing of culture specific
+      input/output formats</li>
+
+      <li>Calendar specific date and time manipulation</li>
+
+      <li>Complex text layout for Arabic, Hebrew, Indic and Thai</li>
+
+      <li>Text boundary analysis for finding characters, word and sentence
+      boundaries</li>
+    </ul>
+
+    <p>ICU has a sister project ICU4J that extends the internationalization
+    capabilities of Java to a level similar to ICU. The ICU C/C++ project is also
+    called ICU4C when a distinction is necessary.</p>
+
+    <h2><a name="GettingStarted" href="#GettingStarted" id=
+    "GettingStarted">Getting started</a></h2>
+
+    <p>This document describes how to build and install ICU on your machine. For
+    other information about ICU please see the following table of links.<br />
+     The ICU homepage also links to related information about writing
+    internationalized software.</p>
+
+    <table class="docTable" summary="These are some useful links regarding ICU and internationalization in general.">
+      <caption>
+        Here are some useful links regarding ICU and internationalization in
+        general.
+      </caption>
+
+      <tr>
+        <td>ICU, ICU4C &amp; ICU4J Homepage</td>
+
+        <td><a href=
+        "http://icu-project.org/">http://icu-project.org/</a></td>
+      </tr>
+
+      <tr>
+        <td>FAQ - Frequently Asked Questions about ICU</td>
+
+        <td><a href=
+        "http://userguide.icu-project.org/icufaq">http://userguide.icu-project.org/icufaq</a></td>
+      </tr>
+
+      <tr>
+        <td>ICU User's Guide</td>
+
+        <td><a href=
+        "http://userguide.icu-project.org/">http://userguide.icu-project.org/</a></td>
+      </tr>
+
+      <tr>
+        <td>How To Use ICU</td>
+
+        <td><a href="http://userguide.icu-project.org/howtouseicu">http://userguide.icu-project.org/howtouseicu</a></td>
+      </tr>
+
+      <tr>
+        <td>Download ICU Releases</td>
+
+        <td><a href=
+        "http://site.icu-project.org/download">http://site.icu-project.org/download</a></td>
+      </tr>
+
+      <tr>
+        <td>ICU4C API Documentation Online</td>
+
+        <td><a href=
+        "http://icu-project.org/apiref/icu4c/">http://icu-project.org/apiref/icu4c/</a></td>
+      </tr>
+
+      <tr>
+        <td>Online ICU Demos</td>
+
+        <td><a href=
+        "http://demo.icu-project.org/icu-bin/icudemos">http://demo.icu-project.org/icu-bin/icudemos</a></td>
+      </tr>
+
+      <tr>
+        <td>Contacts and Bug Reports/Feature Requests</td>
+
+        <td><a href=
+        "http://site.icu-project.org/contacts">http://site.icu-project.org/contacts</a></td>
+      </tr>
+    </table>
+
+    <p><strong>Important:</strong> Please make sure you understand the <a href=
+    "license.html">Copyright and License Information</a>.</p>
+
+    <h2><a name="News" href="#News" id="News">What is new in this
+    release?</a></h2>
+
+    <p>To see which APIs are new or changed in this release, view the <a href="APIChangeReport.html">ICU4C API Change Report</a>. </p>
+
+    <p>The following list concentrates on <em>changes that affect existing
+    applications migrating from previous ICU releases</em>.
+    For more news about
+    this release, see the <a href="http://site.icu-project.org/download">ICU
+    download page</a>.</p>
+
+    <ul>
+      <li><strong>Compiler RTTI</strong><br />
+        ICU 4.6 requires compiler RTTI to be turned on.
+        It is used with many of ICU's polymorphic classes
+        (classes with virtual functions; they are subclasses of UObject).<br />
+        Existing "poor man's RTTI" functions continue to be available, but
+        the ICU code does not use them any more and users are encouraged
+        to use real C++ RTTI as well where necessary.
+        (<code>dynamic_cast&lt;pointer&gt;</code> for casting and testing whether
+        an object is an instance of a class <em>or subclass</em>,
+        and <code>typeid(object or type)</code> for testing for type equality.)<br />
+        New ICU class hierarchies (new immediate subclasses of UObject) will not
+        add "poor man's RTTI" functions.<br />
+        On AIX with the Visual Age compiler, RTTI must be turned on explicitly
+        via the the <code>-qrtti</code> option.
+        When using ICU's own makefiles, this is done automatically via the
+        <code><a href="source/config/mh-aix-va">mh-aix-va</a></code> file.</li>
+    </ul>
+
+    <h2><a name="Download" href="#Download" id="Download">How To Download the
+    Source Code</a></h2>
+
+    <p>There are two ways to download ICU releases:</p>
+
+    <ul>
+      <li><strong>Official Release Snapshot:</strong><br />
+       If you want to use ICU (as opposed to developing it), you should download
+      an official packaged version of the ICU source code. These versions are
+      tested more thoroughly than day-to-day development builds of the system,
+      and they are packaged in zip and tar files for convenient download. These
+      packaged files can be found at <a href=
+      "http://site.icu-project.org/download">http://site.icu-project.org/download</a>.<br />
+       The packaged snapshots are named <strong>icu-nnnn.zip</strong> or
+      <strong>icu-nnnn.tgz</strong>, where nnnn is the version number. The .zip
+      file is used for Windows platforms, while the .tgz file is preferred on
+      most other platforms.<br />
+       Please unzip this file. </li>
+
+      <li><strong>Subversion Source Repository:</strong><br />
+       If you are interested in developing features, patches, or bug fixes for
+      ICU, you should probably be working with the latest version of the ICU
+      source code. You will need to check the code out of our Subversion repository to
+      ensure that you have the most recent version of all of the files. See our
+      <a href="http://site.icu-project.org/repository">source
+      repository</a> for details.</li>
+    </ul>
+
+    <h2><a name="SourceCode" href="#SourceCode" id="SourceCode">ICU Source Code
+    Organization</a></h2>
+
+    <p>In the descriptions below, <strong><i>&lt;ICU&gt;</i></strong> is the full
+    path name of the ICU directory (the top level directory from the distribution
+    archives) in your file system. You can also view the <a href=
+    "http://userguide.icu-project.org/design">ICU Architectural
+    Design</a> section of the User's Guide to see which libraries you need for
+    your software product. You need at least the data (<code>[lib]icudt</code>)
+    and the common (<code>[lib]icuuc</code>) libraries in order to use ICU.</p>
+
+    <table class="docTable" summary="The following files describe the code drop.">
+      <caption>
+        The following files describe the code drop.
+      </caption>
+
+      <tr>
+        <th scope="col">File</th>
+
+        <th scope="col">Description</th>
+      </tr>
+
+      <tr>
+        <td>readme.html</td>
+
+        <td>Describes the International Components for Unicode (this file)</td>
+      </tr>
+
+      <tr>
+        <td>license.html</td>
+
+        <td>Contains the text of the ICU license</td>
+      </tr>
+    </table>
+
+    <p><br />
+    </p>
+
+    <table class="docTable" summary=
+    "The following directories contain source code and data files.">
+      <caption>
+        The following directories contain source code and data files.
+      </caption>
+
+      <tr>
+        <th scope="col">Directory</th>
+
+        <th scope="col">Description</th>
+      </tr>
+
+      <tr>
+        <td><i>&lt;ICU&gt;</i>/source/<b>common</b>/</td>
+
+        <td>The core Unicode and support functionality, such as resource bundles,
+        character properties, locales, codepage conversion, normalization,
+        Unicode properties, Locale, and UnicodeString.</td>
+      </tr>
+
+      <tr>
+        <td><i>&lt;ICU&gt;</i>/source/<b>i18n</b>/</td>
+
+        <td>Modules in i18n are generally the more data-driven, that is to say
+        resource bundle driven, components. These deal with higher-level
+        internationalization issues such as formatting, collation, text break
+        analysis, and transliteration.</td>
+      </tr>
+
+      <tr>
+        <td><i>&lt;ICU&gt;</i>/source/<b>layout</b>/</td>
+
+        <td>Contains the ICU layout engine (not a rasterizer).</td>
+      </tr>
+
+      <tr>
+        <td><i>&lt;ICU&gt;</i>/source/<b>io</b>/</td>
+
+        <td>Contains the ICU I/O library.</td>
+      </tr>
+
+      <tr>
+        <td><i>&lt;ICU&gt;</i>/source/<b>data</b>/</td>
+
+        <td>
+          <p>This directory contains the source data in text format, which is
+          compiled into binary form during the ICU build process. It contains
+          several subdirectories, in which the data files are grouped by
+          function. Note that the build process must be run again after any
+          changes are made to this directory.</p>
+
+          <p>If some of the following directories are missing, it's probably
+          because you got an official download. If you need the data source files
+          for customization, then please download the ICU source code from <a
+          href="http://site.icu-project.org/repository">subversion</a>.</p>
+
+          <ul>
+            <li><b>in/</b> A directory that contains a pre-built data library for
+            ICU. A standard source code package will contain this file without
+            several of the following directories. This is to simplify the build
+            process for the majority of users and to reduce platform porting
+            issues.</li>
+
+            <li><b>brkitr/</b> Data files for character, word, sentence, title
+            casing and line boundary analysis.</li>
+
+            <li><b>locales/</b> These .txt files contain ICU language and
+            culture-specific localization data. Two special bundles are
+            <b>root</b>, which is the fallback data and parent of other bundles,
+            and <b>index</b>, which contains a list of installed bundles. The
+            makefile <b>resfiles.mk</b> contains the list of resource bundle
+            files.</li>
+
+            <li><b>mappings/</b> Here are the code page converter tables. These
+            .ucm files contain mappings to and from Unicode. These are compiled
+            into .cnv files. <b>convrtrs.txt</b> is the alias mapping table from
+            various converter name formats to ICU internal format and vice versa.
+            It produces cnvalias.icu. The makefiles <b>ucmfiles.mk,
+            ucmcore.mk,</b> and <b>ucmebcdic.mk</b> contain the list of
+            converters to be built.</li>
+
+            <li><b>translit/</b> This directory contains transliterator rules as
+            resource bundles, a makefile <b>trnsfiles.mk</b> containing the list
+            of installed system translitaration files, and as well the special
+            bundle <b>translit_index</b> which lists the system transliterator
+            aliases.</li>
+
+            <li><b>unidata/</b> This directory contains the Unicode data files.
+            Please see <a href=
+            "http://www.unicode.org/">http://www.unicode.org/</a> for more
+            information.</li>
+
+            <li><b>misc/</b> The misc directory contains other data files which
+            did not fit into the above categories. Currently it only contains
+            time zone information, and a name preperation file for <a href=
+            "http://www.ietf.org/rfc/rfc3490.txt">IDNA</a>.</li>
+
+            <li><b>out/</b> This directory contains the assembled memory mapped
+            files.</li>
+
+            <li><b>out/build/</b> This directory contains intermediate (compiled)
+            files, such as .cnv, .res, etc.</li>
+          </ul>
+
+          <p>If you are creating a special ICU build, you can set the ICU_DATA
+          environment variable to the out/ or the out/build/ directories, but
+          this is generally discouraged because most people set it incorrectly.
+          You can view the <a href=
+          "http://userguide.icu-project.org/icudata">ICU Data
+          Management</a> section of the ICU User's Guide for details.</p>
+        </td>
+      </tr>
+
+      <tr>
+        <td><i>&lt;ICU&gt;</i>/source/test/<b>intltest</b>/</td>
+
+        <td>A test suite including all C++ APIs. For information about running
+        the test suite, see the build instructions specific to your platform
+        later in this document.</td>
+      </tr>
+
+      <tr>
+        <td><i>&lt;ICU&gt;</i>/source/test/<b>cintltst</b>/</td>
+
+        <td>A test suite written in C, including all C APIs. For information
+        about running the test suite, see the build instructions specific to your
+        platform later in this document.</td>
+      </tr>
+
+      <tr>
+        <td><i>&lt;ICU&gt;</i>/source/test/<b>iotest</b>/</td>
+
+        <td>A test suite written in C and C++ to test the icuio library. For
+        information about running the test suite, see the build instructions
+        specific to your platform later in this document.</td>
+      </tr>
+
+      <tr>
+        <td><i>&lt;ICU&gt;</i>/source/test/<b>testdata</b>/</td>
+
+        <td>Source text files for data, which are read by the tests. It contains
+        the subdirectories <b>out/build/</b> which is used for intermediate
+        files, and <b>out/</b> which contains <b>testdata.dat.</b></td>
+      </tr>
+
+      <tr>
+        <td><i>&lt;ICU&gt;</i>/source/<b>tools</b>/</td>
+
+        <td>Tools for generating the data files. Data files are generated by
+        invoking <i>&lt;ICU&gt;</i>/source/data/build/makedata.bat on Win32 or
+        <i>&lt;ICU&gt;</i>/source/make on UNIX.</td>
+      </tr>
+
+      <tr>
+        <td><i>&lt;ICU&gt;</i>/source/<b>samples</b>/</td>
+
+        <td>Various sample programs that use ICU</td>
+      </tr>
+
+      <tr>
+        <td><i>&lt;ICU&gt;</i>/source/<b>extra</b>/</td>
+
+        <td>Non-supported API additions. Currently, it contains the 'uconv' tool
+        to perform codepage conversion on files.</td>
+      </tr>
+
+      <tr>
+        <td><i>&lt;ICU&gt;</i>/<b>packaging</b>/</td>
+
+        <td>This directory contain scripts and tools for packaging the final
+        ICU build for various release platforms.</td>
+      </tr>
+
+      <tr>
+        <td><i>&lt;ICU&gt;</i>/source/<b>config</b>/</td>
+
+        <td>Contains helper makefiles for platform specific build commands. Used
+        by 'configure'.</td>
+      </tr>
+
+      <tr>
+        <td><i>&lt;ICU&gt;</i>/source/<b>allinone</b>/</td>
+
+        <td>Contains top-level ICU workspace and project files, for instance to
+        build all of ICU under one MSVC project.</td>
+      </tr>
+
+      <tr>
+        <td><i>&lt;ICU&gt;</i>/<b>include</b>/</td>
+
+        <td>Contains the headers needed for developing software that uses ICU on
+        Windows.</td>
+      </tr>
+
+      <tr>
+        <td><i>&lt;ICU&gt;</i>/<b>lib</b>/</td>
+
+        <td>Contains the import libraries for linking ICU into your Windows
+        application.</td>
+      </tr>
+
+      <tr>
+        <td><i>&lt;ICU&gt;</i>/<b>bin</b>/</td>
+
+        <td>Contains the libraries and executables for using ICU on Windows.</td>
+      </tr>
+    </table>
+    <!-- end of ICU structure ==================================== -->
+
+    <h2><a name="HowToBuild" href="#HowToBuild" id="HowToBuild">How To Build And
+    Install ICU</a></h2>
+
+    <h3><a name="RecBuild" href="#RecBuild" id=
+    "RecBuild">Recommended Build Options</a></h3>
+
+    <p>Depending on the platform and the type of installation,
+    we recommend a small number of modifications and build options.</p>
+    <ul>
+      <li><b>Namespace:</b> By default, unicode/uversion.h has
+        "using namespace icu;" which defeats much of the purpose of the namespace.
+        (This is for historical reasons: Originally, ICU4C did not use namespaces,
+        and some compilers did not support them. The default "using" statement
+        preserves source code compatibility.)<br>
+        We recommend you turn this off via <code>-DU_USING_ICU_NAMESPACE=0</code>
+        or by modifying unicode/uversion.h:
+<pre>Index: source/common/unicode/uversion.h
+===================================================================
+--- source/common/unicode/uversion.h    (revision 26606)
++++ source/common/unicode/uversion.h    (working copy)
+@@ -180,7 +180,8 @@
+ #   define U_NAMESPACE_QUALIFIER U_ICU_NAMESPACE::
+
+ #   ifndef U_USING_ICU_NAMESPACE
+-#       define U_USING_ICU_NAMESPACE 1
++        // Set to 0 to force namespace declarations in ICU usage.
++#       define U_USING_ICU_NAMESPACE 0
+ #   endif
+ #   if U_USING_ICU_NAMESPACE
+         U_NAMESPACE_USE
+</pre>
+        ICU call sites then either qualify ICU types explicitly,
+        for example <code>icu::UnicodeString</code>,
+        or do <code>using icu::UnicodeString;</code> where appropriate.</li>
+      <li><b>Hardcode the default charset to UTF-8:</b> On platforms where
+        the default charset is always UTF-8,
+        like MacOS X and some Linux distributions,
+        we recommend hardcoding ICU's default charset to UTF-8.
+        This means that some implementation code becomes simpler and faster,
+        and statically linked ICU libraries become smaller.
+        (See the <a href="http://icu-project.org/apiref/icu4c/utypes_8h.html#0a33e1edf3cd23d9e9c972b63c9f7943">U_CHARSET_IS_UTF8</a>
+        API documentation for more details.)<br>
+        You can <code>-DU_CHARSET_IS_UTF8=1</code> or modify unicode/utypes.h:
+<pre>Index: source/common/unicode/utypes.h
+===================================================================
+--- source/common/unicode/utypes.h      (revision 26606)
++++ source/common/unicode/utypes.h      (working copy)
+@@ -160,7 +160,7 @@
+  * @see UCONFIG_NO_CONVERSION
+  */
+ #ifndef U_CHARSET_IS_UTF8
+-#   define U_CHARSET_IS_UTF8 0
++#   define U_CHARSET_IS_UTF8 1
+ #endif
+
+ /*===========================================================================*/
+</pre></li>
+      <li><b>.dat file:</b> By default, the ICU data is built into
+        a shared library (DLL). This is convenient because it requires no
+        install-time or runtime configuration,
+        but the library is platform-specific and cannot be modified.
+        A .dat package file makes the opposite trade-off:
+        Platform-portable (except for endianness and charset family, which
+        can be changed with the icupkg tool)
+        and modifiable (also with the icupkg tool).
+        If a path is set, then single data files (e.g., .res files)
+        can be copied to that location to provide new locale data
+        or conversion tables etc.<br>
+        The only drawback with a .dat package file is that the application
+        needs to provide ICU with the file system path to the package file
+        (e.g., by calling <code>u_setDataDirectory()</code>)
+        or with a pointer to the data (<code>udata_setCommonData()</code>)
+        before other ICU API calls.
+        This is usually easy if ICU is used from an application where
+        <code>main()</code> takes care of such initialization.
+        It may be hard if ICU is shipped with
+        another shared library (such as the Xerces-C++ XML parser)
+        which does not control <code>main()</code>.<br>
+        See the <a href="http://userguide.icu-project.org/icudata">User Guide ICU Data</a>
+        chapter for more details.<br>
+        If possible, we recommend building the .dat package.
+        Specify <code>--with-data-packaging=archive</code>
+        on the configure command line, as in<br>
+        <code>runConfigureICU Linux --with-data-packaging=archive</code><br>
+        (Read the configure script's output for further instructions.
+        On Windows, the Visual Studio build generates both the .dat package
+        and the data DLL.)<br>
+        Be sure to install and use the tiny stubdata library
+        rather than the large data DLL.</li>
+      <li><b>Static libraries:</b> It may make sense to build the ICU code
+        into static libraries (.a) rather than shared libraries (.so/.dll).
+        Static linking reduces the overall size of the binary by removing
+        code that is never called.<br>
+        Example configure command line:<br>
+        <code>runConfigureICU Linux --enable-static --disable-shared</code></li>
+      <li><b>Out-of-source build:</b> It is usually desirable to keep the ICU
+        source file tree clean and have build output files written to
+        a different location. This is called an "out-of-source build".
+        Simply invoke the configure script from the target location:
+<pre>~/icu$ svn export http://source.icu-project.org/repos/icu/icu/trunk
+~/icu$ mkdir trunk-dev
+~/icu$ cd trunk-dev
+~/icu/trunk-dev$ ../trunk/source/runConfigureICU Linux
+~/icu/trunk-dev$ make check</pre></li>
+    </ul>
+    <h4>ICU as a System-Level Library</h4>
+    <p>If ICU is installed as a system-level library, there are further
+      opportunities and restrictions to consider.
+      For details, see the <em>Using ICU as an Operating System Level Library</em>
+      section of the <a href="http://userguide.icu-project.org/design">User Guide ICU Architectural Design</a> chapter.</p>
+    <ul>
+      <li><b>Data path:</b> For a system-level library, it is best to load
+        ICU data from the .dat package file because the file system path
+        to the .dat package file can be hardcoded. ICU will automatically set
+        the path to the final install location using U_ICU_DATA_DEFAULT_DIR.
+        Alternatively, you can set <code>-DICU_DATA_DIR=/path/to/icu/data</code>
+        when building the ICU code. (Used by source/common/putil.c.)<br>
+        Consider also setting <code>-DICU_NO_USER_DATA_OVERRIDE</code>
+        if you do not want the "ICU_DATA" environment variable to be used.
+        (An application can still override the data path via
+        <code>u_setDataDirectory()</code> or
+        <code>udata_setCommonData()</code>.</li>
+      <li><b>Hide draft API:</b> API marked with <code>@draft</code>
+        is new and not yet stable. Applications must not rely on unstable
+        APIs from a system-level library.
+        Define <code>U_HIDE_DRAFT_API</code>, <code>U_HIDE_INTERNAL_API</code>
+        and <code>U_HIDE_SYSTEM_API</code>
+        by modifying unicode/utypes.h before installing it.</li>
+      <li><b>Only C APIs:</b> Applications must not rely on C++ APIs from a
+        system-level library because binary C++ compatibility
+        across library and compiler versions is very hard to achieve.
+        Most ICU C++ APIs are in header files that contain a comment with
+        <code>\brief C++ API</code>.
+        Consider not installing these header files.</li>
+      <li><b>Disable renaming:</b> By default, ICU library entry point names
+        have an ICU version suffix. Turn this off for a system-level installation,
+        to enable upgrading ICU without breaking applications. For example:<br>
+        <code>runConfigureICU Linux --disable-renaming</code><br>
+        The public header files from this configuration must be installed
+        for applications to include and get the correct entry point names.</li>
+    </ul>
+
+    <h3><a name="HowToBuildWindows" href="#HowToBuildWindows" id=
+    "HowToBuildWindows">How To Build And Install On Windows</a></h3>
+
+    <p>Building International Components for Unicode requires:</p>
+
+    <ul>
+      <li>Microsoft Windows</li>
+
+      <li>Microsoft Visual C++</li>
+
+      <li><a href="#HowToBuildCygwin">Cygwin</a> is required when other versions
+      of Microsoft Visual C++ and other compilers are used to build ICU.</li>
+    </ul>
+
+    <p>The steps are:</p>
+
+    <ol>
+      <li>Unzip the icu-XXXX.zip file into any convenient location. Using command
+      line zip, type "unzip -a icu-XXXX.zip -d drive:\directory", or just use
+      WinZip.</li>
+
+      <li>Be sure that the ICU binary directory, <i>&lt;ICU&gt;</i>\bin\, is
+      included in the <strong>PATH</strong> environment variable. The tests will
+      not work without the location of the ICU DLL files in the path.</li>
+
+      <li>Open the "<i>&lt;ICU&gt;</i>\source\allinone\allinone.sln" workspace
+      file in Microsoft Visual Studio. (This solution includes all the
+      International Components for Unicode libraries, necessary ICU building
+      tools, and the test suite projects). Please see the <a href=
+      "#HowToBuildWindowsCommandLine">command line note below</a> if you want to
+      build from the command line instead.</li>
+
+      <li>Set the active platform to "Win32" or "x64" (See <a href="#HowToBuildWindowsPlatform">Windows platform note</a> below) 
+      and configuration to "Debug" or "Release" (See <a href="#HowToBuildWindowsConfig">Windows configuration note</a> below).</li>
+
+      <li>Choose the "Build" menu and select "Rebuild Solution". If you want to
+      build the Debug and Release at the same time, see the <a href=
+      "#HowToBuildWindowsBatch">batch configuration note</a> below.</li>
+
+
+      <li>Run the tests. They can be run from the command line or from within Visual Studio.
+
+	 <h4>Running the Tests from the Windows Command Line (cmd)</h4>
+	<ul>
+	   <li>For x86 (32 bit) and Debug, use: <br />
+
+	<tt><i>&lt;ICU&gt;</i>\source\allinone\icucheck.bat  <i>Platform</i> <i>Configuration</i>
+		</tt> <br />
+       </li>
+	<li>So, for example:
+				 <br />
+		<tt><i>&lt;ICU&gt;</i>\source\allinone\icucheck.bat  <b>x86</b> <b>Debug</b>
+		</tt>
+				<br/>  or <br />
+		<tt><i>&lt;ICU&gt;</i>\source\allinone\icucheck.bat  <b>x86</b> <b>Release</b>
+		</tt>
+				<br/>  or <br />
+		<tt><i>&lt;ICU&gt;</i>\source\allinone\icucheck.bat  <b>x64</b> <b>Release</b>
+		</tt></li>
+	</ul>	
+
+         <h4>Running the Tests from within Visual Studio</h4>
+
+	<ol>
+      <li>Run the C++ test suite, "intltest". To do this: set the active startup
+      project to "intltest", and press Ctrl+F5 to run it. Make sure that it
+      passes without any errors.</li>
+
+      <li>Run the C test suite, "cintltst". To do this: set the active startup
+      project to "cintltst", and press Ctrl+F5 to run it. Make sure that it
+      passes without any errors.</li>
+
+      <li>Run the I/O test suite, "iotest". To do this: set the active startup
+      project to "iotest", and press Ctrl+F5 to run it. Make sure that it passes
+      without any errors.</li>
+
+	</ol>
+
+	</li>
+
+      <li>You are now able to develop applications with ICU by using the
+      libraries and tools in <i>&lt;ICU&gt;</i>\bin\. The headers are in
+      <i>&lt;ICU&gt;</i>\include\ and the link libraries are in
+      <i>&lt;ICU&gt;</i>\lib\. To install the ICU runtime on a machine, or ship
+      it with your application, copy the needed components from
+      <i>&lt;ICU&gt;</i>\bin\ to a location on the system PATH or to your
+      application directory.</li>
+    </ol>
+
+    <p><a name="HowToBuildWindowsCommandLine" id=
+    "HowToBuildWindowsCommandLine"><strong>Using MSDEV At The Command Line
+    Note:</strong></a> You can build ICU from the command line. Assuming that you
+    have properly installed Microsoft Visual C++ to support command line
+    execution, you can run the following command, 'devenv.com
+    <i>&lt;ICU&gt;</i>\source\allinone\allinone.sln /build "Win32|Release"'. You can also
+    use Cygwin with this compiler to build ICU, and you can refer to the <a href=
+    "#HowToBuildCygwin">How To Build And Install On Windows with Cygwin</a>
+    section for more details.</p>
+    
+    <p><a name="HowToBuildWindowsPlatform" id=
+    "HowToBuildWindowsPlatform"><strong>Setting Active Platform
+    Note:</strong></a> Even though you are able to select "x64" as the active platform, if your operating system is 
+    not a 64 bit version of Windows, the build will fail. To set the active platform, two different possibilities are:</p>
+
+    <ul>
+      <li>Choose "Build" menu, select "Configuration Manager...", and select
+      "Win32" or "x64" for the Active Platform Solution.</li>
+
+      <li>Another way is to select the desired build configuration from "Solution
+      Platforms" dropdown menu from the standard toolbar. It will say
+      "Win32" or "x64" in the dropdown list.</li>
+    </ul>
+
+    <p><a name="HowToBuildWindowsConfig" id=
+    "HowToBuildWindowsConfig"><strong>Setting Active Configuration
+    Note:</strong></a> To set the active configuration, two different
+    possibilities are:</p>
+
+    <ul>
+      <li>Choose "Build" menu, select "Configuration Manager...", and select
+      "Release" or "Debug" for the Active Configuration Solution.</li>
+
+      <li>Another way is to select the desired build configuration from "Solution
+      Configurations" dropdown menu from the standard toolbar. It will say
+      "Release" or "Debug" in the dropdown list.</li>
+    </ul>
+
+    <p><a name="HowToBuildWindowsBatch" id="HowToBuildWindowsBatch"><strong>Batch
+    Configuration Note:</strong></a> If you want to build the Win32 and x64 platforms and 
+    Debug and Release configurations at the same time, choose "Build" menu, and select "Batch
+    Build...". Click the "Select All" button, and then click the "Rebuild"
+    button.</p>
+
+    <h3><a name="HowToBuildCygwin" href="#HowToBuildCygwin" id=
+    "HowToBuildCygwin">How To Build And Install On Windows with Cygwin</a></h3>
+
+    <p>Building International Components for Unicode with this configuration
+    requires:</p>
+
+    <ul>
+      <li>Microsoft Windows</li>
+
+      <li>Microsoft Visual C++ (when gcc isn't used).</li>
+
+      <li>
+        Cygwin with the following installed: 
+
+        <ul>
+          <li>bash</li>
+
+          <li>GNU make</li>
+
+          <li>ar</li>
+
+          <li>ranlib</li>
+
+          <li>man (if you plan to look at the man pages)</li>
+        </ul>
+      </li>
+    </ul>
+
+    <p>There are two ways you can build ICU with Cygwin. You can build with gcc
+    or Microsoft Visual C++. If you use gcc, the resulting libraries and tools
+    will depend on the Cygwin environment. If you use Microsoft Visual C++, the
+    resulting libraries and tools do not depend on Cygwin and can be more easily
+    distributed to other Windows computers (the generated man pages and shell
+    scripts still need Cygwin). To build with gcc, please follow the "<a href=
+    "#HowToBuildUNIX">How To Build And Install On UNIX</a>" instructions, while
+    you are inside a Cygwin bash shell. To build with Microsoft Visual C++,
+    please use the following instructions:</p>
+
+    <ol>
+      <li>Start the Windows "Command Prompt" window. This is different from the
+      gcc build, which requires the Cygwin Bash command prompt. The Microsoft
+      Visual C++ compiler will not work with a bash command prompt.</li>
+
+      <li>If the computer isn't set up to use Visual C++ from the command line,
+      you need to run vcvars32.bat.<br>For example:<br>"<tt>C:\Program Files\Microsoft
+      Visual Studio 8\VC\bin\vcvars32.bat</tt>" can be used for 32-bit builds
+      <strong>or</strong> <br>"<tt>C:\Program Files (x86)\Microsoft Visual Studio
+      8\VC\bin\amd64\vcvarsamd64.bat</tt>" can be used for 64-bit builds on
+      Windows x64.</li>
+
+      <li>Unzip the icu-XXXX.zip file into any convenient location. Using command
+      line zip, type "unzip -a icu-XXXX.zip -d drive:\directory", or just use
+      WinZip.</li>
+
+      <li>Change directory to "icu/source", which is where you unzipped ICU.</li>
+
+      <li>Run "<tt>bash <a href="source/runConfigureICU">./runConfigureICU</a>
+      Cygwin/MSVC</tt>" (See <a href="#HowToWindowsConfigureICU">Windows
+      configuration note</a> and non-functional configure options below).</li>
+
+      <li>Type <tt>"make"</tt> to compile the libraries and all the data files.
+      This make command should be GNU make.</li>
+
+      <li>Optionally, type <tt>"make check"</tt> to run the test suite, which
+      checks for ICU's functionality integrity (See <a href=
+      "#HowToTestWithoutGmake">testing note</a> below).</li>
+
+      <li>Type <tt>"make install"</tt> to install ICU. If you used the --prefix=
+      option on configure or runConfigureICU, ICU will be installed to the
+      directory you specified. (See <a href="#HowToInstallICU">installation
+      note</a> below).</li>
+    </ol>
+
+    <p><a name="HowToWindowsConfigureICU" id=
+    "HowToWindowsConfigureICU"><strong>Configuring ICU on Windows
+    NOTE:</strong></a> </p>
+    <p>
+    Ensure that the order of the PATH is MSVC, Cygwin, and then other PATHs. The configure 
+    script needs certain tools in Cygwin (e.g. grep).
+    </p>
+    <p>
+    Also, you may need to run <tt>"dos2unix.exe"</tt> on all of the scripts (e.g. configure)
+    in the top source directory of ICU. To avoid this issue, you can download
+    the ICU source for Unix platforms (icu-xxx.tgz).
+    </p>
+    <p>In addition to the Unix <a href=
+    "#HowToConfigureICU">configuration note</a> the following configure options
+    currently do not work on Windows with Microsoft's compiler. Some options can
+    work by manually editing <tt>icu/source/common/unicode/pwin32.h</tt>, but
+    manually editing the files is not recommended.</p>
+
+    <ul>
+      <li><tt>--disable-renaming</tt></li>
+
+      <li><tt>--disable-threading</tt> (This flag does disable threading in ICU,
+      but the resulting ICU library will still be linked with MSVC's multithread DLL)</li>
+
+      <li><tt>--enable-tracing</tt></li>
+
+      <li><tt>--enable-rpath</tt></li>
+
+      <li><tt>--with-iostream</tt></li>
+
+      <li><tt>--enable-static</tt> (Requires that U_STATIC_IMPLEMENTATION be
+      defined in user code that links against ICU's static libraries.)</li>
+
+      <li><tt>--with-data-packaging=files</tt> (The pkgdata tool currently does
+      not work in this mode. Manual packaging is required to use this mode.)</li>
+    </ul>
+
+    <h3><a name="HowToBuildUNIX" href="#HowToBuildUNIX" id="HowToBuildUNIX">How
+    To Build And Install On UNIX</a></h3>
+
+    <p>Building International Components for Unicode on UNIX requires:</p>
+
+    <ul>
+      <li>A C++ compiler installed on the target machine (for example: gcc, CC,
+      xlC_r, aCC, cxx, etc...).</li>
+
+      <li>An ANSI C compiler installed on the target machine (for example:
+      cc).</li>
+
+      <li>A recent version of GNU make (3.80+).</li>
+
+      <li>For a list of z/OS tools please view the <a href="#HowToBuildZOS">z/OS
+      build section</a> of this document for further details.</li>
+    </ul>
+
+    <p>Here are the steps to build ICU:</p>
+
+    <ol>
+      <li>Decompress the icu-<i>X</i>.<i>Y</i>.tgz (or
+      icu-<i>X</i>.<i>Y</i>.tar.gz) file. For example, <tt>"gunzip -d &lt;
+      icu-<i>X</i>.<i>Y</i>.tgz | tar xvf -"</tt></li>
+
+      <li>Change directory to the "icu/source".</li>
+
+      <li>Run <tt>"chmod +x runConfigureICU configure install-sh"</tt> because
+      these files may have the wrong permissions.</li>
+
+      <li>Run the <tt><a href="source/runConfigureICU">runConfigureICU</a></tt>
+      script for your platform. (See <a href="#HowToConfigureICU">configuration
+      note</a> below).</li>
+
+      <li>Type <tt>"gmake"</tt> (or "make" if GNU make is the default make on
+      your platform) to compile the libraries and all the data files. The proper
+      name of the GNU make command is printed at the end of the configuration
+      run, as in "You must use gmake to compile ICU".</li>
+
+      <li>Optionally, type <tt>"gmake check"</tt> to run the test suite, which
+      checks for ICU's functionality integrity (See <a href=
+      "#HowToTestWithoutGmake">testing note</a> below).</li>
+
+      <li>Type <tt>"gmake install"</tt> to install ICU. If you used the --prefix=
+      option on configure or runConfigureICU, ICU will be installed to the
+      directory you specified. (See <a href="#HowToInstallICU">installation
+      note</a> below).</li>
+    </ol>
+
+    <p><a name="HowToConfigureICU" id="HowToConfigureICU"><strong>Configuring ICU
+    NOTE:</strong></a> Type <tt>"./runConfigureICU --help"</tt> for help on how
+    to run it and a list of supported platforms. You may also want to type
+    <tt>"./configure --help"</tt> to print the available configure options that
+    you may want to give runConfigureICU. If you are not using the
+    runConfigureICU script, or your platform is not supported by the script, you
+    may need to set your CC, CXX, CFLAGS and CXXFLAGS environment variables, and
+    type <tt>"./configure"</tt>. 
+    HP-UX users, please see this <a href="#ImportantNotesHPUX">note regarding
+    HP-UX multithreaded build issues</a> with newer compilers. Solaris users,
+    please see this <a href="#ImportantNotesSolaris">note regarding Solaris
+    multithreaded build issues</a>.</p>
+
+    <p>ICU is built with strict compiler warnings enabled by default.  If this
+    causes excessive numbers of warnings on your platform, use the --disable-strict
+    option to configure to reduce the warning level.</p>
+
+    <p><a name="HowToTestWithoutGmake" id="HowToTestWithoutGmake"><strong>Running
+    The Tests From The Command Line NOTE:</strong></a> You may have to set
+    certain variables if you with to run test programs individually, that is
+    apart from "gmake check". The environment variable <strong>ICU_DATA</strong>
+    can be set to the full pathname of the data directory to indicate where the
+    locale data files and conversion mapping tables are when you are not using
+    the shared library (e.g. by using the .dat archive or the individual data
+    files). The trailing "/" is required after the directory name (e.g.
+    "$Root/source/data/out/" will work, but the value "$Root/source/data/out" is
+    not acceptable). You do not need to set <strong>ICU_DATA</strong> if the
+    complete shared data library is in your library path.</p>
+
+    <p><a name="HowToInstallICU" id="HowToInstallICU"><strong>Installing ICU
+    NOTE:</strong></a> Some platforms use package management tools to control the
+    installation and uninstallation of files on the system, as well as the
+    integrity of the system configuration. You may want to check if ICU can be
+    packaged for your package management tools by looking into the "packaging"
+    directory. (Please note that if you are using a snapshot of ICU from Subversion, it
+    is probable that the packaging scripts or related files are not up to date
+    with the contents of ICU at this time, so use them with caution).</p>
+
+    <h3><a name="HowToBuildZOS" href="#HowToBuildZOS" id="HowToBuildZOS">How To
+    Build And Install On z/OS (OS/390)</a></h3>
+
+    <p>You can install ICU on z/OS or OS/390 (the previous name of z/OS), but IBM
+    tests only the z/OS installation. You install ICU in a z/OS UNIX system
+    services file system such as HFS or zFS. On this platform, it is important
+    that you understand a few details:</p>
+
+    <ul>
+      <li>The makedep and GNU make tools are required for building ICU. If it
+      is not already installed on your system, it is available at the <a href=
+      "http://www-03.ibm.com/servers/eserver/zseries/zos/unix/bpxa1toy.html">z/OS UNIX -
+      Tools and Toys</a> site. The PATH environment variable should be updated to
+      contain the location of this executable prior to build. Failure to add these
+      tools to your PATH will cause ICU build failures or cause pkgdata to fail
+      to run.</li>
+
+      <li>Since USS does not support using the mmap() function over NFS, it is
+      recommended that you build ICU on a local filesystem. Once ICU has been
+      built, you should not have this problem while using ICU when the data
+      library has been built as a shared library, which is this is the default
+      setting.</li>
+
+      <li>Encoding considerations: The source code assumes that it is compiled
+      with codepage ibm-1047 (to be exact, the UNIX System Services variant of
+      it). The pax command converts all of the source code files from ASCII to
+      codepage ibm-1047 (USS) EBCDIC. However, some files are binary files and
+      must not be converted, or must be converted back to their original state.
+      You can use the <a href="as_is/os390/unpax-icu.sh">unpax-icu.sh</a> script
+      to do this for you automatically. It will unpackage the tar file and
+      convert all the necessary files for you automatically.</li>
+
+      <li>z/OS supports both native S/390 hexadecimal floating point and (with
+      OS/390 2.6 and later) IEEE 754 binary floating point. This is a compile
+      time option. Applications built with IEEE should use ICU DLLs that are
+      built with IEEE (and vice versa). The environment variable IEEE390=0 will
+      cause the z/OS version of ICU to be built without IEEE floating point
+      support and use the native hexadecimal floating point. By default ICU is
+      built with IEEE 754 support. Native floating point support is sufficient
+      for codepage conversion, resource bundle and UnicodeString operations, but
+      the Format APIs require IEEE binary floating point.</li>
+
+      <li>z/OS introduced the concept of Extra Performance Linkage (XPLINK) to
+      bring performance improvement opportunities to call-intensive C and C++
+      applications such as ICU. XPLINK is enabled on a DLL-by-DLL basis, so if
+      you are considering using XPLINK in your application that uses ICU, you
+      should consider building the XPLINK-enabled version of ICU. You need to
+      set ICU's environment variable <code>OS390_XPLINK=1</code> prior to
+      invoking the make process to produce binaries that are enabled for
+      XPLINK. The XPLINK option, which is available for z/OS 1.2 and later,
+      requires the PTF PQ69418 to build XPLINK enabled binaries.</li>
+
+      <li>Currently in ICU 3.0, there is an issue with building on z/OS without
+      XPLINK and with the C++ iostream. By default, the iostream library on z/OS
+      is XPLINK enabled. If you are not building an XPLINK enabled version of
+      ICU, you should use the <code>--with-iostream=old</code> configure option
+      when using runConfigureICU. This will prevent applications that use the
+      icuio library from crashing.</li>
+
+      <li>The rest of the instructions for building and testing ICU on z/OS with
+      UNIX System Services are the same as the <a href="#HowToBuildUNIX">How To
+      Build And Install On UNIX</a> section.</li>
+    </ul>
+
+    <h4>z/OS (Batch/PDS) support outside the UNIX system services
+    environment</h4>
+
+    <p>By default, ICU builds its libraries into the UNIX file system (HFS). In
+    addition, there is a z/OS specific environment variable (OS390BATCH) to build
+    some libraries into the z/OS native file system. This is useful, for example,
+    when your application is externalized via Job Control Language (JCL).</p>
+
+    <p>The OS390BATCH environment variable enables non-UNIX support including the
+    batch environment. When OS390BATCH is set, the libicui18n<i>XX</i>.dll,
+    libicuuc<i>XX</i>.dll, and libicudt<i>XX</i>e.dll binaries are built into
+    data sets (the native file system). Turning on OS390BATCH does not turn off
+    the normal z/OS UNIX build. This means that the z/OS UNIX (HFS) DLLs will
+    always be created.</p>
+
+    <p>Two additional environment variables indicate the names of the z/OS data
+    sets to use. The LOADMOD environment variable identifies the name of the data
+    set that contains the dynamic link libraries (DLLs) and the LOADEXP
+    environment variable identifies the name of the data set that contains the
+    side decks, which are normally the files with the .x suffix in the UNIX file
+    system.</p>
+
+    <p>A data set is roughly equivalent to a UNIX or Windows file. For most kinds
+    of data sets the operating system maintains record boundaries. UNIX and
+    Windows files are byte streams. Two kinds of data sets are PDS and PDSE. Each
+    data set of these two types contains a directory. It is like a UNIX
+    directory. Each "file" is called a "member". Each member name is limited to
+    eight bytes, normally EBCDIC.</p>
+
+    <p>Here is an example of some environment variables that you can set prior to
+    building ICU:</p>
+<pre>
+<samp>OS390BATCH=1
+LOADMOD=<i>USER</i>.ICU.LOAD
+LOADEXP=<i>USER</i>.ICU.EXP</samp>
+</pre>
+
+    <p>The PDS member names for the DLL file names are as follows:</p>
+<pre>
+<samp>IXMI<i>XX</i>IN --&gt; libicui18n<i>XX</i>.dll
+IXMI<i>XX</i>UC --&gt; libicuuc<i>XX</i>.dll
+IXMI<i>XX</i>DA --&gt; libicudt<i>XX</i>e.dll</samp>
+</pre>
+
+    <p>You should point the LOADMOD environment variable at a partitioned data
+    set extended (PDSE) and point the LOADEXP environment variable at a
+    partitioned data set (PDS). The PDSE can be allocated with the following
+    attributes:</p>
+<pre>
+<samp>Data Set Name . . . : <i>USER</i>.ICU.LOAD
+Management class. . : <i>**None**</i>
+Storage class . . . : <i>BASE</i>
+Volume serial . . . : <i>TSO007</i>
+Device type . . . . : <i>3390</i>
+Data class. . . . . : <i>LOAD</i>
+Organization  . . . : PO
+Record format . . . : U
+Record length . . . : 0
+Block size  . . . . : <i>32760</i>
+1st extent cylinders: 1
+Secondary cylinders : 5
+Data set name type  : LIBRARY</samp>
+</pre>
+
+    <p>The PDS can be allocated with the following attributes:</p>
+<pre>
+<samp>Data Set Name . . . : <i>USER</i>.ICU.EXP
+Management class. . : <i>**None**</i>
+Storage class . . . : <i>BASE</i>
+Volume serial . . . : <i>TSO007</i>
+Device type . . . . : <i>3390</i>
+Data class. . . . . : <i>**None**</i>
+Organization  . . . : PO
+Record format . . . : FB
+Record length . . . : 80
+Block size  . . . . : <i>3200</i>
+1st extent cylinders: 3
+Secondary cylinders : 3
+Data set name type  : PDS</samp>
+</pre>
+
+    <h3><a name="HowToBuildOS400" href="#HowToBuildOS400" id=
+    "HowToBuildOS400">How To Build And Install On The IBM i Family (IBM i, i5/OS OS/400)</a></h3>
+
+    <p>Before you start building ICU, ICU requires the following:</p>
+
+    <ul>
+      <li>QSHELL interpreter installed (install base option 30, operating system)
+      <!--li>QShell Utilities, PRPQ 5799-XEH (not required for V4R5)</li--></li>
+
+      <li>ILE C/C++ Compiler installed on the system</li>
+
+      <li>The latest GNU facilities (You can get the GNU facilities 
+      from <a href=
+      "http://www.ibm.com/servers/enable/site/porting/iseries/overview/gnu_utilities.html">
+      http://www.ibm.com/servers/enable/site/porting/iseries/overview/gnu_utilities.html</a>).
+      Older versions may not work properly.</li>
+    </ul>
+
+    <p>The following describes how to setup and build ICU. For background
+    information, you should look at the <a href="#HowToBuildUNIX">UNIX build
+    instructions</a>.</p>
+
+    <ol>
+      <li>
+        Create target library. This library will be the target for the
+        resulting modules, programs and service programs. You will specify this
+        library on the OUTPUTDIR environment variable.
+<pre>
+<samp>CRTLIB LIB(<i>libraryname</i>)
+ADDENVVAR ENVVAR(OUTPUTDIR) VALUE('<i>libraryname</i>') REPLACE(*YES)   </samp>
+</pre>
+      </li>
+
+      <li>
+      Set up the following environment variables and job characteristics in your build process
+<pre>
+<samp>ADDENVVAR ENVVAR(MAKE) VALUE('/usr/bin/gmake') REPLACE(*YES)
+CHGJOB CCSID(37)</samp>
+</pre></li>
+
+      <li>Run <tt>'QSH'</tt></li>
+
+      <li>Run gunzip on the ICU source code compressed tar archive
+      (icu-<i>X</i>.<i>Y</i>.tgz).</li>
+
+      <li>Run <a href='as_is/os400/unpax-icu.sh'>unpax-icu.sh</a> on the tar file generated from the previous step.</li>
+
+      <li>Change your current directory to icu/source.</li>
+
+      <li>Run <tt>'./runConfigureICU IBMi'</tt>  (See <a href="#HowToConfigureICU">configuration
+      note</a> for details).</li>
+
+      <li>Run <tt>'gmake'</tt> to build ICU.</li>
+
+      <li>Run <tt>'gmake check QIBM_MULTI_THREADED=Y'</tt> to build and run the tests.
+      You can look at the <a href=
+      "http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=/apis/concept4.htm">
+      iSeries Information Center</a> for more details regarding the running of multiple threads
+      on IBM i.</li>
+    </ol>
+
+      <!-- cross -->
+    <h3><a name="HowToCrossCompileICU" href="#HowToCrossCompileICU" id="HowToCrossCompileICU">How To Cross Compile ICU</a></h3>
+		<p>This section will explain how to build ICU on one platform, but to produce binaries intended to run on another. This is commonly known as a cross compile.</p>
+		<p>Normally, in the course of a build, ICU needs to run the tools that it builds in order to generate and package data and test-data.In a cross compilation setting, ICU is built on a different system from that which it eventually runs on. An example might be, if you are building for a small/headless system (such as an embedded device), or a system where you can't easily run the ICU command line tools (any non-UNIX-like system).</p>
+		<p>To reduce confusion, we will here refer to the "A" and the "B" system.System "A" is the actual system we will be running on- the only requirements on it is are it is able to build ICU from the command line targetting itself (with configure or runConfigureICU), and secondly, that it also contain the correct toolchain for compiling and linking for the resultant platform, referred to as the "B" system.</p>
+		<p>The autoconf docs use the term "build" for A, and "host" for B. More details at: <a href="http://www.gnu.org/software/autoconf/manual/html_node/Specifying-Names.html#Specifying-Names">http://www.gnu.org/software/autoconf/manual/html_node/Specifying-Names.html</a></p>
+		<p>Three initially-empty directories will be used in this example:</p>
+		<table summary="Three directories used in this example" class="docTable">
+			<tr>
+				<th align="left">/icu</th><td>a copy of the ICU source</td>
+			</tr>
+			<tr>
+				<th align="left">/buildA</th><td>an empty directory, it will contain ICU built for A<br>(MacOSX in this case)</td>
+			</tr>
+			<tr>
+				<th align="left">/buildB</th><td>an empty directory, it will contain ICU built for B<br>(HaikuOS in this case)</td>
+			</tr>
+		</table>
+		
+		<ol>
+		<li>Check out or unpack the ICU source code into the /icu directory.You will have the directories /icu/source, etc.</li>
+		<li>Build ICU in /buildA normally (using runConfigureICU or configure):
+<pre class="samp">cd /buildA
+sh /icu/source/runConfigureICU <strong>MacOSX</strong>
+gnumake
+</pre>
+		</li>
+		<li>Set PATH or other variables as needed, such as CPPFLAGS.</li>
+		<li>Build ICU in /buildB<br>
+			<div class="note"><b>Note:</b> "<code>--with-cross-build</code>" takes an absolute path.</div>
+<pre class="samp">cd /buildB
+sh /icu/source/configure --host=<strong>i586-pc-haiku</strong> --with-cross-build=<strong>/buildA</strong>
+gnumake</pre>
+		</li>
+		<li>Tests and testdata can be built with "gnumake tests".</li>
+	</ol>
+      <!-- end cross -->
+
+    <!-- end build environment -->
+
+    <h2><a name="HowToPackage" href="#HowToPackage" id="HowToPackage">How To
+    Package ICU</a></h2>
+
+    <p>There are many ways that a person can package ICU with their software
+    products. Usually only the libraries need to be considered for packaging.</p>
+
+    <p>On UNIX, you should use "<tt>gmake install</tt>" to make it easier to
+    develop and package ICU. The bin, lib and include directories are needed to
+    develop applications that use ICU. These directories will be created relative
+    to the "<tt>--prefix=</tt><i>dir</i>" configure option (See the <a href=
+    "#HowToBuildUNIX">UNIX build instructions</a>). When ICU is built on Windows,
+    a similar directory structure is built.</p>
+
+    <p>When changes have been made to the standard ICU distribution, it is
+    recommended that at least one of the following guidelines be followed for
+    special packaging.</p>
+
+    <ol>
+      <li>Add a suffix name to the library names. This can be done with the
+      --with-library-suffix configure option.</li>
+
+      <li>The installation script should install the ICU libraries into the
+      application's directory.</li>
+    </ol>
+
+    <p>Following these guidelines prevents other applications that use a standard
+    ICU distribution from conflicting with any libraries that you need. On
+    operating systems that do not have a standard C++ ABI (name mangling) for
+    compilers, it is recommended to do this special packaging anyway. More
+    details on customizing ICU are available in the <a href=
+    "http://userguide.icu-project.org/">User's Guide</a>. The <a href=
+    "#SourceCode">ICU Source Code Organization</a> section of this readme.html
+    gives a more complete description of the libraries.</p>
+
+    <table class="docTable" summary=
+    "ICU has several libraries for you to use.">
+      <caption>
+        Here is an example of libraries that are frequently packaged.
+      </caption>
+
+      <tr>
+        <th scope="col">Library Name</th>
+
+        <th scope="col">Windows Filename</th>
+
+        <th scope="col">Linux Filename</th>
+
+        <th scope="col">Comment</th>
+      </tr>
+
+      <tr>
+        <td>Data Library</td>
+
+        <td>icudt<i>XY</i>l.dll</td>
+
+        <td>libicudata.so.<i>XY</i>.<i>Z</i></td>
+
+        <td>Data required by the Common and I18n libraries. There are many ways
+        to package and <a href=
+        "http://userguide.icu-project.org/icudata">customize this
+        data</a>, but by default this is all you need.</td>
+      </tr>
+
+      <tr>
+        <td>Common Library</td>
+
+        <td>icuuc<i>XY</i>.dll</td>
+
+        <td>libicuuc.so.<i>XY</i>.<i>Z</i></td>
+
+        <td>Base library required by all other ICU libraries.</td>
+      </tr>
+
+      <tr>
+        <td>Internationalization (i18n) Library</td>
+
+        <td>icuin<i>XY</i>.dll</td>
+
+        <td>libicui18n.so.<i>XY</i>.<i>Z</i></td>
+
+        <td>A library that contains many locale based internationalization (i18n)
+        functions.</td>
+      </tr>
+
+      <tr>
+        <td>Layout Engine</td>
+
+        <td>icule<i>XY</i>.dll</td>
+
+        <td>libicule.so.<i>XY</i>.<i>Z</i></td>
+
+        <td>An optional engine for doing font layout.</td>
+      </tr>
+
+      <tr>
+        <td>Layout Extensions Engine</td>
+
+        <td>iculx<i>XY</i>.dll</td>
+
+        <td>libiculx.so.<i>XY</i>.<i>Z</i></td>
+
+        <td>An optional engine for doing font layout that uses parts of ICU.</td>
+      </tr>
+
+      <tr>
+        <td>ICU I/O (Unicode stdio) Library</td>
+
+        <td>icuio<i>XY</i>.dll</td>
+
+        <td>libicuio.so.<i>XY</i>.<i>Z</i></td>
+
+        <td>An optional library that provides a stdio like API with Unicode
+        support.</td>
+      </tr>
+
+      <tr>
+        <td>Tool Utility Library</td>
+
+        <td>icutu<i>XY</i>.dll</td>
+
+        <td>libicutu.so.<i>XY</i>.<i>Z</i></td>
+
+        <td>An internal library that contains internal APIs that are only used by
+        ICU's tools. If you do not use ICU's tools, you do not need this
+        library.</td>
+      </tr>
+    </table>
+
+    <p>Normally only the above ICU libraries need to be considered for packaging.
+    The versionless symbolic links to these libraries are only needed for easier
+    development. The <i>X</i>, <i>Y</i> and <i>Z</i> parts of the name are the
+    version numbers of ICU. For example, ICU 2.0.2 would have the name
+    libicuuc.so.20.2 for the common library. The exact format of the library
+    names can vary between platforms due to how each platform can handles library
+    versioning.</p>
+
+    <h2><a name="ImportantNotes" href="#ImportantNotes" id=
+    "ImportantNotes">Important Notes About Using ICU</a></h2>
+
+    <h3><a name="ImportantNotesMultithreaded" href="#ImportantNotesMultithreaded"
+    id="ImportantNotesMultithreaded">Using ICU in a Multithreaded
+    Environment</a></h3>
+
+    <p>Some versions of ICU require calling the <code>u_init()</code> function
+    from <code>uclean.h</code> to ensure that ICU is initialized properly. In
+    those ICU versions, <code>u_init()</code> must be called before ICU is used
+    from multiple threads. There is no harm in calling <code>u_init()</code> in a
+    single-threaded application, on a single-CPU machine, or in other cases where
+    <code>u_init()</code> is not required.</p>
+
+    <p>In addition to ensuring thread safety, <code>u_init()</code> also attempts
+    to load at least one ICU data file. Assuming that all data files are packaged
+    together (or are in the same folder in files mode), a failure code from
+    <code>u_init()</code> usually means that the data cannot be found. In this
+    case, the data may not be installed properly, or the application may have
+    failed to call <code>udata_setCommonData()</code> or
+    <code>u_setDataDirectory()</code> which specify to ICU where it can find its
+    data.</p>
+
+    <p>Since <code>u_init()</code> will load only one or two data files, it
+    cannot guarantee that all of the data that an application needs is available.
+    It cannot check for all data files because the set of files is customizable,
+    and some ICU services work without loading any data at all. An application
+    should always check for error codes when opening ICU service objects (using
+    <code>ucnv_open()</code>, <code>ucol_open()</code>, C++ constructors,
+    etc.).</p>
+
+    <h4>ICU 3.4 and later</h4>
+
+    <p>ICU 3.4 self-initializes properly for multi-threaded use. It achieves this
+    without performance penalty by hardcoding the core Unicode properties data,
+    at the cost of some flexibility. (For details see Jitterbug 4497.)</p>
+
+    <p><code>u_init()</code> can be used to check for data loading. It tries to
+    load the converter alias table (<code>cnvalias.icu</code>).</p>
+
+    <h4>ICU 2.6..3.2</h4>
+
+    <p>These ICU versions require a call to <code>u_init()</code> before
+    multi-threaded use. The services that are directly affected are those that
+    don't have a service object and need to be fast: normalization and character
+    properties.</p>
+
+    <p><code>u_init()</code> loads and initializes the data files for
+    normalization and character properties (<code>unorm.icu</code> and
+    <code>uprops.icu</code>) and can therefore also be used to check for data
+    loading.</p>
+
+    <h4>ICU 2.4 and earlier</h4>
+
+    <p>ICU 2.4 and earlier versions were not prepared for multithreaded use on
+    multi-CPU platforms where the CPUs implement weak memory coherency. These
+    CPUs include: Power4, Power5, Alpha, Itanium. <code>u_init()</code> was not
+    defined yet.</p>
+
+    <h4><a name="ImportantNotesHPUX" href="#ImportantNotesHPUX" id=
+    "ImportantNotesHPUX">Using ICU in a Multithreaded Environment on
+    HP-UX</a></h4>
+
+    <p>If you are building ICU with a newer aCC compiler and you are planning on
+    using the older &lt;iostream.h&gt; instead of the newer &lt;iostream&gt;, you
+    will need to use a special configure flag before building ICU. By default,
+    the aCC <a href="http://docs.hp.com/en/1405/options.htm#optioncap-AA">-AA</a>
+    flag is used on HP-UX when the compiler supports that option in order to make
+    ICU thread safe with RogueWave and other libraries using the 2.0 Standard C++
+    library. Your applications that use ICU will also need to use the <a href=
+    "http://docs.hp.com/en/1405/options.htm#optioncap-AA">-AA</a> compiler flag.
+    To turn off this behavior in ICU, you will need to use the --with-iostream=old
+    configure option when you first use runConfigureICU.</p>
+
+    <h4><a name="ImportantNotesSolaris" href="#ImportantNotesSolaris" id=
+    "ImportantNotesSolaris">Using ICU in a Multithreaded Environment on
+    Solaris</a></h4>
+
+    <h5>Linking on Solaris</h5>
+
+    <p>In order to avoid synchronization and threading issues, developers are
+    <strong>suggested</strong> to strictly follow the compiling and linking
+    guidelines for multithreaded applications, specified in the following
+    document from Sun Microsystems. Most notably, pay strict attention to the
+    following statements from Sun:</p>
+
+    <blockquote>
+      <p>To use libthread, specify -lthread before -lc on the ld command line, or
+      last on the cc command line.</p>
+
+      <p>To use libpthread, specify -lpthread before -lc on the ld command line,
+      or last on the cc command line.</p>
+    </blockquote>
+
+    <p>Failure to do this may cause spurious lock conflicts, recursive mutex
+    failure, and deadlock.</p>
+
+    <p>Source: "<i>Solaris Multithreaded Programming Guide, Compiling and
+    Debugging</i>", Sun Microsystems, Inc., Apr 2004<br />
+     <a href=
+    "http://docs.sun.com/app/docs/doc/816-5137/6mba5vpke?a=view">http://docs.sun.com/app/docs/doc/816-5137/6mba5vpke?a=view</a></p>
+
+    <h3><a name="ImportantNotesWindows" href="#ImportantNotesWindows" id=
+    "ImportantNotesWindows">Windows Platform</a></h3>
+
+    <p>If you are building on the Win32 platform, it is important that you
+    understand a few of the following build details.</p>
+
+    <h4>DLL directories and the PATH setting</h4>
+
+    <p>As delivered, the International Components for Unicode build as several
+    DLLs, which are placed in the "<i>&lt;ICU&gt;</i>\bin" directory. You must
+    add this directory to the PATH environment variable in your system, or any
+    executables you build will not be able to access International Components for
+    Unicode libraries. Alternatively, you can copy the DLL files into a directory
+    already in your PATH, but we do not recommend this. You can wind up with
+    multiple copies of the DLL and wind up using the wrong one.</p>
+
+    <h4><a name="ImportantNotesWindowsPath" id=
+    "ImportantNotesWindowsPath">Changing your PATH</a></h4>
+
+    <p><strong>Windows 2000/XP</strong>: Use the System Icon in the Control
+    Panel. Pick the "Advanced" tab. Select the "Environment Variables..."
+    button. Select the variable PATH in the lower box, and select the lower
+    "Edit..." button. In the "Variable Value" box, append the string
+    ";<i>&lt;ICU&gt;</i>\bin" to the end of the path string. If there is
+    nothing there, just type in "<i>&lt;ICU&gt;</i>\bin". Click the Set button,
+    then the OK button.</p>
+
+    <p>Note: When packaging a Windows application for distribution and
+    installation on user systems, copies of the ICU DLLs should be included with
+    the application, and installed for exclusive use by the application. This is
+    the only way to insure that your application is running with the same version
+    of ICU, built with exactly the same options, that you developed and tested
+    with. Refer to Microsoft's guidelines on the usage of DLLs, or search for the
+    phrase "DLL hell" on <a href=
+    "http://msdn.microsoft.com/">msdn.microsoft.com</a>.</p>
+
+    <h3><a name="ImportantNotesUNIX" href="#ImportantNotesUNIX" id=
+    "ImportantNotesUNIX">UNIX Type Platform</a></h3>
+
+    <p>If you are building on a UNIX platform, and if you are installing ICU in a
+    non-standard location, you may need to add the location of your ICU libraries
+    to your <strong>LD_LIBRARY_PATH</strong> or <strong>LIBPATH</strong>
+    environment variable (or the equivalent runtime library path environment
+    variable for your system). The ICU libraries may not link or load properly
+    without doing this.</p>
+
+    <p>Note that if you do not want to have to set this variable, you may instead
+    use the --enable-rpath option at configuration time. This option will
+    instruct the linker to always look for the libraries where they are
+    installed. You will need to use the appropriate linker options when linking
+    your own applications and libraries against ICU, too. Please refer to your
+    system's linker manual for information about runtime paths. The use of rpath
+    also means that when building a new version of ICU you should not have an
+    older version installed in the same place as the new version's installation
+    directory, as the older libraries will used during the build, instead of the
+    new ones, likely leading to an incorrectly build ICU. This is the proper
+    behavior of rpath.</p>
+
+    <h2><a name="PlatformDependencies" href="#PlatformDependencies" id=
+    "PlatformDependencies">Platform Dependencies</a></h2>
+
+    <h3><a name="PlatformDependenciesNew" href="#PlatformDependenciesNew" id=
+    "PlatformDependenciesNew">Porting To A New Platform</a></h3>
+
+    <p>If you are using ICU's Makefiles to build ICU on a new platform, there are
+    a few places where you will need to add or modify some files. If you need
+    more help, you can always ask the <a href=
+    "http://site.icu-project.org/contacts">icu-support mailing list</a>. Once
+    you have finished porting ICU to a new platform, it is recommended that you
+    contribute your changes back to ICU via the icu-support mailing list. This
+    will make it easier for everyone to benefit from your work.</p>
+
+    <h4>Data For a New Platform</h4>
+
+    <p>For some people, it may not be necessary for completely build ICU. Most of
+    the makefiles and build targets are for tools that are used for building
+    ICU's data, and an application's data (when an application uses ICU resource
+    bundles for its data).</p>
+
+    <p>Data files can be built on a different platform when both platforms share
+    the same endianness and the same charset family. This assertion does not
+    include platform dependent DLLs/shared/static libraries. For details see the
+    User Guide <a href="http://userguide.icu-project.org/icudata">ICU
+    Data</a> chapter.</p>
+
+    <p>ICU 3.6 removes the requirement that ICU be completely built in the native
+    operating environment. It adds the icupkg tool which can be run on any
+    platform to turn binary ICU data files from any one of the three formats into
+    any one of the other data formats. This allows a application to use ICU data
+    built anywhere to be used for any other target platform.</p>
+
+    <p><strong>WARNING!</strong> Building ICU without running the tests is not
+    recommended. The tests verify that ICU is safe to use. It is recommended that
+    you try to completely port and test ICU before using the libraries for your
+    own application.</p>
+
+    <h4>Adapting Makefiles For a New Platform</h4>
+
+    <p>Try to follow the build steps from the <a href="#HowToBuildUNIX">UNIX</a>
+    build instructions. If the configure script fails, then you will need to
+    modify some files. Here are the usual steps for porting to a new
+    platform:<br />
+    </p>
+
+    <ol>
+      <li>Create an mh file in icu/source/config/. You can use mh-linux or a
+      similar mh file as your base configuration.</li>
+
+      <li>Modify icu/source/aclocal.m4 to recognize your platform's mh file.</li>
+
+      <li>Modify icu/source/configure.in to properly set your <b>platform</b> C
+      Macro define.</li>
+
+      <li>Run <a href="http://www.gnu.org/software/autoconf/">autoconf</a> in
+      icu/source/ without any options. The autoconf tool is standard on most
+      Linux systems.</li>
+
+      <li>If you have any optimization options that you want to normally use, you
+      can modify icu/source/runConfigureICU to specify those options for your
+      platform.</li>
+
+      <li>Build and test ICU on your platform. It is very important that you run
+      the tests. If you don't run the tests, there is no guarentee that you have
+      properly ported ICU.</li>
+    </ol>
+
+    <h3><a name="PlatformDependenciesImpl" href="#PlatformDependenciesImpl" id=
+    "PlatformDependenciesImpl">Platform Dependent Implementations</a></h3>
+
+    <p>The platform dependencies have been mostly isolated into the following
+    files in the common library. This information can be useful if you are
+    porting ICU to a new platform.</p>
+
+    <ul>
+      <li>
+        <strong>unicode/platform.h.in</strong> (autoconf'ed platforms)<br />
+         <strong>unicode/p<i>XXXX</i>.h</strong> (others: pwin32.h, ppalmos.h,
+        ..): Platform-dependent typedefs and defines:<br />
+        <br />
+         
+
+        <ul>
+          <li>Generic types like UBool, int8_t, int16_t, int32_t, int64_t,
+          uint64_t etc.</li>
+
+          <li>U_EXPORT and U_IMPORT for specifying dynamic library import and
+          export</li>
+
+          <li>&lt;iostream&gt; usability</li>
+
+          <li>Thread safety usability</li>
+        </ul>
+        <br />
+      </li>
+
+      <li>
+        <strong>unicode/putil.h, putil.c</strong>: platform-dependent
+        implementations of various functions that are platform dependent:<br />
+        <br />
+         
+
+        <ul>
+          <li>uprv_isNaN, uprv_isInfinite, uprv_getNaN and uprv_getInfinity for
+          handling special floating point values.</li>
+
+          <li>uprv_tzset, uprv_timezone, uprv_tzname and time for getting
+          platform specific time and time zone information.</li>
+
+          <li>u_getDataDirectory for getting the default data directory.</li>
+
+          <li>uprv_getDefaultLocaleID for getting the default locale
+          setting.</li>
+
+          <li>uprv_getDefaultCodepage for getting the default codepage
+          encoding.</li>
+        </ul>
+        <br />
+      </li>
+
+      <li>
+        <strong>umutex.h, umutex.c</strong>: Code for doing synchronization in
+        multithreaded applications. If you wish to use International Components
+        for Unicode in a multithreaded application, you must provide a
+        synchronization primitive that the classes can use to protect their
+        global data against simultaneous modifications. We already supply working
+        implementations for many platforms that ICU builds on.<br />
+        <br />
+      </li>
+
+      <li><strong>umapfile.h, umapfile.c</strong>: functions for mapping or
+      otherwise reading or loading files into memory. All access by ICU to data
+      from files makes use of these functions.<br />
+      <br />
+      </li>
+
+      <li>Using platform specific #ifdef macros are highly discouraged outside of
+      the scope of these files. When the source code gets updated in the future,
+      these #ifdef's can cause testing problems for your platform.</li>
+    </ul>
+    <hr />
+
+    <p>Copyright &copy; 1997-2011 International Business Machines Corporation and
+    others. All Rights Reserved.<br />
+     IBM Globalization Center of Competency - San Jos&eacute;<br />
+     4400 North First Street<br />
+     San Jos&eacute;, CA 95134<br />
+     USA</p>
+  </body>
+</html>
+
diff --git a/source/Doxyfile.in b/source/Doxyfile.in
new file mode 100644
index 0000000..771b993
--- /dev/null
+++ b/source/Doxyfile.in
@@ -0,0 +1,233 @@
+# Doxyfile 1.3.7
+#  ********************************************************************
+#  * COPYRIGHT:
+#  * Copyright (c) 2004-2010, International Business Machines Corporation
+#  * and others. All Rights Reserved.
+#  ********************************************************************
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME           = "ICU @VERSION@"
+PROJECT_NUMBER         = @VERSION@
+OUTPUT_DIRECTORY       = doc
+CREATE_SUBDIRS         = NO
+OUTPUT_LANGUAGE        = English
+#USE_WINDOWS_ENCODING   = YES
+DOXYFILE_ENCODING	= UTF-8
+BRIEF_MEMBER_DESC      = YES
+REPEAT_BRIEF           = YES
+ABBREVIATE_BRIEF       = 
+ALWAYS_DETAILED_SEC    = NO
+INLINE_INHERITED_MEMB  = NO
+FULL_PATH_NAMES        = NO
+STRIP_FROM_PATH        = 
+STRIP_FROM_INC_PATH    = 
+SHORT_NAMES            = NO
+JAVADOC_AUTOBRIEF      = YES
+MULTILINE_CPP_IS_BRIEF = NO
+#DETAILS_AT_TOP         = NO
+INHERIT_DOCS           = YES
+DISTRIBUTE_GROUP_DOC   = YES
+TAB_SIZE               = 8
+ALIASES                = "memo=\par Note:\n" \
+                         "draft=\xrefitem draft \"Draft\" \"Draft List\"  This API may be changed in the future versions and was introduced in" \
+                         "stable=\xrefitem stable \"Stable\" \"Stable List\"" \
+                         "deprecated=\xrefitem deprecated \"Deprecated\" \"Deprecated List\"" \
+                         "obsolete=\xrefitem obsolete \"Obsolete\" \"Obsolete List\"" \
+                         "system=\xrefitem system \"System\" \"System List\" \n Do not use unless you know what you are doing." \
+                         "internal=\xrefitem internal \"Internal\"  \"Internal List\"  Do not use. This API is for internal use only." 
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+OPTIMIZE_OUTPUT_JAVA   = NO
+SUBGROUPING            = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL            = NO
+EXTRACT_PRIVATE        = NO
+EXTRACT_STATIC         = NO
+EXTRACT_LOCAL_CLASSES  = YES
+EXTRACT_LOCAL_METHODS  = NO
+HIDE_UNDOC_MEMBERS     = NO
+HIDE_UNDOC_CLASSES     = NO
+HIDE_FRIEND_COMPOUNDS  = NO
+HIDE_IN_BODY_DOCS      = NO
+INTERNAL_DOCS          = YES
+CASE_SENSE_NAMES       = YES
+HIDE_SCOPE_NAMES       = NO
+SHOW_INCLUDE_FILES     = YES
+INLINE_INFO            = YES
+SORT_MEMBER_DOCS       = YES
+SORT_BRIEF_DOCS        = NO
+SORT_BY_SCOPE_NAME     = NO
+GENERATE_TODOLIST      = YES
+GENERATE_TESTLIST      = YES
+GENERATE_BUGLIST       = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS       = 
+MAX_INITIALIZER_LINES  = 30
+SHOW_USED_FILES        = YES
+
+# docset
+GENERATE_DOCSET        = NO
+DOCSET_FEEDNAME        = "ICU @VERSION@"
+DOCSET_BUNDLE_ID       = org.icu-project.icu4c
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET                  = NO
+WARNINGS               = YES
+WARN_IF_UNDOCUMENTED   = YES
+WARN_IF_DOC_ERROR      = YES
+WARN_FORMAT            = "$file:$line: $text"
+WARN_LOGFILE           = 
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT                  = ./common/unicode/platform.h @srcdir@/common/unicode @srcdir@/i18n/unicode @srcdir@/io/unicode @srcdir@/layout/LEFontInstance.h @srcdir@/layout/LEGlyphStorage.h @srcdir@/layout/LELanguages.h @srcdir@/layout/LEScripts.h @srcdir@/layout/LESwaps.h @srcdir@/layout/LETypes.h @srcdir@/layout/LayoutEngine.h @srcdir@/layoutex/layout
+FILE_PATTERNS          = *.h
+RECURSIVE              = NO
+EXCLUDE                = @srcdir@/common/unicode/urename.h @srcdir@/common/unicode/udraft.h @srcdir@/common/unicode/udeprctd.h @srcdir@/common/unicode/uobslete.h @srcdir@/common/unicode/ppalmos.h  
+EXCLUDE_SYMLINKS       = NO
+EXCLUDE_PATTERNS       = config*.h
+EXAMPLE_PATH           = 
+EXAMPLE_PATTERNS       = 
+EXAMPLE_RECURSIVE      = NO
+IMAGE_PATH             = 
+INPUT_FILTER           = 
+FILTER_SOURCE_FILES    = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER         = YES
+INLINE_SOURCES         = NO
+STRIP_CODE_COMMENTS    = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION    = YES
+VERBATIM_HEADERS       = YES
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX     = YES
+COLS_IN_ALPHA_INDEX    = 5
+IGNORE_PREFIX          = 
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML          = YES
+HTML_OUTPUT            = html
+HTML_FILE_EXTENSION    = .html
+HTML_HEADER            = 
+HTML_FOOTER            = 
+HTML_STYLESHEET        = 
+HTML_ALIGN_MEMBERS     = YES
+GENERATE_HTMLHELP      = NO
+CHM_FILE               = 
+HHC_LOCATION           = 
+GENERATE_CHI           = NO
+BINARY_TOC             = NO
+TOC_EXPAND             = NO
+DISABLE_INDEX          = NO
+ENUM_VALUES_PER_LINE   = 4
+GENERATE_TREEVIEW      = NO
+TREEVIEW_WIDTH         = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX         = NO
+LATEX_OUTPUT           = latex
+LATEX_CMD_NAME         = latex
+MAKEINDEX_CMD_NAME     = makeindex
+COMPACT_LATEX          = NO
+PAPER_TYPE             = a4wide
+EXTRA_PACKAGES         = 
+LATEX_HEADER           = 
+PDF_HYPERLINKS         = NO
+USE_PDFLATEX           = NO
+LATEX_BATCHMODE        = NO
+LATEX_HIDE_INDICES     = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF           = NO
+RTF_OUTPUT             = rtf
+COMPACT_RTF            = NO
+RTF_HYPERLINKS         = NO
+RTF_STYLESHEET_FILE    = 
+RTF_EXTENSIONS_FILE    = 
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN           = NO
+MAN_OUTPUT             = man
+MAN_EXTENSION          = .3
+MAN_LINKS              = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML           = NO
+XML_OUTPUT             = xml
+XML_SCHEMA             = 
+XML_DTD                = 
+XML_PROGRAMLISTING     = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF   = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD       = NO 
+PERLMOD_LATEX          = YES
+PERLMOD_PRETTY         = YES
+PERLMOD_MAKEVAR_PREFIX = 
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = YES
+EXPAND_ONLY_PREDEF     = YES
+SEARCH_INCLUDES        = YES
+INCLUDE_PATH           = 
+INCLUDE_FILE_PATTERNS  = 
+PREDEFINED             = U_EXPORT2= U_STABLE= U_DRAFT= U_INTERNAL= U_SYSTEM= U_DEPRECATED= U_OBSOLETE= U_CALLCONV= U_CDECL_BEGIN= U_CDECL_END=  U_NO_THROW= U_NAMESPACE_BEGIN= U_NAMESPACE_END= 
+EXPAND_AS_DEFINED      = 
+SKIP_FUNCTION_MACROS   = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+TAGFILES               = 
+GENERATE_TAGFILE       =  "@builddir@/doc/html/icudocs.tag"
+ALLEXTERNALS           = NO
+EXTERNAL_GROUPS        = YES
+PERL_PATH              = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS         = YES
+HIDE_UNDOC_RELATIONS   = YES
+HAVE_DOT               = NO
+CLASS_GRAPH            = YES
+COLLABORATION_GRAPH    = YES
+UML_LOOK               = NO
+TEMPLATE_RELATIONS     = NO
+INCLUDE_GRAPH          = YES
+INCLUDED_BY_GRAPH      = YES
+CALL_GRAPH             = NO
+CALLER_GRAPH		= NO
+GRAPHICAL_HIERARCHY    = YES
+DOT_IMAGE_FORMAT       = png
+DOT_PATH               = 
+#DOT_FONTNAME	       = FreeSans
+DOTFILE_DIRS           = 
+MAX_DOT_GRAPH_WIDTH    = 1024
+MAX_DOT_GRAPH_HEIGHT   = 1024
+MAX_DOT_GRAPH_DEPTH    = 0
+GENERATE_LEGEND        = YES
+DOT_CLEANUP            = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+SEARCHENGINE           = YES
diff --git a/source/Makefile.in b/source/Makefile.in
new file mode 100644
index 0000000..fa94c48
--- /dev/null
+++ b/source/Makefile.in
@@ -0,0 +1,337 @@
+#******************************************************************************
+#
+#   Copyright (C) 1998-2010, International Business Machines
+#   Corporation and others.  All Rights Reserved.
+#
+#******************************************************************************
+## Top-level Makefile.in for ICU
+## Stephen F. Booth
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+
+top_builddir = .
+
+include $(top_builddir)/icudefs.mk
+
+docdir = $(datadir)/doc
+docsubdir = $(PACKAGE)$(ICULIBDASHSUFFIX)/html
+docsubsrchdir = $(docsubdir)/search
+docfilesdir = doc/html
+docfiles = $(docfilesdir)/*.png $(docfilesdir)/*.html $(docfilesdir)/*.css $(docfilesdir)/*.tag $(docfilesdir)/installdox
+docsrchdir = $(docfilesdir)/search
+docsrchfiles = $(docsrchdir)/*
+
+##
+
+## Build directory information
+subdir = .
+
+#AUTOCONF = @AUTOCONF@
+
+## Optional directory setup
+@LAYOUT_TRUE@LAYOUT = layout layoutex
+@ICUIO_TRUE@ICUIO = io
+@EXTRAS_TRUE@EXTRA = extra
+@TESTS_TRUE@TEST = test
+@SAMPLES_TRUE@SAMPLE = samples
+
+DOXYGEN = @DOXYGEN@
+DOCZIP = icu-docs.zip
+
+## Files to remove for 'make clean'
+CLEANFILES = *~
+
+ALL_PKGCONFIG_SUFFIX=uc i18n io le lx
+ALL_PKGCONFIG_FILES=$(ALL_PKGCONFIG_SUFFIX:%=$(top_builddir)/config/icu-%.pc)
+
+## Files built (autoconfed) and installed
+INSTALLED_BUILT_FILES = $(top_builddir)/config/Makefile.inc $(top_builddir)/config/pkgdata.inc $(top_builddir)/config/icu-config @platform_make_fragment@ $(EXTRA_DATA:%=$(DESTDIR)$(pkglibdir)/%) $(ALL_PKGCONFIG_FILES)
+
+## Files built (autoconfed) but not installed
+LOCAL_BUILT_FILES = icudefs.mk config/icucross.mk
+
+DOCDIRS = common i18n
+SUBDIRS =  stubdata common i18n $(LAYOUT) tools data $(ICUIO) $(EXTRA) $(SAMPLE) $(TEST)
+
+SECTION = 1
+
+MANX_FILES = config/icu-config.$(SECTION)
+
+ALL_MAN_FILES = $(MANX_FILES)
+
+## Extra files to install [nothing at present]
+EXTRA_DATA =
+
+## List of phony targets
+.PHONY : all all-local all-recursive install install-local install-udata install-udata-files install-udata-dlls		\
+install-recursive clean clean-local clean-recursive distclean		\
+distclean-local distclean-recursive doc dist dist-local dist-recursive	\
+check check-local check-recursive clean-recursive-with-twist install-icu \
+doc install-doc tests icu4j-data icu4j-data-install update-windows-makefiles xcheck-local xcheck-recursive xperf xcheck xperf-recursive
+
+## Clear suffix list
+.SUFFIXES :
+
+## List of standard targets
+all: all-local all-recursive
+install: install-recursive install-local
+clean: clean-recursive-with-twist clean-local
+distclean : distclean-recursive distclean-local
+dist: dist-recursive dist-local
+check: all check-recursive
+check-recursive: all
+xcheck: all xcheck-recursive
+xperf: all xperf-recursive
+
+xcheck-recursive: all xcheck-local
+	@$(MAKE) -C test xcheck
+
+xperf-recursive: all tests
+	@$(MAKE) -C test/perf xperf
+
+ifeq ($(DOXYGEN),)
+doc:
+	@echo you need Doxygen to generate documentation. Doxygen can be found on the Web
+	@echo at http://www.doxygen.org/
+else
+doc: doc/html/index.html
+
+doc/html/index.html: Doxyfile $(wildcard ./common/unicode/platform.h $(srcdir)/common/unicode/*.h $(srcdir)/i18n/unicode/*.h $(srcdir)/layout/unicode/*.h $(srcdir)/io/unicode/*.h)
+	$(DOXYGEN)
+
+Doxyfile: $(srcdir)/Doxyfile.in
+	CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(DOCZIP): doc
+	-$(RMV) $(DOCZIP)
+	( cd doc/html ; zip -r ../../$(DOCZIP) * )
+endif
+
+LOCAL_SUBDIRS = $(SUBDIRS)
+CLEAN_FIRST_SUBDIRS = tools
+
+$(LIBDIR) $(BINDIR):
+	-$(MKINSTALLDIRS) $@
+
+## Recursive targets
+all-recursive install-recursive clean-recursive distclean-recursive dist-recursive check-recursive: $(LIBDIR) $(BINDIR)
+	@dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(LOCAL_SUBDIRS)'; for subdir in $$list; do \
+	  echo "$(MAKE)[$(MAKELEVEL)]: Making \`$$target' in \`$$subdir'"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-local"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) RECURSIVE=YES $$local_target) || exit; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) "$$target-local" || exit; \
+	fi
+
+clean-recursive-with-twist:
+	$(MAKE) clean-recursive LOCAL_SUBDIRS='$(CLEAN_FIRST_SUBDIRS) $(filter-out $(CLEAN_FIRST_SUBDIRS),$(LOCAL_SUBDIRS))'
+
+all-local: $(srcdir)/configure $(LOCAL_BUILT_FILES) $(INSTALLED_BUILT_FILES)
+
+install-local: install-icu install-manx
+
+install-icu: $(INSTALLED_BUILT_FILES)
+	@$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/config
+	@$(MKINSTALLDIRS) $(DESTDIR)$(pkglibdir)
+	@$(MKINSTALLDIRS) $(DESTDIR)$(bindir)
+	@$(MKINSTALLDIRS) $(DESTDIR)$(sbindir)
+	$(INSTALL_DATA) @platform_make_fragment@ $(DESTDIR)$(pkgdatadir)/config/@platform_make_fragment_name@
+	$(INSTALL_SCRIPT) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(pkgdatadir)/mkinstalldirs
+	$(INSTALL_SCRIPT) $(top_srcdir)/install-sh $(DESTDIR)$(pkgdatadir)/install-sh
+	@$(MKINSTALLDIRS) $(DESTDIR)$(libdir)/pkgconfig
+	$(INSTALL_DATA) $(ALL_PKGCONFIG_FILES) $(DESTDIR)$(libdir)/pkgconfig/
+	$(INSTALL_DATA) $(top_srcdir)/../license.html $(DESTDIR)$(pkgdatadir)/license.html
+	$(INSTALL_SCRIPT) $(top_builddir)/config/icu-config $(DESTDIR)$(bindir)/icu-config
+	$(INSTALL_DATA) $(top_builddir)/config/Makefile.inc $(DESTDIR)$(pkglibdir)/Makefile.inc
+	$(INSTALL_DATA) $(top_builddir)/config/pkgdata.inc $(DESTDIR)$(pkglibdir)/pkgdata.inc
+	cd $(DESTDIR)$(pkglibdir)/..; \
+	    $(RM) current && ln -s $(VERSION) current; \
+	    $(RM) Makefile.inc && ln -s current/Makefile.inc Makefile.inc; \
+	    $(RM) pkgdata.inc && ln -s current/pkgdata.inc pkgdata.inc
+
+ifeq ($(DOXYGEN),)
+install-doc:
+else
+install-doc: doc
+	$(RM) -r $(DESTDIR)$(docdir)/$(docsubdir)
+	$(MKINSTALLDIRS) $(DESTDIR)$(docdir)/$(docsubsrchdir)
+	$(INSTALL_DATA) $(docfiles) $(DESTDIR)$(docdir)/$(docsubdir)
+	$(INSTALL_DATA) $(docsrchfiles) $(DESTDIR)$(docdir)/$(docsubsrchdir)
+endif
+
+$(DESTDIR)$(pkglibdir)/%: $(top_srcdir)/../data/%
+	$(INSTALL_DATA) $< $@
+
+# Build the tests, but don't run them.
+tests: all
+	$(MAKE) -C $(top_builddir)/test
+
+clean-local:
+	test -z "$(CLEANFILES)" || $(RMV) $(CLEANFILES)
+	-$(RMV) "test-*.xml"
+	-$(RMV) "perf-*.xml"
+	-$(RMV) $(ALL_PKGCONFIG_FILES)
+	$(RMV) Doxyfile doc $(DOCZIP)
+
+distclean-local: clean-local
+	$(RMV) $(top_builddir)/config/Makefile.inc $(top_builddir)/config/pkgdata.inc $(top_builddir)/config/icu-config $(top_builddir)/config/icu.pc $(ALL_PKGCONFIG_FILES)
+	$(RMV) config.cache config.log config.status $(top_builddir)/config/icucross.mk autom4te.cache
+	$(RMV) Makefile config/Makefile icudefs.mk $(LIBDIR) $(BINDIR)
+	-$(RMV) dist
+
+check-local: xcheck-local
+	-$(RMV) test-local.xml
+
+xcheck-local: $(top_builddir)/config/icu-config $(top_builddir)/config/Makefile.inc $(top_builddir)/config/pkgdata.inc
+	@echo verifying that icu-config --selfcheck can operate
+	@test "passed" = "$(shell $(top_builddir)/config/icu-config --selfcheck 2>&1)" || (echo "FAIL: icu-config could not run properly." ; exit 1)
+	@echo verifying that $(MAKE) -f Makefile.inc selfcheck can operate
+	@test "passed" = "$(shell $(MAKE) --no-print-directory -f $(top_builddir)/config/Makefile.inc SELFCHECK=1 selfcheck)" || (echo "FAIL: Makefile.inc could not run properly." ; exit 1 )
+	@echo "PASS: config selfcheck OK"
+
+#$(srcdir)/configure : $(srcdir)/configure.in $(top_srcdir)/aclocal.m4
+#	cd $(srcdir) && $(AUTOCONF)
+
+icudefs.mk: $(srcdir)/icudefs.mk.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+		&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+config/icucross.mk: $(top_builddir)/icudefs.mk  $(top_builddir)/Makefile
+	@echo rebuilding $@
+	@(echo "CROSS_ICU_VERSION=$(VERSION)" ;\
+	  echo "TOOLEXEEXT=$(EXEEXT)" \
+	   ) > $@
+	@(echo 'TOOLBINDIR=$$(cross_buildroot)/bin' ;\
+	  echo 'TOOLLIBDIR=$$(cross_buildroot)/lib' ;\
+	  echo "INVOKE=$(LDLIBRARYPATH_ENVVAR)=$(LIBRARY_PATH_PREFIX)"'$$(TOOLLIBDIR):$$(cross_buildroot)/stubdata:$$(cross_buildroot)/tools/ctestfw:$$$$'"$(LDLIBRARYPATH_ENVVAR)" ;\
+	  echo "PKGDATA_INVOKE=$(LDLIBRARYPATH_ENVVAR)=$(LIBRARY_PATH_PREFIX)"'$$(cross_buildroot)/stubdata:$$(cross_buildroot)/tools/ctestfw:$$(TOOLLIBDIR):$$$$'"$(LDLIBRARYPATH_ENVVAR) "'$$'"(PKGDATA_INVOKE_OPTS)" ;\
+	  echo ) >> $@
+
+
+config/icu.pc: $(srcdir)/config/icu.pc.in
+	cd $(top_builddir) \
+	 && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+config/icu-uc.pc: config/icu.pc Makefile icudefs.mk
+	@cat config/icu.pc > $@
+	@echo "Description: $(PACKAGE_ICU_DESCRIPTION): Common and Data libraries" >> $@
+	@echo "Name: $(PACKAGE)-uc" >> $@
+	@echo "Libs:" '-L$${libdir}' "${ICULIBS_UC}" "${ICULIBS_DT}" >> $@
+	@echo "Libs.private:" '$${baselibs}' >> $@
+	@echo $@ updated.
+
+config/icu-i18n.pc: config/icu.pc Makefile icudefs.mk
+	@cat config/icu.pc > $@
+	@echo "Description: $(PACKAGE_ICU_DESCRIPTION): Internationalization library" >> $@
+	@echo "Name: $(PACKAGE)-i18n" >> $@
+	@echo "Requires: icu-uc" >> $@
+	@echo "Libs:" "${ICULIBS_I18N}" >> $@
+	@echo $@ updated.
+
+config/icu-io.pc: config/icu.pc Makefile icudefs.mk
+	@cat config/icu.pc > $@
+	@echo "Description: $(PACKAGE_ICU_DESCRIPTION): Stream and I/O Library" >> $@
+	@echo "Name: $(PACKAGE)-io" >> $@
+	@echo "Requires: icu-i18n" >> $@
+	@echo "Libs:" "${ICULIBS_IO}" >> $@
+	@echo $@ updated.
+
+config/icu-le.pc: config/icu.pc Makefile icudefs.mk
+	@cat config/icu.pc > $@
+	@echo "Description: $(PACKAGE_ICU_DESCRIPTION): Layout library" >> $@
+	@echo "Name: $(PACKAGE)-le" >> $@
+	@echo "Requires: icu-uc" >> $@
+	@echo "Libs:" "${ICULIBS_LE}" >> $@
+	@echo $@ updated.
+
+config/icu-lx.pc: config/icu.pc Makefile icudefs.mk
+	@cat config/icu.pc > $@
+	@echo "Description: $(PACKAGE_ICU_DESCRIPTION): Paragraph Layout library" >> $@
+	@echo "Name: $(PACKAGE)-lx" >> $@
+	@echo "Requires: icu-le" >> $@
+	@echo "Libs:" "${ICULIBS_LX}" >> $@
+	@echo $@ updated.
+
+
+Makefile: $(srcdir)/Makefile.in icudefs.mk $(top_builddir)/config.status
+	cd $(top_builddir) \
+		&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(top_builddir)/config/Makefile.inc: $(srcdir)/config/Makefile.inc.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+		&& CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(top_builddir)/config/pkgdata.inc: icudefs.mk $(top_builddir)/config/pkgdataMakefile
+	cd $(top_builddir)/config; \
+		$(MAKE) -f pkgdataMakefile
+
+$(top_builddir)/config/pkgdataMakefile:
+	cd $(top_builddir) \
+		&& CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(top_builddir)/config/icu-config: $(top_builddir)/Makefile $(top_srcdir)/config/icu-config-top $(top_srcdir)/config/icu-config-bottom $(top_builddir)/config/Makefile.inc @platform_make_fragment@ $(top_srcdir)/config/make2sh.sed
+	-$(RMV) $@
+	$(INSTALL_SCRIPT) $(top_srcdir)/config/icu-config-top $@
+	chmod u+w $@
+	@echo "# Following from @platform_make_fragment@" >> $@
+	LC_ALL=C sed -f $(top_srcdir)/config/make2sh.sed < $(top_builddir)/config/Makefile.inc | grep -v '#M#' | uniq >> $@
+	LC_ALL=C sed -f $(top_srcdir)/config/make2sh.sed < @platform_make_fragment@ | grep -v '#M#' | uniq >> $@
+	cat $(top_srcdir)/config/icu-config-bottom >> $@
+	echo "# Rebuilt on "`date` >> $@
+	chmod u-w $@
+
+config.status: $(srcdir)/configure $(srcdir)/common/unicode/uvernum.h
+	@echo
+	@echo
+	@echo "*** config.status has become stale ***"
+	@echo "   'configure' and/or 'uvernum.h' have changed, please"
+	@echo "  do 'runConfigureICU' (or 'configure') again, as per"
+	@echo "  the readme.html."
+	@echo
+	@echo
+	exit 1
+
+
+install-manx: $(MANX_FILES)
+	$(MKINSTALLDIRS) $(DESTDIR)$(mandir)/man$(SECTION)
+	$(INSTALL_DATA) $? $(DESTDIR)$(mandir)/man$(SECTION)
+
+config/%.$(SECTION): $(srcdir)/config/%.$(SECTION).in
+	cd $(top_builddir) \
+	 && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+icu4j-data-install icu4j-data: all tests
+	@echo ICU4J_ROOT=$(ICU4J_ROOT)
+	@$(MAKE) -C test/testdata $@
+	@$(MAKE) -C data $@
+
+# For updating Windows makefiles
+
+WINDOWS_UPDATEFILES=$(srcdir)/data/makedata.mak $(shell find $(srcdir) -name '*.vcproj' -o -name '*.vcxproj')
+
+WINDOWS_UPDATEFILES_SED=config/windows-update.sed
+
+update-windows-makefiles: config.status
+	@echo Updating Windows Makefiles for ICU $(VERSION)
+	CONFIG_FILES=$(WINDOWS_UPDATEFILES_SED) CONFIG_HEADERS= $(SHELL) ./config.status
+	@for file in $(WINDOWS_UPDATEFILES); do \
+	  echo "Updating $$file"; \
+	  mv "$${file}" "$${file}.bak" && \
+	  sed -f $(WINDOWS_UPDATEFILES_SED) < "$${file}.bak" > "$${file}" && \
+	  rm "$${file}.bak"; \
+	done;
+	$(RMV) $(WINDOWS_UPDATEFILES_SED)
+	@echo Please check over the changes carefully before checking them in.
+
+# For building a source distribution.
+distcheck dist-local:
+	$(MAKE) -C . -f config/dist.mk srcdir="$(srcdir)" top_srcdir="$(top_srcdir)" $@
diff --git a/source/aclocal.m4 b/source/aclocal.m4
new file mode 100644
index 0000000..78ddc14
--- /dev/null
+++ b/source/aclocal.m4
@@ -0,0 +1,487 @@
+# aclocal.m4 for ICU
+# Copyright (c) 1999-2010, International Business Machines Corporation and
+# others. All Rights Reserved.
+# Stephen F. Booth
+
+# @TOP@
+
+# ICU_CHECK_MH_FRAG
+AC_DEFUN(ICU_CHECK_MH_FRAG, [
+	AC_CACHE_CHECK(
+		[which Makefile fragment to use for ${host}],
+		[icu_cv_host_frag],
+		[
+case "${host}" in
+*-*-solaris*)
+	if test "$GCC" = yes; then	
+		icu_cv_host_frag=mh-solaris-gcc
+	else
+		icu_cv_host_frag=mh-solaris
+	fi ;;
+alpha*-*-linux-gnu)
+	if test "$GCC" = yes; then
+		icu_cv_host_frag=mh-alpha-linux-gcc
+	else
+		icu_cv_host_frag=mh-alpha-linux-cc
+	fi ;;
+powerpc*-*-linux*)
+	if test "$GCC" = yes; then
+		icu_cv_host_frag=mh-linux
+	else
+		icu_cv_host_frag=mh-linux-va
+	fi ;;
+*-*-linux*|*-*-gnu|*-*-k*bsd*-gnu|*-*-kopensolaris*-gnu) icu_cv_host_frag=mh-linux ;;
+*-*-cygwin|*-*-mingw32)
+	if test "$GCC" = yes; then
+		AC_TRY_COMPILE([
+#ifndef __MINGW32__
+#error This is not MinGW
+#endif], [], icu_cv_host_frag=mh-mingw, icu_cv_host_frag=mh-cygwin)
+	else
+		icu_cv_host_frag=mh-cygwin-msvc
+	fi ;;
+*-*-*bsd*|*-*-dragonfly*) 	icu_cv_host_frag=mh-bsd-gcc ;;
+*-*-aix*)
+	if test "$GCC" = yes; then
+		icu_cv_host_frag=mh-aix-gcc
+	else
+		icu_cv_host_frag=mh-aix-va
+	fi ;;
+*-*-hpux*)
+	if test "$GCC" = yes; then
+		icu_cv_host_frag=mh-hpux-gcc
+	else
+		case "$CXX" in
+		*aCC)    icu_cv_host_frag=mh-hpux-acc ;;
+		esac
+	fi ;;
+*-*ibm-openedition*|*-*-os390*)	icu_cv_host_frag=mh-os390 ;;
+*-*-os400*)	icu_cv_host_frag=mh-os400 ;;
+*-apple-rhapsody*)	icu_cv_host_frag=mh-darwin ;;
+*-apple-darwin*)	icu_cv_host_frag=mh-darwin ;;
+*-*-beos)       icu_cv_host_frag=mh-beos ;; 
+*-*-haiku)      icu_cv_host_frag=mh-haiku ;; 
+*-*-irix*)	icu_cv_host_frag=mh-irix ;;
+*-dec-osf*) icu_cv_host_frag=mh-alpha-osf ;;
+*-*-nto*)	icu_cv_host_frag=mh-qnx ;;
+*-ncr-*)	icu_cv_host_frag=mh-mpras ;;
+*) 		icu_cv_host_frag=mh-unknown ;;
+esac
+		]
+	)
+])
+
+# ICU_CONDITIONAL - similar example taken from Automake 1.4
+AC_DEFUN(ICU_CONDITIONAL,
+[AC_SUBST($1_TRUE)
+if $2; then
+  $1_TRUE=
+else
+  $1_TRUE='#'
+fi])
+
+# ICU_PROG_LINK - Make sure that the linker is usable
+AC_DEFUN(ICU_PROG_LINK,
+[
+case "${host}" in
+    *-*-cygwin*|*-*-mingw*)
+        if test "$GCC" != yes && test -n "`link --version 2>&1 | grep 'GNU coreutils'`"; then
+            AC_MSG_ERROR([link.exe is not a valid linker. Your PATH is incorrect.
+                  Please follow the directions in ICU's readme.])
+        fi;;
+    *);;
+esac])
+
+# AC_SEARCH_LIBS_FIRST(FUNCTION, SEARCH-LIBS [, ACTION-IF-FOUND
+#            [, ACTION-IF-NOT-FOUND [, OTHER-LIBRARIES]]])
+# Search for a library defining FUNC, then see if it's not already available.
+
+AC_DEFUN(AC_SEARCH_LIBS_FIRST,
+[AC_PREREQ([2.13])
+AC_CACHE_CHECK([for library containing $1], [ac_cv_search_$1],
+[ac_func_search_save_LIBS="$LIBS"
+ac_cv_search_$1="no"
+for i in $2; do
+LIBS="-l$i $5 $ac_func_search_save_LIBS"
+AC_TRY_LINK_FUNC([$1],
+[ac_cv_search_$1="-l$i"
+break])
+done
+if test "$ac_cv_search_$1" = "no"; then
+AC_TRY_LINK_FUNC([$1], [ac_cv_search_$1="none required"])
+fi
+LIBS="$ac_func_search_save_LIBS"])
+if test "$ac_cv_search_$1" != "no"; then
+  test "$ac_cv_search_$1" = "none required" || LIBS="$ac_cv_search_$1 $LIBS"
+  $3
+else :
+  $4
+fi])
+
+
+
+# Check if we can build and use 64-bit libraries
+AC_DEFUN(AC_CHECK_64BIT_LIBS,
+[
+    BITS_REQ=nochange
+    ENABLE_64BIT_LIBS=unknown
+    ## revisit this for cross-compile.
+    
+    AC_ARG_ENABLE(64bit-libs,
+        [  --enable-64bit-libs     (deprecated, use --with-library-bits) build 64-bit libraries [default= platform default]],
+        [echo "note, use --with-library-bits instead of --*-64bit-libs"
+         case "${enableval}" in
+            no|false|32) with_library_bits=32;  ;;
+            yes|true|64) with_library_bits=64else32 ;;
+            nochange) with_library_bits=nochange; ;;
+            *) AC_MSG_ERROR(bad value ${enableval} for '--*-64bit-libs') ;;
+            esac]    )
+    
+
+    AC_ARG_WITH(library-bits,
+        [  --with-library-bits=bits specify how many bits to use for the library (32, 64, 64else32, nochange) [default=nochange]],
+        [case "${withval}" in
+            ""|nochange) BITS_REQ=$withval ;;
+            32|64|64else32) BITS_REQ=$withval ;;
+            *) AC_MSG_ERROR(bad value ${withval} for --with-library-bits) ;;
+            esac])
+        
+    # don't use these for cross compiling
+    if test "$cross_compiling" = "yes" -a "${BITS_REQ}" != "nochange"; then
+        AC_MSG_ERROR([Don't specify bitness when cross compiling. See readme.html for help with cross compilation., and set compiler options manually.])
+    fi
+    AC_CHECK_SIZEOF([void *])
+    AC_MSG_CHECKING([whether runnable 64 bit binaries are built by default])
+    case $ac_cv_sizeof_void_p in
+        8) DEFAULT_64BIT=yes ;;
+        4) DEFAULT_64BIT=no ;;
+        *) DEFAULT_64BIT=unknown
+    esac
+    BITS_GOT=unknown
+    
+    # 'OK' here means, we can exit any further checking, everything's copa
+    BITS_OK=yes
+
+    # do we need to check for buildable/runnable 32 or 64 bit?
+    BITS_CHECK_32=no
+    BITS_CHECK_64=no
+    
+    # later, can we run the 32/64 bit binaries so made?
+    BITS_RUN_32=no
+    BITS_RUN_64=no
+    
+    if test "$DEFAULT_64BIT" = "yes"; then
+        # we get 64 bits by default.
+        BITS_GOT=64
+        case "$BITS_REQ" in
+            32) 
+                # need to look for 32 bit support. 
+                BITS_CHECK_32=yes
+                # not copa.
+                BITS_OK=no;;
+            # everyone else is happy.
+            nochange) ;;
+            *) ;;
+        esac
+    elif test "$DEFAULT_64BIT" = "no"; then
+        # not 64 bit by default.
+        BITS_GOT=32
+        case "$BITS_REQ" in
+            64|64else32)
+                BITS_CHECK_64=yes
+                #BITS_CHECK_32=yes
+                BITS_OK=no;;
+            nochange) ;;
+            *) ;;
+        esac
+    elif test "$DEFAULT_64BIT" = "unknown"; then
+        # cross compiling.
+        BITS_GOT=unknown
+        case "$BITS_REQ" in
+            64|64else32) BITS_OK=no
+            BITS_CHECK_32=yes
+            BITS_CHECK_64=yes ;;
+            32) BITS_OK=no;;
+            nochange) ;;
+            *) ;;
+        esac
+    fi
+            
+    AC_MSG_RESULT($DEFAULT_64BIT);
+
+    if test "$BITS_OK" != "yes"; then
+        # not copa. back these up.
+        CFLAGS_OLD="${CFLAGS}"
+        CXXFLAGS_OLD="${CXXFLAGS}"
+        LDFLAGS_OLD="${LDFLAGS}"
+        ARFLAGS_OLD="${ARFLAGS}"        
+        
+        CFLAGS_32="${CFLAGS}"
+        CXXFLAGS_32="${CXXFLAGS}"
+        LDFLAGS_32="${LDFLAGS}"
+        ARFLAGS_32="${ARFLAGS}"        
+        
+        CFLAGS_64="${CFLAGS}"
+        CXXFLAGS_64="${CXXFLAGS}"
+        LDFLAGS_64="${LDFLAGS}"
+        ARFLAGS_64="${ARFLAGS}"        
+        
+        CAN_BUILD_64=unknown
+        CAN_BUILD_32=unknown
+        # These results can't be cached because is sets compiler flags.
+        if test "$BITS_CHECK_64" = "yes"; then
+            AC_MSG_CHECKING([how to build 64-bit executables])
+            CAN_BUILD_64=no
+            ####
+            # Find out if we think we can *build* for 64 bit. Doesn't check whether we can run it.
+            #  Note, we don't have to actually check if the options work- we'll try them before using them.
+            #  So, only try actually testing the options, if you are trying to decide between multiple options.
+            # On exit from the following clauses:
+            # if CAN_BUILD_64=yes:
+            #    *FLAGS are assumed to contain the right settings for 64bit
+            # else if CAN_BUILD_64=no: (default)
+            #    *FLAGS are assumed to be trashed, and will be reset from *FLAGS_OLD
+            
+            if test "$GCC" = yes; then
+                CFLAGS="${CFLAGS} -m64"
+                CXXFLAGS="${CXXFLAGS} -m64"
+                AC_COMPILE_IFELSE(int main(void) {return (sizeof(void*)*8==64)?0:1;},
+                   CAN_BUILD_64=yes, CAN_BUILD_64=no)
+            else
+                case "${host}" in
+                sparc*-*-solaris*)
+                    # 1. try -m64
+                    CFLAGS="${CFLAGS} -m64"
+                    CXXFLAGS="${CXXFLAGS} -m64"
+                    AC_COMPILE_IFELSE(int main(void) {return (sizeof(void*)*8==64)?0:1;},
+                       CAN_BUILD_64=yes, CAN_BUILD_64=no)
+                    if test "$CAN_BUILD_64" != yes; then
+                        # Nope. back out changes.
+                        CFLAGS="${CFLAGS_OLD}"
+                        CXXFLAGS="${CFLAGS_OLD}"
+                        # 2. try xarch=v9 [deprecated]
+                        ## TODO: cross compile: the following won't work.
+                        SPARCV9=`isainfo -n 2>&1 | grep sparcv9`
+                        SOL64=`$CXX -xarch=v9 2>&1 && $CC -xarch=v9 2>&1 | grep -v usage:`
+                        # "Warning: -xarch=v9 is deprecated, use -m64 to create 64-bit programs"
+                        if test -z "$SOL64" && test -n "$SPARCV9"; then
+                            CFLAGS="${CFLAGS} -xtarget=ultra -xarch=v9"
+                            CXXFLAGS="${CXXFLAGS} -xtarget=ultra -xarch=v9"
+                            LDFLAGS="${LDFLAGS} -xtarget=ultra -xarch=v9"
+                            CAN_BUILD_64=yes
+                        fi
+                    fi
+                    ;;
+                i386-*-solaris*)
+                    # 1. try -m64
+                    CFLAGS="${CFLAGS} -m64"
+                    CXXFLAGS="${CXXFLAGS} -m64"
+                    AC_COMPILE_IFELSE(int main(void) {return (sizeof(void*)*8==64)?0:1;},
+                       CAN_BUILD_64=yes, CAN_BUILD_64=no)
+                    if test "$CAN_BUILD_64" != yes; then
+                        # Nope. back out changes.
+                        CFLAGS="${CFLAGS_OLD}"
+                        CXXFLAGS="${CXXFLAGS_OLD}"
+                        # 2. try the older compiler option
+                        ## TODO: cross compile problem
+                        SOL64=`$CXX -xtarget=generic64 2>&1 && $CC -xtarget=generic64 2>&1 | grep -v usage:`
+                        if test -z "$SOL64" && test -n "$AMD64"; then
+                            CFLAGS="${CFLAGS} -xtarget=generic64"
+                            CXXFLAGS="${CXXFLAGS} -xtarget=generic64"
+                            CAN_BUILD_64=yes
+                        fi
+                    fi
+                    ;;
+                ia64-*-linux*)
+                    # check for ecc/ecpc compiler support
+                    ## TODO: cross compiler problem
+                    if test -n "`$CXX --help 2>&1 && $CC --help 2>&1 | grep -v Intel`"; then
+                        if test -n "`$CXX --help 2>&1 && $CC --help 2>&1 | grep -v Itanium`"; then
+                            CAN_BUILD_64=yes
+                        fi
+                    fi
+                    ;;
+                *-*-cygwin)
+                    # vcvarsamd64.bat should have been used to enable 64-bit builds.
+                    # We only do this check to display the correct answer.
+                    ## TODO: cross compiler problem
+                    if test -n "`$CXX -help 2>&1 | grep 'for x64'`"; then
+                        CAN_BUILD_64=yes
+                    fi
+                    ;;
+                *-*-aix*|powerpc64-*-linux*)
+                    CFLAGS="${CFLAGS} -q64"
+                    CXXFLAGS="${CXXFLAGS} -q64"
+                    LDFLAGS="${LDFLAGS} -q64"
+                    AC_COMPILE_IFELSE(int main(void) {return (sizeof(void*)*8==64)?0:1;},
+                       CAN_BUILD_64=yes, CAN_BUILD_64=no)
+                    if test "$CAN_BUILD_64" = yes; then
+                        # worked- set other options.
+                        case "${host}" in
+                        *-*-aix*)
+                            # tell AIX what executable mode to use.
+                            ARFLAGS="${ARFLAGS} -X64"
+                        esac
+                    fi
+                    ;;
+                *-*-hpux*)
+                    # First we try the newer +DD64, if that doesn't work,
+                    # try other options.
+
+                    CFLAGS="${CFLAGS} +DD64"
+                    CXXFLAGS="${CXXFLAGS} +DD64"
+                    AC_COMPILE_IFELSE(int main(void) {return (sizeof(void*)*8==64)?0:1;},
+                        CAN_BUILD_64=yes, CAN_BUILD_64=no)
+                    if test "$CAN_BUILD_64" != yes; then
+                        # reset
+                        CFLAGS="${CFLAGS_OLD}"
+                        CXXFLAGS="${CXXFLAGS_OLD}"
+                        # append
+                        CFLAGS="${CFLAGS} +DA2.0W"
+                        CXXFLAGS="${CXXFLAGS} +DA2.0W"
+                        AC_COMPILE_IFELSE(int main(void) {return (sizeof(void*)*8==64)?0:1;},
+                            CAN_BUILD_64=yes, CAN_BUILD_64=no)
+                    fi
+                    ;;
+                *-*ibm-openedition*|*-*-os390*)
+                    CFLAGS="${CFLAGS} -Wc,lp64"
+                    CXXFLAGS="${CXXFLAGS} -Wc,lp64"
+                    LDFLAGS="${LDFLAGS} -Wl,lp64"
+                    AC_COMPILE_IFELSE(int main(void) {return (sizeof(void*)*8==64)?0:1;},
+                       CAN_BUILD_64=yes, CAN_BUILD_64=no)
+                    ;;
+                *)
+                    # unknown platform.
+                    ;;
+                esac
+            fi
+            AC_MSG_RESULT($CAN_BUILD_64)
+            if test "$CAN_BUILD_64" = yes; then
+                AC_MSG_CHECKING([whether runnable 64-bit binaries are being built ])
+                AC_TRY_RUN(int main(void) {return (sizeof(void*)*8==64)?0:1;},
+                   BITS_RUN_64=yes, BITS_RUN_64=no, BITS_RUN_64=unknown)
+                AC_MSG_RESULT($BITS_RUN_64);
+
+                CFLAGS_64="${CFLAGS}"
+                CXXFLAGS_64="${CXXFLAGS}"
+                LDFLAGS_64="${LDFLAGS}"
+                ARFLAGS_64="${ARFLAGS}"        
+            fi
+            # put it back.
+            CFLAGS="${CFLAGS_OLD}"
+            CXXFLAGS="${CXXFLAGS_OLD}"
+            LDFLAGS="${LDFLAGS_OLD}"
+            ARFLAGS="${ARFLAGS_OLD}"     
+        fi
+        if test "$BITS_CHECK_32" = "yes"; then
+            # see comment under 'if BITS_CHECK_64', above.
+            AC_MSG_CHECKING([how to build 32-bit executables])
+            if test "$GCC" = yes; then
+                CFLAGS="${CFLAGS} -m32"
+                CXXFLAGS="${CXXFLAGS} -m32"
+                AC_COMPILE_IFELSE(int main(void) {return (sizeof(void*)*8==32)?0:1;},
+                   CAN_BUILD_32=yes, CAN_BUILD_32=no)
+            fi
+            AC_MSG_RESULT($CAN_BUILD_32)
+            if test "$CAN_BUILD_32" = yes; then
+                AC_MSG_CHECKING([whether runnable 32-bit binaries are being built ])
+                AC_TRY_RUN(int main(void) {return (sizeof(void*)*8==32)?0:1;},
+                   BITS_RUN_32=yes, BITS_RUN_32=no, BITS_RUN_32=unknown)
+                AC_MSG_RESULT($BITS_RUN_32);
+                CFLAGS_32="${CFLAGS}"
+                CXXFLAGS_32="${CXXFLAGS}"
+                LDFLAGS_32="${LDFLAGS}"
+                ARFLAGS_32="${ARFLAGS}"        
+            fi
+            # put it back.
+            CFLAGS="${CFLAGS_OLD}"
+            CXXFLAGS="${CXXFLAGS_OLD}"
+            LDFLAGS="${LDFLAGS_OLD}"
+            ARFLAGS="${ARFLAGS_OLD}"     
+        fi
+        
+        ##
+        # OK. Now, we've tested for 32 and 64 bitness. Let's see what we'll do.
+        #
+        
+        # First, implement 64else32
+        if test "$BITS_REQ" = "64else32"; then
+            if test "$BITS_RUN_64" = "yes"; then
+                BITS_REQ=64
+            else
+                # no changes.
+                BITS_OK=yes 
+            fi
+        fi
+        
+        # implement.
+        if test "$BITS_REQ" = "32" -a "$BITS_RUN_32" = "yes"; then
+            CFLAGS="${CFLAGS_32}"
+            CXXFLAGS="${CXXFLAGS_32}"
+            LDFLAGS="${LDFLAGS_32}"
+            ARFLAGS="${ARFLAGS_32}"     
+            BITS_OK=yes
+        elif test "$BITS_REQ" = "64" -a "$BITS_RUN_64" = "yes"; then
+            CFLAGS="${CFLAGS_64}"
+            CXXFLAGS="${CXXFLAGS_64}"
+            LDFLAGS="${LDFLAGS_64}"
+            ARFLAGS="${ARFLAGS_64}"     
+            BITS_OK=yes
+        elif test "$BITS_OK" != "yes"; then
+            AC_MSG_ERROR([Requested $BITS_REQ bit binaries but could not compile and execute them. See readme.html for help with cross compilation., and set compiler options manually.])
+        fi
+     fi
+])
+
+# Strict compilation options.
+AC_DEFUN(AC_CHECK_STRICT_COMPILE,
+[
+    AC_MSG_CHECKING([whether strict compiling is on])
+    AC_ARG_ENABLE(strict,[  --enable-strict         compile with strict compiler options [default=yes]], [
+        if test "$enableval" = no
+        then
+            ac_use_strict_options=no
+        else
+            ac_use_strict_options=yes
+        fi
+      ], [ac_use_strict_options=yes])
+    AC_MSG_RESULT($ac_use_strict_options)
+
+    if test "$ac_use_strict_options" = yes
+    then
+        if test "$GCC" = yes
+        then
+            CFLAGS="$CFLAGS -Wall -ansi -pedantic -Wshadow -Wpointer-arith -Wmissing-prototypes -Wwrite-strings -Wno-long-long"
+            case "${host}" in
+            *-*-solaris*)
+                CFLAGS="$CFLAGS -D__STDC__=0";;
+            esac
+        else
+            case "${host}" in
+            *-*-cygwin)
+                if test "`$CC /help 2>&1 | head -c9`" = "Microsoft"
+                then
+                    CFLAGS="$CFLAGS /W4"
+                fi
+            esac
+        fi
+        if test "$GXX" = yes
+        then
+            CXXFLAGS="$CXXFLAGS -W -Wall -ansi -pedantic -Wpointer-arith -Wwrite-strings -Wno-long-long"
+            case "${host}" in
+            *-*-solaris*)
+                CXXFLAGS="$CXXFLAGS -D__STDC__=0";;
+            esac
+        else
+            case "${host}" in
+            *-*-cygwin)
+                if test "`$CXX /help 2>&1 | head -c9`" = "Microsoft"
+                then
+                    CXXFLAGS="$CXXFLAGS /W4"
+                fi
+            esac
+        fi
+    fi
+])
+
+
diff --git a/source/allinone/icucheck.bat b/source/allinone/icucheck.bat
new file mode 100644
index 0000000..0a92b33
--- /dev/null
+++ b/source/allinone/icucheck.bat
@@ -0,0 +1,122 @@
+@echo off

+REM  ********************************************************************

+REM  * COPYRIGHT:

+REM  * Copyright (c) 2010, International Business Machines Corporation

+REM  * and others. All Rights Reserved.

+REM  ********************************************************************

+

+set ICU_ARCH=%1

+set ICU_DBRL=%2

+

+if "%1" == "" (

+echo Usage: %0 "x86 or x64"  "Debug or Release"

+exit /b 1

+)

+

+if "%2" == "" (

+echo Usage: %0 %1 "Debug or Release"

+exit /b 1

+)

+

+set ICU_OPATH=%PATH%

+

+set ICU_ICUDIR=%~f0\..\..\..

+set ICU_BINDIR=%ICU_ICUDIR%\bin

+set PATH=%ICU_BINDIR%;%PATH%

+

+echo testing ICU in %ICU_ICUDIR%  arch=%ICU_ARCH% type=%ICU_DBRL%

+pushd %ICU_ICUDIR%

+

+@rem factor these out

+set ICUINFO_CMD=%ICU_ICUDIR%\source\tools\icuinfo\%ICU_ARCH%\%ICU_DBRL%\icuinfo.exe

+set INTLTEST_CMD=%ICU_ICUDIR%\source\test\intltest\%ICU_ARCH%\%ICU_DBRL%\intltest.exe

+set IOTEST_CMD=%ICU_ICUDIR%\source\test\iotest\%ICU_ARCH%\%ICU_DBRL%\iotest.exe

+set CINTLTST_CMD=%ICU_ICUDIR%\source\test\cintltst\%ICU_ARCH%\%ICU_DBRL%\cintltst.exe

+set LETEST_CMD=%ICU_ICUDIR%\source\test\letest\%ICU_ARCH%\%ICU_DBRL%\letest.exe

+

+set ICUFAILED=

+set ICURUN=

+set ICUFAILCNT=0

+

+@echo on

+

+@set THT=icuinfo

+@echo ==== %THT% =========================================================================

+%ICUINFO_CMD% %ICUINFO_OPTS%

+

+@IF NOT ERRORLEVEL 1 GOTO OK_%THT%

+@set ICUFAILED=%ICUFAILED% %THT%

+@set ICUFAILCNT=1

+:OK_icuinfo

+@set ICURUN=%ICURUN% %THT%

+

+@set THT=intltest

+@echo ==== %THT% =========================================================================

+@cd %ICU_ICUDIR%\source\test\intltest

+%INTLTEST_CMD% %INTLTEST_OPTS%

+

+@IF NOT ERRORLEVEL 1 GOTO OK_%THT%

+@set ICUFAILED=%ICUFAILED% %THT%

+@set ICUFAILCNT=1

+:OK_intltest

+@set ICURUN=%ICURUN% %THT%

+

+@set THT=iotest

+@echo ==== %THT% =========================================================================

+@cd %ICU_ICUDIR%\source\test\iotest

+%IOTEST_CMD% %IOTEST_OPTS%

+

+@IF NOT ERRORLEVEL 1 GOTO OK_%THT%

+@set ICUFAILED=%ICUFAILED% %THT%

+@set ICUFAILCNT=1

+:OK_IOTEST

+@set ICURUN=%ICURUN% %THT%

+

+@set THT=cintltst

+@echo ==== %THT% =========================================================================

+@cd %ICU_ICUDIR%\source\test\cintltst

+%CINTLTST_CMD% %CINTLTST_OPTS%

+

+@IF NOT ERRORLEVEL 1 GOTO OK_%THT%

+@set ICUFAILED=%ICUFAILED% %THT%

+@set ICUFAILCNT=1

+:OK_cintltst

+@set ICURUN=%ICURUN% %THT%

+

+@set THT=letest

+@echo ==== %THT% =========================================================================

+@cd %ICU_ICUDIR%\source\test\letest

+%LETST_CMD% %LETEST_OPTS%

+

+@IF NOT ERRORLEVEL 1 GOTO OK_%THT%

+@set ICUFAILED=%ICUFAILED% %THT%

+@set ICUFAILCNT=1

+:OK_letest

+@set ICURUN=%ICURUN% %THT%

+

+@echo off

+

+REM clean up

+set PATH=%ICU_OPATH%

+REM unset ICU_OPATH

+popd

+

+@REM done

+

+echo -

+echo -

+echo -

+echo ============================================================

+echo Summary:

+echo -

+echo Tests Run    : %ICURUN%

+

+if %ICUFAILCNT% == 0 (

+	echo " - All Passed!"

+	exit /b 0

+)

+echo Failing Tests: %ICUFAILED%

+echo -

+echo FAILED!

+

+exit /b 1
\ No newline at end of file
diff --git a/source/common/Makefile.in b/source/common/Makefile.in
new file mode 100644
index 0000000..b3fb587
--- /dev/null
+++ b/source/common/Makefile.in
@@ -0,0 +1,216 @@
+#******************************************************************************
+#
+#   Copyright (C) 1999-2010, International Business Machines
+#   Corporation and others.  All Rights Reserved.
+#
+#******************************************************************************
+## Makefile.in for ICU - icuuc.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 = common
+
+# for service hook
+LOCALSVC_CPP=localsvc.cpp
+SVC_HOOK_INC=$(top_builddir)/common/svchook.mk
+
+## Extra files to remove for 'make clean'
+CLEANFILES = *~ $(DEPS) $(IMPORT_LIB) $(MIDDLE_IMPORT_LIB) $(FINAL_IMPORT_LIB) $(SVC_HOOK_INC)
+
+## Target information
+
+TARGET_STUBNAME=$(COMMON_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 = common.res
+endif
+
+ifeq ($(OS390BATCH),1)
+BATCH_TARGET = $(BATCH_COMMON_TARGET)
+BATCH_LIBS = $(BATCH_LIBICUDT) -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)/i18n $(LIBCPPFLAGS) $(CPPFLAGSICUUC)
+# we want DEFS here, because we want icucfg.h
+DEFS += -DU_COMMON_IMPLEMENTATION @DEFS@ 
+LDFLAGS += $(LDFLAGSICUUC)
+
+# for plugin configuration
+CPPFLAGS += "-DDEFAULT_ICU_PLUGINS=\"$(libdir)/icu\" "
+
+# for icu data location
+ifeq ($(PKGDATA_MODE),common)
+CPPFLAGS += "-DU_ICU_DATA_DEFAULT_DIR=\"$(ICUDATA_DIR)\""
+endif
+
+# $(LIBICUDT) is either stub data or the real DLL common data.
+LIBS = $(LIBICUDT) $(DEFAULT_LIBS)
+
+OBJECTS = errorcode.o putil.o umath.o utypes.o uinvchar.o umutex.o ucln_cmn.o \
+uinit.o uobject.o cmemory.o charstr.o \
+udata.o ucmndata.o udatamem.o umapfile.o udataswp.o ucol_swp.o utrace.o \
+uhash.o uhash_us.o uenum.o ustrenum.o uvector.o ustack.o uvectr32.o uvectr64.o \
+ucnv.o ucnv_bld.o ucnv_cnv.o ucnv_io.o ucnv_cb.o ucnv_err.o ucnvlat1.o \
+ucnv_u7.o ucnv_u8.o ucnv_u16.o ucnv_u32.o ucnvscsu.o ucnvbocu.o \
+ucnv_ext.o ucnvmbcs.o ucnv2022.o ucnvhz.o ucnv_lmb.o ucnvisci.o ucnvdisp.o ucnv_set.o \
+uresbund.o ures_cnv.o uresdata.o resbund.o resbund_cnv.o \
+ucat.o locmap.o uloc.o locid.o locutil.o locavailable.o locdispnames.o loclikely.o locresdata.o \
+bytestream.o stringpiece.o \
+ustr_cnv.o unistr_cnv.o unistr.o unistr_case.o unistr_props.o \
+utf_impl.o ustring.o ustrcase.o ucasemap.o cstring.o ustrfmt.o ustrtrns.o ustr_wcs.o utext.o \
+normalizer2impl.o normalizer2.o filterednormalizer2.o normlzr.o unorm.o unormcmp.o unorm_it.o \
+chariter.o schriter.o uchriter.o uiter.o \
+uchar.o uprops.o ucase.o propname.o ubidi_props.o ubidi.o ubidiwrt.o ubidiln.o ushape.o \
+uscript.o usc_impl.o unames.o \
+utrie.o utrie2.o utrie2_builder.o bmpset.o unisetspan.o uset_props.o uniset_props.o uset.o uniset.o usetiter.o ruleiter.o caniter.o unifilt.o unifunct.o \
+uarrsort.o brkiter.o ubrk.o brkeng.o dictbe.o triedict.o \
+rbbi.o rbbidata.o rbbinode.o rbbirb.o rbbiscan.o rbbisetb.o rbbistbl.o rbbitblb.o \
+serv.o servnotf.o servls.o servlk.o servlkf.o servrbf.o servslkf.o \
+uidna.o usprep.o uts46.o punycode.o \
+util.o util_props.o parsepos.o locbased.o cwchar.o wintz.o mutex.o dtintrv.o ucnvsel.o propsvec.o \
+ulist.o uloc_tag.o icudataver.o icuplug.o
+
+## Header files to install
+HEADERS = $(srcdir)/unicode/*.h unicode/*.h
+
+STATIC_OBJECTS = $(OBJECTS:.o=.$(STATIC_O))
+
+DEPS = $(OBJECTS:.o=.d)
+
+-include Makefile.local
+
+-include $(SVC_HOOK_INC)
+
+
+## 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) unicode/platform.h
+
+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
+
+$(SVC_HOOK_INC):
+	@echo generating $@
+	@-test -f $(top_srcdir)/common/$(LOCALSVC_CPP) && ( echo "have $(LOCALSVC_CPP) - U_LOCAL_SERVICE_HOOK=1" ; \
+		echo 'CPPFLAGS +=-DU_LOCAL_SERVICE_HOOK=1' > $@ ; \
+		echo 'OBJECTS += $(LOCALSVC_CPP:%.cpp=%.o)' >> $@ \
+		 ) ; true
+	@echo "# Autogenerated by Makefile" >> $@
+
+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 icucfg.h unicode/platform.h $(SVC_HOOK_INC)
+
+check-local:
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(SVC_HOOK_INC)
+	cd $(top_builddir) \
+	 && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+unicode/platform.h: $(srcdir)/unicode/platform.h.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/source/common/bmpset.cpp b/source/common/bmpset.cpp
new file mode 100644
index 0000000..db87c70
--- /dev/null
+++ b/source/common/bmpset.cpp
@@ -0,0 +1,723 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2007-2008, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  bmpset.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2007jan29
+*   created by: Markus W. Scherer
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uniset.h"
+#include "cmemory.h"
+#include "bmpset.h"
+
+U_NAMESPACE_BEGIN
+
+BMPSet::BMPSet(const int32_t *parentList, int32_t parentListLength) :
+        list(parentList), listLength(parentListLength) {
+    uprv_memset(asciiBytes, 0, sizeof(asciiBytes));
+    uprv_memset(table7FF, 0, sizeof(table7FF));
+    uprv_memset(bmpBlockBits, 0, sizeof(bmpBlockBits));
+
+    /*
+     * Set the list indexes for binary searches for
+     * U+0800, U+1000, U+2000, .., U+F000, U+10000.
+     * U+0800 is the first 3-byte-UTF-8 code point. Lower code points are
+     * looked up in the bit tables.
+     * The last pair of indexes is for finding supplementary code points.
+     */
+    list4kStarts[0]=findCodePoint(0x800, 0, listLength-1);
+    int32_t i;
+    for(i=1; i<=0x10; ++i) {
+        list4kStarts[i]=findCodePoint(i<<12, list4kStarts[i-1], listLength-1);
+    }
+    list4kStarts[0x11]=listLength-1;
+
+    initBits();
+    overrideIllegal();
+}
+
+BMPSet::BMPSet(const BMPSet &otherBMPSet, const int32_t *newParentList, int32_t newParentListLength) :
+        list(newParentList), listLength(newParentListLength) {
+    uprv_memcpy(asciiBytes, otherBMPSet.asciiBytes, sizeof(asciiBytes));
+    uprv_memcpy(table7FF, otherBMPSet.table7FF, sizeof(table7FF));
+    uprv_memcpy(bmpBlockBits, otherBMPSet.bmpBlockBits, sizeof(bmpBlockBits));
+    uprv_memcpy(list4kStarts, otherBMPSet.list4kStarts, sizeof(list4kStarts));
+}
+
+BMPSet::~BMPSet() {
+}
+
+/*
+ * Set bits in a bit rectangle in "vertical" bit organization.
+ * start<limit<=0x800
+ */
+static void set32x64Bits(uint32_t table[64], int32_t start, int32_t limit) {
+    int32_t lead=start>>6;
+    int32_t trail=start&0x3f;
+
+    // Set one bit indicating an all-one block.
+    uint32_t bits=(uint32_t)1<<lead;
+    if((start+1)==limit) {  // Single-character shortcut.
+        table[trail]|=bits;
+        return;
+    }
+
+    int32_t limitLead=limit>>6;
+    int32_t limitTrail=limit&0x3f;
+
+    if(lead==limitLead) {
+        // Partial vertical bit column.
+        while(trail<limitTrail) {
+            table[trail++]|=bits;
+        }
+    } else {
+        // Partial vertical bit column,
+        // followed by a bit rectangle,
+        // followed by another partial vertical bit column.
+        if(trail>0) {
+            do {
+                table[trail++]|=bits;
+            } while(trail<64);
+            ++lead;
+        }
+        if(lead<limitLead) {
+            bits=~((1<<lead)-1);
+            if(limitLead<0x20) {
+                bits&=(1<<limitLead)-1;
+            }
+            for(trail=0; trail<64; ++trail) {
+                table[trail]|=bits;
+            }
+        }
+        bits=1<<limitLead;
+        for(trail=0; trail<limitTrail; ++trail) {
+            table[trail]|=bits;
+        }
+    }
+}
+
+void BMPSet::initBits() {
+    UChar32 start, limit;
+    int32_t listIndex=0;
+
+    // Set asciiBytes[].
+    do {
+        start=list[listIndex++];
+        if(listIndex<listLength) {
+            limit=list[listIndex++];
+        } else {
+            limit=0x110000;
+        }
+        if(start>=0x80) {
+            break;
+        }
+        do {
+            asciiBytes[start++]=1;
+        } while(start<limit && start<0x80);
+    } while(limit<=0x80);
+
+    // Set table7FF[].
+    while(start<0x800) {
+        set32x64Bits(table7FF, start, limit<=0x800 ? limit : 0x800);
+        if(limit>0x800) {
+            start=0x800;
+            break;
+        }
+
+        start=list[listIndex++];
+        if(listIndex<listLength) {
+            limit=list[listIndex++];
+        } else {
+            limit=0x110000;
+        }
+    }
+
+    // Set bmpBlockBits[].
+    int32_t minStart=0x800;
+    while(start<0x10000) {
+        if(limit>0x10000) {
+            limit=0x10000;
+        }
+
+        if(start<minStart) {
+            start=minStart;
+        }
+        if(start<limit) {  // Else: Another range entirely in a known mixed-value block.
+            if(start&0x3f) {
+                // Mixed-value block of 64 code points.
+                start>>=6;
+                bmpBlockBits[start&0x3f]|=0x10001<<(start>>6);
+                start=(start+1)<<6;  // Round up to the next block boundary.
+                minStart=start;      // Ignore further ranges in this block.
+            }
+            if(start<limit) {
+                if(start<(limit&~0x3f)) {
+                    // Multiple all-ones blocks of 64 code points each.
+                    set32x64Bits(bmpBlockBits, start>>6, limit>>6);
+                }
+
+                if(limit&0x3f) {
+                    // Mixed-value block of 64 code points.
+                    limit>>=6;
+                    bmpBlockBits[limit&0x3f]|=0x10001<<(limit>>6);
+                    limit=(limit+1)<<6;  // Round up to the next block boundary.
+                    minStart=limit;      // Ignore further ranges in this block.
+                }
+            }
+        }
+
+        if(limit==0x10000) {
+            break;
+        }
+
+        start=list[listIndex++];
+        if(listIndex<listLength) {
+            limit=list[listIndex++];
+        } else {
+            limit=0x110000;
+        }
+    }
+}
+
+/*
+ * Override some bits and bytes to the result of contains(FFFD)
+ * for faster validity checking at runtime.
+ * No need to set 0 values where they were reset to 0 in the constructor
+ * and not modified by initBits().
+ * (asciiBytes[] trail bytes, table7FF[] 0..7F, bmpBlockBits[] 0..7FF)
+ * Need to set 0 values for surrogates D800..DFFF.
+ */
+void BMPSet::overrideIllegal() {
+    uint32_t bits, mask;
+    int32_t i;
+
+    if(containsSlow(0xfffd, list4kStarts[0xf], list4kStarts[0x10])) {
+        // contains(FFFD)==TRUE
+        for(i=0x80; i<0xc0; ++i) {
+            asciiBytes[i]=1;
+        }
+
+        bits=3;                 // Lead bytes 0xC0 and 0xC1.
+        for(i=0; i<64; ++i) {
+            table7FF[i]|=bits;
+        }
+
+        bits=1;                 // Lead byte 0xE0.
+        for(i=0; i<32; ++i) {   // First half of 4k block.
+            bmpBlockBits[i]|=bits;
+        }
+
+        mask=~(0x10001<<0xd);   // Lead byte 0xED.
+        bits=1<<0xd;
+        for(i=32; i<64; ++i) {  // Second half of 4k block.
+            bmpBlockBits[i]=(bmpBlockBits[i]&mask)|bits;
+        }
+    } else {
+        // contains(FFFD)==FALSE
+        mask=~(0x10001<<0xd);   // Lead byte 0xED.
+        for(i=32; i<64; ++i) {  // Second half of 4k block.
+            bmpBlockBits[i]&=mask;
+        }
+    }
+}
+
+int32_t BMPSet::findCodePoint(UChar32 c, int32_t lo, int32_t hi) const {
+    /* Examples:
+                                       findCodePoint(c)
+       set              list[]         c=0 1 3 4 7 8
+       ===              ==============   ===========
+       []               [110000]         0 0 0 0 0 0
+       [\u0000-\u0003]  [0, 4, 110000]   1 1 1 2 2 2
+       [\u0004-\u0007]  [4, 8, 110000]   0 0 0 1 1 2
+       [:Any:]          [0, 110000]      1 1 1 1 1 1
+     */
+
+    // Return the smallest i such that c < list[i].  Assume
+    // list[len - 1] == HIGH and that c is legal (0..HIGH-1).
+    if (c < list[lo])
+        return lo;
+    // High runner test.  c is often after the last range, so an
+    // initial check for this condition pays off.
+    if (lo >= hi || c >= list[hi-1])
+        return hi;
+    // invariant: c >= list[lo]
+    // invariant: c < list[hi]
+    for (;;) {
+        int32_t i = (lo + hi) >> 1;
+        if (i == lo) {
+            break; // Found!
+        } else if (c < list[i]) {
+            hi = i;
+        } else {
+            lo = i;
+        }
+    }
+    return hi;
+}
+
+UBool
+BMPSet::contains(UChar32 c) const {
+    if((uint32_t)c<=0x7f) {
+        return (UBool)asciiBytes[c];
+    } else if((uint32_t)c<=0x7ff) {
+        return (UBool)((table7FF[c&0x3f]&((uint32_t)1<<(c>>6)))!=0);
+    } else if((uint32_t)c<0xd800 || (c>=0xe000 && c<=0xffff)) {
+        int lead=c>>12;
+        uint32_t twoBits=(bmpBlockBits[(c>>6)&0x3f]>>lead)&0x10001;
+        if(twoBits<=1) {
+            // All 64 code points with the same bits 15..6
+            // are either in the set or not.
+            return (UBool)twoBits;
+        } else {
+            // Look up the code point in its 4k block of code points.
+            return containsSlow(c, list4kStarts[lead], list4kStarts[lead+1]);
+        }
+    } else if((uint32_t)c<=0x10ffff) {
+        // surrogate or supplementary code point
+        return containsSlow(c, list4kStarts[0xd], list4kStarts[0x11]);
+    } else {
+        // Out-of-range code points get FALSE, consistent with long-standing
+        // behavior of UnicodeSet::contains(c).
+        return FALSE;
+    }
+}
+
+/*
+ * Check for sufficient length for trail unit for each surrogate pair.
+ * Handle single surrogates as surrogate code points as usual in ICU.
+ */
+const UChar *
+BMPSet::span(const UChar *s, const UChar *limit, USetSpanCondition spanCondition) const {
+    UChar c, c2;
+
+    if(spanCondition) {
+        // span
+        do {
+            c=*s;
+            if(c<=0x7f) {
+                if(!asciiBytes[c]) {
+                    break;
+                }
+            } else if(c<=0x7ff) {
+                if((table7FF[c&0x3f]&((uint32_t)1<<(c>>6)))==0) {
+                    break;
+                }
+            } else if(c<0xd800 || c>=0xe000) {
+                int lead=c>>12;
+                uint32_t twoBits=(bmpBlockBits[(c>>6)&0x3f]>>lead)&0x10001;
+                if(twoBits<=1) {
+                    // All 64 code points with the same bits 15..6
+                    // are either in the set or not.
+                    if(twoBits==0) {
+                        break;
+                    }
+                } else {
+                    // Look up the code point in its 4k block of code points.
+                    if(!containsSlow(c, list4kStarts[lead], list4kStarts[lead+1])) {
+                        break;
+                    }
+                }
+            } else if(c>=0xdc00 || (s+1)==limit || (c2=s[1])<0xdc00 || c2>=0xe000) {
+                // surrogate code point
+                if(!containsSlow(c, list4kStarts[0xd], list4kStarts[0xe])) {
+                    break;
+                }
+            } else {
+                // surrogate pair
+                if(!containsSlow(U16_GET_SUPPLEMENTARY(c, c2), list4kStarts[0x10], list4kStarts[0x11])) {
+                    break;
+                }
+                ++s;
+            }
+        } while(++s<limit);
+    } else {
+        // span not
+        do {
+            c=*s;
+            if(c<=0x7f) {
+                if(asciiBytes[c]) {
+                    break;
+                }
+            } else if(c<=0x7ff) {
+                if((table7FF[c&0x3f]&((uint32_t)1<<(c>>6)))!=0) {
+                    break;
+                }
+            } else if(c<0xd800 || c>=0xe000) {
+                int lead=c>>12;
+                uint32_t twoBits=(bmpBlockBits[(c>>6)&0x3f]>>lead)&0x10001;
+                if(twoBits<=1) {
+                    // All 64 code points with the same bits 15..6
+                    // are either in the set or not.
+                    if(twoBits!=0) {
+                        break;
+                    }
+                } else {
+                    // Look up the code point in its 4k block of code points.
+                    if(containsSlow(c, list4kStarts[lead], list4kStarts[lead+1])) {
+                        break;
+                    }
+                }
+            } else if(c>=0xdc00 || (s+1)==limit || (c2=s[1])<0xdc00 || c2>=0xe000) {
+                // surrogate code point
+                if(containsSlow(c, list4kStarts[0xd], list4kStarts[0xe])) {
+                    break;
+                }
+            } else {
+                // surrogate pair
+                if(containsSlow(U16_GET_SUPPLEMENTARY(c, c2), list4kStarts[0x10], list4kStarts[0x11])) {
+                    break;
+                }
+                ++s;
+            }
+        } while(++s<limit);
+    }
+    return s;
+}
+
+/* Symmetrical with span(). */
+const UChar *
+BMPSet::spanBack(const UChar *s, const UChar *limit, USetSpanCondition spanCondition) const {
+    UChar c, c2;
+
+    if(spanCondition) {
+        // span
+        for(;;) {
+            c=*(--limit);
+            if(c<=0x7f) {
+                if(!asciiBytes[c]) {
+                    break;
+                }
+            } else if(c<=0x7ff) {
+                if((table7FF[c&0x3f]&((uint32_t)1<<(c>>6)))==0) {
+                    break;
+                }
+            } else if(c<0xd800 || c>=0xe000) {
+                int lead=c>>12;
+                uint32_t twoBits=(bmpBlockBits[(c>>6)&0x3f]>>lead)&0x10001;
+                if(twoBits<=1) {
+                    // All 64 code points with the same bits 15..6
+                    // are either in the set or not.
+                    if(twoBits==0) {
+                        break;
+                    }
+                } else {
+                    // Look up the code point in its 4k block of code points.
+                    if(!containsSlow(c, list4kStarts[lead], list4kStarts[lead+1])) {
+                        break;
+                    }
+                }
+            } else if(c<0xdc00 || s==limit || (c2=*(limit-1))<0xd800 || c2>=0xdc00) {
+                // surrogate code point
+                if(!containsSlow(c, list4kStarts[0xd], list4kStarts[0xe])) {
+                    break;
+                }
+            } else {
+                // surrogate pair
+                if(!containsSlow(U16_GET_SUPPLEMENTARY(c2, c), list4kStarts[0x10], list4kStarts[0x11])) {
+                    break;
+                }
+                --limit;
+            }
+            if(s==limit) {
+                return s;
+            }
+        }
+    } else {
+        // span not
+        for(;;) {
+            c=*(--limit);
+            if(c<=0x7f) {
+                if(asciiBytes[c]) {
+                    break;
+                }
+            } else if(c<=0x7ff) {
+                if((table7FF[c&0x3f]&((uint32_t)1<<(c>>6)))!=0) {
+                    break;
+                }
+            } else if(c<0xd800 || c>=0xe000) {
+                int lead=c>>12;
+                uint32_t twoBits=(bmpBlockBits[(c>>6)&0x3f]>>lead)&0x10001;
+                if(twoBits<=1) {
+                    // All 64 code points with the same bits 15..6
+                    // are either in the set or not.
+                    if(twoBits!=0) {
+                        break;
+                    }
+                } else {
+                    // Look up the code point in its 4k block of code points.
+                    if(containsSlow(c, list4kStarts[lead], list4kStarts[lead+1])) {
+                        break;
+                    }
+                }
+            } else if(c<0xdc00 || s==limit || (c2=*(limit-1))<0xd800 || c2>=0xdc00) {
+                // surrogate code point
+                if(containsSlow(c, list4kStarts[0xd], list4kStarts[0xe])) {
+                    break;
+                }
+            } else {
+                // surrogate pair
+                if(containsSlow(U16_GET_SUPPLEMENTARY(c2, c), list4kStarts[0x10], list4kStarts[0x11])) {
+                    break;
+                }
+                --limit;
+            }
+            if(s==limit) {
+                return s;
+            }
+        }
+    }
+    return limit+1;
+}
+
+/*
+ * Precheck for sufficient trail bytes at end of string only once per span.
+ * Check validity.
+ */
+const uint8_t *
+BMPSet::spanUTF8(const uint8_t *s, int32_t length, USetSpanCondition spanCondition) const {
+    const uint8_t *limit=s+length;
+    uint8_t b=*s;
+    if((int8_t)b>=0) {
+        // Initial all-ASCII span.
+        if(spanCondition) {
+            do {
+                if(!asciiBytes[b] || ++s==limit) {
+                    return s;
+                }
+                b=*s;
+            } while((int8_t)b>=0);
+        } else {
+            do {
+                if(asciiBytes[b] || ++s==limit) {
+                    return s;
+                }
+                b=*s;
+            } while((int8_t)b>=0);
+        }
+        length=(int32_t)(limit-s);
+    }
+
+    if(spanCondition!=USET_SPAN_NOT_CONTAINED) {
+        spanCondition=USET_SPAN_CONTAINED;  // Pin to 0/1 values.
+    }
+
+    const uint8_t *limit0=limit;
+
+    /*
+     * Make sure that the last 1/2/3/4-byte sequence before limit is complete
+     * or runs into a lead byte.
+     * In the span loop compare s with limit only once
+     * per multi-byte character.
+     *
+     * Give a trailing illegal sequence the same value as the result of contains(FFFD),
+     * including it if that is part of the span, otherwise set limit0 to before
+     * the truncated sequence.
+     */
+    b=*(limit-1);
+    if((int8_t)b<0) {
+        // b>=0x80: lead or trail byte
+        if(b<0xc0) {
+            // single trail byte, check for preceding 3- or 4-byte lead byte
+            if(length>=2 && (b=*(limit-2))>=0xe0) {
+                limit-=2;
+                if(asciiBytes[0x80]!=spanCondition) {
+                    limit0=limit;
+                }
+            } else if(b<0xc0 && b>=0x80 && length>=3 && (b=*(limit-3))>=0xf0) {
+                // 4-byte lead byte with only two trail bytes
+                limit-=3;
+                if(asciiBytes[0x80]!=spanCondition) {
+                    limit0=limit;
+                }
+            }
+        } else {
+            // lead byte with no trail bytes
+            --limit;
+            if(asciiBytes[0x80]!=spanCondition) {
+                limit0=limit;
+            }
+        }
+    }
+
+    uint8_t t1, t2, t3;
+
+    while(s<limit) {
+        b=*s;
+        if(b<0xc0) {
+            // ASCII; or trail bytes with the result of contains(FFFD).
+            if(spanCondition) {
+                do {
+                    if(!asciiBytes[b]) {
+                        return s;
+                    } else if(++s==limit) {
+                        return limit0;
+                    }
+                    b=*s;
+                } while(b<0xc0);
+            } else {
+                do {
+                    if(asciiBytes[b]) {
+                        return s;
+                    } else if(++s==limit) {
+                        return limit0;
+                    }
+                    b=*s;
+                } while(b<0xc0);
+            }
+        }
+        ++s;  // Advance past the lead byte.
+        if(b>=0xe0) {
+            if(b<0xf0) {
+                if( /* handle U+0000..U+FFFF inline */
+                    (t1=(uint8_t)(s[0]-0x80)) <= 0x3f &&
+                    (t2=(uint8_t)(s[1]-0x80)) <= 0x3f
+                ) {
+                    b&=0xf;
+                    uint32_t twoBits=(bmpBlockBits[t1]>>b)&0x10001;
+                    if(twoBits<=1) {
+                        // All 64 code points with this lead byte and middle trail byte
+                        // are either in the set or not.
+                        if(twoBits!=(uint32_t)spanCondition) {
+                            return s-1;
+                        }
+                    } else {
+                        // Look up the code point in its 4k block of code points.
+                        UChar32 c=(b<<12)|(t1<<6)|t2;
+                        if(containsSlow(c, list4kStarts[b], list4kStarts[b+1]) != spanCondition) {
+                            return s-1;
+                        }
+                    }
+                    s+=2;
+                    continue;
+                }
+            } else if( /* handle U+10000..U+10FFFF inline */
+                (t1=(uint8_t)(s[0]-0x80)) <= 0x3f &&
+                (t2=(uint8_t)(s[1]-0x80)) <= 0x3f &&
+                (t3=(uint8_t)(s[2]-0x80)) <= 0x3f
+            ) {
+                // Give an illegal sequence the same value as the result of contains(FFFD).
+                UChar32 c=((UChar32)(b-0xf0)<<18)|((UChar32)t1<<12)|(t2<<6)|t3;
+                if( (   (0x10000<=c && c<=0x10ffff) ?
+                            containsSlow(c, list4kStarts[0x10], list4kStarts[0x11]) :
+                            asciiBytes[0x80]
+                    ) != spanCondition
+                ) {
+                    return s-1;
+                }
+                s+=3;
+                continue;
+            }
+        } else /* 0xc0<=b<0xe0 */ {
+            if( /* handle U+0000..U+07FF inline */
+                (t1=(uint8_t)(*s-0x80)) <= 0x3f
+            ) {
+                if((USetSpanCondition)((table7FF[t1]&((uint32_t)1<<(b&0x1f)))!=0) != spanCondition) {
+                    return s-1;
+                }
+                ++s;
+                continue;
+            }
+        }
+
+        // Give an illegal sequence the same value as the result of contains(FFFD).
+        // Handle each byte of an illegal sequence separately to simplify the code;
+        // no need to optimize error handling.
+        if(asciiBytes[0x80]!=spanCondition) {
+            return s-1;
+        }
+    }
+
+    return limit0;
+}
+
+/*
+ * While going backwards through UTF-8 optimize only for ASCII.
+ * Unlike UTF-16, UTF-8 is not forward-backward symmetrical, that is, it is not
+ * possible to tell from the last byte in a multi-byte sequence how many
+ * preceding bytes there should be. Therefore, going backwards through UTF-8
+ * is much harder than going forward.
+ */
+int32_t
+BMPSet::spanBackUTF8(const uint8_t *s, int32_t length, USetSpanCondition spanCondition) const {
+    if(spanCondition!=USET_SPAN_NOT_CONTAINED) {
+        spanCondition=USET_SPAN_CONTAINED;  // Pin to 0/1 values.
+    }
+
+    uint8_t b;
+
+    do {
+        b=s[--length];
+        if((int8_t)b>=0) {
+            // ASCII sub-span
+            if(spanCondition) {
+                do {
+                    if(!asciiBytes[b]) {
+                        return length+1;
+                    } else if(length==0) {
+                        return 0;
+                    }
+                    b=s[--length];
+                } while((int8_t)b>=0);
+            } else {
+                do {
+                    if(asciiBytes[b]) {
+                        return length+1;
+                    } else if(length==0) {
+                        return 0;
+                    }
+                    b=s[--length];
+                } while((int8_t)b>=0);
+            }
+        }
+
+        int32_t prev=length;
+        UChar32 c;
+        if(b<0xc0) {
+            // trail byte: collect a multi-byte character
+            c=utf8_prevCharSafeBody(s, 0, &length, b, -1);
+            if(c<0) {
+                c=0xfffd;
+            }
+        } else {
+            // lead byte in last-trail position
+            c=0xfffd;
+        }
+        // c is a valid code point, not ASCII, not a surrogate
+        if(c<=0x7ff) {
+            if((USetSpanCondition)((table7FF[c&0x3f]&((uint32_t)1<<(c>>6)))!=0) != spanCondition) {
+                return prev+1;
+            }
+        } else if(c<=0xffff) {
+            int lead=c>>12;
+            uint32_t twoBits=(bmpBlockBits[(c>>6)&0x3f]>>lead)&0x10001;
+            if(twoBits<=1) {
+                // All 64 code points with the same bits 15..6
+                // are either in the set or not.
+                if(twoBits!=(uint32_t)spanCondition) {
+                    return prev+1;
+                }
+            } else {
+                // Look up the code point in its 4k block of code points.
+                if(containsSlow(c, list4kStarts[lead], list4kStarts[lead+1]) != spanCondition) {
+                    return prev+1;
+                }
+            }
+        } else {
+            if(containsSlow(c, list4kStarts[0x10], list4kStarts[0x11]) != spanCondition) {
+                return prev+1;
+            }
+        }
+    } while(length>0);
+    return 0;
+}
+
+U_NAMESPACE_END
diff --git a/source/common/bmpset.h b/source/common/bmpset.h
new file mode 100644
index 0000000..d9e08ea
--- /dev/null
+++ b/source/common/bmpset.h
@@ -0,0 +1,161 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2007, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  bmpset.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2007jan29
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __BMPSET_H__
+#define __BMPSET_H__
+
+#include "unicode/utypes.h"
+#include "unicode/uniset.h"
+
+U_NAMESPACE_BEGIN
+
+/*
+ * Helper class for frozen UnicodeSets, implements contains() and span()
+ * optimized for BMP code points. Structured to be UTF-8-friendly.
+ *
+ * ASCII: Look up bytes.
+ * 2-byte characters: Bits organized vertically.
+ * 3-byte characters: Use zero/one/mixed data per 64-block in U+0000..U+FFFF,
+ *                    with mixed for illegal ranges.
+ * Supplementary characters: Call contains() on the parent set.
+ */
+class BMPSet : public UMemory {
+public:
+    BMPSet(const int32_t *parentList, int32_t parentListLength);
+    BMPSet(const BMPSet &otherBMPSet, const int32_t *newParentList, int32_t newParentListLength);
+    virtual ~BMPSet();
+
+    virtual UBool contains(UChar32 c) const;
+
+    /*
+     * Span the initial substring for which each character c has spanCondition==contains(c).
+     * It must be s<limit and spanCondition==0 or 1.
+     * @return The string pointer which limits the span.
+     */
+    const UChar *span(const UChar *s, const UChar *limit, USetSpanCondition spanCondition) const;
+
+    /*
+     * Span the trailing substring for which each character c has spanCondition==contains(c).
+     * It must be s<limit and spanCondition==0 or 1.
+     * @return The string pointer which starts the span.
+     */
+    const UChar *spanBack(const UChar *s, const UChar *limit, USetSpanCondition spanCondition) const;
+
+    /*
+     * Span the initial substring for which each character c has spanCondition==contains(c).
+     * It must be length>0 and spanCondition==0 or 1.
+     * @return The string pointer which limits the span.
+     */
+    const uint8_t *spanUTF8(const uint8_t *s, int32_t length, USetSpanCondition spanCondition) const;
+
+    /*
+     * Span the trailing substring for which each character c has spanCondition==contains(c).
+     * It must be length>0 and spanCondition==0 or 1.
+     * @return The start of the span.
+     */
+    int32_t spanBackUTF8(const uint8_t *s, int32_t length, USetSpanCondition spanCondition) const;
+
+private:
+    void initBits();
+    void overrideIllegal();
+
+    /**
+     * Same as UnicodeSet::findCodePoint(UChar32 c) const except that the
+     * binary search is restricted for finding code points in a certain range.
+     *
+     * For restricting the search for finding in the range start..end,
+     * pass in
+     *   lo=findCodePoint(start) and
+     *   hi=findCodePoint(end)
+     * with 0<=lo<=hi<len.
+     * findCodePoint(c) defaults to lo=0 and hi=len-1.
+     *
+     * @param c a character in a subrange of MIN_VALUE..MAX_VALUE
+     * @param lo The lowest index to be returned.
+     * @param hi The highest index to be returned.
+     * @return the smallest integer i in the range lo..hi,
+     *         inclusive, such that c < list[i]
+     */
+    int32_t findCodePoint(UChar32 c, int32_t lo, int32_t hi) const;
+
+    inline UBool containsSlow(UChar32 c, int32_t lo, int32_t hi) const;
+
+    /*
+     * One byte per ASCII character, or trail byte in lead position.
+     * 0 or 1 for ASCII characters.
+     * The value for trail bytes is the result of contains(FFFD)
+     * for faster validity checking at runtime.
+     */
+    UBool asciiBytes[0xc0];
+
+    /*
+     * One bit per code point from U+0000..U+07FF.
+     * The bits are organized vertically; consecutive code points
+     * correspond to the same bit positions in consecutive table words.
+     * With code point parts
+     *   lead=c{10..6}
+     *   trail=c{5..0}
+     * it is set.contains(c)==(table7FF[trail] bit lead)
+     *
+     * Bits for 0..7F (non-shortest forms) are set to the result of contains(FFFD)
+     * for faster validity checking at runtime.
+     */
+    uint32_t table7FF[64];
+
+    /*
+     * One bit per 64 BMP code points.
+     * The bits are organized vertically; consecutive 64-code point blocks
+     * correspond to the same bit position in consecutive table words.
+     * With code point parts
+     *   lead=c{15..12}
+     *   t1=c{11..6}
+     * test bits (lead+16) and lead in bmpBlockBits[t1].
+     * If the upper bit is 0, then the lower bit indicates if contains(c)
+     * for all code points in the 64-block.
+     * If the upper bit is 1, then the block is mixed and set.contains(c)
+     * must be called.
+     *
+     * Bits for 0..7FF (non-shortest forms) and D800..DFFF are set to
+     * the result of contains(FFFD) for faster validity checking at runtime.
+     */
+    uint32_t bmpBlockBits[64];
+
+    /*
+     * Inversion list indexes for restricted binary searches in
+     * findCodePoint(), from
+     * findCodePoint(U+0800, U+1000, U+2000, .., U+F000, U+10000).
+     * U+0800 is the first 3-byte-UTF-8 code point. Code points below U+0800 are
+     * always looked up in the bit tables.
+     * The last pair of indexes is for finding supplementary code points.
+     */
+    int32_t list4kStarts[18];
+
+    /*
+     * The inversion list of the parent set, for the slower contains() implementation
+     * for mixed BMP blocks and for supplementary code points.
+     * The list is terminated with list[listLength-1]=0x110000.
+     */
+    const int32_t *list;
+    int32_t listLength;
+};
+
+inline UBool BMPSet::containsSlow(UChar32 c, int32_t lo, int32_t hi) const {
+    return (UBool)(findCodePoint(c, lo, hi) & 1);
+}
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/brkeng.cpp b/source/common/brkeng.cpp
new file mode 100644
index 0000000..6d1fa36
--- /dev/null
+++ b/source/common/brkeng.cpp
@@ -0,0 +1,290 @@
+/**
+ ************************************************************************************
+ * Copyright (C) 2006-2009, International Business Machines Corporation and others. *
+ * All Rights Reserved.                                                             *
+ ************************************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "brkeng.h"
+#include "dictbe.h"
+#include "triedict.h"
+#include "unicode/uchar.h"
+#include "unicode/uniset.h"
+#include "unicode/chariter.h"
+#include "unicode/ures.h"
+#include "unicode/udata.h"
+#include "unicode/putil.h"
+#include "unicode/ustring.h"
+#include "unicode/uscript.h"
+#include "uvector.h"
+#include "umutex.h"
+#include "uresimp.h"
+#include "ubrkimpl.h"
+
+U_NAMESPACE_BEGIN
+
+/*
+ ******************************************************************
+ */
+
+LanguageBreakEngine::LanguageBreakEngine() {
+}
+
+LanguageBreakEngine::~LanguageBreakEngine() {
+}
+
+/*
+ ******************************************************************
+ */
+
+LanguageBreakFactory::LanguageBreakFactory() {
+}
+
+LanguageBreakFactory::~LanguageBreakFactory() {
+}
+
+/*
+ ******************************************************************
+ */
+
+UnhandledEngine::UnhandledEngine(UErrorCode &/*status*/) {
+    for (int32_t i = 0; i < (int32_t)(sizeof(fHandled)/sizeof(fHandled[0])); ++i) {
+        fHandled[i] = 0;
+    }
+}
+
+UnhandledEngine::~UnhandledEngine() {
+    for (int32_t i = 0; i < (int32_t)(sizeof(fHandled)/sizeof(fHandled[0])); ++i) {
+        if (fHandled[i] != 0) {
+            delete fHandled[i];
+        }
+    }
+}
+
+UBool
+UnhandledEngine::handles(UChar32 c, int32_t breakType) const {
+    return (breakType >= 0 && breakType < (int32_t)(sizeof(fHandled)/sizeof(fHandled[0]))
+        && fHandled[breakType] != 0 && fHandled[breakType]->contains(c));
+}
+
+int32_t
+UnhandledEngine::findBreaks( UText *text,
+                                 int32_t startPos,
+                                 int32_t endPos,
+                                 UBool reverse,
+                                 int32_t breakType,
+                                 UStack &/*foundBreaks*/ ) const {
+    if (breakType >= 0 && breakType < (int32_t)(sizeof(fHandled)/sizeof(fHandled[0]))) {
+        UChar32 c = utext_current32(text); 
+        if (reverse) {
+            while((int32_t)utext_getNativeIndex(text) > startPos && fHandled[breakType]->contains(c)) {
+                c = utext_previous32(text);
+            }
+        }
+        else {
+            while((int32_t)utext_getNativeIndex(text) < endPos && fHandled[breakType]->contains(c)) {
+                utext_next32(text);            // TODO:  recast loop to work with post-increment operations.
+                c = utext_current32(text);
+            }
+        }
+    }
+    return 0;
+}
+
+void
+UnhandledEngine::handleCharacter(UChar32 c, int32_t breakType) {
+    if (breakType >= 0 && breakType < (int32_t)(sizeof(fHandled)/sizeof(fHandled[0]))) {
+        if (fHandled[breakType] == 0) {
+            fHandled[breakType] = new UnicodeSet();
+            if (fHandled[breakType] == 0) {
+                return;
+            }
+        }
+        if (!fHandled[breakType]->contains(c)) {
+            UErrorCode status = U_ZERO_ERROR;
+            // Apply the entire script of the character.
+            int32_t script = u_getIntPropertyValue(c, UCHAR_SCRIPT);
+            fHandled[breakType]->applyIntPropertyValue(UCHAR_SCRIPT, script, status);
+        }
+    }
+}
+
+/*
+ ******************************************************************
+ */
+
+ICULanguageBreakFactory::ICULanguageBreakFactory(UErrorCode &/*status*/) {
+    fEngines = 0;
+}
+
+ICULanguageBreakFactory::~ICULanguageBreakFactory() {
+    if (fEngines != 0) {
+        delete fEngines;
+    }
+}
+
+U_NAMESPACE_END
+U_CDECL_BEGIN
+static void U_CALLCONV _deleteEngine(void *obj) {
+    delete (const U_NAMESPACE_QUALIFIER LanguageBreakEngine *) obj;
+}
+U_CDECL_END
+U_NAMESPACE_BEGIN
+
+const LanguageBreakEngine *
+ICULanguageBreakFactory::getEngineFor(UChar32 c, int32_t breakType) {
+    UBool       needsInit;
+    int32_t     i;
+    const LanguageBreakEngine *lbe = NULL;
+    UErrorCode  status = U_ZERO_ERROR;
+
+    // TODO: The global mutex should not be used.
+    // The global mutex should only be used for short periods.
+    // A ICULanguageBreakFactory specific mutex should be used.
+    umtx_lock(NULL);
+    needsInit = (UBool)(fEngines == NULL);
+    if (!needsInit) {
+        i = fEngines->size();
+        while (--i >= 0) {
+            lbe = (const LanguageBreakEngine *)(fEngines->elementAt(i));
+            if (lbe != NULL && lbe->handles(c, breakType)) {
+                break;
+            }
+            lbe = NULL;
+        }
+    }
+    umtx_unlock(NULL);
+    
+    if (lbe != NULL) {
+        return lbe;
+    }
+    
+    if (needsInit) {
+        UStack  *engines = new UStack(_deleteEngine, NULL, status);
+        if (U_SUCCESS(status) && engines == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+        }
+        else if (U_FAILURE(status)) {
+            delete engines;
+            engines = NULL;
+        }
+        else {
+            umtx_lock(NULL);
+            if (fEngines == NULL) {
+                fEngines = engines;
+                engines = NULL;
+            }
+            umtx_unlock(NULL);
+            delete engines;
+        }
+    }
+    
+    if (fEngines == NULL) {
+        return NULL;
+    }
+
+    // We didn't find an engine the first time through, or there was no
+    // stack. Create an engine.
+    const LanguageBreakEngine *newlbe = loadEngineFor(c, breakType);
+    
+    // Now get the lock, and see if someone else has created it in the
+    // meantime
+    umtx_lock(NULL);
+    i = fEngines->size();
+    while (--i >= 0) {
+        lbe = (const LanguageBreakEngine *)(fEngines->elementAt(i));
+        if (lbe != NULL && lbe->handles(c, breakType)) {
+            break;
+        }
+        lbe = NULL;
+    }
+    if (lbe == NULL && newlbe != NULL) {
+        fEngines->push((void *)newlbe, status);
+        lbe = newlbe;
+        newlbe = NULL;
+    }
+    umtx_unlock(NULL);
+    
+    delete newlbe;
+
+    return lbe;
+}
+
+const LanguageBreakEngine *
+ICULanguageBreakFactory::loadEngineFor(UChar32 c, int32_t breakType) {
+    UErrorCode status = U_ZERO_ERROR;
+    UScriptCode code = uscript_getScript(c, &status);
+    if (U_SUCCESS(status)) {
+        const CompactTrieDictionary *dict = loadDictionaryFor(code, breakType);
+        if (dict != NULL) {
+            const LanguageBreakEngine *engine = NULL;
+            switch(code) {
+            case USCRIPT_THAI:
+                engine = new ThaiBreakEngine(dict, status);
+                break;
+            default:
+                break;
+            }
+            if (engine == NULL) {
+                delete dict;
+            }
+            else if (U_FAILURE(status)) {
+                delete engine;
+                engine = NULL;
+            }
+            return engine;
+        }
+    }
+    return NULL;
+}
+
+const CompactTrieDictionary *
+ICULanguageBreakFactory::loadDictionaryFor(UScriptCode script, int32_t /*breakType*/) {
+    UErrorCode status = U_ZERO_ERROR;
+    // Open root from brkitr tree.
+    char dictnbuff[256];
+    char ext[4]={'\0'};
+
+    UResourceBundle *b = ures_open(U_ICUDATA_BRKITR, "", &status);
+    b = ures_getByKeyWithFallback(b, "dictionaries", b, &status);
+    b = ures_getByKeyWithFallback(b, uscript_getShortName(script), b, &status);
+    int32_t dictnlength = 0;
+    const UChar *dictfname = ures_getString(b, &dictnlength, &status);
+    if (U_SUCCESS(status) && (size_t)dictnlength >= sizeof(dictnbuff)) {
+        dictnlength = 0;
+        status = U_BUFFER_OVERFLOW_ERROR;
+    }
+    if (U_SUCCESS(status) && dictfname) {
+        UChar* extStart=u_strchr(dictfname, 0x002e);
+        int len = 0;
+        if(extStart!=NULL){
+            len = (int)(extStart-dictfname);
+            u_UCharsToChars(extStart+1, ext, sizeof(ext)); // nul terminates the buff
+            u_UCharsToChars(dictfname, dictnbuff, len);
+        }
+        dictnbuff[len]=0; // nul terminate
+    }
+    ures_close(b);
+    UDataMemory *file = udata_open(U_ICUDATA_BRKITR, ext, dictnbuff, &status);
+    if (U_SUCCESS(status)) {
+        const CompactTrieDictionary *dict = new CompactTrieDictionary(
+            file, status);
+        if (U_SUCCESS(status) && dict == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+        }
+        if (U_FAILURE(status)) {
+            delete dict;
+            dict = NULL;
+        }
+        return dict;
+    }
+    return NULL;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
diff --git a/source/common/brkeng.h b/source/common/brkeng.h
new file mode 100644
index 0000000..618b2ae
--- /dev/null
+++ b/source/common/brkeng.h
@@ -0,0 +1,292 @@
+/**
+ ************************************************************************************
+ * Copyright (C) 2006-2007, International Business Machines Corporation and others. *
+ * All Rights Reserved.                                                             *
+ ************************************************************************************
+ */
+
+#ifndef BRKENG_H
+#define BRKENG_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/utext.h"
+#include "unicode/uscript.h"
+
+U_NAMESPACE_BEGIN
+
+class UnicodeSet;
+class UStack;
+class CompactTrieDictionary;
+
+/*******************************************************************
+ * LanguageBreakEngine
+ */
+
+/**
+ * <p>LanguageBreakEngines implement language-specific knowledge for
+ * finding text boundaries within a run of characters belonging to a
+ * specific set. The boundaries will be of a specific kind, e.g. word,
+ * line, etc.</p>
+ *
+ * <p>LanguageBreakEngines should normally be implemented so as to
+ * be shared between threads without locking.</p>
+ */
+class LanguageBreakEngine : public UMemory {
+ public:
+
+  /**
+   * <p>Default constructor.</p>
+   *
+   */
+  LanguageBreakEngine();
+
+  /**
+   * <p>Virtual destructor.</p>
+   */
+  virtual ~LanguageBreakEngine();
+
+ /**
+  * <p>Indicate whether this engine handles a particular character for
+  * a particular kind of break.</p>
+  *
+  * @param c A character which begins a run that the engine might handle
+  * @param breakType The type of text break which the caller wants to determine
+  * @return TRUE if this engine handles the particular character and break
+  * type.
+  */
+  virtual UBool handles(UChar32 c, int32_t breakType) const = 0;
+
+ /**
+  * <p>Find any breaks within a run in the supplied text.</p>
+  *
+  * @param text A UText representing the text. The
+  * iterator is left at the end of the run of characters which the engine
+  * is capable of handling.
+  * @param startPos The start of the run within the supplied text.
+  * @param endPos The end of the run within the supplied text.
+  * @param reverse Whether the caller is looking for breaks in a reverse
+  * direction.
+  * @param breakType The type of break desired, or -1.
+  * @param foundBreaks An allocated C array of the breaks found, if any
+  * @return The number of breaks found.
+  */
+  virtual int32_t findBreaks( UText *text,
+                              int32_t startPos,
+                              int32_t endPos,
+                              UBool reverse,
+                              int32_t breakType,
+                              UStack &foundBreaks ) const = 0;
+
+};
+
+/*******************************************************************
+ * LanguageBreakFactory
+ */
+
+/**
+ * <p>LanguageBreakFactorys find and return a LanguageBreakEngine
+ * that can determine breaks for characters in a specific set, if
+ * such an object can be found.</p>
+ *
+ * <p>If a LanguageBreakFactory is to be shared between threads,
+ * appropriate synchronization must be used; there is none internal
+ * to the factory.</p>
+ *
+ * <p>A LanguageBreakEngine returned by a LanguageBreakFactory can
+ * normally be shared between threads without synchronization, unless
+ * the specific subclass of LanguageBreakFactory indicates otherwise.</p>
+ *
+ * <p>A LanguageBreakFactory is responsible for deleting any LanguageBreakEngine
+ * it returns when it itself is deleted, unless the specific subclass of
+ * LanguageBreakFactory indicates otherwise. Naturally, the factory should
+ * not be deleted until the LanguageBreakEngines it has returned are no
+ * longer needed.</p>
+ */
+class LanguageBreakFactory : public UMemory {
+ public:
+
+  /**
+   * <p>Default constructor.</p>
+   *
+   */
+  LanguageBreakFactory();
+
+  /**
+   * <p>Virtual destructor.</p>
+   */
+  virtual ~LanguageBreakFactory();
+
+ /**
+  * <p>Find and return a LanguageBreakEngine that can find the desired
+  * kind of break for the set of characters to which the supplied
+  * character belongs. It is up to the set of available engines to
+  * determine what the sets of characters are.</p>
+  *
+  * @param c A character that begins a run for which a LanguageBreakEngine is
+  * sought.
+  * @param breakType The kind of text break for which a LanguageBreakEngine is
+  * sought.
+  * @return A LanguageBreakEngine with the desired characteristics, or 0.
+  */
+  virtual const LanguageBreakEngine *getEngineFor(UChar32 c, int32_t breakType) = 0;
+
+};
+
+/*******************************************************************
+ * UnhandledEngine
+ */
+
+/**
+ * <p>UnhandledEngine is a special subclass of LanguageBreakEngine that
+ * handles characters that no other LanguageBreakEngine is available to
+ * handle. It is told the character and the type of break; at its
+ * discretion it may handle more than the specified character (e.g.,
+ * the entire script to which that character belongs.</p>
+ *
+ * <p>UnhandledEngines may not be shared between threads without
+ * external synchronization.</p>
+ */
+
+class UnhandledEngine : public LanguageBreakEngine {
+ private:
+
+    /**
+     * The sets of characters handled, for each break type
+     * @internal
+     */
+
+  UnicodeSet    *fHandled[4];
+
+ public:
+
+  /**
+   * <p>Default constructor.</p>
+   *
+   */
+  UnhandledEngine(UErrorCode &status);
+
+  /**
+   * <p>Virtual destructor.</p>
+   */
+  virtual ~UnhandledEngine();
+
+ /**
+  * <p>Indicate whether this engine handles a particular character for
+  * a particular kind of break.</p>
+  *
+  * @param c A character which begins a run that the engine might handle
+  * @param breakType The type of text break which the caller wants to determine
+  * @return TRUE if this engine handles the particular character and break
+  * type.
+  */
+  virtual UBool handles(UChar32 c, int32_t breakType) const;
+
+ /**
+  * <p>Find any breaks within a run in the supplied text.</p>
+  *
+  * @param text A UText representing the text (TODO: UText). The
+  * iterator is left at the end of the run of characters which the engine
+  * is capable of handling.
+  * @param startPos The start of the run within the supplied text.
+  * @param endPos The end of the run within the supplied text.
+  * @param reverse Whether the caller is looking for breaks in a reverse
+  * direction.
+  * @param breakType The type of break desired, or -1.
+  * @param foundBreaks An allocated C array of the breaks found, if any
+  * @return The number of breaks found.
+  */
+  virtual int32_t findBreaks( UText *text,
+                              int32_t startPos,
+                              int32_t endPos,
+                              UBool reverse,
+                              int32_t breakType,
+                              UStack &foundBreaks ) const;
+
+ /**
+  * <p>Tell the engine to handle a particular character and break type.</p>
+  *
+  * @param c A character which the engine should handle
+  * @param breakType The type of text break for which the engine should handle c
+  */
+  virtual void handleCharacter(UChar32 c, int32_t breakType);
+
+};
+
+/*******************************************************************
+ * ICULanguageBreakFactory
+ */
+
+/**
+ * <p>ICULanguageBreakFactory is the default LanguageBreakFactory for
+ * ICU. It creates dictionary-based LanguageBreakEngines from dictionary
+ * data in the ICU data file.</p>
+ */
+class ICULanguageBreakFactory : public LanguageBreakFactory {
+ private:
+
+    /**
+     * The stack of break engines created by this factory
+     * @internal
+     */
+
+  UStack    *fEngines;
+
+ public:
+
+  /**
+   * <p>Standard constructor.</p>
+   *
+   */
+  ICULanguageBreakFactory(UErrorCode &status);
+
+  /**
+   * <p>Virtual destructor.</p>
+   */
+  virtual ~ICULanguageBreakFactory();
+
+ /**
+  * <p>Find and return a LanguageBreakEngine that can find the desired
+  * kind of break for the set of characters to which the supplied
+  * character belongs. It is up to the set of available engines to
+  * determine what the sets of characters are.</p>
+  *
+  * @param c A character that begins a run for which a LanguageBreakEngine is
+  * sought.
+  * @param breakType The kind of text break for which a LanguageBreakEngine is
+  * sought.
+  * @return A LanguageBreakEngine with the desired characteristics, or 0.
+  */
+  virtual const LanguageBreakEngine *getEngineFor(UChar32 c, int32_t breakType);
+
+ protected:
+
+ /**
+  * <p>Create a LanguageBreakEngine for the set of characters to which
+  * the supplied character belongs, for the specified break type.</p>
+  *
+  * @param c A character that begins a run for which a LanguageBreakEngine is
+  * sought.
+  * @param breakType The kind of text break for which a LanguageBreakEngine is
+  * sought.
+  * @return A LanguageBreakEngine with the desired characteristics, or 0.
+  */
+  virtual const LanguageBreakEngine *loadEngineFor(UChar32 c, int32_t breakType);
+
+ /**
+  * <p>Create a CompactTrieDictionary for the specified script and break type.</p>
+  *
+  * @param script An ISO 15924 script code that identifies the dictionary to be
+  * created.
+  * @param breakType The kind of text break for which a dictionary is
+  * sought.
+  * @return A CompactTrieDictionary with the desired characteristics, or 0.
+  */
+  virtual const CompactTrieDictionary *loadDictionaryFor(UScriptCode script, int32_t breakType);
+
+};
+
+U_NAMESPACE_END
+
+    /* BRKENG_H */
+#endif
diff --git a/source/common/brkiter.cpp b/source/common/brkiter.cpp
new file mode 100644
index 0000000..26f7b6a
--- /dev/null
+++ b/source/common/brkiter.cpp
@@ -0,0 +1,443 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2010, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File TXTBDRY.CPP
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   02/18/97    aliu        Converted from OpenClass.  Added DONE.
+*   01/13/2000  helena      Added UErrorCode parameter to createXXXInstance methods.
+*****************************************************************************************
+*/
+
+// *****************************************************************************
+// This file was generated from the java source file BreakIterator.java
+// *****************************************************************************
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/rbbi.h"
+#include "unicode/brkiter.h"
+#include "unicode/udata.h"
+#include "unicode/ures.h"
+#include "unicode/ustring.h"
+#include "ucln_cmn.h"
+#include "cstring.h"
+#include "umutex.h"
+#include "servloc.h"
+#include "locbased.h"
+#include "uresimp.h"
+#include "uassert.h"
+#include "ubrkimpl.h"
+
+// *****************************************************************************
+// class BreakIterator
+// This class implements methods for finding the location of boundaries in text.
+// Instances of BreakIterator maintain a current position and scan over text
+// returning the index of characters where boundaries occur.
+// *****************************************************************************
+
+U_NAMESPACE_BEGIN
+
+// -------------------------------------
+
+BreakIterator*
+BreakIterator::buildInstance(const Locale& loc, const char *type, int32_t kind, UErrorCode &status)
+{
+    char fnbuff[256];
+    char ext[4]={'\0'};
+    char actualLocale[ULOC_FULLNAME_CAPACITY];
+    int32_t size;
+    const UChar* brkfname = NULL;
+    UResourceBundle brkRulesStack;
+    UResourceBundle brkNameStack;
+    UResourceBundle *brkRules = &brkRulesStack;
+    UResourceBundle *brkName  = &brkNameStack;
+    RuleBasedBreakIterator *result = NULL;
+
+    if (U_FAILURE(status))
+        return NULL;
+
+    ures_initStackObject(brkRules);
+    ures_initStackObject(brkName);
+
+    // Get the locale
+    UResourceBundle *b = ures_open(U_ICUDATA_BRKITR, loc.getName(), &status);
+    /* this is a hack for now. Should be fixed when the data is fetched from
+        brk_index.txt */
+    if(status==U_USING_DEFAULT_WARNING){
+        status=U_ZERO_ERROR;
+        ures_openFillIn(b, U_ICUDATA_BRKITR, "", &status);
+    }
+
+    // Get the "boundaries" array.
+    if (U_SUCCESS(status)) {
+        brkRules = ures_getByKeyWithFallback(b, "boundaries", brkRules, &status);
+        // Get the string object naming the rules file
+        brkName = ures_getByKeyWithFallback(brkRules, type, brkName, &status);
+        // Get the actual string
+        brkfname = ures_getString(brkName, &size, &status);
+        U_ASSERT((size_t)size<sizeof(fnbuff));
+        if ((size_t)size>=sizeof(fnbuff)) {
+            size=0;
+            if (U_SUCCESS(status)) {
+                status = U_BUFFER_OVERFLOW_ERROR;
+            }
+        }
+
+        // Use the string if we found it
+        if (U_SUCCESS(status) && brkfname) {
+            uprv_strncpy(actualLocale,
+                ures_getLocale(brkName, &status),
+                sizeof(actualLocale)/sizeof(actualLocale[0]));
+
+            UChar* extStart=u_strchr(brkfname, 0x002e);
+            int len = 0;
+            if(extStart!=NULL){
+                len = (int)(extStart-brkfname);
+                u_UCharsToChars(extStart+1, ext, sizeof(ext)); // nul terminates the buff
+                u_UCharsToChars(brkfname, fnbuff, len);
+            }
+            fnbuff[len]=0; // nul terminate
+        }
+    }
+
+    ures_close(brkRules);
+    ures_close(brkName);
+
+    UDataMemory* file = udata_open(U_ICUDATA_BRKITR, ext, fnbuff, &status);
+    if (U_FAILURE(status)) {
+        ures_close(b);
+        return NULL;
+    }
+
+    // Create a RuleBasedBreakIterator
+    result = new RuleBasedBreakIterator(file, status);
+
+    // If there is a result, set the valid locale and actual locale, and the kind
+    if (U_SUCCESS(status) && result != NULL) {
+        U_LOCALE_BASED(locBased, *(BreakIterator*)result);
+        locBased.setLocaleIDs(ures_getLocaleByType(b, ULOC_VALID_LOCALE, &status), actualLocale);
+        result->setBreakType(kind);
+    }
+
+    ures_close(b);
+
+    if (U_FAILURE(status) && result != NULL) {  // Sometimes redundant check, but simple
+        delete result;
+        return NULL;
+    }
+
+    if (result == NULL) {
+        udata_close(file);
+        if (U_SUCCESS(status)) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+        }
+    }
+
+    return result;
+}
+
+// Creates a break iterator for word breaks.
+BreakIterator* U_EXPORT2
+BreakIterator::createWordInstance(const Locale& key, UErrorCode& status)
+{
+    return createInstance(key, UBRK_WORD, status);
+}
+
+// -------------------------------------
+
+// Creates a break iterator  for line breaks.
+BreakIterator* U_EXPORT2
+BreakIterator::createLineInstance(const Locale& key, UErrorCode& status)
+{
+    return createInstance(key, UBRK_LINE, status);
+}
+
+// -------------------------------------
+
+// Creates a break iterator  for character breaks.
+BreakIterator* U_EXPORT2
+BreakIterator::createCharacterInstance(const Locale& key, UErrorCode& status)
+{
+    return createInstance(key, UBRK_CHARACTER, status);
+}
+
+// -------------------------------------
+
+// Creates a break iterator  for sentence breaks.
+BreakIterator* U_EXPORT2
+BreakIterator::createSentenceInstance(const Locale& key, UErrorCode& status)
+{
+    return createInstance(key, UBRK_SENTENCE, status);
+}
+
+// -------------------------------------
+
+// Creates a break iterator for title casing breaks.
+BreakIterator* U_EXPORT2
+BreakIterator::createTitleInstance(const Locale& key, UErrorCode& status)
+{
+    return createInstance(key, UBRK_TITLE, status);
+}
+
+// -------------------------------------
+
+// Gets all the available locales that has localized text boundary data.
+const Locale* U_EXPORT2
+BreakIterator::getAvailableLocales(int32_t& count)
+{
+    return Locale::getAvailableLocales(count);
+}
+
+// ------------------------------------------
+//
+// Default constructor and destructor
+//
+//-------------------------------------------
+
+BreakIterator::BreakIterator()
+{
+    fBufferClone = FALSE;
+    *validLocale = *actualLocale = 0;
+}
+
+BreakIterator::~BreakIterator()
+{
+}
+
+// ------------------------------------------
+//
+// Registration
+//
+//-------------------------------------------
+#if !UCONFIG_NO_SERVICE
+
+// -------------------------------------
+
+class ICUBreakIteratorFactory : public ICUResourceBundleFactory {
+protected:
+    virtual UObject* handleCreate(const Locale& loc, int32_t kind, const ICUService* /*service*/, UErrorCode& status) const {
+        return BreakIterator::makeInstance(loc, kind, status);
+    }
+};
+
+// -------------------------------------
+
+class ICUBreakIteratorService : public ICULocaleService {
+public:
+    ICUBreakIteratorService()
+        : ICULocaleService(UNICODE_STRING("Break Iterator", 14))
+    {
+        UErrorCode status = U_ZERO_ERROR;
+        registerFactory(new ICUBreakIteratorFactory(), status);
+    }
+
+    virtual UObject* cloneInstance(UObject* instance) const {
+        return ((BreakIterator*)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 BreakIterator::makeInstance(loc, kind, status);
+    }
+
+    virtual UBool isDefault() const {
+        return countFactories() == 1;
+    }
+};
+
+// -------------------------------------
+
+U_NAMESPACE_END
+
+// defined in ucln_cmn.h
+
+static U_NAMESPACE_QUALIFIER ICULocaleService* gService = NULL;
+
+/**
+ * Release all static memory held by breakiterator.
+ */
+U_CDECL_BEGIN
+static UBool U_CALLCONV breakiterator_cleanup(void) {
+#if !UCONFIG_NO_SERVICE
+    if (gService) {
+        delete gService;
+        gService = NULL;
+    }
+#endif
+    return TRUE;
+}
+U_CDECL_END
+U_NAMESPACE_BEGIN
+
+static ICULocaleService*
+getService(void)
+{
+    UBool needsInit;
+    UMTX_CHECK(NULL, (UBool)(gService == NULL), needsInit);
+
+    if (needsInit) {
+        ICULocaleService  *tService = new ICUBreakIteratorService();
+        umtx_lock(NULL);
+        if (gService == NULL) {
+            gService = tService;
+            tService = NULL;
+            ucln_common_registerCleanup(UCLN_COMMON_BREAKITERATOR, breakiterator_cleanup);
+        }
+        umtx_unlock(NULL);
+        delete tService;
+    }
+    return gService;
+}
+
+// -------------------------------------
+
+static inline UBool
+hasService(void)
+{
+    UBool retVal;
+    UMTX_CHECK(NULL, gService != NULL, retVal);
+    return retVal;
+}
+
+// -------------------------------------
+
+URegistryKey U_EXPORT2
+BreakIterator::registerInstance(BreakIterator* toAdopt, const Locale& locale, UBreakIteratorType kind, UErrorCode& status)
+{
+    ICULocaleService *service = getService();
+    if (service == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    return service->registerInstance(toAdopt, locale, kind, status);
+}
+
+// -------------------------------------
+
+UBool U_EXPORT2
+BreakIterator::unregister(URegistryKey key, UErrorCode& status)
+{
+    if (U_SUCCESS(status)) {
+        if (hasService()) {
+            return gService->unregister(key, status);
+        }
+        status = U_MEMORY_ALLOCATION_ERROR;
+    }
+    return FALSE;
+}
+
+// -------------------------------------
+
+StringEnumeration* U_EXPORT2
+BreakIterator::getAvailableLocales(void)
+{
+    ICULocaleService *service = getService();
+    if (service == NULL) {
+        return NULL;
+    }
+    return service->getAvailableLocales();
+}
+#endif /* UCONFIG_NO_SERVICE */
+
+// -------------------------------------
+
+BreakIterator*
+BreakIterator::createInstance(const Locale& loc, int32_t kind, UErrorCode& status)
+{
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+
+#if !UCONFIG_NO_SERVICE
+    if (hasService()) {
+        Locale actualLoc("");
+        BreakIterator *result = (BreakIterator*)gService->get(loc, kind, &actualLoc, status);
+        // TODO: The way the service code works in ICU 2.8 is that if
+        // there is a real registered break iterator, the actualLoc
+        // will be populated, but if the handleDefault path is taken
+        // (because nothing is registered that can handle the
+        // requested locale) then the actualLoc comes back empty.  In
+        // that case, the returned object already has its actual/valid
+        // locale data populated (by makeInstance, which is what
+        // handleDefault calls), so we don't touch it.  YES, A COMMENT
+        // THIS LONG is a sign of bad code -- so the action item is to
+        // revisit this in ICU 3.0 and clean it up/fix it/remove it.
+        if (U_SUCCESS(status) && (result != NULL) && *actualLoc.getName() != 0) {
+            U_LOCALE_BASED(locBased, *result);
+            locBased.setLocaleIDs(actualLoc.getName(), actualLoc.getName());
+        }
+        return result;
+    }
+    else
+#endif
+    {
+        return makeInstance(loc, kind, status);
+    }
+}
+
+// -------------------------------------
+
+BreakIterator*
+BreakIterator::makeInstance(const Locale& loc, int32_t kind, UErrorCode& status)
+{
+
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+
+    BreakIterator *result = NULL;
+    switch (kind) {
+    case UBRK_CHARACTER:
+        result = BreakIterator::buildInstance(loc, "grapheme", kind, status);
+        break;
+    case UBRK_WORD:
+        result = BreakIterator::buildInstance(loc, "word", kind, status);
+        break;
+    case UBRK_LINE:
+        result = BreakIterator::buildInstance(loc, "line", kind, status);
+        break;
+    case UBRK_SENTENCE:
+        result = BreakIterator::buildInstance(loc, "sentence", kind, status);
+        break;
+    case UBRK_TITLE:
+        result = BreakIterator::buildInstance(loc, "title", kind, status);
+        break;
+    default:
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+    }
+
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+
+    return result;
+}
+
+Locale
+BreakIterator::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
+    U_LOCALE_BASED(locBased, *this);
+    return locBased.getLocale(type, status);
+}
+
+const char *
+BreakIterator::getLocaleID(ULocDataLocaleType type, UErrorCode& status) const {
+    U_LOCALE_BASED(locBased, *this);
+    return locBased.getLocaleID(type, status);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
+
+//eof
diff --git a/source/common/bytestream.cpp b/source/common/bytestream.cpp
new file mode 100644
index 0000000..e2142ce
--- /dev/null
+++ b/source/common/bytestream.cpp
@@ -0,0 +1,73 @@
+// Copyright (C) 2009-2010, International Business Machines
+// Corporation and others. All Rights Reserved.
+//
+// Copyright 2007 Google Inc. All Rights Reserved.
+// Author: sanjay@google.com (Sanjay Ghemawat)
+
+#include "unicode/utypes.h"
+#include "unicode/bytestream.h"
+#include "cmemory.h"
+
+U_NAMESPACE_BEGIN
+
+char* ByteSink::GetAppendBuffer(int32_t min_capacity,
+                                int32_t /*desired_capacity_hint*/,
+                                char* scratch, int32_t scratch_capacity,
+                                int32_t* result_capacity) {
+  if (min_capacity < 1 || scratch_capacity < min_capacity) {
+    *result_capacity = 0;
+    return NULL;
+  }
+  *result_capacity = scratch_capacity;
+  return scratch;
+}
+
+void ByteSink::Flush() {}
+
+CheckedArrayByteSink::CheckedArrayByteSink(char* outbuf, int32_t capacity)
+    : outbuf_(outbuf), capacity_(capacity < 0 ? 0 : capacity),
+      size_(0), appended_(0), overflowed_(FALSE) {
+}
+
+CheckedArrayByteSink& CheckedArrayByteSink::Reset() {
+  size_ = appended_ = 0;
+  overflowed_ = FALSE;
+  return *this;
+}
+
+void CheckedArrayByteSink::Append(const char* bytes, int32_t n) {
+  if (n <= 0) {
+    return;
+  }
+  appended_ += n;
+  int32_t available = capacity_ - size_;
+  if (n > available) {
+    n = available;
+    overflowed_ = TRUE;
+  }
+  if (n > 0 && bytes != (outbuf_ + size_)) {
+    uprv_memcpy(outbuf_ + size_, bytes, n);
+  }
+  size_ += n;
+}
+
+char* CheckedArrayByteSink::GetAppendBuffer(int32_t min_capacity,
+                                            int32_t /*desired_capacity_hint*/,
+                                            char* scratch,
+                                            int32_t scratch_capacity,
+                                            int32_t* result_capacity) {
+  if (min_capacity < 1 || scratch_capacity < min_capacity) {
+    *result_capacity = 0;
+    return NULL;
+  }
+  int32_t available = capacity_ - size_;
+  if (available >= min_capacity) {
+    *result_capacity = available;
+    return outbuf_ + size_;
+  } else {
+    *result_capacity = scratch_capacity;
+    return scratch;
+  }
+}
+
+U_NAMESPACE_END
diff --git a/source/common/caniter.cpp b/source/common/caniter.cpp
new file mode 100644
index 0000000..e6b0e83
--- /dev/null
+++ b/source/common/caniter.cpp
@@ -0,0 +1,576 @@
+/*
+ *****************************************************************************
+ * Copyright (C) 1996-2010, International Business Machines Corporation and  *
+ * others. All Rights Reserved.                                              *
+ *****************************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/caniter.h"
+#include "unicode/normalizer2.h"
+#include "unicode/uchar.h"
+#include "unicode/uniset.h"
+#include "unicode/usetiter.h"
+#include "unicode/ustring.h"
+#include "cmemory.h"
+#include "hash.h"
+#include "normalizer2impl.h"
+
+/**
+ * This class allows one to iterate through all the strings that are canonically equivalent to a given
+ * string. For example, here are some sample results:
+Results for: {LATIN CAPITAL LETTER A WITH RING ABOVE}{LATIN SMALL LETTER D}{COMBINING DOT ABOVE}{COMBINING CEDILLA}
+1: \u0041\u030A\u0064\u0307\u0327
+ = {LATIN CAPITAL LETTER A}{COMBINING RING ABOVE}{LATIN SMALL LETTER D}{COMBINING DOT ABOVE}{COMBINING CEDILLA}
+2: \u0041\u030A\u0064\u0327\u0307
+ = {LATIN CAPITAL LETTER A}{COMBINING RING ABOVE}{LATIN SMALL LETTER D}{COMBINING CEDILLA}{COMBINING DOT ABOVE}
+3: \u0041\u030A\u1E0B\u0327
+ = {LATIN CAPITAL LETTER A}{COMBINING RING ABOVE}{LATIN SMALL LETTER D WITH DOT ABOVE}{COMBINING CEDILLA}
+4: \u0041\u030A\u1E11\u0307
+ = {LATIN CAPITAL LETTER A}{COMBINING RING ABOVE}{LATIN SMALL LETTER D WITH CEDILLA}{COMBINING DOT ABOVE}
+5: \u00C5\u0064\u0307\u0327
+ = {LATIN CAPITAL LETTER A WITH RING ABOVE}{LATIN SMALL LETTER D}{COMBINING DOT ABOVE}{COMBINING CEDILLA}
+6: \u00C5\u0064\u0327\u0307
+ = {LATIN CAPITAL LETTER A WITH RING ABOVE}{LATIN SMALL LETTER D}{COMBINING CEDILLA}{COMBINING DOT ABOVE}
+7: \u00C5\u1E0B\u0327
+ = {LATIN CAPITAL LETTER A WITH RING ABOVE}{LATIN SMALL LETTER D WITH DOT ABOVE}{COMBINING CEDILLA}
+8: \u00C5\u1E11\u0307
+ = {LATIN CAPITAL LETTER A WITH RING ABOVE}{LATIN SMALL LETTER D WITH CEDILLA}{COMBINING DOT ABOVE}
+9: \u212B\u0064\u0307\u0327
+ = {ANGSTROM SIGN}{LATIN SMALL LETTER D}{COMBINING DOT ABOVE}{COMBINING CEDILLA}
+10: \u212B\u0064\u0327\u0307
+ = {ANGSTROM SIGN}{LATIN SMALL LETTER D}{COMBINING CEDILLA}{COMBINING DOT ABOVE}
+11: \u212B\u1E0B\u0327
+ = {ANGSTROM SIGN}{LATIN SMALL LETTER D WITH DOT ABOVE}{COMBINING CEDILLA}
+12: \u212B\u1E11\u0307
+ = {ANGSTROM SIGN}{LATIN SMALL LETTER D WITH CEDILLA}{COMBINING DOT ABOVE}
+ *<br>Note: the code is intended for use with small strings, and is not suitable for larger ones,
+ * since it has not been optimized for that situation.
+ *@author M. Davis
+ *@draft
+ */
+
+// public
+
+U_NAMESPACE_BEGIN
+
+// TODO: add boilerplate methods.
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CanonicalIterator)
+
+/**
+ *@param source string to get results for
+ */
+CanonicalIterator::CanonicalIterator(const UnicodeString &sourceStr, UErrorCode &status) :
+    pieces(NULL),
+    pieces_length(0),
+    pieces_lengths(NULL),
+    current(NULL),
+    current_length(0),
+    nfd(*Normalizer2Factory::getNFDInstance(status)),
+    nfcImpl(*Normalizer2Factory::getNFCImpl(status))
+{
+    if(U_SUCCESS(status) && nfcImpl.ensureCanonIterData(status)) {
+      setSource(sourceStr, status);
+    }
+}
+
+CanonicalIterator::~CanonicalIterator() {
+  cleanPieces();
+}
+
+void CanonicalIterator::cleanPieces() {
+    int32_t i = 0;
+    if(pieces != NULL) {
+        for(i = 0; i < pieces_length; i++) {
+            if(pieces[i] != NULL) {
+                delete[] pieces[i];
+            }
+        }
+        uprv_free(pieces);
+        pieces = NULL;
+        pieces_length = 0;
+    }
+    if(pieces_lengths != NULL) {
+        uprv_free(pieces_lengths);
+        pieces_lengths = NULL;
+    }
+    if(current != NULL) {
+        uprv_free(current);
+        current = NULL;
+        current_length = 0;
+    }
+}
+
+/**
+ *@return gets the source: NOTE: it is the NFD form of source
+ */
+UnicodeString CanonicalIterator::getSource() {
+  return source;
+}
+
+/**
+ * Resets the iterator so that one can start again from the beginning.
+ */
+void CanonicalIterator::reset() {
+    done = FALSE;
+    for (int i = 0; i < current_length; ++i) {
+        current[i] = 0;
+    }
+}
+
+/**
+ *@return the next string that is canonically equivalent. The value null is returned when
+ * the iteration is done.
+ */
+UnicodeString CanonicalIterator::next() {
+    int32_t i = 0;
+
+    if (done) {
+      buffer.setToBogus();
+      return buffer;
+    }
+
+    // delete old contents
+    buffer.remove();
+
+    // construct return value
+
+    for (i = 0; i < pieces_length; ++i) {
+        buffer.append(pieces[i][current[i]]);
+    }
+    //String result = buffer.toString(); // not needed
+
+    // find next value for next time
+
+    for (i = current_length - 1; ; --i) {
+        if (i < 0) {
+            done = TRUE;
+            break;
+        }
+        current[i]++;
+        if (current[i] < pieces_lengths[i]) break; // got sequence
+        current[i] = 0;
+    }
+    return buffer;
+}
+
+/**
+ *@param set the source string to iterate against. This allows the same iterator to be used
+ * while changing the source string, saving object creation.
+ */
+void CanonicalIterator::setSource(const UnicodeString &newSource, UErrorCode &status) {
+    int32_t list_length = 0;
+    UChar32 cp = 0;
+    int32_t start = 0;
+    int32_t i = 0;
+    UnicodeString *list = NULL;
+
+    nfd.normalize(newSource, source, status);
+    if(U_FAILURE(status)) {
+      return;
+    }
+    done = FALSE;
+
+    cleanPieces();
+
+    // catch degenerate case
+    if (newSource.length() == 0) {
+        pieces = (UnicodeString **)uprv_malloc(sizeof(UnicodeString *));
+        pieces_lengths = (int32_t*)uprv_malloc(1 * sizeof(int32_t));
+        pieces_length = 1;
+        current = (int32_t*)uprv_malloc(1 * sizeof(int32_t));
+        current_length = 1;
+        if (pieces == NULL || pieces_lengths == NULL || current == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            goto CleanPartialInitialization;
+        }
+        current[0] = 0;
+        pieces[0] = new UnicodeString[1];
+        pieces_lengths[0] = 1;
+        if (pieces[0] == 0) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            goto CleanPartialInitialization;
+        }
+        return;
+    }
+
+
+    list = new UnicodeString[source.length()];
+    if (list == 0) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        goto CleanPartialInitialization;
+    }
+
+    // i should initialy be the number of code units at the 
+    // start of the string
+    i = UTF16_CHAR_LENGTH(source.char32At(0));
+    //int32_t i = 1;
+    // find the segments
+    // This code iterates through the source string and 
+    // extracts segments that end up on a codepoint that
+    // doesn't start any decompositions. (Analysis is done
+    // on the NFD form - see above).
+    for (; i < source.length(); i += UTF16_CHAR_LENGTH(cp)) {
+        cp = source.char32At(i);
+        if (nfcImpl.isCanonSegmentStarter(cp)) {
+            source.extract(start, i-start, list[list_length++]); // add up to i
+            start = i;
+        }
+    }
+    source.extract(start, i-start, list[list_length++]); // add last one
+
+
+    // allocate the arrays, and find the strings that are CE to each segment
+    pieces = (UnicodeString **)uprv_malloc(list_length * sizeof(UnicodeString *));
+    pieces_length = list_length;
+    pieces_lengths = (int32_t*)uprv_malloc(list_length * sizeof(int32_t));
+    current = (int32_t*)uprv_malloc(list_length * sizeof(int32_t));
+    current_length = list_length;
+    if (pieces == NULL || pieces_lengths == NULL || current == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        goto CleanPartialInitialization;
+    }
+
+    for (i = 0; i < current_length; i++) {
+        current[i] = 0;
+    }
+    // for each segment, get all the combinations that can produce 
+    // it after NFD normalization
+    for (i = 0; i < pieces_length; ++i) {
+        //if (PROGRESS) printf("SEGMENT\n");
+        pieces[i] = getEquivalents(list[i], pieces_lengths[i], status);
+    }
+
+    delete[] list;
+    return;
+// Common section to cleanup all local variables and reset object variables.
+CleanPartialInitialization:
+    if (list != NULL) {
+        delete[] list;
+    }
+    cleanPieces();
+}
+
+/**
+ * Dumb recursive implementation of permutation.
+ * TODO: optimize
+ * @param source the string to find permutations for
+ * @return the results in a set.
+ */
+void U_EXPORT2 CanonicalIterator::permute(UnicodeString &source, UBool skipZeros, Hashtable *result, UErrorCode &status) {
+    if(U_FAILURE(status)) {
+        return;
+    }
+    //if (PROGRESS) printf("Permute: %s\n", UToS(Tr(source)));
+    int32_t i = 0;
+
+    // optimization:
+    // if zero or one character, just return a set with it
+    // we check for length < 2 to keep from counting code points all the time
+    if (source.length() <= 2 && source.countChar32() <= 1) {
+        UnicodeString *toPut = new UnicodeString(source);
+        /* test for NULL */
+        if (toPut == 0) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+        result->put(source, toPut, status);
+        return;
+    }
+
+    // otherwise iterate through the string, and recursively permute all the other characters
+    UChar32 cp;
+    Hashtable subpermute(status);
+    if(U_FAILURE(status)) {
+        return;
+    }
+    subpermute.setValueDeleter(uhash_deleteUnicodeString);
+
+    for (i = 0; i < source.length(); i += UTF16_CHAR_LENGTH(cp)) {
+        cp = source.char32At(i);
+        const UHashElement *ne = NULL;
+        int32_t el = -1;
+        UnicodeString subPermuteString = source;
+
+        // optimization:
+        // if the character is canonical combining class zero,
+        // don't permute it
+        if (skipZeros && i != 0 && u_getCombiningClass(cp) == 0) {
+            //System.out.println("Skipping " + Utility.hex(UTF16.valueOf(source, i)));
+            continue;
+        }
+
+        subpermute.removeAll();
+
+        // see what the permutations of the characters before and after this one are
+        //Hashtable *subpermute = permute(source.substring(0,i) + source.substring(i + UTF16.getCharCount(cp)));
+        permute(subPermuteString.replace(i, UTF16_CHAR_LENGTH(cp), NULL, 0), skipZeros, &subpermute, status);
+        /* Test for buffer overflows */
+        if(U_FAILURE(status)) {
+            return;
+        }
+        // The upper replace is destructive. The question is do we have to make a copy, or we don't care about the contents 
+        // of source at this point.
+
+        // prefix this character to all of them
+        ne = subpermute.nextElement(el);
+        while (ne != NULL) {
+            UnicodeString *permRes = (UnicodeString *)(ne->value.pointer);
+            UnicodeString *chStr = new UnicodeString(cp);
+            //test for  NULL
+            if (chStr == NULL) {
+                status = U_MEMORY_ALLOCATION_ERROR;
+                return;
+            }
+            chStr->append(*permRes); //*((UnicodeString *)(ne->value.pointer));
+            //if (PROGRESS) printf("  Piece: %s\n", UToS(*chStr));
+            result->put(*chStr, chStr, status);
+            ne = subpermute.nextElement(el);
+        }
+    }
+    //return result;
+}
+
+// privates
+
+// we have a segment, in NFD. Find all the strings that are canonically equivalent to it.
+UnicodeString* CanonicalIterator::getEquivalents(const UnicodeString &segment, int32_t &result_len, UErrorCode &status) {
+    Hashtable result(status);
+    Hashtable permutations(status);
+    Hashtable basic(status);
+    if (U_FAILURE(status)) {
+        return 0;
+    }
+    result.setValueDeleter(uhash_deleteUnicodeString);
+    permutations.setValueDeleter(uhash_deleteUnicodeString);
+    basic.setValueDeleter(uhash_deleteUnicodeString);
+
+    UChar USeg[256];
+    int32_t segLen = segment.extract(USeg, 256, status);
+    getEquivalents2(&basic, USeg, segLen, status);
+
+    // now get all the permutations
+    // add only the ones that are canonically equivalent
+    // TODO: optimize by not permuting any class zero.
+
+    const UHashElement *ne = NULL;
+    int32_t el = -1;
+    //Iterator it = basic.iterator();
+    ne = basic.nextElement(el);
+    //while (it.hasNext())
+    while (ne != NULL) {
+        //String item = (String) it.next();
+        UnicodeString item = *((UnicodeString *)(ne->value.pointer));
+
+        permutations.removeAll();
+        permute(item, CANITER_SKIP_ZEROES, &permutations, status);
+        const UHashElement *ne2 = NULL;
+        int32_t el2 = -1;
+        //Iterator it2 = permutations.iterator();
+        ne2 = permutations.nextElement(el2);
+        //while (it2.hasNext())
+        while (ne2 != NULL) {
+            //String possible = (String) it2.next();
+            //UnicodeString *possible = new UnicodeString(*((UnicodeString *)(ne2->value.pointer)));
+            UnicodeString possible(*((UnicodeString *)(ne2->value.pointer)));
+            UnicodeString attempt;
+            nfd.normalize(possible, attempt, status);
+
+            // TODO: check if operator == is semanticaly the same as attempt.equals(segment)
+            if (attempt==segment) {
+                //if (PROGRESS) printf("Adding Permutation: %s\n", UToS(Tr(*possible)));
+                // TODO: use the hashtable just to catch duplicates - store strings directly (somehow).
+                result.put(possible, new UnicodeString(possible), status); //add(possible);
+            } else {
+                //if (PROGRESS) printf("-Skipping Permutation: %s\n", UToS(Tr(*possible)));
+            }
+
+            ne2 = permutations.nextElement(el2);
+        }
+        ne = basic.nextElement(el);
+    }
+
+    /* Test for buffer overflows */
+    if(U_FAILURE(status)) {
+        return 0;
+    }
+    // convert into a String[] to clean up storage
+    //String[] finalResult = new String[result.size()];
+    UnicodeString *finalResult = NULL;
+    int32_t resultCount;
+    if((resultCount = result.count())) {
+        finalResult = new UnicodeString[resultCount];
+        if (finalResult == 0) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return NULL;
+        }
+    }
+    else {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+    //result.toArray(finalResult);
+    result_len = 0;
+    el = -1;
+    ne = result.nextElement(el);
+    while(ne != NULL) {
+        finalResult[result_len++] = *((UnicodeString *)(ne->value.pointer));
+        ne = result.nextElement(el);
+    }
+
+
+    return finalResult;
+}
+
+Hashtable *CanonicalIterator::getEquivalents2(Hashtable *fillinResult, const UChar *segment, int32_t segLen, UErrorCode &status) {
+
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+
+    //if (PROGRESS) printf("Adding: %s\n", UToS(Tr(segment)));
+
+    UnicodeString toPut(segment, segLen);
+
+    fillinResult->put(toPut, new UnicodeString(toPut), status);
+
+    UnicodeSet starts;
+
+    // cycle through all the characters
+    UChar32 cp;
+    for (int32_t i = 0; i < segLen; i += UTF16_CHAR_LENGTH(cp)) {
+        // see if any character is at the start of some decomposition
+        UTF_GET_CHAR(segment, 0, i, segLen, cp);
+        if (!nfcImpl.getCanonStartSet(cp, starts)) {
+            continue;
+        }
+        // if so, see which decompositions match
+        UnicodeSetIterator iter(starts);
+        while (iter.next()) {
+            UChar32 cp2 = iter.getCodepoint();
+            Hashtable remainder(status);
+            remainder.setValueDeleter(uhash_deleteUnicodeString);
+            if (extract(&remainder, cp2, segment, segLen, i, status) == NULL) {
+                continue;
+            }
+
+            // there were some matches, so add all the possibilities to the set.
+            UnicodeString prefix(segment, i);
+            prefix += cp2;
+
+            int32_t el = -1;
+            const UHashElement *ne = remainder.nextElement(el);
+            while (ne != NULL) {
+                UnicodeString item = *((UnicodeString *)(ne->value.pointer));
+                UnicodeString *toAdd = new UnicodeString(prefix);
+                /* test for NULL */
+                if (toAdd == 0) {
+                    status = U_MEMORY_ALLOCATION_ERROR;
+                    return NULL;
+                }
+                *toAdd += item;
+                fillinResult->put(*toAdd, toAdd, status);
+
+                //if (PROGRESS) printf("Adding: %s\n", UToS(Tr(*toAdd)));
+
+                ne = remainder.nextElement(el);
+            }
+        }
+    }
+
+    /* Test for buffer overflows */
+    if(U_FAILURE(status)) {
+        return NULL;
+    }
+    return fillinResult;
+}
+
+/**
+ * See if the decomposition of cp2 is at segment starting at segmentPos 
+ * (with canonical rearrangment!)
+ * If so, take the remainder, and return the equivalents 
+ */
+Hashtable *CanonicalIterator::extract(Hashtable *fillinResult, UChar32 comp, const UChar *segment, int32_t segLen, int32_t segmentPos, UErrorCode &status) {
+//Hashtable *CanonicalIterator::extract(UChar32 comp, const UnicodeString &segment, int32_t segLen, int32_t segmentPos, UErrorCode &status) {
+    //if (PROGRESS) printf(" extract: %s, ", UToS(Tr(UnicodeString(comp))));
+    //if (PROGRESS) printf("%s, %i\n", UToS(Tr(segment)), segmentPos);
+
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+
+    UnicodeString temp(comp);
+    int32_t inputLen=temp.length();
+    UnicodeString decompString;
+    nfd.normalize(temp, decompString, status);
+    const UChar *decomp=decompString.getBuffer();
+    int32_t decompLen=decompString.length();
+
+    // See if it matches the start of segment (at segmentPos)
+    UBool ok = FALSE;
+    UChar32 cp;
+    int32_t decompPos = 0;
+    UChar32 decompCp;
+    U16_NEXT(decomp, decompPos, decompLen, decompCp);
+
+    int32_t i = segmentPos;
+    while(i < segLen) {
+        U16_NEXT(segment, i, segLen, cp);
+
+        if (cp == decompCp) { // if equal, eat another cp from decomp
+
+            //if (PROGRESS) printf("  matches: %s\n", UToS(Tr(UnicodeString(cp))));
+
+            if (decompPos == decompLen) { // done, have all decomp characters!
+                temp.append(segment+i, segLen-i);
+                ok = TRUE;
+                break;
+            }
+            U16_NEXT(decomp, decompPos, decompLen, decompCp);
+        } else {
+            //if (PROGRESS) printf("  buffer: %s\n", UToS(Tr(UnicodeString(cp))));
+
+            // brute force approach
+            temp.append(cp);
+
+            /* TODO: optimize
+            // since we know that the classes are monotonically increasing, after zero
+            // e.g. 0 5 7 9 0 3
+            // we can do an optimization
+            // there are only a few cases that work: zero, less, same, greater
+            // if both classes are the same, we fail
+            // if the decomp class < the segment class, we fail
+
+            segClass = getClass(cp);
+            if (decompClass <= segClass) return null;
+            */
+        }
+    }
+    if (!ok)
+        return NULL; // we failed, characters left over
+
+    //if (PROGRESS) printf("Matches\n");
+
+    if (inputLen == temp.length()) {
+        fillinResult->put(UnicodeString(), new UnicodeString(), status);
+        return fillinResult; // succeed, but no remainder
+    }
+
+    // brute force approach
+    // check to make sure result is canonically equivalent
+    UnicodeString trial;
+    nfd.normalize(temp, trial, status);
+    if(U_FAILURE(status) || trial.compare(segment+segmentPos, segLen - segmentPos) != 0) {
+        return NULL;
+    }
+
+    return getEquivalents2(fillinResult, temp.getBuffer()+inputLen, temp.length()-inputLen, status);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_NORMALIZATION */
diff --git a/source/common/chariter.cpp b/source/common/chariter.cpp
new file mode 100644
index 0000000..a598bd6
--- /dev/null
+++ b/source/common/chariter.cpp
@@ -0,0 +1,96 @@
+/*
+**********************************************************************
+*   Copyright (C) 1999-2004, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+
+#include "unicode/chariter.h"
+
+U_NAMESPACE_BEGIN
+
+ForwardCharacterIterator::~ForwardCharacterIterator() {}
+ForwardCharacterIterator::ForwardCharacterIterator()
+: UObject()
+{}
+ForwardCharacterIterator::ForwardCharacterIterator(const ForwardCharacterIterator &other)
+: UObject(other)
+{}
+
+
+CharacterIterator::CharacterIterator()
+: textLength(0), pos(0), begin(0), end(0) {
+}
+
+CharacterIterator::CharacterIterator(int32_t length)
+: textLength(length), pos(0), begin(0), end(length) {
+    if(textLength < 0) {
+        textLength = end = 0;
+    }
+}
+
+CharacterIterator::CharacterIterator(int32_t length, int32_t position)
+: textLength(length), pos(position), begin(0), end(length) {
+    if(textLength < 0) {
+        textLength = end = 0;
+    }
+    if(pos < 0) {
+        pos = 0;
+    } else if(pos > end) {
+        pos = end;
+    }
+}
+
+CharacterIterator::CharacterIterator(int32_t length, int32_t textBegin, int32_t textEnd, int32_t position)
+: textLength(length), pos(position), begin(textBegin), end(textEnd) {
+    if(textLength < 0) {
+        textLength = 0;
+    }
+    if(begin < 0) {
+        begin = 0;
+    } else if(begin > textLength) {
+        begin = textLength;
+    }
+    if(end < begin) {
+        end = begin;
+    } else if(end > textLength) {
+        end = textLength;
+    }
+    if(pos < begin) {
+        pos = begin;
+    } else if(pos > end) {
+        pos = end;
+    }
+}
+
+CharacterIterator::CharacterIterator(const CharacterIterator &that) :
+ForwardCharacterIterator(that),
+textLength(that.textLength), pos(that.pos), begin(that.begin), end(that.end)
+{
+}
+
+CharacterIterator &
+CharacterIterator::operator=(const CharacterIterator &that) {
+    ForwardCharacterIterator::operator=(that);
+    textLength = that.textLength;
+    pos = that.pos;
+    begin = that.begin;
+    end = that.end;
+    return *this;
+}
+
+// implementing first[32]PostInc() directly in a subclass should be faster
+// but these implementations make subclassing a little easier
+UChar
+CharacterIterator::firstPostInc(void) {
+    setToStart();
+    return nextPostInc();
+}
+
+UChar32
+CharacterIterator::first32PostInc(void) {
+    setToStart();
+    return next32PostInc();
+}
+
+U_NAMESPACE_END
diff --git a/source/common/charstr.cpp b/source/common/charstr.cpp
new file mode 100644
index 0000000..cdd5828
--- /dev/null
+++ b/source/common/charstr.cpp
@@ -0,0 +1,130 @@
+/*
+*******************************************************************************
+*   Copyright (C) 2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*******************************************************************************
+*   file name:  charstr.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2010may19
+*   created by: Markus W. Scherer
+*/
+
+#include "unicode/utypes.h"
+#include "charstr.h"
+#include "cmemory.h"
+#include "cstring.h"
+
+U_NAMESPACE_BEGIN
+
+CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) {
+    if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) {
+        len=s.len;
+        uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1);
+    }
+    return *this;
+}
+
+CharString &CharString::truncate(int32_t newLength) {
+    if(newLength<0) {
+        newLength=0;
+    }
+    if(newLength<len) {
+        buffer[len=newLength]=0;
+    }
+    return *this;
+}
+
+CharString &CharString::append(char c, UErrorCode &errorCode) {
+    if(ensureCapacity(len+2, 0, errorCode)) {
+        buffer[len++]=c;
+        buffer[len]=0;
+    }
+    return *this;
+}
+
+CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) {
+    if(U_FAILURE(errorCode)) {
+        return *this;
+    }
+    if(sLength<-1 || (s==NULL && sLength!=0)) {
+        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return *this;
+    }
+    if(sLength<0) {
+        sLength=uprv_strlen(s);
+    }
+    if(sLength>0) {
+        if(s==(buffer.getAlias()+len)) {
+            // The caller wrote into the getAppendBuffer().
+            if(sLength>=(buffer.getCapacity()-len)) {
+                // The caller wrote too much.
+                errorCode=U_INTERNAL_PROGRAM_ERROR;
+            } else {
+                buffer[len+=sLength]=0;
+            }
+        } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
+                  sLength>=(buffer.getCapacity()-len)
+        ) {
+            // (Part of) this string is appended to itself which requires reallocation,
+            // so we have to make a copy of the substring and append that.
+            return append(CharString(s, sLength, errorCode), errorCode);
+        } else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
+            uprv_memcpy(buffer.getAlias()+len, s, sLength);
+            buffer[len+=sLength]=0;
+        }
+    }
+    return *this;
+}
+
+char *CharString::getAppendBuffer(int32_t minCapacity,
+                                  int32_t desiredCapacityHint,
+                                  int32_t &resultCapacity,
+                                  UErrorCode &errorCode) {
+    if(U_FAILURE(errorCode)) {
+        resultCapacity=0;
+        return NULL;
+    }
+    int32_t appendCapacity=buffer.getCapacity()-len-1;  // -1 for NUL
+    if(appendCapacity>=minCapacity) {
+        resultCapacity=appendCapacity;
+        return buffer.getAlias()+len;
+    }
+    if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
+        resultCapacity=buffer.getCapacity()-len-1;
+        return buffer.getAlias()+len;
+    }
+    resultCapacity=0;
+    return NULL;
+}
+
+CharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) {
+    if(ensureCapacity(len+s.length()+1, 0, errorCode)) {
+        len+=s.extract(0, 0x7fffffff, buffer.getAlias()+len, buffer.getCapacity()-len, US_INV);
+    }
+    return *this;
+}
+
+UBool CharString::ensureCapacity(int32_t capacity,
+                                 int32_t desiredCapacityHint,
+                                 UErrorCode &errorCode) {
+    if(U_FAILURE(errorCode)) {
+        return FALSE;
+    }
+    if(capacity>buffer.getCapacity()) {
+        if(desiredCapacityHint==0) {
+            desiredCapacityHint=capacity+buffer.getCapacity();
+        }
+        if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==NULL) &&
+            buffer.resize(capacity, len+1)==NULL
+        ) {
+            errorCode=U_MEMORY_ALLOCATION_ERROR;
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+U_NAMESPACE_END
diff --git a/source/common/charstr.h b/source/common/charstr.h
new file mode 100644
index 0000000..2eb87a0
--- /dev/null
+++ b/source/common/charstr.h
@@ -0,0 +1,123 @@
+/*
+**********************************************************************
+*   Copyright (c) 2001-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   Date        Name        Description
+*   11/19/2001  aliu        Creation.
+*   05/19/2010  markus      Rewritten from scratch
+**********************************************************************
+*/
+
+#ifndef CHARSTRING_H
+#define CHARSTRING_H
+
+#include "unicode/utypes.h"
+#include "unicode/unistr.h"
+#include "unicode/uobject.h"
+#include "cmemory.h"
+
+U_NAMESPACE_BEGIN
+
+// Windows needs us to DLL-export the MaybeStackArray template specialization,
+// but MacOS X cannot handle it. Same as in digitlst.h.
+#if !defined(U_DARWIN)
+template class U_COMMON_API MaybeStackArray<char, 40>;
+#endif
+
+/**
+ * ICU-internal char * string class.
+ * This class does not assume or enforce any particular character encoding.
+ * Raw bytes can be stored. The string object owns its characters.
+ * A terminating NUL is stored, but the class does not prevent embedded NUL characters.
+ *
+ * This class wants to be convenient but is also deliberately minimalist.
+ * Please do not add methods if they only add minor convenience.
+ * For example:
+ *   cs.data()[5]='a';  // no need for setCharAt(5, 'a')
+ */
+class U_COMMON_API CharString : public UMemory {
+public:
+    CharString() : len(0) { buffer[0]=0; }
+    CharString(const StringPiece &s, UErrorCode &errorCode) : len(0) {
+        buffer[0]=0;
+        append(s, errorCode);
+    }
+    CharString(const CharString &s, UErrorCode &errorCode) : len(0) {
+        buffer[0]=0;
+        append(s, errorCode);
+    }
+    CharString(const char *s, int32_t sLength, UErrorCode &errorCode) : len(0) {
+        buffer[0]=0;
+        append(s, sLength, errorCode);
+    }
+    ~CharString() {}
+
+    /**
+     * Replaces this string's contents with the other string's contents.
+     * CharString does not support the standard copy constructor nor
+     * the assignment operator, to make copies explicit and to
+     * use a UErrorCode where memory allocations might be needed.
+     */
+    CharString &copyFrom(const CharString &other, UErrorCode &errorCode);
+
+    UBool isEmpty() { return len==0; }
+    int32_t length() const { return len; }
+    char operator[] (int32_t index) const { return buffer[index]; }
+    StringPiece toStringPiece() const { return StringPiece(buffer.getAlias(), len); }
+
+    const char *data() const { return buffer.getAlias(); }
+    char *data() { return buffer.getAlias(); }
+
+    CharString &clear() { len=0; buffer[0]=0; return *this; }
+    CharString &truncate(int32_t newLength);
+
+    CharString &append(char c, UErrorCode &errorCode);
+    CharString &append(const StringPiece &s, UErrorCode &errorCode) {
+        return append(s.data(), s.length(), errorCode);
+    }
+    CharString &append(const CharString &s, UErrorCode &errorCode) {
+        return append(s.data(), s.length(), errorCode);
+    }
+    CharString &append(const char *s, int32_t sLength, UErrorCode &status);
+    /**
+     * Returns a writable buffer for appending and writes the buffer's capacity to
+     * resultCapacity. Guarantees resultCapacity>=minCapacity if U_SUCCESS().
+     * There will additionally be space for a terminating NUL right at resultCapacity.
+     * (This function is similar to ByteSink.GetAppendBuffer().)
+     *
+     * The returned buffer is only valid until the next write operation
+     * on this string.
+     *
+     * After writing at most resultCapacity bytes, call append() with the
+     * pointer returned from this function and the number of bytes written.
+     *
+     * @param minCapacity required minimum capacity of the returned buffer;
+     *                    must be non-negative
+     * @param desiredCapacityHint desired capacity of the returned buffer;
+     *                            must be non-negative
+     * @param resultCapacity will be set to the capacity of the returned buffer
+     * @param errorCode in/out error code
+     * @return a buffer with resultCapacity>=min_capacity
+     */
+    char *getAppendBuffer(int32_t minCapacity,
+                          int32_t desiredCapacityHint,
+                          int32_t &resultCapacity,
+                          UErrorCode &errorCode);
+
+    CharString &appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode);
+
+private:
+    MaybeStackArray<char, 40> buffer;
+    int32_t len;
+
+    UBool ensureCapacity(int32_t capacity, int32_t desiredCapacityHint, UErrorCode &errorCode);
+
+    CharString(const CharString &other); // forbid copying of this class
+    CharString &operator=(const CharString &other); // forbid copying of this class
+};
+
+U_NAMESPACE_END
+
+#endif
+//eof
diff --git a/source/common/cmemory.c b/source/common/cmemory.c
new file mode 100644
index 0000000..0f93f36
--- /dev/null
+++ b/source/common/cmemory.c
@@ -0,0 +1,124 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2002-2003, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File cmemory.c      ICU Heap allocation.
+*                     All ICU heap allocation, both for C and C++ new of ICU
+*                     class types, comes through these functions.
+*
+*                     If you have a need to replace ICU allocation, this is the
+*                     place to do it.
+*
+*                     Note that uprv_malloc(0) returns a non-NULL pointer, and
+*                     that a subsequent free of that pointer value is a NOP.
+*
+******************************************************************************
+*/
+#include "unicode/uclean.h"
+#include "cmemory.h"
+#include <stdlib.h>
+
+/* uprv_malloc(0) returns a pointer to this read-only data. */                
+static const int32_t zeroMem[] = {0, 0, 0, 0, 0, 0};
+
+/* Function Pointers for user-supplied heap functions  */
+static const void     *pContext;
+static UMemAllocFn    *pAlloc;
+static UMemReallocFn  *pRealloc;
+static UMemFreeFn     *pFree;
+
+/* Flag indicating whether any heap allocations have happened.
+ *   Used to prevent changing out the heap functions after allocations have been made */
+static UBool   gHeapInUse;
+
+U_CAPI void * U_EXPORT2
+uprv_malloc(size_t s) {
+    if (s > 0) {
+        gHeapInUse = TRUE;
+        if (pAlloc) {
+            return (*pAlloc)(pContext, s);
+        } else {
+            return malloc(s);
+        }
+    } else {
+        return (void *)zeroMem;
+    }
+}
+
+U_CAPI void * U_EXPORT2
+uprv_realloc(void * buffer, size_t size) {
+    if (buffer == zeroMem) {
+        return uprv_malloc(size);
+    } else if (size == 0) {
+        if (pFree) {
+            (*pFree)(pContext, buffer);
+        } else {
+            free(buffer);
+        }
+        return (void *)zeroMem;
+    } else {
+        gHeapInUse = TRUE;
+        if (pRealloc) {
+            return (*pRealloc)(pContext, buffer, size);
+        } else {
+            return realloc(buffer, size);
+        }
+    }
+}
+
+U_CAPI void U_EXPORT2
+uprv_free(void *buffer) {
+    if (buffer != zeroMem) {
+        if (pFree) {
+            (*pFree)(pContext, buffer);
+        } else {
+            free(buffer);
+        }
+    }
+}
+
+U_CAPI void U_EXPORT2
+u_setMemoryFunctions(const void *context, UMemAllocFn *a, UMemReallocFn *r, UMemFreeFn *f,  UErrorCode *status)
+{
+    if (U_FAILURE(*status)) {
+        return;
+    }
+    if (a==NULL || r==NULL || f==NULL) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    if (gHeapInUse) {
+        *status = U_INVALID_STATE_ERROR;
+        return;
+    }
+    pContext  = context;
+    pAlloc    = a;
+    pRealloc  = r;
+    pFree     = f;
+}
+
+
+U_CFUNC UBool cmemory_cleanup(void) {
+    pContext   = NULL;
+    pAlloc     = NULL;
+    pRealloc   = NULL;
+    pFree      = NULL;
+    gHeapInUse = FALSE;
+    return TRUE;
+}
+
+
+/*
+ *   gHeapInUse
+ *       Return True if ICU has allocated any memory.
+ *       Used by u_SetMutexFunctions() and similar to verify that ICU has not
+ *               been used, that it is in a pristine initial state.
+ */
+U_CFUNC UBool cmemory_inUse() {
+    return gHeapInUse;
+}
+
diff --git a/source/common/cmemory.h b/source/common/cmemory.h
new file mode 100644
index 0000000..ba8c550
--- /dev/null
+++ b/source/common/cmemory.h
@@ -0,0 +1,539 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File CMEMORY.H
+*
+*  Contains stdlib.h/string.h memory functions
+*
+* @author       Bertrand A. Damiba
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   6/20/98     Bertrand    Created.
+*  05/03/99     stephen     Changed from functions to macros.
+*
+******************************************************************************
+*/
+
+#ifndef CMEMORY_H
+#define CMEMORY_H
+
+#include <stddef.h>
+#include <string.h>
+#include "unicode/utypes.h"
+#include "unicode/localpointer.h"
+
+#define uprv_memcpy(dst, src, size) U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size)
+#define uprv_memmove(dst, src, size) U_STANDARD_CPP_NAMESPACE memmove(dst, src, size)
+#define uprv_memset(buffer, mark, size) U_STANDARD_CPP_NAMESPACE memset(buffer, mark, size)
+#define uprv_memcmp(buffer1, buffer2, size) U_STANDARD_CPP_NAMESPACE memcmp(buffer1, buffer2,size)
+
+U_CAPI void * U_EXPORT2
+uprv_malloc(size_t s);
+
+U_CAPI void * U_EXPORT2
+uprv_realloc(void *mem, size_t size);
+
+U_CAPI void U_EXPORT2
+uprv_free(void *mem);
+
+/**
+ * This should align the memory properly on any machine.
+ * This is very useful for the safeClone functions.
+ */
+typedef union {
+    long    t1;
+    double  t2;
+    void   *t3;
+} UAlignedMemory;
+
+/**
+ * Get the least significant bits of a pointer (a memory address).
+ * For example, with a mask of 3, the macro gets the 2 least significant bits,
+ * which will be 0 if the pointer is 32-bit (4-byte) aligned.
+ *
+ * ptrdiff_t is the most appropriate integer type to cast to.
+ * size_t should work too, since on most (or all?) platforms it has the same
+ * width as ptrdiff_t.
+ */
+#define U_POINTER_MASK_LSB(ptr, mask) (((ptrdiff_t)(char *)(ptr)) & (mask))
+
+/**
+ * Get the amount of bytes that a pointer is off by from
+ * the previous UAlignedMemory-aligned pointer.
+ */
+#define U_ALIGNMENT_OFFSET(ptr) U_POINTER_MASK_LSB(ptr, sizeof(UAlignedMemory) - 1)
+
+/**
+ * Get the amount of bytes to add to a pointer
+ * in order to get the next UAlignedMemory-aligned address.
+ */
+#define U_ALIGNMENT_OFFSET_UP(ptr) (sizeof(UAlignedMemory) - U_ALIGNMENT_OFFSET(ptr))
+
+/**
+  *  Indicate whether the ICU allocation functions have been used.
+  *  This is used to determine whether ICU is in an initial, unused state.
+  */
+U_CFUNC UBool 
+cmemory_inUse(void);
+
+/**
+  *  Heap clean up function, called from u_cleanup()
+  *    Clears any user heap functions from u_setMemoryFunctions()
+  *    Does NOT deallocate any remaining allocated memory.
+  */
+U_CFUNC UBool 
+cmemory_cleanup(void);
+
+#ifdef XP_CPLUSPLUS
+
+U_NAMESPACE_BEGIN
+
+/**
+ * "Smart pointer" class, deletes memory via uprv_free().
+ * For most methods see the LocalPointerBase base class.
+ * Adds operator[] for array item access.
+ *
+ * @see LocalPointerBase
+ */
+template<typename T>
+class LocalMemory : public LocalPointerBase<T> {
+public:
+    /**
+     * Constructor takes ownership.
+     * @param p simple pointer to an array of T items that is adopted
+     */
+    explicit LocalMemory(T *p=NULL) : LocalPointerBase<T>(p) {}
+    /**
+     * Destructor deletes the memory it owns.
+     */
+    ~LocalMemory() {
+        uprv_free(LocalPointerBase<T>::ptr);
+    }
+    /**
+     * Deletes the array it owns,
+     * and adopts (takes ownership of) the one passed in.
+     * @param p simple pointer to an array of T items that is adopted
+     */
+    void adoptInstead(T *p) {
+        uprv_free(LocalPointerBase<T>::ptr);
+        LocalPointerBase<T>::ptr=p;
+    }
+    /**
+     * Deletes the array it owns, allocates a new one and reset its bytes to 0.
+     * Returns the new array pointer.
+     * If the allocation fails, then the current array is unchanged and
+     * this method returns NULL.
+     * @param newCapacity must be >0
+     * @return the allocated array pointer, or NULL if the allocation failed
+     */
+    inline T *allocateInsteadAndReset(int32_t newCapacity=1);
+    /**
+     * Deletes the array it owns and allocates a new one, copying length T items.
+     * Returns the new array pointer.
+     * If the allocation fails, then the current array is unchanged and
+     * this method returns NULL.
+     * @param newCapacity must be >0
+     * @param length number of T items to be copied from the old array to the new one;
+     *               must be no more than the capacity of the old array,
+     *               which the caller must track because the LocalMemory does not track it
+     * @return the allocated array pointer, or NULL if the allocation failed
+     */
+    inline T *allocateInsteadAndCopy(int32_t newCapacity=1, int32_t length=0);
+    /**
+     * Array item access (writable).
+     * No index bounds check.
+     * @param i array index
+     * @return reference to the array item
+     */
+    T &operator[](ptrdiff_t i) const { return LocalPointerBase<T>::ptr[i]; }
+};
+
+template<typename T>
+inline T *LocalMemory<T>::allocateInsteadAndReset(int32_t newCapacity) {
+    if(newCapacity>0) {
+        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
+        if(p!=NULL) {
+            uprv_memset(p, 0, newCapacity*sizeof(T));
+            uprv_free(LocalPointerBase<T>::ptr);
+            LocalPointerBase<T>::ptr=p;
+        }
+        return p;
+    } else {
+        return NULL;
+    }
+}
+
+
+template<typename T>
+inline T *LocalMemory<T>::allocateInsteadAndCopy(int32_t newCapacity, int32_t length) {
+    if(newCapacity>0) {
+        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
+        if(p!=NULL) {
+            if(length>0) {
+                if(length>newCapacity) {
+                    length=newCapacity;
+                }
+                uprv_memcpy(p, LocalPointerBase<T>::ptr, length*sizeof(T));
+            }
+            uprv_free(LocalPointerBase<T>::ptr);
+            LocalPointerBase<T>::ptr=p;
+        }
+        return p;
+    } else {
+        return NULL;
+    }
+}
+
+/**
+ * Simple array/buffer management class using uprv_malloc() and uprv_free().
+ * Provides an internal array with fixed capacity. Can alias another array
+ * or allocate one.
+ *
+ * The array address is properly aligned for type T. It might not be properly
+ * aligned for types larger than T (or larger than the largest subtype of T).
+ *
+ * Unlike LocalMemory and LocalArray, this class never adopts
+ * (takes ownership of) another array.
+ */
+template<typename T, int32_t stackCapacity>
+class MaybeStackArray {
+public:
+    /**
+     * Default constructor initializes with internal T[stackCapacity] buffer.
+     */
+    MaybeStackArray() : ptr(stackArray), capacity(stackCapacity), needToRelease(FALSE) {}
+    /**
+     * Destructor deletes the array (if owned).
+     */
+    ~MaybeStackArray() { releaseArray(); }
+    /**
+     * Returns the array capacity (number of T items).
+     * @return array capacity
+     */
+    int32_t getCapacity() const { return capacity; }
+    /**
+     * Access without ownership change.
+     * @return the array pointer
+     */
+    T *getAlias() const { return ptr; }
+    /**
+     * Returns the array limit. Simple convenience method.
+     * @return getAlias()+getCapacity()
+     */
+    T *getArrayLimit() const { return getAlias()+capacity; }
+    /**
+     * Access without ownership change. Same as getAlias().
+     * A class instance can be used directly in expressions that take a T *.
+     * @return the array pointer
+     */
+    operator T *() const { return ptr; }
+    /**
+     * Array item access (writable).
+     * No index bounds check.
+     * @param i array index
+     * @return reference to the array item
+     */
+    T &operator[](ptrdiff_t i) { return ptr[i]; }
+    /**
+     * Deletes the array (if owned) and aliases another one, no transfer of ownership.
+     * If the arguments are illegal, then the current array is unchanged.
+     * @param otherArray must not be NULL
+     * @param otherCapacity must be >0
+     */
+    void aliasInstead(T *otherArray, int32_t otherCapacity) {
+        if(otherArray!=NULL && otherCapacity>0) {
+            releaseArray();
+            ptr=otherArray;
+            capacity=otherCapacity;
+            needToRelease=FALSE;
+        }
+    };
+    /**
+     * Deletes the array (if owned) and allocates a new one, copying length T items.
+     * Returns the new array pointer.
+     * If the allocation fails, then the current array is unchanged and
+     * this method returns NULL.
+     * @param newCapacity can be less than or greater than the current capacity;
+     *                    must be >0
+     * @param length number of T items to be copied from the old array to the new one
+     * @return the allocated array pointer, or NULL if the allocation failed
+     */
+    inline T *resize(int32_t newCapacity, int32_t length=0);
+    /**
+     * Gives up ownership of the array if owned, or else clones it,
+     * copying length T items; resets itself to the internal stack array.
+     * Returns NULL if the allocation failed.
+     * @param length number of T items to copy when cloning,
+     *        and capacity of the clone when cloning
+     * @param resultCapacity will be set to the returned array's capacity (output-only)
+     * @return the array pointer;
+     *         caller becomes responsible for deleting the array
+     * @draft ICU 4.4
+     */
+    inline T *orphanOrClone(int32_t length, int32_t &resultCapacity);
+private:
+    T *ptr;
+    int32_t capacity;
+    UBool needToRelease;
+    T stackArray[stackCapacity];
+    void releaseArray() {
+        if(needToRelease) {
+            uprv_free(ptr);
+        }
+    }
+    /* No comparison operators with other MaybeStackArray's. */
+    bool operator==(const MaybeStackArray & /*other*/) {return FALSE;};
+    bool operator!=(const MaybeStackArray & /*other*/) {return TRUE;};
+    /* No ownership transfer: No copy constructor, no assignment operator. */
+    MaybeStackArray(const MaybeStackArray & /*other*/) {};
+    void operator=(const MaybeStackArray & /*other*/) {};
+
+    // No heap allocation. Use only on the stack.
+    //   (Declaring these functions private triggers a cascade of problems:
+    //      MSVC insists on exporting an instantiation of MaybeStackArray, which
+    //      requires that all functions be defined.
+    //      An empty implementation of new() is rejected, it must return a value.
+    //      Returning NULL is rejected by gcc for operator new.
+    //      The expedient thing is just not to override operator new.
+    //      While relatively pointless, heap allocated instances will function.
+    // static void * U_EXPORT2 operator new(size_t size); 
+    // static void * U_EXPORT2 operator new[](size_t size);
+#if U_HAVE_PLACEMENT_NEW
+    // static void * U_EXPORT2 operator new(size_t, void *ptr);
+#endif
+};
+
+template<typename T, int32_t stackCapacity>
+inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) {
+    if(newCapacity>0) {
+        T *p=(T *)uprv_malloc(newCapacity*sizeof(T));
+        if(p!=NULL) {
+            if(length>0) {
+                if(length>capacity) {
+                    length=capacity;
+                }
+                if(length>newCapacity) {
+                    length=newCapacity;
+                }
+                uprv_memcpy(p, ptr, length*sizeof(T));
+            }
+            releaseArray();
+            ptr=p;
+            capacity=newCapacity;
+            needToRelease=TRUE;
+        }
+        return p;
+    } else {
+        return NULL;
+    }
+}
+
+template<typename T, int32_t stackCapacity>
+inline T *MaybeStackArray<T, stackCapacity>::orphanOrClone(int32_t length, int32_t &resultCapacity) {
+    T *p;
+    if(needToRelease) {
+        p=ptr;
+    } else if(length<=0) {
+        return NULL;
+    } else {
+        if(length>capacity) {
+            length=capacity;
+        }
+        p=(T *)uprv_malloc(length*sizeof(T));
+        if(p==NULL) {
+            return NULL;
+        }
+        uprv_memcpy(p, ptr, length*sizeof(T));
+    }
+    resultCapacity=length;
+    ptr=stackArray;
+    capacity=stackCapacity;
+    needToRelease=FALSE;
+    return p;
+}
+
+/**
+ * Variant of MaybeStackArray that allocates a header struct and an array
+ * in one contiguous memory block, using uprv_malloc() and uprv_free().
+ * Provides internal memory with fixed array capacity. Can alias another memory
+ * block or allocate one.
+ * The stackCapacity is the number of T items in the internal memory,
+ * not counting the H header.
+ * Unlike LocalMemory and LocalArray, this class never adopts
+ * (takes ownership of) another memory block.
+ */
+template<typename H, typename T, int32_t stackCapacity>
+class MaybeStackHeaderAndArray {
+public:
+    /**
+     * Default constructor initializes with internal H+T[stackCapacity] buffer.
+     */
+    MaybeStackHeaderAndArray() : ptr(&stackHeader), capacity(stackCapacity), needToRelease(FALSE) {}
+    /**
+     * Destructor deletes the memory (if owned).
+     */
+    ~MaybeStackHeaderAndArray() { releaseMemory(); }
+    /**
+     * Returns the array capacity (number of T items).
+     * @return array capacity
+     */
+    int32_t getCapacity() const { return capacity; }
+    /**
+     * Access without ownership change.
+     * @return the header pointer
+     */
+    H *getAlias() const { return ptr; }
+    /**
+     * Returns the array start.
+     * @return array start, same address as getAlias()+1
+     */
+    T *getArrayStart() const { return reinterpret_cast<T *>(getAlias()+1); }
+    /**
+     * Returns the array limit.
+     * @return array limit
+     */
+    T *getArrayLimit() const { return getArrayStart()+capacity; }
+    /**
+     * Access without ownership change. Same as getAlias().
+     * A class instance can be used directly in expressions that take a T *.
+     * @return the header pointer
+     */
+    operator H *() const { return ptr; }
+    /**
+     * Array item access (writable).
+     * No index bounds check.
+     * @param i array index
+     * @return reference to the array item
+     */
+    T &operator[](ptrdiff_t i) { return getArrayStart()[i]; }
+    /**
+     * Deletes the memory block (if owned) and aliases another one, no transfer of ownership.
+     * If the arguments are illegal, then the current memory is unchanged.
+     * @param otherArray must not be NULL
+     * @param otherCapacity must be >0
+     */
+    void aliasInstead(H *otherMemory, int32_t otherCapacity) {
+        if(otherMemory!=NULL && otherCapacity>0) {
+            releaseMemory();
+            ptr=otherMemory;
+            capacity=otherCapacity;
+            needToRelease=FALSE;
+        }
+    };
+    /**
+     * Deletes the memory block (if owned) and allocates a new one,
+     * copying the header and length T array items.
+     * Returns the new header pointer.
+     * If the allocation fails, then the current memory is unchanged and
+     * this method returns NULL.
+     * @param newCapacity can be less than or greater than the current capacity;
+     *                    must be >0
+     * @param length number of T items to be copied from the old array to the new one
+     * @return the allocated pointer, or NULL if the allocation failed
+     */
+    inline H *resize(int32_t newCapacity, int32_t length=0);
+    /**
+     * Gives up ownership of the memory if owned, or else clones it,
+     * copying the header and length T array items; resets itself to the internal memory.
+     * Returns NULL if the allocation failed.
+     * @param length number of T items to copy when cloning,
+     *        and array capacity of the clone when cloning
+     * @param resultCapacity will be set to the returned array's capacity (output-only)
+     * @return the header pointer;
+     *         caller becomes responsible for deleting the array
+     * @draft ICU 4.4
+     */
+    inline H *orphanOrClone(int32_t length, int32_t &resultCapacity);
+private:
+    H *ptr;
+    int32_t capacity;
+    UBool needToRelease;
+    // stackHeader must precede stackArray immediately.
+    H stackHeader;
+    T stackArray[stackCapacity];
+    void releaseMemory() {
+        if(needToRelease) {
+            uprv_free(ptr);
+        }
+    }
+    /* No comparison operators with other MaybeStackHeaderAndArray's. */
+    bool operator==(const MaybeStackHeaderAndArray & /*other*/) {return FALSE;};
+    bool operator!=(const MaybeStackHeaderAndArray & /*other*/) {return TRUE;};
+    /* No ownership transfer: No copy constructor, no assignment operator. */
+    MaybeStackHeaderAndArray(const MaybeStackHeaderAndArray & /*other*/) {};
+    void operator=(const MaybeStackHeaderAndArray & /*other*/) {};
+
+    // No heap allocation. Use only on the stack.
+    //   (Declaring these functions private triggers a cascade of problems;
+    //    see the MaybeStackArray class for details.)
+    // static void * U_EXPORT2 operator new(size_t size); 
+    // static void * U_EXPORT2 operator new[](size_t size);
+#if U_HAVE_PLACEMENT_NEW
+    // static void * U_EXPORT2 operator new(size_t, void *ptr);
+#endif
+};
+
+template<typename H, typename T, int32_t stackCapacity>
+inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::resize(int32_t newCapacity,
+                                                                int32_t length) {
+    if(newCapacity>=0) {
+        H *p=(H *)uprv_malloc(sizeof(H)+newCapacity*sizeof(T));
+        if(p!=NULL) {
+            if(length<0) {
+                length=0;
+            } else if(length>0) {
+                if(length>capacity) {
+                    length=capacity;
+                }
+                if(length>newCapacity) {
+                    length=newCapacity;
+                }
+            }
+            uprv_memcpy(p, ptr, sizeof(H)+length*sizeof(T));
+            releaseMemory();
+            ptr=p;
+            capacity=newCapacity;
+            needToRelease=TRUE;
+        }
+        return p;
+    } else {
+        return NULL;
+    }
+}
+
+template<typename H, typename T, int32_t stackCapacity>
+inline H *MaybeStackHeaderAndArray<H, T, stackCapacity>::orphanOrClone(int32_t length,
+                                                                       int32_t &resultCapacity) {
+    H *p;
+    if(needToRelease) {
+        p=ptr;
+    } else {
+        if(length<0) {
+            length=0;
+        } else if(length>capacity) {
+            length=capacity;
+        }
+        p=(H *)uprv_malloc(sizeof(H)+length*sizeof(T));
+        if(p==NULL) {
+            return NULL;
+        }
+        uprv_memcpy(p, ptr, sizeof(H)+length*sizeof(T));
+    }
+    resultCapacity=length;
+    ptr=&stackHeader;
+    capacity=stackCapacity;
+    needToRelease=FALSE;
+    return p;
+}
+
+U_NAMESPACE_END
+
+#endif  /* XP_CPLUSPLUS */
+#endif  /* CMEMORY_H */
diff --git a/source/common/common.rc b/source/common/common.rc
new file mode 100644
index 0000000..e0820bb
--- /dev/null
+++ b/source/common/common.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 "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
+    "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 " Common 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", "icuuc" U_ICU_VERSION_SHORT "d.dll\0"
+#else
+            VALUE "OriginalFilename", "icuuc" 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/source/common/common.vcxproj b/source/common/common.vcxproj
new file mode 100644
index 0000000..50ab5a6
--- /dev/null
+++ b/source/common/common.vcxproj
@@ -0,0 +1,1610 @@
+<?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>{73C0A65B-D1F2-4DE1-B3A6-15DAD2C23F3D}</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\icuuc.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;U_COMMON_IMPLEMENTATION;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <StringPooling>true</StringPooling>

+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x86\Release/common.pch</PrecompiledHeaderOutputFile>

+      <AssemblerListingLocation>.\x86\Release/</AssemblerListingLocation>

+      <ObjectFileName>.\x86\Release/</ObjectFileName>

+      <ProgramDataBaseFileName>.\x86\Release/</ProgramDataBaseFileName>

+      <WarningLevel>Level3</WarningLevel>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+    </ClCompile>

+    <ResourceCompile>

+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <Culture>0x0409</Culture>

+    </ResourceCompile>

+    <Link>

+      <OutputFile>..\..\bin\icuuc46.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <ProgramDatabaseFile>.\..\..\lib\icuuc.pdb</ProgramDatabaseFile>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <BaseAddress>0x4a800000</BaseAddress>

+      <RandomizedBaseAddress>false</RandomizedBaseAddress>

+      <DataExecutionPrevention>

+      </DataExecutionPrevention>

+      <ImportLibrary>..\..\lib\icuuc.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\icuucd.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;U_COMMON_IMPLEMENTATION;RBBI_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>

+      <BufferSecurityCheck>true</BufferSecurityCheck>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x86\Debug/common.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>

+    </ClCompile>

+    <ResourceCompile>

+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <Culture>0x0409</Culture>

+    </ResourceCompile>

+    <Link>

+      <OutputFile>..\..\bin\icuuc46d.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <ProgramDatabaseFile>.\..\..\lib\icuucd.pdb</ProgramDatabaseFile>

+      <BaseAddress>0x4a800000</BaseAddress>

+      <RandomizedBaseAddress>false</RandomizedBaseAddress>

+      <DataExecutionPrevention>

+      </DataExecutionPrevention>

+      <ImportLibrary>..\..\lib\icuucd.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\icuuc.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <PreprocessorDefinitions>WIN64;WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;U_COMMON_IMPLEMENTATION;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <StringPooling>true</StringPooling>

+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x64\Release/common.pch</PrecompiledHeaderOutputFile>

+      <AssemblerListingLocation>.\x64\Release/</AssemblerListingLocation>

+      <ObjectFileName>.\x64\Release/</ObjectFileName>

+      <ProgramDataBaseFileName>.\x64\Release/</ProgramDataBaseFileName>

+      <WarningLevel>Level3</WarningLevel>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+    </ClCompile>

+    <ResourceCompile>

+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <Culture>0x0409</Culture>

+    </ResourceCompile>

+    <Link>

+      <OutputFile>..\..\bin64\icuuc46.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <ProgramDatabaseFile>.\..\..\lib64\icuuc.pdb</ProgramDatabaseFile>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <BaseAddress>0x4a800000</BaseAddress>

+      <ImportLibrary>..\..\lib64\icuuc.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\icuucd.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <PreprocessorDefinitions>WIN64;WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;U_COMMON_IMPLEMENTATION;RBBI_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>

+      <BufferSecurityCheck>true</BufferSecurityCheck>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x64\Debug/common.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>

+    </ClCompile>

+    <ResourceCompile>

+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <Culture>0x0409</Culture>

+    </ResourceCompile>

+    <Link>

+      <OutputFile>..\..\bin64\icuuc46d.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <ProgramDatabaseFile>.\..\..\lib64\icuucd.pdb</ProgramDatabaseFile>

+      <BaseAddress>0x4a800000</BaseAddress>

+      <ImportLibrary>..\..\lib64\icuucd.lib</ImportLibrary>

+      <TargetMachine>MachineX64</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="ubidi.c" />

+    <ClCompile Include="ubidi_props.c" />

+    <ClCompile Include="ubidiln.c" />

+    <ClCompile Include="ubidiwrt.c" />

+    <ClCompile Include="ushape.c" />

+    <ClCompile Include="brkeng.cpp" />

+    <ClCompile Include="brkiter.cpp" />

+    <ClCompile Include="dictbe.cpp" />

+    <ClCompile Include="rbbi.cpp" />

+    <ClCompile Include="rbbidata.cpp" />

+    <ClCompile Include="rbbinode.cpp" />

+    <ClCompile Include="rbbirb.cpp" />

+    <ClCompile Include="rbbiscan.cpp" />

+    <ClCompile Include="rbbisetb.cpp" />

+    <ClCompile Include="rbbistbl.cpp" />

+    <ClCompile Include="rbbitblb.cpp" />

+    <ClCompile Include="triedict.cpp" />

+    <ClCompile Include="ubrk.cpp" />

+    <ClCompile Include="ucol_swp.cpp">

+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\i18n;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\i18n;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\i18n;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\i18n;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+    </ClCompile>

+    <ClCompile Include="propsvec.c" />

+    <ClCompile Include="uarrsort.c" />

+    <ClCompile Include="uenum.c" />

+    <ClCompile Include="uhash.c" />

+    <ClCompile Include="uhash_us.cpp" />

+    <ClCompile Include="ulist.c" />

+    <ClCompile Include="ustack.cpp" />

+    <ClCompile Include="ustrenum.cpp" />

+    <ClCompile Include="utrie.c" />

+    <ClCompile Include="utrie2.cpp" />

+    <ClCompile Include="utrie2_builder.c" />

+    <ClCompile Include="uvector.cpp" />

+    <ClCompile Include="uvectr32.cpp" />

+    <ClCompile Include="uvectr64.cpp" />

+    <ClCompile Include="errorcode.cpp" />

+    <ClCompile Include="icudataver.c" />

+    <ClCompile Include="locmap.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="mutex.cpp" />

+    <ClCompile Include="putil.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="umath.c" />

+    <ClCompile Include="umutex.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="utrace.c" />

+    <ClCompile Include="utypes.c" />

+    <ClCompile Include="wintz.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="ucnv.c" />

+    <ClCompile Include="ucnv2022.c" />

+    <ClCompile Include="ucnv_bld.c" />

+    <ClCompile Include="ucnv_cb.c" />

+    <ClCompile Include="ucnv_cnv.c" />

+    <ClCompile Include="ucnv_err.c" />

+    <ClCompile Include="ucnv_ext.c" />

+    <ClCompile Include="ucnv_io.c" />

+    <ClCompile Include="ucnv_lmb.c" />

+    <ClCompile Include="ucnv_set.c" />

+    <ClCompile Include="ucnv_u16.c" />

+    <ClCompile Include="ucnv_u32.c" />

+    <ClCompile Include="ucnv_u7.c" />

+    <ClCompile Include="ucnv_u8.c" />

+    <ClCompile Include="ucnvbocu.c" />

+    <ClCompile Include="ucnvdisp.c" />

+    <ClCompile Include="ucnvhz.c" />

+    <ClCompile Include="ucnvisci.c" />

+    <ClCompile Include="ucnvlat1.c" />

+    <ClCompile Include="ucnvmbcs.c" />

+    <ClCompile Include="ucnvscsu.c" />

+    <ClCompile Include="ucnvsel.cpp" />

+    <ClCompile Include="cmemory.c" />

+    <ClCompile Include="ucln_cmn.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="ucmndata.c" />

+    <ClCompile Include="udata.cpp" />

+    <ClCompile Include="udatamem.c" />

+    <ClCompile Include="udataswp.c" />

+    <ClCompile Include="uinit.c" />

+    <ClCompile Include="umapfile.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="uobject.cpp" />

+    <ClCompile Include="dtintrv.cpp" />

+    <ClCompile Include="parsepos.cpp" />

+    <ClCompile Include="ustrfmt.c" />

+    <ClCompile Include="util.cpp" />

+    <ClCompile Include="util_props.cpp" />

+    <ClCompile Include="punycode.c" />

+    <ClCompile Include="uidna.cpp" />

+    <ClCompile Include="uts46.cpp" />

+    <ClCompile Include="locavailable.cpp" />

+    <ClCompile Include="locbased.cpp" />

+    <ClCompile Include="locdispnames.cpp" />

+    <ClCompile Include="locid.cpp" />

+    <ClCompile Include="loclikely.cpp" />

+    <ClCompile Include="locresdata.cpp" />

+    <ClCompile Include="locutil.cpp" />

+    <ClCompile Include="resbund.cpp" />

+    <ClCompile Include="resbund_cnv.cpp" />

+    <ClCompile Include="ucat.c" />

+    <ClCompile Include="uloc.c" />

+    <ClCompile Include="uloc_tag.c" />

+    <ClCompile Include="ures_cnv.c" />

+    <ClCompile Include="uresbund.c" />

+    <ClCompile Include="uresdata.c" />

+    <ClCompile Include="caniter.cpp" />

+    <ClCompile Include="filterednormalizer2.cpp" />

+    <ClCompile Include="normalizer2.cpp" />

+    <ClCompile Include="normalizer2impl.cpp" />

+    <ClCompile Include="normlzr.cpp" />

+    <ClCompile Include="unorm.cpp" />

+    <ClCompile Include="unorm_it.c" />

+    <ClCompile Include="unormcmp.cpp" />

+    <ClCompile Include="bmpset.cpp" />

+    <ClCompile Include="propname.cpp" />

+    <ClCompile Include="ruleiter.cpp" />

+    <ClCompile Include="ucase.c" />

+    <ClCompile Include="uchar.c" />

+    <ClCompile Include="unames.c" />

+    <ClCompile Include="unifilt.cpp" />

+    <ClCompile Include="unifunct.cpp" />

+    <ClCompile Include="uniset.cpp" />

+    <ClCompile Include="uniset_props.cpp" />

+    <ClCompile Include="unisetspan.cpp" />

+    <ClCompile Include="uprops.cpp" />

+    <ClCompile Include="usc_impl.c" />

+    <ClCompile Include="uscript.c" />

+    <ClCompile Include="uset.cpp" />

+    <ClCompile Include="uset_props.cpp" />

+    <ClCompile Include="usetiter.cpp" />

+    <ClCompile Include="icuplug.c" />

+    <ClCompile Include="serv.cpp" />

+    <ClCompile Include="servlk.cpp" />

+    <ClCompile Include="servlkf.cpp" />

+    <ClCompile Include="servls.cpp" />

+    <ClCompile Include="servnotf.cpp" />

+    <ClCompile Include="servrbf.cpp" />

+    <ClCompile Include="servslkf.cpp" />

+    <ClCompile Include="usprep.cpp" />

+    <ClCompile Include="bytestream.cpp" />

+    <ClCompile Include="chariter.cpp" />

+    <ClCompile Include="charstr.cpp" />

+    <ClCompile Include="cstring.c" />

+    <ClCompile Include="cwchar.c" />

+    <ClCompile Include="schriter.cpp" />

+    <ClCompile Include="stringpiece.cpp" />

+    <ClCompile Include="ucasemap.c" />

+    <ClCompile Include="uchriter.cpp" />

+    <ClCompile Include="uinvchar.c" />

+    <ClCompile Include="uiter.cpp" />

+    <ClCompile Include="unistr.cpp" />

+    <ClCompile Include="unistr_case.cpp" />

+    <ClCompile Include="unistr_cnv.cpp" />

+    <ClCompile Include="unistr_props.cpp" />

+    <ClCompile Include="ustr_cnv.c" />

+    <ClCompile Include="ustr_wcs.c" />

+    <ClCompile Include="ustrcase.c" />

+    <ClCompile Include="ustring.c" />

+    <ClCompile Include="ustrtrns.c" />

+    <ClCompile Include="utext.cpp" />

+    <ClCompile Include="utf_impl.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <CustomBuild Include="unicode\ubidi.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="ubidi_props.h" />

+    <ClInclude Include="ubidiimp.h" />

+    <CustomBuild Include="unicode\ushape.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="brkeng.h" />

+    <CustomBuild Include="unicode\brkiter.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\dbbi.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="dictbe.h" />

+    <CustomBuild Include="unicode\rbbi.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="rbbidata.h" />

+    <ClInclude Include="rbbinode.h" />

+    <ClInclude Include="rbbirb.h" />

+    <ClInclude Include="rbbirpt.h" />

+    <ClInclude Include="rbbiscan.h" />

+    <ClInclude Include="rbbisetb.h" />

+    <ClInclude Include="rbbitblb.h" />

+    <ClInclude Include="triedict.h" />

+    <CustomBuild Include="unicode\ubrk.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="ubrkimpl.h" />

+    <ClInclude Include="ucol_swp.h" />

+    <ClInclude Include="hash.h" />

+    <ClInclude Include="propsvec.h" />

+    <CustomBuild Include="unicode\strenum.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="uarrsort.h" />

+    <CustomBuild Include="unicode\uenum.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="uenumimp.h" />

+    <ClInclude Include="uhash.h" />

+    <ClInclude Include="ulist.h" />

+    <ClInclude Include="ustrenum.h" />

+    <ClInclude Include="utrie.h" />

+    <ClInclude Include="utrie2.h" />

+    <ClInclude Include="utrie2_impl.h" />

+    <ClInclude Include="uvector.h" />

+    <ClInclude Include="uvectr32.h" />

+    <ClInclude Include="uvectr64.h" />

+    <ClInclude Include="cpputils.h" />

+    <CustomBuild Include="unicode\docmain.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\errorcode.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\icudataver.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="locmap.h" />

+    <ClInclude Include="mutex.h" />

+    <CustomBuild Include="unicode\putil.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="putilimp.h" />

+    <CustomBuild Include="unicode\pwin32.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\std_string.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="uassert.h" />

+    <CustomBuild Include="unicode\uconfig.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\udeprctd.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\udraft.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\uintrnal.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\umachine.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="umutex.h" />

+    <CustomBuild Include="unicode\uobslete.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\urename.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\usystem.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\utrace.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="utracimp.h" />

+    <CustomBuild Include="unicode\utypes.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\uvernum.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\uversion.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="wintz.h" />

+    <CustomBuild Include="unicode\ucnv.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="ucnv_bld.h" />

+    <CustomBuild Include="unicode\ucnv_cb.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="ucnv_cnv.h" />

+    <CustomBuild Include="unicode\ucnv_err.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="ucnv_ext.h" />

+    <ClInclude Include="ucnv_imp.h" />

+    <ClInclude Include="ucnv_io.h" />

+    <ClInclude Include="ucnvmbcs.h" />

+    <CustomBuild Include="unicode\ucnvsel.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="cmemory.h" />

+    <CustomBuild Include="unicode\localpointer.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\uclean.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="ucln.h" />

+    <ClInclude Include="ucln_cmn.h" />

+    <ClInclude Include="ucln_imp.h" />

+    <ClInclude Include="ucmndata.h" />

+    <CustomBuild Include="unicode\udata.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="udatamem.h" />

+    <ClInclude Include="udataswp.h" />

+    <ClInclude Include="umapfile.h" />

+    <CustomBuild Include="unicode\uobject.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\dtintrv.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\parseerr.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\parsepos.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\umisc.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="ustrfmt.h" />

+    <ClInclude Include="util.h" />

+    <CustomBuild Include="unicode\idna.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="punycode.h" />

+    <CustomBuild Include="unicode\uidna.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="locbased.h" />

+    <CustomBuild Include="unicode\locid.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="locutil.h" />

+    <CustomBuild Include="unicode\resbund.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\ucat.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\uloc.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="ulocimp.h" />

+    <CustomBuild Include="unicode\ures.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="uresdata.h" />

+    <ClInclude Include="uresimp.h" />

+    <ClInclude Include="ureslocs.h" />

+    <CustomBuild Include="unicode\caniter.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\normalizer2.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="normalizer2impl.h" />

+    <CustomBuild Include="unicode\normlzr.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\unorm.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\unorm2.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="unorm_it.h" />

+    <ClInclude Include="unormimp.h" />

+    <ClInclude Include="bmpset.h" />

+    <ClInclude Include="propname.h" />

+    <ClInclude Include="ruleiter.h" />

+    <CustomBuild Include="unicode\symtable.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="ucase.h" />

+    <CustomBuild Include="unicode\uchar.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\unifilt.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\unifunct.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\unimatch.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\uniset.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="unisetspan.h" />

+    <ClInclude Include="uprops.h" />

+    <ClInclude Include="usc_impl.h" />

+    <CustomBuild Include="unicode\uscript.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\uset.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="uset_imp.h" />

+    <CustomBuild Include="unicode\usetiter.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\icuplug.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="icuplugimp.h" />

+    <ClInclude Include="serv.h" />

+    <ClInclude Include="servloc.h" />

+    <ClInclude Include="servnotf.h" />

+    <ClInclude Include="sprpimpl.h" />

+    <CustomBuild Include="unicode\usprep.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\bytestream.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\chariter.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="charstr.h" />

+    <ClInclude Include="cstring.h" />

+    <ClInclude Include="cwchar.h" />

+    <CustomBuild Include="unicode\rep.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\schriter.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\stringpiece.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\ucasemap.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\uchriter.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="uinvchar.h" />

+    <CustomBuild Include="unicode\uiter.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\unistr.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\urep.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="ustr_cnv.h" />

+    <ClInclude Include="ustr_imp.h" />

+    <CustomBuild Include="unicode\ustring.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\utext.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\utf.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\utf16.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\utf32.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\utf8.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\utf_old.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>

+  </ItemGroup>

+  <ItemGroup>

+    <ResourceCompile Include="common.rc" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\stubdata\stubdata.vcxproj">

+      <Project>{203ec78a-0531-43f0-a636-285439bde025}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
diff --git a/source/common/common.vcxproj.filters b/source/common/common.vcxproj.filters
new file mode 100644
index 0000000..95e14b0
--- /dev/null
+++ b/source/common/common.vcxproj.filters
@@ -0,0 +1,995 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="bidi">

+      <UniqueIdentifier>{8049805d-3f8b-4731-ac8a-aa19b3cbea45}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="break iteration">

+      <UniqueIdentifier>{7668dce2-7846-4b48-8bd4-4ef781671b62}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="collation">

+      <UniqueIdentifier>{f08dc85c-73ea-47b5-a867-b67589e6bebf}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="collections">

+      <UniqueIdentifier>{51edbf4b-fe36-401e-9571-0472d9dae727}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="configuration">

+      <UniqueIdentifier>{3fd9d1ea-6efc-4768-a43d-811379162322}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="conversion">

+      <UniqueIdentifier>{f74f43ea-8ea9-49a9-a097-e2aa5a409368}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="data &amp; memory">

+      <UniqueIdentifier>{c7b856da-4f50-42c5-a741-8995df25dc6b}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="formatting">

+      <UniqueIdentifier>{c76cfce3-cfe6-4de0-aa37-44c599377e2f}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="idna">

+      <UniqueIdentifier>{9abf6a02-9db0-4ecd-a8d9-bbb28073a424}</UniqueIdentifier>

+      <Extensions>*.c,*.h</Extensions>

+    </Filter>

+    <Filter Include="locales &amp; resources">

+      <UniqueIdentifier>{b481ca81-7bc8-4399-a220-27fc29a7b74d}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="normalization">

+      <UniqueIdentifier>{923074b3-0112-4faf-b8c7-59feb85a0835}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="properties &amp; sets">

+      <UniqueIdentifier>{17948745-0376-4851-bf12-7dabf94622e7}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="registration">

+      <UniqueIdentifier>{b32b9445-b6dc-4800-94a6-28641e586cd4}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="sprep">

+      <UniqueIdentifier>{ea285df7-8e35-4b10-ae2a-86cb32c0d477}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="strings">

+      <UniqueIdentifier>{2c52192a-7b17-4c3b-998e-ca025063bd3c}</UniqueIdentifier>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="ubidi.c">

+      <Filter>bidi</Filter>

+    </ClCompile>

+    <ClCompile Include="ubidi_props.c">

+      <Filter>bidi</Filter>

+    </ClCompile>

+    <ClCompile Include="ubidiln.c">

+      <Filter>bidi</Filter>

+    </ClCompile>

+    <ClCompile Include="ubidiwrt.c">

+      <Filter>bidi</Filter>

+    </ClCompile>

+    <ClCompile Include="ushape.c">

+      <Filter>bidi</Filter>

+    </ClCompile>

+    <ClCompile Include="brkeng.cpp">

+      <Filter>break iteration</Filter>

+    </ClCompile>

+    <ClCompile Include="brkiter.cpp">

+      <Filter>break iteration</Filter>

+    </ClCompile>

+    <ClCompile Include="dictbe.cpp">

+      <Filter>break iteration</Filter>

+    </ClCompile>

+    <ClCompile Include="rbbi.cpp">

+      <Filter>break iteration</Filter>

+    </ClCompile>

+    <ClCompile Include="rbbidata.cpp">

+      <Filter>break iteration</Filter>

+    </ClCompile>

+    <ClCompile Include="rbbinode.cpp">

+      <Filter>break iteration</Filter>

+    </ClCompile>

+    <ClCompile Include="rbbirb.cpp">

+      <Filter>break iteration</Filter>

+    </ClCompile>

+    <ClCompile Include="rbbiscan.cpp">

+      <Filter>break iteration</Filter>

+    </ClCompile>

+    <ClCompile Include="rbbisetb.cpp">

+      <Filter>break iteration</Filter>

+    </ClCompile>

+    <ClCompile Include="rbbistbl.cpp">

+      <Filter>break iteration</Filter>

+    </ClCompile>

+    <ClCompile Include="rbbitblb.cpp">

+      <Filter>break iteration</Filter>

+    </ClCompile>

+    <ClCompile Include="triedict.cpp">

+      <Filter>break iteration</Filter>

+    </ClCompile>

+    <ClCompile Include="ubrk.cpp">

+      <Filter>break iteration</Filter>

+    </ClCompile>

+    <ClCompile Include="ucol_swp.cpp">

+      <Filter>collation</Filter>

+    </ClCompile>

+    <ClCompile Include="propsvec.c">

+      <Filter>collections</Filter>

+    </ClCompile>

+    <ClCompile Include="uarrsort.c">

+      <Filter>collections</Filter>

+    </ClCompile>

+    <ClCompile Include="uenum.c">

+      <Filter>collections</Filter>

+    </ClCompile>

+    <ClCompile Include="uhash.c">

+      <Filter>collections</Filter>

+    </ClCompile>

+    <ClCompile Include="uhash_us.cpp">

+      <Filter>collections</Filter>

+    </ClCompile>

+    <ClCompile Include="ulist.c">

+      <Filter>collections</Filter>

+    </ClCompile>

+    <ClCompile Include="ustack.cpp">

+      <Filter>collections</Filter>

+    </ClCompile>

+    <ClCompile Include="ustrenum.cpp">

+      <Filter>collections</Filter>

+    </ClCompile>

+    <ClCompile Include="utrie.c">

+      <Filter>collections</Filter>

+    </ClCompile>

+    <ClCompile Include="utrie2.cpp">

+      <Filter>collections</Filter>

+    </ClCompile>

+    <ClCompile Include="utrie2_builder.c">

+      <Filter>collections</Filter>

+    </ClCompile>

+    <ClCompile Include="uvector.cpp">

+      <Filter>collections</Filter>

+    </ClCompile>

+    <ClCompile Include="uvectr32.cpp">

+      <Filter>collections</Filter>

+    </ClCompile>

+    <ClCompile Include="uvectr64.cpp">

+      <Filter>collections</Filter>

+    </ClCompile>

+    <ClCompile Include="errorcode.cpp">

+      <Filter>configuration</Filter>

+    </ClCompile>

+    <ClCompile Include="icudataver.c">

+      <Filter>configuration</Filter>

+    </ClCompile>

+    <ClCompile Include="locmap.c">

+      <Filter>configuration</Filter>

+    </ClCompile>

+    <ClCompile Include="mutex.cpp">

+      <Filter>configuration</Filter>

+    </ClCompile>

+    <ClCompile Include="putil.c">

+      <Filter>configuration</Filter>

+    </ClCompile>

+    <ClCompile Include="umath.c">

+      <Filter>configuration</Filter>

+    </ClCompile>

+    <ClCompile Include="umutex.c">

+      <Filter>configuration</Filter>

+    </ClCompile>

+    <ClCompile Include="utrace.c">

+      <Filter>configuration</Filter>

+    </ClCompile>

+    <ClCompile Include="utypes.c">

+      <Filter>configuration</Filter>

+    </ClCompile>

+    <ClCompile Include="wintz.c">

+      <Filter>configuration</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnv.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnv2022.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnv_bld.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnv_cb.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnv_cnv.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnv_err.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnv_ext.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnv_io.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnv_lmb.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnv_set.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnv_u16.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnv_u32.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnv_u7.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnv_u8.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnvbocu.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnvdisp.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnvhz.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnvisci.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnvlat1.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnvmbcs.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnvscsu.c">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="ucnvsel.cpp">

+      <Filter>conversion</Filter>

+    </ClCompile>

+    <ClCompile Include="cmemory.c">

+      <Filter>data &amp; memory</Filter>

+    </ClCompile>

+    <ClCompile Include="ucln_cmn.c">

+      <Filter>data &amp; memory</Filter>

+    </ClCompile>

+    <ClCompile Include="ucmndata.c">

+      <Filter>data &amp; memory</Filter>

+    </ClCompile>

+    <ClCompile Include="udata.cpp">

+      <Filter>data &amp; memory</Filter>

+    </ClCompile>

+    <ClCompile Include="udatamem.c">

+      <Filter>data &amp; memory</Filter>

+    </ClCompile>

+    <ClCompile Include="udataswp.c">

+      <Filter>data &amp; memory</Filter>

+    </ClCompile>

+    <ClCompile Include="uinit.c">

+      <Filter>data &amp; memory</Filter>

+    </ClCompile>

+    <ClCompile Include="umapfile.c">

+      <Filter>data &amp; memory</Filter>

+    </ClCompile>

+    <ClCompile Include="uobject.cpp">

+      <Filter>data &amp; memory</Filter>

+    </ClCompile>

+    <ClCompile Include="dtintrv.cpp">

+      <Filter>formatting</Filter>

+    </ClCompile>

+    <ClCompile Include="parsepos.cpp">

+      <Filter>formatting</Filter>

+    </ClCompile>

+    <ClCompile Include="ustrfmt.c">

+      <Filter>formatting</Filter>

+    </ClCompile>

+    <ClCompile Include="util.cpp">

+      <Filter>formatting</Filter>

+    </ClCompile>

+    <ClCompile Include="util_props.cpp">

+      <Filter>formatting</Filter>

+    </ClCompile>

+    <ClCompile Include="punycode.c">

+      <Filter>idna</Filter>

+    </ClCompile>

+    <ClCompile Include="uidna.cpp">

+      <Filter>idna</Filter>

+    </ClCompile>

+    <ClCompile Include="uts46.cpp">

+      <Filter>idna</Filter>

+    </ClCompile>

+    <ClCompile Include="locavailable.cpp">

+      <Filter>locales &amp; resources</Filter>

+    </ClCompile>

+    <ClCompile Include="locbased.cpp">

+      <Filter>locales &amp; resources</Filter>

+    </ClCompile>

+    <ClCompile Include="locdispnames.cpp">

+      <Filter>locales &amp; resources</Filter>

+    </ClCompile>

+    <ClCompile Include="locid.cpp">

+      <Filter>locales &amp; resources</Filter>

+    </ClCompile>

+    <ClCompile Include="loclikely.cpp">

+      <Filter>locales &amp; resources</Filter>

+    </ClCompile>

+    <ClCompile Include="locresdata.cpp">

+      <Filter>locales &amp; resources</Filter>

+    </ClCompile>

+    <ClCompile Include="locutil.cpp">

+      <Filter>locales &amp; resources</Filter>

+    </ClCompile>

+    <ClCompile Include="resbund.cpp">

+      <Filter>locales &amp; resources</Filter>

+    </ClCompile>

+    <ClCompile Include="resbund_cnv.cpp">

+      <Filter>locales &amp; resources</Filter>

+    </ClCompile>

+    <ClCompile Include="ucat.c">

+      <Filter>locales &amp; resources</Filter>

+    </ClCompile>

+    <ClCompile Include="uloc.c">

+      <Filter>locales &amp; resources</Filter>

+    </ClCompile>

+    <ClCompile Include="uloc_tag.c">

+      <Filter>locales &amp; resources</Filter>

+    </ClCompile>

+    <ClCompile Include="ures_cnv.c">

+      <Filter>locales &amp; resources</Filter>

+    </ClCompile>

+    <ClCompile Include="uresbund.c">

+      <Filter>locales &amp; resources</Filter>

+    </ClCompile>

+    <ClCompile Include="uresdata.c">

+      <Filter>locales &amp; resources</Filter>

+    </ClCompile>

+    <ClCompile Include="caniter.cpp">

+      <Filter>normalization</Filter>

+    </ClCompile>

+    <ClCompile Include="filterednormalizer2.cpp">

+      <Filter>normalization</Filter>

+    </ClCompile>

+    <ClCompile Include="normalizer2.cpp">

+      <Filter>normalization</Filter>

+    </ClCompile>

+    <ClCompile Include="normalizer2impl.cpp">

+      <Filter>normalization</Filter>

+    </ClCompile>

+    <ClCompile Include="normlzr.cpp">

+      <Filter>normalization</Filter>

+    </ClCompile>

+    <ClCompile Include="unorm.cpp">

+      <Filter>normalization</Filter>

+    </ClCompile>

+    <ClCompile Include="unorm_it.c">

+      <Filter>normalization</Filter>

+    </ClCompile>

+    <ClCompile Include="unormcmp.cpp">

+      <Filter>normalization</Filter>

+    </ClCompile>

+    <ClCompile Include="bmpset.cpp">

+      <Filter>properties &amp; sets</Filter>

+    </ClCompile>

+    <ClCompile Include="propname.cpp">

+      <Filter>properties &amp; sets</Filter>

+    </ClCompile>

+    <ClCompile Include="ruleiter.cpp">

+      <Filter>properties &amp; sets</Filter>

+    </ClCompile>

+    <ClCompile Include="ucase.c">

+      <Filter>properties &amp; sets</Filter>

+    </ClCompile>

+    <ClCompile Include="uchar.c">

+      <Filter>properties &amp; sets</Filter>

+    </ClCompile>

+    <ClCompile Include="unames.c">

+      <Filter>properties &amp; sets</Filter>

+    </ClCompile>

+    <ClCompile Include="unifilt.cpp">

+      <Filter>properties &amp; sets</Filter>

+    </ClCompile>

+    <ClCompile Include="unifunct.cpp">

+      <Filter>properties &amp; sets</Filter>

+    </ClCompile>

+    <ClCompile Include="uniset.cpp">

+      <Filter>properties &amp; sets</Filter>

+    </ClCompile>

+    <ClCompile Include="uniset_props.cpp">

+      <Filter>properties &amp; sets</Filter>

+    </ClCompile>

+    <ClCompile Include="unisetspan.cpp">

+      <Filter>properties &amp; sets</Filter>

+    </ClCompile>

+    <ClCompile Include="uprops.cpp">

+      <Filter>properties &amp; sets</Filter>

+    </ClCompile>

+    <ClCompile Include="usc_impl.c">

+      <Filter>properties &amp; sets</Filter>

+    </ClCompile>

+    <ClCompile Include="uscript.c">

+      <Filter>properties &amp; sets</Filter>

+    </ClCompile>

+    <ClCompile Include="uset.cpp">

+      <Filter>properties &amp; sets</Filter>

+    </ClCompile>

+    <ClCompile Include="uset_props.cpp">

+      <Filter>properties &amp; sets</Filter>

+    </ClCompile>

+    <ClCompile Include="usetiter.cpp">

+      <Filter>properties &amp; sets</Filter>

+    </ClCompile>

+    <ClCompile Include="icuplug.c">

+      <Filter>registration</Filter>

+    </ClCompile>

+    <ClCompile Include="serv.cpp">

+      <Filter>registration</Filter>

+    </ClCompile>

+    <ClCompile Include="servlk.cpp">

+      <Filter>registration</Filter>

+    </ClCompile>

+    <ClCompile Include="servlkf.cpp">

+      <Filter>registration</Filter>

+    </ClCompile>

+    <ClCompile Include="servls.cpp">

+      <Filter>registration</Filter>

+    </ClCompile>

+    <ClCompile Include="servnotf.cpp">

+      <Filter>registration</Filter>

+    </ClCompile>

+    <ClCompile Include="servrbf.cpp">

+      <Filter>registration</Filter>

+    </ClCompile>

+    <ClCompile Include="servslkf.cpp">

+      <Filter>registration</Filter>

+    </ClCompile>

+    <ClCompile Include="usprep.cpp">

+      <Filter>sprep</Filter>

+    </ClCompile>

+    <ClCompile Include="bytestream.cpp">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="chariter.cpp">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="charstr.cpp">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="cstring.c">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="cwchar.c">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="schriter.cpp">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="stringpiece.cpp">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="ucasemap.c">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="uchriter.cpp">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="uinvchar.c">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="uiter.cpp">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="unistr.cpp">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="unistr_case.cpp">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="unistr_cnv.cpp">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="unistr_props.cpp">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="ustr_cnv.c">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="ustr_wcs.c">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="ustrcase.c">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="ustring.c">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="ustrtrns.c">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="utext.cpp">

+      <Filter>strings</Filter>

+    </ClCompile>

+    <ClCompile Include="utf_impl.c">

+      <Filter>strings</Filter>

+    </ClCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="ubidi_props.h">

+      <Filter>bidi</Filter>

+    </ClInclude>

+    <ClInclude Include="ubidiimp.h">

+      <Filter>bidi</Filter>

+    </ClInclude>

+    <ClInclude Include="brkeng.h">

+      <Filter>break iteration</Filter>

+    </ClInclude>

+    <ClInclude Include="dictbe.h">

+      <Filter>break iteration</Filter>

+    </ClInclude>

+    <ClInclude Include="rbbidata.h">

+      <Filter>break iteration</Filter>

+    </ClInclude>

+    <ClInclude Include="rbbinode.h">

+      <Filter>break iteration</Filter>

+    </ClInclude>

+    <ClInclude Include="rbbirb.h">

+      <Filter>break iteration</Filter>

+    </ClInclude>

+    <ClInclude Include="rbbirpt.h">

+      <Filter>break iteration</Filter>

+    </ClInclude>

+    <ClInclude Include="rbbiscan.h">

+      <Filter>break iteration</Filter>

+    </ClInclude>

+    <ClInclude Include="rbbisetb.h">

+      <Filter>break iteration</Filter>

+    </ClInclude>

+    <ClInclude Include="rbbitblb.h">

+      <Filter>break iteration</Filter>

+    </ClInclude>

+    <ClInclude Include="triedict.h">

+      <Filter>break iteration</Filter>

+    </ClInclude>

+    <ClInclude Include="ubrkimpl.h">

+      <Filter>break iteration</Filter>

+    </ClInclude>

+    <ClInclude Include="ucol_swp.h">

+      <Filter>collation</Filter>

+    </ClInclude>

+    <ClInclude Include="hash.h">

+      <Filter>collections</Filter>

+    </ClInclude>

+    <ClInclude Include="propsvec.h">

+      <Filter>collections</Filter>

+    </ClInclude>

+    <ClInclude Include="uarrsort.h">

+      <Filter>collections</Filter>

+    </ClInclude>

+    <ClInclude Include="uenumimp.h">

+      <Filter>collections</Filter>

+    </ClInclude>

+    <ClInclude Include="uhash.h">

+      <Filter>collections</Filter>

+    </ClInclude>

+    <ClInclude Include="ulist.h">

+      <Filter>collections</Filter>

+    </ClInclude>

+    <ClInclude Include="ustrenum.h">

+      <Filter>collections</Filter>

+    </ClInclude>

+    <ClInclude Include="utrie.h">

+      <Filter>collections</Filter>

+    </ClInclude>

+    <ClInclude Include="utrie2.h">

+      <Filter>collections</Filter>

+    </ClInclude>

+    <ClInclude Include="utrie2_impl.h">

+      <Filter>collections</Filter>

+    </ClInclude>

+    <ClInclude Include="uvector.h">

+      <Filter>collections</Filter>

+    </ClInclude>

+    <ClInclude Include="uvectr32.h">

+      <Filter>collections</Filter>

+    </ClInclude>

+    <ClInclude Include="uvectr64.h">

+      <Filter>collections</Filter>

+    </ClInclude>

+    <ClInclude Include="cpputils.h">

+      <Filter>configuration</Filter>

+    </ClInclude>

+    <ClInclude Include="locmap.h">

+      <Filter>configuration</Filter>

+    </ClInclude>

+    <ClInclude Include="mutex.h">

+      <Filter>configuration</Filter>

+    </ClInclude>

+    <ClInclude Include="putilimp.h">

+      <Filter>configuration</Filter>

+    </ClInclude>

+    <ClInclude Include="uassert.h">

+      <Filter>configuration</Filter>

+    </ClInclude>

+    <ClInclude Include="umutex.h">

+      <Filter>configuration</Filter>

+    </ClInclude>

+    <ClInclude Include="utracimp.h">

+      <Filter>configuration</Filter>

+    </ClInclude>

+    <ClInclude Include="wintz.h">

+      <Filter>configuration</Filter>

+    </ClInclude>

+    <ClInclude Include="ucnv_bld.h">

+      <Filter>conversion</Filter>

+    </ClInclude>

+    <ClInclude Include="ucnv_cnv.h">

+      <Filter>conversion</Filter>

+    </ClInclude>

+    <ClInclude Include="ucnv_ext.h">

+      <Filter>conversion</Filter>

+    </ClInclude>

+    <ClInclude Include="ucnv_imp.h">

+      <Filter>conversion</Filter>

+    </ClInclude>

+    <ClInclude Include="ucnv_io.h">

+      <Filter>conversion</Filter>

+    </ClInclude>

+    <ClInclude Include="ucnvmbcs.h">

+      <Filter>conversion</Filter>

+    </ClInclude>

+    <ClInclude Include="cmemory.h">

+      <Filter>data &amp; memory</Filter>

+    </ClInclude>

+    <ClInclude Include="ucln.h">

+      <Filter>data &amp; memory</Filter>

+    </ClInclude>

+    <ClInclude Include="ucln_cmn.h">

+      <Filter>data &amp; memory</Filter>

+    </ClInclude>

+    <ClInclude Include="ucln_imp.h">

+      <Filter>data &amp; memory</Filter>

+    </ClInclude>

+    <ClInclude Include="ucmndata.h">

+      <Filter>data &amp; memory</Filter>

+    </ClInclude>

+    <ClInclude Include="udatamem.h">

+      <Filter>data &amp; memory</Filter>

+    </ClInclude>

+    <ClInclude Include="udataswp.h">

+      <Filter>data &amp; memory</Filter>

+    </ClInclude>

+    <ClInclude Include="umapfile.h">

+      <Filter>data &amp; memory</Filter>

+    </ClInclude>

+    <ClInclude Include="ustrfmt.h">

+      <Filter>formatting</Filter>

+    </ClInclude>

+    <ClInclude Include="util.h">

+      <Filter>formatting</Filter>

+    </ClInclude>

+    <ClInclude Include="punycode.h">

+      <Filter>idna</Filter>

+    </ClInclude>

+    <ClInclude Include="locbased.h">

+      <Filter>locales &amp; resources</Filter>

+    </ClInclude>

+    <ClInclude Include="locutil.h">

+      <Filter>locales &amp; resources</Filter>

+    </ClInclude>

+    <ClInclude Include="ulocimp.h">

+      <Filter>locales &amp; resources</Filter>

+    </ClInclude>

+    <ClInclude Include="uresdata.h">

+      <Filter>locales &amp; resources</Filter>

+    </ClInclude>

+    <ClInclude Include="uresimp.h">

+      <Filter>locales &amp; resources</Filter>

+    </ClInclude>

+    <ClInclude Include="ureslocs.h">

+      <Filter>locales &amp; resources</Filter>

+    </ClInclude>

+    <ClInclude Include="normalizer2impl.h">

+      <Filter>normalization</Filter>

+    </ClInclude>

+    <ClInclude Include="unorm_it.h">

+      <Filter>normalization</Filter>

+    </ClInclude>

+    <ClInclude Include="unormimp.h">

+      <Filter>normalization</Filter>

+    </ClInclude>

+    <ClInclude Include="bmpset.h">

+      <Filter>properties &amp; sets</Filter>

+    </ClInclude>

+    <ClInclude Include="propname.h">

+      <Filter>properties &amp; sets</Filter>

+    </ClInclude>

+    <ClInclude Include="ruleiter.h">

+      <Filter>properties &amp; sets</Filter>

+    </ClInclude>

+    <ClInclude Include="ucase.h">

+      <Filter>properties &amp; sets</Filter>

+    </ClInclude>

+    <ClInclude Include="unisetspan.h">

+      <Filter>properties &amp; sets</Filter>

+    </ClInclude>

+    <ClInclude Include="uprops.h">

+      <Filter>properties &amp; sets</Filter>

+    </ClInclude>

+    <ClInclude Include="usc_impl.h">

+      <Filter>properties &amp; sets</Filter>

+    </ClInclude>

+    <ClInclude Include="uset_imp.h">

+      <Filter>properties &amp; sets</Filter>

+    </ClInclude>

+    <ClInclude Include="unicode\icuplug.h">

+      <Filter>registration</Filter>

+    </ClInclude>

+    <ClInclude Include="icuplugimp.h">

+      <Filter>registration</Filter>

+    </ClInclude>

+    <ClInclude Include="serv.h">

+      <Filter>registration</Filter>

+    </ClInclude>

+    <ClInclude Include="servloc.h">

+      <Filter>registration</Filter>

+    </ClInclude>

+    <ClInclude Include="servnotf.h">

+      <Filter>registration</Filter>

+    </ClInclude>

+    <ClInclude Include="sprpimpl.h">

+      <Filter>sprep</Filter>

+    </ClInclude>

+    <ClInclude Include="charstr.h">

+      <Filter>strings</Filter>

+    </ClInclude>

+    <ClInclude Include="cstring.h">

+      <Filter>strings</Filter>

+    </ClInclude>

+    <ClInclude Include="cwchar.h">

+      <Filter>strings</Filter>

+    </ClInclude>

+    <ClInclude Include="uinvchar.h">

+      <Filter>strings</Filter>

+    </ClInclude>

+    <ClInclude Include="ustr_cnv.h">

+      <Filter>strings</Filter>

+    </ClInclude>

+    <ClInclude Include="ustr_imp.h">

+      <Filter>strings</Filter>

+    </ClInclude>

+  </ItemGroup>

+  <ItemGroup>

+    <ResourceCompile Include="common.rc">

+      <Filter>configuration</Filter>

+    </ResourceCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <CustomBuild Include="unicode\ubidi.h">

+      <Filter>bidi</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\ushape.h">

+      <Filter>bidi</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\brkiter.h">

+      <Filter>break iteration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\dbbi.h">

+      <Filter>break iteration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\rbbi.h">

+      <Filter>break iteration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\ubrk.h">

+      <Filter>break iteration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\strenum.h">

+      <Filter>collections</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\uenum.h">

+      <Filter>collections</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\docmain.h">

+      <Filter>configuration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\errorcode.h">

+      <Filter>configuration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\icudataver.h">

+      <Filter>configuration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\putil.h">

+      <Filter>configuration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\pwin32.h">

+      <Filter>configuration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\std_string.h">

+      <Filter>configuration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\uconfig.h">

+      <Filter>configuration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\udeprctd.h">

+      <Filter>configuration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\udraft.h">

+      <Filter>configuration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\uintrnal.h">

+      <Filter>configuration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\umachine.h">

+      <Filter>configuration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\uobslete.h">

+      <Filter>configuration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\urename.h">

+      <Filter>configuration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\usystem.h">

+      <Filter>configuration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\utrace.h">

+      <Filter>configuration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\utypes.h">

+      <Filter>configuration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\uvernum.h">

+      <Filter>configuration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\uversion.h">

+      <Filter>configuration</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\ucnv.h">

+      <Filter>conversion</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\ucnv_cb.h">

+      <Filter>conversion</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\ucnv_err.h">

+      <Filter>conversion</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\ucnvsel.h">

+      <Filter>conversion</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\localpointer.h">

+      <Filter>data &amp; memory</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\uclean.h">

+      <Filter>data &amp; memory</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\udata.h">

+      <Filter>data &amp; memory</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\uobject.h">

+      <Filter>data &amp; memory</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\dtintrv.h">

+      <Filter>formatting</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\parseerr.h">

+      <Filter>formatting</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\parsepos.h">

+      <Filter>formatting</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\umisc.h">

+      <Filter>formatting</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\idna.h">

+      <Filter>idna</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\uidna.h">

+      <Filter>idna</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\locid.h">

+      <Filter>locales &amp; resources</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\resbund.h">

+      <Filter>locales &amp; resources</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\ucat.h">

+      <Filter>locales &amp; resources</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\uloc.h">

+      <Filter>locales &amp; resources</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\ures.h">

+      <Filter>locales &amp; resources</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\caniter.h">

+      <Filter>normalization</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\normalizer2.h">

+      <Filter>normalization</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\normlzr.h">

+      <Filter>normalization</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\unorm.h">

+      <Filter>normalization</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\unorm2.h">

+      <Filter>normalization</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\symtable.h">

+      <Filter>properties &amp; sets</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\uchar.h">

+      <Filter>properties &amp; sets</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\unifilt.h">

+      <Filter>properties &amp; sets</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\unifunct.h">

+      <Filter>properties &amp; sets</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\unimatch.h">

+      <Filter>properties &amp; sets</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\uniset.h">

+      <Filter>properties &amp; sets</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\uscript.h">

+      <Filter>properties &amp; sets</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\uset.h">

+      <Filter>properties &amp; sets</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\usetiter.h">

+      <Filter>properties &amp; sets</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\usprep.h">

+      <Filter>sprep</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\bytestream.h">

+      <Filter>strings</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\chariter.h">

+      <Filter>strings</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\rep.h">

+      <Filter>strings</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\schriter.h">

+      <Filter>strings</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\stringpiece.h">

+      <Filter>strings</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\ucasemap.h">

+      <Filter>strings</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\uchriter.h">

+      <Filter>strings</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\uiter.h">

+      <Filter>strings</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\unistr.h">

+      <Filter>strings</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\urep.h">

+      <Filter>strings</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\ustring.h">

+      <Filter>strings</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\utext.h">

+      <Filter>strings</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\utf.h">

+      <Filter>strings</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\utf16.h">

+      <Filter>strings</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\utf32.h">

+      <Filter>strings</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\utf8.h">

+      <Filter>strings</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\utf_old.h">

+      <Filter>strings</Filter>

+    </CustomBuild>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/source/common/cpputils.h b/source/common/cpputils.h
new file mode 100644
index 0000000..e423900
--- /dev/null
+++ b/source/common/cpputils.h
@@ -0,0 +1,95 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  cpputils.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*/
+
+#ifndef CPPUTILS_H
+#define CPPUTILS_H
+
+#include "unicode/utypes.h"
+#include "unicode/unistr.h"
+#include "cmemory.h"
+
+/*==========================================================================*/
+/* Array copy utility functions */
+/*==========================================================================*/
+
+static
+inline void uprv_arrayCopy(const double* src, double* dst, int32_t count)
+{ uprv_memcpy(dst, src, (size_t)(count * sizeof(*src))); }
+
+static
+inline void uprv_arrayCopy(const double* src, int32_t srcStart,
+              double* dst, int32_t dstStart, int32_t count)
+{ uprv_memcpy(dst+dstStart, src+srcStart, (size_t)(count * sizeof(*src))); }
+
+static
+inline void uprv_arrayCopy(const int8_t* src, int8_t* dst, int32_t count)
+    { uprv_memcpy(dst, src, (size_t)(count * sizeof(*src))); }
+
+static
+inline void uprv_arrayCopy(const int8_t* src, int32_t srcStart,
+              int8_t* dst, int32_t dstStart, int32_t count)
+{ uprv_memcpy(dst+dstStart, src+srcStart, (size_t)(count * sizeof(*src))); }
+
+static
+inline void uprv_arrayCopy(const int16_t* src, int16_t* dst, int32_t count)
+{ uprv_memcpy(dst, src, (size_t)(count * sizeof(*src))); }
+
+static
+inline void uprv_arrayCopy(const int16_t* src, int32_t srcStart,
+              int16_t* dst, int32_t dstStart, int32_t count)
+{ uprv_memcpy(dst+dstStart, src+srcStart, (size_t)(count * sizeof(*src))); }
+
+static
+inline void uprv_arrayCopy(const int32_t* src, int32_t* dst, int32_t count)
+{ uprv_memcpy(dst, src, (size_t)(count * sizeof(*src))); }
+
+static
+inline void uprv_arrayCopy(const int32_t* src, int32_t srcStart,
+              int32_t* dst, int32_t dstStart, int32_t count)
+{ uprv_memcpy(dst+dstStart, src+srcStart, (size_t)(count * sizeof(*src))); }
+
+static
+inline void
+uprv_arrayCopy(const UChar *src, int32_t srcStart,
+        UChar *dst, int32_t dstStart, int32_t count)
+{ uprv_memcpy(dst+dstStart, src+srcStart, (size_t)(count * sizeof(*src))); }
+
+/**
+ * Copy an array of UnicodeString OBJECTS (not pointers).
+ * @internal
+ */
+static inline void
+uprv_arrayCopy(const U_NAMESPACE_QUALIFIER UnicodeString *src, U_NAMESPACE_QUALIFIER UnicodeString *dst, int32_t count)
+{ while(count-- > 0) *dst++ = *src++; }
+
+/**
+ * Copy an array of UnicodeString OBJECTS (not pointers).
+ * @internal
+ */
+static inline void
+uprv_arrayCopy(const U_NAMESPACE_QUALIFIER UnicodeString *src, int32_t srcStart,
+        U_NAMESPACE_QUALIFIER UnicodeString *dst, int32_t dstStart, int32_t count)
+{ uprv_arrayCopy(src+srcStart, dst+dstStart, count); }
+
+/**
+ * Checks that the string is readable and writable.
+ * Sets U_ILLEGAL_ARGUMENT_ERROR if the string isBogus() or has an open getBuffer().
+ */
+inline void
+uprv_checkCanGetBuffer(const U_NAMESPACE_QUALIFIER UnicodeString &s, UErrorCode &errorCode) {
+    if(U_SUCCESS(errorCode) && s.isBogus()) {
+        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+    }
+}
+
+#endif /* _CPPUTILS */
diff --git a/source/common/cstring.c b/source/common/cstring.c
new file mode 100644
index 0000000..a5b2c6b
--- /dev/null
+++ b/source/common/cstring.c
@@ -0,0 +1,328 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1997-2003, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File CSTRING.C
+*
+* @author       Helena Shih
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   6/18/98     hshih       Created
+*   09/08/98    stephen     Added include for ctype, for Mac Port
+*   11/15/99    helena      Integrated S/390 IEEE changes. 
+******************************************************************************
+*/
+
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "unicode/utypes.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uassert.h"
+
+/*
+ * We hardcode case conversion for invariant characters to match our expectation
+ * and the compiler execution charset.
+ * This prevents problems on systems
+ * - with non-default casing behavior, like Turkish system locales where
+ *   tolower('I') maps to dotless i and toupper('i') maps to dotted I
+ * - where there are no lowercase Latin characters at all, or using different
+ *   codes (some old EBCDIC codepages)
+ *
+ * This works because the compiler usually runs on a platform where the execution
+ * charset includes all of the invariant characters at their expected
+ * code positions, so that the char * string literals in ICU code match
+ * the char literals here.
+ *
+ * Note that the set of lowercase Latin letters is discontiguous in EBCDIC
+ * and the set of uppercase Latin letters is discontiguous as well.
+ */
+
+U_CAPI char U_EXPORT2
+uprv_toupper(char c) {
+#if U_CHARSET_FAMILY==U_EBCDIC_FAMILY
+    if(('a'<=c && c<='i') || ('j'<=c && c<='r') || ('s'<=c && c<='z')) {
+        c=(char)(c+('A'-'a'));
+    }
+#else
+    if('a'<=c && c<='z') {
+        c=(char)(c+('A'-'a'));
+    }
+#endif
+    return c;
+}
+
+
+#if 0
+/*
+ * Commented out because cstring.h defines uprv_tolower() to be
+ * the same as either uprv_asciitolower() or uprv_ebcdictolower()
+ * to reduce the amount of code to cover with tests.
+ *
+ * Note that this uprv_tolower() definition is likely to work for most
+ * charset families, not just ASCII and EBCDIC, because its #else branch
+ * is written generically.
+ */
+U_CAPI char U_EXPORT2
+uprv_tolower(char c) {
+#if U_CHARSET_FAMILY==U_EBCDIC_FAMILY
+    if(('A'<=c && c<='I') || ('J'<=c && c<='R') || ('S'<=c && c<='Z')) {
+        c=(char)(c+('a'-'A'));
+    }
+#else
+    if('A'<=c && c<='Z') {
+        c=(char)(c+('a'-'A'));
+    }
+#endif
+    return c;
+}
+#endif
+
+U_CAPI char U_EXPORT2
+uprv_asciitolower(char c) {
+    if(0x41<=c && c<=0x5a) {
+        c=(char)(c+0x20);
+    }
+    return c;
+}
+
+U_CAPI char U_EXPORT2
+uprv_ebcdictolower(char c) {
+    if( (0xc1<=(uint8_t)c && (uint8_t)c<=0xc9) ||
+        (0xd1<=(uint8_t)c && (uint8_t)c<=0xd9) ||
+        (0xe2<=(uint8_t)c && (uint8_t)c<=0xe9)
+    ) {
+        c=(char)(c-0x40);
+    }
+    return c;
+}
+
+
+U_CAPI char* U_EXPORT2
+T_CString_toLowerCase(char* str)
+{
+    char* origPtr = str;
+
+    if (str) {
+        do
+            *str = (char)uprv_tolower(*str);
+        while (*(str++));
+    }
+
+    return origPtr;
+}
+
+U_CAPI char* U_EXPORT2
+T_CString_toUpperCase(char* str)
+{
+    char* origPtr = str;
+
+    if (str) {
+        do
+            *str = (char)uprv_toupper(*str);
+        while (*(str++));
+    }
+
+    return origPtr;
+}
+
+/*
+ * Takes a int32_t and fills in  a char* string with that number "radix"-based.
+ * Does not handle negative values (makes an empty string for them).
+ * Writes at most 12 chars ("-2147483647" plus NUL).
+ * Returns the length of the string (not including the NUL).
+ */
+U_CAPI int32_t U_EXPORT2
+T_CString_integerToString(char* buffer, int32_t v, int32_t radix)
+{
+    char      tbuf[30];
+    int32_t   tbx    = sizeof(tbuf);
+    uint8_t   digit;
+    int32_t   length = 0;
+    uint32_t  uval;
+    
+    U_ASSERT(radix>=2 && radix<=16);
+    uval = (uint32_t) v;
+    if(v<0 && radix == 10) {
+        /* Only in base 10 do we conside numbers to be signed. */
+        uval = (uint32_t)(-v); 
+        buffer[length++] = '-';
+    }
+    
+    tbx = sizeof(tbuf)-1;
+    tbuf[tbx] = 0;   /* We are generating the digits backwards.  Null term the end. */
+    do {
+        digit = (uint8_t)(uval % radix);
+        tbuf[--tbx] = (char)(T_CString_itosOffset(digit));
+        uval  = uval / radix;
+    } while (uval != 0);
+    
+    /* copy converted number into user buffer  */
+    uprv_strcpy(buffer+length, tbuf+tbx);
+    length += sizeof(tbuf) - tbx -1;
+    return length;
+}
+
+
+
+/*
+ * Takes a int64_t and fills in  a char* string with that number "radix"-based.
+ * Writes at most 21: chars ("-9223372036854775807" plus NUL).
+ * Returns the length of the string, not including the terminating NULL.
+ */
+U_CAPI int32_t U_EXPORT2
+T_CString_int64ToString(char* buffer, int64_t v, uint32_t radix)
+{
+    char      tbuf[30];
+    int32_t   tbx    = sizeof(tbuf);
+    uint8_t   digit;
+    int32_t   length = 0;
+    uint64_t  uval;
+    
+    U_ASSERT(radix>=2 && radix<=16);
+    uval = (uint64_t) v;
+    if(v<0 && radix == 10) {
+        /* Only in base 10 do we conside numbers to be signed. */
+        uval = (uint64_t)(-v); 
+        buffer[length++] = '-';
+    }
+    
+    tbx = sizeof(tbuf)-1;
+    tbuf[tbx] = 0;   /* We are generating the digits backwards.  Null term the end. */
+    do {
+        digit = (uint8_t)(uval % radix);
+        tbuf[--tbx] = (char)(T_CString_itosOffset(digit));
+        uval  = uval / radix;
+    } while (uval != 0);
+    
+    /* copy converted number into user buffer  */
+    uprv_strcpy(buffer+length, tbuf+tbx);
+    length += sizeof(tbuf) - tbx -1;
+    return length;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+T_CString_stringToInteger(const char *integerString, int32_t radix)
+{
+    char *end;
+    return uprv_strtoul(integerString, &end, radix);
+
+}
+    
+U_CAPI int U_EXPORT2
+T_CString_stricmp(const char *str1, const char *str2) {
+    if(str1==NULL) {
+        if(str2==NULL) {
+            return 0;
+        } else {
+            return -1;
+        }
+    } else if(str2==NULL) {
+        return 1;
+    } else {
+        /* compare non-NULL strings lexically with lowercase */
+        int rc;
+        unsigned char c1, c2;
+
+        for(;;) {
+            c1=(unsigned char)*str1;
+            c2=(unsigned char)*str2;
+            if(c1==0) {
+                if(c2==0) {
+                    return 0;
+                } else {
+                    return -1;
+                }
+            } else if(c2==0) {
+                return 1;
+            } else {
+                /* compare non-zero characters with lowercase */
+                rc=(int)(unsigned char)uprv_tolower(c1)-(int)(unsigned char)uprv_tolower(c2);
+                if(rc!=0) {
+                    return rc;
+                }
+            }
+            ++str1;
+            ++str2;
+        }
+    }
+}
+
+U_CAPI int U_EXPORT2
+T_CString_strnicmp(const char *str1, const char *str2, uint32_t n) {
+    if(str1==NULL) {
+        if(str2==NULL) {
+            return 0;
+        } else {
+            return -1;
+        }
+    } else if(str2==NULL) {
+        return 1;
+    } else {
+        /* compare non-NULL strings lexically with lowercase */
+        int rc;
+        unsigned char c1, c2;
+
+        for(; n--;) {
+            c1=(unsigned char)*str1;
+            c2=(unsigned char)*str2;
+            if(c1==0) {
+                if(c2==0) {
+                    return 0;
+                } else {
+                    return -1;
+                }
+            } else if(c2==0) {
+                return 1;
+            } else {
+                /* compare non-zero characters with lowercase */
+                rc=(int)(unsigned char)uprv_tolower(c1)-(int)(unsigned char)uprv_tolower(c2);
+                if(rc!=0) {
+                    return rc;
+                }
+            }
+            ++str1;
+            ++str2;
+        }
+    }
+
+    return 0;
+}
+
+U_CAPI char* U_EXPORT2
+uprv_strdup(const char *src) {
+    size_t len = uprv_strlen(src) + 1;
+    char *dup = (char *) uprv_malloc(len);
+
+    if (dup) {
+        uprv_memcpy(dup, src, len);
+    }
+
+    return dup;
+}
+
+U_CAPI char* U_EXPORT2
+uprv_strndup(const char *src, int32_t n) {
+    char *dup;
+
+    if(n < 0) {
+        dup = uprv_strdup(src);
+    } else {
+        dup = (char*)uprv_malloc(n+1);
+        if (dup) { 
+            uprv_memcpy(dup, src, n);
+            dup[n] = 0;
+        }
+    }
+
+    return dup;
+}
diff --git a/source/common/cstring.h b/source/common/cstring.h
new file mode 100644
index 0000000..6d2fd0e
--- /dev/null
+++ b/source/common/cstring.h
@@ -0,0 +1,120 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1997-2005, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File CSTRING.H
+*
+* Contains CString interface
+*
+* @author       Helena Shih
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   6/17/98     hshih       Created.
+*  05/03/99     stephen     Changed from functions to macros.
+*  06/14/99     stephen     Added icu_strncat, icu_strncmp, icu_tolower
+*
+******************************************************************************
+*/
+
+#ifndef CSTRING_H
+#define CSTRING_H 1
+
+#include "unicode/utypes.h"
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#define uprv_strcpy(dst, src) U_STANDARD_CPP_NAMESPACE  strcpy(dst, src)
+#define uprv_strncpy(dst, src, size) U_STANDARD_CPP_NAMESPACE strncpy(dst, src, size)
+#define uprv_strlen(str) U_STANDARD_CPP_NAMESPACE strlen(str)
+#define uprv_strcmp(s1, s2) U_STANDARD_CPP_NAMESPACE strcmp(s1, s2)
+#define uprv_strncmp(s1, s2, n) U_STANDARD_CPP_NAMESPACE strncmp(s1, s2, n)
+#define uprv_strcat(dst, src) U_STANDARD_CPP_NAMESPACE strcat(dst, src)
+#define uprv_strncat(dst, src, n) U_STANDARD_CPP_NAMESPACE strncat(dst, src, n)
+#define uprv_strchr(s, c) U_STANDARD_CPP_NAMESPACE strchr(s, c)
+#define uprv_strstr(s, c) U_STANDARD_CPP_NAMESPACE strstr(s, c)
+#define uprv_strrchr(s, c) U_STANDARD_CPP_NAMESPACE strrchr(s, c)
+
+U_CAPI char U_EXPORT2
+uprv_toupper(char c);
+
+
+U_CAPI char U_EXPORT2
+uprv_asciitolower(char c);
+
+U_CAPI char U_EXPORT2
+uprv_ebcdictolower(char c);
+
+#if U_CHARSET_FAMILY==U_ASCII_FAMILY
+#   define uprv_tolower uprv_asciitolower
+#elif U_CHARSET_FAMILY==U_EBCDIC_FAMILY
+#   define uprv_tolower uprv_ebcdictolower
+#else
+#   error U_CHARSET_FAMILY is not valid
+#endif
+
+#define uprv_strtod(source, end) U_STANDARD_CPP_NAMESPACE strtod(source, end)
+#define uprv_strtoul(str, end, base) U_STANDARD_CPP_NAMESPACE strtoul(str, end, base)
+#define uprv_strtol(str, end, base) U_STANDARD_CPP_NAMESPACE strtol(str, end, base)
+#ifdef U_WINDOWS
+#   if defined(__BORLANDC__)
+#       define uprv_stricmp(str1, str2) U_STANDARD_CPP_NAMESPACE stricmp(str1, str2)
+#       define uprv_strnicmp(str1, str2, n) U_STANDARD_CPP_NAMESPACE strnicmp(str1, str2, n)
+#   else
+#       define uprv_stricmp(str1, str2) U_STANDARD_CPP_NAMESPACE _stricmp(str1, str2)
+#       define uprv_strnicmp(str1, str2, n) U_STANDARD_CPP_NAMESPACE _strnicmp(str1, str2, n)
+#   endif
+#elif defined(POSIX) 
+#   define uprv_stricmp(str1, str2) U_STANDARD_CPP_NAMESPACE strcasecmp(str1, str2) 
+#   define uprv_strnicmp(str1, str2, n) U_STANDARD_CPP_NAMESPACE strncasecmp(str1, str2, n) 
+#else
+#   define uprv_stricmp(str1, str2) T_CString_stricmp(str1, str2)
+#   define uprv_strnicmp(str1, str2, n) T_CString_strnicmp(str1, str2, n)
+#endif
+
+/* Conversion from a digit to the character with radix base from 2-19 */
+/* May need to use U_UPPER_ORDINAL*/
+#define T_CString_itosOffset(a) ((a)<=9?('0'+(a)):('A'+(a)-10))
+
+U_CAPI char* U_EXPORT2
+uprv_strdup(const char *src);
+
+/**
+ * uprv_malloc n+1 bytes, and copy n bytes from src into the new string.
+ * Terminate with a null at offset n.   If n is -1, works like uprv_strdup
+ * @param src
+ * @param n length of the input string, not including null.
+ * @return new string (owned by caller, use uprv_free to free).
+ * @internal
+ */
+U_CAPI char* U_EXPORT2
+uprv_strndup(const char *src, int32_t n);
+
+U_CAPI char* U_EXPORT2
+T_CString_toLowerCase(char* str);
+
+U_CAPI char* U_EXPORT2
+T_CString_toUpperCase(char* str);
+
+U_CAPI int32_t U_EXPORT2
+T_CString_integerToString(char *buffer, int32_t n, int32_t radix);
+
+U_CAPI int32_t U_EXPORT2
+T_CString_int64ToString(char *buffer, int64_t n, uint32_t radix);
+
+U_CAPI int32_t U_EXPORT2
+T_CString_stringToInteger(const char *integerString, int32_t radix);
+
+U_CAPI int U_EXPORT2
+T_CString_stricmp(const char *str1, const char *str2);
+
+U_CAPI int U_EXPORT2
+T_CString_strnicmp(const char *str1, const char *str2, uint32_t n);
+
+#endif /* ! CSTRING_H */
diff --git a/source/common/cwchar.c b/source/common/cwchar.c
new file mode 100644
index 0000000..78bb8c5
--- /dev/null
+++ b/source/common/cwchar.c
@@ -0,0 +1,53 @@
+/*  
+******************************************************************************
+*
+*   Copyright (C) 2001, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  cwchar.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2001may25
+*   created by: Markus W. Scherer
+*/
+
+#include "unicode/utypes.h"
+
+#if !U_HAVE_WCSCPY
+
+#include "cwchar.h"
+
+U_CAPI wchar_t *uprv_wcscat(wchar_t *dst, const wchar_t *src) {
+    wchar_t *start=dst;
+    while(*dst!=0) {
+        ++dst;
+    }
+    while((*dst=*src)!=0) {
+        ++dst;
+        ++src;
+    }
+    return start;
+}
+
+U_CAPI wchar_t *uprv_wcscpy(wchar_t *dst, const wchar_t *src) {
+    wchar_t *start=dst;
+    while((*dst=*src)!=0) {
+        ++dst;
+        ++src;
+    }
+    return start;
+}
+
+U_CAPI size_t uprv_wcslen(const wchar_t *src) {
+    const wchar_t *start=src;
+    while(*src!=0) {
+        ++src;
+    }
+    return src-start;
+}
+
+#endif
+
diff --git a/source/common/cwchar.h b/source/common/cwchar.h
new file mode 100644
index 0000000..2ab36c0
--- /dev/null
+++ b/source/common/cwchar.h
@@ -0,0 +1,56 @@
+/*  
+******************************************************************************
+*
+*   Copyright (C) 2001, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  cwchar.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2001may25
+*   created by: Markus W. Scherer
+*
+*   This file contains ICU-internal definitions of wchar_t operations.
+*   These definitions were moved here from cstring.h so that fewer
+*   ICU implementation files include wchar.h.
+*/
+
+#ifndef __CWCHAR_H__
+#define __CWCHAR_H__
+
+#include <string.h>
+#include <stdlib.h>
+#include "unicode/utypes.h"
+
+/* Do this after utypes.h so that we have U_HAVE_WCHAR_H . */
+#if U_HAVE_WCHAR_H
+#   include <wchar.h>
+#endif
+
+/*===========================================================================*/
+/* Wide-character functions                                                  */
+/*===========================================================================*/
+
+/* The following are not available on all systems, defined in wchar.h or string.h. */
+#if U_HAVE_WCSCPY
+#   define uprv_wcscpy wcscpy
+#   define uprv_wcscat wcscat
+#   define uprv_wcslen wcslen
+#else
+U_CAPI wchar_t* U_EXPORT2 
+uprv_wcscpy(wchar_t *dst, const wchar_t *src);
+U_CAPI wchar_t* U_EXPORT2 
+uprv_wcscat(wchar_t *dst, const wchar_t *src);
+U_CAPI size_t U_EXPORT2 
+uprv_wcslen(const wchar_t *src);
+#endif
+
+/* The following are part of the ANSI C standard, defined in stdlib.h . */
+#define uprv_wcstombs(mbstr, wcstr, count) U_STANDARD_CPP_NAMESPACE wcstombs(mbstr, wcstr, count)
+#define uprv_mbstowcs(wcstr, mbstr, count) U_STANDARD_CPP_NAMESPACE mbstowcs(wcstr, mbstr, count)
+
+
+#endif
diff --git a/source/common/dictbe.cpp b/source/common/dictbe.cpp
new file mode 100644
index 0000000..9698893
--- /dev/null
+++ b/source/common/dictbe.cpp
@@ -0,0 +1,427 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2006-2008, International Business Machines Corporation and others. *
+ * All Rights Reserved.                                                        *
+ *******************************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "brkeng.h"
+#include "dictbe.h"
+#include "unicode/uniset.h"
+#include "unicode/chariter.h"
+#include "unicode/ubrk.h"
+#include "uvector.h"
+#include "triedict.h"
+
+U_NAMESPACE_BEGIN
+
+/*
+ ******************************************************************
+ */
+
+/*DictionaryBreakEngine::DictionaryBreakEngine() {
+    fTypes = 0;
+}*/
+
+DictionaryBreakEngine::DictionaryBreakEngine(uint32_t breakTypes) {
+    fTypes = breakTypes;
+}
+
+DictionaryBreakEngine::~DictionaryBreakEngine() {
+}
+
+UBool
+DictionaryBreakEngine::handles(UChar32 c, int32_t breakType) const {
+    return (breakType >= 0 && breakType < 32 && (((uint32_t)1 << breakType) & fTypes)
+            && fSet.contains(c));
+}
+
+int32_t
+DictionaryBreakEngine::findBreaks( UText *text,
+                                 int32_t startPos,
+                                 int32_t endPos,
+                                 UBool reverse,
+                                 int32_t breakType,
+                                 UStack &foundBreaks ) const {
+    int32_t result = 0;
+
+    // Find the span of characters included in the set.
+    int32_t start = (int32_t)utext_getNativeIndex(text);
+    int32_t current;
+    int32_t rangeStart;
+    int32_t rangeEnd;
+    UChar32 c = utext_current32(text);
+    if (reverse) {
+        UBool   isDict = fSet.contains(c);
+        while((current = (int32_t)utext_getNativeIndex(text)) > startPos && isDict) {
+            c = utext_previous32(text);
+            isDict = fSet.contains(c);
+        }
+        rangeStart = (current < startPos) ? startPos : current+(isDict ? 0 : 1);
+        rangeEnd = start + 1;
+    }
+    else {
+        while((current = (int32_t)utext_getNativeIndex(text)) < endPos && fSet.contains(c)) {
+            utext_next32(text);         // TODO:  recast loop for postincrement
+            c = utext_current32(text);
+        }
+        rangeStart = start;
+        rangeEnd = current;
+    }
+    if (breakType >= 0 && breakType < 32 && (((uint32_t)1 << breakType) & fTypes)) {
+        result = divideUpDictionaryRange(text, rangeStart, rangeEnd, foundBreaks);
+        utext_setNativeIndex(text, current);
+    }
+    
+    return result;
+}
+
+void
+DictionaryBreakEngine::setCharacters( const UnicodeSet &set ) {
+    fSet = set;
+    // Compact for caching
+    fSet.compact();
+}
+
+/*void
+DictionaryBreakEngine::setBreakTypes( uint32_t breakTypes ) {
+    fTypes = breakTypes;
+}*/
+
+/*
+ ******************************************************************
+ */
+
+
+// Helper class for improving readability of the Thai word break
+// algorithm. The implementation is completely inline.
+
+// List size, limited by the maximum number of words in the dictionary
+// that form a nested sequence.
+#define POSSIBLE_WORD_LIST_MAX 20
+
+class PossibleWord {
+ private:
+  // list of word candidate lengths, in increasing length order
+  int32_t   lengths[POSSIBLE_WORD_LIST_MAX];
+  int       count;      // Count of candidates
+  int32_t   prefix;     // The longest match with a dictionary word
+  int32_t   offset;     // Offset in the text of these candidates
+  int       mark;       // The preferred candidate's offset
+  int       current;    // The candidate we're currently looking at
+
+ public:
+  PossibleWord();
+  ~PossibleWord();
+  
+  // Fill the list of candidates if needed, select the longest, and return the number found
+  int       candidates( UText *text, const TrieWordDictionary *dict, int32_t rangeEnd );
+  
+  // Select the currently marked candidate, point after it in the text, and invalidate self
+  int32_t   acceptMarked( UText *text );
+  
+  // Back up from the current candidate to the next shorter one; return TRUE if that exists
+  // and point the text after it
+  UBool     backUp( UText *text );
+  
+  // Return the longest prefix this candidate location shares with a dictionary word
+  int32_t   longestPrefix();
+  
+  // Mark the current candidate as the one we like
+  void      markCurrent();
+};
+
+inline
+PossibleWord::PossibleWord() {
+    offset = -1;
+}
+
+inline
+PossibleWord::~PossibleWord() {
+}
+
+inline int
+PossibleWord::candidates( UText *text, const TrieWordDictionary *dict, int32_t rangeEnd ) {
+    // TODO: If getIndex is too slow, use offset < 0 and add discardAll()
+    int32_t start = (int32_t)utext_getNativeIndex(text);
+    if (start != offset) {
+        offset = start;
+        prefix = dict->matches(text, rangeEnd-start, lengths, count, sizeof(lengths)/sizeof(lengths[0]));
+        // Dictionary leaves text after longest prefix, not longest word. Back up.
+        if (count <= 0) {
+            utext_setNativeIndex(text, start);
+        }
+    }
+    if (count > 0) {
+        utext_setNativeIndex(text, start+lengths[count-1]);
+    }
+    current = count-1;
+    mark = current;
+    return count;
+}
+
+inline int32_t
+PossibleWord::acceptMarked( UText *text ) {
+    utext_setNativeIndex(text, offset + lengths[mark]);
+    return lengths[mark];
+}
+
+inline UBool
+PossibleWord::backUp( UText *text ) {
+    if (current > 0) {
+        utext_setNativeIndex(text, offset + lengths[--current]);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+inline int32_t
+PossibleWord::longestPrefix() {
+    return prefix;
+}
+
+inline void
+PossibleWord::markCurrent() {
+    mark = current;
+}
+
+// How many words in a row are "good enough"?
+#define THAI_LOOKAHEAD 3
+
+// Will not combine a non-word with a preceding dictionary word longer than this
+#define THAI_ROOT_COMBINE_THRESHOLD 3
+
+// Will not combine a non-word that shares at least this much prefix with a
+// dictionary word, with a preceding word
+#define THAI_PREFIX_COMBINE_THRESHOLD 3
+
+// Ellision character
+#define THAI_PAIYANNOI 0x0E2F
+
+// Repeat character
+#define THAI_MAIYAMOK 0x0E46
+
+// Minimum word size
+#define THAI_MIN_WORD 2
+
+// Minimum number of characters for two words
+#define THAI_MIN_WORD_SPAN (THAI_MIN_WORD * 2)
+
+ThaiBreakEngine::ThaiBreakEngine(const TrieWordDictionary *adoptDictionary, UErrorCode &status)
+    : DictionaryBreakEngine((1<<UBRK_WORD) | (1<<UBRK_LINE)),
+      fDictionary(adoptDictionary)
+{
+    fThaiWordSet.applyPattern(UNICODE_STRING_SIMPLE("[[:Thai:]&[:LineBreak=SA:]]"), status);
+    if (U_SUCCESS(status)) {
+        setCharacters(fThaiWordSet);
+    }
+    fMarkSet.applyPattern(UNICODE_STRING_SIMPLE("[[:Thai:]&[:LineBreak=SA:]&[:M:]]"), status);
+    fMarkSet.add(0x0020);
+    fEndWordSet = fThaiWordSet;
+    fEndWordSet.remove(0x0E31);             // MAI HAN-AKAT
+    fEndWordSet.remove(0x0E40, 0x0E44);     // SARA E through SARA AI MAIMALAI
+    fBeginWordSet.add(0x0E01, 0x0E2E);      // KO KAI through HO NOKHUK
+    fBeginWordSet.add(0x0E40, 0x0E44);      // SARA E through SARA AI MAIMALAI
+    fSuffixSet.add(THAI_PAIYANNOI);
+    fSuffixSet.add(THAI_MAIYAMOK);
+
+    // Compact for caching.
+    fMarkSet.compact();
+    fEndWordSet.compact();
+    fBeginWordSet.compact();
+    fSuffixSet.compact();
+}
+
+ThaiBreakEngine::~ThaiBreakEngine() {
+    delete fDictionary;
+}
+
+int32_t
+ThaiBreakEngine::divideUpDictionaryRange( UText *text,
+                                                int32_t rangeStart,
+                                                int32_t rangeEnd,
+                                                UStack &foundBreaks ) const {
+    if ((rangeEnd - rangeStart) < THAI_MIN_WORD_SPAN) {
+        return 0;       // Not enough characters for two words
+    }
+
+    uint32_t wordsFound = 0;
+    int32_t wordLength;
+    int32_t current;
+    UErrorCode status = U_ZERO_ERROR;
+    PossibleWord words[THAI_LOOKAHEAD];
+    UChar32 uc;
+    
+    utext_setNativeIndex(text, rangeStart);
+    
+    while (U_SUCCESS(status) && (current = (int32_t)utext_getNativeIndex(text)) < rangeEnd) {
+        wordLength = 0;
+
+        // Look for candidate words at the current position
+        int candidates = words[wordsFound%THAI_LOOKAHEAD].candidates(text, fDictionary, rangeEnd);
+        
+        // If we found exactly one, use that
+        if (candidates == 1) {
+            wordLength = words[wordsFound%THAI_LOOKAHEAD].acceptMarked(text);
+            wordsFound += 1;
+        }
+        
+        // If there was more than one, see which one can take us forward the most words
+        else if (candidates > 1) {
+            // If we're already at the end of the range, we're done
+            if ((int32_t)utext_getNativeIndex(text) >= rangeEnd) {
+                goto foundBest;
+            }
+            do {
+                int wordsMatched = 1;
+                if (words[(wordsFound+1)%THAI_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) > 0) {
+                    if (wordsMatched < 2) {
+                        // Followed by another dictionary word; mark first word as a good candidate
+                        words[wordsFound%THAI_LOOKAHEAD].markCurrent();
+                        wordsMatched = 2;
+                    }
+                    
+                    // If we're already at the end of the range, we're done
+                    if ((int32_t)utext_getNativeIndex(text) >= rangeEnd) {
+                        goto foundBest;
+                    }
+                    
+                    // See if any of the possible second words is followed by a third word
+                    do {
+                        // If we find a third word, stop right away
+                        if (words[(wordsFound+2)%THAI_LOOKAHEAD].candidates(text, fDictionary, rangeEnd)) {
+                            words[wordsFound%THAI_LOOKAHEAD].markCurrent();
+                            goto foundBest;
+                        }
+                    }
+                    while (words[(wordsFound+1)%THAI_LOOKAHEAD].backUp(text));
+                }
+            }
+            while (words[wordsFound%THAI_LOOKAHEAD].backUp(text));
+foundBest:
+            wordLength = words[wordsFound%THAI_LOOKAHEAD].acceptMarked(text);
+            wordsFound += 1;
+        }
+        
+        // We come here after having either found a word or not. We look ahead to the
+        // next word. If it's not a dictionary word, we will combine it withe the word we
+        // just found (if there is one), but only if the preceding word does not exceed
+        // the threshold.
+        // The text iterator should now be positioned at the end of the word we found.
+        if ((int32_t)utext_getNativeIndex(text) < rangeEnd && wordLength < THAI_ROOT_COMBINE_THRESHOLD) {
+            // if it is a dictionary word, do nothing. If it isn't, then if there is
+            // no preceding word, or the non-word shares less than the minimum threshold
+            // of characters with a dictionary word, then scan to resynchronize
+            if (words[wordsFound%THAI_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) <= 0
+                  && (wordLength == 0
+                      || words[wordsFound%THAI_LOOKAHEAD].longestPrefix() < THAI_PREFIX_COMBINE_THRESHOLD)) {
+                // Look for a plausible word boundary
+                //TODO: This section will need a rework for UText.
+                int32_t remaining = rangeEnd - (current+wordLength);
+                UChar32 pc = utext_current32(text);
+                int32_t chars = 0;
+                for (;;) {
+                    utext_next32(text);
+                    uc = utext_current32(text);
+                    // TODO: Here we're counting on the fact that the SA languages are all
+                    // in the BMP. This should get fixed with the UText rework.
+                    chars += 1;
+                    if (--remaining <= 0) {
+                        break;
+                    }
+                    if (fEndWordSet.contains(pc) && fBeginWordSet.contains(uc)) {
+                        // Maybe. See if it's in the dictionary.
+                        // NOTE: In the original Apple code, checked that the next
+                        // two characters after uc were not 0x0E4C THANTHAKHAT before
+                        // checking the dictionary. That is just a performance filter,
+                        // but it's not clear it's faster than checking the trie.
+                        int candidates = words[(wordsFound+1)%THAI_LOOKAHEAD].candidates(text, fDictionary, rangeEnd);
+                        utext_setNativeIndex(text, current+wordLength+chars);
+                        if (candidates > 0) {
+                            break;
+                        }
+                    }
+                    pc = uc;
+                }
+                
+                // Bump the word count if there wasn't already one
+                if (wordLength <= 0) {
+                    wordsFound += 1;
+                }
+                
+                // Update the length with the passed-over characters
+                wordLength += chars;
+            }
+            else {
+                // Back up to where we were for next iteration
+                utext_setNativeIndex(text, current+wordLength);
+            }
+        }
+        
+        // Never stop before a combining mark.
+        int32_t currPos;
+        while ((currPos = (int32_t)utext_getNativeIndex(text)) < rangeEnd && fMarkSet.contains(utext_current32(text))) {
+            utext_next32(text);
+            wordLength += (int32_t)utext_getNativeIndex(text) - currPos;
+        }
+        
+        // Look ahead for possible suffixes if a dictionary word does not follow.
+        // We do this in code rather than using a rule so that the heuristic
+        // resynch continues to function. For example, one of the suffix characters
+        // could be a typo in the middle of a word.
+        if ((int32_t)utext_getNativeIndex(text) < rangeEnd && wordLength > 0) {
+            if (words[wordsFound%THAI_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) <= 0
+                && fSuffixSet.contains(uc = utext_current32(text))) {
+                if (uc == THAI_PAIYANNOI) {
+                    if (!fSuffixSet.contains(utext_previous32(text))) {
+                        // Skip over previous end and PAIYANNOI
+                        utext_next32(text);
+                        utext_next32(text);
+                        wordLength += 1;            // Add PAIYANNOI to word
+                        uc = utext_current32(text);     // Fetch next character
+                    }
+                    else {
+                        // Restore prior position
+                        utext_next32(text);
+                    }
+                }
+                if (uc == THAI_MAIYAMOK) {
+                    if (utext_previous32(text) != THAI_MAIYAMOK) {
+                        // Skip over previous end and MAIYAMOK
+                        utext_next32(text);
+                        utext_next32(text);
+                        wordLength += 1;            // Add MAIYAMOK to word
+                    }
+                    else {
+                        // Restore prior position
+                        utext_next32(text);
+                    }
+                }
+            }
+            else {
+                utext_setNativeIndex(text, current+wordLength);
+            }
+        }
+        
+        // Did we find a word on this iteration? If so, push it on the break stack
+        if (wordLength > 0) {
+            foundBreaks.push((current+wordLength), status);
+        }
+    }
+    
+    // Don't return a break for the end of the dictionary range if there is one there.
+    if (foundBreaks.peeki() >= rangeEnd) {
+        (void) foundBreaks.popi();
+        wordsFound -= 1;
+    }
+
+    return wordsFound;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
diff --git a/source/common/dictbe.h b/source/common/dictbe.h
new file mode 100644
index 0000000..d6f8b14
--- /dev/null
+++ b/source/common/dictbe.h
@@ -0,0 +1,193 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2006, International Business Machines Corporation and others. *
+ * All Rights Reserved.                                                        *
+ *******************************************************************************
+ */
+
+#ifndef DICTBE_H
+#define DICTBE_H
+
+#include "unicode/utypes.h"
+#include "unicode/uniset.h"
+#include "unicode/utext.h"
+
+#include "brkeng.h"
+
+U_NAMESPACE_BEGIN
+
+class TrieWordDictionary;
+
+/*******************************************************************
+ * DictionaryBreakEngine
+ */
+
+/**
+ * <p>DictionaryBreakEngine is a kind of LanguageBreakEngine that uses a
+ * dictionary to determine language-specific breaks.</p>
+ *
+ * <p>After it is constructed a DictionaryBreakEngine may be shared between
+ * threads without synchronization.</p>
+ */
+class DictionaryBreakEngine : public LanguageBreakEngine {
+ private:
+    /**
+     * The set of characters handled by this engine
+     * @internal
+     */
+
+  UnicodeSet    fSet;
+
+    /**
+     * The set of break types handled by this engine
+     * @internal
+     */
+
+  uint32_t      fTypes;
+
+  /**
+   * <p>Default constructor.</p>
+   *
+   */
+  DictionaryBreakEngine();
+
+ public:
+
+  /**
+   * <p>Constructor setting the break types handled.</p>
+   *
+   * @param breakTypes A bitmap of types handled by the engine.
+   */
+  DictionaryBreakEngine( uint32_t breakTypes );
+
+  /**
+   * <p>Virtual destructor.</p>
+   */
+  virtual ~DictionaryBreakEngine();
+
+ /**
+  * <p>Indicate whether this engine handles a particular character for
+  * a particular kind of break.</p>
+  *
+  * @param c A character which begins a run that the engine might handle
+  * @param breakType The type of text break which the caller wants to determine
+  * @return TRUE if this engine handles the particular character and break
+  * type.
+  */
+  virtual UBool handles( UChar32 c, int32_t breakType ) const;
+
+ /**
+  * <p>Find any breaks within a run in the supplied text.</p>
+  *
+  * @param text A UText representing the text. The
+  * iterator is left at the end of the run of characters which the engine
+  * is capable of handling.
+  * @param startPos The start of the run within the supplied text.
+  * @param endPos The end of the run within the supplied text.
+  * @param reverse Whether the caller is looking for breaks in a reverse
+  * direction.
+  * @param breakType The type of break desired, or -1.
+  * @param foundBreaks An allocated C array of the breaks found, if any
+  * @return The number of breaks found.
+  */
+  virtual int32_t findBreaks( UText *text,
+                              int32_t startPos,
+                              int32_t endPos,
+                              UBool reverse,
+                              int32_t breakType,
+                              UStack &foundBreaks ) const;
+
+ protected:
+
+ /**
+  * <p>Set the character set handled by this engine.</p>
+  *
+  * @param set A UnicodeSet of the set of characters handled by the engine
+  */
+  virtual void setCharacters( const UnicodeSet &set );
+
+ /**
+  * <p>Set the break types handled by this engine.</p>
+  *
+  * @param breakTypes A bitmap of types handled by the engine.
+  */
+//  virtual void setBreakTypes( uint32_t breakTypes );
+
+ /**
+  * <p>Divide up a range of known dictionary characters.</p>
+  *
+  * @param text A UText representing the text
+  * @param rangeStart The start of the range of dictionary characters
+  * @param rangeEnd The end of the range of dictionary characters
+  * @param foundBreaks Output of C array of int32_t break positions, or 0
+  * @return The number of breaks found
+  */
+  virtual int32_t divideUpDictionaryRange( UText *text,
+                                           int32_t rangeStart,
+                                           int32_t rangeEnd,
+                                           UStack &foundBreaks ) const = 0;
+
+};
+
+/*******************************************************************
+ * ThaiBreakEngine
+ */
+
+/**
+ * <p>ThaiBreakEngine is a kind of DictionaryBreakEngine that uses a
+ * TrieWordDictionary and heuristics to determine Thai-specific breaks.</p>
+ *
+ * <p>After it is constructed a ThaiBreakEngine may be shared between
+ * threads without synchronization.</p>
+ */
+class ThaiBreakEngine : public DictionaryBreakEngine {
+ private:
+    /**
+     * The set of characters handled by this engine
+     * @internal
+     */
+
+  UnicodeSet                fThaiWordSet;
+  UnicodeSet                fEndWordSet;
+  UnicodeSet                fBeginWordSet;
+  UnicodeSet                fSuffixSet;
+  UnicodeSet                fMarkSet;
+  const TrieWordDictionary  *fDictionary;
+
+ public:
+
+  /**
+   * <p>Default constructor.</p>
+   *
+   * @param adoptDictionary A TrieWordDictionary to adopt. Deleted when the
+   * engine is deleted.
+   */
+  ThaiBreakEngine(const TrieWordDictionary *adoptDictionary, UErrorCode &status);
+
+  /**
+   * <p>Virtual destructor.</p>
+   */
+  virtual ~ThaiBreakEngine();
+
+ protected:
+ /**
+  * <p>Divide up a range of known dictionary characters.</p>
+  *
+  * @param text A UText representing the text
+  * @param rangeStart The start of the range of dictionary characters
+  * @param rangeEnd The end of the range of dictionary characters
+  * @param foundBreaks Output of C array of int32_t break positions, or 0
+  * @return The number of breaks found
+  */
+  virtual int32_t divideUpDictionaryRange( UText *text,
+                                           int32_t rangeStart,
+                                           int32_t rangeEnd,
+                                           UStack &foundBreaks ) const;
+
+};
+
+
+U_NAMESPACE_END
+
+    /* DICTBE_H */
+#endif
diff --git a/source/common/dtintrv.cpp b/source/common/dtintrv.cpp
new file mode 100644
index 0000000..bece836
--- /dev/null
+++ b/source/common/dtintrv.cpp
@@ -0,0 +1,61 @@
+/*******************************************************************************
+* Copyright (C) 2008, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File DTINTRV.CPP 
+*
+*******************************************************************************
+*/
+
+
+
+#include "unicode/dtintrv.h"
+
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateInterval)
+
+//DateInterval::DateInterval(){}
+
+
+DateInterval::DateInterval(UDate from, UDate to)
+:   fromDate(from),
+    toDate(to)
+{}
+
+
+DateInterval::~DateInterval(){}
+
+
+DateInterval::DateInterval(const DateInterval& other)
+: UObject(other) {
+    *this = other;
+}   
+
+
+DateInterval&
+DateInterval::operator=(const DateInterval& other) {
+    if ( this != &other ) {
+        fromDate = other.fromDate;
+        toDate = other.toDate;
+    }
+    return *this;
+}
+
+
+DateInterval* 
+DateInterval::clone() const {
+    return new DateInterval(*this);
+}
+
+
+UBool 
+DateInterval::operator==(const DateInterval& other) const { 
+    return ( fromDate == other.fromDate && toDate == other.toDate );
+}
+
+
+U_NAMESPACE_END
+
diff --git a/source/common/errorcode.cpp b/source/common/errorcode.cpp
new file mode 100644
index 0000000..4ff151e
--- /dev/null
+++ b/source/common/errorcode.cpp
@@ -0,0 +1,38 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  errorcode.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2009mar10
+*   created by: Markus W. Scherer
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/errorcode.h"
+
+U_NAMESPACE_BEGIN
+
+UErrorCode ErrorCode::reset() {
+    UErrorCode code = errorCode;
+    errorCode = U_ZERO_ERROR;
+    return code;
+}
+
+void ErrorCode::assertSuccess() const {
+    if(isFailure()) {
+        handleFailure();
+    }
+}
+
+const char* ErrorCode::errorName() const {
+  return u_errorName(errorCode);
+}
+
+U_NAMESPACE_END
diff --git a/source/common/filterednormalizer2.cpp b/source/common/filterednormalizer2.cpp
new file mode 100644
index 0000000..a23a459
--- /dev/null
+++ b/source/common/filterednormalizer2.cpp
@@ -0,0 +1,271 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2009-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  filterednormalizer2.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2009dec10
+*   created by: Markus W. Scherer
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/normalizer2.h"
+#include "unicode/uniset.h"
+#include "unicode/unistr.h"
+#include "unicode/unorm.h"
+#include "cpputils.h"
+
+U_NAMESPACE_BEGIN
+
+UnicodeString &
+FilteredNormalizer2::normalize(const UnicodeString &src,
+                               UnicodeString &dest,
+                               UErrorCode &errorCode) const {
+    uprv_checkCanGetBuffer(src, errorCode);
+    if(U_FAILURE(errorCode)) {
+        dest.setToBogus();
+        return dest;
+    }
+    if(&dest==&src) {
+        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return dest;
+    }
+    dest.remove();
+    return normalize(src, dest, USET_SPAN_SIMPLE, errorCode);
+}
+
+// Internal: No argument checking, and appends to dest.
+// Pass as input spanCondition the one that is likely to yield a non-zero
+// span length at the start of src.
+// For set=[:age=3.2:], since almost all common characters were in Unicode 3.2,
+// USET_SPAN_SIMPLE should be passed in for the start of src
+// and USET_SPAN_NOT_CONTAINED should be passed in if we continue after
+// an in-filter prefix.
+UnicodeString &
+FilteredNormalizer2::normalize(const UnicodeString &src,
+                               UnicodeString &dest,
+                               USetSpanCondition spanCondition,
+                               UErrorCode &errorCode) const {
+    UnicodeString tempDest;  // Don't throw away destination buffer between iterations.
+    for(int32_t prevSpanLimit=0; prevSpanLimit<src.length();) {
+        int32_t spanLimit=set.span(src, prevSpanLimit, spanCondition);
+        int32_t spanLength=spanLimit-prevSpanLimit;
+        if(spanCondition==USET_SPAN_NOT_CONTAINED) {
+            if(spanLength!=0) {
+                dest.append(src, prevSpanLimit, spanLength);
+            }
+            spanCondition=USET_SPAN_SIMPLE;
+        } else {
+            if(spanLength!=0) {
+                // Not norm2.normalizeSecondAndAppend() because we do not want
+                // to modify the non-filter part of dest.
+                dest.append(norm2.normalize(src.tempSubStringBetween(prevSpanLimit, spanLimit),
+                                            tempDest, errorCode));
+                if(U_FAILURE(errorCode)) {
+                    break;
+                }
+            }
+            spanCondition=USET_SPAN_NOT_CONTAINED;
+        }
+        prevSpanLimit=spanLimit;
+    }
+    return dest;
+}
+
+UnicodeString &
+FilteredNormalizer2::normalizeSecondAndAppend(UnicodeString &first,
+                                              const UnicodeString &second,
+                                              UErrorCode &errorCode) const {
+    return normalizeSecondAndAppend(first, second, TRUE, errorCode);
+}
+
+UnicodeString &
+FilteredNormalizer2::append(UnicodeString &first,
+                            const UnicodeString &second,
+                            UErrorCode &errorCode) const {
+    return normalizeSecondAndAppend(first, second, FALSE, errorCode);
+}
+
+UnicodeString &
+FilteredNormalizer2::normalizeSecondAndAppend(UnicodeString &first,
+                                              const UnicodeString &second,
+                                              UBool doNormalize,
+                                              UErrorCode &errorCode) const {
+    uprv_checkCanGetBuffer(first, errorCode);
+    uprv_checkCanGetBuffer(second, errorCode);
+    if(U_FAILURE(errorCode)) {
+        return first;
+    }
+    if(&first==&second) {
+        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return first;
+    }
+    if(first.isEmpty()) {
+        if(doNormalize) {
+            return normalize(second, first, errorCode);
+        } else {
+            return first=second;
+        }
+    }
+    // merge the in-filter suffix of the first string with the in-filter prefix of the second
+    int32_t prefixLimit=set.span(second, 0, USET_SPAN_SIMPLE);
+    if(prefixLimit!=0) {
+        UnicodeString prefix(second.tempSubString(0, prefixLimit));
+        int32_t suffixStart=set.spanBack(first, INT32_MAX, USET_SPAN_SIMPLE);
+        if(suffixStart==0) {
+            if(doNormalize) {
+                norm2.normalizeSecondAndAppend(first, prefix, errorCode);
+            } else {
+                norm2.append(first, prefix, errorCode);
+            }
+        } else {
+            UnicodeString middle(first, suffixStart, INT32_MAX);
+            if(doNormalize) {
+                norm2.normalizeSecondAndAppend(middle, prefix, errorCode);
+            } else {
+                norm2.append(middle, prefix, errorCode);
+            }
+            first.replace(suffixStart, INT32_MAX, middle);
+        }
+    }
+    if(prefixLimit<second.length()) {
+        UnicodeString rest(second.tempSubString(prefixLimit, INT32_MAX));
+        if(doNormalize) {
+            normalize(rest, first, USET_SPAN_NOT_CONTAINED, errorCode);
+        } else {
+            first.append(rest);
+        }
+    }
+    return first;
+}
+
+UBool
+FilteredNormalizer2::getDecomposition(UChar32 c, UnicodeString &decomposition) const {
+    return set.contains(c) && norm2.getDecomposition(c, decomposition);
+}
+
+UBool
+FilteredNormalizer2::isNormalized(const UnicodeString &s, UErrorCode &errorCode) const {
+    uprv_checkCanGetBuffer(s, errorCode);
+    if(U_FAILURE(errorCode)) {
+        return FALSE;
+    }
+    USetSpanCondition spanCondition=USET_SPAN_SIMPLE;
+    for(int32_t prevSpanLimit=0; prevSpanLimit<s.length();) {
+        int32_t spanLimit=set.span(s, prevSpanLimit, spanCondition);
+        if(spanCondition==USET_SPAN_NOT_CONTAINED) {
+            spanCondition=USET_SPAN_SIMPLE;
+        } else {
+            if( !norm2.isNormalized(s.tempSubStringBetween(prevSpanLimit, spanLimit), errorCode) ||
+                U_FAILURE(errorCode)
+            ) {
+                return FALSE;
+            }
+            spanCondition=USET_SPAN_NOT_CONTAINED;
+        }
+        prevSpanLimit=spanLimit;
+    }
+    return TRUE;
+}
+
+UNormalizationCheckResult
+FilteredNormalizer2::quickCheck(const UnicodeString &s, UErrorCode &errorCode) const {
+    uprv_checkCanGetBuffer(s, errorCode);
+    if(U_FAILURE(errorCode)) {
+        return UNORM_MAYBE;
+    }
+    UNormalizationCheckResult result=UNORM_YES;
+    USetSpanCondition spanCondition=USET_SPAN_SIMPLE;
+    for(int32_t prevSpanLimit=0; prevSpanLimit<s.length();) {
+        int32_t spanLimit=set.span(s, prevSpanLimit, spanCondition);
+        if(spanCondition==USET_SPAN_NOT_CONTAINED) {
+            spanCondition=USET_SPAN_SIMPLE;
+        } else {
+            UNormalizationCheckResult qcResult=
+                norm2.quickCheck(s.tempSubStringBetween(prevSpanLimit, spanLimit), errorCode);
+            if(U_FAILURE(errorCode) || qcResult==UNORM_NO) {
+                return qcResult;
+            } else if(qcResult==UNORM_MAYBE) {
+                result=qcResult;
+            }
+            spanCondition=USET_SPAN_NOT_CONTAINED;
+        }
+        prevSpanLimit=spanLimit;
+    }
+    return result;
+}
+
+int32_t
+FilteredNormalizer2::spanQuickCheckYes(const UnicodeString &s, UErrorCode &errorCode) const {
+    uprv_checkCanGetBuffer(s, errorCode);
+    if(U_FAILURE(errorCode)) {
+        return 0;
+    }
+    USetSpanCondition spanCondition=USET_SPAN_SIMPLE;
+    for(int32_t prevSpanLimit=0; prevSpanLimit<s.length();) {
+        int32_t spanLimit=set.span(s, prevSpanLimit, spanCondition);
+        if(spanCondition==USET_SPAN_NOT_CONTAINED) {
+            spanCondition=USET_SPAN_SIMPLE;
+        } else {
+            int32_t yesLimit=
+                prevSpanLimit+
+                norm2.spanQuickCheckYes(
+                    s.tempSubStringBetween(prevSpanLimit, spanLimit), errorCode);
+            if(U_FAILURE(errorCode) || yesLimit<spanLimit) {
+                return yesLimit;
+            }
+            spanCondition=USET_SPAN_NOT_CONTAINED;
+        }
+        prevSpanLimit=spanLimit;
+    }
+    return s.length();
+}
+
+UBool
+FilteredNormalizer2::hasBoundaryBefore(UChar32 c) const {
+    return !set.contains(c) || norm2.hasBoundaryBefore(c);
+}
+
+UBool
+FilteredNormalizer2::hasBoundaryAfter(UChar32 c) const {
+    return !set.contains(c) || norm2.hasBoundaryAfter(c);
+}
+
+UBool
+FilteredNormalizer2::isInert(UChar32 c) const {
+    return !set.contains(c) || norm2.isInert(c);
+}
+
+U_NAMESPACE_END
+
+// C API ------------------------------------------------------------------- ***
+
+U_NAMESPACE_USE
+
+U_DRAFT UNormalizer2 * U_EXPORT2
+unorm2_openFiltered(const UNormalizer2 *norm2, const USet *filterSet, UErrorCode *pErrorCode) {
+    if(U_FAILURE(*pErrorCode)) {
+        return NULL;
+    }
+    if(filterSet==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+    Normalizer2 *fn2=new FilteredNormalizer2(*(Normalizer2 *)norm2,
+                                             *UnicodeSet::fromUSet(filterSet));
+    if(fn2==NULL) {
+        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+    }
+    return (UNormalizer2 *)fn2;
+}
+
+#endif  // !UCONFIG_NO_NORMALIZATION
diff --git a/source/common/hash.h b/source/common/hash.h
new file mode 100644
index 0000000..9fedd0e
--- /dev/null
+++ b/source/common/hash.h
@@ -0,0 +1,207 @@
+/*
+******************************************************************************
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+******************************************************************************
+*   Date        Name        Description
+*   03/28/00    aliu        Creation.
+******************************************************************************
+*/
+
+#ifndef HASH_H
+#define HASH_H
+
+#include "unicode/unistr.h"
+#include "unicode/uobject.h"
+#include "uhash.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Hashtable is a thin C++ wrapper around UHashtable, a general-purpose void*
+ * hashtable implemented in C.  Hashtable is designed to be idiomatic and
+ * easy-to-use in C++.
+ *
+ * Hashtable is an INTERNAL CLASS.
+ */
+class U_COMMON_API Hashtable : public UMemory {
+    UHashtable* hash;
+    UHashtable hashObj;
+
+    inline void init(UHashFunction *keyHash, UKeyComparator *keyComp, UValueComparator *valueComp, UErrorCode& status);
+
+public:
+    /**
+     * Construct a hashtable
+     * @param ignoreKeyCase If true, keys are case insensitive.
+     * @param status Error code
+    */
+    Hashtable(UBool ignoreKeyCase, UErrorCode& status);
+
+    /**
+     * Construct a hashtable
+     * @param keyComp Comparator for comparing the keys
+     * @param valueComp Comparator for comparing the values
+     * @param status Error code
+    */
+    Hashtable(UKeyComparator *keyComp, UValueComparator *valueComp, UErrorCode& status);
+
+    /**
+     * Construct a hashtable
+     * @param status Error code
+    */
+    Hashtable(UErrorCode& status);
+
+    /**
+     * Construct a hashtable, _disregarding any error_.  Use this constructor
+     * with caution.
+     */
+    Hashtable();
+
+    /**
+     * Non-virtual destructor; make this virtual if Hashtable is subclassed
+     * in the future.
+     */
+    ~Hashtable();
+
+    UObjectDeleter *setValueDeleter(UObjectDeleter *fn);
+
+    int32_t count() const;
+
+    void* put(const UnicodeString& key, void* value, UErrorCode& status);
+
+    int32_t puti(const UnicodeString& key, int32_t value, UErrorCode& status);
+
+    void* get(const UnicodeString& key) const;
+    
+    int32_t geti(const UnicodeString& key) const;
+    
+    void* remove(const UnicodeString& key);
+
+    int32_t removei(const UnicodeString& key);
+
+    void removeAll(void);
+
+    const UHashElement* find(const UnicodeString& key) const;
+
+    const UHashElement* nextElement(int32_t& pos) const;
+    
+    UKeyComparator* setKeyComparator(UKeyComparator*keyComp);
+    
+    UValueComparator* setValueComparator(UValueComparator* valueComp);
+
+    UBool equals(const Hashtable& that) const;
+private:
+    Hashtable(const Hashtable &other); // forbid copying of this class
+    Hashtable &operator=(const Hashtable &other); // forbid copying of this class
+};
+
+/*********************************************************************
+ * Implementation
+ ********************************************************************/
+
+inline void Hashtable::init(UHashFunction *keyHash, UKeyComparator *keyComp, 
+                            UValueComparator *valueComp, UErrorCode& status) {
+    if (U_FAILURE(status)) {
+        return;
+    }
+    uhash_init(&hashObj, keyHash, keyComp, valueComp, &status);
+    if (U_SUCCESS(status)) {
+        hash = &hashObj;
+        uhash_setKeyDeleter(hash, uhash_deleteUnicodeString);
+    }
+}
+
+inline Hashtable::Hashtable(UKeyComparator *keyComp, UValueComparator *valueComp, 
+                 UErrorCode& status) : hash(0) {
+    init( uhash_hashUnicodeString, keyComp, valueComp, status);
+}
+inline Hashtable::Hashtable(UBool ignoreKeyCase, UErrorCode& status)
+ : hash(0)
+{
+    init(ignoreKeyCase ? uhash_hashCaselessUnicodeString
+                        : uhash_hashUnicodeString,
+            ignoreKeyCase ? uhash_compareCaselessUnicodeString
+                        : uhash_compareUnicodeString,
+            NULL,
+            status);
+}
+
+inline Hashtable::Hashtable(UErrorCode& status)
+ : hash(0)
+{
+    init(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, status);
+}
+
+inline Hashtable::Hashtable()
+ : hash(0)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    init(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, status);
+}
+
+inline Hashtable::~Hashtable() {
+    if (hash != NULL) {
+        uhash_close(hash);
+    }
+}
+
+inline UObjectDeleter *Hashtable::setValueDeleter(UObjectDeleter *fn) {
+    return uhash_setValueDeleter(hash, fn);
+}
+
+inline int32_t Hashtable::count() const {
+    return uhash_count(hash);
+}
+
+inline void* Hashtable::put(const UnicodeString& key, void* value, UErrorCode& status) {
+    return uhash_put(hash, new UnicodeString(key), value, &status);
+}
+
+inline int32_t Hashtable::puti(const UnicodeString& key, int32_t value, UErrorCode& status) {
+    return uhash_puti(hash, new UnicodeString(key), value, &status);
+}
+
+inline void* Hashtable::get(const UnicodeString& key) const {
+    return uhash_get(hash, &key);
+}
+
+inline int32_t Hashtable::geti(const UnicodeString& key) const {
+    return uhash_geti(hash, &key);
+}
+
+inline void* Hashtable::remove(const UnicodeString& key) {
+    return uhash_remove(hash, &key);
+}
+
+inline int32_t Hashtable::removei(const UnicodeString& key) {
+    return uhash_removei(hash, &key);
+}
+
+inline const UHashElement* Hashtable::find(const UnicodeString& key) const {
+    return uhash_find(hash, &key);
+}
+
+inline const UHashElement* Hashtable::nextElement(int32_t& pos) const {
+    return uhash_nextElement(hash, &pos);
+}
+
+inline void Hashtable::removeAll(void) {
+    uhash_removeAll(hash);
+}
+
+inline UKeyComparator* Hashtable::setKeyComparator(UKeyComparator*keyComp){
+    return uhash_setKeyComparator(hash, keyComp);
+}
+    
+inline UValueComparator* Hashtable::setValueComparator(UValueComparator* valueComp){
+    return uhash_setValueComparator(hash, valueComp);
+}
+
+inline UBool Hashtable::equals(const Hashtable& that)const{
+   return uhash_equals(hash, that.hash);
+}
+U_NAMESPACE_END
+
+#endif
+
diff --git a/source/common/icucfg.h.in b/source/common/icucfg.h.in
new file mode 100644
index 0000000..5e2a6ea
--- /dev/null
+++ b/source/common/icucfg.h.in
@@ -0,0 +1,115 @@
+/* common/icucfg.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Define to 1 if you have the <dirent.h> header file. */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the `dlopen' function. */
+#undef HAVE_DLOPEN
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `m' library (-lm). */
+#undef HAVE_LIBM
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#undef HAVE_LIBPTHREAD
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* wchar.h was found. */
+#undef HAVE_WCHAR_H
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* The size of `void *', as computed by sizeof. */
+#undef SIZEOF_VOID_P
+
+/* The size of `wchar_t', as computed by sizeof. */
+#undef SIZEOF_WCHAR_T
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+#  undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* Define to `signed short' if <sys/types.h> does not define. */
+#undef int16_t
+
+/* Define to `signed long' if <sys/types.h> does not define. */
+#undef int32_t
+
+/* Define to `signed long long' if <sys/types.h> does not define. */
+#undef int64_t
+
+/* Define to `signed char' if <sys/types.h> does not define. */
+#undef int8_t
+
+/* Define to `unsigned short' if <sys/types.h> does not define. */
+#undef uint16_t
+
+/* Define to `unsigned long' if <sys/types.h> does not define. */
+#undef uint32_t
+
+/* Define to `unsigned long long' if <sys/types.h> does not define. */
+#undef uint64_t
+
+/* Define to `unsigned char' if <sys/types.h> does not define. */
+#undef uint8_t
diff --git a/source/common/icudataver.c b/source/common/icudataver.c
new file mode 100644
index 0000000..51fe9ce
--- /dev/null
+++ b/source/common/icudataver.c
@@ -0,0 +1,83 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/icudataver.h"
+#include "unicode/uversion.h"
+#include "unicode/ures.h"
+#include "uresimp.h" /* for ures_getVersionByKey */
+#include "cmemory.h"
+
+/*
+ * Determines if icustd is in the data.
+ */
+static UBool hasICUSTDBundle();
+
+static UBool hasICUSTDBundle() {
+    UErrorCode status = U_ZERO_ERROR;
+    UBool result = TRUE;
+    
+    UResourceBundle *icustdbundle = ures_openDirect(NULL, U_ICU_STD_BUNDLE, &status);
+    if (U_SUCCESS(status)) {
+        result = TRUE;
+    } else {
+        result = FALSE;
+    }
+    
+    ures_close(icustdbundle);
+    
+    return result;
+}
+
+U_CAPI void U_EXPORT2 u_getDataVersion(UVersionInfo dataVersionFillin, UErrorCode *status) {
+    UResourceBundle *icudatares = NULL;
+    
+    if (U_FAILURE(*status)) {
+        return;
+    }
+    
+    if (dataVersionFillin != NULL) {
+        icudatares = ures_openDirect(NULL, U_ICU_VERSION_BUNDLE , status);
+        if (U_SUCCESS(*status)) {
+            ures_getVersionByKey(icudatares, U_ICU_DATA_KEY, dataVersionFillin, status);
+        }
+        ures_close(icudatares);
+    }
+}
+
+U_CAPI UBool U_EXPORT2 u_isDataOlder(UVersionInfo dataVersionFillin, UBool *isModifiedFillin, UErrorCode *status) {
+    UBool result = TRUE;
+    UVersionInfo dataVersion;
+    UVersionInfo wiredVersion;
+    
+    if (U_FAILURE(*status)) {
+        return result;
+    }
+    
+    u_getDataVersion(dataVersion, status);
+    if (U_SUCCESS(*status)) {
+        u_versionFromString(wiredVersion, U_ICU_DATA_VERSION);
+        
+        if (uprv_memcmp(dataVersion, wiredVersion, sizeof(UVersionInfo)) >= 0) {
+            result = FALSE;
+        }
+        
+        if (dataVersionFillin != NULL) {
+            uprv_memcpy(dataVersionFillin, dataVersion, sizeof(UVersionInfo));
+        }
+        
+        if (hasICUSTDBundle()) {
+            *isModifiedFillin = FALSE;
+        } else {
+            *isModifiedFillin = TRUE;
+        }
+    }
+    
+    return result;
+}
diff --git a/source/common/icuplug.c b/source/common/icuplug.c
new file mode 100644
index 0000000..4fd77f3
--- /dev/null
+++ b/source/common/icuplug.c
@@ -0,0 +1,825 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2009-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+*  FILE NAME : icuplug.c
+*
+*   Date         Name        Description
+*   10/29/2009   sl          New.
+******************************************************************************
+*/
+
+#include "unicode/icuplug.h"
+#include "icuplugimp.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include "putilimp.h"
+#include "ucln.h"
+#include <stdio.h>
+
+#ifndef UPLUG_TRACE
+#define UPLUG_TRACE 0
+#endif
+
+#if UPLUG_TRACE
+#include <stdio.h>
+#define DBG(x) fprintf(stderr, "%s:%d: ",__FILE__,__LINE__); fprintf x
+#endif
+
+/**
+ * Internal structure of an ICU plugin. 
+ */
+
+struct UPlugData {
+  UPlugEntrypoint  *entrypoint; /**< plugin entrypoint */
+  uint32_t structSize;    /**< initialized to the size of this structure */
+  uint32_t token;         /**< must be U_PLUG_TOKEN */
+  void *lib;              /**< plugin library, or NULL */
+  char libName[UPLUG_NAME_MAX];   /**< library name */
+  char sym[UPLUG_NAME_MAX];        /**< plugin symbol, or NULL */
+  char config[UPLUG_NAME_MAX];     /**< configuration data */
+  void *context;          /**< user context data */
+  char name[UPLUG_NAME_MAX];   /**< name of plugin */
+  UPlugLevel  level; /**< level of plugin */
+  UBool   awaitingLoad; /**< TRUE if the plugin is awaiting a load call */
+  UBool   dontUnload; /**< TRUE if plugin must stay resident (leak plugin and lib) */
+  UErrorCode pluginStatus; /**< status code of plugin */
+};
+
+
+
+#define UPLUG_LIBRARY_INITIAL_COUNT 8
+#define UPLUG_PLUGIN_INITIAL_COUNT 12
+
+/**
+ * Remove an item
+ * @param list the full list
+ * @param listSize the number of entries in the list
+ * @param memberSize the size of one member
+ * @param itemToRemove the item number of the member
+ * @return the new listsize 
+ */
+static int32_t uplug_removeEntryAt(void *list, int32_t listSize, int32_t memberSize, int32_t itemToRemove) {
+  uint8_t *bytePtr = (uint8_t *)list;
+    
+  /* get rid of some bad cases first */
+  if(listSize<1) {
+    return listSize;
+  }
+    
+  /* is there anything to move? */
+  if(listSize > itemToRemove+1) {
+    memmove(bytePtr+(itemToRemove*memberSize), bytePtr+((itemToRemove+1)*memberSize), memberSize);
+  }
+    
+  return listSize-1;
+}
+
+
+
+
+#if U_ENABLE_DYLOAD
+/**
+ * Library management. Internal. 
+ * @internal
+ */
+struct UPlugLibrary;
+
+/**
+ * Library management. Internal. 
+ * @internal
+ */
+typedef struct UPlugLibrary {
+  void *lib;                           /**< library ptr */
+  char name[UPLUG_NAME_MAX]; /**< library name */
+  uint32_t ref;                        /**< reference count */
+} UPlugLibrary;
+
+static UPlugLibrary   staticLibraryList[UPLUG_LIBRARY_INITIAL_COUNT];
+static UPlugLibrary * libraryList = staticLibraryList;
+static int32_t libraryCount = 0;
+static int32_t libraryMax = UPLUG_LIBRARY_INITIAL_COUNT;
+
+/**
+ * Search for a library. Doesn't lock
+ * @param libName libname to search for
+ * @return the library's struct
+ */
+static int32_t searchForLibraryName(const char *libName) {
+  int32_t i;
+    
+  for(i=0;i<libraryCount;i++) {
+    if(!uprv_strcmp(libName, libraryList[i].name)) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+static int32_t searchForLibrary(void *lib) {
+  int32_t i;
+    
+  for(i=0;i<libraryCount;i++) {
+    if(lib==libraryList[i].lib) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+U_INTERNAL char * U_EXPORT2
+uplug_findLibrary(void *lib, UErrorCode *status) {
+  int32_t libEnt;
+  char *ret = NULL;
+  if(U_FAILURE(*status)) {
+    return NULL;
+  }
+  libEnt = searchForLibrary(lib);
+  if(libEnt!=-1) { 
+    ret = libraryList[libEnt].name;
+  } else {
+    *status = U_MISSING_RESOURCE_ERROR;
+  }
+  return ret;
+}
+
+U_INTERNAL void * U_EXPORT2
+uplug_openLibrary(const char *libName, UErrorCode *status) {
+  int32_t libEntry = -1;
+  void *lib = NULL;
+    
+  if(U_FAILURE(*status)) return NULL;
+
+  libEntry = searchForLibraryName(libName);
+  if(libEntry == -1) {
+    libEntry = libraryCount++;
+    if(libraryCount >= libraryMax) {
+      /* Ran out of library slots. Statically allocated because we can't depend on allocating memory.. */
+      *status = U_MEMORY_ALLOCATION_ERROR;
+#if UPLUG_TRACE
+      DBG((stderr, "uplug_openLibrary() - out of library slots (max %d)\n", libraryMax));
+#endif
+      return NULL;
+    }
+    /* Some operating systems don't want 
+       DL operations from multiple threads. */
+    libraryList[libEntry].lib = uprv_dl_open(libName, status);
+#if UPLUG_TRACE
+    DBG((stderr, "uplug_openLibrary(%s,%s) libEntry %d, lib %p\n", libName, u_errorName(*status), libEntry, lib));
+#endif
+        
+    if(libraryList[libEntry].lib == NULL || U_FAILURE(*status)) {
+      /* cleanup. */
+      libraryList[libEntry].lib = NULL; /* failure with open */
+      libraryList[libEntry].name[0] = 0;
+#if UPLUG_TRACE
+      DBG((stderr, "uplug_openLibrary(%s,%s) libEntry %d, lib %p\n", libName, u_errorName(*status), libEntry, lib));
+#endif
+      /* no need to free - just won't increase the count. */
+      libraryCount--;
+    } else { /* is it still there? */
+      /* link it in */
+      uprv_strncpy(libraryList[libEntry].name,libName,UPLUG_NAME_MAX);
+      libraryList[libEntry].ref=1;
+      lib = libraryList[libEntry].lib;
+    }
+
+  } else {
+    lib = libraryList[libEntry].lib;
+    libraryList[libEntry].ref++;
+  }
+  return lib;
+}
+
+U_INTERNAL void U_EXPORT2
+uplug_closeLibrary(void *lib, UErrorCode *status) {
+  int32_t i;
+    
+#if UPLUG_TRACE
+  DBG((stderr, "uplug_closeLibrary(%p,%s) list %p\n", lib, u_errorName(*status), (void*)libraryList));
+#endif
+  if(U_FAILURE(*status)) return;
+    
+  for(i=0;i<libraryCount;i++) {
+    if(lib==libraryList[i].lib) {
+      if(--(libraryList[i].ref) == 0) {
+        uprv_dl_close(libraryList[i].lib, status);
+        libraryCount = uplug_removeEntryAt(libraryList, libraryCount, sizeof(*libraryList), i);
+      }
+      return;
+    }
+  }
+  *status = U_INTERNAL_PROGRAM_ERROR; /* could not find the entry! */
+}
+
+#endif
+
+static UPlugData pluginList[UPLUG_PLUGIN_INITIAL_COUNT];
+static int32_t pluginCount = 0;
+
+
+
+  
+static int32_t uplug_pluginNumber(UPlugData* d) {
+  UPlugData *pastPlug = &pluginList[pluginCount];
+  if(d<=pluginList) {
+    return 0;
+  } else if(d>=pastPlug) {
+    return pluginCount;
+  } else {
+    return (d-pluginList)/sizeof(pluginList[0]);
+  }
+}
+
+
+U_CAPI UPlugData * U_EXPORT2
+uplug_nextPlug(UPlugData *prior) {
+  if(prior==NULL) {
+    return pluginList;
+  } else {
+    UPlugData *nextPlug = &prior[1];
+    UPlugData *pastPlug = &pluginList[pluginCount];
+    
+    if(nextPlug>=pastPlug) {
+      return NULL;
+    } else {
+      return nextPlug;
+    }
+  }
+}
+
+
+
+/**
+ * Call the plugin with some params
+ */
+static void uplug_callPlug(UPlugData *plug, UPlugReason reason, UErrorCode *status) {
+  UPlugTokenReturn token;
+  if(plug==NULL||U_FAILURE(*status)) {
+    return;
+  }
+  token = (*(plug->entrypoint))(plug, reason, status);
+  if(token!=UPLUG_TOKEN) {
+    *status = U_INTERNAL_PROGRAM_ERROR;
+  }
+}
+
+
+static void uplug_unloadPlug(UPlugData *plug, UErrorCode *status) {
+  if(plug->awaitingLoad) {  /* shouldn't happen. Plugin hasn'tbeen loaded yet.*/
+    *status = U_INTERNAL_PROGRAM_ERROR;
+    return; 
+  }
+  if(U_SUCCESS(plug->pluginStatus)) {
+    /* Don't unload a plug which has a failing load status - means it didn't actually load. */
+    uplug_callPlug(plug, UPLUG_REASON_UNLOAD, status);
+  }
+}
+
+static void uplug_queryPlug(UPlugData *plug, UErrorCode *status) {
+  if(!plug->awaitingLoad || !(plug->level == UPLUG_LEVEL_UNKNOWN) ) {  /* shouldn't happen. Plugin hasn'tbeen loaded yet.*/
+    *status = U_INTERNAL_PROGRAM_ERROR;
+    return; 
+  }
+  plug->level = UPLUG_LEVEL_INVALID;
+  uplug_callPlug(plug, UPLUG_REASON_QUERY, status);
+  if(U_SUCCESS(*status)) { 
+    if(plug->level == UPLUG_LEVEL_INVALID) {
+      plug->pluginStatus = U_PLUGIN_DIDNT_SET_LEVEL;
+      plug->awaitingLoad = FALSE;
+    }
+  } else {
+    plug->pluginStatus = U_INTERNAL_PROGRAM_ERROR;
+    plug->awaitingLoad = FALSE;
+  }
+}
+
+
+static void uplug_loadPlug(UPlugData *plug, UErrorCode *status) {
+  if(!plug->awaitingLoad || (plug->level < UPLUG_LEVEL_LOW) ) {  /* shouldn't happen. Plugin hasn'tbeen loaded yet.*/
+    *status = U_INTERNAL_PROGRAM_ERROR;
+    return;
+  }
+  uplug_callPlug(plug, UPLUG_REASON_LOAD, status);
+  plug->awaitingLoad = FALSE;
+  if(!U_SUCCESS(*status)) {
+    plug->pluginStatus = U_INTERNAL_PROGRAM_ERROR;
+  }
+}
+
+static UPlugData *uplug_allocateEmptyPlug(UErrorCode *status)
+{
+  UPlugData *plug = NULL;
+
+  if(U_FAILURE(*status)) {
+    return NULL;
+  }
+
+  if(pluginCount == UPLUG_PLUGIN_INITIAL_COUNT) {
+    *status = U_MEMORY_ALLOCATION_ERROR;
+    return NULL;
+  }
+
+  plug = &pluginList[pluginCount++];
+
+  plug->token = UPLUG_TOKEN;
+  plug->structSize = sizeof(UPlugData);
+  plug->name[0]=0;
+  plug->level = UPLUG_LEVEL_UNKNOWN; /* initialize to null state */
+  plug->awaitingLoad = TRUE;
+  plug->dontUnload = FALSE;
+  plug->pluginStatus = U_ZERO_ERROR;
+  plug->libName[0] = 0;
+  plug->config[0]=0;
+  plug->sym[0]=0;
+  plug->lib=NULL;
+  plug->entrypoint=NULL;
+
+
+  return plug;
+}
+
+static UPlugData *uplug_allocatePlug(UPlugEntrypoint *entrypoint, const char *config, void *lib, const char *symName,
+                                     UErrorCode *status) {
+  UPlugData *plug;
+
+  if(U_FAILURE(*status)) {
+    return NULL;
+  }
+
+  plug = uplug_allocateEmptyPlug(status);
+  if(config!=NULL) {
+    uprv_strncpy(plug->config, config, UPLUG_NAME_MAX);
+  } else {
+    plug->config[0] = 0;
+  }
+    
+  if(symName!=NULL) {
+    uprv_strncpy(plug->sym, symName, UPLUG_NAME_MAX);
+  } else {
+    plug->sym[0] = 0;
+  }
+    
+  plug->entrypoint = entrypoint;
+  plug->lib = lib;
+  uplug_queryPlug(plug, status);
+    
+  return plug;
+}
+
+static void uplug_deallocatePlug(UPlugData *plug, UErrorCode *status) {
+  UErrorCode subStatus = U_ZERO_ERROR;
+  if(!plug->dontUnload) {
+#if U_ENABLE_DYLOAD
+    uplug_closeLibrary(plug->lib, &subStatus);
+#endif
+  }
+  plug->lib = NULL;
+  if(U_SUCCESS(*status) && U_FAILURE(subStatus)) {
+    *status = subStatus;
+  }
+  /* shift plugins up and decrement count. */
+  if(U_SUCCESS(*status)) {
+    /* all ok- remove. */
+    pluginCount = uplug_removeEntryAt(pluginList, pluginCount, sizeof(plug[0]), uplug_pluginNumber(plug));
+  } else {
+    /* not ok- leave as a message. */
+    plug->awaitingLoad=FALSE;
+    plug->entrypoint=0;
+    plug->dontUnload=TRUE;
+  }
+}
+
+static void uplug_doUnloadPlug(UPlugData *plugToRemove, UErrorCode *status) {
+  if(plugToRemove != NULL) {
+    uplug_unloadPlug(plugToRemove, status);
+    uplug_deallocatePlug(plugToRemove, status);
+  }
+}
+
+U_CAPI void U_EXPORT2
+uplug_removePlug(UPlugData *plug, UErrorCode *status)  {
+  UPlugData *cursor = NULL;
+  UPlugData *plugToRemove = NULL;
+  if(U_FAILURE(*status)) return;
+    
+  for(cursor=pluginList;cursor!=NULL;) {
+    if(cursor==plug) {
+      plugToRemove = plug;
+      cursor=NULL;
+    } else {
+      cursor = uplug_nextPlug(cursor);
+    }
+  }
+    
+  uplug_doUnloadPlug(plugToRemove, status);
+}
+
+
+
+
+U_CAPI void U_EXPORT2 
+uplug_setPlugNoUnload(UPlugData *data, UBool dontUnload)
+{
+  data->dontUnload = dontUnload;
+}
+
+
+U_CAPI void U_EXPORT2
+uplug_setPlugLevel(UPlugData *data, UPlugLevel level) {
+  data->level = level;
+}
+
+
+U_CAPI UPlugLevel U_EXPORT2
+uplug_getPlugLevel(UPlugData *data) {
+  return data->level;
+}
+
+
+U_CAPI void U_EXPORT2
+uplug_setPlugName(UPlugData *data, const char *name) {
+  uprv_strncpy(data->name, name, UPLUG_NAME_MAX);
+}
+
+
+U_CAPI const char * U_EXPORT2
+uplug_getPlugName(UPlugData *data) {
+  return data->name;
+}
+
+
+U_CAPI const char * U_EXPORT2
+uplug_getSymbolName(UPlugData *data) {
+  return data->sym;
+}
+
+U_CAPI const char * U_EXPORT2
+uplug_getLibraryName(UPlugData *data, UErrorCode *status) {
+  if(data->libName[0]) {
+    return data->libName;
+  } else {
+#if U_ENABLE_DYLOAD
+    return uplug_findLibrary(data->lib, status);
+#else
+    return NULL;
+#endif
+  }
+}
+
+U_CAPI void * U_EXPORT2
+uplug_getLibrary(UPlugData *data) {
+  return data->lib;
+}
+
+U_CAPI void * U_EXPORT2
+uplug_getContext(UPlugData *data) {
+  return data->context;
+}
+
+
+U_CAPI void U_EXPORT2
+uplug_setContext(UPlugData *data, void *context) {
+  data->context = context;
+}
+
+U_CAPI const char* U_EXPORT2
+uplug_getConfiguration(UPlugData *data) {
+  return data->config;
+}
+
+U_INTERNAL UPlugData* U_EXPORT2
+uplug_getPlugInternal(int32_t n) { 
+  if(n <0 || n >= pluginCount) {
+    return NULL;
+  } else { 
+    return &(pluginList[n]);
+  }
+}
+
+
+U_CAPI UErrorCode U_EXPORT2
+uplug_getPlugLoadStatus(UPlugData *plug) {
+  return plug->pluginStatus;
+}
+
+
+
+
+/**
+ * Initialize a plugin fron an entrypoint and library - but don't load it.
+ */
+static UPlugData* uplug_initPlugFromEntrypointAndLibrary(UPlugEntrypoint *entrypoint, const char *config, void *lib, const char *sym,
+                                                         UErrorCode *status) {
+  UPlugData *plug = NULL;
+
+  plug = uplug_allocatePlug(entrypoint, config, lib, sym, status);
+
+  if(U_SUCCESS(*status)) {
+    return plug;
+  } else {
+    uplug_deallocatePlug(plug, status);
+    return NULL;
+  }
+}
+
+U_CAPI UPlugData* U_EXPORT2
+uplug_loadPlugFromEntrypoint(UPlugEntrypoint *entrypoint, const char *config, UErrorCode *status) {
+  UPlugData* plug = uplug_initPlugFromEntrypointAndLibrary(entrypoint, config, NULL, NULL, status);
+  uplug_loadPlug(plug, status);
+  return plug;
+}
+
+
+static UPlugData* 
+uplug_initErrorPlug(const char *libName, const char *sym, const char *config, const char *nameOrError, UErrorCode loadStatus, UErrorCode *status)
+{
+  UPlugData *plug = uplug_allocateEmptyPlug(status);
+  if(U_FAILURE(*status)) return NULL;
+
+  plug->pluginStatus = loadStatus;
+  plug->awaitingLoad = FALSE; /* Won't load. */
+  plug->dontUnload = TRUE; /* cannot unload. */
+
+  if(sym!=NULL) {
+    uprv_strncpy(plug->sym, sym, UPLUG_NAME_MAX);
+  }
+
+  if(libName!=NULL) {
+    uprv_strncpy(plug->libName, libName, UPLUG_NAME_MAX);
+  }
+
+  if(nameOrError!=NULL) {
+    uprv_strncpy(plug->name, nameOrError, UPLUG_NAME_MAX);
+  }
+
+  if(config!=NULL) {
+    uprv_strncpy(plug->config, config, UPLUG_NAME_MAX);
+  }
+
+  return plug;
+}
+
+/**
+ * Fetch a plugin from DLL, and then initialize it from a library- but don't load it.
+ */
+
+#if U_ENABLE_DYLOAD
+
+static UPlugData* 
+uplug_initPlugFromLibrary(const char *libName, const char *sym, const char *config, UErrorCode *status) {
+  void *lib = NULL;
+  UPlugData *plug = NULL;
+  if(U_FAILURE(*status)) { return NULL; }
+  lib = uplug_openLibrary(libName, status);
+  if(lib!=NULL && U_SUCCESS(*status)) {
+    UPlugEntrypoint *entrypoint = NULL;
+    /*
+     * ISO forbids the following cast.
+     *  See: http://www.trilithium.com/johan/2004/12/problem-with-dlsym/ 
+     */
+    entrypoint = (UPlugEntrypoint*)uprv_dl_sym(lib, sym, status);
+      
+    if(entrypoint!=NULL&&U_SUCCESS(*status)) {
+      plug = uplug_initPlugFromEntrypointAndLibrary(entrypoint, config, lib, sym, status);
+      if(plug!=NULL&&U_SUCCESS(*status)) {
+        plug->lib = lib; /* plug takes ownership of library */
+        lib = NULL; /* library is now owned by plugin. */
+      }
+    } else {
+      UErrorCode subStatus = U_ZERO_ERROR;
+      plug = uplug_initErrorPlug(libName,sym,config,"ERROR: Could not load entrypoint",(lib==NULL)?U_MISSING_RESOURCE_ERROR:*status,&subStatus);
+    }
+    if(lib!=NULL) { /* still need to close the lib */
+      UErrorCode subStatus = U_ZERO_ERROR;
+      uplug_closeLibrary(lib, &subStatus); /* don't care here */
+    }
+  } else {
+    UErrorCode subStatus = U_ZERO_ERROR;
+    plug = uplug_initErrorPlug(libName,sym,config,"ERROR: could not load library",(lib==NULL)?U_MISSING_RESOURCE_ERROR:*status,&subStatus);
+  }
+  return plug;
+}
+
+U_CAPI UPlugData* U_EXPORT2
+uplug_loadPlugFromLibrary(const char *libName, const char *sym, const char *config, UErrorCode *status) { 
+  UPlugData *plug = NULL;
+  if(U_FAILURE(*status)) { return NULL; }
+  plug = uplug_initPlugFromLibrary(libName, sym, config, status);
+  uplug_loadPlug(plug, status);
+
+  return plug;
+}
+
+#endif
+
+U_CAPI UPlugLevel U_EXPORT2 uplug_getCurrentLevel() {
+  if(cmemory_inUse()) {
+    return UPLUG_LEVEL_HIGH;
+  } else {
+    return UPLUG_LEVEL_LOW;
+  }
+}
+
+static UBool U_CALLCONV uplug_cleanup(void)
+{
+  int32_t i;
+    
+  UPlugData *pluginToRemove;
+  /* cleanup plugs */
+  for(i=0;i<pluginCount;i++) {
+    UErrorCode subStatus = U_ZERO_ERROR;
+    pluginToRemove = &pluginList[i];
+    /* unload and deallocate */
+    uplug_doUnloadPlug(pluginToRemove, &subStatus);
+  }
+  /* close other held libs? */
+  return TRUE;
+}
+
+static void uplug_loadWaitingPlugs(UErrorCode *status) {
+  int32_t i;
+  UPlugLevel currentLevel = uplug_getCurrentLevel();
+    
+  if(U_FAILURE(*status)) {
+    return;
+  }
+#if UPLUG_TRACE
+  DBG((stderr,  "uplug_loadWaitingPlugs() Level: %d\n", currentLevel));
+#endif
+  /* pass #1: low level plugs */
+  for(i=0;i<pluginCount;i++) {
+    UErrorCode subStatus = U_ZERO_ERROR;
+    UPlugData *pluginToLoad = &pluginList[i];
+    if(pluginToLoad->awaitingLoad) {
+      if(pluginToLoad->level == UPLUG_LEVEL_LOW) {
+        if(currentLevel > UPLUG_LEVEL_LOW) {
+          pluginToLoad->pluginStatus = U_PLUGIN_TOO_HIGH;
+        } else {
+          UPlugLevel newLevel;
+          uplug_loadPlug(pluginToLoad, &subStatus);
+          newLevel = uplug_getCurrentLevel();
+          if(newLevel > currentLevel) {
+            pluginToLoad->pluginStatus = U_PLUGIN_CHANGED_LEVEL_WARNING;
+            currentLevel = newLevel;
+          }
+        }
+        pluginToLoad->awaitingLoad = FALSE;
+      } 
+    }
+  }
+  currentLevel = uplug_getCurrentLevel();
+    
+  for(i=0;i<pluginCount;i++) {
+    UErrorCode subStatus = U_ZERO_ERROR;
+    UPlugData *pluginToLoad = &pluginList[i];
+        
+    if(pluginToLoad->awaitingLoad) {
+      if(pluginToLoad->level == UPLUG_LEVEL_INVALID) { 
+        pluginToLoad->pluginStatus = U_PLUGIN_DIDNT_SET_LEVEL;
+      } else if(pluginToLoad->level == UPLUG_LEVEL_UNKNOWN) {
+        pluginToLoad->pluginStatus = U_INTERNAL_PROGRAM_ERROR;
+      } else {
+        uplug_loadPlug(pluginToLoad, &subStatus);
+      }
+      pluginToLoad->awaitingLoad = FALSE;
+    }
+  }
+    
+#if UPLUG_TRACE
+  DBG((stderr,  " Done Loading Plugs. Level: %d\n", (int32_t)uplug_getCurrentLevel()));
+#endif
+}
+
+#if U_ENABLE_DYLOAD
+/* Name of the plugin config file */
+static char plugin_file[2048] = "";
+#endif
+
+U_INTERNAL const char* U_EXPORT2
+uplug_getPluginFile() {
+#if U_ENABLE_DYLOAD
+  return plugin_file;
+#else
+  return NULL;
+#endif
+}
+
+
+U_CAPI void U_EXPORT2
+uplug_init(UErrorCode *status) {
+#if !U_ENABLE_DYLOAD
+  (void)status; /* unused */
+#else
+  const char *plugin_dir;
+
+  if(U_FAILURE(*status)) return;
+  plugin_dir = getenv("ICU_PLUGINS");
+
+#if defined(DEFAULT_ICU_PLUGINS) 
+  if(plugin_dir == NULL || !*plugin_dir) {
+    plugin_dir = DEFAULT_ICU_PLUGINS;
+  }
+#endif
+
+#if UPLUG_TRACE
+  DBG((stderr, "ICU_PLUGINS=%s\n", plugin_dir));
+#endif
+
+  if(plugin_dir != NULL && *plugin_dir) {
+    FILE *f;
+        
+        
+    uprv_strncpy(plugin_file, plugin_dir, 2047);
+    uprv_strncat(plugin_file, U_FILE_SEP_STRING,2047);
+    uprv_strncat(plugin_file, "icuplugins",2047);
+    uprv_strncat(plugin_file, U_ICU_VERSION_SHORT ,2047);
+    uprv_strncat(plugin_file, ".txt" ,2047);
+        
+#if UPLUG_TRACE
+    DBG((stderr, "pluginfile= %s\n", plugin_file));
+#endif
+        
+    f = fopen(plugin_file, "r");
+
+    if(f != NULL) {
+      char linebuf[1024];
+      char *p, *libName=NULL, *symName=NULL, *config=NULL;
+      int32_t line = 0;
+            
+            
+      while(fgets(linebuf,1023,f)) {
+        line++;
+
+        if(!*linebuf || *linebuf=='#') {
+          continue;
+        } else {
+          p = linebuf;
+          while(*p&&isspace(*p))
+            p++;
+          if(!*p || *p=='#') continue;
+          libName = p;
+          while(*p&&!isspace(*p)) {
+            p++;
+          }
+          if(!*p || *p=='#') continue; /* no tab after libname */
+          *p=0; /* end of libname */
+          p++;
+          while(*p&&isspace(*p)) {
+            p++;
+          }
+          if(!*p||*p=='#') continue; /* no symname after libname +tab */
+          symName = p;
+          while(*p&&!isspace(*p)) {
+            p++;
+          }
+                    
+          if(*p) { /* has config */
+            *p=0;
+            ++p;
+            while(*p&&isspace(*p)) {
+              p++;
+            }
+            if(*p) {
+              config = p;
+            }
+          }
+                    
+          /* chop whitespace at the end of the config */
+          if(config!=NULL&&*config!=0) {
+            p = config+strlen(config);
+            while(p>config&&isspace(*(--p))) {
+              *p=0;
+            }
+          }
+                
+          /* OK, we're good. */
+          { 
+            UErrorCode subStatus = U_ZERO_ERROR;
+            UPlugData *plug = uplug_initPlugFromLibrary(libName, symName, config, &subStatus);
+            if(U_FAILURE(subStatus) && U_SUCCESS(*status)) {
+              *status = subStatus;
+            }
+#if UPLUG_TRACE
+            DBG((stderr, "PLUGIN libName=[%s], sym=[%s], config=[%s]\n", libName, symName, config));
+            DBG((stderr, " -> %p, %s\n", (void*)plug, u_errorName(subStatus)));
+#else
+            (void)plug; /* unused */
+#endif
+          }
+        }
+      }
+    } else {
+#if UPLUG_TRACE
+      DBG((stderr, "Can't open plugin file %s\n", plugin_file));
+#endif
+    }
+  }
+  uplug_loadWaitingPlugs(status);
+#endif /* U_ENABLE_DYLOAD */
+  ucln_registerCleanup(UCLN_UPLUG, uplug_cleanup);
+}
diff --git a/source/common/icuplugimp.h b/source/common/icuplugimp.h
new file mode 100644
index 0000000..53b9c0c
--- /dev/null
+++ b/source/common/icuplugimp.h
@@ -0,0 +1,87 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2009-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+*  FILE NAME : icuplugimp.h
+* 
+*  Internal functions for the ICU plugin system
+*
+*   Date         Name        Description
+*   10/29/2009   sl          New.
+******************************************************************************
+*/
+
+
+#ifndef ICUPLUGIMP_H
+#define ICUPLUGIMP_H
+
+#include "unicode/icuplug.h"
+
+/*========================*/
+/** @{ Library Manipulation  
+ */
+
+/**
+ * Open a library, adding a reference count if needed.
+ * @param libName library name to load
+ * @param status error code
+ * @return the library pointer, or NULL
+ * @internal internal use only
+ */
+U_INTERNAL void * U_EXPORT2
+uplug_openLibrary(const char *libName, UErrorCode *status);
+
+/**
+ * Close a library, if its reference count is 0
+ * @param lib the library to close
+ * @param status error code
+ * @internal internal use only
+ */
+U_INTERNAL void U_EXPORT2
+uplug_closeLibrary(void *lib, UErrorCode *status);
+
+/**
+ * Get a library's name, or NULL if not found.
+ * @param lib the library's name
+ * @param status error code
+ * @return the library name, or NULL if not found.
+ * @internal internal use only
+ */
+U_INTERNAL  char * U_EXPORT2
+uplug_findLibrary(void *lib, UErrorCode *status);
+
+/** @} */
+
+/*========================*/
+/** {@ ICU Plugin internal interfaces
+ */
+
+/**
+ * Initialize the plugins 
+ * @param status error result
+ * @internal - Internal use only.
+ */
+U_INTERNAL void U_EXPORT2
+uplug_init(UErrorCode *status);
+
+/**
+ * Get raw plug N
+ * @internal - Internal use only
+ */ 
+U_INTERNAL UPlugData* U_EXPORT2
+uplug_getPlugInternal(int32_t n);
+
+/**
+ * Get the name of the plugin file. 
+ * @internal - Internal use only.
+ */
+U_INTERNAL const char* U_EXPORT2
+uplug_getPluginFile(void);
+
+/** @} */
+
+#endif
diff --git a/source/common/localsvc.h b/source/common/localsvc.h
new file mode 100644
index 0000000..67e5a84
--- /dev/null
+++ b/source/common/localsvc.h
@@ -0,0 +1,25 @@
+/*
+***************************************************************************
+*   Copyright (C) 2006 International Business Machines Corporation        *
+*   and others. All rights reserved.                                      *
+***************************************************************************
+*/
+
+#ifndef LOCALSVC_H
+#define LOCALSVC_H
+
+#include "unicode/utypes.h"
+
+#if U_LOCAL_SERVICE_HOOK
+/**
+ * Prototype for user-supplied service hook. This function is expected to return
+ * a type of factory object specific to the requested service.
+ * 
+ * @param what service-specific string identifying the specific user hook
+ * @param status error status
+ * @return a service-specific hook, or NULL on failure.
+ */
+U_CAPI void* uprv_svc_hook(const char *what, UErrorCode *status);
+#endif
+
+#endif
diff --git a/source/common/locavailable.cpp b/source/common/locavailable.cpp
new file mode 100644
index 0000000..7060a68
--- /dev/null
+++ b/source/common/locavailable.cpp
@@ -0,0 +1,187 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  locavailable.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2010feb25
+*   created by: Markus W. Scherer
+*
+*   Code for available locales, separated out from other .cpp files
+*   that then do not depend on resource bundle code and res_index bundles.
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/locid.h"
+#include "unicode/uloc.h"
+#include "unicode/ures.h"
+#include "cmemory.h"
+#include "ucln_cmn.h"
+#include "umutex.h"
+#include "uresimp.h"
+
+// C++ API ----------------------------------------------------------------- ***
+
+static U_NAMESPACE_QUALIFIER Locale*  availableLocaleList = NULL;
+static int32_t  availableLocaleListCount;
+
+U_CDECL_BEGIN
+
+static UBool U_CALLCONV locale_available_cleanup(void)
+{
+    U_NAMESPACE_USE
+
+    if (availableLocaleList) {
+        delete []availableLocaleList;
+        availableLocaleList = NULL;
+    }
+    availableLocaleListCount = 0;
+
+    return TRUE;
+}
+
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+const Locale* U_EXPORT2
+Locale::getAvailableLocales(int32_t& count)
+{
+    // 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) {
+        int32_t locCount = uloc_countAvailable();
+        Locale *newLocaleList = 0;
+        if(locCount) {
+           newLocaleList = new Locale[locCount];
+        }
+        if (newLocaleList == NULL) {
+            count = 0;
+            return NULL;
+        }
+
+        count = locCount;
+
+        while(--locCount >= 0) {
+            newLocaleList[locCount].setFromPOSIXID(uloc_getAvailable(locCount));
+        }
+
+        umtx_lock(NULL);
+        if(availableLocaleList == 0) {
+            availableLocaleListCount = count;
+            availableLocaleList = newLocaleList;
+            newLocaleList = NULL;
+            ucln_common_registerCleanup(UCLN_COMMON_LOCALE_AVAILABLE, locale_available_cleanup);
+        }
+        umtx_unlock(NULL);
+        delete []newLocaleList;
+    }
+    count = availableLocaleListCount;
+    return availableLocaleList;
+}
+
+
+U_NAMESPACE_END
+
+// C API ------------------------------------------------------------------- ***
+
+U_NAMESPACE_USE
+
+/* ### Constants **************************************************/
+
+/* These strings describe the resources we attempt to load from
+ the locale ResourceBundle data file.*/
+static const char _kIndexLocaleName[] = "res_index";
+static const char _kIndexTag[]        = "InstalledLocales";
+
+static char** _installedLocales = NULL;
+static int32_t _installedLocalesCount = 0;
+
+/* ### Get available **************************************************/
+
+static UBool U_CALLCONV uloc_cleanup(void) {
+    char ** temp;
+
+    if (_installedLocales) {
+        temp = _installedLocales;
+        _installedLocales = NULL;
+
+        _installedLocalesCount = 0;
+
+        uprv_free(temp);
+    }
+    return TRUE;
+}
+
+static void _load_installedLocales()
+{
+    UBool   localesLoaded;
+
+    UMTX_CHECK(NULL, _installedLocales != NULL, localesLoaded);
+    
+    if (localesLoaded == FALSE) {
+        UResourceBundle *indexLocale = NULL;
+        UResourceBundle installed;
+        UErrorCode status = U_ZERO_ERROR;
+        char ** temp;
+        int32_t i = 0;
+        int32_t localeCount;
+        
+        ures_initStackObject(&installed);
+        indexLocale = ures_openDirect(NULL, _kIndexLocaleName, &status);
+        ures_getByKey(indexLocale, _kIndexTag, &installed, &status);
+        
+        if(U_SUCCESS(status)) {
+            localeCount = ures_getSize(&installed);
+            temp = (char **) uprv_malloc(sizeof(char*) * (localeCount+1));
+            /* Check for null pointer */
+            if (temp != NULL) {
+                ures_resetIterator(&installed);
+                while(ures_hasNext(&installed)) {
+                    ures_getNextString(&installed, NULL, (const char **)&temp[i++], &status);
+                }
+                temp[i] = NULL;
+
+                umtx_lock(NULL);
+                if (_installedLocales == NULL)
+                {
+                    _installedLocalesCount = localeCount;
+                    _installedLocales = temp;
+                    temp = NULL;
+                    ucln_common_registerCleanup(UCLN_COMMON_ULOC, uloc_cleanup);
+                } 
+                umtx_unlock(NULL);
+
+                uprv_free(temp);
+            }
+        }
+        ures_close(&installed);
+        ures_close(indexLocale);
+    }
+}
+
+U_CAPI const char* U_EXPORT2
+uloc_getAvailable(int32_t offset) 
+{
+    
+    _load_installedLocales();
+    
+    if (offset > _installedLocalesCount)
+        return NULL;
+    return _installedLocales[offset];
+}
+
+U_CAPI int32_t  U_EXPORT2
+uloc_countAvailable()
+{
+    _load_installedLocales();
+    return _installedLocalesCount;
+}
diff --git a/source/common/locbased.cpp b/source/common/locbased.cpp
new file mode 100644
index 0000000..e96b9f7
--- /dev/null
+++ b/source/common/locbased.cpp
@@ -0,0 +1,46 @@
+/*
+**********************************************************************
+* Copyright (c) 2004, International Business Machines
+* Corporation and others.  All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: January 16 2004
+* Since: ICU 2.8
+**********************************************************************
+*/
+#include "locbased.h"
+#include "cstring.h"
+
+U_NAMESPACE_BEGIN
+
+Locale LocaleBased::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
+    const char* id = getLocaleID(type, status);
+    return Locale((id != 0) ? id : "");
+}
+
+const char* LocaleBased::getLocaleID(ULocDataLocaleType type, UErrorCode& status) const {
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+
+    switch(type) {
+    case ULOC_VALID_LOCALE:
+        return valid;
+    case ULOC_ACTUAL_LOCALE:
+        return actual;
+    default:
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+}
+
+void LocaleBased::setLocaleIDs(const char* validID, const char* actualID) {
+    if (validID != 0) {
+        uprv_strcpy(valid, validID);
+    }
+    if (actualID != 0) {
+        uprv_strcpy(actual, actualID);
+    }
+}
+
+U_NAMESPACE_END
diff --git a/source/common/locbased.h b/source/common/locbased.h
new file mode 100644
index 0000000..366b151
--- /dev/null
+++ b/source/common/locbased.h
@@ -0,0 +1,97 @@
+/*
+**********************************************************************
+* Copyright (c) 2004, International Business Machines
+* Corporation and others.  All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: January 16 2004
+* Since: ICU 2.8
+**********************************************************************
+*/
+#ifndef LOCBASED_H
+#define LOCBASED_H
+
+#include "unicode/locid.h"
+#include "unicode/uobject.h"
+
+/**
+ * Macro to declare a locale LocaleBased wrapper object for the given
+ * object, which must have two members named `validLocale' and
+ * `actualLocale'.
+ */
+#define U_LOCALE_BASED(varname, objname) \
+  LocaleBased varname((objname).validLocale, (objname).actualLocale);
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A utility class that unifies the implementation of getLocale() by
+ * various ICU services.  This class is likely to be removed in the
+ * ICU 3.0 time frame in favor of an integrated approach with the
+ * services framework.
+ * @since ICU 2.8
+ */
+class U_COMMON_API LocaleBased : public UMemory {
+
+ public:
+
+    /**
+     * Construct a LocaleBased wrapper around the two pointers.  These
+     * will be aliased for the lifetime of this object.
+     */
+    inline LocaleBased(char* validAlias, char* actualAlias);
+
+    /**
+     * Construct a LocaleBased wrapper around the two const pointers.
+     * These will be aliased for the lifetime of this object.
+     */
+    inline LocaleBased(const char* validAlias, const char* actualAlias);
+
+    /**
+     * Return locale meta-data for the service object wrapped by this
+     * object.  Either the valid or the actual locale may be
+     * retrieved.
+     * @param type either ULOC_VALID_LOCALE or ULOC_ACTUAL_LOCALE
+     * @param status input-output error code
+     * @return the indicated locale
+     */
+    Locale getLocale(ULocDataLocaleType type, UErrorCode& status) const;
+
+    /**
+     * Return the locale ID for the service object wrapped by this
+     * object.  Either the valid or the actual locale may be
+     * retrieved.
+     * @param type either ULOC_VALID_LOCALE or ULOC_ACTUAL_LOCALE
+     * @param status input-output error code
+     * @return the indicated locale ID
+     */
+    const char* getLocaleID(ULocDataLocaleType type, UErrorCode& status) const;
+
+    /**
+     * Set the locale meta-data for the service object wrapped by this
+     * object.  If either parameter is zero, it is ignored.
+     * @param valid the ID of the valid locale
+     * @param actual the ID of the actual locale
+     */
+    void setLocaleIDs(const char* valid, const char* actual);
+
+ private:
+
+    char* valid;
+    
+    char* actual;
+};
+
+inline LocaleBased::LocaleBased(char* validAlias, char* actualAlias) :
+    valid(validAlias), actual(actualAlias) {
+}
+
+inline LocaleBased::LocaleBased(const char* validAlias,
+                                const char* actualAlias) :
+    // ugh: cast away const
+    valid((char*)validAlias), actual((char*)actualAlias) {
+}
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/locdispnames.cpp b/source/common/locdispnames.cpp
new file mode 100644
index 0000000..c3362d3
--- /dev/null
+++ b/source/common/locdispnames.cpp
@@ -0,0 +1,824 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  locdispnames.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2010feb25
+*   created by: Markus W. Scherer
+*
+*   Code for locale display names, separated out from other .cpp files
+*   that then do not depend on resource bundle code and display name data.
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/brkiter.h"
+#include "unicode/locid.h"
+#include "unicode/uloc.h"
+#include "unicode/ures.h"
+#include "unicode/ustring.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "putilimp.h"
+#include "ulocimp.h"
+#include "uresimp.h"
+#include "ureslocs.h"
+#include "ustr_imp.h"
+
+// C++ API ----------------------------------------------------------------- ***
+
+U_NAMESPACE_BEGIN
+
+UnicodeString&
+Locale::getDisplayLanguage(UnicodeString& dispLang) const
+{
+    return this->getDisplayLanguage(getDefault(), dispLang);
+}
+
+/*We cannot make any assumptions on the size of the output display strings
+* Yet, since we are calling through to a C API, we need to set limits on
+* buffer size. For all the following getDisplay functions we first attempt
+* to fill up a stack allocated buffer. If it is to small we heap allocated
+* the exact buffer we need copy it to the UnicodeString and delete it*/
+
+UnicodeString&
+Locale::getDisplayLanguage(const Locale &displayLocale,
+                           UnicodeString &result) const {
+    UChar *buffer;
+    UErrorCode errorCode=U_ZERO_ERROR;
+    int32_t length;
+
+    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
+    if(buffer==0) {
+        result.truncate(0);
+        return result;
+    }
+
+    length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
+                                   buffer, result.getCapacity(),
+                                   &errorCode);
+    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
+
+    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
+        buffer=result.getBuffer(length);
+        if(buffer==0) {
+            result.truncate(0);
+            return result;
+        }
+        errorCode=U_ZERO_ERROR;
+        length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
+                                       buffer, result.getCapacity(),
+                                       &errorCode);
+        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
+    }
+
+    return result;
+}
+
+UnicodeString&
+Locale::getDisplayScript(UnicodeString& dispScript) const
+{
+    return this->getDisplayScript(getDefault(), dispScript);
+}
+
+UnicodeString&
+Locale::getDisplayScript(const Locale &displayLocale,
+                          UnicodeString &result) const {
+    UChar *buffer;
+    UErrorCode errorCode=U_ZERO_ERROR;
+    int32_t length;
+
+    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
+    if(buffer==0) {
+        result.truncate(0);
+        return result;
+    }
+
+    length=uloc_getDisplayScript(fullName, displayLocale.fullName,
+                                  buffer, result.getCapacity(),
+                                  &errorCode);
+    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
+
+    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
+        buffer=result.getBuffer(length);
+        if(buffer==0) {
+            result.truncate(0);
+            return result;
+        }
+        errorCode=U_ZERO_ERROR;
+        length=uloc_getDisplayScript(fullName, displayLocale.fullName,
+                                      buffer, result.getCapacity(),
+                                      &errorCode);
+        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
+    }
+
+    return result;
+}
+
+UnicodeString&
+Locale::getDisplayCountry(UnicodeString& dispCntry) const
+{
+    return this->getDisplayCountry(getDefault(), dispCntry);
+}
+
+UnicodeString&
+Locale::getDisplayCountry(const Locale &displayLocale,
+                          UnicodeString &result) const {
+    UChar *buffer;
+    UErrorCode errorCode=U_ZERO_ERROR;
+    int32_t length;
+
+    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
+    if(buffer==0) {
+        result.truncate(0);
+        return result;
+    }
+
+    length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
+                                  buffer, result.getCapacity(),
+                                  &errorCode);
+    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
+
+    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
+        buffer=result.getBuffer(length);
+        if(buffer==0) {
+            result.truncate(0);
+            return result;
+        }
+        errorCode=U_ZERO_ERROR;
+        length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
+                                      buffer, result.getCapacity(),
+                                      &errorCode);
+        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
+    }
+
+    return result;
+}
+
+UnicodeString&
+Locale::getDisplayVariant(UnicodeString& dispVar) const
+{
+    return this->getDisplayVariant(getDefault(), dispVar);
+}
+
+UnicodeString&
+Locale::getDisplayVariant(const Locale &displayLocale,
+                          UnicodeString &result) const {
+    UChar *buffer;
+    UErrorCode errorCode=U_ZERO_ERROR;
+    int32_t length;
+
+    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
+    if(buffer==0) {
+        result.truncate(0);
+        return result;
+    }
+
+    length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
+                                  buffer, result.getCapacity(),
+                                  &errorCode);
+    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
+
+    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
+        buffer=result.getBuffer(length);
+        if(buffer==0) {
+            result.truncate(0);
+            return result;
+        }
+        errorCode=U_ZERO_ERROR;
+        length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
+                                      buffer, result.getCapacity(),
+                                      &errorCode);
+        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
+    }
+
+    return result;
+}
+
+UnicodeString&
+Locale::getDisplayName( UnicodeString& name ) const
+{
+    return this->getDisplayName(getDefault(), name);
+}
+
+UnicodeString&
+Locale::getDisplayName(const Locale &displayLocale,
+                       UnicodeString &result) const {
+    UChar *buffer;
+    UErrorCode errorCode=U_ZERO_ERROR;
+    int32_t length;
+
+    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
+    if(buffer==0) {
+        result.truncate(0);
+        return result;
+    }
+
+    length=uloc_getDisplayName(fullName, displayLocale.fullName,
+                               buffer, result.getCapacity(),
+                               &errorCode);
+    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
+
+    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
+        buffer=result.getBuffer(length);
+        if(buffer==0) {
+            result.truncate(0);
+            return result;
+        }
+        errorCode=U_ZERO_ERROR;
+        length=uloc_getDisplayName(fullName, displayLocale.fullName,
+                                   buffer, result.getCapacity(),
+                                   &errorCode);
+        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
+    }
+
+    return result;
+}
+
+#if ! UCONFIG_NO_BREAK_ITERATION
+
+// -------------------------------------
+// Gets the objectLocale display name in the default locale language.
+UnicodeString& U_EXPORT2
+BreakIterator::getDisplayName(const Locale& objectLocale,
+                             UnicodeString& name)
+{
+    return objectLocale.getDisplayName(name);
+}
+
+// -------------------------------------
+// Gets the objectLocale display name in the displayLocale language.
+UnicodeString& U_EXPORT2
+BreakIterator::getDisplayName(const Locale& objectLocale,
+                             const Locale& displayLocale,
+                             UnicodeString& name)
+{
+    return objectLocale.getDisplayName(displayLocale, name);
+}
+
+#endif
+
+
+U_NAMESPACE_END
+
+// C API ------------------------------------------------------------------- ***
+
+U_NAMESPACE_USE
+
+/* ### Constants **************************************************/
+
+/* These strings describe the resources we attempt to load from
+ the locale ResourceBundle data file.*/
+static const char _kLanguages[]       = "Languages";
+static const char _kScripts[]         = "Scripts";
+static const char _kCountries[]       = "Countries";
+static const char _kVariants[]        = "Variants";
+static const char _kKeys[]            = "Keys";
+static const char _kTypes[]           = "Types";
+static const char _kRootName[]        = "root";
+static const char _kCurrency[]        = "currency";
+static const char _kCurrencies[]      = "Currencies";
+static const char _kLocaleDisplayPattern[] = "localeDisplayPattern";
+static const char _kPattern[]         = "pattern";
+static const char _kSeparator[]       = "separator";
+
+/* ### Display name **************************************************/
+
+static int32_t
+_getStringOrCopyKey(const char *path, const char *locale,
+                    const char *tableKey, 
+                    const char* subTableKey,
+                    const char *itemKey,
+                    const char *substitute,
+                    UChar *dest, int32_t destCapacity,
+                    UErrorCode *pErrorCode) {
+    const UChar *s = NULL;
+    int32_t length = 0;
+
+    if(itemKey==NULL) {
+        /* top-level item: normal resource bundle access */
+        UResourceBundle *rb;
+
+        rb=ures_open(path, locale, pErrorCode);
+
+        if(U_SUCCESS(*pErrorCode)) {
+            s=ures_getStringByKey(rb, tableKey, &length, pErrorCode);
+            /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */
+            ures_close(rb);
+        }
+    } else {
+        /* Language code should not be a number. If it is, set the error code. */
+        if (!uprv_strncmp(tableKey, "Languages", 9) && uprv_strtol(itemKey, NULL, 10)) {
+            *pErrorCode = U_MISSING_RESOURCE_ERROR;
+        } else {
+            /* second-level item, use special fallback */
+            s=uloc_getTableStringWithFallback(path, locale,
+                                               tableKey, 
+                                               subTableKey,
+                                               itemKey,
+                                               &length,
+                                               pErrorCode);
+        }
+    }
+
+    if(U_SUCCESS(*pErrorCode)) {
+        int32_t copyLength=uprv_min(length, destCapacity);
+        if(copyLength>0 && s != NULL) {
+            u_memcpy(dest, s, copyLength);
+        }
+    } else {
+        /* no string from a resource bundle: convert the substitute */
+        length=(int32_t)uprv_strlen(substitute);
+        u_charsToUChars(substitute, dest, uprv_min(length, destCapacity));
+        *pErrorCode=U_USING_DEFAULT_WARNING;
+    }
+
+    return u_terminateUChars(dest, destCapacity, length, pErrorCode);
+}
+
+typedef  int32_t U_CALLCONV UDisplayNameGetter(const char *, char *, int32_t, UErrorCode *);
+
+static int32_t
+_getDisplayNameForComponent(const char *locale,
+                            const char *displayLocale,
+                            UChar *dest, int32_t destCapacity,
+                            UDisplayNameGetter *getter,
+                            const char *tag,
+                            UErrorCode *pErrorCode) {
+    char localeBuffer[ULOC_FULLNAME_CAPACITY*4];
+    int32_t length;
+    UErrorCode localStatus;
+    const char* root = NULL;
+
+    /* argument checking */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    localStatus = U_ZERO_ERROR;
+    length=(*getter)(locale, localeBuffer, sizeof(localeBuffer), &localStatus);
+    if(U_FAILURE(localStatus) || localStatus==U_STRING_NOT_TERMINATED_WARNING) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    if(length==0) {
+        return u_terminateUChars(dest, destCapacity, 0, pErrorCode);
+    }
+
+    root = tag == _kCountries ? U_ICUDATA_REGION : U_ICUDATA_LANG;
+
+    return _getStringOrCopyKey(root, displayLocale,
+                               tag, NULL, localeBuffer,
+                               localeBuffer,
+                               dest, destCapacity,
+                               pErrorCode);
+}
+
+U_CAPI int32_t U_EXPORT2
+uloc_getDisplayLanguage(const char *locale,
+                        const char *displayLocale,
+                        UChar *dest, int32_t destCapacity,
+                        UErrorCode *pErrorCode) {
+    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
+                uloc_getLanguage, _kLanguages, pErrorCode);
+}
+
+U_CAPI int32_t U_EXPORT2
+uloc_getDisplayScript(const char* locale,
+                      const char* displayLocale,
+                      UChar *dest, int32_t destCapacity,
+                      UErrorCode *pErrorCode)
+{
+    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
+                uloc_getScript, _kScripts, pErrorCode);
+}
+
+U_CAPI int32_t U_EXPORT2
+uloc_getDisplayCountry(const char *locale,
+                       const char *displayLocale,
+                       UChar *dest, int32_t destCapacity,
+                       UErrorCode *pErrorCode) {
+    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
+                uloc_getCountry, _kCountries, pErrorCode);
+}
+
+/*
+ * TODO separate variant1_variant2_variant3...
+ * by getting each tag's display string and concatenating them with ", "
+ * in between - similar to uloc_getDisplayName()
+ */
+U_CAPI int32_t U_EXPORT2
+uloc_getDisplayVariant(const char *locale,
+                       const char *displayLocale,
+                       UChar *dest, int32_t destCapacity,
+                       UErrorCode *pErrorCode) {
+    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
+                uloc_getVariant, _kVariants, pErrorCode);
+}
+
+U_CAPI int32_t U_EXPORT2
+uloc_getDisplayName(const char *locale,
+                    const char *displayLocale,
+                    UChar *dest, int32_t destCapacity,
+                    UErrorCode *pErrorCode)
+{
+    int32_t length, length2, length3 = 0;
+    UBool hasLanguage, hasScript, hasCountry, hasVariant, hasKeywords;
+    UEnumeration* keywordEnum = NULL;
+    int32_t keywordCount = 0;
+    const char *keyword = NULL;
+    int32_t keywordLen = 0;
+    char keywordValue[256];
+    int32_t keywordValueLen = 0;
+
+    int32_t locSepLen = 0;
+    int32_t locPatLen = 0;
+    int32_t p0Len = 0;
+    int32_t defaultPatternLen = 9;
+    const UChar *dispLocSeparator;
+    const UChar *dispLocPattern;
+    static const UChar defaultSeparator[3] = { 0x002c, 0x0020 , 0x0000 }; /* comma + space */
+    static const UChar defaultPattern[10] = { 0x007b, 0x0030, 0x007d, 0x0020, 0x0028, 0x007b, 0x0031, 0x007d, 0x0029, 0x0000 }; /* {0} ({1}) */
+    static const UChar pat0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 } ; /* {0} */
+    static const UChar pat1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 } ; /* {1} */
+    
+    UResourceBundle *bundle = NULL;
+    UResourceBundle *locdsppat = NULL;
+    
+    UErrorCode status = U_ZERO_ERROR;
+
+    /* argument checking */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    bundle    = ures_open(U_ICUDATA_LANG, displayLocale, &status);
+
+    locdsppat = ures_getByKeyWithFallback(bundle, _kLocaleDisplayPattern, NULL, &status);
+    dispLocSeparator = ures_getStringByKeyWithFallback(locdsppat, _kSeparator, &locSepLen, &status);
+    dispLocPattern = ures_getStringByKeyWithFallback(locdsppat, _kPattern, &locPatLen, &status);
+        
+    /*close the bundles */
+    ures_close(locdsppat);
+    ures_close(bundle);
+
+    /* If we couldn't find any data, then use the defaults */
+    if ( locSepLen == 0) {
+       dispLocSeparator = defaultSeparator;
+       locSepLen = 2;
+    }
+
+    if ( locPatLen == 0) {
+       dispLocPattern = defaultPattern;
+       locPatLen = 9;
+    }
+
+    /*
+     * if there is a language, then write "language (country, variant)"
+     * otherwise write "country, variant"
+     */
+
+    /* write the language */
+    length=uloc_getDisplayLanguage(locale, displayLocale,
+                                   dest, destCapacity,
+                                   pErrorCode);
+    hasLanguage= length>0;
+
+    if(hasLanguage) {
+        p0Len = length;
+
+        /* append " (" */
+        if(length<destCapacity) {
+            dest[length]=0x20;
+        }
+        ++length;
+        if(length<destCapacity) {
+            dest[length]=0x28;
+        }
+        ++length;
+    }
+
+    if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
+        /* keep preflighting */
+        *pErrorCode=U_ZERO_ERROR;
+    }
+
+    /* append the script */
+    if(length<destCapacity) {
+        length2=uloc_getDisplayScript(locale, displayLocale,
+                                       dest+length, destCapacity-length,
+                                       pErrorCode);
+    } else {
+        length2=uloc_getDisplayScript(locale, displayLocale,
+                                       NULL, 0,
+                                       pErrorCode);
+    }
+    hasScript= length2>0;
+    length+=length2;
+
+    if(hasScript) {
+        /* append separator */
+        if(length+locSepLen<=destCapacity) {
+            u_memcpy(dest+length,dispLocSeparator,locSepLen);
+        }
+        length+=locSepLen;
+    }
+
+    if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
+        /* keep preflighting */
+        *pErrorCode=U_ZERO_ERROR;
+    }
+
+    /* append the country */
+    if(length<destCapacity) {
+        length2=uloc_getDisplayCountry(locale, displayLocale,
+                                       dest+length, destCapacity-length,
+                                       pErrorCode);
+    } else {
+        length2=uloc_getDisplayCountry(locale, displayLocale,
+                                       NULL, 0,
+                                       pErrorCode);
+    }
+    hasCountry= length2>0;
+    length+=length2;
+
+    if(hasCountry) {
+        /* append separator */
+        if(length+locSepLen<=destCapacity) {
+            u_memcpy(dest+length,dispLocSeparator,locSepLen);
+        }
+        length+=locSepLen;
+    }
+
+    if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
+        /* keep preflighting */
+        *pErrorCode=U_ZERO_ERROR;
+    }
+
+    /* append the variant */
+    if(length<destCapacity) {
+        length2=uloc_getDisplayVariant(locale, displayLocale,
+                                       dest+length, destCapacity-length,
+                                       pErrorCode);
+    } else {
+        length2=uloc_getDisplayVariant(locale, displayLocale,
+                                       NULL, 0,
+                                       pErrorCode);
+    }
+    hasVariant= length2>0;
+    length+=length2;
+
+    if(hasVariant) {
+        /* append separator */
+        if(length+locSepLen<=destCapacity) {
+            u_memcpy(dest+length,dispLocSeparator,locSepLen);
+        }
+        length+=locSepLen;
+    }
+
+    keywordEnum = uloc_openKeywords(locale, pErrorCode);
+    
+    for(keywordCount = uenum_count(keywordEnum, pErrorCode); keywordCount > 0 ; keywordCount--){
+          if(U_FAILURE(*pErrorCode)){
+              break;
+          }
+          /* the uenum_next returns NUL terminated string */
+          keyword = uenum_next(keywordEnum, &keywordLen, pErrorCode);
+          if(length + length3 < destCapacity) {
+            length3 += uloc_getDisplayKeyword(keyword, displayLocale, dest+length+length3, destCapacity-length-length3, pErrorCode);
+          } else {
+            length3 += uloc_getDisplayKeyword(keyword, displayLocale, NULL, 0, pErrorCode);
+          }
+          if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
+              /* keep preflighting */
+              *pErrorCode=U_ZERO_ERROR;
+          }
+          keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, 256, pErrorCode);
+          if(keywordValueLen) {
+            if(length + length3 < destCapacity) {
+              dest[length + length3] = 0x3D;
+            }
+            length3++;
+            if(length + length3 < destCapacity) {
+              length3 += uloc_getDisplayKeywordValue(locale, keyword, displayLocale, dest+length+length3, destCapacity-length-length3, pErrorCode);
+            } else {
+              length3 += uloc_getDisplayKeywordValue(locale, keyword, displayLocale, NULL, 0, pErrorCode);
+            }
+            if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
+                /* keep preflighting */
+                *pErrorCode=U_ZERO_ERROR;
+            }
+          }
+          if(keywordCount > 1) {
+              if(length + length3 + locSepLen <= destCapacity && keywordCount) {
+                  u_memcpy(dest+length+length3,dispLocSeparator,locSepLen);
+                  length3+=locSepLen;
+              }
+          }
+    }
+    uenum_close(keywordEnum);
+
+    hasKeywords = length3 > 0;
+    length += length3;
+
+
+    if ((hasScript && !hasCountry)
+        || ((hasScript || hasCountry) && !hasVariant && !hasKeywords)
+        || ((hasScript || hasCountry || hasVariant) && !hasKeywords)) {
+        /* Remove separator  */
+        length -= locSepLen;
+    } else if (hasLanguage && !hasScript && !hasCountry && !hasVariant && !hasKeywords) {
+        /* Remove " (" */
+        length-=2;
+    }
+
+    if (hasLanguage && (hasScript || hasCountry || hasVariant || hasKeywords)) {
+        /* append ")" */
+        if(length<destCapacity) {
+            dest[length]=0x29;
+        }
+        ++length;
+
+        /* If the localized display pattern is something other than the default pattern of "{0} ({1})", then
+         * then we need to do the formatting here.  It would be easier to use a messageFormat to do this, but we
+         * can't since we don't have the APIs in the i18n library available to us at this point.
+         */
+        if (locPatLen != defaultPatternLen || u_strcmp(dispLocPattern,defaultPattern)) { /* Something other than the default pattern */
+           UChar *p0 = u_strstr(dispLocPattern,pat0);
+           UChar *p1 = u_strstr(dispLocPattern,pat1);
+           u_terminateUChars(dest, destCapacity, length, pErrorCode);
+
+           if ( p0 != NULL && p1 != NULL ) { /* The pattern is well formed */
+              if ( dest ) {
+                  int32_t destLen = 0;
+                  UChar *result = (UChar *)uprv_malloc((length+1)*sizeof(UChar));
+                  UChar *upos = (UChar *)dispLocPattern;
+                  u_strcpy(result,dest);
+                  dest[0] = 0;
+                  while ( *upos ) {
+                     if ( upos == p0 ) { /* Handle {0} substitution */
+                         u_strncat(dest,result,p0Len);
+                         destLen += p0Len;
+                         dest[destLen] = 0; /* Null terminate */
+                         upos += 3;
+                     } else if ( upos == p1 ) { /* Handle {1} substitution */
+                         UChar *p1Start = &result[p0Len+2];
+                         u_strncat(dest,p1Start,length-p0Len-3);
+                         destLen += (length-p0Len-3);
+                         dest[destLen] = 0; /* Null terminate */
+                         upos += 3;
+                     } else { /* Something from the pattern not {0} or {1} */
+                         u_strncat(dest,upos,1);
+                         upos++;
+                         destLen++;
+                         dest[destLen] = 0; /* Null terminate */
+                     }
+                  }
+                  length = destLen;
+                  uprv_free(result);
+              }
+           }
+        }
+    }
+    if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
+        /* keep preflighting */
+        *pErrorCode=U_ZERO_ERROR;
+    }
+
+    return u_terminateUChars(dest, destCapacity, length, pErrorCode);
+}
+
+U_CAPI int32_t U_EXPORT2
+uloc_getDisplayKeyword(const char* keyword,
+                       const char* displayLocale,
+                       UChar* dest,
+                       int32_t destCapacity,
+                       UErrorCode* status){
+
+    /* argument checking */
+    if(status==NULL || U_FAILURE(*status)) {
+        return 0;
+    }
+
+    if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
+        *status=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+
+    /* pass itemKey=NULL to look for a top-level item */
+    return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
+                               _kKeys, NULL, 
+                               keyword, 
+                               keyword,      
+                               dest, destCapacity,
+                               status);
+
+}
+
+
+#define UCURRENCY_DISPLAY_NAME_INDEX 1
+
+U_CAPI int32_t U_EXPORT2
+uloc_getDisplayKeywordValue(   const char* locale,
+                               const char* keyword,
+                               const char* displayLocale,
+                               UChar* dest,
+                               int32_t destCapacity,
+                               UErrorCode* status){
+
+
+    char keywordValue[ULOC_FULLNAME_CAPACITY*4];
+    int32_t capacity = ULOC_FULLNAME_CAPACITY*4;
+    int32_t keywordValueLen =0;
+
+    /* argument checking */
+    if(status==NULL || U_FAILURE(*status)) {
+        return 0;
+    }
+
+    if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
+        *status=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* get the keyword value */
+    keywordValue[0]=0;
+    keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, capacity, status);
+
+    /* 
+     * if the keyword is equal to currency .. then to get the display name 
+     * we need to do the fallback ourselves
+     */
+    if(uprv_stricmp(keyword, _kCurrency)==0){
+
+        int32_t dispNameLen = 0;
+        const UChar *dispName = NULL;
+        
+        UResourceBundle *bundle     = ures_open(U_ICUDATA_CURR, displayLocale, status);
+        UResourceBundle *currencies = ures_getByKey(bundle, _kCurrencies, NULL, status);
+        UResourceBundle *currency   = ures_getByKeyWithFallback(currencies, keywordValue, NULL, status);
+        
+        dispName = ures_getStringByIndex(currency, UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status);
+        
+        /*close the bundles */
+        ures_close(currency);
+        ures_close(currencies);
+        ures_close(bundle);
+        
+        if(U_FAILURE(*status)){
+            if(*status == U_MISSING_RESOURCE_ERROR){
+                /* we just want to write the value over if nothing is available */
+                *status = U_USING_DEFAULT_WARNING;
+            }else{
+                return 0;
+            }
+        }
+
+        /* now copy the dispName over if not NULL */
+        if(dispName != NULL){
+            if(dispNameLen <= destCapacity){
+                uprv_memcpy(dest, dispName, dispNameLen * U_SIZEOF_UCHAR);
+                return u_terminateUChars(dest, destCapacity, dispNameLen, status);
+            }else{
+                *status = U_BUFFER_OVERFLOW_ERROR;
+                return dispNameLen;
+            }
+        }else{
+            /* we have not found the display name for the value .. just copy over */
+            if(keywordValueLen <= destCapacity){
+                u_charsToUChars(keywordValue, dest, keywordValueLen);
+                return u_terminateUChars(dest, destCapacity, keywordValueLen, status);
+            }else{
+                 *status = U_BUFFER_OVERFLOW_ERROR;
+                return keywordValueLen;
+            }
+        }
+
+        
+    }else{
+
+        return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
+                                   _kTypes, keyword, 
+                                   keywordValue,
+                                   keywordValue,
+                                   dest, destCapacity,
+                                   status);
+    }
+}
diff --git a/source/common/locid.cpp b/source/common/locid.cpp
new file mode 100644
index 0000000..e6a93ea
--- /dev/null
+++ b/source/common/locid.cpp
@@ -0,0 +1,1101 @@
+/*
+ **********************************************************************
+ *   Copyright (C) 1997-2010, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ **********************************************************************
+*
+* File locid.cpp
+*
+* Created by: Richard Gillam
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   02/11/97    aliu        Changed gLocPath to fgDataDirectory and added
+*                           methods to get and set it.
+*   04/02/97    aliu        Made operator!= inline; fixed return value
+*                           of getName().
+*   04/15/97    aliu        Cleanup for AIX/Win32.
+*   04/24/97    aliu        Numerous changes per code review.
+*   08/18/98    stephen     Changed getDisplayName()
+*                           Added SIMPLIFIED_CHINESE, TRADITIONAL_CHINESE
+*                           Added getISOCountries(), getISOLanguages(),
+*                           getLanguagesForCountry()
+*   03/16/99    bertrand    rehaul.
+*   07/21/99    stephen     Added U_CFUNC setDefault
+*   11/09/99    weiv        Added const char * getName() const;
+*   04/12/00    srl         removing unicodestring api's and cached hash code
+*   08/10/01    grhoten     Change the static Locales to accessor functions
+******************************************************************************
+*/
+
+
+#include "unicode/locid.h"
+#include "unicode/uloc.h"
+#include "umutex.h"
+#include "uassert.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uhash.h"
+#include "ucln_cmn.h"
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+typedef enum ELocalePos {
+    eENGLISH,
+    eFRENCH,
+    eGERMAN,
+    eITALIAN,
+    eJAPANESE,
+    eKOREAN,
+    eCHINESE,
+
+    eFRANCE,
+    eGERMANY,
+    eITALY,
+    eJAPAN,
+    eKOREA,
+    eCHINA,      /* Alias for PRC */
+    eTAIWAN,
+    eUK,
+    eUS,
+    eCANADA,
+    eCANADA_FRENCH,
+    eROOT,
+
+
+    //eDEFAULT,
+    eMAX_LOCALES
+} ELocalePos;
+
+U_CFUNC int32_t locale_getKeywords(const char *localeID,
+            char prev,
+            char *keywords, int32_t keywordCapacity,
+            char *values, int32_t valuesCapacity, int32_t *valLen,
+            UBool valuesToo,
+            UErrorCode *status);
+
+static U_NAMESPACE_QUALIFIER Locale *gLocaleCache         = NULL;
+static U_NAMESPACE_QUALIFIER Locale *gDefaultLocale       = NULL;
+static UHashtable                   *gDefaultLocalesHashT = NULL;
+
+U_CDECL_BEGIN
+//
+// Deleter function for Locales owned by the default Locale hash table/
+//
+static void U_CALLCONV
+deleteLocale(void *obj) {
+    delete (U_NAMESPACE_QUALIFIER Locale *) obj;
+}
+
+static UBool U_CALLCONV locale_cleanup(void)
+{
+    U_NAMESPACE_USE
+
+    if (gLocaleCache) {
+        delete [] gLocaleCache;
+        gLocaleCache = NULL;
+    }
+
+    if (gDefaultLocalesHashT) {
+        uhash_close(gDefaultLocalesHashT);   // Automatically deletes all elements, using deleter func.
+        gDefaultLocalesHashT = NULL;
+    }
+    else if (gDefaultLocale) {
+        // The cache wasn't created, and only one default locale was created.
+        delete gDefaultLocale;
+    }
+    gDefaultLocale = NULL;
+
+    return TRUE;
+}
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+//
+//  locale_set_default_internal.
+//
+void locale_set_default_internal(const char *id)
+{
+    UErrorCode   status = U_ZERO_ERROR;
+    UBool canonicalize = FALSE;
+
+    // If given a NULL string for the locale id, grab the default
+    //   name from the system.
+    //   (Different from most other locale APIs, where a null name means use
+    //    the current ICU default locale.)
+    if (id == NULL) {
+        umtx_lock(NULL);
+        id = uprv_getDefaultLocaleID();
+        umtx_unlock(NULL);
+        canonicalize = TRUE; // always canonicalize host ID
+    }
+
+    // put the locale id into a canonical form,
+    //   in preparation for looking up this locale in the hash table of
+    //   already-created locale objects.
+    //
+    status = U_ZERO_ERROR;
+    char localeNameBuf[512];
+
+    if (canonicalize) {
+        uloc_canonicalize(id, localeNameBuf, sizeof(localeNameBuf)-1, &status);
+    } else {
+        uloc_getName(id, localeNameBuf, sizeof(localeNameBuf)-1, &status);
+    }
+    localeNameBuf[sizeof(localeNameBuf)-1] = 0;  // Force null termination in event of
+                                                 //   a long name filling the buffer.
+                                                 //   (long names are truncated.)
+
+    // Lazy creation of the hash table itself, if needed.
+    UBool isOnlyLocale;
+    UMTX_CHECK(NULL, (gDefaultLocale == NULL), isOnlyLocale);
+    if (isOnlyLocale) {
+        // We haven't seen this locale id before.
+        // Create a new Locale object for it.
+        Locale *newFirstDefault = new Locale(Locale::eBOGUS);
+        if (newFirstDefault == NULL) {
+            // No way to report errors from here.
+            return;
+        }
+        newFirstDefault->init(localeNameBuf, FALSE);
+        umtx_lock(NULL);
+        if (gDefaultLocale == NULL) {
+            gDefaultLocale = newFirstDefault;  // Assignment to gDefaultLocale must happen inside mutex
+            newFirstDefault = NULL;
+            ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
+        }
+        // Else some other thread raced us through here, and set the new Locale.
+        // Use the hash table next.
+        umtx_unlock(NULL);
+        if (newFirstDefault == NULL) {
+            // We were successful in setting the locale, and we were the first one to set it.
+            return;
+        }
+        // else start using the hash table.
+    }
+
+    // Lazy creation of the hash table itself, if needed.
+    UBool hashTableNeedsInit;
+    UMTX_CHECK(NULL, (gDefaultLocalesHashT == NULL), hashTableNeedsInit);
+    if (hashTableNeedsInit) {
+        status = U_ZERO_ERROR;
+        UHashtable *tHashTable = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
+        if (U_FAILURE(status)) {
+            return;
+        }
+        uhash_setValueDeleter(tHashTable, deleteLocale);
+        umtx_lock(NULL);
+        if (gDefaultLocalesHashT == NULL) {
+            gDefaultLocalesHashT = tHashTable;
+            ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
+        } else {
+            uhash_close(tHashTable);
+            hashTableNeedsInit = FALSE;
+        }
+        umtx_unlock(NULL);
+    }
+
+    // Hash table lookup, key is the locale full name
+    umtx_lock(NULL);
+    Locale *newDefault = (Locale *)uhash_get(gDefaultLocalesHashT, localeNameBuf);
+    if (newDefault != NULL) {
+        // We have the requested locale in the hash table already.
+        // Just set it as default.  Inside the mutex lock, for those troublesome processors.
+        gDefaultLocale = newDefault;
+        umtx_unlock(NULL);
+    } else {
+        umtx_unlock(NULL);
+        // We haven't seen this locale id before.
+        // Create a new Locale object for it.
+        newDefault = new Locale(Locale::eBOGUS);
+        if (newDefault == NULL) {
+            // No way to report errors from here.
+            return;
+        }
+        newDefault->init(localeNameBuf, FALSE);
+
+        // Add newly created Locale to the hash table of default Locales
+        const char *key = newDefault->getName();
+        U_ASSERT(uprv_strcmp(key, localeNameBuf) == 0);
+        umtx_lock(NULL);
+        Locale *hashTableVal = (Locale *)uhash_get(gDefaultLocalesHashT, key);
+        if (hashTableVal == NULL) {
+            if (hashTableNeedsInit) {
+                // This is the second request to set the locale.
+                // Cache the first one.
+                uhash_put(gDefaultLocalesHashT, (void *)gDefaultLocale->getName(), gDefaultLocale, &status);
+            }
+            uhash_put(gDefaultLocalesHashT, (void *)key, newDefault, &status);
+            gDefaultLocale = newDefault;
+            // ignore errors from hash table insert.  (Couldn't do anything anyway)
+            // We can still set the default Locale,
+            //  it just wont be cached, and will eventually leak.
+        } else {
+            // Some other thread raced us through here, and got the new Locale
+            //   into the hash table before us.  Use that one.
+            gDefaultLocale = hashTableVal;  // Assignment to gDefaultLocale must happen inside mutex
+            delete newDefault;
+        }
+        umtx_unlock(NULL);
+    }
+}
+U_NAMESPACE_END
+
+/* sfb 07/21/99 */
+U_CFUNC void
+locale_set_default(const char *id)
+{
+    U_NAMESPACE_USE
+    locale_set_default_internal(id);
+}
+/* end */
+
+U_CFUNC const char *
+locale_get_default(void)
+{
+    U_NAMESPACE_USE
+
+    return Locale::getDefault().getName();
+}
+
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale)
+
+/*Character separating the posix id fields*/
+// '_'
+// In the platform codepage.
+#define SEP_CHAR '_'
+
+Locale::~Locale()
+{
+    /*if fullName is on the heap, we free it*/
+    if (fullName != fullNameBuffer)
+    {
+        uprv_free(fullName);
+        fullName = NULL;
+    }
+    if (baseName && baseName != baseNameBuffer) {
+        uprv_free(baseName);
+        baseName = NULL;
+    }
+}
+
+Locale::Locale()
+    : UObject(), fullName(fullNameBuffer), baseName(NULL)
+{
+    init(NULL, FALSE);
+}
+
+/*
+ * Internal constructor to allow construction of a locale object with
+ *   NO side effects.   (Default constructor tries to get
+ *   the default locale.)
+ */
+Locale::Locale(Locale::ELocaleType)
+    : UObject(), fullName(fullNameBuffer), baseName(NULL)
+{
+    setToBogus();
+}
+
+
+Locale::Locale( const   char * newLanguage,
+                const   char * newCountry,
+                const   char * newVariant,
+                const   char * newKeywords)
+    : UObject(), fullName(fullNameBuffer), baseName(NULL)
+{
+    if( (newLanguage==NULL) && (newCountry == NULL) && (newVariant == NULL) )
+    {
+        init(NULL, FALSE); /* shortcut */
+    }
+    else
+    {
+        MaybeStackArray<char, ULOC_FULLNAME_CAPACITY> togo;
+        int32_t size = 0;
+        int32_t lsize = 0;
+        int32_t csize = 0;
+        int32_t vsize = 0;
+        int32_t ksize = 0;
+        char    *p;
+
+        // Calculate the size of the resulting string.
+
+        // Language
+        if ( newLanguage != NULL )
+        {
+            lsize = (int32_t)uprv_strlen(newLanguage);
+            size = lsize;
+        }
+
+        // _Country
+        if ( newCountry != NULL )
+        {
+            csize = (int32_t)uprv_strlen(newCountry);
+            size += csize;
+        }
+
+        // _Variant
+        if ( newVariant != NULL )
+        {
+            // remove leading _'s
+            while(newVariant[0] == SEP_CHAR)
+            {
+                newVariant++;
+            }
+
+            // remove trailing _'s
+            vsize = (int32_t)uprv_strlen(newVariant);
+            while( (vsize>1) && (newVariant[vsize-1] == SEP_CHAR) )
+            {
+                vsize--;
+            }
+        }
+
+        if( vsize > 0 )
+        {
+            size += vsize;
+        }
+
+        // Separator rules:
+        if ( vsize > 0 )
+        {
+            size += 2;  // at least: __v
+        }
+        else if ( csize > 0 )
+        {
+            size += 1;  // at least: _v
+        }
+
+        if ( newKeywords != NULL)
+        {
+            ksize = (int32_t)uprv_strlen(newKeywords);
+            size += ksize + 1;
+        }
+
+
+        //  NOW we have the full locale string..
+
+        /*if the whole string is longer than our internal limit, we need
+        to go to the heap for temporary buffers*/
+        if (size >= togo.getCapacity())
+        {
+            // If togo_heap could not be created, initialize with default settings.
+            if (togo.resize(size+1) == NULL) {
+                init(NULL, FALSE);
+            }
+        }
+
+        togo[0] = 0;
+
+        // Now, copy it back.
+        p = togo.getAlias();
+        if ( lsize != 0 )
+        {
+            uprv_strcpy(p, newLanguage);
+            p += lsize;
+        }
+
+        if ( ( vsize != 0 ) || (csize != 0) )  // at least:  __v
+        {                                      //            ^
+            *p++ = SEP_CHAR;
+        }
+
+        if ( csize != 0 )
+        {
+            uprv_strcpy(p, newCountry);
+            p += csize;
+        }
+
+        if ( vsize != 0)
+        {
+            *p++ = SEP_CHAR; // at least: __v
+
+            uprv_strncpy(p, newVariant, vsize);  // Must use strncpy because
+            p += vsize;                          // of trimming (above).
+            *p = 0; // terminate
+        }
+
+        if ( ksize != 0)
+        {
+            if (uprv_strchr(newKeywords, '=')) {
+                *p++ = '@'; /* keyword parsing */
+            }
+            else {
+                *p++ = '_'; /* Variant parsing with a script */
+                if ( vsize == 0) {
+                    *p++ = '_'; /* No country found */
+                }
+            }
+            uprv_strcpy(p, newKeywords);
+            p += ksize;
+        }
+
+        // Parse it, because for example 'language' might really be a complete
+        // string.
+        init(togo.getAlias(), FALSE);
+    }
+}
+
+Locale::Locale(const Locale &other)
+    : UObject(other), fullName(fullNameBuffer), baseName(NULL)
+{
+    *this = other;
+}
+
+Locale &Locale::operator=(const Locale &other)
+{
+    if (this == &other) {
+        return *this;
+    }
+
+    if (&other == NULL) {
+        this->setToBogus();
+        return *this;
+    }
+
+    /* Free our current storage */
+    if(fullName != fullNameBuffer) {
+        uprv_free(fullName);
+        fullName = fullNameBuffer;
+    }
+
+    /* Allocate the full name if necessary */
+    if(other.fullName != other.fullNameBuffer) {
+        fullName = (char *)uprv_malloc(sizeof(char)*(uprv_strlen(other.fullName)+1));
+        if (fullName == NULL) {
+            return *this;
+        }
+    }
+    /* Copy the full name */
+    uprv_strcpy(fullName, other.fullName);
+
+    /* baseName is the cached result of getBaseName.  if 'other' has a
+       baseName and it fits in baseNameBuffer, then copy it. otherwise set
+       it to NULL, and let the user lazy-create it (in getBaseName) if they
+       want it. */
+    if(baseName && baseName != baseNameBuffer) {
+        uprv_free(baseName);
+    }
+    baseName = NULL;
+
+    if(other.baseName == other.baseNameBuffer) {
+        uprv_strcpy(baseNameBuffer, other.baseNameBuffer);
+        baseName = baseNameBuffer;
+    }
+
+    /* Copy the language and country fields */
+    uprv_strcpy(language, other.language);
+    uprv_strcpy(script, other.script);
+    uprv_strcpy(country, other.country);
+
+    /* The variantBegin is an offset, just copy it */
+    variantBegin = other.variantBegin;
+    fIsBogus = other.fIsBogus;
+    return *this;
+}
+
+Locale *
+Locale::clone() const {
+    return new Locale(*this);
+}
+
+UBool
+Locale::operator==( const   Locale& other) const
+{
+    return (uprv_strcmp(other.fullName, fullName) == 0);
+}
+
+/*This function initializes a Locale from a C locale ID*/
+Locale& Locale::init(const char* localeID, UBool canonicalize)
+{
+    fIsBogus = FALSE;
+    /* Free our current storage */
+    if(fullName != fullNameBuffer) {
+        uprv_free(fullName);
+        fullName = fullNameBuffer;
+    }
+
+    if(baseName && baseName != baseNameBuffer) {
+        uprv_free(baseName);
+        baseName = NULL;
+    }
+
+    // not a loop:
+    // just an easy way to have a common error-exit
+    // without goto and without another function
+    do {
+        char *separator;
+        char *field[5] = {0};
+        int32_t fieldLen[5] = {0};
+        int32_t fieldIdx;
+        int32_t variantField;
+        int32_t length;
+        UErrorCode err;
+
+        if(localeID == NULL) {
+            // not an error, just set the default locale
+            return *this = getDefault();
+        }
+
+        /* preset all fields to empty */
+        language[0] = script[0] = country[0] = 0;
+
+        // "canonicalize" the locale ID to ICU/Java format
+        err = U_ZERO_ERROR;
+        length = canonicalize ?
+            uloc_canonicalize(localeID, fullName, sizeof(fullNameBuffer), &err) :
+            uloc_getName(localeID, fullName, sizeof(fullNameBuffer), &err);
+
+        if(err == U_BUFFER_OVERFLOW_ERROR || length >= (int32_t)sizeof(fullNameBuffer)) {
+            /*Go to heap for the fullName if necessary*/
+            fullName = (char *)uprv_malloc(sizeof(char)*(length + 1));
+            if(fullName == 0) {
+                fullName = fullNameBuffer;
+                break; // error: out of memory
+            }
+            err = U_ZERO_ERROR;
+            length = canonicalize ?
+                uloc_canonicalize(localeID, fullName, length+1, &err) :
+                uloc_getName(localeID, fullName, length+1, &err);
+        }
+        if(U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) {
+            /* should never occur */
+            break;
+        }
+
+        variantBegin = length;
+
+        /* after uloc_getName/canonicalize() we know that only '_' are separators */
+        separator = field[0] = fullName;
+        fieldIdx = 1;
+        while ((separator = uprv_strchr(field[fieldIdx-1], SEP_CHAR)) && fieldIdx < (int32_t)(sizeof(field)/sizeof(field[0]))-1) {
+            field[fieldIdx] = separator + 1;
+            fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]);
+            fieldIdx++;
+        }
+        // variant may contain @foo or .foo POSIX cruft; remove it
+        separator = uprv_strchr(field[fieldIdx-1], '@');
+        char* sep2 = uprv_strchr(field[fieldIdx-1], '.');
+        if (separator!=NULL || sep2!=NULL) {
+            if (separator==NULL || (sep2!=NULL && separator > sep2)) {
+                separator = sep2;
+            }
+            fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]);
+        } else {
+            fieldLen[fieldIdx-1] = length - (int32_t)(field[fieldIdx-1] - fullName);
+        }
+
+        if (fieldLen[0] >= (int32_t)(sizeof(language))
+            || (fieldLen[1] == 4 && fieldLen[2] >= (int32_t)(sizeof(country)))
+            || (fieldLen[1] != 4 && fieldLen[1] >= (int32_t)(sizeof(country))))
+        {
+            break; // error: one of the fields is too long
+        }
+
+        variantField = 2; /* Usually the 2nd one, except when a script is used. */
+        if (fieldLen[0] > 0) {
+            /* We have a language */
+            uprv_memcpy(language, fullName, fieldLen[0]);
+            language[fieldLen[0]] = 0;
+        }
+        if (fieldLen[1] == 4) {
+            /* We have at least a script */
+            uprv_memcpy(script, field[1], fieldLen[1]);
+            script[fieldLen[1]] = 0;
+            variantField = 3;
+            if (fieldLen[2] > 0) {
+                /* We have a country */
+                uprv_memcpy(country, field[2], fieldLen[2]);
+                country[fieldLen[2]] = 0;
+            }
+        }
+        else if (fieldLen[1] > 0) {
+            /* We have a country and no script */
+            uprv_memcpy(country, field[1], fieldLen[1]);
+            country[fieldLen[1]] = 0;
+        }
+        if (variantField > 0 && fieldLen[variantField] > 0) {
+            /* We have a variant */
+            variantBegin = (int32_t)(field[variantField] - fullName);
+        }
+
+        // successful end of init()
+        return *this;
+    } while(0); /*loop doesn't iterate*/
+
+    // when an error occurs, then set this object to "bogus" (there is no UErrorCode here)
+    setToBogus();
+
+    return *this;
+}
+
+int32_t
+Locale::hashCode() const
+{
+    UHashTok hashKey;
+    hashKey.pointer = fullName;
+    return uhash_hashChars(hashKey);
+}
+
+void
+Locale::setToBogus() {
+    /* Free our current storage */
+    if(fullName != fullNameBuffer) {
+        uprv_free(fullName);
+        fullName = fullNameBuffer;
+    }
+    if(baseName && baseName != baseNameBuffer) {
+        uprv_free(baseName);
+        baseName = NULL;
+    }
+    *fullNameBuffer = 0;
+    *language = 0;
+    *script = 0;
+    *country = 0;
+    fIsBogus = TRUE;
+}
+
+const Locale& U_EXPORT2
+Locale::getDefault()
+{
+    const Locale *retLocale;
+    UMTX_CHECK(NULL, gDefaultLocale, retLocale);
+    if (retLocale == NULL) {
+        locale_set_default_internal(NULL);
+        umtx_lock(NULL);
+        // Need a mutex  in case some other thread set a new
+        // default inbetween when we set and when we get the new default.  For
+        // processors with weak memory coherency, we might not otherwise see all
+        // of the newly created new default locale.
+        retLocale = gDefaultLocale;
+        umtx_unlock(NULL);
+    }
+    return *retLocale;
+}
+
+
+
+void U_EXPORT2
+Locale::setDefault( const   Locale&     newLocale,
+                            UErrorCode&  status)
+{
+    if (U_FAILURE(status)) {
+        return;
+    }
+
+    /* Set the default from the full name string of the supplied locale.
+     * This is a convenient way to access the default locale caching mechanisms.
+     */
+    const char *localeID = newLocale.getName();
+    locale_set_default_internal(localeID);
+}
+
+Locale U_EXPORT2
+Locale::createFromName (const char *name)
+{
+    if (name) {
+        Locale l("");
+        l.init(name, FALSE);
+        return l;
+    }
+    else {
+        return getDefault();
+    }
+}
+
+Locale U_EXPORT2
+Locale::createCanonical(const char* name) {
+    Locale loc("");
+    loc.init(name, TRUE);
+    return loc;
+}
+
+const char *
+Locale::getISO3Language() const
+{
+    return uloc_getISO3Language(fullName);
+}
+
+
+const char *
+Locale::getISO3Country() const
+{
+    return uloc_getISO3Country(fullName);
+}
+
+/**
+ * Return the LCID value as specified in the "LocaleID" resource for this
+ * locale.  The LocaleID must be expressed as a hexadecimal number, from
+ * one to four digits.  If the LocaleID resource is not present, or is
+ * in an incorrect format, 0 is returned.  The LocaleID is for use in
+ * Windows (it is an LCID), but is available on all platforms.
+ */
+uint32_t
+Locale::getLCID() const
+{
+    return uloc_getLCID(fullName);
+}
+
+const char* const* U_EXPORT2 Locale::getISOCountries()
+{
+    return uloc_getISOCountries();
+}
+
+const char* const* U_EXPORT2 Locale::getISOLanguages()
+{
+    return uloc_getISOLanguages();
+}
+
+// Set the locale's data based on a posix id.
+void Locale::setFromPOSIXID(const char *posixID)
+{
+    init(posixID, TRUE);
+}
+
+const Locale & U_EXPORT2
+Locale::getRoot(void)
+{
+    return getLocale(eROOT);
+}
+
+const Locale & U_EXPORT2
+Locale::getEnglish(void)
+{
+    return getLocale(eENGLISH);
+}
+
+const Locale & U_EXPORT2
+Locale::getFrench(void)
+{
+    return getLocale(eFRENCH);
+}
+
+const Locale & U_EXPORT2
+Locale::getGerman(void)
+{
+    return getLocale(eGERMAN);
+}
+
+const Locale & U_EXPORT2
+Locale::getItalian(void)
+{
+    return getLocale(eITALIAN);
+}
+
+const Locale & U_EXPORT2
+Locale::getJapanese(void)
+{
+    return getLocale(eJAPANESE);
+}
+
+const Locale & U_EXPORT2
+Locale::getKorean(void)
+{
+    return getLocale(eKOREAN);
+}
+
+const Locale & U_EXPORT2
+Locale::getChinese(void)
+{
+    return getLocale(eCHINESE);
+}
+
+const Locale & U_EXPORT2
+Locale::getSimplifiedChinese(void)
+{
+    return getLocale(eCHINA);
+}
+
+const Locale & U_EXPORT2
+Locale::getTraditionalChinese(void)
+{
+    return getLocale(eTAIWAN);
+}
+
+
+const Locale & U_EXPORT2
+Locale::getFrance(void)
+{
+    return getLocale(eFRANCE);
+}
+
+const Locale & U_EXPORT2
+Locale::getGermany(void)
+{
+    return getLocale(eGERMANY);
+}
+
+const Locale & U_EXPORT2
+Locale::getItaly(void)
+{
+    return getLocale(eITALY);
+}
+
+const Locale & U_EXPORT2
+Locale::getJapan(void)
+{
+    return getLocale(eJAPAN);
+}
+
+const Locale & U_EXPORT2
+Locale::getKorea(void)
+{
+    return getLocale(eKOREA);
+}
+
+const Locale & U_EXPORT2
+Locale::getChina(void)
+{
+    return getLocale(eCHINA);
+}
+
+const Locale & U_EXPORT2
+Locale::getPRC(void)
+{
+    return getLocale(eCHINA);
+}
+
+const Locale & U_EXPORT2
+Locale::getTaiwan(void)
+{
+    return getLocale(eTAIWAN);
+}
+
+const Locale & U_EXPORT2
+Locale::getUK(void)
+{
+    return getLocale(eUK);
+}
+
+const Locale & U_EXPORT2
+Locale::getUS(void)
+{
+    return getLocale(eUS);
+}
+
+const Locale & U_EXPORT2
+Locale::getCanada(void)
+{
+    return getLocale(eCANADA);
+}
+
+const Locale & U_EXPORT2
+Locale::getCanadaFrench(void)
+{
+    return getLocale(eCANADA_FRENCH);
+}
+
+const Locale &
+Locale::getLocale(int locid)
+{
+    Locale *localeCache = getLocaleCache();
+    U_ASSERT((locid < eMAX_LOCALES)&&(locid>=0));
+    if (localeCache == NULL) {
+        // Failure allocating the locale cache.
+        //   The best we can do is return a NULL reference.
+        locid = 0;
+    }
+    return localeCache[locid]; /*operating on NULL*/
+}
+
+/*
+This function is defined this way in order to get around static
+initialization and static destruction.
+ */
+Locale *
+Locale::getLocaleCache(void)
+{
+    umtx_lock(NULL);
+    UBool needInit = (gLocaleCache == NULL);
+    umtx_unlock(NULL);
+
+    if (needInit) {
+        Locale *tLocaleCache = new Locale[(int)eMAX_LOCALES];
+        if (tLocaleCache == NULL) {
+            return NULL;
+        }
+	tLocaleCache[eROOT]          = Locale("");
+        tLocaleCache[eENGLISH]       = Locale("en");
+        tLocaleCache[eFRENCH]        = Locale("fr");
+        tLocaleCache[eGERMAN]        = Locale("de");
+        tLocaleCache[eITALIAN]       = Locale("it");
+        tLocaleCache[eJAPANESE]      = Locale("ja");
+        tLocaleCache[eKOREAN]        = Locale("ko");
+        tLocaleCache[eCHINESE]       = Locale("zh");
+        tLocaleCache[eFRANCE]        = Locale("fr", "FR");
+        tLocaleCache[eGERMANY]       = Locale("de", "DE");
+        tLocaleCache[eITALY]         = Locale("it", "IT");
+        tLocaleCache[eJAPAN]         = Locale("ja", "JP");
+        tLocaleCache[eKOREA]         = Locale("ko", "KR");
+        tLocaleCache[eCHINA]         = Locale("zh", "CN");
+        tLocaleCache[eTAIWAN]        = Locale("zh", "TW");
+        tLocaleCache[eUK]            = Locale("en", "GB");
+        tLocaleCache[eUS]            = Locale("en", "US");
+        tLocaleCache[eCANADA]        = Locale("en", "CA");
+        tLocaleCache[eCANADA_FRENCH] = Locale("fr", "CA");
+
+        umtx_lock(NULL);
+        if (gLocaleCache == NULL) {
+            gLocaleCache = tLocaleCache;
+            tLocaleCache = NULL;
+            ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
+        }
+        umtx_unlock(NULL);
+        if (tLocaleCache) {
+            delete [] tLocaleCache;  // Fancy array delete will destruct each member.
+        }
+    }
+    return gLocaleCache;
+}
+
+class KeywordEnumeration : public StringEnumeration {
+private:
+    char *keywords;
+    char *current;
+    int32_t length;
+    UnicodeString currUSKey;
+    static const char fgClassID;/* Warning this is used beyond the typical RTTI usage. */
+
+public:
+    static UClassID U_EXPORT2 getStaticClassID(void) { return (UClassID)&fgClassID; }
+    virtual UClassID getDynamicClassID(void) const { return getStaticClassID(); }
+public:
+    KeywordEnumeration(const char *keys, int32_t keywordLen, int32_t currentIndex, UErrorCode &status)
+        : keywords((char *)&fgClassID), current((char *)&fgClassID), length(0) {
+        if(U_SUCCESS(status) && keywordLen != 0) {
+            if(keys == NULL || keywordLen < 0) {
+                status = U_ILLEGAL_ARGUMENT_ERROR;
+            } else {
+                keywords = (char *)uprv_malloc(keywordLen+1);
+                if (keywords == NULL) {
+                    status = U_MEMORY_ALLOCATION_ERROR;
+                }
+                else {
+                    uprv_memcpy(keywords, keys, keywordLen);
+                    keywords[keywordLen] = 0;
+                    current = keywords + currentIndex;
+                    length = keywordLen;
+                }
+            }
+        }
+    }
+
+    virtual ~KeywordEnumeration() {
+        uprv_free(keywords);
+    }
+
+    virtual StringEnumeration * clone() const
+    {
+        UErrorCode status = U_ZERO_ERROR;
+        return new KeywordEnumeration(keywords, length, (int32_t)(current - keywords), status);
+    }
+
+    virtual int32_t count(UErrorCode &/*status*/) const {
+        char *kw = keywords;
+        int32_t result = 0;
+        while(*kw) {
+            result++;
+            kw += uprv_strlen(kw)+1;
+        }
+        return result;
+    }
+
+    virtual const char* next(int32_t* resultLength, UErrorCode& status) {
+        const char* result;
+        int32_t len;
+        if(U_SUCCESS(status) && *current != 0) {
+            result = current;
+            len = (int32_t)uprv_strlen(current);
+            current += len+1;
+            if(resultLength != NULL) {
+                *resultLength = len;
+            }
+        } 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*/) {
+        current = keywords;
+    }
+};
+
+const char KeywordEnumeration::fgClassID = '\0';
+
+StringEnumeration *
+Locale::createKeywords(UErrorCode &status) const
+{
+    char keywords[256];
+    int32_t keywordCapacity = 256;
+    StringEnumeration *result = NULL;
+
+    const char* variantStart = uprv_strchr(fullName, '@');
+    const char* assignment = uprv_strchr(fullName, '=');
+    if(variantStart) {
+        if(assignment > variantStart) {
+            int32_t keyLen = locale_getKeywords(variantStart+1, '@', keywords, keywordCapacity, NULL, 0, NULL, FALSE, &status);
+            if(keyLen) {
+                result = new KeywordEnumeration(keywords, keyLen, 0, status);
+            }
+        } else {
+            status = U_INVALID_FORMAT_ERROR;
+        }
+    }
+    return result;
+}
+
+int32_t
+Locale::getKeywordValue(const char* keywordName, char *buffer, int32_t bufLen, UErrorCode &status) const
+{
+    return uloc_getKeywordValue(fullName, keywordName, buffer, bufLen, &status);
+}
+
+void
+Locale::setKeywordValue(const char* keywordName, const char* keywordValue, UErrorCode &status)
+{
+    uloc_setKeywordValue(keywordName, keywordValue, fullName, ULOC_FULLNAME_CAPACITY, &status);
+}
+
+const char *
+Locale::getBaseName() const
+{
+    // lazy init
+    UErrorCode status = U_ZERO_ERROR;
+    // semantically const
+    if(baseName == 0) {
+        ((Locale *)this)->baseName = ((Locale *)this)->baseNameBuffer;
+        int32_t baseNameSize = uloc_getBaseName(fullName, baseName, ULOC_FULLNAME_CAPACITY, &status);
+        if(baseNameSize >= ULOC_FULLNAME_CAPACITY) {
+            ((Locale *)this)->baseName = (char *)uprv_malloc(sizeof(char) * baseNameSize + 1);
+            if (baseName == NULL) {
+                return baseName;
+            }
+            uloc_getBaseName(fullName, baseName, baseNameSize+1, &status);
+        }
+        baseName[baseNameSize] = 0;
+
+        // the computation of variantBegin leaves it equal to the length
+        // of fullName if there is no variant.  It should instead be
+        // the length of the baseName.  Patch around this for now.
+        if (variantBegin == (int32_t)uprv_strlen(fullName)) {
+          ((Locale*)this)->variantBegin = baseNameSize;
+        }
+    }
+    return baseName;
+}
+
+//eof
+U_NAMESPACE_END
diff --git a/source/common/loclikely.cpp b/source/common/loclikely.cpp
new file mode 100644
index 0000000..edee908
--- /dev/null
+++ b/source/common/loclikely.cpp
@@ -0,0 +1,1276 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1997-2011, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  loclikely.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2010feb25
+*   created by: Markus W. Scherer
+*
+*   Code for likely and minimized locale subtags, separated out from other .cpp files
+*   that then do not depend on resource bundle code and likely-subtags data.
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/putil.h"
+#include "unicode/uloc.h"
+#include "unicode/ures.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "ulocimp.h"
+#include "ustr_imp.h"
+
+/**
+ * This function looks for the localeID in the likelySubtags resource.
+ *
+ * @param localeID The tag to find.
+ * @param buffer A buffer to hold the matching entry
+ * @param bufferLength The length of the output buffer
+ * @return A pointer to "buffer" if found, or a null pointer if not.
+ */
+static const char*  U_CALLCONV
+findLikelySubtags(const char* localeID,
+                  char* buffer,
+                  int32_t bufferLength,
+                  UErrorCode* err) {
+    const char* result = NULL;
+
+    if (!U_FAILURE(*err)) {
+        int32_t resLen = 0;
+        const UChar* s = NULL;
+        UErrorCode tmpErr = U_ZERO_ERROR;
+        UResourceBundle* subtags = ures_openDirect(NULL, "likelySubtags", &tmpErr);
+        if (U_SUCCESS(tmpErr)) {
+            s = ures_getStringByKey(subtags, localeID, &resLen, &tmpErr);
+
+            if (U_FAILURE(tmpErr)) {
+                /*
+                 * If a resource is missing, it's not really an error, it's
+                 * just that we don't have any data for that particular locale ID.
+                 */
+                if (tmpErr != U_MISSING_RESOURCE_ERROR) {
+                    *err = tmpErr;
+                }
+            }
+            else if (resLen >= bufferLength) {
+                /* The buffer should never overflow. */
+                *err = U_INTERNAL_PROGRAM_ERROR;
+            }
+            else {
+                u_UCharsToChars(s, buffer, resLen + 1);
+                result = buffer;
+            }
+
+            ures_close(subtags);
+        } else {
+            *err = tmpErr;
+        }
+    }
+
+    return result;
+}
+
+/**
+ * Append a tag to a buffer, adding the separator if necessary.  The buffer
+ * must be large enough to contain the resulting tag plus any separator
+ * necessary. The tag must not be a zero-length string.
+ *
+ * @param tag The tag to add.
+ * @param tagLength The length of the tag.
+ * @param buffer The output buffer.
+ * @param bufferLength The length of the output buffer.  This is an input/ouput parameter.
+ **/
+static void U_CALLCONV
+appendTag(
+    const char* tag,
+    int32_t tagLength,
+    char* buffer,
+    int32_t* bufferLength) {
+
+    if (*bufferLength > 0) {
+        buffer[*bufferLength] = '_';
+        ++(*bufferLength);
+    }
+
+    uprv_memmove(
+        &buffer[*bufferLength],
+        tag,
+        tagLength);
+
+    *bufferLength += tagLength;
+}
+
+/**
+ * These are the canonical strings for unknown languages, scripts and regions.
+ **/
+static const char* const unknownLanguage = "und";
+static const char* const unknownScript = "Zzzz";
+static const char* const unknownRegion = "ZZ";
+
+/**
+ * Create a tag string from the supplied parameters.  The lang, script and region
+ * parameters may be NULL pointers. If they are, their corresponding length parameters
+ * must be less than or equal to 0.
+ *
+ * If any of the language, script or region parameters are empty, and the alternateTags
+ * parameter is not NULL, it will be parsed for potential language, script and region tags
+ * to be used when constructing the new tag.  If the alternateTags parameter is NULL, or
+ * it contains no language tag, the default tag for the unknown language is used.
+ *
+ * If the length of the new string exceeds the capacity of the output buffer, 
+ * the function copies as many bytes to the output buffer as it can, and returns
+ * the error U_BUFFER_OVERFLOW_ERROR.
+ *
+ * If an illegal argument is provided, the function returns the error
+ * U_ILLEGAL_ARGUMENT_ERROR.
+ *
+ * Note that this function can return the warning U_STRING_NOT_TERMINATED_WARNING if
+ * the tag string fits in the output buffer, but the null terminator doesn't.
+ *
+ * @param lang The language tag to use.
+ * @param langLength The length of the language tag.
+ * @param script The script tag to use.
+ * @param scriptLength The length of the script tag.
+ * @param region The region tag to use.
+ * @param regionLength The length of the region tag.
+ * @param trailing Any trailing data to append to the new tag.
+ * @param trailingLength The length of the trailing data.
+ * @param alternateTags A string containing any alternate tags.
+ * @param tag The output buffer.
+ * @param tagCapacity The capacity of the output buffer.
+ * @param err A pointer to a UErrorCode for error reporting.
+ * @return The length of the tag string, which may be greater than tagCapacity, or -1 on error.
+ **/
+static int32_t U_CALLCONV
+createTagStringWithAlternates(
+    const char* lang,
+    int32_t langLength,
+    const char* script,
+    int32_t scriptLength,
+    const char* region,
+    int32_t regionLength,
+    const char* trailing,
+    int32_t trailingLength,
+    const char* alternateTags,
+    char* tag,
+    int32_t tagCapacity,
+    UErrorCode* err) {
+
+    if (U_FAILURE(*err)) {
+        goto error;
+    }
+    else if (tag == NULL ||
+             tagCapacity <= 0 ||
+             langLength >= ULOC_LANG_CAPACITY ||
+             scriptLength >= ULOC_SCRIPT_CAPACITY ||
+             regionLength >= ULOC_COUNTRY_CAPACITY) {
+        goto error;
+    }
+    else {
+        /**
+         * ULOC_FULLNAME_CAPACITY will provide enough capacity
+         * that we can build a string that contains the language,
+         * script and region code without worrying about overrunning
+         * the user-supplied buffer.
+         **/
+        char tagBuffer[ULOC_FULLNAME_CAPACITY];
+        int32_t tagLength = 0;
+        int32_t capacityRemaining = tagCapacity;
+        UBool regionAppended = FALSE;
+
+        if (langLength > 0) {
+            appendTag(
+                lang,
+                langLength,
+                tagBuffer,
+                &tagLength);
+        }
+        else if (alternateTags == NULL) {
+            /*
+             * Append the value for an unknown language, if
+             * we found no language.
+             */
+            appendTag(
+                unknownLanguage,
+                (int32_t)uprv_strlen(unknownLanguage),
+                tagBuffer,
+                &tagLength);
+        }
+        else {
+            /*
+             * Parse the alternateTags string for the language.
+             */
+            char alternateLang[ULOC_LANG_CAPACITY];
+            int32_t alternateLangLength = sizeof(alternateLang);
+
+            alternateLangLength =
+                uloc_getLanguage(
+                    alternateTags,
+                    alternateLang,
+                    alternateLangLength,
+                    err);
+            if(U_FAILURE(*err) ||
+                alternateLangLength >= ULOC_LANG_CAPACITY) {
+                goto error;
+            }
+            else if (alternateLangLength == 0) {
+                /*
+                 * Append the value for an unknown language, if
+                 * we found no language.
+                 */
+                appendTag(
+                    unknownLanguage,
+                    (int32_t)uprv_strlen(unknownLanguage),
+                    tagBuffer,
+                    &tagLength);
+            }
+            else {
+                appendTag(
+                    alternateLang,
+                    alternateLangLength,
+                    tagBuffer,
+                    &tagLength);
+            }
+        }
+
+        if (scriptLength > 0) {
+            appendTag(
+                script,
+                scriptLength,
+                tagBuffer,
+                &tagLength);
+        }
+        else if (alternateTags != NULL) {
+            /*
+             * Parse the alternateTags string for the script.
+             */
+            char alternateScript[ULOC_SCRIPT_CAPACITY];
+
+            const int32_t alternateScriptLength =
+                uloc_getScript(
+                    alternateTags,
+                    alternateScript,
+                    sizeof(alternateScript),
+                    err);
+
+            if (U_FAILURE(*err) ||
+                alternateScriptLength >= ULOC_SCRIPT_CAPACITY) {
+                goto error;
+            }
+            else if (alternateScriptLength > 0) {
+                appendTag(
+                    alternateScript,
+                    alternateScriptLength,
+                    tagBuffer,
+                    &tagLength);
+            }
+        }
+
+        if (regionLength > 0) {
+            appendTag(
+                region,
+                regionLength,
+                tagBuffer,
+                &tagLength);
+
+            regionAppended = TRUE;
+        }
+        else if (alternateTags != NULL) {
+            /*
+             * Parse the alternateTags string for the region.
+             */
+            char alternateRegion[ULOC_COUNTRY_CAPACITY];
+
+            const int32_t alternateRegionLength =
+                uloc_getCountry(
+                    alternateTags,
+                    alternateRegion,
+                    sizeof(alternateRegion),
+                    err);
+            if (U_FAILURE(*err) ||
+                alternateRegionLength >= ULOC_COUNTRY_CAPACITY) {
+                goto error;
+            }
+            else if (alternateRegionLength > 0) {
+                appendTag(
+                    alternateRegion,
+                    alternateRegionLength,
+                    tagBuffer,
+                    &tagLength);
+
+                regionAppended = TRUE;
+            }
+        }
+
+        {
+            const int32_t toCopy =
+                tagLength >= tagCapacity ? tagCapacity : tagLength;
+
+            /**
+             * Copy the partial tag from our internal buffer to the supplied
+             * target.
+             **/
+            uprv_memcpy(
+                tag,
+                tagBuffer,
+                toCopy);
+
+            capacityRemaining -= toCopy;
+        }
+
+        if (trailingLength > 0) {
+            if (*trailing != '@' && capacityRemaining > 0) {
+                tag[tagLength++] = '_';
+                --capacityRemaining;
+                if (capacityRemaining > 0 && !regionAppended) {
+                    /* extra separator is required */
+                    tag[tagLength++] = '_';
+                    --capacityRemaining;
+                }
+            }
+
+            if (capacityRemaining > 0) {
+                /*
+                 * Copy the trailing data into the supplied buffer.  Use uprv_memmove, since we
+                 * don't know if the user-supplied buffers overlap.
+                 */
+                const int32_t toCopy =
+                    trailingLength >= capacityRemaining ? capacityRemaining : trailingLength;
+
+                uprv_memmove(
+                    &tag[tagLength],
+                    trailing,
+                    toCopy);
+            }
+        }
+
+        tagLength += trailingLength;
+
+        return u_terminateChars(
+                    tag,
+                    tagCapacity,
+                    tagLength,
+                    err);
+    }
+
+error:
+
+    /**
+     * An overflow indicates the locale ID passed in
+     * is ill-formed.  If we got here, and there was
+     * no previous error, it's an implicit overflow.
+     **/
+    if (*err ==  U_BUFFER_OVERFLOW_ERROR ||
+        U_SUCCESS(*err)) {
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+    }
+
+    return -1;
+}
+
+/**
+ * Create a tag string from the supplied parameters.  The lang, script and region
+ * parameters may be NULL pointers. If they are, their corresponding length parameters
+ * must be less than or equal to 0.  If the lang parameter is an empty string, the
+ * default value for an unknown language is written to the output buffer.
+ *
+ * If the length of the new string exceeds the capacity of the output buffer, 
+ * the function copies as many bytes to the output buffer as it can, and returns
+ * the error U_BUFFER_OVERFLOW_ERROR.
+ *
+ * If an illegal argument is provided, the function returns the error
+ * U_ILLEGAL_ARGUMENT_ERROR.
+ *
+ * @param lang The language tag to use.
+ * @param langLength The length of the language tag.
+ * @param script The script tag to use.
+ * @param scriptLength The length of the script tag.
+ * @param region The region tag to use.
+ * @param regionLength The length of the region tag.
+ * @param trailing Any trailing data to append to the new tag.
+ * @param trailingLength The length of the trailing data.
+ * @param tag The output buffer.
+ * @param tagCapacity The capacity of the output buffer.
+ * @param err A pointer to a UErrorCode for error reporting.
+ * @return The length of the tag string, which may be greater than tagCapacity.
+ **/
+static int32_t U_CALLCONV
+createTagString(
+    const char* lang,
+    int32_t langLength,
+    const char* script,
+    int32_t scriptLength,
+    const char* region,
+    int32_t regionLength,
+    const char* trailing,
+    int32_t trailingLength,
+    char* tag,
+    int32_t tagCapacity,
+    UErrorCode* err)
+{
+    return createTagStringWithAlternates(
+                lang,
+                langLength,
+                script,
+                scriptLength,
+                region,
+                regionLength,
+                trailing,
+                trailingLength,
+                NULL,
+                tag,
+                tagCapacity,
+                err);
+}
+
+/**
+ * Parse the language, script, and region subtags from a tag string, and copy the
+ * results into the corresponding output parameters. The buffers are null-terminated,
+ * unless overflow occurs.
+ *
+ * The langLength, scriptLength, and regionLength parameters are input/output
+ * parameters, and must contain the capacity of their corresponding buffers on
+ * input.  On output, they will contain the actual length of the buffers, not
+ * including the null terminator.
+ *
+ * If the length of any of the output subtags exceeds the capacity of the corresponding
+ * buffer, the function copies as many bytes to the output buffer as it can, and returns
+ * the error U_BUFFER_OVERFLOW_ERROR.  It will not parse any more subtags once overflow
+ * occurs.
+ *
+ * If an illegal argument is provided, the function returns the error
+ * U_ILLEGAL_ARGUMENT_ERROR.
+ *
+ * @param localeID The locale ID to parse.
+ * @param lang The language tag buffer.
+ * @param langLength The length of the language tag.
+ * @param script The script tag buffer.
+ * @param scriptLength The length of the script tag.
+ * @param region The region tag buffer.
+ * @param regionLength The length of the region tag.
+ * @param err A pointer to a UErrorCode for error reporting.
+ * @return The number of chars of the localeID parameter consumed.
+ **/
+static int32_t U_CALLCONV
+parseTagString(
+    const char* localeID,
+    char* lang,
+    int32_t* langLength,
+    char* script,
+    int32_t* scriptLength,
+    char* region,
+    int32_t* regionLength,
+    UErrorCode* err)
+{
+    const char* position = localeID;
+    int32_t subtagLength = 0;
+
+    if(U_FAILURE(*err) ||
+       localeID == NULL ||
+       lang == NULL ||
+       langLength == NULL ||
+       script == NULL ||
+       scriptLength == NULL ||
+       region == NULL ||
+       regionLength == NULL) {
+        goto error;
+    }
+
+    subtagLength = ulocimp_getLanguage(position, lang, *langLength, &position);
+    u_terminateChars(lang, *langLength, subtagLength, err);
+
+    /*
+     * Note that we explicit consider U_STRING_NOT_TERMINATED_WARNING
+     * to be an error, because it indicates the user-supplied tag is
+     * not well-formed.
+     */
+    if(U_FAILURE(*err)) {
+        goto error;
+    }
+
+    *langLength = subtagLength;
+
+    /*
+     * If no language was present, use the value of unknownLanguage
+     * instead.  Otherwise, move past any separator.
+     */
+    if (*langLength == 0) {
+        uprv_strcpy(
+            lang,
+            unknownLanguage);
+        *langLength = (int32_t)uprv_strlen(lang);
+    }
+    else if (_isIDSeparator(*position)) {
+        ++position;
+    }
+
+    subtagLength = ulocimp_getScript(position, script, *scriptLength, &position);
+    u_terminateChars(script, *scriptLength, subtagLength, err);
+
+    if(U_FAILURE(*err)) {
+        goto error;
+    }
+
+    *scriptLength = subtagLength;
+
+    if (*scriptLength > 0) {
+        if (uprv_strnicmp(script, unknownScript, *scriptLength) == 0) {
+            /**
+             * If the script part is the "unknown" script, then don't return it.
+             **/
+            *scriptLength = 0;
+        }
+
+        /*
+         * Move past any separator.
+         */
+        if (_isIDSeparator(*position)) {
+            ++position;
+        }    
+    }
+
+    subtagLength = ulocimp_getCountry(position, region, *regionLength, &position);
+    u_terminateChars(region, *regionLength, subtagLength, err);
+
+    if(U_FAILURE(*err)) {
+        goto error;
+    }
+
+    *regionLength = subtagLength;
+
+    if (*regionLength > 0) {
+        if (uprv_strnicmp(region, unknownRegion, *regionLength) == 0) {
+            /**
+             * If the region part is the "unknown" region, then don't return it.
+             **/
+            *regionLength = 0;
+        }
+    } else if (*position != 0 && *position != '@') {
+        /* back up over consumed trailing separator */
+        --position;
+    }
+
+exit:
+
+    return (int32_t)(position - localeID);
+
+error:
+
+    /**
+     * If we get here, we have no explicit error, it's the result of an
+     * illegal argument.
+     **/
+    if (!U_FAILURE(*err)) {
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+    }
+
+    goto exit;
+}
+
+static int32_t U_CALLCONV
+createLikelySubtagsString(
+    const char* lang,
+    int32_t langLength,
+    const char* script,
+    int32_t scriptLength,
+    const char* region,
+    int32_t regionLength,
+    const char* variants,
+    int32_t variantsLength,
+    char* tag,
+    int32_t tagCapacity,
+    UErrorCode* err)
+{
+    /**
+     * ULOC_FULLNAME_CAPACITY will provide enough capacity
+     * that we can build a string that contains the language,
+     * script and region code without worrying about overrunning
+     * the user-supplied buffer.
+     **/
+    char tagBuffer[ULOC_FULLNAME_CAPACITY];
+    char likelySubtagsBuffer[ULOC_FULLNAME_CAPACITY];
+    int32_t tagBufferLength = 0;
+
+    if(U_FAILURE(*err)) {
+        goto error;
+    }
+
+    /**
+     * Try the language with the script and region first.
+     **/
+    if (scriptLength > 0 && regionLength > 0) {
+
+        const char* likelySubtags = NULL;
+
+        tagBufferLength = createTagString(
+            lang,
+            langLength,
+            script,
+            scriptLength,
+            region,
+            regionLength,
+            NULL,
+            0,
+            tagBuffer,
+            sizeof(tagBuffer),
+            err);
+        if(U_FAILURE(*err)) {
+            goto error;
+        }
+
+        likelySubtags =
+            findLikelySubtags(
+                tagBuffer,
+                likelySubtagsBuffer,
+                sizeof(likelySubtagsBuffer),
+                err);
+        if(U_FAILURE(*err)) {
+            goto error;
+        }
+
+        if (likelySubtags != NULL) {
+            /* Always use the language tag from the
+               maximal string, since it may be more
+               specific than the one provided. */
+            return createTagStringWithAlternates(
+                        NULL,
+                        0,
+                        NULL,
+                        0,
+                        NULL,
+                        0,
+                        variants,
+                        variantsLength,
+                        likelySubtags,
+                        tag,
+                        tagCapacity,
+                        err);
+        }
+    }
+
+    /**
+     * Try the language with just the script.
+     **/
+    if (scriptLength > 0) {
+
+        const char* likelySubtags = NULL;
+
+        tagBufferLength = createTagString(
+            lang,
+            langLength,
+            script,
+            scriptLength,
+            NULL,
+            0,
+            NULL,
+            0,
+            tagBuffer,
+            sizeof(tagBuffer),
+            err);
+        if(U_FAILURE(*err)) {
+            goto error;
+        }
+
+        likelySubtags =
+            findLikelySubtags(
+                tagBuffer,
+                likelySubtagsBuffer,
+                sizeof(likelySubtagsBuffer),
+                err);
+        if(U_FAILURE(*err)) {
+            goto error;
+        }
+
+        if (likelySubtags != NULL) {
+            /* Always use the language tag from the
+               maximal string, since it may be more
+               specific than the one provided. */
+            return createTagStringWithAlternates(
+                        NULL,
+                        0,
+                        NULL,
+                        0,
+                        region,
+                        regionLength,
+                        variants,
+                        variantsLength,
+                        likelySubtags,
+                        tag,
+                        tagCapacity,
+                        err);
+        }
+    }
+
+    /**
+     * Try the language with just the region.
+     **/
+    if (regionLength > 0) {
+
+        const char* likelySubtags = NULL;
+
+        createTagString(
+            lang,
+            langLength,
+            NULL,
+            0,
+            region,
+            regionLength,
+            NULL,
+            0,
+            tagBuffer,
+            sizeof(tagBuffer),
+            err);
+        if(U_FAILURE(*err)) {
+            goto error;
+        }
+
+        likelySubtags =
+            findLikelySubtags(
+                tagBuffer,
+                likelySubtagsBuffer,
+                sizeof(likelySubtagsBuffer),
+                err);
+        if(U_FAILURE(*err)) {
+            goto error;
+        }
+
+        if (likelySubtags != NULL) {
+            /* Always use the language tag from the
+               maximal string, since it may be more
+               specific than the one provided. */
+            return createTagStringWithAlternates(
+                        NULL,
+                        0,
+                        script,
+                        scriptLength,
+                        NULL,
+                        0,
+                        variants,
+                        variantsLength,
+                        likelySubtags,
+                        tag,
+                        tagCapacity,
+                        err);
+        }
+    }
+
+    /**
+     * Finally, try just the language.
+     **/
+    {
+        const char* likelySubtags = NULL;
+
+        createTagString(
+            lang,
+            langLength,
+            NULL,
+            0,
+            NULL,
+            0,
+            NULL,
+            0,
+            tagBuffer,
+            sizeof(tagBuffer),
+            err);
+        if(U_FAILURE(*err)) {
+            goto error;
+        }
+
+        likelySubtags =
+            findLikelySubtags(
+                tagBuffer,
+                likelySubtagsBuffer,
+                sizeof(likelySubtagsBuffer),
+                err);
+        if(U_FAILURE(*err)) {
+            goto error;
+        }
+
+        if (likelySubtags != NULL) {
+            /* Always use the language tag from the
+               maximal string, since it may be more
+               specific than the one provided. */
+            return createTagStringWithAlternates(
+                        NULL,
+                        0,
+                        script,
+                        scriptLength,
+                        region,
+                        regionLength,
+                        variants,
+                        variantsLength,
+                        likelySubtags,
+                        tag,
+                        tagCapacity,
+                        err);
+        }
+    }
+
+    return u_terminateChars(
+                tag,
+                tagCapacity,
+                0,
+                err);
+
+error:
+
+    if (!U_FAILURE(*err)) {
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+    }
+
+    return -1;
+}
+
+#define CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength) \
+    {   int32_t count = 0; \
+        int32_t i; \
+        for (i = 0; i < trailingLength; i++) { \
+            if (trailing[i] == '-' || trailing[i] == '_') { \
+                count = 0; \
+                if (count > 8) { \
+                    goto error; \
+                } \
+            } else if (trailing[i] == '@') { \
+                break; \
+            } else if (count > 8) { \
+                goto error; \
+            } else { \
+                count++; \
+            } \
+        } \
+    }
+
+static int32_t
+_uloc_addLikelySubtags(const char*    localeID,
+         char* maximizedLocaleID,
+         int32_t maximizedLocaleIDCapacity,
+         UErrorCode* err)
+{
+    char lang[ULOC_LANG_CAPACITY];
+    int32_t langLength = sizeof(lang);
+    char script[ULOC_SCRIPT_CAPACITY];
+    int32_t scriptLength = sizeof(script);
+    char region[ULOC_COUNTRY_CAPACITY];
+    int32_t regionLength = sizeof(region);
+    const char* trailing = "";
+    int32_t trailingLength = 0;
+    int32_t trailingIndex = 0;
+    int32_t resultLength = 0;
+
+    if(U_FAILURE(*err)) {
+        goto error;
+    }
+    else if (localeID == NULL ||
+             maximizedLocaleID == NULL ||
+             maximizedLocaleIDCapacity <= 0) {
+        goto error;
+    }
+
+    trailingIndex = parseTagString(
+        localeID,
+        lang,
+        &langLength,
+        script,
+        &scriptLength,
+        region,
+        &regionLength,
+        err);
+    if(U_FAILURE(*err)) {
+        /* Overflow indicates an illegal argument error */
+        if (*err == U_BUFFER_OVERFLOW_ERROR) {
+            *err = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+
+        goto error;
+    }
+
+    /* Find the length of the trailing portion. */
+    while (_isIDSeparator(localeID[trailingIndex])) {
+        trailingIndex++;
+    }
+    trailing = &localeID[trailingIndex];
+    trailingLength = (int32_t)uprv_strlen(trailing);
+
+    CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength);
+
+    resultLength =
+        createLikelySubtagsString(
+            lang,
+            langLength,
+            script,
+            scriptLength,
+            region,
+            regionLength,
+            trailing,
+            trailingLength,
+            maximizedLocaleID,
+            maximizedLocaleIDCapacity,
+            err);
+
+    if (resultLength == 0) {
+        const int32_t localIDLength = (int32_t)uprv_strlen(localeID);
+
+        /*
+         * If we get here, we need to return localeID.
+         */
+        uprv_memcpy(
+            maximizedLocaleID,
+            localeID,
+            localIDLength <= maximizedLocaleIDCapacity ? 
+                localIDLength : maximizedLocaleIDCapacity);
+
+        resultLength =
+            u_terminateChars(
+                maximizedLocaleID,
+                maximizedLocaleIDCapacity,
+                localIDLength,
+                err);
+    }
+
+    return resultLength;
+
+error:
+
+    if (!U_FAILURE(*err)) {
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+    }
+
+    return -1;
+}
+
+static int32_t
+_uloc_minimizeSubtags(const char*    localeID,
+         char* minimizedLocaleID,
+         int32_t minimizedLocaleIDCapacity,
+         UErrorCode* err)
+{
+    /**
+     * ULOC_FULLNAME_CAPACITY will provide enough capacity
+     * that we can build a string that contains the language,
+     * script and region code without worrying about overrunning
+     * the user-supplied buffer.
+     **/
+    char maximizedTagBuffer[ULOC_FULLNAME_CAPACITY];
+    int32_t maximizedTagBufferLength = sizeof(maximizedTagBuffer);
+
+    char lang[ULOC_LANG_CAPACITY];
+    int32_t langLength = sizeof(lang);
+    char script[ULOC_SCRIPT_CAPACITY];
+    int32_t scriptLength = sizeof(script);
+    char region[ULOC_COUNTRY_CAPACITY];
+    int32_t regionLength = sizeof(region);
+    const char* trailing = "";
+    int32_t trailingLength = 0;
+    int32_t trailingIndex = 0;
+
+    if(U_FAILURE(*err)) {
+        goto error;
+    }
+    else if (localeID == NULL ||
+             minimizedLocaleID == NULL ||
+             minimizedLocaleIDCapacity <= 0) {
+        goto error;
+    }
+
+    trailingIndex =
+        parseTagString(
+            localeID,
+            lang,
+            &langLength,
+            script,
+            &scriptLength,
+            region,
+            &regionLength,
+            err);
+    if(U_FAILURE(*err)) {
+
+        /* Overflow indicates an illegal argument error */
+        if (*err == U_BUFFER_OVERFLOW_ERROR) {
+            *err = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+
+        goto error;
+    }
+
+    /* Find the spot where the variants or the keywords begin, if any. */
+    while (_isIDSeparator(localeID[trailingIndex])) {
+        trailingIndex++;
+    }
+    trailing = &localeID[trailingIndex];
+    trailingLength = (int32_t)uprv_strlen(trailing);
+
+    CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength);
+
+    createTagString(
+        lang,
+        langLength,
+        script,
+        scriptLength,
+        region,
+        regionLength,
+        NULL,
+        0,
+        maximizedTagBuffer,
+        maximizedTagBufferLength,
+        err);
+    if(U_FAILURE(*err)) {
+        goto error;
+    }
+
+    /**
+     * First, we need to first get the maximization
+     * from AddLikelySubtags.
+     **/
+    maximizedTagBufferLength =
+        uloc_addLikelySubtags(
+            maximizedTagBuffer,
+            maximizedTagBuffer,
+            maximizedTagBufferLength,
+            err);
+
+    if(U_FAILURE(*err)) {
+        goto error;
+    }
+
+    /**
+     * Start first with just the language.
+     **/
+    {
+        char tagBuffer[ULOC_FULLNAME_CAPACITY];
+
+        const int32_t tagBufferLength =
+            createLikelySubtagsString(
+                lang,
+                langLength,
+                NULL,
+                0,
+                NULL,
+                0,
+                NULL,
+                0,
+                tagBuffer,
+                sizeof(tagBuffer),
+                err);
+
+        if(U_FAILURE(*err)) {
+            goto error;
+        }
+        else if (uprv_strnicmp(
+                    maximizedTagBuffer,
+                    tagBuffer,
+                    tagBufferLength) == 0) {
+
+            return createTagString(
+                        lang,
+                        langLength,
+                        NULL,
+                        0,
+                        NULL,
+                        0,
+                        trailing,
+                        trailingLength,
+                        minimizedLocaleID,
+                        minimizedLocaleIDCapacity,
+                        err);
+        }
+    }
+
+    /**
+     * Next, try the language and region.
+     **/
+    if (regionLength > 0) {
+
+        char tagBuffer[ULOC_FULLNAME_CAPACITY];
+
+        const int32_t tagBufferLength =
+            createLikelySubtagsString(
+                lang,
+                langLength,
+                NULL,
+                0,
+                region,
+                regionLength,
+                NULL,
+                0,
+                tagBuffer,
+                sizeof(tagBuffer),
+                err);
+
+        if(U_FAILURE(*err)) {
+            goto error;
+        }
+        else if (uprv_strnicmp(
+                    maximizedTagBuffer,
+                    tagBuffer,
+                    tagBufferLength) == 0) {
+
+            return createTagString(
+                        lang,
+                        langLength,
+                        NULL,
+                        0,
+                        region,
+                        regionLength,
+                        trailing,
+                        trailingLength,
+                        minimizedLocaleID,
+                        minimizedLocaleIDCapacity,
+                        err);
+        }
+    }
+
+    /**
+     * Finally, try the language and script.  This is our last chance,
+     * since trying with all three subtags would only yield the
+     * maximal version that we already have.
+     **/
+    if (scriptLength > 0 && regionLength > 0) {
+        char tagBuffer[ULOC_FULLNAME_CAPACITY];
+
+        const int32_t tagBufferLength =
+            createLikelySubtagsString(
+                lang,
+                langLength,
+                script,
+                scriptLength,
+                NULL,
+                0,
+                NULL,
+                0,
+                tagBuffer,
+                sizeof(tagBuffer),
+                err);
+
+        if(U_FAILURE(*err)) {
+            goto error;
+        }
+        else if (uprv_strnicmp(
+                    maximizedTagBuffer,
+                    tagBuffer,
+                    tagBufferLength) == 0) {
+
+            return createTagString(
+                        lang,
+                        langLength,
+                        script,
+                        scriptLength,
+                        NULL,
+                        0,
+                        trailing,
+                        trailingLength,
+                        minimizedLocaleID,
+                        minimizedLocaleIDCapacity,
+                        err);
+        }
+    }
+
+    {
+        /**
+         * If we got here, return the locale ID parameter.
+         **/
+        const int32_t localeIDLength = (int32_t)uprv_strlen(localeID);
+
+        uprv_memcpy(
+            minimizedLocaleID,
+            localeID,
+            localeIDLength <= minimizedLocaleIDCapacity ? 
+                localeIDLength : minimizedLocaleIDCapacity);
+
+        return u_terminateChars(
+                    minimizedLocaleID,
+                    minimizedLocaleIDCapacity,
+                    localeIDLength,
+                    err);
+    }
+
+error:
+
+    if (!U_FAILURE(*err)) {
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+    }
+
+    return -1;
+
+
+}
+
+static UBool
+do_canonicalize(const char*    localeID,
+         char* buffer,
+         int32_t bufferCapacity,
+         UErrorCode* err)
+{
+    uloc_canonicalize(
+        localeID,
+        buffer,
+        bufferCapacity,
+        err);
+
+    if (*err == U_STRING_NOT_TERMINATED_WARNING ||
+        *err == U_BUFFER_OVERFLOW_ERROR) {
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+
+        return FALSE;
+    }
+    else if (U_FAILURE(*err)) {
+
+        return FALSE;
+    }
+    else {
+        return TRUE;
+    }
+}
+
+U_DRAFT int32_t U_EXPORT2
+uloc_addLikelySubtags(const char*    localeID,
+         char* maximizedLocaleID,
+         int32_t maximizedLocaleIDCapacity,
+         UErrorCode* err)
+{
+    char localeBuffer[ULOC_FULLNAME_CAPACITY];
+
+    if (!do_canonicalize(
+        localeID,
+        localeBuffer,
+        sizeof(localeBuffer),
+        err)) {
+        return -1;
+    }
+    else {
+        return _uloc_addLikelySubtags(
+                    localeBuffer,
+                    maximizedLocaleID,
+                    maximizedLocaleIDCapacity,
+                    err);
+    }    
+}
+
+U_DRAFT int32_t U_EXPORT2
+uloc_minimizeSubtags(const char*    localeID,
+         char* minimizedLocaleID,
+         int32_t minimizedLocaleIDCapacity,
+         UErrorCode* err)
+{
+    char localeBuffer[ULOC_FULLNAME_CAPACITY];
+
+    if (!do_canonicalize(
+        localeID,
+        localeBuffer,
+        sizeof(localeBuffer),
+        err)) {
+        return -1;
+    }
+    else {
+        return _uloc_minimizeSubtags(
+                    localeBuffer,
+                    minimizedLocaleID,
+                    minimizedLocaleIDCapacity,
+                    err);
+    }    
+}
diff --git a/source/common/locmap.c b/source/common/locmap.c
new file mode 100644
index 0000000..0dece00
--- /dev/null
+++ b/source/common/locmap.c
@@ -0,0 +1,992 @@
+/*
+ **********************************************************************
+ *   Copyright (C) 1996-2010, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ **********************************************************************
+ *
+ * Provides functionality for mapping between
+ * LCID and Posix IDs or ICU locale to codepage
+ *
+ * Note: All classes and code in this file are
+ *       intended for internal use only.
+ *
+ * Methods of interest:
+ *   unsigned long convertToLCID(const char*);
+ *   const char* convertToPosix(unsigned long);
+ *
+ * Kathleen Wilson, 4/30/96
+ *
+ *  Date        Name        Description
+ *  3/11/97     aliu        Fixed off-by-one bug in assignment operator. Added
+ *                          setId() method and safety check against 
+ *                          MAX_ID_LENGTH.
+ * 04/23/99     stephen     Added C wrapper for convertToPosix.
+ * 09/18/00     george      Removed the memory leaks.
+ * 08/23/01     george      Convert to C
+ */
+
+#include "locmap.h"
+#include "unicode/uloc.h"
+#include "cstring.h"
+#include "cmemory.h"
+
+#if defined(U_WINDOWS) && defined(_MSC_VER) && (_MSC_VER >= 1500)
+#define USE_WINDOWS_LOCALE_API
+#endif
+
+#ifdef USE_WINDOWS_LOCALE_API
+#include <windows.h>
+#include <winnls.h>
+#endif
+
+/*
+ * Note:
+ * The mapping from Win32 locale ID numbers to POSIX locale strings should
+ * be the faster one.
+ *
+ * Many LCID values come from winnt.h
+ * Some also come from http://www.microsoft.com/globaldev/reference/lcid-all.mspx
+ */
+
+/*
+////////////////////////////////////////////////
+//
+// Internal Classes for LCID <--> POSIX Mapping
+//
+/////////////////////////////////////////////////
+*/
+
+typedef struct ILcidPosixElement
+{
+    const uint32_t hostID;
+    const char * const posixID;
+} ILcidPosixElement;
+
+typedef struct ILcidPosixMap
+{
+    const uint32_t numRegions;
+    const struct ILcidPosixElement* const regionMaps;
+} ILcidPosixMap;
+
+
+/*
+/////////////////////////////////////////////////
+//
+// Easy macros to make the LCID <--> POSIX Mapping
+//
+/////////////////////////////////////////////////
+*/
+
+/**
+ * The standard one language/one country mapping for LCID.
+ * The first element must be the language, and the following
+ * elements are the language with the country.
+ * @param hostID LCID in host format such as 0x044d
+ * @param languageID posix ID of just the language such as 'de'
+ * @param posixID posix ID of the language_TERRITORY such as 'de_CH'
+ */
+#define ILCID_POSIX_ELEMENT_ARRAY(hostID, languageID, posixID) \
+static const ILcidPosixElement locmap_ ## languageID [] = { \
+    {LANGUAGE_LCID(hostID), #languageID},     /* parent locale */ \
+    {hostID, #posixID}, \
+};
+
+/**
+ * Define a subtable by ID
+ * @param id the POSIX ID, either a language or language_TERRITORY
+ */
+#define ILCID_POSIX_SUBTABLE(id) \
+static const ILcidPosixElement locmap_ ## id [] =
+
+
+/**
+ * Create the map for the posixID. This macro supposes that the language string
+ * name is the same as the global variable name, and that the first element
+ * in the ILcidPosixElement is just the language.
+ * @param _posixID the full POSIX ID for this entry. 
+ */
+#define ILCID_POSIX_MAP(_posixID) \
+    {sizeof(locmap_ ## _posixID)/sizeof(ILcidPosixElement), locmap_ ## _posixID}
+
+/*
+////////////////////////////////////////////
+//
+// Create the table of LCID to POSIX Mapping
+// None of it should be dynamically created.
+//
+// Keep static locale variables inside the function so that
+// it can be created properly during static init.
+//
+// Note: This table should be updated periodically. Check the National Lanaguage Support API Reference Website.
+//       Microsoft is moving away from LCID in favor of locale name as of Vista.  This table needs to be
+//       maintained for support of older Windows version.
+//       Update: Windows 7 (091130)
+////////////////////////////////////////////
+*/
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0436, af, af_ZA)
+
+ILCID_POSIX_SUBTABLE(ar) {
+    {0x01,   "ar"},
+    {0x3801, "ar_AE"},
+    {0x3c01, "ar_BH"},
+    {0x1401, "ar_DZ"},
+    {0x0c01, "ar_EG"},
+    {0x0801, "ar_IQ"},
+    {0x2c01, "ar_JO"},
+    {0x3401, "ar_KW"},
+    {0x3001, "ar_LB"},
+    {0x1001, "ar_LY"},
+    {0x1801, "ar_MA"},
+    {0x2001, "ar_OM"},
+    {0x4001, "ar_QA"},
+    {0x0401, "ar_SA"},
+    {0x2801, "ar_SY"},
+    {0x1c01, "ar_TN"},
+    {0x2401, "ar_YE"}
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x044d, as, as_IN)
+ILCID_POSIX_ELEMENT_ARRAY(0x045e, am, am_ET)
+ILCID_POSIX_ELEMENT_ARRAY(0x047a, arn,arn_CL)
+
+ILCID_POSIX_SUBTABLE(az) {
+    {0x2c,   "az"},
+    {0x082c, "az_Cyrl_AZ"},  /* Cyrillic based */
+    {0x742c, "az_Cyrl"},  /* Cyrillic based */
+    {0x042c, "az_Latn_AZ"}, /* Latin based */
+    {0x782c, "az_Latn"}, /* Latin based */
+    {0x042c, "az_AZ"} /* Latin based */
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x046d, ba, ba_RU)
+ILCID_POSIX_ELEMENT_ARRAY(0x0423, be, be_BY)
+
+ILCID_POSIX_SUBTABLE(ber) {
+    {0x5f,   "ber"},
+    {0x045f, "ber_Arab_DZ"},
+    {0x045f, "ber_Arab"},
+    {0x085f, "ber_Latn_DZ"},
+    {0x085f, "ber_Latn"}
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0402, bg, bg_BG)
+
+ILCID_POSIX_SUBTABLE(bn) {
+    {0x45,   "bn"},
+    {0x0845, "bn_BD"},
+    {0x0445, "bn_IN"}
+};
+
+ILCID_POSIX_SUBTABLE(bo) {
+    {0x51,   "bo"},
+    {0x0851, "bo_BT"},
+    {0x0451, "bo_CN"}
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x047e, br, br_FR)
+ILCID_POSIX_ELEMENT_ARRAY(0x0403, ca, ca_ES)
+ILCID_POSIX_ELEMENT_ARRAY(0x0483, co, co_FR)
+ILCID_POSIX_ELEMENT_ARRAY(0x045c, chr,chr_US)
+
+/* Declared as cs_CZ to get around compiler errors on z/OS, which defines cs as a function */
+ILCID_POSIX_ELEMENT_ARRAY(0x0405, cs, cs_CZ)
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0452, cy, cy_GB)
+ILCID_POSIX_ELEMENT_ARRAY(0x0406, da, da_DK)
+
+ILCID_POSIX_SUBTABLE(de) {
+    {0x07,   "de"},
+    {0x0c07, "de_AT"},
+    {0x0807, "de_CH"},
+    {0x0407, "de_DE"},
+    {0x1407, "de_LI"},
+    {0x1007, "de_LU"},
+    {0x10407,"de_DE@collation=phonebook"},  /*This is really de_DE_PHONEBOOK on Windows*/
+    {0x10407,"de@collation=phonebook"}  /*This is really de_DE_PHONEBOOK on Windows*/
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0465, dv, dv_MV)
+ILCID_POSIX_ELEMENT_ARRAY(0x0408, el, el_GR)
+
+ILCID_POSIX_SUBTABLE(en) {
+    {0x09,   "en"},
+    {0x0c09, "en_AU"},
+    {0x2809, "en_BZ"},
+    {0x1009, "en_CA"},
+    {0x0809, "en_GB"},
+    {0x1809, "en_IE"},
+    {0x4009, "en_IN"},
+    {0x2009, "en_JM"},
+    {0x4409, "en_MY"},
+    {0x1409, "en_NZ"},
+    {0x3409, "en_PH"},
+    {0x4809, "en_SG"},
+    {0x2C09, "en_TT"},
+    {0x0409, "en_US"},
+    {0x007f, "en_US_POSIX"}, /* duplicate for roundtripping */
+    {0x2409, "en_VI"},  /* Virgin Islands AKA Caribbean Islands (en_CB). */
+    {0x1c09, "en_ZA"},
+    {0x3009, "en_ZW"},
+    {0x2409, "en_029"},
+    {0x0409, "en_AS"},  /* Alias for en_US. Leave last. */
+    {0x0409, "en_GU"},  /* Alias for en_US. Leave last. */
+    {0x0409, "en_MH"},  /* Alias for en_US. Leave last. */
+    {0x0409, "en_MP"},  /* Alias for en_US. Leave last. */
+    {0x0409, "en_UM"}   /* Alias for en_US. Leave last. */
+};
+
+ILCID_POSIX_SUBTABLE(en_US_POSIX) {
+    {0x007f, "en_US_POSIX"} /* duplicate for roundtripping */
+};
+
+ILCID_POSIX_SUBTABLE(es) {
+    {0x0a,   "es"},
+    {0x2c0a, "es_AR"},
+    {0x400a, "es_BO"},
+    {0x340a, "es_CL"},
+    {0x240a, "es_CO"},
+    {0x140a, "es_CR"},
+    {0x1c0a, "es_DO"},
+    {0x300a, "es_EC"},
+    {0x0c0a, "es_ES"},      /*Modern sort.*/
+    {0x100a, "es_GT"},
+    {0x480a, "es_HN"},
+    {0x080a, "es_MX"},
+    {0x4c0a, "es_NI"},
+    {0x180a, "es_PA"},
+    {0x280a, "es_PE"},
+    {0x500a, "es_PR"},
+    {0x3c0a, "es_PY"},
+    {0x440a, "es_SV"},
+    {0x540a, "es_US"},
+    {0x380a, "es_UY"},
+    {0x200a, "es_VE"},
+    {0x040a, "es_ES@collation=traditional"},
+    {0x040a, "es@collation=traditional"}
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0425, et, et_EE)
+ILCID_POSIX_ELEMENT_ARRAY(0x042d, eu, eu_ES)
+
+/* ISO-639 doesn't distinguish between Persian and Dari.*/
+ILCID_POSIX_SUBTABLE(fa) {
+    {0x29,   "fa"},
+    {0x0429, "fa_IR"},  /* Persian/Farsi (Iran) */
+    {0x048c, "fa_AF"}   /* Persian/Dari (Afghanistan) */
+};
+
+/* duplicate for roundtripping */
+ILCID_POSIX_SUBTABLE(fa_AF) {
+    {0x8c,   "fa_AF"},  /* Persian/Dari (Afghanistan) */
+    {0x048c, "fa_AF"}   /* Persian/Dari (Afghanistan) */
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x040b, fi, fi_FI)
+ILCID_POSIX_ELEMENT_ARRAY(0x0464, fil,fil_PH)
+ILCID_POSIX_ELEMENT_ARRAY(0x0438, fo, fo_FO)
+
+ILCID_POSIX_SUBTABLE(fr) {
+    {0x0c,   "fr"},
+    {0x080c, "fr_BE"},
+    {0x0c0c, "fr_CA"},
+    {0x240c, "fr_CD"},
+    {0x100c, "fr_CH"},
+    {0x300c, "fr_CI"},
+    {0x2c0c, "fr_CM"},
+    {0x040c, "fr_FR"},
+    {0x3c0c, "fr_HT"},
+    {0x140c, "fr_LU"},
+    {0x380c, "fr_MA"},
+    {0x180c, "fr_MC"},
+    {0x340c, "fr_ML"},
+    {0x200c, "fr_RE"},
+    {0x280c, "fr_SN"}
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0462, fy, fy_NL)
+
+/* This LCID is really two different locales.*/
+ILCID_POSIX_ELEMENT_ARRAY(0x083c, ga, ga_IE) /* Gaelic (Ireland) */
+ILCID_POSIX_ELEMENT_ARRAY(0x0491, gd, gd_GB) /* Gaelic (Scotland) */
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0456, gl, gl_ES)
+ILCID_POSIX_ELEMENT_ARRAY(0x0447, gu, gu_IN)
+ILCID_POSIX_ELEMENT_ARRAY(0x0474, gn, gn_PY)
+ILCID_POSIX_ELEMENT_ARRAY(0x0484, gsw,gsw_FR)
+
+ILCID_POSIX_SUBTABLE(ha) {
+    {0x68,   "ha"},
+    {0x7c68, "ha_Latn"},
+    {0x0468, "ha_Latn_NG"},
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0475, haw,haw_US)
+ILCID_POSIX_ELEMENT_ARRAY(0x040d, he, he_IL)
+ILCID_POSIX_ELEMENT_ARRAY(0x0439, hi, hi_IN)
+
+/* This LCID is really four different locales.*/
+ILCID_POSIX_SUBTABLE(hr) {
+    {0x1a,   "hr"},
+    {0x141a, "bs_Latn_BA"},  /* Bosnian, Bosnia and Herzegovina */
+    {0x681a, "bs_Latn"},  /* Bosnian, Bosnia and Herzegovina */
+    {0x141a, "bs_BA"},  /* Bosnian, Bosnia and Herzegovina */
+    {0x781a, "bs"},     /* Bosnian */
+    {0x201a, "bs_Cyrl_BA"},  /* Bosnian, Bosnia and Herzegovina */
+    {0x641a, "bs_Cyrl"},  /* Bosnian, Bosnia and Herzegovina */
+    {0x101a, "hr_BA"},  /* Croatian in Bosnia */
+    {0x041a, "hr_HR"},  /* Croatian*/
+    {0x2c1a, "sr_Latn_ME"},
+    {0x241a, "sr_Latn_RS"},
+    {0x181a, "sr_Latn_BA"}, /* Serbo-Croatian in Bosnia */
+    {0x081a, "sr_Latn_CS"}, /* Serbo-Croatian*/
+    {0x701a, "sr_Latn"},    /* It's 0x1a or 0x081a, pick one to make the test program happy. */
+    {0x1c1a, "sr_Cyrl_BA"}, /* Serbo-Croatian in Bosnia */
+    {0x0c1a, "sr_Cyrl_CS"}, /* Serbian*/
+    {0x301a, "sr_Cyrl_ME"},
+    {0x281a, "sr_Cyrl_RS"},
+    {0x6c1a, "sr_Cyrl"},    /* It's 0x1a or 0x0c1a, pick one to make the test program happy. */
+    {0x7c1a, "sr"}          /* In CLDR sr is sr_Cyrl. */
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x040e, hu, hu_HU)
+ILCID_POSIX_ELEMENT_ARRAY(0x042b, hy, hy_AM)
+ILCID_POSIX_ELEMENT_ARRAY(0x0421, id, id_ID)
+ILCID_POSIX_ELEMENT_ARRAY(0x0470, ig, ig_NG)
+ILCID_POSIX_ELEMENT_ARRAY(0x0478, ii, ii_CN)
+ILCID_POSIX_ELEMENT_ARRAY(0x040f, is, is_IS)
+
+ILCID_POSIX_SUBTABLE(it) {
+    {0x10,   "it"},
+    {0x0810, "it_CH"},
+    {0x0410, "it_IT"}
+};
+
+ILCID_POSIX_SUBTABLE(iu) {
+    {0x5d,   "iu"},
+    {0x045d, "iu_Cans_CA"},
+    {0x785d, "iu_Cans"},
+    {0x085d, "iu_Latn_CA"},
+    {0x7c5d, "iu_Latn"}
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x040d, iw, iw_IL)    /*Left in for compatibility*/
+ILCID_POSIX_ELEMENT_ARRAY(0x0411, ja, ja_JP)
+ILCID_POSIX_ELEMENT_ARRAY(0x0437, ka, ka_GE)
+ILCID_POSIX_ELEMENT_ARRAY(0x043f, kk, kk_KZ)
+ILCID_POSIX_ELEMENT_ARRAY(0x046f, kl, kl_GL)
+ILCID_POSIX_ELEMENT_ARRAY(0x0453, km, km_KH)
+ILCID_POSIX_ELEMENT_ARRAY(0x044b, kn, kn_IN)
+
+ILCID_POSIX_SUBTABLE(ko) {
+    {0x12,   "ko"},
+    {0x0812, "ko_KP"},
+    {0x0412, "ko_KR"}
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0457, kok, kok_IN)
+ILCID_POSIX_ELEMENT_ARRAY(0x0471, kr,  kr_NG)
+
+ILCID_POSIX_SUBTABLE(ks) {         /* We could add PK and CN too */
+    {0x60,   "ks"},
+    {0x0860, "ks_IN"},              /* Documentation doesn't mention script */
+    {0x0460, "ks_Arab_IN"}
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0440, ky, ky_KG)   /* Kyrgyz is spoken in Kyrgyzstan */
+ILCID_POSIX_ELEMENT_ARRAY(0x0476, la, la_IT)   /* TODO: Verify the country */
+ILCID_POSIX_ELEMENT_ARRAY(0x046e, lb, lb_LU)
+ILCID_POSIX_ELEMENT_ARRAY(0x0454, lo, lo_LA)
+ILCID_POSIX_ELEMENT_ARRAY(0x0427, lt, lt_LT)
+ILCID_POSIX_ELEMENT_ARRAY(0x0426, lv, lv_LV)
+ILCID_POSIX_ELEMENT_ARRAY(0x0481, mi, mi_NZ)
+ILCID_POSIX_ELEMENT_ARRAY(0x042f, mk, mk_MK)
+ILCID_POSIX_ELEMENT_ARRAY(0x044c, ml, ml_IN)
+
+ILCID_POSIX_SUBTABLE(mn) {
+    {0x50,   "mn"},
+    {0x0450, "mn_MN"},
+    {0x7c50, "mn_Mong"},
+    {0x0850, "mn_Mong_CN"},
+    {0x0850, "mn_CN"},
+    {0x7850, "mn_Cyrl"}
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0458, mni,mni_IN)
+ILCID_POSIX_ELEMENT_ARRAY(0x047c, moh,moh_CA)
+ILCID_POSIX_ELEMENT_ARRAY(0x044e, mr, mr_IN)
+
+ILCID_POSIX_SUBTABLE(ms) {
+    {0x3e,   "ms"},
+    {0x083e, "ms_BN"},   /* Brunei Darussalam*/
+    {0x043e, "ms_MY"}    /* Malaysia*/
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x043a, mt, mt_MT)
+ILCID_POSIX_ELEMENT_ARRAY(0x0455, my, my_MM)
+
+ILCID_POSIX_SUBTABLE(ne) {
+    {0x61,   "ne"},
+    {0x0861, "ne_IN"},   /* India*/
+    {0x0461, "ne_NP"}    /* Nepal*/
+};
+
+ILCID_POSIX_SUBTABLE(nl) {
+    {0x13,   "nl"},
+    {0x0813, "nl_BE"},
+    {0x0413, "nl_NL"}
+};
+
+/* The "no" locale split into nb and nn.  By default in ICU, "no" is nb.*/
+ILCID_POSIX_SUBTABLE(no) {
+    {0x14,   "no"},     /* really nb_NO */
+    {0x7c14, "nb"},     /* really nb */
+    {0x0414, "nb_NO"},  /* really nb_NO. Keep first in the 414 list. */
+    {0x0414, "no_NO"},  /* really nb_NO */
+    {0x0814, "nn_NO"},  /* really nn_NO. Keep first in the 814 list.  */
+    {0x7814, "nn"},     /* It's 0x14 or 0x814, pick one to make the test program happy. */
+    {0x0814, "no_NO_NY"}/* really nn_NO */
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x046c, nso,nso_ZA)   /* TODO: Verify the ISO-639 code */
+ILCID_POSIX_ELEMENT_ARRAY(0x0482, oc, oc_FR)
+ILCID_POSIX_ELEMENT_ARRAY(0x0472, om, om_ET)    /* TODO: Verify the country */
+
+/* Declared as or_IN to get around compiler errors*/
+ILCID_POSIX_SUBTABLE(or_IN) {
+    {0x48,   "or"},
+    {0x0448, "or_IN"},
+};
+
+
+ILCID_POSIX_SUBTABLE(pa) {
+    {0x46,   "pa"},
+    {0x0446, "pa_IN"},
+    {0x0846, "pa_PK"}
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0415, pl, pl_PL)
+ILCID_POSIX_ELEMENT_ARRAY(0x0463, ps, ps_AF)
+
+ILCID_POSIX_SUBTABLE(pt) {
+    {0x16,   "pt"},
+    {0x0416, "pt_BR"},
+    {0x0816, "pt_PT"}
+};
+
+ILCID_POSIX_SUBTABLE(qu) {
+    {0x6b,   "qu"},
+    {0x046b, "qu_BO"},
+    {0x086b, "qu_EC"},
+    {0x0C6b, "qu_PE"}
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0486, qut, qut_GT) /* qut is an ISO-639-3 code */
+ILCID_POSIX_ELEMENT_ARRAY(0x0417, rm, rm_CH)
+ILCID_POSIX_ELEMENT_ARRAY(0x0418, ro, ro_RO)
+
+ILCID_POSIX_SUBTABLE(root) {
+    {0x00,   "root"}
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0419, ru, ru_RU)
+ILCID_POSIX_ELEMENT_ARRAY(0x0487, rw, rw_RW)
+ILCID_POSIX_ELEMENT_ARRAY(0x044f, sa, sa_IN)
+ILCID_POSIX_ELEMENT_ARRAY(0x0485, sah,sah_RU)
+
+ILCID_POSIX_SUBTABLE(sd) {
+    {0x59,   "sd"},
+    {0x0459, "sd_IN"},
+    {0x0859, "sd_PK"}
+};
+
+ILCID_POSIX_SUBTABLE(se) {
+    {0x3b,   "se"},
+    {0x0c3b, "se_FI"},
+    {0x043b, "se_NO"},
+    {0x083b, "se_SE"},
+    {0x783b, "sma"},
+    {0x183b, "sma_NO"},
+    {0x1c3b, "sma_SE"},
+    {0x7c3b, "smj"},
+    {0x703b, "smn"},
+    {0x743b, "sms"},
+    {0x103b, "smj_NO"},
+    {0x143b, "smj_SE"},
+    {0x243b, "smn_FI"},
+    {0x203b, "sms_FI"},
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x045b, si, si_LK)
+ILCID_POSIX_ELEMENT_ARRAY(0x041b, sk, sk_SK)
+ILCID_POSIX_ELEMENT_ARRAY(0x0424, sl, sl_SI)
+ILCID_POSIX_ELEMENT_ARRAY(0x0477, so, so_ET)    /* TODO: Verify the country */
+ILCID_POSIX_ELEMENT_ARRAY(0x041c, sq, sq_AL)
+
+ILCID_POSIX_SUBTABLE(sv) {
+    {0x1d,   "sv"},
+    {0x081d, "sv_FI"},
+    {0x041d, "sv_SE"}
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0441, sw, sw_KE)
+ILCID_POSIX_ELEMENT_ARRAY(0x045A, syr, syr_SY)
+ILCID_POSIX_ELEMENT_ARRAY(0x0449, ta, ta_IN)
+ILCID_POSIX_ELEMENT_ARRAY(0x044a, te, te_IN)
+
+/* Cyrillic based by default */
+ILCID_POSIX_SUBTABLE(tg) {
+    {0x28,   "tg"},
+    {0x7c28, "tg_Cyrl"},
+    {0x0428, "tg_Cyrl_TJ"}
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x041e, th, th_TH)
+
+ILCID_POSIX_SUBTABLE(ti) {
+    {0x73,   "ti"},
+    {0x0873, "ti_ER"},
+    {0x0473, "ti_ET"}
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0442, tk, tk_TM)
+ILCID_POSIX_ELEMENT_ARRAY(0x0432, tn, tn_BW)
+ILCID_POSIX_ELEMENT_ARRAY(0x041f, tr, tr_TR)
+ILCID_POSIX_ELEMENT_ARRAY(0x0444, tt, tt_RU)
+
+ILCID_POSIX_SUBTABLE(tzm) {
+    {0x5f,   "tzm"},
+    {0x7c5f, "tzm_Latn"},
+    {0x085f, "tzm_Latn_DZ"}
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0480, ug, ug_CN)
+ILCID_POSIX_ELEMENT_ARRAY(0x0422, uk, uk_UA)
+
+ILCID_POSIX_SUBTABLE(ur) {
+    {0x20,   "ur"},
+    {0x0820, "ur_IN"},
+    {0x0420, "ur_PK"}
+};
+
+ILCID_POSIX_SUBTABLE(uz) {
+    {0x43,   "uz"},
+    {0x0843, "uz_Cyrl_UZ"},  /* Cyrillic based */
+    {0x7843, "uz_Cyrl"},  /* Cyrillic based */
+    {0x0843, "uz_UZ"},  /* Cyrillic based */
+    {0x0443, "uz_Latn_UZ"}, /* Latin based */
+    {0x7c43, "uz_Latn"} /* Latin based */
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0433, ve, ve_ZA)    /* TODO: Verify the country */
+ILCID_POSIX_ELEMENT_ARRAY(0x042a, vi, vi_VN)
+
+ILCID_POSIX_SUBTABLE(wen) {
+    {0x2E,   "wen"},
+    {0x042E, "wen_DE"},
+    {0x042E, "hsb_DE"},
+    {0x082E, "dsb_DE"},
+    {0x7C2E, "dsb"},
+    {0x2E,   "hsb"}
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0488, wo, wo_SN)
+ILCID_POSIX_ELEMENT_ARRAY(0x0434, xh, xh_ZA)
+ILCID_POSIX_ELEMENT_ARRAY(0x046a, yo, yo_NG)
+
+ILCID_POSIX_SUBTABLE(zh) {
+    {0x0004, "zh_Hans"},
+    {0x7804, "zh"},
+    {0x0804, "zh_CN"},
+    {0x0804, "zh_Hans_CN"},
+    {0x0c04, "zh_Hant_HK"},
+    {0x0c04, "zh_HK"},
+    {0x1404, "zh_Hant_MO"},
+    {0x1404, "zh_MO"},
+    {0x1004, "zh_Hans_SG"},
+    {0x1004, "zh_SG"},
+    {0x0404, "zh_Hant_TW"},
+    {0x7c04, "zh_Hant"},
+    {0x0404, "zh_TW"},
+    {0x30404,"zh_Hant_TW"},     /* Bopomofo order */
+    {0x30404,"zh_TW"},          /* Bopomofo order */
+    {0x20004,"zh@collation=stroke"},
+    {0x20404,"zh_Hant@collation=stroke"},
+    {0x20404,"zh_Hant_TW@collation=stroke"},
+    {0x20404,"zh_TW@collation=stroke"},
+    {0x20804,"zh_Hans@collation=stroke"},
+    {0x20804,"zh_Hans_CN@collation=stroke"},
+    {0x20804,"zh_CN@collation=stroke"}
+};
+
+ILCID_POSIX_ELEMENT_ARRAY(0x0435, zu, zu_ZA)
+
+/* This must be static and grouped by LCID. */
+
+/* non-existent ISO-639-2 codes */
+/*
+0x466   Edo
+0x467   Fulfulde - Nigeria
+0x486   K'iche - Guatemala
+0x430   Sutu
+*/
+static const ILcidPosixMap gPosixIDmap[] = {
+    ILCID_POSIX_MAP(af),    /*  af  Afrikaans                 0x36 */
+    ILCID_POSIX_MAP(am),    /*  am  Amharic                   0x5e */
+    ILCID_POSIX_MAP(ar),    /*  ar  Arabic                    0x01 */
+    ILCID_POSIX_MAP(arn),   /*  arn Araucanian/Mapudungun     0x7a */
+    ILCID_POSIX_MAP(as),    /*  as  Assamese                  0x4d */
+    ILCID_POSIX_MAP(az),    /*  az  Azerbaijani               0x2c */
+    ILCID_POSIX_MAP(ba),    /*  ba  Bashkir                   0x6d */
+    ILCID_POSIX_MAP(be),    /*  be  Belarusian                0x23 */
+/*    ILCID_POSIX_MAP(ber),     ber Berber/Tamazight          0x5f */
+    ILCID_POSIX_MAP(bg),    /*  bg  Bulgarian                 0x02 */
+    ILCID_POSIX_MAP(bn),    /*  bn  Bengali; Bangla           0x45 */
+    ILCID_POSIX_MAP(bo),    /*  bo  Tibetan                   0x51 */
+    ILCID_POSIX_MAP(br),    /*  br  Breton                    0x7e */
+    ILCID_POSIX_MAP(ca),    /*  ca  Catalan                   0x03 */
+    ILCID_POSIX_MAP(chr),   /*  chr Cherokee                  0x5c */
+    ILCID_POSIX_MAP(co),    /*  co  Corsican                  0x83 */
+    ILCID_POSIX_MAP(cs),    /*  cs  Czech                     0x05 */
+    ILCID_POSIX_MAP(cy),    /*  cy  Welsh                     0x52 */
+    ILCID_POSIX_MAP(da),    /*  da  Danish                    0x06 */
+    ILCID_POSIX_MAP(de),    /*  de  German                    0x07 */
+    ILCID_POSIX_MAP(dv),    /*  dv  Divehi                    0x65 */
+    ILCID_POSIX_MAP(el),    /*  el  Greek                     0x08 */
+    ILCID_POSIX_MAP(en),    /*  en  English                   0x09 */
+    ILCID_POSIX_MAP(en_US_POSIX), /*    invariant             0x7f */
+    ILCID_POSIX_MAP(es),    /*  es  Spanish                   0x0a */
+    ILCID_POSIX_MAP(et),    /*  et  Estonian                  0x25 */
+    ILCID_POSIX_MAP(eu),    /*  eu  Basque                    0x2d */
+    ILCID_POSIX_MAP(fa),    /*  fa  Persian/Farsi             0x29 */
+    ILCID_POSIX_MAP(fa_AF), /*  fa  Persian/Dari              0x8c */
+    ILCID_POSIX_MAP(fi),    /*  fi  Finnish                   0x0b */
+    ILCID_POSIX_MAP(fil),   /*  fil Filipino                  0x64 */
+    ILCID_POSIX_MAP(fo),    /*  fo  Faroese                   0x38 */
+    ILCID_POSIX_MAP(fr),    /*  fr  French                    0x0c */
+    ILCID_POSIX_MAP(fy),    /*  fy  Frisian                   0x62 */
+    ILCID_POSIX_MAP(ga),    /*  *   Gaelic (Ireland,Scotland) 0x3c */
+    ILCID_POSIX_MAP(gd),    /*  gd  Gaelic (United Kingdom)   0x91 */
+    ILCID_POSIX_MAP(gl),    /*  gl  Galician                  0x56 */
+    ILCID_POSIX_MAP(gn),    /*  gn  Guarani                   0x74 */
+    ILCID_POSIX_MAP(gsw),   /*  gsw Alemanic/Alsatian/Swiss German 0x84 */
+    ILCID_POSIX_MAP(gu),    /*  gu  Gujarati                  0x47 */
+    ILCID_POSIX_MAP(ha),    /*  ha  Hausa                     0x68 */
+    ILCID_POSIX_MAP(haw),   /*  haw Hawaiian                  0x75 */
+    ILCID_POSIX_MAP(he),    /*  he  Hebrew (formerly iw)      0x0d */
+    ILCID_POSIX_MAP(hi),    /*  hi  Hindi                     0x39 */
+    ILCID_POSIX_MAP(hr),    /*  *   Croatian and others       0x1a */
+    ILCID_POSIX_MAP(hu),    /*  hu  Hungarian                 0x0e */
+    ILCID_POSIX_MAP(hy),    /*  hy  Armenian                  0x2b */
+    ILCID_POSIX_MAP(id),    /*  id  Indonesian (formerly in)  0x21 */
+    ILCID_POSIX_MAP(ig),    /*  ig  Igbo                      0x70 */
+    ILCID_POSIX_MAP(ii),    /*  ii  Sichuan Yi                0x78 */
+    ILCID_POSIX_MAP(is),    /*  is  Icelandic                 0x0f */
+    ILCID_POSIX_MAP(it),    /*  it  Italian                   0x10 */
+    ILCID_POSIX_MAP(iu),    /*  iu  Inuktitut                 0x5d */
+    ILCID_POSIX_MAP(iw),    /*  iw  Hebrew                    0x0d */
+    ILCID_POSIX_MAP(ja),    /*  ja  Japanese                  0x11 */
+    ILCID_POSIX_MAP(ka),    /*  ka  Georgian                  0x37 */
+    ILCID_POSIX_MAP(kk),    /*  kk  Kazakh                    0x3f */
+    ILCID_POSIX_MAP(kl),    /*  kl  Kalaallisut               0x6f */
+    ILCID_POSIX_MAP(km),    /*  km  Khmer                     0x53 */
+    ILCID_POSIX_MAP(kn),    /*  kn  Kannada                   0x4b */
+    ILCID_POSIX_MAP(ko),    /*  ko  Korean                    0x12 */
+    ILCID_POSIX_MAP(kok),   /*  kok Konkani                   0x57 */
+    ILCID_POSIX_MAP(kr),    /*  kr  Kanuri                    0x71 */
+    ILCID_POSIX_MAP(ks),    /*  ks  Kashmiri                  0x60 */
+    ILCID_POSIX_MAP(ky),    /*  ky  Kyrgyz                    0x40 */
+    ILCID_POSIX_MAP(lb),    /*  lb  Luxembourgish             0x6e */
+    ILCID_POSIX_MAP(la),    /*  la  Latin                     0x76 */
+    ILCID_POSIX_MAP(lo),    /*  lo  Lao                       0x54 */
+    ILCID_POSIX_MAP(lt),    /*  lt  Lithuanian                0x27 */
+    ILCID_POSIX_MAP(lv),    /*  lv  Latvian, Lettish          0x26 */
+    ILCID_POSIX_MAP(mi),    /*  mi  Maori                     0x81 */
+    ILCID_POSIX_MAP(mk),    /*  mk  Macedonian                0x2f */
+    ILCID_POSIX_MAP(ml),    /*  ml  Malayalam                 0x4c */
+    ILCID_POSIX_MAP(mn),    /*  mn  Mongolian                 0x50 */
+    ILCID_POSIX_MAP(mni),   /*  mni Manipuri                  0x58 */
+    ILCID_POSIX_MAP(moh),   /*  moh Mohawk                    0x7c */
+    ILCID_POSIX_MAP(mr),    /*  mr  Marathi                   0x4e */
+    ILCID_POSIX_MAP(ms),    /*  ms  Malay                     0x3e */
+    ILCID_POSIX_MAP(mt),    /*  mt  Maltese                   0x3a */
+    ILCID_POSIX_MAP(my),    /*  my  Burmese                   0x55 */
+/*    ILCID_POSIX_MAP(nb),    //  no  Norwegian                 0x14 */
+    ILCID_POSIX_MAP(ne),    /*  ne  Nepali                    0x61 */
+    ILCID_POSIX_MAP(nl),    /*  nl  Dutch                     0x13 */
+/*    ILCID_POSIX_MAP(nn),    //  no  Norwegian                 0x14 */
+    ILCID_POSIX_MAP(no),    /*  *   Norwegian                 0x14 */
+    ILCID_POSIX_MAP(nso),   /*  nso Sotho, Northern (Sepedi dialect) 0x6c */
+    ILCID_POSIX_MAP(oc),    /*  oc  Occitan                   0x82 */
+    ILCID_POSIX_MAP(om),    /*  om  Oromo                     0x72 */
+    ILCID_POSIX_MAP(or_IN), /*  or  Oriya                     0x48 */
+    ILCID_POSIX_MAP(pa),    /*  pa  Punjabi                   0x46 */
+    ILCID_POSIX_MAP(pl),    /*  pl  Polish                    0x15 */
+    ILCID_POSIX_MAP(ps),    /*  ps  Pashto                    0x63 */
+    ILCID_POSIX_MAP(pt),    /*  pt  Portuguese                0x16 */
+    ILCID_POSIX_MAP(qu),    /*  qu  Quechua                   0x6B */
+    ILCID_POSIX_MAP(qut),   /*  qut K'iche                    0x86 */
+    ILCID_POSIX_MAP(rm),    /*  rm  Raeto-Romance/Romansh     0x17 */
+    ILCID_POSIX_MAP(ro),    /*  ro  Romanian                  0x18 */
+    ILCID_POSIX_MAP(root),  /*  root                          0x00 */
+    ILCID_POSIX_MAP(ru),    /*  ru  Russian                   0x19 */
+    ILCID_POSIX_MAP(rw),    /*  rw  Kinyarwanda               0x87 */
+    ILCID_POSIX_MAP(sa),    /*  sa  Sanskrit                  0x4f */
+    ILCID_POSIX_MAP(sah),   /*  sah Yakut                     0x85 */
+    ILCID_POSIX_MAP(sd),    /*  sd  Sindhi                    0x59 */
+    ILCID_POSIX_MAP(se),    /*  se  Sami                      0x3b */
+/*    ILCID_POSIX_MAP(sh),    //  sh  Serbo-Croatian            0x1a */
+    ILCID_POSIX_MAP(si),    /*  si  Sinhalese                 0x5b */
+    ILCID_POSIX_MAP(sk),    /*  sk  Slovak                    0x1b */
+    ILCID_POSIX_MAP(sl),    /*  sl  Slovenian                 0x24 */
+    ILCID_POSIX_MAP(so),    /*  so  Somali                    0x77 */
+    ILCID_POSIX_MAP(sq),    /*  sq  Albanian                  0x1c */
+/*    ILCID_POSIX_MAP(sr),    //  sr  Serbian                   0x1a */
+    ILCID_POSIX_MAP(sv),    /*  sv  Swedish                   0x1d */
+    ILCID_POSIX_MAP(sw),    /*  sw  Swahili                   0x41 */
+    ILCID_POSIX_MAP(syr),   /*  syr Syriac                    0x5A */
+    ILCID_POSIX_MAP(ta),    /*  ta  Tamil                     0x49 */
+    ILCID_POSIX_MAP(te),    /*  te  Telugu                    0x4a */
+    ILCID_POSIX_MAP(tg),    /*  tg  Tajik                     0x28 */
+    ILCID_POSIX_MAP(th),    /*  th  Thai                      0x1e */
+    ILCID_POSIX_MAP(ti),    /*  ti  Tigrigna                  0x73 */
+    ILCID_POSIX_MAP(tk),    /*  tk  Turkmen                   0x42 */
+    ILCID_POSIX_MAP(tn),    /*  tn  Tswana                    0x32 */
+    ILCID_POSIX_MAP(tr),    /*  tr  Turkish                   0x1f */
+    ILCID_POSIX_MAP(tt),    /*  tt  Tatar                     0x44 */
+    ILCID_POSIX_MAP(tzm),   /*  tzm                           0x5f */
+    ILCID_POSIX_MAP(ug),    /*  ug  Uighur                    0x80 */
+    ILCID_POSIX_MAP(uk),    /*  uk  Ukrainian                 0x22 */
+    ILCID_POSIX_MAP(ur),    /*  ur  Urdu                      0x20 */
+    ILCID_POSIX_MAP(uz),    /*  uz  Uzbek                     0x43 */
+    ILCID_POSIX_MAP(ve),    /*  ve  Venda                     0x33 */
+    ILCID_POSIX_MAP(vi),    /*  vi  Vietnamese                0x2a */
+    ILCID_POSIX_MAP(wen),   /*  wen Sorbian                   0x2e */
+    ILCID_POSIX_MAP(wo),    /*  wo  Wolof                     0x88 */
+    ILCID_POSIX_MAP(xh),    /*  xh  Xhosa                     0x34 */
+    ILCID_POSIX_MAP(yo),    /*  yo  Yoruba                    0x6a */
+    ILCID_POSIX_MAP(zh),    /*  zh  Chinese                   0x04 */
+    ILCID_POSIX_MAP(zu),    /*  zu  Zulu                      0x35 */
+};
+
+static const uint32_t gLocaleCount = sizeof(gPosixIDmap)/sizeof(ILcidPosixMap);
+
+/**
+ * Do not call this function. It is called by hostID.
+ * The function is not private because this struct must stay as a C struct,
+ * and this is an internal class.
+ */
+static int32_t
+idCmp(const char* id1, const char* id2)
+{
+    int32_t diffIdx = 0;
+    while (*id1 == *id2 && *id1 != 0) {
+        diffIdx++;
+        id1++;
+        id2++;
+    }
+    return diffIdx;
+}
+
+/**
+ * Searches for a Windows LCID
+ *
+ * @param posixid the Posix style locale id.
+ * @param status gets set to U_ILLEGAL_ARGUMENT_ERROR when the Posix ID has
+ *               no equivalent Windows LCID.
+ * @return the LCID
+ */
+static uint32_t
+getHostID(const ILcidPosixMap *this_0, const char* posixID, UErrorCode* status)
+{
+    int32_t bestIdx = 0;
+    int32_t bestIdxDiff = 0;
+    int32_t posixIDlen = (int32_t)uprv_strlen(posixID);
+    uint32_t idx;
+
+    for (idx = 0; idx < this_0->numRegions; idx++ ) {
+        int32_t sameChars = idCmp(posixID, this_0->regionMaps[idx].posixID);
+        if (sameChars > bestIdxDiff && this_0->regionMaps[idx].posixID[sameChars] == 0) {
+            if (posixIDlen == sameChars) {
+                /* Exact match */
+                return this_0->regionMaps[idx].hostID;
+            }
+            bestIdxDiff = sameChars;
+            bestIdx = idx;
+        }
+    }
+    /* We asked for something unusual, like en_ZZ, and we try to return the number for the same language. */
+    /* We also have to make sure that sid and si and similar string subsets don't match. */
+    if ((posixID[bestIdxDiff] == '_' || posixID[bestIdxDiff] == '@')
+        && this_0->regionMaps[bestIdx].posixID[bestIdxDiff] == 0)
+    {
+        *status = U_USING_FALLBACK_WARNING;
+        return this_0->regionMaps[bestIdx].hostID;
+    }
+
+    /*no match found */
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+    return this_0->regionMaps->hostID;
+}
+
+static const char*
+getPosixID(const ILcidPosixMap *this_0, uint32_t hostID)
+{
+    uint32_t i;
+    for (i = 0; i <= this_0->numRegions; i++)
+    {
+        if (this_0->regionMaps[i].hostID == hostID)
+        {
+            return this_0->regionMaps[i].posixID;
+        }
+    }
+
+    /* If you get here, then no matching region was found,
+       so return the language id with the wild card region. */
+    return this_0->regionMaps[0].posixID;
+}
+
+/*
+//////////////////////////////////////
+//
+// LCID --> POSIX
+//
+/////////////////////////////////////
+*/
+#ifdef USE_WINDOWS_LOCALE_API
+/*
+ * Change the tag separator from '-' to '_'
+ */
+#define FIX_LOCALE_ID_TAG_SEPARATOR(buffer, len, i) \
+    for(i = 0; i < len; i++) \
+        if (buffer[i] == '-') buffer[i] = '_';
+
+/*
+ * Various language tags needs to be changed:
+ * quz -> qu
+ * prs -> fa
+ */
+#define FIX_LANGUAGE_ID_TAG(buffer, len) \
+    if (len >= 3) { \
+        if (buffer[0] == 'q' && buffer[1] == 'u' && buffer[2] == 'z') {\
+            buffer[2] = 0; \
+            uprv_strcat(buffer, buffer+3); \
+        } else if (buffer[0] == 'p' && buffer[1] == 'r' && buffer[2] == 's') {\
+            buffer[0] = 'f'; buffer[1] = 'a'; buffer[2] = 0; \
+            uprv_strcat(buffer, buffer+3); \
+        } \
+    }
+
+static char gPosixFromLCID[ULOC_FULLNAME_CAPACITY];
+#endif
+U_CAPI const char *
+uprv_convertToPosix(uint32_t hostid, UErrorCode* status)
+{
+    uint16_t langID;
+    uint32_t localeIndex;
+#ifdef USE_WINDOWS_LOCALE_API
+    int32_t ret = 0;
+
+    uprv_memset(gPosixFromLCID, 0, sizeof(gPosixFromLCID));
+
+    ret = GetLocaleInfoA(hostid, LOCALE_SNAME, (LPSTR)gPosixFromLCID, sizeof(gPosixFromLCID));
+    if (ret > 1) {
+        FIX_LOCALE_ID_TAG_SEPARATOR(gPosixFromLCID, ret, localeIndex)
+        FIX_LANGUAGE_ID_TAG(gPosixFromLCID, ret)
+
+        return gPosixFromLCID;
+    }
+#endif
+    langID = LANGUAGE_LCID(hostid);
+
+    for (localeIndex = 0; localeIndex < gLocaleCount; localeIndex++)
+    {
+        if (langID == gPosixIDmap[localeIndex].regionMaps->hostID)
+        {
+            return getPosixID(&gPosixIDmap[localeIndex], hostid);
+        }
+    }
+
+    /* no match found */
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+    return NULL;
+}
+
+/*
+//////////////////////////////////////
+//
+// POSIX --> LCID
+// This should only be called from uloc_getLCID.
+// The locale ID must be in canonical form.
+// langID is separate so that this file doesn't depend on the uloc_* API.
+//
+/////////////////////////////////////
+*/
+
+U_CAPI uint32_t
+uprv_convertToLCID(const char *langID, const char* posixID, UErrorCode* status)
+{
+
+    uint32_t   low    = 0;
+    uint32_t   high   = gLocaleCount;
+    uint32_t   mid    = high;
+    uint32_t   oldmid = 0;
+    int32_t    compVal;
+
+    uint32_t   value         = 0;
+    uint32_t   fallbackValue = (uint32_t)-1;
+    UErrorCode myStatus;
+    uint32_t   idx;
+
+    /* Check for incomplete id. */
+    if (!langID || !posixID || uprv_strlen(langID) < 2 || uprv_strlen(posixID) < 2) {
+        return 0;
+    }
+
+    /*Binary search for the map entry for normal cases */
+
+    while (high > low)  /*binary search*/{
+
+        mid = (high+low) >> 1; /*Finds median*/
+
+        if (mid == oldmid) 
+            break;
+
+        compVal = uprv_strcmp(langID, gPosixIDmap[mid].regionMaps->posixID);
+        if (compVal < 0){
+            high = mid;
+        }
+        else if (compVal > 0){
+            low = mid;
+        }
+        else /*we found it*/{
+            return getHostID(&gPosixIDmap[mid], posixID, status);
+        }
+        oldmid = mid;
+    }
+
+    /*
+     * Sometimes we can't do a binary search on posixID because some LCIDs
+     * go to different locales.  We hit one of those special cases.
+     */
+    for (idx = 0; idx < gLocaleCount; idx++ ) {
+        myStatus = U_ZERO_ERROR;
+        value = getHostID(&gPosixIDmap[idx], posixID, &myStatus);
+        if (myStatus == U_ZERO_ERROR) {
+            return value;
+        }
+        else if (myStatus == U_USING_FALLBACK_WARNING) {
+            fallbackValue = value;
+        }
+    }
+
+    if (fallbackValue != (uint32_t)-1) {
+        *status = U_USING_FALLBACK_WARNING;
+        return fallbackValue;
+    }
+
+    /* no match found */
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+    return 0;   /* return international (root) */
+}
+
diff --git a/source/common/locmap.h b/source/common/locmap.h
new file mode 100644
index 0000000..7db0607
--- /dev/null
+++ b/source/common/locmap.h
@@ -0,0 +1,37 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1996-2004, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File locmap.h      : Locale Mapping Classes
+* 
+*
+* Created by: Helena Shih
+*
+* Modification History:
+*
+*  Date        Name        Description
+*  3/11/97     aliu        Added setId().
+*  4/20/99     Madhu       Added T_convertToPosix()
+* 09/18/00     george      Removed the memory leaks.
+* 08/23/01     george      Convert to C
+*============================================================================
+*/
+
+#ifndef LOCMAP_H
+#define LOCMAP_H
+
+#include "unicode/utypes.h"
+
+#define LANGUAGE_LCID(hostID) (uint16_t)(0x03FF & hostID)
+
+U_CAPI const char *uprv_convertToPosix(uint32_t hostid, UErrorCode* status);
+
+/* Don't call this function directly. Use uloc_getLCID instead. */
+U_CAPI uint32_t uprv_convertToLCID(const char *langID, const char* posixID, UErrorCode* status);
+
+#endif /* LOCMAP_H */
+
diff --git a/source/common/locresdata.cpp b/source/common/locresdata.cpp
new file mode 100644
index 0000000..2c601c2
--- /dev/null
+++ b/source/common/locresdata.cpp
@@ -0,0 +1,224 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  loclikely.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2010feb25
+*   created by: Markus W. Scherer
+*
+*   Code for miscellaneous locale-related resource bundle data access,
+*   separated out from other .cpp files
+*   that then do not depend on resource bundle code and this data.
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/putil.h"
+#include "unicode/uloc.h"
+#include "unicode/ures.h"
+#include "cstring.h"
+#include "ulocimp.h"
+#include "uresimp.h"
+
+/*
+ * Lookup a resource bundle table item with fallback on the table level.
+ * Regular resource bundle lookups perform fallback to parent locale bundles
+ * and eventually the root bundle, but only for top-level items.
+ * This function takes the name of a top-level table and of an item in that table
+ * and performs a lookup of both, falling back until a bundle contains a table
+ * with this item.
+ *
+ * Note: Only the opening of entire bundles falls back through the default locale
+ * before root. Once a bundle is open, item lookups do not go through the
+ * default locale because that would result in a mix of languages that is
+ * unpredictable to the programmer and most likely useless.
+ */
+U_CAPI const UChar * U_EXPORT2
+uloc_getTableStringWithFallback(const char *path, const char *locale,
+                              const char *tableKey, const char *subTableKey,
+                              const char *itemKey,
+                              int32_t *pLength,
+                              UErrorCode *pErrorCode)
+{
+/*    char localeBuffer[ULOC_FULLNAME_CAPACITY*4];*/
+    UResourceBundle *rb=NULL, table, subTable;
+    const UChar *item=NULL;
+    UErrorCode errorCode;
+    char explicitFallbackName[ULOC_FULLNAME_CAPACITY] = {0};
+
+    /*
+     * open the bundle for the current locale
+     * this falls back through the locale's chain to root
+     */
+    errorCode=U_ZERO_ERROR;
+    rb=ures_open(path, locale, &errorCode);
+
+    if(U_FAILURE(errorCode)) {
+        /* total failure, not even root could be opened */
+        *pErrorCode=errorCode;
+        return NULL;
+    } else if(errorCode==U_USING_DEFAULT_WARNING ||
+                (errorCode==U_USING_FALLBACK_WARNING && *pErrorCode!=U_USING_DEFAULT_WARNING)
+    ) {
+        /* set the "strongest" error code (success->fallback->default->failure) */
+        *pErrorCode=errorCode;
+    }
+
+    for(;;){
+        ures_initStackObject(&table);
+        ures_initStackObject(&subTable);
+        ures_getByKeyWithFallback(rb, tableKey, &table, &errorCode);
+
+        if (subTableKey != NULL) {
+            /*
+            ures_getByKeyWithFallback(&table,subTableKey, &subTable, &errorCode);
+            item = ures_getStringByKeyWithFallback(&subTable, itemKey, pLength, &errorCode);
+            if(U_FAILURE(errorCode)){
+                *pErrorCode = errorCode;
+            }
+            
+            break;*/
+            
+            ures_getByKeyWithFallback(&table,subTableKey, &table, &errorCode);
+        }
+        if(U_SUCCESS(errorCode)){
+            item = ures_getStringByKeyWithFallback(&table, itemKey, pLength, &errorCode);
+            if(U_FAILURE(errorCode)){
+                const char* replacement = NULL;
+                *pErrorCode = errorCode; /*save the errorCode*/
+                errorCode = U_ZERO_ERROR;
+                /* may be a deprecated code */
+                if(uprv_strcmp(tableKey, "Countries")==0){
+                    replacement =  uloc_getCurrentCountryID(itemKey);
+                }else if(uprv_strcmp(tableKey, "Languages")==0){
+                    replacement =  uloc_getCurrentLanguageID(itemKey);
+                }
+                /*pointer comparison is ok since uloc_getCurrentCountryID & uloc_getCurrentLanguageID return the key itself is replacement is not found*/
+                if(replacement!=NULL && itemKey != replacement){
+                    item = ures_getStringByKeyWithFallback(&table, replacement, pLength, &errorCode);
+                    if(U_SUCCESS(errorCode)){
+                        *pErrorCode = errorCode;
+                        break;
+                    }
+                }
+            }else{
+                break;
+            }
+        }
+        
+        if(U_FAILURE(errorCode)){    
+
+            /* still can't figure out ?.. try the fallback mechanism */
+            int32_t len = 0;
+            const UChar* fallbackLocale =  NULL;
+            *pErrorCode = errorCode;
+            errorCode = U_ZERO_ERROR;
+
+            fallbackLocale = ures_getStringByKeyWithFallback(&table, "Fallback", &len, &errorCode);
+            if(U_FAILURE(errorCode)){
+               *pErrorCode = errorCode;
+                break;
+            }
+            
+            u_UCharsToChars(fallbackLocale, explicitFallbackName, len);
+            
+            /* guard against recursive fallback */
+            if(uprv_strcmp(explicitFallbackName, locale)==0){
+                *pErrorCode = U_INTERNAL_PROGRAM_ERROR;
+                break;
+            }
+            ures_close(rb);
+            rb = ures_open(path, explicitFallbackName, &errorCode);
+            if(U_FAILURE(errorCode)){
+                *pErrorCode = errorCode;
+                break;
+            }
+            /* succeeded in opening the fallback bundle .. continue and try to fetch the item */
+        }else{
+            break;
+        }
+    }
+    /* done with the locale string - ready to close table and rb */
+    ures_close(&subTable);
+    ures_close(&table);
+    ures_close(rb);
+    return item;
+}
+
+static ULayoutType
+_uloc_getOrientationHelper(const char* localeId,
+                           const char* key,
+                           UErrorCode *status)
+{
+    ULayoutType result = ULOC_LAYOUT_UNKNOWN;
+
+    if (!U_FAILURE(*status)) {
+        int32_t length = 0;
+        char localeBuffer[ULOC_FULLNAME_CAPACITY];
+
+        uloc_canonicalize(localeId, localeBuffer, sizeof(localeBuffer), status);
+
+        if (!U_FAILURE(*status)) {
+            const UChar* const value =
+                uloc_getTableStringWithFallback(
+                    NULL,
+                    localeBuffer,
+                    "layout",
+                    NULL,
+                    key,
+                    &length,
+                    status);
+
+            if (!U_FAILURE(*status) && length != 0) {
+                switch(value[0])
+                {
+                case 0x0062: /* 'b' */
+                    result = ULOC_LAYOUT_BTT;
+                    break;
+                case 0x006C: /* 'l' */
+                    result = ULOC_LAYOUT_LTR;
+                    break;
+                case 0x0072: /* 'r' */
+                    result = ULOC_LAYOUT_RTL;
+                    break;
+                case 0x0074: /* 't' */
+                    result = ULOC_LAYOUT_TTB;
+                    break;
+                default:
+                    *status = U_INTERNAL_PROGRAM_ERROR;
+                    break;
+                }
+            }
+        }
+    }
+
+    return result;
+}
+
+U_DRAFT ULayoutType U_EXPORT2
+uloc_getCharacterOrientation(const char* localeId,
+                             UErrorCode *status)
+{
+    return _uloc_getOrientationHelper(localeId, "characters", status);
+}
+
+/**
+ * Get the layout line orientation for the specified locale.
+ * 
+ * @param localeID locale name
+ * @param status Error status
+ * @return an enum indicating the layout orientation for lines.
+ * @stable ICU 4.0
+ */
+U_DRAFT ULayoutType U_EXPORT2
+uloc_getLineOrientation(const char* localeId,
+                        UErrorCode *status)
+{
+    return _uloc_getOrientationHelper(localeId, "lines", status);
+}
diff --git a/source/common/locutil.cpp b/source/common/locutil.cpp
new file mode 100644
index 0000000..57c305f
--- /dev/null
+++ b/source/common/locutil.cpp
@@ -0,0 +1,265 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2002-2010, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ *******************************************************************************
+ */
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_SERVICE || !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/resbund.h"
+#include "cmemory.h"
+#include "ustrfmt.h"
+#include "locutil.h"
+#include "charstr.h"
+#include "ucln_cmn.h"
+#include "uassert.h"
+#include "umutex.h"
+
+// see LocaleUtility::getAvailableLocaleNames
+static U_NAMESPACE_QUALIFIER Hashtable * LocaleUtility_cache = NULL;
+
+#define UNDERSCORE_CHAR ((UChar)0x005f)
+#define AT_SIGN_CHAR    ((UChar)64)
+#define PERIOD_CHAR     ((UChar)46)
+
+/*
+ ******************************************************************
+ */
+
+/**
+ * Release all static memory held by Locale Utility.  
+ */
+U_CDECL_BEGIN
+static UBool U_CALLCONV service_cleanup(void) {
+    if (LocaleUtility_cache) {
+        delete LocaleUtility_cache;
+        LocaleUtility_cache = NULL;
+    }
+    return TRUE;
+}
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+UnicodeString&
+LocaleUtility::canonicalLocaleString(const UnicodeString* id, UnicodeString& result)
+{
+  if (id == NULL) {
+    result.setToBogus();
+  } else {
+    // Fix case only (no other changes) up to the first '@' or '.' or
+    // end of string, whichever comes first.  In 3.0 I changed this to
+    // stop at first '@' or '.'.  It used to run out to the end of
+    // string.  My fix makes the tests pass but is probably
+    // structurally incorrect.  See below.  [alan 3.0]
+
+    // TODO: Doug, you might want to revise this...
+    result = *id;
+    int32_t i = 0;
+    int32_t end = result.indexOf(AT_SIGN_CHAR);
+    int32_t n = result.indexOf(PERIOD_CHAR);
+    if (n >= 0 && n < end) {
+        end = n;
+    }
+    if (end < 0) {
+        end = result.length();
+    }
+    n = result.indexOf(UNDERSCORE_CHAR);
+    if (n < 0) {
+      n = end;
+    }
+    for (; i < n; ++i) {
+      UChar c = result.charAt(i);
+      if (c >= 0x0041 && c <= 0x005a) {
+        c += 0x20;
+        result.setCharAt(i, c);
+      }
+    }
+    for (n = end; i < n; ++i) {
+      UChar c = result.charAt(i);
+      if (c >= 0x0061 && c <= 0x007a) {
+        c -= 0x20;
+        result.setCharAt(i, c);
+      }
+    }
+  }
+  return result;
+
+#if 0
+    // This code does a proper full level 2 canonicalization of id.
+    // It's nasty to go from UChar to char to char to UChar -- but
+    // that's what you have to do to use the uloc_canonicalize
+    // function on UnicodeStrings.
+
+    // I ended up doing the alternate fix (see above) not for
+    // performance reasons, although performance will certainly be
+    // better, but because doing a full level 2 canonicalization
+    // causes some tests to fail.  [alan 3.0]
+
+    // TODO: Doug, you might want to revisit this...
+    result.setToBogus();
+    if (id != 0) {
+        int32_t buflen = id->length() + 8; // space for NUL
+        char* buf = (char*) uprv_malloc(buflen);
+        char* canon = (buf == 0) ? 0 : (char*) uprv_malloc(buflen);
+        if (buf != 0 && canon != 0) {
+            U_ASSERT(id->extract(0, INT32_MAX, buf, buflen) < buflen);
+            UErrorCode ec = U_ZERO_ERROR;
+            uloc_canonicalize(buf, canon, buflen, &ec);
+            if (U_SUCCESS(ec)) {
+                result = UnicodeString(canon);
+            }
+        }
+        uprv_free(buf);
+        uprv_free(canon);
+    }
+    return result;
+#endif
+}
+
+Locale&
+LocaleUtility::initLocaleFromName(const UnicodeString& id, Locale& result)
+{
+    enum { BUFLEN = 128 }; // larger than ever needed
+
+    if (id.isBogus() || id.length() >= BUFLEN) {
+        result.setToBogus();
+    } else {
+        /*
+         * We need to convert from a UnicodeString to char * in order to
+         * create a Locale.
+         *
+         * Problem: Locale ID strings may contain '@' which is a variant
+         * character and cannot be handled by invariant-character conversion.
+         *
+         * Hack: Since ICU code can handle locale IDs with multiple encodings
+         * of '@' (at least for EBCDIC; it's not known to be a problem for
+         * ASCII-based systems),
+         * we use regular invariant-character conversion for everything else
+         * and manually convert U+0040 into a compiler-char-constant '@'.
+         * While this compilation-time constant may not match the runtime
+         * encoding of '@', it should be one of the encodings which ICU
+         * recognizes.
+         *
+         * There should be only at most one '@' in a locale ID.
+         */
+        char buffer[BUFLEN];
+        int32_t prev, i;
+        prev = 0;
+        for(;;) {
+            i = id.indexOf((UChar)0x40, prev);
+            if(i < 0) {
+                // no @ between prev and the rest of the string
+                id.extract(prev, INT32_MAX, buffer + prev, BUFLEN - prev, US_INV);
+                break; // done
+            } else {
+                // normal invariant-character conversion for text between @s
+                id.extract(prev, i - prev, buffer + prev, BUFLEN - prev, US_INV);
+                // manually "convert" U+0040 at id[i] into '@' at buffer[i]
+                buffer[i] = '@';
+                prev = i + 1;
+            }
+        }
+        result = Locale::createFromName(buffer);
+    }
+    return result;
+}
+
+UnicodeString&
+LocaleUtility::initNameFromLocale(const Locale& locale, UnicodeString& result)
+{
+    if (locale.isBogus()) {
+        result.setToBogus();
+    } else {
+        result.append(UnicodeString(locale.getName(), -1, US_INV));
+    }
+    return result;
+}
+
+const Hashtable*
+LocaleUtility::getAvailableLocaleNames(const UnicodeString& bundleID)
+{
+    // LocaleUtility_cache is a hash-of-hashes.  The top-level keys
+    // are path strings ('bundleID') passed to
+    // ures_openAvailableLocales.  The top-level values are
+    // second-level hashes.  The second-level keys are result strings
+    // from ures_openAvailableLocales.  The second-level values are
+    // garbage ((void*)1 or other random pointer).
+
+    UErrorCode status = U_ZERO_ERROR;
+    Hashtable* cache;
+    umtx_lock(NULL);
+    cache = LocaleUtility_cache;
+    umtx_unlock(NULL);
+
+    if (cache == NULL) {
+        cache = new Hashtable(status);
+        if (cache == NULL || U_FAILURE(status)) {
+            return NULL; // catastrophic failure; e.g. out of memory
+        }
+        cache->setValueDeleter(uhash_deleteHashtable);
+        Hashtable* h; // set this to final LocaleUtility_cache value
+        umtx_lock(NULL);
+        h = LocaleUtility_cache;
+        if (h == NULL) {
+            LocaleUtility_cache = h = cache;
+            cache = NULL;
+            ucln_common_registerCleanup(UCLN_COMMON_SERVICE, service_cleanup);
+        }
+        umtx_unlock(NULL);
+        if(cache != NULL) {
+          delete cache;
+        }
+        cache = h;
+    }
+
+    U_ASSERT(cache != NULL);
+
+    Hashtable* htp;
+    umtx_lock(NULL);
+    htp = (Hashtable*) cache->get(bundleID);
+    umtx_unlock(NULL);
+
+    if (htp == NULL) {
+        htp = new Hashtable(status);
+        if (htp && U_SUCCESS(status)) {
+            CharString cbundleID;
+            cbundleID.appendInvariantChars(bundleID, status);
+            const char* path = cbundleID.isEmpty() ? NULL : cbundleID.data();
+            UEnumeration *uenum = ures_openAvailableLocales(path, &status);
+            for (;;) {
+                const UChar* id = uenum_unext(uenum, NULL, &status);
+                if (id == NULL) {
+                    break;
+                }
+                htp->put(UnicodeString(id), (void*)htp, status);
+            }
+            uenum_close(uenum);
+            if (U_FAILURE(status)) {
+                delete htp;
+                return NULL;
+            }
+            umtx_lock(NULL);
+            cache->put(bundleID, (void*)htp, status);
+            umtx_unlock(NULL);
+        }
+    }
+    return htp;
+}
+
+UBool
+LocaleUtility::isFallbackOf(const UnicodeString& root, const UnicodeString& child)
+{
+    return child.indexOf(root) == 0 &&
+      (child.length() == root.length() ||
+       child.charAt(root.length()) == UNDERSCORE_CHAR);
+}
+
+U_NAMESPACE_END
+
+/* !UCONFIG_NO_SERVICE */
+#endif
+
+
diff --git a/source/common/locutil.h b/source/common/locutil.h
new file mode 100644
index 0000000..cf64e34
--- /dev/null
+++ b/source/common/locutil.h
@@ -0,0 +1,37 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2002-2005, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ *******************************************************************************
+ */
+#ifndef LOCUTIL_H
+#define LOCUTIL_H
+
+#include "unicode/utypes.h"
+#include "hash.h"
+
+#if !UCONFIG_NO_SERVICE || !UCONFIG_NO_TRANSLITERATION
+
+
+U_NAMESPACE_BEGIN
+
+// temporary utility functions, till I know where to find them
+// in header so tests can also access them
+
+class U_COMMON_API LocaleUtility {
+public:
+  static UnicodeString& canonicalLocaleString(const UnicodeString* id, UnicodeString& result);
+  static Locale& initLocaleFromName(const UnicodeString& id, Locale& result);
+  static UnicodeString& initNameFromLocale(const Locale& locale, UnicodeString& result);
+  static const Hashtable* getAvailableLocaleNames(const UnicodeString& bundleID);
+  static UBool isFallbackOf(const UnicodeString& root, const UnicodeString& child);
+};
+
+U_NAMESPACE_END
+
+
+#endif
+
+#endif
diff --git a/source/common/msvcres.h b/source/common/msvcres.h
new file mode 100644
index 0000000..7ed61b4
--- /dev/null
+++ b/source/common/msvcres.h
@@ -0,0 +1,23 @@
+//{{NO_DEPENDENCIES}}
+// Copyright (c) 2003-2010 International Business Machines
+// Corporation and others. All Rights Reserved.
+//
+// Used by common.rc and other .rc files.
+//Do not edit with Microsoft Developer Studio because it will modify this
+//header the wrong way. This is here to prevent Visual Studio .NET from
+//unnessarily building the resource files when it's not needed.
+//
+
+/*
+These are defined before unicode/uversion.h in order to prevent 
+STLPort's broken stddef.h from being used when rc.exe parses this file. 
+*/
+#define _STLP_OUTERMOST_HEADER_ID 0
+#define _STLP_WINCE 1
+
+#include "unicode/uversion.h"
+
+#define ICU_WEBSITE "http://icu-project.org"
+#define ICU_COMPANY "The ICU Project"
+#define ICU_PRODUCT_PREFIX "ICU"
+#define ICU_PRODUCT "International Components for Unicode"
diff --git a/source/common/mutex.cpp b/source/common/mutex.cpp
new file mode 100644
index 0000000..8da3c7e
--- /dev/null
+++ b/source/common/mutex.cpp
@@ -0,0 +1,91 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2008-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  mutex.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*/
+
+#include "unicode/utypes.h"
+#include "mutex.h"
+
+U_NAMESPACE_BEGIN
+
+void *SimpleSingleton::getInstance(InstantiatorFn *instantiator, const void *context,
+                                   void *&duplicate,
+                                   UErrorCode &errorCode) {
+    duplicate=NULL;
+    if(U_FAILURE(errorCode)) {
+        return NULL;
+    }
+    void *instance;
+    UMTX_CHECK(NULL, fInstance, instance);
+    if(instance!=NULL) {
+        return instance;
+    } else {
+        instance=instantiator(context, errorCode);
+        Mutex mutex;
+        if(fInstance==NULL && U_SUCCESS(errorCode)) {
+            fInstance=instance;
+        } else {
+            duplicate=instance;
+        }
+        return fInstance;
+    }
+}
+
+void *TriStateSingleton::getInstance(InstantiatorFn *instantiator, const void *context,
+                                     void *&duplicate,
+                                     UErrorCode &errorCode) {
+    duplicate=NULL;
+    if(U_FAILURE(errorCode)) {
+        return NULL;
+    }
+    int8_t haveInstance;
+    UMTX_CHECK(NULL, fHaveInstance, haveInstance);
+    if(haveInstance>0) {
+        return fInstance;  // instance was created
+    } else if(haveInstance<0) {
+        errorCode=fErrorCode;  // instance creation failed
+        return NULL;
+    } else /* haveInstance==0 */ {
+        void *instance=instantiator(context, errorCode);
+        Mutex mutex;
+        if(fHaveInstance==0) {
+            if(U_SUCCESS(errorCode)) {
+                fInstance=instance;
+                instance=NULL;
+                fHaveInstance=1;
+            } else {
+                fErrorCode=errorCode;
+                fHaveInstance=-1;
+            }
+        } else {
+            errorCode=fErrorCode;
+        }
+        duplicate=instance;
+        return fInstance;
+    }
+}
+
+void TriStateSingleton::reset() {
+    fInstance=NULL;
+    fErrorCode=U_ZERO_ERROR;
+    fHaveInstance=0;
+}
+
+#if UCONFIG_NO_SERVICE
+
+/* If UCONFIG_NO_SERVICE, then there is no invocation of Mutex elsewhere in
+   common, so add one here to force an export */
+static Mutex *aMutex = 0;
+
+/* UCONFIG_NO_SERVICE */
+#endif
+
+U_NAMESPACE_END
diff --git a/source/common/mutex.h b/source/common/mutex.h
new file mode 100644
index 0000000..ea2e348
--- /dev/null
+++ b/source/common/mutex.h
@@ -0,0 +1,199 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*/
+//----------------------------------------------------------------------------
+// File:     mutex.h
+//
+// Lightweight C++ wrapper for umtx_ C mutex functions
+//
+// Author:   Alan Liu  1/31/97
+// History:
+// 06/04/97   helena         Updated setImplementation as per feedback from 5/21 drop.
+// 04/07/1999  srl               refocused as a thin wrapper
+//
+//----------------------------------------------------------------------------
+#ifndef MUTEX_H
+#define MUTEX_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "umutex.h"
+
+U_NAMESPACE_BEGIN
+
+//----------------------------------------------------------------------------
+// Code within that accesses shared static or global data should
+// should instantiate a Mutex object while doing so. You should make your own 
+// private mutex where possible.
+
+// For example:
+// 
+// UMTX myMutex;
+// 
+// void Function(int arg1, int arg2)
+// {
+//    static Object* foo;     // Shared read-write object
+//    Mutex mutex(&myMutex);  // or no args for the global lock
+//    foo->Method();
+//    // When 'mutex' goes out of scope and gets destroyed here, the lock is released
+// }
+//
+// Note:  Do NOT use the form 'Mutex mutex();' as that merely forward-declares a function
+//        returning a Mutex. This is a common mistake which silently slips through the
+//        compiler!!
+//
+
+class U_COMMON_API Mutex : public UMemory {
+public:
+  inline Mutex(UMTX *mutex = NULL);
+  inline ~Mutex();
+
+private:
+  UMTX   *fMutex;
+
+  Mutex(const Mutex &other); // forbid copying of this class
+  Mutex &operator=(const Mutex &other); // forbid copying of this class
+};
+
+inline Mutex::Mutex(UMTX *mutex)
+  : fMutex(mutex)
+{
+  umtx_lock(fMutex);
+}
+
+inline Mutex::~Mutex()
+{
+  umtx_unlock(fMutex);
+}
+
+// common code for singletons ---------------------------------------------- ***
+
+/**
+ * Function pointer for the instantiator parameter of
+ * SimpleSingleton::getInstance() and TriStateSingleton::getInstance().
+ * The function creates some object, optionally using the context parameter.
+ * The function need not check for U_FAILURE(errorCode).
+ */
+typedef void *InstantiatorFn(const void *context, UErrorCode &errorCode);
+
+/**
+ * Singleton struct with shared instantiation/mutexing code.
+ * Simple: Does not remember if a previous instantiation failed.
+ * Best used if the instantiation can really only fail with an out-of-memory error,
+ * otherwise use a TriStateSingleton.
+ * Best used via SimpleSingletonWrapper or similar.
+ * Define a static SimpleSingleton instance via the STATIC_SIMPLE_SINGLETON macro.
+ */
+struct SimpleSingleton {
+    void *fInstance;
+
+    /**
+     * Returns the singleton instance, or NULL if it could not be created.
+     * Calls the instantiator with the context if the instance has not been
+     * created yet. In a race condition, the duplicate may not be NULL.
+     * The caller must delete the duplicate.
+     * The caller need not initialize the duplicate before the call.
+     */
+    void *getInstance(InstantiatorFn *instantiator, const void *context,
+                      void *&duplicate,
+                      UErrorCode &errorCode);
+    /**
+     * Resets the fields. The caller must have deleted the singleton instance.
+     * Not mutexed.
+     * Call this from a cleanup function.
+     */
+    void reset() { fInstance=NULL; }
+};
+
+#define STATIC_SIMPLE_SINGLETON(name) static SimpleSingleton name={ NULL }
+
+/**
+ * Handy wrapper for an SimpleSingleton.
+ * Intended for temporary use on the stack, to make the SimpleSingleton easier to deal with.
+ * Takes care of the duplicate deletion and type casting.
+ */
+template<typename T>
+class SimpleSingletonWrapper {
+public:
+    SimpleSingletonWrapper(SimpleSingleton &s) : singleton(s) {}
+    void deleteInstance() {
+        delete (T *)singleton.fInstance;
+        singleton.reset();
+    }
+    T *getInstance(InstantiatorFn *instantiator, const void *context,
+                   UErrorCode &errorCode) {
+        void *duplicate;
+        T *instance=(T *)singleton.getInstance(instantiator, context, duplicate, errorCode);
+        delete (T *)duplicate;
+        return instance;
+    }
+private:
+    SimpleSingleton &singleton;
+};
+
+/**
+ * Singleton struct with shared instantiation/mutexing code.
+ * Tri-state: Instantiation succeeded/failed/not attempted yet.
+ * Best used via TriStateSingletonWrapper or similar.
+ * Define a static TriStateSingleton instance via the STATIC_TRI_STATE_SINGLETON macro.
+ */
+struct TriStateSingleton {
+    void *fInstance;
+    UErrorCode fErrorCode;
+    int8_t fHaveInstance;
+
+    /**
+     * Returns the singleton instance, or NULL if it could not be created.
+     * Calls the instantiator with the context if the instance has not been
+     * created yet. In a race condition, the duplicate may not be NULL.
+     * The caller must delete the duplicate.
+     * The caller need not initialize the duplicate before the call.
+     * The singleton creation is only attempted once. If it fails,
+     * the singleton will then always return NULL.
+     */
+    void *getInstance(InstantiatorFn *instantiator, const void *context,
+                      void *&duplicate,
+                      UErrorCode &errorCode);
+    /**
+     * Resets the fields. The caller must have deleted the singleton instance.
+     * Not mutexed.
+     * Call this from a cleanup function.
+     */
+    void reset();
+};
+
+#define STATIC_TRI_STATE_SINGLETON(name) static TriStateSingleton name={ NULL, U_ZERO_ERROR, 0 }
+
+/**
+ * Handy wrapper for an TriStateSingleton.
+ * Intended for temporary use on the stack, to make the TriStateSingleton easier to deal with.
+ * Takes care of the duplicate deletion and type casting.
+ */
+template<typename T>
+class TriStateSingletonWrapper {
+public:
+    TriStateSingletonWrapper(TriStateSingleton &s) : singleton(s) {}
+    void deleteInstance() {
+        delete (T *)singleton.fInstance;
+        singleton.reset();
+    }
+    T *getInstance(InstantiatorFn *instantiator, const void *context,
+                   UErrorCode &errorCode) {
+        void *duplicate;
+        T *instance=(T *)singleton.getInstance(instantiator, context, duplicate, errorCode);
+        delete (T *)duplicate;
+        return instance;
+    }
+private:
+    TriStateSingleton &singleton;
+};
+
+U_NAMESPACE_END
+
+#endif //_MUTEX_
+//eof
diff --git a/source/common/normalizer2.cpp b/source/common/normalizer2.cpp
new file mode 100644
index 0000000..fd0048c
--- /dev/null
+++ b/source/common/normalizer2.cpp
@@ -0,0 +1,847 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2009-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  normalizer2.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2009nov22
+*   created by: Markus W. Scherer
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/localpointer.h"
+#include "unicode/normalizer2.h"
+#include "unicode/unistr.h"
+#include "unicode/unorm.h"
+#include "cpputils.h"
+#include "cstring.h"
+#include "mutex.h"
+#include "normalizer2impl.h"
+#include "ucln_cmn.h"
+#include "uhash.h"
+
+U_NAMESPACE_BEGIN
+
+// Public API dispatch via Normalizer2 subclasses -------------------------- ***
+
+// Normalizer2 implementation for the old UNORM_NONE.
+class NoopNormalizer2 : public Normalizer2 {
+    virtual UnicodeString &
+    normalize(const UnicodeString &src,
+              UnicodeString &dest,
+              UErrorCode &errorCode) const {
+        if(U_SUCCESS(errorCode)) {
+            if(&dest!=&src) {
+                dest=src;
+            } else {
+                errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+            }
+        }
+        return dest;
+    }
+    virtual UnicodeString &
+    normalizeSecondAndAppend(UnicodeString &first,
+                             const UnicodeString &second,
+                             UErrorCode &errorCode) const {
+        if(U_SUCCESS(errorCode)) {
+            if(&first!=&second) {
+                first.append(second);
+            } else {
+                errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+            }
+        }
+        return first;
+    }
+    virtual UnicodeString &
+    append(UnicodeString &first,
+           const UnicodeString &second,
+           UErrorCode &errorCode) const {
+        if(U_SUCCESS(errorCode)) {
+            if(&first!=&second) {
+                first.append(second);
+            } else {
+                errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+            }
+        }
+        return first;
+    }
+    virtual UBool
+    getDecomposition(UChar32, UnicodeString &) const {
+        return FALSE;
+    }
+    virtual UBool
+    isNormalized(const UnicodeString &, UErrorCode &) const {
+        return TRUE;
+    }
+    virtual UNormalizationCheckResult
+    quickCheck(const UnicodeString &, UErrorCode &) const {
+        return UNORM_YES;
+    }
+    virtual int32_t
+    spanQuickCheckYes(const UnicodeString &s, UErrorCode &) const {
+        return s.length();
+    }
+    virtual UBool hasBoundaryBefore(UChar32) const { return TRUE; }
+    virtual UBool hasBoundaryAfter(UChar32) const { return TRUE; }
+    virtual UBool isInert(UChar32) const { return TRUE; }
+};
+
+// Intermediate class:
+// Has Normalizer2Impl and does boilerplate argument checking and setup.
+class Normalizer2WithImpl : public Normalizer2 {
+public:
+    Normalizer2WithImpl(const Normalizer2Impl &ni) : impl(ni) {}
+
+    // normalize
+    virtual UnicodeString &
+    normalize(const UnicodeString &src,
+              UnicodeString &dest,
+              UErrorCode &errorCode) const {
+        if(U_FAILURE(errorCode)) {
+            dest.setToBogus();
+            return dest;
+        }
+        const UChar *sArray=src.getBuffer();
+        if(&dest==&src || sArray==NULL) {
+            errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+            dest.setToBogus();
+            return dest;
+        }
+        dest.remove();
+        ReorderingBuffer buffer(impl, dest);
+        if(buffer.init(src.length(), errorCode)) {
+            normalize(sArray, sArray+src.length(), buffer, errorCode);
+        }
+        return dest;
+    }
+    virtual void
+    normalize(const UChar *src, const UChar *limit,
+              ReorderingBuffer &buffer, UErrorCode &errorCode) const = 0;
+
+    // normalize and append
+    virtual UnicodeString &
+    normalizeSecondAndAppend(UnicodeString &first,
+                             const UnicodeString &second,
+                             UErrorCode &errorCode) const {
+        return normalizeSecondAndAppend(first, second, TRUE, errorCode);
+    }
+    virtual UnicodeString &
+    append(UnicodeString &first,
+           const UnicodeString &second,
+           UErrorCode &errorCode) const {
+        return normalizeSecondAndAppend(first, second, FALSE, errorCode);
+    }
+    UnicodeString &
+    normalizeSecondAndAppend(UnicodeString &first,
+                             const UnicodeString &second,
+                             UBool doNormalize,
+                             UErrorCode &errorCode) const {
+        uprv_checkCanGetBuffer(first, errorCode);
+        if(U_FAILURE(errorCode)) {
+            return first;
+        }
+        const UChar *secondArray=second.getBuffer();
+        if(&first==&second || secondArray==NULL) {
+            errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+            return first;
+        }
+        ReorderingBuffer buffer(impl, first);
+        if(buffer.init(first.length()+second.length(), errorCode)) {
+            normalizeAndAppend(secondArray, secondArray+second.length(), doNormalize,
+                               buffer, errorCode);
+        }
+        return first;
+    }
+    virtual void
+    normalizeAndAppend(const UChar *src, const UChar *limit, UBool doNormalize,
+                       ReorderingBuffer &buffer, UErrorCode &errorCode) const = 0;
+    virtual UBool
+    getDecomposition(UChar32 c, UnicodeString &decomposition) const {
+        UChar buffer[4];
+        int32_t length;
+        const UChar *d=impl.getDecomposition(c, buffer, length);
+        if(d==NULL) {
+            return FALSE;
+        }
+        if(d==buffer) {
+            decomposition.setTo(buffer, length);  // copy the string (Jamos from Hangul syllable c)
+        } else {
+            decomposition.setTo(FALSE, d, length);  // read-only alias
+        }
+        return TRUE;
+    }
+
+    // quick checks
+    virtual UBool
+    isNormalized(const UnicodeString &s, UErrorCode &errorCode) const {
+        if(U_FAILURE(errorCode)) {
+            return FALSE;
+        }
+        const UChar *sArray=s.getBuffer();
+        if(sArray==NULL) {
+            errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+            return FALSE;
+        }
+        const UChar *sLimit=sArray+s.length();
+        return sLimit==spanQuickCheckYes(sArray, sLimit, errorCode);
+    }
+    virtual UNormalizationCheckResult
+    quickCheck(const UnicodeString &s, UErrorCode &errorCode) const {
+        return Normalizer2WithImpl::isNormalized(s, errorCode) ? UNORM_YES : UNORM_NO;
+    }
+    virtual int32_t
+    spanQuickCheckYes(const UnicodeString &s, UErrorCode &errorCode) const {
+        if(U_FAILURE(errorCode)) {
+            return 0;
+        }
+        const UChar *sArray=s.getBuffer();
+        if(sArray==NULL) {
+            errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+            return 0;
+        }
+        return (int32_t)(spanQuickCheckYes(sArray, sArray+s.length(), errorCode)-sArray);
+    }
+    virtual const UChar *
+    spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const = 0;
+
+    virtual UNormalizationCheckResult getQuickCheck(UChar32) const {
+        return UNORM_YES;
+    }
+
+    const Normalizer2Impl &impl;
+};
+
+class DecomposeNormalizer2 : public Normalizer2WithImpl {
+public:
+    DecomposeNormalizer2(const Normalizer2Impl &ni) : Normalizer2WithImpl(ni) {}
+
+private:
+    virtual void
+    normalize(const UChar *src, const UChar *limit,
+              ReorderingBuffer &buffer, UErrorCode &errorCode) const {
+        impl.decompose(src, limit, &buffer, errorCode);
+    }
+    using Normalizer2WithImpl::normalize;  // Avoid warning about hiding base class function.
+    virtual void
+    normalizeAndAppend(const UChar *src, const UChar *limit, UBool doNormalize,
+                       ReorderingBuffer &buffer, UErrorCode &errorCode) const {
+        impl.decomposeAndAppend(src, limit, doNormalize, buffer, errorCode);
+    }
+    virtual const UChar *
+    spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const {
+        return impl.decompose(src, limit, NULL, errorCode);
+    }
+    using Normalizer2WithImpl::spanQuickCheckYes;  // Avoid warning about hiding base class function.
+    virtual UNormalizationCheckResult getQuickCheck(UChar32 c) const {
+        return impl.isDecompYes(impl.getNorm16(c)) ? UNORM_YES : UNORM_NO;
+    }
+    virtual UBool hasBoundaryBefore(UChar32 c) const { return impl.hasDecompBoundary(c, TRUE); }
+    virtual UBool hasBoundaryAfter(UChar32 c) const { return impl.hasDecompBoundary(c, FALSE); }
+    virtual UBool isInert(UChar32 c) const { return impl.isDecompInert(c); }
+};
+
+class ComposeNormalizer2 : public Normalizer2WithImpl {
+public:
+    ComposeNormalizer2(const Normalizer2Impl &ni, UBool fcc) :
+        Normalizer2WithImpl(ni), onlyContiguous(fcc) {}
+
+private:
+    virtual void
+    normalize(const UChar *src, const UChar *limit,
+              ReorderingBuffer &buffer, UErrorCode &errorCode) const {
+        impl.compose(src, limit, onlyContiguous, TRUE, buffer, errorCode);
+    }
+    using Normalizer2WithImpl::normalize;  // Avoid warning about hiding base class function.
+    virtual void
+    normalizeAndAppend(const UChar *src, const UChar *limit, UBool doNormalize,
+                       ReorderingBuffer &buffer, UErrorCode &errorCode) const {
+        impl.composeAndAppend(src, limit, doNormalize, onlyContiguous, buffer, errorCode);
+    }
+
+    virtual UBool
+    isNormalized(const UnicodeString &s, UErrorCode &errorCode) const {
+        if(U_FAILURE(errorCode)) {
+            return FALSE;
+        }
+        const UChar *sArray=s.getBuffer();
+        if(sArray==NULL) {
+            errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+            return FALSE;
+        }
+        UnicodeString temp;
+        ReorderingBuffer buffer(impl, temp);
+        if(!buffer.init(5, errorCode)) {  // small destCapacity for substring normalization
+            return FALSE;
+        }
+        return impl.compose(sArray, sArray+s.length(), onlyContiguous, FALSE, buffer, errorCode);
+    }
+    virtual UNormalizationCheckResult
+    quickCheck(const UnicodeString &s, UErrorCode &errorCode) const {
+        if(U_FAILURE(errorCode)) {
+            return UNORM_MAYBE;
+        }
+        const UChar *sArray=s.getBuffer();
+        if(sArray==NULL) {
+            errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+            return UNORM_MAYBE;
+        }
+        UNormalizationCheckResult qcResult=UNORM_YES;
+        impl.composeQuickCheck(sArray, sArray+s.length(), onlyContiguous, &qcResult);
+        return qcResult;
+    }
+    virtual const UChar *
+    spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &) const {
+        return impl.composeQuickCheck(src, limit, onlyContiguous, NULL);
+    }
+    using Normalizer2WithImpl::spanQuickCheckYes;  // Avoid warning about hiding base class function.
+    virtual UNormalizationCheckResult getQuickCheck(UChar32 c) const {
+        return impl.getCompQuickCheck(impl.getNorm16(c));
+    }
+    virtual UBool hasBoundaryBefore(UChar32 c) const {
+        return impl.hasCompBoundaryBefore(c);
+    }
+    virtual UBool hasBoundaryAfter(UChar32 c) const {
+        return impl.hasCompBoundaryAfter(c, onlyContiguous, FALSE);
+    }
+    virtual UBool isInert(UChar32 c) const {
+        return impl.hasCompBoundaryAfter(c, onlyContiguous, TRUE);
+    }
+
+    const UBool onlyContiguous;
+};
+
+class FCDNormalizer2 : public Normalizer2WithImpl {
+public:
+    FCDNormalizer2(const Normalizer2Impl &ni) : Normalizer2WithImpl(ni) {}
+
+private:
+    virtual void
+    normalize(const UChar *src, const UChar *limit,
+              ReorderingBuffer &buffer, UErrorCode &errorCode) const {
+        impl.makeFCD(src, limit, &buffer, errorCode);
+    }
+    using Normalizer2WithImpl::normalize;  // Avoid warning about hiding base class function.
+    virtual void
+    normalizeAndAppend(const UChar *src, const UChar *limit, UBool doNormalize,
+                       ReorderingBuffer &buffer, UErrorCode &errorCode) const {
+        impl.makeFCDAndAppend(src, limit, doNormalize, buffer, errorCode);
+    }
+    virtual const UChar *
+    spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const {
+        return impl.makeFCD(src, limit, NULL, errorCode);
+    }
+    using Normalizer2WithImpl::spanQuickCheckYes;  // Avoid warning about hiding base class function.
+    virtual UBool hasBoundaryBefore(UChar32 c) const { return impl.hasFCDBoundaryBefore(c); }
+    virtual UBool hasBoundaryAfter(UChar32 c) const { return impl.hasFCDBoundaryAfter(c); }
+    virtual UBool isInert(UChar32 c) const { return impl.isFCDInert(c); }
+};
+
+// instance cache ---------------------------------------------------------- ***
+
+struct Norm2AllModes : public UMemory {
+    static Norm2AllModes *createInstance(const char *packageName,
+                                         const char *name,
+                                         UErrorCode &errorCode);
+    Norm2AllModes() : comp(impl, FALSE), decomp(impl), fcd(impl), fcc(impl, TRUE) {}
+
+    Normalizer2Impl impl;
+    ComposeNormalizer2 comp;
+    DecomposeNormalizer2 decomp;
+    FCDNormalizer2 fcd;
+    ComposeNormalizer2 fcc;
+};
+
+Norm2AllModes *
+Norm2AllModes::createInstance(const char *packageName,
+                              const char *name,
+                              UErrorCode &errorCode) {
+    if(U_FAILURE(errorCode)) {
+        return NULL;
+    }
+    LocalPointer<Norm2AllModes> allModes(new Norm2AllModes);
+    if(allModes.isNull()) {
+        errorCode=U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    allModes->impl.load(packageName, name, errorCode);
+    return U_SUCCESS(errorCode) ? allModes.orphan() : NULL;
+}
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV uprv_normalizer2_cleanup();
+U_CDECL_END
+
+class Norm2AllModesSingleton : public TriStateSingletonWrapper<Norm2AllModes> {
+public:
+    Norm2AllModesSingleton(TriStateSingleton &s, const char *n) :
+        TriStateSingletonWrapper<Norm2AllModes>(s), name(n) {}
+    Norm2AllModes *getInstance(UErrorCode &errorCode) {
+        return TriStateSingletonWrapper<Norm2AllModes>::getInstance(createInstance, name, errorCode);
+    }
+private:
+    static void *createInstance(const void *context, UErrorCode &errorCode) {
+        ucln_common_registerCleanup(UCLN_COMMON_NORMALIZER2, uprv_normalizer2_cleanup);
+        return Norm2AllModes::createInstance(NULL, (const char *)context, errorCode);
+    }
+
+    const char *name;
+};
+
+STATIC_TRI_STATE_SINGLETON(nfcSingleton);
+STATIC_TRI_STATE_SINGLETON(nfkcSingleton);
+STATIC_TRI_STATE_SINGLETON(nfkc_cfSingleton);
+
+class Norm2Singleton : public SimpleSingletonWrapper<Normalizer2> {
+public:
+    Norm2Singleton(SimpleSingleton &s) : SimpleSingletonWrapper<Normalizer2>(s) {}
+    Normalizer2 *getInstance(UErrorCode &errorCode) {
+        return SimpleSingletonWrapper<Normalizer2>::getInstance(createInstance, NULL, errorCode);
+    }
+private:
+    static void *createInstance(const void *, UErrorCode &errorCode) {
+        Normalizer2 *noop=new NoopNormalizer2;
+        if(noop==NULL) {
+            errorCode=U_MEMORY_ALLOCATION_ERROR;
+        }
+        ucln_common_registerCleanup(UCLN_COMMON_NORMALIZER2, uprv_normalizer2_cleanup);
+        return noop;
+    }
+};
+
+STATIC_SIMPLE_SINGLETON(noopSingleton);
+
+static UHashtable *cache=NULL;
+
+U_CDECL_BEGIN
+
+static void U_CALLCONV deleteNorm2AllModes(void *allModes) {
+    delete (Norm2AllModes *)allModes;
+}
+
+static UBool U_CALLCONV uprv_normalizer2_cleanup() {
+    Norm2AllModesSingleton(nfcSingleton, NULL).deleteInstance();
+    Norm2AllModesSingleton(nfkcSingleton, NULL).deleteInstance();
+    Norm2AllModesSingleton(nfkc_cfSingleton, NULL).deleteInstance();
+    Norm2Singleton(noopSingleton).deleteInstance();
+    uhash_close(cache);
+    cache=NULL;
+    return TRUE;
+}
+
+U_CDECL_END
+
+const Normalizer2 *Normalizer2Factory::getNFCInstance(UErrorCode &errorCode) {
+    Norm2AllModes *allModes=Norm2AllModesSingleton(nfcSingleton, "nfc").getInstance(errorCode);
+    return allModes!=NULL ? &allModes->comp : NULL;
+}
+
+const Normalizer2 *Normalizer2Factory::getNFDInstance(UErrorCode &errorCode) {
+    Norm2AllModes *allModes=Norm2AllModesSingleton(nfcSingleton, "nfc").getInstance(errorCode);
+    return allModes!=NULL ? &allModes->decomp : NULL;
+}
+
+const Normalizer2 *Normalizer2Factory::getFCDInstance(UErrorCode &errorCode) {
+    Norm2AllModes *allModes=Norm2AllModesSingleton(nfcSingleton, "nfc").getInstance(errorCode);
+    if(allModes!=NULL) {
+        allModes->impl.getFCDTrie(errorCode);
+        return &allModes->fcd;
+    } else {
+        return NULL;
+    }
+}
+
+const Normalizer2 *Normalizer2Factory::getFCCInstance(UErrorCode &errorCode) {
+    Norm2AllModes *allModes=Norm2AllModesSingleton(nfcSingleton, "nfc").getInstance(errorCode);
+    return allModes!=NULL ? &allModes->fcc : NULL;
+}
+
+const Normalizer2 *Normalizer2Factory::getNFKCInstance(UErrorCode &errorCode) {
+    Norm2AllModes *allModes=
+        Norm2AllModesSingleton(nfkcSingleton, "nfkc").getInstance(errorCode);
+    return allModes!=NULL ? &allModes->comp : NULL;
+}
+
+const Normalizer2 *Normalizer2Factory::getNFKDInstance(UErrorCode &errorCode) {
+    Norm2AllModes *allModes=
+        Norm2AllModesSingleton(nfkcSingleton, "nfkc").getInstance(errorCode);
+    return allModes!=NULL ? &allModes->decomp : NULL;
+}
+
+const Normalizer2 *Normalizer2Factory::getNFKC_CFInstance(UErrorCode &errorCode) {
+    Norm2AllModes *allModes=
+        Norm2AllModesSingleton(nfkc_cfSingleton, "nfkc_cf").getInstance(errorCode);
+    return allModes!=NULL ? &allModes->comp : NULL;
+}
+
+const Normalizer2 *Normalizer2Factory::getNoopInstance(UErrorCode &errorCode) {
+    return Norm2Singleton(noopSingleton).getInstance(errorCode);
+}
+
+const Normalizer2 *
+Normalizer2Factory::getInstance(UNormalizationMode mode, UErrorCode &errorCode) {
+    if(U_FAILURE(errorCode)) {
+        return NULL;
+    }
+    switch(mode) {
+    case UNORM_NFD:
+        return getNFDInstance(errorCode);
+    case UNORM_NFKD:
+        return getNFKDInstance(errorCode);
+    case UNORM_NFC:
+        return getNFCInstance(errorCode);
+    case UNORM_NFKC:
+        return getNFKCInstance(errorCode);
+    case UNORM_FCD:
+        return getFCDInstance(errorCode);
+    default:  // UNORM_NONE
+        return getNoopInstance(errorCode);
+    }
+}
+
+const Normalizer2Impl *
+Normalizer2Factory::getNFCImpl(UErrorCode &errorCode) {
+    Norm2AllModes *allModes=
+        Norm2AllModesSingleton(nfcSingleton, "nfc").getInstance(errorCode);
+    return allModes!=NULL ? &allModes->impl : NULL;
+}
+
+const Normalizer2Impl *
+Normalizer2Factory::getNFKCImpl(UErrorCode &errorCode) {
+    Norm2AllModes *allModes=
+        Norm2AllModesSingleton(nfkcSingleton, "nfkc").getInstance(errorCode);
+    return allModes!=NULL ? &allModes->impl : NULL;
+}
+
+const Normalizer2Impl *
+Normalizer2Factory::getNFKC_CFImpl(UErrorCode &errorCode) {
+    Norm2AllModes *allModes=
+        Norm2AllModesSingleton(nfkc_cfSingleton, "nfkc_cf").getInstance(errorCode);
+    return allModes!=NULL ? &allModes->impl : NULL;
+}
+
+const Normalizer2Impl *
+Normalizer2Factory::getImpl(const Normalizer2 *norm2) {
+    return &((Normalizer2WithImpl *)norm2)->impl;
+}
+
+const UTrie2 *
+Normalizer2Factory::getFCDTrie(UErrorCode &errorCode) {
+    Norm2AllModes *allModes=
+        Norm2AllModesSingleton(nfcSingleton, "nfc").getInstance(errorCode);
+    if(allModes!=NULL) {
+        return allModes->impl.getFCDTrie(errorCode);
+    } else {
+        return NULL;
+    }
+}
+
+const Normalizer2 *
+Normalizer2::getInstance(const char *packageName,
+                         const char *name,
+                         UNormalization2Mode mode,
+                         UErrorCode &errorCode) {
+    if(U_FAILURE(errorCode)) {
+        return NULL;
+    }
+    if(name==NULL || *name==0) {
+        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+    }
+    Norm2AllModes *allModes=NULL;
+    if(packageName==NULL) {
+        if(0==uprv_strcmp(name, "nfc")) {
+            allModes=Norm2AllModesSingleton(nfcSingleton, "nfc").getInstance(errorCode);
+        } else if(0==uprv_strcmp(name, "nfkc")) {
+            allModes=Norm2AllModesSingleton(nfkcSingleton, "nfkc").getInstance(errorCode);
+        } else if(0==uprv_strcmp(name, "nfkc_cf")) {
+            allModes=Norm2AllModesSingleton(nfkc_cfSingleton, "nfkc_cf").getInstance(errorCode);
+        }
+    }
+    if(allModes==NULL && U_SUCCESS(errorCode)) {
+        {
+            Mutex lock;
+            if(cache!=NULL) {
+                allModes=(Norm2AllModes *)uhash_get(cache, name);
+            }
+        }
+        if(allModes==NULL) {
+            LocalPointer<Norm2AllModes> localAllModes(
+                Norm2AllModes::createInstance(packageName, name, errorCode));
+            if(U_SUCCESS(errorCode)) {
+                Mutex lock;
+                if(cache==NULL) {
+                    cache=uhash_open(uhash_hashChars, uhash_compareChars, NULL, &errorCode);
+                    if(U_FAILURE(errorCode)) {
+                        return NULL;
+                    }
+                    uhash_setKeyDeleter(cache, uprv_free);
+                    uhash_setValueDeleter(cache, deleteNorm2AllModes);
+                }
+                void *temp=uhash_get(cache, name);
+                if(temp==NULL) {
+                    int32_t keyLength=uprv_strlen(name)+1;
+                    char *nameCopy=(char *)uprv_malloc(keyLength);
+                    if(nameCopy==NULL) {
+                        errorCode=U_MEMORY_ALLOCATION_ERROR;
+                        return NULL;
+                    }
+                    uprv_memcpy(nameCopy, name, keyLength);
+                    uhash_put(cache, nameCopy, allModes=localAllModes.orphan(), &errorCode);
+                } else {
+                    // race condition
+                    allModes=(Norm2AllModes *)temp;
+                }
+            }
+        }
+    }
+    if(allModes!=NULL && U_SUCCESS(errorCode)) {
+        switch(mode) {
+        case UNORM2_COMPOSE:
+            return &allModes->comp;
+        case UNORM2_DECOMPOSE:
+            return &allModes->decomp;
+        case UNORM2_FCD:
+            allModes->impl.getFCDTrie(errorCode);
+            return &allModes->fcd;
+        case UNORM2_COMPOSE_CONTIGUOUS:
+            return &allModes->fcc;
+        default:
+            break;  // do nothing
+        }
+    }
+    return NULL;
+}
+
+UOBJECT_DEFINE_NO_RTTI_IMPLEMENTATION(Normalizer2)
+
+U_NAMESPACE_END
+
+// C API ------------------------------------------------------------------- ***
+
+U_NAMESPACE_USE
+
+U_DRAFT const UNormalizer2 * U_EXPORT2
+unorm2_getInstance(const char *packageName,
+                   const char *name,
+                   UNormalization2Mode mode,
+                   UErrorCode *pErrorCode) {
+    return (const UNormalizer2 *)Normalizer2::getInstance(packageName, name, mode, *pErrorCode);
+}
+
+U_DRAFT void U_EXPORT2
+unorm2_close(UNormalizer2 *norm2) {
+    delete (Normalizer2 *)norm2;
+}
+
+U_DRAFT int32_t U_EXPORT2
+unorm2_normalize(const UNormalizer2 *norm2,
+                 const UChar *src, int32_t length,
+                 UChar *dest, int32_t capacity,
+                 UErrorCode *pErrorCode) {
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if( (src==NULL ? length!=0 : length<-1) ||
+        (dest==NULL ? capacity!=0 : capacity<0) ||
+        (src==dest && src!=NULL)
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    UnicodeString destString(dest, 0, capacity);
+    // length==0: Nothing to do, and n2wi->normalize(NULL, NULL, buffer, ...) would crash.
+    if(length!=0) {
+        const Normalizer2 *n2=(const Normalizer2 *)norm2;
+        const Normalizer2WithImpl *n2wi=dynamic_cast<const Normalizer2WithImpl *>(n2);
+        if(n2wi!=NULL) {
+            // Avoid duplicate argument checking and support NUL-terminated src.
+            ReorderingBuffer buffer(n2wi->impl, destString);
+            if(buffer.init(length, *pErrorCode)) {
+                n2wi->normalize(src, length>=0 ? src+length : NULL, buffer, *pErrorCode);
+            }
+        } else {
+            UnicodeString srcString(length<0, src, length);
+            n2->normalize(srcString, destString, *pErrorCode);
+        }
+    }
+    return destString.extract(dest, capacity, *pErrorCode);
+}
+
+static int32_t
+normalizeSecondAndAppend(const UNormalizer2 *norm2,
+                         UChar *first, int32_t firstLength, int32_t firstCapacity,
+                         const UChar *second, int32_t secondLength,
+                         UBool doNormalize,
+                         UErrorCode *pErrorCode) {
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if( (second==NULL ? secondLength!=0 : secondLength<-1) ||
+        (first==NULL ? (firstCapacity!=0 || firstLength!=0) :
+                       (firstCapacity<0 || firstLength<-1)) ||
+        (first==second && first!=NULL)
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    UnicodeString firstString(first, firstLength, firstCapacity);
+    // secondLength==0: Nothing to do, and n2wi->normalizeAndAppend(NULL, NULL, buffer, ...) would crash.
+    if(secondLength!=0) {
+        const Normalizer2 *n2=(const Normalizer2 *)norm2;
+        const Normalizer2WithImpl *n2wi=dynamic_cast<const Normalizer2WithImpl *>(n2);
+        if(n2wi!=NULL) {
+            // Avoid duplicate argument checking and support NUL-terminated src.
+            ReorderingBuffer buffer(n2wi->impl, firstString);
+            if(buffer.init(firstLength+secondLength+1, *pErrorCode)) {  // destCapacity>=-1
+                n2wi->normalizeAndAppend(second, secondLength>=0 ? second+secondLength : NULL,
+                                        doNormalize, buffer, *pErrorCode);
+            }
+        } else {
+            UnicodeString secondString(secondLength<0, second, secondLength);
+            if(doNormalize) {
+                n2->normalizeSecondAndAppend(firstString, secondString, *pErrorCode);
+            } else {
+                n2->append(firstString, secondString, *pErrorCode);
+            }
+        }
+    }
+    return firstString.extract(first, firstCapacity, *pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+unorm2_normalizeSecondAndAppend(const UNormalizer2 *norm2,
+                                UChar *first, int32_t firstLength, int32_t firstCapacity,
+                                const UChar *second, int32_t secondLength,
+                                UErrorCode *pErrorCode) {
+    return normalizeSecondAndAppend(norm2,
+                                    first, firstLength, firstCapacity,
+                                    second, secondLength,
+                                    TRUE, pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+unorm2_append(const UNormalizer2 *norm2,
+              UChar *first, int32_t firstLength, int32_t firstCapacity,
+              const UChar *second, int32_t secondLength,
+              UErrorCode *pErrorCode) {
+    return normalizeSecondAndAppend(norm2,
+                                    first, firstLength, firstCapacity,
+                                    second, secondLength,
+                                    FALSE, pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+unorm2_getDecomposition(const UNormalizer2 *norm2,
+                        UChar32 c, UChar *decomposition, int32_t capacity,
+                        UErrorCode *pErrorCode) {
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(decomposition==NULL ? capacity!=0 : capacity<0) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    UnicodeString destString(decomposition, 0, capacity);
+    if(reinterpret_cast<const Normalizer2 *>(norm2)->getDecomposition(c, destString)) {
+        return destString.extract(decomposition, capacity, *pErrorCode);
+    } else {
+        return -1;
+    }
+}
+
+U_DRAFT UBool U_EXPORT2
+unorm2_isNormalized(const UNormalizer2 *norm2,
+                    const UChar *s, int32_t length,
+                    UErrorCode *pErrorCode) {
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if((s==NULL && length!=0) || length<-1) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    UnicodeString sString(length<0, s, length);
+    return ((const Normalizer2 *)norm2)->isNormalized(sString, *pErrorCode);
+}
+
+U_DRAFT UNormalizationCheckResult U_EXPORT2
+unorm2_quickCheck(const UNormalizer2 *norm2,
+                  const UChar *s, int32_t length,
+                  UErrorCode *pErrorCode) {
+    if(U_FAILURE(*pErrorCode)) {
+        return UNORM_NO;
+    }
+    if((s==NULL && length!=0) || length<-1) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return UNORM_NO;
+    }
+    UnicodeString sString(length<0, s, length);
+    return ((const Normalizer2 *)norm2)->quickCheck(sString, *pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+unorm2_spanQuickCheckYes(const UNormalizer2 *norm2,
+                         const UChar *s, int32_t length,
+                         UErrorCode *pErrorCode) {
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if((s==NULL && length!=0) || length<-1) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    UnicodeString sString(length<0, s, length);
+    return ((const Normalizer2 *)norm2)->spanQuickCheckYes(sString, *pErrorCode);
+}
+
+U_DRAFT UBool U_EXPORT2
+unorm2_hasBoundaryBefore(const UNormalizer2 *norm2, UChar32 c) {
+    return ((const Normalizer2 *)norm2)->hasBoundaryBefore(c);
+}
+
+U_DRAFT UBool U_EXPORT2
+unorm2_hasBoundaryAfter(const UNormalizer2 *norm2, UChar32 c) {
+    return ((const Normalizer2 *)norm2)->hasBoundaryAfter(c);
+}
+
+U_DRAFT UBool U_EXPORT2
+unorm2_isInert(const UNormalizer2 *norm2, UChar32 c) {
+    return ((const Normalizer2 *)norm2)->isInert(c);
+}
+
+// Some properties APIs ---------------------------------------------------- ***
+
+U_CFUNC UNormalizationCheckResult U_EXPORT2
+unorm_getQuickCheck(UChar32 c, UNormalizationMode mode) {
+    if(mode<=UNORM_NONE || UNORM_FCD<=mode) {
+        return UNORM_YES;
+    }
+    UErrorCode errorCode=U_ZERO_ERROR;
+    const Normalizer2 *norm2=Normalizer2Factory::getInstance(mode, errorCode);
+    if(U_SUCCESS(errorCode)) {
+        return ((const Normalizer2WithImpl *)norm2)->getQuickCheck(c);
+    } else {
+        return UNORM_MAYBE;
+    }
+}
+
+U_CAPI const uint16_t * U_EXPORT2
+unorm_getFCDTrieIndex(UChar32 &fcdHighStart, UErrorCode *pErrorCode) {
+    const UTrie2 *trie=Normalizer2Factory::getFCDTrie(*pErrorCode);
+    if(U_SUCCESS(*pErrorCode)) {
+        fcdHighStart=trie->highStart;
+        return trie->index;
+    } else {
+        return NULL;
+    }
+}
+
+#endif  // !UCONFIG_NO_NORMALIZATION
diff --git a/source/common/normalizer2impl.cpp b/source/common/normalizer2impl.cpp
new file mode 100644
index 0000000..52459be
--- /dev/null
+++ b/source/common/normalizer2impl.cpp
@@ -0,0 +1,2011 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2009-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  normalizer2impl.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2009nov22
+*   created by: Markus W. Scherer
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/normalizer2.h"
+#include "unicode/udata.h"
+#include "unicode/ustring.h"
+#include "cmemory.h"
+#include "mutex.h"
+#include "normalizer2impl.h"
+#include "uassert.h"
+#include "uhash.h"
+#include "uset_imp.h"
+#include "utrie2.h"
+#include "uvector.h"
+
+U_NAMESPACE_BEGIN
+
+// ReorderingBuffer -------------------------------------------------------- ***
+
+UBool ReorderingBuffer::init(int32_t destCapacity, UErrorCode &errorCode) {
+    int32_t length=str.length();
+    start=str.getBuffer(destCapacity);
+    if(start==NULL) {
+        // getBuffer() already did str.setToBogus()
+        errorCode=U_MEMORY_ALLOCATION_ERROR;
+        return FALSE;
+    }
+    limit=start+length;
+    remainingCapacity=str.getCapacity()-length;
+    reorderStart=start;
+    if(start==limit) {
+        lastCC=0;
+    } else {
+        setIterator();
+        lastCC=previousCC();
+        // Set reorderStart after the last code point with cc<=1 if there is one.
+        if(lastCC>1) {
+            while(previousCC()>1) {}
+        }
+        reorderStart=codePointLimit;
+    }
+    return TRUE;
+}
+
+UBool ReorderingBuffer::equals(const UChar *otherStart, const UChar *otherLimit) const {
+    int32_t length=(int32_t)(limit-start);
+    return
+        length==(int32_t)(otherLimit-otherStart) &&
+        0==u_memcmp(start, otherStart, length);
+}
+
+UBool ReorderingBuffer::appendSupplementary(UChar32 c, uint8_t cc, UErrorCode &errorCode) {
+    if(remainingCapacity<2 && !resize(2, errorCode)) {
+        return FALSE;
+    }
+    if(lastCC<=cc || cc==0) {
+        limit[0]=U16_LEAD(c);
+        limit[1]=U16_TRAIL(c);
+        limit+=2;
+        lastCC=cc;
+        if(cc<=1) {
+            reorderStart=limit;
+        }
+    } else {
+        insert(c, cc);
+    }
+    remainingCapacity-=2;
+    return TRUE;
+}
+
+UBool ReorderingBuffer::append(const UChar *s, int32_t length,
+                               uint8_t leadCC, uint8_t trailCC,
+                               UErrorCode &errorCode) {
+    if(length==0) {
+        return TRUE;
+    }
+    if(remainingCapacity<length && !resize(length, errorCode)) {
+        return FALSE;
+    }
+    remainingCapacity-=length;
+    if(lastCC<=leadCC || leadCC==0) {
+        if(trailCC<=1) {
+            reorderStart=limit+length;
+        } else if(leadCC<=1) {
+            reorderStart=limit+1;  // Ok if not a code point boundary.
+        }
+        const UChar *sLimit=s+length;
+        do { *limit++=*s++; } while(s!=sLimit);
+        lastCC=trailCC;
+    } else {
+        int32_t i=0;
+        UChar32 c;
+        U16_NEXT(s, i, length, c);
+        insert(c, leadCC);  // insert first code point
+        while(i<length) {
+            U16_NEXT(s, i, length, c);
+            if(i<length) {
+                // s must be in NFD, otherwise we need to use getCC().
+                leadCC=Normalizer2Impl::getCCFromYesOrMaybe(impl.getNorm16(c));
+            } else {
+                leadCC=trailCC;
+            }
+            append(c, leadCC, errorCode);
+        }
+    }
+    return TRUE;
+}
+
+UBool ReorderingBuffer::appendZeroCC(UChar32 c, UErrorCode &errorCode) {
+    int32_t cpLength=U16_LENGTH(c);
+    if(remainingCapacity<cpLength && !resize(cpLength, errorCode)) {
+        return FALSE;
+    }
+    remainingCapacity-=cpLength;
+    if(cpLength==1) {
+        *limit++=(UChar)c;
+    } else {
+        limit[0]=U16_LEAD(c);
+        limit[1]=U16_TRAIL(c);
+        limit+=2;
+    }
+    lastCC=0;
+    reorderStart=limit;
+    return TRUE;
+}
+
+UBool ReorderingBuffer::appendZeroCC(const UChar *s, const UChar *sLimit, UErrorCode &errorCode) {
+    if(s==sLimit) {
+        return TRUE;
+    }
+    int32_t length=(int32_t)(sLimit-s);
+    if(remainingCapacity<length && !resize(length, errorCode)) {
+        return FALSE;
+    }
+    u_memcpy(limit, s, length);
+    limit+=length;
+    remainingCapacity-=length;
+    lastCC=0;
+    reorderStart=limit;
+    return TRUE;
+}
+
+void ReorderingBuffer::remove() {
+    reorderStart=limit=start;
+    remainingCapacity=str.getCapacity();
+    lastCC=0;
+}
+
+void ReorderingBuffer::removeSuffix(int32_t suffixLength) {
+    if(suffixLength<(limit-start)) {
+        limit-=suffixLength;
+        remainingCapacity+=suffixLength;
+    } else {
+        limit=start;
+        remainingCapacity=str.getCapacity();
+    }
+    lastCC=0;
+    reorderStart=limit;
+}
+
+UBool ReorderingBuffer::resize(int32_t appendLength, UErrorCode &errorCode) {
+    int32_t reorderStartIndex=(int32_t)(reorderStart-start);
+    int32_t length=(int32_t)(limit-start);
+    str.releaseBuffer(length);
+    int32_t newCapacity=length+appendLength;
+    int32_t doubleCapacity=2*str.getCapacity();
+    if(newCapacity<doubleCapacity) {
+        newCapacity=doubleCapacity;
+    }
+    if(newCapacity<256) {
+        newCapacity=256;
+    }
+    start=str.getBuffer(newCapacity);
+    if(start==NULL) {
+        // getBuffer() already did str.setToBogus()
+        errorCode=U_MEMORY_ALLOCATION_ERROR;
+        return FALSE;
+    }
+    reorderStart=start+reorderStartIndex;
+    limit=start+length;
+    remainingCapacity=str.getCapacity()-length;
+    return TRUE;
+}
+
+void ReorderingBuffer::skipPrevious() {
+    codePointLimit=codePointStart;
+    UChar c=*--codePointStart;
+    if(U16_IS_TRAIL(c) && start<codePointStart && U16_IS_LEAD(*(codePointStart-1))) {
+        --codePointStart;
+    }
+}
+
+uint8_t ReorderingBuffer::previousCC() {
+    codePointLimit=codePointStart;
+    if(reorderStart>=codePointStart) {
+        return 0;
+    }
+    UChar32 c=*--codePointStart;
+    if(c<Normalizer2Impl::MIN_CCC_LCCC_CP) {
+        return 0;
+    }
+
+    UChar c2;
+    if(U16_IS_TRAIL(c) && start<codePointStart && U16_IS_LEAD(c2=*(codePointStart-1))) {
+        --codePointStart;
+        c=U16_GET_SUPPLEMENTARY(c2, c);
+    }
+    return Normalizer2Impl::getCCFromYesOrMaybe(impl.getNorm16(c));
+}
+
+// Inserts c somewhere before the last character.
+// Requires 0<cc<lastCC which implies reorderStart<limit.
+void ReorderingBuffer::insert(UChar32 c, uint8_t cc) {
+    for(setIterator(), skipPrevious(); previousCC()>cc;) {}
+    // insert c at codePointLimit, after the character with prevCC<=cc
+    UChar *q=limit;
+    UChar *r=limit+=U16_LENGTH(c);
+    do {
+        *--r=*--q;
+    } while(codePointLimit!=q);
+    writeCodePoint(q, c);
+    if(cc<=1) {
+        reorderStart=r;
+    }
+}
+
+// Normalizer2Impl --------------------------------------------------------- ***
+
+struct CanonIterData : public UMemory {
+    CanonIterData(UErrorCode &errorCode);
+    ~CanonIterData();
+    void addToStartSet(UChar32 origin, UChar32 decompLead, UErrorCode &errorCode);
+    UTrie2 *trie;
+    UVector canonStartSets;  // contains UnicodeSet *
+};
+
+Normalizer2Impl::~Normalizer2Impl() {
+    udata_close(memory);
+    utrie2_close(normTrie);
+    UTrie2Singleton(fcdTrieSingleton).deleteInstance();
+    delete (CanonIterData *)canonIterDataSingleton.fInstance;
+}
+
+UBool U_CALLCONV
+Normalizer2Impl::isAcceptable(void *context,
+                              const char * /* type */, const char * /*name*/,
+                              const UDataInfo *pInfo) {
+    if(
+        pInfo->size>=20 &&
+        pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
+        pInfo->charsetFamily==U_CHARSET_FAMILY &&
+        pInfo->dataFormat[0]==0x4e &&    /* dataFormat="Nrm2" */
+        pInfo->dataFormat[1]==0x72 &&
+        pInfo->dataFormat[2]==0x6d &&
+        pInfo->dataFormat[3]==0x32 &&
+        pInfo->formatVersion[0]==1
+    ) {
+        Normalizer2Impl *me=(Normalizer2Impl *)context;
+        uprv_memcpy(me->dataVersion, pInfo->dataVersion, 4);
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+}
+
+void
+Normalizer2Impl::load(const char *packageName, const char *name, UErrorCode &errorCode) {
+    if(U_FAILURE(errorCode)) {
+        return;
+    }
+    memory=udata_openChoice(packageName, "nrm", name, isAcceptable, this, &errorCode);
+    if(U_FAILURE(errorCode)) {
+        return;
+    }
+    const uint8_t *inBytes=(const uint8_t *)udata_getMemory(memory);
+    const int32_t *inIndexes=(const int32_t *)inBytes;
+    int32_t indexesLength=inIndexes[IX_NORM_TRIE_OFFSET]/4;
+    if(indexesLength<=IX_MIN_MAYBE_YES) {
+        errorCode=U_INVALID_FORMAT_ERROR;  // Not enough indexes.
+        return;
+    }
+
+    minDecompNoCP=inIndexes[IX_MIN_DECOMP_NO_CP];
+    minCompNoMaybeCP=inIndexes[IX_MIN_COMP_NO_MAYBE_CP];
+
+    minYesNo=inIndexes[IX_MIN_YES_NO];
+    minNoNo=inIndexes[IX_MIN_NO_NO];
+    limitNoNo=inIndexes[IX_LIMIT_NO_NO];
+    minMaybeYes=inIndexes[IX_MIN_MAYBE_YES];
+
+    int32_t offset=inIndexes[IX_NORM_TRIE_OFFSET];
+    int32_t nextOffset=inIndexes[IX_EXTRA_DATA_OFFSET];
+    normTrie=utrie2_openFromSerialized(UTRIE2_16_VALUE_BITS,
+                                       inBytes+offset, nextOffset-offset, NULL,
+                                       &errorCode);
+    if(U_FAILURE(errorCode)) {
+        return;
+    }
+
+    offset=nextOffset;
+    maybeYesCompositions=(const uint16_t *)(inBytes+offset);
+    extraData=maybeYesCompositions+(MIN_NORMAL_MAYBE_YES-minMaybeYes);
+}
+
+uint8_t Normalizer2Impl::getTrailCCFromCompYesAndZeroCC(const UChar *cpStart, const UChar *cpLimit) const {
+    UChar32 c;
+    if(cpStart==(cpLimit-1)) {
+        c=*cpStart;
+    } else {
+        c=U16_GET_SUPPLEMENTARY(cpStart[0], cpStart[1]);
+    }
+    uint16_t prevNorm16=getNorm16(c);
+    if(prevNorm16<=minYesNo) {
+        return 0;  // yesYes and Hangul LV/LVT have ccc=tccc=0
+    } else {
+        return (uint8_t)(*getMapping(prevNorm16)>>8);  // tccc from yesNo
+    }
+}
+
+U_CDECL_BEGIN
+
+static UBool U_CALLCONV
+enumPropertyStartsRange(const void *context, UChar32 start, UChar32 /*end*/, uint32_t /*value*/) {
+    /* add the start code point to the USet */
+    const USetAdder *sa=(const USetAdder *)context;
+    sa->add(sa->set, start);
+    return TRUE;
+}
+
+static uint32_t U_CALLCONV
+segmentStarterMapper(const void * /*context*/, uint32_t value) {
+    return value&CANON_NOT_SEGMENT_STARTER;
+}
+
+U_CDECL_END
+
+void
+Normalizer2Impl::addPropertyStarts(const USetAdder *sa, UErrorCode & /*errorCode*/) const {
+    /* add the start code point of each same-value range of each trie */
+    utrie2_enum(normTrie, NULL, enumPropertyStartsRange, sa);
+
+    /* add Hangul LV syllables and LV+1 because of skippables */
+    for(UChar c=Hangul::HANGUL_BASE; c<Hangul::HANGUL_LIMIT; c+=Hangul::JAMO_T_COUNT) {
+        sa->add(sa->set, c);
+        sa->add(sa->set, c+1);
+    }
+    sa->add(sa->set, Hangul::HANGUL_LIMIT); /* add Hangul+1 to continue with other properties */
+}
+
+void
+Normalizer2Impl::addCanonIterPropertyStarts(const USetAdder *sa, UErrorCode &errorCode) const {
+    /* add the start code point of each same-value range of the canonical iterator data trie */
+    if(ensureCanonIterData(errorCode)) {
+        // currently only used for the SEGMENT_STARTER property
+        utrie2_enum(((CanonIterData *)canonIterDataSingleton.fInstance)->trie,
+                    segmentStarterMapper, enumPropertyStartsRange, sa);
+    }
+}
+
+const UChar *
+Normalizer2Impl::copyLowPrefixFromNulTerminated(const UChar *src,
+                                                UChar32 minNeedDataCP,
+                                                ReorderingBuffer *buffer,
+                                                UErrorCode &errorCode) const {
+    // Make some effort to support NUL-terminated strings reasonably.
+    // Take the part of the fast quick check loop that does not look up
+    // data and check the first part of the string.
+    // After this prefix, determine the string length to simplify the rest
+    // of the code.
+    const UChar *prevSrc=src;
+    UChar c;
+    while((c=*src++)<minNeedDataCP && c!=0) {}
+    // Back out the last character for full processing.
+    // Copy this prefix.
+    if(--src!=prevSrc) {
+        if(buffer!=NULL) {
+            buffer->appendZeroCC(prevSrc, src, errorCode);
+        }
+    }
+    return src;
+}
+
+// Dual functionality:
+// buffer!=NULL: normalize
+// buffer==NULL: isNormalized/spanQuickCheckYes
+const UChar *
+Normalizer2Impl::decompose(const UChar *src, const UChar *limit,
+                           ReorderingBuffer *buffer,
+                           UErrorCode &errorCode) const {
+    UChar32 minNoCP=minDecompNoCP;
+    if(limit==NULL) {
+        src=copyLowPrefixFromNulTerminated(src, minNoCP, buffer, errorCode);
+        if(U_FAILURE(errorCode)) {
+            return src;
+        }
+        limit=u_strchr(src, 0);
+    }
+
+    const UChar *prevSrc;
+    UChar32 c=0;
+    uint16_t norm16=0;
+
+    // only for quick check
+    const UChar *prevBoundary=src;
+    uint8_t prevCC=0;
+
+    for(;;) {
+        // count code units below the minimum or with irrelevant data for the quick check
+        for(prevSrc=src; src!=limit;) {
+            if( (c=*src)<minNoCP ||
+                isMostDecompYesAndZeroCC(norm16=UTRIE2_GET16_FROM_U16_SINGLE_LEAD(normTrie, c))
+            ) {
+                ++src;
+            } else if(!U16_IS_SURROGATE(c)) {
+                break;
+            } else {
+                UChar c2;
+                if(U16_IS_SURROGATE_LEAD(c)) {
+                    if((src+1)!=limit && U16_IS_TRAIL(c2=src[1])) {
+                        c=U16_GET_SUPPLEMENTARY(c, c2);
+                    }
+                } else /* trail surrogate */ {
+                    if(prevSrc<src && U16_IS_LEAD(c2=*(src-1))) {
+                        --src;
+                        c=U16_GET_SUPPLEMENTARY(c2, c);
+                    }
+                }
+                if(isMostDecompYesAndZeroCC(norm16=getNorm16(c))) {
+                    src+=U16_LENGTH(c);
+                } else {
+                    break;
+                }
+            }
+        }
+        // copy these code units all at once
+        if(src!=prevSrc) {
+            if(buffer!=NULL) {
+                if(!buffer->appendZeroCC(prevSrc, src, errorCode)) {
+                    break;
+                }
+            } else {
+                prevCC=0;
+                prevBoundary=src;
+            }
+        }
+        if(src==limit) {
+            break;
+        }
+
+        // Check one above-minimum, relevant code point.
+        src+=U16_LENGTH(c);
+        if(buffer!=NULL) {
+            if(!decompose(c, norm16, *buffer, errorCode)) {
+                break;
+            }
+        } else {
+            if(isDecompYes(norm16)) {
+                uint8_t cc=getCCFromYesOrMaybe(norm16);
+                if(prevCC<=cc || cc==0) {
+                    prevCC=cc;
+                    if(cc<=1) {
+                        prevBoundary=src;
+                    }
+                    continue;
+                }
+            }
+            return prevBoundary;  // "no" or cc out of order
+        }
+    }
+    return src;
+}
+
+// Decompose a short piece of text which is likely to contain characters that
+// fail the quick check loop and/or where the quick check loop's overhead
+// is unlikely to be amortized.
+// Called by the compose() and makeFCD() implementations.
+UBool Normalizer2Impl::decomposeShort(const UChar *src, const UChar *limit,
+                                      ReorderingBuffer &buffer,
+                                      UErrorCode &errorCode) const {
+    while(src<limit) {
+        UChar32 c;
+        uint16_t norm16;
+        UTRIE2_U16_NEXT16(normTrie, src, limit, c, norm16);
+        if(!decompose(c, norm16, buffer, errorCode)) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+UBool Normalizer2Impl::decompose(UChar32 c, uint16_t norm16,
+                                 ReorderingBuffer &buffer,
+                                 UErrorCode &errorCode) const {
+    // Only loops for 1:1 algorithmic mappings.
+    for(;;) {
+        // get the decomposition and the lead and trail cc's
+        if(isDecompYes(norm16)) {
+            // c does not decompose
+            return buffer.append(c, getCCFromYesOrMaybe(norm16), errorCode);
+        } else if(isHangul(norm16)) {
+            // Hangul syllable: decompose algorithmically
+            UChar jamos[3];
+            return buffer.appendZeroCC(jamos, jamos+Hangul::decompose(c, jamos), errorCode);
+        } else if(isDecompNoAlgorithmic(norm16)) {
+            c=mapAlgorithmic(c, norm16);
+            norm16=getNorm16(c);
+        } else {
+            // c decomposes, get everything from the variable-length extra data
+            const uint16_t *mapping=getMapping(norm16);
+            uint16_t firstUnit=*mapping++;
+            int32_t length=firstUnit&MAPPING_LENGTH_MASK;
+            uint8_t leadCC, trailCC;
+            trailCC=(uint8_t)(firstUnit>>8);
+            if(firstUnit&MAPPING_HAS_CCC_LCCC_WORD) {
+                leadCC=(uint8_t)(*mapping++>>8);
+            } else {
+                leadCC=0;
+            }
+            return buffer.append((const UChar *)mapping, length, leadCC, trailCC, errorCode);
+        }
+    }
+}
+
+const UChar *
+Normalizer2Impl::getDecomposition(UChar32 c, UChar buffer[4], int32_t &length) const {
+    const UChar *decomp=NULL;
+    uint16_t norm16;
+    for(;;) {
+        if(c<minDecompNoCP || isDecompYes(norm16=getNorm16(c))) {
+            // c does not decompose
+            return decomp;
+        } else if(isHangul(norm16)) {
+            // Hangul syllable: decompose algorithmically
+            length=Hangul::decompose(c, buffer);
+            return buffer;
+        } else if(isDecompNoAlgorithmic(norm16)) {
+            c=mapAlgorithmic(c, norm16);
+            decomp=buffer;
+            length=0;
+            U16_APPEND_UNSAFE(buffer, length, c);
+        } else {
+            // c decomposes, get everything from the variable-length extra data
+            const uint16_t *mapping=getMapping(norm16);
+            uint16_t firstUnit=*mapping++;
+            length=firstUnit&MAPPING_LENGTH_MASK;
+            if(firstUnit&MAPPING_HAS_CCC_LCCC_WORD) {
+                ++mapping;
+            }
+            return (const UChar *)mapping;
+        }
+    }
+}
+
+void Normalizer2Impl::decomposeAndAppend(const UChar *src, const UChar *limit,
+                                         UBool doDecompose,
+                                         ReorderingBuffer &buffer,
+                                         UErrorCode &errorCode) const {
+    if(doDecompose) {
+        decompose(src, limit, &buffer, errorCode);
+        return;
+    }
+    // Just merge the strings at the boundary.
+    ForwardUTrie2StringIterator iter(normTrie, src, limit);
+    uint8_t firstCC, prevCC, cc;
+    firstCC=prevCC=cc=getCC(iter.next16());
+    while(cc!=0) {
+        prevCC=cc;
+        cc=getCC(iter.next16());
+    };
+    buffer.append(src, (int32_t)(iter.codePointStart-src), firstCC, prevCC, errorCode) &&
+        buffer.appendZeroCC(iter.codePointStart, limit, errorCode);
+}
+
+// Note: hasDecompBoundary() could be implemented as aliases to
+// hasFCDBoundaryBefore() and hasFCDBoundaryAfter()
+// at the cost of building the FCD trie for a decomposition normalizer.
+UBool Normalizer2Impl::hasDecompBoundary(UChar32 c, UBool before) const {
+    for(;;) {
+        if(c<minDecompNoCP) {
+            return TRUE;
+        }
+        uint16_t norm16=getNorm16(c);
+        if(isHangul(norm16) || isDecompYesAndZeroCC(norm16)) {
+            return TRUE;
+        } else if(norm16>MIN_NORMAL_MAYBE_YES) {
+            return FALSE;  // ccc!=0
+        } else if(isDecompNoAlgorithmic(norm16)) {
+            c=mapAlgorithmic(c, norm16);
+        } else {
+            // c decomposes, get everything from the variable-length extra data
+            const uint16_t *mapping=getMapping(norm16);
+            uint16_t firstUnit=*mapping++;
+            if((firstUnit&MAPPING_LENGTH_MASK)==0) {
+                return FALSE;
+            }
+            if(!before) {
+                // decomp after-boundary: same as hasFCDBoundaryAfter(),
+                // fcd16<=1 || trailCC==0
+                if(firstUnit>0x1ff) {
+                    return FALSE;  // trailCC>1
+                }
+                if(firstUnit<=0xff) {
+                    return TRUE;  // trailCC==0
+                }
+                // if(trailCC==1) test leadCC==0, same as checking for before-boundary
+            }
+            // TRUE if leadCC==0 (hasFCDBoundaryBefore())
+            return (firstUnit&MAPPING_HAS_CCC_LCCC_WORD)==0 || (*mapping&0xff00)==0;
+        }
+    }
+}
+
+/*
+ * Finds the recomposition result for
+ * a forward-combining "lead" character,
+ * specified with a pointer to its compositions list,
+ * and a backward-combining "trail" character.
+ *
+ * If the lead and trail characters combine, then this function returns
+ * the following "compositeAndFwd" value:
+ * Bits 21..1  composite character
+ * Bit      0  set if the composite is a forward-combining starter
+ * otherwise it returns -1.
+ *
+ * The compositions list has (trail, compositeAndFwd) pair entries,
+ * encoded as either pairs or triples of 16-bit units.
+ * The last entry has the high bit of its first unit set.
+ *
+ * The list is sorted by ascending trail characters (there are no duplicates).
+ * A linear search is used.
+ *
+ * See normalizer2impl.h for a more detailed description
+ * of the compositions list format.
+ */
+int32_t Normalizer2Impl::combine(const uint16_t *list, UChar32 trail) {
+    uint16_t key1, firstUnit;
+    if(trail<COMP_1_TRAIL_LIMIT) {
+        // trail character is 0..33FF
+        // result entry may have 2 or 3 units
+        key1=(uint16_t)(trail<<1);
+        while(key1>(firstUnit=*list)) {
+            list+=2+(firstUnit&COMP_1_TRIPLE);
+        }
+        if(key1==(firstUnit&COMP_1_TRAIL_MASK)) {
+            if(firstUnit&COMP_1_TRIPLE) {
+                return ((int32_t)list[1]<<16)|list[2];
+            } else {
+                return list[1];
+            }
+        }
+    } else {
+        // trail character is 3400..10FFFF
+        // result entry has 3 units
+        key1=(uint16_t)(COMP_1_TRAIL_LIMIT+
+                        (((trail>>COMP_1_TRAIL_SHIFT))&
+                          ~COMP_1_TRIPLE));
+        uint16_t key2=(uint16_t)(trail<<COMP_2_TRAIL_SHIFT);
+        uint16_t secondUnit;
+        for(;;) {
+            if(key1>(firstUnit=*list)) {
+                list+=2+(firstUnit&COMP_1_TRIPLE);
+            } else if(key1==(firstUnit&COMP_1_TRAIL_MASK)) {
+                if(key2>(secondUnit=list[1])) {
+                    if(firstUnit&COMP_1_LAST_TUPLE) {
+                        break;
+                    } else {
+                        list+=3;
+                    }
+                } else if(key2==(secondUnit&COMP_2_TRAIL_MASK)) {
+                    return ((int32_t)(secondUnit&~COMP_2_TRAIL_MASK)<<16)|list[2];
+                } else {
+                    break;
+                }
+            } else {
+                break;
+            }
+        }
+    }
+    return -1;
+}
+
+/**
+  * @param list some character's compositions list
+  * @param set recursively receives the composites from these compositions
+  */
+void Normalizer2Impl::addComposites(const uint16_t *list, UnicodeSet &set) const {
+    uint16_t firstUnit;
+    int32_t compositeAndFwd;
+    do {
+        firstUnit=*list;
+        if((firstUnit&COMP_1_TRIPLE)==0) {
+            compositeAndFwd=list[1];
+            list+=2;
+        } else {
+            compositeAndFwd=(((int32_t)list[1]&~COMP_2_TRAIL_MASK)<<16)|list[2];
+            list+=3;
+        }
+        UChar32 composite=compositeAndFwd>>1;
+        if((compositeAndFwd&1)!=0) {
+            addComposites(getCompositionsListForComposite(getNorm16(composite)), set);
+        }
+        set.add(composite);
+    } while((firstUnit&COMP_1_LAST_TUPLE)==0);
+}
+
+/*
+ * Recomposes the buffer text starting at recomposeStartIndex
+ * (which is in NFD - decomposed and canonically ordered),
+ * and truncates the buffer contents.
+ *
+ * Note that recomposition never lengthens the text:
+ * Any character consists of either one or two code units;
+ * a composition may contain at most one more code unit than the original starter,
+ * while the combining mark that is removed has at least one code unit.
+ */
+void Normalizer2Impl::recompose(ReorderingBuffer &buffer, int32_t recomposeStartIndex,
+                                UBool onlyContiguous) const {
+    UChar *p=buffer.getStart()+recomposeStartIndex;
+    UChar *limit=buffer.getLimit();
+    if(p==limit) {
+        return;
+    }
+
+    UChar *starter, *pRemove, *q, *r;
+    const uint16_t *compositionsList;
+    UChar32 c, compositeAndFwd;
+    uint16_t norm16;
+    uint8_t cc, prevCC;
+    UBool starterIsSupplementary;
+
+    // Some of the following variables are not used until we have a forward-combining starter
+    // and are only initialized now to avoid compiler warnings.
+    compositionsList=NULL;  // used as indicator for whether we have a forward-combining starter
+    starter=NULL;
+    starterIsSupplementary=FALSE;
+    prevCC=0;
+
+    for(;;) {
+        UTRIE2_U16_NEXT16(normTrie, p, limit, c, norm16);
+        cc=getCCFromYesOrMaybe(norm16);
+        if( // this character combines backward and
+            isMaybe(norm16) &&
+            // we have seen a starter that combines forward and
+            compositionsList!=NULL &&
+            // the backward-combining character is not blocked
+            (prevCC<cc || prevCC==0)
+        ) {
+            if(isJamoVT(norm16)) {
+                // c is a Jamo V/T, see if we can compose it with the previous character.
+                if(c<Hangul::JAMO_T_BASE) {
+                    // c is a Jamo Vowel, compose with previous Jamo L and following Jamo T.
+                    UChar prev=(UChar)(*starter-Hangul::JAMO_L_BASE);
+                    if(prev<Hangul::JAMO_L_COUNT) {
+                        pRemove=p-1;
+                        UChar syllable=(UChar)
+                            (Hangul::HANGUL_BASE+
+                             (prev*Hangul::JAMO_V_COUNT+(c-Hangul::JAMO_V_BASE))*
+                             Hangul::JAMO_T_COUNT);
+                        UChar t;
+                        if(p!=limit && (t=(UChar)(*p-Hangul::JAMO_T_BASE))<Hangul::JAMO_T_COUNT) {
+                            ++p;
+                            syllable+=t;  // The next character was a Jamo T.
+                        }
+                        *starter=syllable;
+                        // remove the Jamo V/T
+                        q=pRemove;
+                        r=p;
+                        while(r<limit) {
+                            *q++=*r++;
+                        }
+                        limit=q;
+                        p=pRemove;
+                    }
+                }
+                /*
+                 * No "else" for Jamo T:
+                 * Since the input is in NFD, there are no Hangul LV syllables that
+                 * a Jamo T could combine with.
+                 * All Jamo Ts are combined above when handling Jamo Vs.
+                 */
+                if(p==limit) {
+                    break;
+                }
+                compositionsList=NULL;
+                continue;
+            } else if((compositeAndFwd=combine(compositionsList, c))>=0) {
+                // The starter and the combining mark (c) do combine.
+                UChar32 composite=compositeAndFwd>>1;
+
+                // Replace the starter with the composite, remove the combining mark.
+                pRemove=p-U16_LENGTH(c);  // pRemove & p: start & limit of the combining mark
+                if(starterIsSupplementary) {
+                    if(U_IS_SUPPLEMENTARY(composite)) {
+                        // both are supplementary
+                        starter[0]=U16_LEAD(composite);
+                        starter[1]=U16_TRAIL(composite);
+                    } else {
+                        *starter=(UChar)composite;
+                        // The composite is shorter than the starter,
+                        // move the intermediate characters forward one.
+                        starterIsSupplementary=FALSE;
+                        q=starter+1;
+                        r=q+1;
+                        while(r<pRemove) {
+                            *q++=*r++;
+                        }
+                        --pRemove;
+                    }
+                } else if(U_IS_SUPPLEMENTARY(composite)) {
+                    // The composite is longer than the starter,
+                    // move the intermediate characters back one.
+                    starterIsSupplementary=TRUE;
+                    ++starter;  // temporarily increment for the loop boundary
+                    q=pRemove;
+                    r=++pRemove;
+                    while(starter<q) {
+                        *--r=*--q;
+                    }
+                    *starter=U16_TRAIL(composite);
+                    *--starter=U16_LEAD(composite);  // undo the temporary increment
+                } else {
+                    // both are on the BMP
+                    *starter=(UChar)composite;
+                }
+
+                /* remove the combining mark by moving the following text over it */
+                if(pRemove<p) {
+                    q=pRemove;
+                    r=p;
+                    while(r<limit) {
+                        *q++=*r++;
+                    }
+                    limit=q;
+                    p=pRemove;
+                }
+                // Keep prevCC because we removed the combining mark.
+
+                if(p==limit) {
+                    break;
+                }
+                // Is the composite a starter that combines forward?
+                if(compositeAndFwd&1) {
+                    compositionsList=
+                        getCompositionsListForComposite(getNorm16(composite));
+                } else {
+                    compositionsList=NULL;
+                }
+
+                // We combined; continue with looking for compositions.
+                continue;
+            }
+        }
+
+        // no combination this time
+        prevCC=cc;
+        if(p==limit) {
+            break;
+        }
+
+        // If c did not combine, then check if it is a starter.
+        if(cc==0) {
+            // Found a new starter.
+            if((compositionsList=getCompositionsListForDecompYes(norm16))!=NULL) {
+                // It may combine with something, prepare for it.
+                if(U_IS_BMP(c)) {
+                    starterIsSupplementary=FALSE;
+                    starter=p-1;
+                } else {
+                    starterIsSupplementary=TRUE;
+                    starter=p-2;
+                }
+            }
+        } else if(onlyContiguous) {
+            // FCC: no discontiguous compositions; any intervening character blocks.
+            compositionsList=NULL;
+        }
+    }
+    buffer.setReorderingLimit(limit);
+}
+
+// Very similar to composeQuickCheck(): Make the same changes in both places if relevant.
+// doCompose: normalize
+// !doCompose: isNormalized (buffer must be empty and initialized)
+UBool
+Normalizer2Impl::compose(const UChar *src, const UChar *limit,
+                         UBool onlyContiguous,
+                         UBool doCompose,
+                         ReorderingBuffer &buffer,
+                         UErrorCode &errorCode) const {
+    /*
+     * prevBoundary points to the last character before the current one
+     * that has a composition boundary before it with ccc==0 and quick check "yes".
+     * Keeping track of prevBoundary saves us looking for a composition boundary
+     * when we find a "no" or "maybe".
+     *
+     * When we back out from prevSrc back to prevBoundary,
+     * then we also remove those same characters (which had been simply copied
+     * or canonically-order-inserted) from the ReorderingBuffer.
+     * Therefore, at all times, the [prevBoundary..prevSrc[ source units
+     * must correspond 1:1 to destination units at the end of the destination buffer.
+     */
+    const UChar *prevBoundary=src;
+    UChar32 minNoMaybeCP=minCompNoMaybeCP;
+    if(limit==NULL) {
+        src=copyLowPrefixFromNulTerminated(src, minNoMaybeCP,
+                                           doCompose ? &buffer : NULL,
+                                           errorCode);
+        if(U_FAILURE(errorCode)) {
+            return FALSE;
+        }
+        if(prevBoundary<src) {
+            // Set prevBoundary to the last character in the prefix.
+            prevBoundary=src-1;
+        }
+        limit=u_strchr(src, 0);
+    }
+
+    const UChar *prevSrc;
+    UChar32 c=0;
+    uint16_t norm16=0;
+
+    // only for isNormalized
+    uint8_t prevCC=0;
+
+    for(;;) {
+        // count code units below the minimum or with irrelevant data for the quick check
+        for(prevSrc=src; src!=limit;) {
+            if( (c=*src)<minNoMaybeCP ||
+                isCompYesAndZeroCC(norm16=UTRIE2_GET16_FROM_U16_SINGLE_LEAD(normTrie, c))
+            ) {
+                ++src;
+            } else if(!U16_IS_SURROGATE(c)) {
+                break;
+            } else {
+                UChar c2;
+                if(U16_IS_SURROGATE_LEAD(c)) {
+                    if((src+1)!=limit && U16_IS_TRAIL(c2=src[1])) {
+                        c=U16_GET_SUPPLEMENTARY(c, c2);
+                    }
+                } else /* trail surrogate */ {
+                    if(prevSrc<src && U16_IS_LEAD(c2=*(src-1))) {
+                        --src;
+                        c=U16_GET_SUPPLEMENTARY(c2, c);
+                    }
+                }
+                if(isCompYesAndZeroCC(norm16=getNorm16(c))) {
+                    src+=U16_LENGTH(c);
+                } else {
+                    break;
+                }
+            }
+        }
+        // copy these code units all at once
+        if(src!=prevSrc) {
+            if(doCompose) {
+                if(!buffer.appendZeroCC(prevSrc, src, errorCode)) {
+                    break;
+                }
+            } else {
+                prevCC=0;
+            }
+            if(src==limit) {
+                break;
+            }
+            // Set prevBoundary to the last character in the quick check loop.
+            prevBoundary=src-1;
+            if( U16_IS_TRAIL(*prevBoundary) && prevSrc<prevBoundary &&
+                U16_IS_LEAD(*(prevBoundary-1))
+            ) {
+                --prevBoundary;
+            }
+            // The start of the current character (c).
+            prevSrc=src;
+        } else if(src==limit) {
+            break;
+        }
+
+        src+=U16_LENGTH(c);
+        /*
+         * isCompYesAndZeroCC(norm16) is false, that is, norm16>=minNoNo.
+         * c is either a "noNo" (has a mapping) or a "maybeYes" (combines backward)
+         * or has ccc!=0.
+         * Check for Jamo V/T, then for regular characters.
+         * c is not a Hangul syllable or Jamo L because those have "yes" properties.
+         */
+        if(isJamoVT(norm16) && prevBoundary!=prevSrc) {
+            UChar prev=*(prevSrc-1);
+            UBool needToDecompose=FALSE;
+            if(c<Hangul::JAMO_T_BASE) {
+                // c is a Jamo Vowel, compose with previous Jamo L and following Jamo T.
+                prev=(UChar)(prev-Hangul::JAMO_L_BASE);
+                if(prev<Hangul::JAMO_L_COUNT) {
+                    if(!doCompose) {
+                        return FALSE;
+                    }
+                    UChar syllable=(UChar)
+                        (Hangul::HANGUL_BASE+
+                         (prev*Hangul::JAMO_V_COUNT+(c-Hangul::JAMO_V_BASE))*
+                         Hangul::JAMO_T_COUNT);
+                    UChar t;
+                    if(src!=limit && (t=(UChar)(*src-Hangul::JAMO_T_BASE))<Hangul::JAMO_T_COUNT) {
+                        ++src;
+                        syllable+=t;  // The next character was a Jamo T.
+                        prevBoundary=src;
+                        buffer.setLastChar(syllable);
+                        continue;
+                    }
+                    // If we see L+V+x where x!=T then we drop to the slow path,
+                    // decompose and recompose.
+                    // This is to deal with NFKC finding normal L and V but a
+                    // compatibility variant of a T. We need to either fully compose that
+                    // combination here (which would complicate the code and may not work
+                    // with strange custom data) or use the slow path -- or else our replacing
+                    // two input characters (L+V) with one output character (LV syllable)
+                    // would violate the invariant that [prevBoundary..prevSrc[ has the same
+                    // length as what we appended to the buffer since prevBoundary.
+                    needToDecompose=TRUE;
+                }
+            } else if(Hangul::isHangulWithoutJamoT(prev)) {
+                // c is a Jamo Trailing consonant,
+                // compose with previous Hangul LV that does not contain a Jamo T.
+                if(!doCompose) {
+                    return FALSE;
+                }
+                buffer.setLastChar((UChar)(prev+c-Hangul::JAMO_T_BASE));
+                prevBoundary=src;
+                continue;
+            }
+            if(!needToDecompose) {
+                // The Jamo V/T did not compose into a Hangul syllable.
+                if(doCompose) {
+                    if(!buffer.appendBMP((UChar)c, 0, errorCode)) {
+                        break;
+                    }
+                } else {
+                    prevCC=0;
+                }
+                continue;
+            }
+        }
+        /*
+         * Source buffer pointers:
+         *
+         *  all done      quick check   current char  not yet
+         *                "yes" but     (c)           processed
+         *                may combine
+         *                forward
+         * [-------------[-------------[-------------[-------------[
+         * |             |             |             |             |
+         * orig. src     prevBoundary  prevSrc       src           limit
+         *
+         *
+         * Destination buffer pointers inside the ReorderingBuffer:
+         *
+         *  all done      might take    not filled yet
+         *                characters for
+         *                reordering
+         * [-------------[-------------[-------------[
+         * |             |             |             |
+         * start         reorderStart  limit         |
+         *                             +remainingCap.+
+         */
+        if(norm16>=MIN_YES_YES_WITH_CC) {
+            uint8_t cc=(uint8_t)norm16;  // cc!=0
+            if( onlyContiguous &&  // FCC
+                (doCompose ? buffer.getLastCC() : prevCC)==0 &&
+                prevBoundary<prevSrc &&
+                // buffer.getLastCC()==0 && prevBoundary<prevSrc tell us that
+                // [prevBoundary..prevSrc[ (which is exactly one character under these conditions)
+                // passed the quick check "yes && ccc==0" test.
+                // Check whether the last character was a "yesYes" or a "yesNo".
+                // If a "yesNo", then we get its trailing ccc from its
+                // mapping and check for canonical order.
+                // All other cases are ok.
+                getTrailCCFromCompYesAndZeroCC(prevBoundary, prevSrc)>cc
+            ) {
+                // Fails FCD test, need to decompose and contiguously recompose.
+                if(!doCompose) {
+                    return FALSE;
+                }
+            } else if(doCompose) {
+                if(!buffer.append(c, cc, errorCode)) {
+                    break;
+                }
+                continue;
+            } else if(prevCC<=cc) {
+                prevCC=cc;
+                continue;
+            } else {
+                return FALSE;
+            }
+        } else if(!doCompose && !isMaybeOrNonZeroCC(norm16)) {
+            return FALSE;
+        }
+
+        /*
+         * Find appropriate boundaries around this character,
+         * decompose the source text from between the boundaries,
+         * and recompose it.
+         *
+         * We may need to remove the last few characters from the ReorderingBuffer
+         * to account for source text that was copied or appended
+         * but needs to take part in the recomposition.
+         */
+
+        /*
+         * Find the last composition boundary in [prevBoundary..src[.
+         * It is either the decomposition of the current character (at prevSrc),
+         * or prevBoundary.
+         */
+        if(hasCompBoundaryBefore(c, norm16)) {
+            prevBoundary=prevSrc;
+        } else if(doCompose) {
+            buffer.removeSuffix((int32_t)(prevSrc-prevBoundary));
+        }
+
+        // Find the next composition boundary in [src..limit[ -
+        // modifies src to point to the next starter.
+        src=(UChar *)findNextCompBoundary(src, limit);
+
+        // Decompose [prevBoundary..src[ into the buffer and then recompose that part of it.
+        int32_t recomposeStartIndex=buffer.length();
+        if(!decomposeShort(prevBoundary, src, buffer, errorCode)) {
+            break;
+        }
+        recompose(buffer, recomposeStartIndex, onlyContiguous);
+        if(!doCompose) {
+            if(!buffer.equals(prevBoundary, src)) {
+                return FALSE;
+            }
+            buffer.remove();
+            prevCC=0;
+        }
+
+        // Move to the next starter. We never need to look back before this point again.
+        prevBoundary=src;
+    }
+    return TRUE;
+}
+
+// Very similar to compose(): Make the same changes in both places if relevant.
+// pQCResult==NULL: spanQuickCheckYes
+// pQCResult!=NULL: quickCheck (*pQCResult must be UNORM_YES)
+const UChar *
+Normalizer2Impl::composeQuickCheck(const UChar *src, const UChar *limit,
+                                   UBool onlyContiguous,
+                                   UNormalizationCheckResult *pQCResult) const {
+    /*
+     * prevBoundary points to the last character before the current one
+     * that has a composition boundary before it with ccc==0 and quick check "yes".
+     */
+    const UChar *prevBoundary=src;
+    UChar32 minNoMaybeCP=minCompNoMaybeCP;
+    if(limit==NULL) {
+        UErrorCode errorCode=U_ZERO_ERROR;
+        src=copyLowPrefixFromNulTerminated(src, minNoMaybeCP, NULL, errorCode);
+        if(prevBoundary<src) {
+            // Set prevBoundary to the last character in the prefix.
+            prevBoundary=src-1;
+        }
+        limit=u_strchr(src, 0);
+    }
+
+    const UChar *prevSrc;
+    UChar32 c=0;
+    uint16_t norm16=0;
+    uint8_t prevCC=0;
+
+    for(;;) {
+        // count code units below the minimum or with irrelevant data for the quick check
+        for(prevSrc=src;;) {
+            if(src==limit) {
+                return src;
+            }
+            if( (c=*src)<minNoMaybeCP ||
+                isCompYesAndZeroCC(norm16=UTRIE2_GET16_FROM_U16_SINGLE_LEAD(normTrie, c))
+            ) {
+                ++src;
+            } else if(!U16_IS_SURROGATE(c)) {
+                break;
+            } else {
+                UChar c2;
+                if(U16_IS_SURROGATE_LEAD(c)) {
+                    if((src+1)!=limit && U16_IS_TRAIL(c2=src[1])) {
+                        c=U16_GET_SUPPLEMENTARY(c, c2);
+                    }
+                } else /* trail surrogate */ {
+                    if(prevSrc<src && U16_IS_LEAD(c2=*(src-1))) {
+                        --src;
+                        c=U16_GET_SUPPLEMENTARY(c2, c);
+                    }
+                }
+                if(isCompYesAndZeroCC(norm16=getNorm16(c))) {
+                    src+=U16_LENGTH(c);
+                } else {
+                    break;
+                }
+            }
+        }
+        if(src!=prevSrc) {
+            // Set prevBoundary to the last character in the quick check loop.
+            prevBoundary=src-1;
+            if( U16_IS_TRAIL(*prevBoundary) && prevSrc<prevBoundary &&
+                U16_IS_LEAD(*(prevBoundary-1))
+            ) {
+                --prevBoundary;
+            }
+            prevCC=0;
+            // The start of the current character (c).
+            prevSrc=src;
+        }
+
+        src+=U16_LENGTH(c);
+        /*
+         * isCompYesAndZeroCC(norm16) is false, that is, norm16>=minNoNo.
+         * c is either a "noNo" (has a mapping) or a "maybeYes" (combines backward)
+         * or has ccc!=0.
+         */
+        if(isMaybeOrNonZeroCC(norm16)) {
+            uint8_t cc=getCCFromYesOrMaybe(norm16);
+            if( onlyContiguous &&  // FCC
+                cc!=0 &&
+                prevCC==0 &&
+                prevBoundary<prevSrc &&
+                // prevCC==0 && prevBoundary<prevSrc tell us that
+                // [prevBoundary..prevSrc[ (which is exactly one character under these conditions)
+                // passed the quick check "yes && ccc==0" test.
+                // Check whether the last character was a "yesYes" or a "yesNo".
+                // If a "yesNo", then we get its trailing ccc from its
+                // mapping and check for canonical order.
+                // All other cases are ok.
+                getTrailCCFromCompYesAndZeroCC(prevBoundary, prevSrc)>cc
+            ) {
+                // Fails FCD test.
+            } else if(prevCC<=cc || cc==0) {
+                prevCC=cc;
+                if(norm16<MIN_YES_YES_WITH_CC) {
+                    if(pQCResult!=NULL) {
+                        *pQCResult=UNORM_MAYBE;
+                    } else {
+                        return prevBoundary;
+                    }
+                }
+                continue;
+            }
+        }
+        if(pQCResult!=NULL) {
+            *pQCResult=UNORM_NO;
+        }
+        return prevBoundary;
+    }
+}
+
+void Normalizer2Impl::composeAndAppend(const UChar *src, const UChar *limit,
+                                       UBool doCompose,
+                                       UBool onlyContiguous,
+                                       ReorderingBuffer &buffer,
+                                       UErrorCode &errorCode) const {
+    if(!buffer.isEmpty()) {
+        const UChar *firstStarterInSrc=findNextCompBoundary(src, limit);
+        if(src!=firstStarterInSrc) {
+            const UChar *lastStarterInDest=findPreviousCompBoundary(buffer.getStart(),
+                                                                    buffer.getLimit());
+            UnicodeString middle(lastStarterInDest,
+                                 (int32_t)(buffer.getLimit()-lastStarterInDest));
+            buffer.removeSuffix((int32_t)(buffer.getLimit()-lastStarterInDest));
+            middle.append(src, (int32_t)(firstStarterInSrc-src));
+            const UChar *middleStart=middle.getBuffer();
+            compose(middleStart, middleStart+middle.length(), onlyContiguous,
+                    TRUE, buffer, errorCode);
+            if(U_FAILURE(errorCode)) {
+                return;
+            }
+            src=firstStarterInSrc;
+        }
+    }
+    if(doCompose) {
+        compose(src, limit, onlyContiguous, TRUE, buffer, errorCode);
+    } else {
+        buffer.appendZeroCC(src, limit, errorCode);
+    }
+}
+
+/**
+ * Does c have a composition boundary before it?
+ * True if its decomposition begins with a character that has
+ * ccc=0 && NFC_QC=Yes (isCompYesAndZeroCC()).
+ * As a shortcut, this is true if c itself has ccc=0 && NFC_QC=Yes
+ * (isCompYesAndZeroCC()) so we need not decompose.
+ */
+UBool Normalizer2Impl::hasCompBoundaryBefore(UChar32 c, uint16_t norm16) const {
+    for(;;) {
+        if(isCompYesAndZeroCC(norm16)) {
+            return TRUE;
+        } else if(isMaybeOrNonZeroCC(norm16)) {
+            return FALSE;
+        } else if(isDecompNoAlgorithmic(norm16)) {
+            c=mapAlgorithmic(c, norm16);
+            norm16=getNorm16(c);
+        } else {
+            // c decomposes, get everything from the variable-length extra data
+            const uint16_t *mapping=getMapping(norm16);
+            uint16_t firstUnit=*mapping++;
+            if((firstUnit&MAPPING_LENGTH_MASK)==0) {
+                return FALSE;
+            }
+            if((firstUnit&MAPPING_HAS_CCC_LCCC_WORD) && (*mapping++&0xff00)) {
+                return FALSE;  // non-zero leadCC
+            }
+            int32_t i=0;
+            UChar32 c;
+            U16_NEXT_UNSAFE(mapping, i, c);
+            return isCompYesAndZeroCC(getNorm16(c));
+        }
+    }
+}
+
+UBool Normalizer2Impl::hasCompBoundaryAfter(UChar32 c, UBool onlyContiguous, UBool testInert) const {
+    for(;;) {
+        uint16_t norm16=getNorm16(c);
+        if(isInert(norm16)) {
+            return TRUE;
+        } else if(norm16<=minYesNo) {
+            // Hangul LVT (==minYesNo) has a boundary after it.
+            // Hangul LV and non-inert yesYes characters combine forward.
+            return isHangul(norm16) && !Hangul::isHangulWithoutJamoT((UChar)c);
+        } else if(norm16>= (testInert ? minNoNo : minMaybeYes)) {
+            return FALSE;
+        } else if(isDecompNoAlgorithmic(norm16)) {
+            c=mapAlgorithmic(c, norm16);
+        } else {
+            // c decomposes, get everything from the variable-length extra data.
+            // If testInert, then c must be a yesNo character which has lccc=0,
+            // otherwise it could be a noNo.
+            const uint16_t *mapping=getMapping(norm16);
+            uint16_t firstUnit=*mapping;
+            // TRUE if
+            //      c is not deleted, and
+            //      it and its decomposition do not combine forward, and it has a starter, and
+            //      if FCC then trailCC<=1
+            return
+                (firstUnit&MAPPING_LENGTH_MASK)!=0 &&
+                (firstUnit&(MAPPING_PLUS_COMPOSITION_LIST|MAPPING_NO_COMP_BOUNDARY_AFTER))==0 &&
+                (!onlyContiguous || firstUnit<=0x1ff);
+        }
+    }
+}
+
+const UChar *Normalizer2Impl::findPreviousCompBoundary(const UChar *start, const UChar *p) const {
+    BackwardUTrie2StringIterator iter(normTrie, start, p);
+    uint16_t norm16;
+    do {
+        norm16=iter.previous16();
+    } while(!hasCompBoundaryBefore(iter.codePoint, norm16));
+    // We could also test hasCompBoundaryAfter() and return iter.codePointLimit,
+    // but that's probably not worth the extra cost.
+    return iter.codePointStart;
+}
+
+const UChar *Normalizer2Impl::findNextCompBoundary(const UChar *p, const UChar *limit) const {
+    ForwardUTrie2StringIterator iter(normTrie, p, limit);
+    uint16_t norm16;
+    do {
+        norm16=iter.next16();
+    } while(!hasCompBoundaryBefore(iter.codePoint, norm16));
+    return iter.codePointStart;
+}
+
+class FCDTrieSingleton : public UTrie2Singleton {
+public:
+    FCDTrieSingleton(SimpleSingleton &s, Normalizer2Impl &ni, UErrorCode &ec) :
+        UTrie2Singleton(s), impl(ni), errorCode(ec) {}
+    UTrie2 *getInstance(UErrorCode &errorCode) {
+        return UTrie2Singleton::getInstance(createInstance, this, errorCode);
+    }
+    static void *createInstance(const void *context, UErrorCode &errorCode);
+    UBool rangeHandler(UChar32 start, UChar32 end, uint32_t value) {
+        if(value!=0) {
+            impl.setFCD16FromNorm16(start, end, (uint16_t)value, newFCDTrie, errorCode);
+        }
+        return U_SUCCESS(errorCode);
+    }
+
+    Normalizer2Impl &impl;
+    UTrie2 *newFCDTrie;
+    UErrorCode &errorCode;
+};
+
+U_CDECL_BEGIN
+
+// Set the FCD value for a range of same-norm16 characters.
+static UBool U_CALLCONV
+enumRangeHandler(const void *context, UChar32 start, UChar32 end, uint32_t value) {
+    return ((FCDTrieSingleton *)context)->rangeHandler(start, end, value);
+}
+
+// Collect (OR together) the FCD values for a range of supplementary characters,
+// for their lead surrogate code unit.
+static UBool U_CALLCONV
+enumRangeOrValue(const void *context, UChar32 /*start*/, UChar32 /*end*/, uint32_t value) {
+    *((uint32_t *)context)|=value;
+    return TRUE;
+}
+
+U_CDECL_END
+
+void *FCDTrieSingleton::createInstance(const void *context, UErrorCode &errorCode) {
+    FCDTrieSingleton *me=(FCDTrieSingleton *)context;
+    me->newFCDTrie=utrie2_open(0, 0, &errorCode);
+    if(U_SUCCESS(errorCode)) {
+        utrie2_enum(me->impl.getNormTrie(), NULL, enumRangeHandler, me);
+        for(UChar lead=0xd800; lead<0xdc00; ++lead) {
+            uint32_t oredValue=utrie2_get32(me->newFCDTrie, lead);
+            utrie2_enumForLeadSurrogate(me->newFCDTrie, lead, NULL, enumRangeOrValue, &oredValue);
+            if(oredValue!=0) {
+                // Set a "bad" value for makeFCD() to break the quick check loop
+                // and look up the value for the supplementary code point.
+                // If there is any lccc, then set the worst-case lccc of 1.
+                // The ORed-together value's tccc is already the worst case.
+                if(oredValue>0xff) {
+                    oredValue=0x100|(oredValue&0xff);
+                }
+                utrie2_set32ForLeadSurrogateCodeUnit(me->newFCDTrie, lead, oredValue, &errorCode);
+            }
+        }
+        utrie2_freeze(me->newFCDTrie, UTRIE2_16_VALUE_BITS, &errorCode);
+        if(U_SUCCESS(errorCode)) {
+            return me->newFCDTrie;
+        }
+    }
+    utrie2_close(me->newFCDTrie);
+    return NULL;
+}
+
+void Normalizer2Impl::setFCD16FromNorm16(UChar32 start, UChar32 end, uint16_t norm16,
+                                         UTrie2 *newFCDTrie, UErrorCode &errorCode) const {
+    // Only loops for 1:1 algorithmic mappings.
+    for(;;) {
+        if(norm16>=MIN_NORMAL_MAYBE_YES) {
+            norm16&=0xff;
+            norm16|=norm16<<8;
+        } else if(norm16<=minYesNo || minMaybeYes<=norm16) {
+            // no decomposition or Hangul syllable, all zeros
+            break;
+        } else if(limitNoNo<=norm16) {
+            int32_t delta=norm16-(minMaybeYes-MAX_DELTA-1);
+            if(start==end) {
+                start+=delta;
+                norm16=getNorm16(start);
+            } else {
+                // the same delta leads from different original characters to different mappings
+                do {
+                    UChar32 c=start+delta;
+                    setFCD16FromNorm16(c, c, getNorm16(c), newFCDTrie, errorCode);
+                } while(++start<=end);
+                break;
+            }
+        } else {
+            // c decomposes, get everything from the variable-length extra data
+            const uint16_t *mapping=getMapping(norm16);
+            uint16_t firstUnit=*mapping;
+            if((firstUnit&MAPPING_LENGTH_MASK)==0) {
+                // A character that is deleted (maps to an empty string) must
+                // get the worst-case lccc and tccc values because arbitrary
+                // characters on both sides will become adjacent.
+                norm16=0x1ff;
+            } else {
+                if(firstUnit&MAPPING_HAS_CCC_LCCC_WORD) {
+                    norm16=mapping[1]&0xff00;  // lccc
+                } else {
+                    norm16=0;
+                }
+                norm16|=firstUnit>>8;  // tccc
+            }
+        }
+        utrie2_setRange32(newFCDTrie, start, end, norm16, TRUE, &errorCode);
+        break;
+    }
+}
+
+const UTrie2 *Normalizer2Impl::getFCDTrie(UErrorCode &errorCode) const {
+    // Logically const: Synchronized instantiation.
+    Normalizer2Impl *me=const_cast<Normalizer2Impl *>(this);
+    return FCDTrieSingleton(me->fcdTrieSingleton, *me, errorCode).getInstance(errorCode);
+}
+
+// Dual functionality:
+// buffer!=NULL: normalize
+// buffer==NULL: isNormalized/quickCheck/spanQuickCheckYes
+const UChar *
+Normalizer2Impl::makeFCD(const UChar *src, const UChar *limit,
+                         ReorderingBuffer *buffer,
+                         UErrorCode &errorCode) const {
+    // Tracks the last FCD-safe boundary, before lccc=0 or after properly-ordered tccc<=1.
+    // Similar to the prevBoundary in the compose() implementation.
+    const UChar *prevBoundary=src;
+    int32_t prevFCD16=0;
+    if(limit==NULL) {
+        src=copyLowPrefixFromNulTerminated(src, MIN_CCC_LCCC_CP, buffer, errorCode);
+        if(U_FAILURE(errorCode)) {
+            return src;
+        }
+        if(prevBoundary<src) {
+            prevBoundary=src;
+            // We know that the previous character's lccc==0.
+            // Fetching the fcd16 value was deferred for this below-U+0300 code point.
+            prevFCD16=getFCD16FromSingleLead(*(src-1));
+            if(prevFCD16>1) {
+                --prevBoundary;
+            }
+        }
+        limit=u_strchr(src, 0);
+    }
+
+    // Note: In this function we use buffer->appendZeroCC() because we track
+    // the lead and trail combining classes here, rather than leaving it to
+    // the ReorderingBuffer.
+    // The exception is the call to decomposeShort() which uses the buffer
+    // in the normal way.
+
+    const UTrie2 *trie=fcdTrie();
+
+    const UChar *prevSrc;
+    UChar32 c=0;
+    uint16_t fcd16=0;
+
+    for(;;) {
+        // count code units with lccc==0
+        for(prevSrc=src; src!=limit;) {
+            if((c=*src)<MIN_CCC_LCCC_CP) {
+                prevFCD16=~c;
+                ++src;
+            } else if((fcd16=UTRIE2_GET16_FROM_U16_SINGLE_LEAD(trie, c))<=0xff) {
+                prevFCD16=fcd16;
+                ++src;
+            } else if(!U16_IS_SURROGATE(c)) {
+                break;
+            } else {
+                UChar c2;
+                if(U16_IS_SURROGATE_LEAD(c)) {
+                    if((src+1)!=limit && U16_IS_TRAIL(c2=src[1])) {
+                        c=U16_GET_SUPPLEMENTARY(c, c2);
+                    }
+                } else /* trail surrogate */ {
+                    if(prevSrc<src && U16_IS_LEAD(c2=*(src-1))) {
+                        --src;
+                        c=U16_GET_SUPPLEMENTARY(c2, c);
+                    }
+                }
+                if((fcd16=getFCD16(c))<=0xff) {
+                    prevFCD16=fcd16;
+                    src+=U16_LENGTH(c);
+                } else {
+                    break;
+                }
+            }
+        }
+        // copy these code units all at once
+        if(src!=prevSrc) {
+            if(buffer!=NULL && !buffer->appendZeroCC(prevSrc, src, errorCode)) {
+                break;
+            }
+            if(src==limit) {
+                break;
+            }
+            prevBoundary=src;
+            // We know that the previous character's lccc==0.
+            if(prevFCD16<0) {
+                // Fetching the fcd16 value was deferred for this below-U+0300 code point.
+                prevFCD16=getFCD16FromSingleLead((UChar)~prevFCD16);
+                if(prevFCD16>1) {
+                    --prevBoundary;
+                }
+            } else {
+                const UChar *p=src-1;
+                if(U16_IS_TRAIL(*p) && prevSrc<p && U16_IS_LEAD(*(p-1))) {
+                    --p;
+                    // Need to fetch the previous character's FCD value because
+                    // prevFCD16 was just for the trail surrogate code point.
+                    prevFCD16=getFCD16FromSurrogatePair(p[0], p[1]);
+                    // Still known to have lccc==0 because its lead surrogate unit had lccc==0.
+                }
+                if(prevFCD16>1) {
+                    prevBoundary=p;
+                }
+            }
+            // The start of the current character (c).
+            prevSrc=src;
+        } else if(src==limit) {
+            break;
+        }
+
+        src+=U16_LENGTH(c);
+        // The current character (c) at [prevSrc..src[ has a non-zero lead combining class.
+        // Check for proper order, and decompose locally if necessary.
+        if((prevFCD16&0xff)<=(fcd16>>8)) {
+            // proper order: prev tccc <= current lccc
+            if((fcd16&0xff)<=1) {
+                prevBoundary=src;
+            }
+            if(buffer!=NULL && !buffer->appendZeroCC(c, errorCode)) {
+                break;
+            }
+            prevFCD16=fcd16;
+            continue;
+        } else if(buffer==NULL) {
+            return prevBoundary;  // quick check "no"
+        } else {
+            /*
+             * Back out the part of the source that we copied or appended
+             * already but is now going to be decomposed.
+             * prevSrc is set to after what was copied/appended.
+             */
+            buffer->removeSuffix((int32_t)(prevSrc-prevBoundary));
+            /*
+             * Find the part of the source that needs to be decomposed,
+             * up to the next safe boundary.
+             */
+            src=findNextFCDBoundary(src, limit);
+            /*
+             * The source text does not fulfill the conditions for FCD.
+             * Decompose and reorder a limited piece of the text.
+             */
+            if(!decomposeShort(prevBoundary, src, *buffer, errorCode)) {
+                break;
+            }
+            prevBoundary=src;
+            prevFCD16=0;
+        }
+    }
+    return src;
+}
+
+void Normalizer2Impl::makeFCDAndAppend(const UChar *src, const UChar *limit,
+                                       UBool doMakeFCD,
+                                       ReorderingBuffer &buffer,
+                                       UErrorCode &errorCode) const {
+    if(!buffer.isEmpty()) {
+        const UChar *firstBoundaryInSrc=findNextFCDBoundary(src, limit);
+        if(src!=firstBoundaryInSrc) {
+            const UChar *lastBoundaryInDest=findPreviousFCDBoundary(buffer.getStart(),
+                                                                    buffer.getLimit());
+            UnicodeString middle(lastBoundaryInDest,
+                                 (int32_t)(buffer.getLimit()-lastBoundaryInDest));
+            buffer.removeSuffix((int32_t)(buffer.getLimit()-lastBoundaryInDest));
+            middle.append(src, (int32_t)(firstBoundaryInSrc-src));
+            const UChar *middleStart=middle.getBuffer();
+            makeFCD(middleStart, middleStart+middle.length(), &buffer, errorCode);
+            if(U_FAILURE(errorCode)) {
+                return;
+            }
+            src=firstBoundaryInSrc;
+        }
+    }
+    if(doMakeFCD) {
+        makeFCD(src, limit, &buffer, errorCode);
+    } else {
+        buffer.appendZeroCC(src, limit, errorCode);
+    }
+}
+
+const UChar *Normalizer2Impl::findPreviousFCDBoundary(const UChar *start, const UChar *p) const {
+    BackwardUTrie2StringIterator iter(fcdTrie(), start, p);
+    uint16_t fcd16;
+    do {
+        fcd16=iter.previous16();
+    } while(fcd16>0xff);
+    return iter.codePointStart;
+}
+
+const UChar *Normalizer2Impl::findNextFCDBoundary(const UChar *p, const UChar *limit) const {
+    ForwardUTrie2StringIterator iter(fcdTrie(), p, limit);
+    uint16_t fcd16;
+    do {
+        fcd16=iter.next16();
+    } while(fcd16>0xff);
+    return iter.codePointStart;
+}
+
+// CanonicalIterator data -------------------------------------------------- ***
+
+CanonIterData::CanonIterData(UErrorCode &errorCode) :
+        trie(utrie2_open(0, 0, &errorCode)),
+        canonStartSets(uhash_deleteUObject, NULL, errorCode) {}
+
+CanonIterData::~CanonIterData() {
+    utrie2_close(trie);
+}
+
+void CanonIterData::addToStartSet(UChar32 origin, UChar32 decompLead, UErrorCode &errorCode) {
+    uint32_t canonValue=utrie2_get32(trie, decompLead);
+    if((canonValue&(CANON_HAS_SET|CANON_VALUE_MASK))==0 && origin!=0) {
+        // origin is the first character whose decomposition starts with
+        // the character for which we are setting the value.
+        utrie2_set32(trie, decompLead, canonValue|origin, &errorCode);
+    } else {
+        // origin is not the first character, or it is U+0000.
+        UnicodeSet *set;
+        if((canonValue&CANON_HAS_SET)==0) {
+            set=new UnicodeSet;
+            if(set==NULL) {
+                errorCode=U_MEMORY_ALLOCATION_ERROR;
+                return;
+            }
+            UChar32 firstOrigin=(UChar32)(canonValue&CANON_VALUE_MASK);
+            canonValue=(canonValue&~CANON_VALUE_MASK)|CANON_HAS_SET|(uint32_t)canonStartSets.size();
+            utrie2_set32(trie, decompLead, canonValue, &errorCode);
+            canonStartSets.addElement(set, errorCode);
+            if(firstOrigin!=0) {
+                set->add(firstOrigin);
+            }
+        } else {
+            set=(UnicodeSet *)canonStartSets[(int32_t)(canonValue&CANON_VALUE_MASK)];
+        }
+        set->add(origin);
+    }
+}
+
+class CanonIterDataSingleton {
+public:
+    CanonIterDataSingleton(SimpleSingleton &s, Normalizer2Impl &ni, UErrorCode &ec) :
+        singleton(s), impl(ni), errorCode(ec) {}
+    CanonIterData *getInstance(UErrorCode &errorCode) {
+        void *duplicate;
+        CanonIterData *instance=
+            (CanonIterData *)singleton.getInstance(createInstance, this, duplicate, errorCode);
+        delete (CanonIterData *)duplicate;
+        return instance;
+    }
+    static void *createInstance(const void *context, UErrorCode &errorCode);
+    UBool rangeHandler(UChar32 start, UChar32 end, uint32_t value) {
+        if(value!=0) {
+            impl.makeCanonIterDataFromNorm16(start, end, (uint16_t)value, *newData, errorCode);
+        }
+        return U_SUCCESS(errorCode);
+    }
+
+private:
+    SimpleSingleton &singleton;
+    Normalizer2Impl &impl;
+    CanonIterData *newData;
+    UErrorCode &errorCode;
+};
+
+U_CDECL_BEGIN
+
+// Call Normalizer2Impl::makeCanonIterDataFromNorm16() for a range of same-norm16 characters.
+static UBool U_CALLCONV
+enumCIDRangeHandler(const void *context, UChar32 start, UChar32 end, uint32_t value) {
+    return ((CanonIterDataSingleton *)context)->rangeHandler(start, end, value);
+}
+
+U_CDECL_END
+
+void *CanonIterDataSingleton::createInstance(const void *context, UErrorCode &errorCode) {
+    CanonIterDataSingleton *me=(CanonIterDataSingleton *)context;
+    me->newData=new CanonIterData(errorCode);
+    if(me->newData==NULL) {
+        errorCode=U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    if(U_SUCCESS(errorCode)) {
+        utrie2_enum(me->impl.getNormTrie(), NULL, enumCIDRangeHandler, me);
+        utrie2_freeze(me->newData->trie, UTRIE2_32_VALUE_BITS, &errorCode);
+        if(U_SUCCESS(errorCode)) {
+            return me->newData;
+        }
+    }
+    delete me->newData;
+    return NULL;
+}
+
+void Normalizer2Impl::makeCanonIterDataFromNorm16(UChar32 start, UChar32 end, uint16_t norm16,
+                                                  CanonIterData &newData,
+                                                  UErrorCode &errorCode) const {
+    if(norm16==0 || (minYesNo<=norm16 && norm16<minNoNo)) {
+        // Inert, or 2-way mapping (including Hangul syllable).
+        // We do not write a canonStartSet for any yesNo character.
+        // Composites from 2-way mappings are added at runtime from the
+        // starter's compositions list, and the other characters in
+        // 2-way mappings get CANON_NOT_SEGMENT_STARTER set because they are
+        // "maybe" characters.
+        return;
+    }
+    for(UChar32 c=start; c<=end; ++c) {
+        uint32_t oldValue=utrie2_get32(newData.trie, c);
+        uint32_t newValue=oldValue;
+        if(norm16>=minMaybeYes) {
+            // not a segment starter if it occurs in a decomposition or has cc!=0
+            newValue|=CANON_NOT_SEGMENT_STARTER;
+            if(norm16<MIN_NORMAL_MAYBE_YES) {
+                newValue|=CANON_HAS_COMPOSITIONS;
+            }
+        } else if(norm16<minYesNo) {
+            newValue|=CANON_HAS_COMPOSITIONS;
+        } else {
+            // c has a one-way decomposition
+            UChar32 c2=c;
+            uint16_t norm16_2=norm16;
+            while(limitNoNo<=norm16_2 && norm16_2<minMaybeYes) {
+                c2=mapAlgorithmic(c2, norm16_2);
+                norm16_2=getNorm16(c2);
+            }
+            if(minYesNo<=norm16_2 && norm16_2<limitNoNo) {
+                // c decomposes, get everything from the variable-length extra data
+                const uint16_t *mapping=getMapping(norm16_2);
+                uint16_t firstUnit=*mapping++;
+                int32_t length=firstUnit&MAPPING_LENGTH_MASK;
+                if((firstUnit&MAPPING_HAS_CCC_LCCC_WORD)!=0) {
+                    if(c==c2 && (*mapping&0xff)!=0) {
+                        newValue|=CANON_NOT_SEGMENT_STARTER;  // original c has cc!=0
+                    }
+                    ++mapping;
+                }
+                // Skip empty mappings (no characters in the decomposition).
+                if(length!=0) {
+                    // add c to first code point's start set
+                    int32_t i=0;
+                    U16_NEXT_UNSAFE(mapping, i, c2);
+                    newData.addToStartSet(c, c2, errorCode);
+                    // Set CANON_NOT_SEGMENT_STARTER for each remaining code point of a
+                    // one-way mapping. A 2-way mapping is possible here after
+                    // intermediate algorithmic mapping.
+                    if(norm16_2>=minNoNo) {
+                        while(i<length) {
+                            U16_NEXT_UNSAFE(mapping, i, c2);
+                            uint32_t c2Value=utrie2_get32(newData.trie, c2);
+                            if((c2Value&CANON_NOT_SEGMENT_STARTER)==0) {
+                                utrie2_set32(newData.trie, c2, c2Value|CANON_NOT_SEGMENT_STARTER,
+                                             &errorCode);
+                            }
+                        }
+                    }
+                }
+            } else {
+                // c decomposed to c2 algorithmically; c has cc==0
+                newData.addToStartSet(c, c2, errorCode);
+            }
+        }
+        if(newValue!=oldValue) {
+            utrie2_set32(newData.trie, c, newValue, &errorCode);
+        }
+    }
+}
+
+UBool Normalizer2Impl::ensureCanonIterData(UErrorCode &errorCode) const {
+    // Logically const: Synchronized instantiation.
+    Normalizer2Impl *me=const_cast<Normalizer2Impl *>(this);
+    CanonIterDataSingleton(me->canonIterDataSingleton, *me, errorCode).getInstance(errorCode);
+    return U_SUCCESS(errorCode);
+}
+
+int32_t Normalizer2Impl::getCanonValue(UChar32 c) const {
+    return (int32_t)utrie2_get32(((CanonIterData *)canonIterDataSingleton.fInstance)->trie, c);
+}
+
+const UnicodeSet &Normalizer2Impl::getCanonStartSet(int32_t n) const {
+    return *(const UnicodeSet *)(
+        ((CanonIterData *)canonIterDataSingleton.fInstance)->canonStartSets[n]);
+}
+
+UBool Normalizer2Impl::isCanonSegmentStarter(UChar32 c) const {
+    return getCanonValue(c)>=0;
+}
+
+UBool Normalizer2Impl::getCanonStartSet(UChar32 c, UnicodeSet &set) const {
+    int32_t canonValue=getCanonValue(c)&~CANON_NOT_SEGMENT_STARTER;
+    if(canonValue==0) {
+        return FALSE;
+    }
+    set.clear();
+    int32_t value=canonValue&CANON_VALUE_MASK;
+    if((canonValue&CANON_HAS_SET)!=0) {
+        set.addAll(getCanonStartSet(value));
+    } else if(value!=0) {
+        set.add(value);
+    }
+    if((canonValue&CANON_HAS_COMPOSITIONS)!=0) {
+        uint16_t norm16=getNorm16(c);
+        if(norm16==JAMO_L) {
+            UChar32 syllable=
+                (UChar32)(Hangul::HANGUL_BASE+(c-Hangul::JAMO_L_BASE)*Hangul::JAMO_VT_COUNT);
+            set.add(syllable, syllable+Hangul::JAMO_VT_COUNT-1);
+        } else {
+            addComposites(getCompositionsList(norm16), set);
+        }
+    }
+    return TRUE;
+}
+
+U_NAMESPACE_END
+
+// Normalizer2 data swapping ----------------------------------------------- ***
+
+U_NAMESPACE_USE
+
+U_CAPI int32_t U_EXPORT2
+unorm2_swap(const UDataSwapper *ds,
+            const void *inData, int32_t length, void *outData,
+            UErrorCode *pErrorCode) {
+    const UDataInfo *pInfo;
+    int32_t headerSize;
+
+    const uint8_t *inBytes;
+    uint8_t *outBytes;
+
+    const int32_t *inIndexes;
+    int32_t indexes[Normalizer2Impl::IX_MIN_MAYBE_YES+1];
+
+    int32_t i, offset, nextOffset, size;
+
+    /* udata_swapDataHeader checks the arguments */
+    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    /* check data format and format version */
+    pInfo=(const UDataInfo *)((const char *)inData+4);
+    if(!(
+        pInfo->dataFormat[0]==0x4e &&   /* dataFormat="Nrm2" */
+        pInfo->dataFormat[1]==0x72 &&
+        pInfo->dataFormat[2]==0x6d &&
+        pInfo->dataFormat[3]==0x32 &&
+        pInfo->formatVersion[0]==1
+    )) {
+        udata_printError(ds, "unorm2_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as Normalizer2 data\n",
+                         pInfo->dataFormat[0], pInfo->dataFormat[1],
+                         pInfo->dataFormat[2], pInfo->dataFormat[3],
+                         pInfo->formatVersion[0]);
+        *pErrorCode=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    inBytes=(const uint8_t *)inData+headerSize;
+    outBytes=(uint8_t *)outData+headerSize;
+
+    inIndexes=(const int32_t *)inBytes;
+
+    if(length>=0) {
+        length-=headerSize;
+        if(length<(int32_t)sizeof(indexes)) {
+            udata_printError(ds, "unorm2_swap(): too few bytes (%d after header) for Normalizer2 data\n",
+                             length);
+            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+            return 0;
+        }
+    }
+
+    /* read the first few indexes */
+    for(i=0; i<=Normalizer2Impl::IX_MIN_MAYBE_YES; ++i) {
+        indexes[i]=udata_readInt32(ds, inIndexes[i]);
+    }
+
+    /* get the total length of the data */
+    size=indexes[Normalizer2Impl::IX_TOTAL_SIZE];
+
+    if(length>=0) {
+        if(length<size) {
+            udata_printError(ds, "unorm2_swap(): too few bytes (%d after header) for all of Normalizer2 data\n",
+                             length);
+            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+            return 0;
+        }
+
+        /* copy the data for inaccessible bytes */
+        if(inBytes!=outBytes) {
+            uprv_memcpy(outBytes, inBytes, size);
+        }
+
+        offset=0;
+
+        /* swap the int32_t indexes[] */
+        nextOffset=indexes[Normalizer2Impl::IX_NORM_TRIE_OFFSET];
+        ds->swapArray32(ds, inBytes, nextOffset-offset, outBytes, pErrorCode);
+        offset=nextOffset;
+
+        /* swap the UTrie2 */
+        nextOffset=indexes[Normalizer2Impl::IX_EXTRA_DATA_OFFSET];
+        utrie2_swap(ds, inBytes+offset, nextOffset-offset, outBytes+offset, pErrorCode);
+        offset=nextOffset;
+
+        /* swap the uint16_t extraData[] */
+        nextOffset=indexes[Normalizer2Impl::IX_EXTRA_DATA_OFFSET+1];
+        ds->swapArray16(ds, inBytes+offset, nextOffset-offset, outBytes+offset, pErrorCode);
+        offset=nextOffset;
+
+        U_ASSERT(offset==size);
+    }
+
+    return headerSize+size;
+}
+
+#endif  // !UCONFIG_NO_NORMALIZATION
diff --git a/source/common/normalizer2impl.h b/source/common/normalizer2impl.h
new file mode 100644
index 0000000..ebcf981
--- /dev/null
+++ b/source/common/normalizer2impl.h
@@ -0,0 +1,739 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2009-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  normalizer2impl.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2009nov22
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __NORMALIZER2IMPL_H__
+#define __NORMALIZER2IMPL_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/normalizer2.h"
+#include "unicode/udata.h"
+#include "unicode/unistr.h"
+#include "unicode/unorm.h"
+#include "mutex.h"
+#include "uset_imp.h"
+#include "utrie2.h"
+
+U_NAMESPACE_BEGIN
+
+class CanonIterData;
+
+class Hangul {
+public:
+    /* Korean Hangul and Jamo constants */
+    enum {
+        JAMO_L_BASE=0x1100,     /* "lead" jamo */
+        JAMO_V_BASE=0x1161,     /* "vowel" jamo */
+        JAMO_T_BASE=0x11a7,     /* "trail" jamo */
+
+        HANGUL_BASE=0xac00,
+
+        JAMO_L_COUNT=19,
+        JAMO_V_COUNT=21,
+        JAMO_T_COUNT=28,
+
+        JAMO_VT_COUNT=JAMO_V_COUNT*JAMO_T_COUNT,
+
+        HANGUL_COUNT=JAMO_L_COUNT*JAMO_V_COUNT*JAMO_T_COUNT,
+        HANGUL_LIMIT=HANGUL_BASE+HANGUL_COUNT
+    };
+
+    static inline UBool isHangul(UChar32 c) {
+        return HANGUL_BASE<=c && c<HANGUL_LIMIT;
+    }
+    static inline UBool
+    isHangulWithoutJamoT(UChar c) {
+        c-=HANGUL_BASE;
+        return c<HANGUL_COUNT && c%JAMO_T_COUNT==0;
+    }
+    static inline UBool isJamoL(UChar32 c) {
+        return (uint32_t)(c-JAMO_L_BASE)<JAMO_L_COUNT;
+    }
+    static inline UBool isJamoV(UChar32 c) {
+        return (uint32_t)(c-JAMO_V_BASE)<JAMO_V_COUNT;
+    }
+
+    /**
+     * Decomposes c, which must be a Hangul syllable, into buffer
+     * and returns the length of the decomposition (2 or 3).
+     */
+    static inline int32_t decompose(UChar32 c, UChar buffer[3]) {
+        c-=HANGUL_BASE;
+        UChar32 c2=c%JAMO_T_COUNT;
+        c/=JAMO_T_COUNT;
+        buffer[0]=(UChar)(JAMO_L_BASE+c/JAMO_V_COUNT);
+        buffer[1]=(UChar)(JAMO_V_BASE+c%JAMO_V_COUNT);
+        if(c2==0) {
+            return 2;
+        } else {
+            buffer[2]=(UChar)(JAMO_T_BASE+c2);
+            return 3;
+        }
+    }
+private:
+    Hangul();  // no instantiation
+};
+
+class Normalizer2Impl;
+
+class ReorderingBuffer : public UMemory {
+public:
+    ReorderingBuffer(const Normalizer2Impl &ni, UnicodeString &dest) :
+        impl(ni), str(dest),
+        start(NULL), reorderStart(NULL), limit(NULL),
+        remainingCapacity(0), lastCC(0) {}
+    ~ReorderingBuffer() {
+        if(start!=NULL) {
+            str.releaseBuffer((int32_t)(limit-start));
+        }
+    }
+    UBool init(int32_t destCapacity, UErrorCode &errorCode);
+
+    UBool isEmpty() const { return start==limit; }
+    int32_t length() const { return (int32_t)(limit-start); }
+    UChar *getStart() { return start; }
+    UChar *getLimit() { return limit; }
+    uint8_t getLastCC() const { return lastCC; }
+
+    UBool equals(const UChar *start, const UChar *limit) const;
+
+    // For Hangul composition, replacing the Leading consonant Jamo with the syllable.
+    void setLastChar(UChar c) {
+        *(limit-1)=c;
+    }
+
+    UBool append(UChar32 c, uint8_t cc, UErrorCode &errorCode) {
+        return (c<=0xffff) ?
+            appendBMP((UChar)c, cc, errorCode) :
+            appendSupplementary(c, cc, errorCode);
+    }
+    // s must be in NFD, otherwise change the implementation.
+    UBool append(const UChar *s, int32_t length,
+                 uint8_t leadCC, uint8_t trailCC,
+                 UErrorCode &errorCode);
+    UBool appendBMP(UChar c, uint8_t cc, UErrorCode &errorCode) {
+        if(remainingCapacity==0 && !resize(1, errorCode)) {
+            return FALSE;
+        }
+        if(lastCC<=cc || cc==0) {
+            *limit++=c;
+            lastCC=cc;
+            if(cc<=1) {
+                reorderStart=limit;
+            }
+        } else {
+            insert(c, cc);
+        }
+        --remainingCapacity;
+        return TRUE;
+    }
+    UBool appendZeroCC(UChar32 c, UErrorCode &errorCode);
+    UBool appendZeroCC(const UChar *s, const UChar *sLimit, UErrorCode &errorCode);
+    void remove();
+    void removeSuffix(int32_t suffixLength);
+    void setReorderingLimit(UChar *newLimit) {
+        remainingCapacity+=(int32_t)(limit-newLimit);
+        reorderStart=limit=newLimit;
+        lastCC=0;
+    }
+private:
+    /*
+     * TODO: Revisit whether it makes sense to track reorderStart.
+     * It is set to after the last known character with cc<=1,
+     * which stops previousCC() before it reads that character and looks up its cc.
+     * previousCC() is normally only called from insert().
+     * In other words, reorderStart speeds up the insertion of a combining mark
+     * into a multi-combining mark sequence where it does not belong at the end.
+     * This might not be worth the trouble.
+     * On the other hand, it's not a huge amount of trouble.
+     *
+     * We probably need it for UNORM_SIMPLE_APPEND.
+     */
+
+    UBool appendSupplementary(UChar32 c, uint8_t cc, UErrorCode &errorCode);
+    void insert(UChar32 c, uint8_t cc);
+    static void writeCodePoint(UChar *p, UChar32 c) {
+        if(c<=0xffff) {
+            *p=(UChar)c;
+        } else {
+            p[0]=U16_LEAD(c);
+            p[1]=U16_TRAIL(c);
+        }
+    }
+    UBool resize(int32_t appendLength, UErrorCode &errorCode);
+
+    const Normalizer2Impl &impl;
+    UnicodeString &str;
+    UChar *start, *reorderStart, *limit;
+    int32_t remainingCapacity;
+    uint8_t lastCC;
+
+    // private backward iterator
+    void setIterator() { codePointStart=limit; }
+    void skipPrevious();  // Requires start<codePointStart.
+    uint8_t previousCC();  // Returns 0 if there is no previous character.
+
+    UChar *codePointStart, *codePointLimit;
+};
+
+class U_COMMON_API Normalizer2Impl : public UMemory {
+public:
+    Normalizer2Impl() : memory(NULL), normTrie(NULL) {
+        fcdTrieSingleton.fInstance=NULL;
+        canonIterDataSingleton.fInstance=NULL;
+    }
+    ~Normalizer2Impl();
+
+    void load(const char *packageName, const char *name, UErrorCode &errorCode);
+
+    void addPropertyStarts(const USetAdder *sa, UErrorCode &errorCode) const;
+    void addCanonIterPropertyStarts(const USetAdder *sa, UErrorCode &errorCode) const;
+
+    // low-level properties ------------------------------------------------ ***
+
+    const UTrie2 *getNormTrie() const { return normTrie; }
+    const UTrie2 *getFCDTrie(UErrorCode &errorCode) const ;
+
+    UBool ensureCanonIterData(UErrorCode &errorCode) const;
+
+    uint16_t getNorm16(UChar32 c) const { return UTRIE2_GET16(normTrie, c); }
+
+    UNormalizationCheckResult getCompQuickCheck(uint16_t norm16) const {
+        if(norm16<minNoNo || MIN_YES_YES_WITH_CC<=norm16) {
+            return UNORM_YES;
+        } else if(minMaybeYes<=norm16) {
+            return UNORM_MAYBE;
+        } else {
+            return UNORM_NO;
+        }
+    }
+    UBool isCompNo(uint16_t norm16) const { return minNoNo<=norm16 && norm16<minMaybeYes; }
+    UBool isDecompYes(uint16_t norm16) const { return norm16<minYesNo || minMaybeYes<=norm16; }
+
+    uint8_t getCC(uint16_t norm16) const {
+        if(norm16>=MIN_NORMAL_MAYBE_YES) {
+            return (uint8_t)norm16;
+        }
+        if(norm16<minNoNo || limitNoNo<=norm16) {
+            return 0;
+        }
+        return getCCFromNoNo(norm16);
+    }
+    static uint8_t getCCFromYesOrMaybe(uint16_t norm16) {
+        return norm16>=MIN_NORMAL_MAYBE_YES ? (uint8_t)norm16 : 0;
+    }
+
+    uint16_t getFCD16(UChar32 c) const { return UTRIE2_GET16(fcdTrie(), c); }
+    uint16_t getFCD16FromSingleLead(UChar c) const {
+        return UTRIE2_GET16_FROM_U16_SINGLE_LEAD(fcdTrie(), c);
+    }
+    uint16_t getFCD16FromSupplementary(UChar32 c) const {
+        return UTRIE2_GET16_FROM_SUPP(fcdTrie(), c);
+    }
+    uint16_t getFCD16FromSurrogatePair(UChar c, UChar c2) const {
+        return getFCD16FromSupplementary(U16_GET_SUPPLEMENTARY(c, c2));
+    }
+
+    void setFCD16FromNorm16(UChar32 start, UChar32 end, uint16_t norm16,
+                            UTrie2 *newFCDTrie, UErrorCode &errorCode) const;
+
+    void makeCanonIterDataFromNorm16(UChar32 start, UChar32 end, uint16_t norm16,
+                                     CanonIterData &newData, UErrorCode &errorCode) const;
+
+    /**
+     * Get the decomposition for one code point.
+     * @param c code point
+     * @param buffer out-only buffer for algorithmic decompositions
+     * @param length out-only, takes the length of the decomposition, if any
+     * @return pointer to the decomposition, or NULL if none
+     */
+    const UChar *getDecomposition(UChar32 c, UChar buffer[4], int32_t &length) const;
+
+    UBool isCanonSegmentStarter(UChar32 c) const;
+    UBool getCanonStartSet(UChar32 c, UnicodeSet &set) const;
+
+    enum {
+        MIN_CCC_LCCC_CP=0x300
+    };
+
+    enum {
+        MIN_YES_YES_WITH_CC=0xff01,
+        JAMO_VT=0xff00,
+        MIN_NORMAL_MAYBE_YES=0xfe00,
+        JAMO_L=1,
+        MAX_DELTA=0x40
+    };
+
+    enum {
+        // Byte offsets from the start of the data, after the generic header.
+        IX_NORM_TRIE_OFFSET,
+        IX_EXTRA_DATA_OFFSET,
+        IX_RESERVED2_OFFSET,
+        IX_RESERVED3_OFFSET,
+        IX_RESERVED4_OFFSET,
+        IX_RESERVED5_OFFSET,
+        IX_RESERVED6_OFFSET,
+        IX_TOTAL_SIZE,
+
+        // Code point thresholds for quick check codes.
+        IX_MIN_DECOMP_NO_CP,
+        IX_MIN_COMP_NO_MAYBE_CP,
+
+        // Norm16 value thresholds for quick check combinations and types of extra data.
+        IX_MIN_YES_NO,
+        IX_MIN_NO_NO,
+        IX_LIMIT_NO_NO,
+        IX_MIN_MAYBE_YES,
+
+        IX_RESERVED14,
+        IX_RESERVED15,
+        IX_COUNT
+    };
+
+    enum {
+        MAPPING_HAS_CCC_LCCC_WORD=0x80,
+        MAPPING_PLUS_COMPOSITION_LIST=0x40,
+        MAPPING_NO_COMP_BOUNDARY_AFTER=0x20,
+        MAPPING_LENGTH_MASK=0x1f
+    };
+
+    enum {
+        COMP_1_LAST_TUPLE=0x8000,
+        COMP_1_TRIPLE=1,
+        COMP_1_TRAIL_LIMIT=0x3400,
+        COMP_1_TRAIL_MASK=0x7ffe,
+        COMP_1_TRAIL_SHIFT=9,  // 10-1 for the "triple" bit
+        COMP_2_TRAIL_SHIFT=6,
+        COMP_2_TRAIL_MASK=0xffc0
+    };
+
+    // higher-level functionality ------------------------------------------ ***
+
+    const UChar *decompose(const UChar *src, const UChar *limit,
+                           ReorderingBuffer *buffer, UErrorCode &errorCode) const;
+    void decomposeAndAppend(const UChar *src, const UChar *limit,
+                            UBool doDecompose,
+                            ReorderingBuffer &buffer,
+                            UErrorCode &errorCode) const;
+    UBool compose(const UChar *src, const UChar *limit,
+                  UBool onlyContiguous,
+                  UBool doCompose,
+                  ReorderingBuffer &buffer,
+                  UErrorCode &errorCode) const;
+    const UChar *composeQuickCheck(const UChar *src, const UChar *limit,
+                                   UBool onlyContiguous,
+                                   UNormalizationCheckResult *pQCResult) const;
+    void composeAndAppend(const UChar *src, const UChar *limit,
+                          UBool doCompose,
+                          UBool onlyContiguous,
+                          ReorderingBuffer &buffer,
+                          UErrorCode &errorCode) const;
+    const UChar *makeFCD(const UChar *src, const UChar *limit,
+                         ReorderingBuffer *buffer, UErrorCode &errorCode) const;
+    void makeFCDAndAppend(const UChar *src, const UChar *limit,
+                          UBool doMakeFCD,
+                          ReorderingBuffer &buffer,
+                          UErrorCode &errorCode) const;
+
+    UBool hasDecompBoundary(UChar32 c, UBool before) const;
+    UBool isDecompInert(UChar32 c) const { return isDecompYesAndZeroCC(getNorm16(c)); }
+
+    UBool hasCompBoundaryBefore(UChar32 c) const {
+        return c<minCompNoMaybeCP || hasCompBoundaryBefore(c, getNorm16(c));
+    }
+    UBool hasCompBoundaryAfter(UChar32 c, UBool onlyContiguous, UBool testInert) const;
+
+    UBool hasFCDBoundaryBefore(UChar32 c) const { return c<MIN_CCC_LCCC_CP || getFCD16(c)<=0xff; }
+    UBool hasFCDBoundaryAfter(UChar32 c) const {
+        uint16_t fcd16=getFCD16(c);
+        return fcd16<=1 || (fcd16&0xff)==0;
+    }
+    UBool isFCDInert(UChar32 c) const { return getFCD16(c)<=1; }
+private:
+    static UBool U_CALLCONV
+    isAcceptable(void *context, const char *type, const char *name, const UDataInfo *pInfo);
+
+    UBool isMaybe(uint16_t norm16) const { return minMaybeYes<=norm16 && norm16<=JAMO_VT; }
+    UBool isMaybeOrNonZeroCC(uint16_t norm16) const { return norm16>=minMaybeYes; }
+    static UBool isInert(uint16_t norm16) { return norm16==0; }
+    // static UBool isJamoL(uint16_t norm16) const { return norm16==1; }
+    static UBool isJamoVT(uint16_t norm16) { return norm16==JAMO_VT; }
+    UBool isHangul(uint16_t norm16) const { return norm16==minYesNo; }
+    UBool isCompYesAndZeroCC(uint16_t norm16) const { return norm16<minNoNo; }
+    // UBool isCompYes(uint16_t norm16) const {
+    //     return norm16>=MIN_YES_YES_WITH_CC || norm16<minNoNo;
+    // }
+    // UBool isCompYesOrMaybe(uint16_t norm16) const {
+    //     return norm16<minNoNo || minMaybeYes<=norm16;
+    // }
+    // UBool hasZeroCCFromDecompYes(uint16_t norm16) const {
+    //     return norm16<=MIN_NORMAL_MAYBE_YES || norm16==JAMO_VT;
+    // }
+    UBool isDecompYesAndZeroCC(uint16_t norm16) const {
+        return norm16<minYesNo ||
+               norm16==JAMO_VT ||
+               (minMaybeYes<=norm16 && norm16<=MIN_NORMAL_MAYBE_YES);
+    }
+    /**
+     * A little faster and simpler than isDecompYesAndZeroCC() but does not include
+     * the MaybeYes which combine-forward and have ccc=0.
+     * (Standard Unicode 5.2 normalization does not have such characters.)
+     */
+    UBool isMostDecompYesAndZeroCC(uint16_t norm16) const {
+        return norm16<minYesNo || norm16==MIN_NORMAL_MAYBE_YES || norm16==JAMO_VT;
+    }
+    UBool isDecompNoAlgorithmic(uint16_t norm16) const { return norm16>=limitNoNo; }
+
+    // For use with isCompYes().
+    // Perhaps the compiler can combine the two tests for MIN_YES_YES_WITH_CC.
+    // static uint8_t getCCFromYes(uint16_t norm16) {
+    //     return norm16>=MIN_YES_YES_WITH_CC ? (uint8_t)norm16 : 0;
+    // }
+    uint8_t getCCFromNoNo(uint16_t norm16) const {
+        const uint16_t *mapping=getMapping(norm16);
+        if(*mapping&MAPPING_HAS_CCC_LCCC_WORD) {
+            return (uint8_t)mapping[1];
+        } else {
+            return 0;
+        }
+    }
+    // requires that the [cpStart..cpLimit[ character passes isCompYesAndZeroCC()
+    uint8_t getTrailCCFromCompYesAndZeroCC(const UChar *cpStart, const UChar *cpLimit) const;
+
+    // Requires algorithmic-NoNo.
+    UChar32 mapAlgorithmic(UChar32 c, uint16_t norm16) const {
+        return c+norm16-(minMaybeYes-MAX_DELTA-1);
+    }
+
+    // Requires minYesNo<norm16<limitNoNo.
+    const uint16_t *getMapping(uint16_t norm16) const { return extraData+norm16; }
+    const uint16_t *getCompositionsListForDecompYes(uint16_t norm16) const {
+        if(norm16==0 || MIN_NORMAL_MAYBE_YES<=norm16) {
+            return NULL;
+        } else if(norm16<minMaybeYes) {
+            return extraData+norm16;  // for yesYes; if Jamo L: harmless empty list
+        } else {
+            return maybeYesCompositions+norm16-minMaybeYes;
+        }
+    }
+    const uint16_t *getCompositionsListForComposite(uint16_t norm16) const {
+        const uint16_t *list=extraData+norm16;  // composite has both mapping & compositions list
+        return list+  // mapping pointer
+            1+  // +1 to skip the first unit with the mapping lenth
+            (*list&MAPPING_LENGTH_MASK)+  // + mapping length
+            ((*list>>7)&1);  // +1 if MAPPING_HAS_CCC_LCCC_WORD
+    }
+    /**
+     * @param c code point must have compositions
+     * @return compositions list pointer
+     */
+    const uint16_t *getCompositionsList(uint16_t norm16) const {
+        return isDecompYes(norm16) ?
+                getCompositionsListForDecompYes(norm16) :
+                getCompositionsListForComposite(norm16);
+    }
+
+    const UChar *copyLowPrefixFromNulTerminated(const UChar *src,
+                                                UChar32 minNeedDataCP,
+                                                ReorderingBuffer *buffer,
+                                                UErrorCode &errorCode) const;
+    UBool decomposeShort(const UChar *src, const UChar *limit,
+                         ReorderingBuffer &buffer, UErrorCode &errorCode) const;
+    UBool decompose(UChar32 c, uint16_t norm16,
+                    ReorderingBuffer &buffer, UErrorCode &errorCode) const;
+
+    static int32_t combine(const uint16_t *list, UChar32 trail);
+    void addComposites(const uint16_t *list, UnicodeSet &set) const;
+    void recompose(ReorderingBuffer &buffer, int32_t recomposeStartIndex,
+                   UBool onlyContiguous) const;
+
+    UBool hasCompBoundaryBefore(UChar32 c, uint16_t norm16) const;
+    const UChar *findPreviousCompBoundary(const UChar *start, const UChar *p) const;
+    const UChar *findNextCompBoundary(const UChar *p, const UChar *limit) const;
+
+    const UTrie2 *fcdTrie() const { return (const UTrie2 *)fcdTrieSingleton.fInstance; }
+
+    const UChar *findPreviousFCDBoundary(const UChar *start, const UChar *p) const;
+    const UChar *findNextFCDBoundary(const UChar *p, const UChar *limit) const;
+
+    int32_t getCanonValue(UChar32 c) const;
+    const UnicodeSet &getCanonStartSet(int32_t n) const;
+
+    UDataMemory *memory;
+    UVersionInfo dataVersion;
+
+    // Code point thresholds for quick check codes.
+    UChar32 minDecompNoCP;
+    UChar32 minCompNoMaybeCP;
+
+    // Norm16 value thresholds for quick check combinations and types of extra data.
+    uint16_t minYesNo;
+    uint16_t minNoNo;
+    uint16_t limitNoNo;
+    uint16_t minMaybeYes;
+
+    UTrie2 *normTrie;
+    const uint16_t *maybeYesCompositions;
+    const uint16_t *extraData;  // mappings and/or compositions for yesYes, yesNo & noNo characters
+
+    SimpleSingleton fcdTrieSingleton;
+    SimpleSingleton canonIterDataSingleton;
+};
+
+// bits in canonIterData
+#define CANON_NOT_SEGMENT_STARTER 0x80000000
+#define CANON_HAS_COMPOSITIONS 0x40000000
+#define CANON_HAS_SET 0x200000
+#define CANON_VALUE_MASK 0x1fffff
+
+/**
+ * ICU-internal shortcut for quick access to standard Unicode normalization.
+ */
+class U_COMMON_API Normalizer2Factory {
+public:
+    static const Normalizer2 *getNFCInstance(UErrorCode &errorCode);
+    static const Normalizer2 *getNFDInstance(UErrorCode &errorCode);
+    static const Normalizer2 *getFCDInstance(UErrorCode &errorCode);
+    static const Normalizer2 *getFCCInstance(UErrorCode &errorCode);
+    static const Normalizer2 *getNFKCInstance(UErrorCode &errorCode);
+    static const Normalizer2 *getNFKDInstance(UErrorCode &errorCode);
+    static const Normalizer2 *getNFKC_CFInstance(UErrorCode &errorCode);
+    static const Normalizer2 *getNoopInstance(UErrorCode &errorCode);
+
+    static const Normalizer2 *getInstance(UNormalizationMode mode, UErrorCode &errorCode);
+
+    static const Normalizer2Impl *getNFCImpl(UErrorCode &errorCode);
+    static const Normalizer2Impl *getNFKCImpl(UErrorCode &errorCode);
+    static const Normalizer2Impl *getNFKC_CFImpl(UErrorCode &errorCode);
+
+    // Get the Impl instance of the Normalizer2.
+    // Must be used only when it is known that norm2 is a Normalizer2WithImpl instance.
+    static const Normalizer2Impl *getImpl(const Normalizer2 *norm2);
+
+    static const UTrie2 *getFCDTrie(UErrorCode &errorCode);
+private:
+    Normalizer2Factory();  // No instantiation.
+};
+
+U_NAMESPACE_END
+
+U_CAPI int32_t U_EXPORT2
+unorm2_swap(const UDataSwapper *ds,
+            const void *inData, int32_t length, void *outData,
+            UErrorCode *pErrorCode);
+
+/**
+ * Get the NF*_QC property for a code point, for u_getIntPropertyValue().
+ * @internal
+ */
+U_CFUNC UNormalizationCheckResult U_EXPORT2
+unorm_getQuickCheck(UChar32 c, UNormalizationMode mode);
+
+/**
+ * Internal API, used by collation code.
+ * Get access to the internal FCD trie table to be able to perform
+ * incremental, per-code unit, FCD checks in collation.
+ * One pointer is sufficient because the trie index values are offset
+ * by the index size, so that the same pointer is used to access the trie data.
+ * Code points at fcdHighStart and above have a zero FCD value.
+ * @internal
+ */
+U_CAPI const uint16_t * U_EXPORT2
+unorm_getFCDTrieIndex(UChar32 &fcdHighStart, UErrorCode *pErrorCode);
+
+/**
+ * Internal API, used by collation code.
+ * Get the FCD value for a code unit, with
+ * bits 15..8   lead combining class
+ * bits  7..0   trail combining class
+ *
+ * If c is a lead surrogate and the value is not 0,
+ * then some of c's associated supplementary code points have a non-zero FCD value.
+ *
+ * @internal
+ */
+static inline uint16_t
+unorm_getFCD16(const uint16_t *fcdTrieIndex, UChar c) {
+    return fcdTrieIndex[_UTRIE2_INDEX_FROM_U16_SINGLE_LEAD(fcdTrieIndex, c)];
+}
+
+/**
+ * Internal API, used by collation code.
+ * Get the FCD value of the next code point (post-increment), with
+ * bits 15..8   lead combining class
+ * bits  7..0   trail combining class
+ *
+ * @internal
+ */
+static inline uint16_t
+unorm_nextFCD16(const uint16_t *fcdTrieIndex, UChar32 fcdHighStart,
+                const UChar *&s, const UChar *limit) {
+    UChar32 c=*s++;
+    uint16_t fcd=fcdTrieIndex[_UTRIE2_INDEX_FROM_U16_SINGLE_LEAD(fcdTrieIndex, c)];
+    if(fcd!=0 && U16_IS_LEAD(c)) {
+        UChar c2;
+        if(s!=limit && U16_IS_TRAIL(c2=*s)) {
+            ++s;
+            c=U16_GET_SUPPLEMENTARY(c, c2);
+            if(c<fcdHighStart) {
+                fcd=fcdTrieIndex[_UTRIE2_INDEX_FROM_SUPP(fcdTrieIndex, c)];
+            } else {
+                fcd=0;
+            }
+        } else /* unpaired lead surrogate */ {
+            fcd=0;
+        }
+    }
+    return fcd;
+}
+
+/**
+ * Internal API, used by collation code.
+ * Get the FCD value of the previous code point (pre-decrement), with
+ * bits 15..8   lead combining class
+ * bits  7..0   trail combining class
+ *
+ * @internal
+ */
+static inline uint16_t
+unorm_prevFCD16(const uint16_t *fcdTrieIndex, UChar32 fcdHighStart,
+                const UChar *start, const UChar *&s) {
+    UChar32 c=*--s;
+    uint16_t fcd;
+    if(!U16_IS_SURROGATE(c)) {
+        fcd=fcdTrieIndex[_UTRIE2_INDEX_FROM_U16_SINGLE_LEAD(fcdTrieIndex, c)];
+    } else {
+        UChar c2;
+        if(U16_IS_SURROGATE_TRAIL(c) && s!=start && U16_IS_LEAD(c2=*(s-1))) {
+            --s;
+            c=U16_GET_SUPPLEMENTARY(c2, c);
+            if(c<fcdHighStart) {
+                fcd=fcdTrieIndex[_UTRIE2_INDEX_FROM_SUPP(fcdTrieIndex, c)];
+            } else {
+                fcd=0;
+            }
+        } else /* unpaired surrogate */ {
+            fcd=0;
+        }
+    }
+    return fcd;
+}
+
+/**
+ * Format of Normalizer2 .nrm data files.
+ * Format version 1.0.
+ *
+ * Normalizer2 .nrm data files provide data for the Unicode Normalization algorithms.
+ * ICU ships with data files for standard Unicode Normalization Forms
+ * NFC and NFD (nfc.nrm), NFKC and NFKD (nfkc.nrm) and NFKC_Casefold (nfkc_cf.nrm).
+ * Custom (application-specific) data can be built into additional .nrm files
+ * with the gennorm2 build tool.
+ *
+ * Normalizer2.getInstance() causes a .nrm file to be loaded, unless it has been
+ * cached already. Internally, Normalizer2Impl.load() reads the .nrm file.
+ *
+ * A .nrm file begins with a standard ICU data file header
+ * (DataHeader, see ucmndata.h and unicode/udata.h).
+ * The UDataInfo.dataVersion field usually contains the Unicode version
+ * for which the data was generated.
+ *
+ * After the header, the file contains the following parts.
+ * Constants are defined as enum values of the Normalizer2Impl class.
+ *
+ * Many details of the data structures are described in the design doc
+ * which is at http://site.icu-project.org/design/normalization/custom
+ *
+ * int32_t indexes[indexesLength]; -- indexesLength=indexes[IX_NORM_TRIE_OFFSET]/4;
+ *
+ *      The first eight indexes are byte offsets in ascending order.
+ *      Each byte offset marks the start of the next part in the data file,
+ *      and the end of the previous one.
+ *      When two consecutive byte offsets are the same, then the corresponding part is empty.
+ *      Byte offsets are offsets from after the header,
+ *      that is, from the beginning of the indexes[].
+ *      Each part starts at an offset with proper alignment for its data.
+ *      If necessary, the previous part may include padding bytes to achieve this alignment.
+ *
+ *      minDecompNoCP=indexes[IX_MIN_DECOMP_NO_CP] is the lowest code point
+ *      with a decomposition mapping, that is, with NF*D_QC=No.
+ *      minCompNoMaybeCP=indexes[IX_MIN_COMP_NO_MAYBE_CP] is the lowest code point
+ *      with NF*C_QC=No (has a one-way mapping) or Maybe (combines backward).
+ *
+ *      The next four indexes are thresholds of 16-bit trie values for ranges of
+ *      values indicating multiple normalization properties.
+ *          minYesNo=indexes[IX_MIN_YES_NO];
+ *          minNoNo=indexes[IX_MIN_NO_NO];
+ *          limitNoNo=indexes[IX_LIMIT_NO_NO];
+ *          minMaybeYes=indexes[IX_MIN_MAYBE_YES];
+ *      See the normTrie description below and the design doc for details.
+ *
+ * UTrie2 normTrie; -- see utrie2_impl.h and utrie2.h
+ *
+ *      The trie holds the main normalization data. Each code point is mapped to a 16-bit value.
+ *      Rather than using independent bits in the value (which would require more than 16 bits),
+ *      information is extracted primarily via range checks.
+ *      For example, a 16-bit value norm16 in the range minYesNo<=norm16<minNoNo
+ *      means that the character has NF*C_QC=Yes and NF*D_QC=No properties,
+ *      which means it has a two-way (round-trip) decomposition mapping.
+ *      Values in the range 2<=norm16<limitNoNo are also directly indexes into the extraData
+ *      pointing to mappings, composition lists, or both.
+ *      Value norm16==0 means that the character is normalization-inert, that is,
+ *      it does not have a mapping, does not participate in composition, has a zero
+ *      canonical combining class, and forms a boundary where text before it and after it
+ *      can be normalized independently.
+ *      For details about how multiple properties are encoded in 16-bit values
+ *      see the design doc.
+ *      Note that the encoding cannot express all combinations of the properties involved;
+ *      it only supports those combinations that are allowed by
+ *      the Unicode Normalization algorithms. Details are in the design doc as well.
+ *      The gennorm2 tool only builds .nrm files for data that conforms to the limitations.
+ *
+ *      The trie has a value for each lead surrogate code unit representing the "worst case"
+ *      properties of the 1024 supplementary characters whose UTF-16 form starts with
+ *      the lead surrogate. If all of the 1024 supplementary characters are normalization-inert,
+ *      then their lead surrogate code unit has the trie value 0.
+ *      When the lead surrogate unit's value exceeds the quick check minimum during processing,
+ *      the properties for the full supplementary code point need to be looked up.
+ *
+ * uint16_t maybeYesCompositions[MIN_NORMAL_MAYBE_YES-minMaybeYes];
+ * uint16_t extraData[];
+ *
+ *      There is only one byte offset for the end of these two arrays.
+ *      The split between them is given by the constant and variable mentioned above.
+ *
+ *      The maybeYesCompositions array contains composition lists for characters that
+ *      combine both forward (as starters in composition pairs)
+ *      and backward (as trailing characters in composition pairs).
+ *      Such characters do not occur in Unicode 5.2 but are allowed by
+ *      the Unicode Normalization algorithms.
+ *      If there are no such characters, then minMaybeYes==MIN_NORMAL_MAYBE_YES
+ *      and the maybeYesCompositions array is empty.
+ *      If there are such characters, then minMaybeYes is subtracted from their norm16 values
+ *      to get the index into this array.
+ *
+ *      The extraData array contains composition lists for "YesYes" characters,
+ *      followed by mappings and optional composition lists for "YesNo" characters,
+ *      followed by only mappings for "NoNo" characters.
+ *      (Referring to pairs of NFC/NFD quick check values.)
+ *      The norm16 values of those characters are directly indexes into the extraData array.
+ *
+ *      The data structures for composition lists and mappings are described in the design doc.
+ */
+
+#endif  /* !UCONFIG_NO_NORMALIZATION */
+#endif  /* __NORMALIZER2IMPL_H__ */
diff --git a/source/common/normlzr.cpp b/source/common/normlzr.cpp
new file mode 100644
index 0000000..52f2c29
--- /dev/null
+++ b/source/common/normlzr.cpp
@@ -0,0 +1,522 @@
+/*
+ *************************************************************************
+ * COPYRIGHT: 
+ * Copyright (c) 1996-2010, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ *************************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/uniset.h"
+#include "unicode/unistr.h"
+#include "unicode/chariter.h"
+#include "unicode/schriter.h"
+#include "unicode/uchriter.h"
+#include "unicode/normlzr.h"
+#include "cmemory.h"
+#include "normalizer2impl.h"
+#include "uprops.h"  // for uniset_getUnicode32Instance()
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Normalizer)
+
+//-------------------------------------------------------------------------
+// Constructors and other boilerplate
+//-------------------------------------------------------------------------
+
+Normalizer::Normalizer(const UnicodeString& str, UNormalizationMode mode) :
+    UObject(), fFilteredNorm2(NULL), fNorm2(NULL), fUMode(mode), fOptions(0),
+    text(new StringCharacterIterator(str)),
+    currentIndex(0), nextIndex(0),
+    buffer(), bufferPos(0)
+{
+    init();
+}
+
+Normalizer::Normalizer(const UChar *str, int32_t length, UNormalizationMode mode) :
+    UObject(), fFilteredNorm2(NULL), fNorm2(NULL), fUMode(mode), fOptions(0),
+    text(new UCharCharacterIterator(str, length)),
+    currentIndex(0), nextIndex(0),
+    buffer(), bufferPos(0)
+{
+    init();
+}
+
+Normalizer::Normalizer(const CharacterIterator& iter, UNormalizationMode mode) :
+    UObject(), fFilteredNorm2(NULL), fNorm2(NULL), fUMode(mode), fOptions(0),
+    text(iter.clone()),
+    currentIndex(0), nextIndex(0),
+    buffer(), bufferPos(0)
+{
+    init();
+}
+
+Normalizer::Normalizer(const Normalizer &copy) :
+    UObject(copy), fFilteredNorm2(NULL), fNorm2(NULL), fUMode(copy.fUMode), fOptions(copy.fOptions),
+    text(copy.text->clone()),
+    currentIndex(copy.currentIndex), nextIndex(copy.nextIndex),
+    buffer(copy.buffer), bufferPos(copy.bufferPos)
+{
+    init();
+}
+
+static const UChar _NUL=0;
+
+void
+Normalizer::init() {
+    UErrorCode errorCode=U_ZERO_ERROR;
+    fNorm2=Normalizer2Factory::getInstance(fUMode, errorCode);
+    if(fOptions&UNORM_UNICODE_3_2) {
+        delete fFilteredNorm2;
+        fNorm2=fFilteredNorm2=
+            new FilteredNormalizer2(*fNorm2, *uniset_getUnicode32Instance(errorCode));
+    }
+    if(U_FAILURE(errorCode)) {
+        errorCode=U_ZERO_ERROR;
+        fNorm2=Normalizer2Factory::getNoopInstance(errorCode);
+    }
+}
+
+Normalizer::~Normalizer()
+{
+    delete fFilteredNorm2;
+    delete text;
+}
+
+Normalizer* 
+Normalizer::clone() const
+{
+    return new Normalizer(*this);
+}
+
+/**
+ * Generates a hash code for this iterator.
+ */
+int32_t Normalizer::hashCode() const
+{
+    return text->hashCode() + fUMode + fOptions + buffer.hashCode() + bufferPos + currentIndex + nextIndex;
+}
+    
+UBool Normalizer::operator==(const Normalizer& that) const
+{
+    return
+        this==&that ||
+        (fUMode==that.fUMode &&
+        fOptions==that.fOptions &&
+        *text==*that.text &&
+        buffer==that.buffer &&
+        bufferPos==that.bufferPos &&
+        nextIndex==that.nextIndex);
+}
+
+//-------------------------------------------------------------------------
+// Static utility methods
+//-------------------------------------------------------------------------
+
+void U_EXPORT2
+Normalizer::normalize(const UnicodeString& source, 
+                      UNormalizationMode mode, int32_t options,
+                      UnicodeString& result, 
+                      UErrorCode &status) {
+    if(source.isBogus() || U_FAILURE(status)) {
+        result.setToBogus();
+        if(U_SUCCESS(status)) {
+            status=U_ILLEGAL_ARGUMENT_ERROR;
+        }
+    } else {
+        UnicodeString localDest;
+        UnicodeString *dest;
+
+        if(&source!=&result) {
+            dest=&result;
+        } else {
+            // the source and result strings are the same object, use a temporary one
+            dest=&localDest;
+        }
+        const Normalizer2 *n2=Normalizer2Factory::getInstance(mode, status);
+        if(U_SUCCESS(status)) {
+            if(options&UNORM_UNICODE_3_2) {
+                FilteredNormalizer2(*n2, *uniset_getUnicode32Instance(status)).
+                    normalize(source, *dest, status);
+            } else {
+                n2->normalize(source, *dest, status);
+            }
+        }
+        if(dest==&localDest && U_SUCCESS(status)) {
+            result=*dest;
+        }
+    }
+}
+
+void U_EXPORT2
+Normalizer::compose(const UnicodeString& source, 
+                    UBool compat, int32_t options,
+                    UnicodeString& result, 
+                    UErrorCode &status) {
+    normalize(source, compat ? UNORM_NFKC : UNORM_NFC, options, result, status);
+}
+
+void U_EXPORT2
+Normalizer::decompose(const UnicodeString& source, 
+                      UBool compat, int32_t options,
+                      UnicodeString& result, 
+                      UErrorCode &status) {
+    normalize(source, compat ? UNORM_NFKD : UNORM_NFD, options, result, status);
+}
+
+UNormalizationCheckResult
+Normalizer::quickCheck(const UnicodeString& source,
+                       UNormalizationMode mode, int32_t options,
+                       UErrorCode &status) {
+    const Normalizer2 *n2=Normalizer2Factory::getInstance(mode, status);
+    if(U_SUCCESS(status)) {
+        if(options&UNORM_UNICODE_3_2) {
+            return FilteredNormalizer2(*n2, *uniset_getUnicode32Instance(status)).
+                quickCheck(source, status);
+        } else {
+            return n2->quickCheck(source, status);
+        }
+    } else {
+        return UNORM_MAYBE;
+    }
+}
+
+UBool
+Normalizer::isNormalized(const UnicodeString& source,
+                         UNormalizationMode mode, int32_t options,
+                         UErrorCode &status) {
+    const Normalizer2 *n2=Normalizer2Factory::getInstance(mode, status);
+    if(U_SUCCESS(status)) {
+        if(options&UNORM_UNICODE_3_2) {
+            return FilteredNormalizer2(*n2, *uniset_getUnicode32Instance(status)).
+                isNormalized(source, status);
+        } else {
+            return n2->isNormalized(source, status);
+        }
+    } else {
+        return FALSE;
+    }
+}
+
+UnicodeString & U_EXPORT2
+Normalizer::concatenate(UnicodeString &left, UnicodeString &right,
+                        UnicodeString &result,
+                        UNormalizationMode mode, int32_t options,
+                        UErrorCode &errorCode) {
+    if(left.isBogus() || right.isBogus() || U_FAILURE(errorCode)) {
+        result.setToBogus();
+        if(U_SUCCESS(errorCode)) {
+            errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        }
+    } else {
+        UnicodeString localDest;
+        UnicodeString *dest;
+
+        if(&right!=&result) {
+            dest=&result;
+        } else {
+            // the right and result strings are the same object, use a temporary one
+            dest=&localDest;
+        }
+        *dest=left;
+        const Normalizer2 *n2=Normalizer2Factory::getInstance(mode, errorCode);
+        if(U_SUCCESS(errorCode)) {
+            if(options&UNORM_UNICODE_3_2) {
+                FilteredNormalizer2(*n2, *uniset_getUnicode32Instance(errorCode)).
+                    append(*dest, right, errorCode);
+            } else {
+                n2->append(*dest, right, errorCode);
+            }
+        }
+        if(dest==&localDest && U_SUCCESS(errorCode)) {
+            result=*dest;
+        }
+    }
+    return result;
+}
+
+//-------------------------------------------------------------------------
+// Iteration API
+//-------------------------------------------------------------------------
+
+/**
+ * Return the current character in the normalized text.
+ */
+UChar32 Normalizer::current() {
+    if(bufferPos<buffer.length() || nextNormalize()) {
+        return buffer.char32At(bufferPos);
+    } else {
+        return DONE;
+    }
+}
+
+/**
+ * Return the next character in the normalized text and advance
+ * the iteration position by one.  If the end
+ * of the text has already been reached, {@link #DONE} is returned.
+ */
+UChar32 Normalizer::next() {
+    if(bufferPos<buffer.length() ||  nextNormalize()) {
+        UChar32 c=buffer.char32At(bufferPos);
+        bufferPos+=UTF_CHAR_LENGTH(c);
+        return c;
+    } else {
+        return DONE;
+    }
+}
+
+/**
+ * Return the previous character in the normalized text and decrement
+ * the iteration position by one.  If the beginning
+ * of the text has already been reached, {@link #DONE} is returned.
+ */
+UChar32 Normalizer::previous() {
+    if(bufferPos>0 || previousNormalize()) {
+        UChar32 c=buffer.char32At(bufferPos-1);
+        bufferPos-=UTF_CHAR_LENGTH(c);
+        return c;
+    } else {
+        return DONE;
+    }
+}
+
+void Normalizer::reset() {
+    currentIndex=nextIndex=text->setToStart();
+    clearBuffer();
+}
+
+void
+Normalizer::setIndexOnly(int32_t index) {
+    text->setIndex(index);  // pins index
+    currentIndex=nextIndex=text->getIndex();
+    clearBuffer();
+}
+
+/**
+ * Return the first character in the normalized text.  This resets
+ * the <tt>Normalizer's</tt> position to the beginning of the text.
+ */
+UChar32 Normalizer::first() {
+    reset();
+    return next();
+}
+
+/**
+ * Return the last character in the normalized text.  This resets
+ * the <tt>Normalizer's</tt> position to be just before the
+ * the input text corresponding to that normalized character.
+ */
+UChar32 Normalizer::last() {
+    currentIndex=nextIndex=text->setToEnd();
+    clearBuffer();
+    return previous();
+}
+
+/**
+ * Retrieve the current iteration position in the input text that is
+ * being normalized.  This method is useful in applications such as
+ * searching, where you need to be able to determine the position in
+ * the input text that corresponds to a given normalized output character.
+ * <p>
+ * <b>Note:</b> This method sets the position in the <em>input</em>, while
+ * {@link #next} and {@link #previous} iterate through characters in the
+ * <em>output</em>.  This means that there is not necessarily a one-to-one
+ * correspondence between characters returned by <tt>next</tt> and
+ * <tt>previous</tt> and the indices passed to and returned from
+ * <tt>setIndex</tt> and {@link #getIndex}.
+ *
+ */
+int32_t Normalizer::getIndex() const {
+    if(bufferPos<buffer.length()) {
+        return currentIndex;
+    } else {
+        return nextIndex;
+    }
+}
+
+/**
+ * Retrieve the index of the start of the input text.  This is the begin index
+ * of the <tt>CharacterIterator</tt> or the start (i.e. 0) of the <tt>String</tt>
+ * over which this <tt>Normalizer</tt> is iterating
+ */
+int32_t Normalizer::startIndex() const {
+    return text->startIndex();
+}
+
+/**
+ * Retrieve the index of the end of the input text.  This is the end index
+ * of the <tt>CharacterIterator</tt> or the length of the <tt>String</tt>
+ * over which this <tt>Normalizer</tt> is iterating
+ */
+int32_t Normalizer::endIndex() const {
+    return text->endIndex();
+}
+
+//-------------------------------------------------------------------------
+// Property access methods
+//-------------------------------------------------------------------------
+
+void
+Normalizer::setMode(UNormalizationMode newMode) 
+{
+    fUMode = newMode;
+    init();
+}
+
+UNormalizationMode
+Normalizer::getUMode() const
+{
+    return fUMode;
+}
+
+void
+Normalizer::setOption(int32_t option, 
+                      UBool value) 
+{
+    if (value) {
+        fOptions |= option;
+    } else {
+        fOptions &= (~option);
+    }
+    init();
+}
+
+UBool
+Normalizer::getOption(int32_t option) const
+{
+    return (fOptions & option) != 0;
+}
+
+/**
+ * Set the input text over which this <tt>Normalizer</tt> will iterate.
+ * The iteration position is set to the beginning of the input text.
+ */
+void
+Normalizer::setText(const UnicodeString& newText, 
+                    UErrorCode &status)
+{
+    if (U_FAILURE(status)) {
+        return;
+    }
+    CharacterIterator *newIter = new StringCharacterIterator(newText);
+    if (newIter == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    delete text;
+    text = newIter;
+    reset();
+}
+
+/**
+ * Set the input text over which this <tt>Normalizer</tt> will iterate.
+ * The iteration position is set to the beginning of the string.
+ */
+void
+Normalizer::setText(const CharacterIterator& newText, 
+                    UErrorCode &status) 
+{
+    if (U_FAILURE(status)) {
+        return;
+    }
+    CharacterIterator *newIter = newText.clone();
+    if (newIter == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    delete text;
+    text = newIter;
+    reset();
+}
+
+void
+Normalizer::setText(const UChar* newText,
+                    int32_t length,
+                    UErrorCode &status)
+{
+    if (U_FAILURE(status)) {
+        return;
+    }
+    CharacterIterator *newIter = new UCharCharacterIterator(newText, length);
+    if (newIter == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    delete text;
+    text = newIter;
+    reset();
+}
+
+/**
+ * Copies the text under iteration into the UnicodeString referred to by "result".
+ * @param result Receives a copy of the text under iteration.
+ */
+void
+Normalizer::getText(UnicodeString&  result) 
+{
+    text->getText(result);
+}
+
+//-------------------------------------------------------------------------
+// Private utility methods
+//-------------------------------------------------------------------------
+
+void Normalizer::clearBuffer() {
+    buffer.remove();
+    bufferPos=0;
+}
+
+UBool
+Normalizer::nextNormalize() {
+    clearBuffer();
+    currentIndex=nextIndex;
+    text->setIndex(nextIndex);
+    if(!text->hasNext()) {
+        return FALSE;
+    }
+    // Skip at least one character so we make progress.
+    UnicodeString segment(text->next32PostInc());
+    while(text->hasNext()) {
+        UChar32 c;
+        if(fNorm2->hasBoundaryBefore(c=text->next32PostInc())) {
+            text->move32(-1, CharacterIterator::kCurrent);
+            break;
+        }
+        segment.append(c);
+    }
+    nextIndex=text->getIndex();
+    UErrorCode errorCode=U_ZERO_ERROR;
+    fNorm2->normalize(segment, buffer, errorCode);
+    return U_SUCCESS(errorCode) && !buffer.isEmpty();
+}
+
+UBool
+Normalizer::previousNormalize() {
+    clearBuffer();
+    nextIndex=currentIndex;
+    text->setIndex(currentIndex);
+    if(!text->hasPrevious()) {
+        return FALSE;
+    }
+    UnicodeString segment;
+    while(text->hasPrevious()) {
+        UChar32 c=text->previous32();
+        segment.insert(0, c);
+        if(fNorm2->hasBoundaryBefore(c)) {
+            break;
+        }
+    }
+    currentIndex=text->getIndex();
+    UErrorCode errorCode=U_ZERO_ERROR;
+    fNorm2->normalize(segment, buffer, errorCode);
+    bufferPos=buffer.length();
+    return U_SUCCESS(errorCode) && !buffer.isEmpty();
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_NORMALIZATION */
diff --git a/source/common/parsepos.cpp b/source/common/parsepos.cpp
new file mode 100644
index 0000000..26f8820
--- /dev/null
+++ b/source/common/parsepos.cpp
@@ -0,0 +1,21 @@
+/*
+**********************************************************************
+*   Copyright (C) 2003-2003, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+
+#include "unicode/parsepos.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ParsePosition)
+
+ParsePosition::~ParsePosition() {}
+
+ParsePosition *
+ParsePosition::clone() const {
+    return new ParsePosition(*this);
+}
+
+U_NAMESPACE_END
diff --git a/source/common/propname.cpp b/source/common/propname.cpp
new file mode 100644
index 0000000..1721f83
--- /dev/null
+++ b/source/common/propname.cpp
@@ -0,0 +1,752 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2009, International Business Machines
+* Corporation and others.  All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: October 30 2002
+* Since: ICU 2.4
+**********************************************************************
+*/
+#include "propname.h"
+#include "unicode/uchar.h"
+#include "unicode/udata.h"
+#include "umutex.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "ucln_cmn.h"
+#include "uarrsort.h"
+
+U_CDECL_BEGIN
+
+/**
+ * Get the next non-ignorable ASCII character from a property name
+ * and lowercases it.
+ * @return ((advance count for the name)<<8)|character
+ */
+static inline int32_t
+getASCIIPropertyNameChar(const char *name) {
+    int32_t i;
+    char c;
+
+    /* Ignore delimiters '-', '_', and ASCII White_Space */
+    for(i=0;
+        (c=name[i++])==0x2d || c==0x5f ||
+        c==0x20 || (0x09<=c && c<=0x0d);
+    ) {}
+
+    if(c!=0) {
+        return (i<<8)|(uint8_t)uprv_asciitolower((char)c);
+    } else {
+        return i<<8;
+    }
+}
+
+/**
+ * Get the next non-ignorable EBCDIC character from a property name
+ * and lowercases it.
+ * @return ((advance count for the name)<<8)|character
+ */
+static inline int32_t
+getEBCDICPropertyNameChar(const char *name) {
+    int32_t i;
+    char c;
+
+    /* Ignore delimiters '-', '_', and EBCDIC White_Space */
+    for(i=0;
+        (c=name[i++])==0x60 || c==0x6d ||
+        c==0x40 || c==0x05 || c==0x15 || c==0x25 || c==0x0b || c==0x0c || c==0x0d;
+    ) {}
+
+    if(c!=0) {
+        return (i<<8)|(uint8_t)uprv_ebcdictolower((char)c);
+    } else {
+        return i<<8;
+    }
+}
+
+/**
+ * Unicode property names and property value names are compared "loosely".
+ *
+ * UCD.html 4.0.1 says:
+ *   For all property names, property value names, and for property values for
+ *   Enumerated, Binary, or Catalog properties, use the following
+ *   loose matching rule:
+ *
+ *   LM3. Ignore case, whitespace, underscore ('_'), and hyphens.
+ *
+ * This function does just that, for (char *) name strings.
+ * It is almost identical to ucnv_compareNames() but also ignores
+ * C0 White_Space characters (U+0009..U+000d, and U+0085 on EBCDIC).
+ *
+ * @internal
+ */
+
+U_CAPI int32_t U_EXPORT2
+uprv_compareASCIIPropertyNames(const char *name1, const char *name2) {
+    int32_t rc, r1, r2;
+
+    for(;;) {
+        r1=getASCIIPropertyNameChar(name1);
+        r2=getASCIIPropertyNameChar(name2);
+
+        /* If we reach the ends of both strings then they match */
+        if(((r1|r2)&0xff)==0) {
+            return 0;
+        }
+        
+        /* Compare the lowercased characters */
+        if(r1!=r2) {
+            rc=(r1&0xff)-(r2&0xff);
+            if(rc!=0) {
+                return rc;
+            }
+        }
+
+        name1+=r1>>8;
+        name2+=r2>>8;
+    }
+}
+
+U_CAPI int32_t U_EXPORT2
+uprv_compareEBCDICPropertyNames(const char *name1, const char *name2) {
+    int32_t rc, r1, r2;
+
+    for(;;) {
+        r1=getEBCDICPropertyNameChar(name1);
+        r2=getEBCDICPropertyNameChar(name2);
+
+        /* If we reach the ends of both strings then they match */
+        if(((r1|r2)&0xff)==0) {
+            return 0;
+        }
+        
+        /* Compare the lowercased characters */
+        if(r1!=r2) {
+            rc=(r1&0xff)-(r2&0xff);
+            if(rc!=0) {
+                return rc;
+            }
+        }
+
+        name1+=r1>>8;
+        name2+=r2>>8;
+    }
+}
+
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+//----------------------------------------------------------------------
+// PropertyAliases implementation
+
+const char*
+PropertyAliases::chooseNameInGroup(Offset offset,
+                                   UPropertyNameChoice choice) const {
+    int32_t c = choice;
+    if (!offset || c < 0) {
+        return NULL;
+    }
+    const Offset* p = (const Offset*) getPointer(offset);
+    while (c-- > 0) {
+        if (*p++ < 0) return NULL;
+    }
+    Offset a = *p;
+    if (a < 0) a = -a;
+    return (const char*) getPointerNull(a);
+}
+
+const ValueMap*
+PropertyAliases::getValueMap(EnumValue prop) const {
+    NonContiguousEnumToOffset* e2o = (NonContiguousEnumToOffset*) getPointer(enumToValue_offset);
+    Offset a = e2o->getOffset(prop);
+    return (const ValueMap*) (a ? getPointerNull(a) : NULL);
+}
+
+inline const char*
+PropertyAliases::getPropertyName(EnumValue prop,
+                                 UPropertyNameChoice choice) const {
+    NonContiguousEnumToOffset* e2n = (NonContiguousEnumToOffset*) getPointer(enumToName_offset);
+    return chooseNameInGroup(e2n->getOffset(prop), choice);
+}
+
+inline EnumValue
+PropertyAliases::getPropertyEnum(const char* alias) const {
+    NameToEnum* n2e = (NameToEnum*) getPointer(nameToEnum_offset);
+    return n2e->getEnum(alias, *this);
+}
+
+inline const char*
+PropertyAliases::getPropertyValueName(EnumValue prop,
+                                      EnumValue value,
+                                      UPropertyNameChoice choice) const {
+    const ValueMap* vm = getValueMap(prop);
+    if (!vm) return NULL;
+    Offset a;
+    if (vm->enumToName_offset) {
+        a = ((EnumToOffset*) getPointer(vm->enumToName_offset))->
+            getOffset(value);
+    } else {
+        a = ((NonContiguousEnumToOffset*) getPointer(vm->ncEnumToName_offset))->
+            getOffset(value);
+    }
+    return chooseNameInGroup(a, choice);
+}
+
+inline EnumValue
+PropertyAliases::getPropertyValueEnum(EnumValue prop,
+                                      const char* alias) const {
+    const ValueMap* vm = getValueMap(prop);
+    if (!vm) return UCHAR_INVALID_CODE;
+    NameToEnum* n2e = (NameToEnum*) getPointer(vm->nameToEnum_offset);
+    return n2e->getEnum(alias, *this);
+}
+
+U_NAMESPACE_END
+U_NAMESPACE_USE
+
+//----------------------------------------------------------------------
+// UDataMemory structures
+
+static const PropertyAliases* PNAME = NULL;
+static UDataMemory* UDATA = NULL;
+
+//----------------------------------------------------------------------
+// UDataMemory loading/unloading
+
+/**
+ * udata callback to verify the zone data.
+ */
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+isPNameAcceptable(void* /*context*/,
+             const char* /*type*/, const char* /*name*/,
+             const UDataInfo* info) {
+    return
+        info->size >= sizeof(UDataInfo) &&
+        info->isBigEndian == U_IS_BIG_ENDIAN &&
+        info->charsetFamily == U_CHARSET_FAMILY &&
+        info->dataFormat[0] == PNAME_SIG_0 &&
+        info->dataFormat[1] == PNAME_SIG_1 &&
+        info->dataFormat[2] == PNAME_SIG_2 &&
+        info->dataFormat[3] == PNAME_SIG_3 &&
+        info->formatVersion[0] == PNAME_FORMAT_VERSION;
+}
+
+static UBool U_CALLCONV pname_cleanup(void) {
+    if (UDATA) {
+        udata_close(UDATA);
+        UDATA = NULL;
+    }
+    PNAME = NULL;
+    return TRUE;
+}
+U_CDECL_END
+
+/**
+ * Load the property names data.  Caller should check that data is
+ * not loaded BEFORE calling this function.  Returns TRUE if the load
+ * succeeds.
+ */
+static UBool _load() {
+    UErrorCode ec = U_ZERO_ERROR;
+    UDataMemory* data =
+        udata_openChoice(0, PNAME_DATA_TYPE, PNAME_DATA_NAME,
+                         isPNameAcceptable, 0, &ec);
+    if (U_SUCCESS(ec)) {
+        umtx_lock(NULL);
+        if (UDATA == NULL) {
+            UDATA = data;
+            PNAME = (const PropertyAliases*) udata_getMemory(UDATA);
+            ucln_common_registerCleanup(UCLN_COMMON_PNAME, pname_cleanup);
+            data = NULL;
+        }
+        umtx_unlock(NULL);
+    }
+    if (data) {
+        udata_close(data);
+    }
+    return PNAME!=NULL;
+}
+
+/**
+ * Inline function that expands to code that does a lazy load of the
+ * property names data.  If the data is already loaded, avoids an
+ * unnecessary function call.  If the data is not loaded, call _load()
+ * to load it, and return TRUE if the load succeeds.
+ */
+static inline UBool load() {
+    UBool f;
+    UMTX_CHECK(NULL, (PNAME!=NULL), f);
+    return f || _load();
+}
+
+//----------------------------------------------------------------------
+// Public API implementation
+
+// The C API is just a thin wrapper.  Each function obtains a pointer
+// to the singleton PropertyAliases, and calls the appropriate method
+// on it.  If it cannot obtain a pointer, because valid data is not
+// available, then it returns NULL or UCHAR_INVALID_CODE.
+
+U_CAPI const char* U_EXPORT2
+u_getPropertyName(UProperty property,
+                  UPropertyNameChoice nameChoice) {
+    return load() ? PNAME->getPropertyName(property, nameChoice)
+                  : NULL;
+}
+
+U_CAPI UProperty U_EXPORT2
+u_getPropertyEnum(const char* alias) {
+    UProperty p = load() ? (UProperty) PNAME->getPropertyEnum(alias)
+                         : UCHAR_INVALID_CODE;
+    return p;
+}
+
+U_CAPI const char* U_EXPORT2
+u_getPropertyValueName(UProperty property,
+                       int32_t value,
+                       UPropertyNameChoice nameChoice) {
+    return load() ? PNAME->getPropertyValueName(property, value, nameChoice)
+                  : NULL;
+}
+
+U_CAPI int32_t U_EXPORT2
+u_getPropertyValueEnum(UProperty property,
+                       const char* alias) {
+    return load() ? PNAME->getPropertyValueEnum(property, alias)
+                  : (int32_t)UCHAR_INVALID_CODE;
+}
+
+/* data swapping ------------------------------------------------------------ */
+
+/*
+ * Sub-structure-swappers use the temp array (which is as large as the
+ * actual data) for intermediate storage,
+ * as well as to indicate if a particular structure has been swapped already.
+ * The temp array is initially reset to all 0.
+ * pos is the byte offset of the sub-structure in the inBytes/outBytes/temp arrays.
+ */
+
+int32_t
+EnumToOffset::swap(const UDataSwapper *ds,
+                   const uint8_t *inBytes, int32_t length, uint8_t *outBytes,
+                   uint8_t *temp, int32_t pos,
+                   UErrorCode *pErrorCode) {
+    const EnumToOffset *inMap;
+    EnumToOffset *outMap, *tempMap;
+    int32_t size;
+
+    tempMap=(EnumToOffset *)(temp+pos);
+    if(tempMap->enumStart!=0 || tempMap->enumLimit!=0) {
+        /* this map was swapped already */
+        size=tempMap->getSize();
+        return size;
+    }
+
+    inMap=(const EnumToOffset *)(inBytes+pos);
+    outMap=(EnumToOffset *)(outBytes+pos);
+
+    tempMap->enumStart=udata_readInt32(ds, inMap->enumStart);
+    tempMap->enumLimit=udata_readInt32(ds, inMap->enumLimit);
+    size=tempMap->getSize();
+
+    if(length>=0) {
+        if(length<(pos+size)) {
+            if(length<(int32_t)sizeof(PropertyAliases)) {
+                udata_printError(ds, "upname_swap(EnumToOffset): too few bytes (%d after header)\n"
+                                     "    for pnames.icu EnumToOffset{%d..%d} at %d\n",
+                                 length, tempMap->enumStart, tempMap->enumLimit, pos);
+                *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+                return 0;
+            }
+        }
+
+        /* swap enumStart and enumLimit */
+        ds->swapArray32(ds, inMap, 2*sizeof(EnumValue), outMap, pErrorCode);
+
+        /* swap _offsetArray[] */
+        ds->swapArray16(ds, inMap->getOffsetArray(), (tempMap->enumLimit-tempMap->enumStart)*sizeof(Offset),
+                           outMap->getOffsetArray(), pErrorCode);
+    }
+
+    return size;
+}
+
+int32_t
+NonContiguousEnumToOffset::swap(const UDataSwapper *ds,
+                   const uint8_t *inBytes, int32_t length, uint8_t *outBytes,
+                   uint8_t *temp, int32_t pos,
+                   UErrorCode *pErrorCode) {
+    const NonContiguousEnumToOffset *inMap;
+    NonContiguousEnumToOffset *outMap, *tempMap;
+    int32_t size;
+
+    tempMap=(NonContiguousEnumToOffset *)(temp+pos);
+    if(tempMap->count!=0) {
+        /* this map was swapped already */
+        size=tempMap->getSize();
+        return size;
+    }
+
+    inMap=(const NonContiguousEnumToOffset *)(inBytes+pos);
+    outMap=(NonContiguousEnumToOffset *)(outBytes+pos);
+
+    tempMap->count=udata_readInt32(ds, inMap->count);
+    size=tempMap->getSize();
+
+    if(length>=0) {
+        if(length<(pos+size)) {
+            if(length<(int32_t)sizeof(PropertyAliases)) {
+                udata_printError(ds, "upname_swap(NonContiguousEnumToOffset): too few bytes (%d after header)\n"
+                                     "    for pnames.icu NonContiguousEnumToOffset[%d] at %d\n",
+                                 length, tempMap->count, pos);
+                *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+                return 0;
+            }
+        }
+
+        /* swap count and _enumArray[] */
+        length=(1+tempMap->count)*sizeof(EnumValue);
+        ds->swapArray32(ds, inMap, length,
+                           outMap, pErrorCode);
+
+        /* swap _offsetArray[] */
+        pos+=length;
+        ds->swapArray16(ds, inBytes+pos, tempMap->count*sizeof(Offset),
+                           outBytes+pos, pErrorCode);
+    }
+
+    return size;
+}
+
+struct NameAndIndex {
+    Offset name, index;
+};
+
+U_CDECL_BEGIN
+typedef int32_t U_CALLCONV PropNameCompareFn(const char *name1, const char *name2);
+
+struct CompareContext {
+    const char *chars;
+    PropNameCompareFn *propCompare;
+};
+
+static int32_t U_CALLCONV
+upname_compareRows(const void *context, const void *left, const void *right) {
+    CompareContext *cmp=(CompareContext *)context;
+    return cmp->propCompare(cmp->chars+((const NameAndIndex *)left)->name,
+                            cmp->chars+((const NameAndIndex *)right)->name);
+}
+U_CDECL_END
+
+int32_t
+NameToEnum::swap(const UDataSwapper *ds,
+                   const uint8_t *inBytes, int32_t length, uint8_t *outBytes,
+                   uint8_t *temp, int32_t pos,
+                   UErrorCode *pErrorCode) {
+    const NameToEnum *inMap;
+    NameToEnum *outMap, *tempMap;
+
+    const EnumValue *inEnumArray;
+    EnumValue *outEnumArray;
+
+    const Offset *inNameArray;
+    Offset *outNameArray;
+
+    NameAndIndex *sortArray;
+    CompareContext cmp;
+
+    int32_t i, size, oldIndex;
+
+    tempMap=(NameToEnum *)(temp+pos);
+    if(tempMap->count!=0) {
+        /* this map was swapped already */
+        size=tempMap->getSize();
+        return size;
+    }
+
+    inMap=(const NameToEnum *)(inBytes+pos);
+    outMap=(NameToEnum *)(outBytes+pos);
+
+    tempMap->count=udata_readInt32(ds, inMap->count);
+    size=tempMap->getSize();
+
+    if(length>=0) {
+        if(length<(pos+size)) {
+            if(length<(int32_t)sizeof(PropertyAliases)) {
+                udata_printError(ds, "upname_swap(NameToEnum): too few bytes (%d after header)\n"
+                                     "    for pnames.icu NameToEnum[%d] at %d\n",
+                                 length, tempMap->count, pos);
+                *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+                return 0;
+            }
+        }
+
+        /* swap count */
+        ds->swapArray32(ds, inMap, 4, outMap, pErrorCode);
+
+        inEnumArray=inMap->getEnumArray();
+        outEnumArray=outMap->getEnumArray();
+
+        inNameArray=(const Offset *)(inEnumArray+tempMap->count);
+        outNameArray=(Offset *)(outEnumArray+tempMap->count);
+
+        if(ds->inCharset==ds->outCharset) {
+            /* no need to sort, just swap the enum/name arrays */
+            ds->swapArray32(ds, inEnumArray, tempMap->count*4, outEnumArray, pErrorCode);
+            ds->swapArray16(ds, inNameArray, tempMap->count*2, outNameArray, pErrorCode);
+            return size;
+        }
+
+        /*
+         * The name and enum arrays are sorted by names and must be resorted
+         * if inCharset!=outCharset.
+         * We use the corresponding part of the temp array to sort an array
+         * of pairs of name offsets and sorting indexes.
+         * Then the sorting indexes are used to permutate-swap the name and enum arrays.
+         *
+         * The outBytes must already contain the swapped strings.
+         */
+        sortArray=(NameAndIndex *)tempMap->getEnumArray();
+        for(i=0; i<tempMap->count; ++i) {
+            sortArray[i].name=udata_readInt16(ds, inNameArray[i]);
+            sortArray[i].index=(Offset)i;
+        }
+
+        /*
+         * use a stable sort to avoid shuffling of equal strings,
+         * which makes testing harder
+         */
+        cmp.chars=(const char *)outBytes;
+        if (ds->outCharset==U_ASCII_FAMILY) {
+            cmp.propCompare=uprv_compareASCIIPropertyNames;
+        }
+        else {
+            cmp.propCompare=uprv_compareEBCDICPropertyNames;
+        }
+        uprv_sortArray(sortArray, tempMap->count, sizeof(NameAndIndex),
+                       upname_compareRows, &cmp,
+                       TRUE, pErrorCode);
+        if(U_FAILURE(*pErrorCode)) {
+            udata_printError(ds, "upname_swap(NameToEnum).uprv_sortArray(%d items) failed\n",
+                             tempMap->count);
+            return 0;
+        }
+
+        /* copy/swap/permutate _enumArray[] and _nameArray[] */
+        if(inEnumArray!=outEnumArray) {
+            for(i=0; i<tempMap->count; ++i) {
+                oldIndex=sortArray[i].index;
+                ds->swapArray32(ds, inEnumArray+oldIndex, 4, outEnumArray+i, pErrorCode);
+                ds->swapArray16(ds, inNameArray+oldIndex, 2, outNameArray+i, pErrorCode);
+            }
+        } else {
+            /*
+             * in-place swapping: need to permutate into a temporary array
+             * and then copy back to not destroy the data
+             */
+            EnumValue *tempEnumArray;
+            Offset *oldIndexes;
+
+            /* write name offsets directly from sortArray */
+            for(i=0; i<tempMap->count; ++i) {
+                ds->writeUInt16((uint16_t *)outNameArray+i, (uint16_t)sortArray[i].name);
+            }
+
+            /*
+             * compress the oldIndexes into a separate array to make space for tempEnumArray
+             * the tempMap _nameArray becomes oldIndexes[], getting the index
+             *   values from the 2D sortArray[],
+             * while sortArray=tempMap _enumArray[] becomes tempEnumArray[]
+             * this saves us allocating more memory
+             *
+             * it works because sizeof(NameAndIndex)<=sizeof(EnumValue)
+             * and because the nameArray[] can be used for oldIndexes[]
+             */
+            tempEnumArray=(EnumValue *)sortArray;
+            oldIndexes=(Offset *)(sortArray+tempMap->count);
+
+            /* copy sortArray[].index values into oldIndexes[] */
+            for(i=0; i<tempMap->count; ++i) {
+                oldIndexes[i]=sortArray[i].index;
+            }
+
+            /* permutate inEnumArray[] into tempEnumArray[] */
+            for(i=0; i<tempMap->count; ++i) {
+                ds->swapArray32(ds, inEnumArray+oldIndexes[i], 4, tempEnumArray+i, pErrorCode);
+            }
+
+            /* copy tempEnumArray[] to outEnumArray[] */
+            uprv_memcpy(outEnumArray, tempEnumArray, tempMap->count*4);
+        }
+    }
+
+    return size;
+}
+
+int32_t
+PropertyAliases::swap(const UDataSwapper *ds,
+                      const uint8_t *inBytes, int32_t length, uint8_t *outBytes,
+                      UErrorCode *pErrorCode) {
+    const PropertyAliases *inAliases;
+    PropertyAliases *outAliases;
+    PropertyAliases aliases;
+
+    const ValueMap *inValueMaps;
+    ValueMap *outValueMaps;
+    ValueMap valueMap;
+
+    int32_t i;
+
+    inAliases=(const PropertyAliases *)inBytes;
+    outAliases=(PropertyAliases *)outBytes;
+
+    /* read the input PropertyAliases - all 16-bit values */
+    for(i=0; i<(int32_t)sizeof(PropertyAliases)/2; ++i) {
+        ((uint16_t *)&aliases)[i]=ds->readUInt16(((const uint16_t *)inBytes)[i]);
+    }
+
+    if(length>=0) {
+        if(length<aliases.total_size) {
+            udata_printError(ds, "upname_swap(): too few bytes (%d after header) for all of pnames.icu\n",
+                             length);
+            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+            return 0;
+        }
+
+        /* copy the data for inaccessible bytes */
+        if(inBytes!=outBytes) {
+            uprv_memcpy(outBytes, inBytes, aliases.total_size);
+        }
+
+        /* swap the PropertyAliases class fields */
+        ds->swapArray16(ds, inAliases, sizeof(PropertyAliases), outAliases, pErrorCode);
+
+        /* swap the name groups */
+        ds->swapArray16(ds, inBytes+aliases.nameGroupPool_offset,
+                                aliases.stringPool_offset-aliases.nameGroupPool_offset,
+                           outBytes+aliases.nameGroupPool_offset, pErrorCode);
+
+        /* swap the strings */
+        udata_swapInvStringBlock(ds, inBytes+aliases.stringPool_offset,
+                                        aliases.total_size-aliases.stringPool_offset,
+                                    outBytes+aliases.stringPool_offset, pErrorCode);
+
+        /*
+         * alloc uint8_t temp[total_size] and reset it
+         * swap each top-level struct, put at least the count fields into temp
+         *   use subclass-specific swap() functions
+         * enumerate value maps, for each
+         *   if temp does not have count!=0 yet
+         *     read count, put it into temp
+         *     swap the array(s)
+         *     resort strings in name->enum maps
+         * swap value maps
+         */
+        LocalMemory<uint8_t> temp;
+        if(temp.allocateInsteadAndReset(aliases.total_size)==NULL) {
+            udata_printError(ds, "upname_swap(): unable to allocate temp memory (%d bytes)\n",
+                             aliases.total_size);
+            *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+
+        /* swap properties->name groups map */
+        NonContiguousEnumToOffset::swap(ds, inBytes, length, outBytes,
+                                        temp.getAlias(), aliases.enumToName_offset, pErrorCode);
+
+        /* swap name->properties map */
+        NameToEnum::swap(ds, inBytes, length, outBytes,
+                         temp.getAlias(), aliases.nameToEnum_offset, pErrorCode);
+
+        /* swap properties->value maps map */
+        NonContiguousEnumToOffset::swap(ds, inBytes, length, outBytes,
+                                        temp.getAlias(), aliases.enumToValue_offset, pErrorCode);
+
+        /* enumerate all ValueMaps and swap them */
+        inValueMaps=(const ValueMap *)(inBytes+aliases.valueMap_offset);
+        outValueMaps=(ValueMap *)(outBytes+aliases.valueMap_offset);
+
+        for(i=0; i<aliases.valueMap_count; ++i) {
+            valueMap.enumToName_offset=udata_readInt16(ds, inValueMaps[i].enumToName_offset);
+            valueMap.ncEnumToName_offset=udata_readInt16(ds, inValueMaps[i].ncEnumToName_offset);
+            valueMap.nameToEnum_offset=udata_readInt16(ds, inValueMaps[i].nameToEnum_offset);
+
+            if(valueMap.enumToName_offset!=0) {
+                EnumToOffset::swap(ds, inBytes, length, outBytes,
+                                   temp.getAlias(), valueMap.enumToName_offset,
+                                   pErrorCode);
+            } else if(valueMap.ncEnumToName_offset!=0) {
+                NonContiguousEnumToOffset::swap(ds, inBytes, length, outBytes,
+                                                temp.getAlias(), valueMap.ncEnumToName_offset,
+                                                pErrorCode);
+            }
+            if(valueMap.nameToEnum_offset!=0) {
+                NameToEnum::swap(ds, inBytes, length, outBytes,
+                                 temp.getAlias(), valueMap.nameToEnum_offset,
+                                 pErrorCode);
+            }
+        }
+
+        /* swap the ValueMaps array itself */
+        ds->swapArray16(ds, inValueMaps, aliases.valueMap_count*sizeof(ValueMap),
+                           outValueMaps, pErrorCode);
+
+        /* name groups and strings were swapped above */
+    }
+
+    return aliases.total_size;
+}
+
+U_CAPI int32_t U_EXPORT2
+upname_swap(const UDataSwapper *ds,
+            const void *inData, int32_t length, void *outData,
+            UErrorCode *pErrorCode) {
+    const UDataInfo *pInfo;
+    int32_t headerSize;
+
+    const uint8_t *inBytes;
+    uint8_t *outBytes;
+
+    /* udata_swapDataHeader checks the arguments */
+    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    /* check data format and format version */
+    pInfo=(const UDataInfo *)((const char *)inData+4);
+    if(!(
+        pInfo->dataFormat[0]==0x70 &&   /* dataFormat="pnam" */
+        pInfo->dataFormat[1]==0x6e &&
+        pInfo->dataFormat[2]==0x61 &&
+        pInfo->dataFormat[3]==0x6d &&
+        pInfo->formatVersion[0]==1
+    )) {
+        udata_printError(ds, "upname_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as pnames.icu\n",
+                         pInfo->dataFormat[0], pInfo->dataFormat[1],
+                         pInfo->dataFormat[2], pInfo->dataFormat[3],
+                         pInfo->formatVersion[0]);
+        *pErrorCode=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    inBytes=(const uint8_t *)inData+headerSize;
+    outBytes=(uint8_t *)outData+headerSize;
+
+    if(length>=0) {
+        length-=headerSize;
+        if(length<(int32_t)sizeof(PropertyAliases)) {
+            udata_printError(ds, "upname_swap(): too few bytes (%d after header) for pnames.icu\n",
+                             length);
+            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+            return 0;
+        }
+    }
+
+    return headerSize+PropertyAliases::swap(ds, inBytes, length, outBytes, pErrorCode);
+}
+
+//eof
diff --git a/source/common/propname.h b/source/common/propname.h
new file mode 100644
index 0000000..a3a7718
--- /dev/null
+++ b/source/common/propname.h
@@ -0,0 +1,515 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2004, International Business Machines
+* Corporation and others.  All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: October 30 2002
+* Since: ICU 2.4
+**********************************************************************
+*/
+#ifndef PROPNAME_H
+#define PROPNAME_H
+
+#include "unicode/utypes.h"
+#include "unicode/uchar.h"
+#include "udataswp.h"
+#include "uprops.h"
+
+/*
+ * This header defines the in-memory layout of the property names data
+ * structure representing the UCD data files PropertyAliases.txt and
+ * PropertyValueAliases.txt.  It is used by:
+ *   propname.cpp - reads data
+ *   genpname     - creates data
+ */
+
+/* low-level char * property name comparison -------------------------------- */
+
+U_CDECL_BEGIN
+
+/**
+ * \var uprv_comparePropertyNames
+ * Unicode property names and property value names are compared "loosely".
+ *
+ * UCD.html 4.0.1 says:
+ *   For all property names, property value names, and for property values for
+ *   Enumerated, Binary, or Catalog properties, use the following
+ *   loose matching rule:
+ *
+ *   LM3. Ignore case, whitespace, underscore ('_'), and hyphens.
+ *
+ * This function does just that, for (char *) name strings.
+ * It is almost identical to ucnv_compareNames() but also ignores
+ * C0 White_Space characters (U+0009..U+000d, and U+0085 on EBCDIC).
+ *
+ * @internal
+ */
+
+U_CAPI int32_t U_EXPORT2
+uprv_compareASCIIPropertyNames(const char *name1, const char *name2);
+
+U_CAPI int32_t U_EXPORT2
+uprv_compareEBCDICPropertyNames(const char *name1, const char *name2);
+
+#if U_CHARSET_FAMILY==U_ASCII_FAMILY
+#   define uprv_comparePropertyNames uprv_compareASCIIPropertyNames
+#elif U_CHARSET_FAMILY==U_EBCDIC_FAMILY
+#   define uprv_comparePropertyNames uprv_compareEBCDICPropertyNames
+#else
+#   error U_CHARSET_FAMILY is not valid
+#endif
+
+U_CDECL_END
+
+/* UDataMemory structure and signatures ------------------------------------- */
+
+#define PNAME_DATA_NAME "pnames"
+#define PNAME_DATA_TYPE "icu"
+
+/* Fields in UDataInfo: */
+
+/* PNAME_SIG[] is encoded as numeric literals for compatibility with the HP compiler */
+#define PNAME_SIG_0 ((uint8_t)0x70) /* p */
+#define PNAME_SIG_1 ((uint8_t)0x6E) /* n */
+#define PNAME_SIG_2 ((uint8_t)0x61) /* a */
+#define PNAME_SIG_3 ((uint8_t)0x6D) /* m */
+
+#define PNAME_FORMAT_VERSION ((int8_t)1) /* formatVersion[0] */
+
+/**
+ * Swap pnames.icu. See udataswp.h.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+upname_swap(const UDataSwapper *ds,
+            const void *inData, int32_t length, void *outData,
+            UErrorCode *pErrorCode);
+
+
+#ifdef XP_CPLUSPLUS
+
+class Builder;
+
+U_NAMESPACE_BEGIN
+
+/**
+ * An offset from the start of the pnames data to a contained entity.
+ * This must be a signed value, since negative offsets are used as an
+ * end-of-list marker.  Offsets to actual objects are non-zero.  A
+ * zero offset indicates an absent entry; this corresponds to aliases
+ * marked "n/a" in the original Unicode data files.
+ */
+typedef int16_t Offset; /*  must be signed */
+
+#define MAX_OFFSET 0x7FFF
+
+/**
+ * A generic value for a property or property value.  Typically an
+ * enum from uchar.h, but sometimes a non-enum value.  It must be
+ * large enough to accomodate the largest enum value, which as of this
+ * writing is the largest general category mask.  Need not be signed
+ * but may be.  Typically it doesn't matter, since the caller will
+ * cast it to the proper type before use.  Takes the special value
+ * UCHAR_INVALID_CODE for invalid input.
+ */
+typedef int32_t EnumValue;
+
+/* ---------------------------------------------------------------------- */
+/*  ValueMap */
+
+/**
+ * For any top-level property that has named values (binary and
+ * enumerated properties), there is a ValueMap object.  This object
+ * maps from enum values to two other maps.  One goes from value enums
+ * to value names.  The other goes from value names to value enums.
+ * 
+ * The value enum values may be contiguous or disjoint.  If they are
+ * contiguous then the enumToName_offset is nonzero, and the
+ * ncEnumToName_offset is zero.  Vice versa if the value enums are
+ * disjoint.
+ *
+ * There are n of these objects, where n is the number of binary
+ * properties + the number of enumerated properties.
+ */
+struct ValueMap {
+
+    /*  -- begin pnames data -- */
+    /*  Enum=>name EnumToOffset / NonContiguousEnumToOffset objects. */
+    /*  Exactly one of these will be nonzero. */
+    Offset enumToName_offset;
+    Offset ncEnumToName_offset;
+
+    Offset nameToEnum_offset; /*  Name=>enum data */
+    /*  -- end pnames data -- */
+};
+
+/* ---------------------------------------------------------------------- */
+/*  PropertyAliases class */
+
+/**
+ * A class encapsulating access to the memory-mapped data representing
+ * property aliases and property value aliases (pnames).  The class
+ * MUST have no v-table and declares certain methods inline -- small
+ * methods and methods that are called from only one point.
+ *
+ * The data members in this class correspond to the in-memory layout
+ * of the header of the pnames data.
+ */
+class PropertyAliases {
+
+    /*  -- begin pnames data -- */
+    /*  Enum=>name EnumToOffset object for binary and enumerated */
+    /*  properties */
+    Offset enumToName_offset;
+
+    /*  Name=>enum data for binary & enumerated properties */
+    Offset nameToEnum_offset;
+
+    /*  Enum=>offset EnumToOffset object mapping enumerated properties */
+    /*  to ValueMap objects */
+    Offset enumToValue_offset;
+
+    /*  The following are needed by external readers of this data. */
+    /*  We don't use them ourselves. */
+    int16_t total_size; /*  size in bytes excluding the udata header */
+    Offset valueMap_offset; /*  offset to start of array */
+    int16_t valueMap_count; /*  number of entries */
+    Offset nameGroupPool_offset; /*  offset to start of array */
+    int16_t nameGroupPool_count; /*  number of entries (not groups) */
+    Offset stringPool_offset; /*  offset to start of pool */
+    int16_t stringPool_count; /*  number of strings (not size in bytes) */
+
+    /*  -- end pnames data -- */
+
+    friend class ::Builder;
+
+    const ValueMap* getValueMap(EnumValue prop) const;
+
+    const char* chooseNameInGroup(Offset offset,
+                                  UPropertyNameChoice choice) const;
+
+ public:
+
+    inline const int8_t* getPointer(Offset o) const {
+        return ((const int8_t*) this) + o;
+    }
+
+    inline const int8_t* getPointerNull(Offset o) const {
+        return o ? getPointer(o) : NULL;
+    }
+
+    inline const char* getPropertyName(EnumValue prop,
+                                       UPropertyNameChoice choice) const;
+    
+    inline EnumValue getPropertyEnum(const char* alias) const;
+
+    inline const char* getPropertyValueName(EnumValue prop, EnumValue value,
+                                            UPropertyNameChoice choice) const;
+    
+    inline EnumValue getPropertyValueEnum(EnumValue prop,
+                                          const char* alias) const;
+
+    static int32_t
+    swap(const UDataSwapper *ds,
+         const uint8_t *inBytes, int32_t length, uint8_t *outBytes,
+         UErrorCode *pErrorCode);
+};
+
+/* ---------------------------------------------------------------------- */
+/*  EnumToOffset */
+
+/**
+ * A generic map from enum values to Offsets.  The enum values must be
+ * contiguous, from enumStart to enumLimit.  The Offset values may
+ * point to anything.
+ */
+class EnumToOffset {
+
+    /*  -- begin pnames data -- */
+    EnumValue enumStart;
+    EnumValue enumLimit;
+    Offset _offsetArray; /*  [array of enumLimit-enumStart] */
+    /*  -- end pnames data -- */
+
+    friend class ::Builder;
+
+    Offset* getOffsetArray() {
+        return &_offsetArray;
+    }
+
+    const Offset* getOffsetArray() const {
+        return &_offsetArray;
+    }
+
+    static int32_t getSize(int32_t n) {
+        return sizeof(EnumToOffset) + sizeof(Offset) * (n - 1);
+    }
+
+    int32_t getSize() {
+        return getSize(enumLimit - enumStart);
+    }
+
+ public:
+
+    Offset getOffset(EnumValue enumProbe) const {
+        if (enumProbe < enumStart ||
+            enumProbe >= enumLimit) {
+            return 0; /*  not found */
+        }
+        const Offset* p = getOffsetArray();
+        return p[enumProbe - enumStart];
+    }
+
+    static int32_t
+    swap(const UDataSwapper *ds,
+         const uint8_t *inBytes, int32_t length, uint8_t *outBytes,
+         uint8_t *temp, int32_t pos,
+         UErrorCode *pErrorCode);
+};
+
+/* ---------------------------------------------------------------------- */
+/*  NonContiguousEnumToOffset */
+
+/**
+ * A generic map from enum values to Offsets.  The enum values may be
+ * disjoint.  If they are contiguous, an EnumToOffset should be used
+ * instead.  The Offset values may point to anything.
+ */
+class NonContiguousEnumToOffset {
+
+    /*  -- begin pnames data -- */
+    int32_t count;
+    EnumValue _enumArray; /*  [array of count] */
+    /*  Offset _offsetArray; // [array of count] after enumValue[count-1] */
+    /*  -- end pnames data -- */
+
+    friend class ::Builder;
+
+    EnumValue* getEnumArray() {
+        return &_enumArray;
+    }
+
+    const EnumValue* getEnumArray() const {
+        return &_enumArray;
+    }
+    
+    Offset* getOffsetArray() {
+        return (Offset*) (getEnumArray() + count);
+    }
+
+    const Offset* getOffsetArray() const {
+        return (Offset*) (getEnumArray() + count);
+    }
+
+    static int32_t getSize(int32_t n) {
+        return sizeof(int32_t) + (sizeof(EnumValue) + sizeof(Offset)) * n;
+    }
+
+    int32_t getSize() {
+        return getSize(count);
+    }
+
+ public:
+
+    Offset getOffset(EnumValue enumProbe) const {
+        const EnumValue* e = getEnumArray();
+        const Offset* p = getOffsetArray();
+        /*  linear search; binary later if warranted */
+        /*  (binary is not faster for short lists) */
+        for (int32_t i=0; i<count; ++i) {
+            if (e[i] < enumProbe) continue;
+            if (e[i] > enumProbe) break;
+            return p[i];
+        }
+        return 0; /*  not found */
+    }
+
+    static int32_t
+    swap(const UDataSwapper *ds,
+         const uint8_t *inBytes, int32_t length, uint8_t *outBytes,
+         uint8_t *temp, int32_t pos,
+         UErrorCode *pErrorCode);
+};
+
+/* ---------------------------------------------------------------------- */
+/*  NameToEnum */
+
+/**
+ * A map from names to enum values.
+ */
+class NameToEnum {
+
+    /*  -- begin pnames data -- */
+    int32_t count;       /*  number of entries */
+    EnumValue _enumArray; /*  [array of count] EnumValues */
+    /*  Offset _nameArray; // [array of count] offsets to names */
+    /*  -- end pnames data -- */
+
+    friend class ::Builder;
+
+    EnumValue* getEnumArray() {
+        return &_enumArray;
+    }
+
+    const EnumValue* getEnumArray() const {
+        return &_enumArray;
+    }
+
+    Offset* getNameArray() {
+        return (Offset*) (getEnumArray() + count);
+    }
+
+    const Offset* getNameArray() const {
+        return (Offset*) (getEnumArray() + count);
+    }
+
+    static int32_t getSize(int32_t n) {
+        return sizeof(int32_t) + (sizeof(Offset) + sizeof(EnumValue)) * n;
+    }
+
+    int32_t getSize() {
+        return getSize(count);
+    }
+
+ public:
+  
+    EnumValue getEnum(const char* alias, const PropertyAliases& data) const {
+
+        const Offset* n = getNameArray();
+        const EnumValue* e = getEnumArray();
+
+        /*  linear search; binary later if warranted */
+        /*  (binary is not faster for short lists) */
+        for (int32_t i=0; i<count; ++i) {
+            const char* name = (const char*) data.getPointer(n[i]);
+            int32_t c = uprv_comparePropertyNames(alias, name);
+            if (c > 0) continue;
+            if (c < 0) break;
+            return e[i];
+        }
+        
+        return UCHAR_INVALID_CODE;
+    }
+
+    static int32_t
+    swap(const UDataSwapper *ds,
+         const uint8_t *inBytes, int32_t length, uint8_t *outBytes,
+         uint8_t *temp, int32_t pos,
+         UErrorCode *pErrorCode);
+};
+
+/*----------------------------------------------------------------------
+ * 
+ * In-memory layout.  THIS IS NOT A STANDALONE DOCUMENT.  It goes
+ * together with above C++ declarations and gives an overview.
+ *
+ * See above for definitions of Offset and EnumValue.  Also, refer to
+ * above class declarations for the "bottom line" on data layout.
+ *
+ * Sizes:
+ * '*_offset' is an Offset (see above)
+ * 'count' members are typically int32_t (see above declarations)
+ * 'enumArray' is an array of EnumValue (see above)
+ * 'offsetArray' is an array of Offset (see above)
+ * 'nameArray' is an array of Offset (see above)
+ * 'enum*' is an EnumValue (see above)
+ * '*Array [x n]' means that *Array has n elements
+ *
+ * References:
+ * Instead of pointers, this flat data structure contains offsets.
+ * All offsets are relative to the start of 'header'.  A notation
+ * is used to indicate what structure each offset points to:
+ * 'foo (>x)' the offset(s) in foo point to structure x
+ * 
+ * Structures:
+ * Each structure is assigned a number, except for the header,
+ * which is called 'header'.  The numbers are not contiguous
+ * for historical reasons.  Some structures have sub-parts
+ * that are denoted with a letter, e.g., "5a".
+ * 
+ * BEGIN LAYOUT
+ * ============
+ * header:
+ *  enumToName_offset (>0)
+ *  nameToEnum_offset (>2)
+ *  enumToValue_offset (>3)
+ *  (alignment padding build in to header)
+ *
+ * The header also contains the following, used by "external readers"
+ * like ICU4J and icuswap.
+ *
+ *  // The following are needed by external readers of this data.
+ *  // We don't use them ourselves.
+ *  int16_t total_size; // size in bytes excluding the udata header
+ *  Offset valueMap_offset; // offset to start of array
+ *  int16_t valueMap_count; // number of entries
+ *  Offset nameGroupPool_offset; // offset to start of array
+ *  int16_t nameGroupPool_count; // number of entries (not groups)
+ *  Offset stringPool_offset; // offset to start of pool
+ *  int16_t stringPool_count; // number of strings (not size in bytes)
+ *
+ * 0: # NonContiguousEnumToOffset obj for props => name groups
+ *  count
+ *  enumArray [x count]
+ *  offsetArray [x count] (>98)
+ * 
+ * => pad to next 4-byte boundary
+ * 
+ * (1: omitted -- no longer used)
+ * 
+ * 2: # NameToEnum obj for binary & enumerated props
+ *  count
+ *  enumArray [x count]
+ *  nameArray [x count] (>99)
+ * 
+ * => pad to next 4-byte boundary
+ * 
+ * 3: # NonContiguousEnumToOffset obj for enumerated props => ValueMaps
+ *  count
+ *  enumArray [x count]
+ *  offsetArray [x count] (>4)
+ * 
+ * => pad to next 4-byte boundary
+ * 
+ * 4: # ValueMap array [x one for each enumerated prop i]
+ *  enumToName_offset (>5a +2*i)   one of these two is NULL, one is not
+ *  ncEnumToName_offset (>5b +2*i)
+ *  nameToEnums_offset (>6 +2*i)
+ * 
+ * => pad to next 4-byte boundary
+ * 
+ * for each enumerated prop (either 5a or 5b):
+ * 
+ *   5a: # EnumToOffset for enumerated prop's values => name groups
+ *    enumStart
+ *    enumLimit
+ *    offsetArray [x enumLimit - enumStart] (>98) 
+ * 
+ *   => pad to next 4-byte boundary
+ * 
+ *   5b: # NonContiguousEnumToOffset for enumerated prop's values => name groups
+ *    count
+ *    enumArray [x count]
+ *    offsetArray [x count] (>98)
+ * 
+ *   => pad to next 4-byte boundary
+ * 
+ *   6: # NameToEnum for enumerated prop's values
+ *    count
+ *    enumArray [x count]
+ *    nameArray [x count] (>99)
+ * 
+ *   => pad to next 4-byte boundary
+ * 
+ * 98: # name group pool {NGP}
+ *  [array of Offset values] (>99)
+ * 
+ * 99: # string pool {SP}
+ *  [pool of nul-terminated char* strings]
+ */
+U_NAMESPACE_END
+
+#endif /* C++ */
+
+#endif
diff --git a/source/common/propsvec.c b/source/common/propsvec.c
new file mode 100644
index 0000000..705e40f
--- /dev/null
+++ b/source/common/propsvec.c
@@ -0,0 +1,523 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2002-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  propsvec.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002feb22
+*   created by: Markus W. Scherer
+*
+*   Store bits (Unicode character properties) in bit set vectors.
+*/
+
+#include <stdlib.h>
+#include "unicode/utypes.h"
+#include "cmemory.h"
+#include "utrie.h"
+#include "utrie2.h"
+#include "uarrsort.h"
+#include "propsvec.h"
+
+struct UPropsVectors {
+    uint32_t *v;
+    int32_t columns;  /* number of columns, plus two for start & limit values */
+    int32_t maxRows;
+    int32_t rows;
+    int32_t prevRow;  /* search optimization: remember last row seen */
+    UBool isCompacted;
+};
+
+#define UPVEC_INITIAL_ROWS (1<<12)
+#define UPVEC_MEDIUM_ROWS ((int32_t)1<<16)
+#define UPVEC_MAX_ROWS (UPVEC_MAX_CP+1)
+
+U_CAPI UPropsVectors * U_EXPORT2
+upvec_open(int32_t columns, UErrorCode *pErrorCode) {
+    UPropsVectors *pv;
+    uint32_t *v, *row;
+    uint32_t cp;
+
+    if(U_FAILURE(*pErrorCode)) {
+        return NULL;
+    }
+    if(columns<1) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+    columns+=2; /* count range start and limit columns */
+
+    pv=(UPropsVectors *)uprv_malloc(sizeof(UPropsVectors));
+    v=(uint32_t *)uprv_malloc(UPVEC_INITIAL_ROWS*columns*4);
+    if(pv==NULL || v==NULL) {
+        uprv_free(pv);
+        uprv_free(v);
+        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    uprv_memset(pv, 0, sizeof(UPropsVectors));
+    pv->v=v;
+    pv->columns=columns;
+    pv->maxRows=UPVEC_INITIAL_ROWS;
+    pv->rows=2+(UPVEC_MAX_CP-UPVEC_FIRST_SPECIAL_CP);
+
+    /* set the all-Unicode row and the special-value rows */
+    row=pv->v;
+    uprv_memset(row, 0, pv->rows*columns*4);
+    row[0]=0;
+    row[1]=0x110000;
+    row+=columns;
+    for(cp=UPVEC_FIRST_SPECIAL_CP; cp<=UPVEC_MAX_CP; ++cp) {
+        row[0]=cp;
+        row[1]=cp+1;
+        row+=columns;
+    }
+    return pv;
+}
+
+U_CAPI void U_EXPORT2
+upvec_close(UPropsVectors *pv) {
+    if(pv!=NULL) {
+        uprv_free(pv->v);
+        uprv_free(pv);
+    }
+}
+
+static uint32_t *
+_findRow(UPropsVectors *pv, UChar32 rangeStart) {
+    uint32_t *row;
+    int32_t columns, i, start, limit, prevRow, rows;
+
+    columns=pv->columns;
+    rows=limit=pv->rows;
+    prevRow=pv->prevRow;
+
+    /* check the vicinity of the last-seen row (start searching with an unrolled loop) */
+    row=pv->v+prevRow*columns;
+    if(rangeStart>=(UChar32)row[0]) {
+        if(rangeStart<(UChar32)row[1]) {
+            /* same row as last seen */
+            return row;
+        } else if(rangeStart<(UChar32)(row+=columns)[1]) {
+            /* next row after the last one */
+            pv->prevRow=prevRow+1;
+            return row;
+        } else if(rangeStart<(UChar32)(row+=columns)[1]) {
+            /* second row after the last one */
+            pv->prevRow=prevRow+2;
+            return row;
+        } else if((rangeStart-(UChar32)row[1])<10) {
+            /* we are close, continue looping */
+            prevRow+=2;
+            do {
+                ++prevRow;
+                row+=columns;
+            } while(rangeStart>=(UChar32)row[1]);
+            pv->prevRow=prevRow;
+            return row;
+        }
+    } else if(rangeStart<(UChar32)pv->v[1]) {
+        /* the very first row */
+        pv->prevRow=0;
+        return pv->v;
+    }
+
+    /* do a binary search for the start of the range */
+    start=0;
+    while(start<limit-1) {
+        i=(start+limit)/2;
+        row=pv->v+i*columns;
+        if(rangeStart<(UChar32)row[0]) {
+            limit=i;
+        } else if(rangeStart<(UChar32)row[1]) {
+            pv->prevRow=i;
+            return row;
+        } else {
+            start=i;
+        }
+    }
+
+    /* must be found because all ranges together always cover all of Unicode */
+    pv->prevRow=start;
+    return pv->v+start*columns;
+}
+
+U_CAPI void U_EXPORT2
+upvec_setValue(UPropsVectors *pv,
+               UChar32 start, UChar32 end,
+               int32_t column,
+               uint32_t value, uint32_t mask,
+               UErrorCode *pErrorCode) {
+    uint32_t *firstRow, *lastRow;
+    int32_t columns;
+    UChar32 limit;
+    UBool splitFirstRow, splitLastRow;
+
+    /* argument checking */
+    if(U_FAILURE(*pErrorCode)) {
+        return;
+    }
+    if( pv==NULL ||
+        start<0 || start>end || end>UPVEC_MAX_CP ||
+        column<0 || column>=(pv->columns-2)
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    if(pv->isCompacted) {
+        *pErrorCode=U_NO_WRITE_PERMISSION;
+        return;
+    }
+    limit=end+1;
+
+    /* initialize */
+    columns=pv->columns;
+    column+=2; /* skip range start and limit columns */
+    value&=mask;
+
+    /* find the rows whose ranges overlap with the input range */
+
+    /* find the first and last rows, always successful */
+    firstRow=_findRow(pv, start);
+    lastRow=_findRow(pv, end);
+
+    /*
+     * Rows need to be split if they partially overlap with the
+     * input range (only possible for the first and last rows)
+     * and if their value differs from the input value.
+     */
+    splitFirstRow= (UBool)(start!=(UChar32)firstRow[0] && value!=(firstRow[column]&mask));
+    splitLastRow= (UBool)(limit!=(UChar32)lastRow[1] && value!=(lastRow[column]&mask));
+
+    /* split first/last rows if necessary */
+    if(splitFirstRow || splitLastRow) {
+        int32_t count, rows;
+
+        rows=pv->rows;
+        if((rows+splitFirstRow+splitLastRow)>pv->maxRows) {
+            uint32_t *newVectors;
+            int32_t newMaxRows;
+
+            if(pv->maxRows<UPVEC_MEDIUM_ROWS) {
+                newMaxRows=UPVEC_MEDIUM_ROWS;
+            } else if(pv->maxRows<UPVEC_MAX_ROWS) {
+                newMaxRows=UPVEC_MAX_ROWS;
+            } else {
+                /* Implementation bug, or UPVEC_MAX_ROWS too low. */
+                *pErrorCode=U_INTERNAL_PROGRAM_ERROR;
+                return;
+            }
+            newVectors=(uint32_t *)uprv_malloc(newMaxRows*columns*4);
+            if(newVectors==NULL) {
+                *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+                return;
+            }
+            uprv_memcpy(newVectors, pv->v, rows*columns*4);
+            firstRow=newVectors+(firstRow-pv->v);
+            lastRow=newVectors+(lastRow-pv->v);
+            uprv_free(pv->v);
+            pv->v=newVectors;
+            pv->maxRows=newMaxRows;
+        }
+
+        /* count the number of row cells to move after the last row, and move them */
+        count = (int32_t)((pv->v+rows*columns)-(lastRow+columns));
+        if(count>0) {
+            uprv_memmove(
+                lastRow+(1+splitFirstRow+splitLastRow)*columns,
+                lastRow+columns,
+                count*4);
+        }
+        pv->rows=rows+splitFirstRow+splitLastRow;
+
+        /* split the first row, and move the firstRow pointer to the second part */
+        if(splitFirstRow) {
+            /* copy all affected rows up one and move the lastRow pointer */
+            count = (int32_t)((lastRow-firstRow)+columns);
+            uprv_memmove(firstRow+columns, firstRow, count*4);
+            lastRow+=columns;
+
+            /* split the range and move the firstRow pointer */
+            firstRow[1]=firstRow[columns]=(uint32_t)start;
+            firstRow+=columns;
+        }
+
+        /* split the last row */
+        if(splitLastRow) {
+            /* copy the last row data */
+            uprv_memcpy(lastRow+columns, lastRow, columns*4);
+
+            /* split the range and move the firstRow pointer */
+            lastRow[1]=lastRow[columns]=(uint32_t)limit;
+        }
+    }
+
+    /* set the "row last seen" to the last row for the range */
+    pv->prevRow=(int32_t)((lastRow-(pv->v))/columns);
+
+    /* set the input value in all remaining rows */
+    firstRow+=column;
+    lastRow+=column;
+    mask=~mask;
+    for(;;) {
+        *firstRow=(*firstRow&mask)|value;
+        if(firstRow==lastRow) {
+            break;
+        }
+        firstRow+=columns;
+    }
+}
+
+U_CAPI uint32_t U_EXPORT2
+upvec_getValue(const UPropsVectors *pv, UChar32 c, int32_t column) {
+    uint32_t *row;
+    UPropsVectors *ncpv;
+
+    if(pv->isCompacted || c<0 || c>UPVEC_MAX_CP || column<0 || column>=(pv->columns-2)) {
+        return 0;
+    }
+    ncpv=(UPropsVectors *)pv;
+    row=_findRow(ncpv, c);
+    return row[2+column];
+}
+
+U_CAPI uint32_t * U_EXPORT2
+upvec_getRow(const UPropsVectors *pv, int32_t rowIndex,
+             UChar32 *pRangeStart, UChar32 *pRangeEnd) {
+    uint32_t *row;
+    int32_t columns;
+
+    if(pv->isCompacted || rowIndex<0 || rowIndex>=pv->rows) {
+        return NULL;
+    }
+
+    columns=pv->columns;
+    row=pv->v+rowIndex*columns;
+    if(pRangeStart!=NULL) {
+        *pRangeStart=(UChar32)row[0];
+    }
+    if(pRangeEnd!=NULL) {
+        *pRangeEnd=(UChar32)row[1]-1;
+    }
+    return row+2;
+}
+
+static int32_t U_CALLCONV
+upvec_compareRows(const void *context, const void *l, const void *r) {
+    const uint32_t *left=(const uint32_t *)l, *right=(const uint32_t *)r;
+    const UPropsVectors *pv=(const UPropsVectors *)context;
+    int32_t i, count, columns;
+
+    count=columns=pv->columns; /* includes start/limit columns */
+
+    /* start comparing after start/limit but wrap around to them */
+    i=2;
+    do {
+        if(left[i]!=right[i]) {
+            return left[i]<right[i] ? -1 : 1;
+        }
+        if(++i==columns) {
+            i=0;
+        }
+    } while(--count>0);
+
+    return 0;
+}
+
+U_CAPI void U_EXPORT2
+upvec_compact(UPropsVectors *pv, UPVecCompactHandler *handler, void *context, UErrorCode *pErrorCode) {
+    uint32_t *row;
+    int32_t i, columns, valueColumns, rows, count;
+    UChar32 start, limit;
+
+    /* argument checking */
+    if(U_FAILURE(*pErrorCode)) {
+        return;
+    }
+    if(handler==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    if(pv->isCompacted) {
+        return;
+    }
+
+    /* Set the flag now: Sorting and compacting destroys the builder data structure. */
+    pv->isCompacted=TRUE;
+
+    rows=pv->rows;
+    columns=pv->columns;
+    valueColumns=columns-2; /* not counting start & limit */
+
+    /* sort the properties vectors to find unique vector values */
+    uprv_sortArray(pv->v, rows, columns*4,
+                   upvec_compareRows, pv, FALSE, pErrorCode);
+    if(U_FAILURE(*pErrorCode)) {
+        return;
+    }
+
+    /*
+     * Find and set the special values.
+     * This has to do almost the same work as the compaction below,
+     * to find the indexes where the special-value rows will move.
+     */
+    row=pv->v;
+    count=-valueColumns;
+    for(i=0; i<rows; ++i) {
+        start=(UChar32)row[0];
+
+        /* count a new values vector if it is different from the current one */
+        if(count<0 || 0!=uprv_memcmp(row+2, row-valueColumns, valueColumns*4)) {
+            count+=valueColumns;
+        }
+
+        if(start>=UPVEC_FIRST_SPECIAL_CP) {
+            handler(context, start, start, count, row+2, valueColumns, pErrorCode);
+            if(U_FAILURE(*pErrorCode)) {
+                return;
+            }
+        }
+
+        row+=columns;
+    }
+
+    /* count is at the beginning of the last vector, add valueColumns to include that last vector */
+    count+=valueColumns;
+
+    /* Call the handler once more to signal the start of delivering real values. */
+    handler(context, UPVEC_START_REAL_VALUES_CP, UPVEC_START_REAL_VALUES_CP,
+            count, row-valueColumns, valueColumns, pErrorCode);
+    if(U_FAILURE(*pErrorCode)) {
+        return;
+    }
+
+    /*
+     * Move vector contents up to a contiguous array with only unique
+     * vector values, and call the handler function for each vector.
+     *
+     * This destroys the Properties Vector structure and replaces it
+     * with an array of just vector values.
+     */
+    row=pv->v;
+    count=-valueColumns;
+    for(i=0; i<rows; ++i) {
+        /* fetch these first before memmove() may overwrite them */
+        start=(UChar32)row[0];
+        limit=(UChar32)row[1];
+
+        /* add a new values vector if it is different from the current one */
+        if(count<0 || 0!=uprv_memcmp(row+2, pv->v+count, valueColumns*4)) {
+            count+=valueColumns;
+            uprv_memmove(pv->v+count, row+2, valueColumns*4);
+        }
+
+        if(start<UPVEC_FIRST_SPECIAL_CP) {
+            handler(context, start, limit-1, count, pv->v+count, valueColumns, pErrorCode);
+            if(U_FAILURE(*pErrorCode)) {
+                return;
+            }
+        }
+
+        row+=columns;
+    }
+
+    /* count is at the beginning of the last vector, add one to include that last vector */
+    pv->rows=count/valueColumns+1;
+}
+
+U_CAPI const uint32_t * U_EXPORT2
+upvec_getArray(const UPropsVectors *pv, int32_t *pRows, int32_t *pColumns) {
+    if(!pv->isCompacted) {
+        return NULL;
+    }
+    if(pRows!=NULL) {
+        *pRows=pv->rows;
+    }
+    if(pColumns!=NULL) {
+        *pColumns=pv->columns-2;
+    }
+    return pv->v;
+}
+
+U_CAPI uint32_t * U_EXPORT2
+upvec_cloneArray(const UPropsVectors *pv,
+                 int32_t *pRows, int32_t *pColumns, UErrorCode *pErrorCode) {
+    uint32_t *clonedArray;
+    int32_t byteLength;
+
+    if(U_FAILURE(*pErrorCode)) {
+        return NULL;
+    }
+    if(!pv->isCompacted) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+    byteLength=pv->rows*(pv->columns-2)*4;
+    clonedArray=(uint32_t *)uprv_malloc(byteLength);
+    if(clonedArray==NULL) {
+        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    uprv_memcpy(clonedArray, pv->v, byteLength);
+    if(pRows!=NULL) {
+        *pRows=pv->rows;
+    }
+    if(pColumns!=NULL) {
+        *pColumns=pv->columns-2;
+    }
+    return clonedArray;
+}
+
+U_CAPI UTrie2 * U_EXPORT2
+upvec_compactToUTrie2WithRowIndexes(UPropsVectors *pv, UErrorCode *pErrorCode) {
+    UPVecToUTrie2Context toUTrie2={ NULL };
+    upvec_compact(pv, upvec_compactToUTrie2Handler, &toUTrie2, pErrorCode);
+    utrie2_freeze(toUTrie2.trie, UTRIE2_16_VALUE_BITS, pErrorCode);
+    if(U_FAILURE(*pErrorCode)) {
+        utrie2_close(toUTrie2.trie);
+        toUTrie2.trie=NULL;
+    }
+    return toUTrie2.trie;
+}
+
+/*
+ * TODO(markus): Add upvec_16BitsToUTrie2() function that enumerates all rows, extracts
+ * some 16-bit field and builds and returns a UTrie2.
+ */
+
+U_CAPI void U_CALLCONV
+upvec_compactToUTrie2Handler(void *context,
+                             UChar32 start, UChar32 end,
+                             int32_t rowIndex, uint32_t *row, int32_t columns,
+                             UErrorCode *pErrorCode) {
+    UPVecToUTrie2Context *toUTrie2=(UPVecToUTrie2Context *)context;
+    if(start<UPVEC_FIRST_SPECIAL_CP) {
+        utrie2_setRange32(toUTrie2->trie, start, end, (uint32_t)rowIndex, TRUE, pErrorCode);
+    } else {
+        switch(start) {
+        case UPVEC_INITIAL_VALUE_CP:
+            toUTrie2->initialValue=rowIndex;
+            break;
+        case UPVEC_ERROR_VALUE_CP:
+            toUTrie2->errorValue=rowIndex;
+            break;
+        case UPVEC_START_REAL_VALUES_CP:
+            toUTrie2->maxValue=rowIndex;
+            if(rowIndex>0xffff) {
+                /* too many rows for a 16-bit trie */
+                *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+            } else {
+                toUTrie2->trie=utrie2_open(toUTrie2->initialValue,
+                                           toUTrie2->errorValue, pErrorCode);
+            }
+            break;
+        default:
+            break;
+        }
+    }
+}
diff --git a/source/common/propsvec.h b/source/common/propsvec.h
new file mode 100644
index 0000000..fb62809
--- /dev/null
+++ b/source/common/propsvec.h
@@ -0,0 +1,176 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2002-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  propsvec.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002feb22
+*   created by: Markus W. Scherer
+*
+*   Store bits (Unicode character properties) in bit set vectors.
+*/
+
+#ifndef __UPROPSVEC_H__
+#define __UPROPSVEC_H__
+
+#include "unicode/utypes.h"
+#include "utrie.h"
+#include "utrie2.h"
+
+U_CDECL_BEGIN
+
+/**
+ * Unicode Properties Vectors associated with code point ranges.
+ *
+ * Rows of uint32_t integers in a contiguous array store
+ * the range limits and the properties vectors.
+ *
+ * Logically, each row has a certain number of uint32_t values,
+ * which is set via the upvec_open() "columns" parameter.
+ *
+ * Internally, two additional columns are stored.
+ * In each internal row,
+ * row[0] contains the start code point and
+ * row[1] contains the limit code point,
+ * which is the start of the next range.
+ *
+ * Initially, there is only one "normal" row for
+ * range [0..0x110000[ with values 0.
+ * There are additional rows for special purposes, see UPVEC_FIRST_SPECIAL_CP.
+ *
+ * It would be possible to store only one range boundary per row,
+ * but self-contained rows allow to later sort them by contents.
+ */
+struct UPropsVectors;
+typedef struct UPropsVectors UPropsVectors;
+
+/*
+ * Special pseudo code points for storing the initialValue and the errorValue,
+ * which are used to initialize a UTrie2 or similar.
+ */
+#define UPVEC_FIRST_SPECIAL_CP 0x110000
+#define UPVEC_INITIAL_VALUE_CP 0x110000
+#define UPVEC_ERROR_VALUE_CP 0x110001
+#define UPVEC_MAX_CP 0x110001
+
+/*
+ * Special pseudo code point used in upvec_compact() signalling the end of
+ * delivering special values and the beginning of delivering real ones.
+ * Stable value, unlike UPVEC_MAX_CP which might grow over time.
+ */
+#define UPVEC_START_REAL_VALUES_CP 0x200000
+
+/*
+ * Open a UPropsVectors object.
+ * @param columns Number of value integers (uint32_t) per row.
+ */
+U_CAPI UPropsVectors * U_EXPORT2
+upvec_open(int32_t columns, UErrorCode *pErrorCode);
+
+U_CAPI void U_EXPORT2
+upvec_close(UPropsVectors *pv);
+
+/*
+ * In rows for code points [start..end], select the column,
+ * reset the mask bits and set the value bits (ANDed with the mask).
+ *
+ * Will set U_NO_WRITE_PERMISSION if called after upvec_compact().
+ */
+U_CAPI void U_EXPORT2
+upvec_setValue(UPropsVectors *pv,
+               UChar32 start, UChar32 end,
+               int32_t column,
+               uint32_t value, uint32_t mask,
+               UErrorCode *pErrorCode);
+
+/*
+ * Logically const but must not be used on the same pv concurrently!
+ * Always returns 0 if called after upvec_compact().
+ */
+U_CAPI uint32_t U_EXPORT2
+upvec_getValue(const UPropsVectors *pv, UChar32 c, int32_t column);
+
+/*
+ * pRangeStart and pRangeEnd can be NULL.
+ * @return NULL if rowIndex out of range and for illegal arguments,
+ *         or if called after upvec_compact()
+ */
+U_CAPI uint32_t * U_EXPORT2
+upvec_getRow(const UPropsVectors *pv, int32_t rowIndex,
+             UChar32 *pRangeStart, UChar32 *pRangeEnd);
+
+/*
+ * Compact the vectors:
+ * - modify the memory
+ * - keep only unique vectors
+ * - store them contiguously from the beginning of the memory
+ * - for each (non-unique) row, call the handler function
+ *
+ * The handler's rowIndex is the index of the row in the compacted
+ * memory block.
+ * (Therefore, it starts at 0 increases in increments of the columns value.)
+ *
+ * In a first phase, only special values are delivered (each exactly once),
+ * with start==end both equalling a special pseudo code point.
+ * Then the handler is called once more with start==end==UPVEC_START_REAL_VALUES_CP
+ * where rowIndex is the length of the compacted array,
+ * and the row is arbitrary (but not NULL).
+ * Then, in the second phase, the handler is called for each row of real values.
+ */
+typedef void U_CALLCONV
+UPVecCompactHandler(void *context,
+                    UChar32 start, UChar32 end,
+                    int32_t rowIndex, uint32_t *row, int32_t columns,
+                    UErrorCode *pErrorCode);
+
+U_CAPI void U_EXPORT2
+upvec_compact(UPropsVectors *pv, UPVecCompactHandler *handler, void *context, UErrorCode *pErrorCode);
+
+/*
+ * Get the vectors array after calling upvec_compact().
+ * The caller must not modify nor release the returned array.
+ * Returns NULL if called before upvec_compact().
+ */
+U_CAPI const uint32_t * U_EXPORT2
+upvec_getArray(const UPropsVectors *pv, int32_t *pRows, int32_t *pColumns);
+
+/*
+ * Get a clone of the vectors array after calling upvec_compact().
+ * The caller owns the returned array and must uprv_free() it.
+ * Returns NULL if called before upvec_compact().
+ */
+U_CAPI uint32_t * U_EXPORT2
+upvec_cloneArray(const UPropsVectors *pv,
+                 int32_t *pRows, int32_t *pColumns, UErrorCode *pErrorCode);
+
+/*
+ * Call upvec_compact(), create a 16-bit UTrie2 with indexes into the compacted
+ * vectors array, and freeze the trie.
+ */
+U_CAPI UTrie2 * U_EXPORT2
+upvec_compactToUTrie2WithRowIndexes(UPropsVectors *pv, UErrorCode *pErrorCode);
+
+struct UPVecToUTrie2Context {
+    UTrie2 *trie;
+    int32_t initialValue;
+    int32_t errorValue;
+    int32_t maxValue;
+};
+typedef struct UPVecToUTrie2Context UPVecToUTrie2Context;
+
+/* context=UPVecToUTrie2Context, creates the trie and stores the rowIndex values */
+U_CAPI void U_CALLCONV
+upvec_compactToUTrie2Handler(void *context,
+                             UChar32 start, UChar32 end,
+                             int32_t rowIndex, uint32_t *row, int32_t columns,
+                             UErrorCode *pErrorCode);
+
+U_CDECL_END
+
+#endif
diff --git a/source/common/punycode.c b/source/common/punycode.c
new file mode 100644
index 0000000..bf85b67
--- /dev/null
+++ b/source/common/punycode.c
@@ -0,0 +1,582 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2002-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  punycode.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002jan31
+*   created by: Markus W. Scherer
+*/
+
+
+/* This ICU code derived from: */
+/*
+punycode.c 0.4.0 (2001-Nov-17-Sat)
+http://www.cs.berkeley.edu/~amc/idn/
+Adam M. Costello
+http://www.nicemice.net/amc/
+
+Disclaimer and license
+
+    Regarding this entire document or any portion of it (including
+    the pseudocode and C code), the author makes no guarantees and
+    is not responsible for any damage resulting from its use.  The
+    author grants irrevocable permission to anyone to use, modify,
+    and distribute it in any way that does not diminish the rights
+    of anyone else to use, modify, and distribute it, provided that
+    redistributed derivative works do not contain misleading author or
+    version information.  Derivative works need not be licensed under
+    similar terms.
+*/
+/*
+ * ICU modifications:
+ * - ICU data types and coding conventions
+ * - ICU string buffer handling with implicit source lengths
+ *   and destination preflighting
+ * - UTF-16 handling
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_IDNA
+
+#include "ustr_imp.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include "punycode.h"
+#include "unicode/ustring.h"
+
+
+/* Punycode ----------------------------------------------------------------- */
+
+/* Punycode parameters for Bootstring */
+#define BASE            36
+#define TMIN            1
+#define TMAX            26
+#define SKEW            38
+#define DAMP            700
+#define INITIAL_BIAS    72
+#define INITIAL_N       0x80
+
+/* "Basic" Unicode/ASCII code points */
+#define _HYPHEN         0X2d
+#define DELIMITER       _HYPHEN
+
+#define _ZERO_          0X30
+#define _NINE           0x39
+
+#define _SMALL_A        0X61
+#define _SMALL_Z        0X7a
+
+#define _CAPITAL_A      0X41
+#define _CAPITAL_Z      0X5a
+
+#define IS_BASIC(c) ((c)<0x80)
+#define IS_BASIC_UPPERCASE(c) (_CAPITAL_A<=(c) && (c)<=_CAPITAL_Z)
+
+/**
+ * digitToBasic() returns the basic code point whose value
+ * (when used for representing integers) is d, which must be in the
+ * range 0 to BASE-1. The lowercase form is used unless the uppercase flag is
+ * nonzero, in which case the uppercase form is used.
+ */
+static U_INLINE char
+digitToBasic(int32_t digit, UBool uppercase) {
+    /*  0..25 map to ASCII a..z or A..Z */
+    /* 26..35 map to ASCII 0..9         */
+    if(digit<26) {
+        if(uppercase) {
+            return (char)(_CAPITAL_A+digit);
+        } else {
+            return (char)(_SMALL_A+digit);
+        }
+    } else {
+        return (char)((_ZERO_-26)+digit);
+    }
+}
+
+/**
+ * basicToDigit[] contains the numeric value of a basic code
+ * point (for use in representing integers) in the range 0 to
+ * BASE-1, or -1 if b is does not represent a value.
+ */
+static const int8_t
+basicToDigit[256]={
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1,
+
+    -1,  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, -1, -1, -1, -1, -1,
+
+    -1,  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, -1, -1, -1, -1, -1,
+
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+static U_INLINE char
+asciiCaseMap(char b, UBool uppercase) {
+    if(uppercase) {
+        if(_SMALL_A<=b && b<=_SMALL_Z) {
+            b-=(_SMALL_A-_CAPITAL_A);
+        }
+    } else {
+        if(_CAPITAL_A<=b && b<=_CAPITAL_Z) {
+            b+=(_SMALL_A-_CAPITAL_A);
+        }
+    }
+    return b;
+}
+
+/* Punycode-specific Bootstring code ---------------------------------------- */
+
+/*
+ * The following code omits the {parts} of the pseudo-algorithm in the spec
+ * that are not used with the Punycode parameter set.
+ */
+
+/* Bias adaptation function. */
+static int32_t
+adaptBias(int32_t delta, int32_t length, UBool firstTime) {
+    int32_t count;
+
+    if(firstTime) {
+        delta/=DAMP;
+    } else {
+        delta/=2;
+    }
+
+    delta+=delta/length;
+    for(count=0; delta>((BASE-TMIN)*TMAX)/2; count+=BASE) {
+        delta/=(BASE-TMIN);
+    }
+
+    return count+(((BASE-TMIN+1)*delta)/(delta+SKEW));
+}
+
+#define MAX_CP_COUNT    200
+
+U_CFUNC int32_t
+u_strToPunycode(const UChar *src, int32_t srcLength,
+                UChar *dest, int32_t destCapacity,
+                const UBool *caseFlags,
+                UErrorCode *pErrorCode) {
+
+    int32_t cpBuffer[MAX_CP_COUNT];
+    int32_t n, delta, handledCPCount, basicLength, destLength, bias, j, m, q, k, t, srcCPCount;
+    UChar c, c2;
+
+    /* argument checking */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    if(src==NULL || srcLength<-1 || (dest==NULL && destCapacity!=0)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /*
+     * Handle the basic code points and
+     * convert extended ones to UTF-32 in cpBuffer (caseFlag in sign bit):
+     */
+    srcCPCount=destLength=0;
+    if(srcLength==-1) {
+        /* NUL-terminated input */
+        for(j=0; /* no condition */; ++j) {
+            if((c=src[j])==0) {
+                break;
+            }
+            if(srcCPCount==MAX_CP_COUNT) {
+                /* too many input code points */
+                *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+                return 0;
+            }
+            if(IS_BASIC(c)) {
+                cpBuffer[srcCPCount++]=0;
+                if(destLength<destCapacity) {
+                    dest[destLength]=
+                        caseFlags!=NULL ?
+                            asciiCaseMap((char)c, caseFlags[j]) :
+                            (char)c;
+                }
+                ++destLength;
+            } else {
+                n=(caseFlags!=NULL && caseFlags[j])<<31L;
+                if(UTF_IS_SINGLE(c)) {
+                    n|=c;
+                } else if(UTF_IS_LEAD(c) && UTF_IS_TRAIL(c2=src[j+1])) {
+                    ++j;
+                    n|=(int32_t)UTF16_GET_PAIR_VALUE(c, c2);
+                } else {
+                    /* error: unmatched surrogate */
+                    *pErrorCode=U_INVALID_CHAR_FOUND;
+                    return 0;
+                }
+                cpBuffer[srcCPCount++]=n;
+            }
+        }
+    } else {
+        /* length-specified input */
+        for(j=0; j<srcLength; ++j) {
+            if(srcCPCount==MAX_CP_COUNT) {
+                /* too many input code points */
+                *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+                return 0;
+            }
+            c=src[j];
+            if(IS_BASIC(c)) {
+                cpBuffer[srcCPCount++]=0;
+                if(destLength<destCapacity) {
+                    dest[destLength]=
+                        caseFlags!=NULL ?
+                            asciiCaseMap((char)c, caseFlags[j]) :
+                            (char)c;
+                }
+                ++destLength;
+            } else {
+                n=(caseFlags!=NULL && caseFlags[j])<<31L;
+                if(UTF_IS_SINGLE(c)) {
+                    n|=c;
+                } else if(UTF_IS_LEAD(c) && (j+1)<srcLength && UTF_IS_TRAIL(c2=src[j+1])) {
+                    ++j;
+                    n|=(int32_t)UTF16_GET_PAIR_VALUE(c, c2);
+                } else {
+                    /* error: unmatched surrogate */
+                    *pErrorCode=U_INVALID_CHAR_FOUND;
+                    return 0;
+                }
+                cpBuffer[srcCPCount++]=n;
+            }
+        }
+    }
+
+    /* Finish the basic string - if it is not empty - with a delimiter. */
+    basicLength=destLength;
+    if(basicLength>0) {
+        if(destLength<destCapacity) {
+            dest[destLength]=DELIMITER;
+        }
+        ++destLength;
+    }
+
+    /*
+     * handledCPCount is the number of code points that have been handled
+     * basicLength is the number of basic code points
+     * destLength is the number of chars that have been output
+     */
+
+    /* Initialize the state: */
+    n=INITIAL_N;
+    delta=0;
+    bias=INITIAL_BIAS;
+
+    /* Main encoding loop: */
+    for(handledCPCount=basicLength; handledCPCount<srcCPCount; /* no op */) {
+        /*
+         * All non-basic code points < n have been handled already.
+         * Find the next larger one:
+         */
+        for(m=0x7fffffff, j=0; j<srcCPCount; ++j) {
+            q=cpBuffer[j]&0x7fffffff; /* remove case flag from the sign bit */
+            if(n<=q && q<m) {
+                m=q;
+            }
+        }
+
+        /*
+         * Increase delta enough to advance the decoder's
+         * <n,i> state to <m,0>, but guard against overflow:
+         */
+        if(m-n>(0x7fffffff-MAX_CP_COUNT-delta)/(handledCPCount+1)) {
+            *pErrorCode=U_INTERNAL_PROGRAM_ERROR;
+            return 0;
+        }
+        delta+=(m-n)*(handledCPCount+1);
+        n=m;
+
+        /* Encode a sequence of same code points n */
+        for(j=0; j<srcCPCount; ++j) {
+            q=cpBuffer[j]&0x7fffffff; /* remove case flag from the sign bit */
+            if(q<n) {
+                ++delta;
+            } else if(q==n) {
+                /* Represent delta as a generalized variable-length integer: */
+                for(q=delta, k=BASE; /* no condition */; k+=BASE) {
+
+                    /** RAM: comment out the old code for conformance with draft-ietf-idn-punycode-03.txt
+
+                    t=k-bias;
+                    if(t<TMIN) {
+                        t=TMIN;
+                    } else if(t>TMAX) {
+                        t=TMAX;
+                    }
+                    */
+
+                    t=k-bias;
+                    if(t<TMIN) {
+                        t=TMIN;
+                    } else if(k>=(bias+TMAX)) {
+                        t=TMAX;
+                    }
+
+                    if(q<t) {
+                        break;
+                    }
+
+                    if(destLength<destCapacity) {
+                        dest[destLength]=digitToBasic(t+(q-t)%(BASE-t), 0);
+                    }
+                    ++destLength;
+                    q=(q-t)/(BASE-t);
+                }
+
+                if(destLength<destCapacity) {
+                    dest[destLength]=digitToBasic(q, (UBool)(cpBuffer[j]<0));
+                }
+                ++destLength;
+                bias=adaptBias(delta, handledCPCount+1, (UBool)(handledCPCount==basicLength));
+                delta=0;
+                ++handledCPCount;
+            }
+        }
+
+        ++delta;
+        ++n;
+    }
+
+    return u_terminateUChars(dest, destCapacity, destLength, pErrorCode);
+}
+
+U_CFUNC int32_t
+u_strFromPunycode(const UChar *src, int32_t srcLength,
+                  UChar *dest, int32_t destCapacity,
+                  UBool *caseFlags,
+                  UErrorCode *pErrorCode) {
+    int32_t n, destLength, i, bias, basicLength, j, in, oldi, w, k, digit, t,
+            destCPCount, firstSupplementaryIndex, cpLength;
+    UChar b;
+
+    /* argument checking */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    if(src==NULL || srcLength<-1 || (dest==NULL && destCapacity!=0)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    if(srcLength==-1) {
+        srcLength=u_strlen(src);
+    }
+
+    /*
+     * Handle the basic code points:
+     * Let basicLength be the number of input code points
+     * before the last delimiter, or 0 if there is none,
+     * then copy the first basicLength code points to the output.
+     *
+     * The two following loops iterate backward.
+     */
+    for(j=srcLength; j>0;) {
+        if(src[--j]==DELIMITER) {
+            break;
+        }
+    }
+    destLength=basicLength=destCPCount=j;
+
+    while(j>0) {
+        b=src[--j];
+        if(!IS_BASIC(b)) {
+            *pErrorCode=U_INVALID_CHAR_FOUND;
+            return 0;
+        }
+
+        if(j<destCapacity) {
+            dest[j]=(UChar)b;
+
+            if(caseFlags!=NULL) {
+                caseFlags[j]=IS_BASIC_UPPERCASE(b);
+            }
+        }
+    }
+
+    /* Initialize the state: */
+    n=INITIAL_N;
+    i=0;
+    bias=INITIAL_BIAS;
+    firstSupplementaryIndex=1000000000;
+
+    /*
+     * Main decoding loop:
+     * Start just after the last delimiter if any
+     * basic code points were copied; start at the beginning otherwise.
+     */
+    for(in=basicLength>0 ? basicLength+1 : 0; in<srcLength; /* no op */) {
+        /*
+         * in is the index of the next character to be consumed, and
+         * destCPCount is the number of code points in the output array.
+         *
+         * Decode a generalized variable-length integer into delta,
+         * which gets added to i.  The overflow checking is easier
+         * if we increase i as we go, then subtract off its starting
+         * value at the end to obtain delta.
+         */
+        for(oldi=i, w=1, k=BASE; /* no condition */; k+=BASE) {
+            if(in>=srcLength) {
+                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                return 0;
+            }
+
+            digit=basicToDigit[(uint8_t)src[in++]];
+            if(digit<0) {
+                *pErrorCode=U_INVALID_CHAR_FOUND;
+                return 0;
+            }
+            if(digit>(0x7fffffff-i)/w) {
+                /* integer overflow */
+                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                return 0;
+            }
+
+            i+=digit*w;
+            /** RAM: comment out the old code for conformance with draft-ietf-idn-punycode-03.txt  
+            t=k-bias;
+            if(t<TMIN) {
+                t=TMIN;
+            } else if(t>TMAX) {
+                t=TMAX;
+            }
+            */
+            t=k-bias;
+            if(t<TMIN) {
+                t=TMIN;
+            } else if(k>=(bias+TMAX)) {
+                t=TMAX;
+            }
+            if(digit<t) {
+                break;
+            }
+
+            if(w>0x7fffffff/(BASE-t)) {
+                /* integer overflow */
+                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                return 0;
+            }
+            w*=BASE-t;
+        }
+
+        /*
+         * Modification from sample code:
+         * Increments destCPCount here,
+         * where needed instead of in for() loop tail.
+         */
+        ++destCPCount;
+        bias=adaptBias(i-oldi, destCPCount, (UBool)(oldi==0));
+
+        /*
+         * i was supposed to wrap around from (incremented) destCPCount to 0,
+         * incrementing n each time, so we'll fix that now:
+         */
+        if(i/destCPCount>(0x7fffffff-n)) {
+            /* integer overflow */
+            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+            return 0;
+        }
+
+        n+=i/destCPCount;
+        i%=destCPCount;
+        /* not needed for Punycode: */
+        /* if (decode_digit(n) <= BASE) return punycode_invalid_input; */
+
+        if(n>0x10ffff || UTF_IS_SURROGATE(n)) {
+            /* Unicode code point overflow */
+            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+            return 0;
+        }
+
+        /* Insert n at position i of the output: */
+        cpLength=UTF_CHAR_LENGTH(n);
+        if((destLength+cpLength)<=destCapacity) {
+            int32_t codeUnitIndex;
+
+            /*
+             * Handle indexes when supplementary code points are present.
+             *
+             * In almost all cases, there will be only BMP code points before i
+             * and even in the entire string.
+             * This is handled with the same efficiency as with UTF-32.
+             *
+             * Only the rare cases with supplementary code points are handled
+             * more slowly - but not too bad since this is an insertion anyway.
+             */
+            if(i<=firstSupplementaryIndex) {
+                codeUnitIndex=i;
+                if(cpLength>1) {
+                    firstSupplementaryIndex=codeUnitIndex;
+                } else {
+                    ++firstSupplementaryIndex;
+                }
+            } else {
+                codeUnitIndex=firstSupplementaryIndex;
+                UTF_FWD_N(dest, codeUnitIndex, destLength, i-codeUnitIndex);
+            }
+
+            /* use the UChar index codeUnitIndex instead of the code point index i */
+            if(codeUnitIndex<destLength) {
+                uprv_memmove(dest+codeUnitIndex+cpLength,
+                             dest+codeUnitIndex,
+                             (destLength-codeUnitIndex)*U_SIZEOF_UCHAR);
+                if(caseFlags!=NULL) {
+                    uprv_memmove(caseFlags+codeUnitIndex+cpLength,
+                                 caseFlags+codeUnitIndex,
+                                 destLength-codeUnitIndex);
+                }
+            }
+            if(cpLength==1) {
+                /* BMP, insert one code unit */
+                dest[codeUnitIndex]=(UChar)n;
+            } else {
+                /* supplementary character, insert two code units */
+                dest[codeUnitIndex]=UTF16_LEAD(n);
+                dest[codeUnitIndex+1]=UTF16_TRAIL(n);
+            }
+            if(caseFlags!=NULL) {
+                /* Case of last character determines uppercase flag: */
+                caseFlags[codeUnitIndex]=IS_BASIC_UPPERCASE(src[in-1]);
+                if(cpLength==2) {
+                    caseFlags[codeUnitIndex+1]=FALSE;
+                }
+            }
+        }
+        destLength+=cpLength;
+        ++i;
+    }
+
+    return u_terminateUChars(dest, destCapacity, destLength, pErrorCode);
+}
+
+/* ### check notes on overflow handling - only necessary if not IDNA? are these Punycode functions to be public? */
+
+#endif /* #if !UCONFIG_NO_IDNA */
diff --git a/source/common/punycode.h b/source/common/punycode.h
new file mode 100644
index 0000000..21ae91d
--- /dev/null
+++ b/source/common/punycode.h
@@ -0,0 +1,118 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2002-2003, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  punycode.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002jan31
+*   created by: Markus W. Scherer
+*/
+
+/* This ICU code derived from: */
+/*
+punycode.c 0.4.0 (2001-Nov-17-Sat)
+http://www.cs.berkeley.edu/~amc/idn/
+Adam M. Costello
+http://www.nicemice.net/amc/
+*/
+
+#ifndef __PUNYCODE_H__
+#define __PUNYCODE_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_IDNA
+
+/**
+ * u_strToPunycode() converts Unicode to Punycode.
+ *
+ * The input string must not contain single, unpaired surrogates.
+ * The output will be represented as an array of ASCII code points.
+ *
+ * The output string is NUL-terminated according to normal ICU
+ * string output rules.
+ *
+ * @param src Input Unicode string.
+ *            This function handles a limited amount of code points
+ *            (the limit is >=64).
+ *            U_INDEX_OUTOFBOUNDS_ERROR is set if the limit is exceeded.
+ * @param srcLength Number of UChars in src, or -1 if NUL-terminated.
+ * @param dest Output Punycode array.
+ * @param destCapacity Size of dest.
+ * @param caseFlags Vector of boolean values, one per input UChar,
+ *                  indicating that the corresponding character is to be
+ *                  marked for the decoder optionally
+ *                  uppercasing (TRUE) or lowercasing (FALSE)
+ *                  the character.
+ *                  ASCII characters are output directly in the case as marked.
+ *                  Flags corresponding to trail surrogates are ignored.
+ *                  If caseFlags==NULL then input characters are not
+ *                  case-mapped.
+ * @param pErrorCode ICU in/out error code parameter.
+ *                   U_INVALID_CHAR_FOUND if src contains
+ *                   unmatched single surrogates.
+ *                   U_INDEX_OUTOFBOUNDS_ERROR if src contains
+ *                   too many code points.
+ * @return Number of ASCII characters in puny.
+ *
+ * @see u_strFromPunycode
+ */
+U_CFUNC int32_t
+u_strToPunycode(const UChar *src, int32_t srcLength,
+                UChar *dest, int32_t destCapacity,
+                const UBool *caseFlags,
+                UErrorCode *pErrorCode);
+
+/**
+ * u_strFromPunycode() converts Punycode to Unicode.
+ * The Unicode string will be at most as long (in UChars)
+ * than the Punycode string (in chars).
+ *
+ * @param src Input Punycode string.
+ * @param srcLength Length of puny, or -1 if NUL-terminated
+ * @param dest Output Unicode string buffer.
+ * @param destCapacity Size of dest in number of UChars,
+ *                     and of caseFlags in numbers of UBools.
+ * @param caseFlags Output array for case flags as
+ *                  defined by the Punycode string.
+ *                  The caller should uppercase (TRUE) or lowercase (FASLE)
+ *                  the corresponding character in dest.
+ *                  For supplementary characters, only the lead surrogate
+ *                  is marked, and FALSE is stored for the trail surrogate.
+ *                  This is redundant and not necessary for ASCII characters
+ *                  because they are already in the case indicated.
+ *                  Can be NULL if the case flags are not needed.
+ * @param pErrorCode ICU in/out error code parameter.
+ *                   U_INVALID_CHAR_FOUND if a non-ASCII character
+ *                   precedes the last delimiter ('-'),
+ *                   or if an invalid character (not a-zA-Z0-9) is found
+ *                   after the last delimiter.
+ *                   U_ILLEGAL_CHAR_FOUND if the delta sequence is ill-formed.
+ * @return Number of UChars written to dest.
+ *
+ * @see u_strToPunycode
+ */
+U_CFUNC int32_t
+u_strFromPunycode(const UChar *src, int32_t srcLength,
+                  UChar *dest, int32_t destCapacity,
+                  UBool *caseFlags,
+                  UErrorCode *pErrorCode);
+
+#endif /* #if !UCONFIG_NO_IDNA */
+
+#endif
+
+/*
+ * Hey, Emacs, please set the following:
+ *
+ * Local Variables:
+ * indent-tabs-mode: nil
+ * End:
+ *
+ */
diff --git a/source/common/putil.c b/source/common/putil.c
new file mode 100644
index 0000000..499d25a
--- /dev/null
+++ b/source/common/putil.c
@@ -0,0 +1,2242 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+*  FILE NAME : putil.c (previously putil.cpp and ptypes.cpp)
+*
+*   Date        Name        Description
+*   04/14/97    aliu        Creation.
+*   04/24/97    aliu        Added getDefaultDataDirectory() and
+*                            getDefaultLocaleID().
+*   04/28/97    aliu        Rewritten to assume Unix and apply general methods
+*                            for assumed case.  Non-UNIX platforms must be
+*                            special-cased.  Rewrote numeric methods dealing
+*                            with NaN and Infinity to be platform independent
+*                             over all IEEE 754 platforms.
+*   05/13/97    aliu        Restored sign of timezone
+*                            (semantics are hours West of GMT)
+*   06/16/98    erm         Added IEEE_754 stuff, cleaned up isInfinite, isNan,
+*                             nextDouble..
+*   07/22/98    stephen     Added remainder, max, min, trunc
+*   08/13/98    stephen     Added isNegativeInfinity, isPositiveInfinity
+*   08/24/98    stephen     Added longBitsFromDouble
+*   09/08/98    stephen     Minor changes for Mac Port
+*   03/02/99    stephen     Removed openFile().  Added AS400 support.
+*                            Fixed EBCDIC tables
+*   04/15/99    stephen     Converted to C.
+*   06/28/99    stephen     Removed mutex locking in u_isBigEndian().
+*   08/04/99    jeffrey R.  Added OS/2 changes
+*   11/15/99    helena      Integrated S/390 IEEE support.
+*   04/26/01    Barry N.    OS/400 support for uprv_getDefaultLocaleID
+*   08/15/01    Steven H.   OS/400 support for uprv_getDefaultCodepage
+*   01/03/08    Steven L.   Fake Time Support
+******************************************************************************
+*/
+
+/* Define _XOPEN_SOURCE for Solaris and friends. */
+/* NetBSD needs it to be >= 4 */
+#if !defined(_XOPEN_SOURCE)
+#if __STDC_VERSION__ >= 199901L
+/* It is invalid to compile an XPG3, XPG4, XPG4v2 or XPG5 application using c99 on Solaris */
+#define _XOPEN_SOURCE 600
+#else
+#define _XOPEN_SOURCE 4
+#endif
+#endif
+
+/* Make sure things like readlink and such functions work.
+Poorly upgraded Solaris machines can't have this defined.
+Cleanly installed Solaris can use this #define.
+*/
+#if !defined(_XOPEN_SOURCE_EXTENDED) && ((!defined(__STDC_VERSION__) || __STDC_VERSION__ >= 199901L) || defined(__xlc__))
+#define _XOPEN_SOURCE_EXTENDED 1
+#endif
+
+/* include ICU headers */
+#include "unicode/utypes.h"
+#include "unicode/putil.h"
+#include "unicode/ustring.h"
+#include "putilimp.h"
+#include "uassert.h"
+#include "umutex.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "locmap.h"
+#include "ucln_cmn.h"
+
+/* Include standard headers. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <locale.h>
+#include <float.h>
+#include <time.h>
+
+/* include system headers */
+#ifdef U_WINDOWS
+#   define WIN32_LEAN_AND_MEAN
+#   define VC_EXTRALEAN
+#   define NOUSER
+#   define NOSERVICE
+#   define NOIME
+#   define NOMCX
+#   include <windows.h>
+#   include "wintz.h"
+#elif defined(U_CYGWIN) && defined(__STRICT_ANSI__)
+/* tzset isn't defined in strict ANSI on Cygwin. */
+#   undef __STRICT_ANSI__
+#elif defined(OS400)
+#   include <float.h>
+#   include <qusec.h>       /* error code structure */
+#   include <qusrjobi.h>
+#   include <qliept.h>      /* EPT_CALL macro  - this include must be after all other "QSYSINCs" */
+#   include <mih/testptr.h> /* For uprv_maximumPtr */
+#elif defined(XP_MAC)
+#   include <Files.h>
+#   include <IntlResources.h>
+#   include <Script.h>
+#   include <Folders.h>
+#   include <MacTypes.h>
+#   include <TextUtils.h>
+#   define ICU_NO_USER_DATA_OVERRIDE 1
+#elif defined(OS390)
+#include "unicode/ucnv.h"   /* Needed for UCNV_SWAP_LFNL_OPTION_STRING */
+#elif defined(U_DARWIN) || defined(U_LINUX) || defined(U_BSD)
+#include <limits.h>
+#include <unistd.h>
+#elif defined(U_QNX)
+#include <sys/neutrino.h>
+#elif defined(U_SOLARIS)
+# ifndef _XPG4_2
+#  define _XPG4_2
+# endif
+#endif
+
+
+#if defined(U_DARWIN)
+#include <TargetConditionals.h>
+#endif
+
+#ifndef U_WINDOWS
+#include <sys/time.h>
+#endif
+
+/*
+ * Only include langinfo.h if we have a way to get the codeset. If we later
+ * depend on more feature, we can test on U_HAVE_NL_LANGINFO.
+ *
+ */
+
+#if U_HAVE_NL_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+/**
+ * Simple things (presence of functions, etc) should just go in configure.in and be added to
+ * icucfg.h via autoheader.
+ */
+#if defined(HAVE_CONFIG_H)
+#include "icucfg.h"
+#endif
+
+/* Define the extension for data files, again... */
+#define DATA_TYPE "dat"
+
+/* Leave this copyright notice here! */
+static const char copyright[] = U_COPYRIGHT_STRING;
+
+/* floating point implementations ------------------------------------------- */
+
+/* We return QNAN rather than SNAN*/
+#define SIGN 0x80000000U
+
+/* Make it easy to define certain types of constants */
+typedef union {
+    int64_t i64; /* This must be defined first in order to allow the initialization to work. This is a C89 feature. */
+    double d64;
+} BitPatternConversion;
+static const BitPatternConversion gNan = { (int64_t) INT64_C(0x7FF8000000000000) };
+static const BitPatternConversion gInf = { (int64_t) INT64_C(0x7FF0000000000000) };
+
+/*---------------------------------------------------------------------------
+  Platform utilities
+  Our general strategy is to assume we're on a POSIX platform.  Platforms which
+  are non-POSIX must declare themselves so.  The default POSIX implementation
+  will sometimes work for non-POSIX platforms as well (e.g., the NaN-related
+  functions).
+  ---------------------------------------------------------------------------*/
+
+#if defined(U_WINDOWS) || defined(XP_MAC) || defined(OS400)
+#   undef U_POSIX_LOCALE
+#else
+#   define U_POSIX_LOCALE    1
+#endif
+
+/*
+    WARNING! u_topNBytesOfDouble and u_bottomNBytesOfDouble
+    can't be properly optimized by the gcc compiler sometimes (i.e. gcc 3.2).
+*/
+#if !IEEE_754
+static char*
+u_topNBytesOfDouble(double* d, int n)
+{
+#if U_IS_BIG_ENDIAN
+    return (char*)d;
+#else
+    return (char*)(d + 1) - n;
+#endif
+}
+
+static char*
+u_bottomNBytesOfDouble(double* d, int n)
+{
+#if U_IS_BIG_ENDIAN
+    return (char*)(d + 1) - n;
+#else
+    return (char*)d;
+#endif
+}
+#endif   /* !IEEE_754 */
+
+#if IEEE_754
+static UBool
+u_signBit(double d) {
+    uint8_t hiByte;
+#if U_IS_BIG_ENDIAN
+    hiByte = *(uint8_t *)&d;
+#else
+    hiByte = *(((uint8_t *)&d) + sizeof(double) - 1);
+#endif
+    return (hiByte & 0x80) != 0;
+}
+#endif
+
+
+
+#if defined (U_DEBUG_FAKETIME)
+/* Override the clock to test things without having to move the system clock.
+ * Assumes POSIX gettimeofday() will function
+ */
+UDate fakeClock_t0 = 0; /** Time to start the clock from **/
+UDate fakeClock_dt = 0; /** Offset (fake time - real time) **/
+UBool fakeClock_set = FALSE; /** True if fake clock has spun up **/
+static UMTX fakeClockMutex = NULL;
+
+static UDate getUTCtime_real() {
+    struct timeval posixTime;
+    gettimeofday(&posixTime, NULL);
+    return (UDate)(((int64_t)posixTime.tv_sec * U_MILLIS_PER_SECOND) + (posixTime.tv_usec/1000));
+}
+
+static UDate getUTCtime_fake() {
+    umtx_lock(&fakeClockMutex);
+    if(!fakeClock_set) {
+        UDate real = getUTCtime_real();
+        const char *fake_start = getenv("U_FAKETIME_START");
+        if((fake_start!=NULL) && (fake_start[0]!=0)) {
+            sscanf(fake_start,"%lf",&fakeClock_t0);
+            fakeClock_dt = fakeClock_t0 - real;
+            fprintf(stderr,"U_DEBUG_FAKETIME was set at compile time, so the ICU clock will start at a preset value\n"
+                    "env variable U_FAKETIME_START=%.0f (%s) for an offset of %.0f ms from the current time %.0f\n",
+                    fakeClock_t0, fake_start, fakeClock_dt, real);
+        } else {
+          fakeClock_dt = 0;
+            fprintf(stderr,"U_DEBUG_FAKETIME was set at compile time, but U_FAKETIME_START was not set.\n"
+                    "Set U_FAKETIME_START to the number of milliseconds since 1/1/1970 to set the ICU clock.\n");
+        }
+        fakeClock_set = TRUE;
+    }
+    umtx_unlock(&fakeClockMutex);
+
+    return getUTCtime_real() + fakeClock_dt;
+}
+#endif
+
+#if defined(U_WINDOWS)
+typedef union {
+    int64_t int64;
+    FILETIME fileTime;
+} FileTimeConversion;   /* This is like a ULARGE_INTEGER */
+
+/* Number of 100 nanoseconds from 1/1/1601 to 1/1/1970 */
+#define EPOCH_BIAS  INT64_C(116444736000000000)
+#define HECTONANOSECOND_PER_MILLISECOND   10000
+
+#endif
+
+/*---------------------------------------------------------------------------
+  Universal Implementations
+  These are designed to work on all platforms.  Try these, and if they
+  don't work on your platform, then special case your platform with new
+  implementations.
+---------------------------------------------------------------------------*/
+
+U_CAPI UDate U_EXPORT2
+uprv_getUTCtime()
+{
+#if defined(U_DEBUG_FAKETIME)
+    return getUTCtime_fake(); /* Hook for overriding the clock */
+#else
+    return uprv_getRawUTCtime();
+#endif
+}
+
+/* Return UTC (GMT) time measured in milliseconds since 0:00 on 1/1/70.*/
+U_CAPI UDate U_EXPORT2
+uprv_getRawUTCtime()
+{
+#if defined(XP_MAC)
+    time_t t, t1, t2;
+    struct tm tmrec;
+
+    uprv_memset( &tmrec, 0, sizeof(tmrec) );
+    tmrec.tm_year = 70;
+    tmrec.tm_mon = 0;
+    tmrec.tm_mday = 1;
+    t1 = mktime(&tmrec);    /* seconds of 1/1/1970*/
+
+    time(&t);
+    uprv_memcpy( &tmrec, gmtime(&t), sizeof(tmrec) );
+    t2 = mktime(&tmrec);    /* seconds of current GMT*/
+    return (UDate)(t2 - t1) * U_MILLIS_PER_SECOND;         /* GMT (or UTC) in seconds since 1970*/
+#elif defined(U_WINDOWS)
+
+    FileTimeConversion winTime;
+    GetSystemTimeAsFileTime(&winTime.fileTime);
+    return (UDate)((winTime.int64 - EPOCH_BIAS) / HECTONANOSECOND_PER_MILLISECOND);
+#else
+
+#if defined(HAVE_GETTIMEOFDAY)
+    struct timeval posixTime;
+    gettimeofday(&posixTime, NULL);
+    return (UDate)(((int64_t)posixTime.tv_sec * U_MILLIS_PER_SECOND) + (posixTime.tv_usec/1000));
+#else
+    time_t epochtime;
+    time(&epochtime);
+    return (UDate)epochtime * U_MILLIS_PER_SECOND;
+#endif
+
+#endif
+}
+
+/*-----------------------------------------------------------------------------
+  IEEE 754
+  These methods detect and return NaN and infinity values for doubles
+  conforming to IEEE 754.  Platforms which support this standard include X86,
+  Mac 680x0, Mac PowerPC, AIX RS/6000, and most others.
+  If this doesn't work on your platform, you have non-IEEE floating-point, and
+  will need to code your own versions.  A naive implementation is to return 0.0
+  for getNaN and getInfinity, and false for isNaN and isInfinite.
+  ---------------------------------------------------------------------------*/
+
+U_CAPI UBool U_EXPORT2
+uprv_isNaN(double number)
+{
+#if IEEE_754
+    BitPatternConversion convertedNumber;
+    convertedNumber.d64 = number;
+    /* Infinity is 0x7FF0000000000000U. Anything greater than that is a NaN */
+    return (UBool)((convertedNumber.i64 & U_INT64_MAX) > gInf.i64);
+
+#elif defined(OS390)
+    uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
+                        sizeof(uint32_t));
+    uint32_t lowBits  = *(uint32_t*)u_bottomNBytesOfDouble(&number,
+                        sizeof(uint32_t));
+
+    return ((highBits & 0x7F080000L) == 0x7F080000L) &&
+      (lowBits == 0x00000000L);
+
+#else
+    /* If your platform doesn't support IEEE 754 but *does* have an NaN value,*/
+    /* you'll need to replace this default implementation with what's correct*/
+    /* for your platform.*/
+    return number != number;
+#endif
+}
+
+U_CAPI UBool U_EXPORT2
+uprv_isInfinite(double number)
+{
+#if IEEE_754
+    BitPatternConversion convertedNumber;
+    convertedNumber.d64 = number;
+    /* Infinity is exactly 0x7FF0000000000000U. */
+    return (UBool)((convertedNumber.i64 & U_INT64_MAX) == gInf.i64);
+#elif defined(OS390)
+    uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
+                        sizeof(uint32_t));
+    uint32_t lowBits  = *(uint32_t*)u_bottomNBytesOfDouble(&number,
+                        sizeof(uint32_t));
+
+    return ((highBits  & ~SIGN) == 0x70FF0000L) && (lowBits == 0x00000000L);
+
+#else
+    /* If your platform doesn't support IEEE 754 but *does* have an infinity*/
+    /* value, you'll need to replace this default implementation with what's*/
+    /* correct for your platform.*/
+    return number == (2.0 * number);
+#endif
+}
+
+U_CAPI UBool U_EXPORT2
+uprv_isPositiveInfinity(double number)
+{
+#if IEEE_754 || defined(OS390)
+    return (UBool)(number > 0 && uprv_isInfinite(number));
+#else
+    return uprv_isInfinite(number);
+#endif
+}
+
+U_CAPI UBool U_EXPORT2
+uprv_isNegativeInfinity(double number)
+{
+#if IEEE_754 || defined(OS390)
+    return (UBool)(number < 0 && uprv_isInfinite(number));
+
+#else
+    uint32_t highBits = *(uint32_t*)u_topNBytesOfDouble(&number,
+                        sizeof(uint32_t));
+    return((highBits & SIGN) && uprv_isInfinite(number));
+
+#endif
+}
+
+U_CAPI double U_EXPORT2
+uprv_getNaN()
+{
+#if IEEE_754 || defined(OS390)
+    return gNan.d64;
+#else
+    /* If your platform doesn't support IEEE 754 but *does* have an NaN value,*/
+    /* you'll need to replace this default implementation with what's correct*/
+    /* for your platform.*/
+    return 0.0;
+#endif
+}
+
+U_CAPI double U_EXPORT2
+uprv_getInfinity()
+{
+#if IEEE_754 || defined(OS390)
+    return gInf.d64;
+#else
+    /* If your platform doesn't support IEEE 754 but *does* have an infinity*/
+    /* value, you'll need to replace this default implementation with what's*/
+    /* correct for your platform.*/
+    return 0.0;
+#endif
+}
+
+U_CAPI double U_EXPORT2
+uprv_floor(double x)
+{
+    return floor(x);
+}
+
+U_CAPI double U_EXPORT2
+uprv_ceil(double x)
+{
+    return ceil(x);
+}
+
+U_CAPI double U_EXPORT2
+uprv_round(double x)
+{
+    return uprv_floor(x + 0.5);
+}
+
+U_CAPI double U_EXPORT2
+uprv_fabs(double x)
+{
+    return fabs(x);
+}
+
+U_CAPI double U_EXPORT2
+uprv_modf(double x, double* y)
+{
+    return modf(x, y);
+}
+
+U_CAPI double U_EXPORT2
+uprv_fmod(double x, double y)
+{
+    return fmod(x, y);
+}
+
+U_CAPI double U_EXPORT2
+uprv_pow(double x, double y)
+{
+    /* This is declared as "double pow(double x, double y)" */
+    return pow(x, y);
+}
+
+U_CAPI double U_EXPORT2
+uprv_pow10(int32_t x)
+{
+    return pow(10.0, (double)x);
+}
+
+U_CAPI double U_EXPORT2
+uprv_fmax(double x, double y)
+{
+#if IEEE_754
+    /* first handle NaN*/
+    if(uprv_isNaN(x) || uprv_isNaN(y))
+        return uprv_getNaN();
+
+    /* check for -0 and 0*/
+    if(x == 0.0 && y == 0.0 && u_signBit(x))
+        return y;
+
+#endif
+
+    /* this should work for all flt point w/o NaN and Inf special cases */
+    return (x > y ? x : y);
+}
+
+U_CAPI double U_EXPORT2
+uprv_fmin(double x, double y)
+{
+#if IEEE_754
+    /* first handle NaN*/
+    if(uprv_isNaN(x) || uprv_isNaN(y))
+        return uprv_getNaN();
+
+    /* check for -0 and 0*/
+    if(x == 0.0 && y == 0.0 && u_signBit(y))
+        return y;
+
+#endif
+
+    /* this should work for all flt point w/o NaN and Inf special cases */
+    return (x > y ? y : x);
+}
+
+/**
+ * Truncates the given double.
+ * trunc(3.3) = 3.0, trunc (-3.3) = -3.0
+ * This is different than calling floor() or ceil():
+ * floor(3.3) = 3, floor(-3.3) = -4
+ * ceil(3.3) = 4, ceil(-3.3) = -3
+ */
+U_CAPI double U_EXPORT2
+uprv_trunc(double d)
+{
+#if IEEE_754
+    /* handle error cases*/
+    if(uprv_isNaN(d))
+        return uprv_getNaN();
+    if(uprv_isInfinite(d))
+        return uprv_getInfinity();
+
+    if(u_signBit(d))    /* Signbit() picks up -0.0;  d<0 does not. */
+        return ceil(d);
+    else
+        return floor(d);
+
+#else
+    return d >= 0 ? floor(d) : ceil(d);
+
+#endif
+}
+
+/**
+ * Return the largest positive number that can be represented by an integer
+ * type of arbitrary bit length.
+ */
+U_CAPI double U_EXPORT2
+uprv_maxMantissa(void)
+{
+    return pow(2.0, DBL_MANT_DIG + 1.0) - 1.0;
+}
+
+U_CAPI double U_EXPORT2
+uprv_log(double d)
+{
+    return log(d);
+}
+
+U_CAPI void * U_EXPORT2
+uprv_maximumPtr(void * base)
+{
+#if defined(OS400)
+    /*
+     * With the provided function we should never be out of range of a given segment
+     * (a traditional/typical segment that is).  Our segments have 5 bytes for the
+     * id and 3 bytes for the offset.  The key is that the casting takes care of
+     * only retrieving the offset portion minus x1000.  Hence, the smallest offset
+     * seen in a program is x001000 and when casted to an int would be 0.
+     * That's why we can only add 0xffefff.  Otherwise, we would exceed the segment.
+     *
+     * Currently, 16MB is the current addressing limitation on i5/OS if the activation is
+     * non-TERASPACE.  If it is TERASPACE it is 2GB - 4k(header information).
+     * This function determines the activation based on the pointer that is passed in and
+     * calculates the appropriate maximum available size for
+     * each pointer type (TERASPACE and non-TERASPACE)
+     *
+     * Unlike other operating systems, the pointer model isn't determined at
+     * compile time on i5/OS.
+     */
+    if ((base != NULL) && (_TESTPTR(base, _C_TERASPACE_CHECK))) {
+        /* if it is a TERASPACE pointer the max is 2GB - 4k */
+        return ((void *)(((char *)base)-((uint32_t)(base))+((uint32_t)0x7fffefff)));
+    }
+    /* otherwise 16MB since NULL ptr is not checkable or the ptr is not TERASPACE */
+    return ((void *)(((char *)base)-((uint32_t)(base))+((uint32_t)0xffefff)));
+
+#else
+    return U_MAX_PTR(base);
+#endif
+}
+
+/*---------------------------------------------------------------------------
+  Platform-specific Implementations
+  Try these, and if they don't work on your platform, then special case your
+  platform with new implementations.
+  ---------------------------------------------------------------------------*/
+
+/* Generic time zone layer -------------------------------------------------- */
+
+/* Time zone utilities */
+U_CAPI void U_EXPORT2
+uprv_tzset()
+{
+#ifdef U_TZSET
+    U_TZSET();
+#else
+    /* no initialization*/
+#endif
+}
+
+U_CAPI int32_t U_EXPORT2
+uprv_timezone()
+{
+#ifdef U_TIMEZONE
+    return U_TIMEZONE;
+#else
+    time_t t, t1, t2;
+    struct tm tmrec;
+    UBool dst_checked;
+    int32_t tdiff = 0;
+
+    time(&t);
+    uprv_memcpy( &tmrec, localtime(&t), sizeof(tmrec) );
+    dst_checked = (tmrec.tm_isdst != 0); /* daylight savings time is checked*/
+    t1 = mktime(&tmrec);                 /* local time in seconds*/
+    uprv_memcpy( &tmrec, gmtime(&t), sizeof(tmrec) );
+    t2 = mktime(&tmrec);                 /* GMT (or UTC) in seconds*/
+    tdiff = t2 - t1;
+    /* imitate NT behaviour, which returns same timezone offset to GMT for
+       winter and summer*/
+    if (dst_checked)
+        tdiff += 3600;
+    return tdiff;
+#endif
+}
+
+/* Note that U_TZNAME does *not* have to be tzname, but if it is,
+   some platforms need to have it declared here. */
+
+#if defined(U_TZNAME) && (defined(U_IRIX) || defined(U_DARWIN) || defined(U_CYGWIN))
+/* RS6000 and others reject char **tzname.  */
+extern U_IMPORT char *U_TZNAME[];
+#endif
+
+#if !UCONFIG_NO_FILE_IO && (defined(U_DARWIN) || defined(U_LINUX) || defined(U_BSD))
+/* These platforms are likely to use Olson timezone IDs. */
+#define CHECK_LOCALTIME_LINK 1
+#if defined(U_DARWIN)
+#include <tzfile.h>
+#define TZZONEINFO      (TZDIR "/")
+#else
+#define TZDEFAULT       "/etc/localtime"
+#define TZZONEINFO      "/usr/share/zoneinfo/"
+#endif
+#if U_HAVE_DIRENT_H
+#define TZFILE_SKIP     "posixrules" /* tz file to skip when searching. */
+/* Some Linux distributions have 'localtime' in /usr/share/zoneinfo
+   symlinked to /etc/localtime, which makes searchForTZFile return
+   'localtime' when it's the first match. */
+#define TZFILE_SKIP2    "localtime"
+#define SEARCH_TZFILE
+#include <dirent.h>  /* Needed to search through system timezone files */
+#endif
+static char gTimeZoneBuffer[PATH_MAX];
+static char *gTimeZoneBufferPtr = NULL;
+#endif
+
+#ifndef U_WINDOWS
+#define isNonDigit(ch) (ch < '0' || '9' < ch)
+static UBool isValidOlsonID(const char *id) {
+    int32_t idx = 0;
+
+    /* Determine if this is something like Iceland (Olson ID)
+    or AST4ADT (non-Olson ID) */
+    while (id[idx] && isNonDigit(id[idx]) && id[idx] != ',') {
+        idx++;
+    }
+
+    /* If we went through the whole string, then it might be okay.
+    The timezone is sometimes set to "CST-7CDT", "CST6CDT5,J129,J131/19:30",
+    "GRNLNDST3GRNLNDDT" or similar, so we cannot use it.
+    The rest of the time it could be an Olson ID. George */
+    return (UBool)(id[idx] == 0
+        || uprv_strcmp(id, "PST8PDT") == 0
+        || uprv_strcmp(id, "MST7MDT") == 0
+        || uprv_strcmp(id, "CST6CDT") == 0
+        || uprv_strcmp(id, "EST5EDT") == 0);
+}
+
+/* On some Unix-like OS, 'posix' subdirectory in
+   /usr/share/zoneinfo replicates the top-level contents. 'right'
+   subdirectory has the same set of files, but individual files
+   are different from those in the top-level directory or 'posix'
+   because 'right' has files for TAI (Int'l Atomic Time) while 'posix'
+   has files for UTC.
+   When the first match for /etc/localtime is in either of them
+   (usually in posix because 'right' has different file contents),
+   or TZ environment variable points to one of them, createTimeZone
+   fails because, say, 'posix/America/New_York' is not an Olson
+   timezone id ('America/New_York' is). So, we have to skip
+   'posix/' and 'right/' at the beginning. */
+static void skipZoneIDPrefix(const char** id) {
+    if (uprv_strncmp(*id, "posix/", 6) == 0
+        || uprv_strncmp(*id, "right/", 6) == 0)
+    {
+        *id += 6;
+    }
+}
+#endif
+
+#if defined(U_TZNAME) && !defined(U_WINDOWS)
+
+#define CONVERT_HOURS_TO_SECONDS(offset) (int32_t)(offset*3600)
+typedef struct OffsetZoneMapping {
+    int32_t offsetSeconds;
+    int32_t daylightType; /* 1=daylight in June, 2=daylight in December*/
+    const char *stdID;
+    const char *dstID;
+    const char *olsonID;
+} OffsetZoneMapping;
+
+/*
+This list tries to disambiguate a set of abbreviated timezone IDs and offsets
+and maps it to an Olson ID.
+Before adding anything to this list, take a look at
+icu/source/tools/tzcode/tz.alias
+Sometimes no daylight savings (0) is important to define due to aliases.
+This list can be tested with icu/source/test/compat/tzone.pl
+More values could be added to daylightType to increase precision.
+*/
+static const struct OffsetZoneMapping OFFSET_ZONE_MAPPINGS[] = {
+    {-45900, 2, "CHAST", "CHADT", "Pacific/Chatham"},
+    {-43200, 1, "PETT", "PETST", "Asia/Kamchatka"},
+    {-43200, 2, "NZST", "NZDT", "Pacific/Auckland"},
+    {-43200, 1, "ANAT", "ANAST", "Asia/Anadyr"},
+    {-39600, 1, "MAGT", "MAGST", "Asia/Magadan"},
+    {-37800, 2, "LHST", "LHST", "Australia/Lord_Howe"},
+    {-36000, 2, "EST", "EST", "Australia/Sydney"},
+    {-36000, 1, "SAKT", "SAKST", "Asia/Sakhalin"},
+    {-36000, 1, "VLAT", "VLAST", "Asia/Vladivostok"},
+    {-34200, 2, "CST", "CST", "Australia/South"},
+    {-32400, 1, "YAKT", "YAKST", "Asia/Yakutsk"},
+    {-32400, 1, "CHOT", "CHOST", "Asia/Choibalsan"},
+    {-31500, 2, "CWST", "CWST", "Australia/Eucla"},
+    {-28800, 1, "IRKT", "IRKST", "Asia/Irkutsk"},
+    {-28800, 1, "ULAT", "ULAST", "Asia/Ulaanbaatar"},
+    {-28800, 2, "WST", "WST", "Australia/West"},
+    {-25200, 1, "HOVT", "HOVST", "Asia/Hovd"},
+    {-25200, 1, "KRAT", "KRAST", "Asia/Krasnoyarsk"},
+    {-21600, 1, "NOVT", "NOVST", "Asia/Novosibirsk"},
+    {-21600, 1, "OMST", "OMSST", "Asia/Omsk"},
+    {-18000, 1, "YEKT", "YEKST", "Asia/Yekaterinburg"},
+    {-14400, 1, "SAMT", "SAMST", "Europe/Samara"},
+    {-14400, 1, "AMT", "AMST", "Asia/Yerevan"},
+    {-14400, 1, "AZT", "AZST", "Asia/Baku"},
+    {-10800, 1, "AST", "ADT", "Asia/Baghdad"},
+    {-10800, 1, "MSK", "MSD", "Europe/Moscow"},
+    {-10800, 1, "VOLT", "VOLST", "Europe/Volgograd"},
+    {-7200, 0, "EET", "CEST", "Africa/Tripoli"},
+    {-7200, 1, "EET", "EEST", "Europe/Athens"}, /* Conflicts with Africa/Cairo */
+    {-7200, 1, "IST", "IDT", "Asia/Jerusalem"},
+    {-3600, 0, "CET", "WEST", "Africa/Algiers"},
+    {-3600, 2, "WAT", "WAST", "Africa/Windhoek"},
+    {0, 1, "GMT", "IST", "Europe/Dublin"},
+    {0, 1, "GMT", "BST", "Europe/London"},
+    {0, 0, "WET", "WEST", "Africa/Casablanca"},
+    {0, 0, "WET", "WET", "Africa/El_Aaiun"},
+    {3600, 1, "AZOT", "AZOST", "Atlantic/Azores"},
+    {3600, 1, "EGT", "EGST", "America/Scoresbysund"},
+    {10800, 1, "PMST", "PMDT", "America/Miquelon"},
+    {10800, 2, "UYT", "UYST", "America/Montevideo"},
+    {10800, 1, "WGT", "WGST", "America/Godthab"},
+    {10800, 2, "BRT", "BRST", "Brazil/East"},
+    {12600, 1, "NST", "NDT", "America/St_Johns"},
+    {14400, 1, "AST", "ADT", "Canada/Atlantic"},
+    {14400, 2, "AMT", "AMST", "America/Cuiaba"},
+    {14400, 2, "CLT", "CLST", "Chile/Continental"},
+    {14400, 2, "FKT", "FKST", "Atlantic/Stanley"},
+    {14400, 2, "PYT", "PYST", "America/Asuncion"},
+    {18000, 1, "CST", "CDT", "America/Havana"},
+    {18000, 1, "EST", "EDT", "US/Eastern"}, /* Conflicts with America/Grand_Turk */
+    {21600, 2, "EAST", "EASST", "Chile/EasterIsland"},
+    {21600, 0, "CST", "MDT", "Canada/Saskatchewan"},
+    {21600, 0, "CST", "CDT", "America/Guatemala"},
+    {21600, 1, "CST", "CDT", "US/Central"}, /* Conflicts with Mexico/General */
+    {25200, 1, "MST", "MDT", "US/Mountain"}, /* Conflicts with Mexico/BajaSur */
+    {28800, 0, "PST", "PST", "Pacific/Pitcairn"},
+    {28800, 1, "PST", "PDT", "US/Pacific"}, /* Conflicts with Mexico/BajaNorte */
+    {32400, 1, "AKST", "AKDT", "US/Alaska"},
+    {36000, 1, "HAST", "HADT", "US/Aleutian"}
+};
+
+/*#define DEBUG_TZNAME*/
+
+static const char* remapShortTimeZone(const char *stdID, const char *dstID, int32_t daylightType, int32_t offset)
+{
+    int32_t idx;
+#ifdef DEBUG_TZNAME
+    fprintf(stderr, "TZ=%s std=%s dst=%s daylight=%d offset=%d\n", getenv("TZ"), stdID, dstID, daylightType, offset);
+#endif
+    for (idx = 0; idx < (int32_t)sizeof(OFFSET_ZONE_MAPPINGS)/sizeof(OFFSET_ZONE_MAPPINGS[0]); idx++)
+    {
+        if (offset == OFFSET_ZONE_MAPPINGS[idx].offsetSeconds
+            && daylightType == OFFSET_ZONE_MAPPINGS[idx].daylightType
+            && strcmp(OFFSET_ZONE_MAPPINGS[idx].stdID, stdID) == 0
+            && strcmp(OFFSET_ZONE_MAPPINGS[idx].dstID, dstID) == 0)
+        {
+            return OFFSET_ZONE_MAPPINGS[idx].olsonID;
+        }
+    }
+    return NULL;
+}
+#endif
+
+#ifdef SEARCH_TZFILE
+#define MAX_PATH_SIZE PATH_MAX /* Set the limit for the size of the path. */
+#define MAX_READ_SIZE 512
+
+typedef struct DefaultTZInfo {
+    char* defaultTZBuffer;
+    int64_t defaultTZFileSize;
+    FILE* defaultTZFilePtr;
+    UBool defaultTZstatus;
+    int32_t defaultTZPosition;
+} DefaultTZInfo;
+
+/*
+ * This method compares the two files given to see if they are a match.
+ * It is currently use to compare two TZ files.
+ */
+static UBool compareBinaryFiles(const char* defaultTZFileName, const char* TZFileName, DefaultTZInfo* tzInfo) {
+    FILE* file; 
+    int64_t sizeFile;
+    int64_t sizeFileLeft;
+    int32_t sizeFileRead;
+    int32_t sizeFileToRead;
+    char bufferFile[MAX_READ_SIZE];
+    UBool result = TRUE;
+
+    if (tzInfo->defaultTZFilePtr == NULL) {
+        tzInfo->defaultTZFilePtr = fopen(defaultTZFileName, "r");
+    }
+    file = fopen(TZFileName, "r");
+
+    tzInfo->defaultTZPosition = 0; /* reset position to begin search */
+
+    if (file != NULL && tzInfo->defaultTZFilePtr != NULL) {
+        /* First check that the file size are equal. */
+        if (tzInfo->defaultTZFileSize == 0) {
+            fseek(tzInfo->defaultTZFilePtr, 0, SEEK_END);
+            tzInfo->defaultTZFileSize = ftell(tzInfo->defaultTZFilePtr);
+        }
+        fseek(file, 0, SEEK_END);
+        sizeFile = ftell(file);
+        sizeFileLeft = sizeFile;
+
+        if (sizeFile != tzInfo->defaultTZFileSize) {
+            result = FALSE;
+        } else {
+            /* Store the data from the files in seperate buffers and
+             * compare each byte to determine equality.
+             */
+            if (tzInfo->defaultTZBuffer == NULL) {
+                rewind(tzInfo->defaultTZFilePtr);
+                tzInfo->defaultTZBuffer = (char*)uprv_malloc(sizeof(char) * tzInfo->defaultTZFileSize);
+                fread(tzInfo->defaultTZBuffer, 1, tzInfo->defaultTZFileSize, tzInfo->defaultTZFilePtr);
+            }
+            rewind(file);
+            while(sizeFileLeft > 0) {
+                uprv_memset(bufferFile, 0, MAX_READ_SIZE);
+                sizeFileToRead = sizeFileLeft < MAX_READ_SIZE ? sizeFileLeft : MAX_READ_SIZE;
+
+                sizeFileRead = fread(bufferFile, 1, sizeFileToRead, file);
+                if (memcmp(tzInfo->defaultTZBuffer + tzInfo->defaultTZPosition, bufferFile, sizeFileRead) != 0) {
+                    result = FALSE;
+                    break;
+                }
+                sizeFileLeft -= sizeFileRead;
+                tzInfo->defaultTZPosition += sizeFileRead;
+            }
+        }
+    } else {
+        result = FALSE;
+    }
+
+    if (file != NULL) {
+        fclose(file);
+    }
+
+    return result;
+}
+/*
+ * This method recursively traverses the directory given for a matching TZ file and returns the first match.
+ */
+/* dirent also lists two entries: "." and ".." that we can safely ignore. */
+#define SKIP1 "."
+#define SKIP2 ".."
+static char SEARCH_TZFILE_RESULT[MAX_PATH_SIZE] = "";
+static char* searchForTZFile(const char* path, DefaultTZInfo* tzInfo) {
+    char curpath[MAX_PATH_SIZE];
+    DIR* dirp = opendir(path);
+    DIR* subDirp = NULL;
+    struct dirent* dirEntry = NULL;
+
+    char* result = NULL;
+    if (dirp == NULL) {
+        return result;
+    }
+
+    /* Save the current path */
+    uprv_memset(curpath, 0, MAX_PATH_SIZE);
+    uprv_strcpy(curpath, path);
+
+    /* Check each entry in the directory. */
+    while((dirEntry = readdir(dirp)) != NULL) {
+        const char* dirName = dirEntry->d_name;
+        if (uprv_strcmp(dirName, SKIP1) != 0 && uprv_strcmp(dirName, SKIP2) != 0) {
+            /* Create a newpath with the new entry to test each entry in the directory. */
+            char newpath[MAX_PATH_SIZE];
+            uprv_strcpy(newpath, curpath);
+            uprv_strcat(newpath, dirName);
+
+            if ((subDirp = opendir(newpath)) != NULL) {
+                /* If this new path is a directory, make a recursive call with the newpath. */
+                closedir(subDirp);
+                uprv_strcat(newpath, "/");
+                result = searchForTZFile(newpath, tzInfo);
+                /*
+                 Have to get out here. Otherwise, we'd keep looking
+                 and return the first match in the top-level directory
+                 if there's a match in the top-level. If not, this function
+                 would return NULL and set gTimeZoneBufferPtr to NULL in initDefault().
+                 It worked without this in most cases because we have a fallback of calling
+                 localtime_r to figure out the default timezone.
+                */
+                if (result != NULL)
+                    break;
+            } else if (uprv_strcmp(TZFILE_SKIP, dirName) != 0 && uprv_strcmp(TZFILE_SKIP2, dirName) != 0) {
+                if(compareBinaryFiles(TZDEFAULT, newpath, tzInfo)) {
+                    const char* zoneid = newpath + (sizeof(TZZONEINFO)) - 1;
+                    skipZoneIDPrefix(&zoneid);
+                    uprv_strcpy(SEARCH_TZFILE_RESULT, zoneid);
+                    result = SEARCH_TZFILE_RESULT;
+                    /* Get out after the first one found. */
+                    break;
+                }
+            }
+        }
+    }
+    closedir(dirp);
+    return result;
+}
+#endif
+U_CAPI const char* U_EXPORT2
+uprv_tzname(int n)
+{
+    const char *tzid = NULL;
+#ifdef U_WINDOWS
+    tzid = uprv_detectWindowsTimeZone();
+
+    if (tzid != NULL) {
+        return tzid;
+    }
+#else
+
+/*#if defined(U_DARWIN)
+    int ret;
+
+    tzid = getenv("TZFILE");
+    if (tzid != NULL) {
+        return tzid;
+    }
+#endif*/
+
+/* This code can be temporarily disabled to test tzname resolution later on. */
+#ifndef DEBUG_TZNAME
+    tzid = getenv("TZ");
+    if (tzid != NULL && isValidOlsonID(tzid))
+    {
+        /* This might be a good Olson ID. */
+        skipZoneIDPrefix(&tzid);
+        return tzid;
+    }
+    /* else U_TZNAME will give a better result. */
+#endif
+
+#if defined(CHECK_LOCALTIME_LINK)
+    /* Caller must handle threading issues */
+    if (gTimeZoneBufferPtr == NULL) {
+        /*
+        This is a trick to look at the name of the link to get the Olson ID
+        because the tzfile contents is underspecified.
+        This isn't guaranteed to work because it may not be a symlink.
+        */
+        int32_t ret = (int32_t)readlink(TZDEFAULT, gTimeZoneBuffer, sizeof(gTimeZoneBuffer));
+        if (0 < ret) {
+            int32_t tzZoneInfoLen = uprv_strlen(TZZONEINFO);
+            gTimeZoneBuffer[ret] = 0;
+            if (uprv_strncmp(gTimeZoneBuffer, TZZONEINFO, tzZoneInfoLen) == 0
+                && isValidOlsonID(gTimeZoneBuffer + tzZoneInfoLen))
+            {
+                return (gTimeZoneBufferPtr = gTimeZoneBuffer + tzZoneInfoLen);
+            }
+        } else {
+#if defined(SEARCH_TZFILE)
+            DefaultTZInfo* tzInfo = (DefaultTZInfo*)uprv_malloc(sizeof(DefaultTZInfo));
+            if (tzInfo != NULL) {
+                tzInfo->defaultTZBuffer = NULL;
+                tzInfo->defaultTZFileSize = 0;
+                tzInfo->defaultTZFilePtr = NULL;
+                tzInfo->defaultTZstatus = FALSE;
+                tzInfo->defaultTZPosition = 0;
+
+                gTimeZoneBufferPtr = searchForTZFile(TZZONEINFO, tzInfo);
+
+                /* Free previously allocated memory */
+                if (tzInfo->defaultTZBuffer != NULL) {
+                    uprv_free(tzInfo->defaultTZBuffer);
+                }
+                if (tzInfo->defaultTZFilePtr != NULL) {
+                    fclose(tzInfo->defaultTZFilePtr);
+                }
+                uprv_free(tzInfo);
+            }
+
+            if (gTimeZoneBufferPtr != NULL && isValidOlsonID(gTimeZoneBufferPtr)) {
+                return gTimeZoneBufferPtr;
+            }
+#endif
+        }
+    }
+    else {
+        return gTimeZoneBufferPtr;
+    }
+#endif
+#endif
+
+#ifdef U_TZNAME
+#ifdef U_WINDOWS
+    /* The return value is free'd in timezone.cpp on Windows because
+     * the other code path returns a pointer to a heap location. */
+    return uprv_strdup(U_TZNAME[n]);
+#else
+    /*
+    U_TZNAME is usually a non-unique abbreviation, which isn't normally usable.
+    So we remap the abbreviation to an olson ID.
+
+    Since Windows exposes a little more timezone information,
+    we normally don't use this code on Windows because
+    uprv_detectWindowsTimeZone should have already given the correct answer.
+    */
+    {
+        struct tm juneSol, decemberSol;
+        int daylightType;
+        static const time_t juneSolstice=1182478260; /*2007-06-21 18:11 UT*/
+        static const time_t decemberSolstice=1198332540; /*2007-12-22 06:09 UT*/
+
+        /* This probing will tell us when daylight savings occurs.  */
+        localtime_r(&juneSolstice, &juneSol);
+        localtime_r(&decemberSolstice, &decemberSol);
+        daylightType = ((decemberSol.tm_isdst > 0) << 1) | (juneSol.tm_isdst > 0);
+        tzid = remapShortTimeZone(U_TZNAME[0], U_TZNAME[1], daylightType, uprv_timezone());
+        if (tzid != NULL) {
+            return tzid;
+        }
+    }
+    return U_TZNAME[n];
+#endif
+#else
+    return "";
+#endif
+}
+
+/* Get and set the ICU data directory --------------------------------------- */
+
+static char *gDataDirectory = NULL;
+#if U_POSIX_LOCALE
+ static char *gCorrectedPOSIXLocale = NULL; /* Heap allocated */
+#endif
+
+static UBool U_CALLCONV putil_cleanup(void)
+{
+    if (gDataDirectory && *gDataDirectory) {
+        uprv_free(gDataDirectory);
+    }
+    gDataDirectory = NULL;
+#if U_POSIX_LOCALE
+    if (gCorrectedPOSIXLocale) {
+        uprv_free(gCorrectedPOSIXLocale);
+        gCorrectedPOSIXLocale = NULL;
+    }
+#endif
+    return TRUE;
+}
+
+/*
+ * Set the data directory.
+ *    Make a copy of the passed string, and set the global data dir to point to it.
+ *    TODO:  see bug #2849, regarding thread safety.
+ */
+U_CAPI void U_EXPORT2
+u_setDataDirectory(const char *directory) {
+    char *newDataDir;
+    int32_t length;
+
+    if(directory==NULL || *directory==0) {
+        /* A small optimization to prevent the malloc and copy when the
+        shared library is used, and this is a way to make sure that NULL
+        is never returned.
+        */
+        newDataDir = (char *)"";
+    }
+    else {
+        length=(int32_t)uprv_strlen(directory);
+        newDataDir = (char *)uprv_malloc(length + 2);
+        /* Exit out if newDataDir could not be created. */
+        if (newDataDir == NULL) {
+            return;
+        }
+        uprv_strcpy(newDataDir, directory);
+
+#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
+        {
+            char *p;
+            while(p = uprv_strchr(newDataDir, U_FILE_ALT_SEP_CHAR)) {
+                *p = U_FILE_SEP_CHAR;
+            }
+        }
+#endif
+    }
+
+    umtx_lock(NULL);
+    if (gDataDirectory && *gDataDirectory) {
+        uprv_free(gDataDirectory);
+    }
+    gDataDirectory = newDataDir;
+    ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
+    umtx_unlock(NULL);
+}
+
+U_CAPI UBool U_EXPORT2
+uprv_pathIsAbsolute(const char *path)
+{
+  if(!path || !*path) {
+    return FALSE;
+  }
+
+  if(*path == U_FILE_SEP_CHAR) {
+    return TRUE;
+  }
+
+#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
+  if(*path == U_FILE_ALT_SEP_CHAR) {
+    return TRUE;
+  }
+#endif
+
+#if defined(U_WINDOWS)
+  if( (((path[0] >= 'A') && (path[0] <= 'Z')) ||
+       ((path[0] >= 'a') && (path[0] <= 'z'))) &&
+      path[1] == ':' ) {
+    return TRUE;
+  }
+#endif
+
+  return FALSE;
+}
+
+/* Temporary backup setting of ICU_DATA_DIR_PREFIX_ENV_VAR
+   until some client wrapper makefiles are updated */
+#if defined(U_DARWIN) && TARGET_IPHONE_SIMULATOR
+# if !defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
+#  define ICU_DATA_DIR_PREFIX_ENV_VAR "IPHONE_SIMULATOR_ROOT"
+# endif
+#endif
+
+U_CAPI const char * U_EXPORT2
+u_getDataDirectory(void) {
+    const char *path = NULL;
+#if defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
+    char datadir_path_buffer[PATH_MAX];
+#endif
+
+    /* if we have the directory, then return it immediately */
+    UMTX_CHECK(NULL, gDataDirectory, path);
+
+    if(path) {
+        return path;
+    }
+
+    /*
+    When ICU_NO_USER_DATA_OVERRIDE is defined, users aren't allowed to
+    override ICU's data with the ICU_DATA environment variable. This prevents
+    problems where multiple custom copies of ICU's specific version of data
+    are installed on a system. Either the application must define the data
+    directory with u_setDataDirectory, define ICU_DATA_DIR when compiling
+    ICU, set the data with udata_setCommonData or trust that all of the
+    required data is contained in ICU's data library that contains
+    the entry point defined by U_ICUDATA_ENTRY_POINT.
+
+    There may also be some platforms where environment variables
+    are not allowed.
+    */
+#   if !defined(ICU_NO_USER_DATA_OVERRIDE) && !UCONFIG_NO_FILE_IO
+    /* First try to get the environment variable */
+    path=getenv("ICU_DATA");
+#   endif
+
+    /* ICU_DATA_DIR may be set as a compile option.
+     * U_ICU_DATA_DEFAULT_DIR is provided and is set by ICU at compile time
+     * and is used only when data is built in archive mode eliminating the need
+     * for ICU_DATA_DIR to be set. U_ICU_DATA_DEFAULT_DIR is set to the installation
+     * directory of the data dat file. Users should use ICU_DATA_DIR if they want to
+     * set their own path.
+     */
+#if defined(ICU_DATA_DIR) || defined(U_ICU_DATA_DEFAULT_DIR)
+    if(path==NULL || *path==0) {
+# if defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
+        const char *prefix = getenv(ICU_DATA_DIR_PREFIX_ENV_VAR);
+# endif
+# ifdef ICU_DATA_DIR
+        path=ICU_DATA_DIR;
+# else
+        path=U_ICU_DATA_DEFAULT_DIR;
+# endif
+# if defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
+        if (prefix != NULL) {
+            snprintf(datadir_path_buffer, PATH_MAX, "%s%s", prefix, path);
+            path=datadir_path_buffer;
+        }
+# endif
+    }
+#endif
+
+    if(path==NULL) {
+        /* It looks really bad, set it to something. */
+        path = "";
+    }
+
+    u_setDataDirectory(path);
+    return gDataDirectory;
+}
+
+
+
+
+
+/* Macintosh-specific locale information ------------------------------------ */
+#ifdef XP_MAC
+
+typedef struct {
+    int32_t script;
+    int32_t region;
+    int32_t lang;
+    int32_t date_region;
+    const char* posixID;
+} mac_lc_rec;
+
+/* Todo: This will be updated with a newer version from www.unicode.org web
+   page when it's available.*/
+#define MAC_LC_MAGIC_NUMBER -5
+#define MAC_LC_INIT_NUMBER -9
+
+static const mac_lc_rec mac_lc_recs[] = {
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 0, "en_US",
+    /* United States*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 1, "fr_FR",
+    /* France*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 2, "en_GB",
+    /* Great Britain*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 3, "de_DE",
+    /* Germany*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 4, "it_IT",
+    /* Italy*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 5, "nl_NL",
+    /* Metherlands*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 6, "fr_BE",
+    /* French for Belgium or Lxembourg*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 7, "sv_SE",
+    /* Sweden*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 9, "da_DK",
+    /* Denmark*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 10, "pt_PT",
+    /* Portugal*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 11, "fr_CA",
+    /* French Canada*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 13, "is_IS",
+    /* Israel*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 14, "ja_JP",
+    /* Japan*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 15, "en_AU",
+    /* Australia*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 16, "ar_AE",
+    /* the Arabic world (?)*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 17, "fi_FI",
+    /* Finland*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 18, "fr_CH",
+    /* French for Switzerland*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 19, "de_CH",
+    /* German for Switzerland*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 20, "el_GR",
+    /* Greece*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 21, "is_IS",
+    /* Iceland ===*/
+    /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 22, "",*/
+    /* Malta ===*/
+    /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 23, "",*/
+    /* Cyprus ===*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 24, "tr_TR",
+    /* Turkey ===*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 25, "sh_YU",
+    /* Croatian system for Yugoslavia*/
+    /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 33, "",*/
+    /* Hindi system for India*/
+    /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 34, "",*/
+    /* Pakistan*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 41, "lt_LT",
+    /* Lithuania*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 42, "pl_PL",
+    /* Poland*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 43, "hu_HU",
+    /* Hungary*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 44, "et_EE",
+    /* Estonia*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 45, "lv_LV",
+    /* Latvia*/
+    /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 46, "",*/
+    /* Lapland  [Ask Rich for the data. HS]*/
+    /*MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 47, "",*/
+    /* Faeroe Islands*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 48, "fa_IR",
+    /* Iran*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 49, "ru_RU",
+    /* Russia*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 50, "en_IE",
+    /* Ireland*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 51, "ko_KR",
+    /* Korea*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 52, "zh_CN",
+    /* People's Republic of China*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 53, "zh_TW",
+    /* Taiwan*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, 54, "th_TH",
+    /* Thailand*/
+
+    /* fallback is en_US*/
+    MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER, MAC_LC_MAGIC_NUMBER,
+    MAC_LC_MAGIC_NUMBER, "en_US"
+};
+
+#endif
+
+#if U_POSIX_LOCALE
+/* A helper function used by uprv_getPOSIXIDForDefaultLocale and
+ * uprv_getPOSIXIDForDefaultCodepage. Returns the posix locale id for
+ * LC_CTYPE and LC_MESSAGES. It doesn't support other locale categories.
+ */
+static const char *uprv_getPOSIXIDForCategory(int category)
+{
+    const char* posixID = NULL;
+    if (category == LC_MESSAGES || category == LC_CTYPE) {
+        /*
+        * On Solaris two different calls to setlocale can result in
+        * different values. Only get this value once.
+        *
+        * We must check this first because an application can set this.
+        *
+        * LC_ALL can't be used because it's platform dependent. The LANG
+        * environment variable seems to affect LC_CTYPE variable by default.
+        * Here is what setlocale(LC_ALL, NULL) can return.
+        * HPUX can return 'C C C C C C C'
+        * Solaris can return /en_US/C/C/C/C/C on the second try.
+        * Linux can return LC_CTYPE=C;LC_NUMERIC=C;...
+        *
+        * The default codepage detection also needs to use LC_CTYPE.
+        *
+        * Do not call setlocale(LC_*, "")! Using an empty string instead
+        * of NULL, will modify the libc behavior.
+        */
+        posixID = setlocale(category, NULL);
+        if ((posixID == 0)
+            || (uprv_strcmp("C", posixID) == 0)
+            || (uprv_strcmp("POSIX", posixID) == 0))
+        {
+            /* Maybe we got some garbage.  Try something more reasonable */
+            posixID = getenv("LC_ALL");
+            if (posixID == 0) {
+                posixID = getenv(category == LC_MESSAGES ? "LC_MESSAGES" : "LC_CTYPE");
+                if (posixID == 0) {
+                    posixID = getenv("LANG");
+                }
+            }
+        }
+    }
+    if ((posixID==0)
+        || (uprv_strcmp("C", posixID) == 0)
+        || (uprv_strcmp("POSIX", posixID) == 0))
+    {
+        /* Nothing worked.  Give it a nice POSIX default value. */
+        posixID = "en_US_POSIX";
+    }
+    return posixID;
+}
+
+/* Return just the POSIX id for the default locale, whatever happens to be in
+ * it. It gets the value from LC_MESSAGES and indirectly from LC_ALL and LANG.
+ */
+static const char *uprv_getPOSIXIDForDefaultLocale(void)
+{
+    static const char* posixID = NULL;
+    if (posixID == 0) {
+        posixID = uprv_getPOSIXIDForCategory(LC_MESSAGES);
+    }
+    return posixID;
+}
+
+/* Return just the POSIX id for the default codepage, whatever happens to be in
+ * it. It gets the value from LC_CTYPE and indirectly from LC_ALL and LANG.
+ */
+static const char *uprv_getPOSIXIDForDefaultCodepage(void)
+{
+    static const char* posixID = NULL;
+    if (posixID == 0) {
+        posixID = uprv_getPOSIXIDForCategory(LC_CTYPE);
+    }
+    return posixID;
+}
+#endif
+
+/* NOTE: The caller should handle thread safety */
+U_CAPI const char* U_EXPORT2
+uprv_getDefaultLocaleID()
+{
+#if U_POSIX_LOCALE
+/*
+  Note that:  (a '!' means the ID is improper somehow)
+     LC_ALL  ---->     default_loc          codepage
+--------------------------------------------------------
+     ab.CD             ab                   CD
+     ab@CD             ab__CD               -
+     ab@CD.EF          ab__CD               EF
+
+     ab_CD.EF@GH       ab_CD_GH             EF
+
+Some 'improper' ways to do the same as above:
+  !  ab_CD@GH.EF       ab_CD_GH             EF
+  !  ab_CD.EF@GH.IJ    ab_CD_GH             EF
+  !  ab_CD@ZZ.EF@GH.IJ ab_CD_GH             EF
+
+     _CD@GH            _CD_GH               -
+     _CD.EF@GH         _CD_GH               EF
+
+The variant cannot have dots in it.
+The 'rightmost' variant (@xxx) wins.
+The leftmost codepage (.xxx) wins.
+*/
+    char *correctedPOSIXLocale = 0;
+    const char* posixID = uprv_getPOSIXIDForDefaultLocale();
+    const char *p;
+    const char *q;
+    int32_t len;
+
+    /* Format: (no spaces)
+    ll [ _CC ] [ . MM ] [ @ VV]
+
+      l = lang, C = ctry, M = charmap, V = variant
+    */
+
+    if (gCorrectedPOSIXLocale != NULL) {
+        return gCorrectedPOSIXLocale;
+    }
+
+    if ((p = uprv_strchr(posixID, '.')) != NULL) {
+        /* assume new locale can't be larger than old one? */
+        correctedPOSIXLocale = uprv_malloc(uprv_strlen(posixID)+1);
+        /* Exit on memory allocation error. */
+        if (correctedPOSIXLocale == NULL) {
+            return NULL;
+        }
+        uprv_strncpy(correctedPOSIXLocale, posixID, p-posixID);
+        correctedPOSIXLocale[p-posixID] = 0;
+
+        /* do not copy after the @ */
+        if ((p = uprv_strchr(correctedPOSIXLocale, '@')) != NULL) {
+            correctedPOSIXLocale[p-correctedPOSIXLocale] = 0;
+        }
+    }
+
+    /* Note that we scan the *uncorrected* ID. */
+    if ((p = uprv_strrchr(posixID, '@')) != NULL) {
+        if (correctedPOSIXLocale == NULL) {
+            correctedPOSIXLocale = uprv_malloc(uprv_strlen(posixID)+1);
+            /* Exit on memory allocation error. */
+            if (correctedPOSIXLocale == NULL) {
+                return NULL;
+            }
+            uprv_strncpy(correctedPOSIXLocale, posixID, p-posixID);
+            correctedPOSIXLocale[p-posixID] = 0;
+        }
+        p++;
+
+        /* Take care of any special cases here.. */
+        if (!uprv_strcmp(p, "nynorsk")) {
+            p = "NY";
+            /* Don't worry about no__NY. In practice, it won't appear. */
+        }
+
+        if (uprv_strchr(correctedPOSIXLocale,'_') == NULL) {
+            uprv_strcat(correctedPOSIXLocale, "__"); /* aa@b -> aa__b */
+        }
+        else {
+            uprv_strcat(correctedPOSIXLocale, "_"); /* aa_CC@b -> aa_CC_b */
+        }
+
+        if ((q = uprv_strchr(p, '.')) != NULL) {
+            /* How big will the resulting string be? */
+            len = (int32_t)(uprv_strlen(correctedPOSIXLocale) + (q-p));
+            uprv_strncat(correctedPOSIXLocale, p, q-p);
+            correctedPOSIXLocale[len] = 0;
+        }
+        else {
+            /* Anything following the @ sign */
+            uprv_strcat(correctedPOSIXLocale, p);
+        }
+
+        /* Should there be a map from 'no@nynorsk' -> no_NO_NY here?
+         * How about 'russian' -> 'ru'?
+         * Many of the other locales using ISO codes will be handled by the
+         * canonicalization functions in uloc_getDefault.
+         */
+    }
+
+    /* Was a correction made? */
+    if (correctedPOSIXLocale != NULL) {
+        posixID = correctedPOSIXLocale;
+    }
+    else {
+        /* copy it, just in case the original pointer goes away.  See j2395 */
+        correctedPOSIXLocale = (char *)uprv_malloc(uprv_strlen(posixID) + 1);
+        /* Exit on memory allocation error. */
+        if (correctedPOSIXLocale == NULL) {
+            return NULL;
+        }
+        posixID = uprv_strcpy(correctedPOSIXLocale, posixID);
+    }
+
+    if (gCorrectedPOSIXLocale == NULL) {
+        gCorrectedPOSIXLocale = correctedPOSIXLocale;
+        ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
+        correctedPOSIXLocale = NULL;
+    }
+
+    if (correctedPOSIXLocale != NULL) {  /* Was already set - clean up. */
+        uprv_free(correctedPOSIXLocale);
+    }
+
+    return posixID;
+
+#elif defined(U_WINDOWS)
+    UErrorCode status = U_ZERO_ERROR;
+    LCID id = GetThreadLocale();
+    const char* locID = uprv_convertToPosix(id, &status);
+
+    if (U_FAILURE(status)) {
+        locID = "en_US";
+    }
+    return locID;
+
+#elif defined(XP_MAC)
+    int32_t script = MAC_LC_INIT_NUMBER;
+    /* = IntlScript(); or GetScriptManagerVariable(smSysScript);*/
+    int32_t region = MAC_LC_INIT_NUMBER;
+    /* = GetScriptManagerVariable(smRegionCode);*/
+    int32_t lang = MAC_LC_INIT_NUMBER;
+    /* = GetScriptManagerVariable(smScriptLang);*/
+    int32_t date_region = MAC_LC_INIT_NUMBER;
+    const char* posixID = 0;
+    int32_t count = sizeof(mac_lc_recs) / sizeof(mac_lc_rec);
+    int32_t i;
+    Intl1Hndl ih;
+
+    ih = (Intl1Hndl) GetIntlResource(1);
+    if (ih)
+        date_region = ((uint16_t)(*ih)->intl1Vers) >> 8;
+
+    for (i = 0; i < count; i++) {
+        if (   ((mac_lc_recs[i].script == MAC_LC_MAGIC_NUMBER)
+             || (mac_lc_recs[i].script == script))
+            && ((mac_lc_recs[i].region == MAC_LC_MAGIC_NUMBER)
+             || (mac_lc_recs[i].region == region))
+            && ((mac_lc_recs[i].lang == MAC_LC_MAGIC_NUMBER)
+             || (mac_lc_recs[i].lang == lang))
+            && ((mac_lc_recs[i].date_region == MAC_LC_MAGIC_NUMBER)
+             || (mac_lc_recs[i].date_region == date_region))
+            )
+        {
+            posixID = mac_lc_recs[i].posixID;
+            break;
+        }
+    }
+
+    return posixID;
+
+#elif defined(OS400)
+    /* locales are process scoped and are by definition thread safe */
+    static char correctedLocale[64];
+    const  char *localeID = getenv("LC_ALL");
+           char *p;
+
+    if (localeID == NULL)
+        localeID = getenv("LANG");
+    if (localeID == NULL)
+        localeID = setlocale(LC_ALL, NULL);
+    /* Make sure we have something... */
+    if (localeID == NULL)
+        return "en_US_POSIX";
+
+    /* Extract the locale name from the path. */
+    if((p = uprv_strrchr(localeID, '/')) != NULL)
+    {
+        /* Increment p to start of locale name. */
+        p++;
+        localeID = p;
+    }
+
+    /* Copy to work location. */
+    uprv_strcpy(correctedLocale, localeID);
+
+    /* Strip off the '.locale' extension. */
+    if((p = uprv_strchr(correctedLocale, '.')) != NULL) {
+        *p = 0;
+    }
+
+    /* Upper case the locale name. */
+    T_CString_toUpperCase(correctedLocale);
+
+    /* See if we are using the POSIX locale.  Any of the
+    * following are equivalent and use the same QLGPGCMA
+    * (POSIX) locale.
+    * QLGPGCMA2 means UCS2
+    * QLGPGCMA_4 means UTF-32
+    * QLGPGCMA_8 means UTF-8
+    */
+    if ((uprv_strcmp("C", correctedLocale) == 0) ||
+        (uprv_strcmp("POSIX", correctedLocale) == 0) ||
+        (uprv_strncmp("QLGPGCMA", correctedLocale, 8) == 0))
+    {
+        uprv_strcpy(correctedLocale, "en_US_POSIX");
+    }
+    else
+    {
+        int16_t LocaleLen;
+
+        /* Lower case the lang portion. */
+        for(p = correctedLocale; *p != 0 && *p != '_'; p++)
+        {
+            *p = uprv_tolower(*p);
+        }
+
+        /* Adjust for Euro.  After '_E' add 'URO'. */
+        LocaleLen = uprv_strlen(correctedLocale);
+        if (correctedLocale[LocaleLen - 2] == '_' &&
+            correctedLocale[LocaleLen - 1] == 'E')
+        {
+            uprv_strcat(correctedLocale, "URO");
+        }
+
+        /* If using Lotus-based locale then convert to
+         * equivalent non Lotus.
+         */
+        else if (correctedLocale[LocaleLen - 2] == '_' &&
+            correctedLocale[LocaleLen - 1] == 'L')
+        {
+            correctedLocale[LocaleLen - 2] = 0;
+        }
+
+        /* There are separate simplified and traditional
+         * locales called zh_HK_S and zh_HK_T.
+         */
+        else if (uprv_strncmp(correctedLocale, "zh_HK", 5) == 0)
+        {
+            uprv_strcpy(correctedLocale, "zh_HK");
+        }
+
+        /* A special zh_CN_GBK locale...
+        */
+        else if (uprv_strcmp(correctedLocale, "zh_CN_GBK") == 0)
+        {
+            uprv_strcpy(correctedLocale, "zh_CN");
+        }
+
+    }
+
+    return correctedLocale;
+#endif
+
+}
+
+#if !U_CHARSET_IS_UTF8
+#if U_POSIX_LOCALE
+/*
+Due to various platform differences, one platform may specify a charset,
+when they really mean a different charset. Remap the names so that they are
+compatible with ICU. Only conflicting/ambiguous aliases should be resolved
+here. Before adding anything to this function, please consider adding unique
+names to the ICU alias table in the data directory.
+*/
+static const char*
+remapPlatformDependentCodepage(const char *locale, const char *name) {
+    if (locale != NULL && *locale == 0) {
+        /* Make sure that an empty locale is handled the same way. */
+        locale = NULL;
+    }
+    if (name == NULL) {
+        return NULL;
+    }
+#if defined(U_AIX)
+    if (uprv_strcmp(name, "IBM-943") == 0) {
+        /* Use the ASCII compatible ibm-943 */
+        name = "Shift-JIS";
+    }
+    else if (uprv_strcmp(name, "IBM-1252") == 0) {
+        /* Use the windows-1252 that contains the Euro */
+        name = "IBM-5348";
+    }
+#elif defined(U_SOLARIS)
+    if (locale != NULL && uprv_strcmp(name, "EUC") == 0) {
+        /* Solaris underspecifies the "EUC" name. */
+        if (uprv_strcmp(locale, "zh_CN") == 0) {
+            name = "EUC-CN";
+        }
+        else if (uprv_strcmp(locale, "zh_TW") == 0) {
+            name = "EUC-TW";
+        }
+        else if (uprv_strcmp(locale, "ko_KR") == 0) {
+            name = "EUC-KR";
+        }
+    }
+    else if (uprv_strcmp(name, "eucJP") == 0) {
+        /*
+        ibm-954 is the best match.
+        ibm-33722 is the default for eucJP (similar to Windows).
+        */
+        name = "eucjis";
+    }
+    else if (uprv_strcmp(name, "646") == 0) {
+        /*
+         * The default codepage given by Solaris is 646 but the C library routines treat it as if it was
+         * ISO-8859-1 instead of US-ASCII(646).
+         */
+        name = "ISO-8859-1";
+    }
+#elif defined(U_DARWIN)
+    if (locale == NULL && *name == 0) {
+        /*
+        No locale was specified, and an empty name was passed in.
+        This usually indicates that nl_langinfo didn't return valid information.
+        Mac OS X uses UTF-8 by default (especially the locale data and console).
+        */
+        name = "UTF-8";
+    }
+    else if (uprv_strcmp(name, "CP949") == 0) {
+        /* Remap CP949 to a similar codepage to avoid issues with backslash and won symbol. */
+        name = "EUC-KR";
+    }
+    else if (locale != NULL && uprv_strcmp(locale, "en_US_POSIX") != 0 && uprv_strcmp(name, "US-ASCII") == 0) {
+        /*
+         * For non C/POSIX locale, default the code page to UTF-8 instead of US-ASCII.
+         */
+        name = "UTF-8";
+    }
+#elif defined(U_BSD)
+    if (uprv_strcmp(name, "CP949") == 0) {
+        /* Remap CP949 to a similar codepage to avoid issues with backslash and won symbol. */
+        name = "EUC-KR";
+    }
+#elif defined(U_HPUX)
+    if (locale != NULL && uprv_strcmp(locale, "zh_HK") == 0 && uprv_strcmp(name, "big5") == 0) {
+        /* HP decided to extend big5 as hkbig5 even though it's not compatible :-( */
+        /* zh_TW.big5 is not the same charset as zh_HK.big5! */
+        name = "hkbig5";
+    }
+    else if (uprv_strcmp(name, "eucJP") == 0) {
+        /*
+        ibm-1350 is the best match, but unavailable.
+        ibm-954 is mostly a superset of ibm-1350.
+        ibm-33722 is the default for eucJP (similar to Windows).
+        */
+        name = "eucjis";
+    }
+#elif defined(U_LINUX)
+    if (locale != NULL && uprv_strcmp(name, "euc") == 0) {
+        /* Linux underspecifies the "EUC" name. */
+        if (uprv_strcmp(locale, "korean") == 0) {
+            name = "EUC-KR";
+        }
+        else if (uprv_strcmp(locale, "japanese") == 0) {
+            /* See comment below about eucJP */
+            name = "eucjis";
+        }
+    }
+    else if (uprv_strcmp(name, "eucjp") == 0) {
+        /*
+        ibm-1350 is the best match, but unavailable.
+        ibm-954 is mostly a superset of ibm-1350.
+        ibm-33722 is the default for eucJP (similar to Windows).
+        */
+        name = "eucjis";
+    }
+    else if (locale != NULL && uprv_strcmp(locale, "en_US_POSIX") != 0 &&
+            (uprv_strcmp(name, "ANSI_X3.4-1968") == 0 || uprv_strcmp(name, "US-ASCII") == 0)) {
+        /*
+         * For non C/POSIX locale, default the code page to UTF-8 instead of US-ASCII.
+         */
+        name = "UTF-8";
+    }
+    /*
+     * Linux returns ANSI_X3.4-1968 for C/POSIX, but the call site takes care of
+     * it by falling back to 'US-ASCII' when NULL is returned from this
+     * function. So, we don't have to worry about it here.
+     */
+#endif
+    /* return NULL when "" is passed in */
+    if (*name == 0) {
+        name = NULL;
+    }
+    return name;
+}
+
+static const char*
+getCodepageFromPOSIXID(const char *localeName, char * buffer, int32_t buffCapacity)
+{
+    char localeBuf[100];
+    const char *name = NULL;
+    char *variant = NULL;
+
+    if (localeName != NULL && (name = (uprv_strchr(localeName, '.'))) != NULL) {
+        size_t localeCapacity = uprv_min(sizeof(localeBuf), (name-localeName)+1);
+        uprv_strncpy(localeBuf, localeName, localeCapacity);
+        localeBuf[localeCapacity-1] = 0; /* ensure NULL termination */
+        name = uprv_strncpy(buffer, name+1, buffCapacity);
+        buffer[buffCapacity-1] = 0; /* ensure NULL termination */
+        if ((variant = (uprv_strchr(name, '@'))) != NULL) {
+            *variant = 0;
+        }
+        name = remapPlatformDependentCodepage(localeBuf, name);
+    }
+    return name;
+}
+#endif
+
+static const char*
+int_getDefaultCodepage()
+{
+#if defined(OS400)
+    uint32_t ccsid = 37; /* Default to ibm-37 */
+    static char codepage[64];
+    Qwc_JOBI0400_t jobinfo;
+    Qus_EC_t error = { sizeof(Qus_EC_t) }; /* SPI error code */
+
+    EPT_CALL(QUSRJOBI)(&jobinfo, sizeof(jobinfo), "JOBI0400",
+        "*                         ", "                ", &error);
+
+    if (error.Bytes_Available == 0) {
+        if (jobinfo.Coded_Char_Set_ID != 0xFFFF) {
+            ccsid = (uint32_t)jobinfo.Coded_Char_Set_ID;
+        }
+        else if (jobinfo.Default_Coded_Char_Set_Id != 0xFFFF) {
+            ccsid = (uint32_t)jobinfo.Default_Coded_Char_Set_Id;
+        }
+        /* else use the default */
+    }
+    sprintf(codepage,"ibm-%d", ccsid);
+    return codepage;
+
+#elif defined(OS390)
+    static char codepage[64];
+
+    strncpy(codepage, nl_langinfo(CODESET),63-strlen(UCNV_SWAP_LFNL_OPTION_STRING));
+    strcat(codepage,UCNV_SWAP_LFNL_OPTION_STRING);
+    codepage[63] = 0; /* NULL terminate */
+
+    return codepage;
+
+#elif defined(XP_MAC)
+    return "macintosh"; /* TODO: Macintosh Roman. There must be a better way. fixme! */
+
+#elif defined(U_WINDOWS)
+    static char codepage[64];
+    sprintf(codepage, "windows-%d", GetACP());
+    return codepage;
+
+#elif U_POSIX_LOCALE
+    static char codesetName[100];
+    const char *localeName = NULL;
+    const char *name = NULL;
+
+    localeName = uprv_getPOSIXIDForDefaultCodepage();
+    uprv_memset(codesetName, 0, sizeof(codesetName));
+#if U_HAVE_NL_LANGINFO_CODESET
+    /* When available, check nl_langinfo first because it usually gives more
+       useful names. It depends on LC_CTYPE.
+       nl_langinfo may use the same buffer as setlocale. */
+    {
+        const char *codeset = nl_langinfo(U_NL_LANGINFO_CODESET);
+#if defined(U_DARWIN) || defined(U_LINUX)
+        /*
+         * On Linux and MacOSX, ensure that default codepage for non C/POSIX locale is UTF-8
+         * instead of ASCII.
+         */
+        if (uprv_strcmp(localeName, "en_US_POSIX") != 0) {
+            codeset = remapPlatformDependentCodepage(localeName, codeset);
+        } else
+#endif
+        {
+            codeset = remapPlatformDependentCodepage(NULL, codeset);
+        }
+
+        if (codeset != NULL) {
+            uprv_strncpy(codesetName, codeset, sizeof(codesetName));
+            codesetName[sizeof(codesetName)-1] = 0;
+            return codesetName;
+        }
+    }
+#endif
+
+    /* Use setlocale in a nice way, and then check some environment variables.
+       Maybe the application used setlocale already.
+    */
+    uprv_memset(codesetName, 0, sizeof(codesetName));
+    name = getCodepageFromPOSIXID(localeName, codesetName, sizeof(codesetName));
+    if (name) {
+        /* if we can find the codeset name from setlocale, return that. */
+        return name;
+    }
+
+    if (*codesetName == 0)
+    {
+        /* Everything failed. Return US ASCII (ISO 646). */
+        (void)uprv_strcpy(codesetName, "US-ASCII");
+    }
+    return codesetName;
+#else
+    return "US-ASCII";
+#endif
+}
+
+
+U_CAPI const char*  U_EXPORT2
+uprv_getDefaultCodepage()
+{
+    static char const  *name = NULL;
+    umtx_lock(NULL);
+    if (name == NULL) {
+        name = int_getDefaultCodepage();
+    }
+    umtx_unlock(NULL);
+    return name;
+}
+#endif  /* !U_CHARSET_IS_UTF8 */
+
+
+/* end of platform-specific implementation -------------- */
+
+/* version handling --------------------------------------------------------- */
+
+U_CAPI void U_EXPORT2
+u_versionFromString(UVersionInfo versionArray, const char *versionString) {
+    char *end;
+    uint16_t part=0;
+
+    if(versionArray==NULL) {
+        return;
+    }
+
+    if(versionString!=NULL) {
+        for(;;) {
+            versionArray[part]=(uint8_t)uprv_strtoul(versionString, &end, 10);
+            if(end==versionString || ++part==U_MAX_VERSION_LENGTH || *end!=U_VERSION_DELIMITER) {
+                break;
+            }
+            versionString=end+1;
+        }
+    }
+
+    while(part<U_MAX_VERSION_LENGTH) {
+        versionArray[part++]=0;
+    }
+}
+
+U_CAPI void U_EXPORT2
+u_versionFromUString(UVersionInfo versionArray, const UChar *versionString) {
+    if(versionArray!=NULL && versionString!=NULL) {
+        char versionChars[U_MAX_VERSION_STRING_LENGTH+1];
+        int32_t len = u_strlen(versionString);
+        if(len>U_MAX_VERSION_STRING_LENGTH) {
+            len = U_MAX_VERSION_STRING_LENGTH;
+        }
+        u_UCharsToChars(versionString, versionChars, len);
+        versionChars[len]=0;
+        u_versionFromString(versionArray, versionChars);
+    }
+}
+
+U_CAPI void U_EXPORT2
+u_versionToString(UVersionInfo versionArray, char *versionString) {
+    uint16_t count, part;
+    uint8_t field;
+
+    if(versionString==NULL) {
+        return;
+    }
+
+    if(versionArray==NULL) {
+        versionString[0]=0;
+        return;
+    }
+
+    /* count how many fields need to be written */
+    for(count=4; count>0 && versionArray[count-1]==0; --count) {
+    }
+
+    if(count <= 1) {
+        count = 2;
+    }
+
+    /* write the first part */
+    /* write the decimal field value */
+    field=versionArray[0];
+    if(field>=100) {
+        *versionString++=(char)('0'+field/100);
+        field%=100;
+    }
+    if(field>=10) {
+        *versionString++=(char)('0'+field/10);
+        field%=10;
+    }
+    *versionString++=(char)('0'+field);
+
+    /* write the following parts */
+    for(part=1; part<count; ++part) {
+        /* write a dot first */
+        *versionString++=U_VERSION_DELIMITER;
+
+        /* write the decimal field value */
+        field=versionArray[part];
+        if(field>=100) {
+            *versionString++=(char)('0'+field/100);
+            field%=100;
+        }
+        if(field>=10) {
+            *versionString++=(char)('0'+field/10);
+            field%=10;
+        }
+        *versionString++=(char)('0'+field);
+    }
+
+    /* NUL-terminate */
+    *versionString=0;
+}
+
+U_CAPI void U_EXPORT2
+u_getVersion(UVersionInfo versionArray) {
+    u_versionFromString(versionArray, U_ICU_VERSION);
+}
+
+/**
+ * icucfg.h dependent code 
+ */
+
+#if U_ENABLE_DYLOAD
+ 
+#if defined(U_CHECK_DYLOAD)
+
+#if defined(HAVE_DLOPEN) 
+
+#ifdef HAVE_DLFCN_H
+#ifdef __MVS__
+#ifndef __SUSV3
+#define __SUSV3 1
+#endif
+#endif
+#include <dlfcn.h>
+#endif
+
+U_INTERNAL void * U_EXPORT2
+uprv_dl_open(const char *libName, UErrorCode *status) {
+  void *ret = NULL;
+  if(U_FAILURE(*status)) return ret;
+  ret =  dlopen(libName, RTLD_NOW|RTLD_GLOBAL);
+  if(ret==NULL) {
+#ifndef U_TRACE_DYLOAD
+    perror("dlopen");
+#endif
+    *status = U_MISSING_RESOURCE_ERROR;
+  }
+  return ret;
+}
+
+U_INTERNAL void U_EXPORT2
+uprv_dl_close(void *lib, UErrorCode *status) {
+  if(U_FAILURE(*status)) return;
+  dlclose(lib);
+}
+
+U_INTERNAL void* U_EXPORT2
+uprv_dl_sym(void *lib, const char* sym, UErrorCode *status) {
+  void *ret = NULL;
+  if(U_FAILURE(*status)) return ret;
+  ret = dlsym(lib, sym);
+  if(ret == NULL) {
+    *status = U_MISSING_RESOURCE_ERROR;
+  }
+  return ret;
+}
+
+#else
+
+/* null (nonexistent) implementation. */
+
+U_INTERNAL void * U_EXPORT2
+uprv_dl_open(const char *libName, UErrorCode *status) {
+  if(U_FAILURE(*status)) return NULL;
+  *status = U_UNSUPPORTED_ERROR;
+  return NULL;
+}
+
+U_INTERNAL void U_EXPORT2
+uprv_dl_close(void *lib, UErrorCode *status) {
+  if(U_FAILURE(*status)) return;
+  *status = U_UNSUPPORTED_ERROR;
+  return;
+}
+
+
+U_INTERNAL void* U_EXPORT2
+uprv_dl_sym(void *lib, const char* sym, UErrorCode *status) {
+  if(U_FAILURE(*status)) return NULL;
+  *status = U_UNSUPPORTED_ERROR;
+  return NULL;
+}
+
+
+
+#endif
+
+#elif defined U_WINDOWS
+
+U_INTERNAL void * U_EXPORT2
+uprv_dl_open(const char *libName, UErrorCode *status) {
+  HMODULE lib = NULL;
+  
+  if(U_FAILURE(*status)) return NULL;
+  
+  lib = LoadLibrary(libName);
+  
+  if(lib==NULL) {
+    *status = U_MISSING_RESOURCE_ERROR;
+  }
+  
+  return (void*)lib;
+}
+
+U_INTERNAL void U_EXPORT2
+uprv_dl_close(void *lib, UErrorCode *status) {
+  HMODULE handle = (HMODULE)lib;
+  if(U_FAILURE(*status)) return;
+  
+  FreeLibrary(handle);
+  
+  return;
+}
+
+
+U_INTERNAL void* U_EXPORT2
+uprv_dl_sym(void *lib, const char* sym, UErrorCode *status) {
+  HMODULE handle = (HMODULE)lib;
+  void * addr = NULL;
+  
+  if(U_FAILURE(*status) || lib==NULL) return NULL;
+  
+  addr = GetProcAddress(handle, sym);
+  
+  if(addr==NULL) {
+    DWORD lastError = GetLastError();
+    if(lastError == ERROR_PROC_NOT_FOUND) {
+      *status = U_MISSING_RESOURCE_ERROR;
+    } else {
+      *status = U_UNSUPPORTED_ERROR; /* other unknown error. */
+    }
+  }
+  
+  return addr;
+}
+
+
+#else
+
+/* No dynamic loading set. */
+
+U_INTERNAL void * U_EXPORT2
+uprv_dl_open(const char *libName, UErrorCode *status) {
+    if(U_FAILURE(*status)) return NULL;
+    *status = U_UNSUPPORTED_ERROR;
+    return NULL;
+}
+
+U_INTERNAL void U_EXPORT2
+uprv_dl_close(void *lib, UErrorCode *status) {
+    if(U_FAILURE(*status)) return;
+    *status = U_UNSUPPORTED_ERROR;
+    return;
+}
+
+
+U_INTERNAL void* U_EXPORT2
+uprv_dl_sym(void *lib, const char* sym, UErrorCode *status) {
+    if(U_FAILURE(*status)) return NULL;
+    *status = U_UNSUPPORTED_ERROR;
+    return NULL;
+}
+
+
+#endif
+
+#endif /* U_ENABLE_DYLOAD */
+
+/*
+ * Hey, Emacs, please set the following:
+ *
+ * Local Variables:
+ * indent-tabs-mode: nil
+ * End:
+ *
+ */
diff --git a/source/common/putilimp.h b/source/common/putilimp.h
new file mode 100644
index 0000000..93de6a0
--- /dev/null
+++ b/source/common/putilimp.h
@@ -0,0 +1,310 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+*  FILE NAME : putilimp.h
+*
+*   Date        Name        Description
+*   10/17/04    grhoten     Move internal functions from putil.h to this file.
+******************************************************************************
+*/
+
+#ifndef PUTILIMP_H
+#define PUTILIMP_H
+
+#include "unicode/utypes.h"
+#include "unicode/putil.h"
+
+/*==========================================================================*/
+/* Platform utilities                                                       */
+/*==========================================================================*/
+
+/**
+ * Platform utilities isolates the platform dependencies of the
+ * libarary.  For each platform which this code is ported to, these
+ * functions may have to be re-implemented.
+ */
+
+/**
+ * Floating point utility to determine if a double is Not a Number (NaN).
+ * @internal
+ */
+U_INTERNAL UBool   U_EXPORT2 uprv_isNaN(double d);
+/**
+ * Floating point utility to determine if a double has an infinite value.
+ * @internal
+ */
+U_INTERNAL UBool   U_EXPORT2 uprv_isInfinite(double d);
+/**
+ * Floating point utility to determine if a double has a positive infinite value.
+ * @internal
+ */
+U_INTERNAL UBool   U_EXPORT2 uprv_isPositiveInfinity(double d);
+/**
+ * Floating point utility to determine if a double has a negative infinite value.
+ * @internal
+ */
+U_INTERNAL UBool   U_EXPORT2 uprv_isNegativeInfinity(double d);
+/**
+ * Floating point utility that returns a Not a Number (NaN) value.
+ * @internal
+ */
+U_INTERNAL double  U_EXPORT2 uprv_getNaN(void);
+/**
+ * Floating point utility that returns an infinite value.
+ * @internal
+ */
+U_INTERNAL double  U_EXPORT2 uprv_getInfinity(void);
+
+/**
+ * Floating point utility to truncate a double.
+ * @internal
+ */
+U_INTERNAL double  U_EXPORT2 uprv_trunc(double d);
+/**
+ * Floating point utility to calculate the floor of a double.
+ * @internal
+ */
+U_INTERNAL double  U_EXPORT2 uprv_floor(double d);
+/**
+ * Floating point utility to calculate the ceiling of a double.
+ * @internal
+ */
+U_INTERNAL double  U_EXPORT2 uprv_ceil(double d);
+/**
+ * Floating point utility to calculate the absolute value of a double.
+ * @internal
+ */
+U_INTERNAL double  U_EXPORT2 uprv_fabs(double d);
+/**
+ * Floating point utility to calculate the fractional and integer parts of a double.
+ * @internal
+ */
+U_INTERNAL double  U_EXPORT2 uprv_modf(double d, double* pinteger);
+/**
+ * Floating point utility to calculate the remainder of a double divided by another double.
+ * @internal
+ */
+U_INTERNAL double  U_EXPORT2 uprv_fmod(double d, double y);
+/**
+ * Floating point utility to calculate d to the power of exponent (d^exponent).
+ * @internal
+ */
+U_INTERNAL double  U_EXPORT2 uprv_pow(double d, double exponent);
+/**
+ * Floating point utility to calculate 10 to the power of exponent (10^exponent).
+ * @internal
+ */
+U_INTERNAL double  U_EXPORT2 uprv_pow10(int32_t exponent);
+/**
+ * Floating point utility to calculate the maximum value of two doubles.
+ * @internal
+ */
+U_INTERNAL double  U_EXPORT2 uprv_fmax(double d, double y);
+/**
+ * Floating point utility to calculate the minimum value of two doubles.
+ * @internal
+ */
+U_INTERNAL double  U_EXPORT2 uprv_fmin(double d, double y);
+/**
+ * Private utility to calculate the maximum value of two integers.
+ * @internal
+ */
+U_INTERNAL int32_t U_EXPORT2 uprv_max(int32_t d, int32_t y);
+/**
+ * Private utility to calculate the minimum value of two integers.
+ * @internal
+ */
+U_INTERNAL int32_t U_EXPORT2 uprv_min(int32_t d, int32_t y);
+
+#if U_IS_BIG_ENDIAN
+#   define uprv_isNegative(number) (*((signed char *)&(number))<0)
+#else
+#   define uprv_isNegative(number) (*((signed char *)&(number)+sizeof(number)-1)<0)
+#endif
+
+/**
+ * Return the largest positive number that can be represented by an integer
+ * type of arbitrary bit length.
+ * @internal
+ */
+U_INTERNAL double  U_EXPORT2 uprv_maxMantissa(void);
+
+/**
+ * Floating point utility to calculate the logarithm of a double.
+ * @internal
+ */
+U_INTERNAL double  U_EXPORT2 uprv_log(double d);
+
+/**
+ * Does common notion of rounding e.g. uprv_floor(x + 0.5);
+ * @param x the double number
+ * @return the rounded double
+ * @internal
+ */
+U_INTERNAL double  U_EXPORT2 uprv_round(double x);
+
+#if 0
+/**
+ * Returns the number of digits after the decimal point in a double number x.
+ *
+ * @param x the double number
+ * @return the number of digits after the decimal point in a double number x.
+ * @internal
+ */
+/*U_INTERNAL int32_t  U_EXPORT2 uprv_digitsAfterDecimal(double x);*/
+#endif
+
+/**
+ * Time zone utilities
+ *
+ * Wrappers for C runtime library functions relating to timezones.
+ * The t_tzset() function (similar to tzset) uses the current setting
+ * of the environment variable TZ to assign values to three global
+ * variables: daylight, timezone, and tzname. These variables have the
+ * following meanings, and are declared in &lt;time.h&gt;.
+ *
+ *   daylight   Nonzero if daylight-saving-time zone (DST) is specified
+ *              in TZ; otherwise, 0. Default value is 1.
+ *   timezone   Difference in seconds between coordinated universal
+ *              time and local time. E.g., -28,800 for PST (GMT-8hrs)
+ *   tzname(0)  Three-letter time-zone name derived from TZ environment
+ *              variable. E.g., "PST".
+ *   tzname(1)  Three-letter DST zone name derived from TZ environment
+ *              variable.  E.g., "PDT". If DST zone is omitted from TZ,
+ *              tzname(1) is an empty string.
+ *
+ * Notes: For example, to set the TZ environment variable to correspond
+ * to the current time zone in Germany, you can use one of the
+ * following statements:
+ *
+ *   set TZ=GST1GDT
+ *   set TZ=GST+1GDT
+ *
+ * If the TZ value is not set, t_tzset() attempts to use the time zone
+ * information specified by the operating system. Under Windows NT
+ * and Windows 95, this information is specified in the Control Panel's
+ * Date/Time application.
+ * @internal
+ */
+U_INTERNAL void     U_EXPORT2 uprv_tzset(void);
+
+/**
+ * Difference in seconds between coordinated universal
+ * time and local time. E.g., -28,800 for PST (GMT-8hrs)
+ * @return the difference in seconds between coordinated universal time and local time.
+ * @internal
+ */
+U_INTERNAL int32_t  U_EXPORT2 uprv_timezone(void);
+
+/**
+ *   tzname(0)  Three-letter time-zone name derived from TZ environment
+ *              variable. E.g., "PST".
+ *   tzname(1)  Three-letter DST zone name derived from TZ environment
+ *              variable.  E.g., "PDT". If DST zone is omitted from TZ,
+ *              tzname(1) is an empty string.
+ * @internal
+ */
+U_INTERNAL const char* U_EXPORT2 uprv_tzname(int n);
+
+/**
+ * Get UTC (GMT) time measured in milliseconds since 0:00 on 1/1/1970.
+ * This function is affected by 'faketime' and should be the bottleneck for all user-visible ICU time functions.
+ * @return the UTC time measured in milliseconds
+ * @internal
+ */
+U_INTERNAL UDate U_EXPORT2 uprv_getUTCtime(void);
+
+/**
+ * Get UTC (GMT) time measured in milliseconds since 0:00 on 1/1/1970.
+ * This function is not affected by 'faketime', so it should only be used by low level test functions- not by anything that
+ * exposes time to the end user.
+ * @return the UTC time measured in milliseconds
+ * @internal
+ */
+U_INTERNAL UDate U_EXPORT2 uprv_getRawUTCtime(void);
+
+/**
+ * Determine whether a pathname is absolute or not, as defined by the platform.
+ * @param path Pathname to test
+ * @return TRUE if the path is absolute
+ * @internal (ICU 3.0)
+ */
+U_INTERNAL UBool U_EXPORT2 uprv_pathIsAbsolute(const char *path);
+
+/**
+ * Use U_MAX_PTR instead of this function.
+ * @param void pointer to test
+ * @return the largest possible pointer greater than the base
+ * @internal (ICU 3.8)
+ */
+U_INTERNAL void * U_EXPORT2 uprv_maximumPtr(void *base);
+
+/**
+ * Maximum value of a (void*) - use to indicate the limit of an 'infinite' buffer.
+ * In fact, buffer sizes must not exceed 2GB so that the difference between
+ * the buffer limit and the buffer start can be expressed in an int32_t.
+ *
+ * The definition of U_MAX_PTR must fulfill the following conditions:
+ * - return the largest possible pointer greater than base
+ * - return a valid pointer according to the machine architecture (AS/400, 64-bit, etc.)
+ * - avoid wrapping around at high addresses
+ * - make sure that the returned pointer is not farther from base than 0x7fffffff
+ *
+ * @param base The beginning of a buffer to find the maximum offset from
+ * @internal
+ */
+#ifndef U_MAX_PTR
+#  if defined(OS390) && !defined(_LP64)
+    /* We have 31-bit pointers. */
+#    define U_MAX_PTR(base) ((void *)0x7fffffff)
+#  elif defined(OS400)
+#    define U_MAX_PTR(base) uprv_maximumPtr((void *)base)
+#  elif defined(__GNUC__) && __GNUC__ >= 4
+/*
+ * Due to a compiler optimization bug, gcc 4 causes test failures when doing
+ * this math arithmetic on pointers on some platforms. It seems like the
+ * pointers are considered signed instead of unsigned. The uintptr_t type
+ * isn't available on all platforms (i.e MSVC 6) and pointers aren't always
+ * a scalar value (i.e. i5/OS see uprv_maximumPtr function).
+ */
+#    define U_MAX_PTR(base) \
+    ((void *)(((uintptr_t)(base)+0x7fffffffu) > (uintptr_t)(base) \
+        ? ((uintptr_t)(base)+0x7fffffffu) \
+        : (uintptr_t)-1))
+#  else
+#    define U_MAX_PTR(base) \
+    ((char *)(((char *)(base)+0x7fffffffu) > (char *)(base) \
+        ? ((char *)(base)+0x7fffffffu) \
+        : (char *)-1))
+#  endif
+#endif
+
+#if U_ENABLE_DYLOAD
+/*  Dynamic Library Functions */
+
+/**
+ * Load a library
+ * @internal (ICU 4.4)
+ */
+U_INTERNAL void * U_EXPORT2 uprv_dl_open(const char *libName, UErrorCode *status);
+
+/**
+ * Close a library
+ * @internal (ICU 4.4)
+ */
+U_INTERNAL void U_EXPORT2 uprv_dl_close( void *lib, UErrorCode *status);
+
+/**
+ * Extract a symbol from a library
+ * @internal (ICU 4.4)
+ */
+U_INTERNAL void * U_EXPORT2 uprv_dl_sym( void *lib, const char *symbolName, UErrorCode *status);
+
+#endif
+
+#endif
diff --git a/source/common/rbbi.cpp b/source/common/rbbi.cpp
new file mode 100644
index 0000000..2615a4b
--- /dev/null
+++ b/source/common/rbbi.cpp
@@ -0,0 +1,1879 @@
+/*
+***************************************************************************
+*   Copyright (C) 1999-2010 International Business Machines Corporation
+*   and others. All rights reserved.
+***************************************************************************
+*/
+//
+//  file:  rbbi.c    Contains the implementation of the rule based break iterator
+//                   runtime engine and the API implementation for
+//                   class RuleBasedBreakIterator
+//
+
+#include <typeinfo>  // for 'typeid' to work
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/rbbi.h"
+#include "unicode/schriter.h"
+#include "unicode/uchriter.h"
+#include "unicode/udata.h"
+#include "unicode/uclean.h"
+#include "rbbidata.h"
+#include "rbbirb.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "umutex.h"
+#include "ucln_cmn.h"
+#include "brkeng.h"
+
+#include "uassert.h"
+#include "uvector.h"
+
+// if U_LOCAL_SERVICE_HOOK is defined, then localsvc.cpp is expected to be included.
+#if U_LOCAL_SERVICE_HOOK
+#include "localsvc.h"
+#endif
+
+#ifdef RBBI_DEBUG
+static UBool fTrace = FALSE;
+#endif
+
+U_NAMESPACE_BEGIN
+
+// The state number of the starting state
+#define START_STATE 1
+
+// The state-transition value indicating "stop"
+#define STOP_STATE  0
+
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedBreakIterator)
+
+
+//=======================================================================
+// constructors
+//=======================================================================
+
+/**
+ * Constructs a RuleBasedBreakIterator that uses the already-created
+ * tables object that is passed in as a parameter.
+ */
+RuleBasedBreakIterator::RuleBasedBreakIterator(RBBIDataHeader* data, UErrorCode &status)
+{
+    init();
+    fData = new RBBIDataWrapper(data, status); // status checked in constructor
+    if (U_FAILURE(status)) {return;}
+    if(fData == 0) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+}
+
+/**
+ * Same as above but does not adopt memory
+ */
+RuleBasedBreakIterator::RuleBasedBreakIterator(const RBBIDataHeader* data, enum EDontAdopt, UErrorCode &status)
+{
+    init();
+    fData = new RBBIDataWrapper(data, RBBIDataWrapper::kDontAdopt, status); // status checked in constructor
+    if (U_FAILURE(status)) {return;}
+    if(fData == 0) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+}
+
+//-------------------------------------------------------------------------------
+//
+//   Constructor   from a UDataMemory handle to precompiled break rules
+//                 stored in an ICU data file.
+//
+//-------------------------------------------------------------------------------
+RuleBasedBreakIterator::RuleBasedBreakIterator(UDataMemory* udm, UErrorCode &status)
+{
+    init();
+    fData = new RBBIDataWrapper(udm, status); // status checked in constructor
+    if (U_FAILURE(status)) {return;}
+    if(fData == 0) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+}
+
+
+
+//-------------------------------------------------------------------------------
+//
+//   Constructor       from a set of rules supplied as a string.
+//
+//-------------------------------------------------------------------------------
+RuleBasedBreakIterator::RuleBasedBreakIterator( const UnicodeString  &rules,
+                                                UParseError          &parseError,
+                                                UErrorCode           &status)
+{
+    init();
+    if (U_FAILURE(status)) {return;}
+    RuleBasedBreakIterator *bi = (RuleBasedBreakIterator *)
+        RBBIRuleBuilder::createRuleBasedBreakIterator(rules, &parseError, status);
+    // Note:  This is a bit awkward.  The RBBI ruleBuilder has a factory method that
+    //        creates and returns a complete RBBI.  From here, in a constructor, we
+    //        can't just return the object created by the builder factory, hence
+    //        the assignment of the factory created object to "this".
+    if (U_SUCCESS(status)) {
+        *this = *bi;
+        delete bi;
+    }
+}
+
+
+//-------------------------------------------------------------------------------
+//
+// Default Constructor.      Create an empty shell that can be set up later.
+//                           Used when creating a RuleBasedBreakIterator from a set
+//                           of rules.
+//-------------------------------------------------------------------------------
+RuleBasedBreakIterator::RuleBasedBreakIterator() {
+    init();
+}
+
+
+//-------------------------------------------------------------------------------
+//
+//   Copy constructor.  Will produce a break iterator with the same behavior,
+//                      and which iterates over the same text, as the one passed in.
+//
+//-------------------------------------------------------------------------------
+RuleBasedBreakIterator::RuleBasedBreakIterator(const RuleBasedBreakIterator& other)
+: BreakIterator(other)
+{
+    this->init();
+    *this = other;
+}
+
+
+/**
+ * Destructor
+ */
+RuleBasedBreakIterator::~RuleBasedBreakIterator() {
+    if (fCharIter!=fSCharIter && fCharIter!=fDCharIter) {
+        // fCharIter was adopted from the outside.
+        delete fCharIter;
+    }
+    fCharIter = NULL;
+    delete fSCharIter;
+    fCharIter = NULL;
+    delete fDCharIter;
+    fDCharIter = NULL;
+    
+    utext_close(fText);
+
+    if (fData != NULL) {
+        fData->removeReference();
+        fData = NULL;
+    }
+    if (fCachedBreakPositions) {
+        uprv_free(fCachedBreakPositions);
+        fCachedBreakPositions = NULL;
+    }
+    if (fLanguageBreakEngines) {
+        delete fLanguageBreakEngines;
+        fLanguageBreakEngines = NULL;
+    }
+    if (fUnhandledBreakEngine) {
+        delete fUnhandledBreakEngine;
+        fUnhandledBreakEngine = NULL;
+    }
+}
+
+/**
+ * Assignment operator.  Sets this iterator to have the same behavior,
+ * and iterate over the same text, as the one passed in.
+ */
+RuleBasedBreakIterator&
+RuleBasedBreakIterator::operator=(const RuleBasedBreakIterator& that) {
+    if (this == &that) {
+        return *this;
+    }
+    reset();    // Delete break cache information
+    fBreakType = that.fBreakType;
+    if (fLanguageBreakEngines != NULL) {
+        delete fLanguageBreakEngines;
+        fLanguageBreakEngines = NULL;   // Just rebuild for now
+    }
+    // TODO: clone fLanguageBreakEngines from "that"
+    UErrorCode status = U_ZERO_ERROR;
+    fText = utext_clone(fText, that.fText, FALSE, TRUE, &status);
+
+    if (fCharIter!=fSCharIter && fCharIter!=fDCharIter) {
+        delete fCharIter;
+    }
+    fCharIter = NULL;
+
+    if (that.fCharIter != NULL ) {
+        // This is a little bit tricky - it will intially appear that
+        //  this->fCharIter is adopted, even if that->fCharIter was
+        //  not adopted.  That's ok.
+        fCharIter = that.fCharIter->clone();
+    }
+
+    if (fData != NULL) {
+        fData->removeReference();
+        fData = NULL;
+    }
+    if (that.fData != NULL) {
+        fData = that.fData->addReference();
+    }
+
+    return *this;
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+//    init()      Shared initialization routine.   Used by all the constructors.
+//                Initializes all fields, leaving the object in a consistent state.
+//
+//-----------------------------------------------------------------------------
+void RuleBasedBreakIterator::init() {
+    UErrorCode  status    = U_ZERO_ERROR;
+    fBufferClone          = FALSE;
+    fText                 = utext_openUChars(NULL, NULL, 0, &status);
+    fCharIter             = NULL;
+    fSCharIter            = NULL;
+    fDCharIter            = NULL;
+    fData                 = NULL;
+    fLastRuleStatusIndex  = 0;
+    fLastStatusIndexValid = TRUE;
+    fDictionaryCharCount  = 0;
+    fBreakType            = UBRK_WORD;  // Defaulting BreakType to word gives reasonable
+                                        //   dictionary behavior for Break Iterators that are
+                                        //   built from rules.  Even better would be the ability to
+                                        //   declare the type in the rules.
+
+    fCachedBreakPositions    = NULL;
+    fLanguageBreakEngines    = NULL;
+    fUnhandledBreakEngine    = NULL;
+    fNumCachedBreakPositions = 0;
+    fPositionInCache         = 0;
+
+#ifdef RBBI_DEBUG
+    static UBool debugInitDone = FALSE;
+    if (debugInitDone == FALSE) {
+        char *debugEnv = getenv("U_RBBIDEBUG");
+        if (debugEnv && uprv_strstr(debugEnv, "trace")) {
+            fTrace = TRUE;
+        }
+        debugInitDone = TRUE;
+    }
+#endif
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+//    clone - Returns a newly-constructed RuleBasedBreakIterator with the same
+//            behavior, and iterating over the same text, as this one.
+//            Virtual function: does the right thing with subclasses.
+//
+//-----------------------------------------------------------------------------
+BreakIterator*
+RuleBasedBreakIterator::clone(void) const {
+    return new RuleBasedBreakIterator(*this);
+}
+
+/**
+ * Equality operator.  Returns TRUE if both BreakIterators are of the
+ * same class, have the same behavior, and iterate over the same text.
+ */
+UBool
+RuleBasedBreakIterator::operator==(const BreakIterator& that) const {
+    if (typeid(*this) != typeid(that)) {
+        return FALSE;
+    }
+
+    const RuleBasedBreakIterator& that2 = (const RuleBasedBreakIterator&) that;
+
+    if (!utext_equals(fText, that2.fText)) {
+        // The two break iterators are operating on different text,
+        //   or have a different interation position.
+        return FALSE;
+    };
+
+    // TODO:  need a check for when in a dictionary region at different offsets.
+
+    if (that2.fData == fData ||
+        (fData != NULL && that2.fData != NULL && *that2.fData == *fData)) {
+            // The two break iterators are using the same rules.
+            return TRUE;
+        }
+    return FALSE;
+}
+
+/**
+ * Compute a hash code for this BreakIterator
+ * @return A hash code
+ */
+int32_t
+RuleBasedBreakIterator::hashCode(void) const {
+    int32_t   hash = 0;
+    if (fData != NULL) {
+        hash = fData->hashCode();
+    }
+    return hash;
+}
+
+
+void RuleBasedBreakIterator::setText(UText *ut, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return;
+    }
+    reset();
+    fText = utext_clone(fText, ut, FALSE, TRUE, &status);
+
+    // Set up a dummy CharacterIterator to be returned if anyone
+    //   calls getText().  With input from UText, there is no reasonable
+    //   way to return a characterIterator over the actual input text.
+    //   Return one over an empty string instead - this is the closest
+    //   we can come to signaling a failure.
+    //   (GetText() is obsolete, this failure is sort of OK)
+    if (fDCharIter == NULL) {
+        static const UChar c = 0;
+        fDCharIter = new UCharCharacterIterator(&c, 0);
+        if (fDCharIter == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+    }
+
+    if (fCharIter!=fSCharIter && fCharIter!=fDCharIter) {
+        // existing fCharIter was adopted from the outside.  Delete it now.
+        delete fCharIter;
+    }
+    fCharIter = fDCharIter;
+
+    this->first();
+}
+
+
+UText *RuleBasedBreakIterator::getUText(UText *fillIn, UErrorCode &status) const {
+    UText *result = utext_clone(fillIn, fText, FALSE, TRUE, &status);  
+    return result;
+}
+
+
+
+/**
+ * Returns the description used to create this iterator
+ */
+const UnicodeString&
+RuleBasedBreakIterator::getRules() const {
+    if (fData != NULL) {
+        return fData->getRuleSourceString();
+    } else {
+        static const UnicodeString *s;
+        if (s == NULL) {
+            // TODO:  something more elegant here.
+            //        perhaps API should return the string by value.
+            //        Note:  thread unsafe init & leak are semi-ok, better than
+            //               what was before.  Sould be cleaned up, though.
+            s = new UnicodeString;
+        }
+        return *s;
+    }
+}
+
+//=======================================================================
+// BreakIterator overrides
+//=======================================================================
+
+/**
+ * Return a CharacterIterator over the text being analyzed.  
+ */
+CharacterIterator&
+RuleBasedBreakIterator::getText() const {
+    return *fCharIter;
+}
+
+/**
+ * Set the iterator to analyze a new piece of text.  This function resets
+ * the current iteration position to the beginning of the text.
+ * @param newText An iterator over the text to analyze.
+ */
+void
+RuleBasedBreakIterator::adoptText(CharacterIterator* newText) {
+    // If we are holding a CharacterIterator adopted from a 
+    //   previous call to this function, delete it now.
+    if (fCharIter!=fSCharIter && fCharIter!=fDCharIter) {
+        delete fCharIter;
+    }
+
+    fCharIter = newText;
+    UErrorCode status = U_ZERO_ERROR;
+    reset();
+    if (newText==NULL || newText->startIndex() != 0) {   
+        // startIndex !=0 wants to be an error, but there's no way to report it.
+        // Make the iterator text be an empty string.
+        fText = utext_openUChars(fText, NULL, 0, &status);
+    } else {
+        fText = utext_openCharacterIterator(fText, newText, &status);
+    }
+    this->first();
+}
+
+/**
+ * Set the iterator to analyze a new piece of text.  This function resets
+ * the current iteration position to the beginning of the text.
+ * @param newText An iterator over the text to analyze.
+ */
+void
+RuleBasedBreakIterator::setText(const UnicodeString& newText) {
+    UErrorCode status = U_ZERO_ERROR;
+    reset();
+    fText = utext_openConstUnicodeString(fText, &newText, &status);
+
+    // Set up a character iterator on the string.  
+    //   Needed in case someone calls getText().
+    //  Can not, unfortunately, do this lazily on the (probably never)
+    //  call to getText(), because getText is const.
+    if (fSCharIter == NULL) {
+        fSCharIter = new StringCharacterIterator(newText);
+    } else {
+        fSCharIter->setText(newText);
+    }
+
+    if (fCharIter!=fSCharIter && fCharIter!=fDCharIter) {
+        // old fCharIter was adopted from the outside.  Delete it.
+        delete fCharIter;
+    }
+    fCharIter = fSCharIter;
+
+    this->first();
+}
+
+
+
+/**
+ * Sets the current iteration position to the beginning of the text.
+ * @return The offset of the beginning of the text.
+ */
+int32_t RuleBasedBreakIterator::first(void) {
+    reset();
+    fLastRuleStatusIndex  = 0;
+    fLastStatusIndexValid = TRUE;
+    //if (fText == NULL)
+    //    return BreakIterator::DONE;
+
+    utext_setNativeIndex(fText, 0);
+    return 0;
+}
+
+/**
+ * Sets the current iteration position to the end of the text.
+ * @return The text's past-the-end offset.
+ */
+int32_t RuleBasedBreakIterator::last(void) {
+    reset();
+    if (fText == NULL) {
+        fLastRuleStatusIndex  = 0;
+        fLastStatusIndexValid = TRUE;
+        return BreakIterator::DONE;
+    }
+
+    fLastStatusIndexValid = FALSE;
+    int32_t pos = (int32_t)utext_nativeLength(fText);
+    utext_setNativeIndex(fText, pos);
+    return pos;
+}
+
+/**
+ * Advances the iterator either forward or backward the specified number of steps.
+ * Negative values move backward, and positive values move forward.  This is
+ * equivalent to repeatedly calling next() or previous().
+ * @param n The number of steps to move.  The sign indicates the direction
+ * (negative is backwards, and positive is forwards).
+ * @return The character offset of the boundary position n boundaries away from
+ * the current one.
+ */
+int32_t RuleBasedBreakIterator::next(int32_t n) {
+    int32_t result = current();
+    while (n > 0) {
+        result = next();
+        --n;
+    }
+    while (n < 0) {
+        result = previous();
+        ++n;
+    }
+    return result;
+}
+
+/**
+ * Advances the iterator to the next boundary position.
+ * @return The position of the first boundary after this one.
+ */
+int32_t RuleBasedBreakIterator::next(void) {
+    // if we have cached break positions and we're still in the range
+    // covered by them, just move one step forward in the cache
+    if (fCachedBreakPositions != NULL) {
+        if (fPositionInCache < fNumCachedBreakPositions - 1) {
+            ++fPositionInCache;
+            int32_t pos = fCachedBreakPositions[fPositionInCache];
+            utext_setNativeIndex(fText, pos);
+            return pos;
+        }
+        else {
+            reset();
+        }
+    }
+
+    int32_t startPos = current();
+    int32_t result = handleNext(fData->fForwardTable);
+    if (fDictionaryCharCount > 0) {
+        result = checkDictionary(startPos, result, FALSE);
+    }
+    return result;
+}
+
+/**
+ * Advances the iterator backwards, to the last boundary preceding this one.
+ * @return The position of the last boundary position preceding this one.
+ */
+int32_t RuleBasedBreakIterator::previous(void) {
+    int32_t result;
+    int32_t startPos;
+
+    // if we have cached break positions and we're still in the range
+    // covered by them, just move one step backward in the cache
+    if (fCachedBreakPositions != NULL) {
+        if (fPositionInCache > 0) {
+            --fPositionInCache;
+            // If we're at the beginning of the cache, need to reevaluate the
+            // rule status
+            if (fPositionInCache <= 0) {
+                fLastStatusIndexValid = FALSE;
+            }
+            int32_t pos = fCachedBreakPositions[fPositionInCache];
+            utext_setNativeIndex(fText, pos);
+            return pos;
+        }
+        else {
+            reset();
+        }
+    }
+
+    // if we're already sitting at the beginning of the text, return DONE
+    if (fText == NULL || (startPos = current()) == 0) {
+        fLastRuleStatusIndex  = 0;
+        fLastStatusIndexValid = TRUE;
+        return BreakIterator::DONE;
+    }
+
+    if (fData->fSafeRevTable != NULL || fData->fSafeFwdTable != NULL) {
+        result = handlePrevious(fData->fReverseTable);
+        if (fDictionaryCharCount > 0) {
+            result = checkDictionary(result, startPos, TRUE);
+        }
+        return result;
+    }
+
+    // old rule syntax
+    // set things up.  handlePrevious() will back us up to some valid
+    // break position before the current position (we back our internal
+    // iterator up one step to prevent handlePrevious() from returning
+    // the current position), but not necessarily the last one before
+
+    // where we started
+
+    int32_t start = current();
+
+    UTEXT_PREVIOUS32(fText);
+    int32_t lastResult    = handlePrevious(fData->fReverseTable);
+    if (lastResult == UBRK_DONE) {
+        lastResult = 0;
+        utext_setNativeIndex(fText, 0);
+    }
+    result = lastResult;
+    int32_t lastTag       = 0;
+    UBool   breakTagValid = FALSE;
+
+    // iterate forward from the known break position until we pass our
+    // starting point.  The last break position before the starting
+    // point is our return value
+
+    for (;;) {
+        result         = next();
+        if (result == BreakIterator::DONE || result >= start) {
+            break;
+        }
+        lastResult     = result;
+        lastTag        = fLastRuleStatusIndex;
+        breakTagValid  = TRUE;
+    }
+
+    // fLastBreakTag wants to have the value for section of text preceding
+    // the result position that we are to return (in lastResult.)  If
+    // the backwards rules overshot and the above loop had to do two or more
+    // next()s to move up to the desired return position, we will have a valid
+    // tag value. But, if handlePrevious() took us to exactly the correct result positon,
+    // we wont have a tag value for that position, which is only set by handleNext().
+
+    // set the current iteration position to be the last break position
+    // before where we started, and then return that value
+    utext_setNativeIndex(fText, lastResult);
+    fLastRuleStatusIndex  = lastTag;       // for use by getRuleStatus()
+    fLastStatusIndexValid = breakTagValid;
+
+    // No need to check the dictionary; it will have been handled by
+    // next()
+
+    return lastResult;
+}
+
+/**
+ * Sets the iterator to refer to the first boundary position following
+ * the specified position.
+ * @offset The position from which to begin searching for a break position.
+ * @return The position of the first break after the current position.
+ */
+int32_t RuleBasedBreakIterator::following(int32_t offset) {
+    // if we have cached break positions and offset is in the range
+    // covered by them, use them
+    // TODO: could use binary search
+    // TODO: what if offset is outside range, but break is not?
+    if (fCachedBreakPositions != NULL) {
+        if (offset >= fCachedBreakPositions[0]
+                && offset < fCachedBreakPositions[fNumCachedBreakPositions - 1]) {
+            fPositionInCache = 0;
+            // We are guaranteed not to leave the array due to range test above
+            while (offset >= fCachedBreakPositions[fPositionInCache]) {
+                ++fPositionInCache;
+            }
+            int32_t pos = fCachedBreakPositions[fPositionInCache];
+            utext_setNativeIndex(fText, pos);
+            return pos;
+        }
+        else {
+            reset();
+        }
+    }
+
+    // if the offset passed in is already past the end of the text,
+    // just return DONE; if it's before the beginning, return the
+    // text's starting offset
+    fLastRuleStatusIndex  = 0;
+    fLastStatusIndexValid = TRUE;
+    if (fText == NULL || offset >= utext_nativeLength(fText)) {
+        last();
+        return next();
+    }
+    else if (offset < 0) {
+        return first();
+    }
+
+    // otherwise, set our internal iteration position (temporarily)
+    // to the position passed in.  If this is the _beginning_ position,
+    // then we can just use next() to get our return value
+
+    int32_t result = 0;
+
+    if (fData->fSafeRevTable != NULL) {
+        // new rule syntax
+        utext_setNativeIndex(fText, offset);
+        // move forward one codepoint to prepare for moving back to a
+        // safe point.
+        // this handles offset being between a supplementary character
+        UTEXT_NEXT32(fText);
+        // handlePrevious will move most of the time to < 1 boundary away
+        handlePrevious(fData->fSafeRevTable);
+        int32_t result = next();
+        while (result <= offset) {
+            result = next();
+        }
+        return result;
+    }
+    if (fData->fSafeFwdTable != NULL) {
+        // backup plan if forward safe table is not available
+        utext_setNativeIndex(fText, offset);
+        UTEXT_PREVIOUS32(fText);
+        // handle next will give result >= offset
+        handleNext(fData->fSafeFwdTable);
+        // previous will give result 0 or 1 boundary away from offset,
+        // most of the time
+        // we have to
+        int32_t oldresult = previous();
+        while (oldresult > offset) {
+            int32_t result = previous();
+            if (result <= offset) {
+                return oldresult;
+            }
+            oldresult = result;
+        }
+        int32_t result = next();
+        if (result <= offset) {
+            return next();
+        }
+        return result;
+    }
+    // otherwise, we have to sync up first.  Use handlePrevious() to back
+    // up to a known break position before the specified position (if
+    // we can determine that the specified position is a break position,
+    // we don't back up at all).  This may or may not be the last break
+    // position at or before our starting position.  Advance forward
+    // from here until we've passed the starting position.  The position
+    // we stop on will be the first break position after the specified one.
+    // old rule syntax
+
+    utext_setNativeIndex(fText, offset);
+    if (offset==0 || 
+        (offset==1  && utext_getNativeIndex(fText)==0)) {
+        return next();
+    }
+    result = previous();
+
+    while (result != BreakIterator::DONE && result <= offset) {
+        result = next();
+    }
+
+    return result;
+}
+
+/**
+ * Sets the iterator to refer to the last boundary position before the
+ * specified position.
+ * @offset The position to begin searching for a break from.
+ * @return The position of the last boundary before the starting position.
+ */
+int32_t RuleBasedBreakIterator::preceding(int32_t offset) {
+    // if we have cached break positions and offset is in the range
+    // covered by them, use them
+    if (fCachedBreakPositions != NULL) {
+        // TODO: binary search?
+        // TODO: What if offset is outside range, but break is not?
+        if (offset > fCachedBreakPositions[0]
+                && offset <= fCachedBreakPositions[fNumCachedBreakPositions - 1]) {
+            fPositionInCache = 0;
+            while (fPositionInCache < fNumCachedBreakPositions
+                   && offset > fCachedBreakPositions[fPositionInCache])
+                ++fPositionInCache;
+            --fPositionInCache;
+            // If we're at the beginning of the cache, need to reevaluate the
+            // rule status
+            if (fPositionInCache <= 0) {
+                fLastStatusIndexValid = FALSE;
+            }
+            utext_setNativeIndex(fText, fCachedBreakPositions[fPositionInCache]);
+            return fCachedBreakPositions[fPositionInCache];
+        }
+        else {
+            reset();
+        }
+    }
+
+    // if the offset passed in is already past the end of the text,
+    // just return DONE; if it's before the beginning, return the
+    // text's starting offset
+    if (fText == NULL || offset > utext_nativeLength(fText)) {
+        // return BreakIterator::DONE;
+        return last();
+    }
+    else if (offset < 0) {
+        return first();
+    }
+
+    // if we start by updating the current iteration position to the
+    // position specified by the caller, we can just use previous()
+    // to carry out this operation
+
+    if (fData->fSafeFwdTable != NULL) {
+        // new rule syntax
+        utext_setNativeIndex(fText, offset);
+        int32_t newOffset = (int32_t)UTEXT_GETNATIVEINDEX(fText);
+        if (newOffset != offset) {
+            // Will come here if specified offset was not a code point boundary AND
+            //   the underlying implmentation is using UText, which snaps any non-code-point-boundary
+            //   indices to the containing code point.
+            // For breakitereator::preceding only, these non-code-point indices need to be moved
+            //   up to refer to the following codepoint.
+            UTEXT_NEXT32(fText);
+            offset = (int32_t)UTEXT_GETNATIVEINDEX(fText);
+        }
+
+        // TODO:  (synwee) would it be better to just check for being in the middle of a surrogate pair,
+        //        rather than adjusting the position unconditionally?
+        //        (Change would interact with safe rules.)
+        // TODO:  change RBBI behavior for off-boundary indices to match that of UText?
+        //        affects only preceding(), seems cleaner, but is slightly different.
+        UTEXT_PREVIOUS32(fText);
+        handleNext(fData->fSafeFwdTable);
+        int32_t result = (int32_t)UTEXT_GETNATIVEINDEX(fText);
+        while (result >= offset) {
+            result = previous();
+        }
+        return result;
+    }
+    if (fData->fSafeRevTable != NULL) {
+        // backup plan if forward safe table is not available
+        //  TODO:  check whether this path can be discarded
+        //         It's probably OK to say that rules must supply both safe tables
+        //            if they use safe tables at all.  We have certainly never described
+        //            to anyone how to work with just one safe table.
+        utext_setNativeIndex(fText, offset);
+        UTEXT_NEXT32(fText);
+        
+        // handle previous will give result <= offset
+        handlePrevious(fData->fSafeRevTable);
+
+        // next will give result 0 or 1 boundary away from offset,
+        // most of the time
+        // we have to
+        int32_t oldresult = next();
+        while (oldresult < offset) {
+            int32_t result = next();
+            if (result >= offset) {
+                return oldresult;
+            }
+            oldresult = result;
+        }
+        int32_t result = previous();
+        if (result >= offset) {
+            return previous();
+        }
+        return result;
+    }
+
+    // old rule syntax
+    utext_setNativeIndex(fText, offset);
+    return previous();
+}
+
+/**
+ * Returns true if the specfied position is a boundary position.  As a side
+ * effect, leaves the iterator pointing to the first boundary position at
+ * or after "offset".
+ * @param offset the offset to check.
+ * @return True if "offset" is a boundary position.
+ */
+UBool RuleBasedBreakIterator::isBoundary(int32_t offset) {
+    // the beginning index of the iterator is always a boundary position by definition
+    if (offset == 0) {
+        first();       // For side effects on current position, tag values.
+        return TRUE;
+    }
+
+    if (offset == (int32_t)utext_nativeLength(fText)) {
+        last();       // For side effects on current position, tag values.
+        return TRUE;
+    }
+
+    // out-of-range indexes are never boundary positions
+    if (offset < 0) {
+        first();       // For side effects on current position, tag values.
+        return FALSE;
+    }
+
+    if (offset > utext_nativeLength(fText)) {
+        last();        // For side effects on current position, tag values.
+        return FALSE;
+    }
+
+    // otherwise, we can use following() on the position before the specified
+    // one and return true if the position we get back is the one the user
+    // specified
+    utext_previous32From(fText, offset);
+    int32_t backOne = (int32_t)UTEXT_GETNATIVEINDEX(fText);
+    UBool    result  = following(backOne) == offset;
+    return result;
+}
+
+/**
+ * Returns the current iteration position.
+ * @return The current iteration position.
+ */
+int32_t RuleBasedBreakIterator::current(void) const {
+    int32_t  pos = (int32_t)UTEXT_GETNATIVEINDEX(fText);
+    return pos;
+}
+ 
+//=======================================================================
+// implementation
+//=======================================================================
+
+//
+// RBBIRunMode  -  the state machine runs an extra iteration at the beginning and end
+//                 of user text.  A variable with this enum type keeps track of where we
+//                 are.  The state machine only fetches user input while in the RUN mode.
+//
+enum RBBIRunMode {
+    RBBI_START,     // state machine processing is before first char of input
+    RBBI_RUN,       // state machine processing is in the user text
+    RBBI_END        // state machine processing is after end of user text.
+};
+
+
+//-----------------------------------------------------------------------------------
+//
+//  handleNext(stateTable)
+//     This method is the actual implementation of the rbbi next() method. 
+//     This method initializes the state machine to state 1
+//     and advances through the text character by character until we reach the end
+//     of the text or the state machine transitions to state 0.  We update our return
+//     value every time the state machine passes through an accepting state.
+//
+//-----------------------------------------------------------------------------------
+int32_t RuleBasedBreakIterator::handleNext(const RBBIStateTable *statetable) {
+    int32_t             state;
+    int16_t             category        = 0;
+    RBBIRunMode         mode;
+    
+    RBBIStateTableRow  *row;
+    UChar32             c;
+    int32_t             lookaheadStatus = 0;
+    int32_t             lookaheadTagIdx = 0;
+    int32_t             result          = 0;
+    int32_t             initialPosition = 0;
+    int32_t             lookaheadResult = 0;
+    UBool               lookAheadHardBreak = (statetable->fFlags & RBBI_LOOKAHEAD_HARD_BREAK) != 0;
+    const char         *tableData       = statetable->fTableData;
+    uint32_t            tableRowLen     = statetable->fRowLen;
+
+    #ifdef RBBI_DEBUG
+        if (fTrace) {
+            RBBIDebugPuts("Handle Next   pos   char  state category");
+        }
+    #endif
+
+    // No matter what, handleNext alway correctly sets the break tag value.
+    fLastStatusIndexValid = TRUE;
+    fLastRuleStatusIndex = 0;
+
+    // if we're already at the end of the text, return DONE.
+    initialPosition = (int32_t)UTEXT_GETNATIVEINDEX(fText); 
+    result          = initialPosition;
+    c               = UTEXT_NEXT32(fText);
+    if (fData == NULL || c==U_SENTINEL) {
+        return BreakIterator::DONE;
+    }
+
+    //  Set the initial state for the state machine
+    state = START_STATE;
+    row = (RBBIStateTableRow *)
+            //(statetable->fTableData + (statetable->fRowLen * state));
+            (tableData + tableRowLen * state);
+            
+    
+    mode     = RBBI_RUN;
+    if (statetable->fFlags & RBBI_BOF_REQUIRED) {
+        category = 2;
+        mode     = RBBI_START;
+    }
+
+
+    // loop until we reach the end of the text or transition to state 0
+    //
+    for (;;) {
+        if (c == U_SENTINEL) {
+            // Reached end of input string.
+            if (mode == RBBI_END) {
+                // We have already run the loop one last time with the 
+                //   character set to the psueudo {eof} value.  Now it is time
+                //   to unconditionally bail out.
+                if (lookaheadResult > result) {
+                    // We ran off the end of the string with a pending look-ahead match.
+                    // Treat this as if the look-ahead condition had been met, and return
+                    //  the match at the / position from the look-ahead rule.
+                    result               = lookaheadResult;
+                    fLastRuleStatusIndex = lookaheadTagIdx;
+                    lookaheadStatus = 0;
+                } 
+                break;
+            }
+            // Run the loop one last time with the fake end-of-input character category.
+            mode = RBBI_END;
+            category = 1;
+        }
+
+        //
+        // Get the char category.  An incoming category of 1 or 2 means that
+        //      we are preset for doing the beginning or end of input, and
+        //      that we shouldn't get a category from an actual text input character.
+        //
+        if (mode == RBBI_RUN) {
+            // look up the current character's character category, which tells us
+            // which column in the state table to look at.
+            // Note:  the 16 in UTRIE_GET16 refers to the size of the data being returned,
+            //        not the size of the character going in, which is a UChar32.
+            //
+            UTRIE_GET16(&fData->fTrie, c, category);
+
+            // Check the dictionary bit in the character's category.
+            //    Counter is only used by dictionary based iterators (subclasses).
+            //    Chars that need to be handled by a dictionary have a flag bit set
+            //    in their category values.
+            //
+            if ((category & 0x4000) != 0)  {
+                fDictionaryCharCount++;
+                //  And off the dictionary flag bit.
+                category &= ~0x4000;
+            }
+        }
+
+        #ifdef RBBI_DEBUG
+            if (fTrace) {
+                RBBIDebugPrintf("             %4ld   ", utext_getNativeIndex(fText));
+                if (0x20<=c && c<0x7f) {
+                    RBBIDebugPrintf("\"%c\"  ", c);
+                } else {
+                    RBBIDebugPrintf("%5x  ", c);
+                }
+                RBBIDebugPrintf("%3d  %3d\n", state, category);
+            }
+        #endif
+
+        // State Transition - move machine to its next state
+        //
+        state = row->fNextState[category];
+        row = (RBBIStateTableRow *)
+            // (statetable->fTableData + (statetable->fRowLen * state));
+            (tableData + tableRowLen * state);
+
+
+        if (row->fAccepting == -1) {
+            // Match found, common case.
+            if (mode != RBBI_START) {
+                result = (int32_t)UTEXT_GETNATIVEINDEX(fText);
+            }
+            fLastRuleStatusIndex = row->fTagIdx;   // Remember the break status (tag) values.
+        }
+
+        if (row->fLookAhead != 0) {
+            if (lookaheadStatus != 0
+                && row->fAccepting == lookaheadStatus) {
+                // Lookahead match is completed.  
+                result               = lookaheadResult;
+                fLastRuleStatusIndex = lookaheadTagIdx;
+                lookaheadStatus      = 0;
+                // TODO:  make a standalone hard break in a rule work.
+                if (lookAheadHardBreak) {
+                    UTEXT_SETNATIVEINDEX(fText, result);
+                    return result;
+                }
+                // Look-ahead completed, but other rules may match further.  Continue on
+                //  TODO:  junk this feature?  I don't think it's used anywhwere.
+                goto continueOn;
+            }
+
+            int32_t  r = (int32_t)UTEXT_GETNATIVEINDEX(fText);
+            lookaheadResult = r;
+            lookaheadStatus = row->fLookAhead;
+            lookaheadTagIdx = row->fTagIdx;
+            goto continueOn;
+        }
+
+
+        if (row->fAccepting != 0) {
+            // Because this is an accepting state, any in-progress look-ahead match
+            //   is no longer relavant.  Clear out the pending lookahead status.
+            lookaheadStatus = 0;           // clear out any pending look-ahead match.
+        }
+
+continueOn:
+        if (state == STOP_STATE) {
+            // This is the normal exit from the lookup state machine.
+            // We have advanced through the string until it is certain that no
+            //   longer match is possible, no matter what characters follow.
+            break;
+        }
+        
+        // Advance to the next character.  
+        // If this is a beginning-of-input loop iteration, don't advance
+        //    the input position.  The next iteration will be processing the
+        //    first real input character.
+        if (mode == RBBI_RUN) {
+            c = UTEXT_NEXT32(fText);
+        } else {
+            if (mode == RBBI_START) {
+                mode = RBBI_RUN;
+            }
+        }
+
+
+    }
+
+    // The state machine is done.  Check whether it found a match...
+
+    // If the iterator failed to advance in the match engine, force it ahead by one.
+    //   (This really indicates a defect in the break rules.  They should always match
+    //    at least one character.)
+    if (result == initialPosition) {
+        UTEXT_SETNATIVEINDEX(fText, initialPosition);
+        UTEXT_NEXT32(fText);
+        result = (int32_t)UTEXT_GETNATIVEINDEX(fText);
+    }
+
+    // Leave the iterator at our result position.
+    UTEXT_SETNATIVEINDEX(fText, result);
+    #ifdef RBBI_DEBUG
+        if (fTrace) {
+            RBBIDebugPrintf("result = %d\n\n", result);
+        }
+    #endif
+    return result;
+}
+
+
+
+//-----------------------------------------------------------------------------------
+//
+//  handlePrevious()
+//
+//      Iterate backwards, according to the logic of the reverse rules.
+//      This version handles the exact style backwards rules.
+//
+//      The logic of this function is very similar to handleNext(), above.
+//
+//-----------------------------------------------------------------------------------
+int32_t RuleBasedBreakIterator::handlePrevious(const RBBIStateTable *statetable) {
+    int32_t             state;
+    int16_t             category        = 0;
+    RBBIRunMode         mode;
+    RBBIStateTableRow  *row;
+    UChar32             c;
+    int32_t             lookaheadStatus = 0;
+    int32_t             result          = 0;
+    int32_t             initialPosition = 0;
+    int32_t             lookaheadResult = 0;
+    UBool               lookAheadHardBreak = (statetable->fFlags & RBBI_LOOKAHEAD_HARD_BREAK) != 0;
+
+    #ifdef RBBI_DEBUG
+        if (fTrace) {
+            RBBIDebugPuts("Handle Previous   pos   char  state category");
+        }
+    #endif
+
+    // handlePrevious() never gets the rule status.
+    // Flag the status as invalid; if the user ever asks for status, we will need
+    // to back up, then re-find the break position using handleNext(), which does
+    // get the status value.
+    fLastStatusIndexValid = FALSE;
+    fLastRuleStatusIndex = 0;
+
+    // if we're already at the start of the text, return DONE.
+    if (fText == NULL || fData == NULL || UTEXT_GETNATIVEINDEX(fText)==0) {
+        return BreakIterator::DONE;
+    }
+
+    //  Set up the starting char.
+    initialPosition = (int32_t)UTEXT_GETNATIVEINDEX(fText);
+    result          = initialPosition;
+    c               = UTEXT_PREVIOUS32(fText);
+
+    //  Set the initial state for the state machine
+    state = START_STATE;
+    row = (RBBIStateTableRow *)
+            (statetable->fTableData + (statetable->fRowLen * state));
+    category = 3;
+    mode     = RBBI_RUN;
+    if (statetable->fFlags & RBBI_BOF_REQUIRED) {
+        category = 2;
+        mode     = RBBI_START;
+    }
+
+
+    // loop until we reach the start of the text or transition to state 0
+    //
+    for (;;) {
+        if (c == U_SENTINEL) {
+            // Reached end of input string.
+            if (mode == RBBI_END) {
+                // We have already run the loop one last time with the 
+                //   character set to the psueudo {eof} value.  Now it is time
+                //   to unconditionally bail out.
+                if (lookaheadResult < result) {
+                    // We ran off the end of the string with a pending look-ahead match.
+                    // Treat this as if the look-ahead condition had been met, and return
+                    //  the match at the / position from the look-ahead rule.
+                    result               = lookaheadResult;
+                    lookaheadStatus = 0;
+                } else if (result == initialPosition) {
+                    // Ran off start, no match found.
+                    // move one index one (towards the start, since we are doing a previous())
+                    UTEXT_SETNATIVEINDEX(fText, initialPosition);
+                    UTEXT_PREVIOUS32(fText);   // TODO:  shouldn't be necessary.  We're already at beginning.  Check.
+                }
+                break;
+            }
+            // Run the loop one last time with the fake end-of-input character category.
+            mode = RBBI_END;
+            category = 1;
+        }
+
+        //
+        // Get the char category.  An incoming category of 1 or 2 means that
+        //      we are preset for doing the beginning or end of input, and
+        //      that we shouldn't get a category from an actual text input character.
+        //
+        if (mode == RBBI_RUN) {
+            // look up the current character's character category, which tells us
+            // which column in the state table to look at.
+            // Note:  the 16 in UTRIE_GET16 refers to the size of the data being returned,
+            //        not the size of the character going in, which is a UChar32.
+            //
+            UTRIE_GET16(&fData->fTrie, c, category);
+
+            // Check the dictionary bit in the character's category.
+            //    Counter is only used by dictionary based iterators (subclasses).
+            //    Chars that need to be handled by a dictionary have a flag bit set
+            //    in their category values.
+            //
+            if ((category & 0x4000) != 0)  {
+                fDictionaryCharCount++;
+                //  And off the dictionary flag bit.
+                category &= ~0x4000;
+            }
+        }
+
+        #ifdef RBBI_DEBUG
+            if (fTrace) {
+                RBBIDebugPrintf("             %4d   ", (int32_t)utext_getNativeIndex(fText));
+                if (0x20<=c && c<0x7f) {
+                    RBBIDebugPrintf("\"%c\"  ", c);
+                } else {
+                    RBBIDebugPrintf("%5x  ", c);
+                }
+                RBBIDebugPrintf("%3d  %3d\n", state, category);
+            }
+        #endif
+
+        // State Transition - move machine to its next state
+        //
+        state = row->fNextState[category];
+        row = (RBBIStateTableRow *)
+            (statetable->fTableData + (statetable->fRowLen * state));
+
+        if (row->fAccepting == -1) {
+            // Match found, common case.
+            result = (int32_t)UTEXT_GETNATIVEINDEX(fText);
+        }
+
+        if (row->fLookAhead != 0) {
+            if (lookaheadStatus != 0
+                && row->fAccepting == lookaheadStatus) {
+                // Lookahead match is completed.  
+                result               = lookaheadResult;
+                lookaheadStatus      = 0;
+                // TODO:  make a standalone hard break in a rule work.
+                if (lookAheadHardBreak) {
+                    UTEXT_SETNATIVEINDEX(fText, result);
+                    return result;
+                }
+                // Look-ahead completed, but other rules may match further.  Continue on
+                //  TODO:  junk this feature?  I don't think it's used anywhwere.
+                goto continueOn;
+            }
+
+            int32_t  r = (int32_t)UTEXT_GETNATIVEINDEX(fText);
+            lookaheadResult = r;
+            lookaheadStatus = row->fLookAhead;
+            goto continueOn;
+        }
+
+
+        if (row->fAccepting != 0) {
+            // Because this is an accepting state, any in-progress look-ahead match
+            //   is no longer relavant.  Clear out the pending lookahead status.
+            lookaheadStatus = 0;    
+        }
+
+continueOn:
+        if (state == STOP_STATE) {
+            // This is the normal exit from the lookup state machine.
+            // We have advanced through the string until it is certain that no
+            //   longer match is possible, no matter what characters follow.
+            break;
+        }
+
+        // Move (backwards) to the next character to process.  
+        // If this is a beginning-of-input loop iteration, don't advance
+        //    the input position.  The next iteration will be processing the
+        //    first real input character.
+        if (mode == RBBI_RUN) {
+            c = UTEXT_PREVIOUS32(fText);
+        } else {            
+            if (mode == RBBI_START) {
+                mode = RBBI_RUN;
+            }
+        }
+    }
+
+    // The state machine is done.  Check whether it found a match...
+
+    // If the iterator failed to advance in the match engine, force it ahead by one.
+    //   (This really indicates a defect in the break rules.  They should always match
+    //    at least one character.)
+    if (result == initialPosition) {
+        UTEXT_SETNATIVEINDEX(fText, initialPosition);
+        UTEXT_PREVIOUS32(fText);
+        result = (int32_t)UTEXT_GETNATIVEINDEX(fText);
+    }
+
+    // Leave the iterator at our result position.
+    UTEXT_SETNATIVEINDEX(fText, result);
+    #ifdef RBBI_DEBUG
+        if (fTrace) {
+            RBBIDebugPrintf("result = %d\n\n", result);
+        }
+    #endif
+    return result;
+}
+
+
+void
+RuleBasedBreakIterator::reset()
+{
+    if (fCachedBreakPositions) {
+        uprv_free(fCachedBreakPositions);
+    }
+    fCachedBreakPositions = NULL;
+    fNumCachedBreakPositions = 0;
+    fDictionaryCharCount = 0;
+    fPositionInCache = 0;
+}
+
+
+
+//-------------------------------------------------------------------------------
+//
+//   getRuleStatus()   Return the break rule tag associated with the current
+//                     iterator position.  If the iterator arrived at its current
+//                     position by iterating forwards, the value will have been
+//                     cached by the handleNext() function.
+//
+//                     If no cached status value is available, the status is
+//                     found by doing a previous() followed by a next(), which
+//                     leaves the iterator where it started, and computes the
+//                     status while doing the next().
+//
+//-------------------------------------------------------------------------------
+void RuleBasedBreakIterator::makeRuleStatusValid() {
+    if (fLastStatusIndexValid == FALSE) {
+        //  No cached status is available.
+        if (fText == NULL || current() == 0) {
+            //  At start of text, or there is no text.  Status is always zero.
+            fLastRuleStatusIndex = 0;
+            fLastStatusIndexValid = TRUE;
+        } else {
+            //  Not at start of text.  Find status the tedious way.
+            int32_t pa = current();
+            previous();
+            if (fNumCachedBreakPositions > 0) {
+                reset();                // Blow off the dictionary cache
+            }
+            int32_t pb = next();
+            if (pa != pb) {
+                // note: the if (pa != pb) test is here only to eliminate warnings for
+                //       unused local variables on gcc.  Logically, it isn't needed.
+                U_ASSERT(pa == pb);
+            }
+        }
+    }
+    U_ASSERT(fLastRuleStatusIndex >= 0  &&  fLastRuleStatusIndex < fData->fStatusMaxIdx);
+}
+
+
+int32_t  RuleBasedBreakIterator::getRuleStatus() const {
+    RuleBasedBreakIterator *nonConstThis  = (RuleBasedBreakIterator *)this;
+    nonConstThis->makeRuleStatusValid();
+
+    // fLastRuleStatusIndex indexes to the start of the appropriate status record
+    //                                                 (the number of status values.)
+    //   This function returns the last (largest) of the array of status values.
+    int32_t  idx = fLastRuleStatusIndex + fData->fRuleStatusTable[fLastRuleStatusIndex];
+    int32_t  tagVal = fData->fRuleStatusTable[idx];
+
+    return tagVal;
+}
+
+
+
+
+int32_t RuleBasedBreakIterator::getRuleStatusVec(
+             int32_t *fillInVec, int32_t capacity, UErrorCode &status)
+{
+    if (U_FAILURE(status)) {
+        return 0;
+    }
+
+    RuleBasedBreakIterator *nonConstThis  = (RuleBasedBreakIterator *)this;
+    nonConstThis->makeRuleStatusValid();
+    int32_t  numVals = fData->fRuleStatusTable[fLastRuleStatusIndex];
+    int32_t  numValsToCopy = numVals;
+    if (numVals > capacity) {
+        status = U_BUFFER_OVERFLOW_ERROR;
+        numValsToCopy = capacity;
+    }
+    int i;
+    for (i=0; i<numValsToCopy; i++) {
+        fillInVec[i] = fData->fRuleStatusTable[fLastRuleStatusIndex + i + 1];
+    }
+    return numVals;
+}
+
+
+
+//-------------------------------------------------------------------------------
+//
+//   getBinaryRules        Access to the compiled form of the rules,
+//                         for use by build system tools that save the data
+//                         for standard iterator types.
+//
+//-------------------------------------------------------------------------------
+const uint8_t  *RuleBasedBreakIterator::getBinaryRules(uint32_t &length) {
+    const uint8_t  *retPtr = NULL;
+    length = 0;
+
+    if (fData != NULL) {
+        retPtr = (const uint8_t *)fData->fHeader;
+        length = fData->fHeader->fLength;
+    }
+    return retPtr;
+}
+
+
+
+
+//-------------------------------------------------------------------------------
+//
+//  BufferClone       TODO:  In my (Andy) opinion, this function should be deprecated.
+//                    Saving one heap allocation isn't worth the trouble.
+//                    Cloning shouldn't be done in tight loops, and
+//                    making the clone copy involves other heap operations anyway.
+//                    And the application code for correctly dealing with buffer
+//                    size problems and the eventual object destruction is ugly.
+//
+//-------------------------------------------------------------------------------
+BreakIterator *  RuleBasedBreakIterator::createBufferClone(void *stackBuffer,
+                                   int32_t &bufferSize,
+                                   UErrorCode &status)
+{
+    if (U_FAILURE(status)){
+        return NULL;
+    }
+
+    //
+    //  If user buffer size is zero this is a preflight operation to
+    //    obtain the needed buffer size, allowing for worst case misalignment.
+    //
+    if (bufferSize == 0) {
+        bufferSize = sizeof(RuleBasedBreakIterator) + U_ALIGNMENT_OFFSET_UP(0);
+        return NULL;
+    }
+
+
+    //
+    //  Check the alignment and size of the user supplied buffer.
+    //  Allocate heap memory if the user supplied memory is insufficient.
+    //
+    char    *buf   = (char *)stackBuffer;
+    uint32_t s      = bufferSize;
+
+    if (stackBuffer == NULL) {
+        s = 0;   // Ignore size, force allocation if user didn't give us a buffer.
+    }
+    if (U_ALIGNMENT_OFFSET(stackBuffer) != 0) {
+        uint32_t offsetUp = (uint32_t)U_ALIGNMENT_OFFSET_UP(buf);
+        s   -= offsetUp;
+        buf += offsetUp;
+    }
+    if (s < sizeof(RuleBasedBreakIterator)) {
+        // Not enough room in the caller-supplied buffer.
+        // Do a plain-vanilla heap based clone and return that, along with
+        //   a warning that the clone was allocated.
+        RuleBasedBreakIterator *clonedBI = new RuleBasedBreakIterator(*this);
+        if (clonedBI == 0) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+        } else {
+            status = U_SAFECLONE_ALLOCATED_WARNING;
+        }
+        return clonedBI;
+    }
+
+    //
+    //  Clone the source BI into the caller-supplied buffer.
+    //    TODO:  using an overloaded operator new to directly initialize the
+    //           copy in the user's buffer would be better, but it doesn't seem
+    //           to get along with namespaces.  Investigate why.
+    //
+    //           The memcpy is only safe with an empty (default constructed)
+    //           break iterator.  Use on others can screw up reference counts
+    //           to data.  memcpy-ing objects is not really a good idea...
+    //
+    RuleBasedBreakIterator localIter;        // Empty break iterator, source for memcpy
+    RuleBasedBreakIterator *clone = (RuleBasedBreakIterator *)buf;
+    uprv_memcpy(clone, &localIter, sizeof(RuleBasedBreakIterator)); // init C++ gorp, BreakIterator base class part
+    clone->init();                // Init RuleBasedBreakIterator part, (user default constructor)
+    *clone = *this;               // clone = the real BI we want.
+    clone->fBufferClone = TRUE;   // Flag to prevent deleting storage on close (From C code)
+
+    return clone;
+}
+
+
+//-------------------------------------------------------------------------------
+//
+//  isDictionaryChar      Return true if the category lookup for this char
+//                        indicates that it is in the set of dictionary lookup
+//                        chars.
+//
+//                        This function is intended for use by dictionary based
+//                        break iterators.
+//
+//-------------------------------------------------------------------------------
+/*UBool RuleBasedBreakIterator::isDictionaryChar(UChar32   c) {
+    if (fData == NULL) {
+        return FALSE;
+    }
+    uint16_t category;
+    UTRIE_GET16(&fData->fTrie, c, category);
+    return (category & 0x4000) != 0;
+}*/
+
+
+//-------------------------------------------------------------------------------
+//
+//  checkDictionary       This function handles all processing of characters in
+//                        the "dictionary" set. It will determine the appropriate
+//                        course of action, and possibly set up a cache in the
+//                        process.
+//
+//-------------------------------------------------------------------------------
+int32_t RuleBasedBreakIterator::checkDictionary(int32_t startPos,
+                            int32_t endPos,
+                            UBool reverse) {
+    // Reset the old break cache first.
+    uint32_t dictionaryCount = fDictionaryCharCount;
+    reset();
+
+    if (dictionaryCount <= 1 || (endPos - startPos) <= 1) {
+        return (reverse ? startPos : endPos);
+    }
+    
+    // Bug 5532.  The dictionary code will crash if the input text is UTF-8
+    //      because native indexes are different from UTF-16 indexes.
+    //      Temporary hack: skip dictionary lookup for UTF-8 encoded text.
+    //      It wont give the right breaks, but it's better than a crash.
+    //
+    //      Check the type of the UText by checking its pFuncs field, which
+    //      is UText's function dispatch table.  It will be the same for all
+    //      UTF-8 UTexts and different for any other UText type.
+    //
+    //      We have no other type of UText available with non-UTF-16 native indexing.
+    //      This whole check will go away once the dictionary code is fixed.
+    static const void *utext_utf8Funcs;
+    if (utext_utf8Funcs == NULL) {
+        // Cache the UTF-8 UText function pointer value.
+        UErrorCode status = U_ZERO_ERROR;
+        UText tempUText = UTEXT_INITIALIZER; 
+        utext_openUTF8(&tempUText, NULL, 0, &status);
+        utext_utf8Funcs = tempUText.pFuncs;
+        utext_close(&tempUText);
+    }
+    if (fText->pFuncs == utext_utf8Funcs) {
+        return (reverse ? startPos : endPos);
+    }
+
+    // Starting from the starting point, scan towards the proposed result,
+    // looking for the first dictionary character (which may be the one
+    // we're on, if we're starting in the middle of a range).
+    utext_setNativeIndex(fText, reverse ? endPos : startPos);
+    if (reverse) {
+        UTEXT_PREVIOUS32(fText);
+    }
+    
+    int32_t rangeStart = startPos;
+    int32_t rangeEnd = endPos;
+
+    uint16_t    category;
+    int32_t     current;
+    UErrorCode  status = U_ZERO_ERROR;
+    UStack      breaks(status);
+    int32_t     foundBreakCount = 0;
+    UChar32     c = utext_current32(fText);
+
+    UTRIE_GET16(&fData->fTrie, c, category);
+    
+    // Is the character we're starting on a dictionary character? If so, we
+    // need to back up to include the entire run; otherwise the results of
+    // the break algorithm will differ depending on where we start. Since
+    // the result is cached and there is typically a non-dictionary break
+    // within a small number of words, there should be little performance impact.
+    if (category & 0x4000) {
+        if (reverse) {
+            do {
+                utext_next32(fText);          // TODO:  recast to work directly with postincrement.
+                c = utext_current32(fText);
+                UTRIE_GET16(&fData->fTrie, c, category);
+            } while (c != U_SENTINEL && (category & 0x4000));
+            // Back up to the last dictionary character
+            rangeEnd = (int32_t)UTEXT_GETNATIVEINDEX(fText);
+            if (c == U_SENTINEL) {
+                // c = fText->last32();
+                //   TODO:  why was this if needed?
+                c = UTEXT_PREVIOUS32(fText);
+            }
+            else {
+                c = UTEXT_PREVIOUS32(fText);
+            }
+        }
+        else {
+            do {
+                c = UTEXT_PREVIOUS32(fText);
+                UTRIE_GET16(&fData->fTrie, c, category);
+            }
+            while (c != U_SENTINEL && (category & 0x4000));
+            // Back up to the last dictionary character
+            if (c == U_SENTINEL) {
+                // c = fText->first32();
+                c = utext_current32(fText);
+            }
+            else {
+                utext_next32(fText);
+                c = utext_current32(fText);
+            }
+            rangeStart = (int32_t)UTEXT_GETNATIVEINDEX(fText);;
+        }
+        UTRIE_GET16(&fData->fTrie, c, category);
+    }
+    
+    // Loop through the text, looking for ranges of dictionary characters.
+    // For each span, find the appropriate break engine, and ask it to find
+    // any breaks within the span.
+    // Note: we always do this in the forward direction, so that the break
+    // cache is built in the right order.
+    if (reverse) {
+        utext_setNativeIndex(fText, rangeStart);
+        c = utext_current32(fText);
+        UTRIE_GET16(&fData->fTrie, c, category);
+    }
+    while(U_SUCCESS(status)) {
+        while((current = (int32_t)UTEXT_GETNATIVEINDEX(fText)) < rangeEnd && (category & 0x4000) == 0) {
+            utext_next32(fText);           // TODO:  tweak for post-increment operation
+            c = utext_current32(fText);
+            UTRIE_GET16(&fData->fTrie, c, category);
+        }
+        if (current >= rangeEnd) {
+            break;
+        }
+        
+        // We now have a dictionary character. Get the appropriate language object
+        // to deal with it.
+        const LanguageBreakEngine *lbe = getLanguageBreakEngine(c);
+        
+        // Ask the language object if there are any breaks. It will leave the text
+        // pointer on the other side of its range, ready to search for the next one.
+        if (lbe != NULL) {
+            foundBreakCount += lbe->findBreaks(fText, rangeStart, rangeEnd, FALSE, fBreakType, breaks);
+        }
+        
+        // Reload the loop variables for the next go-round
+        c = utext_current32(fText);
+        UTRIE_GET16(&fData->fTrie, c, category);
+    }
+    
+    // If we found breaks, build a new break cache. The first and last entries must
+    // be the original starting and ending position.
+    if (foundBreakCount > 0) {
+        int32_t totalBreaks = foundBreakCount;
+        if (startPos < breaks.elementAti(0)) {
+            totalBreaks += 1;
+        }
+        if (endPos > breaks.peeki()) {
+            totalBreaks += 1;
+        }
+        fCachedBreakPositions = (int32_t *)uprv_malloc(totalBreaks * sizeof(int32_t));
+        if (fCachedBreakPositions != NULL) {
+            int32_t out = 0;
+            fNumCachedBreakPositions = totalBreaks;
+            if (startPos < breaks.elementAti(0)) {
+                fCachedBreakPositions[out++] = startPos;
+            }
+            for (int32_t i = 0; i < foundBreakCount; ++i) {
+                fCachedBreakPositions[out++] = breaks.elementAti(i);
+            }
+            if (endPos > fCachedBreakPositions[out-1]) {
+                fCachedBreakPositions[out] = endPos;
+            }
+            // If there are breaks, then by definition, we are replacing the original
+            // proposed break by one of the breaks we found. Use following() and
+            // preceding() to do the work. They should never recurse in this case.
+            if (reverse) {
+                return preceding(endPos - 1);
+            }
+            else {
+                return following(startPos);
+            }
+        }
+        // If the allocation failed, just fall through to the "no breaks found" case.
+    }
+
+    // If we get here, there were no language-based breaks. Set the text pointer
+    // to the original proposed break.
+    utext_setNativeIndex(fText, reverse ? startPos : endPos);
+    return (reverse ? startPos : endPos);
+}
+
+U_NAMESPACE_END
+
+// defined in ucln_cmn.h
+
+static U_NAMESPACE_QUALIFIER UStack *gLanguageBreakFactories = NULL;
+
+/**
+ * Release all static memory held by breakiterator.  
+ */
+U_CDECL_BEGIN
+static UBool U_CALLCONV breakiterator_cleanup_dict(void) {
+    if (gLanguageBreakFactories) {
+        delete gLanguageBreakFactories;
+        gLanguageBreakFactories = NULL;
+    }
+    return TRUE;
+}
+U_CDECL_END
+
+U_CDECL_BEGIN
+static void U_CALLCONV _deleteFactory(void *obj) {
+    delete (U_NAMESPACE_QUALIFIER LanguageBreakFactory *) obj;
+}
+U_CDECL_END
+U_NAMESPACE_BEGIN
+
+static const LanguageBreakEngine*
+getLanguageBreakEngineFromFactory(UChar32 c, int32_t breakType)
+{
+    UBool       needsInit;
+    UErrorCode  status = U_ZERO_ERROR;
+    UMTX_CHECK(NULL, (UBool)(gLanguageBreakFactories == NULL), needsInit);
+    
+    if (needsInit) {
+        UStack  *factories = new UStack(_deleteFactory, NULL, status);
+        if (factories != NULL && U_SUCCESS(status)) {
+            ICULanguageBreakFactory *builtIn = new ICULanguageBreakFactory(status);
+            factories->push(builtIn, status);
+#ifdef U_LOCAL_SERVICE_HOOK
+            LanguageBreakFactory *extra = (LanguageBreakFactory *)uprv_svc_hook("languageBreakFactory", &status);
+            if (extra != NULL) {
+                factories->push(extra, status);
+            }
+#endif
+        }
+        umtx_lock(NULL);
+        if (gLanguageBreakFactories == NULL) {
+            gLanguageBreakFactories = factories;
+            factories = NULL;
+            ucln_common_registerCleanup(UCLN_COMMON_BREAKITERATOR_DICT, breakiterator_cleanup_dict);
+        }
+        umtx_unlock(NULL);
+        delete factories;
+    }
+    
+    if (gLanguageBreakFactories == NULL) {
+        return NULL;
+    }
+    
+    int32_t i = gLanguageBreakFactories->size();
+    const LanguageBreakEngine *lbe = NULL;
+    while (--i >= 0) {
+        LanguageBreakFactory *factory = (LanguageBreakFactory *)(gLanguageBreakFactories->elementAt(i));
+        lbe = factory->getEngineFor(c, breakType);
+        if (lbe != NULL) {
+            break;
+        }
+    }
+    return lbe;
+}
+
+
+//-------------------------------------------------------------------------------
+//
+//  getLanguageBreakEngine  Find an appropriate LanguageBreakEngine for the
+//                          the characer c.
+//
+//-------------------------------------------------------------------------------
+const LanguageBreakEngine *
+RuleBasedBreakIterator::getLanguageBreakEngine(UChar32 c) {
+    const LanguageBreakEngine *lbe = NULL;
+    UErrorCode status = U_ZERO_ERROR;
+    
+    if (fLanguageBreakEngines == NULL) {
+        fLanguageBreakEngines = new UStack(status);
+        if (fLanguageBreakEngines == NULL || U_FAILURE(status)) {
+            delete fLanguageBreakEngines;
+            fLanguageBreakEngines = 0;
+            return NULL;
+        }
+    }
+    
+    int32_t i = fLanguageBreakEngines->size();
+    while (--i >= 0) {
+        lbe = (const LanguageBreakEngine *)(fLanguageBreakEngines->elementAt(i));
+        if (lbe->handles(c, fBreakType)) {
+            return lbe;
+        }
+    }
+    
+    // No existing dictionary took the character. See if a factory wants to
+    // give us a new LanguageBreakEngine for this character.
+    lbe = getLanguageBreakEngineFromFactory(c, fBreakType);
+    
+    // If we got one, use it and push it on our stack.
+    if (lbe != NULL) {
+        fLanguageBreakEngines->push((void *)lbe, status);
+        // Even if we can't remember it, we can keep looking it up, so
+        // return it even if the push fails.
+        return lbe;
+    }
+    
+    // No engine is forthcoming for this character. Add it to the
+    // reject set. Create the reject break engine if needed.
+    if (fUnhandledBreakEngine == NULL) {
+        fUnhandledBreakEngine = new UnhandledEngine(status);
+        if (U_SUCCESS(status) && fUnhandledBreakEngine == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+        }
+        // Put it last so that scripts for which we have an engine get tried
+        // first.
+        fLanguageBreakEngines->insertElementAt(fUnhandledBreakEngine, 0, status);
+        // If we can't insert it, or creation failed, get rid of it
+        if (U_FAILURE(status)) {
+            delete fUnhandledBreakEngine;
+            fUnhandledBreakEngine = 0;
+            return NULL;
+        }
+    }
+    
+    // Tell the reject engine about the character; at its discretion, it may
+    // add more than just the one character.
+    fUnhandledBreakEngine->handleCharacter(c, fBreakType);
+        
+    return fUnhandledBreakEngine;
+}
+
+
+
+/*int32_t RuleBasedBreakIterator::getBreakType() const {
+    return fBreakType;
+}*/
+
+void RuleBasedBreakIterator::setBreakType(int32_t type) {
+    fBreakType = type;
+    reset();
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
diff --git a/source/common/rbbicst.pl b/source/common/rbbicst.pl
new file mode 100755
index 0000000..98b06cb
--- /dev/null
+++ b/source/common/rbbicst.pl
@@ -0,0 +1,453 @@
+#**************************************************************************
+#   Copyright (C) 2002-2005 International Business Machines Corporation   *
+#   and others. All rights reserved.                                      *
+#**************************************************************************
+#
+#  rbbicst   Compile the RBBI rule paser state table data into initialized C data.
+#            Usage:
+#                   cd icu/source/common
+#                   perl rbbicst.pl    < rbbirpt.txt > rbbirpt.h
+#                   perl rbbicst.pl -j < rbbirpt.txt > RBBIRuleParseTable.java
+#
+#             The output file, rbbrpt.h, is included by some of the .cpp rbbi
+#             implementation files.   This perl script is NOT run as part
+#             of a normal ICU build.  It is run by hand when needed, and the
+#             rbbirpt.h generated file is put back into cvs.
+#
+#             See rbbirpt.txt for a description of the input format for this script.
+#
+
+if ($ARGV[0] eq "-j") {
+    $javaOutput = 1;
+    shift @ARGV;
+}
+
+
+$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] = $javaOutput? "false" : "FALSE";
+    if ($fields[0] eq "n") {
+        $state_flag[$num_states] = $javaOutput? "true": "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);
+
+#
+# Assign numbers to each of the character classes classes  used.
+#   Sets are numbered from 128 - 250
+#   The values 0-127 in the state table are used for matching
+#     individual ASCII characters (the only thing that can appear in the rules.)
+#   The "set" names appearing in the code below (default, etc.)  need special
+#     handling because they do not correspond to a normal set of characters,
+#     but trigger special handling by code in the state machine.
+#
+$i = 128;
+foreach $setName (sort keys %charClasses) {
+    if ($setName eq "default") {
+        $charClasses{$setName} = 255;}
+    elsif ($setName eq "escaped") {
+        $charClasses{$setName} = 254;}
+    elsif ($setName eq "escapedP") {
+        $charClasses{$setName} = 253;}
+    elsif ($setName eq "eof") {
+        $charClasses{$setName} = 252;}
+    else {
+        # Normal (single) character class.  Number them.
+        $charClasses{$setName} = $i;
+        $i++;
+    }
+}
+
+
+my ($sec, $min, $hour, , $day, $mon, $year, $wday, $yday, $isdst) = localtime;
+$year += 1900;
+
+if ($javaOutput) {
+    print "/*\n";
+    print " *******************************************************************************\n";
+    print " * Copyright (C) 2003-$year,\n";
+    print " * International Business Machines Corporation and others. All Rights Reserved.\n";
+    print " *******************************************************************************\n";
+    print " */\n";
+    print " \n";
+    print "package com.ibm.icu.text;\n";
+    print " \n";
+    print "/**\n";
+    print " * Generated Java File.  Do not edit by hand.\n";
+    print " * This file contains the state table for the ICU Rule Based Break Iterator\n";
+    print " * rule parser.\n";
+    print " * It is generated by the Perl script \"rbbicst.pl\" from\n";
+    print " * the rule parser state definitions file \"rbbirpt.txt\".\n";
+    print " * \@internal \n";
+    print " *\n";
+    print " */\n";
+
+    print "class RBBIRuleParseTable\n";
+    print "{\n";
+
+     #
+    # Emit the constants for the actions to be performed.
+    #
+    $n = 1;
+    foreach $act (sort keys %actions) {
+        print "     static final short $act = $n;\n";
+        $n++;
+    }
+    print " \n";
+    
+    #
+    # Emit constants for char class names
+    #
+    foreach $setName (sort keys %charClasses) {
+       print "     static final short kRuleSet_$setName = $charClasses{$setName};\n";
+    }
+    print "\n\n";
+    
+    
+    print "   static class RBBIRuleTableElement { \n";
+    print "      short      fAction; \n";
+    print "      short      fCharClass; \n";
+    print "      short      fNextState; \n";
+    print "      short      fPushState; \n";
+    print "      boolean    fNextChar;  \n";
+    print "      String     fStateName; \n";
+    print "      RBBIRuleTableElement(short a, int cc, int ns, int ps, boolean nc, String sn) {  \n";
+    print "      fAction = a; \n";
+    print "      fCharClass = (short)cc; \n";
+    print "      fNextState = (short)ns; \n";
+    print "      fPushState = (short)ps; \n";
+    print "      fNextChar  = nc; \n";
+    print "      fStateName = sn; \n";
+    print "   } \n";
+    print "   }; \n";
+    print "  \n";
+    
+    
+    print "    static RBBIRuleTableElement[] gRuleParseStateTable = { \n ";
+    print "      new RBBIRuleTableElement(doNOP, 0, 0,0,  true,   null )     //  0 \n";  #output the unused state 0. 
+    for ($state=1; $state < $num_states; $state++) {
+        print "     , new RBBIRuleTableElement($state_func_name[$state],";
+        if ($state_literal_chars[$state] ne "") {
+            $c = $state_literal_chars[$state];
+            print("'$c', "); 
+        }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], ";
+ 
+        # if this is the first row of the table for this state, put out the state name.
+        if ($stateNames[$state] ne "") {
+            print "  \"$stateNames[$state]\") ";
+        } else {
+            print "  null ) ";
+        }
+            
+        # Put out a comment showing the number (index) of this state row,
+        print "    //  $state ";
+        print "\n";
+    }
+    print " };\n";
+
+    print "}; \n";
+    
+}
+else
+{
+    #
+    #  C++ Output ...
+    #
+
+
+    print "//---------------------------------------------------------------------------------\n";
+    print "//\n";
+    print "// Generated Header File.  Do not edit by hand.\n";
+    print "//    This file contains the state table for the ICU Rule Based Break Iterator\n";
+    print "//    rule parser.\n";
+    print "//    It is generated by the Perl script \"rbbicst.pl\" from\n";
+    print "//    the rule parser state definitions file \"rbbirpt.txt\".\n";
+    print "//\n";
+    print "//   Copyright (C) 2002-$year 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 RBBI rule scanning.\n";
+    print "//\n";
+    foreach $setName (sort keys %charClasses) {
+        if ($charClasses{$setName} < 250) {
+           # Normal character class.
+           print "    static const uint8_t kRuleSet_$setName = $charClasses{$setName};\n";
+        }
+    }
+    print "\n\n";
+
+    #
+    # Emit the enum for the actions to be performed.
+    #
+    print "enum RBBI_RuleParseAction {\n";
+    foreach $act (sort keys %actions) {
+        print "    $act,\n";
+    }
+    print "    rbbiLastAction};\n\n";
+
+    #
+    # Emit the struct definition for transtion table elements.
+    #
+    print "//-------------------------------------------------------------------------------\n";
+    print "//\n";
+    print "//  RBBIRuleTableEl    represents the structure of a row in the transition table\n";
+    print "//                     for the rule parser state machine.\n";
+    print "//-------------------------------------------------------------------------------\n";
+    print "struct RBBIRuleTableEl {\n";
+    print "    RBBI_RuleParseAction          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-stat 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 RBBIRuleTableEl 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 rule parser.
+    #
+    print "#ifdef RBBI_DEBUG\n";
+    print "static const char * const RBBIRuleStateNames[] = {";
+    for ($state=0; $state<$num_states; $state++) {
+        if ($stateNames[$state] ne "") {
+            print "     \"$stateNames[$state]\",\n";
+        } else {
+            print "    0,\n";
+        }
+    }
+    print "    0};\n";
+    print "#endif\n\n";
+
+    print "U_NAMESPACE_END\n";
+    print "#endif\n";
+}
+
+
+
diff --git a/source/common/rbbidata.cpp b/source/common/rbbidata.cpp
new file mode 100644
index 0000000..09d4796
--- /dev/null
+++ b/source/common/rbbidata.cpp
@@ -0,0 +1,446 @@
+/*
+***************************************************************************
+*   Copyright (C) 1999-2010 International Business Machines Corporation   *
+*   and others. All rights reserved.                                      *
+***************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/utypes.h"
+#include "rbbidata.h"
+#include "rbbirb.h"
+#include "utrie.h"
+#include "udatamem.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "umutex.h"
+
+#include "uassert.h"
+
+
+//-----------------------------------------------------------------------------------
+//
+//   Trie access folding function.  Copied as-is from properties code in uchar.c
+//
+//-----------------------------------------------------------------------------------
+U_CDECL_BEGIN
+static int32_t U_CALLCONV
+getFoldingOffset(uint32_t data) {
+    /* if bit 15 is set, then the folding offset is in bits 14..0 of the 16-bit trie result */
+    if(data&0x8000) {
+        return (int32_t)(data&0x7fff);
+    } else {
+        return 0;
+    }
+}
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+//-----------------------------------------------------------------------------
+//
+//    Constructors.
+//
+//-----------------------------------------------------------------------------
+RBBIDataWrapper::RBBIDataWrapper(const RBBIDataHeader *data, UErrorCode &status) {
+    init(data, status);
+}
+
+RBBIDataWrapper::RBBIDataWrapper(const RBBIDataHeader *data, enum EDontAdopt, UErrorCode &status) {
+    init(data, status);
+    fDontFreeData = TRUE;
+}
+
+RBBIDataWrapper::RBBIDataWrapper(UDataMemory* udm, UErrorCode &status) {
+    const RBBIDataHeader *d = (const RBBIDataHeader *)
+        // ((char *)&(udm->pHeader->info) + udm->pHeader->info.size);
+        // taking into consideration the padding added in by udata_write
+        ((char *)(udm->pHeader) + udm->pHeader->dataHeader.headerSize);
+    init(d, status);
+    fUDataMem = udm;
+}
+
+//-----------------------------------------------------------------------------
+//
+//    init().   Does most of the work of construction, shared between the
+//              constructors.
+//
+//-----------------------------------------------------------------------------
+void RBBIDataWrapper::init(const RBBIDataHeader *data, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return;
+    }
+    fHeader = data;
+    if (fHeader->fMagic != 0xb1a0 || fHeader->fFormatVersion[0] != 3) 
+    {
+        status = U_INVALID_FORMAT_ERROR;
+        return;
+    }
+    // Note: in ICU version 3.2 and earlier, there was a formatVersion 1
+    //       that is no longer supported.  At that time fFormatVersion was
+    //       an int32_t field, rather than an array of 4 bytes.
+
+    fDontFreeData = FALSE;
+    fUDataMem     = NULL;
+    fReverseTable = NULL;
+    fSafeFwdTable = NULL;
+    fSafeRevTable = NULL;
+    if (data->fFTableLen != 0) {
+        fForwardTable = (RBBIStateTable *)((char *)data + fHeader->fFTable);
+    }
+    if (data->fRTableLen != 0) {
+        fReverseTable = (RBBIStateTable *)((char *)data + fHeader->fRTable);
+    }
+    if (data->fSFTableLen != 0) {
+        fSafeFwdTable = (RBBIStateTable *)((char *)data + fHeader->fSFTable);
+    }
+    if (data->fSRTableLen != 0) {
+        fSafeRevTable = (RBBIStateTable *)((char *)data + fHeader->fSRTable);
+    }
+
+
+    utrie_unserialize(&fTrie,
+                       (uint8_t *)data + fHeader->fTrie,
+                       fHeader->fTrieLen,
+                       &status);
+    if (U_FAILURE(status)) {
+        return;
+    }
+    fTrie.getFoldingOffset=getFoldingOffset;
+
+
+    fRuleSource   = (UChar *)((char *)data + fHeader->fRuleSource);
+    fRuleString.setTo(TRUE, fRuleSource, -1);
+    U_ASSERT(data->fRuleSourceLen > 0);
+
+    fRuleStatusTable = (int32_t *)((char *)data + fHeader->fStatusTable);
+    fStatusMaxIdx    = data->fStatusTableLen / sizeof(int32_t);
+
+    fRefCount = 1;
+
+#ifdef RBBI_DEBUG
+    char *debugEnv = getenv("U_RBBIDEBUG");
+    if (debugEnv && uprv_strstr(debugEnv, "data")) {this->printData();}
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+//
+//    Destructor.     Don't call this - use removeReference() instead.
+//
+//-----------------------------------------------------------------------------
+RBBIDataWrapper::~RBBIDataWrapper() {
+    U_ASSERT(fRefCount == 0);
+    if (fUDataMem) {
+        udata_close(fUDataMem);
+    } else if (!fDontFreeData) {
+        uprv_free((void *)fHeader);
+    }
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+//   Operator ==    Consider two RBBIDataWrappers to be equal if they
+//                  refer to the same underlying data.  Although
+//                  the data wrappers are normally shared between
+//                  iterator instances, it's possible to independently
+//                  open the same data twice, and get two instances, which
+//                  should still be ==.
+//
+//-----------------------------------------------------------------------------
+UBool RBBIDataWrapper::operator ==(const RBBIDataWrapper &other) const {
+    if (fHeader == other.fHeader) {
+        return TRUE;
+    }
+    if (fHeader->fLength != other.fHeader->fLength) {
+        return FALSE;
+    }
+    if (uprv_memcmp(fHeader, other.fHeader, fHeader->fLength) == 0) {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+int32_t  RBBIDataWrapper::hashCode() {
+    return fHeader->fFTableLen;
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+//    Reference Counting.   A single RBBIDataWrapper object is shared among
+//                          however many RulesBasedBreakIterator instances are
+//                          referencing the same data.
+//
+//-----------------------------------------------------------------------------
+void RBBIDataWrapper::removeReference() {
+    if (umtx_atomic_dec(&fRefCount) == 0) {
+        delete this;
+    }
+}
+
+
+RBBIDataWrapper *RBBIDataWrapper::addReference() {
+   umtx_atomic_inc(&fRefCount);
+   return this;
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+//  getRuleSourceString
+//
+//-----------------------------------------------------------------------------
+const UnicodeString &RBBIDataWrapper::getRuleSourceString() const {
+    return fRuleString;
+}
+
+
+//-----------------------------------------------------------------------------
+//
+//  print   -  debugging function to dump the runtime data tables.
+//
+//-----------------------------------------------------------------------------
+#ifdef RBBI_DEBUG
+void  RBBIDataWrapper::printTable(const char *heading, const RBBIStateTable *table) {
+    uint32_t   c;
+    uint32_t   s;
+
+    RBBIDebugPrintf("   %s\n", heading);
+
+    RBBIDebugPrintf("State |  Acc  LA TagIx");
+    for (c=0; c<fHeader->fCatCount; c++) {RBBIDebugPrintf("%3d ", c);}
+    RBBIDebugPrintf("\n------|---------------"); for (c=0;c<fHeader->fCatCount; c++) {
+        RBBIDebugPrintf("----");
+    }
+    RBBIDebugPrintf("\n");
+
+    if (table == NULL) {
+        RBBIDebugPrintf("         N U L L   T A B L E\n\n");
+        return;
+    }
+    for (s=0; s<table->fNumStates; s++) {
+        RBBIStateTableRow *row = (RBBIStateTableRow *)
+                                  (table->fTableData + (table->fRowLen * s));
+        RBBIDebugPrintf("%4d  |  %3d %3d %3d ", s, row->fAccepting, row->fLookAhead, row->fTagIdx);
+        for (c=0; c<fHeader->fCatCount; c++)  {
+            RBBIDebugPrintf("%3d ", row->fNextState[c]);
+        }
+        RBBIDebugPrintf("\n");
+    }
+    RBBIDebugPrintf("\n");
+}
+#endif
+
+
+#ifdef RBBI_DEBUG
+void  RBBIDataWrapper::printData() {
+    RBBIDebugPrintf("RBBI Data at %p\n", (void *)fHeader);
+    RBBIDebugPrintf("   Version = {%d %d %d %d}\n", fHeader->fFormatVersion[0], fHeader->fFormatVersion[1],
+                                                    fHeader->fFormatVersion[2], fHeader->fFormatVersion[3]);
+    RBBIDebugPrintf("   total length of data  = %d\n", fHeader->fLength);
+    RBBIDebugPrintf("   number of character categories = %d\n\n", fHeader->fCatCount);
+
+    printTable("Forward State Transition Table", fForwardTable);
+    printTable("Reverse State Transition Table", fReverseTable);
+    printTable("Safe Forward State Transition Table", fSafeFwdTable);
+    printTable("Safe Reverse State Transition Table", fSafeRevTable);
+
+    RBBIDebugPrintf("\nOrignal Rules source:\n");
+    for (int32_t c=0; fRuleSource[c] != 0; c++) {
+        RBBIDebugPrintf("%c", fRuleSource[c]);
+    }
+    RBBIDebugPrintf("\n\n");
+}
+#endif
+
+
+U_NAMESPACE_END
+U_NAMESPACE_USE
+
+//-----------------------------------------------------------------------------
+//
+//  ubrk_swap   -  byte swap and char encoding swap of RBBI data
+//
+//-----------------------------------------------------------------------------
+
+U_CAPI int32_t U_EXPORT2
+ubrk_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 for break data.
+    //    (Header contents are defined in genbrk.cpp)
+    //
+    const UDataInfo *pInfo = (const UDataInfo *)((const char *)inData+4);
+    if(!(  pInfo->dataFormat[0]==0x42 &&   /* dataFormat="Brk " */
+           pInfo->dataFormat[1]==0x72 &&
+           pInfo->dataFormat[2]==0x6b &&
+           pInfo->dataFormat[3]==0x20 &&
+           pInfo->formatVersion[0]==3  )) {
+        udata_printError(ds, "ubrk_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized\n",
+                         pInfo->dataFormat[0], pInfo->dataFormat[1],
+                         pInfo->dataFormat[2], pInfo->dataFormat[3],
+                         pInfo->formatVersion[0]);
+        *status=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    //
+    // Swap the data header.  (This is the generic ICU Data Header, not the RBBI Specific
+    //                         RBBIDataHeader).  This swap also conveniently gets us
+    //                         the size of the ICU d.h., which lets us locate the start
+    //                         of the RBBI specific data.
+    //
+    int32_t headerSize=udata_swapDataHeader(ds, inData, length, outData, status);
+
+
+    //
+    // Get the RRBI Data Header, and check that it appears to be OK.
+    //
+    //    Note:  ICU 3.2 and earlier, RBBIDataHeader::fDataFormat was actually 
+    //           an int32_t with a value of 1.  Starting with ICU 3.4,
+    //           RBBI's fDataFormat matches the dataFormat field from the
+    //           UDataInfo header, four int8_t bytes.  The value is {3,1,0,0}
+    //
+    const uint8_t  *inBytes =(const uint8_t *)inData+headerSize;
+    RBBIDataHeader *rbbiDH = (RBBIDataHeader *)inBytes;
+    if (ds->readUInt32(rbbiDH->fMagic) != 0xb1a0 || 
+        rbbiDH->fFormatVersion[0] != 3 ||
+        ds->readUInt32(rbbiDH->fLength)  <  sizeof(RBBIDataHeader)) 
+    {
+        udata_printError(ds, "ubrk_swap(): RBBI Data header is invalid.\n");
+        *status=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    //
+    // Prefight operation?  Just return the size
+    //
+    int32_t breakDataLength = ds->readUInt32(rbbiDH->fLength);
+    int32_t totalSize = headerSize + breakDataLength;
+    if (length < 0) {
+        return totalSize;
+    }
+
+    //
+    // Check that length passed in is consistent with length from RBBI data header.
+    //
+    if (length < totalSize) {
+        udata_printError(ds, "ubrk_swap(): too few bytes (%d after ICU Data header) for break data.\n",
+                            breakDataLength);
+        *status=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0;
+        }
+
+
+    //
+    // Swap the Data.  Do the data itself first, then the RBBI 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;
+    RBBIDataHeader  *outputDH = (RBBIDataHeader *)outBytes;
+
+    int32_t   tableStartOffset;
+    int32_t   tableLength;
+
+    //
+    // If not swapping in place, zero out the output buffer before starting.
+    //    Individual tables and other data items within are aligned to 8 byte boundaries
+    //    when originally created.  Any unused space between items needs to be zero.
+    //
+    if (inBytes != outBytes) {
+        uprv_memset(outBytes, 0, breakDataLength);
+    }
+
+    //
+    // Each state table begins with several 32 bit fields.  Calculate the size
+    //   in bytes of these.
+    //
+    int32_t         topSize = offsetof(RBBIStateTable, fTableData);
+
+    // Forward state table.  
+    tableStartOffset = ds->readUInt32(rbbiDH->fFTable);
+    tableLength      = ds->readUInt32(rbbiDH->fFTableLen);
+
+    if (tableLength > 0) {
+        ds->swapArray32(ds, inBytes+tableStartOffset, topSize, 
+                            outBytes+tableStartOffset, status);
+        ds->swapArray16(ds, inBytes+tableStartOffset+topSize, tableLength-topSize,
+                            outBytes+tableStartOffset+topSize, status);
+    }
+    
+    // Reverse state table.  Same layout as forward table, above.
+    tableStartOffset = ds->readUInt32(rbbiDH->fRTable);
+    tableLength      = ds->readUInt32(rbbiDH->fRTableLen);
+
+    if (tableLength > 0) {
+        ds->swapArray32(ds, inBytes+tableStartOffset, topSize, 
+                            outBytes+tableStartOffset, status);
+        ds->swapArray16(ds, inBytes+tableStartOffset+topSize, tableLength-topSize,
+                            outBytes+tableStartOffset+topSize, status);
+    }
+
+    // Safe Forward state table.  Same layout as forward table, above.
+    tableStartOffset = ds->readUInt32(rbbiDH->fSFTable);
+    tableLength      = ds->readUInt32(rbbiDH->fSFTableLen);
+
+    if (tableLength > 0) {
+        ds->swapArray32(ds, inBytes+tableStartOffset, topSize, 
+                            outBytes+tableStartOffset, status);
+        ds->swapArray16(ds, inBytes+tableStartOffset+topSize, tableLength-topSize,
+                            outBytes+tableStartOffset+topSize, status);
+    }
+
+    // Safe Reverse state table.  Same layout as forward table, above.
+    tableStartOffset = ds->readUInt32(rbbiDH->fSRTable);
+    tableLength      = ds->readUInt32(rbbiDH->fSRTableLen);
+
+    if (tableLength > 0) {
+        ds->swapArray32(ds, inBytes+tableStartOffset, topSize, 
+                            outBytes+tableStartOffset, status);
+        ds->swapArray16(ds, inBytes+tableStartOffset+topSize, tableLength-topSize,
+                            outBytes+tableStartOffset+topSize, status);
+    }
+
+    // Trie table for character categories
+    utrie_swap(ds, inBytes+ds->readUInt32(rbbiDH->fTrie), ds->readUInt32(rbbiDH->fTrieLen),
+                            outBytes+ds->readUInt32(rbbiDH->fTrie), status);
+
+    // Source Rules Text.  It's UChar data
+    ds->swapArray16(ds, inBytes+ds->readUInt32(rbbiDH->fRuleSource), ds->readUInt32(rbbiDH->fRuleSourceLen),
+                        outBytes+ds->readUInt32(rbbiDH->fRuleSource), status);
+
+    // Table of rule status values.  It's all int_32 values
+    ds->swapArray32(ds, inBytes+ds->readUInt32(rbbiDH->fStatusTable), ds->readUInt32(rbbiDH->fStatusTableLen),
+                        outBytes+ds->readUInt32(rbbiDH->fStatusTable), status);
+
+    // And, last, the header.
+    //   It is all int32_t values except for fFormataVersion, which is an array of four bytes.
+    //   Swap the whole thing as int32_t, then re-swap the one field.
+    //
+    ds->swapArray32(ds, inBytes, sizeof(RBBIDataHeader), outBytes, status);
+    ds->swapArray32(ds, outputDH->fFormatVersion, 4, outputDH->fFormatVersion, status);
+
+    return totalSize;
+}
+
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
diff --git a/source/common/rbbidata.h b/source/common/rbbidata.h
new file mode 100644
index 0000000..ee6aa48
--- /dev/null
+++ b/source/common/rbbidata.h
@@ -0,0 +1,198 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1999-2005,2008 International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  rbbidata.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   RBBI data formats  Includes
+*
+*                          Structs that describes the format of the Binary RBBI data,
+*                          as it is stored in ICU's data file.
+*
+*      RBBIDataWrapper  -  Instances of this class sit between the
+*                          raw data structs and the RulesBasedBreakIterator objects
+*                          that are created by applications.  The wrapper class
+*                          provides reference counting for the underlying data,
+*                          and direct pointers to data that would not otherwise
+*                          be accessible without ugly pointer arithmetic.  The
+*                          wrapper does not attempt to provide any higher level
+*                          abstractions for the data itself.
+*
+*                          There will be only one instance of RBBIDataWrapper for any
+*                          set of RBBI run time data being shared by instances
+*                          (clones) of RulesBasedBreakIterator.
+*/
+
+#ifndef __RBBIDATA_H__
+#define __RBBIDATA_H__
+
+#include "unicode/utypes.h"
+#include "unicode/udata.h"
+#include "udataswp.h"
+
+/**
+ * Swap RBBI data. See udataswp.h.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+ubrk_swap(const UDataSwapper *ds,
+          const void *inData, int32_t length, void *outData,
+          UErrorCode *pErrorCode);
+
+#ifdef XP_CPLUSPLUS
+
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+#include "utrie.h"
+
+U_NAMESPACE_BEGIN
+
+/*  
+ *   The following structs map exactly onto the raw data from ICU common data file. 
+ */
+struct RBBIDataHeader {
+    uint32_t         fMagic;           /*  == 0xbla0                                               */
+    uint8_t          fFormatVersion[4]; /* Data Format.  Same as the value in struct UDataInfo      */
+                                       /*   if there is one associated with this data.             */
+                                       /*     (version originates in rbbi, is copied to UDataInfo) */
+                                       /*   For ICU 3.2 and earlier, this field was                */
+                                       /*       uint32_t  fVersion                                 */
+                                       /*   with a value of 1.                                     */
+    uint32_t         fLength;          /*  Total length in bytes of this RBBI Data,                */
+                                       /*      including all sections, not just the header.        */
+    uint32_t         fCatCount;        /*  Number of character categories.                         */
+
+    /*                                                                        */
+    /*  Offsets and sizes of each of the subsections within the RBBI data.    */
+    /*  All offsets are bytes from the start of the RBBIDataHeader.           */
+    /*  All sizes are in bytes.                                               */
+    /*                                                                        */
+    uint32_t         fFTable;         /*  forward state transition table. */
+    uint32_t         fFTableLen;
+    uint32_t         fRTable;         /*  Offset to the reverse state transition table. */
+    uint32_t         fRTableLen;
+    uint32_t         fSFTable;        /*  safe point forward transition table */
+    uint32_t         fSFTableLen;
+    uint32_t         fSRTable;        /*  safe point reverse transition table */
+    uint32_t         fSRTableLen;
+    uint32_t         fTrie;           /*  Offset to Trie data for character categories */
+    uint32_t         fTrieLen;
+    uint32_t         fRuleSource;     /*  Offset to the source for for the break */
+    uint32_t         fRuleSourceLen;  /*    rules.  Stored UChar *. */
+    uint32_t         fStatusTable;    /* Offset to the table of rule status values */
+    uint32_t         fStatusTableLen;
+
+    uint32_t         fReserved[6];    /*  Reserved for expansion */
+
+};
+
+
+
+struct  RBBIStateTableRow {
+    int16_t          fAccepting;    /*  Non-zero if this row is for an accepting state.   */
+                                    /*  Value 0: not an accepting state.                  */
+                                    /*       -1: Unconditional Accepting state.           */
+                                    /*    positive:  Look-ahead match has completed.      */
+                                    /*           Actual boundary position happened earlier */
+                                    /*           Value here == fLookAhead in earlier      */
+                                    /*              state, at actual boundary pos.        */
+    int16_t          fLookAhead;    /*  Non-zero if this row is for a state that          */
+                                    /*    corresponds to a '/' in the rule source.        */
+                                    /*    Value is the same as the fAccepting             */
+                                    /*      value for the rule (which will appear         */
+                                    /*      in a different state.                         */
+    int16_t          fTagIdx;       /*  Non-zero if this row covers a {tagged} position   */
+                                    /*     from a rule.  Value is the index in the        */
+                                    /*     StatusTable of the set of matching             */
+                                    /*     tags (rule status values)                      */
+    int16_t          fReserved;
+    uint16_t         fNextState[2]; /*  Next State, indexed by char category.             */
+                                    /*    Array Size is fNumCols from the                 */
+                                    /*    state table header.                             */
+                                    /*    CAUTION:  see RBBITableBuilder::getTableSize()  */
+                                    /*              before changing anything here.        */
+};
+
+
+struct RBBIStateTable {
+    uint32_t         fNumStates;    /*  Number of states.                                 */
+    uint32_t         fRowLen;       /*  Length of a state table row, in bytes.            */
+    uint32_t         fFlags;        /*  Option Flags for this state table                 */
+    uint32_t         fReserved;     /*  reserved                                          */
+    char             fTableData[4]; /*  First RBBIStateTableRow begins here.              */
+                                    /*    (making it char[] simplifies ugly address       */
+                                    /*     arithmetic for indexing variable length rows.) */
+};
+
+typedef enum {
+    RBBI_LOOKAHEAD_HARD_BREAK = 1,
+    RBBI_BOF_REQUIRED = 2
+} RBBIStateTableFlags;
+
+
+/*                                        */
+/*   The reference counting wrapper class */
+/*                                        */
+class RBBIDataWrapper : public UMemory {
+public:
+    enum EDontAdopt {
+        kDontAdopt
+    };
+    RBBIDataWrapper(const RBBIDataHeader *data, UErrorCode &status);
+    RBBIDataWrapper(const RBBIDataHeader *data, enum EDontAdopt dontAdopt, UErrorCode &status);
+    RBBIDataWrapper(UDataMemory* udm, UErrorCode &status);
+    ~RBBIDataWrapper();
+
+    void                  init(const RBBIDataHeader *data, UErrorCode &status);
+    RBBIDataWrapper      *addReference();
+    void                  removeReference();
+    UBool                 operator ==(const RBBIDataWrapper &other) const;
+    int32_t               hashCode();
+    const UnicodeString  &getRuleSourceString() const;
+#ifdef RBBI_DEBUG
+    void                  printData();
+    void                  printTable(const char *heading, const RBBIStateTable *table);
+#else
+    #define printData()
+    #define printTable(heading, table)
+#endif
+
+    /*                                     */
+    /*   Pointers to items within the data */
+    /*                                     */
+    const RBBIDataHeader     *fHeader;
+    const RBBIStateTable     *fForwardTable;
+    const RBBIStateTable     *fReverseTable;
+    const RBBIStateTable     *fSafeFwdTable;
+    const RBBIStateTable     *fSafeRevTable;
+    const UChar              *fRuleSource;
+    const int32_t            *fRuleStatusTable; 
+
+    /* number of int32_t values in the rule status table.   Used to sanity check indexing */
+    int32_t             fStatusMaxIdx;
+
+    UTrie               fTrie;
+
+private:
+    int32_t             fRefCount;
+    UDataMemory        *fUDataMem;
+    UnicodeString       fRuleString;
+    UBool               fDontFreeData;
+
+    RBBIDataWrapper(const RBBIDataWrapper &other); /*  forbid copying of this class */
+    RBBIDataWrapper &operator=(const RBBIDataWrapper &other); /*  forbid copying of this class */
+};
+
+
+
+U_NAMESPACE_END
+
+#endif /* C++ */
+
+#endif
diff --git a/source/common/rbbinode.cpp b/source/common/rbbinode.cpp
new file mode 100644
index 0000000..49e0ad3
--- /dev/null
+++ b/source/common/rbbinode.cpp
@@ -0,0 +1,358 @@
+/*
+***************************************************************************
+*   Copyright (C) 2002-2008 International Business Machines Corporation   *
+*   and others. All rights reserved.                                      *
+***************************************************************************
+*/
+
+//
+//  File:  rbbinode.cpp
+//
+//         Implementation of class RBBINode, which represents a node in the
+//         tree generated when parsing the Rules Based Break Iterator rules.
+//
+//         This "Class" is actually closer to a struct.
+//         Code using it is expected to directly access fields much of the time.
+//
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/unistr.h"
+#include "unicode/uniset.h"
+#include "unicode/uchar.h"
+#include "unicode/parsepos.h"
+#include "uvector.h"
+
+#include "rbbirb.h"
+#include "rbbinode.h"
+
+#include "uassert.h"
+
+
+U_NAMESPACE_BEGIN
+
+#ifdef RBBI_DEBUG
+static int  gLastSerial = 0;
+#endif
+
+
+//-------------------------------------------------------------------------
+//
+//    Constructor.   Just set the fields to reasonable default values.
+//
+//-------------------------------------------------------------------------
+RBBINode::RBBINode(NodeType t) : UMemory() {
+#ifdef RBBI_DEBUG
+    fSerialNum    = ++gLastSerial;
+#endif
+    fType         = t;
+    fParent       = NULL;
+    fLeftChild    = NULL;
+    fRightChild   = NULL;
+    fInputSet     = NULL;
+    fFirstPos     = 0;
+    fLastPos      = 0;
+    fNullable     = FALSE;
+    fLookAheadEnd = FALSE;
+    fVal          = 0;
+    fPrecedence   = precZero;
+
+    UErrorCode     status = U_ZERO_ERROR;
+    fFirstPosSet  = new UVector(status);  // TODO - get a real status from somewhere
+    fLastPosSet   = new UVector(status);
+    fFollowPos    = new UVector(status);
+    if      (t==opCat)    {fPrecedence = precOpCat;}
+    else if (t==opOr)     {fPrecedence = precOpOr;}
+    else if (t==opStart)  {fPrecedence = precStart;}
+    else if (t==opLParen) {fPrecedence = precLParen;}
+
+}
+
+
+RBBINode::RBBINode(const RBBINode &other) : UMemory(other) {
+#ifdef RBBI_DEBUG
+    fSerialNum   = ++gLastSerial;
+#endif
+    fType        = other.fType;
+    fParent      = NULL;
+    fLeftChild   = NULL;
+    fRightChild  = NULL;
+    fInputSet    = other.fInputSet;
+    fPrecedence  = other.fPrecedence;
+    fText        = other.fText;
+    fFirstPos    = other.fFirstPos;
+    fLastPos     = other.fLastPos;
+    fNullable    = other.fNullable;
+    fVal         = other.fVal;
+    UErrorCode     status = U_ZERO_ERROR;
+    fFirstPosSet = new UVector(status);   // TODO - get a real status from somewhere
+    fLastPosSet  = new UVector(status);
+    fFollowPos   = new UVector(status);
+}
+
+
+//-------------------------------------------------------------------------
+//
+//    Destructor.   Deletes both this node AND any child nodes,
+//                  except in the case of variable reference nodes.  For
+//                  these, the l. child points back to the definition, which
+//                  is common for all references to the variable, meaning
+//                  it can't be deleted here.
+//
+//-------------------------------------------------------------------------
+RBBINode::~RBBINode() {
+    // printf("deleting node %8x   serial %4d\n", this, this->fSerialNum);
+    delete fInputSet;
+    fInputSet = NULL;
+
+    switch (this->fType) {
+    case varRef:
+    case setRef:
+        // for these node types, multiple instances point to the same "children"
+        // Storage ownership of children handled elsewhere.  Don't delete here.
+        break;
+
+    default:
+        delete        fLeftChild;
+        fLeftChild =   NULL;
+        delete        fRightChild;
+        fRightChild = NULL;
+    }
+
+
+    delete fFirstPosSet;
+    delete fLastPosSet;
+    delete fFollowPos;
+
+}
+
+
+//-------------------------------------------------------------------------
+//
+//    cloneTree     Make a copy of the subtree rooted at this node.
+//                  Discard any variable references encountered along the way,
+//                  and replace with copies of the variable's definitions.
+//                  Used to replicate the expression underneath variable
+//                  references in preparation for generating the DFA tables.
+//
+//-------------------------------------------------------------------------
+RBBINode *RBBINode::cloneTree() {
+    RBBINode    *n;
+
+    if (fType == RBBINode::varRef) {
+        // If the current node is a variable reference, skip over it
+        //   and clone the definition of the variable instead.
+        n = fLeftChild->cloneTree();
+    } else if (fType == RBBINode::uset) {
+        n = this;
+    } else {
+        n = new RBBINode(*this);
+        // Check for null pointer.
+        if (n != NULL) {
+            if (fLeftChild != NULL) {
+                n->fLeftChild          = fLeftChild->cloneTree();
+                n->fLeftChild->fParent = n;
+            }
+            if (fRightChild != NULL) {
+                n->fRightChild          = fRightChild->cloneTree();
+                n->fRightChild->fParent = n;
+            }
+        }
+    }
+    return n;
+}
+
+
+
+//-------------------------------------------------------------------------
+//
+//   flattenVariables   Walk a parse tree, replacing any variable
+//                      references with a copy of the variable's definition.
+//                      Aside from variables, the tree is not changed.
+//
+//                      Return the root of the tree.  If the root was not a variable
+//                      reference, it remains unchanged - the root we started with
+//                      is the root we return.  If, however, the root was a variable
+//                      reference, the root of the newly cloned replacement tree will
+//                      be returned, and the original tree deleted.
+//
+//                      This function works by recursively walking the tree
+//                      without doing anything until a variable reference is
+//                      found, then calling cloneTree() at that point.  Any
+//                      nested references are handled by cloneTree(), not here.
+//
+//-------------------------------------------------------------------------
+RBBINode *RBBINode::flattenVariables() {
+    if (fType == varRef) {
+        RBBINode *retNode = fLeftChild->cloneTree();
+        delete this;
+        return retNode;
+    }
+
+    if (fLeftChild != NULL) {
+        fLeftChild = fLeftChild->flattenVariables();
+        fLeftChild->fParent  = this;
+    }
+    if (fRightChild != NULL) {
+        fRightChild = fRightChild->flattenVariables();
+        fRightChild->fParent = this;
+    }
+    return this;
+}
+
+
+//-------------------------------------------------------------------------
+//
+//  flattenSets    Walk the parse tree, replacing any nodes of type setRef
+//                 with a copy of the expression tree for the set.  A set's
+//                 equivalent expression tree is precomputed and saved as
+//                 the left child of the uset node.
+//
+//-------------------------------------------------------------------------
+void RBBINode::flattenSets() {
+    U_ASSERT(fType != setRef);
+
+    if (fLeftChild != NULL) {
+        if (fLeftChild->fType==setRef) {
+            RBBINode *setRefNode = fLeftChild;
+            RBBINode *usetNode   = setRefNode->fLeftChild;
+            RBBINode *replTree   = usetNode->fLeftChild;
+            fLeftChild           = replTree->cloneTree();
+            fLeftChild->fParent  = this;
+            delete setRefNode;
+        } else {
+            fLeftChild->flattenSets();
+        }
+    }
+
+    if (fRightChild != NULL) {
+        if (fRightChild->fType==setRef) {
+            RBBINode *setRefNode = fRightChild;
+            RBBINode *usetNode   = setRefNode->fLeftChild;
+            RBBINode *replTree   = usetNode->fLeftChild;
+            fRightChild           = replTree->cloneTree();
+            fRightChild->fParent  = this;
+            delete setRefNode;
+        } else {
+            fRightChild->flattenSets();
+        }
+    }
+}
+
+
+
+//-------------------------------------------------------------------------
+//
+//   findNodes()     Locate all the nodes of the specified type, starting
+//                   at the specified root.
+//
+//-------------------------------------------------------------------------
+void   RBBINode::findNodes(UVector *dest, RBBINode::NodeType kind, UErrorCode &status) {
+    /* test for buffer overflows */
+    if (U_FAILURE(status)) {
+        return;
+    }
+    if (fType == kind) {
+        dest->addElement(this, status);
+    }
+    if (fLeftChild != NULL) {
+        fLeftChild->findNodes(dest, kind, status);
+    }
+    if (fRightChild != NULL) {
+        fRightChild->findNodes(dest, kind, status);
+    }
+}
+
+
+//-------------------------------------------------------------------------
+//
+//    print.         Print out a single node, for debugging.
+//
+//-------------------------------------------------------------------------
+#ifdef RBBI_DEBUG
+void RBBINode::printNode() {
+    static const char * const nodeTypeNames[] = {
+                "setRef",
+                "uset",
+                "varRef",
+                "leafChar",
+                "lookAhead",
+                "tag",
+                "endMark",
+                "opStart",
+                "opCat",
+                "opOr",
+                "opStar",
+                "opPlus",
+                "opQuestion",
+                "opBreak",
+                "opReverse",
+                "opLParen"
+    };
+
+    if (this==NULL) {
+        RBBIDebugPrintf("%10p", (void *)this);
+    } else {
+        RBBIDebugPrintf("%10p  %12s  %10p  %10p  %10p      %4d     %6d   %d ",
+            (void *)this, nodeTypeNames[fType], (void *)fParent, (void *)fLeftChild, (void *)fRightChild,
+            fSerialNum, fFirstPos, fVal);
+        if (fType == varRef) {
+            RBBI_DEBUG_printUnicodeString(fText);
+        }
+    }
+    RBBIDebugPrintf("\n");
+}
+#endif
+
+
+#ifdef RBBI_DEBUG
+U_CFUNC void RBBI_DEBUG_printUnicodeString(const UnicodeString &s, int minWidth)
+{
+    int i;
+    for (i=0; i<s.length(); i++) {
+        RBBIDebugPrintf("%c", s.charAt(i));
+        // putc(s.charAt(i), stdout);
+    }
+    for (i=s.length(); i<minWidth; i++) {
+        RBBIDebugPrintf(" ");
+    }
+}
+#endif
+
+
+//-------------------------------------------------------------------------
+//
+//    print.         Print out the tree of nodes rooted at "this"
+//
+//-------------------------------------------------------------------------
+#ifdef RBBI_DEBUG
+void RBBINode::printTree(UBool printHeading) {
+    if (printHeading) {
+        RBBIDebugPrintf( "-------------------------------------------------------------------\n"
+                         "    Address       type         Parent   LeftChild  RightChild    serial  position value\n"
+              );
+    }
+    this->printNode();
+    if (this != NULL) {
+        // Only dump the definition under a variable reference if asked to.
+        // Unconditinally dump children of all other node types.
+        if (fType != varRef) {
+            if (fLeftChild != NULL) {
+                fLeftChild->printTree(FALSE);
+            }
+            
+            if (fRightChild != NULL) {
+                fRightChild->printTree(FALSE);
+            }
+        }
+    }
+}
+#endif
+
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
diff --git a/source/common/rbbinode.h b/source/common/rbbinode.h
new file mode 100644
index 0000000..0cbf6a7
--- /dev/null
+++ b/source/common/rbbinode.h
@@ -0,0 +1,118 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2001-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef RBBINODE_H
+#define RBBINODE_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+
+//
+//  class RBBINode
+//
+//                    Represents a node in the parse tree generated when reading
+//                    a rule file.
+//
+
+U_NAMESPACE_BEGIN
+
+class    UnicodeSet;
+class    UVector;
+
+class RBBINode : public UMemory {
+    public:
+        enum NodeType {
+            setRef,
+            uset,
+            varRef,
+            leafChar,
+            lookAhead,
+            tag,
+            endMark,
+            opStart,
+            opCat,
+            opOr,
+            opStar,
+            opPlus,
+            opQuestion,
+            opBreak,
+            opReverse,
+            opLParen
+        };
+
+        enum OpPrecedence {      
+            precZero,
+            precStart,
+            precLParen,
+            precOpOr,
+            precOpCat
+        };
+            
+        NodeType      fType;
+        RBBINode      *fParent;
+        RBBINode      *fLeftChild;
+        RBBINode      *fRightChild;
+        UnicodeSet    *fInputSet;           // For uset nodes only.
+        OpPrecedence  fPrecedence;          // For binary ops only.
+        
+        UnicodeString fText;                // Text corresponding to this node.
+                                            //   May be lazily evaluated when (if) needed
+                                            //   for some node types.
+        int           fFirstPos;            // Position in the rule source string of the
+                                            //   first text associated with the node.
+                                            //   If there's a left child, this will be the same
+                                            //   as that child's left pos.
+        int           fLastPos;             //  Last position in the rule source string
+                                            //    of any text associated with this node.
+                                            //    If there's a right child, this will be the same
+                                            //    as that child's last postion.
+
+        UBool         fNullable;            // See Aho.
+        int32_t       fVal;                 // For leafChar nodes, the value.
+                                            //   Values are the character category,
+                                            //   corresponds to columns in the final
+                                            //   state transition table.
+
+        UBool         fLookAheadEnd;        // For endMark nodes, set TRUE if
+                                            //   marking the end of a look-ahead rule.
+
+        UVector       *fFirstPosSet;
+        UVector       *fLastPosSet;         // TODO: rename fFirstPos & fLastPos to avoid confusion.
+        UVector       *fFollowPos;
+
+
+        RBBINode(NodeType t);
+        RBBINode(const RBBINode &other);
+        ~RBBINode();
+        
+        RBBINode    *cloneTree();
+        RBBINode    *flattenVariables();
+        void         flattenSets();
+        void         findNodes(UVector *dest, RBBINode::NodeType kind, UErrorCode &status);
+
+#ifdef RBBI_DEBUG
+        void        printNode();
+        void        printTree(UBool withHeading);
+#endif
+
+    private:
+        RBBINode &operator = (const RBBINode &other); // No defs.
+        UBool operator == (const RBBINode &other);    // Private, so these functions won't accidently be used.
+
+#ifdef RBBI_DEBUG
+        int           fSerialNum;           //  Debugging aids.
+#endif
+};
+
+#ifdef RBBI_DEBUG
+U_CFUNC void 
+RBBI_DEBUG_printUnicodeString(const UnicodeString &s, int minWidth=0);
+#endif
+
+U_NAMESPACE_END
+
+#endif
+
diff --git a/source/common/rbbirb.cpp b/source/common/rbbirb.cpp
new file mode 100644
index 0000000..bbc11cd
--- /dev/null
+++ b/source/common/rbbirb.cpp
@@ -0,0 +1,323 @@
+//
+//  file:  rbbirb.cpp
+//
+//  Copyright (C) 2002-2008, International Business Machines Corporation and others.
+//  All Rights Reserved.
+//
+//  This file contains the RBBIRuleBuilder class implementation.  This is the main class for
+//    building (compiling) break rules into the tables required by the runtime
+//    RBBI engine.
+//
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/brkiter.h"
+#include "unicode/rbbi.h"
+#include "unicode/ubrk.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 "cmemory.h"
+#include "cstring.h"
+
+#include "rbbirb.h"
+#include "rbbinode.h"
+
+#include "rbbiscan.h"
+#include "rbbisetb.h"
+#include "rbbitblb.h"
+#include "rbbidata.h"
+
+
+U_NAMESPACE_BEGIN
+
+
+//----------------------------------------------------------------------------------------
+//
+//  Constructor.
+//
+//----------------------------------------------------------------------------------------
+RBBIRuleBuilder::RBBIRuleBuilder(const UnicodeString   &rules,
+                                       UParseError     *parseErr,
+                                       UErrorCode      &status)
+ : fRules(rules)
+{
+    fStatus = &status; // status is checked below
+    fParseError = parseErr;
+    fDebugEnv   = NULL;
+#ifdef RBBI_DEBUG
+    fDebugEnv   = getenv("U_RBBIDEBUG");
+#endif
+
+
+    fForwardTree        = NULL;
+    fReverseTree        = NULL;
+    fSafeFwdTree        = NULL;
+    fSafeRevTree        = NULL;
+    fDefaultTree        = &fForwardTree;
+    fForwardTables      = NULL;
+    fReverseTables      = NULL;
+    fSafeFwdTables      = NULL;
+    fSafeRevTables      = NULL;
+    fRuleStatusVals     = NULL;
+    fChainRules         = FALSE;
+    fLBCMNoChain        = FALSE;
+    fLookAheadHardBreak = FALSE;
+    fUSetNodes          = NULL;
+    fRuleStatusVals     = NULL;
+    fScanner            = NULL;
+    fSetBuilder         = NULL;
+    if (parseErr) {
+        uprv_memset(parseErr, 0, sizeof(UParseError));
+    }
+
+    if (U_FAILURE(status)) {
+        return;
+    }
+
+    fUSetNodes          = new UVector(status); // bcos status gets overwritten here
+    fRuleStatusVals     = new UVector(status);
+    fScanner            = new RBBIRuleScanner(this);
+    fSetBuilder         = new RBBISetBuilder(this);
+    if (U_FAILURE(status)) {
+        return;
+    }
+    if(fSetBuilder == 0 || fScanner == 0 || fUSetNodes == 0 || fRuleStatusVals == 0) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+    }
+}
+
+
+
+//----------------------------------------------------------------------------------------
+//
+//  Destructor
+//
+//----------------------------------------------------------------------------------------
+RBBIRuleBuilder::~RBBIRuleBuilder() {
+
+    int        i;
+    for (i=0; ; i++) {
+        RBBINode *n = (RBBINode *)fUSetNodes->elementAt(i);
+        if (n==NULL) {
+            break;
+        }
+        delete n;
+    }
+
+    delete fUSetNodes;
+    delete fSetBuilder;
+    delete fForwardTables;
+    delete fReverseTables;
+    delete fSafeFwdTables;
+    delete fSafeRevTables;
+
+    delete fForwardTree;
+    delete fReverseTree;
+    delete fSafeFwdTree;
+    delete fSafeRevTree;
+    delete fScanner;
+    delete fRuleStatusVals;
+}
+
+
+
+
+
+//----------------------------------------------------------------------------------------
+//
+//   flattenData() -  Collect up the compiled RBBI rule data and put it into
+//                    the format for saving in ICU data files,
+//                    which is also the format needed by the RBBI runtime engine.
+//
+//----------------------------------------------------------------------------------------
+static int32_t align8(int32_t i) {return (i+7) & 0xfffffff8;}
+
+RBBIDataHeader *RBBIRuleBuilder::flattenData() {
+    int32_t    i;
+
+    if (U_FAILURE(*fStatus)) {
+        return NULL;
+    }
+
+    // Remove comments and whitespace from the rules to make it smaller.
+    UnicodeString strippedRules((const UnicodeString&)RBBIRuleScanner::stripRules(fRules));
+
+    // Calculate the size of each section in the data.
+    //   Sizes here are padded up to a multiple of 8 for better memory alignment.
+    //   Sections sizes actually stored in the header are for the actual data
+    //     without the padding.
+    //
+    int32_t headerSize        = align8(sizeof(RBBIDataHeader));
+    int32_t forwardTableSize  = align8(fForwardTables->getTableSize());
+    int32_t reverseTableSize  = align8(fReverseTables->getTableSize());
+    int32_t safeFwdTableSize  = align8(fSafeFwdTables->getTableSize());
+    int32_t safeRevTableSize  = align8(fSafeRevTables->getTableSize());
+    int32_t trieSize          = align8(fSetBuilder->getTrieSize());
+    int32_t statusTableSize   = align8(fRuleStatusVals->size() * sizeof(int32_t));
+    int32_t rulesSize         = align8((strippedRules.length()+1) * sizeof(UChar));
+
+    int32_t         totalSize = headerSize + forwardTableSize + reverseTableSize
+                                + safeFwdTableSize + safeRevTableSize 
+                                + statusTableSize + trieSize + rulesSize;
+
+    RBBIDataHeader  *data     = (RBBIDataHeader *)uprv_malloc(totalSize);
+    if (data == NULL) {
+        *fStatus = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    uprv_memset(data, 0, totalSize);
+
+
+    data->fMagic            = 0xb1a0;
+    data->fFormatVersion[0] = 3;
+    data->fFormatVersion[1] = 1;
+    data->fFormatVersion[2] = 0;
+    data->fFormatVersion[3] = 0;
+    data->fLength           = totalSize;
+    data->fCatCount         = fSetBuilder->getNumCharCategories();
+
+    data->fFTable        = headerSize;
+    data->fFTableLen     = forwardTableSize;
+    data->fRTable        = data->fFTable  + forwardTableSize;
+    data->fRTableLen     = reverseTableSize;
+    data->fSFTable       = data->fRTable  + reverseTableSize;
+    data->fSFTableLen    = safeFwdTableSize;
+    data->fSRTable       = data->fSFTable + safeFwdTableSize;
+    data->fSRTableLen    = safeRevTableSize;
+
+    data->fTrie          = data->fSRTable + safeRevTableSize;
+    data->fTrieLen       = fSetBuilder->getTrieSize();
+    data->fStatusTable   = data->fTrie    + trieSize;
+    data->fStatusTableLen= statusTableSize;
+    data->fRuleSource    = data->fStatusTable + statusTableSize;
+    data->fRuleSourceLen = strippedRules.length() * sizeof(UChar);
+
+    uprv_memset(data->fReserved, 0, sizeof(data->fReserved));
+
+    fForwardTables->exportTable((uint8_t *)data + data->fFTable);
+    fReverseTables->exportTable((uint8_t *)data + data->fRTable);
+    fSafeFwdTables->exportTable((uint8_t *)data + data->fSFTable);
+    fSafeRevTables->exportTable((uint8_t *)data + data->fSRTable);
+    fSetBuilder->serializeTrie ((uint8_t *)data + data->fTrie);
+
+    int32_t *ruleStatusTable = (int32_t *)((uint8_t *)data + data->fStatusTable);
+    for (i=0; i<fRuleStatusVals->size(); i++) {
+        ruleStatusTable[i] = fRuleStatusVals->elementAti(i);
+    }
+
+    strippedRules.extract((UChar *)((uint8_t *)data+data->fRuleSource), rulesSize/2+1, *fStatus);
+
+    return data;
+}
+
+
+
+
+
+
+//----------------------------------------------------------------------------------------
+//
+//  createRuleBasedBreakIterator    construct from source rules that are passed in
+//                                  in a UnicodeString
+//
+//----------------------------------------------------------------------------------------
+BreakIterator *
+RBBIRuleBuilder::createRuleBasedBreakIterator( const UnicodeString    &rules,
+                                    UParseError      *parseError,
+                                    UErrorCode       &status)
+{
+    // status checked below
+
+    //
+    // Read the input rules, generate a parse tree, symbol table,
+    // and list of all Unicode Sets referenced by the rules.
+    //
+    RBBIRuleBuilder  builder(rules, parseError, status);
+    if (U_FAILURE(status)) { // status checked here bcos build below doesn't
+        return NULL;
+    }
+    builder.fScanner->parse();
+
+    //
+    // UnicodeSet processing.
+    //    Munge the Unicode Sets to create a set of character categories.
+    //    Generate the mapping tables (TRIE) from input 32-bit characters to
+    //    the character categories.
+    //
+    builder.fSetBuilder->build();
+
+
+    //
+    //   Generate the DFA state transition table.
+    //
+    builder.fForwardTables = new RBBITableBuilder(&builder, &builder.fForwardTree);
+    builder.fReverseTables = new RBBITableBuilder(&builder, &builder.fReverseTree);
+    builder.fSafeFwdTables = new RBBITableBuilder(&builder, &builder.fSafeFwdTree);
+    builder.fSafeRevTables = new RBBITableBuilder(&builder, &builder.fSafeRevTree);
+    if (U_SUCCESS(status)
+        && (builder.fForwardTables == NULL || builder.fReverseTables == NULL ||
+            builder.fSafeFwdTables == NULL || builder.fSafeRevTables == NULL)) 
+    {
+        status = U_MEMORY_ALLOCATION_ERROR;
+    }
+    
+    // Before building the tables, check to make sure the status is ok.
+    if (U_FAILURE(status)) {
+    	delete builder.fForwardTables; builder.fForwardTables = NULL;
+    	delete builder.fReverseTables; builder.fReverseTables = NULL;
+    	delete builder.fSafeFwdTables; builder.fSafeFwdTables = NULL;
+    	delete builder.fSafeRevTables; builder.fSafeRevTables = NULL;
+        return NULL;
+    }
+
+    builder.fForwardTables->build();
+    builder.fReverseTables->build();
+    builder.fSafeFwdTables->build();
+    builder.fSafeRevTables->build();
+
+#ifdef RBBI_DEBUG
+    if (builder.fDebugEnv && uprv_strstr(builder.fDebugEnv, "states")) {
+        builder.fForwardTables->printRuleStatusTable();
+    }
+#endif
+
+    //
+    //   Package up the compiled data into a memory image
+    //      in the run-time format.
+    //
+    RBBIDataHeader *data = builder.flattenData(); // returns NULL if error
+    if (U_FAILURE(*builder.fStatus)) {
+        return NULL;
+    }
+
+
+    //
+    //  Clean up the compiler related stuff
+    //
+
+
+    //
+    //  Create a break iterator from the compiled rules.
+    //     (Identical to creation from stored pre-compiled rules)
+    //
+    // status is checked after init in construction.
+    RuleBasedBreakIterator *This = new RuleBasedBreakIterator(data, status);
+    if (U_FAILURE(status)) {
+        delete This;
+        This = NULL;
+    } 
+    else if(This == NULL) { // test for NULL
+        status = U_MEMORY_ALLOCATION_ERROR;
+    }
+    return This;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
diff --git a/source/common/rbbirb.h b/source/common/rbbirb.h
new file mode 100644
index 0000000..deb9b0e
--- /dev/null
+++ b/source/common/rbbirb.h
@@ -0,0 +1,211 @@
+//
+//  rbbirb.h
+//
+//  Copyright (C) 2002-2008, International Business Machines Corporation and others.
+//  All Rights Reserved.
+//
+//  This file contains declarations for several classes from the
+//    Rule Based Break Iterator rule builder.
+//
+
+
+#ifndef RBBIRB_H
+#define RBBIRB_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/rbbi.h"
+#include "unicode/uniset.h"
+#include "unicode/parseerr.h"
+#include "uhash.h"
+#include "uvector.h"
+#include "unicode/symtable.h"// For UnicodeSet parsing, is the interface that
+                          //    looks up references to $variables within a set.
+
+
+
+U_NAMESPACE_BEGIN
+
+class               RBBIRuleScanner;
+struct              RBBIRuleTableEl;
+class               RBBISetBuilder;
+class               RBBINode;
+class               RBBITableBuilder;
+
+
+
+//--------------------------------------------------------------------------------
+//
+//   RBBISymbolTable.    Implements SymbolTable interface that is used by the
+//                       UnicodeSet parser to resolve references to $variables.
+//
+//--------------------------------------------------------------------------------
+class RBBISymbolTableEntry : public UMemory { // The symbol table hash table contains one
+public:                                       //   of these structs for each entry.
+    RBBISymbolTableEntry();
+    UnicodeString          key;
+    RBBINode               *val;
+    ~RBBISymbolTableEntry();
+
+private:
+    RBBISymbolTableEntry(const RBBISymbolTableEntry &other); // forbid copying of this class
+    RBBISymbolTableEntry &operator=(const RBBISymbolTableEntry &other); // forbid copying of this class
+};
+
+
+class RBBISymbolTable : public UMemory, public SymbolTable {
+private:
+    const UnicodeString      &fRules;
+    UHashtable               *fHashTable;
+    RBBIRuleScanner          *fRuleScanner;
+
+    // These next two fields are part of the mechanism for passing references to
+    //   already-constructed UnicodeSets back to the UnicodeSet constructor
+    //   when the pattern includes $variable references.
+    const UnicodeString      ffffString;      // = "/uffff"
+    UnicodeSet              *fCachedSetLookup;
+
+public:
+    //  API inherited from class SymbolTable
+    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;
+
+    //  Additional Functions
+    RBBISymbolTable(RBBIRuleScanner *, const UnicodeString &fRules, UErrorCode &status);
+    virtual ~RBBISymbolTable();
+
+    virtual RBBINode *lookupNode(const UnicodeString &key) const;
+    virtual void      addEntry  (const UnicodeString &key, RBBINode *val, UErrorCode &err);
+
+#ifdef RBBI_DEBUG
+    virtual void      rbbiSymtablePrint() const;
+#else
+    // A do-nothing inline function for non-debug builds.  Member funcs can't be empty
+    //  or the call sites won't compile.
+    int32_t fFakeField;
+    #define rbbiSymtablePrint() fFakeField=0; 
+#endif
+
+private:
+    RBBISymbolTable(const RBBISymbolTable &other); // forbid copying of this class
+    RBBISymbolTable &operator=(const RBBISymbolTable &other); // forbid copying of this class
+};
+
+
+//--------------------------------------------------------------------------------
+//
+//  class RBBIRuleBuilder       The top-level class handling RBBI rule compiling.
+//
+//--------------------------------------------------------------------------------
+class RBBIRuleBuilder : public UMemory {
+public:
+
+    //  Create a rule based break iterator from a set of rules.
+    //  This function is the main entry point into the rule builder.  The
+    //   public ICU API for creating RBBIs uses this function to do the actual work.
+    //
+    static BreakIterator * createRuleBasedBreakIterator( const UnicodeString    &rules,
+                                    UParseError      *parseError,
+                                    UErrorCode       &status);
+
+public:
+    // The "public" functions and data members that appear below are accessed
+    //  (and shared) by the various parts that make up the rule builder.  They
+    //  are NOT intended to be accessed by anything outside of the
+    //  rule builder implementation.
+    RBBIRuleBuilder(const UnicodeString  &rules,
+                    UParseError          *parseErr,
+                    UErrorCode           &status
+        );
+
+    virtual    ~RBBIRuleBuilder();
+    char                          *fDebugEnv;        // controls debug trace output
+    UErrorCode                    *fStatus;          // Error reporting.  Keeping status
+    UParseError                   *fParseError;      //   here avoids passing it everywhere.
+    const UnicodeString           &fRules;           // The rule string that we are compiling
+
+    RBBIRuleScanner               *fScanner;         // The scanner.
+    RBBINode                      *fForwardTree;     // The parse trees, generated by the scanner,
+    RBBINode                      *fReverseTree;     //   then manipulated by subsequent steps.
+    RBBINode                      *fSafeFwdTree;
+    RBBINode                      *fSafeRevTree;
+
+    RBBINode                      **fDefaultTree;    // For rules not qualified with a !
+                                                     //   the tree to which they belong to.
+
+    UBool                         fChainRules;       // True for chained Unicode TR style rules.
+                                                     // False for traditional regexp rules.
+
+    UBool                         fLBCMNoChain;      // True:  suppress chaining of rules on
+                                                     //   chars with LineBreak property == CM.
+
+    UBool                         fLookAheadHardBreak;  // True:  Look ahead matches cause an
+                                                     // immediate break, no continuing for the
+                                                     // longest match.
+
+    RBBISetBuilder                *fSetBuilder;      // Set and Character Category builder.
+    UVector                       *fUSetNodes;       // Vector of all uset nodes.
+
+    RBBITableBuilder              *fForwardTables;   // State transition tables
+    RBBITableBuilder              *fReverseTables;
+    RBBITableBuilder              *fSafeFwdTables;
+    RBBITableBuilder              *fSafeRevTables;
+
+    UVector                       *fRuleStatusVals;  // The values that can be returned
+                                                     //   from getRuleStatus().
+
+    RBBIDataHeader                *flattenData();    // Create the flattened (runtime format)
+                                                     // data tables..
+private:
+    RBBIRuleBuilder(const RBBIRuleBuilder &other); // forbid copying of this class
+    RBBIRuleBuilder &operator=(const RBBIRuleBuilder &other); // forbid copying of this class
+};
+
+
+
+
+//----------------------------------------------------------------------------
+//
+//   RBBISetTableEl   is an entry in the hash table of UnicodeSets that have
+//                    been encountered.  The val Node will be of nodetype uset
+//                    and contain pointers to the actual UnicodeSets.
+//                    The Key is the source string for initializing the set.
+//
+//                    The hash table is used to avoid creating duplicate
+//                    unnamed (not $var references) UnicodeSets.
+//
+//                    Memory Management:
+//                       The Hash Table owns these RBBISetTableEl structs and
+//                            the key strings.  It does NOT own the val nodes.
+//
+//----------------------------------------------------------------------------
+struct RBBISetTableEl {
+    UnicodeString *key;
+    RBBINode      *val;
+};
+
+
+//----------------------------------------------------------------------------
+//
+//   RBBIDebugPrintf    Printf equivalent, for debugging output.
+//                      Conditional compilation of the implementation lets us
+//                      get rid of the stdio dependency in environments where it
+//                      is unavailable.
+//
+//----------------------------------------------------------------------------
+#ifdef RBBI_DEBUG
+#include <stdio.h>
+#define RBBIDebugPrintf printf
+#define RBBIDebugPuts puts
+#else
+#undef RBBIDebugPrintf 
+#define RBBIDebugPuts(arg)
+#endif
+
+U_NAMESPACE_END
+#endif
+
+
+
diff --git a/source/common/rbbirpt.h b/source/common/rbbirpt.h
new file mode 100644
index 0000000..deea57b
--- /dev/null
+++ b/source/common/rbbirpt.h
@@ -0,0 +1,275 @@
+//---------------------------------------------------------------------------------
+//
+// Generated Header File.  Do not edit by hand.
+//    This file contains the state table for the ICU Rule Based Break Iterator
+//    rule parser.
+//    It is generated by the Perl script "rbbicst.pl" from
+//    the rule parser state definitions file "rbbirpt.txt".
+//
+//   Copyright (C) 2002-2005 International Business Machines Corporation 
+//   and others. All rights reserved.  
+//
+//---------------------------------------------------------------------------------
+#ifndef RBBIRPT_H
+#define RBBIRPT_H
+
+U_NAMESPACE_BEGIN
+//
+// Character classes for RBBI rule scanning.
+//
+    static const uint8_t kRuleSet_digit_char = 128;
+    static const uint8_t kRuleSet_name_char = 129;
+    static const uint8_t kRuleSet_name_start_char = 130;
+    static const uint8_t kRuleSet_rule_char = 131;
+    static const uint8_t kRuleSet_white_space = 132;
+
+
+enum RBBI_RuleParseAction {
+    doCheckVarDef,
+    doDotAny,
+    doEndAssign,
+    doEndOfRule,
+    doEndVariableName,
+    doExit,
+    doExprCatOperator,
+    doExprFinished,
+    doExprOrOperator,
+    doExprRParen,
+    doExprStart,
+    doLParen,
+    doNOP,
+    doOptionEnd,
+    doOptionStart,
+    doReverseDir,
+    doRuleChar,
+    doRuleError,
+    doRuleErrorAssignExpr,
+    doScanUnicodeSet,
+    doSlash,
+    doStartAssign,
+    doStartTagValue,
+    doStartVariableName,
+    doTagDigit,
+    doTagExpectedError,
+    doTagValue,
+    doUnaryOpPlus,
+    doUnaryOpQuestion,
+    doUnaryOpStar,
+    doVariableNameExpectedErr,
+    rbbiLastAction};
+
+//-------------------------------------------------------------------------------
+//
+//  RBBIRuleTableEl    represents the structure of a row in the transition table
+//                     for the rule parser state machine.
+//-------------------------------------------------------------------------------
+struct RBBIRuleTableEl {
+    RBBI_RuleParseAction          fAction;
+    uint8_t                       fCharClass;       // 0-127:    an individual ASCII character
+                                                    // 128-255:  character class index
+    uint8_t                       fNextState;       // 0-250:    normal next-stat numbers
+                                                    // 255:      pop next-state from stack.
+    uint8_t                       fPushState;
+    UBool                         fNextChar;
+};
+
+static const struct RBBIRuleTableEl gRuleParseStateTable[] = {
+    {doNOP, 0, 0, 0, TRUE}
+    , {doExprStart, 254, 21, 8, FALSE}     //  1      start
+    , {doNOP, 132, 1,0,  TRUE}     //  2 
+    , {doExprStart, 36 /* $ */, 80, 90, FALSE}     //  3 
+    , {doNOP, 33 /* ! */, 11,0,  TRUE}     //  4 
+    , {doNOP, 59 /* ; */, 1,0,  TRUE}     //  5 
+    , {doNOP, 252, 0,0,  FALSE}     //  6 
+    , {doExprStart, 255, 21, 8, FALSE}     //  7 
+    , {doEndOfRule, 59 /* ; */, 1,0,  TRUE}     //  8      break-rule-end
+    , {doNOP, 132, 8,0,  TRUE}     //  9 
+    , {doRuleError, 255, 95,0,  FALSE}     //  10 
+    , {doNOP, 33 /* ! */, 13,0,  TRUE}     //  11      rev-option
+    , {doReverseDir, 255, 20, 8, FALSE}     //  12 
+    , {doOptionStart, 130, 15,0,  TRUE}     //  13      option-scan1
+    , {doRuleError, 255, 95,0,  FALSE}     //  14 
+    , {doNOP, 129, 15,0,  TRUE}     //  15      option-scan2
+    , {doOptionEnd, 255, 17,0,  FALSE}     //  16 
+    , {doNOP, 59 /* ; */, 1,0,  TRUE}     //  17      option-scan3
+    , {doNOP, 132, 17,0,  TRUE}     //  18 
+    , {doRuleError, 255, 95,0,  FALSE}     //  19 
+    , {doExprStart, 255, 21, 8, FALSE}     //  20      reverse-rule
+    , {doRuleChar, 254, 30,0,  TRUE}     //  21      term
+    , {doNOP, 132, 21,0,  TRUE}     //  22 
+    , {doRuleChar, 131, 30,0,  TRUE}     //  23 
+    , {doNOP, 91 /* [ */, 86, 30, FALSE}     //  24 
+    , {doLParen, 40 /* ( */, 21, 30, TRUE}     //  25 
+    , {doNOP, 36 /* $ */, 80, 29, FALSE}     //  26 
+    , {doDotAny, 46 /* . */, 30,0,  TRUE}     //  27 
+    , {doRuleError, 255, 95,0,  FALSE}     //  28 
+    , {doCheckVarDef, 255, 30,0,  FALSE}     //  29      term-var-ref
+    , {doNOP, 132, 30,0,  TRUE}     //  30      expr-mod
+    , {doUnaryOpStar, 42 /* * */, 35,0,  TRUE}     //  31 
+    , {doUnaryOpPlus, 43 /* + */, 35,0,  TRUE}     //  32 
+    , {doUnaryOpQuestion, 63 /* ? */, 35,0,  TRUE}     //  33 
+    , {doNOP, 255, 35,0,  FALSE}     //  34 
+    , {doExprCatOperator, 254, 21,0,  FALSE}     //  35      expr-cont
+    , {doNOP, 132, 35,0,  TRUE}     //  36 
+    , {doExprCatOperator, 131, 21,0,  FALSE}     //  37 
+    , {doExprCatOperator, 91 /* [ */, 21,0,  FALSE}     //  38 
+    , {doExprCatOperator, 40 /* ( */, 21,0,  FALSE}     //  39 
+    , {doExprCatOperator, 36 /* $ */, 21,0,  FALSE}     //  40 
+    , {doExprCatOperator, 46 /* . */, 21,0,  FALSE}     //  41 
+    , {doExprCatOperator, 47 /* / */, 47,0,  FALSE}     //  42 
+    , {doExprCatOperator, 123 /* { */, 59,0,  TRUE}     //  43 
+    , {doExprOrOperator, 124 /* | */, 21,0,  TRUE}     //  44 
+    , {doExprRParen, 41 /* ) */, 255,0,  TRUE}     //  45 
+    , {doExprFinished, 255, 255,0,  FALSE}     //  46 
+    , {doSlash, 47 /* / */, 49,0,  TRUE}     //  47      look-ahead
+    , {doNOP, 255, 95,0,  FALSE}     //  48 
+    , {doExprCatOperator, 254, 21,0,  FALSE}     //  49      expr-cont-no-slash
+    , {doNOP, 132, 35,0,  TRUE}     //  50 
+    , {doExprCatOperator, 131, 21,0,  FALSE}     //  51 
+    , {doExprCatOperator, 91 /* [ */, 21,0,  FALSE}     //  52 
+    , {doExprCatOperator, 40 /* ( */, 21,0,  FALSE}     //  53 
+    , {doExprCatOperator, 36 /* $ */, 21,0,  FALSE}     //  54 
+    , {doExprCatOperator, 46 /* . */, 21,0,  FALSE}     //  55 
+    , {doExprOrOperator, 124 /* | */, 21,0,  TRUE}     //  56 
+    , {doExprRParen, 41 /* ) */, 255,0,  TRUE}     //  57 
+    , {doExprFinished, 255, 255,0,  FALSE}     //  58 
+    , {doNOP, 132, 59,0,  TRUE}     //  59      tag-open
+    , {doStartTagValue, 128, 62,0,  FALSE}     //  60 
+    , {doTagExpectedError, 255, 95,0,  FALSE}     //  61 
+    , {doNOP, 132, 66,0,  TRUE}     //  62      tag-value
+    , {doNOP, 125 /* } */, 66,0,  FALSE}     //  63 
+    , {doTagDigit, 128, 62,0,  TRUE}     //  64 
+    , {doTagExpectedError, 255, 95,0,  FALSE}     //  65 
+    , {doNOP, 132, 66,0,  TRUE}     //  66      tag-close
+    , {doTagValue, 125 /* } */, 69,0,  TRUE}     //  67 
+    , {doTagExpectedError, 255, 95,0,  FALSE}     //  68 
+    , {doExprCatOperator, 254, 21,0,  FALSE}     //  69      expr-cont-no-tag
+    , {doNOP, 132, 69,0,  TRUE}     //  70 
+    , {doExprCatOperator, 131, 21,0,  FALSE}     //  71 
+    , {doExprCatOperator, 91 /* [ */, 21,0,  FALSE}     //  72 
+    , {doExprCatOperator, 40 /* ( */, 21,0,  FALSE}     //  73 
+    , {doExprCatOperator, 36 /* $ */, 21,0,  FALSE}     //  74 
+    , {doExprCatOperator, 46 /* . */, 21,0,  FALSE}     //  75 
+    , {doExprCatOperator, 47 /* / */, 47,0,  FALSE}     //  76 
+    , {doExprOrOperator, 124 /* | */, 21,0,  TRUE}     //  77 
+    , {doExprRParen, 41 /* ) */, 255,0,  TRUE}     //  78 
+    , {doExprFinished, 255, 255,0,  FALSE}     //  79 
+    , {doStartVariableName, 36 /* $ */, 82,0,  TRUE}     //  80      scan-var-name
+    , {doNOP, 255, 95,0,  FALSE}     //  81 
+    , {doNOP, 130, 84,0,  TRUE}     //  82      scan-var-start
+    , {doVariableNameExpectedErr, 255, 95,0,  FALSE}     //  83 
+    , {doNOP, 129, 84,0,  TRUE}     //  84      scan-var-body
+    , {doEndVariableName, 255, 255,0,  FALSE}     //  85 
+    , {doScanUnicodeSet, 91 /* [ */, 255,0,  TRUE}     //  86      scan-unicode-set
+    , {doScanUnicodeSet, 112 /* p */, 255,0,  TRUE}     //  87 
+    , {doScanUnicodeSet, 80 /* P */, 255,0,  TRUE}     //  88 
+    , {doNOP, 255, 95,0,  FALSE}     //  89 
+    , {doNOP, 132, 90,0,  TRUE}     //  90      assign-or-rule
+    , {doStartAssign, 61 /* = */, 21, 93, TRUE}     //  91 
+    , {doNOP, 255, 29, 8, FALSE}     //  92 
+    , {doEndAssign, 59 /* ; */, 1,0,  TRUE}     //  93      assign-end
+    , {doRuleErrorAssignExpr, 255, 95,0,  FALSE}     //  94 
+    , {doExit, 255, 95,0,  TRUE}     //  95      errorDeath
+ };
+#ifdef RBBI_DEBUG
+static const char * const RBBIRuleStateNames[] = {    0,
+     "start",
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+     "break-rule-end",
+    0,
+    0,
+     "rev-option",
+    0,
+     "option-scan1",
+    0,
+     "option-scan2",
+    0,
+     "option-scan3",
+    0,
+    0,
+     "reverse-rule",
+     "term",
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+     "term-var-ref",
+     "expr-mod",
+    0,
+    0,
+    0,
+    0,
+     "expr-cont",
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+     "look-ahead",
+    0,
+     "expr-cont-no-slash",
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+     "tag-open",
+    0,
+    0,
+     "tag-value",
+    0,
+    0,
+    0,
+     "tag-close",
+    0,
+    0,
+     "expr-cont-no-tag",
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+     "scan-var-name",
+    0,
+     "scan-var-start",
+    0,
+     "scan-var-body",
+    0,
+     "scan-unicode-set",
+    0,
+    0,
+    0,
+     "assign-or-rule",
+    0,
+    0,
+     "assign-end",
+    0,
+     "errorDeath",
+    0};
+#endif
+
+U_NAMESPACE_END
+#endif
diff --git a/source/common/rbbirpt.txt b/source/common/rbbirpt.txt
new file mode 100644
index 0000000..8e932a6
--- /dev/null
+++ b/source/common/rbbirpt.txt
@@ -0,0 +1,315 @@
+
+#*****************************************************************************
+#
+#   Copyright (C) 2002-2003, International Business Machines Corporation and others.
+#   All Rights Reserved.
+#
+#*****************************************************************************
+#
+#  file:  rbbirpt.txt
+#  ICU Break Iterator Rule Parser State Table
+#
+#     This state table is used when reading and parsing a set of RBBI rules
+#     The rule parser uses a state machine; the data in this file define the
+#     state transitions that occur for each input character.
+#
+#     *** This file defines the RBBI rule grammar.   This is it.
+#     *** The determination of what is accepted is here.
+#
+#     This file is processed by a perl script "rbbicst.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 rules file, or in between two rules.
+#
+start:
+    escaped                term                  ^break-rule-end    doExprStart                       
+    white_space          n start                     
+    '$'                    scan-var-name         ^assign-or-rule    doExprStart
+    '!'                  n rev-option                             
+    ';'                  n start                                                  # ignore empty rules.
+    eof                    exit              
+    default                term                  ^break-rule-end    doExprStart
+    
+#
+#  break-rule-end:  Returned from doing a break-rule expression.
+#
+break-rule-end:
+    ';'	                 n start                                    doEndOfRule
+    white_space          n break-rule-end
+    default                errorDeath                               doRuleError
+     
+
+#
+#   !               We've just scanned a '!', indicating either a !!key word flag or a
+#                   !Reverse rule.
+#
+rev-option:
+    '!'                  n option-scan1   
+    default                reverse-rule           ^break-rule-end   doReverseDir
+    
+option-scan1:
+    name_start_char      n option-scan2                             doOptionStart
+    default                errorDeath                               doRuleError
+    
+option-scan2:
+    name_char            n option-scan2
+    default                option-scan3                             doOptionEnd
+    
+option-scan3:
+    ';'                  n start 
+    white_space          n option-scan3 
+    default                errorDeath                               doRuleError 
+    
+
+reverse-rule:
+    default                term                   ^break-rule-end   doExprStart
+    
+    
+#
+#  term.  Eat through a single rule character, or a composite thing, which
+#         could be a parenthesized expression, a variable name, or a Unicode Set.
+#
+term:
+    escaped              n expr-mod                                 doRuleChar
+    white_space          n term
+    rule_char            n expr-mod                                 doRuleChar
+    '['                    scan-unicode-set      ^expr-mod
+    '('                  n term                  ^expr-mod          doLParen
+    '$'                    scan-var-name         ^term-var-ref
+    '.'                  n expr-mod                                 doDotAny
+    default                errorDeath                               doRuleError
+    
+    
+
+#
+#  term-var-ref   We've just finished scanning a reference to a $variable.
+#                 Check that the variable was defined.
+#                 The variable name scanning is in common with assignment statements,
+#                 so the check can't be done there.
+term-var-ref:
+    default                expr-mod                                 doCheckVarDef
+    
+    
+#
+#   expr-mod      We've just finished scanning a term, now look for the optional
+#                 trailing '*', '?', '+'
+#
+expr-mod:
+    white_space          n  expr-mod
+    '*'                  n  expr-cont                               doUnaryOpStar
+    '+'                  n  expr-cont                               doUnaryOpPlus
+    '?'                  n  expr-cont                               doUnaryOpQuestion
+    default                 expr-cont 
+    
+    
+#
+#  expr-cont      Expression, continuation.  At a point where additional terms are
+#                                            allowed, but not required.
+#
+expr-cont:
+    escaped                 term                                    doExprCatOperator
+    white_space          n  expr-cont
+    rule_char               term                                    doExprCatOperator
+    '['                     term                                    doExprCatOperator
+    '('                     term                                    doExprCatOperator
+    '$'                     term                                    doExprCatOperator
+    '.'                     term                                    doExprCatOperator
+    '/'                     look-ahead                              doExprCatOperator
+    '{'                  n  tag-open                                doExprCatOperator
+    '|'                  n  term                                    doExprOrOperator
+    ')'                  n  pop                                     doExprRParen
+    default                 pop                                     doExprFinished
+    
+
+#
+#   look-ahead    Scanning a '/', which identifies a break point, assuming that the
+#                 remainder of the expression matches.
+#
+#                 Generate a parse tree as if this was a special kind of input symbol
+#                 appearing in an otherwise normal concatenation expression.
+#
+look-ahead:
+    '/'                   n expr-cont-no-slash                      doSlash
+    default                 errorDeath
+
+
+#
+#  expr-cont-no-slash    Expression, continuation.  At a point where additional terms are
+#                                            allowed, but not required.  Just like
+#                                            expr-cont, above, except that no '/'
+#                                            look-ahead symbol is permitted.
+#
+expr-cont-no-slash:
+    escaped                 term                                    doExprCatOperator
+    white_space          n  expr-cont
+    rule_char               term                                    doExprCatOperator
+    '['                     term                                    doExprCatOperator
+    '('                     term                                    doExprCatOperator
+    '$'                     term                                    doExprCatOperator
+    '.'                     term                                    doExprCatOperator
+    '|'                  n  term                                    doExprOrOperator
+    ')'                  n  pop                                     doExprRParen
+    default                 pop                                     doExprFinished
+
+
+#
+#   tags             scanning a '{', the opening delimiter for a tag that identifies
+#                    the kind of match.  Scan the whole {dddd} tag, where d=digit
+#
+tag-open:
+    white_space          n  tag-open
+    digit_char              tag-value                               doStartTagValue
+    default                 errorDeath                              doTagExpectedError
+    
+tag-value:
+    white_space          n  tag-close
+    '}'                     tag-close
+    digit_char           n  tag-value                               doTagDigit
+    default                 errorDeath                              doTagExpectedError
+    
+tag-close:
+    white_space          n  tag-close
+    '}'                  n  expr-cont-no-tag                        doTagValue
+    default                 errorDeath                              doTagExpectedError
+    
+    
+    
+#
+#  expr-cont-no-tag    Expression, continuation.  At a point where additional terms are
+#                                            allowed, but not required.  Just like
+#                                            expr-cont, above, except that no "{ddd}"
+#                                            tagging is permitted.
+#
+expr-cont-no-tag:
+    escaped                 term                                    doExprCatOperator
+    white_space          n  expr-cont-no-tag
+    rule_char               term                                    doExprCatOperator
+    '['                     term                                    doExprCatOperator
+    '('                     term                                    doExprCatOperator
+    '$'                     term                                    doExprCatOperator
+    '.'                     term                                    doExprCatOperator
+    '/'                     look-ahead                              doExprCatOperator
+    '|'                  n  term                                    doExprOrOperator
+    ')'                  n  pop                                     doExprRParen
+    default                 pop                                     doExprFinished
+    
+    
+
+
+#
+#   Variable Name Scanning.
+#
+#                    The state that branched to here must have pushed a return state
+#                    to go to after completion of the variable name scanning.
+#
+#                    The current input character must be the $ that introduces the name.
+#                    The $ is consummed here rather than in the state that first detected it
+#                    so that the doStartVariableName action only needs to happen in one
+#                    place (here), and the other states don't need to worry about it.
+#
+scan-var-name:
+   '$'                  n scan-var-start                            doStartVariableName
+   default                errorDeath
+
+
+scan-var-start:
+    name_start_char      n scan-var-body
+    default                errorDeath                               doVariableNameExpectedErr
+    
+scan-var-body:
+    name_char            n scan-var-body
+    default                pop                                      doEndVariableName
+    
+    
+    
+#
+#  scan-unicode-set   Unicode Sets are parsed by the the UnicodeSet class.
+#                     Within the RBBI parser, after finding the first character
+#                     of a Unicode Set, we just hand the rule input at that
+#                     point of to the Unicode Set constructor, then pick
+#                     up parsing after the close of the set.
+#
+#                     The action for this state invokes the UnicodeSet parser.
+#
+scan-unicode-set:
+    '['                   n pop                                      doScanUnicodeSet
+    'p'                   n pop                                      doScanUnicodeSet
+    'P'                   n pop                                      doScanUnicodeSet
+    default		    errorDeath 
+    
+    
+
+
+
+
+
+#
+#  assign-or-rule.   A $variable was encountered at the start of something, could be
+#                    either an assignment statement or a rule, depending on whether an '='
+#                    follows the variable name.  We get to this state when the variable name
+#                    scanning does a return.
+#
+assign-or-rule:
+    white_space          n assign-or-rule
+    '='                  n term                  ^assign-end        doStartAssign   # variable was target of assignment
+    default                term-var-ref          ^break-rule-end                    # variable was a term in a rule
+
+
+
+#
+#  assign-end        This state is entered when the end of the expression on the
+#                    right hand side of an assignment is found.  We get here via
+#                    a pop; this state is pushed when the '=' in an assignment is found.
+#
+#                    The only thing allowed at this point is a ';'.  The RHS of an
+#                    assignment must look like a rule expression, and we come here
+#                    when what is being scanned no longer looks like an expression.
+#
+assign-end:
+    ';'                  n start                                    doEndAssign
+    default                errorDeath                               doRuleErrorAssignExpr
+    
+    
+    
+#
+# 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/source/common/rbbiscan.cpp b/source/common/rbbiscan.cpp
new file mode 100644
index 0000000..dacbd63
--- /dev/null
+++ b/source/common/rbbiscan.cpp
@@ -0,0 +1,1210 @@
+
+//
+//  file:  rbbiscan.cpp
+//
+//  Copyright (C) 2002-2010, International Business Machines Corporation and others.
+//  All Rights Reserved.
+//
+//  This file contains the Rule Based Break Iterator Rule Builder functions for
+//   scanning the rules and assembling a parse tree.  This is the first phase
+//   of compiling the rules.
+//
+//  The overall of the rules is managed by class RBBIRuleBuilder, which will
+//  create and use an instance of this class as part of the process.
+//
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#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 "util.h"
+#include "cmemory.h"
+#include "cstring.h"
+
+#include "rbbirpt.h"   // Contains state table for the rbbi rules parser.
+                       //   generated by a Perl script.
+#include "rbbirb.h"
+#include "rbbinode.h"
+#include "rbbiscan.h"
+#include "rbbitblb.h"
+
+#include "uassert.h"
+
+
+//------------------------------------------------------------------------------
+//
+// Unicode Set init strings for each of the character classes needed for parsing a rule file.
+//               (Initialized with hex values for portability to EBCDIC based machines.
+//                Really ugly, but there's no good way to avoid it.)
+//
+//              The sets are referred to by name in the rbbirpt.txt, which is the
+//              source form of the state transition table for the RBBI rule parser.
+//
+//------------------------------------------------------------------------------
+static const UChar gRuleSet_rule_char_pattern[]       = {
+ //   [    ^      [    \     p     {      Z     }     \     u    0      0    2      0
+    0x5b, 0x5e, 0x5b, 0x5c, 0x70, 0x7b, 0x5a, 0x7d, 0x5c, 0x75, 0x30, 0x30, 0x32, 0x30,
+ //   -    \      u    0     0     7      f     ]     -     [    \      p
+    0x2d, 0x5c, 0x75, 0x30, 0x30, 0x37, 0x66, 0x5d, 0x2d, 0x5b, 0x5c, 0x70,
+ //   {     L     }    ]     -     [      \     p     {     N    }      ]     ]
+    0x7b, 0x4c, 0x7d, 0x5d, 0x2d, 0x5b, 0x5c, 0x70, 0x7b, 0x4e, 0x7d, 0x5d, 0x5d, 0};
+
+static const UChar gRuleSet_name_char_pattern[]       = {
+//    [    _      \    p     {     L      }     \     p     {    N      }     ]
+    0x5b, 0x5f, 0x5c, 0x70, 0x7b, 0x4c, 0x7d, 0x5c, 0x70, 0x7b, 0x4e, 0x7d, 0x5d, 0};
+
+static const UChar gRuleSet_digit_char_pattern[] = {
+//    [    0      -    9     ]
+    0x5b, 0x30, 0x2d, 0x39, 0x5d, 0};
+
+static const UChar gRuleSet_name_start_char_pattern[] = {
+//    [    _      \    p     {     L      }     ]
+    0x5b, 0x5f, 0x5c, 0x70, 0x7b, 0x4c, 0x7d, 0x5d, 0 };
+
+static const UChar kAny[] = {0x61, 0x6e, 0x79, 0x00};  // "any"
+
+
+U_CDECL_BEGIN
+static void U_CALLCONV RBBISetTable_deleter(void *p) {
+    U_NAMESPACE_QUALIFIER RBBISetTableEl *px = (U_NAMESPACE_QUALIFIER RBBISetTableEl *)p;
+    delete px->key;
+    // Note:  px->val is owned by the linked list "fSetsListHead" in scanner.
+    //        Don't delete the value nodes here.
+    uprv_free(px);
+}
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+//------------------------------------------------------------------------------
+//
+//  Constructor.
+//
+//------------------------------------------------------------------------------
+RBBIRuleScanner::RBBIRuleScanner(RBBIRuleBuilder *rb)
+{
+    fRB                 = rb;
+    fStackPtr           = 0;
+    fStack[fStackPtr]   = 0;
+    fNodeStackPtr       = 0;
+    fRuleNum            = 0;
+    fNodeStack[0]       = NULL;
+
+    fSymbolTable                            = NULL;
+    fSetTable                               = NULL;
+
+    fScanIndex = 0;
+    fNextIndex = 0;
+
+    fReverseRule        = FALSE;
+    fLookAheadRule      = FALSE;
+
+    fLineNum    = 1;
+    fCharNum    = 0;
+    fQuoteMode  = FALSE;
+
+    // Do not check status until after all critical fields are sufficiently initialized
+    //   that the destructor can run cleanly.
+    if (U_FAILURE(*rb->fStatus)) {
+        return;
+    }
+
+    //
+    //  Set up the constant Unicode Sets.
+    //     Note:  These could be made static, lazily initialized, and shared among
+    //            all instances of RBBIRuleScanners.  BUT this is quite a bit simpler,
+    //            and the time to build these few sets should be small compared to a
+    //            full break iterator build.
+    fRuleSets[kRuleSet_rule_char-128]       = UnicodeSet(gRuleSet_rule_char_pattern,       *rb->fStatus);
+    UnicodeSet *whitespaceSet = uprv_openRuleWhiteSpaceSet(rb->fStatus);
+    if (U_FAILURE(*rb->fStatus)) {
+        return;
+    }
+    fRuleSets[kRuleSet_white_space-128]     = *whitespaceSet;
+    delete whitespaceSet;
+    fRuleSets[kRuleSet_name_char-128]       = UnicodeSet(gRuleSet_name_char_pattern,       *rb->fStatus);
+    fRuleSets[kRuleSet_name_start_char-128] = UnicodeSet(gRuleSet_name_start_char_pattern, *rb->fStatus);
+    fRuleSets[kRuleSet_digit_char-128]      = UnicodeSet(gRuleSet_digit_char_pattern,      *rb->fStatus);
+    if (*rb->fStatus == U_ILLEGAL_ARGUMENT_ERROR) {
+        // This case happens if ICU's data is missing.  UnicodeSet tries to look up property
+        //   names from the init string, can't find them, and claims an illegal arguement.
+        //   Change the error so that the actual problem will be clearer to users.
+        *rb->fStatus = U_BRK_INIT_ERROR;
+    }
+    if (U_FAILURE(*rb->fStatus)) {
+        return;
+    }
+
+    fSymbolTable = new RBBISymbolTable(this, rb->fRules, *rb->fStatus);
+    if (fSymbolTable == NULL) {
+        *rb->fStatus = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    fSetTable    = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, rb->fStatus);
+    if (U_FAILURE(*rb->fStatus)) {
+        return;
+    }
+    uhash_setValueDeleter(fSetTable, RBBISetTable_deleter);
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+//  Destructor
+//
+//------------------------------------------------------------------------------
+RBBIRuleScanner::~RBBIRuleScanner() {
+    delete fSymbolTable;
+    if (fSetTable != NULL) {
+         uhash_close(fSetTable);
+         fSetTable = NULL;
+
+    }
+
+
+    // Node Stack.
+    //   Normally has one entry, which is the entire parse tree for the rules.
+    //   If errors occured, there may be additional subtrees left on the stack.
+    while (fNodeStackPtr > 0) {
+        delete fNodeStack[fNodeStackPtr];
+        fNodeStackPtr--;
+    }
+
+}
+
+//------------------------------------------------------------------------------
+//
+//  doParseAction        Do some action during rule parsing.
+//                       Called by the parse state machine.
+//                       Actions build the parse tree and Unicode Sets,
+//                       and maintain the parse stack for nested expressions.
+//
+//                       TODO:  unify EParseAction and RBBI_RuleParseAction enum types.
+//                              They represent exactly the same thing.  They're separate
+//                              only to work around enum forward declaration restrictions
+//                              in some compilers, while at the same time avoiding multiple
+//                              definitions problems.  I'm sure that there's a better way.
+//
+//------------------------------------------------------------------------------
+UBool RBBIRuleScanner::doParseActions(int32_t action)
+{
+    RBBINode *n       = NULL;
+
+    UBool   returnVal = TRUE;
+
+    switch (action) {
+
+    case doExprStart:
+        pushNewNode(RBBINode::opStart);
+        fRuleNum++;
+        break;
+
+
+    case doExprOrOperator:
+        {
+            fixOpStack(RBBINode::precOpCat);
+            RBBINode  *operandNode = fNodeStack[fNodeStackPtr--];
+            RBBINode  *orNode      = pushNewNode(RBBINode::opOr);
+            orNode->fLeftChild     = operandNode;
+            operandNode->fParent   = orNode;
+        }
+        break;
+
+    case doExprCatOperator:
+        // concatenation operator.
+        // For the implicit concatenation of adjacent terms in an expression that are
+        //   not separated by any other operator.  Action is invoked between the
+        //   actions for the two terms.
+        {
+            fixOpStack(RBBINode::precOpCat);
+            RBBINode  *operandNode = fNodeStack[fNodeStackPtr--];
+            RBBINode  *catNode     = pushNewNode(RBBINode::opCat);
+            catNode->fLeftChild    = operandNode;
+            operandNode->fParent   = catNode;
+        }
+        break;
+
+    case doLParen:
+        // Open Paren.
+        //   The openParen node is a dummy operation type with a low precedence,
+        //     which has the affect of ensuring that any real binary op that
+        //     follows within the parens binds more tightly to the operands than
+        //     stuff outside of the parens.
+        pushNewNode(RBBINode::opLParen);
+        break;
+
+    case doExprRParen:
+        fixOpStack(RBBINode::precLParen);
+        break;
+
+    case doNOP:
+        break;
+
+    case doStartAssign:
+        // We've just scanned "$variable = "
+        // The top of the node stack has the $variable ref node.
+
+        // Save the start position of the RHS text in the StartExpression node
+        //   that precedes the $variableReference node on the stack.
+        //   This will eventually be used when saving the full $variable replacement
+        //   text as a string.
+        n = fNodeStack[fNodeStackPtr-1];
+        n->fFirstPos = fNextIndex;              // move past the '='
+
+        // Push a new start-of-expression node; needed to keep parse of the
+        //   RHS expression happy.
+        pushNewNode(RBBINode::opStart);
+        break;
+
+
+
+
+    case doEndAssign:
+        {
+            // We have reached the end of an assignement statement.
+            //   Current scan char is the ';' that terminates the assignment.
+
+            // Terminate expression, leaves expression parse tree rooted in TOS node.
+            fixOpStack(RBBINode::precStart);
+
+            RBBINode *startExprNode  = fNodeStack[fNodeStackPtr-2];
+            RBBINode *varRefNode     = fNodeStack[fNodeStackPtr-1];
+            RBBINode *RHSExprNode    = fNodeStack[fNodeStackPtr];
+
+            // Save original text of right side of assignment, excluding the terminating ';'
+            //  in the root of the node for the right-hand-side expression.
+            RHSExprNode->fFirstPos = startExprNode->fFirstPos;
+            RHSExprNode->fLastPos  = fScanIndex;
+            fRB->fRules.extractBetween(RHSExprNode->fFirstPos, RHSExprNode->fLastPos, RHSExprNode->fText);
+
+            // Expression parse tree becomes l. child of the $variable reference node.
+            varRefNode->fLeftChild = RHSExprNode;
+            RHSExprNode->fParent   = varRefNode;
+
+            // Make a symbol table entry for the $variableRef node.
+            fSymbolTable->addEntry(varRefNode->fText, varRefNode, *fRB->fStatus);
+            if (U_FAILURE(*fRB->fStatus)) {
+                // This is a round-about way to get the parse position set
+                //  so that duplicate symbols error messages include a line number.
+                UErrorCode t = *fRB->fStatus;
+                *fRB->fStatus = U_ZERO_ERROR;
+                error(t);
+            }
+
+            // Clean up the stack.
+            delete startExprNode;
+            fNodeStackPtr-=3;
+            break;
+        }
+
+    case doEndOfRule:
+        {
+        fixOpStack(RBBINode::precStart);      // Terminate expression, leaves expression
+        if (U_FAILURE(*fRB->fStatus)) {       //   parse tree rooted in TOS node.
+            break;
+        }
+#ifdef RBBI_DEBUG
+        if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "rtree")) {printNodeStack("end of rule");}
+#endif
+        U_ASSERT(fNodeStackPtr == 1);
+
+        // If this rule includes a look-ahead '/', add a endMark node to the
+        //   expression tree.
+        if (fLookAheadRule) {
+            RBBINode  *thisRule       = fNodeStack[fNodeStackPtr];
+            RBBINode  *endNode        = pushNewNode(RBBINode::endMark);
+            RBBINode  *catNode        = pushNewNode(RBBINode::opCat);
+            fNodeStackPtr -= 2;
+            catNode->fLeftChild       = thisRule;
+            catNode->fRightChild      = endNode;
+            fNodeStack[fNodeStackPtr] = catNode;
+            endNode->fVal             = fRuleNum;
+            endNode->fLookAheadEnd    = TRUE;
+        }
+
+        // All rule expressions are ORed together.
+        // The ';' that terminates an expression really just functions as a '|' with
+        //   a low operator prededence.
+        //
+        // Each of the four sets of rules are collected separately.
+        //  (forward, reverse, safe_forward, safe_reverse)
+        //  OR this rule into the appropriate group of them.
+        //
+        RBBINode **destRules = (fReverseRule? &fRB->fReverseTree : fRB->fDefaultTree);
+
+        if (*destRules != NULL) {
+            // This is not the first rule encounted.
+            // OR previous stuff  (from *destRules)
+            // with the current rule expression (on the Node Stack)
+            //  with the resulting OR expression going to *destRules
+            //
+            RBBINode  *thisRule    = fNodeStack[fNodeStackPtr];
+            RBBINode  *prevRules   = *destRules;
+            RBBINode  *orNode      = pushNewNode(RBBINode::opOr);
+            orNode->fLeftChild     = prevRules;
+            prevRules->fParent     = orNode;
+            orNode->fRightChild    = thisRule;
+            thisRule->fParent      = orNode;
+            *destRules             = orNode;
+        }
+        else
+        {
+            // This is the first rule encountered (for this direction).
+            // Just move its parse tree from the stack to *destRules.
+            *destRules = fNodeStack[fNodeStackPtr];
+        }
+        fReverseRule   = FALSE;   // in preparation for the next rule.
+        fLookAheadRule = FALSE;
+        fNodeStackPtr  = 0;
+        }
+        break;
+
+
+    case doRuleError:
+        error(U_BRK_RULE_SYNTAX);
+        returnVal = FALSE;
+        break;
+
+
+    case doVariableNameExpectedErr:
+        error(U_BRK_RULE_SYNTAX);
+        break;
+
+
+    //
+    //  Unary operands  + ? *
+    //    These all appear after the operand to which they apply.
+    //    When we hit one, the operand (may be a whole sub expression)
+    //    will be on the top of the stack.
+    //    Unary Operator becomes TOS, with the old TOS as its one child.
+    case doUnaryOpPlus:
+        {
+            RBBINode  *operandNode = fNodeStack[fNodeStackPtr--];
+            RBBINode  *plusNode    = pushNewNode(RBBINode::opPlus);
+            plusNode->fLeftChild   = operandNode;
+            operandNode->fParent   = plusNode;
+        }
+        break;
+
+    case doUnaryOpQuestion:
+        {
+            RBBINode  *operandNode = fNodeStack[fNodeStackPtr--];
+            RBBINode  *qNode       = pushNewNode(RBBINode::opQuestion);
+            qNode->fLeftChild      = operandNode;
+            operandNode->fParent   = qNode;
+        }
+        break;
+
+    case doUnaryOpStar:
+        {
+            RBBINode  *operandNode = fNodeStack[fNodeStackPtr--];
+            RBBINode  *starNode    = pushNewNode(RBBINode::opStar);
+            starNode->fLeftChild   = operandNode;
+            operandNode->fParent   = starNode;
+        }
+        break;
+
+    case doRuleChar:
+        // A "Rule Character" is any single character that is a literal part
+        // of the regular expression.  Like a, b and c in the expression "(abc*) | [:L:]"
+        // These are pretty uncommon in break rules; the terms are more commonly
+        //  sets.  To keep things uniform, treat these characters like as
+        // sets that just happen to contain only one character.
+        {
+            n = pushNewNode(RBBINode::setRef);
+            findSetFor(fC.fChar, n);
+            n->fFirstPos = fScanIndex;
+            n->fLastPos  = fNextIndex;
+            fRB->fRules.extractBetween(n->fFirstPos, n->fLastPos, n->fText);
+            break;
+        }
+
+    case doDotAny:
+        // scanned a ".", meaning match any single character.
+        {
+            n = pushNewNode(RBBINode::setRef);
+            findSetFor(kAny, n);
+            n->fFirstPos = fScanIndex;
+            n->fLastPos  = fNextIndex;
+            fRB->fRules.extractBetween(n->fFirstPos, n->fLastPos, n->fText);
+            break;
+        }
+
+    case doSlash:
+        // Scanned a '/', which identifies a look-ahead break position in a rule.
+        n = pushNewNode(RBBINode::lookAhead);
+        n->fVal      = fRuleNum;
+        n->fFirstPos = fScanIndex;
+        n->fLastPos  = fNextIndex;
+        fRB->fRules.extractBetween(n->fFirstPos, n->fLastPos, n->fText);
+        fLookAheadRule = TRUE;
+        break;
+
+
+    case doStartTagValue:
+        // Scanned a '{', the opening delimiter for a tag value within a rule.
+        n = pushNewNode(RBBINode::tag);
+        n->fVal      = 0;
+        n->fFirstPos = fScanIndex;
+        n->fLastPos  = fNextIndex;
+        break;
+
+    case doTagDigit:
+        // Just scanned a decimal digit that's part of a tag value
+        {
+            n = fNodeStack[fNodeStackPtr];
+            uint32_t v = u_charDigitValue(fC.fChar);
+            U_ASSERT(v < 10);
+            n->fVal = n->fVal*10 + v;
+            break;
+        }
+
+    case doTagValue:
+        n = fNodeStack[fNodeStackPtr];
+        n->fLastPos = fNextIndex;
+        fRB->fRules.extractBetween(n->fFirstPos, n->fLastPos, n->fText);
+        break;
+
+    case doTagExpectedError:
+        error(U_BRK_MALFORMED_RULE_TAG);
+        returnVal = FALSE;
+        break;
+
+    case doOptionStart:
+        // Scanning a !!option.   At the start of string.
+        fOptionStart = fScanIndex;
+        break;
+
+    case doOptionEnd:
+        {
+            UnicodeString opt(fRB->fRules, fOptionStart, fScanIndex-fOptionStart);
+            if (opt == UNICODE_STRING("chain", 5)) {
+                fRB->fChainRules = TRUE;
+            } else if (opt == UNICODE_STRING("LBCMNoChain", 11)) {
+                fRB->fLBCMNoChain = TRUE;
+            } else if (opt == UNICODE_STRING("forward", 7)) {
+                fRB->fDefaultTree   = &fRB->fForwardTree;
+            } else if (opt == UNICODE_STRING("reverse", 7)) {
+                fRB->fDefaultTree   = &fRB->fReverseTree;
+            } else if (opt == UNICODE_STRING("safe_forward", 12)) {
+                fRB->fDefaultTree   = &fRB->fSafeFwdTree;
+            } else if (opt == UNICODE_STRING("safe_reverse", 12)) {
+                fRB->fDefaultTree   = &fRB->fSafeRevTree;
+            } else if (opt == UNICODE_STRING("lookAheadHardBreak", 18)) {
+                fRB->fLookAheadHardBreak = TRUE;
+            } else {
+                error(U_BRK_UNRECOGNIZED_OPTION);
+            }
+        }
+        break;
+
+    case doReverseDir:
+        fReverseRule = TRUE;
+        break;
+
+    case doStartVariableName:
+        n = pushNewNode(RBBINode::varRef);
+        if (U_FAILURE(*fRB->fStatus)) {
+            break;
+        }
+        n->fFirstPos = fScanIndex;
+        break;
+
+    case doEndVariableName:
+        n = fNodeStack[fNodeStackPtr];
+        if (n==NULL || n->fType != RBBINode::varRef) {
+            error(U_BRK_INTERNAL_ERROR);
+            break;
+        }
+        n->fLastPos = fScanIndex;
+        fRB->fRules.extractBetween(n->fFirstPos+1, n->fLastPos, n->fText);
+        // Look the newly scanned name up in the symbol table
+        //   If there's an entry, set the l. child of the var ref to the replacement expression.
+        //   (We also pass through here when scanning assignments, but no harm is done, other
+        //    than a slight wasted effort that seems hard to avoid.  Lookup will be null)
+        n->fLeftChild = fSymbolTable->lookupNode(n->fText);
+        break;
+
+    case doCheckVarDef:
+        n = fNodeStack[fNodeStackPtr];
+        if (n->fLeftChild == NULL) {
+            error(U_BRK_UNDEFINED_VARIABLE);
+            returnVal = FALSE;
+        }
+        break;
+
+    case doExprFinished:
+        break;
+
+    case doRuleErrorAssignExpr:
+        error(U_BRK_ASSIGN_ERROR);
+        returnVal = FALSE;
+        break;
+
+    case doExit:
+        returnVal = FALSE;
+        break;
+
+    case doScanUnicodeSet:
+        scanSet();
+        break;
+
+    default:
+        error(U_BRK_INTERNAL_ERROR);
+        returnVal = FALSE;
+        break;
+    }
+    return returnVal;
+}
+
+
+
+
+//------------------------------------------------------------------------------
+//
+//  Error         Report a rule parse error.
+//                Only report it if no previous error has been recorded.
+//
+//------------------------------------------------------------------------------
+void RBBIRuleScanner::error(UErrorCode e) {
+    if (U_SUCCESS(*fRB->fStatus)) {
+        *fRB->fStatus = e;
+        if (fRB->fParseError) {
+            fRB->fParseError->line  = fLineNum;
+            fRB->fParseError->offset = fCharNum;
+            fRB->fParseError->preContext[0] = 0;
+            fRB->fParseError->preContext[0] = 0;
+        }
+    }
+}
+
+
+
+
+//------------------------------------------------------------------------------
+//
+//  fixOpStack   The parse stack holds partially assembled chunks of the parse tree.
+//               An entry on the stack may be as small as a single setRef node,
+//               or as large as the parse tree
+//               for an entire expression (this will be the one item left on the stack
+//               when the parsing of an RBBI rule completes.
+//
+//               This function is called when a binary operator is encountered.
+//               It looks back up the stack for operators that are not yet associated
+//               with a right operand, and if the precedence of the stacked operator >=
+//               the precedence of the current operator, binds the operand left,
+//               to the previously encountered operator.
+//
+//------------------------------------------------------------------------------
+void RBBIRuleScanner::fixOpStack(RBBINode::OpPrecedence p) {
+    RBBINode *n;
+    // printNodeStack("entering fixOpStack()");
+    for (;;) {
+        n = fNodeStack[fNodeStackPtr-1];   // an operator node
+        if (n->fPrecedence == 0) {
+            RBBIDebugPuts("RBBIRuleScanner::fixOpStack, bad operator node");
+            error(U_BRK_INTERNAL_ERROR);
+            return;
+        }
+
+        if (n->fPrecedence < p || n->fPrecedence <= RBBINode::precLParen) {
+            // The most recent operand goes with the current operator,
+            //   not with the previously stacked one.
+            break;
+        }
+            // Stack operator is a binary op  ( '|' or concatenation)
+            //   TOS operand becomes right child of this operator.
+            //   Resulting subexpression becomes the TOS operand.
+            n->fRightChild = fNodeStack[fNodeStackPtr];
+            fNodeStack[fNodeStackPtr]->fParent = n;
+            fNodeStackPtr--;
+        // printNodeStack("looping in fixOpStack()   ");
+    }
+
+    if (p <= RBBINode::precLParen) {
+        // Scan is at a right paren or end of expression.
+        //  The scanned item must match the stack, or else there was an error.
+        //  Discard the left paren (or start expr) node from the stack,
+            //  leaving the completed (sub)expression as TOS.
+            if (n->fPrecedence != p) {
+                // Right paren encountered matched start of expression node, or
+                // end of expression matched with a left paren node.
+                error(U_BRK_MISMATCHED_PAREN);
+            }
+            fNodeStack[fNodeStackPtr-1] = fNodeStack[fNodeStackPtr];
+            fNodeStackPtr--;
+            // Delete the now-discarded LParen or Start node.
+            delete n;
+    }
+    // printNodeStack("leaving fixOpStack()");
+}
+
+
+
+
+//------------------------------------------------------------------------------
+//
+//   findSetFor    given a UnicodeString,
+//                  - find the corresponding Unicode Set  (uset node)
+//                         (create one if necessary)
+//                  - Set fLeftChild of the caller's node (should be a setRef node)
+//                         to the uset node
+//                 Maintain a hash table of uset nodes, so the same one is always used
+//                    for the same string.
+//                 If a "to adopt" set is provided and we haven't seen this key before,
+//                    add the provided set to the hash table.
+//                 If the string is one (32 bit) char in length, the set contains
+//                    just one element which is the char in question.
+//                 If the string is "any", return a set containing all chars.
+//
+//------------------------------------------------------------------------------
+void RBBIRuleScanner::findSetFor(const UnicodeString &s, RBBINode *node, UnicodeSet *setToAdopt) {
+
+    RBBISetTableEl   *el;
+
+    // First check whether we've already cached a set for this string.
+    // If so, just use the cached set in the new node.
+    //   delete any set provided by the caller, since we own it.
+    el = (RBBISetTableEl *)uhash_get(fSetTable, &s);
+    if (el != NULL) {
+        delete setToAdopt;
+        node->fLeftChild = el->val;
+        U_ASSERT(node->fLeftChild->fType == RBBINode::uset);
+        return;
+    }
+
+    // Haven't seen this set before.
+    // If the caller didn't provide us with a prebuilt set,
+    //   create a new UnicodeSet now.
+    if (setToAdopt == NULL) {
+        if (s.compare(kAny, -1) == 0) {
+            setToAdopt = new UnicodeSet(0x000000, 0x10ffff);
+        } else {
+            UChar32 c;
+            c = s.char32At(0);
+            setToAdopt = new UnicodeSet(c, c);
+        }
+    }
+
+    //
+    // Make a new uset node to refer to this UnicodeSet
+    // This new uset node becomes the child of the caller's setReference node.
+    //
+    RBBINode *usetNode    = new RBBINode(RBBINode::uset);
+    if (usetNode == NULL) {
+        error(U_MEMORY_ALLOCATION_ERROR);
+        return;
+    }
+    usetNode->fInputSet   = setToAdopt;
+    usetNode->fParent     = node;
+    node->fLeftChild      = usetNode;
+    usetNode->fText = s;
+
+
+    //
+    // Add the new uset node to the list of all uset nodes.
+    //
+    fRB->fUSetNodes->addElement(usetNode, *fRB->fStatus);
+
+
+    //
+    // Add the new set to the set hash table.
+    //
+    el      = (RBBISetTableEl *)uprv_malloc(sizeof(RBBISetTableEl));
+    UnicodeString *tkey = new UnicodeString(s);
+    if (tkey == NULL || el == NULL || setToAdopt == NULL) {
+        // Delete to avoid memory leak
+        delete tkey;
+        tkey = NULL;
+        uprv_free(el);
+        el = NULL;
+        delete setToAdopt;
+        setToAdopt = NULL;
+
+        error(U_MEMORY_ALLOCATION_ERROR);
+        return;
+    }
+    el->key = tkey;
+    el->val = usetNode;
+    uhash_put(fSetTable, el->key, el, fRB->fStatus);
+
+    return;
+}
+
+
+
+//
+//  Assorted Unicode character constants.
+//     Numeric because there is no portable way to enter them as literals.
+//     (Think EBCDIC).
+//
+static const UChar      chCR        = 0x0d;      // New lines, for terminating comments.
+static const UChar      chLF        = 0x0a;
+static const UChar      chNEL       = 0x85;      //    NEL newline variant
+static const UChar      chLS        = 0x2028;    //    Unicode Line Separator
+static const UChar      chApos      = 0x27;      //  single quote, for quoted chars.
+static const UChar      chPound     = 0x23;      // '#', introduces a comment.
+static const UChar      chBackSlash = 0x5c;      // '\'  introduces a char escape
+static const UChar      chLParen    = 0x28;
+static const UChar      chRParen    = 0x29;
+
+
+//------------------------------------------------------------------------------
+//
+//  stripRules    Return a rules string without unnecessary
+//                characters.
+//
+//------------------------------------------------------------------------------
+UnicodeString RBBIRuleScanner::stripRules(const UnicodeString &rules) {
+    UnicodeString strippedRules;
+    int rulesLength = rules.length();
+    for (int idx = 0; idx < rulesLength; ) {
+        UChar ch = rules[idx++];
+        if (ch == chPound) {
+            while (idx < rulesLength
+                && ch != chCR && ch != chLF && ch != chNEL)
+            {
+                ch = rules[idx++];
+            }
+        }
+        if (!u_isISOControl(ch)) {
+            strippedRules.append(ch);
+        }
+    }
+    // strippedRules = strippedRules.unescape();
+    return strippedRules;
+}
+
+
+//------------------------------------------------------------------------------
+//
+//  nextCharLL    Low Level Next Char from rule input source.
+//                Get a char from the input character iterator,
+//                keep track of input position for error reporting.
+//
+//------------------------------------------------------------------------------
+UChar32  RBBIRuleScanner::nextCharLL() {
+    UChar32  ch;
+
+    if (fNextIndex >= fRB->fRules.length()) {
+        return (UChar32)-1;
+    }
+    ch         = fRB->fRules.char32At(fNextIndex);
+    fNextIndex = fRB->fRules.moveIndex32(fNextIndex, 1);
+
+    if (ch == chCR ||
+        ch == chNEL ||
+        ch == chLS   ||
+        (ch == chLF && fLastChar != chCR)) {
+        // Character is starting a new line.  Bump up the line number, and
+        //  reset the column to 0.
+        fLineNum++;
+        fCharNum=0;
+        if (fQuoteMode) {
+            error(U_BRK_NEW_LINE_IN_QUOTED_STRING);
+            fQuoteMode = FALSE;
+        }
+    }
+    else {
+        // Character is not starting a new line.  Except in the case of a
+        //   LF following a CR, increment the column position.
+        if (ch != chLF) {
+            fCharNum++;
+        }
+    }
+    fLastChar = ch;
+    return ch;
+}
+
+
+//------------------------------------------------------------------------------
+//
+//   nextChar     for rules scanning.  At this level, we handle stripping
+//                out comments and processing backslash character escapes.
+//                The rest of the rules grammar is handled at the next level up.
+//
+//------------------------------------------------------------------------------
+void RBBIRuleScanner::nextChar(RBBIRuleChar &c) {
+
+    // Unicode Character constants needed for the processing done by nextChar(),
+    //   in hex because literals wont work on EBCDIC machines.
+
+    fScanIndex = fNextIndex;
+    c.fChar    = nextCharLL();
+    c.fEscaped = FALSE;
+
+    //
+    //  check for '' sequence.
+    //  These are recognized in all contexts, whether in quoted text or not.
+    //
+    if (c.fChar == chApos) {
+        if (fRB->fRules.char32At(fNextIndex) == chApos) {
+            c.fChar    = nextCharLL();        // get nextChar officially so character counts
+            c.fEscaped = TRUE;                //   stay correct.
+        }
+        else
+        {
+            // Single quote, by itself.
+            //   Toggle quoting mode.
+            //   Return either '('  or ')', because quotes cause a grouping of the quoted text.
+            fQuoteMode = !fQuoteMode;
+            if (fQuoteMode == TRUE) {
+                c.fChar = chLParen;
+            } else {
+                c.fChar = chRParen;
+            }
+            c.fEscaped = FALSE;      // The paren that we return is not escaped.
+            return;
+        }
+    }
+
+    if (fQuoteMode) {
+        c.fEscaped = TRUE;
+    }
+    else
+    {
+        // We are not in a 'quoted region' of the source.
+        //
+        if (c.fChar == chPound) {
+            // Start of a comment.  Consume the rest of it.
+            //  The new-line char that terminates the comment is always returned.
+            //  It will be treated as white-space, and serves to break up anything
+            //    that might otherwise incorrectly clump together with a comment in
+            //    the middle (a variable name, for example.)
+            for (;;) {
+                c.fChar = nextCharLL();
+                if (c.fChar == (UChar32)-1 ||  // EOF
+                    c.fChar == chCR     ||
+                    c.fChar == chLF     ||
+                    c.fChar == chNEL    ||
+                    c.fChar == chLS)       {break;}
+            }
+        }
+        if (c.fChar == (UChar32)-1) {
+            return;
+        }
+
+        //
+        //  check for backslash escaped characters.
+        //  Use UnicodeString::unescapeAt() to handle them.
+        //
+        if (c.fChar == chBackSlash) {
+            c.fEscaped = TRUE;
+            int32_t startX = fNextIndex;
+            c.fChar = fRB->fRules.unescapeAt(fNextIndex);
+            if (fNextIndex == startX) {
+                error(U_BRK_HEX_DIGITS_EXPECTED);
+            }
+            fCharNum += fNextIndex-startX;
+        }
+    }
+    // putc(c.fChar, stdout);
+}
+
+//------------------------------------------------------------------------------
+//
+//  Parse RBBI rules.   The state machine for rules parsing is here.
+//                      The state tables are hand-written in the file rbbirpt.txt,
+//                      and converted to the form used here by a perl
+//                      script rbbicst.pl
+//
+//------------------------------------------------------------------------------
+void RBBIRuleScanner::parse() {
+    uint16_t                state;
+    const RBBIRuleTableEl  *tableEl;
+
+    if (U_FAILURE(*fRB->fStatus)) {
+        return;
+    }
+
+    state = 1;
+    nextChar(fC);
+    //
+    // Main loop for the rule parsing state machine.
+    //   Runs once per state transition.
+    //   Each time through optionally performs, depending on the state table,
+    //      - an advance to the the next input char
+    //      - an action to be performed.
+    //      - pushing or popping a state to/from the local state return stack.
+    //
+    for (;;) {
+        //  Bail out if anything has gone wrong.
+        //  RBBI rule file parsing stops on the first error encountered.
+        if (U_FAILURE(*fRB->fStatus)) {
+            break;
+        }
+
+        // Quit if state == 0.  This is the normal way to exit the state machine.
+        //
+        if (state == 0) {
+            break;
+        }
+
+        // Find the state table element that matches the input char from the rule, 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];
+        #ifdef RBBI_DEBUG
+            if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "scan")) {
+                RBBIDebugPrintf("char, line, col = (\'%c\', %d, %d)    state=%s ",
+                    fC.fChar, fLineNum, fCharNum, RBBIRuleStateNames[state]);
+            }
+        #endif
+
+        for (;;) {
+            #ifdef RBBI_DEBUG
+                if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "scan")) { RBBIDebugPrintf(".");}
+            #endif
+            if (tableEl->fCharClass < 127 && fC.fEscaped == FALSE &&   tableEl->fCharClass == fC.fChar) {
+                // Table row specified an individual character, not a set, and
+                //   the input character is not escaped, 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.fEscaped)  {
+                // Table row specified "escaped" and the char was escaped.
+                break;
+            }
+            if (tableEl->fCharClass == 253 && fC.fEscaped &&
+                (fC.fChar == 0x50 || fC.fChar == 0x70 ))  {
+                // Table row specified "escaped P" and the char is either 'p' or 'P'.
+                break;
+            }
+            if (tableEl->fCharClass == 252 && 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.fEscaped == FALSE &&                                      //   char is not escaped &&
+                fC.fChar != (UChar32)-1) {                                   //   char is not EOF
+                if (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++;
+        }
+        if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "scan")) { RBBIDebugPuts("");}
+
+        //
+        // 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((int32_t)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_BRK_INTERNAL_ERROR);
+                RBBIDebugPuts("RBBIRuleScanner::parse() - state stack overflow.");
+                fStackPtr--;
+            }
+            fStack[fStackPtr] = tableEl->fPushState;
+        }
+
+        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) {
+                error(U_BRK_INTERNAL_ERROR);
+                RBBIDebugPuts("RBBIRuleScanner::parse() - state stack underflow.");
+                fStackPtr++;
+            }
+        }
+
+    }
+
+    //
+    // If there were NO user specified reverse rules, set up the equivalent of ".*;"
+    //
+    if (fRB->fReverseTree == NULL) {
+        fRB->fReverseTree  = pushNewNode(RBBINode::opStar);
+        RBBINode  *operand = pushNewNode(RBBINode::setRef);
+        findSetFor(kAny, operand);
+        fRB->fReverseTree->fLeftChild = operand;
+        operand->fParent              = fRB->fReverseTree;
+        fNodeStackPtr -= 2;
+    }
+
+
+    //
+    // Parsing of the input RBBI rules is complete.
+    // We now have a parse tree for the rule expressions
+    // and a list of all UnicodeSets that are referenced.
+    //
+#ifdef RBBI_DEBUG
+    if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "symbols")) {fSymbolTable->rbbiSymtablePrint();}
+    if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "ptree"))
+    {
+        RBBIDebugPrintf("Completed Forward Rules Parse Tree...\n");
+        fRB->fForwardTree->printTree(TRUE);
+        RBBIDebugPrintf("\nCompleted Reverse Rules Parse Tree...\n");
+        fRB->fReverseTree->printTree(TRUE);
+        RBBIDebugPrintf("\nCompleted Safe Point Forward Rules Parse Tree...\n");
+        fRB->fSafeFwdTree->printTree(TRUE);
+        RBBIDebugPrintf("\nCompleted Safe Point Reverse Rules Parse Tree...\n");
+        fRB->fSafeRevTree->printTree(TRUE);
+    }
+#endif
+}
+
+
+//------------------------------------------------------------------------------
+//
+//  printNodeStack     for debugging...
+//
+//------------------------------------------------------------------------------
+#ifdef RBBI_DEBUG
+void RBBIRuleScanner::printNodeStack(const char *title) {
+    int i;
+    RBBIDebugPrintf("%s.  Dumping node stack...\n", title);
+    for (i=fNodeStackPtr; i>0; i--) {fNodeStack[i]->printTree(TRUE);}
+}
+#endif
+
+
+
+
+//------------------------------------------------------------------------------
+//
+//  pushNewNode   create a new RBBINode of the specified type and push it
+//                onto the stack of nodes.
+//
+//------------------------------------------------------------------------------
+RBBINode  *RBBIRuleScanner::pushNewNode(RBBINode::NodeType  t) {
+    fNodeStackPtr++;
+    if (fNodeStackPtr >= kStackSize) {
+        error(U_BRK_INTERNAL_ERROR);
+        RBBIDebugPuts("RBBIRuleScanner::pushNewNode - stack overflow.");
+        *fRB->fStatus = U_BRK_INTERNAL_ERROR;
+        return NULL;
+    }
+    fNodeStack[fNodeStackPtr] = new RBBINode(t);
+    if (fNodeStack[fNodeStackPtr] == NULL) {
+        *fRB->fStatus = U_MEMORY_ALLOCATION_ERROR;
+    }
+    return fNodeStack[fNodeStackPtr];
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+//  scanSet    Construct a UnicodeSet from the text at the current scan
+//             position.  Advance the scan position to the first character
+//             after the set.
+//
+//             A new RBBI setref node referring to the set is pushed onto the node
+//             stack.
+//
+//             The scan position is normally under the control of the state machine
+//             that controls rule parsing.  UnicodeSets, however, are parsed by
+//             the UnicodeSet constructor, not by the RBBI rule parser.
+//
+//------------------------------------------------------------------------------
+void RBBIRuleScanner::scanSet() {
+    UnicodeSet    *uset;
+    ParsePosition  pos;
+    int            startPos;
+    int            i;
+
+    if (U_FAILURE(*fRB->fStatus)) {
+        return;
+    }
+
+    pos.setIndex(fScanIndex);
+    startPos = fScanIndex;
+    UErrorCode localStatus = U_ZERO_ERROR;
+    uset = new UnicodeSet(fRB->fRules, pos, USET_IGNORE_SPACE,
+                         fSymbolTable,
+                         localStatus);
+    if (uset == NULL) {
+        localStatus = U_MEMORY_ALLOCATION_ERROR;
+    }
+    if (U_FAILURE(localStatus)) {
+        //  TODO:  Get more accurate position of the error from UnicodeSet's return info.
+        //         UnicodeSet appears to not be reporting correctly at this time.
+        #ifdef RBBI_DEBUG
+            RBBIDebugPrintf("UnicodeSet parse postion.ErrorIndex = %d\n", pos.getIndex());
+        #endif
+        error(localStatus);
+        delete uset;
+        return;
+    }
+
+    // Verify that the set contains at least one code point.
+    //
+    if (uset->isEmpty()) {
+        // This set is empty.
+        //  Make it an error, because it almost certainly is not what the user wanted.
+        //  Also, avoids having to think about corner cases in the tree manipulation code
+        //   that occurs later on.
+        error(U_BRK_RULE_EMPTY_SET);
+        delete uset;
+        return;
+    }
+
+
+    // Advance the RBBI parse postion over the UnicodeSet pattern.
+    //   Don't just set fScanIndex because the line/char positions maintained
+    //   for error reporting would be thrown off.
+    i = pos.getIndex();
+    for (;;) {
+        if (fNextIndex >= i) {
+            break;
+        }
+        nextCharLL();
+    }
+
+    if (U_SUCCESS(*fRB->fStatus)) {
+        RBBINode         *n;
+
+        n = pushNewNode(RBBINode::setRef);
+        n->fFirstPos = startPos;
+        n->fLastPos  = fNextIndex;
+        fRB->fRules.extractBetween(n->fFirstPos, n->fLastPos, n->fText);
+        //  findSetFor() serves several purposes here:
+        //     - Adopts storage for the UnicodeSet, will be responsible for deleting.
+        //     - Mantains collection of all sets in use, needed later for establishing
+        //          character categories for run time engine.
+        //     - Eliminates mulitiple instances of the same set.
+        //     - Creates a new uset node if necessary (if this isn't a duplicate.)
+        findSetFor(n->fText, n, uset);
+    }
+
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
diff --git a/source/common/rbbiscan.h b/source/common/rbbiscan.h
new file mode 100644
index 0000000..dd9b8e6
--- /dev/null
+++ b/source/common/rbbiscan.h
@@ -0,0 +1,162 @@
+//
+//  rbbiscan.h
+//
+//  Copyright (C) 2002-2008, International Business Machines Corporation and others.
+//  All Rights Reserved.
+//
+//  This file contains declarations for class RBBIRuleScanner
+//
+
+
+#ifndef RBBISCAN_H
+#define RBBISCAN_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/rbbi.h"
+#include "unicode/uniset.h"
+#include "unicode/parseerr.h"
+#include "uhash.h"
+#include "uvector.h"
+#include "unicode/symtable.h"// For UnicodeSet parsing, is the interface that
+                          //    looks up references to $variables within a set.
+#include "rbbinode.h"
+//#include "rbbitblb.h"
+
+
+
+U_NAMESPACE_BEGIN
+
+class   RBBIRuleBuilder;
+class   RBBISymbolTable;
+
+
+//--------------------------------------------------------------------------------
+//
+//  class RBBIRuleScanner does the lowest level, character-at-a-time
+//                        scanning of break iterator rules.  
+//
+//                        The output of the scanner is parse trees for
+//                        the rule expressions and a list of all Unicode Sets
+//                        encountered.
+//
+//--------------------------------------------------------------------------------
+
+class RBBIRuleScanner : public UMemory {
+public:
+
+    enum {
+        kStackSize = 100            // The size of the state stack for
+    };                              //   rules parsing.  Corresponds roughly
+                                    //   to the depth of parentheses nesting
+                                    //   that is allowed in the rules.
+
+    struct RBBIRuleChar {
+        UChar32             fChar;
+        UBool               fEscaped;
+    };
+
+    RBBIRuleScanner(RBBIRuleBuilder  *rb);
+
+
+    virtual    ~RBBIRuleScanner();
+
+    void        nextChar(RBBIRuleChar &c);          // Get the next char from the input stream.
+                                                    // Return false if at end.
+
+    UBool       push(const RBBIRuleChar &c);        // Push (unget) one character.
+                                                    //   Only a single character may be pushed.
+
+    void        parse();                            // Parse the rules, generating two parse
+                                                    //   trees, one each for the forward and
+                                                    //   reverse rules,
+                                                    //   and a list of UnicodeSets encountered.
+
+    /**
+     * Return a rules string without unnecessary
+     * characters.
+     */
+    static UnicodeString stripRules(const UnicodeString &rules);
+private:
+
+    UBool       doParseActions(int32_t a);
+    void        error(UErrorCode e);                   // error reporting convenience function.
+    void        fixOpStack(RBBINode::OpPrecedence p);
+                                                       //   a character.
+    void        findSetFor(const UnicodeString &s, RBBINode *node, UnicodeSet *setToAdopt = NULL);
+
+    UChar32     nextCharLL();
+#ifdef RBBI_DEBUG
+    void        printNodeStack(const char *title);
+#endif
+    RBBINode    *pushNewNode(RBBINode::NodeType  t);
+    void        scanSet();
+
+
+    RBBIRuleBuilder               *fRB;              // The rule builder that we are part of.
+
+    int32_t                       fScanIndex;        // Index of current character being processed
+                                                     //   in the rule input string.
+    int32_t                       fNextIndex;        // Index of the next character, which
+                                                     //   is the first character not yet scanned.
+    UBool                         fQuoteMode;        // Scan is in a 'quoted region'
+    int32_t                       fLineNum;          // Line number in input file.
+    int32_t                       fCharNum;          // Char position within the line.
+    UChar32                       fLastChar;         // Previous char, needed to count CR-LF
+                                                     //   as a single line, not two.
+
+    RBBIRuleChar                  fC;                // Current char for parse state machine
+                                                     //   processing.
+    UnicodeString                 fVarName;          // $variableName, valid when we've just
+                                                     //   scanned one.
+
+    RBBIRuleTableEl               **fStateTable;     // State Transition Table for RBBI 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.
+
+    RBBINode                      *fNodeStack[kStackSize]; // Node stack, holds nodes created
+                                                           //  during the parse of a rule
+    int32_t                        fNodeStackPtr;
+
+
+    UBool                          fReverseRule;     // True if the rule currently being scanned
+                                                     //  is a reverse direction rule (if it
+                                                     //  starts with a '!')
+
+    UBool                          fLookAheadRule;   // True if the rule includes a '/'
+                                                     //   somewhere within it.
+
+    RBBISymbolTable               *fSymbolTable;     // symbol table, holds definitions of
+                                                     //   $variable symbols.
+
+    UHashtable                    *fSetTable;        // UnicocodeSet hash table, holds indexes to
+                                                     //   the sets created while parsing rules.
+                                                     //   The key is the string used for creating
+                                                     //   the set.
+
+    UnicodeSet                     fRuleSets[10];    // Unicode Sets that are needed during
+                                                     //  the scanning of RBBI rules.  The
+                                                     //  indicies for these are assigned by the
+                                                     //  perl script that builds the state tables.
+                                                     //  See rbbirpt.h.
+
+    int32_t                        fRuleNum;         // Counts each rule as it is scanned.
+
+    int32_t                        fOptionStart;     // Input index of start of a !!option
+                                                     //   keyword, while being scanned.
+
+    UnicodeSet *gRuleSet_rule_char;
+    UnicodeSet *gRuleSet_white_space;
+    UnicodeSet *gRuleSet_name_char;
+    UnicodeSet *gRuleSet_name_start_char;
+
+    RBBIRuleScanner(const RBBIRuleScanner &other); // forbid copying of this class
+    RBBIRuleScanner &operator=(const RBBIRuleScanner &other); // forbid copying of this class
+};
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/rbbisetb.cpp b/source/common/rbbisetb.cpp
new file mode 100644
index 0000000..cd855f7
--- /dev/null
+++ b/source/common/rbbisetb.cpp
@@ -0,0 +1,695 @@
+//
+//  rbbisetb.cpp
+//
+/*
+***************************************************************************
+*   Copyright (C) 2002-2008 International Business Machines Corporation   *
+*   and others. All rights reserved.                                      *
+***************************************************************************
+*/
+//
+//  RBBISetBuilder   Handles processing of Unicode Sets from RBBI rules
+//                   (part of the rule building process.)
+//
+//      Starting with the rules parse tree from the scanner,
+//
+//                   -  Enumerate the set of UnicodeSets that are referenced
+//                      by the RBBI rules.
+//                   -  compute a set of non-overlapping character ranges
+//                      with all characters within a range belonging to the same
+//                      set of input uniocde sets.
+//                   -  Derive a set of non-overlapping UnicodeSet (like things)
+//                      that will correspond to columns in the state table for
+//                      the RBBI execution engine.  All characters within one
+//                      of these sets belong to the same set of the original
+//                      UnicodeSets from the user's rules.
+//                   -  construct the trie table that maps input characters
+//                      to the index of the matching non-overlapping set of set from
+//                      the previous step.
+//
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/uniset.h"
+#include "utrie.h"
+#include "uvector.h"
+#include "uassert.h"
+#include "cmemory.h"
+#include "cstring.h"
+
+#include "rbbisetb.h"
+#include "rbbinode.h"
+
+
+//------------------------------------------------------------------------
+//
+//   getFoldedRBBIValue        Call-back function used during building of Trie table.
+//                             Folding value: just store the offset (16 bits)
+//                             if there is any non-0 entry.
+//                             (It'd really be nice if the Trie builder would provide a
+//                             simple default, so this function could go away from here.)
+//
+//------------------------------------------------------------------------
+/* folding value: just store the offset (16 bits) if there is any non-0 entry */
+U_CDECL_BEGIN
+static uint32_t U_CALLCONV
+getFoldedRBBIValue(UNewTrie *trie, UChar32 start, int32_t offset) {
+    uint32_t value;
+    UChar32 limit;
+    UBool inBlockZero;
+
+    limit=start+0x400;
+    while(start<limit) {
+        value=utrie_get32(trie, start, &inBlockZero);
+        if(inBlockZero) {
+            start+=UTRIE_DATA_BLOCK_LENGTH;
+        } else if(value!=0) {
+            return (uint32_t)(offset|0x8000);
+        } else {
+            ++start;
+        }
+    }
+    return 0;
+}
+
+
+U_CDECL_END
+
+
+
+U_NAMESPACE_BEGIN
+
+//------------------------------------------------------------------------
+//
+//   Constructor
+//
+//------------------------------------------------------------------------
+RBBISetBuilder::RBBISetBuilder(RBBIRuleBuilder *rb)
+{
+    fRB             = rb;
+    fStatus         = rb->fStatus;
+    fRangeList      = 0;
+    fTrie           = 0;
+    fTrieSize       = 0;
+    fGroupCount     = 0;
+    fSawBOF         = FALSE;
+}
+
+
+//------------------------------------------------------------------------
+//
+//   Destructor
+//
+//------------------------------------------------------------------------
+RBBISetBuilder::~RBBISetBuilder()
+{
+    RangeDescriptor   *nextRangeDesc;
+
+    // Walk through & delete the linked list of RangeDescriptors
+    for (nextRangeDesc = fRangeList; nextRangeDesc!=NULL;) {
+        RangeDescriptor *r = nextRangeDesc;
+        nextRangeDesc      = r->fNext;
+        delete r;
+    }
+
+    utrie_close(fTrie);
+}
+
+
+
+
+//------------------------------------------------------------------------
+//
+//   build          Build the list of non-overlapping character ranges
+//                  from the Unicode Sets.
+//
+//------------------------------------------------------------------------
+void RBBISetBuilder::build() {
+    RBBINode        *usetNode;
+    RangeDescriptor *rlRange;
+
+    if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "usets")) {printSets();}
+
+    //
+    //  Initialize the process by creating a single range encompassing all characters
+    //  that is in no sets.
+    //
+    fRangeList                = new RangeDescriptor(*fStatus); // will check for status here
+    if (fRangeList == NULL) {
+        *fStatus = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    fRangeList->fStartChar    = 0;
+    fRangeList->fEndChar      = 0x10ffff;
+
+    if (U_FAILURE(*fStatus)) {
+        return;
+    }
+
+    //
+    //  Find the set of non-overlapping ranges of characters
+    //
+    int  ni;
+    for (ni=0; ; ni++) {        // Loop over each of the UnicodeSets encountered in the input rules
+        usetNode = (RBBINode *)this->fRB->fUSetNodes->elementAt(ni);
+        if (usetNode==NULL) {
+            break;
+        }
+
+        UnicodeSet      *inputSet             = usetNode->fInputSet;
+        int32_t          inputSetRangeCount   = inputSet->getRangeCount();
+        int              inputSetRangeIndex   = 0;
+                         rlRange              = fRangeList;
+
+        for (;;) {
+            if (inputSetRangeIndex >= inputSetRangeCount) {
+                break;
+            }
+            UChar32      inputSetRangeBegin  = inputSet->getRangeStart(inputSetRangeIndex);
+            UChar32      inputSetRangeEnd    = inputSet->getRangeEnd(inputSetRangeIndex);
+
+            // skip over ranges from the range list that are completely
+            //   below the current range from the input unicode set.
+            while (rlRange->fEndChar < inputSetRangeBegin) {
+                rlRange = rlRange->fNext;
+            }
+
+            // If the start of the range from the range list is before with
+            //   the start of the range from the unicode set, split the range list range
+            //   in two, with one part being before (wholly outside of) the unicode set
+            //   and the other containing the rest.
+            //   Then continue the loop; the post-split current range will then be skipped
+            //     over
+            if (rlRange->fStartChar < inputSetRangeBegin) {
+                rlRange->split(inputSetRangeBegin, *fStatus);
+                if (U_FAILURE(*fStatus)) {
+                    return;
+                }
+                continue;
+            }
+
+            // Same thing at the end of the ranges...
+            // If the end of the range from the range list doesn't coincide with
+            //   the end of the range from the unicode set, split the range list
+            //   range in two.  The first part of the split range will be
+            //   wholly inside the Unicode set.
+            if (rlRange->fEndChar > inputSetRangeEnd) {
+                rlRange->split(inputSetRangeEnd+1, *fStatus);
+                if (U_FAILURE(*fStatus)) {
+                    return;
+                }
+            }
+
+            // The current rlRange is now entirely within the UnicodeSet range.
+            // Add this unicode set to the list of sets for this rlRange
+            if (rlRange->fIncludesSets->indexOf(usetNode) == -1) {
+                rlRange->fIncludesSets->addElement(usetNode, *fStatus);
+                if (U_FAILURE(*fStatus)) {
+                    return;
+                }
+            }
+
+            // Advance over ranges that we are finished with.
+            if (inputSetRangeEnd == rlRange->fEndChar) {
+                inputSetRangeIndex++;
+            }
+            rlRange = rlRange->fNext;
+        }
+    }
+
+    if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "range")) { printRanges();}
+
+    //
+    //  Group the above ranges, with each group consisting of one or more
+    //    ranges that are in exactly the same set of original UnicodeSets.
+    //    The groups are numbered, and these group numbers are the set of
+    //    input symbols recognized by the run-time state machine.
+    //
+    //    Numbering: # 0  (state table column 0) is unused.
+    //               # 1  is reserved - table column 1 is for end-of-input
+    //               # 2  is reserved - table column 2 is for beginning-in-input
+    //               # 3  is the first range list.
+    //
+    RangeDescriptor *rlSearchRange;
+    for (rlRange = fRangeList; rlRange!=0; rlRange=rlRange->fNext) {
+        for (rlSearchRange=fRangeList; rlSearchRange != rlRange; rlSearchRange=rlSearchRange->fNext) {
+            if (rlRange->fIncludesSets->equals(*rlSearchRange->fIncludesSets)) {
+                rlRange->fNum = rlSearchRange->fNum;
+                break;
+            }
+        }
+        if (rlRange->fNum == 0) {
+            fGroupCount ++;
+            rlRange->fNum = fGroupCount+2; 
+            rlRange->setDictionaryFlag();
+            addValToSets(rlRange->fIncludesSets, fGroupCount+2);
+        }
+    }
+
+    // Handle input sets that contain the special string {eof}.
+    //   Column 1 of the state table is reserved for EOF on input.
+    //   Column 2 is reserved for before-the-start-input.
+    //            (This column can be optimized away later if there are no rule
+    //             references to {bof}.)
+    //   Add this column value (1 or 2) to the equivalent expression
+    //     subtree for each UnicodeSet that contains the string {eof}
+    //   Because {bof} and {eof} are not a characters in the normal sense,
+    //   they doesn't affect the computation of ranges or TRIE.
+    static const UChar eofUString[] = {0x65, 0x6f, 0x66, 0};
+    static const UChar bofUString[] = {0x62, 0x6f, 0x66, 0};
+
+    UnicodeString eofString(eofUString);
+    UnicodeString bofString(bofUString);
+    for (ni=0; ; ni++) {        // Loop over each of the UnicodeSets encountered in the input rules
+        usetNode = (RBBINode *)this->fRB->fUSetNodes->elementAt(ni);
+        if (usetNode==NULL) {
+            break;
+        }
+        UnicodeSet      *inputSet = usetNode->fInputSet;
+        if (inputSet->contains(eofString)) {
+            addValToSet(usetNode, 1);
+        }
+        if (inputSet->contains(bofString)) {
+            addValToSet(usetNode, 2);
+            fSawBOF = TRUE;
+        }
+    }
+
+
+    if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "rgroup")) {printRangeGroups();}
+    if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "esets")) {printSets();}
+
+    //
+    // Build the Trie table for mapping UChar32 values to the corresponding
+    //   range group number
+    //
+    fTrie = utrie_open(NULL,    //  Pre-existing trie to be filled in
+                      NULL,    //  Data array  (utrie will allocate one)
+                      100000,  //  Max Data Length
+                      0,       //  Initial value for all code points
+                      0,       //  Lead surrogate unit value
+                      TRUE);   //  Keep Latin 1 in separately
+
+
+    for (rlRange = fRangeList; rlRange!=0; rlRange=rlRange->fNext) {
+        utrie_setRange32(fTrie, rlRange->fStartChar, rlRange->fEndChar+1, rlRange->fNum, TRUE);
+    }
+}
+
+
+
+//-----------------------------------------------------------------------------------
+//
+//  getTrieSize()    Return the size that will be required to serialize the Trie.
+//
+//-----------------------------------------------------------------------------------
+int32_t RBBISetBuilder::getTrieSize() /*const*/ {
+    fTrieSize  = utrie_serialize(fTrie,
+                                    NULL,                // Buffer
+                                    0,                   // Capacity
+                                    getFoldedRBBIValue,
+                                    TRUE,                // Reduce to 16 bits
+                                    fStatus);
+    // RBBIDebugPrintf("Trie table size is %d\n", trieSize);
+    return fTrieSize;
+}
+
+
+//-----------------------------------------------------------------------------------
+//
+//  serializeTrie()   Put the serialized trie at the specified address.
+//                    Trust the caller to have given us enough memory.
+//                    getTrieSize() MUST be called first.
+//
+//-----------------------------------------------------------------------------------
+void RBBISetBuilder::serializeTrie(uint8_t *where) {
+    utrie_serialize(fTrie,
+                    where,                   // Buffer
+                    fTrieSize,               // Capacity
+                    getFoldedRBBIValue,
+                    TRUE,                    // Reduce to 16 bits
+                    fStatus);
+}
+
+//------------------------------------------------------------------------
+//
+//  addValToSets     Add a runtime-mapped input value to each uset from a
+//                   list of uset nodes. (val corresponds to a state table column.)
+//                   For each of the original Unicode sets - which correspond
+//                   directly to uset nodes - a logically equivalent expression
+//                   is constructed in terms of the remapped runtime input
+//                   symbol set.  This function adds one runtime input symbol to
+//                   a list of sets.
+//
+//                   The "logically equivalent expression" is the tree for an
+//                   or-ing together of all of the symbols that go into the set.
+//
+//------------------------------------------------------------------------
+void  RBBISetBuilder::addValToSets(UVector *sets, uint32_t val) {
+    int32_t       ix;
+
+    for (ix=0; ix<sets->size(); ix++) {
+        RBBINode *usetNode = (RBBINode *)sets->elementAt(ix);
+        addValToSet(usetNode, val);
+    }
+}
+
+void  RBBISetBuilder::addValToSet(RBBINode *usetNode, uint32_t val) {
+    RBBINode *leafNode = new RBBINode(RBBINode::leafChar);
+    if (leafNode == NULL) {
+        *fStatus = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    leafNode->fVal = (unsigned short)val;
+    if (usetNode->fLeftChild == NULL) {
+        usetNode->fLeftChild = leafNode;
+        leafNode->fParent    = usetNode;
+    } else {
+        // There are already input symbols present for this set.
+        // Set up an OR node, with the previous stuff as the left child
+        //   and the new value as the right child.
+        RBBINode *orNode = new RBBINode(RBBINode::opOr);
+        if (orNode == NULL) {
+            *fStatus = U_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+        orNode->fLeftChild  = usetNode->fLeftChild;
+        orNode->fRightChild = leafNode;
+        orNode->fLeftChild->fParent  = orNode;
+        orNode->fRightChild->fParent = orNode;
+        usetNode->fLeftChild = orNode;
+        orNode->fParent = usetNode;
+    }
+}
+
+
+//------------------------------------------------------------------------
+//
+//   getNumCharCategories
+//
+//------------------------------------------------------------------------
+int32_t  RBBISetBuilder::getNumCharCategories() const {
+    return fGroupCount + 3;
+}
+
+
+//------------------------------------------------------------------------
+//
+//   sawBOF
+//
+//------------------------------------------------------------------------
+UBool  RBBISetBuilder::sawBOF() const {
+    return fSawBOF;
+}
+
+
+//------------------------------------------------------------------------
+//
+//   getFirstChar      Given a runtime RBBI character category, find
+//                     the first UChar32 that is in the set of chars 
+//                     in the category.
+//------------------------------------------------------------------------
+UChar32  RBBISetBuilder::getFirstChar(int32_t category) const {
+    RangeDescriptor   *rlRange;
+    UChar32            retVal = (UChar32)-1;
+    for (rlRange = fRangeList; rlRange!=0; rlRange=rlRange->fNext) {
+        if (rlRange->fNum == category) {
+            retVal = rlRange->fStartChar;
+            break;
+        }
+    }
+    return retVal;
+}
+
+
+
+//------------------------------------------------------------------------
+//
+//   printRanges        A debugging function.
+//                      dump out all of the range definitions.
+//
+//------------------------------------------------------------------------
+#ifdef RBBI_DEBUG
+void RBBISetBuilder::printRanges() {
+    RangeDescriptor       *rlRange;
+    int                    i;
+
+    RBBIDebugPrintf("\n\n Nonoverlapping Ranges ...\n");
+    for (rlRange = fRangeList; rlRange!=0; rlRange=rlRange->fNext) {
+        RBBIDebugPrintf("%2i  %4x-%4x  ", rlRange->fNum, rlRange->fStartChar, rlRange->fEndChar);
+
+        for (i=0; i<rlRange->fIncludesSets->size(); i++) {
+            RBBINode       *usetNode    = (RBBINode *)rlRange->fIncludesSets->elementAt(i);
+            UnicodeString   setName = UNICODE_STRING("anon", 4);
+            RBBINode       *setRef = usetNode->fParent;
+            if (setRef != NULL) {
+                RBBINode *varRef = setRef->fParent;
+                if (varRef != NULL  &&  varRef->fType == RBBINode::varRef) {
+                    setName = varRef->fText;
+                }
+            }
+            RBBI_DEBUG_printUnicodeString(setName); RBBIDebugPrintf("  ");
+        }
+        RBBIDebugPrintf("\n");
+    }
+}
+#endif
+
+
+//------------------------------------------------------------------------
+//
+//   printRangeGroups     A debugging function.
+//                        dump out all of the range groups.
+//
+//------------------------------------------------------------------------
+#ifdef RBBI_DEBUG
+void RBBISetBuilder::printRangeGroups() {
+    RangeDescriptor       *rlRange;
+    RangeDescriptor       *tRange;
+    int                    i;
+    int                    lastPrintedGroupNum = 0;
+
+    RBBIDebugPrintf("\nRanges grouped by Unicode Set Membership...\n");
+    for (rlRange = fRangeList; rlRange!=0; rlRange=rlRange->fNext) {
+        int groupNum = rlRange->fNum & 0xbfff;
+        if (groupNum > lastPrintedGroupNum) {
+            lastPrintedGroupNum = groupNum;
+            RBBIDebugPrintf("%2i  ", groupNum);
+
+            if (rlRange->fNum & 0x4000) { RBBIDebugPrintf(" <DICT> ");}
+
+            for (i=0; i<rlRange->fIncludesSets->size(); i++) {
+                RBBINode       *usetNode    = (RBBINode *)rlRange->fIncludesSets->elementAt(i);
+                UnicodeString   setName = UNICODE_STRING("anon", 4);
+                RBBINode       *setRef = usetNode->fParent;
+                if (setRef != NULL) {
+                    RBBINode *varRef = setRef->fParent;
+                    if (varRef != NULL  &&  varRef->fType == RBBINode::varRef) {
+                        setName = varRef->fText;
+                    }
+                }
+                RBBI_DEBUG_printUnicodeString(setName); RBBIDebugPrintf(" ");
+            }
+
+            i = 0;
+            for (tRange = rlRange; tRange != 0; tRange = tRange->fNext) {
+                if (tRange->fNum == rlRange->fNum) {
+                    if (i++ % 5 == 0) {
+                        RBBIDebugPrintf("\n    ");
+                    }
+                    RBBIDebugPrintf("  %05x-%05x", tRange->fStartChar, tRange->fEndChar);
+                }
+            }
+            RBBIDebugPrintf("\n");
+        }
+    }
+    RBBIDebugPrintf("\n");
+}
+#endif
+
+
+//------------------------------------------------------------------------
+//
+//   printSets          A debugging function.
+//                      dump out all of the set definitions.
+//
+//------------------------------------------------------------------------
+#ifdef RBBI_DEBUG
+void RBBISetBuilder::printSets() {
+    int                   i;
+
+    RBBIDebugPrintf("\n\nUnicode Sets List\n------------------\n");
+    for (i=0; ; i++) {
+        RBBINode        *usetNode;
+        RBBINode        *setRef;
+        RBBINode        *varRef;
+        UnicodeString    setName;
+
+        usetNode = (RBBINode *)fRB->fUSetNodes->elementAt(i);
+        if (usetNode == NULL) {
+            break;
+        }
+
+        RBBIDebugPrintf("%3d    ", i);
+        setName = UNICODE_STRING("anonymous", 9);
+        setRef = usetNode->fParent;
+        if (setRef != NULL) {
+            varRef = setRef->fParent;
+            if (varRef != NULL  &&  varRef->fType == RBBINode::varRef) {
+                setName = varRef->fText;
+            }
+        }
+        RBBI_DEBUG_printUnicodeString(setName);
+        RBBIDebugPrintf("   ");
+        RBBI_DEBUG_printUnicodeString(usetNode->fText);
+        RBBIDebugPrintf("\n");
+        if (usetNode->fLeftChild != NULL) {
+            usetNode->fLeftChild->printTree(TRUE);
+        }
+    }
+    RBBIDebugPrintf("\n");
+}
+#endif
+
+
+
+//-------------------------------------------------------------------------------------
+//
+//  RangeDescriptor copy constructor
+//
+//-------------------------------------------------------------------------------------
+
+RangeDescriptor::RangeDescriptor(const RangeDescriptor &other, UErrorCode &status) {
+    int  i;
+
+    this->fStartChar    = other.fStartChar;
+    this->fEndChar      = other.fEndChar;
+    this->fNum          = other.fNum;
+    this->fNext         = NULL;
+    UErrorCode oldstatus = status;
+    this->fIncludesSets = new UVector(status);
+    if (U_FAILURE(oldstatus)) {
+        status = oldstatus;
+    }
+    if (U_FAILURE(status)) {
+        return;
+    }
+    /* test for NULL */
+    if (this->fIncludesSets == 0) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+
+    for (i=0; i<other.fIncludesSets->size(); i++) {
+        this->fIncludesSets->addElement(other.fIncludesSets->elementAt(i), status);
+    }
+}
+
+
+//-------------------------------------------------------------------------------------
+//
+//  RangeDesriptor default constructor
+//
+//-------------------------------------------------------------------------------------
+RangeDescriptor::RangeDescriptor(UErrorCode &status) {
+    this->fStartChar    = 0;
+    this->fEndChar      = 0;
+    this->fNum          = 0;
+    this->fNext         = NULL;
+    UErrorCode oldstatus = status;
+    this->fIncludesSets = new UVector(status);
+    if (U_FAILURE(oldstatus)) {
+        status = oldstatus;
+    }
+    if (U_FAILURE(status)) {
+        return;
+    }
+    /* test for NULL */
+    if(this->fIncludesSets == 0) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+
+}
+
+
+//-------------------------------------------------------------------------------------
+//
+//  RangeDesriptor Destructor
+//
+//-------------------------------------------------------------------------------------
+RangeDescriptor::~RangeDescriptor() {
+    delete  fIncludesSets;
+    fIncludesSets = NULL;
+}
+
+//-------------------------------------------------------------------------------------
+//
+//  RangeDesriptor::split()
+//
+//-------------------------------------------------------------------------------------
+void RangeDescriptor::split(UChar32 where, UErrorCode &status) {
+    U_ASSERT(where>fStartChar && where<=fEndChar);
+    RangeDescriptor *nr = new RangeDescriptor(*this, status);
+    if(nr == 0) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    if (U_FAILURE(status)) {
+        delete nr;
+        return;
+    }
+    //  RangeDescriptor copy constructor copies all fields.
+    //  Only need to update those that are different after the split.
+    nr->fStartChar = where;
+    this->fEndChar = where-1;
+    nr->fNext      = this->fNext;
+    this->fNext    = nr;
+}
+
+
+//-------------------------------------------------------------------------------------
+//
+//   RangeDescriptor::setDictionaryFlag
+//
+//            Character Category Numbers that include characters from
+//            the original Unicode Set named "dictionary" have bit 14
+//            set to 1.  The RBBI runtime engine uses this to trigger
+//            use of the word dictionary.
+//
+//            This function looks through the Unicode Sets that it
+//            (the range) includes, and sets the bit in fNum when
+//            "dictionary" is among them.
+//
+//            TODO:  a faster way would be to find the set node for
+//                   "dictionary" just once, rather than looking it
+//                   up by name every time.
+//
+//-------------------------------------------------------------------------------------
+void RangeDescriptor::setDictionaryFlag() {
+    int i;
+
+    for (i=0; i<this->fIncludesSets->size(); i++) {
+        RBBINode       *usetNode    = (RBBINode *)fIncludesSets->elementAt(i);
+        UnicodeString   setName;
+        RBBINode       *setRef = usetNode->fParent;
+        if (setRef != NULL) {
+            RBBINode *varRef = setRef->fParent;
+            if (varRef != NULL  &&  varRef->fType == RBBINode::varRef) {
+                setName = varRef->fText;
+            }
+        }
+        if (setName.compare(UNICODE_STRING("dictionary", 10)) == 0) {   // TODO:  no string literals.
+            this->fNum |= 0x4000;
+            break;
+        }
+    }
+}
+
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
diff --git a/source/common/rbbisetb.h b/source/common/rbbisetb.h
new file mode 100644
index 0000000..c8bc1df
--- /dev/null
+++ b/source/common/rbbisetb.h
@@ -0,0 +1,130 @@
+//
+//  rbbisetb.h
+/*
+**********************************************************************
+*   Copyright (c) 2001-2005, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+
+#ifndef RBBISETB_H
+#define RBBISETB_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "rbbirb.h"
+#include "uvector.h"
+
+struct  UNewTrie;
+
+U_NAMESPACE_BEGIN
+
+//
+//  RBBISetBuilder   Derives the character categories used by the runtime RBBI engine
+//                   from the Unicode Sets appearing in the source  RBBI rules, and
+//                   creates the TRIE table used to map from Unicode to the
+//                   character categories.
+//
+
+
+//
+//  RangeDescriptor
+//
+//     Each of the non-overlapping character ranges gets one of these descriptors.
+//     All of them are strung together in a linked list, which is kept in order
+//     (by character)
+//
+class RangeDescriptor : public UMemory {
+public:
+    UChar32            fStartChar;      // Start of range, unicode 32 bit value.
+    UChar32            fEndChar;        // End of range, unicode 32 bit value.
+    int32_t            fNum;            // runtime-mapped input value for this range.
+    UVector           *fIncludesSets;   // vector of the the original
+                                        //   Unicode sets that include this range.
+                                        //    (Contains ptrs to uset nodes)
+    RangeDescriptor   *fNext;           // Next RangeDescriptor in the linked list.
+
+    RangeDescriptor(UErrorCode &status);
+    RangeDescriptor(const RangeDescriptor &other, UErrorCode &status);
+    ~RangeDescriptor();
+    void split(UChar32 where, UErrorCode &status);   // Spit this range in two at "where", with
+                                        //   where appearing in the second (higher) part.
+    void setDictionaryFlag();           // Check whether this range appears as part of
+                                        //   the Unicode set named "dictionary"
+
+private:
+    RangeDescriptor(const RangeDescriptor &other); // forbid copying of this class
+    RangeDescriptor &operator=(const RangeDescriptor &other); // forbid copying of this class
+};
+
+
+//
+//  RBBISetBuilder   Handles processing of Unicode Sets from RBBI rules.
+//
+//      Starting with the rules parse tree from the scanner,
+//
+//                   -  Enumerate the set of UnicodeSets that are referenced
+//                      by the RBBI rules.
+//                   -  compute a derived set of non-overlapping UnicodeSets
+//                      that will correspond to columns in the state table for
+//                      the RBBI execution engine.
+//                   -  construct the trie table that maps input characters
+//                      to set numbers in the non-overlapping set of sets.
+//
+
+
+class RBBISetBuilder : public UMemory {
+public:
+    RBBISetBuilder(RBBIRuleBuilder *rb);
+    ~RBBISetBuilder();
+
+    void     build();
+    void     addValToSets(UVector *sets,      uint32_t val);
+    void     addValToSet (RBBINode *usetNode, uint32_t val);
+    int32_t  getNumCharCategories() const;   // CharCategories are the same as input symbol set to the
+                                             //    runtime state machine, which are the same as
+                                             //    columns in the DFA state table
+    int32_t  getTrieSize() /*const*/;        // Size in bytes of the serialized Trie.
+    void     serializeTrie(uint8_t *where);  // write out the serialized Trie.
+    UChar32  getFirstChar(int32_t  val) const;
+    UBool    sawBOF() const;                 // Indicate whether any references to the {bof} pseudo
+                                             //   character were encountered.
+#ifdef RBBI_DEBUG
+    void     printSets();
+    void     printRanges();
+    void     printRangeGroups();
+#else
+    #define printSets()
+    #define printRanges()
+    #define printRangeGroups()
+#endif
+
+private:
+    void           numberSets();
+
+    RBBIRuleBuilder       *fRB;             // The RBBI Rule Compiler that owns us.
+    UErrorCode            *fStatus;
+
+    RangeDescriptor       *fRangeList;      // Head of the linked list of RangeDescriptors
+
+    UNewTrie              *fTrie;           // The mapping TRIE that is the end result of processing
+    uint32_t              fTrieSize;        //  the Unicode Sets.
+
+    // Groups correspond to character categories -
+    //       groups of ranges that are in the same original UnicodeSets.
+    //       fGroupCount is the index of the last used group.
+    //       fGroupCount+1 is also the number of columns in the RBBI state table being compiled.
+    //       State table column 0 is not used.  Column 1 is for end-of-input.
+    //       column 2 is for group 0.  Funny counting.
+    int32_t               fGroupCount;
+
+    UBool                 fSawBOF;
+
+    RBBISetBuilder(const RBBISetBuilder &other); // forbid copying of this class
+    RBBISetBuilder &operator=(const RBBISetBuilder &other); // forbid copying of this class
+};
+
+
+
+U_NAMESPACE_END
+#endif
diff --git a/source/common/rbbistbl.cpp b/source/common/rbbistbl.cpp
new file mode 100644
index 0000000..cbcd381
--- /dev/null
+++ b/source/common/rbbistbl.cpp
@@ -0,0 +1,269 @@
+//
+//  file:  rbbistbl.cpp    Implementation of the ICU RBBISymbolTable class
+//
+/*
+***************************************************************************
+*   Copyright (C) 2002-2006 International Business Machines Corporation   *
+*   and others. All rights reserved.                                      *
+***************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/unistr.h"
+#include "unicode/uniset.h"
+#include "unicode/uchar.h"
+#include "unicode/parsepos.h"
+
+#include "umutex.h"
+
+#include "rbbirb.h"
+#include "rbbinode.h"
+
+
+//
+//  RBBISymbolTableEntry_deleter    Used by the UHashTable to delete the contents
+//                                  when the hash table is deleted.
+//
+U_CDECL_BEGIN
+static void U_CALLCONV RBBISymbolTableEntry_deleter(void *p) {
+    U_NAMESPACE_QUALIFIER RBBISymbolTableEntry *px = (U_NAMESPACE_QUALIFIER RBBISymbolTableEntry *)p;
+    delete px;
+}
+U_CDECL_END
+
+
+
+U_NAMESPACE_BEGIN
+
+RBBISymbolTable::RBBISymbolTable(RBBIRuleScanner *rs, const UnicodeString &rules, UErrorCode &status)
+    :fRules(rules), fRuleScanner(rs), ffffString(UChar(0xffff))
+{
+    fHashTable       = NULL;
+    fCachedSetLookup = NULL;
+    
+    fHashTable = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, &status);
+    // uhash_open checks status
+    if (U_FAILURE(status)) {
+        return;
+    }
+    uhash_setValueDeleter(fHashTable, RBBISymbolTableEntry_deleter);
+}
+
+
+
+RBBISymbolTable::~RBBISymbolTable()
+{
+    uhash_close(fHashTable);
+}
+
+
+//
+//  RBBISymbolTable::lookup       This function from the abstract symbol table inteface
+//                                looks up a variable name and returns a UnicodeString
+//                                containing the substitution text.
+//
+//                                The variable name does NOT include the leading $.
+//
+const UnicodeString  *RBBISymbolTable::lookup(const UnicodeString& s) const
+{
+    RBBISymbolTableEntry  *el;
+    RBBINode              *varRefNode;
+    RBBINode              *exprNode;
+    RBBINode              *usetNode;
+    const UnicodeString   *retString;
+    RBBISymbolTable       *This = (RBBISymbolTable *)this;   // cast off const
+
+    el = (RBBISymbolTableEntry *)uhash_get(fHashTable, &s);
+    if (el == NULL) {
+        return NULL;
+    }
+
+    varRefNode = el->val;
+    exprNode   = varRefNode->fLeftChild;     // Root node of expression for variable
+    if (exprNode->fType == RBBINode::setRef) {
+        // The $variable refers to a single UnicodeSet
+        //   return the ffffString, which will subsequently be interpreted as a
+        //   stand-in character for the set by RBBISymbolTable::lookupMatcher()
+        usetNode = exprNode->fLeftChild;
+        This->fCachedSetLookup = usetNode->fInputSet;
+        retString = &ffffString;
+    }
+    else
+    {
+        // The variable refers to something other than just a set.
+        // return the original source string for the expression
+        retString = &exprNode->fText;
+        This->fCachedSetLookup = NULL;
+    }
+    return retString;
+}
+
+
+
+//
+//  RBBISymbolTable::lookupMatcher   This function from the abstract symbol table
+//                                   interface maps a single stand-in character to a
+//                                   pointer to a Unicode Set.   The Unicode Set code uses this
+//                                   mechanism to get all references to the same $variable
+//                                   name to refer to a single common Unicode Set instance.
+//
+//    This implementation cheats a little, and does not maintain a map of stand-in chars
+//    to sets.  Instead, it takes advantage of the fact that  the UnicodeSet
+//    constructor will always call this function right after calling lookup(),
+//    and we just need to remember what set to return between these two calls.
+const UnicodeFunctor *RBBISymbolTable::lookupMatcher(UChar32 ch) const
+{
+    UnicodeSet *retVal = NULL;
+    RBBISymbolTable *This = (RBBISymbolTable *)this;   // cast off const
+    if (ch == 0xffff) {
+        retVal = fCachedSetLookup;
+        This->fCachedSetLookup = 0;
+    }
+    return retVal;
+}
+
+//
+// RBBISymbolTable::parseReference   This function from the abstract symbol table interface
+//                                   looks for a $variable name in the source text.
+//                                   It does not look it up, only scans for it.
+//                                   It is used by the UnicodeSet parser.
+//
+//                                   This implementation is lifted pretty much verbatim
+//                                   from the rules based transliterator implementation.
+//                                   I didn't see an obvious way of sharing it.
+//
+UnicodeString   RBBISymbolTable::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;
+}
+
+
+
+//
+// RBBISymbolTable::lookupNode      Given a key (a variable name), return the
+//                                  corresponding RBBI Node.  If there is no entry
+//                                  in the table for this name, return NULL.
+//
+RBBINode       *RBBISymbolTable::lookupNode(const UnicodeString &key) const{
+
+    RBBINode             *retNode = NULL;
+    RBBISymbolTableEntry *el;
+
+    el = (RBBISymbolTableEntry *)uhash_get(fHashTable, &key);
+    if (el != NULL) {
+        retNode = el->val;
+    }
+    return retNode;
+}
+
+
+//
+//    RBBISymbolTable::addEntry     Add a new entry to the symbol table.
+//                                  Indicate an error if the name already exists -
+//                                    this will only occur in the case of duplicate
+//                                    variable assignments.
+//
+void            RBBISymbolTable::addEntry  (const UnicodeString &key, RBBINode *val, UErrorCode &err) {
+    RBBISymbolTableEntry *e;
+    /* test for buffer overflows */
+    if (U_FAILURE(err)) {
+        return;
+    }
+    e = (RBBISymbolTableEntry *)uhash_get(fHashTable, &key);
+    if (e != NULL) {
+        err = U_BRK_VARIABLE_REDFINITION;
+        return;
+    }
+
+    e = new RBBISymbolTableEntry;
+    if (e == NULL) {
+        err = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    e->key = key;
+    e->val = val;
+    uhash_put( fHashTable, &e->key, e, &err);
+}
+
+
+RBBISymbolTableEntry::RBBISymbolTableEntry() : UMemory(), key(), val(NULL) {}
+
+RBBISymbolTableEntry::~RBBISymbolTableEntry() {
+    // The "val" of a symbol table entry is a variable reference node.
+    // The l. child of the val is the rhs expression from the assignment.
+    // Unlike other node types, children of variable reference nodes are not
+    //    automatically recursively deleted.  We do it manually here.
+    delete val->fLeftChild;
+    val->fLeftChild = NULL;
+
+    delete  val;
+
+    // Note: the key UnicodeString is destructed by virtue of being in the object by value.
+}
+
+
+//
+//  RBBISymbolTable::print    Debugging function, dump out the symbol table contents.
+//
+#ifdef RBBI_DEBUG
+void RBBISymbolTable::rbbiSymtablePrint() const {
+    RBBIDebugPrintf("Variable Definitions\n"
+           "Name               Node Val     String Val\n"
+           "----------------------------------------------------------------------\n");
+
+    int32_t pos = -1;
+    const UHashElement  *e   = NULL;
+    for (;;) {
+        e = uhash_nextElement(fHashTable,  &pos);
+        if (e == NULL ) {
+            break;
+        }
+        RBBISymbolTableEntry  *s   = (RBBISymbolTableEntry *)e->value.pointer;
+
+        RBBI_DEBUG_printUnicodeString(s->key, 15);
+        RBBIDebugPrintf("   %8p   ", (void *)s->val);
+        RBBI_DEBUG_printUnicodeString(s->val->fLeftChild->fText);
+        RBBIDebugPrintf("\n");
+    }
+
+    RBBIDebugPrintf("\nParsed Variable Definitions\n");
+    pos = -1;
+    for (;;) {
+        e = uhash_nextElement(fHashTable,  &pos);
+        if (e == NULL ) {
+            break;
+        }
+        RBBISymbolTableEntry  *s   = (RBBISymbolTableEntry *)e->value.pointer;
+        RBBI_DEBUG_printUnicodeString(s->key);
+        s->val->fLeftChild->printTree(TRUE);
+        RBBIDebugPrintf("\n");
+    }
+}
+#endif
+
+
+
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
diff --git a/source/common/rbbitblb.cpp b/source/common/rbbitblb.cpp
new file mode 100644
index 0000000..2ce82df
--- /dev/null
+++ b/source/common/rbbitblb.cpp
@@ -0,0 +1,1260 @@
+/*
+**********************************************************************
+*   Copyright (c) 2002-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+//
+//  rbbitblb.cpp
+//
+
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/unistr.h"
+#include "rbbitblb.h"
+#include "rbbirb.h"
+#include "rbbisetb.h"
+#include "rbbidata.h"
+#include "cstring.h"
+#include "uassert.h"
+#include "cmemory.h"
+
+U_NAMESPACE_BEGIN
+
+RBBITableBuilder::RBBITableBuilder(RBBIRuleBuilder *rb, RBBINode **rootNode) :
+ fTree(*rootNode) {
+    fRB                 = rb;
+    fStatus             = fRB->fStatus;
+    UErrorCode status   = U_ZERO_ERROR;
+    fDStates            = new UVector(status);
+    if (U_FAILURE(*fStatus)) {
+        return;
+    }
+    if (U_FAILURE(status)) {
+        *fStatus = status;
+        return;
+    }
+    if (fDStates == NULL) {
+        *fStatus = U_MEMORY_ALLOCATION_ERROR;;
+    }
+}
+
+
+
+RBBITableBuilder::~RBBITableBuilder() {
+    int i;
+    for (i=0; i<fDStates->size(); i++) {
+        delete (RBBIStateDescriptor *)fDStates->elementAt(i);
+    }
+    delete   fDStates;
+}
+
+
+//-----------------------------------------------------------------------------
+//
+//   RBBITableBuilder::build  -  This is the main function for building the DFA state transtion
+//                               table from the RBBI rules parse tree.
+//
+//-----------------------------------------------------------------------------
+void  RBBITableBuilder::build() {
+
+    if (U_FAILURE(*fStatus)) {
+        return;
+    }
+
+    // If there were no rules, just return.  This situation can easily arise
+    //   for the reverse rules.
+    if (fTree==NULL) {
+        return;
+    }
+
+    //
+    // Walk through the tree, replacing any references to $variables with a copy of the
+    //   parse tree for the substition expression.
+    //
+    fTree = fTree->flattenVariables();
+#ifdef RBBI_DEBUG
+    if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "ftree")) {
+        RBBIDebugPuts("Parse tree after flattening variable references.");
+        fTree->printTree(TRUE);
+    }
+#endif
+
+    //
+    // If the rules contained any references to {bof} 
+    //   add a {bof} <cat> <former root of tree> to the
+    //   tree.  Means that all matches must start out with the 
+    //   {bof} fake character.
+    // 
+    if (fRB->fSetBuilder->sawBOF()) {
+        RBBINode *bofTop    = new RBBINode(RBBINode::opCat);
+        RBBINode *bofLeaf   = new RBBINode(RBBINode::leafChar);
+        // Delete and exit if memory allocation failed.
+        if (bofTop == NULL || bofLeaf == NULL) {
+            *fStatus = U_MEMORY_ALLOCATION_ERROR;
+            delete bofTop;
+            delete bofLeaf;
+            return;
+        }
+        bofTop->fLeftChild  = bofLeaf;
+        bofTop->fRightChild = fTree;
+        bofLeaf->fParent    = bofTop;
+        bofLeaf->fVal       = 2;      // Reserved value for {bof}.
+        fTree               = bofTop;
+    }
+
+    //
+    // Add a unique right-end marker to the expression.
+    //   Appears as a cat-node, left child being the original tree,
+    //   right child being the end marker.
+    //
+    RBBINode *cn = new RBBINode(RBBINode::opCat);
+    // Exit if memory allocation failed.
+    if (cn == NULL) {
+        *fStatus = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    cn->fLeftChild = fTree;
+    fTree->fParent = cn;
+    cn->fRightChild = new RBBINode(RBBINode::endMark);
+    // Delete and exit if memory allocation failed.
+    if (cn->fRightChild == NULL) {
+        *fStatus = U_MEMORY_ALLOCATION_ERROR;
+        delete cn;
+        return;
+    }
+    cn->fRightChild->fParent = cn;
+    fTree = cn;
+
+    //
+    //  Replace all references to UnicodeSets with the tree for the equivalent
+    //      expression.
+    //
+    fTree->flattenSets();
+#ifdef RBBI_DEBUG
+    if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "stree")) {
+        RBBIDebugPuts("Parse tree after flattening Unicode Set references.");
+        fTree->printTree(TRUE);
+    }
+#endif
+
+
+    //
+    // calculate the functions nullable, firstpos, lastpos and followpos on
+    // nodes in the parse tree.
+    //    See the alogrithm description in Aho.
+    //    Understanding how this works by looking at the code alone will be
+    //       nearly impossible.
+    //
+    calcNullable(fTree);
+    calcFirstPos(fTree);
+    calcLastPos(fTree);
+    calcFollowPos(fTree);
+    if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "pos")) {
+        RBBIDebugPuts("\n");
+        printPosSets(fTree);
+    }
+
+    //
+    //  For "chained" rules, modify the followPos sets
+    //
+    if (fRB->fChainRules) {
+        calcChainedFollowPos(fTree);
+    }
+
+    //
+    //  BOF (start of input) test fixup.
+    //
+    if (fRB->fSetBuilder->sawBOF()) {
+        bofFixup();
+    }
+
+    //
+    // Build the DFA state transition tables.
+    //
+    buildStateTable();
+    flagAcceptingStates();
+    flagLookAheadStates();
+    flagTaggedStates();
+
+    //
+    // Update the global table of rule status {tag} values
+    // The rule builder has a global vector of status values that are common
+    //    for all tables.  Merge the ones from this table into the global set.
+    //
+    mergeRuleStatusVals();
+
+    if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "states")) {printStates();};
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+//   calcNullable.    Impossible to explain succinctly.  See Aho, section 3.9
+//
+//-----------------------------------------------------------------------------
+void RBBITableBuilder::calcNullable(RBBINode *n) {
+    if (n == NULL) {
+        return;
+    }
+    if (n->fType == RBBINode::setRef ||
+        n->fType == RBBINode::endMark ) {
+        // These are non-empty leaf node types.
+        n->fNullable = FALSE;
+        return;
+    }
+
+    if (n->fType == RBBINode::lookAhead || n->fType == RBBINode::tag) {
+        // Lookahead marker node.  It's a leaf, so no recursion on children.
+        // It's nullable because it does not match any literal text from the input stream.
+        n->fNullable = TRUE;
+        return;
+    }
+
+
+    // The node is not a leaf.
+    //  Calculate nullable on its children.
+    calcNullable(n->fLeftChild);
+    calcNullable(n->fRightChild);
+
+    // Apply functions from table 3.40 in Aho
+    if (n->fType == RBBINode::opOr) {
+        n->fNullable = n->fLeftChild->fNullable || n->fRightChild->fNullable;
+    }
+    else if (n->fType == RBBINode::opCat) {
+        n->fNullable = n->fLeftChild->fNullable && n->fRightChild->fNullable;
+    }
+    else if (n->fType == RBBINode::opStar || n->fType == RBBINode::opQuestion) {
+        n->fNullable = TRUE;
+    }
+    else {
+        n->fNullable = FALSE;
+    }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+//
+//   calcFirstPos.    Impossible to explain succinctly.  See Aho, section 3.9
+//
+//-----------------------------------------------------------------------------
+void RBBITableBuilder::calcFirstPos(RBBINode *n) {
+    if (n == NULL) {
+        return;
+    }
+    if (n->fType == RBBINode::leafChar  ||
+        n->fType == RBBINode::endMark   ||
+        n->fType == RBBINode::lookAhead ||
+        n->fType == RBBINode::tag) {
+        // These are non-empty leaf node types.
+        // Note: In order to maintain the sort invariant on the set,
+        // this function should only be called on a node whose set is
+        // empty to start with.
+        n->fFirstPosSet->addElement(n, *fStatus);
+        return;
+    }
+
+    // The node is not a leaf.
+    //  Calculate firstPos on its children.
+    calcFirstPos(n->fLeftChild);
+    calcFirstPos(n->fRightChild);
+
+    // Apply functions from table 3.40 in Aho
+    if (n->fType == RBBINode::opOr) {
+        setAdd(n->fFirstPosSet, n->fLeftChild->fFirstPosSet);
+        setAdd(n->fFirstPosSet, n->fRightChild->fFirstPosSet);
+    }
+    else if (n->fType == RBBINode::opCat) {
+        setAdd(n->fFirstPosSet, n->fLeftChild->fFirstPosSet);
+        if (n->fLeftChild->fNullable) {
+            setAdd(n->fFirstPosSet, n->fRightChild->fFirstPosSet);
+        }
+    }
+    else if (n->fType == RBBINode::opStar ||
+             n->fType == RBBINode::opQuestion ||
+             n->fType == RBBINode::opPlus) {
+        setAdd(n->fFirstPosSet, n->fLeftChild->fFirstPosSet);
+    }
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+//   calcLastPos.    Impossible to explain succinctly.  See Aho, section 3.9
+//
+//-----------------------------------------------------------------------------
+void RBBITableBuilder::calcLastPos(RBBINode *n) {
+    if (n == NULL) {
+        return;
+    }
+    if (n->fType == RBBINode::leafChar  ||
+        n->fType == RBBINode::endMark   ||
+        n->fType == RBBINode::lookAhead ||
+        n->fType == RBBINode::tag) {
+        // These are non-empty leaf node types.
+        // Note: In order to maintain the sort invariant on the set,
+        // this function should only be called on a node whose set is
+        // empty to start with.
+        n->fLastPosSet->addElement(n, *fStatus);
+        return;
+    }
+
+    // The node is not a leaf.
+    //  Calculate lastPos on its children.
+    calcLastPos(n->fLeftChild);
+    calcLastPos(n->fRightChild);
+
+    // Apply functions from table 3.40 in Aho
+    if (n->fType == RBBINode::opOr) {
+        setAdd(n->fLastPosSet, n->fLeftChild->fLastPosSet);
+        setAdd(n->fLastPosSet, n->fRightChild->fLastPosSet);
+    }
+    else if (n->fType == RBBINode::opCat) {
+        setAdd(n->fLastPosSet, n->fRightChild->fLastPosSet);
+        if (n->fRightChild->fNullable) {
+            setAdd(n->fLastPosSet, n->fLeftChild->fLastPosSet);
+        }
+    }
+    else if (n->fType == RBBINode::opStar     ||
+             n->fType == RBBINode::opQuestion ||
+             n->fType == RBBINode::opPlus) {
+        setAdd(n->fLastPosSet, n->fLeftChild->fLastPosSet);
+    }
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+//   calcFollowPos.    Impossible to explain succinctly.  See Aho, section 3.9
+//
+//-----------------------------------------------------------------------------
+void RBBITableBuilder::calcFollowPos(RBBINode *n) {
+    if (n == NULL ||
+        n->fType == RBBINode::leafChar ||
+        n->fType == RBBINode::endMark) {
+        return;
+    }
+
+    calcFollowPos(n->fLeftChild);
+    calcFollowPos(n->fRightChild);
+
+    // Aho rule #1
+    if (n->fType == RBBINode::opCat) {
+        RBBINode *i;   // is 'i' in Aho's description
+        uint32_t     ix;
+
+        UVector *LastPosOfLeftChild = n->fLeftChild->fLastPosSet;
+
+        for (ix=0; ix<(uint32_t)LastPosOfLeftChild->size(); ix++) {
+            i = (RBBINode *)LastPosOfLeftChild->elementAt(ix);
+            setAdd(i->fFollowPos, n->fRightChild->fFirstPosSet);
+        }
+    }
+
+    // Aho rule #2
+    if (n->fType == RBBINode::opStar ||
+        n->fType == RBBINode::opPlus) {
+        RBBINode   *i;  // again, n and i are the names from Aho's description.
+        uint32_t    ix;
+
+        for (ix=0; ix<(uint32_t)n->fLastPosSet->size(); ix++) {
+            i = (RBBINode *)n->fLastPosSet->elementAt(ix);
+            setAdd(i->fFollowPos, n->fFirstPosSet);
+        }
+    }
+
+
+
+}
+
+
+//-----------------------------------------------------------------------------
+//
+//   calcChainedFollowPos.    Modify the previously calculated followPos sets
+//                            to implement rule chaining.  NOT described by Aho
+//
+//-----------------------------------------------------------------------------
+void RBBITableBuilder::calcChainedFollowPos(RBBINode *tree) {
+
+    UVector         endMarkerNodes(*fStatus);
+    UVector         leafNodes(*fStatus);
+    int32_t         i;
+
+    if (U_FAILURE(*fStatus)) {
+        return;
+    }
+
+    // get a list of all endmarker nodes.
+    tree->findNodes(&endMarkerNodes, RBBINode::endMark, *fStatus);
+
+    // get a list all leaf nodes
+    tree->findNodes(&leafNodes, RBBINode::leafChar, *fStatus);
+    if (U_FAILURE(*fStatus)) {
+        return;
+    }
+
+    // Get all nodes that can be the start a match, which is FirstPosition()
+    // of the portion of the tree corresponding to user-written rules.
+    // See the tree description in bofFixup().
+    RBBINode *userRuleRoot = tree;
+    if (fRB->fSetBuilder->sawBOF()) {
+        userRuleRoot = tree->fLeftChild->fRightChild;
+    }
+    U_ASSERT(userRuleRoot != NULL);
+    UVector *matchStartNodes = userRuleRoot->fFirstPosSet;
+
+
+    // Iteratate over all leaf nodes,
+    //
+    int32_t  endNodeIx;
+    int32_t  startNodeIx;
+
+    for (endNodeIx=0; endNodeIx<leafNodes.size(); endNodeIx++) {
+        RBBINode *tNode   = (RBBINode *)leafNodes.elementAt(endNodeIx);
+        RBBINode *endNode = NULL;
+
+        // Identify leaf nodes that correspond to overall rule match positions.
+        //   These include an endMarkerNode in their followPos sets.
+        for (i=0; i<endMarkerNodes.size(); i++) {
+            if (tNode->fFollowPos->contains(endMarkerNodes.elementAt(i))) {
+                endNode = tNode;
+                break;
+            }
+        }
+        if (endNode == NULL) {
+            // node wasn't an end node.  Try again with the next.
+            continue;
+        }
+
+        // We've got a node that can end a match.
+
+        // Line Break Specific hack:  If this node's val correspond to the $CM char class,
+        //                            don't chain from it.
+        // TODO:  Add rule syntax for this behavior, get specifics out of here and
+        //        into the rule file.
+        if (fRB->fLBCMNoChain) {
+            UChar32 c = this->fRB->fSetBuilder->getFirstChar(endNode->fVal);
+            if (c != -1) {
+                // c == -1 occurs with sets containing only the {eof} marker string.
+                ULineBreak cLBProp = (ULineBreak)u_getIntPropertyValue(c, UCHAR_LINE_BREAK);
+                if (cLBProp == U_LB_COMBINING_MARK) {
+                    continue;
+                }
+            }
+        }
+
+
+        // Now iterate over the nodes that can start a match, looking for ones
+        //   with the same char class as our ending node.
+        RBBINode *startNode;
+        for (startNodeIx = 0; startNodeIx<matchStartNodes->size(); startNodeIx++) {
+            startNode = (RBBINode *)matchStartNodes->elementAt(startNodeIx);
+            if (startNode->fType != RBBINode::leafChar) {
+                continue;
+            }
+
+            if (endNode->fVal == startNode->fVal) {
+                // The end val (character class) of one possible match is the
+                //   same as the start of another.
+
+                // Add all nodes from the followPos of the start node to the
+                //  followPos set of the end node, which will have the effect of
+                //  letting matches transition from a match state at endNode
+                //  to the second char of a match starting with startNode.
+                setAdd(endNode->fFollowPos, startNode->fFollowPos);
+            }
+        }
+    }
+}
+
+
+//-----------------------------------------------------------------------------
+//
+//   bofFixup.    Fixup for state tables that include {bof} beginning of input testing.
+//                Do an swizzle similar to chaining, modifying the followPos set of
+//                the bofNode to include the followPos nodes from other {bot} nodes
+//                scattered through the tree.
+//
+//                This function has much in common with calcChainedFollowPos().
+//
+//-----------------------------------------------------------------------------
+void RBBITableBuilder::bofFixup() {
+
+    if (U_FAILURE(*fStatus)) {
+        return;
+    }
+
+    //   The parse tree looks like this ...
+    //         fTree root  --->       <cat>
+    //                               /     \       .
+    //                            <cat>   <#end node>
+    //                           /     \  .
+    //                     <bofNode>   rest
+    //                               of tree
+    //
+    //    We will be adding things to the followPos set of the <bofNode>
+    //
+    RBBINode  *bofNode = fTree->fLeftChild->fLeftChild;
+    U_ASSERT(bofNode->fType == RBBINode::leafChar);
+    U_ASSERT(bofNode->fVal == 2);
+
+    // Get all nodes that can be the start a match of the user-written rules
+    //  (excluding the fake bofNode)
+    //  We want the nodes that can start a match in the
+    //     part labeled "rest of tree"
+    // 
+    UVector *matchStartNodes = fTree->fLeftChild->fRightChild->fFirstPosSet;
+
+    RBBINode *startNode;
+    int       startNodeIx;
+    for (startNodeIx = 0; startNodeIx<matchStartNodes->size(); startNodeIx++) {
+        startNode = (RBBINode *)matchStartNodes->elementAt(startNodeIx);
+        if (startNode->fType != RBBINode::leafChar) {
+            continue;
+        }
+
+        if (startNode->fVal == bofNode->fVal) {
+            //  We found a leaf node corresponding to a {bof} that was
+            //    explicitly written into a rule.
+            //  Add everything from the followPos set of this node to the
+            //    followPos set of the fake bofNode at the start of the tree.
+            //  
+            setAdd(bofNode->fFollowPos, startNode->fFollowPos);
+        }
+    }
+}
+
+//-----------------------------------------------------------------------------
+//
+//   buildStateTable()    Determine the set of runtime DFA states and the
+//                        transition tables for these states, by the algorithm
+//                        of fig. 3.44 in Aho.
+//
+//                        Most of the comments are quotes of Aho's psuedo-code.
+//
+//-----------------------------------------------------------------------------
+void RBBITableBuilder::buildStateTable() {
+    if (U_FAILURE(*fStatus)) {
+        return;
+    }
+    RBBIStateDescriptor *failState;
+    // Set it to NULL to avoid uninitialized warning
+    RBBIStateDescriptor *initialState = NULL; 
+    //
+    // Add a dummy state 0 - the stop state.  Not from Aho.
+    int      lastInputSymbol = fRB->fSetBuilder->getNumCharCategories() - 1;
+    failState = new RBBIStateDescriptor(lastInputSymbol, fStatus);
+    if (failState == NULL) {
+        *fStatus = U_MEMORY_ALLOCATION_ERROR;
+        goto ExitBuildSTdeleteall;
+    }
+    failState->fPositions = new UVector(*fStatus);
+    if (failState->fPositions == NULL) {
+        *fStatus = U_MEMORY_ALLOCATION_ERROR;
+    }
+    if (failState->fPositions == NULL || U_FAILURE(*fStatus)) {
+        goto ExitBuildSTdeleteall;
+    }
+    fDStates->addElement(failState, *fStatus);
+    if (U_FAILURE(*fStatus)) {
+        goto ExitBuildSTdeleteall;
+    }
+
+    // initially, the only unmarked state in Dstates is firstpos(root),
+    //       where toot is the root of the syntax tree for (r)#;
+    initialState = new RBBIStateDescriptor(lastInputSymbol, fStatus);
+    if (initialState == NULL) {
+        *fStatus = U_MEMORY_ALLOCATION_ERROR;
+    }
+    if (U_FAILURE(*fStatus)) {
+        goto ExitBuildSTdeleteall;
+    }
+    initialState->fPositions = new UVector(*fStatus);
+    if (initialState->fPositions == NULL) {
+        *fStatus = U_MEMORY_ALLOCATION_ERROR;
+    }
+    if (U_FAILURE(*fStatus)) {
+        goto ExitBuildSTdeleteall;
+    }
+    setAdd(initialState->fPositions, fTree->fFirstPosSet);
+    fDStates->addElement(initialState, *fStatus);
+    if (U_FAILURE(*fStatus)) {
+        goto ExitBuildSTdeleteall;
+    }
+
+    // while there is an unmarked state T in Dstates do begin
+    for (;;) {
+        RBBIStateDescriptor *T = NULL;
+        int32_t              tx;
+        for (tx=1; tx<fDStates->size(); tx++) {
+            RBBIStateDescriptor *temp;
+            temp = (RBBIStateDescriptor *)fDStates->elementAt(tx);
+            if (temp->fMarked == FALSE) {
+                T = temp;
+                break;
+            }
+        }
+        if (T == NULL) {
+            break;
+        }
+
+        // mark T;
+        T->fMarked = TRUE;
+
+        // for each input symbol a do begin
+        int32_t  a;
+        for (a = 1; a<=lastInputSymbol; a++) {
+            // let U be the set of positions that are in followpos(p)
+            //    for some position p in T
+            //    such that the symbol at position p is a;
+            UVector    *U = NULL;
+            RBBINode   *p;
+            int32_t     px;
+            for (px=0; px<T->fPositions->size(); px++) {
+                p = (RBBINode *)T->fPositions->elementAt(px);
+                if ((p->fType == RBBINode::leafChar) &&  (p->fVal == a)) {
+                    if (U == NULL) {
+                        U = new UVector(*fStatus);
+                        if (U == NULL) {
+                        	*fStatus = U_MEMORY_ALLOCATION_ERROR;
+                        	goto ExitBuildSTdeleteall;
+                        }
+                    }
+                    setAdd(U, p->fFollowPos);
+                }
+            }
+
+            // if U is not empty and not in DStates then
+            int32_t  ux = 0;
+            UBool    UinDstates = FALSE;
+            if (U != NULL) {
+                U_ASSERT(U->size() > 0);
+                int  ix;
+                for (ix=0; ix<fDStates->size(); ix++) {
+                    RBBIStateDescriptor *temp2;
+                    temp2 = (RBBIStateDescriptor *)fDStates->elementAt(ix);
+                    if (setEquals(U, temp2->fPositions)) {
+                        delete U;
+                        U  = temp2->fPositions;
+                        ux = ix;
+                        UinDstates = TRUE;
+                        break;
+                    }
+                }
+
+                // Add U as an unmarked state to Dstates
+                if (!UinDstates)
+                {
+                    RBBIStateDescriptor *newState = new RBBIStateDescriptor(lastInputSymbol, fStatus);
+                    if (newState == NULL) {
+                    	*fStatus = U_MEMORY_ALLOCATION_ERROR;
+                    }
+                    if (U_FAILURE(*fStatus)) {
+                        goto ExitBuildSTdeleteall;
+                    }
+                    newState->fPositions = U;
+                    fDStates->addElement(newState, *fStatus);
+                    if (U_FAILURE(*fStatus)) {
+                        return;
+                    }
+                    ux = fDStates->size()-1;
+                }
+
+                // Dtran[T, a] := U;
+                T->fDtran->setElementAt(ux, a);
+            }
+        }
+    }
+    return;
+    // delete local pointers only if error occured.
+ExitBuildSTdeleteall:
+    delete initialState;
+    delete failState;
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+//   flagAcceptingStates    Identify accepting states.
+//                          First get a list of all of the end marker nodes.
+//                          Then, for each state s,
+//                              if s contains one of the end marker nodes in its list of tree positions then
+//                                  s is an accepting state.
+//
+//-----------------------------------------------------------------------------
+void     RBBITableBuilder::flagAcceptingStates() {
+    if (U_FAILURE(*fStatus)) {
+        return;
+    }
+    UVector     endMarkerNodes(*fStatus);
+    RBBINode    *endMarker;
+    int32_t     i;
+    int32_t     n;
+
+    if (U_FAILURE(*fStatus)) {
+        return;
+    }
+
+    fTree->findNodes(&endMarkerNodes, RBBINode::endMark, *fStatus);
+    if (U_FAILURE(*fStatus)) {
+        return;
+    }
+
+    for (i=0; i<endMarkerNodes.size(); i++) {
+        endMarker = (RBBINode *)endMarkerNodes.elementAt(i);
+        for (n=0; n<fDStates->size(); n++) {
+            RBBIStateDescriptor *sd = (RBBIStateDescriptor *)fDStates->elementAt(n);
+            if (sd->fPositions->indexOf(endMarker) >= 0) {
+                // Any non-zero value for fAccepting means this is an accepting node.
+                // The value is what will be returned to the user as the break status.
+                // If no other value was specified, force it to -1.
+
+                if (sd->fAccepting==0) {
+                    // State hasn't been marked as accepting yet.  Do it now.
+                    sd->fAccepting = endMarker->fVal;
+                    if (sd->fAccepting == 0) {
+                        sd->fAccepting = -1;
+                    }
+                }
+                if (sd->fAccepting==-1 && endMarker->fVal != 0) {
+                    // Both lookahead and non-lookahead accepting for this state.
+                    // Favor the look-ahead.  Expedient for line break.
+                    // TODO:  need a more elegant resolution for conflicting rules.
+                    sd->fAccepting = endMarker->fVal;
+                }
+                // implicit else:
+                // if sd->fAccepting already had a value other than 0 or -1, leave it be.
+
+                // If the end marker node is from a look-ahead rule, set
+                //   the fLookAhead field or this state also.
+                if (endMarker->fLookAheadEnd) {
+                    // TODO:  don't change value if already set?
+                    // TODO:  allow for more than one active look-ahead rule in engine.
+                    //        Make value here an index to a side array in engine?
+                    sd->fLookAhead = sd->fAccepting;
+                }
+            }
+        }
+    }
+}
+
+
+//-----------------------------------------------------------------------------
+//
+//    flagLookAheadStates   Very similar to flagAcceptingStates, above.
+//
+//-----------------------------------------------------------------------------
+void     RBBITableBuilder::flagLookAheadStates() {
+    if (U_FAILURE(*fStatus)) {
+        return;
+    }
+    UVector     lookAheadNodes(*fStatus);
+    RBBINode    *lookAheadNode;
+    int32_t     i;
+    int32_t     n;
+
+    fTree->findNodes(&lookAheadNodes, RBBINode::lookAhead, *fStatus);
+    if (U_FAILURE(*fStatus)) {
+        return;
+    }
+    for (i=0; i<lookAheadNodes.size(); i++) {
+        lookAheadNode = (RBBINode *)lookAheadNodes.elementAt(i);
+
+        for (n=0; n<fDStates->size(); n++) {
+            RBBIStateDescriptor *sd = (RBBIStateDescriptor *)fDStates->elementAt(n);
+            if (sd->fPositions->indexOf(lookAheadNode) >= 0) {
+                sd->fLookAhead = lookAheadNode->fVal;
+            }
+        }
+    }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+//
+//    flagTaggedStates
+//
+//-----------------------------------------------------------------------------
+void     RBBITableBuilder::flagTaggedStates() {
+    if (U_FAILURE(*fStatus)) {
+        return;
+    }
+    UVector     tagNodes(*fStatus);
+    RBBINode    *tagNode;
+    int32_t     i;
+    int32_t     n;
+
+    if (U_FAILURE(*fStatus)) {
+        return;
+    }
+    fTree->findNodes(&tagNodes, RBBINode::tag, *fStatus);
+    if (U_FAILURE(*fStatus)) {
+        return;
+    }
+    for (i=0; i<tagNodes.size(); i++) {                   // For each tag node t (all of 'em)
+        tagNode = (RBBINode *)tagNodes.elementAt(i);
+
+        for (n=0; n<fDStates->size(); n++) {              //    For each state  s (row in the state table)
+            RBBIStateDescriptor *sd = (RBBIStateDescriptor *)fDStates->elementAt(n);
+            if (sd->fPositions->indexOf(tagNode) >= 0) {  //       if  s include the tag node t
+                sortedAdd(&sd->fTagVals, tagNode->fVal);
+            }
+        }
+    }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+//
+//  mergeRuleStatusVals
+//
+//      Update the global table of rule status {tag} values
+//      The rule builder has a global vector of status values that are common
+//      for all tables.  Merge the ones from this table into the global set.
+//
+//-----------------------------------------------------------------------------
+void  RBBITableBuilder::mergeRuleStatusVals() {
+    //
+    //  The basic outline of what happens here is this...
+    //
+    //    for each state in this state table
+    //       if the status tag list for this state is in the global statuses list
+    //           record where and
+    //           continue with the next state
+    //       else
+    //           add the tag list for this state to the global list.
+    //
+    int i;
+    int n;
+
+    // Pre-set a single tag of {0} into the table.
+    //   We will need this as a default, for rule sets with no explicit tagging.
+    if (fRB->fRuleStatusVals->size() == 0) {
+        fRB->fRuleStatusVals->addElement(1, *fStatus);  // Num of statuses in group
+        fRB->fRuleStatusVals->addElement((int32_t)0, *fStatus);  //   and our single status of zero
+    }
+
+    //    For each state
+    for (n=0; n<fDStates->size(); n++) {
+        RBBIStateDescriptor *sd = (RBBIStateDescriptor *)fDStates->elementAt(n);
+        UVector *thisStatesTagValues = sd->fTagVals;
+        if (thisStatesTagValues == NULL) {
+            // No tag values are explicitly associated with this state.
+            //   Set the default tag value.
+            sd->fTagsIdx = 0;
+            continue;
+        }
+
+        // There are tag(s) associated with this state.
+        //   fTagsIdx will be the index into the global tag list for this state's tag values.
+        //   Initial value of -1 flags that we haven't got it set yet.
+        sd->fTagsIdx = -1;
+        int32_t  thisTagGroupStart = 0;   // indexes into the global rule status vals list
+        int32_t  nextTagGroupStart = 0;
+
+        // Loop runs once per group of tags in the global list
+        while (nextTagGroupStart < fRB->fRuleStatusVals->size()) {
+            thisTagGroupStart = nextTagGroupStart;
+            nextTagGroupStart += fRB->fRuleStatusVals->elementAti(thisTagGroupStart) + 1;
+            if (thisStatesTagValues->size() != fRB->fRuleStatusVals->elementAti(thisTagGroupStart)) {
+                // The number of tags for this state is different from
+                //    the number of tags in this group from the global list.
+                //    Continue with the next group from the global list.
+                continue;
+            }
+            // The lengths match, go ahead and compare the actual tag values
+            //    between this state and the group from the global list.
+            for (i=0; i<thisStatesTagValues->size(); i++) {
+                if (thisStatesTagValues->elementAti(i) !=
+                    fRB->fRuleStatusVals->elementAti(thisTagGroupStart + 1 + i) ) {
+                    // Mismatch.
+                    break;
+                }
+            }
+
+            if (i == thisStatesTagValues->size()) {
+                // We found a set of tag values in the global list that match
+                //   those for this state.  Use them.
+                sd->fTagsIdx = thisTagGroupStart;
+                break;
+            }
+        }
+
+        if (sd->fTagsIdx == -1) {
+            // No suitable entry in the global tag list already.  Add one
+            sd->fTagsIdx = fRB->fRuleStatusVals->size();
+            fRB->fRuleStatusVals->addElement(thisStatesTagValues->size(), *fStatus);
+            for (i=0; i<thisStatesTagValues->size(); i++) {
+                fRB->fRuleStatusVals->addElement(thisStatesTagValues->elementAti(i), *fStatus);
+            }
+        }
+    }
+}
+
+
+
+
+
+
+
+//-----------------------------------------------------------------------------
+//
+//  sortedAdd  Add a value to a vector of sorted values (ints).
+//             Do not replicate entries; if the value is already there, do not
+//                add a second one.
+//             Lazily create the vector if it does not already exist.
+//
+//-----------------------------------------------------------------------------
+void RBBITableBuilder::sortedAdd(UVector **vector, int32_t val) {
+    int32_t i;
+
+    if (*vector == NULL) {
+        *vector = new UVector(*fStatus);
+    }
+    if (*vector == NULL || U_FAILURE(*fStatus)) {
+        return;
+    }
+    UVector *vec = *vector;
+    int32_t  vSize = vec->size();
+    for (i=0; i<vSize; i++) {
+        int32_t valAtI = vec->elementAti(i);
+        if (valAtI == val) {
+            // The value is already in the vector.  Don't add it again.
+            return;
+        }
+        if (valAtI > val) {
+            break;
+        }
+    }
+    vec->insertElementAt(val, i, *fStatus);
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+//  setAdd     Set operation on UVector
+//             dest = dest union source
+//             Elements may only appear once and must be sorted.
+//
+//-----------------------------------------------------------------------------
+void RBBITableBuilder::setAdd(UVector *dest, UVector *source) {
+    int32_t destOriginalSize = dest->size();
+    int32_t sourceSize       = source->size();
+    int32_t di           = 0;
+    MaybeStackArray<void *, 16> destArray, sourceArray;  // Handle small cases without malloc
+    void **destPtr, **sourcePtr;
+    void **destLim, **sourceLim;
+
+    if (destOriginalSize > destArray.getCapacity()) {
+        if (destArray.resize(destOriginalSize) == NULL) {
+            return;
+        }
+    }
+    destPtr = destArray.getAlias();
+    destLim = destPtr + destOriginalSize;  // destArray.getArrayLimit()?
+
+    if (sourceSize > sourceArray.getCapacity()) {
+        if (sourceArray.resize(sourceSize) == NULL) {
+            return;
+        }
+    }
+    sourcePtr = sourceArray.getAlias();
+    sourceLim = sourcePtr + sourceSize;  // sourceArray.getArrayLimit()?
+
+    // Avoid multiple "get element" calls by getting the contents into arrays
+    (void) dest->toArray(destPtr);
+    (void) source->toArray(sourcePtr);
+
+    dest->setSize(sourceSize+destOriginalSize, *fStatus);
+
+    while (sourcePtr < sourceLim && destPtr < destLim) {
+        if (*destPtr == *sourcePtr) {
+            dest->setElementAt(*sourcePtr++, di++);
+            destPtr++;
+        }
+        // This check is required for machines with segmented memory, like i5/OS.
+        // Direct pointer comparison is not recommended.
+        else if (uprv_memcmp(destPtr, sourcePtr, sizeof(void *)) < 0) {
+            dest->setElementAt(*destPtr++, di++);
+        }
+        else { /* *sourcePtr < *destPtr */
+            dest->setElementAt(*sourcePtr++, di++);
+        }
+    }
+
+    // At most one of these two cleanup loops will execute
+    while (destPtr < destLim) {
+        dest->setElementAt(*destPtr++, di++);
+    }
+    while (sourcePtr < sourceLim) {
+        dest->setElementAt(*sourcePtr++, di++);
+    }
+
+    dest->setSize(di, *fStatus);
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+//  setEqual    Set operation on UVector.
+//              Compare for equality.
+//              Elements must be sorted.
+//
+//-----------------------------------------------------------------------------
+UBool RBBITableBuilder::setEquals(UVector *a, UVector *b) {
+    return a->equals(*b);
+}
+
+
+//-----------------------------------------------------------------------------
+//
+//  printPosSets   Debug function.  Dump Nullable, firstpos, lastpos and followpos
+//                 for each node in the tree.
+//
+//-----------------------------------------------------------------------------
+#ifdef RBBI_DEBUG
+void RBBITableBuilder::printPosSets(RBBINode *n) {
+    if (n==NULL) {
+        return;
+    }
+    n->printNode();
+    RBBIDebugPrintf("         Nullable:  %s\n", n->fNullable?"TRUE":"FALSE");
+
+    RBBIDebugPrintf("         firstpos:  ");
+    printSet(n->fFirstPosSet);
+
+    RBBIDebugPrintf("         lastpos:   ");
+    printSet(n->fLastPosSet);
+
+    RBBIDebugPrintf("         followpos: ");
+    printSet(n->fFollowPos);
+
+    printPosSets(n->fLeftChild);
+    printPosSets(n->fRightChild);
+}
+#endif
+
+
+
+//-----------------------------------------------------------------------------
+//
+//   getTableSize()    Calculate the size of the runtime form of this
+//                     state transition table.
+//
+//-----------------------------------------------------------------------------
+int32_t  RBBITableBuilder::getTableSize() const {
+    int32_t    size = 0;
+    int32_t    numRows;
+    int32_t    numCols;
+    int32_t    rowSize;
+
+    if (fTree == NULL) {
+        return 0;
+    }
+
+    size    = sizeof(RBBIStateTable) - 4;    // The header, with no rows to the table.
+
+    numRows = fDStates->size();
+    numCols = fRB->fSetBuilder->getNumCharCategories();
+
+    //  Note  The declaration of RBBIStateTableRow is for a table of two columns.
+    //        Therefore we subtract two from numCols when determining
+    //        how much storage to add to a row for the total columns.
+    rowSize = sizeof(RBBIStateTableRow) + sizeof(uint16_t)*(numCols-2);
+    size   += numRows * rowSize;
+    return size;
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+//   exportTable()    export the state transition table in the format required
+//                    by the runtime engine.  getTableSize() bytes of memory
+//                    must be available at the output address "where".
+//
+//-----------------------------------------------------------------------------
+void RBBITableBuilder::exportTable(void *where) {
+    RBBIStateTable    *table = (RBBIStateTable *)where;
+    uint32_t           state;
+    int                col;
+
+    if (U_FAILURE(*fStatus) || fTree == NULL) {
+        return;
+    }
+
+    if (fRB->fSetBuilder->getNumCharCategories() > 0x7fff ||
+        fDStates->size() > 0x7fff) {
+        *fStatus = U_BRK_INTERNAL_ERROR;
+        return;
+    }
+
+    table->fRowLen    = sizeof(RBBIStateTableRow) +
+                            sizeof(uint16_t) * (fRB->fSetBuilder->getNumCharCategories() - 2);
+    table->fNumStates = fDStates->size();
+    table->fFlags     = 0;
+    if (fRB->fLookAheadHardBreak) {
+        table->fFlags  |= RBBI_LOOKAHEAD_HARD_BREAK;
+    }
+    if (fRB->fSetBuilder->sawBOF()) {
+        table->fFlags  |= RBBI_BOF_REQUIRED;
+    }
+    table->fReserved  = 0;
+
+    for (state=0; state<table->fNumStates; state++) {
+        RBBIStateDescriptor *sd = (RBBIStateDescriptor *)fDStates->elementAt(state);
+        RBBIStateTableRow   *row = (RBBIStateTableRow *)(table->fTableData + state*table->fRowLen);
+        U_ASSERT (-32768 < sd->fAccepting && sd->fAccepting <= 32767);
+        U_ASSERT (-32768 < sd->fLookAhead && sd->fLookAhead <= 32767);
+        row->fAccepting = (int16_t)sd->fAccepting;
+        row->fLookAhead = (int16_t)sd->fLookAhead;
+        row->fTagIdx    = (int16_t)sd->fTagsIdx;
+        for (col=0; col<fRB->fSetBuilder->getNumCharCategories(); col++) {
+            row->fNextState[col] = (uint16_t)sd->fDtran->elementAti(col);
+        }
+    }
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+//   printSet    Debug function.   Print the contents of a UVector
+//
+//-----------------------------------------------------------------------------
+#ifdef RBBI_DEBUG
+void RBBITableBuilder::printSet(UVector *s) {
+    int32_t  i;
+    for (i=0; i<s->size(); i++) {
+        void *v = s->elementAt(i);
+        RBBIDebugPrintf("%10p", v);
+    }
+    RBBIDebugPrintf("\n");
+}
+#endif
+
+
+//-----------------------------------------------------------------------------
+//
+//   printStates    Debug Function.  Dump the fully constructed state transition table.
+//
+//-----------------------------------------------------------------------------
+#ifdef RBBI_DEBUG
+void RBBITableBuilder::printStates() {
+    int     c;    // input "character"
+    int     n;    // state number
+
+    RBBIDebugPrintf("state |           i n p u t     s y m b o l s \n");
+    RBBIDebugPrintf("      | Acc  LA    Tag");
+    for (c=0; c<fRB->fSetBuilder->getNumCharCategories(); c++) {
+        RBBIDebugPrintf(" %2d", c);
+    }
+    RBBIDebugPrintf("\n");
+    RBBIDebugPrintf("      |---------------");
+    for (c=0; c<fRB->fSetBuilder->getNumCharCategories(); c++) {
+        RBBIDebugPrintf("---");
+    }
+    RBBIDebugPrintf("\n");
+
+    for (n=0; n<fDStates->size(); n++) {
+        RBBIStateDescriptor *sd = (RBBIStateDescriptor *)fDStates->elementAt(n);
+        RBBIDebugPrintf("  %3d | " , n);
+        RBBIDebugPrintf("%3d %3d %5d ", sd->fAccepting, sd->fLookAhead, sd->fTagsIdx);
+        for (c=0; c<fRB->fSetBuilder->getNumCharCategories(); c++) {
+            RBBIDebugPrintf(" %2d", sd->fDtran->elementAti(c));
+        }
+        RBBIDebugPrintf("\n");
+    }
+    RBBIDebugPrintf("\n\n");
+}
+#endif
+
+
+
+//-----------------------------------------------------------------------------
+//
+//   printRuleStatusTable    Debug Function.  Dump the common rule status table
+//
+//-----------------------------------------------------------------------------
+#ifdef RBBI_DEBUG
+void RBBITableBuilder::printRuleStatusTable() {
+    int32_t  thisRecord = 0;
+    int32_t  nextRecord = 0;
+    int      i;
+    UVector  *tbl = fRB->fRuleStatusVals;
+
+    RBBIDebugPrintf("index |  tags \n");
+    RBBIDebugPrintf("-------------------\n");
+
+    while (nextRecord < tbl->size()) {
+        thisRecord = nextRecord;
+        nextRecord = thisRecord + tbl->elementAti(thisRecord) + 1;
+        RBBIDebugPrintf("%4d   ", thisRecord);
+        for (i=thisRecord+1; i<nextRecord; i++) {
+            RBBIDebugPrintf("  %5d", tbl->elementAti(i));
+        }
+        RBBIDebugPrintf("\n");
+    }
+    RBBIDebugPrintf("\n\n");
+}
+#endif
+
+
+//-----------------------------------------------------------------------------
+//
+//   RBBIStateDescriptor     Methods.  This is a very struct-like class
+//                           Most access is directly to the fields.
+//
+//-----------------------------------------------------------------------------
+
+RBBIStateDescriptor::RBBIStateDescriptor(int lastInputSymbol, UErrorCode *fStatus) {
+    fMarked    = FALSE;
+    fAccepting = 0;
+    fLookAhead = 0;
+    fTagsIdx   = 0;
+    fTagVals   = NULL;
+    fPositions = NULL;
+    fDtran     = NULL;
+
+    fDtran     = new UVector(lastInputSymbol+1, *fStatus);
+    if (U_FAILURE(*fStatus)) {
+        return;
+    }
+    if (fDtran == NULL) {
+        *fStatus = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    fDtran->setSize(lastInputSymbol+1, *fStatus);    // fDtran needs to be pre-sized.
+                                           //   It is indexed by input symbols, and will
+                                           //   hold  the next state number for each
+                                           //   symbol.
+}
+
+
+RBBIStateDescriptor::~RBBIStateDescriptor() {
+    delete       fPositions;
+    delete       fDtran;
+    delete       fTagVals;
+    fPositions = NULL;
+    fDtran     = NULL;
+    fTagVals   = NULL;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
diff --git a/source/common/rbbitblb.h b/source/common/rbbitblb.h
new file mode 100644
index 0000000..3805b67
--- /dev/null
+++ b/source/common/rbbitblb.h
@@ -0,0 +1,127 @@
+//
+//  rbbitblb.h
+//
+
+/*
+**********************************************************************
+*   Copyright (c) 2002-2005, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+
+#ifndef RBBITBLB_H
+#define RBBITBLB_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/rbbi.h"
+#include "rbbinode.h"
+
+
+U_NAMESPACE_BEGIN
+
+class RBBIRuleScanner;
+class RBBIRuleBuilder;
+
+//
+//  class RBBITableBuilder is part of the RBBI rule compiler.
+//                         It builds the state transition table used by the RBBI runtime
+//                         from the expression syntax tree generated by the rule scanner.
+//
+//                         This class is part of the RBBI implementation only.
+//                         There is no user-visible public API here.
+//
+
+class RBBITableBuilder : public UMemory {
+public:
+    RBBITableBuilder(RBBIRuleBuilder *rb, RBBINode **rootNode);
+    ~RBBITableBuilder();
+
+    void     build();
+    int32_t  getTableSize() const;      // Return the runtime size in bytes of
+                                        //     the built state table
+    void     exportTable(void *where);  // fill in the runtime state table.
+                                        //     Sufficient memory must exist at
+                                        //     the specified location.
+
+
+private:
+    void     calcNullable(RBBINode *n);
+    void     calcFirstPos(RBBINode *n);
+    void     calcLastPos(RBBINode  *n);
+    void     calcFollowPos(RBBINode *n);
+    void     calcChainedFollowPos(RBBINode *n);
+    void     bofFixup();
+    void     buildStateTable();
+    void     flagAcceptingStates();
+    void     flagLookAheadStates();
+    void     flagTaggedStates();
+    void     mergeRuleStatusVals();
+
+    // Set functions for UVector.
+    //   TODO:  make a USet subclass of UVector
+
+    void     setAdd(UVector *dest, UVector *source);
+    UBool    setEquals(UVector *a, UVector *b);
+
+    void     sortedAdd(UVector **dest, int32_t val);
+
+public:
+#ifdef RBBI_DEBUG
+    void     printSet(UVector *s);
+    void     printPosSets(RBBINode *n /* = NULL*/);
+    void     printStates();
+    void     printRuleStatusTable();
+#else
+    #define  printSet(s)
+    #define  printPosSets(n)
+    #define  printStates()
+    #define  printRuleStatusTable()
+#endif
+
+private:
+    RBBIRuleBuilder  *fRB;
+    RBBINode         *&fTree;              // The root node of the parse tree to build a
+                                           //   table for.
+    UErrorCode       *fStatus;
+
+    UVector          *fDStates;            //  D states (Aho's terminology)
+                                           //  Index is state number
+                                           //  Contents are RBBIStateDescriptor pointers.
+
+
+    RBBITableBuilder(const RBBITableBuilder &other); // forbid copying of this class
+    RBBITableBuilder &operator=(const RBBITableBuilder &other); // forbid copying of this class
+};
+
+//
+//  RBBIStateDescriptor - The DFA is constructed as a set of these descriptors,
+//                        one for each state.
+class RBBIStateDescriptor : public UMemory {
+public:
+    UBool            fMarked;
+    int32_t          fAccepting;
+    int32_t          fLookAhead;
+    UVector          *fTagVals;
+    int32_t          fTagsIdx;
+    UVector          *fPositions;          // Set of parse tree positions associated
+                                           //   with this state.  Unordered (it's a set).
+                                           //   UVector contents are RBBINode *
+
+    UVector          *fDtran;              // Transitions out of this state.
+                                           //   indexed by input character
+                                           //   contents is int index of dest state
+                                           //   in RBBITableBuilder.fDStates
+
+    RBBIStateDescriptor(int maxInputSymbol,  UErrorCode *fStatus);
+    ~RBBIStateDescriptor();
+
+private:
+    RBBIStateDescriptor(const RBBIStateDescriptor &other); // forbid copying of this class
+    RBBIStateDescriptor &operator=(const RBBIStateDescriptor &other); // forbid copying of this class
+};
+
+
+
+U_NAMESPACE_END
+#endif
diff --git a/source/common/resbund.cpp b/source/common/resbund.cpp
new file mode 100644
index 0000000..e1a58d2
--- /dev/null
+++ b/source/common/resbund.cpp
@@ -0,0 +1,400 @@
+/*
+**********************************************************************
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*
+* File resbund.cpp
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   02/05/97    aliu        Fixed bug in chopLocale.  Added scanForLocaleInFile
+*                           based on code taken from scanForLocale.  Added
+*                           constructor which attempts to read resource bundle
+*                           from a specific file, without searching other files.
+*   02/11/97    aliu        Added UErrorCode return values to constructors. Fixed
+*                           infinite loops in scanForFile and scanForLocale.
+*                           Modified getRawResourceData to not delete storage in
+*                           localeData and resourceData which it doesn't own.
+*                           Added Mac compatibility #ifdefs for tellp() and
+*                           ios::nocreate.
+*   03/04/97    aliu        Modified to use ExpandingDataSink objects instead of
+*                           the highly inefficient ostrstream objects.
+*   03/13/97    aliu        Rewrote to load in entire resource bundle and store
+*                           it as a Hashtable of ResourceBundleData objects.
+*                           Added state table to govern parsing of files.
+*                           Modified to load locale index out of new file distinct
+*                           from default.txt.
+*   03/25/97    aliu        Modified to support 2-d arrays, needed for timezone data.
+*                           Added support for custom file suffixes.  Again, needed
+*                           to support timezone data.  Improved error handling to
+*                           detect duplicate tags and subtags.
+*   04/07/97    aliu        Fixed bug in getHashtableForLocale().  Fixed handling
+*                           of failing UErrorCode values on entry to API methods.
+*                           Fixed bugs in getArrayItem() for negative indices.
+*   04/29/97    aliu        Update to use new Hashtable deletion protocol.
+*   05/06/97    aliu        Flattened kTransitionTable for HP compiler.
+*                           Fixed usage of CharString.
+* 06/11/99      stephen     Removed parsing of .txt files.
+*                           Reworked to use new binary format.
+*                           Cleaned up.
+* 06/14/99      stephen     Removed methods taking a filename suffix.
+* 06/22/99      stephen     Added missing T_FileStream_close in parse()
+* 11/09/99      weiv        Added getLocale(), rewritten constructForLocale()
+* March 2000    weiv        complete overhaul.
+******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/resbund.h"
+#include "umutex.h"
+
+#include "uresimp.h"
+
+U_NAMESPACE_BEGIN
+
+/*-----------------------------------------------------------------------------
+ * Implementation Notes
+ *
+ * Resource bundles are read in once, and thereafter cached.
+ * ResourceBundle statically keeps track of which files have been
+ * read, so we are guaranteed that each file is read at most once.
+ * Resource bundles can be loaded from different data directories and
+ * will be treated as distinct, even if they are for the same locale.
+ *
+ * Resource bundles are lightweight objects, which have pointers to
+ * one or more shared Hashtable objects containing all the data.
+ * Copying would be cheap, but there is no copy constructor, since
+ * there wasn't one in the original API.
+ *
+ * The ResourceBundle parsing mechanism is implemented as a transition
+ * network, for easy maintenance and modification.  The network is
+ * implemented as a matrix (instead of in code) to make this even
+ * easier.  The matrix contains Transition objects.  Each Transition
+ * object describes a destination node and an action to take before
+ * moving to the destination node.  The source node is encoded by the
+ * index of the object in the array that contains it.  The pieces
+ * needed to understand the transition network are the enums for node
+ * IDs and actions, the parse() method, which walks through the
+ * network and implements the actions, and the network itself.  The
+ * network guarantees certain conditions, for example, that a new
+ * resource will not be closed until one has been opened first; or
+ * that data will not be stored into a TaggedList until a TaggedList
+ * has been created.  Nonetheless, the code in parse() does some
+ * consistency checks as it runs the network, and fails with an
+ * U_INTERNAL_PROGRAM_ERROR if one of these checks fails.  If the input
+ * data has a bad format, an U_INVALID_FORMAT_ERROR is returned.  If you
+ * see an U_INTERNAL_PROGRAM_ERROR the transition matrix has a bug in
+ * it.
+ *
+ * Old functionality of multiple locales in a single file is still
+ * supported.  For this reason, LOCALE names override FILE names.  If
+ * data for en_US is located in the en.txt file, once it is loaded,
+ * the code will not care where it came from (other than remembering
+ * which directory it came from).  However, if there is an en_US
+ * resource in en_US.txt, that will take precedence.  There is no
+ * limit to the number or type of resources that can be stored in a
+ * file, however, files are only searched in a specific way.  If
+ * en_US_CA is requested, then first en_US_CA.txt is searched, then
+ * en_US.txt, then en.txt, then default.txt.  So it only makes sense
+ * to put certain locales in certain files.  In this example, it would
+ * be logical to put en_US_CA, en_US, and en into the en.txt file,
+ * since they would be found there if asked for.  The extreme example
+ * is to place all locale resources into default.txt, which should
+ * also work.
+ *
+ * Inheritance is implemented.  For example, xx_YY_zz inherits as
+ * follows: xx_YY_zz, xx_YY, xx, default.  Inheritance is implemented
+ * as an array of hashtables.  There will be from 1 to 4 hashtables in
+ * the array.
+ *
+ * Fallback files are implemented.  The fallback pattern is Language
+ * Country Variant (LCV) -> LC -> L.  Fallback is first done for the
+ * requested locale.  Then it is done for the default locale, as
+ * returned by Locale::getDefault().  Then the special file
+ * default.txt is searched for the default locale.  The overall FILE
+ * fallback path is LCV -> LC -> L -> dLCV -> dLC -> dL -> default.
+ *
+ * Note that although file name searching includes the default locale,
+ * once a ResourceBundle object is constructed, the inheritance path
+ * no longer includes the default locale.  The path is LCV -> LC -> L
+ * -> default.
+ *
+ * File parsing is lazy.  Nothing is parsed unless it is called for by
+ * someone.  So when a ResourceBundle for xx_YY_zz is constructed,
+ * only that locale is parsed (along with anything else in the same
+ * file).  Later, if the FooBar tag is asked for, and if it isn't
+ * found in xx_YY_zz, then xx_YY.txt will be parsed and checked, and
+ * so forth, until the chain is exhausted or the tag is found.
+ *
+ * Thread-safety is implemented around caches, both the cache that
+ * stores all the resouce data, and the cache that stores flags
+ * indicating whether or not a file has been visited.  These caches
+ * delete their storage at static cleanup time, when the process
+ * quits.
+ *
+ * ResourceBundle supports TableCollation as a special case.  This
+ * involves having special ResourceBundle objects which DO own their
+ * data, since we don't want large collation rule strings in the
+ * ResourceBundle cache (these are already cached in the
+ * TableCollation cache).  TableCollation files (.ctx files) have the
+ * same format as normal resource data files, with a different
+ * interpretation, from the standpoint of ResourceBundle.  .ctx files
+ * are loaded into otherwise ordinary ResourceBundle objects.  They
+ * don't inherit (that's implemented by TableCollation) and they own
+ * their data (as mentioned above).  However, they still support
+ * possible multiple locales in a single .ctx file.  (This is in
+ * practice a bad idea, since you only want the one locale you're
+ * looking for, and only one tag will be present
+ * ("CollationElements"), so you don't need an inheritance chain of
+ * multiple locales.)  Up to 4 locale resources will be loaded from a
+ * .ctx file; everything after the first 4 is ignored (parsed and
+ * deleted).  (Normal .txt files have no limit.)  Instead of being
+ * loaded into the cache, and then looked up as needed, the locale
+ * resources are read straight into the ResourceBundle object.
+ *
+ * The Index, which used to reside in default.txt, has been moved to a
+ * new file, index.txt.  This file contains a slightly modified format
+ * with the addition of the "InstalledLocales" tag; it looks like:
+ *
+ * Index {
+ *   InstalledLocales {
+ *     ar
+ *     ..
+ *     zh_TW
+ *   }
+ * }
+ */
+//-----------------------------------------------------------------------------
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ResourceBundle)
+
+ResourceBundle::ResourceBundle(UErrorCode &err)
+                                :UObject(), fLocale(NULL)
+{
+    fResource = ures_open(0, Locale::getDefault().getName(), &err);
+}
+
+ResourceBundle::ResourceBundle(const ResourceBundle &other)
+                              :UObject(other), fLocale(NULL)
+{
+    UErrorCode status = U_ZERO_ERROR;
+
+    if (other.fResource) {
+        fResource = ures_copyResb(0, other.fResource, &status);
+    } else {
+        /* Copying a bad resource bundle */
+        fResource = NULL;
+    }
+}
+
+ResourceBundle::ResourceBundle(UResourceBundle *res, UErrorCode& err)
+                               :UObject(), fLocale(NULL)
+{
+    if (res) {
+        fResource = ures_copyResb(0, res, &err);
+    } else {
+        /* Copying a bad resource bundle */
+        fResource = NULL;
+    }
+}
+
+ResourceBundle::ResourceBundle(const char* path, const Locale& locale, UErrorCode& err) 
+                               :UObject(), fLocale(NULL)
+{
+    fResource = ures_open(path, locale.getName(), &err);
+}
+
+
+ResourceBundle& ResourceBundle::operator=(const ResourceBundle& other)
+{
+    if(this == &other) {
+        return *this;
+    }
+    if(fResource != 0) {
+        ures_close(fResource);
+        fResource = NULL;
+    }
+    UErrorCode status = U_ZERO_ERROR;
+    if (other.fResource) {
+        fResource = ures_copyResb(0, other.fResource, &status);
+    } else {
+        /* Copying a bad resource bundle */
+        fResource = NULL;
+    }
+    return *this;
+}
+
+ResourceBundle::~ResourceBundle()
+{
+    if(fResource != 0) {
+        ures_close(fResource);
+    }
+    if(fLocale != NULL) {
+      delete(fLocale);
+    }
+}
+
+ResourceBundle *
+ResourceBundle::clone() const {
+    return new ResourceBundle(*this);
+}
+
+UnicodeString ResourceBundle::getString(UErrorCode& status) const {
+    int32_t len = 0;
+    const UChar *r = ures_getString(fResource, &len, &status);
+    return UnicodeString(TRUE, r, len);
+}
+
+const uint8_t *ResourceBundle::getBinary(int32_t& len, UErrorCode& status) const {
+    return ures_getBinary(fResource, &len, &status);
+}
+
+const int32_t *ResourceBundle::getIntVector(int32_t& len, UErrorCode& status) const {
+    return ures_getIntVector(fResource, &len, &status);
+}
+
+uint32_t ResourceBundle::getUInt(UErrorCode& status) const {
+    return ures_getUInt(fResource, &status);
+}
+
+int32_t ResourceBundle::getInt(UErrorCode& status) const {
+    return ures_getInt(fResource, &status);
+}
+
+const char *ResourceBundle::getName(void) const {
+    return ures_getName(fResource);
+}
+
+const char *ResourceBundle::getKey(void) const {
+    return ures_getKey(fResource);
+}
+
+UResType ResourceBundle::getType(void) const {
+    return ures_getType(fResource);
+}
+
+int32_t ResourceBundle::getSize(void) const {
+    return ures_getSize(fResource);
+}
+
+UBool ResourceBundle::hasNext(void) const {
+    return ures_hasNext(fResource);
+}
+
+void ResourceBundle::resetIterator(void) {
+    ures_resetIterator(fResource);
+}
+
+ResourceBundle ResourceBundle::getNext(UErrorCode& status) {
+    UResourceBundle r;
+
+    ures_initStackObject(&r);
+    ures_getNextResource(fResource, &r, &status);
+    ResourceBundle res(&r, status);
+    if (U_SUCCESS(status)) {
+        ures_close(&r);
+    }
+    return res;
+}
+
+UnicodeString ResourceBundle::getNextString(UErrorCode& status) {
+    int32_t len = 0;
+    const UChar* r = ures_getNextString(fResource, &len, 0, &status);
+    return UnicodeString(TRUE, r, len);
+}
+
+UnicodeString ResourceBundle::getNextString(const char ** key, UErrorCode& status) {
+    int32_t len = 0;
+    const UChar* r = ures_getNextString(fResource, &len, key, &status);
+    return UnicodeString(TRUE, r, len);
+}
+
+ResourceBundle ResourceBundle::get(int32_t indexR, UErrorCode& status) const {
+    UResourceBundle r;
+
+    ures_initStackObject(&r);
+    ures_getByIndex(fResource, indexR, &r, &status);
+    ResourceBundle res(&r, status);
+    if (U_SUCCESS(status)) {
+        ures_close(&r);
+    }
+    return res;
+}
+
+UnicodeString ResourceBundle::getStringEx(int32_t indexS, UErrorCode& status) const {
+    int32_t len = 0;
+    const UChar* r = ures_getStringByIndex(fResource, indexS, &len, &status);
+    return UnicodeString(TRUE, r, len);
+}
+
+ResourceBundle ResourceBundle::get(const char* key, UErrorCode& status) const {
+    UResourceBundle r;
+
+    ures_initStackObject(&r);
+    ures_getByKey(fResource, key, &r, &status);
+    ResourceBundle res(&r, status);
+    if (U_SUCCESS(status)) {
+        ures_close(&r);
+    }
+    return res;
+}
+
+ResourceBundle ResourceBundle::getWithFallback(const char* key, UErrorCode& status){
+    UResourceBundle r;
+    ures_initStackObject(&r);
+    ures_getByKeyWithFallback(fResource, key, &r, &status);
+    ResourceBundle res(&r, status);
+    if(U_SUCCESS(status)){
+        ures_close(&r);
+    }
+    return res;
+}
+UnicodeString ResourceBundle::getStringEx(const char* key, UErrorCode& status) const {
+    int32_t len = 0;
+    const UChar* r = ures_getStringByKey(fResource, key, &len, &status);
+    return UnicodeString(TRUE, r, len);
+}
+
+const char*
+ResourceBundle::getVersionNumber()  const
+{
+    return ures_getVersionNumberInternal(fResource);
+}
+
+void ResourceBundle::getVersion(UVersionInfo versionInfo) const {
+    ures_getVersion(fResource, versionInfo);
+}
+
+const Locale &ResourceBundle::getLocale(void) const
+{
+    UBool needInit;
+    UMTX_CHECK(NULL, (fLocale == NULL), needInit);
+    if(needInit) {
+        UErrorCode status = U_ZERO_ERROR;
+        const char *localeName = ures_getLocaleInternal(fResource, &status);
+        Locale  *tLocale = new Locale(localeName);
+        // Null pointer check
+        if (tLocale == NULL) {
+        	return Locale::getDefault(); // Return default locale if one could not be created.
+        }
+        umtx_lock(NULL);
+        ResourceBundle *me = (ResourceBundle *)this; // semantically const
+        if (me->fLocale == NULL) {
+            me->fLocale = tLocale;
+            tLocale = NULL;
+        }
+        umtx_unlock(NULL);
+        delete tLocale;
+    }
+    return *fLocale;
+}
+
+const Locale ResourceBundle::getLocale(ULocDataLocaleType type, UErrorCode &status) const
+{
+  return ures_getLocaleByType(fResource, type, &status);
+}
+
+//eof
+U_NAMESPACE_END
diff --git a/source/common/resbund_cnv.cpp b/source/common/resbund_cnv.cpp
new file mode 100644
index 0000000..a18e57e
--- /dev/null
+++ b/source/common/resbund_cnv.cpp
@@ -0,0 +1,55 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1997-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  resbund_cnv.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2004aug25
+*   created by: Markus W. Scherer
+*
+*   Character conversion functions moved here from resbund.cpp
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/resbund.h"
+#include "uinvchar.h"
+
+U_NAMESPACE_BEGIN
+
+ResourceBundle::ResourceBundle( const UnicodeString&    path,
+                                const Locale&           locale,
+                                UErrorCode&              error)
+                                :UObject(), fLocale(NULL)
+{
+    constructForLocale(path, locale, error);
+}
+
+ResourceBundle::ResourceBundle( const UnicodeString&    path,
+                                UErrorCode&              error)
+                                :UObject(), fLocale(NULL)
+{
+    constructForLocale(path, Locale::getDefault(), error);
+}
+
+void 
+ResourceBundle::constructForLocale(const UnicodeString& path,
+                                   const Locale& locale,
+                                   UErrorCode& error)
+{
+    if (path.isEmpty()) {
+        fResource = ures_open(NULL, locale.getName(), &error);
+    }
+    else {
+        UnicodeString nullTerminatedPath(path);
+        nullTerminatedPath.append((UChar)0);
+        fResource = ures_openU(nullTerminatedPath.getBuffer(), locale.getName(), &error);
+    }
+}
+
+U_NAMESPACE_END
diff --git a/source/common/ruleiter.cpp b/source/common/ruleiter.cpp
new file mode 100644
index 0000000..b99a831
--- /dev/null
+++ b/source/common/ruleiter.cpp
@@ -0,0 +1,160 @@
+/*
+**********************************************************************
+* Copyright (c) 2003-2007, International Business Machines
+* Corporation and others.  All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: September 24 2003
+* Since: ICU 2.8
+**********************************************************************
+*/
+#include "ruleiter.h"
+#include "unicode/parsepos.h"
+#include "unicode/unistr.h"
+#include "unicode/symtable.h"
+#include "util.h"
+
+/* \U87654321 or \ud800\udc00 */
+#define MAX_U_NOTATION_LEN 12
+
+U_NAMESPACE_BEGIN
+
+RuleCharacterIterator::RuleCharacterIterator(const UnicodeString& theText, const SymbolTable* theSym,
+                      ParsePosition& thePos) :
+    text(theText),
+    pos(thePos),
+    sym(theSym),
+    buf(0),
+    bufPos(0)
+{}
+
+UBool RuleCharacterIterator::atEnd() const {
+    return buf == 0 && pos.getIndex() == text.length();
+}
+
+UChar32 RuleCharacterIterator::next(int32_t options, UBool& isEscaped, UErrorCode& ec) {
+    if (U_FAILURE(ec)) return DONE;
+
+    UChar32 c = DONE;
+    isEscaped = FALSE;
+
+    for (;;) {
+        c = _current();
+        _advance(UTF_CHAR_LENGTH(c));
+
+        if (c == SymbolTable::SYMBOL_REF && buf == 0 &&
+            (options & PARSE_VARIABLES) != 0 && sym != 0) {
+            UnicodeString name = sym->parseReference(text, pos, text.length());
+            // If name is empty there was an isolated SYMBOL_REF;
+            // return it.  Caller must be prepared for this.
+            if (name.length() == 0) {
+                break;
+            }
+            bufPos = 0;
+            buf = sym->lookup(name);
+            if (buf == 0) {
+                ec = U_UNDEFINED_VARIABLE;
+                return DONE;
+            }
+            // Handle empty variable value
+            if (buf->length() == 0) {
+                buf = 0;
+            }
+            continue;
+        }
+
+        if ((options & SKIP_WHITESPACE) != 0 &&
+            uprv_isRuleWhiteSpace(c)) {
+            continue;
+        }
+
+        if (c == 0x5C /*'\\'*/ && (options & PARSE_ESCAPES) != 0) {
+            UnicodeString tempEscape;
+            int32_t offset = 0;
+            c = lookahead(tempEscape, MAX_U_NOTATION_LEN).unescapeAt(offset);
+            jumpahead(offset);
+            isEscaped = TRUE;
+            if (c < 0) {
+                ec = U_MALFORMED_UNICODE_ESCAPE;
+                return DONE;
+            }
+        }
+
+        break;
+    }
+
+    return c;
+}
+
+void RuleCharacterIterator::getPos(RuleCharacterIterator::Pos& p) const {
+    p.buf = buf;
+    p.pos = pos.getIndex();
+    p.bufPos = bufPos;
+}
+
+void RuleCharacterIterator::setPos(const RuleCharacterIterator::Pos& p) {
+    buf = p.buf;
+    pos.setIndex(p.pos);
+    bufPos = p.bufPos;
+}
+
+void RuleCharacterIterator::skipIgnored(int32_t options) {
+    if ((options & SKIP_WHITESPACE) != 0) {
+        for (;;) {
+            UChar32 a = _current();
+            if (!uprv_isRuleWhiteSpace(a)) break;
+            _advance(UTF_CHAR_LENGTH(a));
+        }
+    }
+}
+
+UnicodeString& RuleCharacterIterator::lookahead(UnicodeString& result, int32_t maxLookAhead) const {
+    if (maxLookAhead < 0) {
+        maxLookAhead = 0x7FFFFFFF;
+    }
+    if (buf != 0) {
+        buf->extract(bufPos, maxLookAhead, result);
+    } else {
+        text.extract(pos.getIndex(), maxLookAhead, result);
+    }
+    return result;
+}
+
+void RuleCharacterIterator::jumpahead(int32_t count) {
+    _advance(count);
+}
+
+/*
+UnicodeString& RuleCharacterIterator::toString(UnicodeString& result) const {
+    int32_t b = pos.getIndex();
+    text.extract(0, b, result);
+    return result.append((UChar) 0x7C).append(text, b, 0x7FFFFFFF); // Insert '|' at index
+}
+*/
+
+UChar32 RuleCharacterIterator::_current() const {
+    if (buf != 0) {
+        return buf->char32At(bufPos);
+    } else {
+        int i = pos.getIndex();
+        return (i < text.length()) ? text.char32At(i) : (UChar32)DONE;
+    }
+}
+
+void RuleCharacterIterator::_advance(int32_t count) {
+    if (buf != 0) {
+        bufPos += count;
+        if (bufPos == buf->length()) {
+            buf = 0;
+        }
+    } else {
+        pos.setIndex(pos.getIndex() + count);
+        if (pos.getIndex() > text.length()) {
+            pos.setIndex(text.length());
+        }
+    }
+}
+
+U_NAMESPACE_END
+
+//eof
diff --git a/source/common/ruleiter.h b/source/common/ruleiter.h
new file mode 100644
index 0000000..cc4e847
--- /dev/null
+++ b/source/common/ruleiter.h
@@ -0,0 +1,232 @@
+/*
+**********************************************************************
+* Copyright (c) 2003-2007, International Business Machines
+* Corporation and others.  All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: September 24 2003
+* Since: ICU 2.8
+**********************************************************************
+*/
+#ifndef _RULEITER_H_
+#define _RULEITER_H_
+
+#include "unicode/uobject.h"
+
+U_NAMESPACE_BEGIN
+
+class UnicodeString;
+class ParsePosition;
+class SymbolTable;
+
+/**
+ * An iterator that returns 32-bit code points.  This class is deliberately
+ * <em>not</em> related to any of the ICU character iterator classes
+ * in order to minimize complexity.
+ * @author Alan Liu
+ * @since ICU 2.8
+ */
+class RuleCharacterIterator : public UMemory {
+
+    // TODO: Ideas for later.  (Do not implement if not needed, lest the
+    // code coverage numbers go down due to unused methods.)
+    // 1. Add a copy constructor, operator==() method.
+    // 2. Rather than return DONE, throw an exception if the end
+    // is reached -- this is an alternate usage model, probably not useful.
+
+private:
+    /**
+     * Text being iterated.
+     */    
+    const UnicodeString& text;
+
+    /**
+     * Position of iterator.
+     */
+    ParsePosition& pos;
+
+    /**
+     * Symbol table used to parse and dereference variables.  May be 0.
+     */
+    const SymbolTable* sym;
+    
+    /**
+     * Current variable expansion, or 0 if none.
+     */
+    const UnicodeString* buf;
+
+    /**
+     * Position within buf.  Meaningless if buf == 0.
+     */
+    int32_t bufPos;
+
+public:
+    /**
+     * Value returned when there are no more characters to iterate.
+     */
+    enum { DONE = -1 };
+
+    /**
+     * Bitmask option to enable parsing of variable names.  If (options &
+     * PARSE_VARIABLES) != 0, then an embedded variable will be expanded to
+     * its value.  Variables are parsed using the SymbolTable API.
+     */
+    enum { PARSE_VARIABLES = 1 };
+
+    /**
+     * Bitmask option to enable parsing of escape sequences.  If (options &
+     * PARSE_ESCAPES) != 0, then an embedded escape sequence will be expanded
+     * to its value.  Escapes are parsed using Utility.unescapeAt().
+     */
+    enum { PARSE_ESCAPES   = 2 };
+
+    /**
+     * Bitmask option to enable skipping of whitespace.  If (options &
+     * SKIP_WHITESPACE) != 0, then whitespace characters will be silently
+     * skipped, as if they were not present in the input.  Whitespace
+     * characters are defined by UCharacterProperty.isRuleWhiteSpace().
+     */
+    enum { SKIP_WHITESPACE = 4 };
+
+    /**
+     * Constructs an iterator over the given text, starting at the given
+     * position.
+     * @param text the text to be iterated
+     * @param sym the symbol table, or null if there is none.  If sym is null,
+     * then variables will not be deferenced, even if the PARSE_VARIABLES
+     * option is set.
+     * @param pos upon input, the index of the next character to return.  If a
+     * variable has been dereferenced, then pos will <em>not</em> increment as
+     * characters of the variable value are iterated.
+     */
+    RuleCharacterIterator(const UnicodeString& text, const SymbolTable* sym,
+                          ParsePosition& pos);
+    
+    /**
+     * Returns true if this iterator has no more characters to return.
+     */
+    UBool atEnd() const;
+
+    /**
+     * Returns the next character using the given options, or DONE if there
+     * are no more characters, and advance the position to the next
+     * character.
+     * @param options one or more of the following options, bitwise-OR-ed
+     * together: PARSE_VARIABLES, PARSE_ESCAPES, SKIP_WHITESPACE.
+     * @param isEscaped output parameter set to TRUE if the character
+     * was escaped
+     * @param ec input-output error code.  An error will only be set by
+     * this routing if options includes PARSE_VARIABLES and an unknown
+     * variable name is seen, or if options includes PARSE_ESCAPES and
+     * an invalid escape sequence is seen.
+     * @return the current 32-bit code point, or DONE
+     */
+    UChar32 next(int32_t options, UBool& isEscaped, UErrorCode& ec);
+
+    /**
+     * Returns true if this iterator is currently within a variable expansion.
+     */
+    inline UBool inVariable() const;
+
+    /**
+     * An opaque object representing the position of a RuleCharacterIterator.
+     */
+    struct Pos : public UMemory {
+    private:
+        const UnicodeString* buf;
+        int32_t pos;
+        int32_t bufPos;
+        friend class RuleCharacterIterator;
+    };
+
+    /**
+     * Sets an object which, when later passed to setPos(), will
+     * restore this iterator's position.  Usage idiom:
+     *
+     * RuleCharacterIterator iterator = ...;
+     * RuleCharacterIterator::Pos pos;
+     * iterator.getPos(pos);
+     * for (;;) {
+     *   iterator.getPos(pos);
+     *   int c = iterator.next(...);
+     *   ...
+     * }
+     * iterator.setPos(pos);
+     *
+     * @param p a position object to be set to this iterator's
+     * current position.
+     */
+    void getPos(Pos& p) const;
+
+    /**
+     * Restores this iterator to the position it had when getPos()
+     * set the given object.
+     * @param p a position object previously set by getPos()
+     */
+    void setPos(const Pos& p);
+
+    /**
+     * Skips ahead past any ignored characters, as indicated by the given
+     * options.  This is useful in conjunction with the lookahead() method.
+     *
+     * Currently, this only has an effect for SKIP_WHITESPACE.
+     * @param options one or more of the following options, bitwise-OR-ed
+     * together: PARSE_VARIABLES, PARSE_ESCAPES, SKIP_WHITESPACE.
+     */
+    void skipIgnored(int32_t options);
+
+    /**
+     * Returns a string containing the remainder of the characters to be
+     * returned by this iterator, without any option processing.  If the
+     * iterator is currently within a variable expansion, this will only
+     * extend to the end of the variable expansion.  This method is provided
+     * so that iterators may interoperate with string-based APIs.  The typical
+     * sequence of calls is to call skipIgnored(), then call lookahead(), then
+     * parse the string returned by lookahead(), then call jumpahead() to
+     * resynchronize the iterator.
+     * @param result a string to receive the characters to be returned
+     * by future calls to next()
+     * @param maxLookAhead The maximum to copy into the result.
+     * @return a reference to result
+     */
+    UnicodeString& lookahead(UnicodeString& result, int32_t maxLookAhead = -1) const;
+
+    /**
+     * Advances the position by the given number of 16-bit code units.
+     * This is useful in conjunction with the lookahead() method.
+     * @param count the number of 16-bit code units to jump over
+     */
+    void jumpahead(int32_t count);
+
+    /**
+     * Returns a string representation of this object, consisting of the
+     * characters being iterated, with a '|' marking the current position.
+     * Position within an expanded variable is <em>not</em> indicated.
+     * @param result output parameter to receive a string
+     * representation of this object
+     */
+//    UnicodeString& toString(UnicodeString& result) const;
+    
+private:
+    /**
+     * Returns the current 32-bit code point without parsing escapes, parsing
+     * variables, or skipping whitespace.
+     * @return the current 32-bit code point
+     */
+    UChar32 _current() const;
+    
+    /**
+     * Advances the position by the given amount.
+     * @param count the number of 16-bit code units to advance past
+     */
+    void _advance(int32_t count);
+};
+
+inline UBool RuleCharacterIterator::inVariable() const {
+    return buf != 0;
+}
+
+U_NAMESPACE_END
+
+#endif // _RULEITER_H_
+//eof
diff --git a/source/common/schriter.cpp b/source/common/schriter.cpp
new file mode 100644
index 0000000..b226339
--- /dev/null
+++ b/source/common/schriter.cpp
@@ -0,0 +1,117 @@
+/*
+******************************************************************************
+* Copyright (C) 1998-2010, International Business Machines Corporation and
+* others. All Rights Reserved.
+******************************************************************************
+*
+* File schriter.cpp
+*
+* Modification History:
+*
+*   Date        Name        Description
+*  05/05/99     stephen     Cleaned up.
+******************************************************************************
+*/
+
+#include <typeinfo>  // for 'typeid' to work
+
+#include "unicode/chariter.h"
+#include "unicode/schriter.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(StringCharacterIterator)
+
+StringCharacterIterator::StringCharacterIterator()
+  : UCharCharacterIterator(),
+    text()
+{
+  // NEVER DEFAULT CONSTRUCT!
+}
+
+StringCharacterIterator::StringCharacterIterator(const UnicodeString& textStr)
+  : UCharCharacterIterator(textStr.getBuffer(), textStr.length()),
+    text(textStr)
+{
+    // we had set the input parameter's array, now we need to set our copy's array
+    UCharCharacterIterator::text = this->text.getBuffer();
+}
+
+StringCharacterIterator::StringCharacterIterator(const UnicodeString& textStr,
+                                                 int32_t textPos)
+  : UCharCharacterIterator(textStr.getBuffer(), textStr.length(), textPos),
+    text(textStr)
+{
+    // we had set the input parameter's array, now we need to set our copy's array
+    UCharCharacterIterator::text = this->text.getBuffer();
+}
+
+StringCharacterIterator::StringCharacterIterator(const UnicodeString& textStr,
+                                                 int32_t textBegin,
+                                                 int32_t textEnd,
+                                                 int32_t textPos)
+  : UCharCharacterIterator(textStr.getBuffer(), textStr.length(), textBegin, textEnd, textPos),
+    text(textStr)
+{
+    // we had set the input parameter's array, now we need to set our copy's array
+    UCharCharacterIterator::text = this->text.getBuffer();
+}
+
+StringCharacterIterator::StringCharacterIterator(const StringCharacterIterator& that)
+  : UCharCharacterIterator(that),
+    text(that.text)
+{
+    // we had set the input parameter's array, now we need to set our copy's array
+    UCharCharacterIterator::text = this->text.getBuffer();
+}
+
+StringCharacterIterator::~StringCharacterIterator() {
+}
+
+StringCharacterIterator&
+StringCharacterIterator::operator=(const StringCharacterIterator& that) {
+    UCharCharacterIterator::operator=(that);
+    text = that.text;
+    // we had set the input parameter's array, now we need to set our copy's array
+    UCharCharacterIterator::text = this->text.getBuffer();
+    return *this;
+}
+
+UBool
+StringCharacterIterator::operator==(const ForwardCharacterIterator& that) const {
+    if (this == &that) {
+        return TRUE;
+    }
+
+    // do not call UCharCharacterIterator::operator==()
+    // because that checks for array pointer equality
+    // while we compare UnicodeString objects
+
+    if (typeid(*this) != typeid(that)) {
+        return FALSE;
+    }
+
+    StringCharacterIterator&    realThat = (StringCharacterIterator&)that;
+
+    return text == realThat.text
+        && pos == realThat.pos
+        && begin == realThat.begin
+        && end == realThat.end;
+}
+
+CharacterIterator*
+StringCharacterIterator::clone() const {
+    return new StringCharacterIterator(*this);
+}
+
+void
+StringCharacterIterator::setText(const UnicodeString& newText) {
+    text = newText;
+    UCharCharacterIterator::setText(text.getBuffer(), text.length());
+}
+
+void
+StringCharacterIterator::getText(UnicodeString& result) {
+    result = text;
+}
+U_NAMESPACE_END
diff --git a/source/common/serv.cpp b/source/common/serv.cpp
new file mode 100644
index 0000000..4f1da5b
--- /dev/null
+++ b/source/common/serv.cpp
@@ -0,0 +1,981 @@
+/**
+*******************************************************************************
+* Copyright (C) 2001-2010, International Business Machines Corporation.
+* All Rights Reserved.
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_SERVICE
+
+#include "serv.h"
+#include "umutex.h"
+
+#undef SERVICE_REFCOUNT
+
+// in case we use the refcount stuff
+
+U_NAMESPACE_BEGIN
+
+/*
+******************************************************************
+*/
+
+const UChar ICUServiceKey::PREFIX_DELIMITER = 0x002F;   /* '/' */
+
+ICUServiceKey::ICUServiceKey(const UnicodeString& id) 
+: _id(id) {
+}
+
+ICUServiceKey::~ICUServiceKey() 
+{
+}
+
+const UnicodeString& 
+ICUServiceKey::getID() const 
+{
+    return _id;
+}
+
+UnicodeString& 
+ICUServiceKey::canonicalID(UnicodeString& result) const 
+{
+    return result.append(_id);
+}
+
+UnicodeString& 
+ICUServiceKey::currentID(UnicodeString& result) const 
+{
+    return canonicalID(result);
+}
+
+UnicodeString& 
+ICUServiceKey::currentDescriptor(UnicodeString& result) const 
+{
+    prefix(result);
+    result.append(PREFIX_DELIMITER);
+    return currentID(result);
+}
+
+UBool 
+ICUServiceKey::fallback() 
+{
+    return FALSE;
+}
+
+UBool 
+ICUServiceKey::isFallbackOf(const UnicodeString& id) const 
+{
+    return id == _id;
+}
+
+UnicodeString& 
+ICUServiceKey::prefix(UnicodeString& result) const 
+{
+    return result;
+}
+
+UnicodeString& 
+ICUServiceKey::parsePrefix(UnicodeString& result) 
+{
+    int32_t n = result.indexOf(PREFIX_DELIMITER);
+    if (n < 0) {
+        n = 0;
+    }
+    result.remove(n);
+    return result;
+}
+
+UnicodeString& 
+ICUServiceKey::parseSuffix(UnicodeString& result) 
+{
+    int32_t n = result.indexOf(PREFIX_DELIMITER);
+    if (n >= 0) {
+        result.remove(0, n+1);
+    }
+    return result;
+}
+
+#ifdef SERVICE_DEBUG
+UnicodeString& 
+ICUServiceKey::debug(UnicodeString& result) const 
+{
+    debugClass(result);
+    result.append(" id: ");
+    result.append(_id);
+    return result;
+}
+
+UnicodeString& 
+ICUServiceKey::debugClass(UnicodeString& result) const 
+{
+    return result.append("ICUServiceKey");
+}
+#endif
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ICUServiceKey)
+
+/*
+******************************************************************
+*/
+
+SimpleFactory::SimpleFactory(UObject* instanceToAdopt, const UnicodeString& id, UBool visible) 
+: _instance(instanceToAdopt), _id(id), _visible(visible)
+{
+}
+
+SimpleFactory::~SimpleFactory() 
+{
+    delete _instance;
+}
+
+UObject* 
+SimpleFactory::create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const 
+{
+    if (U_SUCCESS(status)) {
+        UnicodeString temp;
+        if (_id == key.currentID(temp)) {
+            return service->cloneInstance(_instance); 
+        }
+    }
+    return NULL;
+}
+
+void 
+SimpleFactory::updateVisibleIDs(Hashtable& result, UErrorCode& status) const 
+{
+    if (_visible) {
+        result.put(_id, (void*)this, status); // cast away const
+    } else {
+        result.remove(_id);
+    }
+}
+
+UnicodeString& 
+SimpleFactory::getDisplayName(const UnicodeString& id, const Locale& /* locale */, UnicodeString& result) const 
+{
+    if (_visible && _id == id) {
+        result = _id;
+    } else {
+        result.setToBogus();
+    }
+    return result;
+}
+
+#ifdef SERVICE_DEBUG
+UnicodeString& 
+SimpleFactory::debug(UnicodeString& toAppendTo) const 
+{
+    debugClass(toAppendTo);
+    toAppendTo.append(" id: ");
+    toAppendTo.append(_id);
+    toAppendTo.append(", visible: ");
+    toAppendTo.append(_visible ? "T" : "F");
+    return toAppendTo;
+}
+
+UnicodeString& 
+SimpleFactory::debugClass(UnicodeString& toAppendTo) const 
+{
+    return toAppendTo.append("SimpleFactory");
+}
+#endif
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleFactory)
+
+/*
+******************************************************************
+*/
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceListener)
+
+/*
+******************************************************************
+*/
+
+// Record the actual id for this service in the cache, so we can return it
+// even if we succeed later with a different id.
+class CacheEntry : public UMemory {
+private:
+    int32_t refcount;
+
+public:
+    UnicodeString actualDescriptor;
+    UObject* service;
+
+    /**
+    * Releases a reference to the shared resource.
+    */
+    ~CacheEntry() {
+        delete service;
+    }
+
+    CacheEntry(const UnicodeString& _actualDescriptor, UObject* _service) 
+        : refcount(1), actualDescriptor(_actualDescriptor), service(_service) {
+    }
+
+    /**
+    * Instantiation creates an initial reference, so don't call this
+    * unless you're creating a new pointer to this.  Management of
+    * that pointer will have to know how to deal with refcounts.  
+    * Return true if the resource has not already been released.
+    */
+    CacheEntry* ref() {
+        ++refcount;
+        return this;
+    }
+
+    /**
+    * Destructions removes a reference, so don't call this unless
+    * you're removing pointer to this somewhere.  Management of that
+    * pointer will have to know how to deal with refcounts.  Once
+    * the refcount drops to zero, the resource is released.  Return
+    * false if the resouce has been released.
+    */
+    CacheEntry* unref() {
+        if ((--refcount) == 0) {
+            delete this;
+            return NULL;
+        }
+        return this;
+    }
+
+    /**
+    * Return TRUE if there is at least one reference to this and the
+    * resource has not been released.
+    */
+    UBool isShared() const {
+        return refcount > 1;
+    }
+};
+
+// UObjectDeleter for serviceCache
+U_CDECL_BEGIN
+static void U_CALLCONV
+cacheDeleter(void* obj) {
+    U_NAMESPACE_USE ((CacheEntry*)obj)->unref();
+}
+
+/**
+* Deleter for UObjects
+*/
+static void U_CALLCONV
+deleteUObject(void *obj) {
+    U_NAMESPACE_USE delete (UObject*) obj;
+}
+U_CDECL_END
+
+/*
+******************************************************************
+*/
+
+class DNCache : public UMemory {
+public:
+    Hashtable cache;
+    const Locale locale;
+
+    DNCache(const Locale& _locale) 
+        : cache(), locale(_locale) 
+    {
+        // cache.setKeyDeleter(uhash_deleteUnicodeString);
+    }
+};
+
+
+/*
+******************************************************************
+*/
+
+StringPair* 
+StringPair::create(const UnicodeString& displayName, 
+                   const UnicodeString& id,
+                   UErrorCode& status)
+{
+    if (U_SUCCESS(status)) {
+        StringPair* sp = new StringPair(displayName, id);
+        if (sp == NULL || sp->isBogus()) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            delete sp;
+            return NULL;
+        }
+        return sp;
+    }
+    return NULL;
+}
+
+UBool 
+StringPair::isBogus() const {
+    return displayName.isBogus() || id.isBogus();
+}
+
+StringPair::StringPair(const UnicodeString& _displayName, 
+                       const UnicodeString& _id)
+: displayName(_displayName)
+, id(_id)
+{
+}
+
+U_CDECL_BEGIN
+static void U_CALLCONV
+userv_deleteStringPair(void *obj) {
+    U_NAMESPACE_USE delete (StringPair*) obj;
+}
+U_CDECL_END
+
+/*
+******************************************************************
+*/
+
+ICUService::ICUService()
+: name()
+, lock(0)
+, timestamp(0)
+, factories(NULL)
+, serviceCache(NULL)
+, idCache(NULL)
+, dnCache(NULL)
+{
+    umtx_init(&lock);
+}
+
+ICUService::ICUService(const UnicodeString& newName) 
+: name(newName)
+, lock(0)
+, timestamp(0)
+, factories(NULL)
+, serviceCache(NULL)
+, idCache(NULL)
+, dnCache(NULL)
+{
+    umtx_init(&lock);
+}
+
+ICUService::~ICUService()
+{
+    {
+        Mutex mutex(&lock);
+        clearCaches();
+        delete factories;
+        factories = NULL;
+    }
+    umtx_destroy(&lock);
+}
+
+UObject* 
+ICUService::get(const UnicodeString& descriptor, UErrorCode& status) const 
+{
+    return get(descriptor, NULL, status);
+}
+
+UObject* 
+ICUService::get(const UnicodeString& descriptor, UnicodeString* actualReturn, UErrorCode& status) const 
+{
+    UObject* result = NULL;
+    ICUServiceKey* key = createKey(&descriptor, status);
+    if (key) {
+        result = getKey(*key, actualReturn, status);
+        delete key;
+    }
+    return result;
+}
+
+UObject* 
+ICUService::getKey(ICUServiceKey& key, UErrorCode& status) const 
+{
+    return getKey(key, NULL, status);
+}
+
+// this is a vector that subclasses of ICUService can override to further customize the result object
+// before returning it.  All other public get functions should call this one.
+
+UObject* 
+ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const 
+{
+    return getKey(key, actualReturn, NULL, status);
+}
+
+// make it possible to call reentrantly on systems that don't have reentrant mutexes.
+// we can use this simple approach since we know the situation where we're calling
+// reentrantly even without knowing the thread.
+class XMutex : public UMemory {
+public:
+    inline XMutex(UMTX *mutex, UBool reentering) 
+        : fMutex(mutex)
+        , fActive(!reentering) 
+    {
+        if (fActive) umtx_lock(fMutex);
+    }
+    inline ~XMutex() {
+        if (fActive) umtx_unlock(fMutex);
+    }
+
+private:
+    UMTX  *fMutex;
+    UBool fActive;
+};
+
+struct UVectorDeleter {
+    UVector* _obj;
+    UVectorDeleter() : _obj(NULL) {}
+    ~UVectorDeleter() { delete _obj; }
+};
+
+// called only by factories, treat as private
+UObject* 
+ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, const ICUServiceFactory* factory, UErrorCode& status) const 
+{
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+
+    if (isDefault()) {
+        return handleDefault(key, actualReturn, status);
+    }
+
+    ICUService* ncthis = (ICUService*)this; // cast away semantic const
+
+    CacheEntry* result = NULL;
+    {
+        // The factory list can't be modified until we're done, 
+        // otherwise we might update the cache with an invalid result.
+        // The cache has to stay in synch with the factory list.
+        // ICU doesn't have monitors so we can't use rw locks, so 
+        // we single-thread everything using this service, for now.
+
+        // if factory is not null, we're calling from within the mutex,
+        // and since some unix machines don't have reentrant mutexes we
+        // need to make sure not to try to lock it again.
+        XMutex mutex(&ncthis->lock, factory != NULL);
+
+        if (serviceCache == NULL) {
+            ncthis->serviceCache = new Hashtable(status);
+            if (ncthis->serviceCache == NULL) {
+                return NULL;
+            }
+            if (U_FAILURE(status)) {
+                delete serviceCache;
+                return NULL;
+            }
+            serviceCache->setValueDeleter(cacheDeleter);
+        }
+
+        UnicodeString currentDescriptor;
+        UVectorDeleter cacheDescriptorList;
+        UBool putInCache = FALSE;
+
+        int32_t startIndex = 0;
+        int32_t limit = factories->size();
+        UBool cacheResult = TRUE;
+
+        if (factory != NULL) {
+            for (int32_t i = 0; i < limit; ++i) {
+                if (factory == (const ICUServiceFactory*)factories->elementAt(i)) {
+                    startIndex = i + 1;
+                    break;
+                }
+            }
+            if (startIndex == 0) {
+                // throw new InternalError("Factory " + factory + "not registered with service: " + this);
+                status = U_ILLEGAL_ARGUMENT_ERROR;
+                return NULL;
+            }
+            cacheResult = FALSE;
+        }
+
+        do {
+            currentDescriptor.remove();
+            key.currentDescriptor(currentDescriptor);
+            result = (CacheEntry*)serviceCache->get(currentDescriptor);
+            if (result != NULL) {
+                break;
+            }
+
+            // first test of cache failed, so we'll have to update
+            // the cache if we eventually succeed-- that is, if we're 
+            // going to update the cache at all.
+            putInCache = TRUE;
+
+            int32_t index = startIndex;
+            while (index < limit) {
+                ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(index++);
+                UObject* service = f->create(key, this, status);
+                if (U_FAILURE(status)) {
+                    delete service;
+                    return NULL;
+                }
+                if (service != NULL) {
+                    result = new CacheEntry(currentDescriptor, service);
+                    if (result == NULL) {
+                        delete service;
+                        status = U_MEMORY_ALLOCATION_ERROR;
+                        return NULL;
+                    }
+
+                    goto outerEnd;
+                }
+            }
+
+            // prepare to load the cache with all additional ids that 
+            // will resolve to result, assuming we'll succeed.  We
+            // don't want to keep querying on an id that's going to
+            // fallback to the one that succeeded, we want to hit the
+            // cache the first time next goaround.
+            if (cacheDescriptorList._obj == NULL) {
+                cacheDescriptorList._obj = new UVector(uhash_deleteUnicodeString, NULL, 5, status);
+                if (U_FAILURE(status)) {
+                    return NULL;
+                }
+            }
+            UnicodeString* idToCache = new UnicodeString(currentDescriptor);
+            if (idToCache == NULL || idToCache->isBogus()) {
+                status = U_MEMORY_ALLOCATION_ERROR;
+                return NULL;
+            }
+
+            cacheDescriptorList._obj->addElement(idToCache, status);
+            if (U_FAILURE(status)) {
+                return NULL;
+            }
+        } while (key.fallback());
+outerEnd:
+
+        if (result != NULL) {
+            if (putInCache && cacheResult) {
+                serviceCache->put(result->actualDescriptor, result, status);
+                if (U_FAILURE(status)) {
+                    delete result;
+                    return NULL;
+                }
+
+                if (cacheDescriptorList._obj != NULL) {
+                    for (int32_t i = cacheDescriptorList._obj->size(); --i >= 0;) {
+                        UnicodeString* desc = (UnicodeString*)cacheDescriptorList._obj->elementAt(i);
+                        serviceCache->put(*desc, result, status);
+                        if (U_FAILURE(status)) {
+                            delete result;
+                            return NULL;
+                        }
+
+                        result->ref();
+                        cacheDescriptorList._obj->removeElementAt(i);
+                    }
+                }
+            }
+
+            if (actualReturn != NULL) {
+                // strip null prefix
+                if (result->actualDescriptor.indexOf((UChar)0x2f) == 0) { // U+002f=slash (/)
+                    actualReturn->remove();
+                    actualReturn->append(result->actualDescriptor, 
+                        1, 
+                        result->actualDescriptor.length() - 1);
+                } else {
+                    *actualReturn = result->actualDescriptor;
+                }
+
+                if (actualReturn->isBogus()) {
+                    status = U_MEMORY_ALLOCATION_ERROR;
+                    delete result;
+                    return NULL;
+                }
+            }
+
+            UObject* service = cloneInstance(result->service);
+            if (putInCache && !cacheResult) {
+                delete result;
+            }
+            return service;
+        }
+    }
+
+    return handleDefault(key, actualReturn, status);
+}
+
+UObject* 
+ICUService::handleDefault(const ICUServiceKey& /* key */, UnicodeString* /* actualIDReturn */, UErrorCode& /* status */) const 
+{
+    return NULL;
+}
+
+UVector& 
+ICUService::getVisibleIDs(UVector& result, UErrorCode& status) const {
+    return getVisibleIDs(result, NULL, status);
+}
+
+UVector& 
+ICUService::getVisibleIDs(UVector& result, const UnicodeString* matchID, UErrorCode& status) const 
+{
+    result.removeAllElements();
+
+    if (U_FAILURE(status)) {
+        return result;
+    }
+
+    ICUService * ncthis = (ICUService*)this; // cast away semantic const
+    {
+        Mutex mutex(&ncthis->lock);
+        const Hashtable* map = getVisibleIDMap(status);
+        if (map != NULL) {
+            ICUServiceKey* fallbackKey = createKey(matchID, status);
+
+            for (int32_t pos = -1;;) {
+                const UHashElement* e = map->nextElement(pos);
+                if (e == NULL) {
+                    break;
+                }
+
+                const UnicodeString* id = (const UnicodeString*)e->key.pointer;
+                if (fallbackKey != NULL) {
+                    if (!fallbackKey->isFallbackOf(*id)) {
+                        continue;
+                    }
+                }
+
+                UnicodeString* idClone = new UnicodeString(*id);
+                if (idClone == NULL || idClone->isBogus()) {
+                    delete idClone;
+                    status = U_MEMORY_ALLOCATION_ERROR;
+                    break;
+                }
+                result.addElement(idClone, status);
+                if (U_FAILURE(status)) {
+                    delete idClone;
+                    break;
+                }
+            }
+            delete fallbackKey;
+        }
+    }
+    if (U_FAILURE(status)) {
+        result.removeAllElements();
+    }
+    return result;
+}
+
+const Hashtable* 
+ICUService::getVisibleIDMap(UErrorCode& status) const {
+    if (U_FAILURE(status)) return NULL;
+
+    // must only be called when lock is already held
+
+    ICUService* ncthis = (ICUService*)this; // cast away semantic const
+    if (idCache == NULL) {
+        ncthis->idCache = new Hashtable(status);
+        if (idCache == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+        } else if (factories != NULL) {
+            for (int32_t pos = factories->size(); --pos >= 0;) {
+                ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(pos);
+                f->updateVisibleIDs(*idCache, status);
+            }
+            if (U_FAILURE(status)) {
+                delete idCache;
+                ncthis->idCache = NULL;
+            }
+        }
+    }
+
+    return idCache;
+}
+
+
+UnicodeString& 
+ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result) const 
+{
+    return getDisplayName(id, result, Locale::getDefault());
+}
+
+UnicodeString& 
+ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result, const Locale& locale) const 
+{
+    {
+        ICUService* ncthis = (ICUService*)this; // cast away semantic const
+        UErrorCode status = U_ZERO_ERROR;
+        Mutex mutex(&ncthis->lock);
+        const Hashtable* map = getVisibleIDMap(status);
+        if (map != NULL) {
+            ICUServiceFactory* f = (ICUServiceFactory*)map->get(id);
+            if (f != NULL) {
+                f->getDisplayName(id, locale, result);
+                return result;
+            }
+
+            // fallback
+            UErrorCode status = U_ZERO_ERROR;
+            ICUServiceKey* fallbackKey = createKey(&id, status);
+            while (fallbackKey->fallback()) {
+                UnicodeString us;
+                fallbackKey->currentID(us);
+                f = (ICUServiceFactory*)map->get(us);
+                if (f != NULL) {
+                    f->getDisplayName(id, locale, result);
+                    delete fallbackKey;
+                    return result;
+                }
+            }
+            delete fallbackKey;
+        }
+    }
+    result.setToBogus();
+    return result;
+}
+
+UVector& 
+ICUService::getDisplayNames(UVector& result, UErrorCode& status) const 
+{
+    return getDisplayNames(result, Locale::getDefault(), NULL, status);
+}
+
+
+UVector& 
+ICUService::getDisplayNames(UVector& result, const Locale& locale, UErrorCode& status) const 
+{
+    return getDisplayNames(result, locale, NULL, status);
+}
+
+UVector& 
+ICUService::getDisplayNames(UVector& result, 
+                            const Locale& locale, 
+                            const UnicodeString* matchID, 
+                            UErrorCode& status) const 
+{
+    result.removeAllElements();
+    result.setDeleter(userv_deleteStringPair);
+    if (U_SUCCESS(status)) {
+        ICUService* ncthis = (ICUService*)this; // cast away semantic const
+        Mutex mutex(&ncthis->lock);
+
+        if (dnCache != NULL && dnCache->locale != locale) {
+            delete dnCache;
+            ncthis->dnCache = NULL;
+        }
+
+        if (dnCache == NULL) {
+            const Hashtable* m = getVisibleIDMap(status);
+            if (m != NULL) {
+                ncthis->dnCache = new DNCache(locale); 
+                if (dnCache == NULL) {
+                    status = U_MEMORY_ALLOCATION_ERROR;
+                    return result;
+                }
+
+                int32_t pos = -1;
+                const UHashElement* entry = NULL;
+                while ((entry = m->nextElement(pos)) != NULL) {
+                    const UnicodeString* id = (const UnicodeString*)entry->key.pointer;
+                    ICUServiceFactory* f = (ICUServiceFactory*)entry->value.pointer;
+                    UnicodeString dname;
+                    f->getDisplayName(*id, locale, dname);
+                    if (dname.isBogus()) {
+                        status = U_MEMORY_ALLOCATION_ERROR;
+                    } else {
+                        dnCache->cache.put(dname, (void*)id, status); // share pointer with visibleIDMap
+                        if (U_SUCCESS(status)) {
+                            continue;
+                        }
+                    }
+                    delete dnCache;
+                    ncthis->dnCache = NULL;
+                    return result;
+                }
+            }
+        }
+    }
+
+    ICUServiceKey* matchKey = createKey(matchID, status);
+    /* To ensure that all elements in the hashtable are iterated, set pos to -1.
+     * nextElement(pos) will skip the position at pos and begin the iteration
+     * at the next position, which in this case will be 0.
+     */
+    int32_t pos = -1; 
+    const UHashElement *entry = NULL;
+    while ((entry = dnCache->cache.nextElement(pos)) != NULL) {
+        const UnicodeString* id = (const UnicodeString*)entry->value.pointer;
+        if (matchKey != NULL && !matchKey->isFallbackOf(*id)) {
+            continue;
+        }
+        const UnicodeString* dn = (const UnicodeString*)entry->key.pointer;
+        StringPair* sp = StringPair::create(*id, *dn, status);
+        result.addElement(sp, status);
+        if (U_FAILURE(status)) {
+            result.removeAllElements();
+            break;
+        }
+    }
+    delete matchKey;
+
+    return result;
+}
+
+URegistryKey
+ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UErrorCode& status) 
+{
+    return registerInstance(objToAdopt, id, TRUE, status);
+}
+
+URegistryKey
+ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status) 
+{
+    ICUServiceKey* key = createKey(&id, status);
+    if (key != NULL) {
+        UnicodeString canonicalID;
+        key->canonicalID(canonicalID);
+        delete key;
+
+        ICUServiceFactory* f = createSimpleFactory(objToAdopt, canonicalID, visible, status);
+        if (f != NULL) {
+            return registerFactory(f, status);
+        }
+    }
+    delete objToAdopt;
+    return NULL;
+}
+
+ICUServiceFactory* 
+ICUService::createSimpleFactory(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status)
+{
+    if (U_SUCCESS(status)) {
+        if ((objToAdopt != NULL) && (!id.isBogus())) {
+            return new SimpleFactory(objToAdopt, id, visible);
+        }
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+    }
+    return NULL;
+}
+
+URegistryKey
+ICUService::registerFactory(ICUServiceFactory* factoryToAdopt, UErrorCode& status) 
+{
+    if (U_SUCCESS(status) && factoryToAdopt != NULL) {
+        Mutex mutex(&lock);
+
+        if (factories == NULL) {
+            factories = new UVector(deleteUObject, NULL, status);
+            if (U_FAILURE(status)) {
+                delete factories;
+                return NULL;
+            }
+        }
+        factories->insertElementAt(factoryToAdopt, 0, status);
+        if (U_SUCCESS(status)) {
+            clearCaches();
+        } else {
+            delete factoryToAdopt;
+            factoryToAdopt = NULL;
+        }
+    }
+
+    if (factoryToAdopt != NULL) {
+        notifyChanged();
+    }
+
+    return (URegistryKey)factoryToAdopt;
+}
+
+UBool 
+ICUService::unregister(URegistryKey rkey, UErrorCode& status) 
+{
+    ICUServiceFactory *factory = (ICUServiceFactory*)rkey;
+    UBool result = FALSE;
+    if (factory != NULL && factories != NULL) {
+        Mutex mutex(&lock);
+
+        if (factories->removeElement(factory)) {
+            clearCaches();
+            result = TRUE;
+        } else {
+            status = U_ILLEGAL_ARGUMENT_ERROR;
+            delete factory;
+        }
+    }
+    if (result) {
+        notifyChanged();
+    }
+    return result;
+}
+
+void 
+ICUService::reset() 
+{
+    {
+        Mutex mutex(&lock);
+        reInitializeFactories();
+        clearCaches();
+    }
+    notifyChanged();
+}
+
+void 
+ICUService::reInitializeFactories() 
+{
+    if (factories != NULL) {
+        factories->removeAllElements();
+    }
+}
+
+UBool 
+ICUService::isDefault() const 
+{
+    return countFactories() == 0;
+}
+
+ICUServiceKey* 
+ICUService::createKey(const UnicodeString* id, UErrorCode& status) const 
+{
+    return (U_FAILURE(status) || id == NULL) ? NULL : new ICUServiceKey(*id);
+}
+
+void 
+ICUService::clearCaches() 
+{
+    // callers synchronize before use
+    ++timestamp;
+    delete dnCache;
+    dnCache = NULL;
+    delete idCache;
+    idCache = NULL;
+    delete serviceCache; serviceCache = NULL;
+}
+
+void 
+ICUService::clearServiceCache() 
+{
+    // callers synchronize before use
+    delete serviceCache; serviceCache = NULL;
+}
+
+UBool 
+ICUService::acceptsListener(const EventListener& l) const 
+{
+    return dynamic_cast<const ServiceListener*>(&l) != NULL;
+}
+
+void 
+ICUService::notifyListener(EventListener& l) const 
+{
+    ((ServiceListener&)l).serviceChanged(*this);
+}
+
+UnicodeString&
+ICUService::getName(UnicodeString& result) const 
+{
+    return result.append(name);
+}
+
+int32_t 
+ICUService::countFactories() const 
+{
+    return factories == NULL ? 0 : factories->size();
+}
+
+int32_t
+ICUService::getTimestamp() const
+{
+    return timestamp;
+}
+
+U_NAMESPACE_END
+
+/* UCONFIG_NO_SERVICE */
+#endif
diff --git a/source/common/serv.h b/source/common/serv.h
new file mode 100644
index 0000000..2e498fb
--- /dev/null
+++ b/source/common/serv.h
@@ -0,0 +1,996 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2001-2007, International Business Machines Corporation.       *
+ * All Rights Reserved.                                                        *
+ *******************************************************************************
+ */
+
+#ifndef ICUSERV_H
+#define ICUSERV_H
+
+#include "unicode/utypes.h"
+
+#if UCONFIG_NO_SERVICE
+
+U_NAMESPACE_BEGIN
+
+/*
+ * Allow the declaration of APIs with pointers to ICUService
+ * even when service is removed from the build.
+ */
+class ICUService;
+
+U_NAMESPACE_END
+
+#else
+
+#include "unicode/unistr.h"
+#include "unicode/locid.h"
+#include "unicode/umisc.h"
+
+#include "hash.h"
+#include "uvector.h"
+#include "servnotf.h"
+
+class ICUServiceTest;
+
+U_NAMESPACE_BEGIN
+
+class ICUServiceKey;
+class ICUServiceFactory;
+class SimpleFactory;
+class ServiceListener;
+class ICUService;
+
+class DNCache;
+
+/*******************************************************************
+ * ICUServiceKey
+ */
+
+/**
+ * <p>ICUServiceKeys are used to communicate with factories to
+ * generate an instance of the service.  ICUServiceKeys define how
+ * ids are canonicalized, provide both a current id and a current
+ * descriptor to use in querying the cache and factories, and
+ * determine the fallback strategy.</p>
+ *
+ * <p>ICUServiceKeys provide both a currentDescriptor and a currentID.
+ * The descriptor contains an optional prefix, followed by '/'
+ * and the currentID.  Factories that handle complex keys,
+ * for example number format factories that generate multiple
+ * kinds of formatters for the same locale, use the descriptor 
+ * to provide a fully unique identifier for the service object, 
+ * while using the currentID (in this case, the locale string),
+ * as the visible IDs that can be localized.</p>
+ *
+ * <p>The default implementation of ICUServiceKey has no fallbacks and
+ * has no custom descriptors.</p> 
+ */
+class U_COMMON_API ICUServiceKey : public UObject {
+ private: 
+  const UnicodeString _id;
+
+ protected:
+  static const UChar PREFIX_DELIMITER;
+
+ public:
+
+  /**
+   * <p>Construct a key from an id.</p>
+   *
+   * @param id the ID from which to construct the key.
+   */
+  ICUServiceKey(const UnicodeString& id);
+
+  /**
+   * <p>Virtual destructor.</p>
+   */
+  virtual ~ICUServiceKey();
+
+ /**
+  * <p>Return the original ID used to construct this key.</p>
+  *
+  * @return the ID used to construct this key.
+  */
+  virtual const UnicodeString& getID() const;
+
+ /**
+  * <p>Return the canonical version of the original ID.  This implementation
+  * appends the original ID to result.  Result is returned as a convenience.</p>
+  *
+  * @param result the output parameter to which the id will be appended.
+  * @return the modified result.
+  */
+  virtual UnicodeString& canonicalID(UnicodeString& result) const;
+
+ /**
+  * <p>Return the (canonical) current ID.  This implementation appends
+  * the canonical ID to result.  Result is returned as a convenience.</p>
+  *
+  * @param result the output parameter to which the current id will be appended.
+  * @return the modified result.  
+  */
+  virtual UnicodeString& currentID(UnicodeString& result) const;
+
+ /**
+  * <p>Return the current descriptor.  This implementation appends
+  * the current descriptor to result.  Result is returned as a convenience.</p>
+  *
+  * <p>The current descriptor is used to fully
+  * identify an instance of the service in the cache.  A
+  * factory may handle all descriptors for an ID, or just a
+  * particular descriptor.  The factory can either parse the
+  * descriptor or use custom API on the key in order to
+  * instantiate the service.</p>
+  *
+  * @param result the output parameter to which the current id will be appended.
+  * @return the modified result.  
+  */
+  virtual UnicodeString& currentDescriptor(UnicodeString& result) const;
+
+ /**
+  * <p>If the key has a fallback, modify the key and return true,
+  * otherwise return false.  The current ID will change if there
+  * is a fallback.  No currentIDs should be repeated, and fallback
+  * must eventually return false.  This implementation has no fallbacks
+  * and always returns false.</p>
+  *
+  * @return TRUE if the ICUServiceKey changed to a valid fallback value.
+  */
+  virtual UBool fallback();
+
+ /**
+  * <p>Return TRUE if a key created from id matches, or would eventually
+  * fallback to match, the canonical ID of this ICUServiceKey.</p>
+  *
+  * @param id the id to test.
+  * @return TRUE if this ICUServiceKey's canonical ID is a fallback of id.
+  */
+  virtual UBool isFallbackOf(const UnicodeString& id) const;
+
+ /**
+  * <p>Return the prefix.  This implementation leaves result unchanged.
+  * Result is returned as a convenience.</p>
+  *
+  * @param result the output parameter to which the prefix will be appended.
+  * @return the modified result.
+  */
+  virtual UnicodeString& prefix(UnicodeString& result) const;
+
+ /**
+  * <p>A utility to parse the prefix out of a descriptor string.  Only
+  * the (undelimited) prefix, if any, remains in result.  Result is returned as a 
+  * convenience.</p>
+  *
+  * @param result an input/output parameter that on entry is a descriptor, and 
+  * on exit is the prefix of that descriptor.
+  * @return the modified result.
+  */
+  static UnicodeString& parsePrefix(UnicodeString& result);
+
+  /**
+  * <p>A utility to parse the suffix out of a descriptor string.  Only
+  * the (undelimited) suffix, if any, remains in result.  Result is returned as a 
+  * convenience.</p>
+  *
+  * @param result an input/output parameter that on entry is a descriptor, and 
+  * on exit is the suffix of that descriptor.
+  * @return the modified result.
+  */
+  static UnicodeString& parseSuffix(UnicodeString& result);
+
+public:
+  /**
+   * UObject RTTI boilerplate.
+   */
+  static UClassID U_EXPORT2 getStaticClassID();
+
+  /**
+   * UObject RTTI boilerplate.
+   */
+  virtual UClassID getDynamicClassID() const;
+
+#ifdef SERVICE_DEBUG
+ public:
+  virtual UnicodeString& debug(UnicodeString& result) const;
+  virtual UnicodeString& debugClass(UnicodeString& result) const;
+#endif
+
+};
+
+ /*******************************************************************
+  * ICUServiceFactory
+  */
+
+ /**
+  * <p>An implementing ICUServiceFactory generates the service objects maintained by the
+  * service.  A factory generates a service object from a key,
+  * updates id->factory mappings, and returns the display name for
+  * a supported id.</p>
+  */
+class U_COMMON_API ICUServiceFactory : public UObject {
+ public:
+
+    /**
+     * <p>Create a service object from the key, if this factory
+     * supports the key.  Otherwise, return NULL.</p>
+     *
+     * <p>If the factory supports the key, then it can call
+     * the service's getKey(ICUServiceKey, String[], ICUServiceFactory) method
+     * passing itself as the factory to get the object that
+     * the service would have created prior to the factory's
+     * registration with the service.  This can change the
+     * key, so any information required from the key should
+     * be extracted before making such a callback.</p>
+     *
+     * @param key the service key.
+     * @param service the service with which this factory is registered.
+     * @param status the error code status.
+     * @return the service object, or NULL if the factory does not support the key.
+     */
+    virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const = 0;
+
+    /**
+     * <p>Update result to reflect the IDs (not descriptors) that this
+     * factory publicly handles.  Result contains mappings from ID to
+     * factory.  On entry it will contain all (visible) mappings from
+     * previously-registered factories.</p>
+     *
+     * <p>This function, together with getDisplayName, are used to
+     * support ICUService::getDisplayNames.  The factory determines
+     * which IDs (of those it supports) it will make visible, and of
+     * those, which it will provide localized display names for.  In
+     * most cases it will register mappings from all IDs it supports
+     * to itself.</p>
+     *
+     * @param result the mapping table to update.
+     * @param status the error code status.
+     */
+    virtual void updateVisibleIDs(Hashtable& result, UErrorCode& status) const = 0;
+
+    /**
+     * <p>Return, in result, the display name of the id in the provided locale.
+     * This is an id, not a descriptor.  If the id is 
+     * not visible, sets result to bogus.  If the
+     * incoming result is bogus, it remains bogus.  Result is returned as a
+     * convenience.  Results are not defined if id is not one supported by this
+         * factory.</p>
+     *
+     * @param id a visible id supported by this factory.
+     * @param locale the locale for which to generate the corresponding localized display name.
+     * @param result output parameter to hold the display name.
+     * @return result.
+     */
+    virtual UnicodeString& getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const = 0;
+};
+
+/*
+ ******************************************************************
+ */
+
+ /**
+  * <p>A default implementation of factory.  This provides default
+  * implementations for subclasses, and implements a singleton
+  * factory that matches a single ID and returns a single
+  * (possibly deferred-initialized) instance.  This implements
+  * updateVisibleIDs to add a mapping from its ID to itself
+  * if visible is true, or to remove any existing mapping
+  * for its ID if visible is false.  No localization of display
+  * names is performed.</p>
+  */
+class U_COMMON_API SimpleFactory : public ICUServiceFactory {
+ protected:
+  UObject* _instance;
+  const UnicodeString _id;
+  const UBool _visible;
+
+ public:
+  /**
+   * <p>Construct a SimpleFactory that maps a single ID to a single 
+   * service instance.  If visible is TRUE, the ID will be visible.
+   * The instance must not be NULL.  The SimpleFactory will adopt
+   * the instance, which must not be changed subsequent to this call.</p>
+   *
+   * @param instanceToAdopt the service instance to adopt.
+   * @param id the ID to assign to this service instance.
+   * @param visible if TRUE, the ID will be visible.
+   */
+  SimpleFactory(UObject* instanceToAdopt, const UnicodeString& id, UBool visible = TRUE);
+
+  /**
+   * <p>Destructor.</p>
+   */
+  virtual ~SimpleFactory();
+
+  /**
+   * <p>This implementation returns a clone of the service instance if the factory's ID is equal to
+   * the key's currentID.  Service and prefix are ignored.</p>
+   *
+   * @param key the service key.
+   * @param service the service with which this factory is registered.
+   * @param status the error code status.
+   * @return the service object, or NULL if the factory does not support the key.
+   */
+  virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
+
+  /**
+   * <p>This implementation adds a mapping from ID -> this to result if visible is TRUE, 
+   * otherwise it removes ID from result.</p>
+   *
+   * @param result the mapping table to update.
+   * @param status the error code status.
+   */
+  virtual void updateVisibleIDs(Hashtable& result, UErrorCode& status) const;
+
+  /**
+   * <p>This implementation returns the factory ID if it equals id and visible is TRUE,
+   * otherwise it returns the empty string.  (This implementation provides
+   * no localized id information.)</p>
+   *
+   * @param id a visible id supported by this factory.
+   * @param locale the locale for which to generate the corresponding localized display name.
+   * @param result output parameter to hold the display name.
+   * @return result.
+   */
+  virtual UnicodeString& getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const;
+
+public:
+ /**
+  * UObject RTTI boilerplate.
+  */
+  static UClassID U_EXPORT2 getStaticClassID();
+
+ /**
+  * UObject RTTI boilerplate.
+  */
+  virtual UClassID getDynamicClassID() const;
+
+#ifdef SERVICE_DEBUG
+ public:
+  virtual UnicodeString& debug(UnicodeString& toAppendTo) const;
+  virtual UnicodeString& debugClass(UnicodeString& toAppendTo) const;
+#endif
+
+};
+
+/*
+ ******************************************************************
+ */
+
+/**
+ * <p>ServiceListener is the listener that ICUService provides by default.
+ * ICUService will notifiy this listener when factories are added to
+ * or removed from the service.  Subclasses can provide
+ * different listener interfaces that extend EventListener, and modify
+ * acceptsListener and notifyListener as appropriate.</p>
+ */
+class U_COMMON_API ServiceListener : public EventListener {
+public:
+    /**
+     * <p>This method is called when the service changes. At the time of the
+     * call this listener is registered with the service.  It must
+     * not modify the notifier in the context of this call.</p>
+     * 
+     * @param service the service that changed.
+     */
+    virtual void serviceChanged(const ICUService& service) const = 0;
+    
+public:
+    /**
+     * UObject RTTI boilerplate.
+     */
+    static UClassID U_EXPORT2 getStaticClassID();
+    
+    /**
+     * UObject RTTI boilerplate.
+     */
+    virtual UClassID getDynamicClassID() const;
+    
+};
+
+/*
+ ******************************************************************
+ */
+
+/**
+ * <p>A StringPair holds a displayName/ID pair.  ICUService uses it
+ * as the array elements returned by getDisplayNames.
+ */
+class U_COMMON_API StringPair : public UMemory {
+public:
+  /**
+   * <p>The display name of the pair.</p>
+   */
+  const UnicodeString displayName;
+
+  /**
+   * <p>The ID of the pair.</p>
+   */
+  const UnicodeString id;
+
+  /**
+   * <p>Creates a string pair from a displayName and an ID.</p>
+   *
+   * @param displayName the displayName.
+   * @param id the ID.
+   * @param status the error code status.
+   * @return a StringPair if the creation was successful, otherwise NULL.
+   */
+  static StringPair* create(const UnicodeString& displayName, 
+                            const UnicodeString& id,
+                            UErrorCode& status);
+
+  /**
+   * <p>Return TRUE if either string of the pair is bogus.</p>
+   * @return TRUE if either string of the pair is bogus.
+   */
+  UBool isBogus() const;
+
+private:
+  StringPair(const UnicodeString& displayName, const UnicodeString& id);
+};
+
+/*******************************************************************
+ * ICUService
+ */
+
+ /**
+ * <p>A Service provides access to service objects that implement a
+ * particular service, e.g. transliterators.  Users provide a String
+ * id (for example, a locale string) to the service, and get back an
+ * object for that id.  Service objects can be any kind of object.  A
+ * new service object is returned for each query. The caller is
+ * responsible for deleting it.</p>
+ *
+ * <p>Services 'canonicalize' the query ID and use the canonical ID to
+ * query for the service.  The service also defines a mechanism to
+ * 'fallback' the ID multiple times.  Clients can optionally request
+ * the actual ID that was matched by a query when they use an ID to
+ * retrieve a service object.</p>
+ *
+ * <p>Service objects are instantiated by ICUServiceFactory objects
+ * registered with the service.  The service queries each
+ * ICUServiceFactory in turn, from most recently registered to
+ * earliest registered, until one returns a service object.  If none
+ * responds with a service object, a fallback ID is generated, and the
+ * process repeats until a service object is returned or until the ID
+ * has no further fallbacks.</p>
+ *
+ * <p>In ICU 2.4, UObject (the base class of service instances) does
+ * not define a polymorphic clone function.  ICUService uses clones to
+ * manage ownership.  Thus, for now, ICUService defines an abstract
+ * method, cloneInstance, that clients must implement to create clones
+ * of the service instances.  This may change in future releases of
+ * ICU.</p>
+ *
+ * <p>ICUServiceFactories can be dynamically registered and
+ * unregistered with the service.  When registered, an
+ * ICUServiceFactory is installed at the head of the factory list, and
+ * so gets 'first crack' at any keys or fallback keys.  When
+ * unregistered, it is removed from the service and can no longer be
+ * located through it.  Service objects generated by this factory and
+ * held by the client are unaffected.</p>
+ *
+ * <p>If a service has variants (e.g., the different variants of
+ * BreakIterator) an ICUServiceFactory can use the prefix of the
+ * ICUServiceKey to determine the variant of a service to generate.
+ * If it does not support all variants, it can request
+ * previously-registered factories to handle the ones it does not
+ * support.</p>
+ *
+ * <p>ICUService uses ICUServiceKeys to query factories and perform
+ * fallback.  The ICUServiceKey defines the canonical form of the ID,
+ * and implements the fallback strategy.  Custom ICUServiceKeys can be
+ * defined that parse complex IDs into components that
+ * ICUServiceFactories can more easily use.  The ICUServiceKey can
+ * cache the results of this parsing to save repeated effort.
+ * ICUService provides convenience APIs that take UnicodeStrings and
+ * generate default ICUServiceKeys for use in querying.</p>
+ *
+ * <p>ICUService provides API to get the list of IDs publicly
+ * supported by the service (although queries aren't restricted to
+ * this list).  This list contains only 'simple' IDs, and not fully
+ * unique IDs.  ICUServiceFactories are associated with each simple ID
+ * and the responsible factory can also return a human-readable
+ * localized version of the simple ID, for use in user interfaces.
+ * ICUService can also provide an array of the all the localized
+ * visible IDs and their corresponding internal IDs.</p>
+ *
+ * <p>ICUService implements ICUNotifier, so that clients can register
+ * to receive notification when factories are added or removed from
+ * the service.  ICUService provides a default EventListener
+ * subinterface, ServiceListener, which can be registered with the
+ * service.  When the service changes, the ServiceListener's
+ * serviceChanged method is called with the service as the
+ * argument.</p>
+ *
+ * <p>The ICUService API is both rich and generic, and it is expected
+ * that most implementations will statically 'wrap' ICUService to
+ * present a more appropriate API-- for example, to declare the type
+ * of the objects returned from get, to limit the factories that can
+ * be registered with the service, or to define their own listener
+ * interface with a custom callback method.  They might also customize
+ * ICUService by overriding it, for example, to customize the
+ * ICUServiceKey and fallback strategy.  ICULocaleService is a
+ * subclass of ICUService that uses Locale names as IDs and uses
+ * ICUServiceKeys that implement the standard resource bundle fallback
+ * strategy.  Most clients will wish to subclass it instead of
+ * ICUService.</p> 
+ */
+class U_COMMON_API ICUService : public ICUNotifier {
+ protected: 
+    /**
+     * Name useful for debugging.
+     */
+    const UnicodeString name;
+
+ private:
+
+    /**
+     * single lock used by this service.
+     */
+    UMTX lock;
+
+    /**
+     * Timestamp so iterators can be fail-fast.
+     */
+    uint32_t timestamp;
+
+    /**
+     * All the factories registered with this service.
+     */
+    UVector* factories;
+
+    /**
+     * The service cache.
+     */
+    Hashtable* serviceCache;
+
+    /**
+     * The ID cache.
+     */
+    Hashtable* idCache;
+
+    /**
+     * The name cache.
+     */
+    DNCache* dnCache;
+
+    /**
+     * Constructor.
+     */
+ public:
+    /**
+     * <p>Construct a new ICUService.</p>
+     */
+    ICUService();
+
+    /**
+     * <p>Construct with a name (useful for debugging).</p>
+     *
+     * @param name a name to use in debugging.
+     */
+    ICUService(const UnicodeString& name);
+
+    /**
+     * <p>Destructor.</p>
+     */
+    virtual ~ICUService();
+
+    /**
+     * <p>Return the name of this service. This will be the empty string if none was assigned.
+     * Returns result as a convenience.</p>
+     *
+     * @param result an output parameter to contain the name of this service.
+     * @return the name of this service.
+     */
+    UnicodeString& getName(UnicodeString& result) const;
+
+    /**
+     * <p>Convenience override for get(ICUServiceKey&, UnicodeString*). This uses
+     * createKey to create a key for the provided descriptor.</p>
+     *
+     * @param descriptor the descriptor.
+     * @param status the error code status.
+     * @return the service instance, or NULL.
+     */
+    UObject* get(const UnicodeString& descriptor, UErrorCode& status) const;
+
+    /**
+     * <p>Convenience override for get(ICUServiceKey&, UnicodeString*).  This uses
+     * createKey to create a key from the provided descriptor.</p>
+     *
+     * @param descriptor the descriptor.
+     * @param actualReturn a pointer to a UnicodeString to hold the matched descriptor, or NULL.
+     * @param status the error code status.
+     * @return the service instance, or NULL.
+     */
+    UObject* get(const UnicodeString& descriptor, UnicodeString* actualReturn, UErrorCode& status) const;
+
+    /**
+     * <p>Convenience override for get(ICUServiceKey&, UnicodeString*).</p>
+     *
+     * @param key the key.
+     * @param status the error code status.
+     * @return the service instance, or NULL.
+     */
+    UObject* getKey(ICUServiceKey& key, UErrorCode& status) const;
+
+    /**
+     * <p>Given a key, return a service object, and, if actualReturn
+     * is not NULL, the descriptor with which it was found in the
+     * first element of actualReturn.  If no service object matches
+     * this key, returns NULL and leaves actualReturn unchanged.</p>
+     *
+     * <p>This queries the cache using the key's descriptor, and if no
+     * object in the cache matches, tries the key on each
+     * registered factory, in order.  If none generates a service
+     * object for the key, repeats the process with each fallback of
+     * the key, until either a factory returns a service object, or the key
+     * has no fallback.  If no object is found, the result of handleDefault
+     * is returned.</p>
+     *
+     * <p>Subclasses can override this method to further customize the 
+     * result before returning it.
+     *
+     * @param key the key.
+     * @param actualReturn a pointer to a UnicodeString to hold the matched descriptor, or NULL.
+     * @param status the error code status.
+     * @return the service instance, or NULL.
+     */
+    virtual UObject* getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const;
+
+    /**
+     * <p>This version of getKey is only called by ICUServiceFactories within the scope
+     * of a previous getKey call, to determine what previously-registered factories would
+     * have returned.  For details, see getKey(ICUServiceKey&, UErrorCode&).  Subclasses
+     * should not call it directly, but call through one of the other get functions.</p>
+     * 
+     * @param key the key.
+     * @param actualReturn a pointer to a UnicodeString to hold the matched descriptor, or NULL.
+     * @param factory the factory making the recursive call.
+     * @param status the error code status.
+     * @return the service instance, or NULL.
+     */
+    UObject* getKey(ICUServiceKey& key, UnicodeString* actualReturn, const ICUServiceFactory* factory, UErrorCode& status) const;
+
+    /**
+     * <p>Convenience override for getVisibleIDs(String) that passes null
+     * as the fallback, thus returning all visible IDs.</p>
+     *
+     * @param result a vector to hold the returned IDs.
+     * @param status the error code status.
+     * @return the result vector.
+     */
+    UVector& getVisibleIDs(UVector& result, UErrorCode& status) const;
+
+    /**
+     * <p>Return a snapshot of the visible IDs for this service.  This
+     * list will not change as ICUServiceFactories are added or removed, but the
+     * supported IDs will, so there is no guarantee that all and only
+     * the IDs in the returned list will be visible and supported by the
+     * service in subsequent calls.</p>
+     *
+     * <p>The IDs are returned as pointers to UnicodeStrings.  The
+     * caller owns the IDs.  Previous contents of result are discarded before
+     * new elements, if any, are added.</p>
+     *
+     * <p>matchID is passed to createKey to create a key.  If the key
+     * is not NULL, its isFallbackOf method is used to filter out IDs
+     * that don't match the key or have it as a fallback.</p>
+     *
+     * @param result a vector to hold the returned IDs.
+     * @param matchID an ID used to filter the result, or NULL if all IDs are desired.
+     * @param status the error code status.
+     * @return the result vector.
+     */
+    UVector& getVisibleIDs(UVector& result, const UnicodeString* matchID, UErrorCode& status) const;
+
+    /**
+     * <p>Convenience override for getDisplayName(const UnicodeString&, const Locale&, UnicodeString&) that
+     * uses the current default locale.</p>
+     *
+     * @param id the ID for which to retrieve the localized displayName.
+     * @param result an output parameter to hold the display name.
+     * @return the modified result.
+     */
+    UnicodeString& getDisplayName(const UnicodeString& id, UnicodeString& result) const;
+
+    /**
+     * <p>Given a visible ID, return the display name in the requested locale.
+     * If there is no directly supported ID corresponding to this ID, result is
+     * set to bogus.</p>
+     *
+     * @param id the ID for which to retrieve the localized displayName.
+     * @param result an output parameter to hold the display name.
+     * @param locale the locale in which to localize the ID.
+     * @return the modified result.
+     */
+    UnicodeString& getDisplayName(const UnicodeString& id, UnicodeString& result, const Locale& locale) const;
+
+    /**
+     * <p>Convenience override of getDisplayNames(const Locale&, const UnicodeString*) that 
+     * uses the current default Locale as the locale and NULL for
+     * the matchID.</p>
+     *
+     * @param result a vector to hold the returned displayName/id StringPairs.
+     * @param status the error code status.
+     * @return the modified result vector.
+     */
+    UVector& getDisplayNames(UVector& result, UErrorCode& status) const;
+
+    /**
+     * <p>Convenience override of getDisplayNames(const Locale&, const UnicodeString*) that 
+     * uses NULL for the matchID.</p>
+     *
+     * @param result a vector to hold the returned displayName/id StringPairs.
+     * @param locale the locale in which to localize the ID.
+     * @param status the error code status.
+     * @return the modified result vector.
+     */
+    UVector& getDisplayNames(UVector& result, const Locale& locale, UErrorCode& status) const;
+
+    /**
+     * <p>Return a snapshot of the mapping from display names to visible
+     * IDs for this service.  This set will not change as factories
+     * are added or removed, but the supported IDs will, so there is
+     * no guarantee that all and only the IDs in the returned map will
+     * be visible and supported by the service in subsequent calls,
+     * nor is there any guarantee that the current display names match
+     * those in the result.</p>
+     *
+     * <p>The names are returned as pointers to StringPairs, which
+     * contain both the displayName and the corresponding ID.  The
+     * caller owns the StringPairs.  Previous contents of result are
+     * discarded before new elements, if any, are added.</p>
+     *
+     * <p>matchID is passed to createKey to create a key.  If the key
+     * is not NULL, its isFallbackOf method is used to filter out IDs
+     * that don't match the key or have it as a fallback.</p>
+     *
+     * @param result a vector to hold the returned displayName/id StringPairs.
+     * @param locale the locale in which to localize the ID.
+     * @param matchID an ID used to filter the result, or NULL if all IDs are desired.
+     * @param status the error code status.
+     * @return the result vector.  */
+    UVector& getDisplayNames(UVector& result,
+                             const Locale& locale, 
+                             const UnicodeString* matchID, 
+                             UErrorCode& status) const;
+
+    /**
+     * <p>A convenience override of registerInstance(UObject*, const UnicodeString&, UBool)
+     * that defaults visible to TRUE.</p>
+     *
+     * @param objToAdopt the object to register and adopt.
+     * @param id the ID to assign to this object.
+     * @param status the error code status.
+     * @return a registry key that can be passed to unregister to unregister
+     * (and discard) this instance.
+     */
+    URegistryKey registerInstance(UObject* objToAdopt, const UnicodeString& id, UErrorCode& status);
+
+    /**
+     * <p>Register a service instance with the provided ID.  The ID will be 
+     * canonicalized.  The canonicalized ID will be returned by
+     * getVisibleIDs if visible is TRUE.  The service instance will be adopted and
+     * must not be modified subsequent to this call.</p>
+     *
+     * <p>This issues a serviceChanged notification to registered listeners.</p>
+     *
+     * <p>This implementation wraps the object using
+     * createSimpleFactory, and calls registerFactory.</p>
+     *
+     * @param objToAdopt the object to register and adopt.
+     * @param id the ID to assign to this object.
+     * @param visible TRUE if getVisibleIDs is to return this ID.
+     * @param status the error code status.
+     * @return a registry key that can be passed to unregister() to unregister
+     * (and discard) this instance.
+     */
+    virtual URegistryKey registerInstance(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status);
+
+    /**
+     * <p>Register an ICUServiceFactory.  Returns a registry key that
+     * can be used to unregister the factory.  The factory
+     * must not be modified subsequent to this call.  The service owns
+     * all registered factories. In case of an error, the factory is
+     * deleted.</p>
+     *
+     * <p>This issues a serviceChanged notification to registered listeners.</p>
+     *
+     * <p>The default implementation accepts all factories.</p>
+     *
+     * @param factoryToAdopt the factory to register and adopt.
+     * @param status the error code status.
+     * @return a registry key that can be passed to unregister to unregister
+     * (and discard) this factory.
+     */
+    virtual URegistryKey registerFactory(ICUServiceFactory* factoryToAdopt, UErrorCode& status);
+
+    /**
+     * <p>Unregister a factory using a registry key returned by
+     * registerInstance or registerFactory.  After a successful call,
+     * the factory will be removed from the service factory list and
+     * deleted, and the key becomes invalid.</p>
+     *
+     * <p>This issues a serviceChanged notification to registered
+     * listeners.</p>
+     *
+     * @param rkey the registry key.
+     * @param status the error code status.  
+     * @return TRUE if the call successfully unregistered the factory.
+     */
+    virtual UBool unregister(URegistryKey rkey, UErrorCode& status);
+
+    /**
+     * </p>Reset the service to the default factories.  The factory
+     * lock is acquired and then reInitializeFactories is called.</p>
+     *
+     * <p>This issues a serviceChanged notification to registered listeners.</p>
+     */
+    virtual void reset(void);
+
+    /**
+     * <p>Return TRUE if the service is in its default state.</p>
+     *
+     * <p>The default implementation returns TRUE if there are no 
+     * factories registered.</p>
+     */
+    virtual UBool isDefault(void) const;
+
+    /**
+     * <p>Create a key from an ID.  If ID is NULL, returns NULL.</p>
+     *
+     * <p>The default implementation creates an ICUServiceKey instance.
+     * Subclasses can override to define more useful keys appropriate
+     * to the factories they accept.</p>
+     *
+     * @param a pointer to the ID for which to create a default ICUServiceKey.
+     * @param status the error code status.
+     * @return the ICUServiceKey corresponding to ID, or NULL.
+     */
+    virtual ICUServiceKey* createKey(const UnicodeString* id, UErrorCode& status) const;
+
+    /**
+     * <p>Clone object so that caller can own the copy.  In ICU2.4, UObject doesn't define
+     * clone, so we need an instance-aware method that knows how to do this.
+     * This is public so factories can call it, but should really be protected.</p>
+     *
+     * @param instance the service instance to clone.
+     * @return a clone of the passed-in instance, or NULL if cloning was unsuccessful.
+     */
+    virtual UObject* cloneInstance(UObject* instance) const = 0;
+
+
+    /************************************************************************
+     * Subclassing API
+     */
+
+ protected:
+
+    /**
+     * <p>Create a factory that wraps a single service object.  Called by registerInstance.</p>
+     *
+     * <p>The default implementation returns an instance of SimpleFactory.</p>
+     *
+     * @param instanceToAdopt the service instance to adopt.
+     * @param id the ID to assign to this service instance.
+     * @param visible if TRUE, the ID will be visible.
+     * @param status the error code status.
+     * @return an instance of ICUServiceFactory that maps this instance to the provided ID.
+     */
+    virtual ICUServiceFactory* createSimpleFactory(UObject* instanceToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status);
+
+    /**
+     * <p>Reinitialize the factory list to its default state.  After this call, isDefault()
+     * must return TRUE.</p>
+     *
+     * <p>This issues a serviceChanged notification to registered listeners.</p>
+     *
+     * <p>The default implementation clears the factory list.
+     * Subclasses can override to provide other default initialization
+     * of the factory list.  Subclasses must not call this method
+     * directly, since it must only be called while holding write
+     * access to the factory list.</p>
+     */
+    virtual void reInitializeFactories(void);
+
+    /**
+     * <p>Default handler for this service if no factory in the factory list
+     * handled the key passed to getKey.</p>
+     *
+     * <p>The default implementation returns NULL.</p>
+     *
+     * @param key the key.
+     * @param actualReturn a pointer to a UnicodeString to hold the matched descriptor, or NULL.
+     * @param status the error code status.
+     * @return the service instance, or NULL.
+     */
+    virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const;
+
+    /**
+     * <p>Clear caches maintained by this service.</p>
+     *
+     * <p>Subclasses can override if they implement additional caches
+     * that need to be cleared when the service changes.  Subclasses
+     * should generally not call this method directly, as it must only
+     * be called while synchronized on the factory lock.</p>
+     */
+    virtual void clearCaches(void);
+
+    /**
+     * <p>Return true if the listener is accepted.</p>
+     *
+     * <p>The default implementation accepts the listener if it is
+     * a ServiceListener.  Subclasses can override this to accept
+     * different listeners.</p>
+     *
+     * @param l the listener to test.
+     * @return TRUE if the service accepts the listener.
+     */
+    virtual UBool acceptsListener(const EventListener& l) const;
+
+    /**
+     * <p>Notify the listener of a service change.</p>
+     *
+     * <p>The default implementation assumes a ServiceListener.
+     * If acceptsListener has been overridden to accept different
+     * listeners, this should be overridden as well.</p>
+     *
+     * @param l the listener to notify.
+     */
+    virtual void notifyListener(EventListener& l) const;
+
+    /************************************************************************
+     * Utilities for subclasses.
+     */
+
+    /**
+     * <p>Clear only the service cache.</p>
+     *
+     * <p>This can be called by subclasses when a change affects the service
+     * cache but not the ID caches, e.g., when the default locale changes
+     * the resolution of IDs also changes, requiring the cache to be
+     * flushed, but not the visible IDs themselves.</p>
+     */
+    void clearServiceCache(void);
+
+    /**
+     * <p>Return a map from visible IDs to factories.
+     * This must only be called when the mutex is held.</p>
+     *
+     * @param status the error code status.
+     * @return a Hashtable containing mappings from visible
+     * IDs to factories.
+     */
+    const Hashtable* getVisibleIDMap(UErrorCode& status) const;
+
+    /**
+     * <p>Allow subclasses to read the time stamp.</p>
+     *
+     * @return the timestamp.
+     */
+    int32_t getTimestamp(void) const;
+
+    /**
+     * <p>Return the number of registered factories.</p>
+     *
+     * @return the number of factories registered at the time of the call.
+     */
+    int32_t countFactories(void) const;
+
+private:
+
+    friend class ::ICUServiceTest; // give tests access to countFactories.
+};
+
+U_NAMESPACE_END
+
+    /* UCONFIG_NO_SERVICE */
+#endif
+
+    /* ICUSERV_H */
+#endif
+
diff --git a/source/common/servlk.cpp b/source/common/servlk.cpp
new file mode 100644
index 0000000..b620414
--- /dev/null
+++ b/source/common/servlk.cpp
@@ -0,0 +1,187 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2001-2004, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ *******************************************************************************
+ */
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_SERVICE
+
+#include "unicode/resbund.h"
+#include "uresimp.h"
+#include "cmemory.h"
+#include "servloc.h"
+#include "ustrfmt.h"
+#include "uhash.h"
+#include "charstr.h"
+#include "ucln_cmn.h"
+#include "uassert.h"
+
+#define UNDERSCORE_CHAR ((UChar)0x005f)
+#define AT_SIGN_CHAR    ((UChar)64)
+#define PERIOD_CHAR     ((UChar)46)
+
+U_NAMESPACE_BEGIN
+
+LocaleKey*
+LocaleKey::createWithCanonicalFallback(const UnicodeString* primaryID,
+                                       const UnicodeString* canonicalFallbackID,
+                                       UErrorCode& status)
+{
+    return LocaleKey::createWithCanonicalFallback(primaryID, canonicalFallbackID, KIND_ANY, status);
+}
+
+LocaleKey*
+LocaleKey::createWithCanonicalFallback(const UnicodeString* primaryID,
+                                       const UnicodeString* canonicalFallbackID,
+                                       int32_t kind,
+                                       UErrorCode& status)
+{
+    if (primaryID == NULL || U_FAILURE(status)) {
+        return NULL;
+    }
+    UnicodeString canonicalPrimaryID;
+    LocaleUtility::canonicalLocaleString(primaryID, canonicalPrimaryID);
+    return new LocaleKey(*primaryID, canonicalPrimaryID, canonicalFallbackID, kind);
+}
+
+LocaleKey::LocaleKey(const UnicodeString& primaryID,
+                     const UnicodeString& canonicalPrimaryID,
+                     const UnicodeString* canonicalFallbackID,
+                     int32_t kind)
+  : ICUServiceKey(primaryID)
+  , _kind(kind)
+  , _primaryID(canonicalPrimaryID)
+  , _fallbackID()
+  , _currentID()
+{
+    _fallbackID.setToBogus();
+    if (_primaryID.length() != 0) {
+        if (canonicalFallbackID != NULL && _primaryID != *canonicalFallbackID) {
+            _fallbackID = *canonicalFallbackID;
+        }
+    }
+
+    _currentID = _primaryID;
+}
+
+LocaleKey::~LocaleKey() {}
+
+UnicodeString&
+LocaleKey::prefix(UnicodeString& result) const {
+    if (_kind != KIND_ANY) {
+        UChar buffer[64];
+        uprv_itou(buffer, 64, _kind, 10, 0);
+        UnicodeString temp(buffer);
+        result.append(temp);
+    }
+    return result;
+}
+
+int32_t
+LocaleKey::kind() const {
+    return _kind;
+}
+
+UnicodeString&
+LocaleKey::canonicalID(UnicodeString& result) const {
+    return result.append(_primaryID);
+}
+
+UnicodeString&
+LocaleKey::currentID(UnicodeString& result) const {
+    if (!_currentID.isBogus()) {
+        result.append(_currentID);
+    }
+    return result;
+}
+
+UnicodeString&
+LocaleKey::currentDescriptor(UnicodeString& result) const {
+    if (!_currentID.isBogus()) {
+        prefix(result).append(PREFIX_DELIMITER).append(_currentID);
+    } else {
+        result.setToBogus();
+    }
+    return result;
+}
+
+Locale&
+LocaleKey::canonicalLocale(Locale& result) const {
+    return LocaleUtility::initLocaleFromName(_primaryID, result);
+}
+
+Locale&
+LocaleKey::currentLocale(Locale& result) const {
+    return LocaleUtility::initLocaleFromName(_currentID, result);
+}
+
+UBool
+LocaleKey::fallback() {
+    if (!_currentID.isBogus()) {
+        int x = _currentID.lastIndexOf(UNDERSCORE_CHAR);
+        if (x != -1) {
+            _currentID.remove(x); // truncate current or fallback, whichever we're pointing to
+            return TRUE;
+        }
+
+        if (!_fallbackID.isBogus()) {
+            _currentID = _fallbackID;
+            _fallbackID.setToBogus();
+            return TRUE;
+        }
+
+        if (_currentID.length() > 0) {
+            _currentID.remove(0); // completely truncate
+            return TRUE;
+        }
+
+        _currentID.setToBogus();
+    }
+
+    return FALSE;
+}
+
+UBool
+LocaleKey::isFallbackOf(const UnicodeString& id) const {
+    UnicodeString temp(id);
+    parseSuffix(temp);
+    return temp.indexOf(_primaryID) == 0 &&
+        (temp.length() == _primaryID.length() ||
+        temp.charAt(_primaryID.length()) == UNDERSCORE_CHAR);
+}
+
+#ifdef SERVICE_DEBUG
+UnicodeString&
+LocaleKey::debug(UnicodeString& result) const
+{
+    ICUServiceKey::debug(result);
+    result.append(" kind: ");
+    result.append(_kind);
+    result.append(" primaryID: ");
+    result.append(_primaryID);
+    result.append(" fallbackID: ");
+    result.append(_fallbackID);
+    result.append(" currentID: ");
+    result.append(_currentID);
+    return result;
+}
+
+UnicodeString&
+LocaleKey::debugClass(UnicodeString& result) const
+{
+    return result.append("LocaleKey ");
+}
+#endif
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LocaleKey)
+
+U_NAMESPACE_END
+
+/* !UCONFIG_NO_SERVICE */
+#endif
+
+
diff --git a/source/common/servlkf.cpp b/source/common/servlkf.cpp
new file mode 100644
index 0000000..c455080
--- /dev/null
+++ b/source/common/servlkf.cpp
@@ -0,0 +1,151 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2001-2005, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ *******************************************************************************
+ */
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_SERVICE
+
+#include "unicode/resbund.h"
+#include "uresimp.h"
+#include "cmemory.h"
+#include "servloc.h"
+#include "ustrfmt.h"
+#include "uhash.h"
+#include "charstr.h"
+#include "ucln_cmn.h"
+#include "uassert.h"
+
+#define UNDERSCORE_CHAR ((UChar)0x005f)
+#define AT_SIGN_CHAR    ((UChar)64)
+#define PERIOD_CHAR     ((UChar)46)
+
+
+U_NAMESPACE_BEGIN
+
+LocaleKeyFactory::LocaleKeyFactory(int32_t coverage)
+  : _name()
+  , _coverage(coverage)
+{
+}
+
+LocaleKeyFactory::LocaleKeyFactory(int32_t coverage, const UnicodeString& name)
+  : _name(name)
+  , _coverage(coverage)
+{
+}
+
+LocaleKeyFactory::~LocaleKeyFactory() {
+}
+
+UObject*
+LocaleKeyFactory::create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const {
+    if (handlesKey(key, status)) {
+        const LocaleKey& lkey = (const LocaleKey&)key;
+        int32_t kind = lkey.kind();
+        Locale loc;
+        lkey.currentLocale(loc);
+
+        return handleCreate(loc, kind, service, status);
+    }
+    return NULL;
+}
+
+UBool
+LocaleKeyFactory::handlesKey(const ICUServiceKey& key, UErrorCode& status) const {
+    const Hashtable* supported = getSupportedIDs(status);
+    if (supported) {
+        UnicodeString id;
+        key.currentID(id);
+        return supported->get(id) != NULL;
+    }
+    return FALSE;
+}
+
+void
+LocaleKeyFactory::updateVisibleIDs(Hashtable& result, UErrorCode& status) const {
+    const Hashtable* supported = getSupportedIDs(status);
+    if (supported) {
+        UBool visible = (_coverage & 0x1) == 0;
+
+        const UHashElement* elem = NULL;
+        int32_t pos = 0;
+        while ((elem = supported->nextElement(pos)) != NULL) {
+            const UnicodeString& id = *((const UnicodeString*)elem->key.pointer);
+            if (!visible) {
+                result.remove(id);
+            } else {
+                result.put(id, (void*)this, status); // this is dummy non-void marker used for set semantics
+                if (U_FAILURE(status)) {
+                    break;
+                }
+            }
+        }
+    }
+}
+
+UnicodeString&
+LocaleKeyFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const {
+    if ((_coverage & 0x1) == 0) {
+        //UErrorCode status = U_ZERO_ERROR;
+        // assume if this is called on us, we support some fallback of this id
+        // if (isSupportedID(id, status)) {
+            Locale loc;
+            LocaleUtility::initLocaleFromName(id, loc);
+            return loc.getDisplayName(locale, result);
+        // }
+    }
+    result.setToBogus();
+    return result;
+}
+
+UObject*
+LocaleKeyFactory::handleCreate(const Locale& /* loc */, 
+                   int32_t /* kind */, 
+                   const ICUService* /* service */, 
+                   UErrorCode& /* status */) const {
+    return NULL;
+}
+
+//UBool
+//LocaleKeyFactory::isSupportedID(const UnicodeString& id, UErrorCode& status) const {
+//    const Hashtable* ids = getSupportedIDs(status);
+//    return ids && ids->get(id);
+//}
+
+const Hashtable*
+LocaleKeyFactory::getSupportedIDs(UErrorCode& /* status */) const {
+    return NULL;
+}
+
+#ifdef SERVICE_DEBUG
+UnicodeString&
+LocaleKeyFactory::debug(UnicodeString& result) const
+{
+    debugClass(result);
+    result.append(", name: ");
+    result.append(_name);
+    result.append(", coverage: ");
+    result.append(_coverage);
+    return result;
+}
+
+UnicodeString&
+LocaleKeyFactory::debugClass(UnicodeString& result) const
+{
+  return result.append("LocaleKeyFactory");
+}
+#endif
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LocaleKeyFactory)
+
+U_NAMESPACE_END
+
+/* !UCONFIG_NO_SERVICE */
+#endif
+
+
diff --git a/source/common/servloc.h b/source/common/servloc.h
new file mode 100644
index 0000000..d08b09e
--- /dev/null
+++ b/source/common/servloc.h
@@ -0,0 +1,550 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2001-2005, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ *******************************************************************************
+ */
+#ifndef ICULSERV_H
+#define ICULSERV_H
+
+#include "unicode/utypes.h"
+
+#if UCONFIG_NO_SERVICE
+
+U_NAMESPACE_BEGIN
+
+/*
+ * Allow the declaration of APIs with pointers to ICUService
+ * even when service is removed from the build.
+ */
+class ICULocaleService;
+
+U_NAMESPACE_END
+
+#else
+
+#include "unicode/unistr.h"
+#include "unicode/locid.h"
+#include "unicode/strenum.h"
+
+#include "hash.h"
+#include "uvector.h"
+
+#include "serv.h"
+#include "locutil.h"
+
+U_NAMESPACE_BEGIN
+
+class ICULocaleService;
+
+class LocaleKey;
+class LocaleKeyFactory;
+class SimpleLocaleKeyFactory;
+class ServiceListener;
+
+/*
+ ******************************************************************
+ */
+
+/**
+ * A subclass of Key that implements a locale fallback mechanism.
+ * The first locale to search for is the locale provided by the
+ * client, and the fallback locale to search for is the current
+ * default locale.  If a prefix is present, the currentDescriptor
+ * includes it before the locale proper, separated by "/".  This
+ * is the default key instantiated by ICULocaleService.</p>
+ *
+ * <p>Canonicalization adjusts the locale string so that the
+ * section before the first understore is in lower case, and the rest
+ * is in upper case, with no trailing underscores.</p> 
+ */
+
+class U_COMMON_API LocaleKey : public ICUServiceKey {
+  private: 
+    int32_t _kind;
+    UnicodeString _primaryID;
+    UnicodeString _fallbackID;
+    UnicodeString _currentID;
+
+  public:
+    enum {
+        KIND_ANY = -1
+    };
+
+    /**
+     * Create a LocaleKey with canonical primary and fallback IDs.
+     */
+    static LocaleKey* createWithCanonicalFallback(const UnicodeString* primaryID, 
+                                                  const UnicodeString* canonicalFallbackID,
+                                                  UErrorCode& status);
+
+    /**
+     * Create a LocaleKey with canonical primary and fallback IDs.
+     */
+    static LocaleKey* createWithCanonicalFallback(const UnicodeString* primaryID, 
+                                                  const UnicodeString* canonicalFallbackID, 
+                                                  int32_t kind,
+                                                  UErrorCode& status);
+
+  protected:
+    /**
+     * PrimaryID is the user's requested locale string,
+     * canonicalPrimaryID is this string in canonical form,
+     * fallbackID is the current default locale's string in
+     * canonical form.
+     */
+    LocaleKey(const UnicodeString& primaryID, 
+              const UnicodeString& canonicalPrimaryID, 
+              const UnicodeString* canonicalFallbackID, 
+              int32_t kind);
+
+ public:
+    /**
+     * Append the prefix associated with the kind, or nothing if the kind is KIND_ANY.
+     */
+    virtual UnicodeString& prefix(UnicodeString& result) const;
+
+    /**
+     * Return the kind code associated with this key.
+     */
+    virtual int32_t kind() const;
+
+    /**
+     * Return the canonicalID.
+     */
+    virtual UnicodeString& canonicalID(UnicodeString& result) const;
+
+    /**
+     * Return the currentID.
+     */
+    virtual UnicodeString& currentID(UnicodeString& result) const;
+
+    /**
+     * Return the (canonical) current descriptor, or null if no current id.
+     */
+    virtual UnicodeString& currentDescriptor(UnicodeString& result) const;
+
+    /**
+     * Convenience method to return the locale corresponding to the (canonical) original ID.
+     */
+    virtual Locale& canonicalLocale(Locale& result) const;
+
+    /**
+     * Convenience method to return the locale corresponding to the (canonical) current ID.
+     */
+    virtual Locale& currentLocale(Locale& result) const;
+
+    /**
+     * If the key has a fallback, modify the key and return true,
+     * otherwise return false.</p>
+     *
+     * <p>First falls back through the primary ID, then through
+     * the fallbackID.  The final fallback is the empty string,
+     * unless the primary id was the empty string, in which case
+     * there is no fallback.  
+     */
+    virtual UBool fallback();
+
+    /**
+     * Return true if a key created from id matches, or would eventually
+     * fallback to match, the canonical ID of this key.  
+     */
+    virtual UBool isFallbackOf(const UnicodeString& id) const;
+    
+ public:
+    /**
+     * UObject boilerplate.
+     */
+    static UClassID U_EXPORT2 getStaticClassID();
+
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * Destructor.
+     */
+    virtual ~LocaleKey();
+
+#ifdef SERVICE_DEBUG
+ public:
+    virtual UnicodeString& debug(UnicodeString& result) const;
+    virtual UnicodeString& debugClass(UnicodeString& result) const;
+#endif
+
+};
+
+/*
+ ******************************************************************
+ */
+
+/**
+ * A subclass of ICUServiceFactory that uses LocaleKeys, and is able to
+ * 'cover' more specific locales with more general locales that it
+ * supports.  
+ *
+ * <p>Coverage may be either of the values VISIBLE or INVISIBLE.
+ *
+ * <p>'Visible' indicates that the specific locale(s) supported by
+ * the factory are registered in getSupportedIDs, 'Invisible'
+ * indicates that they are not.
+ *
+ * <p>Localization of visible ids is handled
+ * by the handling factory, regardless of kind.
+ */
+class U_COMMON_API LocaleKeyFactory : public ICUServiceFactory {
+protected:
+    const UnicodeString _name;
+    const int32_t _coverage;
+
+public:
+    enum {
+        /**
+         * Coverage value indicating that the factory makes
+         * its locales visible, and does not cover more specific 
+         * locales.
+         */
+        VISIBLE = 0,
+
+        /**
+         * Coverage value indicating that the factory does not make
+         * its locales visible, and does not cover more specific
+         * locales.
+         */
+        INVISIBLE = 1
+    };
+
+    /**
+     * Destructor.
+     */
+    virtual ~LocaleKeyFactory();
+
+protected:
+    /**
+     * Constructor used by subclasses.
+     */
+    LocaleKeyFactory(int32_t coverage);
+
+    /**
+     * Constructor used by subclasses.
+     */
+    LocaleKeyFactory(int32_t coverage, const UnicodeString& name);
+
+    /**
+     * Implement superclass abstract method.  This checks the currentID of
+     * the key against the supported IDs, and passes the canonicalLocale and
+     * kind off to handleCreate (which subclasses must implement).
+     */
+public:
+    virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
+
+protected:
+    virtual UBool handlesKey(const ICUServiceKey& key, UErrorCode& status) const;
+
+public:
+    /**
+     * Override of superclass method.  This adjusts the result based
+     * on the coverage rule for this factory.
+     */
+    virtual void updateVisibleIDs(Hashtable& result, UErrorCode& status) const;
+
+    /**
+     * Return a localized name for the locale represented by id.
+     */
+    virtual UnicodeString& getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const;
+
+protected:
+    /**
+     * Utility method used by create(ICUServiceKey, ICUService).  Subclasses can implement
+     * this instead of create.  The default returns NULL.
+     */
+    virtual UObject* handleCreate(const Locale& loc, int32_t kind, const ICUService* service, UErrorCode& status) const;
+
+   /**
+     * Return true if this id is one the factory supports (visible or 
+     * otherwise).
+     */
+ //   virtual UBool isSupportedID(const UnicodeString& id, UErrorCode& status) const;
+
+   /**
+     * 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;
+
+public:
+    /**
+     * UObject boilerplate.
+     */
+    static UClassID U_EXPORT2 getStaticClassID();
+
+    virtual UClassID getDynamicClassID() const;
+
+#ifdef SERVICE_DEBUG
+ public:
+    virtual UnicodeString& debug(UnicodeString& result) const;
+    virtual UnicodeString& debugClass(UnicodeString& result) const;
+#endif
+
+};
+
+/*
+ ******************************************************************
+ */
+
+/**
+ * A LocaleKeyFactory that just returns a single object for a kind/locale.
+ */
+
+class U_COMMON_API SimpleLocaleKeyFactory : public LocaleKeyFactory {
+ private:
+    UObject* _obj;
+    UnicodeString _id;
+    const int32_t _kind;
+
+ public:
+    SimpleLocaleKeyFactory(UObject* objToAdopt, 
+                           const UnicodeString& locale, 
+                           int32_t kind, 
+                           int32_t coverage);
+
+    SimpleLocaleKeyFactory(UObject* objToAdopt, 
+                           const Locale& locale, 
+                           int32_t kind, 
+                           int32_t coverage);
+
+    /**
+     * Destructor.
+     */
+    virtual ~SimpleLocaleKeyFactory();
+
+    /**
+     * Override of superclass method.  Returns the service object if kind/locale match.  Service is not used.
+     */
+    virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
+
+    /**
+     * Override of superclass method.  This adjusts the result based
+     * on the coverage rule for this factory.
+     */
+    virtual void updateVisibleIDs(Hashtable& result, UErrorCode& status) const;
+
+ protected:
+    /**
+     * Return true if this id is equal to the locale name.
+     */
+    //virtual UBool isSupportedID(const UnicodeString& id, UErrorCode& status) const;
+
+
+public:
+    /**
+     * UObject boilerplate.
+     */
+    static UClassID U_EXPORT2 getStaticClassID();
+
+    virtual UClassID getDynamicClassID() const;
+
+#ifdef SERVICE_DEBUG
+ public:
+    virtual UnicodeString& debug(UnicodeString& result) const;
+    virtual UnicodeString& debugClass(UnicodeString& result) const;
+#endif
+
+};
+
+/*
+ ******************************************************************
+ */
+
+/**
+ * A LocaleKeyFactory that creates a service based on the ICU locale data.
+ * This is a base class for most ICU factories.  Subclasses instantiate it
+ * with a constructor that takes a bundle name, which determines the supported
+ * IDs.  Subclasses then override handleCreate to create the actual service
+ * object.  The default implementation returns a resource bundle.
+ */
+class U_COMMON_API ICUResourceBundleFactory : public LocaleKeyFactory 
+{
+ protected:
+    UnicodeString _bundleName;
+
+ public:
+    /**
+     * Convenience constructor that uses the main ICU bundle name.
+     */
+    ICUResourceBundleFactory();
+
+    /**
+     * A service factory based on ICU resource data in resources with
+     * the given name.  This should be a 'path' that can be passed to
+     * ures_openAvailableLocales, such as U_ICUDATA or U_ICUDATA_COLL.
+     * The empty string is equivalent to U_ICUDATA.
+     */
+    ICUResourceBundleFactory(const UnicodeString& bundleName);
+
+    /**
+     * Destructor
+     */
+    virtual ~ICUResourceBundleFactory();
+
+protected:
+    /**
+     * Return the supported IDs.  This is the set of all locale names in ICULocaleData.
+     */
+    virtual const Hashtable* getSupportedIDs(UErrorCode& status) const;
+
+    /**
+     * Create the service.  The default implementation returns the resource bundle
+     * for the locale, ignoring kind, and service.
+     */
+    virtual UObject* handleCreate(const Locale& loc, int32_t kind, const ICUService* service, UErrorCode& status) const;
+
+public:
+    /**
+     * UObject boilerplate.
+     */
+    static UClassID U_EXPORT2 getStaticClassID();
+    virtual UClassID getDynamicClassID() const;
+
+
+#ifdef SERVICE_DEBUG
+ public:
+    virtual UnicodeString& debug(UnicodeString& result) const;
+    virtual UnicodeString& debugClass(UnicodeString& result) const;
+#endif
+
+};
+
+/*
+ ******************************************************************
+ */
+
+class U_COMMON_API ICULocaleService : public ICUService 
+{
+ private:
+  Locale fallbackLocale;
+  UnicodeString fallbackLocaleName;
+  UMTX llock;
+
+ public:
+  /**
+   * Construct an ICULocaleService.
+   */
+  ICULocaleService();
+
+  /**
+   * Construct an ICULocaleService with a name (useful for debugging).
+   */
+  ICULocaleService(const UnicodeString& name);
+
+  /**
+   * Destructor.
+   */
+  virtual ~ICULocaleService();
+
+#if 0
+  // redeclare because of overload resolution rules?
+  // no, causes ambiguities since both UnicodeString and Locale have constructors that take a const char*
+  // need some compiler flag to remove warnings 
+  UObject* get(const UnicodeString& descriptor, UErrorCode& status) const {
+    return ICUService::get(descriptor, status);
+  }
+
+  UObject* get(const UnicodeString& descriptor, UnicodeString* actualReturn, UErrorCode& status) const {
+    return ICUService::get(descriptor, actualReturn, status);
+  }
+#endif
+
+  /**
+   * Convenience override for callers using locales.  This calls
+   * get(Locale, int, Locale[]) with KIND_ANY for kind and null for
+   * actualReturn.
+   */
+  UObject* get(const Locale& locale, UErrorCode& status) const;
+
+  /**
+   * Convenience override for callers using locales.  This calls
+   * get(Locale, int, Locale[]) with a null actualReturn.
+   */
+  UObject* get(const Locale& locale, int32_t kind, UErrorCode& status) const;
+
+  /**
+   * Convenience override for callers using locales. This calls
+   * get(Locale, String, Locale[]) with a null kind.
+   */
+  UObject* get(const Locale& locale, Locale* actualReturn, UErrorCode& status) const;
+                   
+  /**
+   * Convenience override for callers using locales.  This uses
+   * createKey(Locale.toString(), kind) to create a key, calls getKey, and then
+   * if actualReturn is not null, returns the actualResult from
+   * getKey (stripping any prefix) into a Locale.  
+   */
+  UObject* get(const Locale& locale, int32_t kind, Locale* actualReturn, UErrorCode& status) const;
+
+  /**
+   * Convenience override for callers using locales.  This calls
+   * registerObject(Object, Locale, int32_t kind, int coverage)
+   * passing KIND_ANY for the kind, and VISIBLE for the coverage.
+   */
+  virtual URegistryKey registerInstance(UObject* objToAdopt, const Locale& locale, UErrorCode& status);
+
+  /**
+   * Convenience function for callers using locales.  This calls
+   * registerObject(Object, Locale, int kind, int coverage)
+   * passing VISIBLE for the coverage.
+   */
+  virtual URegistryKey registerInstance(UObject* objToAdopt, const Locale& locale, int32_t kind, UErrorCode& status);
+
+  /**
+   * Convenience function for callers using locales.  This  instantiates
+   * a SimpleLocaleKeyFactory, and registers the factory.
+   */
+  virtual URegistryKey registerInstance(UObject* objToAdopt, const Locale& locale, int32_t kind, int32_t coverage, UErrorCode& status);
+
+
+  /**
+   * (Stop compiler from complaining about hidden overrides.)
+   * Since both UnicodeString and Locale have constructors that take const char*, adding a public
+   * method that takes UnicodeString causes ambiguity at call sites that use const char*.
+   * We really need a flag that is understood by all compilers that will suppress the warning about
+   * hidden overrides.
+   */
+  virtual URegistryKey registerInstance(UObject* objToAdopt, const UnicodeString& locale, UBool visible, UErrorCode& status);
+
+  /**
+   * Convenience method for callers using locales.  This returns the standard
+   * service ID enumeration.
+   */
+  virtual StringEnumeration* getAvailableLocales(void) const;
+
+ protected:
+
+  /**
+   * Return the name of the current fallback locale.  If it has changed since this was
+   * last accessed, the service cache is cleared.
+   */
+  const UnicodeString& validateFallbackLocale() const;
+
+  /**
+   * Override superclass createKey method.
+   */
+  virtual ICUServiceKey* createKey(const UnicodeString* id, UErrorCode& status) const;
+
+  /**
+   * Additional createKey that takes a kind.
+   */
+  virtual ICUServiceKey* createKey(const UnicodeString* id, int32_t kind, UErrorCode& status) const;
+
+  friend class ServiceEnumeration;
+};
+
+U_NAMESPACE_END
+
+    /* UCONFIG_NO_SERVICE */
+#endif
+
+    /* ICULSERV_H */
+#endif
+
diff --git a/source/common/servls.cpp b/source/common/servls.cpp
new file mode 100644
index 0000000..b39e72e
--- /dev/null
+++ b/source/common/servls.cpp
@@ -0,0 +1,297 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2001-2004, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ *******************************************************************************
+ */
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_SERVICE
+
+#include "unicode/resbund.h"
+#include "uresimp.h"
+#include "cmemory.h"
+#include "servloc.h"
+#include "ustrfmt.h"
+#include "uhash.h"
+#include "charstr.h"
+#include "ucln_cmn.h"
+#include "uassert.h"
+
+#define UNDERSCORE_CHAR ((UChar)0x005f)
+#define AT_SIGN_CHAR    ((UChar)64)
+#define PERIOD_CHAR     ((UChar)46)
+
+U_NAMESPACE_BEGIN
+
+ICULocaleService::ICULocaleService()
+  : fallbackLocale(Locale::getDefault())
+  , llock(0)
+{
+  umtx_init(&llock);
+}
+
+ICULocaleService::ICULocaleService(const UnicodeString& dname)
+  : ICUService(dname)
+  , fallbackLocale(Locale::getDefault())
+  , llock(0)
+{
+  umtx_init(&llock);
+}
+
+ICULocaleService::~ICULocaleService()
+{
+  umtx_destroy(&llock);
+}
+
+UObject*
+ICULocaleService::get(const Locale& locale, UErrorCode& status) const
+{
+    return get(locale, LocaleKey::KIND_ANY, NULL, status);
+}
+
+UObject*
+ICULocaleService::get(const Locale& locale, int32_t kind, UErrorCode& status) const
+{
+    return get(locale, kind, NULL, status);
+}
+
+UObject*
+ICULocaleService::get(const Locale& locale, Locale* actualReturn, UErrorCode& status) const
+{
+    return get(locale, LocaleKey::KIND_ANY, actualReturn, status);
+}
+
+UObject*
+ICULocaleService::get(const Locale& locale, int32_t kind, Locale* actualReturn, UErrorCode& status) const
+{
+    UObject* result = NULL;
+    if (U_FAILURE(status)) {
+        return result;
+    }
+
+    UnicodeString locName(locale.getName(), -1, US_INV);
+    if (locName.isBogus()) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+    } else {
+        ICUServiceKey* key = createKey(&locName, kind, status);
+        if (key) {
+            if (actualReturn == NULL) {
+                result = getKey(*key, status);
+            } else {
+                UnicodeString temp;
+                result = getKey(*key, &temp, status);
+
+                if (result != NULL) {
+                    key->parseSuffix(temp);
+                    LocaleUtility::initLocaleFromName(temp, *actualReturn);
+                }
+            }
+            delete key;
+        }
+    }
+    return result;
+}
+
+
+URegistryKey
+ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, 
+    UBool visible, UErrorCode& status)
+{
+    Locale loc;
+    LocaleUtility::initLocaleFromName(locale, loc);
+    return registerInstance(objToAdopt, loc, LocaleKey::KIND_ANY, 
+        visible ? LocaleKeyFactory::VISIBLE : LocaleKeyFactory::INVISIBLE, status);
+}
+
+URegistryKey
+ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, UErrorCode& status)
+{
+    return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY, LocaleKeyFactory::VISIBLE, status);
+}
+
+URegistryKey
+ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, int32_t kind, UErrorCode& status)
+{
+    return registerInstance(objToAdopt, locale, kind, LocaleKeyFactory::VISIBLE, status);
+}
+
+URegistryKey
+ICULocaleService::registerInstance(UObject* objToAdopt, const Locale& locale, int32_t kind, int32_t coverage, UErrorCode& status)
+{
+    ICUServiceFactory * factory = new SimpleLocaleKeyFactory(objToAdopt, locale, kind, coverage);
+    if (factory != NULL) {
+        return registerFactory(factory, status);
+    }
+    delete objToAdopt;
+    return NULL;
+}
+
+#if 0
+URegistryKey
+ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, UErrorCode& status)
+{
+    return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY, LocaleKeyFactory::VISIBLE, status);
+}
+
+URegistryKey
+ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, UBool visible, UErrorCode& status)
+{
+    return registerInstance(objToAdopt, locale, LocaleKey::KIND_ANY,
+                            visible ? LocaleKeyFactory::VISIBLE : LocaleKeyFactory::INVISIBLE,
+                            status);
+}
+
+URegistryKey
+ICULocaleService::registerInstance(UObject* objToAdopt, const UnicodeString& locale, int32_t kind, int32_t coverage, UErrorCode& status)
+{
+    ICUServiceFactory * factory = new SimpleLocaleKeyFactory(objToAdopt, locale, kind, coverage);
+    if (factory != NULL) {
+        return registerFactory(factory, status);
+    }
+    delete objToAdopt;
+    return NULL;
+}
+#endif
+
+class ServiceEnumeration : public StringEnumeration {
+private:
+    const ICULocaleService* _service;
+    int32_t _timestamp;
+    UVector _ids;
+    int32_t _pos;
+
+private:
+    ServiceEnumeration(const ICULocaleService* service, UErrorCode &status)
+        : _service(service)
+        , _timestamp(service->getTimestamp())
+        , _ids(uhash_deleteUnicodeString, NULL, status)
+        , _pos(0)
+    {
+        _service->getVisibleIDs(_ids, status);
+    }
+
+    ServiceEnumeration(const ServiceEnumeration &other, UErrorCode &status)
+        : _service(other._service)
+        , _timestamp(other._timestamp)
+        , _ids(uhash_deleteUnicodeString, NULL, status)
+        , _pos(0)
+    {
+        if(U_SUCCESS(status)) {
+            int32_t i, length;
+
+            length = other._ids.size();
+            for(i = 0; i < length; ++i) {
+                _ids.addElement(((UnicodeString *)other._ids.elementAt(i))->clone(), status);
+            }
+
+            if(U_SUCCESS(status)) {
+                _pos = other._pos;
+            }
+        }
+    }
+
+public:
+    static ServiceEnumeration* create(const ICULocaleService* service) {
+        UErrorCode status = U_ZERO_ERROR;
+        ServiceEnumeration* result = new ServiceEnumeration(service, status);
+        if (U_SUCCESS(status)) {
+            return result;
+        }
+        delete result;
+        return NULL;
+    }
+
+    virtual ~ServiceEnumeration() {}
+
+    virtual StringEnumeration *clone() const {
+        UErrorCode status = U_ZERO_ERROR;
+        ServiceEnumeration *cl = new ServiceEnumeration(*this, status);
+        if(U_FAILURE(status)) {
+            delete cl;
+            cl = NULL;
+        }
+        return cl;
+    }
+
+    UBool upToDate(UErrorCode& status) const {
+        if (U_SUCCESS(status)) {
+            if (_timestamp == _service->getTimestamp()) {
+                return TRUE;
+            }
+            status = U_ENUM_OUT_OF_SYNC_ERROR;
+        }
+        return FALSE;
+    }
+
+    virtual int32_t count(UErrorCode& status) const {
+        return upToDate(status) ? _ids.size() : 0;
+    }
+
+    virtual const UnicodeString* snext(UErrorCode& status) {
+        if (upToDate(status) && (_pos < _ids.size())) {
+            return (const UnicodeString*)_ids[_pos++];
+        }
+        return NULL;
+    }
+
+    virtual void reset(UErrorCode& status) {
+        if (status == U_ENUM_OUT_OF_SYNC_ERROR) {
+            status = U_ZERO_ERROR;
+        }
+        if (U_SUCCESS(status)) {
+            _timestamp = _service->getTimestamp();
+            _pos = 0;
+            _service->getVisibleIDs(_ids, status);
+        }
+    }
+
+public:
+    static UClassID U_EXPORT2 getStaticClassID(void);
+    virtual UClassID getDynamicClassID(void) const;
+};
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceEnumeration)
+
+StringEnumeration*
+ICULocaleService::getAvailableLocales(void) const
+{
+    return ServiceEnumeration::create(this);
+}
+
+const UnicodeString&
+ICULocaleService::validateFallbackLocale() const
+{
+    const Locale&     loc    = Locale::getDefault();
+    ICULocaleService* ncThis = (ICULocaleService*)this;
+    {
+        Mutex mutex(&ncThis->llock);
+        if (loc != fallbackLocale) {
+            ncThis->fallbackLocale = loc;
+            LocaleUtility::initNameFromLocale(loc, ncThis->fallbackLocaleName);
+            ncThis->clearServiceCache();
+        }
+    }
+    return fallbackLocaleName;
+}
+
+ICUServiceKey*
+ICULocaleService::createKey(const UnicodeString* id, UErrorCode& status) const
+{
+    return LocaleKey::createWithCanonicalFallback(id, &validateFallbackLocale(), status);
+}
+
+ICUServiceKey*
+ICULocaleService::createKey(const UnicodeString* id, int32_t kind, UErrorCode& status) const
+{
+    return LocaleKey::createWithCanonicalFallback(id, &validateFallbackLocale(), kind, status);
+}
+
+U_NAMESPACE_END
+
+/* !UCONFIG_NO_SERVICE */
+#endif
+
+
diff --git a/source/common/servnotf.cpp b/source/common/servnotf.cpp
new file mode 100644
index 0000000..6adf52e
--- /dev/null
+++ b/source/common/servnotf.cpp
@@ -0,0 +1,118 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2001-2006, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_SERVICE
+
+#include "servnotf.h"
+#ifdef NOTIFIER_DEBUG
+#include <stdio.h>
+#endif
+
+U_NAMESPACE_BEGIN
+
+EventListener::~EventListener() {}
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(EventListener)
+
+ICUNotifier::ICUNotifier(void) 
+: notifyLock(0), listeners(NULL) 
+{
+    umtx_init(&notifyLock);
+}
+
+ICUNotifier::~ICUNotifier(void) {
+    {
+        Mutex lmx(&notifyLock);
+        delete listeners;
+        listeners = NULL;
+    }
+    umtx_destroy(&notifyLock);
+}
+
+
+void 
+ICUNotifier::addListener(const EventListener* l, UErrorCode& status) 
+{
+    if (U_SUCCESS(status)) {
+        if (l == NULL) {
+            status = U_ILLEGAL_ARGUMENT_ERROR;
+            return;
+        }
+
+        if (acceptsListener(*l)) {
+            Mutex lmx(&notifyLock);
+            if (listeners == NULL) {
+                listeners = new UVector(5, status);
+            } else {
+                for (int i = 0, e = listeners->size(); i < e; ++i) {
+                    const EventListener* el = (const EventListener*)(listeners->elementAt(i));
+                    if (l == el) {
+                        return;
+                    }
+                }
+            }
+
+            listeners->addElement((void*)l, status); // cast away const
+        }
+#ifdef NOTIFIER_DEBUG
+        else {
+            fprintf(stderr, "Listener invalid for this notifier.");
+            exit(1);
+        }
+#endif
+    }
+}
+
+void 
+ICUNotifier::removeListener(const EventListener *l, UErrorCode& status) 
+{
+    if (U_SUCCESS(status)) {
+        if (l == NULL) {
+            status = U_ILLEGAL_ARGUMENT_ERROR;
+            return;
+        }
+
+        {
+            Mutex lmx(&notifyLock);
+            if (listeners != NULL) {
+                // identity equality check
+                for (int i = 0, e = listeners->size(); i < e; ++i) {
+                    const EventListener* el = (const EventListener*)listeners->elementAt(i);
+                    if (l == el) {
+                        listeners->removeElementAt(i);
+                        if (listeners->size() == 0) {
+                            delete listeners;
+                            listeners = NULL;
+                        }
+                        return;
+                    }
+                }
+            }
+        }
+    }
+}
+
+void 
+ICUNotifier::notifyChanged(void) 
+{
+    if (listeners != NULL) {
+        Mutex lmx(&notifyLock);
+        if (listeners != NULL) {
+            for (int i = 0, e = listeners->size(); i < e; ++i) {
+                EventListener* el = (EventListener*)listeners->elementAt(i);
+                notifyListener(*el);
+            }
+        }
+    }
+}
+
+U_NAMESPACE_END
+
+/* UCONFIG_NO_SERVICE */
+#endif
+
diff --git a/source/common/servnotf.h b/source/common/servnotf.h
new file mode 100644
index 0000000..19c2d69
--- /dev/null
+++ b/source/common/servnotf.h
@@ -0,0 +1,124 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2001-2004, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+#ifndef ICUNOTIF_H
+#define ICUNOTIF_H
+
+#include "unicode/utypes.h"
+
+#if UCONFIG_NO_SERVICE
+
+U_NAMESPACE_BEGIN
+
+/*
+ * Allow the declaration of APIs with pointers to BreakIterator
+ * even when break iteration is removed from the build.
+ */
+class ICUNotifier;
+
+U_NAMESPACE_END
+
+#else
+
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+
+#include "mutex.h"
+#include "uvector.h"
+
+U_NAMESPACE_BEGIN
+
+class U_COMMON_API EventListener : public UObject {
+public: 
+    virtual ~EventListener();
+
+public:
+    static UClassID U_EXPORT2 getStaticClassID();
+
+    virtual UClassID getDynamicClassID() const;
+
+public:
+#ifdef SERVICE_DEBUG
+    virtual UnicodeString& debug(UnicodeString& result) const {
+      return debugClass(result);
+    }
+
+    virtual UnicodeString& debugClass(UnicodeString& result) const {
+      return result.append("Key");
+    }
+#endif
+};
+
+/**
+ * <p>Abstract implementation of a notification facility.  Clients add
+ * EventListeners with addListener and remove them with removeListener.
+ * Notifiers call notifyChanged when they wish to notify listeners.
+ * This queues the listener list on the notification thread, which
+ * eventually dequeues the list and calls notifyListener on each
+ * listener in the list.</p>
+ *
+ * <p>Subclasses override acceptsListener and notifyListener 
+ * to add type-safe notification.  AcceptsListener should return
+ * true if the listener is of the appropriate type; ICUNotifier
+ * itself will ensure the listener is non-null and that the
+ * identical listener is not already registered with the Notifier.
+ * NotifyListener should cast the listener to the appropriate 
+ * type and call the appropriate method on the listener.
+ */
+
+class U_COMMON_API ICUNotifier : public UMemory  {
+private: UMTX notifyLock;
+private: UVector* listeners;
+         
+public: 
+    ICUNotifier(void);
+    
+    virtual ~ICUNotifier(void);
+    
+    /**
+     * Add a listener to be notified when notifyChanged is called.
+     * The listener must not be null. AcceptsListener must return
+     * true for the listener.  Attempts to concurrently
+     * register the identical listener more than once will be
+     * silently ignored.  
+     */
+    virtual void addListener(const EventListener* l, UErrorCode& status);
+    
+    /**
+     * Stop notifying this listener.  The listener must
+     * not be null.  Attemps to remove a listener that is
+     * not registered will be silently ignored.
+     */
+    virtual void removeListener(const EventListener* l, UErrorCode& status);
+    
+    /**
+     * ICU doesn't spawn its own threads.  All listeners are notified in
+     * the thread of the caller.  Misbehaved listeners can therefore
+     * indefinitely block the calling thread.  Callers should beware of
+     * deadlock situations.  
+     */
+    virtual void notifyChanged(void);
+    
+protected: 
+    /**
+     * Subclasses implement this to return TRUE if the listener is
+     * of the appropriate type.
+     */
+    virtual UBool acceptsListener(const EventListener& l) const = 0;
+    
+    /**
+     * Subclasses implement this to notify the listener.
+     */
+    virtual void notifyListener(EventListener& l) const = 0;
+};
+
+U_NAMESPACE_END
+
+/* UCONFIG_NO_SERVICE */
+#endif
+
+/* ICUNOTIF_H */
+#endif
diff --git a/source/common/servrbf.cpp b/source/common/servrbf.cpp
new file mode 100644
index 0000000..3a0227f
--- /dev/null
+++ b/source/common/servrbf.cpp
@@ -0,0 +1,94 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2001-2005, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ *******************************************************************************
+ */
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_SERVICE
+
+#include "unicode/resbund.h"
+#include "uresimp.h"
+#include "cmemory.h"
+#include "servloc.h"
+#include "ustrfmt.h"
+#include "uhash.h"
+#include "charstr.h"
+#include "ucln_cmn.h"
+#include "uassert.h"
+
+#define UNDERSCORE_CHAR ((UChar)0x005f)
+#define AT_SIGN_CHAR    ((UChar)64)
+#define PERIOD_CHAR     ((UChar)46)
+
+U_NAMESPACE_BEGIN
+
+ICUResourceBundleFactory::ICUResourceBundleFactory()
+  : LocaleKeyFactory(VISIBLE)
+  , _bundleName()
+{
+}
+
+ICUResourceBundleFactory::ICUResourceBundleFactory(const UnicodeString& bundleName)
+  : LocaleKeyFactory(VISIBLE)
+  , _bundleName(bundleName)
+{
+}
+
+ICUResourceBundleFactory::~ICUResourceBundleFactory() {}
+
+const Hashtable*
+ICUResourceBundleFactory::getSupportedIDs(UErrorCode& status) const
+{
+    if (U_SUCCESS(status)) {
+        return LocaleUtility::getAvailableLocaleNames(_bundleName);
+    }
+    return NULL;
+}
+
+UObject*
+ICUResourceBundleFactory::handleCreate(const Locale& loc, int32_t /* kind */, const ICUService* /* service */, UErrorCode& status) const
+{
+    if (U_SUCCESS(status)) {
+        // _bundleName is a package name
+        // and should only contain invariant characters
+                // ??? is it always true that the max length of the bundle name is 19?
+                // who made this change? -- dlf
+        char pkg[20];
+        int32_t length;
+        length=_bundleName.extract(0, INT32_MAX, pkg, (int32_t)sizeof(pkg), US_INV);
+        if(length>=(int32_t)sizeof(pkg)) {
+            return NULL;
+        }
+        return new ResourceBundle(pkg, loc, status);
+    }
+    return NULL;
+}
+
+#ifdef SERVICE_DEBUG
+UnicodeString&
+ICUResourceBundleFactory::debug(UnicodeString& result) const
+{
+    LocaleKeyFactory::debug(result);
+    result.append(", bundle: ");
+    return result.append(_bundleName);
+}
+
+UnicodeString&
+ICUResourceBundleFactory::debugClass(UnicodeString& result) const
+{
+    return result.append("ICUResourceBundleFactory");
+}
+#endif
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ICUResourceBundleFactory)
+
+U_NAMESPACE_END
+
+/* !UCONFIG_NO_SERVICE */
+#endif
+
+
diff --git a/source/common/servslkf.cpp b/source/common/servslkf.cpp
new file mode 100644
index 0000000..b8afaaa
--- /dev/null
+++ b/source/common/servslkf.cpp
@@ -0,0 +1,122 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2001-2005, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ *
+ *******************************************************************************
+ */
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_SERVICE
+
+#include "unicode/resbund.h"
+#include "uresimp.h"
+#include "cmemory.h"
+#include "servloc.h"
+#include "ustrfmt.h"
+#include "uhash.h"
+#include "charstr.h"
+#include "ucln_cmn.h"
+#include "uassert.h"
+
+#define UNDERSCORE_CHAR ((UChar)0x005f)
+#define AT_SIGN_CHAR    ((UChar)64)
+#define PERIOD_CHAR     ((UChar)46)
+
+U_NAMESPACE_BEGIN
+
+/*
+ ******************************************************************
+ */
+
+SimpleLocaleKeyFactory::SimpleLocaleKeyFactory(UObject* objToAdopt,
+                                               const UnicodeString& locale,
+                                               int32_t kind,
+                                               int32_t coverage)
+  : LocaleKeyFactory(coverage)
+  , _obj(objToAdopt)
+  , _id(locale)
+  , _kind(kind)
+{
+}
+
+SimpleLocaleKeyFactory::SimpleLocaleKeyFactory(UObject* objToAdopt,
+                                               const Locale& locale,
+                                               int32_t kind,
+                                               int32_t coverage)
+  : LocaleKeyFactory(coverage)
+  , _obj(objToAdopt)
+  , _id()
+  , _kind(kind)
+{
+    LocaleUtility::initNameFromLocale(locale, _id);
+}
+
+SimpleLocaleKeyFactory::~SimpleLocaleKeyFactory()
+{
+  delete _obj;
+  _obj = NULL;
+}
+
+UObject*
+SimpleLocaleKeyFactory::create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const
+{
+    if (U_SUCCESS(status)) {
+        const LocaleKey& lkey = (const LocaleKey&)key;
+        if (_kind == LocaleKey::KIND_ANY || _kind == lkey.kind()) {
+            UnicodeString keyID;
+            lkey.currentID(keyID);
+            if (_id == keyID) {
+                return service->cloneInstance(_obj);
+            }
+        }
+    }
+    return NULL;
+}
+
+//UBool
+//SimpleLocaleKeyFactory::isSupportedID(const UnicodeString& id, UErrorCode& /* status */) const
+//{
+//    return id == _id;
+//}
+
+void
+SimpleLocaleKeyFactory::updateVisibleIDs(Hashtable& result, UErrorCode& status) const
+{
+    if (U_SUCCESS(status)) {
+        if (_coverage & 0x1) {
+            result.remove(_id);
+        } else {
+            result.put(_id, (void*)this, status);
+        }
+    }
+}
+
+#ifdef SERVICE_DEBUG
+UnicodeString&
+SimpleLocaleKeyFactory::debug(UnicodeString& result) const
+{
+    LocaleKeyFactory::debug(result);
+    result.append(", id: ");
+    result.append(_id);
+    result.append(", kind: ");
+    result.append(_kind);
+    return result;
+}
+
+UnicodeString&
+SimpleLocaleKeyFactory::debugClass(UnicodeString& result) const
+{
+    return result.append("SimpleLocaleKeyFactory");
+}
+#endif
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleLocaleKeyFactory)
+
+U_NAMESPACE_END
+
+/* !UCONFIG_NO_SERVICE */
+#endif
+
+
diff --git a/source/common/sprpimpl.h b/source/common/sprpimpl.h
new file mode 100644
index 0000000..1422cc3
--- /dev/null
+++ b/source/common/sprpimpl.h
@@ -0,0 +1,129 @@
+/*
+ *******************************************************************************
+ *
+ *   Copyright (C) 2003-2006, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ *
+ *******************************************************************************
+ *   file name:  sprpimpl.h
+ *   encoding:   US-ASCII
+ *   tab size:   8 (not used)
+ *   indentation:4
+ *
+ *   created on: 2003feb1
+ *   created by: Ram Viswanadha
+ */
+
+#ifndef SPRPIMPL_H
+#define SPRPIMPL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_IDNA
+
+#include "unicode/ustring.h"
+#include "unicode/parseerr.h"
+#include "unicode/usprep.h"
+#include "unicode/udata.h"
+#include "utrie.h"
+#include "udataswp.h"
+#include "ubidi_props.h"
+
+#define _SPREP_DATA_TYPE "spp"
+
+enum UStringPrepType{
+    USPREP_UNASSIGNED           = 0x0000 ,
+    USPREP_MAP                  = 0x0001 ,
+    USPREP_PROHIBITED           = 0x0002 , 
+    USPREP_DELETE               = 0x0003 ,
+    USPREP_TYPE_LIMIT           = 0x0004  
+};
+
+typedef enum UStringPrepType UStringPrepType;
+
+#ifdef USPREP_TYPE_NAMES_ARRAY
+static const char* usprepTypeNames[] ={
+    "UNASSIGNED" ,          
+    "MAP" , 
+    "PROHIBITED" ,        
+    "DELETE",
+    "TYPE_LIMIT" 
+};
+#endif
+
+enum{
+    _SPREP_NORMALIZATION_ON = 0x0001,
+    _SPREP_CHECK_BIDI_ON    = 0x0002
+};
+
+enum{
+    _SPREP_TYPE_THRESHOLD       = 0xFFF0,
+    _SPREP_MAX_INDEX_VALUE      = 0x3FBF,   /*16139*/ 
+    _SPREP_MAX_INDEX_TOP_LENGTH = 0x0003
+};
+
+/* indexes[] value names */
+enum {
+    _SPREP_INDEX_TRIE_SIZE                  = 0, /* number of bytes in StringPrep trie */
+    _SPREP_INDEX_MAPPING_DATA_SIZE          = 1, /* The array that contains the mapping   */
+    _SPREP_NORM_CORRECTNS_LAST_UNI_VERSION  = 2, /* The index of Unicode version of last entry in NormalizationCorrections.txt */ 
+    _SPREP_ONE_UCHAR_MAPPING_INDEX_START    = 3, /* The starting index of 1 UChar mapping index in the mapping data array */
+    _SPREP_TWO_UCHARS_MAPPING_INDEX_START   = 4, /* The starting index of 2 UChars mapping index in the mapping data array */
+    _SPREP_THREE_UCHARS_MAPPING_INDEX_START = 5, /* The starting index of 3 UChars mapping index in the mapping data array */
+    _SPREP_FOUR_UCHARS_MAPPING_INDEX_START  = 6, /* The starting index of 4 UChars mapping index in the mapping data array */
+    _SPREP_OPTIONS                          = 7, /* Bit set of options to turn on in the profile */
+    _SPREP_INDEX_TOP=16                          /* changing this requires a new formatVersion */
+};
+
+typedef struct UStringPrepKey UStringPrepKey;
+
+
+struct UStringPrepKey{
+    char* name;
+    char* path;
+};
+
+struct UStringPrepProfile{
+    int32_t indexes[_SPREP_INDEX_TOP];
+    UTrie sprepTrie;
+    const uint16_t* mappingData;
+    UDataMemory* sprepData;
+    const UBiDiProps *bdp; /* used only if checkBiDi is set */
+    int32_t refCount;
+    UBool isDataLoaded;
+    UBool doNFKC;
+    UBool checkBiDi;
+};
+
+/**
+ * Helper function for populating the UParseError struct
+ * @internal
+ */
+U_CAPI void U_EXPORT2
+uprv_syntaxError(const UChar* rules, 
+                 int32_t pos,
+                 int32_t rulesLen,
+                 UParseError* parseError);
+
+
+/**
+ * Swap StringPrep .spp profile data. See udataswp.h.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+usprep_swap(const UDataSwapper *ds,
+            const void *inData, int32_t length, void *outData,
+            UErrorCode *pErrorCode);
+
+#endif /* #if !UCONFIG_NO_IDNA */
+
+#endif
+
+/*
+ * Hey, Emacs, please set the following:
+ *
+ * Local Variables:
+ * indent-tabs-mode: nil
+ * End:
+ *
+ */
diff --git a/source/common/stringpiece.cpp b/source/common/stringpiece.cpp
new file mode 100644
index 0000000..64cd376
--- /dev/null
+++ b/source/common/stringpiece.cpp
@@ -0,0 +1,82 @@
+// Copyright (C) 2009-2010, International Business Machines
+// Corporation and others. All Rights Reserved.
+//
+// Copyright 2004 and onwards Google Inc.
+//
+// Author: wilsonh@google.com (Wilson Hsieh)
+//
+
+#include "unicode/utypes.h"
+#include "unicode/stringpiece.h"
+#include "cstring.h"
+#include "cmemory.h"
+
+U_NAMESPACE_BEGIN
+
+StringPiece::StringPiece(const char* str)
+    : ptr_(str), length_((str == NULL) ? 0 : static_cast<int32_t>(uprv_strlen(str))) { }
+
+StringPiece::StringPiece(const StringPiece& x, int32_t pos) {
+  if (pos < 0) {
+    pos = 0;
+  } else if (pos > x.length_) {
+    pos = x.length_;
+  }
+  ptr_ = x.ptr_ + pos;
+  length_ = x.length_ - pos;
+}
+
+StringPiece::StringPiece(const StringPiece& x, int32_t pos, int32_t len) {
+  if (pos < 0) {
+    pos = 0;
+  } else if (pos > x.length_) {
+    pos = x.length_;
+  }
+  if (len < 0) {
+    len = 0;
+  } else if (len > x.length_ - pos) {
+    len = x.length_ - pos;
+  }
+  ptr_ = x.ptr_ + pos;
+  length_ = len;
+}
+
+void StringPiece::set(const char* str) {
+  ptr_ = str;
+  if (str != NULL)
+    length_ = static_cast<int32_t>(uprv_strlen(str));
+  else
+    length_ = 0;
+}
+
+U_EXPORT UBool U_EXPORT2
+operator==(const StringPiece& x, const StringPiece& y) {
+  int32_t len = x.size();
+  if (len != y.size()) {
+    return false;
+  }
+  if (len == 0) {
+    return true;
+  }
+  const char* p = x.data();
+  const char* p2 = y.data();
+  // Test last byte in case strings share large common prefix
+  --len;
+  if (p[len] != p2[len]) return false;
+  // At this point we can, but don't have to, ignore the last byte.
+  return uprv_memcmp(p, p2, len) == 0;
+}
+
+
+/* Microsft Visual Studios <= 8.0 complains about redefinition of this
+ * static const class variable. However, the C++ standard states that this 
+ * definition is correct. Perhaps there is a bug in the Microsoft compiler. 
+ * This is not an issue on any other compilers (that we know of) including 
+ * Visual Studios 9.0.
+ * Cygwin with MSVC 9.0 also complains here about redefinition.
+ */
+#if (!defined(_MSC_VER) || (_MSC_VER > 1500)) && !defined(CYGWINMSVC)
+const int32_t StringPiece::npos;
+#endif
+
+U_NAMESPACE_END
diff --git a/source/common/triedict.cpp b/source/common/triedict.cpp
new file mode 100644
index 0000000..0dbb566
--- /dev/null
+++ b/source/common/triedict.cpp
@@ -0,0 +1,1408 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2006-2008, International Business Machines Corporation        *
+ * and others. All Rights Reserved.                                            *
+ *******************************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "triedict.h"
+#include "unicode/chariter.h"
+#include "unicode/uchriter.h"
+#include "unicode/strenum.h"
+#include "unicode/uenum.h"
+#include "unicode/udata.h"
+#include "cmemory.h"
+#include "udataswp.h"
+#include "uvector.h"
+#include "uvectr32.h"
+#include "uarrsort.h"
+
+//#define DEBUG_TRIE_DICT 1
+
+#ifdef DEBUG_TRIE_DICT
+#include <sys/times.h>
+#include <limits.h>
+#include <stdio.h>
+#endif
+
+U_NAMESPACE_BEGIN
+
+/*******************************************************************
+ * TrieWordDictionary
+ */
+
+TrieWordDictionary::TrieWordDictionary() {
+}
+
+TrieWordDictionary::~TrieWordDictionary() {
+}
+
+/*******************************************************************
+ * MutableTrieDictionary
+ */
+
+// Node structure for the ternary, uncompressed trie
+struct TernaryNode : public UMemory {
+    UChar       ch;         // UTF-16 code unit
+    uint16_t    flags;      // Flag word
+    TernaryNode *low;       // Less-than link
+    TernaryNode *equal;     // Equal link
+    TernaryNode *high;      // Greater-than link
+
+    TernaryNode(UChar uc);
+    ~TernaryNode();
+};
+
+enum MutableTrieNodeFlags {
+    kEndsWord = 0x0001      // This node marks the end of a valid word
+};
+
+inline
+TernaryNode::TernaryNode(UChar uc) {
+    ch = uc;
+    flags = 0;
+    low = NULL;
+    equal = NULL;
+    high = NULL;
+}
+
+// Not inline since it's recursive
+TernaryNode::~TernaryNode() {
+    delete low;
+    delete equal;
+    delete high;
+}
+
+MutableTrieDictionary::MutableTrieDictionary( UChar median, UErrorCode &status ) {
+    // Start the trie off with something. Having the root node already present
+    // cuts a special case out of the search/insertion functions.
+    // Making it a median character cuts the worse case for searches from
+    // 4x a balanced trie to 2x a balanced trie. It's best to choose something
+    // that starts a word that is midway in the list.
+    fTrie = new TernaryNode(median);
+    if (fTrie == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+    }
+    fIter = utext_openUChars(NULL, NULL, 0, &status);
+    if (U_SUCCESS(status) && fIter == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+    }
+}
+
+MutableTrieDictionary::MutableTrieDictionary( UErrorCode &status ) {
+    fTrie = NULL;
+    fIter = utext_openUChars(NULL, NULL, 0, &status);
+    if (U_SUCCESS(status) && fIter == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+    }
+}
+
+MutableTrieDictionary::~MutableTrieDictionary() {
+    delete fTrie;
+    utext_close(fIter);
+}
+
+int32_t
+MutableTrieDictionary::search( UText *text,
+                                   int32_t maxLength,
+                                   int32_t *lengths,
+                                   int &count,
+                                   int limit,
+                                   TernaryNode *&parent,
+                                   UBool &pMatched ) const {
+    // TODO: current implementation works in UTF-16 space
+    const TernaryNode *up = NULL;
+    const TernaryNode *p = fTrie;
+    int mycount = 0;
+    pMatched = TRUE;
+    int i;
+
+    UChar uc = utext_current32(text);
+    for (i = 0; i < maxLength && p != NULL; ++i) {
+        while (p != NULL) {
+            if (uc < p->ch) {
+                up = p;
+                p = p->low;
+            }
+            else if (uc == p->ch) {
+                break;
+            }
+            else {
+                up = p;
+                p = p->high;
+            }
+        }
+        if (p == NULL) {
+            pMatched = FALSE;
+            break;
+        }
+        // Must be equal to get here
+        if (limit > 0 && (p->flags & kEndsWord)) {
+            lengths[mycount++] = i+1;
+            --limit;
+        }
+        up = p;
+        p = p->equal;
+        uc = utext_next32(text);
+        uc = utext_current32(text);
+    }
+    
+    // Note that there is no way to reach here with up == 0 unless
+    // maxLength is 0 coming in.
+    parent = (TernaryNode *)up;
+    count = mycount;
+    return i;
+}
+
+void
+MutableTrieDictionary::addWord( const UChar *word,
+                                int32_t length,
+                                UErrorCode &status ) {
+#if 0
+    if (length <= 0) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+#endif
+    TernaryNode *parent;
+    UBool pMatched;
+    int count;
+    fIter = utext_openUChars(fIter, word, length, &status);
+    
+    int matched;
+    matched = search(fIter, length, NULL, count, 0, parent, pMatched);
+    
+    while (matched++ < length) {
+        UChar32 uc = utext_next32(fIter);  // TODO:  supplemetary support?
+        U_ASSERT(uc != U_SENTINEL);
+        TernaryNode *newNode = new TernaryNode(uc);
+        if (newNode == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+        if (pMatched) {
+            parent->equal = newNode;
+        }
+        else {
+            pMatched = TRUE;
+            if (uc < parent->ch) {
+                parent->low = newNode;
+            }
+            else {
+                parent->high = newNode;
+            }
+        }
+        parent = newNode;
+    }
+
+    parent->flags |= kEndsWord;
+}
+
+#if 0
+void
+MutableTrieDictionary::addWords( UEnumeration *words,
+                                  UErrorCode &status ) {
+    int32_t length;
+    const UChar *word;
+    while ((word = uenum_unext(words, &length, &status)) && U_SUCCESS(status)) {
+        addWord(word, length, status);
+    }
+}
+#endif
+
+int32_t
+MutableTrieDictionary::matches( UText *text,
+                                int32_t maxLength,
+                                int32_t *lengths,
+                                int &count,
+                                int limit ) const {
+    TernaryNode *parent;
+    UBool pMatched;
+    return search(text, maxLength, lengths, count, limit, parent, pMatched);
+}
+
+// Implementation of iteration for MutableTrieDictionary
+class MutableTrieEnumeration : public StringEnumeration {
+private:
+    UStack      fNodeStack;     // Stack of nodes to process
+    UVector32   fBranchStack;   // Stack of which branch we are working on
+    TernaryNode *fRoot;         // Root node
+    enum StackBranch {
+        kLessThan,
+        kEqual,
+        kGreaterThan,
+        kDone
+    };
+
+public:
+    static UClassID U_EXPORT2 getStaticClassID(void);
+    virtual UClassID getDynamicClassID(void) const;
+public:
+    MutableTrieEnumeration(TernaryNode *root, UErrorCode &status) 
+        : fNodeStack(status), fBranchStack(status) {
+        fRoot = root;
+        fNodeStack.push(root, status);
+        fBranchStack.push(kLessThan, status);
+        unistr.remove();
+    }
+    
+    virtual ~MutableTrieEnumeration() {
+    }
+    
+    virtual StringEnumeration *clone() const {
+        UErrorCode status = U_ZERO_ERROR;
+        return new MutableTrieEnumeration(fRoot, status);
+    }
+    
+    virtual const UnicodeString *snext(UErrorCode &status) {
+        if (fNodeStack.empty() || U_FAILURE(status)) {
+            return NULL;
+        }
+        TernaryNode *node = (TernaryNode *) fNodeStack.peek();
+        StackBranch where = (StackBranch) fBranchStack.peeki();
+        while (!fNodeStack.empty() && U_SUCCESS(status)) {
+            UBool emit;
+            UBool equal;
+
+            switch (where) {
+            case kLessThan:
+                if (node->low != NULL) {
+                    fBranchStack.setElementAt(kEqual, fBranchStack.size()-1);
+                    node = (TernaryNode *) fNodeStack.push(node->low, status);
+                    where = (StackBranch) fBranchStack.push(kLessThan, status);
+                    break;
+                }
+            case kEqual:
+                emit = (node->flags & kEndsWord) != 0;
+                equal = (node->equal != NULL);
+                // If this node should be part of the next emitted string, append
+                // the UChar to the string, and make sure we pop it when we come
+                // back to this node. The character should only be in the string
+                // for as long as we're traversing the equal subtree of this node
+                if (equal || emit) {
+                    unistr.append(node->ch);
+                    fBranchStack.setElementAt(kGreaterThan, fBranchStack.size()-1);
+                }
+                if (equal) {
+                    node = (TernaryNode *) fNodeStack.push(node->equal, status);
+                    where = (StackBranch) fBranchStack.push(kLessThan, status);
+                }
+                if (emit) {
+                    return &unistr;
+                }
+                if (equal) {
+                    break;
+                }
+            case kGreaterThan:
+                // If this node's character is in the string, remove it.
+                if (node->equal != NULL || (node->flags & kEndsWord)) {
+                    unistr.truncate(unistr.length()-1);
+                }
+                if (node->high != NULL) {
+                    fBranchStack.setElementAt(kDone, fBranchStack.size()-1);
+                    node = (TernaryNode *) fNodeStack.push(node->high, status);
+                    where = (StackBranch) fBranchStack.push(kLessThan, status);
+                    break;
+                }
+            case kDone:
+                fNodeStack.pop();
+                fBranchStack.popi();
+                node = (TernaryNode *) fNodeStack.peek();
+                where = (StackBranch) fBranchStack.peeki();
+                break;
+            default:
+                return NULL;
+            }
+        }
+        return NULL;
+    }
+    
+    // Very expensive, but this should never be used.
+    virtual int32_t count(UErrorCode &status) const {
+        MutableTrieEnumeration counter(fRoot, status);
+        int32_t result = 0;
+        while (counter.snext(status) != NULL && U_SUCCESS(status)) {
+            ++result;
+        }
+        return result;
+    }
+    
+    virtual void reset(UErrorCode &status) {
+        fNodeStack.removeAllElements();
+        fBranchStack.removeAllElements();
+        fNodeStack.push(fRoot, status);
+        fBranchStack.push(kLessThan, status);
+        unistr.remove();
+    }
+};
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MutableTrieEnumeration)
+
+StringEnumeration *
+MutableTrieDictionary::openWords( UErrorCode &status ) const {
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+    return new MutableTrieEnumeration(fTrie, status);
+}
+
+/*******************************************************************
+ * CompactTrieDictionary
+ */
+
+struct CompactTrieHeader {
+    uint32_t        size;           // Size of the data in bytes
+    uint32_t        magic;          // Magic number (including version)
+    uint16_t        nodeCount;      // Number of entries in offsets[]
+    uint16_t        root;           // Node number of the root node
+    uint32_t        offsets[1];      // Offsets to nodes from start of data
+};
+
+// Note that to avoid platform-specific alignment issues, all members of the node
+// structures should be the same size, or should contain explicit padding to
+// natural alignment boundaries.
+
+// We can't use a bitfield for the flags+count field, because the layout of those
+// is not portable. 12 bits of count allows for up to 4096 entries in a node.
+struct CompactTrieNode {
+    uint16_t        flagscount;     // Count of sub-entries, plus flags
+};
+
+enum CompactTrieNodeFlags {
+    kVerticalNode   = 0x1000,       // This is a vertical node
+    kParentEndsWord = 0x2000,       // The node whose equal link points to this ends a word
+    kReservedFlag1  = 0x4000,
+    kReservedFlag2  = 0x8000,
+    kCountMask      = 0x0FFF,       // The count portion of flagscount
+    kFlagMask       = 0xF000        // The flags portion of flagscount
+};
+
+// The two node types are distinguished by the kVerticalNode flag.
+
+struct CompactTrieHorizontalEntry {
+    uint16_t        ch;             // UChar
+    uint16_t        equal;          // Equal link node index
+};
+
+// We don't use inheritance here because C++ does not guarantee that the
+// base class comes first in memory!!
+
+struct CompactTrieHorizontalNode {
+    uint16_t        flagscount;     // Count of sub-entries, plus flags
+    CompactTrieHorizontalEntry      entries[1];
+};
+
+struct CompactTrieVerticalNode {
+    uint16_t        flagscount;     // Count of sub-entries, plus flags
+    uint16_t        equal;          // Equal link node index
+    uint16_t        chars[1];       // Code units
+};
+
+// {'Dic', 1}, version 1
+#define COMPACT_TRIE_MAGIC_1 0x44696301
+
+CompactTrieDictionary::CompactTrieDictionary(UDataMemory *dataObj,
+                                                UErrorCode &status )
+: fUData(dataObj)
+{
+    fData = (const CompactTrieHeader *) udata_getMemory(dataObj);
+    fOwnData = FALSE;
+    if (fData->magic != COMPACT_TRIE_MAGIC_1) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        fData = NULL;
+    }
+}
+CompactTrieDictionary::CompactTrieDictionary( const void *data,
+                                                UErrorCode &status )
+: fUData(NULL)
+{
+    fData = (const CompactTrieHeader *) data;
+    fOwnData = FALSE;
+    if (fData->magic != COMPACT_TRIE_MAGIC_1) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        fData = NULL;
+    }
+}
+
+CompactTrieDictionary::CompactTrieDictionary( const MutableTrieDictionary &dict,
+                                                UErrorCode &status )
+: fUData(NULL)
+{
+    fData = compactMutableTrieDictionary(dict, status);
+    fOwnData = !U_FAILURE(status);
+}
+
+CompactTrieDictionary::~CompactTrieDictionary() {
+    if (fOwnData) {
+        uprv_free((void *)fData);
+    }
+    if (fUData) {
+        udata_close(fUData);
+    }
+}
+
+uint32_t
+CompactTrieDictionary::dataSize() const {
+    return fData->size;
+}
+
+const void *
+CompactTrieDictionary::data() const {
+    return fData;
+}
+
+// This function finds the address of a node for us, given its node ID
+static inline const CompactTrieNode *
+getCompactNode(const CompactTrieHeader *header, uint16_t node) {
+    return (const CompactTrieNode *)((const uint8_t *)header + header->offsets[node]);
+}
+
+int32_t
+CompactTrieDictionary::matches( UText *text,
+                                int32_t maxLength,
+                                int32_t *lengths,
+                                int &count,
+                                int limit ) const {
+    // TODO: current implementation works in UTF-16 space
+    const CompactTrieNode *node = getCompactNode(fData, fData->root);
+    int mycount = 0;
+
+    UChar uc = utext_current32(text);
+    int i = 0;
+
+    while (node != NULL) {
+        // Check if the node we just exited ends a word
+        if (limit > 0 && (node->flagscount & kParentEndsWord)) {
+            lengths[mycount++] = i;
+            --limit;
+        }
+        // Check that we haven't exceeded the maximum number of input characters.
+        // We have to do that here rather than in the while condition so that
+        // we can check for ending a word, above.
+        if (i >= maxLength) {
+            break;
+        }
+
+        int nodeCount = (node->flagscount & kCountMask);
+        if (nodeCount == 0) {
+            // Special terminal node; return now
+            break;
+        }
+        if (node->flagscount & kVerticalNode) {
+            // Vertical node; check all the characters in it
+            const CompactTrieVerticalNode *vnode = (const CompactTrieVerticalNode *)node;
+            for (int j = 0; j < nodeCount && i < maxLength; ++j) {
+                if (uc != vnode->chars[j]) {
+                    // We hit a non-equal character; return
+                    goto exit;
+                }
+                utext_next32(text);
+                uc = utext_current32(text);
+                ++i;
+            }
+            // To get here we must have come through the whole list successfully;
+            // go on to the next node. Note that a word cannot end in the middle
+            // of a vertical node.
+            node = getCompactNode(fData, vnode->equal);
+        }
+        else {
+            // Horizontal node; do binary search
+            const CompactTrieHorizontalNode *hnode = (const CompactTrieHorizontalNode *)node;
+            int low = 0;
+            int high = nodeCount-1;
+            int middle;
+            node = NULL;    // If we don't find a match, we'll fall out of the loop
+            while (high >= low) {
+                middle = (high+low)/2;
+                if (uc == hnode->entries[middle].ch) {
+                    // We hit a match; get the next node and next character
+                    node = getCompactNode(fData, hnode->entries[middle].equal);
+                    utext_next32(text);
+                    uc = utext_current32(text);
+                    ++i;
+                    break;
+                }
+                else if (uc < hnode->entries[middle].ch) {
+                    high = middle-1;
+                }
+                else {
+                    low = middle+1;
+                }
+            }
+        }
+    }
+exit:
+    count = mycount;
+    return i;
+}
+
+// Implementation of iteration for CompactTrieDictionary
+class CompactTrieEnumeration : public StringEnumeration {
+private:
+    UVector32               fNodeStack;     // Stack of nodes to process
+    UVector32               fIndexStack;    // Stack of where in node we are
+    const CompactTrieHeader *fHeader;       // Trie data
+
+public:
+    static UClassID U_EXPORT2 getStaticClassID(void);
+    virtual UClassID getDynamicClassID(void) const;
+public:
+    CompactTrieEnumeration(const CompactTrieHeader *header, UErrorCode &status) 
+        : fNodeStack(status), fIndexStack(status) {
+        fHeader = header;
+        fNodeStack.push(header->root, status);
+        fIndexStack.push(0, status);
+        unistr.remove();
+    }
+    
+    virtual ~CompactTrieEnumeration() {
+    }
+    
+    virtual StringEnumeration *clone() const {
+        UErrorCode status = U_ZERO_ERROR;
+        return new CompactTrieEnumeration(fHeader, status);
+    }
+    
+    virtual const UnicodeString * snext(UErrorCode &status);
+
+    // Very expensive, but this should never be used.
+    virtual int32_t count(UErrorCode &status) const {
+        CompactTrieEnumeration counter(fHeader, status);
+        int32_t result = 0;
+        while (counter.snext(status) != NULL && U_SUCCESS(status)) {
+            ++result;
+        }
+        return result;
+    }
+    
+    virtual void reset(UErrorCode &status) {
+        fNodeStack.removeAllElements();
+        fIndexStack.removeAllElements();
+        fNodeStack.push(fHeader->root, status);
+        fIndexStack.push(0, status);
+        unistr.remove();
+    }
+};
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CompactTrieEnumeration)
+
+const UnicodeString *
+CompactTrieEnumeration::snext(UErrorCode &status) {
+    if (fNodeStack.empty() || U_FAILURE(status)) {
+        return NULL;
+    }
+    const CompactTrieNode *node = getCompactNode(fHeader, fNodeStack.peeki());
+    int where = fIndexStack.peeki();
+    while (!fNodeStack.empty() && U_SUCCESS(status)) {
+        int nodeCount = (node->flagscount & kCountMask);
+        UBool goingDown = FALSE;
+        if (nodeCount == 0) {
+            // Terminal node; go up immediately
+            fNodeStack.popi();
+            fIndexStack.popi();
+            node = getCompactNode(fHeader, fNodeStack.peeki());
+            where = fIndexStack.peeki();
+        }
+        else if (node->flagscount & kVerticalNode) {
+            // Vertical node
+            const CompactTrieVerticalNode *vnode = (const CompactTrieVerticalNode *)node;
+            if (where == 0) {
+                // Going down
+                unistr.append((const UChar *)vnode->chars, (int32_t) nodeCount);
+                fIndexStack.setElementAt(1, fIndexStack.size()-1);
+                node = getCompactNode(fHeader, fNodeStack.push(vnode->equal, status));
+                where = fIndexStack.push(0, status);
+                goingDown = TRUE;
+            }
+            else {
+                // Going up
+                unistr.truncate(unistr.length()-nodeCount);
+                fNodeStack.popi();
+                fIndexStack.popi();
+                node = getCompactNode(fHeader, fNodeStack.peeki());
+                where = fIndexStack.peeki();
+            }
+        }
+        else {
+            // Horizontal node
+            const CompactTrieHorizontalNode *hnode = (const CompactTrieHorizontalNode *)node;
+            if (where > 0) {
+                // Pop previous char
+                unistr.truncate(unistr.length()-1);
+            }
+            if (where < nodeCount) {
+                // Push on next node
+                unistr.append((UChar)hnode->entries[where].ch);
+                fIndexStack.setElementAt(where+1, fIndexStack.size()-1);
+                node = getCompactNode(fHeader, fNodeStack.push(hnode->entries[where].equal, status));
+                where = fIndexStack.push(0, status);
+                goingDown = TRUE;
+            }
+            else {
+                // Going up
+                fNodeStack.popi();
+                fIndexStack.popi();
+                node = getCompactNode(fHeader, fNodeStack.peeki());
+                where = fIndexStack.peeki();
+            }
+        }
+        // Check if the parent of the node we've just gone down to ends a
+        // word. If so, return it.
+        if (goingDown && (node->flagscount & kParentEndsWord)) {
+            return &unistr;
+        }
+    }
+    return NULL;
+}
+
+StringEnumeration *
+CompactTrieDictionary::openWords( UErrorCode &status ) const {
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+    return new CompactTrieEnumeration(fData, status);
+}
+
+//
+// Below here is all code related to converting a ternary trie to a compact trie
+// and back again
+//
+
+// Helper classes to construct the compact trie
+class BuildCompactTrieNode: public UMemory {
+ public:
+    UBool           fParentEndsWord;
+    UBool           fVertical;
+    UBool           fHasDuplicate;
+    int32_t         fNodeID;
+    UnicodeString   fChars;
+
+ public:
+    BuildCompactTrieNode(UBool parentEndsWord, UBool vertical, UStack &nodes, UErrorCode &status) {
+        fParentEndsWord = parentEndsWord;
+        fHasDuplicate = FALSE;
+        fVertical = vertical;
+        fNodeID = nodes.size();
+        nodes.push(this, status);
+    }
+    
+    virtual ~BuildCompactTrieNode() {
+    }
+    
+    virtual uint32_t size() {
+        return sizeof(uint16_t);
+    }
+    
+    virtual void write(uint8_t *bytes, uint32_t &offset, const UVector32 &/*translate*/) {
+        // Write flag/count
+        *((uint16_t *)(bytes+offset)) = (fChars.length() & kCountMask)
+            | (fVertical ? kVerticalNode : 0) | (fParentEndsWord ? kParentEndsWord : 0 );
+        offset += sizeof(uint16_t);
+    }
+};
+
+class BuildCompactTrieHorizontalNode: public BuildCompactTrieNode {
+ public:
+    UStack          fLinks;
+
+ public:
+    BuildCompactTrieHorizontalNode(UBool parentEndsWord, UStack &nodes, UErrorCode &status)
+        : BuildCompactTrieNode(parentEndsWord, FALSE, nodes, status), fLinks(status) {
+    }
+    
+    virtual ~BuildCompactTrieHorizontalNode() {
+    }
+    
+    virtual uint32_t size() {
+        return offsetof(CompactTrieHorizontalNode,entries) +
+                (fChars.length()*sizeof(CompactTrieHorizontalEntry));
+    }
+    
+    virtual void write(uint8_t *bytes, uint32_t &offset, const UVector32 &translate) {
+        BuildCompactTrieNode::write(bytes, offset, translate);
+        int32_t count = fChars.length();
+        for (int32_t i = 0; i < count; ++i) {
+            CompactTrieHorizontalEntry *entry = (CompactTrieHorizontalEntry *)(bytes+offset);
+            entry->ch = fChars[i];
+            entry->equal = translate.elementAti(((BuildCompactTrieNode *)fLinks[i])->fNodeID);
+#ifdef DEBUG_TRIE_DICT
+            if (entry->equal == 0) {
+                fprintf(stderr, "ERROR: horizontal link %d, logical node %d maps to physical node zero\n",
+                        i, ((BuildCompactTrieNode *)fLinks[i])->fNodeID);
+            }
+#endif
+            offset += sizeof(CompactTrieHorizontalEntry);
+        }
+    }
+    
+    void addNode(UChar ch, BuildCompactTrieNode *link, UErrorCode &status) {
+        fChars.append(ch);
+        fLinks.push(link, status);
+    }
+};
+
+class BuildCompactTrieVerticalNode: public BuildCompactTrieNode {
+ public:
+    BuildCompactTrieNode    *fEqual;
+
+ public:
+    BuildCompactTrieVerticalNode(UBool parentEndsWord, UStack &nodes, UErrorCode &status)
+        : BuildCompactTrieNode(parentEndsWord, TRUE, nodes, status) {
+        fEqual = NULL;
+    }
+    
+    virtual ~BuildCompactTrieVerticalNode() {
+    }
+    
+    virtual uint32_t size() {
+        return offsetof(CompactTrieVerticalNode,chars) + (fChars.length()*sizeof(uint16_t));
+    }
+    
+    virtual void write(uint8_t *bytes, uint32_t &offset, const UVector32 &translate) {
+        CompactTrieVerticalNode *node = (CompactTrieVerticalNode *)(bytes+offset);
+        BuildCompactTrieNode::write(bytes, offset, translate);
+        node->equal = translate.elementAti(fEqual->fNodeID);
+        offset += sizeof(node->equal);
+#ifdef DEBUG_TRIE_DICT
+        if (node->equal == 0) {
+            fprintf(stderr, "ERROR: vertical link, logical node %d maps to physical node zero\n",
+                    fEqual->fNodeID);
+        }
+#endif
+        fChars.extract(0, fChars.length(), (UChar *)node->chars);
+        offset += sizeof(uint16_t)*fChars.length();
+    }
+    
+    void addChar(UChar ch) {
+        fChars.append(ch);
+    }
+    
+    void setLink(BuildCompactTrieNode *node) {
+        fEqual = node;
+    }
+};
+
+// Forward declaration
+static void walkHorizontal(const TernaryNode *node,
+                            BuildCompactTrieHorizontalNode *building,
+                            UStack &nodes,
+                            UErrorCode &status);
+
+// Convert one node. Uses recursion.
+
+static BuildCompactTrieNode *
+compactOneNode(const TernaryNode *node, UBool parentEndsWord, UStack &nodes, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+    BuildCompactTrieNode *result = NULL;
+    UBool horizontal = (node->low != NULL || node->high != NULL);
+    if (horizontal) {
+        BuildCompactTrieHorizontalNode *hResult =
+                new BuildCompactTrieHorizontalNode(parentEndsWord, nodes, status);
+        if (hResult == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return NULL;
+        }
+        if (U_SUCCESS(status)) {
+            walkHorizontal(node, hResult, nodes, status);
+            result = hResult;
+        }
+    }
+    else {
+        BuildCompactTrieVerticalNode *vResult =
+                new BuildCompactTrieVerticalNode(parentEndsWord, nodes, status);
+        if (vResult == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+        }
+        else if (U_SUCCESS(status)) {
+            UBool   endsWord = FALSE;
+            // Take up nodes until we end a word, or hit a node with < or > links
+            do {
+                vResult->addChar(node->ch);
+                endsWord = (node->flags & kEndsWord) != 0;
+                node = node->equal;
+            }
+            while(node != NULL && !endsWord && node->low == NULL && node->high == NULL);
+            if (node == NULL) {
+                if (!endsWord) {
+                    status = U_ILLEGAL_ARGUMENT_ERROR;  // Corrupt input trie
+                }
+                else {
+                    vResult->setLink((BuildCompactTrieNode *)nodes[1]);
+                }
+            }
+            else {
+                vResult->setLink(compactOneNode(node, endsWord, nodes, status));
+            }
+            result = vResult;
+        }
+    }
+    return result;
+}
+
+// Walk the set of peers at the same level, to build a horizontal node.
+// Uses recursion.
+
+static void walkHorizontal(const TernaryNode *node,
+                            BuildCompactTrieHorizontalNode *building,
+                            UStack &nodes,
+                            UErrorCode &status) {
+    while (U_SUCCESS(status) && node != NULL) {
+        if (node->low != NULL) {
+            walkHorizontal(node->low, building, nodes, status);
+        }
+        BuildCompactTrieNode *link = NULL;
+        if (node->equal != NULL) {
+            link = compactOneNode(node->equal, (node->flags & kEndsWord) != 0, nodes, status);
+        }
+        else if (node->flags & kEndsWord) {
+            link = (BuildCompactTrieNode *)nodes[1];
+        }
+        if (U_SUCCESS(status) && link != NULL) {
+            building->addNode(node->ch, link, status);
+        }
+        // Tail recurse manually instead of leaving it to the compiler.
+        //if (node->high != NULL) {
+        //    walkHorizontal(node->high, building, nodes, status);
+        //}
+        node = node->high;
+    }
+}
+
+U_NAMESPACE_END
+U_NAMESPACE_USE
+U_CDECL_BEGIN
+static int32_t U_CALLCONV
+_sortBuildNodes(const void * /*context*/, const void *voidl, const void *voidr) {
+    BuildCompactTrieNode *left = *(BuildCompactTrieNode **)voidl;
+    BuildCompactTrieNode *right = *(BuildCompactTrieNode **)voidr;
+    // Check for comparing a node to itself, to avoid spurious duplicates
+    if (left == right) {
+        return 0;
+    }
+    // Most significant is type of node. Can never coalesce.
+    if (left->fVertical != right->fVertical) {
+        return left->fVertical - right->fVertical;
+    }
+    // Next, the "parent ends word" flag. If that differs, we cannot coalesce.
+    if (left->fParentEndsWord != right->fParentEndsWord) {
+        return left->fParentEndsWord - right->fParentEndsWord;
+    }
+    // Next, the string. If that differs, we can never coalesce.
+    int32_t result = left->fChars.compare(right->fChars);
+    if (result != 0) {
+        return result;
+    }
+    // We know they're both the same node type, so branch for the two cases.
+    if (left->fVertical) {
+        result = ((BuildCompactTrieVerticalNode *)left)->fEqual->fNodeID
+                            - ((BuildCompactTrieVerticalNode *)right)->fEqual->fNodeID;
+    }
+    else {
+        // We need to compare the links vectors. They should be the
+        // same size because the strings were equal.
+        // We compare the node IDs instead of the pointers, to handle
+        // coalesced nodes.
+        BuildCompactTrieHorizontalNode *hleft, *hright;
+        hleft = (BuildCompactTrieHorizontalNode *)left;
+        hright = (BuildCompactTrieHorizontalNode *)right;
+        int32_t count = hleft->fLinks.size();
+        for (int32_t i = 0; i < count && result == 0; ++i) {
+            result = ((BuildCompactTrieNode *)(hleft->fLinks[i]))->fNodeID -
+                     ((BuildCompactTrieNode *)(hright->fLinks[i]))->fNodeID;
+        }
+    }
+    // If they are equal to each other, mark them (speeds coalescing)
+    if (result == 0) {
+        left->fHasDuplicate = TRUE;
+        right->fHasDuplicate = TRUE;
+    }
+    return result;
+}
+U_CDECL_END
+U_NAMESPACE_BEGIN
+
+static void coalesceDuplicates(UStack &nodes, UErrorCode &status) {
+    // We sort the array of nodes to place duplicates next to each other
+    if (U_FAILURE(status)) {
+        return;
+    }
+    int32_t size = nodes.size();
+    void **array = (void **)uprv_malloc(sizeof(void *)*size);
+    if (array == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    (void) nodes.toArray(array);
+    
+    // Now repeatedly identify duplicates until there are no more
+    int32_t dupes = 0;
+    long    passCount = 0;
+#ifdef DEBUG_TRIE_DICT
+    long    totalDupes = 0;
+#endif
+    do {
+        BuildCompactTrieNode *node;
+        BuildCompactTrieNode *first = NULL;
+        BuildCompactTrieNode **p;
+        BuildCompactTrieNode **pFirst = NULL;
+        int32_t counter = size - 2;
+        // Sort the array, skipping nodes 0 and 1. Use quicksort for the first
+        // pass for speed. For the second and subsequent passes, we use stable
+        // (insertion) sort for two reasons:
+        // 1. The array is already mostly ordered, so we get better performance.
+        // 2. The way we find one and only one instance of a set of duplicates is to
+        //    check that the node ID equals the array index. If we used an unstable
+        //    sort for the second or later passes, it's possible that none of the
+        //    duplicates would wind up with a node ID equal to its array index.
+        //    The sort stability guarantees that, because as we coalesce more and
+        //    more groups, the first element of the resultant group will be one of
+        //    the first elements of the groups being coalesced.
+        // To use quicksort for the second and subsequent passes, we would have to
+        // find the minimum of the node numbers in a group, and set all the nodes
+        // in the group to that node number.
+        uprv_sortArray(array+2, counter, sizeof(void *), _sortBuildNodes, NULL, (passCount > 0), &status);
+        dupes = 0;
+        for (p = (BuildCompactTrieNode **)array + 2; counter > 0; --counter, ++p) {
+            node = *p;
+            if (node->fHasDuplicate) {
+                if (first == NULL) {
+                    first = node;
+                    pFirst = p;
+                }
+                else if (_sortBuildNodes(NULL, pFirst, p) != 0) {
+                    // Starting a new run of dupes
+                    first = node;
+                    pFirst = p;
+                }
+                else if (node->fNodeID != first->fNodeID) {
+                    // Slave one to the other, note duplicate
+                    node->fNodeID = first->fNodeID;
+                    dupes += 1;
+                }
+            }
+            else {
+                // This node has no dupes
+                first = NULL;
+                pFirst = NULL;
+            }
+        }
+        passCount += 1;
+#ifdef DEBUG_TRIE_DICT
+        totalDupes += dupes;
+        fprintf(stderr, "Trie node dupe removal, pass %d: %d nodes tagged\n", passCount, dupes);
+#endif
+    }
+    while (dupes > 0);
+#ifdef DEBUG_TRIE_DICT
+    fprintf(stderr, "Trie node dupe removal complete: %d tagged in %d passes\n", totalDupes, passCount);
+#endif
+
+    // We no longer need the temporary array, as the nodes have all been marked appropriately.
+    uprv_free(array);
+}
+
+U_NAMESPACE_END
+U_CDECL_BEGIN
+static void U_CALLCONV _deleteBuildNode(void *obj) {
+    delete (BuildCompactTrieNode *) obj;
+}
+U_CDECL_END
+U_NAMESPACE_BEGIN
+
+CompactTrieHeader *
+CompactTrieDictionary::compactMutableTrieDictionary( const MutableTrieDictionary &dict,
+                                UErrorCode &status ) {
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+#ifdef DEBUG_TRIE_DICT
+    struct tms timing;
+    struct tms previous;
+    (void) ::times(&previous);
+#endif
+    UStack nodes(_deleteBuildNode, NULL, status);      // Index of nodes
+
+    // Add node 0, used as the NULL pointer/sentinel.
+    nodes.addElement((int32_t)0, status);
+
+    // Start by creating the special empty node we use to indicate that the parent
+    // terminates a word. This must be node 1, because the builder assumes
+    // that.
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+    BuildCompactTrieNode *terminal = new BuildCompactTrieNode(TRUE, FALSE, nodes, status);
+    if (terminal == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+    }
+
+    // This call does all the work of building the new trie structure. The root
+    // will be node 2.
+    BuildCompactTrieNode *root = compactOneNode(dict.fTrie, FALSE, nodes, status);
+#ifdef DEBUG_TRIE_DICT
+    (void) ::times(&timing);
+    fprintf(stderr, "Compact trie built, %d nodes, time user %f system %f\n",
+        nodes.size(), (double)(timing.tms_utime-previous.tms_utime)/CLK_TCK,
+        (double)(timing.tms_stime-previous.tms_stime)/CLK_TCK);
+    previous = timing;
+#endif
+
+    // Now coalesce all duplicate nodes.
+    coalesceDuplicates(nodes, status);
+#ifdef DEBUG_TRIE_DICT
+    (void) ::times(&timing);
+    fprintf(stderr, "Duplicates coalesced, time user %f system %f\n",
+        (double)(timing.tms_utime-previous.tms_utime)/CLK_TCK,
+        (double)(timing.tms_stime-previous.tms_stime)/CLK_TCK);
+    previous = timing;
+#endif
+
+    // Next, build the output trie.
+    // First we compute all the sizes and build the node ID translation table.
+    uint32_t totalSize = offsetof(CompactTrieHeader,offsets);
+    int32_t count = nodes.size();
+    int32_t nodeCount = 1;              // The sentinel node we already have
+    BuildCompactTrieNode *node;
+    int32_t i;
+    UVector32 translate(count, status); // Should be no growth needed after this
+    translate.push(0, status);          // The sentinel node
+    
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+
+    for (i = 1; i < count; ++i) {
+        node = (BuildCompactTrieNode *)nodes[i];
+        if (node->fNodeID == i) {
+            // Only one node out of each duplicate set is used
+            if (i >= translate.size()) {
+                // Logically extend the mapping table
+                translate.setSize(i+1);
+            }
+            translate.setElementAt(nodeCount++, i);
+            totalSize += node->size();
+        }
+    }
+    
+    // Check for overflowing 16 bits worth of nodes.
+    if (nodeCount > 0x10000) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+    
+    // Add enough room for the offsets.
+    totalSize += nodeCount*sizeof(uint32_t);
+#ifdef DEBUG_TRIE_DICT
+    (void) ::times(&timing);
+    fprintf(stderr, "Sizes/mapping done, time user %f system %f\n",
+        (double)(timing.tms_utime-previous.tms_utime)/CLK_TCK,
+        (double)(timing.tms_stime-previous.tms_stime)/CLK_TCK);
+    previous = timing;
+    fprintf(stderr, "%d nodes, %d unique, %d bytes\n", nodes.size(), nodeCount, totalSize);
+#endif
+    uint8_t *bytes = (uint8_t *)uprv_malloc(totalSize);
+    if (bytes == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+
+    CompactTrieHeader *header = (CompactTrieHeader *)bytes;
+    header->size = totalSize;
+    header->nodeCount = nodeCount;
+    header->offsets[0] = 0;                     // Sentinel
+    header->root = translate.elementAti(root->fNodeID);
+#ifdef DEBUG_TRIE_DICT
+    if (header->root == 0) {
+        fprintf(stderr, "ERROR: root node %d translate to physical zero\n", root->fNodeID);
+    }
+#endif
+    uint32_t offset = offsetof(CompactTrieHeader,offsets)+(nodeCount*sizeof(uint32_t));
+    nodeCount = 1;
+    // Now write the data
+    for (i = 1; i < count; ++i) {
+        node = (BuildCompactTrieNode *)nodes[i];
+        if (node->fNodeID == i) {
+            header->offsets[nodeCount++] = offset;
+            node->write(bytes, offset, translate);
+        }
+    }
+#ifdef DEBUG_TRIE_DICT
+    (void) ::times(&timing);
+    fprintf(stderr, "Trie built, time user %f system %f\n",
+        (double)(timing.tms_utime-previous.tms_utime)/CLK_TCK,
+        (double)(timing.tms_stime-previous.tms_stime)/CLK_TCK);
+    previous = timing;
+    fprintf(stderr, "Final offset is %d\n", offset);
+    
+    // Collect statistics on node types and sizes
+    int hCount = 0;
+    int vCount = 0;
+    size_t hSize = 0;
+    size_t vSize = 0;
+    size_t hItemCount = 0;
+    size_t vItemCount = 0;
+    uint32_t previousOff = offset;
+    for (uint16_t nodeIdx = nodeCount-1; nodeIdx >= 2; --nodeIdx) {
+        const CompactTrieNode *node = getCompactNode(header, nodeIdx);
+        if (node->flagscount & kVerticalNode) {
+            vCount += 1;
+            vItemCount += (node->flagscount & kCountMask);
+            vSize += previousOff-header->offsets[nodeIdx];
+        }
+        else {
+            hCount += 1;
+            hItemCount += (node->flagscount & kCountMask);
+            hSize += previousOff-header->offsets[nodeIdx];
+        }
+        previousOff = header->offsets[nodeIdx];
+    }
+    fprintf(stderr, "Horizontal nodes: %d total, average %f bytes with %f items\n", hCount,
+                (double)hSize/hCount, (double)hItemCount/hCount);
+    fprintf(stderr, "Vertical nodes: %d total, average %f bytes with %f items\n", vCount,
+                (double)vSize/vCount, (double)vItemCount/vCount);
+#endif
+
+    if (U_FAILURE(status)) {
+        uprv_free(bytes);
+        header = NULL;
+    }
+    else {
+        header->magic = COMPACT_TRIE_MAGIC_1;
+    }
+    return header;
+}
+
+// Forward declaration
+static TernaryNode *
+unpackOneNode( const CompactTrieHeader *header, const CompactTrieNode *node, UErrorCode &status );
+
+
+// Convert a horizontal node (or subarray thereof) into a ternary subtrie
+static TernaryNode *
+unpackHorizontalArray( const CompactTrieHeader *header, const CompactTrieHorizontalEntry *array,
+                            int low, int high, UErrorCode &status ) {
+    if (U_FAILURE(status) || low > high) {
+        return NULL;
+    }
+    int middle = (low+high)/2;
+    TernaryNode *result = new TernaryNode(array[middle].ch);
+    if (result == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    const CompactTrieNode *equal = getCompactNode(header, array[middle].equal);
+    if (equal->flagscount & kParentEndsWord) {
+        result->flags |= kEndsWord;
+    }
+    result->low = unpackHorizontalArray(header, array, low, middle-1, status);
+    result->high = unpackHorizontalArray(header, array, middle+1, high, status);
+    result->equal = unpackOneNode(header, equal, status);
+    return result;
+}                            
+
+// Convert one compact trie node into a ternary subtrie
+static TernaryNode *
+unpackOneNode( const CompactTrieHeader *header, const CompactTrieNode *node, UErrorCode &status ) {
+    int nodeCount = (node->flagscount & kCountMask);
+    if (nodeCount == 0 || U_FAILURE(status)) {
+        // Failure, or terminal node
+        return NULL;
+    }
+    if (node->flagscount & kVerticalNode) {
+        const CompactTrieVerticalNode *vnode = (const CompactTrieVerticalNode *)node;
+        TernaryNode *head = NULL;
+        TernaryNode *previous = NULL;
+        TernaryNode *latest = NULL;
+        for (int i = 0; i < nodeCount; ++i) {
+            latest = new TernaryNode(vnode->chars[i]);
+            if (latest == NULL) {
+                status = U_MEMORY_ALLOCATION_ERROR;
+                break;
+            }
+            if (head == NULL) {
+                head = latest;
+            }
+            if (previous != NULL) {
+                previous->equal = latest;
+            }
+            previous = latest;
+        }
+        if (latest != NULL) {
+            const CompactTrieNode *equal = getCompactNode(header, vnode->equal);
+            if (equal->flagscount & kParentEndsWord) {
+                latest->flags |= kEndsWord;
+            }
+            latest->equal = unpackOneNode(header, equal, status);
+        }
+        return head;
+    }
+    else {
+        // Horizontal node
+        const CompactTrieHorizontalNode *hnode = (const CompactTrieHorizontalNode *)node;
+        return unpackHorizontalArray(header, &hnode->entries[0], 0, nodeCount-1, status);
+    }
+}
+
+MutableTrieDictionary *
+CompactTrieDictionary::cloneMutable( UErrorCode &status ) const {
+    MutableTrieDictionary *result = new MutableTrieDictionary( status );
+    if (result == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    TernaryNode *root = unpackOneNode(fData, getCompactNode(fData, fData->root), status);
+    if (U_FAILURE(status)) {
+        delete root;    // Clean up
+        delete result;
+        return NULL;
+    }
+    result->fTrie = root;
+    return result;
+}
+
+U_NAMESPACE_END
+
+U_CAPI int32_t U_EXPORT2
+triedict_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 for dictionary data.
+    //    (Header contents are defined in genxxx.cpp)
+    //
+    const UDataInfo *pInfo = (const UDataInfo *)((const uint8_t *)inData+4);
+    if(!(  pInfo->dataFormat[0]==0x54 &&   /* dataFormat="TrDc" */
+           pInfo->dataFormat[1]==0x72 &&
+           pInfo->dataFormat[2]==0x44 &&
+           pInfo->dataFormat[3]==0x63 &&
+           pInfo->formatVersion[0]==1  )) {
+        udata_printError(ds, "triedict_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized\n",
+                         pInfo->dataFormat[0], pInfo->dataFormat[1],
+                         pInfo->dataFormat[2], pInfo->dataFormat[3],
+                         pInfo->formatVersion[0]);
+        *status=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    //
+    // Swap the data header.  (This is the generic ICU Data Header, not the 
+    //                         CompactTrieHeader).  This swap also conveniently gets us
+    //                         the size of the ICU d.h., which lets us locate the start
+    //                         of the RBBI specific data.
+    //
+    int32_t headerSize=udata_swapDataHeader(ds, inData, length, outData, status);
+
+    //
+    // Get the CompactTrieHeader, and check that it appears to be OK.
+    //
+    const uint8_t  *inBytes =(const uint8_t *)inData+headerSize;
+    const CompactTrieHeader *header = (const CompactTrieHeader *)inBytes;
+    if (ds->readUInt32(header->magic) != COMPACT_TRIE_MAGIC_1
+            || ds->readUInt32(header->size) < sizeof(CompactTrieHeader))
+    {
+        udata_printError(ds, "triedict_swap(): CompactTrieHeader is invalid.\n");
+        *status=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    //
+    // Prefight operation?  Just return the size
+    //
+    uint32_t totalSize = ds->readUInt32(header->size);
+    int32_t sizeWithUData = (int32_t)totalSize + headerSize;
+    if (length < 0) {
+        return sizeWithUData;
+    }
+
+    //
+    // Check that length passed in is consistent with length from RBBI data header.
+    //
+    if (length < sizeWithUData) {
+        udata_printError(ds, "triedict_swap(): too few bytes (%d after ICU Data header) for trie data.\n",
+                            totalSize);
+        *status=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0;
+        }
+
+    //
+    // Swap the Data.  Do the data itself first, then the CompactTrieHeader, 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;
+    CompactTrieHeader   *outputHeader = (CompactTrieHeader *)outBytes;
+
+#if 0
+    //
+    // If not swapping in place, zero out the output buffer before starting.
+    //
+    if (inBytes != outBytes) {
+        uprv_memset(outBytes, 0, totalSize);
+    }
+
+    // We need to loop through all the nodes in the offset table, and swap each one.
+    uint16_t nodeCount = ds->readUInt16(header->nodeCount);
+    // Skip node 0, which should always be 0.
+    for (int i = 1; i < nodeCount; ++i) {
+        uint32_t nodeOff = ds->readUInt32(header->offsets[i]);
+        const CompactTrieNode *inNode = (const CompactTrieNode *)(inBytes + nodeOff);
+        CompactTrieNode *outNode = (CompactTrieNode *)(outBytes + nodeOff);
+        uint16_t flagscount = ds->readUInt16(inNode->flagscount);
+        uint16_t itemCount = flagscount & kCountMask;
+        ds->writeUInt16(&outNode->flagscount, flagscount);
+        if (itemCount > 0) {
+            if (flagscount & kVerticalNode) {
+                ds->swapArray16(ds, inBytes+nodeOff+offsetof(CompactTrieVerticalNode,chars),
+                                    itemCount*sizeof(uint16_t),
+                                    outBytes+nodeOff+offsetof(CompactTrieVerticalNode,chars), status);
+                uint16_t equal = ds->readUInt16(inBytes+nodeOff+offsetof(CompactTrieVerticalNode,equal);
+                ds->writeUInt16(outBytes+nodeOff+offsetof(CompactTrieVerticalNode,equal));
+            }
+            else {
+                const CompactTrieHorizontalNode *inHNode = (const CompactTrieHorizontalNode *)inNode;
+                CompactTrieHorizontalNode *outHNode = (CompactTrieHorizontalNode *)outNode;
+                for (int j = 0; j < itemCount; ++j) {
+                    uint16_t word = ds->readUInt16(inHNode->entries[j].ch);
+                    ds->writeUInt16(&outHNode->entries[j].ch, word);
+                    word = ds->readUInt16(inHNode->entries[j].equal);
+                    ds->writeUInt16(&outHNode->entries[j].equal, word);
+                }
+            }
+        }
+    }
+#endif
+
+    // All the data in all the nodes consist of 16 bit items. Swap them all at once.
+    uint16_t nodeCount = ds->readUInt16(header->nodeCount);
+    uint32_t nodesOff = offsetof(CompactTrieHeader,offsets)+((uint32_t)nodeCount*sizeof(uint32_t));
+    ds->swapArray16(ds, inBytes+nodesOff, totalSize-nodesOff, outBytes+nodesOff, status);
+
+    // Swap the header
+    ds->writeUInt32(&outputHeader->size, totalSize);
+    uint32_t magic = ds->readUInt32(header->magic);
+    ds->writeUInt32(&outputHeader->magic, magic);
+    ds->writeUInt16(&outputHeader->nodeCount, nodeCount);
+    uint16_t root = ds->readUInt16(header->root);
+    ds->writeUInt16(&outputHeader->root, root);
+    ds->swapArray32(ds, inBytes+offsetof(CompactTrieHeader,offsets),
+            sizeof(uint32_t)*(int32_t)nodeCount,
+            outBytes+offsetof(CompactTrieHeader,offsets), status);
+
+    return sizeWithUData;
+}
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
diff --git a/source/common/triedict.h b/source/common/triedict.h
new file mode 100644
index 0000000..b879661
--- /dev/null
+++ b/source/common/triedict.h
@@ -0,0 +1,346 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2006, International Business Machines Corporation and others. *
+ * All Rights Reserved.                                                        *
+ *******************************************************************************
+ */
+
+#ifndef TRIEDICT_H
+#define TRIEDICT_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/utext.h"
+
+struct UEnumeration;
+struct UDataSwapper;
+struct UDataMemory;
+
+ /**
+  * <p>UDataSwapFn function for use in swapping a compact dictionary.</p>
+  *
+  * @param ds Pointer to UDataSwapper containing global data about the
+  *           transformation and function pointers for handling primitive
+  *           types.
+  * @param inData Pointer to the input data to be transformed or examined.
+  * @param length Length of the data, counting bytes. May be -1 for preflighting.
+  *               If length>=0, then transform the data.
+  *               If length==-1, then only determine the length of the data.
+  *               The length cannot be determined from the data itself for all
+  *               types of data (e.g., not for simple arrays of integers).
+  * @param outData Pointer to the output data buffer.
+  *                If length>=0 (transformation), then the output buffer must
+  *                have a capacity of at least length.
+  *                If length==-1, then outData will not be used and can be NULL.
+  * @param pErrorCode ICU UErrorCode parameter, must not be NULL and must
+  *                   fulfill U_SUCCESS on input.
+  * @return The actual length of the data.
+  *
+  * @see UDataSwapper
+  */
+
+U_CAPI int32_t U_EXPORT2
+triedict_swap(const UDataSwapper *ds,
+            const void *inData, int32_t length, void *outData,
+            UErrorCode *pErrorCode);
+
+U_NAMESPACE_BEGIN
+
+class StringEnumeration;
+struct CompactTrieHeader;
+
+/*******************************************************************
+ * TrieWordDictionary
+ */
+
+/**
+ * <p>TrieWordDictionary is an abstract class that represents a word
+ * dictionary based on a trie. The base protocol is read-only.
+ * Subclasses may allow writing.</p>
+ */
+class U_COMMON_API TrieWordDictionary : public UMemory {
+ public:
+
+  /**
+   * <p>Default constructor.</p>
+   *
+   */
+  TrieWordDictionary();
+
+  /**
+   * <p>Virtual destructor.</p>
+   */
+  virtual ~TrieWordDictionary();
+
+ /**
+  * <p>Find dictionary words that match the text.</p>
+  *
+  * @param text A UText representing the text. The
+  * iterator is left after the longest prefix match in the dictionary.
+  * @param start The current position in text.
+  * @param maxLength The maximum number of code units to match.
+  * @param lengths An array that is filled with the lengths of words that matched.
+  * @param count Filled with the number of elements output in lengths.
+  * @param limit The size of the lengths array; this limits the number of words output.
+  * @return The number of characters in text that were matched.
+  */
+  virtual int32_t matches( UText *text,
+                              int32_t maxLength,
+                              int32_t *lengths,
+                              int &count,
+                              int limit ) const = 0;
+
+  /**
+   * <p>Return a StringEnumeration for iterating all the words in the dictionary.</p>
+   *
+   * @param status A status code recording the success of the call.
+   * @return A StringEnumeration that will iterate through the whole dictionary.
+   * The caller is responsible for closing it. The order is unspecified.
+   */
+  virtual StringEnumeration *openWords( UErrorCode &status ) const = 0;
+
+};
+
+/*******************************************************************
+ * MutableTrieDictionary
+ */
+
+/**
+ * <p>MutableTrieDictionary is a TrieWordDictionary that allows words to be
+ * added.</p>
+ */
+
+struct TernaryNode;             // Forwards declaration
+
+class U_COMMON_API MutableTrieDictionary : public TrieWordDictionary {
+ private:
+    /**
+     * The root node of the trie
+     * @internal
+     */
+
+  TernaryNode               *fTrie;
+
+    /**
+     * A UText for internal use
+     * @internal
+     */
+
+  UText    *fIter;
+
+  friend class CompactTrieDictionary;   // For fast conversion
+
+ public:
+
+ /**
+  * <p>Constructor.</p>
+  *
+  * @param median A UChar around which to balance the trie. Ideally, it should
+  * begin at least one word that is near the median of the set in the dictionary
+  * @param status A status code recording the success of the call.
+  */
+  MutableTrieDictionary( UChar median, UErrorCode &status );
+
+  /**
+   * <p>Virtual destructor.</p>
+   */
+  virtual ~MutableTrieDictionary();
+
+ /**
+  * <p>Find dictionary words that match the text.</p>
+  *
+  * @param text A UText representing the text. The
+  * iterator is left after the longest prefix match in the dictionary.
+  * @param maxLength The maximum number of code units to match.
+  * @param lengths An array that is filled with the lengths of words that matched.
+  * @param count Filled with the number of elements output in lengths.
+  * @param limit The size of the lengths array; this limits the number of words output.
+  * @return The number of characters in text that were matched.
+  */
+  virtual int32_t matches( UText *text,
+                              int32_t maxLength,
+                              int32_t *lengths,
+                              int &count,
+                              int limit ) const;
+
+  /**
+   * <p>Return a StringEnumeration for iterating all the words in the dictionary.</p>
+   *
+   * @param status A status code recording the success of the call.
+   * @return A StringEnumeration that will iterate through the whole dictionary.
+   * The caller is responsible for closing it. The order is unspecified.
+   */
+  virtual StringEnumeration *openWords( UErrorCode &status ) const;
+
+ /**
+  * <p>Add one word to the dictionary.</p>
+  *
+  * @param word A UChar buffer containing the word.
+  * @param length The length of the word.
+  * @param status The resultant status
+  */
+  virtual void addWord( const UChar *word,
+                        int32_t length,
+                        UErrorCode &status);
+
+#if 0
+ /**
+  * <p>Add all strings from a UEnumeration to the dictionary.</p>
+  *
+  * @param words A UEnumeration that will return the desired words.
+  * @param status The resultant status
+  */
+  virtual void addWords( UEnumeration *words, UErrorCode &status );
+#endif
+
+protected:
+ /**
+  * <p>Search the dictionary for matches.</p>
+  *
+  * @param text A UText representing the text. The
+  * iterator is left after the longest prefix match in the dictionary.
+  * @param maxLength The maximum number of code units to match.
+  * @param lengths An array that is filled with the lengths of words that matched.
+  * @param count Filled with the number of elements output in lengths.
+  * @param limit The size of the lengths array; this limits the number of words output.
+  * @param parent The parent of the current node
+  * @param pMatched The returned parent node matched the input
+  * @return The number of characters in text that were matched.
+  */
+  virtual int32_t search( UText *text,
+                              int32_t maxLength,
+                              int32_t *lengths,
+                              int &count,
+                              int limit,
+                              TernaryNode *&parent,
+                              UBool &pMatched ) const;
+
+private:
+ /**
+  * <p>Private constructor. The root node it not allocated.</p>
+  *
+  * @param status A status code recording the success of the call.
+  */
+  MutableTrieDictionary( UErrorCode &status );
+};
+
+/*******************************************************************
+ * CompactTrieDictionary
+ */
+
+/**
+ * <p>CompactTrieDictionary is a TrieWordDictionary that has been compacted
+ * to save space.</p>
+ */
+class U_COMMON_API CompactTrieDictionary : public TrieWordDictionary {
+ private:
+    /**
+     * The root node of the trie
+     */
+
+  const CompactTrieHeader   *fData;
+
+    /**
+     * A UBool indicating whether or not we own the fData.
+     */
+
+  UBool                     fOwnData;
+
+    UDataMemory              *fUData;
+ public:
+  /**
+   * <p>Construct a dictionary from a UDataMemory.</p>
+   *
+   * @param data A pointer to a UDataMemory, which is adopted
+   * @param status A status code giving the result of the constructor
+   */
+  CompactTrieDictionary(UDataMemory *dataObj, UErrorCode &status);
+
+  /**
+   * <p>Construct a dictionary from raw saved data.</p>
+   *
+   * @param data A pointer to the raw data, which is still owned by the caller
+   * @param status A status code giving the result of the constructor
+   */
+  CompactTrieDictionary(const void *dataObj, UErrorCode &status);
+
+  /**
+   * <p>Construct a dictionary from a MutableTrieDictionary.</p>
+   *
+   * @param dict The dictionary to use as input.
+   * @param status A status code recording the success of the call.
+   */
+  CompactTrieDictionary( const MutableTrieDictionary &dict, UErrorCode &status );
+
+  /**
+   * <p>Virtual destructor.</p>
+   */
+  virtual ~CompactTrieDictionary();
+
+ /**
+  * <p>Find dictionary words that match the text.</p>
+  *
+  * @param text A UText representing the text. The
+  * iterator is left after the longest prefix match in the dictionary.
+  * @param maxLength The maximum number of code units to match.
+  * @param lengths An array that is filled with the lengths of words that matched.
+  * @param count Filled with the number of elements output in lengths.
+  * @param limit The size of the lengths array; this limits the number of words output.
+  * @return The number of characters in text that were matched.
+  */
+  virtual int32_t matches( UText *text,
+                              int32_t rangeEnd,
+                              int32_t *lengths,
+                              int &count,
+                              int limit ) const;
+
+  /**
+   * <p>Return a StringEnumeration for iterating all the words in the dictionary.</p>
+   *
+   * @param status A status code recording the success of the call.
+   * @return A StringEnumeration that will iterate through the whole dictionary.
+   * The caller is responsible for closing it. The order is unspecified.
+   */
+  virtual StringEnumeration *openWords( UErrorCode &status ) const;
+
+ /**
+  * <p>Return the size of the compact data.</p>
+  *
+  * @return The size of the dictionary's compact data.
+  */
+  virtual uint32_t dataSize() const;
+  
+ /**
+  * <p>Return a void * pointer to the compact data, platform-endian.</p>
+  *
+  * @return The data for the compact dictionary, suitable for passing to the
+  * constructor.
+  */
+  virtual const void *data() const;
+  
+ /**
+  * <p>Return a MutableTrieDictionary clone of this dictionary.</p>
+  *
+  * @param status A status code recording the success of the call.
+  * @return A MutableTrieDictionary with the same data as this dictionary
+  */
+  virtual MutableTrieDictionary *cloneMutable( UErrorCode &status ) const;
+  
+ private:
+ 
+  /**
+   * <p>Convert a MutableTrieDictionary into a compact data blob.</p>
+   *
+   * @param dict The dictionary to convert.
+   * @param status A status code recording the success of the call.
+   * @return A single data blob starting with a CompactTrieHeader.
+   */
+  static CompactTrieHeader *compactMutableTrieDictionary( const MutableTrieDictionary &dict,
+                                                        UErrorCode &status );
+
+};
+
+U_NAMESPACE_END
+
+    /* TRIEDICT_H */
+#endif
diff --git a/source/common/uarrsort.c b/source/common/uarrsort.c
new file mode 100644
index 0000000..8bc967c
--- /dev/null
+++ b/source/common/uarrsort.c
@@ -0,0 +1,236 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2003, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  uarrsort.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2003aug04
+*   created by: Markus W. Scherer
+*
+*   Internal function for sorting arrays.
+*/
+
+#include "unicode/utypes.h"
+#include "cmemory.h"
+#include "uarrsort.h"
+
+enum {
+    MIN_QSORT=9, /* from Knuth */
+    STACK_ITEM_SIZE=200
+};
+
+/* UComparator convenience implementations ---------------------------------- */
+
+U_CAPI int32_t U_EXPORT2
+uprv_uint16Comparator(const void *context, const void *left, const void *right) {
+    return (int32_t)*(const uint16_t *)left - (int32_t)*(const uint16_t *)right;
+}
+
+U_CAPI int32_t U_EXPORT2
+uprv_int32Comparator(const void *context, const void *left, const void *right) {
+    return *(const int32_t *)left - *(const int32_t *)right;
+}
+
+U_CAPI int32_t U_EXPORT2
+uprv_uint32Comparator(const void *context, const void *left, const void *right) {
+    uint32_t l=*(const uint32_t *)left, r=*(const uint32_t *)right;
+
+    /* compare directly because (l-r) would overflow the int32_t result */
+    if(l<r) {
+        return -1;
+    } else if(l==r) {
+        return 0;
+    } else /* l>r */ {
+        return 1;
+    }
+}
+
+/* Straight insertion sort from Knuth vol. III, pg. 81 ---------------------- */
+
+static void
+doInsertionSort(char *array, int32_t start, int32_t limit, int32_t itemSize,
+                UComparator *cmp, const void *context, void *pv) {
+    int32_t i, j;
+
+    for(j=start+1; j<limit; ++j) {
+        /* v=array[j] */
+        uprv_memcpy(pv, array+j*itemSize, itemSize);
+
+        for(i=j; i>start; --i) {
+            if(/* v>=array[i-1] */ cmp(context, pv, array+(i-1)*itemSize)>=0) {
+                break;
+            }
+
+            /* array[i]=array[i-1]; */
+            uprv_memcpy(array+i*itemSize, array+(i-1)*itemSize, itemSize);
+        }
+
+        if(i!=j) {
+            /* array[i]=v; */
+            uprv_memcpy(array+i*itemSize, pv, itemSize);
+        }
+    }
+}
+
+static void
+insertionSort(char *array, int32_t length, int32_t itemSize,
+              UComparator *cmp, const void *context, UErrorCode *pErrorCode) {
+    UAlignedMemory v[STACK_ITEM_SIZE/sizeof(UAlignedMemory)+1];
+    void *pv;
+
+    /* allocate an intermediate item variable (v) */
+    if(itemSize<=STACK_ITEM_SIZE) {
+        pv=v;
+    } else {
+        pv=uprv_malloc(itemSize);
+        if(pv==NULL) {
+            *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+    }
+
+    doInsertionSort(array, 0, length, itemSize, cmp, context, pv);
+
+    if(pv!=v) {
+        uprv_free(pv);
+    }
+}
+
+/* QuickSort ---------------------------------------------------------------- */
+
+/*
+ * This implementation is semi-recursive:
+ * It recurses for the smaller sub-array to shorten the recursion depth,
+ * and loops for the larger sub-array.
+ *
+ * Loosely after QuickSort algorithms in
+ * Niklaus Wirth
+ * Algorithmen und Datenstrukturen mit Modula-2
+ * B.G. Teubner Stuttgart
+ * 4. Auflage 1986
+ * ISBN 3-519-02260-5
+ */
+static void
+subQuickSort(char *array, int32_t start, int32_t limit, int32_t itemSize,
+             UComparator *cmp, const void *context,
+             void *px, void *pw) {
+    int32_t left, right;
+
+    /* start and left are inclusive, limit and right are exclusive */
+    do {
+        if((start+MIN_QSORT)>=limit) {
+            doInsertionSort(array, start, limit, itemSize, cmp, context, px);
+            break;
+        }
+
+        left=start;
+        right=limit;
+
+        /* x=array[middle] */
+        uprv_memcpy(px, array+((start+limit)/2)*itemSize, itemSize);
+
+        do {
+            while(/* array[left]<x */
+                  cmp(context, array+left*itemSize, px)<0
+            ) {
+                ++left;
+            }
+            while(/* x<array[right-1] */
+                  cmp(context, px, array+(right-1)*itemSize)<0
+            ) {
+                --right;
+            }
+
+            /* swap array[left] and array[right-1] via w; ++left; --right */
+            if(left<right) {
+                --right;
+
+                if(left<right) {
+                    uprv_memcpy(pw, array+left*itemSize, itemSize);
+                    uprv_memcpy(array+left*itemSize, array+right*itemSize, itemSize);
+                    uprv_memcpy(array+right*itemSize, pw, itemSize);
+                }
+
+                ++left;
+            }
+        } while(left<right);
+
+        /* sort sub-arrays */
+        if((right-start)<(limit-left)) {
+            /* sort [start..right[ */
+            if(start<(right-1)) {
+                subQuickSort(array, start, right, itemSize, cmp, context, px, pw);
+            }
+
+            /* sort [left..limit[ */
+            start=left;
+        } else {
+            /* sort [left..limit[ */
+            if(left<(limit-1)) {
+                subQuickSort(array, left, limit, itemSize, cmp, context, px, pw);
+            }
+
+            /* sort [start..right[ */
+            limit=right;
+        }
+    } while(start<(limit-1));
+}
+
+static void
+quickSort(char *array, int32_t length, int32_t itemSize,
+            UComparator *cmp, const void *context, UErrorCode *pErrorCode) {
+    UAlignedMemory xw[(2*STACK_ITEM_SIZE)/sizeof(UAlignedMemory)+1];
+    void *p;
+
+    /* allocate two intermediate item variables (x and w) */
+    if(itemSize<=STACK_ITEM_SIZE) {
+        p=xw;
+    } else {
+        p=uprv_malloc(2*itemSize);
+        if(p==NULL) {
+            *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+    }
+
+    subQuickSort(array, 0, length, itemSize,
+                 cmp, context, p, (char *)p+itemSize);
+
+    if(p!=xw) {
+        uprv_free(p);
+    }
+}
+
+/* uprv_sortArray() API ----------------------------------------------------- */
+
+/*
+ * Check arguments, select an appropriate implementation,
+ * cast the array to char * so that array+i*itemSize works.
+ */
+U_CAPI void U_EXPORT2
+uprv_sortArray(void *array, int32_t length, int32_t itemSize,
+               UComparator *cmp, const void *context,
+               UBool sortStable, UErrorCode *pErrorCode) {
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return;
+    }
+    if((length>0 && array==NULL) || length<0 || itemSize<=0 || cmp==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    if(length<=1) {
+        return;
+    } else if(length<MIN_QSORT || sortStable) {
+        insertionSort((char *)array, length, itemSize, cmp, context, pErrorCode);
+        /* could add heapSort or similar for stable sorting of longer arrays */
+    } else {
+        quickSort((char *)array, length, itemSize, cmp, context, pErrorCode);
+    }
+}
diff --git a/source/common/uarrsort.h b/source/common/uarrsort.h
new file mode 100644
index 0000000..b9a580c
--- /dev/null
+++ b/source/common/uarrsort.h
@@ -0,0 +1,84 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2003, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  uarrsort.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2003aug04
+*   created by: Markus W. Scherer
+*
+*   Internal function for sorting arrays.
+*/
+
+#ifndef __UARRSORT_H__
+#define __UARRSORT_H__
+
+#include "unicode/utypes.h"
+
+U_CDECL_BEGIN
+/**
+ * Function type for comparing two items as part of sorting an array or similar.
+ * Callback function for uprv_sortArray().
+ *
+ * @param context Application-specific pointer, passed through by uprv_sortArray().
+ * @param left    Pointer to the "left" item.
+ * @param right   Pointer to the "right" item.
+ * @return 32-bit signed integer comparison result:
+ *                <0 if left<right
+ *               ==0 if left==right
+ *                >0 if left>right
+ *
+ * @internal
+ */
+typedef int32_t U_CALLCONV
+UComparator(const void *context, const void *left, const void *right);
+U_CDECL_END
+
+/**
+ * Array sorting function.
+ * Uses a UComparator for comparing array items to each other, and simple
+ * memory copying to move items.
+ *
+ * @param array      The array to be sorted.
+ * @param length     The number of items in the array.
+ * @param itemSize   The size in bytes of each array item.
+ * @param cmp        UComparator function used to compare two items each.
+ * @param context    Application-specific pointer, passed through to the UComparator.
+ * @param sortStable If true, a stable sorting algorithm must be used.
+ * @param pErrorCode ICU in/out UErrorCode parameter.
+ *
+ * @internal
+ */
+U_CAPI void U_EXPORT2
+uprv_sortArray(void *array, int32_t length, int32_t itemSize,
+               UComparator *cmp, const void *context,
+               UBool sortStable, UErrorCode *pErrorCode);
+
+/**
+ * Convenience UComparator implementation for uint16_t arrays.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+uprv_uint16Comparator(const void *context, const void *left, const void *right);
+
+/**
+ * Convenience UComparator implementation for int32_t arrays.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+uprv_int32Comparator(const void *context, const void *left, const void *right);
+
+/**
+ * Convenience UComparator implementation for uint32_t arrays.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+uprv_uint32Comparator(const void *context, const void *left, const void *right);
+
+#endif
diff --git a/source/common/uassert.h b/source/common/uassert.h
new file mode 100644
index 0000000..9b1a141
--- /dev/null
+++ b/source/common/uassert.h
@@ -0,0 +1,32 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2002-2003, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File uassert.h
+*
+*  Contains U_ASSERT macro
+*
+*    By default, U_ASSERT just wraps the C library assert macro.
+*    By changing the definition here, the assert behavior for ICU can be changed
+*    without affecting other non-ICU uses of the C library assert().
+*
+******************************************************************************
+*/
+
+#ifndef U_ASSERT_H
+#define U_ASSERT_H
+/* utypes.h is included to get the proper define for uint8_t */
+#include "unicode/utypes.h"
+#if U_RELEASE
+#define U_ASSERT(exp)
+#else
+#include <assert.h>
+#define U_ASSERT(exp) assert(exp)
+#endif
+#endif
+
+
diff --git a/source/common/ubidi.c b/source/common/ubidi.c
new file mode 100644
index 0000000..cec0372
--- /dev/null
+++ b/source/common/ubidi.c
@@ -0,0 +1,2240 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  ubidi.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999jul27
+*   created by: Markus W. Scherer, updated by Matitiahu Allouche
+*/
+
+#include "cmemory.h"
+#include "unicode/utypes.h"
+#include "unicode/ustring.h"
+#include "unicode/uchar.h"
+#include "unicode/ubidi.h"
+#include "ubidi_props.h"
+#include "ubidiimp.h"
+#include "uassert.h"
+
+/*
+ * General implementation notes:
+ *
+ * Throughout the implementation, there are comments like (W2) that refer to
+ * rules of the BiDi algorithm in its version 5, in this example to the second
+ * rule of the resolution of weak types.
+ *
+ * For handling surrogate pairs, where two UChar's form one "abstract" (or UTF-32)
+ * character according to UTF-16, the second UChar gets the directional property of
+ * the entire character assigned, while the first one gets a BN, a boundary
+ * neutral, type, which is ignored by most of the algorithm according to
+ * rule (X9) and the implementation suggestions of the BiDi algorithm.
+ *
+ * Later, adjustWSLevels() will set the level for each BN to that of the
+ * following character (UChar), which results in surrogate pairs getting the
+ * same level on each of their surrogates.
+ *
+ * In a UTF-8 implementation, the same thing could be done: the last byte of
+ * a multi-byte sequence would get the "real" property, while all previous
+ * bytes of that sequence would get BN.
+ *
+ * It is not possible to assign all those parts of a character the same real
+ * property because this would fail in the resolution of weak types with rules
+ * that look at immediately surrounding types.
+ *
+ * As a related topic, this implementation does not remove Boundary Neutral
+ * types from the input, but ignores them wherever this is relevant.
+ * For example, the loop for the resolution of the weak types reads
+ * types until it finds a non-BN.
+ * Also, explicit embedding codes are neither changed into BN nor removed.
+ * They are only treated the same way real BNs are.
+ * As stated before, adjustWSLevels() takes care of them at the end.
+ * For the purpose of conformance, the levels of all these codes
+ * do not matter.
+ *
+ * Note that this implementation never modifies the dirProps
+ * after the initial setup.
+ *
+ *
+ * In this implementation, the resolution of weak types (Wn),
+ * neutrals (Nn), and the assignment of the resolved level (In)
+ * are all done in one single loop, in resolveImplicitLevels().
+ * Changes of dirProp values are done on the fly, without writing
+ * them back to the dirProps array.
+ *
+ *
+ * This implementation contains code that allows to bypass steps of the
+ * algorithm that are not needed on the specific paragraph
+ * in order to speed up the most common cases considerably,
+ * like text that is entirely LTR, or RTL text without numbers.
+ *
+ * Most of this is done by setting a bit for each directional property
+ * in a flags variable and later checking for whether there are
+ * any LTR characters or any RTL characters, or both, whether
+ * there are any explicit embedding codes, etc.
+ *
+ * If the (Xn) steps are performed, then the flags are re-evaluated,
+ * because they will then not contain the embedding codes any more
+ * and will be adjusted for override codes, so that subsequently
+ * more bypassing may be possible than what the initial flags suggested.
+ *
+ * If the text is not mixed-directional, then the
+ * algorithm steps for the weak type resolution are not performed,
+ * and all levels are set to the paragraph level.
+ *
+ * If there are no explicit embedding codes, then the (Xn) steps
+ * are not performed.
+ *
+ * If embedding levels are supplied as a parameter, then all
+ * explicit embedding codes are ignored, and the (Xn) steps
+ * are not performed.
+ *
+ * White Space types could get the level of the run they belong to,
+ * and are checked with a test of (flags&MASK_EMBEDDING) to
+ * consider if the paragraph direction should be considered in
+ * the flags variable.
+ *
+ * If there are no White Space types in the paragraph, then
+ * (L1) is not necessary in adjustWSLevels().
+ */
+
+/* to avoid some conditional statements, use tiny constant arrays */
+static const Flags flagLR[2]={ DIRPROP_FLAG(L), DIRPROP_FLAG(R) };
+static const Flags flagE[2]={ DIRPROP_FLAG(LRE), DIRPROP_FLAG(RLE) };
+static const Flags flagO[2]={ DIRPROP_FLAG(LRO), DIRPROP_FLAG(RLO) };
+
+#define DIRPROP_FLAG_LR(level) flagLR[(level)&1]
+#define DIRPROP_FLAG_E(level) flagE[(level)&1]
+#define DIRPROP_FLAG_O(level) flagO[(level)&1]
+
+/* UBiDi object management -------------------------------------------------- */
+
+U_CAPI UBiDi * U_EXPORT2
+ubidi_open(void)
+{
+    UErrorCode errorCode=U_ZERO_ERROR;
+    return ubidi_openSized(0, 0, &errorCode);
+}
+
+U_CAPI UBiDi * U_EXPORT2
+ubidi_openSized(int32_t maxLength, int32_t maxRunCount, UErrorCode *pErrorCode) {
+    UBiDi *pBiDi;
+
+    /* check the argument values */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return NULL;
+    } else if(maxLength<0 || maxRunCount<0) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;    /* invalid arguments */
+    }
+
+    /* allocate memory for the object */
+    pBiDi=(UBiDi *)uprv_malloc(sizeof(UBiDi));
+    if(pBiDi==NULL) {
+        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+
+    /* reset the object, all pointers NULL, all flags FALSE, all sizes 0 */
+    uprv_memset(pBiDi, 0, sizeof(UBiDi));
+
+    /* get BiDi properties */
+    pBiDi->bdp=ubidi_getSingleton();
+
+    /* allocate memory for arrays as requested */
+    if(maxLength>0) {
+        if( !getInitialDirPropsMemory(pBiDi, maxLength) ||
+            !getInitialLevelsMemory(pBiDi, maxLength)
+        ) {
+            *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+        }
+    } else {
+        pBiDi->mayAllocateText=TRUE;
+    }
+
+    if(maxRunCount>0) {
+        if(maxRunCount==1) {
+            /* use simpleRuns[] */
+            pBiDi->runsSize=sizeof(Run);
+        } else if(!getInitialRunsMemory(pBiDi, maxRunCount)) {
+            *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+        }
+    } else {
+        pBiDi->mayAllocateRuns=TRUE;
+    }
+
+    if(U_SUCCESS(*pErrorCode)) {
+        return pBiDi;
+    } else {
+        ubidi_close(pBiDi);
+        return NULL;
+    }
+}
+
+/*
+ * We are allowed to allocate memory if memory==NULL or
+ * mayAllocate==TRUE for each array that we need.
+ * We also try to grow memory as needed if we
+ * allocate it.
+ *
+ * Assume sizeNeeded>0.
+ * If *pMemory!=NULL, then assume *pSize>0.
+ *
+ * ### this realloc() may unnecessarily copy the old data,
+ * which we know we don't need any more;
+ * is this the best way to do this??
+ */
+U_CFUNC UBool
+ubidi_getMemory(BidiMemoryForAllocation *bidiMem, int32_t *pSize, UBool mayAllocate, int32_t sizeNeeded) {
+    void **pMemory = (void **)bidiMem;
+    /* check for existing memory */
+    if(*pMemory==NULL) {
+        /* we need to allocate memory */
+        if(mayAllocate && (*pMemory=uprv_malloc(sizeNeeded))!=NULL) {
+            *pSize=sizeNeeded;
+            return TRUE;
+        } else {
+            return FALSE;
+        }
+    } else {
+        if(sizeNeeded<=*pSize) {
+            /* there is already enough memory */
+            return TRUE;
+        }
+        else if(!mayAllocate) {
+            /* not enough memory, and we must not allocate */
+            return FALSE;
+        } else {
+            /* we try to grow */
+            void *memory;
+            /* in most cases, we do not need the copy-old-data part of
+             * realloc, but it is needed when adding runs using getRunsMemory()
+             * in setParaRunsOnly()
+             */
+            if((memory=uprv_realloc(*pMemory, sizeNeeded))!=NULL) {
+                *pMemory=memory;
+                *pSize=sizeNeeded;
+                return TRUE;
+            } else {
+                /* we failed to grow */
+                return FALSE;
+            }
+        }
+    }
+}
+
+U_CAPI void U_EXPORT2
+ubidi_close(UBiDi *pBiDi) {
+    if(pBiDi!=NULL) {
+        pBiDi->pParaBiDi=NULL;          /* in case one tries to reuse this block */
+        if(pBiDi->dirPropsMemory!=NULL) {
+            uprv_free(pBiDi->dirPropsMemory);
+        }
+        if(pBiDi->levelsMemory!=NULL) {
+            uprv_free(pBiDi->levelsMemory);
+        }
+        if(pBiDi->runsMemory!=NULL) {
+            uprv_free(pBiDi->runsMemory);
+        }
+        if(pBiDi->parasMemory!=NULL) {
+            uprv_free(pBiDi->parasMemory);
+        }
+        if(pBiDi->insertPoints.points!=NULL) {
+            uprv_free(pBiDi->insertPoints.points);
+        }
+
+        uprv_free(pBiDi);
+    }
+}
+
+/* set to approximate "inverse BiDi" ---------------------------------------- */
+
+U_CAPI void U_EXPORT2
+ubidi_setInverse(UBiDi *pBiDi, UBool isInverse) {
+    if(pBiDi!=NULL) {
+        pBiDi->isInverse=isInverse;
+        pBiDi->reorderingMode = isInverse ? UBIDI_REORDER_INVERSE_NUMBERS_AS_L
+                                          : UBIDI_REORDER_DEFAULT;
+    }
+}
+
+U_CAPI UBool U_EXPORT2
+ubidi_isInverse(UBiDi *pBiDi) {
+    if(pBiDi!=NULL) {
+        return pBiDi->isInverse;
+    } else {
+        return FALSE;
+    }
+}
+
+/* FOOD FOR THOUGHT: currently the reordering modes are a mixture of
+ * algorithm for direct BiDi, algorithm for inverse BiDi and the bizarre
+ * concept of RUNS_ONLY which is a double operation.
+ * It could be advantageous to divide this into 3 concepts:
+ * a) Operation: direct / inverse / RUNS_ONLY
+ * b) Direct algorithm: default / NUMBERS_SPECIAL / GROUP_NUMBERS_WITH_R
+ * c) Inverse algorithm: default / INVERSE_LIKE_DIRECT / NUMBERS_SPECIAL
+ * This would allow combinations not possible today like RUNS_ONLY with
+ * NUMBERS_SPECIAL.
+ * Also allow to set INSERT_MARKS for the direct step of RUNS_ONLY and
+ * REMOVE_CONTROLS for the inverse step.
+ * Not all combinations would be supported, and probably not all do make sense.
+ * This would need to document which ones are supported and what are the
+ * fallbacks for unsupported combinations.
+ */
+U_CAPI void U_EXPORT2
+ubidi_setReorderingMode(UBiDi *pBiDi, UBiDiReorderingMode reorderingMode) {
+    if ((pBiDi!=NULL) && (reorderingMode >= UBIDI_REORDER_DEFAULT)
+                        && (reorderingMode < UBIDI_REORDER_COUNT)) {
+        pBiDi->reorderingMode = reorderingMode;
+        pBiDi->isInverse = (UBool)(reorderingMode == UBIDI_REORDER_INVERSE_NUMBERS_AS_L);
+    }
+}
+
+U_CAPI UBiDiReorderingMode U_EXPORT2
+ubidi_getReorderingMode(UBiDi *pBiDi) {
+    if (pBiDi!=NULL) {
+        return pBiDi->reorderingMode;
+    } else {
+        return UBIDI_REORDER_DEFAULT;
+    }
+}
+
+U_CAPI void U_EXPORT2
+ubidi_setReorderingOptions(UBiDi *pBiDi, uint32_t reorderingOptions) {
+    if (reorderingOptions & UBIDI_OPTION_REMOVE_CONTROLS) {
+        reorderingOptions&=~UBIDI_OPTION_INSERT_MARKS;
+    }
+    if (pBiDi!=NULL) {
+        pBiDi->reorderingOptions=reorderingOptions;
+    }
+}
+
+U_CAPI uint32_t U_EXPORT2
+ubidi_getReorderingOptions(UBiDi *pBiDi) {
+    if (pBiDi!=NULL) {
+        return pBiDi->reorderingOptions;
+    } else {
+        return 0;
+    }
+}
+
+U_CAPI UBiDiDirection U_EXPORT2
+ubidi_getBaseDirection(const UChar *text,
+int32_t length){
+
+    int32_t i;
+    UChar32 uchar;
+    UCharDirection dir;
+    
+    if( text==NULL || length<-1 ){
+        return UBIDI_NEUTRAL;
+    }
+
+    if(length==-1) {
+        length=u_strlen(text);
+    }
+
+    for( i = 0 ; i < length; ) {
+        /* i is incremented by U16_NEXT */
+        U16_NEXT(text, i, length, uchar);
+        dir = u_charDirection(uchar);
+        if( dir == U_LEFT_TO_RIGHT )
+                return UBIDI_LTR;
+        if( dir == U_RIGHT_TO_LEFT || dir ==U_RIGHT_TO_LEFT_ARABIC )
+                return UBIDI_RTL;
+    }
+    return UBIDI_NEUTRAL;
+}
+
+/* perform (P2)..(P3) ------------------------------------------------------- */
+
+/*
+ * Get the directional properties for the text,
+ * calculate the flags bit-set, and
+ * determine the paragraph level if necessary.
+ */
+static void
+getDirProps(UBiDi *pBiDi) {
+    const UChar *text=pBiDi->text;
+    DirProp *dirProps=pBiDi->dirPropsMemory;    /* pBiDi->dirProps is const */
+
+    int32_t i=0, i1, length=pBiDi->originalLength;
+    Flags flags=0;      /* collect all directionalities in the text */
+    UChar32 uchar;
+    DirProp dirProp=0, paraDirDefault=0;/* initialize to avoid compiler warnings */
+    UBool isDefaultLevel=IS_DEFAULT_LEVEL(pBiDi->paraLevel);
+    /* for inverse BiDi, the default para level is set to RTL if there is a
+       strong R or AL character at either end of the text                           */
+    UBool isDefaultLevelInverse=isDefaultLevel && (UBool)
+            (pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_LIKE_DIRECT ||
+             pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL);
+    int32_t lastArabicPos=-1;
+    int32_t controlCount=0;
+    UBool removeBiDiControls = (UBool)(pBiDi->reorderingOptions &
+                                       UBIDI_OPTION_REMOVE_CONTROLS);
+
+    typedef enum {
+         NOT_CONTEXTUAL,                /* 0: not contextual paraLevel */
+         LOOKING_FOR_STRONG,            /* 1: looking for first strong char */
+         FOUND_STRONG_CHAR              /* 2: found first strong char       */
+    } State;
+    State state;
+    int32_t paraStart=0;                /* index of first char in paragraph */
+    DirProp paraDir;                    /* == CONTEXT_RTL within paragraphs
+                                           starting with strong R char      */
+    DirProp lastStrongDir=0;            /* for default level & inverse BiDi */
+    int32_t lastStrongLTR=0;            /* for STREAMING option             */
+
+    if(pBiDi->reorderingOptions & UBIDI_OPTION_STREAMING) {
+        pBiDi->length=0;
+        lastStrongLTR=0;
+    }
+    if(isDefaultLevel) {
+        paraDirDefault=pBiDi->paraLevel&1 ? CONTEXT_RTL : 0;
+        paraDir=paraDirDefault;
+        lastStrongDir=paraDirDefault;
+        state=LOOKING_FOR_STRONG;
+    } else {
+        state=NOT_CONTEXTUAL;
+        paraDir=0;
+    }
+    /* count paragraphs and determine the paragraph level (P2..P3) */
+    /*
+     * see comment in ubidi.h:
+     * the DEFAULT_XXX values are designed so that
+     * their bit 0 alone yields the intended default
+     */
+    for( /* i=0 above */ ; i<length; ) {
+        /* i is incremented by U16_NEXT */
+        U16_NEXT(text, i, length, uchar);
+        flags|=DIRPROP_FLAG(dirProp=(DirProp)ubidi_getCustomizedClass(pBiDi, uchar));
+        dirProps[i-1]=dirProp|paraDir;
+        if(uchar>0xffff) {  /* set the lead surrogate's property to BN */
+            flags|=DIRPROP_FLAG(BN);
+            dirProps[i-2]=(DirProp)(BN|paraDir);
+        }
+        if(state==LOOKING_FOR_STRONG) {
+            if(dirProp==L) {
+                state=FOUND_STRONG_CHAR;
+                if(paraDir) {
+                    paraDir=0;
+                    for(i1=paraStart; i1<i; i1++) {
+                        dirProps[i1]&=~CONTEXT_RTL;
+                    }
+                }
+                continue;
+            }
+            if(dirProp==R || dirProp==AL) {
+                state=FOUND_STRONG_CHAR;
+                if(paraDir==0) {
+                    paraDir=CONTEXT_RTL;
+                    for(i1=paraStart; i1<i; i1++) {
+                        dirProps[i1]|=CONTEXT_RTL;
+                    }
+                }
+                continue;
+            }
+        }
+        if(dirProp==L) {
+            lastStrongDir=0;
+            lastStrongLTR=i;            /* i is index to next character */
+        }
+        else if(dirProp==R) {
+            lastStrongDir=CONTEXT_RTL;
+        }
+        else if(dirProp==AL) {
+            lastStrongDir=CONTEXT_RTL;
+            lastArabicPos=i-1;
+        }
+        else if(dirProp==B) {
+            if(pBiDi->reorderingOptions & UBIDI_OPTION_STREAMING) {
+                pBiDi->length=i;        /* i is index to next character */
+            }
+            if(isDefaultLevelInverse && (lastStrongDir==CONTEXT_RTL) &&(paraDir!=lastStrongDir)) {
+                for( ; paraStart<i; paraStart++) {
+                    dirProps[paraStart]|=CONTEXT_RTL;
+                }
+            }
+            if(i<length) {              /* B not last char in text */
+                if(!((uchar==CR) && (text[i]==LF))) {
+                    pBiDi->paraCount++;
+                }
+                if(isDefaultLevel) {
+                    state=LOOKING_FOR_STRONG;
+                    paraStart=i;        /* i is index to next character */
+                    paraDir=paraDirDefault;
+                    lastStrongDir=paraDirDefault;
+                }
+            }
+        }
+        if(removeBiDiControls && IS_BIDI_CONTROL_CHAR(uchar)) {
+            controlCount++;
+        }
+    }
+    if(isDefaultLevelInverse && (lastStrongDir==CONTEXT_RTL) &&(paraDir!=lastStrongDir)) {
+        for(i1=paraStart; i1<length; i1++) {
+            dirProps[i1]|=CONTEXT_RTL;
+        }
+    }
+    if(isDefaultLevel) {
+        pBiDi->paraLevel=GET_PARALEVEL(pBiDi, 0);
+    }
+    if(pBiDi->reorderingOptions & UBIDI_OPTION_STREAMING) {
+        if((lastStrongLTR>pBiDi->length) &&
+           (GET_PARALEVEL(pBiDi, lastStrongLTR)==0)) {
+            pBiDi->length = lastStrongLTR;
+        }
+        if(pBiDi->length<pBiDi->originalLength) {
+            pBiDi->paraCount--;
+        }
+    }
+    /* The following line does nothing new for contextual paraLevel, but is
+       needed for absolute paraLevel.                               */
+    flags|=DIRPROP_FLAG_LR(pBiDi->paraLevel);
+
+    if(pBiDi->orderParagraphsLTR && (flags&DIRPROP_FLAG(B))) {
+        flags|=DIRPROP_FLAG(L);
+    }
+
+    pBiDi->controlCount = controlCount;
+    pBiDi->flags=flags;
+    pBiDi->lastArabicPos=lastArabicPos;
+}
+
+/* perform (X1)..(X9) ------------------------------------------------------- */
+
+/* determine if the text is mixed-directional or single-directional */
+static UBiDiDirection
+directionFromFlags(UBiDi *pBiDi) {
+    Flags flags=pBiDi->flags;
+    /* if the text contains AN and neutrals, then some neutrals may become RTL */
+    if(!(flags&MASK_RTL || ((flags&DIRPROP_FLAG(AN)) && (flags&MASK_POSSIBLE_N)))) {
+        return UBIDI_LTR;
+    } else if(!(flags&MASK_LTR)) {
+        return UBIDI_RTL;
+    } else {
+        return UBIDI_MIXED;
+    }
+}
+
+/*
+ * Resolve the explicit levels as specified by explicit embedding codes.
+ * Recalculate the flags to have them reflect the real properties
+ * after taking the explicit embeddings into account.
+ *
+ * The BiDi algorithm is designed to result in the same behavior whether embedding
+ * levels are externally specified (from "styled text", supposedly the preferred
+ * method) or set by explicit embedding codes (LRx, RLx, PDF) in the plain text.
+ * That is why (X9) instructs to remove all explicit codes (and BN).
+ * However, in a real implementation, this removal of these codes and their index
+ * positions in the plain text is undesirable since it would result in
+ * reallocated, reindexed text.
+ * Instead, this implementation leaves the codes in there and just ignores them
+ * in the subsequent processing.
+ * In order to get the same reordering behavior, positions with a BN or an
+ * explicit embedding code just get the same level assigned as the last "real"
+ * character.
+ *
+ * Some implementations, not this one, then overwrite some of these
+ * directionality properties at "real" same-level-run boundaries by
+ * L or R codes so that the resolution of weak types can be performed on the
+ * entire paragraph at once instead of having to parse it once more and
+ * perform that resolution on same-level-runs.
+ * This limits the scope of the implicit rules in effectively
+ * the same way as the run limits.
+ *
+ * Instead, this implementation does not modify these codes.
+ * On one hand, the paragraph has to be scanned for same-level-runs, but
+ * on the other hand, this saves another loop to reset these codes,
+ * or saves making and modifying a copy of dirProps[].
+ *
+ *
+ * Note that (Pn) and (Xn) changed significantly from version 4 of the BiDi algorithm.
+ *
+ *
+ * Handling the stack of explicit levels (Xn):
+ *
+ * With the BiDi stack of explicit levels,
+ * as pushed with each LRE, RLE, LRO, and RLO and popped with each PDF,
+ * the explicit level must never exceed UBIDI_MAX_EXPLICIT_LEVEL==61.
+ *
+ * In order to have a correct push-pop semantics even in the case of overflows,
+ * there are two overflow counters:
+ * - countOver60 is incremented with each LRx at level 60
+ * - from level 60, one RLx increases the level to 61
+ * - countOver61 is incremented with each LRx and RLx at level 61
+ *
+ * Popping levels with PDF must work in the opposite order so that level 61
+ * is correct at the correct point. Underflows (too many PDFs) must be checked.
+ *
+ * This implementation assumes that UBIDI_MAX_EXPLICIT_LEVEL is odd.
+ */
+static UBiDiDirection
+resolveExplicitLevels(UBiDi *pBiDi) {
+    const DirProp *dirProps=pBiDi->dirProps;
+    UBiDiLevel *levels=pBiDi->levels;
+    const UChar *text=pBiDi->text;
+
+    int32_t i=0, length=pBiDi->length;
+    Flags flags=pBiDi->flags;       /* collect all directionalities in the text */
+    DirProp dirProp;
+    UBiDiLevel level=GET_PARALEVEL(pBiDi, 0);
+
+    UBiDiDirection direction;
+    int32_t paraIndex=0;
+
+    /* determine if the text is mixed-directional or single-directional */
+    direction=directionFromFlags(pBiDi);
+
+    /* we may not need to resolve any explicit levels, but for multiple
+       paragraphs we want to loop on all chars to set the para boundaries */
+    if((direction!=UBIDI_MIXED) && (pBiDi->paraCount==1)) {
+        /* not mixed directionality: levels don't matter - trailingWSStart will be 0 */
+    } else if((pBiDi->paraCount==1) &&
+              (!(flags&MASK_EXPLICIT) ||
+               (pBiDi->reorderingMode > UBIDI_REORDER_LAST_LOGICAL_TO_VISUAL))) {
+        /* mixed, but all characters are at the same embedding level */
+        /* or we are in "inverse BiDi" */
+        /* and we don't have contextual multiple paragraphs with some B char */
+        /* set all levels to the paragraph level */
+        for(i=0; i<length; ++i) {
+            levels[i]=level;
+        }
+    } else {
+        /* continue to perform (Xn) */
+
+        /* (X1) level is set for all codes, embeddingLevel keeps track of the push/pop operations */
+        /* both variables may carry the UBIDI_LEVEL_OVERRIDE flag to indicate the override status */
+        UBiDiLevel embeddingLevel=level, newLevel, stackTop=0;
+
+        UBiDiLevel stack[UBIDI_MAX_EXPLICIT_LEVEL];        /* we never push anything >=UBIDI_MAX_EXPLICIT_LEVEL */
+        uint32_t countOver60=0, countOver61=0;  /* count overflows of explicit levels */
+
+        /* recalculate the flags */
+        flags=0;
+
+        for(i=0; i<length; ++i) {
+            dirProp=NO_CONTEXT_RTL(dirProps[i]);
+            switch(dirProp) {
+            case LRE:
+            case LRO:
+                /* (X3, X5) */
+                newLevel=(UBiDiLevel)((embeddingLevel+2)&~(UBIDI_LEVEL_OVERRIDE|1)); /* least greater even level */
+                if(newLevel<=UBIDI_MAX_EXPLICIT_LEVEL) {
+                    stack[stackTop]=embeddingLevel;
+                    ++stackTop;
+                    embeddingLevel=newLevel;
+                    if(dirProp==LRO) {
+                        embeddingLevel|=UBIDI_LEVEL_OVERRIDE;
+                    }
+                    /* we don't need to set UBIDI_LEVEL_OVERRIDE off for LRE
+                       since this has already been done for newLevel which is
+                       the source for embeddingLevel.
+                     */
+                } else if((embeddingLevel&~UBIDI_LEVEL_OVERRIDE)==UBIDI_MAX_EXPLICIT_LEVEL) {
+                    ++countOver61;
+                } else /* (embeddingLevel&~UBIDI_LEVEL_OVERRIDE)==UBIDI_MAX_EXPLICIT_LEVEL-1 */ {
+                    ++countOver60;
+                }
+                flags|=DIRPROP_FLAG(BN);
+                break;
+            case RLE:
+            case RLO:
+                /* (X2, X4) */
+                newLevel=(UBiDiLevel)(((embeddingLevel&~UBIDI_LEVEL_OVERRIDE)+1)|1); /* least greater odd level */
+                if(newLevel<=UBIDI_MAX_EXPLICIT_LEVEL) {
+                    stack[stackTop]=embeddingLevel;
+                    ++stackTop;
+                    embeddingLevel=newLevel;
+                    if(dirProp==RLO) {
+                        embeddingLevel|=UBIDI_LEVEL_OVERRIDE;
+                    }
+                    /* we don't need to set UBIDI_LEVEL_OVERRIDE off for RLE
+                       since this has already been done for newLevel which is
+                       the source for embeddingLevel.
+                     */
+                } else {
+                    ++countOver61;
+                }
+                flags|=DIRPROP_FLAG(BN);
+                break;
+            case PDF:
+                /* (X7) */
+                /* handle all the overflow cases first */
+                if(countOver61>0) {
+                    --countOver61;
+                } else if(countOver60>0 && (embeddingLevel&~UBIDI_LEVEL_OVERRIDE)!=UBIDI_MAX_EXPLICIT_LEVEL) {
+                    /* handle LRx overflows from level 60 */
+                    --countOver60;
+                } else if(stackTop>0) {
+                    /* this is the pop operation; it also pops level 61 while countOver60>0 */
+                    --stackTop;
+                    embeddingLevel=stack[stackTop];
+                /* } else { (underflow) */
+                }
+                flags|=DIRPROP_FLAG(BN);
+                break;
+            case B:
+                stackTop=0;
+                countOver60=countOver61=0;
+                level=GET_PARALEVEL(pBiDi, i);
+                if((i+1)<length) {
+                    embeddingLevel=GET_PARALEVEL(pBiDi, i+1);
+                    if(!((text[i]==CR) && (text[i+1]==LF))) {
+                        pBiDi->paras[paraIndex++]=i+1;
+                    }
+                }
+                flags|=DIRPROP_FLAG(B);
+                break;
+            case BN:
+                /* BN, LRE, RLE, and PDF are supposed to be removed (X9) */
+                /* they will get their levels set correctly in adjustWSLevels() */
+                flags|=DIRPROP_FLAG(BN);
+                break;
+            default:
+                /* all other types get the "real" level */
+                if(level!=embeddingLevel) {
+                    level=embeddingLevel;
+                    if(level&UBIDI_LEVEL_OVERRIDE) {
+                        flags|=DIRPROP_FLAG_O(level)|DIRPROP_FLAG_MULTI_RUNS;
+                    } else {
+                        flags|=DIRPROP_FLAG_E(level)|DIRPROP_FLAG_MULTI_RUNS;
+                    }
+                }
+                if(!(level&UBIDI_LEVEL_OVERRIDE)) {
+                    flags|=DIRPROP_FLAG(dirProp);
+                }
+                break;
+            }
+
+            /*
+             * We need to set reasonable levels even on BN codes and
+             * explicit codes because we will later look at same-level runs (X10).
+             */
+            levels[i]=level;
+        }
+        if(flags&MASK_EMBEDDING) {
+            flags|=DIRPROP_FLAG_LR(pBiDi->paraLevel);
+        }
+        if(pBiDi->orderParagraphsLTR && (flags&DIRPROP_FLAG(B))) {
+            flags|=DIRPROP_FLAG(L);
+        }
+
+        /* subsequently, ignore the explicit codes and BN (X9) */
+
+        /* again, determine if the text is mixed-directional or single-directional */
+        pBiDi->flags=flags;
+        direction=directionFromFlags(pBiDi);
+    }
+
+    return direction;
+}
+
+/*
+ * Use a pre-specified embedding levels array:
+ *
+ * Adjust the directional properties for overrides (->LEVEL_OVERRIDE),
+ * ignore all explicit codes (X9),
+ * and check all the preset levels.
+ *
+ * Recalculate the flags to have them reflect the real properties
+ * after taking the explicit embeddings into account.
+ */
+static UBiDiDirection
+checkExplicitLevels(UBiDi *pBiDi, UErrorCode *pErrorCode) {
+    const DirProp *dirProps=pBiDi->dirProps;
+    DirProp dirProp;
+    UBiDiLevel *levels=pBiDi->levels;
+    const UChar *text=pBiDi->text;
+
+    int32_t i, length=pBiDi->length;
+    Flags flags=0;  /* collect all directionalities in the text */
+    UBiDiLevel level;
+    uint32_t paraIndex=0;
+
+    for(i=0; i<length; ++i) {
+        level=levels[i];
+        dirProp=NO_CONTEXT_RTL(dirProps[i]);
+        if(level&UBIDI_LEVEL_OVERRIDE) {
+            /* keep the override flag in levels[i] but adjust the flags */
+            level&=~UBIDI_LEVEL_OVERRIDE;     /* make the range check below simpler */
+            flags|=DIRPROP_FLAG_O(level);
+        } else {
+            /* set the flags */
+            flags|=DIRPROP_FLAG_E(level)|DIRPROP_FLAG(dirProp);
+        }
+        if((level<GET_PARALEVEL(pBiDi, i) &&
+            !((0==level)&&(dirProp==B))) ||
+           (UBIDI_MAX_EXPLICIT_LEVEL<level)) {
+            /* level out of bounds */
+            *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+            return UBIDI_LTR;
+        }
+        if((dirProp==B) && ((i+1)<length)) {
+            if(!((text[i]==CR) && (text[i+1]==LF))) {
+                pBiDi->paras[paraIndex++]=i+1;
+            }
+        }
+    }
+    if(flags&MASK_EMBEDDING) {
+        flags|=DIRPROP_FLAG_LR(pBiDi->paraLevel);
+    }
+
+    /* determine if the text is mixed-directional or single-directional */
+    pBiDi->flags=flags;
+    return directionFromFlags(pBiDi);
+}
+
+/******************************************************************
+ The Properties state machine table
+*******************************************************************
+
+ All table cells are 8 bits:
+      bits 0..4:  next state
+      bits 5..7:  action to perform (if > 0)
+
+ Cells may be of format "n" where n represents the next state
+ (except for the rightmost column).
+ Cells may also be of format "s(x,y)" where x represents an action
+ to perform and y represents the next state.
+
+*******************************************************************
+ Definitions and type for properties state table
+*******************************************************************
+*/
+#define IMPTABPROPS_COLUMNS 14
+#define IMPTABPROPS_RES (IMPTABPROPS_COLUMNS - 1)
+#define GET_STATEPROPS(cell) ((cell)&0x1f)
+#define GET_ACTIONPROPS(cell) ((cell)>>5)
+#define s(action, newState) ((uint8_t)(newState+(action<<5)))
+
+static const uint8_t groupProp[] =          /* dirProp regrouped */
+{
+/*  L   R   EN  ES  ET  AN  CS  B   S   WS  ON  LRE LRO AL  RLE RLO PDF NSM BN  */
+    0,  1,  2,  7,  8,  3,  9,  6,  5,  4,  4,  10, 10, 12, 10, 10, 10, 11, 10
+};
+enum { DirProp_L=0, DirProp_R=1, DirProp_EN=2, DirProp_AN=3, DirProp_ON=4, DirProp_S=5, DirProp_B=6 }; /* reduced dirProp */
+
+/******************************************************************
+
+      PROPERTIES  STATE  TABLE
+
+ In table impTabProps,
+      - the ON column regroups ON and WS
+      - the BN column regroups BN, LRE, RLE, LRO, RLO, PDF
+      - the Res column is the reduced property assigned to a run
+
+ Action 1: process current run1, init new run1
+        2: init new run2
+        3: process run1, process run2, init new run1
+        4: process run1, set run1=run2, init new run2
+
+ Notes:
+  1) This table is used in resolveImplicitLevels().
+  2) This table triggers actions when there is a change in the Bidi
+     property of incoming characters (action 1).
+  3) Most such property sequences are processed immediately (in
+     fact, passed to processPropertySeq().
+  4) However, numbers are assembled as one sequence. This means
+     that undefined situations (like CS following digits, until
+     it is known if the next char will be a digit) are held until
+     following chars define them.
+     Example: digits followed by CS, then comes another CS or ON;
+              the digits will be processed, then the CS assigned
+              as the start of an ON sequence (action 3).
+  5) There are cases where more than one sequence must be
+     processed, for instance digits followed by CS followed by L:
+     the digits must be processed as one sequence, and the CS
+     must be processed as an ON sequence, all this before starting
+     assembling chars for the opening L sequence.
+
+
+*/
+static const uint8_t impTabProps[][IMPTABPROPS_COLUMNS] =
+{
+/*                        L ,     R ,    EN ,    AN ,    ON ,     S ,     B ,    ES ,    ET ,    CS ,    BN ,   NSM ,    AL ,  Res */
+/* 0 Init        */ {     1 ,     2 ,     4 ,     5 ,     7 ,    15 ,    17 ,     7 ,     9 ,     7 ,     0 ,     7 ,     3 ,  DirProp_ON },
+/* 1 L           */ {     1 , s(1,2), s(1,4), s(1,5), s(1,7),s(1,15),s(1,17), s(1,7), s(1,9), s(1,7),     1 ,     1 , s(1,3),   DirProp_L },
+/* 2 R           */ { s(1,1),     2 , s(1,4), s(1,5), s(1,7),s(1,15),s(1,17), s(1,7), s(1,9), s(1,7),     2 ,     2 , s(1,3),   DirProp_R },
+/* 3 AL          */ { s(1,1), s(1,2), s(1,6), s(1,6), s(1,8),s(1,16),s(1,17), s(1,8), s(1,8), s(1,8),     3 ,     3 ,     3 ,   DirProp_R },
+/* 4 EN          */ { s(1,1), s(1,2),     4 , s(1,5), s(1,7),s(1,15),s(1,17),s(2,10),    11 ,s(2,10),     4 ,     4 , s(1,3),  DirProp_EN },
+/* 5 AN          */ { s(1,1), s(1,2), s(1,4),     5 , s(1,7),s(1,15),s(1,17), s(1,7), s(1,9),s(2,12),     5 ,     5 , s(1,3),  DirProp_AN },
+/* 6 AL:EN/AN    */ { s(1,1), s(1,2),     6 ,     6 , s(1,8),s(1,16),s(1,17), s(1,8), s(1,8),s(2,13),     6 ,     6 , s(1,3),  DirProp_AN },
+/* 7 ON          */ { s(1,1), s(1,2), s(1,4), s(1,5),     7 ,s(1,15),s(1,17),     7 ,s(2,14),     7 ,     7 ,     7 , s(1,3),  DirProp_ON },
+/* 8 AL:ON       */ { s(1,1), s(1,2), s(1,6), s(1,6),     8 ,s(1,16),s(1,17),     8 ,     8 ,     8 ,     8 ,     8 , s(1,3),  DirProp_ON },
+/* 9 ET          */ { s(1,1), s(1,2),     4 , s(1,5),     7 ,s(1,15),s(1,17),     7 ,     9 ,     7 ,     9 ,     9 , s(1,3),  DirProp_ON },
+/*10 EN+ES/CS    */ { s(3,1), s(3,2),     4 , s(3,5), s(4,7),s(3,15),s(3,17), s(4,7),s(4,14), s(4,7),    10 , s(4,7), s(3,3),  DirProp_EN },
+/*11 EN+ET       */ { s(1,1), s(1,2),     4 , s(1,5), s(1,7),s(1,15),s(1,17), s(1,7),    11 , s(1,7),    11 ,    11 , s(1,3),  DirProp_EN },
+/*12 AN+CS       */ { s(3,1), s(3,2), s(3,4),     5 , s(4,7),s(3,15),s(3,17), s(4,7),s(4,14), s(4,7),    12 , s(4,7), s(3,3),  DirProp_AN },
+/*13 AL:EN/AN+CS */ { s(3,1), s(3,2),     6 ,     6 , s(4,8),s(3,16),s(3,17), s(4,8), s(4,8), s(4,8),    13 , s(4,8), s(3,3),  DirProp_AN },
+/*14 ON+ET       */ { s(1,1), s(1,2), s(4,4), s(1,5),     7 ,s(1,15),s(1,17),     7 ,    14 ,     7 ,    14 ,    14 , s(1,3),  DirProp_ON },
+/*15 S           */ { s(1,1), s(1,2), s(1,4), s(1,5), s(1,7),    15 ,s(1,17), s(1,7), s(1,9), s(1,7),    15 , s(1,7), s(1,3),   DirProp_S },
+/*16 AL:S        */ { s(1,1), s(1,2), s(1,6), s(1,6), s(1,8),    16 ,s(1,17), s(1,8), s(1,8), s(1,8),    16 , s(1,8), s(1,3),   DirProp_S },
+/*17 B           */ { s(1,1), s(1,2), s(1,4), s(1,5), s(1,7),s(1,15),    17 , s(1,7), s(1,9), s(1,7),    17 , s(1,7), s(1,3),   DirProp_B }
+};
+
+/*  we must undef macro s because the levels table have a different
+ *  structure (4 bits for action and 4 bits for next state.
+ */
+#undef s
+
+/******************************************************************
+ The levels state machine tables
+*******************************************************************
+
+ All table cells are 8 bits:
+      bits 0..3:  next state
+      bits 4..7:  action to perform (if > 0)
+
+ Cells may be of format "n" where n represents the next state
+ (except for the rightmost column).
+ Cells may also be of format "s(x,y)" where x represents an action
+ to perform and y represents the next state.
+
+ This format limits each table to 16 states each and to 15 actions.
+
+*******************************************************************
+ Definitions and type for levels state tables
+*******************************************************************
+*/
+#define IMPTABLEVELS_COLUMNS (DirProp_B + 2)
+#define IMPTABLEVELS_RES (IMPTABLEVELS_COLUMNS - 1)
+#define GET_STATE(cell) ((cell)&0x0f)
+#define GET_ACTION(cell) ((cell)>>4)
+#define s(action, newState) ((uint8_t)(newState+(action<<4)))
+
+typedef uint8_t ImpTab[][IMPTABLEVELS_COLUMNS];
+typedef uint8_t ImpAct[];
+
+/* FOOD FOR THOUGHT: each ImpTab should have its associated ImpAct,
+ * instead of having a pair of ImpTab and a pair of ImpAct.
+ */
+typedef struct ImpTabPair {
+    const void * pImpTab[2];
+    const void * pImpAct[2];
+} ImpTabPair;
+
+/******************************************************************
+
+      LEVELS  STATE  TABLES
+
+ In all levels state tables,
+      - state 0 is the initial state
+      - the Res column is the increment to add to the text level
+        for this property sequence.
+
+ The impAct arrays for each table of a pair map the local action
+ numbers of the table to the total list of actions. For instance,
+ action 2 in a given table corresponds to the action number which
+ appears in entry [2] of the impAct array for that table.
+ The first entry of all impAct arrays must be 0.
+
+ Action 1: init conditional sequence
+        2: prepend conditional sequence to current sequence
+        3: set ON sequence to new level - 1
+        4: init EN/AN/ON sequence
+        5: fix EN/AN/ON sequence followed by R
+        6: set previous level sequence to level 2
+
+ Notes:
+  1) These tables are used in processPropertySeq(). The input
+     is property sequences as determined by resolveImplicitLevels.
+  2) Most such property sequences are processed immediately
+     (levels are assigned).
+  3) However, some sequences cannot be assigned a final level till
+     one or more following sequences are received. For instance,
+     ON following an R sequence within an even-level paragraph.
+     If the following sequence is R, the ON sequence will be
+     assigned basic run level+1, and so will the R sequence.
+  4) S is generally handled like ON, since its level will be fixed
+     to paragraph level in adjustWSLevels().
+
+*/
+
+static const ImpTab impTabL_DEFAULT =   /* Even paragraph level */
+/*  In this table, conditional sequences receive the higher possible level
+    until proven otherwise.
+*/
+{
+/*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
+/* 0 : init       */ {     0 ,     1 ,     0 ,     2 ,     0 ,     0 ,     0 ,  0 },
+/* 1 : R          */ {     0 ,     1 ,     3 ,     3 , s(1,4), s(1,4),     0 ,  1 },
+/* 2 : AN         */ {     0 ,     1 ,     0 ,     2 , s(1,5), s(1,5),     0 ,  2 },
+/* 3 : R+EN/AN    */ {     0 ,     1 ,     3 ,     3 , s(1,4), s(1,4),     0 ,  2 },
+/* 4 : R+ON       */ { s(2,0),     1 ,     3 ,     3 ,     4 ,     4 , s(2,0),  1 },
+/* 5 : AN+ON      */ { s(2,0),     1 , s(2,0),     2 ,     5 ,     5 , s(2,0),  1 }
+};
+static const ImpTab impTabR_DEFAULT =   /* Odd  paragraph level */
+/*  In this table, conditional sequences receive the lower possible level
+    until proven otherwise.
+*/
+{
+/*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
+/* 0 : init       */ {     1 ,     0 ,     2 ,     2 ,     0 ,     0 ,     0 ,  0 },
+/* 1 : L          */ {     1 ,     0 ,     1 ,     3 , s(1,4), s(1,4),     0 ,  1 },
+/* 2 : EN/AN      */ {     1 ,     0 ,     2 ,     2 ,     0 ,     0 ,     0 ,  1 },
+/* 3 : L+AN       */ {     1 ,     0 ,     1 ,     3 ,     5 ,     5 ,     0 ,  1 },
+/* 4 : L+ON       */ { s(2,1),     0 , s(2,1),     3 ,     4 ,     4 ,     0 ,  0 },
+/* 5 : L+AN+ON    */ {     1 ,     0 ,     1 ,     3 ,     5 ,     5 ,     0 ,  0 }
+};
+static const ImpAct impAct0 = {0,1,2,3,4,5,6};
+static const ImpTabPair impTab_DEFAULT = {{&impTabL_DEFAULT,
+                                           &impTabR_DEFAULT},
+                                          {&impAct0, &impAct0}};
+
+static const ImpTab impTabL_NUMBERS_SPECIAL =   /* Even paragraph level */
+/*  In this table, conditional sequences receive the higher possible level
+    until proven otherwise.
+*/
+{
+/*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
+/* 0 : init       */ {     0 ,     2 ,    1 ,      1 ,     0 ,     0 ,     0 ,  0 },
+/* 1 : L+EN/AN    */ {     0 ,     2 ,    1 ,      1 ,     0 ,     0 ,     0 ,  2 },
+/* 2 : R          */ {     0 ,     2 ,    4 ,      4 , s(1,3),     0 ,     0 ,  1 },
+/* 3 : R+ON       */ { s(2,0),     2 ,    4 ,      4 ,     3 ,     3 , s(2,0),  1 },
+/* 4 : R+EN/AN    */ {     0 ,     2 ,    4 ,      4 , s(1,3), s(1,3),     0 ,  2 }
+  };
+static const ImpTabPair impTab_NUMBERS_SPECIAL = {{&impTabL_NUMBERS_SPECIAL,
+                                                   &impTabR_DEFAULT},
+                                                  {&impAct0, &impAct0}};
+
+static const ImpTab impTabL_GROUP_NUMBERS_WITH_R =
+/*  In this table, EN/AN+ON sequences receive levels as if associated with R
+    until proven that there is L or sor/eor on both sides. AN is handled like EN.
+*/
+{
+/*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
+/* 0 init         */ {     0 ,     3 , s(1,1), s(1,1),     0 ,     0 ,     0 ,  0 },
+/* 1 EN/AN        */ { s(2,0),     3 ,     1 ,     1 ,     2 , s(2,0), s(2,0),  2 },
+/* 2 EN/AN+ON     */ { s(2,0),     3 ,     1 ,     1 ,     2 , s(2,0), s(2,0),  1 },
+/* 3 R            */ {     0 ,     3 ,     5 ,     5 , s(1,4),     0 ,     0 ,  1 },
+/* 4 R+ON         */ { s(2,0),     3 ,     5 ,     5 ,     4 , s(2,0), s(2,0),  1 },
+/* 5 R+EN/AN      */ {     0 ,     3 ,     5 ,     5 , s(1,4),     0 ,     0 ,  2 }
+};
+static const ImpTab impTabR_GROUP_NUMBERS_WITH_R =
+/*  In this table, EN/AN+ON sequences receive levels as if associated with R
+    until proven that there is L on both sides. AN is handled like EN.
+*/
+{
+/*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
+/* 0 init         */ {     2 ,     0 ,     1 ,     1 ,     0 ,     0 ,     0 ,  0 },
+/* 1 EN/AN        */ {     2 ,     0 ,     1 ,     1 ,     0 ,     0 ,     0 ,  1 },
+/* 2 L            */ {     2 ,     0 , s(1,4), s(1,4), s(1,3),     0 ,     0 ,  1 },
+/* 3 L+ON         */ { s(2,2),     0 ,     4 ,     4 ,     3 ,     0 ,     0 ,  0 },
+/* 4 L+EN/AN      */ { s(2,2),     0 ,     4 ,     4 ,     3 ,     0 ,     0 ,  1 }
+};
+static const ImpTabPair impTab_GROUP_NUMBERS_WITH_R = {
+                        {&impTabL_GROUP_NUMBERS_WITH_R,
+                         &impTabR_GROUP_NUMBERS_WITH_R},
+                        {&impAct0, &impAct0}};
+
+
+static const ImpTab impTabL_INVERSE_NUMBERS_AS_L =
+/*  This table is identical to the Default LTR table except that EN and AN are
+    handled like L.
+*/
+{
+/*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
+/* 0 : init       */ {     0 ,     1 ,     0 ,     0 ,     0 ,     0 ,     0 ,  0 },
+/* 1 : R          */ {     0 ,     1 ,     0 ,     0 , s(1,4), s(1,4),     0 ,  1 },
+/* 2 : AN         */ {     0 ,     1 ,     0 ,     0 , s(1,5), s(1,5),     0 ,  2 },
+/* 3 : R+EN/AN    */ {     0 ,     1 ,     0 ,     0 , s(1,4), s(1,4),     0 ,  2 },
+/* 4 : R+ON       */ { s(2,0),     1 , s(2,0), s(2,0),     4 ,     4 , s(2,0),  1 },
+/* 5 : AN+ON      */ { s(2,0),     1 , s(2,0), s(2,0),     5 ,     5 , s(2,0),  1 }
+};
+static const ImpTab impTabR_INVERSE_NUMBERS_AS_L =
+/*  This table is identical to the Default RTL table except that EN and AN are
+    handled like L.
+*/
+{
+/*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
+/* 0 : init       */ {     1 ,     0 ,     1 ,     1 ,     0 ,     0 ,     0 ,  0 },
+/* 1 : L          */ {     1 ,     0 ,     1 ,     1 , s(1,4), s(1,4),     0 ,  1 },
+/* 2 : EN/AN      */ {     1 ,     0 ,     1 ,     1 ,     0 ,     0 ,     0 ,  1 },
+/* 3 : L+AN       */ {     1 ,     0 ,     1 ,     1 ,     5 ,     5 ,     0 ,  1 },
+/* 4 : L+ON       */ { s(2,1),     0 , s(2,1), s(2,1),     4 ,     4 ,     0 ,  0 },
+/* 5 : L+AN+ON    */ {     1 ,     0 ,     1 ,     1 ,     5 ,     5 ,     0 ,  0 }
+};
+static const ImpTabPair impTab_INVERSE_NUMBERS_AS_L = {
+                        {&impTabL_INVERSE_NUMBERS_AS_L,
+                         &impTabR_INVERSE_NUMBERS_AS_L},
+                        {&impAct0, &impAct0}};
+
+static const ImpTab impTabR_INVERSE_LIKE_DIRECT =   /* Odd  paragraph level */
+/*  In this table, conditional sequences receive the lower possible level
+    until proven otherwise.
+*/
+{
+/*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
+/* 0 : init       */ {     1 ,     0 ,     2 ,     2 ,     0 ,     0 ,     0 ,  0 },
+/* 1 : L          */ {     1 ,     0 ,     1 ,     2 , s(1,3), s(1,3),     0 ,  1 },
+/* 2 : EN/AN      */ {     1 ,     0 ,     2 ,     2 ,     0 ,     0 ,     0 ,  1 },
+/* 3 : L+ON       */ { s(2,1), s(3,0),     6 ,     4 ,     3 ,     3 , s(3,0),  0 },
+/* 4 : L+ON+AN    */ { s(2,1), s(3,0),     6 ,     4 ,     5 ,     5 , s(3,0),  3 },
+/* 5 : L+AN+ON    */ { s(2,1), s(3,0),     6 ,     4 ,     5 ,     5 , s(3,0),  2 },
+/* 6 : L+ON+EN    */ { s(2,1), s(3,0),     6 ,     4 ,     3 ,     3 , s(3,0),  1 }
+};
+static const ImpAct impAct1 = {0,1,11,12};
+/* FOOD FOR THOUGHT: in LTR table below, check case "JKL 123abc"
+ */
+static const ImpTabPair impTab_INVERSE_LIKE_DIRECT = {
+                        {&impTabL_DEFAULT,
+                         &impTabR_INVERSE_LIKE_DIRECT},
+                        {&impAct0, &impAct1}};
+
+static const ImpTab impTabL_INVERSE_LIKE_DIRECT_WITH_MARKS =
+/*  The case handled in this table is (visually):  R EN L
+*/
+{
+/*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
+/* 0 : init       */ {     0 , s(6,3),     0 ,     1 ,     0 ,     0 ,     0 ,  0 },
+/* 1 : L+AN       */ {     0 , s(6,3),     0 ,     1 , s(1,2), s(3,0),     0 ,  4 },
+/* 2 : L+AN+ON    */ { s(2,0), s(6,3), s(2,0),     1 ,     2 , s(3,0), s(2,0),  3 },
+/* 3 : R          */ {     0 , s(6,3), s(5,5), s(5,6), s(1,4), s(3,0),     0 ,  3 },
+/* 4 : R+ON       */ { s(3,0), s(4,3), s(5,5), s(5,6),     4 , s(3,0), s(3,0),  3 },
+/* 5 : R+EN       */ { s(3,0), s(4,3),     5 , s(5,6), s(1,4), s(3,0), s(3,0),  4 },
+/* 6 : R+AN       */ { s(3,0), s(4,3), s(5,5),     6 , s(1,4), s(3,0), s(3,0),  4 }
+};
+static const ImpTab impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS =
+/*  The cases handled in this table are (visually):  R EN L
+                                                     R L AN L
+*/
+{
+/*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
+/* 0 : init       */ { s(1,3),     0 ,     1 ,     1 ,     0 ,     0 ,     0 ,  0 },
+/* 1 : R+EN/AN    */ { s(2,3),     0 ,     1 ,     1 ,     2 , s(4,0),     0 ,  1 },
+/* 2 : R+EN/AN+ON */ { s(2,3),     0 ,     1 ,     1 ,     2 , s(4,0),     0 ,  0 },
+/* 3 : L          */ {     3 ,     0 ,     3 , s(3,6), s(1,4), s(4,0),     0 ,  1 },
+/* 4 : L+ON       */ { s(5,3), s(4,0),     5 , s(3,6),     4 , s(4,0), s(4,0),  0 },
+/* 5 : L+ON+EN    */ { s(5,3), s(4,0),     5 , s(3,6),     4 , s(4,0), s(4,0),  1 },
+/* 6 : L+AN       */ { s(5,3), s(4,0),     6 ,     6 ,     4 , s(4,0), s(4,0),  3 }
+};
+static const ImpAct impAct2 = {0,1,7,8,9,10};
+static const ImpTabPair impTab_INVERSE_LIKE_DIRECT_WITH_MARKS = {
+                        {&impTabL_INVERSE_LIKE_DIRECT_WITH_MARKS,
+                         &impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS},
+                        {&impAct0, &impAct2}};
+
+static const ImpTabPair impTab_INVERSE_FOR_NUMBERS_SPECIAL = {
+                        {&impTabL_NUMBERS_SPECIAL,
+                         &impTabR_INVERSE_LIKE_DIRECT},
+                        {&impAct0, &impAct1}};
+
+static const ImpTab impTabL_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS =
+/*  The case handled in this table is (visually):  R EN L
+*/
+{
+/*                         L ,     R ,    EN ,    AN ,    ON ,     S ,     B , Res */
+/* 0 : init       */ {     0 , s(6,2),     1 ,     1 ,     0 ,     0 ,     0 ,  0 },
+/* 1 : L+EN/AN    */ {     0 , s(6,2),     1 ,     1 ,     0 , s(3,0),     0 ,  4 },
+/* 2 : R          */ {     0 , s(6,2), s(5,4), s(5,4), s(1,3), s(3,0),     0 ,  3 },
+/* 3 : R+ON       */ { s(3,0), s(4,2), s(5,4), s(5,4),     3 , s(3,0), s(3,0),  3 },
+/* 4 : R+EN/AN    */ { s(3,0), s(4,2),     4 ,     4 , s(1,3), s(3,0), s(3,0),  4 }
+};
+static const ImpTabPair impTab_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS = {
+                        {&impTabL_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS,
+                         &impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS},
+                        {&impAct0, &impAct2}};
+
+#undef s
+
+typedef struct {
+    const ImpTab * pImpTab;             /* level table pointer          */
+    const ImpAct * pImpAct;             /* action map array             */
+    int32_t startON;                    /* start of ON sequence         */
+    int32_t startL2EN;                  /* start of level 2 sequence    */
+    int32_t lastStrongRTL;              /* index of last found R or AL  */
+    int32_t state;                      /* current state                */
+    UBiDiLevel runLevel;                /* run level before implicit solving */
+} LevState;
+
+/*------------------------------------------------------------------------*/
+
+static void
+addPoint(UBiDi *pBiDi, int32_t pos, int32_t flag)
+  /* param pos:     position where to insert
+     param flag:    one of LRM_BEFORE, LRM_AFTER, RLM_BEFORE, RLM_AFTER
+  */
+{
+#define FIRSTALLOC  10
+    Point point;
+    InsertPoints * pInsertPoints=&(pBiDi->insertPoints);
+
+    if (pInsertPoints->capacity == 0)
+    {
+        pInsertPoints->points=uprv_malloc(sizeof(Point)*FIRSTALLOC);
+        if (pInsertPoints->points == NULL)
+        {
+            pInsertPoints->errorCode=U_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+        pInsertPoints->capacity=FIRSTALLOC;
+    }
+    if (pInsertPoints->size >= pInsertPoints->capacity) /* no room for new point */
+    {
+        void * savePoints=pInsertPoints->points;
+        pInsertPoints->points=uprv_realloc(pInsertPoints->points,
+                                           pInsertPoints->capacity*2*sizeof(Point));
+        if (pInsertPoints->points == NULL)
+        {
+            pInsertPoints->points=savePoints;
+            pInsertPoints->errorCode=U_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+        else  pInsertPoints->capacity*=2;
+    }
+    point.pos=pos;
+    point.flag=flag;
+    pInsertPoints->points[pInsertPoints->size]=point;
+    pInsertPoints->size++;
+#undef FIRSTALLOC
+}
+
+/* perform rules (Wn), (Nn), and (In) on a run of the text ------------------ */
+
+/*
+ * This implementation of the (Wn) rules applies all rules in one pass.
+ * In order to do so, it needs a look-ahead of typically 1 character
+ * (except for W5: sequences of ET) and keeps track of changes
+ * in a rule Wp that affect a later Wq (p<q).
+ *
+ * The (Nn) and (In) rules are also performed in that same single loop,
+ * but effectively one iteration behind for white space.
+ *
+ * Since all implicit rules are performed in one step, it is not necessary
+ * to actually store the intermediate directional properties in dirProps[].
+ */
+
+static void
+processPropertySeq(UBiDi *pBiDi, LevState *pLevState, uint8_t _prop,
+                   int32_t start, int32_t limit) {
+    uint8_t cell, oldStateSeq, actionSeq;
+    const ImpTab * pImpTab=pLevState->pImpTab;
+    const ImpAct * pImpAct=pLevState->pImpAct;
+    UBiDiLevel * levels=pBiDi->levels;
+    UBiDiLevel level, addLevel;
+    InsertPoints * pInsertPoints;
+    int32_t start0, k;
+
+    start0=start;                           /* save original start position */
+    oldStateSeq=(uint8_t)pLevState->state;
+    cell=(*pImpTab)[oldStateSeq][_prop];
+    pLevState->state=GET_STATE(cell);       /* isolate the new state */
+    actionSeq=(*pImpAct)[GET_ACTION(cell)]; /* isolate the action */
+    addLevel=(*pImpTab)[pLevState->state][IMPTABLEVELS_RES];
+
+    if(actionSeq) {
+        switch(actionSeq) {
+        case 1:                         /* init ON seq */
+            pLevState->startON=start0;
+            break;
+
+        case 2:                         /* prepend ON seq to current seq */
+            start=pLevState->startON;
+            break;
+
+        case 3:                         /* L or S after possible relevant EN/AN */
+            /* check if we had EN after R/AL */
+            if (pLevState->startL2EN >= 0) {
+                addPoint(pBiDi, pLevState->startL2EN, LRM_BEFORE);
+            }
+            pLevState->startL2EN=-1;  /* not within previous if since could also be -2 */
+            /* check if we had any relevant EN/AN after R/AL */
+            pInsertPoints=&(pBiDi->insertPoints);
+            if ((pInsertPoints->capacity == 0) ||
+                (pInsertPoints->size <= pInsertPoints->confirmed))
+            {
+                /* nothing, just clean up */
+                pLevState->lastStrongRTL=-1;
+                /* check if we have a pending conditional segment */
+                level=(*pImpTab)[oldStateSeq][IMPTABLEVELS_RES];
+                if ((level & 1) && (pLevState->startON > 0)) {  /* after ON */
+                    start=pLevState->startON;   /* reset to basic run level */
+                }
+                if (_prop == DirProp_S)                /* add LRM before S */
+                {
+                    addPoint(pBiDi, start0, LRM_BEFORE);
+                    pInsertPoints->confirmed=pInsertPoints->size;
+                }
+                break;
+            }
+            /* reset previous RTL cont to level for LTR text */
+            for (k=pLevState->lastStrongRTL+1; k<start0; k++)
+            {
+                /* reset odd level, leave runLevel+2 as is */
+                levels[k]=(levels[k] - 2) & ~1;
+            }
+            /* mark insert points as confirmed */
+            pInsertPoints->confirmed=pInsertPoints->size;
+            pLevState->lastStrongRTL=-1;
+            if (_prop == DirProp_S)            /* add LRM before S */
+            {
+                addPoint(pBiDi, start0, LRM_BEFORE);
+                pInsertPoints->confirmed=pInsertPoints->size;
+            }
+            break;
+
+        case 4:                         /* R/AL after possible relevant EN/AN */
+            /* just clean up */
+            pInsertPoints=&(pBiDi->insertPoints);
+            if (pInsertPoints->capacity > 0)
+                /* remove all non confirmed insert points */
+                pInsertPoints->size=pInsertPoints->confirmed;
+            pLevState->startON=-1;
+            pLevState->startL2EN=-1;
+            pLevState->lastStrongRTL=limit - 1;
+            break;
+
+        case 5:                         /* EN/AN after R/AL + possible cont */
+            /* check for real AN */
+            if ((_prop == DirProp_AN) && (NO_CONTEXT_RTL(pBiDi->dirProps[start0]) == AN) &&
+                (pBiDi->reorderingMode!=UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL))
+            {
+                /* real AN */
+                if (pLevState->startL2EN == -1) /* if no relevant EN already found */
+                {
+                    /* just note the righmost digit as a strong RTL */
+                    pLevState->lastStrongRTL=limit - 1;
+                    break;
+                }
+                if (pLevState->startL2EN >= 0)  /* after EN, no AN */
+                {
+                    addPoint(pBiDi, pLevState->startL2EN, LRM_BEFORE);
+                    pLevState->startL2EN=-2;
+                }
+                /* note AN */
+                addPoint(pBiDi, start0, LRM_BEFORE);
+                break;
+            }
+            /* if first EN/AN after R/AL */
+            if (pLevState->startL2EN == -1) {
+                pLevState->startL2EN=start0;
+            }
+            break;
+
+        case 6:                         /* note location of latest R/AL */
+            pLevState->lastStrongRTL=limit - 1;
+            pLevState->startON=-1;
+            break;
+
+        case 7:                         /* L after R+ON/EN/AN */
+            /* include possible adjacent number on the left */
+            for (k=start0-1; k>=0 && !(levels[k]&1); k--);
+            if(k>=0) {
+                addPoint(pBiDi, k, RLM_BEFORE);             /* add RLM before */
+                pInsertPoints=&(pBiDi->insertPoints);
+                pInsertPoints->confirmed=pInsertPoints->size;   /* confirm it */
+            }
+            pLevState->startON=start0;
+            break;
+
+        case 8:                         /* AN after L */
+            /* AN numbers between L text on both sides may be trouble. */
+            /* tentatively bracket with LRMs; will be confirmed if followed by L */
+            addPoint(pBiDi, start0, LRM_BEFORE);    /* add LRM before */
+            addPoint(pBiDi, start0, LRM_AFTER);     /* add LRM after  */
+            break;
+
+        case 9:                         /* R after L+ON/EN/AN */
+            /* false alert, infirm LRMs around previous AN */
+            pInsertPoints=&(pBiDi->insertPoints);
+            pInsertPoints->size=pInsertPoints->confirmed;
+            if (_prop == DirProp_S)            /* add RLM before S */
+            {
+                addPoint(pBiDi, start0, RLM_BEFORE);
+                pInsertPoints->confirmed=pInsertPoints->size;
+            }
+            break;
+
+        case 10:                        /* L after L+ON/AN */
+            level=pLevState->runLevel + addLevel;
+            for(k=pLevState->startON; k<start0; k++) {
+                if (levels[k]<level)
+                    levels[k]=level;
+            }
+            pInsertPoints=&(pBiDi->insertPoints);
+            pInsertPoints->confirmed=pInsertPoints->size;   /* confirm inserts */
+            pLevState->startON=start0;
+            break;
+
+        case 11:                        /* L after L+ON+EN/AN/ON */
+            level=pLevState->runLevel;
+            for(k=start0-1; k>=pLevState->startON; k--) {
+                if(levels[k]==level+3) {
+                    while(levels[k]==level+3) {
+                        levels[k--]-=2;
+                    }
+                    while(levels[k]==level) {
+                        k--;
+                    }
+                }
+                if(levels[k]==level+2) {
+                    levels[k]=level;
+                    continue;
+                }
+                levels[k]=level+1;
+            }
+            break;
+
+        case 12:                        /* R after L+ON+EN/AN/ON */
+            level=pLevState->runLevel+1;
+            for(k=start0-1; k>=pLevState->startON; k--) {
+                if(levels[k]>level) {
+                    levels[k]-=2;
+                }
+            }
+            break;
+
+        default:                        /* we should never get here */
+            U_ASSERT(FALSE);
+            break;
+        }
+    }
+    if((addLevel) || (start < start0)) {
+        level=pLevState->runLevel + addLevel;
+        for(k=start; k<limit; k++) {
+            levels[k]=level;
+        }
+    }
+}
+
+static void
+resolveImplicitLevels(UBiDi *pBiDi,
+                      int32_t start, int32_t limit,
+                      DirProp sor, DirProp eor) {
+    const DirProp *dirProps=pBiDi->dirProps;
+
+    LevState levState;
+    int32_t i, start1, start2;
+    uint8_t oldStateImp, stateImp, actionImp;
+    uint8_t gprop, resProp, cell;
+    UBool inverseRTL;
+    DirProp nextStrongProp=R;
+    int32_t nextStrongPos=-1;
+
+    levState.startON = -1;  /* silence gcc flow analysis */
+
+    /* check for RTL inverse BiDi mode */
+    /* FOOD FOR THOUGHT: in case of RTL inverse BiDi, it would make sense to
+     * loop on the text characters from end to start.
+     * This would need a different properties state table (at least different
+     * actions) and different levels state tables (maybe very similar to the
+     * LTR corresponding ones.
+     */
+    inverseRTL=(UBool)
+        ((start<pBiDi->lastArabicPos) && (GET_PARALEVEL(pBiDi, start) & 1) &&
+         (pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_LIKE_DIRECT  ||
+          pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL));
+    /* initialize for levels state table */
+    levState.startL2EN=-1;              /* used for INVERSE_LIKE_DIRECT_WITH_MARKS */
+    levState.lastStrongRTL=-1;          /* used for INVERSE_LIKE_DIRECT_WITH_MARKS */
+    levState.state=0;
+    levState.runLevel=pBiDi->levels[start];
+    levState.pImpTab=(const ImpTab*)((pBiDi->pImpTabPair)->pImpTab)[levState.runLevel&1];
+    levState.pImpAct=(const ImpAct*)((pBiDi->pImpTabPair)->pImpAct)[levState.runLevel&1];
+    processPropertySeq(pBiDi, &levState, sor, start, start);
+    /* initialize for property state table */
+    if(NO_CONTEXT_RTL(dirProps[start])==NSM) {
+        stateImp = 1 + sor;
+    } else {
+        stateImp=0;
+    }
+    start1=start;
+    start2=start;
+
+    for(i=start; i<=limit; i++) {
+        if(i>=limit) {
+            gprop=eor;
+        } else {
+            DirProp prop, prop1;
+            prop=NO_CONTEXT_RTL(dirProps[i]);
+            if(inverseRTL) {
+                if(prop==AL) {
+                    /* AL before EN does not make it AN */
+                    prop=R;
+                } else if(prop==EN) {
+                    if(nextStrongPos<=i) {
+                        /* look for next strong char (L/R/AL) */
+                        int32_t j;
+                        nextStrongProp=R;   /* set default */
+                        nextStrongPos=limit;
+                        for(j=i+1; j<limit; j++) {
+                            prop1=NO_CONTEXT_RTL(dirProps[j]);
+                            if(prop1==L || prop1==R || prop1==AL) {
+                                nextStrongProp=prop1;
+                                nextStrongPos=j;
+                                break;
+                            }
+                        }
+                    }
+                    if(nextStrongProp==AL) {
+                        prop=AN;
+                    }
+                }
+            }
+            gprop=groupProp[prop];
+        }
+        oldStateImp=stateImp;
+        cell=impTabProps[oldStateImp][gprop];
+        stateImp=GET_STATEPROPS(cell);      /* isolate the new state */
+        actionImp=GET_ACTIONPROPS(cell);    /* isolate the action */
+        if((i==limit) && (actionImp==0)) {
+            /* there is an unprocessed sequence if its property == eor   */
+            actionImp=1;                    /* process the last sequence */
+        }
+        if(actionImp) {
+            resProp=impTabProps[oldStateImp][IMPTABPROPS_RES];
+            switch(actionImp) {
+            case 1:             /* process current seq1, init new seq1 */
+                processPropertySeq(pBiDi, &levState, resProp, start1, i);
+                start1=i;
+                break;
+            case 2:             /* init new seq2 */
+                start2=i;
+                break;
+            case 3:             /* process seq1, process seq2, init new seq1 */
+                processPropertySeq(pBiDi, &levState, resProp, start1, start2);
+                processPropertySeq(pBiDi, &levState, DirProp_ON, start2, i);
+                start1=i;
+                break;
+            case 4:             /* process seq1, set seq1=seq2, init new seq2 */
+                processPropertySeq(pBiDi, &levState, resProp, start1, start2);
+                start1=start2;
+                start2=i;
+                break;
+            default:            /* we should never get here */
+                U_ASSERT(FALSE);
+                break;
+            }
+        }
+    }
+    /* flush possible pending sequence, e.g. ON */
+    processPropertySeq(pBiDi, &levState, eor, limit, limit);
+}
+
+/* perform (L1) and (X9) ---------------------------------------------------- */
+
+/*
+ * Reset the embedding levels for some non-graphic characters (L1).
+ * This function also sets appropriate levels for BN, and
+ * explicit embedding types that are supposed to have been removed
+ * from the paragraph in (X9).
+ */
+static void
+adjustWSLevels(UBiDi *pBiDi) {
+    const DirProp *dirProps=pBiDi->dirProps;
+    UBiDiLevel *levels=pBiDi->levels;
+    int32_t i;
+
+    if(pBiDi->flags&MASK_WS) {
+        UBool orderParagraphsLTR=pBiDi->orderParagraphsLTR;
+        Flags flag;
+
+        i=pBiDi->trailingWSStart;
+        while(i>0) {
+            /* reset a sequence of WS/BN before eop and B/S to the paragraph paraLevel */
+            while(i>0 && (flag=DIRPROP_FLAG_NC(dirProps[--i]))&MASK_WS) {
+                if(orderParagraphsLTR&&(flag&DIRPROP_FLAG(B))) {
+                    levels[i]=0;
+                } else {
+                    levels[i]=GET_PARALEVEL(pBiDi, i);
+                }
+            }
+
+            /* reset BN to the next character's paraLevel until B/S, which restarts above loop */
+            /* here, i+1 is guaranteed to be <length */
+            while(i>0) {
+                flag=DIRPROP_FLAG_NC(dirProps[--i]);
+                if(flag&MASK_BN_EXPLICIT) {
+                    levels[i]=levels[i+1];
+                } else if(orderParagraphsLTR&&(flag&DIRPROP_FLAG(B))) {
+                    levels[i]=0;
+                    break;
+                } else if(flag&MASK_B_S) {
+                    levels[i]=GET_PARALEVEL(pBiDi, i);
+                    break;
+                }
+            }
+        }
+    }
+}
+
+#define BIDI_MIN(x, y)   ((x)<(y) ? (x) : (y))
+#define BIDI_ABS(x)      ((x)>=0  ? (x) : (-(x)))
+static void
+setParaRunsOnly(UBiDi *pBiDi, const UChar *text, int32_t length,
+                UBiDiLevel paraLevel, UErrorCode *pErrorCode) {
+    void *runsOnlyMemory;
+    int32_t *visualMap;
+    UChar *visualText;
+    int32_t saveLength, saveTrailingWSStart;
+    const UBiDiLevel *levels;
+    UBiDiLevel *saveLevels;
+    UBiDiDirection saveDirection;
+    UBool saveMayAllocateText;
+    Run *runs;
+    int32_t visualLength, i, j, visualStart, logicalStart,
+            runCount, runLength, addedRuns, insertRemove,
+            start, limit, step, indexOddBit, logicalPos,
+            index0, index1;
+    uint32_t saveOptions;
+
+    pBiDi->reorderingMode=UBIDI_REORDER_DEFAULT;
+    if(length==0) {
+        ubidi_setPara(pBiDi, text, length, paraLevel, NULL, pErrorCode);
+        goto cleanup3;
+    }
+    /* obtain memory for mapping table and visual text */
+    runsOnlyMemory=uprv_malloc(length*(sizeof(int32_t)+sizeof(UChar)+sizeof(UBiDiLevel)));
+    if(runsOnlyMemory==NULL) {
+        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+        goto cleanup3;
+    }
+    visualMap=runsOnlyMemory;
+    visualText=(UChar *)&visualMap[length];
+    saveLevels=(UBiDiLevel *)&visualText[length];
+    saveOptions=pBiDi->reorderingOptions;
+    if(saveOptions & UBIDI_OPTION_INSERT_MARKS) {
+        pBiDi->reorderingOptions&=~UBIDI_OPTION_INSERT_MARKS;
+        pBiDi->reorderingOptions|=UBIDI_OPTION_REMOVE_CONTROLS;
+    }
+    paraLevel&=1;                       /* accept only 0 or 1 */
+    ubidi_setPara(pBiDi, text, length, paraLevel, NULL, pErrorCode);
+    if(U_FAILURE(*pErrorCode)) {
+        goto cleanup3;
+    }
+    /* we cannot access directly pBiDi->levels since it is not yet set if
+     * direction is not MIXED
+     */
+    levels=ubidi_getLevels(pBiDi, pErrorCode);
+    uprv_memcpy(saveLevels, levels, pBiDi->length*sizeof(UBiDiLevel));
+    saveTrailingWSStart=pBiDi->trailingWSStart;
+    saveLength=pBiDi->length;
+    saveDirection=pBiDi->direction;
+
+    /* FOOD FOR THOUGHT: instead of writing the visual text, we could use
+     * the visual map and the dirProps array to drive the second call
+     * to ubidi_setPara (but must make provision for possible removal of
+     * BiDi controls.  Alternatively, only use the dirProps array via
+     * customized classifier callback.
+     */
+    visualLength=ubidi_writeReordered(pBiDi, visualText, length,
+                                      UBIDI_DO_MIRRORING, pErrorCode);
+    ubidi_getVisualMap(pBiDi, visualMap, pErrorCode);
+    if(U_FAILURE(*pErrorCode)) {
+        goto cleanup2;
+    }
+    pBiDi->reorderingOptions=saveOptions;
+
+    pBiDi->reorderingMode=UBIDI_REORDER_INVERSE_LIKE_DIRECT;
+    paraLevel^=1;
+    /* Because what we did with reorderingOptions, visualText may be shorter
+     * than the original text. But we don't want the levels memory to be
+     * reallocated shorter than the original length, since we need to restore
+     * the levels as after the first call to ubidi_setpara() before returning.
+     * We will force mayAllocateText to FALSE before the second call to
+     * ubidi_setpara(), and will restore it afterwards.
+     */
+    saveMayAllocateText=pBiDi->mayAllocateText;
+    pBiDi->mayAllocateText=FALSE;
+    ubidi_setPara(pBiDi, visualText, visualLength, paraLevel, NULL, pErrorCode);
+    pBiDi->mayAllocateText=saveMayAllocateText;
+    ubidi_getRuns(pBiDi, pErrorCode);
+    if(U_FAILURE(*pErrorCode)) {
+        goto cleanup1;
+    }
+    /* check if some runs must be split, count how many splits */
+    addedRuns=0;
+    runCount=pBiDi->runCount;
+    runs=pBiDi->runs;
+    visualStart=0;
+    for(i=0; i<runCount; i++, visualStart+=runLength) {
+        runLength=runs[i].visualLimit-visualStart;
+        if(runLength<2) {
+            continue;
+        }
+        logicalStart=GET_INDEX(runs[i].logicalStart);
+        for(j=logicalStart+1; j<logicalStart+runLength; j++) {
+            index0=visualMap[j];
+            index1=visualMap[j-1];
+            if((BIDI_ABS(index0-index1)!=1) || (saveLevels[index0]!=saveLevels[index1])) {
+                addedRuns++;
+            }
+        }
+    }
+    if(addedRuns) {
+        if(getRunsMemory(pBiDi, runCount+addedRuns)) {
+            if(runCount==1) {
+                /* because we switch from UBiDi.simpleRuns to UBiDi.runs */
+                pBiDi->runsMemory[0]=runs[0];
+            }
+            runs=pBiDi->runs=pBiDi->runsMemory;
+            pBiDi->runCount+=addedRuns;
+        } else {
+            goto cleanup1;
+        }
+    }
+    /* split runs which are not consecutive in source text */
+    for(i=runCount-1; i>=0; i--) {
+        runLength= i==0 ? runs[0].visualLimit :
+                          runs[i].visualLimit-runs[i-1].visualLimit;
+        logicalStart=runs[i].logicalStart;
+        indexOddBit=GET_ODD_BIT(logicalStart);
+        logicalStart=GET_INDEX(logicalStart);
+        if(runLength<2) {
+            if(addedRuns) {
+                runs[i+addedRuns]=runs[i];
+            }
+            logicalPos=visualMap[logicalStart];
+            runs[i+addedRuns].logicalStart=MAKE_INDEX_ODD_PAIR(logicalPos,
+                                            saveLevels[logicalPos]^indexOddBit);
+            continue;
+        }
+        if(indexOddBit) {
+            start=logicalStart;
+            limit=logicalStart+runLength-1;
+            step=1;
+        } else {
+            start=logicalStart+runLength-1;
+            limit=logicalStart;
+            step=-1;
+        }
+        for(j=start; j!=limit; j+=step) {
+            index0=visualMap[j];
+            index1=visualMap[j+step];
+            if((BIDI_ABS(index0-index1)!=1) || (saveLevels[index0]!=saveLevels[index1])) {
+                logicalPos=BIDI_MIN(visualMap[start], index0);
+                runs[i+addedRuns].logicalStart=MAKE_INDEX_ODD_PAIR(logicalPos,
+                                            saveLevels[logicalPos]^indexOddBit);
+                runs[i+addedRuns].visualLimit=runs[i].visualLimit;
+                runs[i].visualLimit-=BIDI_ABS(j-start)+1;
+                insertRemove=runs[i].insertRemove&(LRM_AFTER|RLM_AFTER);
+                runs[i+addedRuns].insertRemove=insertRemove;
+                runs[i].insertRemove&=~insertRemove;
+                start=j+step;
+                addedRuns--;
+            }
+        }
+        if(addedRuns) {
+            runs[i+addedRuns]=runs[i];
+        }
+        logicalPos=BIDI_MIN(visualMap[start], visualMap[limit]);
+        runs[i+addedRuns].logicalStart=MAKE_INDEX_ODD_PAIR(logicalPos,
+                                            saveLevels[logicalPos]^indexOddBit);
+    }
+
+  cleanup1:
+    /* restore initial paraLevel */
+    pBiDi->paraLevel^=1;
+  cleanup2:
+    /* restore real text */
+    pBiDi->text=text;
+    pBiDi->length=saveLength;
+    pBiDi->originalLength=length;
+    pBiDi->direction=saveDirection;
+    /* the saved levels should never excess levelsSize, but we check anyway */
+    if(saveLength>pBiDi->levelsSize) {
+        saveLength=pBiDi->levelsSize;
+    }
+    uprv_memcpy(pBiDi->levels, saveLevels, saveLength*sizeof(UBiDiLevel));
+    pBiDi->trailingWSStart=saveTrailingWSStart;
+    /* free memory for mapping table and visual text */
+    uprv_free(runsOnlyMemory);
+    if(pBiDi->runCount>1) {
+        pBiDi->direction=UBIDI_MIXED;
+    }
+  cleanup3:
+    pBiDi->reorderingMode=UBIDI_REORDER_RUNS_ONLY;
+}
+
+/* ubidi_setPara ------------------------------------------------------------ */
+
+U_CAPI void U_EXPORT2
+ubidi_setPara(UBiDi *pBiDi, const UChar *text, int32_t length,
+              UBiDiLevel paraLevel, UBiDiLevel *embeddingLevels,
+              UErrorCode *pErrorCode) {
+    UBiDiDirection direction;
+
+    /* check the argument values */
+    RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode);
+    if(pBiDi==NULL || text==NULL || length<-1 ||
+       (paraLevel>UBIDI_MAX_EXPLICIT_LEVEL && paraLevel<UBIDI_DEFAULT_LTR)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    if(length==-1) {
+        length=u_strlen(text);
+    }
+
+    /* special treatment for RUNS_ONLY mode */
+    if(pBiDi->reorderingMode==UBIDI_REORDER_RUNS_ONLY) {
+        setParaRunsOnly(pBiDi, text, length, paraLevel, pErrorCode);
+        return;
+    }
+
+    /* initialize the UBiDi structure */
+    pBiDi->pParaBiDi=NULL;          /* mark unfinished setPara */
+    pBiDi->text=text;
+    pBiDi->length=pBiDi->originalLength=pBiDi->resultLength=length;
+    pBiDi->paraLevel=paraLevel;
+    pBiDi->direction=UBIDI_LTR;
+    pBiDi->paraCount=1;
+
+    pBiDi->dirProps=NULL;
+    pBiDi->levels=NULL;
+    pBiDi->runs=NULL;
+    pBiDi->insertPoints.size=0;         /* clean up from last call */
+    pBiDi->insertPoints.confirmed=0;    /* clean up from last call */
+
+    /*
+     * Save the original paraLevel if contextual; otherwise, set to 0.
+     */
+    if(IS_DEFAULT_LEVEL(paraLevel)) {
+        pBiDi->defaultParaLevel=paraLevel;
+    } else {
+        pBiDi->defaultParaLevel=0;
+    }
+
+    if(length==0) {
+        /*
+         * For an empty paragraph, create a UBiDi object with the paraLevel and
+         * the flags and the direction set but without allocating zero-length arrays.
+         * There is nothing more to do.
+         */
+        if(IS_DEFAULT_LEVEL(paraLevel)) {
+            pBiDi->paraLevel&=1;
+            pBiDi->defaultParaLevel=0;
+        }
+        if(paraLevel&1) {
+            pBiDi->flags=DIRPROP_FLAG(R);
+            pBiDi->direction=UBIDI_RTL;
+        } else {
+            pBiDi->flags=DIRPROP_FLAG(L);
+            pBiDi->direction=UBIDI_LTR;
+        }
+
+        pBiDi->runCount=0;
+        pBiDi->paraCount=0;
+        pBiDi->pParaBiDi=pBiDi;         /* mark successful setPara */
+        return;
+    }
+
+    pBiDi->runCount=-1;
+
+    /*
+     * Get the directional properties,
+     * the flags bit-set, and
+     * determine the paragraph level if necessary.
+     */
+    if(getDirPropsMemory(pBiDi, length)) {
+        pBiDi->dirProps=pBiDi->dirPropsMemory;
+        getDirProps(pBiDi);
+    } else {
+        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    /* the processed length may have changed if UBIDI_OPTION_STREAMING */
+    length= pBiDi->length;
+    pBiDi->trailingWSStart=length;  /* the levels[] will reflect the WS run */
+    /* allocate paras memory */
+    if(pBiDi->paraCount>1) {
+        if(getInitialParasMemory(pBiDi, pBiDi->paraCount)) {
+            pBiDi->paras=pBiDi->parasMemory;
+            pBiDi->paras[pBiDi->paraCount-1]=length;
+        } else {
+            *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+    } else {
+        /* initialize paras for single paragraph */
+        pBiDi->paras=pBiDi->simpleParas;
+        pBiDi->simpleParas[0]=length;
+    }
+
+    /* are explicit levels specified? */
+    if(embeddingLevels==NULL) {
+        /* no: determine explicit levels according to the (Xn) rules */\
+        if(getLevelsMemory(pBiDi, length)) {
+            pBiDi->levels=pBiDi->levelsMemory;
+            direction=resolveExplicitLevels(pBiDi);
+        } else {
+            *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+    } else {
+        /* set BN for all explicit codes, check that all levels are 0 or paraLevel..UBIDI_MAX_EXPLICIT_LEVEL */
+        pBiDi->levels=embeddingLevels;
+        direction=checkExplicitLevels(pBiDi, pErrorCode);
+        if(U_FAILURE(*pErrorCode)) {
+            return;
+        }
+    }
+
+    /*
+     * The steps after (X9) in the UBiDi algorithm are performed only if
+     * the paragraph text has mixed directionality!
+     */
+    pBiDi->direction=direction;
+    switch(direction) {
+    case UBIDI_LTR:
+        /* make sure paraLevel is even */
+        pBiDi->paraLevel=(UBiDiLevel)((pBiDi->paraLevel+1)&~1);
+
+        /* all levels are implicitly at paraLevel (important for ubidi_getLevels()) */
+        pBiDi->trailingWSStart=0;
+        break;
+    case UBIDI_RTL:
+        /* make sure paraLevel is odd */
+        pBiDi->paraLevel|=1;
+
+        /* all levels are implicitly at paraLevel (important for ubidi_getLevels()) */
+        pBiDi->trailingWSStart=0;
+        break;
+    default:
+        /*
+         *  Choose the right implicit state table
+         */
+        switch(pBiDi->reorderingMode) {
+        case UBIDI_REORDER_DEFAULT:
+            pBiDi->pImpTabPair=&impTab_DEFAULT;
+            break;
+        case UBIDI_REORDER_NUMBERS_SPECIAL:
+            pBiDi->pImpTabPair=&impTab_NUMBERS_SPECIAL;
+            break;
+        case UBIDI_REORDER_GROUP_NUMBERS_WITH_R:
+            pBiDi->pImpTabPair=&impTab_GROUP_NUMBERS_WITH_R;
+            break;
+        case UBIDI_REORDER_INVERSE_NUMBERS_AS_L:
+            pBiDi->pImpTabPair=&impTab_INVERSE_NUMBERS_AS_L;
+            break;
+        case UBIDI_REORDER_INVERSE_LIKE_DIRECT:
+            if (pBiDi->reorderingOptions & UBIDI_OPTION_INSERT_MARKS) {
+                pBiDi->pImpTabPair=&impTab_INVERSE_LIKE_DIRECT_WITH_MARKS;
+            } else {
+                pBiDi->pImpTabPair=&impTab_INVERSE_LIKE_DIRECT;
+            }
+            break;
+        case UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL:
+            if (pBiDi->reorderingOptions & UBIDI_OPTION_INSERT_MARKS) {
+                pBiDi->pImpTabPair=&impTab_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS;
+            } else {
+                pBiDi->pImpTabPair=&impTab_INVERSE_FOR_NUMBERS_SPECIAL;
+            }
+            break;
+        default:
+            /* we should never get here */
+            U_ASSERT(FALSE);
+            break;
+        }
+        /*
+         * If there are no external levels specified and there
+         * are no significant explicit level codes in the text,
+         * then we can treat the entire paragraph as one run.
+         * Otherwise, we need to perform the following rules on runs of
+         * the text with the same embedding levels. (X10)
+         * "Significant" explicit level codes are ones that actually
+         * affect non-BN characters.
+         * Examples for "insignificant" ones are empty embeddings
+         * LRE-PDF, LRE-RLE-PDF-PDF, etc.
+         */
+        if(embeddingLevels==NULL && pBiDi->paraCount<=1 &&
+                                   !(pBiDi->flags&DIRPROP_FLAG_MULTI_RUNS)) {
+            resolveImplicitLevels(pBiDi, 0, length,
+                                    GET_LR_FROM_LEVEL(GET_PARALEVEL(pBiDi, 0)),
+                                    GET_LR_FROM_LEVEL(GET_PARALEVEL(pBiDi, length-1)));
+        } else {
+            /* sor, eor: start and end types of same-level-run */
+            UBiDiLevel *levels=pBiDi->levels;
+            int32_t start, limit=0;
+            UBiDiLevel level, nextLevel;
+            DirProp sor, eor;
+
+            /* determine the first sor and set eor to it because of the loop body (sor=eor there) */
+            level=GET_PARALEVEL(pBiDi, 0);
+            nextLevel=levels[0];
+            if(level<nextLevel) {
+                eor=GET_LR_FROM_LEVEL(nextLevel);
+            } else {
+                eor=GET_LR_FROM_LEVEL(level);
+            }
+
+            do {
+                /* determine start and limit of the run (end points just behind the run) */
+
+                /* the values for this run's start are the same as for the previous run's end */
+                start=limit;
+                level=nextLevel;
+                if((start>0) && (NO_CONTEXT_RTL(pBiDi->dirProps[start-1])==B)) {
+                    /* except if this is a new paragraph, then set sor = para level */
+                    sor=GET_LR_FROM_LEVEL(GET_PARALEVEL(pBiDi, start));
+                } else {
+                    sor=eor;
+                }
+
+                /* search for the limit of this run */
+                while(++limit<length && levels[limit]==level) {}
+
+                /* get the correct level of the next run */
+                if(limit<length) {
+                    nextLevel=levels[limit];
+                } else {
+                    nextLevel=GET_PARALEVEL(pBiDi, length-1);
+                }
+
+                /* determine eor from max(level, nextLevel); sor is last run's eor */
+                if((level&~UBIDI_LEVEL_OVERRIDE)<(nextLevel&~UBIDI_LEVEL_OVERRIDE)) {
+                    eor=GET_LR_FROM_LEVEL(nextLevel);
+                } else {
+                    eor=GET_LR_FROM_LEVEL(level);
+                }
+
+                /* if the run consists of overridden directional types, then there
+                   are no implicit types to be resolved */
+                if(!(level&UBIDI_LEVEL_OVERRIDE)) {
+                    resolveImplicitLevels(pBiDi, start, limit, sor, eor);
+                } else {
+                    /* remove the UBIDI_LEVEL_OVERRIDE flags */
+                    do {
+                        levels[start++]&=~UBIDI_LEVEL_OVERRIDE;
+                    } while(start<limit);
+                }
+            } while(limit<length);
+        }
+        /* check if we got any memory shortage while adding insert points */
+        if (U_FAILURE(pBiDi->insertPoints.errorCode))
+        {
+            *pErrorCode=pBiDi->insertPoints.errorCode;
+            return;
+        }
+        /* reset the embedding levels for some non-graphic characters (L1), (X9) */
+        adjustWSLevels(pBiDi);
+        break;
+    }
+    /* add RLM for inverse Bidi with contextual orientation resolving
+     * to RTL which would not round-trip otherwise
+     */
+    if((pBiDi->defaultParaLevel>0) &&
+       (pBiDi->reorderingOptions & UBIDI_OPTION_INSERT_MARKS) &&
+       ((pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_LIKE_DIRECT) ||
+        (pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL))) {
+        int32_t i, j, start, last;
+        DirProp dirProp;
+        for(i=0; i<pBiDi->paraCount; i++) {
+            last=pBiDi->paras[i]-1;
+            if((pBiDi->dirProps[last] & CONTEXT_RTL)==0) {
+                continue;           /* LTR paragraph */
+            }
+            start= i==0 ? 0 : pBiDi->paras[i - 1];
+            for(j=last; j>=start; j--) {
+                dirProp=NO_CONTEXT_RTL(pBiDi->dirProps[j]);
+                if(dirProp==L) {
+                    if(j<last) {
+                        while(NO_CONTEXT_RTL(pBiDi->dirProps[last])==B) {
+                            last--;
+                        }
+                    }
+                    addPoint(pBiDi, last, RLM_BEFORE);
+                    break;
+                }
+                if(DIRPROP_FLAG(dirProp) & MASK_R_AL) {
+                    break;
+                }
+            }
+        }
+    }
+
+    if(pBiDi->reorderingOptions & UBIDI_OPTION_REMOVE_CONTROLS) {
+        pBiDi->resultLength -= pBiDi->controlCount;
+    } else {
+        pBiDi->resultLength += pBiDi->insertPoints.size;
+    }
+    pBiDi->pParaBiDi=pBiDi;             /* mark successful setPara */
+}
+
+U_CAPI void U_EXPORT2
+ubidi_orderParagraphsLTR(UBiDi *pBiDi, UBool orderParagraphsLTR) {
+    if(pBiDi!=NULL) {
+        pBiDi->orderParagraphsLTR=orderParagraphsLTR;
+    }
+}
+
+U_CAPI UBool U_EXPORT2
+ubidi_isOrderParagraphsLTR(UBiDi *pBiDi) {
+    if(pBiDi!=NULL) {
+        return pBiDi->orderParagraphsLTR;
+    } else {
+        return FALSE;
+    }
+}
+
+U_CAPI UBiDiDirection U_EXPORT2
+ubidi_getDirection(const UBiDi *pBiDi) {
+    if(IS_VALID_PARA_OR_LINE(pBiDi)) {
+        return pBiDi->direction;
+    } else {
+        return UBIDI_LTR;
+    }
+}
+
+U_CAPI const UChar * U_EXPORT2
+ubidi_getText(const UBiDi *pBiDi) {
+    if(IS_VALID_PARA_OR_LINE(pBiDi)) {
+        return pBiDi->text;
+    } else {
+        return NULL;
+    }
+}
+
+U_CAPI int32_t U_EXPORT2
+ubidi_getLength(const UBiDi *pBiDi) {
+    if(IS_VALID_PARA_OR_LINE(pBiDi)) {
+        return pBiDi->originalLength;
+    } else {
+        return 0;
+    }
+}
+
+U_CAPI int32_t U_EXPORT2
+ubidi_getProcessedLength(const UBiDi *pBiDi) {
+    if(IS_VALID_PARA_OR_LINE(pBiDi)) {
+        return pBiDi->length;
+    } else {
+        return 0;
+    }
+}
+
+U_CAPI int32_t U_EXPORT2
+ubidi_getResultLength(const UBiDi *pBiDi) {
+    if(IS_VALID_PARA_OR_LINE(pBiDi)) {
+        return pBiDi->resultLength;
+    } else {
+        return 0;
+    }
+}
+
+/* paragraphs API functions ------------------------------------------------- */
+
+U_CAPI UBiDiLevel U_EXPORT2
+ubidi_getParaLevel(const UBiDi *pBiDi) {
+    if(IS_VALID_PARA_OR_LINE(pBiDi)) {
+        return pBiDi->paraLevel;
+    } else {
+        return 0;
+    }
+}
+
+U_CAPI int32_t U_EXPORT2
+ubidi_countParagraphs(UBiDi *pBiDi) {
+    if(!IS_VALID_PARA_OR_LINE(pBiDi)) {
+        return 0;
+    } else {
+        return pBiDi->paraCount;
+    }
+}
+
+U_CAPI void U_EXPORT2
+ubidi_getParagraphByIndex(const UBiDi *pBiDi, int32_t paraIndex,
+                          int32_t *pParaStart, int32_t *pParaLimit,
+                          UBiDiLevel *pParaLevel, UErrorCode *pErrorCode) {
+    int32_t paraStart;
+
+    /* check the argument values */
+    RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode);
+    RETURN_VOID_IF_NOT_VALID_PARA_OR_LINE(pBiDi, *pErrorCode);
+    RETURN_VOID_IF_BAD_RANGE(paraIndex, 0, pBiDi->paraCount, *pErrorCode);
+
+    pBiDi=pBiDi->pParaBiDi;             /* get Para object if Line object */
+    if(paraIndex) {
+        paraStart=pBiDi->paras[paraIndex-1];
+    } else {
+        paraStart=0;
+    }
+    if(pParaStart!=NULL) {
+        *pParaStart=paraStart;
+    }
+    if(pParaLimit!=NULL) {
+        *pParaLimit=pBiDi->paras[paraIndex];
+    }
+    if(pParaLevel!=NULL) {
+        *pParaLevel=GET_PARALEVEL(pBiDi, paraStart);
+    }
+}
+
+U_CAPI int32_t U_EXPORT2
+ubidi_getParagraph(const UBiDi *pBiDi, int32_t charIndex,
+                          int32_t *pParaStart, int32_t *pParaLimit,
+                          UBiDiLevel *pParaLevel, UErrorCode *pErrorCode) {
+    uint32_t paraIndex;
+
+    /* check the argument values */
+    /* pErrorCode will be checked by the call to ubidi_getParagraphByIndex */
+    RETURN_IF_NULL_OR_FAILING_ERRCODE(pErrorCode, -1);
+    RETURN_IF_NOT_VALID_PARA_OR_LINE(pBiDi, *pErrorCode, -1);
+    pBiDi=pBiDi->pParaBiDi;             /* get Para object if Line object */
+    RETURN_IF_BAD_RANGE(charIndex, 0, pBiDi->length, *pErrorCode, -1);
+
+    for(paraIndex=0; charIndex>=pBiDi->paras[paraIndex]; paraIndex++);
+    ubidi_getParagraphByIndex(pBiDi, paraIndex, pParaStart, pParaLimit, pParaLevel, pErrorCode);
+    return paraIndex;
+}
+
+U_CAPI void U_EXPORT2
+ubidi_setClassCallback(UBiDi *pBiDi, UBiDiClassCallback *newFn,
+                       const void *newContext, UBiDiClassCallback **oldFn,
+                       const void **oldContext, UErrorCode *pErrorCode)
+{
+    RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode);
+    if(pBiDi==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    if( oldFn )
+    {
+        *oldFn = pBiDi->fnClassCallback;
+    }
+    if( oldContext )
+    {
+        *oldContext = pBiDi->coClassCallback;
+    }
+    pBiDi->fnClassCallback = newFn;
+    pBiDi->coClassCallback = newContext;
+}
+
+U_CAPI void U_EXPORT2
+ubidi_getClassCallback(UBiDi *pBiDi, UBiDiClassCallback **fn, const void **context)
+{
+    if(pBiDi==NULL) {
+        return;
+    }
+    if( fn )
+    {
+        *fn = pBiDi->fnClassCallback;
+    }
+    if( context )
+    {
+        *context = pBiDi->coClassCallback;
+    }
+}
+
+U_CAPI UCharDirection U_EXPORT2
+ubidi_getCustomizedClass(UBiDi *pBiDi, UChar32 c)
+{
+    UCharDirection dir;
+
+    if( pBiDi->fnClassCallback == NULL ||
+        (dir = (*pBiDi->fnClassCallback)(pBiDi->coClassCallback, c)) == U_BIDI_CLASS_DEFAULT )
+    {
+        return ubidi_getClass(pBiDi->bdp, c);
+    } else {
+        return dir;
+    }
+}
+
diff --git a/source/common/ubidi_props.c b/source/common/ubidi_props.c
new file mode 100644
index 0000000..55cc7cf
--- /dev/null
+++ b/source/common/ubidi_props.c
@@ -0,0 +1,220 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2004-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  ubidi_props.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2004dec30
+*   created by: Markus W. Scherer
+*
+*   Low-level Unicode bidi/shaping properties access.
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uset.h"
+#include "unicode/udata.h" /* UDataInfo */
+#include "ucmndata.h" /* DataHeader */
+#include "udatamem.h"
+#include "umutex.h"
+#include "uassert.h"
+#include "cmemory.h"
+#include "utrie2.h"
+#include "ubidi_props.h"
+#include "ucln_cmn.h"
+
+struct UBiDiProps {
+    UDataMemory *mem;
+    const int32_t *indexes;
+    const uint32_t *mirrors;
+    const uint8_t *jgArray;
+
+    UTrie2 trie;
+    uint8_t formatVersion[4];
+};
+
+/* ubidi_props_data.c is machine-generated by genbidi --csource */
+#include "ubidi_props_data.c"
+
+/* UBiDiProps singleton ----------------------------------------------------- */
+
+U_CFUNC const UBiDiProps *
+ubidi_getSingleton() {
+    return &ubidi_props_singleton;
+}
+
+/* set of property starts for UnicodeSet ------------------------------------ */
+
+static UBool U_CALLCONV
+_enumPropertyStartsRange(const void *context, UChar32 start, UChar32 end, uint32_t value) {
+    /* add the start code point to the USet */
+    const USetAdder *sa=(const USetAdder *)context;
+    sa->add(sa->set, start);
+    return TRUE;
+}
+
+U_CFUNC void
+ubidi_addPropertyStarts(const UBiDiProps *bdp, const USetAdder *sa, UErrorCode *pErrorCode) {
+    int32_t i, length;
+    UChar32 c, start, limit;
+
+    const uint8_t *jgArray;
+    uint8_t prev, jg;
+
+    if(U_FAILURE(*pErrorCode)) {
+        return;
+    }
+
+    /* add the start code point of each same-value range of the trie */
+    utrie2_enum(&bdp->trie, NULL, _enumPropertyStartsRange, sa);
+
+    /* add the code points from the bidi mirroring table */
+    length=bdp->indexes[UBIDI_IX_MIRROR_LENGTH];
+    for(i=0; i<length; ++i) {
+        c=UBIDI_GET_MIRROR_CODE_POINT(bdp->mirrors[i]);
+        sa->addRange(sa->set, c, c+1);
+    }
+
+    /* add the code points from the Joining_Group array where the value changes */
+    start=bdp->indexes[UBIDI_IX_JG_START];
+    limit=bdp->indexes[UBIDI_IX_JG_LIMIT];
+    jgArray=bdp->jgArray;
+    prev=0;
+    while(start<limit) {
+        jg=*jgArray++;
+        if(jg!=prev) {
+            sa->add(sa->set, start);
+            prev=jg;
+        }
+        ++start;
+    }
+    if(prev!=0) {
+        /* add the limit code point if the last value was not 0 (it is now start==limit) */
+        sa->add(sa->set, limit);
+    }
+
+    /* add code points with hardcoded properties, plus the ones following them */
+
+    /* (none right now) */
+}
+
+/* property access functions ------------------------------------------------ */
+
+U_CFUNC int32_t
+ubidi_getMaxValue(const UBiDiProps *bdp, UProperty which) {
+    int32_t max;
+
+    if(bdp==NULL) {
+        return -1;
+    }
+
+    max=bdp->indexes[UBIDI_MAX_VALUES_INDEX];
+    switch(which) {
+    case UCHAR_BIDI_CLASS:
+        return (max&UBIDI_CLASS_MASK);
+    case UCHAR_JOINING_GROUP:
+        return (max&UBIDI_MAX_JG_MASK)>>UBIDI_MAX_JG_SHIFT;
+    case UCHAR_JOINING_TYPE:
+        return (max&UBIDI_JT_MASK)>>UBIDI_JT_SHIFT;
+    default:
+        return -1; /* undefined */
+    }
+}
+
+U_CAPI UCharDirection
+ubidi_getClass(const UBiDiProps *bdp, UChar32 c) {
+    uint16_t props=UTRIE2_GET16(&bdp->trie, c);
+    return (UCharDirection)UBIDI_GET_CLASS(props);
+}
+
+U_CFUNC UBool
+ubidi_isMirrored(const UBiDiProps *bdp, UChar32 c) {
+    uint16_t props=UTRIE2_GET16(&bdp->trie, c);
+    return (UBool)UBIDI_GET_FLAG(props, UBIDI_IS_MIRRORED_SHIFT);
+}
+
+U_CFUNC UChar32
+ubidi_getMirror(const UBiDiProps *bdp, UChar32 c) {
+    uint16_t props=UTRIE2_GET16(&bdp->trie, c);
+    int32_t delta=((int16_t)props)>>UBIDI_MIRROR_DELTA_SHIFT;
+    if(delta!=UBIDI_ESC_MIRROR_DELTA) {
+        return c+delta;
+    } else {
+        /* look for mirror code point in the mirrors[] table */
+        const uint32_t *mirrors;
+        uint32_t m;
+        int32_t i, length;
+        UChar32 c2;
+
+        mirrors=bdp->mirrors;
+        length=bdp->indexes[UBIDI_IX_MIRROR_LENGTH];
+
+        /* linear search */
+        for(i=0; i<length; ++i) {
+            m=mirrors[i];
+            c2=UBIDI_GET_MIRROR_CODE_POINT(m);
+            if(c==c2) {
+                /* found c, return its mirror code point using the index in m */
+                return UBIDI_GET_MIRROR_CODE_POINT(mirrors[UBIDI_GET_MIRROR_INDEX(m)]);
+            } else if(c<c2) {
+                break;
+            }
+        }
+
+        /* c not found, return it itself */
+        return c;
+    }
+}
+
+U_CFUNC UBool
+ubidi_isBidiControl(const UBiDiProps *bdp, UChar32 c) {
+    uint16_t props=UTRIE2_GET16(&bdp->trie, c);
+    return (UBool)UBIDI_GET_FLAG(props, UBIDI_BIDI_CONTROL_SHIFT);
+}
+
+U_CFUNC UBool
+ubidi_isJoinControl(const UBiDiProps *bdp, UChar32 c) {
+    uint16_t props=UTRIE2_GET16(&bdp->trie, c);
+    return (UBool)UBIDI_GET_FLAG(props, UBIDI_JOIN_CONTROL_SHIFT);
+}
+
+U_CFUNC UJoiningType
+ubidi_getJoiningType(const UBiDiProps *bdp, UChar32 c) {
+    uint16_t props=UTRIE2_GET16(&bdp->trie, c);
+    return (UJoiningType)((props&UBIDI_JT_MASK)>>UBIDI_JT_SHIFT);
+}
+
+U_CFUNC UJoiningGroup
+ubidi_getJoiningGroup(const UBiDiProps *bdp, UChar32 c) {
+    UChar32 start, limit;
+
+    start=bdp->indexes[UBIDI_IX_JG_START];
+    limit=bdp->indexes[UBIDI_IX_JG_LIMIT];
+    if(start<=c && c<limit) {
+        return (UJoiningGroup)bdp->jgArray[c-start];
+    } else {
+        return U_JG_NO_JOINING_GROUP;
+    }
+}
+
+/* public API (see uchar.h) ------------------------------------------------- */
+
+U_CFUNC UCharDirection
+u_charDirection(UChar32 c) {   
+    return ubidi_getClass(&ubidi_props_singleton, c);
+}
+
+U_CFUNC UBool
+u_isMirrored(UChar32 c) {
+    return ubidi_isMirrored(&ubidi_props_singleton, c);
+}
+
+U_CFUNC UChar32
+u_charMirror(UChar32 c) {
+    return ubidi_getMirror(&ubidi_props_singleton, c);
+}
diff --git a/source/common/ubidi_props.h b/source/common/ubidi_props.h
new file mode 100644
index 0000000..503bd5d
--- /dev/null
+++ b/source/common/ubidi_props.h
@@ -0,0 +1,141 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2004-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  ubidi_props.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2004dec30
+*   created by: Markus W. Scherer
+*
+*   Low-level Unicode bidi/shaping properties access.
+*/
+
+#ifndef __UBIDI_PROPS_H__
+#define __UBIDI_PROPS_H__
+
+#include "unicode/utypes.h"
+#include "unicode/uset.h"
+#include "uset_imp.h"
+#include "udataswp.h"
+
+U_CDECL_BEGIN
+
+/* library API -------------------------------------------------------------- */
+
+struct UBiDiProps;
+typedef struct UBiDiProps UBiDiProps;
+
+U_CFUNC const UBiDiProps *
+ubidi_getSingleton(void);
+
+U_CAPI int32_t
+ubidi_swap(const UDataSwapper *ds,
+           const void *inData, int32_t length, void *outData,
+           UErrorCode *pErrorCode);
+
+U_CFUNC void
+ubidi_addPropertyStarts(const UBiDiProps *bdp, const USetAdder *sa, UErrorCode *pErrorCode);
+
+/* property access functions */
+
+U_CFUNC int32_t
+ubidi_getMaxValue(const UBiDiProps *bdp, UProperty which);
+
+U_CAPI UCharDirection
+ubidi_getClass(const UBiDiProps *bdp, UChar32 c);
+
+U_CFUNC UBool
+ubidi_isMirrored(const UBiDiProps *bdp, UChar32 c);
+
+U_CFUNC UChar32
+ubidi_getMirror(const UBiDiProps *bdp, UChar32 c);
+
+U_CFUNC UBool
+ubidi_isBidiControl(const UBiDiProps *bdp, UChar32 c);
+
+U_CFUNC UBool
+ubidi_isJoinControl(const UBiDiProps *bdp, UChar32 c);
+
+U_CFUNC UJoiningType
+ubidi_getJoiningType(const UBiDiProps *bdp, UChar32 c);
+
+U_CFUNC UJoiningGroup
+ubidi_getJoiningGroup(const UBiDiProps *bdp, UChar32 c);
+
+/* file definitions --------------------------------------------------------- */
+
+#define UBIDI_DATA_NAME "ubidi"
+#define UBIDI_DATA_TYPE "icu"
+
+/* format "BiDi" */
+#define UBIDI_FMT_0 0x42
+#define UBIDI_FMT_1 0x69
+#define UBIDI_FMT_2 0x44
+#define UBIDI_FMT_3 0x69
+
+/* indexes into indexes[] */
+enum {
+    UBIDI_IX_INDEX_TOP,
+    UBIDI_IX_LENGTH,
+    UBIDI_IX_TRIE_SIZE,
+    UBIDI_IX_MIRROR_LENGTH,
+
+    UBIDI_IX_JG_START,
+    UBIDI_IX_JG_LIMIT,
+
+    UBIDI_MAX_VALUES_INDEX=15,
+    UBIDI_IX_TOP=16
+};
+
+/* definitions for 16-bit bidi/shaping properties word ---------------------- */
+
+enum {
+ /* UBIDI_CLASS_SHIFT=0, */     /* bidi class: 5 bits (4..0) */
+    UBIDI_JT_SHIFT=5,           /* joining type: 3 bits (7..5) */
+
+    /* UBIDI__SHIFT=8, reserved: 2 bits (9..8) */
+
+    UBIDI_JOIN_CONTROL_SHIFT=10,
+    UBIDI_BIDI_CONTROL_SHIFT=11,
+
+    UBIDI_IS_MIRRORED_SHIFT=12,         /* 'is mirrored' */
+    UBIDI_MIRROR_DELTA_SHIFT=13,        /* bidi mirroring delta: 3 bits (15..13) */
+
+    UBIDI_MAX_JG_SHIFT=16               /* max JG value in indexes[UBIDI_MAX_VALUES_INDEX] bits 23..16 */
+};
+
+#define UBIDI_CLASS_MASK        0x0000001f
+#define UBIDI_JT_MASK           0x000000e0
+
+#define UBIDI_MAX_JG_MASK       0x00ff0000
+
+#define UBIDI_GET_CLASS(props) ((props)&UBIDI_CLASS_MASK)
+#define UBIDI_GET_FLAG(props, shift) (((props)>>(shift))&1)
+
+enum {
+    UBIDI_ESC_MIRROR_DELTA=-4,
+    UBIDI_MIN_MIRROR_DELTA=-3,
+    UBIDI_MAX_MIRROR_DELTA=3
+};
+
+/* definitions for 32-bit mirror table entry -------------------------------- */
+
+enum {
+    /* the source Unicode code point takes 21 bits (20..0) */
+    UBIDI_MIRROR_INDEX_SHIFT=21,
+    UBIDI_MAX_MIRROR_INDEX=0x7ff
+};
+
+#define UBIDI_GET_MIRROR_CODE_POINT(m) (UChar32)((m)&0x1fffff)
+
+#define UBIDI_GET_MIRROR_INDEX(m) ((m)>>UBIDI_MIRROR_INDEX_SHIFT)
+
+U_CDECL_END
+
+#endif
diff --git a/source/common/ubidi_props_data.c b/source/common/ubidi_props_data.c
new file mode 100644
index 0000000..eeec97b
--- /dev/null
+++ b/source/common/ubidi_props_data.c
@@ -0,0 +1,688 @@
+/*
+ * Copyright (C) 1999-2010, International Business Machines
+ * Corporation and others.  All Rights Reserved.
+ *
+ * file name: ubidi_props_data.c
+ *
+ * machine-generated on: 2010-09-19
+ */
+
+static const UVersionInfo ubidi_props_dataVersion={6,0,0,0};
+
+static const int32_t ubidi_props_indexes[UBIDI_IX_TOP]={0x10,0x4fa0,0x4d98,0x1a,0x620,0x780,0,0,0,0,0,0,0,0,0,0x3800b2};
+
+static const uint16_t ubidi_props_trieIndex[9924]={
+0x311,0x319,0x321,0x329,0x341,0x349,0x351,0x359,0x331,0x339,0x331,0x339,0x331,0x339,0x331,0x339,
+0x331,0x339,0x331,0x339,0x35f,0x367,0x36f,0x377,0x37f,0x387,0x383,0x38b,0x393,0x39b,0x396,0x39e,
+0x331,0x339,0x331,0x339,0x3a6,0x3ae,0x331,0x339,0x331,0x339,0x331,0x339,0x3b4,0x3bc,0x3c4,0x3cc,
+0x3d4,0x3dc,0x3e4,0x3ec,0x3f2,0x3fa,0x402,0x40a,0x412,0x41a,0x420,0x428,0x430,0x438,0x440,0x448,
+0x44f,0x456,0x45a,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x462,0x464,0x46c,0x474,0x47c,0x47d,0x485,0x48d,
+0x495,0x47d,0x49d,0x4a2,0x495,0x47d,0x4aa,0x4b2,0x47c,0x4b7,0x4bf,0x474,0x4c4,0x331,0x4cc,0x4d0,
+0x331,0x4d7,0x4df,0x4e7,0x331,0x4ef,0x4f7,0x474,0x331,0x331,0x485,0x474,0x331,0x331,0x4fd,0x331,
+0x331,0x503,0x50b,0x331,0x331,0x50f,0x517,0x331,0x51b,0x522,0x331,0x52a,0x532,0x539,0x4c3,0x331,
+0x331,0x541,0x549,0x551,0x559,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x561,0x331,0x569,0x331,0x331,0x331,
+0x571,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x579,0x331,0x331,0x331,0x581,0x581,0x489,0x489,0x331,0x587,0x58f,0x569,
+0x597,0x331,0x331,0x331,0x331,0x47a,0x331,0x331,0x331,0x59f,0x5a7,0x331,0x331,0x331,0x5a9,0x5b1,
+0x5b9,0x331,0x5c0,0x5c8,0x331,0x331,0x331,0x331,0x5d0,0x5d3,0x4c4,0x5db,0x3a8,0x5e3,0x331,0x5ea,
+0x331,0x5ef,0x331,0x331,0x331,0x331,0x5f5,0x5fd,0x331,0x331,0x331,0x331,0x331,0x331,0x37f,0x605,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x60d,0x615,0x619,
+0x621,0x627,0x62e,0x636,0x63e,0x646,0x64d,0x53c,0x655,0x65d,0x665,0x331,0x66d,0x5b1,0x5b1,0x5b1,
+0x675,0x67d,0x685,0x68d,0x692,0x69a,0x6a2,0x6a8,0x6b0,0x6b8,0x331,0x6be,0x6c5,0x5b1,0x5b1,0x5b4,
+0x5b1,0x4ed,0x6cb,0x5b1,0x6d3,0x331,0x331,0x5ae,0x5b1,0x5b1,0x5b1,0x5b1,0x5b1,0x5b1,0x5b1,0x5b1,
+0x5b1,0x5b1,0x5b1,0x5b1,0x5b1,0x6db,0x5b1,0x5b1,0x6de,0x5b1,0x5b1,0x6e4,0x5b1,0x5b1,0x6ec,0x6f4,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x5b1,0x5b1,0x5b1,0x5b1,0x6fc,0x703,0x70b,0x713,
+0x71b,0x723,0x72b,0x732,0x73a,0x742,0x749,0x751,0x5b1,0x5b1,0x759,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x760,0x331,0x331,0x331,0x768,0x331,0x331,0x331,0x37f,
+0x770,0x778,0x331,0x331,0x780,0x5b1,0x5b1,0x5b4,0x5b1,0x5b1,0x5b1,0x5b1,0x5b1,0x5b1,0x787,0x78d,
+0x795,0x79d,0x331,0x331,0x7a5,0x571,0x331,0x358,0x331,0x331,0x331,0x331,0x331,0x331,0x5b1,0x767,
+0x366,0x331,0x7ad,0x7b5,0x331,0x7bd,0x7c5,0x331,0x331,0x331,0x331,0x7c9,0x331,0x331,0x5a9,0x357,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x5b1,0x5b1,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x7ad,0x5b1,0x4ed,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x7d0,0x331,0x331,0x7d5,0x331,0x331,0x331,0x51d,0x5b1,0x5a8,0x331,0x331,0x7dd,0x331,0x331,0x331,
+0x7e5,0x7ec,0x331,0x7f3,0x331,0x331,0x7fa,0x802,0x331,0x809,0x810,0x331,0x462,0x815,0x331,0x331,
+0x331,0x81d,0x825,0x331,0x331,0x829,0x47c,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x831,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x835,0x83d,0x841,0x430,0x430,0x430,0x430,0x430,
+0x430,0x430,0x430,0x430,0x430,0x430,0x430,0x430,0x430,0x845,0x430,0x430,0x430,0x430,0x84d,0x851,
+0x859,0x861,0x865,0x86d,0x430,0x430,0x430,0x871,0x879,0x321,0x881,0x889,0x331,0x331,0x331,0x891,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0xcc4,0xcc4,0xd04,0xd44,0xcc4,0xcc4,0xcc4,0xcc4,0xcc4,0xcc4,0xd7c,0xdbc,0xdfc,0xe0c,0xe4c,0xe58,
+0xcc4,0xcc4,0xe98,0xcc4,0xcc4,0xcc4,0xed0,0xf10,0xf50,0xf90,0xfc8,0x1008,0x1048,0x1080,0x10c0,0x1100,
+0xa40,0xa80,0xac0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xaf5,0x1a0,0x1a0,0xb35,0xb75,0xbb1,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xbb1,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xbb1,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xbb1,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xbb1,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xbb1,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xbb1,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xbb1,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xbb1,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xbb1,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xbb1,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xbb1,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xbb1,
+0xbf1,0xc01,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xbb1,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xbb1,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,
+0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0x1a0,0xbb1,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x899,0x331,0x5b1,0x5b1,0x8a1,0x331,0x331,0x475,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x8a9,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,
+0x8b1,0x8b5,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x8bd,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,
+0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,
+0x3c6,0x3c6,0x3c6,0x8c5,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,
+0x47c,0x7fc,0x8cd,0x6bc,0x3a8,0x8d5,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x8dd,0x8e5,0x8eb,0x331,0x331,0x5b1,0x5b1,0x8f3,0x331,0x331,0x331,0x331,0x331,0x5b1,0x5b1,0x8fb,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x901,0x331,0x908,0x331,0x904,
+0x331,0x90b,0x331,0x913,0x917,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,
+0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,
+0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,
+0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,
+0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x5b1,0x91f,0x5b1,0x5b1,0x5b4,0x924,0x92c,0x331,0x934,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x5b1,0x93c,0x5b1,
+0x942,0x5b4,0x5b1,0x94a,0x952,0x5b1,0x95a,0x962,0x5b1,0x6db,0x5b1,0x5b1,0x964,0x5b1,0x96c,0x7ad,
+0x7b3,0x331,0x331,0x331,0x6be,0x974,0x97c,0x984,0x331,0x5b1,0x5b1,0x6bc,0x331,0x5b1,0x5b1,0x5b1,
+0x5b4,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,0x331,
+0x988,0x990,0x998,0x998,0x998,0x9a0,0x9a0,0x9a0,0x9a0,0x37f,0x37f,0x37f,0x37f,0x37f,0x37f,0x37f,
+0x9a8,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,
+0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,
+0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,
+0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,0x9a0,
+0x9a0,0x310,0x310,0x310,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,8,7,8,
+9,7,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,
+7,7,7,8,9,0xa,0xa,4,4,4,0xa,0xa,0x300a,0xf00a,0xa,3,
+6,3,6,6,2,2,2,2,2,2,2,2,2,2,6,0xa,
+0x500a,0xa,0xd00a,0xa,0xa,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,0x500a,
+0xa,0xd00a,0xa,0xa,0xa,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,0x500a,
+0xa,0xd00a,0xa,0x12,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,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x12,0x12,0x12,0x12,0x12,7,0x12,0x12,0x12,0x12,0x12,0x12,
+0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,
+0x12,0x12,0x12,0x12,6,0xa,4,4,4,4,0xa,0xa,0xa,0xa,0,0x900a,
+0xa,0xb2,0xa,0xa,4,4,2,2,0xa,0,0xa,0xa,0xa,2,0,0x900a,
+0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0xa,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,0xa,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,0,0,0,0,
+0,0,0,0,0,0xa,0xa,0,0,0,0,0,0,0,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,
+0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,
+0xa,0xa,0,0,0,0,0,0,0,0,0xa,0,0,0,0,0,
+0xa,0xa,0,0xa,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,0,0,0,0,0,0,0,0,0,0,0xa,0,
+0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,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,0,0,0,0,0,0,0,0,0xa,0,0,0,0,0,
+1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,1,0xb1,
+1,0xb1,0xb1,1,0xb1,0xb1,1,0xb1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+5,5,5,5,0xd,0xd,0xa,0xa,0xd,4,4,0xd,6,0xd,0xa,0xa,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xd,0xd,0xd,0xd,0xd,
+0x4d,0xd,0x8d,0x8d,0x8d,0x8d,0x4d,0x8d,0x4d,0x8d,0x4d,0x4d,0x4d,0x4d,0x4d,0x8d,
+0x8d,0x8d,0x8d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,
+0x2d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x8d,0x4d,0x4d,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+5,5,5,5,5,5,5,5,5,5,4,5,5,0xd,0x4d,0x4d,
+0xb1,0x8d,0x8d,0x8d,0xd,0x8d,0x8d,0x8d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,
+0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,
+0x8d,0x8d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,
+0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,
+0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x8d,0x4d,0x4d,0x8d,0x8d,0x8d,0x8d,0x8d,
+0x8d,0x8d,0x8d,0x8d,0x4d,0x8d,0x4d,0x8d,0x4d,0x4d,0x8d,0x8d,0xd,0x8d,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,5,0xa,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xd,0xd,0xb1,
+0xb1,0xa,0xb1,0xb1,0xb1,0xb1,0x8d,0x8d,2,2,2,2,2,2,2,2,
+2,2,0x4d,0x4d,0x4d,0xd,0xd,0x4d,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,
+0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xa5,0x8d,0xb1,0x4d,0x4d,0x4d,0x8d,0x8d,0x8d,
+0x8d,0x8d,0x4d,0x4d,0x4d,0x4d,0x8d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,
+0x8d,0x4d,0x8d,0x4d,0x8d,0x4d,0x4d,0x8d,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xd,0xd,0x8d,0x4d,0x4d,
+0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x8d,0x8d,0x8d,0x4d,0x4d,0x4d,0x4d,
+0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x8d,0x8d,0x4d,0x4d,0x4d,
+0x4d,0x8d,0x4d,0x8d,0x8d,0x4d,0x4d,0x4d,0x8d,0x8d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,
+0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,
+0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,
+0xd,0xd,0xd,0xd,0xd,0xd,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,
+1,1,1,1,1,1,1,1,1,1,0x41,0x41,0x41,0x41,0x41,0x41,
+0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
+0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,1,1,0xa,0xa,0xa,0xa,0x21,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,0xb1,0xb1,0xb1,0xb1,1,0xb1,0xb1,0xb1,0xb1,0xb1,1,0xb1,0xb1,0xb1,
+1,0xb1,0xb1,0xb1,0xb1,0xb1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,0xb1,0xb1,0xb1,1,1,1,1,0xb1,0xb1,0xb1,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,0xb1,0,0xb1,0,0,0,
+0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0xb1,0,0,
+0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,
+0,0,0xb1,0xb1,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,0xb1,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,
+0xb1,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,
+0,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xb1,0xb1,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,4,
+0,0,0,0,0,0xb1,0xb1,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,0xb1,0xb1,0,0,0,0,0xb1,0xb1,0,0,0xb1,
+0xb1,0xb1,0,0,0,0xb1,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0xb1,0xb1,0,0,0,0xb1,0,0,
+0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,
+0xb1,0,0,0,0,0xb1,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0,0,0,0,
+0,0,0,0,0,0,0,0,0,4,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,0xb1,0,0,0xb1,0,0xb1,0xb1,0xb1,
+0xb1,0,0,0,0,0,0,0,0,0xb1,0,0,0,0,0,0,
+0,0,0xb1,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,
+0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,4,0xa,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,0xb1,0xb1,0xb1,0,0,0,
+0,0,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,
+0,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,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,0xb1,0,0,0xa0,0,0,0,0,
+0,0,0xa0,0,0,0,0,0,0xb1,0xb1,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0,
+0,0,0,0,0,0,0xb1,0xb1,0xb1,0,0xb1,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0,0,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,4,0,0,0,0,
+0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0,0,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0,0,0,0,0,0,0,
+0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,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,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0,0xb1,
+0,0xb1,0x300a,0xf00a,0x300a,0xf00a,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,
+0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0,
+0,0xb1,0xb1,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,0xb1,0xb1,0,0,
+0,0,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xb1,0,0,0xb1,0xb1,0,0,0,0,0,
+0,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0xb1,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,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,
+0,0,0,0,0xa,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,9,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,0x300a,
+0xf00a,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0xa0,0xa0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,
+0,0,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0,0,0,0,0,0,0,4,0,0xb1,0,0,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xb1,0xb1,0xb1,9,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0,
+0,0,0,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0xb1,0,
+0,0,0,0,0,0xb1,0xb1,0xb1,0,0,0,0,0xa,0,0,0,
+0xa,0xa,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,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,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,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,
+0xb1,0,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,
+0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,
+0xb1,0xb1,0xb1,0xb1,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,
+0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,
+0xb1,0xb1,0,0,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0,
+0xb1,0xb1,0,0,0,0xb1,0,0xb1,0xb1,0xb1,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0,0,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,
+0,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0xb1,0xb1,0xb1,0xb1,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,0xa,0,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0,
+0,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0xa,0xa,0,9,9,9,9,9,9,9,9,9,9,9,0xb2,
+0x412,0x432,0x8a0,0x8a1,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,9,7,0x8ab,0x8ae,0x8b0,0x8ac,0x8af,6,4,4,4,4,
+4,0xa,0xa,0xa,0xa,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,6,0x300a,0xf00a,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,9,0xb2,0xb2,0xb2,0xb2,0xb2,0x12,0x12,0x12,
+0x12,0x12,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,2,0,0,0,2,2,2,2,
+2,2,3,3,0xa,0x300a,0xf00a,0,2,2,2,2,2,2,2,2,
+2,2,3,3,0xa,0x300a,0xf00a,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,
+4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xa,0xa,0,0xa,0xa,0xa,0xa,0,0xa,0xa,0,0,
+0,0,0,0,0,0,0,0,0xa,0,0xa,0xa,0xa,0,0,0,
+0,0,0xa,0xa,0xa,0xa,0xa,0xa,0,0xa,0,0xa,0,0xa,0,0,
+0,0,4,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,
+0,0,0,0,0x100a,0xa,0xa,0xa,0xa,0,0,0,0,0,0xa,0xa,
+0xa,0xa,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0xa,0,0,
+0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0x100a,0x100a,0x100a,0x100a,0xa,0xa,0xa,0x700a,0x700a,0x700a,0xb00a,
+0xb00a,0xb00a,0xa,0xa,0xa,0x100a,3,4,0xa,0x900a,0x100a,0xa,0xa,0xa,0x100a,0x100a,
+0x100a,0x100a,0xa,0x100a,0x100a,0x100a,0x100a,0xa,0x100a,0xa,0x100a,0xa,0xa,0xa,0xa,0x100a,
+0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0xa,0xa,0xa,0xa,0xa,0x100a,0xa,0x100a,
+0x300a,0xf00a,0x100a,0x100a,0x100a,0x100a,0x100a,0x900a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,
+0x100a,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0x100a,0x100a,0xa,0x100a,0xa,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,
+0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,
+0x300a,0xf00a,0x300a,0xf00a,0x100a,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,
+0x900a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0xa,0xa,0x900a,0x100a,
+0x900a,0x900a,0x100a,0x900a,0x100a,0x100a,0x100a,0x100a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,
+0x100a,0xa,0xa,0xa,0xa,0xa,0x100a,0x100a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0x300a,0xf00a,0x300a,0xf00a,0x900a,0xa,0xa,0x300a,0xf00a,0xa,0xa,0xa,0xa,0x300a,0xf00a,
+0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,
+0x300a,0xf00a,0x900a,0x900a,0x900a,0x100a,0x900a,0x900a,0x100a,0x100a,0x900a,0x900a,0x900a,0x900a,0x900a,0x100a,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0x100a,0x100a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,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,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,0,0,0,0,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,
+0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0x100a,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0xa,0x300a,0xf00a,0xa,0,0x100a,0,0xa,0xa,
+0xa,0xa,0xa,0x100a,0x100a,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,0x100a,0x300a,0xf00a,0xa,
+0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x700a,0x300a,0xf00a,
+0xb00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0x100a,0x100a,0x100a,0x100a,0x100a,
+0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0x900a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0x100a,0x100a,
+0x300a,0xf00a,0xa,0xa,0xa,0x100a,0xa,0xa,0xa,0xa,0x100a,0x300a,0xf00a,0x300a,0xf00a,0xa,
+0x300a,0xf00a,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0x100a,0xa,0xa,0xa,0xa,0x100a,0xa,0x100a,
+0x100a,0x100a,0xa,0xa,0x100a,0x100a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0x100a,0x900a,0x100a,0x100a,0x300a,0xf00a,0xa,0xa,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,
+0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0x100a,0xa,0x100a,0x100a,0x100a,0x100a,0xa,0xa,
+0x100a,0xa,0x100a,0xa,0xa,0x100a,0xa,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,
+0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0x100a,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0x100a,0x100a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0xa,0xa,
+0xa,0xa,0x100a,0x100a,0x100a,0x100a,0xa,0x100a,0x100a,0xa,0xa,0x100a,0x100a,0xa,0xa,0xa,
+0xa,0x300a,0xf00a,0x100a,0x100a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x100a,0x100a,0x100a,
+0x100a,0x100a,0x100a,0x300a,0xf00a,0x100a,0x100a,0x100a,0x100a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,
+0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x100a,0x100a,0x100a,0x100a,0x300a,0xf00a,0x100a,0xa,0xa,0x300a,0xf00a,
+0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0xa,0x300a,0xf00a,0x100a,0x100a,0x300a,0xf00a,0x100a,0x100a,0x100a,
+0x100a,0x100a,0x100a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x100a,0x100a,0x100a,0x100a,0x100a,
+0x100a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,
+0x100a,0xa,0x900a,0xa,0xa,0xa,0x100a,0x900a,0x900a,0x900a,0x100a,0xa,0xa,0xa,0xa,0xa,
+0x300a,0xf00a,0x100a,0xa,0xa,0xa,0xa,0x100a,0xa,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0x100a,
+0xa,0x100a,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,
+0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0xb1,
+0xb1,0xb1,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+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,0xb1,
+0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0xa,0x300a,0xf00a,0xa,0x300a,0xf00a,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0x300a,0xf00a,0xa,0xa,
+0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0,0,0,0,9,0xa,0xa,0xa,0xa,0,0,0,0x300a,0xf00a,0x300a,0xf00a,
+0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0xa,0xa,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,0x300a,0xf00a,
+0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xa,0,0,0,0,0,0xa,0xa,0,0,0,0,
+0,0xa,0xa,0xa,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,0xb1,0xb1,0xa,
+0xa,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,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,
+0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0,
+0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xb1,0xb1,0xb1,0xb1,0xa,0,0,0,0,0,0,0,0,
+0xb1,0xb1,0xa,0xa,0,0,0,0,0,0,0,0,0xa,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,0xb1,0,0,0,0xb1,0,0,0,0,0xb1,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0xb1,0xb1,0,0xa,0xa,0xa,0xa,0,0,0,0,
+0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0xb1,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,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0,0,
+0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0,0,0xb1,0xb1,0,0,0,0,0,
+0,0,0,0,0,0,0,0xb1,0,0,0,0,0,0,0,0,
+0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xb1,0,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0,0,0,
+0,0,0xb1,0xb1,0,0,0,0,0,0xb1,0,0,0xb1,0,0,0,
+0,0xb1,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,1,0xb1,1,1,1,1,1,1,1,1,1,1,3,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,
+0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,
+0xd,0xd,0xa,0xa,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,
+0xd,0xd,0xd,0xd,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,
+0x12,0x12,0x12,0x12,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,
+0xd,0xa,0xd,0xd,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,
+0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,
+0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,6,0xa,6,0,0xa,6,0xa,0xa,0xa,0x300a,0xf00a,0x300a,
+0xf00a,0x300a,0xf00a,4,0xa,0xa,3,3,0x300a,0xf00a,0xa,0,0xa,4,4,0xa,
+0,0,0,0,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,
+0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,
+0xd,0xd,0xd,0xb2,0,0xa,0xa,4,4,4,0xa,0xa,0x300a,0xf00a,0xa,3,
+6,3,6,6,2,2,2,2,2,2,2,2,2,2,6,0xa,
+0x500a,0xa,0xd00a,0xa,0xa,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,0x500a,
+0xa,0xd00a,0xa,0x300a,0xf00a,0xa,0x300a,0xf00a,0xa,0xa,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,4,4,0xa,0xa,0xa,4,4,0,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0xaa,0xaa,0xaa,
+0xa,0xa,0x12,0x12,0,0xa,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,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,
+0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,0xa,1,0xb1,0xb1,0xb1,1,0xb1,0xb1,1,1,1,1,1,
+0xb1,0xb1,0xb1,0xb1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,0xb1,0xb1,0xb1,1,
+1,1,1,0xb1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,
+0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0,
+0,0xa0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0,0,
+0,0,0,0,0,0,0,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0xb1,0xb1,
+0xb1,0xa,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,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,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,0x100a,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x100a,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,0x100a,
+0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,
+0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,
+0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0xa,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0xa,0xa,0xa,0xa,0xa,0xa,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0,0,0,0xa,0xa,0xa,0xa,0xa,0,0xa,0xa,
+0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0xa,0,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0xa,0xa,0xa,0xa,0,0,0,
+0xa,0xa,0xa,0xa,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,
+0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0,0xa,0xa,0xa,0,0xa,0,0xa,0,0xa,0,0xa,0xa,0xa,0,
+0xa,0xa,0xa,0xa,0xa,0xa,0,0,0xa,0xa,0xa,0xa,0,0xa,0,0,
+0xa,0xa,0xa,0xa,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+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,0x12,0x12,
+0x12,0xb2,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,
+0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,
+0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,
+0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,
+0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,
+0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,
+0,0,0,0
+};
+
+static const uint32_t ubidi_props_mirrors[26]={
+0x2000ab,0xbb,0x2a02215,0x1202243,0x2802298,0x2c022a6,0x30022a8,0x2e022a9,0x32022ab,0x6022cd,0x1e022f2,0x20022f3,0x22022f4,0x24022f6,0x26022f7,0x14022fa,
+0x16022fb,0x18022fc,0x1a022fd,0x1c022fe,0x8029b8,0x4029f5,0xa02ade,0xe02ae3,0xc02ae4,0x1002ae5
+};
+
+static const uint8_t ubidi_props_jgArray[352]={
+0x2d,0,3,3,0x2c,3,0x2d,3,4,0x2a,4,4,0xd,0xd,0xd,6,
+6,0x1f,0x1f,0x23,0x23,0x21,0x21,0x28,0x28,1,1,0xb,0xb,0x37,0x37,0x37,
+0,9,0x1d,0x13,0x16,0x18,0x1a,0x10,0x2c,0x2d,0x2d,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,4,0x1d,
+0,3,3,3,0,3,0x2c,0x2c,0x2d,4,4,4,4,4,4,4,
+4,0xd,0xd,0xd,0xd,0xd,0xd,0xd,6,6,6,6,6,6,6,6,
+6,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x23,0x23,0x23,0x21,0x21,0x28,
+1,9,9,9,9,9,9,0x1d,0x1d,0xb,0x26,0xb,0x13,0x13,0x13,0xb,
+0xb,0xb,0xb,0xb,0xb,0x16,0x16,0x16,0x16,0x1a,0x1a,0x1a,0x1a,0x38,0x15,0xd,
+0x2a,0x11,0x11,0xe,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x37,0x2f,0x37,0x2c,
+0x2d,0x2d,0x2e,0x2e,0,0x2a,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0x1f,
+0,0,0,0,0,0,0,0,0,0,0x23,0x21,1,0,0,0x15,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+2,0,5,0xc,0xc,7,7,0xf,0x27,0x32,0x12,0x2b,0x2b,0x30,0x31,0x14,
+0x17,0x19,0x1b,0x24,0xa,8,0x1c,0x20,0x22,0x1e,7,0x25,0x29,5,0xc,7,
+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,0x35,0x34,0x33,
+4,4,4,4,4,4,4,0xd,0xd,6,6,0x1f,0x23,1,1,1,
+9,9,0xb,0xb,0xb,0x18,0x18,0x1a,0x1a,0x1a,0x16,0x1f,0x1f,0x23,0xd,0xd,
+0x23,0x1f,0xd,3,3,0x37,0x37,0x2d,0x2c,0x2c,0x36,0x36,0xd,0x23,0x23,0x13
+};
+
+static const UBiDiProps ubidi_props_singleton={
+  NULL,
+  ubidi_props_indexes,
+  ubidi_props_mirrors,
+  ubidi_props_jgArray,
+  {
+    ubidi_props_trieIndex,
+    ubidi_props_trieIndex+3140,
+    NULL,
+    3140,
+    6784,
+    0x1a0,
+    0xcc4,
+    0x0,
+    0x0,
+    0x110000,
+    0x26c0,
+    NULL, 0, FALSE, FALSE, 0, NULL
+  },
+  { 2,0,0,0 }
+};
diff --git a/source/common/ubidiimp.h b/source/common/ubidiimp.h
new file mode 100644
index 0000000..1f1dcaa
--- /dev/null
+++ b/source/common/ubidiimp.h
@@ -0,0 +1,385 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2007, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  ubidiimp.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999aug06
+*   created by: Markus W. Scherer, updated by Matitiahu Allouche
+*/
+
+#ifndef UBIDIIMP_H
+#define UBIDIIMP_H
+
+/* set import/export definitions */
+#ifdef U_COMMON_IMPLEMENTATION
+
+#include "unicode/utypes.h"
+#include "unicode/uchar.h"
+#include "ubidi_props.h"
+
+/* miscellaneous definitions ---------------------------------------------- */
+
+typedef uint8_t DirProp;
+typedef uint32_t Flags;
+
+/*  Comparing the description of the BiDi algorithm with this implementation
+    is easier with the same names for the BiDi types in the code as there.
+    See UCharDirection in uchar.h .
+*/
+enum {
+    L=  U_LEFT_TO_RIGHT,
+    R=  U_RIGHT_TO_LEFT,
+    EN= U_EUROPEAN_NUMBER,
+    ES= U_EUROPEAN_NUMBER_SEPARATOR,
+    ET= U_EUROPEAN_NUMBER_TERMINATOR,
+    AN= U_ARABIC_NUMBER,
+    CS= U_COMMON_NUMBER_SEPARATOR,
+    B=  U_BLOCK_SEPARATOR,
+    S=  U_SEGMENT_SEPARATOR,
+    WS= U_WHITE_SPACE_NEUTRAL,
+    ON= U_OTHER_NEUTRAL,
+    LRE=U_LEFT_TO_RIGHT_EMBEDDING,
+    LRO=U_LEFT_TO_RIGHT_OVERRIDE,
+    AL= U_RIGHT_TO_LEFT_ARABIC,
+    RLE=U_RIGHT_TO_LEFT_EMBEDDING,
+    RLO=U_RIGHT_TO_LEFT_OVERRIDE,
+    PDF=U_POP_DIRECTIONAL_FORMAT,
+    NSM=U_DIR_NON_SPACING_MARK,
+    BN= U_BOUNDARY_NEUTRAL,
+    dirPropCount
+};
+
+/*
+ * Sometimes, bit values are more appropriate
+ * to deal with directionality properties.
+ * Abbreviations in these macro names refer to names
+ * used in the BiDi algorithm.
+ */
+#define DIRPROP_FLAG(dir) (1UL<<(dir))
+
+/* special flag for multiple runs from explicit embedding codes */
+#define DIRPROP_FLAG_MULTI_RUNS (1UL<<31)
+
+/* are there any characters that are LTR or RTL? */
+#define MASK_LTR (DIRPROP_FLAG(L)|DIRPROP_FLAG(EN)|DIRPROP_FLAG(AN)|DIRPROP_FLAG(LRE)|DIRPROP_FLAG(LRO))
+#define MASK_RTL (DIRPROP_FLAG(R)|DIRPROP_FLAG(AL)|DIRPROP_FLAG(RLE)|DIRPROP_FLAG(RLO))
+#define MASK_R_AL (DIRPROP_FLAG(R)|DIRPROP_FLAG(AL))
+
+/* explicit embedding codes */
+#define MASK_LRX (DIRPROP_FLAG(LRE)|DIRPROP_FLAG(LRO))
+#define MASK_RLX (DIRPROP_FLAG(RLE)|DIRPROP_FLAG(RLO))
+#define MASK_OVERRIDE (DIRPROP_FLAG(LRO)|DIRPROP_FLAG(RLO))
+
+#define MASK_EXPLICIT (MASK_LRX|MASK_RLX|DIRPROP_FLAG(PDF))
+#define MASK_BN_EXPLICIT (DIRPROP_FLAG(BN)|MASK_EXPLICIT)
+
+/* paragraph and segment separators */
+#define MASK_B_S (DIRPROP_FLAG(B)|DIRPROP_FLAG(S))
+
+/* all types that are counted as White Space or Neutral in some steps */
+#define MASK_WS (MASK_B_S|DIRPROP_FLAG(WS)|MASK_BN_EXPLICIT)
+#define MASK_N (DIRPROP_FLAG(ON)|MASK_WS)
+
+/* all types that are included in a sequence of European Terminators for (W5) */
+#define MASK_ET_NSM_BN (DIRPROP_FLAG(ET)|DIRPROP_FLAG(NSM)|MASK_BN_EXPLICIT)
+
+/* types that are neutrals or could becomes neutrals in (Wn) */
+#define MASK_POSSIBLE_N (DIRPROP_FLAG(CS)|DIRPROP_FLAG(ES)|DIRPROP_FLAG(ET)|MASK_N)
+
+/*
+ * These types may be changed to "e",
+ * the embedding type (L or R) of the run,
+ * in the BiDi algorithm (N2)
+ */
+#define MASK_EMBEDDING (DIRPROP_FLAG(NSM)|MASK_POSSIBLE_N)
+
+/* the dirProp's L and R are defined to 0 and 1 values in UCharDirection */
+#define GET_LR_FROM_LEVEL(level) ((DirProp)((level)&1))
+
+#define IS_DEFAULT_LEVEL(level) ((level)>=0xfe)
+
+/*
+ * The following bit is ORed to the property of characters in paragraphs
+ * with contextual RTL direction when paraLevel is contextual.
+ */
+#define CONTEXT_RTL 0x80
+#define NO_CONTEXT_RTL(dir) ((dir)&~CONTEXT_RTL)
+/*
+ * The following is a variant of DIRPROP_FLAG which ignores the CONTEXT_RTL bit.
+ */
+#define DIRPROP_FLAG_NC(dir) (1UL<<(NO_CONTEXT_RTL(dir)))
+
+#define GET_PARALEVEL(ubidi, index) \
+            (UBiDiLevel)((ubidi)->defaultParaLevel ? (ubidi)->dirProps[index]>>7 \
+                                                   : (ubidi)->paraLevel)
+
+/* Paragraph type for multiple paragraph support ---------------------------- */
+typedef int32_t Para;
+
+#define CR  0x000D
+#define LF  0x000A
+
+/* Run structure for reordering --------------------------------------------- */
+enum {
+    LRM_BEFORE=1,
+    LRM_AFTER=2,
+    RLM_BEFORE=4,
+    RLM_AFTER=8
+};
+
+typedef struct Run {
+    int32_t logicalStart,   /* first character of the run; b31 indicates even/odd level */
+            visualLimit,    /* last visual position of the run +1 */
+            insertRemove;   /* if >0, flags for inserting LRM/RLM before/after run,
+                               if <0, count of bidi controls within run            */
+} Run;
+
+/* in a Run, logicalStart will get this bit set if the run level is odd */
+#define INDEX_ODD_BIT (1UL<<31)
+
+#define MAKE_INDEX_ODD_PAIR(index, level) ((index)|((int32_t)(level)<<31))
+#define ADD_ODD_BIT_FROM_LEVEL(x, level)  ((x)|=((int32_t)(level)<<31))
+#define REMOVE_ODD_BIT(x)                 ((x)&=~INDEX_ODD_BIT)
+
+#define GET_INDEX(x)   ((x)&~INDEX_ODD_BIT)
+#define GET_ODD_BIT(x) ((uint32_t)(x)>>31)
+#define IS_ODD_RUN(x)  ((UBool)(((x)&INDEX_ODD_BIT)!=0))
+#define IS_EVEN_RUN(x) ((UBool)(((x)&INDEX_ODD_BIT)==0))
+
+U_CFUNC UBool
+ubidi_getRuns(UBiDi *pBiDi, UErrorCode *pErrorCode);
+
+/** BiDi control code points */
+enum {
+    ZWNJ_CHAR=0x200c,
+    ZWJ_CHAR,
+    LRM_CHAR,
+    RLM_CHAR,
+    LRE_CHAR=0x202a,
+    RLE_CHAR,
+    PDF_CHAR,
+    LRO_CHAR,
+    RLO_CHAR
+};
+
+#define IS_BIDI_CONTROL_CHAR(c) (((uint32_t)(c)&0xfffffffc)==ZWNJ_CHAR || (uint32_t)((c)-LRE_CHAR)<5)
+
+/* InsertPoints structure for noting where to put BiDi marks ---------------- */
+
+typedef struct Point {
+    int32_t pos;            /* position in text */
+    int32_t flag;           /* flag for LRM/RLM, before/after */
+} Point;
+
+typedef struct InsertPoints {
+    int32_t capacity;       /* number of points allocated */
+    int32_t size;           /* number of points used */
+    int32_t confirmed;      /* number of points confirmed */
+    UErrorCode errorCode;   /* for eventual memory shortage */
+    Point *points;          /* pointer to array of points */
+} InsertPoints;
+
+
+/* UBiDi structure ----------------------------------------------------------- */
+
+struct UBiDi {
+    /* pointer to parent paragraph object (pointer to self if this object is
+     * a paragraph object); set to NULL in a newly opened object; set to a
+     * real value after a successful execution of ubidi_setPara or ubidi_setLine
+     */
+    const UBiDi * pParaBiDi;
+
+    const UBiDiProps *bdp;
+
+    /* alias pointer to the current text */
+    const UChar *text;
+
+    /* length of the current text */
+    int32_t originalLength;
+
+    /* if the UBIDI_OPTION_STREAMING option is set, this is the length
+     * of text actually processed by ubidi_setPara, which may be shorter than
+     * the original length.
+     * Otherwise, it is identical to the original length.
+     */
+    int32_t length;
+
+    /* if the UBIDI_OPTION_REMOVE_CONTROLS option is set, and/or
+     * marks are allowed to be inserted in one of the reordering mode, the
+     * length of the result string may be different from the processed length.
+     */
+    int32_t resultLength;
+
+    /* memory sizes in bytes */
+    int32_t dirPropsSize, levelsSize, parasSize, runsSize;
+
+    /* allocated memory */
+    DirProp *dirPropsMemory;
+    UBiDiLevel *levelsMemory;
+    Para *parasMemory;
+    Run *runsMemory;
+
+    /* indicators for whether memory may be allocated after ubidi_open() */
+    UBool mayAllocateText, mayAllocateRuns;
+
+    /* arrays with one value per text-character */
+    const DirProp *dirProps;
+    UBiDiLevel *levels;
+
+    /* are we performing an approximation of the "inverse BiDi" algorithm? */
+    UBool isInverse;
+
+    /* are we using the basic algorithm or its variation? */
+    UBiDiReorderingMode reorderingMode;
+
+    /* UBIDI_REORDER_xxx values must be ordered so that all the regular
+     * logical to visual modes come first, and all inverse BiDi modes
+     * come last.
+     */
+    #define UBIDI_REORDER_LAST_LOGICAL_TO_VISUAL    UBIDI_REORDER_NUMBERS_SPECIAL
+
+    /* bitmask for reordering options */
+    uint32_t reorderingOptions;
+
+    /* must block separators receive level 0? */
+    UBool orderParagraphsLTR;
+
+    /* the paragraph level */
+    UBiDiLevel paraLevel;
+    /* original paraLevel when contextual */
+    /* must be one of UBIDI_DEFAULT_xxx or 0 if not contextual */
+    UBiDiLevel defaultParaLevel;
+
+    /* the following is set in ubidi_setPara, used in processPropertySeq */
+    const struct ImpTabPair * pImpTabPair;  /* pointer to levels state table pair */
+
+    /* the overall paragraph or line directionality - see UBiDiDirection */
+    UBiDiDirection direction;
+
+    /* flags is a bit set for which directional properties are in the text */
+    Flags flags;
+
+    /* lastArabicPos is index to the last AL in the text, -1 if none */
+    int32_t lastArabicPos;
+
+    /* characters after trailingWSStart are WS and are */
+    /* implicitly at the paraLevel (rule (L1)) - levels may not reflect that */
+    int32_t trailingWSStart;
+
+    /* fields for paragraph handling */
+    int32_t paraCount;                  /* set in getDirProps() */
+    Para *paras;                        /* limits of paragraphs, filled in
+                            ResolveExplicitLevels() or CheckExplicitLevels() */
+
+    /* for single paragraph text, we only need a tiny array of paras (no malloc()) */
+    Para simpleParas[1];
+
+    /* fields for line reordering */
+    int32_t runCount;     /* ==-1: runs not set up yet */
+    Run *runs;
+
+    /* for non-mixed text, we only need a tiny array of runs (no malloc()) */
+    Run simpleRuns[1];
+
+    /* for inverse Bidi with insertion of directional marks */
+    InsertPoints insertPoints;
+
+    /* for option UBIDI_OPTION_REMOVE_CONTROLS */
+    int32_t controlCount;
+
+    /* for Bidi class callback */
+    UBiDiClassCallback *fnClassCallback;    /* action pointer */
+    const void *coClassCallback;            /* context pointer */
+};
+
+#define IS_VALID_PARA(x) ((x) && ((x)->pParaBiDi==(x)))
+#define IS_VALID_PARA_OR_LINE(x) ((x) && ((x)->pParaBiDi==(x) || (((x)->pParaBiDi) && (x)->pParaBiDi->pParaBiDi==(x)->pParaBiDi)))
+
+typedef union {
+    DirProp *dirPropsMemory;
+    UBiDiLevel *levelsMemory;
+    Para *parasMemory;
+    Run *runsMemory;
+} BidiMemoryForAllocation;
+
+/* Macros for initial checks at function entry */
+#define RETURN_IF_NULL_OR_FAILING_ERRCODE(pErrcode, retvalue)   \
+        if((pErrcode)==NULL || U_FAILURE(*pErrcode)) return retvalue
+#define RETURN_IF_NOT_VALID_PARA(bidi, errcode, retvalue)   \
+        if(!IS_VALID_PARA(bidi)) {  \
+            errcode=U_INVALID_STATE_ERROR;  \
+            return retvalue;                \
+        }
+#define RETURN_IF_NOT_VALID_PARA_OR_LINE(bidi, errcode, retvalue)   \
+        if(!IS_VALID_PARA_OR_LINE(bidi)) {  \
+            errcode=U_INVALID_STATE_ERROR;  \
+            return retvalue;                \
+        }
+#define RETURN_IF_BAD_RANGE(arg, start, limit, errcode, retvalue)   \
+        if((arg)<(start) || (arg)>=(limit)) {       \
+            (errcode)=U_ILLEGAL_ARGUMENT_ERROR;     \
+            return retvalue;                        \
+        }
+
+#define RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrcode)   \
+        if((pErrcode)==NULL || U_FAILURE(*pErrcode)) return
+#define RETURN_VOID_IF_NOT_VALID_PARA(bidi, errcode)   \
+        if(!IS_VALID_PARA(bidi)) {  \
+            errcode=U_INVALID_STATE_ERROR;  \
+            return;                \
+        }
+#define RETURN_VOID_IF_NOT_VALID_PARA_OR_LINE(bidi, errcode)   \
+        if(!IS_VALID_PARA_OR_LINE(bidi)) {  \
+            errcode=U_INVALID_STATE_ERROR;  \
+            return;                \
+        }
+#define RETURN_VOID_IF_BAD_RANGE(arg, start, limit, errcode)   \
+        if((arg)<(start) || (arg)>=(limit)) {       \
+            (errcode)=U_ILLEGAL_ARGUMENT_ERROR;     \
+            return;                        \
+        }
+
+/* helper function to (re)allocate memory if allowed */
+U_CFUNC UBool
+ubidi_getMemory(BidiMemoryForAllocation *pMemory, int32_t *pSize, UBool mayAllocate, int32_t sizeNeeded);
+
+/* helper macros for each allocated array in UBiDi */
+#define getDirPropsMemory(pBiDi, length) \
+        ubidi_getMemory((BidiMemoryForAllocation *)&(pBiDi)->dirPropsMemory, &(pBiDi)->dirPropsSize, \
+                        (pBiDi)->mayAllocateText, (length))
+
+#define getLevelsMemory(pBiDi, length) \
+        ubidi_getMemory((BidiMemoryForAllocation *)&(pBiDi)->levelsMemory, &(pBiDi)->levelsSize, \
+                        (pBiDi)->mayAllocateText, (length))
+
+#define getRunsMemory(pBiDi, length) \
+        ubidi_getMemory((BidiMemoryForAllocation *)&(pBiDi)->runsMemory, &(pBiDi)->runsSize, \
+                        (pBiDi)->mayAllocateRuns, (length)*sizeof(Run))
+
+/* additional macros used by ubidi_open() - always allow allocation */
+#define getInitialDirPropsMemory(pBiDi, length) \
+        ubidi_getMemory((BidiMemoryForAllocation *)&(pBiDi)->dirPropsMemory, &(pBiDi)->dirPropsSize, \
+                        TRUE, (length))
+
+#define getInitialLevelsMemory(pBiDi, length) \
+        ubidi_getMemory((BidiMemoryForAllocation *)&(pBiDi)->levelsMemory, &(pBiDi)->levelsSize, \
+                        TRUE, (length))
+
+#define getInitialParasMemory(pBiDi, length) \
+        ubidi_getMemory((BidiMemoryForAllocation *)&(pBiDi)->parasMemory, &(pBiDi)->parasSize, \
+                        TRUE, (length)*sizeof(Para))
+
+#define getInitialRunsMemory(pBiDi, length) \
+        ubidi_getMemory((BidiMemoryForAllocation *)&(pBiDi)->runsMemory, &(pBiDi)->runsSize, \
+                        TRUE, (length)*sizeof(Run))
+
+#endif
+
+#endif
diff --git a/source/common/ubidiln.c b/source/common/ubidiln.c
new file mode 100644
index 0000000..66bcefc
--- /dev/null
+++ b/source/common/ubidiln.c
@@ -0,0 +1,1347 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  ubidiln.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999aug06
+*   created by: Markus W. Scherer, updated by Matitiahu Allouche
+*/
+
+#include "cmemory.h"
+#include "unicode/utypes.h"
+#include "unicode/ustring.h"
+#include "unicode/uchar.h"
+#include "unicode/ubidi.h"
+#include "ubidiimp.h"
+#include "uassert.h"
+
+/*
+ * General remarks about the functions in this file:
+ *
+ * These functions deal with the aspects of potentially mixed-directional
+ * text in a single paragraph or in a line of a single paragraph
+ * which has already been processed according to
+ * the Unicode 3.0 BiDi algorithm as defined in
+ * http://www.unicode.org/unicode/reports/tr9/ , version 13,
+ * also described in The Unicode Standard, Version 4.0.1 .
+ *
+ * This means that there is a UBiDi object with a levels
+ * and a dirProps array.
+ * paraLevel and direction are also set.
+ * Only if the length of the text is zero, then levels==dirProps==NULL.
+ *
+ * The overall directionality of the paragraph
+ * or line is used to bypass the reordering steps if possible.
+ * Even purely RTL text does not need reordering there because
+ * the ubidi_getLogical/VisualIndex() functions can compute the
+ * index on the fly in such a case.
+ *
+ * The implementation of the access to same-level-runs and of the reordering
+ * do attempt to provide better performance and less memory usage compared to
+ * a direct implementation of especially rule (L2) with an array of
+ * one (32-bit) integer per text character.
+ *
+ * Here, the levels array is scanned as soon as necessary, and a vector of
+ * same-level-runs is created. Reordering then is done on this vector.
+ * For each run of text positions that were resolved to the same level,
+ * only 8 bytes are stored: the first text position of the run and the visual
+ * position behind the run after reordering.
+ * One sign bit is used to hold the directionality of the run.
+ * This is inefficient if there are many very short runs. If the average run
+ * length is <2, then this uses more memory.
+ *
+ * In a further attempt to save memory, the levels array is never changed
+ * after all the resolution rules (Xn, Wn, Nn, In).
+ * Many functions have to consider the field trailingWSStart:
+ * if it is less than length, then there is an implicit trailing run
+ * at the paraLevel,
+ * which is not reflected in the levels array.
+ * This allows a line UBiDi object to use the same levels array as
+ * its paragraph parent object.
+ *
+ * When a UBiDi object is created for a line of a paragraph, then the
+ * paragraph's levels and dirProps arrays are reused by way of setting
+ * a pointer into them, not by copying. This again saves memory and forbids to
+ * change the now shared levels for (L1).
+ */
+
+/* handle trailing WS (L1) -------------------------------------------------- */
+
+/*
+ * setTrailingWSStart() sets the start index for a trailing
+ * run of WS in the line. This is necessary because we do not modify
+ * the paragraph's levels array that we just point into.
+ * Using trailingWSStart is another form of performing (L1).
+ *
+ * To make subsequent operations easier, we also include the run
+ * before the WS if it is at the paraLevel - we merge the two here.
+ *
+ * This function is called only from ubidi_setLine(), so pBiDi->paraLevel is
+ * set correctly for the line even when contextual multiple paragraphs.
+ */
+static void
+setTrailingWSStart(UBiDi *pBiDi) {
+    /* pBiDi->direction!=UBIDI_MIXED */
+
+    const DirProp *dirProps=pBiDi->dirProps;
+    UBiDiLevel *levels=pBiDi->levels;
+    int32_t start=pBiDi->length;
+    UBiDiLevel paraLevel=pBiDi->paraLevel;
+
+    /* If the line is terminated by a block separator, all preceding WS etc...
+       are already set to paragraph level.
+       Setting trailingWSStart to pBidi->length will avoid changing the
+       level of B chars from 0 to paraLevel in ubidi_getLevels when
+       orderParagraphsLTR==TRUE.
+     */
+    if(NO_CONTEXT_RTL(dirProps[start-1])==B) {
+        pBiDi->trailingWSStart=start;   /* currently == pBiDi->length */
+        return;
+    }
+    /* go backwards across all WS, BN, explicit codes */
+    while(start>0 && DIRPROP_FLAG_NC(dirProps[start-1])&MASK_WS) {
+        --start;
+    }
+
+    /* if the WS run can be merged with the previous run then do so here */
+    while(start>0 && levels[start-1]==paraLevel) {
+        --start;
+    }
+
+    pBiDi->trailingWSStart=start;
+}
+
+/* ubidi_setLine ------------------------------------------------------------ */
+
+U_CAPI void U_EXPORT2
+ubidi_setLine(const UBiDi *pParaBiDi,
+              int32_t start, int32_t limit,
+              UBiDi *pLineBiDi,
+              UErrorCode *pErrorCode) {
+    int32_t length;
+
+    /* check the argument values */
+    RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode);
+    RETURN_VOID_IF_NOT_VALID_PARA(pParaBiDi, *pErrorCode);
+    RETURN_VOID_IF_BAD_RANGE(start, 0, limit, *pErrorCode);
+    RETURN_VOID_IF_BAD_RANGE(limit, 0, pParaBiDi->length+1, *pErrorCode);
+    if(pLineBiDi==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    if(ubidi_getParagraph(pParaBiDi, start, NULL, NULL, NULL, pErrorCode) !=
+       ubidi_getParagraph(pParaBiDi, limit-1, NULL, NULL, NULL, pErrorCode)) {
+        /* the line crosses a paragraph boundary */
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    /* set the values in pLineBiDi from its pParaBiDi parent */
+    pLineBiDi->pParaBiDi=NULL;          /* mark unfinished setLine */
+    pLineBiDi->text=pParaBiDi->text+start;
+    length=pLineBiDi->length=limit-start;
+    pLineBiDi->resultLength=pLineBiDi->originalLength=length;
+    pLineBiDi->paraLevel=GET_PARALEVEL(pParaBiDi, start);
+    pLineBiDi->paraCount=pParaBiDi->paraCount;
+    pLineBiDi->runs=NULL;
+    pLineBiDi->flags=0;
+    pLineBiDi->reorderingMode=pParaBiDi->reorderingMode;
+    pLineBiDi->reorderingOptions=pParaBiDi->reorderingOptions;
+    pLineBiDi->controlCount=0;
+    if(pParaBiDi->controlCount>0) {
+        int32_t j;
+        for(j=start; j<limit; j++) {
+            if(IS_BIDI_CONTROL_CHAR(pParaBiDi->text[j])) {
+                pLineBiDi->controlCount++;
+            }
+        }
+        pLineBiDi->resultLength-=pLineBiDi->controlCount;
+    }
+
+    pLineBiDi->dirProps=pParaBiDi->dirProps+start;
+    pLineBiDi->levels=pParaBiDi->levels+start;
+    pLineBiDi->runCount=-1;
+
+    if(pParaBiDi->direction!=UBIDI_MIXED) {
+        /* the parent is already trivial */
+        pLineBiDi->direction=pParaBiDi->direction;
+
+        /*
+         * The parent's levels are all either
+         * implicitly or explicitly ==paraLevel;
+         * do the same here.
+         */
+        if(pParaBiDi->trailingWSStart<=start) {
+            pLineBiDi->trailingWSStart=0;
+        } else if(pParaBiDi->trailingWSStart<limit) {
+            pLineBiDi->trailingWSStart=pParaBiDi->trailingWSStart-start;
+        } else {
+            pLineBiDi->trailingWSStart=length;
+        }
+    } else {
+        const UBiDiLevel *levels=pLineBiDi->levels;
+        int32_t i, trailingWSStart;
+        UBiDiLevel level;
+
+        setTrailingWSStart(pLineBiDi);
+        trailingWSStart=pLineBiDi->trailingWSStart;
+
+        /* recalculate pLineBiDi->direction */
+        if(trailingWSStart==0) {
+            /* all levels are at paraLevel */
+            pLineBiDi->direction=(UBiDiDirection)(pLineBiDi->paraLevel&1);
+        } else {
+            /* get the level of the first character */
+            level=(UBiDiLevel)(levels[0]&1);
+
+            /* if there is anything of a different level, then the line is mixed */
+            if(trailingWSStart<length && (pLineBiDi->paraLevel&1)!=level) {
+                /* the trailing WS is at paraLevel, which differs from levels[0] */
+                pLineBiDi->direction=UBIDI_MIXED;
+            } else {
+                /* see if levels[1..trailingWSStart-1] have the same direction as levels[0] and paraLevel */
+                i=1;
+                for(;;) {
+                    if(i==trailingWSStart) {
+                        /* the direction values match those in level */
+                        pLineBiDi->direction=(UBiDiDirection)level;
+                        break;
+                    } else if((levels[i]&1)!=level) {
+                        pLineBiDi->direction=UBIDI_MIXED;
+                        break;
+                    }
+                    ++i;
+                }
+            }
+        }
+
+        switch(pLineBiDi->direction) {
+        case UBIDI_LTR:
+            /* make sure paraLevel is even */
+            pLineBiDi->paraLevel=(UBiDiLevel)((pLineBiDi->paraLevel+1)&~1);
+
+            /* all levels are implicitly at paraLevel (important for ubidi_getLevels()) */
+            pLineBiDi->trailingWSStart=0;
+            break;
+        case UBIDI_RTL:
+            /* make sure paraLevel is odd */
+            pLineBiDi->paraLevel|=1;
+
+            /* all levels are implicitly at paraLevel (important for ubidi_getLevels()) */
+            pLineBiDi->trailingWSStart=0;
+            break;
+        default:
+            break;
+        }
+    }
+    pLineBiDi->pParaBiDi=pParaBiDi;     /* mark successful setLine */
+    return;
+}
+
+U_CAPI UBiDiLevel U_EXPORT2
+ubidi_getLevelAt(const UBiDi *pBiDi, int32_t charIndex) {
+    /* return paraLevel if in the trailing WS run, otherwise the real level */
+    if(!IS_VALID_PARA_OR_LINE(pBiDi) || charIndex<0 || pBiDi->length<=charIndex) {
+        return 0;
+    } else if(pBiDi->direction!=UBIDI_MIXED || charIndex>=pBiDi->trailingWSStart) {
+        return GET_PARALEVEL(pBiDi, charIndex);
+    } else {
+        return pBiDi->levels[charIndex];
+    }
+}
+
+U_CAPI const UBiDiLevel * U_EXPORT2
+ubidi_getLevels(UBiDi *pBiDi, UErrorCode *pErrorCode) {
+    int32_t start, length;
+
+    RETURN_IF_NULL_OR_FAILING_ERRCODE(pErrorCode, NULL);
+    RETURN_IF_NOT_VALID_PARA_OR_LINE(pBiDi, *pErrorCode, NULL);
+    if((length=pBiDi->length)<=0) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+    if((start=pBiDi->trailingWSStart)==length) {
+        /* the current levels array reflects the WS run */
+        return pBiDi->levels;
+    }
+
+    /*
+     * After the previous if(), we know that the levels array
+     * has an implicit trailing WS run and therefore does not fully
+     * reflect itself all the levels.
+     * This must be a UBiDi object for a line, and
+     * we need to create a new levels array.
+     */
+    if(getLevelsMemory(pBiDi, length)) {
+        UBiDiLevel *levels=pBiDi->levelsMemory;
+
+        if(start>0 && levels!=pBiDi->levels) {
+            uprv_memcpy(levels, pBiDi->levels, start);
+        }
+        /* pBiDi->paraLevel is ok even if contextual multiple paragraphs,
+           since pBidi is a line object                                     */
+        uprv_memset(levels+start, pBiDi->paraLevel, length-start);
+
+        /* this new levels array is set for the line and reflects the WS run */
+        pBiDi->trailingWSStart=length;
+        return pBiDi->levels=levels;
+    } else {
+        /* out of memory */
+        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+}
+
+U_CAPI void U_EXPORT2
+ubidi_getLogicalRun(const UBiDi *pBiDi, int32_t logicalPosition,
+                    int32_t *pLogicalLimit, UBiDiLevel *pLevel) {
+    UErrorCode errorCode;
+    int32_t runCount, visualStart, logicalLimit, logicalFirst, i;
+    Run iRun;
+
+    errorCode=U_ZERO_ERROR;
+    RETURN_VOID_IF_BAD_RANGE(logicalPosition, 0, pBiDi->length, errorCode);
+    /* ubidi_countRuns will check VALID_PARA_OR_LINE */
+    runCount=ubidi_countRuns((UBiDi *)pBiDi, &errorCode);
+    if(U_FAILURE(errorCode)) {
+        return;
+    }
+    /* this is done based on runs rather than on levels since levels have
+       a special interpretation when UBIDI_REORDER_RUNS_ONLY
+     */
+    visualStart=logicalLimit=0;
+    iRun=pBiDi->runs[0];
+
+    for(i=0; i<runCount; i++) {
+        iRun = pBiDi->runs[i];
+        logicalFirst=GET_INDEX(iRun.logicalStart);
+        logicalLimit=logicalFirst+iRun.visualLimit-visualStart;
+        if((logicalPosition>=logicalFirst) &&
+           (logicalPosition<logicalLimit)) {
+            break;
+        }
+        visualStart = iRun.visualLimit;
+    }
+    if(pLogicalLimit) {
+        *pLogicalLimit=logicalLimit;
+    }
+    if(pLevel) {
+        if(pBiDi->reorderingMode==UBIDI_REORDER_RUNS_ONLY) {
+            *pLevel=(UBiDiLevel)GET_ODD_BIT(iRun.logicalStart);
+        }
+        else if(pBiDi->direction!=UBIDI_MIXED || logicalPosition>=pBiDi->trailingWSStart) {
+            *pLevel=GET_PARALEVEL(pBiDi, logicalPosition);
+        } else {
+        *pLevel=pBiDi->levels[logicalPosition];
+        }
+    }
+}
+
+/* runs API functions ------------------------------------------------------- */
+
+U_CAPI int32_t U_EXPORT2
+ubidi_countRuns(UBiDi *pBiDi, UErrorCode *pErrorCode) {
+    RETURN_IF_NULL_OR_FAILING_ERRCODE(pErrorCode, -1);
+    RETURN_IF_NOT_VALID_PARA_OR_LINE(pBiDi, *pErrorCode, -1);
+    ubidi_getRuns(pBiDi, pErrorCode);
+    if(U_FAILURE(*pErrorCode)) {
+        return -1;
+    }
+    return pBiDi->runCount;
+}
+
+U_CAPI UBiDiDirection U_EXPORT2
+ubidi_getVisualRun(UBiDi *pBiDi, int32_t runIndex,
+                   int32_t *pLogicalStart, int32_t *pLength)
+{
+    int32_t start;
+    UErrorCode errorCode = U_ZERO_ERROR;
+    RETURN_IF_NOT_VALID_PARA_OR_LINE(pBiDi, errorCode, UBIDI_LTR);
+    ubidi_getRuns(pBiDi, &errorCode);
+    if(U_FAILURE(errorCode)) {
+        return UBIDI_LTR;
+    }
+    RETURN_IF_BAD_RANGE(runIndex, 0, pBiDi->runCount, errorCode, UBIDI_LTR);
+
+    start=pBiDi->runs[runIndex].logicalStart;
+    if(pLogicalStart!=NULL) {
+        *pLogicalStart=GET_INDEX(start);
+    }
+    if(pLength!=NULL) {
+        if(runIndex>0) {
+            *pLength=pBiDi->runs[runIndex].visualLimit-
+                     pBiDi->runs[runIndex-1].visualLimit;
+        } else {
+            *pLength=pBiDi->runs[0].visualLimit;
+        }
+    }
+    return (UBiDiDirection)GET_ODD_BIT(start);
+}
+
+/* in trivial cases there is only one trivial run; called by ubidi_getRuns() */
+static void
+getSingleRun(UBiDi *pBiDi, UBiDiLevel level) {
+    /* simple, single-run case */
+    pBiDi->runs=pBiDi->simpleRuns;
+    pBiDi->runCount=1;
+
+    /* fill and reorder the single run */
+    pBiDi->runs[0].logicalStart=MAKE_INDEX_ODD_PAIR(0, level);
+    pBiDi->runs[0].visualLimit=pBiDi->length;
+    pBiDi->runs[0].insertRemove=0;
+}
+
+/* reorder the runs array (L2) ---------------------------------------------- */
+
+/*
+ * Reorder the same-level runs in the runs array.
+ * Here, runCount>1 and maxLevel>=minLevel>=paraLevel.
+ * All the visualStart fields=logical start before reordering.
+ * The "odd" bits are not set yet.
+ *
+ * Reordering with this data structure lends itself to some handy shortcuts:
+ *
+ * Since each run is moved but not modified, and since at the initial maxLevel
+ * each sequence of same-level runs consists of only one run each, we
+ * don't need to do anything there and can predecrement maxLevel.
+ * In many simple cases, the reordering is thus done entirely in the
+ * index mapping.
+ * Also, reordering occurs only down to the lowest odd level that occurs,
+ * which is minLevel|1. However, if the lowest level itself is odd, then
+ * in the last reordering the sequence of the runs at this level or higher
+ * will be all runs, and we don't need the elaborate loop to search for them.
+ * This is covered by ++minLevel instead of minLevel|=1 followed
+ * by an extra reorder-all after the reorder-some loop.
+ * About a trailing WS run:
+ * Such a run would need special treatment because its level is not
+ * reflected in levels[] if this is not a paragraph object.
+ * Instead, all characters from trailingWSStart on are implicitly at
+ * paraLevel.
+ * However, for all maxLevel>paraLevel, this run will never be reordered
+ * and does not need to be taken into account. maxLevel==paraLevel is only reordered
+ * if minLevel==paraLevel is odd, which is done in the extra segment.
+ * This means that for the main reordering loop we don't need to consider
+ * this run and can --runCount. If it is later part of the all-runs
+ * reordering, then runCount is adjusted accordingly.
+ */
+static void
+reorderLine(UBiDi *pBiDi, UBiDiLevel minLevel, UBiDiLevel maxLevel) {
+    Run *runs, tempRun;
+    UBiDiLevel *levels;
+    int32_t firstRun, endRun, limitRun, runCount;
+
+    /* nothing to do? */
+    if(maxLevel<=(minLevel|1)) {
+        return;
+    }
+
+    /*
+     * Reorder only down to the lowest odd level
+     * and reorder at an odd minLevel in a separate, simpler loop.
+     * See comments above for why minLevel is always incremented.
+     */
+    ++minLevel;
+
+    runs=pBiDi->runs;
+    levels=pBiDi->levels;
+    runCount=pBiDi->runCount;
+
+    /* do not include the WS run at paraLevel<=old minLevel except in the simple loop */
+    if(pBiDi->trailingWSStart<pBiDi->length) {
+        --runCount;
+    }
+
+    while(--maxLevel>=minLevel) {
+        firstRun=0;
+
+        /* loop for all sequences of runs */
+        for(;;) {
+            /* look for a sequence of runs that are all at >=maxLevel */
+            /* look for the first run of such a sequence */
+            while(firstRun<runCount && levels[runs[firstRun].logicalStart]<maxLevel) {
+                ++firstRun;
+            }
+            if(firstRun>=runCount) {
+                break;  /* no more such runs */
+            }
+
+            /* look for the limit run of such a sequence (the run behind it) */
+            for(limitRun=firstRun; ++limitRun<runCount && levels[runs[limitRun].logicalStart]>=maxLevel;) {}
+
+            /* Swap the entire sequence of runs from firstRun to limitRun-1. */
+            endRun=limitRun-1;
+            while(firstRun<endRun) {
+                tempRun = runs[firstRun];
+                runs[firstRun]=runs[endRun];
+                runs[endRun]=tempRun;
+                ++firstRun;
+                --endRun;
+            }
+
+            if(limitRun==runCount) {
+                break;  /* no more such runs */
+            } else {
+                firstRun=limitRun+1;
+            }
+        }
+    }
+
+    /* now do maxLevel==old minLevel (==odd!), see above */
+    if(!(minLevel&1)) {
+        firstRun=0;
+
+        /* include the trailing WS run in this complete reordering */
+        if(pBiDi->trailingWSStart==pBiDi->length) {
+            --runCount;
+        }
+
+        /* Swap the entire sequence of all runs. (endRun==runCount) */
+        while(firstRun<runCount) {
+            tempRun=runs[firstRun];
+            runs[firstRun]=runs[runCount];
+            runs[runCount]=tempRun;
+            ++firstRun;
+            --runCount;
+        }
+    }
+}
+
+/* compute the runs array --------------------------------------------------- */
+
+static int32_t getRunFromLogicalIndex(UBiDi *pBiDi, int32_t logicalIndex, UErrorCode *pErrorCode) {
+    Run *runs=pBiDi->runs;
+    int32_t runCount=pBiDi->runCount, visualStart=0, i, length, logicalStart;
+
+    for(i=0; i<runCount; i++) {
+        length=runs[i].visualLimit-visualStart;
+        logicalStart=GET_INDEX(runs[i].logicalStart);
+        if((logicalIndex>=logicalStart) && (logicalIndex<(logicalStart+length))) {
+            return i;
+        }
+        visualStart+=length;
+    }
+    /* we should never get here */
+    U_ASSERT(FALSE);
+    *pErrorCode = U_INVALID_STATE_ERROR;
+    return 0;
+}
+
+/*
+ * Compute the runs array from the levels array.
+ * After ubidi_getRuns() returns TRUE, runCount is guaranteed to be >0
+ * and the runs are reordered.
+ * Odd-level runs have visualStart on their visual right edge and
+ * they progress visually to the left.
+ * If option UBIDI_OPTION_INSERT_MARKS is set, insertRemove will contain the
+ * sum of appropriate LRM/RLM_BEFORE/AFTER flags.
+ * If option UBIDI_OPTION_REMOVE_CONTROLS is set, insertRemove will contain the
+ * negative number of BiDi control characters within this run.
+ */
+U_CFUNC UBool
+ubidi_getRuns(UBiDi *pBiDi, UErrorCode *pErrorCode) {
+    /*
+     * This method returns immediately if the runs are already set. This
+     * includes the case of length==0 (handled in setPara)..
+     */
+    if (pBiDi->runCount>=0) {
+        return TRUE;
+    }
+
+    if(pBiDi->direction!=UBIDI_MIXED) {
+        /* simple, single-run case - this covers length==0 */
+        /* pBiDi->paraLevel is ok even for contextual multiple paragraphs */
+        getSingleRun(pBiDi, pBiDi->paraLevel);
+    } else /* UBIDI_MIXED, length>0 */ {
+        /* mixed directionality */
+        int32_t length=pBiDi->length, limit;
+        UBiDiLevel *levels=pBiDi->levels;
+        int32_t i, runCount;
+        UBiDiLevel level=UBIDI_DEFAULT_LTR;   /* initialize with no valid level */
+        /*
+         * If there are WS characters at the end of the line
+         * and the run preceding them has a level different from
+         * paraLevel, then they will form their own run at paraLevel (L1).
+         * Count them separately.
+         * We need some special treatment for this in order to not
+         * modify the levels array which a line UBiDi object shares
+         * with its paragraph parent and its other line siblings.
+         * In other words, for the trailing WS, it may be
+         * levels[]!=paraLevel but we have to treat it like it were so.
+         */
+        limit=pBiDi->trailingWSStart;
+        /* count the runs, there is at least one non-WS run, and limit>0 */
+        runCount=0;
+        for(i=0; i<limit; ++i) {
+            /* increment runCount at the start of each run */
+            if(levels[i]!=level) {
+                ++runCount;
+                level=levels[i];
+            }
+        }
+
+        /*
+         * We don't need to see if the last run can be merged with a trailing
+         * WS run because setTrailingWSStart() would have done that.
+         */
+        if(runCount==1 && limit==length) {
+            /* There is only one non-WS run and no trailing WS-run. */
+            getSingleRun(pBiDi, levels[0]);
+        } else /* runCount>1 || limit<length */ {
+            /* allocate and set the runs */
+            Run *runs;
+            int32_t runIndex, start;
+            UBiDiLevel minLevel=UBIDI_MAX_EXPLICIT_LEVEL+1, maxLevel=0;
+
+            /* now, count a (non-mergeable) WS run */
+            if(limit<length) {
+                ++runCount;
+            }
+
+            /* runCount>1 */
+            if(getRunsMemory(pBiDi, runCount)) {
+                runs=pBiDi->runsMemory;
+            } else {
+                return FALSE;
+            }
+
+            /* set the runs */
+            /* FOOD FOR THOUGHT: this could be optimized, e.g.:
+             * 464->444, 484->444, 575->555, 595->555
+             * However, that would take longer. Check also how it would
+             * interact with BiDi control removal and inserting Marks.
+             */
+            runIndex=0;
+
+            /* search for the run limits and initialize visualLimit values with the run lengths */
+            i=0;
+            do {
+                /* prepare this run */
+                start=i;
+                level=levels[i];
+                if(level<minLevel) {
+                    minLevel=level;
+                }
+                if(level>maxLevel) {
+                    maxLevel=level;
+                }
+
+                /* look for the run limit */
+                while(++i<limit && levels[i]==level) {}
+
+                /* i is another run limit */
+                runs[runIndex].logicalStart=start;
+                runs[runIndex].visualLimit=i-start;
+                runs[runIndex].insertRemove=0;
+                ++runIndex;
+            } while(i<limit);
+
+            if(limit<length) {
+                /* there is a separate WS run */
+                runs[runIndex].logicalStart=limit;
+                runs[runIndex].visualLimit=length-limit;
+                /* For the trailing WS run, pBiDi->paraLevel is ok even
+                   if contextual multiple paragraphs.                   */
+                if(pBiDi->paraLevel<minLevel) {
+                    minLevel=pBiDi->paraLevel;
+                }
+            }
+
+            /* set the object fields */
+            pBiDi->runs=runs;
+            pBiDi->runCount=runCount;
+
+            reorderLine(pBiDi, minLevel, maxLevel);
+
+            /* now add the direction flags and adjust the visualLimit's to be just that */
+            /* this loop will also handle the trailing WS run */
+            limit=0;
+            for(i=0; i<runCount; ++i) {
+                ADD_ODD_BIT_FROM_LEVEL(runs[i].logicalStart, levels[runs[i].logicalStart]);
+                limit+=runs[i].visualLimit;
+                runs[i].visualLimit=limit;
+            }
+
+            /* Set the "odd" bit for the trailing WS run. */
+            /* For a RTL paragraph, it will be the *first* run in visual order. */
+            /* For the trailing WS run, pBiDi->paraLevel is ok even if
+               contextual multiple paragraphs.                          */
+            if(runIndex<runCount) {
+                int32_t trailingRun = ((pBiDi->paraLevel & 1) != 0)? 0 : runIndex;
+
+                ADD_ODD_BIT_FROM_LEVEL(runs[trailingRun].logicalStart, pBiDi->paraLevel);
+            }
+        }
+    }
+
+    /* handle insert LRM/RLM BEFORE/AFTER run */
+    if(pBiDi->insertPoints.size>0) {
+        Point *point, *start=pBiDi->insertPoints.points,
+                      *limit=start+pBiDi->insertPoints.size;
+        int32_t runIndex;
+        for(point=start; point<limit; point++) {
+            runIndex=getRunFromLogicalIndex(pBiDi, point->pos, pErrorCode);
+            pBiDi->runs[runIndex].insertRemove|=point->flag;
+        }
+    }
+
+    /* handle remove BiDi control characters */
+    if(pBiDi->controlCount>0) {
+        int32_t runIndex;
+        const UChar *start=pBiDi->text, *limit=start+pBiDi->length, *pu;
+        for(pu=start; pu<limit; pu++) {
+            if(IS_BIDI_CONTROL_CHAR(*pu)) {
+                runIndex=getRunFromLogicalIndex(pBiDi, (int32_t)(pu-start), pErrorCode);
+                pBiDi->runs[runIndex].insertRemove--;
+            }
+        }
+    }
+
+    return TRUE;
+}
+
+static UBool
+prepareReorder(const UBiDiLevel *levels, int32_t length,
+               int32_t *indexMap,
+               UBiDiLevel *pMinLevel, UBiDiLevel *pMaxLevel) {
+    int32_t start;
+    UBiDiLevel level, minLevel, maxLevel;
+
+    if(levels==NULL || length<=0) {
+        return FALSE;
+    }
+
+    /* determine minLevel and maxLevel */
+    minLevel=UBIDI_MAX_EXPLICIT_LEVEL+1;
+    maxLevel=0;
+    for(start=length; start>0;) {
+        level=levels[--start];
+        if(level>UBIDI_MAX_EXPLICIT_LEVEL+1) {
+            return FALSE;
+        }
+        if(level<minLevel) {
+            minLevel=level;
+        }
+        if(level>maxLevel) {
+            maxLevel=level;
+        }
+    }
+    *pMinLevel=minLevel;
+    *pMaxLevel=maxLevel;
+
+    /* initialize the index map */
+    for(start=length; start>0;) {
+        --start;
+        indexMap[start]=start;
+    }
+
+    return TRUE;
+}
+
+/* reorder a line based on a levels array (L2) ------------------------------ */
+
+U_CAPI void U_EXPORT2
+ubidi_reorderLogical(const UBiDiLevel *levels, int32_t length, int32_t *indexMap) {
+    int32_t start, limit, sumOfSosEos;
+    UBiDiLevel minLevel = 0, maxLevel = 0;
+
+    if(indexMap==NULL || !prepareReorder(levels, length, indexMap, &minLevel, &maxLevel)) {
+        return;
+    }
+
+    /* nothing to do? */
+    if(minLevel==maxLevel && (minLevel&1)==0) {
+        return;
+    }
+
+    /* reorder only down to the lowest odd level */
+    minLevel|=1;
+
+    /* loop maxLevel..minLevel */
+    do {
+        start=0;
+
+        /* loop for all sequences of levels to reorder at the current maxLevel */
+        for(;;) {
+            /* look for a sequence of levels that are all at >=maxLevel */
+            /* look for the first index of such a sequence */
+            while(start<length && levels[start]<maxLevel) {
+                ++start;
+            }
+            if(start>=length) {
+                break;  /* no more such sequences */
+            }
+
+            /* look for the limit of such a sequence (the index behind it) */
+            for(limit=start; ++limit<length && levels[limit]>=maxLevel;) {}
+
+            /*
+             * sos=start of sequence, eos=end of sequence
+             *
+             * The closed (inclusive) interval from sos to eos includes all the logical
+             * and visual indexes within this sequence. They are logically and
+             * visually contiguous and in the same range.
+             *
+             * For each run, the new visual index=sos+eos-old visual index;
+             * we pre-add sos+eos into sumOfSosEos ->
+             * new visual index=sumOfSosEos-old visual index;
+             */
+            sumOfSosEos=start+limit-1;
+
+            /* reorder each index in the sequence */
+            do {
+                indexMap[start]=sumOfSosEos-indexMap[start];
+            } while(++start<limit);
+
+            /* start==limit */
+            if(limit==length) {
+                break;  /* no more such sequences */
+            } else {
+                start=limit+1;
+            }
+        }
+    } while(--maxLevel>=minLevel);
+}
+
+U_CAPI void U_EXPORT2
+ubidi_reorderVisual(const UBiDiLevel *levels, int32_t length, int32_t *indexMap) {
+    int32_t start, end, limit, temp;
+    UBiDiLevel minLevel = 0, maxLevel = 0;
+
+    if(indexMap==NULL || !prepareReorder(levels, length, indexMap, &minLevel, &maxLevel)) {
+        return;
+    }
+
+    /* nothing to do? */
+    if(minLevel==maxLevel && (minLevel&1)==0) {
+        return;
+    }
+
+    /* reorder only down to the lowest odd level */
+    minLevel|=1;
+
+    /* loop maxLevel..minLevel */
+    do {
+        start=0;
+
+        /* loop for all sequences of levels to reorder at the current maxLevel */
+        for(;;) {
+            /* look for a sequence of levels that are all at >=maxLevel */
+            /* look for the first index of such a sequence */
+            while(start<length && levels[start]<maxLevel) {
+                ++start;
+            }
+            if(start>=length) {
+                break;  /* no more such runs */
+            }
+
+            /* look for the limit of such a sequence (the index behind it) */
+            for(limit=start; ++limit<length && levels[limit]>=maxLevel;) {}
+
+            /*
+             * Swap the entire interval of indexes from start to limit-1.
+             * We don't need to swap the levels for the purpose of this
+             * algorithm: the sequence of levels that we look at does not
+             * move anyway.
+             */
+            end=limit-1;
+            while(start<end) {
+                temp=indexMap[start];
+                indexMap[start]=indexMap[end];
+                indexMap[end]=temp;
+
+                ++start;
+                --end;
+            }
+
+            if(limit==length) {
+                break;  /* no more such sequences */
+            } else {
+                start=limit+1;
+            }
+        }
+    } while(--maxLevel>=minLevel);
+}
+
+/* API functions for logical<->visual mapping ------------------------------- */
+
+U_CAPI int32_t U_EXPORT2
+ubidi_getVisualIndex(UBiDi *pBiDi, int32_t logicalIndex, UErrorCode *pErrorCode) {
+    int32_t visualIndex=UBIDI_MAP_NOWHERE;
+    RETURN_IF_NULL_OR_FAILING_ERRCODE(pErrorCode, -1);
+    RETURN_IF_NOT_VALID_PARA_OR_LINE(pBiDi, *pErrorCode, -1);
+    RETURN_IF_BAD_RANGE(logicalIndex, 0, pBiDi->length, *pErrorCode, -1);
+
+    /* we can do the trivial cases without the runs array */
+    switch(pBiDi->direction) {
+    case UBIDI_LTR:
+        visualIndex=logicalIndex;
+        break;
+    case UBIDI_RTL:
+        visualIndex=pBiDi->length-logicalIndex-1;
+        break;
+    default:
+        if(!ubidi_getRuns(pBiDi, pErrorCode)) {
+            *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+            return -1;
+        } else {
+            Run *runs=pBiDi->runs;
+            int32_t i, visualStart=0, offset, length;
+
+            /* linear search for the run, search on the visual runs */
+            for(i=0; i<pBiDi->runCount; ++i) {
+                length=runs[i].visualLimit-visualStart;
+                offset=logicalIndex-GET_INDEX(runs[i].logicalStart);
+                if(offset>=0 && offset<length) {
+                    if(IS_EVEN_RUN(runs[i].logicalStart)) {
+                        /* LTR */
+                        visualIndex=visualStart+offset;
+                    } else {
+                        /* RTL */
+                        visualIndex=visualStart+length-offset-1;
+                    }
+                    break;          /* exit for loop */
+                }
+                visualStart+=length;
+            }
+            if(i>=pBiDi->runCount) {
+                return UBIDI_MAP_NOWHERE;
+            }
+        }
+    }
+
+    if(pBiDi->insertPoints.size>0) {
+        /* add the number of added marks until the calculated visual index */
+        Run *runs=pBiDi->runs;
+        int32_t i, length, insertRemove;
+        int32_t visualStart=0, markFound=0;
+        for(i=0; ; i++, visualStart+=length) {
+            length=runs[i].visualLimit-visualStart;
+            insertRemove=runs[i].insertRemove;
+            if(insertRemove & (LRM_BEFORE|RLM_BEFORE)) {
+                markFound++;
+            }
+            /* is it the run containing the visual index? */
+            if(visualIndex<runs[i].visualLimit) {
+                return visualIndex+markFound;
+            }
+            if(insertRemove & (LRM_AFTER|RLM_AFTER)) {
+                markFound++;
+            }
+        }
+    }
+    else if(pBiDi->controlCount>0) {
+        /* subtract the number of controls until the calculated visual index */
+        Run *runs=pBiDi->runs;
+        int32_t i, j, start, limit, length, insertRemove;
+        int32_t visualStart=0, controlFound=0;
+        UChar uchar=pBiDi->text[logicalIndex];
+        /* is the logical index pointing to a control ? */
+        if(IS_BIDI_CONTROL_CHAR(uchar)) {
+            return UBIDI_MAP_NOWHERE;
+        }
+        /* loop on runs */
+        for(i=0; ; i++, visualStart+=length) {
+            length=runs[i].visualLimit-visualStart;
+            insertRemove=runs[i].insertRemove;
+            /* calculated visual index is beyond this run? */
+            if(visualIndex>=runs[i].visualLimit) {
+                controlFound-=insertRemove;
+                continue;
+            }
+            /* calculated visual index must be within current run */
+            if(insertRemove==0) {
+                return visualIndex-controlFound;
+            }
+            if(IS_EVEN_RUN(runs[i].logicalStart)) {
+                /* LTR: check from run start to logical index */
+                start=runs[i].logicalStart;
+                limit=logicalIndex;
+            } else {
+                /* RTL: check from logical index to run end */
+                start=logicalIndex+1;
+                limit=GET_INDEX(runs[i].logicalStart)+length;
+            }
+            for(j=start; j<limit; j++) {
+                uchar=pBiDi->text[j];
+                if(IS_BIDI_CONTROL_CHAR(uchar)) {
+                    controlFound++;
+                }
+            }
+            return visualIndex-controlFound;
+        }
+    }
+
+    return visualIndex;
+}
+
+U_CAPI int32_t U_EXPORT2
+ubidi_getLogicalIndex(UBiDi *pBiDi, int32_t visualIndex, UErrorCode *pErrorCode) {
+    Run *runs;
+    int32_t i, runCount, start;
+    RETURN_IF_NULL_OR_FAILING_ERRCODE(pErrorCode, -1);
+    RETURN_IF_NOT_VALID_PARA_OR_LINE(pBiDi, *pErrorCode, -1);
+    RETURN_IF_BAD_RANGE(visualIndex, 0, pBiDi->resultLength, *pErrorCode, -1);
+    /* we can do the trivial cases without the runs array */
+    if(pBiDi->insertPoints.size==0 && pBiDi->controlCount==0) {
+        if(pBiDi->direction==UBIDI_LTR) {
+            return visualIndex;
+        }
+        else if(pBiDi->direction==UBIDI_RTL) {
+            return pBiDi->length-visualIndex-1;
+        }
+    }
+    if(!ubidi_getRuns(pBiDi, pErrorCode)) {
+        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+        return -1;
+    }
+
+    runs=pBiDi->runs;
+    runCount=pBiDi->runCount;
+    if(pBiDi->insertPoints.size>0) {
+        /* handle inserted LRM/RLM */
+        int32_t markFound=0, insertRemove;
+        int32_t visualStart=0, length;
+        runs=pBiDi->runs;
+        /* subtract number of marks until visual index */
+        for(i=0; ; i++, visualStart+=length) {
+            length=runs[i].visualLimit-visualStart;
+            insertRemove=runs[i].insertRemove;
+            if(insertRemove&(LRM_BEFORE|RLM_BEFORE)) {
+                if(visualIndex<=(visualStart+markFound)) {
+                    return UBIDI_MAP_NOWHERE;
+                }
+                markFound++;
+            }
+            /* is adjusted visual index within this run? */
+            if(visualIndex<(runs[i].visualLimit+markFound)) {
+                visualIndex-=markFound;
+                break;
+            }
+            if(insertRemove&(LRM_AFTER|RLM_AFTER)) {
+                if(visualIndex==(visualStart+length+markFound)) {
+                    return UBIDI_MAP_NOWHERE;
+                }
+                markFound++;
+            }
+        }
+    }
+    else if(pBiDi->controlCount>0) {
+        /* handle removed BiDi control characters */
+        int32_t controlFound=0, insertRemove, length;
+        int32_t logicalStart, logicalEnd, visualStart=0, j, k;
+        UChar uchar;
+        UBool evenRun;
+        /* add number of controls until visual index */
+        for(i=0; ; i++, visualStart+=length) {
+            length=runs[i].visualLimit-visualStart;
+            insertRemove=runs[i].insertRemove;
+            /* is adjusted visual index beyond current run? */
+            if(visualIndex>=(runs[i].visualLimit-controlFound+insertRemove)) {
+                controlFound-=insertRemove;
+                continue;
+            }
+            /* adjusted visual index is within current run */
+            if(insertRemove==0) {
+                visualIndex+=controlFound;
+                break;
+            }
+            /* count non-control chars until visualIndex */
+            logicalStart=runs[i].logicalStart;
+            evenRun=IS_EVEN_RUN(logicalStart);
+            REMOVE_ODD_BIT(logicalStart);
+            logicalEnd=logicalStart+length-1;
+            for(j=0; j<length; j++) {
+                k= evenRun ? logicalStart+j : logicalEnd-j;
+                uchar=pBiDi->text[k];
+                if(IS_BIDI_CONTROL_CHAR(uchar)) {
+                    controlFound++;
+                }
+                if((visualIndex+controlFound)==(visualStart+j)) {
+                    break;
+                }
+            }
+            visualIndex+=controlFound;
+            break;
+        }
+    }
+    /* handle all cases */
+    if(runCount<=10) {
+        /* linear search for the run */
+        for(i=0; visualIndex>=runs[i].visualLimit; ++i) {}
+    } else {
+        /* binary search for the run */
+        int32_t begin=0, limit=runCount;
+
+        /* the middle if() is guaranteed to find the run, we don't need a loop limit */
+        for(;;) {
+            i=(begin+limit)/2;
+            if(visualIndex>=runs[i].visualLimit) {
+                begin=i+1;
+            } else if(i==0 || visualIndex>=runs[i-1].visualLimit) {
+                break;
+            } else {
+                limit=i;
+            }
+        }
+    }
+
+    start=runs[i].logicalStart;
+    if(IS_EVEN_RUN(start)) {
+        /* LTR */
+        /* the offset in runs[i] is visualIndex-runs[i-1].visualLimit */
+        if(i>0) {
+            visualIndex-=runs[i-1].visualLimit;
+        }
+        return start+visualIndex;
+    } else {
+        /* RTL */
+        return GET_INDEX(start)+runs[i].visualLimit-visualIndex-1;
+    }
+}
+
+U_CAPI void U_EXPORT2
+ubidi_getLogicalMap(UBiDi *pBiDi, int32_t *indexMap, UErrorCode *pErrorCode) {
+    RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode);
+    /* ubidi_countRuns() checks for VALID_PARA_OR_LINE */
+    ubidi_countRuns(pBiDi, pErrorCode);
+    if(U_FAILURE(*pErrorCode)) {
+        /* no op */
+    } else if(indexMap==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+    } else {
+        /* fill a logical-to-visual index map using the runs[] */
+        int32_t visualStart, visualLimit, i, j, k;
+        int32_t logicalStart, logicalLimit;
+        Run *runs=pBiDi->runs;
+        if (pBiDi->length<=0) {
+            return;
+        }
+        if (pBiDi->length>pBiDi->resultLength) {
+            uprv_memset(indexMap, 0xFF, pBiDi->length*sizeof(int32_t));
+        }
+
+        visualStart=0;
+        for(j=0; j<pBiDi->runCount; ++j) {
+            logicalStart=GET_INDEX(runs[j].logicalStart);
+            visualLimit=runs[j].visualLimit;
+            if(IS_EVEN_RUN(runs[j].logicalStart)) {
+                do { /* LTR */
+                    indexMap[logicalStart++]=visualStart++;
+                } while(visualStart<visualLimit);
+            } else {
+                logicalStart+=visualLimit-visualStart;  /* logicalLimit */
+                do { /* RTL */
+                    indexMap[--logicalStart]=visualStart++;
+                } while(visualStart<visualLimit);
+            }
+            /* visualStart==visualLimit; */
+        }
+
+        if(pBiDi->insertPoints.size>0) {
+            int32_t markFound=0, runCount=pBiDi->runCount;
+            int32_t length, insertRemove;
+            visualStart=0;
+            /* add number of marks found until each index */
+            for(i=0; i<runCount; i++, visualStart+=length) {
+                length=runs[i].visualLimit-visualStart;
+                insertRemove=runs[i].insertRemove;
+                if(insertRemove&(LRM_BEFORE|RLM_BEFORE)) {
+                    markFound++;
+                }
+                if(markFound>0) {
+                    logicalStart=GET_INDEX(runs[i].logicalStart);
+                    logicalLimit=logicalStart+length;
+                    for(j=logicalStart; j<logicalLimit; j++) {
+                        indexMap[j]+=markFound;
+                    }
+                }
+                if(insertRemove&(LRM_AFTER|RLM_AFTER)) {
+                    markFound++;
+                }
+            }
+        }
+        else if(pBiDi->controlCount>0) {
+            int32_t controlFound=0, runCount=pBiDi->runCount;
+            int32_t length, insertRemove;
+            UBool evenRun;
+            UChar uchar;
+            visualStart=0;
+            /* subtract number of controls found until each index */
+            for(i=0; i<runCount; i++, visualStart+=length) {
+                length=runs[i].visualLimit-visualStart;
+                insertRemove=runs[i].insertRemove;
+                /* no control found within previous runs nor within this run */
+                if((controlFound-insertRemove)==0) {
+                    continue;
+                }
+                logicalStart=runs[i].logicalStart;
+                evenRun=IS_EVEN_RUN(logicalStart);
+                REMOVE_ODD_BIT(logicalStart);
+                logicalLimit=logicalStart+length;
+                /* if no control within this run */
+                if(insertRemove==0) {
+                    for(j=logicalStart; j<logicalLimit; j++) {
+                        indexMap[j]-=controlFound;
+                    }
+                    continue;
+                }
+                for(j=0; j<length; j++) {
+                    k= evenRun ? logicalStart+j : logicalLimit-j-1;
+                    uchar=pBiDi->text[k];
+                    if(IS_BIDI_CONTROL_CHAR(uchar)) {
+                        controlFound++;
+                        indexMap[k]=UBIDI_MAP_NOWHERE;
+                        continue;
+                    }
+                    indexMap[k]-=controlFound;
+                }
+            }
+        }
+    }
+}
+
+U_CAPI void U_EXPORT2
+ubidi_getVisualMap(UBiDi *pBiDi, int32_t *indexMap, UErrorCode *pErrorCode) {
+    RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode);
+    if(indexMap==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    /* ubidi_countRuns() checks for VALID_PARA_OR_LINE */
+    ubidi_countRuns(pBiDi, pErrorCode);
+    if(U_SUCCESS(*pErrorCode)) {
+        /* fill a visual-to-logical index map using the runs[] */
+        Run *runs=pBiDi->runs, *runsLimit=runs+pBiDi->runCount;
+        int32_t logicalStart, visualStart, visualLimit, *pi=indexMap;
+
+        if (pBiDi->resultLength<=0) {
+            return;
+        }
+        visualStart=0;
+        for(; runs<runsLimit; ++runs) {
+            logicalStart=runs->logicalStart;
+            visualLimit=runs->visualLimit;
+            if(IS_EVEN_RUN(logicalStart)) {
+                do { /* LTR */
+                    *pi++ = logicalStart++;
+                } while(++visualStart<visualLimit);
+            } else {
+                REMOVE_ODD_BIT(logicalStart);
+                logicalStart+=visualLimit-visualStart;  /* logicalLimit */
+                do { /* RTL */
+                    *pi++ = --logicalStart;
+                } while(++visualStart<visualLimit);
+            }
+            /* visualStart==visualLimit; */
+        }
+
+        if(pBiDi->insertPoints.size>0) {
+            int32_t markFound=0, runCount=pBiDi->runCount;
+            int32_t insertRemove, i, j, k;
+            runs=pBiDi->runs;
+            /* count all inserted marks */
+            for(i=0; i<runCount; i++) {
+                insertRemove=runs[i].insertRemove;
+                if(insertRemove&(LRM_BEFORE|RLM_BEFORE)) {
+                    markFound++;
+                }
+                if(insertRemove&(LRM_AFTER|RLM_AFTER)) {
+                    markFound++;
+                }
+            }
+            /* move back indexes by number of preceding marks */
+            k=pBiDi->resultLength;
+            for(i=runCount-1; i>=0 && markFound>0; i--) {
+                insertRemove=runs[i].insertRemove;
+                if(insertRemove&(LRM_AFTER|RLM_AFTER)) {
+                    indexMap[--k]= UBIDI_MAP_NOWHERE;
+                    markFound--;
+                }
+                visualStart= i>0 ? runs[i-1].visualLimit : 0;
+                for(j=runs[i].visualLimit-1; j>=visualStart && markFound>0; j--) {
+                    indexMap[--k]=indexMap[j];
+                }
+                if(insertRemove&(LRM_BEFORE|RLM_BEFORE)) {
+                    indexMap[--k]= UBIDI_MAP_NOWHERE;
+                    markFound--;
+                }
+            }
+        }
+        else if(pBiDi->controlCount>0) {
+            int32_t runCount=pBiDi->runCount, logicalEnd;
+            int32_t insertRemove, length, i, j, k, m;
+            UChar uchar;
+            UBool evenRun;
+            runs=pBiDi->runs;
+            visualStart=0;
+            /* move forward indexes by number of preceding controls */
+            k=0;
+            for(i=0; i<runCount; i++, visualStart+=length) {
+                length=runs[i].visualLimit-visualStart;
+                insertRemove=runs[i].insertRemove;
+                /* if no control found yet, nothing to do in this run */
+                if((insertRemove==0)&&(k==visualStart)) {
+                    k+=length;
+                    continue;
+                }
+                /* if no control in this run */
+                if(insertRemove==0) {
+                    visualLimit=runs[i].visualLimit;
+                    for(j=visualStart; j<visualLimit; j++) {
+                        indexMap[k++]=indexMap[j];
+                    }
+                    continue;
+                }
+                logicalStart=runs[i].logicalStart;
+                evenRun=IS_EVEN_RUN(logicalStart);
+                REMOVE_ODD_BIT(logicalStart);
+                logicalEnd=logicalStart+length-1;
+                for(j=0; j<length; j++) {
+                    m= evenRun ? logicalStart+j : logicalEnd-j;
+                    uchar=pBiDi->text[m];
+                    if(!IS_BIDI_CONTROL_CHAR(uchar)) {
+                        indexMap[k++]=m;
+                    }
+                }
+            }
+        }
+    }
+}
+
+U_CAPI void U_EXPORT2
+ubidi_invertMap(const int32_t *srcMap, int32_t *destMap, int32_t length) {
+    if(srcMap!=NULL && destMap!=NULL && length>0) {
+        const int32_t *pi;
+        int32_t destLength=-1, count=0;
+        /* find highest value and count positive indexes in srcMap */
+        pi=srcMap+length;
+        while(pi>srcMap) {
+            if(*--pi>destLength) {
+                destLength=*pi;
+            }
+            if(*pi>=0) {
+                count++;
+            }
+        }
+        destLength++;           /* add 1 for origin 0 */
+        if(count<destLength) {
+            /* we must fill unmatched destMap entries with -1 */
+            uprv_memset(destMap, 0xFF, destLength*sizeof(int32_t));
+        }
+        pi=srcMap+length;
+        while(length>0) {
+            if(*--pi>=0) {
+                destMap[*pi]=--length;
+            } else {
+                --length;
+            }
+        }
+    }
+}
diff --git a/source/common/ubidiwrt.c b/source/common/ubidiwrt.c
new file mode 100644
index 0000000..34b1371
--- /dev/null
+++ b/source/common/ubidiwrt.c
@@ -0,0 +1,630 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2000-2007, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  ubidiwrt.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999aug06
+*   created by: Markus W. Scherer, updated by Matitiahu Allouche
+*
+* This file contains implementations for BiDi functions that use
+* the core algorithm and core API to write reordered text.
+*/
+
+/* set import/export definitions */
+#ifndef U_COMMON_IMPLEMENTATION
+#   define U_COMMON_IMPLEMENTATION
+#endif
+
+#include "unicode/utypes.h"
+#include "unicode/ustring.h"
+#include "unicode/uchar.h"
+#include "unicode/ubidi.h"
+#include "cmemory.h"
+#include "ustr_imp.h"
+#include "ubidiimp.h"
+
+/*
+ * The function implementations in this file are designed
+ * for UTF-16 and UTF-32, not for UTF-8.
+ *
+ * Assumptions that are not true for UTF-8:
+ * - Any code point always needs the same number of code units
+ *   ("minimum-length-problem" of UTF-8)
+ * - The BiDi control characters need only one code unit each
+ *
+ * Further assumptions for all UTFs:
+ * - u_charMirror(c) needs the same number of code units as c
+ */
+#if UTF_SIZE==8
+# error reimplement ubidi_writeReordered() for UTF-8, see comment above
+#endif
+
+#define IS_COMBINING(type) ((1UL<<(type))&(1UL<<U_NON_SPACING_MARK|1UL<<U_COMBINING_SPACING_MARK|1UL<<U_ENCLOSING_MARK))
+
+/*
+ * When we have UBIDI_OUTPUT_REVERSE set on ubidi_writeReordered(), then we
+ * semantically write RTL runs in reverse and later reverse them again.
+ * Instead, we actually write them in forward order to begin with.
+ * However, if the RTL run was to be mirrored, we need to mirror here now
+ * since the implicit second reversal must not do it.
+ * It looks strange to do mirroring in LTR output, but it is only because
+ * we are writing RTL output in reverse.
+ */
+static int32_t
+doWriteForward(const UChar *src, int32_t srcLength,
+               UChar *dest, int32_t destSize,
+               uint16_t options,
+               UErrorCode *pErrorCode) {
+    /* optimize for several combinations of options */
+    switch(options&(UBIDI_REMOVE_BIDI_CONTROLS|UBIDI_DO_MIRRORING)) {
+    case 0: {
+        /* simply copy the LTR run to the destination */
+        int32_t length=srcLength;
+        if(destSize<length) {
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            return srcLength;
+        }
+        do {
+            *dest++=*src++;
+        } while(--length>0);
+        return srcLength;
+    }
+    case UBIDI_DO_MIRRORING: {
+        /* do mirroring */
+        int32_t i=0, j=0;
+        UChar32 c;
+
+        if(destSize<srcLength) {
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            return srcLength;
+        }
+        do {
+            UTF_NEXT_CHAR(src, i, srcLength, c);
+            c=u_charMirror(c);
+            UTF_APPEND_CHAR_UNSAFE(dest, j, c);
+        } while(i<srcLength);
+        return srcLength;
+    }
+    case UBIDI_REMOVE_BIDI_CONTROLS: {
+        /* copy the LTR run and remove any BiDi control characters */
+        int32_t remaining=destSize;
+        UChar c;
+        do {
+            c=*src++;
+            if(!IS_BIDI_CONTROL_CHAR(c)) {
+                if(--remaining<0) {
+                    *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+
+                    /* preflight the length */
+                    while(--srcLength>0) {
+                        c=*src++;
+                        if(!IS_BIDI_CONTROL_CHAR(c)) {
+                            --remaining;
+                        }
+                    }
+                    return destSize-remaining;
+                }
+                *dest++=c;
+            }
+        } while(--srcLength>0);
+        return destSize-remaining;
+    }
+    default: {
+        /* remove BiDi control characters and do mirroring */
+        int32_t remaining=destSize;
+        int32_t i, j=0;
+        UChar32 c;
+        do {
+            i=0;
+            UTF_NEXT_CHAR(src, i, srcLength, c);
+            src+=i;
+            srcLength-=i;
+            if(!IS_BIDI_CONTROL_CHAR(c)) {
+                remaining-=i;
+                if(remaining<0) {
+                    *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+
+                    /* preflight the length */
+                    while(srcLength>0) {
+                        c=*src++;
+                        if(!IS_BIDI_CONTROL_CHAR(c)) {
+                            --remaining;
+                        }
+                        --srcLength;
+                    }
+                    return destSize-remaining;
+                }
+                c=u_charMirror(c);
+                UTF_APPEND_CHAR_UNSAFE(dest, j, c);
+            }
+        } while(srcLength>0);
+        return j;
+    }
+    } /* end of switch */
+}
+
+static int32_t
+doWriteReverse(const UChar *src, int32_t srcLength,
+               UChar *dest, int32_t destSize,
+               uint16_t options,
+               UErrorCode *pErrorCode) {
+    /*
+     * RTL run -
+     *
+     * RTL runs need to be copied to the destination in reverse order
+     * of code points, not code units, to keep Unicode characters intact.
+     *
+     * The general strategy for this is to read the source text
+     * in backward order, collect all code units for a code point
+     * (and optionally following combining characters, see below),
+     * and copy all these code units in ascending order
+     * to the destination for this run.
+     *
+     * Several options request whether combining characters
+     * should be kept after their base characters,
+     * whether BiDi control characters should be removed, and
+     * whether characters should be replaced by their mirror-image
+     * equivalent Unicode characters.
+     */
+    int32_t i, j;
+    UChar32 c;
+
+    /* optimize for several combinations of options */
+    switch(options&(UBIDI_REMOVE_BIDI_CONTROLS|UBIDI_DO_MIRRORING|UBIDI_KEEP_BASE_COMBINING)) {
+    case 0:
+        /*
+         * With none of the "complicated" options set, the destination
+         * run will have the same length as the source run,
+         * and there is no mirroring and no keeping combining characters
+         * with their base characters.
+         */
+        if(destSize<srcLength) {
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            return srcLength;
+        }
+        destSize=srcLength;
+
+        /* preserve character integrity */
+        do {
+            /* i is always after the last code unit known to need to be kept in this segment */
+            i=srcLength;
+
+            /* collect code units for one base character */
+            UTF_BACK_1(src, 0, srcLength);
+
+            /* copy this base character */
+            j=srcLength;
+            do {
+                *dest++=src[j++];
+            } while(j<i);
+        } while(srcLength>0);
+        break;
+    case UBIDI_KEEP_BASE_COMBINING:
+        /*
+         * Here, too, the destination
+         * run will have the same length as the source run,
+         * and there is no mirroring.
+         * We do need to keep combining characters with their base characters.
+         */
+        if(destSize<srcLength) {
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            return srcLength;
+        }
+        destSize=srcLength;
+
+        /* preserve character integrity */
+        do {
+            /* i is always after the last code unit known to need to be kept in this segment */
+            i=srcLength;
+
+            /* collect code units and modifier letters for one base character */
+            do {
+                UTF_PREV_CHAR(src, 0, srcLength, c);
+            } while(srcLength>0 && IS_COMBINING(u_charType(c)));
+
+            /* copy this "user character" */
+            j=srcLength;
+            do {
+                *dest++=src[j++];
+            } while(j<i);
+        } while(srcLength>0);
+        break;
+    default:
+        /*
+         * With several "complicated" options set, this is the most
+         * general and the slowest copying of an RTL run.
+         * We will do mirroring, remove BiDi controls, and
+         * keep combining characters with their base characters
+         * as requested.
+         */
+        if(!(options&UBIDI_REMOVE_BIDI_CONTROLS)) {
+            i=srcLength;
+        } else {
+            /* we need to find out the destination length of the run,
+               which will not include the BiDi control characters */
+            int32_t length=srcLength;
+            UChar ch;
+
+            i=0;
+            do {
+                ch=*src++;
+                if(!IS_BIDI_CONTROL_CHAR(ch)) {
+                    ++i;
+                }
+            } while(--length>0);
+            src-=srcLength;
+        }
+
+        if(destSize<i) {
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            return i;
+        }
+        destSize=i;
+
+        /* preserve character integrity */
+        do {
+            /* i is always after the last code unit known to need to be kept in this segment */
+            i=srcLength;
+
+            /* collect code units for one base character */
+            UTF_PREV_CHAR(src, 0, srcLength, c);
+            if(options&UBIDI_KEEP_BASE_COMBINING) {
+                /* collect modifier letters for this base character */
+                while(srcLength>0 && IS_COMBINING(u_charType(c))) {
+                    UTF_PREV_CHAR(src, 0, srcLength, c);
+                }
+            }
+
+            if(options&UBIDI_REMOVE_BIDI_CONTROLS && IS_BIDI_CONTROL_CHAR(c)) {
+                /* do not copy this BiDi control character */
+                continue;
+            }
+
+            /* copy this "user character" */
+            j=srcLength;
+            if(options&UBIDI_DO_MIRRORING) {
+                /* mirror only the base character */
+                int32_t k=0;
+                c=u_charMirror(c);
+                UTF_APPEND_CHAR_UNSAFE(dest, k, c);
+                dest+=k;
+                j+=k;
+            }
+            while(j<i) {
+                *dest++=src[j++];
+            }
+        } while(srcLength>0);
+        break;
+    } /* end of switch */
+
+    return destSize;
+}
+
+U_CAPI int32_t U_EXPORT2
+ubidi_writeReverse(const UChar *src, int32_t srcLength,
+                   UChar *dest, int32_t destSize,
+                   uint16_t options,
+                   UErrorCode *pErrorCode) {
+    int32_t destLength;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    /* more error checking */
+    if( src==NULL || srcLength<-1 ||
+        destSize<0 || (destSize>0 && dest==NULL))
+    {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* do input and output overlap? */
+    if( dest!=NULL &&
+        ((src>=dest && src<dest+destSize) ||
+         (dest>=src && dest<src+srcLength)))
+    {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    if(srcLength==-1) {
+        srcLength=u_strlen(src);
+    }
+    if(srcLength>0) {
+        destLength=doWriteReverse(src, srcLength, dest, destSize, options, pErrorCode);
+    } else {
+        /* nothing to do */
+        destLength=0;
+    }
+
+    return u_terminateUChars(dest, destSize, destLength, pErrorCode);
+}
+
+U_CAPI int32_t U_EXPORT2
+ubidi_writeReordered(UBiDi *pBiDi,
+                     UChar *dest, int32_t destSize,
+                     uint16_t options,
+                     UErrorCode *pErrorCode) {
+    const UChar *text;
+    UChar *saveDest;
+    int32_t length, destCapacity;
+    int32_t run, runCount, logicalStart, runLength;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    /* more error checking */
+    if( pBiDi==NULL ||
+        (text=pBiDi->text)==NULL || (length=pBiDi->length)<0 ||
+        destSize<0 || (destSize>0 && dest==NULL))
+    {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* do input and output overlap? */
+    if( dest!=NULL &&
+        ((text>=dest && text<dest+destSize) ||
+         (dest>=text && dest<text+pBiDi->originalLength)))
+    {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    if(length==0) {
+        /* nothing to do */
+        return u_terminateUChars(dest, destSize, 0, pErrorCode);
+    }
+
+    runCount=ubidi_countRuns(pBiDi, pErrorCode);
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    /* destSize shrinks, later destination length=destCapacity-destSize */
+    saveDest=dest;
+    destCapacity=destSize;
+
+    /*
+     * Option "insert marks" implies UBIDI_INSERT_LRM_FOR_NUMERIC if the
+     * reordering mode (checked below) is appropriate.
+     */
+    if(pBiDi->reorderingOptions & UBIDI_OPTION_INSERT_MARKS) {
+        options|=UBIDI_INSERT_LRM_FOR_NUMERIC;
+        options&=~UBIDI_REMOVE_BIDI_CONTROLS;
+    }
+    /*
+     * Option "remove controls" implies UBIDI_REMOVE_BIDI_CONTROLS
+     * and cancels UBIDI_INSERT_LRM_FOR_NUMERIC.
+     */
+    if(pBiDi->reorderingOptions & UBIDI_OPTION_REMOVE_CONTROLS) {
+        options|=UBIDI_REMOVE_BIDI_CONTROLS;
+        options&=~UBIDI_INSERT_LRM_FOR_NUMERIC;
+    }
+    /*
+     * If we do not perform the "inverse BiDi" algorithm, then we
+     * don't need to insert any LRMs, and don't need to test for it.
+     */
+    if((pBiDi->reorderingMode != UBIDI_REORDER_INVERSE_NUMBERS_AS_L) &&
+       (pBiDi->reorderingMode != UBIDI_REORDER_INVERSE_LIKE_DIRECT)  &&
+       (pBiDi->reorderingMode != UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL) &&
+       (pBiDi->reorderingMode != UBIDI_REORDER_RUNS_ONLY)) {
+        options&=~UBIDI_INSERT_LRM_FOR_NUMERIC;
+    }
+    /*
+     * Iterate through all visual runs and copy the run text segments to
+     * the destination, according to the options.
+     *
+     * The tests for where to insert LRMs ignore the fact that there may be
+     * BN codes or non-BMP code points at the beginning and end of a run;
+     * they may insert LRMs unnecessarily but the tests are faster this way
+     * (this would have to be improved for UTF-8).
+     *
+     * Note that the only errors that are set by doWriteXY() are buffer overflow
+     * errors. Ignore them until the end, and continue for preflighting.
+     */
+    if(!(options&UBIDI_OUTPUT_REVERSE)) {
+        /* forward output */
+        if(!(options&UBIDI_INSERT_LRM_FOR_NUMERIC)) {
+            /* do not insert BiDi controls */
+            for(run=0; run<runCount; ++run) {
+                if(UBIDI_LTR==ubidi_getVisualRun(pBiDi, run, &logicalStart, &runLength)) {
+                    runLength=doWriteForward(text+logicalStart, runLength,
+                                             dest, destSize,
+                                             (uint16_t)(options&~UBIDI_DO_MIRRORING), pErrorCode);
+                } else {
+                    runLength=doWriteReverse(text+logicalStart, runLength,
+                                             dest, destSize,
+                                             options, pErrorCode);
+                }
+                dest+=runLength;
+                destSize-=runLength;
+            }
+        } else {
+            /* insert BiDi controls for "inverse BiDi" */
+            const DirProp *dirProps=pBiDi->dirProps;
+            const UChar *src;
+            UChar uc;
+            UBiDiDirection dir;
+            int32_t markFlag;
+
+            for(run=0; run<runCount; ++run) {
+                dir=ubidi_getVisualRun(pBiDi, run, &logicalStart, &runLength);
+                src=text+logicalStart;
+                /* check if something relevant in insertPoints */
+                markFlag=pBiDi->runs[run].insertRemove;
+                if(markFlag<0) {        /* BiDi controls count */
+                    markFlag=0;
+                }
+
+                if(UBIDI_LTR==dir) {
+                    if((pBiDi->isInverse) &&
+                       (/*run>0 &&*/ dirProps[logicalStart]!=L)) {
+                        markFlag |= LRM_BEFORE;
+                    }
+                    if (markFlag & LRM_BEFORE) {
+                        uc=LRM_CHAR;
+                    }
+                    else if (markFlag & RLM_BEFORE) {
+                        uc=RLM_CHAR;
+                    }
+                    else  uc=0;
+                    if(uc) {
+                        if(destSize>0) {
+                            *dest++=uc;
+                        }
+                        --destSize;
+                    }
+
+                    runLength=doWriteForward(src, runLength,
+                                             dest, destSize,
+                                             (uint16_t)(options&~UBIDI_DO_MIRRORING), pErrorCode);
+                    dest+=runLength;
+                    destSize-=runLength;
+
+                    if((pBiDi->isInverse) &&
+                       (/*run<runCount-1 &&*/ dirProps[logicalStart+runLength-1]!=L)) {
+                        markFlag |= LRM_AFTER;
+                    }
+                    if (markFlag & LRM_AFTER) {
+                        uc=LRM_CHAR;
+                    }
+                    else if (markFlag & RLM_AFTER) {
+                        uc=RLM_CHAR;
+                    }
+                    else  uc=0;
+                    if(uc) {
+                        if(destSize>0) {
+                            *dest++=uc;
+                        }
+                        --destSize;
+                    }
+                } else {                /* RTL run */
+                    if((pBiDi->isInverse) &&
+                       (/*run>0 &&*/ !(MASK_R_AL&DIRPROP_FLAG(dirProps[logicalStart+runLength-1])))) {
+                        markFlag |= RLM_BEFORE;
+                    }
+                    if (markFlag & LRM_BEFORE) {
+                        uc=LRM_CHAR;
+                    }
+                    else if (markFlag & RLM_BEFORE) {
+                        uc=RLM_CHAR;
+                    }
+                    else  uc=0;
+                    if(uc) {
+                        if(destSize>0) {
+                            *dest++=uc;
+                        }
+                        --destSize;
+                    }
+
+                    runLength=doWriteReverse(src, runLength,
+                                             dest, destSize,
+                                             options, pErrorCode);
+                    dest+=runLength;
+                    destSize-=runLength;
+
+                    if((pBiDi->isInverse) &&
+                       (/*run<runCount-1 &&*/ !(MASK_R_AL&DIRPROP_FLAG(dirProps[logicalStart])))) {
+                        markFlag |= RLM_AFTER;
+                    }
+                    if (markFlag & LRM_AFTER) {
+                        uc=LRM_CHAR;
+                    }
+                    else if (markFlag & RLM_AFTER) {
+                        uc=RLM_CHAR;
+                    }
+                    else  uc=0;
+                    if(uc) {
+                        if(destSize>0) {
+                            *dest++=uc;
+                        }
+                        --destSize;
+                    }
+                }
+            }
+        }
+    } else {
+        /* reverse output */
+        if(!(options&UBIDI_INSERT_LRM_FOR_NUMERIC)) {
+            /* do not insert BiDi controls */
+            for(run=runCount; --run>=0;) {
+                if(UBIDI_LTR==ubidi_getVisualRun(pBiDi, run, &logicalStart, &runLength)) {
+                    runLength=doWriteReverse(text+logicalStart, runLength,
+                                             dest, destSize,
+                                             (uint16_t)(options&~UBIDI_DO_MIRRORING), pErrorCode);
+                } else {
+                    runLength=doWriteForward(text+logicalStart, runLength,
+                                             dest, destSize,
+                                             options, pErrorCode);
+                }
+                dest+=runLength;
+                destSize-=runLength;
+            }
+        } else {
+            /* insert BiDi controls for "inverse BiDi" */
+            const DirProp *dirProps=pBiDi->dirProps;
+            const UChar *src;
+            UBiDiDirection dir;
+
+            for(run=runCount; --run>=0;) {
+                /* reverse output */
+                dir=ubidi_getVisualRun(pBiDi, run, &logicalStart, &runLength);
+                src=text+logicalStart;
+
+                if(UBIDI_LTR==dir) {
+                    if(/*run<runCount-1 &&*/ dirProps[logicalStart+runLength-1]!=L) {
+                        if(destSize>0) {
+                            *dest++=LRM_CHAR;
+                        }
+                        --destSize;
+                    }
+
+                    runLength=doWriteReverse(src, runLength,
+                                             dest, destSize,
+                                             (uint16_t)(options&~UBIDI_DO_MIRRORING), pErrorCode);
+                    dest+=runLength;
+                    destSize-=runLength;
+
+                    if(/*run>0 &&*/ dirProps[logicalStart]!=L) {
+                        if(destSize>0) {
+                            *dest++=LRM_CHAR;
+                        }
+                        --destSize;
+                    }
+                } else {
+                    if(/*run<runCount-1 &&*/ !(MASK_R_AL&DIRPROP_FLAG(dirProps[logicalStart]))) {
+                        if(destSize>0) {
+                            *dest++=RLM_CHAR;
+                        }
+                        --destSize;
+                    }
+
+                    runLength=doWriteForward(src, runLength,
+                                             dest, destSize,
+                                             options, pErrorCode);
+                    dest+=runLength;
+                    destSize-=runLength;
+
+                    if(/*run>0 &&*/ !(MASK_R_AL&DIRPROP_FLAG(dirProps[logicalStart+runLength-1]))) {
+                        if(destSize>0) {
+                            *dest++=RLM_CHAR;
+                        }
+                        --destSize;
+                    }
+                }
+            }
+        }
+    }
+
+    return u_terminateUChars(saveDest, destCapacity, destCapacity-destSize, pErrorCode);
+}
diff --git a/source/common/ubrk.cpp b/source/common/ubrk.cpp
new file mode 100644
index 0000000..944708a
--- /dev/null
+++ b/source/common/ubrk.cpp
@@ -0,0 +1,293 @@
+/*
+********************************************************************************
+*   Copyright (C) 1996-2008, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/ubrk.h"
+
+#include "unicode/brkiter.h"
+#include "unicode/uloc.h"
+#include "unicode/ustring.h"
+#include "unicode/uchriter.h"
+#include "unicode/rbbi.h"
+#include "rbbirb.h"
+#include "uassert.h"
+
+U_NAMESPACE_USE
+
+//------------------------------------------------------------------------------
+//
+//    ubrk_open      Create a canned type of break iterator based on type (word, line, etc.)
+//                   and locale.
+//
+//------------------------------------------------------------------------------
+U_CAPI UBreakIterator* U_EXPORT2
+ubrk_open(UBreakIteratorType type,
+      const char *locale,
+      const UChar *text,
+      int32_t textLength,
+      UErrorCode *status)
+{
+
+  if(U_FAILURE(*status)) return 0;
+
+  BreakIterator *result = 0;
+
+  switch(type) {
+
+  case UBRK_CHARACTER:
+    result = BreakIterator::createCharacterInstance(Locale(locale), *status);
+    break;
+
+  case UBRK_WORD:
+    result = BreakIterator::createWordInstance(Locale(locale), *status);
+    break;
+
+  case UBRK_LINE:
+    result = BreakIterator::createLineInstance(Locale(locale), *status);
+    break;
+
+  case UBRK_SENTENCE:
+    result = BreakIterator::createSentenceInstance(Locale(locale), *status);
+    break;
+
+  case UBRK_TITLE:
+    result = BreakIterator::createTitleInstance(Locale(locale), *status);
+    break;
+
+  default:
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+  }
+
+  // check for allocation error
+  if (U_FAILURE(*status)) {
+     return 0;
+  }
+  if(result == 0) {
+    *status = U_MEMORY_ALLOCATION_ERROR;
+    return 0;
+  }
+
+
+  UBreakIterator *uBI = (UBreakIterator *)result;
+  if (text != NULL) {
+      ubrk_setText(uBI, text, textLength, status);
+  }
+  return uBI;
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+//   ubrk_openRules      open a break iterator from a set of break rules.
+//                       Invokes the rule builder.
+//
+//------------------------------------------------------------------------------
+U_CAPI UBreakIterator* U_EXPORT2
+ubrk_openRules(  const UChar        *rules,
+                       int32_t       rulesLength,
+                 const UChar        *text,
+                       int32_t       textLength,
+                       UParseError  *parseErr,
+                       UErrorCode   *status)  {
+
+    if (status == NULL || U_FAILURE(*status)){
+        return 0;
+    }
+
+    BreakIterator *result = 0;
+    UnicodeString ruleString(rules, rulesLength);
+    result = RBBIRuleBuilder::createRuleBasedBreakIterator(ruleString, parseErr, *status);
+    if(U_FAILURE(*status)) {
+        return 0;
+    }
+
+    UBreakIterator *uBI = (UBreakIterator *)result;
+    if (text != NULL) {
+        ubrk_setText(uBI, text, textLength, status);
+    }
+    return uBI;
+}
+
+
+
+
+
+U_CAPI UBreakIterator * U_EXPORT2
+ubrk_safeClone(
+          const UBreakIterator *bi,
+          void *stackBuffer,
+          int32_t *pBufferSize,
+          UErrorCode *status)
+{
+    if (status == NULL || U_FAILURE(*status)){
+        return 0;
+    }
+    if (!pBufferSize || !bi){
+       *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    // Clear any incoming Safe Clone Allocated warning.
+    //  Propagating this through to our return would really
+    //  confuse our caller.
+    if (*status==U_SAFECLONE_ALLOCATED_WARNING) {
+        *status = U_ZERO_ERROR;
+    }
+    return (UBreakIterator *)(((BreakIterator*)bi)->
+        createBufferClone(stackBuffer, *pBufferSize, *status));
+}
+
+
+
+U_CAPI void U_EXPORT2
+ubrk_close(UBreakIterator *bi)
+{
+    BreakIterator *ubi = (BreakIterator*) bi;
+    if (ubi) {
+        if (ubi->isBufferClone()) {
+            ubi->~BreakIterator();
+            *(uint32_t *)ubi = 0xdeadbeef;
+        } else {
+            delete ubi;
+        }
+    }
+}
+
+U_CAPI void U_EXPORT2
+ubrk_setText(UBreakIterator* bi,
+             const UChar*    text,
+             int32_t         textLength,
+             UErrorCode*     status)
+{
+    BreakIterator *brit = (BreakIterator *)bi;
+    UText  ut = UTEXT_INITIALIZER;
+    utext_openUChars(&ut, text, textLength, status);
+    brit->setText(&ut, *status);
+    // A stack allocated UText wrapping a UCHar * string
+    //   can be dumped without explicitly closing it.
+}
+
+
+
+U_CAPI void U_EXPORT2
+ubrk_setUText(UBreakIterator *bi,
+             UText          *text,
+             UErrorCode     *status)
+{
+    RuleBasedBreakIterator *brit = (RuleBasedBreakIterator *)bi;
+    brit->RuleBasedBreakIterator::setText(text, *status);
+}
+
+
+
+
+
+U_CAPI int32_t U_EXPORT2
+ubrk_current(const UBreakIterator *bi)
+{
+
+  return ((RuleBasedBreakIterator*)bi)->RuleBasedBreakIterator::current();
+}
+
+U_CAPI int32_t U_EXPORT2
+ubrk_next(UBreakIterator *bi)
+{
+
+  return ((RuleBasedBreakIterator*)bi)->RuleBasedBreakIterator::next();
+}
+
+U_CAPI int32_t U_EXPORT2
+ubrk_previous(UBreakIterator *bi)
+{
+
+  return ((RuleBasedBreakIterator*)bi)->RuleBasedBreakIterator::previous();
+}
+
+U_CAPI int32_t U_EXPORT2
+ubrk_first(UBreakIterator *bi)
+{
+
+  return ((RuleBasedBreakIterator*)bi)->RuleBasedBreakIterator::first();
+}
+
+U_CAPI int32_t U_EXPORT2
+ubrk_last(UBreakIterator *bi)
+{
+
+  return ((RuleBasedBreakIterator*)bi)->RuleBasedBreakIterator::last();
+}
+
+U_CAPI int32_t U_EXPORT2
+ubrk_preceding(UBreakIterator *bi,
+           int32_t offset)
+{
+
+  return ((RuleBasedBreakIterator*)bi)->RuleBasedBreakIterator::preceding(offset);
+}
+
+U_CAPI int32_t U_EXPORT2
+ubrk_following(UBreakIterator *bi,
+           int32_t offset)
+{
+
+  return ((RuleBasedBreakIterator*)bi)->RuleBasedBreakIterator::following(offset);
+}
+
+U_CAPI const char* U_EXPORT2
+ubrk_getAvailable(int32_t index)
+{
+
+  return uloc_getAvailable(index);
+}
+
+U_CAPI int32_t U_EXPORT2
+ubrk_countAvailable()
+{
+
+  return uloc_countAvailable();
+}
+
+
+U_CAPI  UBool U_EXPORT2
+ubrk_isBoundary(UBreakIterator *bi, int32_t offset)
+{
+    return ((RuleBasedBreakIterator *)bi)->RuleBasedBreakIterator::isBoundary(offset);
+}
+
+
+U_CAPI  int32_t U_EXPORT2
+ubrk_getRuleStatus(UBreakIterator *bi)
+{
+    return ((RuleBasedBreakIterator *)bi)->RuleBasedBreakIterator::getRuleStatus();
+}
+
+U_CAPI  int32_t U_EXPORT2
+ubrk_getRuleStatusVec(UBreakIterator *bi, int32_t *fillInVec, int32_t capacity, UErrorCode *status)
+{
+    return ((RuleBasedBreakIterator *)bi)->RuleBasedBreakIterator::getRuleStatusVec(fillInVec, capacity, *status);
+}
+
+
+U_CAPI const char* U_EXPORT2
+ubrk_getLocaleByType(const UBreakIterator *bi,
+                     ULocDataLocaleType type,
+                     UErrorCode* status)
+{
+    if (bi == NULL) {
+        if (U_SUCCESS(*status)) {
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+        return NULL;
+    }
+    return ((BreakIterator*)bi)->getLocaleID(type, *status);
+}
+
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
diff --git a/source/common/ubrkimpl.h b/source/common/ubrkimpl.h
new file mode 100644
index 0000000..e490971
--- /dev/null
+++ b/source/common/ubrkimpl.h
@@ -0,0 +1,13 @@
+/*
+**********************************************************************
+*   Copyright (C) 2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+
+#ifndef UBRKIMPL_H
+#define UBRKIMPL_H
+
+#define U_ICUDATA_BRKITR U_ICUDATA_NAME U_TREE_SEPARATOR_STRING "brkitr"
+
+#endif /*UBRKIMPL_H*/
diff --git a/source/common/ucase.c b/source/common/ucase.c
new file mode 100644
index 0000000..0f9c526
--- /dev/null
+++ b/source/common/ucase.c
@@ -0,0 +1,1294 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2004-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  ucase.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2004aug30
+*   created by: Markus W. Scherer
+*
+*   Low-level Unicode character/string case mapping code.
+*   Much code moved here (and modified) from uchar.c.
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uset.h"
+#include "unicode/udata.h" /* UDataInfo */
+#include "ucmndata.h" /* DataHeader */
+#include "udatamem.h"
+#include "umutex.h"
+#include "uassert.h"
+#include "cmemory.h"
+#include "utrie2.h"
+#include "ucase.h"
+#include "ucln_cmn.h"
+
+struct UCaseProps {
+    UDataMemory *mem;
+    const int32_t *indexes;
+    const uint16_t *exceptions;
+    const UChar *unfold;
+
+    UTrie2 trie;
+    uint8_t formatVersion[4];
+};
+
+/* ucase_props_data.c is machine-generated by gencase --csource */
+#include "ucase_props_data.c"
+
+/* UCaseProps singleton ----------------------------------------------------- */
+
+U_CAPI const UCaseProps * U_EXPORT2
+ucase_getSingleton() {
+    return &ucase_props_singleton;
+}
+
+/* set of property starts for UnicodeSet ------------------------------------ */
+
+static UBool U_CALLCONV
+_enumPropertyStartsRange(const void *context, UChar32 start, UChar32 end, uint32_t value) {
+    /* add the start code point to the USet */
+    const USetAdder *sa=(const USetAdder *)context;
+    sa->add(sa->set, start);
+    return TRUE;
+}
+
+U_CFUNC void U_EXPORT2
+ucase_addPropertyStarts(const UCaseProps *csp, const USetAdder *sa, UErrorCode *pErrorCode) {
+    if(U_FAILURE(*pErrorCode)) {
+        return;
+    }
+
+    /* add the start code point of each same-value range of the trie */
+    utrie2_enum(&csp->trie, NULL, _enumPropertyStartsRange, sa);
+
+    /* add code points with hardcoded properties, plus the ones following them */
+
+    /* (none right now, see comment below) */
+
+    /*
+     * Omit code points with hardcoded specialcasing properties
+     * because we do not build property UnicodeSets for them right now.
+     */
+}
+
+/* data access primitives --------------------------------------------------- */
+
+#define GET_EXCEPTIONS(csp, props) ((csp)->exceptions+((props)>>UCASE_EXC_SHIFT))
+
+#define PROPS_HAS_EXCEPTION(props) ((props)&UCASE_EXCEPTION)
+
+/* number of bits in an 8-bit integer value */
+static const uint8_t flagsOffset[256]={
+    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+    4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+};
+
+#define HAS_SLOT(flags, idx) ((flags)&(1<<(idx)))
+#define SLOT_OFFSET(flags, idx) flagsOffset[(flags)&((1<<(idx))-1)]
+
+/*
+ * Get the value of an optional-value slot where HAS_SLOT(excWord, idx).
+ *
+ * @param excWord (in) initial exceptions word
+ * @param idx (in) desired slot index
+ * @param pExc16 (in/out) const uint16_t * after excWord=*pExc16++;
+ *               moved to the last uint16_t of the value, use +1 for beginning of next slot
+ * @param value (out) int32_t or uint32_t output if hasSlot, otherwise not modified
+ */
+#define GET_SLOT_VALUE(excWord, idx, pExc16, value) \
+    if(((excWord)&UCASE_EXC_DOUBLE_SLOTS)==0) { \
+        (pExc16)+=SLOT_OFFSET(excWord, idx); \
+        (value)=*pExc16; \
+    } else { \
+        (pExc16)+=2*SLOT_OFFSET(excWord, idx); \
+        (value)=*pExc16++; \
+        (value)=((value)<<16)|*pExc16; \
+    }
+
+/* simple case mappings ----------------------------------------------------- */
+
+U_CAPI UChar32 U_EXPORT2
+ucase_tolower(const UCaseProps *csp, UChar32 c) {
+    uint16_t props=UTRIE2_GET16(&csp->trie, c);
+    if(!PROPS_HAS_EXCEPTION(props)) {
+        if(UCASE_GET_TYPE(props)>=UCASE_UPPER) {
+            c+=UCASE_GET_DELTA(props);
+        }
+    } else {
+        const uint16_t *pe=GET_EXCEPTIONS(csp, props);
+        uint16_t excWord=*pe++;
+        if(HAS_SLOT(excWord, UCASE_EXC_LOWER)) {
+            GET_SLOT_VALUE(excWord, UCASE_EXC_LOWER, pe, c);
+        }
+    }
+    return c;
+}
+
+U_CAPI UChar32 U_EXPORT2
+ucase_toupper(const UCaseProps *csp, UChar32 c) {
+    uint16_t props=UTRIE2_GET16(&csp->trie, c);
+    if(!PROPS_HAS_EXCEPTION(props)) {
+        if(UCASE_GET_TYPE(props)==UCASE_LOWER) {
+            c+=UCASE_GET_DELTA(props);
+        }
+    } else {
+        const uint16_t *pe=GET_EXCEPTIONS(csp, props);
+        uint16_t excWord=*pe++;
+        if(HAS_SLOT(excWord, UCASE_EXC_UPPER)) {
+            GET_SLOT_VALUE(excWord, UCASE_EXC_UPPER, pe, c);
+        }
+    }
+    return c;
+}
+
+U_CAPI UChar32 U_EXPORT2
+ucase_totitle(const UCaseProps *csp, UChar32 c) {
+    uint16_t props=UTRIE2_GET16(&csp->trie, c);
+    if(!PROPS_HAS_EXCEPTION(props)) {
+        if(UCASE_GET_TYPE(props)==UCASE_LOWER) {
+            c+=UCASE_GET_DELTA(props);
+        }
+    } else {
+        const uint16_t *pe=GET_EXCEPTIONS(csp, props);
+        uint16_t excWord=*pe++;
+        int32_t idx;
+        if(HAS_SLOT(excWord, UCASE_EXC_TITLE)) {
+            idx=UCASE_EXC_TITLE;
+        } else if(HAS_SLOT(excWord, UCASE_EXC_UPPER)) {
+            idx=UCASE_EXC_UPPER;
+        } else {
+            return c;
+        }
+        GET_SLOT_VALUE(excWord, idx, pe, c);
+    }
+    return c;
+}
+
+static const UChar iDot[2] = { 0x69, 0x307 };
+static const UChar jDot[2] = { 0x6a, 0x307 };
+static const UChar iOgonekDot[3] = { 0x12f, 0x307 };
+static const UChar iDotGrave[3] = { 0x69, 0x307, 0x300 };
+static const UChar iDotAcute[3] = { 0x69, 0x307, 0x301 };
+static const UChar iDotTilde[3] = { 0x69, 0x307, 0x303 };
+
+
+U_CFUNC void U_EXPORT2
+ucase_addCaseClosure(const UCaseProps *csp, UChar32 c, const USetAdder *sa) {
+    uint16_t props;
+
+    /*
+     * Hardcode the case closure of i and its relatives and ignore the
+     * data file data for these characters.
+     * The Turkic dotless i and dotted I with their case mapping conditions
+     * and case folding option make the related characters behave specially.
+     * This code matches their closure behavior to their case folding behavior.
+     */
+
+    switch(c) {
+    case 0x49:
+        /* regular i and I are in one equivalence class */
+        sa->add(sa->set, 0x69);
+        return;
+    case 0x69:
+        sa->add(sa->set, 0x49);
+        return;
+    case 0x130:
+        /* dotted I is in a class with <0069 0307> (for canonical equivalence with <0049 0307>) */
+        sa->addString(sa->set, iDot, 2);
+        return;
+    case 0x131:
+        /* dotless i is in a class by itself */
+        return;
+    default:
+        /* otherwise use the data file data */
+        break;
+    }
+
+    props=UTRIE2_GET16(&csp->trie, c);
+    if(!PROPS_HAS_EXCEPTION(props)) {
+        if(UCASE_GET_TYPE(props)!=UCASE_NONE) {
+            /* add the one simple case mapping, no matter what type it is */
+            int32_t delta=UCASE_GET_DELTA(props);
+            if(delta!=0) {
+                sa->add(sa->set, c+delta);
+            }
+        }
+    } else {
+        /*
+         * c has exceptions, so there may be multiple simple and/or
+         * full case mappings. Add them all.
+         */
+        const uint16_t *pe0, *pe=GET_EXCEPTIONS(csp, props);
+        const UChar *closure;
+        uint16_t excWord=*pe++;
+        int32_t idx, closureLength, fullLength, length;
+
+        pe0=pe;
+
+        /* add all simple case mappings */
+        for(idx=UCASE_EXC_LOWER; idx<=UCASE_EXC_TITLE; ++idx) {
+            if(HAS_SLOT(excWord, idx)) {
+                pe=pe0;
+                GET_SLOT_VALUE(excWord, idx, pe, c);
+                sa->add(sa->set, c);
+            }
+        }
+
+        /* get the closure string pointer & length */
+        if(HAS_SLOT(excWord, UCASE_EXC_CLOSURE)) {
+            pe=pe0;
+            GET_SLOT_VALUE(excWord, UCASE_EXC_CLOSURE, pe, closureLength);
+            closureLength&=UCASE_CLOSURE_MAX_LENGTH; /* higher bits are reserved */
+            closure=(const UChar *)pe+1; /* behind this slot, unless there are full case mappings */
+        } else {
+            closureLength=0;
+            closure=NULL;
+        }
+
+        /* add the full case folding */
+        if(HAS_SLOT(excWord, UCASE_EXC_FULL_MAPPINGS)) {
+            pe=pe0;
+            GET_SLOT_VALUE(excWord, UCASE_EXC_FULL_MAPPINGS, pe, fullLength);
+
+            /* start of full case mapping strings */
+            ++pe;
+
+            fullLength&=0xffff; /* bits 16 and higher are reserved */
+
+            /* skip the lowercase result string */
+            pe+=fullLength&UCASE_FULL_LOWER;
+            fullLength>>=4;
+
+            /* add the full case folding string */
+            length=fullLength&0xf;
+            if(length!=0) {
+                sa->addString(sa->set, (const UChar *)pe, length);
+                pe+=length;
+            }
+
+            /* skip the uppercase and titlecase strings */
+            fullLength>>=4;
+            pe+=fullLength&0xf;
+            fullLength>>=4;
+            pe+=fullLength;
+
+            closure=(const UChar *)pe; /* behind full case mappings */
+        }
+
+        /* add each code point in the closure string */
+        for(idx=0; idx<closureLength;) {
+            U16_NEXT_UNSAFE(closure, idx, c);
+            sa->add(sa->set, c);
+        }
+    }
+}
+
+/*
+ * compare s, which has a length, with t, which has a maximum length or is NUL-terminated
+ * must be length>0 and max>0 and length<=max
+ */
+static U_INLINE int32_t
+strcmpMax(const UChar *s, int32_t length, const UChar *t, int32_t max) {
+    int32_t c1, c2;
+
+    max-=length; /* we require length<=max, so no need to decrement max in the loop */
+    do {
+        c1=*s++;
+        c2=*t++;
+        if(c2==0) {
+            return 1; /* reached the end of t but not of s */
+        }
+        c1-=c2;
+        if(c1!=0) {
+            return c1; /* return difference result */
+        }
+    } while(--length>0);
+    /* ends with length==0 */
+
+    if(max==0 || *t==0) {
+        return 0; /* equal to length of both strings */
+    } else {
+        return -max; /* return lengh difference */
+    }
+}
+
+U_CFUNC UBool U_EXPORT2
+ucase_addStringCaseClosure(const UCaseProps *csp, const UChar *s, int32_t length, const USetAdder *sa) {
+    const UChar *unfold, *p;
+    int32_t i, start, limit, result, unfoldRows, unfoldRowWidth, unfoldStringWidth;
+
+    if(csp->unfold==NULL || s==NULL) {
+        return FALSE; /* no reverse case folding data, or no string */
+    }
+    if(length<=1) {
+        /* the string is too short to find any match */
+        /*
+         * more precise would be:
+         * if(!u_strHasMoreChar32Than(s, length, 1))
+         * but this does not make much practical difference because
+         * a single supplementary code point would just not be found
+         */
+        return FALSE;
+    }
+
+    unfold=csp->unfold;
+    unfoldRows=unfold[UCASE_UNFOLD_ROWS];
+    unfoldRowWidth=unfold[UCASE_UNFOLD_ROW_WIDTH];
+    unfoldStringWidth=unfold[UCASE_UNFOLD_STRING_WIDTH];
+    unfold+=unfoldRowWidth;
+
+    if(length>unfoldStringWidth) {
+        /* the string is too long to find any match */
+        return FALSE;
+    }
+
+    /* do a binary search for the string */
+    start=0;
+    limit=unfoldRows;
+    while(start<limit) {
+        i=(start+limit)/2;
+        p=unfold+(i*unfoldRowWidth);
+        result=strcmpMax(s, length, p, unfoldStringWidth);
+
+        if(result==0) {
+            /* found the string: add each code point, and its case closure */
+            UChar32 c;
+
+            for(i=unfoldStringWidth; i<unfoldRowWidth && p[i]!=0;) {
+                U16_NEXT_UNSAFE(p, i, c);
+                sa->add(sa->set, c);
+                ucase_addCaseClosure(csp, c, sa);
+            }
+            return TRUE;
+        } else if(result<0) {
+            limit=i;
+        } else /* result>0 */ {
+            start=i+1;
+        }
+    }
+
+    return FALSE; /* string not found */
+}
+
+/** @return UCASE_NONE, UCASE_LOWER, UCASE_UPPER, UCASE_TITLE */
+U_CAPI int32_t U_EXPORT2
+ucase_getType(const UCaseProps *csp, UChar32 c) {
+    uint16_t props=UTRIE2_GET16(&csp->trie, c);
+    return UCASE_GET_TYPE(props);
+}
+
+/** @return same as ucase_getType() and set bit 2 if c is case-ignorable */
+U_CAPI int32_t U_EXPORT2
+ucase_getTypeOrIgnorable(const UCaseProps *csp, UChar32 c) {
+    uint16_t props=UTRIE2_GET16(&csp->trie, c);
+    int32_t type=UCASE_GET_TYPE(props);
+    if(props&UCASE_EXCEPTION) {
+        const uint16_t *pe=GET_EXCEPTIONS(csp, props);
+        if(*pe&UCASE_EXC_CASE_IGNORABLE) {
+            type|=4;
+        }
+    } else if(type==UCASE_NONE && (props&UCASE_CASE_IGNORABLE)) {
+        type|=4;
+    }
+    return type;
+}
+
+/** @return UCASE_NO_DOT, UCASE_SOFT_DOTTED, UCASE_ABOVE, UCASE_OTHER_ACCENT */
+static U_INLINE int32_t
+getDotType(const UCaseProps *csp, UChar32 c) {
+    uint16_t props=UTRIE2_GET16(&csp->trie, c);
+    if(!PROPS_HAS_EXCEPTION(props)) {
+        return props&UCASE_DOT_MASK;
+    } else {
+        const uint16_t *pe=GET_EXCEPTIONS(csp, props);
+        return (*pe>>UCASE_EXC_DOT_SHIFT)&UCASE_DOT_MASK;
+    }
+}
+
+U_CAPI UBool U_EXPORT2
+ucase_isSoftDotted(const UCaseProps *csp, UChar32 c) {
+    return (UBool)(getDotType(csp, c)==UCASE_SOFT_DOTTED);
+}
+
+U_CAPI UBool U_EXPORT2
+ucase_isCaseSensitive(const UCaseProps *csp, UChar32 c) {
+    uint16_t props=UTRIE2_GET16(&csp->trie, c);
+    return (UBool)((props&UCASE_SENSITIVE)!=0);
+}
+
+/* string casing ------------------------------------------------------------ */
+
+/*
+ * These internal functions form the core of string case mappings.
+ * They map single code points to result code points or strings and take
+ * all necessary conditions (context, locale ID, options) into account.
+ *
+ * They do not iterate over the source or write to the destination
+ * so that the same functions are useful for non-standard string storage,
+ * such as in a Replaceable (for Transliterator) or UTF-8/32 strings etc.
+ * For the same reason, the "surrounding text" context is passed in as a
+ * UCaseContextIterator which does not make any assumptions about
+ * the underlying storage.
+ *
+ * This section contains helper functions that check for conditions
+ * in the input text surrounding the current code point
+ * according to SpecialCasing.txt.
+ *
+ * Each helper function gets the index
+ * - after the current code point if it looks at following text
+ * - before the current code point if it looks at preceding text
+ *
+ * Unicode 3.2 UAX 21 "Case Mappings" defines the conditions as follows:
+ *
+ * Final_Sigma
+ *   C is preceded by a sequence consisting of
+ *     a cased letter and a case-ignorable sequence,
+ *   and C is not followed by a sequence consisting of
+ *     an ignorable sequence and then a cased letter.
+ *
+ * More_Above
+ *   C is followed by one or more characters of combining class 230 (ABOVE)
+ *   in the combining character sequence.
+ *
+ * After_Soft_Dotted
+ *   The last preceding character with combining class of zero before C
+ *   was Soft_Dotted,
+ *   and there is no intervening combining character class 230 (ABOVE).
+ *
+ * Before_Dot
+ *   C is followed by combining dot above (U+0307).
+ *   Any sequence of characters with a combining class that is neither 0 nor 230
+ *   may intervene between the current character and the combining dot above.
+ *
+ * The erratum from 2002-10-31 adds the condition
+ *
+ * After_I
+ *   The last preceding base character was an uppercase I, and there is no
+ *   intervening combining character class 230 (ABOVE).
+ *
+ *   (See Jitterbug 2344 and the comments on After_I below.)
+ *
+ * Helper definitions in Unicode 3.2 UAX 21:
+ *
+ * D1. A character C is defined to be cased
+ *     if it meets any of the following criteria:
+ *
+ *   - The general category of C is Titlecase Letter (Lt)
+ *   - In [CoreProps], C has one of the properties Uppercase, or Lowercase
+ *   - Given D = NFD(C), then it is not the case that:
+ *     D = UCD_lower(D) = UCD_upper(D) = UCD_title(D)
+ *     (This third criterium does not add any characters to the list
+ *      for Unicode 3.2. Ignored.)
+ *
+ * D2. A character C is defined to be case-ignorable
+ *     if it meets either of the following criteria:
+ *
+ *   - The general category of C is
+ *     Nonspacing Mark (Mn), or Enclosing Mark (Me), or Format Control (Cf), or
+ *     Letter Modifier (Lm), or Symbol Modifier (Sk)
+ *   - C is one of the following characters 
+ *     U+0027 APOSTROPHE
+ *     U+00AD SOFT HYPHEN (SHY)
+ *     U+2019 RIGHT SINGLE QUOTATION MARK
+ *            (the preferred character for apostrophe)
+ *
+ * D3. A case-ignorable sequence is a sequence of
+ *     zero or more case-ignorable characters.
+ */
+
+#define is_a(c) ((c)=='a' || (c)=='A')
+#define is_d(c) ((c)=='d' || (c)=='D')
+#define is_e(c) ((c)=='e' || (c)=='E')
+#define is_i(c) ((c)=='i' || (c)=='I')
+#define is_l(c) ((c)=='l' || (c)=='L')
+#define is_n(c) ((c)=='n' || (c)=='N')
+#define is_r(c) ((c)=='r' || (c)=='R')
+#define is_t(c) ((c)=='t' || (c)=='T')
+#define is_u(c) ((c)=='u' || (c)=='U')
+#define is_z(c) ((c)=='z' || (c)=='Z')
+
+/* separator? */
+#define is_sep(c) ((c)=='_' || (c)=='-' || (c)==0)
+
+/**
+ * Requires non-NULL locale ID but otherwise does the equivalent of
+ * checking for language codes as if uloc_getLanguage() were called:
+ * Accepts both 2- and 3-letter codes and accepts case variants.
+ */
+U_CFUNC int32_t
+ucase_getCaseLocale(const char *locale, int32_t *locCache) {
+    int32_t result;
+    char c;
+
+    if(locCache!=NULL && (result=*locCache)!=UCASE_LOC_UNKNOWN) {
+        return result;
+    }
+
+    result=UCASE_LOC_ROOT;
+
+    /*
+     * This function used to use uloc_getLanguage(), but the current code
+     * removes the dependency of this low-level code on uloc implementation code
+     * and is faster because not the whole locale ID has to be
+     * examined and copied/transformed.
+     *
+     * Because this code does not want to depend on uloc, the caller must
+     * pass in a non-NULL locale, i.e., may need to call uloc_getDefault().
+     */
+    c=*locale++;
+    if(is_t(c)) {
+        /* tr or tur? */
+        c=*locale++;
+        if(is_u(c)) {
+            c=*locale++;
+        }
+        if(is_r(c)) {
+            c=*locale;
+            if(is_sep(c)) {
+                result=UCASE_LOC_TURKISH;
+            }
+        }
+    } else if(is_a(c)) {
+        /* az or aze? */
+        c=*locale++;
+        if(is_z(c)) {
+            c=*locale++;
+            if(is_e(c)) {
+                c=*locale;
+            }
+            if(is_sep(c)) {
+                result=UCASE_LOC_TURKISH;
+            }
+        }
+    } else if(is_l(c)) {
+        /* lt or lit? */
+        c=*locale++;
+        if(is_i(c)) {
+            c=*locale++;
+        }
+        if(is_t(c)) {
+            c=*locale;
+            if(is_sep(c)) {
+                result=UCASE_LOC_LITHUANIAN;
+            }
+        }
+    } else if(is_n(c)) {
+        /* nl or nld? */
+        c=*locale++;
+        if(is_l(c)) {
+            c=*locale++;
+            if(is_d(c)) {
+                c=*locale;
+            }
+            if(is_sep(c)) {
+                result=UCASE_LOC_DUTCH;
+            }
+        }
+    }
+
+    if(locCache!=NULL) {
+        *locCache=result;
+    }
+    return result;
+}
+
+/*
+ * Is followed by
+ *   {case-ignorable}* cased
+ * ?
+ * (dir determines looking forward/backward)
+ * If a character is case-ignorable, it is skipped regardless of whether
+ * it is also cased or not.
+ */
+static UBool
+isFollowedByCasedLetter(const UCaseProps *csp, UCaseContextIterator *iter, void *context, int8_t dir) {
+    UChar32 c;
+
+    if(iter==NULL) {
+        return FALSE;
+    }
+
+    for(/* dir!=0 sets direction */; (c=iter(context, dir))>=0; dir=0) {
+        int32_t type=ucase_getTypeOrIgnorable(csp, c);
+        if(type&4) {
+            /* case-ignorable, continue with the loop */
+        } else if(type!=UCASE_NONE) {
+            return TRUE; /* followed by cased letter */
+        } else {
+            return FALSE; /* uncased and not case-ignorable */
+        }
+    }
+
+    return FALSE; /* not followed by cased letter */
+}
+
+/* Is preceded by Soft_Dotted character with no intervening cc=230 ? */
+static UBool
+isPrecededBySoftDotted(const UCaseProps *csp, UCaseContextIterator *iter, void *context) {
+    UChar32 c;
+    int32_t dotType;
+    int8_t dir;
+
+    if(iter==NULL) {
+        return FALSE;
+    }
+
+    for(dir=-1; (c=iter(context, dir))>=0; dir=0) {
+        dotType=getDotType(csp, c);
+        if(dotType==UCASE_SOFT_DOTTED) {
+            return TRUE; /* preceded by TYPE_i */
+        } else if(dotType!=UCASE_OTHER_ACCENT) {
+            return FALSE; /* preceded by different base character (not TYPE_i), or intervening cc==230 */
+        }
+    }
+
+    return FALSE; /* not preceded by TYPE_i */
+}
+
+/*
+ * See Jitterbug 2344:
+ * The condition After_I for Turkic-lowercasing of U+0307 combining dot above
+ * is checked in ICU 2.0, 2.1, 2.6 but was not in 2.2 & 2.4 because
+ * we made those releases compatible with Unicode 3.2 which had not fixed
+ * a related bug in SpecialCasing.txt.
+ *
+ * From the Jitterbug 2344 text:
+ * ... this bug is listed as a Unicode erratum
+ * from 2002-10-31 at http://www.unicode.org/uni2errata/UnicodeErrata.html
+ * <quote>
+ * There are two errors in SpecialCasing.txt.
+ * 1. Missing semicolons on two lines. ... [irrelevant for ICU]
+ * 2. An incorrect context definition. Correct as follows:
+ * < 0307; ; 0307; 0307; tr After_Soft_Dotted; # COMBINING DOT ABOVE
+ * < 0307; ; 0307; 0307; az After_Soft_Dotted; # COMBINING DOT ABOVE
+ * ---
+ * > 0307; ; 0307; 0307; tr After_I; # COMBINING DOT ABOVE
+ * > 0307; ; 0307; 0307; az After_I; # COMBINING DOT ABOVE
+ * where the context After_I is defined as:
+ * The last preceding base character was an uppercase I, and there is no
+ * intervening combining character class 230 (ABOVE).
+ * </quote>
+ *
+ * Note that SpecialCasing.txt even in Unicode 3.2 described the condition as:
+ *
+ * # When lowercasing, remove dot_above in the sequence I + dot_above, which will turn into i.
+ * # This matches the behavior of the canonically equivalent I-dot_above
+ *
+ * See also the description in this place in older versions of uchar.c (revision 1.100).
+ *
+ * Markus W. Scherer 2003-feb-15
+ */
+
+/* Is preceded by base character 'I' with no intervening cc=230 ? */
+static UBool
+isPrecededBy_I(const UCaseProps *csp, UCaseContextIterator *iter, void *context) {
+    UChar32 c;
+    int32_t dotType;
+    int8_t dir;
+
+    if(iter==NULL) {
+        return FALSE;
+    }
+
+    for(dir=-1; (c=iter(context, dir))>=0; dir=0) {
+        if(c==0x49) {
+            return TRUE; /* preceded by I */
+        }
+        dotType=getDotType(csp, c);
+        if(dotType!=UCASE_OTHER_ACCENT) {
+            return FALSE; /* preceded by different base character (not I), or intervening cc==230 */
+        }
+    }
+
+    return FALSE; /* not preceded by I */
+}
+
+/* Is followed by one or more cc==230 ? */
+static UBool
+isFollowedByMoreAbove(const UCaseProps *csp, UCaseContextIterator *iter, void *context) {
+    UChar32 c;
+    int32_t dotType;
+    int8_t dir;
+
+    if(iter==NULL) {
+        return FALSE;
+    }
+
+    for(dir=1; (c=iter(context, dir))>=0; dir=0) {
+        dotType=getDotType(csp, c);
+        if(dotType==UCASE_ABOVE) {
+            return TRUE; /* at least one cc==230 following */
+        } else if(dotType!=UCASE_OTHER_ACCENT) {
+            return FALSE; /* next base character, no more cc==230 following */
+        }
+    }
+
+    return FALSE; /* no more cc==230 following */
+}
+
+/* Is followed by a dot above (without cc==230 in between) ? */
+static UBool
+isFollowedByDotAbove(const UCaseProps *csp, UCaseContextIterator *iter, void *context) {
+    UChar32 c;
+    int32_t dotType;
+    int8_t dir;
+
+    if(iter==NULL) {
+        return FALSE;
+    }
+
+    for(dir=1; (c=iter(context, dir))>=0; dir=0) {
+        if(c==0x307) {
+            return TRUE;
+        }
+        dotType=getDotType(csp, c);
+        if(dotType!=UCASE_OTHER_ACCENT) {
+            return FALSE; /* next base character or cc==230 in between */
+        }
+    }
+
+    return FALSE; /* no dot above following */
+}
+
+U_CAPI int32_t U_EXPORT2
+ucase_toFullLower(const UCaseProps *csp, UChar32 c,
+                  UCaseContextIterator *iter, void *context,
+                  const UChar **pString,
+                  const char *locale, int32_t *locCache)
+{
+    UChar32 result=c;
+    uint16_t props=UTRIE2_GET16(&csp->trie, c);
+    if(!PROPS_HAS_EXCEPTION(props)) {
+        if(UCASE_GET_TYPE(props)>=UCASE_UPPER) {
+            result=c+UCASE_GET_DELTA(props);
+        }
+    } else {
+        const uint16_t *pe=GET_EXCEPTIONS(csp, props), *pe2;
+        uint16_t excWord=*pe++;
+        int32_t full;
+
+        pe2=pe;
+
+        if(excWord&UCASE_EXC_CONDITIONAL_SPECIAL) {
+            /* use hardcoded conditions and mappings */
+            int32_t loc=ucase_getCaseLocale(locale, locCache);
+
+            /*
+             * Test for conditional mappings first
+             *   (otherwise the unconditional default mappings are always taken),
+             * then test for characters that have unconditional mappings in SpecialCasing.txt,
+             * then get the UnicodeData.txt mappings.
+             */
+            if( loc==UCASE_LOC_LITHUANIAN &&
+                    /* base characters, find accents above */
+                    (((c==0x49 || c==0x4a || c==0x12e) &&
+                        isFollowedByMoreAbove(csp, iter, context)) ||
+                    /* precomposed with accent above, no need to find one */
+                    (c==0xcc || c==0xcd || c==0x128))
+            ) {
+                /*
+                    # Lithuanian
+
+                    # Lithuanian retains the dot in a lowercase i when followed by accents.
+
+                    # Introduce an explicit dot above when lowercasing capital I's and J's
+                    # whenever there are more accents above.
+                    # (of the accents used in Lithuanian: grave, acute, tilde above, and ogonek)
+
+                    0049; 0069 0307; 0049; 0049; lt More_Above; # LATIN CAPITAL LETTER I
+                    004A; 006A 0307; 004A; 004A; lt More_Above; # LATIN CAPITAL LETTER J
+                    012E; 012F 0307; 012E; 012E; lt More_Above; # LATIN CAPITAL LETTER I WITH OGONEK
+                    00CC; 0069 0307 0300; 00CC; 00CC; lt; # LATIN CAPITAL LETTER I WITH GRAVE
+                    00CD; 0069 0307 0301; 00CD; 00CD; lt; # LATIN CAPITAL LETTER I WITH ACUTE
+                    0128; 0069 0307 0303; 0128; 0128; lt; # LATIN CAPITAL LETTER I WITH TILDE
+                 */
+                switch(c) {
+                case 0x49:  /* LATIN CAPITAL LETTER I */
+                    *pString=iDot;
+                    return 2;
+                case 0x4a:  /* LATIN CAPITAL LETTER J */
+                    *pString=jDot;
+                    return 2;
+                case 0x12e: /* LATIN CAPITAL LETTER I WITH OGONEK */
+                    *pString=iOgonekDot;
+                    return 2;
+                case 0xcc:  /* LATIN CAPITAL LETTER I WITH GRAVE */
+                    *pString=iDotGrave;
+                    return 3;
+                case 0xcd:  /* LATIN CAPITAL LETTER I WITH ACUTE */
+                    *pString=iDotAcute;
+                    return 3;
+                case 0x128: /* LATIN CAPITAL LETTER I WITH TILDE */
+                    *pString=iDotTilde;
+                    return 3;
+                default:
+                    return 0; /* will not occur */
+                }
+            /* # Turkish and Azeri */
+            } else if(loc==UCASE_LOC_TURKISH && c==0x130) {
+                /*
+                    # I and i-dotless; I-dot and i are case pairs in Turkish and Azeri
+                    # The following rules handle those cases.
+
+                    0130; 0069; 0130; 0130; tr # LATIN CAPITAL LETTER I WITH DOT ABOVE
+                    0130; 0069; 0130; 0130; az # LATIN CAPITAL LETTER I WITH DOT ABOVE
+                 */
+                return 0x69;
+            } else if(loc==UCASE_LOC_TURKISH && c==0x307 && isPrecededBy_I(csp, iter, context)) {
+                /*
+                    # When lowercasing, remove dot_above in the sequence I + dot_above, which will turn into i.
+                    # This matches the behavior of the canonically equivalent I-dot_above
+
+                    0307; ; 0307; 0307; tr After_I; # COMBINING DOT ABOVE
+                    0307; ; 0307; 0307; az After_I; # COMBINING DOT ABOVE
+                 */
+                return 0; /* remove the dot (continue without output) */
+            } else if(loc==UCASE_LOC_TURKISH && c==0x49 && !isFollowedByDotAbove(csp, iter, context)) {
+                /*
+                    # When lowercasing, unless an I is before a dot_above, it turns into a dotless i.
+
+                    0049; 0131; 0049; 0049; tr Not_Before_Dot; # LATIN CAPITAL LETTER I
+                    0049; 0131; 0049; 0049; az Not_Before_Dot; # LATIN CAPITAL LETTER I
+                 */
+                return 0x131;
+            } else if(c==0x130) {
+                /*
+                    # Preserve canonical equivalence for I with dot. Turkic is handled below.
+
+                    0130; 0069 0307; 0130; 0130; # LATIN CAPITAL LETTER I WITH DOT ABOVE
+                 */
+                *pString=iDot;
+                return 2;
+            } else if(  c==0x3a3 &&
+                        !isFollowedByCasedLetter(csp, iter, context, 1) &&
+                        isFollowedByCasedLetter(csp, iter, context, -1) /* -1=preceded */
+            ) {
+                /* greek capital sigma maps depending on surrounding cased letters (see SpecialCasing.txt) */
+                /*
+                    # Special case for final form of sigma
+
+                    03A3; 03C2; 03A3; 03A3; Final_Sigma; # GREEK CAPITAL LETTER SIGMA
+                 */
+                return 0x3c2; /* greek small final sigma */
+            } else {
+                /* no known conditional special case mapping, use a normal mapping */
+            }
+        } else if(HAS_SLOT(excWord, UCASE_EXC_FULL_MAPPINGS)) {
+            GET_SLOT_VALUE(excWord, UCASE_EXC_FULL_MAPPINGS, pe, full);
+            full&=UCASE_FULL_LOWER;
+            if(full!=0) {
+                /* set the output pointer to the lowercase mapping */
+                *pString=pe+1;
+
+                /* return the string length */
+                return full;
+            }
+        }
+
+        if(HAS_SLOT(excWord, UCASE_EXC_LOWER)) {
+            GET_SLOT_VALUE(excWord, UCASE_EXC_LOWER, pe2, result);
+        }
+    }
+
+    return (result==c) ? ~result : result;
+}
+
+/* internal */
+static int32_t
+toUpperOrTitle(const UCaseProps *csp, UChar32 c,
+               UCaseContextIterator *iter, void *context,
+               const UChar **pString,
+               const char *locale, int32_t *locCache,
+               UBool upperNotTitle) {
+    UChar32 result=c;
+    uint16_t props=UTRIE2_GET16(&csp->trie, c);
+    if(!PROPS_HAS_EXCEPTION(props)) {
+        if(UCASE_GET_TYPE(props)==UCASE_LOWER) {
+            result=c+UCASE_GET_DELTA(props);
+        }
+    } else {
+        const uint16_t *pe=GET_EXCEPTIONS(csp, props), *pe2;
+        uint16_t excWord=*pe++;
+        int32_t full, idx;
+
+        pe2=pe;
+
+        if(excWord&UCASE_EXC_CONDITIONAL_SPECIAL) {
+            /* use hardcoded conditions and mappings */
+            int32_t loc=ucase_getCaseLocale(locale, locCache);
+
+            if(loc==UCASE_LOC_TURKISH && c==0x69) {
+                /*
+                    # Turkish and Azeri
+
+                    # I and i-dotless; I-dot and i are case pairs in Turkish and Azeri
+                    # The following rules handle those cases.
+
+                    # When uppercasing, i turns into a dotted capital I
+
+                    0069; 0069; 0130; 0130; tr; # LATIN SMALL LETTER I
+                    0069; 0069; 0130; 0130; az; # LATIN SMALL LETTER I
+                */
+                return 0x130;
+            } else if(loc==UCASE_LOC_LITHUANIAN && c==0x307 && isPrecededBySoftDotted(csp, iter, context)) {
+                /*
+                    # Lithuanian
+
+                    # Lithuanian retains the dot in a lowercase i when followed by accents.
+
+                    # Remove DOT ABOVE after "i" with upper or titlecase
+
+                    0307; 0307; ; ; lt After_Soft_Dotted; # COMBINING DOT ABOVE
+                 */
+                return 0; /* remove the dot (continue without output) */
+            } else {
+                /* no known conditional special case mapping, use a normal mapping */
+            }
+        } else if(HAS_SLOT(excWord, UCASE_EXC_FULL_MAPPINGS)) {
+            GET_SLOT_VALUE(excWord, UCASE_EXC_FULL_MAPPINGS, pe, full);
+
+            /* start of full case mapping strings */
+            ++pe;
+
+            /* skip the lowercase and case-folding result strings */
+            pe+=full&UCASE_FULL_LOWER;
+            full>>=4;
+            pe+=full&0xf;
+            full>>=4;
+
+            if(upperNotTitle) {
+                full&=0xf;
+            } else {
+                /* skip the uppercase result string */
+                pe+=full&0xf;
+                full=(full>>4)&0xf;
+            }
+
+            if(full!=0) {
+                /* set the output pointer to the result string */
+                *pString=pe;
+
+                /* return the string length */
+                return full;
+            }
+        }
+
+        if(!upperNotTitle && HAS_SLOT(excWord, UCASE_EXC_TITLE)) {
+            idx=UCASE_EXC_TITLE;
+        } else if(HAS_SLOT(excWord, UCASE_EXC_UPPER)) {
+            /* here, titlecase is same as uppercase */
+            idx=UCASE_EXC_UPPER;
+        } else {
+            return ~c;
+        }
+        GET_SLOT_VALUE(excWord, idx, pe2, result);
+    }
+
+    return (result==c) ? ~result : result;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucase_toFullUpper(const UCaseProps *csp, UChar32 c,
+                  UCaseContextIterator *iter, void *context,
+                  const UChar **pString,
+                  const char *locale, int32_t *locCache) {
+    return toUpperOrTitle(csp, c, iter, context, pString, locale, locCache, TRUE);
+}
+
+U_CAPI int32_t U_EXPORT2
+ucase_toFullTitle(const UCaseProps *csp, UChar32 c,
+                  UCaseContextIterator *iter, void *context,
+                  const UChar **pString,
+                  const char *locale, int32_t *locCache) {
+    return toUpperOrTitle(csp, c, iter, context, pString, locale, locCache, FALSE);
+}
+
+/* case folding ------------------------------------------------------------- */
+
+/*
+ * Case folding is similar to lowercasing.
+ * The result may be a simple mapping, i.e., a single code point, or
+ * a full mapping, i.e., a string.
+ * If the case folding for a code point is the same as its simple (1:1) lowercase mapping,
+ * then only the lowercase mapping is stored.
+ *
+ * Some special cases are hardcoded because their conditions cannot be
+ * parsed and processed from CaseFolding.txt.
+ *
+ * Unicode 3.2 CaseFolding.txt specifies for its status field:
+
+# C: common case folding, common mappings shared by both simple and full mappings.
+# F: full case folding, mappings that cause strings to grow in length. Multiple characters are separated by spaces.
+# S: simple case folding, mappings to single characters where different from F.
+# T: special case for uppercase I and dotted uppercase I
+#    - For non-Turkic languages, this mapping is normally not used.
+#    - For Turkic languages (tr, az), this mapping can be used instead of the normal mapping for these characters.
+#
+# Usage:
+#  A. To do a simple case folding, use the mappings with status C + S.
+#  B. To do a full case folding, use the mappings with status C + F.
+#
+#    The mappings with status T can be used or omitted depending on the desired case-folding
+#    behavior. (The default option is to exclude them.)
+
+ * Unicode 3.2 has 'T' mappings as follows:
+
+0049; T; 0131; # LATIN CAPITAL LETTER I
+0130; T; 0069; # LATIN CAPITAL LETTER I WITH DOT ABOVE
+
+ * while the default mappings for these code points are:
+
+0049; C; 0069; # LATIN CAPITAL LETTER I
+0130; F; 0069 0307; # LATIN CAPITAL LETTER I WITH DOT ABOVE
+
+ * U+0130 has no simple case folding (simple-case-folds to itself).
+ */
+
+/* return the simple case folding mapping for c */
+U_CAPI UChar32 U_EXPORT2
+ucase_fold(const UCaseProps *csp, UChar32 c, uint32_t options) {
+    uint16_t props=UTRIE2_GET16(&csp->trie, c);
+    if(!PROPS_HAS_EXCEPTION(props)) {
+        if(UCASE_GET_TYPE(props)>=UCASE_UPPER) {
+            c+=UCASE_GET_DELTA(props);
+        }
+    } else {
+        const uint16_t *pe=GET_EXCEPTIONS(csp, props);
+        uint16_t excWord=*pe++;
+        int32_t idx;
+        if(excWord&UCASE_EXC_CONDITIONAL_FOLD) {
+            /* special case folding mappings, hardcoded */
+            if((options&_FOLD_CASE_OPTIONS_MASK)==U_FOLD_CASE_DEFAULT) {
+                /* default mappings */
+                if(c==0x49) {
+                    /* 0049; C; 0069; # LATIN CAPITAL LETTER I */
+                    return 0x69;
+                } else if(c==0x130) {
+                    /* no simple case folding for U+0130 */
+                    return c;
+                }
+            } else {
+                /* Turkic mappings */
+                if(c==0x49) {
+                    /* 0049; T; 0131; # LATIN CAPITAL LETTER I */
+                    return 0x131;
+                } else if(c==0x130) {
+                    /* 0130; T; 0069; # LATIN CAPITAL LETTER I WITH DOT ABOVE */
+                    return 0x69;
+                }
+            }
+        }
+        if(HAS_SLOT(excWord, UCASE_EXC_FOLD)) {
+            idx=UCASE_EXC_FOLD;
+        } else if(HAS_SLOT(excWord, UCASE_EXC_LOWER)) {
+            idx=UCASE_EXC_LOWER;
+        } else {
+            return c;
+        }
+        GET_SLOT_VALUE(excWord, idx, pe, c);
+    }
+    return c;
+}
+
+/*
+ * Issue for canonical caseless match (UAX #21):
+ * Turkic casefolding (using "T" mappings in CaseFolding.txt) does not preserve
+ * canonical equivalence, unlike default-option casefolding.
+ * For example, I-grave and I + grave fold to strings that are not canonically
+ * equivalent.
+ * For more details, see the comment in unorm_compare() in unorm.cpp
+ * and the intermediate prototype changes for Jitterbug 2021.
+ * (For example, revision 1.104 of uchar.c and 1.4 of CaseFolding.txt.)
+ *
+ * This did not get fixed because it appears that it is not possible to fix
+ * it for uppercase and lowercase characters (I-grave vs. i-grave)
+ * together in a way that they still fold to common result strings.
+ */
+
+U_CAPI int32_t U_EXPORT2
+ucase_toFullFolding(const UCaseProps *csp, UChar32 c,
+                    const UChar **pString,
+                    uint32_t options)
+{
+    UChar32 result=c;
+    uint16_t props=UTRIE2_GET16(&csp->trie, c);
+    if(!PROPS_HAS_EXCEPTION(props)) {
+        if(UCASE_GET_TYPE(props)>=UCASE_UPPER) {
+            result=c+UCASE_GET_DELTA(props);
+        }
+    } else {
+        const uint16_t *pe=GET_EXCEPTIONS(csp, props), *pe2;
+        uint16_t excWord=*pe++;
+        int32_t full, idx;
+
+        pe2=pe;
+
+        if(excWord&UCASE_EXC_CONDITIONAL_FOLD) {
+            /* use hardcoded conditions and mappings */
+            if((options&_FOLD_CASE_OPTIONS_MASK)==U_FOLD_CASE_DEFAULT) {
+                /* default mappings */
+                if(c==0x49) {
+                    /* 0049; C; 0069; # LATIN CAPITAL LETTER I */
+                    return 0x69;
+                } else if(c==0x130) {
+                    /* 0130; F; 0069 0307; # LATIN CAPITAL LETTER I WITH DOT ABOVE */
+                    *pString=iDot;
+                    return 2;
+                }
+            } else {
+                /* Turkic mappings */
+                if(c==0x49) {
+                    /* 0049; T; 0131; # LATIN CAPITAL LETTER I */
+                    return 0x131;
+                } else if(c==0x130) {
+                    /* 0130; T; 0069; # LATIN CAPITAL LETTER I WITH DOT ABOVE */
+                    return 0x69;
+                }
+            }
+        } else if(HAS_SLOT(excWord, UCASE_EXC_FULL_MAPPINGS)) {
+            GET_SLOT_VALUE(excWord, UCASE_EXC_FULL_MAPPINGS, pe, full);
+
+            /* start of full case mapping strings */
+            ++pe;
+
+            /* skip the lowercase result string */
+            pe+=full&UCASE_FULL_LOWER;
+            full=(full>>4)&0xf;
+
+            if(full!=0) {
+                /* set the output pointer to the result string */
+                *pString=pe;
+
+                /* return the string length */
+                return full;
+            }
+        }
+
+        if(HAS_SLOT(excWord, UCASE_EXC_FOLD)) {
+            idx=UCASE_EXC_FOLD;
+        } else if(HAS_SLOT(excWord, UCASE_EXC_LOWER)) {
+            idx=UCASE_EXC_LOWER;
+        } else {
+            return ~c;
+        }
+        GET_SLOT_VALUE(excWord, idx, pe2, result);
+    }
+
+    return (result==c) ? ~result : result;
+}
+
+/* case mapping properties API ---------------------------------------------- */
+
+#define GET_CASE_PROPS() &ucase_props_singleton
+
+/* public API (see uchar.h) */
+
+U_CAPI UBool U_EXPORT2
+u_isULowercase(UChar32 c) {
+    return (UBool)(UCASE_LOWER==ucase_getType(GET_CASE_PROPS(), c));
+}
+
+U_CAPI UBool U_EXPORT2
+u_isUUppercase(UChar32 c) {
+    return (UBool)(UCASE_UPPER==ucase_getType(GET_CASE_PROPS(), c));
+}
+
+/* Transforms the Unicode character to its lower case equivalent.*/
+U_CAPI UChar32 U_EXPORT2
+u_tolower(UChar32 c) {
+    return ucase_tolower(GET_CASE_PROPS(), c);
+}
+    
+/* Transforms the Unicode character to its upper case equivalent.*/
+U_CAPI UChar32 U_EXPORT2
+u_toupper(UChar32 c) {
+    return ucase_toupper(GET_CASE_PROPS(), c);
+}
+
+/* Transforms the Unicode character to its title case equivalent.*/
+U_CAPI UChar32 U_EXPORT2
+u_totitle(UChar32 c) {
+    return ucase_totitle(GET_CASE_PROPS(), c);
+}
+
+/* return the simple case folding mapping for c */
+U_CAPI UChar32 U_EXPORT2
+u_foldCase(UChar32 c, uint32_t options) {
+    return ucase_fold(GET_CASE_PROPS(), c, options);
+}
+
+U_CFUNC int32_t U_EXPORT2
+ucase_hasBinaryProperty(UChar32 c, UProperty which) {
+    /* case mapping properties */
+    const UChar *resultString;
+    int32_t locCache;
+    const UCaseProps *csp=GET_CASE_PROPS();
+    if(csp==NULL) {
+        return FALSE;
+    }
+    switch(which) {
+    case UCHAR_LOWERCASE:
+        return (UBool)(UCASE_LOWER==ucase_getType(csp, c));
+    case UCHAR_UPPERCASE:
+        return (UBool)(UCASE_UPPER==ucase_getType(csp, c));
+    case UCHAR_SOFT_DOTTED:
+        return ucase_isSoftDotted(csp, c);
+    case UCHAR_CASE_SENSITIVE:
+        return ucase_isCaseSensitive(csp, c);
+    case UCHAR_CASED:
+        return (UBool)(UCASE_NONE!=ucase_getType(csp, c));
+    case UCHAR_CASE_IGNORABLE:
+        return (UBool)(ucase_getTypeOrIgnorable(csp, c)>>2);
+    /*
+     * Note: The following Changes_When_Xyz are defined as testing whether
+     * the NFD form of the input changes when Xyz-case-mapped.
+     * However, this simpler implementation of these properties,
+     * ignoring NFD, passes the tests.
+     * The implementation needs to be changed if the tests start failing.
+     * When that happens, optimizations should be used to work with the
+     * per-single-code point ucase_toFullXyz() functions unless
+     * the NFD form has more than one code point,
+     * and the property starts set needs to be the union of the
+     * start sets for normalization and case mappings.
+     */
+    case UCHAR_CHANGES_WHEN_LOWERCASED:
+        locCache=UCASE_LOC_ROOT;
+        return (UBool)(ucase_toFullLower(csp, c, NULL, NULL, &resultString, "", &locCache)>=0);
+    case UCHAR_CHANGES_WHEN_UPPERCASED:
+        locCache=UCASE_LOC_ROOT;
+        return (UBool)(ucase_toFullUpper(csp, c, NULL, NULL, &resultString, "", &locCache)>=0);
+    case UCHAR_CHANGES_WHEN_TITLECASED:
+        locCache=UCASE_LOC_ROOT;
+        return (UBool)(ucase_toFullTitle(csp, c, NULL, NULL, &resultString, "", &locCache)>=0);
+    /* case UCHAR_CHANGES_WHEN_CASEFOLDED: -- in uprops.c */
+    case UCHAR_CHANGES_WHEN_CASEMAPPED:
+        locCache=UCASE_LOC_ROOT;
+        return (UBool)(
+            ucase_toFullLower(csp, c, NULL, NULL, &resultString, "", &locCache)>=0 ||
+            ucase_toFullUpper(csp, c, NULL, NULL, &resultString, "", &locCache)>=0 ||
+            ucase_toFullTitle(csp, c, NULL, NULL, &resultString, "", &locCache)>=0);
+    default:
+        return FALSE;
+    }
+}
diff --git a/source/common/ucase.h b/source/common/ucase.h
new file mode 100644
index 0000000..cfdd729
--- /dev/null
+++ b/source/common/ucase.h
@@ -0,0 +1,368 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2004-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  ucase.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2004aug30
+*   created by: Markus W. Scherer
+*
+*   Low-level Unicode character/string case mapping code.
+*/
+
+#ifndef __UCASE_H__
+#define __UCASE_H__
+
+#include "unicode/utypes.h"
+#include "unicode/uset.h"
+#include "uset_imp.h"
+#include "udataswp.h"
+
+U_CDECL_BEGIN
+
+/* library API -------------------------------------------------------------- */
+
+struct UCaseProps;
+typedef struct UCaseProps UCaseProps;
+
+U_CAPI const UCaseProps * U_EXPORT2
+ucase_getSingleton(void);
+
+U_CAPI int32_t U_EXPORT2
+ucase_swap(const UDataSwapper *ds,
+           const void *inData, int32_t length, void *outData,
+           UErrorCode *pErrorCode);
+
+U_CFUNC void U_EXPORT2
+ucase_addPropertyStarts(const UCaseProps *csp, const USetAdder *sa, UErrorCode *pErrorCode);
+
+/**
+ * Requires non-NULL locale ID but otherwise does the equivalent of
+ * checking for language codes as if uloc_getLanguage() were called:
+ * Accepts both 2- and 3-letter codes and accepts case variants.
+ */
+U_CFUNC int32_t
+ucase_getCaseLocale(const char *locale, int32_t *locCache);
+
+/* Casing locale types for ucase_getCaseLocale */
+enum {
+    UCASE_LOC_UNKNOWN,
+    UCASE_LOC_ROOT,
+    UCASE_LOC_TURKISH,
+    UCASE_LOC_LITHUANIAN,
+    UCASE_LOC_DUTCH
+};
+
+/**
+ * Bit mask for getting just the options from a string compare options word
+ * that are relevant for case-insensitive string comparison.
+ * See uchar.h. Also include _STRNCMP_STYLE and U_COMPARE_CODE_POINT_ORDER.
+ * @internal
+ */
+#define _STRCASECMP_OPTIONS_MASK 0xffff
+
+/**
+ * Bit mask for getting just the options from a string compare options word
+ * that are relevant for case folding (of a single string or code point).
+ * See uchar.h.
+ * @internal
+ */
+#define _FOLD_CASE_OPTIONS_MASK 0xff
+
+/* single-code point functions */
+
+U_CAPI UChar32 U_EXPORT2
+ucase_tolower(const UCaseProps *csp, UChar32 c);
+
+U_CAPI UChar32 U_EXPORT2
+ucase_toupper(const UCaseProps *csp, UChar32 c);
+
+U_CAPI UChar32 U_EXPORT2
+ucase_totitle(const UCaseProps *csp, UChar32 c);
+
+U_CAPI UChar32 U_EXPORT2
+ucase_fold(const UCaseProps *csp, UChar32 c, uint32_t options);
+
+/**
+ * Adds all simple case mappings and the full case folding for c to sa,
+ * and also adds special case closure mappings.
+ * c itself is not added.
+ * For example, the mappings
+ * - for s include long s
+ * - for sharp s include ss
+ * - for k include the Kelvin sign
+ */
+U_CFUNC void U_EXPORT2
+ucase_addCaseClosure(const UCaseProps *csp, UChar32 c, const USetAdder *sa);
+
+/**
+ * Maps the string to single code points and adds the associated case closure
+ * mappings.
+ * The string is mapped to code points if it is their full case folding string.
+ * In other words, this performs a reverse full case folding and then
+ * adds the case closure items of the resulting code points.
+ * If the string is found and its closure applied, then
+ * the string itself is added as well as part of its code points' closure.
+ * It must be length>=0.
+ *
+ * @return TRUE if the string was found
+ */
+U_CFUNC UBool U_EXPORT2
+ucase_addStringCaseClosure(const UCaseProps *csp, const UChar *s, int32_t length, const USetAdder *sa);
+
+/** @return UCASE_NONE, UCASE_LOWER, UCASE_UPPER, UCASE_TITLE */
+U_CAPI int32_t U_EXPORT2
+ucase_getType(const UCaseProps *csp, UChar32 c);
+
+/** @return same as ucase_getType(), or <0 if c is case-ignorable */
+U_CAPI int32_t U_EXPORT2
+ucase_getTypeOrIgnorable(const UCaseProps *csp, UChar32 c);
+
+U_CAPI UBool U_EXPORT2
+ucase_isSoftDotted(const UCaseProps *csp, UChar32 c);
+
+U_CAPI UBool U_EXPORT2
+ucase_isCaseSensitive(const UCaseProps *csp, UChar32 c);
+
+/* string case mapping functions */
+
+/**
+ * Iterator function for string case mappings, which need to look at the
+ * context (surrounding text) of a given character for conditional mappings.
+ *
+ * The iterator only needs to go backward or forward away from the
+ * character in question. It does not use any indexes on this interface.
+ * It does not support random access or an arbitrary change of
+ * iteration direction.
+ *
+ * The code point being case-mapped itself is never returned by
+ * this iterator.
+ *
+ * @param context A pointer to the iterator's working data.
+ * @param dir If <0 then start iterating backward from the character;
+ *            if >0 then start iterating forward from the character;
+ *            if 0 then continue iterating in the current direction.
+ * @return Next code point, or <0 when the iteration is done.
+ */
+typedef UChar32 U_CALLCONV
+UCaseContextIterator(void *context, int8_t dir);
+
+/**
+ * Sample struct which may be used by some implementations of
+ * UCaseContextIterator.
+ */
+struct UCaseContext {
+    void *p;
+    int32_t start, index, limit;
+    int32_t cpStart, cpLimit;
+    int8_t dir;
+    int8_t b1, b2, b3;
+};
+typedef struct UCaseContext UCaseContext;
+
+enum {
+    /**
+     * For string case mappings, a single character (a code point) is mapped
+     * either to itself (in which case in-place mapping functions do nothing),
+     * or to another single code point, or to a string.
+     * Aside from the string contents, these are indicated with a single int32_t
+     * value as follows:
+     *
+     * Mapping to self: Negative values (~self instead of -self to support U+0000)
+     *
+     * Mapping to another code point: Positive values >UCASE_MAX_STRING_LENGTH
+     *
+     * Mapping to a string: The string length (0..UCASE_MAX_STRING_LENGTH) is
+     * returned. Note that the string result may indeed have zero length.
+     */
+    UCASE_MAX_STRING_LENGTH=0x1f
+};
+
+/**
+ * Get the full lowercase mapping for c.
+ *
+ * @param csp Case mapping properties.
+ * @param c Character to be mapped.
+ * @param iter Character iterator, used for context-sensitive mappings.
+ *             See UCaseContextIterator for details.
+ *             If iter==NULL then a context-independent result is returned.
+ * @param context Pointer to be passed into iter.
+ * @param pString If the mapping result is a string, then the pointer is
+ *                written to *pString.
+ * @param locale Locale ID for locale-dependent mappings.
+ * @param locCache Initialize to 0; may be used to cache the result of parsing
+ *                 the locale ID for subsequent calls.
+ *                 Can be NULL.
+ * @return Output code point or string length, see UCASE_MAX_STRING_LENGTH.
+ *
+ * @see UCaseContextIterator
+ * @see UCASE_MAX_STRING_LENGTH
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+ucase_toFullLower(const UCaseProps *csp, UChar32 c,
+                  UCaseContextIterator *iter, void *context,
+                  const UChar **pString,
+                  const char *locale, int32_t *locCache);
+
+U_CAPI int32_t U_EXPORT2
+ucase_toFullUpper(const UCaseProps *csp, UChar32 c,
+                  UCaseContextIterator *iter, void *context,
+                  const UChar **pString,
+                  const char *locale, int32_t *locCache);
+
+U_CAPI int32_t U_EXPORT2
+ucase_toFullTitle(const UCaseProps *csp, UChar32 c,
+                  UCaseContextIterator *iter, void *context,
+                  const UChar **pString,
+                  const char *locale, int32_t *locCache);
+
+U_CAPI int32_t U_EXPORT2
+ucase_toFullFolding(const UCaseProps *csp, UChar32 c,
+                    const UChar **pString,
+                    uint32_t options);
+
+U_CFUNC int32_t U_EXPORT2
+ucase_hasBinaryProperty(UChar32 c, UProperty which);
+
+
+U_CDECL_BEGIN
+
+/**
+ * @internal
+ */
+typedef int32_t U_CALLCONV
+UCaseMapFull(const UCaseProps *csp, UChar32 c,
+             UCaseContextIterator *iter, void *context,
+             const UChar **pString,
+             const char *locale, int32_t *locCache);
+
+U_CDECL_END
+
+/* file definitions --------------------------------------------------------- */
+
+#define UCASE_DATA_NAME "ucase"
+#define UCASE_DATA_TYPE "icu"
+
+/* format "cAsE" */
+#define UCASE_FMT_0 0x63
+#define UCASE_FMT_1 0x41
+#define UCASE_FMT_2 0x53
+#define UCASE_FMT_3 0x45
+
+/* indexes into indexes[] */
+enum {
+    UCASE_IX_INDEX_TOP,
+    UCASE_IX_LENGTH,
+    UCASE_IX_TRIE_SIZE,
+    UCASE_IX_EXC_LENGTH,
+    UCASE_IX_UNFOLD_LENGTH,
+
+    UCASE_IX_MAX_FULL_LENGTH=15,
+    UCASE_IX_TOP=16
+};
+
+/* definitions for 16-bit case properties word ------------------------------ */
+
+/* 2-bit constants for types of cased characters */
+#define UCASE_TYPE_MASK     3
+enum {
+    UCASE_NONE,
+    UCASE_LOWER,
+    UCASE_UPPER,
+    UCASE_TITLE
+};
+
+#define UCASE_GET_TYPE(props) ((props)&UCASE_TYPE_MASK)
+
+#define UCASE_SENSITIVE     4
+#define UCASE_EXCEPTION     8
+
+#define UCASE_DOT_MASK      0x30
+enum {
+    UCASE_NO_DOT=0,         /* normal characters with cc=0 */
+    UCASE_SOFT_DOTTED=0x10, /* soft-dotted characters with cc=0 */
+    UCASE_ABOVE=0x20,       /* "above" accents with cc=230 */
+    UCASE_OTHER_ACCENT=0x30 /* other accent character (0<cc!=230) */
+};
+
+/* no exception: bits 15..6 are a 10-bit signed case mapping delta */
+#define UCASE_DELTA_SHIFT   6
+#define UCASE_DELTA_MASK    0xffc0
+#define UCASE_MAX_DELTA     0x1ff
+#define UCASE_MIN_DELTA     (-UCASE_MAX_DELTA-1)
+
+#define UCASE_GET_DELTA(props) ((int16_t)(props)>>UCASE_DELTA_SHIFT)
+
+/* case-ignorable uses one of the delta bits, see gencase/store.c */
+#define UCASE_CASE_IGNORABLE 0x40
+
+/* exception: bits 15..4 are an unsigned 12-bit index into the exceptions array */
+#define UCASE_EXC_SHIFT     4
+#define UCASE_EXC_MASK      0xfff0
+#define UCASE_MAX_EXCEPTIONS 0x1000
+
+/* definitions for 16-bit main exceptions word ------------------------------ */
+
+/* first 8 bits indicate values in optional slots */
+enum {
+    UCASE_EXC_LOWER,
+    UCASE_EXC_FOLD,
+    UCASE_EXC_UPPER,
+    UCASE_EXC_TITLE,
+    UCASE_EXC_4,            /* reserved */
+    UCASE_EXC_5,            /* reserved */
+    UCASE_EXC_CLOSURE,
+    UCASE_EXC_FULL_MAPPINGS,
+    UCASE_EXC_ALL_SLOTS     /* one past the last slot */
+};
+
+/* each slot is 2 uint16_t instead of 1 */
+#define UCASE_EXC_DOUBLE_SLOTS      0x100
+
+/* reserved: exception bits 10..9 */
+
+#define UCASE_EXC_CASE_IGNORABLE        0x800
+
+/* UCASE_EXC_DOT_MASK=UCASE_DOT_MASK<<UCASE_EXC_DOT_SHIFT */
+#define UCASE_EXC_DOT_SHIFT     8
+
+/* normally stored in the main word, but pushed out for larger exception indexes */
+#define UCASE_EXC_DOT_MASK      0x3000
+enum {
+    UCASE_EXC_NO_DOT=0,
+    UCASE_EXC_SOFT_DOTTED=0x1000,
+    UCASE_EXC_ABOVE=0x2000,         /* "above" accents with cc=230 */
+    UCASE_EXC_OTHER_ACCENT=0x3000   /* other character (0<cc!=230) */
+};
+
+/* complex/conditional mappings */
+#define UCASE_EXC_CONDITIONAL_SPECIAL   0x4000
+#define UCASE_EXC_CONDITIONAL_FOLD      0x8000
+
+/* definitions for lengths word for full case mappings */
+#define UCASE_FULL_LOWER    0xf
+#define UCASE_FULL_FOLDING  0xf0
+#define UCASE_FULL_UPPER    0xf00
+#define UCASE_FULL_TITLE    0xf000
+
+/* maximum lengths */
+#define UCASE_FULL_MAPPINGS_MAX_LENGTH (4*0xf)
+#define UCASE_CLOSURE_MAX_LENGTH 0xf
+
+/* constants for reverse case folding ("unfold") data */
+enum {
+    UCASE_UNFOLD_ROWS,
+    UCASE_UNFOLD_ROW_WIDTH,
+    UCASE_UNFOLD_STRING_WIDTH
+};
+
+U_CDECL_END
+
+#endif
diff --git a/source/common/ucase_props_data.c b/source/common/ucase_props_data.c
new file mode 100644
index 0000000..db35d0a
--- /dev/null
+++ b/source/common/ucase_props_data.c
@@ -0,0 +1,733 @@
+/*
+ * Copyright (C) 1999-2010, International Business Machines
+ * Corporation and others.  All Rights Reserved.
+ *
+ * file name: ucase_props_data.c
+ *
+ * machine-generated on: 2010-09-19
+ */
+
+static const UVersionInfo ucase_props_dataVersion={6,0,0,0};
+
+static const int32_t ucase_props_indexes[UCASE_IX_TOP]={0x10,0x5654,0x4918,0x50c,0x172,0,0,0,0,0,0,0,0,0,0,3};
+
+static const uint16_t ucase_props_trieIndex[9348]={
+0x2c2,0x2ca,0x2d2,0x2da,0x2e8,0x2f0,0x2f8,0x300,0x308,0x310,0x317,0x31f,0x327,0x32f,0x337,0x33f,
+0x345,0x34d,0x355,0x35d,0x365,0x36d,0x375,0x37d,0x385,0x38d,0x395,0x39d,0x3a5,0x3ad,0x3b5,0x3bd,
+0x3c5,0x3cd,0x3d1,0x3d9,0x3e1,0x3e9,0x3f1,0x3f9,0x3f7,0x3ff,0x404,0x40c,0x413,0x41b,0x423,0x42b,
+0x433,0x43b,0x443,0x44b,0x2e1,0x2e9,0x450,0x458,0x45d,0x465,0x46d,0x475,0x474,0x47c,0x481,0x489,
+0x490,0x497,0x49b,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x4a3,0x4a5,0x4ad,0x4b5,0x4b9,0x4ba,0x4c2,0x4ca,
+0x4d2,0x4ba,0x4da,0x4df,0x4d2,0x4ba,0x4e7,0x4ca,0x4b9,0x4eb,0x4f3,0x4ca,0x4f8,0x2e1,0x500,0x2e1,
+0x2e1,0x476,0x508,0x4ca,0x2e1,0x4eb,0x50f,0x4ca,0x2e1,0x2e1,0x4c2,0x4ca,0x2e1,0x2e1,0x515,0x2e1,
+0x2e1,0x51b,0x522,0x2e1,0x2e1,0x526,0x52e,0x2e1,0x532,0x539,0x2e1,0x540,0x548,0x54f,0x557,0x2e1,
+0x2e1,0x55c,0x564,0x56c,0x574,0x57c,0x584,0x429,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x586,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x58e,0x58e,0x4c6,0x4c6,0x2e1,0x594,0x59c,0x2e1,
+0x5a4,0x2e1,0x5ac,0x2e1,0x2e1,0x5b2,0x2e1,0x2e1,0x2e1,0x5ba,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x5c1,0x2e1,0x5c8,0x5d0,0x2e1,0x5ab,0x2e1,0x2e1,0x5d8,0x5db,0x5e3,0x5e9,0x5f1,0x5f9,0x2e1,0x600,
+0x2e1,0x605,0x2e1,0x60b,0x2e1,0x2e1,0x613,0x61b,0x623,0x628,0x62b,0x633,0x63b,0x642,0x64a,0x651,
+0x308,0x659,0x308,0x661,0x664,0x308,0x66c,0x308,0x674,0x67c,0x684,0x68c,0x694,0x69c,0x6a4,0x6ac,
+0x6b4,0x6bb,0x2e1,0x6c3,0x6cb,0x2e1,0x6d3,0x6db,0x6e3,0x6eb,0x6f3,0x6fb,0x703,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x706,0x70c,0x712,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x71a,0x71f,0x723,0x72b,0x308,0x308,0x308,0x733,0x73b,0x743,0x2e1,0x748,0x2e1,0x2e1,0x2e1,0x750,
+0x2e1,0x5a9,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x4b8,0x758,0x2e1,0x2e1,0x75f,0x2e1,0x2e1,0x767,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x76f,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x60b,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x775,0x2e1,0x308,0x77d,0x3fb,0x2e1,0x2e1,0x785,0x78d,0x795,0x308,0x79a,0x7a2,0x7aa,0x2e1,0x7ad,
+0x7b5,0x4d1,0x2e1,0x2e1,0x2e1,0x2e1,0x7bc,0x7c4,0x2e1,0x7cb,0x7d2,0x2e1,0x4a3,0x7d7,0x7df,0x2e1,
+0x2e1,0x7e5,0x7ed,0x7f1,0x2e1,0x7f6,0x7fe,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x804,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x80c,0x2e1,0x2e1,0x2e1,0x2e1,0x814,0x5f1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x819,0x821,0x825,0x2e1,0x2e1,0x2e1,0x2e1,0x2c4,0x2ca,0x82d,0x835,0x7f1,0x476,0x2e1,0x2e1,0x83d,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0xb88,0xb88,0xba0,0xbe0,0xc20,0xc5c,0xc9c,0xcdc,0xd14,0xd54,0xd94,0xdd4,0xe14,0xe54,0xe94,0xed4,
+0xf14,0xf44,0xf84,0xfc4,0xfdc,0x1010,0x104c,0x108c,0x10cc,0x110c,0xb84,0x1140,0x1174,0x11b4,0x11d0,0x1204,
+0x9e1,0xa11,0xa51,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0xa86,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
+0xac6,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x5ad,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x845,0x84b,0x84f,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x857,0x85b,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x4b9,0x863,0x86a,0x2e1,0x5f1,0x86e,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x876,0x87e,0x884,0x2e1,0x2e1,0x2e1,0x2e1,0x88c,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x894,0x89c,0x8a1,0x8a7,0x8af,0x8b7,0x8bf,0x898,0x8c7,0x8cf,
+0x8d7,0x8de,0x899,0x894,0x89c,0x897,0x8a7,0x89a,0x895,0x8e6,0x898,0x8ee,0x8f6,0x8fe,0x905,0x8f1,
+0x8f9,0x901,0x908,0x8f4,0x910,0x2e1,0x4b9,0x78d,0x78d,0x78d,0x2e1,0x2e1,0x2e1,0x2e1,0x78d,0x78d,
+0x78d,0x78d,0x78d,0x78d,0x78d,0x918,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,
+0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2e1,0x2c1,0x2c1,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,0x40,
+0,0,0,0,0,0,0x40,0,0,0,0,0,0,0,0,0,
+0,0,0x40,0,0,0,0,0,0,0x806,0x806,0x806,0x806,0x806,0x806,0x806,
+0x806,0xe,0x5e,0x7e,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0xbe,0x806,0x806,0x806,0x806,
+0x806,0x806,0x806,0,0,0,0x40,0,0x40,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,
+0xf805,0xfd,0xf815,0x14d,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0x18d,0xf805,0xf805,0xf805,0xf805,
+0xf805,0xf805,0xf805,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,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x40,0,1,0,0,0x40,0,0x40,
+0,0,0,0,0x40,0x1cd,0,0x40,0x40,0,1,0,0,0,0,0,
+0x806,0x806,0x806,0x806,0x806,0x1fe,0x806,0x806,0x806,0x806,0x806,0x806,0x23e,0x25e,0x806,0x806,
+0x806,0x806,0x806,0x806,0x806,0x806,0x806,0,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x27d,
+0xf805,0xf805,0xf805,0xf805,0xf805,0x31d,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,
+0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0x1e45,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x35e,0xffc5,0x46,0xffc5,0x46,0xffc5,0x37e,0xffd5,
+0x39e,0x3ed,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,1,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,
+0xffc5,0x46,0xffc5,0x46,0xffc5,0x43d,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0xe1c6,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x4bd,0x30c5,0x3486,0x46,0xffc5,
+0x46,0xffc5,0x3386,0x46,0xffc5,0x3346,0x3346,0x46,0xffc5,1,0x13c6,0x3286,0x32c6,0x46,0xffc5,0x3346,
+0x33c6,0x1845,0x34c6,0x3446,0x46,0xffc5,0x28c5,1,0x34c6,0x3546,0x2085,0x3586,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x3686,0x46,0xffc5,0x3686,1,1,0x46,0xffc5,0x3686,0x46,0xffc5,0x3646,0x3646,0x46,
+0xffc5,0x46,0xffc5,0x36c6,0x46,0xffc5,1,0,0x46,0xffc5,1,0xe05,0,0,0,0,
+0x4ee,0x51f,0x55d,0x58e,0x5bf,0x5fd,0x62e,0x65f,0x69d,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,
+0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0xec45,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x6cd,0x74e,0x77f,0x7bd,
+0x46,0xffc5,0xe7c6,0xf206,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0xdf86,1,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,1,1,1,1,1,1,0x7ee,0x46,
+0xffc5,0xd746,0x80e,0x82d,0x84d,0x46,0xffc5,0xcf46,0x1146,0x11c6,0x46,0xffc5,0x46,0xffd5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x86d,0x88d,0x8ad,0xcb85,0xcc85,1,0xccc5,0xccc5,1,0xcd85,1,0xcd45,
+1,1,1,1,0xccc5,1,1,0xcc45,1,0x8cd,1,1,0xcbd5,0xcb45,1,0x8ed,
+1,1,1,0xcb45,1,0x90d,0xcac5,1,1,0xca85,1,1,1,1,1,1,
+1,0x92d,1,1,0xc985,1,1,0xc985,1,1,1,1,0xc985,0xeec5,0xc9c5,0xc9c5,
+0xee45,1,1,1,1,1,0xc945,1,0,1,1,1,1,1,1,1,
+1,0x11,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,0x949,0x949,0x959,0x949,0x949,0x949,0x949,0x949,0x949,0x40,0x40,0x40,
+0x44,0x40,0x44,0x40,0x949,0x949,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+0x40,0x40,0x40,0x40,0x949,0x949,0x949,0x949,0x949,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+0x40,0x40,0x40,0x40,0x64,0x64,0x60,0x60,0x60,0x60,0x60,0x96c,0x64,0x60,0x64,0x60,
+0x64,0x60,0x60,0x60,0x60,0x60,0x60,0x64,0x60,0x70,0x70,0x70,0x70,0x70,0x70,0x70,
+0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,
+0x70,0x70,0x70,0x70,0x70,0x74,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,
+0x70,0x60,0x60,0x60,0x60,0x60,0x64,0x60,0x60,0x97d,0x60,0x70,0x70,0x70,0x60,0x60,
+0x60,0x70,0x70,0x40,0x60,0x60,0x60,0x70,0x70,0x70,0x70,0x60,0x70,0x70,0x70,0x60,
+0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,
+0x60,0x60,0x60,0x60,0x46,0xffc5,0x46,0xffc5,0x40,0x40,0x46,0xffc5,0,0,0x949,0x2085,
+0x2085,0x2085,0,0,0,0,0,0,0x40,0x40,0x986,0x40,0x946,0x946,0x946,0,
+0x1006,0,0xfc6,0xfc6,0x9cd,0x806,0xa9e,0x806,0x806,0xade,0x806,0x806,0xb1e,0xb6e,0xbbe,0x806,
+0xbfe,0x806,0x806,0x806,0xc3e,0xc7e,0,0xcbe,0x806,0x806,0xcfe,0x806,0x806,0xd3e,0x806,0x806,
+0xf685,0xf6c5,0xf6c5,0xf6c5,0xd7d,0xf805,0xe4d,0xf805,0xf805,0xe8d,0xf805,0xf805,0xecd,0xf1d,0xf6d,0xf805,
+0xfad,0xf805,0xf805,0xf805,0xfed,0x102d,0x106d,0x109d,0xf805,0xf805,0x10dd,0xf805,0xf805,0x111d,0xf805,0xf805,
+0xf005,0xf045,0xf045,0x206,0x115d,0x118d,2,2,2,0x11dd,0x120d,0xfe05,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x123d,0x126d,0x1c5,0x11,0x129e,0x12ed,0,0x46,0xffc5,0xfe46,0x46,0xffc5,
+1,0xdf86,0xdf86,0xdf86,0x1406,0x1406,0x1406,0x1406,0x1406,0x1406,0x1406,0x1406,0x1406,0x1406,0x1406,0x1406,
+0x1406,0x1406,0x1406,0x1406,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,
+0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,
+0x806,0x806,0x806,0x806,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,
+0xf805,0xf805,0xf805,0xf805,0xec05,0xec05,0xec05,0xec05,0xec05,0xec05,0xec15,0xec05,0xec15,0xec05,0xec05,0xec05,
+0xec05,0xec05,0xec05,0xec05,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0,0x60,0x60,0x60,0x60,0x60,0x40,0x40,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x3c6,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,
+0xffc5,0x46,0xffc5,0xfc45,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0,0,0,0,0,0,0,0,0,0xc06,0xc06,0xc06,
+0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,
+0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0,0,0x40,0,0,0,0,0,0,
+0,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,
+0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,
+0xf405,0xf405,0xf405,0x131d,0,0,0,0,0,0,0,0,0,0x70,0x60,0x60,
+0x60,0x60,0x70,0x60,0x60,0x60,0x70,0x70,0x60,0x60,0x60,0x60,0x60,0x60,0x70,0x70,
+0x70,0x70,0x70,0x70,0x60,0x60,0x70,0x60,0x60,0x70,0x70,0x60,0x70,0x70,0x70,0x70,
+0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0,0x70,0,0x70,0x70,0,
+0x60,0x70,0,0x70,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,
+0x40,0,0,0,0,0,0,0,0,0,0,0,0x40,0x40,0x40,0x40,
+0,0,0,0,0,0,0,0,0,0,0,0,0x60,0x60,0x60,0x60,
+0x60,0x60,0x60,0x60,0x70,0x70,0x70,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,0x40,0,0,0,
+0,0,0,0,0,0,0,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x60,
+0x60,0x70,0x70,0x60,0x60,0x60,0x60,0x60,0x70,0x60,0x60,0x70,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0x70,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,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x40,0,0x60,
+0x60,0x60,0x60,0x70,0x60,0x40,0x40,0x60,0x60,0,0x70,0x60,0x60,0x70,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x40,0,0x70,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,0x60,0x70,0x60,0x60,0x70,0x60,0x60,0x70,0x70,0x70,0x60,0x70,
+0x70,0x60,0x70,0x60,0x60,0x60,0x70,0x60,0x70,0x60,0x70,0x60,0x70,0x60,0x60,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,0,
+0,0,0,0,0,0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+0x40,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,0x60,
+0x60,0x60,0x60,0x60,0x60,0x60,0x70,0x60,0x40,0x40,0,0,0,0,0x40,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x60,0x60,0x60,0x60,0x40,0x60,0x60,0x60,0x60,0x60,
+0x40,0x60,0x60,0x60,0x40,0x60,0x60,0x60,0x60,0x60,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,0x70,0x70,0x70,0,0,0,0,0x40,0x40,0x40,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,0x40,0,
+0x70,0,0,0,0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0,0,0,
+0,0x70,0,0,0,0x60,0x70,0x60,0x60,0x40,0x40,0x40,0,0,0,0,
+0,0,0,0,0,0,0x40,0x40,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0x40,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,0x70,0,0,0,0,0x40,0x40,0x40,0x40,0,0,0,
+0,0,0,0,0,0x70,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0x40,0x40,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,0x40,0x40,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,0x40,0x40,0,0,0,0,0x40,
+0x40,0,0,0x40,0x40,0x70,0,0,0,0x40,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0x40,0x40,0,0,
+0,0x40,0,0,0,0,0,0,0,0,0,0,0,0x40,0x40,0x40,
+0x40,0x40,0,0x40,0x40,0,0,0,0,0x70,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,0x70,0,0,0x40,0,0x40,0x40,0x40,
+0x40,0,0,0,0,0,0,0,0,0x70,0,0,0,0,0,0,
+0,0,0x40,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,
+0x40,0,0,0,0,0,0,0,0,0,0,0,0,0x70,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x40,0,0,0,0,0,0x40,0x40,0x40,0,0x40,0x40,0x40,0x70,0,0,
+0,0,0,0,0,0x70,0x70,0,0,0,0,0,0,0,0,0,
+0,0,0x40,0,0,0,0,0,0x40,0x70,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x70,0,
+0,0,0,0,0,0,0x40,0x40,0x40,0,0x40,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0x40,0,0,
+0x40,0x40,0x40,0x40,0x70,0x70,0x70,0,0,0,0,0,0,0,0x40,0x40,
+0x70,0x70,0x70,0x70,0x40,0x40,0x40,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x40,0,0,0x40,0x40,0x40,0x40,
+0x70,0x70,0,0x40,0x40,0,0,0,0,0,0,0,0,0,0x40,0,
+0x70,0x70,0x70,0x70,0x40,0x40,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,
+0x70,0x70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x70,0,0x70,0,0x70,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0x70,0x70,0x40,0x70,0x40,0x40,0x40,0x40,0x40,0x70,0x70,0x70,0x70,0x40,0,
+0x70,0x40,0x60,0x60,0x70,0,0x60,0x60,0,0,0,0,0,0x40,0x40,0x40,
+0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0,0,0,0,0,0,0,
+0,0,0x70,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,0x40,0x40,0x40,
+0x40,0,0x40,0x40,0x40,0x40,0x40,0x70,0,0x70,0x70,0,0,0x40,0x40,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,0x40,0x40,0,0,0,0,0x40,0x40,
+0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0x40,0x40,0x40,0x40,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0x40,0,0,0x40,0x40,0,0,0,0,0,0,0x70,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0x40,0,0,
+0x139e,0x13be,0x13de,0x13fe,0x141e,0x143e,0x145e,0x147e,0x149e,0x14be,0x14de,0x14fe,0x151e,0x153e,0x155e,0x157e,
+0x159e,0x15be,0x15de,0x15fe,0x161e,0x163e,0x165e,0x167e,0x169e,0x16be,0x16de,0x16fe,0x171e,0x173e,0x175e,0x177e,
+0x179e,0x17be,0x17de,0x17fe,0x181e,0x183e,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,0x60,0x60,0x60,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0x40,0x40,0x70,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x40,0x40,0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0,0,
+0,0,0,0,0,0,0x40,0,0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+0x40,0x40,0x70,0x40,0,0,0,0x40,0,0,0,0,0,0x60,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0x40,0x40,0x40,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x40,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,0x70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x40,0x40,0x40,0,0,0,0,0x40,
+0x40,0,0,0,0,0,0,0,0,0,0x40,0,0,0,0,0,
+0,0x70,0x60,0x70,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0x60,0x70,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,0x40,0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0,
+0x70,0,0x40,0,0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0,0,0,
+0,0,0,0x40,0x40,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0,0,0x70,
+0x40,0x40,0x40,0x40,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,
+0x70,0,0x40,0x40,0x40,0x40,0x40,0,0x40,0,0,0,0,0,0x40,0,
+0x30,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,0x60,
+0x70,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0,0,0,0,0,0,0,0,
+0,0,0,0,0x40,0x40,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,0x40,0x40,0x40,0x40,0,0,0x40,0x40,0x30,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x70,0,0x40,0x40,0,0,0,0x40,0,0x40,
+0x40,0x40,0x30,0x30,0,0,0,0,0,0,0,0,0,0,0,0,
+0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0,0,0x40,0x70,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x40,0x40,0x40,0x40,0x40,0x40,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0x60,0x60,0x60,0,
+0x70,0x70,0x70,0x70,0x70,0x70,0x60,0x60,0x70,0x70,0x70,0x70,0x60,0,0x70,0x70,
+0x70,0x70,0x70,0x70,0x70,0,0,0,0,0x70,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,0x949,0x949,0x949,0x949,
+0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,
+0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x11,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,0x949,0x185d,1,1,1,0x187d,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,0x11,1,1,1,1,0x949,0x949,0x949,0x949,0x949,0x959,0x949,0x949,0x949,
+0x959,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,
+0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x949,0x60,0x60,0x70,0x60,0x60,0x60,0x60,0x60,
+0x60,0x60,0x70,0x60,0x60,0x70,0x70,0x70,0x70,0x60,0x60,0x60,0x60,0x60,0x60,0x60,
+0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x70,0x70,0x60,0x70,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffd5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x189e,0x18dd,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x191d,0x199d,0x1a1d,0x1a9d,0x1b1d,0x1b9d,1,1,0x1bce,1,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffd5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x205,0x205,0x205,0x205,0x205,0x205,0x205,0x205,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,
+0x205,0x205,0x205,0x205,0x205,0x205,0,0,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,0,0,
+0x205,0x205,0x205,0x205,0x205,0x205,0x205,0x205,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,
+0x205,0x205,0x205,0x205,0x205,0x205,0x205,0x205,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,
+0x205,0x205,0x205,0x205,0x205,0x205,0,0,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,0,0,
+0x1c1d,0x205,0x1c9d,0x205,0x1d4d,0x205,0x1dfd,0x205,0,0xfe06,0,0xfe06,0,0xfe06,0,0xfe06,
+0x205,0x205,0x205,0x205,0x205,0x205,0x205,0x205,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,0xfe06,
+0x1285,0x1285,0x1585,0x1585,0x1585,0x1585,0x1905,0x1905,0x2005,0x2005,0x1c05,0x1c05,0x1f85,0x1f85,0,0,
+0x1ead,0x1f1d,0x1f8d,0x1ffd,0x206d,0x20dd,0x214d,0x21bd,0x222f,0x229f,0x230f,0x237f,0x23ef,0x245f,0x24cf,0x253f,
+0x25ad,0x261d,0x268d,0x26fd,0x276d,0x27dd,0x284d,0x28bd,0x292f,0x299f,0x2a0f,0x2a7f,0x2aef,0x2b5f,0x2bcf,0x2c3f,
+0x2cad,0x2d1d,0x2d8d,0x2dfd,0x2e6d,0x2edd,0x2f4d,0x2fbd,0x302f,0x309f,0x310f,0x317f,0x31ef,0x325f,0x32cf,0x333f,
+0x205,0x205,0x33ad,0x342d,0x349d,0,0x351d,0x359d,0xfe06,0xfe06,0xed86,0xed86,0x364f,0x40,0x36bd,0x40,
+0x40,0x40,0x370d,0x378d,0x37fd,0,0x387d,0x38fd,0xea86,0xea86,0xea86,0xea86,0x39af,0x40,0x40,0x40,
+0x205,0x205,0x3a1d,0x3acd,0,0,0x3b9d,0x3c1d,0xfe06,0xfe06,0xe706,0xe706,0,0x40,0x40,0x40,
+0x205,0x205,0x3ccd,0x3d7d,0x3e4d,0x1c5,0x3ecd,0x3f4d,0xfe06,0xfe06,0xe406,0xe406,0xfe46,0x40,0x40,0x40,
+0,0,0x3ffd,0x407d,0x40ed,0,0x416d,0x41ed,0xe006,0xe006,0xe086,0xe086,0x429f,0x40,0x40,0,
+0,0,0,0,0,0,0,0,0,0,0,0x40,0x40,0x40,0x40,0x40,
+0,0,0,0,0,0,0,0,0x40,0x40,0,0,0,0,0,0,
+0x40,0,0,0x40,0,0,0x40,0x40,0x40,0x40,0x40,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0x40,0x40,0x40,0x40,
+0x40,0,0,0,0,0,0x40,0x40,0x40,0x40,0x40,0x40,0,0x50,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0x40,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0x949,0x949,0x949,0x949,
+0x949,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0x60,0x60,0x70,0x70,
+0x60,0x60,0x60,0x60,0x70,0x70,0x70,0x60,0x60,0x40,0x40,0x40,0x40,0x60,0x40,0x40,
+0x40,0x70,0x70,0x60,0x70,0x60,0x70,0x70,0x70,0x70,0x70,0x70,0x60,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,
+0,0,0,2,0,0,1,2,2,2,1,1,2,2,2,1,
+0,2,0,0,0,2,2,2,2,2,0,0,0,0,0,0,
+2,0,0x430e,0,2,0,0x434e,0x438e,2,2,0,1,2,2,0x706,2,
+1,0,0,0,0,1,0,0,1,1,2,2,0,0,0,0,
+0,2,1,1,0x11,0x11,0,0,0,0,0xf905,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0x406,0x406,0x406,0x406,
+0x406,0x406,0x406,0x406,0x406,0x406,0x406,0x406,0x406,0x406,0x406,0x406,0xfc05,0xfc05,0xfc05,0xfc05,
+0xfc05,0xfc05,0xfc05,0xfc05,0xfc05,0xfc05,0xfc05,0xfc05,0xfc05,0xfc05,0xfc05,0xfc05,0,0,0,0x46,
+0xffc5,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,0x686,0x686,
+0x686,0x686,0x686,0x686,0x686,0x686,0x686,0x686,0x686,0x686,0x686,0x686,0x686,0x686,0x686,0x686,
+0xf985,0xf985,0xf985,0xf985,0xf985,0xf985,0xf985,0xf985,0xf985,0xf985,0xf985,0xf985,0xf985,0xf985,0xf985,0xf985,
+0xf985,0xf985,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,
+0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,
+0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0,0xf405,0xf405,0xf405,0xf405,
+0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,
+0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0xf405,0,0x46,0xffc5,0x43ce,0x43ee,
+0x440e,0x442d,0x444d,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x446e,0x448e,0x44ae,0x44ce,1,0x46,0xffc5,
+1,0x46,0xffc5,1,1,1,1,1,0x11,0x949,0x44ee,0x450e,0x46,0xffc5,0x46,0xffc5,
+1,0,0,0,0,0,0,0x46,0xffc5,0x46,0xffc5,0x60,0x60,0x60,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0x452d,0x454d,0x456d,0x458d,
+0x45ad,0x45cd,0x45ed,0x460d,0x462d,0x464d,0x466d,0x468d,0x46ad,0x46cd,0x46ed,0x470d,0x472d,0x474d,0x476d,0x478d,
+0x47ad,0x47cd,0x47ed,0x480d,0x482d,0x484d,0x486d,0x488d,0x48ad,0x48cd,0x48ed,0x490d,0x492d,0x494d,0x496d,0x498d,
+0x49ad,0x49cd,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,0x40,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x70,
+0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,
+0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,
+0,0,0,0,0,0,0,0,0,0,0x70,0x70,0x70,0x70,0x70,0x70,
+0,0x40,0x40,0x40,0x40,0x40,0,0,0,0,0,0x40,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,0x70,0x70,0x40,0x40,0x40,0x40,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,0x40,0x40,0x40,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0,0x60,0x40,0x40,0x40,0,0,0,0,0,0,0,0,0,
+0x60,0x60,0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x60,0x60,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+0x40,0x40,0x40,0x40,0x40,0x40,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,1,1,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x949,1,1,1,1,1,1,1,
+1,0x46,0xffc5,0x46,0xffc5,0x49ee,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x40,0x40,0x40,0x46,0xffc5,0x4a0e,1,0,0x46,0xffc5,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,0x46,0xffc5,
+0x46,0xffc5,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,1,0,
+0,0,0,0,0,0,0x40,0,0,0,0x70,0,0,0,0,0x40,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x70,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,
+0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,
+0x60,0x60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0x40,0x40,0x40,0x40,0x40,0x70,0x70,0x70,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x40,
+0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0,0x30,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x70,
+0,0,0x40,0x40,0x40,0x40,0,0,0x40,0,0,0,0x30,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0x40,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0x40,0x40,0x40,
+0x40,0x40,0x40,0,0,0x40,0x40,0,0,0x40,0x40,0,0,0,0,0,
+0,0,0,0,0,0,0,0x40,0,0,0,0,0,0,0,0,
+0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x40,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x60,0,0x60,0x60,0x70,0,0,0x60,
+0x60,0,0,0,0,0,0x60,0x60,0,0x60,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,0x40,0,0,0x40,0,0,0,0,0x70,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x4a2d,0x4aad,0x4b2d,0x4bad,0x4c5d,0x4d0d,0x4dad,0,0,0,0,0,0,0,0,0,
+0,0,0,0x4e4d,0x4ecd,0x4f4d,0x4fcd,0x504d,0,0,0,0,0,0,0x70,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+0x40,0x40,0x40,0x40,0,0,0,0x40,0,0,0,0,0,0,0,0,
+0,0,0,0,0x60,0x60,0x60,0x60,0x60,0x60,0x60,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,0x40,0,0,0x40,0,0,0,0,0,0,
+0,0,0,0,0,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,
+0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0x806,0,
+0,0,0x40,0,0x40,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,
+0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0xf805,0,
+0,0,0,0,0,0,0,0x40,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0x40,0x40,0x40,
+0,0,0,0,0xa06,0xa06,0xa06,0xa06,0xa06,0xa06,0xa06,0xa06,0xa06,0xa06,0xa06,0xa06,
+0xa06,0xa06,0xa06,0xa06,0xa06,0xa06,0xa06,0xa06,0xa06,0xa06,0xa06,0xa06,0xa06,0xa06,0xa06,0xa06,
+0xa06,0xa06,0xa06,0xa06,0xf605,0xf605,0xf605,0xf605,0xf605,0xf605,0xf605,0xf605,0xf605,0xf605,0xf605,0xf605,
+0xf605,0xf605,0xf605,0xf605,0xf605,0xf605,0xf605,0xf605,0xf605,0xf605,0xf605,0xf605,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0x40,0x40,0x40,
+0,0x40,0x40,0,0,0,0,0,0x40,0x70,0x40,0x60,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x60,0x70,0x70,0,0,0,0,0x70,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x70,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,0x40,0x40,0x40,0x40,0,
+0,0x70,0x70,0,0,0x40,0,0,0,0,0,0,0,0x30,0x30,0x70,
+0x70,0x70,0,0,0,0x30,0x30,0x30,0x30,0x30,0x30,0x40,0x40,0x40,0x40,0x40,
+0x40,0x40,0x40,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0,0,0x60,0x60,0x60,
+0x60,0x60,0x70,0x70,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0x60,0x60,0x60,0x60,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0x60,0x60,0x60,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,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,
+1,1,0x11,0x11,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,1,1,1,1,1,1,1,0,0x11,0x11,1,1,1,1,
+1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,
+1,1,1,1,1,1,0x11,0x11,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,2,0,2,2,0,0,2,0,
+0,2,2,0,0,2,2,2,2,0,2,2,2,2,2,2,
+2,2,1,1,1,1,0,1,0,1,0x11,0x11,1,1,1,1,
+0,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,
+2,2,0,2,2,2,2,0,0,2,2,2,2,2,2,2,
+2,0,2,2,2,2,2,2,2,0,1,1,1,1,1,1,
+1,1,0x11,0x11,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,2,2,0,2,2,2,2,0,2,2,2,2,
+2,0,2,0,0,0,2,2,2,2,2,2,2,0,1,1,
+1,1,1,1,1,1,0x11,0x11,1,1,1,1,1,1,1,1,
+1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,1,1,1,1,1,1,0,0,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,0,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,0,1,1,1,1,1,1,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,0,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+1,1,1,0,1,1,1,1,1,1,2,1,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0
+};
+
+static const uint16_t ucase_props_exceptions[1292]={
+0xc041,0x69,2,0x130,0x131,0x4001,0x6a,0x41,0x6b,1,0x212a,0x41,0x73,1,0x17f,0x5044,
+0x49,2,0x130,0x131,0x44,0x4b,1,0x212a,0x44,0x53,1,0x17f,6,0x3bc,0x39c,0x41,
+0xe5,1,0x212b,0x4001,0xec,0x4001,0xed,0xc0,1,0x2220,0x73,0x73,0x53,0x53,0x53,0x73,
+0x1e9e,0x44,0xc5,1,0x212b,0x4001,0x129,0x4001,0x12f,0xc041,0x69,2,0x131,0x49,0x44,0x49,
+2,0x69,0x130,0x80,0x2220,0x2bc,0x6e,0x2bc,0x4e,0x2bc,0x4e,6,0x73,0x53,9,0x1c6,
+0x1c5,0xd,0x1c6,0x1c4,0x1c5,0xc,0x1c4,0x1c5,9,0x1c9,0x1c8,0xd,0x1c9,0x1c7,0x1c8,0xc,
+0x1c7,0x1c8,9,0x1cc,0x1cb,0xd,0x1cc,0x1ca,0x1cb,0xc,0x1ca,0x1cb,0x80,0x2220,0x6a,0x30c,
+0x4a,0x30c,0x4a,0x30c,9,0x1f3,0x1f2,0xd,0x1f3,0x1f1,0x1f2,0xc,0x1f1,0x1f2,1,0x2c65,
+1,0x2c66,4,0x2c7e,4,0x2c7f,4,0x2c6f,4,0x2c6d,4,0x2c70,4,0xa78d,4,0x2c62,
+4,0x2c6e,4,0x2c64,0x800,0x1800,0x6800,0x3846,0x3b9,0x399,1,0x1fbe,0xc0,1,0x3330,0x3b9,
+0x308,0x301,0x399,0x308,0x301,0x399,0x308,0x301,0x1fd3,0x41,0x3b2,1,0x3d0,0x41,0x3b5,1,
+0x3f5,0x41,0x3b8,2,0x3d1,0x3f4,0x41,0x3b9,2,0x345,0x1fbe,0x41,0x3ba,1,0x3f0,0x41,
+0x3bc,1,0xb5,0x41,0x3c0,1,0x3d6,0x41,0x3c1,1,0x3f1,0x4041,0x3c3,1,0x3c2,0x41,
+0x3c6,1,0x3d5,0x41,0x3c9,1,0x2126,0xc0,1,0x3330,0x3c5,0x308,0x301,0x3a5,0x308,0x301,
+0x3a5,0x308,0x301,0x1fe3,0x44,0x392,1,0x3d0,0x44,0x395,1,0x3f5,0x44,0x398,2,0x3d1,
+0x3f4,0x44,0x399,2,0x345,0x1fbe,0x44,0x39a,1,0x3f0,0x44,0x39c,1,0xb5,0x44,0x3a0,
+1,0x3d6,0x44,0x3a1,1,0x3f1,6,0x3c3,0x3a3,0x44,0x3a3,1,0x3c2,0x44,0x3a6,1,
+0x3d5,0x44,0x3a9,1,0x2126,6,0x3b2,0x392,0x46,0x3b8,0x398,1,0x3f4,6,0x3c6,0x3a6,
+6,0x3c0,0x3a0,6,0x3ba,0x39a,6,0x3c1,0x3a1,0x41,0x3b8,2,0x398,0x3d1,6,0x3b5,
+0x395,0x80,0x2220,0x565,0x582,0x535,0x552,0x535,0x582,1,0x2d00,1,0x2d01,1,0x2d02,1,
+0x2d03,1,0x2d04,1,0x2d05,1,0x2d06,1,0x2d07,1,0x2d08,1,0x2d09,1,0x2d0a,1,
+0x2d0b,1,0x2d0c,1,0x2d0d,1,0x2d0e,1,0x2d0f,1,0x2d10,1,0x2d11,1,0x2d12,1,
+0x2d13,1,0x2d14,1,0x2d15,1,0x2d16,1,0x2d17,1,0x2d18,1,0x2d19,1,0x2d1a,1,
+0x2d1b,1,0x2d1c,1,0x2d1d,1,0x2d1e,1,0x2d1f,1,0x2d20,1,0x2d21,1,0x2d22,1,
+0x2d23,1,0x2d24,1,0x2d25,4,0xa77d,4,0x2c63,0x41,0x1e61,1,0x1e9b,0x44,0x1e60,1,
+0x1e9b,0x80,0x2220,0x68,0x331,0x48,0x331,0x48,0x331,0x80,0x2220,0x74,0x308,0x54,0x308,0x54,
+0x308,0x80,0x2220,0x77,0x30a,0x57,0x30a,0x57,0x30a,0x80,0x2220,0x79,0x30a,0x59,0x30a,0x59,
+0x30a,0x80,0x2220,0x61,0x2be,0x41,0x2be,0x41,0x2be,6,0x1e61,0x1e60,0x81,0xdf,0x20,0x73,
+0x73,0x80,0x2220,0x3c5,0x313,0x3a5,0x313,0x3a5,0x313,0x80,0x3330,0x3c5,0x313,0x300,0x3a5,0x313,
+0x300,0x3a5,0x313,0x300,0x80,0x3330,0x3c5,0x313,0x301,0x3a5,0x313,0x301,0x3a5,0x313,0x301,0x80,
+0x3330,0x3c5,0x313,0x342,0x3a5,0x313,0x342,0x3a5,0x313,0x342,0x84,0x1f88,0x220,0x1f00,0x3b9,0x1f08,
+0x399,0x84,0x1f89,0x220,0x1f01,0x3b9,0x1f09,0x399,0x84,0x1f8a,0x220,0x1f02,0x3b9,0x1f0a,0x399,0x84,
+0x1f8b,0x220,0x1f03,0x3b9,0x1f0b,0x399,0x84,0x1f8c,0x220,0x1f04,0x3b9,0x1f0c,0x399,0x84,0x1f8d,0x220,
+0x1f05,0x3b9,0x1f0d,0x399,0x84,0x1f8e,0x220,0x1f06,0x3b9,0x1f0e,0x399,0x84,0x1f8f,0x220,0x1f07,0x3b9,
+0x1f0f,0x399,0x81,0x1f80,0x220,0x1f00,0x3b9,0x1f08,0x399,0x81,0x1f81,0x220,0x1f01,0x3b9,0x1f09,0x399,
+0x81,0x1f82,0x220,0x1f02,0x3b9,0x1f0a,0x399,0x81,0x1f83,0x220,0x1f03,0x3b9,0x1f0b,0x399,0x81,0x1f84,
+0x220,0x1f04,0x3b9,0x1f0c,0x399,0x81,0x1f85,0x220,0x1f05,0x3b9,0x1f0d,0x399,0x81,0x1f86,0x220,0x1f06,
+0x3b9,0x1f0e,0x399,0x81,0x1f87,0x220,0x1f07,0x3b9,0x1f0f,0x399,0x84,0x1f98,0x220,0x1f20,0x3b9,0x1f28,
+0x399,0x84,0x1f99,0x220,0x1f21,0x3b9,0x1f29,0x399,0x84,0x1f9a,0x220,0x1f22,0x3b9,0x1f2a,0x399,0x84,
+0x1f9b,0x220,0x1f23,0x3b9,0x1f2b,0x399,0x84,0x1f9c,0x220,0x1f24,0x3b9,0x1f2c,0x399,0x84,0x1f9d,0x220,
+0x1f25,0x3b9,0x1f2d,0x399,0x84,0x1f9e,0x220,0x1f26,0x3b9,0x1f2e,0x399,0x84,0x1f9f,0x220,0x1f27,0x3b9,
+0x1f2f,0x399,0x81,0x1f90,0x220,0x1f20,0x3b9,0x1f28,0x399,0x81,0x1f91,0x220,0x1f21,0x3b9,0x1f29,0x399,
+0x81,0x1f92,0x220,0x1f22,0x3b9,0x1f2a,0x399,0x81,0x1f93,0x220,0x1f23,0x3b9,0x1f2b,0x399,0x81,0x1f94,
+0x220,0x1f24,0x3b9,0x1f2c,0x399,0x81,0x1f95,0x220,0x1f25,0x3b9,0x1f2d,0x399,0x81,0x1f96,0x220,0x1f26,
+0x3b9,0x1f2e,0x399,0x81,0x1f97,0x220,0x1f27,0x3b9,0x1f2f,0x399,0x84,0x1fa8,0x220,0x1f60,0x3b9,0x1f68,
+0x399,0x84,0x1fa9,0x220,0x1f61,0x3b9,0x1f69,0x399,0x84,0x1faa,0x220,0x1f62,0x3b9,0x1f6a,0x399,0x84,
+0x1fab,0x220,0x1f63,0x3b9,0x1f6b,0x399,0x84,0x1fac,0x220,0x1f64,0x3b9,0x1f6c,0x399,0x84,0x1fad,0x220,
+0x1f65,0x3b9,0x1f6d,0x399,0x84,0x1fae,0x220,0x1f66,0x3b9,0x1f6e,0x399,0x84,0x1faf,0x220,0x1f67,0x3b9,
+0x1f6f,0x399,0x81,0x1fa0,0x220,0x1f60,0x3b9,0x1f68,0x399,0x81,0x1fa1,0x220,0x1f61,0x3b9,0x1f69,0x399,
+0x81,0x1fa2,0x220,0x1f62,0x3b9,0x1f6a,0x399,0x81,0x1fa3,0x220,0x1f63,0x3b9,0x1f6b,0x399,0x81,0x1fa4,
+0x220,0x1f64,0x3b9,0x1f6c,0x399,0x81,0x1fa5,0x220,0x1f65,0x3b9,0x1f6d,0x399,0x81,0x1fa6,0x220,0x1f66,
+0x3b9,0x1f6e,0x399,0x81,0x1fa7,0x220,0x1f67,0x3b9,0x1f6f,0x399,0x80,0x2220,0x1f70,0x3b9,0x1fba,0x399,
+0x1fba,0x345,0x84,0x1fbc,0x220,0x3b1,0x3b9,0x391,0x399,0x80,0x2220,0x3ac,0x3b9,0x386,0x399,0x386,
+0x345,0x80,0x2220,0x3b1,0x342,0x391,0x342,0x391,0x342,0x80,0x3330,0x3b1,0x342,0x3b9,0x391,0x342,
+0x399,0x391,0x342,0x345,0x81,0x1fb3,0x220,0x3b1,0x3b9,0x391,0x399,0x46,0x3b9,0x399,1,0x345,
+0x80,0x2220,0x1f74,0x3b9,0x1fca,0x399,0x1fca,0x345,0x84,0x1fcc,0x220,0x3b7,0x3b9,0x397,0x399,0x80,
+0x2220,0x3ae,0x3b9,0x389,0x399,0x389,0x345,0x80,0x2220,0x3b7,0x342,0x397,0x342,0x397,0x342,0x80,
+0x3330,0x3b7,0x342,0x3b9,0x397,0x342,0x399,0x397,0x342,0x345,0x81,0x1fc3,0x220,0x3b7,0x3b9,0x397,
+0x399,0x80,0x3330,0x3b9,0x308,0x300,0x399,0x308,0x300,0x399,0x308,0x300,0xc0,1,0x3330,0x3b9,
+0x308,0x301,0x399,0x308,0x301,0x399,0x308,0x301,0x390,0x80,0x2220,0x3b9,0x342,0x399,0x342,0x399,
+0x342,0x80,0x3330,0x3b9,0x308,0x342,0x399,0x308,0x342,0x399,0x308,0x342,0x80,0x3330,0x3c5,0x308,
+0x300,0x3a5,0x308,0x300,0x3a5,0x308,0x300,0xc0,1,0x3330,0x3c5,0x308,0x301,0x3a5,0x308,0x301,
+0x3a5,0x308,0x301,0x3b0,0x80,0x2220,0x3c1,0x313,0x3a1,0x313,0x3a1,0x313,0x80,0x2220,0x3c5,0x342,
+0x3a5,0x342,0x3a5,0x342,0x80,0x3330,0x3c5,0x308,0x342,0x3a5,0x308,0x342,0x3a5,0x308,0x342,0x80,
+0x2220,0x1f7c,0x3b9,0x1ffa,0x399,0x1ffa,0x345,0x84,0x1ffc,0x220,0x3c9,0x3b9,0x3a9,0x399,0x80,0x2220,
+0x3ce,0x3b9,0x38f,0x399,0x38f,0x345,0x80,0x2220,0x3c9,0x342,0x3a9,0x342,0x3a9,0x342,0x80,0x3330,
+0x3c9,0x342,0x3b9,0x3a9,0x342,0x399,0x3a9,0x342,0x345,0x81,0x1ff3,0x220,0x3c9,0x3b9,0x3a9,0x399,
+0x41,0x3c9,1,0x3a9,0x41,0x6b,1,0x4b,0x41,0xe5,1,0xc5,1,0x26b,1,0x1d7d,
+1,0x27d,4,0x23a,4,0x23e,1,0x251,1,0x271,1,0x250,1,0x252,1,0x23f,
+1,0x240,4,0x10a0,4,0x10a1,4,0x10a2,4,0x10a3,4,0x10a4,4,0x10a5,4,0x10a6,
+4,0x10a7,4,0x10a8,4,0x10a9,4,0x10aa,4,0x10ab,4,0x10ac,4,0x10ad,4,0x10ae,
+4,0x10af,4,0x10b0,4,0x10b1,4,0x10b2,4,0x10b3,4,0x10b4,4,0x10b5,4,0x10b6,
+4,0x10b7,4,0x10b8,4,0x10b9,4,0x10ba,4,0x10bb,4,0x10bc,4,0x10bd,4,0x10be,
+4,0x10bf,4,0x10c0,4,0x10c1,4,0x10c2,4,0x10c3,4,0x10c4,4,0x10c5,1,0x1d79,
+1,0x265,0x80,0x2220,0x66,0x66,0x46,0x46,0x46,0x66,0x80,0x2220,0x66,0x69,0x46,0x49,
+0x46,0x69,0x80,0x2220,0x66,0x6c,0x46,0x4c,0x46,0x6c,0x80,0x3330,0x66,0x66,0x69,0x46,
+0x46,0x49,0x46,0x66,0x69,0x80,0x3330,0x66,0x66,0x6c,0x46,0x46,0x4c,0x46,0x66,0x6c,
+0xc0,1,0x2220,0x73,0x74,0x53,0x54,0x53,0x74,0xfb06,0xc0,1,0x2220,0x73,0x74,0x53,
+0x54,0x53,0x74,0xfb05,0x80,0x2220,0x574,0x576,0x544,0x546,0x544,0x576,0x80,0x2220,0x574,0x565,
+0x544,0x535,0x544,0x565,0x80,0x2220,0x574,0x56b,0x544,0x53b,0x544,0x56b,0x80,0x2220,0x57e,0x576,
+0x54e,0x546,0x54e,0x576,0x80,0x2220,0x574,0x56d,0x544,0x53d,0x544,0x56d
+};
+
+static const uint16_t ucase_props_unfold[370]={
+0x49,5,3,0,0,0x61,0x2be,0,0x1e9a,0,0x66,0x66,0,0xfb00,0,0x66,
+0x66,0x69,0xfb03,0,0x66,0x66,0x6c,0xfb04,0,0x66,0x69,0,0xfb01,0,0x66,0x6c,
+0,0xfb02,0,0x68,0x331,0,0x1e96,0,0x69,0x307,0,0x130,0,0x6a,0x30c,0,
+0x1f0,0,0x73,0x73,0,0xdf,0x1e9e,0x73,0x74,0,0xfb05,0xfb06,0x74,0x308,0,0x1e97,
+0,0x77,0x30a,0,0x1e98,0,0x79,0x30a,0,0x1e99,0,0x2bc,0x6e,0,0x149,0,
+0x3ac,0x3b9,0,0x1fb4,0,0x3ae,0x3b9,0,0x1fc4,0,0x3b1,0x342,0,0x1fb6,0,0x3b1,
+0x342,0x3b9,0x1fb7,0,0x3b1,0x3b9,0,0x1fb3,0x1fbc,0x3b7,0x342,0,0x1fc6,0,0x3b7,0x342,
+0x3b9,0x1fc7,0,0x3b7,0x3b9,0,0x1fc3,0x1fcc,0x3b9,0x308,0x300,0x1fd2,0,0x3b9,0x308,0x301,
+0x390,0x1fd3,0x3b9,0x308,0x342,0x1fd7,0,0x3b9,0x342,0,0x1fd6,0,0x3c1,0x313,0,0x1fe4,
+0,0x3c5,0x308,0x300,0x1fe2,0,0x3c5,0x308,0x301,0x3b0,0x1fe3,0x3c5,0x308,0x342,0x1fe7,0,
+0x3c5,0x313,0,0x1f50,0,0x3c5,0x313,0x300,0x1f52,0,0x3c5,0x313,0x301,0x1f54,0,0x3c5,
+0x313,0x342,0x1f56,0,0x3c5,0x342,0,0x1fe6,0,0x3c9,0x342,0,0x1ff6,0,0x3c9,0x342,
+0x3b9,0x1ff7,0,0x3c9,0x3b9,0,0x1ff3,0x1ffc,0x3ce,0x3b9,0,0x1ff4,0,0x565,0x582,0,
+0x587,0,0x574,0x565,0,0xfb14,0,0x574,0x56b,0,0xfb15,0,0x574,0x56d,0,0xfb17,
+0,0x574,0x576,0,0xfb13,0,0x57e,0x576,0,0xfb16,0,0x1f00,0x3b9,0,0x1f80,0x1f88,
+0x1f01,0x3b9,0,0x1f81,0x1f89,0x1f02,0x3b9,0,0x1f82,0x1f8a,0x1f03,0x3b9,0,0x1f83,0x1f8b,0x1f04,
+0x3b9,0,0x1f84,0x1f8c,0x1f05,0x3b9,0,0x1f85,0x1f8d,0x1f06,0x3b9,0,0x1f86,0x1f8e,0x1f07,0x3b9,
+0,0x1f87,0x1f8f,0x1f20,0x3b9,0,0x1f90,0x1f98,0x1f21,0x3b9,0,0x1f91,0x1f99,0x1f22,0x3b9,0,
+0x1f92,0x1f9a,0x1f23,0x3b9,0,0x1f93,0x1f9b,0x1f24,0x3b9,0,0x1f94,0x1f9c,0x1f25,0x3b9,0,0x1f95,
+0x1f9d,0x1f26,0x3b9,0,0x1f96,0x1f9e,0x1f27,0x3b9,0,0x1f97,0x1f9f,0x1f60,0x3b9,0,0x1fa0,0x1fa8,
+0x1f61,0x3b9,0,0x1fa1,0x1fa9,0x1f62,0x3b9,0,0x1fa2,0x1faa,0x1f63,0x3b9,0,0x1fa3,0x1fab,0x1f64,
+0x3b9,0,0x1fa4,0x1fac,0x1f65,0x3b9,0,0x1fa5,0x1fad,0x1f66,0x3b9,0,0x1fa6,0x1fae,0x1f67,0x3b9,
+0,0x1fa7,0x1faf,0x1f70,0x3b9,0,0x1fb2,0,0x1f74,0x3b9,0,0x1fc2,0,0x1f7c,0x3b9,0,
+0x1ff2,0
+};
+
+static const UCaseProps ucase_props_singleton={
+  NULL,
+  ucase_props_indexes,
+  ucase_props_exceptions,
+  ucase_props_unfold,
+  {
+    ucase_props_trieIndex,
+    ucase_props_trieIndex+2824,
+    NULL,
+    2824,
+    6524,
+    0x188,
+    0xb84,
+    0x0,
+    0x0,
+    0xe0800,
+    0x2480,
+    NULL, 0, FALSE, FALSE, 0, NULL
+  },
+  { 2,0,0,0 }
+};
diff --git a/source/common/ucasemap.c b/source/common/ucasemap.c
new file mode 100644
index 0000000..9f94235
--- /dev/null
+++ b/source/common/ucasemap.c
@@ -0,0 +1,574 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2005-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  ucasemap.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2005may06
+*   created by: Markus W. Scherer
+*
+*   Case mapping service object and functions using it.
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uloc.h"
+#include "unicode/ustring.h"
+#include "unicode/ucasemap.h"
+#if !UCONFIG_NO_BREAK_ITERATION
+#include "unicode/ubrk.h"
+#include "unicode/utext.h"
+#endif
+#include "cmemory.h"
+#include "cstring.h"
+#include "ucase.h"
+#include "ustr_imp.h"
+
+/* UCaseMap service object -------------------------------------------------- */
+
+U_CAPI UCaseMap * U_EXPORT2
+ucasemap_open(const char *locale, uint32_t options, UErrorCode *pErrorCode) {
+    UCaseMap *csm;
+
+    if(U_FAILURE(*pErrorCode)) {
+        return NULL;
+    }
+
+    csm=(UCaseMap *)uprv_malloc(sizeof(UCaseMap));
+    if(csm==NULL) {
+        return NULL;
+    }
+    uprv_memset(csm, 0, sizeof(UCaseMap));
+
+    csm->csp=ucase_getSingleton();
+    ucasemap_setLocale(csm, locale, pErrorCode);
+    if(U_FAILURE(*pErrorCode)) {
+        uprv_free(csm);
+        return NULL;
+    }
+
+    csm->options=options;
+    return csm;
+}
+
+U_CAPI void U_EXPORT2
+ucasemap_close(UCaseMap *csm) {
+    if(csm!=NULL) {
+#if !UCONFIG_NO_BREAK_ITERATION
+        ubrk_close(csm->iter);
+#endif
+        uprv_free(csm);
+    }
+}
+
+U_CAPI const char * U_EXPORT2
+ucasemap_getLocale(const UCaseMap *csm) {
+    return csm->locale;
+}
+
+U_CAPI uint32_t U_EXPORT2
+ucasemap_getOptions(const UCaseMap *csm) {
+    return csm->options;
+}
+
+U_CAPI void U_EXPORT2
+ucasemap_setLocale(UCaseMap *csm, const char *locale, UErrorCode *pErrorCode) {
+    int32_t length;
+
+    if(U_FAILURE(*pErrorCode)) {
+        return;
+    }
+
+    length=uloc_getName(locale, csm->locale, (int32_t)sizeof(csm->locale), pErrorCode);
+    if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR || length==sizeof(csm->locale)) {
+        *pErrorCode=U_ZERO_ERROR;
+        /* we only really need the language code for case mappings */
+        length=uloc_getLanguage(locale, csm->locale, (int32_t)sizeof(csm->locale), pErrorCode);
+    }
+    if(length==sizeof(csm->locale)) {
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+    csm->locCache=0;
+    if(U_SUCCESS(*pErrorCode)) {
+        ucase_getCaseLocale(csm->locale, &csm->locCache);
+    } else {
+        csm->locale[0]=0;
+    }
+}
+
+U_CAPI void U_EXPORT2
+ucasemap_setOptions(UCaseMap *csm, uint32_t options, UErrorCode *pErrorCode) {
+    csm->options=options;
+}
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+U_CAPI const UBreakIterator * U_EXPORT2
+ucasemap_getBreakIterator(const UCaseMap *csm) {
+    return csm->iter;
+}
+
+U_CAPI void U_EXPORT2
+ucasemap_setBreakIterator(UCaseMap *csm, UBreakIterator *iterToAdopt, UErrorCode *pErrorCode) {
+    ubrk_close(csm->iter);
+    csm->iter=iterToAdopt;
+}
+
+#endif
+
+/* UTF-8 string case mappings ----------------------------------------------- */
+
+/* TODO(markus): Move to a new, separate utf8case.c file. */
+
+/* append a full case mapping result, see UCASE_MAX_STRING_LENGTH */
+static U_INLINE int32_t
+appendResult(uint8_t *dest, int32_t destIndex, int32_t destCapacity,
+             int32_t result, const UChar *s) {
+    UChar32 c;
+    int32_t length, destLength;
+    UErrorCode errorCode;
+
+    /* decode the result */
+    if(result<0) {
+        /* (not) original code point */
+        c=~result;
+        length=-1;
+    } else if(result<=UCASE_MAX_STRING_LENGTH) {
+        c=U_SENTINEL;
+        length=result;
+    } else {
+        c=result;
+        length=-1;
+    }
+
+    if(destIndex<destCapacity) {
+        /* append the result */
+        if(length<0) {
+            /* code point */
+            UBool isError=FALSE;
+            U8_APPEND(dest, destIndex, destCapacity, c, isError);
+            if(isError) {
+                /* overflow, nothing written */
+                destIndex+=U8_LENGTH(c);
+            }
+        } else {
+            /* string */
+            errorCode=U_ZERO_ERROR;
+            u_strToUTF8(
+                (char *)(dest+destIndex), destCapacity-destIndex, &destLength,
+                s, length,
+                &errorCode);
+            destIndex+=destLength;
+            /* we might have an overflow, but we know the actual length */
+        }
+    } else {
+        /* preflight */
+        if(length<0) {
+            destIndex+=U8_LENGTH(c);
+        } else {
+            errorCode=U_ZERO_ERROR;
+            u_strToUTF8(
+                NULL, 0, &destLength,
+                s, length,
+                &errorCode);
+            destIndex+=destLength;
+        }
+    }
+    return destIndex;
+}
+
+static UChar32 U_CALLCONV
+utf8_caseContextIterator(void *context, int8_t dir) {
+    UCaseContext *csc=(UCaseContext *)context;
+    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;
+    }
+
+    if(dir<0) {
+        if(csc->start<csc->index) {
+            U8_PREV((const uint8_t *)csc->p, csc->start, csc->index, c);
+            return c;
+        }
+    } else {
+        if(csc->index<csc->limit) {
+            U8_NEXT((const uint8_t *)csc->p, csc->index, csc->limit, c);
+            return c;
+        }
+    }
+    return U_SENTINEL;
+}
+
+/*
+ * Case-maps [srcStart..srcLimit[ but takes
+ * context [0..srcLength[ into account.
+ */
+static int32_t
+_caseMap(const UCaseMap *csm, UCaseMapFull *map,
+         uint8_t *dest, int32_t destCapacity,
+         const uint8_t *src, UCaseContext *csc,
+         int32_t srcStart, int32_t srcLimit,
+         UErrorCode *pErrorCode) {
+    const UChar *s;
+    UChar32 c, c2 = 0;
+    int32_t srcIndex, destIndex;
+    int32_t locCache;
+
+    locCache=csm->locCache;
+
+    /* case mapping loop */
+    srcIndex=srcStart;
+    destIndex=0;
+    while(srcIndex<srcLimit) {
+        csc->cpStart=srcIndex;
+        U8_NEXT(src, srcIndex, srcLimit, c);
+        csc->cpLimit=srcIndex;
+        if(c<0) {
+            int32_t i=csc->cpStart;
+            while(destIndex<destCapacity && i<srcIndex) {
+                dest[destIndex++]=src[i++];
+            }
+            continue;
+        }
+        c=map(csm->csp, c, utf8_caseContextIterator, csc, &s, csm->locale, &locCache);
+        if((destIndex<destCapacity) && (c<0 ? (c2=~c)<=0x7f : UCASE_MAX_STRING_LENGTH<c && (c2=c)<=0x7f)) {
+            /* fast path version of appendResult() for ASCII results */
+            dest[destIndex++]=(uint8_t)c2;
+        } else {
+            destIndex=appendResult(dest, destIndex, destCapacity, c, s);
+        }
+    }
+
+    if(destIndex>destCapacity) {
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+    return destIndex;
+}
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+/*
+ * Internal titlecasing function.
+ */
+static int32_t
+_toTitle(UCaseMap *csm,
+         uint8_t *dest, int32_t destCapacity,
+         const uint8_t *src, UCaseContext *csc,
+         int32_t srcLength,
+         UErrorCode *pErrorCode) {
+    UText utext=UTEXT_INITIALIZER;
+    const UChar *s;
+    UChar32 c;
+    int32_t prev, titleStart, titleLimit, idx, destIndex, length;
+    UBool isFirstIndex;
+
+    utext_openUTF8(&utext, (const char *)src, srcLength, pErrorCode);
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(csm->iter==NULL) {
+        csm->iter=ubrk_open(UBRK_WORD, csm->locale,
+                            NULL, 0,
+                            pErrorCode);
+    }
+    ubrk_setUText(csm->iter, &utext, pErrorCode);
+    if(U_FAILURE(*pErrorCode)) {
+        utext_close(&utext);
+        return 0;
+    }
+
+    /* set up local variables */
+    destIndex=0;
+    prev=0;
+    isFirstIndex=TRUE;
+
+    /* titlecasing loop */
+    while(prev<srcLength) {
+        /* find next index where to titlecase */
+        if(isFirstIndex) {
+            isFirstIndex=FALSE;
+            idx=ubrk_first(csm->iter);
+        } else {
+            idx=ubrk_next(csm->iter);
+        }
+        if(idx==UBRK_DONE || idx>srcLength) {
+            idx=srcLength;
+        }
+
+        /*
+         * Unicode 4 & 5 section 3.13 Default Case Operations:
+         *
+         * R3  toTitlecase(X): Find the word boundaries based on Unicode Standard Annex
+         * #29, "Text Boundaries." Between each pair of word boundaries, find the first
+         * cased character F. If F exists, map F to default_title(F); then map each
+         * subsequent character C to default_lower(C).
+         *
+         * In this implementation, segment [prev..index[ into 3 parts:
+         * a) uncased characters (copy as-is) [prev..titleStart[
+         * b) first case letter (titlecase)         [titleStart..titleLimit[
+         * c) subsequent characters (lowercase)                 [titleLimit..index[
+         */
+        if(prev<idx) {
+            /* find and copy uncased characters [prev..titleStart[ */
+            titleStart=titleLimit=prev;
+            U8_NEXT(src, titleLimit, idx, c);
+            if((csm->options&U_TITLECASE_NO_BREAK_ADJUSTMENT)==0 && UCASE_NONE==ucase_getType(csm->csp, c)) {
+                /* Adjust the titlecasing index (titleStart) to the next cased character. */
+                for(;;) {
+                    titleStart=titleLimit;
+                    if(titleLimit==idx) {
+                        /*
+                         * only uncased characters in [prev..index[
+                         * stop with titleStart==titleLimit==index
+                         */
+                        break;
+                    }
+                    U8_NEXT(src, titleLimit, idx, c);
+                    if(UCASE_NONE!=ucase_getType(csm->csp, c)) {
+                        break; /* cased letter at [titleStart..titleLimit[ */
+                    }
+                }
+                length=titleStart-prev;
+                if(length>0) {
+                    if((destIndex+length)<=destCapacity) {
+                        uprv_memcpy(dest+destIndex, src+prev, length);
+                    }
+                    destIndex+=length;
+                }
+            }
+
+            if(titleStart<titleLimit) {
+                /* titlecase c which is from [titleStart..titleLimit[ */
+                csc->cpStart=titleStart;
+                csc->cpLimit=titleLimit;
+                c=ucase_toFullTitle(csm->csp, c, utf8_caseContextIterator, csc, &s, csm->locale, &csm->locCache);
+                destIndex=appendResult(dest, destIndex, destCapacity, c, s);
+
+                
+                /* Special case Dutch IJ titlecasing */
+                if ( titleStart+1 < idx && 
+                     ucase_getCaseLocale(csm->locale,&csm->locCache) == UCASE_LOC_DUTCH &&
+                     ( src[titleStart] == 0x0049 || src[titleStart] == 0x0069 ) &&
+                     ( src[titleStart+1] == 0x004A || src[titleStart+1] == 0x006A )) { 
+                            c=0x004A;
+                            destIndex=appendResult(dest, destIndex, destCapacity, c, s);
+                            titleLimit++;
+                }
+                /* lowercase [titleLimit..index[ */
+                if(titleLimit<idx) {
+                    if((csm->options&U_TITLECASE_NO_LOWERCASE)==0) {
+                        /* Normal operation: Lowercase the rest of the word. */
+                        destIndex+=
+                            _caseMap(
+                                csm, ucase_toFullLower,
+                                dest+destIndex, destCapacity-destIndex,
+                                src, csc,
+                                titleLimit, idx,
+                                pErrorCode);
+                    } else {
+                        /* Optionally just copy the rest of the word unchanged. */
+                        length=idx-titleLimit;
+                        if((destIndex+length)<=destCapacity) {
+                            uprv_memcpy(dest+destIndex, src+titleLimit, length);
+                        }
+                        destIndex+=length;
+                    }
+                }
+            }
+        }
+
+        prev=idx;
+    }
+
+    if(destIndex>destCapacity) {
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+    utext_close(&utext);
+    return destIndex;
+}
+
+#endif
+
+static int32_t
+utf8_foldCase(const UCaseProps *csp,
+              uint8_t *dest, int32_t destCapacity,
+              const uint8_t *src, int32_t srcLength,
+              uint32_t options,
+              UErrorCode *pErrorCode) {
+    int32_t srcIndex, destIndex;
+
+    const UChar *s;
+    UChar32 c, c2;
+    int32_t start;
+
+    /* case mapping loop */
+    srcIndex=destIndex=0;
+    while(srcIndex<srcLength) {
+        start=srcIndex;
+        U8_NEXT(src, srcIndex, srcLength, c);
+        if(c<0) {
+            while(destIndex<destCapacity && start<srcIndex) {
+                dest[destIndex++]=src[start++];
+            }
+            continue;
+        }
+        c=ucase_toFullFolding(csp, c, &s, options);
+        if((destIndex<destCapacity) && (c<0 ? (c2=~c)<=0x7f : UCASE_MAX_STRING_LENGTH<c && (c2=c)<=0x7f)) {
+            /* fast path version of appendResult() for ASCII results */
+            dest[destIndex++]=(uint8_t)c2;
+        } else {
+            destIndex=appendResult(dest, destIndex, destCapacity, c, s);
+        }
+    }
+
+    if(destIndex>destCapacity) {
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+    return destIndex;
+}
+
+/*
+ * Implement argument checking and buffer handling
+ * for string case mapping as a common function.
+ */
+
+/* common internal function for public API functions */
+
+static int32_t
+caseMap(const UCaseMap *csm,
+        uint8_t *dest, int32_t destCapacity,
+        const uint8_t *src, int32_t srcLength,
+        int32_t toWhichCase,
+        UErrorCode *pErrorCode) {
+    int32_t destLength;
+
+    /* check argument values */
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if( destCapacity<0 ||
+        (dest==NULL && destCapacity>0) ||
+        src==NULL ||
+        srcLength<-1
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* get the string length */
+    if(srcLength==-1) {
+        srcLength=(int32_t)uprv_strlen((const char *)src);
+    }
+
+    /* check for overlapping source and destination */
+    if( dest!=NULL &&
+        ((src>=dest && src<(dest+destCapacity)) ||
+         (dest>=src && dest<(src+srcLength)))
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    destLength=0;
+
+    if(toWhichCase==FOLD_CASE) {
+        destLength=utf8_foldCase(csm->csp, dest, destCapacity, src, srcLength,
+                                 csm->options, pErrorCode);
+    } else {
+        UCaseContext csc={ NULL };
+
+        csc.p=(void *)src;
+        csc.limit=srcLength;
+
+        if(toWhichCase==TO_LOWER) {
+            destLength=_caseMap(csm, ucase_toFullLower,
+                                dest, destCapacity,
+                                src, &csc,
+                                0, srcLength,
+                                pErrorCode);
+        } else if(toWhichCase==TO_UPPER) {
+            destLength=_caseMap(csm, ucase_toFullUpper,
+                                dest, destCapacity,
+                                src, &csc,
+                                0, srcLength,
+                                pErrorCode);
+        } else /* if(toWhichCase==TO_TITLE) */ {
+#if UCONFIG_NO_BREAK_ITERATION
+            *pErrorCode=U_UNSUPPORTED_ERROR;
+#else
+            /* UCaseMap is actually non-const in toTitle() APIs. */
+            UCaseMap *tmp = (UCaseMap *)csm;
+            destLength=_toTitle(tmp, dest, destCapacity,
+                                src, &csc, srcLength,
+                                pErrorCode);
+#endif
+        }
+    }
+
+    return u_terminateChars((char *)dest, destCapacity, destLength, pErrorCode);
+}
+
+/* public API functions */
+
+U_CAPI int32_t U_EXPORT2
+ucasemap_utf8ToLower(const UCaseMap *csm,
+                     char *dest, int32_t destCapacity,
+                     const char *src, int32_t srcLength,
+                     UErrorCode *pErrorCode) {
+    return caseMap(csm,
+                   (uint8_t *)dest, destCapacity,
+                   (const uint8_t *)src, srcLength,
+                   TO_LOWER, pErrorCode);
+}
+
+U_CAPI int32_t U_EXPORT2
+ucasemap_utf8ToUpper(const UCaseMap *csm,
+                     char *dest, int32_t destCapacity,
+                     const char *src, int32_t srcLength,
+                     UErrorCode *pErrorCode) {
+    return caseMap(csm,
+                   (uint8_t *)dest, destCapacity,
+                   (const uint8_t *)src, srcLength,
+                   TO_UPPER, pErrorCode);
+}
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+U_CAPI int32_t U_EXPORT2
+ucasemap_utf8ToTitle(UCaseMap *csm,
+                     char *dest, int32_t destCapacity,
+                     const char *src, int32_t srcLength,
+                     UErrorCode *pErrorCode) {
+    return caseMap(csm,
+                   (uint8_t *)dest, destCapacity,
+                   (const uint8_t *)src, srcLength,
+                   TO_TITLE, pErrorCode);
+}
+
+#endif
+
+U_CAPI int32_t U_EXPORT2
+ucasemap_utf8FoldCase(const UCaseMap *csm,
+                      char *dest, int32_t destCapacity,
+                      const char *src, int32_t srcLength,
+                      UErrorCode *pErrorCode) {
+    return caseMap(csm,
+                   (uint8_t *)dest, destCapacity,
+                   (const uint8_t *)src, srcLength,
+                   FOLD_CASE, pErrorCode);
+}
diff --git a/source/common/ucat.c b/source/common/ucat.c
new file mode 100644
index 0000000..5f6feb9
--- /dev/null
+++ b/source/common/ucat.c
@@ -0,0 +1,76 @@
+/*
+**********************************************************************
+* Copyright (c) 2003, International Business Machines
+* Corporation and others.  All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: March 19 2003
+* Since: ICU 2.6
+**********************************************************************
+*/
+#include "unicode/ucat.h"
+#include "unicode/ustring.h"
+#include "cstring.h"
+#include "uassert.h"
+
+/* Separator between set_num and msg_num */
+static const char SEPARATOR = '%';
+
+/* Maximum length of a set_num/msg_num key, incl. terminating zero.
+ * Longest possible key is "-2147483648%-2147483648" */
+#define MAX_KEY_LEN (24)
+
+/**
+ * Fill in buffer with a set_num/msg_num key string, given the numeric
+ * values. Numeric values must be >= 0. Buffer must be of length
+ * MAX_KEY_LEN or more.
+ */
+static char*
+_catkey(char* buffer, int32_t set_num, int32_t msg_num) {
+    int32_t i = 0;
+    i = T_CString_integerToString(buffer, set_num, 10);
+    buffer[i++] = SEPARATOR;
+    T_CString_integerToString(buffer+i, msg_num, 10);
+    return buffer;
+}
+
+U_CAPI u_nl_catd U_EXPORT2
+u_catopen(const char* name, const char* locale, UErrorCode* ec) {
+    return (u_nl_catd) ures_open(name, locale, ec);
+}
+
+U_CAPI void U_EXPORT2
+u_catclose(u_nl_catd catd) {
+    ures_close((UResourceBundle*) catd); /* may be NULL */
+}
+
+U_CAPI const UChar* U_EXPORT2
+u_catgets(u_nl_catd catd, int32_t set_num, int32_t msg_num,
+          const UChar* s,
+          int32_t* len, UErrorCode* ec) {
+
+    char key[MAX_KEY_LEN];
+    const UChar* result;
+
+    if (ec == NULL || U_FAILURE(*ec)) {
+        goto ERROR;
+    }
+
+    result = ures_getStringByKey((const UResourceBundle*) catd,
+                                 _catkey(key, set_num, msg_num),
+                                 len, ec);
+    if (U_FAILURE(*ec)) {
+        goto ERROR;
+    }
+
+    return result;
+
+ ERROR:
+    /* In case of any failure, return s */
+    if (len != NULL) {
+        *len = u_strlen(s);
+    }
+    return s;
+}
+
+/*eof*/
diff --git a/source/common/uchar.c b/source/common/uchar.c
new file mode 100644
index 0000000..04dd60b
--- /dev/null
+++ b/source/common/uchar.c
@@ -0,0 +1,702 @@
+/*
+********************************************************************************
+*   Copyright (C) 1996-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+********************************************************************************
+*
+* File UCHAR.C
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   04/02/97    aliu        Creation.
+*   4/15/99     Madhu       Updated all the function definitions for C Implementation
+*   5/20/99     Madhu       Added the function u_getVersion()
+*   8/19/1999   srl         Upgraded scripts to Unicode3.0 
+*   11/11/1999  weiv        added u_isalnum(), cleaned comments
+*   01/11/2000  helena      Renamed u_getVersion to u_getUnicodeVersion.
+*   06/20/2000  helena      OS/400 port changes; mostly typecast.
+******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uchar.h"
+#include "unicode/uscript.h"
+#include "unicode/udata.h"
+#include "umutex.h"
+#include "cmemory.h"
+#include "ucln_cmn.h"
+#include "utrie2.h"
+#include "udataswp.h"
+#include "uprops.h"
+#include "ustr_imp.h"
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+/* uchar_props_data.c is machine-generated by genprops --csource */
+#include "uchar_props_data.c"
+
+/* constants and macros for access to the data ------------------------------ */
+
+/* getting a uint32_t properties word from the data */
+#define GET_PROPS(c, result) ((result)=UTRIE2_GET16(&propsTrie, c));
+
+U_CFUNC UBool
+uprv_haveProperties(UErrorCode *pErrorCode) {
+    if(U_FAILURE(*pErrorCode)) {
+        return FALSE;
+    }
+    return TRUE;
+}
+
+/* API functions ------------------------------------------------------------ */
+
+/* Gets the Unicode character's general category.*/
+U_CAPI int8_t U_EXPORT2
+u_charType(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    return (int8_t)GET_CATEGORY(props);
+}
+
+/* Enumerate all code points with their general categories. */
+struct _EnumTypeCallback {
+    UCharEnumTypeRange *enumRange;
+    const void *context;
+};
+
+static uint32_t U_CALLCONV
+_enumTypeValue(const void *context, uint32_t value) {
+    return GET_CATEGORY(value);
+}
+
+static UBool U_CALLCONV
+_enumTypeRange(const void *context, UChar32 start, UChar32 end, uint32_t value) {
+    /* just cast the value to UCharCategory */
+    return ((struct _EnumTypeCallback *)context)->
+        enumRange(((struct _EnumTypeCallback *)context)->context,
+                  start, end+1, (UCharCategory)value);
+}
+
+U_CAPI void U_EXPORT2
+u_enumCharTypes(UCharEnumTypeRange *enumRange, const void *context) {
+    struct _EnumTypeCallback callback;
+
+    if(enumRange==NULL) {
+        return;
+    }
+
+    callback.enumRange=enumRange;
+    callback.context=context;
+    utrie2_enum(&propsTrie, _enumTypeValue, _enumTypeRange, &callback);
+}
+
+/* Checks if ch is a lower case letter.*/
+U_CAPI UBool U_EXPORT2
+u_islower(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    return (UBool)(GET_CATEGORY(props)==U_LOWERCASE_LETTER);
+}
+
+/* Checks if ch is an upper case letter.*/
+U_CAPI UBool U_EXPORT2
+u_isupper(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    return (UBool)(GET_CATEGORY(props)==U_UPPERCASE_LETTER);
+}
+
+/* Checks if ch is a title case letter; usually upper case letters.*/
+U_CAPI UBool U_EXPORT2
+u_istitle(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    return (UBool)(GET_CATEGORY(props)==U_TITLECASE_LETTER);
+}
+
+/* Checks if ch is a decimal digit. */
+U_CAPI UBool U_EXPORT2
+u_isdigit(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    return (UBool)(GET_CATEGORY(props)==U_DECIMAL_DIGIT_NUMBER);
+}
+
+U_CAPI UBool U_EXPORT2
+u_isxdigit(UChar32 c) {
+    uint32_t props;
+
+    /* check ASCII and Fullwidth ASCII a-fA-F */
+    if(
+        (c<=0x66 && c>=0x41 && (c<=0x46 || c>=0x61)) ||
+        (c>=0xff21 && c<=0xff46 && (c<=0xff26 || c>=0xff41))
+    ) {
+        return TRUE;
+    }
+
+    GET_PROPS(c, props);
+    return (UBool)(GET_CATEGORY(props)==U_DECIMAL_DIGIT_NUMBER);
+}
+
+/* Checks if the Unicode character is a letter.*/
+U_CAPI UBool U_EXPORT2
+u_isalpha(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    return (UBool)((CAT_MASK(props)&U_GC_L_MASK)!=0);
+}
+
+U_CAPI UBool U_EXPORT2
+u_isUAlphabetic(UChar32 c) {
+    return (u_getUnicodeProperties(c, 1)&U_MASK(UPROPS_ALPHABETIC))!=0;
+}
+
+/* Checks if c is a letter or a decimal digit */
+U_CAPI UBool U_EXPORT2
+u_isalnum(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    return (UBool)((CAT_MASK(props)&(U_GC_L_MASK|U_GC_ND_MASK))!=0);
+}
+
+/**
+ * Checks if c is alphabetic, or a decimal digit; implements UCHAR_POSIX_ALNUM.
+ * @internal
+ */
+U_CFUNC UBool
+u_isalnumPOSIX(UChar32 c) {
+    return (UBool)(u_isUAlphabetic(c) || u_isdigit(c));
+}
+
+/* Checks if ch is a unicode character with assigned character type.*/
+U_CAPI UBool U_EXPORT2
+u_isdefined(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    return (UBool)(GET_CATEGORY(props)!=0);
+}
+
+/* Checks if the Unicode character is a base form character that can take a diacritic.*/
+U_CAPI UBool U_EXPORT2
+u_isbase(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    return (UBool)((CAT_MASK(props)&(U_GC_L_MASK|U_GC_N_MASK|U_GC_MC_MASK|U_GC_ME_MASK))!=0);
+}
+
+/* Checks if the Unicode character is a control character.*/
+U_CAPI UBool U_EXPORT2
+u_iscntrl(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    return (UBool)((CAT_MASK(props)&(U_GC_CC_MASK|U_GC_CF_MASK|U_GC_ZL_MASK|U_GC_ZP_MASK))!=0);
+}
+
+U_CAPI UBool U_EXPORT2
+u_isISOControl(UChar32 c) {
+    return (uint32_t)c<=0x9f && (c<=0x1f || c>=0x7f);
+}
+
+/* Some control characters that are used as space. */
+#define IS_THAT_CONTROL_SPACE(c) \
+    (c<=0x9f && ((c>=TAB && c<=CR) || (c>=0x1c && c <=0x1f) || c==NL))
+
+/* Java has decided that U+0085 New Line is not whitespace any more. */
+#define IS_THAT_ASCII_CONTROL_SPACE(c) \
+    (c<=0x1f && c>=TAB && (c<=CR || c>=0x1c))
+
+/* Checks if the Unicode character is a space character.*/
+U_CAPI UBool U_EXPORT2
+u_isspace(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    return (UBool)((CAT_MASK(props)&U_GC_Z_MASK)!=0 || IS_THAT_CONTROL_SPACE(c));
+}
+
+U_CAPI UBool U_EXPORT2
+u_isJavaSpaceChar(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    return (UBool)((CAT_MASK(props)&U_GC_Z_MASK)!=0);
+}
+
+/* Checks if the Unicode character is a whitespace character.*/
+U_CAPI UBool U_EXPORT2
+u_isWhitespace(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    return (UBool)(
+                ((CAT_MASK(props)&U_GC_Z_MASK)!=0 &&
+                    c!=NBSP && c!=FIGURESP && c!=NNBSP) || /* exclude no-break spaces */
+                IS_THAT_ASCII_CONTROL_SPACE(c)
+           );
+}
+
+U_CAPI UBool U_EXPORT2
+u_isblank(UChar32 c) {
+    if((uint32_t)c<=0x9f) {
+        return c==9 || c==0x20; /* TAB or SPACE */
+    } else {
+        /* Zs */
+        uint32_t props;
+        GET_PROPS(c, props);
+        return (UBool)(GET_CATEGORY(props)==U_SPACE_SEPARATOR);
+    }
+}
+
+U_CAPI UBool U_EXPORT2
+u_isUWhiteSpace(UChar32 c) {
+    return (u_getUnicodeProperties(c, 1)&U_MASK(UPROPS_WHITE_SPACE))!=0;
+}
+
+/* Checks if the Unicode character is printable.*/
+U_CAPI UBool U_EXPORT2
+u_isprint(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    /* comparing ==0 returns FALSE for the categories mentioned */
+    return (UBool)((CAT_MASK(props)&U_GC_C_MASK)==0);
+}
+
+/**
+ * Checks if c is in \p{graph}\p{blank} - \p{cntrl}.
+ * Implements UCHAR_POSIX_PRINT.
+ * @internal
+ */
+U_CFUNC UBool
+u_isprintPOSIX(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    /*
+     * The only cntrl character in graph+blank is TAB (in blank).
+     * Here we implement (blank-TAB)=Zs instead of calling u_isblank().
+     */
+    return (UBool)((GET_CATEGORY(props)==U_SPACE_SEPARATOR) || u_isgraphPOSIX(c));
+}
+
+U_CAPI UBool U_EXPORT2
+u_isgraph(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    /* comparing ==0 returns FALSE for the categories mentioned */
+    return (UBool)((CAT_MASK(props)&
+                    (U_GC_CC_MASK|U_GC_CF_MASK|U_GC_CS_MASK|U_GC_CN_MASK|U_GC_Z_MASK))
+                   ==0);
+}
+
+/**
+ * Checks if c is in
+ * [^\p{space}\p{gc=Control}\p{gc=Surrogate}\p{gc=Unassigned}]
+ * with space=\p{Whitespace} and Control=Cc.
+ * Implements UCHAR_POSIX_GRAPH.
+ * @internal
+ */
+U_CFUNC UBool
+u_isgraphPOSIX(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    /* \p{space}\p{gc=Control} == \p{gc=Z}\p{Control} */
+    /* comparing ==0 returns FALSE for the categories mentioned */
+    return (UBool)((CAT_MASK(props)&
+                    (U_GC_CC_MASK|U_GC_CS_MASK|U_GC_CN_MASK|U_GC_Z_MASK))
+                   ==0);
+}
+
+U_CAPI UBool U_EXPORT2
+u_ispunct(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    return (UBool)((CAT_MASK(props)&U_GC_P_MASK)!=0);
+}
+
+/* Checks if the Unicode character can start a Unicode identifier.*/
+U_CAPI UBool U_EXPORT2
+u_isIDStart(UChar32 c) {
+    /* same as u_isalpha() */
+    uint32_t props;
+    GET_PROPS(c, props);
+    return (UBool)((CAT_MASK(props)&(U_GC_L_MASK|U_GC_NL_MASK))!=0);
+}
+
+/* Checks if the Unicode character can be a Unicode identifier part other than starting the
+ identifier.*/
+U_CAPI UBool U_EXPORT2
+u_isIDPart(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    return (UBool)(
+           (CAT_MASK(props)&
+            (U_GC_ND_MASK|U_GC_NL_MASK|
+             U_GC_L_MASK|
+             U_GC_PC_MASK|U_GC_MC_MASK|U_GC_MN_MASK)
+           )!=0 ||
+           u_isIDIgnorable(c));
+}
+
+/*Checks if the Unicode character can be ignorable in a Java or Unicode identifier.*/
+U_CAPI UBool U_EXPORT2
+u_isIDIgnorable(UChar32 c) {
+    if(c<=0x9f) {
+        return u_isISOControl(c) && !IS_THAT_ASCII_CONTROL_SPACE(c);
+    } else {
+        uint32_t props;
+        GET_PROPS(c, props);
+        return (UBool)(GET_CATEGORY(props)==U_FORMAT_CHAR);
+    }
+}
+
+/*Checks if the Unicode character can start a Java identifier.*/
+U_CAPI UBool U_EXPORT2
+u_isJavaIDStart(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    return (UBool)((CAT_MASK(props)&(U_GC_L_MASK|U_GC_SC_MASK|U_GC_PC_MASK))!=0);
+}
+
+/*Checks if the Unicode character can be a Java identifier part other than starting the
+ * identifier.
+ */
+U_CAPI UBool U_EXPORT2
+u_isJavaIDPart(UChar32 c) {
+    uint32_t props;
+    GET_PROPS(c, props);
+    return (UBool)(
+           (CAT_MASK(props)&
+            (U_GC_ND_MASK|U_GC_NL_MASK|
+             U_GC_L_MASK|
+             U_GC_SC_MASK|U_GC_PC_MASK|
+             U_GC_MC_MASK|U_GC_MN_MASK)
+           )!=0 ||
+           u_isIDIgnorable(c));
+}
+
+U_CAPI int32_t U_EXPORT2
+u_charDigitValue(UChar32 c) {
+    uint32_t props;
+    int32_t value;
+    GET_PROPS(c, props);
+    value=(int32_t)GET_NUMERIC_TYPE_VALUE(props)-UPROPS_NTV_DECIMAL_START;
+    if(value<=9) {
+        return value;
+    } else {
+        return -1;
+    }
+}
+
+U_CAPI double U_EXPORT2
+u_getNumericValue(UChar32 c) {
+    uint32_t props;
+    int32_t ntv;
+    GET_PROPS(c, props);
+    ntv=(int32_t)GET_NUMERIC_TYPE_VALUE(props);
+
+    if(ntv==UPROPS_NTV_NONE) {
+        return U_NO_NUMERIC_VALUE;
+    } else if(ntv<UPROPS_NTV_DIGIT_START) {
+        /* decimal digit */
+        return ntv-UPROPS_NTV_DECIMAL_START;
+    } else if(ntv<UPROPS_NTV_NUMERIC_START) {
+        /* other digit */
+        return ntv-UPROPS_NTV_DIGIT_START;
+    } else if(ntv<UPROPS_NTV_FRACTION_START) {
+        /* small integer */
+        return ntv-UPROPS_NTV_NUMERIC_START;
+    } else if(ntv<UPROPS_NTV_LARGE_START) {
+        /* fraction */
+        int32_t numerator=(ntv>>4)-12;
+        int32_t denominator=(ntv&0xf)+1;
+        return (double)numerator/denominator;
+    } else if(ntv<UPROPS_NTV_RESERVED_START) {
+        /* large, single-significant-digit integer */
+        double numValue;
+        int32_t mant=(ntv>>5)-14;
+        int32_t exp=(ntv&0x1f)+2;
+        numValue=mant;
+
+        /* multiply by 10^exp without math.h */
+        while(exp>=4) {
+            numValue*=10000.;
+            exp-=4;
+        }
+        switch(exp) {
+        case 3:
+            numValue*=1000.;
+            break;
+        case 2:
+            numValue*=100.;
+            break;
+        case 1:
+            numValue*=10.;
+            break;
+        case 0:
+        default:
+            break;
+        }
+
+        return numValue;
+    } else {
+        /* reserved */
+        return U_NO_NUMERIC_VALUE;
+    }
+}
+
+U_CAPI int32_t U_EXPORT2
+u_digit(UChar32 ch, int8_t radix) {
+    int8_t value;
+    if((uint8_t)(radix-2)<=(36-2)) {
+        value=(int8_t)u_charDigitValue(ch);
+        if(value<0) {
+            /* ch is not a decimal digit, try latin letters */
+            if(ch>=0x61 && ch<=0x7A) {
+                value=(int8_t)(ch-0x57);  /* ch - 'a' + 10 */
+            } else if(ch>=0x41 && ch<=0x5A) {
+                value=(int8_t)(ch-0x37);  /* ch - 'A' + 10 */
+            } else if(ch>=0xFF41 && ch<=0xFF5A) {
+                value=(int8_t)(ch-0xFF37);  /* fullwidth ASCII a-z */
+            } else if(ch>=0xFF21 && ch<=0xFF3A) {
+                value=(int8_t)(ch-0xFF17);  /* fullwidth ASCII A-Z */
+            }
+        }
+    } else {
+        value=-1;   /* invalid radix */
+    }
+    return (int8_t)((value<radix) ? value : -1);
+}
+
+U_CAPI UChar32 U_EXPORT2
+u_forDigit(int32_t digit, int8_t radix) {
+    if((uint8_t)(radix-2)>(36-2) || (uint32_t)digit>=(uint32_t)radix) {
+        return 0;
+    } else if(digit<10) {
+        return (UChar32)(0x30+digit);
+    } else {
+        return (UChar32)((0x61-10)+digit);
+    }
+}
+
+/* miscellaneous, and support for uprops.c ---------------------------------- */
+
+U_CAPI void U_EXPORT2
+u_getUnicodeVersion(UVersionInfo versionArray) {
+    if(versionArray!=NULL) {
+        uprv_memcpy(versionArray, dataVersion, U_MAX_VERSION_LENGTH);
+    }
+}
+
+U_CFUNC uint32_t
+u_getUnicodeProperties(UChar32 c, int32_t column) {
+    uint16_t vecIndex;
+
+    if(column==-1) {
+        uint32_t props;
+        GET_PROPS(c, props);
+        return props;
+    } else if(
+               column<0 || column>=propsVectorsColumns
+    ) {
+        return 0;
+    } else {
+        vecIndex=UTRIE2_GET16(&propsVectorsTrie, c);
+        return propsVectors[vecIndex+column];
+    }
+}
+
+U_CFUNC int32_t
+uprv_getMaxValues(int32_t column) {
+    switch(column) {
+    case 0:
+        return indexes[UPROPS_MAX_VALUES_INDEX];
+    case 2:
+        return indexes[UPROPS_MAX_VALUES_2_INDEX];
+    default:
+        return 0;
+    }
+}
+
+U_CAPI void U_EXPORT2
+u_charAge(UChar32 c, UVersionInfo versionArray) {
+    if(versionArray!=NULL) {
+        uint32_t version=u_getUnicodeProperties(c, 0)>>UPROPS_AGE_SHIFT;
+        versionArray[0]=(uint8_t)(version>>4);
+        versionArray[1]=(uint8_t)(version&0xf);
+        versionArray[2]=versionArray[3]=0;
+    }
+}
+
+U_CAPI UScriptCode U_EXPORT2
+uscript_getScript(UChar32 c, UErrorCode *pErrorCode) {
+    uint32_t scriptX;
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return USCRIPT_INVALID_CODE;
+    }
+    if((uint32_t)c>0x10ffff) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return USCRIPT_INVALID_CODE;
+    }
+    scriptX=u_getUnicodeProperties(c, 0)&UPROPS_SCRIPT_X_MASK;
+    if(scriptX<UPROPS_SCRIPT_X_WITH_COMMON) {
+        return (UScriptCode)scriptX;
+    } else if(scriptX<UPROPS_SCRIPT_X_WITH_INHERITED) {
+        return USCRIPT_COMMON;
+    } else if(scriptX<UPROPS_SCRIPT_X_WITH_OTHER) {
+        return USCRIPT_INHERITED;
+    } else {
+        return (UScriptCode)scriptExtensions[scriptX&UPROPS_SCRIPT_MASK];
+    }
+}
+
+U_DRAFT UBool U_EXPORT2
+uscript_hasScript(UChar32 c, UScriptCode sc) {
+    UScriptCode script;
+    const uint16_t *scx;
+    uint32_t scriptX=u_getUnicodeProperties(c, 0)&UPROPS_SCRIPT_X_MASK;
+    if(scriptX<UPROPS_SCRIPT_X_WITH_COMMON) {
+        return sc==(UScriptCode)scriptX;
+    }
+
+    scx=scriptExtensions+(scriptX&UPROPS_SCRIPT_MASK);
+    if(scriptX<UPROPS_SCRIPT_X_WITH_INHERITED) {
+        script=USCRIPT_COMMON;
+    } else if(scriptX<UPROPS_SCRIPT_X_WITH_OTHER) {
+        script=USCRIPT_INHERITED;
+    } else {
+        script=(UScriptCode)scx[0];
+        scx=scriptExtensions+scx[1];
+    }
+    if(sc==script) {
+        return TRUE;
+    }
+    while(sc>*scx) {
+        ++scx;
+    }
+    return sc==(*scx&0x7fff);
+}
+
+U_DRAFT int32_t U_EXPORT2
+uscript_getScriptExtensions(UChar32 c,
+                            UScriptCode *scripts, int32_t capacity,
+                            UErrorCode *pErrorCode) {
+    uint32_t scriptX;
+    int32_t length;
+    const uint16_t *scx;
+    uint16_t sx;
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(capacity<0 || (capacity>0 && scripts==NULL)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    scriptX=u_getUnicodeProperties(c, 0)&UPROPS_SCRIPT_X_MASK;
+    if(scriptX<UPROPS_SCRIPT_X_WITH_COMMON) {
+        return 0;
+    }
+
+    length=0;
+    scx=scriptExtensions+(scriptX&UPROPS_SCRIPT_MASK);
+    if(scriptX>=UPROPS_SCRIPT_X_WITH_OTHER) {
+        scx=scriptExtensions+scx[1];
+    }
+    do {
+        sx=*scx++;
+        if(length<capacity) {
+            scripts[length]=sx&0x7fff;
+        }
+        ++length;
+    } while(sx<0x8000);
+    if(length>capacity) {
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+    return length;
+}
+
+U_CAPI UBlockCode U_EXPORT2
+ublock_getCode(UChar32 c) {
+    return (UBlockCode)((u_getUnicodeProperties(c, 0)&UPROPS_BLOCK_MASK)>>UPROPS_BLOCK_SHIFT);
+}
+
+/* property starts for UnicodeSet ------------------------------------------- */
+
+static UBool U_CALLCONV
+_enumPropertyStartsRange(const void *context, UChar32 start, UChar32 end, uint32_t value) {
+    /* add the start code point to the USet */
+    const USetAdder *sa=(const USetAdder *)context;
+    sa->add(sa->set, start);
+    return TRUE;
+}
+
+#define USET_ADD_CP_AND_NEXT(sa, cp) sa->add(sa->set, cp); sa->add(sa->set, cp+1)
+
+U_CFUNC void U_EXPORT2
+uchar_addPropertyStarts(const USetAdder *sa, UErrorCode *pErrorCode) {
+    if(U_FAILURE(*pErrorCode)) {
+        return;
+    }
+
+    /* add the start code point of each same-value range of the main trie */
+    utrie2_enum(&propsTrie, NULL, _enumPropertyStartsRange, sa);
+
+    /* add code points with hardcoded properties, plus the ones following them */
+
+    /* add for u_isblank() */
+    USET_ADD_CP_AND_NEXT(sa, TAB);
+
+    /* add for IS_THAT_CONTROL_SPACE() */
+    sa->add(sa->set, CR+1); /* range TAB..CR */
+    sa->add(sa->set, 0x1c);
+    sa->add(sa->set, 0x1f+1);
+    USET_ADD_CP_AND_NEXT(sa, NL);
+
+    /* add for u_isIDIgnorable() what was not added above */
+    sa->add(sa->set, DEL); /* range DEL..NBSP-1, NBSP added below */
+    sa->add(sa->set, HAIRSP);
+    sa->add(sa->set, RLM+1);
+    sa->add(sa->set, INHSWAP);
+    sa->add(sa->set, NOMDIG+1);
+    USET_ADD_CP_AND_NEXT(sa, ZWNBSP);
+
+    /* add no-break spaces for u_isWhitespace() what was not added above */
+    USET_ADD_CP_AND_NEXT(sa, NBSP);
+    USET_ADD_CP_AND_NEXT(sa, FIGURESP);
+    USET_ADD_CP_AND_NEXT(sa, NNBSP);
+
+    /* add for u_digit() */
+    sa->add(sa->set, U_a);
+    sa->add(sa->set, U_z+1);
+    sa->add(sa->set, U_A);
+    sa->add(sa->set, U_Z+1);
+    sa->add(sa->set, U_FW_a);
+    sa->add(sa->set, U_FW_z+1);
+    sa->add(sa->set, U_FW_A);
+    sa->add(sa->set, U_FW_Z+1);
+
+    /* add for u_isxdigit() */
+    sa->add(sa->set, U_f+1);
+    sa->add(sa->set, U_F+1);
+    sa->add(sa->set, U_FW_f+1);
+    sa->add(sa->set, U_FW_F+1);
+
+    /* add for UCHAR_DEFAULT_IGNORABLE_CODE_POINT what was not added above */
+    sa->add(sa->set, WJ); /* range WJ..NOMDIG */
+    sa->add(sa->set, 0xfff0);
+    sa->add(sa->set, 0xfffb+1);
+    sa->add(sa->set, 0xe0000);
+    sa->add(sa->set, 0xe0fff+1);
+
+    /* add for UCHAR_GRAPHEME_BASE and others */
+    USET_ADD_CP_AND_NEXT(sa, CGJ);
+}
+
+U_CFUNC void U_EXPORT2
+upropsvec_addPropertyStarts(const USetAdder *sa, UErrorCode *pErrorCode) {
+    if(U_FAILURE(*pErrorCode)) {
+        return;
+    }
+
+    /* add the start code point of each same-value range of the properties vectors trie */
+    if(propsVectorsColumns>0) {
+        /* if propsVectorsColumns==0 then the properties vectors trie may not be there at all */
+        utrie2_enum(&propsVectorsTrie, NULL, _enumPropertyStartsRange, sa);
+    }
+}
diff --git a/source/common/uchar_props_data.c b/source/common/uchar_props_data.c
new file mode 100644
index 0000000..4313d02
--- /dev/null
+++ b/source/common/uchar_props_data.c
@@ -0,0 +1,2822 @@
+/*
+ * Copyright (C) 1999-2010, International Business Machines
+ * Corporation and others.  All Rights Reserved.
+ *
+ * file name: uchar_props_data.c
+ *
+ * machine-generated on: 2010-09-19
+ */
+
+static const UVersionInfo dataVersion={6,0,0,0};
+
+static const uint16_t propsTrie_index[17204]={
+0x3cc,0x3d4,0x3dc,0x3e4,0x3fc,0x404,0x40c,0x414,0x41c,0x424,0x42a,0x432,0x43a,0x442,0x44a,0x452,
+0x458,0x460,0x468,0x470,0x473,0x47b,0x483,0x48b,0x493,0x49b,0x497,0x49f,0x4a7,0x4af,0x4b4,0x4bc,
+0x4c4,0x4cc,0x4d0,0x4d8,0x4e0,0x4e8,0x4f0,0x4f8,0x4f6,0x4fe,0x503,0x50b,0x511,0x519,0x521,0x529,
+0x531,0x539,0x541,0x549,0x54e,0x556,0x559,0x561,0x569,0x571,0x577,0x57f,0x57e,0x586,0x58e,0x596,
+0x59e,0x5a5,0x5ad,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x5b5,0x5b7,0x5bf,0x5c7,0x5cf,0x5d5,0x5dd,0x5e5,
+0x5ed,0x5f3,0x5fb,0x603,0x60b,0x611,0x619,0x621,0x5cf,0x629,0x631,0x639,0x641,0x649,0x651,0x658,
+0x660,0x666,0x66e,0x676,0x67e,0x684,0x68c,0x694,0x67e,0x69c,0x6a4,0x6ac,0x6b4,0x6bb,0x6c3,0x6cb,
+0x57a,0x6d3,0x6db,0x3ec,0x6e3,0x6eb,0x6f3,0x3ec,0x6fb,0x703,0x70b,0x710,0x718,0x71f,0x727,0x3ec,
+0x539,0x72f,0x737,0x73f,0x747,0x4c4,0x74f,0x753,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x75b,0x539,0x763,0x767,0x76f,0x539,0x775,0x539,0x77b,0x783,0x78b,0x539,0x539,0x793,
+0x79b,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x7a0,0x7a8,0x539,0x539,0x7b0,0x7b8,0x7c0,0x7c8,0x7d0,0x539,0x7d8,0x7e0,0x7e8,
+0x7f0,0x539,0x7f8,0x7fa,0x539,0x802,0x539,0x806,0x80e,0x816,0x81e,0x823,0x539,0x82b,0x833,0x83b,
+0x843,0x539,0x84b,0x853,0x85b,0x863,0x3ec,0x3ec,0x86b,0x86e,0x876,0x87e,0x886,0x88e,0x539,0x896,
+0x539,0x89e,0x8a6,0x8ad,0x3ec,0x3ec,0x8b5,0x8bd,0x46c,0x8c5,0x8c8,0x8d0,0x8d7,0x8c8,0x493,0x8df,
+0x41c,0x41c,0x41c,0x41c,0x8e7,0x41c,0x41c,0x41c,0x8ef,0x8f7,0x8ff,0x907,0x90f,0x913,0x91b,0x923,
+0x92b,0x933,0x93b,0x943,0x94b,0x953,0x95a,0x962,0x96a,0x972,0x97a,0x982,0x98a,0x992,0x997,0x99d,
+0x9a2,0x9a2,0x9a2,0x9a2,0x9a2,0x9a2,0x9a2,0x9a2,0x9aa,0x9b2,0x83b,0x9b5,0x9bd,0x9c4,0x9c9,0x9d1,
+0x83b,0x9d9,0x9e1,0x9e9,0x9ec,0x83b,0x83b,0x9f3,0x83b,0x83b,0x83b,0x83b,0x83b,0x9fb,0xa03,0xa05,
+0x83b,0x83b,0x83b,0xa0d,0x83b,0x83b,0x83b,0x83b,0xa15,0x83b,0x83b,0xa1b,0xa23,0x83b,0xa2b,0xa32,
+0x83b,0x83b,0x83b,0x83b,0x83b,0x83b,0x83b,0x83b,0x9a2,0x9a2,0x9a2,0x9a2,0xa3a,0x9a2,0xa41,0xa48,
+0x9a2,0x9a2,0x9a2,0x9a2,0x9a2,0x9a2,0x9a2,0x9a2,0x83b,0x99e,0xa50,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x4c4,0xa58,0xa5c,0xa64,0x41c,0x41c,0x41c,0xa6c,0x46c,0xa74,0x539,0xa7b,0xa83,0xa8b,0xa8b,0x493,
+0xa93,0xa9b,0x3ec,0x3ec,0xaa3,0x83b,0x83b,0xaaa,0x83b,0x83b,0x83b,0x83b,0x83b,0x83b,0xab2,0xab8,
+0xac0,0xac8,0x57a,0x539,0xad0,0x79b,0x539,0xad8,0xae0,0xae5,0x539,0x539,0xaea,0x525,0x83b,0xaf1,
+0xaf9,0xb01,0xb05,0x83b,0xb01,0xb0d,0x83b,0xaf9,0x83b,0x83b,0x83b,0x83b,0x83b,0x83b,0x83b,0x83b,
+0x1033,0x539,0x539,0x539,0xfcb,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x1039,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x1053,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x806,0x83b,0x83b,
+0xfab,0x539,0x106b,0x539,0xfd0,0x10b5,0x1083,0xfe6,0x1031,0x539,0x539,0x109f,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x10bd,0x539,0x10c4,0xfd6,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x108b,0x539,0x539,0x539,0xfee,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x1011,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0xfaf,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0xfb6,0x539,0x539,0x539,0x1073,0xfbd,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x108f,0x539,0x539,0x1067,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x1057,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x105a,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x107b,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x10a4,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x1018,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x10b1,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0xfdb,0x539,0x539,0x539,0xfe0,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x10ac,0x1048,0x104c,0x539,0x539,0x539,0xfa3,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0xc64,0x3ec,
+0xb15,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0xb1b,0x83b,0xb22,0x8ad,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0xb27,0xb2f,0x41c,0xb37,0x4fa,0x539,0x539,0xb3f,0xb47,0xb4f,0x41c,0xb54,0xb5c,0xb64,0x3ec,0xb67,
+0xb6f,0xb77,0x539,0xb7f,0xb87,0xb8a,0xb91,0xb99,0x58e,0xba1,0xba8,0x80e,0x5b5,0xbb0,0xbb8,0x3ec,
+0x539,0xbc0,0xbc8,0xbd0,0x539,0xbd8,0xbe0,0x3ec,0xbe8,0xbf0,0x3ec,0x3ec,0x3ec,0x3ec,0x539,0xbf8,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0xc00,0xc07,0x7f9,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,
+0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,
+0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,
+0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,
+0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,
+0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,
+0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,
+0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,
+0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,
+0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,
+0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,
+0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,
+0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,
+0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,
+0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0x539,0x539,0x539,0xc0d,0x539,0xc14,0xc19,0xc1e,
+0x539,0xc26,0x539,0xc26,0x539,0x539,0xc2a,0x3ec,0xc32,0xc3a,0xc42,0x539,0x539,0xc46,0xc4e,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0xc53,0xc5b,0x539,0xc5f,0x539,0xc65,0xc69,
+0xc71,0xc79,0xc80,0xc88,0x539,0x539,0x539,0xc8e,0xc96,0x3dc,0xc9e,0xca6,0xcab,0xcb3,0xcbb,0xcc3,
+0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,
+0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,0xf92,
+0xfb0,0xfb0,0xff0,0x1030,0x1070,0x10a8,0x10e8,0x1128,0x1160,0x11a0,0x11cc,0x120c,0x124c,0x125c,0x129c,0x12d0,
+0x1310,0x1340,0x1380,0x13c0,0x13d8,0x140c,0x1444,0x1484,0x14c4,0x1504,0x1538,0x1564,0x15a4,0x15dc,0x15f8,0x1638,
+0xa80,0xac0,0xb00,0xa40,0xb40,0xa40,0xb80,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xbc0,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xc00,0xa40,0xa40,0xa40,0xc40,0xa40,0xa40,0xa40,0xc80,0xa40,
+0xd40,0xd77,0x1db,0x1db,0xd9b,0xdcf,0x1db,0xdf7,0x1db,0x1db,0x1db,0x1db,0xe24,0x1db,0x1db,0x1db,
+0x1db,0x1db,0x1db,0x1db,0xe38,0x1db,0xe70,0xeb0,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xcc0,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xd00,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,
+0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0xef0,
+0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,
+0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0xef0,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0xccb,0xcd2,0xcda,0x3ec,0x539,0x539,0x539,0x525,0xce2,0xcea,0xcf2,0xcfa,0xd01,0x3ec,0xd08,0xd0c,
+0x3ec,0x3ec,0x3ec,0x3ec,0x80e,0x539,0xd14,0x3ec,0xcb3,0xd1c,0xd24,0x3ec,0xd2c,0x539,0xd34,0x3ec,
+0x4c4,0x4ce,0xd3c,0x539,0xd40,0xd48,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0xd50,0xd53,0xd5b,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0xd63,0xd6b,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0xd73,0xd7a,0xd82,0xd8a,0x3ec,0x3ec,0x3ec,0x3ec,0x539,0xd92,0xd9a,0xda2,0x3ec,0x3ec,0x3ec,0x3ec,
+0x539,0x539,0xdaa,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0xdb2,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0xdba,0x56f,0xdc2,0xdca,0x886,0xdd2,0xdda,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0xde2,0x3ec,0x3ec,0x3ec,0x3ec,
+0xdea,0xdf2,0xdfa,0xe02,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0xde2,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0xe0a,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0xe12,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x83b,0x83b,0x83b,0x83b,0x83b,0x83b,0x83b,0xab2,0x83b,0xe1a,0x83b,0xe21,0xe29,0xe2f,0xe33,0x3ec,
+0x83b,0x83b,0xe3b,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x83b,0x83b,0xe43,0xe4b,0x3ec,0x3ec,0x3ec,0x3ec,
+0xe53,0xe5a,0xe5f,0xe65,0xe6d,0xe75,0xe7d,0xe57,0xe85,0xe8d,0xe95,0xe9a,0xe6c,0xe53,0xe5a,0xe56,
+0xe65,0xea2,0xe54,0xea5,0xe57,0xead,0xeb5,0xebd,0xec4,0xeb0,0xeb8,0xec0,0xec7,0xeb3,0xecf,0xed7,
+0x83b,0xedf,0x83b,0x83b,0xaaa,0xee4,0xeec,0x3ec,0xef4,0xef9,0x83b,0xeff,0xf03,0x3ec,0x3ec,0xf0a,
+0xf12,0xf03,0xf18,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x83b,0xf20,0x83b,0xf26,0xaaa,0x83b,0xf2e,0xf36,
+0x83b,0xaf9,0xf3e,0x83b,0x83b,0x83b,0x83b,0xf40,0x83b,0xe33,0xd08,0xf48,0x3ec,0x3ec,0x3ec,0xf4a,
+0xf52,0xf5a,0xf62,0x3ec,0x83b,0x83b,0xf6a,0x3ec,0x83b,0x83b,0x83b,0xaaa,0x3ec,0x3ec,0x3ec,0x3ec,
+0x539,0x539,0x539,0x539,0xf72,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0xd40,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0xf7a,0xf82,0xf82,0xf82,0x3ec,0x3ec,0x3ec,0x3ec,0x493,0x493,0x493,0x493,0x493,0x493,0x493,0xf8a,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x1062,0x539,0x539,0x101f,0x539,0x539,0x539,0x1027,0x539,0x1041,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0xfc3,0x539,0x539,0x1097,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0xff4,0xffc,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0xfe0,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x1003,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x100a,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x102c,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0xa83,0x3ec,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,
+0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x539,0x793,0x539,0x539,0x539,0x539,0x539,0x539,
+0xd40,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,0x3ec,
+0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,
+0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,
+0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,
+0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9a,0xf9b,
+0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,
+0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,
+0xc,0x17,0x17,0x17,0x19,0x17,0x17,0x17,0x14,0x15,0x17,0x18,0x17,0x13,0x17,0x17,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,0x18,0x18,0x18,0x17,
+0x17,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,0x14,0x17,0x15,0x1a,0x16,
+0x1a,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,0x14,0x18,0x15,0x18,0xf,
+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,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,
+0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,
+0xc,0x17,0x19,0x19,0x19,0x19,0x1b,0x1b,0x1a,0x1b,2,0x1c,0x18,0x10,0x1b,0x1a,
+0x1b,0x18,0x34b,0x38b,0x1a,2,0x1b,0x17,0x1a,0x30b,2,0x1d,0x34cb,0x344b,0x3ccb,0x17,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,0x18,1,1,1,1,1,1,1,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,0x18,2,2,2,2,2,2,2,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,2,1,2,1,2,1,2,1,
+2,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,1,2,1,2,1,2,2,2,1,1,2,1,2,1,1,
+2,1,1,1,2,2,1,1,1,1,2,1,1,2,1,1,
+1,2,2,2,1,1,2,1,1,2,1,2,1,2,1,1,
+2,1,2,2,1,2,1,1,2,1,1,1,2,1,2,1,
+1,2,2,5,1,2,2,2,5,5,5,5,1,3,2,1,
+3,2,1,3,2,1,2,1,2,1,2,1,2,1,2,1,
+2,1,2,1,2,2,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,2,1,3,2,1,2,1,1,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,2,2,2,2,2,2,1,1,2,1,1,2,
+2,1,2,1,1,1,1,2,1,2,1,2,1,2,1,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,
+4,4,4,4,4,4,4,4,4,4,4,4,4,4,0x1a,0x1a,
+0x1a,0x1a,4,4,4,4,4,4,4,4,4,4,4,4,0x1a,0x1a,
+0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,4,4,4,4,
+4,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,4,0x1a,4,0x1a,0x1a,0x1a,0x1a,0x1a,
+0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,6,6,6,6,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,6,6,6,6,6,6,6,6,6,1,2,1,2,
+4,0x1a,1,2,0,0,4,2,2,2,0x17,0,0,0,0,0,
+0x1a,0x1a,1,0x17,1,1,1,0,1,0,1,1,2,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,
+1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,
+2,2,1,1,1,2,2,2,1,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+2,2,2,2,1,2,0x18,1,2,1,1,2,2,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,0x1b,6,6,6,6,6,7,7,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,1,2,1,2,1,2,1,2,1,2,1,2,1,2,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,0,0,4,0x17,0x17,0x17,0x17,0x17,0x17,0,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,0,0x17,0x13,0,
+0,0,0,0,0,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,0x13,6,0x17,6,6,0x17,6,6,0x17,6,0,0,0,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,
+0,0,0,0,5,5,5,0x17,0x17,0,0,0,0,0,0,0,
+0,0,0,0,0x10,0x10,0x10,0x10,0,0,0x18,0x18,0x18,0x17,0x17,0x19,
+0x17,0x17,0x1b,0x1b,6,6,6,6,6,6,6,6,6,6,6,0x17,
+0,0,0x17,0x17,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,4,5,5,5,5,5,5,5,5,5,5,6,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,6,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,
+0x17,0x17,5,5,6,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,0x17,5,6,6,6,6,6,6,
+6,0x10,0x1b,6,6,6,6,6,6,4,4,6,6,0x1b,6,6,
+6,6,5,5,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,5,5,
+5,0x1b,0x1b,5,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+0x17,0x17,0,0x10,5,6,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,6,6,6,6,0,0,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,
+6,6,6,6,6,6,6,6,6,5,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
+0x249,0x289,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,6,6,6,6,6,6,6,6,6,4,4,0x1b,0x17,
+0x17,0x17,4,0,0,0,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,
+6,6,4,6,6,6,6,6,4,6,6,6,4,6,6,6,
+6,6,0,0,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+0x17,0x17,0x17,0,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,
+0,0,0x17,0,6,6,6,8,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,6,8,6,5,8,8,8,6,6,6,
+6,6,6,6,6,8,8,8,8,6,8,8,5,6,6,6,
+6,6,6,6,5,5,5,5,5,5,5,5,5,5,6,6,
+0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,4,5,5,
+5,5,5,5,0,5,5,5,5,5,5,5,0,6,8,8,
+0,5,5,5,5,5,5,5,5,0,0,5,5,0,0,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,
+5,5,5,5,5,0,5,0,0,0,5,5,5,5,0,0,
+6,5,8,8,8,6,6,6,6,0,0,8,8,0,0,8,
+8,6,5,0,0,0,0,0,0,0,0,8,0,0,0,0,
+5,5,0,5,5,5,6,6,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,
+0x1c9,0x209,0x249,0x289,5,5,0x19,0x19,0x37cb,0x35cb,0x3fcb,0x34cb,0x3ccb,0x94b,0x1b,0x19,
+0,0,0,0,0,6,6,8,0,5,5,5,5,5,5,0,
+0,0,0,5,5,0,0,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,0,5,5,5,5,5,5,5,0,5,5,
+0,5,5,0,5,5,0,0,6,0,8,8,8,6,6,0,
+0,0,0,6,6,0,0,6,6,6,0,0,0,6,0,0,
+0,0,0,0,0,5,5,5,5,0,5,0,0,0,0,0,
+0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,6,6,5,5,
+5,6,0,0,0,0,0,0,0,0,0,0,0,6,6,8,
+0,5,5,5,5,5,5,5,5,5,0,5,5,5,0,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,
+5,5,5,5,5,0,5,5,0,5,5,5,5,5,0,0,
+6,5,8,8,8,6,6,6,6,6,0,6,6,8,0,8,
+8,6,0,0,5,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,5,5,6,6,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,
+0x1c9,0x209,0x249,0x289,0,0x19,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,0,5,5,
+5,5,5,5,5,0,5,5,0,5,5,5,5,5,0,0,
+6,5,8,6,8,6,6,6,6,0,0,8,8,0,0,8,
+8,6,0,0,0,0,0,0,0,0,6,8,0,0,0,0,
+5,5,0,5,5,5,6,6,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,
+0x1c9,0x209,0x249,0x289,0x1b,5,0x34cb,0x344b,0x3ccb,0x37cb,0x35cb,0x3fcb,0,0,0,0,
+0,0,0,0,0,0,6,5,0,5,5,5,5,5,5,0,
+0,0,5,5,5,0,5,5,5,5,0,0,0,5,5,0,
+5,0,5,5,0,0,0,5,5,0,0,0,5,5,5,0,
+0,0,5,5,5,5,5,5,5,5,5,5,5,5,0,0,
+0,0,8,8,6,8,8,0,0,0,8,8,8,0,8,8,
+8,6,0,0,5,0,0,0,0,0,0,8,0,0,0,0,
+0,0,0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,
+0x7cb,0x1e4b,0x784b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x1b,0,0,0,0,0,
+0,8,8,8,0,5,5,5,5,5,5,5,5,0,5,5,
+5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,0,5,5,5,5,5,5,5,5,5,5,0,5,5,5,
+5,5,0,0,0,5,6,6,6,8,8,8,8,0,6,6,
+6,0,6,6,6,6,0,0,0,0,0,0,0,6,6,0,
+5,5,0,0,0,0,0,0,5,5,6,6,0,0,0x49,0x89,
+0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,0,0,
+0x54b,0x58b,0x5cb,0x60b,0x58b,0x5cb,0x60b,0x1b,0,0,8,8,0,5,5,5,
+5,5,5,5,5,0,5,5,5,0,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,
+5,5,5,5,0,5,5,5,5,5,0,0,6,5,8,6,
+8,8,8,8,8,0,6,8,8,0,8,8,6,6,0,0,
+0,0,0,0,0,8,8,0,0,0,0,0,0,0,5,0,
+5,5,6,6,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,
+0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,0,0,5,8,8,
+8,6,6,6,6,0,8,8,8,0,8,8,8,6,5,0,
+0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,
+5,5,6,6,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,
+0x7cb,0x1e4b,0x784b,0x34cb,0x344b,0x3ccb,0,0,0,0x1b,5,5,5,5,5,5,
+0,0,8,8,0,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,0,0,0,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,
+5,5,5,5,5,5,5,5,0,5,0,0,5,5,5,5,
+5,5,5,0,0,0,6,0,0,0,0,8,8,8,6,6,
+6,0,6,0,8,8,8,8,8,8,8,8,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,8,
+0x17,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,6,5,5,
+6,6,6,6,6,6,6,0,0,0,0,0x19,5,5,5,5,
+5,5,4,6,6,6,6,6,6,6,6,0x17,0x49,0x89,0xc9,0x109,
+0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,0,0,0,0,0,5,5,0,
+5,0,0,5,5,0,5,0,0,5,0,0,0,0,0,0,
+5,5,5,5,0,5,5,5,5,5,5,5,0,5,5,5,
+0,5,0,5,0,0,5,5,0,5,5,5,5,6,5,5,
+6,6,6,6,6,6,0,6,6,5,0,0,5,5,5,5,
+5,0,4,0,6,6,6,6,6,6,0,0,0x49,0x89,0xc9,0x109,
+0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,5,5,0,0,5,0x1b,0x1b,0x1b,
+0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x1b,
+0x1b,0x1b,0x1b,0x1b,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x49,0x89,0xc9,0x109,
+0x149,0x189,0x1c9,0x209,0x249,0x289,0x344b,0x3c4b,0x444b,0x4c4b,0x544b,0x5c4b,0x644b,0x6c4b,0x744b,0x2c4b,
+0x1b,6,0x1b,6,0x1b,6,0x14,0x15,0x14,0x15,8,8,5,5,5,5,
+5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,
+0,6,6,6,6,6,6,6,6,6,6,6,6,6,6,8,
+6,6,6,6,6,0x17,6,6,5,5,5,5,5,6,6,6,
+6,6,6,6,6,6,6,6,0,6,6,6,6,6,6,6,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,6,6,6,6,6,6,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x17,0x17,0x17,0x17,
+0x17,0x1b,0x1b,0x1b,0x1b,0x17,0x17,0,0,0,0,0,5,5,5,5,
+5,5,5,5,5,5,5,8,8,6,6,6,6,8,6,6,
+6,6,6,6,8,6,6,8,8,6,6,5,0x49,0x89,0xc9,0x109,
+0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,0x17,0x17,0x17,0x17,5,5,5,5,
+5,5,8,8,6,6,5,5,5,5,6,6,6,5,8,8,
+8,5,5,8,8,8,8,8,8,8,5,5,5,6,6,6,
+6,5,5,5,5,5,5,5,5,5,5,5,5,5,6,8,
+8,6,6,8,8,8,8,8,8,6,5,8,0x49,0x89,0xc9,0x109,
+0x149,0x189,0x1c9,0x209,0x249,0x289,8,8,8,6,0x1b,0x1b,1,1,1,1,
+1,1,0,0,0,0,0,0,0,0,0,0,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,0x17,4,0,0,0,5,5,5,5,
+5,5,5,5,5,0,5,5,5,5,0,0,5,5,5,5,
+5,5,5,0,5,0,5,5,5,5,0,0,5,5,5,5,
+5,5,5,5,5,0,5,5,5,5,0,0,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,
+5,5,0,0,5,5,5,5,5,5,5,0,5,0,5,5,
+5,5,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,0,5,5,5,5,0,0,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,0,0,6,6,6,0x1b,0x17,0x17,0x17,
+0x17,0x17,0x17,0x17,0x17,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0xa4b,
+0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0x788b,0,0,0,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,0,0,0,0,0,0,0,0,0,0,0,0x13,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0x17,0x17,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+0xc,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,0x14,0x15,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,0x17,0x17,0x17,0x98a,0x9ca,
+0xa0a,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,
+5,5,6,6,6,0,0,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,6,6,6,0x17,0x17,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,6,6,0,0,0,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,
+5,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,0x10,0x10,8,6,6,6,6,6,6,6,8,8,
+8,8,8,8,8,8,6,8,8,6,6,6,6,6,6,6,
+6,6,6,6,0x17,0x17,0x17,4,0x17,0x17,0x17,0x19,5,6,0,0,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,
+0x54b,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0,0,0,0,0,0,
+0x17,0x17,0x17,0x17,0x17,0x17,0x13,0x17,0x17,0x17,0x17,6,6,6,0xc,0,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,
+5,5,5,4,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,
+5,6,5,0,0,0,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,
+0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,0,0,0,6,6,6,8,8,8,8,6,
+6,8,8,8,0,0,0,0,8,8,6,8,8,8,8,8,
+8,6,6,6,0,0,0,0,0x1b,0,0,0,0x17,0x17,0x49,0x89,
+0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,0,0,5,5,5,5,
+5,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,
+5,5,5,5,5,5,5,5,0,0,0,0,8,8,8,8,
+8,8,8,8,8,8,8,8,8,8,8,8,8,5,5,5,
+5,5,5,5,8,8,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,
+0x149,0x189,0x1c9,0x209,0x249,0x289,0x30b,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,6,6,8,8,8,0,0,0x17,0x17,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,8,6,8,6,6,6,6,6,6,6,0,6,8,6,8,
+8,6,6,6,6,6,6,6,6,8,8,8,8,8,8,6,
+6,6,6,6,6,6,6,6,6,0,0,6,0x49,0x89,0xc9,0x109,
+0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,
+0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,0x17,0x17,0x17,0x17,
+0x17,0x17,0x17,4,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,
+8,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,6,8,6,6,
+6,6,6,8,6,8,8,8,8,8,6,8,8,5,5,5,
+5,5,5,5,0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
+0x249,0x289,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,6,6,6,6,6,6,6,6,6,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,6,6,8,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,8,6,6,6,6,8,8,
+6,6,8,0,0,0,5,5,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
+0x249,0x289,0,0,0,0,0,0,5,5,5,5,5,5,6,8,
+6,6,8,8,8,6,8,6,6,6,8,8,0,0,0,0,
+0,0,0,0,0x17,0x17,0x17,0x17,5,5,5,5,8,8,8,8,
+8,8,8,8,6,6,6,6,6,6,6,6,8,8,6,6,
+0,0,0,0x17,0x17,0x17,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
+0x249,0x289,0,0,0,5,5,5,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
+0x249,0x289,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,
+4,4,0x17,0x17,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,6,6,6,0x17,6,6,6,6,6,6,6,6,
+6,6,6,6,6,8,6,6,6,6,6,6,6,5,5,5,
+5,6,5,5,5,5,8,0,0,0,0,0,0,0,0,0,
+0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,
+4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,4,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,4,4,4,4,4,6,6,6,6,
+6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,6,6,6,6,1,2,1,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,
+2,2,2,2,1,1,1,1,1,1,1,1,2,2,2,2,
+2,2,0,0,1,1,1,1,1,1,0,0,2,2,2,2,
+2,2,2,2,1,1,1,1,1,1,1,1,2,2,2,2,
+2,2,2,2,1,1,1,1,1,1,1,1,2,2,2,2,
+2,2,0,0,1,1,1,1,1,1,0,0,2,2,2,2,
+2,2,2,2,0,1,0,1,0,1,0,1,2,2,2,2,
+2,2,2,2,1,1,1,1,1,1,1,1,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,
+2,2,2,2,3,3,3,3,3,3,3,3,2,2,2,2,
+2,2,2,2,3,3,3,3,3,3,3,3,2,2,2,2,
+2,0,2,2,1,1,1,1,3,0x1a,2,0x1a,0x1a,0x1a,2,2,
+2,0,2,2,1,1,1,1,3,0x1a,0x1a,0x1a,2,2,2,2,
+0,0,2,2,1,1,1,1,0,0x1a,0x1a,0x1a,2,2,2,2,
+2,2,2,2,1,1,1,1,1,0x1a,0x1a,0x1a,0,0,2,2,
+2,0,2,2,1,1,1,1,3,0x1a,0x1a,0,0xc,0xc,0xc,0xc,
+0xc,0xc,0xc,0xc,0xc,0xc,0xc,0x10,0x10,0x10,0x10,0x10,0x13,0x13,0x13,0x13,
+0x13,0x13,0x17,0x17,0x1c,0x1d,0x14,0x1c,0x1c,0x1d,0x14,0x1c,0x17,0x17,0x17,0x17,
+0x17,0x17,0x17,0x17,0xd,0xe,0x10,0x10,0x10,0x10,0x10,0xc,0x17,0x17,0x17,0x17,
+0x17,0x17,0x17,0x17,0x17,0x1c,0x1d,0x17,0x17,0x17,0x17,0x16,0x16,0x17,0x17,0x17,
+0x18,0x14,0x15,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x18,0x17,
+0x16,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0xc,0x10,0x10,0x10,0x10,
+0x10,0,0,0,0,0,0x10,0x10,0x10,0x10,0x10,0x10,0x2cb,4,0,0,
+0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x18,0x18,0x18,0x14,0x15,4,0x2cb,0x30b,0x34b,0x38b,
+0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x18,0x18,0x18,0x14,0x15,0,4,4,4,4,
+4,4,4,4,4,4,4,4,4,0,0,0,0x19,0x19,0x19,0x19,
+0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,
+0x19,0x19,0x19,0x19,0x19,0x19,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,6,6,6,6,6,6,6,6,
+6,6,6,6,6,7,7,7,7,6,7,7,7,6,6,6,
+6,6,6,6,6,6,6,6,6,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x1b,0x1b,1,0x1b,0x1b,0x1b,0x1b,1,
+0x1b,0x1b,2,1,1,1,2,2,1,1,1,2,0x1b,1,0x1b,0x1b,
+0x18,1,1,1,1,1,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,1,0x1b,1,0x1b,
+1,0x1b,1,1,1,1,0x1b,2,1,1,1,1,2,5,5,5,
+5,2,0x1b,0x1b,2,2,1,1,0x18,0x18,0x18,0x18,0x18,1,2,2,
+2,2,0x1b,0x18,0x1b,0x1b,2,0x1b,0x358b,0x360b,0x364b,0x348b,0x388b,0x350b,0x390b,0x3d0b,
+0x410b,0x354b,0x454b,0x35cb,0x3dcb,0x45cb,0x4dcb,0x58b,0x58a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,
+0x78a,0x7ca,0x80a,0x84a,0x11ca,0x1e4a,0x980a,0x784a,0x58a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,
+0x78a,0x7ca,0x80a,0x84a,0x11ca,0x1e4a,0x980a,0x784a,0x784a,0x984a,0x788a,1,2,0x6ca,0x11ca,0x988a,
+0x78ca,0x54b,0,0,0,0,0,0,0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x18,0x1b,0x1b,0x18,0x1b,0x1b,0x18,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x1b,0x1b,0x18,0x1b,
+0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x14,0x15,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x18,0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,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,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0x80b,0x84b,
+0x88b,0x8cb,0x90b,0x94b,0x98b,0x9cb,0xa0b,0xa4b,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,
+0x50b,0x7cb,0x80b,0x84b,0x88b,0x8cb,0x90b,0x94b,0x98b,0x9cb,0xa0b,0xa4b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x2cb,0x80b,0x84b,0x88b,0x8cb,0x90b,0x94b,0x98b,0x9cb,0xa0b,
+0xa4b,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0x2cb,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,
+0x14,0x15,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0x30b,0x34b,0x38b,0x3cb,
+0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,
+0x18,0x14,0x15,0x18,0x18,0x18,0x18,0,0x18,0,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x14,0x15,
+0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x14,0x15,0x14,0x15,0x14,
+0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,
+0x15,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x14,0x15,0x14,0x15,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x14,0x15,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0,0,0,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
+1,2,1,1,1,2,2,1,2,1,2,1,2,1,1,1,
+1,2,1,2,2,1,2,2,2,2,2,2,2,4,1,1,
+1,2,1,2,2,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,1,2,1,2,6,
+6,6,0,0,0,0,0,0,0,0x17,0x17,0x17,0x17,0x344b,0x17,0x17,
+2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,0,0,0,0,0,0,0,0,0,4,0x17,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,6,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,0,0,0,0,0,0,0,0,0,5,5,5,5,
+5,5,5,0,5,5,5,5,5,5,5,0,5,5,5,5,
+5,5,5,0,5,5,5,5,5,5,5,0,0x17,0x17,0x1c,0x1d,
+0x1c,0x1d,0x17,0x17,0x17,0x1c,0x1d,0x17,0x1c,0x1d,0x17,0x17,0x17,0x17,0x17,0x17,
+0x17,0x17,0x17,0x13,0x17,0x17,0x13,0x17,0x1c,0x1d,0x17,0x17,0x1c,0x1d,0x14,0x15,
+0x14,0x15,0x14,0x15,0x14,0x15,0x17,0x17,0x17,0x17,0x17,4,0x17,0x17,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,
+0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,
+0xc,0x17,0x17,0x17,0x1b,4,5,0x54a,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,
+0x14,0x15,0x1b,0x1b,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x13,0x14,0x15,0x15,
+0x1b,0x58a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,6,6,6,6,6,6,
+0x13,4,4,4,4,4,0x1b,0x1b,0x7ca,0xa4a,0xcca,4,5,0x17,0x1b,0x1b,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,0,0,6,6,0x1a,0x1a,4,4,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,0x17,4,4,4,5,
+0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,0,0,0,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,0,0x1b,0x1b,0x58b,0x5cb,0x60b,0x64b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0xa8b,0xacb,0xb0b,0xb4b,0xb8b,0xbcb,0xc0b,0xc4b,0xc8b,0xccb,0xd0b,
+0xd4b,0xd8b,0xdcb,0xe0b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0xe4b,0xe8b,0xecb,0xf0b,0xf4b,0xf8b,0xfcb,0x100b,0x104b,0x108b,0x10cb,
+0x110b,0x114b,0x118b,0x11cb,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,4,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,0,0,0,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,
+0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,4,0x17,0x17,0x17,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,0x49,0x89,0xc9,0x109,
+0x149,0x189,0x1c9,0x209,0x249,0x289,5,5,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,2,
+1,2,1,2,1,2,1,2,1,2,5,6,7,7,7,0x17,
+0,0,0,0,0,0,0,0,6,6,0x17,4,5,5,5,5,
+5,5,0x58a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0x54a,6,6,0x17,0x17,
+0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,0,0x1a,0x1a,0x1a,0x1a,
+0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,
+0x1a,0x1a,0x1a,4,4,4,4,4,4,4,4,4,0x1a,0x1a,1,2,
+1,2,1,2,1,2,1,2,1,2,1,2,2,2,1,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+4,2,2,2,2,2,2,2,2,1,2,1,2,1,1,2,
+1,2,1,2,1,2,1,2,4,0x1a,0x1a,1,2,1,2,0,
+1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+1,2,1,2,1,2,1,2,1,2,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,2,5,5,5,5,5,5,5,6,5,
+5,5,6,5,5,5,5,6,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,8,
+8,6,6,8,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0x34cb,0x344b,0x3ccb,0x37cb,
+0x35cb,0x3fcb,0x1b,0x1b,0x19,0x1b,0,0,0,0,0,0,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,0,8,8,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,8,8,8,8,
+8,8,8,8,8,8,8,8,6,0,0,0,0,0,0,0,
+0,0,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,
+0,0,0,0,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,6,6,6,5,5,5,5,5,5,0x17,0x17,0x17,5,
+0,0,0,0,5,5,5,5,5,5,6,6,6,6,6,6,
+6,6,0x17,0x17,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,
+6,6,8,8,0,0,0,0,0,0,0,0,0,0,0,0x17,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,6,8,8,6,6,6,6,8,8,6,8,8,8,
+8,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,4,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0x17,0x17,
+5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,8,
+8,6,6,8,8,6,6,0,0,0,0,0,0,0,0,0,
+5,5,5,6,5,5,5,5,5,5,5,5,6,8,0,0,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0x17,0x17,0x17,0x17,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+4,5,5,5,5,5,5,0x1b,0x1b,0x1b,5,8,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+6,5,6,6,6,5,5,6,6,5,5,5,5,5,6,6,
+5,6,5,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,5,5,4,0x17,0x17,
+0,5,5,5,5,5,5,0,0,5,5,5,5,5,5,0,
+0,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,5,5,8,8,6,8,8,6,8,8,0x17,8,6,0,0,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,
+5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,0,0,0,0,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x605,
+5,5,5,5,5,5,5,0x7c5,5,5,5,5,0x5c5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,0x545,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,0x6c5,5,0x6c5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,0x7c5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,0,0,0,0,0,0,2,2,2,2,2,2,2,0,
+0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,
+0,0,0,0,0,5,6,5,5,5,5,5,5,5,5,5,
+5,0x18,5,5,5,5,5,5,5,5,5,5,5,5,5,0,
+5,5,5,5,5,0,5,0,5,5,0,5,5,0,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,
+0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,0x14,0x15,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,0,0,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
+0x19,0x1b,0,0,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,6,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x14,0x15,0x17,0,0,
+0,0,0,0,6,6,6,6,6,6,6,0,0,0,0,0,
+0,0,0,0,0x17,0x13,0x13,0x16,0x16,0x14,0x15,0x14,0x15,0x14,0x15,0x14,
+0x15,0x14,0x15,0x14,0x15,0x17,0x17,0x14,0x15,0x17,0x17,0x17,0x17,0x16,0x16,0x16,
+0x17,0x17,0x17,0,0x17,0x17,0x17,0x17,0x13,0x14,0x15,0x14,0x15,0x14,0x15,0x17,
+0x17,0x17,0x18,0x13,0x18,0x18,0x18,0,0x17,0x19,0x17,0x17,0,0,0,0,
+5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,0,0,0x10,0,0x17,0x17,0x17,0x19,0x17,0x17,0x17,
+0x14,0x15,0x17,0x18,0x17,0x13,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
+0x249,0x289,0x17,0x17,0x18,0x18,0x18,0x17,0x1a,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,0x14,0x18,0x15,0x18,0x14,0x15,0x17,0x14,0x15,0x17,0x17,5,5,
+5,5,5,5,5,5,5,5,4,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,4,4,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,0,0,0,5,5,
+5,5,5,5,0,0,5,5,5,5,5,5,0,0,5,5,
+5,5,5,5,0,0,5,5,5,0,0,0,0x19,0x19,0x18,0x1a,
+0x1b,0x19,0x19,0,0x1b,0x18,0x18,0x18,0x18,0x1b,0x1b,0,0,0,0,0,
+0,0,0,0,0,0x10,0x10,0x10,0x1b,0x1b,0,0,5,5,5,5,
+5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,0,5,5,0,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,0,0,0x17,0x17,0x1b,0,0,0,0,0x58b,
+0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,
+0x1bcb,0x1e4b,0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b,0x784b,0x804b,0x884b,0x904b,0x984b,0xa04b,
+0xa84b,0xb04b,0xb84b,0x788b,0x808b,0x888b,0x908b,0x988b,0xa08b,0xa88b,0xb08b,0xb88b,0,0,0,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x34ca,0x344a,0x58a,0x68a,0x11ca,0x980a,0x984a,0x988a,
+0x68a,0x7ca,0x11ca,0x1e4a,0x980a,0x784a,0x984a,0x68a,0x7ca,0x11ca,0x1e4a,0x980a,0x784a,0x788a,0x988a,0x7ca,
+0x58a,0x58a,0x58a,0x5ca,0x5ca,0x5ca,0x5ca,0x68a,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0xcca,0x11ca,0x11ca,
+0x11ca,0x11ca,0x1e4a,0x880a,0x980a,0x980a,0x980a,0x980a,0x980a,0x784a,0x984a,0x68a,0x11ca,0x344b,0x344b,0x388b,
+0x3ccb,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x54b,0,
+0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x58b,0x68b,0x7cb,0x11cb,0,0,0,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,0x1bca,5,5,5,5,5,5,5,5,0xb80a,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0x17,
+5,5,5,5,0,0,0,0,5,5,5,5,5,5,5,5,
+0x17,0x58a,0x5ca,0x7ca,0xa4a,0x1e4a,0,0,0,0,0,0,0,0,0,0,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,0,0,5,0,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,0,5,5,0,0,0,5,0,0,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,0,0x17,0x58b,0x5cb,0x60b,0x7cb,0xa4b,0x1e4b,0x784b,0x788b,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,0x58b,0x7cb,0xa4b,0x1e4b,0x5cb,0x60b,0,0,0,0x17,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,0,0,0,0,0,0x17,5,6,6,6,
+0,6,6,0,0,0,0,0,6,6,6,6,5,5,5,5,
+0,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,
+6,6,6,0,0,0,0,6,0x30b,0x34b,0x38b,0x3cb,0x7cb,0xa4b,0x1e4b,0x784b,
+0,0,0,0,0,0,0,0,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+0x17,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,0x58b,0x11cb,0x17,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,
+0,0x17,0x17,0x17,0x17,0x17,0x17,0x17,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,
+0x58b,0x5cb,0x60b,0x64b,0x7cb,0xa4b,0x1e4b,0x784b,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,
+0x58b,0x5cb,0x60b,0x64b,0x7cb,0xa4b,0x1e4b,0x784b,5,5,5,5,5,5,5,5,
+5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,
+0x50b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0x800b,0x880b,0x900b,0x980b,0xa00b,
+0xa80b,0xb00b,0xb80b,0x344b,0x34cb,0x348b,0x388b,0,8,6,8,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,0x17,
+0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,
+0x48b,0x4cb,0x50b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0x784b,0x49,0x89,
+0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,8,8,8,6,6,6,6,8,
+8,6,6,0x17,0x17,0x10,0x17,0x17,0x17,0x17,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,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,
+0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0x58a,0x5ca,0x60a,
+0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0x58a,0x5ca,0x60a,0x64a,0x68a,0x5ca,0x60a,0x60a,0x64a,0x68a,
+0x6ca,0x70a,0x74a,0x78a,0x58a,0x5ca,0x60a,0x60a,0x64a,0x68a,0xa,0xa,0x58a,0x5ca,0x60a,0x60a,
+0x64a,0x68a,0x60a,0x60a,0x64a,0x64a,0x64a,0x64a,0x6ca,0x70a,0x70a,0x70a,0x74a,0x74a,0x78a,0x78a,
+0x78a,0x78a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x58a,0x5ca,0x60a,0x64a,0x64a,0x68a,0x68a,0xa,0xa,
+0x58a,0x5ca,0x348a,0x388a,0x454a,0x348a,0x388a,0x35ca,0x34ca,0x354a,0x34ca,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x17,0x17,0x17,0x17,0,0,0,0,
+0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,0,0,0,0,0,0,0,5,5,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,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,
+0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,8,8,6,6,6,0x1b,0x1b,
+0x1b,8,8,8,8,8,8,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,6,
+6,6,6,6,6,6,6,0x1b,0x1b,6,6,6,6,6,6,6,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,6,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0x1b,0x1b,6,6,
+6,0x1b,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,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0,0x58b,0x5cb,0x60b,0x64b,
+0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,
+2,0,2,2,2,2,2,2,2,2,2,2,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+1,0,1,1,0,0,1,0,0,1,1,0,0,1,1,1,
+1,0,1,1,1,1,1,1,1,1,2,2,2,2,0,2,
+0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,
+2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,2,2,2,2,1,1,0,1,1,1,1,0,
+0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
+1,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,1,1,0,1,
+1,1,1,0,1,1,1,1,1,0,1,0,0,0,1,1,
+1,1,1,1,1,0,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,2,2,2,2,2,2,0,0,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,0x18,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0x18,
+2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0x18,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,0x18,2,2,2,2,2,2,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,0x18,
+2,2,2,2,2,2,1,2,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,
+0x1c9,0x209,0x249,0x289,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x49,0x89,
+0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
+0x249,0x289,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,
+0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,
+0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x2cb,0x2cb,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0,0,0,0,0,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,
+0x1b,0x1b,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x1b,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,
+0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,0x1b,0,0,0,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,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,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,0,0x1b,0,
+0x1b,0,0x1b,0,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,
+0x1b,0x1b,0x1b,0x1b,0,0x1b,0,0,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,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,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,0x785,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,0,0x10,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,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,6,6,6,6,6,6,6,6,
+6,6,6,6,6,6,6,6,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,
+0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,
+0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
+0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
+0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0,0,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,0x545,5,5,5,5,5,5,5,5,5,0x585,5,5,0x705,
+5,5,5,0x7885,5,0x605,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0x585,5,5,
+5,5,5,5,5,0x585,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,0x585,5,5,5,5,5,5,5,5,5,5,5,5,5,
+0x585,0x5c5,0x605,5,0x5c5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,0x585,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x5c5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,0x5c5,5,5,5,
+5,5,5,5,0x685,5,0x645,5,5,5,5,5,5,5,5,5,
+5,0x5c5,5,0x745,5,0x6c5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,0x5c5,5,5,5,5,0x5c5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+0x5c5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+0x605,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,0x605,0x605,0x605,0x605,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,0x6c5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0x605,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,0x605,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,0x605,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,0x605,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x645,
+5,5,5,5,5,5,0x645,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+0x645,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x645,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0x645,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,0x685,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x685,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,0x685,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,0x6c5,5,5,5,5,5,0x1e45,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,0x6c5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,0x705,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x705,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,0x705,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,0x745,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,0x785,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,0x785,0xa45,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,0x785,5,5,5,5,5,5,5,5,5,0x7c5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,0x7845,5,0x7c5,5,0x7845,
+0xa45,0xcc5,5,5,5,5,5,5,0xf45,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,0x7c5,5,5,5,5,0xcc5,
+5,5,5,5,5,5,5,5,0xf45,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,0xf45,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,0x1e45,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x1e45,5,
+5,0x7845,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+0x7885,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,0x7985,5,5,5,5,0x7985,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,0x7a85,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+0,0,0,0
+};
+
+static const UTrie2 propsTrie={
+    propsTrie_index,
+    propsTrie_index+3888,
+    NULL,
+    3888,
+    13316,
+    0xa40,
+    0xfb0,
+    0x0,
+    0x0,
+    0x110000,
+    0x4330,
+    NULL, 0, FALSE, FALSE, 0, NULL
+};
+
+static const uint16_t propsVectorsTrie_index[22376]={
+0x404,0x40c,0x414,0x41c,0x434,0x43c,0x444,0x44c,0x454,0x45c,0x464,0x46c,0x474,0x47c,0x484,0x48c,
+0x493,0x49b,0x4a3,0x4ab,0x4ae,0x4b6,0x4be,0x4c6,0x4ce,0x4d6,0x4de,0x4e6,0x4ee,0x4f6,0x4fe,0x506,
+0x50e,0x516,0x51d,0x525,0x52d,0x535,0x53d,0x545,0x54d,0x555,0x55a,0x562,0x569,0x571,0x579,0x581,
+0x589,0x591,0x599,0x5a1,0x5a8,0x5b0,0x5b8,0x5c0,0x5c8,0x5d0,0x5d8,0x5e0,0x5e8,0x5f0,0x5f8,0x600,
+0x14fe,0xc75,0xd55,0x424,0x424,0x424,0x424,0x424,0xe70,0xe76,0xe68,0x670,0x678,0x67e,0x686,0x68e,
+0x696,0x69c,0x6a4,0x6ac,0x6b4,0x6ba,0x6c2,0x6ca,0x6d2,0x6d8,0x6e0,0x6e8,0x6f0,0x6f8,0x700,0x707,
+0x70f,0x715,0x71d,0x725,0x72d,0x733,0x73b,0x743,0x74b,0x751,0x759,0x761,0x769,0x770,0x778,0x780,
+0x788,0x78c,0x794,0x79b,0x7a3,0x7ab,0x7b3,0x7bb,0x1158,0x1160,0x7c3,0x7cb,0x7d3,0x7db,0x7e3,0x7ea,
+0x11be,0x11ae,0x11b6,0x146b,0x1473,0xe7e,0x7f2,0x7f6,0x10ad,0x10ad,0x10af,0xe92,0xe93,0xe86,0xe88,0xe8a,
+0x11c6,0x11c8,0x7fe,0x11c8,0x806,0x80b,0x813,0x11cd,0x819,0x11c8,0x81f,0x827,0xb30,0x11d5,0x11d5,0x82f,
+0x11e5,0x11e6,0x11e6,0x11e6,0x11e6,0x11e6,0x11e6,0x11e6,0x11e6,0x11e6,0x11e6,0x11e6,0x11e6,0x11e6,0x11e6,0x11e6,
+0x11e6,0x11e6,0x11e6,0x11dd,0x837,0x11ee,0x11ee,0x83f,0xa4f,0xa57,0xa5f,0xa67,0x11fe,0x11f6,0x847,0x84f,
+0x857,0x1206,0x120e,0x85f,0x1206,0x867,0x1506,0xc7d,0xa77,0xa7f,0xa87,0xa8c,0x13e6,0xb63,0xb6b,0x134e,
+0xb00,0x150e,0xc85,0xc8d,0xc95,0x608,0x424,0x424,0x1436,0x143b,0xba0,0xba8,0x148f,0xbf1,0x159f,0xd5d,
+0x1497,0xbf9,0xc01,0x149f,0x424,0x424,0x60c,0xc9d,0x136e,0x1356,0x1366,0x135e,0x13fe,0x13f6,0x13be,0xb10,
+0xe9b,0xe9b,0xe9b,0xe9b,0xe9e,0xe9b,0xe9b,0xea6,0x86f,0xeae,0x873,0x87b,0xeae,0x883,0x88b,0x893,
+0xebe,0xeb6,0xec6,0x89b,0x8a3,0x8ab,0x8b2,0x8ba,0xece,0xed6,0xede,0xee6,0x8c2,0xeee,0xef5,0xefd,
+0xf05,0xf0d,0xf15,0xf1d,0xf25,0xf2c,0xf34,0xf3c,0xf44,0xf4c,0xf4f,0xf51,0x1216,0x12eb,0x12f1,0x8ca,
+0xf59,0x8d2,0x8da,0x1062,0x1067,0x106a,0x1070,0xf61,0x1078,0x1078,0xf71,0xf69,0xf79,0xf81,0xf89,0xf91,
+0xf99,0xfa1,0xfa9,0xfb1,0x12f9,0x1346,0x147b,0x1587,0x8e2,0xfbf,0xfc7,0xfcf,0xfb9,0xfd7,0xa6f,0x1301,
+0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x1309,0x1309,0x1309,0x1309,0x1311,0x1318,0x131a,0x1321,
+0x1329,0x132d,0x132d,0x1330,0x132d,0x132d,0x1336,0x132d,0x1376,0x142e,0xa94,0xa9b,0xa9b,0xa9b,0xa9b,0xa9b,
+0x13d6,0xb40,0xb44,0x1443,0x13c6,0x13c6,0x13c6,0xb18,0x13ce,0xb38,0x1416,0xb90,0xb20,0xb28,0xb28,0x14a7,
+0x1406,0xb7b,0xb80,0xb80,0x8ea,0x1226,0x1226,0x8f2,0x122e,0x122e,0x122e,0x122e,0x122e,0x122e,0x8fa,0x614,
+0x1095,0x10b7,0x902,0x10bf,0x90a,0x10c7,0x10cf,0x10d7,0x912,0x917,0x10df,0x10e6,0x91c,0x924,0x1426,0xb08,
+0x92c,0x1135,0x113c,0x10ee,0x1144,0x1148,0x10f6,0x934,0x110f,0x110f,0x1111,0x10fe,0x1106,0x1106,0x1107,0x1150,
+0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,
+0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,
+0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,
+0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,
+0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,
+0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,
+0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,
+0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,
+0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,
+0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,
+0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,
+0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,
+0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0x1236,0xe1c,0x137e,0x137e,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1120,0xe24,0xe27,
+0x123e,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,
+0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,0x1244,
+0x1244,0x1244,0x1244,0x1244,0x93c,0x124c,0x944,0x1516,0x14b3,0x14b3,0x14b3,0x14b3,0x14b3,0x14b3,0x14b3,0x14b3,
+0x14af,0xc09,0x14bb,0xc11,0xc19,0x151e,0x151e,0xca5,0x13de,0x144b,0x1483,0x1487,0xbb0,0xbb8,0xbbb,0xbbd,
+0x140e,0xb88,0x1453,0xbc5,0x14c3,0x14c6,0xc21,0xcad,0x14d6,0x14ce,0xc29,0xcb5,0x1526,0x152a,0xcbd,0x424,
+0x14de,0xc31,0xc39,0xcc5,0x153a,0x1532,0xccd,0x424,0xd65,0x61c,0x424,0x424,0x424,0x424,0x1542,0xcd5,
+0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,
+0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,
+0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,
+0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,
+0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,
+0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,
+0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,
+0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,
+0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,
+0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,
+0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,
+0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,
+0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,
+0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,
+0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,
+0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,
+0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,
+0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,
+0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,
+0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,
+0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,
+0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x94c,0xcdd,0xce0,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,
+0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,0x1178,
+0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,
+0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,
+0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,
+0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,
+0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,
+0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,
+0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,
+0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,
+0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,
+0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,
+0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,
+0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,
+0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1128,0x1128,0x1128,0x1128,0x1128,0x1128,0x1128,0x1128,
+0x112d,0xe2f,0x133e,0xe35,0x141e,0x141e,0xe39,0xe40,0x954,0x95c,0x964,0xff7,0xffe,0x1006,0x96c,0x100e,
+0x103f,0x103f,0xfe7,0xfef,0x1016,0x1036,0x1037,0x1047,0x101e,0xfdf,0x974,0x1026,0x97c,0x102e,0x984,0x988,
+0xb98,0x990,0x998,0x9a0,0x104f,0x1055,0x105a,0x9a8,0x9b8,0x109d,0x10a5,0x1088,0x108d,0x9c0,0x9c8,0x9b0,
+0x1168,0x1168,0x1168,0x1168,0x1168,0x1168,0x1168,0x1168,0x1168,0x1168,0x1168,0x1168,0x1168,0x1168,0x1168,0x1168,
+0x1168,0x1168,0x1168,0x1168,0x1168,0x1168,0x1168,0x1168,0x1168,0x1168,0x1168,0x1168,0x1170,0x1170,0x1170,0x1170,
+0x1090,0x1090,0x10d0,0x1110,0x1150,0x1190,0x11d0,0x1210,0x124c,0x128c,0x12b8,0x12f8,0x1338,0x1378,0x13b8,0x13f8,
+0x1438,0x1474,0x14b4,0x14f4,0x1534,0x1568,0x15a4,0x15e4,0x1624,0x1664,0x16a0,0x16e0,0x1720,0x1760,0x17a0,0x17e0,
+0xa80,0xac0,0xb00,0xa40,0xc8c,0xa40,0xb40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xccc,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xd0c,0xa40,0xa40,0xa40,0xb80,0xa40,0xa40,0xa40,0xbc0,0xbfc,
+0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,
+0xf8d,0xf8d,0xf8d,0xf8d,0xd4c,0xfcd,0xe4d,0xd8c,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xdcd,
+0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,
+0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xd8d,0xe0d,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xbfc,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xbfc,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xbfc,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xbfc,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xbfc,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xbfc,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xbfc,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xbfc,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xbfc,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xbfc,
+0xc3c,0xc4c,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xbfc,
+0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,
+0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xf0d,0xe8d,
+0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,
+0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xf4d,0xecd,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0xaa3,0xaaa,0xab2,0xaba,0x1386,0x1386,0x1386,0xac2,0xaca,0xacd,0x13b6,0x13ae,0xaf8,0xc41,0xc45,0xc49,
+0x424,0x424,0x424,0x424,0xc51,0x14e6,0xc59,0x424,0x9d0,0x9d8,0x624,0x424,0xad5,0x13ee,0xb73,0x424,
+0x1261,0x1254,0x1259,0x138e,0xadd,0x62c,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0xae5,0xae8,0xce8,0x424,0x424,0x424,0x424,0x424,0xbcd,0xc61,0x424,0x424,0x424,0x424,0x424,0x424,
+0xb4c,0xb53,0xb5b,0x154a,0x424,0x424,0x424,0x424,0x1552,0xcf0,0xcf8,0xd00,0x424,0x424,0x424,0x424,
+0x155a,0x155a,0x634,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0xd08,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x15a7,0x15a9,0xd6d,0xd74,0x156a,0x1562,0x63c,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x1572,0x1572,0x1572,0x1572,0x1572,0x1572,0x1572,0x1572,0x1572,0x1572,0x1572,0x1572,0x1572,0x1572,0x1572,0x1572,
+0x1572,0x1572,0x1574,0x1572,0x157c,0x1572,0x1572,0x1572,0x1572,0x1572,0x1572,0x157f,0x1572,0x1572,0x1572,0x1572,
+0x1572,0x644,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x9e0,0x1279,0x9e8,0x127a,0x1271,0x1282,0x1288,0x9f0,0x9f8,
+0x13a6,0x13a6,0x64c,0x424,0x424,0x424,0x424,0x424,0x1396,0x1396,0xaf0,0xbe9,0x424,0x424,0x424,0x424,
+0x12b9,0x12c0,0xa00,0x12c3,0xa08,0xa10,0xa18,0x12bd,0xa20,0xa28,0xa30,0x12c2,0x12ca,0x12b9,0x12c0,0x12bc,
+0x12c3,0x12cb,0x12ba,0x12c1,0x12bd,0xa37,0x1290,0x1298,0x129f,0x12a6,0x1293,0x129b,0x12a2,0x12a9,0xa3f,0x12b1,
+0x14ee,0xc69,0x14f6,0x14f6,0xc6d,0xd8d,0xd95,0xd9d,0xd10,0xd16,0x158f,0xd1e,0xd26,0xd2d,0xd2d,0xd34,
+0xd3c,0xd40,0xd48,0xd4d,0xd4d,0xd4d,0xd4d,0xd4d,0x15b9,0xda5,0x15b9,0xdab,0xdb3,0x15b9,0xdbb,0xdc3,
+0x15b9,0xdcb,0xdd3,0x15b9,0x15b9,0x15b9,0x15b9,0xdd5,0x15b9,0xddd,0xdbf,0xde5,0xde7,0xde7,0xde7,0xde9,
+0xdf1,0xdf9,0x654,0x424,0x15c1,0x15c1,0xe01,0xe03,0x15c9,0x15c9,0x15c9,0xe0b,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x658,0xa47,0x12d3,0x12d3,0x12d3,
+0x660,0x660,0x660,0x660,0x139e,0x139e,0x139e,0x139e,0x139e,0x139e,0x139e,0x668,0x660,0x660,0x660,0x660,
+0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,
+0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,
+0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,
+0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x660,0x145b,0x145b,0x145b,0x145b,
+0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,
+0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0xbd5,0xbd9,0xbd9,0xbd9,0xbd9,0x1463,0x1463,0x1463,0xbe1,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x15b1,0x15b1,0x15b1,0x15b1,
+0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0xd7c,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0xd84,0xd85,0xd85,0xd85,
+0xd85,0xd85,0xd85,0xd85,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,
+0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x424,0x12db,0x12db,0x12db,0x12db,
+0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,
+0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,
+0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,
+0x12db,0x12db,0xe48,0xe13,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0xe60,0xe13,0xe13,0xe13,
+0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,
+0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,
+0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,
+0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0x12e3,0x12e3,0x12e3,
+0x12e3,0x12e3,0x12e3,0x12e3,0x12e3,0x12e3,0x12e3,0x12e3,0x12e3,0x12e3,0x12e3,0x12e3,0x12e3,0xe50,0xe13,0xe13,
+0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,
+0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,
+0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe14,0xe13,0xe13,0xe13,
+0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,
+0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,
+0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,
+0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe14,0x1597,0x1597,0x1597,
+0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,
+0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,
+0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,
+0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0xe58,0x15d1,0x15d1,0x15d1,0x15d1,0x15d1,0x15d1,0x1190,0x1190,0x1190,
+0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,
+0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,
+0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,
+0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1180,0x1198,0x1198,0x1198,
+0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,
+0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,
+0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,
+0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1188,0x1190,0x1190,0x1190,
+0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,
+0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,
+0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,
+0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1190,0x1198,0x1198,0x1198,
+0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,
+0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,
+0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,
+0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x1198,0x12db,0x12db,0x12db,
+0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,
+0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,
+0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,
+0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x12db,0x1597,0x1597,0x1597,
+0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,
+0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,
+0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,
+0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x1597,0x403,0x403,0x403,
+0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1e0,0x1e9,0x1e3,0x1e3,0x1e6,0x1dd,0x1dd,
+0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,0x1dd,
+0x6e7,0x6e1,0x6c3,0x6ab,0x6b7,0x6b4,0x6ab,0x6c6,0x6b1,0x6bd,0x6ab,0x6d8,0x6cf,0x6c0,0x6e4,0x6ba,
+0x6a8,0x6a8,0x6a8,0x6a8,0x6a8,0x6a8,0x6a8,0x6a8,0x6a8,0x6a8,0x6cc,0x6c9,0x6d2,0x6d2,0x6d2,0x6e1,
+0x6ab,0x6f3,0x6f3,0x6f3,0x6f3,0x6f3,0x6f3,0x6ed,0x6ed,0x6ed,0x6ed,0x6ed,0x6ed,0x6ed,0x6ed,0x6ed,
+0x6ed,0x6ed,0x6ed,0x6ed,0x6ed,0x6ed,0x6ed,0x6ed,0x6ed,0x6ed,0x6ed,0x6b1,0x6b7,0x6bd,0x6de,0x6a5,
+0x6db,0x6f0,0x6f0,0x6f0,0x6f0,0x6f0,0x6f0,0x6ea,0x6ea,0x6ea,0x6ea,0x6ea,0x6ea,0x6ea,0x6ea,0x6ea,
+0x6ea,0x6ea,0x6ea,0x6ea,0x6ea,0x6ea,0x6ea,0x6ea,0x6ea,0x6ea,0x6ea,0x6b1,0x6d5,0x6ae,0x6d2,0x1dd,
+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,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1fb,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,
+0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,
+0x1ef,0x558,0x6fc,0x6ff,0x55e,0x6ff,0x6f9,0x552,0x549,0x1f5,0x567,0x1f8,0x702,0x540,0x555,0x6f6,
+0x55b,0x564,0x546,0x546,0x54c,0x1f2,0x552,0x54f,0x549,0x546,0x567,0x1f8,0x543,0x543,0x543,0x558,
+0x201,0x201,0x201,0x201,0x201,0x201,0x570,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201,
+0x570,0x201,0x201,0x201,0x201,0x201,0x201,0x561,0x570,0x201,0x201,0x201,0x201,0x201,0x570,0x56a,
+0x56d,0x56d,0x1fe,0x1fe,0x1fe,0x1fe,0x56a,0x1fe,0x56d,0x56d,0x56d,0x1fe,0x56d,0x56d,0x1fe,0x1fe,
+0x56a,0x1fe,0x56d,0x56d,0x1fe,0x1fe,0x1fe,0x561,0x56a,0x56d,0x56d,0x1fe,0x56d,0x1fe,0x56a,0x1fe,
+0x20d,0x576,0x20d,0x204,0x20d,0x204,0x20d,0x204,0x20d,0x204,0x20d,0x204,0x20d,0x204,0x20d,0x204,
+0x20a,0x573,0x20d,0x576,0x20d,0x204,0x20d,0x204,0x20d,0x204,0x20d,0x576,0x20d,0x204,0x20d,0x204,
+0x20d,0x204,0x20d,0x204,0x20d,0x204,0x57c,0x573,0x20d,0x204,0x20d,0x576,0x20d,0x204,0x20d,0x204,
+0x20d,0x573,0x57f,0x579,0x20d,0x204,0x20d,0x204,0x573,0x20d,0x204,0x20d,0x204,0x20d,0x204,0x57f,
+0x579,0x57c,0x573,0x20d,0x576,0x20d,0x204,0x20d,0x576,0x582,0x57c,0x573,0x20d,0x576,0x20d,0x204,
+0x20d,0x204,0x57c,0x573,0x20d,0x204,0x20d,0x204,0x20d,0x204,0x20d,0x204,0x20d,0x204,0x20d,0x204,
+0x20d,0x204,0x20d,0x204,0x20d,0x204,0x57c,0x573,0x20d,0x204,0x20d,0x576,0x20d,0x204,0x20d,0x204,
+0x20d,0x204,0x20d,0x204,0x20d,0x204,0x20d,0x204,0x20d,0x20d,0x204,0x20d,0x204,0x20d,0x204,0x207,
+0x210,0x21c,0x21c,0x210,0x21c,0x210,0x21c,0x21c,0x210,0x21c,0x21c,0x21c,0x210,0x210,0x21c,0x21c,
+0x21c,0x21c,0x210,0x21c,0x21c,0x210,0x21c,0x21c,0x21c,0x210,0x210,0x210,0x21c,0x21c,0x210,0x21c,
+0x21f,0x213,0x21c,0x210,0x21c,0x210,0x21c,0x21c,0x210,0x21c,0x210,0x210,0x21c,0x210,0x21c,0x21f,
+0x213,0x21c,0x21c,0x21c,0x210,0x21c,0x210,0x21c,0x21c,0x210,0x210,0x219,0x21c,0x210,0x210,0x210,
+0x219,0x219,0x219,0x219,0x222,0x222,0x216,0x222,0x222,0x216,0x222,0x222,0x216,0x21f,0x585,0x21f,
+0x585,0x21f,0x585,0x21f,0x585,0x21f,0x585,0x21f,0x585,0x21f,0x585,0x21f,0x585,0x210,0x21f,0x213,
+0x21f,0x213,0x21f,0x213,0x21c,0x210,0x21f,0x213,0x21f,0x213,0x21f,0x213,0x21f,0x213,0x21f,0x213,
+0x213,0x222,0x222,0x216,0x21f,0x213,0x89a,0x89a,0x89d,0x897,0x21f,0x213,0x21f,0x213,0x21f,0x213,
+0x21f,0x213,0x21f,0x213,0x21f,0x213,0x21f,0x213,0x21f,0x213,0x21f,0x213,0x21f,0x213,0x21f,0x213,
+0x21f,0x213,0x21f,0x213,0x89d,0x897,0x89d,0x897,0x89a,0x894,0x89d,0x897,0xa4a,0xb40,0x89a,0x894,
+0x89a,0x894,0x89d,0x897,0x89d,0x897,0x89d,0x897,0x89d,0x897,0x89d,0x897,0x89d,0x897,0x89d,0x897,
+0xb40,0xb40,0xb40,0xc2d,0xc2d,0xc2d,0xc30,0xc30,0xc2d,0xc30,0xc30,0xc2d,0xc2d,0xc30,0xd62,0xd65,
+0xd65,0xd65,0xd65,0xd62,0xd65,0xd62,0xd65,0xd62,0xd65,0xd62,0xd65,0xd62,0x225,0x588,0x225,0x225,
+0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x588,0x225,0x225,
+0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,
+0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x228,0x225,0x225,0x225,
+0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,
+0x225,0x8a0,0x8a0,0x8a0,0x8a0,0x8a0,0xb43,0xb43,0x23d,0x23d,0x23d,0x23d,0x23d,0x23d,0x23d,0x23d,
+0x23d,0x234,0x234,0x234,0x234,0x234,0x234,0x234,0x231,0x231,0x22b,0x22b,0x58e,0x22b,0x234,0x591,
+0x237,0x591,0x591,0x591,0x237,0x591,0x234,0x234,0x594,0x23a,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,
+0x58b,0x58b,0x58b,0x58b,0x22e,0x58b,0x22b,0x9c9,0x23d,0x23d,0x23d,0x23d,0x23d,0x22b,0x22b,0x22b,
+0x22b,0x22b,0x8a9,0x8a9,0x8a6,0x8a3,0x8a6,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,
+0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,
+0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,
+0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,
+0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,
+0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x597,0x59a,0x59a,0x597,0x59a,0x59a,0x5a0,0x9cc,0x9cc,
+0x9cc,0x9cc,0x9cc,0x9cc,0x9cc,0x9cc,0x9cc,0xafe,0xc09,0xc09,0xc09,0xc09,0xc09,0xc09,0xc09,0xc09,
+0xd35,0xd35,0xd35,0xd35,0xd38,0xc0c,0xc0c,0xc0c,0x59d,0x59d,0x9cf,0xafb,0xafb,0xafb,0xafb,0xafb,
+0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xafb,0xe10,0xe0d,0xe10,0xe0d,0x249,0x252,0xe10,0xe0d,
+6,6,0x258,0xd68,0xd68,0xd68,0x240,6,6,6,6,6,0x255,0x243,0x267,0x246,
+0x267,0x267,0x267,6,0x267,6,0x267,0x267,0x25e,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,
+0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,
+0x5a6,0x5a6,0x267,0x267,0x25e,0x25e,0x25e,0x25e,0x25e,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,
+0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x25b,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,
+0x5a3,0x5a3,0x25e,0x25e,0x25e,0x25e,0x25e,0xe10,0x26a,0x26a,0x26d,0x267,0x267,0x26a,0x261,0x8ac,
+0xa53,0xa50,0x264,0x8ac,0x264,0x8ac,0x264,0x8ac,0x264,0x8ac,0x24f,0x24c,0x24f,0x24c,0x24f,0x24c,
+0x24f,0x24c,0x24f,0x24c,0x24f,0x24c,0x24f,0x24c,0x26a,0x26a,0x261,0x25b,0xa05,0xa02,0xa4d,0xb4c,
+0xb49,0xb4f,0xb4c,0xb49,0xc33,0xc36,0xc36,0xc36,0x8bb,0x5b2,0x27f,0x282,0x27f,0x27f,0x27f,0x282,
+0x27f,0x27f,0x27f,0x27f,0x282,0x8bb,0x282,0x27f,0x5af,0x5af,0x5af,0x5af,0x5af,0x5af,0x5af,0x5af,
+0x5af,0x5b2,0x5af,0x5af,0x5af,0x5af,0x5af,0x5af,0x5af,0x5af,0x5af,0x5af,0x5af,0x5af,0x5af,0x5af,
+0x5af,0x5af,0x5af,0x5af,0x5af,0x5af,0x5af,0x5af,0x5a9,0x5a9,0x5a9,0x5a9,0x5a9,0x5a9,0x5a9,0x5a9,
+0x5a9,0x5ac,0x5a9,0x5a9,0x5a9,0x5a9,0x5a9,0x5a9,0x5a9,0x5a9,0x5a9,0x5a9,0x5a9,0x5a9,0x5a9,0x5a9,
+0x5a9,0x5a9,0x5a9,0x5a9,0x8b5,0x5ac,0x279,0x27c,0x279,0x279,0x279,0x27c,0x279,0x279,0x279,0x279,
+0x27c,0x8b5,0x27c,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,
+0x27f,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,0x282,0x27c,0x27f,0x279,0x27f,0x279,
+0x27f,0x279,0x27f,0x279,0x27f,0x279,0x276,0x273,0x273,0x270,0x270,0xe13,0x8af,0x8af,0xa59,0xa56,
+0x8b8,0x8b2,0x8b8,0x8b2,0x27f,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,
+0x27f,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,
+0x27f,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,0x27f,0x279,
+0x27f,0x279,0x27f,0x279,0x27f,0x282,0x27c,0x27f,0x279,0xa59,0xa56,0x27f,0x279,0xa59,0xa56,0x27f,
+0x279,0xa59,0xa56,0xd6b,0x282,0x27c,0x282,0x27c,0x27f,0x279,0x282,0x27c,0x27f,0x279,0x282,0x27c,
+0x282,0x27c,0x282,0x27c,0x27f,0x279,0x282,0x27c,0x282,0x27c,0x282,0x27c,0x27f,0x279,0x282,0x27c,
+0x8bb,0x8b5,0x282,0x27c,0x282,0x27c,0x282,0x27c,0x282,0x27c,0xc3c,0xc39,0x282,0x27c,0xd6e,0xd6b,
+0xd6e,0xd6b,0xd6e,0xd6b,0xabf,0xabc,0xabf,0xabc,0xabf,0xabc,0xabf,0xabc,0xabf,0xabc,0xabf,0xabc,
+0xabf,0xabc,0xabf,0xabc,0xd9b,0xd98,0xd9b,0xd98,0xe8e,0xe8b,0xe8e,0xe8b,0xe8e,0xe8b,0xe8e,0xe8b,
+0xe8e,0xe8b,0xe8e,0xe8b,0xe8e,0xe8b,0xe8e,0xe8b,0xfe1,0xfde,0x1188,0x1185,0xba,0xba,0xba,0xba,
+0xba,0xba,0xba,0xba,9,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,
+0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,9,
+9,0x294,0x285,0x285,0x297,0x288,0x297,0x285,9,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,
+0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,
+0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28e,9,0x7aa,0x8be,9,
+9,9,9,9,0xc,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,
+0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0xc3f,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,
+0x82e,0x82e,0x82e,0x82e,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0xd71,0x29a,
+0x29a,0x29a,0x2a6,0x29a,0x29d,0x29a,0x29a,0x2a9,0x831,0xc42,0xc45,0xc42,0xc,0xc,0xc,0xc,
+0xc,0xc,0xc,0xc,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,
+0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0xc,
+0xc,0xc,0xc,0xc,0x2ac,0x2ac,0x2ac,0x2a3,0x2a0,0xc,0xc,0xc,0xc,0xc,0xc,0xc,
+0xc,0xc,0xc,0xc,0xb52,0xb52,0xb52,0xb52,0xf,0xf,0xe1c,0xe1c,0xe1c,0xe19,0xe19,0xc4e,
+0x7b6,0xb61,0xb5e,0xb5e,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xe16,0xe16,0xe16,0xe16,0xe16,0x7b3,
+0xf,0xf,0xc4b,0x7b9,0x1155,0x2c7,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,
+0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0xe1f,
+0xe1f,0xe1f,0xe1f,0xe1f,0x7ad,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x81f,
+0x81f,0x81f,0x81f,0x81f,0x81f,0x81f,0x81f,0x9ff,0x9ff,0x9ff,0xb55,0xb5b,0xb58,0xc48,0xc48,0xc48,
+0xc48,0xc48,0xc48,0x1152,0x7b0,0x7b0,0x7b0,0x7b0,0x7b0,0x7b0,0x7b0,0x7b0,0x7b0,0x7b0,0x2c1,0x2be,
+0x2bb,0x2b8,0xa5c,0xa5c,0x81c,0x2c7,0x2c7,0x2d3,0x2c7,0x2cd,0x2cd,0x2cd,0x2cd,0x2c7,0x2c7,0x2c7,
+0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,
+0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,
+0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,
+0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x8c4,0x8c4,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x8c4,
+0x2ca,0x2c7,0x2ca,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x8c4,
+0x2c7,0x2c7,0x2c7,0x2ca,0x2d6,0x2c7,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x2af,0x2b8,0x2b5,
+0x2b5,0x2b2,0x2b2,0x2b2,0x2b2,0x2d0,0x2d0,0x2b2,0x2b2,0x2b8,0x2b5,0x2b5,0x2b5,0x2b2,0xb64,0xb64,
+0x2c4,0x2c4,0x2c4,0x2c4,0x2c4,0x2c4,0x2c4,0x2c4,0x2c4,0x2c4,0x8c4,0x8c4,0x8c4,0x8c1,0x8c1,0xb64,
+0x8dc,0x8dc,0x8dc,0x8d6,0x8d6,0x8d6,0x8d6,0x8d6,0x8d6,0x8d6,0x8d6,0x8d3,0x8d6,0x8d3,0x12,0x8c7,
+0x8d9,0x8ca,0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,
+0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,0x8d9,0xb67,0xb67,0xb67,
+0x8d0,0x8d0,0x8d0,0x8d0,0x8d0,0x8d0,0x8d0,0x8d0,0x8d0,0x8d0,0x8d0,0x8d0,0x8d0,0x8d0,0x8d0,0x8d0,
+0x8cd,0x8cd,0x8cd,0x8cd,0x8cd,0x8cd,0x8cd,0x8cd,0x8cd,0x8cd,0x8cd,0x12,0x12,0xb67,0xb67,0xb67,
+0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,
+0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xcab,0xea0,0xea0,
+0xea0,0xea0,0xea0,0xea0,0xea0,0xea0,0xea0,0xea0,0xea0,0xea0,0xea0,0xea0,0xea0,0xea0,0xea0,0xea0,
+0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,
+0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,
+0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8e2,0x8df,0x8df,0x8df,0x8df,0x8df,0x8df,0x8df,0x8df,0x8df,0x8df,
+0x8df,0xa5f,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+0xdb3,0xdb3,0xdb3,0xdb3,0xdb3,0xdb3,0xdb3,0xdb3,0xdb3,0xdb3,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,
+0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,
+0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdb6,0xdaa,0xdaa,0xdaa,0xdaa,0xdaa,
+0xdaa,0xdaa,0xdaa,0xdaa,0xdb9,0xdb9,0xdad,0xdad,0xdb0,0xdbf,0xdbc,0x11d,0x11d,0x11d,0x11d,0x11d,
+0x101d,0x101d,0x101d,0x101d,0x101d,0x101d,0x101d,0x1029,0x102c,0x102c,0x102c,0x102c,0x101d,0x101d,0x165,0x165,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x103b,0x103b,0x103b,0x102f,0x103b,0x103b,0x103b,0x103b,0x103b,0x103b,0x103b,0x103b,0x103b,0x103b,0x103b,0x103b,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x9db,0x9db,0x9de,0x9de,0x9db,0x9db,0x9db,0x9db,0x9db,0x9db,0x9db,0x9db,0x78,0x78,0x78,0x78,
+0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x1aa,0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x1aa,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0xa11,0xa11,0xa11,0xa11,0xa11,0xa11,0xa11,0xa11,0xa11,0xa11,0xa11,0xab,0xab,0xab,0xab,0xab,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0xbfd,0xbfd,0xbfd,0xbfd,0xbfd,0xbfd,0xbfd,0xbfd,0xbfd,0xbfd,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x192,0x192,0x192,0x192,0x192,0x192,0x192,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x1101,0x1101,0x198,0x198,0x198,0x198,0x198,0x198,0x198,0x198,0x198,0x198,0x198,0x198,0x198,0x198,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x19b,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0xca2,0xca2,0xc9f,0xc9f,0xc9f,0xca2,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x11e5,0x1bc,0x1bc,0x1bc,0x1bc,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,
+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,0x82b,0x82b,
+3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,
+3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+0x2ee,0x2ee,0x2df,0x2df,0x7bc,0x7bc,0x2e8,0x2e8,0x2e8,0x2e8,0x2e8,0x2e8,0x2e8,0x2e8,0x2e8,0x2e8,
+0x2d9,0xe25,0xe22,0x115e,0x115e,0x115e,0x115e,0x115e,0x18,0xfb7,0xfb7,0xd74,0xd74,0xc51,0xd74,0xd74,
+0x1b,0x2f4,0x306,0x306,0x1b,0x30c,0x30c,0x30c,0x30c,0x30c,0x30c,0x30c,0x30c,0x1b,0x1b,0x30c,
+0x30c,0x1b,0x1b,0x30c,0x30c,0x30c,0x30c,0x30c,0x30c,0x30c,0x30c,0x30c,0x30c,0x30c,0x30c,0x30c,
+0x30c,0x1b,0x30c,0x30c,0x30c,0x30c,0x30c,0x30c,0x30c,0x1b,0x30c,0x1b,0x1b,0x1b,0x30c,0x30c,
+0x30c,0x30c,0x1b,0x1b,0x2f7,0xb6d,0x2f4,0x306,0x306,0x2f4,0x2f4,0x2f4,0x2f4,0x1b,0x1b,0x306,
+0x306,0x1b,0x1b,0x309,0x309,0x2fa,0xc54,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x2f4,
+0x1b,0x1b,0x1b,0x1b,0x30f,0x30f,0x1b,0x30f,0x30c,0x30c,0x2f4,0x2f4,0x1b,0x1b,0x303,0x303,
+0x303,0x303,0x303,0x303,0x303,0x303,0x303,0x303,0x30c,0x30c,0x300,0x300,0x2fd,0x2fd,0x2fd,0x2fd,
+0x2fd,0x300,0x2fd,0xfba,0x1b,0x1b,0x1b,0x1b,0x1e,0xb70,0x312,0xb73,0x1e,0x321,0x321,0x321,
+0x321,0x321,0x321,0x1e,0x1e,0x1e,0x1e,0x321,0x321,0x1e,0x1e,0x321,0x321,0x321,0x321,0x321,
+0x321,0x321,0x321,0x321,0x321,0x321,0x321,0x321,0x321,0x1e,0x321,0x321,0x321,0x321,0x321,0x321,
+0x321,0x1e,0x321,0x324,0x1e,0x321,0x324,0x1e,0x321,0x321,0x1e,0x1e,0x315,0x1e,0x31e,0x31e,
+0x31e,0x312,0x312,0x1e,0x1e,0x1e,0x1e,0x312,0x312,0x1e,0x1e,0x312,0x312,0x318,0x1e,0x1e,
+0x1e,0xe28,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x324,0x324,0x324,0x321,0x1e,0x324,0x1e,
+0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,
+0x312,0x312,0x321,0x321,0x321,0xe28,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
+0x21,0x327,0x327,0x333,0x21,0x336,0x336,0x336,0x336,0x336,0x336,0x336,0xb7c,0x336,0x21,0x336,
+0x336,0x336,0x21,0x336,0x336,0x336,0x336,0x336,0x336,0x336,0x336,0x336,0x336,0x336,0x336,0x336,
+0x336,0x21,0x336,0x336,0x336,0x336,0x336,0x336,0x336,0x21,0x336,0x336,0x21,0x336,0x336,0x336,
+0x336,0x336,0x21,0x21,0x32a,0x336,0x333,0x333,0x333,0x327,0x327,0x327,0x327,0x327,0x21,0x327,
+0x327,0x333,0x21,0x333,0x333,0x32d,0x21,0x21,0x336,0x21,0x21,0x21,0x21,0x21,0x21,0x21,
+0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x336,0xb7c,0xb76,0xb76,0x21,0x21,0x330,0x330,
+0x330,0x330,0x330,0x330,0x330,0x330,0x330,0x330,0x21,0xb79,0x21,0x21,0x21,0x21,0x21,0x21,
+0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x24,0x339,0x348,0x348,0x24,0x34e,0x34e,0x34e,
+0x34e,0x34e,0x34e,0x34e,0x34e,0x24,0x24,0x34e,0x34e,0x24,0x24,0x34e,0x34e,0x34e,0x34e,0x34e,
+0x34e,0x34e,0x34e,0x34e,0x34e,0x34e,0x34e,0x34e,0x34e,0x24,0x34e,0x34e,0x34e,0x34e,0x34e,0x34e,
+0x34e,0x24,0x34e,0x34e,0x24,0xb7f,0x34e,0x34e,0x34e,0x34e,0x24,0x24,0x33c,0x34e,0x339,0x339,
+0x348,0x339,0x339,0x339,0xe2b,0x24,0x24,0x348,0x34b,0x24,0x24,0x34b,0x34b,0x33f,0x24,0x24,
+0x24,0x24,0x24,0x24,0x24,0x24,0x339,0x339,0x24,0x24,0x24,0x24,0x351,0x351,0x24,0x34e,
+0x34e,0x34e,0xe2b,0xe2b,0x24,0x24,0x345,0x345,0x345,0x345,0x345,0x345,0x345,0x345,0x345,0x345,
+0x342,0xb7f,0x1161,0x1161,0x1161,0x1161,0x1161,0x1161,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,
+0x27,0x27,0x354,0x366,0x27,0x366,0x366,0x366,0x366,0x366,0x366,0x27,0x27,0x27,0x366,0x366,
+0x366,0x27,0x366,0x366,0x369,0x366,0x27,0x27,0x27,0x366,0x366,0x27,0x366,0x27,0x366,0x366,
+0x27,0x27,0x27,0x366,0x366,0x27,0x27,0x27,0x366,0x366,0x366,0x27,0x27,0x27,0x366,0x366,
+0x366,0x366,0x366,0x366,0x366,0x366,0xc5a,0x366,0x366,0x366,0x27,0x27,0x27,0x27,0x354,0x360,
+0x354,0x360,0x360,0x27,0x27,0x27,0x360,0x360,0x360,0x27,0x363,0x363,0x363,0x357,0x27,0x27,
+0xe2e,0x27,0x27,0x27,0x27,0x27,0x27,0x354,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,
+0x27,0x27,0xc57,0x35d,0x35d,0x35d,0x35d,0x35d,0x35d,0x35d,0x35d,0x35d,0x35a,0x35a,0x35a,0xb82,
+0xb82,0xb82,0xb82,0xb82,0xb82,0xb85,0xb82,0x27,0x27,0x27,0x27,0x27,0x2a,0x378,0x378,0x378,
+0x2a,0x37b,0x37b,0x37b,0x37b,0x37b,0x37b,0x37b,0x37b,0x2a,0x37b,0x37b,0x37b,0x2a,0x37b,0x37b,
+0x37b,0x37b,0x37b,0x37b,0x37b,0x37b,0x37b,0x37b,0x37b,0x37b,0x37b,0x37b,0x37b,0x2a,0x37b,0x37b,
+0x37b,0x37b,0x37b,0x37b,0x37b,0x37b,0x37b,0x37b,0x2a,0x37b,0x37b,0x37b,0x37b,0x37b,0x2a,0x2a,
+0x2a,0xe37,0x36c,0x36c,0x36c,0x378,0x378,0x378,0x378,0x2a,0x36c,0x36c,0x36f,0x2a,0x36c,0x36c,
+0x36c,0x372,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x36c,0x36c,0x2a,0xe37,0xe37,0x2a,0x2a,
+0x2a,0x2a,0x2a,0x2a,0x37b,0x37b,0xe31,0xe31,0x2a,0x2a,0x375,0x375,0x375,0x375,0x375,0x375,
+0x375,0x375,0x375,0x375,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0xe34,0xe34,0xe34,0xe34,
+0xe34,0xe34,0xe34,0xe34,0x2d,0x2d,0x387,0x387,0x2d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,
+0x38d,0x2d,0x38d,0x38d,0x38d,0x2d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,
+0x38d,0x38d,0x38d,0x38d,0x38d,0x2d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,
+0x2d,0x38d,0x38d,0x38d,0x38d,0x38d,0x2d,0x2d,0xb88,0xb8b,0x387,0x37e,0x38a,0x387,0x37e,0x387,
+0x387,0x2d,0x37e,0x38a,0x38a,0x2d,0x38a,0x38a,0x37e,0x381,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,
+0x2d,0x37e,0x37e,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x38d,0x2d,0x38d,0x38d,0xd77,0xd77,
+0x2d,0x2d,0x384,0x384,0x384,0x384,0x384,0x384,0x384,0x384,0x384,0x384,0x2d,0xd7a,0xd7a,0x2d,
+0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x30,0x30,0x399,0x399,
+0x30,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x30,0x39f,0x39f,0x39f,0x30,0x39f,0x39f,
+0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x1164,0x39f,0x39f,
+0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x1164,0x30,
+0x30,0xe43,0x390,0x399,0x399,0x390,0x390,0x390,0xe3a,0x30,0x399,0x399,0x399,0x30,0x39c,0x39c,
+0x39c,0x393,0x1164,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x390,0x30,0x30,0x30,0x30,
+0x30,0x30,0x30,0x30,0x39f,0x39f,0xe3a,0xe3a,0x30,0x30,0x396,0x396,0x396,0x396,0x396,0x396,
+0x396,0x396,0x396,0x396,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0x30,0x30,0x30,0xe40,0xe43,0xe43,
+0xe43,0xe43,0xe43,0xe43,0x33,0x33,0x8ee,0x8ee,0x33,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,
+0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x33,0x33,0x33,0x8f4,0x8f4,
+0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,
+0x8f4,0x8f4,0x33,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x33,0x8f4,0x33,0x33,
+0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x8f4,0x33,0x33,0x33,0x8e8,0x33,0x33,0x33,0x33,0x8e5,
+0x8ee,0x8ee,0x8e5,0x8e5,0x8e5,0x33,0x8e5,0x33,0x8ee,0x8ee,0x8f1,0x8ee,0x8f1,0x8f1,0x8f1,0x8e5,
+0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
+0x33,0x33,0x8ee,0x8ee,0x8eb,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
+0x36,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,
+0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,
+0x3bd,0x3a5,0x3bd,0x3b7,0x3a5,0x3a5,0x3a5,0x3a5,0x3a5,0x3a5,0x3ab,0x36,0x36,0x36,0x36,0x3a2,
+0x3c3,0x3c3,0x3c3,0x3c3,0x3c3,0x3bd,0x3c0,0x3a8,0x3a8,0x3a8,0x3a8,0x3a8,0x3a8,0x3a5,0x3a8,0x3ae,
+0x3b4,0x3b4,0x3b4,0x3b4,0x3b4,0x3b4,0x3b4,0x3b4,0x3b4,0x3b4,0x3b1,0x3b1,0x36,0x36,0x36,0x36,
+0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x39,0x3d2,0x3d2,0x39,
+0x3d2,0x39,0x39,0x3d2,0x3d2,0x39,0x3d2,0x39,0x39,0x3d2,0x39,0x39,0x39,0x39,0x39,0x39,
+0x3d2,0x3d2,0x3d2,0x3d2,0x39,0x3d2,0x3d2,0x3d2,0x3d2,0x3d2,0x3d2,0x3d2,0x39,0x3d2,0x3d2,0x3d2,
+0x39,0x3d2,0x39,0x3d2,0x39,0x39,0x3d2,0x3d2,0x39,0x3d2,0x3d2,0x3d2,0x3d8,0x3c6,0x3d8,0x3cf,
+0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x39,0x3c6,0x3c6,0x3d2,0x39,0x39,0x3de,0x3de,0x3de,0x3de,
+0x3de,0x39,0x3db,0x39,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c6,0x39,0x39,0x3cc,0x3cc,0x3cc,0x3cc,
+0x3cc,0x3cc,0x3cc,0x3cc,0x3cc,0x3cc,0x39,0x39,0x3d5,0x3d5,0x39,0x39,0x39,0x39,0x39,0x39,
+0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,
+0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x867,0x867,0x867,0x86a,
+0x867,0x867,0x867,0x867,0x3c,0x867,0x867,0x867,0x867,0x86a,0x867,0x867,0x867,0x867,0x86a,0x867,
+0x867,0x867,0x867,0x86a,0x867,0x867,0x867,0x867,0x86a,0x867,0x867,0x867,0x867,0x867,0x867,0x867,
+0x867,0x867,0x867,0x867,0x867,0x86a,0x903,0xe4f,0xe4f,0x3c,0x3c,0x3c,0x3c,0x834,0x834,0x837,
+0x834,0x837,0x837,0x840,0x837,0x840,0x834,0x834,0x834,0x834,0x834,0x861,0x834,0x837,0x83a,0x83a,
+0x83d,0x846,0x83a,0x83a,0x867,0x867,0x867,0x867,0x116d,0x1167,0x1167,0x1167,0x834,0x834,0x834,0x837,
+0x834,0x834,0x8f7,0x834,0x3c,0x834,0x834,0x834,0x834,0x837,0x834,0x834,0x834,0x834,0x837,0x834,
+0x834,0x834,0x834,0x837,0x834,0x834,0x834,0x834,0x837,0x834,0x8f7,0x8f7,0x8f7,0x834,0x834,0x834,
+0x834,0x834,0x834,0x834,0x8f7,0x837,0x8f7,0x8f7,0x8f7,0x3c,0x900,0x900,0x8fd,0x8fd,0x8fd,0x8fd,
+0x8fd,0x8fd,0x8fa,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x3c,0xe46,0x8fd,0xc5d,0xc5d,0xe49,0xe4c,
+0xe46,0xfbd,0xfbd,0xfbd,0xfbd,0x116a,0x116a,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,
+0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,
+0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3f,0x3f,
+0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3e4,0x3e4,0x3e4,0x3e4,0x3e4,0x3e4,0x3e4,0x3e4,
+0x3e4,0x3e4,0x3e4,0x3e4,0x3e4,0x3e4,0x3e4,0x3e4,0x3e4,0x3e4,0x3e4,0x3e4,0x3e4,0x3e4,0x3e4,0xa62,
+0xa62,0xc60,0xc60,0x3e1,0xc63,0x3f,0x3f,0x3f,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0xc6c,
+0x92d,0x42,0x92d,0x92d,0x92d,0x92d,0x42,0x42,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x42,
+0x92d,0x42,0x92d,0x92d,0x92d,0x92d,0x42,0x42,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0xc6c,
+0x92d,0x42,0x92d,0x92d,0x92d,0x92d,0x42,0x42,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,
+0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0xc6c,0x92d,0x42,0x92d,0x92d,
+0x92d,0x92d,0x42,0x42,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x42,0x92d,0x42,0x92d,0x92d,
+0x92d,0x92d,0x42,0x42,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0xc6c,0x92d,0x92d,0x92d,0x92d,
+0x92d,0x92d,0x92d,0x42,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,
+0x92d,0x92d,0x92d,0xc6c,0x92d,0x42,0x92d,0x92d,0x92d,0x92d,0x42,0x42,0x92d,0x92d,0x92d,0x92d,
+0x92d,0x92d,0x92d,0xc6c,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,
+0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x42,0x42,0x1170,0x1170,0xc66,0xc69,0x927,0x930,0x924,
+0x924,0x924,0x924,0x930,0x930,0x92a,0x92a,0x92a,0x92a,0x92a,0x92a,0x92a,0x92a,0x92a,0x921,0x921,
+0x921,0x921,0x921,0x921,0x921,0x921,0x921,0x921,0x921,0x42,0x42,0x42,0x933,0x933,0x933,0x933,
+0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,
+0x933,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x945,0x948,0x948,0x948,
+0x948,0x948,0x948,0x948,0x948,0x948,0x948,0x948,0x948,0x948,0x948,0x948,0x948,0x948,0x948,0x948,
+0x948,0x948,0x948,0x948,0x948,0x948,0x948,0x942,0x93f,0x48,0x48,0x48,0x94e,0x94e,0x94e,0x94e,
+0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94b,0x94b,0x94b,0x94e,0x94e,0x94e,0x4b,0x4b,0x4b,
+0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x96f,0x96f,0x96f,0x96f,
+0x96f,0x96f,0x954,0x96f,0x96f,0x957,0x957,0x957,0x957,0x957,0x957,0x957,0x957,0x957,0x95a,0x957,
+0x966,0x966,0x969,0x972,0x960,0x95d,0x966,0x963,0x972,0xb8e,0x4e,0x4e,0x96c,0x96c,0x96c,0x96c,
+0x96c,0x96c,0x96c,0x96c,0x96c,0x96c,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0xb91,0xb91,0xb91,0xb91,
+0xb91,0xb91,0xb91,0xb91,0xb91,0xb91,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x97b,0x97b,0x9f6,0x9f9,
+0x984,0x9f3,0x981,0x97b,0x987,0x993,0x97b,0x996,0x996,0x996,0x97e,0x51,0x98a,0x98a,0x98a,0x98a,
+0x98a,0x98a,0x98a,0x98a,0x98a,0x98a,0x51,0x51,0x51,0x51,0x51,0x51,0x98d,0x98d,0x98d,0x98d,
+0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,
+0x98d,0x98d,0x98d,0x98d,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x98d,0x98d,0x98d,0x98d,
+0x98d,0x98d,0x98d,0x98d,0x98d,0x978,0xe6d,0x51,0x51,0x51,0x51,0x51,0x100e,0x100e,0x100e,0x100e,
+0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x405,0x405,0x405,0x405,
+0x405,0x405,0x405,0x405,0x408,0x408,0x408,0x408,0x408,0x408,0x408,0x408,0x405,0x405,0x405,0x405,
+0x405,0x405,0x54,0x54,0x408,0x408,0x408,0x408,0x408,0x408,0x54,0x54,0x405,0x405,0x405,0x405,
+0x405,0x405,0x405,0x405,0x54,0x408,0x54,0x408,0x54,0x408,0x54,0x408,0x405,0x405,0x405,0x405,
+0x405,0x405,0x405,0x405,0x408,0x408,0x408,0x408,0x408,0x408,0x408,0x408,0x405,0x405,0x405,0x405,
+0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x54,0x54,0x405,0x405,0x405,0x405,
+0x405,0x405,0x405,0x405,0x408,0x408,0x408,0x408,0x408,0x408,0x408,0x408,0x405,0x405,0x405,0x405,
+0x405,0x54,0x405,0x405,0x408,0x408,0x408,0x408,0x408,0x3ff,0x405,0x3ff,0x3ff,0x3fc,0x405,0x405,
+0x405,0x54,0x405,0x405,0x408,0x408,0x408,0x408,0x408,0x3fc,0x3fc,0x3fc,0x405,0x405,0x405,0x405,
+0x54,0x54,0x405,0x405,0x408,0x408,0x408,0x408,0x54,0x3fc,0x3fc,0x3fc,0x405,0x405,0x405,0x405,
+0x405,0x405,0x405,0x405,0x408,0x408,0x408,0x408,0x408,0x3fc,0x3fc,0x3fc,0x54,0x54,0x405,0x405,
+0x405,0x54,0x405,0x405,0x408,0x408,0x408,0x408,0x408,0x402,0x3ff,0x54,0xa65,0xa68,0xa68,0xa68,
+0xe76,0x57,0x57,0x57,0x57,0x57,0x411,0x411,0x411,0x411,0x411,0x411,0x459,0xa7a,0x5a,0x5a,
+0x5e8,0x459,0x459,0x459,0x459,0x459,0x45f,0x471,0x45f,0x46b,0x465,0x5eb,0x456,0x5e5,0x5e5,0x5e5,
+0x5e5,0x456,0x456,0x456,0x456,0x456,0x45c,0x46e,0x45c,0x468,0x462,0x5a,0xc75,0xc75,0xc75,0xc75,
+0xc75,0x1173,0x1173,0x1173,0x1173,0x1173,0x1173,0x1173,0x1173,0x5a,0x5a,0x5a,0x477,0x477,0x477,0x477,
+0x477,0x477,0x477,0x474,0x47a,0x64b,0x477,0x870,0x891,0x9a2,0x9a2,0x9a2,0xa7d,0xa7d,0xc78,0xc78,
+0xc78,0xc78,0xfcf,0xfd2,0xfd2,0x1176,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,
+0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x480,0x480,0x480,0x480,0x480,0x480,0x480,0x480,
+0x480,0x480,0x480,0x480,0x480,0x47d,0x47d,0x47d,0x47d,0x480,0x9a5,0x9a5,0xa80,0xa86,0xa86,0xa83,
+0xa83,0xa83,0xa83,0xc7b,0xd7d,0xd7d,0xd7d,0xd7d,0xe79,0x60,0x60,0x60,0x60,0x60,0x60,0x60,
+0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x4b0,0x4b0,0x4b0,0x9ae,0xd86,0xe7f,0xe7f,0xe7f,
+0xe7f,0x1110,0x63,0x63,0x63,0x63,0x63,0x63,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,
+0x612,0x612,0x4bc,0x4bc,0x4b9,0x4b9,0x4b9,0x4b9,0xd8c,0xd8c,0xd8c,0xd89,0xd89,0xd89,0xd89,0xd89,
+0xfd8,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x66,0x66,0x66,0x66,
+0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x9b7,0x9b7,0x69,
+0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,
+0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x4d7,0x4d7,0x4d7,0x4d7,0x4d7,0x4d7,0x4d7,0x4d7,
+0x4d7,0x4d7,0x4d7,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,
+0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6f,0x4f5,0x4f5,0x4f5,0x4f5,0x117f,0x4f5,0x4f5,
+0x4f5,0x4f5,0x117f,0x117f,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,
+0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,
+0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,
+0x9d2,0x9d2,0x72,0x9d2,0x9d2,0x9d2,0x9d2,0x9d5,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,
+0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d5,0x72,0x72,0x72,0x72,
+0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,
+0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x75,0x75,
+0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x7b,0x729,0x723,0x729,0x723,0x729,0x723,0x729,
+0x723,0x729,0x723,0x723,0x726,0x723,0x726,0x723,0x726,0x723,0x726,0x723,0x726,0x723,0x726,0x723,
+0x726,0x723,0x726,0x723,0x726,0x723,0x726,0x723,0x723,0x723,0x723,0x729,0x723,0x729,0x723,0x729,
+0x723,0x723,0x723,0x723,0x723,0x723,0x729,0x723,0x723,0x723,0x723,0x723,0x726,0xb1f,0xb1f,0x7b,
+0x7b,0x825,0x825,0x801,0x801,0x72c,0x72f,0xb1c,0x7e,0x7e,0x7e,0x7e,0x7e,0x741,0x741,0x741,
+0x741,0x741,0x741,0x741,0x741,0x741,0x741,0x741,0x741,0x741,0x741,0x741,0x741,0x741,0x741,0x741,
+0x741,0x741,0x741,0x741,0x741,0x741,0x741,0x741,0x741,0xfa8,0x7e,0x7e,0x81,0x744,0x744,0x744,
+0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x81,
+0x80a,0x80a,0x80d,0x80d,0x80d,0x80d,0x80d,0x80d,0x80d,0x80d,0x80d,0x80d,0x80d,0x80d,0x80d,0x80d,
+0x9e4,0x9e4,0x9e4,0x9e4,0x9e4,0x9e4,0x9e4,0x9e4,0x9e4,0x9e4,0x9e4,0x9e4,0x9e4,0x9e4,0x9e4,0x9e4,
+0x9e4,0x9e4,0x9e4,0x9e4,0x9e4,0x9e4,0x9e4,0x9e4,0x11f4,0x11f4,0x11f4,0x84,0x84,0x84,0x84,0x84,
+0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,
+0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0xc1b,0xc1b,0x87,
+0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,
+0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x87,
+0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x8a,0x8a,0x8a,
+0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,
+0x9f0,0xb28,0x9f0,0x9f0,0x9f0,0xb28,0x9f0,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,
+0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,
+0x88b,0x88b,0x88b,0x88b,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,
+0x1143,0x1143,0x1143,0x1143,0x1143,0x1143,0x1143,0x1143,0x1143,0x1143,0x1143,0x1143,0x1143,0x1143,0x1143,0x1143,
+0x510,0x510,0x510,0x510,0x510,0x510,0x510,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,
+0x93,0x93,0x93,0x4fe,0x4fe,0x4fe,0x4fe,0x4fe,0x93,0x93,0x93,0x93,0x93,0x9c3,0x501,0x507,
+0x50d,0x50d,0x50d,0x50d,0x50d,0x50d,0x50d,0x50d,0x50d,0x504,0x507,0x507,0x507,0x507,0x507,0x507,
+0x507,0x507,0x507,0x507,0x507,0x507,0x507,0x93,0x507,0x507,0x507,0x507,0x507,0x93,0x507,0x93,
+0x507,0x507,0x93,0x507,0x507,0x93,0x507,0x507,0x507,0x507,0x507,0x507,0x507,0x507,0x507,0x50a,
+0x522,0x51c,0x522,0x51c,0x51f,0x525,0x522,0x51c,0x51f,0x525,0x522,0x51c,0x51f,0x525,0x522,0x51c,
+0x1182,0x1182,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,
+0x96,0x96,0x96,0x522,0x51c,0x51f,0x525,0x522,0x51c,0x522,0x51c,0x522,0x51c,0x522,0x522,0x51c,
+0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,
+0x51f,0x51c,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51c,0x51f,0x51c,0x51c,0x51f,0x51f,0x51c,0x51c,
+0x51c,0x51c,0x51c,0x51f,0x51c,0x51c,0x51f,0x51c,0x51f,0x51f,0x51f,0x51c,0x51f,0x51f,0x51f,0x51f,
+0x96,0x96,0x51f,0x51f,0x51f,0x51f,0x51c,0x51c,0x51f,0x51c,0x51c,0x51c,0x51c,0x51f,0x51c,0x51c,
+0x51c,0x51c,0x51c,0x51f,0x51f,0x51f,0x51c,0x51c,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,
+0xa08,0xa08,0xa08,0xa08,0xa08,0xa08,0xa08,0xa08,0xa08,0xa08,0xa08,0xa08,0xa08,0xa08,0xa08,0xa08,
+0x522,0x522,0x828,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x519,0x519,0xab6,0xc2a,0x96,0x96,
+0x528,0x528,0x528,0x528,0xe85,0xe85,0xe85,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
+0x76b,0x771,0x771,0x77d,0x77d,0x76e,0x765,0x76e,0x765,0x76e,0x765,0x76e,0x765,0x76e,0x765,0x76e,
+0x765,0x777,0x774,0x777,0x774,0xb3d,0xb3d,0xc27,0xc24,0x768,0x768,0x768,0x768,0x77a,0x77a,0x77a,
+0x792,0x795,0x7a4,0x9c,0x798,0x79b,0x7a7,0x7a7,0x78f,0x786,0x780,0x786,0x780,0x786,0x780,0x783,
+0x783,0x79e,0x79e,0x7a1,0x79e,0x79e,0x79e,0x9c,0x79e,0x78c,0x789,0x783,0x9c,0x9c,0x9c,0x9c,
+0x52e,0x53a,0x52e,0xab9,0x52e,0x9f,0x52e,0x53a,0x52e,0x53a,0x52e,0x53a,0x52e,0x53a,0x52e,0x53a,
+0x53a,0x537,0x531,0x534,0x53a,0x537,0x531,0x534,0x53a,0x537,0x531,0x534,0x53a,0x537,0x531,0x537,
+0x531,0x537,0x531,0x534,0x53a,0x537,0x531,0x537,0x531,0x537,0x531,0x537,0x531,0x9f,0x9f,0x52b,
+0x66c,0x66f,0x684,0x687,0x666,0x66f,0x66f,0xa5,0x64e,0x651,0x651,0x651,0x651,0x64e,0x64e,0xa5,
+0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0x9c6,0x9c6,0x9c6,0x88e,0x648,0x53d,0x53d,
+0xa5,0x696,0x675,0x666,0x66f,0x66c,0x666,0x678,0x669,0x663,0x666,0x684,0x67b,0x672,0x693,0x666,
+0x690,0x690,0x690,0x690,0x690,0x690,0x690,0x690,0x690,0x690,0x681,0x67e,0x684,0x684,0x684,0x696,
+0x657,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,
+0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0x654,0xa5,
+0xa5,0xa5,0x654,0x654,0x654,0x654,0x654,0x654,0xa5,0xa5,0x654,0x654,0x654,0x654,0x654,0x654,
+0xa5,0xa5,0x654,0x654,0x654,0x654,0x654,0x654,0xa5,0xa5,0x654,0x654,0x654,0xa5,0xa5,0xa5,
+0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,
+0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa0e,0xa8,
+0xa0b,0xa0b,0xa0b,0xa0b,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,
+0xa11,0xa11,0xa11,0xa11,0xa11,0xa11,0xa11,0xa11,0xa11,0xa11,0xa11,0xa11,0xa11,0xa11,0xa11,0xa11,
+0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,
+0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,
+0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xb1,0xb1,0xe88,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,
+0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,
+0xa29,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,
+0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3b,0xa3b,
+0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xb4,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,
+0xa3e,0xa3e,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,
+0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3e,0xb4,0xa3e,0xa3e,
+0xb4,0xb4,0xa3e,0xb4,0xb4,0xa3e,0xa3e,0xb4,0xb4,0xa3e,0xa3e,0xa3e,0xa3e,0xb4,0xa3e,0xa3e,
+0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3b,0xa3b,0xa3b,0xa3b,0xb4,0xa3b,0xb4,0xa3b,0xa3b,0xa3b,
+0xa3b,0xbac,0xa3b,0xa3b,0xb4,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,
+0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,
+0xa3b,0xa3b,0xa3b,0xa3b,0xa3e,0xa3e,0xb4,0xa3e,0xa3e,0xa3e,0xa3e,0xb4,0xb4,0xa3e,0xa3e,0xa3e,
+0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xb4,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xb4,0xa3b,0xa3b,
+0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,
+0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3e,0xa3e,0xb4,0xa3e,0xa3e,0xa3e,0xa3e,0xb4,
+0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xb4,0xa3e,0xb4,0xb4,0xb4,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,
+0xa3e,0xb4,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,
+0xc8a,0xc8a,0xb4,0xb4,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,
+0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3b,0xa3b,0xa3b,0xa35,
+0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xd95,0xd92,0xb4,0xb4,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,
+0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xb7,0xa41,0xb7,0xb7,
+0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,
+0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xac8,0xac8,0xac8,0xac8,
+0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xbd,0xac8,0xac8,0xac8,0xac8,0xac2,0xac2,
+0xac5,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xad1,0xad1,0xad1,0xad1,
+0xad1,0xad1,0xad1,0xad1,0xad1,0xad1,0xad1,0xad1,0xad1,0xad1,0xad1,0xad1,0xad1,0xad1,0xacb,0xacb,
+0xace,0xb31,0xb31,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xad7,0xad7,0xad7,0xad7,
+0xad7,0xad7,0xad7,0xad7,0xad7,0xad7,0xad7,0xad7,0xad7,0xad7,0xad7,0xad7,0xad7,0xad7,0xad4,0xad4,
+0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xadd,0xadd,0xadd,0xadd,
+0xadd,0xadd,0xadd,0xadd,0xadd,0xadd,0xadd,0xadd,0xadd,0xc6,0xadd,0xadd,0xadd,0xc6,0xada,0xada,
+0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc8d,0xc8d,0xc8d,0xc8d,
+0xc8d,0xc93,0xc90,0xd9e,0xd9e,0xd9e,0xd9e,0xc9,0xe91,0xc9,0x118b,0x118b,0xae0,0xae0,0xae0,0xae0,
+0xae0,0xae0,0xae0,0xae0,0xae0,0xae0,0xae0,0xae0,0xae0,0xae0,0xae0,0xae0,0xbbe,0xbbe,0xbbe,0xbbe,
+0xbbe,0xbbe,0xbbe,0xbbe,0xbbe,0xbbe,0xbbe,0xbbe,0xbbe,0xbbe,0xbbe,0xbbe,0xbbe,0xbbe,0xbbe,0xbbe,
+0xbbe,0xbbe,0xbbe,0xbbe,0xbbe,0xbbe,0xbbe,0xbbe,0xbbe,0xcc,0xcc,0xcc,0xbaf,0xbaf,0xbaf,0xbbb,
+0xbbb,0xbbb,0xbbb,0xbaf,0xbaf,0xbbb,0xbbb,0xbbb,0xcc,0xcc,0xcc,0xcc,0xbbb,0xbbb,0xbaf,0xbbb,
+0xbbb,0xbbb,0xbbb,0xbbb,0xbbb,0xbb2,0xbb2,0xbb2,0xcc,0xcc,0xcc,0xcc,0xbb5,0xcc,0xcc,0xcc,
+0xbc1,0xbc1,0xbb8,0xbb8,0xbb8,0xbb8,0xbb8,0xbb8,0xbb8,0xbb8,0xbb8,0xbb8,0xbc4,0xbc4,0xbc4,0xbc4,
+0xbc4,0xbc4,0xbc4,0xbc4,0xbc4,0xbc4,0xbc4,0xbc4,0xbc4,0xbc4,0xbc4,0xbc4,0xbc4,0xbc4,0xcf,0xcf,
+0xbc4,0xbc4,0xbc4,0xbc4,0xbc4,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,
+0xe9d,0xe9d,0xe9d,0xe9d,0xe9d,0xe9a,0xe9a,0xe9d,0xe9d,0xe9d,0xe9d,0xe9d,0xe9d,0xd2,0xd2,0xd2,
+0xe9a,0xe9a,0xe9a,0xe9a,0xe9a,0x111c,0x111c,0x111c,0x111c,0x111c,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,
+0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,
+0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xbe8,0xbe8,0xbe8,0xbe8,
+0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xd5,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,
+0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xd5,
+0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,
+0xbe8,0xbe8,0xbe8,0xd5,0xbe8,0xbe8,0xd5,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,
+0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xd5,0xd5,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,
+0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xbe8,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,
+0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,
+0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,
+0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,
+0xbeb,0xbeb,0xbeb,0xd8,0xd8,0xd8,0xd8,0xd8,0xbf1,0xbf1,0xbf1,0xdb,0xdb,0xdb,0xdb,0xbee,
+0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,
+0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xdb,0xdb,0xdb,0xbee,0xbee,0xbee,0xbee,0xbee,
+0xbee,0xbee,0xbee,0xbee,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,
+0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,
+0xbf7,0xbf7,0xde,0xbf4,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,
+0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,
+0xc00,0xc00,0xe1,0xe1,0xc03,0xc03,0xc03,0xc03,0xc03,0xc03,0xe4,0xe4,0xc03,0xe4,0xc03,0xc03,
+0xc03,0xc03,0xc03,0xc03,0xc03,0xc03,0xc03,0xc03,0xc03,0xc03,0xc03,0xc03,0xc03,0xc03,0xc03,0xc03,
+0xc03,0xc03,0xc03,0xc03,0xc03,0xc03,0xe4,0xc03,0xc03,0xe4,0xe4,0xe4,0xc03,0xe4,0xe4,0xc03,
+0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,
+0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,
+0xca5,0xca5,0xca5,0xca5,0xca5,0xca5,0xca5,0xca5,0xca5,0xca5,0xca5,0xed,0xed,0xed,0xed,0xed,
+0xf87,0xf87,0xf87,0xf87,0xf87,0xf87,0xf87,0xf87,0xf87,0xf87,0xf87,0xf87,0x14a,0x14a,0x14a,0x14a,
+0xcb7,0xcb7,0xcb7,0xcb7,0xcb7,0xcb7,0xcb7,0xcb7,0xcb7,0xcb7,0xcb7,0xcb7,0xcb7,0xcb7,0xcb7,0xcb7,
+0xcb7,0xcb7,0xcb7,0xcb7,0xcb7,0xcb7,0xcb7,0xcae,0xcae,0xcb4,0xcb4,0xcb4,0xf0,0xf0,0xcb1,0xcb1,
+0xfae,0xfae,0xfae,0xfae,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,
+0xb2e,0xb2e,0xb2e,0xb2e,0xb2e,0xb2e,0xb2e,0xb2e,0xb2e,0xb2e,0xb2e,0xb2e,0xb2e,0xb2e,0xb2e,0xb2e,
+0xea3,0xea3,0xea3,0xea3,0xea3,0xea3,0xea3,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,
+0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0x118e,0xfe4,0xda4,0xda4,
+0xcc9,0xcc6,0xcc9,0xcc6,0xcc6,0xcbd,0xcbd,0xcbd,0xcbd,0xcbd,0xcbd,0xfed,0xfea,0xfed,0xfea,0xfe7,
+0xfe7,0xfe7,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xcc3,0xcc0,0xcc0,0xcc0,0xcbd,0xcc3,0xcc0,
+0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,
+0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,
+0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xfc,0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xfc,
+0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xfc,0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xccc,0xfc,
+0xcd2,0xcd2,0xcd2,0xcd2,0xcd2,0xcd2,0xcd2,0xcd2,0xcd2,0xcd2,0xcd2,0xcd2,0xcd2,0xcd2,0xcd2,0xcd2,
+0xccf,0xccf,0xccf,0xccf,0xccf,0xccf,0xccf,0xccf,0xccf,0xccf,0xff,0xff,0xff,0xff,0xff,0xff,
+0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0x102,0x102,0x102,0x102,0x102,0x102,0x102,0x102,0x102,0x102,
+0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,
+0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0x105,
+0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,
+0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0xcd8,0x105,
+0xced,0xce1,0xce1,0xce1,0x108,0xce1,0xce1,0x108,0x108,0x108,0x108,0x108,0xce1,0xce1,0xce1,0xce1,
+0xced,0xced,0xced,0xced,0x108,0xced,0xced,0xced,0x108,0xced,0xced,0xced,0xced,0xced,0xced,0xced,
+0xced,0xced,0xced,0xced,0xced,0xced,0xced,0xced,0xced,0xced,0xced,0xced,0xced,0xced,0xced,0xced,
+0x108,0x108,0x108,0x108,0xcde,0xcde,0xcde,0x108,0x108,0x108,0x108,0xce4,0xce7,0xce7,0xce7,0xce7,
+0xce7,0xce7,0xce7,0xce7,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0xcea,0xcea,0xcea,0xcea,
+0xcea,0xcea,0xcf0,0xcf0,0xce7,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0xcff,0xcff,0xcff,0xcff,
+0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xff3,0xff3,0x10b,0x10b,0x10b,0x10b,0xcfc,0xcfc,0xcfc,0xcfc,
+0xcfc,0xcfc,0xcfc,0xcfc,0xcfc,0xcfc,0xcfc,0xcfc,0xcfc,0xcfc,0xcfc,0xcfc,0xcfc,0xcff,0xcff,0xcff,
+0xcff,0xcff,0xcff,0xcff,0xcfc,0xcfc,0x10b,0x10b,0x10b,0x10b,0x10b,0x10b,0xcf9,0xcf9,0xcf9,0xcf9,
+0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xff0,0x10b,0x10b,0x10b,0xcf6,0xcf6,0xd05,0xd05,0xd05,0xd05,
+0x10e,0x10e,0x10e,0x10e,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd02,0xd05,0xd05,0xd05,
+0xd05,0xd05,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0x10e,0xebb,0xebb,0xeb8,0xeb2,
+0xeb8,0xeb2,0xeb8,0xeb2,0xeb8,0xeb2,0xeaf,0xeaf,0xeaf,0xeaf,0xec4,0xec1,0xeaf,0xff6,0x111,0x111,
+0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,
+0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,
+0xd2c,0xd2c,0xd2c,0xd29,0xd29,0xd20,0xd20,0xd29,0xd26,0xd26,0xd26,0xd26,0x114,0x114,0x114,0x114,
+0x1056,0x1056,0x1056,0x1056,0x1056,0x1056,0x1056,0x1056,0x1059,0x1056,0x16e,0x16e,0x16e,0x16e,0x16e,0x16e,
+0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0x117,0x117,0x117,0x117,0x117,0x117,0x117,0x117,0x117,0xd32,
+0x1194,0x117,0x117,0x117,0x117,0x117,0x117,0x117,0x117,0x117,0x117,0x117,0x117,0x117,0x117,0x1191,
+0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,
+0xd59,0xd4a,0xd44,0xd56,0xd53,0xd4d,0xd4d,0xd5c,0xd47,0xd50,0x11a,0x11a,0x11a,0x11a,0x11a,0x11a,
+0xdd7,0xdd7,0xdc2,0xdd7,0xdda,0xddd,0xddd,0xddd,0xddd,0xddd,0xddd,0xddd,0x120,0x120,0x120,0x120,
+0xdd1,0xdd1,0xdd1,0xdd1,0xdd1,0xdd1,0xdd1,0xdd1,0xdd1,0xdd1,0xde3,0xde3,0xdc8,0xdce,0xde3,0xde3,
+0xdcb,0xdc8,0xdc8,0xdc8,0xdc8,0xdc8,0xdc8,0xdc8,0xdc8,0xdc8,0xdc8,0xdc5,0xdc5,0xdc5,0xdc5,0xdc5,
+0xdc5,0xdc5,0xdc5,0xdc5,0xdc8,0xdc8,0xdc8,0xdc8,0xdc8,0xdc8,0xdc8,0xdc8,0xdc8,0x120,0x120,0x120,
+0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xed6,0xed3,0xed3,0xee2,0xed9,0x119a,0x1197,0x123,
+0x119a,0x1197,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,
+0x119a,0x1197,0x119a,0x1197,0x119a,0x1197,0x119a,0x1197,0x119a,0x1197,0x123,0x123,0x123,0x123,0x123,0x123,
+0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,
+0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x1197,0xedf,
+0xedf,0xedf,0xedf,0xedf,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,
+0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdef,0xdef,0xdf5,0xdf5,0x126,0x126,0x126,0x126,
+0x126,0x126,0x126,0x126,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,
+0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdfe,0xdf8,0xdf8,0xdf8,0xdf8,0xffc,0xffc,
+0x129,0x129,0x129,0xdfb,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,
+0xe01,0xe01,0xe01,0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,
+0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,0x12c,
+0x12c,0x12c,0x12c,0x12c,0xe07,0xe07,0xe07,0x12f,0x12f,0x12f,0x12f,0x12f,0x12f,0x12f,0x12f,0x12f,
+0x12f,0x12f,0x12f,0x12f,0xe04,0xe04,0xe04,0xe04,0x12f,0x12f,0x12f,0x12f,0x12f,0x12f,0x12f,0x12f,
+0x12f,0x12f,0x12f,0x12f,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,
+0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0x132,0x132,0x132,0x132,0x132,0x132,0x132,0x132,0x132,0x132,
+0x132,0x132,0x132,0x132,0xef1,0xeeb,0xee5,0xee5,0xee5,0xee5,0xeeb,0xeeb,0xee5,0xee5,0xeee,0x135,
+0x135,0x135,0xef1,0xef1,0xee8,0xee8,0xee8,0xee8,0xee8,0xee8,0xee8,0xee8,0xee8,0xee8,0x135,0x135,
+0x135,0x135,0x135,0x135,0xf06,0xf06,0xf06,0xf06,0xf03,0xf03,0xf03,0xf03,0xf03,0xf03,0xf03,0xf03,
+0xef4,0xef4,0xef4,0xef4,0xef4,0xef4,0xef4,0xef4,0xf03,0xf03,0xefa,0xef7,0x138,0x138,0x138,0xf09,
+0xf09,0xefd,0xefd,0xefd,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0x138,0x138,
+0x138,0xf06,0xf06,0xf06,0xf0c,0xf0c,0xf0c,0xf0c,0xf0c,0xf0c,0xf0c,0xf0c,0xf0c,0xf0c,0xf0f,0xf0f,
+0xf0f,0xf0f,0xf0f,0xf0f,0xf21,0xf21,0xf21,0xf21,0xf21,0xf21,0xf21,0xf21,0xf21,0xf21,0xf24,0xf24,
+0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,
+0x13b,0x13b,0x13b,0x13b,0x11a0,0x119d,0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,
+0xf3f,0xf39,0xf3c,0xf33,0xf30,0xf30,0xf30,0xf36,0x13e,0x13e,0x13e,0x13e,0x13e,0x13e,0x13e,0x13e,
+0xf33,0xf33,0xf36,0xf42,0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,
+0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,0x13e,0x13e,0x13e,0x13e,
+0x13e,0x13e,0x13e,0x13e,0xf4b,0xf4b,0xf4b,0xf4b,0xf45,0x141,0x141,0x141,0x141,0x141,0x141,0x141,
+0x141,0x141,0xf51,0xf51,0xf48,0xf48,0xf48,0xf48,0xf48,0xf48,0xf48,0xf48,0xf48,0xf48,0x141,0x141,
+0x141,0x141,0x141,0x141,0xf72,0xf72,0xf72,0xf72,0xf72,0xf72,0xf72,0xf66,0xf66,0xf66,0xf66,0xf66,
+0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf6c,0xf6f,0x144,0x144,0x144,0x144,0x144,0x144,0x144,0x144,
+0x144,0x144,0x144,0xf69,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf75,0xf75,0xf75,
+0xf75,0xf75,0xf75,0xf7e,0xf7e,0xf75,0xf75,0xf7e,0xf7e,0xf75,0xf75,0x147,0x147,0x147,0x147,0x147,
+0x147,0x147,0x147,0x147,0xf81,0xf81,0xf81,0xf75,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,
+0xf75,0xf7e,0x147,0x147,0xf7b,0xf7b,0xf7b,0xf7b,0xf7b,0xf7b,0xf7b,0xf7b,0xf7b,0xf7b,0x147,0x147,
+0xf78,0xf84,0xf84,0xf84,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,
+0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,
+0x14a,0x14a,0x14a,0x14a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,
+0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,0xf8a,
+0xf8a,0xf8d,0x14d,0x14d,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,
+0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,0xf90,
+0xf90,0x150,0x150,0x150,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,
+0xf93,0xf93,0xf93,0xf93,0xf93,0x153,0x153,0x153,0x153,0x153,0x153,0x153,0x153,0x153,0x153,0x153,
+0x153,0x153,0x153,0x153,0xf99,0xf99,0xf99,0xf99,0xf99,0xf99,0xf99,0xf99,0xf99,0xf99,0xf99,0xf99,
+0xf99,0xf99,0xf99,0xf99,0xf99,0xf99,0xf99,0xf99,0xf99,0xf99,0xf99,0xf99,0xf99,0xf99,0x156,0x156,
+0x156,0x156,0x156,0xf96,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,
+0x159,0x159,0x159,0x159,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,
+0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0x15c,0x15c,0x15c,0x15c,0x15c,0x15c,0x15c,0x15c,
+0x15c,0x15c,0x15c,0x15c,0x1002,0x1002,0x1002,0x1002,0x100b,0x1002,0x1002,0x1002,0x100b,0x1002,0x1002,0x1002,
+0x1002,0xfff,0x15f,0x15f,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,0x1008,
+0x1008,0x1008,0x1008,0x15f,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,
+0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x162,0x162,0x162,0x162,0x162,0x162,
+0x162,0x162,0x162,0x162,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,
+0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1023,0x1011,0x1023,0x1011,0x1011,0x1011,0x1011,
+0x1011,0x1011,0x1011,0x165,0x101a,0x1023,0x1011,0x1023,0x1023,0x1011,0x1011,0x1011,0x1011,0x1011,0x1011,0x1011,
+0x1011,0x1023,0x1023,0x1023,0x1023,0x1023,0x1023,0x1011,0x1011,0x1017,0x1017,0x1017,0x1017,0x1017,0x1017,0x1017,
+0x1017,0x165,0x165,0x1014,0x1020,0x1020,0x1020,0x1020,0x1020,0x1020,0x1020,0x1020,0x1020,0x1020,0x165,0x165,
+0x165,0x165,0x165,0x165,0x1020,0x1020,0x1020,0x1020,0x1020,0x1020,0x1020,0x1020,0x1020,0x1020,0x165,0x165,
+0x165,0x165,0x165,0x165,0x103b,0x1035,0x103b,0x103b,0x103b,0x103b,0x103b,0x103b,0x103b,0x1038,0x1038,0x1038,
+0x1038,0x103b,0x1038,0x1038,0x1038,0x1038,0x1032,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168,
+0x168,0x168,0x168,0x168,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,
+0x1050,0x1050,0x1050,0x1050,0x1047,0x1047,0x104a,0x1053,0x104d,0x104d,0x104d,0x1053,0x16b,0x16b,0x16b,0x16b,
+0x16b,0x16b,0x16b,0x16b,0x105c,0x105c,0x105c,0x105c,0x105c,0x105c,0x105c,0x105c,0x105c,0x105c,0x105c,0x105c,
+0x105c,0x105c,0x105c,0x105c,0x105c,0x105c,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x105f,0x105f,0x105f,0x1062,
+0x171,0x171,0x171,0x171,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,
+0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,
+0x113d,0x174,0x174,0x174,0x1077,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106e,0x1080,0x1080,0x106b,0x106b,
+0x106b,0x106b,0x177,0x107d,0x1071,0x1071,0x1071,0x1071,0x1071,0x1071,0x1071,0x1071,0x1071,0x1071,0x177,0x177,
+0x177,0x177,0x106b,0x106b,0x1089,0x1089,0x1089,0x1089,0x1089,0x1089,0x1089,0x1089,0x1089,0x1089,0x1089,0x1089,
+0x1089,0x1089,0x1089,0x1089,0x108c,0x1089,0x1089,0x1089,0x1089,0x1089,0x1089,0x1083,0x1083,0x1083,0x1089,0x1086,
+0x17a,0x17a,0x17a,0x17a,0x109e,0x1092,0x109e,0x17d,0x17d,0x17d,0x17d,0x17d,0x17d,0x17d,0x17d,0x17d,
+0x17d,0x17d,0x17d,0x17d,0x17d,0x17d,0x17d,0x17d,0x17d,0x17d,0x17d,0x17d,0x17d,0x17d,0x17d,0x109b,
+0x109b,0x10a1,0x1095,0x1098,0x10b6,0x10b6,0x10b6,0x10b0,0x10b0,0x10a7,0x10b0,0x10b0,0x10a7,0x10b0,0x10b0,0x10b9,
+0x10b3,0x10aa,0x180,0x180,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x10ad,0x180,0x180,
+0x180,0x180,0x180,0x180,0x1143,0x1143,0x1143,0x1143,0x1143,0x1143,0x1143,0x183,0x183,0x183,0x183,0x1140,
+0x1140,0x1140,0x1140,0x1140,0x1140,0x1140,0x1140,0x1140,0x1140,0x1140,0x1140,0x1140,0x1140,0x1140,0x1140,0x1140,
+0x1140,0x1140,0x1140,0x1140,0x1140,0x1140,0x1140,0x1140,0x1140,0x1140,0x1140,0x1140,0x183,0x183,0x183,0x183,
+0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,
+0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x10c2,0x186,0x10bf,0x10bc,0x10bc,0x10bc,0x10bc,0x10bc,0x10bc,0x10bc,0x10bc,
+0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,
+0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x189,0x189,0x189,0x10cb,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,
+0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,
+0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x18c,0x18c,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,
+0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,
+0x10dd,0x10dd,0x10dd,0x18f,0x18f,0x18f,0x18f,0x18f,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,
+0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,
+0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x195,
+0x1122,0x1122,0x1122,0x1122,0x1122,0x1122,0x1122,0x1122,0x1122,0x1122,0x1122,0x19e,0x19e,0x19e,0x19e,0x19e,
+0x1122,0x1122,0x1122,0x1122,0x1122,0x1122,0x1122,0x1122,0x1122,0x1122,0x1122,0x1122,0x1122,0x1122,0x1122,0x1122,
+0x1122,0x1122,0x1122,0x1125,0x1125,0x1125,0x110d,0x19e,0x11f1,0x1128,0x11f1,0x11f1,0x11f1,0x11f1,0x11f1,0x11f1,
+0x11f1,0x11f1,0x11f1,0x11f1,0x11f1,0x1128,0x11f1,0x1128,0x11ee,0x11ee,0x11ee,0x11ee,0x11ee,0x11ee,0x11ee,0x11ee,
+0x11ee,0x11ee,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x11ee,0x11ee,0x11ee,0x11ee,0x11ee,0x11ee,0x11ee,0x11ee,
+0x11ee,0x111f,0x11ee,0x111f,0x111f,0x11ee,0x11ee,0x111f,0x11ee,0x11ee,0x11ee,0x11ee,0x11ee,0x11ee,0x11ee,0x11ee,
+0x11ee,0x11ee,0x111f,0x111f,0x111f,0x111f,0x11ee,0x11ee,0x1128,0x11ee,0x11ee,0x11ee,0x11ee,0x11ee,0x11ee,0x11ee,
+0x11ee,0x11ee,0x11ee,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,
+0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,
+0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x11a3,0x11a3,0x11a3,0x11a3,0x11a3,0x11a3,0x11a3,0x11a3,0x11a3,0x11a3,
+0x11a3,0x11a3,0x11a3,0x11a3,0x11a3,0x11a3,0x11a3,0x11a3,0x11a3,0x11a3,0x11a3,0x11a3,0x11a3,0x11a3,0x11a3,0x11a3,
+0x114c,0x11fa,0x11fa,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,
+0x1149,0x1149,0x1149,0x1149,0x1149,0x1149,0x1149,0x1149,0x1149,0x1149,0x1149,0x1149,0x1149,0x1149,0x1149,0x1149,
+0x1149,0x1149,0x11fa,0x11fa,0x11fa,0x11fa,0x11fa,0x11fa,0x11fa,0x11fa,0x11fa,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,
+0x1146,0x1146,0x1146,0x1146,0x1146,0x1146,0x1146,0x1146,0x1146,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,
+0x11f7,0x11f7,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,
+0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,
+0x1a1,0x1a1,0x1a1,0x1a1,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,
+0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11ac,0x11a6,0x11a6,0x11a6,
+0x1a4,0x1a4,0x11a9,0x1a4,0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,0x11af,0x11b8,0x11b2,0x11b2,0x11b8,0x11b8,
+0x11b8,0x11b2,0x11b8,0x11b2,0x11b2,0x11b2,0x11bb,0x11bb,0x1a7,0x1a7,0x1a7,0x1a7,0x1a7,0x1a7,0x1a7,0x1a7,
+0x11b5,0x11b5,0x11b5,0x11b5,0x1aa,0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x1aa,0x1aa,0x11c1,0x11c1,0x11c1,
+0x11c1,0x11c1,0x11c1,0x1aa,0x1aa,0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x11c1,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa,
+0x1aa,0x1aa,0x1aa,0x1aa,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c7,0x11d9,0x11d9,0x11cd,0x11cd,0x11cd,
+0x11cd,0x11cd,0x1ad,0x1ad,0x1ad,0x1ad,0x11ca,0x11ca,0x11ca,0x11ca,0x11ca,0x11ca,0x11ca,0x11ca,0x11ca,0x11ca,
+0x11ca,0x11ca,0x11ca,0x11ca,0x11ca,0x11ca,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,
+0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,
+0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,
+0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,
+0x1200,0x11fd,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,
+0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,
+0x1b3,0x1b3,0x1b3,0x1b3,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,
+0x11df,0x11df,0x11df,0x1b6,0x1b6,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,
+0x11df,0x11df,0x11df,0x1b6,0x1b6,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,
+0x11df,0x11df,0x11df,0x11df,0x1b6,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,0x11df,
+0x11df,0x11df,0x11df,0x11df,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,
+0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,
+0x1b6,0x1b6,0x1b6,0x1b6,0x11e2,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,
+0x1b9,0x1b9,0x1b9,0x1b9,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x1b9,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,
+0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,
+0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x1b9,0x1b9,0x1b9,0x11e2,0x11e2,0x11e2,0x11e2,
+0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,
+0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x11e2,0x11e2,0x11e2,0x11e2,
+0x11e2,0x1b9,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,
+0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x11e2,0x11e2,0x11e2,0x11e2,
+0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x1b9,0x1b9,0x1b9,
+0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x11e2,0x11e2,0x11e2,0x11e2,
+0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,
+0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x1b9,0x11e2,0x1b9,0x11e2,0x11e2,
+0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,
+0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x1b9,0x11e2,0x11e2,0x11e2,
+0x11e2,0x1b9,0x1b9,0x1b9,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,
+0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,
+0x11e2,0x11e2,0x1b9,0x1b9,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x1b9,0x1b9,0x1b9,0x1b9,
+0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,
+0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,0x11e2,
+0x11e2,0x11e2,0x11e2,0x11e2,0x1bc,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,
+0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x1bc,0x11e5,0x11e5,0x11e5,0x1bc,0x11e5,0x1bc,0x11e5,0x1bc,0x11e5,0x1bc,
+0x11e5,0x11e5,0x11e5,0x1bc,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x1bc,0x1bc,0x11e5,0x11e5,0x11e5,0x11e5,
+0x1bc,0x11e5,0x1bc,0x1bc,0x11e5,0x11e5,0x11e5,0x11e5,0x1bc,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,
+0x11e5,0x11e5,0x11e5,0x11e5,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,
+0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,
+0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x11eb,0x11eb,0x11eb,0x11eb,
+0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,
+0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c5,0x1c5,0x1c5,0x1c5,
+0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,
+0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x82b,0x82b,
+0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,
+0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,
+0xfab,0xfab,0xfab,0xfab,0x1137,0x1137,0x1137,0x1137,0x1137,0x1137,0x1137,0x1137,0x1cb,0x1cb,0x1cb,0x1cb,
+0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,
+0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x75f,0x762,0x75f,0x762,
+0x762,0x75f,0x75f,0x762,0x762,0x762,0x75f,0x75f,0x75f,0x75f,0x1ce,0x1ce,0xb2b,0xb2b,0xb2b,0xb2b,
+0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0x113a,
+0x113a,0x113a,0x1ce,0x1ce,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,
+0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0x1ce,0x1ce,
+0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,
+0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,
+0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,
+0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,
+0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,
+0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0x1d4,0x1d4,
+0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,
+0x114f,0x114f,0x114f,0x114f,0x114f,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,
+0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,
+0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1da,0x1da,
+0x2eb,0x2df,0x2df,0x2df,0x2df,0x2df,0x2df,0x2df,0x2df,0x2eb,0x2eb,0x2eb,0x2eb,0x2e5,0xfb4,0x115b,
+0x2ee,0x2dc,0x2dc,0x2e2,0x2e2,0xfb1,0x1158,0x1158,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,
+0xfb1,0x2df,0x2df,0x2eb,0xb6a,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,
+0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,
+0x2ee,0x2f1,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2ee,0x2f1,0x2ee,0x2ee,0x2f1,0x2ee,0x2ee,0x2ee,
+0x2ee,0x2ee,0x1158,0x115b,0x2e2,0x2ee,0x2eb,0x2eb,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,
+0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,
+0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3e7,0x3ed,0x3ed,0x3ed,0x1131,0x1131,0x1131,0x1131,0x1131,
+0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,
+0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,
+0x3ea,0x3ea,0x112e,0x112e,0x112e,0x112e,0x112e,0x112e,0x3f0,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,
+0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,
+0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3f9,0x3f3,0x3f9,0x3f3,
+0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,
+0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,0x3f3,0x3f3,
+0x3f3,0x3f3,0x3f6,0x86d,0xe70,0xe70,0xe73,0xe70,0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,
+0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,0x3f9,0x3f3,
+0x3f9,0x3f3,0xe73,0xe70,0xe73,0xe70,0xe73,0xe70,0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x405,
+0x408,0x408,0x408,0x408,0x408,0x408,0x408,0x408,0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x405,
+0x408,0x408,0x408,0x408,0x408,0x408,0x408,0x408,0x5b5,0x5b5,0x5b8,0x423,0x5c4,0x5c1,0x5c1,0x5be,
+0x44d,0x44d,0x40b,0x40b,0x40b,0x40b,0x40b,0x999,0x5c7,0x42f,0x5df,0x5e2,0x444,0x5c7,0x432,0x432,
+0x423,0x43e,0x43e,0x5b5,0x44a,0x447,0x5bb,0x41d,0x414,0x414,0x417,0x417,0x417,0x417,0x417,0x41a,
+0x417,0x417,0x417,0x40e,0x453,0x453,0x450,0x450,0x5d3,0x438,0x435,0x5d0,0x5cd,0x5ca,0x5dc,0x426,
+0x5d9,0x5d9,0x43b,0x43e,0x5d6,0x5d6,0x43b,0x43e,0x420,0x423,0x423,0x423,0x441,0x42c,0x429,0xa77,
+0x99f,0x99f,0x99c,0x99c,0x99c,0x99c,0xa6e,0xa6e,0xa6e,0xa6e,0xa74,0xb97,0xb94,0xc6f,0xc72,0xa71,
+0xc72,0xc72,0xc72,0xc72,0xc6f,0xc72,0xc72,0xa6b,0x486,0x486,0x49e,0x5f4,0x483,0x5ee,0x486,0x49b,
+0x483,0x5f4,0x495,0x49e,0x49e,0x49e,0x495,0x495,0x49e,0x49e,0x49e,0x5fa,0x483,0x49e,0x5f7,0x483,
+0x492,0x49e,0x49e,0x49e,0x49e,0x49e,0x483,0x483,0x489,0x5ee,0x5f1,0x483,0x49e,0x483,0x5fd,0x483,
+0x49e,0x48c,0x4a4,0x600,0x49e,0x49e,0x48f,0x495,0x49e,0x49e,0x4a1,0x49e,0x495,0x498,0x498,0x498,
+0x498,0x9ab,0x9a8,0xb9a,0xc81,0xa92,0xa95,0xa95,0xa8f,0xa8c,0xa8c,0xa8c,0xa8c,0xa95,0xa92,0xa92,
+0xa92,0xa92,0xa89,0xa8c,0xc7e,0xd80,0xd83,0xe7c,0xfd5,0xfd5,0xfd5,0x606,0x603,0x4a7,0x4aa,0x4aa,
+0x4aa,0x4aa,0x4aa,0x603,0x606,0x606,0x603,0x4aa,0x60c,0x60c,0x60c,0x60c,0x60c,0x60c,0x60c,0x60c,
+0x60c,0x60c,0x60c,0x60c,0x4b3,0x4b3,0x4b3,0x4b3,0x609,0x609,0x609,0x609,0x609,0x609,0x609,0x609,
+0x609,0x609,0x4ad,0x4ad,0x4ad,0x4ad,0x4ad,0x4ad,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,
+0x4b6,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4bc,0x4b6,0x4b9,0x4b9,0x4b6,0x4b6,0x4b6,0x4b6,0x4b9,0x4b9,
+0x60f,0x60f,0x4b6,0x4b6,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,
+0x4b9,0x4bc,0x4bc,0x4bc,0x4b9,0x4b9,0x612,0x4b9,0x612,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,
+0x4b6,0x4b9,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b9,0x4b9,0x4b6,0x60f,0x4b6,0x4b6,0x4b6,0x9b1,
+0x9b1,0x9b1,0x9b1,0x9b1,0x9b1,0x9b1,0x9b1,0x9b1,0xa98,0xa98,0xa98,0xa98,0xa98,0xa98,0xa98,0xa98,
+0xa98,0xa98,0xa98,0xa98,0x615,0x4bf,0x615,0x615,0x4c2,0x4bf,0x4bf,0x615,0x615,0x4c2,0x4bf,0x615,
+0x4c2,0x4bf,0x4bf,0x615,0x4bf,0x615,0x4cb,0x4c8,0x4bf,0x615,0x4bf,0x4bf,0x4bf,0x4bf,0x615,0x4bf,
+0x4bf,0x615,0x615,0x615,0x615,0x4bf,0x4bf,0x615,0x4c2,0x615,0x4c2,0x615,0x615,0x615,0x615,0x615,
+0x61b,0x4c5,0x615,0x4c5,0x4c5,0x4bf,0x4bf,0x4bf,0x615,0x615,0x615,0x615,0x4bf,0x4bf,0x4bf,0x4bf,
+0x615,0x615,0x4bf,0x4bf,0x4bf,0x4c2,0x4bf,0x4bf,0x4c2,0x4bf,0x4bf,0x4c2,0x615,0x4c2,0x4bf,0x4bf,
+0x615,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x615,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,
+0x4bf,0x4bf,0x4bf,0x4bf,0x618,0x615,0x4c2,0x4bf,0x615,0x615,0x615,0x615,0x4bf,0x4bf,0x615,0x615,
+0x4bf,0x4c2,0x618,0x618,0x4c2,0x4c2,0x4bf,0x4bf,0x4c2,0x4c2,0x4bf,0x4bf,0x4c2,0x4c2,0x4bf,0x4bf,
+0x4bf,0x4bf,0x4bf,0x4bf,0x4c2,0x4c2,0x615,0x615,0x4c2,0x4c2,0x615,0x615,0x4c2,0x4c2,0x4bf,0x4bf,
+0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x615,0x4bf,0x4bf,0x4bf,0x615,0x4bf,0x4bf,
+0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x615,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4c2,0x4c2,0x4c2,0x4c2,
+0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x615,
+0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,
+0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,
+0x4c2,0x4c2,0x4c2,0x4c2,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4c2,0x4c2,0x4c2,0x4c2,0x4bf,0x4bf,
+0x4bf,0x4bf,0xa9b,0xa9b,0xa9b,0xa9b,0xa9b,0xa9b,0xa9b,0xa9b,0xa9b,0xa9b,0xa9b,0xa9b,0xa9b,0xa9b,
+0x4ce,0x9b4,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4d1,0x4d1,0x4d1,0x4d1,0x4ce,0x4ce,0x4ce,0x4ce,
+0x4ce,0x4ce,0x61e,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,
+0x4d1,0x4d1,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x70e,0x70b,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,
+0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,
+0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x9b4,
+0xaa1,0x9b4,0x9b4,0x9b4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,
+0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,0x4d4,
+0x4d4,0x4d4,0x4d4,0x4d4,0x627,0x627,0x627,0x627,0x627,0x627,0x627,0x627,0x627,0x627,0x4da,0xb01,
+0xb01,0xb01,0xb01,0xb01,0xb01,0xb01,0xb01,0xb01,0xb01,0xb01,0xb01,0xb01,0xb01,0xb01,0xb01,0xb01,
+0xb01,0xb01,0xb01,0xc0f,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,
+0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x4dd,0x4e0,0x4e0,0x4e0,0x4e0,0x4e0,0x4e0,0x4e0,
+0x4e0,0x4e0,0x4e0,0x4e0,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,
+0x4e0,0x4e0,0x4e0,0x4e0,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,
+0x62d,0x62d,0x62d,0x62d,0x630,0x630,0x630,0x630,0x630,0x630,0x630,0x630,0x630,0x630,0x630,0x630,
+0x630,0x630,0x630,0x630,0x4e3,0x4e3,0x630,0x630,0x630,0x630,0xaa4,0xaa4,0xaa4,0xaa4,0xaa4,0xaa4,
+0xaa4,0xaa4,0xaa4,0xaa4,0x636,0x636,0x4e6,0x633,0x633,0x633,0x633,0x633,0x633,0x633,0x4e6,0x4e6,
+0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x636,0x636,0x4e9,0x4e9,0x636,0x636,0x4e6,0x4e6,0x4e6,0x4e6,
+0x636,0x636,0x4e9,0x4e9,0x636,0x636,0x4e6,0x4e6,0x4e6,0x4e6,0x636,0x636,0x633,0x4e6,0x4e9,0x636,
+0x4e6,0x4e6,0x633,0x636,0x636,0x636,0x4e9,0x4e9,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,
+0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x636,0x633,0x636,0x633,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,
+0x4e9,0x4e6,0x4e6,0x633,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0xaa7,0xaa7,0xaa7,0xaa7,
+0xaa7,0xaa7,0xaa7,0xaa7,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x63c,0x63c,0x4ec,0x4ec,0x639,0x4ec,0x4ec,
+0x4ec,0x4ec,0x639,0x639,0x4ec,0x4ec,0x4ec,0x4ec,0xc12,0xc12,0xaaa,0xaaa,0xc87,0x9bd,0x4ec,0x4ec,
+0x639,0x4ec,0x639,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,
+0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,
+0x4ec,0x4ec,0x4ec,0x4ec,0x63c,0x4ec,0x63c,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,
+0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,
+0x4ec,0x4ec,0x4ec,0x4ec,0x63c,0x63c,0x4ef,0x63c,0x639,0x639,0x4ec,0x639,0x639,0x639,0x639,0x4ec,
+0x639,0x63c,0x4ef,0x63c,0x9bd,0x9bd,0xaad,0xaad,0xaad,0xaad,0xaad,0xaad,0xaad,0xaad,0xaad,0xaad,
+0xaad,0xaad,0xc87,0xc87,0x4f2,0x4f2,0x4f2,0x4f2,0x4f2,0x4f2,0x4f2,0x4f2,0x4f2,0x4f2,0x4f2,0x4f2,
+0x4f2,0x4f2,0x4f2,0x4f2,0x4f2,0x4f2,0x4f2,0x4f2,0x4f5,0x117f,0x117f,0x117f,0x4f5,0x4f5,0x4f5,0x4f5,
+0x4f5,0x4f5,0x4f5,0x4f5,0x117f,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,
+0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x642,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,
+0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x117f,0x4f5,0x117f,0x4f5,0x4f5,0x4f5,0x4f5,0x117f,
+0x117f,0x117f,0x4f5,0x1116,0x4f5,0x4f5,0x4f5,0x4fb,0x4fb,0x4fb,0x4fb,0x117f,0x117f,0x4f5,0x4f8,0x4f8,
+0x4f5,0x4f5,0x4f5,0x4f5,0xab3,0xab0,0xab3,0xab0,0xab3,0xab0,0xab3,0xab0,0xab3,0xab0,0xab3,0xab0,
+0xab3,0xab0,0x63f,0x63f,0x63f,0x63f,0x63f,0x63f,0x63f,0x63f,0x63f,0x63f,0x4f5,0x4f5,0x4f5,0x4f5,
+0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x117f,0x4f5,0x4f5,0x4f5,
+0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x4f5,0x117f,0x51c,0x51c,0x51c,0x51c,
+0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,
+0x525,0x525,0x525,0x525,0x525,0x525,0x525,0x525,0x51c,0x522,0x516,0x513,0x522,0x522,0x522,0x522,
+0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,
+0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x519,0x519,0x519,0x519,0x519,0x519,
+0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,
+0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51f,0x525,0x522,0x51c,
+0x51f,0x525,0x522,0x51c,0x51f,0x525,0x522,0x51c,0x51f,0x525,0x522,0x51c,0x51f,0x525,0x522,0x51c,
+0x51f,0x525,0x522,0x51c,0x51f,0x525,0x522,0x51c,0x51f,0x525,0x522,0x51c,0x522,0x51c,0x522,0x51c,
+0x522,0x51c,0x522,0x51c,0x522,0x51c,0x522,0x51c,0x51f,0x525,0x522,0x51c,0x51f,0x525,0x522,0x51c,
+0x51f,0x525,0x522,0x51c,0x51f,0x525,0x522,0x51c,0x522,0x51c,0x51f,0x525,0x522,0x51c,0x522,0x51c,
+0x51f,0x525,0x522,0x51c,0x51f,0x525,0x522,0x51c,0x522,0x51c,0x1182,0x1182,0x1182,0x1182,0x1182,0x1182,
+0x1182,0x1182,0x1182,0x1182,0x1182,0x1182,0x1182,0x1182,0x522,0x51c,0x522,0x51c,0x522,0x51c,0x51f,0x525,
+0x51f,0x525,0x522,0x51c,0x522,0x51c,0x522,0x51c,0x522,0x51c,0x522,0x51c,0x522,0x51c,0x522,0x51c,
+0x51f,0x522,0x51c,0x51f,0x522,0x51c,0x51f,0x525,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,
+0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51f,
+0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,
+0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,
+0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51f,0x51f,0x51c,0x51f,0x51c,0x51f,0x51c,0x51c,
+0x51f,0x51c,0x51c,0x51f,0x51c,0x51f,0x51c,0x51c,0x51f,0x51c,0x51f,0x51f,0x51c,0x51c,0x51c,0x51f,
+0x51c,0x51c,0x51c,0x51c,0x51c,0x51f,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,
+0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51c,0x51f,0x51f,0x51c,0x51c,
+0x51f,0x51c,0x51f,0x51c,0x51c,0x51c,0x51c,0x51c,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,
+0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,
+0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x51f,0x525,0x522,0x522,0x522,0x522,
+0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,
+0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x525,0x525,0x525,0x525,
+0x525,0x525,0x525,0x525,0x525,0x525,0x525,0x525,0x525,0x525,0x525,0x525,0x525,0x525,0x525,0x525,
+0x525,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x522,0x537,0x537,0x531,0x537,
+0x531,0x537,0x531,0x537,0x531,0x537,0x531,0x534,0x53a,0x537,0x531,0x537,0x531,0x534,0x53a,0x537,
+0x531,0x537,0x531,0x534,0x53a,0x537,0x531,0x534,0x53a,0x537,0x531,0x534,0x53a,0x537,0x531,0x537,
+0x531,0x537,0x531,0x537,0x531,0x537,0x531,0x534,0x53a,0x537,0x531,0x534,0x53a,0x537,0x531,0x534,
+0x53a,0x537,0x531,0x534,0x53a,0x537,0x531,0x534,0x53a,0x537,0x531,0x534,0x53a,0x537,0x531,0x534,
+0x53a,0x537,0x531,0x534,0x53a,0x537,0x531,0x534,0x624,0x624,0x624,0x624,0x624,0x624,0x624,0x624,
+0x624,0x624,0x624,0x624,0x624,0x624,0x624,0x624,0x624,0x624,0x624,0x624,0x621,0x621,0x621,0x621,
+0x621,0x621,0x621,0x621,0x621,0x621,0x621,0x621,0x621,0x621,0x621,0x621,0x621,0x621,0x621,0x621,
+0x621,0x621,0x621,0x621,0x621,0x621,0x621,0x621,0x621,0x621,0x621,0x621,0x621,0x621,0x62a,0x62a,
+0x62a,0x62a,0x62a,0x62a,0x62a,0x62a,0x62a,0x62a,0x62a,0x62a,0x62a,0x62a,0x62a,0x62a,0x62a,0x62a,
+0x627,0x627,0x627,0x627,0x627,0x627,0x627,0x627,0x627,0x627,0x627,0x627,0x627,0x627,0x627,0x627,
+0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,
+0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,0x62d,
+0x645,0x645,0x645,0x645,0x645,0x645,0x645,0x645,0x645,0x645,0x645,0x645,0x645,0x645,0x645,0x645,
+0x645,0x645,0x645,0x645,0x645,0x645,0x645,0x645,0x645,0x645,0x645,0x645,0x645,0x645,0x645,0x645,
+0xb07,0x7d4,0x7ce,0x7cb,0x7d1,0x7c8,0x65a,0x65d,0x65d,0x65d,0x65d,0x65d,0x65d,0x65d,0x65d,0x65d,
+0x7c5,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,
+0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,0x65a,
+0x65a,0x65a,0x7c2,0x7c2,0x660,0x7fb,0x7fe,0x7e0,0x711,0x71d,0x7da,0x71a,0x7f2,0x7ef,0x7f2,0x7ef,
+0x7f8,0x7f5,0x7f8,0x7f5,0x7f2,0x7ef,0x717,0x7e0,0x7f2,0x7ef,0x7f2,0x7ef,0x7f2,0x7ef,0x7f2,0x7ef,
+0x7e6,0x7ec,0x7e9,0x7e9,0x666,0x6a2,0x6a2,0x6a2,0x6a2,0x6a2,0x6a2,0x69c,0x69c,0x69c,0x69c,0x69c,
+0x69c,0x69c,0x69c,0x69c,0x69c,0x69c,0x69c,0x69c,0x69c,0x69c,0x69c,0x69c,0x69c,0x69c,0x69c,0x669,
+0x684,0x663,0x68a,0x68d,0x687,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x699,0x699,0x699,0x699,0x699,
+0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x669,
+0x684,0x663,0x684,0xb0a,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,
+0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,
+0x705,0x705,0x705,0x705,0x705,0x705,0x112b,0x112b,0x112b,0x112b,0x112b,0x708,0x717,0x71a,0x71a,0x71a,
+0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x822,0x822,0x822,0x822,0x720,0x720,0x7e3,0x7d7,0x7d7,0x7d7,
+0x7d7,0x7d7,0x714,0x7dd,0x9e1,0x9e1,0x9e1,0xb19,0xb37,0xb34,0x9fc,0x7bf,0x726,0x723,0x726,0x729,
+0x723,0x726,0x723,0x726,0x723,0x726,0x723,0x723,0x723,0x723,0x723,0x723,0x726,0x726,0x723,0x726,
+0x726,0x723,0x726,0x726,0x723,0x726,0x726,0x723,0x726,0x726,0x723,0x723,0xb3a,0x738,0x732,0x738,
+0x732,0x738,0x732,0x738,0x732,0x738,0x732,0x732,0x735,0x732,0x735,0x732,0x735,0x732,0x735,0x732,
+0x735,0x732,0x735,0x732,0x735,0x732,0x735,0x732,0x735,0x732,0x735,0x732,0x735,0x732,0x735,0x738,
+0x732,0x735,0x732,0x735,0x732,0x735,0x732,0x732,0x732,0x732,0x732,0x732,0x735,0x735,0x732,0x735,
+0x735,0x732,0x735,0x735,0x732,0x735,0x735,0x732,0x735,0x735,0x732,0x732,0x732,0x732,0x732,0x738,
+0x732,0x738,0x732,0x738,0x732,0x732,0x732,0x732,0x732,0x732,0x738,0x732,0x732,0x732,0x732,0x732,
+0x735,0x738,0x738,0x735,0x735,0x735,0x735,0x807,0x804,0x73b,0x73e,0xb22,0x744,0x744,0x744,0x744,
+0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,
+0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x747,0x744,0x744,0x744,
+0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,
+0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x744,0x750,0x750,0x750,0x750,0x750,0x750,0x750,0x750,
+0x750,0x750,0x750,0x750,0x750,0x750,0x750,0x750,0x750,0x750,0x750,0x750,0x750,0x750,0x750,0x750,
+0x750,0x750,0x750,0x750,0xc1e,0xc1e,0xd3b,0x74a,0x810,0x810,0x810,0x810,0x810,0x810,0x810,0x810,
+0x810,0x810,0x810,0x810,0xc18,0xc18,0xc18,0xc18,0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,
+0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x753,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,
+0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x756,0x756,0x756,0x756,0x756,0x756,0xc21,
+0xc21,0xc21,0xc21,0x819,0x819,0x819,0x819,0x819,0x756,0x756,0x756,0x756,0x756,0x756,0x756,0x756,
+0x756,0x756,0x756,0x756,0x756,0x756,0x756,0x756,0x756,0x756,0x756,0x756,0x756,0x756,0x756,0x756,
+0x756,0x756,0x756,0x756,0x756,0x756,0x756,0x756,0x756,0x756,0xc21,0xc21,0x759,0x759,0x759,0x759,
+0x759,0x759,0x759,0x759,0x759,0x759,0x759,0x759,0x759,0x759,0x759,0x759,0x759,0x759,0x759,0x759,
+0x759,0x759,0x759,0x759,0x759,0x759,0x759,0x759,0x759,0x759,0x759,0x759,0x816,0x816,0x816,0x816,
+0x816,0x816,0x816,0x816,0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,
+0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,
+0x75c,0x75c,0x75c,0x75c,0x75c,0x75c,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,
+0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xfab,0xfab,0xfab,0xfab,
+0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,
+0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,
+0x75f,0x75f,0x762,0x762,0x75f,0x762,0x75f,0x762,0x762,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,0x75f,
+0x75f,0x75f,0x75f,0x762,0x810,0x810,0x810,0x810,0x810,0x810,0x810,0x810,0x810,0x810,0x810,0x810,
+0x810,0x810,0x810,0x810,0x810,0x810,0x810,0x810,0x810,0x810,0x810,0x810,0x810,0x810,0x810,0x810,
+0x810,0x810,0x810,0x810,0x1134,0x1134,0x1134,0x1134,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,
+0xc18,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,
+0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,
+0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,
+0x813,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,0xb25,
+0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,
+0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0x816,0xc21,
+0x867,0x849,0x849,0x849,0x849,0x843,0x849,0x849,0x85b,0x849,0x849,0x846,0x852,0x858,0x858,0x858,
+0x858,0x858,0x85b,0x843,0x84f,0x843,0x843,0x843,0x83a,0x83a,0x843,0x843,0x843,0x843,0x843,0x843,
+0x85e,0x85e,0x85e,0x85e,0x85e,0x85e,0x85e,0x85e,0x85e,0x85e,0x843,0x843,0x843,0x843,0x843,0x843,
+0x843,0x843,0x843,0x843,0x846,0x83a,0x843,0x83a,0x843,0x83a,0x855,0x84c,0x855,0x84c,0x864,0x864,
+0x873,0x873,0x873,0x873,0x873,0x873,0x873,0x873,0x873,0x873,0x873,0x873,0x873,0x873,0x873,0x873,
+0x873,0x873,0x873,0x873,0x873,0x873,0x873,0x873,0x873,0x873,0x873,0x873,0x873,0x873,0x873,0x873,
+0x876,0x876,0x876,0x876,0x876,0x876,0x876,0x876,0x876,0x876,0x876,0x876,0x876,0x876,0x876,0x876,
+0x876,0x876,0x876,0x876,0x876,0x876,0x876,0x876,0x876,0x876,0x876,0x876,0x876,0x876,0x876,0x876,
+0x879,0x879,0x879,0x879,0x879,0x879,0x879,0x879,0x879,0x879,0x879,0x879,0x879,0x879,0x879,0x879,
+0x879,0x879,0x879,0x879,0x879,0x879,0x879,0x879,0x879,0x879,0x879,0x879,0x879,0x879,0x879,0x879,
+0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,
+0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x87c,0x87c,
+0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,
+0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x87f,0x87f,
+0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,
+0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,0x882,
+0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,
+0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,0x885,
+0x888,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,
+0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x888,0x88b,0x88b,0x88b,
+0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,
+0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x88b,0x918,0x918,0xe6a,0x918,0x918,0x918,0x91b,0x918,
+0xe6a,0x918,0x918,0xe64,0x915,0x906,0x906,0x906,0x906,0x915,0x906,0xe52,0xe52,0xe52,0x906,0x909,
+0x915,0x90c,0xe58,0xe64,0xe64,0xe52,0xe52,0xe6a,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,
+0x912,0x912,0x91e,0x91e,0x90f,0x90f,0x90f,0x90f,0x918,0x918,0x918,0x918,0x918,0x918,0x915,0x915,
+0x906,0x906,0xe6a,0xe6a,0xe6a,0xe6a,0xe52,0xe52,0x918,0x918,0x918,0x918,0x918,0x918,0x918,0x918,
+0x918,0x918,0x918,0x918,0x918,0x918,0x918,0x918,0x918,0x918,0x918,0x918,0x918,0x918,0x918,0x918,
+0x918,0x918,0x918,0x918,0x918,0x918,0x918,0x918,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0xc6c,
+0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,
+0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,
+0x92d,0x92d,0x92d,0xc6c,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,0x92d,
+0x92d,0x92d,0x92d,0x92d,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,
+0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,0x933,
+0x933,0x933,0x933,0x933,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,
+0x939,0x936,0x93c,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0xfcc,0xfcc,0xfcc,0xfcc,0xfcc,
+0xfcc,0xfcc,0xfcc,0xfcc,0xfc9,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,
+0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,
+0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,
+0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,
+0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x972,0x972,0x972,0x975,0x975,0x972,0x972,0x972,
+0x972,0x972,0x972,0x972,0x972,0x972,0x972,0x972,0x972,0x972,0x972,0x972,0x951,0x951,0x96f,0x954,
+0x954,0x954,0x954,0x954,0x954,0x954,0x96f,0x96f,0x972,0x972,0x972,0x972,0x972,0x972,0x972,0x972,
+0x972,0x972,0x972,0x972,0x972,0x972,0x972,0x972,0x972,0x972,0x972,0x972,0x972,0x972,0x972,0x972,
+0x972,0x972,0x972,0x972,0x972,0x972,0x972,0x972,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,
+0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,
+0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x990,0x98d,0x98d,0x98d,0x98d,
+0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,
+0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x98d,0x9b4,0x9b4,0x9b4,0x9b4,0x9b4,0x9b4,0x9b4,0x9b4,
+0x9b4,0x9b4,0x9b4,0x9b4,0x9b4,0x9b4,0x9b4,0x9b4,0x9b4,0x9b4,0x9b4,0x9b4,0x9b4,0x9b4,0x9b4,0x9b4,
+0x9b4,0x9b4,0x9b4,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,
+0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,
+0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,
+0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,
+0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d2,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,
+0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,
+0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9d8,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,
+0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,
+0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9e7,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,
+0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ed,0x9ea,0x9ea,
+0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,
+0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,0x9ea,
+0x9f0,0x9f0,0xb28,0xb28,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,
+0x9f0,0x9f0,0x9f0,0x9f0,0xb28,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,
+0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xba9,0xba9,0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,
+0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,
+0xa14,0xa14,0xba6,0xba6,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,
+0xbfa,0xbfa,0xbfa,0xbfa,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,
+0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,
+0xa17,0xa17,0xa17,0xa17,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,
+0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,0xa1a,
+0xa1a,0xa1a,0xa1a,0xa1a,0xa29,0xa29,0xa29,0xa29,0xa29,0xa20,0xa2c,0xa32,0xa32,0xa32,0xa26,0xa26,
+0xa26,0xa2f,0xa23,0xa23,0xa23,0xa23,0xa23,0xa1d,0xa1d,0xa1d,0xa1d,0xa1d,0xa1d,0xa1d,0xa1d,0xa32,
+0xa32,0xa32,0xa32,0xa32,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,
+0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,
+0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa29,0xa29,0xa32,0xa32,0xa32,0xa26,0xa26,0xa32,0xa32,0xa32,
+0xa32,0xa32,0xa32,0xa32,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,
+0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa32,0xa32,0xa32,0xa32,0xa26,0xa26,
+0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa26,0xa29,0xa29,0xa29,0xa29,0xa29,
+0xa3e,0xa35,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,
+0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa35,0xa3b,0xa3b,0xa3b,0xa3b,
+0xa3b,0xa3b,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,
+0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa35,0xa3b,0xa3b,0xa3b,0xa3b,
+0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,
+0xa3b,0xa35,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,
+0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa35,0xa3b,0xa3b,
+0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,
+0xa3b,0xa3b,0xa3b,0xa3b,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,
+0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,0xa38,
+0xa38,0xa38,0xa38,0xa38,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,
+0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3b,0xa3b,
+0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,
+0xa3b,0xa3b,0xa3b,0xa3b,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,
+0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3e,0xa3b,0xa3b,
+0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,
+0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3e,0xa3e,0xa3e,0xa3e,0xa41,0xa41,0xa41,0xa41,
+0xa41,0xa41,0xa41,0xa41,0xa41,0xa41,0xa41,0xa41,0xa41,0xa41,0xa41,0xa41,0xa41,0xa41,0xa41,0xa41,
+0xa41,0xa41,0xa41,0xa41,0xa41,0xa41,0xa41,0xa41,0xa41,0xa41,0xa41,0xa41,0xa44,0xa44,0xa44,0xa44,
+0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,
+0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa47,0xa47,0xa47,0xa47,
+0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,
+0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xa47,0xaa1,0xaa1,0xaa1,0xaa1,
+0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,
+0xaa1,0xaa1,0xa9e,0xaa1,0xa9e,0xa9e,0xa9e,0xa9e,0xa9e,0xa9e,0xa9e,0xa9e,0xa9e,0xa9e,0xa9e,0xa9e,
+0xa9e,0xa9e,0xa9e,0xb9d,0xba0,0xc84,0xc84,0xc84,0xc84,0xc84,0xc84,0xc84,0xc84,0xc84,0xc84,0xc84,
+0xd8c,0xd8c,0xd8c,0xd8c,0xaad,0xaad,0xaad,0xaad,0xaad,0xaad,0xaad,0xaad,0xaad,0xaad,0xba3,0xba3,
+0xba3,0xba3,0xba3,0xba3,0xba3,0xba3,0xc87,0xc87,0xc87,0xc87,0xc87,0xc87,0xc87,0xc87,0xc87,0xc87,
+0xc87,0xe82,0x1113,0x1113,0xae0,0xae0,0xae0,0xae0,0xae0,0xae0,0xb10,0xb0d,0xb10,0xb0d,0xb10,0xb0d,
+0xfa5,0xfa2,0xe97,0xe94,0xae3,0xae3,0xae3,0xae3,0xae3,0xae3,0xae3,0xae3,0xae3,0xae3,0xae3,0xae3,
+0xae3,0xae3,0xae3,0xae3,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,
+0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,
+0xae6,0xae6,0xae6,0xae6,0xae9,0xae9,0xae9,0xaef,0xaec,0xb16,0xb13,0xaef,0xaec,0xaef,0xaec,0xaef,
+0xaec,0xaef,0xaec,0xaef,0xaec,0xaef,0xaec,0xaef,0xaec,0xaef,0xaec,0xaef,0xaec,0xae9,0xae9,0xae9,
+0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,
+0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,
+0xaef,0xaec,0xaef,0xaec,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,
+0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,
+0xaef,0xaec,0xae9,0xae9,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,
+0xaf8,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,
+0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,
+0xaf2,0xaf2,0xaf2,0xaf2,0xaf8,0xaf8,0xaf8,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,
+0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,
+0xaf2,0xaf2,0xaf2,0xaf2,0xaf5,0xaf2,0xaf2,0xaf2,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,
+0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,
+0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xba3,0xba3,0xc87,0xc87,0xc87,0xc87,0xc87,0xc87,
+0xc87,0xc87,0xc87,0xc87,0xc87,0xc87,0xc87,0xc87,0xc87,0xc87,0xd8f,0xe82,0xe82,0xe82,0xe82,0xe82,
+0xe82,0xe82,0xe82,0xe82,0xe82,0xfdb,0x1113,0x1113,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,
+0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,
+0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbcd,0xbcd,
+0xbcd,0xbcd,0xbcd,0xbca,0xbdf,0xbdf,0xbdf,0xbd9,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,
+0xbdf,0xbdf,0xbdf,0xbd9,0xbdf,0xbdf,0xbdf,0xbdf,0xbd3,0xbd3,0xbdc,0xbdc,0xbdc,0xbdc,0xbd0,0xbd0,
+0xbd0,0xbd0,0xbd0,0xbd6,0xc99,0xc99,0xc99,0xc99,0xc99,0xc99,0xc99,0xc99,0xc99,0xc99,0xc99,0xc99,
+0xc96,0xc99,0xc99,0xc99,0xc99,0xc99,0xc99,0xc99,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,
+0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbd9,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,
+0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbd3,0xbd3,0xbd3,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,
+0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,
+0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,
+0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xc9c,0xc9c,0xc9c,0xc9c,0xc9c,0xc9c,0xda1,0xda1,0xda1,0xda1,
+0xda1,0xda1,0xda1,0xe9a,0xe9a,0xe9a,0xe9a,0xe9a,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,
+0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,
+0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,
+0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,
+0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbeb,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,
+0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,
+0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xbfa,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,
+0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,
+0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,
+0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,
+0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xca2,0xca2,0xca2,0xca2,0xca2,0xca2,0xca2,0xca2,
+0xca2,0xca2,0xca2,0xca2,0xca2,0xca2,0xca2,0xca2,0xca2,0xca2,0xca2,0xca2,0xca2,0xca2,0xca2,0xca2,
+0xca2,0xca2,0xca2,0xca2,0xca2,0xca2,0xca2,0xca2,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,
+0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca5,0xca5,0xca5,
+0xca5,0xca5,0xca5,0xca5,0xca5,0xca5,0xca5,0xca5,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,
+0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,
+0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xca8,0xcba,0xcba,0xcba,0xcba,0xda4,0xda4,0xda4,0xda4,
+0xda4,0xda4,0xda4,0xea6,0xea6,0xea6,0xea6,0xea6,0xea3,0xea3,0xea3,0xea3,0xea3,0xea3,0xea3,0xea3,
+0xea3,0xea3,0xea3,0xea3,0xea3,0xea3,0xea3,0xea3,0xcc9,0xcc6,0xcc9,0xcc6,0xcc9,0xcc6,0xcc9,0xcc6,
+0xcc9,0xcc6,0xcc9,0xcc6,0xcc9,0xcc6,0xcc9,0xcc6,0xcc9,0xcc6,0xcc9,0xcc6,0xcc9,0xcc6,0xcc9,0xcc6,
+0xcc9,0xcc6,0xcc9,0xcc6,0xcc9,0xcc6,0xcc9,0xcc6,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,
+0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,
+0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,
+0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,
+0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcdb,0xcf3,0xcf3,0xcf3,0xcf3,0xcf3,0xcf3,0xcf3,0xcf3,
+0xcf3,0xcf3,0xcf3,0xcf3,0xcf3,0xcf3,0xcf3,0xcf3,0xcf3,0xcf3,0xcf3,0xcf3,0xcf3,0xcf3,0xcf3,0xda7,
+0xda7,0xda7,0xda7,0xea9,0xea9,0xea9,0xea9,0xea9,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,
+0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,
+0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xcff,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,
+0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,
+0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd05,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,
+0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,
+0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd08,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,
+0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,
+0xd0b,0xd0b,0xd0b,0xd0e,0xd0e,0xd0e,0xd0e,0xd0e,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,
+0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd14,0xd14,0xd14,0xd14,0xd14,0xd14,0xd14,0xd14,0xd11,0xd1a,
+0xeb5,0xeaf,0xebe,0xeac,0xd17,0xd17,0xeac,0xeac,0xd2c,0xd2c,0xd1d,0xd2c,0xd2c,0xd2c,0xd23,0xd2c,
+0xd2c,0xd2c,0xd2c,0xd1d,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,
+0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,
+0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,
+0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,
+0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,
+0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd5f,0xd5f,0xd5f,0xd5f,0xd5f,0xd5f,0xd5f,0xd5f,
+0xd5f,0xd5f,0xd5f,0xd5f,0xd5f,0xd5f,0xd5f,0xd5f,0xfae,0xfae,0xfae,0xfae,0xfae,0xfae,0xfae,0xfae,
+0xfae,0xfae,0xfae,0xfae,0xfae,0xfae,0xfae,0xfae,0xda1,0xda1,0xda1,0xda1,0xe9a,0xe9a,0xe9a,0xe9a,
+0xe9a,0xe9a,0xe9a,0xe9a,0xe9a,0xe9a,0xe9a,0xe9a,0xe9d,0xe9d,0xe9d,0xe9d,0xe9d,0xe9d,0xe9d,0xe9d,
+0xe9d,0xe9d,0xe9d,0xe9d,0xe9d,0xe9d,0xe9d,0xe9d,0xdc2,0xdc2,0xdc2,0xdc2,0xdd4,0xddd,0xde0,0xddd,
+0xde0,0xddd,0xde0,0xddd,0xde0,0xddd,0xde0,0xddd,0xddd,0xddd,0xde0,0xddd,0xddd,0xddd,0xddd,0xddd,
+0xddd,0xddd,0xddd,0xddd,0xddd,0xddd,0xddd,0xddd,0xddd,0xddd,0xddd,0xddd,0xddd,0xddd,0xddd,0xddd,
+0xdc5,0xdd4,0xdc2,0xdc2,0xdc2,0xdc2,0xdc2,0xdd7,0xdc2,0xdd7,0xdd4,0xdd4,0xde9,0xde6,0xde9,0xde9,
+0xde9,0xde6,0xde6,0xde9,0xde6,0xde9,0xde6,0xde9,0xde6,0xed0,0xed0,0xed0,0xff9,0xec7,0xed0,0xec7,
+0xde6,0xde9,0xde6,0xde6,0xec7,0xec7,0xec7,0xec7,0xeca,0xecd,0xff9,0xff9,0xdec,0xdec,0xee2,0xed9,
+0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xed9,0xed9,0xee2,0xed9,
+0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xdf2,0xdf2,0xdf2,0xdf2,
+0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,
+0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xe01,0xe01,0xe01,0xe01,
+0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,
+0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe01,0xe07,0xe07,0xe07,0xe07,
+0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,
+0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe52,0xe6a,0xe64,0xe61,
+0xe61,0xe6a,0xe6a,0xe64,0xe64,0xe61,0xe61,0xe61,0xe61,0xe61,0xe6a,0xe6a,0xe6a,0xe52,0xe52,0xe52,
+0xe52,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe52,0xe64,
+0xe64,0xe52,0xe52,0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,0xe55,0xe6a,0xe67,0xe5e,0xe5e,0xe5e,0xe5e,
+0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xfc6,0xfc6,0xfc3,0xfc0,0xe5b,0xe5b,0xe82,0xe82,0xe82,0xe82,
+0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x117c,0x1113,0x1113,0x1113,0x1113,0x1113,
+0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0xee2,0xed9,0xee2,0xed9,
+0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,
+0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xee2,0xed9,0xedc,0xed9,0xed9,0xed9,
+0xed9,0xed9,0xed9,0xed9,0xed9,0xee2,0xed9,0xee2,0xed9,0xee2,0xee2,0xed9,0xee5,0xee5,0xeeb,0xef1,
+0xef1,0xef1,0xef1,0xef1,0xef1,0xef1,0xef1,0xef1,0xef1,0xef1,0xef1,0xef1,0xef1,0xef1,0xef1,0xef1,
+0xef1,0xef1,0xef1,0xef1,0xef1,0xef1,0xef1,0xef1,0xef1,0xef1,0xef1,0xef1,0xf06,0xf06,0xf06,0xf06,
+0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,
+0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf0f,0xf0f,0xf0f,0xf0f,
+0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,
+0xf0f,0xf0f,0xf0f,0xf0f,0xf12,0xf12,0xf12,0xf15,0xf12,0xf12,0xf18,0xf18,0xf1b,0xf1b,0xf1b,0xf1b,
+0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,
+0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf24,0xf24,0xf24,0xf24,
+0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf27,0xf1e,0xf2d,0xf2a,0xf24,0xf24,0xf24,0xf24,
+0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,
+0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf3f,0xf39,0xf3f,0xf39,
+0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,
+0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,0xf3f,0xf39,0xf4b,0xf4b,0xf4e,0xf4e,
+0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,
+0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4b,0xf4b,0xf4b,0xf4b,
+0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf54,0xf54,
+0xf54,0xf54,0xf54,0xf57,0xf57,0xf57,0xf5a,0xf63,0xf72,0xf72,0xf72,0xf72,0xf72,0xf72,0xf72,0xf72,
+0xf72,0xf72,0xf72,0xf72,0xf72,0xf72,0xf72,0xf72,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,
+0xf5d,0xf5d,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,
+0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf60,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,
+0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,
+0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf81,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,
+0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,
+0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf93,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,
+0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,
+0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9c,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,
+0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,
+0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0xf9f,0x100b,0x100b,0x100b,0x100b,0x100b,0x100b,0x100b,0x100b,
+0x100b,0x100b,0x100b,0x100b,0x100b,0x100b,0x100b,0x100b,0x100b,0x100b,0x100b,0x100b,0x100b,0x100b,0x1002,0x1002,
+0x1005,0x1005,0x100b,0x1002,0x1002,0x1002,0x1002,0x1002,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,
+0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,
+0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x100e,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,
+0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,
+0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1026,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,
+0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,
+0x1041,0x1041,0x1041,0x1041,0x1041,0x1041,0x103e,0x1044,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,
+0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,
+0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1065,0x1065,0x1065,0x1074,0x107a,0x107a,0x107a,0x107a,
+0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,
+0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x107a,0x1068,0x1074,0x1074,0x1065,0x1065,
+0x1065,0x1065,0x1074,0x1074,0x1065,0x1074,0x1074,0x1074,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,
+0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x108f,0x109b,0x108f,0x108f,0x108f,0x10a4,0x10a4,0x108f,
+0x108f,0x10a4,0x109b,0x10a4,0x10a4,0x109b,0x108f,0x1092,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,
+0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,
+0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x109b,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,
+0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,
+0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10c8,0x10c8,0x10c8,0x10c8,0x10c8,0x10c8,0x10c8,0x10c8,
+0x10c8,0x10c8,0x10c8,0x10c8,0x10c8,0x10c8,0x10c8,0x10c8,0x10c8,0x10c8,0x10c8,0x10c8,0x10c8,0x10c8,0x10c8,0x10c8,
+0x10c8,0x10c8,0x10c8,0x10c8,0x10c8,0x10c5,0x10c5,0x10c5,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,
+0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,
+0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10d1,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,
+0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,
+0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,
+0x10fb,0x10fb,0x10fb,0x10fe,0x10fb,0x10fb,0x10fb,0x10fb,0x10f8,0x10f8,0x10f8,0x10ec,0x10ec,0x10ec,0x10ec,0x10f8,
+0x10f8,0x10f2,0x10ef,0x10f5,0x10f5,0x10e6,0x1101,0x1101,0x10e9,0x10e9,0x10f8,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,
+0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,
+0x10fb,0x10fb,0x10fe,0x10fb,0x10fe,0x10fb,0x10fb,0x10fb,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,
+0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,
+0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x110a,0x110a,0x110a,0x1107,0x1107,0x1107,0x1104,0x1104,
+0x1104,0x1104,0x1107,0x1104,0x1104,0x1104,0x110a,0x1107,0x110a,0x1107,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,
+0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,0x1104,
+0x1104,0x1104,0x1104,0x1104,0x1104,0x110a,0x1107,0x1107,0x1104,0x1104,0x1104,0x1104,0x1113,0x1113,0x117c,0x1113,
+0x117c,0x117c,0x117c,0x117c,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,
+0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x1113,0x11f1,0x11f1,0x1128,0x11f1,
+0x11f1,0x11f1,0x1128,0x11f1,0x11f1,0x11f1,0x1128,0x1128,0x1128,0x1128,0x1128,0x11f1,0x11ee,0x11ee,0x11ee,0x11ee,
+0x11ee,0x11ee,0x11ee,0x111f,0x11ee,0x11ee,0x11ee,0x11ee,0x11ee,0x11ee,0x11ee,0x111f,0x114f,0x114f,0x114f,0x114f,
+0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,
+0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x114f,0x11be,0x11be,0x11be,0x11be,
+0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,
+0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,0x11be,0x11d3,0x11c4,0x11d3,0x11d6,
+0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,
+0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11d6,0x11c4,0x11c4,0x11c4,0x11c4,
+0x11c4,0x11c4,0x11c4,0x11c4,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,
+0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,0x11dc,
+0x11dc,0x11dc,0x11dc,0x11dc,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,
+0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,
+0x11e2,0x11e2,0x11e2,0x11e2,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,
+0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,0x11e8,
+0x11e8,0x11e8,0x11e8,0x11e8,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,
+0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,0x11eb,
+0x11eb,0x11eb,0x11eb,0x11eb,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,
+0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,
+0x1203,0x1203,0x1203,0x1203,0,0,0,0
+};
+
+static const UTrie2 propsVectorsTrie={
+    propsVectorsTrie_index,
+    propsVectorsTrie_index+4112,
+    NULL,
+    4112,
+    18264,
+    0xa40,
+    0x1090,
+    0x0,
+    0x0,
+    0x110000,
+    0x5764,
+    NULL, 0, FALSE, FALSE, 0, NULL
+};
+
+static const uint32_t propsVectors[4614]={
+0x67,0,0,0x67,0x80000,0,0x867,0,0,0xa67,0,0,0xb67,0,0,0xc67,
+0,0,0xd67,0,0,0xe67,0,0,0xf67,0,0,0x1067,0,0,0x1167,0,
+0,0x1267,0,0,0x1367,0,0,0x1467,0,0,0x1567,0,0,0x1667,0,0,
+0x1767,0,0,0x1867,0,0,0x1967,0,0,0x1a67,0,0,0x1b67,0,0,0x1d67,
+0,0,0x1f67,0,0,0x2067,0,0,0x2267,0,0,0x2367,0,0,0x2467,0,
+0,0x2567,0,0,0x2767,0,0,0x2867,0x80000,0,0x2967,0,0,0x2a67,0,0,
+0x2b67,0,0,0x2d67,0,0,0x3067,0x20000000,0,0x3167,0x20000000,0,0x3267,0x20000000,0,0x3867,
+0x20000000,0,0x3a67,0,0,0x3b67,0,0,0x3c67,0,0,0x3e67,0,0,0x4067,0,
+0,0x4167,0,0,0x4367,0,0,0x4467,0,0,0x4867,0,0,0x4967,0,0,
+0x4a67,0,0,0x5067,0,0,0x5167,0,0,0x5267,0,0,0x5467,0,0,0x5567,
+0,0,0x5667,0x80000,0,0x5767,0,0,0x5867,0,0,0x5967,0,0,0x5b67,0,
+0,0x5c67,0,0,0x5d67,0,0,0x6067,0x80000,0,0x6167,0,0,0x6267,0,0,
+0x6367,0,0,0x6467,0,0,0x6567,0,0,0x6667,0x20000000,0,0x6f67,0,0,0x7067,
+0,0,0x7367,0x20000000,0,0x7567,0,0,0x7667,0,0,0x7767,0,0,0x7867,0,
+0,0x7a67,0,0,0x7b67,0,0,0x7c67,0,0,0x7e67,0,0,0x7f67,0,0,
+0x8167,0,0,0x8267,0,0,0x8367,0,0,0x8467,0,0,0x8567,0,0,0x8667,
+0,0,0x8767,0,0,0x8867,0,0,0x8967,0,0,0x8b67,0,0,0x8c67,0,
+0,0x8e67,0x20000000,0,0x8f67,0,0,0x9067,0,0,0x9167,0,0,0x9267,0,0,
+0x9367,0,0,0x9567,0,0,0x9667,0,0,0x9767,0,0,0x9867,0,0,0x9967,
+0,0,0x9a67,0,0,0x9b67,0,0,0x9c67,0,0,0x9f67,0,0,0xa067,0,
+0,0xa167,0,0,0xa367,0,0,0xa467,0,0,0xa567,0,0,0xa667,0,0,
+0xa767,0,0,0xa867,0,0,0xa967,0,0,0xaa67,0,0,0xab67,0,0,0xac67,
+0,0,0xad67,0,0,0xae67,0,0,0xaf67,0,0,0xb167,0,0,0xb267,0,
+0,0xb367,0,0,0xb467,0,0,0xb567,0,0,0xb667,0,0,0xb767,0,0,
+0xb867,0,0,0xb967,0,0,0xba67,0,0,0xbc67,0,0,0xbd67,0,0,0xbe67,
+0,0,0xbf67,0,0,0xc067,0,0,0xc167,0,0,0xc267,0,0,0xc367,0,
+0,0xc467,0,0,0xc667,0,0,0xc767,0,0,0xc867,0,0,0xc967,0,0,
+0xca67,0,0,0xcb67,0,0,0xcc67,0,0,0xcd67,0,0,0xce67,0,0,0xcf67,
+0,0,0xd067,0,0,0xa0067,0,0xe00000,0xa4667,0,0xe00000,0xa4767,0,0xe00000,0xa4f67,0,
+0xe00000,0xa5e67,0,0xe00000,0xa5f67,0,0xe00000,0xac567,0,0xe00000,0xad167,0,0xe00000,0x11000100,0,0x900020,
+0x11000100,0x40000001,0x440020,0x11000100,0x40000001,0x643020,0x11000100,0x40000001,0xa5a040,0x11000100,0x40000001,0x116a8a0,0x11000200,0,0x900020,0x11000200,
+0x4000001,0xc4000b,0x11000200,0x7c00100,0x220402,0x11000200,0x24000000,0x200000,0x11000200,0x24000008,0x1710000,0x11000200,0x40000001,0x1d3b020,0x11000219,0x7c00100,
+0x220401,0x11000219,0x7c00100,0x250401,0x11000319,0x7c00100,0x220401,0x11000319,0x7c00100,0x220402,0x11000319,0x7c00100,0x250400,0x11000319,0x7c00100,0x250401,
+0x11000419,0x7c00100,0x220400,0x11000419,0x7c00100,0x220401,0x11000419,0x7c00100,0x220402,0x11000419,0x7c00100,0x230400,0x11000419,0x7c00100,0x250400,0x11000419,
+0x7c00100,0x250401,0x11000419,0x7c00100,0x250402,0x11000519,0x7c00100,0x220400,0x11000519,0x7c00100,0x230400,0x11000600,0x4000400,0x200000,0x11000600,0x4000400,
+0x200002,0x11000600,0x7c00500,0x220400,0x11000600,0x7c00500,0x230400,0x11000600,0x7c00500,0x530400,0x11000600,0x7c00d00,0x230400,0x11000619,0x7c00500,0x22040f,
+0x11000800,0x4000010,0x1001401,0x11000800,0x4000400,0x200001,0x11000800,0x6800010,0x201001,0x11000800,0x7c00500,0x230401,0x11000807,0x7c00100,0x220400,0x11000807,
+0x7c00100,0x250400,0x1100080e,0x4000400,0x200000,0x1100080e,0x4000400,0x200002,0x1100080e,0x7000500,0x220402,0x1100080e,0x7c00100,0x220400,0x1100080e,0x7c00100,
+0x220401,0x1100080e,0x7c00100,0x220402,0x1100080e,0x7c00100,0x250400,0x1100080e,0x7c00100,0x250401,0x1100080e,0x7c00120,0x220402,0x1100080e,0x7c00120,0x250402,
+0x11000901,0x2802400,0x962460,0x11000908,0x2802400,0x962460,0x11000908,0x4000000,0x200000,0x11000908,0x7c00100,0x220400,0x11000908,0x7c00100,0x220401,0x11000908,
+0x7c00100,0x250400,0x11000908,0x7c00100,0x250401,0x11000a03,0x4000000,0x200000,0x11000a03,0x4000000,0x270000,0x11000a03,0x7c00100,0x220400,0x11000a03,0x7c00100,
+0x220402,0x11000a03,0x7c00100,0x250400,0x11000a03,0x7c00500,0x230400,0x11000a03,0xc000000,0x248000,0x11000b13,0x2802500,0x962460,0x11000b13,0x4000000,0x200000,
+0x11000b13,0x4000000,0x201000,0x11000b13,0x4000000,0x230400,0x11000b13,0x4000002,0x400000,0x11000b13,0x4000010,0x200000,0x11000b13,0x7c00100,0x230400,0x11000c00,
+0,0x218820,0x11000c02,0x2802100,0x962460,0x11000c02,0x2802400,0x962460,0x11000c02,0x4000000,0x200000,0x11000c02,0x4000000,0x1329400,0x11000c02,0x4000000,
+0x1329800,0x11000c02,0x4000000,0x1500000,0x11000c02,0x6800000,0x1329800,0x11000c02,0x7c00100,0x230400,0x11000c02,0x7c00100,0x230401,0x11000c02,0x7c00100,0x230402,
+0x11000c02,0x7c00500,0x230400,0x11000c02,0x7d00100,0x230400,0x11000c02,0xc000010,0xb48000,0x11000f00,0x4000000,0x200000,0x11000f01,0x2802400,0x962460,0x11000f0a,
+0x2802100,0x962460,0x11000f0a,0x2802400,0x962460,0x11000f0a,0x2806400,0x962460,0x11000f0a,0x6800000,0x1329800,0x11000f0a,0x6800100,0x962540,0x11000f0a,0x7c00100,
+0x230400,0x11000f0a,0x7c00100,0x230401,0x11001004,0x2802100,0x962460,0x11001004,0x2802400,0x962460,0x11001004,0x2806400,0x962460,0x11001004,0x4000000,0x200000,
+0x11001004,0x4000000,0x1500000,0x11001004,0x6800000,0x1329800,0x11001004,0x6800100,0x962540,0x11001004,0x6800100,0x962541,0x11001004,0x7c00100,0x230400,0x11001004,
+0x7c00100,0x230401,0x11001110,0x2802100,0x962460,0x11001110,0x2802400,0x962460,0x11001110,0x2806400,0x962460,0x11001110,0x6800000,0x1329800,0x11001110,0x6800100,
+0x962540,0x11001110,0x7c00100,0x230400,0x11001110,0x7c00100,0x230401,0x1100120f,0x2802100,0x962460,0x1100120f,0x2802400,0x962460,0x1100120f,0x2806400,0x962460,
+0x1100120f,0x6800000,0x1329800,0x1100120f,0x6800100,0x962540,0x1100120f,0x7c00100,0x230400,0x1100131f,0x2802100,0x962460,0x1100131f,0x2802400,0x962460,0x1100131f,
+0x2806400,0x962460,0x1100131f,0x4000000,0x200000,0x1100131f,0x6800000,0x1329800,0x1100131f,0x6800100,0x962540,0x1100131f,0x6800100,0x962541,0x1100131f,0x7c00100,
+0x230400,0x1100131f,0x7c00100,0x230401,0x11001423,0x2802100,0x962460,0x11001423,0x2806400,0x962460,0x11001423,0x4000000,0x200000,0x11001423,0x6800000,0x1329800,
+0x11001423,0x6800100,0x962540,0x11001423,0x6800100,0x962541,0x11001423,0x7c00100,0x230400,0x11001423,0x7c00100,0x230401,0x11001524,0x2802100,0x962460,0x11001524,
+0x2802100,0x962461,0x11001524,0x2806400,0x962460,0x11001524,0x6800000,0x1329800,0x11001524,0x6800100,0x962540,0x11001524,0x7c00100,0x230400,0x11001615,0x2802100,
+0x962460,0x11001615,0x2806400,0x962460,0x11001615,0x6800000,0x1329800,0x11001615,0x6800100,0x962540,0x11001615,0x6800100,0x962541,0x11001615,0x7c00100,0x230400,
+0x1100171a,0x2802100,0x962460,0x1100171a,0x2806400,0x962460,0x1100171a,0x6800000,0x1329800,0x1100171a,0x6800100,0x962540,0x1100171a,0x6800100,0x962541,0x1100171a,
+0x7c00100,0x230400,0x11001900,0x4000000,0x1600000,0x11001926,0x2802100,0x1862460,0x11001926,0x2802400,0x1862460,0x11001926,0x2806100,0x1862460,0x11001926,0x4000000,
+0x200000,0x11001926,0x4000010,0x400000,0x11001926,0x6800000,0x1329800,0x11001926,0x7800100,0x1830142,0x11001926,0x7c00100,0x1830000,0x11001926,0x7c00100,0x1830140,
+0x11001926,0x7c00900,0x1830000,0x11001926,0x7e00100,0x1830160,0x11001a18,0x2802100,0x1862460,0x11001a18,0x2802400,0x1862460,0x11001a18,0x6800000,0x1329800,0x11001a18,
+0x7800100,0x1830142,0x11001a18,0x7c00100,0x1830000,0x11001a18,0x7c00100,0x1830002,0x11001a18,0x7c00100,0x1830140,0x11001a18,0x7c00900,0x1830000,0x11001a18,0x7e00100,
+0x1830160,0x11001d00,0x4000000,0x200000,0x11001d0c,0x7c00100,0x230400,0x11001d0c,0x7c00100,0x250400,0x11001e12,0x7c00100,0x2230500,0x11001e12,0x7c00100,0x2330520,
+0x11001e12,0x7c80100,0x2330520,0x11002619,0x7c00100,0x220401,0x11002619,0x7c00100,0x220402,0x11002619,0x7c00100,0x250401,0x1100270e,0x4000400,0x200001,0x1100270e,
+0x4000400,0x200002,0x1100270e,0x4000400,0x500001,0x1100270e,0x7c00100,0x220401,0x1100270e,0x7c00100,0x250401,0x11002800,0x80000,0x918820,0x11002800,0x80000,
+0x1c18020,0x11002800,0x180000,0x918820,0x11002800,0x4000001,0x440001,0x11002800,0x4000001,0x440002,0x11002800,0x4000001,0xc4000b,0x11002800,0x6800000,0x201c00,
+0x11002800,0x6800020,0x201c00,0x11002800,0x24000000,0x200000,0x11002800,0x24000000,0x200002,0x11002800,0x24000000,0x810000,0x11002800,0x24000000,0x1410000,0x11002800,
+0x24000000,0x1500000,0x11002800,0x24000000,0x1500002,0x11002800,0x24000002,0x400000,0x11002800,0x24000006,0xc0000b,0x11002800,0x24000008,0x1410000,0x11002800,0x24000008,
+0x1710000,0x11002800,0x24000020,0x1001400,0x11002800,0x24000020,0x1500002,0x11002800,0x2c000010,0x1248000,0x11002800,0x2c000010,0x1248002,0x11002800,0x40000001,0x63b020,
+0x11002800,0x40080000,0x918820,0x11002801,0x82000,0x962460,0x11002900,0x4000000,0x20000e,0x11002900,0x4000000,0x20000f,0x11002900,0x4000020,0x20000e,0x11002900,
+0x4000020,0x20000f,0x11002900,0x4000020,0x81000e,0x11002900,0x4000020,0x81000f,0x11002900,0x4000020,0x141000e,0x11002900,0x4000020,0x141000f,0x11002900,0x4000022,
+0x20000e,0x11002900,0x4000022,0x20000f,0x11002a00,0x4000000,0x1500000,0x11002a00,0x4000000,0x1600000,0x11002a00,0x4000000,0x1600002,0x11002b01,0x2000,0x962460,
+0x11002b01,0x2802020,0x962460,0x11002c00,0x4000000,0x200000,0x11002c00,0x4000000,0x200002,0x11002c00,0x4000000,0x20000f,0x11002c00,0x4000020,0x200000,0x11002c00,
+0x7c00000,0x200000,0x11002c00,0x7c00020,0x200000,0x11002c00,0x7c00120,0x220405,0x11002c00,0x7c00120,0x230402,0x11002c00,0x7c00120,0x250402,0x11002c00,0x7c00120,
+0x250405,0x11002c19,0x7c00100,0x250400,0x11002c19,0x7c00100,0x250401,0x11002d00,0x4000000,0x100006,0x11002d00,0x4000000,0x200006,0x11002d19,0x7c00100,0x220402,
+0x11002d19,0x7c00100,0x230400,0x11002d19,0x7c00100,0x250402,0x11002e00,0x24000000,0x200000,0x11002e00,0x24000020,0x200000,0x11002e00,0x24000020,0x200001,0x11002f00,
+0x24000020,0x200000,0x11002f00,0x24000020,0x200001,0x11002f00,0x24000020,0x200002,0x11002f00,0x24000020,0x1600000,0x11002f00,0x24000022,0x1600000,0x11003000,0x24000000,
+0x200000,0x11003000,0x24000020,0x200000,0x11003100,0x24000000,0x200000,0x11003200,0x24000000,0x200000,0x11003300,0x4000000,0x100003,0x11003400,0x24000000,0x100000,
+0x11003400,0x24000000,0x200000,0x11003500,0x24000000,0x200000,0x11003600,0x24000000,0x200000,0x11003600,0x24000020,0x200000,0x11003700,0x24000000,0x200000,0x11003700,
+0x24000020,0x200000,0x11003800,0x4000000,0x100000,0x11003800,0x24000000,0x200000,0x11003800,0x24000000,0xb00000,0x11003800,0x24000000,0x1710000,0x11005003,0x7c00100,
+0x220402,0x11005013,0x2802500,0x962460,0x11005013,0x4000020,0x200005,0x11005013,0x7c00100,0x230401,0x11005013,0x7c00100,0x230402,0x11005013,0x7c00100,0x230405,
+0x11005019,0x7c00100,0x220402,0x11005100,0x24000000,0x810000,0x11005100,0x24000000,0x1410000,0x11005102,0x7000100,0x230408,0x11005102,0x7c00100,0x230404,0x11005102,
+0x7c00100,0x230407,0x11005102,0x7c00100,0x230408,0x11005102,0x7c00100,0x230409,0x11005201,0x2802400,0x962460,0x11005500,0x80000,0x1e18820,0x11005502,0x7000100,
+0x230408,0x11005502,0x7c00100,0x230404,0x11005502,0x7c00100,0x230407,0x11005502,0x7c00100,0x230408,0x11005502,0x7c00100,0x230409,0x11005667,0x1000,0,
+0x11020200,0x80004,0x418820,0x11020200,0x4000000,0x100006,0x11020200,0x4000000,0x10000f,0x11020200,0x4000400,0x100002,0x11020200,0x4000400,0x500002,0x11020200,
+0x6800c00,0x101000,0x11020200,0x24000000,0x100000,0x11020200,0x24000000,0x200000,0x11020200,0x24000000,0x1400000,0x11020200,0x24000000,0x1500000,0x11020200,0x24000000,
+0x1600000,0x11020200,0x24000020,0x100000,0x11020200,0x24000020,0x1600000,0x11020219,0x7c00100,0x12040f,0x11020219,0x7c00100,0x220400,0x11020219,0x7c00100,0x220401,
+0x11020219,0x7c00100,0x250400,0x11020319,0x7c00100,0x220400,0x11020319,0x7c00100,0x220401,0x11020319,0x7c00100,0x220402,0x11020319,0x7c00100,0x250400,0x11020319,
+0x7c00100,0x250402,0x11020319,0x7d00100,0x220402,0x11020419,0x7c00100,0x220401,0x11020519,0x7c00100,0x220400,0x11020600,0x4000400,0x100002,0x11020600,0x4000400,
+0x200000,0x11020600,0x7c00500,0x130400,0x11020600,0x7c00d00,0x130400,0x11020701,0x2802400,0x962460,0x11020701,0x2802400,0x962461,0x11020701,0x2802400,0xc62460,
+0x11020701,0x2802500,0x962460,0x1102080e,0x7c00100,0x220400,0x1102080e,0x7c00100,0x250400,0x11020908,0x7c00100,0x220400,0x11020908,0x7c00100,0x220401,0x11020908,
+0x7c00100,0x250400,0x11020908,0x7c00100,0x250401,0x11022800,0x24000000,0x100000,0x11022800,0x24000000,0x200000,0x11022800,0x24000000,0x200002,0x11022800,0x24000000,
+0x401000,0x11022800,0x24000000,0xf00002,0x11022800,0x24000000,0xf0ac02,0x11022800,0x24000000,0x1500000,0x11022800,0x24000002,0x100000,0x11022800,0x24000002,0x370000,
+0x11022800,0x24000002,0x470000,0x11022800,0x24000006,0x400000,0x11022800,0x24000008,0x1710000,0x11022800,0x24000008,0x1712c00,0x11022800,0x24000020,0x100000,0x11022800,
+0x24000020,0x1500000,0x11022800,0x24000020,0x1500002,0x11022900,0x4000000,0x10000e,0x11022900,0x4000000,0x10000f,0x11022919,0x7c00100,0x13040f,0x11022c00,0x4000000,
+0x100002,0x11022c00,0x4000000,0x10000f,0x11022c00,0x4000000,0x1500002,0x11022c00,0x4000000,0x1600002,0x11022c00,0x7c00120,0x120405,0x11022c0e,0x7c00100,0x250401,
+0x11022c19,0x7c00100,0x150401,0x11022d00,0x4000000,0x100006,0x11022d00,0x4000000,0x200006,0x11022d19,0x7c00100,0x120402,0x11022d19,0x7c00100,0x150402,0x11022e00,
+0x24000000,0x200000,0x11022e00,0x24000020,0x100000,0x11022f00,0x24000020,0x100000,0x11022f00,0x24000020,0x100001,0x11022f00,0x24000020,0x100002,0x11023000,0x24000000,
+0x100000,0x11023300,0x4000000,0x100002,0x11023300,0x4000000,0x100003,0x11023300,0x4000100,0x120403,0x11023300,0x4000100,0x150403,0x11023400,0x24000000,0x100000,
+0x11023500,0x24000000,0x100000,0x11023600,0x24000000,0x100000,0x11023600,0x24000020,0x100000,0x11023700,0x24000000,0x100000,0x11023700,0x24000020,0x100000,0x11023800,
+0x4000000,0x100000,0x11023800,0x24000000,0x200000,0x11024e67,0,0,0x11025600,0x4000000,0x100000,0x11042a00,0x4000000,0x1600000,0x11045700,0x4000000,
+0x20000a,0x11045700,0x4000020,0x20000a,0x11045712,0x7c00100,0x23040a,0x11045712,0x7c80100,0x23040a,0x11045716,0x7c00100,0x230c0a,0x11045716,0x7c00100,0x1230c0a,
+0x11063d00,0x4000001,0xe40011,0x11065700,0x4000000,0x810011,0x11065700,0x4000000,0xe00011,0x11065700,0x4000000,0x1410011,0x11065700,0x4000000,0x1500011,0x11065700,
+0x4000000,0x1600011,0x11065700,0x4000006,0xe70011,0x11065700,0x4000008,0xe00011,0x11065700,0x4000008,0xe02c11,0x11065700,0x4000010,0x871411,0x11065700,0x4000010,
+0x1201411,0x11065700,0x4000010,0x1271011,0x11065700,0x4000020,0xe00011,0x11065700,0x4000400,0xe00011,0x11065700,0x4000420,0xe00011,0x11065700,0x6800000,0xe01c11,
+0x11065700,0x6800040,0xe00011,0x11065700,0xc000010,0x80ac11,0x11065700,0xc000010,0xb48011,0x11065719,0x7c00100,0xe20411,0x11065719,0x7c00100,0xe50411,0x11065719,
+0x7c00140,0xe20411,0x11065719,0x7c00140,0xe50411,0x11080100,0x6800000,0x201c00,0x11080100,0x68000c0,0x1329800,0x11080100,0x24000000,0x200000,0x11080100,0x24000000,
+0x810000,0x11080100,0x24000000,0x1410000,0x11080100,0x24000000,0x1500000,0x11080100,0x24000000,0x1600000,0x11080100,0x24000000,0x1b00000,0x11080100,0x24000000,0x2410000,
+0x11080100,0x24000006,0xd70000,0x11080100,0x24000008,0x1710000,0x11080100,0x24000008,0x1712c00,0x11080100,0x24000010,0x1001400,0x11080100,0x24000010,0x1071000,0x11080100,
+0x24000010,0x1071400,0x11080100,0x24000020,0x200000,0x11080100,0x24000020,0x400000,0x11080100,0x24000020,0x1600000,0x11080100,0x24000400,0x200000,0x11080100,0x24000420,
+0x200000,0x11080100,0x2c000010,0xb48000,0x11080100,0x2c000010,0x100ac00,0x11080100,0x44000001,0x1a40000,0x11080119,0x7c00100,0x220400,0x11080119,0x7c00100,0x250400,
+0x11080119,0x7c001c0,0x220400,0x11080119,0x7c001c0,0x250400,0x11080200,0x4000400,0x200002,0x11080200,0x24000000,0x200000,0x11080200,0x24000000,0x1500000,0x11080200,
+0x24000000,0x1600000,0x11080200,0x24000020,0x200000,0x110a1e12,0x7c00100,0x2130480,0x110a1e12,0x7c80100,0x2130480,0x110a3000,0x24100000,0x810001,0x110a3000,0x24100000,
+0x1410001,0x110a3d00,0x4000000,0xe00000,0x110a3d00,0x4000000,0xe00002,0x110a3d00,0x24000000,0xe00000,0x110a3d11,0x7c00300,0xe30000,0x110a3d11,0x7c00900,0x1230400,
+0x110a3d12,0x2802400,0x962460,0x110a3e14,0x7c00100,0xe30000,0x110a3e14,0x7c00100,0xe30001,0x110a3e14,0x7c00100,0x1230000,0x110a3e14,0x7c00900,0x1230000,0x110a3e14,
+0x7c00900,0x1230001,0x110a3f16,0x7c00100,0xe30c00,0x110a3f16,0x7c00100,0xe30c01,0x110a3f16,0x7c00100,0x1230c00,0x110a3f16,0x7c00900,0x1230c00,0x110a3f16,0x7c00900,
+0x1230c01,0x110a4005,0x7c00100,0xe30400,0x110a4112,0x7c00100,0xe30402,0x110a4112,0x7c80100,0xe30402,0x110a4400,0x4000000,0xe00000,0x110a4412,0x4000000,0xe00002,
+0x110a4412,0x4000000,0xe00003,0x110a4416,0x4000000,0xe00c03,0x110a4500,0x4000000,0xe0000d,0x110a4516,0x4000000,0xe00c0d,0x110a4711,0x7c40300,0xe30000,0x110a4f11,
+0x7c00300,0xe30001,0x110a4f11,0x7c40300,0xe30000,0x110a5300,0x4000000,0x810010,0x110a5300,0x4000000,0xe00002,0x110a5300,0x4000000,0xe00010,0x110a5300,0x4000000,
+0x1410010,0x110a5300,0x4000002,0xe70010,0x110a5300,0x4000008,0x810010,0x110a5300,0x4000008,0x1410010,0x110a5300,0x6800000,0xe01c02,0x110a5300,0x6800000,0xe01c10,
+0x110a5400,0x4000000,0x81000c,0x110a5400,0x4000000,0xe0000c,0x110a5400,0x4000000,0x141000c,0x110a5400,0x4000000,0x150000c,0x110a5400,0x4000000,0x160000c,0x110a5400,
+0x4000002,0xe7000c,0x110a5400,0x4000010,0x87140c,0x110a5400,0x4000010,0xe7000c,0x110a5400,0x4000010,0x120140c,0x110a5400,0x4000010,0x127100c,0x110a5400,0x4000020,
+0xe0000c,0x110a5400,0x4000026,0xe7000c,0x110a5400,0xc000010,0x80ac0c,0x110a5400,0xc000010,0xb4800c,0x11400a06,0xc000010,0x1049400,0x11400c00,0x7c00900,0x230400,
+0x11400c02,0x6800000,0x1329800,0x11400c0e,0x4000010,0xb00000,0x11400c0e,0x4000010,0x1071400,0x11400c0e,0xc000010,0xb48000,0x11400f14,0xc000010,0x448000,0x11403d1c,
+0x4000000,0xe00000,0x1144570a,0x3802500,0x126246a,0x1144570a,0x7c00d00,0x1230c0a,0x11445721,0x4000004,0x120000a,0x11445721,0x4000008,0x81000a,0x11445721,0x4000008,
+0x141000a,0x11445721,0x4000010,0x87000a,0x11445721,0xc000010,0x84800a,0x114a3d0a,0x7c00900,0xe30c00,0x114a3d11,0x7c00300,0xe30000,0x114a3d1c,0x4000000,0xe00000,
+0x114a3d1c,0x24000000,0xe00000,0x114a3d1c,0x24000002,0xe00000,0x114a3d1c,0x24000002,0x1200000,0x114a3d1c,0x24000008,0x810000,0x114a3d1c,0x24000008,0x1410000,0x114a3d21,
+0x24000000,0x810000,0x114a3d21,0x24000000,0x1410000,0x114a3d21,0x24000008,0x810000,0x114a3d21,0x24000008,0x1410000,0x114a3d21,0x24000010,0x870000,0x114a3d21,0x2c000010,
+0x848000,0x114a3e0a,0x7000400,0x1200c02,0x114a3f0a,0x7c00d00,0x1230c00,0x114a3f21,0x4000004,0x1200000,0x114a4211,0x4000000,0xe00000,0x114a4211,0x4000000,0xe0000f,
+0x114a441c,0x4000000,0xe00002,0x114a441c,0x4000000,0xe00003,0x114a451c,0x4000000,0xe00002,0x114a451c,0x4000000,0xe0000d,0x11800c00,0x2802100,0x962460,0x11800c00,
+0x2802500,0x962460,0x118a3d08,0x2802400,0x962460,0x118a3e0a,0x2802400,0x962460,0x11c05104,0x7c00100,0x230408,0x20000067,0x1000,0,0x20000b13,0x2802400,
+0x962460,0x20000b13,0x2802500,0x962460,0x20001b27,0x2802100,0x962460,0x20001b27,0x2802100,0x962461,0x20001b27,0x2802400,0x962460,0x20001b27,0x2806400,0x962460,
+0x20001b27,0x2902100,0x962462,0x20001b27,0x4000000,0x200000,0x20001b27,0x4000000,0x400000,0x20001b27,0x4000000,0x500000,0x20001b27,0x4000000,0x810000,0x20001b27,
+0x4000000,0xb00000,0x20001b27,0x4000000,0xc0000b,0x20001b27,0x4000000,0x1410000,0x20001b27,0x4000010,0xb00000,0x20001b27,0x4000010,0xc00000,0x20001b27,0x6800000,
+0x1329800,0x20001b27,0x6800100,0x462540,0x20001b27,0x6800400,0x962540,0x20001b27,0x7c00100,0x230400,0x20001b27,0x7c00100,0x230401,0x20002619,0x7c00100,0x220401,
+0x20002a00,0x4000000,0x1600000,0x20004b67,0,0x1900000,0x20004c67,0,0x1900000,0x20004d67,0,0x1900000,0x20006d67,0x1000,0,0x20006e67,
+0x1000,0,0x20026d67,0,0,0x20026e67,0,0,0x200a4a12,0x7c00100,0x1f304c1,0x200a4a12,0x7c00100,0x20304e1,0x21005600,0x4000000,
+0x700000,0x21022a00,0x4000000,0x1600000,0x30000419,0x7c00100,0x220400,0x30000419,0x7c00100,0x220401,0x30000419,0x7c00100,0x250400,0x30000419,0x7c00100,0x250401,
+0x30000519,0x7c00100,0x220400,0x30000600,0x4000400,0x200000,0x30000600,0x7c00500,0x230400,0x30000605,0x4000400,0x200000,0x3000080e,0x7c00100,0x220400,0x30000908,
+0x2000,0x962460,0x30000908,0x7c00100,0x220400,0x30000908,0x7c00100,0x220401,0x30000908,0x7c00100,0x250400,0x30000908,0x7c00100,0x250401,0x30000a03,0x4000006,
+0x400000,0x30000c02,0x4000000,0x200000,0x30000c02,0x7c00100,0x230400,0x30000d22,0,0x218820,0x30000d22,0x2802100,0x962460,0x30000d22,0x2802400,0x962460,
+0x30000d22,0x2802500,0x962460,0x30000d22,0x4000000,0x200000,0x30000d22,0x4000010,0x200000,0x30000d22,0x7c00100,0x230400,0x30000d22,0xc000010,0x248000,0x30000e25,
+0x2802500,0x962460,0x30000e25,0x7c00100,0x230400,0x30001821,0x2802100,0x962460,0x30001821,0x2806400,0x962460,0x30001821,0x4000000,0x200000,0x30001821,0x6800100,
+0x962540,0x30001821,0x6800100,0x962541,0x30001821,0x7c00100,0x230400,0x30001b27,0x2802100,0x962460,0x30001b27,0x2802400,0x962460,0x30001b27,0x4000000,0x200000,
+0x30001b27,0x4000000,0x400000,0x30001b27,0x7c00100,0x230400,0x30001c1c,0x2802100,0x1862460,0x30001c1c,0x2802400,0x1862460,0x30001c1c,0x2806400,0x1862460,0x30001c1c,
+0x4000000,0x200000,0x30001c1c,0x6800000,0x1329800,0x30001c1c,0x6800100,0x1862540,0x30001c1c,0x7c00100,0x1830000,0x30001c1c,0x7c00100,0x1830001,0x30001c1c,0xc000010,
+0x448000,0x30001f0b,0x4000000,0x200000,0x30001f0b,0x4000010,0x200000,0x30001f0b,0x4000010,0x400000,0x30001f0b,0x6800000,0x200000,0x30001f0b,0x7c00100,0x230400,
+0x30001f0b,0xc000010,0x248000,0x30002006,0x7c00100,0x230400,0x30002128,0x4000010,0x200000,0x30002128,0x7c00100,0x230400,0x30002128,0xc000010,0x248000,0x3000221d,
+0x4000000,0x810000,0x3000221d,0x4000000,0x1410000,0x3000221d,0x4000001,0x440000,0x3000221d,0x7c00100,0x230400,0x30002300,0x4000010,0x400000,0x30002320,0x7c00100,
+0x230400,0x30002417,0x80000,0x1818820,0x30002417,0x2802100,0x1862460,0x30002417,0x2802400,0x1862460,0x30002417,0x2806400,0x1862460,0x30002417,0x4000000,0x200000,
+0x30002417,0x4000000,0x400000,0x30002417,0x4000000,0x1600000,0x30002417,0x4000010,0x400000,0x30002417,0x4000010,0x1200000,0x30002417,0x6800000,0x1329800,0x30002417,
+0x6800100,0x1862540,0x30002417,0x7c00100,0x1830000,0x30002417,0x7d00100,0x1830000,0x3000251b,0x2802100,0x962460,0x3000251b,0x4000000,0x200000,0x3000251b,0x4000001,
+0xc40000,0x3000251b,0x4000006,0x500000,0x3000251b,0x4000010,0x400000,0x3000251b,0x4000010,0xb70000,0x3000251b,0x6800000,0x1329800,0x3000251b,0x7c00100,0x230400,
+0x3000251b,0x7c00900,0x230400,0x3000251b,0xc000010,0xb48000,0x3000251b,0x12882000,0x962460,0x30002800,0x4000001,0xc4000b,0x30002800,0x24000000,0x200000,0x30002800,
+0x2c000010,0x1248002,0x30002a00,0x4000000,0x1600000,0x30002b01,0x2000,0x962460,0x30002c00,0x4000000,0x200000,0x30002c00,0x7c00100,0x220405,0x30002d19,0x7c00100,
+0x250400,0x30002e00,0x24000000,0x200000,0x30003000,0x24000000,0x200000,0x30003100,0x24000000,0x200000,0x30003600,0x24000000,0x200000,0x30003700,0x24000000,0x200000,
+0x3000392e,0x24000000,0x200000,0x30005013,0x7c00100,0x230401,0x30005600,0,0x918820,0x30020600,0x4000400,0x500000,0x30020701,0x2802400,0x962460,0x30020701,
+0x2802400,0xc62460,0x300a3a11,0x4020000,0xe00000,0x300a3a11,0x4020000,0xe00002,0x300a3b11,0x4020000,0xe00002,0x300a3c00,0x4008000,0xe00000,0x300a3c00,0x4010000,
+0xe00000,0x300a3d11,0x7c00300,0xe30002,0x300a4305,0x7c00100,0xe30400,0x300a4611,0x7c40300,0xe30000,0x300a4829,0x7c00100,0xe30400,0x300a4829,0x7c00900,0x1230400,
+0x300a4929,0x4000000,0xe00000,0x3040250c,0x4000010,0x400000,0x3040250c,0x4000010,0xb70000,0x3040250c,0xc000010,0xb48000,0x304a3d1c,0x4000000,0xe00000,0x30800c00,
+0x2802100,0x962460,0x3100080e,0x7c00120,0x220402,0x3100080e,0x7c00120,0x250402,0x31005167,0x1000,0,0x3100581e,0x4000000,0x200000,0x3100581e,0x7c00100,
+0x230400,0x3100590d,0x7c00100,0x230400,0x31005a09,0x7c00100,0x220400,0x31005a09,0x7c00100,0x250400,0x31005b00,0x4000000,0x200000,0x31005c00,0x80000,0x918820,
+0x31005c00,0x2802000,0x962460,0x31005c00,0x2802400,0x962460,0x31005c00,0x4000000,0x200000,0x31005c00,0x4000000,0x200001,0x31005c00,0x6800000,0x962540,0x31005c00,
+0x6800400,0x962540,0x31005c01,0x2802400,0x962460,0x31005d00,0x4000020,0x200005,0x31005d00,0x6800020,0x1329805,0x31005d00,0x7c00120,0x220405,0x31005d00,0x7c00120,
+0x250405,0x31006000,0x180000,0x918820,0x310a5e11,0x7c40300,0xe30000,0x310a5f11,0x7c00300,0xe30001,0x32000419,0x7c00100,0x250400,0x3200080e,0x4000020,0x200000,
+0x3200080e,0x7c00100,0x220400,0x3200080e,0x7c00100,0x250400,0x32000908,0x7c00100,0x220400,0x32000908,0x7c00100,0x250400,0x32000c02,0x7c00100,0x230400,0x32000e25,
+0x7c00100,0x230400,0x32001d0c,0x7c00100,0x230400,0x32002800,0x80000,0x1e18820,0x32002800,0x80020,0x218820,0x32002800,0x4000001,0x440002,0x32002800,0x24000000,
+0x200000,0x32002800,0x24000000,0x200002,0x32002800,0x24000020,0x200000,0x32002800,0x2c000010,0x1248002,0x32002919,0x7c00100,0x23040f,0x32002a00,0x4000000,0x1600000,
+0x32002b01,0x2000,0x962460,0x32002b01,0x2802000,0x962460,0x32002b01,0x2802020,0x962460,0x32002c00,0x4000000,0x200000,0x32002c00,0x4000020,0x200000,0x32002c00,
+0x4000020,0x200005,0x32002c00,0x7c00120,0x220405,0x32002c00,0x7c00120,0x250405,0x32002e00,0x24000020,0x200000,0x32002f00,0x24000020,0x200000,0x32003000,0x24000000,
+0x200000,0x32003000,0x24000020,0x200000,0x32003500,0x24000000,0x200000,0x32003600,0x24000020,0x200000,0x32003700,0x24000000,0x100000,0x32003700,0x24000000,0x200000,
+0x32003800,0x24000000,0x810000,0x32003800,0x24000000,0x1410000,0x32005102,0x4000000,0x1500008,0x32005502,0x7c00100,0x230400,0x32006108,0x7c00100,0x220400,0x32006108,
+0x7c00100,0x250400,0x3200622a,0x2802100,0x962460,0x3200622a,0x2806000,0x962460,0x3200622a,0x7c00100,0x230400,0x3200632b,0x2802100,0x962460,0x3200632b,0x2806000,
+0x962460,0x3200632b,0x7c00100,0x230400,0x3200642c,0x2802100,0x962460,0x3200642c,0x7c00100,0x230400,0x3200652d,0x2802100,0x962460,0x3200652d,0x7c00100,0x230400,
+0x32006600,0x24000020,0x200000,0x32006700,0x24000020,0x200000,0x32006800,0x24000020,0x200000,0x32006900,0x24000020,0x200000,0x32006900,0x24000020,0x810000,0x32006900,
+0x24000020,0x1410000,0x32006a00,0x24000020,0x200000,0x32006a00,0x24000020,0x200001,0x32006a00,0x24000020,0x200002,0x32020701,0x2802000,0x962460,0x32020701,0x2882000,
+0xc62460,0x32023300,0x4000000,0x100000,0x32026c01,0x12882000,0x962460,0x32065700,0x4000000,0x810011,0x32065700,0x4000000,0x1410011,0x32086600,0x24000020,0x810000,
+0x32086600,0x24000020,0x1410000,0x32086900,0x24000020,0x810000,0x32086900,0x24000020,0x1410000,0x320a3d11,0x7c00100,0x1230400,0x320a3e14,0x7c00100,0xe30010,0x320a3e14,
+0x7c00100,0x1230000,0x320a3f16,0x7c00100,0xe30c10,0x320a4400,0x4000000,0xe00003,0x320a4929,0x4000000,0xe00000,0x320a4f11,0x7c00300,0xe30001,0x320a6b16,0x7c00100,
+0x1230c00,0x32406318,0xc000000,0x448000,0x324a3d11,0x4000000,0xe00000,0x324a3d11,0x7c00100,0x1230400,0x324a3f0a,0x4000002,0x1200c00,0x324a531c,0x24000000,0xe00000,
+0x40000419,0x7c00100,0x220400,0x40000519,0x7c00100,0x220400,0x40000600,0x4000400,0x200000,0x4000080e,0x7c00100,0x220400,0x4000080e,0x7c00100,0x250400,0x4000080e,
+0x7c00100,0x250402,0x40000c02,0,0x218820,0x40000c02,0x2802100,0x962460,0x40000c02,0x2802400,0x962460,0x40000c02,0x2802500,0x962460,0x40000c02,0x4000000,
+0x200000,0x40000c02,0x4000000,0x1071400,0x40000c02,0x7c00100,0x230400,0x40000d22,0x7c00100,0x230400,0x40000f0a,0x7c00100,0x230400,0x40001004,0x7c00100,0x230400,
+0x40001110,0x2802100,0x962460,0x40001110,0x6800100,0x962540,0x4000120f,0x2802100,0x962460,0x4000120f,0x4000000,0x1600000,0x4000120f,0x7c00100,0x230400,0x4000131f,
+0x7c00100,0x230400,0x40001423,0x4000000,0x200000,0x40001423,0x4000000,0x1600000,0x40001615,0x2802400,0x962460,0x40001615,0x7c00100,0x230400,0x40002417,0x2802400,
+0x1862460,0x40002417,0x4000000,0x200000,0x40002800,0x6800000,0x201c00,0x40002800,0x24000002,0x200000,0x40002c00,0x4000000,0x200002,0x40003000,0x24000000,0x200000,
+0x40003000,0x24000020,0x200000,0x40003700,0x24000000,0x200000,0x40005a09,0x7c00100,0x220400,0x40005a09,0x7c00100,0x250400,0x40005d00,0x7c00120,0x220405,0x40006f30,
+0x2802100,0x962460,0x40006f30,0x2802400,0x962460,0x40006f30,0x4000000,0x200000,0x40006f30,0x6800000,0x1329800,0x40006f30,0x6800100,0x962540,0x40006f30,0x7c00100,
+0x230400,0x40006f30,0xc000010,0xb48000,0x40007034,0x7c00100,0x1830000,0x40007117,0x4000000,0x200000,0x40007208,0x7c00100,0x220400,0x4000720e,0x7c00100,0x220400,
+0x4000720e,0x7c00500,0x22040e,0x4000720e,0x7c00500,0x22040f,0x40007219,0x7c00100,0x220400,0x40007219,0x7c00500,0x220400,0x40007219,0x7c00500,0x22040e,0x40007219,
+0x7c00500,0x22040f,0x40007300,0x24000000,0x200000,0x40007400,0x4000000,0x200000,0x40007531,0x7c00100,0x230400,0x40007631,0x7c00100,0x230400,0x40007700,0x4000000,
+0x200000,0x40007700,0x4000000,0x400000,0x40007835,0x4000010,0x400000,0x40007835,0x7c00100,0x230400,0x40007933,0x7c00100,0x230400,0x40007a32,0x6800000,0x1329800,
+0x40007a32,0x7c00100,0x230400,0x40007b2f,0x7c00100,0x230400,0x40007c00,0x4000000,0x200000,0x40020701,0x2802400,0x962460,0x40020701,0x2802400,0xc62460,0x40023300,
+0x4000000,0x200000,0x40023700,0x24000000,0x100000,0x40027d01,0x12882000,0x962460,0x400a4400,0x4000000,0xe0000d,0x400a4412,0x4000000,0xe00002,0x400a4412,0x4000000,
+0xe00003,0x400a4500,0x4000000,0xe0000d,0x400a5300,0x4000000,0x810010,0x400a5300,0x4000000,0x1410010,0x40405102,0x4000000,0x200000,0x41000419,0x7c00100,0x220400,
+0x41000419,0x7c00100,0x250400,0x4100080e,0x7c00100,0x220400,0x4100080e,0x7c00100,0x250400,0x41000908,0x7c00100,0x220400,0x41000908,0x7c00100,0x250400,0x41000b13,
+0x2802000,0x962460,0x41000b13,0x2802100,0x962460,0x41000b13,0x4000000,0xb00000,0x41000c02,0x2802100,0x962460,0x41000c02,0x4000000,0xb00000,0x41000c02,0x4000000,
+0x1500000,0x41000f0a,0x7c00100,0x230400,0x41001004,0x7c00100,0x230400,0x41001423,0x6800000,0x1329800,0x41001423,0x7c00100,0x230400,0x41001b27,0x4000000,0x500000,
+0x41001d0c,0x7c00100,0x230400,0x41001d0c,0x7c00100,0x23040f,0x41001f0b,0x2802100,0x962460,0x41001f0b,0x4000000,0x200000,0x41001f0b,0x7c00100,0x230400,0x41002800,
+0x24000000,0x200000,0x41002800,0x24000000,0x400000,0x41002919,0x7c00100,0x22040e,0x41002a00,0x4000000,0x1600000,0x41002b01,0x2802020,0x962460,0x41002c00,0x4000000,
+0x200000,0x41002c00,0x7c00120,0x220405,0x41003000,0x24000000,0x200000,0x41003700,0x24000000,0x200000,0x41005d00,0x7c00120,0x220405,0x41006600,0x24000020,0x200000,
+0x41006600,0x24000020,0x810000,0x41006600,0x24000020,0x1410000,0x41007208,0x7c00100,0x22040f,0x41007219,0x7c00100,0x220400,0x41007300,0x24000000,0x200000,0x41007e0e,
+0x2802000,0x962460,0x41007e0e,0x4000000,0x200000,0x41007f0e,0x4000000,0x200000,0x41007f0e,0x7c00100,0x230400,0x41008002,0x7c00100,0x230400,0x41008137,0x2802100,
+0x962460,0x41008137,0x4000000,0x200000,0x41008137,0x6800100,0x962540,0x41008137,0x7c00100,0x230400,0x41008301,0x2802000,0x962460,0x41008407,0x4000000,0x200000,
+0x41008407,0x4000000,0x400000,0x41008407,0x4000000,0xb00000,0x41008407,0x7c00100,0x220400,0x41008407,0x7c00100,0x250400,0x4100850b,0x7c00100,0x230400,0x4100860b,
+0x4000000,0x200000,0x4100860b,0x7c00100,0x230400,0x4100870c,0x7c00100,0x220400,0x41008838,0x7c00100,0x220400,0x41008838,0x7c00100,0x250400,0x41008939,0x2802000,
+0x962460,0x41008939,0x2802100,0x962460,0x41008939,0x2806000,0x962460,0x41008939,0x4000000,0x200000,0x41008939,0x4000000,0x400000,0x41008939,0x7c00100,0x230400,
+0x41008939,0xc000000,0x448000,0x41008a00,0x4000000,0x200000,0x41008b3b,0x4000000,0x1800000,0x41008b3b,0x6800000,0x1329800,0x41008b3b,0x6800100,0x1862540,0x41008b3b,
+0x7c00100,0x1830000,0x41008c3d,0x4000010,0x400000,0x41008c3d,0x7c00100,0x230400,0x41008d0e,0x7c00100,0x22040f,0x41008d19,0x7c00100,0x220400,0x41008d19,0x7c00100,
+0x22040f,0x41008e00,0x24000000,0x200000,0x41008e00,0x24000000,0x400000,0x41008e00,0x24000000,0x1710000,0x41008e00,0x24000006,0x400000,0x41008f3a,0x2802000,0x962460,
+0x41008f3a,0x2802100,0x962460,0x41008f3a,0x2806000,0x962460,0x41008f3a,0x4000000,0x200000,0x41008f3a,0x6800100,0x962540,0x41008f3a,0x7c00100,0x230400,0x4100903c,
+0x7c00100,0x230400,0x4100903c,0x7c00100,0x23040f,0x41020701,0x2802000,0x962460,0x41020701,0x2802000,0xc62460,0x410a4412,0x4000000,0xe00003,0x410a4711,0x7c40300,
+0xe30000,0x410a4f11,0x7c00300,0xe30001,0x410a9100,0x4000000,0x800010,0x410a9100,0x4000000,0x810010,0x410a9100,0x4000000,0x870010,0x410a9100,0x4000000,0xb00010,
+0x410a9100,0x4000000,0xf00010,0x410a9100,0x4000000,0x1001410,0x410a9100,0x4000000,0x1071010,0x410a9100,0x4000000,0x1071410,0x410a9100,0x4000000,0x1410010,0x414a821c,
+0x4000000,0xe00000,0x50000419,0x7c00100,0x220400,0x50000419,0x7c00100,0x250400,0x5000080e,0x7c00100,0x220400,0x50000908,0x7c00100,0x220400,0x50000908,0x7c00100,
+0x250400,0x50000b13,0x2802500,0x962460,0x50000f0a,0x7c00100,0x230400,0x50001615,0x2802100,0x962460,0x50001615,0x7c00100,0x230400,0x50002b01,0x2802020,0x962460,
+0x50002c00,0x4000000,0x200000,0x50002c19,0x7c00100,0x220400,0x50002d19,0x7c00100,0x220400,0x50003000,0x24000000,0x200000,0x50003000,0x24000020,0x200000,0x50003700,
+0x24000000,0x200000,0x50005d00,0x7c00120,0x220405,0x50005d00,0x7c00120,0x250405,0x50006108,0x7c00100,0x220400,0x50006108,0x7c00100,0x250400,0x50006600,0x24000020,
+0x200000,0x50007300,0x24000000,0x200000,0x50008301,0x2802400,0x962460,0x50008a00,0x7c00500,0x230400,0x50009257,0x2802400,0x962460,0x50009257,0x4000000,0x200000,
+0x50009257,0x4000010,0x1071400,0x50009257,0x6800000,0x1329800,0x50009257,0x7c00100,0x230400,0x50009257,0x7c00500,0x230400,0x50009257,0x7c00900,0x230400,0x50009257,
+0xc000010,0xb48000,0x5000933e,0x2802100,0x962460,0x5000933e,0x2802400,0x962460,0x5000933e,0x4000000,0x200000,0x5000933e,0x4000000,0x400000,0x5000933e,0x4000010,
+0x400000,0x5000933e,0x6800000,0x1329800,0x5000933e,0x6800100,0x962540,0x5000933e,0x6800100,0x962541,0x5000933e,0x6804400,0x962540,0x5000933e,0x7c00100,0x230400,
+0x5000933e,0x7c00100,0x230401,0x5000933e,0xc000010,0x448000,0x50009419,0x7c00100,0x220400,0x50009419,0x7c00100,0x250400,0x50009500,0x4000400,0x200000,0x5000965a,
+0x4000000,0x500000,0x5000965a,0x7c00100,0x230400,0x5000965a,0xc000010,0xb48000,0x5000975b,0x4000000,0x200000,0x5000975b,0x4000010,0x400000,0x5000975b,0x7c00100,
+0x230400,0x50009865,0x7c00100,0x230400,0x50009965,0x4000010,0x400000,0x50009965,0x7c00100,0x230400,0x50009a00,0x4000000,0x200000,0x5100080e,0x7c00100,0x220400,
+0x5100080e,0x7c00100,0x250400,0x51000908,0x2802400,0x962460,0x51000c02,0x2802100,0x962460,0x51000c02,0x4000000,0x1500000,0x51000c02,0x4000020,0x200000,0x51000c02,
+0x7c00100,0x230400,0x51000f0a,0x7c00100,0x230400,0x51000f0a,0x7c00500,0x230400,0x51001110,0x2802100,0x962460,0x5100131f,0x2802100,0x962460,0x51001423,0x7c00100,
+0x230400,0x51001524,0x2802100,0x962460,0x51001524,0x4000000,0x200000,0x51001524,0x7c00100,0x230400,0x5100171a,0x2802100,0x962460,0x5100171a,0x4000000,0x200000,
+0x5100171a,0x4000000,0x1500000,0x5100171a,0x7c00100,0x230400,0x51001b27,0x4000000,0x200000,0x51001b27,0x4000000,0x400000,0x51001b27,0x4000000,0x500000,0x51001b27,
+0x7c00100,0x230400,0x51001c1c,0x2802100,0x1862460,0x51001c1c,0x2802400,0x1862460,0x51001c1c,0x2806400,0x1862460,0x51001c1c,0x4000000,0x1800000,0x51001c1c,0x6800000,
+0x1329800,0x51001c1c,0x6800000,0x1862540,0x51001c1c,0x6800100,0x1862540,0x51001c1c,0x6800400,0x1862540,0x51001c1c,0x7c00100,0x1830000,0x5100251b,0x7c00100,0x230400,
+0x51002619,0x7c00100,0x220400,0x51002619,0x7c00100,0x250400,0x51002800,0x80020,0x218820,0x51002b01,0x2802000,0x962460,0x51002c00,0x4000000,0x200000,0x51002d19,
+0x7c00100,0x230400,0x51003700,0x24000000,0x200000,0x51005201,0x2802400,0x962460,0x51005c00,0x4000000,0x200000,0x51006108,0x7c00100,0x220400,0x51006108,0x7c00100,
+0x250400,0x51006600,0x24000020,0x200000,0x51006600,0x24000020,0x810000,0x51006600,0x24000020,0x1410000,0x51007300,0x24000000,0x200000,0x51007300,0x24000020,0x200000,
+0x51008002,0x7c00100,0x230400,0x51008301,0x2802000,0x962460,0x51008301,0x2802400,0x962460,0x51008a00,0x7c00500,0x230400,0x51008e00,0x24000000,0x200000,0x51008e00,
+0x24000000,0x400000,0x51008e00,0x24000000,0x810000,0x51008e00,0x24000000,0x1400000,0x51008e00,0x24000000,0x1410000,0x51008e00,0x24000000,0x1710000,0x51008e00,0x24000002,
+0x200000,0x51008e00,0x24000500,0x230400,0x51008e00,0x2c000010,0xb48000,0x51009419,0x7c00100,0x220400,0x51009419,0x7c00100,0x22040e,0x51009419,0x7c00100,0x22040f,
+0x51009419,0x7c00100,0x250400,0x51009500,0x4000000,0x200000,0x51009500,0x7c00500,0x230400,0x51009519,0x7c00100,0x220400,0x51009519,0x7c00100,0x22040f,0x51009519,
+0x7c00100,0x230400,0x51009519,0x7c00100,0x250400,0x51009b71,0x2802100,0x962460,0x51009b71,0x6800000,0x1329800,0x51009b71,0x6800100,0x962540,0x51009b71,0x6804400,
+0x962540,0x51009b71,0x7c00100,0x230400,0x51009c52,0x2802100,0x962460,0x51009c52,0x2802400,0x962460,0x51009c52,0x2802c00,0x962460,0x51009c52,0x4000010,0x400000,
+0x51009c52,0x6800000,0x1329800,0x51009c52,0x6800100,0x962540,0x51009c52,0x7c00100,0x230400,0x51009c52,0xc000010,0x448000,0x51009d6d,0x6800000,0x1329800,0x51009d6d,
+0x7c00100,0x230400,0x51009d6d,0x7c00500,0x230400,0x51009d6d,0x7c00d00,0x230400,0x51009d6d,0xc000010,0x448000,0x51009e08,0x2802100,0x962460,0x51009f63,0x4000010,
+0x400000,0x51009f63,0x6800000,0x1329800,0x51009f63,0x7c00100,0x230400,0x51009f63,0x7c00900,0x230400,0x51009f63,0xc000010,0x448000,0x51009f63,0xc000010,0xb48000,
+0x5100a008,0x2000,0x962460,0x5100a008,0x2802400,0x962460,0x5100a008,0x4000000,0x200000,0x5100a008,0x7c00100,0x220400,0x5100a008,0x7c00100,0x230400,0x5100a008,
+0x7c00100,0x250400,0x5100a008,0x7c00500,0x230400,0x5100a16f,0x2806400,0x962460,0x5100a16f,0x6800000,0x1329800,0x5100a16f,0x6800100,0x962540,0x5100a16f,0x7c00100,
+0x230400,0x5100a16f,0xc000010,0x448000,0x5100a24f,0x2802100,0x962460,0x5100a24f,0x2802400,0x962460,0x5100a24f,0x4000400,0x400000,0x5100a24f,0x6800000,0x1329800,
+0x5100a24f,0x7c00100,0x230400,0x5100a24f,0xc000010,0x448000,0x5100a36e,0x2802100,0x962460,0x5100a36e,0x4000000,0x200000,0x5100a36e,0x6800100,0x962540,0x5100a36e,
+0x6804400,0x962540,0x5100a36e,0x7c00100,0x230400,0x5100a442,0x2802100,0x962460,0x5100a442,0x4000000,0x200000,0x5100a442,0x6800000,0x1329800,0x5100a442,0x6800100,
+0x962540,0x5100a442,0x7c00100,0x230400,0x5100a442,0xc000010,0x448000,0x5100a500,0x4000000,0x200000,0x5100a600,0x4000000,0x200000,0x5100a601,0x2802000,0x962460,
+0x5100a76b,0x7c00100,0x230400,0x5100a868,0x7c00100,0x230400,0x5100a96c,0x4000000,0x200000,0x5100a96c,0x7c00100,0x230400,0x5100aa00,0x4000000,0x200000,0x5100ab00,
+0x4000000,0x200000,0x51086600,0x24000020,0x810000,0x51086600,0x24000020,0x1410000,0x510a4005,0x7c00100,0xe30400,0x510a4711,0x7c40300,0xe30000,0x514a821c,0x4000000,
+0xe00000,0x52000f0a,0x2802100,0x962460,0x52000f0a,0x6800100,0x962540,0x52000f0a,0x7c00100,0x230400,0x52001004,0x4000000,0x1600000,0x52001b00,0x4000000,0x200000,
+0x52001c1c,0x2802100,0x1862460,0x52001c1c,0x6800100,0x1862540,0x52001c1c,0x6800400,0x1862540,0x52002128,0x4000002,0x400000,0x52002128,0x7c00100,0x230400,0x52002a00,
+0x4000000,0x1500000,0x52002a00,0x4000000,0x1600000,0x52002d00,0x4000000,0x200006,0x52003000,0x24000000,0x200000,0x52003700,0x24000000,0x200000,0x52006108,0x7c00100,
+0x220400,0x52006108,0x7c00100,0x250400,0x52008301,0x2802400,0x962460,0x52008407,0x2802400,0x962460,0x52008407,0x7c00100,0x220400,0x52008407,0x7c00100,0x250400,
+0x52008b3b,0x6800000,0x1800000,0x52008b3b,0x7c00100,0x1830000,0x52008e00,0x24000000,0x400000,0x52009419,0x7c00100,0x250400,0x5200975b,0x4000000,0x200000,0x5200ac7e,
+0x2802000,0x962460,0x5200ac7e,0x2802100,0x962460,0x5200ac7e,0x2802400,0x962460,0x5200ac7e,0x4000010,0x200000,0x5200ac7e,0x7c00100,0x230400,0x5200ad28,0x7c00100,
+0x230400,0x5200ae6a,0x2802100,0x1862460,0x5200ae6a,0x2802400,0x962460,0x5200ae6a,0x2802400,0x1862460,0x5200ae6a,0x2806000,0x1862460,0x5200ae6a,0x4000000,0x1800000,
+0x5200ae6a,0x6800000,0x1329800,0x5200ae6a,0x6800100,0x1862540,0x5200ae6a,0x7c00100,0x1830000,0x5200ae6a,0x7c00900,0x1830000,0x5200ae6a,0xc000010,0x1848000,0x5200af00,
+0x4000400,0x200000,0x5200af00,0x6800100,0x962540,0x5200af00,0x6800400,0x962540,0x5200af00,0x7c00100,0x230400,0x5200af01,0x2802400,0x962460,0x5200b083,0x4000010,
+0x400000,0x5200b083,0x7c00100,0x230400,0x5200b083,0xc000010,0x448000,0x5200b182,0x2802400,0x962460,0x5200b182,0x4000000,0x200000,0x5200b182,0x4000010,0x400000,
+0x5200b182,0x7c00100,0x230400,0x5200b182,0xc000010,0x448000,0x5200b200,0x4000000,0x200000,0x5200b200,0x4000000,0x1500000,0x5200b30a,0x2802400,0x962460,0x5200b30a,
+0x4000000,0x200000,0x5200b30a,0x7c00100,0x230400,0x5200b54e,0x2802100,0x962460,0x5200b54e,0x2802400,0x962460,0x5200b54e,0x4000000,0x200000,0x5200b54e,0x4000010,
+0x400000,0x5200b54e,0x6800000,0x1329800,0x5200b54e,0x6800100,0x962540,0x5200b54e,0x6804400,0x962540,0x5200b54e,0x7c00100,0x230400,0x5200b54e,0x7c00900,0x230400,
+0x5200b54e,0xc000010,0x448000,0x5200b61c,0x4000000,0x1800000,0x5200b61c,0x6800400,0x1862540,0x5200b61c,0x7c00100,0x1830000,0x5200b61c,0x7c00900,0x1830000,0x5200b77f,
+0x2802100,0x1862460,0x5200b77f,0x2802400,0x1862460,0x5200b77f,0x4000000,0x1800000,0x5200b77f,0x4000010,0x1800000,0x5200b77f,0x7c00100,0x1830000,0x5200b77f,0x7c00500,
+0x1830000,0x5200b77f,0x7c00900,0x1830000,0x5200b77f,0x7e00100,0x1830160,0x5200b873,0x2802100,0x962460,0x5200b873,0x2806400,0x962460,0x5200b873,0x6800000,0x1329800,
+0x5200b873,0x6800100,0x962540,0x5200b873,0x6800400,0x962540,0x5200b873,0x7c00100,0x230400,0x5200b873,0xc000010,0x448000,0x5200ba74,0x4000000,0x200000,0x5200ba74,
+0x4000010,0x400000,0x5200ba74,0x7c00100,0x230400,0x5200bb85,0x4000000,0x200000,0x5200bb85,0x7c00100,0x230400,0x5200bc75,0x4000000,0x400000,0x5200bc75,0x4000010,
+0x400000,0x5200bc75,0x7c00100,0x230400,0x5200bd7d,0x4000000,0x200000,0x5200bd7d,0x7c00100,0x230400,0x5200be7a,0x4000000,0x200000,0x5200be7a,0x7c00100,0x230400,
+0x5200bf58,0x7c00100,0x230400,0x5200c002,0x4000000,0x200000,0x5200c178,0,0x218820,0x5200c178,0x2802000,0x962460,0x5200c178,0x2802100,0x962460,0x5200c178,
+0x2802400,0x962460,0x5200c178,0x2806400,0x962460,0x5200c178,0x4000000,0x200000,0x5200c178,0x6800100,0x962540,0x5200c178,0x7c00100,0x230400,0x5200c178,0x7c00100,
+0x230401,0x5200c178,0xc000010,0x448000,0x5200c247,0x7c00100,0x230400,0x5200c247,0x7c00100,0x830400,0x5200c247,0x7c00100,0x1430400,0x5200c300,0x4000000,0x200003,
+0x52022d00,0x4000000,0x100006,0x52023700,0x24000000,0x100000,0x52023800,0x24000000,0x100000,0x52024400,0x4000000,0x100000,0x52027300,0x24000000,0x100000,0x5202c300,
+0x4000000,0x100000,0x5202c300,0x4000000,0x100002,0x5202c300,0x4000000,0x100003,0x5202c300,0x4000000,0x10000d,0x520a1e12,0x7c00100,0x2130480,0x520a1e12,0x7c00100,
+0x2230500,0x520a1e12,0x7c00100,0x2330520,0x520a4400,0x4000000,0xe00003,0x520a4711,0x7c40300,0xe30000,0x520a4f11,0x7c00300,0xe30001,0x520ab412,0x7c00100,0x2130480,
+0x520ab912,0x7c00100,0x2230500,0x520ab912,0x7c00100,0x2330520,0x520ac400,0x4000000,0xe00002,0x520ac400,0x4000000,0xe0000d,0x520ac414,0x4000000,0xe0000d,0x520ac511,
+0x7c40300,0xe30000,0x60000c01,0x2802100,0x962460,0x60000c02,0x7c00100,0x230400,0x60000f0a,0x2802100,0x962460,0x60000f0a,0x6800100,0x962540,0x60000f0a,0x7c00100,
+0x230400,0x6000131f,0x4000000,0x200000,0x6000171a,0x7c00100,0x230400,0x60001b27,0x2802100,0x962460,0x60001b27,0x4000000,0xc00000,0x60001b27,0x7c00100,0x230400,
+0x60001f0b,0x2802000,0x962460,0x60002919,0x7c00100,0x23040e,0x60002a00,0x4000000,0x1600000,0x60003000,0x24000000,0x200000,0x60003700,0x24000000,0x200000,0x60003800,
+0x24000000,0x200000,0x60005102,0x4000000,0x200000,0x60006108,0x7c00100,0x220400,0x60006108,0x7c00100,0x250400,0x60006600,0x24000020,0x200000,0x60008301,0x2802000,
+0x962460,0x6000903c,0x2806000,0x962460,0x6000903c,0x4000000,0x400000,0x60009519,0x7c00100,0x220400,0x60009519,0x7c00100,0x250400,0x6000a008,0x7c00100,0x220400,
+0x6000a008,0x7c00100,0x250400,0x6000c300,0x4000000,0x200000,0x6000c654,0x2802000,0x962460,0x6000c654,0x4000010,0x200000,0x6000c654,0x7c00100,0x230400,0x6000c73f,
+0x2802000,0x962460,0x6000c73f,0x2802100,0x962460,0x6000c73f,0x4000000,0x200000,0x6000c73f,0x6800100,0x962540,0x6000c73f,0x6804000,0x962540,0x6000c73f,0x7c00100,
+0x230400,0x6000c80b,0x7c00100,0x230400,0x6000c941,0x2802100,0x962460,0x6000c941,0x2806000,0x962460,0x6000c941,0x4000000,0x200000,0x6000c941,0x4000010,0x200000,
+0x6000c941,0x6800000,0x1329800,0x6000c941,0x6800100,0x962540,0x6000c941,0x7c00100,0x230400,0x6000c941,0xc000010,0x448000,0x6000ca82,0x7c00100,0x230400,0x6000cc00,
+0x4000000,0x200000,0x6000cd00,0x4000000,0x200000,0x6000ce00,0x4000000,0x200000,0x6000cf00,0x4000000,0x200000,0x6000d000,0x4000000,0x200000,0x6002c300,0x4000000,
+0x100000,0x6002c300,0x4000000,0x10000d,0x600a4305,0x7c00100,0xe30400,0x600ac400,0x4000000,0xe00003,0x600ac400,0x4000000,0xe0000d,0x600acb14,0x7c00100,0xe30000,
+0x600acb16,0x7c00100,0xe30c00,0x600ad111,0x7c40300,0xe30000};
+
+static const int32_t countPropsVectors=4614;
+static const int32_t propsVectorsColumns=3;
+static const uint16_t scriptExtensions[40]={
+2,0x8022,2,0x8025,2,2,3,0x800c,5,0x8011,0x14,0x8016,0x1b,0x805a,2,0x22,
+0x8025,0x11,0x14,0x8016,4,0xa,0x10,0x801f,0x2a,0x2b,0x2c,0x802d,5,0x11,0x12,0x14,
+0x8016,5,0x11,0x12,0x14,0x16,0x8029,0};
+
+static const int32_t indexes[UPROPS_INDEX_COUNT]={0x21ae,0x21ae,0x21ae,0x21ae,0x4d66,3,0x5f6c,0x5f80,0x5f80,0x5f80,0xad192,0x2473171,0,0,0,0};
+
diff --git a/source/common/uchriter.cpp b/source/common/uchriter.cpp
new file mode 100644
index 0000000..f287881
--- /dev/null
+++ b/source/common/uchriter.cpp
@@ -0,0 +1,364 @@
+/*
+******************************************************************************
+* Copyright (C) 1998-2010, International Business Machines Corporation and
+* others. All Rights Reserved.
+******************************************************************************
+*/
+
+#include <typeinfo>  // for 'typeid' to work
+
+#include "unicode/uchriter.h"
+#include "unicode/ustring.h"
+#include "uhash.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UCharCharacterIterator)
+
+UCharCharacterIterator::UCharCharacterIterator()
+  : CharacterIterator(),
+  text(0)
+{
+    // never default construct!
+}
+
+UCharCharacterIterator::UCharCharacterIterator(const UChar* textPtr,
+                                               int32_t length)
+  : CharacterIterator(textPtr != 0 ? (length>=0 ? length : u_strlen(textPtr)) : 0),
+  text(textPtr)
+{
+}
+
+UCharCharacterIterator::UCharCharacterIterator(const UChar* textPtr,
+                                               int32_t length,
+                                               int32_t position)
+  : CharacterIterator(textPtr != 0 ? (length>=0 ? length : u_strlen(textPtr)) : 0, position),
+  text(textPtr)
+{
+}
+
+UCharCharacterIterator::UCharCharacterIterator(const UChar* textPtr,
+                                               int32_t length,
+                                               int32_t textBegin,
+                                               int32_t textEnd,
+                                               int32_t position)
+  : CharacterIterator(textPtr != 0 ? (length>=0 ? length : u_strlen(textPtr)) : 0, textBegin, textEnd, position),
+  text(textPtr)
+{
+}
+
+UCharCharacterIterator::UCharCharacterIterator(const UCharCharacterIterator& that)
+: CharacterIterator(that),
+  text(that.text)
+{
+}
+
+UCharCharacterIterator&
+UCharCharacterIterator::operator=(const UCharCharacterIterator& that) {
+    CharacterIterator::operator=(that);
+    text = that.text;
+    return *this;
+}
+
+UCharCharacterIterator::~UCharCharacterIterator() {
+}
+
+UBool
+UCharCharacterIterator::operator==(const ForwardCharacterIterator& that) const {
+    if (this == &that) {
+        return TRUE;
+    }
+    if (typeid(*this) != typeid(that)) {
+        return FALSE;
+    }
+
+    UCharCharacterIterator&    realThat = (UCharCharacterIterator&)that;
+
+    return text == realThat.text
+        && textLength == realThat.textLength
+        && pos == realThat.pos
+        && begin == realThat.begin
+        && end == realThat.end;
+}
+
+int32_t
+UCharCharacterIterator::hashCode() const {
+    return uhash_hashUCharsN(text, textLength) ^ pos ^ begin ^ end;
+}
+
+CharacterIterator*
+UCharCharacterIterator::clone() const {
+    return new UCharCharacterIterator(*this);
+}
+
+UChar
+UCharCharacterIterator::first() {
+    pos = begin;
+    if(pos < end) {
+        return text[pos];
+    } else {
+        return DONE;
+    }
+}
+
+UChar
+UCharCharacterIterator::firstPostInc() {
+    pos = begin;
+    if(pos < end) {
+        return text[pos++];
+    } else {
+        return DONE;
+    }
+}
+
+UChar
+UCharCharacterIterator::last() {
+    pos = end;
+    if(pos > begin) {
+        return text[--pos];
+    } else {
+        return DONE;
+    }
+}
+
+UChar
+UCharCharacterIterator::setIndex(int32_t position) {
+    if(position < begin) {
+        pos = begin;
+    } else if(position > end) {
+        pos = end;
+    } else {
+        pos = position;
+    }
+    if(pos < end) {
+        return text[pos];
+    } else {
+        return DONE;
+    }
+}
+
+UChar
+UCharCharacterIterator::current() const {
+    if (pos >= begin && pos < end) {
+        return text[pos];
+    } else {
+        return DONE;
+    }
+}
+
+UChar
+UCharCharacterIterator::next() {
+    if (pos + 1 < end) {
+        return text[++pos];
+    } else {
+        /* make current() return DONE */
+        pos = end;
+        return DONE;
+    }
+}
+
+UChar
+UCharCharacterIterator::nextPostInc() {
+    if (pos < end) {
+        return text[pos++];
+    } else {
+        return DONE;
+    }
+}
+
+UBool
+UCharCharacterIterator::hasNext() {
+    return (UBool)(pos < end ? TRUE : FALSE);
+}
+
+UChar
+UCharCharacterIterator::previous() {
+    if (pos > begin) {
+        return text[--pos];
+    } else {
+        return DONE;
+    }
+}
+
+UBool
+UCharCharacterIterator::hasPrevious() {
+    return (UBool)(pos > begin ? TRUE : FALSE);
+}
+
+UChar32
+UCharCharacterIterator::first32() {
+    pos = begin;
+    if(pos < end) {
+        int32_t i = pos;
+        UChar32 c;
+        UTF_NEXT_CHAR(text, i, end, c);
+        return c;
+    } else {
+        return DONE;
+    }
+}
+
+UChar32
+UCharCharacterIterator::first32PostInc() {
+    pos = begin;
+    if(pos < end) {
+        UChar32 c;
+        UTF_NEXT_CHAR(text, pos, end, c);
+        return c;
+    } else {
+        return DONE;
+    }
+}
+
+UChar32
+UCharCharacterIterator::last32() {
+    pos = end;
+    if(pos > begin) {
+        UChar32 c;
+        UTF_PREV_CHAR(text, begin, pos, c);
+        return c;
+    } else {
+        return DONE;
+    }
+}
+
+UChar32
+UCharCharacterIterator::setIndex32(int32_t position) {
+    if(position < begin) {
+        position = begin;
+    } else if(position > end) {
+        position = end;
+    }
+    if(position < end) {
+        UTF_SET_CHAR_START(text, begin, position);
+        int32_t i = this->pos = position;
+        UChar32 c;
+        UTF_NEXT_CHAR(text, i, end, c);
+        return c;
+    } else {
+        this->pos = position;
+        return DONE;
+    }
+}
+
+UChar32
+UCharCharacterIterator::current32() const {
+    if (pos >= begin && pos < end) {
+        UChar32 c;
+        UTF_GET_CHAR(text, begin, pos, end, c);
+        return c;
+    } else {
+        return DONE;
+    }
+}
+
+UChar32
+UCharCharacterIterator::next32() {
+    if (pos < end) {
+        UTF_FWD_1(text, pos, end);
+        if(pos < end) {
+            int32_t i = pos;
+            UChar32 c;
+            UTF_NEXT_CHAR(text, i, end, c);
+            return c;
+        }
+    }
+    /* make current() return DONE */
+    pos = end;
+    return DONE;
+}
+
+UChar32
+UCharCharacterIterator::next32PostInc() {
+    if (pos < end) {
+        UChar32 c;
+        UTF_NEXT_CHAR(text, pos, end, c);
+        return c;
+    } else {
+        return DONE;
+    }
+}
+
+UChar32
+UCharCharacterIterator::previous32() {
+    if (pos > begin) {
+        UChar32 c;
+        UTF_PREV_CHAR(text, begin, pos, c);
+        return c;
+    } else {
+        return DONE;
+    }
+}
+
+int32_t
+UCharCharacterIterator::move(int32_t delta, CharacterIterator::EOrigin origin) {
+    switch(origin) {
+    case kStart:
+        pos = begin + delta;
+        break;
+    case kCurrent:
+        pos += delta;
+        break;
+    case kEnd:
+        pos = end + delta;
+        break;
+    default:
+        break;
+    }
+
+    if(pos < begin) {
+        pos = begin;
+    } else if(pos > end) {
+        pos = end;
+    }
+
+    return pos;
+}
+
+int32_t
+UCharCharacterIterator::move32(int32_t delta, CharacterIterator::EOrigin origin) {
+    // this implementation relies on the "safe" version of the UTF macros
+    // (or the trustworthiness of the caller)
+    switch(origin) {
+    case kStart:
+        pos = begin;
+        if(delta > 0) {
+            UTF_FWD_N(text, pos, end, delta);
+        }
+        break;
+    case kCurrent:
+        if(delta > 0) {
+            UTF_FWD_N(text, pos, end, delta);
+        } else {
+            UTF_BACK_N(text, begin, pos, -delta);
+        }
+        break;
+    case kEnd:
+        pos = end;
+        if(delta < 0) {
+            UTF_BACK_N(text, begin, pos, -delta);
+        }
+        break;
+    default:
+        break;
+    }
+
+    return pos;
+}
+
+void UCharCharacterIterator::setText(const UChar* newText,
+                                     int32_t      newTextLength) {
+    text = newText;
+    if(newText == 0 || newTextLength < 0) {
+        newTextLength = 0;
+    }
+    end = textLength = newTextLength;
+    pos = begin = 0;
+}
+
+void
+UCharCharacterIterator::getText(UnicodeString& result) {
+    result = UnicodeString(text, textLength);
+}
+
+U_NAMESPACE_END
diff --git a/source/common/ucln.h b/source/common/ucln.h
new file mode 100644
index 0000000..3f9847f
--- /dev/null
+++ b/source/common/ucln.h
@@ -0,0 +1,89 @@
+/*
+******************************************************************************
+*                                                                            *
+* Copyright (C) 2001-2010, 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_H__
+#define __UCLN_H__
+
+#include "unicode/utypes.h"
+
+/** These are the functions used to register a library's memory cleanup
+ * functions.  Each library should define a single library register function
+ * to call this API.  In the i18n library, it is ucln_i18n_registerCleanup().
+ *
+ * None of the cleanup functions should use a mutex to clean up an API's
+ * allocated memory because a cleanup function is not meant to be thread safe,
+ * and plenty of data cannot be reference counted in order to make sure that
+ * no one else needs the allocated data.
+ *
+ * In order to make a cleanup function get called when u_cleanup is called,
+ * You should add your function to the library specific cleanup function.
+ * If the cleanup function is not in the common library, the code that
+ * allocates the memory should call the library specific cleanup function.
+ * For instance, in the i18n library, any memory allocated statically must
+ * call ucln_i18n_registerCleanup() from the ucln_in.h header.  These library
+ * cleanup functions are needed in order to prevent a circular dependency
+ * between the common library and any other library.
+ *
+ * The order of the cleanup is very important.  In general, an API that
+ * depends on a second API should be cleaned up before the second API.
+ * For instance, the default converter in ustring depends upon the converter
+ * API.  So the default converter should be closed before the converter API
+ * has its cache flushed.  This will prevent any memory leaks due to
+ * reference counting.
+ *
+ * Please see common/ucln_cmn.{h,c} and i18n/ucln_in.{h,c} for examples.
+ */
+
+/**
+ * Data Type for cleanup function selector. These roughly correspond to libraries.
+ */
+typedef enum ECleanupLibraryType {
+    UCLN_START = -1,
+    UCLN_UPLUG,     /* ICU plugins */
+    UCLN_CUSTOM,    /* Custom is for anyone else. */
+    UCLN_CTESTFW,
+    UCLN_TOOLUTIL,
+    UCLN_LAYOUTEX,
+    UCLN_LAYOUT,
+    UCLN_IO,
+    UCLN_I18N,
+    UCLN_COMMON /* This must be the last one to cleanup. */
+} ECleanupLibraryType;
+
+/**
+ * Data type for cleanup function pointer
+ */
+U_CDECL_BEGIN
+typedef UBool U_CALLCONV cleanupFunc(void);
+U_CDECL_END
+
+/**
+ * Register a cleanup function
+ * @param type which library to register for.
+ * @param func the function pointer
+ */
+U_CAPI void U_EXPORT2 ucln_registerCleanup(ECleanupLibraryType type,
+                                           cleanupFunc *func);
+
+/**
+ * Request cleanup for one specific library.
+ * Not thread safe.
+ * Calling this with UCLN_COMMON just calls u_cleanup();
+ * @param type which library to cleanup
+ */
+U_CAPI void U_EXPORT2 ucln_cleanupOne(ECleanupLibraryType type);
+
+#endif
diff --git a/source/common/ucln_cmn.c b/source/common/ucln_cmn.c
new file mode 100644
index 0000000..498c15e
--- /dev/null
+++ b/source/common/ucln_cmn.c
@@ -0,0 +1,112 @@
+/*
+******************************************************************************
+* Copyright (C) 2001-2010, International Business Machines
+*                Corporation and others. All Rights Reserved.
+******************************************************************************
+*   file name:  ucln_cmn.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2001July05
+*   created by: George Rhoten
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uclean.h"
+#include "utracimp.h"
+#include "ustr_imp.h"
+#include "ucln_cmn.h"
+#include "umutex.h"
+#include "ucln.h"
+#include "cmemory.h"
+#include "uassert.h"
+
+/**  Auto-client for UCLN_COMMON **/
+#define UCLN_TYPE UCLN_COMMON
+#include "ucln_imp.h"
+
+static cleanupFunc *gCommonCleanupFunctions[UCLN_COMMON_COUNT];
+static cleanupFunc *gLibCleanupFunctions[UCLN_COMMON];
+
+
+/* Enables debugging information about when a library is cleaned up. */
+#ifndef UCLN_DEBUG_CLEANUP
+#define UCLN_DEBUG_CLEANUP 0
+#endif
+
+
+#if defined(UCLN_DEBUG_CLEANUP)
+#include <stdio.h>
+#endif
+
+static void ucln_cleanup_internal(ECleanupLibraryType libType) 
+{
+    if (gLibCleanupFunctions[libType])
+    {
+        gLibCleanupFunctions[libType]();
+        gLibCleanupFunctions[libType] = NULL;
+    }
+}
+
+U_CAPI void U_EXPORT2 ucln_cleanupOne(ECleanupLibraryType libType)
+{
+    if(libType==UCLN_COMMON) {
+#if UCLN_DEBUG_CLEANUP
+        fprintf(stderr, "Cleaning up: UCLN_COMMON with u_cleanup, type %d\n", (int)libType);
+#endif
+        u_cleanup();
+    } else {
+#if UCLN_DEBUG_CLEANUP
+        fprintf(stderr, "Cleaning up: using ucln_cleanup_internal, type %d\n", (int)libType);
+#endif
+        ucln_cleanup_internal(libType);
+    }
+}
+
+
+U_CFUNC void
+ucln_common_registerCleanup(ECleanupCommonType type,
+                            cleanupFunc *func)
+{
+    U_ASSERT(UCLN_COMMON_START < type && type < UCLN_COMMON_COUNT);
+    if (UCLN_COMMON_START < type && type < UCLN_COMMON_COUNT)
+    {
+        gCommonCleanupFunctions[type] = func;
+    }
+#if !UCLN_NO_AUTO_CLEANUP && (defined(UCLN_AUTO_ATEXIT) || defined(UCLN_AUTO_LOCAL))
+    ucln_registerAutomaticCleanup();
+#endif
+}
+
+U_CAPI void U_EXPORT2
+ucln_registerCleanup(ECleanupLibraryType type,
+                     cleanupFunc *func)
+{
+    U_ASSERT(UCLN_START < type && type < UCLN_COMMON);
+    if (UCLN_START < type && type < UCLN_COMMON)
+    {
+        gLibCleanupFunctions[type] = func;
+    }
+}
+
+U_CFUNC UBool ucln_lib_cleanup(void) {
+    ECleanupLibraryType libType = UCLN_START;
+    ECleanupCommonType commonFunc = UCLN_COMMON_START;
+
+    for (libType++; libType<UCLN_COMMON; libType++) {
+        ucln_cleanup_internal(libType);
+    }
+
+    for (commonFunc++; commonFunc<UCLN_COMMON_COUNT; commonFunc++) {
+        if (gCommonCleanupFunctions[commonFunc])
+        {
+            gCommonCleanupFunctions[commonFunc]();
+            gCommonCleanupFunctions[commonFunc] = NULL;
+        }
+    }
+#if !UCLN_NO_AUTO_CLEANUP && (defined(UCLN_AUTO_ATEXIT) || defined(UCLN_AUTO_LOCAL))
+    ucln_unRegisterAutomaticCleanup();
+#endif
+    return TRUE;
+}
diff --git a/source/common/ucln_cmn.h b/source/common/ucln_cmn.h
new file mode 100644
index 0000000..7872232
--- /dev/null
+++ b/source/common/ucln_cmn.h
@@ -0,0 +1,61 @@
+/*
+******************************************************************************
+*                                                                            *
+* Copyright (C) 2001-2010, 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"
+
+/* These are the cleanup functions for various APIs. */
+/* @return true if cleanup complete successfully.*/
+U_CFUNC UBool umtx_cleanup(void);
+
+U_CFUNC UBool utrace_cleanup(void);
+
+U_CFUNC UBool ucln_lib_cleanup(void);
+
+/*
+Please keep the order of enums declared in same order
+as the cleanup functions are suppose to be called. */
+typedef enum ECleanupCommonType {
+    UCLN_COMMON_START = -1,
+    UCLN_COMMON_USPREP,
+    UCLN_COMMON_BREAKITERATOR,
+    UCLN_COMMON_BREAKITERATOR_DICT,
+    UCLN_COMMON_SERVICE,
+    UCLN_COMMON_URES,
+    UCLN_COMMON_LOCALE,
+    UCLN_COMMON_LOCALE_AVAILABLE,
+    UCLN_COMMON_ULOC,
+    UCLN_COMMON_NORMALIZER2,
+    UCLN_COMMON_USET,
+    UCLN_COMMON_UNAMES,
+    UCLN_COMMON_PNAME,
+    UCLN_COMMON_UPROPS,
+    UCLN_COMMON_UCNV,
+    UCLN_COMMON_UCNV_IO,
+    UCLN_COMMON_UDATA,
+    UCLN_COMMON_PUTIL,
+    UCLN_COMMON_COUNT /* This must be last */
+} ECleanupCommonType;
+
+/* Main library cleanup registration function. */
+/* See common/ucln.h for details on adding a cleanup function. */
+U_CFUNC void U_EXPORT2 ucln_common_registerCleanup(ECleanupCommonType type,
+                                                   cleanupFunc *func);
+
+#endif
diff --git a/source/common/ucln_imp.h b/source/common/ucln_imp.h
new file mode 100644
index 0000000..9268729
--- /dev/null
+++ b/source/common/ucln_imp.h
@@ -0,0 +1,171 @@
+/*
+******************************************************************************
+*                                                                            *
+* Copyright (C) 2009, International Business Machines                   *
+*                Corporation and others. All Rights Reserved.                *
+*                                                                            *
+******************************************************************************
+*   file name:  ucln_imp.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   This file contains the platform specific implementation of per-library cleanup.
+*
+*/
+
+
+#ifndef __UCLN_IMP_H__
+#define __UCLN_IMP_H__
+
+#include "ucln.h"
+#include <stdlib.h>
+
+/**
+ * Auto cleanup of ICU libraries
+ * There are several methods in per library cleanup of icu libraries:
+ * 1) Compiler/Platform based cleanup:
+ *   a) Windows MSVC uses DllMain()
+ *   b) GCC uses destructor function attribute
+ *   c) Sun Studio, AIX VA, and HP-UX aCC uses a linker option to set the exit function
+ * 2) Using atexit()
+ * 3) Implementing own automatic cleanup functions
+ *
+ * For option 1, ensure that UCLN_NO_AUTO_CLEANUP is set to 0 by using --enable-auto-cleanup
+ * configure option or by setting UCLN_NO_AUTO_CLEANUP to 0 in pwin32.h (For Visual Studio
+ * solution file builds)
+ * For option 2, follow option 1 and also define UCLN_AUTO_ATEXIT
+ * For option 3, follow option 1 and also define UCLN_AUTO_LOCAL (see below for more information)
+ */
+
+#if !UCLN_NO_AUTO_CLEANUP
+
+/*
+ * The following declarations are for when UCLN_AUTO_LOCAL or UCLN_AUTO_ATEXIT
+ * are defined. They are commented out because they are static and will be defined
+ * later. The information is still here to provide some guidance for the developer
+ * who chooses to use UCLN_AUTO_LOCAL.
+ */
+/**
+ * Give the library an opportunity to register an automatic cleanup.
+ * This may be called more than once.
+ */
+/*static void ucln_registerAutomaticCleanup();*/
+/**
+ * Unregister an automatic cleanup, if possible. Called from cleanup.
+ */
+/*static void ucln_unRegisterAutomaticCleanup();*/
+
+/* ------------ automatic cleanup: registration. Choose ONE ------- */
+#if defined(UCLN_AUTO_LOCAL)
+/* To use:
+ *  1. define UCLN_AUTO_LOCAL,
+ *  2. create ucln_local_hook.c containing implementations of
+ *           static void ucln_registerAutomaticCleanup()
+ *           static void ucln_unRegisterAutomaticCleanup()
+ */
+#include "ucln_local_hook.c"
+
+#elif defined(UCLN_AUTO_ATEXIT)
+/*
+ * Use the ANSI C 'atexit' function. Note that this mechanism does not
+ * guarantee the order of cleanup relative to other users of ICU!
+ */
+static UBool gAutoCleanRegistered = FALSE;
+
+static void ucln_atexit_handler()
+{
+    ucln_cleanupOne(UCLN_TYPE);
+}
+
+static void ucln_registerAutomaticCleanup()
+{
+    if(!gAutoCleanRegistered) {
+        gAutoCleanRegistered = TRUE;
+        atexit(&ucln_atexit_handler);
+    }
+}
+
+static void ucln_unRegisterAutomaticCleanup () {
+}
+/* ------------end of automatic cleanup: registration. ------- */
+
+#elif defined (UCLN_FINI)
+/**
+ * If UCLN_FINI is defined, it is the (versioned, etc) name of a cleanup
+ * entrypoint. Add a stub to call ucln_cleanupOne
+ * Used on AIX, Solaris, and HP-UX
+ */
+U_CAPI void U_EXPORT2 UCLN_FINI (void);
+
+U_CAPI void U_EXPORT2 UCLN_FINI ()
+{
+    /* This function must be defined, if UCLN_FINI is defined, else link error. */
+     ucln_cleanupOne(UCLN_TYPE);
+}
+#elif defined(__GNUC__)
+/* GCC - use __attribute((destructor)) */
+static void ucln_destructor()   __attribute__((destructor)) ;
+
+static void ucln_destructor() 
+{
+    ucln_cleanupOne(UCLN_TYPE);
+}
+
+/* Windows: DllMain */
+#elif defined (U_WINDOWS)
+/* 
+ * ICU's own DllMain.
+ */
+
+/* these are from putil.c */
+/* READ READ READ READ!    Are you getting compilation errors from windows.h?
+          Any source file which includes this (ucln_imp.h) header MUST 
+          be defined with language extensions ON. */
+#   define WIN32_LEAN_AND_MEAN
+#   define VC_EXTRALEAN
+#   define NOUSER
+#   define NOSERVICE
+#   define NOIME
+#   define NOMCX
+#   include <windows.h>
+/*
+ * This is a stub DllMain function with icu specific process handling code.
+ */
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+    BOOL status = TRUE;
+
+    switch(fdwReason) {
+        case DLL_PROCESS_ATTACH:
+             /* ICU does not trap process attach, but must pass these through properly. */
+            /* ICU specific process attach could go here */
+            break;
+
+        case DLL_PROCESS_DETACH:
+            /* Here is the one we actually care about. */
+
+            ucln_cleanupOne(UCLN_TYPE);
+
+            break;
+
+        case DLL_THREAD_ATTACH:
+            /* ICU does not trap thread attach, but must pass these through properly. */
+            /* ICU specific thread attach could go here */
+            break;
+
+        case DLL_THREAD_DETACH:
+            /* ICU does not trap thread detach, but must pass these through properly. */
+            /* ICU specific thread detach could go here */
+            break;
+
+    }
+    return status;
+}
+#endif
+
+#endif /* UCLN_NO_AUTO_CLEANUP */
+
+#else
+#error This file can only be included once.
+#endif
diff --git a/source/common/ucmndata.c b/source/common/ucmndata.c
new file mode 100644
index 0000000..c3a1317
--- /dev/null
+++ b/source/common/ucmndata.c
@@ -0,0 +1,300 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************/
+
+
+/*------------------------------------------------------------------------------
+ *
+ *   UCommonData   An abstract interface for dealing with ICU Common Data Files.
+ *                 ICU Common Data Files are a grouping of a number of individual
+ *                 data items (resources, converters, tables, anything) into a
+ *                 single file or dll.  The combined format includes a table of
+ *                 contents for locating the individual items by name.
+ *
+ *                 Two formats for the table of contents are supported, which is
+ *                 why there is an abstract inteface involved.
+ *
+ */
+
+#include "unicode/utypes.h"
+#include "unicode/udata.h"
+#include "cstring.h"
+#include "ucmndata.h"
+#include "udatamem.h"
+
+#if defined(UDATA_DEBUG) || defined(UDATA_DEBUG_DUMP)
+#   include <stdio.h>
+#endif
+
+U_CFUNC uint16_t
+udata_getHeaderSize(const DataHeader *udh) {
+    if(udh==NULL) {
+        return 0;
+    } else if(udh->info.isBigEndian==U_IS_BIG_ENDIAN) {
+        /* same endianness */
+        return udh->dataHeader.headerSize;
+    } else {
+        /* opposite endianness */
+        uint16_t x=udh->dataHeader.headerSize;
+        return (uint16_t)((x<<8)|(x>>8));
+    }
+}
+
+U_CFUNC uint16_t
+udata_getInfoSize(const UDataInfo *info) {
+    if(info==NULL) {
+        return 0;
+    } else if(info->isBigEndian==U_IS_BIG_ENDIAN) {
+        /* same endianness */
+        return info->size;
+    } else {
+        /* opposite endianness */
+        uint16_t x=info->size;
+        return (uint16_t)((x<<8)|(x>>8));
+    }
+}
+
+/*-----------------------------------------------------------------------------*
+ *                                                                             *
+ *  Pointer TOCs.   TODO: This form of table-of-contents should be removed     *
+ *                  because DLLs must be relocated on loading to correct the   *
+ *                  pointer values and this operation makes shared memory      *
+ *                  mapping of the data much less likely to work.              *
+ *                                                                             *
+ *-----------------------------------------------------------------------------*/
+typedef struct {
+    const char       *entryName;
+    const DataHeader *pHeader;
+} PointerTOCEntry;
+
+
+typedef struct  {
+    uint32_t          count;
+    uint32_t          reserved;
+    PointerTOCEntry   entry[2];   /* Actual size is from count. */
+}  PointerTOC;
+
+
+/* definition of OffsetTOC struct types moved to ucmndata.h */
+
+/*-----------------------------------------------------------------------------*
+ *                                                                             *
+ *    entry point lookup implementations                                       *
+ *                                                                             *
+ *-----------------------------------------------------------------------------*/
+static uint32_t offsetTOCEntryCount(const UDataMemory *pData) {
+    int32_t          retVal=0;
+    const UDataOffsetTOC *toc = (UDataOffsetTOC *)pData->toc;
+    if (toc != NULL) {
+        retVal = toc->count;
+    }
+    return retVal;
+}
+
+
+static const DataHeader *
+offsetTOCLookupFn(const UDataMemory *pData,
+                  const char *tocEntryName,
+                  int32_t *pLength,
+                  UErrorCode *pErrorCode) {
+    const UDataOffsetTOC  *toc = (UDataOffsetTOC *)pData->toc;
+    if(toc!=NULL) {
+        const char *base=(const char *)toc;
+        uint32_t start, limit, number, lastNumber;
+        int32_t strResult;
+        const UDataOffsetTOCEntry *entry;
+
+        /* perform a binary search for the data in the common data's table of contents */
+#if defined (UDATA_DEBUG_DUMP)
+        /* list the contents of the TOC each time .. not recommended */
+        for(start=0;start<toc->count;start++) {
+          fprintf(stderr, "\tx%d: %s\n", start, &base[toc->entry[start].nameOffset]);
+        }
+#endif
+
+        start=0;
+        limit=toc->count;         /* number of names in this table of contents */
+        lastNumber=limit;
+        entry=toc->entry;
+        for (;;) {
+            number = (start+limit)/2;
+            if (lastNumber == number) { /* Have we moved? */
+                break;  /* We haven't moved, and it wasn't found; */
+                        /* or the empty stub common data library was used during build. */
+            }
+            lastNumber = number;
+            strResult = uprv_strcmp(tocEntryName, base+entry[number].nameOffset);
+            if(strResult<0) {
+                limit=number;
+            } else if (strResult>0) {
+                start=number;
+            }
+            else {
+                /* found it */
+#ifdef UDATA_DEBUG
+                fprintf(stderr, "%s: Found.\n", tocEntryName);
+#endif
+                entry += number; /* Alias the entry to the current entry. */
+                if((number+1) < toc->count) {
+                    *pLength = (int32_t)(entry[1].dataOffset - entry->dataOffset);
+                } else {
+                    *pLength = -1;
+                }
+                return (const DataHeader *)(base+entry->dataOffset);
+            }
+        }
+#ifdef UDATA_DEBUG
+        fprintf(stderr, "%s: Not found.\n", tocEntryName);
+#endif
+        return NULL;
+    } else {
+#ifdef UDATA_DEBUG
+        fprintf(stderr, "returning header\n");
+#endif
+
+        return pData->pHeader;
+    }
+}
+
+
+static uint32_t pointerTOCEntryCount(const UDataMemory *pData) {
+    const PointerTOC *toc = (PointerTOC *)pData->toc;
+    return (uint32_t)((toc != NULL) ? (toc->count) : 0);
+}
+
+
+static const DataHeader *pointerTOCLookupFn(const UDataMemory *pData,
+                   const char *name,
+                   int32_t *pLength,
+                   UErrorCode *pErrorCode) {
+    if(pData->toc!=NULL) {
+        const PointerTOC *toc = (PointerTOC *)pData->toc;
+        uint32_t start, limit, number, lastNumber;
+        int32_t strResult;
+
+#if defined (UDATA_DEBUG_DUMP)
+        /* list the contents of the TOC each time .. not recommended */
+        for(start=0;start<toc->count;start++) {
+            fprintf(stderr, "\tx%d: %s\n", start, toc->entry[start].entryName);
+        }
+#endif
+
+        /* perform a binary search for the data in the common data's table of contents */
+        start=0;
+        limit=toc->count;
+        lastNumber=limit;
+
+        for (;;) {
+            number = (start+limit)/2;
+            if (lastNumber == number) { /* Have we moved? */
+                break;  /* We haven't moved, and it wasn't found, */
+                        /* or the empty stub common data library was used during build. */
+            }
+            lastNumber = number;
+            strResult = uprv_strcmp(name, toc->entry[number].entryName);
+            if(strResult<0) {
+                limit=number;
+            } else if (strResult>0) {
+                start=number;
+            }
+            else {
+                /* found it */
+#ifdef UDATA_DEBUG
+                fprintf(stderr, "%s: Found.\n", toc->entry[number].entryName);
+#endif
+                *pLength=-1;
+                return UDataMemory_normalizeDataPointer(toc->entry[number].pHeader);
+            }
+        }
+#ifdef UDATA_DEBUG
+        fprintf(stderr, "%s: Not found.\n", name);
+#endif
+        return NULL;
+    } else {
+        return pData->pHeader;
+    }
+}
+
+static const commonDataFuncs CmnDFuncs = {offsetTOCLookupFn,  offsetTOCEntryCount};
+static const commonDataFuncs ToCPFuncs = {pointerTOCLookupFn, pointerTOCEntryCount};
+
+
+
+/*----------------------------------------------------------------------*
+ *                                                                      *
+ *  checkCommonData   Validate the format of a common data file.        *
+ *                    Fill in the virtual function ptr based on TOC type *
+ *                    If the data is invalid, close the UDataMemory     *
+ *                    and set the appropriate error code.               *
+ *                                                                      *
+ *----------------------------------------------------------------------*/
+U_CFUNC void udata_checkCommonData(UDataMemory *udm, UErrorCode *err) {
+    if (U_FAILURE(*err)) {
+        return;
+    }
+
+    if(!(udm->pHeader->dataHeader.magic1==0xda &&
+        udm->pHeader->dataHeader.magic2==0x27 &&
+        udm->pHeader->info.isBigEndian==U_IS_BIG_ENDIAN &&
+        udm->pHeader->info.charsetFamily==U_CHARSET_FAMILY)
+        ) {
+        /* header not valid */
+        *err=U_INVALID_FORMAT_ERROR;
+    }
+    else if (udm->pHeader->info.dataFormat[0]==0x43 &&
+        udm->pHeader->info.dataFormat[1]==0x6d &&
+        udm->pHeader->info.dataFormat[2]==0x6e &&
+        udm->pHeader->info.dataFormat[3]==0x44 &&
+        udm->pHeader->info.formatVersion[0]==1
+        ) {
+        /* dataFormat="CmnD" */
+        udm->vFuncs = &CmnDFuncs;
+        udm->toc=(const char *)udm->pHeader+udata_getHeaderSize(udm->pHeader);
+    }
+    else if(udm->pHeader->info.dataFormat[0]==0x54 &&
+        udm->pHeader->info.dataFormat[1]==0x6f &&
+        udm->pHeader->info.dataFormat[2]==0x43 &&
+        udm->pHeader->info.dataFormat[3]==0x50 &&
+        udm->pHeader->info.formatVersion[0]==1
+        ) {
+        /* dataFormat="ToCP" */
+        udm->vFuncs = &ToCPFuncs;
+        udm->toc=(const char *)udm->pHeader+udata_getHeaderSize(udm->pHeader);
+    }
+    else {
+        /* dataFormat not recognized */
+        *err=U_INVALID_FORMAT_ERROR;
+    }
+
+    if (U_FAILURE(*err)) {
+        /* If the data is no good and we memory-mapped it ourselves,
+         *  close the memory mapping so it doesn't leak.  Note that this has
+         *  no effect on non-memory mapped data, other than clearing fields in udm.
+         */
+        udata_close(udm);
+    }
+}
+
+/*
+ * TODO: Add a udata_swapPackageHeader() function that swaps an ICU .dat package
+ * header but not its sub-items.
+ * This function will be needed for automatic runtime swapping.
+ * Sub-items should not be swapped to limit the swapping to the parts of the
+ * package that are actually used.
+ *
+ * Since lengths of items are implicit in the order and offsets of their
+ * ToC entries, and since offsets are relative to the start of the ToC,
+ * a swapped version may need to generate a different data structure
+ * with pointers to the original data items and with their lengths
+ * (-1 for the last one if it is not known), and maybe even pointers to the
+ * swapped versions of the items.
+ * These pointers to swapped versions would establish a cache;
+ * instead, each open data item could simply own the storage for its swapped
+ * data. This fits better with the current design.
+ *
+ * markus 2003sep18 Jitterbug 2235
+ */
diff --git a/source/common/ucmndata.h b/source/common/ucmndata.h
new file mode 100644
index 0000000..5c5a124
--- /dev/null
+++ b/source/common/ucmndata.h
@@ -0,0 +1,108 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************/
+
+
+/*----------------------------------------------------------------------------------
+ *
+ *   UCommonData   An abstract interface for dealing with ICU Common Data Files.
+ *                 ICU Common Data Files are a grouping of a number of individual
+ *                 data items (resources, converters, tables, anything) into a
+ *                 single file or dll.  The combined format includes a table of
+ *                 contents for locating the individual items by name.
+ *
+ *                 Two formats for the table of contents are supported, which is
+ *                 why there is an abstract inteface involved.
+ *
+ *                 These functions are part of the ICU internal implementation, and
+ *                 are not inteded to be used directly by applications.
+ */
+
+#ifndef __UCMNDATA_H__
+#define __UCMNDATA_H__
+
+#include "unicode/udata.h"
+#include "umapfile.h"
+
+
+#define COMMON_DATA_NAME U_ICUDATA_NAME
+
+typedef struct  {
+    uint16_t    headerSize;
+    uint8_t     magic1;
+    uint8_t     magic2;
+} MappedData;
+
+
+typedef struct  {
+    MappedData  dataHeader;
+    UDataInfo   info;
+} DataHeader;
+
+typedef struct {
+    uint32_t nameOffset;
+    uint32_t dataOffset;
+} UDataOffsetTOCEntry;
+
+typedef struct {
+    uint32_t count;
+    UDataOffsetTOCEntry entry[2];    /* Actual size of array is from count. */
+} UDataOffsetTOC;
+
+/**
+ * Get the header size from a const DataHeader *udh.
+ * Handles opposite-endian data.
+ *
+ * @internal
+ */
+U_CFUNC uint16_t
+udata_getHeaderSize(const DataHeader *udh);
+
+/**
+ * Get the UDataInfo.size from a const UDataInfo *info.
+ * Handles opposite-endian data.
+ *
+ * @internal
+ */
+U_CFUNC uint16_t
+udata_getInfoSize(const UDataInfo *info);
+
+/*
+ *  "Virtual" functions for data lookup.
+ *  To call one, given a UDataMemory *p, the code looks like this:
+ *     p->vFuncs.Lookup(p, tocEntryName, pErrorCode);
+ *          (I sure do wish this was written in C++, not C)
+ */
+
+typedef const DataHeader *
+(* LookupFn)(const UDataMemory *pData,
+             const char *tocEntryName,
+             int32_t *pLength,
+             UErrorCode *pErrorCode);
+
+typedef uint32_t
+(* NumEntriesFn)(const UDataMemory *pData);
+
+typedef struct {
+    LookupFn      Lookup;
+    NumEntriesFn  NumEntries; 
+} commonDataFuncs;
+
+
+/*
+ *  Functions to check whether a UDataMemory refers to memory containing 
+ *     a recognizable header and table of contents a Common Data Format
+ *
+ *     If a valid header and TOC are found,
+ *         set the CommonDataFuncs function dispatch vector in the UDataMemory
+ *             to point to the right functions for the TOC type.
+ *     otherwise
+ *         set an errorcode.
+ */
+U_CFUNC void udata_checkCommonData(UDataMemory *pData, UErrorCode *pErrorCode);
+
+#endif
diff --git a/source/common/ucnv.c b/source/common/ucnv.c
new file mode 100644
index 0000000..5c4eb55
--- /dev/null
+++ b/source/common/ucnv.c
@@ -0,0 +1,2894 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1998-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+*  ucnv.c:
+*  Implements APIs for the ICU's codeset conversion library;
+*  mostly calls through internal functions;
+*  created by Bertrand A. Damiba
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   04/04/99    helena      Fixed internal header inclusion.
+*   05/09/00    helena      Added implementation to handle fallback mappings.
+*   06/20/2000  helena      OS/400 port changes; mostly typecast.
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ustring.h"
+#include "unicode/ucnv.h"
+#include "unicode/ucnv_err.h"
+#include "unicode/uset.h"
+#include "putilimp.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uassert.h"
+#include "utracimp.h"
+#include "ustr_imp.h"
+#include "ucnv_imp.h"
+#include "ucnv_cnv.h"
+#include "ucnv_bld.h"
+
+/* size of intermediate and preflighting buffers in ucnv_convert() */
+#define CHUNK_SIZE 1024
+
+typedef struct UAmbiguousConverter {
+    const char *name;
+    const UChar variant5c;
+} UAmbiguousConverter;
+
+static const UAmbiguousConverter ambiguousConverters[]={
+    { "ibm-897_P100-1995", 0xa5 },
+    { "ibm-942_P120-1999", 0xa5 },
+    { "ibm-943_P130-1999", 0xa5 },
+    { "ibm-946_P100-1995", 0xa5 },
+    { "ibm-33722_P120-1999", 0xa5 },
+    { "ibm-1041_P100-1995", 0xa5 },
+    /*{ "ibm-54191_P100-2006", 0xa5 },*/
+    /*{ "ibm-62383_P100-2007", 0xa5 },*/
+    /*{ "ibm-891_P100-1995", 0x20a9 },*/
+    { "ibm-944_P100-1995", 0x20a9 },
+    { "ibm-949_P110-1999", 0x20a9 },
+    { "ibm-1363_P110-1997", 0x20a9 },
+    { "ISO_2022,locale=ko,version=0", 0x20a9 },
+    { "ibm-1088_P100-1995", 0x20a9 }
+};
+
+/*Calls through createConverter */
+U_CAPI UConverter* U_EXPORT2
+ucnv_open (const char *name,
+                       UErrorCode * err)
+{
+    UConverter *r;
+
+    if (err == NULL || U_FAILURE (*err)) {
+        return NULL;
+    }
+
+    r =  ucnv_createConverter(NULL, name, err);
+    return r;
+}
+
+U_CAPI UConverter* U_EXPORT2 
+ucnv_openPackage   (const char *packageName, const char *converterName, UErrorCode * err)
+{
+    return ucnv_createConverterFromPackage(packageName, converterName,  err);
+}
+
+/*Extracts the UChar* to a char* and calls through createConverter */
+U_CAPI UConverter*   U_EXPORT2
+ucnv_openU (const UChar * name,
+                         UErrorCode * err)
+{
+    char asciiName[UCNV_MAX_CONVERTER_NAME_LENGTH];
+
+    if (err == NULL || U_FAILURE(*err))
+        return NULL;
+    if (name == NULL)
+        return ucnv_open (NULL, err);
+    if (u_strlen(name) >= UCNV_MAX_CONVERTER_NAME_LENGTH)
+    {
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+    return ucnv_open(u_austrcpy(asciiName, name), err);
+}
+
+/* Copy the string that is represented by the UConverterPlatform enum
+ * @param platformString An output buffer
+ * @param platform An enum representing a platform
+ * @return the length of the copied string.
+ */
+static int32_t
+ucnv_copyPlatformString(char *platformString, UConverterPlatform pltfrm)
+{
+    switch (pltfrm)
+    {
+    case UCNV_IBM:
+        uprv_strcpy(platformString, "ibm-");
+        return 4;
+    case UCNV_UNKNOWN:
+        break;
+    }
+
+    /* default to empty string */
+    *platformString = 0;
+    return 0;
+}
+
+/*Assumes a $platform-#codepage.$CONVERTER_FILE_EXTENSION scheme and calls
+ *through createConverter*/
+U_CAPI UConverter*   U_EXPORT2
+ucnv_openCCSID (int32_t codepage,
+                UConverterPlatform platform,
+                UErrorCode * err)
+{
+    char myName[UCNV_MAX_CONVERTER_NAME_LENGTH];
+    int32_t myNameLen;
+
+    if (err == NULL || U_FAILURE (*err))
+        return NULL;
+
+    /* ucnv_copyPlatformString could return "ibm-" or "cp" */
+    myNameLen = ucnv_copyPlatformString(myName, platform);
+    T_CString_integerToString(myName + myNameLen, codepage, 10);
+
+    return ucnv_createConverter(NULL, myName, err);
+}
+
+/* Creating a temporary stack-based object that can be used in one thread, 
+and created from a converter that is shared across threads.
+*/
+
+U_CAPI UConverter* U_EXPORT2
+ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, UErrorCode *status)
+{
+    UConverter *localConverter, *allocatedConverter;
+    int32_t bufferSizeNeeded;
+    char *stackBufferChars = (char *)stackBuffer;
+    UErrorCode cbErr;
+    UConverterToUnicodeArgs toUArgs = {
+        sizeof(UConverterToUnicodeArgs),
+            TRUE,
+            NULL,
+            NULL,
+            NULL,
+            NULL,
+            NULL,
+            NULL
+    };
+    UConverterFromUnicodeArgs fromUArgs = {
+        sizeof(UConverterFromUnicodeArgs),
+            TRUE,
+            NULL,
+            NULL,
+            NULL,
+            NULL,
+            NULL,
+            NULL
+    };
+
+    UTRACE_ENTRY_OC(UTRACE_UCNV_CLONE);
+
+    if (status == NULL || U_FAILURE(*status)){
+        UTRACE_EXIT_STATUS(status? *status: U_ILLEGAL_ARGUMENT_ERROR);
+        return 0;
+    }
+
+    if (!pBufferSize || !cnv){
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        UTRACE_EXIT_STATUS(*status);
+        return 0;
+    }
+
+    UTRACE_DATA3(UTRACE_OPEN_CLOSE, "clone converter %s at %p into stackBuffer %p",
+                                    ucnv_getName(cnv, status), cnv, stackBuffer);
+
+    if (cnv->sharedData->impl->safeClone != NULL) {
+        /* call the custom safeClone function for sizing */
+        bufferSizeNeeded = 0;
+        cnv->sharedData->impl->safeClone(cnv, NULL, &bufferSizeNeeded, status);
+    }
+    else
+    {
+        /* inherent sizing */
+        bufferSizeNeeded = sizeof(UConverter);
+    }
+
+    if (*pBufferSize <= 0){ /* 'preflighting' request - set needed size into *pBufferSize */
+        *pBufferSize = bufferSizeNeeded;
+        UTRACE_EXIT_VALUE(bufferSizeNeeded);
+        return 0;
+    }
+
+
+    /* Pointers on 64-bit platforms need to be aligned
+     * on a 64-bit boundary 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;
+    
+    /* Now, see if we must allocate any memory */
+    if (*pBufferSize < bufferSizeNeeded || stackBuffer == NULL)
+    {
+        /* allocate one here...*/
+        localConverter = allocatedConverter = (UConverter *) uprv_malloc (bufferSizeNeeded);
+
+        if(localConverter == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            UTRACE_EXIT_STATUS(*status);
+            return NULL;
+        }
+        
+        if (U_SUCCESS(*status)) {
+            *status = U_SAFECLONE_ALLOCATED_WARNING;
+        }
+        
+        /* record the fact that memory was allocated */
+        *pBufferSize = bufferSizeNeeded;
+    } else {
+        /* just use the stack buffer */
+        localConverter = (UConverter*) stackBuffer;
+        allocatedConverter = NULL;
+    }
+
+    uprv_memset(localConverter, 0, bufferSizeNeeded);
+
+    /* Copy initial state */
+    uprv_memcpy(localConverter, cnv, sizeof(UConverter));
+    localConverter->isCopyLocal = localConverter->isExtraLocal = FALSE;
+
+    /* copy the substitution string */
+    if (cnv->subChars == (uint8_t *)cnv->subUChars) {
+        localConverter->subChars = (uint8_t *)localConverter->subUChars;
+    } else {
+        localConverter->subChars = (uint8_t *)uprv_malloc(UCNV_ERROR_BUFFER_LENGTH * U_SIZEOF_UCHAR);
+        if (localConverter->subChars == NULL) {
+            uprv_free(allocatedConverter);
+            UTRACE_EXIT_STATUS(*status);
+            return NULL;
+        }
+        uprv_memcpy(localConverter->subChars, cnv->subChars, UCNV_ERROR_BUFFER_LENGTH * U_SIZEOF_UCHAR);
+    }
+
+    /* now either call the safeclone fcn or not */
+    if (cnv->sharedData->impl->safeClone != NULL) {
+        /* call the custom safeClone function */
+        localConverter = cnv->sharedData->impl->safeClone(cnv, localConverter, pBufferSize, status);
+    }
+
+    if(localConverter==NULL || U_FAILURE(*status)) {
+        if (allocatedConverter != NULL && allocatedConverter->subChars != (uint8_t *)allocatedConverter->subUChars) {
+            uprv_free(allocatedConverter->subChars);
+        }
+        uprv_free(allocatedConverter);
+        UTRACE_EXIT_STATUS(*status);
+        return NULL;
+    }
+
+    /* increment refcount of shared data if needed */
+    /*
+    Checking whether it's an algorithic converter is okay
+    in multithreaded applications because the value never changes.
+    Don't check referenceCounter for any other value.
+    */
+    if (cnv->sharedData->referenceCounter != ~0) {
+        ucnv_incrementRefCount(cnv->sharedData);
+    }
+
+    if(localConverter == (UConverter*)stackBuffer) {
+        /* we're using user provided data - set to not destroy */
+        localConverter->isCopyLocal = TRUE;
+    }
+
+    /* allow callback functions to handle any memory allocation */
+    toUArgs.converter = fromUArgs.converter = localConverter;
+    cbErr = U_ZERO_ERROR;
+    cnv->fromCharErrorBehaviour(cnv->toUContext, &toUArgs, NULL, 0, UCNV_CLONE, &cbErr);
+    cbErr = U_ZERO_ERROR;
+    cnv->fromUCharErrorBehaviour(cnv->fromUContext, &fromUArgs, NULL, 0, 0, UCNV_CLONE, &cbErr);
+
+    UTRACE_EXIT_PTR_STATUS(localConverter, *status);
+    return localConverter;
+}
+
+
+
+/*Decreases the reference counter in the shared immutable section of the object
+ *and frees the mutable part*/
+
+U_CAPI void  U_EXPORT2
+ucnv_close (UConverter * converter)
+{
+    UErrorCode errorCode = U_ZERO_ERROR;
+
+    UTRACE_ENTRY_OC(UTRACE_UCNV_CLOSE);
+
+    if (converter == NULL)
+    {
+        UTRACE_EXIT();
+        return;
+    }
+
+    UTRACE_DATA3(UTRACE_OPEN_CLOSE, "close converter %s at %p, isCopyLocal=%b",
+        ucnv_getName(converter, &errorCode), converter, converter->isCopyLocal);
+
+    /* In order to speed up the close, only call the callbacks when they have been changed.
+    This performance check will only work when the callbacks are set within a shared library
+    or from user code that statically links this code. */
+    /* first, notify the callback functions that the converter is closed */
+    if (converter->fromCharErrorBehaviour != UCNV_TO_U_DEFAULT_CALLBACK) {
+        UConverterToUnicodeArgs toUArgs = {
+            sizeof(UConverterToUnicodeArgs),
+                TRUE,
+                NULL,
+                NULL,
+                NULL,
+                NULL,
+                NULL,
+                NULL
+        };
+
+        toUArgs.converter = converter;
+        errorCode = U_ZERO_ERROR;
+        converter->fromCharErrorBehaviour(converter->toUContext, &toUArgs, NULL, 0, UCNV_CLOSE, &errorCode);
+    }
+    if (converter->fromUCharErrorBehaviour != UCNV_FROM_U_DEFAULT_CALLBACK) {
+        UConverterFromUnicodeArgs fromUArgs = {
+            sizeof(UConverterFromUnicodeArgs),
+                TRUE,
+                NULL,
+                NULL,
+                NULL,
+                NULL,
+                NULL,
+                NULL
+        };
+        fromUArgs.converter = converter;
+        errorCode = U_ZERO_ERROR;
+        converter->fromUCharErrorBehaviour(converter->fromUContext, &fromUArgs, NULL, 0, 0, UCNV_CLOSE, &errorCode);
+    }
+
+    if (converter->sharedData->impl->close != NULL) {
+        converter->sharedData->impl->close(converter);
+    }
+
+    if (converter->subChars != (uint8_t *)converter->subUChars) {
+        uprv_free(converter->subChars);
+    }
+
+    /*
+    Checking whether it's an algorithic converter is okay
+    in multithreaded applications because the value never changes.
+    Don't check referenceCounter for any other value.
+    */
+    if (converter->sharedData->referenceCounter != ~0) {
+        ucnv_unloadSharedDataIfReady(converter->sharedData);
+    }
+
+    if(!converter->isCopyLocal){
+        uprv_free(converter);
+    }
+
+    UTRACE_EXIT();
+}
+
+/*returns a single Name from the list, will return NULL if out of bounds
+ */
+U_CAPI const char*   U_EXPORT2
+ucnv_getAvailableName (int32_t n)
+{
+    if (0 <= n && n <= 0xffff) {
+        UErrorCode err = U_ZERO_ERROR;
+        const char *name = ucnv_bld_getAvailableConverter((uint16_t)n, &err);
+        if (U_SUCCESS(err)) {
+            return name;
+        }
+    }
+    return NULL;
+}
+
+U_CAPI int32_t   U_EXPORT2
+ucnv_countAvailable ()
+{
+    UErrorCode err = U_ZERO_ERROR;
+    return ucnv_bld_countAvailableConverters(&err);
+}
+
+U_CAPI void    U_EXPORT2
+ucnv_getSubstChars (const UConverter * converter,
+                    char *mySubChar,
+                    int8_t * len,
+                    UErrorCode * err)
+{
+    if (U_FAILURE (*err))
+        return;
+
+    if (converter->subCharLen <= 0) {
+        /* Unicode string or empty string from ucnv_setSubstString(). */
+        *len = 0;
+        return;
+    }
+
+    if (*len < converter->subCharLen) /*not enough space in subChars */
+    {
+        *err = U_INDEX_OUTOFBOUNDS_ERROR;
+        return;
+    }
+
+    uprv_memcpy (mySubChar, converter->subChars, converter->subCharLen);   /*fills in the subchars */
+    *len = converter->subCharLen; /*store # of bytes copied to buffer */
+}
+
+U_CAPI void    U_EXPORT2
+ucnv_setSubstChars (UConverter * converter,
+                    const char *mySubChar,
+                    int8_t len,
+                    UErrorCode * err)
+{
+    if (U_FAILURE (*err))
+        return;
+    
+    /*Makes sure that the subChar is within the codepages char length boundaries */
+    if ((len > converter->sharedData->staticData->maxBytesPerChar)
+     || (len < converter->sharedData->staticData->minBytesPerChar))
+    {
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    
+    uprv_memcpy (converter->subChars, mySubChar, len); /*copies the subchars */
+    converter->subCharLen = len;  /*sets the new len */
+
+    /*
+    * There is currently (2001Feb) no separate API to set/get subChar1.
+    * In order to always have subChar written after it is explicitly set,
+    * we set subChar1 to 0.
+    */
+    converter->subChar1 = 0;
+    
+    return;
+}
+
+U_CAPI void U_EXPORT2
+ucnv_setSubstString(UConverter *cnv,
+                    const UChar *s,
+                    int32_t length,
+                    UErrorCode *err) {
+    UAlignedMemory cloneBuffer[U_CNV_SAFECLONE_BUFFERSIZE / sizeof(UAlignedMemory) + 1];
+    char chars[UCNV_ERROR_BUFFER_LENGTH];
+
+    UConverter *clone;
+    uint8_t *subChars;
+    int32_t cloneSize, length8;
+
+    /* Let the following functions check all arguments. */
+    cloneSize = sizeof(cloneBuffer);
+    clone = ucnv_safeClone(cnv, cloneBuffer, &cloneSize, err);
+    ucnv_setFromUCallBack(clone, UCNV_FROM_U_CALLBACK_STOP, NULL, NULL, NULL, err);
+    length8 = ucnv_fromUChars(clone, chars, (int32_t)sizeof(chars), s, length, err);
+    ucnv_close(clone);
+    if (U_FAILURE(*err)) {
+        return;
+    }
+
+    if (cnv->sharedData->impl->writeSub == NULL
+#if !UCONFIG_NO_LEGACY_CONVERSION
+        || (cnv->sharedData->staticData->conversionType == UCNV_MBCS &&
+         ucnv_MBCSGetType(cnv) != UCNV_EBCDIC_STATEFUL)
+#endif
+    ) {
+        /* The converter is not stateful. Store the charset bytes as a fixed string. */
+        subChars = (uint8_t *)chars;
+    } else {
+        /*
+         * The converter has a non-default writeSub() function, indicating
+         * that it is stateful.
+         * Store the Unicode string for on-the-fly conversion for correct
+         * state handling.
+         */
+        if (length > UCNV_ERROR_BUFFER_LENGTH) {
+            /*
+             * Should not occur. The converter should output at least one byte
+             * per UChar, which means that ucnv_fromUChars() should catch all
+             * overflows.
+             */
+            *err = U_BUFFER_OVERFLOW_ERROR;
+            return;
+        }
+        subChars = (uint8_t *)s;
+        if (length < 0) {
+            length = u_strlen(s);
+        }
+        length8 = length * U_SIZEOF_UCHAR;
+    }
+
+    /*
+     * For storing the substitution string, select either the small buffer inside
+     * UConverter or allocate a subChars buffer.
+     */
+    if (length8 > UCNV_MAX_SUBCHAR_LEN) {
+        /* Use a separate buffer for the string. Outside UConverter to not make it too large. */
+        if (cnv->subChars == (uint8_t *)cnv->subUChars) {
+            /* Allocate a new buffer for the string. */
+            cnv->subChars = (uint8_t *)uprv_malloc(UCNV_ERROR_BUFFER_LENGTH * U_SIZEOF_UCHAR);
+            if (cnv->subChars == NULL) {
+                cnv->subChars = (uint8_t *)cnv->subUChars;
+                *err = U_MEMORY_ALLOCATION_ERROR;
+                return;
+            }
+            uprv_memset(cnv->subChars, 0, UCNV_ERROR_BUFFER_LENGTH * U_SIZEOF_UCHAR);
+        }
+    }
+
+    /* Copy the substitution string into the UConverter or its subChars buffer. */
+    if (length8 == 0) {
+        cnv->subCharLen = 0;
+    } else {
+        uprv_memcpy(cnv->subChars, subChars, length8);
+        if (subChars == (uint8_t *)chars) {
+            cnv->subCharLen = (int8_t)length8;
+        } else /* subChars == s */ {
+            cnv->subCharLen = (int8_t)-length;
+        }
+    }
+
+    /* See comment in ucnv_setSubstChars(). */
+    cnv->subChar1 = 0;
+}
+
+/*resets the internal states of a converter
+ *goal : have the same behaviour than a freshly created converter
+ */
+static void _reset(UConverter *converter, UConverterResetChoice choice,
+                   UBool callCallback) {
+    if(converter == NULL) {
+        return;
+    }
+
+    if(callCallback) {
+        /* first, notify the callback functions that the converter is reset */
+        UErrorCode errorCode;
+
+        if(choice<=UCNV_RESET_TO_UNICODE && converter->fromCharErrorBehaviour != UCNV_TO_U_DEFAULT_CALLBACK) {
+            UConverterToUnicodeArgs toUArgs = {
+                sizeof(UConverterToUnicodeArgs),
+                TRUE,
+                NULL,
+                NULL,
+                NULL,
+                NULL,
+                NULL,
+                NULL
+            };
+            toUArgs.converter = converter;
+            errorCode = U_ZERO_ERROR;
+            converter->fromCharErrorBehaviour(converter->toUContext, &toUArgs, NULL, 0, UCNV_RESET, &errorCode);
+        }
+        if(choice!=UCNV_RESET_TO_UNICODE && converter->fromUCharErrorBehaviour != UCNV_FROM_U_DEFAULT_CALLBACK) {
+            UConverterFromUnicodeArgs fromUArgs = {
+                sizeof(UConverterFromUnicodeArgs),
+                TRUE,
+                NULL,
+                NULL,
+                NULL,
+                NULL,
+                NULL,
+                NULL
+            };
+            fromUArgs.converter = converter;
+            errorCode = U_ZERO_ERROR;
+            converter->fromUCharErrorBehaviour(converter->fromUContext, &fromUArgs, NULL, 0, 0, UCNV_RESET, &errorCode);
+        }
+    }
+
+    /* now reset the converter itself */
+    if(choice<=UCNV_RESET_TO_UNICODE) {
+        converter->toUnicodeStatus = converter->sharedData->toUnicodeStatus;
+        converter->mode = 0;
+        converter->toULength = 0;
+        converter->invalidCharLength = converter->UCharErrorBufferLength = 0;
+        converter->preToULength = 0;
+    }
+    if(choice!=UCNV_RESET_TO_UNICODE) {
+        converter->fromUnicodeStatus = 0;
+        converter->fromUChar32 = 0;
+        converter->invalidUCharLength = converter->charErrorBufferLength = 0;
+        converter->preFromUFirstCP = U_SENTINEL;
+        converter->preFromULength = 0;
+    }
+
+    if (converter->sharedData->impl->reset != NULL) {
+        /* call the custom reset function */
+        converter->sharedData->impl->reset(converter, choice);
+    }
+}
+
+U_CAPI void  U_EXPORT2
+ucnv_reset(UConverter *converter)
+{
+    _reset(converter, UCNV_RESET_BOTH, TRUE);
+}
+
+U_CAPI void  U_EXPORT2
+ucnv_resetToUnicode(UConverter *converter)
+{
+    _reset(converter, UCNV_RESET_TO_UNICODE, TRUE);
+}
+
+U_CAPI void  U_EXPORT2
+ucnv_resetFromUnicode(UConverter *converter)
+{
+    _reset(converter, UCNV_RESET_FROM_UNICODE, TRUE);
+}
+
+U_CAPI int8_t   U_EXPORT2
+ucnv_getMaxCharSize (const UConverter * converter)
+{
+    return converter->maxBytesPerUChar;
+}
+
+
+U_CAPI int8_t   U_EXPORT2
+ucnv_getMinCharSize (const UConverter * converter)
+{
+    return converter->sharedData->staticData->minBytesPerChar;
+}
+
+U_CAPI const char*   U_EXPORT2
+ucnv_getName (const UConverter * converter, UErrorCode * err)
+     
+{
+    if (U_FAILURE (*err))
+        return NULL;
+    if(converter->sharedData->impl->getName){
+        const char* temp= converter->sharedData->impl->getName(converter);
+        if(temp)
+            return temp;
+    }
+    return converter->sharedData->staticData->name;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucnv_getCCSID(const UConverter * converter,
+              UErrorCode * err)
+{
+    int32_t ccsid;
+    if (U_FAILURE (*err))
+        return -1;
+
+    ccsid = converter->sharedData->staticData->codepage;
+    if (ccsid == 0) {
+        /* Rare case. This is for cases like gb18030,
+        which doesn't have an IBM cannonical name, but does have an IBM alias. */
+        const char *standardName = ucnv_getStandardName(ucnv_getName(converter, err), "IBM", err);
+        if (U_SUCCESS(*err) && standardName) {
+            const char *ccsidStr = uprv_strchr(standardName, '-');
+            if (ccsidStr) {
+                ccsid = (int32_t)atol(ccsidStr+1);  /* +1 to skip '-' */
+            }
+        }
+    }
+    return ccsid;
+}
+
+
+U_CAPI UConverterPlatform   U_EXPORT2
+ucnv_getPlatform (const UConverter * converter,
+                                      UErrorCode * err)
+{
+    if (U_FAILURE (*err))
+        return UCNV_UNKNOWN;
+
+    return (UConverterPlatform)converter->sharedData->staticData->platform;
+}
+
+U_CAPI void U_EXPORT2
+    ucnv_getToUCallBack (const UConverter * converter,
+                         UConverterToUCallback *action,
+                         const void **context)
+{
+    *action = converter->fromCharErrorBehaviour;
+    *context = converter->toUContext;
+}
+
+U_CAPI void U_EXPORT2
+    ucnv_getFromUCallBack (const UConverter * converter,
+                           UConverterFromUCallback *action,
+                           const void **context)
+{
+    *action = converter->fromUCharErrorBehaviour;
+    *context = converter->fromUContext;
+}
+
+U_CAPI void    U_EXPORT2
+ucnv_setToUCallBack (UConverter * converter,
+                            UConverterToUCallback newAction,
+                            const void* newContext,
+                            UConverterToUCallback *oldAction,
+                            const void** oldContext,
+                            UErrorCode * err)
+{
+    if (U_FAILURE (*err))
+        return;
+    if (oldAction) *oldAction = converter->fromCharErrorBehaviour;
+    converter->fromCharErrorBehaviour = newAction;
+    if (oldContext) *oldContext = converter->toUContext;
+    converter->toUContext = newContext;
+}
+
+U_CAPI void  U_EXPORT2
+ucnv_setFromUCallBack (UConverter * converter,
+                            UConverterFromUCallback newAction,
+                            const void* newContext,
+                            UConverterFromUCallback *oldAction,
+                            const void** oldContext,
+                            UErrorCode * err)
+{
+    if (U_FAILURE (*err))
+        return;
+    if (oldAction) *oldAction = converter->fromUCharErrorBehaviour;
+    converter->fromUCharErrorBehaviour = newAction;
+    if (oldContext) *oldContext = converter->fromUContext;
+    converter->fromUContext = newContext;
+}
+
+static void
+_updateOffsets(int32_t *offsets, int32_t length,
+               int32_t sourceIndex, int32_t errorInputLength) {
+    int32_t *limit;
+    int32_t delta, offset;
+
+    if(sourceIndex>=0) {
+        /*
+         * adjust each offset by adding the previous sourceIndex
+         * minus the length of the input sequence that caused an
+         * error, if any
+         */
+        delta=sourceIndex-errorInputLength;
+    } else {
+        /*
+         * set each offset to -1 because this conversion function
+         * does not handle offsets
+         */
+        delta=-1;
+    }
+
+    limit=offsets+length;
+    if(delta==0) {
+        /* most common case, nothing to do */
+    } else if(delta>0) {
+        /* add the delta to each offset (but not if the offset is <0) */
+        while(offsets<limit) {
+            offset=*offsets;
+            if(offset>=0) {
+                *offsets=offset+delta;
+            }
+            ++offsets;
+        }
+    } else /* delta<0 */ {
+        /*
+         * set each offset to -1 because this conversion function
+         * does not handle offsets
+         * or the error input sequence started in a previous buffer
+         */
+        while(offsets<limit) {
+            *offsets++=-1;
+        }
+    }
+}
+
+/* ucnv_fromUnicode --------------------------------------------------------- */
+
+/*
+ * Implementation note for m:n conversions
+ *
+ * While collecting source units to find the longest match for m:n conversion,
+ * some source units may need to be stored for a partial match.
+ * When a second buffer does not yield a match on all of the previously stored
+ * source units, then they must be "replayed", i.e., fed back into the converter.
+ *
+ * The code relies on the fact that replaying will not nest -
+ * converting a replay buffer will not result in a replay.
+ * This is because a replay is necessary only after the _continuation_ of a
+ * partial match failed, but a replay buffer is converted as a whole.
+ * It may result in some of its units being stored again for a partial match,
+ * but there will not be a continuation _during_ the replay which could fail.
+ *
+ * It is conceivable that a callback function could call the converter
+ * recursively in a way that causes another replay to be stored, but that
+ * would be an error in the callback function.
+ * Such violations will cause assertion failures in a debug build,
+ * and wrong output, but they will not cause a crash.
+ */
+
+static void
+_fromUnicodeWithCallback(UConverterFromUnicodeArgs *pArgs, UErrorCode *err) {
+    UConverterFromUnicode fromUnicode;
+    UConverter *cnv;
+    const UChar *s;
+    char *t;
+    int32_t *offsets;
+    int32_t sourceIndex;
+    int32_t errorInputLength;
+    UBool converterSawEndOfInput, calledCallback;
+
+    /* variables for m:n conversion */
+    UChar replay[UCNV_EXT_MAX_UCHARS];
+    const UChar *realSource, *realSourceLimit;
+    int32_t realSourceIndex;
+    UBool realFlush;
+
+    cnv=pArgs->converter;
+    s=pArgs->source;
+    t=pArgs->target;
+    offsets=pArgs->offsets;
+
+    /* get the converter implementation function */
+    sourceIndex=0;
+    if(offsets==NULL) {
+        fromUnicode=cnv->sharedData->impl->fromUnicode;
+    } else {
+        fromUnicode=cnv->sharedData->impl->fromUnicodeWithOffsets;
+        if(fromUnicode==NULL) {
+            /* there is no WithOffsets implementation */
+            fromUnicode=cnv->sharedData->impl->fromUnicode;
+            /* we will write -1 for each offset */
+            sourceIndex=-1;
+        }
+    }
+
+    if(cnv->preFromULength>=0) {
+        /* normal mode */
+        realSource=NULL;
+
+        /* avoid compiler warnings - not otherwise necessary, and the values do not matter */
+        realSourceLimit=NULL;
+        realFlush=FALSE;
+        realSourceIndex=0;
+    } else {
+        /*
+         * Previous m:n conversion stored source units from a partial match
+         * and failed to consume all of them.
+         * We need to "replay" them from a temporary buffer and convert them first.
+         */
+        realSource=pArgs->source;
+        realSourceLimit=pArgs->sourceLimit;
+        realFlush=pArgs->flush;
+        realSourceIndex=sourceIndex;
+
+        uprv_memcpy(replay, cnv->preFromU, -cnv->preFromULength*U_SIZEOF_UCHAR);
+        pArgs->source=replay;
+        pArgs->sourceLimit=replay-cnv->preFromULength;
+        pArgs->flush=FALSE;
+        sourceIndex=-1;
+
+        cnv->preFromULength=0;
+    }
+
+    /*
+     * loop for conversion and error handling
+     *
+     * loop {
+     *   convert
+     *   loop {
+     *     update offsets
+     *     handle end of input
+     *     handle errors/call callback
+     *   }
+     * }
+     */
+    for(;;) {
+        if(U_SUCCESS(*err)) {
+            /* convert */
+            fromUnicode(pArgs, err);
+
+            /*
+             * set a flag for whether the converter
+             * successfully processed the end of the input
+             *
+             * need not check cnv->preFromULength==0 because a replay (<0) will cause
+             * s<sourceLimit before converterSawEndOfInput is checked
+             */
+            converterSawEndOfInput=
+                (UBool)(U_SUCCESS(*err) &&
+                        pArgs->flush && pArgs->source==pArgs->sourceLimit &&
+                        cnv->fromUChar32==0);
+        } else {
+            /* handle error from ucnv_convertEx() */
+            converterSawEndOfInput=FALSE;
+        }
+
+        /* no callback called yet for this iteration */
+        calledCallback=FALSE;
+
+        /* no sourceIndex adjustment for conversion, only for callback output */
+        errorInputLength=0;
+
+        /*
+         * loop for offsets and error handling
+         *
+         * iterates at most 3 times:
+         * 1. to clean up after the conversion function
+         * 2. after the callback
+         * 3. after the callback again if there was truncated input
+         */
+        for(;;) {
+            /* update offsets if we write any */
+            if(offsets!=NULL) {
+                int32_t length=(int32_t)(pArgs->target-t);
+                if(length>0) {
+                    _updateOffsets(offsets, length, sourceIndex, errorInputLength);
+
+                    /*
+                     * if a converter handles offsets and updates the offsets
+                     * pointer at the end, then pArgs->offset should not change
+                     * here;
+                     * however, some converters do not handle offsets at all
+                     * (sourceIndex<0) or may not update the offsets pointer
+                     */
+                    pArgs->offsets=offsets+=length;
+                }
+
+                if(sourceIndex>=0) {
+                    sourceIndex+=(int32_t)(pArgs->source-s);
+                }
+            }
+
+            if(cnv->preFromULength<0) {
+                /*
+                 * switch the source to new replay units (cannot occur while replaying)
+                 * after offset handling and before end-of-input and callback handling
+                 */
+                if(realSource==NULL) {
+                    realSource=pArgs->source;
+                    realSourceLimit=pArgs->sourceLimit;
+                    realFlush=pArgs->flush;
+                    realSourceIndex=sourceIndex;
+
+                    uprv_memcpy(replay, cnv->preFromU, -cnv->preFromULength*U_SIZEOF_UCHAR);
+                    pArgs->source=replay;
+                    pArgs->sourceLimit=replay-cnv->preFromULength;
+                    pArgs->flush=FALSE;
+                    if((sourceIndex+=cnv->preFromULength)<0) {
+                        sourceIndex=-1;
+                    }
+
+                    cnv->preFromULength=0;
+                } else {
+                    /* see implementation note before _fromUnicodeWithCallback() */
+                    U_ASSERT(realSource==NULL);
+                    *err=U_INTERNAL_PROGRAM_ERROR;
+                }
+            }
+
+            /* update pointers */
+            s=pArgs->source;
+            t=pArgs->target;
+
+            if(U_SUCCESS(*err)) {
+                if(s<pArgs->sourceLimit) {
+                    /*
+                     * continue with the conversion loop while there is still input left
+                     * (continue converting by breaking out of only the inner loop)
+                     */
+                    break;
+                } else if(realSource!=NULL) {
+                    /* switch back from replaying to the real source and continue */
+                    pArgs->source=realSource;
+                    pArgs->sourceLimit=realSourceLimit;
+                    pArgs->flush=realFlush;
+                    sourceIndex=realSourceIndex;
+
+                    realSource=NULL;
+                    break;
+                } else if(pArgs->flush && cnv->fromUChar32!=0) {
+                    /*
+                     * the entire input stream is consumed
+                     * and there is a partial, truncated input sequence left
+                     */
+
+                    /* inject an error and continue with callback handling */
+                    *err=U_TRUNCATED_CHAR_FOUND;
+                    calledCallback=FALSE; /* new error condition */
+                } else {
+                    /* input consumed */
+                    if(pArgs->flush) {
+                        /*
+                         * return to the conversion loop once more if the flush
+                         * flag is set and the conversion function has not
+                         * successfully processed the end of the input yet
+                         *
+                         * (continue converting by breaking out of only the inner loop)
+                         */
+                        if(!converterSawEndOfInput) {
+                            break;
+                        }
+
+                        /* reset the converter without calling the callback function */
+                        _reset(cnv, UCNV_RESET_FROM_UNICODE, FALSE);
+                    }
+
+                    /* done successfully */
+                    return;
+                }
+            }
+
+            /* U_FAILURE(*err) */
+            {
+                UErrorCode e;
+
+                if( calledCallback ||
+                    (e=*err)==U_BUFFER_OVERFLOW_ERROR ||
+                    (e!=U_INVALID_CHAR_FOUND &&
+                     e!=U_ILLEGAL_CHAR_FOUND &&
+                     e!=U_TRUNCATED_CHAR_FOUND)
+                ) {
+                    /*
+                     * the callback did not or cannot resolve the error:
+                     * set output pointers and return
+                     *
+                     * the check for buffer overflow is redundant but it is
+                     * a high-runner case and hopefully documents the intent
+                     * well
+                     *
+                     * if we were replaying, then the replay buffer must be
+                     * copied back into the UConverter
+                     * and the real arguments must be restored
+                     */
+                    if(realSource!=NULL) {
+                        int32_t length;
+
+                        U_ASSERT(cnv->preFromULength==0);
+
+                        length=(int32_t)(pArgs->sourceLimit-pArgs->source);
+                        if(length>0) {
+                            uprv_memcpy(cnv->preFromU, pArgs->source, length*U_SIZEOF_UCHAR);
+                            cnv->preFromULength=(int8_t)-length;
+                        }
+
+                        pArgs->source=realSource;
+                        pArgs->sourceLimit=realSourceLimit;
+                        pArgs->flush=realFlush;
+                    }
+
+                    return;
+                }
+            }
+
+            /* callback handling */
+            {
+                UChar32 codePoint;
+
+                /* get and write the code point */
+                codePoint=cnv->fromUChar32;
+                errorInputLength=0;
+                U16_APPEND_UNSAFE(cnv->invalidUCharBuffer, errorInputLength, codePoint);
+                cnv->invalidUCharLength=(int8_t)errorInputLength;
+
+                /* set the converter state to deal with the next character */
+                cnv->fromUChar32=0;
+
+                /* call the callback function */
+                cnv->fromUCharErrorBehaviour(cnv->fromUContext, pArgs,
+                    cnv->invalidUCharBuffer, errorInputLength, codePoint,
+                    *err==U_INVALID_CHAR_FOUND ? UCNV_UNASSIGNED : UCNV_ILLEGAL,
+                    err);
+            }
+
+            /*
+             * loop back to the offset handling
+             *
+             * this flag will indicate after offset handling
+             * that a callback was called;
+             * if the callback did not resolve the error, then we return
+             */
+            calledCallback=TRUE;
+        }
+    }
+}
+
+/*
+ * Output the fromUnicode overflow buffer.
+ * Call this function if(cnv->charErrorBufferLength>0).
+ * @return TRUE if overflow
+ */
+static UBool
+ucnv_outputOverflowFromUnicode(UConverter *cnv,
+                               char **target, const char *targetLimit,
+                               int32_t **pOffsets,
+                               UErrorCode *err) {
+    int32_t *offsets;
+    char *overflow, *t;
+    int32_t i, length;
+
+    t=*target;
+    if(pOffsets!=NULL) {
+        offsets=*pOffsets;
+    } else {
+        offsets=NULL;
+    }
+
+    overflow=(char *)cnv->charErrorBuffer;
+    length=cnv->charErrorBufferLength;
+    i=0;
+    while(i<length) {
+        if(t==targetLimit) {
+            /* the overflow buffer contains too much, keep the rest */
+            int32_t j=0;
+
+            do {
+                overflow[j++]=overflow[i++];
+            } while(i<length);
+
+            cnv->charErrorBufferLength=(int8_t)j;
+            *target=t;
+            if(offsets!=NULL) {
+                *pOffsets=offsets;
+            }
+            *err=U_BUFFER_OVERFLOW_ERROR;
+            return TRUE;
+        }
+
+        /* copy the overflow contents to the target */
+        *t++=overflow[i++];
+        if(offsets!=NULL) {
+            *offsets++=-1; /* no source index available for old output */
+        }
+    }
+
+    /* the overflow buffer is completely copied to the target */
+    cnv->charErrorBufferLength=0;
+    *target=t;
+    if(offsets!=NULL) {
+        *pOffsets=offsets;
+    }
+    return FALSE;
+}
+
+U_CAPI void U_EXPORT2
+ucnv_fromUnicode(UConverter *cnv,
+                 char **target, const char *targetLimit,
+                 const UChar **source, const UChar *sourceLimit,
+                 int32_t *offsets,
+                 UBool flush,
+                 UErrorCode *err) {
+    UConverterFromUnicodeArgs args;
+    const UChar *s;
+    char *t;
+
+    /* check parameters */
+    if(err==NULL || U_FAILURE(*err)) {
+        return;
+    }
+
+    if(cnv==NULL || target==NULL || source==NULL) {
+        *err=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    s=*source;
+    t=*target;
+
+    if ((const void *)U_MAX_PTR(sourceLimit) == (const void *)sourceLimit) {
+        /*
+        Prevent code from going into an infinite loop in case we do hit this
+        limit. The limit pointer is expected to be on a UChar * boundary.
+        This also prevents the next argument check from failing.
+        */
+        sourceLimit = (const UChar *)(((const char *)sourceLimit) - 1);
+    }
+
+    /*
+     * All these conditions should never happen.
+     *
+     * 1) Make sure that the limits are >= to the address source or target
+     *
+     * 2) Make sure that the buffer sizes do not exceed the number range for
+     * int32_t because some functions use the size (in units or bytes)
+     * rather than comparing pointers, and because offsets are int32_t values.
+     *
+     * size_t is guaranteed to be unsigned and large enough for the job.
+     *
+     * Return with an error instead of adjusting the limits because we would
+     * not be able to maintain the semantics that either the source must be
+     * consumed or the target filled (unless an error occurs).
+     * An adjustment would be targetLimit=t+0x7fffffff; for example.
+     *
+     * 3) Make sure that the user didn't incorrectly cast a UChar * pointer
+     * to a char * pointer and provide an incomplete UChar code unit.
+     */
+    if (sourceLimit<s || targetLimit<t ||
+        ((size_t)(sourceLimit-s)>(size_t)0x3fffffff && sourceLimit>s) ||
+        ((size_t)(targetLimit-t)>(size_t)0x7fffffff && targetLimit>t) ||
+        (((const char *)sourceLimit-(const char *)s) & 1) != 0)
+    {
+        *err=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    
+    /* output the target overflow buffer */
+    if( cnv->charErrorBufferLength>0 &&
+        ucnv_outputOverflowFromUnicode(cnv, target, targetLimit, &offsets, err)
+    ) {
+        /* U_BUFFER_OVERFLOW_ERROR */
+        return;
+    }
+    /* *target may have moved, therefore stop using t */
+
+    if(!flush && s==sourceLimit && cnv->preFromULength>=0) {
+        /* the overflow buffer is emptied and there is no new input: we are done */
+        return;
+    }
+
+    /*
+     * Do not simply return with a buffer overflow error if
+     * !flush && t==targetLimit
+     * because it is possible that the source will not generate any output.
+     * For example, the skip callback may be called;
+     * it does not output anything.
+     */
+
+    /* prepare the converter arguments */
+    args.converter=cnv;
+    args.flush=flush;
+    args.offsets=offsets;
+    args.source=s;
+    args.sourceLimit=sourceLimit;
+    args.target=*target;
+    args.targetLimit=targetLimit;
+    args.size=sizeof(args);
+
+    _fromUnicodeWithCallback(&args, err);
+
+    *source=args.source;
+    *target=args.target;
+}
+
+/* ucnv_toUnicode() --------------------------------------------------------- */
+
+static void
+_toUnicodeWithCallback(UConverterToUnicodeArgs *pArgs, UErrorCode *err) {
+    UConverterToUnicode toUnicode;
+    UConverter *cnv;
+    const char *s;
+    UChar *t;
+    int32_t *offsets;
+    int32_t sourceIndex;
+    int32_t errorInputLength;
+    UBool converterSawEndOfInput, calledCallback;
+
+    /* variables for m:n conversion */
+    char replay[UCNV_EXT_MAX_BYTES];
+    const char *realSource, *realSourceLimit;
+    int32_t realSourceIndex;
+    UBool realFlush;
+
+    cnv=pArgs->converter;
+    s=pArgs->source;
+    t=pArgs->target;
+    offsets=pArgs->offsets;
+
+    /* get the converter implementation function */
+    sourceIndex=0;
+    if(offsets==NULL) {
+        toUnicode=cnv->sharedData->impl->toUnicode;
+    } else {
+        toUnicode=cnv->sharedData->impl->toUnicodeWithOffsets;
+        if(toUnicode==NULL) {
+            /* there is no WithOffsets implementation */
+            toUnicode=cnv->sharedData->impl->toUnicode;
+            /* we will write -1 for each offset */
+            sourceIndex=-1;
+        }
+    }
+
+    if(cnv->preToULength>=0) {
+        /* normal mode */
+        realSource=NULL;
+
+        /* avoid compiler warnings - not otherwise necessary, and the values do not matter */
+        realSourceLimit=NULL;
+        realFlush=FALSE;
+        realSourceIndex=0;
+    } else {
+        /*
+         * Previous m:n conversion stored source units from a partial match
+         * and failed to consume all of them.
+         * We need to "replay" them from a temporary buffer and convert them first.
+         */
+        realSource=pArgs->source;
+        realSourceLimit=pArgs->sourceLimit;
+        realFlush=pArgs->flush;
+        realSourceIndex=sourceIndex;
+
+        uprv_memcpy(replay, cnv->preToU, -cnv->preToULength);
+        pArgs->source=replay;
+        pArgs->sourceLimit=replay-cnv->preToULength;
+        pArgs->flush=FALSE;
+        sourceIndex=-1;
+
+        cnv->preToULength=0;
+    }
+
+    /*
+     * loop for conversion and error handling
+     *
+     * loop {
+     *   convert
+     *   loop {
+     *     update offsets
+     *     handle end of input
+     *     handle errors/call callback
+     *   }
+     * }
+     */
+    for(;;) {
+        if(U_SUCCESS(*err)) {
+            /* convert */
+            toUnicode(pArgs, err);
+
+            /*
+             * set a flag for whether the converter
+             * successfully processed the end of the input
+             *
+             * need not check cnv->preToULength==0 because a replay (<0) will cause
+             * s<sourceLimit before converterSawEndOfInput is checked
+             */
+            converterSawEndOfInput=
+                (UBool)(U_SUCCESS(*err) &&
+                        pArgs->flush && pArgs->source==pArgs->sourceLimit &&
+                        cnv->toULength==0);
+        } else {
+            /* handle error from getNextUChar() or ucnv_convertEx() */
+            converterSawEndOfInput=FALSE;
+        }
+
+        /* no callback called yet for this iteration */
+        calledCallback=FALSE;
+
+        /* no sourceIndex adjustment for conversion, only for callback output */
+        errorInputLength=0;
+
+        /*
+         * loop for offsets and error handling
+         *
+         * iterates at most 3 times:
+         * 1. to clean up after the conversion function
+         * 2. after the callback
+         * 3. after the callback again if there was truncated input
+         */
+        for(;;) {
+            /* update offsets if we write any */
+            if(offsets!=NULL) {
+                int32_t length=(int32_t)(pArgs->target-t);
+                if(length>0) {
+                    _updateOffsets(offsets, length, sourceIndex, errorInputLength);
+
+                    /*
+                     * if a converter handles offsets and updates the offsets
+                     * pointer at the end, then pArgs->offset should not change
+                     * here;
+                     * however, some converters do not handle offsets at all
+                     * (sourceIndex<0) or may not update the offsets pointer
+                     */
+                    pArgs->offsets=offsets+=length;
+                }
+
+                if(sourceIndex>=0) {
+                    sourceIndex+=(int32_t)(pArgs->source-s);
+                }
+            }
+
+            if(cnv->preToULength<0) {
+                /*
+                 * switch the source to new replay units (cannot occur while replaying)
+                 * after offset handling and before end-of-input and callback handling
+                 */
+                if(realSource==NULL) {
+                    realSource=pArgs->source;
+                    realSourceLimit=pArgs->sourceLimit;
+                    realFlush=pArgs->flush;
+                    realSourceIndex=sourceIndex;
+
+                    uprv_memcpy(replay, cnv->preToU, -cnv->preToULength);
+                    pArgs->source=replay;
+                    pArgs->sourceLimit=replay-cnv->preToULength;
+                    pArgs->flush=FALSE;
+                    if((sourceIndex+=cnv->preToULength)<0) {
+                        sourceIndex=-1;
+                    }
+
+                    cnv->preToULength=0;
+                } else {
+                    /* see implementation note before _fromUnicodeWithCallback() */
+                    U_ASSERT(realSource==NULL);
+                    *err=U_INTERNAL_PROGRAM_ERROR;
+                }
+            }
+
+            /* update pointers */
+            s=pArgs->source;
+            t=pArgs->target;
+
+            if(U_SUCCESS(*err)) {
+                if(s<pArgs->sourceLimit) {
+                    /*
+                     * continue with the conversion loop while there is still input left
+                     * (continue converting by breaking out of only the inner loop)
+                     */
+                    break;
+                } else if(realSource!=NULL) {
+                    /* switch back from replaying to the real source and continue */
+                    pArgs->source=realSource;
+                    pArgs->sourceLimit=realSourceLimit;
+                    pArgs->flush=realFlush;
+                    sourceIndex=realSourceIndex;
+
+                    realSource=NULL;
+                    break;
+                } else if(pArgs->flush && cnv->toULength>0) {
+                    /*
+                     * the entire input stream is consumed
+                     * and there is a partial, truncated input sequence left
+                     */
+
+                    /* inject an error and continue with callback handling */
+                    *err=U_TRUNCATED_CHAR_FOUND;
+                    calledCallback=FALSE; /* new error condition */
+                } else {
+                    /* input consumed */
+                    if(pArgs->flush) {
+                        /*
+                         * return to the conversion loop once more if the flush
+                         * flag is set and the conversion function has not
+                         * successfully processed the end of the input yet
+                         *
+                         * (continue converting by breaking out of only the inner loop)
+                         */
+                        if(!converterSawEndOfInput) {
+                            break;
+                        }
+
+                        /* reset the converter without calling the callback function */
+                        _reset(cnv, UCNV_RESET_TO_UNICODE, FALSE);
+                    }
+
+                    /* done successfully */
+                    return;
+                }
+            }
+
+            /* U_FAILURE(*err) */
+            {
+                UErrorCode e;
+
+                if( calledCallback ||
+                    (e=*err)==U_BUFFER_OVERFLOW_ERROR ||
+                    (e!=U_INVALID_CHAR_FOUND &&
+                     e!=U_ILLEGAL_CHAR_FOUND &&
+                     e!=U_TRUNCATED_CHAR_FOUND &&
+                     e!=U_ILLEGAL_ESCAPE_SEQUENCE &&
+                     e!=U_UNSUPPORTED_ESCAPE_SEQUENCE)
+                ) {
+                    /*
+                     * the callback did not or cannot resolve the error:
+                     * set output pointers and return
+                     *
+                     * the check for buffer overflow is redundant but it is
+                     * a high-runner case and hopefully documents the intent
+                     * well
+                     *
+                     * if we were replaying, then the replay buffer must be
+                     * copied back into the UConverter
+                     * and the real arguments must be restored
+                     */
+                    if(realSource!=NULL) {
+                        int32_t length;
+
+                        U_ASSERT(cnv->preToULength==0);
+
+                        length=(int32_t)(pArgs->sourceLimit-pArgs->source);
+                        if(length>0) {
+                            uprv_memcpy(cnv->preToU, pArgs->source, length);
+                            cnv->preToULength=(int8_t)-length;
+                        }
+
+                        pArgs->source=realSource;
+                        pArgs->sourceLimit=realSourceLimit;
+                        pArgs->flush=realFlush;
+                    }
+
+                    return;
+                }
+            }
+
+            /* copy toUBytes[] to invalidCharBuffer[] */
+            errorInputLength=cnv->invalidCharLength=cnv->toULength;
+            if(errorInputLength>0) {
+                uprv_memcpy(cnv->invalidCharBuffer, cnv->toUBytes, errorInputLength);
+            }
+
+            /* set the converter state to deal with the next character */
+            cnv->toULength=0;
+
+            /* call the callback function */
+            if(cnv->toUCallbackReason==UCNV_ILLEGAL && *err==U_INVALID_CHAR_FOUND) {
+                cnv->toUCallbackReason = UCNV_UNASSIGNED;
+            }
+            cnv->fromCharErrorBehaviour(cnv->toUContext, pArgs,
+                cnv->invalidCharBuffer, errorInputLength,
+                cnv->toUCallbackReason,
+                err);
+            cnv->toUCallbackReason = UCNV_ILLEGAL; /* reset to default value */
+
+            /*
+             * loop back to the offset handling
+             *
+             * this flag will indicate after offset handling
+             * that a callback was called;
+             * if the callback did not resolve the error, then we return
+             */
+            calledCallback=TRUE;
+        }
+    }
+}
+
+/*
+ * Output the toUnicode overflow buffer.
+ * Call this function if(cnv->UCharErrorBufferLength>0).
+ * @return TRUE if overflow
+ */
+static UBool
+ucnv_outputOverflowToUnicode(UConverter *cnv,
+                             UChar **target, const UChar *targetLimit,
+                             int32_t **pOffsets,
+                             UErrorCode *err) {
+    int32_t *offsets;
+    UChar *overflow, *t;
+    int32_t i, length;
+
+    t=*target;
+    if(pOffsets!=NULL) {
+        offsets=*pOffsets;
+    } else {
+        offsets=NULL;
+    }
+
+    overflow=cnv->UCharErrorBuffer;
+    length=cnv->UCharErrorBufferLength;
+    i=0;
+    while(i<length) {
+        if(t==targetLimit) {
+            /* the overflow buffer contains too much, keep the rest */
+            int32_t j=0;
+
+            do {
+                overflow[j++]=overflow[i++];
+            } while(i<length);
+
+            cnv->UCharErrorBufferLength=(int8_t)j;
+            *target=t;
+            if(offsets!=NULL) {
+                *pOffsets=offsets;
+            }
+            *err=U_BUFFER_OVERFLOW_ERROR;
+            return TRUE;
+        }
+
+        /* copy the overflow contents to the target */
+        *t++=overflow[i++];
+        if(offsets!=NULL) {
+            *offsets++=-1; /* no source index available for old output */
+        }
+    }
+
+    /* the overflow buffer is completely copied to the target */
+    cnv->UCharErrorBufferLength=0;
+    *target=t;
+    if(offsets!=NULL) {
+        *pOffsets=offsets;
+    }
+    return FALSE;
+}
+
+U_CAPI void U_EXPORT2
+ucnv_toUnicode(UConverter *cnv,
+               UChar **target, const UChar *targetLimit,
+               const char **source, const char *sourceLimit,
+               int32_t *offsets,
+               UBool flush,
+               UErrorCode *err) {
+    UConverterToUnicodeArgs args;
+    const char *s;
+    UChar *t;
+
+    /* check parameters */
+    if(err==NULL || U_FAILURE(*err)) {
+        return;
+    }
+
+    if(cnv==NULL || target==NULL || source==NULL) {
+        *err=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    s=*source;
+    t=*target;
+
+    if ((const void *)U_MAX_PTR(targetLimit) == (const void *)targetLimit) {
+        /*
+        Prevent code from going into an infinite loop in case we do hit this
+        limit. The limit pointer is expected to be on a UChar * boundary.
+        This also prevents the next argument check from failing.
+        */
+        targetLimit = (const UChar *)(((const char *)targetLimit) - 1);
+    }
+
+    /*
+     * All these conditions should never happen.
+     *
+     * 1) Make sure that the limits are >= to the address source or target
+     *
+     * 2) Make sure that the buffer sizes do not exceed the number range for
+     * int32_t because some functions use the size (in units or bytes)
+     * rather than comparing pointers, and because offsets are int32_t values.
+     *
+     * size_t is guaranteed to be unsigned and large enough for the job.
+     *
+     * Return with an error instead of adjusting the limits because we would
+     * not be able to maintain the semantics that either the source must be
+     * consumed or the target filled (unless an error occurs).
+     * An adjustment would be sourceLimit=t+0x7fffffff; for example.
+     *
+     * 3) Make sure that the user didn't incorrectly cast a UChar * pointer
+     * to a char * pointer and provide an incomplete UChar code unit.
+     */
+    if (sourceLimit<s || targetLimit<t ||
+        ((size_t)(sourceLimit-s)>(size_t)0x7fffffff && sourceLimit>s) ||
+        ((size_t)(targetLimit-t)>(size_t)0x3fffffff && targetLimit>t) ||
+        (((const char *)targetLimit-(const char *)t) & 1) != 0
+    ) {
+        *err=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    
+    /* output the target overflow buffer */
+    if( cnv->UCharErrorBufferLength>0 &&
+        ucnv_outputOverflowToUnicode(cnv, target, targetLimit, &offsets, err)
+    ) {
+        /* U_BUFFER_OVERFLOW_ERROR */
+        return;
+    }
+    /* *target may have moved, therefore stop using t */
+
+    if(!flush && s==sourceLimit && cnv->preToULength>=0) {
+        /* the overflow buffer is emptied and there is no new input: we are done */
+        return;
+    }
+
+    /*
+     * Do not simply return with a buffer overflow error if
+     * !flush && t==targetLimit
+     * because it is possible that the source will not generate any output.
+     * For example, the skip callback may be called;
+     * it does not output anything.
+     */
+
+    /* prepare the converter arguments */
+    args.converter=cnv;
+    args.flush=flush;
+    args.offsets=offsets;
+    args.source=s;
+    args.sourceLimit=sourceLimit;
+    args.target=*target;
+    args.targetLimit=targetLimit;
+    args.size=sizeof(args);
+
+    _toUnicodeWithCallback(&args, err);
+
+    *source=args.source;
+    *target=args.target;
+}
+
+/* ucnv_to/fromUChars() ----------------------------------------------------- */
+
+U_CAPI int32_t U_EXPORT2
+ucnv_fromUChars(UConverter *cnv,
+                char *dest, int32_t destCapacity,
+                const UChar *src, int32_t srcLength,
+                UErrorCode *pErrorCode) {
+    const UChar *srcLimit;
+    char *originalDest, *destLimit;
+    int32_t destLength;
+
+    /* check arguments */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    if( cnv==NULL ||
+        destCapacity<0 || (destCapacity>0 && dest==NULL) ||
+        srcLength<-1 || (srcLength!=0 && src==NULL)
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* initialize */
+    ucnv_resetFromUnicode(cnv);
+    originalDest=dest;
+    if(srcLength==-1) {
+        srcLength=u_strlen(src);
+    }
+    if(srcLength>0) {
+        srcLimit=src+srcLength;
+        destLimit=dest+destCapacity;
+
+        /* pin the destination limit to U_MAX_PTR; NULL check is for OS/400 */
+        if(destLimit<dest || (destLimit==NULL && dest!=NULL)) {
+            destLimit=(char *)U_MAX_PTR(dest);
+        }
+
+        /* perform the conversion */
+        ucnv_fromUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, pErrorCode);
+        destLength=(int32_t)(dest-originalDest);
+
+        /* if an overflow occurs, then get the preflighting length */
+        if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
+            char buffer[1024];
+
+            destLimit=buffer+sizeof(buffer);
+            do {
+                dest=buffer;
+                *pErrorCode=U_ZERO_ERROR;
+                ucnv_fromUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, pErrorCode);
+                destLength+=(int32_t)(dest-buffer);
+            } while(*pErrorCode==U_BUFFER_OVERFLOW_ERROR);
+        }
+    } else {
+        destLength=0;
+    }
+
+    return u_terminateChars(originalDest, destCapacity, destLength, pErrorCode);
+}
+
+U_CAPI int32_t U_EXPORT2
+ucnv_toUChars(UConverter *cnv,
+              UChar *dest, int32_t destCapacity,
+              const char *src, int32_t srcLength,
+              UErrorCode *pErrorCode) {
+    const char *srcLimit;
+    UChar *originalDest, *destLimit;
+    int32_t destLength;
+
+    /* check arguments */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    if( cnv==NULL ||
+        destCapacity<0 || (destCapacity>0 && dest==NULL) ||
+        srcLength<-1 || (srcLength!=0 && src==NULL))
+    {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* initialize */
+    ucnv_resetToUnicode(cnv);
+    originalDest=dest;
+    if(srcLength==-1) {
+        srcLength=(int32_t)uprv_strlen(src);
+    }
+    if(srcLength>0) {
+        srcLimit=src+srcLength;
+        destLimit=dest+destCapacity;
+
+        /* pin the destination limit to U_MAX_PTR; NULL check is for OS/400 */
+        if(destLimit<dest || (destLimit==NULL && dest!=NULL)) {
+            destLimit=(UChar *)U_MAX_PTR(dest);
+        }
+
+        /* perform the conversion */
+        ucnv_toUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, pErrorCode);
+        destLength=(int32_t)(dest-originalDest);
+
+        /* if an overflow occurs, then get the preflighting length */
+        if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR)
+        {
+            UChar buffer[1024];
+
+            destLimit=buffer+sizeof(buffer)/U_SIZEOF_UCHAR;
+            do {
+                dest=buffer;
+                *pErrorCode=U_ZERO_ERROR;
+                ucnv_toUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, pErrorCode);
+                destLength+=(int32_t)(dest-buffer);
+            }
+            while(*pErrorCode==U_BUFFER_OVERFLOW_ERROR);
+        }
+    } else {
+        destLength=0;
+    }
+
+    return u_terminateUChars(originalDest, destCapacity, destLength, pErrorCode);
+}
+
+/* ucnv_getNextUChar() ------------------------------------------------------ */
+
+U_CAPI UChar32 U_EXPORT2
+ucnv_getNextUChar(UConverter *cnv,
+                  const char **source, const char *sourceLimit,
+                  UErrorCode *err) {
+    UConverterToUnicodeArgs args;
+    UChar buffer[U16_MAX_LENGTH];
+    const char *s;
+    UChar32 c;
+    int32_t i, length;
+
+    /* check parameters */
+    if(err==NULL || U_FAILURE(*err)) {
+        return 0xffff;
+    }
+
+    if(cnv==NULL || source==NULL) {
+        *err=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0xffff;
+    }
+
+    s=*source;
+    if(sourceLimit<s) {
+        *err=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0xffff;
+    }
+
+    /*
+     * Make sure that the buffer sizes do not exceed the number range for
+     * int32_t because some functions use the size (in units or bytes)
+     * rather than comparing pointers, and because offsets are int32_t values.
+     *
+     * size_t is guaranteed to be unsigned and large enough for the job.
+     *
+     * Return with an error instead of adjusting the limits because we would
+     * not be able to maintain the semantics that either the source must be
+     * consumed or the target filled (unless an error occurs).
+     * An adjustment would be sourceLimit=t+0x7fffffff; for example.
+     */
+    if(((size_t)(sourceLimit-s)>(size_t)0x7fffffff && sourceLimit>s)) {
+        *err=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0xffff;
+    }
+
+    c=U_SENTINEL;
+
+    /* flush the target overflow buffer */
+    if(cnv->UCharErrorBufferLength>0) {
+        UChar *overflow;
+
+        overflow=cnv->UCharErrorBuffer;
+        i=0;
+        length=cnv->UCharErrorBufferLength;
+        U16_NEXT(overflow, i, length, c);
+
+        /* move the remaining overflow contents up to the beginning */
+        if((cnv->UCharErrorBufferLength=(int8_t)(length-i))>0) {
+            uprv_memmove(cnv->UCharErrorBuffer, cnv->UCharErrorBuffer+i,
+                         cnv->UCharErrorBufferLength*U_SIZEOF_UCHAR);
+        }
+
+        if(!U16_IS_LEAD(c) || i<length) {
+            return c;
+        }
+        /*
+         * Continue if the overflow buffer contained only a lead surrogate,
+         * in case the converter outputs single surrogates from complete
+         * input sequences.
+         */
+    }
+
+    /*
+     * flush==TRUE is implied for ucnv_getNextUChar()
+     *
+     * do not simply return even if s==sourceLimit because the converter may
+     * not have seen flush==TRUE before
+     */
+
+    /* prepare the converter arguments */
+    args.converter=cnv;
+    args.flush=TRUE;
+    args.offsets=NULL;
+    args.source=s;
+    args.sourceLimit=sourceLimit;
+    args.target=buffer;
+    args.targetLimit=buffer+1;
+    args.size=sizeof(args);
+
+    if(c<0) {
+        /*
+         * call the native getNextUChar() implementation if we are
+         * at a character boundary (toULength==0)
+         *
+         * unlike with _toUnicode(), getNextUChar() implementations must set
+         * U_TRUNCATED_CHAR_FOUND for truncated input,
+         * in addition to setting toULength/toUBytes[]
+         */
+        if(cnv->toULength==0 && cnv->sharedData->impl->getNextUChar!=NULL) {
+            c=cnv->sharedData->impl->getNextUChar(&args, err);
+            *source=s=args.source;
+            if(*err==U_INDEX_OUTOFBOUNDS_ERROR) {
+                /* reset the converter without calling the callback function */
+                _reset(cnv, UCNV_RESET_TO_UNICODE, FALSE);
+                return 0xffff; /* no output */
+            } else if(U_SUCCESS(*err) && c>=0) {
+                return c;
+            /*
+             * else fall through to use _toUnicode() because
+             *   UCNV_GET_NEXT_UCHAR_USE_TO_U: the native function did not want to handle it after all
+             *   U_FAILURE: call _toUnicode() for callback handling (do not output c)
+             */
+            }
+        }
+
+        /* convert to one UChar in buffer[0], or handle getNextUChar() errors */
+        _toUnicodeWithCallback(&args, err);
+
+        if(*err==U_BUFFER_OVERFLOW_ERROR) {
+            *err=U_ZERO_ERROR;
+        }
+
+        i=0;
+        length=(int32_t)(args.target-buffer);
+    } else {
+        /* write the lead surrogate from the overflow buffer */
+        buffer[0]=(UChar)c;
+        args.target=buffer+1;
+        i=0;
+        length=1;
+    }
+
+    /* buffer contents starts at i and ends before length */
+
+    if(U_FAILURE(*err)) {
+        c=0xffff; /* no output */
+    } else if(length==0) {
+        /* no input or only state changes */
+        *err=U_INDEX_OUTOFBOUNDS_ERROR;
+        /* no need to reset explicitly because _toUnicodeWithCallback() did it */
+        c=0xffff; /* no output */
+    } else {
+        c=buffer[0];
+        i=1;
+        if(!U16_IS_LEAD(c)) {
+            /* consume c=buffer[0], done */
+        } else {
+            /* got a lead surrogate, see if a trail surrogate follows */
+            UChar c2;
+
+            if(cnv->UCharErrorBufferLength>0) {
+                /* got overflow output from the conversion */
+                if(U16_IS_TRAIL(c2=cnv->UCharErrorBuffer[0])) {
+                    /* got a trail surrogate, too */
+                    c=U16_GET_SUPPLEMENTARY(c, c2);
+
+                    /* move the remaining overflow contents up to the beginning */
+                    if((--cnv->UCharErrorBufferLength)>0) {
+                        uprv_memmove(cnv->UCharErrorBuffer, cnv->UCharErrorBuffer+1,
+                                     cnv->UCharErrorBufferLength*U_SIZEOF_UCHAR);
+                    }
+                } else {
+                    /* c is an unpaired lead surrogate, just return it */
+                }
+            } else if(args.source<sourceLimit) {
+                /* convert once more, to buffer[1] */
+                args.targetLimit=buffer+2;
+                _toUnicodeWithCallback(&args, err);
+                if(*err==U_BUFFER_OVERFLOW_ERROR) {
+                    *err=U_ZERO_ERROR;
+                }
+
+                length=(int32_t)(args.target-buffer);
+                if(U_SUCCESS(*err) && length==2 && U16_IS_TRAIL(c2=buffer[1])) {
+                    /* got a trail surrogate, too */
+                    c=U16_GET_SUPPLEMENTARY(c, c2);
+                    i=2;
+                }
+            }
+        }
+    }
+
+    /*
+     * move leftover output from buffer[i..length[
+     * into the beginning of the overflow buffer
+     */
+    if(i<length) {
+        /* move further overflow back */
+        int32_t delta=length-i;
+        if((length=cnv->UCharErrorBufferLength)>0) {
+            uprv_memmove(cnv->UCharErrorBuffer+delta, cnv->UCharErrorBuffer,
+                         length*U_SIZEOF_UCHAR);
+        }
+        cnv->UCharErrorBufferLength=(int8_t)(length+delta);
+
+        cnv->UCharErrorBuffer[0]=buffer[i++];
+        if(delta>1) {
+            cnv->UCharErrorBuffer[1]=buffer[i];
+        }
+    }
+
+    *source=args.source;
+    return c;
+}
+
+/* ucnv_convert() and siblings ---------------------------------------------- */
+
+U_CAPI void U_EXPORT2
+ucnv_convertEx(UConverter *targetCnv, UConverter *sourceCnv,
+               char **target, const char *targetLimit,
+               const char **source, const char *sourceLimit,
+               UChar *pivotStart, UChar **pivotSource,
+               UChar **pivotTarget, const UChar *pivotLimit,
+               UBool reset, UBool flush,
+               UErrorCode *pErrorCode) {
+    UChar pivotBuffer[CHUNK_SIZE];
+    const UChar *myPivotSource;
+    UChar *myPivotTarget;
+    const char *s;
+    char *t;
+
+    UConverterToUnicodeArgs toUArgs;
+    UConverterFromUnicodeArgs fromUArgs;
+    UConverterConvert convert;
+
+    /* error checking */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return;
+    }
+
+    if( targetCnv==NULL || sourceCnv==NULL ||
+        source==NULL || *source==NULL ||
+        target==NULL || *target==NULL || targetLimit==NULL
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    s=*source;
+    t=*target;
+    if((sourceLimit!=NULL && sourceLimit<s) || targetLimit<t) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    /*
+     * Make sure that the buffer sizes do not exceed the number range for
+     * int32_t. See ucnv_toUnicode() for a more detailed comment.
+     */
+    if(
+        (sourceLimit!=NULL && ((size_t)(sourceLimit-s)>(size_t)0x7fffffff && sourceLimit>s)) ||
+        ((size_t)(targetLimit-t)>(size_t)0x7fffffff && targetLimit>t)
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    
+    if(pivotStart==NULL) {
+        if(!flush) {
+            /* streaming conversion requires an explicit pivot buffer */
+            *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+            return;
+        }
+
+        /* use the stack pivot buffer */
+        myPivotSource=myPivotTarget=pivotStart=pivotBuffer;
+        pivotSource=(UChar **)&myPivotSource;
+        pivotTarget=&myPivotTarget;
+        pivotLimit=pivotBuffer+CHUNK_SIZE;
+    } else if(  pivotStart>=pivotLimit ||
+                pivotSource==NULL || *pivotSource==NULL ||
+                pivotTarget==NULL || *pivotTarget==NULL ||
+                pivotLimit==NULL
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    if(sourceLimit==NULL) {
+        /* get limit of single-byte-NUL-terminated source string */
+        sourceLimit=uprv_strchr(*source, 0);
+    }
+
+    if(reset) {
+        ucnv_resetToUnicode(sourceCnv);
+        ucnv_resetFromUnicode(targetCnv);
+        *pivotSource=*pivotTarget=pivotStart;
+    } else if(targetCnv->charErrorBufferLength>0) {
+        /* output the targetCnv overflow buffer */
+        if(ucnv_outputOverflowFromUnicode(targetCnv, target, targetLimit, NULL, pErrorCode)) {
+            /* U_BUFFER_OVERFLOW_ERROR */
+            return;
+        }
+        /* *target has moved, therefore stop using t */
+
+        if( !flush &&
+            targetCnv->preFromULength>=0 && *pivotSource==*pivotTarget &&
+            sourceCnv->UCharErrorBufferLength==0 && sourceCnv->preToULength>=0 && s==sourceLimit
+        ) {
+            /* the fromUnicode overflow buffer is emptied and there is no new input: we are done */
+            return;
+        }
+    }
+
+    /* Is direct-UTF-8 conversion available? */
+    if( sourceCnv->sharedData->staticData->conversionType==UCNV_UTF8 &&
+        targetCnv->sharedData->impl->fromUTF8!=NULL
+    ) {
+        convert=targetCnv->sharedData->impl->fromUTF8;
+    } else if( targetCnv->sharedData->staticData->conversionType==UCNV_UTF8 &&
+               sourceCnv->sharedData->impl->toUTF8!=NULL
+    ) {
+        convert=sourceCnv->sharedData->impl->toUTF8;
+    } else {
+        convert=NULL;
+    }
+
+    /*
+     * If direct-UTF-8 conversion is available, then we use a smaller
+     * pivot buffer for error handling and partial matches
+     * so that we quickly return to direct conversion.
+     *
+     * 32 is large enough for UCNV_EXT_MAX_UCHARS and UCNV_ERROR_BUFFER_LENGTH.
+     *
+     * We could reduce the pivot buffer size further, at the cost of
+     * buffer overflows from callbacks.
+     * The pivot buffer should not be smaller than the maximum number of
+     * fromUnicode extension table input UChars
+     * (for m:n conversion, see
+     * targetCnv->sharedData->mbcs.extIndexes[UCNV_EXT_COUNT_UCHARS])
+     * or 2 for surrogate pairs.
+     *
+     * Too small a buffer can cause thrashing between pivoting and direct
+     * conversion, with function call overhead outweighing the benefits
+     * of direct conversion.
+     */
+    if(convert!=NULL && (pivotLimit-pivotStart)>32) {
+        pivotLimit=pivotStart+32;
+    }
+
+    /* prepare the converter arguments */
+    fromUArgs.converter=targetCnv;
+    fromUArgs.flush=FALSE;
+    fromUArgs.offsets=NULL;
+    fromUArgs.target=*target;
+    fromUArgs.targetLimit=targetLimit;
+    fromUArgs.size=sizeof(fromUArgs);
+
+    toUArgs.converter=sourceCnv;
+    toUArgs.flush=flush;
+    toUArgs.offsets=NULL;
+    toUArgs.source=s;
+    toUArgs.sourceLimit=sourceLimit;
+    toUArgs.targetLimit=pivotLimit;
+    toUArgs.size=sizeof(toUArgs);
+
+    /*
+     * TODO: Consider separating this function into two functions,
+     * extracting exactly the conversion loop,
+     * for readability and to reduce the set of visible variables.
+     *
+     * Otherwise stop using s and t from here on.
+     */
+    s=t=NULL;
+
+    /*
+     * conversion loop
+     *
+     * The sequence of steps in the loop may appear backward,
+     * but the principle is simple:
+     * In the chain of
+     *   source - sourceCnv overflow - pivot - targetCnv overflow - target
+     * empty out later buffers before refilling them from earlier ones.
+     *
+     * The targetCnv overflow buffer is flushed out only once before the loop.
+     */
+    for(;;) {
+        /*
+         * if(pivot not empty or error or replay or flush fromUnicode) {
+         *   fromUnicode(pivot -> target);
+         * }
+         *
+         * For pivoting conversion; and for direct conversion for
+         * error callback handling and flushing the replay buffer.
+         */
+        if( *pivotSource<*pivotTarget ||
+            U_FAILURE(*pErrorCode) ||
+            targetCnv->preFromULength<0 ||
+            fromUArgs.flush
+        ) {
+            fromUArgs.source=*pivotSource;
+            fromUArgs.sourceLimit=*pivotTarget;
+            _fromUnicodeWithCallback(&fromUArgs, pErrorCode);
+            if(U_FAILURE(*pErrorCode)) {
+                /* target overflow, or conversion error */
+                *pivotSource=(UChar *)fromUArgs.source;
+                break;
+            }
+
+            /*
+             * _fromUnicodeWithCallback() must have consumed the pivot contents
+             * (*pivotSource==*pivotTarget) since it returned with U_SUCCESS()
+             */
+        }
+
+        /* The pivot buffer is empty; reset it so we start at pivotStart. */
+        *pivotSource=*pivotTarget=pivotStart;
+
+        /*
+         * if(sourceCnv overflow buffer not empty) {
+         *     move(sourceCnv overflow buffer -> pivot);
+         *     continue;
+         * }
+         */
+        /* output the sourceCnv overflow buffer */
+        if(sourceCnv->UCharErrorBufferLength>0) {
+            if(ucnv_outputOverflowToUnicode(sourceCnv, pivotTarget, pivotLimit, NULL, pErrorCode)) {
+                /* U_BUFFER_OVERFLOW_ERROR */
+                *pErrorCode=U_ZERO_ERROR;
+            }
+            continue;
+        }
+
+        /*
+         * check for end of input and break if done
+         *
+         * Checking both flush and fromUArgs.flush ensures that the converters
+         * have been called with the flush flag set if the ucnv_convertEx()
+         * caller set it.
+         */
+        if( toUArgs.source==sourceLimit &&
+            sourceCnv->preToULength>=0 && sourceCnv->toULength==0 &&
+            (!flush || fromUArgs.flush)
+        ) {
+            /* done successfully */
+            break;
+        }
+
+        /*
+         * use direct conversion if available
+         * but not if continuing a partial match
+         * or flushing the toUnicode replay buffer
+         */
+        if(convert!=NULL && targetCnv->preFromUFirstCP<0 && sourceCnv->preToULength==0) {
+            if(*pErrorCode==U_USING_DEFAULT_WARNING) {
+                /* remove a warning that may be set by this function */
+                *pErrorCode=U_ZERO_ERROR;
+            }
+            convert(&fromUArgs, &toUArgs, pErrorCode);
+            if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
+                break;
+            } else if(U_FAILURE(*pErrorCode)) {
+                if(sourceCnv->toULength>0) {
+                    /*
+                     * Fall through to calling _toUnicodeWithCallback()
+                     * for callback handling.
+                     *
+                     * The pivot buffer will be reset with
+                     *   *pivotSource=*pivotTarget=pivotStart;
+                     * which indicates a toUnicode error to the caller
+                     * (*pivotSource==pivotStart shows no pivot UChars consumed).
+                     */
+                } else {
+                    /*
+                     * Indicate a fromUnicode error to the caller
+                     * (*pivotSource>pivotStart shows some pivot UChars consumed).
+                     */
+                    *pivotSource=*pivotTarget=pivotStart+1;
+                    /*
+                     * Loop around to calling _fromUnicodeWithCallbacks()
+                     * for callback handling.
+                     */
+                    continue;
+                }
+            } else if(*pErrorCode==U_USING_DEFAULT_WARNING) {
+                /*
+                 * No error, but the implementation requested to temporarily
+                 * fall back to pivoting.
+                 */
+                *pErrorCode=U_ZERO_ERROR;
+            /*
+             * The following else branches are almost identical to the end-of-input
+             * handling in _toUnicodeWithCallback().
+             * Avoid calling it just for the end of input.
+             */
+            } else if(flush && sourceCnv->toULength>0) { /* flush==toUArgs.flush */
+                /*
+                 * the entire input stream is consumed
+                 * and there is a partial, truncated input sequence left
+                 */
+
+                /* inject an error and continue with callback handling */
+                *pErrorCode=U_TRUNCATED_CHAR_FOUND;
+            } else {
+                /* input consumed */
+                if(flush) {
+                    /* reset the converters without calling the callback functions */
+                    _reset(sourceCnv, UCNV_RESET_TO_UNICODE, FALSE);
+                    _reset(targetCnv, UCNV_RESET_FROM_UNICODE, FALSE);
+                }
+
+                /* done successfully */
+                break;
+            }
+        }
+        
+        /*
+         * toUnicode(source -> pivot);
+         *
+         * For pivoting conversion; and for direct conversion for
+         * error callback handling, continuing partial matches
+         * and flushing the replay buffer.
+         *
+         * The pivot buffer is empty and reset.
+         */
+        toUArgs.target=pivotStart; /* ==*pivotTarget */
+        /* toUArgs.targetLimit=pivotLimit; already set before the loop */
+        _toUnicodeWithCallback(&toUArgs, pErrorCode);
+        *pivotTarget=toUArgs.target;
+        if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
+            /* pivot overflow: continue with the conversion loop */
+            *pErrorCode=U_ZERO_ERROR;
+        } else if(U_FAILURE(*pErrorCode) || (!flush && *pivotTarget==pivotStart)) {
+            /* conversion error, or there was nothing left to convert */
+            break;
+        }
+        /*
+         * else:
+         * _toUnicodeWithCallback() wrote into the pivot buffer,
+         * continue with fromUnicode conversion.
+         *
+         * Set the fromUnicode flush flag if we flush and if toUnicode has
+         * processed the end of the input.
+         */
+        if( flush && toUArgs.source==sourceLimit &&
+            sourceCnv->preToULength>=0 &&
+            sourceCnv->UCharErrorBufferLength==0
+        ) {
+            fromUArgs.flush=TRUE;
+        }
+    }
+
+    /*
+     * The conversion loop is exited when one of the following is true:
+     * - the entire source text has been converted successfully to the target buffer
+     * - a target buffer overflow occurred
+     * - a conversion error occurred
+     */
+
+    *source=toUArgs.source;
+    *target=fromUArgs.target;
+
+    /* terminate the target buffer if possible */
+    if(flush && U_SUCCESS(*pErrorCode)) {
+        if(*target!=targetLimit) {
+            **target=0;
+            if(*pErrorCode==U_STRING_NOT_TERMINATED_WARNING) {
+                *pErrorCode=U_ZERO_ERROR;
+            }
+        } else {
+            *pErrorCode=U_STRING_NOT_TERMINATED_WARNING;
+        }
+    }
+}
+
+/* internal implementation of ucnv_convert() etc. with preflighting */
+static int32_t
+ucnv_internalConvert(UConverter *outConverter, UConverter *inConverter,
+                     char *target, int32_t targetCapacity,
+                     const char *source, int32_t sourceLength,
+                     UErrorCode *pErrorCode) {
+    UChar pivotBuffer[CHUNK_SIZE];
+    UChar *pivot, *pivot2;
+
+    char *myTarget;
+    const char *sourceLimit;
+    const char *targetLimit;
+    int32_t targetLength=0;
+
+    /* set up */
+    if(sourceLength<0) {
+        sourceLimit=uprv_strchr(source, 0);
+    } else {
+        sourceLimit=source+sourceLength;
+    }
+
+    /* if there is no input data, we're done */
+    if(source==sourceLimit) {
+        return u_terminateChars(target, targetCapacity, 0, pErrorCode);
+    }
+
+    pivot=pivot2=pivotBuffer;
+    myTarget=target;
+    targetLength=0;
+
+    if(targetCapacity>0) {
+        /* perform real conversion */
+        targetLimit=target+targetCapacity;
+        ucnv_convertEx(outConverter, inConverter,
+                       &myTarget, targetLimit,
+                       &source, sourceLimit,
+                       pivotBuffer, &pivot, &pivot2, pivotBuffer+CHUNK_SIZE,
+                       FALSE,
+                       TRUE,
+                       pErrorCode);
+        targetLength=(int32_t)(myTarget-target);
+    }
+
+    /*
+     * If the output buffer is exhausted (or we are only "preflighting"), we need to stop writing
+     * to it but continue the conversion in order to store in targetCapacity
+     * the number of bytes that was required.
+     */
+    if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR || targetCapacity==0)
+    {
+        char targetBuffer[CHUNK_SIZE];
+
+        targetLimit=targetBuffer+CHUNK_SIZE;
+        do {
+            *pErrorCode=U_ZERO_ERROR;
+            myTarget=targetBuffer;
+            ucnv_convertEx(outConverter, inConverter,
+                           &myTarget, targetLimit,
+                           &source, sourceLimit,
+                           pivotBuffer, &pivot, &pivot2, pivotBuffer+CHUNK_SIZE,
+                           FALSE,
+                           TRUE,
+                           pErrorCode);
+            targetLength+=(int32_t)(myTarget-targetBuffer);
+        } while(*pErrorCode==U_BUFFER_OVERFLOW_ERROR);
+
+        /* done with preflighting, set warnings and errors as appropriate */
+        return u_terminateChars(target, targetCapacity, targetLength, pErrorCode);
+    }
+
+    /* no need to call u_terminateChars() because ucnv_convertEx() took care of that */
+    return targetLength;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucnv_convert(const char *toConverterName, const char *fromConverterName,
+             char *target, int32_t targetCapacity,
+             const char *source, int32_t sourceLength,
+             UErrorCode *pErrorCode) {
+    UConverter in, out; /* stack-allocated */
+    UConverter *inConverter, *outConverter;
+    int32_t targetLength;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    if( source==NULL || sourceLength<-1 ||
+        targetCapacity<0 || (targetCapacity>0 && target==NULL)
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* if there is no input data, we're done */
+    if(sourceLength==0 || (sourceLength<0 && *source==0)) {
+        return u_terminateChars(target, targetCapacity, 0, pErrorCode);
+    }
+
+    /* create the converters */
+    inConverter=ucnv_createConverter(&in, fromConverterName, pErrorCode);
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    outConverter=ucnv_createConverter(&out, toConverterName, pErrorCode);
+    if(U_FAILURE(*pErrorCode)) {
+        ucnv_close(inConverter);
+        return 0;
+    }
+
+    targetLength=ucnv_internalConvert(outConverter, inConverter,
+                                      target, targetCapacity,
+                                      source, sourceLength,
+                                      pErrorCode);
+
+    ucnv_close(inConverter);
+    ucnv_close(outConverter);
+
+    return targetLength;
+}
+
+/* @internal */
+static int32_t
+ucnv_convertAlgorithmic(UBool convertToAlgorithmic,
+                        UConverterType algorithmicType,
+                        UConverter *cnv,
+                        char *target, int32_t targetCapacity,
+                        const char *source, int32_t sourceLength,
+                        UErrorCode *pErrorCode) {
+    UConverter algoConverterStatic; /* stack-allocated */
+    UConverter *algoConverter, *to, *from;
+    int32_t targetLength;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    if( cnv==NULL || source==NULL || sourceLength<-1 ||
+        targetCapacity<0 || (targetCapacity>0 && target==NULL)
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* if there is no input data, we're done */
+    if(sourceLength==0 || (sourceLength<0 && *source==0)) {
+        return u_terminateChars(target, targetCapacity, 0, pErrorCode);
+    }
+
+    /* create the algorithmic converter */
+    algoConverter=ucnv_createAlgorithmicConverter(&algoConverterStatic, algorithmicType,
+                                                  "", 0, pErrorCode);
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    /* reset the other converter */
+    if(convertToAlgorithmic) {
+        /* cnv->Unicode->algo */
+        ucnv_resetToUnicode(cnv);
+        to=algoConverter;
+        from=cnv;
+    } else {
+        /* algo->Unicode->cnv */
+        ucnv_resetFromUnicode(cnv);
+        from=algoConverter;
+        to=cnv;
+    }
+
+    targetLength=ucnv_internalConvert(to, from,
+                                      target, targetCapacity,
+                                      source, sourceLength,
+                                      pErrorCode);
+
+    ucnv_close(algoConverter);
+
+    return targetLength;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucnv_toAlgorithmic(UConverterType algorithmicType,
+                   UConverter *cnv,
+                   char *target, int32_t targetCapacity,
+                   const char *source, int32_t sourceLength,
+                   UErrorCode *pErrorCode) {
+    return ucnv_convertAlgorithmic(TRUE, algorithmicType, cnv,
+                                   target, targetCapacity,
+                                   source, sourceLength,
+                                   pErrorCode);
+}
+
+U_CAPI int32_t U_EXPORT2
+ucnv_fromAlgorithmic(UConverter *cnv,
+                     UConverterType algorithmicType,
+                     char *target, int32_t targetCapacity,
+                     const char *source, int32_t sourceLength,
+                     UErrorCode *pErrorCode) {
+    return ucnv_convertAlgorithmic(FALSE, algorithmicType, cnv,
+                                   target, targetCapacity,
+                                   source, sourceLength,
+                                   pErrorCode);
+}
+
+U_CAPI UConverterType  U_EXPORT2
+ucnv_getType(const UConverter* converter)
+{
+    int8_t type = converter->sharedData->staticData->conversionType;
+#if !UCONFIG_NO_LEGACY_CONVERSION
+    if(type == UCNV_MBCS) {
+        return ucnv_MBCSGetType(converter);
+    }
+#endif
+    return (UConverterType)type;
+}
+
+U_CAPI void  U_EXPORT2
+ucnv_getStarters(const UConverter* converter, 
+                 UBool starters[256],
+                 UErrorCode* err)
+{
+    if (err == NULL || U_FAILURE(*err)) {
+        return;
+    }
+
+    if(converter->sharedData->impl->getStarters != NULL) {
+        converter->sharedData->impl->getStarters(converter, starters, err);
+    } else {
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+    }
+}
+
+static const UAmbiguousConverter *ucnv_getAmbiguous(const UConverter *cnv)
+{
+    UErrorCode errorCode;
+    const char *name;
+    int32_t i;
+
+    if(cnv==NULL) {
+        return NULL;
+    }
+
+    errorCode=U_ZERO_ERROR;
+    name=ucnv_getName(cnv, &errorCode);
+    if(U_FAILURE(errorCode)) {
+        return NULL;
+    }
+
+    for(i=0; i<(int32_t)(sizeof(ambiguousConverters)/sizeof(UAmbiguousConverter)); ++i)
+    {
+        if(0==uprv_strcmp(name, ambiguousConverters[i].name))
+        {
+            return ambiguousConverters+i;
+        }
+    }
+
+    return NULL;
+}
+
+U_CAPI void  U_EXPORT2
+ucnv_fixFileSeparator(const UConverter *cnv, 
+                      UChar* source, 
+                      int32_t sourceLength) {
+    const UAmbiguousConverter *a;
+    int32_t i;
+    UChar variant5c;
+
+    if(cnv==NULL || source==NULL || sourceLength<=0 || (a=ucnv_getAmbiguous(cnv))==NULL)
+    {
+        return;
+    }
+
+    variant5c=a->variant5c;
+    for(i=0; i<sourceLength; ++i) {
+        if(source[i]==variant5c) {
+            source[i]=0x5c;
+        }
+    }
+}
+
+U_CAPI UBool  U_EXPORT2
+ucnv_isAmbiguous(const UConverter *cnv) {
+    return (UBool)(ucnv_getAmbiguous(cnv)!=NULL);
+}
+
+U_CAPI void  U_EXPORT2
+ucnv_setFallback(UConverter *cnv, UBool usesFallback)
+{
+    cnv->useFallback = usesFallback;
+}
+
+U_CAPI UBool  U_EXPORT2
+ucnv_usesFallback(const UConverter *cnv)
+{
+    return cnv->useFallback;
+}
+
+U_CAPI void  U_EXPORT2
+ucnv_getInvalidChars (const UConverter * converter,
+                      char *errBytes,
+                      int8_t * len,
+                      UErrorCode * err)
+{
+    if (err == NULL || U_FAILURE(*err))
+    {
+        return;
+    }
+    if (len == NULL || errBytes == NULL || converter == NULL)
+    {
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    if (*len < converter->invalidCharLength)
+    {
+        *err = U_INDEX_OUTOFBOUNDS_ERROR;
+        return;
+    }
+    if ((*len = converter->invalidCharLength) > 0)
+    {
+        uprv_memcpy (errBytes, converter->invalidCharBuffer, *len);
+    }
+}
+
+U_CAPI void  U_EXPORT2
+ucnv_getInvalidUChars (const UConverter * converter,
+                       UChar *errChars,
+                       int8_t * len,
+                       UErrorCode * err)
+{
+    if (err == NULL || U_FAILURE(*err))
+    {
+        return;
+    }
+    if (len == NULL || errChars == NULL || converter == NULL)
+    {
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    if (*len < converter->invalidUCharLength)
+    {
+        *err = U_INDEX_OUTOFBOUNDS_ERROR;
+        return;
+    }
+    if ((*len = converter->invalidUCharLength) > 0)
+    {
+        uprv_memcpy (errChars, converter->invalidUCharBuffer, sizeof(UChar) * (*len));
+    }
+}
+
+#define SIG_MAX_LEN 5
+
+U_CAPI const char* U_EXPORT2
+ucnv_detectUnicodeSignature( const char* source,
+                             int32_t sourceLength,
+                             int32_t* signatureLength,
+                             UErrorCode* pErrorCode) {
+    int32_t dummy;
+
+    /* initial 0xa5 bytes: make sure that if we read <SIG_MAX_LEN
+     * bytes we don't misdetect something 
+     */
+    char start[SIG_MAX_LEN]={ '\xa5', '\xa5', '\xa5', '\xa5', '\xa5' };
+    int i = 0;
+
+    if((pErrorCode==NULL) || U_FAILURE(*pErrorCode)){
+        return NULL;
+    }
+    
+    if(source == NULL || sourceLength < -1){
+        *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    if(signatureLength == NULL) {
+        signatureLength = &dummy;
+    }
+
+    if(sourceLength==-1){
+        sourceLength=(int32_t)uprv_strlen(source);
+    }
+
+    
+    while(i<sourceLength&& i<SIG_MAX_LEN){
+        start[i]=source[i];
+        i++;
+    }
+
+    if(start[0] == '\xFE' && start[1] == '\xFF') {
+        *signatureLength=2;
+        return  "UTF-16BE";
+    } else if(start[0] == '\xFF' && start[1] == '\xFE') {
+        if(start[2] == '\x00' && start[3] =='\x00') {
+            *signatureLength=4;
+            return "UTF-32LE";
+        } else {
+            *signatureLength=2;
+            return  "UTF-16LE";
+        }
+    } else if(start[0] == '\xEF' && start[1] == '\xBB' && start[2] == '\xBF') {
+        *signatureLength=3;
+        return  "UTF-8";
+    } else if(start[0] == '\x00' && start[1] == '\x00' && 
+              start[2] == '\xFE' && start[3]=='\xFF') {
+        *signatureLength=4;
+        return  "UTF-32BE";
+    } else if(start[0] == '\x0E' && start[1] == '\xFE' && start[2] == '\xFF') {
+        *signatureLength=3;
+        return "SCSU";
+    } else if(start[0] == '\xFB' && start[1] == '\xEE' && start[2] == '\x28') {
+        *signatureLength=3;
+        return "BOCU-1";
+    } else if(start[0] == '\x2B' && start[1] == '\x2F' && start[2] == '\x76') {
+        /*
+         * UTF-7: Initial U+FEFF is encoded as +/v8  or  +/v9  or  +/v+  or  +/v/
+         * depending on the second UTF-16 code unit.
+         * Detect the entire, closed Unicode mode sequence +/v8- for only U+FEFF
+         * if it occurs.
+         *
+         * So far we have +/v
+         */
+        if(start[3] == '\x38' && start[4] == '\x2D') {
+            /* 5 bytes +/v8- */
+            *signatureLength=5;
+            return "UTF-7";
+        } else if(start[3] == '\x38' || start[3] == '\x39' || start[3] == '\x2B' || start[3] == '\x2F') {
+            /* 4 bytes +/v8  or  +/v9  or  +/v+  or  +/v/ */
+            *signatureLength=4;
+            return "UTF-7";
+        }
+    }else if(start[0]=='\xDD' && start[1]== '\x73'&& start[2]=='\x66' && start[3]=='\x73'){
+        *signatureLength=4;
+        return "UTF-EBCDIC";
+    }
+
+
+    /* no known Unicode signature byte sequence recognized */
+    *signatureLength=0;
+    return NULL;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucnv_fromUCountPending(const UConverter* cnv, UErrorCode* status)
+{
+    if(status == NULL || U_FAILURE(*status)){
+        return -1;
+    }
+    if(cnv == NULL){
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return -1;
+    }
+
+    if(cnv->preFromULength > 0){
+        return U16_LENGTH(cnv->preFromUFirstCP)+cnv->preFromULength ;
+    }else if(cnv->preFromULength < 0){
+        return -cnv->preFromULength ;
+    }else if(cnv->fromUChar32 > 0){
+        return 1;
+    }else if(cnv->preFromUFirstCP >0){
+        return U16_LENGTH(cnv->preFromUFirstCP);
+    }
+    return 0; 
+
+}
+
+U_CAPI int32_t U_EXPORT2
+ucnv_toUCountPending(const UConverter* cnv, UErrorCode* status){
+
+    if(status == NULL || U_FAILURE(*status)){
+        return -1;
+    }
+    if(cnv == NULL){
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return -1;
+    }
+
+    if(cnv->preToULength > 0){
+        return cnv->preToULength ;
+    }else if(cnv->preToULength < 0){
+        return -cnv->preToULength;
+    }else if(cnv->toULength > 0){
+        return cnv->toULength;
+    }
+    return 0;
+}
+#endif
+
+/*
+ * Hey, Emacs, please set the following:
+ *
+ * Local Variables:
+ * indent-tabs-mode: nil
+ * End:
+ *
+ */
diff --git a/source/common/ucnv2022.c b/source/common/ucnv2022.c
new file mode 100644
index 0000000..22ebe24
--- /dev/null
+++ b/source/common/ucnv2022.c
@@ -0,0 +1,3917 @@
+/*
+**********************************************************************
+*   Copyright (C) 2000-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   file name:  ucnv2022.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2000feb03
+*   created by: Markus W. Scherer
+*
+*   Change history:
+*
+*   06/29/2000  helena  Major rewrite of the callback APIs.
+*   08/08/2000  Ram     Included support for ISO-2022-JP-2
+*                       Changed implementation of toUnicode
+*                       function
+*   08/21/2000  Ram     Added support for ISO-2022-KR
+*   08/29/2000  Ram     Seperated implementation of EBCDIC to
+*                       ucnvebdc.c
+*   09/20/2000  Ram     Added support for ISO-2022-CN
+*                       Added implementations for getNextUChar()
+*                       for specific 2022 country variants.
+*   10/31/2000  Ram     Implemented offsets logic functions
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION && !UCONFIG_NO_LEGACY_CONVERSION
+
+#include "unicode/ucnv.h"
+#include "unicode/uset.h"
+#include "unicode/ucnv_err.h"
+#include "unicode/ucnv_cb.h"
+#include "ucnv_imp.h"
+#include "ucnv_bld.h"
+#include "ucnv_cnv.h"
+#include "ucnvmbcs.h"
+#include "cstring.h"
+#include "cmemory.h"
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+#ifdef U_ENABLE_GENERIC_ISO_2022
+/*
+ * I am disabling the generic ISO-2022 converter after proposing to do so on
+ * the icu mailing list two days ago.
+ *
+ * Reasons:
+ * 1. It does not fully support the ISO-2022/ECMA-35 specification with all of
+ *    its designation sequences, single shifts with return to the previous state,
+ *    switch-with-no-return to UTF-16BE or similar, etc.
+ *    This is unlike the language-specific variants like ISO-2022-JP which
+ *    require a much smaller repertoire of ISO-2022 features.
+ *    These variants continue to be supported.
+ * 2. I believe that no one is really using the generic ISO-2022 converter
+ *    but rather always one of the language-specific variants.
+ *    Note that ICU's generic ISO-2022 converter has always output one escape
+ *    sequence followed by UTF-8 for the whole stream.
+ * 3. Switching between subcharsets is extremely slow, because each time
+ *    the previous converter is closed and a new one opened,
+ *    without any kind of caching, least-recently-used list, etc.
+ * 4. The code is currently buggy, and given the above it does not seem
+ *    reasonable to spend the time on maintenance.
+ * 5. ISO-2022 subcharsets should normally be used with 7-bit byte encodings.
+ *    This means, for example, that when ISO-8859-7 is designated, the following
+ *    ISO-2022 bytes 00..7f should be interpreted as ISO-8859-7 bytes 80..ff.
+ *    The ICU ISO-2022 converter does not handle this - and has no information
+ *    about which subconverter would have to be shifted vs. which is designed
+ *    for 7-bit ISO-2022.
+ *
+ * Markus Scherer 2003-dec-03
+ */
+#endif
+
+static const char SHIFT_IN_STR[]  = "\x0F";
+static const char SHIFT_OUT_STR[] = "\x0E";
+
+#define CR      0x0D
+#define LF      0x0A
+#define H_TAB   0x09
+#define V_TAB   0x0B
+#define SPACE   0x20
+
+enum {
+    HWKANA_START=0xff61,
+    HWKANA_END=0xff9f
+};
+
+/*
+ * 94-character sets with native byte values A1..FE are encoded in ISO 2022
+ * as bytes 21..7E. (Subtract 0x80.)
+ * 96-character sets with native byte values A0..FF are encoded in ISO 2022
+ * as bytes 20..7F. (Subtract 0x80.)
+ * Do not encode C1 control codes with native bytes 80..9F
+ * as bytes 00..1F (C0 control codes).
+ */
+enum {
+    GR94_START=0xa1,
+    GR94_END=0xfe,
+    GR96_START=0xa0,
+    GR96_END=0xff
+};
+
+/*
+ * ISO 2022 control codes must not be converted from Unicode
+ * because they would mess up the byte stream.
+ * The bit mask 0x0800c000 has bits set at bit positions 0xe, 0xf, 0x1b
+ * corresponding to SO, SI, and ESC.
+ */
+#define IS_2022_CONTROL(c) (((c)<0x20) && (((uint32_t)1<<(c))&0x0800c000)!=0)
+
+/* for ISO-2022-JP and -CN implementations */
+typedef enum  {
+        /* shared values */
+        INVALID_STATE=-1,
+        ASCII = 0,
+
+        SS2_STATE=0x10,
+        SS3_STATE,
+
+        /* JP */
+        ISO8859_1 = 1 ,
+        ISO8859_7 = 2 ,
+        JISX201  = 3,
+        JISX208 = 4,
+        JISX212 = 5,
+        GB2312  =6,
+        KSC5601 =7,
+        HWKANA_7BIT=8,    /* Halfwidth Katakana 7 bit */
+
+        /* CN */
+        /* the first few enum constants must keep their values because they correspond to myConverterArray[] */
+        GB2312_1=1,
+        ISO_IR_165=2,
+        CNS_11643=3,
+
+        /*
+         * these are used in StateEnum and ISO2022State variables,
+         * but CNS_11643 must be used to index into myConverterArray[]
+         */
+        CNS_11643_0=0x20,
+        CNS_11643_1,
+        CNS_11643_2,
+        CNS_11643_3,
+        CNS_11643_4,
+        CNS_11643_5,
+        CNS_11643_6,
+        CNS_11643_7
+} StateEnum;
+
+/* is the StateEnum charset value for a DBCS charset? */
+#define IS_JP_DBCS(cs) (JISX208<=(cs) && (cs)<=KSC5601)
+
+#define CSM(cs) ((uint16_t)1<<(cs))
+
+/*
+ * Each of these charset masks (with index x) contains a bit for a charset in exact correspondence
+ * to whether that charset is used in the corresponding version x of ISO_2022,locale=ja,version=x
+ *
+ * Note: The converter uses some leniency:
+ * - The escape sequence ESC ( I for half-width 7-bit Katakana is recognized in
+ *   all versions, not just JIS7 and JIS8.
+ * - ICU does not distinguish between different versions of JIS X 0208.
+ */
+enum { MAX_JA_VERSION=4 };
+static const uint16_t jpCharsetMasks[MAX_JA_VERSION+1]={
+    CSM(ASCII)|CSM(JISX201)|CSM(JISX208)|CSM(HWKANA_7BIT),
+    CSM(ASCII)|CSM(JISX201)|CSM(JISX208)|CSM(HWKANA_7BIT)|CSM(JISX212),
+    CSM(ASCII)|CSM(JISX201)|CSM(JISX208)|CSM(HWKANA_7BIT)|CSM(JISX212)|CSM(GB2312)|CSM(KSC5601)|CSM(ISO8859_1)|CSM(ISO8859_7),
+    CSM(ASCII)|CSM(JISX201)|CSM(JISX208)|CSM(HWKANA_7BIT)|CSM(JISX212)|CSM(GB2312)|CSM(KSC5601)|CSM(ISO8859_1)|CSM(ISO8859_7),
+    CSM(ASCII)|CSM(JISX201)|CSM(JISX208)|CSM(HWKANA_7BIT)|CSM(JISX212)|CSM(GB2312)|CSM(KSC5601)|CSM(ISO8859_1)|CSM(ISO8859_7)
+};
+
+typedef enum {
+        ASCII1=0,
+        LATIN1,
+        SBCS,
+        DBCS,
+        MBCS,
+        HWKANA
+}Cnv2022Type;
+
+typedef struct ISO2022State {
+    int8_t cs[4];       /* charset number for SI (G0)/SO (G1)/SS2 (G2)/SS3 (G3) */
+    int8_t g;           /* 0..3 for G0..G3 (SI/SO/SS2/SS3) */
+    int8_t prevG;       /* g before single shift (SS2 or SS3) */
+} ISO2022State;
+
+#define UCNV_OPTIONS_VERSION_MASK 0xf
+#define UCNV_2022_MAX_CONVERTERS 10
+
+typedef struct{
+    UConverterSharedData *myConverterArray[UCNV_2022_MAX_CONVERTERS];
+    UConverter *currentConverter;
+    Cnv2022Type currentType;
+    ISO2022State toU2022State, fromU2022State;
+    uint32_t key;
+    uint32_t version;
+#ifdef U_ENABLE_GENERIC_ISO_2022
+    UBool isFirstBuffer;
+#endif
+    UBool isEmptySegment;
+    char name[30];
+    char locale[3];
+}UConverterDataISO2022;
+
+/* Protos */
+/* ISO-2022 ----------------------------------------------------------------- */
+
+/*Forward declaration */
+U_CFUNC void
+ucnv_fromUnicode_UTF8(UConverterFromUnicodeArgs * args,
+                      UErrorCode * err);
+U_CFUNC void
+ucnv_fromUnicode_UTF8_OFFSETS_LOGIC(UConverterFromUnicodeArgs * args,
+                                    UErrorCode * err);
+
+#define ESC_2022 0x1B /*ESC*/
+
+typedef enum
+{
+        INVALID_2022 = -1, /*Doesn't correspond to a valid iso 2022 escape sequence*/
+        VALID_NON_TERMINAL_2022 = 0, /*so far corresponds to a valid iso 2022 escape sequence*/
+        VALID_TERMINAL_2022 = 1, /*corresponds to a valid iso 2022 escape sequence*/
+        VALID_MAYBE_TERMINAL_2022 = 2 /*so far matches one iso 2022 escape sequence, but by adding more characters might match another escape sequence*/
+} UCNV_TableStates_2022;
+
+/*
+* The way these state transition arrays work is:
+* ex : ESC$B is the sequence for JISX208
+*      a) First Iteration: char is ESC
+*          i) Get the value of ESC from normalize_esq_chars_2022[] with int value of ESC as index
+*             int x = normalize_esq_chars_2022[27] which is equal to 1
+*         ii) Search for this value in escSeqStateTable_Key_2022[]
+*             value of x is stored at escSeqStateTable_Key_2022[0]
+*        iii) Save this index as offset
+*         iv) Get state of this sequence from escSeqStateTable_Value_2022[]
+*             escSeqStateTable_Value_2022[offset], which is VALID_NON_TERMINAL_2022
+*     b) Switch on this state and continue to next char
+*          i) Get the value of $ from normalize_esq_chars_2022[] with int value of $ as index
+*             which is normalize_esq_chars_2022[36] == 4
+*         ii) x is currently 1(from above)
+*               x<<=5 -- x is now 32
+*               x+=normalize_esq_chars_2022[36]
+*               now x is 36
+*        iii) Search for this value in escSeqStateTable_Key_2022[]
+*             value of x is stored at escSeqStateTable_Key_2022[2], so offset is 2
+*         iv) Get state of this sequence from escSeqStateTable_Value_2022[]
+*             escSeqStateTable_Value_2022[offset], which is VALID_NON_TERMINAL_2022
+*     c) Switch on this state and continue to next char
+*        i)  Get the value of B from normalize_esq_chars_2022[] with int value of B as index
+*        ii) x is currently 36 (from above)
+*            x<<=5 -- x is now 1152
+*            x+=normalize_esq_chars_2022[66]
+*            now x is 1161
+*       iii) Search for this value in escSeqStateTable_Key_2022[]
+*            value of x is stored at escSeqStateTable_Key_2022[21], so offset is 21
+*        iv) Get state of this sequence from escSeqStateTable_Value_2022[21]
+*            escSeqStateTable_Value_2022[offset], which is VALID_TERMINAL_2022
+*         v) Get the converter name form escSeqStateTable_Result_2022[21] which is JISX208
+*/
+
+
+/*Below are the 3 arrays depicting a state transition table*/
+static const int8_t normalize_esq_chars_2022[256] = {
+/*       0      1       2       3       4      5       6        7       8       9           */
+
+         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      ,1      ,0      ,0
+        ,0     ,0      ,0      ,0      ,0      ,0      ,4      ,7      ,29      ,0
+        ,2     ,24     ,26     ,27     ,0      ,3      ,23     ,6      ,0      ,0
+        ,0     ,0      ,0      ,0      ,0      ,0      ,0      ,0      ,0      ,0
+        ,0     ,0      ,0      ,0      ,5      ,8      ,9      ,10     ,11     ,12
+        ,13    ,14     ,15     ,16     ,17     ,18     ,19     ,20     ,25     ,28
+        ,0     ,0      ,21     ,0      ,0      ,0      ,0      ,0      ,0      ,0
+        ,22    ,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      ,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      ,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      ,0      ,0      ,0      ,0      ,0
+        ,0     ,0      ,0      ,0      ,0      ,0      ,0      ,0      ,0      ,0
+        ,0     ,0      ,0      ,0      ,0      ,0
+};
+
+#ifdef U_ENABLE_GENERIC_ISO_2022
+/*
+ * When the generic ISO-2022 converter is completely removed, not just disabled
+ * per #ifdef, then the following state table and the associated tables that are
+ * dimensioned with MAX_STATES_2022 should be trimmed.
+ *
+ * Especially, VALID_MAYBE_TERMINAL_2022 will not be used any more, and all of
+ * the associated escape sequences starting with ESC ( B should be removed.
+ * This includes the ones with key values 1097 and all of the ones above 1000000.
+ *
+ * For the latter, the tables can simply be truncated.
+ * For the former, since the tables must be kept parallel, it is probably best
+ * to simply duplicate an adjacent table cell, parallel in all tables.
+ *
+ * It may make sense to restructure the tables, especially by using small search
+ * tables for the variants instead of indexing them parallel to the table here.
+ */
+#endif
+
+#define MAX_STATES_2022 74
+static const int32_t escSeqStateTable_Key_2022[MAX_STATES_2022] = {
+/*   0           1           2           3           4           5           6           7           8           9           */
+
+     1          ,34         ,36         ,39         ,55         ,57         ,60         ,61         ,1093       ,1096
+    ,1097       ,1098       ,1099       ,1100       ,1101       ,1102       ,1103       ,1104       ,1105       ,1106
+    ,1109       ,1154       ,1157       ,1160       ,1161       ,1176       ,1178       ,1179       ,1254       ,1257
+    ,1768       ,1773       ,1957       ,35105      ,36933      ,36936      ,36937      ,36938      ,36939      ,36940
+    ,36942      ,36943      ,36944      ,36945      ,36946      ,36947      ,36948      ,37640      ,37642      ,37644
+    ,37646      ,37711      ,37744      ,37745      ,37746      ,37747      ,37748      ,40133      ,40136      ,40138
+    ,40139      ,40140      ,40141      ,1123363    ,35947624   ,35947625   ,35947626   ,35947627   ,35947629   ,35947630
+    ,35947631   ,35947635   ,35947636   ,35947638
+};
+
+#ifdef U_ENABLE_GENERIC_ISO_2022
+
+static const char* const escSeqStateTable_Result_2022[MAX_STATES_2022] = {
+ /*  0                      1                        2                      3                   4                   5                        6                      7                       8                       9    */
+
+     NULL                   ,NULL                   ,NULL                   ,NULL               ,NULL               ,NULL                   ,NULL                   ,NULL                   ,"latin1"               ,"latin1"
+    ,"latin1"               ,"ibm-865"              ,"ibm-865"              ,"ibm-865"          ,"ibm-865"          ,"ibm-865"              ,"ibm-865"              ,"JISX0201"             ,"JISX0201"             ,"latin1"
+    ,"latin1"               ,NULL                   ,"JISX-208"             ,"ibm-5478"         ,"JISX-208"         ,NULL                   ,NULL                   ,NULL                   ,NULL                   ,"UTF8"
+    ,"ISO-8859-1"           ,"ISO-8859-7"           ,"JIS-X-208"            ,NULL               ,"ibm-955"          ,"ibm-367"              ,"ibm-952"              ,"ibm-949"              ,"JISX-212"             ,"ibm-1383"
+    ,"ibm-952"              ,"ibm-964"              ,"ibm-964"              ,"ibm-964"          ,"ibm-964"          ,"ibm-964"              ,"ibm-964"              ,"ibm-5478"         ,"ibm-949"              ,"ISO-IR-165"
+    ,"CNS-11643-1992,1"     ,"CNS-11643-1992,2"     ,"CNS-11643-1992,3"     ,"CNS-11643-1992,4" ,"CNS-11643-1992,5" ,"CNS-11643-1992,6"     ,"CNS-11643-1992,7"     ,"UTF16_PlatformEndian" ,"UTF16_PlatformEndian" ,"UTF16_PlatformEndian"
+    ,"UTF16_PlatformEndian" ,"UTF16_PlatformEndian" ,"UTF16_PlatformEndian" ,NULL               ,"latin1"           ,"ibm-912"              ,"ibm-913"              ,"ibm-914"              ,"ibm-813"              ,"ibm-1089"
+    ,"ibm-920"              ,"ibm-915"              ,"ibm-915"              ,"latin1"
+};
+
+#endif
+
+static const int8_t escSeqStateTable_Value_2022[MAX_STATES_2022] = {
+/*          0                           1                         2                             3                           4                           5                               6                        7                          8                           9       */
+     VALID_NON_TERMINAL_2022    ,VALID_NON_TERMINAL_2022    ,VALID_NON_TERMINAL_2022    ,VALID_NON_TERMINAL_2022     ,VALID_NON_TERMINAL_2022   ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_NON_TERMINAL_2022    ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022
+    ,VALID_MAYBE_TERMINAL_2022  ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022
+    ,VALID_TERMINAL_2022        ,VALID_NON_TERMINAL_2022    ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_NON_TERMINAL_2022    ,VALID_NON_TERMINAL_2022    ,VALID_NON_TERMINAL_2022    ,VALID_NON_TERMINAL_2022    ,VALID_TERMINAL_2022
+    ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_NON_TERMINAL_2022    ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022
+    ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022
+    ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022
+    ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_NON_TERMINAL_2022    ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022
+    ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022        ,VALID_TERMINAL_2022
+};
+
+
+/* Type def for refactoring changeState_2022 code*/
+typedef enum{
+#ifdef U_ENABLE_GENERIC_ISO_2022
+    ISO_2022=0,
+#endif
+    ISO_2022_JP=1,
+    ISO_2022_KR=2,
+    ISO_2022_CN=3
+} Variant2022;
+
+/*********** ISO 2022 Converter Protos ***********/
+static void
+_ISO2022Open(UConverter *cnv, UConverterLoadArgs *pArgs, UErrorCode *errorCode);
+
+static void
+ _ISO2022Close(UConverter *converter);
+
+static void
+_ISO2022Reset(UConverter *converter, UConverterResetChoice choice);
+
+static const char*
+_ISO2022getName(const UConverter* cnv);
+
+static void
+_ISO_2022_WriteSub(UConverterFromUnicodeArgs *args, int32_t offsetIndex, UErrorCode *err);
+
+static UConverter *
+_ISO_2022_SafeClone(const UConverter *cnv, void *stackBuffer, int32_t *pBufferSize, UErrorCode *status);
+
+#ifdef U_ENABLE_GENERIC_ISO_2022
+static void
+T_UConverter_toUnicode_ISO_2022_OFFSETS_LOGIC(UConverterToUnicodeArgs* args, UErrorCode* err);
+#endif
+
+/*const UConverterSharedData _ISO2022Data;*/
+static const UConverterSharedData _ISO2022JPData;
+static const UConverterSharedData _ISO2022KRData;
+static const UConverterSharedData _ISO2022CNData;
+
+/*************** Converter implementations ******************/
+
+/* The purpose of this function is to get around gcc compiler warnings. */
+static U_INLINE void
+fromUWriteUInt8(UConverter *cnv,
+                 const char *bytes, int32_t length,
+                 uint8_t **target, const char *targetLimit,
+                 int32_t **offsets,
+                 int32_t sourceIndex,
+                 UErrorCode *pErrorCode)
+{
+    char *targetChars = (char *)*target;
+    ucnv_fromUWriteBytes(cnv, bytes, length, &targetChars, targetLimit,
+                         offsets, sourceIndex, pErrorCode);
+    *target = (uint8_t*)targetChars;
+
+}
+
+static U_INLINE void
+setInitialStateToUnicodeKR(UConverter* converter, UConverterDataISO2022 *myConverterData){
+    if(myConverterData->version == 1) {
+        UConverter *cnv = myConverterData->currentConverter;
+
+        cnv->toUnicodeStatus=0;     /* offset */
+        cnv->mode=0;                /* state */
+        cnv->toULength=0;           /* byteIndex */
+    }
+}
+
+static U_INLINE void
+setInitialStateFromUnicodeKR(UConverter* converter,UConverterDataISO2022 *myConverterData){
+   /* in ISO-2022-KR the designator sequence appears only once
+    * in a file so we append it only once
+    */
+    if( converter->charErrorBufferLength==0){
+
+        converter->charErrorBufferLength = 4;
+        converter->charErrorBuffer[0] = 0x1b;
+        converter->charErrorBuffer[1] = 0x24;
+        converter->charErrorBuffer[2] = 0x29;
+        converter->charErrorBuffer[3] = 0x43;
+    }
+    if(myConverterData->version == 1) {
+        UConverter *cnv = myConverterData->currentConverter;
+
+        cnv->fromUChar32=0;
+        cnv->fromUnicodeStatus=1;   /* prevLength */
+    }
+}
+
+static void
+_ISO2022Open(UConverter *cnv, UConverterLoadArgs *pArgs, UErrorCode *errorCode){
+
+    char myLocale[6]={' ',' ',' ',' ',' ',' '};
+
+    cnv->extraInfo = uprv_malloc (sizeof (UConverterDataISO2022));
+    if(cnv->extraInfo != NULL) {
+        UConverterNamePieces stackPieces;
+        UConverterLoadArgs stackArgs={ (int32_t)sizeof(UConverterLoadArgs) };
+        UConverterDataISO2022 *myConverterData=(UConverterDataISO2022 *) cnv->extraInfo;
+        uint32_t version;
+
+        stackArgs.onlyTestIsLoadable = pArgs->onlyTestIsLoadable;
+
+        uprv_memset(myConverterData, 0, sizeof(UConverterDataISO2022));
+        myConverterData->currentType = ASCII1;
+        cnv->fromUnicodeStatus =FALSE;
+        if(pArgs->locale){
+            uprv_strncpy(myLocale, pArgs->locale, sizeof(myLocale));
+        }
+        version = pArgs->options & UCNV_OPTIONS_VERSION_MASK;
+        myConverterData->version = version;
+        if(myLocale[0]=='j' && (myLocale[1]=='a'|| myLocale[1]=='p') &&
+            (myLocale[2]=='_' || myLocale[2]=='\0'))
+        {
+            size_t len=0;
+            /* open the required converters and cache them */
+            if(version>MAX_JA_VERSION) {
+                /* prevent indexing beyond jpCharsetMasks[] */
+                myConverterData->version = version = 0;
+            }
+            if(jpCharsetMasks[version]&CSM(ISO8859_7)) {
+                myConverterData->myConverterArray[ISO8859_7] =
+                    ucnv_loadSharedData("ISO8859_7", &stackPieces, &stackArgs, errorCode);
+            }
+            myConverterData->myConverterArray[JISX208] =
+                ucnv_loadSharedData("Shift-JIS", &stackPieces, &stackArgs, errorCode);
+            if(jpCharsetMasks[version]&CSM(JISX212)) {
+                myConverterData->myConverterArray[JISX212] =
+                    ucnv_loadSharedData("jisx-212", &stackPieces, &stackArgs, errorCode);
+            }
+            if(jpCharsetMasks[version]&CSM(GB2312)) {
+                myConverterData->myConverterArray[GB2312] =
+                    ucnv_loadSharedData("ibm-5478", &stackPieces, &stackArgs, errorCode);   /* gb_2312_80-1 */
+            }
+            if(jpCharsetMasks[version]&CSM(KSC5601)) {
+                myConverterData->myConverterArray[KSC5601] =
+                    ucnv_loadSharedData("ksc_5601", &stackPieces, &stackArgs, errorCode);
+            }
+
+            /* set the function pointers to appropriate funtions */
+            cnv->sharedData=(UConverterSharedData*)(&_ISO2022JPData);
+            uprv_strcpy(myConverterData->locale,"ja");
+
+            (void)uprv_strcpy(myConverterData->name,"ISO_2022,locale=ja,version=");
+            len = uprv_strlen(myConverterData->name);
+            myConverterData->name[len]=(char)(myConverterData->version+(int)'0');
+            myConverterData->name[len+1]='\0';
+        }
+        else if(myLocale[0]=='k' && (myLocale[1]=='o'|| myLocale[1]=='r') &&
+            (myLocale[2]=='_' || myLocale[2]=='\0'))
+        {
+            const char *cnvName;
+            if(version==1) {
+                cnvName="icu-internal-25546";
+            } else {
+                cnvName="ibm-949";
+                myConverterData->version=version=0;
+            }
+            if(pArgs->onlyTestIsLoadable) {
+                ucnv_canCreateConverter(cnvName, errorCode);  /* errorCode carries result */
+                uprv_free(cnv->extraInfo);
+                cnv->extraInfo=NULL;
+                return;
+            } else {
+                myConverterData->currentConverter=ucnv_open(cnvName, errorCode);
+                if (U_FAILURE(*errorCode)) {
+                    _ISO2022Close(cnv);
+                    return;
+                }
+
+                if(version==1) {
+                    (void)uprv_strcpy(myConverterData->name,"ISO_2022,locale=ko,version=1");
+                    uprv_memcpy(cnv->subChars, myConverterData->currentConverter->subChars, 4);
+                    cnv->subCharLen = myConverterData->currentConverter->subCharLen;
+                }else{
+                    (void)uprv_strcpy(myConverterData->name,"ISO_2022,locale=ko,version=0");
+                }
+
+                /* initialize the state variables */
+                setInitialStateToUnicodeKR(cnv, myConverterData);
+                setInitialStateFromUnicodeKR(cnv, myConverterData);
+
+                /* set the function pointers to appropriate funtions */
+                cnv->sharedData=(UConverterSharedData*)&_ISO2022KRData;
+                uprv_strcpy(myConverterData->locale,"ko");
+            }
+        }
+        else if(((myLocale[0]=='z' && myLocale[1]=='h') || (myLocale[0]=='c'&& myLocale[1]=='n'))&&
+            (myLocale[2]=='_' || myLocale[2]=='\0'))
+        {
+
+            /* open the required converters and cache them */
+            myConverterData->myConverterArray[GB2312_1] =
+                ucnv_loadSharedData("ibm-5478", &stackPieces, &stackArgs, errorCode);
+            if(version==1) {
+                myConverterData->myConverterArray[ISO_IR_165] =
+                    ucnv_loadSharedData("iso-ir-165", &stackPieces, &stackArgs, errorCode);
+            }
+            myConverterData->myConverterArray[CNS_11643] =
+                ucnv_loadSharedData("cns-11643-1992", &stackPieces, &stackArgs, errorCode);
+
+
+            /* set the function pointers to appropriate funtions */
+            cnv->sharedData=(UConverterSharedData*)&_ISO2022CNData;
+            uprv_strcpy(myConverterData->locale,"cn");
+
+            if (version==0){
+                myConverterData->version = 0;
+                (void)uprv_strcpy(myConverterData->name,"ISO_2022,locale=zh,version=0");
+            }else if (version==1){
+                myConverterData->version = 1;
+                (void)uprv_strcpy(myConverterData->name,"ISO_2022,locale=zh,version=1");
+            }else {
+                myConverterData->version = 2;
+                (void)uprv_strcpy(myConverterData->name,"ISO_2022,locale=zh,version=2");
+            }
+        }
+        else{
+#ifdef U_ENABLE_GENERIC_ISO_2022
+            myConverterData->isFirstBuffer = TRUE;
+
+            /* append the UTF-8 escape sequence */
+            cnv->charErrorBufferLength = 3;
+            cnv->charErrorBuffer[0] = 0x1b;
+            cnv->charErrorBuffer[1] = 0x25;
+            cnv->charErrorBuffer[2] = 0x42;
+
+            cnv->sharedData=(UConverterSharedData*)&_ISO2022Data;
+            /* initialize the state variables */
+            uprv_strcpy(myConverterData->name,"ISO_2022");
+#else
+            *errorCode = U_UNSUPPORTED_ERROR;
+            return;
+#endif
+        }
+
+        cnv->maxBytesPerUChar=cnv->sharedData->staticData->maxBytesPerChar;
+
+        if(U_FAILURE(*errorCode) || pArgs->onlyTestIsLoadable) {
+            _ISO2022Close(cnv);
+        }
+    } else {
+        *errorCode = U_MEMORY_ALLOCATION_ERROR;
+    }
+}
+
+
+static void
+_ISO2022Close(UConverter *converter) {
+    UConverterDataISO2022* myData =(UConverterDataISO2022 *) (converter->extraInfo);
+    UConverterSharedData **array = myData->myConverterArray;
+    int32_t i;
+
+    if (converter->extraInfo != NULL) {
+        /*close the array of converter pointers and free the memory*/
+        for (i=0; i<UCNV_2022_MAX_CONVERTERS; i++) {
+            if(array[i]!=NULL) {
+                ucnv_unloadSharedDataIfReady(array[i]);
+            }
+        }
+
+        ucnv_close(myData->currentConverter);
+
+        if(!converter->isExtraLocal){
+            uprv_free (converter->extraInfo);
+            converter->extraInfo = NULL;
+        }
+    }
+}
+
+static void
+_ISO2022Reset(UConverter *converter, UConverterResetChoice choice) {
+    UConverterDataISO2022 *myConverterData=(UConverterDataISO2022 *) (converter->extraInfo);
+    if(choice<=UCNV_RESET_TO_UNICODE) {
+        uprv_memset(&myConverterData->toU2022State, 0, sizeof(ISO2022State));
+        myConverterData->key = 0;
+        myConverterData->isEmptySegment = FALSE;
+    }
+    if(choice!=UCNV_RESET_TO_UNICODE) {
+        uprv_memset(&myConverterData->fromU2022State, 0, sizeof(ISO2022State));
+    }
+#ifdef U_ENABLE_GENERIC_ISO_2022
+    if(myConverterData->locale[0] == 0){
+        if(choice<=UCNV_RESET_TO_UNICODE) {
+            myConverterData->isFirstBuffer = TRUE;
+            myConverterData->key = 0;
+            if (converter->mode == UCNV_SO){
+                ucnv_close (myConverterData->currentConverter);
+                myConverterData->currentConverter=NULL;
+            }
+            converter->mode = UCNV_SI;
+        }
+        if(choice!=UCNV_RESET_TO_UNICODE) {
+            /* re-append UTF-8 escape sequence */
+            converter->charErrorBufferLength = 3;
+            converter->charErrorBuffer[0] = 0x1b;
+            converter->charErrorBuffer[1] = 0x28;
+            converter->charErrorBuffer[2] = 0x42;
+        }
+    }
+    else
+#endif
+    {
+        /* reset the state variables */
+        if(myConverterData->locale[0] == 'k'){
+            if(choice<=UCNV_RESET_TO_UNICODE) {
+                setInitialStateToUnicodeKR(converter, myConverterData);
+            }
+            if(choice!=UCNV_RESET_TO_UNICODE) {
+                setInitialStateFromUnicodeKR(converter, myConverterData);
+            }
+        }
+    }
+}
+
+static const char*
+_ISO2022getName(const UConverter* cnv){
+    if(cnv->extraInfo){
+        UConverterDataISO2022* myData= (UConverterDataISO2022*)cnv->extraInfo;
+        return myData->name;
+    }
+    return NULL;
+}
+
+
+/*************** to unicode *******************/
+/****************************************************************************
+ * Recognized escape sequences are
+ * <ESC>(B  ASCII
+ * <ESC>.A  ISO-8859-1
+ * <ESC>.F  ISO-8859-7
+ * <ESC>(J  JISX-201
+ * <ESC>(I  JISX-201
+ * <ESC>$B  JISX-208
+ * <ESC>$@  JISX-208
+ * <ESC>$(D JISX-212
+ * <ESC>$A  GB2312
+ * <ESC>$(C KSC5601
+ */
+static const int8_t nextStateToUnicodeJP[MAX_STATES_2022]= {
+/*      0                1               2               3               4               5               6               7               8               9    */
+    INVALID_STATE   ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,SS2_STATE      ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE
+    ,ASCII          ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,JISX201        ,HWKANA_7BIT    ,JISX201        ,INVALID_STATE
+    ,INVALID_STATE  ,INVALID_STATE  ,JISX208        ,GB2312         ,JISX208        ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE
+    ,ISO8859_1      ,ISO8859_7      ,JISX208        ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,KSC5601        ,JISX212        ,INVALID_STATE
+    ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE
+    ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE
+    ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE
+    ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE
+};
+
+/*************** to unicode *******************/
+static const int8_t nextStateToUnicodeCN[MAX_STATES_2022]= {
+/*      0                1               2               3               4               5               6               7               8               9    */
+     INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,SS2_STATE      ,SS3_STATE      ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE
+    ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE
+    ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE
+    ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE
+    ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,GB2312_1       ,INVALID_STATE  ,ISO_IR_165
+    ,CNS_11643_1    ,CNS_11643_2    ,CNS_11643_3    ,CNS_11643_4    ,CNS_11643_5    ,CNS_11643_6    ,CNS_11643_7    ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE
+    ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE
+    ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE  ,INVALID_STATE
+};
+
+
+static UCNV_TableStates_2022
+getKey_2022(char c,int32_t* key,int32_t* offset){
+    int32_t togo;
+    int32_t low = 0;
+    int32_t hi = MAX_STATES_2022;
+    int32_t oldmid=0;
+
+    togo = normalize_esq_chars_2022[(uint8_t)c];
+    if(togo == 0) {
+        /* not a valid character anywhere in an escape sequence */
+        *key = 0;
+        *offset = 0;
+        return INVALID_2022;
+    }
+    togo = (*key << 5) + togo;
+
+    while (hi != low)  /*binary search*/{
+
+        register int32_t mid = (hi+low) >> 1; /*Finds median*/
+
+        if (mid == oldmid)
+            break;
+
+        if (escSeqStateTable_Key_2022[mid] > togo){
+            hi = mid;
+        }
+        else if (escSeqStateTable_Key_2022[mid] < togo){
+            low = mid;
+        }
+        else /*we found it*/{
+            *key = togo;
+            *offset = mid;
+            return (UCNV_TableStates_2022)escSeqStateTable_Value_2022[mid];
+        }
+        oldmid = mid;
+
+    }
+
+    *key = 0;
+    *offset = 0;
+    return INVALID_2022;
+}
+
+/*runs through a state machine to determine the escape sequence - codepage correspondance
+ */
+static void
+changeState_2022(UConverter* _this,
+                const char** source,
+                const char* sourceLimit,
+                Variant2022 var,
+                UErrorCode* err){
+    UCNV_TableStates_2022 value;
+    UConverterDataISO2022* myData2022 = ((UConverterDataISO2022*)_this->extraInfo);
+    uint32_t key = myData2022->key;
+    int32_t offset = 0;
+    int8_t initialToULength = _this->toULength;
+    char c;
+
+    value = VALID_NON_TERMINAL_2022;
+    while (*source < sourceLimit) {
+        c = *(*source)++;
+        _this->toUBytes[_this->toULength++]=(uint8_t)c;
+        value = getKey_2022(c,(int32_t *) &key, &offset);
+
+        switch (value){
+
+        case VALID_NON_TERMINAL_2022 :
+            /* continue with the loop */
+            break;
+
+        case VALID_TERMINAL_2022:
+            key = 0;
+            goto DONE;
+
+        case INVALID_2022:
+            goto DONE;
+
+        case VALID_MAYBE_TERMINAL_2022:
+#ifdef U_ENABLE_GENERIC_ISO_2022
+            /* ESC ( B is ambiguous only for ISO_2022 itself */
+            if(var == ISO_2022) {
+                /* discard toUBytes[] for ESC ( B because this sequence is correct and complete */
+                _this->toULength = 0;
+
+                /* TODO need to indicate that ESC ( B was seen; if failure, then need to replay from source or from MBCS-style replay */
+
+                /* continue with the loop */
+                value = VALID_NON_TERMINAL_2022;
+                break;
+            } else
+#endif
+            {
+                /* not ISO_2022 itself, finish here */
+                value = VALID_TERMINAL_2022;
+                key = 0;
+                goto DONE;
+            }
+        }
+    }
+
+DONE:
+    myData2022->key = key;
+
+    if (value == VALID_NON_TERMINAL_2022) {
+        /* indicate that the escape sequence is incomplete: key!=0 */
+        return;
+    } else if (value == INVALID_2022 ) {
+        *err = U_ILLEGAL_ESCAPE_SEQUENCE;
+    } else /* value == VALID_TERMINAL_2022 */ {
+        switch(var){
+#ifdef U_ENABLE_GENERIC_ISO_2022
+        case ISO_2022:
+        {
+            const char *chosenConverterName = escSeqStateTable_Result_2022[offset];
+            if(chosenConverterName == NULL) {
+                /* SS2 or SS3 */
+                *err = U_UNSUPPORTED_ESCAPE_SEQUENCE;
+                _this->toUCallbackReason = UCNV_UNASSIGNED;
+                return;
+            }
+
+            _this->mode = UCNV_SI;
+            ucnv_close(myData2022->currentConverter);
+            myData2022->currentConverter = myUConverter = ucnv_open(chosenConverterName, err);
+            if(U_SUCCESS(*err)) {
+                myUConverter->fromCharErrorBehaviour = UCNV_TO_U_CALLBACK_STOP;
+                _this->mode = UCNV_SO;
+            }
+            break;
+        }
+#endif
+        case ISO_2022_JP:
+            {
+                StateEnum tempState=(StateEnum)nextStateToUnicodeJP[offset];
+                switch(tempState) {
+                case INVALID_STATE:
+                    *err = U_UNSUPPORTED_ESCAPE_SEQUENCE;
+                    break;
+                case SS2_STATE:
+                    if(myData2022->toU2022State.cs[2]!=0) {
+                        if(myData2022->toU2022State.g<2) {
+                            myData2022->toU2022State.prevG=myData2022->toU2022State.g;
+                        }
+                        myData2022->toU2022State.g=2;
+                    } else {
+                        /* illegal to have SS2 before a matching designator */
+                        *err = U_ILLEGAL_ESCAPE_SEQUENCE;
+                    }
+                    break;
+                /* case SS3_STATE: not used in ISO-2022-JP-x */
+                case ISO8859_1:
+                case ISO8859_7:
+                    if((jpCharsetMasks[myData2022->version] & CSM(tempState)) == 0) {
+                        *err = U_UNSUPPORTED_ESCAPE_SEQUENCE;
+                    } else {
+                        /* G2 charset for SS2 */
+                        myData2022->toU2022State.cs[2]=(int8_t)tempState;
+                    }
+                    break;
+                default:
+                    if((jpCharsetMasks[myData2022->version] & CSM(tempState)) == 0) {
+                        *err = U_UNSUPPORTED_ESCAPE_SEQUENCE;
+                    } else {
+                        /* G0 charset */
+                        myData2022->toU2022State.cs[0]=(int8_t)tempState;
+                    }
+                    break;
+                }
+            }
+            break;
+        case ISO_2022_CN:
+            {
+                StateEnum tempState=(StateEnum)nextStateToUnicodeCN[offset];
+                switch(tempState) {
+                case INVALID_STATE:
+                    *err = U_UNSUPPORTED_ESCAPE_SEQUENCE;
+                    break;
+                case SS2_STATE:
+                    if(myData2022->toU2022State.cs[2]!=0) {
+                        if(myData2022->toU2022State.g<2) {
+                            myData2022->toU2022State.prevG=myData2022->toU2022State.g;
+                        }
+                        myData2022->toU2022State.g=2;
+                    } else {
+                        /* illegal to have SS2 before a matching designator */
+                        *err = U_ILLEGAL_ESCAPE_SEQUENCE;
+                    }
+                    break;
+                case SS3_STATE:
+                    if(myData2022->toU2022State.cs[3]!=0) {
+                        if(myData2022->toU2022State.g<2) {
+                            myData2022->toU2022State.prevG=myData2022->toU2022State.g;
+                        }
+                        myData2022->toU2022State.g=3;
+                    } else {
+                        /* illegal to have SS3 before a matching designator */
+                        *err = U_ILLEGAL_ESCAPE_SEQUENCE;
+                    }
+                    break;
+                case ISO_IR_165:
+                    if(myData2022->version==0) {
+                        *err = U_UNSUPPORTED_ESCAPE_SEQUENCE;
+                        break;
+                    }
+                    /*fall through*/
+                case GB2312_1:
+                    /*fall through*/
+                case CNS_11643_1:
+                    myData2022->toU2022State.cs[1]=(int8_t)tempState;
+                    break;
+                case CNS_11643_2:
+                    myData2022->toU2022State.cs[2]=(int8_t)tempState;
+                    break;
+                default:
+                    /* other CNS 11643 planes */
+                    if(myData2022->version==0) {
+                        *err = U_UNSUPPORTED_ESCAPE_SEQUENCE;
+                    } else {
+                       myData2022->toU2022State.cs[3]=(int8_t)tempState;
+                    }
+                    break;
+                }
+            }
+            break;
+        case ISO_2022_KR:
+            if(offset==0x30){
+                /* nothing to be done, just accept this one escape sequence */
+            } else {
+                *err = U_UNSUPPORTED_ESCAPE_SEQUENCE;
+            }
+            break;
+
+        default:
+            *err = U_ILLEGAL_ESCAPE_SEQUENCE;
+            break;
+        }
+    }
+    if(U_SUCCESS(*err)) {
+        _this->toULength = 0;
+    } else if(*err==U_ILLEGAL_ESCAPE_SEQUENCE) {
+        if(_this->toULength>1) {
+            /*
+             * Ticket 5691: consistent illegal sequences:
+             * - We include at least the first byte (ESC) in the illegal sequence.
+             * - If any of the non-initial bytes could be the start of a character,
+             *   we stop the illegal sequence before the first one of those.
+             *   In escape sequences, all following bytes are "printable", that is,
+             *   unless they are completely illegal (>7f in SBCS, outside 21..7e in DBCS),
+             *   they are valid single/lead bytes.
+             *   For simplicity, we always only report the initial ESC byte as the
+             *   illegal sequence and back out all other bytes we looked at.
+             */
+            /* Back out some bytes. */
+            int8_t backOutDistance=_this->toULength-1;
+            int8_t bytesFromThisBuffer=_this->toULength-initialToULength;
+            if(backOutDistance<=bytesFromThisBuffer) {
+                /* same as initialToULength<=1 */
+                *source-=backOutDistance;
+            } else {
+                /* Back out bytes from the previous buffer: Need to replay them. */
+                _this->preToULength=(int8_t)(bytesFromThisBuffer-backOutDistance);
+                /* same as -(initialToULength-1) */
+                /* preToULength is negative! */
+                uprv_memcpy(_this->preToU, _this->toUBytes+1, -_this->preToULength);
+                *source-=bytesFromThisBuffer;
+            }
+            _this->toULength=1;
+        }
+    } else if(*err==U_UNSUPPORTED_ESCAPE_SEQUENCE) {
+        _this->toUCallbackReason = UCNV_UNASSIGNED;
+    }
+}
+
+/*Checks the characters of the buffer against valid 2022 escape sequences
+*if the match we return a pointer to the initial start of the sequence otherwise
+*we return sourceLimit
+*/
+/*for 2022 looks ahead in the stream
+ *to determine the longest possible convertible
+ *data stream
+ */
+static U_INLINE const char*
+getEndOfBuffer_2022(const char** source,
+                   const char* sourceLimit,
+                   UBool flush){
+
+    const char* mySource = *source;
+
+#ifdef U_ENABLE_GENERIC_ISO_2022
+    if (*source >= sourceLimit)
+        return sourceLimit;
+
+    do{
+
+        if (*mySource == ESC_2022){
+            int8_t i;
+            int32_t key = 0;
+            int32_t offset;
+            UCNV_TableStates_2022 value = VALID_NON_TERMINAL_2022;
+
+            /* Kludge: I could not
+            * figure out the reason for validating an escape sequence
+            * twice - once here and once in changeState_2022().
+            * is it possible to have an ESC character in a ISO2022
+            * byte stream which is valid in a code page? Is it legal?
+            */
+            for (i=0;
+            (mySource+i < sourceLimit)&&(value == VALID_NON_TERMINAL_2022);
+            i++) {
+                value =  getKey_2022(*(mySource+i), &key, &offset);
+            }
+            if (value > 0 || *mySource==ESC_2022)
+                return mySource;
+
+            if ((value == VALID_NON_TERMINAL_2022)&&(!flush) )
+                return sourceLimit;
+        }
+    }while (++mySource < sourceLimit);
+
+    return sourceLimit;
+#else
+    while(mySource < sourceLimit && *mySource != ESC_2022) {
+        ++mySource;
+    }
+    return mySource;
+#endif
+}
+
+
+/* This inline function replicates code in _MBCSFromUChar32() function in ucnvmbcs.c
+ * any future change in _MBCSFromUChar32() function should be reflected here.
+ * @return number of bytes in *value; negative number if fallback; 0 if no mapping
+ */
+static U_INLINE int32_t
+MBCS_FROM_UCHAR32_ISO2022(UConverterSharedData* sharedData,
+                                         UChar32 c,
+                                         uint32_t* value,
+                                         UBool useFallback,
+                                         int outputType)
+{
+    const int32_t *cx;
+    const uint16_t *table;
+    uint32_t stage2Entry;
+    uint32_t myValue;
+    int32_t length;
+    const uint8_t *p;
+    /*
+     * TODO(markus): Use and require new, faster MBCS conversion table structures.
+     * Use internal version of ucnv_open() that verifies that the new structures are available,
+     * else U_INTERNAL_PROGRAM_ERROR.
+     */
+    /* BMP-only codepages are stored without stage 1 entries for supplementary code points */
+    if(c<0x10000 || (sharedData->mbcs.unicodeMask&UCNV_HAS_SUPPLEMENTARY)) {
+        table=sharedData->mbcs.fromUnicodeTable;
+        stage2Entry=MBCS_STAGE_2_FROM_U(table, c);
+        /* get the bytes and the length for the output */
+        if(outputType==MBCS_OUTPUT_2){
+            myValue=MBCS_VALUE_2_FROM_STAGE_2(sharedData->mbcs.fromUnicodeBytes, stage2Entry, c);
+            if(myValue<=0xff) {
+                length=1;
+            } else {
+                length=2;
+            }
+        } else /* outputType==MBCS_OUTPUT_3 */ {
+            p=MBCS_POINTER_3_FROM_STAGE_2(sharedData->mbcs.fromUnicodeBytes, stage2Entry, c);
+            myValue=((uint32_t)*p<<16)|((uint32_t)p[1]<<8)|p[2];
+            if(myValue<=0xff) {
+                length=1;
+            } else if(myValue<=0xffff) {
+                length=2;
+            } else {
+                length=3;
+            }
+        }
+        /* is this code point assigned, or do we use fallbacks? */
+        if((stage2Entry&(1<<(16+(c&0xf))))!=0) {
+            /* assigned */
+            *value=myValue;
+            return length;
+        } else if(FROM_U_USE_FALLBACK(useFallback, c) && myValue!=0) {
+            /*
+             * We allow a 0 byte output if the "assigned" bit is set for this entry.
+             * There is no way with this data structure for fallback output
+             * to be a zero byte.
+             */
+            *value=myValue;
+            return -length;
+        }
+    }
+
+    cx=sharedData->mbcs.extIndexes;
+    if(cx!=NULL) {
+        return ucnv_extSimpleMatchFromU(cx, c, value, useFallback);
+    }
+
+    /* unassigned */
+    return 0;
+}
+
+/* This inline function replicates code in _MBCSSingleFromUChar32() function in ucnvmbcs.c
+ * any future change in _MBCSSingleFromUChar32() function should be reflected here.
+ * @param retval pointer to output byte
+ * @return 1 roundtrip byte  0 no mapping  -1 fallback byte
+ */
+static U_INLINE int32_t
+MBCS_SINGLE_FROM_UCHAR32(UConverterSharedData* sharedData,
+                                       UChar32 c,
+                                       uint32_t* retval,
+                                       UBool useFallback)
+{
+    const uint16_t *table;
+    int32_t value;
+    /* BMP-only codepages are stored without stage 1 entries for supplementary code points */
+    if(c>=0x10000 && !(sharedData->mbcs.unicodeMask&UCNV_HAS_SUPPLEMENTARY)) {
+        return 0;
+    }
+    /* convert the Unicode code point in c into codepage bytes (same as in _MBCSFromUnicodeWithOffsets) */
+    table=sharedData->mbcs.fromUnicodeTable;
+    /* get the byte for the output */
+    value=MBCS_SINGLE_RESULT_FROM_U(table, (uint16_t *)sharedData->mbcs.fromUnicodeBytes, c);
+    /* is this code point assigned, or do we use fallbacks? */
+    *retval=(uint32_t)(value&0xff);
+    if(value>=0xf00) {
+        return 1;  /* roundtrip */
+    } else if(useFallback ? value>=0x800 : value>=0xc00) {
+        return -1;  /* fallback taken */
+    } else {
+        return 0;  /* no mapping */
+    }
+}
+
+/*
+ * Check that the result is a 2-byte value with each byte in the range A1..FE
+ * (strict EUC DBCS) before accepting it and subtracting 0x80 from each byte
+ * to move it to the ISO 2022 range 21..7E.
+ * Return 0 if out of range.
+ */
+static U_INLINE uint32_t
+_2022FromGR94DBCS(uint32_t value) {
+    if( (uint16_t)(value - 0xa1a1) <= (0xfefe - 0xa1a1) &&
+        (uint8_t)(value - 0xa1) <= (0xfe - 0xa1)
+    ) {
+        return value - 0x8080;  /* shift down to 21..7e byte range */
+    } else {
+        return 0;  /* not valid for ISO 2022 */
+    }
+}
+
+#if 0 /* 5691: Call sites now check for validity. They can just += 0x8080 after that. */
+/*
+ * This method does the reverse of _2022FromGR94DBCS(). Given the 2022 code point, it returns the
+ * 2 byte value that is in the range A1..FE for each byte. Otherwise it returns the 2022 code point
+ * unchanged. 
+ */
+static U_INLINE uint32_t
+_2022ToGR94DBCS(uint32_t value) {
+    uint32_t returnValue = value + 0x8080;
+    if( (uint16_t)(returnValue - 0xa1a1) <= (0xfefe - 0xa1a1) &&
+        (uint8_t)(returnValue - 0xa1) <= (0xfe - 0xa1)) {
+        return returnValue;
+    } else {
+        return value;
+    }
+}
+#endif
+
+#ifdef U_ENABLE_GENERIC_ISO_2022
+
+/**********************************************************************************
+*  ISO-2022 Converter
+*
+*
+*/
+
+static void
+T_UConverter_toUnicode_ISO_2022_OFFSETS_LOGIC(UConverterToUnicodeArgs* args,
+                                                           UErrorCode* err){
+    const char* mySourceLimit, *realSourceLimit;
+    const char* sourceStart;
+    const UChar* myTargetStart;
+    UConverter* saveThis;
+    UConverterDataISO2022* myData;
+    int8_t length;
+
+    saveThis = args->converter;
+    myData=((UConverterDataISO2022*)(saveThis->extraInfo));
+
+    realSourceLimit = args->sourceLimit;
+    while (args->source < realSourceLimit) {
+        if(myData->key == 0) { /* are we in the middle of an escape sequence? */
+            /*Find the end of the buffer e.g : Next Escape Seq | end of Buffer*/
+            mySourceLimit = getEndOfBuffer_2022(&(args->source), realSourceLimit, args->flush);
+
+            if(args->source < mySourceLimit) {
+                if(myData->currentConverter==NULL) {
+                    myData->currentConverter = ucnv_open("ASCII",err);
+                    if(U_FAILURE(*err)){
+                        return;
+                    }
+
+                    myData->currentConverter->fromCharErrorBehaviour = UCNV_TO_U_CALLBACK_STOP;
+                    saveThis->mode = UCNV_SO;
+                }
+
+                /* convert to before the ESC or until the end of the buffer */
+                myData->isFirstBuffer=FALSE;
+                sourceStart = args->source;
+                myTargetStart = args->target;
+                args->converter = myData->currentConverter;
+                ucnv_toUnicode(args->converter,
+                    &args->target,
+                    args->targetLimit,
+                    &args->source,
+                    mySourceLimit,
+                    args->offsets,
+                    (UBool)(args->flush && mySourceLimit == realSourceLimit),
+                    err);
+                args->converter = saveThis;
+
+                if (*err == U_BUFFER_OVERFLOW_ERROR) {
+                    /* move the overflow buffer */
+                    length = saveThis->UCharErrorBufferLength = myData->currentConverter->UCharErrorBufferLength;
+                    myData->currentConverter->UCharErrorBufferLength = 0;
+                    if(length > 0) {
+                        uprv_memcpy(saveThis->UCharErrorBuffer,
+                                    myData->currentConverter->UCharErrorBuffer,
+                                    length*U_SIZEOF_UCHAR);
+                    }
+                    return;
+                }
+
+                /*
+                 * At least one of:
+                 * -Error while converting
+                 * -Done with entire buffer
+                 * -Need to write offsets or update the current offset
+                 *  (leave that up to the code in ucnv.c)
+                 *
+                 * or else we just stopped at an ESC byte and continue with changeState_2022()
+                 */
+                if (U_FAILURE(*err) ||
+                    (args->source == realSourceLimit) ||
+                    (args->offsets != NULL && (args->target != myTargetStart || args->source != sourceStart) ||
+                    (mySourceLimit < realSourceLimit && myData->currentConverter->toULength > 0))
+                ) {
+                    /* copy partial or error input for truncated detection and error handling */
+                    if(U_FAILURE(*err)) {
+                        length = saveThis->invalidCharLength = myData->currentConverter->invalidCharLength;
+                        if(length > 0) {
+                            uprv_memcpy(saveThis->invalidCharBuffer, myData->currentConverter->invalidCharBuffer, length);
+                        }
+                    } else {
+                        length = saveThis->toULength = myData->currentConverter->toULength;
+                        if(length > 0) {
+                            uprv_memcpy(saveThis->toUBytes, myData->currentConverter->toUBytes, length);
+                            if(args->source < mySourceLimit) {
+                                *err = U_TRUNCATED_CHAR_FOUND; /* truncated input before ESC */
+                            }
+                        }
+                    }
+                    return;
+                }
+            }
+        }
+
+        sourceStart = args->source;
+        changeState_2022(args->converter,
+               &(args->source),
+               realSourceLimit,
+               ISO_2022,
+               err);
+        if (U_FAILURE(*err) || (args->source != sourceStart && args->offsets != NULL)) {
+            /* let the ucnv.c code update its current offset */
+            return;
+        }
+    }
+}
+
+#endif
+
+/*
+ * To Unicode Callback helper function
+ */
+static void
+toUnicodeCallback(UConverter *cnv,
+                  const uint32_t sourceChar, const uint32_t targetUniChar,
+                  UErrorCode* err){
+    if(sourceChar>0xff){
+        cnv->toUBytes[0] = (uint8_t)(sourceChar>>8);
+        cnv->toUBytes[1] = (uint8_t)sourceChar;
+        cnv->toULength = 2;
+    }
+    else{
+        cnv->toUBytes[0] =(char) sourceChar;
+        cnv->toULength = 1;
+    }
+
+    if(targetUniChar == (missingCharMarker-1/*0xfffe*/)){
+        *err = U_INVALID_CHAR_FOUND;
+    }
+    else{
+        *err = U_ILLEGAL_CHAR_FOUND;
+    }
+}
+
+/**************************************ISO-2022-JP*************************************************/
+
+/************************************** IMPORTANT **************************************************
+* The UConverter_fromUnicode_ISO2022_JP converter does not use ucnv_fromUnicode() functions for SBCS,DBCS and
+* MBCS; instead, the values are obtained directly by calling _MBCSFromUChar32().
+* The converter iterates over each Unicode codepoint
+* to obtain the equivalent codepoints from the codepages supported. Since the source buffer is
+* processed one char at a time it would make sense to reduce the extra processing a canned converter
+* would do as far as possible.
+*
+* If the implementation of these macros or structure of sharedData struct change in the future, make
+* sure that ISO-2022 is also changed.
+***************************************************************************************************
+*/
+
+/***************************************************************************************************
+* Rules for ISO-2022-jp encoding
+* (i)   Escape sequences must be fully contained within a line they should not
+*       span new lines or CRs
+* (ii)  If the last character on a line is represented by two bytes then an ASCII or
+*       JIS-Roman character escape sequence should follow before the line terminates
+* (iii) If the first character on the line is represented by two bytes then a two
+*       byte character escape sequence should precede it
+* (iv)  If no escape sequence is encountered then the characters are ASCII
+* (v)   Latin(ISO-8859-1) and Greek(ISO-8859-7) characters must be designated to G2,
+*       and invoked with SS2 (ESC N).
+* (vi)  If there is any G0 designation in text, there must be a switch to
+*       ASCII or to JIS X 0201-Roman before a space character (but not
+*       necessarily before "ESC 4/14 2/0" or "ESC N ' '") or control
+*       characters such as tab or CRLF.
+* (vi)  Supported encodings:
+*          ASCII, JISX201, JISX208, JISX212, GB2312, KSC5601, ISO-8859-1,ISO-8859-7
+*
+*  source : RFC-1554
+*
+*          JISX201, JISX208,JISX212 : new .cnv data files created
+*          KSC5601 : alias to ibm-949 mapping table
+*          GB2312 : alias to ibm-1386 mapping table
+*          ISO-8859-1 : Algorithmic implemented as LATIN1 case
+*          ISO-8859-7 : alisas to ibm-9409 mapping table
+*/
+
+/* preference order of JP charsets */
+static const StateEnum jpCharsetPref[]={
+    ASCII,
+    JISX201,
+    ISO8859_1,
+    ISO8859_7,
+    JISX208,
+    JISX212,
+    GB2312,
+    KSC5601,
+    HWKANA_7BIT
+};
+
+/*
+ * The escape sequences must be in order of the enum constants like JISX201  = 3,
+ * not in order of jpCharsetPref[]!
+ */
+static const char escSeqChars[][6] ={
+    "\x1B\x28\x42",         /* <ESC>(B  ASCII       */
+    "\x1B\x2E\x41",         /* <ESC>.A  ISO-8859-1  */
+    "\x1B\x2E\x46",         /* <ESC>.F  ISO-8859-7  */
+    "\x1B\x28\x4A",         /* <ESC>(J  JISX-201    */
+    "\x1B\x24\x42",         /* <ESC>$B  JISX-208    */
+    "\x1B\x24\x28\x44",     /* <ESC>$(D JISX-212    */
+    "\x1B\x24\x41",         /* <ESC>$A  GB2312      */
+    "\x1B\x24\x28\x43",     /* <ESC>$(C KSC5601     */
+    "\x1B\x28\x49"          /* <ESC>(I  HWKANA_7BIT */
+
+};
+static  const int8_t escSeqCharsLen[] ={
+    3, /* length of <ESC>(B  ASCII       */
+    3, /* length of <ESC>.A  ISO-8859-1  */
+    3, /* length of <ESC>.F  ISO-8859-7  */
+    3, /* length of <ESC>(J  JISX-201    */
+    3, /* length of <ESC>$B  JISX-208    */
+    4, /* length of <ESC>$(D JISX-212    */
+    3, /* length of <ESC>$A  GB2312      */
+    4, /* length of <ESC>$(C KSC5601     */
+    3  /* length of <ESC>(I  HWKANA_7BIT */
+};
+
+/*
+* The iteration over various code pages works this way:
+* i)   Get the currentState from myConverterData->currentState
+* ii)  Check if the character is mapped to a valid character in the currentState
+*      Yes ->  a) set the initIterState to currentState
+*       b) remain in this state until an invalid character is found
+*      No  ->  a) go to the next code page and find the character
+* iii) Before changing the state increment the current state check if the current state
+*      is equal to the intitIteration state
+*      Yes ->  A character that cannot be represented in any of the supported encodings
+*       break and return a U_INVALID_CHARACTER error
+*      No  ->  Continue and find the character in next code page
+*
+*
+* TODO: Implement a priority technique where the users are allowed to set the priority of code pages
+*/
+
+/* Map 00..7F to Unicode according to JIS X 0201. */
+static U_INLINE uint32_t
+jisx201ToU(uint32_t value) {
+    if(value < 0x5c) {
+        return value;
+    } else if(value == 0x5c) {
+        return 0xa5;
+    } else if(value == 0x7e) {
+        return 0x203e;
+    } else /* value <= 0x7f */ {
+        return value;
+    }
+}
+
+/* Map Unicode to 00..7F according to JIS X 0201. Return U+FFFE if unmappable. */
+static U_INLINE uint32_t
+jisx201FromU(uint32_t value) {
+    if(value<=0x7f) {
+        if(value!=0x5c && value!=0x7e) {
+            return value;
+        }
+    } else if(value==0xa5) {
+        return 0x5c;
+    } else if(value==0x203e) {
+        return 0x7e;
+    }
+    return 0xfffe;
+}
+
+/*
+ * Take a valid Shift-JIS byte pair, check that it is in the range corresponding
+ * to JIS X 0208, and convert it to a pair of 21..7E bytes.
+ * Return 0 if the byte pair is out of range.
+ */
+static U_INLINE uint32_t
+_2022FromSJIS(uint32_t value) {
+    uint8_t trail;
+
+    if(value > 0xEFFC) {
+        return 0;  /* beyond JIS X 0208 */
+    }
+
+    trail = (uint8_t)value;
+
+    value &= 0xff00;  /* lead byte */
+    if(value <= 0x9f00) {
+        value -= 0x7000;
+    } else /* 0xe000 <= value <= 0xef00 */ {
+        value -= 0xb000;
+    }
+    value <<= 1;
+
+    if(trail <= 0x9e) {
+        value -= 0x100;
+        if(trail <= 0x7e) {
+            value |= trail - 0x1f;
+        } else {
+            value |= trail - 0x20;
+        }
+    } else /* trail <= 0xfc */ {
+        value |= trail - 0x7e;
+    }
+    return value;
+}
+
+/*
+ * Convert a pair of JIS X 0208 21..7E bytes to Shift-JIS.
+ * If either byte is outside 21..7E make sure that the result is not valid
+ * for Shift-JIS so that the converter catches it.
+ * Some invalid byte values already turn into equally invalid Shift-JIS
+ * byte values and need not be tested explicitly.
+ */
+static U_INLINE void
+_2022ToSJIS(uint8_t c1, uint8_t c2, char bytes[2]) {
+    if(c1&1) {
+        ++c1;
+        if(c2 <= 0x5f) {
+            c2 += 0x1f;
+        } else if(c2 <= 0x7e) {
+            c2 += 0x20;
+        } else {
+            c2 = 0;  /* invalid */
+        }
+    } else {
+        if((uint8_t)(c2-0x21) <= ((0x7e)-0x21)) {
+            c2 += 0x7e;
+        } else {
+            c2 = 0;  /* invalid */
+        }
+    }
+    c1 >>= 1;
+    if(c1 <= 0x2f) {
+        c1 += 0x70;
+    } else if(c1 <= 0x3f) {
+        c1 += 0xb0;
+    } else {
+        c1 = 0;  /* invalid */
+    }
+    bytes[0] = (char)c1;
+    bytes[1] = (char)c2;
+}
+
+/*
+ * JIS X 0208 has fallbacks from Unicode half-width Katakana to full-width (DBCS)
+ * Katakana.
+ * Now that we use a Shift-JIS table for JIS X 0208 we need to hardcode these fallbacks
+ * because Shift-JIS roundtrips half-width Katakana to single bytes.
+ * These were the only fallbacks in ICU's jisx-208.ucm file.
+ */
+static const uint16_t hwkana_fb[HWKANA_END - HWKANA_START + 1] = {
+    0x2123,  /* U+FF61 */
+    0x2156,
+    0x2157,
+    0x2122,
+    0x2126,
+    0x2572,
+    0x2521,
+    0x2523,
+    0x2525,
+    0x2527,
+    0x2529,
+    0x2563,
+    0x2565,
+    0x2567,
+    0x2543,
+    0x213C,  /* U+FF70 */
+    0x2522,
+    0x2524,
+    0x2526,
+    0x2528,
+    0x252A,
+    0x252B,
+    0x252D,
+    0x252F,
+    0x2531,
+    0x2533,
+    0x2535,
+    0x2537,
+    0x2539,
+    0x253B,
+    0x253D,
+    0x253F,  /* U+FF80 */
+    0x2541,
+    0x2544,
+    0x2546,
+    0x2548,
+    0x254A,
+    0x254B,
+    0x254C,
+    0x254D,
+    0x254E,
+    0x254F,
+    0x2552,
+    0x2555,
+    0x2558,
+    0x255B,
+    0x255E,
+    0x255F,  /* U+FF90 */
+    0x2560,
+    0x2561,
+    0x2562,
+    0x2564,
+    0x2566,
+    0x2568,
+    0x2569,
+    0x256A,
+    0x256B,
+    0x256C,
+    0x256D,
+    0x256F,
+    0x2573,
+    0x212B,
+    0x212C   /* U+FF9F */
+};
+
+static void
+UConverter_fromUnicode_ISO_2022_JP_OFFSETS_LOGIC(UConverterFromUnicodeArgs* args, UErrorCode* err) {
+    UConverter *cnv = args->converter;
+    UConverterDataISO2022 *converterData;
+    ISO2022State *pFromU2022State;
+    uint8_t *target = (uint8_t *) args->target;
+    const uint8_t *targetLimit = (const uint8_t *) args->targetLimit;
+    const UChar* source = args->source;
+    const UChar* sourceLimit = args->sourceLimit;
+    int32_t* offsets = args->offsets;
+    UChar32 sourceChar;
+    char buffer[8];
+    int32_t len, outLen;
+    int8_t choices[10];
+    int32_t choiceCount;
+    uint32_t targetValue = 0;
+    UBool useFallback;
+
+    int32_t i;
+    int8_t cs, g;
+
+    /* set up the state */
+    converterData     = (UConverterDataISO2022*)cnv->extraInfo;
+    pFromU2022State   = &converterData->fromU2022State;
+
+    choiceCount = 0;
+
+    /* check if the last codepoint of previous buffer was a lead surrogate*/
+    if((sourceChar = cnv->fromUChar32)!=0 && target< targetLimit) {
+        goto getTrail;
+    }
+
+    while(source < sourceLimit) {
+        if(target < targetLimit) {
+
+            sourceChar  = *(source++);
+            /*check if the char is a First surrogate*/
+            if(UTF_IS_SURROGATE(sourceChar)) {
+                if(UTF_IS_SURROGATE_FIRST(sourceChar)) {
+getTrail:
+                    /*look ahead to find the trail surrogate*/
+                    if(source < sourceLimit) {
+                        /* test the following code unit */
+                        UChar trail=(UChar) *source;
+                        if(UTF_IS_SECOND_SURROGATE(trail)) {
+                            source++;
+                            sourceChar=UTF16_GET_PAIR_VALUE(sourceChar, trail);
+                            cnv->fromUChar32=0x00;
+                            /* convert this supplementary code point */
+                            /* exit this condition tree */
+                        } else {
+                            /* this is an unmatched lead code unit (1st surrogate) */
+                            /* callback(illegal) */
+                            *err=U_ILLEGAL_CHAR_FOUND;
+                            cnv->fromUChar32=sourceChar;
+                            break;
+                        }
+                    } else {
+                        /* no more input */
+                        cnv->fromUChar32=sourceChar;
+                        break;
+                    }
+                } else {
+                    /* this is an unmatched trail code unit (2nd surrogate) */
+                    /* callback(illegal) */
+                    *err=U_ILLEGAL_CHAR_FOUND;
+                    cnv->fromUChar32=sourceChar;
+                    break;
+                }
+            }
+
+            /* do not convert SO/SI/ESC */
+            if(IS_2022_CONTROL(sourceChar)) {
+                /* callback(illegal) */
+                *err=U_ILLEGAL_CHAR_FOUND;
+                cnv->fromUChar32=sourceChar;
+                break;
+            }
+
+            /* do the conversion */
+
+            if(choiceCount == 0) {
+                uint16_t csm;
+
+                /*
+                 * The csm variable keeps track of which charsets are allowed
+                 * and not used yet while building the choices[].
+                 */
+                csm = jpCharsetMasks[converterData->version];
+                choiceCount = 0;
+
+                /* JIS7/8: try single-byte half-width Katakana before JISX208 */
+                if(converterData->version == 3 || converterData->version == 4) {
+                    choices[choiceCount++] = (int8_t)HWKANA_7BIT;
+                }
+                /* Do not try single-byte half-width Katakana for other versions. */
+                csm &= ~CSM(HWKANA_7BIT);
+
+                /* try the current G0 charset */
+                choices[choiceCount++] = cs = pFromU2022State->cs[0];
+                csm &= ~CSM(cs);
+
+                /* try the current G2 charset */
+                if((cs = pFromU2022State->cs[2]) != 0) {
+                    choices[choiceCount++] = cs;
+                    csm &= ~CSM(cs);
+                }
+
+                /* try all the other possible charsets */
+                for(i = 0; i < LENGTHOF(jpCharsetPref); ++i) {
+                    cs = (int8_t)jpCharsetPref[i];
+                    if(CSM(cs) & csm) {
+                        choices[choiceCount++] = cs;
+                        csm &= ~CSM(cs);
+                    }
+                }
+            }
+
+            cs = g = 0;
+            /*
+             * len==0: no mapping found yet
+             * len<0: found a fallback result: continue looking for a roundtrip but no further fallbacks
+             * len>0: found a roundtrip result, done
+             */
+            len = 0;
+            /*
+             * We will turn off useFallback after finding a fallback,
+             * but we still get fallbacks from PUA code points as usual.
+             * Therefore, we will also need to check that we don't overwrite
+             * an early fallback with a later one.
+             */
+            useFallback = cnv->useFallback;
+
+            for(i = 0; i < choiceCount && len <= 0; ++i) {
+                uint32_t value;
+                int32_t len2;
+                int8_t cs0 = choices[i];
+                switch(cs0) {
+                case ASCII:
+                    if(sourceChar <= 0x7f) {
+                        targetValue = (uint32_t)sourceChar;
+                        len = 1;
+                        cs = cs0;
+                        g = 0;
+                    }
+                    break;
+                case ISO8859_1:
+                    if(GR96_START <= sourceChar && sourceChar <= GR96_END) {
+                        targetValue = (uint32_t)sourceChar - 0x80;
+                        len = 1;
+                        cs = cs0;
+                        g = 2;
+                    }
+                    break;
+                case HWKANA_7BIT:
+                    if((uint32_t)(sourceChar - HWKANA_START) <= (HWKANA_END - HWKANA_START)) {
+                        if(converterData->version==3) {
+                            /* JIS7: use G1 (SO) */
+                            /* Shift U+FF61..U+FF9F to bytes 21..5F. */
+                            targetValue = (uint32_t)(sourceChar - (HWKANA_START - 0x21));
+                            len = 1;
+                            pFromU2022State->cs[1] = cs = cs0; /* do not output an escape sequence */
+                            g = 1;
+                        } else if(converterData->version==4) {
+                            /* JIS8: use 8-bit bytes with any single-byte charset, see escape sequence output below */
+                            /* Shift U+FF61..U+FF9F to bytes A1..DF. */
+                            targetValue = (uint32_t)(sourceChar - (HWKANA_START - 0xa1));
+                            len = 1;
+
+                            cs = pFromU2022State->cs[0];
+                            if(IS_JP_DBCS(cs)) {
+                                /* switch from a DBCS charset to JISX201 */
+                                cs = (int8_t)JISX201;
+                            }
+                            /* else stay in the current G0 charset */
+                            g = 0;
+                        }
+                        /* else do not use HWKANA_7BIT with other versions */
+                    }
+                    break;
+                case JISX201:
+                    /* G0 SBCS */
+                    value = jisx201FromU(sourceChar);
+                    if(value <= 0x7f) {
+                        targetValue = value;
+                        len = 1;
+                        cs = cs0;
+                        g = 0;
+                        useFallback = FALSE;
+                    }
+                    break;
+                case JISX208:
+                    /* G0 DBCS from Shift-JIS table */
+                    len2 = MBCS_FROM_UCHAR32_ISO2022(
+                                converterData->myConverterArray[cs0],
+                                sourceChar, &value,
+                                useFallback, MBCS_OUTPUT_2);
+                    if(len2 == 2 || (len2 == -2 && len == 0)) {  /* only accept DBCS: abs(len)==2 */
+                        value = _2022FromSJIS(value);
+                        if(value != 0) {
+                            targetValue = value;
+                            len = len2;
+                            cs = cs0;
+                            g = 0;
+                            useFallback = FALSE;
+                        }
+                    } else if(len == 0 && useFallback &&
+                              (uint32_t)(sourceChar - HWKANA_START) <= (HWKANA_END - HWKANA_START)) {
+                        targetValue = hwkana_fb[sourceChar - HWKANA_START];
+                        len = -2;
+                        cs = cs0;
+                        g = 0;
+                        useFallback = FALSE;
+                    }
+                    break;
+                case ISO8859_7:
+                    /* G0 SBCS forced to 7-bit output */
+                    len2 = MBCS_SINGLE_FROM_UCHAR32(
+                                converterData->myConverterArray[cs0],
+                                sourceChar, &value,
+                                useFallback);
+                    if(len2 != 0 && !(len2 < 0 && len != 0) && GR96_START <= value && value <= GR96_END) {
+                        targetValue = value - 0x80;
+                        len = len2;
+                        cs = cs0;
+                        g = 2;
+                        useFallback = FALSE;
+                    }
+                    break;
+                default:
+                    /* G0 DBCS */
+                    len2 = MBCS_FROM_UCHAR32_ISO2022(
+                                converterData->myConverterArray[cs0],
+                                sourceChar, &value,
+                                useFallback, MBCS_OUTPUT_2);
+                    if(len2 == 2 || (len2 == -2 && len == 0)) {  /* only accept DBCS: abs(len)==2 */
+                        if(cs0 == KSC5601) {
+                            /*
+                             * Check for valid bytes for the encoding scheme.
+                             * This is necessary because the sub-converter (windows-949)
+                             * has a broader encoding scheme than is valid for 2022.
+                             */
+                            value = _2022FromGR94DBCS(value);
+                            if(value == 0) {
+                                break;
+                            }
+                        }
+                        targetValue = value;
+                        len = len2;
+                        cs = cs0;
+                        g = 0;
+                        useFallback = FALSE;
+                    }
+                    break;
+                }
+            }
+
+            if(len != 0) {
+                if(len < 0) {
+                    len = -len;  /* fallback */
+                }
+                outLen = 0; /* count output bytes */
+
+                /* write SI if necessary (only for JIS7) */
+                if(pFromU2022State->g == 1 && g == 0) {
+                    buffer[outLen++] = UCNV_SI;
+                    pFromU2022State->g = 0;
+                }
+
+                /* write the designation sequence if necessary */
+                if(cs != pFromU2022State->cs[g]) {
+                    int32_t escLen = escSeqCharsLen[cs];
+                    uprv_memcpy(buffer + outLen, escSeqChars[cs], escLen);
+                    outLen += escLen;
+                    pFromU2022State->cs[g] = cs;
+
+                    /* invalidate the choices[] */
+                    choiceCount = 0;
+                }
+
+                /* write the shift sequence if necessary */
+                if(g != pFromU2022State->g) {
+                    switch(g) {
+                    /* case 0 handled before writing escapes */
+                    case 1:
+                        buffer[outLen++] = UCNV_SO;
+                        pFromU2022State->g = 1;
+                        break;
+                    default: /* case 2 */
+                        buffer[outLen++] = 0x1b;
+                        buffer[outLen++] = 0x4e;
+                        break;
+                    /* no case 3: no SS3 in ISO-2022-JP-x */
+                    }
+                }
+
+                /* write the output bytes */
+                if(len == 1) {
+                    buffer[outLen++] = (char)targetValue;
+                } else /* len == 2 */ {
+                    buffer[outLen++] = (char)(targetValue >> 8);
+                    buffer[outLen++] = (char)targetValue;
+                }
+            } else {
+                /*
+                 * if we cannot find the character after checking all codepages
+                 * then this is an error
+                 */
+                *err = U_INVALID_CHAR_FOUND;
+                cnv->fromUChar32=sourceChar;
+                break;
+            }
+
+            if(sourceChar == CR || sourceChar == LF) {
+                /* reset the G2 state at the end of a line (conversion got us into ASCII or JISX201 already) */
+                pFromU2022State->cs[2] = 0;
+                choiceCount = 0;
+            }
+
+            /* output outLen>0 bytes in buffer[] */
+            if(outLen == 1) {
+                *target++ = buffer[0];
+                if(offsets) {
+                    *offsets++ = (int32_t)(source - args->source - 1); /* -1: known to be ASCII */
+                }
+            } else if(outLen == 2 && (target + 2) <= targetLimit) {
+                *target++ = buffer[0];
+                *target++ = buffer[1];
+                if(offsets) {
+                    int32_t sourceIndex = (int32_t)(source - args->source - U16_LENGTH(sourceChar));
+                    *offsets++ = sourceIndex;
+                    *offsets++ = sourceIndex;
+                }
+            } else {
+                fromUWriteUInt8(
+                    cnv,
+                    buffer, outLen,
+                    &target, (const char *)targetLimit,
+                    &offsets, (int32_t)(source - args->source - U16_LENGTH(sourceChar)),
+                    err);
+                if(U_FAILURE(*err)) {
+                    break;
+                }
+            }
+        } /* end if(myTargetIndex<myTargetLength) */
+        else{
+            *err =U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+
+    }/* end while(mySourceIndex<mySourceLength) */
+
+    /*
+     * the end of the input stream and detection of truncated input
+     * are handled by the framework, but for ISO-2022-JP conversion
+     * we need to be in ASCII mode at the very end
+     *
+     * conditions:
+     *   successful
+     *   in SO mode or not in ASCII mode
+     *   end of input and no truncated input
+     */
+    if( U_SUCCESS(*err) &&
+        (pFromU2022State->g!=0 || pFromU2022State->cs[0]!=ASCII) &&
+        args->flush && source>=sourceLimit && cnv->fromUChar32==0
+    ) {
+        int32_t sourceIndex;
+
+        outLen = 0;
+
+        if(pFromU2022State->g != 0) {
+            buffer[outLen++] = UCNV_SI;
+            pFromU2022State->g = 0;
+        }
+
+        if(pFromU2022State->cs[0] != ASCII) {
+            int32_t escLen = escSeqCharsLen[ASCII];
+            uprv_memcpy(buffer + outLen, escSeqChars[ASCII], escLen);
+            outLen += escLen;
+            pFromU2022State->cs[0] = (int8_t)ASCII;
+        }
+
+        /* get the source index of the last input character */
+        /*
+         * TODO this would be simpler and more reliable if we used a pair
+         * of sourceIndex/prevSourceIndex like in ucnvmbcs.c
+         * so that we could simply use the prevSourceIndex here;
+         * this code gives an incorrect result for the rare case of an unmatched
+         * trail surrogate that is alone in the last buffer of the text stream
+         */
+        sourceIndex=(int32_t)(source-args->source);
+        if(sourceIndex>0) {
+            --sourceIndex;
+            if( U16_IS_TRAIL(args->source[sourceIndex]) &&
+                (sourceIndex==0 || U16_IS_LEAD(args->source[sourceIndex-1]))
+            ) {
+                --sourceIndex;
+            }
+        } else {
+            sourceIndex=-1;
+        }
+
+        fromUWriteUInt8(
+            cnv,
+            buffer, outLen,
+            &target, (const char *)targetLimit,
+            &offsets, sourceIndex,
+            err);
+    }
+
+    /*save the state and return */
+    args->source = source;
+    args->target = (char*)target;
+}
+
+/*************** to unicode *******************/
+
+static void
+UConverter_toUnicode_ISO_2022_JP_OFFSETS_LOGIC(UConverterToUnicodeArgs *args,
+                                               UErrorCode* err){
+    char tempBuf[2];
+    const char *mySource = (char *) args->source;
+    UChar *myTarget = args->target;
+    const char *mySourceLimit = args->sourceLimit;
+    uint32_t targetUniChar = 0x0000;
+    uint32_t mySourceChar = 0x0000;
+    uint32_t tmpSourceChar = 0x0000;
+    UConverterDataISO2022* myData;
+    ISO2022State *pToU2022State;
+    StateEnum cs;
+
+    myData=(UConverterDataISO2022*)(args->converter->extraInfo);
+    pToU2022State = &myData->toU2022State;
+
+    if(myData->key != 0) {
+        /* continue with a partial escape sequence */
+        goto escape;
+    } else if(args->converter->toULength == 1 && mySource < mySourceLimit && myTarget < args->targetLimit) {
+        /* continue with a partial double-byte character */
+        mySourceChar = args->converter->toUBytes[0];
+        args->converter->toULength = 0;
+        cs = (StateEnum)pToU2022State->cs[pToU2022State->g];
+        targetUniChar = missingCharMarker;
+        goto getTrailByte;
+    }
+
+    while(mySource < mySourceLimit){
+
+        targetUniChar =missingCharMarker;
+
+        if(myTarget < args->targetLimit){
+
+            mySourceChar= (unsigned char) *mySource++;
+
+            switch(mySourceChar) {
+            case UCNV_SI:
+                if(myData->version==3) {
+                    pToU2022State->g=0;
+                    continue;
+                } else {
+                    /* only JIS7 uses SI/SO, not ISO-2022-JP-x */
+                    myData->isEmptySegment = FALSE;	/* reset this, we have a different error */
+                    break;
+                }
+
+            case UCNV_SO:
+                if(myData->version==3) {
+                    /* JIS7: switch to G1 half-width Katakana */
+                    pToU2022State->cs[1] = (int8_t)HWKANA_7BIT;
+                    pToU2022State->g=1;
+                    continue;
+                } else {
+                    /* only JIS7 uses SI/SO, not ISO-2022-JP-x */
+                    myData->isEmptySegment = FALSE;	/* reset this, we have a different error */
+                    break;
+                }
+
+            case ESC_2022:
+                mySource--;
+escape:
+                {
+                    const char * mySourceBefore = mySource;
+                    int8_t toULengthBefore = args->converter->toULength;
+
+                    changeState_2022(args->converter,&(mySource),
+                        mySourceLimit, ISO_2022_JP,err);
+
+                    /* If in ISO-2022-JP only and we successully completed an escape sequence, but previous segment was empty, create an error */
+                    if(myData->version==0 && myData->key==0 && U_SUCCESS(*err) && myData->isEmptySegment) {
+                        *err = U_ILLEGAL_ESCAPE_SEQUENCE;
+                        args->converter->toUCallbackReason = UCNV_IRREGULAR;
+                        args->converter->toULength = (int8_t)(toULengthBefore + (mySource - mySourceBefore));
+                    }
+                }
+
+                /* invalid or illegal escape sequence */
+                if(U_FAILURE(*err)){
+                    args->target = myTarget;
+                    args->source = mySource;
+                    myData->isEmptySegment = FALSE;	/* Reset to avoid future spurious errors */
+                    return;
+                }
+                /* If we successfully completed an escape sequence, we begin a new segment, empty so far */
+                if(myData->key==0) {
+                    myData->isEmptySegment = TRUE;
+                }
+                continue;
+
+            /* ISO-2022-JP does not use single-byte (C1) SS2 and SS3 */
+
+            case CR:
+                /*falls through*/
+            case LF:
+                /* automatically reset to single-byte mode */
+                if((StateEnum)pToU2022State->cs[0] != ASCII && (StateEnum)pToU2022State->cs[0] != JISX201) {
+                    pToU2022State->cs[0] = (int8_t)ASCII;
+                }
+                pToU2022State->cs[2] = 0;
+                pToU2022State->g = 0;
+                /* falls through */
+            default:
+                /* convert one or two bytes */
+                myData->isEmptySegment = FALSE;
+                cs = (StateEnum)pToU2022State->cs[pToU2022State->g];
+                if( (uint8_t)(mySourceChar - 0xa1) <= (0xdf - 0xa1) && myData->version==4 &&
+                    !IS_JP_DBCS(cs)
+                ) {
+                    /* 8-bit halfwidth katakana in any single-byte mode for JIS8 */
+                    targetUniChar = mySourceChar + (HWKANA_START - 0xa1);
+
+                    /* return from a single-shift state to the previous one */
+                    if(pToU2022State->g >= 2) {
+                        pToU2022State->g=pToU2022State->prevG;
+                    }
+                } else switch(cs) {
+                case ASCII:
+                    if(mySourceChar <= 0x7f) {
+                        targetUniChar = mySourceChar;
+                    }
+                    break;
+                case ISO8859_1:
+                    if(mySourceChar <= 0x7f) {
+                        targetUniChar = mySourceChar + 0x80;
+                    }
+                    /* return from a single-shift state to the previous one */
+                    pToU2022State->g=pToU2022State->prevG;
+                    break;
+                case ISO8859_7:
+                    if(mySourceChar <= 0x7f) {
+                        /* convert mySourceChar+0x80 to use a normal 8-bit table */
+                        targetUniChar =
+                            _MBCS_SINGLE_SIMPLE_GET_NEXT_BMP(
+                                myData->myConverterArray[cs],
+                                mySourceChar + 0x80);
+                    }
+                    /* return from a single-shift state to the previous one */
+                    pToU2022State->g=pToU2022State->prevG;
+                    break;
+                case JISX201:
+                    if(mySourceChar <= 0x7f) {
+                        targetUniChar = jisx201ToU(mySourceChar);
+                    }
+                    break;
+                case HWKANA_7BIT:
+                    if((uint8_t)(mySourceChar - 0x21) <= (0x5f - 0x21)) {
+                        /* 7-bit halfwidth Katakana */
+                        targetUniChar = mySourceChar + (HWKANA_START - 0x21);
+                    }
+                    break;
+                default:
+                    /* G0 DBCS */
+                    if(mySource < mySourceLimit) {
+                        int leadIsOk, trailIsOk;
+                        uint8_t trailByte;
+getTrailByte:
+                        trailByte = (uint8_t)*mySource;
+                        /*
+                         * Ticket 5691: consistent illegal sequences:
+                         * - We include at least the first byte in the illegal sequence.
+                         * - If any of the non-initial bytes could be the start of a character,
+                         *   we stop the illegal sequence before the first one of those.
+                         *
+                         * In ISO-2022 DBCS, if the second byte is in the 21..7e range or is
+                         * an ESC/SO/SI, we report only the first byte as the illegal sequence.
+                         * Otherwise we convert or report the pair of bytes.
+                         */
+                        leadIsOk = (uint8_t)(mySourceChar - 0x21) <= (0x7e - 0x21);
+                        trailIsOk = (uint8_t)(trailByte - 0x21) <= (0x7e - 0x21);
+                        if (leadIsOk && trailIsOk) {
+                            ++mySource;
+                            tmpSourceChar = (mySourceChar << 8) | trailByte;
+                            if(cs == JISX208) {
+                                _2022ToSJIS((uint8_t)mySourceChar, trailByte, tempBuf);
+                                mySourceChar = tmpSourceChar;
+                            } else {
+                                /* Copy before we modify tmpSourceChar so toUnicodeCallback() sees the correct bytes. */
+                                mySourceChar = tmpSourceChar;
+                                if (cs == KSC5601) {
+                                    tmpSourceChar += 0x8080;  /* = _2022ToGR94DBCS(tmpSourceChar) */
+                                }
+                                tempBuf[0] = (char)(tmpSourceChar >> 8);
+                                tempBuf[1] = (char)(tmpSourceChar);
+                            }
+                            targetUniChar = ucnv_MBCSSimpleGetNextUChar(myData->myConverterArray[cs], tempBuf, 2, FALSE);
+                        } else if (!(trailIsOk || IS_2022_CONTROL(trailByte))) {
+                            /* report a pair of illegal bytes if the second byte is not a DBCS starter */
+                            ++mySource;
+                            /* add another bit so that the code below writes 2 bytes in case of error */
+                            mySourceChar = 0x10000 | (mySourceChar << 8) | trailByte;
+                        }
+                    } else {
+                        args->converter->toUBytes[0] = (uint8_t)mySourceChar;
+                        args->converter->toULength = 1;
+                        goto endloop;
+                    }
+                }  /* End of inner switch */
+                break;
+            }  /* End of outer switch */
+            if(targetUniChar < (missingCharMarker-1/*0xfffe*/)){
+                if(args->offsets){
+                    args->offsets[myTarget - args->target] = (int32_t)(mySource - args->source - (mySourceChar <= 0xff ? 1 : 2));
+                }
+                *(myTarget++)=(UChar)targetUniChar;
+            }
+            else if(targetUniChar > missingCharMarker){
+                /* disassemble the surrogate pair and write to output*/
+                targetUniChar-=0x0010000;
+                *myTarget = (UChar)(0xd800+(UChar)(targetUniChar>>10));
+                if(args->offsets){
+                    args->offsets[myTarget - args->target] = (int32_t)(mySource - args->source - (mySourceChar <= 0xff ? 1 : 2));
+                }
+                ++myTarget;
+                if(myTarget< args->targetLimit){
+                    *myTarget = (UChar)(0xdc00+(UChar)(targetUniChar&0x3ff));
+                    if(args->offsets){
+                        args->offsets[myTarget - args->target] = (int32_t)(mySource - args->source - (mySourceChar <= 0xff ? 1 : 2));
+                    }
+                    ++myTarget;
+                }else{
+                    args->converter->UCharErrorBuffer[args->converter->UCharErrorBufferLength++]=
+                                    (UChar)(0xdc00+(UChar)(targetUniChar&0x3ff));
+                }
+
+            }
+            else{
+                /* Call the callback function*/
+                toUnicodeCallback(args->converter,mySourceChar,targetUniChar,err);
+                break;
+            }
+        }
+        else{    /* goes with "if(myTarget < args->targetLimit)"  way up near top of function */
+            *err =U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+    }
+endloop:
+    args->target = myTarget;
+    args->source = mySource;
+}
+
+
+/***************************************************************
+*   Rules for ISO-2022-KR encoding
+*   i) The KSC5601 designator sequence should appear only once in a file,
+*      at the begining of a line before any KSC5601 characters. This usually
+*      means that it appears by itself on the first line of the file
+*  ii) There are only 2 shifting sequences SO to shift into double byte mode
+*      and SI to shift into single byte mode
+*/
+static void
+UConverter_fromUnicode_ISO_2022_KR_OFFSETS_LOGIC_IBM(UConverterFromUnicodeArgs* args, UErrorCode* err){
+
+    UConverter* saveConv = args->converter;
+    UConverterDataISO2022 *myConverterData=(UConverterDataISO2022*)saveConv->extraInfo;
+    args->converter=myConverterData->currentConverter;
+
+    myConverterData->currentConverter->fromUChar32 = saveConv->fromUChar32;
+    ucnv_MBCSFromUnicodeWithOffsets(args,err);
+    saveConv->fromUChar32 = myConverterData->currentConverter->fromUChar32;
+
+    if(*err == U_BUFFER_OVERFLOW_ERROR) {
+        if(myConverterData->currentConverter->charErrorBufferLength > 0) {
+            uprv_memcpy(
+                saveConv->charErrorBuffer,
+                myConverterData->currentConverter->charErrorBuffer,
+                myConverterData->currentConverter->charErrorBufferLength);
+        }
+        saveConv->charErrorBufferLength = myConverterData->currentConverter->charErrorBufferLength;
+        myConverterData->currentConverter->charErrorBufferLength = 0;
+    }
+    args->converter=saveConv;
+}
+
+static void
+UConverter_fromUnicode_ISO_2022_KR_OFFSETS_LOGIC(UConverterFromUnicodeArgs* args, UErrorCode* err){
+
+    const UChar *source = args->source;
+    const UChar *sourceLimit = args->sourceLimit;
+    unsigned char *target = (unsigned char *) args->target;
+    unsigned char *targetLimit = (unsigned char *) args->targetLimit;
+    int32_t* offsets = args->offsets;
+    uint32_t targetByteUnit = 0x0000;
+    UChar32 sourceChar = 0x0000;
+    UBool isTargetByteDBCS;
+    UBool oldIsTargetByteDBCS;
+    UConverterDataISO2022 *converterData;
+    UConverterSharedData* sharedData;
+    UBool useFallback;
+    int32_t length =0;
+
+    converterData=(UConverterDataISO2022*)args->converter->extraInfo;
+    /* if the version is 1 then the user is requesting
+     * conversion with ibm-25546 pass the arguments to
+     * MBCS converter and return
+     */
+    if(converterData->version==1){
+        UConverter_fromUnicode_ISO_2022_KR_OFFSETS_LOGIC_IBM(args,err);
+        return;
+    }
+
+    /* initialize data */
+    sharedData = converterData->currentConverter->sharedData;
+    useFallback = args->converter->useFallback;
+    isTargetByteDBCS=(UBool)args->converter->fromUnicodeStatus;
+    oldIsTargetByteDBCS = isTargetByteDBCS;
+
+    isTargetByteDBCS   = (UBool) args->converter->fromUnicodeStatus;
+    if((sourceChar = args->converter->fromUChar32)!=0 && target <targetLimit) {
+        goto getTrail;
+    }
+    while(source < sourceLimit){
+
+        targetByteUnit = missingCharMarker;
+
+        if(target < (unsigned char*) args->targetLimit){
+            sourceChar = *source++;
+
+            /* do not convert SO/SI/ESC */
+            if(IS_2022_CONTROL(sourceChar)) {
+                /* callback(illegal) */
+                *err=U_ILLEGAL_CHAR_FOUND;
+                args->converter->fromUChar32=sourceChar;
+                break;
+            }
+
+            length = MBCS_FROM_UCHAR32_ISO2022(sharedData,sourceChar,&targetByteUnit,useFallback,MBCS_OUTPUT_2);
+            if(length < 0) {
+                length = -length;  /* fallback */
+            }
+            /* only DBCS or SBCS characters are expected*/
+            /* DB characters with high bit set to 1 are expected */
+            if( length > 2 || length==0 ||
+                (length == 1 && targetByteUnit > 0x7f) ||
+                (length == 2 &&
+                    ((uint16_t)(targetByteUnit - 0xa1a1) > (0xfefe - 0xa1a1) ||
+                    (uint8_t)(targetByteUnit - 0xa1) > (0xfe - 0xa1)))
+            ) {
+                targetByteUnit=missingCharMarker;
+            }
+            if (targetByteUnit != missingCharMarker){
+
+                oldIsTargetByteDBCS = isTargetByteDBCS;
+                isTargetByteDBCS = (UBool)(targetByteUnit>0x00FF);
+                  /* append the shift sequence */
+                if (oldIsTargetByteDBCS != isTargetByteDBCS ){
+
+                    if (isTargetByteDBCS)
+                        *target++ = UCNV_SO;
+                    else
+                        *target++ = UCNV_SI;
+                    if(offsets)
+                        *(offsets++) = (int32_t)(source - args->source-1);
+                }
+                /* write the targetUniChar  to target */
+                if(targetByteUnit <= 0x00FF){
+                    if( target < targetLimit){
+                        *(target++) = (unsigned char) targetByteUnit;
+                        if(offsets){
+                            *(offsets++) = (int32_t)(source - args->source-1);
+                        }
+
+                    }else{
+                        args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = (unsigned char) (targetByteUnit);
+                        *err = U_BUFFER_OVERFLOW_ERROR;
+                    }
+                }else{
+                    if(target < targetLimit){
+                        *(target++) =(unsigned char) ((targetByteUnit>>8) -0x80);
+                        if(offsets){
+                            *(offsets++) = (int32_t)(source - args->source-1);
+                        }
+                        if(target < targetLimit){
+                            *(target++) =(unsigned char) (targetByteUnit -0x80);
+                            if(offsets){
+                                *(offsets++) = (int32_t)(source - args->source-1);
+                            }
+                        }else{
+                            args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = (unsigned char) (targetByteUnit -0x80);
+                            *err = U_BUFFER_OVERFLOW_ERROR;
+                        }
+                    }else{
+                        args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = (unsigned char) ((targetByteUnit>>8) -0x80);
+                        args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = (unsigned char) (targetByteUnit-0x80);
+                        *err = U_BUFFER_OVERFLOW_ERROR;
+                    }
+                }
+
+            }
+            else{
+                /* oops.. the code point is unassingned
+                 * set the error and reason
+                 */
+
+                /*check if the char is a First surrogate*/
+                if(UTF_IS_SURROGATE(sourceChar)) {
+                    if(UTF_IS_SURROGATE_FIRST(sourceChar)) {
+getTrail:
+                        /*look ahead to find the trail surrogate*/
+                        if(source <  sourceLimit) {
+                            /* test the following code unit */
+                            UChar trail=(UChar) *source;
+                            if(UTF_IS_SECOND_SURROGATE(trail)) {
+                                source++;
+                                sourceChar=UTF16_GET_PAIR_VALUE(sourceChar, trail);
+                                *err = U_INVALID_CHAR_FOUND;
+                                /* convert this surrogate code point */
+                                /* exit this condition tree */
+                            } else {
+                                /* this is an unmatched lead code unit (1st surrogate) */
+                                /* callback(illegal) */
+                                *err=U_ILLEGAL_CHAR_FOUND;
+                            }
+                        } else {
+                            /* no more input */
+                            *err = U_ZERO_ERROR;
+                        }
+                    } else {
+                        /* this is an unmatched trail code unit (2nd surrogate) */
+                        /* callback(illegal) */
+                        *err=U_ILLEGAL_CHAR_FOUND;
+                    }
+                } else {
+                    /* callback(unassigned) for a BMP code point */
+                    *err = U_INVALID_CHAR_FOUND;
+                }
+
+                args->converter->fromUChar32=sourceChar;
+                break;
+            }
+        } /* end if(myTargetIndex<myTargetLength) */
+        else{
+            *err =U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+
+    }/* end while(mySourceIndex<mySourceLength) */
+
+    /*
+     * the end of the input stream and detection of truncated input
+     * are handled by the framework, but for ISO-2022-KR conversion
+     * we need to be in ASCII mode at the very end
+     *
+     * conditions:
+     *   successful
+     *   not in ASCII mode
+     *   end of input and no truncated input
+     */
+    if( U_SUCCESS(*err) &&
+        isTargetByteDBCS &&
+        args->flush && source>=sourceLimit && args->converter->fromUChar32==0
+    ) {
+        int32_t sourceIndex;
+
+        /* we are switching to ASCII */
+        isTargetByteDBCS=FALSE;
+
+        /* get the source index of the last input character */
+        /*
+         * TODO this would be simpler and more reliable if we used a pair
+         * of sourceIndex/prevSourceIndex like in ucnvmbcs.c
+         * so that we could simply use the prevSourceIndex here;
+         * this code gives an incorrect result for the rare case of an unmatched
+         * trail surrogate that is alone in the last buffer of the text stream
+         */
+        sourceIndex=(int32_t)(source-args->source);
+        if(sourceIndex>0) {
+            --sourceIndex;
+            if( U16_IS_TRAIL(args->source[sourceIndex]) &&
+                (sourceIndex==0 || U16_IS_LEAD(args->source[sourceIndex-1]))
+            ) {
+                --sourceIndex;
+            }
+        } else {
+            sourceIndex=-1;
+        }
+
+        fromUWriteUInt8(
+            args->converter,
+            SHIFT_IN_STR, 1,
+            &target, (const char *)targetLimit,
+            &offsets, sourceIndex,
+            err);
+    }
+
+    /*save the state and return */
+    args->source = source;
+    args->target = (char*)target;
+    args->converter->fromUnicodeStatus = (uint32_t)isTargetByteDBCS;
+}
+
+/************************ To Unicode ***************************************/
+
+static void
+UConverter_toUnicode_ISO_2022_KR_OFFSETS_LOGIC_IBM(UConverterToUnicodeArgs *args,
+                                                            UErrorCode* err){
+    char const* sourceStart;
+    UConverterDataISO2022* myData=(UConverterDataISO2022*)(args->converter->extraInfo);
+
+    UConverterToUnicodeArgs subArgs;
+    int32_t minArgsSize;
+
+    /* set up the subconverter arguments */
+    if(args->size<sizeof(UConverterToUnicodeArgs)) {
+        minArgsSize = args->size;
+    } else {
+        minArgsSize = (int32_t)sizeof(UConverterToUnicodeArgs);
+    }
+
+    uprv_memcpy(&subArgs, args, minArgsSize);
+    subArgs.size = (uint16_t)minArgsSize;
+    subArgs.converter = myData->currentConverter;
+
+    /* remember the original start of the input for offsets */
+    sourceStart = args->source;
+
+    if(myData->key != 0) {
+        /* continue with a partial escape sequence */
+        goto escape;
+    }
+
+    while(U_SUCCESS(*err) && args->source < args->sourceLimit) {
+        /*Find the end of the buffer e.g : Next Escape Seq | end of Buffer*/
+        subArgs.source = args->source;
+        subArgs.sourceLimit = getEndOfBuffer_2022(&(args->source), args->sourceLimit, args->flush);
+        if(subArgs.source != subArgs.sourceLimit) {
+            /*
+             * get the current partial byte sequence
+             *
+             * it needs to be moved between the public and the subconverter
+             * so that the conversion framework, which only sees the public
+             * converter, can handle truncated and illegal input etc.
+             */
+            if(args->converter->toULength > 0) {
+                uprv_memcpy(subArgs.converter->toUBytes, args->converter->toUBytes, args->converter->toULength);
+            }
+            subArgs.converter->toULength = args->converter->toULength;
+
+            /*
+             * Convert up to the end of the input, or to before the next escape character.
+             * Does not handle conversion extensions because the preToU[] state etc.
+             * is not copied.
+             */
+            ucnv_MBCSToUnicodeWithOffsets(&subArgs, err);
+
+            if(args->offsets != NULL && sourceStart != args->source) {
+                /* update offsets to base them on the actual start of the input */
+                int32_t *offsets = args->offsets;
+                UChar *target = args->target;
+                int32_t delta = (int32_t)(args->source - sourceStart);
+                while(target < subArgs.target) {
+                    if(*offsets >= 0) {
+                        *offsets += delta;
+                    }
+                    ++offsets;
+                    ++target;
+                }
+            }
+            args->source = subArgs.source;
+            args->target = subArgs.target;
+            args->offsets = subArgs.offsets;
+
+            /* copy input/error/overflow buffers */
+            if(subArgs.converter->toULength > 0) {
+                uprv_memcpy(args->converter->toUBytes, subArgs.converter->toUBytes, subArgs.converter->toULength);
+            }
+            args->converter->toULength = subArgs.converter->toULength;
+
+            if(*err == U_BUFFER_OVERFLOW_ERROR) {
+                if(subArgs.converter->UCharErrorBufferLength > 0) {
+                    uprv_memcpy(args->converter->UCharErrorBuffer, subArgs.converter->UCharErrorBuffer,
+                                subArgs.converter->UCharErrorBufferLength);
+                }
+                args->converter->UCharErrorBufferLength=subArgs.converter->UCharErrorBufferLength;
+                subArgs.converter->UCharErrorBufferLength = 0;
+            }
+        }
+
+        if (U_FAILURE(*err) || (args->source == args->sourceLimit)) {
+            return;
+        }
+
+escape:
+        changeState_2022(args->converter,
+               &(args->source),
+               args->sourceLimit,
+               ISO_2022_KR,
+               err);
+    }
+}
+
+static void
+UConverter_toUnicode_ISO_2022_KR_OFFSETS_LOGIC(UConverterToUnicodeArgs *args,
+                                                            UErrorCode* err){
+    char tempBuf[2];
+    const char *mySource = ( char *) args->source;
+    UChar *myTarget = args->target;
+    const char *mySourceLimit = args->sourceLimit;
+    UChar32 targetUniChar = 0x0000;
+    UChar mySourceChar = 0x0000;
+    UConverterDataISO2022* myData;
+    UConverterSharedData* sharedData ;
+    UBool useFallback;
+
+    myData=(UConverterDataISO2022*)(args->converter->extraInfo);
+    if(myData->version==1){
+        UConverter_toUnicode_ISO_2022_KR_OFFSETS_LOGIC_IBM(args,err);
+        return;
+    }
+
+    /* initialize state */
+    sharedData = myData->currentConverter->sharedData;
+    useFallback = args->converter->useFallback;
+
+    if(myData->key != 0) {
+        /* continue with a partial escape sequence */
+        goto escape;
+    } else if(args->converter->toULength == 1 && mySource < mySourceLimit && myTarget < args->targetLimit) {
+        /* continue with a partial double-byte character */
+        mySourceChar = args->converter->toUBytes[0];
+        args->converter->toULength = 0;
+        goto getTrailByte;
+    }
+
+    while(mySource< mySourceLimit){
+
+        if(myTarget < args->targetLimit){
+
+            mySourceChar= (unsigned char) *mySource++;
+
+            if(mySourceChar==UCNV_SI){
+                myData->toU2022State.g = 0;
+                if (myData->isEmptySegment) {
+                    myData->isEmptySegment = FALSE;	/* we are handling it, reset to avoid future spurious errors */
+                    *err = U_ILLEGAL_ESCAPE_SEQUENCE;
+                    args->converter->toUCallbackReason = UCNV_IRREGULAR;
+                    args->converter->toUBytes[0] = (uint8_t)mySourceChar;
+                    args->converter->toULength = 1;
+                    args->target = myTarget;
+                    args->source = mySource;
+                    return;
+                }
+                /*consume the source */
+                continue;
+            }else if(mySourceChar==UCNV_SO){
+                myData->toU2022State.g = 1;
+                myData->isEmptySegment = TRUE;	/* Begin a new segment, empty so far */
+                /*consume the source */
+                continue;
+            }else if(mySourceChar==ESC_2022){
+                mySource--;
+escape:
+                myData->isEmptySegment = FALSE;	/* Any invalid ESC sequences will be detected separately, so just reset this */
+                changeState_2022(args->converter,&(mySource),
+                                mySourceLimit, ISO_2022_KR, err);
+                if(U_FAILURE(*err)){
+                    args->target = myTarget;
+                    args->source = mySource;
+                    return;
+                }
+                continue;
+            }
+
+            myData->isEmptySegment = FALSE;	/* Any invalid char errors will be detected separately, so just reset this */
+            if(myData->toU2022State.g == 1) {
+                if(mySource < mySourceLimit) {
+                    int leadIsOk, trailIsOk;
+                    uint8_t trailByte;
+getTrailByte:
+                    targetUniChar = missingCharMarker;
+                    trailByte = (uint8_t)*mySource;
+                    /*
+                     * Ticket 5691: consistent illegal sequences:
+                     * - We include at least the first byte in the illegal sequence.
+                     * - If any of the non-initial bytes could be the start of a character,
+                     *   we stop the illegal sequence before the first one of those.
+                     *
+                     * In ISO-2022 DBCS, if the second byte is in the 21..7e range or is
+                     * an ESC/SO/SI, we report only the first byte as the illegal sequence.
+                     * Otherwise we convert or report the pair of bytes.
+                     */
+                    leadIsOk = (uint8_t)(mySourceChar - 0x21) <= (0x7e - 0x21);
+                    trailIsOk = (uint8_t)(trailByte - 0x21) <= (0x7e - 0x21);
+                    if (leadIsOk && trailIsOk) {
+                        ++mySource;
+                        tempBuf[0] = (char)(mySourceChar + 0x80);
+                        tempBuf[1] = (char)(trailByte + 0x80);
+                        targetUniChar = ucnv_MBCSSimpleGetNextUChar(sharedData, tempBuf, 2, useFallback);
+                        mySourceChar = (mySourceChar << 8) | trailByte;
+                    } else if (!(trailIsOk || IS_2022_CONTROL(trailByte))) {
+                        /* report a pair of illegal bytes if the second byte is not a DBCS starter */
+                        ++mySource;
+                        /* add another bit so that the code below writes 2 bytes in case of error */
+                        mySourceChar = 0x10000 | (mySourceChar << 8) | trailByte;
+                    }
+                } else {
+                    args->converter->toUBytes[0] = (uint8_t)mySourceChar;
+                    args->converter->toULength = 1;
+                    break;
+                }
+            }
+            else if(mySourceChar <= 0x7f) {
+                targetUniChar = ucnv_MBCSSimpleGetNextUChar(sharedData, mySource - 1, 1, useFallback);
+            } else {
+                targetUniChar = 0xffff;
+            }
+            if(targetUniChar < 0xfffe){
+                if(args->offsets) {
+                    args->offsets[myTarget - args->target] = (int32_t)(mySource - args->source - (mySourceChar <= 0xff ? 1 : 2));
+                }
+                *(myTarget++)=(UChar)targetUniChar;
+            }
+            else {
+                /* Call the callback function*/
+                toUnicodeCallback(args->converter,mySourceChar,targetUniChar,err);
+                break;
+            }
+        }
+        else{
+            *err =U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+    }
+    args->target = myTarget;
+    args->source = mySource;
+}
+
+/*************************** END ISO2022-KR *********************************/
+
+/*************************** ISO-2022-CN *********************************
+*
+* Rules for ISO-2022-CN Encoding:
+* i)   The designator sequence must appear once on a line before any instance
+*      of character set it designates.
+* ii)  If two lines contain characters from the same character set, both lines
+*      must include the designator sequence.
+* iii) Once the designator sequence is known, a shifting sequence has to be found
+*      to invoke the  shifting
+* iv)  All lines start in ASCII and end in ASCII.
+* v)   Four shifting sequences are employed for this purpose:
+*
+*      Sequcence   ASCII Eq    Charsets
+*      ----------  -------    ---------
+*      SI           <SI>        US-ASCII
+*      SO           <SO>        CNS-11643-1992 Plane 1, GB2312, ISO-IR-165
+*      SS2          <ESC>N      CNS-11643-1992 Plane 2
+*      SS3          <ESC>O      CNS-11643-1992 Planes 3-7
+*
+* vi)
+*      SOdesignator  : ESC "$" ")" finalchar_for_SO
+*      SS2designator : ESC "$" "*" finalchar_for_SS2
+*      SS3designator : ESC "$" "+" finalchar_for_SS3
+*
+*      ESC $ ) A       Indicates the bytes following SO are Chinese
+*       characters as defined in GB 2312-80, until
+*       another SOdesignation appears
+*
+*
+*      ESC $ ) E       Indicates the bytes following SO are as defined
+*       in ISO-IR-165 (for details, see section 2.1),
+*       until another SOdesignation appears
+*
+*      ESC $ ) G       Indicates the bytes following SO are as defined
+*       in CNS 11643-plane-1, until another
+*       SOdesignation appears
+*
+*      ESC $ * H       Indicates the two bytes immediately following
+*       SS2 is a Chinese character as defined in CNS
+*       11643-plane-2, until another SS2designation
+*       appears
+*       (Meaning <ESC>N must preceed every 2 byte
+*        sequence.)
+*
+*      ESC $ + I       Indicates the immediate two bytes following SS3
+*       is a Chinese character as defined in CNS
+*       11643-plane-3, until another SS3designation
+*       appears
+*       (Meaning <ESC>O must preceed every 2 byte
+*        sequence.)
+*
+*      ESC $ + J       Indicates the immediate two bytes following SS3
+*       is a Chinese character as defined in CNS
+*       11643-plane-4, until another SS3designation
+*       appears
+*       (In English: <ESC>O must preceed every 2 byte
+*        sequence.)
+*
+*      ESC $ + K       Indicates the immediate two bytes following SS3
+*       is a Chinese character as defined in CNS
+*       11643-plane-5, until another SS3designation
+*       appears
+*
+*      ESC $ + L       Indicates the immediate two bytes following SS3
+*       is a Chinese character as defined in CNS
+*       11643-plane-6, until another SS3designation
+*       appears
+*
+*      ESC $ + M       Indicates the immediate two bytes following SS3
+*       is a Chinese character as defined in CNS
+*       11643-plane-7, until another SS3designation
+*       appears
+*
+*       As in ISO-2022-CN, each line starts in ASCII, and ends in ASCII, and
+*       has its own designation information before any Chinese characters
+*       appear
+*
+*/
+
+/* The following are defined this way to make the strings truely readonly */
+static const char GB_2312_80_STR[] = "\x1B\x24\x29\x41";
+static const char ISO_IR_165_STR[] = "\x1B\x24\x29\x45";
+static const char CNS_11643_1992_Plane_1_STR[] = "\x1B\x24\x29\x47";
+static const char CNS_11643_1992_Plane_2_STR[] = "\x1B\x24\x2A\x48";
+static const char CNS_11643_1992_Plane_3_STR[] = "\x1B\x24\x2B\x49";
+static const char CNS_11643_1992_Plane_4_STR[] = "\x1B\x24\x2B\x4A";
+static const char CNS_11643_1992_Plane_5_STR[] = "\x1B\x24\x2B\x4B";
+static const char CNS_11643_1992_Plane_6_STR[] = "\x1B\x24\x2B\x4C";
+static const char CNS_11643_1992_Plane_7_STR[] = "\x1B\x24\x2B\x4D";
+
+/********************** ISO2022-CN Data **************************/
+static const char* const escSeqCharsCN[10] ={
+        SHIFT_IN_STR,           /* ASCII */
+        GB_2312_80_STR,
+        ISO_IR_165_STR,
+        CNS_11643_1992_Plane_1_STR,
+        CNS_11643_1992_Plane_2_STR,
+        CNS_11643_1992_Plane_3_STR,
+        CNS_11643_1992_Plane_4_STR,
+        CNS_11643_1992_Plane_5_STR,
+        CNS_11643_1992_Plane_6_STR,
+        CNS_11643_1992_Plane_7_STR
+};
+
+static void
+UConverter_fromUnicode_ISO_2022_CN_OFFSETS_LOGIC(UConverterFromUnicodeArgs* args, UErrorCode* err){
+    UConverter *cnv = args->converter;
+    UConverterDataISO2022 *converterData;
+    ISO2022State *pFromU2022State;
+    uint8_t *target = (uint8_t *) args->target;
+    const uint8_t *targetLimit = (const uint8_t *) args->targetLimit;
+    const UChar* source = args->source;
+    const UChar* sourceLimit = args->sourceLimit;
+    int32_t* offsets = args->offsets;
+    UChar32 sourceChar;
+    char buffer[8];
+    int32_t len;
+    int8_t choices[3];
+    int32_t choiceCount;
+    uint32_t targetValue = 0;
+    UBool useFallback;
+
+    /* set up the state */
+    converterData     = (UConverterDataISO2022*)cnv->extraInfo;
+    pFromU2022State   = &converterData->fromU2022State;
+
+    choiceCount = 0;
+
+    /* check if the last codepoint of previous buffer was a lead surrogate*/
+    if((sourceChar = cnv->fromUChar32)!=0 && target< targetLimit) {
+        goto getTrail;
+    }
+
+    while( source < sourceLimit){
+        if(target < targetLimit){
+
+            sourceChar  = *(source++);
+            /*check if the char is a First surrogate*/
+             if(UTF_IS_SURROGATE(sourceChar)) {
+                if(UTF_IS_SURROGATE_FIRST(sourceChar)) {
+getTrail:
+                    /*look ahead to find the trail surrogate*/
+                    if(source < sourceLimit) {
+                        /* test the following code unit */
+                        UChar trail=(UChar) *source;
+                        if(UTF_IS_SECOND_SURROGATE(trail)) {
+                            source++;
+                            sourceChar=UTF16_GET_PAIR_VALUE(sourceChar, trail);
+                            cnv->fromUChar32=0x00;
+                            /* convert this supplementary code point */
+                            /* exit this condition tree */
+                        } else {
+                            /* this is an unmatched lead code unit (1st surrogate) */
+                            /* callback(illegal) */
+                            *err=U_ILLEGAL_CHAR_FOUND;
+                            cnv->fromUChar32=sourceChar;
+                            break;
+                        }
+                    } else {
+                        /* no more input */
+                        cnv->fromUChar32=sourceChar;
+                        break;
+                    }
+                } else {
+                    /* this is an unmatched trail code unit (2nd surrogate) */
+                    /* callback(illegal) */
+                    *err=U_ILLEGAL_CHAR_FOUND;
+                    cnv->fromUChar32=sourceChar;
+                    break;
+                }
+            }
+
+            /* do the conversion */
+            if(sourceChar <= 0x007f ){
+                /* do not convert SO/SI/ESC */
+                if(IS_2022_CONTROL(sourceChar)) {
+                    /* callback(illegal) */
+                    *err=U_ILLEGAL_CHAR_FOUND;
+                    cnv->fromUChar32=sourceChar;
+                    break;
+                }
+
+                /* US-ASCII */
+                if(pFromU2022State->g == 0) {
+                    buffer[0] = (char)sourceChar;
+                    len = 1;
+                } else {
+                    buffer[0] = UCNV_SI;
+                    buffer[1] = (char)sourceChar;
+                    len = 2;
+                    pFromU2022State->g = 0;
+                    choiceCount = 0;
+                }
+                if(sourceChar == CR || sourceChar == LF) {
+                    /* reset the state at the end of a line */
+                    uprv_memset(pFromU2022State, 0, sizeof(ISO2022State));
+                    choiceCount = 0;
+                }
+            }
+            else{
+                /* convert U+0080..U+10ffff */
+                int32_t i;
+                int8_t cs, g;
+
+                if(choiceCount == 0) {
+                    /* try the current SO/G1 converter first */
+                    choices[0] = pFromU2022State->cs[1];
+
+                    /* default to GB2312_1 if none is designated yet */
+                    if(choices[0] == 0) {
+                        choices[0] = GB2312_1;
+                    }
+
+                    if(converterData->version == 0) {
+                        /* ISO-2022-CN */
+
+                        /* try the other SO/G1 converter; a CNS_11643_1 lookup may result in any plane */
+                        if(choices[0] == GB2312_1) {
+                            choices[1] = (int8_t)CNS_11643_1;
+                        } else {
+                            choices[1] = (int8_t)GB2312_1;
+                        }
+
+                        choiceCount = 2;
+                    } else if (converterData->version == 1) {
+                        /* ISO-2022-CN-EXT */
+
+                        /* try one of the other converters */
+                        switch(choices[0]) {
+                        case GB2312_1:
+                            choices[1] = (int8_t)CNS_11643_1;
+                            choices[2] = (int8_t)ISO_IR_165;
+                            break;
+                        case ISO_IR_165:
+                            choices[1] = (int8_t)GB2312_1;
+                            choices[2] = (int8_t)CNS_11643_1;
+                            break;
+                        default: /* CNS_11643_x */
+                            choices[1] = (int8_t)GB2312_1;
+                            choices[2] = (int8_t)ISO_IR_165;
+                            break;
+                        }
+
+                        choiceCount = 3;
+                    } else {
+                        choices[0] = (int8_t)CNS_11643_1;
+                        choices[1] = (int8_t)GB2312_1;
+                    }
+                }
+
+                cs = g = 0;
+                /*
+                 * len==0: no mapping found yet
+                 * len<0: found a fallback result: continue looking for a roundtrip but no further fallbacks
+                 * len>0: found a roundtrip result, done
+                 */
+                len = 0;
+                /*
+                 * We will turn off useFallback after finding a fallback,
+                 * but we still get fallbacks from PUA code points as usual.
+                 * Therefore, we will also need to check that we don't overwrite
+                 * an early fallback with a later one.
+                 */
+                useFallback = cnv->useFallback;
+
+                for(i = 0; i < choiceCount && len <= 0; ++i) {
+                    int8_t cs0 = choices[i];
+                    if(cs0 > 0) {
+                        uint32_t value;
+                        int32_t len2;
+                        if(cs0 >= CNS_11643_0) {
+                            len2 = MBCS_FROM_UCHAR32_ISO2022(
+                                        converterData->myConverterArray[CNS_11643],
+                                        sourceChar,
+                                        &value,
+                                        useFallback,
+                                        MBCS_OUTPUT_3);
+                            if(len2 == 3 || (len2 == -3 && len == 0)) {
+                                targetValue = value;
+                                cs = (int8_t)(CNS_11643_0 + (value >> 16) - 0x80);
+                                if(len2 >= 0) {
+                                    len = 2;
+                                } else {
+                                    len = -2;
+                                    useFallback = FALSE;
+                                }
+                                if(cs == CNS_11643_1) {
+                                    g = 1;
+                                } else if(cs == CNS_11643_2) {
+                                    g = 2;
+                                } else /* plane 3..7 */ if(converterData->version == 1) {
+                                    g = 3;
+                                } else {
+                                    /* ISO-2022-CN (without -EXT) does not support plane 3..7 */
+                                    len = 0;
+                                }
+                            }
+                        } else {
+                            /* GB2312_1 or ISO-IR-165 */
+                            len2 = MBCS_FROM_UCHAR32_ISO2022(
+                                        converterData->myConverterArray[cs0],
+                                        sourceChar,
+                                        &value,
+                                        useFallback,
+                                        MBCS_OUTPUT_2);
+                            if(len2 == 2 || (len2 == -2 && len == 0)) {
+                                targetValue = value;
+                                len = len2;
+                                cs = cs0;
+                                g = 1;
+                                useFallback = FALSE;
+                            }
+                        }
+                    }
+                }
+
+                if(len != 0) {
+                    len = 0; /* count output bytes; it must have been abs(len) == 2 */
+
+                    /* write the designation sequence if necessary */
+                    if(cs != pFromU2022State->cs[g]) {
+                        if(cs < CNS_11643) {
+                            uprv_memcpy(buffer, escSeqCharsCN[cs], 4);
+                        } else {
+                            uprv_memcpy(buffer, escSeqCharsCN[CNS_11643 + (cs - CNS_11643_1)], 4);
+                        }
+                        len = 4;
+                        pFromU2022State->cs[g] = cs;
+                        if(g == 1) {
+                            /* changing the SO/G1 charset invalidates the choices[] */
+                            choiceCount = 0;
+                        }
+                    }
+
+                    /* write the shift sequence if necessary */
+                    if(g != pFromU2022State->g) {
+                        switch(g) {
+                        case 1:
+                            buffer[len++] = UCNV_SO;
+
+                            /* set the new state only if it is the locking shift SO/G1, not for SS2 or SS3 */
+                            pFromU2022State->g = 1;
+                            break;
+                        case 2:
+                            buffer[len++] = 0x1b;
+                            buffer[len++] = 0x4e;
+                            break;
+                        default: /* case 3 */
+                            buffer[len++] = 0x1b;
+                            buffer[len++] = 0x4f;
+                            break;
+                        }
+                    }
+
+                    /* write the two output bytes */
+                    buffer[len++] = (char)(targetValue >> 8);
+                    buffer[len++] = (char)targetValue;
+                } else {
+                    /* if we cannot find the character after checking all codepages
+                     * then this is an error
+                     */
+                    *err = U_INVALID_CHAR_FOUND;
+                    cnv->fromUChar32=sourceChar;
+                    break;
+                }
+            }
+
+            /* output len>0 bytes in buffer[] */
+            if(len == 1) {
+                *target++ = buffer[0];
+                if(offsets) {
+                    *offsets++ = (int32_t)(source - args->source - 1); /* -1: known to be ASCII */
+                }
+            } else if(len == 2 && (target + 2) <= targetLimit) {
+                *target++ = buffer[0];
+                *target++ = buffer[1];
+                if(offsets) {
+                    int32_t sourceIndex = (int32_t)(source - args->source - U16_LENGTH(sourceChar));
+                    *offsets++ = sourceIndex;
+                    *offsets++ = sourceIndex;
+                }
+            } else {
+                fromUWriteUInt8(
+                    cnv,
+                    buffer, len,
+                    &target, (const char *)targetLimit,
+                    &offsets, (int32_t)(source - args->source - U16_LENGTH(sourceChar)),
+                    err);
+                if(U_FAILURE(*err)) {
+                    break;
+                }
+            }
+        } /* end if(myTargetIndex<myTargetLength) */
+        else{
+            *err =U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+
+    }/* end while(mySourceIndex<mySourceLength) */
+
+    /*
+     * the end of the input stream and detection of truncated input
+     * are handled by the framework, but for ISO-2022-CN conversion
+     * we need to be in ASCII mode at the very end
+     *
+     * conditions:
+     *   successful
+     *   not in ASCII mode
+     *   end of input and no truncated input
+     */
+    if( U_SUCCESS(*err) &&
+        pFromU2022State->g!=0 &&
+        args->flush && source>=sourceLimit && cnv->fromUChar32==0
+    ) {
+        int32_t sourceIndex;
+
+        /* we are switching to ASCII */
+        pFromU2022State->g=0;
+
+        /* get the source index of the last input character */
+        /*
+         * TODO this would be simpler and more reliable if we used a pair
+         * of sourceIndex/prevSourceIndex like in ucnvmbcs.c
+         * so that we could simply use the prevSourceIndex here;
+         * this code gives an incorrect result for the rare case of an unmatched
+         * trail surrogate that is alone in the last buffer of the text stream
+         */
+        sourceIndex=(int32_t)(source-args->source);
+        if(sourceIndex>0) {
+            --sourceIndex;
+            if( U16_IS_TRAIL(args->source[sourceIndex]) &&
+                (sourceIndex==0 || U16_IS_LEAD(args->source[sourceIndex-1]))
+            ) {
+                --sourceIndex;
+            }
+        } else {
+            sourceIndex=-1;
+        }
+
+        fromUWriteUInt8(
+            cnv,
+            SHIFT_IN_STR, 1,
+            &target, (const char *)targetLimit,
+            &offsets, sourceIndex,
+            err);
+    }
+
+    /*save the state and return */
+    args->source = source;
+    args->target = (char*)target;
+}
+
+
+static void
+UConverter_toUnicode_ISO_2022_CN_OFFSETS_LOGIC(UConverterToUnicodeArgs *args,
+                                               UErrorCode* err){
+    char tempBuf[3];
+    const char *mySource = (char *) args->source;
+    UChar *myTarget = args->target;
+    const char *mySourceLimit = args->sourceLimit;
+    uint32_t targetUniChar = 0x0000;
+    uint32_t mySourceChar = 0x0000;
+    UConverterDataISO2022* myData;
+    ISO2022State *pToU2022State;
+
+    myData=(UConverterDataISO2022*)(args->converter->extraInfo);
+    pToU2022State = &myData->toU2022State;
+
+    if(myData->key != 0) {
+        /* continue with a partial escape sequence */
+        goto escape;
+    } else if(args->converter->toULength == 1 && mySource < mySourceLimit && myTarget < args->targetLimit) {
+        /* continue with a partial double-byte character */
+        mySourceChar = args->converter->toUBytes[0];
+        args->converter->toULength = 0;
+        targetUniChar = missingCharMarker;
+        goto getTrailByte;
+    }
+
+    while(mySource < mySourceLimit){
+
+        targetUniChar =missingCharMarker;
+
+        if(myTarget < args->targetLimit){
+
+            mySourceChar= (unsigned char) *mySource++;
+
+            switch(mySourceChar){
+            case UCNV_SI:
+                pToU2022State->g=0;
+                if (myData->isEmptySegment) {
+                    myData->isEmptySegment = FALSE;	/* we are handling it, reset to avoid future spurious errors */
+                    *err = U_ILLEGAL_ESCAPE_SEQUENCE;
+                    args->converter->toUCallbackReason = UCNV_IRREGULAR;
+                    args->converter->toUBytes[0] = mySourceChar;
+                    args->converter->toULength = 1;
+                    args->target = myTarget;
+                    args->source = mySource;
+                    return;
+                }
+                continue;
+
+            case UCNV_SO:
+                if(pToU2022State->cs[1] != 0) {
+                    pToU2022State->g=1;
+                    myData->isEmptySegment = TRUE;	/* Begin a new segment, empty so far */
+                    continue;
+                } else {
+                    /* illegal to have SO before a matching designator */
+                    myData->isEmptySegment = FALSE;	/* Handling a different error, reset this to avoid future spurious errs */
+                    break;
+                }
+
+            case ESC_2022:
+                mySource--;
+escape:
+                {
+                    const char * mySourceBefore = mySource;
+                    int8_t toULengthBefore = args->converter->toULength;
+
+                    changeState_2022(args->converter,&(mySource),
+                        mySourceLimit, ISO_2022_CN,err);
+
+                    /* After SO there must be at least one character before a designator (designator error handled separately) */
+                    if(myData->key==0 && U_SUCCESS(*err) && myData->isEmptySegment) {
+                        *err = U_ILLEGAL_ESCAPE_SEQUENCE;
+                        args->converter->toUCallbackReason = UCNV_IRREGULAR;
+                        args->converter->toULength = (int8_t)(toULengthBefore + (mySource - mySourceBefore));
+                    }
+                }
+
+                /* invalid or illegal escape sequence */
+                if(U_FAILURE(*err)){
+                    args->target = myTarget;
+                    args->source = mySource;
+                    myData->isEmptySegment = FALSE;	/* Reset to avoid future spurious errors */
+                    return;
+                }
+                continue;
+
+            /* ISO-2022-CN does not use single-byte (C1) SS2 and SS3 */
+
+            case CR:
+                /*falls through*/
+            case LF:
+                uprv_memset(pToU2022State, 0, sizeof(ISO2022State));
+                /* falls through */
+            default:
+                /* convert one or two bytes */
+                myData->isEmptySegment = FALSE;
+                if(pToU2022State->g != 0) {
+                    if(mySource < mySourceLimit) {
+                        UConverterSharedData *cnv;
+                        StateEnum tempState;
+                        int32_t tempBufLen;
+                        int leadIsOk, trailIsOk;
+                        uint8_t trailByte;
+getTrailByte:
+                        trailByte = (uint8_t)*mySource;
+                        /*
+                         * Ticket 5691: consistent illegal sequences:
+                         * - We include at least the first byte in the illegal sequence.
+                         * - If any of the non-initial bytes could be the start of a character,
+                         *   we stop the illegal sequence before the first one of those.
+                         *
+                         * In ISO-2022 DBCS, if the second byte is in the 21..7e range or is
+                         * an ESC/SO/SI, we report only the first byte as the illegal sequence.
+                         * Otherwise we convert or report the pair of bytes.
+                         */
+                        leadIsOk = (uint8_t)(mySourceChar - 0x21) <= (0x7e - 0x21);
+                        trailIsOk = (uint8_t)(trailByte - 0x21) <= (0x7e - 0x21);
+                        if (leadIsOk && trailIsOk) {
+                            ++mySource;
+                            tempState = (StateEnum)pToU2022State->cs[pToU2022State->g];
+                            if(tempState >= CNS_11643_0) {
+                                cnv = myData->myConverterArray[CNS_11643];
+                                tempBuf[0] = (char) (0x80+(tempState-CNS_11643_0));
+                                tempBuf[1] = (char) (mySourceChar);
+                                tempBuf[2] = (char) trailByte;
+                                tempBufLen = 3;
+
+                            }else{
+                                cnv = myData->myConverterArray[tempState];
+                                tempBuf[0] = (char) (mySourceChar);
+                                tempBuf[1] = (char) trailByte;
+                                tempBufLen = 2;
+                            }
+                            targetUniChar = ucnv_MBCSSimpleGetNextUChar(cnv, tempBuf, tempBufLen, FALSE);
+                            mySourceChar = (mySourceChar << 8) | trailByte;
+                        } else if (!(trailIsOk || IS_2022_CONTROL(trailByte))) {
+                            /* report a pair of illegal bytes if the second byte is not a DBCS starter */
+                            ++mySource;
+                            /* add another bit so that the code below writes 2 bytes in case of error */
+                            mySourceChar = 0x10000 | (mySourceChar << 8) | trailByte;
+                        }
+                        if(pToU2022State->g>=2) {
+                            /* return from a single-shift state to the previous one */
+                            pToU2022State->g=pToU2022State->prevG;
+                        }
+                    } else {
+                        args->converter->toUBytes[0] = (uint8_t)mySourceChar;
+                        args->converter->toULength = 1;
+                        goto endloop;
+                    }
+                }
+                else{
+                    if(mySourceChar <= 0x7f) {
+                        targetUniChar = (UChar) mySourceChar;
+                    }
+                }
+                break;
+            }
+            if(targetUniChar < (missingCharMarker-1/*0xfffe*/)){
+                if(args->offsets){
+                    args->offsets[myTarget - args->target] = (int32_t)(mySource - args->source - (mySourceChar <= 0xff ? 1 : 2));
+                }
+                *(myTarget++)=(UChar)targetUniChar;
+            }
+            else if(targetUniChar > missingCharMarker){
+                /* disassemble the surrogate pair and write to output*/
+                targetUniChar-=0x0010000;
+                *myTarget = (UChar)(0xd800+(UChar)(targetUniChar>>10));
+                if(args->offsets){
+                    args->offsets[myTarget - args->target] = (int32_t)(mySource - args->source - (mySourceChar <= 0xff ? 1 : 2));
+                }
+                ++myTarget;
+                if(myTarget< args->targetLimit){
+                    *myTarget = (UChar)(0xdc00+(UChar)(targetUniChar&0x3ff));
+                    if(args->offsets){
+                        args->offsets[myTarget - args->target] = (int32_t)(mySource - args->source - (mySourceChar <= 0xff ? 1 : 2));
+                    }
+                    ++myTarget;
+                }else{
+                    args->converter->UCharErrorBuffer[args->converter->UCharErrorBufferLength++]=
+                                    (UChar)(0xdc00+(UChar)(targetUniChar&0x3ff));
+                }
+
+            }
+            else{
+                /* Call the callback function*/
+                toUnicodeCallback(args->converter,mySourceChar,targetUniChar,err);
+                break;
+            }
+        }
+        else{
+            *err =U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+    }
+endloop:
+    args->target = myTarget;
+    args->source = mySource;
+}
+
+static void
+_ISO_2022_WriteSub(UConverterFromUnicodeArgs *args, int32_t offsetIndex, UErrorCode *err) {
+    UConverter *cnv = args->converter;
+    UConverterDataISO2022 *myConverterData=(UConverterDataISO2022 *) cnv->extraInfo;
+    ISO2022State *pFromU2022State=&myConverterData->fromU2022State;
+    char *p, *subchar;
+    char buffer[8];
+    int32_t length;
+
+    subchar=(char *)cnv->subChars;
+    length=cnv->subCharLen; /* assume length==1 for most variants */
+
+    p = buffer;
+    switch(myConverterData->locale[0]){
+    case 'j':
+        {
+            int8_t cs;
+
+            if(pFromU2022State->g == 1) {
+                /* JIS7: switch from G1 to G0 */
+                pFromU2022State->g = 0;
+                *p++ = UCNV_SI;
+            }
+
+            cs = pFromU2022State->cs[0];
+            if(cs != ASCII && cs != JISX201) {
+                /* not in ASCII or JIS X 0201: switch to ASCII */
+                pFromU2022State->cs[0] = (int8_t)ASCII;
+                *p++ = '\x1b';
+                *p++ = '\x28';
+                *p++ = '\x42';
+            }
+
+            *p++ = subchar[0];
+            break;
+        }
+    case 'c':
+        if(pFromU2022State->g != 0) {
+            /* not in ASCII mode: switch to ASCII */
+            pFromU2022State->g = 0;
+            *p++ = UCNV_SI;
+        }
+        *p++ = subchar[0];
+        break;
+    case 'k':
+        if(myConverterData->version == 0) {
+            if(length == 1) {
+                if((UBool)args->converter->fromUnicodeStatus) {
+                    /* in DBCS mode: switch to SBCS */
+                    args->converter->fromUnicodeStatus = 0;
+                    *p++ = UCNV_SI;
+                }
+                *p++ = subchar[0];
+            } else /* length == 2*/ {
+                if(!(UBool)args->converter->fromUnicodeStatus) {
+                    /* in SBCS mode: switch to DBCS */
+                    args->converter->fromUnicodeStatus = 1;
+                    *p++ = UCNV_SO;
+                }
+                *p++ = subchar[0];
+                *p++ = subchar[1];
+            }
+            break;
+        } else {
+            /* save the subconverter's substitution string */
+            uint8_t *currentSubChars = myConverterData->currentConverter->subChars;
+            int8_t currentSubCharLen = myConverterData->currentConverter->subCharLen;
+
+            /* set our substitution string into the subconverter */
+            myConverterData->currentConverter->subChars = (uint8_t *)subchar;
+            myConverterData->currentConverter->subCharLen = (int8_t)length;
+
+            /* let the subconverter write the subchar, set/retrieve fromUChar32 state */
+            args->converter = myConverterData->currentConverter;
+            myConverterData->currentConverter->fromUChar32 = cnv->fromUChar32;
+            ucnv_cbFromUWriteSub(args, 0, err);
+            cnv->fromUChar32 = myConverterData->currentConverter->fromUChar32;
+            args->converter = cnv;
+
+            /* restore the subconverter's substitution string */
+            myConverterData->currentConverter->subChars = currentSubChars;
+            myConverterData->currentConverter->subCharLen = currentSubCharLen;
+
+            if(*err == U_BUFFER_OVERFLOW_ERROR) {
+                if(myConverterData->currentConverter->charErrorBufferLength > 0) {
+                    uprv_memcpy(
+                        cnv->charErrorBuffer,
+                        myConverterData->currentConverter->charErrorBuffer,
+                        myConverterData->currentConverter->charErrorBufferLength);
+                }
+                cnv->charErrorBufferLength = myConverterData->currentConverter->charErrorBufferLength;
+                myConverterData->currentConverter->charErrorBufferLength = 0;
+            }
+            return;
+        }
+    default:
+        /* not expected */
+        break;
+    }
+    ucnv_cbFromUWriteBytes(args,
+                           buffer, (int32_t)(p - buffer),
+                           offsetIndex, err);
+}
+
+/*
+ * Structure for cloning an ISO 2022 converter into a single memory block.
+ * ucnv_safeClone() of the converter will align the entire cloneStruct,
+ * and then ucnv_safeClone() of the sub-converter may additionally align
+ * currentConverter inside the cloneStruct, for which we need the deadSpace
+ * after currentConverter.
+ * This is because UAlignedMemory may be larger than the actually
+ * necessary alignment size for the platform.
+ * The other cloneStruct fields will not be moved around,
+ * and are aligned properly with cloneStruct's alignment.
+ */
+struct cloneStruct
+{
+    UConverter cnv;
+    UConverter currentConverter;
+    UAlignedMemory deadSpace;
+    UConverterDataISO2022 mydata;
+};
+
+
+static UConverter *
+_ISO_2022_SafeClone(
+            const UConverter *cnv,
+            void *stackBuffer,
+            int32_t *pBufferSize,
+            UErrorCode *status)
+{
+    struct cloneStruct * localClone;
+    UConverterDataISO2022 *cnvData;
+    int32_t i, size;
+
+    if (*pBufferSize == 0) { /* 'preflighting' request - set needed size into *pBufferSize */
+        *pBufferSize = (int32_t)sizeof(struct cloneStruct);
+        return NULL;
+    }
+
+    cnvData = (UConverterDataISO2022 *)cnv->extraInfo;
+    localClone = (struct cloneStruct *)stackBuffer;
+
+    /* ucnv.c/ucnv_safeClone() copied the main UConverter already */
+
+    uprv_memcpy(&localClone->mydata, cnvData, sizeof(UConverterDataISO2022));
+    localClone->cnv.extraInfo = &localClone->mydata; /* set pointer to extra data */
+    localClone->cnv.isExtraLocal = TRUE;
+
+    /* share the subconverters */
+
+    if(cnvData->currentConverter != NULL) {
+        size = (int32_t)(sizeof(UConverter) + sizeof(UAlignedMemory)); /* include size of padding */
+        localClone->mydata.currentConverter =
+            ucnv_safeClone(cnvData->currentConverter,
+                            &localClone->currentConverter,
+                            &size, status);
+        if(U_FAILURE(*status)) {
+            return NULL;
+        }
+    }
+
+    for(i=0; i<UCNV_2022_MAX_CONVERTERS; ++i) {
+        if(cnvData->myConverterArray[i] != NULL) {
+            ucnv_incrementRefCount(cnvData->myConverterArray[i]);
+        }
+    }
+
+    return &localClone->cnv;
+}
+
+static void
+_ISO_2022_GetUnicodeSet(const UConverter *cnv,
+                    const USetAdder *sa,
+                    UConverterUnicodeSet which,
+                    UErrorCode *pErrorCode)
+{
+    int32_t i;
+    UConverterDataISO2022* cnvData;
+
+    if (U_FAILURE(*pErrorCode)) {
+        return;
+    }
+#ifdef U_ENABLE_GENERIC_ISO_2022
+    if (cnv->sharedData == &_ISO2022Data) {
+        /* We use UTF-8 in this case */
+        sa->addRange(sa->set, 0, 0xd7FF);
+        sa->addRange(sa->set, 0xE000, 0x10FFFF);
+        return;
+    }
+#endif
+
+    cnvData = (UConverterDataISO2022*)cnv->extraInfo;
+
+    /* open a set and initialize it with code points that are algorithmically round-tripped */
+    switch(cnvData->locale[0]){
+    case 'j':
+        /* include JIS X 0201 which is hardcoded */
+        sa->add(sa->set, 0xa5);
+        sa->add(sa->set, 0x203e);
+        if(jpCharsetMasks[cnvData->version]&CSM(ISO8859_1)) {
+            /* include Latin-1 for some variants of JP */
+            sa->addRange(sa->set, 0, 0xff);
+        } else {
+            /* include ASCII for JP */
+            sa->addRange(sa->set, 0, 0x7f);
+        }
+        if(cnvData->version==3 || cnvData->version==4 || which==UCNV_ROUNDTRIP_AND_FALLBACK_SET) {
+            /*
+             * Do not test (jpCharsetMasks[cnvData->version]&CSM(HWKANA_7BIT))!=0
+             * because the bit is on for all JP versions although only versions 3 & 4 (JIS7 & JIS8)
+             * use half-width Katakana.
+             * This is because all ISO-2022-JP variants are lenient in that they accept (in toUnicode)
+             * half-width Katakana via the ESC ( I sequence.
+             * However, we only emit (fromUnicode) half-width Katakana according to the
+             * definition of each variant.
+             *
+             * When including fallbacks,
+             * we need to include half-width Katakana Unicode code points for all JP variants because
+             * JIS X 0208 has hardcoded fallbacks for them (which map to full-width Katakana).
+             */
+            /* include half-width Katakana for JP */
+            sa->addRange(sa->set, HWKANA_START, HWKANA_END);
+        }
+        break;
+    case 'c':
+    case 'z':
+        /* include ASCII for CN */
+        sa->addRange(sa->set, 0, 0x7f);
+        break;
+    case 'k':
+        /* there is only one converter for KR, and it is not in the myConverterArray[] */
+        cnvData->currentConverter->sharedData->impl->getUnicodeSet(
+                cnvData->currentConverter, sa, which, pErrorCode);
+        /* the loop over myConverterArray[] will simply not find another converter */
+        break;
+    default:
+        break;
+    }
+
+#if 0  /* Replaced by ucnv_MBCSGetFilteredUnicodeSetForUnicode() until we implement ucnv_getUnicodeSet() with reverse fallbacks. */
+            if( (cnvData->locale[0]=='c' || cnvData->locale[0]=='z') &&
+                cnvData->version==0 && i==CNS_11643
+            ) {
+                /* special handling for non-EXT ISO-2022-CN: add only code points for CNS planes 1 and 2 */
+                ucnv_MBCSGetUnicodeSetForBytes(
+                        cnvData->myConverterArray[i],
+                        sa, UCNV_ROUNDTRIP_SET,
+                        0, 0x81, 0x82,
+                        pErrorCode);
+            }
+#endif
+
+    for (i=0; i<UCNV_2022_MAX_CONVERTERS; i++) {
+        UConverterSetFilter filter;
+        if(cnvData->myConverterArray[i]!=NULL) {
+            if( (cnvData->locale[0]=='c' || cnvData->locale[0]=='z') &&
+                cnvData->version==0 && i==CNS_11643
+            ) {
+                /*
+                 * Version-specific for CN:
+                 * CN version 0 does not map CNS planes 3..7 although
+                 * they are all available in the CNS conversion table;
+                 * CN version 1 (-EXT) does map them all.
+                 * The two versions create different Unicode sets.
+                 */
+                filter=UCNV_SET_FILTER_2022_CN;
+            } else if(cnvData->locale[0]=='j' && i==JISX208) {
+                /*
+                 * Only add code points that map to Shift-JIS codes
+                 * corresponding to JIS X 0208.
+                 */
+                filter=UCNV_SET_FILTER_SJIS;
+            } else if(i==KSC5601) {
+                /*
+                 * Some of the KSC 5601 tables (convrtrs.txt has this aliases on multiple tables)
+                 * are broader than GR94.
+                 */
+                filter=UCNV_SET_FILTER_GR94DBCS;
+            } else {
+                filter=UCNV_SET_FILTER_NONE;
+            }
+            ucnv_MBCSGetFilteredUnicodeSetForUnicode(cnvData->myConverterArray[i], sa, which, filter, pErrorCode);
+        }
+    }
+
+    /*
+     * ISO 2022 converters must not convert SO/SI/ESC despite what
+     * sub-converters do by themselves.
+     * Remove these characters from the set.
+     */
+    sa->remove(sa->set, 0x0e);
+    sa->remove(sa->set, 0x0f);
+    sa->remove(sa->set, 0x1b);
+
+    /* ISO 2022 converters do not convert C1 controls either */
+    sa->removeRange(sa->set, 0x80, 0x9f);
+}
+
+static const UConverterImpl _ISO2022Impl={
+    UCNV_ISO_2022,
+
+    NULL,
+    NULL,
+
+    _ISO2022Open,
+    _ISO2022Close,
+    _ISO2022Reset,
+
+#ifdef U_ENABLE_GENERIC_ISO_2022
+    T_UConverter_toUnicode_ISO_2022_OFFSETS_LOGIC,
+    T_UConverter_toUnicode_ISO_2022_OFFSETS_LOGIC,
+    ucnv_fromUnicode_UTF8,
+    ucnv_fromUnicode_UTF8_OFFSETS_LOGIC,
+#else
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+#endif
+    NULL,
+
+    NULL,
+    _ISO2022getName,
+    _ISO_2022_WriteSub,
+    _ISO_2022_SafeClone,
+    _ISO_2022_GetUnicodeSet
+};
+static const UConverterStaticData _ISO2022StaticData={
+    sizeof(UConverterStaticData),
+    "ISO_2022",
+    2022,
+    UCNV_IBM,
+    UCNV_ISO_2022,
+    1,
+    3, /* max 3 bytes per UChar from UTF-8 (4 bytes from surrogate _pair_) */
+    { 0x1a, 0, 0, 0 },
+    1,
+    FALSE,
+    FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+const UConverterSharedData _ISO2022Data={
+    sizeof(UConverterSharedData),
+    ~((uint32_t) 0),
+    NULL,
+    NULL,
+    &_ISO2022StaticData,
+    FALSE,
+    &_ISO2022Impl,
+    0
+};
+
+/*************JP****************/
+static const UConverterImpl _ISO2022JPImpl={
+    UCNV_ISO_2022,
+
+    NULL,
+    NULL,
+
+    _ISO2022Open,
+    _ISO2022Close,
+    _ISO2022Reset,
+
+    UConverter_toUnicode_ISO_2022_JP_OFFSETS_LOGIC,
+    UConverter_toUnicode_ISO_2022_JP_OFFSETS_LOGIC,
+    UConverter_fromUnicode_ISO_2022_JP_OFFSETS_LOGIC,
+    UConverter_fromUnicode_ISO_2022_JP_OFFSETS_LOGIC,
+    NULL,
+
+    NULL,
+    _ISO2022getName,
+    _ISO_2022_WriteSub,
+    _ISO_2022_SafeClone,
+    _ISO_2022_GetUnicodeSet
+};
+static const UConverterStaticData _ISO2022JPStaticData={
+    sizeof(UConverterStaticData),
+    "ISO_2022_JP",
+    0,
+    UCNV_IBM,
+    UCNV_ISO_2022,
+    1,
+    6, /* max 6 bytes per UChar: 4-byte escape sequence + DBCS */
+    { 0x1a, 0, 0, 0 },
+    1,
+    FALSE,
+    FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+static const UConverterSharedData _ISO2022JPData={
+    sizeof(UConverterSharedData),
+    ~((uint32_t) 0),
+    NULL,
+    NULL,
+    &_ISO2022JPStaticData,
+    FALSE,
+    &_ISO2022JPImpl,
+    0
+};
+
+/************* KR ***************/
+static const UConverterImpl _ISO2022KRImpl={
+    UCNV_ISO_2022,
+
+    NULL,
+    NULL,
+
+    _ISO2022Open,
+    _ISO2022Close,
+    _ISO2022Reset,
+
+    UConverter_toUnicode_ISO_2022_KR_OFFSETS_LOGIC,
+    UConverter_toUnicode_ISO_2022_KR_OFFSETS_LOGIC,
+    UConverter_fromUnicode_ISO_2022_KR_OFFSETS_LOGIC,
+    UConverter_fromUnicode_ISO_2022_KR_OFFSETS_LOGIC,
+    NULL,
+
+    NULL,
+    _ISO2022getName,
+    _ISO_2022_WriteSub,
+    _ISO_2022_SafeClone,
+    _ISO_2022_GetUnicodeSet
+};
+static const UConverterStaticData _ISO2022KRStaticData={
+    sizeof(UConverterStaticData),
+    "ISO_2022_KR",
+    0,
+    UCNV_IBM,
+    UCNV_ISO_2022,
+    1,
+    3, /* max 3 bytes per UChar: SO+DBCS */
+    { 0x1a, 0, 0, 0 },
+    1,
+    FALSE,
+    FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+static const UConverterSharedData _ISO2022KRData={
+    sizeof(UConverterSharedData),
+    ~((uint32_t) 0),
+    NULL,
+    NULL,
+    &_ISO2022KRStaticData,
+    FALSE,
+    &_ISO2022KRImpl,
+    0
+};
+
+/*************** CN ***************/
+static const UConverterImpl _ISO2022CNImpl={
+
+    UCNV_ISO_2022,
+
+    NULL,
+    NULL,
+
+    _ISO2022Open,
+    _ISO2022Close,
+    _ISO2022Reset,
+
+    UConverter_toUnicode_ISO_2022_CN_OFFSETS_LOGIC,
+    UConverter_toUnicode_ISO_2022_CN_OFFSETS_LOGIC,
+    UConverter_fromUnicode_ISO_2022_CN_OFFSETS_LOGIC,
+    UConverter_fromUnicode_ISO_2022_CN_OFFSETS_LOGIC,
+    NULL,
+
+    NULL,
+    _ISO2022getName,
+    _ISO_2022_WriteSub,
+    _ISO_2022_SafeClone,
+    _ISO_2022_GetUnicodeSet
+};
+static const UConverterStaticData _ISO2022CNStaticData={
+    sizeof(UConverterStaticData),
+    "ISO_2022_CN",
+    0,
+    UCNV_IBM,
+    UCNV_ISO_2022,
+    1,
+    8, /* max 8 bytes per UChar: 4-byte CNS designator + 2 bytes for SS2/SS3 + DBCS */
+    { 0x1a, 0, 0, 0 },
+    1,
+    FALSE,
+    FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+static const UConverterSharedData _ISO2022CNData={
+    sizeof(UConverterSharedData),
+    ~((uint32_t) 0),
+    NULL,
+    NULL,
+    &_ISO2022CNStaticData,
+    FALSE,
+    &_ISO2022CNImpl,
+    0
+};
+
+
+
+#endif /* #if !UCONFIG_NO_LEGACY_CONVERSION */
diff --git a/source/common/ucnv_bld.c b/source/common/ucnv_bld.c
new file mode 100644
index 0000000..a95b7b8
--- /dev/null
+++ b/source/common/ucnv_bld.c
@@ -0,0 +1,1697 @@
+/*
+ ********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1996-2010, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************
+ *
+ *  uconv_bld.c:
+ *
+ *  Defines functions that are used in the creation/initialization/deletion
+ *  of converters and related structures.
+ *  uses uconv_io.h routines to access disk information
+ *  is used by ucnv.h to implement public API create/delete/flushCache routines
+ * Modification History:
+ *
+ *   Date        Name        Description
+ *
+ *   06/20/2000  helena      OS/400 port changes; mostly typecast.
+ *   06/29/2000  helena      Major rewrite of the callback interface.
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/putil.h"
+#include "unicode/udata.h"
+#include "unicode/ucnv.h"
+#include "unicode/uloc.h"
+#include "utracimp.h"
+#include "ucnv_io.h"
+#include "ucnv_bld.h"
+#include "ucnvmbcs.h"
+#include "ucnv_ext.h"
+#include "ucnv_cnv.h"
+#include "ucnv_imp.h"
+#include "uhash.h"
+#include "umutex.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include "ucln_cmn.h"
+#include "ustr_cnv.h"
+
+
+
+#if 0
+#include <stdio.h>
+extern void UCNV_DEBUG_LOG(char *what, char *who, void *p, int l);
+#define UCNV_DEBUG_LOG(x,y,z) UCNV_DEBUG_LOG(x,y,z,__LINE__)
+#else
+# define UCNV_DEBUG_LOG(x,y,z)
+#endif
+
+static const UConverterSharedData * const
+converterData[UCNV_NUMBER_OF_SUPPORTED_CONVERTER_TYPES]={
+    NULL, NULL,
+
+#if UCONFIG_NO_LEGACY_CONVERSION
+    NULL,
+#else
+    &_MBCSData,
+#endif
+
+    &_Latin1Data,
+    &_UTF8Data, &_UTF16BEData, &_UTF16LEData, &_UTF32BEData, &_UTF32LEData,
+    NULL,
+
+#if UCONFIG_NO_LEGACY_CONVERSION
+    NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL,
+#else
+    &_ISO2022Data,
+    &_LMBCSData1,&_LMBCSData2, &_LMBCSData3, &_LMBCSData4, &_LMBCSData5, &_LMBCSData6,
+    &_LMBCSData8,&_LMBCSData11,&_LMBCSData16,&_LMBCSData17,&_LMBCSData18,&_LMBCSData19,
+    &_HZData,
+#endif
+
+    &_SCSUData,
+
+#if UCONFIG_NO_LEGACY_CONVERSION
+    NULL,
+#else
+    &_ISCIIData,
+#endif
+
+    &_ASCIIData,
+    &_UTF7Data, &_Bocu1Data, &_UTF16Data, &_UTF32Data, &_CESU8Data, &_IMAPData
+};
+
+/* Please keep this in binary sorted order for getAlgorithmicTypeFromName.
+   Also the name should be in lower case and all spaces, dashes and underscores
+   removed
+*/
+static struct {
+  const char *name;
+  const UConverterType type;
+} const cnvNameType[] = {
+  { "bocu1", UCNV_BOCU1 },
+  { "cesu8", UCNV_CESU8 },
+#if !UCONFIG_NO_LEGACY_CONVERSION
+  { "hz",UCNV_HZ },
+#endif
+  { "imapmailboxname", UCNV_IMAP_MAILBOX },
+#if !UCONFIG_NO_LEGACY_CONVERSION
+  { "iscii", UCNV_ISCII },
+  { "iso2022", UCNV_ISO_2022 },
+#endif
+  { "iso88591", UCNV_LATIN_1 },
+#if !UCONFIG_NO_LEGACY_CONVERSION
+  { "lmbcs1", UCNV_LMBCS_1 },
+  { "lmbcs11",UCNV_LMBCS_11 },
+  { "lmbcs16",UCNV_LMBCS_16 },
+  { "lmbcs17",UCNV_LMBCS_17 },
+  { "lmbcs18",UCNV_LMBCS_18 },
+  { "lmbcs19",UCNV_LMBCS_19 },
+  { "lmbcs2", UCNV_LMBCS_2 },
+  { "lmbcs3", UCNV_LMBCS_3 },
+  { "lmbcs4", UCNV_LMBCS_4 },
+  { "lmbcs5", UCNV_LMBCS_5 },
+  { "lmbcs6", UCNV_LMBCS_6 },
+  { "lmbcs8", UCNV_LMBCS_8 },
+#endif
+  { "scsu", UCNV_SCSU },
+  { "usascii", UCNV_US_ASCII },
+  { "utf16", UCNV_UTF16 },
+  { "utf16be", UCNV_UTF16_BigEndian },
+  { "utf16le", UCNV_UTF16_LittleEndian },
+#if U_IS_BIG_ENDIAN
+  { "utf16oppositeendian", UCNV_UTF16_LittleEndian },
+  { "utf16platformendian", UCNV_UTF16_BigEndian },
+#else
+  { "utf16oppositeendian", UCNV_UTF16_BigEndian},
+  { "utf16platformendian", UCNV_UTF16_LittleEndian },
+#endif
+  { "utf32", UCNV_UTF32 },
+  { "utf32be", UCNV_UTF32_BigEndian },
+  { "utf32le", UCNV_UTF32_LittleEndian },
+#if U_IS_BIG_ENDIAN
+  { "utf32oppositeendian", UCNV_UTF32_LittleEndian },
+  { "utf32platformendian", UCNV_UTF32_BigEndian },
+#else
+  { "utf32oppositeendian", UCNV_UTF32_BigEndian },
+  { "utf32platformendian", UCNV_UTF32_LittleEndian },
+#endif
+  { "utf7", UCNV_UTF7 },
+  { "utf8", UCNV_UTF8 }
+};
+
+
+/*initializes some global variables */
+static UHashtable *SHARED_DATA_HASHTABLE = NULL;
+static UMTX        cnvCacheMutex = NULL;  /* Mutex for synchronizing cnv cache access. */
+                                          /*  Note:  the global mutex is used for      */
+                                          /*         reference count updates.          */
+
+static const char **gAvailableConverters = NULL;
+static uint16_t gAvailableConverterCount = 0;
+
+#if !U_CHARSET_IS_UTF8
+
+/* This contains the resolved converter name. So no further alias lookup is needed again. */
+static char gDefaultConverterNameBuffer[UCNV_MAX_CONVERTER_NAME_LENGTH + 1]; /* +1 for NULL */
+static const char *gDefaultConverterName = NULL;
+
+/*
+If the default converter is an algorithmic converter, this is the cached value.
+We don't cache a full UConverter and clone it because ucnv_clone doesn't have
+less overhead than an algorithmic open. We don't cache non-algorithmic converters
+because ucnv_flushCache must be able to unload the default converter and its table.
+*/
+static const UConverterSharedData *gDefaultAlgorithmicSharedData = NULL;
+
+/* Does gDefaultConverterName have a converter option and require extra parsing? */
+static UBool gDefaultConverterContainsOption;
+
+#endif  /* !U_CHARSET_IS_UTF8 */
+
+static const char DATA_TYPE[] = "cnv";
+
+static void
+ucnv_flushAvailableConverterCache() {
+    if (gAvailableConverters) {
+        umtx_lock(&cnvCacheMutex);
+        gAvailableConverterCount = 0;
+        uprv_free((char **)gAvailableConverters);
+        gAvailableConverters = NULL;
+        umtx_unlock(&cnvCacheMutex);
+    }
+}
+
+/* ucnv_cleanup - delete all storage held by the converter cache, except any  */
+/*                in use by open converters.                                  */
+/*                Not thread safe.                                            */
+/*                Not supported API.                                          */
+static UBool U_CALLCONV ucnv_cleanup(void) {
+    ucnv_flushCache();
+    if (SHARED_DATA_HASHTABLE != NULL && uhash_count(SHARED_DATA_HASHTABLE) == 0) {
+        uhash_close(SHARED_DATA_HASHTABLE);
+        SHARED_DATA_HASHTABLE = NULL;
+    }
+
+    /* Isn't called from flushCache because other threads may have preexisting references to the table. */
+    ucnv_flushAvailableConverterCache();
+
+#if !U_CHARSET_IS_UTF8
+    gDefaultConverterName = NULL;
+    gDefaultConverterNameBuffer[0] = 0;
+    gDefaultConverterContainsOption = FALSE;
+    gDefaultAlgorithmicSharedData = NULL;
+#endif
+
+    umtx_destroy(&cnvCacheMutex);    /* Don't worry about destroying the mutex even  */
+                                     /*  if the hash table still exists.  The mutex  */
+                                     /*  will lazily re-init  itself if needed.      */
+    return (SHARED_DATA_HASHTABLE == NULL);
+}
+
+static UBool U_CALLCONV
+isCnvAcceptable(void *context,
+                const char *type, const char *name,
+                const UDataInfo *pInfo) {
+    return (UBool)(
+        pInfo->size>=20 &&
+        pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
+        pInfo->charsetFamily==U_CHARSET_FAMILY &&
+        pInfo->sizeofUChar==U_SIZEOF_UCHAR &&
+        pInfo->dataFormat[0]==0x63 &&   /* dataFormat="cnvt" */
+        pInfo->dataFormat[1]==0x6e &&
+        pInfo->dataFormat[2]==0x76 &&
+        pInfo->dataFormat[3]==0x74 &&
+        pInfo->formatVersion[0]==6);  /* Everything will be version 6 */
+}
+
+/**
+ * Un flatten shared data from a UDATA..
+ */
+static UConverterSharedData*
+ucnv_data_unFlattenClone(UConverterLoadArgs *pArgs, UDataMemory *pData, UErrorCode *status)
+{
+    /* UDataInfo info; -- necessary only if some converters have different formatVersion */
+    const uint8_t *raw = (const uint8_t *)udata_getMemory(pData);
+    const UConverterStaticData *source = (const UConverterStaticData *) raw;
+    UConverterSharedData *data;
+    UConverterType type = (UConverterType)source->conversionType;
+
+    if(U_FAILURE(*status))
+        return NULL;
+
+    if( (uint16_t)type >= UCNV_NUMBER_OF_SUPPORTED_CONVERTER_TYPES ||
+        converterData[type] == NULL ||
+        converterData[type]->referenceCounter != 1 ||
+        source->structSize != sizeof(UConverterStaticData))
+    {
+        *status = U_INVALID_TABLE_FORMAT;
+        return NULL;
+    }
+
+    data = (UConverterSharedData *)uprv_malloc(sizeof(UConverterSharedData));
+    if(data == NULL) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+
+    /* copy initial values from the static structure for this type */
+    uprv_memcpy(data, converterData[type], sizeof(UConverterSharedData));
+
+#if 0 /* made UConverterMBCSTable part of UConverterSharedData -- markus 20031107 */
+    /*
+     * It would be much more efficient if the table were a direct member, not a pointer.
+     * However, that would add to the size of all UConverterSharedData objects
+     * even if they do not use this table (especially algorithmic ones).
+     * If this changes, then the static templates from converterData[type]
+     * need more entries.
+     *
+     * In principle, it would be cleaner if the load() function below
+     * allocated the table.
+     */
+    data->table = (UConverterTable *)uprv_malloc(sizeof(UConverterTable));
+    if(data->table == NULL) {
+        uprv_free(data);
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    uprv_memset(data->table, 0, sizeof(UConverterTable));
+#endif
+
+    data->staticData = source;
+
+    data->sharedDataCached = FALSE;
+
+    /* fill in fields from the loaded data */
+    data->dataMemory = (void*)pData; /* for future use */
+
+    if(data->impl->load != NULL) {
+        data->impl->load(data, pArgs, raw + source->structSize, status);
+        if(U_FAILURE(*status)) {
+            uprv_free(data->table);
+            uprv_free(data);
+            return NULL;
+        }
+    }
+    return data;
+}
+
+/*Takes an alias name gets an actual converter file name
+ *goes to disk and opens it.
+ *allocates the memory and returns a new UConverter object
+ */
+static UConverterSharedData *createConverterFromFile(UConverterLoadArgs *pArgs, UErrorCode * err)
+{
+    UDataMemory *data;
+    UConverterSharedData *sharedData;
+
+    UTRACE_ENTRY_OC(UTRACE_UCNV_LOAD);
+
+    if (U_FAILURE (*err)) {
+        UTRACE_EXIT_STATUS(*err);
+        return NULL;
+    }
+
+    UTRACE_DATA2(UTRACE_OPEN_CLOSE, "load converter %s from package %s", pArgs->name, pArgs->pkg);
+
+    data = udata_openChoice(pArgs->pkg, DATA_TYPE, pArgs->name, isCnvAcceptable, NULL, err);
+    if(U_FAILURE(*err))
+    {
+        UTRACE_EXIT_STATUS(*err);
+        return NULL;
+    }
+
+    sharedData = ucnv_data_unFlattenClone(pArgs, data, err);
+    if(U_FAILURE(*err))
+    {
+        udata_close(data);
+        UTRACE_EXIT_STATUS(*err);
+        return NULL;
+    }
+
+    /*
+     * TODO Store pkg in a field in the shared data so that delta-only converters
+     * can load base converters from the same package.
+     * If the pkg name is longer than the field, then either do not load the converter
+     * in the first place, or just set the pkg field to "".
+     */
+
+    UTRACE_EXIT_PTR_STATUS(sharedData, *err);
+    return sharedData;
+}
+
+/*returns a converter type from a string
+ */
+static const UConverterSharedData *
+getAlgorithmicTypeFromName(const char *realName)
+{
+    uint32_t mid, start, limit;
+    uint32_t lastMid;
+    int result;
+    char strippedName[UCNV_MAX_CONVERTER_NAME_LENGTH];
+
+    /* Lower case and remove ignoreable characters. */
+    ucnv_io_stripForCompare(strippedName, realName);
+
+    /* do a binary search for the alias */
+    start = 0;
+    limit = sizeof(cnvNameType)/sizeof(cnvNameType[0]);
+    mid = limit;
+    lastMid = UINT32_MAX;
+
+    for (;;) {
+        mid = (uint32_t)((start + limit) / 2);
+        if (lastMid == mid) {   /* Have we moved? */
+            break;  /* We haven't moved, and it wasn't found. */
+        }
+        lastMid = mid;
+        result = uprv_strcmp(strippedName, cnvNameType[mid].name);
+
+        if (result < 0) {
+            limit = mid;
+        } else if (result > 0) {
+            start = mid;
+        } else {
+            return converterData[cnvNameType[mid].type];
+        }
+    }
+
+    return NULL;
+}
+
+/*
+* Based on the number of known converters, this determines how many times larger
+* the shared data hash table should be. When on small platforms, or just a couple
+* of converters are used, this number should be 2. When memory is plentiful, or
+* when ucnv_countAvailable is ever used with a lot of available converters,
+* this should be 4.
+* Larger numbers reduce the number of hash collisions, but use more memory.
+*/
+#define UCNV_CACHE_LOAD_FACTOR 2
+
+/* Puts the shared data in the static hashtable SHARED_DATA_HASHTABLE */
+/*   Will always be called with the cnvCacheMutex alrady being held   */
+/*     by the calling function.                                       */
+/* Stores the shared data in the SHARED_DATA_HASHTABLE
+ * @param data The shared data
+ */
+static void
+ucnv_shareConverterData(UConverterSharedData * data)
+{
+    UErrorCode err = U_ZERO_ERROR;
+    /*Lazy evaluates the Hashtable itself */
+    /*void *sanity = NULL;*/
+
+    if (SHARED_DATA_HASHTABLE == NULL)
+    {
+        SHARED_DATA_HASHTABLE = uhash_openSize(uhash_hashChars, uhash_compareChars, NULL,
+                            ucnv_io_countKnownConverters(&err)*UCNV_CACHE_LOAD_FACTOR,
+                            &err);
+        ucln_common_registerCleanup(UCLN_COMMON_UCNV, ucnv_cleanup);
+
+        if (U_FAILURE(err))
+            return;
+    }
+
+    /* ### check to see if the element is not already there! */
+
+    /*
+    sanity =   ucnv_getSharedConverterData (data->staticData->name);
+    if(sanity != NULL)
+    {
+    UCNV_DEBUG_LOG("put:overwrite!",data->staticData->name,sanity);
+    }
+    UCNV_DEBUG_LOG("put:chk",data->staticData->name,sanity);
+    */
+
+    /* Mark it shared */
+    data->sharedDataCached = TRUE;
+
+    uhash_put(SHARED_DATA_HASHTABLE,
+            (void*) data->staticData->name, /* Okay to cast away const as long as
+            keyDeleter == NULL */
+            data,
+            &err);
+    UCNV_DEBUG_LOG("put", data->staticData->name,data);
+
+}
+
+/*  Look up a converter name in the shared data cache.                    */
+/*    cnvCacheMutex must be held by the caller to protect the hash table. */
+/* gets the shared data from the SHARED_DATA_HASHTABLE (might return NULL if it isn't there)
+ * @param name The name of the shared data
+ * @return the shared data from the SHARED_DATA_HASHTABLE
+ */
+static UConverterSharedData *
+ucnv_getSharedConverterData(const char *name)
+{
+    /*special case when no Table has yet been created we return NULL */
+    if (SHARED_DATA_HASHTABLE == NULL)
+    {
+        return NULL;
+    }
+    else
+    {
+        UConverterSharedData *rc;
+
+        rc = (UConverterSharedData*)uhash_get(SHARED_DATA_HASHTABLE, name);
+        UCNV_DEBUG_LOG("get",name,rc);
+        return rc;
+    }
+}
+
+/*frees the string of memory blocks associates with a sharedConverter
+ *if and only if the referenceCounter == 0
+ */
+/* Deletes (frees) the Shared data it's passed. first it checks the referenceCounter to
+ * see if anyone is using it, if not it frees all the memory stemming from sharedConverterData and
+ * returns TRUE,
+ * otherwise returns FALSE
+ * @param sharedConverterData The shared data
+ * @return if not it frees all the memory stemming from sharedConverterData and
+ * returns TRUE, otherwise returns FALSE
+ */
+static UBool
+ucnv_deleteSharedConverterData(UConverterSharedData * deadSharedData)
+{
+    UTRACE_ENTRY_OC(UTRACE_UCNV_UNLOAD);
+    UTRACE_DATA2(UTRACE_OPEN_CLOSE, "unload converter %s shared data %p", deadSharedData->staticData->name, deadSharedData);
+
+    if (deadSharedData->referenceCounter > 0) {
+        UTRACE_EXIT_VALUE((int32_t)FALSE);
+        return FALSE;
+    }
+
+    if (deadSharedData->impl->unload != NULL) {
+        deadSharedData->impl->unload(deadSharedData);
+    }
+
+    if(deadSharedData->dataMemory != NULL)
+    {
+        UDataMemory *data = (UDataMemory*)deadSharedData->dataMemory;
+        udata_close(data);
+    }
+
+    if(deadSharedData->table != NULL)
+    {
+        uprv_free(deadSharedData->table);
+    }
+
+#if 0
+    /* if the static data is actually owned by the shared data */
+    /* enable if we ever have this situation. */
+    if(deadSharedData->staticDataOwned == TRUE) /* see ucnv_bld.h */
+    {
+        uprv_free((void*)deadSharedData->staticData);
+    }
+#endif
+
+#if 0
+    /* Zap it ! */
+    uprv_memset(deadSharedData->0, sizeof(*deadSharedData));
+#endif
+
+    uprv_free(deadSharedData);
+
+    UTRACE_EXIT_VALUE((int32_t)TRUE);
+    return TRUE;
+}
+
+/**
+ * Load a non-algorithmic converter.
+ * If pkg==NULL, then this function must be called inside umtx_lock(&cnvCacheMutex).
+ */
+UConverterSharedData *
+ucnv_load(UConverterLoadArgs *pArgs, UErrorCode *err) {
+    UConverterSharedData *mySharedConverterData;
+
+    if(err == NULL || U_FAILURE(*err)) {
+        return NULL;
+    }
+
+    if(pArgs->pkg != NULL && *pArgs->pkg != 0) {
+        /* application-provided converters are not currently cached */
+        return createConverterFromFile(pArgs, err);
+    }
+
+    mySharedConverterData = ucnv_getSharedConverterData(pArgs->name);
+    if (mySharedConverterData == NULL)
+    {
+        /*Not cached, we need to stream it in from file */
+        mySharedConverterData = createConverterFromFile(pArgs, err);
+        if (U_FAILURE (*err) || (mySharedConverterData == NULL))
+        {
+            return NULL;
+        }
+        else if (!pArgs->onlyTestIsLoadable)
+        {
+            /* share it with other library clients */
+            ucnv_shareConverterData(mySharedConverterData);
+        }
+    }
+    else
+    {
+        /* The data for this converter was already in the cache.            */
+        /* Update the reference counter on the shared data: one more client */
+        mySharedConverterData->referenceCounter++;
+    }
+
+    return mySharedConverterData;
+}
+
+/**
+ * Unload a non-algorithmic converter.
+ * It must be sharedData->referenceCounter != ~0
+ * and this function must be called inside umtx_lock(&cnvCacheMutex).
+ */
+void
+ucnv_unload(UConverterSharedData *sharedData) {
+    if(sharedData != NULL) {
+        if (sharedData->referenceCounter > 0) {
+            sharedData->referenceCounter--;
+        }
+
+        if((sharedData->referenceCounter <= 0)&&(sharedData->sharedDataCached == FALSE)) {
+            ucnv_deleteSharedConverterData(sharedData);
+        }
+    }
+}
+
+void
+ucnv_unloadSharedDataIfReady(UConverterSharedData *sharedData)
+{
+    /*
+    Checking whether it's an algorithic converter is okay
+    in multithreaded applications because the value never changes.
+    Don't check referenceCounter for any other value.
+    */
+    if(sharedData != NULL && sharedData->referenceCounter != ~0) {
+        umtx_lock(&cnvCacheMutex);
+        ucnv_unload(sharedData);
+        umtx_unlock(&cnvCacheMutex);
+    }
+}
+
+void
+ucnv_incrementRefCount(UConverterSharedData *sharedData)
+{
+    /*
+    Checking whether it's an algorithic converter is okay
+    in multithreaded applications because the value never changes.
+    Don't check referenceCounter for any other value.
+    */
+    if(sharedData != NULL && sharedData->referenceCounter != ~0) {
+        umtx_lock(&cnvCacheMutex);
+        sharedData->referenceCounter++;
+        umtx_unlock(&cnvCacheMutex);
+    }
+}
+
+/*
+ * *pPieces must be initialized.
+ * The name without options will be copied to pPieces->cnvName.
+ * The locale and options will be copied to pPieces only if present in inName,
+ * otherwise the existing values in pPieces remain.
+ * *pArgs will be set to the pPieces values.
+ */
+static void
+parseConverterOptions(const char *inName,
+                      UConverterNamePieces *pPieces,
+                      UConverterLoadArgs *pArgs,
+                      UErrorCode *err)
+{
+    char *cnvName = pPieces->cnvName;
+    char c;
+    int32_t len = 0;
+
+    pArgs->name=inName;
+    pArgs->locale=pPieces->locale;
+    pArgs->options=pPieces->options;
+
+    /* copy the converter name itself to cnvName */
+    while((c=*inName)!=0 && c!=UCNV_OPTION_SEP_CHAR) {
+        if (++len>=UCNV_MAX_CONVERTER_NAME_LENGTH) {
+            *err = U_ILLEGAL_ARGUMENT_ERROR;    /* bad name */
+            pPieces->cnvName[0]=0;
+            return;
+        }
+        *cnvName++=c;
+        inName++;
+    }
+    *cnvName=0;
+    pArgs->name=pPieces->cnvName;
+
+    /* parse options. No more name copying should occur. */
+    while((c=*inName)!=0) {
+        if(c==UCNV_OPTION_SEP_CHAR) {
+            ++inName;
+        }
+
+        /* inName is behind an option separator */
+        if(uprv_strncmp(inName, "locale=", 7)==0) {
+            /* do not modify locale itself in case we have multiple locale options */
+            char *dest=pPieces->locale;
+
+            /* copy the locale option value */
+            inName+=7;
+            len=0;
+            while((c=*inName)!=0 && c!=UCNV_OPTION_SEP_CHAR) {
+                ++inName;
+
+                if(++len>=ULOC_FULLNAME_CAPACITY) {
+                    *err=U_ILLEGAL_ARGUMENT_ERROR;    /* bad name */
+                    pPieces->locale[0]=0;
+                    return;
+                }
+
+                *dest++=c;
+            }
+            *dest=0;
+        } else if(uprv_strncmp(inName, "version=", 8)==0) {
+            /* copy the version option value into bits 3..0 of pPieces->options */
+            inName+=8;
+            c=*inName;
+            if(c==0) {
+                pArgs->options=(pPieces->options&=~UCNV_OPTION_VERSION);
+                return;
+            } else if((uint8_t)(c-'0')<10) {
+                pArgs->options=pPieces->options=(pPieces->options&~UCNV_OPTION_VERSION)|(uint32_t)(c-'0');
+                ++inName;
+            }
+        } else if(uprv_strncmp(inName, "swaplfnl", 8)==0) {
+            inName+=8;
+            pArgs->options=(pPieces->options|=UCNV_OPTION_SWAP_LFNL);
+        /* add processing for new options here with another } else if(uprv_strncmp(inName, "option-name=", XX)==0) { */
+        } else {
+            /* ignore any other options until we define some */
+            while(((c = *inName++) != 0) && (c != UCNV_OPTION_SEP_CHAR)) {
+            }
+            if(c==0) {
+                return;
+            }
+        }
+    }
+}
+
+/*Logic determines if the converter is Algorithmic AND/OR cached
+ *depending on that:
+ * -we either go to get data from disk and cache it (Data=TRUE, Cached=False)
+ * -Get it from a Hashtable (Data=X, Cached=TRUE)
+ * -Call dataConverter initializer (Data=TRUE, Cached=TRUE)
+ * -Call AlgorithmicConverter initializer (Data=FALSE, Cached=TRUE)
+ */
+UConverterSharedData *
+ucnv_loadSharedData(const char *converterName,
+                    UConverterNamePieces *pPieces,
+                    UConverterLoadArgs *pArgs,
+                    UErrorCode * err) {
+    UConverterNamePieces stackPieces;
+    UConverterLoadArgs stackArgs;
+    UConverterSharedData *mySharedConverterData = NULL;
+    UErrorCode internalErrorCode = U_ZERO_ERROR;
+    UBool mayContainOption = TRUE;
+    UBool checkForAlgorithmic = TRUE;
+
+    if (U_FAILURE (*err)) {
+        return NULL;
+    }
+
+    if(pPieces == NULL) {
+        if(pArgs != NULL) {
+            /*
+             * Bad: We may set pArgs pointers to stackPieces fields
+             * which will be invalid after this function returns.
+             */
+            *err = U_INTERNAL_PROGRAM_ERROR;
+            return NULL;
+        }
+        pPieces = &stackPieces;
+    }
+    if(pArgs == NULL) {
+        uprv_memset(&stackArgs, 0, sizeof(stackArgs));
+        stackArgs.size = (int32_t)sizeof(stackArgs);
+        pArgs = &stackArgs;
+    }
+
+    pPieces->cnvName[0] = 0;
+    pPieces->locale[0] = 0;
+    pPieces->options = 0;
+
+    pArgs->name = converterName;
+    pArgs->locale = pPieces->locale;
+    pArgs->options = pPieces->options;
+
+    /* In case "name" is NULL we want to open the default converter. */
+    if (converterName == NULL) {
+#if U_CHARSET_IS_UTF8
+        pArgs->name = "UTF-8";
+        return (UConverterSharedData *)converterData[UCNV_UTF8];
+#else
+        /* Call ucnv_getDefaultName first to query the name from the OS. */
+        pArgs->name = ucnv_getDefaultName();
+        if (pArgs->name == NULL) {
+            *err = U_MISSING_RESOURCE_ERROR;
+            return NULL;
+        }
+        mySharedConverterData = (UConverterSharedData *)gDefaultAlgorithmicSharedData;
+        checkForAlgorithmic = FALSE;
+        mayContainOption = gDefaultConverterContainsOption;
+        /* the default converter name is already canonical */
+#endif
+    }
+    else if(UCNV_FAST_IS_UTF8(converterName)) {
+        /* fastpath for UTF-8 */
+        pArgs->name = "UTF-8";
+        return (UConverterSharedData *)converterData[UCNV_UTF8];
+    }
+    else {
+        /* separate the converter name from the options */
+        parseConverterOptions(converterName, pPieces, pArgs, err);
+        if (U_FAILURE(*err)) {
+            /* Very bad name used. */
+            return NULL;
+        }
+
+        /* get the canonical converter name */
+        pArgs->name = ucnv_io_getConverterName(pArgs->name, &mayContainOption, &internalErrorCode);
+        if (U_FAILURE(internalErrorCode) || pArgs->name == NULL) {
+            /*
+            * set the input name in case the converter was added
+            * without updating the alias table, or when there is no alias table
+            */
+            pArgs->name = pPieces->cnvName;
+        }
+    }
+
+    /* separate the converter name from the options */
+    if(mayContainOption && pArgs->name != pPieces->cnvName) {
+        parseConverterOptions(pArgs->name, pPieces, pArgs, err);
+    }
+
+    /* get the shared data for an algorithmic converter, if it is one */
+    if (checkForAlgorithmic) {
+        mySharedConverterData = (UConverterSharedData *)getAlgorithmicTypeFromName(pArgs->name);
+    }
+    if (mySharedConverterData == NULL)
+    {
+        /* it is a data-based converter, get its shared data.               */
+        /* Hold the cnvCacheMutex through the whole process of checking the */
+        /*   converter data cache, and adding new entries to the cache      */
+        /*   to prevent other threads from modifying the cache during the   */
+        /*   process.                                                       */
+        pArgs->nestedLoads=1;
+        pArgs->pkg=NULL;
+
+        umtx_lock(&cnvCacheMutex);
+        mySharedConverterData = ucnv_load(pArgs, err);
+        umtx_unlock(&cnvCacheMutex);
+        if (U_FAILURE (*err) || (mySharedConverterData == NULL))
+        {
+            return NULL;
+        }
+    }
+
+    return mySharedConverterData;
+}
+
+UConverter *
+ucnv_createConverter(UConverter *myUConverter, const char *converterName, UErrorCode * err)
+{
+    UConverterNamePieces stackPieces;
+    UConverterLoadArgs stackArgs={ (int32_t)sizeof(UConverterLoadArgs) };
+    UConverterSharedData *mySharedConverterData;
+
+    UTRACE_ENTRY_OC(UTRACE_UCNV_OPEN);
+
+    if(U_SUCCESS(*err)) {
+        UTRACE_DATA1(UTRACE_OPEN_CLOSE, "open converter %s", converterName);
+
+        mySharedConverterData = ucnv_loadSharedData(converterName, &stackPieces, &stackArgs, err);
+
+        myUConverter = ucnv_createConverterFromSharedData(
+            myUConverter, mySharedConverterData,
+            &stackArgs,
+            err);
+
+        if(U_SUCCESS(*err)) {
+            UTRACE_EXIT_PTR_STATUS(myUConverter, *err);
+            return myUConverter;
+        }
+    }
+
+    /* exit with error */
+    UTRACE_EXIT_STATUS(*err);
+    return NULL;
+}
+
+U_CFUNC UBool
+ucnv_canCreateConverter(const char *converterName, UErrorCode *err) {
+    UConverter myUConverter;
+    UConverterNamePieces stackPieces;
+    UConverterLoadArgs stackArgs={ (int32_t)sizeof(UConverterLoadArgs) };
+    UConverterSharedData *mySharedConverterData;
+
+    UTRACE_ENTRY_OC(UTRACE_UCNV_OPEN);
+
+    if(U_SUCCESS(*err)) {
+        UTRACE_DATA1(UTRACE_OPEN_CLOSE, "test if can open converter %s", converterName);
+
+        stackArgs.onlyTestIsLoadable=TRUE;
+        mySharedConverterData = ucnv_loadSharedData(converterName, &stackPieces, &stackArgs, err);
+        ucnv_createConverterFromSharedData(
+            &myUConverter, mySharedConverterData,
+            &stackArgs,
+            err);
+        ucnv_unloadSharedDataIfReady(mySharedConverterData);
+    }
+
+    UTRACE_EXIT_STATUS(*err);
+    return U_SUCCESS(*err);
+}
+
+UConverter *
+ucnv_createAlgorithmicConverter(UConverter *myUConverter,
+                                UConverterType type,
+                                const char *locale, uint32_t options,
+                                UErrorCode *err) {
+    UConverter *cnv;
+    const UConverterSharedData *sharedData;
+    UConverterLoadArgs stackArgs={ (int32_t)sizeof(UConverterLoadArgs) };
+
+    UTRACE_ENTRY_OC(UTRACE_UCNV_OPEN_ALGORITHMIC);
+    UTRACE_DATA1(UTRACE_OPEN_CLOSE, "open algorithmic converter type %d", (int32_t)type);
+
+    if(type<0 || UCNV_NUMBER_OF_SUPPORTED_CONVERTER_TYPES<=type) {
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+        UTRACE_EXIT_STATUS(U_ILLEGAL_ARGUMENT_ERROR);
+        return NULL;
+    }
+
+    sharedData = converterData[type];
+    /*
+    Checking whether it's an algorithic converter is okay
+    in multithreaded applications because the value never changes.
+    Don't check referenceCounter for any other value.
+    */
+    if(sharedData == NULL || sharedData->referenceCounter != ~0) {
+        /* not a valid type, or not an algorithmic converter */
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+        UTRACE_EXIT_STATUS(U_ILLEGAL_ARGUMENT_ERROR);
+        return NULL;
+    }
+
+    stackArgs.name = "";
+    stackArgs.options = options;
+    stackArgs.locale=locale;
+    cnv = ucnv_createConverterFromSharedData(
+            myUConverter, (UConverterSharedData *)sharedData,
+            &stackArgs, err);
+
+    UTRACE_EXIT_PTR_STATUS(cnv, *err);
+    return cnv;
+}
+
+UConverter*
+ucnv_createConverterFromPackage(const char *packageName, const char *converterName, UErrorCode * err)
+{
+    UConverter *myUConverter;
+    UConverterSharedData *mySharedConverterData;
+    UConverterNamePieces stackPieces;
+    UConverterLoadArgs stackArgs={ (int32_t)sizeof(UConverterLoadArgs) };
+
+    UTRACE_ENTRY_OC(UTRACE_UCNV_OPEN_PACKAGE);
+
+    if(U_FAILURE(*err)) {
+        UTRACE_EXIT_STATUS(*err);
+        return NULL;
+    }
+
+    UTRACE_DATA2(UTRACE_OPEN_CLOSE, "open converter %s from package %s", converterName, packageName);
+
+    /* first, get the options out of the converterName string */
+    stackPieces.cnvName[0] = 0;
+    stackPieces.locale[0] = 0;
+    stackPieces.options = 0;
+    parseConverterOptions(converterName, &stackPieces, &stackArgs, err);
+    if (U_FAILURE(*err)) {
+        /* Very bad name used. */
+        UTRACE_EXIT_STATUS(*err);
+        return NULL;
+    }
+    stackArgs.nestedLoads=1;
+    stackArgs.pkg=packageName;
+
+    /* open the data, unflatten the shared structure */
+    mySharedConverterData = createConverterFromFile(&stackArgs, err);
+
+    if (U_FAILURE(*err)) {
+        UTRACE_EXIT_STATUS(*err);
+        return NULL;
+    }
+
+    /* create the actual converter */
+    myUConverter = ucnv_createConverterFromSharedData(NULL, mySharedConverterData, &stackArgs, err);
+
+    if (U_FAILURE(*err)) {
+        ucnv_close(myUConverter);
+        UTRACE_EXIT_STATUS(*err);
+        return NULL;
+    }
+
+    UTRACE_EXIT_PTR_STATUS(myUConverter, *err);
+    return myUConverter;
+}
+
+
+UConverter*
+ucnv_createConverterFromSharedData(UConverter *myUConverter,
+                                   UConverterSharedData *mySharedConverterData,
+                                   UConverterLoadArgs *pArgs,
+                                   UErrorCode *err)
+{
+    UBool isCopyLocal;
+
+    if(U_FAILURE(*err)) {
+        ucnv_unloadSharedDataIfReady(mySharedConverterData);
+        return myUConverter;
+    }
+    if(myUConverter == NULL)
+    {
+        myUConverter = (UConverter *) uprv_malloc (sizeof (UConverter));
+        if(myUConverter == NULL)
+        {
+            *err = U_MEMORY_ALLOCATION_ERROR;
+            ucnv_unloadSharedDataIfReady(mySharedConverterData);
+            return NULL;
+        }
+        isCopyLocal = FALSE;
+    } else {
+        isCopyLocal = TRUE;
+    }
+
+    /* initialize the converter */
+    uprv_memset(myUConverter, 0, sizeof(UConverter));
+    myUConverter->isCopyLocal = isCopyLocal;
+    /*myUConverter->isExtraLocal = FALSE;*/ /* Set by the memset call */
+    myUConverter->sharedData = mySharedConverterData;
+    myUConverter->options = pArgs->options;
+    if(!pArgs->onlyTestIsLoadable) {
+        myUConverter->preFromUFirstCP = U_SENTINEL;
+        myUConverter->fromCharErrorBehaviour = UCNV_TO_U_DEFAULT_CALLBACK;
+        myUConverter->fromUCharErrorBehaviour = UCNV_FROM_U_DEFAULT_CALLBACK;
+        myUConverter->toUnicodeStatus = mySharedConverterData->toUnicodeStatus;
+        myUConverter->maxBytesPerUChar = mySharedConverterData->staticData->maxBytesPerChar;
+        myUConverter->subChar1 = mySharedConverterData->staticData->subChar1;
+        myUConverter->subCharLen = mySharedConverterData->staticData->subCharLen;
+        myUConverter->subChars = (uint8_t *)myUConverter->subUChars;
+        uprv_memcpy(myUConverter->subChars, mySharedConverterData->staticData->subChar, myUConverter->subCharLen);
+        myUConverter->toUCallbackReason = UCNV_ILLEGAL; /* default reason to invoke (*fromCharErrorBehaviour) */
+    }
+
+    if(mySharedConverterData->impl->open != NULL) {
+        mySharedConverterData->impl->open(myUConverter, pArgs, err);
+        if(U_FAILURE(*err) && !pArgs->onlyTestIsLoadable) {
+            /* don't ucnv_close() if onlyTestIsLoadable because not fully initialized */
+            ucnv_close(myUConverter);
+            return NULL;
+        }
+    }
+
+    return myUConverter;
+}
+
+/*Frees all shared immutable objects that aren't referred to (reference count = 0)
+ */
+U_CAPI int32_t U_EXPORT2
+ucnv_flushCache ()
+{
+    UConverterSharedData *mySharedData = NULL;
+    int32_t pos;
+    int32_t tableDeletedNum = 0;
+    const UHashElement *e;
+    /*UErrorCode status = U_ILLEGAL_ARGUMENT_ERROR;*/
+    int32_t i, remaining;
+
+    UTRACE_ENTRY_OC(UTRACE_UCNV_FLUSH_CACHE);
+
+    /* Close the default converter without creating a new one so that everything will be flushed. */
+    u_flushDefaultConverter();
+
+    /*if shared data hasn't even been lazy evaluated yet
+    * return 0
+    */
+    if (SHARED_DATA_HASHTABLE == NULL) {
+        UTRACE_EXIT_VALUE((int32_t)0);
+        return 0;
+    }
+
+    /*creates an enumeration to iterate through every element in the
+    * table
+    *
+    * Synchronization:  holding cnvCacheMutex will prevent any other thread from
+    *                   accessing or modifying the hash table during the iteration.
+    *                   The reference count of an entry may be decremented by
+    *                   ucnv_close while the iteration is in process, but this is
+    *                   benign.  It can't be incremented (in ucnv_createConverter())
+    *                   because the sequence of looking up in the cache + incrementing
+    *                   is protected by cnvCacheMutex.
+    */
+    umtx_lock(&cnvCacheMutex);
+    /*
+     * double loop: A delta/extension-only converter has a pointer to its base table's
+     * shared data; the first iteration of the outer loop may see the delta converter
+     * before the base converter, and unloading the delta converter may get the base
+     * converter's reference counter down to 0.
+     */
+    i = 0;
+    do {
+        remaining = 0;
+        pos = -1;
+        while ((e = uhash_nextElement (SHARED_DATA_HASHTABLE, &pos)) != NULL)
+        {
+            mySharedData = (UConverterSharedData *) e->value.pointer;
+            /*deletes only if reference counter == 0 */
+            if (mySharedData->referenceCounter == 0)
+            {
+                tableDeletedNum++;
+
+                UCNV_DEBUG_LOG("del",mySharedData->staticData->name,mySharedData);
+
+                uhash_removeElement(SHARED_DATA_HASHTABLE, e);
+                mySharedData->sharedDataCached = FALSE;
+                ucnv_deleteSharedConverterData (mySharedData);
+            } else {
+                ++remaining;
+            }
+        }
+    } while(++i == 1 && remaining > 0);
+    umtx_unlock(&cnvCacheMutex);
+
+    UTRACE_DATA1(UTRACE_INFO, "ucnv_flushCache() exits with %d converters remaining", remaining);
+
+    UTRACE_EXIT_VALUE(tableDeletedNum);
+    return tableDeletedNum;
+}
+
+/* available converters list --------------------------------------------------- */
+
+static UBool haveAvailableConverterList(UErrorCode *pErrorCode) {
+    int needInit;
+    UMTX_CHECK(&cnvCacheMutex, (gAvailableConverters == NULL), needInit);
+    if (needInit) {
+        UConverter tempConverter;
+        UEnumeration *allConvEnum = NULL;
+        uint16_t idx;
+        uint16_t localConverterCount;
+        uint16_t allConverterCount;
+        UErrorCode localStatus;
+        const char *converterName;
+        const char **localConverterList;
+
+        allConvEnum = ucnv_openAllNames(pErrorCode);
+        allConverterCount = uenum_count(allConvEnum, pErrorCode);
+        if (U_FAILURE(*pErrorCode)) {
+            return FALSE;
+        }
+
+        /* We can't have more than "*converterTable" converters to open */
+        localConverterList = (const char **) uprv_malloc(allConverterCount * sizeof(char*));
+        if (!localConverterList) {
+            *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+            return FALSE;
+        }
+
+        /* Open the default converter to make sure that it has first dibs in the hash table. */
+        localStatus = U_ZERO_ERROR;
+        ucnv_close(ucnv_createConverter(&tempConverter, NULL, &localStatus));
+
+        localConverterCount = 0;
+
+        for (idx = 0; idx < allConverterCount; idx++) {
+            localStatus = U_ZERO_ERROR;
+            converterName = uenum_next(allConvEnum, NULL, &localStatus);
+            if (ucnv_canCreateConverter(converterName, &localStatus)) {
+                localConverterList[localConverterCount++] = converterName;
+            }
+        }
+        uenum_close(allConvEnum);
+
+        umtx_lock(&cnvCacheMutex);
+        if (gAvailableConverters == NULL) {
+            gAvailableConverterCount = localConverterCount;
+            gAvailableConverters = localConverterList;
+            ucln_common_registerCleanup(UCLN_COMMON_UCNV, ucnv_cleanup);
+        }
+        else {
+            uprv_free((char **)localConverterList);
+        }
+        umtx_unlock(&cnvCacheMutex);
+    }
+    return TRUE;
+}
+
+U_CFUNC uint16_t
+ucnv_bld_countAvailableConverters(UErrorCode *pErrorCode) {
+    if (haveAvailableConverterList(pErrorCode)) {
+        return gAvailableConverterCount;
+    }
+    return 0;
+}
+
+U_CFUNC const char *
+ucnv_bld_getAvailableConverter(uint16_t n, UErrorCode *pErrorCode) {
+    if (haveAvailableConverterList(pErrorCode)) {
+        if (n < gAvailableConverterCount) {
+            return gAvailableConverters[n];
+        }
+        *pErrorCode = U_INDEX_OUTOFBOUNDS_ERROR;
+    }
+    return NULL;
+}
+
+/* default converter name --------------------------------------------------- */
+
+#if !U_CHARSET_IS_UTF8
+/*
+Copy the canonical converter name.
+ucnv_getDefaultName must be thread safe, which can call this function.
+
+ucnv_setDefaultName calls this function and it doesn't have to be
+thread safe because there is no reliable/safe way to reset the
+converter in use in all threads. If you did reset the converter, you
+would not be sure that retrieving a default converter for one string
+would be the same type of default converter for a successive string.
+Since the name is a returned via ucnv_getDefaultName without copying,
+you shouldn't be modifying or deleting the string from a separate thread.
+*/
+static U_INLINE void
+internalSetName(const char *name, UErrorCode *status) {
+    UConverterNamePieces stackPieces;
+    UConverterLoadArgs stackArgs={ (int32_t)sizeof(UConverterLoadArgs) };
+    int32_t length=(int32_t)(uprv_strlen(name));
+    UBool containsOption = (UBool)(uprv_strchr(name, UCNV_OPTION_SEP_CHAR) != NULL);
+    const UConverterSharedData *algorithmicSharedData;
+
+    stackArgs.name = name;
+    if(containsOption) {
+        stackPieces.cnvName[0] = 0;
+        stackPieces.locale[0] = 0;
+        stackPieces.options = 0;
+        parseConverterOptions(name, &stackPieces, &stackArgs, status);
+        if(U_FAILURE(*status)) {
+            return;
+        }
+    }
+    algorithmicSharedData = getAlgorithmicTypeFromName(stackArgs.name);
+
+    umtx_lock(&cnvCacheMutex);
+
+    gDefaultAlgorithmicSharedData = algorithmicSharedData;
+    gDefaultConverterContainsOption = containsOption;
+    uprv_memcpy(gDefaultConverterNameBuffer, name, length);
+    gDefaultConverterNameBuffer[length]=0;
+
+    /* gDefaultConverterName MUST be the last global var set by this function.  */
+    /*    It is the variable checked in ucnv_getDefaultName() to see if initialization is required. */
+    gDefaultConverterName = gDefaultConverterNameBuffer;
+
+    ucln_common_registerCleanup(UCLN_COMMON_UCNV, ucnv_cleanup);
+
+    umtx_unlock(&cnvCacheMutex);
+}
+#endif
+
+/*
+ * In order to be really thread-safe, the get function would have to take
+ * a buffer parameter and copy the current string inside a mutex block.
+ * This implementation only tries to be really thread-safe while
+ * setting the name.
+ * It assumes that setting a pointer is atomic.
+ */
+
+U_CAPI const char*  U_EXPORT2
+ucnv_getDefaultName() {
+#if U_CHARSET_IS_UTF8
+    return "UTF-8";
+#else
+    /* local variable to be thread-safe */
+    const char *name;
+
+    /*
+    Multiple calls to ucnv_getDefaultName must be thread safe,
+    but ucnv_setDefaultName is not thread safe.
+    */
+    UMTX_CHECK(&cnvCacheMutex, gDefaultConverterName, name);
+    if(name==NULL) {
+        UErrorCode errorCode = U_ZERO_ERROR;
+        UConverter *cnv = NULL;
+
+        name = uprv_getDefaultCodepage();
+
+        /* if the name is there, test it out and get the canonical name with options */
+        if(name != NULL) {
+            cnv = ucnv_open(name, &errorCode);
+            if(U_SUCCESS(errorCode) && cnv != NULL) {
+                name = ucnv_getName(cnv, &errorCode);
+            }
+        }
+
+        if(name == NULL || name[0] == 0
+            || U_FAILURE(errorCode) || cnv == NULL
+            || uprv_strlen(name)>=sizeof(gDefaultConverterNameBuffer))
+        {
+            /* Panic time, let's use a fallback. */
+#if (U_CHARSET_FAMILY == U_ASCII_FAMILY)
+            name = "US-ASCII";
+            /* there is no 'algorithmic' converter for EBCDIC */
+#elif defined(OS390)
+            name = "ibm-1047_P100-1995" UCNV_SWAP_LFNL_OPTION_STRING;
+#else
+            name = "ibm-37_P100-1995";
+#endif
+        }
+
+        internalSetName(name, &errorCode);
+
+        /* The close may make the current name go away. */
+        ucnv_close(cnv);
+    }
+
+    return name;
+#endif
+}
+
+/*
+This function is not thread safe, and it can't be thread safe.
+See internalSetName or the API reference for details.
+*/
+U_CAPI void U_EXPORT2
+ucnv_setDefaultName(const char *converterName) {
+#if !U_CHARSET_IS_UTF8
+    if(converterName==NULL) {
+        /* reset to the default codepage */
+        gDefaultConverterName=NULL;
+    } else {
+        UErrorCode errorCode = U_ZERO_ERROR;
+        UConverter *cnv = NULL;
+        const char *name = NULL;
+
+        /* if the name is there, test it out and get the canonical name with options */
+        cnv = ucnv_open(converterName, &errorCode);
+        if(U_SUCCESS(errorCode) && cnv != NULL) {
+            name = ucnv_getName(cnv, &errorCode);
+        }
+
+        if(U_SUCCESS(errorCode) && name!=NULL) {
+            internalSetName(name, &errorCode);
+        }
+        /* else this converter is bad to use. Don't change it to a bad value. */
+
+        /* The close may make the current name go away. */
+        ucnv_close(cnv);
+  
+        /* reset the converter cache */
+        u_flushDefaultConverter();
+    }
+#endif
+}
+
+/* data swapping ------------------------------------------------------------ */
+
+/* most of this might belong more properly into ucnvmbcs.c, but that is so large */
+
+#if !UCONFIG_NO_LEGACY_CONVERSION
+
+U_CAPI int32_t U_EXPORT2
+ucnv_swap(const UDataSwapper *ds,
+          const void *inData, int32_t length, void *outData,
+          UErrorCode *pErrorCode) {
+    const UDataInfo *pInfo;
+    int32_t headerSize;
+
+    const uint8_t *inBytes;
+    uint8_t *outBytes;
+
+    uint32_t offset, count, staticDataSize;
+    int32_t size;
+
+    const UConverterStaticData *inStaticData;
+    UConverterStaticData *outStaticData;
+
+    const _MBCSHeader *inMBCSHeader;
+    _MBCSHeader *outMBCSHeader;
+    _MBCSHeader mbcsHeader;
+    uint32_t mbcsHeaderLength;
+    UBool noFromU=FALSE;
+
+    uint8_t outputType;
+
+    int32_t maxFastUChar, mbcsIndexLength;
+
+    const int32_t *inExtIndexes;
+    int32_t extOffset;
+
+    /* udata_swapDataHeader checks the arguments */
+    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    /* check data format and format version */
+    pInfo=(const UDataInfo *)((const char *)inData+4);
+    if(!(
+        pInfo->dataFormat[0]==0x63 &&   /* dataFormat="cnvt" */
+        pInfo->dataFormat[1]==0x6e &&
+        pInfo->dataFormat[2]==0x76 &&
+        pInfo->dataFormat[3]==0x74 &&
+        pInfo->formatVersion[0]==6 &&
+        pInfo->formatVersion[1]>=2
+    )) {
+        udata_printError(ds, "ucnv_swap(): data format %02x.%02x.%02x.%02x (format version %02x.%02x) is not recognized as an ICU .cnv conversion table\n",
+                         pInfo->dataFormat[0], pInfo->dataFormat[1],
+                         pInfo->dataFormat[2], pInfo->dataFormat[3],
+                         pInfo->formatVersion[0], pInfo->formatVersion[1]);
+        *pErrorCode=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    inBytes=(const uint8_t *)inData+headerSize;
+    outBytes=(uint8_t *)outData+headerSize;
+
+    /* read the initial UConverterStaticData structure after the UDataInfo header */
+    inStaticData=(const UConverterStaticData *)inBytes;
+    outStaticData=(UConverterStaticData *)outBytes;
+
+    if(length<0) {
+        staticDataSize=ds->readUInt32(inStaticData->structSize);
+    } else {
+        length-=headerSize;
+        if( length<sizeof(UConverterStaticData) ||
+            (uint32_t)length<(staticDataSize=ds->readUInt32(inStaticData->structSize))
+        ) {
+            udata_printError(ds, "ucnv_swap(): too few bytes (%d after header) for an ICU .cnv conversion table\n",
+                             length);
+            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+            return 0;
+        }
+    }
+
+    if(length>=0) {
+        /* swap the static data */
+        if(inStaticData!=outStaticData) {
+            uprv_memcpy(outStaticData, inStaticData, staticDataSize);
+        }
+
+        ds->swapArray32(ds, &inStaticData->structSize, 4,
+                           &outStaticData->structSize, pErrorCode);
+        ds->swapArray32(ds, &inStaticData->codepage, 4,
+                           &outStaticData->codepage, pErrorCode);
+
+        ds->swapInvChars(ds, inStaticData->name, (int32_t)uprv_strlen(inStaticData->name),
+                            outStaticData->name, pErrorCode);
+        if(U_FAILURE(*pErrorCode)) {
+            udata_printError(ds, "ucnv_swap(): error swapping converter name\n");
+            return 0;
+        }
+    }
+
+    inBytes+=staticDataSize;
+    outBytes+=staticDataSize;
+    if(length>=0) {
+        length-=(int32_t)staticDataSize;
+    }
+
+    /* check for supported conversionType values */
+    if(inStaticData->conversionType==UCNV_MBCS) {
+        /* swap MBCS data */
+        inMBCSHeader=(const _MBCSHeader *)inBytes;
+        outMBCSHeader=(_MBCSHeader *)outBytes;
+
+        if(0<=length && length<sizeof(_MBCSHeader)) {
+            udata_printError(ds, "ucnv_swap(): too few bytes (%d after headers) for an ICU MBCS .cnv conversion table\n",
+                                length);
+            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+            return 0;
+        }
+        if(inMBCSHeader->version[0]==4 && inMBCSHeader->version[1]>=1) {
+            mbcsHeaderLength=MBCS_HEADER_V4_LENGTH;
+        } else if(inMBCSHeader->version[0]==5 && inMBCSHeader->version[1]>=3 &&
+                  ((mbcsHeader.options=ds->readUInt32(inMBCSHeader->options))&
+                   MBCS_OPT_UNKNOWN_INCOMPATIBLE_MASK)==0
+        ) {
+            mbcsHeaderLength=mbcsHeader.options&MBCS_OPT_LENGTH_MASK;
+            noFromU=(UBool)((mbcsHeader.options&MBCS_OPT_NO_FROM_U)!=0);
+        } else {
+            udata_printError(ds, "ucnv_swap(): unsupported _MBCSHeader.version %d.%d\n",
+                             inMBCSHeader->version[0], inMBCSHeader->version[1]);
+            *pErrorCode=U_UNSUPPORTED_ERROR;
+            return 0;
+        }
+
+        uprv_memcpy(mbcsHeader.version, inMBCSHeader->version, 4);
+        mbcsHeader.countStates=         ds->readUInt32(inMBCSHeader->countStates);
+        mbcsHeader.countToUFallbacks=   ds->readUInt32(inMBCSHeader->countToUFallbacks);
+        mbcsHeader.offsetToUCodeUnits=  ds->readUInt32(inMBCSHeader->offsetToUCodeUnits);
+        mbcsHeader.offsetFromUTable=    ds->readUInt32(inMBCSHeader->offsetFromUTable);
+        mbcsHeader.offsetFromUBytes=    ds->readUInt32(inMBCSHeader->offsetFromUBytes);
+        mbcsHeader.flags=               ds->readUInt32(inMBCSHeader->flags);
+        mbcsHeader.fromUBytesLength=    ds->readUInt32(inMBCSHeader->fromUBytesLength);
+        /* mbcsHeader.options have been read above */
+
+        extOffset=(int32_t)(mbcsHeader.flags>>8);
+        outputType=(uint8_t)mbcsHeader.flags;
+        if(noFromU && outputType==MBCS_OUTPUT_1) {
+            udata_printError(ds, "ucnv_swap(): unsupported combination of makeconv --small with SBCS\n");
+            *pErrorCode=U_UNSUPPORTED_ERROR;
+            return 0;
+        }
+
+        /* make sure that the output type is known */
+        switch(outputType) {
+        case MBCS_OUTPUT_1:
+        case MBCS_OUTPUT_2:
+        case MBCS_OUTPUT_3:
+        case MBCS_OUTPUT_4:
+        case MBCS_OUTPUT_3_EUC:
+        case MBCS_OUTPUT_4_EUC:
+        case MBCS_OUTPUT_2_SISO:
+        case MBCS_OUTPUT_EXT_ONLY:
+            /* OK */
+            break;
+        default:
+            udata_printError(ds, "ucnv_swap(): unsupported MBCS output type 0x%x\n",
+                             outputType);
+            *pErrorCode=U_UNSUPPORTED_ERROR;
+            return 0;
+        }
+
+        /* calculate the length of the MBCS data */
+
+        /*
+         * utf8Friendly MBCS files (mbcsHeader.version 4.3)
+         * contain an additional mbcsIndex table:
+         *   uint16_t[(maxFastUChar+1)>>6];
+         * where maxFastUChar=((mbcsHeader.version[2]<<8)|0xff).
+         */
+        maxFastUChar=0;
+        mbcsIndexLength=0;
+        if( outputType!=MBCS_OUTPUT_EXT_ONLY && outputType!=MBCS_OUTPUT_1 &&
+            mbcsHeader.version[1]>=3 && (maxFastUChar=mbcsHeader.version[2])!=0
+        ) {
+            maxFastUChar=(maxFastUChar<<8)|0xff;
+            mbcsIndexLength=((maxFastUChar+1)>>6)*2;  /* number of bytes */
+        }
+
+        if(extOffset==0) {
+            size=(int32_t)(mbcsHeader.offsetFromUBytes+mbcsIndexLength);
+            if(!noFromU) {
+                size+=(int32_t)mbcsHeader.fromUBytesLength;
+            }
+
+            /* avoid compiler warnings - not otherwise necessary, and the value does not matter */
+            inExtIndexes=NULL;
+        } else {
+            /* there is extension data after the base data, see ucnv_ext.h */
+            if(length>=0 && length<(extOffset+UCNV_EXT_INDEXES_MIN_LENGTH*4)) {
+                udata_printError(ds, "ucnv_swap(): too few bytes (%d after headers) for an ICU MBCS .cnv conversion table with extension data\n",
+                                 length);
+                *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+                return 0;
+            }
+
+            inExtIndexes=(const int32_t *)(inBytes+extOffset);
+            size=extOffset+udata_readInt32(ds, inExtIndexes[UCNV_EXT_SIZE]);
+        }
+
+        if(length>=0) {
+            if(length<size) {
+                udata_printError(ds, "ucnv_swap(): too few bytes (%d after headers) for an ICU MBCS .cnv conversion table\n",
+                                 length);
+                *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+                return 0;
+            }
+
+            /* copy the data for inaccessible bytes */
+            if(inBytes!=outBytes) {
+                uprv_memcpy(outBytes, inBytes, size);
+            }
+
+            /* swap the MBCSHeader, except for the version field */
+            count=mbcsHeaderLength*4;
+            ds->swapArray32(ds, &inMBCSHeader->countStates, count-4,
+                               &outMBCSHeader->countStates, pErrorCode);
+
+            if(outputType==MBCS_OUTPUT_EXT_ONLY) {
+                /*
+                 * extension-only file,
+                 * contains a base name instead of normal base table data
+                 */
+
+                /* swap the base name, between the header and the extension data */
+                const char *inBaseName=(const char *)inBytes+count;
+                char *outBaseName=(char *)outBytes+count;
+                ds->swapInvChars(ds, inBaseName, (int32_t)uprv_strlen(inBaseName),
+                                    outBaseName, pErrorCode);
+            } else {
+                /* normal file with base table data */
+
+                /* swap the state table, 1kB per state */
+                offset=count;
+                count=mbcsHeader.countStates*1024;
+                ds->swapArray32(ds, inBytes+offset, (int32_t)count,
+                                   outBytes+offset, pErrorCode);
+
+                /* swap the toUFallbacks[] */
+                offset+=count;
+                count=mbcsHeader.countToUFallbacks*8;
+                ds->swapArray32(ds, inBytes+offset, (int32_t)count,
+                                   outBytes+offset, pErrorCode);
+
+                /* swap the unicodeCodeUnits[] */
+                offset=mbcsHeader.offsetToUCodeUnits;
+                count=mbcsHeader.offsetFromUTable-offset;
+                ds->swapArray16(ds, inBytes+offset, (int32_t)count,
+                                   outBytes+offset, pErrorCode);
+
+                /* offset to the stage 1 table, independent of the outputType */
+                offset=mbcsHeader.offsetFromUTable;
+
+                if(outputType==MBCS_OUTPUT_1) {
+                    /* SBCS: swap the fromU tables, all 16 bits wide */
+                    count=(mbcsHeader.offsetFromUBytes-offset)+mbcsHeader.fromUBytesLength;
+                    ds->swapArray16(ds, inBytes+offset, (int32_t)count,
+                                       outBytes+offset, pErrorCode);
+                } else {
+                    /* otherwise: swap the stage tables separately */
+
+                    /* stage 1 table: uint16_t[0x440 or 0x40] */
+                    if(inStaticData->unicodeMask&UCNV_HAS_SUPPLEMENTARY) {
+                        count=0x440*2; /* for all of Unicode */
+                    } else {
+                        count=0x40*2; /* only BMP */
+                    }
+                    ds->swapArray16(ds, inBytes+offset, (int32_t)count,
+                                       outBytes+offset, pErrorCode);
+
+                    /* stage 2 table: uint32_t[] */
+                    offset+=count;
+                    count=mbcsHeader.offsetFromUBytes-offset;
+                    ds->swapArray32(ds, inBytes+offset, (int32_t)count,
+                                       outBytes+offset, pErrorCode);
+
+                    /* stage 3/result bytes: sometimes uint16_t[] or uint32_t[] */
+                    offset=mbcsHeader.offsetFromUBytes;
+                    count= noFromU ? 0 : mbcsHeader.fromUBytesLength;
+                    switch(outputType) {
+                    case MBCS_OUTPUT_2:
+                    case MBCS_OUTPUT_3_EUC:
+                    case MBCS_OUTPUT_2_SISO:
+                        ds->swapArray16(ds, inBytes+offset, (int32_t)count,
+                                           outBytes+offset, pErrorCode);
+                        break;
+                    case MBCS_OUTPUT_4:
+                        ds->swapArray32(ds, inBytes+offset, (int32_t)count,
+                                           outBytes+offset, pErrorCode);
+                        break;
+                    default:
+                        /* just uint8_t[], nothing to swap */
+                        break;
+                    }
+
+                    if(mbcsIndexLength!=0) {
+                        offset+=count;
+                        count=mbcsIndexLength;
+                        ds->swapArray16(ds, inBytes+offset, (int32_t)count,
+                                           outBytes+offset, pErrorCode);
+                    }
+                }
+            }
+
+            if(extOffset!=0) {
+                /* swap the extension data */
+                inBytes+=extOffset;
+                outBytes+=extOffset;
+
+                /* swap toUTable[] */
+                offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_TO_U_INDEX]);
+                length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_TO_U_LENGTH]);
+                ds->swapArray32(ds, inBytes+offset, length*4, outBytes+offset, pErrorCode);
+
+                /* swap toUUChars[] */
+                offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_TO_U_UCHARS_INDEX]);
+                length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_TO_U_UCHARS_LENGTH]);
+                ds->swapArray16(ds, inBytes+offset, length*2, outBytes+offset, pErrorCode);
+
+                /* swap fromUTableUChars[] */
+                offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_UCHARS_INDEX]);
+                length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_LENGTH]);
+                ds->swapArray16(ds, inBytes+offset, length*2, outBytes+offset, pErrorCode);
+
+                /* swap fromUTableValues[] */
+                offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_VALUES_INDEX]);
+                /* same length as for fromUTableUChars[] */
+                ds->swapArray32(ds, inBytes+offset, length*4, outBytes+offset, pErrorCode);
+
+                /* no need to swap fromUBytes[] */
+
+                /* swap fromUStage12[] */
+                offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_12_INDEX]);
+                length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_12_LENGTH]);
+                ds->swapArray16(ds, inBytes+offset, length*2, outBytes+offset, pErrorCode);
+
+                /* swap fromUStage3[] */
+                offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_3_INDEX]);
+                length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_3_LENGTH]);
+                ds->swapArray16(ds, inBytes+offset, length*2, outBytes+offset, pErrorCode);
+
+                /* swap fromUStage3b[] */
+                offset=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_3B_INDEX]);
+                length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_FROM_U_STAGE_3B_LENGTH]);
+                ds->swapArray32(ds, inBytes+offset, length*4, outBytes+offset, pErrorCode);
+
+                /* swap indexes[] */
+                length=udata_readInt32(ds, inExtIndexes[UCNV_EXT_INDEXES_LENGTH]);
+                ds->swapArray32(ds, inBytes, length*4, outBytes, pErrorCode);
+            }
+        }
+    } else {
+        udata_printError(ds, "ucnv_swap(): unknown conversionType=%d!=UCNV_MBCS\n",
+                         inStaticData->conversionType);
+        *pErrorCode=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    return headerSize+(int32_t)staticDataSize+size;
+}
+
+#endif /* #if !UCONFIG_NO_LEGACY_CONVERSION */
+
+#endif
diff --git a/source/common/ucnv_bld.h b/source/common/ucnv_bld.h
new file mode 100644
index 0000000..227c495
--- /dev/null
+++ b/source/common/ucnv_bld.h
@@ -0,0 +1,285 @@
+/*
+**********************************************************************
+*   Copyright (C) 1999-2009 International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*
+*
+*  ucnv_bld.h:
+*  Contains internal data structure definitions
+* Created by Bertrand A. Damiba
+*
+*   Change history:
+*
+*   06/29/2000  helena      Major rewrite of the callback APIs.
+*/
+
+#ifndef UCNV_BLD_H
+#define UCNV_BLD_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ucnv.h"
+#include "unicode/ucnv_err.h"
+#include "ucnv_cnv.h"
+#include "ucnvmbcs.h"
+#include "ucnv_ext.h"
+#include "udataswp.h"
+
+/* size of the overflow buffers in UConverter, enough for escaping callbacks */
+#define UCNV_ERROR_BUFFER_LENGTH 32
+
+/* at most 4 bytes per substitution character (part of .cnv file format! see UConverterStaticData) */
+#define UCNV_MAX_SUBCHAR_LEN 4
+
+/* at most 8 bytes per character in toUBytes[] (UTF-8 uses up to 6) */
+#define UCNV_MAX_CHAR_LEN 8
+
+/* converter options bits */
+#define UCNV_OPTION_VERSION     0xf
+#define UCNV_OPTION_SWAP_LFNL   0x10
+
+#define UCNV_GET_VERSION(cnv) ((cnv)->options&UCNV_OPTION_VERSION)
+
+U_CDECL_BEGIN /* We must declare the following as 'extern "C"' so that if ucnv
+                 itself is compiled under C++, the linkage of the funcptrs will
+                 work.
+              */
+
+union UConverterTable {
+    UConverterMBCSTable mbcs;
+};
+
+typedef union UConverterTable UConverterTable;
+
+struct UConverterImpl;
+typedef struct UConverterImpl UConverterImpl;
+
+/** values for the unicodeMask */
+#define UCNV_HAS_SUPPLEMENTARY 1
+#define UCNV_HAS_SURROGATES    2
+
+typedef struct UConverterStaticData {   /* +offset: size */
+    uint32_t structSize;                /* +0: 4 Size of this structure */
+    
+    char name 
+      [UCNV_MAX_CONVERTER_NAME_LENGTH]; /* +4: 60  internal name of the converter- invariant chars */
+
+    int32_t codepage;               /* +64: 4 codepage # (now IBM-$codepage) */
+
+    int8_t platform;                /* +68: 1 platform of the converter (only IBM now) */
+    int8_t conversionType;          /* +69: 1 conversion type */
+
+    int8_t minBytesPerChar;         /* +70: 1 Minimum # bytes per char in this codepage */
+    int8_t maxBytesPerChar;         /* +71: 1 Maximum # bytes output per UChar in this codepage */
+
+    uint8_t subChar[UCNV_MAX_SUBCHAR_LEN]; /* +72: 4  [note:  4 and 8 byte boundary] */
+    int8_t subCharLen;              /* +76: 1 */
+    
+    uint8_t hasToUnicodeFallback;   /* +77: 1 UBool needs to be changed to UBool to be consistent across platform */
+    uint8_t hasFromUnicodeFallback; /* +78: 1 */
+    uint8_t unicodeMask;            /* +79: 1  bit 0: has supplementary  bit 1: has single surrogates */
+    uint8_t subChar1;               /* +80: 1  single-byte substitution character for IBM MBCS (0 if none) */
+    uint8_t reserved[19];           /* +81: 19 to round out the structure */
+                                    /* total size: 100 */
+} UConverterStaticData;
+
+/*
+ * Defines the UConverterSharedData struct,
+ * the immutable, shared part of UConverter.
+ */
+struct UConverterSharedData {
+    uint32_t structSize;            /* Size of this structure */
+    uint32_t referenceCounter;      /* used to count number of clients, 0xffffffff for static SharedData */
+
+    const void *dataMemory;         /* from udata_openChoice() - for cleanup */
+    void *table;                    /* Unused. This used to be a UConverterTable - Pointer to conversion data - see mbcs below */
+
+    const UConverterStaticData *staticData; /* pointer to the static (non changing) data. */
+
+    UBool                sharedDataCached;   /* TRUE:  shared data is in cache, don't destroy on ucnv_close() if 0 ref.  FALSE: shared data isn't in the cache, do attempt to clean it up if the ref is 0 */
+  /*UBool               staticDataOwned;   TRUE if static data owned by shared data & should be freed with it, NEVER true for udata() loaded statics. This ignored variable was removed to make space for sharedDataCached.   */
+
+    const UConverterImpl *impl;     /* vtable-style struct of mostly function pointers */
+
+    /*initial values of some members of the mutable part of object */
+    uint32_t toUnicodeStatus;
+
+    /*
+     * Shared data structures currently come in two flavors:
+     * - readonly for built-in algorithmic converters
+     * - allocated for MBCS, with a pointer to an allocated UConverterTable
+     *   which always has a UConverterMBCSTable
+     *
+     * To eliminate one allocation, I am making the UConverterMBCSTable
+     * a member of the shared data. It is the last member so that static
+     * definitions of UConverterSharedData work as before.
+     * The table field above also remains to avoid updating all static
+     * definitions, but is now unused.
+     *
+     * markus 2003-nov-07
+     */
+    UConverterMBCSTable mbcs;
+};
+
+/* Defines a UConverter, the lightweight mutable part the user sees */
+
+struct UConverter {
+    /*
+     * Error function pointer called when conversion issues
+     * occur during a ucnv_fromUnicode call
+     */
+    void (U_EXPORT2 *fromUCharErrorBehaviour) (const void *context,
+                                     UConverterFromUnicodeArgs *args,
+                                     const UChar *codeUnits,
+                                     int32_t length,
+                                     UChar32 codePoint,
+                                     UConverterCallbackReason reason,
+                                     UErrorCode *);
+    /*
+     * Error function pointer called when conversion issues
+     * occur during a ucnv_toUnicode call
+     */
+    void (U_EXPORT2 *fromCharErrorBehaviour) (const void *context,
+                                    UConverterToUnicodeArgs *args,
+                                    const char *codeUnits,
+                                    int32_t length,
+                                    UConverterCallbackReason reason,
+                                    UErrorCode *);
+
+    /*
+     * Pointer to additional data that depends on the converter type.
+     * Used by ISO 2022, SCSU, GB 18030 converters, possibly more.
+     */
+    void *extraInfo;
+
+    const void *fromUContext;
+    const void *toUContext;
+
+    /*
+     * Pointer to charset bytes for substitution string if subCharLen>0,
+     * or pointer to Unicode string (UChar *) if subCharLen<0.
+     * subCharLen==0 is equivalent to using a skip callback.
+     * If the pointer is !=subUChars then it is allocated with
+     * UCNV_ERROR_BUFFER_LENGTH * U_SIZEOF_UCHAR bytes.
+     * The subUChars field is declared as UChar[] not uint8_t[] to
+     * guarantee alignment for UChars.
+     */
+    uint8_t *subChars;
+
+    UConverterSharedData *sharedData;   /* Pointer to the shared immutable part of the converter object */
+
+    uint32_t options; /* options flags from UConverterOpen, may contain additional bits */
+
+    UBool sharedDataIsCached;  /* TRUE:  shared data is in cache, don't destroy on ucnv_close() if 0 ref.  FALSE: shared data isn't in the cache, do attempt to clean it up if the ref is 0 */
+    UBool isCopyLocal;  /* TRUE if UConverter is not owned and not released in ucnv_close() (stack-allocated, safeClone(), etc.) */
+    UBool isExtraLocal; /* TRUE if extraInfo is not owned and not released in ucnv_close() (stack-allocated, safeClone(), etc.) */
+
+    UBool  useFallback;
+    int8_t toULength;                   /* number of bytes in toUBytes */
+    uint8_t toUBytes[UCNV_MAX_CHAR_LEN-1];/* more "toU status"; keeps the bytes of the current character */
+    uint32_t toUnicodeStatus;           /* Used to internalize stream status information */
+    int32_t mode;
+    uint32_t fromUnicodeStatus;
+
+    /*
+     * More fromUnicode() status. Serves 3 purposes:
+     * - keeps a lead surrogate between buffers (similar to toUBytes[])
+     * - keeps a lead surrogate at the end of the stream,
+     *   which the framework handles as truncated input
+     * - if the fromUnicode() implementation returns to the framework
+     *   (ucnv.c ucnv_fromUnicode()), then the framework calls the callback
+     *   for this code point
+     */
+    UChar32 fromUChar32;
+
+    /*
+     * value for ucnv_getMaxCharSize()
+     *
+     * usually simply copied from the static data, but ucnvmbcs.c modifies
+     * the value depending on the converter type and options
+     */
+    int8_t maxBytesPerUChar;
+
+    int8_t subCharLen;                  /* length of the codepage specific character sequence */
+    int8_t invalidCharLength;
+    int8_t charErrorBufferLength;       /* number of valid bytes in charErrorBuffer */
+
+    int8_t invalidUCharLength;
+    int8_t UCharErrorBufferLength;      /* number of valid UChars in charErrorBuffer */
+
+    uint8_t subChar1;                                   /* single-byte substitution character if different from subChar */
+    UBool useSubChar1;
+    char invalidCharBuffer[UCNV_MAX_CHAR_LEN];          /* bytes from last error/callback situation */
+    uint8_t charErrorBuffer[UCNV_ERROR_BUFFER_LENGTH];  /* codepage output from Error functions */
+    UChar subUChars[UCNV_MAX_SUBCHAR_LEN/U_SIZEOF_UCHAR]; /* see subChars documentation */
+
+    UChar invalidUCharBuffer[U16_MAX_LENGTH];           /* UChars from last error/callback situation */
+    UChar UCharErrorBuffer[UCNV_ERROR_BUFFER_LENGTH];   /* unicode output from Error functions */
+
+    /* fields for conversion extension */
+
+    /* store previous UChars/chars to continue partial matches */
+    UChar32 preFromUFirstCP;                /* >=0: partial match */
+    UChar preFromU[UCNV_EXT_MAX_UCHARS];
+    char preToU[UCNV_EXT_MAX_BYTES];
+    int8_t preFromULength, preToULength;    /* negative: replay */
+    int8_t preToUFirstLength;               /* length of first character */
+
+    /* new fields for ICU 4.0 */
+    UConverterCallbackReason toUCallbackReason; /* (*fromCharErrorBehaviour) reason, set when error is detected */
+};
+
+U_CDECL_END /* end of UConverter */
+
+#define CONVERTER_FILE_EXTENSION ".cnv"
+
+
+/**
+ * Return the number of all converter names.
+ * @param pErrorCode The error code
+ * @return the number of all converter names
+ */
+U_CFUNC uint16_t
+ucnv_bld_countAvailableConverters(UErrorCode *pErrorCode);
+
+/**
+ * Return the (n)th converter name in mixed case, or NULL
+ * if there is none (typically, if the data cannot be loaded).
+ * 0<=index<ucnv_io_countAvailableConverters().
+ * @param n The number specifies which converter name to get
+ * @param pErrorCode The error code
+ * @return the (n)th converter name in mixed case, or NULL if there is none.
+ */
+U_CFUNC const char *
+ucnv_bld_getAvailableConverter(uint16_t n, UErrorCode *pErrorCode);
+
+/**
+ * Load a non-algorithmic converter.
+ * If pkg==NULL, then this function must be called inside umtx_lock(&cnvCacheMutex).
+ */
+UConverterSharedData *
+ucnv_load(UConverterLoadArgs *pArgs, UErrorCode *err);
+
+/**
+ * Unload a non-algorithmic converter.
+ * It must be sharedData->referenceCounter != ~0
+ * and this function must be called inside umtx_lock(&cnvCacheMutex).
+ */
+void
+ucnv_unload(UConverterSharedData *sharedData);
+
+/**
+ * Swap ICU .cnv conversion tables. See udataswp.h.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+ucnv_swap(const UDataSwapper *ds,
+          const void *inData, int32_t length, void *outData,
+          UErrorCode *pErrorCode);
+
+#endif
+
+#endif /* _UCNV_BLD */
diff --git a/source/common/ucnv_cb.c b/source/common/ucnv_cb.c
new file mode 100644
index 0000000..fa34b65
--- /dev/null
+++ b/source/common/ucnv_cb.c
@@ -0,0 +1,259 @@
+/*
+**********************************************************************
+*   Copyright (C) 2000-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+ *  ucnv_cb.c:
+ *  External APIs for the ICU's codeset conversion library
+ *  Helena Shih
+ *
+ * Modification History:
+ *
+ *   Date        Name        Description
+ *   7/28/2000   srl         Implementation
+ */
+
+/**
+ * @name Character Conversion C API
+ *
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ucnv_cb.h"
+#include "ucnv_bld.h"
+#include "ucnv_cnv.h"
+#include "cmemory.h"
+
+/* need to update the offsets when the target moves. */
+/* Note: Recursion may occur in the cb functions, be sure to update the offsets correctly
+if you don't use ucnv_cbXXX functions.  Make sure you don't use the same callback within
+the same call stack if the complexity arises. */
+U_CAPI void  U_EXPORT2
+ucnv_cbFromUWriteBytes (UConverterFromUnicodeArgs *args,
+                       const char* source,
+                       int32_t length,
+                       int32_t offsetIndex,
+                       UErrorCode * err)
+{
+    if(U_FAILURE(*err)) {
+        return;
+    }
+
+    ucnv_fromUWriteBytes(
+        args->converter,
+        source, length,
+        &args->target, args->targetLimit,
+        &args->offsets, offsetIndex,
+        err);
+}
+
+U_CAPI void  U_EXPORT2
+ucnv_cbFromUWriteUChars(UConverterFromUnicodeArgs *args,
+                             const UChar** source,
+                             const UChar*  sourceLimit,
+                             int32_t offsetIndex,
+                             UErrorCode * err)
+{
+    /*
+    This is a fun one.  Recursion can occur - we're basically going to
+    just retry shoving data through the same converter. Note, if you got
+    here through some kind of invalid sequence, you maybe should emit a
+    reset sequence of some kind and/or call ucnv_reset().  Since this
+    IS an actual conversion, take care that you've changed the callback
+    or the data, or you'll get an infinite loop.
+
+    Please set the err value to something reasonable before calling
+    into this.
+    */
+
+    char *oldTarget;
+
+    if(U_FAILURE(*err))
+    {
+        return;
+    }
+
+    oldTarget = args->target;
+
+    ucnv_fromUnicode(args->converter,
+        &args->target,
+        args->targetLimit,
+        source,
+        sourceLimit,
+        NULL, /* no offsets */
+        FALSE, /* no flush */
+        err);
+
+    if(args->offsets)
+    {
+        while (args->target != oldTarget)  /* if it moved at all.. */
+        {
+            *(args->offsets)++ = offsetIndex;
+            oldTarget++;
+        }
+    }
+
+    /*
+    Note, if you did something like used a Stop subcallback, things would get interesting.
+    In fact, here's where we want to return the partially consumed in-source!
+    */
+    if(*err == U_BUFFER_OVERFLOW_ERROR)
+    /* && (*source < sourceLimit && args->target >= args->targetLimit)
+    -- S. Hrcek */
+    {
+        /* Overflowed the target.  Now, we'll write into the charErrorBuffer.
+        It's a fixed size. If we overflow it... Hmm */
+        char *newTarget;
+        const char *newTargetLimit;
+        UErrorCode err2 = U_ZERO_ERROR;
+
+        int8_t errBuffLen;
+
+        errBuffLen  = args->converter->charErrorBufferLength;
+
+        /* start the new target at the first free slot in the errbuff.. */
+        newTarget = (char *)(args->converter->charErrorBuffer + errBuffLen);
+
+        newTargetLimit = (char *)(args->converter->charErrorBuffer +
+            sizeof(args->converter->charErrorBuffer));
+
+        if(newTarget >= newTargetLimit)
+        {
+            *err = U_INTERNAL_PROGRAM_ERROR;
+            return;
+        }
+
+        /* We're going to tell the converter that the errbuff len is empty.
+        This prevents the existing errbuff from being 'flushed' out onto
+        itself.  If the errbuff is needed by the converter this time,
+        we're hosed - we're out of space! */
+
+        args->converter->charErrorBufferLength = 0;
+
+        ucnv_fromUnicode(args->converter,
+                         &newTarget,
+                         newTargetLimit,
+                         source,
+                         sourceLimit,
+                         NULL,
+                         FALSE,
+                         &err2);
+
+        /* We can go ahead and overwrite the  length here. We know just how
+        to recalculate it. */
+
+        args->converter->charErrorBufferLength = (int8_t)(
+            newTarget - (char*)args->converter->charErrorBuffer);
+
+        if((newTarget >= newTargetLimit) || (err2 == U_BUFFER_OVERFLOW_ERROR))
+        {
+            /* now we're REALLY in trouble.
+            Internal program error - callback shouldn't have written this much
+            data!
+            */
+            *err = U_INTERNAL_PROGRAM_ERROR;
+            return;
+        }
+        /*else {*/
+            /* sub errs could be invalid/truncated/illegal chars or w/e.
+            These might want to be passed on up.. But the problem is, we already
+            need to pass U_BUFFER_OVERFLOW_ERROR. That has to override these
+            other errs.. */
+
+            /*
+            if(U_FAILURE(err2))
+            ??
+            */
+        /*}*/
+    }
+}
+
+U_CAPI void  U_EXPORT2
+ucnv_cbFromUWriteSub (UConverterFromUnicodeArgs *args,
+                           int32_t offsetIndex,
+                           UErrorCode * err)
+{
+    UConverter *converter;
+    int32_t length;
+
+    if(U_FAILURE(*err)) {
+        return;
+    }
+    converter = args->converter;
+    length = converter->subCharLen;
+
+    if(length == 0) {
+        return;
+    }
+
+    if(length < 0) {
+        /*
+         * Write/convert the substitution string. Its real length is -length.
+         * Unlike the escape callback, we need not change the converter's
+         * callback function because ucnv_setSubstString() verified that
+         * the string can be converted, so we will not get a conversion error
+         * and will not recurse.
+         * At worst we should get a U_BUFFER_OVERFLOW_ERROR.
+         */
+        const UChar *source = (const UChar *)converter->subChars;
+        ucnv_cbFromUWriteUChars(args, &source, source - length, offsetIndex, err);
+        return;
+    }
+
+    if(converter->sharedData->impl->writeSub!=NULL) {
+        converter->sharedData->impl->writeSub(args, offsetIndex, err);
+    }
+    else if(converter->subChar1!=0 && (uint16_t)converter->invalidUCharBuffer[0]<=(uint16_t)0xffu) {
+        /*
+        TODO: Is this untestable because the MBCS converter has a writeSub function to call
+        and the other converters don't use subChar1?
+        */
+        ucnv_cbFromUWriteBytes(args,
+                               (const char *)&converter->subChar1, 1,
+                               offsetIndex, err);
+    }
+    else {
+        ucnv_cbFromUWriteBytes(args,
+                               (const char *)converter->subChars, length,
+                               offsetIndex, err);
+    }
+}
+
+U_CAPI void  U_EXPORT2
+ucnv_cbToUWriteUChars (UConverterToUnicodeArgs *args,
+                            const UChar* source,
+                            int32_t length,
+                            int32_t offsetIndex,
+                            UErrorCode * err)
+{
+    if(U_FAILURE(*err)) {
+        return;
+    }
+
+    ucnv_toUWriteUChars(
+        args->converter,
+        source, length,
+        &args->target, args->targetLimit,
+        &args->offsets, offsetIndex,
+        err);
+}
+
+U_CAPI void  U_EXPORT2
+ucnv_cbToUWriteSub (UConverterToUnicodeArgs *args,
+                         int32_t offsetIndex,
+                       UErrorCode * err)
+{
+    static const UChar kSubstituteChar1 = 0x1A, kSubstituteChar = 0xFFFD;
+
+    /* could optimize this case, just one uchar */
+    if(args->converter->invalidCharLength == 1 && args->converter->subChar1 != 0) {
+        ucnv_cbToUWriteUChars(args, &kSubstituteChar1, 1, offsetIndex, err);
+    } else {
+        ucnv_cbToUWriteUChars(args, &kSubstituteChar, 1, offsetIndex, err);
+    }
+}
+
+#endif
diff --git a/source/common/ucnv_cnv.c b/source/common/ucnv_cnv.c
new file mode 100644
index 0000000..f8e2f83
--- /dev/null
+++ b/source/common/ucnv_cnv.c
@@ -0,0 +1,174 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2004, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+*   uconv_cnv.c:
+*   Implements all the low level conversion functions
+*   T_UnicodeConverter_{to,from}Unicode_$ConversionType
+*
+*   Change history:
+*
+*   06/29/2000  helena      Major rewrite of the callback APIs.
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ucnv_err.h"
+#include "unicode/ucnv.h"
+#include "unicode/uset.h"
+#include "ucnv_cnv.h"
+#include "ucnv_bld.h"
+#include "cmemory.h"
+
+U_CFUNC void
+ucnv_getCompleteUnicodeSet(const UConverter *cnv,
+                   const USetAdder *sa,
+                   UConverterUnicodeSet which,
+                   UErrorCode *pErrorCode) {
+    sa->addRange(sa->set, 0, 0x10ffff);
+}
+
+U_CFUNC void
+ucnv_getNonSurrogateUnicodeSet(const UConverter *cnv,
+                               const USetAdder *sa,
+                               UConverterUnicodeSet which,
+                               UErrorCode *pErrorCode) {
+    sa->addRange(sa->set, 0, 0xd7ff);
+    sa->addRange(sa->set, 0xe000, 0x10ffff);
+}
+
+U_CFUNC void
+ucnv_fromUWriteBytes(UConverter *cnv,
+                     const char *bytes, int32_t length,
+                     char **target, const char *targetLimit,
+                     int32_t **offsets,
+                     int32_t sourceIndex,
+                     UErrorCode *pErrorCode) {
+    char *t=*target;
+    int32_t *o;
+
+    /* write bytes */
+    if(offsets==NULL || (o=*offsets)==NULL) {
+        while(length>0 && t<targetLimit) {
+            *t++=*bytes++;
+            --length;
+        }
+    } else {
+        /* output with offsets */
+        while(length>0 && t<targetLimit) {
+            *t++=*bytes++;
+            *o++=sourceIndex;
+            --length;
+        }
+        *offsets=o;
+    }
+    *target=t;
+
+    /* write overflow */
+    if(length>0) {
+        if(cnv!=NULL) {
+            t=(char *)cnv->charErrorBuffer;
+            cnv->charErrorBufferLength=(int8_t)length;
+            do {
+                *t++=(uint8_t)*bytes++;
+            } while(--length>0);
+        }
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+}
+
+U_CFUNC void
+ucnv_toUWriteUChars(UConverter *cnv,
+                    const UChar *uchars, int32_t length,
+                    UChar **target, const UChar *targetLimit,
+                    int32_t **offsets,
+                    int32_t sourceIndex,
+                    UErrorCode *pErrorCode) {
+    UChar *t=*target;
+    int32_t *o;
+
+    /* write UChars */
+    if(offsets==NULL || (o=*offsets)==NULL) {
+        while(length>0 && t<targetLimit) {
+            *t++=*uchars++;
+            --length;
+        }
+    } else {
+        /* output with offsets */
+        while(length>0 && t<targetLimit) {
+            *t++=*uchars++;
+            *o++=sourceIndex;
+            --length;
+        }
+        *offsets=o;
+    }
+    *target=t;
+
+    /* write overflow */
+    if(length>0) {
+        if(cnv!=NULL) {
+            t=cnv->UCharErrorBuffer;
+            cnv->UCharErrorBufferLength=(int8_t)length;
+            do {
+                *t++=*uchars++;
+            } while(--length>0);
+        }
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+}
+
+U_CFUNC void
+ucnv_toUWriteCodePoint(UConverter *cnv,
+                       UChar32 c,
+                       UChar **target, const UChar *targetLimit,
+                       int32_t **offsets,
+                       int32_t sourceIndex,
+                       UErrorCode *pErrorCode) {
+    UChar *t;
+    int32_t *o;
+
+    t=*target;
+
+    if(t<targetLimit) {
+        if(c<=0xffff) {
+            *t++=(UChar)c;
+            c=U_SENTINEL;
+        } else /* c is a supplementary code point */ {
+            *t++=U16_LEAD(c);
+            c=U16_TRAIL(c);
+            if(t<targetLimit) {
+                *t++=(UChar)c;
+                c=U_SENTINEL;
+            }
+        }
+
+        /* write offsets */
+        if(offsets!=NULL && (o=*offsets)!=NULL) {
+            *o++=sourceIndex;
+            if((*target+1)<t) {
+                *o++=sourceIndex;
+            }
+            *offsets=o;
+        }
+    }
+
+    *target=t;
+
+    /* write overflow from c */
+    if(c>=0) {
+        if(cnv!=NULL) {
+            int8_t i=0;
+            U16_APPEND_UNSAFE(cnv->UCharErrorBuffer, i, c);
+            cnv->UCharErrorBufferLength=i;
+        }
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+}
+
+#endif
diff --git a/source/common/ucnv_cnv.h b/source/common/ucnv_cnv.h
new file mode 100644
index 0000000..cba24d0
--- /dev/null
+++ b/source/common/ucnv_cnv.h
@@ -0,0 +1,318 @@
+/*
+**********************************************************************
+*   Copyright (C) 1999-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*
+*   ucnv_cnv.h:
+*   Definitions for converter implementations.
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   05/09/00    helena      Added implementation to handle fallback mappings.
+*   06/29/2000  helena      Major rewrite of the callback APIs.
+*/
+
+#ifndef UCNV_CNV_H
+#define UCNV_CNV_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ucnv.h"
+#include "unicode/ucnv_err.h"
+#include "unicode/uset.h"
+#include "uset_imp.h"
+
+U_CDECL_BEGIN
+
+/* this is used in fromUnicode DBCS tables as an "unassigned" marker */
+#define missingCharMarker 0xFFFF
+
+/*
+ * #define missingUCharMarker 0xfffe
+ *
+ * commented out because there are actually two values used in toUnicode tables:
+ * U+fffe "unassigned"
+ * U+ffff "illegal"
+ */
+
+/** Forward declaration, see ucnv_bld.h */
+struct UConverterSharedData;
+typedef struct UConverterSharedData UConverterSharedData;
+
+/* function types for UConverterImpl ---------------------------------------- */
+
+/* struct with arguments for UConverterLoad and ucnv_load() */
+typedef struct {
+    int32_t size;               /* sizeof(UConverterLoadArgs) */
+    int32_t nestedLoads;        /* count nested ucnv_load() calls */
+    UBool onlyTestIsLoadable;   /* input: don't actually load */
+    UBool reserved0;            /* reserved - for good alignment of the pointers */
+    int16_t reserved;           /* reserved - for good alignment of the pointers */
+    uint32_t options;
+    const char *pkg, *name, *locale;
+} UConverterLoadArgs;
+
+typedef void (*UConverterLoad) (UConverterSharedData *sharedData,
+                                UConverterLoadArgs *pArgs,
+                                const uint8_t *raw, UErrorCode *pErrorCode);
+typedef void (*UConverterUnload) (UConverterSharedData *sharedData);
+
+typedef void (*UConverterOpen) (UConverter *cnv, UConverterLoadArgs *pArgs, UErrorCode *pErrorCode);
+typedef void (*UConverterClose) (UConverter *cnv);
+
+typedef enum UConverterResetChoice {
+    UCNV_RESET_BOTH,
+    UCNV_RESET_TO_UNICODE,
+    UCNV_RESET_FROM_UNICODE
+} UConverterResetChoice;
+
+typedef void (*UConverterReset) (UConverter *cnv, UConverterResetChoice choice);
+
+/*
+ * Converter implementation function(s) for ucnv_toUnicode().
+ * If the toUnicodeWithOffsets function pointer is NULL,
+ * then the toUnicode function will be used and the offsets will be set to -1.
+ *
+ * Must maintain state across buffers. Use toUBytes[toULength] for partial input
+ * sequences; it will be checked in ucnv.c at the end of the input stream
+ * to detect truncated input.
+ * Some converters may need additional detection and may then set U_TRUNCATED_CHAR_FOUND.
+ *
+ * The toUnicodeWithOffsets must write exactly as many offset values as target
+ * units. Write offset values of -1 for when the source index corresponding to
+ * the output unit is not known (e.g., the character started in an earlier buffer).
+ * The pArgs->offsets pointer need not be moved forward.
+ *
+ * At function return, either one of the following conditions must be true:
+ * - U_BUFFER_OVERFLOW_ERROR and the target is full: target==targetLimit
+ * - another error code with toUBytes[toULength] set to the offending input
+ * - no error, and the source is consumed: source==sourceLimit
+ *
+ * The ucnv.c code will handle the end of the input (reset)
+ * (reset, and truncation detection) and callbacks.
+ */
+typedef void (*UConverterToUnicode) (UConverterToUnicodeArgs *, UErrorCode *);
+
+/*
+ * Same rules as for UConverterToUnicode.
+ * A lead surrogate is kept in fromUChar32 across buffers, and if an error
+ * occurs, then the offending input code point must be put into fromUChar32
+ * as well.
+ */
+typedef void (*UConverterFromUnicode) (UConverterFromUnicodeArgs *, UErrorCode *);
+
+/*
+ * Converter implementation function for ucnv_convertEx(), for direct conversion
+ * between two charsets without pivoting through UTF-16.
+ * The rules are the same as for UConverterToUnicode and UConverterFromUnicode.
+ * In addition,
+ * - The toUnicode side must behave and keep state exactly like the
+ *   UConverterToUnicode implementation for the same source charset.
+ * - A U_USING_DEFAULT_WARNING can be set to request to temporarily fall back
+ *   to pivoting. When this function is called, the conversion framework makes
+ *   sure that this warning is not set on input.
+ * - Continuing a partial match and flushing the toUnicode replay buffer
+ *   are handled by pivoting, using the toUnicode and fromUnicode functions.
+ */
+typedef void (*UConverterConvert) (UConverterFromUnicodeArgs *pFromUArgs,
+                                   UConverterToUnicodeArgs *pToUArgs,
+                                   UErrorCode *pErrorCode);
+
+/*
+ * Converter implementation function for ucnv_getNextUChar().
+ * If the function pointer is NULL, then the toUnicode function will be used.
+ *
+ * Will be called at a character boundary (toULength==0).
+ * May return with
+ * - U_INDEX_OUTOFBOUNDS_ERROR if there was no output for the input
+ *   (the return value will be ignored)
+ * - U_TRUNCATED_CHAR_FOUND or another error code (never U_BUFFER_OVERFLOW_ERROR!)
+ *   with toUBytes[toULength] set to the offending input
+ *   (the return value will be ignored)
+ * - return UCNV_GET_NEXT_UCHAR_USE_TO_U, without moving the source pointer,
+ *   to indicate that the ucnv.c code shall call the toUnicode function instead
+ * - return a real code point result
+ *
+ * Unless UCNV_GET_NEXT_UCHAR_USE_TO_U is returned, the source bytes must be consumed.
+ *
+ * The ucnv.c code will handle the end of the input (reset)
+ * (except for truncation detection!) and callbacks.
+ */
+typedef UChar32 (*UConverterGetNextUChar) (UConverterToUnicodeArgs *, UErrorCode *);
+
+typedef void (*UConverterGetStarters)(const UConverter* converter,
+                                      UBool starters[256],
+                                      UErrorCode *pErrorCode);
+
+/* If this function pointer is null or if the function returns null
+ * the name field in static data struct should be returned by 
+ * ucnv_getName() API function
+ */
+typedef const char * (*UConverterGetName) (const UConverter *cnv);
+
+/**
+ * Write the codepage substitution character.
+ * If this function is not set, then ucnv_cbFromUWriteSub() writes
+ * the substitution character from UConverter.
+ * For stateful converters, it is typically necessary to handle this
+ * specificially for the converter in order to properly maintain the state.
+ */
+typedef void (*UConverterWriteSub) (UConverterFromUnicodeArgs *pArgs, int32_t offsetIndex, UErrorCode *pErrorCode);
+
+/**
+ * For converter-specific safeClone processing
+ * If this function is not set, then ucnv_safeClone assumes that the converter has no private data that changes
+ * after the converter is done opening.
+ * If this function is set, then it is called just after a memcpy() of
+ * converter data to the new, empty converter, and is expected to set up
+ * the initial state of the converter.  It is not expected to increment the
+ * reference counts of the standard data types such as the shared data.
+ */
+typedef UConverter * (*UConverterSafeClone) (const UConverter   *cnv, 
+                                             void               *stackBuffer,
+                                             int32_t            *pBufferSize, 
+                                             UErrorCode         *status);
+
+/**
+ * Filters for some ucnv_getUnicodeSet() implementation code.
+ */
+typedef enum UConverterSetFilter {
+    UCNV_SET_FILTER_NONE,
+    UCNV_SET_FILTER_DBCS_ONLY,
+    UCNV_SET_FILTER_2022_CN,
+    UCNV_SET_FILTER_SJIS,
+    UCNV_SET_FILTER_GR94DBCS,
+    UCNV_SET_FILTER_HZ,
+    UCNV_SET_FILTER_COUNT
+} UConverterSetFilter;
+
+/**
+ * Fills the set of Unicode code points that can be converted by an ICU converter.
+ * The API function ucnv_getUnicodeSet() clears the USet before calling
+ * the converter's getUnicodeSet() implementation; the converter should only
+ * add the appropriate code points to allow recursive use.
+ * For example, the ISO-2022-JP converter will call each subconverter's
+ * getUnicodeSet() implementation to consecutively add code points to
+ * the same USet, which will result in a union of the sets of all subconverters.
+ *
+ * For more documentation, see ucnv_getUnicodeSet() in ucnv.h.
+ */
+typedef void (*UConverterGetUnicodeSet) (const UConverter *cnv,
+                                         const USetAdder *sa,
+                                         UConverterUnicodeSet which,
+                                         UErrorCode *pErrorCode);
+
+UBool CONVERSION_U_SUCCESS (UErrorCode err);
+
+/**
+ * UConverterImpl contains all the data and functions for a converter type.
+ * Its function pointers work much like a C++ vtable.
+ * Many converter types need to define only a subset of the functions;
+ * when a function pointer is NULL, then a default action will be performed.
+ *
+ * Every converter type must implement toUnicode, fromUnicode, and getNextUChar,
+ * otherwise the converter may crash.
+ * Every converter type that has variable-length codepage sequences should
+ * also implement toUnicodeWithOffsets and fromUnicodeWithOffsets for
+ * correct offset handling.
+ * All other functions may or may not be implemented - it depends only on
+ * whether the converter type needs them.
+ *
+ * When open() fails, then close() will be called, if present.
+ */
+struct UConverterImpl {
+    UConverterType type;
+
+    UConverterLoad load;
+    UConverterUnload unload;
+
+    UConverterOpen open;
+    UConverterClose close;
+    UConverterReset reset;
+
+    UConverterToUnicode toUnicode;
+    UConverterToUnicode toUnicodeWithOffsets;
+    UConverterFromUnicode fromUnicode;
+    UConverterFromUnicode fromUnicodeWithOffsets;
+    UConverterGetNextUChar getNextUChar;
+
+    UConverterGetStarters getStarters;
+    UConverterGetName getName;
+    UConverterWriteSub writeSub;
+    UConverterSafeClone safeClone;
+    UConverterGetUnicodeSet getUnicodeSet;
+
+    UConverterConvert toUTF8;
+    UConverterConvert fromUTF8;
+};
+
+extern const UConverterSharedData
+    _MBCSData, _Latin1Data,
+    _UTF8Data, _UTF16BEData, _UTF16LEData, _UTF32BEData, _UTF32LEData,
+    _ISO2022Data, 
+    _LMBCSData1,_LMBCSData2, _LMBCSData3, _LMBCSData4, _LMBCSData5, _LMBCSData6,
+    _LMBCSData8,_LMBCSData11,_LMBCSData16,_LMBCSData17,_LMBCSData18,_LMBCSData19,
+    _HZData,_ISCIIData, _SCSUData, _ASCIIData,
+    _UTF7Data, _Bocu1Data, _UTF16Data, _UTF32Data, _CESU8Data, _IMAPData;
+
+U_CDECL_END
+
+/** Always use fallbacks from codepage to Unicode */
+#define TO_U_USE_FALLBACK(useFallback) TRUE
+#define UCNV_TO_U_USE_FALLBACK(cnv) TRUE
+
+/** Use fallbacks from Unicode to codepage when cnv->useFallback or for private-use code points */
+#define IS_PRIVATE_USE(c) ((uint32_t)((c)-0xe000)<0x1900 || (uint32_t)((c)-0xf0000)<0x20000)
+#define FROM_U_USE_FALLBACK(useFallback, c) ((useFallback) || IS_PRIVATE_USE(c))
+#define UCNV_FROM_U_USE_FALLBACK(cnv, c) FROM_U_USE_FALLBACK((cnv)->useFallback, c)
+
+/**
+ * Magic number for ucnv_getNextUChar(), returned by a
+ * getNextUChar() implementation to indicate to use the converter's toUnicode()
+ * instead of the native function.
+ * @internal
+ */
+#define UCNV_GET_NEXT_UCHAR_USE_TO_U -9
+
+U_CFUNC void
+ucnv_getCompleteUnicodeSet(const UConverter *cnv,
+                   const USetAdder *sa,
+                   UConverterUnicodeSet which,
+                   UErrorCode *pErrorCode);
+
+U_CFUNC void
+ucnv_getNonSurrogateUnicodeSet(const UConverter *cnv,
+                               const USetAdder *sa,
+                               UConverterUnicodeSet which,
+                               UErrorCode *pErrorCode);
+
+U_CFUNC void
+ucnv_fromUWriteBytes(UConverter *cnv,
+                     const char *bytes, int32_t length,
+                     char **target, const char *targetLimit,
+                     int32_t **offsets,
+                     int32_t sourceIndex,
+                     UErrorCode *pErrorCode);
+U_CFUNC void
+ucnv_toUWriteUChars(UConverter *cnv,
+                    const UChar *uchars, int32_t length,
+                    UChar **target, const UChar *targetLimit,
+                    int32_t **offsets,
+                    int32_t sourceIndex,
+                    UErrorCode *pErrorCode);
+
+U_CFUNC void
+ucnv_toUWriteCodePoint(UConverter *cnv,
+                       UChar32 c,
+                       UChar **target, const UChar *targetLimit,
+                       int32_t **offsets,
+                       int32_t sourceIndex,
+                       UErrorCode *pErrorCode);
+
+#endif
+
+#endif /* UCNV_CNV */
diff --git a/source/common/ucnv_err.c b/source/common/ucnv_err.c
new file mode 100644
index 0000000..75659fb
--- /dev/null
+++ b/source/common/ucnv_err.c
@@ -0,0 +1,406 @@
+/*
+ *****************************************************************************
+ *
+ *   Copyright (C) 1998-2007, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ *
+ *****************************************************************************
+ *
+ *  ucnv_err.c
+ *  Implements error behaviour functions called by T_UConverter_{from,to}Unicode
+ *
+ *
+*   Change history:
+*
+*   06/29/2000  helena      Major rewrite of the callback APIs.
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ucnv_err.h"
+#include "unicode/ucnv_cb.h"
+#include "ucnv_cnv.h"
+#include "cmemory.h"
+#include "unicode/ucnv.h"
+#include "ustrfmt.h"
+
+#define VALUE_STRING_LENGTH 32
+/*Magic # 32 = 4(number of char in value string) * 8(max number of bytes per char for any converter) */
+#define UNICODE_PERCENT_SIGN_CODEPOINT  0x0025
+#define UNICODE_U_CODEPOINT             0x0055
+#define UNICODE_X_CODEPOINT             0x0058
+#define UNICODE_RS_CODEPOINT            0x005C
+#define UNICODE_U_LOW_CODEPOINT         0x0075
+#define UNICODE_X_LOW_CODEPOINT         0x0078
+#define UNICODE_AMP_CODEPOINT           0x0026
+#define UNICODE_HASH_CODEPOINT          0x0023
+#define UNICODE_SEMICOLON_CODEPOINT     0x003B
+#define UNICODE_PLUS_CODEPOINT          0x002B
+#define UNICODE_LEFT_CURLY_CODEPOINT    0x007B
+#define UNICODE_RIGHT_CURLY_CODEPOINT   0x007D
+#define UNICODE_SPACE_CODEPOINT         0x0020
+#define UCNV_PRV_ESCAPE_ICU         0
+#define UCNV_PRV_ESCAPE_C           'C'
+#define UCNV_PRV_ESCAPE_XML_DEC     'D'
+#define UCNV_PRV_ESCAPE_XML_HEX     'X'
+#define UCNV_PRV_ESCAPE_JAVA        'J'
+#define UCNV_PRV_ESCAPE_UNICODE     'U'
+#define UCNV_PRV_ESCAPE_CSS2        'S'
+#define UCNV_PRV_STOP_ON_ILLEGAL    'i'
+
+/*Function Pointer STOPS at the ILLEGAL_SEQUENCE */
+U_CAPI void    U_EXPORT2
+UCNV_FROM_U_CALLBACK_STOP (
+                  const void *context,
+                  UConverterFromUnicodeArgs *fromUArgs,
+                  const UChar* codeUnits,
+                  int32_t length,
+                  UChar32 codePoint,
+                  UConverterCallbackReason reason,
+                  UErrorCode * err)
+{
+    /* the caller must have set the error code accordingly */
+    return;
+}
+
+
+/*Function Pointer STOPS at the ILLEGAL_SEQUENCE */
+U_CAPI void    U_EXPORT2
+UCNV_TO_U_CALLBACK_STOP (
+                   const void *context,
+                   UConverterToUnicodeArgs *toUArgs,
+                   const char* codePoints,
+                   int32_t length,
+                   UConverterCallbackReason reason,
+                   UErrorCode * err)
+{
+    /* the caller must have set the error code accordingly */
+    return;
+}
+
+U_CAPI void    U_EXPORT2
+UCNV_FROM_U_CALLBACK_SKIP (                  
+                  const void *context,
+                  UConverterFromUnicodeArgs *fromUArgs,
+                  const UChar* codeUnits,
+                  int32_t length,
+                  UChar32 codePoint,
+                  UConverterCallbackReason reason,
+                  UErrorCode * err)
+{
+    if (reason <= UCNV_IRREGULAR)
+    {
+        if (context == NULL || (*((char*)context) == UCNV_PRV_STOP_ON_ILLEGAL && reason == UCNV_UNASSIGNED))
+        {
+            *err = U_ZERO_ERROR;
+        }
+        /* else the caller must have set the error code accordingly. */
+    }
+    /* else ignore the reset, close and clone calls. */
+}
+
+U_CAPI void    U_EXPORT2
+UCNV_FROM_U_CALLBACK_SUBSTITUTE (
+                  const void *context,
+                  UConverterFromUnicodeArgs *fromArgs,
+                  const UChar* codeUnits,
+                  int32_t length,
+                  UChar32 codePoint,
+                  UConverterCallbackReason reason,
+                  UErrorCode * err)
+{
+    if (reason <= UCNV_IRREGULAR)
+    {
+        if (context == NULL || (*((char*)context) == UCNV_PRV_STOP_ON_ILLEGAL && reason == UCNV_UNASSIGNED))
+        {
+            *err = U_ZERO_ERROR;
+            ucnv_cbFromUWriteSub(fromArgs, 0, err);
+        }
+        /* else the caller must have set the error code accordingly. */
+    }
+    /* else ignore the reset, close and clone calls. */
+}
+
+/*uses uprv_itou to get a unicode escape sequence of the offensive sequence,
+ *uses a clean copy (resetted) of the converter, to convert that unicode
+ *escape sequence to the target codepage (if conversion failure happens then
+ *we revert to substituting with subchar)
+ */
+U_CAPI void    U_EXPORT2
+UCNV_FROM_U_CALLBACK_ESCAPE (
+                         const void *context,
+                         UConverterFromUnicodeArgs *fromArgs,
+                         const UChar *codeUnits,
+                         int32_t length,
+                         UChar32 codePoint,
+                         UConverterCallbackReason reason,
+                         UErrorCode * err)
+{
+
+  UChar valueString[VALUE_STRING_LENGTH];
+  int32_t valueStringLength = 0;
+  int32_t i = 0;
+
+  const UChar *myValueSource = NULL;
+  UErrorCode err2 = U_ZERO_ERROR;
+  UConverterFromUCallback original = NULL;
+  const void *originalContext;
+
+  UConverterFromUCallback ignoredCallback = NULL;
+  const void *ignoredContext;
+  
+  if (reason > UCNV_IRREGULAR)
+  {
+      return;
+  }
+
+  ucnv_setFromUCallBack (fromArgs->converter,
+                     (UConverterFromUCallback) UCNV_FROM_U_CALLBACK_SUBSTITUTE,
+                     NULL,
+                     &original,
+                     &originalContext,
+                     &err2);
+  
+  if (U_FAILURE (err2))
+  {
+    *err = err2;
+    return;
+  } 
+  if(context==NULL)
+  { 
+      while (i < length)
+      {
+        valueString[valueStringLength++] = (UChar) UNICODE_PERCENT_SIGN_CODEPOINT;  /* adding % */
+        valueString[valueStringLength++] = (UChar) UNICODE_U_CODEPOINT; /* adding U */
+        valueStringLength += uprv_itou (valueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, (uint16_t)codeUnits[i++], 16, 4);
+      }
+  }
+  else
+  {
+      switch(*((char*)context))
+      {
+      case UCNV_PRV_ESCAPE_JAVA:
+          while (i < length)
+          {
+              valueString[valueStringLength++] = (UChar) UNICODE_RS_CODEPOINT;    /* adding \ */
+              valueString[valueStringLength++] = (UChar) UNICODE_U_LOW_CODEPOINT; /* adding u */
+              valueStringLength += uprv_itou (valueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, (uint16_t)codeUnits[i++], 16, 4);
+          }
+          break;
+
+      case UCNV_PRV_ESCAPE_C:
+          valueString[valueStringLength++] = (UChar) UNICODE_RS_CODEPOINT;    /* adding \ */
+
+          if(length==2){
+              valueString[valueStringLength++] = (UChar) UNICODE_U_CODEPOINT; /* adding U */
+              valueStringLength += uprv_itou (valueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, codePoint, 16, 8);
+
+          }
+          else{
+              valueString[valueStringLength++] = (UChar) UNICODE_U_LOW_CODEPOINT; /* adding u */
+              valueStringLength += uprv_itou (valueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, (uint16_t)codeUnits[0], 16, 4);
+          }
+          break;
+
+      case UCNV_PRV_ESCAPE_XML_DEC:
+
+          valueString[valueStringLength++] = (UChar) UNICODE_AMP_CODEPOINT;   /* adding & */
+          valueString[valueStringLength++] = (UChar) UNICODE_HASH_CODEPOINT;  /* adding # */
+          if(length==2){
+              valueStringLength += uprv_itou (valueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, codePoint, 10, 0);
+          }
+          else{
+              valueStringLength += uprv_itou (valueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, (uint16_t)codeUnits[0], 10, 0);
+          }
+          valueString[valueStringLength++] = (UChar) UNICODE_SEMICOLON_CODEPOINT; /* adding ; */
+          break;
+
+      case UCNV_PRV_ESCAPE_XML_HEX:
+
+          valueString[valueStringLength++] = (UChar) UNICODE_AMP_CODEPOINT;   /* adding & */
+          valueString[valueStringLength++] = (UChar) UNICODE_HASH_CODEPOINT;  /* adding # */
+          valueString[valueStringLength++] = (UChar) UNICODE_X_LOW_CODEPOINT; /* adding x */
+          if(length==2){
+              valueStringLength += uprv_itou (valueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, codePoint, 16, 0);
+          }
+          else{
+              valueStringLength += uprv_itou (valueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, (uint16_t)codeUnits[0], 16, 0);
+          }
+          valueString[valueStringLength++] = (UChar) UNICODE_SEMICOLON_CODEPOINT; /* adding ; */
+          break;
+
+      case UCNV_PRV_ESCAPE_UNICODE:
+          valueString[valueStringLength++] = (UChar) UNICODE_LEFT_CURLY_CODEPOINT;    /* adding { */
+          valueString[valueStringLength++] = (UChar) UNICODE_U_CODEPOINT;    /* adding U */
+          valueString[valueStringLength++] = (UChar) UNICODE_PLUS_CODEPOINT; /* adding + */
+          if (length == 2) {
+              valueStringLength += uprv_itou (valueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, codePoint, 16, 4);
+          } else {
+              valueStringLength += uprv_itou (valueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, (uint16_t)codeUnits[0], 16, 4);
+          }
+          valueString[valueStringLength++] = (UChar) UNICODE_RIGHT_CURLY_CODEPOINT;    /* adding } */
+          break;
+
+      case UCNV_PRV_ESCAPE_CSS2:
+          valueString[valueStringLength++] = (UChar) UNICODE_RS_CODEPOINT;    /* adding \ */
+          valueStringLength += uprv_itou (valueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, codePoint, 16, 0);
+          /* Always add space character, becase the next character might be whitespace,
+             which would erroneously be considered the termination of the escape sequence. */
+          valueString[valueStringLength++] = (UChar) UNICODE_SPACE_CODEPOINT;
+          break;
+
+      default:
+          while (i < length)
+          {
+              valueString[valueStringLength++] = (UChar) UNICODE_PERCENT_SIGN_CODEPOINT;  /* adding % */
+              valueString[valueStringLength++] = (UChar) UNICODE_U_CODEPOINT;             /* adding U */
+              valueStringLength += uprv_itou (valueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, (uint16_t)codeUnits[i++], 16, 4);
+          }
+      }
+  }  
+  myValueSource = valueString;
+
+  /* reset the error */
+  *err = U_ZERO_ERROR;
+
+  ucnv_cbFromUWriteUChars(fromArgs, &myValueSource, myValueSource+valueStringLength, 0, err);
+
+  ucnv_setFromUCallBack (fromArgs->converter,
+                         original,
+                         originalContext,
+                         &ignoredCallback,
+                         &ignoredContext,
+                         &err2);
+  if (U_FAILURE (err2))
+  {
+      *err = err2;
+      return;
+  }
+
+  return;
+}
+
+
+
+U_CAPI void  U_EXPORT2
+UCNV_TO_U_CALLBACK_SKIP (
+                 const void *context,
+                 UConverterToUnicodeArgs *toArgs,
+                 const char* codeUnits,
+                 int32_t length,
+                 UConverterCallbackReason reason,
+                 UErrorCode * err)
+{
+    if (reason <= UCNV_IRREGULAR)
+    {
+        if (context == NULL || (*((char*)context) == UCNV_PRV_STOP_ON_ILLEGAL && reason == UCNV_UNASSIGNED))
+        {
+            *err = U_ZERO_ERROR;
+        }
+        /* else the caller must have set the error code accordingly. */
+    }
+    /* else ignore the reset, close and clone calls. */
+}
+
+U_CAPI void    U_EXPORT2
+UCNV_TO_U_CALLBACK_SUBSTITUTE (
+                 const void *context,
+                 UConverterToUnicodeArgs *toArgs,
+                 const char* codeUnits,
+                 int32_t length,
+                 UConverterCallbackReason reason,
+                 UErrorCode * err)
+{
+    if (reason <= UCNV_IRREGULAR)
+    {
+        if (context == NULL || (*((char*)context) == UCNV_PRV_STOP_ON_ILLEGAL && reason == UCNV_UNASSIGNED))
+        {
+            *err = U_ZERO_ERROR;
+            ucnv_cbToUWriteSub(toArgs,0,err);
+        }
+        /* else the caller must have set the error code accordingly. */
+    }
+    /* else ignore the reset, close and clone calls. */
+}
+
+/*uses uprv_itou to get a unicode escape sequence of the offensive sequence,
+ *and uses that as the substitution sequence
+ */
+U_CAPI void   U_EXPORT2
+UCNV_TO_U_CALLBACK_ESCAPE (
+                 const void *context,
+                 UConverterToUnicodeArgs *toArgs,
+                 const char* codeUnits,
+                 int32_t length,
+                 UConverterCallbackReason reason,
+                 UErrorCode * err)
+{
+    UChar uniValueString[VALUE_STRING_LENGTH];
+    int32_t valueStringLength = 0;
+    int32_t i = 0;
+
+    if (reason > UCNV_IRREGULAR)
+    {
+        return;
+    }
+
+    if(context==NULL)
+    {    
+        while (i < length)
+        {
+            uniValueString[valueStringLength++] = (UChar) UNICODE_PERCENT_SIGN_CODEPOINT; /* adding % */
+            uniValueString[valueStringLength++] = (UChar) UNICODE_X_CODEPOINT;    /* adding X */
+            valueStringLength += uprv_itou (uniValueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, (uint8_t) codeUnits[i++], 16, 2);
+        }
+    }
+    else
+    {
+        switch(*((char*)context))
+        {
+        case UCNV_PRV_ESCAPE_XML_DEC:
+            while (i < length)
+            {
+                uniValueString[valueStringLength++] = (UChar) UNICODE_AMP_CODEPOINT;   /* adding & */
+                uniValueString[valueStringLength++] = (UChar) UNICODE_HASH_CODEPOINT;  /* adding # */
+                valueStringLength += uprv_itou (uniValueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, (uint8_t)codeUnits[i++], 10, 0);
+                uniValueString[valueStringLength++] = (UChar) UNICODE_SEMICOLON_CODEPOINT; /* adding ; */
+            }
+            break;
+
+        case UCNV_PRV_ESCAPE_XML_HEX:
+            while (i < length)
+            {
+                uniValueString[valueStringLength++] = (UChar) UNICODE_AMP_CODEPOINT;   /* adding & */
+                uniValueString[valueStringLength++] = (UChar) UNICODE_HASH_CODEPOINT;  /* adding # */
+                uniValueString[valueStringLength++] = (UChar) UNICODE_X_LOW_CODEPOINT; /* adding x */
+                valueStringLength += uprv_itou (uniValueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, (uint8_t)codeUnits[i++], 16, 0);
+                uniValueString[valueStringLength++] = (UChar) UNICODE_SEMICOLON_CODEPOINT; /* adding ; */
+            }
+            break;
+        case UCNV_PRV_ESCAPE_C:
+            while (i < length)
+            {
+                uniValueString[valueStringLength++] = (UChar) UNICODE_RS_CODEPOINT;    /* adding \ */
+                uniValueString[valueStringLength++] = (UChar) UNICODE_X_LOW_CODEPOINT; /* adding x */
+                valueStringLength += uprv_itou (uniValueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, (uint8_t)codeUnits[i++], 16, 2);
+            }
+            break;
+        default:
+            while (i < length)
+            {
+                uniValueString[valueStringLength++] = (UChar) UNICODE_PERCENT_SIGN_CODEPOINT; /* adding % */
+                uniValueString[valueStringLength++] = (UChar) UNICODE_X_CODEPOINT;    /* adding X */
+                uprv_itou (uniValueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, (uint8_t) codeUnits[i++], 16, 2);
+                valueStringLength += 2;
+            }
+        }
+    }
+    /* reset the error */
+    *err = U_ZERO_ERROR;
+
+    ucnv_cbToUWriteUChars(toArgs, uniValueString, valueStringLength, 0, err);
+}
+
+#endif
diff --git a/source/common/ucnv_ext.c b/source/common/ucnv_ext.c
new file mode 100644
index 0000000..8e8b326
--- /dev/null
+++ b/source/common/ucnv_ext.c
@@ -0,0 +1,1132 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2003-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  ucnv_ext.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2003jun13
+*   created by: Markus W. Scherer
+*
+*   Conversion extensions
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION && !UCONFIG_NO_LEGACY_CONVERSION
+
+#include "unicode/uset.h"
+#include "ucnv_bld.h"
+#include "ucnv_cnv.h"
+#include "ucnv_ext.h"
+#include "cmemory.h"
+
+/* to Unicode --------------------------------------------------------------- */
+
+/*
+ * @return lookup value for the byte, if found; else 0
+ */
+static U_INLINE uint32_t
+ucnv_extFindToU(const uint32_t *toUSection, int32_t length, uint8_t byte) {
+    uint32_t word0, word;
+    int32_t i, start, limit;
+
+    /* check the input byte against the lowest and highest section bytes */
+    start=(int32_t)UCNV_EXT_TO_U_GET_BYTE(toUSection[0]);
+    limit=(int32_t)UCNV_EXT_TO_U_GET_BYTE(toUSection[length-1]);
+    if(byte<start || limit<byte) {
+        return 0; /* the byte is out of range */
+    }
+
+    if(length==((limit-start)+1)) {
+        /* direct access on a linear array */
+        return UCNV_EXT_TO_U_GET_VALUE(toUSection[byte-start]); /* could be 0 */
+    }
+
+    /* word0 is suitable for <=toUSection[] comparison, word for <toUSection[] */
+    word0=UCNV_EXT_TO_U_MAKE_WORD(byte, 0);
+
+    /*
+     * Shift byte once instead of each section word and add 0xffffff.
+     * We will compare the shifted/added byte (bbffffff) against
+     * section words which have byte values in the same bit position.
+     * If and only if byte bb < section byte ss then bbffffff<ssvvvvvv
+     * for all v=0..f
+     * so we need not mask off the lower 24 bits of each section word.
+     */
+    word=word0|UCNV_EXT_TO_U_VALUE_MASK;
+
+    /* binary search */
+    start=0;
+    limit=length;
+    for(;;) {
+        i=limit-start;
+        if(i<=1) {
+            break; /* done */
+        }
+        /* start<limit-1 */
+
+        if(i<=4) {
+            /* linear search for the last part */
+            if(word0<=toUSection[start]) {
+                break;
+            }
+            if(++start<limit && word0<=toUSection[start]) {
+                break;
+            }
+            if(++start<limit && word0<=toUSection[start]) {
+                break;
+            }
+            /* always break at start==limit-1 */
+            ++start;
+            break;
+        }
+
+        i=(start+limit)/2;
+        if(word<toUSection[i]) {
+            limit=i;
+        } else {
+            start=i;
+        }
+    }
+
+    /* did we really find it? */
+    if(start<limit && byte==UCNV_EXT_TO_U_GET_BYTE(word=toUSection[start])) {
+        return UCNV_EXT_TO_U_GET_VALUE(word); /* never 0 */
+    } else {
+        return 0; /* not found */
+    }
+}
+
+/*
+ * TRUE if not an SI/SO stateful converter,
+ * or if the match length fits with the current converter state
+ */
+#define UCNV_EXT_TO_U_VERIFY_SISO_MATCH(sisoState, match) \
+    ((sisoState)<0 || ((sisoState)==0) == (match==1))
+
+/*
+ * this works like ucnv_extMatchFromU() except
+ * - the first character is in pre
+ * - no trie is used
+ * - the returned matchLength is not offset by 2
+ */
+static int32_t
+ucnv_extMatchToU(const int32_t *cx, int8_t sisoState,
+                 const char *pre, int32_t preLength,
+                 const char *src, int32_t srcLength,
+                 uint32_t *pMatchValue,
+                 UBool useFallback, UBool flush) {
+    const uint32_t *toUTable, *toUSection;
+
+    uint32_t value, matchValue;
+    int32_t i, j, idx, length, matchLength;
+    uint8_t b;
+
+    if(cx==NULL || cx[UCNV_EXT_TO_U_LENGTH]<=0) {
+        return 0; /* no extension data, no match */
+    }
+
+    /* initialize */
+    toUTable=UCNV_EXT_ARRAY(cx, UCNV_EXT_TO_U_INDEX, uint32_t);
+    idx=0;
+
+    matchValue=0;
+    i=j=matchLength=0;
+
+    if(sisoState==0) {
+        /* SBCS state of an SI/SO stateful converter, look at only exactly 1 byte */
+        if(preLength>1) {
+            return 0; /* no match of a DBCS sequence in SBCS mode */
+        } else if(preLength==1) {
+            srcLength=0;
+        } else /* preLength==0 */ {
+            if(srcLength>1) {
+                srcLength=1;
+            }
+        }
+        flush=TRUE;
+    }
+
+    /* we must not remember fallback matches when not using fallbacks */
+
+    /* match input units until there is a full match or the input is consumed */
+    for(;;) {
+        /* go to the next section */
+        toUSection=toUTable+idx;
+
+        /* read first pair of the section */
+        value=*toUSection++;
+        length=UCNV_EXT_TO_U_GET_BYTE(value);
+        value=UCNV_EXT_TO_U_GET_VALUE(value);
+        if( value!=0 &&
+            (UCNV_EXT_TO_U_IS_ROUNDTRIP(value) ||
+             TO_U_USE_FALLBACK(useFallback)) &&
+            UCNV_EXT_TO_U_VERIFY_SISO_MATCH(sisoState, i+j)
+        ) {
+            /* remember longest match so far */
+            matchValue=value;
+            matchLength=i+j;
+        }
+
+        /* match pre[] then src[] */
+        if(i<preLength) {
+            b=(uint8_t)pre[i++];
+        } else if(j<srcLength) {
+            b=(uint8_t)src[j++];
+        } else {
+            /* all input consumed, partial match */
+            if(flush || (length=(i+j))>UCNV_EXT_MAX_BYTES) {
+                /*
+                 * end of the entire input stream, stop with the longest match so far
+                 * or: partial match must not be longer than UCNV_EXT_MAX_BYTES
+                 * because it must fit into state buffers
+                 */
+                break;
+            } else {
+                /* continue with more input next time */
+                return -length;
+            }
+        }
+
+        /* search for the current UChar */
+        value=ucnv_extFindToU(toUSection, length, b);
+        if(value==0) {
+            /* no match here, stop with the longest match so far */
+            break;
+        } else {
+            if(UCNV_EXT_TO_U_IS_PARTIAL(value)) {
+                /* partial match, continue */
+                idx=(int32_t)UCNV_EXT_TO_U_GET_PARTIAL_INDEX(value);
+            } else {
+                if( (UCNV_EXT_TO_U_IS_ROUNDTRIP(value) ||
+                     TO_U_USE_FALLBACK(useFallback)) &&
+                    UCNV_EXT_TO_U_VERIFY_SISO_MATCH(sisoState, i+j)
+                ) {
+                    /* full match, stop with result */
+                    matchValue=value;
+                    matchLength=i+j;
+                } else {
+                    /* full match on fallback not taken, stop with the longest match so far */
+                }
+                break;
+            }
+        }
+    }
+
+    if(matchLength==0) {
+        /* no match at all */
+        return 0;
+    }
+
+    /* return result */
+    *pMatchValue=UCNV_EXT_TO_U_MASK_ROUNDTRIP(matchValue);
+    return matchLength;
+}
+
+static U_INLINE void
+ucnv_extWriteToU(UConverter *cnv, const int32_t *cx,
+                 uint32_t value,
+                 UChar **target, const UChar *targetLimit,
+                 int32_t **offsets, int32_t srcIndex,
+                 UErrorCode *pErrorCode) {
+    /* output the result */
+    if(UCNV_EXT_TO_U_IS_CODE_POINT(value)) {
+        /* output a single code point */
+        ucnv_toUWriteCodePoint(
+            cnv, UCNV_EXT_TO_U_GET_CODE_POINT(value),
+            target, targetLimit,
+            offsets, srcIndex,
+            pErrorCode);
+    } else {
+        /* output a string - with correct data we have resultLength>0 */
+        ucnv_toUWriteUChars(
+            cnv,
+            UCNV_EXT_ARRAY(cx, UCNV_EXT_TO_U_UCHARS_INDEX, UChar)+
+                UCNV_EXT_TO_U_GET_INDEX(value),
+            UCNV_EXT_TO_U_GET_LENGTH(value),
+            target, targetLimit,
+            offsets, srcIndex,
+            pErrorCode);
+    }
+}
+
+/*
+ * get the SI/SO toU state (state 0 is for SBCS, 1 for DBCS),
+ * or 1 for DBCS-only,
+ * or -1 if the converter is not SI/SO stateful
+ *
+ * Note: For SI/SO stateful converters getting here,
+ * cnv->mode==0 is equivalent to firstLength==1.
+ */
+#define UCNV_SISO_STATE(cnv) \
+    ((cnv)->sharedData->mbcs.outputType==MBCS_OUTPUT_2_SISO ? (int8_t)(cnv)->mode : \
+     (cnv)->sharedData->mbcs.outputType==MBCS_OUTPUT_DBCS_ONLY ? 1 : -1)
+
+/*
+ * target<targetLimit; set error code for overflow
+ */
+U_CFUNC UBool
+ucnv_extInitialMatchToU(UConverter *cnv, const int32_t *cx,
+                        int32_t firstLength,
+                        const char **src, const char *srcLimit,
+                        UChar **target, const UChar *targetLimit,
+                        int32_t **offsets, int32_t srcIndex,
+                        UBool flush,
+                        UErrorCode *pErrorCode) {
+    uint32_t value = 0;  /* initialize output-only param to 0 to silence gcc */
+    int32_t match;
+
+    /* try to match */
+    match=ucnv_extMatchToU(cx, (int8_t)UCNV_SISO_STATE(cnv),
+                           (const char *)cnv->toUBytes, firstLength,
+                           *src, (int32_t)(srcLimit-*src),
+                           &value,
+                           cnv->useFallback, flush);
+    if(match>0) {
+        /* advance src pointer for the consumed input */
+        *src+=match-firstLength;
+
+        /* write result to target */
+        ucnv_extWriteToU(cnv, cx,
+                         value,
+                         target, targetLimit,
+                         offsets, srcIndex,
+                         pErrorCode);
+        return TRUE;
+    } else if(match<0) {
+        /* save state for partial match */
+        const char *s;
+        int32_t j;
+
+        /* copy the first code point */
+        s=(const char *)cnv->toUBytes;
+        cnv->preToUFirstLength=(int8_t)firstLength;
+        for(j=0; j<firstLength; ++j) {
+            cnv->preToU[j]=*s++;
+        }
+
+        /* now copy the newly consumed input */
+        s=*src;
+        match=-match;
+        for(; j<match; ++j) {
+            cnv->preToU[j]=*s++;
+        }
+        *src=s; /* same as *src=srcLimit; because we reached the end of input */
+        cnv->preToULength=(int8_t)match;
+        return TRUE;
+    } else /* match==0 no match */ {
+        return FALSE;
+    }
+}
+
+U_CFUNC UChar32
+ucnv_extSimpleMatchToU(const int32_t *cx,
+                       const char *source, int32_t length,
+                       UBool useFallback) {
+    uint32_t value = 0;  /* initialize output-only param to 0 to silence gcc */
+    int32_t match;
+
+    if(length<=0) {
+        return 0xffff;
+    }
+
+    /* try to match */
+    match=ucnv_extMatchToU(cx, -1,
+                           source, length,
+                           NULL, 0,
+                           &value,
+                           useFallback, TRUE);
+    if(match==length) {
+        /* write result for simple, single-character conversion */
+        if(UCNV_EXT_TO_U_IS_CODE_POINT(value)) {
+            return UCNV_EXT_TO_U_GET_CODE_POINT(value);
+        }
+    }
+
+    /*
+     * return no match because
+     * - match>0 && value points to string: simple conversion cannot handle multiple code points
+     * - match>0 && match!=length: not all input consumed, forbidden for this function
+     * - match==0: no match found in the first place
+     * - match<0: partial match, not supported for simple conversion (and flush==TRUE)
+     */
+    return 0xfffe;
+}
+
+/*
+ * continue partial match with new input
+ * never called for simple, single-character conversion
+ */
+U_CFUNC void
+ucnv_extContinueMatchToU(UConverter *cnv,
+                         UConverterToUnicodeArgs *pArgs, int32_t srcIndex,
+                         UErrorCode *pErrorCode) {
+    uint32_t value = 0;  /* initialize output-only param to 0 to silence gcc */
+    int32_t match, length;
+
+    match=ucnv_extMatchToU(cnv->sharedData->mbcs.extIndexes, (int8_t)UCNV_SISO_STATE(cnv),
+                           cnv->preToU, cnv->preToULength,
+                           pArgs->source, (int32_t)(pArgs->sourceLimit-pArgs->source),
+                           &value,
+                           cnv->useFallback, pArgs->flush);
+    if(match>0) {
+        if(match>=cnv->preToULength) {
+            /* advance src pointer for the consumed input */
+            pArgs->source+=match-cnv->preToULength;
+            cnv->preToULength=0;
+        } else {
+            /* the match did not use all of preToU[] - keep the rest for replay */
+            length=cnv->preToULength-match;
+            uprv_memmove(cnv->preToU, cnv->preToU+match, length);
+            cnv->preToULength=(int8_t)-length;
+        }
+
+        /* write result */
+        ucnv_extWriteToU(cnv, cnv->sharedData->mbcs.extIndexes,
+                         value,
+                         &pArgs->target, pArgs->targetLimit,
+                         &pArgs->offsets, srcIndex,
+                         pErrorCode);
+    } else if(match<0) {
+        /* save state for partial match */
+        const char *s;
+        int32_t j;
+
+        /* just _append_ the newly consumed input to preToU[] */
+        s=pArgs->source;
+        match=-match;
+        for(j=cnv->preToULength; j<match; ++j) {
+            cnv->preToU[j]=*s++;
+        }
+        pArgs->source=s; /* same as *src=srcLimit; because we reached the end of input */
+        cnv->preToULength=(int8_t)match;
+    } else /* match==0 */ {
+        /*
+         * no match
+         *
+         * We need to split the previous input into two parts:
+         *
+         * 1. The first codepage character is unmappable - that's how we got into
+         *    trying the extension data in the first place.
+         *    We need to move it from the preToU buffer
+         *    to the error buffer, set an error code,
+         *    and prepare the rest of the previous input for 2.
+         *
+         * 2. The rest of the previous input must be converted once we
+         *    come back from the callback for the first character.
+         *    At that time, we have to try again from scratch to convert
+         *    these input characters.
+         *    The replay will be handled by the ucnv.c conversion code.
+         */
+
+        /* move the first codepage character to the error field */
+        uprv_memcpy(cnv->toUBytes, cnv->preToU, cnv->preToUFirstLength);
+        cnv->toULength=cnv->preToUFirstLength;
+
+        /* move the rest up inside the buffer */
+        length=cnv->preToULength-cnv->preToUFirstLength;
+        if(length>0) {
+            uprv_memmove(cnv->preToU, cnv->preToU+cnv->preToUFirstLength, length);
+        }
+
+        /* mark preToU for replay */
+        cnv->preToULength=(int8_t)-length;
+
+        /* set the error code for unassigned */
+        *pErrorCode=U_INVALID_CHAR_FOUND;
+    }
+}
+
+/* from Unicode ------------------------------------------------------------- */
+
+/*
+ * @return index of the UChar, if found; else <0
+ */
+static U_INLINE int32_t
+ucnv_extFindFromU(const UChar *fromUSection, int32_t length, UChar u) {
+    int32_t i, start, limit;
+
+    /* binary search */
+    start=0;
+    limit=length;
+    for(;;) {
+        i=limit-start;
+        if(i<=1) {
+            break; /* done */
+        }
+        /* start<limit-1 */
+
+        if(i<=4) {
+            /* linear search for the last part */
+            if(u<=fromUSection[start]) {
+                break;
+            }
+            if(++start<limit && u<=fromUSection[start]) {
+                break;
+            }
+            if(++start<limit && u<=fromUSection[start]) {
+                break;
+            }
+            /* always break at start==limit-1 */
+            ++start;
+            break;
+        }
+
+        i=(start+limit)/2;
+        if(u<fromUSection[i]) {
+            limit=i;
+        } else {
+            start=i;
+        }
+    }
+
+    /* did we really find it? */
+    if(start<limit && u==fromUSection[start]) {
+        return start;
+    } else {
+        return -1; /* not found */
+    }
+}
+
+/*
+ * @param cx pointer to extension data; if NULL, returns 0
+ * @param firstCP the first code point before all the other UChars
+ * @param pre UChars that must match; !initialMatch: partial match with them
+ * @param preLength length of pre, >=0
+ * @param src UChars that can be used to complete a match
+ * @param srcLength length of src, >=0
+ * @param pMatchValue [out] output result value for the match from the data structure
+ * @param useFallback "use fallback" flag, usually from cnv->useFallback
+ * @param flush TRUE if the end of the input stream is reached
+ * @return >1: matched, return value=total match length (number of input units matched)
+ *          1: matched, no mapping but request for <subchar1>
+ *             (only for the first code point)
+ *          0: no match
+ *         <0: partial match, return value=negative total match length
+ *             (partial matches are never returned for flush==TRUE)
+ *             (partial matches are never returned as being longer than UCNV_EXT_MAX_UCHARS)
+ *         the matchLength is 2 if only firstCP matched, and >2 if firstCP and
+ *         further code units matched
+ */
+static int32_t
+ucnv_extMatchFromU(const int32_t *cx,
+                   UChar32 firstCP,
+                   const UChar *pre, int32_t preLength,
+                   const UChar *src, int32_t srcLength,
+                   uint32_t *pMatchValue,
+                   UBool useFallback, UBool flush) {
+    const uint16_t *stage12, *stage3;
+    const uint32_t *stage3b;
+
+    const UChar *fromUTableUChars, *fromUSectionUChars;
+    const uint32_t *fromUTableValues, *fromUSectionValues;
+
+    uint32_t value, matchValue;
+    int32_t i, j, idx, length, matchLength;
+    UChar c;
+
+    if(cx==NULL) {
+        return 0; /* no extension data, no match */
+    }
+
+    /* trie lookup of firstCP */
+    idx=firstCP>>10; /* stage 1 index */
+    if(idx>=cx[UCNV_EXT_FROM_U_STAGE_1_LENGTH]) {
+        return 0; /* the first code point is outside the trie */
+    }
+
+    stage12=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_STAGE_12_INDEX, uint16_t);
+    stage3=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_STAGE_3_INDEX, uint16_t);
+    idx=UCNV_EXT_FROM_U(stage12, stage3, idx, firstCP);
+
+    stage3b=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_STAGE_3B_INDEX, uint32_t);
+    value=stage3b[idx];
+    if(value==0) {
+        return 0;
+    }
+
+    /*
+     * Tests for (value&UCNV_EXT_FROM_U_RESERVED_MASK)==0:
+     * Do not interpret values with reserved bits used, for forward compatibility,
+     * and do not even remember intermediate results with reserved bits used.
+     */
+
+    if(UCNV_EXT_TO_U_IS_PARTIAL(value)) {
+        /* partial match, enter the loop below */
+        idx=(int32_t)UCNV_EXT_FROM_U_GET_PARTIAL_INDEX(value);
+
+        /* initialize */
+        fromUTableUChars=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_UCHARS_INDEX, UChar);
+        fromUTableValues=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_VALUES_INDEX, uint32_t);
+
+        matchValue=0;
+        i=j=matchLength=0;
+
+        /* we must not remember fallback matches when not using fallbacks */
+
+        /* match input units until there is a full match or the input is consumed */
+        for(;;) {
+            /* go to the next section */
+            fromUSectionUChars=fromUTableUChars+idx;
+            fromUSectionValues=fromUTableValues+idx;
+
+            /* read first pair of the section */
+            length=*fromUSectionUChars++;
+            value=*fromUSectionValues++;
+            if( value!=0 &&
+                (UCNV_EXT_FROM_U_IS_ROUNDTRIP(value) ||
+                 FROM_U_USE_FALLBACK(useFallback, firstCP)) &&
+                (value&UCNV_EXT_FROM_U_RESERVED_MASK)==0
+            ) {
+                /* remember longest match so far */
+                matchValue=value;
+                matchLength=2+i+j;
+            }
+
+            /* match pre[] then src[] */
+            if(i<preLength) {
+                c=pre[i++];
+            } else if(j<srcLength) {
+                c=src[j++];
+            } else {
+                /* all input consumed, partial match */
+                if(flush || (length=(i+j))>UCNV_EXT_MAX_UCHARS) {
+                    /*
+                     * end of the entire input stream, stop with the longest match so far
+                     * or: partial match must not be longer than UCNV_EXT_MAX_UCHARS
+                     * because it must fit into state buffers
+                     */
+                    break;
+                } else {
+                    /* continue with more input next time */
+                    return -(2+length);
+                }
+            }
+
+            /* search for the current UChar */
+            idx=ucnv_extFindFromU(fromUSectionUChars, length, c);
+            if(idx<0) {
+                /* no match here, stop with the longest match so far */
+                break;
+            } else {
+                value=fromUSectionValues[idx];
+                if(UCNV_EXT_FROM_U_IS_PARTIAL(value)) {
+                    /* partial match, continue */
+                    idx=(int32_t)UCNV_EXT_FROM_U_GET_PARTIAL_INDEX(value);
+                } else {
+                    if( (UCNV_EXT_FROM_U_IS_ROUNDTRIP(value) ||
+                         FROM_U_USE_FALLBACK(useFallback, firstCP)) &&
+                        (value&UCNV_EXT_FROM_U_RESERVED_MASK)==0
+                    ) {
+                        /* full match, stop with result */
+                        matchValue=value;
+                        matchLength=2+i+j;
+                    } else {
+                        /* full match on fallback not taken, stop with the longest match so far */
+                    }
+                    break;
+                }
+            }
+        }
+
+        if(matchLength==0) {
+            /* no match at all */
+            return 0;
+        }
+    } else /* result from firstCP trie lookup */ {
+        if( (UCNV_EXT_FROM_U_IS_ROUNDTRIP(value) ||
+             FROM_U_USE_FALLBACK(useFallback, firstCP)) &&
+            (value&UCNV_EXT_FROM_U_RESERVED_MASK)==0
+        ) {
+            /* full match, stop with result */
+            matchValue=value;
+            matchLength=2;
+        } else {
+            /* fallback not taken */
+            return 0;
+        }
+    }
+
+    /* return result */
+    if(matchValue==UCNV_EXT_FROM_U_SUBCHAR1) {
+        return 1; /* assert matchLength==2 */
+    }
+
+    *pMatchValue=matchValue;
+    return matchLength;
+}
+
+/*
+ * @param value fromUnicode mapping table value; ignores roundtrip and reserved bits
+ */
+static U_INLINE void
+ucnv_extWriteFromU(UConverter *cnv, const int32_t *cx,
+                   uint32_t value,
+                   char **target, const char *targetLimit,
+                   int32_t **offsets, int32_t srcIndex,
+                   UErrorCode *pErrorCode) {
+    uint8_t buffer[1+UCNV_EXT_MAX_BYTES];
+    const uint8_t *result;
+    int32_t length, prevLength;
+
+    length=UCNV_EXT_FROM_U_GET_LENGTH(value);
+    value=(uint32_t)UCNV_EXT_FROM_U_GET_DATA(value);
+
+    /* output the result */
+    if(length<=UCNV_EXT_FROM_U_MAX_DIRECT_LENGTH) {
+        /*
+         * Generate a byte array and then write it below.
+         * This is not the fastest possible way, but it should be ok for
+         * extension mappings, and it is much simpler.
+         * Offset and overflow handling are only done once this way.
+         */
+        uint8_t *p=buffer+1; /* reserve buffer[0] for shiftByte below */
+        switch(length) {
+        case 3:
+            *p++=(uint8_t)(value>>16);
+        case 2:
+            *p++=(uint8_t)(value>>8);
+        case 1:
+            *p++=(uint8_t)value;
+        default:
+            break; /* will never occur */
+        }
+        result=buffer+1;
+    } else {
+        result=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_BYTES_INDEX, uint8_t)+value;
+    }
+
+    /* with correct data we have length>0 */
+
+    if((prevLength=cnv->fromUnicodeStatus)!=0) {
+        /* handle SI/SO stateful output */
+        uint8_t shiftByte;
+
+        if(prevLength>1 && length==1) {
+            /* change from double-byte mode to single-byte */
+            shiftByte=(uint8_t)UCNV_SI;
+            cnv->fromUnicodeStatus=1;
+        } else if(prevLength==1 && length>1) {
+            /* change from single-byte mode to double-byte */
+            shiftByte=(uint8_t)UCNV_SO;
+            cnv->fromUnicodeStatus=2;
+        } else {
+            shiftByte=0;
+        }
+
+        if(shiftByte!=0) {
+            /* prepend the shift byte to the result bytes */
+            buffer[0]=shiftByte;
+            if(result!=buffer+1) {
+                uprv_memcpy(buffer+1, result, length);
+            }
+            result=buffer;
+            ++length;
+        }
+    }
+
+    ucnv_fromUWriteBytes(cnv, (const char *)result, length,
+                         target, targetLimit,
+                         offsets, srcIndex,
+                         pErrorCode);
+}
+
+/*
+ * target<targetLimit; set error code for overflow
+ */
+U_CFUNC UBool
+ucnv_extInitialMatchFromU(UConverter *cnv, const int32_t *cx,
+                          UChar32 cp,
+                          const UChar **src, const UChar *srcLimit,
+                          char **target, const char *targetLimit,
+                          int32_t **offsets, int32_t srcIndex,
+                          UBool flush,
+                          UErrorCode *pErrorCode) {
+    uint32_t value = 0;  /* initialize output-only param to 0 to silence gcc */
+    int32_t match;
+
+    /* try to match */
+    match=ucnv_extMatchFromU(cx, cp,
+                             NULL, 0,
+                             *src, (int32_t)(srcLimit-*src),
+                             &value,
+                             cnv->useFallback, flush);
+
+    /* reject a match if the result is a single byte for DBCS-only */
+    if( match>=2 &&
+        !(UCNV_EXT_FROM_U_GET_LENGTH(value)==1 &&
+          cnv->sharedData->mbcs.outputType==MBCS_OUTPUT_DBCS_ONLY)
+    ) {
+        /* advance src pointer for the consumed input */
+        *src+=match-2; /* remove 2 for the initial code point */
+
+        /* write result to target */
+        ucnv_extWriteFromU(cnv, cx,
+                           value,
+                           target, targetLimit,
+                           offsets, srcIndex,
+                           pErrorCode);
+        return TRUE;
+    } else if(match<0) {
+        /* save state for partial match */
+        const UChar *s;
+        int32_t j;
+
+        /* copy the first code point */
+        cnv->preFromUFirstCP=cp;
+
+        /* now copy the newly consumed input */
+        s=*src;
+        match=-match-2; /* remove 2 for the initial code point */
+        for(j=0; j<match; ++j) {
+            cnv->preFromU[j]=*s++;
+        }
+        *src=s; /* same as *src=srcLimit; because we reached the end of input */
+        cnv->preFromULength=(int8_t)match;
+        return TRUE;
+    } else if(match==1) {
+        /* matched, no mapping but request for <subchar1> */
+        cnv->useSubChar1=TRUE;
+        return FALSE;
+    } else /* match==0 no match */ {
+        return FALSE;
+    }
+}
+
+/*
+ * Used by ISO 2022 implementation.
+ * @return number of bytes in *pValue; negative number if fallback; 0 for no mapping
+ */
+U_CFUNC int32_t
+ucnv_extSimpleMatchFromU(const int32_t *cx,
+                         UChar32 cp, uint32_t *pValue,
+                         UBool useFallback) {
+    uint32_t value;
+    int32_t match;
+
+    /* try to match */
+    match=ucnv_extMatchFromU(cx,
+                             cp,
+                             NULL, 0,
+                             NULL, 0,
+                             &value,
+                             useFallback, TRUE);
+    if(match>=2) {
+        /* write result for simple, single-character conversion */
+        int32_t length;
+        int isRoundtrip;
+
+        isRoundtrip=UCNV_EXT_FROM_U_IS_ROUNDTRIP(value);
+        length=UCNV_EXT_FROM_U_GET_LENGTH(value);
+        value=(uint32_t)UCNV_EXT_FROM_U_GET_DATA(value);
+
+        if(length<=UCNV_EXT_FROM_U_MAX_DIRECT_LENGTH) {
+            *pValue=value;
+            return isRoundtrip ? length : -length;
+#if 0 /* not currently used */
+        } else if(length==4) {
+            /* de-serialize a 4-byte result */
+            const uint8_t *result=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_BYTES_INDEX, uint8_t)+value;
+            *pValue=
+                ((uint32_t)result[0]<<24)|
+                ((uint32_t)result[1]<<16)|
+                ((uint32_t)result[2]<<8)|
+                result[3];
+            return isRoundtrip ? 4 : -4;
+#endif
+        }
+    }
+
+    /*
+     * return no match because
+     * - match>1 && resultLength>4: result too long for simple conversion
+     * - match==1: no match found, <subchar1> preferred
+     * - match==0: no match found in the first place
+     * - match<0: partial match, not supported for simple conversion (and flush==TRUE)
+     */
+    return 0;
+}
+
+/*
+ * continue partial match with new input, requires cnv->preFromUFirstCP>=0
+ * never called for simple, single-character conversion
+ */
+U_CFUNC void
+ucnv_extContinueMatchFromU(UConverter *cnv,
+                           UConverterFromUnicodeArgs *pArgs, int32_t srcIndex,
+                           UErrorCode *pErrorCode) {
+    uint32_t value = 0;  /* initialize output-only param to 0 to silence gcc */
+    int32_t match;
+
+    match=ucnv_extMatchFromU(cnv->sharedData->mbcs.extIndexes,
+                             cnv->preFromUFirstCP,
+                             cnv->preFromU, cnv->preFromULength,
+                             pArgs->source, (int32_t)(pArgs->sourceLimit-pArgs->source),
+                             &value,
+                             cnv->useFallback, pArgs->flush);
+    if(match>=2) {
+        match-=2; /* remove 2 for the initial code point */
+
+        if(match>=cnv->preFromULength) {
+            /* advance src pointer for the consumed input */
+            pArgs->source+=match-cnv->preFromULength;
+            cnv->preFromULength=0;
+        } else {
+            /* the match did not use all of preFromU[] - keep the rest for replay */
+            int32_t length=cnv->preFromULength-match;
+            uprv_memmove(cnv->preFromU, cnv->preFromU+match, length*U_SIZEOF_UCHAR);
+            cnv->preFromULength=(int8_t)-length;
+        }
+
+        /* finish the partial match */
+        cnv->preFromUFirstCP=U_SENTINEL;
+
+        /* write result */
+        ucnv_extWriteFromU(cnv, cnv->sharedData->mbcs.extIndexes,
+                           value,
+                           &pArgs->target, pArgs->targetLimit,
+                           &pArgs->offsets, srcIndex,
+                           pErrorCode);
+    } else if(match<0) {
+        /* save state for partial match */
+        const UChar *s;
+        int32_t j;
+
+        /* just _append_ the newly consumed input to preFromU[] */
+        s=pArgs->source;
+        match=-match-2; /* remove 2 for the initial code point */
+        for(j=cnv->preFromULength; j<match; ++j) {
+            cnv->preFromU[j]=*s++;
+        }
+        pArgs->source=s; /* same as *src=srcLimit; because we reached the end of input */
+        cnv->preFromULength=(int8_t)match;
+    } else /* match==0 or 1 */ {
+        /*
+         * no match
+         *
+         * We need to split the previous input into two parts:
+         *
+         * 1. The first code point is unmappable - that's how we got into
+         *    trying the extension data in the first place.
+         *    We need to move it from the preFromU buffer
+         *    to the error buffer, set an error code,
+         *    and prepare the rest of the previous input for 2.
+         *
+         * 2. The rest of the previous input must be converted once we
+         *    come back from the callback for the first code point.
+         *    At that time, we have to try again from scratch to convert
+         *    these input characters.
+         *    The replay will be handled by the ucnv.c conversion code.
+         */
+
+        if(match==1) {
+            /* matched, no mapping but request for <subchar1> */
+            cnv->useSubChar1=TRUE;
+        }
+
+        /* move the first code point to the error field */
+        cnv->fromUChar32=cnv->preFromUFirstCP;
+        cnv->preFromUFirstCP=U_SENTINEL;
+
+        /* mark preFromU for replay */
+        cnv->preFromULength=-cnv->preFromULength;
+
+        /* set the error code for unassigned */
+        *pErrorCode=U_INVALID_CHAR_FOUND;
+    }
+}
+
+static void
+ucnv_extGetUnicodeSetString(const UConverterSharedData *sharedData,
+                            const int32_t *cx,
+                            const USetAdder *sa,
+                            UBool useFallback,
+                            int32_t minLength,
+                            UChar32 c,
+                            UChar s[UCNV_EXT_MAX_UCHARS], int32_t length,
+                            int32_t sectionIndex,
+                            UErrorCode *pErrorCode) {
+    const UChar *fromUSectionUChars;
+    const uint32_t *fromUSectionValues;
+
+    uint32_t value;
+    int32_t i, count;
+
+    fromUSectionUChars=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_UCHARS_INDEX, UChar)+sectionIndex;
+    fromUSectionValues=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_VALUES_INDEX, uint32_t)+sectionIndex;
+
+    /* read first pair of the section */
+    count=*fromUSectionUChars++;
+    value=*fromUSectionValues++;
+
+    if( value!=0 &&
+        (UCNV_EXT_FROM_U_IS_ROUNDTRIP(value) || useFallback) &&
+        UCNV_EXT_FROM_U_GET_LENGTH(value)>=minLength
+    ) {
+        if(c>=0) {
+            /* add the initial code point */
+            sa->add(sa->set, c);
+        } else {
+            /* add the string so far */
+            sa->addString(sa->set, s, length);
+        }
+    }
+
+    for(i=0; i<count; ++i) {
+        /* append this code unit and recurse or add the string */
+        s[length]=fromUSectionUChars[i];
+        value=fromUSectionValues[i];
+
+        if(value==0) {
+            /* no mapping, do nothing */
+        } else if(UCNV_EXT_FROM_U_IS_PARTIAL(value)) {
+            ucnv_extGetUnicodeSetString(
+                sharedData, cx, sa, useFallback, minLength,
+                U_SENTINEL, s, length+1,
+                (int32_t)UCNV_EXT_FROM_U_GET_PARTIAL_INDEX(value),
+                pErrorCode);
+        } else if((useFallback ?
+                      (value&UCNV_EXT_FROM_U_RESERVED_MASK)==0 :
+                      ((value&(UCNV_EXT_FROM_U_ROUNDTRIP_FLAG|UCNV_EXT_FROM_U_RESERVED_MASK))==
+                          UCNV_EXT_FROM_U_ROUNDTRIP_FLAG)) &&
+                  UCNV_EXT_FROM_U_GET_LENGTH(value)>=minLength
+        ) {
+            sa->addString(sa->set, s, length+1);
+        }
+    }
+}
+
+U_CFUNC void
+ucnv_extGetUnicodeSet(const UConverterSharedData *sharedData,
+                      const USetAdder *sa,
+                      UConverterUnicodeSet which,
+                      UConverterSetFilter filter,
+                      UErrorCode *pErrorCode) {
+    const int32_t *cx;
+    const uint16_t *stage12, *stage3, *ps2, *ps3;
+    const uint32_t *stage3b;
+
+    uint32_t value;
+    int32_t st1, stage1Length, st2, st3, minLength;
+    UBool useFallback;
+
+    UChar s[UCNV_EXT_MAX_UCHARS];
+    UChar32 c;
+    int32_t length;
+
+    cx=sharedData->mbcs.extIndexes;
+    if(cx==NULL) {
+        return;
+    }
+
+    stage12=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_STAGE_12_INDEX, uint16_t);
+    stage3=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_STAGE_3_INDEX, uint16_t);
+    stage3b=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_STAGE_3B_INDEX, uint32_t);
+
+    stage1Length=cx[UCNV_EXT_FROM_U_STAGE_1_LENGTH];
+
+    useFallback=(UBool)(which==UCNV_ROUNDTRIP_AND_FALLBACK_SET);
+
+    /* enumerate the from-Unicode trie table */
+    c=0; /* keep track of the current code point while enumerating */
+
+    if(filter==UCNV_SET_FILTER_2022_CN) {
+        minLength=3;
+    } else if( sharedData->mbcs.outputType==MBCS_OUTPUT_DBCS_ONLY ||
+               filter!=UCNV_SET_FILTER_NONE
+    ) {
+        /* DBCS-only, ignore single-byte results */
+        minLength=2;
+    } else {
+        minLength=1;
+    }
+
+    /*
+     * the trie enumeration is almost the same as
+     * in MBCSGetUnicodeSet() for MBCS_OUTPUT_1
+     */
+    for(st1=0; st1<stage1Length; ++st1) {
+        st2=stage12[st1];
+        if(st2>stage1Length) {
+            ps2=stage12+st2;
+            for(st2=0; st2<64; ++st2) {
+                if((st3=(int32_t)ps2[st2]<<UCNV_EXT_STAGE_2_LEFT_SHIFT)!=0) {
+                    /* read the stage 3 block */
+                    ps3=stage3+st3;
+
+                    /*
+                     * Add code points for which the roundtrip flag is set.
+                     * Do not add <subchar1> entries or other (future?) pseudo-entries
+                     * with an output length of 0, or entries with reserved bits set.
+                     * Recurse for partial results.
+                     */
+                    do {
+                        value=stage3b[*ps3++];
+                        if(value==0) {
+                            /* no mapping, do nothing */
+                        } else if(UCNV_EXT_FROM_U_IS_PARTIAL(value)) {
+                            length=0;
+                            U16_APPEND_UNSAFE(s, length, c);
+                            ucnv_extGetUnicodeSetString(
+                                sharedData, cx, sa, useFallback, minLength,
+                                c, s, length,
+                                (int32_t)UCNV_EXT_FROM_U_GET_PARTIAL_INDEX(value),
+                                pErrorCode);
+                        } else if((useFallback ?
+                                      (value&UCNV_EXT_FROM_U_RESERVED_MASK)==0 :
+                                      ((value&(UCNV_EXT_FROM_U_ROUNDTRIP_FLAG|UCNV_EXT_FROM_U_RESERVED_MASK))==
+                                          UCNV_EXT_FROM_U_ROUNDTRIP_FLAG)) &&
+                                  UCNV_EXT_FROM_U_GET_LENGTH(value)>=minLength
+                        ) {
+                            switch(filter) {
+                            case UCNV_SET_FILTER_2022_CN:
+                                if(!(UCNV_EXT_FROM_U_GET_LENGTH(value)==3 && UCNV_EXT_FROM_U_GET_DATA(value)<=0x82ffff)) {
+                                    continue;
+                                }
+                                break;
+                            case UCNV_SET_FILTER_SJIS:
+                                if(!(UCNV_EXT_FROM_U_GET_LENGTH(value)==2 && (value=UCNV_EXT_FROM_U_GET_DATA(value))>=0x8140 && value<=0xeffc)) {
+                                    continue;
+                                }
+                                break;
+                            case UCNV_SET_FILTER_GR94DBCS:
+                                if(!(UCNV_EXT_FROM_U_GET_LENGTH(value)==2 &&
+                                     (uint16_t)((value=UCNV_EXT_FROM_U_GET_DATA(value))-0xa1a1)<=(0xfefe - 0xa1a1) &&
+                                     (uint8_t)(value-0xa1)<=(0xfe - 0xa1))) {
+                                    continue;
+                                }
+                                break;
+                            case UCNV_SET_FILTER_HZ:
+                                if(!(UCNV_EXT_FROM_U_GET_LENGTH(value)==2 &&
+                                     (uint16_t)((value=UCNV_EXT_FROM_U_GET_DATA(value))-0xa1a1)<=(0xfdfe - 0xa1a1) &&
+                                     (uint8_t)(value-0xa1)<=(0xfe - 0xa1))) {
+                                    continue;
+                                }
+                                break;
+                            default:
+                                /*
+                                 * UCNV_SET_FILTER_NONE,
+                                 * or UCNV_SET_FILTER_DBCS_ONLY which is handled via minLength
+                                 */
+                                break;
+                            }
+                            sa->add(sa->set, c);
+                        }
+                    } while((++c&0xf)!=0);
+                } else {
+                    c+=16; /* empty stage 3 block */
+                }
+            }
+        } else {
+            c+=1024; /* empty stage 2 block */
+        }
+    }
+}
+
+#endif /* #if !UCONFIG_NO_LEGACY_CONVERSION */
diff --git a/source/common/ucnv_ext.h b/source/common/ucnv_ext.h
new file mode 100644
index 0000000..e3e46f4
--- /dev/null
+++ b/source/common/ucnv_ext.h
@@ -0,0 +1,473 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2003-2007, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  ucnv_ext.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2003jun13
+*   created by: Markus W. Scherer
+*
+*   Conversion extensions
+*/
+
+#ifndef __UCNV_EXT_H__
+#define __UCNV_EXT_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ucnv.h"
+#include "ucnv_cnv.h"
+
+/*
+ * See icuhtml/design/conversion/conversion_extensions.html
+ *
+ * Conversion extensions serve two purposes:
+ * 1. They support m:n mappings.
+ * 2. They support extension-only conversion files that are used together
+ *    with the regular conversion data in base files.
+ *
+ * A base file may contain an extension table (explicitly requested or
+ * implicitly generated for m:n mappings), but its extension table is not
+ * used when an extension-only file is used.
+ *
+ * It is an error if a base file contains any regular (not extension) mapping
+ * from the same sequence as a mapping in the extension file
+ * because the base mapping would hide the extension mapping.
+ *
+ *
+ * Data for conversion extensions:
+ *
+ * One set of data structures per conversion direction (to/from Unicode).
+ * The data structures are sorted by input units to allow for binary search.
+ * Input sequences of more than one unit are handled like contraction tables
+ * in collation:
+ * The lookup value of a unit points to another table that is to be searched
+ * for the next unit, recursively.
+ *
+ * For conversion from Unicode, the initial code point is looked up in
+ * a 3-stage trie for speed,
+ * with an additional table of unique results to save space.
+ *
+ * Long output strings are stored in separate arrays, with length and index
+ * in the lookup tables.
+ * Output results also include a flag distinguishing roundtrip from
+ * (reverse) fallback mappings.
+ *
+ * Input Unicode strings must not begin or end with unpaired surrogates
+ * to avoid problems with matches on parts of surrogate pairs.
+ *
+ * Mappings from multiple characters (code points or codepage state
+ * table sequences) must be searched preferring the longest match.
+ * For this to work and be efficient, the variable-width table must contain
+ * all mappings that contain prefixes of the multiple characters.
+ * If an extension table is built on top of a base table in another file
+ * and a base table entry is a prefix of a multi-character mapping, then
+ * this is an error.
+ *
+ *
+ * Implementation note:
+ *
+ * Currently, the parser and several checks in the code limit the number
+ * of UChars or bytes in a mapping to
+ * UCNV_EXT_MAX_UCHARS and UCNV_EXT_MAX_BYTES, respectively,
+ * which are output value limits in the data structure.
+ *
+ * For input, this is not strictly necessary - it is a hard limit only for the
+ * buffers in UConverter that are used to store partial matches.
+ *
+ * Input sequences could otherwise be arbitrarily long if partial matches
+ * need not be stored (i.e., if a sequence does not span several buffers with too
+ * many units before the last buffer), although then results would differ
+ * depending on whether partial matches exceed the limits or not,
+ * which depends on the pattern of buffer sizes.
+ *
+ *
+ * Data structure:
+ *
+ * int32_t indexes[>=32];
+ *
+ *   Array of indexes and lengths etc. The length of the array is at least 32.
+ *   The actual length is stored in indexes[0] to be forward compatible.
+ *
+ *   Each index to another array is the number of bytes from indexes[].
+ *   Each length of an array is the number of array base units in that array.
+ *
+ *   Some of the structures may not be present, in which case their indexes
+ *   and lengths are 0.
+ *
+ *   Usage of indexes[i]:
+ *   [0]  length of indexes[]
+ *
+ *   // to Unicode table
+ *   [1]  index of toUTable[] (array of uint32_t)
+ *   [2]  length of toUTable[]
+ *   [3]  index of toUUChars[] (array of UChar)
+ *   [4]  length of toUUChars[]
+ *
+ *   // from Unicode table, not for the initial code point
+ *   [5]  index of fromUTableUChars[] (array of UChar)
+ *   [6]  index of fromUTableValues[] (array of uint32_t)
+ *   [7]  length of fromUTableUChars[] and fromUTableValues[]
+ *   [8]  index of fromUBytes[] (array of char)
+ *   [9]  length of fromUBytes[]
+ *
+ *   // from Unicode trie for initial-code point lookup
+ *   [10] index of fromUStage12[] (combined array of uint16_t for stages 1 & 2)
+ *   [11] length of stage 1 portion of fromUStage12[]
+ *   [12] length of fromUStage12[]
+ *   [13] index of fromUStage3[] (array of uint16_t indexes into fromUStage3b[])
+ *   [14] length of fromUStage3[]
+ *   [15] index of fromUStage3b[] (array of uint32_t like fromUTableValues[])
+ *   [16] length of fromUStage3b[]
+ *
+ *   [17] Bit field containing numbers of bytes:
+ *        31..24 reserved, 0
+ *        23..16 maximum input bytes
+ *        15.. 8 maximum output bytes
+ *         7.. 0 maximum bytes per UChar
+ *
+ *   [18] Bit field containing numbers of UChars:
+ *        31..24 reserved, 0
+ *        23..16 maximum input UChars
+ *        15.. 8 maximum output UChars
+ *         7.. 0 maximum UChars per byte
+ *
+ *   [19] Bit field containing flags:
+ *               (extension table unicodeMask)
+ *         1     UCNV_HAS_SURROGATES flag for the extension table
+ *         0     UCNV_HAS_SUPPLEMENTARY flag for the extension table
+ *
+ *   [20]..[30] reserved, 0
+ *   [31] number of bytes for the entire extension structure
+ *   [>31] reserved; there are indexes[0] indexes
+ *
+ *
+ * uint32_t toUTable[];
+ *
+ *   Array of byte/value pairs for lookups for toUnicode conversion.
+ *   The array is partitioned into sections like collation contraction tables.
+ *   Each section contains one word with the number of following words and
+ *   a default value for when the lookup in this section yields no match.
+ *
+ *   A section is sorted in ascending order of input bytes,
+ *   allowing for fast linear or binary searches.
+ *   The builder may store entries for a contiguous range of byte values
+ *   (compare difference between the first and last one with count),
+ *   which then allows for direct array access.
+ *   The builder should always do this for the initial table section.
+ *
+ *   Entries may have 0 values, see below.
+ *   No two entries in a section have the same byte values.
+ *
+ *   Each uint32_t contains an input byte value in bits 31..24 and the
+ *   corresponding lookup value in bits 23..0.
+ *   Interpret the value as follows:
+ *     if(value==0) {
+ *       no match, see below
+ *     } else if(value<0x1f0000) {
+ *       partial match - use value as index to the next toUTable section
+ *       and match the next unit; (value indexes toUTable[value])
+ *     } else {
+ *       if(bit 23 set) {
+ *         roundtrip;
+ *       } else {
+ *         fallback;
+ *       }
+ *       unset value bit 23;
+ *       if(value<=0x2fffff) {
+ *         (value-0x1f0000) is a code point; (BMP: value<=0x1fffff)
+ *       } else {
+ *         bits 17..0 (value&0x3ffff) is an index to
+ *           the result UChars in toUUChars[]; (0 indexes toUUChars[0])
+ *         length of the result=((value>>18)-12); (length=0..19)
+ *       }
+ *     }
+ *
+ *   The first word in a section contains the number of following words in the
+ *   input byte position (bits 31..24, number=1..0xff).
+ *   The value of the initial word is used when the current byte is not found
+ *   in this section.
+ *   If the value is not 0, then it represents a result as above.
+ *   If the value is 0, then the search has to return a shorter match with an
+ *   earlier default value as the result, or result in "unmappable" even for the
+ *   initial bytes.
+ *   If the value is 0 for the initial toUTable entry, then the initial byte
+ *   does not start any mapping input.
+ *
+ *
+ * UChar toUUChars[];
+ *
+ *   Contains toUnicode mapping results, stored as sequences of UChars.
+ *   Indexes and lengths stored in the toUTable[].
+ *
+ *
+ * UChar fromUTableUChars[];
+ * uint32_t fromUTableValues[];
+ *
+ *   The fromUTable is split into two arrays, but works otherwise much like
+ *   the toUTable. The array is partitioned into sections like collation
+ *   contraction tables and toUTable.
+ *   A row in the table consists of same-index entries in fromUTableUChars[]
+ *   and fromUTableValues[].
+ *
+ *   Interpret a value as follows:
+ *     if(value==0) {
+ *       no match, see below
+ *     } else if(value<=0xffffff) { (bits 31..24 are 0)
+ *       partial match - use value as index to the next fromUTable section
+ *       and match the next unit; (value indexes fromUTable[value])
+ *     } else {
+ *       if(value==0x80000001) {
+ *         return no mapping, but request for <subchar1>;
+ *       }
+ *       if(bit 31 set) {
+ *         roundtrip;
+ *       } else {
+ *         fallback;
+ *       }
+ *       // bits 30..29 reserved, 0
+ *       length=(value>>24)&0x1f; (bits 28..24)
+ *       if(length==1..3) {
+ *         bits 23..0 contain 1..3 bytes, padded with 00s on the left;
+ *       } else {
+ *         bits 23..0 (value&0xffffff) is an index to
+ *           the result bytes in fromUBytes[]; (0 indexes fromUBytes[0])
+ *       }
+ *     }
+ *       
+ *   The first pair in a section contains the number of following pairs in the
+ *   UChar position (16 bits, number=1..0xffff).
+ *   The value of the initial pair is used when the current UChar is not found
+ *   in this section.
+ *   If the value is not 0, then it represents a result as above.
+ *   If the value is 0, then the search has to return a shorter match with an
+ *   earlier default value as the result, or result in "unmappable" even for the
+ *   initial UChars.
+ *
+ *   If the from Unicode trie is present, then the from Unicode search tables
+ *   are not used for initial code points.
+ *   In this case, the first entries (index 0) in the tables are not used
+ *   (reserved, set to 0) because a value of 0 is used in trie results
+ *   to indicate no mapping.
+ *
+ *
+ * uint16_t fromUStage12[];
+ *
+ *   Stages 1 & 2 of a trie that maps an initial code point.
+ *   Indexes in stage 1 are all offset by the length of stage 1 so that the
+ *   same array pointer can be used for both stages.
+ *   If (c>>10)>=(length of stage 1) then c does not start any mapping.
+ *   Same bit distribution as for regular conversion tries.
+ *
+ *
+ * uint16_t fromUStage3[];
+ * uint32_t fromUStage3b[];
+ *
+ *   Stage 3 of the trie. The first array simply contains indexes to the second,
+ *   which contains words in the same format as fromUTableValues[].
+ *   Use a stage 3 granularity of 4, which allows for 256k stage 3 entries,
+ *   and 16-bit entries in stage 3 allow for 64k stage 3b entries.
+ *   The stage 3 granularity means that the stage 2 entry needs to be left-shifted.
+ *
+ *   Two arrays are used because it is expected that more than half of the stage 3
+ *   entries will be zero. The 16-bit index stage 3 array saves space even
+ *   considering storing a total of 6 bytes per non-zero entry in both arrays
+ *   together.
+ *   Using a stage 3 granularity of >1 diminishes the compactability in that stage
+ *   but provides a larger effective addressing space in stage 2.
+ *   All but the final result stage use 16-bit entries to save space.
+ *
+ *   fromUStage3b[] contains a zero for "no mapping" at its index 0,
+ *   and may contain UCNV_EXT_FROM_U_SUBCHAR1 at index 1 for "<subchar1> SUB mapping"
+ *   (i.e., "no mapping" with preference for <subchar1> rather than <subchar>),
+ *   and all other items are unique non-zero results.
+ *
+ *   The default value of a fromUTableValues[] section that is referenced
+ *   _directly_ from a fromUStage3b[] item may also be UCNV_EXT_FROM_U_SUBCHAR1,
+ *   but this value must not occur anywhere else in fromUTableValues[]
+ *   because "no mapping" is always a property of a single code point,
+ *   never of multiple.
+ *
+ *
+ * char fromUBytes[];
+ *
+ *   Contains fromUnicode mapping results, stored as sequences of chars.
+ *   Indexes and lengths stored in the fromUTableValues[].
+ */
+enum {
+    UCNV_EXT_INDEXES_LENGTH,            /* 0 */
+
+    UCNV_EXT_TO_U_INDEX,                /* 1 */
+    UCNV_EXT_TO_U_LENGTH,
+    UCNV_EXT_TO_U_UCHARS_INDEX,
+    UCNV_EXT_TO_U_UCHARS_LENGTH,
+
+    UCNV_EXT_FROM_U_UCHARS_INDEX,       /* 5 */
+    UCNV_EXT_FROM_U_VALUES_INDEX,
+    UCNV_EXT_FROM_U_LENGTH,
+    UCNV_EXT_FROM_U_BYTES_INDEX,
+    UCNV_EXT_FROM_U_BYTES_LENGTH,
+
+    UCNV_EXT_FROM_U_STAGE_12_INDEX,     /* 10 */
+    UCNV_EXT_FROM_U_STAGE_1_LENGTH,
+    UCNV_EXT_FROM_U_STAGE_12_LENGTH,
+    UCNV_EXT_FROM_U_STAGE_3_INDEX,
+    UCNV_EXT_FROM_U_STAGE_3_LENGTH,
+    UCNV_EXT_FROM_U_STAGE_3B_INDEX,
+    UCNV_EXT_FROM_U_STAGE_3B_LENGTH,
+
+    UCNV_EXT_COUNT_BYTES,               /* 17 */
+    UCNV_EXT_COUNT_UCHARS,
+    UCNV_EXT_FLAGS,
+
+    UCNV_EXT_RESERVED_INDEX,            /* 20, moves with additional indexes */
+
+    UCNV_EXT_SIZE=31,
+    UCNV_EXT_INDEXES_MIN_LENGTH=32
+};
+
+/* get the pointer to an extension array from indexes[index] */
+#define UCNV_EXT_ARRAY(indexes, index, itemType) \
+    ((const itemType *)((const char *)(indexes)+(indexes)[index]))
+
+#define UCNV_GET_MAX_BYTES_PER_UCHAR(indexes) \
+    ((indexes)[UCNV_EXT_COUNT_BYTES]&0xff)
+
+/* internal API ------------------------------------------------------------- */
+
+U_CFUNC UBool
+ucnv_extInitialMatchToU(UConverter *cnv, const int32_t *cx,
+                        int32_t firstLength,
+                        const char **src, const char *srcLimit,
+                        UChar **target, const UChar *targetLimit,
+                        int32_t **offsets, int32_t srcIndex,
+                        UBool flush,
+                        UErrorCode *pErrorCode);
+
+U_CFUNC UChar32
+ucnv_extSimpleMatchToU(const int32_t *cx,
+                       const char *source, int32_t length,
+                       UBool useFallback);
+
+U_CFUNC void
+ucnv_extContinueMatchToU(UConverter *cnv,
+                         UConverterToUnicodeArgs *pArgs, int32_t srcIndex,
+                         UErrorCode *pErrorCode);
+
+
+U_CFUNC UBool
+ucnv_extInitialMatchFromU(UConverter *cnv, const int32_t *cx,
+                          UChar32 cp,
+                          const UChar **src, const UChar *srcLimit,
+                          char **target, const char *targetLimit,
+                          int32_t **offsets, int32_t srcIndex,
+                          UBool flush,
+                          UErrorCode *pErrorCode);
+
+U_CFUNC int32_t
+ucnv_extSimpleMatchFromU(const int32_t *cx,
+                         UChar32 cp, uint32_t *pValue,
+                         UBool useFallback);
+
+U_CFUNC void
+ucnv_extContinueMatchFromU(UConverter *cnv,
+                           UConverterFromUnicodeArgs *pArgs, int32_t srcIndex,
+                           UErrorCode *pErrorCode);
+
+/*
+ * Add code points and strings to the set according to the extension mappings.
+ * Limitation on the UConverterSetFilter:
+ * The filters currently assume that they are used with 1:1 mappings.
+ * They only apply to single input code points, and then they pass through
+ * only mappings with single-charset-code results.
+ * For example, the Shift-JIS filter only works for 2-byte results and tests
+ * that those 2 bytes are in the JIS X 0208 range of Shift-JIS.
+ */
+U_CFUNC void
+ucnv_extGetUnicodeSet(const UConverterSharedData *sharedData,
+                      const USetAdder *sa,
+                      UConverterUnicodeSet which,
+                      UConverterSetFilter filter,
+                      UErrorCode *pErrorCode);
+
+/* toUnicode helpers -------------------------------------------------------- */
+
+#define UCNV_EXT_TO_U_BYTE_SHIFT 24
+#define UCNV_EXT_TO_U_VALUE_MASK 0xffffff
+#define UCNV_EXT_TO_U_MIN_CODE_POINT 0x1f0000
+#define UCNV_EXT_TO_U_MAX_CODE_POINT 0x2fffff
+#define UCNV_EXT_TO_U_ROUNDTRIP_FLAG ((uint32_t)1<<23)
+#define UCNV_EXT_TO_U_INDEX_MASK 0x3ffff
+#define UCNV_EXT_TO_U_LENGTH_SHIFT 18
+#define UCNV_EXT_TO_U_LENGTH_OFFSET 12
+
+/* maximum number of indexed UChars */
+#define UCNV_EXT_MAX_UCHARS 19
+
+#define UCNV_EXT_TO_U_MAKE_WORD(byte, value) (((uint32_t)(byte)<<UCNV_EXT_TO_U_BYTE_SHIFT)|(value))
+
+#define UCNV_EXT_TO_U_GET_BYTE(word) ((word)>>UCNV_EXT_TO_U_BYTE_SHIFT)
+#define UCNV_EXT_TO_U_GET_VALUE(word) ((word)&UCNV_EXT_TO_U_VALUE_MASK)
+
+#define UCNV_EXT_TO_U_IS_PARTIAL(value) ((value)<UCNV_EXT_TO_U_MIN_CODE_POINT)
+#define UCNV_EXT_TO_U_GET_PARTIAL_INDEX(value) (value)
+
+#define UCNV_EXT_TO_U_IS_ROUNDTRIP(value) (((value)&UCNV_EXT_TO_U_ROUNDTRIP_FLAG)!=0)
+#define UCNV_EXT_TO_U_MASK_ROUNDTRIP(value) ((value)&~UCNV_EXT_TO_U_ROUNDTRIP_FLAG)
+
+/* use after masking off the roundtrip flag */
+#define UCNV_EXT_TO_U_IS_CODE_POINT(value) ((value)<=UCNV_EXT_TO_U_MAX_CODE_POINT)
+#define UCNV_EXT_TO_U_GET_CODE_POINT(value) ((value)-UCNV_EXT_TO_U_MIN_CODE_POINT)
+
+#define UCNV_EXT_TO_U_GET_INDEX(value) ((value)&UCNV_EXT_TO_U_INDEX_MASK)
+#define UCNV_EXT_TO_U_GET_LENGTH(value) (((value)>>UCNV_EXT_TO_U_LENGTH_SHIFT)-UCNV_EXT_TO_U_LENGTH_OFFSET)
+
+/* fromUnicode helpers ------------------------------------------------------ */
+
+/* most trie constants are shared with ucnvmbcs.h */
+
+/* see similar utrie.h UTRIE_INDEX_SHIFT and UTRIE_DATA_GRANULARITY */
+#define UCNV_EXT_STAGE_2_LEFT_SHIFT 2
+#define UCNV_EXT_STAGE_3_GRANULARITY 4
+
+/* trie access, returns the stage 3 value=index to stage 3b; s1Index=c>>10 */
+#define UCNV_EXT_FROM_U(stage12, stage3, s1Index, c) \
+    (stage3)[ ((int32_t)(stage12)[ (stage12)[s1Index] +(((c)>>4)&0x3f) ]<<UCNV_EXT_STAGE_2_LEFT_SHIFT) +((c)&0xf) ]
+
+#define UCNV_EXT_FROM_U_LENGTH_SHIFT 24
+#define UCNV_EXT_FROM_U_ROUNDTRIP_FLAG ((uint32_t)1<<31)
+#define UCNV_EXT_FROM_U_RESERVED_MASK 0x60000000
+#define UCNV_EXT_FROM_U_DATA_MASK 0xffffff
+
+/* special value for "no mapping" to <subchar1> (impossible roundtrip to 0 bytes, value 01) */
+#define UCNV_EXT_FROM_U_SUBCHAR1 0x80000001
+
+/* at most 3 bytes in the lower part of the value */
+#define UCNV_EXT_FROM_U_MAX_DIRECT_LENGTH 3
+
+/* maximum number of indexed bytes */
+#define UCNV_EXT_MAX_BYTES 0x1f
+
+#define UCNV_EXT_FROM_U_IS_PARTIAL(value) (((value)>>UCNV_EXT_FROM_U_LENGTH_SHIFT)==0)
+#define UCNV_EXT_FROM_U_GET_PARTIAL_INDEX(value) (value)
+
+#define UCNV_EXT_FROM_U_IS_ROUNDTRIP(value) (((value)&UCNV_EXT_FROM_U_ROUNDTRIP_FLAG)!=0)
+#define UCNV_EXT_FROM_U_MASK_ROUNDTRIP(value) ((value)&~UCNV_EXT_FROM_U_ROUNDTRIP_FLAG)
+
+/* get length; masks away all other bits */
+#define UCNV_EXT_FROM_U_GET_LENGTH(value) (int32_t)(((value)>>UCNV_EXT_FROM_U_LENGTH_SHIFT)&UCNV_EXT_MAX_BYTES)
+
+/* get bytes or bytes index */
+#define UCNV_EXT_FROM_U_GET_DATA(value) ((value)&UCNV_EXT_FROM_U_DATA_MASK)
+
+#endif
+
+#endif
diff --git a/source/common/ucnv_imp.h b/source/common/ucnv_imp.h
new file mode 100644
index 0000000..54b0197
--- /dev/null
+++ b/source/common/ucnv_imp.h
@@ -0,0 +1,136 @@
+/*
+**********************************************************************
+*   Copyright (C) 1999-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*
+*
+*  ucnv_imp.h:
+*  Contains all internal and external data structure definitions
+* Created & Maitained by Bertrand A. Damiba
+*
+*
+*
+* ATTENTION:
+* ---------
+* Although the data structures in this file are open and stack allocatable
+* we reserve the right to hide them in further releases.
+*/
+
+#ifndef UCNV_IMP_H
+#define UCNV_IMP_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/uloc.h"
+#include "ucnv_bld.h"
+
+/*
+ * Fast check for whether a charset name is "UTF-8".
+ * This does not recognize all of the variations that ucnv_open()
+ * and other functions recognize, but it covers most cases.
+ * @param name const char * charset name
+ * @return
+ */
+#define UCNV_FAST_IS_UTF8(name) \
+    (((name[0]=='U' ? \
+      (                name[1]=='T' && name[2]=='F') : \
+      (name[0]=='u' && name[1]=='t' && name[2]=='f'))) \
+  && (name[3]=='-' ? \
+     (name[4]=='8' && name[5]==0) : \
+     (name[3]=='8' && name[4]==0)))
+
+typedef struct {
+    char cnvName[UCNV_MAX_CONVERTER_NAME_LENGTH];
+    char locale[ULOC_FULLNAME_CAPACITY];
+    uint32_t options;
+} UConverterNamePieces;
+
+U_CFUNC UBool
+ucnv_canCreateConverter(const char *converterName, UErrorCode *err);
+
+/* figures out if we need to go to file to read in the data tables.
+ * @param converterName The name of the converter
+ * @param err The error code
+ * @return the newly created converter
+ */
+UConverter *ucnv_createConverter (UConverter *myUConverter, const char *converterName, UErrorCode * err);
+
+/*
+ * Open a purely algorithmic converter, specified by a type constant.
+ * @param myUConverter  NULL, or pre-allocated UConverter structure to avoid
+ *                      a memory allocation
+ * @param type          requested converter type
+ * @param locale        locale parameter, or ""
+ * @param options       converter options bit set (default 0)
+ * @param err           ICU error code, not tested for U_FAILURE on input
+ *                      because this is an internal function
+ * @internal
+ */
+U_CFUNC UConverter *
+ucnv_createAlgorithmicConverter(UConverter *myUConverter,
+                                UConverterType type,
+                                const char *locale, uint32_t options,
+                                UErrorCode *err);
+
+/*
+ * Creates a converter from shared data.
+ * Adopts mySharedConverterData: No matter what happens, the caller must not
+ * unload mySharedConverterData, except via ucnv_close(return value)
+ * if this function is successful.
+ */
+UConverter*
+ucnv_createConverterFromSharedData(UConverter *myUConverter,
+                                   UConverterSharedData *mySharedConverterData,
+                                   UConverterLoadArgs *pArgs,
+                                   UErrorCode *err);
+
+UConverter* ucnv_createConverterFromPackage(const char *packageName, const char *converterName,  
+                                            UErrorCode *err);
+
+/**
+ * Load a converter but do not create a UConverter object.
+ * Simply return the UConverterSharedData.
+ * Performs alias lookup etc.
+ * The UConverterNamePieces need not be initialized
+ * before calling this function.
+ * The UConverterLoadArgs must be initialized
+ * before calling this function.
+ * If the args are passed in, then the pieces must be passed in too.
+ * In other words, the following combinations are allowed:
+ * - pieces==NULL && args==NULL
+ * - pieces!=NULL && args==NULL
+ * - pieces!=NULL && args!=NULL
+ * @internal
+ */
+UConverterSharedData *
+ucnv_loadSharedData(const char *converterName,
+                    UConverterNamePieces *pieces,
+                    UConverterLoadArgs *pArgs,
+                    UErrorCode * err);
+
+/**
+ * This may unload the shared data in a thread safe manner.
+ * This will only unload the data if no other converters are sharing it.
+ */
+void
+ucnv_unloadSharedDataIfReady(UConverterSharedData *sharedData);
+
+/**
+ * This is a thread safe way to increment the reference count.
+ */
+void
+ucnv_incrementRefCount(UConverterSharedData *sharedData);
+
+/**
+ * These are the default error handling callbacks for the charset conversion framework.
+ * For performance reasons, they are only called to handle an error (not normally called for a reset or close).
+ */
+#define UCNV_TO_U_DEFAULT_CALLBACK ((UConverterToUCallback) UCNV_TO_U_CALLBACK_SUBSTITUTE)
+#define UCNV_FROM_U_DEFAULT_CALLBACK ((UConverterFromUCallback) UCNV_FROM_U_CALLBACK_SUBSTITUTE)
+
+#endif
+
+#endif /* _UCNV_IMP */
diff --git a/source/common/ucnv_io.c b/source/common/ucnv_io.c
new file mode 100644
index 0000000..3b806d1
--- /dev/null
+++ b/source/common/ucnv_io.c
@@ -0,0 +1,1341 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2008, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+*
+*  ucnv_io.c:
+*  initializes global variables and defines functions pertaining to converter 
+*  name resolution aspect of the conversion code.
+*
+*   new implementation:
+*
+*   created on: 1999nov22
+*   created by: Markus W. Scherer
+*
+*   Use the binary cnvalias.icu (created from convrtrs.txt) to work
+*   with aliases for converter names.
+*
+*   Date        Name        Description
+*   11/22/1999  markus      Created
+*   06/28/2002  grhoten     Major overhaul of the converter alias design.
+*                           Now an alias can map to different converters
+*                           depending on the specified standard.
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ucnv.h"
+#include "unicode/udata.h"
+
+#include "umutex.h"
+#include "uarrsort.h"
+#include "udataswp.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include "ucnv_io.h"
+#include "uenumimp.h"
+#include "ucln_cmn.h"
+
+/* Format of cnvalias.icu -----------------------------------------------------
+ *
+ * cnvalias.icu is a binary, memory-mappable form of convrtrs.txt.
+ * This binary form contains several tables. All indexes are to uint16_t
+ * units, and not to the bytes (uint8_t units). Addressing everything on
+ * 16-bit boundaries allows us to store more information with small index
+ * numbers, which are also 16-bit in size. The majority of the table (except
+ * the string table) are 16-bit numbers.
+ *
+ * First there is the size of the Table of Contents (TOC). The TOC
+ * entries contain the size of each section. In order to find the offset
+ * you just need to sum up the previous offsets.
+ * The TOC length and entries are an array of uint32_t values.
+ * The first section after the TOC starts immediately after the TOC.
+ *
+ * 1) This section contains a list of converters. This list contains indexes
+ * into the string table for the converter name. The index of this list is
+ * also used by other sections, which are mentioned later on.
+ * This list is not sorted.
+ *
+ * 2) This section contains a list of tags. This list contains indexes
+ * into the string table for the tag name. The index of this list is
+ * also used by other sections, which are mentioned later on.
+ * This list is in priority order of standards.
+ *
+ * 3) This section contains a list of sorted unique aliases. This
+ * list contains indexes into the string table for the alias name. The
+ * index of this list is also used by other sections, like the 4th section.
+ * The index for the 3rd and 4th section is used to get the
+ * alias -> converter name mapping. Section 3 and 4 form a two column table.
+ * Some of the most significant bits of each index may contain other
+ * information (see findConverter for details).
+ *
+ * 4) This section contains a list of mapped converter names. Consider this
+ * as a table that maps the 3rd section to the 1st section. This list contains
+ * indexes into the 1st section. The index of this list is the same index in
+ * the 3rd section. There is also some extra information in the high bits of
+ * each converter index in this table. Currently it's only used to say that
+ * an alias mapped to this converter is ambiguous. See UCNV_CONVERTER_INDEX_MASK
+ * and UCNV_AMBIGUOUS_ALIAS_MAP_BIT for more information. This section is
+ * the predigested form of the 5th section so that an alias lookup can be fast.
+ *
+ * 5) This section contains a 2D array with indexes to the 6th section. This
+ * section is the full form of all alias mappings. The column index is the
+ * index into the converter list (column header). The row index is the index
+ * to tag list (row header). This 2D array is the top part a 3D array. The
+ * third dimension is in the 6th section.
+ *
+ * 6) This is blob of variable length arrays. Each array starts with a size,
+ * and is followed by indexes to alias names in the string table. This is
+ * the third dimension to the section 5. No other section should be referencing
+ * this section.
+ *
+ * 7) Starting in ICU 3.6, this can be a UConverterAliasOptions struct. Its
+ * presence indicates that a section 9 exists. UConverterAliasOptions specifies
+ * what type of string normalization is used among other potential things in the
+ * future.
+ *
+ * 8) This is the string table. All strings are indexed on an even address.
+ * There are two reasons for this. First many chip architectures locate strings
+ * faster on even address boundaries. Second, since all indexes are 16-bit
+ * numbers, this string table can be 128KB in size instead of 64KB when we
+ * only have strings starting on an even address.
+ *
+ * 9) When present this is a set of prenormalized strings from section 8. This
+ * table contains normalized strings with the dashes and spaces stripped out,
+ * and all strings lowercased. In the future, the options in section 7 may state
+ * other types of normalization.
+ *
+ * Here is the concept of section 5 and 6. It's a 3D cube. Each tag
+ * has a unique alias among all converters. That same alias can
+ * be mentioned in other standards on different converters,
+ * but only one alias per tag can be unique.
+ *
+ *
+ *              Converter Names (Usually in TR22 form)
+ *           -------------------------------------------.
+ *     T    /                                          /|
+ *     a   /                                          / |
+ *     g  /                                          /  |
+ *     s /                                          /   |
+ *      /                                          /    |
+ *      ------------------------------------------/     |
+ *    A |                                         |     |
+ *    l |                                         |     |
+ *    i |                                         |    /
+ *    a |                                         |   /
+ *    s |                                         |  /
+ *    e |                                         | /
+ *    s |                                         |/
+ *      -------------------------------------------
+ *
+ *
+ *
+ * Here is what it really looks like. It's like swiss cheese.
+ * There are holes. Some converters aren't recognized by
+ * a standard, or they are really old converters that the
+ * standard doesn't recognize anymore.
+ *
+ *              Converter Names (Usually in TR22 form)
+ *           -------------------------------------------.
+ *     T    /##########################################/|
+ *     a   /     #            #                       /#
+ *     g  /  #      ##     ##     ### # ### ### ### #/
+ *     s / #             #####  ####        ##  ## #/#
+ *      / ### # # ##  #  #   #          ### # #   #/##
+ *      ------------------------------------------/# #
+ *    A |### # # ##  #  #   #          ### # #   #|# #
+ *    l |# # #    #     #               ## #     #|# #
+ *    i |# # #    #     #                #       #|#
+ *    a |#                                       #|#
+ *    s |                                        #|#
+ *    e
+ *    s
+ *
+ */
+
+/**
+ * Used by the UEnumeration API
+ */
+typedef struct UAliasContext {
+    uint32_t listOffset;
+    uint32_t listIdx;
+} UAliasContext;
+
+static const char DATA_NAME[] = "cnvalias";
+static const char DATA_TYPE[] = "icu";
+
+static UDataMemory *gAliasData=NULL;
+
+enum {
+    tocLengthIndex=0,
+    converterListIndex=1,
+    tagListIndex=2,
+    aliasListIndex=3,
+    untaggedConvArrayIndex=4,
+    taggedAliasArrayIndex=5,
+    taggedAliasListsIndex=6,
+    tableOptionsIndex=7,
+    stringTableIndex=8,
+    normalizedStringTableIndex=9,
+    offsetsCount,    /* length of the swapper's temporary offsets[] */
+    minTocLength=8 /* min. tocLength in the file, does not count the tocLengthIndex! */
+};
+
+static const UConverterAliasOptions defaultTableOptions = {
+    UCNV_IO_UNNORMALIZED,
+    0 /* containsCnvOptionInfo */
+};
+static UConverterAlias gMainTable;
+
+#define GET_STRING(idx) (const char *)(gMainTable.stringTable + (idx))
+#define GET_NORMALIZED_STRING(idx) (const char *)(gMainTable.normalizedStringTable + (idx))
+
+static UBool U_CALLCONV
+isAcceptable(void *context,
+             const char *type, const char *name,
+             const UDataInfo *pInfo) {
+    return (UBool)(
+        pInfo->size>=20 &&
+        pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
+        pInfo->charsetFamily==U_CHARSET_FAMILY &&
+        pInfo->dataFormat[0]==0x43 &&   /* dataFormat="CvAl" */
+        pInfo->dataFormat[1]==0x76 &&
+        pInfo->dataFormat[2]==0x41 &&
+        pInfo->dataFormat[3]==0x6c &&
+        pInfo->formatVersion[0]==3);
+}
+
+static UBool U_CALLCONV ucnv_io_cleanup(void)
+{
+    if (gAliasData) {
+        udata_close(gAliasData);
+        gAliasData = NULL;
+    }
+
+    uprv_memset(&gMainTable, 0, sizeof(gMainTable));
+
+    return TRUE;                   /* Everything was cleaned up */
+}
+
+static UBool
+haveAliasData(UErrorCode *pErrorCode) {
+    int needInit;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return FALSE;
+    }
+
+    UMTX_CHECK(NULL, (gAliasData==NULL), needInit);
+
+    /* load converter alias data from file if necessary */
+    if (needInit) {
+        UDataMemory *data;
+        const uint16_t *table;
+        const uint32_t *sectionSizes;
+        uint32_t tableStart;
+        uint32_t currOffset;
+
+        data = udata_openChoice(NULL, DATA_TYPE, DATA_NAME, isAcceptable, NULL, pErrorCode);
+        if(U_FAILURE(*pErrorCode)) {
+            return FALSE;
+        }
+
+        sectionSizes = (const uint32_t *)udata_getMemory(data);
+        table = (const uint16_t *)sectionSizes;
+
+        tableStart      = sectionSizes[0];
+        if (tableStart < minTocLength) {
+            *pErrorCode = U_INVALID_FORMAT_ERROR;
+            udata_close(data);
+            return FALSE;
+        }
+
+        umtx_lock(NULL);
+        if(gAliasData==NULL) {
+            gMainTable.converterListSize      = sectionSizes[1];
+            gMainTable.tagListSize            = sectionSizes[2];
+            gMainTable.aliasListSize          = sectionSizes[3];
+            gMainTable.untaggedConvArraySize  = sectionSizes[4];
+            gMainTable.taggedAliasArraySize   = sectionSizes[5];
+            gMainTable.taggedAliasListsSize   = sectionSizes[6];
+            gMainTable.optionTableSize        = sectionSizes[7];
+            gMainTable.stringTableSize        = sectionSizes[8];
+
+            if (tableStart > 8) {
+                gMainTable.normalizedStringTableSize = sectionSizes[9];
+            }
+
+            currOffset = tableStart * (sizeof(uint32_t)/sizeof(uint16_t)) + (sizeof(uint32_t)/sizeof(uint16_t));
+            gMainTable.converterList = table + currOffset;
+
+            currOffset += gMainTable.converterListSize;
+            gMainTable.tagList = table + currOffset;
+
+            currOffset += gMainTable.tagListSize;
+            gMainTable.aliasList = table + currOffset;
+
+            currOffset += gMainTable.aliasListSize;
+            gMainTable.untaggedConvArray = table + currOffset;
+
+            currOffset += gMainTable.untaggedConvArraySize;
+            gMainTable.taggedAliasArray = table + currOffset;
+
+            /* aliasLists is a 1's based array, but it has a padding character */
+            currOffset += gMainTable.taggedAliasArraySize;
+            gMainTable.taggedAliasLists = table + currOffset;
+
+            currOffset += gMainTable.taggedAliasListsSize;
+            if (gMainTable.optionTableSize > 0
+                && ((const UConverterAliasOptions *)(table + currOffset))->stringNormalizationType < UCNV_IO_NORM_TYPE_COUNT)
+            {
+                /* Faster table */
+                gMainTable.optionTable = (const UConverterAliasOptions *)(table + currOffset);
+            }
+            else {
+                /* Smaller table, or I can't handle this normalization mode!
+                Use the original slower table lookup. */
+                gMainTable.optionTable = &defaultTableOptions;
+            }
+
+            currOffset += gMainTable.optionTableSize;
+            gMainTable.stringTable = table + currOffset;
+
+            currOffset += gMainTable.stringTableSize;
+            gMainTable.normalizedStringTable = ((gMainTable.optionTable->stringNormalizationType == UCNV_IO_UNNORMALIZED)
+                ? gMainTable.stringTable : (table + currOffset));
+
+            ucln_common_registerCleanup(UCLN_COMMON_UCNV_IO, ucnv_io_cleanup);
+
+            gAliasData = data;
+            data=NULL;
+        }
+        umtx_unlock(NULL);
+
+        /* if a different thread set it first, then close the extra data */
+        if(data!=NULL) {
+            udata_close(data); /* NULL if it was set correctly */
+        }
+    }
+
+    return TRUE;
+}
+
+static U_INLINE UBool
+isAlias(const char *alias, UErrorCode *pErrorCode) {
+    if(alias==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return FALSE;
+    }
+    return (UBool)(*alias!=0);
+}
+
+static uint32_t getTagNumber(const char *tagname) {
+    if (gMainTable.tagList) {
+        uint32_t tagNum;
+        for (tagNum = 0; tagNum < gMainTable.tagListSize; tagNum++) {
+            if (!uprv_stricmp(GET_STRING(gMainTable.tagList[tagNum]), tagname)) {
+                return tagNum;
+            }
+        }
+    }
+
+    return UINT32_MAX;
+}
+
+/* character types relevant for ucnv_compareNames() */
+enum {
+    IGNORE,
+    ZERO,
+    NONZERO,
+    MINLETTER /* any values from here on are lowercase letter mappings */
+};
+
+/* character types for ASCII 00..7F */
+static const uint8_t asciiTypes[128] = {
+    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,
+    ZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, 0, 0, 0, 0, 0, 0,
+    0, 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, 0, 0, 0, 0, 0,
+    0, 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, 0, 0, 0, 0, 0
+};
+
+#define GET_ASCII_TYPE(c) ((int8_t)(c) >= 0 ? asciiTypes[(uint8_t)c] : (uint8_t)IGNORE)
+
+/* character types for EBCDIC 80..FF */
+static const uint8_t ebcdicTypes[128] = {
+    0,    0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0, 0, 0, 0, 0, 0,
+    0,    0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0, 0, 0, 0, 0, 0,
+    0,    0,    0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,    0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0, 0, 0, 0, 0, 0,
+    0,    0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0, 0, 0, 0, 0, 0,
+    0,    0,    0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0, 0, 0, 0, 0, 0,
+    ZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, NONZERO, 0, 0, 0, 0, 0, 0
+};
+
+#define GET_EBCDIC_TYPE(c) ((int8_t)(c) < 0 ? ebcdicTypes[(c)&0x7f] : (uint8_t)IGNORE)
+
+#if U_CHARSET_FAMILY==U_ASCII_FAMILY
+#   define GET_CHAR_TYPE(c) GET_ASCII_TYPE(c)
+#elif U_CHARSET_FAMILY==U_EBCDIC_FAMILY
+#   define GET_CHAR_TYPE(c) GET_EBCDIC_TYPE(c)
+#else
+#   error U_CHARSET_FAMILY is not valid
+#endif
+
+/* @see ucnv_compareNames */
+U_CFUNC char * U_EXPORT2
+ucnv_io_stripASCIIForCompare(char *dst, const char *name) {
+    char *dstItr = dst;
+    uint8_t type, nextType;
+    char c1;
+    UBool afterDigit = FALSE;
+
+    while ((c1 = *name++) != 0) {
+        type = GET_ASCII_TYPE(c1);
+        switch (type) {
+        case IGNORE:
+            afterDigit = FALSE;
+            continue; /* ignore all but letters and digits */
+        case ZERO:
+            if (!afterDigit) {
+                nextType = GET_ASCII_TYPE(*name);
+                if (nextType == ZERO || nextType == NONZERO) {
+                    continue; /* ignore leading zero before another digit */
+                }
+            }
+            break;
+        case NONZERO:
+            afterDigit = TRUE;
+            break;
+        default:
+            c1 = (char)type; /* lowercased letter */
+            afterDigit = FALSE;
+            break;
+        }
+        *dstItr++ = c1;
+    }
+    *dstItr = 0;
+    return dst;
+}
+
+U_CFUNC char * U_EXPORT2
+ucnv_io_stripEBCDICForCompare(char *dst, const char *name) {
+    char *dstItr = dst;
+    uint8_t type, nextType;
+    char c1;
+    UBool afterDigit = FALSE;
+
+    while ((c1 = *name++) != 0) {
+        type = GET_EBCDIC_TYPE(c1);
+        switch (type) {
+        case IGNORE:
+            afterDigit = FALSE;
+            continue; /* ignore all but letters and digits */
+        case ZERO:
+            if (!afterDigit) {
+                nextType = GET_EBCDIC_TYPE(*name);
+                if (nextType == ZERO || nextType == NONZERO) {
+                    continue; /* ignore leading zero before another digit */
+                }
+            }
+            break;
+        case NONZERO:
+            afterDigit = TRUE;
+            break;
+        default:
+            c1 = (char)type; /* lowercased letter */
+            afterDigit = FALSE;
+            break;
+        }
+        *dstItr++ = c1;
+    }
+    *dstItr = 0;
+    return dst;
+}
+
+/**
+ * Do a fuzzy compare of two converter/alias names.
+ * The comparison is case-insensitive, ignores leading zeroes if they are not
+ * followed by further digits, and ignores all but letters and digits.
+ * Thus the strings "UTF-8", "utf_8", "u*T@f08" and "Utf 8" are exactly equivalent.
+ * See section 1.4, Charset Alias Matching in Unicode Technical Standard #22
+ * at http://www.unicode.org/reports/tr22/
+ *
+ * This is a symmetrical (commutative) operation; order of arguments
+ * is insignificant.  This is an important property for sorting the
+ * list (when the list is preprocessed into binary form) and for
+ * performing binary searches on it at run time.
+ *
+ * @param name1 a converter name or alias, zero-terminated
+ * @param name2 a converter name or alias, zero-terminated
+ * @return 0 if the names match, or a negative value if the name1
+ * lexically precedes name2, or a positive value if the name1
+ * lexically follows name2.
+ *
+ * @see ucnv_io_stripForCompare
+ */
+U_CAPI int U_EXPORT2
+ucnv_compareNames(const char *name1, const char *name2) {
+    int rc;
+    uint8_t type, nextType;
+    char c1, c2;
+    UBool afterDigit1 = FALSE, afterDigit2 = FALSE;
+
+    for (;;) {
+        while ((c1 = *name1++) != 0) {
+            type = GET_CHAR_TYPE(c1);
+            switch (type) {
+            case IGNORE:
+                afterDigit1 = FALSE;
+                continue; /* ignore all but letters and digits */
+            case ZERO:
+                if (!afterDigit1) {
+                    nextType = GET_CHAR_TYPE(*name1);
+                    if (nextType == ZERO || nextType == NONZERO) {
+                        continue; /* ignore leading zero before another digit */
+                    }
+                }
+                break;
+            case NONZERO:
+                afterDigit1 = TRUE;
+                break;
+            default:
+                c1 = (char)type; /* lowercased letter */
+                afterDigit1 = FALSE;
+                break;
+            }
+            break; /* deliver c1 */
+        }
+        while ((c2 = *name2++) != 0) {
+            type = GET_CHAR_TYPE(c2);
+            switch (type) {
+            case IGNORE:
+                afterDigit2 = FALSE;
+                continue; /* ignore all but letters and digits */
+            case ZERO:
+                if (!afterDigit2) {
+                    nextType = GET_CHAR_TYPE(*name2);
+                    if (nextType == ZERO || nextType == NONZERO) {
+                        continue; /* ignore leading zero before another digit */
+                    }
+                }
+                break;
+            case NONZERO:
+                afterDigit2 = TRUE;
+                break;
+            default:
+                c2 = (char)type; /* lowercased letter */
+                afterDigit2 = FALSE;
+                break;
+            }
+            break; /* deliver c2 */
+        }
+
+        /* If we reach the ends of both strings then they match */
+        if ((c1|c2)==0) {
+            return 0;
+        }
+
+        /* Case-insensitive comparison */
+        rc = (int)(unsigned char)c1 - (int)(unsigned char)c2;
+        if (rc != 0) {
+            return rc;
+        }
+    }
+}
+
+/*
+ * search for an alias
+ * return the converter number index for gConverterList
+ */
+static U_INLINE uint32_t
+findConverter(const char *alias, UBool *containsOption, UErrorCode *pErrorCode) {
+    uint32_t mid, start, limit;
+    uint32_t lastMid;
+    int result;
+    int isUnnormalized = (gMainTable.optionTable->stringNormalizationType == UCNV_IO_UNNORMALIZED);
+    char strippedName[UCNV_MAX_CONVERTER_NAME_LENGTH];
+
+    if (!isUnnormalized) {
+        if (uprv_strlen(alias) >= UCNV_MAX_CONVERTER_NAME_LENGTH) {
+            *pErrorCode = U_BUFFER_OVERFLOW_ERROR;
+            return UINT32_MAX;
+        }
+
+        /* Lower case and remove ignoreable characters. */
+        ucnv_io_stripForCompare(strippedName, alias);
+        alias = strippedName;
+    }
+
+    /* do a binary search for the alias */
+    start = 0;
+    limit = gMainTable.untaggedConvArraySize;
+    mid = limit;
+    lastMid = UINT32_MAX;
+
+    for (;;) {
+        mid = (uint32_t)((start + limit) / 2);
+        if (lastMid == mid) {   /* Have we moved? */
+            break;  /* We haven't moved, and it wasn't found. */
+        }
+        lastMid = mid;
+        if (isUnnormalized) {
+            result = ucnv_compareNames(alias, GET_STRING(gMainTable.aliasList[mid]));
+        }
+        else {
+            result = uprv_strcmp(alias, GET_NORMALIZED_STRING(gMainTable.aliasList[mid]));
+        }
+
+        if (result < 0) {
+            limit = mid;
+        } else if (result > 0) {
+            start = mid;
+        } else {
+            /* Since the gencnval tool folds duplicates into one entry,
+             * this alias in gAliasList is unique, but different standards
+             * may map an alias to different converters.
+             */
+            if (gMainTable.untaggedConvArray[mid] & UCNV_AMBIGUOUS_ALIAS_MAP_BIT) {
+                *pErrorCode = U_AMBIGUOUS_ALIAS_WARNING;
+            }
+            /* State whether the canonical converter name contains an option.
+            This information is contained in this list in order to maintain backward & forward compatibility. */
+            if (containsOption) {
+                UBool containsCnvOptionInfo = (UBool)gMainTable.optionTable->containsCnvOptionInfo;
+                *containsOption = (UBool)((containsCnvOptionInfo
+                    && ((gMainTable.untaggedConvArray[mid] & UCNV_CONTAINS_OPTION_BIT) != 0))
+                    || !containsCnvOptionInfo);
+            }
+            return gMainTable.untaggedConvArray[mid] & UCNV_CONVERTER_INDEX_MASK;
+        }
+    }
+
+    return UINT32_MAX;
+}
+
+/*
+ * Is this alias in this list?
+ * alias and listOffset should be non-NULL.
+ */
+static U_INLINE UBool
+isAliasInList(const char *alias, uint32_t listOffset) {
+    if (listOffset) {
+        uint32_t currAlias;
+        uint32_t listCount = gMainTable.taggedAliasLists[listOffset];
+        /* +1 to skip listCount */
+        const uint16_t *currList = gMainTable.taggedAliasLists + listOffset + 1;
+        for (currAlias = 0; currAlias < listCount; currAlias++) {
+            if (currList[currAlias]
+                && ucnv_compareNames(alias, GET_STRING(currList[currAlias]))==0)
+            {
+                return TRUE;
+            }
+        }
+    }
+    return FALSE;
+}
+
+/*
+ * Search for an standard name of an alias (what is the default name
+ * that this standard uses?)
+ * return the listOffset for gTaggedAliasLists. If it's 0,
+ * the it couldn't be found, but the parameters are valid.
+ */
+static uint32_t
+findTaggedAliasListsOffset(const char *alias, const char *standard, UErrorCode *pErrorCode) {
+    uint32_t idx;
+    uint32_t listOffset;
+    uint32_t convNum;
+    UErrorCode myErr = U_ZERO_ERROR;
+    uint32_t tagNum = getTagNumber(standard);
+
+    /* Make a quick guess. Hopefully they used a TR22 canonical alias. */
+    convNum = findConverter(alias, NULL, &myErr);
+    if (myErr != U_ZERO_ERROR) {
+        *pErrorCode = myErr;
+    }
+
+    if (tagNum < (gMainTable.tagListSize - UCNV_NUM_HIDDEN_TAGS) && convNum < gMainTable.converterListSize) {
+        listOffset = gMainTable.taggedAliasArray[tagNum*gMainTable.converterListSize + convNum];
+        if (listOffset && gMainTable.taggedAliasLists[listOffset + 1]) {
+            return listOffset;
+        }
+        if (myErr == U_AMBIGUOUS_ALIAS_WARNING) {
+            /* Uh Oh! They used an ambiguous alias.
+               We have to search the whole swiss cheese starting
+               at the highest standard affinity.
+               This may take a while.
+            */
+            for (idx = 0; idx < gMainTable.taggedAliasArraySize; idx++) {
+                listOffset = gMainTable.taggedAliasArray[idx];
+                if (listOffset && isAliasInList(alias, listOffset)) {
+                    uint32_t currTagNum = idx/gMainTable.converterListSize;
+                    uint32_t currConvNum = (idx - currTagNum*gMainTable.converterListSize);
+                    uint32_t tempListOffset = gMainTable.taggedAliasArray[tagNum*gMainTable.converterListSize + currConvNum];
+                    if (tempListOffset && gMainTable.taggedAliasLists[tempListOffset + 1]) {
+                        return tempListOffset;
+                    }
+                    /* else keep on looking */
+                    /* We could speed this up by starting on the next row
+                       because an alias is unique per row, right now.
+                       This would change if alias versioning appears. */
+                }
+            }
+            /* The standard doesn't know about the alias */
+        }
+        /* else no default name */
+        return 0;
+    }
+    /* else converter or tag not found */
+
+    return UINT32_MAX;
+}
+
+/* Return the canonical name */
+static uint32_t
+findTaggedConverterNum(const char *alias, const char *standard, UErrorCode *pErrorCode) {
+    uint32_t idx;
+    uint32_t listOffset;
+    uint32_t convNum;
+    UErrorCode myErr = U_ZERO_ERROR;
+    uint32_t tagNum = getTagNumber(standard);
+
+    /* Make a quick guess. Hopefully they used a TR22 canonical alias. */
+    convNum = findConverter(alias, NULL, &myErr);
+    if (myErr != U_ZERO_ERROR) {
+        *pErrorCode = myErr;
+    }
+
+    if (tagNum < (gMainTable.tagListSize - UCNV_NUM_HIDDEN_TAGS) && convNum < gMainTable.converterListSize) {
+        listOffset = gMainTable.taggedAliasArray[tagNum*gMainTable.converterListSize + convNum];
+        if (listOffset && isAliasInList(alias, listOffset)) {
+            return convNum;
+        }
+        if (myErr == U_AMBIGUOUS_ALIAS_WARNING) {
+            /* Uh Oh! They used an ambiguous alias.
+               We have to search one slice of the swiss cheese.
+               We search only in the requested tag, not the whole thing.
+               This may take a while.
+            */
+            uint32_t convStart = (tagNum)*gMainTable.converterListSize;
+            uint32_t convLimit = (tagNum+1)*gMainTable.converterListSize;
+            for (idx = convStart; idx < convLimit; idx++) {
+                listOffset = gMainTable.taggedAliasArray[idx];
+                if (listOffset && isAliasInList(alias, listOffset)) {
+                    return idx-convStart;
+                }
+            }
+            /* The standard doesn't know about the alias */
+        }
+        /* else no canonical name */
+    }
+    /* else converter or tag not found */
+
+    return UINT32_MAX;
+}
+
+
+
+U_CFUNC const char *
+ucnv_io_getConverterName(const char *alias, UBool *containsOption, UErrorCode *pErrorCode) {
+    if(haveAliasData(pErrorCode) && isAlias(alias, pErrorCode)) {
+        uint32_t convNum = findConverter(alias, containsOption, pErrorCode);
+        if (convNum < gMainTable.converterListSize) {
+            return GET_STRING(gMainTable.converterList[convNum]);
+        }
+        /* else converter not found */
+    }
+    return NULL;
+}
+
+static int32_t U_CALLCONV
+ucnv_io_countStandardAliases(UEnumeration *enumerator, UErrorCode *pErrorCode) {
+    int32_t value = 0;
+    UAliasContext *myContext = (UAliasContext *)(enumerator->context);
+    uint32_t listOffset = myContext->listOffset;
+
+    if (listOffset) {
+        value = gMainTable.taggedAliasLists[listOffset];
+    }
+    return value;
+}
+
+static const char* U_CALLCONV
+ucnv_io_nextStandardAliases(UEnumeration *enumerator,
+                            int32_t* resultLength,
+                            UErrorCode *pErrorCode)
+{
+    UAliasContext *myContext = (UAliasContext *)(enumerator->context);
+    uint32_t listOffset = myContext->listOffset;
+
+    if (listOffset) {
+        uint32_t listCount = gMainTable.taggedAliasLists[listOffset];
+        const uint16_t *currList = gMainTable.taggedAliasLists + listOffset + 1;
+
+        if (myContext->listIdx < listCount) {
+            const char *myStr = GET_STRING(currList[myContext->listIdx++]);
+            if (resultLength) {
+                *resultLength = (int32_t)uprv_strlen(myStr);
+            }
+            return myStr;
+        }
+    }
+    /* Either we accessed a zero length list, or we enumerated too far. */
+    if (resultLength) {
+        *resultLength = 0;
+    }
+    return NULL;
+}
+
+static void U_CALLCONV
+ucnv_io_resetStandardAliases(UEnumeration *enumerator, UErrorCode *pErrorCode) {
+    ((UAliasContext *)(enumerator->context))->listIdx = 0;
+}
+
+static void U_CALLCONV
+ucnv_io_closeUEnumeration(UEnumeration *enumerator) {
+    uprv_free(enumerator->context);
+    uprv_free(enumerator);
+}
+
+/* Enumerate the aliases for the specified converter and standard tag */
+static const UEnumeration gEnumAliases = {
+    NULL,
+    NULL,
+    ucnv_io_closeUEnumeration,
+    ucnv_io_countStandardAliases,
+    uenum_unextDefault,
+    ucnv_io_nextStandardAliases,
+    ucnv_io_resetStandardAliases
+};
+
+U_CAPI UEnumeration * U_EXPORT2
+ucnv_openStandardNames(const char *convName,
+                       const char *standard,
+                       UErrorCode *pErrorCode)
+{
+    UEnumeration *myEnum = NULL;
+    if (haveAliasData(pErrorCode) && isAlias(convName, pErrorCode)) {
+        uint32_t listOffset = findTaggedAliasListsOffset(convName, standard, pErrorCode);
+
+        /* When listOffset == 0, we want to acknowledge that the
+           converter name and standard are okay, but there
+           is nothing to enumerate. */
+        if (listOffset < gMainTable.taggedAliasListsSize) {
+            UAliasContext *myContext;
+
+            myEnum = uprv_malloc(sizeof(UEnumeration));
+            if (myEnum == NULL) {
+                *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+                return NULL;
+            }
+            uprv_memcpy(myEnum, &gEnumAliases, sizeof(UEnumeration));
+            myContext = uprv_malloc(sizeof(UAliasContext));
+            if (myContext == NULL) {
+                *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+                uprv_free(myEnum);
+                return NULL;
+            }
+            myContext->listOffset = listOffset;
+            myContext->listIdx = 0;
+            myEnum->context = myContext;
+        }
+        /* else converter or tag not found */
+    }
+    return myEnum;
+}
+
+static uint16_t
+ucnv_io_countAliases(const char *alias, UErrorCode *pErrorCode) {
+    if(haveAliasData(pErrorCode) && isAlias(alias, pErrorCode)) {
+        uint32_t convNum = findConverter(alias, NULL, pErrorCode);
+        if (convNum < gMainTable.converterListSize) {
+            /* tagListNum - 1 is the ALL tag */
+            int32_t listOffset = gMainTable.taggedAliasArray[(gMainTable.tagListSize - 1)*gMainTable.converterListSize + convNum];
+
+            if (listOffset) {
+                return gMainTable.taggedAliasLists[listOffset];
+            }
+            /* else this shouldn't happen. internal program error */
+        }
+        /* else converter not found */
+    }
+    return 0;
+}
+
+static uint16_t
+ucnv_io_getAliases(const char *alias, uint16_t start, const char **aliases, UErrorCode *pErrorCode) {
+    if(haveAliasData(pErrorCode) && isAlias(alias, pErrorCode)) {
+        uint32_t currAlias;
+        uint32_t convNum = findConverter(alias, NULL, pErrorCode);
+        if (convNum < gMainTable.converterListSize) {
+            /* tagListNum - 1 is the ALL tag */
+            int32_t listOffset = gMainTable.taggedAliasArray[(gMainTable.tagListSize - 1)*gMainTable.converterListSize + convNum];
+
+            if (listOffset) {
+                uint32_t listCount = gMainTable.taggedAliasLists[listOffset];
+                /* +1 to skip listCount */
+                const uint16_t *currList = gMainTable.taggedAliasLists + listOffset + 1;
+
+                for (currAlias = start; currAlias < listCount; currAlias++) {
+                    aliases[currAlias] = GET_STRING(currList[currAlias]);
+                }
+            }
+            /* else this shouldn't happen. internal program error */
+        }
+        /* else converter not found */
+    }
+    return 0;
+}
+
+static const char *
+ucnv_io_getAlias(const char *alias, uint16_t n, UErrorCode *pErrorCode) {
+    if(haveAliasData(pErrorCode) && isAlias(alias, pErrorCode)) {
+        uint32_t convNum = findConverter(alias, NULL, pErrorCode);
+        if (convNum < gMainTable.converterListSize) {
+            /* tagListNum - 1 is the ALL tag */
+            int32_t listOffset = gMainTable.taggedAliasArray[(gMainTable.tagListSize - 1)*gMainTable.converterListSize + convNum];
+
+            if (listOffset) {
+                uint32_t listCount = gMainTable.taggedAliasLists[listOffset];
+                /* +1 to skip listCount */
+                const uint16_t *currList = gMainTable.taggedAliasLists + listOffset + 1;
+
+                if (n < listCount)  {
+                    return GET_STRING(currList[n]);
+                }
+                *pErrorCode = U_INDEX_OUTOFBOUNDS_ERROR;
+            }
+            /* else this shouldn't happen. internal program error */
+        }
+        /* else converter not found */
+    }
+    return NULL;
+}
+
+static uint16_t
+ucnv_io_countStandards(UErrorCode *pErrorCode) {
+    if (haveAliasData(pErrorCode)) {
+        /* Don't include the empty list */
+        return (uint16_t)(gMainTable.tagListSize - UCNV_NUM_HIDDEN_TAGS);
+    }
+
+    return 0;
+}
+
+U_CAPI const char * U_EXPORT2
+ucnv_getStandard(uint16_t n, UErrorCode *pErrorCode) {
+    if (haveAliasData(pErrorCode)) {
+        if (n < gMainTable.tagListSize - UCNV_NUM_HIDDEN_TAGS) {
+            return GET_STRING(gMainTable.tagList[n]);
+        }
+        *pErrorCode = U_INDEX_OUTOFBOUNDS_ERROR;
+    }
+
+    return NULL;
+}
+
+U_CAPI const char * U_EXPORT2
+ucnv_getStandardName(const char *alias, const char *standard, UErrorCode *pErrorCode) {
+    if (haveAliasData(pErrorCode) && isAlias(alias, pErrorCode)) {
+        uint32_t listOffset = findTaggedAliasListsOffset(alias, standard, pErrorCode);
+
+        if (0 < listOffset && listOffset < gMainTable.taggedAliasListsSize) {
+            const uint16_t *currList = gMainTable.taggedAliasLists + listOffset + 1;
+
+            /* Get the preferred name from this list */
+            if (currList[0]) {
+                return GET_STRING(currList[0]);
+            }
+            /* else someone screwed up the alias table. */
+            /* *pErrorCode = U_INVALID_FORMAT_ERROR */
+        }
+    }
+
+    return NULL;
+}
+
+U_CAPI uint16_t U_EXPORT2
+ucnv_countAliases(const char *alias, UErrorCode *pErrorCode)
+{
+    return ucnv_io_countAliases(alias, pErrorCode);
+}
+
+
+U_CAPI const char* U_EXPORT2
+ucnv_getAlias(const char *alias, uint16_t n, UErrorCode *pErrorCode)
+{
+    return ucnv_io_getAlias(alias, n, pErrorCode);
+}
+
+U_CAPI void U_EXPORT2
+ucnv_getAliases(const char *alias, const char **aliases, UErrorCode *pErrorCode)
+{
+    ucnv_io_getAliases(alias, 0, aliases, pErrorCode);
+}
+
+U_CAPI uint16_t U_EXPORT2
+ucnv_countStandards(void)
+{
+    UErrorCode err = U_ZERO_ERROR;
+    return ucnv_io_countStandards(&err);
+}
+
+U_CAPI const char * U_EXPORT2
+ucnv_getCanonicalName(const char *alias, const char *standard, UErrorCode *pErrorCode) {
+    if (haveAliasData(pErrorCode) && isAlias(alias, pErrorCode)) {
+        uint32_t convNum = findTaggedConverterNum(alias, standard, pErrorCode);
+
+        if (convNum < gMainTable.converterListSize) {
+            return GET_STRING(gMainTable.converterList[convNum]);
+        }
+    }
+
+    return NULL;
+}
+
+static int32_t U_CALLCONV
+ucnv_io_countAllConverters(UEnumeration *enumerator, UErrorCode *pErrorCode) {
+    return gMainTable.converterListSize;
+}
+
+static const char* U_CALLCONV
+ucnv_io_nextAllConverters(UEnumeration *enumerator,
+                            int32_t* resultLength,
+                            UErrorCode *pErrorCode)
+{
+    uint16_t *myContext = (uint16_t *)(enumerator->context);
+
+    if (*myContext < gMainTable.converterListSize) {
+        const char *myStr = GET_STRING(gMainTable.converterList[(*myContext)++]);
+        if (resultLength) {
+            *resultLength = (int32_t)uprv_strlen(myStr);
+        }
+        return myStr;
+    }
+    /* Either we accessed a zero length list, or we enumerated too far. */
+    if (resultLength) {
+        *resultLength = 0;
+    }
+    return NULL;
+}
+
+static void U_CALLCONV
+ucnv_io_resetAllConverters(UEnumeration *enumerator, UErrorCode *pErrorCode) {
+    *((uint16_t *)(enumerator->context)) = 0;
+}
+
+static const UEnumeration gEnumAllConverters = {
+    NULL,
+    NULL,
+    ucnv_io_closeUEnumeration,
+    ucnv_io_countAllConverters,
+    uenum_unextDefault,
+    ucnv_io_nextAllConverters,
+    ucnv_io_resetAllConverters
+};
+
+U_CAPI UEnumeration * U_EXPORT2
+ucnv_openAllNames(UErrorCode *pErrorCode) {
+    UEnumeration *myEnum = NULL;
+    if (haveAliasData(pErrorCode)) {
+        uint16_t *myContext;
+
+        myEnum = uprv_malloc(sizeof(UEnumeration));
+        if (myEnum == NULL) {
+            *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+            return NULL;
+        }
+        uprv_memcpy(myEnum, &gEnumAllConverters, sizeof(UEnumeration));
+        myContext = uprv_malloc(sizeof(uint16_t));
+        if (myContext == NULL) {
+            *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+            uprv_free(myEnum);
+            return NULL;
+        }
+        *myContext = 0;
+        myEnum->context = myContext;
+    }
+    return myEnum;
+}
+
+U_CFUNC uint16_t
+ucnv_io_countKnownConverters(UErrorCode *pErrorCode) {
+    if (haveAliasData(pErrorCode)) {
+        return (uint16_t)gMainTable.converterListSize;
+    }
+    return 0;
+}
+
+/* alias table swapping ----------------------------------------------------- */
+
+typedef char * U_CALLCONV StripForCompareFn(char *dst, const char *name);
+
+/*
+ * row of a temporary array
+ *
+ * gets platform-endian charset string indexes and sorting indexes;
+ * after sorting this array by strings, the actual arrays are permutated
+ * according to the sorting indexes
+ */
+typedef struct TempRow {
+    uint16_t strIndex, sortIndex;
+} TempRow;
+
+typedef struct TempAliasTable {
+    const char *chars;
+    TempRow *rows;
+    uint16_t *resort;
+    StripForCompareFn *stripForCompare;
+} TempAliasTable;
+
+enum {
+    STACK_ROW_CAPACITY=500
+};
+
+static int32_t
+io_compareRows(const void *context, const void *left, const void *right) {
+    char strippedLeft[UCNV_MAX_CONVERTER_NAME_LENGTH],
+         strippedRight[UCNV_MAX_CONVERTER_NAME_LENGTH];
+
+    TempAliasTable *tempTable=(TempAliasTable *)context;
+    const char *chars=tempTable->chars;
+
+    return (int32_t)uprv_strcmp(tempTable->stripForCompare(strippedLeft, chars+2*((const TempRow *)left)->strIndex),
+                                tempTable->stripForCompare(strippedRight, chars+2*((const TempRow *)right)->strIndex));
+}
+
+U_CAPI int32_t U_EXPORT2
+ucnv_swapAliases(const UDataSwapper *ds,
+                 const void *inData, int32_t length, void *outData,
+                 UErrorCode *pErrorCode) {
+    const UDataInfo *pInfo;
+    int32_t headerSize;
+
+    const uint16_t *inTable;
+    const uint32_t *inSectionSizes;
+    uint32_t toc[offsetsCount];
+    uint32_t offsets[offsetsCount]; /* 16-bit-addressed offsets from inTable/outTable */
+    uint32_t i, count, tocLength, topOffset;
+
+    TempRow rows[STACK_ROW_CAPACITY];
+    uint16_t resort[STACK_ROW_CAPACITY];
+    TempAliasTable tempTable;
+
+    /* udata_swapDataHeader checks the arguments */
+    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    /* check data format and format version */
+    pInfo=(const UDataInfo *)((const char *)inData+4);
+    if(!(
+        pInfo->dataFormat[0]==0x43 &&   /* dataFormat="CvAl" */
+        pInfo->dataFormat[1]==0x76 &&
+        pInfo->dataFormat[2]==0x41 &&
+        pInfo->dataFormat[3]==0x6c &&
+        pInfo->formatVersion[0]==3
+    )) {
+        udata_printError(ds, "ucnv_swapAliases(): data format %02x.%02x.%02x.%02x (format version %02x) is not an alias table\n",
+                         pInfo->dataFormat[0], pInfo->dataFormat[1],
+                         pInfo->dataFormat[2], pInfo->dataFormat[3],
+                         pInfo->formatVersion[0]);
+        *pErrorCode=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    /* an alias table must contain at least the table of contents array */
+    if(length>=0 && (length-headerSize)<4*(1+minTocLength)) {
+        udata_printError(ds, "ucnv_swapAliases(): too few bytes (%d after header) for an alias table\n",
+                         length-headerSize);
+        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0;
+    }
+
+    inSectionSizes=(const uint32_t *)((const char *)inData+headerSize);
+    inTable=(const uint16_t *)inSectionSizes;
+    uprv_memset(toc, 0, sizeof(toc));
+    toc[tocLengthIndex]=tocLength=ds->readUInt32(inSectionSizes[tocLengthIndex]);
+    if(tocLength<minTocLength || offsetsCount<=tocLength) {
+        udata_printError(ds, "ucnv_swapAliases(): table of contents contains unsupported number of sections (%u sections)\n", tocLength);
+        *pErrorCode=U_INVALID_FORMAT_ERROR;
+        return 0;
+    }
+
+    /* read the known part of the table of contents */
+    for(i=converterListIndex; i<=tocLength; ++i) {
+        toc[i]=ds->readUInt32(inSectionSizes[i]);
+    }
+
+    /* compute offsets */
+    uprv_memset(offsets, 0, sizeof(offsets));
+    offsets[converterListIndex]=2*(1+tocLength); /* count two 16-bit units per toc entry */
+    for(i=tagListIndex; i<=tocLength; ++i) {
+        offsets[i]=offsets[i-1]+toc[i-1];
+    }
+
+    /* compute the overall size of the after-header data, in numbers of 16-bit units */
+    topOffset=offsets[i-1]+toc[i-1];
+
+    if(length>=0) {
+        uint16_t *outTable;
+        const uint16_t *p, *p2;
+        uint16_t *q, *q2;
+        uint16_t oldIndex;
+
+        if((length-headerSize)<(2*(int32_t)topOffset)) {
+            udata_printError(ds, "ucnv_swapAliases(): too few bytes (%d after header) for an alias table\n",
+                             length-headerSize);
+            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+            return 0;
+        }
+
+        outTable=(uint16_t *)((char *)outData+headerSize);
+
+        /* swap the entire table of contents */
+        ds->swapArray32(ds, inTable, 4*(1+tocLength), outTable, pErrorCode);
+
+        /* swap unormalized strings & normalized strings */
+        ds->swapInvChars(ds, inTable+offsets[stringTableIndex], 2*(int32_t)(toc[stringTableIndex]+toc[normalizedStringTableIndex]),
+                             outTable+offsets[stringTableIndex], pErrorCode);
+        if(U_FAILURE(*pErrorCode)) {
+            udata_printError(ds, "ucnv_swapAliases().swapInvChars(charset names) failed\n");
+            return 0;
+        }
+
+        if(ds->inCharset==ds->outCharset) {
+            /* no need to sort, just swap all 16-bit values together */
+            ds->swapArray16(ds,
+                            inTable+offsets[converterListIndex],
+                            2*(int32_t)(offsets[stringTableIndex]-offsets[converterListIndex]),
+                            outTable+offsets[converterListIndex],
+                            pErrorCode);
+        } else {
+            /* allocate the temporary table for sorting */
+            count=toc[aliasListIndex];
+
+            tempTable.chars=(const char *)(outTable+offsets[stringTableIndex]); /* sort by outCharset */
+
+            if(count<=STACK_ROW_CAPACITY) {
+                tempTable.rows=rows;
+                tempTable.resort=resort;
+            } else {
+                tempTable.rows=(TempRow *)uprv_malloc(count*sizeof(TempRow)+count*2);
+                if(tempTable.rows==NULL) {
+                    udata_printError(ds, "ucnv_swapAliases(): unable to allocate memory for sorting tables (max length: %u)\n",
+                                     count);
+                    *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+                    return 0;
+                }
+                tempTable.resort=(uint16_t *)(tempTable.rows+count);
+            }
+
+            if(ds->outCharset==U_ASCII_FAMILY) {
+                tempTable.stripForCompare=ucnv_io_stripASCIIForCompare;
+            } else /* U_EBCDIC_FAMILY */ {
+                tempTable.stripForCompare=ucnv_io_stripEBCDICForCompare;
+            }
+
+            /*
+             * Sort unique aliases+mapped names.
+             *
+             * We need to sort the list again by outCharset strings because they
+             * sort differently for different charset families.
+             * First we set up a temporary table with the string indexes and
+             * sorting indexes and sort that.
+             * Then we permutate and copy/swap the actual values.
+             */
+            p=inTable+offsets[aliasListIndex];
+            q=outTable+offsets[aliasListIndex];
+
+            p2=inTable+offsets[untaggedConvArrayIndex];
+            q2=outTable+offsets[untaggedConvArrayIndex];
+
+            for(i=0; i<count; ++i) {
+                tempTable.rows[i].strIndex=ds->readUInt16(p[i]);
+                tempTable.rows[i].sortIndex=(uint16_t)i;
+            }
+
+            uprv_sortArray(tempTable.rows, (int32_t)count, sizeof(TempRow),
+                           io_compareRows, &tempTable,
+                           FALSE, pErrorCode);
+
+            if(U_SUCCESS(*pErrorCode)) {
+                /* copy/swap/permutate items */
+                if(p!=q) {
+                    for(i=0; i<count; ++i) {
+                        oldIndex=tempTable.rows[i].sortIndex;
+                        ds->swapArray16(ds, p+oldIndex, 2, q+i, pErrorCode);
+                        ds->swapArray16(ds, p2+oldIndex, 2, q2+i, pErrorCode);
+                    }
+                } else {
+                    /*
+                     * If we swap in-place, then the permutation must use another
+                     * temporary array (tempTable.resort)
+                     * before the results are copied to the outBundle.
+                     */
+                    uint16_t *r=tempTable.resort;
+
+                    for(i=0; i<count; ++i) {
+                        oldIndex=tempTable.rows[i].sortIndex;
+                        ds->swapArray16(ds, p+oldIndex, 2, r+i, pErrorCode);
+                    }
+                    uprv_memcpy(q, r, 2*count);
+
+                    for(i=0; i<count; ++i) {
+                        oldIndex=tempTable.rows[i].sortIndex;
+                        ds->swapArray16(ds, p2+oldIndex, 2, r+i, pErrorCode);
+                    }
+                    uprv_memcpy(q2, r, 2*count);
+                }
+            }
+
+            if(tempTable.rows!=rows) {
+                uprv_free(tempTable.rows);
+            }
+
+            if(U_FAILURE(*pErrorCode)) {
+                udata_printError(ds, "ucnv_swapAliases().uprv_sortArray(%u items) failed\n",
+                                 count);
+                return 0;
+            }
+
+            /* swap remaining 16-bit values */
+            ds->swapArray16(ds,
+                            inTable+offsets[converterListIndex],
+                            2*(int32_t)(offsets[aliasListIndex]-offsets[converterListIndex]),
+                            outTable+offsets[converterListIndex],
+                            pErrorCode);
+            ds->swapArray16(ds,
+                            inTable+offsets[taggedAliasArrayIndex],
+                            2*(int32_t)(offsets[stringTableIndex]-offsets[taggedAliasArrayIndex]),
+                            outTable+offsets[taggedAliasArrayIndex],
+                            pErrorCode);
+        }
+    }
+
+    return headerSize+2*(int32_t)topOffset;
+}
+
+#endif
+
+/*
+ * Hey, Emacs, please set the following:
+ *
+ * Local Variables:
+ * indent-tabs-mode: nil
+ * End:
+ *
+ */
diff --git a/source/common/ucnv_io.h b/source/common/ucnv_io.h
new file mode 100644
index 0000000..060ffd0
--- /dev/null
+++ b/source/common/ucnv_io.h
@@ -0,0 +1,125 @@
+/*
+ **********************************************************************
+ *   Copyright (C) 1999-2006, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ **********************************************************************
+ *
+ *
+ *  ucnv_io.h:
+ *  defines  variables and functions pertaining to converter name resolution
+ *  aspect of the conversion code
+ */
+
+#ifndef UCNV_IO_H
+#define UCNV_IO_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "udataswp.h"
+
+#define UCNV_AMBIGUOUS_ALIAS_MAP_BIT 0x8000
+#define UCNV_CONTAINS_OPTION_BIT 0x4000
+#define UCNV_CONVERTER_INDEX_MASK 0xFFF
+#define UCNV_NUM_RESERVED_TAGS 2
+#define UCNV_NUM_HIDDEN_TAGS 1
+
+enum {
+    UCNV_IO_UNNORMALIZED,
+    UCNV_IO_STD_NORMALIZED,
+    UCNV_IO_NORM_TYPE_COUNT
+};
+
+typedef struct {
+    uint16_t stringNormalizationType;
+    uint16_t containsCnvOptionInfo;
+} UConverterAliasOptions;
+
+typedef struct UConverterAlias {
+    const uint16_t *converterList;
+    const uint16_t *tagList;
+    const uint16_t *aliasList;
+    const uint16_t *untaggedConvArray;
+    const uint16_t *taggedAliasArray;
+    const uint16_t *taggedAliasLists;
+    const UConverterAliasOptions *optionTable;
+    const uint16_t *stringTable;
+    const uint16_t *normalizedStringTable;
+
+    uint32_t converterListSize;
+    uint32_t tagListSize;
+    uint32_t aliasListSize;
+    uint32_t untaggedConvArraySize;
+    uint32_t taggedAliasArraySize;
+    uint32_t taggedAliasListsSize;
+    uint32_t optionTableSize;
+    uint32_t stringTableSize;
+    uint32_t normalizedStringTableSize;
+} UConverterAlias;
+
+/**
+ * \var ucnv_io_stripForCompare
+ * Remove the underscores, dashes and spaces from the name, and convert
+ * the name to lower case.
+ * @param dst The destination buffer, which is <= the buffer of name.
+ * @param dst The destination buffer, which is <= the buffer of name.
+ * @see ucnv_compareNames
+ * @return the destination buffer.
+ */
+#if U_CHARSET_FAMILY==U_ASCII_FAMILY
+#   define ucnv_io_stripForCompare ucnv_io_stripASCIIForCompare
+#elif U_CHARSET_FAMILY==U_EBCDIC_FAMILY
+#   define ucnv_io_stripForCompare ucnv_io_stripEBCDICForCompare
+#else
+#   error U_CHARSET_FAMILY is not valid
+#endif
+
+U_CAPI char * U_EXPORT2
+ucnv_io_stripASCIIForCompare(char *dst, const char *name);
+
+U_CAPI char * U_EXPORT2
+ucnv_io_stripEBCDICForCompare(char *dst, const char *name);
+
+/**
+ * Map a converter alias name to a canonical converter name.
+ * The alias is searched for case-insensitively, the converter name
+ * is returned in mixed-case.
+ * Returns NULL if the alias is not found.
+ * @param alias The alias name to be searched.
+ * @param containsOption A return value stating whether the returned converter name contains an option (a comma)
+ * @param pErrorCode The error code
+ * @return the converter name in mixed-case, return NULL if the alias is not found.
+ */
+U_CFUNC const char *
+ucnv_io_getConverterName(const char *alias, UBool *containsOption, UErrorCode *pErrorCode);
+
+/**
+ * Return the number of all known converter names (no aliases).
+ * @param pErrorCode The error code
+ * @return the number of all aliases
+ */
+U_CFUNC uint16_t
+ucnv_io_countKnownConverters(UErrorCode *pErrorCode);
+
+/**
+ * Swap an ICU converter alias table. See implementation for details.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+ucnv_swapAliases(const UDataSwapper *ds,
+                 const void *inData, int32_t length, void *outData,
+                 UErrorCode *pErrorCode);
+
+#endif
+
+#endif /* _UCNV_IO */
+
+/*
+ * Hey, Emacs, please set the following:
+ *
+ * Local Variables:
+ * indent-tabs-mode: nil
+ * End:
+ *
+ */
diff --git a/source/common/ucnv_lmb.c b/source/common/ucnv_lmb.c
new file mode 100644
index 0000000..275e7d5
--- /dev/null
+++ b/source/common/ucnv_lmb.c
@@ -0,0 +1,1377 @@
+/*  
+**********************************************************************
+*   Copyright (C) 2000-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   file name:  ucnv_lmb.cpp
+*   encoding:   US-ASCII
+*   tab size:   4 (not used)
+*   indentation:4
+*
+*   created on: 2000feb09
+*   created by: Brendan Murray
+*   extensively hacked up by: Jim Snyder-Grant
+*
+* Modification History:
+* 
+*   Date        Name             Description
+* 
+*   06/20/2000  helena           OS/400 port changes; mostly typecast.
+*   06/27/2000  Jim Snyder-Grant Deal with partial characters and small buffers.
+*                                Add comments to document LMBCS format and implementation
+*                                restructured order & breakdown of functions
+*   06/28/2000  helena           Major rewrite for the callback API changes.
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION && !UCONFIG_NO_LEGACY_CONVERSION
+
+#include "unicode/ucnv_err.h"
+#include "unicode/ucnv.h"
+#include "unicode/uset.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uassert.h"
+#include "ucnv_imp.h"
+#include "ucnv_bld.h"
+#include "ucnv_cnv.h"
+
+#ifdef EBCDIC_RTL
+    #include "ascii_a.h"
+#endif
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+/*
+  LMBCS
+
+  (Lotus Multi-Byte Character Set)
+
+  LMBCS was invented in the late 1980's and is primarily used in Lotus Notes 
+  databases and in Lotus 1-2-3 files. Programmers who work with the APIs 
+  into these products will sometimes need to deal with strings in this format.
+
+  The code in this file provides an implementation for an ICU converter of 
+  LMBCS to and from Unicode. 
+
+  Since the LMBCS character set is only sparsely documented in existing 
+  printed or online material, we have added  extensive annotation to this 
+  file to serve as a guide to understanding LMBCS. 
+
+  LMBCS was originally designed with these four sometimes-competing design goals:
+
+  -Provide encodings for the characters in 12 existing national standards
+   (plus a few other characters)
+  -Minimal memory footprint
+  -Maximal speed of conversion into the existing national character sets
+  -No need to track a changing state as you interpret a string.
+
+
+  All of the national character sets LMBCS was trying to encode are 'ANSI'
+  based, in that the bytes from 0x20 - 0x7F are almost exactly the 
+  same common Latin unaccented characters and symbols in all character sets. 
+
+  So, in order to help meet the speed & memory design goals, the common ANSI 
+  bytes from 0x20-0x7F are represented by the same single-byte values in LMBCS. 
+
+  The general LMBCS code unit is from 1-3 bytes. We can describe the 3 bytes as
+  follows:
+
+  [G] D1 [D2]
+
+  That is, a sometimes-optional 'group' byte, followed by 1 and sometimes 2
+  data bytes. The maximum size of a LMBCS chjaracter is 3 bytes:
+*/
+#define ULMBCS_CHARSIZE_MAX      3
+/*
+  The single-byte values from 0x20 to 0x7F are examples of single D1 bytes.
+  We often have to figure out if byte values are below or above this, so we 
+  use the ANSI nomenclature 'C0' and 'C1' to refer to the range of control 
+  characters just above & below the common lower-ANSI  range */
+#define ULMBCS_C0END           0x1F   
+#define ULMBCS_C1START         0x80   
+/*
+  Since LMBCS is always dealing in byte units. we create a local type here for 
+  dealing with these units of LMBCS code units:
+
+*/  
+typedef uint8_t ulmbcs_byte_t;
+
+/* 
+   Most of the values less than 0x20 are reserved in LMBCS to announce 
+   which national  character standard is being used for the 'D' bytes. 
+   In the comments we show the common name and the IBM character-set ID
+   for these character-set announcers:
+*/
+
+#define ULMBCS_GRP_L1         0x01   /* Latin-1    :ibm-850  */
+#define ULMBCS_GRP_GR         0x02   /* Greek      :ibm-851  */
+#define ULMBCS_GRP_HE         0x03   /* Hebrew     :ibm-1255 */
+#define ULMBCS_GRP_AR         0x04   /* Arabic     :ibm-1256 */
+#define ULMBCS_GRP_RU         0x05   /* Cyrillic   :ibm-1251 */
+#define ULMBCS_GRP_L2         0x06   /* Latin-2    :ibm-852  */
+#define ULMBCS_GRP_TR         0x08   /* Turkish    :ibm-1254 */
+#define ULMBCS_GRP_TH         0x0B   /* Thai       :ibm-874  */
+#define ULMBCS_GRP_JA         0x10   /* Japanese   :ibm-943  */
+#define ULMBCS_GRP_KO         0x11   /* Korean     :ibm-1261 */
+#define ULMBCS_GRP_TW         0x12   /* Chinese SC :ibm-950  */
+#define ULMBCS_GRP_CN         0x13   /* Chinese TC :ibm-1386 */
+
+/*
+   So, the beginning of understanding LMBCS is that IF the first byte of a LMBCS 
+   character is one of those 12 values, you can interpret the remaining bytes of 
+   that character as coming from one of those character sets. Since the lower 
+   ANSI bytes already are represented in single bytes, using one of the character 
+   set announcers is used to announce a character that starts with a byte of 
+   0x80 or greater.
+
+   The character sets are  arranged so that the single byte sets all appear 
+   before the multi-byte character sets. When we need to tell whether a 
+   group byte is for a single byte char set or not we use this define: */
+
+#define ULMBCS_DOUBLEOPTGROUP_START  0x10   
+
+/* 
+However, to fully understand LMBCS, you must also understand a series of 
+exceptions & optimizations made in service of the design goals. 
+
+First, those of you who are character set mavens may have noticed that
+the 'double-byte' character sets are actually multi-byte character sets 
+that can have 1 or two bytes, even in the upper-ascii range. To force
+each group byte to introduce a fixed-width encoding (to make it faster to 
+count characters), we use a convention of doubling up on the group byte 
+to introduce any single-byte character > 0x80 in an otherwise double-byte
+character set. So, for example, the LMBCS sequence x10 x10 xAE is the 
+same as '0xAE' in the Japanese code page 943.
+
+Next, you will notice that the list of group bytes has some gaps. 
+These are used in various ways.
+
+We reserve a few special single byte values for common control 
+characters. These are in the same place as their ANSI eqivalents for speed.
+*/
+                     
+#define ULMBCS_HT    0x09   /* Fixed control char - Horizontal Tab */
+#define ULMBCS_LF    0x0A   /* Fixed control char - Line Feed */
+#define ULMBCS_CR    0x0D   /* Fixed control char - Carriage Return */
+
+/* Then, 1-2-3 reserved a special single-byte character to put at the 
+beginning of internal 'system' range names: */
+
+#define ULMBCS_123SYSTEMRANGE  0x19   
+
+/* Then we needed a place to put all the other ansi control characters 
+that must be moved to different values because LMBCS reserves those 
+values for other purposes. To represent the control characters, we start 
+with a first byte of 0xF & add the control chaarcter value as the 
+second byte */
+#define ULMBCS_GRP_CTRL       0x0F   
+
+/* For the C0 controls (less than 0x20), we add 0x20 to preserve the 
+useful doctrine that any byte less than 0x20 in a LMBCS char must be 
+the first byte of a character:*/
+#define ULMBCS_CTRLOFFSET      0x20   
+
+/* 
+Where to put the characters that aren't part of any of the 12 national 
+character sets? The first thing that was done, in the earlier years of 
+LMBCS, was to use up the spaces of the form
+
+  [G] D1, 
+  
+ where  'G' was one of the single-byte character groups, and
+ D1 was less than 0x80. These sequences are gathered together 
+ into a Lotus-invented doublebyte character set to represent a 
+ lot of stray values. Internally, in this implementation, we track this 
+ as group '0', as a place to tuck this exceptions list.*/
+
+#define ULMBCS_GRP_EXCEPT     0x00    
+/*
+ Finally, as the durability and usefulness of UNICODE became clear, 
+ LOTUS added a new group 0x14 to hold Unicode values not otherwise 
+ represented in LMBCS: */
+#define ULMBCS_GRP_UNICODE    0x14   
+/* The two bytes appearing after a 0x14 are intrepreted as UFT-16 BE
+(Big-Endian) characters. The exception comes when the UTF16 
+representation would have a zero as the second byte. In that case,
+'F6' is used in its place, and the bytes are swapped. (This prevents 
+LMBCS from encoding any Unicode values of the form U+F6xx, but that's OK:
+0xF6xx is in the middle of the Private Use Area.)*/
+#define ULMBCS_UNICOMPATZERO   0xF6   
+
+/* It is also useful in our code to have a constant for the size of 
+a LMBCS char that holds a literal Unicode value */
+#define ULMBCS_UNICODE_SIZE      3    
+
+/* 
+To squish the LMBCS representations down even further, and to make 
+translations even faster,sometimes the optimization group byte can be dropped 
+from a LMBCS character. This is decided on a process-by-process basis. The 
+group byte that is dropped is called the 'optimization group'.
+
+For Notes, the optimzation group is always 0x1.*/
+#define ULMBCS_DEFAULTOPTGROUP 0x1    
+/* For 1-2-3 files, the optimzation group is stored in the header of the 1-2-3 
+file. 
+
+ In any case, when using ICU, you either pass in the 
+optimization group as part of the name of the converter (LMBCS-1, LMBCS-2, 
+etc.). Using plain 'LMBCS' as the name of the converter will give you 
+LMBCS-1.
+
+
+*** Implementation strategy ***
+
+
+Because of the extensive use of other character sets, the LMBCS converter
+keeps a mapping between optimization groups and IBM character sets, so that
+ICU converters can be created and used as needed. */
+
+/* As you can see, even though any byte below 0x20 could be an optimization 
+byte, only those at 0x13 or below can map to an actual converter. To limit
+some loops and searches, we define a value for that last group converter:*/
+
+#define ULMBCS_GRP_LAST       0x13   /* last LMBCS group that has a converter */
+
+static const char * const OptGroupByteToCPName[ULMBCS_GRP_LAST + 1] = {
+   /* 0x0000 */ "lmb-excp", /* internal home for the LOTUS exceptions list */
+   /* 0x0001 */ "ibm-850",
+   /* 0x0002 */ "ibm-851",
+   /* 0x0003 */ "windows-1255",
+   /* 0x0004 */ "windows-1256",
+   /* 0x0005 */ "windows-1251",
+   /* 0x0006 */ "ibm-852",
+   /* 0x0007 */ NULL,      /* Unused */
+   /* 0x0008 */ "windows-1254",
+   /* 0x0009 */ NULL,      /* Control char HT */
+   /* 0x000A */ NULL,      /* Control char LF */
+   /* 0x000B */ "windows-874",
+   /* 0x000C */ NULL,      /* Unused */
+   /* 0x000D */ NULL,      /* Control char CR */
+   /* 0x000E */ NULL,      /* Unused */
+   /* 0x000F */ NULL,      /* Control chars: 0x0F20 + C0/C1 character: algorithmic */
+   /* 0x0010 */ "windows-932",
+   /* 0x0011 */ "windows-949",
+   /* 0x0012 */ "windows-950",
+   /* 0x0013 */ "windows-936"
+
+   /* The rest are null, including the 0x0014 Unicode compatibility region
+   and 0x0019, the 1-2-3 system range control char */      
+};
+
+
+/* That's approximately all the data that's needed for translating 
+  LMBCS to Unicode. 
+
+
+However, to translate Unicode to LMBCS, we need some more support.
+
+That's because there are often more than one possible mappings from a Unicode
+code point back into LMBCS. The first thing we do is look up into a table
+to figure out if there are more than one possible mappings. This table,
+arranged by Unicode values (including ranges) either lists which group 
+to use, or says that it could go into one or more of the SBCS sets, or
+into one or more of the DBCS sets.  (If the character exists in both DBCS & 
+SBCS, the table will place it in the SBCS sets, to make the LMBCS code point 
+length as small as possible. Here's the two special markers we use to indicate
+ambiguous mappings: */
+
+#define ULMBCS_AMBIGUOUS_SBCS   0x80   /* could fit in more than one 
+                                          LMBCS sbcs native encoding 
+                                          (example: most accented latin) */
+#define ULMBCS_AMBIGUOUS_MBCS   0x81   /* could fit in more than one 
+                                          LMBCS mbcs native encoding 
+                                          (example: Unihan) */
+#define ULMBCS_AMBIGUOUS_ALL   0x82
+/* And here's a simple way to see if a group falls in an appropriate range */
+#define ULMBCS_AMBIGUOUS_MATCH(agroup, xgroup) \
+                  ((((agroup) == ULMBCS_AMBIGUOUS_SBCS) && \
+                  (xgroup) < ULMBCS_DOUBLEOPTGROUP_START) || \
+                  (((agroup) == ULMBCS_AMBIGUOUS_MBCS) && \
+                  (xgroup) >= ULMBCS_DOUBLEOPTGROUP_START)) || \
+                  ((agroup) == ULMBCS_AMBIGUOUS_ALL)
+
+
+/* The table & some code to use it: */
+
+
+static const struct _UniLMBCSGrpMap  
+{
+   const UChar uniStartRange;
+   const UChar uniEndRange;
+   const ulmbcs_byte_t  GrpType;
+} UniLMBCSGrpMap[]
+=
+{
+
+    {0x0001, 0x001F,  ULMBCS_GRP_CTRL},
+    {0x0080, 0x009F,  ULMBCS_GRP_CTRL},
+    {0x00A0, 0x00A6,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x00A7, 0x00A8,  ULMBCS_AMBIGUOUS_ALL},
+    {0x00A9, 0x00AF,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x00B0, 0x00B1,  ULMBCS_AMBIGUOUS_ALL},
+    {0x00B2, 0x00B3,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x00B4, 0x00B4,  ULMBCS_AMBIGUOUS_ALL},
+    {0x00B5, 0x00B5,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x00B6, 0x00B6,  ULMBCS_AMBIGUOUS_ALL},
+    {0x00B7, 0x00D6,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x00D7, 0x00D7,  ULMBCS_AMBIGUOUS_ALL},
+    {0x00D8, 0x00F6,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x00F7, 0x00F7,  ULMBCS_AMBIGUOUS_ALL},
+    {0x00F8, 0x01CD,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x01CE, 0x01CE,  ULMBCS_GRP_TW },
+    {0x01CF, 0x02B9,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x02BA, 0x02BA,  ULMBCS_GRP_CN},
+    {0x02BC, 0x02C8,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x02C9, 0x02D0,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x02D8, 0x02DD,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x0384, 0x0390,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x0391, 0x03A9,  ULMBCS_AMBIGUOUS_ALL},
+    {0x03AA, 0x03B0,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x03B1, 0x03C9,  ULMBCS_AMBIGUOUS_ALL},
+    {0x03CA, 0x03CE,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x0400, 0x0400,  ULMBCS_GRP_RU},
+    {0x0401, 0x0401,  ULMBCS_AMBIGUOUS_ALL},
+    {0x0402, 0x040F,  ULMBCS_GRP_RU},
+    {0x0410, 0x0431,  ULMBCS_AMBIGUOUS_ALL},
+    {0x0432, 0x044E,  ULMBCS_GRP_RU},
+    {0x044F, 0x044F,  ULMBCS_AMBIGUOUS_ALL},
+    {0x0450, 0x0491,  ULMBCS_GRP_RU},
+    {0x05B0, 0x05F2,  ULMBCS_GRP_HE},
+    {0x060C, 0x06AF,  ULMBCS_GRP_AR},
+    {0x0E01, 0x0E5B,  ULMBCS_GRP_TH},
+    {0x200C, 0x200F,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x2010, 0x2010,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2013, 0x2014,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x2015, 0x2015,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2016, 0x2016,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2017, 0x2017,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x2018, 0x2019,  ULMBCS_AMBIGUOUS_ALL},
+    {0x201A, 0x201B,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x201C, 0x201D,  ULMBCS_AMBIGUOUS_ALL},
+    {0x201E, 0x201F,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x2020, 0x2021,  ULMBCS_AMBIGUOUS_ALL},
+    {0x2022, 0x2024,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x2025, 0x2025,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2026, 0x2026,  ULMBCS_AMBIGUOUS_ALL},
+    {0x2027, 0x2027,  ULMBCS_GRP_TW},
+    {0x2030, 0x2030,  ULMBCS_AMBIGUOUS_ALL},
+    {0x2031, 0x2031,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x2032, 0x2033,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2035, 0x2035,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2039, 0x203A,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x203B, 0x203B,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x203C, 0x203C,  ULMBCS_GRP_EXCEPT},
+    {0x2074, 0x2074,  ULMBCS_GRP_KO},
+    {0x207F, 0x207F,  ULMBCS_GRP_EXCEPT},
+    {0x2081, 0x2084,  ULMBCS_GRP_KO},
+    {0x20A4, 0x20AC,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x2103, 0x2109,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2111, 0x2120,  ULMBCS_AMBIGUOUS_SBCS},
+    /*zhujin: upgrade, for regressiont test, spr HKIA4YHTSU*/
+    {0x2121, 0x2121,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2122, 0x2126,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x212B, 0x212B,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2135, 0x2135,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x2153, 0x2154,  ULMBCS_GRP_KO},
+    {0x215B, 0x215E,  ULMBCS_GRP_EXCEPT},
+    {0x2160, 0x2179,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2190, 0x2193,  ULMBCS_AMBIGUOUS_ALL},
+    {0x2194, 0x2195,  ULMBCS_GRP_EXCEPT},
+    {0x2196, 0x2199,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x21A8, 0x21A8,  ULMBCS_GRP_EXCEPT},
+    {0x21B8, 0x21B9,  ULMBCS_GRP_CN},
+    {0x21D0, 0x21D1,  ULMBCS_GRP_EXCEPT},
+    {0x21D2, 0x21D2,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x21D3, 0x21D3,  ULMBCS_GRP_EXCEPT},
+    {0x21D4, 0x21D4,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x21D5, 0x21D5,  ULMBCS_GRP_EXCEPT},
+    {0x21E7, 0x21E7,  ULMBCS_GRP_CN},
+    {0x2200, 0x2200,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2201, 0x2201,  ULMBCS_GRP_EXCEPT},
+    {0x2202, 0x2202,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2203, 0x2203,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2204, 0x2206,  ULMBCS_GRP_EXCEPT},
+    {0x2207, 0x2208,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2209, 0x220A,  ULMBCS_GRP_EXCEPT},
+    {0x220B, 0x220B,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x220F, 0x2215,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2219, 0x2219,  ULMBCS_GRP_EXCEPT},
+    {0x221A, 0x221A,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x221B, 0x221C,  ULMBCS_GRP_EXCEPT},
+    {0x221D, 0x221E,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x221F, 0x221F,  ULMBCS_GRP_EXCEPT},
+    {0x2220, 0x2220,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2223, 0x222A,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x222B, 0x223D,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2245, 0x2248,  ULMBCS_GRP_EXCEPT},
+    {0x224C, 0x224C,  ULMBCS_GRP_TW},
+    {0x2252, 0x2252,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2260, 0x2261,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2262, 0x2265,  ULMBCS_GRP_EXCEPT},
+    {0x2266, 0x226F,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2282, 0x2283,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2284, 0x2285,  ULMBCS_GRP_EXCEPT},
+    {0x2286, 0x2287,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2288, 0x2297,  ULMBCS_GRP_EXCEPT},
+    {0x2299, 0x22BF,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x22C0, 0x22C0,  ULMBCS_GRP_EXCEPT},
+    {0x2310, 0x2310,  ULMBCS_GRP_EXCEPT},
+    {0x2312, 0x2312,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2318, 0x2321,  ULMBCS_GRP_EXCEPT},
+    {0x2318, 0x2321,  ULMBCS_GRP_CN},
+    {0x2460, 0x24E9,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2500, 0x2500,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x2501, 0x2501,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2502, 0x2502,  ULMBCS_AMBIGUOUS_ALL},
+    {0x2503, 0x2503,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x2504, 0x2505,  ULMBCS_GRP_TW},
+    {0x2506, 0x2665,  ULMBCS_AMBIGUOUS_ALL},
+    {0x2666, 0x2666,  ULMBCS_GRP_EXCEPT},
+    {0x2667, 0x2669,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x266A, 0x266A,  ULMBCS_AMBIGUOUS_ALL},
+    {0x266B, 0x266C,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x266D, 0x266D,  ULMBCS_AMBIGUOUS_MBCS},
+    {0x266E, 0x266E,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x266F, 0x266F,  ULMBCS_GRP_JA},
+    {0x2670, 0x2E7F,  ULMBCS_AMBIGUOUS_SBCS},
+    {0x2E80, 0xF861,  ULMBCS_AMBIGUOUS_MBCS},
+    {0xF862, 0xF8FF,  ULMBCS_GRP_EXCEPT},
+    {0xF900, 0xFA2D,  ULMBCS_AMBIGUOUS_MBCS},
+    {0xFB00, 0xFEFF,  ULMBCS_AMBIGUOUS_SBCS},
+    {0xFF01, 0xFFEE,  ULMBCS_AMBIGUOUS_MBCS},
+    {0xFFFF, 0xFFFF,  ULMBCS_GRP_UNICODE}
+};
+   
+static ulmbcs_byte_t 
+FindLMBCSUniRange(UChar uniChar)
+{
+   const struct _UniLMBCSGrpMap * pTable = UniLMBCSGrpMap;
+
+   while (uniChar > pTable->uniEndRange) 
+   {
+      pTable++;
+   }
+
+   if (uniChar >= pTable->uniStartRange) 
+   {
+      return pTable->GrpType;
+   }
+   return ULMBCS_GRP_UNICODE;
+}
+
+/* 
+We also ask the creator of a converter to send in a preferred locale 
+that we can use in resolving ambiguous mappings. They send the locale
+in as a string, and we map it, if possible, to one of the 
+LMBCS groups. We use this table, and the associated code, to 
+do the lookup: */
+
+/**************************************************
+  This table maps locale ID's to LMBCS opt groups.
+  The default return is group 0x01. Note that for
+  performance reasons, the table is sorted in
+  increasing alphabetic order, with the notable
+  exception of zhTW. This is to force the check
+  for Traditonal Chinese before dropping back to
+  Simplified.
+
+  Note too that the Latin-1 groups have been
+  commented out because it's the default, and
+  this shortens the table, allowing a serial
+  search to go quickly.
+ *************************************************/
+
+static const struct _LocaleLMBCSGrpMap
+{
+   const char    *LocaleID;
+   const ulmbcs_byte_t OptGroup;
+} LocaleLMBCSGrpMap[] =
+{
+    {"ar", ULMBCS_GRP_AR},
+    {"be", ULMBCS_GRP_RU},
+    {"bg", ULMBCS_GRP_L2},
+   /* {"ca", ULMBCS_GRP_L1}, */
+    {"cs", ULMBCS_GRP_L2},
+   /* {"da", ULMBCS_GRP_L1}, */
+   /* {"de", ULMBCS_GRP_L1}, */
+    {"el", ULMBCS_GRP_GR},
+   /* {"en", ULMBCS_GRP_L1}, */
+   /* {"es", ULMBCS_GRP_L1}, */
+   /* {"et", ULMBCS_GRP_L1}, */
+   /* {"fi", ULMBCS_GRP_L1}, */
+   /* {"fr", ULMBCS_GRP_L1}, */
+    {"he", ULMBCS_GRP_HE},
+    {"hu", ULMBCS_GRP_L2},
+   /* {"is", ULMBCS_GRP_L1}, */
+   /* {"it", ULMBCS_GRP_L1}, */
+    {"iw", ULMBCS_GRP_HE},
+    {"ja", ULMBCS_GRP_JA},
+    {"ko", ULMBCS_GRP_KO},
+   /* {"lt", ULMBCS_GRP_L1}, */
+   /* {"lv", ULMBCS_GRP_L1}, */
+    {"mk", ULMBCS_GRP_RU},
+   /* {"nl", ULMBCS_GRP_L1}, */
+   /* {"no", ULMBCS_GRP_L1}, */
+    {"pl", ULMBCS_GRP_L2},
+   /* {"pt", ULMBCS_GRP_L1}, */
+    {"ro", ULMBCS_GRP_L2},
+    {"ru", ULMBCS_GRP_RU},
+    {"sh", ULMBCS_GRP_L2},
+    {"sk", ULMBCS_GRP_L2},
+    {"sl", ULMBCS_GRP_L2},
+    {"sq", ULMBCS_GRP_L2},
+    {"sr", ULMBCS_GRP_RU},
+   /* {"sv", ULMBCS_GRP_L1}, */
+    {"th", ULMBCS_GRP_TH},
+    {"tr", ULMBCS_GRP_TR},
+    {"uk", ULMBCS_GRP_RU},
+   /* {"vi", ULMBCS_GRP_L1}, */
+    {"zhTW", ULMBCS_GRP_TW},
+    {"zh", ULMBCS_GRP_CN},
+    {NULL, ULMBCS_GRP_L1}
+};
+
+
+static ulmbcs_byte_t 
+FindLMBCSLocale(const char *LocaleID)
+{
+   const struct _LocaleLMBCSGrpMap *pTable = LocaleLMBCSGrpMap;
+
+   if ((!LocaleID) || (!*LocaleID)) 
+   {
+      return 0;
+   }
+
+   while (pTable->LocaleID)
+   {
+      if (*pTable->LocaleID == *LocaleID) /* Check only first char for speed */
+      {
+         /* First char matches - check whole name, for entry-length */
+         if (uprv_strncmp(pTable->LocaleID, LocaleID, strlen(pTable->LocaleID)) == 0)
+            return pTable->OptGroup;
+      }
+      else
+      if (*pTable->LocaleID > *LocaleID) /* Sorted alphabetically - exit */
+         break;
+      pTable++;
+   }
+   return ULMBCS_GRP_L1;
+}
+
+
+/* 
+  Before we get to the main body of code, here's how we hook up to the rest 
+  of ICU. ICU converters are required to define a structure that includes 
+  some function pointers, and some common data, in the style of a C++
+  vtable. There is also room in there for converter-specific data. LMBCS
+  uses that converter-specific data to keep track of the 12 subconverters
+  we use, the optimization group, and the group (if any) that matches the 
+  locale. We have one structure instantiated for each of the 12 possible
+  optimization groups. To avoid typos & to avoid boring the reader, we 
+  put the declarations of these structures and functions into macros. To see 
+  the definitions of these structures, see unicode\ucnv_bld.h
+*/
+
+typedef struct
+  {
+    UConverterSharedData *OptGrpConverter[ULMBCS_GRP_LAST+1];    /* Converter per Opt. grp. */
+    uint8_t    OptGroup;                  /* default Opt. grp. for this LMBCS session */
+    uint8_t    localeConverterIndex;      /* reasonable locale match for index */
+  }
+UConverterDataLMBCS;
+
+static void _LMBCSClose(UConverter * _this);
+
+#define DECLARE_LMBCS_DATA(n) \
+static const UConverterImpl _LMBCSImpl##n={\
+    UCNV_LMBCS_##n,\
+    NULL,NULL,\
+    _LMBCSOpen##n,\
+    _LMBCSClose,\
+    NULL,\
+    _LMBCSToUnicodeWithOffsets,\
+    _LMBCSToUnicodeWithOffsets,\
+    _LMBCSFromUnicode,\
+    _LMBCSFromUnicode,\
+    NULL,\
+    NULL,\
+    NULL,\
+    NULL,\
+    _LMBCSSafeClone,\
+    ucnv_getCompleteUnicodeSet\
+};\
+static const UConverterStaticData _LMBCSStaticData##n={\
+  sizeof(UConverterStaticData),\
+ "LMBCS-"  #n,\
+    0, UCNV_IBM, UCNV_LMBCS_##n, 1, 3,\
+    { 0x3f, 0, 0, 0 },1,FALSE,FALSE,0,0,{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} \
+};\
+const UConverterSharedData _LMBCSData##n={\
+    sizeof(UConverterSharedData), ~((uint32_t) 0),\
+    NULL, NULL, &_LMBCSStaticData##n, FALSE, &_LMBCSImpl##n, \
+    0 \
+};
+
+ /* The only function we needed to duplicate 12 times was the 'open'
+function, which will do basically the same thing except set a  different
+optimization group. So, we put the common stuff into a worker function, 
+and set up another macro to stamp out the 12 open functions:*/
+#define DEFINE_LMBCS_OPEN(n) \
+static void \
+   _LMBCSOpen##n(UConverter* _this, UConverterLoadArgs* pArgs, UErrorCode* err) \
+{ _LMBCSOpenWorker(_this, pArgs, err, n); }
+
+
+
+/* Here's the open worker & the common close function */
+static void 
+_LMBCSOpenWorker(UConverter*  _this,
+                 UConverterLoadArgs *pArgs,
+                 UErrorCode*  err,
+                 ulmbcs_byte_t OptGroup)
+{
+    UConverterDataLMBCS * extraInfo = _this->extraInfo =
+        (UConverterDataLMBCS*)uprv_malloc (sizeof (UConverterDataLMBCS));
+    if(extraInfo != NULL)
+    {
+        UConverterNamePieces stackPieces;
+        UConverterLoadArgs stackArgs={ (int32_t)sizeof(UConverterLoadArgs) };
+        ulmbcs_byte_t i;
+
+        uprv_memset(extraInfo, 0, sizeof(UConverterDataLMBCS));
+
+        stackArgs.onlyTestIsLoadable = pArgs->onlyTestIsLoadable;
+
+        for (i=0; i <= ULMBCS_GRP_LAST && U_SUCCESS(*err); i++)         
+        {
+            if(OptGroupByteToCPName[i] != NULL) {
+                extraInfo->OptGrpConverter[i] = ucnv_loadSharedData(OptGroupByteToCPName[i], &stackPieces, &stackArgs, err);
+            }
+        }
+
+        if(U_FAILURE(*err) || pArgs->onlyTestIsLoadable) {
+            _LMBCSClose(_this);
+            return;
+        }
+        extraInfo->OptGroup = OptGroup;
+        extraInfo->localeConverterIndex = FindLMBCSLocale(pArgs->locale);
+    }
+    else
+    {
+        *err = U_MEMORY_ALLOCATION_ERROR;
+    }
+}
+
+static void 
+_LMBCSClose(UConverter *   _this) 
+{
+    if (_this->extraInfo != NULL)
+    {
+        ulmbcs_byte_t Ix;
+        UConverterDataLMBCS * extraInfo = (UConverterDataLMBCS *) _this->extraInfo;
+
+        for (Ix=0; Ix <= ULMBCS_GRP_LAST; Ix++)
+        {
+           if (extraInfo->OptGrpConverter[Ix] != NULL)
+              ucnv_unloadSharedDataIfReady(extraInfo->OptGrpConverter[Ix]);
+        }
+        if (!_this->isExtraLocal) {
+            uprv_free (_this->extraInfo);
+            _this->extraInfo = NULL;
+        }
+    }
+}
+
+typedef struct LMBCSClone {
+    UConverter cnv;
+    UConverterDataLMBCS lmbcs;
+} LMBCSClone;
+
+static UConverter * 
+_LMBCSSafeClone(const UConverter *cnv, 
+                void *stackBuffer, 
+                int32_t *pBufferSize, 
+                UErrorCode *status) {
+    LMBCSClone *newLMBCS;
+    UConverterDataLMBCS *extraInfo;
+    int32_t i;
+
+    if(*pBufferSize<=0) {
+        *pBufferSize=(int32_t)sizeof(LMBCSClone);
+        return NULL;
+    }
+
+    extraInfo=(UConverterDataLMBCS *)cnv->extraInfo;
+    newLMBCS=(LMBCSClone *)stackBuffer;
+
+    /* ucnv.c/ucnv_safeClone() copied the main UConverter already */
+
+    uprv_memcpy(&newLMBCS->lmbcs, extraInfo, sizeof(UConverterDataLMBCS));
+
+    /* share the subconverters */
+    for(i = 0; i <= ULMBCS_GRP_LAST; ++i) {
+        if(extraInfo->OptGrpConverter[i] != NULL) {
+            ucnv_incrementRefCount(extraInfo->OptGrpConverter[i]);
+        }
+    }
+
+    newLMBCS->cnv.extraInfo = &newLMBCS->lmbcs;
+    newLMBCS->cnv.isExtraLocal = TRUE;
+    return &newLMBCS->cnv;
+}
+
+/*
+ * There used to be a _LMBCSGetUnicodeSet() function here (up to svn revision 20117)
+ * which added all code points except for U+F6xx
+ * because those cannot be represented in the Unicode group.
+ * However, it turns out that windows-950 has roundtrips for all of U+F6xx
+ * which means that LMBCS can convert all Unicode code points after all.
+ * We now simply use ucnv_getCompleteUnicodeSet().
+ *
+ * This may need to be looked at again as Lotus uses _LMBCSGetUnicodeSet(). (091216)
+ */
+
+/* 
+   Here's the basic helper function that we use when converting from
+   Unicode to LMBCS, and we suspect that a Unicode character will fit into 
+   one of the 12 groups. The return value is the number of bytes written 
+   starting at pStartLMBCS (if any).
+*/
+
+static size_t
+LMBCSConversionWorker (
+   UConverterDataLMBCS * extraInfo,    /* subconverters, opt & locale groups */
+   ulmbcs_byte_t group,                /* The group to try */
+   ulmbcs_byte_t  * pStartLMBCS,              /* where to put the results */
+   UChar * pUniChar,                   /* The input unicode character */
+   ulmbcs_byte_t * lastConverterIndex, /* output: track last successful group used */
+   UBool * groups_tried                /* output: track any unsuccessful groups */
+)   
+{
+   ulmbcs_byte_t  * pLMBCS = pStartLMBCS;
+   UConverterSharedData * xcnv = extraInfo->OptGrpConverter[group];
+
+   int bytesConverted;
+   uint32_t value;
+   ulmbcs_byte_t firstByte;
+
+   U_ASSERT(xcnv);
+   U_ASSERT(group<ULMBCS_GRP_UNICODE);
+
+   bytesConverted = ucnv_MBCSFromUChar32(xcnv, *pUniChar, &value, FALSE);
+
+   /* get the first result byte */
+   if(bytesConverted > 0) {
+      firstByte = (ulmbcs_byte_t)(value >> ((bytesConverted - 1) * 8));
+   } else {
+      /* most common failure mode is an unassigned character */
+      groups_tried[group] = TRUE;
+      return 0;
+   }
+
+   *lastConverterIndex = group;
+
+   /* All initial byte values in lower ascii range should have been caught by now,
+      except with the exception group.
+    */
+   U_ASSERT((firstByte <= ULMBCS_C0END) || (firstByte >= ULMBCS_C1START) || (group == ULMBCS_GRP_EXCEPT));
+   
+   /* use converted data: first write 0, 1 or two group bytes */
+   if (group != ULMBCS_GRP_EXCEPT && extraInfo->OptGroup != group)
+   {
+      *pLMBCS++ = group;
+      if (bytesConverted == 1 && group >= ULMBCS_DOUBLEOPTGROUP_START)
+      {
+         *pLMBCS++ = group;
+      }
+   }
+
+  /* don't emit control chars */
+   if ( bytesConverted == 1 && firstByte < 0x20 )
+      return 0;
+
+
+   /* then move over the converted data */
+   switch(bytesConverted)
+   {
+   case 4:
+      *pLMBCS++ = (ulmbcs_byte_t)(value >> 24);
+   case 3:
+      *pLMBCS++ = (ulmbcs_byte_t)(value >> 16);
+   case 2:
+      *pLMBCS++ = (ulmbcs_byte_t)(value >> 8);
+   case 1:
+      *pLMBCS++ = (ulmbcs_byte_t)value;
+   default:
+      /* will never occur */
+      break;
+   }
+
+   return (pLMBCS - pStartLMBCS);
+}
+
+
+/* This is a much simpler version of above, when we 
+know we are writing LMBCS using the Unicode group
+*/
+static size_t 
+LMBCSConvertUni(ulmbcs_byte_t * pLMBCS, UChar uniChar)  
+{
+     /* encode into LMBCS Unicode range */
+   uint8_t LowCh =   (uint8_t)(uniChar & 0x00FF);
+   uint8_t HighCh  = (uint8_t)(uniChar >> 8);
+
+   *pLMBCS++ = ULMBCS_GRP_UNICODE;
+
+   if (LowCh == 0)
+   {
+      *pLMBCS++ = ULMBCS_UNICOMPATZERO;
+      *pLMBCS++ = HighCh;
+   }
+   else
+   {
+      *pLMBCS++ = HighCh;
+      *pLMBCS++ = LowCh;
+   }
+   return ULMBCS_UNICODE_SIZE;
+}
+
+
+
+/* The main Unicode to LMBCS conversion function */
+static void 
+_LMBCSFromUnicode(UConverterFromUnicodeArgs*     args,
+                  UErrorCode*     err)
+{
+   ulmbcs_byte_t lastConverterIndex = 0;
+   UChar uniChar;
+   ulmbcs_byte_t  LMBCS[ULMBCS_CHARSIZE_MAX];
+   ulmbcs_byte_t  * pLMBCS;
+   int32_t bytes_written;
+   UBool groups_tried[ULMBCS_GRP_LAST+1];
+   UConverterDataLMBCS * extraInfo = (UConverterDataLMBCS *) args->converter->extraInfo;
+   int sourceIndex = 0; 
+
+   /* Basic strategy: attempt to fill in local LMBCS 1-char buffer.(LMBCS)
+      If that succeeds, see if it will all fit into the target & copy it over 
+      if it does.
+
+      We try conversions in the following order:
+
+      1. Single-byte ascii & special fixed control chars (&null)
+      2. Look up group in table & try that (could be 
+            A) Unicode group
+            B) control group,
+            C) national encoding, 
+               or ambiguous SBCS or MBCS group (on to step 4...)
+        
+      3. If its ambiguous, try this order:
+         A) The optimization group
+         B) The locale group
+         C) The last group that succeeded with this string.
+         D) every other group that's relevent (single or double)
+         E) If its single-byte ambiguous, try the exceptions group
+
+      4. And as a grand fallback: Unicode
+   */
+
+    /*Fix for SPR#DJOE66JFN3 (Lotus)*/
+    ulmbcs_byte_t OldConverterIndex = 0;
+
+   while (args->source < args->sourceLimit && !U_FAILURE(*err))
+   {
+      /*Fix for SPR#DJOE66JFN3 (Lotus)*/
+      OldConverterIndex = extraInfo->localeConverterIndex;
+
+      if (args->target >= args->targetLimit)
+      {
+         *err = U_BUFFER_OVERFLOW_ERROR;
+         break;
+      }
+      uniChar = *(args->source);
+      bytes_written = 0;
+      pLMBCS = LMBCS;
+
+      /* check cases in rough order of how common they are, for speed */
+
+      /* single byte matches: strategy 1 */
+      /*Fix for SPR#DJOE66JFN3 (Lotus)*/
+      if((uniChar>=0x80) && (uniChar<=0xff)
+      /*Fix for SPR#JUYA6XAERU and TSAO7GL5NK (Lotus)*/ &&(uniChar!=0xB1) &&(uniChar!=0xD7) &&(uniChar!=0xF7)
+        &&(uniChar!=0xB0) &&(uniChar!=0xB4) &&(uniChar!=0xB6) &&(uniChar!=0xA7) &&(uniChar!=0xA8))
+      {
+            extraInfo->localeConverterIndex = ULMBCS_GRP_L1;
+      }
+      if (((uniChar > ULMBCS_C0END) && (uniChar < ULMBCS_C1START)) ||
+          uniChar == 0 || uniChar == ULMBCS_HT || uniChar == ULMBCS_CR || 
+          uniChar == ULMBCS_LF || uniChar == ULMBCS_123SYSTEMRANGE 
+          )
+      {
+         *pLMBCS++ = (ulmbcs_byte_t ) uniChar;
+         bytes_written = 1;
+      }
+
+
+      if (!bytes_written) 
+      {
+         /* Check by UNICODE range (Strategy 2) */
+         ulmbcs_byte_t group = FindLMBCSUniRange(uniChar);
+         
+         if (group == ULMBCS_GRP_UNICODE)  /* (Strategy 2A) */
+         {
+            pLMBCS += LMBCSConvertUni(pLMBCS,uniChar);
+            
+            bytes_written = (int32_t)(pLMBCS - LMBCS);
+         }
+         else if (group == ULMBCS_GRP_CTRL)  /* (Strategy 2B) */
+         {
+            /* Handle control characters here */
+            if (uniChar <= ULMBCS_C0END)
+            {
+               *pLMBCS++ = ULMBCS_GRP_CTRL;
+               *pLMBCS++ = (ulmbcs_byte_t)(ULMBCS_CTRLOFFSET + uniChar);
+            }
+            else if (uniChar >= ULMBCS_C1START && uniChar <= ULMBCS_C1START + ULMBCS_CTRLOFFSET)
+            {
+               *pLMBCS++ = ULMBCS_GRP_CTRL;
+               *pLMBCS++ = (ulmbcs_byte_t ) (uniChar & 0x00FF);
+            }
+            bytes_written = (int32_t)(pLMBCS - LMBCS);
+         }
+         else if (group < ULMBCS_GRP_UNICODE)  /* (Strategy 2C) */
+         {
+            /* a specific converter has been identified - use it */
+            bytes_written = (int32_t)LMBCSConversionWorker (
+                              extraInfo, group, pLMBCS, &uniChar, 
+                              &lastConverterIndex, groups_tried);
+         }
+         if (!bytes_written)    /* the ambiguous group cases  (Strategy 3) */
+         {
+            uprv_memset(groups_tried, 0, sizeof(groups_tried));
+
+            /* check for non-default optimization group (Strategy 3A )*/
+            if ((extraInfo->OptGroup != 1) && (ULMBCS_AMBIGUOUS_MATCH(group, extraInfo->OptGroup)))
+            {
+                /*zhujin: upgrade, merge #39299 here (Lotus) */
+                /*To make R5 compatible translation, look for exceptional group first for non-DBCS*/
+
+                if(extraInfo->localeConverterIndex < ULMBCS_DOUBLEOPTGROUP_START)
+                {
+                  bytes_written = LMBCSConversionWorker (extraInfo,
+                     ULMBCS_GRP_L1, pLMBCS, &uniChar,
+                     &lastConverterIndex, groups_tried);
+
+                  if(!bytes_written)
+                  {
+                     bytes_written = LMBCSConversionWorker (extraInfo,
+                         ULMBCS_GRP_EXCEPT, pLMBCS, &uniChar,
+                         &lastConverterIndex, groups_tried);
+                  }
+                  if(!bytes_written)
+                  {
+                      bytes_written = LMBCSConversionWorker (extraInfo,
+                          extraInfo->localeConverterIndex, pLMBCS, &uniChar,
+                          &lastConverterIndex, groups_tried);
+                  }
+                }
+                else
+                {
+                     bytes_written = LMBCSConversionWorker (extraInfo,
+                         extraInfo->localeConverterIndex, pLMBCS, &uniChar,
+                         &lastConverterIndex, groups_tried);
+                }
+            }
+            /* check for locale optimization group (Strategy 3B) */
+            if (!bytes_written && (extraInfo->localeConverterIndex) && (ULMBCS_AMBIGUOUS_MATCH(group, extraInfo->localeConverterIndex)))
+            {
+                bytes_written = (int32_t)LMBCSConversionWorker (extraInfo,
+                        extraInfo->localeConverterIndex, pLMBCS, &uniChar, &lastConverterIndex, groups_tried);
+            }
+            /* check for last optimization group used for this string (Strategy 3C) */
+            if (!bytes_written && (lastConverterIndex) && (ULMBCS_AMBIGUOUS_MATCH(group, lastConverterIndex)))
+            {
+                bytes_written = (int32_t)LMBCSConversionWorker (extraInfo,
+                        lastConverterIndex, pLMBCS, &uniChar, &lastConverterIndex, groups_tried);
+            }
+            if (!bytes_written)
+            {
+               /* just check every possible matching converter (Strategy 3D) */ 
+               ulmbcs_byte_t grp_start;
+               ulmbcs_byte_t grp_end;  
+               ulmbcs_byte_t grp_ix;
+               grp_start = (ulmbcs_byte_t)((group == ULMBCS_AMBIGUOUS_MBCS) 
+                        ? ULMBCS_DOUBLEOPTGROUP_START 
+                        :  ULMBCS_GRP_L1);
+               grp_end = (ulmbcs_byte_t)((group == ULMBCS_AMBIGUOUS_MBCS) 
+                        ? ULMBCS_GRP_LAST 
+                        :  ULMBCS_GRP_TH);
+               if(group == ULMBCS_AMBIGUOUS_ALL)
+               {
+                   grp_start = ULMBCS_GRP_L1;
+                   grp_end = ULMBCS_GRP_LAST;
+               }
+               for (grp_ix = grp_start;
+                   grp_ix <= grp_end && !bytes_written; 
+                    grp_ix++)
+               {
+                  if (extraInfo->OptGrpConverter [grp_ix] && !groups_tried [grp_ix])
+                  {
+                     bytes_written = (int32_t)LMBCSConversionWorker (extraInfo,
+                       grp_ix, pLMBCS, &uniChar, 
+                       &lastConverterIndex, groups_tried);
+                  }
+               }
+                /* a final conversion fallback to the exceptions group if its likely 
+                     to be single byte  (Strategy 3E) */
+               if (!bytes_written && grp_start == ULMBCS_GRP_L1)
+               {
+                  bytes_written = (int32_t)LMBCSConversionWorker (extraInfo,
+                     ULMBCS_GRP_EXCEPT, pLMBCS, &uniChar, 
+                     &lastConverterIndex, groups_tried);
+               }
+            }
+            /* all of our other strategies failed. Fallback to Unicode. (Strategy 4)*/
+            if (!bytes_written)
+            {
+
+               pLMBCS += LMBCSConvertUni(pLMBCS, uniChar);
+               bytes_written = (int32_t)(pLMBCS - LMBCS);
+            }
+         }
+      }
+  
+      /* we have a translation. increment source and write as much as posible to target */
+      args->source++;
+      pLMBCS = LMBCS;
+      while (args->target < args->targetLimit && bytes_written--)
+      {
+         *(args->target)++ = *pLMBCS++;
+         if (args->offsets)
+         {
+            *(args->offsets)++ = sourceIndex;
+         }
+      }
+      sourceIndex++;
+      if (bytes_written > 0)
+      {
+         /* write any bytes that didn't fit in target to the error buffer,
+            common code will move this to target if we get called back with
+            enough target room
+         */
+         uint8_t * pErrorBuffer = args->converter->charErrorBuffer;
+         *err = U_BUFFER_OVERFLOW_ERROR;
+         args->converter->charErrorBufferLength = (int8_t)bytes_written;
+         while (bytes_written--)
+         {
+            *pErrorBuffer++ = *pLMBCS++;
+         }
+      }
+      /*Fix for SPR#DJOE66JFN3 (Lotus)*/
+      extraInfo->localeConverterIndex = OldConverterIndex;
+   }     
+}
+
+
+/* Now, the Unicode from LMBCS section */
+
+
+/* A function to call when we are looking at the Unicode group byte in LMBCS */
+static UChar
+GetUniFromLMBCSUni(char const ** ppLMBCSin)  /* Called with LMBCS-style Unicode byte stream */
+{
+   uint8_t  HighCh = *(*ppLMBCSin)++;  /* Big-endian Unicode in LMBCS compatibility group*/
+   uint8_t  LowCh  = *(*ppLMBCSin)++;
+
+   if (HighCh == ULMBCS_UNICOMPATZERO ) 
+   {
+      HighCh = LowCh;
+      LowCh = 0; /* zero-byte in LSB special character */
+   }
+   return (UChar)((HighCh << 8) | LowCh);
+}
+
+
+
+/* CHECK_SOURCE_LIMIT: Helper macro to verify that there are at least'index' 
+   bytes left in source up to  sourceLimit.Errors appropriately if not.
+   If we reach the limit, then update the source pointer to there to consume
+   all input as required by ICU converter semantics.
+*/
+
+#define CHECK_SOURCE_LIMIT(index) \
+     if (args->source+index > args->sourceLimit){\
+         *err = U_TRUNCATED_CHAR_FOUND;\
+         args->source = args->sourceLimit;\
+         return 0xffff;}
+
+/* Return the Unicode representation for the current LMBCS character */
+
+static UChar32 
+_LMBCSGetNextUCharWorker(UConverterToUnicodeArgs*   args,
+                         UErrorCode*   err)
+{
+    UChar32 uniChar = 0;    /* an output UNICODE char */
+    ulmbcs_byte_t   CurByte; /* A byte from the input stream */
+
+    /* error check */
+    if (args->source >= args->sourceLimit)
+    {
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0xffff;
+    }
+    /* Grab first byte & save address for error recovery */
+    CurByte = *((ulmbcs_byte_t  *) (args->source++));
+   
+    /*
+    * at entry of each if clause:
+    * 1. 'CurByte' points at the first byte of a LMBCS character
+    * 2. '*source'points to the next byte of the source stream after 'CurByte' 
+    *
+    * the job of each if clause is:
+    * 1. set '*source' to point at the beginning of next char (nop if LMBCS char is only 1 byte)
+    * 2. set 'uniChar' up with the right Unicode value, or set 'err' appropriately
+    */
+   
+    /* First lets check the simple fixed values. */
+
+    if(((CurByte > ULMBCS_C0END) && (CurByte < ULMBCS_C1START)) /* ascii range */
+    ||  (CurByte == 0) 
+    ||  CurByte == ULMBCS_HT || CurByte == ULMBCS_CR 
+    ||  CurByte == ULMBCS_LF || CurByte == ULMBCS_123SYSTEMRANGE)
+    {
+        uniChar = CurByte;
+    }
+    else  
+    {
+        UConverterDataLMBCS * extraInfo;
+        ulmbcs_byte_t group; 
+        UConverterSharedData *cnv; 
+        
+        if (CurByte == ULMBCS_GRP_CTRL)  /* Control character group - no opt group update */
+        {
+            ulmbcs_byte_t  C0C1byte;
+            CHECK_SOURCE_LIMIT(1);
+            C0C1byte = *(args->source)++;
+            uniChar = (C0C1byte < ULMBCS_C1START) ? C0C1byte - ULMBCS_CTRLOFFSET : C0C1byte;
+        }
+        else 
+        if (CurByte == ULMBCS_GRP_UNICODE) /* Unicode compatibility group: BigEndian UTF16 */
+        {
+            CHECK_SOURCE_LIMIT(2);
+     
+            /* don't check for error indicators fffe/ffff below */
+            return GetUniFromLMBCSUni(&(args->source));
+        }
+        else if (CurByte <= ULMBCS_CTRLOFFSET)  
+        {
+            group = CurByte;                   /* group byte is in the source */
+            extraInfo = (UConverterDataLMBCS *) args->converter->extraInfo;
+            if (group > ULMBCS_GRP_LAST || (cnv = extraInfo->OptGrpConverter[group]) == NULL)
+            {
+                /* this is not a valid group byte - no converter*/
+                *err = U_INVALID_CHAR_FOUND;
+            }      
+            else if (group >= ULMBCS_DOUBLEOPTGROUP_START)    /* double byte conversion */
+            {
+
+                CHECK_SOURCE_LIMIT(2);
+
+                /* check for LMBCS doubled-group-byte case */
+                if (*args->source == group) {
+                    /* single byte */
+                    ++args->source;
+                    uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, args->source, 1, FALSE);
+                    ++args->source;
+                } else {
+                    /* double byte */
+                    uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, args->source, 2, FALSE);
+                    args->source += 2;
+                }
+            }
+            else {                                  /* single byte conversion */
+                CHECK_SOURCE_LIMIT(1);
+                CurByte = *(args->source)++;
+        
+                if (CurByte >= ULMBCS_C1START)
+                {
+                    uniChar = _MBCS_SINGLE_SIMPLE_GET_NEXT_BMP(cnv, CurByte);
+                }
+                else
+                {
+                    /* The non-optimizable oddballs where there is an explicit byte 
+                    * AND the second byte is not in the upper ascii range
+                    */
+                    char bytes[2];
+
+                    extraInfo = (UConverterDataLMBCS *) args->converter->extraInfo;
+                    cnv = extraInfo->OptGrpConverter [ULMBCS_GRP_EXCEPT];  
+        
+                    /* Lookup value must include opt group */
+                    bytes[0] = group;
+                    bytes[1] = CurByte;
+                    uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, bytes, 2, FALSE);
+                }
+            }
+        }
+        else if (CurByte >= ULMBCS_C1START) /* group byte is implicit */
+        {
+            extraInfo = (UConverterDataLMBCS *) args->converter->extraInfo;
+            group = extraInfo->OptGroup;
+            cnv = extraInfo->OptGrpConverter[group];
+            if (group >= ULMBCS_DOUBLEOPTGROUP_START)    /* double byte conversion */
+            {
+                if (!ucnv_MBCSIsLeadByte(cnv, CurByte))
+                {
+                    CHECK_SOURCE_LIMIT(0);
+
+                    /* let the MBCS conversion consume CurByte again */
+                    uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, args->source - 1, 1, FALSE);
+                }
+                else
+                {
+                    CHECK_SOURCE_LIMIT(1);
+                    /* let the MBCS conversion consume CurByte again */
+                    uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, args->source - 1, 2, FALSE);
+                    ++args->source;
+                }
+            }
+            else                                   /* single byte conversion */
+            {
+                uniChar = _MBCS_SINGLE_SIMPLE_GET_NEXT_BMP(cnv, CurByte);
+            }
+        }
+    }
+    return uniChar;
+}
+
+
+/* The exported function that converts lmbcs to one or more
+   UChars - currently UTF-16
+*/
+static void 
+_LMBCSToUnicodeWithOffsets(UConverterToUnicodeArgs*    args,
+                     UErrorCode*    err)
+{
+   char LMBCS [ULMBCS_CHARSIZE_MAX];
+   UChar uniChar;    /* one output UNICODE char */
+   const char * saveSource; /* beginning of current code point */
+   const char * pStartLMBCS = args->source;  /* beginning of whole string */
+   const char * errSource = NULL; /* pointer to actual input in case an error occurs */
+   int8_t savebytes = 0;
+
+   /* Process from source to limit, or until error */
+   while (U_SUCCESS(*err) && args->sourceLimit > args->source && args->targetLimit > args->target)
+   {
+      saveSource = args->source; /* beginning of current code point */
+
+      if (args->converter->toULength) /* reassemble char from previous call */
+      {
+        const char *saveSourceLimit; 
+        size_t size_old = args->converter->toULength;
+
+         /* limit from source is either remainder of temp buffer, or user limit on source */
+        size_t size_new_maybe_1 = sizeof(LMBCS) - size_old;
+        size_t size_new_maybe_2 = args->sourceLimit - args->source;
+        size_t size_new = (size_new_maybe_1 < size_new_maybe_2) ? size_new_maybe_1 : size_new_maybe_2;
+         
+      
+        uprv_memcpy(LMBCS, args->converter->toUBytes, size_old);
+        uprv_memcpy(LMBCS + size_old, args->source, size_new);
+        saveSourceLimit = args->sourceLimit;
+        args->source = errSource = LMBCS;
+        args->sourceLimit = LMBCS+size_old+size_new;
+        savebytes = (int8_t)(size_old+size_new);
+        uniChar = (UChar) _LMBCSGetNextUCharWorker(args, err);
+        args->source = saveSource + ((args->source - LMBCS) - size_old);
+        args->sourceLimit = saveSourceLimit;
+
+        if (*err == U_TRUNCATED_CHAR_FOUND)
+        {
+            /* evil special case: source buffers so small a char spans more than 2 buffers */
+            args->converter->toULength = savebytes;
+            uprv_memcpy(args->converter->toUBytes, LMBCS, savebytes);
+            args->source = args->sourceLimit;
+            *err = U_ZERO_ERROR;
+            return;
+         }
+         else
+         {
+            /* clear the partial-char marker */
+            args->converter->toULength = 0;
+         }
+      }
+      else
+      {
+         errSource = saveSource;
+         uniChar = (UChar) _LMBCSGetNextUCharWorker(args, err);
+         savebytes = (int8_t)(args->source - saveSource);
+      }
+      if (U_SUCCESS(*err))
+      {
+         if (uniChar < 0xfffe)
+         {
+            *(args->target)++ = uniChar;
+            if(args->offsets)
+            {
+               *(args->offsets)++ = (int32_t)(saveSource - pStartLMBCS);
+            }
+         }
+         else if (uniChar == 0xfffe)
+         {
+            *err = U_INVALID_CHAR_FOUND;
+         }
+         else /* if (uniChar == 0xffff) */
+         {
+            *err = U_ILLEGAL_CHAR_FOUND;
+         }
+      }
+   }
+   /* if target ran out before source, return U_BUFFER_OVERFLOW_ERROR */
+   if (U_SUCCESS(*err) && args->sourceLimit > args->source && args->targetLimit <= args->target)
+   {
+      *err = U_BUFFER_OVERFLOW_ERROR;
+   }
+   else if (U_FAILURE(*err)) 
+   {
+      /* If character incomplete or unmappable/illegal, store it in toUBytes[] */
+      args->converter->toULength = savebytes;
+      if (savebytes > 0) {
+         uprv_memcpy(args->converter->toUBytes, errSource, savebytes);
+      }
+      if (*err == U_TRUNCATED_CHAR_FOUND) {
+         *err = U_ZERO_ERROR;
+      }
+   }
+}
+
+/* And now, the macroized declarations of data & functions: */
+DEFINE_LMBCS_OPEN(1)
+DEFINE_LMBCS_OPEN(2)
+DEFINE_LMBCS_OPEN(3)
+DEFINE_LMBCS_OPEN(4)
+DEFINE_LMBCS_OPEN(5)
+DEFINE_LMBCS_OPEN(6)
+DEFINE_LMBCS_OPEN(8)
+DEFINE_LMBCS_OPEN(11)
+DEFINE_LMBCS_OPEN(16)
+DEFINE_LMBCS_OPEN(17)
+DEFINE_LMBCS_OPEN(18)
+DEFINE_LMBCS_OPEN(19)
+
+
+DECLARE_LMBCS_DATA(1)
+DECLARE_LMBCS_DATA(2)
+DECLARE_LMBCS_DATA(3)
+DECLARE_LMBCS_DATA(4)
+DECLARE_LMBCS_DATA(5)
+DECLARE_LMBCS_DATA(6)
+DECLARE_LMBCS_DATA(8)
+DECLARE_LMBCS_DATA(11)
+DECLARE_LMBCS_DATA(16)
+DECLARE_LMBCS_DATA(17)
+DECLARE_LMBCS_DATA(18)
+DECLARE_LMBCS_DATA(19)
+
+#endif /* #if !UCONFIG_NO_LEGACY_CONVERSION */
diff --git a/source/common/ucnv_set.c b/source/common/ucnv_set.c
new file mode 100644
index 0000000..3d8d392
--- /dev/null
+++ b/source/common/ucnv_set.c
@@ -0,0 +1,68 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2003-2007, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  ucnv_set.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2004sep07
+*   created by: Markus W. Scherer
+*
+*   Conversion API functions using USet (ucnv_getUnicodeSet())
+*   moved here from ucnv.c for removing the dependency of other ucnv_
+*   implementation functions on the USet implementation.
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uset.h"
+#include "unicode/ucnv.h"
+#include "ucnv_bld.h"
+#include "uset_imp.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+U_CAPI void U_EXPORT2
+ucnv_getUnicodeSet(const UConverter *cnv,
+                   USet *setFillIn,
+                   UConverterUnicodeSet whichSet,
+                   UErrorCode *pErrorCode) {
+    /* argument checking */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return;
+    }
+    if(cnv==NULL || setFillIn==NULL || whichSet<UCNV_ROUNDTRIP_SET || UCNV_SET_COUNT<=whichSet) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    /* does this converter support this function? */
+    if(cnv->sharedData->impl->getUnicodeSet==NULL) {
+        *pErrorCode=U_UNSUPPORTED_ERROR;
+        return;
+    }
+
+    {
+        USetAdder sa={
+            NULL,
+            uset_add,
+            uset_addRange,
+            uset_addString,
+            uset_remove,
+            uset_removeRange
+        };
+        sa.set=setFillIn;
+
+        /* empty the set */
+        uset_clear(setFillIn);
+
+        /* call the converter to add the code points it supports */
+        cnv->sharedData->impl->getUnicodeSet(cnv, &sa, whichSet, pErrorCode);
+    }
+}
+
+#endif
diff --git a/source/common/ucnv_u16.c b/source/common/ucnv_u16.c
new file mode 100644
index 0000000..a2044aa
--- /dev/null
+++ b/source/common/ucnv_u16.c
@@ -0,0 +1,1561 @@
+/*  
+**********************************************************************
+*   Copyright (C) 2002-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   file name:  ucnv_u16.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002jul01
+*   created by: Markus W. Scherer
+*
+*   UTF-16 converter implementation. Used to be in ucnv_utf.c.
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ucnv.h"
+#include "ucnv_bld.h"
+#include "ucnv_cnv.h"
+#include "cmemory.h"
+
+enum {
+    UCNV_NEED_TO_WRITE_BOM=1
+};
+
+/*
+ * The UTF-16 toUnicode implementation is also used for the Java-specific
+ * "with BOM" variants of UTF-16BE and UTF-16LE.
+ */
+static void
+_UTF16ToUnicodeWithOffsets(UConverterToUnicodeArgs *pArgs,
+                           UErrorCode *pErrorCode);
+
+/* UTF-16BE ----------------------------------------------------------------- */
+
+#if U_IS_BIG_ENDIAN
+#   define _UTF16PEFromUnicodeWithOffsets   _UTF16BEFromUnicodeWithOffsets
+#else
+#   define _UTF16PEFromUnicodeWithOffsets   _UTF16LEFromUnicodeWithOffsets
+#endif
+
+
+static void
+_UTF16BEFromUnicodeWithOffsets(UConverterFromUnicodeArgs *pArgs,
+                               UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const UChar *source;
+    char *target;
+    int32_t *offsets;
+
+    uint32_t targetCapacity, length, sourceIndex;
+    UChar c, trail;
+    char overflow[4];
+
+    source=pArgs->source;
+    length=(int32_t)(pArgs->sourceLimit-source);
+    if(length<=0) {
+        /* no input, nothing to do */
+        return;
+    }
+
+    cnv=pArgs->converter;
+
+    /* write the BOM if necessary */
+    if(cnv->fromUnicodeStatus==UCNV_NEED_TO_WRITE_BOM) {
+        static const char bom[]={ (char)0xfe, (char)0xff };
+        ucnv_fromUWriteBytes(cnv,
+                             bom, 2,
+                             &pArgs->target, pArgs->targetLimit,
+                             &pArgs->offsets, -1,
+                             pErrorCode);
+        cnv->fromUnicodeStatus=0;
+    }
+
+    target=pArgs->target;
+    if(target >= pArgs->targetLimit) {
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+        return;
+    }
+
+    targetCapacity=(uint32_t)(pArgs->targetLimit-target);
+    offsets=pArgs->offsets;
+    sourceIndex=0;
+
+    /* c!=0 indicates in several places outside the main loops that a surrogate was found */
+
+    if((c=(UChar)cnv->fromUChar32)!=0 && U16_IS_TRAIL(trail=*source) && targetCapacity>=4) {
+        /* the last buffer ended with a lead surrogate, output the surrogate pair */
+        ++source;
+        --length;
+        target[0]=(uint8_t)(c>>8);
+        target[1]=(uint8_t)c;
+        target[2]=(uint8_t)(trail>>8);
+        target[3]=(uint8_t)trail;
+        target+=4;
+        targetCapacity-=4;
+        if(offsets!=NULL) {
+            *offsets++=-1;
+            *offsets++=-1;
+            *offsets++=-1;
+            *offsets++=-1;
+        }
+        sourceIndex=1;
+        cnv->fromUChar32=c=0;
+    }
+
+    if(c==0) {
+        /* copy an even number of bytes for complete UChars */
+        uint32_t count=2*length;
+        if(count>targetCapacity) {
+            count=targetCapacity&~1;
+        }
+        /* count is even */
+        targetCapacity-=count;
+        count>>=1;
+        length-=count;
+
+        if(offsets==NULL) {
+            while(count>0) {
+                c=*source++;
+                if(U16_IS_SINGLE(c)) {
+                    target[0]=(uint8_t)(c>>8);
+                    target[1]=(uint8_t)c;
+                    target+=2;
+                } else if(U16_IS_SURROGATE_LEAD(c) && count>=2 && U16_IS_TRAIL(trail=*source)) {
+                    ++source;
+                    --count;
+                    target[0]=(uint8_t)(c>>8);
+                    target[1]=(uint8_t)c;
+                    target[2]=(uint8_t)(trail>>8);
+                    target[3]=(uint8_t)trail;
+                    target+=4;
+                } else {
+                    break;
+                }
+                --count;
+            }
+        } else {
+            while(count>0) {
+                c=*source++;
+                if(U16_IS_SINGLE(c)) {
+                    target[0]=(uint8_t)(c>>8);
+                    target[1]=(uint8_t)c;
+                    target+=2;
+                    *offsets++=sourceIndex;
+                    *offsets++=sourceIndex++;
+                } else if(U16_IS_SURROGATE_LEAD(c) && count>=2 && U16_IS_TRAIL(trail=*source)) {
+                    ++source;
+                    --count;
+                    target[0]=(uint8_t)(c>>8);
+                    target[1]=(uint8_t)c;
+                    target[2]=(uint8_t)(trail>>8);
+                    target[3]=(uint8_t)trail;
+                    target+=4;
+                    *offsets++=sourceIndex;
+                    *offsets++=sourceIndex;
+                    *offsets++=sourceIndex;
+                    *offsets++=sourceIndex;
+                    sourceIndex+=2;
+                } else {
+                    break;
+                }
+                --count;
+            }
+        }
+
+        if(count==0) {
+            /* done with the loop for complete UChars */
+            if(length>0 && targetCapacity>0) {
+                /*
+                 * there is more input and some target capacity -
+                 * it must be targetCapacity==1 because otherwise
+                 * the above would have copied more;
+                 * prepare for overflow output
+                 */
+                if(U16_IS_SINGLE(c=*source++)) {
+                    overflow[0]=(char)(c>>8);
+                    overflow[1]=(char)c;
+                    length=2; /* 2 bytes to output */
+                    c=0;
+                /* } else { keep c for surrogate handling, length will be set there */
+                }
+            } else {
+                length=0;
+                c=0;
+            }
+        } else {
+            /* keep c for surrogate handling, length will be set there */
+            targetCapacity+=2*count;
+        }
+    } else {
+        length=0; /* from here on, length counts the bytes in overflow[] */
+    }
+    
+    if(c!=0) {
+        /*
+         * c is a surrogate, and
+         * - source or target too short
+         * - or the surrogate is unmatched
+         */
+        length=0;
+        if(U16_IS_SURROGATE_LEAD(c)) {
+            if(source<pArgs->sourceLimit) {
+                if(U16_IS_TRAIL(trail=*source)) {
+                    /* output the surrogate pair, will overflow (see conditions comment above) */
+                    ++source;
+                    overflow[0]=(char)(c>>8);
+                    overflow[1]=(char)c;
+                    overflow[2]=(char)(trail>>8);
+                    overflow[3]=(char)trail;
+                    length=4; /* 4 bytes to output */
+                    c=0;
+                } else {
+                    /* unmatched lead surrogate */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                }
+            } else {
+                /* see if the trail surrogate is in the next buffer */
+            }
+        } else {
+            /* unmatched trail surrogate */
+            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+        }
+        cnv->fromUChar32=c;
+    }
+
+    if(length>0) {
+        /* output length bytes with overflow (length>targetCapacity>0) */
+        ucnv_fromUWriteBytes(cnv,
+                             overflow, length,
+                             (char **)&target, pArgs->targetLimit,
+                             &offsets, sourceIndex,
+                             pErrorCode);
+        targetCapacity=(uint32_t)(pArgs->targetLimit-(char *)target);
+    }
+
+    if(U_SUCCESS(*pErrorCode) && source<pArgs->sourceLimit && targetCapacity==0) {
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    /* write back the updated pointers */
+    pArgs->source=source;
+    pArgs->target=(char *)target;
+    pArgs->offsets=offsets;
+}
+
+static void
+_UTF16BEToUnicodeWithOffsets(UConverterToUnicodeArgs *pArgs,
+                             UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const uint8_t *source;
+    UChar *target;
+    int32_t *offsets;
+
+    uint32_t targetCapacity, length, count, sourceIndex;
+    UChar c, trail;
+
+    if(pArgs->converter->mode<8) {
+        _UTF16ToUnicodeWithOffsets(pArgs, pErrorCode);
+        return;
+    }
+
+    cnv=pArgs->converter;
+    source=(const uint8_t *)pArgs->source;
+    length=(int32_t)((const uint8_t *)pArgs->sourceLimit-source);
+    if(length<=0 && cnv->toUnicodeStatus==0) {
+        /* no input, nothing to do */
+        return;
+    }
+
+    target=pArgs->target;
+    if(target >= pArgs->targetLimit) {
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+        return;
+    }
+
+    targetCapacity=(uint32_t)(pArgs->targetLimit-target);
+    offsets=pArgs->offsets;
+    sourceIndex=0;
+    c=0;
+
+    /* complete a partial UChar or pair from the last call */
+    if(cnv->toUnicodeStatus!=0) {
+        /*
+         * special case: single byte from a previous buffer,
+         * where the byte turned out not to belong to a trail surrogate
+         * and the preceding, unmatched lead surrogate was put into toUBytes[]
+         * for error handling
+         */
+        cnv->toUBytes[0]=(uint8_t)cnv->toUnicodeStatus;
+        cnv->toULength=1;
+        cnv->toUnicodeStatus=0;
+    }
+    if((count=cnv->toULength)!=0) {
+        uint8_t *p=cnv->toUBytes;
+        do {
+            p[count++]=*source++;
+            ++sourceIndex;
+            --length;
+            if(count==2) {
+                c=((UChar)p[0]<<8)|p[1];
+                if(U16_IS_SINGLE(c)) {
+                    /* output the BMP code point */
+                    *target++=c;
+                    if(offsets!=NULL) {
+                        *offsets++=-1;
+                    }
+                    --targetCapacity;
+                    count=0;
+                    c=0;
+                    break;
+                } else if(U16_IS_SURROGATE_LEAD(c)) {
+                    /* continue collecting bytes for the trail surrogate */
+                    c=0; /* avoid unnecessary surrogate handling below */
+                } else {
+                    /* fall through to error handling for an unmatched trail surrogate */
+                    break;
+                }
+            } else if(count==4) {
+                c=((UChar)p[0]<<8)|p[1];
+                trail=((UChar)p[2]<<8)|p[3];
+                if(U16_IS_TRAIL(trail)) {
+                    /* output the surrogate pair */
+                    *target++=c;
+                    if(targetCapacity>=2) {
+                        *target++=trail;
+                        if(offsets!=NULL) {
+                            *offsets++=-1;
+                            *offsets++=-1;
+                        }
+                        targetCapacity-=2;
+                    } else /* targetCapacity==1 */ {
+                        targetCapacity=0;
+                        cnv->UCharErrorBuffer[0]=trail;
+                        cnv->UCharErrorBufferLength=1;
+                        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                    }
+                    count=0;
+                    c=0;
+                    break;
+                } else {
+                    /* unmatched lead surrogate, handle here for consistent toUBytes[] */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+
+                    /* back out reading the code unit after it */
+                    if(((const uint8_t *)pArgs->source-source)>=2) {
+                        source-=2;
+                    } else {
+                        /*
+                         * if the trail unit's first byte was in a previous buffer, then
+                         * we need to put it into a special place because toUBytes[] will be
+                         * used for the lead unit's bytes
+                         */
+                        cnv->toUnicodeStatus=0x100|p[2];
+                        --source;
+                    }
+                    cnv->toULength=2;
+
+                    /* write back the updated pointers */
+                    pArgs->source=(const char *)source;
+                    pArgs->target=target;
+                    pArgs->offsets=offsets;
+                    return;
+                }
+            }
+        } while(length>0);
+        cnv->toULength=(int8_t)count;
+    }
+
+    /* copy an even number of bytes for complete UChars */
+    count=2*targetCapacity;
+    if(count>length) {
+        count=length&~1;
+    }
+    if(c==0 && count>0) {
+        length-=count;
+        count>>=1;
+        targetCapacity-=count;
+        if(offsets==NULL) {
+            do {
+                c=((UChar)source[0]<<8)|source[1];
+                source+=2;
+                if(U16_IS_SINGLE(c)) {
+                    *target++=c;
+                } else if(U16_IS_SURROGATE_LEAD(c) && count>=2 &&
+                          U16_IS_TRAIL(trail=((UChar)source[0]<<8)|source[1])
+                ) {
+                    source+=2;
+                    --count;
+                    *target++=c;
+                    *target++=trail;
+                } else {
+                    break;
+                }
+            } while(--count>0);
+        } else {
+            do {
+                c=((UChar)source[0]<<8)|source[1];
+                source+=2;
+                if(U16_IS_SINGLE(c)) {
+                    *target++=c;
+                    *offsets++=sourceIndex;
+                    sourceIndex+=2;
+                } else if(U16_IS_SURROGATE_LEAD(c) && count>=2 &&
+                          U16_IS_TRAIL(trail=((UChar)source[0]<<8)|source[1])
+                ) {
+                    source+=2;
+                    --count;
+                    *target++=c;
+                    *target++=trail;
+                    *offsets++=sourceIndex;
+                    *offsets++=sourceIndex;
+                    sourceIndex+=4;
+                } else {
+                    break;
+                }
+            } while(--count>0);
+        }
+
+        if(count==0) {
+            /* done with the loop for complete UChars */
+            c=0;
+        } else {
+            /* keep c for surrogate handling, trail will be set there */
+            length+=2*(count-1); /* one more byte pair was consumed than count decremented */
+            targetCapacity+=count;
+        }
+    }
+
+    if(c!=0) {
+        /*
+         * c is a surrogate, and
+         * - source or target too short
+         * - or the surrogate is unmatched
+         */
+        cnv->toUBytes[0]=(uint8_t)(c>>8);
+        cnv->toUBytes[1]=(uint8_t)c;
+        cnv->toULength=2;
+
+        if(U16_IS_SURROGATE_LEAD(c)) {
+            if(length>=2) {
+                if(U16_IS_TRAIL(trail=((UChar)source[0]<<8)|source[1])) {
+                    /* output the surrogate pair, will overflow (see conditions comment above) */
+                    source+=2;
+                    length-=2;
+                    *target++=c;
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex;
+                    }
+                    cnv->UCharErrorBuffer[0]=trail;
+                    cnv->UCharErrorBufferLength=1;
+                    cnv->toULength=0;
+                    *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                } else {
+                    /* unmatched lead surrogate */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                }
+            } else {
+                /* see if the trail surrogate is in the next buffer */
+            }
+        } else {
+            /* unmatched trail surrogate */
+            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+        }
+    }
+
+    if(U_SUCCESS(*pErrorCode)) {
+        /* check for a remaining source byte */
+        if(length>0) {
+            if(targetCapacity==0) {
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            } else {
+                /* it must be length==1 because otherwise the above would have copied more */
+                cnv->toUBytes[cnv->toULength++]=*source++;
+            }
+        }
+    }
+
+    /* write back the updated pointers */
+    pArgs->source=(const char *)source;
+    pArgs->target=target;
+    pArgs->offsets=offsets;
+}
+
+static UChar32
+_UTF16BEGetNextUChar(UConverterToUnicodeArgs *pArgs, UErrorCode *err) {
+    const uint8_t *s, *sourceLimit;
+    UChar32 c;
+
+    if(pArgs->converter->mode<8) {
+        return UCNV_GET_NEXT_UCHAR_USE_TO_U;
+    }
+
+    s=(const uint8_t *)pArgs->source;
+    sourceLimit=(const uint8_t *)pArgs->sourceLimit;
+
+    if(s>=sourceLimit) {
+        /* no input */
+        *err=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0xffff;
+    }
+
+    if(s+2>sourceLimit) {
+        /* only one byte: truncated UChar */
+        pArgs->converter->toUBytes[0]=*s++;
+        pArgs->converter->toULength=1;
+        pArgs->source=(const char *)s;
+        *err = U_TRUNCATED_CHAR_FOUND;
+        return 0xffff;
+    }
+
+    /* get one UChar */
+    c=((UChar32)*s<<8)|s[1];
+    s+=2;
+
+    /* check for a surrogate pair */
+    if(U_IS_SURROGATE(c)) {
+        if(U16_IS_SURROGATE_LEAD(c)) {
+            if(s+2<=sourceLimit) {
+                UChar trail;
+
+                /* get a second UChar and see if it is a trail surrogate */
+                trail=((UChar)*s<<8)|s[1];
+                if(U16_IS_TRAIL(trail)) {
+                    c=U16_GET_SUPPLEMENTARY(c, trail);
+                    s+=2;
+                } else {
+                    /* unmatched lead surrogate */
+                    c=-2;
+                }
+            } else {
+                /* too few (2 or 3) bytes for a surrogate pair: truncated code point */
+                uint8_t *bytes=pArgs->converter->toUBytes;
+                s-=2;
+                pArgs->converter->toULength=(int8_t)(sourceLimit-s);
+                do {
+                    *bytes++=*s++;
+                } while(s<sourceLimit);
+
+                c=0xffff;
+                *err=U_TRUNCATED_CHAR_FOUND;
+            }
+        } else {
+            /* unmatched trail surrogate */
+            c=-2;
+        }
+
+        if(c<0) {
+            /* write the unmatched surrogate */
+            uint8_t *bytes=pArgs->converter->toUBytes;
+            pArgs->converter->toULength=2;
+            *bytes=*(s-2);
+            bytes[1]=*(s-1);
+
+            c=0xffff;
+            *err=U_ILLEGAL_CHAR_FOUND;
+        }
+    }
+
+    pArgs->source=(const char *)s;
+    return c;
+} 
+
+static void
+_UTF16BEReset(UConverter *cnv, UConverterResetChoice choice) {
+    if(choice<=UCNV_RESET_TO_UNICODE) {
+        /* reset toUnicode state */
+        if(UCNV_GET_VERSION(cnv)==0) {
+            cnv->mode=8; /* no BOM handling */
+        } else {
+            cnv->mode=0; /* Java-specific "UnicodeBig" requires BE BOM or no BOM */
+        }
+    }
+    if(choice!=UCNV_RESET_TO_UNICODE && UCNV_GET_VERSION(cnv)==1) {
+        /* reset fromUnicode for "UnicodeBig": prepare to output the UTF-16BE BOM */
+        cnv->fromUnicodeStatus=UCNV_NEED_TO_WRITE_BOM;
+    }
+}
+
+static void
+_UTF16BEOpen(UConverter *cnv,
+             UConverterLoadArgs *pArgs,
+             UErrorCode *pErrorCode) {
+    if(UCNV_GET_VERSION(cnv)<=1) {
+        _UTF16BEReset(cnv, UCNV_RESET_BOTH);
+    } else {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+    }
+}
+
+static const char *
+_UTF16BEGetName(const UConverter *cnv) {
+    if(UCNV_GET_VERSION(cnv)==0) {
+        return "UTF-16BE";
+    } else {
+        return "UTF-16BE,version=1";
+    }
+}
+
+static const UConverterImpl _UTF16BEImpl={
+    UCNV_UTF16_BigEndian,
+
+    NULL,
+    NULL,
+
+    _UTF16BEOpen,
+    NULL,
+    _UTF16BEReset,
+
+    _UTF16BEToUnicodeWithOffsets,
+    _UTF16BEToUnicodeWithOffsets,
+    _UTF16BEFromUnicodeWithOffsets,
+    _UTF16BEFromUnicodeWithOffsets,
+    _UTF16BEGetNextUChar,
+
+    NULL,
+    _UTF16BEGetName,
+    NULL,
+    NULL,
+    ucnv_getNonSurrogateUnicodeSet
+};
+
+static const UConverterStaticData _UTF16BEStaticData={
+    sizeof(UConverterStaticData),
+    "UTF-16BE",
+    1200, UCNV_IBM, UCNV_UTF16_BigEndian, 2, 2,
+    { 0xff, 0xfd, 0, 0 },2,FALSE,FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+
+
+const UConverterSharedData _UTF16BEData={
+    sizeof(UConverterSharedData), ~((uint32_t) 0),
+    NULL, NULL, &_UTF16BEStaticData, FALSE, &_UTF16BEImpl, 
+    0
+};
+
+/* UTF-16LE ----------------------------------------------------------------- */
+
+static void
+_UTF16LEFromUnicodeWithOffsets(UConverterFromUnicodeArgs *pArgs,
+                               UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const UChar *source;
+    char *target;
+    int32_t *offsets;
+
+    uint32_t targetCapacity, length, sourceIndex;
+    UChar c, trail;
+    char overflow[4];
+
+    source=pArgs->source;
+    length=(int32_t)(pArgs->sourceLimit-source);
+    if(length<=0) {
+        /* no input, nothing to do */
+        return;
+    }
+
+    cnv=pArgs->converter;
+
+    /* write the BOM if necessary */
+    if(cnv->fromUnicodeStatus==UCNV_NEED_TO_WRITE_BOM) {
+        static const char bom[]={ (char)0xff, (char)0xfe };
+        ucnv_fromUWriteBytes(cnv,
+                             bom, 2,
+                             &pArgs->target, pArgs->targetLimit,
+                             &pArgs->offsets, -1,
+                             pErrorCode);
+        cnv->fromUnicodeStatus=0;
+    }
+
+    target=pArgs->target;
+    if(target >= pArgs->targetLimit) {
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+        return;
+    }
+
+    targetCapacity=(uint32_t)(pArgs->targetLimit-pArgs->target);
+    offsets=pArgs->offsets;
+    sourceIndex=0;
+
+    /* c!=0 indicates in several places outside the main loops that a surrogate was found */
+
+    if((c=(UChar)cnv->fromUChar32)!=0 && U16_IS_TRAIL(trail=*source) && targetCapacity>=4) {
+        /* the last buffer ended with a lead surrogate, output the surrogate pair */
+        ++source;
+        --length;
+        target[0]=(uint8_t)c;
+        target[1]=(uint8_t)(c>>8);
+        target[2]=(uint8_t)trail;
+        target[3]=(uint8_t)(trail>>8);
+        target+=4;
+        targetCapacity-=4;
+        if(offsets!=NULL) {
+            *offsets++=-1;
+            *offsets++=-1;
+            *offsets++=-1;
+            *offsets++=-1;
+        }
+        sourceIndex=1;
+        cnv->fromUChar32=c=0;
+    }
+
+    if(c==0) {
+        /* copy an even number of bytes for complete UChars */
+        uint32_t count=2*length;
+        if(count>targetCapacity) {
+            count=targetCapacity&~1;
+        }
+        /* count is even */
+        targetCapacity-=count;
+        count>>=1;
+        length-=count;
+
+        if(offsets==NULL) {
+            while(count>0) {
+                c=*source++;
+                if(U16_IS_SINGLE(c)) {
+                    target[0]=(uint8_t)c;
+                    target[1]=(uint8_t)(c>>8);
+                    target+=2;
+                } else if(U16_IS_SURROGATE_LEAD(c) && count>=2 && U16_IS_TRAIL(trail=*source)) {
+                    ++source;
+                    --count;
+                    target[0]=(uint8_t)c;
+                    target[1]=(uint8_t)(c>>8);
+                    target[2]=(uint8_t)trail;
+                    target[3]=(uint8_t)(trail>>8);
+                    target+=4;
+                } else {
+                    break;
+                }
+                --count;
+            }
+        } else {
+            while(count>0) {
+                c=*source++;
+                if(U16_IS_SINGLE(c)) {
+                    target[0]=(uint8_t)c;
+                    target[1]=(uint8_t)(c>>8);
+                    target+=2;
+                    *offsets++=sourceIndex;
+                    *offsets++=sourceIndex++;
+                } else if(U16_IS_SURROGATE_LEAD(c) && count>=2 && U16_IS_TRAIL(trail=*source)) {
+                    ++source;
+                    --count;
+                    target[0]=(uint8_t)c;
+                    target[1]=(uint8_t)(c>>8);
+                    target[2]=(uint8_t)trail;
+                    target[3]=(uint8_t)(trail>>8);
+                    target+=4;
+                    *offsets++=sourceIndex;
+                    *offsets++=sourceIndex;
+                    *offsets++=sourceIndex;
+                    *offsets++=sourceIndex;
+                    sourceIndex+=2;
+                } else {
+                    break;
+                }
+                --count;
+            }
+        }
+
+        if(count==0) {
+            /* done with the loop for complete UChars */
+            if(length>0 && targetCapacity>0) {
+                /*
+                 * there is more input and some target capacity -
+                 * it must be targetCapacity==1 because otherwise
+                 * the above would have copied more;
+                 * prepare for overflow output
+                 */
+                if(U16_IS_SINGLE(c=*source++)) {
+                    overflow[0]=(char)c;
+                    overflow[1]=(char)(c>>8);
+                    length=2; /* 2 bytes to output */
+                    c=0;
+                /* } else { keep c for surrogate handling, length will be set there */
+                }
+            } else {
+                length=0;
+                c=0;
+            }
+        } else {
+            /* keep c for surrogate handling, length will be set there */
+            targetCapacity+=2*count;
+        }
+    } else {
+        length=0; /* from here on, length counts the bytes in overflow[] */
+    }
+    
+    if(c!=0) {
+        /*
+         * c is a surrogate, and
+         * - source or target too short
+         * - or the surrogate is unmatched
+         */
+        length=0;
+        if(U16_IS_SURROGATE_LEAD(c)) {
+            if(source<pArgs->sourceLimit) {
+                if(U16_IS_TRAIL(trail=*source)) {
+                    /* output the surrogate pair, will overflow (see conditions comment above) */
+                    ++source;
+                    overflow[0]=(char)c;
+                    overflow[1]=(char)(c>>8);
+                    overflow[2]=(char)trail;
+                    overflow[3]=(char)(trail>>8);
+                    length=4; /* 4 bytes to output */
+                    c=0;
+                } else {
+                    /* unmatched lead surrogate */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                }
+            } else {
+                /* see if the trail surrogate is in the next buffer */
+            }
+        } else {
+            /* unmatched trail surrogate */
+            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+        }
+        cnv->fromUChar32=c;
+    }
+
+    if(length>0) {
+        /* output length bytes with overflow (length>targetCapacity>0) */
+        ucnv_fromUWriteBytes(cnv,
+                             overflow, length,
+                             &target, pArgs->targetLimit,
+                             &offsets, sourceIndex,
+                             pErrorCode);
+        targetCapacity=(uint32_t)(pArgs->targetLimit-(char *)target);
+    }
+
+    if(U_SUCCESS(*pErrorCode) && source<pArgs->sourceLimit && targetCapacity==0) {
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    /* write back the updated pointers */
+    pArgs->source=source;
+    pArgs->target=target;
+    pArgs->offsets=offsets;
+}
+
+static void
+_UTF16LEToUnicodeWithOffsets(UConverterToUnicodeArgs *pArgs,
+                             UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const uint8_t *source;
+    UChar *target;
+    int32_t *offsets;
+
+    uint32_t targetCapacity, length, count, sourceIndex;
+    UChar c, trail;
+
+    if(pArgs->converter->mode<8) {
+        _UTF16ToUnicodeWithOffsets(pArgs, pErrorCode);
+        return;
+    }
+
+    cnv=pArgs->converter;
+    source=(const uint8_t *)pArgs->source;
+    length=(int32_t)((const uint8_t *)pArgs->sourceLimit-source);
+    if(length<=0 && cnv->toUnicodeStatus==0) {
+        /* no input, nothing to do */
+        return;
+    }
+
+    target=pArgs->target;
+    if(target >= pArgs->targetLimit) {
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+        return;
+    }
+
+    targetCapacity=(uint32_t)(pArgs->targetLimit-pArgs->target);
+    offsets=pArgs->offsets;
+    sourceIndex=0;
+    c=0;
+
+    /* complete a partial UChar or pair from the last call */
+    if(cnv->toUnicodeStatus!=0) {
+        /*
+         * special case: single byte from a previous buffer,
+         * where the byte turned out not to belong to a trail surrogate
+         * and the preceding, unmatched lead surrogate was put into toUBytes[]
+         * for error handling
+         */
+        cnv->toUBytes[0]=(uint8_t)cnv->toUnicodeStatus;
+        cnv->toULength=1;
+        cnv->toUnicodeStatus=0;
+    }
+    if((count=cnv->toULength)!=0) {
+        uint8_t *p=cnv->toUBytes;
+        do {
+            p[count++]=*source++;
+            ++sourceIndex;
+            --length;
+            if(count==2) {
+                c=((UChar)p[1]<<8)|p[0];
+                if(U16_IS_SINGLE(c)) {
+                    /* output the BMP code point */
+                    *target++=c;
+                    if(offsets!=NULL) {
+                        *offsets++=-1;
+                    }
+                    --targetCapacity;
+                    count=0;
+                    c=0;
+                    break;
+                } else if(U16_IS_SURROGATE_LEAD(c)) {
+                    /* continue collecting bytes for the trail surrogate */
+                    c=0; /* avoid unnecessary surrogate handling below */
+                } else {
+                    /* fall through to error handling for an unmatched trail surrogate */
+                    break;
+                }
+            } else if(count==4) {
+                c=((UChar)p[1]<<8)|p[0];
+                trail=((UChar)p[3]<<8)|p[2];
+                if(U16_IS_TRAIL(trail)) {
+                    /* output the surrogate pair */
+                    *target++=c;
+                    if(targetCapacity>=2) {
+                        *target++=trail;
+                        if(offsets!=NULL) {
+                            *offsets++=-1;
+                            *offsets++=-1;
+                        }
+                        targetCapacity-=2;
+                    } else /* targetCapacity==1 */ {
+                        targetCapacity=0;
+                        cnv->UCharErrorBuffer[0]=trail;
+                        cnv->UCharErrorBufferLength=1;
+                        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                    }
+                    count=0;
+                    c=0;
+                    break;
+                } else {
+                    /* unmatched lead surrogate, handle here for consistent toUBytes[] */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+
+                    /* back out reading the code unit after it */
+                    if(((const uint8_t *)pArgs->source-source)>=2) {
+                        source-=2;
+                    } else {
+                        /*
+                         * if the trail unit's first byte was in a previous buffer, then
+                         * we need to put it into a special place because toUBytes[] will be
+                         * used for the lead unit's bytes
+                         */
+                        cnv->toUnicodeStatus=0x100|p[2];
+                        --source;
+                    }
+                    cnv->toULength=2;
+
+                    /* write back the updated pointers */
+                    pArgs->source=(const char *)source;
+                    pArgs->target=target;
+                    pArgs->offsets=offsets;
+                    return;
+                }
+            }
+        } while(length>0);
+        cnv->toULength=(int8_t)count;
+    }
+
+    /* copy an even number of bytes for complete UChars */
+    count=2*targetCapacity;
+    if(count>length) {
+        count=length&~1;
+    }
+    if(c==0 && count>0) {
+        length-=count;
+        count>>=1;
+        targetCapacity-=count;
+        if(offsets==NULL) {
+            do {
+                c=((UChar)source[1]<<8)|source[0];
+                source+=2;
+                if(U16_IS_SINGLE(c)) {
+                    *target++=c;
+                } else if(U16_IS_SURROGATE_LEAD(c) && count>=2 &&
+                          U16_IS_TRAIL(trail=((UChar)source[1]<<8)|source[0])
+                ) {
+                    source+=2;
+                    --count;
+                    *target++=c;
+                    *target++=trail;
+                } else {
+                    break;
+                }
+            } while(--count>0);
+        } else {
+            do {
+                c=((UChar)source[1]<<8)|source[0];
+                source+=2;
+                if(U16_IS_SINGLE(c)) {
+                    *target++=c;
+                    *offsets++=sourceIndex;
+                    sourceIndex+=2;
+                } else if(U16_IS_SURROGATE_LEAD(c) && count>=2 &&
+                          U16_IS_TRAIL(trail=((UChar)source[1]<<8)|source[0])
+                ) {
+                    source+=2;
+                    --count;
+                    *target++=c;
+                    *target++=trail;
+                    *offsets++=sourceIndex;
+                    *offsets++=sourceIndex;
+                    sourceIndex+=4;
+                } else {
+                    break;
+                }
+            } while(--count>0);
+        }
+
+        if(count==0) {
+            /* done with the loop for complete UChars */
+            c=0;
+        } else {
+            /* keep c for surrogate handling, trail will be set there */
+            length+=2*(count-1); /* one more byte pair was consumed than count decremented */
+            targetCapacity+=count;
+        }
+    }
+
+    if(c!=0) {
+        /*
+         * c is a surrogate, and
+         * - source or target too short
+         * - or the surrogate is unmatched
+         */
+        cnv->toUBytes[0]=(uint8_t)c;
+        cnv->toUBytes[1]=(uint8_t)(c>>8);
+        cnv->toULength=2;
+
+        if(U16_IS_SURROGATE_LEAD(c)) {
+            if(length>=2) {
+                if(U16_IS_TRAIL(trail=((UChar)source[1]<<8)|source[0])) {
+                    /* output the surrogate pair, will overflow (see conditions comment above) */
+                    source+=2;
+                    length-=2;
+                    *target++=c;
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex;
+                    }
+                    cnv->UCharErrorBuffer[0]=trail;
+                    cnv->UCharErrorBufferLength=1;
+                    cnv->toULength=0;
+                    *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                } else {
+                    /* unmatched lead surrogate */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                }
+            } else {
+                /* see if the trail surrogate is in the next buffer */
+            }
+        } else {
+            /* unmatched trail surrogate */
+            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+        }
+    }
+
+    if(U_SUCCESS(*pErrorCode)) {
+        /* check for a remaining source byte */
+        if(length>0) {
+            if(targetCapacity==0) {
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            } else {
+                /* it must be length==1 because otherwise the above would have copied more */
+                cnv->toUBytes[cnv->toULength++]=*source++;
+            }
+        }
+    }
+
+    /* write back the updated pointers */
+    pArgs->source=(const char *)source;
+    pArgs->target=target;
+    pArgs->offsets=offsets;
+}
+
+static UChar32
+_UTF16LEGetNextUChar(UConverterToUnicodeArgs *pArgs, UErrorCode *err) {
+    const uint8_t *s, *sourceLimit;
+    UChar32 c;
+
+    if(pArgs->converter->mode<8) {
+        return UCNV_GET_NEXT_UCHAR_USE_TO_U;
+    }
+
+    s=(const uint8_t *)pArgs->source;
+    sourceLimit=(const uint8_t *)pArgs->sourceLimit;
+
+    if(s>=sourceLimit) {
+        /* no input */
+        *err=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0xffff;
+    }
+
+    if(s+2>sourceLimit) {
+        /* only one byte: truncated UChar */
+        pArgs->converter->toUBytes[0]=*s++;
+        pArgs->converter->toULength=1;
+        pArgs->source=(const char *)s;
+        *err = U_TRUNCATED_CHAR_FOUND;
+        return 0xffff;
+    }
+
+    /* get one UChar */
+    c=((UChar32)s[1]<<8)|*s;
+    s+=2;
+
+    /* check for a surrogate pair */
+    if(U_IS_SURROGATE(c)) {
+        if(U16_IS_SURROGATE_LEAD(c)) {
+            if(s+2<=sourceLimit) {
+                UChar trail;
+
+                /* get a second UChar and see if it is a trail surrogate */
+                trail=((UChar)s[1]<<8)|*s;
+                if(U16_IS_TRAIL(trail)) {
+                    c=U16_GET_SUPPLEMENTARY(c, trail);
+                    s+=2;
+                } else {
+                    /* unmatched lead surrogate */
+                    c=-2;
+                }
+            } else {
+                /* too few (2 or 3) bytes for a surrogate pair: truncated code point */
+                uint8_t *bytes=pArgs->converter->toUBytes;
+                s-=2;
+                pArgs->converter->toULength=(int8_t)(sourceLimit-s);
+                do {
+                    *bytes++=*s++;
+                } while(s<sourceLimit);
+
+                c=0xffff;
+                *err=U_TRUNCATED_CHAR_FOUND;
+            }
+        } else {
+            /* unmatched trail surrogate */
+            c=-2;
+        }
+
+        if(c<0) {
+            /* write the unmatched surrogate */
+            uint8_t *bytes=pArgs->converter->toUBytes;
+            pArgs->converter->toULength=2;
+            *bytes=*(s-2);
+            bytes[1]=*(s-1);
+
+            c=0xffff;
+            *err=U_ILLEGAL_CHAR_FOUND;
+        }
+    }
+
+    pArgs->source=(const char *)s;
+    return c;
+} 
+
+static void
+_UTF16LEReset(UConverter *cnv, UConverterResetChoice choice) {
+    if(choice<=UCNV_RESET_TO_UNICODE) {
+        /* reset toUnicode state */
+        if(UCNV_GET_VERSION(cnv)==0) {
+            cnv->mode=8; /* no BOM handling */
+        } else {
+            cnv->mode=0; /* Java-specific "UnicodeLittle" requires LE BOM or no BOM */
+        }
+    }
+    if(choice!=UCNV_RESET_TO_UNICODE && UCNV_GET_VERSION(cnv)==1) {
+        /* reset fromUnicode for "UnicodeLittle": prepare to output the UTF-16LE BOM */
+        cnv->fromUnicodeStatus=UCNV_NEED_TO_WRITE_BOM;
+    }
+}
+
+static void
+_UTF16LEOpen(UConverter *cnv,
+             UConverterLoadArgs *pArgs,
+             UErrorCode *pErrorCode) {
+    if(UCNV_GET_VERSION(cnv)<=1) {
+        _UTF16LEReset(cnv, UCNV_RESET_BOTH);
+    } else {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+    }
+}
+
+static const char *
+_UTF16LEGetName(const UConverter *cnv) {
+    if(UCNV_GET_VERSION(cnv)==0) {
+        return "UTF-16LE";
+    } else {
+        return "UTF-16LE,version=1";
+    }
+}
+
+static const UConverterImpl _UTF16LEImpl={
+    UCNV_UTF16_LittleEndian,
+
+    NULL,
+    NULL,
+
+    _UTF16LEOpen,
+    NULL,
+    _UTF16LEReset,
+
+    _UTF16LEToUnicodeWithOffsets,
+    _UTF16LEToUnicodeWithOffsets,
+    _UTF16LEFromUnicodeWithOffsets,
+    _UTF16LEFromUnicodeWithOffsets,
+    _UTF16LEGetNextUChar,
+
+    NULL,
+    _UTF16LEGetName,
+    NULL,
+    NULL,
+    ucnv_getNonSurrogateUnicodeSet
+};
+
+
+static const UConverterStaticData _UTF16LEStaticData={
+    sizeof(UConverterStaticData),
+    "UTF-16LE",
+    1202, UCNV_IBM, UCNV_UTF16_LittleEndian, 2, 2,
+    { 0xfd, 0xff, 0, 0 },2,FALSE,FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+
+
+const UConverterSharedData _UTF16LEData={
+    sizeof(UConverterSharedData), ~((uint32_t) 0),
+    NULL, NULL, &_UTF16LEStaticData, FALSE, &_UTF16LEImpl, 
+    0
+};
+
+/* UTF-16 (Detect BOM) ------------------------------------------------------ */
+
+/*
+ * Detect a BOM at the beginning of the stream and select UTF-16BE or UTF-16LE
+ * accordingly.
+ * This is a simpler version of the UTF-32 converter, with
+ * fewer states for shorter BOMs.
+ *
+ * State values:
+ * 0    initial state
+ * 1    saw first byte
+ * 2..5 -
+ * 6..7 see _UTF16ToUnicodeWithOffsets() comments in state 1
+ * 8    UTF-16BE mode
+ * 9    UTF-16LE mode
+ *
+ * During detection: state==number of initial bytes seen so far.
+ *
+ * On output, emit U+FEFF as the first code point.
+ *
+ * Variants:
+ * - UTF-16,version=1 (Java "Unicode" encoding) treats a missing BOM as an error.
+ * - UTF-16BE,version=1 (Java "UnicodeBig" encoding) and
+ *   UTF-16LE,version=1 (Java "UnicodeLittle" encoding) treat a reverse BOM as an error.
+ */
+
+static void
+_UTF16Reset(UConverter *cnv, UConverterResetChoice choice) {
+    if(choice<=UCNV_RESET_TO_UNICODE) {
+        /* reset toUnicode: state=0 */
+        cnv->mode=0;
+    }
+    if(choice!=UCNV_RESET_TO_UNICODE) {
+        /* reset fromUnicode: prepare to output the UTF-16PE BOM */
+        cnv->fromUnicodeStatus=UCNV_NEED_TO_WRITE_BOM;
+    }
+}
+
+static const UConverterSharedData _UTF16v2Data;
+
+static void
+_UTF16Open(UConverter *cnv,
+           UConverterLoadArgs *pArgs,
+           UErrorCode *pErrorCode) {
+    if(UCNV_GET_VERSION(cnv)<=2) {
+        if(UCNV_GET_VERSION(cnv)==2 && !pArgs->onlyTestIsLoadable) {
+            /*
+             * Switch implementation, and switch the staticData that's different
+             * and was copied into the UConverter.
+             * (See ucnv_createConverterFromSharedData() in ucnv_bld.c.)
+             * UTF-16,version=2 fromUnicode() always writes a big-endian byte stream.
+             */
+            cnv->sharedData=(UConverterSharedData*)&_UTF16v2Data;
+            uprv_memcpy(cnv->subChars, _UTF16v2Data.staticData->subChar, UCNV_MAX_SUBCHAR_LEN);
+        }
+        _UTF16Reset(cnv, UCNV_RESET_BOTH);
+    } else {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+    }
+}
+
+static const char *
+_UTF16GetName(const UConverter *cnv) {
+    if(UCNV_GET_VERSION(cnv)==0) {
+        return "UTF-16";
+    } else if(UCNV_GET_VERSION(cnv)==1) {
+        return "UTF-16,version=1";
+    } else {
+        return "UTF-16,version=2";
+    }
+}
+
+const UConverterSharedData _UTF16Data;
+
+#define IS_UTF16BE(cnv) ((cnv)->sharedData==&_UTF16BEData)
+#define IS_UTF16LE(cnv) ((cnv)->sharedData==&_UTF16LEData)
+#define IS_UTF16(cnv) ((cnv)->sharedData==&_UTF16Data || (cnv)->sharedData==&_UTF16v2Data)
+
+static void
+_UTF16ToUnicodeWithOffsets(UConverterToUnicodeArgs *pArgs,
+                           UErrorCode *pErrorCode) {
+    UConverter *cnv=pArgs->converter;
+    const char *source=pArgs->source;
+    const char *sourceLimit=pArgs->sourceLimit;
+    int32_t *offsets=pArgs->offsets;
+
+    int32_t state, offsetDelta;
+    uint8_t b;
+
+    state=cnv->mode;
+
+    /*
+     * If we detect a BOM in this buffer, then we must add the BOM size to the
+     * offsets because the actual converter function will not see and count the BOM.
+     * offsetDelta will have the number of the BOM bytes that are in the current buffer.
+     */
+    offsetDelta=0;
+
+    while(source<sourceLimit && U_SUCCESS(*pErrorCode)) {
+        switch(state) {
+        case 0:
+            cnv->toUBytes[0]=(uint8_t)*source++;
+            cnv->toULength=1;
+            state=1;
+            break;
+        case 1:
+            /*
+             * Only inside this switch case can the state variable
+             * temporarily take two additional values:
+             * 6: BOM error, continue with BE
+             * 7: BOM error, continue with LE
+             */
+            b=*source;
+            if(cnv->toUBytes[0]==0xfe && b==0xff) {
+                if(IS_UTF16LE(cnv)) {
+                    state=7; /* illegal reverse BOM for Java "UnicodeLittle" */
+                } else {
+                    state=8; /* detect UTF-16BE */
+                }
+            } else if(cnv->toUBytes[0]==0xff && b==0xfe) {
+                if(IS_UTF16BE(cnv)) {
+                    state=6; /* illegal reverse BOM for Java "UnicodeBig" */
+                } else {
+                    state=9; /* detect UTF-16LE */
+                }
+            } else if((IS_UTF16(cnv) && UCNV_GET_VERSION(cnv)==1)) {
+                state=6; /* illegal missing BOM for Java "Unicode" */
+            }
+            if(state>=8) {
+                /* BOM detected, consume it */
+                ++source;
+                cnv->toULength=0;
+                offsetDelta=(int32_t)(source-pArgs->source);
+            } else if(state<6) {
+                /* ok: no BOM, and not a reverse BOM */
+                if(source!=pArgs->source) {
+                    /* reset the source for a correct first offset */
+                    source=pArgs->source;
+                    cnv->toULength=0;
+                }
+                if(IS_UTF16LE(cnv)) {
+                    /* Make Java "UnicodeLittle" default to LE. */
+                    state=9;
+                } else {
+                    /* Make standard UTF-16 and Java "UnicodeBig" default to BE. */
+                    state=8;
+                }
+            } else {
+                /*
+                 * error: missing BOM, or reverse BOM
+                 * UTF-16,version=1: Java-specific "Unicode" requires a BOM.
+                 * UTF-16BE,version=1: Java-specific "UnicodeBig" requires a BE BOM or no BOM.
+                 * UTF-16LE,version=1: Java-specific "UnicodeLittle" requires an LE BOM or no BOM.
+                 */
+                /* report the non-BOM or reverse BOM as an illegal sequence */
+                cnv->toUBytes[1]=b;
+                cnv->toULength=2;
+                pArgs->source=source+1;
+                /* continue with conversion if the callback resets the error */
+                /*
+                 * Make Java "Unicode" default to BE like standard UTF-16.
+                 * Make Java "UnicodeBig" and "UnicodeLittle" default
+                 * to their normal endiannesses.
+                 */
+                cnv->mode=state+2;
+                *pErrorCode=U_ILLEGAL_ESCAPE_SEQUENCE;
+                return;
+            }
+            /* convert the rest of the stream */
+            cnv->mode=state;
+            continue;
+        case 8:
+            /* call UTF-16BE */
+            pArgs->source=source;
+            _UTF16BEToUnicodeWithOffsets(pArgs, pErrorCode);
+            source=pArgs->source;
+            break;
+        case 9:
+            /* call UTF-16LE */
+            pArgs->source=source;
+            _UTF16LEToUnicodeWithOffsets(pArgs, pErrorCode);
+            source=pArgs->source;
+            break;
+        default:
+            break; /* does not occur */
+        }
+    }
+
+    /* add BOM size to offsets - see comment at offsetDelta declaration */
+    if(offsets!=NULL && offsetDelta!=0) {
+        int32_t *offsetsLimit=pArgs->offsets;
+        while(offsets<offsetsLimit) {
+            *offsets++ += offsetDelta;
+        }
+    }
+
+    pArgs->source=source;
+
+    if(source==sourceLimit && pArgs->flush) {
+        /* handle truncated input */
+        switch(state) {
+        case 0:
+            break; /* no input at all, nothing to do */
+        case 8:
+            _UTF16BEToUnicodeWithOffsets(pArgs, pErrorCode);
+            break;
+        case 9:
+            _UTF16LEToUnicodeWithOffsets(pArgs, pErrorCode);
+            break;
+        default:
+            /* 0<state<8: framework will report truncation, nothing to do here */
+            break;
+        }
+    }
+
+    cnv->mode=state;
+}
+
+static UChar32
+_UTF16GetNextUChar(UConverterToUnicodeArgs *pArgs,
+                   UErrorCode *pErrorCode) {
+    switch(pArgs->converter->mode) {
+    case 8:
+        return _UTF16BEGetNextUChar(pArgs, pErrorCode);
+    case 9:
+        return _UTF16LEGetNextUChar(pArgs, pErrorCode);
+    default:
+        return UCNV_GET_NEXT_UCHAR_USE_TO_U;
+    }
+}
+
+static const UConverterImpl _UTF16Impl = {
+    UCNV_UTF16,
+
+    NULL,
+    NULL,
+
+    _UTF16Open,
+    NULL,
+    _UTF16Reset,
+
+    _UTF16ToUnicodeWithOffsets,
+    _UTF16ToUnicodeWithOffsets,
+    _UTF16PEFromUnicodeWithOffsets,
+    _UTF16PEFromUnicodeWithOffsets,
+    _UTF16GetNextUChar,
+
+    NULL, /* ### TODO implement getStarters for all Unicode encodings?! */
+    _UTF16GetName,
+    NULL,
+    NULL,
+    ucnv_getNonSurrogateUnicodeSet
+};
+
+static const UConverterStaticData _UTF16StaticData = {
+    sizeof(UConverterStaticData),
+    "UTF-16",
+    1204, /* CCSID for BOM sensitive UTF-16 */
+    UCNV_IBM, UCNV_UTF16, 2, 2,
+#if U_IS_BIG_ENDIAN
+    { 0xff, 0xfd, 0, 0 }, 2,
+#else
+    { 0xfd, 0xff, 0, 0 }, 2,
+#endif
+    FALSE, FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+
+const UConverterSharedData _UTF16Data = {
+    sizeof(UConverterSharedData), ~((uint32_t) 0),
+    NULL, NULL, &_UTF16StaticData, FALSE, &_UTF16Impl, 
+    0
+};
+
+static const UConverterImpl _UTF16v2Impl = {
+    UCNV_UTF16,
+
+    NULL,
+    NULL,
+
+    _UTF16Open,
+    NULL,
+    _UTF16Reset,
+
+    _UTF16ToUnicodeWithOffsets,
+    _UTF16ToUnicodeWithOffsets,
+    _UTF16BEFromUnicodeWithOffsets,
+    _UTF16BEFromUnicodeWithOffsets,
+    _UTF16GetNextUChar,
+
+    NULL, /* ### TODO implement getStarters for all Unicode encodings?! */
+    _UTF16GetName,
+    NULL,
+    NULL,
+    ucnv_getNonSurrogateUnicodeSet
+};
+
+static const UConverterStaticData _UTF16v2StaticData = {
+    sizeof(UConverterStaticData),
+    "UTF-16,version=2",
+    1204, /* CCSID for BOM sensitive UTF-16 */
+    UCNV_IBM, UCNV_UTF16, 2, 2,
+    { 0xff, 0xfd, 0, 0 }, 2,
+    FALSE, FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+
+static const UConverterSharedData _UTF16v2Data = {
+    sizeof(UConverterSharedData), ~((uint32_t) 0),
+    NULL, NULL, &_UTF16v2StaticData, FALSE, &_UTF16v2Impl, 
+    0
+};
+
+#endif
diff --git a/source/common/ucnv_u32.c b/source/common/ucnv_u32.c
new file mode 100644
index 0000000..f76b9b0
--- /dev/null
+++ b/source/common/ucnv_u32.c
@@ -0,0 +1,1248 @@
+/*  
+**********************************************************************
+*   Copyright (C) 2002-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   file name:  ucnv_u32.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002jul01
+*   created by: Markus W. Scherer
+*
+*   UTF-32 converter implementation. Used to be in ucnv_utf.c.
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ucnv.h"
+#include "ucnv_bld.h"
+#include "ucnv_cnv.h"
+#include "cmemory.h"
+
+#define MAXIMUM_UCS2            0x0000FFFF
+#define MAXIMUM_UTF             0x0010FFFF
+#define HALF_SHIFT              10
+#define HALF_BASE               0x0010000
+#define HALF_MASK               0x3FF
+#define SURROGATE_HIGH_START    0xD800
+#define SURROGATE_LOW_START     0xDC00
+
+/* -SURROGATE_LOW_START + HALF_BASE */
+#define SURROGATE_LOW_BASE      9216
+
+enum {
+    UCNV_NEED_TO_WRITE_BOM=1
+};
+
+/* UTF-32BE ----------------------------------------------------------------- */
+
+static void
+T_UConverter_toUnicode_UTF32_BE(UConverterToUnicodeArgs * args,
+                                UErrorCode * err)
+{
+    const unsigned char *mySource = (unsigned char *) args->source;
+    UChar *myTarget = args->target;
+    const unsigned char *sourceLimit = (unsigned char *) args->sourceLimit;
+    const UChar *targetLimit = args->targetLimit;
+    unsigned char *toUBytes = args->converter->toUBytes;
+    uint32_t ch, i;
+
+    /* Restore state of current sequence */
+    if (args->converter->toUnicodeStatus && myTarget < targetLimit) {
+        i = args->converter->toULength;       /* restore # of bytes consumed */
+        args->converter->toULength = 0;
+
+        ch = args->converter->toUnicodeStatus - 1;/*Stores the previously calculated ch from a previous call*/
+        args->converter->toUnicodeStatus = 0;
+        goto morebytes;
+    }
+
+    while (mySource < sourceLimit && myTarget < targetLimit) {
+        i = 0;
+        ch = 0;
+morebytes:
+        while (i < sizeof(uint32_t)) {
+            if (mySource < sourceLimit) {
+                ch = (ch << 8) | (uint8_t)(*mySource);
+                toUBytes[i++] = (char) *(mySource++);
+            }
+            else {
+                /* stores a partially calculated target*/
+                /* + 1 to make 0 a valid character */
+                args->converter->toUnicodeStatus = ch + 1;
+                args->converter->toULength = (int8_t) i;
+                goto donefornow;
+            }
+        }
+
+        if (ch <= MAXIMUM_UTF && !U_IS_SURROGATE(ch)) {
+            /* Normal valid byte when the loop has not prematurely terminated (i < inBytes) */
+            if (ch <= MAXIMUM_UCS2) 
+            {
+                /* fits in 16 bits */
+                *(myTarget++) = (UChar) ch;
+            }
+            else {
+                /* write out the surrogates */
+                *(myTarget++) = U16_LEAD(ch);
+                ch = U16_TRAIL(ch);
+                if (myTarget < targetLimit) {
+                    *(myTarget++) = (UChar)ch;
+                }
+                else {
+                    /* Put in overflow buffer (not handled here) */
+                    args->converter->UCharErrorBuffer[0] = (UChar) ch;
+                    args->converter->UCharErrorBufferLength = 1;
+                    *err = U_BUFFER_OVERFLOW_ERROR;
+                    break;
+                }
+            }
+        }
+        else {
+            args->converter->toULength = (int8_t)i;
+            *err = U_ILLEGAL_CHAR_FOUND;
+            break;
+        }
+    }
+
+donefornow:
+    if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err)) {
+        /* End of target buffer */
+        *err = U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    args->target = myTarget;
+    args->source = (const char *) mySource;
+}
+
+static void
+T_UConverter_toUnicode_UTF32_BE_OFFSET_LOGIC(UConverterToUnicodeArgs * args,
+                                             UErrorCode * err)
+{
+    const unsigned char *mySource = (unsigned char *) args->source;
+    UChar *myTarget = args->target;
+    int32_t *myOffsets = args->offsets;
+    const unsigned char *sourceLimit = (unsigned char *) args->sourceLimit;
+    const UChar *targetLimit = args->targetLimit;
+    unsigned char *toUBytes = args->converter->toUBytes;
+    uint32_t ch, i;
+    int32_t offsetNum = 0;
+
+    /* Restore state of current sequence */
+    if (args->converter->toUnicodeStatus && myTarget < targetLimit) {
+        i = args->converter->toULength;       /* restore # of bytes consumed */
+        args->converter->toULength = 0;
+
+        ch = args->converter->toUnicodeStatus - 1;/*Stores the previously calculated ch from a previous call*/
+        args->converter->toUnicodeStatus = 0;
+        goto morebytes;
+    }
+
+    while (mySource < sourceLimit && myTarget < targetLimit) {
+        i = 0;
+        ch = 0;
+morebytes:
+        while (i < sizeof(uint32_t)) {
+            if (mySource < sourceLimit) {
+                ch = (ch << 8) | (uint8_t)(*mySource);
+                toUBytes[i++] = (char) *(mySource++);
+            }
+            else {
+                /* stores a partially calculated target*/
+                /* + 1 to make 0 a valid character */
+                args->converter->toUnicodeStatus = ch + 1;
+                args->converter->toULength = (int8_t) i;
+                goto donefornow;
+            }
+        }
+
+        if (ch <= MAXIMUM_UTF && !U_IS_SURROGATE(ch)) {
+            /* Normal valid byte when the loop has not prematurely terminated (i < inBytes) */
+            if (ch <= MAXIMUM_UCS2) {
+                /* fits in 16 bits */
+                *(myTarget++) = (UChar) ch;
+                *(myOffsets++) = offsetNum;
+            }
+            else {
+                /* write out the surrogates */
+                *(myTarget++) = U16_LEAD(ch);
+                *myOffsets++ = offsetNum;
+                ch = U16_TRAIL(ch);
+                if (myTarget < targetLimit)
+                {
+                    *(myTarget++) = (UChar)ch;
+                    *(myOffsets++) = offsetNum;
+                }
+                else {
+                    /* Put in overflow buffer (not handled here) */
+                    args->converter->UCharErrorBuffer[0] = (UChar) ch;
+                    args->converter->UCharErrorBufferLength = 1;
+                    *err = U_BUFFER_OVERFLOW_ERROR;
+                    break;
+                }
+            }
+        }
+        else {
+            args->converter->toULength = (int8_t)i;
+            *err = U_ILLEGAL_CHAR_FOUND;
+            break;
+        }
+        offsetNum += i;
+    }
+
+donefornow:
+    if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err))
+    {
+        /* End of target buffer */
+        *err = U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    args->target = myTarget;
+    args->source = (const char *) mySource;
+    args->offsets = myOffsets;
+}
+
+static void
+T_UConverter_fromUnicode_UTF32_BE(UConverterFromUnicodeArgs * args,
+                                  UErrorCode * err)
+{
+    const UChar *mySource = args->source;
+    unsigned char *myTarget;
+    const UChar *sourceLimit = args->sourceLimit;
+    const unsigned char *targetLimit = (unsigned char *) args->targetLimit;
+    UChar32 ch, ch2;
+    unsigned int indexToWrite;
+    unsigned char temp[sizeof(uint32_t)];
+
+    if(mySource >= sourceLimit) {
+        /* no input, nothing to do */
+        return;
+    }
+
+    /* write the BOM if necessary */
+    if(args->converter->fromUnicodeStatus==UCNV_NEED_TO_WRITE_BOM) {
+        static const char bom[]={ 0, 0, (char)0xfe, (char)0xff };
+        ucnv_fromUWriteBytes(args->converter,
+                             bom, 4,
+                             &args->target, args->targetLimit,
+                             &args->offsets, -1,
+                             err);
+        args->converter->fromUnicodeStatus=0;
+    }
+
+    myTarget = (unsigned char *) args->target;
+    temp[0] = 0;
+
+    if (args->converter->fromUChar32) {
+        ch = args->converter->fromUChar32;
+        args->converter->fromUChar32 = 0;
+        goto lowsurogate;
+    }
+
+    while (mySource < sourceLimit && myTarget < targetLimit) {
+        ch = *(mySource++);
+
+        if (UTF_IS_SURROGATE(ch)) {
+            if (U_IS_LEAD(ch)) {
+lowsurogate:
+                if (mySource < sourceLimit) {
+                    ch2 = *mySource;
+                    if (U_IS_TRAIL(ch2)) {
+                        ch = ((ch - SURROGATE_HIGH_START) << HALF_SHIFT) + ch2 + SURROGATE_LOW_BASE;
+                        mySource++;
+                    }
+                    else {
+                        /* this is an unmatched trail code unit (2nd surrogate) */
+                        /* callback(illegal) */
+                        args->converter->fromUChar32 = ch;
+                        *err = U_ILLEGAL_CHAR_FOUND;
+                        break;
+                    }
+                }
+                else {
+                    /* ran out of source */
+                    args->converter->fromUChar32 = ch;
+                    if (args->flush) {
+                        /* this is an unmatched trail code unit (2nd surrogate) */
+                        /* callback(illegal) */
+                        *err = U_ILLEGAL_CHAR_FOUND;
+                    }
+                    break;
+                }
+            }
+            else {
+                /* this is an unmatched trail code unit (2nd surrogate) */
+                /* callback(illegal) */
+                args->converter->fromUChar32 = ch;
+                *err = U_ILLEGAL_CHAR_FOUND;
+                break;
+            }
+        }
+
+        /* We cannot get any larger than 10FFFF because we are coming from UTF-16 */
+        temp[1] = (uint8_t) (ch >> 16 & 0x1F);
+        temp[2] = (uint8_t) (ch >> 8);  /* unsigned cast implicitly does (ch & FF) */
+        temp[3] = (uint8_t) (ch);       /* unsigned cast implicitly does (ch & FF) */
+
+        for (indexToWrite = 0; indexToWrite <= sizeof(uint32_t) - 1; indexToWrite++) {
+            if (myTarget < targetLimit) {
+                *(myTarget++) = temp[indexToWrite];
+            }
+            else {
+                args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = temp[indexToWrite];
+                *err = U_BUFFER_OVERFLOW_ERROR;
+            }
+        }
+    }
+
+    if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err)) {
+        *err = U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    args->target = (char *) myTarget;
+    args->source = mySource;
+}
+
+static void
+T_UConverter_fromUnicode_UTF32_BE_OFFSET_LOGIC(UConverterFromUnicodeArgs * args,
+                                               UErrorCode * err)
+{
+    const UChar *mySource = args->source;
+    unsigned char *myTarget;
+    int32_t *myOffsets;
+    const UChar *sourceLimit = args->sourceLimit;
+    const unsigned char *targetLimit = (unsigned char *) args->targetLimit;
+    UChar32 ch, ch2;
+    int32_t offsetNum = 0;
+    unsigned int indexToWrite;
+    unsigned char temp[sizeof(uint32_t)];
+
+    if(mySource >= sourceLimit) {
+        /* no input, nothing to do */
+        return;
+    }
+
+    /* write the BOM if necessary */
+    if(args->converter->fromUnicodeStatus==UCNV_NEED_TO_WRITE_BOM) {
+        static const char bom[]={ 0, 0, (char)0xfe, (char)0xff };
+        ucnv_fromUWriteBytes(args->converter,
+                             bom, 4,
+                             &args->target, args->targetLimit,
+                             &args->offsets, -1,
+                             err);
+        args->converter->fromUnicodeStatus=0;
+    }
+
+    myTarget = (unsigned char *) args->target;
+    myOffsets = args->offsets;
+    temp[0] = 0;
+
+    if (args->converter->fromUChar32) {
+        ch = args->converter->fromUChar32;
+        args->converter->fromUChar32 = 0;
+        goto lowsurogate;
+    }
+
+    while (mySource < sourceLimit && myTarget < targetLimit) {
+        ch = *(mySource++);
+
+        if (UTF_IS_SURROGATE(ch)) {
+            if (U_IS_LEAD(ch)) {
+lowsurogate:
+                if (mySource < sourceLimit) {
+                    ch2 = *mySource;
+                    if (U_IS_TRAIL(ch2)) {
+                        ch = ((ch - SURROGATE_HIGH_START) << HALF_SHIFT) + ch2 + SURROGATE_LOW_BASE;
+                        mySource++;
+                    }
+                    else {
+                        /* this is an unmatched trail code unit (2nd surrogate) */
+                        /* callback(illegal) */
+                        args->converter->fromUChar32 = ch;
+                        *err = U_ILLEGAL_CHAR_FOUND;
+                        break;
+                    }
+                }
+                else {
+                    /* ran out of source */
+                    args->converter->fromUChar32 = ch;
+                    if (args->flush) {
+                        /* this is an unmatched trail code unit (2nd surrogate) */
+                        /* callback(illegal) */
+                        *err = U_ILLEGAL_CHAR_FOUND;
+                    }
+                    break;
+                }
+            }
+            else {
+                /* this is an unmatched trail code unit (2nd surrogate) */
+                /* callback(illegal) */
+                args->converter->fromUChar32 = ch;
+                *err = U_ILLEGAL_CHAR_FOUND;
+                break;
+            }
+        }
+
+        /* We cannot get any larger than 10FFFF because we are coming from UTF-16 */
+        temp[1] = (uint8_t) (ch >> 16 & 0x1F);
+        temp[2] = (uint8_t) (ch >> 8);  /* unsigned cast implicitly does (ch & FF) */
+        temp[3] = (uint8_t) (ch);       /* unsigned cast implicitly does (ch & FF) */
+
+        for (indexToWrite = 0; indexToWrite <= sizeof(uint32_t) - 1; indexToWrite++) {
+            if (myTarget < targetLimit) {
+                *(myTarget++) = temp[indexToWrite];
+                *(myOffsets++) = offsetNum;
+            }
+            else {
+                args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = temp[indexToWrite];
+                *err = U_BUFFER_OVERFLOW_ERROR;
+            }
+        }
+        offsetNum = offsetNum + 1 + (temp[1] != 0);
+    }
+
+    if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err)) {
+        *err = U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    args->target = (char *) myTarget;
+    args->source = mySource;
+    args->offsets = myOffsets;
+}
+
+static UChar32
+T_UConverter_getNextUChar_UTF32_BE(UConverterToUnicodeArgs* args,
+                                   UErrorCode* err)
+{
+    const uint8_t *mySource;
+    UChar32 myUChar;
+    int32_t length;
+
+    mySource = (const uint8_t *)args->source;
+    if (mySource >= (const uint8_t *)args->sourceLimit)
+    {
+        /* no input */
+        *err = U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0xffff;
+    }
+
+    length = (int32_t)((const uint8_t *)args->sourceLimit - mySource);
+    if (length < 4) 
+    {
+        /* got a partial character */
+        uprv_memcpy(args->converter->toUBytes, mySource, length);
+        args->converter->toULength = (int8_t)length;
+        args->source = (const char *)(mySource + length);
+        *err = U_TRUNCATED_CHAR_FOUND;
+        return 0xffff;
+    }
+
+    /* Don't even try to do a direct cast because the value may be on an odd address. */
+    myUChar = ((UChar32)mySource[0] << 24)
+            | ((UChar32)mySource[1] << 16)
+            | ((UChar32)mySource[2] << 8)
+            | ((UChar32)mySource[3]);
+
+    args->source = (const char *)(mySource + 4);
+    if ((uint32_t)myUChar <= MAXIMUM_UTF && !U_IS_SURROGATE(myUChar)) {
+        return myUChar;
+    }
+
+    uprv_memcpy(args->converter->toUBytes, mySource, 4);
+    args->converter->toULength = 4;
+
+    *err = U_ILLEGAL_CHAR_FOUND;
+    return 0xffff;
+}
+
+static const UConverterImpl _UTF32BEImpl = {
+    UCNV_UTF32_BigEndian,
+
+    NULL,
+    NULL,
+
+    NULL,
+    NULL,
+    NULL,
+
+    T_UConverter_toUnicode_UTF32_BE,
+    T_UConverter_toUnicode_UTF32_BE_OFFSET_LOGIC,
+    T_UConverter_fromUnicode_UTF32_BE,
+    T_UConverter_fromUnicode_UTF32_BE_OFFSET_LOGIC,
+    T_UConverter_getNextUChar_UTF32_BE,
+
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    ucnv_getNonSurrogateUnicodeSet
+};
+
+/* The 1232 CCSID refers to any version of Unicode with any endianess of UTF-32 */
+static const UConverterStaticData _UTF32BEStaticData = {
+    sizeof(UConverterStaticData),
+    "UTF-32BE",
+    1232,
+    UCNV_IBM, UCNV_UTF32_BigEndian, 4, 4,
+    { 0, 0, 0xff, 0xfd }, 4, FALSE, FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+
+const UConverterSharedData _UTF32BEData = {
+    sizeof(UConverterSharedData), ~((uint32_t) 0),
+    NULL, NULL, &_UTF32BEStaticData, FALSE, &_UTF32BEImpl, 
+    0
+};
+
+/* UTF-32LE ---------------------------------------------------------- */
+
+static void
+T_UConverter_toUnicode_UTF32_LE(UConverterToUnicodeArgs * args,
+                                UErrorCode * err)
+{
+    const unsigned char *mySource = (unsigned char *) args->source;
+    UChar *myTarget = args->target;
+    const unsigned char *sourceLimit = (unsigned char *) args->sourceLimit;
+    const UChar *targetLimit = args->targetLimit;
+    unsigned char *toUBytes = args->converter->toUBytes;
+    uint32_t ch, i;
+
+    /* Restore state of current sequence */
+    if (args->converter->toUnicodeStatus && myTarget < targetLimit)
+    {
+        i = args->converter->toULength;       /* restore # of bytes consumed */
+        args->converter->toULength = 0;
+
+        /* Stores the previously calculated ch from a previous call*/
+        ch = args->converter->toUnicodeStatus - 1;
+        args->converter->toUnicodeStatus = 0;
+        goto morebytes;
+    }
+
+    while (mySource < sourceLimit && myTarget < targetLimit)
+    {
+        i = 0;
+        ch = 0;
+morebytes:
+        while (i < sizeof(uint32_t))
+        {
+            if (mySource < sourceLimit)
+            {
+                ch |= ((uint8_t)(*mySource)) << (i * 8);
+                toUBytes[i++] = (char) *(mySource++);
+            }
+            else
+            {
+                /* stores a partially calculated target*/
+                /* + 1 to make 0 a valid character */
+                args->converter->toUnicodeStatus = ch + 1;
+                args->converter->toULength = (int8_t) i;
+                goto donefornow;
+            }
+        }
+
+        if (ch <= MAXIMUM_UTF && !U_IS_SURROGATE(ch)) {
+            /* Normal valid byte when the loop has not prematurely terminated (i < inBytes) */
+            if (ch <= MAXIMUM_UCS2) {
+                /* fits in 16 bits */
+                *(myTarget++) = (UChar) ch;
+            }
+            else {
+                /* write out the surrogates */
+                *(myTarget++) = U16_LEAD(ch);
+                ch = U16_TRAIL(ch);
+                if (myTarget < targetLimit) {
+                    *(myTarget++) = (UChar)ch;
+                }
+                else {
+                    /* Put in overflow buffer (not handled here) */
+                    args->converter->UCharErrorBuffer[0] = (UChar) ch;
+                    args->converter->UCharErrorBufferLength = 1;
+                    *err = U_BUFFER_OVERFLOW_ERROR;
+                    break;
+                }
+            }
+        }
+        else {
+            args->converter->toULength = (int8_t)i;
+            *err = U_ILLEGAL_CHAR_FOUND;
+            break;
+        }
+    }
+
+donefornow:
+    if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err))
+    {
+        /* End of target buffer */
+        *err = U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    args->target = myTarget;
+    args->source = (const char *) mySource;
+}
+
+static void
+T_UConverter_toUnicode_UTF32_LE_OFFSET_LOGIC(UConverterToUnicodeArgs * args,
+                                             UErrorCode * err)
+{
+    const unsigned char *mySource = (unsigned char *) args->source;
+    UChar *myTarget = args->target;
+    int32_t *myOffsets = args->offsets;
+    const unsigned char *sourceLimit = (unsigned char *) args->sourceLimit;
+    const UChar *targetLimit = args->targetLimit;
+    unsigned char *toUBytes = args->converter->toUBytes;
+    uint32_t ch, i;
+    int32_t offsetNum = 0;
+
+    /* Restore state of current sequence */
+    if (args->converter->toUnicodeStatus && myTarget < targetLimit)
+    {
+        i = args->converter->toULength;       /* restore # of bytes consumed */
+        args->converter->toULength = 0;
+
+        /* Stores the previously calculated ch from a previous call*/
+        ch = args->converter->toUnicodeStatus - 1;
+        args->converter->toUnicodeStatus = 0;
+        goto morebytes;
+    }
+
+    while (mySource < sourceLimit && myTarget < targetLimit)
+    {
+        i = 0;
+        ch = 0;
+morebytes:
+        while (i < sizeof(uint32_t))
+        {
+            if (mySource < sourceLimit)
+            {
+                ch |= ((uint8_t)(*mySource)) << (i * 8);
+                toUBytes[i++] = (char) *(mySource++);
+            }
+            else
+            {
+                /* stores a partially calculated target*/
+                /* + 1 to make 0 a valid character */
+                args->converter->toUnicodeStatus = ch + 1;
+                args->converter->toULength = (int8_t) i;
+                goto donefornow;
+            }
+        }
+
+        if (ch <= MAXIMUM_UTF && !U_IS_SURROGATE(ch))
+        {
+            /* Normal valid byte when the loop has not prematurely terminated (i < inBytes) */
+            if (ch <= MAXIMUM_UCS2) 
+            {
+                /* fits in 16 bits */
+                *(myTarget++) = (UChar) ch;
+                *(myOffsets++) = offsetNum;
+            }
+            else {
+                /* write out the surrogates */
+                *(myTarget++) = U16_LEAD(ch);
+                *(myOffsets++) = offsetNum;
+                ch = U16_TRAIL(ch);
+                if (myTarget < targetLimit)
+                {
+                    *(myTarget++) = (UChar)ch;
+                    *(myOffsets++) = offsetNum;
+                }
+                else
+                {
+                    /* Put in overflow buffer (not handled here) */
+                    args->converter->UCharErrorBuffer[0] = (UChar) ch;
+                    args->converter->UCharErrorBufferLength = 1;
+                    *err = U_BUFFER_OVERFLOW_ERROR;
+                    break;
+                }
+            }
+        }
+        else
+        {
+            args->converter->toULength = (int8_t)i;
+            *err = U_ILLEGAL_CHAR_FOUND;
+            break;
+        }
+        offsetNum += i;
+    }
+
+donefornow:
+    if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err))
+    {
+        /* End of target buffer */
+        *err = U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    args->target = myTarget;
+    args->source = (const char *) mySource;
+    args->offsets = myOffsets;
+}
+
+static void
+T_UConverter_fromUnicode_UTF32_LE(UConverterFromUnicodeArgs * args,
+                                  UErrorCode * err)
+{
+    const UChar *mySource = args->source;
+    unsigned char *myTarget;
+    const UChar *sourceLimit = args->sourceLimit;
+    const unsigned char *targetLimit = (unsigned char *) args->targetLimit;
+    UChar32 ch, ch2;
+    unsigned int indexToWrite;
+    unsigned char temp[sizeof(uint32_t)];
+
+    if(mySource >= sourceLimit) {
+        /* no input, nothing to do */
+        return;
+    }
+
+    /* write the BOM if necessary */
+    if(args->converter->fromUnicodeStatus==UCNV_NEED_TO_WRITE_BOM) {
+        static const char bom[]={ (char)0xff, (char)0xfe, 0, 0 };
+        ucnv_fromUWriteBytes(args->converter,
+                             bom, 4,
+                             &args->target, args->targetLimit,
+                             &args->offsets, -1,
+                             err);
+        args->converter->fromUnicodeStatus=0;
+    }
+
+    myTarget = (unsigned char *) args->target;
+    temp[3] = 0;
+
+    if (args->converter->fromUChar32)
+    {
+        ch = args->converter->fromUChar32;
+        args->converter->fromUChar32 = 0;
+        goto lowsurogate;
+    }
+
+    while (mySource < sourceLimit && myTarget < targetLimit)
+    {
+        ch = *(mySource++);
+
+        if (UTF_IS_SURROGATE(ch)) {
+            if (U_IS_LEAD(ch))
+            {
+lowsurogate:
+                if (mySource < sourceLimit)
+                {
+                    ch2 = *mySource;
+                    if (U_IS_TRAIL(ch2)) {
+                        ch = ((ch - SURROGATE_HIGH_START) << HALF_SHIFT) + ch2 + SURROGATE_LOW_BASE;
+                        mySource++;
+                    }
+                    else {
+                        /* this is an unmatched trail code unit (2nd surrogate) */
+                        /* callback(illegal) */
+                        args->converter->fromUChar32 = ch;
+                        *err = U_ILLEGAL_CHAR_FOUND;
+                        break;
+                    }
+                }
+                else {
+                    /* ran out of source */
+                    args->converter->fromUChar32 = ch;
+                    if (args->flush) {
+                        /* this is an unmatched trail code unit (2nd surrogate) */
+                        /* callback(illegal) */
+                        *err = U_ILLEGAL_CHAR_FOUND;
+                    }
+                    break;
+                }
+            }
+            else {
+                /* this is an unmatched trail code unit (2nd surrogate) */
+                /* callback(illegal) */
+                args->converter->fromUChar32 = ch;
+                *err = U_ILLEGAL_CHAR_FOUND;
+                break;
+            }
+        }
+
+        /* We cannot get any larger than 10FFFF because we are coming from UTF-16 */
+        temp[2] = (uint8_t) (ch >> 16 & 0x1F);
+        temp[1] = (uint8_t) (ch >> 8);  /* unsigned cast implicitly does (ch & FF) */
+        temp[0] = (uint8_t) (ch);       /* unsigned cast implicitly does (ch & FF) */
+
+        for (indexToWrite = 0; indexToWrite <= sizeof(uint32_t) - 1; indexToWrite++)
+        {
+            if (myTarget < targetLimit)
+            {
+                *(myTarget++) = temp[indexToWrite];
+            }
+            else
+            {
+                args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = temp[indexToWrite];
+                *err = U_BUFFER_OVERFLOW_ERROR;
+            }
+        }
+    }
+
+    if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err))
+    {
+        *err = U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    args->target = (char *) myTarget;
+    args->source = mySource;
+}
+
+static void
+T_UConverter_fromUnicode_UTF32_LE_OFFSET_LOGIC(UConverterFromUnicodeArgs * args,
+                                               UErrorCode * err)
+{
+    const UChar *mySource = args->source;
+    unsigned char *myTarget;
+    int32_t *myOffsets;
+    const UChar *sourceLimit = args->sourceLimit;
+    const unsigned char *targetLimit = (unsigned char *) args->targetLimit;
+    UChar32 ch, ch2;
+    unsigned int indexToWrite;
+    unsigned char temp[sizeof(uint32_t)];
+    int32_t offsetNum = 0;
+
+    if(mySource >= sourceLimit) {
+        /* no input, nothing to do */
+        return;
+    }
+
+    /* write the BOM if necessary */
+    if(args->converter->fromUnicodeStatus==UCNV_NEED_TO_WRITE_BOM) {
+        static const char bom[]={ (char)0xff, (char)0xfe, 0, 0 };
+        ucnv_fromUWriteBytes(args->converter,
+                             bom, 4,
+                             &args->target, args->targetLimit,
+                             &args->offsets, -1,
+                             err);
+        args->converter->fromUnicodeStatus=0;
+    }
+
+    myTarget = (unsigned char *) args->target;
+    myOffsets = args->offsets;
+    temp[3] = 0;
+
+    if (args->converter->fromUChar32)
+    {
+        ch = args->converter->fromUChar32;
+        args->converter->fromUChar32 = 0;
+        goto lowsurogate;
+    }
+
+    while (mySource < sourceLimit && myTarget < targetLimit)
+    {
+        ch = *(mySource++);
+
+        if (UTF_IS_SURROGATE(ch)) {
+            if (U_IS_LEAD(ch))
+            {
+lowsurogate:
+                if (mySource < sourceLimit)
+                {
+                    ch2 = *mySource;
+                    if (U_IS_TRAIL(ch2))
+                    {
+                        ch = ((ch - SURROGATE_HIGH_START) << HALF_SHIFT) + ch2 + SURROGATE_LOW_BASE;
+                        mySource++;
+                    }
+                    else {
+                        /* this is an unmatched trail code unit (2nd surrogate) */
+                        /* callback(illegal) */
+                        args->converter->fromUChar32 = ch;
+                        *err = U_ILLEGAL_CHAR_FOUND;
+                        break;
+                    }
+                }
+                else {
+                    /* ran out of source */
+                    args->converter->fromUChar32 = ch;
+                    if (args->flush) {
+                        /* this is an unmatched trail code unit (2nd surrogate) */
+                        /* callback(illegal) */
+                        *err = U_ILLEGAL_CHAR_FOUND;
+                    }
+                    break;
+                }
+            }
+            else {
+                /* this is an unmatched trail code unit (2nd surrogate) */
+                /* callback(illegal) */
+                args->converter->fromUChar32 = ch;
+                *err = U_ILLEGAL_CHAR_FOUND;
+                break;
+            }
+        }
+
+        /* We cannot get any larger than 10FFFF because we are coming from UTF-16 */
+        temp[2] = (uint8_t) (ch >> 16 & 0x1F);
+        temp[1] = (uint8_t) (ch >> 8);  /* unsigned cast implicitly does (ch & FF) */
+        temp[0] = (uint8_t) (ch);       /* unsigned cast implicitly does (ch & FF) */
+
+        for (indexToWrite = 0; indexToWrite <= sizeof(uint32_t) - 1; indexToWrite++)
+        {
+            if (myTarget < targetLimit)
+            {
+                *(myTarget++) = temp[indexToWrite];
+                *(myOffsets++) = offsetNum;
+            }
+            else
+            {
+                args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = temp[indexToWrite];
+                *err = U_BUFFER_OVERFLOW_ERROR;
+            }
+        }
+        offsetNum = offsetNum + 1 + (temp[2] != 0);
+    }
+
+    if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err))
+    {
+        *err = U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    args->target = (char *) myTarget;
+    args->source = mySource;
+    args->offsets = myOffsets;
+}
+
+static UChar32
+T_UConverter_getNextUChar_UTF32_LE(UConverterToUnicodeArgs* args,
+                                   UErrorCode* err)
+{
+    const uint8_t *mySource;
+    UChar32 myUChar;
+    int32_t length;
+
+    mySource = (const uint8_t *)args->source;
+    if (mySource >= (const uint8_t *)args->sourceLimit)
+    {
+        /* no input */
+        *err = U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0xffff;
+    }
+
+    length = (int32_t)((const uint8_t *)args->sourceLimit - mySource);
+    if (length < 4) 
+    {
+        /* got a partial character */
+        uprv_memcpy(args->converter->toUBytes, mySource, length);
+        args->converter->toULength = (int8_t)length;
+        args->source = (const char *)(mySource + length);
+        *err = U_TRUNCATED_CHAR_FOUND;
+        return 0xffff;
+    }
+
+    /* Don't even try to do a direct cast because the value may be on an odd address. */
+    myUChar = ((UChar32)mySource[3] << 24)
+            | ((UChar32)mySource[2] << 16)
+            | ((UChar32)mySource[1] << 8)
+            | ((UChar32)mySource[0]);
+
+    args->source = (const char *)(mySource + 4);
+    if ((uint32_t)myUChar <= MAXIMUM_UTF && !U_IS_SURROGATE(myUChar)) {
+        return myUChar;
+    }
+
+    uprv_memcpy(args->converter->toUBytes, mySource, 4);
+    args->converter->toULength = 4;
+
+    *err = U_ILLEGAL_CHAR_FOUND;
+    return 0xffff;
+}
+
+static const UConverterImpl _UTF32LEImpl = {
+    UCNV_UTF32_LittleEndian,
+
+    NULL,
+    NULL,
+
+    NULL,
+    NULL,
+    NULL,
+
+    T_UConverter_toUnicode_UTF32_LE,
+    T_UConverter_toUnicode_UTF32_LE_OFFSET_LOGIC,
+    T_UConverter_fromUnicode_UTF32_LE,
+    T_UConverter_fromUnicode_UTF32_LE_OFFSET_LOGIC,
+    T_UConverter_getNextUChar_UTF32_LE,
+
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    ucnv_getNonSurrogateUnicodeSet
+};
+
+/* The 1232 CCSID refers to any version of Unicode with any endianess of UTF-32 */
+static const UConverterStaticData _UTF32LEStaticData = {
+    sizeof(UConverterStaticData),
+    "UTF-32LE",
+    1234,
+    UCNV_IBM, UCNV_UTF32_LittleEndian, 4, 4,
+    { 0xfd, 0xff, 0, 0 }, 4, FALSE, FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+
+
+const UConverterSharedData _UTF32LEData = {
+    sizeof(UConverterSharedData), ~((uint32_t) 0),
+    NULL, NULL, &_UTF32LEStaticData, FALSE, &_UTF32LEImpl, 
+    0
+};
+
+/* UTF-32 (Detect BOM) ------------------------------------------------------ */
+
+/*
+ * Detect a BOM at the beginning of the stream and select UTF-32BE or UTF-32LE
+ * accordingly.
+ *
+ * State values:
+ * 0    initial state
+ * 1    saw 00
+ * 2    saw 00 00
+ * 3    saw 00 00 FE
+ * 4    -
+ * 5    saw FF
+ * 6    saw FF FE
+ * 7    saw FF FE 00
+ * 8    UTF-32BE mode
+ * 9    UTF-32LE mode
+ *
+ * During detection: state&3==number of matching bytes so far.
+ *
+ * On output, emit U+FEFF as the first code point.
+ */
+
+static void
+_UTF32Reset(UConverter *cnv, UConverterResetChoice choice) {
+    if(choice<=UCNV_RESET_TO_UNICODE) {
+        /* reset toUnicode: state=0 */
+        cnv->mode=0;
+    }
+    if(choice!=UCNV_RESET_TO_UNICODE) {
+        /* reset fromUnicode: prepare to output the UTF-32PE BOM */
+        cnv->fromUnicodeStatus=UCNV_NEED_TO_WRITE_BOM;
+    }
+}
+
+static void
+_UTF32Open(UConverter *cnv,
+           UConverterLoadArgs *pArgs,
+           UErrorCode *pErrorCode) {
+    _UTF32Reset(cnv, UCNV_RESET_BOTH);
+}
+
+static const char utf32BOM[8]={ 0, 0, (char)0xfe, (char)0xff,    (char)0xff, (char)0xfe, 0, 0 };
+
+static void
+_UTF32ToUnicodeWithOffsets(UConverterToUnicodeArgs *pArgs,
+                           UErrorCode *pErrorCode) {
+    UConverter *cnv=pArgs->converter;
+    const char *source=pArgs->source;
+    const char *sourceLimit=pArgs->sourceLimit;
+    int32_t *offsets=pArgs->offsets;
+
+    int32_t state, offsetDelta;
+    char b;
+
+    state=cnv->mode;
+
+    /*
+     * If we detect a BOM in this buffer, then we must add the BOM size to the
+     * offsets because the actual converter function will not see and count the BOM.
+     * offsetDelta will have the number of the BOM bytes that are in the current buffer.
+     */
+    offsetDelta=0;
+
+    while(source<sourceLimit && U_SUCCESS(*pErrorCode)) {
+        switch(state) {
+        case 0:
+            b=*source;
+            if(b==0) {
+                state=1; /* could be 00 00 FE FF */
+            } else if(b==(char)0xff) {
+                state=5; /* could be FF FE 00 00 */
+            } else {
+                state=8; /* default to UTF-32BE */
+                continue;
+            }
+            ++source;
+            break;
+        case 1:
+        case 2:
+        case 3:
+        case 5:
+        case 6:
+        case 7:
+            if(*source==utf32BOM[state]) {
+                ++state;
+                ++source;
+                if(state==4) {
+                    state=8; /* detect UTF-32BE */
+                    offsetDelta=(int32_t)(source-pArgs->source);
+                } else if(state==8) {
+                    state=9; /* detect UTF-32LE */
+                    offsetDelta=(int32_t)(source-pArgs->source);
+                }
+            } else {
+                /* switch to UTF-32BE and pass the previous bytes */
+                int32_t count=(int32_t)(source-pArgs->source); /* number of bytes from this buffer */
+
+                /* reset the source */
+                source=pArgs->source;
+
+                if(count==(state&3)) {
+                    /* simple: all in the same buffer, just reset source */
+                } else {
+                    UBool oldFlush=pArgs->flush;
+
+                    /* some of the bytes are from a previous buffer, replay those first */
+                    pArgs->source=utf32BOM+(state&4); /* select the correct BOM */
+                    pArgs->sourceLimit=pArgs->source+((state&3)-count); /* replay previous bytes */
+                    pArgs->flush=FALSE; /* this sourceLimit is not the real source stream limit */
+
+                    /* no offsets: bytes from previous buffer, and not enough for output */
+                    T_UConverter_toUnicode_UTF32_BE(pArgs, pErrorCode);
+
+                    /* restore real pointers; pArgs->source will be set in case 8/9 */
+                    pArgs->sourceLimit=sourceLimit;
+                    pArgs->flush=oldFlush;
+                }
+                state=8;
+                continue;
+            }
+            break;
+        case 8:
+            /* call UTF-32BE */
+            pArgs->source=source;
+            if(offsets==NULL) {
+                T_UConverter_toUnicode_UTF32_BE(pArgs, pErrorCode);
+            } else {
+                T_UConverter_toUnicode_UTF32_BE_OFFSET_LOGIC(pArgs, pErrorCode);
+            }
+            source=pArgs->source;
+            break;
+        case 9:
+            /* call UTF-32LE */
+            pArgs->source=source;
+            if(offsets==NULL) {
+                T_UConverter_toUnicode_UTF32_LE(pArgs, pErrorCode);
+            } else {
+                T_UConverter_toUnicode_UTF32_LE_OFFSET_LOGIC(pArgs, pErrorCode);
+            }
+            source=pArgs->source;
+            break;
+        default:
+            break; /* does not occur */
+        }
+    }
+
+    /* add BOM size to offsets - see comment at offsetDelta declaration */
+    if(offsets!=NULL && offsetDelta!=0) {
+        int32_t *offsetsLimit=pArgs->offsets;
+        while(offsets<offsetsLimit) {
+            *offsets++ += offsetDelta;
+        }
+    }
+
+    pArgs->source=source;
+
+    if(source==sourceLimit && pArgs->flush) {
+        /* handle truncated input */
+        switch(state) {
+        case 0:
+            break; /* no input at all, nothing to do */
+        case 8:
+            T_UConverter_toUnicode_UTF32_BE(pArgs, pErrorCode);
+            break;
+        case 9:
+            T_UConverter_toUnicode_UTF32_LE(pArgs, pErrorCode);
+            break;
+        default:
+            /* handle 0<state<8: call UTF-32BE with too-short input */
+            pArgs->source=utf32BOM+(state&4); /* select the correct BOM */
+            pArgs->sourceLimit=pArgs->source+(state&3); /* replay bytes */
+
+            /* no offsets: not enough for output */
+            T_UConverter_toUnicode_UTF32_BE(pArgs, pErrorCode);
+            pArgs->source=source;
+            pArgs->sourceLimit=sourceLimit;
+            state=8;
+            break;
+        }
+    }
+
+    cnv->mode=state;
+}
+
+static UChar32
+_UTF32GetNextUChar(UConverterToUnicodeArgs *pArgs,
+                   UErrorCode *pErrorCode) {
+    switch(pArgs->converter->mode) {
+    case 8:
+        return T_UConverter_getNextUChar_UTF32_BE(pArgs, pErrorCode);
+    case 9:
+        return T_UConverter_getNextUChar_UTF32_LE(pArgs, pErrorCode);
+    default:
+        return UCNV_GET_NEXT_UCHAR_USE_TO_U;
+    }
+}
+
+static const UConverterImpl _UTF32Impl = {
+    UCNV_UTF32,
+
+    NULL,
+    NULL,
+
+    _UTF32Open,
+    NULL,
+    _UTF32Reset,
+
+    _UTF32ToUnicodeWithOffsets,
+    _UTF32ToUnicodeWithOffsets,
+#if U_IS_BIG_ENDIAN
+    T_UConverter_fromUnicode_UTF32_BE,
+    T_UConverter_fromUnicode_UTF32_BE_OFFSET_LOGIC,
+#else
+    T_UConverter_fromUnicode_UTF32_LE,
+    T_UConverter_fromUnicode_UTF32_LE_OFFSET_LOGIC,
+#endif
+    _UTF32GetNextUChar,
+
+    NULL, /* ### TODO implement getStarters for all Unicode encodings?! */
+    NULL,
+    NULL,
+    NULL,
+    ucnv_getNonSurrogateUnicodeSet
+};
+
+/* The 1236 CCSID refers to any version of Unicode with a BOM sensitive endianess of UTF-32 */
+static const UConverterStaticData _UTF32StaticData = {
+    sizeof(UConverterStaticData),
+    "UTF-32",
+    1236,
+    UCNV_IBM, UCNV_UTF32, 4, 4,
+#if U_IS_BIG_ENDIAN
+    { 0, 0, 0xff, 0xfd }, 4,
+#else
+    { 0xfd, 0xff, 0, 0 }, 4,
+#endif
+    FALSE, FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+
+const UConverterSharedData _UTF32Data = {
+    sizeof(UConverterSharedData), ~((uint32_t) 0),
+    NULL, NULL, &_UTF32StaticData, FALSE, &_UTF32Impl, 
+    0
+};
+
+#endif
diff --git a/source/common/ucnv_u7.c b/source/common/ucnv_u7.c
new file mode 100644
index 0000000..8ef3605
--- /dev/null
+++ b/source/common/ucnv_u7.c
@@ -0,0 +1,1458 @@
+/*  
+**********************************************************************
+*   Copyright (C) 2002-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   file name:  ucnv_u7.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002jul01
+*   created by: Markus W. Scherer
+*
+*   UTF-7 converter implementation. Used to be in ucnv_utf.c.
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ucnv.h"
+#include "ucnv_bld.h"
+#include "ucnv_cnv.h"
+
+/* UTF-7 -------------------------------------------------------------------- */
+
+/*
+ * UTF-7 is a stateful encoding of Unicode.
+ * It is defined in RFC 2152. (http://www.ietf.org/rfc/rfc2152.txt)
+ * It was intended for use in Internet email systems, using in its bytewise
+ * encoding only a subset of 7-bit US-ASCII.
+ * UTF-7 is deprecated in favor of UTF-8/16/32 and SCSU, but still
+ * occasionally used.
+ *
+ * For converting Unicode to UTF-7, the RFC allows to encode some US-ASCII
+ * characters directly or in base64. Especially, the characters in set O
+ * as defined in the RFC (see below) may be encoded directly but are not
+ * allowed in, e.g., email headers.
+ * By default, the ICU UTF-7 converter encodes set O directly.
+ * By choosing the option "version=1", set O will be escaped instead.
+ * For example:
+ *     utf7Converter=ucnv_open("UTF-7,version=1");
+ *
+ * For details about email headers see RFC 2047.
+ */
+
+/*
+ * Tests for US-ASCII characters belonging to character classes
+ * defined in UTF-7.
+ *
+ * Set D (directly encoded characters) consists of the following
+ * characters: the upper and lower case letters A through Z
+ * and a through z, the 10 digits 0-9, and the following nine special
+ * characters (note that "+" and "=" are omitted):
+ *     '(),-./:?
+ *
+ * Set O (optional direct characters) consists of the following
+ * characters (note that "\" and "~" are omitted):
+ *     !"#$%&*;<=>@[]^_`{|}
+ *
+ * According to the rules in RFC 2152, the byte values for the following
+ * US-ASCII characters are not used in UTF-7 and are therefore illegal:
+ * - all C0 control codes except for CR LF TAB
+ * - BACKSLASH
+ * - TILDE
+ * - DEL
+ * - all codes beyond US-ASCII, i.e. all >127
+ */
+#define inSetD(c) \
+    ((uint8_t)((c)-97)<26 || (uint8_t)((c)-65)<26 || /* letters */ \
+     (uint8_t)((c)-48)<10 ||    /* digits */ \
+     (uint8_t)((c)-39)<3 ||     /* '() */ \
+     (uint8_t)((c)-44)<4 ||     /* ,-./ */ \
+     (c)==58 || (c)==63         /* :? */ \
+    )
+
+#define inSetO(c) \
+    ((uint8_t)((c)-33)<6 ||         /* !"#$%& */ \
+     (uint8_t)((c)-59)<4 ||         /* ;<=> */ \
+     (uint8_t)((c)-93)<4 ||         /* ]^_` */ \
+     (uint8_t)((c)-123)<3 ||        /* {|} */ \
+     (c)==42 || (c)==64 || (c)==91  /* *@[ */ \
+    )
+
+#define isCRLFTAB(c) ((c)==13 || (c)==10 || (c)==9)
+#define isCRLFSPTAB(c) ((c)==32 || (c)==13 || (c)==10 || (c)==9)
+
+#define PLUS  43
+#define MINUS 45
+#define BACKSLASH 92
+#define TILDE 126
+
+/* legal byte values: all US-ASCII graphic characters from space to before tilde, and CR LF TAB */
+#define isLegalUTF7(c) (((uint8_t)((c)-32)<94 && (c)!=BACKSLASH) || isCRLFTAB(c))
+
+/* encode directly sets D and O and CR LF SP TAB */
+static const UBool encodeDirectlyMaximum[128]={
+ /* 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
+
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0
+};
+
+/* encode directly set D and CR LF SP TAB but not set O */
+static const UBool encodeDirectlyRestricted[128]={
+ /* 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+    1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
+
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+
+    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
+};
+
+static const uint8_t
+toBase64[64]={
+    /* A-Z */
+    65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
+    78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+    /* a-z */
+    97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+    110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
+    /* 0-9 */
+    48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+    /* +/ */
+    43, 47
+};
+
+static const int8_t
+fromBase64[128]={
+    /* C0 controls, -1 for legal ones (CR LF TAB), -3 for illegal ones */
+    -3, -3, -3, -3, -3, -3, -3, -3, -3, -1, -1, -3, -3, -1, -3, -3,
+    -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,
+
+    /* general punctuation with + and / and a special value (-2) for - */
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -2, -1, 63,
+    /* digits */
+    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
+
+    /* A-Z */
+    -1,  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, -1, -3, -1, -1, -1,
+
+    /* a-z */
+    -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -3, -3
+};
+
+/*
+ * converter status values:
+ *
+ * toUnicodeStatus:
+ *     24 inDirectMode (boolean)
+ * 23..16 base64Counter (-1..7)
+ * 15..0  bits (up to 14 bits incoming base64)
+ *
+ * fromUnicodeStatus:
+ * 31..28 version (0: set O direct  1: set O escaped)
+ *     24 inDirectMode (boolean)
+ * 23..16 base64Counter (0..2)
+ *  7..0  bits (6 bits outgoing base64)
+ *
+ */
+
+static void
+_UTF7Reset(UConverter *cnv, UConverterResetChoice choice) {
+    if(choice<=UCNV_RESET_TO_UNICODE) {
+        /* reset toUnicode */
+        cnv->toUnicodeStatus=0x1000000; /* inDirectMode=TRUE */
+        cnv->toULength=0;
+    }
+    if(choice!=UCNV_RESET_TO_UNICODE) {
+        /* reset fromUnicode */
+        cnv->fromUnicodeStatus=(cnv->fromUnicodeStatus&0xf0000000)|0x1000000; /* keep version, inDirectMode=TRUE */
+    }
+}
+
+static void
+_UTF7Open(UConverter *cnv,
+          UConverterLoadArgs *pArgs,
+          UErrorCode *pErrorCode) {
+    if(UCNV_GET_VERSION(cnv)<=1) {
+        /* TODO(markus): Should just use cnv->options rather than copying the version number. */
+        cnv->fromUnicodeStatus=UCNV_GET_VERSION(cnv)<<28;
+        _UTF7Reset(cnv, UCNV_RESET_BOTH);
+    } else {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+    }
+}
+
+static void
+_UTF7ToUnicodeWithOffsets(UConverterToUnicodeArgs *pArgs,
+                          UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const uint8_t *source, *sourceLimit;
+    UChar *target;
+    const UChar *targetLimit;
+    int32_t *offsets;
+
+    uint8_t *bytes;
+    uint8_t byteIndex;
+
+    int32_t length, targetCapacity;
+
+    /* UTF-7 state */
+    uint16_t bits;
+    int8_t base64Counter;
+    UBool inDirectMode;
+
+    int8_t base64Value;
+
+    int32_t sourceIndex, nextSourceIndex;
+
+    uint8_t b;
+    /* set up the local pointers */
+    cnv=pArgs->converter;
+
+    source=(const uint8_t *)pArgs->source;
+    sourceLimit=(const uint8_t *)pArgs->sourceLimit;
+    target=pArgs->target;
+    targetLimit=pArgs->targetLimit;
+    offsets=pArgs->offsets;
+    /* get the state machine state */
+    {
+        uint32_t status=cnv->toUnicodeStatus;
+        inDirectMode=(UBool)((status>>24)&1);
+        base64Counter=(int8_t)(status>>16);
+        bits=(uint16_t)status;
+    }
+    bytes=cnv->toUBytes;
+    byteIndex=cnv->toULength;
+
+    /* sourceIndex=-1 if the current character began in the previous buffer */
+    sourceIndex=byteIndex==0 ? 0 : -1;
+    nextSourceIndex=0;
+
+    if(inDirectMode) {
+directMode:
+        /*
+         * In Direct Mode, most US-ASCII characters are encoded directly, i.e.,
+         * with their US-ASCII byte values.
+         * Backslash and Tilde and most control characters are not allowed in UTF-7.
+         * A plus sign starts Unicode (or "escape") Mode.
+         *
+         * In Direct Mode, only the sourceIndex is used.
+         */
+        byteIndex=0;
+        length=(int32_t)(sourceLimit-source);
+        targetCapacity=(int32_t)(targetLimit-target);
+        if(length>targetCapacity) {
+            length=targetCapacity;
+        }
+        while(length>0) {
+            b=*source++;
+            if(!isLegalUTF7(b)) {
+                /* illegal */
+                bytes[0]=b;
+                byteIndex=1;
+                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                break;
+            } else if(b!=PLUS) {
+                /* write directly encoded character */
+                *target++=b;
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex++;
+                }
+            } else /* PLUS */ {
+                /* switch to Unicode mode */
+                nextSourceIndex=++sourceIndex;
+                inDirectMode=FALSE;
+                byteIndex=0;
+                bits=0;
+                base64Counter=-1;
+                goto unicodeMode;
+            }
+            --length;
+        }
+        if(source<sourceLimit && target>=targetLimit) {
+            /* target is full */
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+        }
+    } else {
+unicodeMode:
+        /*
+         * In Unicode (or "escape") Mode, UTF-16BE is base64-encoded.
+         * The base64 sequence ends with any character that is not in the base64 alphabet.
+         * A terminating minus sign is consumed.
+         *
+         * In Unicode Mode, the sourceIndex has the index to the start of the current
+         * base64 bytes, while nextSourceIndex is precisely parallel to source,
+         * keeping the index to the following byte.
+         * Note that in 2 out of 3 cases, UChars overlap within a base64 byte.
+         */
+        while(source<sourceLimit) {
+            if(target<targetLimit) {
+                bytes[byteIndex++]=b=*source++;
+                ++nextSourceIndex;
+                if(b>=126) {
+                    /* illegal - test other illegal US-ASCII values by base64Value==-3 */
+                    inDirectMode=TRUE;
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                    break;
+                } else if((base64Value=fromBase64[b])>=0) {
+                    /* collect base64 bytes into UChars */
+                    switch(base64Counter) {
+                    case -1: /* -1 is immediately after the + */
+                    case 0:
+                        bits=base64Value;
+                        base64Counter=1;
+                        break;
+                    case 1:
+                    case 3:
+                    case 4:
+                    case 6:
+                        bits=(uint16_t)((bits<<6)|base64Value);
+                        ++base64Counter;
+                        break;
+                    case 2:
+                        *target++=(UChar)((bits<<4)|(base64Value>>2));
+                        if(offsets!=NULL) {
+                            *offsets++=sourceIndex;
+                            sourceIndex=nextSourceIndex-1;
+                        }
+                        bytes[0]=b; /* keep this byte in case an error occurs */
+                        byteIndex=1;
+                        bits=(uint16_t)(base64Value&3);
+                        base64Counter=3;
+                        break;
+                    case 5:
+                        *target++=(UChar)((bits<<2)|(base64Value>>4));
+                        if(offsets!=NULL) {
+                            *offsets++=sourceIndex;
+                            sourceIndex=nextSourceIndex-1;
+                        }
+                        bytes[0]=b; /* keep this byte in case an error occurs */
+                        byteIndex=1;
+                        bits=(uint16_t)(base64Value&15);
+                        base64Counter=6;
+                        break;
+                    case 7:
+                        *target++=(UChar)((bits<<6)|base64Value);
+                        if(offsets!=NULL) {
+                            *offsets++=sourceIndex;
+                            sourceIndex=nextSourceIndex;
+                        }
+                        byteIndex=0;
+                        bits=0;
+                        base64Counter=0;
+                        break;
+                    default:
+                        /* will never occur */
+                        break;
+                    }
+                } else if(base64Value==-2) {
+                    /* minus sign terminates the base64 sequence */
+                    inDirectMode=TRUE;
+                    if(base64Counter==-1) {
+                        /* +- i.e. a minus immediately following a plus */
+                        *target++=PLUS;
+                        if(offsets!=NULL) {
+                            *offsets++=sourceIndex-1;
+                        }
+                    } else {
+                        /* absorb the minus and leave the Unicode Mode */
+                        if(bits!=0) {
+                            /* bits are illegally left over, a UChar is incomplete */
+                            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                            break;
+                        }
+                    }
+                    sourceIndex=nextSourceIndex;
+                    goto directMode;
+                } else if(base64Value==-1) /* for any legal character except base64 and minus sign */ {
+                    /* leave the Unicode Mode */
+                    inDirectMode=TRUE;
+                    if(base64Counter==-1) {
+                        /* illegal: + immediately followed by something other than base64 or minus sign */
+                        /* include the plus sign in the reported sequence */
+                        --sourceIndex;
+                        bytes[0]=PLUS;
+                        bytes[1]=b;
+                        byteIndex=2;
+                        *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                        break;
+                    } else if(bits==0) {
+                        /* un-read the character in case it is a plus sign */
+                        --source;
+                        sourceIndex=nextSourceIndex-1;
+                        goto directMode;
+                    } else {
+                        /* bits are illegally left over, a UChar is incomplete */
+                        *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                        break;
+                    }
+                } else /* base64Value==-3 for illegal characters */ {
+                    /* illegal */
+                    inDirectMode=TRUE;
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                    break;
+                }
+            } else {
+                /* target is full */
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                break;
+            }
+        }
+    }
+
+    if(U_SUCCESS(*pErrorCode) && pArgs->flush && source==sourceLimit && bits==0) {
+        /*
+         * if we are in Unicode mode, then the byteIndex might not be 0,
+         * but that is ok if bits==0
+         * -> we set byteIndex=0 at the end of the stream to avoid a truncated error
+         * (not true for IMAP-mailbox-name where we must end in direct mode)
+         */
+        byteIndex=0;
+    }
+
+    /* set the converter state back into UConverter */
+    cnv->toUnicodeStatus=((uint32_t)inDirectMode<<24)|((uint32_t)((uint8_t)base64Counter)<<16)|(uint32_t)bits;
+    cnv->toULength=byteIndex;
+
+    /* write back the updated pointers */
+    pArgs->source=(const char *)source;
+    pArgs->target=target;
+    pArgs->offsets=offsets;
+    return;
+}
+
+static void
+_UTF7FromUnicodeWithOffsets(UConverterFromUnicodeArgs *pArgs,
+                            UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const UChar *source, *sourceLimit;
+    uint8_t *target, *targetLimit;
+    int32_t *offsets;
+
+    int32_t length, targetCapacity, sourceIndex;
+    UChar c;
+
+    /* UTF-7 state */
+    const UBool *encodeDirectly;
+    uint8_t bits;
+    int8_t base64Counter;
+    UBool inDirectMode;
+
+    /* set up the local pointers */
+    cnv=pArgs->converter;
+
+    /* set up the local pointers */
+    source=pArgs->source;
+    sourceLimit=pArgs->sourceLimit;
+    target=(uint8_t *)pArgs->target;
+    targetLimit=(uint8_t *)pArgs->targetLimit;
+    offsets=pArgs->offsets;
+
+    /* get the state machine state */
+    {
+        uint32_t status=cnv->fromUnicodeStatus;
+        encodeDirectly= status<0x10000000 ? encodeDirectlyMaximum : encodeDirectlyRestricted;
+        inDirectMode=(UBool)((status>>24)&1);
+        base64Counter=(int8_t)(status>>16);
+        bits=(uint8_t)status;
+    }
+
+    /* UTF-7 always encodes UTF-16 code units, therefore we need only a simple sourceIndex */
+    sourceIndex=0;
+
+    if(inDirectMode) {
+directMode:
+        length=(int32_t)(sourceLimit-source);
+        targetCapacity=(int32_t)(targetLimit-target);
+        if(length>targetCapacity) {
+            length=targetCapacity;
+        }
+        while(length>0) {
+            c=*source++;
+            /* currently always encode CR LF SP TAB directly */
+            if(c<=127 && encodeDirectly[c]) {
+                /* encode directly */
+                *target++=(uint8_t)c;
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex++;
+                }
+            } else if(c==PLUS) {
+                /* output +- for + */
+                *target++=PLUS;
+                if(target<targetLimit) {
+                    *target++=MINUS;
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex;
+                        *offsets++=sourceIndex++;
+                    }
+                    /* realign length and targetCapacity */
+                    goto directMode;
+                } else {
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex++;
+                    }
+                    cnv->charErrorBuffer[0]=MINUS;
+                    cnv->charErrorBufferLength=1;
+                    *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                    break;
+                }
+            } else {
+                /* un-read this character and switch to Unicode Mode */
+                --source;
+                *target++=PLUS;
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                }
+                inDirectMode=FALSE;
+                base64Counter=0;
+                goto unicodeMode;
+            }
+            --length;
+        }
+        if(source<sourceLimit && target>=targetLimit) {
+            /* target is full */
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+        }
+    } else {
+unicodeMode:
+        while(source<sourceLimit) {
+            if(target<targetLimit) {
+                c=*source++;
+                if(c<=127 && encodeDirectly[c]) {
+                    /* encode directly */
+                    inDirectMode=TRUE;
+
+                    /* trick: back out this character to make this easier */
+                    --source;
+
+                    /* terminate the base64 sequence */
+                    if(base64Counter!=0) {
+                        /* write remaining bits for the previous character */
+                        *target++=toBase64[bits];
+                        if(offsets!=NULL) {
+                            *offsets++=sourceIndex-1;
+                        }
+                    }
+                    if(fromBase64[c]!=-1) {
+                        /* need to terminate with a minus */
+                        if(target<targetLimit) {
+                            *target++=MINUS;
+                            if(offsets!=NULL) {
+                                *offsets++=sourceIndex-1;
+                            }
+                        } else {
+                            cnv->charErrorBuffer[0]=MINUS;
+                            cnv->charErrorBufferLength=1;
+                            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                            break;
+                        }
+                    }
+                    goto directMode;
+                } else {
+                    /*
+                     * base64 this character:
+                     * Output 2 or 3 base64 bytes for the remaining bits of the previous character
+                     * and the bits of this character, each implicitly in UTF-16BE.
+                     *
+                     * Here, bits is an 8-bit variable because only 6 bits need to be kept from one
+                     * character to the next. The actual 2 or 4 bits are shifted to the left edge
+                     * of the 6-bits field 5..0 to make the termination of the base64 sequence easier.
+                     */
+                    switch(base64Counter) {
+                    case 0:
+                        *target++=toBase64[c>>10];
+                        if(target<targetLimit) {
+                            *target++=toBase64[(c>>4)&0x3f];
+                            if(offsets!=NULL) {
+                                *offsets++=sourceIndex;
+                                *offsets++=sourceIndex++;
+                            }
+                        } else {
+                            if(offsets!=NULL) {
+                                *offsets++=sourceIndex++;
+                            }
+                            cnv->charErrorBuffer[0]=toBase64[(c>>4)&0x3f];
+                            cnv->charErrorBufferLength=1;
+                            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                        }
+                        bits=(uint8_t)((c&15)<<2);
+                        base64Counter=1;
+                        break;
+                    case 1:
+                        *target++=toBase64[bits|(c>>14)];
+                        if(target<targetLimit) {
+                            *target++=toBase64[(c>>8)&0x3f];
+                            if(target<targetLimit) {
+                                *target++=toBase64[(c>>2)&0x3f];
+                                if(offsets!=NULL) {
+                                    *offsets++=sourceIndex;
+                                    *offsets++=sourceIndex;
+                                    *offsets++=sourceIndex++;
+                                }
+                            } else {
+                                if(offsets!=NULL) {
+                                    *offsets++=sourceIndex;
+                                    *offsets++=sourceIndex++;
+                                }
+                                cnv->charErrorBuffer[0]=toBase64[(c>>2)&0x3f];
+                                cnv->charErrorBufferLength=1;
+                                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                            }
+                        } else {
+                            if(offsets!=NULL) {
+                                *offsets++=sourceIndex++;
+                            }
+                            cnv->charErrorBuffer[0]=toBase64[(c>>8)&0x3f];
+                            cnv->charErrorBuffer[1]=toBase64[(c>>2)&0x3f];
+                            cnv->charErrorBufferLength=2;
+                            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                        }
+                        bits=(uint8_t)((c&3)<<4);
+                        base64Counter=2;
+                        break;
+                    case 2:
+                        *target++=toBase64[bits|(c>>12)];
+                        if(target<targetLimit) {
+                            *target++=toBase64[(c>>6)&0x3f];
+                            if(target<targetLimit) {
+                                *target++=toBase64[c&0x3f];
+                                if(offsets!=NULL) {
+                                    *offsets++=sourceIndex;
+                                    *offsets++=sourceIndex;
+                                    *offsets++=sourceIndex++;
+                                }
+                            } else {
+                                if(offsets!=NULL) {
+                                    *offsets++=sourceIndex;
+                                    *offsets++=sourceIndex++;
+                                }
+                                cnv->charErrorBuffer[0]=toBase64[c&0x3f];
+                                cnv->charErrorBufferLength=1;
+                                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                            }
+                        } else {
+                            if(offsets!=NULL) {
+                                *offsets++=sourceIndex++;
+                            }
+                            cnv->charErrorBuffer[0]=toBase64[(c>>6)&0x3f];
+                            cnv->charErrorBuffer[1]=toBase64[c&0x3f];
+                            cnv->charErrorBufferLength=2;
+                            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                        }
+                        bits=0;
+                        base64Counter=0;
+                        break;
+                    default:
+                        /* will never occur */
+                        break;
+                    }
+                }
+            } else {
+                /* target is full */
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                break;
+            }
+        }
+    }
+
+    if(pArgs->flush && source>=sourceLimit) {
+        /* flush remaining bits to the target */
+        if(!inDirectMode && base64Counter!=0) {
+            if(target<targetLimit) {
+                *target++=toBase64[bits];
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex-1;
+                }
+            } else {
+                cnv->charErrorBuffer[cnv->charErrorBufferLength++]=toBase64[bits];
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            }
+        }
+        /* reset the state for the next conversion */
+        cnv->fromUnicodeStatus=(cnv->fromUnicodeStatus&0xf0000000)|0x1000000; /* keep version, inDirectMode=TRUE */
+    } else {
+        /* set the converter state back into UConverter */
+        cnv->fromUnicodeStatus=
+            (cnv->fromUnicodeStatus&0xf0000000)|    /* keep version*/
+            ((uint32_t)inDirectMode<<24)|((uint32_t)base64Counter<<16)|(uint32_t)bits;
+    }
+
+    /* write back the updated pointers */
+    pArgs->source=source;
+    pArgs->target=(char *)target;
+    pArgs->offsets=offsets;
+    return;
+}
+
+static const char *
+_UTF7GetName(const UConverter *cnv) {
+    switch(cnv->fromUnicodeStatus>>28) {
+    case 1:
+        return "UTF-7,version=1";
+    default:
+        return "UTF-7";
+    }
+}
+
+static const UConverterImpl _UTF7Impl={
+    UCNV_UTF7,
+
+    NULL,
+    NULL,
+
+    _UTF7Open,
+    NULL,
+    _UTF7Reset,
+
+    _UTF7ToUnicodeWithOffsets,
+    _UTF7ToUnicodeWithOffsets,
+    _UTF7FromUnicodeWithOffsets,
+    _UTF7FromUnicodeWithOffsets,
+    NULL,
+
+    NULL,
+    _UTF7GetName,
+    NULL, /* we don't need writeSub() because we never call a callback at fromUnicode() */
+    NULL,
+    ucnv_getCompleteUnicodeSet
+};
+
+static const UConverterStaticData _UTF7StaticData={
+    sizeof(UConverterStaticData),
+    "UTF-7",
+    0, /* TODO CCSID for UTF-7 */
+    UCNV_IBM, UCNV_UTF7,
+    1, 4,
+    { 0x3f, 0, 0, 0 }, 1, /* the subchar is not used */
+    FALSE, FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+
+const UConverterSharedData _UTF7Data={
+    sizeof(UConverterSharedData), ~((uint32_t)0),
+    NULL, NULL, &_UTF7StaticData, FALSE, &_UTF7Impl,
+    0
+};
+
+/* IMAP mailbox name encoding ----------------------------------------------- */
+
+/*
+ * RFC 2060: INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1
+ * http://www.ietf.org/rfc/rfc2060.txt
+ *
+ * 5.1.3.  Mailbox International Naming Convention
+ *
+ * By convention, international mailbox names are specified using a
+ * modified version of the UTF-7 encoding described in [UTF-7].  The
+ * purpose of these modifications is to correct the following problems
+ * with UTF-7:
+ *
+ *    1) UTF-7 uses the "+" character for shifting; this conflicts with
+ *       the common use of "+" in mailbox names, in particular USENET
+ *       newsgroup names.
+ *
+ *    2) UTF-7's encoding is BASE64 which uses the "/" character; this
+ *       conflicts with the use of "/" as a popular hierarchy delimiter.
+ *
+ *    3) UTF-7 prohibits the unencoded usage of "\"; this conflicts with
+ *       the use of "\" as a popular hierarchy delimiter.
+ *
+ *    4) UTF-7 prohibits the unencoded usage of "~"; this conflicts with
+ *       the use of "~" in some servers as a home directory indicator.
+ *
+ *    5) UTF-7 permits multiple alternate forms to represent the same
+ *       string; in particular, printable US-ASCII chararacters can be
+ *       represented in encoded form.
+ *
+ * In modified UTF-7, printable US-ASCII characters except for "&"
+ * represent themselves; that is, characters with octet values 0x20-0x25
+ * and 0x27-0x7e.  The character "&" (0x26) is represented by the two-
+ * octet sequence "&-".
+ *
+ * All other characters (octet values 0x00-0x1f, 0x7f-0xff, and all
+ * Unicode 16-bit octets) are represented in modified BASE64, with a
+ * further modification from [UTF-7] that "," is used instead of "/".
+ * Modified BASE64 MUST NOT be used to represent any printing US-ASCII
+ * character which can represent itself.
+ *
+ * "&" is used to shift to modified BASE64 and "-" to shift back to US-
+ * ASCII.  All names start in US-ASCII, and MUST end in US-ASCII (that
+ * is, a name that ends with a Unicode 16-bit octet MUST end with a "-
+ * ").
+ *
+ * For example, here is a mailbox name which mixes English, Japanese,
+ * and Chinese text: ~peter/mail/&ZeVnLIqe-/&U,BTFw-
+ */
+
+/*
+ * Tests for US-ASCII characters belonging to character classes
+ * defined in UTF-7.
+ *
+ * Set D (directly encoded characters) consists of the following
+ * characters: the upper and lower case letters A through Z
+ * and a through z, the 10 digits 0-9, and the following nine special
+ * characters (note that "+" and "=" are omitted):
+ *     '(),-./:?
+ *
+ * Set O (optional direct characters) consists of the following
+ * characters (note that "\" and "~" are omitted):
+ *     !"#$%&*;<=>@[]^_`{|}
+ *
+ * According to the rules in RFC 2152, the byte values for the following
+ * US-ASCII characters are not used in UTF-7 and are therefore illegal:
+ * - all C0 control codes except for CR LF TAB
+ * - BACKSLASH
+ * - TILDE
+ * - DEL
+ * - all codes beyond US-ASCII, i.e. all >127
+ */
+
+/* uses '&' not '+' to start a base64 sequence */
+#define AMPERSAND 0x26
+#define COMMA 0x2c
+#define SLASH 0x2f
+
+/* legal byte values: all US-ASCII graphic characters 0x20..0x7e */
+#define isLegalIMAP(c) (0x20<=(c) && (c)<=0x7e)
+
+/* direct-encode all of printable ASCII 0x20..0x7e except '&' 0x26 */
+#define inSetDIMAP(c) (isLegalIMAP(c) && c!=AMPERSAND)
+
+#define TO_BASE64_IMAP(n) ((n)<63 ? toBase64[n] : COMMA)
+#define FROM_BASE64_IMAP(c) ((c)==COMMA ? 63 : (c)==SLASH ? -1 : fromBase64[c])
+
+/*
+ * converter status values:
+ *
+ * toUnicodeStatus:
+ *     24 inDirectMode (boolean)
+ * 23..16 base64Counter (-1..7)
+ * 15..0  bits (up to 14 bits incoming base64)
+ *
+ * fromUnicodeStatus:
+ *     24 inDirectMode (boolean)
+ * 23..16 base64Counter (0..2)
+ *  7..0  bits (6 bits outgoing base64)
+ *
+ * ignore bits 31..25
+ */
+
+static void
+_IMAPToUnicodeWithOffsets(UConverterToUnicodeArgs *pArgs,
+                          UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const uint8_t *source, *sourceLimit;
+    UChar *target;
+    const UChar *targetLimit;
+    int32_t *offsets;
+
+    uint8_t *bytes;
+    uint8_t byteIndex;
+
+    int32_t length, targetCapacity;
+
+    /* UTF-7 state */
+    uint16_t bits;
+    int8_t base64Counter;
+    UBool inDirectMode;
+
+    int8_t base64Value;
+
+    int32_t sourceIndex, nextSourceIndex;
+
+    UChar c;
+    uint8_t b;
+
+    /* set up the local pointers */
+    cnv=pArgs->converter;
+
+    source=(const uint8_t *)pArgs->source;
+    sourceLimit=(const uint8_t *)pArgs->sourceLimit;
+    target=pArgs->target;
+    targetLimit=pArgs->targetLimit;
+    offsets=pArgs->offsets;
+    /* get the state machine state */
+    {
+        uint32_t status=cnv->toUnicodeStatus;
+        inDirectMode=(UBool)((status>>24)&1);
+        base64Counter=(int8_t)(status>>16);
+        bits=(uint16_t)status;
+    }
+    bytes=cnv->toUBytes;
+    byteIndex=cnv->toULength;
+
+    /* sourceIndex=-1 if the current character began in the previous buffer */
+    sourceIndex=byteIndex==0 ? 0 : -1;
+    nextSourceIndex=0;
+
+    if(inDirectMode) {
+directMode:
+        /*
+         * In Direct Mode, US-ASCII characters are encoded directly, i.e.,
+         * with their US-ASCII byte values.
+         * An ampersand starts Unicode (or "escape") Mode.
+         *
+         * In Direct Mode, only the sourceIndex is used.
+         */
+        byteIndex=0;
+        length=(int32_t)(sourceLimit-source);
+        targetCapacity=(int32_t)(targetLimit-target);
+        if(length>targetCapacity) {
+            length=targetCapacity;
+        }
+        while(length>0) {
+            b=*source++;
+            if(!isLegalIMAP(b)) {
+                /* illegal */
+                bytes[0]=b;
+                byteIndex=1;
+                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                break;
+            } else if(b!=AMPERSAND) {
+                /* write directly encoded character */
+                *target++=b;
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex++;
+                }
+            } else /* AMPERSAND */ {
+                /* switch to Unicode mode */
+                nextSourceIndex=++sourceIndex;
+                inDirectMode=FALSE;
+                byteIndex=0;
+                bits=0;
+                base64Counter=-1;
+                goto unicodeMode;
+            }
+            --length;
+        }
+        if(source<sourceLimit && target>=targetLimit) {
+            /* target is full */
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+        }
+    } else {
+unicodeMode:
+        /*
+         * In Unicode (or "escape") Mode, UTF-16BE is base64-encoded.
+         * The base64 sequence ends with any character that is not in the base64 alphabet.
+         * A terminating minus sign is consumed.
+         * US-ASCII must not be base64-ed.
+         *
+         * In Unicode Mode, the sourceIndex has the index to the start of the current
+         * base64 bytes, while nextSourceIndex is precisely parallel to source,
+         * keeping the index to the following byte.
+         * Note that in 2 out of 3 cases, UChars overlap within a base64 byte.
+         */
+        while(source<sourceLimit) {
+            if(target<targetLimit) {
+                bytes[byteIndex++]=b=*source++;
+                ++nextSourceIndex;
+                if(b>0x7e) {
+                    /* illegal - test other illegal US-ASCII values by base64Value==-3 */
+                    inDirectMode=TRUE;
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                    break;
+                } else if((base64Value=FROM_BASE64_IMAP(b))>=0) {
+                    /* collect base64 bytes into UChars */
+                    switch(base64Counter) {
+                    case -1: /* -1 is immediately after the & */
+                    case 0:
+                        bits=base64Value;
+                        base64Counter=1;
+                        break;
+                    case 1:
+                    case 3:
+                    case 4:
+                    case 6:
+                        bits=(uint16_t)((bits<<6)|base64Value);
+                        ++base64Counter;
+                        break;
+                    case 2:
+                        c=(UChar)((bits<<4)|(base64Value>>2));
+                        if(isLegalIMAP(c)) {
+                            /* illegal */
+                            inDirectMode=TRUE;
+                            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                            goto endloop;
+                        }
+                        *target++=c;
+                        if(offsets!=NULL) {
+                            *offsets++=sourceIndex;
+                            sourceIndex=nextSourceIndex-1;
+                        }
+                        bytes[0]=b; /* keep this byte in case an error occurs */
+                        byteIndex=1;
+                        bits=(uint16_t)(base64Value&3);
+                        base64Counter=3;
+                        break;
+                    case 5:
+                        c=(UChar)((bits<<2)|(base64Value>>4));
+                        if(isLegalIMAP(c)) {
+                            /* illegal */
+                            inDirectMode=TRUE;
+                            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                            goto endloop;
+                        }
+                        *target++=c;
+                        if(offsets!=NULL) {
+                            *offsets++=sourceIndex;
+                            sourceIndex=nextSourceIndex-1;
+                        }
+                        bytes[0]=b; /* keep this byte in case an error occurs */
+                        byteIndex=1;
+                        bits=(uint16_t)(base64Value&15);
+                        base64Counter=6;
+                        break;
+                    case 7:
+                        c=(UChar)((bits<<6)|base64Value);
+                        if(isLegalIMAP(c)) {
+                            /* illegal */
+                            inDirectMode=TRUE;
+                            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                            goto endloop;
+                        }
+                        *target++=c;
+                        if(offsets!=NULL) {
+                            *offsets++=sourceIndex;
+                            sourceIndex=nextSourceIndex;
+                        }
+                        byteIndex=0;
+                        bits=0;
+                        base64Counter=0;
+                        break;
+                    default:
+                        /* will never occur */
+                        break;
+                    }
+                } else if(base64Value==-2) {
+                    /* minus sign terminates the base64 sequence */
+                    inDirectMode=TRUE;
+                    if(base64Counter==-1) {
+                        /* &- i.e. a minus immediately following an ampersand */
+                        *target++=AMPERSAND;
+                        if(offsets!=NULL) {
+                            *offsets++=sourceIndex-1;
+                        }
+                    } else {
+                        /* absorb the minus and leave the Unicode Mode */
+                        if(bits!=0 || (base64Counter!=0 && base64Counter!=3 && base64Counter!=6)) {
+                            /* bits are illegally left over, a UChar is incomplete */
+                            /* base64Counter other than 0, 3, 6 means non-minimal zero-padding, also illegal */
+                            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                            break;
+                        }
+                    }
+                    sourceIndex=nextSourceIndex;
+                    goto directMode;
+                } else {
+                    if(base64Counter==-1) {
+                        /* illegal: & immediately followed by something other than base64 or minus sign */
+                        /* include the ampersand in the reported sequence */
+                        --sourceIndex;
+                        bytes[0]=AMPERSAND;
+                        bytes[1]=b;
+                        byteIndex=2;
+                    }
+                    /* base64Value==-1 for characters that are illegal only in Unicode mode */
+                    /* base64Value==-3 for illegal characters */
+                    /* illegal */
+                    inDirectMode=TRUE;
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                    break;
+                }
+            } else {
+                /* target is full */
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                break;
+            }
+        }
+    }
+endloop:
+
+    /*
+     * the end of the input stream and detection of truncated input
+     * are handled by the framework, but here we must check if we are in Unicode
+     * mode and byteIndex==0 because we must end in direct mode
+     *
+     * conditions:
+     *   successful
+     *   in Unicode mode and byteIndex==0
+     *   end of input and no truncated input
+     */
+    if( U_SUCCESS(*pErrorCode) &&
+        !inDirectMode && byteIndex==0 &&
+        pArgs->flush && source>=sourceLimit
+    ) {
+        if(base64Counter==-1) {
+            /* & at the very end of the input */
+            /* make the ampersand the reported sequence */
+            bytes[0]=AMPERSAND;
+            byteIndex=1;
+        }
+        /* else if(base64Counter!=-1) byteIndex remains 0 because there is no particular byte sequence */
+
+        inDirectMode=TRUE; /* avoid looping */
+        *pErrorCode=U_TRUNCATED_CHAR_FOUND;
+    }
+
+    /* set the converter state back into UConverter */
+    cnv->toUnicodeStatus=((uint32_t)inDirectMode<<24)|((uint32_t)((uint8_t)base64Counter)<<16)|(uint32_t)bits;
+    cnv->toULength=byteIndex;
+
+    /* write back the updated pointers */
+    pArgs->source=(const char *)source;
+    pArgs->target=target;
+    pArgs->offsets=offsets;
+    return;
+}
+
+static void
+_IMAPFromUnicodeWithOffsets(UConverterFromUnicodeArgs *pArgs,
+                            UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const UChar *source, *sourceLimit;
+    uint8_t *target, *targetLimit;
+    int32_t *offsets;
+
+    int32_t length, targetCapacity, sourceIndex;
+    UChar c;
+    uint8_t b;
+
+    /* UTF-7 state */
+    uint8_t bits;
+    int8_t base64Counter;
+    UBool inDirectMode;
+
+    /* set up the local pointers */
+    cnv=pArgs->converter;
+
+    /* set up the local pointers */
+    source=pArgs->source;
+    sourceLimit=pArgs->sourceLimit;
+    target=(uint8_t *)pArgs->target;
+    targetLimit=(uint8_t *)pArgs->targetLimit;
+    offsets=pArgs->offsets;
+
+    /* get the state machine state */
+    {
+        uint32_t status=cnv->fromUnicodeStatus;
+        inDirectMode=(UBool)((status>>24)&1);
+        base64Counter=(int8_t)(status>>16);
+        bits=(uint8_t)status;
+    }
+
+    /* UTF-7 always encodes UTF-16 code units, therefore we need only a simple sourceIndex */
+    sourceIndex=0;
+
+    if(inDirectMode) {
+directMode:
+        length=(int32_t)(sourceLimit-source);
+        targetCapacity=(int32_t)(targetLimit-target);
+        if(length>targetCapacity) {
+            length=targetCapacity;
+        }
+        while(length>0) {
+            c=*source++;
+            /* encode 0x20..0x7e except '&' directly */
+            if(inSetDIMAP(c)) {
+                /* encode directly */
+                *target++=(uint8_t)c;
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex++;
+                }
+            } else if(c==AMPERSAND) {
+                /* output &- for & */
+                *target++=AMPERSAND;
+                if(target<targetLimit) {
+                    *target++=MINUS;
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex;
+                        *offsets++=sourceIndex++;
+                    }
+                    /* realign length and targetCapacity */
+                    goto directMode;
+                } else {
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex++;
+                    }
+                    cnv->charErrorBuffer[0]=MINUS;
+                    cnv->charErrorBufferLength=1;
+                    *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                    break;
+                }
+            } else {
+                /* un-read this character and switch to Unicode Mode */
+                --source;
+                *target++=AMPERSAND;
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                }
+                inDirectMode=FALSE;
+                base64Counter=0;
+                goto unicodeMode;
+            }
+            --length;
+        }
+        if(source<sourceLimit && target>=targetLimit) {
+            /* target is full */
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+        }
+    } else {
+unicodeMode:
+        while(source<sourceLimit) {
+            if(target<targetLimit) {
+                c=*source++;
+                if(isLegalIMAP(c)) {
+                    /* encode directly */
+                    inDirectMode=TRUE;
+
+                    /* trick: back out this character to make this easier */
+                    --source;
+
+                    /* terminate the base64 sequence */
+                    if(base64Counter!=0) {
+                        /* write remaining bits for the previous character */
+                        *target++=TO_BASE64_IMAP(bits);
+                        if(offsets!=NULL) {
+                            *offsets++=sourceIndex-1;
+                        }
+                    }
+                    /* need to terminate with a minus */
+                    if(target<targetLimit) {
+                        *target++=MINUS;
+                        if(offsets!=NULL) {
+                            *offsets++=sourceIndex-1;
+                        }
+                    } else {
+                        cnv->charErrorBuffer[0]=MINUS;
+                        cnv->charErrorBufferLength=1;
+                        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                        break;
+                    }
+                    goto directMode;
+                } else {
+                    /*
+                     * base64 this character:
+                     * Output 2 or 3 base64 bytes for the remaining bits of the previous character
+                     * and the bits of this character, each implicitly in UTF-16BE.
+                     *
+                     * Here, bits is an 8-bit variable because only 6 bits need to be kept from one
+                     * character to the next. The actual 2 or 4 bits are shifted to the left edge
+                     * of the 6-bits field 5..0 to make the termination of the base64 sequence easier.
+                     */
+                    switch(base64Counter) {
+                    case 0:
+                        b=(uint8_t)(c>>10);
+                        *target++=TO_BASE64_IMAP(b);
+                        if(target<targetLimit) {
+                            b=(uint8_t)((c>>4)&0x3f);
+                            *target++=TO_BASE64_IMAP(b);
+                            if(offsets!=NULL) {
+                                *offsets++=sourceIndex;
+                                *offsets++=sourceIndex++;
+                            }
+                        } else {
+                            if(offsets!=NULL) {
+                                *offsets++=sourceIndex++;
+                            }
+                            b=(uint8_t)((c>>4)&0x3f);
+                            cnv->charErrorBuffer[0]=TO_BASE64_IMAP(b);
+                            cnv->charErrorBufferLength=1;
+                            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                        }
+                        bits=(uint8_t)((c&15)<<2);
+                        base64Counter=1;
+                        break;
+                    case 1:
+                        b=(uint8_t)(bits|(c>>14));
+                        *target++=TO_BASE64_IMAP(b);
+                        if(target<targetLimit) {
+                            b=(uint8_t)((c>>8)&0x3f);
+                            *target++=TO_BASE64_IMAP(b);
+                            if(target<targetLimit) {
+                                b=(uint8_t)((c>>2)&0x3f);
+                                *target++=TO_BASE64_IMAP(b);
+                                if(offsets!=NULL) {
+                                    *offsets++=sourceIndex;
+                                    *offsets++=sourceIndex;
+                                    *offsets++=sourceIndex++;
+                                }
+                            } else {
+                                if(offsets!=NULL) {
+                                    *offsets++=sourceIndex;
+                                    *offsets++=sourceIndex++;
+                                }
+                                b=(uint8_t)((c>>2)&0x3f);
+                                cnv->charErrorBuffer[0]=TO_BASE64_IMAP(b);
+                                cnv->charErrorBufferLength=1;
+                                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                            }
+                        } else {
+                            if(offsets!=NULL) {
+                                *offsets++=sourceIndex++;
+                            }
+                            b=(uint8_t)((c>>8)&0x3f);
+                            cnv->charErrorBuffer[0]=TO_BASE64_IMAP(b);
+                            b=(uint8_t)((c>>2)&0x3f);
+                            cnv->charErrorBuffer[1]=TO_BASE64_IMAP(b);
+                            cnv->charErrorBufferLength=2;
+                            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                        }
+                        bits=(uint8_t)((c&3)<<4);
+                        base64Counter=2;
+                        break;
+                    case 2:
+                        b=(uint8_t)(bits|(c>>12));
+                        *target++=TO_BASE64_IMAP(b);
+                        if(target<targetLimit) {
+                            b=(uint8_t)((c>>6)&0x3f);
+                            *target++=TO_BASE64_IMAP(b);
+                            if(target<targetLimit) {
+                                b=(uint8_t)(c&0x3f);
+                                *target++=TO_BASE64_IMAP(b);
+                                if(offsets!=NULL) {
+                                    *offsets++=sourceIndex;
+                                    *offsets++=sourceIndex;
+                                    *offsets++=sourceIndex++;
+                                }
+                            } else {
+                                if(offsets!=NULL) {
+                                    *offsets++=sourceIndex;
+                                    *offsets++=sourceIndex++;
+                                }
+                                b=(uint8_t)(c&0x3f);
+                                cnv->charErrorBuffer[0]=TO_BASE64_IMAP(b);
+                                cnv->charErrorBufferLength=1;
+                                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                            }
+                        } else {
+                            if(offsets!=NULL) {
+                                *offsets++=sourceIndex++;
+                            }
+                            b=(uint8_t)((c>>6)&0x3f);
+                            cnv->charErrorBuffer[0]=TO_BASE64_IMAP(b);
+                            b=(uint8_t)(c&0x3f);
+                            cnv->charErrorBuffer[1]=TO_BASE64_IMAP(b);
+                            cnv->charErrorBufferLength=2;
+                            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                        }
+                        bits=0;
+                        base64Counter=0;
+                        break;
+                    default:
+                        /* will never occur */
+                        break;
+                    }
+                }
+            } else {
+                /* target is full */
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                break;
+            }
+        }
+    }
+
+    if(pArgs->flush && source>=sourceLimit) {
+        /* flush remaining bits to the target */
+        if(!inDirectMode) {
+            if(base64Counter!=0) {
+                if(target<targetLimit) {
+                    *target++=TO_BASE64_IMAP(bits);
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex-1;
+                    }
+                } else {
+                    cnv->charErrorBuffer[cnv->charErrorBufferLength++]=TO_BASE64_IMAP(bits);
+                    *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                }
+            }
+            /* need to terminate with a minus */
+            if(target<targetLimit) {
+                *target++=MINUS;
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex-1;
+                }
+            } else {
+                cnv->charErrorBuffer[cnv->charErrorBufferLength++]=MINUS;
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            }
+        }
+        /* reset the state for the next conversion */
+        cnv->fromUnicodeStatus=(cnv->fromUnicodeStatus&0xf0000000)|0x1000000; /* keep version, inDirectMode=TRUE */
+    } else {
+        /* set the converter state back into UConverter */
+        cnv->fromUnicodeStatus=
+            (cnv->fromUnicodeStatus&0xf0000000)|    /* keep version*/
+            ((uint32_t)inDirectMode<<24)|((uint32_t)base64Counter<<16)|(uint32_t)bits;
+    }
+
+    /* write back the updated pointers */
+    pArgs->source=source;
+    pArgs->target=(char *)target;
+    pArgs->offsets=offsets;
+    return;
+}
+
+static const UConverterImpl _IMAPImpl={
+    UCNV_IMAP_MAILBOX,
+
+    NULL,
+    NULL,
+
+    _UTF7Open,
+    NULL,
+    _UTF7Reset,
+
+    _IMAPToUnicodeWithOffsets,
+    _IMAPToUnicodeWithOffsets,
+    _IMAPFromUnicodeWithOffsets,
+    _IMAPFromUnicodeWithOffsets,
+    NULL,
+
+    NULL,
+    NULL,
+    NULL, /* we don't need writeSub() because we never call a callback at fromUnicode() */
+    NULL,
+    ucnv_getCompleteUnicodeSet
+};
+
+static const UConverterStaticData _IMAPStaticData={
+    sizeof(UConverterStaticData),
+    "IMAP-mailbox-name",
+    0, /* TODO CCSID for IMAP-mailbox-name */
+    UCNV_IBM, UCNV_IMAP_MAILBOX,
+    1, 4,
+    { 0x3f, 0, 0, 0 }, 1, /* the subchar is not used */
+    FALSE, FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+
+const UConverterSharedData _IMAPData={
+    sizeof(UConverterSharedData), ~((uint32_t)0),
+    NULL, NULL, &_IMAPStaticData, FALSE, &_IMAPImpl,
+    0
+};
+
+#endif
diff --git a/source/common/ucnv_u8.c b/source/common/ucnv_u8.c
new file mode 100644
index 0000000..75f554c
--- /dev/null
+++ b/source/common/ucnv_u8.c
@@ -0,0 +1,1084 @@
+/*  
+**********************************************************************
+*   Copyright (C) 2002-2007, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   file name:  ucnv_u8.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002jul01
+*   created by: Markus W. Scherer
+*
+*   UTF-8 converter implementation. Used to be in ucnv_utf.c.
+*
+*   Also, CESU-8 implementation, see UTR 26.
+*   The CESU-8 converter uses all the same functions as the
+*   UTF-8 converter, with a branch for converting supplementary code points.
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ucnv.h"
+#include "ucnv_bld.h"
+#include "ucnv_cnv.h"
+#include "cmemory.h"
+
+/* Prototypes --------------------------------------------------------------- */
+
+/* Keep these here to make finicky compilers happy */
+
+U_CFUNC void ucnv_fromUnicode_UTF8(UConverterFromUnicodeArgs *args,
+                                           UErrorCode *err);
+U_CFUNC void ucnv_fromUnicode_UTF8_OFFSETS_LOGIC(UConverterFromUnicodeArgs *args,
+                                                        UErrorCode *err);
+
+
+/* UTF-8 -------------------------------------------------------------------- */
+
+/* UTF-8 Conversion DATA
+ *   for more information see Unicode Standard 2.0, Transformation Formats Appendix A-9
+ */
+/*static const uint32_t REPLACEMENT_CHARACTER = 0x0000FFFD;*/
+#define MAXIMUM_UCS2            0x0000FFFF
+#define MAXIMUM_UTF             0x0010FFFF
+#define MAXIMUM_UCS4            0x7FFFFFFF
+#define HALF_SHIFT              10
+#define HALF_BASE               0x0010000
+#define HALF_MASK               0x3FF
+#define SURROGATE_HIGH_START    0xD800
+#define SURROGATE_HIGH_END      0xDBFF
+#define SURROGATE_LOW_START     0xDC00
+#define SURROGATE_LOW_END       0xDFFF
+
+/* -SURROGATE_LOW_START + HALF_BASE */
+#define SURROGATE_LOW_BASE      9216
+
+static const uint32_t offsetsFromUTF8[7] = {0,
+  (uint32_t) 0x00000000, (uint32_t) 0x00003080, (uint32_t) 0x000E2080,
+  (uint32_t) 0x03C82080, (uint32_t) 0xFA082080, (uint32_t) 0x82082080
+};
+
+/* END OF UTF-8 Conversion DATA */
+
+static const int8_t bytesFromUTF8[256] = {
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0
+};
+
+/*
+ * Starting with Unicode 3.0.1:
+ * UTF-8 byte sequences of length N _must_ encode code points of or above utf8_minChar32[N];
+ * byte sequences with more than 4 bytes are illegal in UTF-8,
+ * which is tested with impossible values for them
+ */
+static const uint32_t
+utf8_minChar32[7]={ 0, 0, 0x80, 0x800, 0x10000, 0xffffffff, 0xffffffff };
+
+static void ucnv_toUnicode_UTF8 (UConverterToUnicodeArgs * args,
+                                  UErrorCode * err)
+{
+    UConverter *cnv = args->converter;
+    const unsigned char *mySource = (unsigned char *) args->source;
+    UChar *myTarget = args->target;
+    const unsigned char *sourceLimit = (unsigned char *) args->sourceLimit;
+    const UChar *targetLimit = args->targetLimit;
+    unsigned char *toUBytes = cnv->toUBytes;
+    UBool isCESU8 = (UBool)(cnv->sharedData == &_CESU8Data);
+    uint32_t ch, ch2 = 0;
+    int32_t i, inBytes;
+  
+    /* Restore size of current sequence */
+    if (cnv->toUnicodeStatus && myTarget < targetLimit)
+    {
+        inBytes = cnv->mode;            /* restore # of bytes to consume */
+        i = cnv->toULength;             /* restore # of bytes consumed */
+        cnv->toULength = 0;
+
+        ch = cnv->toUnicodeStatus;/*Stores the previously calculated ch from a previous call*/
+        cnv->toUnicodeStatus = 0;
+        goto morebytes;
+    }
+
+
+    while (mySource < sourceLimit && myTarget < targetLimit)
+    {
+        ch = *(mySource++);
+        if (ch < 0x80)        /* Simple case */
+        {
+            *(myTarget++) = (UChar) ch;
+        }
+        else
+        {
+            /* store the first char */
+            toUBytes[0] = (char)ch;
+            inBytes = bytesFromUTF8[ch]; /* lookup current sequence length */
+            i = 1;
+
+morebytes:
+            while (i < inBytes)
+            {
+                if (mySource < sourceLimit)
+                {
+                    toUBytes[i] = (char) (ch2 = *mySource);
+                    if (!UTF8_IS_TRAIL(ch2))
+                    {
+                        break; /* i < inBytes */
+                    }
+                    ch = (ch << 6) + ch2;
+                    ++mySource;
+                    i++;
+                }
+                else
+                {
+                    /* stores a partially calculated target*/
+                    cnv->toUnicodeStatus = ch;
+                    cnv->mode = inBytes;
+                    cnv->toULength = (int8_t) i;
+                    goto donefornow;
+                }
+            }
+
+            /* Remove the accumulated high bits */
+            ch -= offsetsFromUTF8[inBytes];
+
+            /*
+             * Legal UTF-8 byte sequences in Unicode 3.0.1 and up:
+             * - use only trail bytes after a lead byte (checked above)
+             * - use the right number of trail bytes for a given lead byte
+             * - encode a code point <= U+10ffff
+             * - use the fewest possible number of bytes for their code points
+             * - use at most 4 bytes (for i>=5 it is 0x10ffff<utf8_minChar32[])
+             *
+             * Starting with Unicode 3.2, surrogate code points must not be encoded in UTF-8.
+             * There are no irregular sequences any more.
+             * In CESU-8, only surrogates, not supplementary code points, are encoded directly.
+             */
+            if (i == inBytes && ch <= MAXIMUM_UTF && ch >= utf8_minChar32[i] &&
+                (isCESU8 ? i <= 3 : !UTF_IS_SURROGATE(ch)))
+            {
+                /* Normal valid byte when the loop has not prematurely terminated (i < inBytes) */
+                if (ch <= MAXIMUM_UCS2) 
+                {
+                    /* fits in 16 bits */
+                    *(myTarget++) = (UChar) ch;
+                }
+                else
+                {
+                    /* write out the surrogates */
+                    ch -= HALF_BASE;
+                    *(myTarget++) = (UChar) ((ch >> HALF_SHIFT) + SURROGATE_HIGH_START);
+                    ch = (ch & HALF_MASK) + SURROGATE_LOW_START;
+                    if (myTarget < targetLimit)
+                    {
+                        *(myTarget++) = (UChar)ch;
+                    }
+                    else
+                    {
+                        /* Put in overflow buffer (not handled here) */
+                        cnv->UCharErrorBuffer[0] = (UChar) ch;
+                        cnv->UCharErrorBufferLength = 1;
+                        *err = U_BUFFER_OVERFLOW_ERROR;
+                        break;
+                    }
+                }
+            }
+            else
+            {
+                cnv->toULength = (int8_t)i;
+                *err = U_ILLEGAL_CHAR_FOUND;
+                break;
+            }
+        }
+    }
+
+donefornow:
+    if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err))
+    {
+        /* End of target buffer */
+        *err = U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    args->target = myTarget;
+    args->source = (const char *) mySource;
+}
+
+static void ucnv_toUnicode_UTF8_OFFSETS_LOGIC (UConverterToUnicodeArgs * args,
+                                                UErrorCode * err)
+{
+    UConverter *cnv = args->converter;
+    const unsigned char *mySource = (unsigned char *) args->source;
+    UChar *myTarget = args->target;
+    int32_t *myOffsets = args->offsets;
+    int32_t offsetNum = 0;
+    const unsigned char *sourceLimit = (unsigned char *) args->sourceLimit;
+    const UChar *targetLimit = args->targetLimit;
+    unsigned char *toUBytes = cnv->toUBytes;
+    UBool isCESU8 = (UBool)(cnv->sharedData == &_CESU8Data);
+    uint32_t ch, ch2 = 0;
+    int32_t i, inBytes;
+
+    /* Restore size of current sequence */
+    if (cnv->toUnicodeStatus && myTarget < targetLimit)
+    {
+        inBytes = cnv->mode;            /* restore # of bytes to consume */
+        i = cnv->toULength;             /* restore # of bytes consumed */
+        cnv->toULength = 0;
+
+        ch = cnv->toUnicodeStatus;/*Stores the previously calculated ch from a previous call*/
+        cnv->toUnicodeStatus = 0;
+        goto morebytes;
+    }
+
+    while (mySource < sourceLimit && myTarget < targetLimit)
+    {
+        ch = *(mySource++);
+        if (ch < 0x80)        /* Simple case */
+        {
+            *(myTarget++) = (UChar) ch;
+            *(myOffsets++) = offsetNum++;
+        }
+        else
+        {
+            toUBytes[0] = (char)ch;
+            inBytes = bytesFromUTF8[ch];
+            i = 1;
+
+morebytes:
+            while (i < inBytes)
+            {
+                if (mySource < sourceLimit)
+                {
+                    toUBytes[i] = (char) (ch2 = *mySource);
+                    if (!UTF8_IS_TRAIL(ch2))
+                    {
+                        break; /* i < inBytes */
+                    }
+                    ch = (ch << 6) + ch2;
+                    ++mySource;
+                    i++;
+                }
+                else
+                {
+                    cnv->toUnicodeStatus = ch;
+                    cnv->mode = inBytes;
+                    cnv->toULength = (int8_t)i;
+                    goto donefornow;
+                }
+            }
+
+            /* Remove the accumulated high bits */
+            ch -= offsetsFromUTF8[inBytes];
+
+            /*
+             * Legal UTF-8 byte sequences in Unicode 3.0.1 and up:
+             * - use only trail bytes after a lead byte (checked above)
+             * - use the right number of trail bytes for a given lead byte
+             * - encode a code point <= U+10ffff
+             * - use the fewest possible number of bytes for their code points
+             * - use at most 4 bytes (for i>=5 it is 0x10ffff<utf8_minChar32[])
+             *
+             * Starting with Unicode 3.2, surrogate code points must not be encoded in UTF-8.
+             * There are no irregular sequences any more.
+             * In CESU-8, only surrogates, not supplementary code points, are encoded directly.
+             */
+            if (i == inBytes && ch <= MAXIMUM_UTF && ch >= utf8_minChar32[i] &&
+                (isCESU8 ? i <= 3 : !UTF_IS_SURROGATE(ch)))
+            {
+                /* Normal valid byte when the loop has not prematurely terminated (i < inBytes) */
+                if (ch <= MAXIMUM_UCS2) 
+                {
+                    /* fits in 16 bits */
+                    *(myTarget++) = (UChar) ch;
+                    *(myOffsets++) = offsetNum;
+                }
+                else
+                {
+                    /* write out the surrogates */
+                    ch -= HALF_BASE;
+                    *(myTarget++) = (UChar) ((ch >> HALF_SHIFT) + SURROGATE_HIGH_START);
+                    *(myOffsets++) = offsetNum;
+                    ch = (ch & HALF_MASK) + SURROGATE_LOW_START;
+                    if (myTarget < targetLimit)
+                    {
+                        *(myTarget++) = (UChar)ch;
+                        *(myOffsets++) = offsetNum;
+                    }
+                    else
+                    {
+                        cnv->UCharErrorBuffer[0] = (UChar) ch;
+                        cnv->UCharErrorBufferLength = 1;
+                        *err = U_BUFFER_OVERFLOW_ERROR;
+                    }
+                }
+                offsetNum += i;
+            }
+            else
+            {
+                cnv->toULength = (int8_t)i;
+                *err = U_ILLEGAL_CHAR_FOUND;
+                break;
+            }
+        }
+    }
+
+donefornow:
+    if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err))
+    {   /* End of target buffer */
+        *err = U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    args->target = myTarget;
+    args->source = (const char *) mySource;
+    args->offsets = myOffsets;
+}
+
+U_CFUNC void ucnv_fromUnicode_UTF8 (UConverterFromUnicodeArgs * args,
+                                    UErrorCode * err)
+{
+    UConverter *cnv = args->converter;
+    const UChar *mySource = args->source;
+    const UChar *sourceLimit = args->sourceLimit;
+    uint8_t *myTarget = (uint8_t *) args->target;
+    const uint8_t *targetLimit = (uint8_t *) args->targetLimit;
+    uint8_t *tempPtr;
+    UChar32 ch;
+    uint8_t tempBuf[4];
+    int32_t indexToWrite;
+    UBool isNotCESU8 = (UBool)(cnv->sharedData != &_CESU8Data);
+
+    if (cnv->fromUChar32 && myTarget < targetLimit)
+    {
+        ch = cnv->fromUChar32;
+        cnv->fromUChar32 = 0;
+        goto lowsurrogate;
+    }
+
+    while (mySource < sourceLimit && myTarget < targetLimit)
+    {
+        ch = *(mySource++);
+
+        if (ch < 0x80)        /* Single byte */
+        {
+            *(myTarget++) = (uint8_t) ch;
+        }
+        else if (ch < 0x800)  /* Double byte */
+        {
+            *(myTarget++) = (uint8_t) ((ch >> 6) | 0xc0);
+            if (myTarget < targetLimit)
+            {
+                *(myTarget++) = (uint8_t) ((ch & 0x3f) | 0x80);
+            }
+            else
+            {
+                cnv->charErrorBuffer[0] = (uint8_t) ((ch & 0x3f) | 0x80);
+                cnv->charErrorBufferLength = 1;
+                *err = U_BUFFER_OVERFLOW_ERROR;
+            }
+        }
+        else {
+            /* Check for surrogates */
+            if(UTF_IS_SURROGATE(ch) && isNotCESU8) {
+lowsurrogate:
+                if (mySource < sourceLimit) {
+                    /* test both code units */
+                    if(UTF_IS_SURROGATE_FIRST(ch) && UTF_IS_SECOND_SURROGATE(*mySource)) {
+                        /* convert and consume this supplementary code point */
+                        ch=UTF16_GET_PAIR_VALUE(ch, *mySource);
+                        ++mySource;
+                        /* exit this condition tree */
+                    }
+                    else {
+                        /* this is an unpaired trail or lead code unit */
+                        /* callback(illegal) */
+                        cnv->fromUChar32 = ch;
+                        *err = U_ILLEGAL_CHAR_FOUND;
+                        break;
+                    }
+                }
+                else {
+                    /* no more input */
+                    cnv->fromUChar32 = ch;
+                    break;
+                }
+            }
+
+            /* Do we write the buffer directly for speed,
+            or do we have to be careful about target buffer space? */
+            tempPtr = (((targetLimit - myTarget) >= 4) ? myTarget : tempBuf);
+
+            if (ch <= MAXIMUM_UCS2) {
+                indexToWrite = 2;
+                tempPtr[0] = (uint8_t) ((ch >> 12) | 0xe0);
+            }
+            else {
+                indexToWrite = 3;
+                tempPtr[0] = (uint8_t) ((ch >> 18) | 0xf0);
+                tempPtr[1] = (uint8_t) (((ch >> 12) & 0x3f) | 0x80);
+            }
+            tempPtr[indexToWrite-1] = (uint8_t) (((ch >> 6) & 0x3f) | 0x80);
+            tempPtr[indexToWrite] = (uint8_t) ((ch & 0x3f) | 0x80);
+
+            if (tempPtr == myTarget) {
+                /* There was enough space to write the codepoint directly. */
+                myTarget += (indexToWrite + 1);
+            }
+            else {
+                /* We might run out of room soon. Write it slowly. */
+                for (; tempPtr <= (tempBuf + indexToWrite); tempPtr++) {
+                    if (myTarget < targetLimit) {
+                        *(myTarget++) = *tempPtr;
+                    }
+                    else {
+                        cnv->charErrorBuffer[cnv->charErrorBufferLength++] = *tempPtr;
+                        *err = U_BUFFER_OVERFLOW_ERROR;
+                    }
+                }
+            }
+        }
+    }
+
+    if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err))
+    {
+        *err = U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    args->target = (char *) myTarget;
+    args->source = mySource;
+}
+
+U_CFUNC void ucnv_fromUnicode_UTF8_OFFSETS_LOGIC (UConverterFromUnicodeArgs * args,
+                                                  UErrorCode * err)
+{
+    UConverter *cnv = args->converter;
+    const UChar *mySource = args->source;
+    int32_t *myOffsets = args->offsets;
+    const UChar *sourceLimit = args->sourceLimit;
+    uint8_t *myTarget = (uint8_t *) args->target;
+    const uint8_t *targetLimit = (uint8_t *) args->targetLimit;
+    uint8_t *tempPtr;
+    UChar32 ch;
+    int32_t offsetNum, nextSourceIndex;
+    int32_t indexToWrite;
+    uint8_t tempBuf[4];
+    UBool isNotCESU8 = (UBool)(cnv->sharedData != &_CESU8Data);
+
+    if (cnv->fromUChar32 && myTarget < targetLimit)
+    {
+        ch = cnv->fromUChar32;
+        cnv->fromUChar32 = 0;
+        offsetNum = -1;
+        nextSourceIndex = 0;
+        goto lowsurrogate;
+    } else {
+        offsetNum = 0;
+    }
+
+    while (mySource < sourceLimit && myTarget < targetLimit)
+    {
+        ch = *(mySource++);
+
+        if (ch < 0x80)        /* Single byte */
+        {
+            *(myOffsets++) = offsetNum++;
+            *(myTarget++) = (char) ch;
+        }
+        else if (ch < 0x800)  /* Double byte */
+        {
+            *(myOffsets++) = offsetNum;
+            *(myTarget++) = (uint8_t) ((ch >> 6) | 0xc0);
+            if (myTarget < targetLimit)
+            {
+                *(myOffsets++) = offsetNum++;
+                *(myTarget++) = (uint8_t) ((ch & 0x3f) | 0x80);
+            }
+            else
+            {
+                cnv->charErrorBuffer[0] = (uint8_t) ((ch & 0x3f) | 0x80);
+                cnv->charErrorBufferLength = 1;
+                *err = U_BUFFER_OVERFLOW_ERROR;
+            }
+        }
+        else
+        /* Check for surrogates */
+        {
+            nextSourceIndex = offsetNum + 1;
+
+            if(UTF_IS_SURROGATE(ch) && isNotCESU8) {
+lowsurrogate:
+                if (mySource < sourceLimit) {
+                    /* test both code units */
+                    if(UTF_IS_SURROGATE_FIRST(ch) && UTF_IS_SECOND_SURROGATE(*mySource)) {
+                        /* convert and consume this supplementary code point */
+                        ch=UTF16_GET_PAIR_VALUE(ch, *mySource);
+                        ++mySource;
+                        ++nextSourceIndex;
+                        /* exit this condition tree */
+                    }
+                    else {
+                        /* this is an unpaired trail or lead code unit */
+                        /* callback(illegal) */
+                        cnv->fromUChar32 = ch;
+                        *err = U_ILLEGAL_CHAR_FOUND;
+                        break;
+                    }
+                }
+                else {
+                    /* no more input */
+                    cnv->fromUChar32 = ch;
+                    break;
+                }
+            }
+
+            /* Do we write the buffer directly for speed,
+            or do we have to be careful about target buffer space? */
+            tempPtr = (((targetLimit - myTarget) >= 4) ? myTarget : tempBuf);
+
+            if (ch <= MAXIMUM_UCS2) {
+                indexToWrite = 2;
+                tempPtr[0] = (uint8_t) ((ch >> 12) | 0xe0);
+            }
+            else {
+                indexToWrite = 3;
+                tempPtr[0] = (uint8_t) ((ch >> 18) | 0xf0);
+                tempPtr[1] = (uint8_t) (((ch >> 12) & 0x3f) | 0x80);
+            }
+            tempPtr[indexToWrite-1] = (uint8_t) (((ch >> 6) & 0x3f) | 0x80);
+            tempPtr[indexToWrite] = (uint8_t) ((ch & 0x3f) | 0x80);
+
+            if (tempPtr == myTarget) {
+                /* There was enough space to write the codepoint directly. */
+                myTarget += (indexToWrite + 1);
+                myOffsets[0] = offsetNum;
+                myOffsets[1] = offsetNum;
+                myOffsets[2] = offsetNum;
+                if (indexToWrite >= 3) {
+                    myOffsets[3] = offsetNum;
+                }
+                myOffsets += (indexToWrite + 1);
+            }
+            else {
+                /* We might run out of room soon. Write it slowly. */
+                for (; tempPtr <= (tempBuf + indexToWrite); tempPtr++) {
+                    if (myTarget < targetLimit)
+                    {
+                        *(myOffsets++) = offsetNum;
+                        *(myTarget++) = *tempPtr;
+                    }
+                    else
+                    {
+                        cnv->charErrorBuffer[cnv->charErrorBufferLength++] = *tempPtr;
+                        *err = U_BUFFER_OVERFLOW_ERROR;
+                    }
+                }
+            }
+            offsetNum = nextSourceIndex;
+        }
+    }
+
+    if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err))
+    {
+        *err = U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    args->target = (char *) myTarget;
+    args->source = mySource;
+    args->offsets = myOffsets;
+}
+
+static UChar32 ucnv_getNextUChar_UTF8(UConverterToUnicodeArgs *args,
+                                               UErrorCode *err) {
+    UConverter *cnv;
+    const uint8_t *sourceInitial;
+    const uint8_t *source;
+    uint16_t extraBytesToWrite;
+    uint8_t myByte;
+    UChar32 ch;
+    int8_t i, isLegalSequence;
+
+    /* UTF-8 only here, the framework handles CESU-8 to combine surrogate pairs */
+
+    cnv = args->converter;
+    sourceInitial = source = (const uint8_t *)args->source;
+    if (source >= (const uint8_t *)args->sourceLimit)
+    {
+        /* no input */
+        *err = U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0xffff;
+    }
+
+    myByte = (uint8_t)*(source++);
+    if (myByte < 0x80)
+    {
+        args->source = (const char *)source;
+        return (UChar32)myByte;
+    }
+
+    extraBytesToWrite = (uint16_t)bytesFromUTF8[myByte];
+    if (extraBytesToWrite == 0) {
+        cnv->toUBytes[0] = myByte;
+        cnv->toULength = 1;
+        *err = U_ILLEGAL_CHAR_FOUND;
+        args->source = (const char *)source;
+        return 0xffff;
+    }
+
+    /*The byte sequence is longer than the buffer area passed*/
+    if (((const char *)source + extraBytesToWrite - 1) > args->sourceLimit)
+    {
+        /* check if all of the remaining bytes are trail bytes */
+        cnv->toUBytes[0] = myByte;
+        i = 1;
+        *err = U_TRUNCATED_CHAR_FOUND;
+        while(source < (const uint8_t *)args->sourceLimit) {
+            if(U8_IS_TRAIL(myByte = *source)) {
+                cnv->toUBytes[i++] = myByte;
+                ++source;
+            } else {
+                /* error even before we run out of input */
+                *err = U_ILLEGAL_CHAR_FOUND;
+                break;
+            }
+        }
+        cnv->toULength = i;
+        args->source = (const char *)source;
+        return 0xffff;
+    }
+
+    isLegalSequence = 1;
+    ch = myByte << 6;
+    switch(extraBytesToWrite)
+    {     
+      /* note: code falls through cases! (sic)*/ 
+    case 6:
+        ch += (myByte = *source);
+        ch <<= 6;
+        if (!UTF8_IS_TRAIL(myByte))
+        {
+            isLegalSequence = 0;
+            break;
+        }
+        ++source;
+    case 5:
+        ch += (myByte = *source);
+        ch <<= 6;
+        if (!UTF8_IS_TRAIL(myByte))
+        {
+            isLegalSequence = 0;
+            break;
+        }
+        ++source;
+    case 4:
+        ch += (myByte = *source);
+        ch <<= 6;
+        if (!UTF8_IS_TRAIL(myByte))
+        {
+            isLegalSequence = 0;
+            break;
+        }
+        ++source;
+    case 3:
+        ch += (myByte = *source);
+        ch <<= 6;
+        if (!UTF8_IS_TRAIL(myByte))
+        {
+            isLegalSequence = 0;
+            break;
+        }
+        ++source;
+    case 2:
+        ch += (myByte = *source);
+        if (!UTF8_IS_TRAIL(myByte))
+        {
+            isLegalSequence = 0;
+            break;
+        }
+        ++source;
+    };
+    ch -= offsetsFromUTF8[extraBytesToWrite];
+    args->source = (const char *)source;
+
+    /*
+     * Legal UTF-8 byte sequences in Unicode 3.0.1 and up:
+     * - use only trail bytes after a lead byte (checked above)
+     * - use the right number of trail bytes for a given lead byte
+     * - encode a code point <= U+10ffff
+     * - use the fewest possible number of bytes for their code points
+     * - use at most 4 bytes (for i>=5 it is 0x10ffff<utf8_minChar32[])
+     *
+     * Starting with Unicode 3.2, surrogate code points must not be encoded in UTF-8.
+     * There are no irregular sequences any more.
+     */
+    if (isLegalSequence &&
+        (uint32_t)ch <= MAXIMUM_UTF &&
+        (uint32_t)ch >= utf8_minChar32[extraBytesToWrite] &&
+        !U_IS_SURROGATE(ch)
+    ) {
+        return ch; /* return the code point */
+    }
+
+    for(i = 0; sourceInitial < source; ++i) {
+        cnv->toUBytes[i] = *sourceInitial++;
+    }
+    cnv->toULength = i;
+    *err = U_ILLEGAL_CHAR_FOUND;
+    return 0xffff;
+} 
+
+/* UTF-8-from-UTF-8 conversion functions ------------------------------------ */
+
+/* minimum code point values for n-byte UTF-8 sequences, n=0..4 */
+static const UChar32
+utf8_minLegal[5]={ 0, 0, 0x80, 0x800, 0x10000 };
+
+/* offsets for n-byte UTF-8 sequences that were calculated with ((lead<<6)+trail)<<6+trail... */
+static const UChar32
+utf8_offsets[7]={ 0, 0, 0x3080, 0xE2080, 0x3C82080 };
+
+/* "Convert" UTF-8 to UTF-8: Validate and copy. Modified from ucnv_DBCSFromUTF8(). */
+static void
+ucnv_UTF8FromUTF8(UConverterFromUnicodeArgs *pFromUArgs,
+                  UConverterToUnicodeArgs *pToUArgs,
+                  UErrorCode *pErrorCode) {
+    UConverter *utf8, *cnv;
+    const uint8_t *source, *sourceLimit;
+    uint8_t *target;
+    int32_t targetCapacity;
+    int32_t count;
+
+    int8_t oldToULength, toULength, toULimit;
+
+    UChar32 c;
+    uint8_t b, t1, t2;
+
+    /* set up the local pointers */
+    utf8=pToUArgs->converter;
+    cnv=pFromUArgs->converter;
+    source=(uint8_t *)pToUArgs->source;
+    sourceLimit=(uint8_t *)pToUArgs->sourceLimit;
+    target=(uint8_t *)pFromUArgs->target;
+    targetCapacity=(int32_t)(pFromUArgs->targetLimit-pFromUArgs->target);
+
+    /* get the converter state from the UTF-8 UConverter */
+    c=(UChar32)utf8->toUnicodeStatus;
+    if(c!=0) {
+        toULength=oldToULength=utf8->toULength;
+        toULimit=(int8_t)utf8->mode;
+    } else {
+        toULength=oldToULength=toULimit=0;
+    }
+
+    count=(int32_t)(sourceLimit-source)+oldToULength;
+    if(count<toULimit) {
+        /*
+         * Not enough input to complete the partial character.
+         * Jump to moreBytes below - it will not output to target.
+         */
+    } else if(targetCapacity<toULimit) {
+        /*
+         * Not enough target capacity to output the partial character.
+         * Let the standard converter handle this.
+         */
+        *pErrorCode=U_USING_DEFAULT_WARNING;
+        return;
+    } else {
+        /*
+         * Use a single counter for source and target, counting the minimum of
+         * the source length and the target capacity.
+         * As a result, the source length is checked only once per multi-byte
+         * character instead of twice.
+         *
+         * Make sure that the last byte sequence is complete, or else
+         * stop just before it.
+         * (The longest legal byte sequence has 3 trail bytes.)
+         * Count oldToULength (number of source bytes from a previous buffer)
+         * into the source length but reduce the source index by toULimit
+         * while going back over trail bytes in order to not go back into
+         * the bytes that will be read for finishing a partial
+         * sequence from the previous buffer.
+         * Let the standard converter handle edge cases.
+         */
+        int32_t i;
+
+        if(count>targetCapacity) {
+            count=targetCapacity;
+        }
+
+        i=0;
+        while(i<3 && i<(count-toULimit)) {
+            b=source[count-oldToULength-i-1];
+            if(U8_IS_TRAIL(b)) {
+                ++i;
+            } else {
+                if(i<utf8_countTrailBytes[b]) {
+                    /* stop converting before the lead byte if there are not enough trail bytes for it */
+                    count-=i+1;
+                }
+                break;
+            }
+        }
+    }
+
+    if(c!=0) {
+        utf8->toUnicodeStatus=0;
+        utf8->toULength=0;
+        goto moreBytes;
+        /* See note in ucnv_SBCSFromUTF8() about this goto. */
+    }
+
+    /* conversion loop */
+    while(count>0) {
+        b=*source++;
+        if((int8_t)b>=0) {
+            /* convert ASCII */
+            *target++=b;
+            --count;
+            continue;
+        } else {
+            if(b>0xe0) {
+                if( /* handle U+1000..U+D7FF inline */
+                    (t1=source[0]) >= 0x80 && ((b<0xed && (t1 <= 0xbf)) ||
+                                               (b==0xed && (t1 <= 0x9f))) &&
+                    (t2=source[1]) >= 0x80 && t2 <= 0xbf
+                ) {
+                    source+=2;
+                    *target++=b;
+                    *target++=t1;
+                    *target++=t2;
+                    count-=3;
+                    continue;
+                }
+            } else if(b<0xe0) {
+                if( /* handle U+0080..U+07FF inline */
+                    b>=0xc2 &&
+                    (t1=*source) >= 0x80 && t1 <= 0xbf
+                ) {
+                    ++source;
+                    *target++=b;
+                    *target++=t1;
+                    count-=2;
+                    continue;
+                }
+            } else if(b==0xe0) {
+                if( /* handle U+0800..U+0FFF inline */
+                    (t1=source[0]) >= 0xa0 && t1 <= 0xbf &&
+                    (t2=source[1]) >= 0x80 && t2 <= 0xbf
+                ) {
+                    source+=2;
+                    *target++=b;
+                    *target++=t1;
+                    *target++=t2;
+                    count-=3;
+                    continue;
+                }
+            }
+
+            /* handle "complicated" and error cases, and continuing partial characters */
+            oldToULength=0;
+            toULength=1;
+            toULimit=utf8_countTrailBytes[b]+1;
+            c=b;
+moreBytes:
+            while(toULength<toULimit) {
+                if(source<sourceLimit) {
+                    b=*source;
+                    if(U8_IS_TRAIL(b)) {
+                        ++source;
+                        ++toULength;
+                        c=(c<<6)+b;
+                    } else {
+                        break; /* sequence too short, stop with toULength<toULimit */
+                    }
+                } else {
+                    /* store the partial UTF-8 character, compatible with the regular UTF-8 converter */
+                    source-=(toULength-oldToULength);
+                    while(oldToULength<toULength) {
+                        utf8->toUBytes[oldToULength++]=*source++;
+                    }
+                    utf8->toUnicodeStatus=c;
+                    utf8->toULength=toULength;
+                    utf8->mode=toULimit;
+                    pToUArgs->source=(char *)source;
+                    pFromUArgs->target=(char *)target;
+                    return;
+                }
+            }
+
+            if( toULength==toULimit &&      /* consumed all trail bytes */
+                (toULength==3 || toULength==2) &&             /* BMP */
+                (c-=utf8_offsets[toULength])>=utf8_minLegal[toULength] &&
+                (c<=0xd7ff || 0xe000<=c)    /* not a surrogate */
+            ) {
+                /* legal byte sequence for BMP code point */
+            } else if(
+                toULength==toULimit && toULength==4 &&
+                (0x10000<=(c-=utf8_offsets[4]) && c<=0x10ffff)
+            ) {
+                /* legal byte sequence for supplementary code point */
+            } else {
+                /* error handling: illegal UTF-8 byte sequence */
+                source-=(toULength-oldToULength);
+                while(oldToULength<toULength) {
+                    utf8->toUBytes[oldToULength++]=*source++;
+                }
+                utf8->toULength=toULength;
+                pToUArgs->source=(char *)source;
+                pFromUArgs->target=(char *)target;
+                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                return;
+            }
+
+            /* copy the legal byte sequence to the target */
+            {
+                int8_t i;
+
+                for(i=0; i<oldToULength; ++i) {
+                    *target++=utf8->toUBytes[i];
+                }
+                source-=(toULength-oldToULength);
+                for(; i<toULength; ++i) {
+                    *target++=*source++;
+                }
+                count-=toULength;
+            }
+        }
+    }
+
+    if(U_SUCCESS(*pErrorCode) && source<sourceLimit) {
+        if(target==(const uint8_t *)pFromUArgs->targetLimit) {
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+        } else {
+            b=*source;
+            toULimit=utf8_countTrailBytes[b]+1;
+            if(toULimit>(sourceLimit-source)) {
+                /* collect a truncated byte sequence */
+                toULength=0;
+                c=b;
+                for(;;) {
+                    utf8->toUBytes[toULength++]=b;
+                    if(++source==sourceLimit) {
+                        /* partial byte sequence at end of source */
+                        utf8->toUnicodeStatus=c;
+                        utf8->toULength=toULength;
+                        utf8->mode=toULimit;
+                        break;
+                    } else if(!U8_IS_TRAIL(b=*source)) {
+                        /* lead byte in trail byte position */
+                        utf8->toULength=toULength;
+                        *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                        break;
+                    }
+                    c=(c<<6)+b;
+                }
+            } else {
+                /* partial-sequence target overflow: fall back to the pivoting implementation */
+                *pErrorCode=U_USING_DEFAULT_WARNING;
+            }
+        }
+    }
+
+    /* write back the updated pointers */
+    pToUArgs->source=(char *)source;
+    pFromUArgs->target=(char *)target;
+}
+
+/* UTF-8 converter data ----------------------------------------------------- */
+
+static const UConverterImpl _UTF8Impl={
+    UCNV_UTF8,
+
+    NULL,
+    NULL,
+
+    NULL,
+    NULL,
+    NULL,
+
+    ucnv_toUnicode_UTF8,
+    ucnv_toUnicode_UTF8_OFFSETS_LOGIC,
+    ucnv_fromUnicode_UTF8,
+    ucnv_fromUnicode_UTF8_OFFSETS_LOGIC,
+    ucnv_getNextUChar_UTF8,
+
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    ucnv_getNonSurrogateUnicodeSet,
+
+    ucnv_UTF8FromUTF8,
+    ucnv_UTF8FromUTF8
+};
+
+/* The 1208 CCSID refers to any version of Unicode of UTF-8 */
+static const UConverterStaticData _UTF8StaticData={
+    sizeof(UConverterStaticData),
+    "UTF-8",
+    1208, UCNV_IBM, UCNV_UTF8,
+    1, 3, /* max 3 bytes per UChar from UTF-8 (4 bytes from surrogate _pair_) */
+    { 0xef, 0xbf, 0xbd, 0 },3,FALSE,FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+
+
+const UConverterSharedData _UTF8Data={
+    sizeof(UConverterSharedData), ~((uint32_t) 0),
+    NULL, NULL, &_UTF8StaticData, FALSE, &_UTF8Impl,
+    0
+};
+
+/* CESU-8 converter data ---------------------------------------------------- */
+
+static const UConverterImpl _CESU8Impl={
+    UCNV_CESU8,
+
+    NULL,
+    NULL,
+
+    NULL,
+    NULL,
+    NULL,
+
+    ucnv_toUnicode_UTF8,
+    ucnv_toUnicode_UTF8_OFFSETS_LOGIC,
+    ucnv_fromUnicode_UTF8,
+    ucnv_fromUnicode_UTF8_OFFSETS_LOGIC,
+    NULL,
+
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    ucnv_getCompleteUnicodeSet
+};
+
+static const UConverterStaticData _CESU8StaticData={
+    sizeof(UConverterStaticData),
+    "CESU-8",
+    9400, /* CCSID for CESU-8 */
+    UCNV_UNKNOWN, UCNV_CESU8, 1, 3,
+    { 0xef, 0xbf, 0xbd, 0 },3,FALSE,FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+
+
+const UConverterSharedData _CESU8Data={
+    sizeof(UConverterSharedData), ~((uint32_t) 0),
+    NULL, NULL, &_CESU8StaticData, FALSE, &_CESU8Impl,
+    0
+};
+
+#endif
diff --git a/source/common/ucnvbocu.c b/source/common/ucnvbocu.c
new file mode 100644
index 0000000..8623b11
--- /dev/null
+++ b/source/common/ucnvbocu.c
@@ -0,0 +1,1393 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2002-2005, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  ucnvbocu.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002mar27
+*   created by: Markus W. Scherer
+*
+*   This is an implementation of the Binary Ordered Compression for Unicode,
+*   in its MIME-friendly form as defined in http://www.unicode.org/notes/tn6/
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ucnv.h"
+#include "unicode/ucnv_cb.h"
+#include "ucnv_bld.h"
+#include "ucnv_cnv.h"
+
+/* BOCU-1 constants and macros ---------------------------------------------- */
+
+/*
+ * BOCU-1 encodes the code points of a Unicode 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 the "previous code point" state
+ * is always moved into the middle of such a block.
+ *
+ * Additionally, "prev" is moved from anywhere in the Unihan and Hangul
+ * areas into the middle of those areas.
+ *
+ * C0 control codes and space are encoded with their US-ASCII bytes.
+ * "prev" is reset for C0 controls but not for space.
+ */
+
+/* initial value for "prev": middle of the ASCII range */
+#define BOCU1_ASCII_PREV        0x40
+
+/* bounding byte values for differences */
+#define BOCU1_MIN               0x21
+#define BOCU1_MIDDLE            0x90
+#define BOCU1_MAX_LEAD          0xfe
+#define BOCU1_MAX_TRAIL         0xff
+#define BOCU1_RESET             0xff
+
+/* number of lead bytes */
+#define BOCU1_COUNT             (BOCU1_MAX_LEAD-BOCU1_MIN+1)
+
+/* adjust trail byte counts for the use of some C0 control byte values */
+#define BOCU1_TRAIL_CONTROLS_COUNT  20
+#define BOCU1_TRAIL_BYTE_OFFSET     (BOCU1_MIN-BOCU1_TRAIL_CONTROLS_COUNT)
+
+/* number of trail bytes */
+#define BOCU1_TRAIL_COUNT       ((BOCU1_MAX_TRAIL-BOCU1_MIN+1)+BOCU1_TRAIL_CONTROLS_COUNT)
+
+/*
+ * number of positive and negative single-byte codes
+ * (counting 0==BOCU1_MIDDLE among the positive ones)
+ */
+#define BOCU1_SINGLE            64
+
+/* number of lead bytes for positive and negative 2/3/4-byte sequences */
+#define BOCU1_LEAD_2            43
+#define BOCU1_LEAD_3            3
+#define BOCU1_LEAD_4            1
+
+/* The difference value range for single-byters. */
+#define BOCU1_REACH_POS_1   (BOCU1_SINGLE-1)
+#define BOCU1_REACH_NEG_1   (-BOCU1_SINGLE)
+
+/* The difference value range for double-byters. */
+#define BOCU1_REACH_POS_2   (BOCU1_REACH_POS_1+BOCU1_LEAD_2*BOCU1_TRAIL_COUNT)
+#define BOCU1_REACH_NEG_2   (BOCU1_REACH_NEG_1-BOCU1_LEAD_2*BOCU1_TRAIL_COUNT)
+
+/* The difference value range for 3-byters. */
+#define BOCU1_REACH_POS_3   \
+    (BOCU1_REACH_POS_2+BOCU1_LEAD_3*BOCU1_TRAIL_COUNT*BOCU1_TRAIL_COUNT)
+
+#define BOCU1_REACH_NEG_3   (BOCU1_REACH_NEG_2-BOCU1_LEAD_3*BOCU1_TRAIL_COUNT*BOCU1_TRAIL_COUNT)
+
+/* The lead byte start values. */
+#define BOCU1_START_POS_2   (BOCU1_MIDDLE+BOCU1_REACH_POS_1+1)
+#define BOCU1_START_POS_3   (BOCU1_START_POS_2+BOCU1_LEAD_2)
+#define BOCU1_START_POS_4   (BOCU1_START_POS_3+BOCU1_LEAD_3)
+     /* ==BOCU1_MAX_LEAD */
+
+#define BOCU1_START_NEG_2   (BOCU1_MIDDLE+BOCU1_REACH_NEG_1)
+#define BOCU1_START_NEG_3   (BOCU1_START_NEG_2-BOCU1_LEAD_2)
+#define BOCU1_START_NEG_4   (BOCU1_START_NEG_3-BOCU1_LEAD_3)
+     /* ==BOCU1_MIN+1 */
+
+/* The length of a byte sequence, according to the lead byte (!=BOCU1_RESET). */
+#define BOCU1_LENGTH_FROM_LEAD(lead) \
+    ((BOCU1_START_NEG_2<=(lead) && (lead)<BOCU1_START_POS_2) ? 1 : \
+     (BOCU1_START_NEG_3<=(lead) && (lead)<BOCU1_START_POS_3) ? 2 : \
+     (BOCU1_START_NEG_4<=(lead) && (lead)<BOCU1_START_POS_4) ? 3 : 4)
+
+/* The length of a byte sequence, according to its packed form. */
+#define BOCU1_LENGTH_FROM_PACKED(packed) \
+    ((uint32_t)(packed)<0x04000000 ? (packed)>>24 : 4)
+
+/*
+ * 12 commonly used C0 control codes (and space) are only used to encode
+ * themselves directly,
+ * which makes BOCU-1 MIME-usable and reasonably safe for
+ * ASCII-oriented software.
+ *
+ * These controls are
+ *  0   NUL
+ *
+ *  7   BEL
+ *  8   BS
+ *
+ *  9   TAB
+ *  a   LF
+ *  b   VT
+ *  c   FF
+ *  d   CR
+ *
+ *  e   SO
+ *  f   SI
+ *
+ * 1a   SUB
+ * 1b   ESC
+ *
+ * The other 20 C0 controls are also encoded directly (to preserve order)
+ * but are also used as trail bytes in difference encoding
+ * (for better compression).
+ */
+#define BOCU1_TRAIL_TO_BYTE(t) ((t)>=BOCU1_TRAIL_CONTROLS_COUNT ? (t)+BOCU1_TRAIL_BYTE_OFFSET : bocu1TrailToByte[t])
+
+/*
+ * Byte value map for control codes,
+ * from external byte values 0x00..0x20
+ * to trail byte values 0..19 (0..0x13) as used in the difference calculation.
+ * External byte values that are illegal as trail bytes are mapped to -1.
+ */
+static const int8_t
+bocu1ByteToTrail[BOCU1_MIN]={
+/*  0     1     2     3     4     5     6     7    */
+    -1,   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, -1,
+
+/*  8     9     a     b     c     d     e     f    */
+    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+
+/*  10    11    12    13    14    15    16    17   */
+    0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+
+/*  18    19    1a    1b    1c    1d    1e    1f   */
+    0x0e, 0x0f, -1,   -1,   0x10, 0x11, 0x12, 0x13,
+
+/*  20   */
+    -1
+};
+
+/*
+ * Byte value map for control codes,
+ * from trail byte values 0..19 (0..0x13) as used in the difference calculation
+ * to external byte values 0x00..0x20.
+ */
+static const int8_t
+bocu1TrailToByte[BOCU1_TRAIL_CONTROLS_COUNT]={
+/*  0     1     2     3     4     5     6     7    */
+    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x10, 0x11,
+
+/*  8     9     a     b     c     d     e     f    */
+    0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+
+/*  10    11    12    13   */
+    0x1c, 0x1d, 0x1e, 0x1f
+};
+
+/**
+ * Integer division and modulo with negative numerators
+ * yields negative modulo results and quotients that are one more than
+ * what we need here.
+ * This macro adjust the results so that the modulo-value m is always >=0.
+ *
+ * For positive n, the if() condition is always FALSE.
+ *
+ * @param n Number to be split into quotient and rest.
+ *          Will be modified to contain the quotient.
+ * @param d Divisor.
+ * @param m Output variable for the rest (modulo result).
+ */
+#define NEGDIVMOD(n, d, m) { \
+    (m)=(n)%(d); \
+    (n)/=(d); \
+    if((m)<0) { \
+        --(n); \
+        (m)+=(d); \
+    } \
+}
+
+/* BOCU-1 implementation functions ------------------------------------------ */
+
+#define BOCU1_SIMPLE_PREV(c) (((c)&~0x7f)+BOCU1_ASCII_PREV)
+
+/**
+ * Compute the next "previous" value for differencing
+ * from the current code point.
+ *
+ * @param c current code point, 0x3040..0xd7a3 (rest handled by macro below)
+ * @return "previous code point" state value
+ */
+static U_INLINE int32_t
+bocu1Prev(int32_t c) {
+    /* compute new prev */
+    if(/* 0x3040<=c && */ c<=0x309f) {
+        /* Hiragana is not 128-aligned */
+        return 0x3070;
+    } else if(0x4e00<=c && c<=0x9fa5) {
+        /* CJK Unihan */
+        return 0x4e00-BOCU1_REACH_NEG_2;
+    } else if(0xac00<=c /* && c<=0xd7a3 */) {
+        /* Korean Hangul */
+        return (0xd7a3+0xac00)/2;
+    } else {
+        /* mostly small scripts */
+        return BOCU1_SIMPLE_PREV(c);
+    }
+}
+
+/** Fast version of bocu1Prev() for most scripts. */
+#define BOCU1_PREV(c) ((c)<0x3040 || (c)>0xd7a3 ? BOCU1_SIMPLE_PREV(c) : bocu1Prev(c))
+
+/*
+ * The BOCU-1 converter uses the standard setup code in ucnv.c/ucnv_bld.c.
+ * The UConverter fields are used as follows:
+ *
+ * fromUnicodeStatus    encoder's prev (0 will be interpreted as BOCU1_ASCII_PREV)
+ *
+ * toUnicodeStatus      decoder's prev (0 will be interpreted as BOCU1_ASCII_PREV)
+ * mode                 decoder's incomplete (diff<<2)|count (ignored when toULength==0)
+ */
+
+/* BOCU-1-from-Unicode conversion functions --------------------------------- */
+
+/**
+ * Encode a difference -0x10ffff..0x10ffff in 1..4 bytes
+ * and return a packed integer with them.
+ *
+ * The encoding favors small absolut differences with short encodings
+ * to compress runs of same-script characters.
+ *
+ * Optimized version with unrolled loops and fewer floating-point operations
+ * than the standard packDiff().
+ *
+ * @param diff difference value -0x10ffff..0x10ffff
+ * @return
+ *      0x010000zz for 1-byte sequence zz
+ *      0x0200yyzz for 2-byte sequence yy zz
+ *      0x03xxyyzz for 3-byte sequence xx yy zz
+ *      0xwwxxyyzz for 4-byte sequence ww xx yy zz (ww>0x03)
+ */
+static int32_t
+packDiff(int32_t diff) {
+    int32_t result, m;
+
+    if(diff>=BOCU1_REACH_NEG_1) {
+        /* mostly positive differences, and single-byte negative ones */
+#if 0   /* single-byte case handled in macros, see below */
+        if(diff<=BOCU1_REACH_POS_1) {
+            /* single byte */
+            return 0x01000000|(BOCU1_MIDDLE+diff);
+        } else
+#endif
+        if(diff<=BOCU1_REACH_POS_2) {
+            /* two bytes */
+            diff-=BOCU1_REACH_POS_1+1;
+            result=0x02000000;
+
+            m=diff%BOCU1_TRAIL_COUNT;
+            diff/=BOCU1_TRAIL_COUNT;
+            result|=BOCU1_TRAIL_TO_BYTE(m);
+
+            result|=(BOCU1_START_POS_2+diff)<<8;
+        } else if(diff<=BOCU1_REACH_POS_3) {
+            /* three bytes */
+            diff-=BOCU1_REACH_POS_2+1;
+            result=0x03000000;
+
+            m=diff%BOCU1_TRAIL_COUNT;
+            diff/=BOCU1_TRAIL_COUNT;
+            result|=BOCU1_TRAIL_TO_BYTE(m);
+
+            m=diff%BOCU1_TRAIL_COUNT;
+            diff/=BOCU1_TRAIL_COUNT;
+            result|=BOCU1_TRAIL_TO_BYTE(m)<<8;
+
+            result|=(BOCU1_START_POS_3+diff)<<16;
+        } else {
+            /* four bytes */
+            diff-=BOCU1_REACH_POS_3+1;
+
+            m=diff%BOCU1_TRAIL_COUNT;
+            diff/=BOCU1_TRAIL_COUNT;
+            result=BOCU1_TRAIL_TO_BYTE(m);
+
+            m=diff%BOCU1_TRAIL_COUNT;
+            diff/=BOCU1_TRAIL_COUNT;
+            result|=BOCU1_TRAIL_TO_BYTE(m)<<8;
+
+            /*
+             * We know that / and % would deliver quotient 0 and rest=diff.
+             * Avoid division and modulo for performance.
+             */
+            result|=BOCU1_TRAIL_TO_BYTE(diff)<<16;
+
+            result|=((uint32_t)BOCU1_START_POS_4)<<24;
+        }
+    } else {
+        /* two- to four-byte negative differences */
+        if(diff>=BOCU1_REACH_NEG_2) {
+            /* two bytes */
+            diff-=BOCU1_REACH_NEG_1;
+            result=0x02000000;
+
+            NEGDIVMOD(diff, BOCU1_TRAIL_COUNT, m);
+            result|=BOCU1_TRAIL_TO_BYTE(m);
+
+            result|=(BOCU1_START_NEG_2+diff)<<8;
+        } else if(diff>=BOCU1_REACH_NEG_3) {
+            /* three bytes */
+            diff-=BOCU1_REACH_NEG_2;
+            result=0x03000000;
+
+            NEGDIVMOD(diff, BOCU1_TRAIL_COUNT, m);
+            result|=BOCU1_TRAIL_TO_BYTE(m);
+
+            NEGDIVMOD(diff, BOCU1_TRAIL_COUNT, m);
+            result|=BOCU1_TRAIL_TO_BYTE(m)<<8;
+
+            result|=(BOCU1_START_NEG_3+diff)<<16;
+        } else {
+            /* four bytes */
+            diff-=BOCU1_REACH_NEG_3;
+
+            NEGDIVMOD(diff, BOCU1_TRAIL_COUNT, m);
+            result=BOCU1_TRAIL_TO_BYTE(m);
+
+            NEGDIVMOD(diff, BOCU1_TRAIL_COUNT, m);
+            result|=BOCU1_TRAIL_TO_BYTE(m)<<8;
+
+            /*
+             * We know that NEGDIVMOD would deliver
+             * quotient -1 and rest=diff+BOCU1_TRAIL_COUNT.
+             * Avoid division and modulo for performance.
+             */
+            m=diff+BOCU1_TRAIL_COUNT;
+            result|=BOCU1_TRAIL_TO_BYTE(m)<<16;
+
+            result|=BOCU1_MIN<<24;
+        }
+    }
+    return result;
+}
+
+/* Faster versions of packDiff() for single-byte-encoded diff values. */
+
+/** Is a diff value encodable in a single byte? */
+#define DIFF_IS_SINGLE(diff) (BOCU1_REACH_NEG_1<=(diff) && (diff)<=BOCU1_REACH_POS_1)
+
+/** Encode a diff value in a single byte. */
+#define PACK_SINGLE_DIFF(diff) (BOCU1_MIDDLE+(diff))
+
+/** Is a diff value encodable in two bytes? */
+#define DIFF_IS_DOUBLE(diff) (BOCU1_REACH_NEG_2<=(diff) && (diff)<=BOCU1_REACH_POS_2)
+
+static void
+_Bocu1FromUnicodeWithOffsets(UConverterFromUnicodeArgs *pArgs,
+                             UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const UChar *source, *sourceLimit;
+    uint8_t *target;
+    int32_t targetCapacity;
+    int32_t *offsets;
+
+    int32_t prev, c, diff;
+
+    int32_t sourceIndex, nextSourceIndex;
+
+U_ALIGN_CODE(16)
+
+    /* set up the local pointers */
+    cnv=pArgs->converter;
+    source=pArgs->source;
+    sourceLimit=pArgs->sourceLimit;
+    target=(uint8_t *)pArgs->target;
+    targetCapacity=(int32_t)(pArgs->targetLimit-pArgs->target);
+    offsets=pArgs->offsets;
+
+    /* get the converter state from UConverter */
+    c=cnv->fromUChar32;
+    prev=(int32_t)cnv->fromUnicodeStatus;
+    if(prev==0) {
+        prev=BOCU1_ASCII_PREV;
+    }
+
+    /* sourceIndex=-1 if the current character began in the previous buffer */
+    sourceIndex= c==0 ? 0 : -1;
+    nextSourceIndex=0;
+
+    /* conversion loop */
+    if(c!=0 && targetCapacity>0) {
+        goto getTrail;
+    }
+
+fastSingle:
+    /* fast loop for single-byte differences */
+    /* use only one loop counter variable, targetCapacity, not also source */
+    diff=(int32_t)(sourceLimit-source);
+    if(targetCapacity>diff) {
+        targetCapacity=diff;
+    }
+    while(targetCapacity>0 && (c=*source)<0x3000) {
+        if(c<=0x20) {
+            if(c!=0x20) {
+                prev=BOCU1_ASCII_PREV;
+            }
+            *target++=(uint8_t)c;
+            *offsets++=nextSourceIndex++;
+            ++source;
+            --targetCapacity;
+        } else {
+            diff=c-prev;
+            if(DIFF_IS_SINGLE(diff)) {
+                prev=BOCU1_SIMPLE_PREV(c);
+                *target++=(uint8_t)PACK_SINGLE_DIFF(diff);
+                *offsets++=nextSourceIndex++;
+                ++source;
+                --targetCapacity;
+            } else {
+                break;
+            }
+        }
+    }
+    /* restore real values */
+    targetCapacity=(int32_t)((const uint8_t *)pArgs->targetLimit-target);
+    sourceIndex=nextSourceIndex; /* wrong if offsets==NULL but does not matter */
+
+    /* regular loop for all cases */
+    while(source<sourceLimit) {
+        if(targetCapacity>0) {
+            c=*source++;
+            ++nextSourceIndex;
+
+            if(c<=0x20) {
+                /*
+                 * ISO C0 control & space:
+                 * Encode directly for MIME compatibility,
+                 * and reset state except for space, to not disrupt compression.
+                 */
+                if(c!=0x20) {
+                    prev=BOCU1_ASCII_PREV;
+                }
+                *target++=(uint8_t)c;
+                *offsets++=sourceIndex;
+                --targetCapacity;
+
+                sourceIndex=nextSourceIndex;
+                continue;
+            }
+
+            if(UTF_IS_LEAD(c)) {
+getTrail:
+                if(source<sourceLimit) {
+                    /* test the following code unit */
+                    UChar trail=*source;
+                    if(UTF_IS_SECOND_SURROGATE(trail)) {
+                        ++source;
+                        ++nextSourceIndex;
+                        c=UTF16_GET_PAIR_VALUE(c, trail);
+                    }
+                } else {
+                    /* no more input */
+                    c=-c; /* negative lead surrogate as "incomplete" indicator to avoid c=0 everywhere else */
+                    break;
+                }
+            }
+
+            /*
+             * all other Unicode code points c==U+0021..U+10ffff
+             * are encoded with the difference c-prev
+             *
+             * a new prev is computed from c,
+             * placed in the middle of a 0x80-block (for most small scripts) or
+             * in the middle of the Unihan and Hangul blocks
+             * to statistically minimize the following difference
+             */
+            diff=c-prev;
+            prev=BOCU1_PREV(c);
+            if(DIFF_IS_SINGLE(diff)) {
+                *target++=(uint8_t)PACK_SINGLE_DIFF(diff);
+                *offsets++=sourceIndex;
+                --targetCapacity;
+                sourceIndex=nextSourceIndex;
+                if(c<0x3000) {
+                    goto fastSingle;
+                }
+            } else if(DIFF_IS_DOUBLE(diff) && 2<=targetCapacity) {
+                /* optimize 2-byte case */
+                int32_t m;
+
+                if(diff>=0) {
+                    diff-=BOCU1_REACH_POS_1+1;
+                    m=diff%BOCU1_TRAIL_COUNT;
+                    diff/=BOCU1_TRAIL_COUNT;
+                    diff+=BOCU1_START_POS_2;
+                } else {
+                    diff-=BOCU1_REACH_NEG_1;
+                    NEGDIVMOD(diff, BOCU1_TRAIL_COUNT, m);
+                    diff+=BOCU1_START_NEG_2;
+                }
+                *target++=(uint8_t)diff;
+                *target++=(uint8_t)BOCU1_TRAIL_TO_BYTE(m);
+                *offsets++=sourceIndex;
+                *offsets++=sourceIndex;
+                targetCapacity-=2;
+                sourceIndex=nextSourceIndex;
+            } else {
+                int32_t length; /* will be 2..4 */
+
+                diff=packDiff(diff);
+                length=BOCU1_LENGTH_FROM_PACKED(diff);
+
+                /* write the output character bytes from diff and length */
+                /* from the first if in the loop we know that targetCapacity>0 */
+                if(length<=targetCapacity) {
+                    switch(length) {
+                        /* each branch falls through to the next one */
+                    case 4:
+                        *target++=(uint8_t)(diff>>24);
+                        *offsets++=sourceIndex;
+                    case 3:
+                        *target++=(uint8_t)(diff>>16);
+                        *offsets++=sourceIndex;
+                    case 2:
+                        *target++=(uint8_t)(diff>>8);
+                        *offsets++=sourceIndex;
+                    /* case 1: handled above */
+                        *target++=(uint8_t)diff;
+                        *offsets++=sourceIndex;
+                    default:
+                        /* will never occur */
+                        break;
+                    }
+                    targetCapacity-=length;
+                    sourceIndex=nextSourceIndex;
+                } else {
+                    uint8_t *charErrorBuffer;
+
+                    /*
+                     * We actually do this backwards here:
+                     * In order to save an intermediate variable, we output
+                     * first to the overflow buffer what does not fit into the
+                     * regular target.
+                     */
+                    /* we know that 1<=targetCapacity<length<=4 */
+                    length-=targetCapacity;
+                    charErrorBuffer=(uint8_t *)cnv->charErrorBuffer;
+                    switch(length) {
+                        /* each branch falls through to the next one */
+                    case 3:
+                        *charErrorBuffer++=(uint8_t)(diff>>16);
+                    case 2:
+                        *charErrorBuffer++=(uint8_t)(diff>>8);
+                    case 1:
+                        *charErrorBuffer=(uint8_t)diff;
+                    default:
+                        /* will never occur */
+                        break;
+                    }
+                    cnv->charErrorBufferLength=(int8_t)length;
+
+                    /* now output what fits into the regular target */
+                    diff>>=8*length; /* length was reduced by targetCapacity */
+                    switch(targetCapacity) {
+                        /* each branch falls through to the next one */
+                    case 3:
+                        *target++=(uint8_t)(diff>>16);
+                        *offsets++=sourceIndex;
+                    case 2:
+                        *target++=(uint8_t)(diff>>8);
+                        *offsets++=sourceIndex;
+                    case 1:
+                        *target++=(uint8_t)diff;
+                        *offsets++=sourceIndex;
+                    default:
+                        /* will never occur */
+                        break;
+                    }
+
+                    /* target overflow */
+                    targetCapacity=0;
+                    *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                    break;
+                }
+            }
+        } else {
+            /* target is full */
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+    }
+
+    /* set the converter state back into UConverter */
+    cnv->fromUChar32= c<0 ? -c : 0;
+    cnv->fromUnicodeStatus=(uint32_t)prev;
+
+    /* write back the updated pointers */
+    pArgs->source=source;
+    pArgs->target=(char *)target;
+    pArgs->offsets=offsets;
+}
+
+/*
+ * Identical to _Bocu1FromUnicodeWithOffsets but without offset handling.
+ * If a change is made in the original function, then either
+ * change this function the same way or
+ * re-copy the original function and remove the variables
+ * offsets, sourceIndex, and nextSourceIndex.
+ */
+static void
+_Bocu1FromUnicode(UConverterFromUnicodeArgs *pArgs,
+                  UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const UChar *source, *sourceLimit;
+    uint8_t *target;
+    int32_t targetCapacity;
+
+    int32_t prev, c, diff;
+
+    /* set up the local pointers */
+    cnv=pArgs->converter;
+    source=pArgs->source;
+    sourceLimit=pArgs->sourceLimit;
+    target=(uint8_t *)pArgs->target;
+    targetCapacity=(int32_t)(pArgs->targetLimit-pArgs->target);
+
+    /* get the converter state from UConverter */
+    c=cnv->fromUChar32;
+    prev=(int32_t)cnv->fromUnicodeStatus;
+    if(prev==0) {
+        prev=BOCU1_ASCII_PREV;
+    }
+
+    /* conversion loop */
+    if(c!=0 && targetCapacity>0) {
+        goto getTrail;
+    }
+
+fastSingle:
+    /* fast loop for single-byte differences */
+    /* use only one loop counter variable, targetCapacity, not also source */
+    diff=(int32_t)(sourceLimit-source);
+    if(targetCapacity>diff) {
+        targetCapacity=diff;
+    }
+    while(targetCapacity>0 && (c=*source)<0x3000) {
+        if(c<=0x20) {
+            if(c!=0x20) {
+                prev=BOCU1_ASCII_PREV;
+            }
+            *target++=(uint8_t)c;
+        } else {
+            diff=c-prev;
+            if(DIFF_IS_SINGLE(diff)) {
+                prev=BOCU1_SIMPLE_PREV(c);
+                *target++=(uint8_t)PACK_SINGLE_DIFF(diff);
+            } else {
+                break;
+            }
+        }
+        ++source;
+        --targetCapacity;
+    }
+    /* restore real values */
+    targetCapacity=(int32_t)((const uint8_t *)pArgs->targetLimit-target);
+
+    /* regular loop for all cases */
+    while(source<sourceLimit) {
+        if(targetCapacity>0) {
+            c=*source++;
+
+            if(c<=0x20) {
+                /*
+                 * ISO C0 control & space:
+                 * Encode directly for MIME compatibility,
+                 * and reset state except for space, to not disrupt compression.
+                 */
+                if(c!=0x20) {
+                    prev=BOCU1_ASCII_PREV;
+                }
+                *target++=(uint8_t)c;
+                --targetCapacity;
+                continue;
+            }
+
+            if(UTF_IS_LEAD(c)) {
+getTrail:
+                if(source<sourceLimit) {
+                    /* test the following code unit */
+                    UChar trail=*source;
+                    if(UTF_IS_SECOND_SURROGATE(trail)) {
+                        ++source;
+                        c=UTF16_GET_PAIR_VALUE(c, trail);
+                    }
+                } else {
+                    /* no more input */
+                    c=-c; /* negative lead surrogate as "incomplete" indicator to avoid c=0 everywhere else */
+                    break;
+                }
+            }
+
+            /*
+             * all other Unicode code points c==U+0021..U+10ffff
+             * are encoded with the difference c-prev
+             *
+             * a new prev is computed from c,
+             * placed in the middle of a 0x80-block (for most small scripts) or
+             * in the middle of the Unihan and Hangul blocks
+             * to statistically minimize the following difference
+             */
+            diff=c-prev;
+            prev=BOCU1_PREV(c);
+            if(DIFF_IS_SINGLE(diff)) {
+                *target++=(uint8_t)PACK_SINGLE_DIFF(diff);
+                --targetCapacity;
+                if(c<0x3000) {
+                    goto fastSingle;
+                }
+            } else if(DIFF_IS_DOUBLE(diff) && 2<=targetCapacity) {
+                /* optimize 2-byte case */
+                int32_t m;
+
+                if(diff>=0) {
+                    diff-=BOCU1_REACH_POS_1+1;
+                    m=diff%BOCU1_TRAIL_COUNT;
+                    diff/=BOCU1_TRAIL_COUNT;
+                    diff+=BOCU1_START_POS_2;
+                } else {
+                    diff-=BOCU1_REACH_NEG_1;
+                    NEGDIVMOD(diff, BOCU1_TRAIL_COUNT, m);
+                    diff+=BOCU1_START_NEG_2;
+                }
+                *target++=(uint8_t)diff;
+                *target++=(uint8_t)BOCU1_TRAIL_TO_BYTE(m);
+                targetCapacity-=2;
+            } else {
+                int32_t length; /* will be 2..4 */
+
+                diff=packDiff(diff);
+                length=BOCU1_LENGTH_FROM_PACKED(diff);
+
+                /* write the output character bytes from diff and length */
+                /* from the first if in the loop we know that targetCapacity>0 */
+                if(length<=targetCapacity) {
+                    switch(length) {
+                        /* each branch falls through to the next one */
+                    case 4:
+                        *target++=(uint8_t)(diff>>24);
+                    case 3:
+                        *target++=(uint8_t)(diff>>16);
+                    /* case 2: handled above */
+                        *target++=(uint8_t)(diff>>8);
+                    /* case 1: handled above */
+                        *target++=(uint8_t)diff;
+                    default:
+                        /* will never occur */
+                        break;
+                    }
+                    targetCapacity-=length;
+                } else {
+                    uint8_t *charErrorBuffer;
+
+                    /*
+                     * We actually do this backwards here:
+                     * In order to save an intermediate variable, we output
+                     * first to the overflow buffer what does not fit into the
+                     * regular target.
+                     */
+                    /* we know that 1<=targetCapacity<length<=4 */
+                    length-=targetCapacity;
+                    charErrorBuffer=(uint8_t *)cnv->charErrorBuffer;
+                    switch(length) {
+                        /* each branch falls through to the next one */
+                    case 3:
+                        *charErrorBuffer++=(uint8_t)(diff>>16);
+                    case 2:
+                        *charErrorBuffer++=(uint8_t)(diff>>8);
+                    case 1:
+                        *charErrorBuffer=(uint8_t)diff;
+                    default:
+                        /* will never occur */
+                        break;
+                    }
+                    cnv->charErrorBufferLength=(int8_t)length;
+
+                    /* now output what fits into the regular target */
+                    diff>>=8*length; /* length was reduced by targetCapacity */
+                    switch(targetCapacity) {
+                        /* each branch falls through to the next one */
+                    case 3:
+                        *target++=(uint8_t)(diff>>16);
+                    case 2:
+                        *target++=(uint8_t)(diff>>8);
+                    case 1:
+                        *target++=(uint8_t)diff;
+                    default:
+                        /* will never occur */
+                        break;
+                    }
+
+                    /* target overflow */
+                    targetCapacity=0;
+                    *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                    break;
+                }
+            }
+        } else {
+            /* target is full */
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+    }
+
+    /* set the converter state back into UConverter */
+    cnv->fromUChar32= c<0 ? -c : 0;
+    cnv->fromUnicodeStatus=(uint32_t)prev;
+
+    /* write back the updated pointers */
+    pArgs->source=source;
+    pArgs->target=(char *)target;
+}
+
+/* BOCU-1-to-Unicode conversion functions ----------------------------------- */
+
+/**
+ * Function for BOCU-1 decoder; handles multi-byte lead bytes.
+ *
+ * @param b lead byte;
+ *          BOCU1_MIN<=b<BOCU1_START_NEG_2 or BOCU1_START_POS_2<=b<BOCU1_MAX_LEAD
+ * @return (diff<<2)|count
+ */
+static U_INLINE int32_t
+decodeBocu1LeadByte(int32_t b) {
+    int32_t diff, count;
+
+    if(b>=BOCU1_START_NEG_2) {
+        /* positive difference */
+        if(b<BOCU1_START_POS_3) {
+            /* two bytes */
+            diff=((int32_t)b-BOCU1_START_POS_2)*BOCU1_TRAIL_COUNT+BOCU1_REACH_POS_1+1;
+            count=1;
+        } else if(b<BOCU1_START_POS_4) {
+            /* three bytes */
+            diff=((int32_t)b-BOCU1_START_POS_3)*BOCU1_TRAIL_COUNT*BOCU1_TRAIL_COUNT+BOCU1_REACH_POS_2+1;
+            count=2;
+        } else {
+            /* four bytes */
+            diff=BOCU1_REACH_POS_3+1;
+            count=3;
+        }
+    } else {
+        /* negative difference */
+        if(b>=BOCU1_START_NEG_3) {
+            /* two bytes */
+            diff=((int32_t)b-BOCU1_START_NEG_2)*BOCU1_TRAIL_COUNT+BOCU1_REACH_NEG_1;
+            count=1;
+        } else if(b>BOCU1_MIN) {
+            /* three bytes */
+            diff=((int32_t)b-BOCU1_START_NEG_3)*BOCU1_TRAIL_COUNT*BOCU1_TRAIL_COUNT+BOCU1_REACH_NEG_2;
+            count=2;
+        } else {
+            /* four bytes */
+            diff=-BOCU1_TRAIL_COUNT*BOCU1_TRAIL_COUNT*BOCU1_TRAIL_COUNT+BOCU1_REACH_NEG_3;
+            count=3;
+        }
+    }
+
+    /* return the state for decoding the trail byte(s) */
+    return (diff<<2)|count;
+}
+
+/**
+ * Function for BOCU-1 decoder; handles multi-byte trail bytes.
+ *
+ * @param count number of remaining trail bytes including this one
+ * @param b trail byte
+ * @return new delta for diff including b - <0 indicates an error
+ *
+ * @see decodeBocu1
+ */
+static U_INLINE int32_t
+decodeBocu1TrailByte(int32_t count, int32_t b) {
+    if(b<=0x20) {
+        /* skip some C0 controls and make the trail byte range contiguous */
+        b=bocu1ByteToTrail[b];
+        /* b<0 for an illegal trail byte value will result in return<0 below */
+#if BOCU1_MAX_TRAIL<0xff
+    } else if(b>BOCU1_MAX_TRAIL) {
+        return -99;
+#endif
+    } else {
+        b-=BOCU1_TRAIL_BYTE_OFFSET;
+    }
+
+    /* add trail byte into difference and decrement count */
+    if(count==1) {
+        return b;
+    } else if(count==2) {
+        return b*BOCU1_TRAIL_COUNT;
+    } else /* count==3 */ {
+        return b*(BOCU1_TRAIL_COUNT*BOCU1_TRAIL_COUNT);
+    }
+}
+
+static void
+_Bocu1ToUnicodeWithOffsets(UConverterToUnicodeArgs *pArgs,
+                           UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const uint8_t *source, *sourceLimit;
+    UChar *target;
+    const UChar *targetLimit;
+    int32_t *offsets;
+
+    int32_t prev, count, diff, c;
+
+    int8_t byteIndex;
+    uint8_t *bytes;
+
+    int32_t sourceIndex, nextSourceIndex;
+
+    /* set up the local pointers */
+    cnv=pArgs->converter;
+    source=(const uint8_t *)pArgs->source;
+    sourceLimit=(const uint8_t *)pArgs->sourceLimit;
+    target=pArgs->target;
+    targetLimit=pArgs->targetLimit;
+    offsets=pArgs->offsets;
+
+    /* get the converter state from UConverter */
+    prev=(int32_t)cnv->toUnicodeStatus;
+    if(prev==0) {
+        prev=BOCU1_ASCII_PREV;
+    }
+    diff=cnv->mode; /* mode may be set to UCNV_SI by ucnv_bld.c but then toULength==0 */
+    count=diff&3;
+    diff>>=2;
+
+    byteIndex=cnv->toULength;
+    bytes=cnv->toUBytes;
+
+    /* sourceIndex=-1 if the current character began in the previous buffer */
+    sourceIndex=byteIndex==0 ? 0 : -1;
+    nextSourceIndex=0;
+
+    /* conversion "loop" similar to _SCSUToUnicodeWithOffsets() */
+    if(count>0 && byteIndex>0 && target<targetLimit) {
+        goto getTrail;
+    }
+
+fastSingle:
+    /* fast loop for single-byte differences */
+    /* use count as the only loop counter variable */
+    diff=(int32_t)(sourceLimit-source);
+    count=(int32_t)(pArgs->targetLimit-target);
+    if(count>diff) {
+        count=diff;
+    }
+    while(count>0) {
+        if(BOCU1_START_NEG_2<=(c=*source) && c<BOCU1_START_POS_2) {
+            c=prev+(c-BOCU1_MIDDLE);
+            if(c<0x3000) {
+                *target++=(UChar)c;
+                *offsets++=nextSourceIndex++;
+                prev=BOCU1_SIMPLE_PREV(c);
+            } else {
+                break;
+            }
+        } else if(c<=0x20) {
+            if(c!=0x20) {
+                prev=BOCU1_ASCII_PREV;
+            }
+            *target++=(UChar)c;
+            *offsets++=nextSourceIndex++;
+        } else {
+            break;
+        }
+        ++source;
+        --count;
+    }
+    sourceIndex=nextSourceIndex; /* wrong if offsets==NULL but does not matter */
+
+    /* decode a sequence of single and lead bytes */
+    while(source<sourceLimit) {
+        if(target>=targetLimit) {
+            /* target is full */
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+
+        ++nextSourceIndex;
+        c=*source++;
+        if(BOCU1_START_NEG_2<=c && c<BOCU1_START_POS_2) {
+            /* Write a code point directly from a single-byte difference. */
+            c=prev+(c-BOCU1_MIDDLE);
+            if(c<0x3000) {
+                *target++=(UChar)c;
+                *offsets++=sourceIndex;
+                prev=BOCU1_SIMPLE_PREV(c);
+                sourceIndex=nextSourceIndex;
+                goto fastSingle;
+            }
+        } else if(c<=0x20) {
+            /*
+             * Direct-encoded C0 control code or space.
+             * Reset prev for C0 control codes but not for space.
+             */
+            if(c!=0x20) {
+                prev=BOCU1_ASCII_PREV;
+            }
+            *target++=(UChar)c;
+            *offsets++=sourceIndex;
+            sourceIndex=nextSourceIndex;
+            continue;
+        } else if(BOCU1_START_NEG_3<=c && c<BOCU1_START_POS_3 && source<sourceLimit) {
+            /* Optimize two-byte case. */
+            if(c>=BOCU1_MIDDLE) {
+                diff=((int32_t)c-BOCU1_START_POS_2)*BOCU1_TRAIL_COUNT+BOCU1_REACH_POS_1+1;
+            } else {
+                diff=((int32_t)c-BOCU1_START_NEG_2)*BOCU1_TRAIL_COUNT+BOCU1_REACH_NEG_1;
+            }
+
+            /* trail byte */
+            ++nextSourceIndex;
+            c=decodeBocu1TrailByte(1, *source++);
+            if(c<0 || (uint32_t)(c=prev+diff+c)>0x10ffff) {
+                bytes[0]=source[-2];
+                bytes[1]=source[-1];
+                byteIndex=2;
+                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                break;
+            }
+        } else if(c==BOCU1_RESET) {
+            /* only reset the state, no code point */
+            prev=BOCU1_ASCII_PREV;
+            sourceIndex=nextSourceIndex;
+            continue;
+        } else {
+            /*
+             * For multi-byte difference lead bytes, set the decoder state
+             * with the partial difference value from the lead byte and
+             * with the number of trail bytes.
+             */
+            bytes[0]=(uint8_t)c;
+            byteIndex=1;
+
+            diff=decodeBocu1LeadByte(c);
+            count=diff&3;
+            diff>>=2;
+getTrail:
+            for(;;) {
+                if(source>=sourceLimit) {
+                    goto endloop;
+                }
+                ++nextSourceIndex;
+                c=bytes[byteIndex++]=*source++;
+
+                /* trail byte in any position */
+                c=decodeBocu1TrailByte(count, c);
+                if(c<0) {
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                    goto endloop;
+                }
+
+                diff+=c;
+                if(--count==0) {
+                    /* final trail byte, deliver a code point */
+                    byteIndex=0;
+                    c=prev+diff;
+                    if((uint32_t)c>0x10ffff) {
+                        *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                        goto endloop;
+                    }
+                    break;
+                }
+            }
+        }
+
+        /* calculate the next prev and output c */
+        prev=BOCU1_PREV(c);
+        if(c<=0xffff) {
+            *target++=(UChar)c;
+            *offsets++=sourceIndex;
+        } else {
+            /* output surrogate pair */
+            *target++=UTF16_LEAD(c);
+            if(target<targetLimit) {
+                *target++=UTF16_TRAIL(c);
+                *offsets++=sourceIndex;
+                *offsets++=sourceIndex;
+            } else {
+                /* target overflow */
+                *offsets++=sourceIndex;
+                cnv->UCharErrorBuffer[0]=UTF16_TRAIL(c);
+                cnv->UCharErrorBufferLength=1;
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                break;
+            }
+        }
+        sourceIndex=nextSourceIndex;
+    }
+endloop:
+
+    if(*pErrorCode==U_ILLEGAL_CHAR_FOUND) {
+        /* set the converter state in UConverter to deal with the next character */
+        cnv->toUnicodeStatus=BOCU1_ASCII_PREV;
+        cnv->mode=0;
+    } else {
+        /* set the converter state back into UConverter */
+        cnv->toUnicodeStatus=(uint32_t)prev;
+        cnv->mode=(diff<<2)|count;
+    }
+    cnv->toULength=byteIndex;
+
+    /* write back the updated pointers */
+    pArgs->source=(const char *)source;
+    pArgs->target=target;
+    pArgs->offsets=offsets;
+    return;
+}
+
+/*
+ * Identical to _Bocu1ToUnicodeWithOffsets but without offset handling.
+ * If a change is made in the original function, then either
+ * change this function the same way or
+ * re-copy the original function and remove the variables
+ * offsets, sourceIndex, and nextSourceIndex.
+ */
+static void
+_Bocu1ToUnicode(UConverterToUnicodeArgs *pArgs,
+                UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const uint8_t *source, *sourceLimit;
+    UChar *target;
+    const UChar *targetLimit;
+
+    int32_t prev, count, diff, c;
+
+    int8_t byteIndex;
+    uint8_t *bytes;
+
+U_ALIGN_CODE(16)
+
+    /* set up the local pointers */
+    cnv=pArgs->converter;
+    source=(const uint8_t *)pArgs->source;
+    sourceLimit=(const uint8_t *)pArgs->sourceLimit;
+    target=pArgs->target;
+    targetLimit=pArgs->targetLimit;
+
+    /* get the converter state from UConverter */
+    prev=(int32_t)cnv->toUnicodeStatus;
+    if(prev==0) {
+        prev=BOCU1_ASCII_PREV;
+    }
+    diff=cnv->mode; /* mode may be set to UCNV_SI by ucnv_bld.c but then toULength==0 */
+    count=diff&3;
+    diff>>=2;
+
+    byteIndex=cnv->toULength;
+    bytes=cnv->toUBytes;
+
+    /* conversion "loop" similar to _SCSUToUnicodeWithOffsets() */
+    if(count>0 && byteIndex>0 && target<targetLimit) {
+        goto getTrail;
+    }
+
+fastSingle:
+    /* fast loop for single-byte differences */
+    /* use count as the only loop counter variable */
+    diff=(int32_t)(sourceLimit-source);
+    count=(int32_t)(pArgs->targetLimit-target);
+    if(count>diff) {
+        count=diff;
+    }
+    while(count>0) {
+        if(BOCU1_START_NEG_2<=(c=*source) && c<BOCU1_START_POS_2) {
+            c=prev+(c-BOCU1_MIDDLE);
+            if(c<0x3000) {
+                *target++=(UChar)c;
+                prev=BOCU1_SIMPLE_PREV(c);
+            } else {
+                break;
+            }
+        } else if(c<=0x20) {
+            if(c!=0x20) {
+                prev=BOCU1_ASCII_PREV;
+            }
+            *target++=(UChar)c;
+        } else {
+            break;
+        }
+        ++source;
+        --count;
+    }
+
+    /* decode a sequence of single and lead bytes */
+    while(source<sourceLimit) {
+        if(target>=targetLimit) {
+            /* target is full */
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+
+        c=*source++;
+        if(BOCU1_START_NEG_2<=c && c<BOCU1_START_POS_2) {
+            /* Write a code point directly from a single-byte difference. */
+            c=prev+(c-BOCU1_MIDDLE);
+            if(c<0x3000) {
+                *target++=(UChar)c;
+                prev=BOCU1_SIMPLE_PREV(c);
+                goto fastSingle;
+            }
+        } else if(c<=0x20) {
+            /*
+             * Direct-encoded C0 control code or space.
+             * Reset prev for C0 control codes but not for space.
+             */
+            if(c!=0x20) {
+                prev=BOCU1_ASCII_PREV;
+            }
+            *target++=(UChar)c;
+            continue;
+        } else if(BOCU1_START_NEG_3<=c && c<BOCU1_START_POS_3 && source<sourceLimit) {
+            /* Optimize two-byte case. */
+            if(c>=BOCU1_MIDDLE) {
+                diff=((int32_t)c-BOCU1_START_POS_2)*BOCU1_TRAIL_COUNT+BOCU1_REACH_POS_1+1;
+            } else {
+                diff=((int32_t)c-BOCU1_START_NEG_2)*BOCU1_TRAIL_COUNT+BOCU1_REACH_NEG_1;
+            }
+
+            /* trail byte */
+            c=decodeBocu1TrailByte(1, *source++);
+            if(c<0 || (uint32_t)(c=prev+diff+c)>0x10ffff) {
+                bytes[0]=source[-2];
+                bytes[1]=source[-1];
+                byteIndex=2;
+                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                break;
+            }
+        } else if(c==BOCU1_RESET) {
+            /* only reset the state, no code point */
+            prev=BOCU1_ASCII_PREV;
+            continue;
+        } else {
+            /*
+             * For multi-byte difference lead bytes, set the decoder state
+             * with the partial difference value from the lead byte and
+             * with the number of trail bytes.
+             */
+            bytes[0]=(uint8_t)c;
+            byteIndex=1;
+
+            diff=decodeBocu1LeadByte(c);
+            count=diff&3;
+            diff>>=2;
+getTrail:
+            for(;;) {
+                if(source>=sourceLimit) {
+                    goto endloop;
+                }
+                c=bytes[byteIndex++]=*source++;
+
+                /* trail byte in any position */
+                c=decodeBocu1TrailByte(count, c);
+                if(c<0) {
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                    goto endloop;
+                }
+
+                diff+=c;
+                if(--count==0) {
+                    /* final trail byte, deliver a code point */
+                    byteIndex=0;
+                    c=prev+diff;
+                    if((uint32_t)c>0x10ffff) {
+                        *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                        goto endloop;
+                    }
+                    break;
+                }
+            }
+        }
+
+        /* calculate the next prev and output c */
+        prev=BOCU1_PREV(c);
+        if(c<=0xffff) {
+            *target++=(UChar)c;
+        } else {
+            /* output surrogate pair */
+            *target++=UTF16_LEAD(c);
+            if(target<targetLimit) {
+                *target++=UTF16_TRAIL(c);
+            } else {
+                /* target overflow */
+                cnv->UCharErrorBuffer[0]=UTF16_TRAIL(c);
+                cnv->UCharErrorBufferLength=1;
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                break;
+            }
+        }
+    }
+endloop:
+
+    if(*pErrorCode==U_ILLEGAL_CHAR_FOUND) {
+        /* set the converter state in UConverter to deal with the next character */
+        cnv->toUnicodeStatus=BOCU1_ASCII_PREV;
+        cnv->mode=0;
+    } else {
+        /* set the converter state back into UConverter */
+        cnv->toUnicodeStatus=(uint32_t)prev;
+        cnv->mode=(diff<<2)|count;
+    }
+    cnv->toULength=byteIndex;
+
+    /* write back the updated pointers */
+    pArgs->source=(const char *)source;
+    pArgs->target=target;
+    return;
+}
+
+/* miscellaneous ------------------------------------------------------------ */
+
+static const UConverterImpl _Bocu1Impl={
+    UCNV_BOCU1,
+
+    NULL,
+    NULL,
+
+    NULL,
+    NULL,
+    NULL,
+
+    _Bocu1ToUnicode,
+    _Bocu1ToUnicodeWithOffsets,
+    _Bocu1FromUnicode,
+    _Bocu1FromUnicodeWithOffsets,
+    NULL,
+
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    ucnv_getCompleteUnicodeSet
+};
+
+static const UConverterStaticData _Bocu1StaticData={
+    sizeof(UConverterStaticData),
+    "BOCU-1",
+    1214, /* CCSID for BOCU-1 */
+    UCNV_IBM, UCNV_BOCU1,
+    1, 4, /* one UChar generates at least 1 byte and at most 4 bytes */
+    { 0x1a, 0, 0, 0 }, 1, /* BOCU-1 never needs to write a subchar */
+    FALSE, FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+
+const UConverterSharedData _Bocu1Data={
+    sizeof(UConverterSharedData), ~((uint32_t)0),
+    NULL, NULL, &_Bocu1StaticData, FALSE, &_Bocu1Impl,
+    0
+};
+
+#endif
diff --git a/source/common/ucnvdisp.c b/source/common/ucnvdisp.c
new file mode 100644
index 0000000..4075be6
--- /dev/null
+++ b/source/common/ucnvdisp.c
@@ -0,0 +1,86 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1998-2004, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+*  ucnvdisp.c:
+*  Implements APIs for the ICU's codeset conversion library display names.
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   04/04/99    helena      Fixed internal header inclusion.
+*   05/09/00    helena      Added implementation to handle fallback mappings.
+*   06/20/2000  helena      OS/400 port changes; mostly typecast.
+*   09/08/2004  grhoten     split from ucnv.c
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ustring.h"
+#include "unicode/ures.h"
+#include "unicode/ucnv.h"
+#include "cstring.h"
+#include "ustr_imp.h"
+#include "ucnv_imp.h"
+#include "putilimp.h"
+
+U_CAPI int32_t U_EXPORT2
+ucnv_getDisplayName(const UConverter *cnv,
+                    const char *displayLocale,
+                    UChar *displayName, int32_t displayNameCapacity,
+                    UErrorCode *pErrorCode) {
+    UResourceBundle *rb;
+    const UChar *name;
+    int32_t length;
+    UErrorCode localStatus = U_ZERO_ERROR;
+
+    /* check arguments */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    if(cnv==NULL || displayNameCapacity<0 || (displayNameCapacity>0 && displayName==NULL)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* open the resource bundle and get the display name string */
+    rb=ures_open(NULL, displayLocale, pErrorCode);
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    /* use the internal name as the key */
+    name=ures_getStringByKey(rb, cnv->sharedData->staticData->name, &length, &localStatus);
+    ures_close(rb);
+
+    if(U_SUCCESS(localStatus)) {
+        /* copy the string */
+        if (*pErrorCode == U_ZERO_ERROR) {
+            *pErrorCode = localStatus;
+        }
+        u_memcpy(displayName, name, uprv_min(length, displayNameCapacity)*U_SIZEOF_UCHAR);
+    } else {
+        /* convert the internal name into a Unicode string */
+        length=(int32_t)uprv_strlen(cnv->sharedData->staticData->name);
+        u_charsToUChars(cnv->sharedData->staticData->name, displayName, uprv_min(length, displayNameCapacity));
+    }
+    return u_terminateUChars(displayName, displayNameCapacity, length, pErrorCode);
+}
+
+#endif
+
+/*
+ * Hey, Emacs, please set the following:
+ *
+ * Local Variables:
+ * indent-tabs-mode: nil
+ * End:
+ *
+ */
diff --git a/source/common/ucnvhz.c b/source/common/ucnvhz.c
new file mode 100644
index 0000000..074b4f4
--- /dev/null
+++ b/source/common/ucnvhz.c
@@ -0,0 +1,640 @@
+/*  
+**********************************************************************
+*   Copyright (C) 2000-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   file name:  ucnvhz.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2000oct16
+*   created by: Ram Viswanadha
+*   10/31/2000  Ram     Implemented offsets logic function
+*   
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION && !UCONFIG_NO_LEGACY_CONVERSION
+
+#include "cmemory.h"
+#include "unicode/ucnv.h"
+#include "unicode/ucnv_cb.h"
+#include "unicode/uset.h"
+#include "ucnv_bld.h"
+#include "ucnv_cnv.h"
+#include "ucnv_imp.h"
+
+#define UCNV_TILDE 0x7E          /* ~ */
+#define UCNV_OPEN_BRACE 0x7B     /* { */
+#define UCNV_CLOSE_BRACE 0x7D   /* } */
+#define SB_ESCAPE    "\x7E\x7D"
+#define DB_ESCAPE    "\x7E\x7B"
+#define TILDE_ESCAPE "\x7E\x7E"
+#define ESC_LEN       2
+
+
+#define CONCAT_ESCAPE_MACRO( args, targetIndex,targetLength,strToAppend, err, len,sourceIndex){                             \
+    while(len-->0){                                                                                                         \
+        if(targetIndex < targetLength){                                                                                     \
+            args->target[targetIndex] = (unsigned char) *strToAppend;                                                       \
+            if(args->offsets!=NULL){                                                                                        \
+                *(offsets++) = sourceIndex-1;                                                                               \
+            }                                                                                                               \
+            targetIndex++;                                                                                                  \
+        }                                                                                                                   \
+        else{                                                                                                               \
+            args->converter->charErrorBuffer[(int)args->converter->charErrorBufferLength++] = (unsigned char) *strToAppend; \
+            *err =U_BUFFER_OVERFLOW_ERROR;                                                                                  \
+        }                                                                                                                   \
+        strToAppend++;                                                                                                      \
+    }                                                                                                                       \
+}
+
+
+typedef struct{
+    UConverter* gbConverter;
+    int32_t targetIndex;
+    int32_t sourceIndex;
+    UBool isEscapeAppended;
+    UBool isStateDBCS;
+    UBool isTargetUCharDBCS;
+    UBool isEmptySegment;
+}UConverterDataHZ;
+
+
+
+static void 
+_HZOpen(UConverter *cnv, UConverterLoadArgs *pArgs, UErrorCode *errorCode){
+    UConverter *gbConverter;
+    if(pArgs->onlyTestIsLoadable) {
+        ucnv_canCreateConverter("GBK", errorCode);  /* errorCode carries result */
+        return;
+    }
+    gbConverter = ucnv_open("GBK", errorCode);
+    if(U_FAILURE(*errorCode)) {
+        return;
+    }
+    cnv->toUnicodeStatus = 0;
+    cnv->fromUnicodeStatus= 0;
+    cnv->mode=0;
+    cnv->fromUChar32=0x0000;
+    cnv->extraInfo = uprv_malloc(sizeof(UConverterDataHZ));
+    if(cnv->extraInfo != NULL){
+        uprv_memset(cnv->extraInfo, 0, sizeof(UConverterDataHZ));
+        ((UConverterDataHZ*)cnv->extraInfo)->gbConverter = gbConverter;
+    }
+    else {
+        ucnv_close(gbConverter);
+        *errorCode = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+}
+
+static void 
+_HZClose(UConverter *cnv){
+    if(cnv->extraInfo != NULL) {
+        ucnv_close (((UConverterDataHZ *) (cnv->extraInfo))->gbConverter);
+        if(!cnv->isExtraLocal) {
+            uprv_free(cnv->extraInfo);
+        }
+        cnv->extraInfo = NULL;
+    }
+}
+
+static void 
+_HZReset(UConverter *cnv, UConverterResetChoice choice){
+    if(choice<=UCNV_RESET_TO_UNICODE) {
+        cnv->toUnicodeStatus = 0;
+        cnv->mode=0;
+        if(cnv->extraInfo != NULL){
+            ((UConverterDataHZ*)cnv->extraInfo)->isStateDBCS = FALSE;
+            ((UConverterDataHZ*)cnv->extraInfo)->isEmptySegment = FALSE;
+        }
+    }
+    if(choice!=UCNV_RESET_TO_UNICODE) {
+        cnv->fromUnicodeStatus= 0;
+        cnv->fromUChar32=0x0000; 
+        if(cnv->extraInfo != NULL){
+            ((UConverterDataHZ*)cnv->extraInfo)->isEscapeAppended = FALSE;
+            ((UConverterDataHZ*)cnv->extraInfo)->targetIndex = 0;
+            ((UConverterDataHZ*)cnv->extraInfo)->sourceIndex = 0;
+            ((UConverterDataHZ*)cnv->extraInfo)->isTargetUCharDBCS = FALSE;
+        }
+    }
+}
+
+/**************************************HZ Encoding*************************************************
+* Rules for HZ encoding
+* 
+*   In ASCII mode, a byte is interpreted as an ASCII character, unless a
+*   '~' is encountered. The character '~' is an escape character. By
+*   convention, it must be immediately followed ONLY by '~', '{' or '\n'
+*   (<LF>), with the following special meaning.
+
+*   1. The escape sequence '~~' is interpreted as a '~'.
+*   2. The escape-to-GB sequence '~{' switches the mode from ASCII to GB.
+*   3. The escape sequence '~\n' is a line-continuation marker to be
+*     consumed with no output produced.
+*   In GB mode, characters are interpreted two bytes at a time as (pure)
+*   GB codes until the escape-from-GB code '~}' is read. This code
+*   switches the mode from GB back to ASCII.  (Note that the escape-
+*   from-GB code '~}' ($7E7D) is outside the defined GB range.)
+*
+*   Source: RFC 1842
+*
+*   Note that the formal syntax in RFC 1842 is invalid. I assume that the
+*   intended definition of single-byte-segment is as follows (pedberg):
+*   single-byte-segment = single-byte-seq 1*single-byte-char
+*/
+
+
+static void 
+UConverter_toUnicode_HZ_OFFSETS_LOGIC(UConverterToUnicodeArgs *args,
+                                                            UErrorCode* err){
+    char tempBuf[2];
+    const char *mySource = ( char *) args->source;
+    UChar *myTarget = args->target;
+    const char *mySourceLimit = args->sourceLimit;
+    UChar32 targetUniChar = 0x0000;
+    int32_t mySourceChar = 0x0000;
+    UConverterDataHZ* myData=(UConverterDataHZ*)(args->converter->extraInfo);
+    tempBuf[0]=0; 
+    tempBuf[1]=0;
+
+    /* Calling code already handles this situation. */
+    /*if ((args->converter == NULL) || (args->targetLimit < args->target) || (mySourceLimit < args->source)){
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }*/
+    
+    while(mySource< mySourceLimit){
+        
+        if(myTarget < args->targetLimit){
+            
+            mySourceChar= (unsigned char) *mySource++;
+
+            if(args->converter->mode == UCNV_TILDE) {
+                /* second byte after ~ */
+                args->converter->mode=0;
+                switch(mySourceChar) {
+                case 0x0A:
+                    /* no output for ~\n (line-continuation marker) */
+                    continue;
+                case UCNV_TILDE:
+                    if(args->offsets) {
+                        args->offsets[myTarget - args->target]=(int32_t)(mySource - args->source - 2);
+                    }
+                    *(myTarget++)=(UChar)mySourceChar;
+                    myData->isEmptySegment = FALSE;
+                    continue;
+                case UCNV_OPEN_BRACE:
+                case UCNV_CLOSE_BRACE:
+                    myData->isStateDBCS = (mySourceChar == UCNV_OPEN_BRACE);
+                    if (myData->isEmptySegment) {
+                        myData->isEmptySegment = FALSE; /* we are handling it, reset to avoid future spurious errors */
+                        *err = U_ILLEGAL_ESCAPE_SEQUENCE;
+                        args->converter->toUCallbackReason = UCNV_IRREGULAR;
+                        args->converter->toUBytes[0] = UCNV_TILDE;
+                        args->converter->toUBytes[1] = mySourceChar;
+                        args->converter->toULength = 2;
+                        args->target = myTarget;
+                        args->source = mySource;
+                        return;
+                    }
+                    myData->isEmptySegment = TRUE;
+                    continue;
+                default:
+                     /* if the first byte is equal to TILDE and the trail byte
+                     * is not a valid byte then it is an error condition
+                     */
+                    /*
+                     * Ticket 5691: consistent illegal sequences:
+                     * - We include at least the first byte in the illegal sequence.
+                     * - If any of the non-initial bytes could be the start of a character,
+                     *   we stop the illegal sequence before the first one of those.
+                     */
+                    myData->isEmptySegment = FALSE; /* different error here, reset this to avoid spurious future error */
+                    *err = U_ILLEGAL_ESCAPE_SEQUENCE;
+                    args->converter->toUBytes[0] = UCNV_TILDE;
+                    if( myData->isStateDBCS ?
+                            (0x21 <= mySourceChar && mySourceChar <= 0x7e) :
+                            mySourceChar <= 0x7f
+                    ) {
+                        /* The current byte could be the start of a character: Back it out. */
+                        args->converter->toULength = 1;
+                        --mySource;
+                    } else {
+                        /* Include the current byte in the illegal sequence. */
+                        args->converter->toUBytes[1] = mySourceChar;
+                        args->converter->toULength = 2;
+                    }
+                    args->target = myTarget;
+                    args->source = mySource;
+                    return;
+                }
+            } else if(myData->isStateDBCS) {
+                if(args->converter->toUnicodeStatus == 0x00){
+                    /* lead byte */
+                    if(mySourceChar == UCNV_TILDE) {
+                        args->converter->mode = UCNV_TILDE;
+                    } else {
+                        /* add another bit to distinguish a 0 byte from not having seen a lead byte */
+                        args->converter->toUnicodeStatus = (uint32_t) (mySourceChar | 0x100);
+                        myData->isEmptySegment = FALSE; /* the segment has something, either valid or will produce a different error, so reset this */
+                    }
+                    continue;
+                }
+                else{
+                    /* trail byte */
+                    int leadIsOk, trailIsOk;
+                    uint32_t leadByte = args->converter->toUnicodeStatus & 0xff;
+                    targetUniChar = 0xffff;
+                    /*
+                     * Ticket 5691: consistent illegal sequences:
+                     * - We include at least the first byte in the illegal sequence.
+                     * - If any of the non-initial bytes could be the start of a character,
+                     *   we stop the illegal sequence before the first one of those.
+                     *
+                     * In HZ DBCS, if the second byte is in the 21..7e range,
+                     * we report only the first byte as the illegal sequence.
+                     * Otherwise we convert or report the pair of bytes.
+                     */
+                    leadIsOk = (uint8_t)(leadByte - 0x21) <= (0x7d - 0x21);
+                    trailIsOk = (uint8_t)(mySourceChar - 0x21) <= (0x7e - 0x21);
+                    if (leadIsOk && trailIsOk) {
+                        tempBuf[0] = (char) (leadByte+0x80) ;
+                        tempBuf[1] = (char) (mySourceChar+0x80);
+                        targetUniChar = ucnv_MBCSSimpleGetNextUChar(myData->gbConverter->sharedData,
+                            tempBuf, 2, args->converter->useFallback);
+                        mySourceChar= (leadByte << 8) | mySourceChar;
+                    } else if (trailIsOk) {
+                        /* report a single illegal byte and continue with the following DBCS starter byte */
+                        --mySource;
+                        mySourceChar = (int32_t)leadByte;
+                    } else {
+                        /* report a pair of illegal bytes if the second byte is not a DBCS starter */
+                        /* add another bit so that the code below writes 2 bytes in case of error */
+                        mySourceChar= 0x10000 | (leadByte << 8) | mySourceChar;
+                    }
+                    args->converter->toUnicodeStatus =0x00;
+                }
+            }
+            else{
+                if(mySourceChar == UCNV_TILDE) {
+                    args->converter->mode = UCNV_TILDE;
+                    continue;
+                } else if(mySourceChar <= 0x7f) {
+                    targetUniChar = (UChar)mySourceChar;  /* ASCII */
+                    myData->isEmptySegment = FALSE; /* the segment has something valid */
+                } else {
+                    targetUniChar = 0xffff;
+                    myData->isEmptySegment = FALSE; /* different error here, reset this to avoid spurious future error */
+                }
+            }
+            if(targetUniChar < 0xfffe){
+                if(args->offsets) {
+                    args->offsets[myTarget - args->target]=(int32_t)(mySource - args->source - 1-(myData->isStateDBCS));
+                }
+
+                *(myTarget++)=(UChar)targetUniChar;
+            }
+            else /* targetUniChar>=0xfffe */ {
+                if(targetUniChar == 0xfffe){
+                    *err = U_INVALID_CHAR_FOUND;
+                }
+                else{
+                    *err = U_ILLEGAL_CHAR_FOUND;
+                }
+                if(mySourceChar > 0xff){
+                    args->converter->toUBytes[0] = (uint8_t)(mySourceChar >> 8);
+                    args->converter->toUBytes[1] = (uint8_t)mySourceChar;
+                    args->converter->toULength=2;
+                }
+                else{
+                    args->converter->toUBytes[0] = (uint8_t)mySourceChar;
+                    args->converter->toULength=1;
+                }
+                break;
+            }
+        }
+        else{
+            *err =U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+    }
+
+    args->target = myTarget;
+    args->source = mySource;
+}
+
+
+static void 
+UConverter_fromUnicode_HZ_OFFSETS_LOGIC (UConverterFromUnicodeArgs * args,
+                                                      UErrorCode * err){
+    const UChar *mySource = args->source;
+    char *myTarget = args->target;
+    int32_t* offsets = args->offsets;
+    int32_t mySourceIndex = 0;
+    int32_t myTargetIndex = 0;
+    int32_t targetLength = (int32_t)(args->targetLimit - myTarget);
+    int32_t mySourceLength = (int32_t)(args->sourceLimit - args->source);
+    int32_t length=0;
+    uint32_t targetUniChar = 0x0000;
+    UChar32 mySourceChar = 0x0000;
+    UConverterDataHZ *myConverterData=(UConverterDataHZ*)args->converter->extraInfo;
+    UBool isTargetUCharDBCS = (UBool) myConverterData->isTargetUCharDBCS;
+    UBool oldIsTargetUCharDBCS = isTargetUCharDBCS;
+    int len =0;
+    const char* escSeq=NULL;
+    
+    /* Calling code already handles this situation. */
+    /*if ((args->converter == NULL) || (args->targetLimit < myTarget) || (args->sourceLimit < args->source)){
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }*/
+    if(args->converter->fromUChar32!=0 && myTargetIndex < targetLength) {
+        goto getTrail;
+    }
+    /*writing the char to the output stream */
+    while (mySourceIndex < mySourceLength){
+        targetUniChar = missingCharMarker;
+        if (myTargetIndex < targetLength){
+            
+            mySourceChar = (UChar) mySource[mySourceIndex++];
+            
+
+            oldIsTargetUCharDBCS = isTargetUCharDBCS;
+            if(mySourceChar ==UCNV_TILDE){
+                /*concatEscape(args, &myTargetIndex, &targetLength,"\x7E\x7E",err,2,&mySourceIndex);*/
+                len = ESC_LEN;
+                escSeq = TILDE_ESCAPE;
+                CONCAT_ESCAPE_MACRO(args, myTargetIndex, targetLength, escSeq,err,len,mySourceIndex);
+                continue;
+            } else if(mySourceChar <= 0x7f) {
+                length = 1;
+                targetUniChar = mySourceChar;
+            } else {
+                length= ucnv_MBCSFromUChar32(myConverterData->gbConverter->sharedData,
+                    mySourceChar,&targetUniChar,args->converter->useFallback);
+                /* we can only use lead bytes 21..7D and trail bytes 21..7E */
+                if( length == 2 &&
+                    (uint16_t)(targetUniChar - 0xa1a1) <= (0xfdfe - 0xa1a1) &&
+                    (uint8_t)(targetUniChar - 0xa1) <= (0xfe - 0xa1)
+                ) {
+                    targetUniChar -= 0x8080;
+                } else {
+                    targetUniChar = missingCharMarker;
+                }
+            }
+            if (targetUniChar != missingCharMarker){
+               myConverterData->isTargetUCharDBCS = isTargetUCharDBCS = (UBool)(targetUniChar>0x00FF);     
+                 if(oldIsTargetUCharDBCS != isTargetUCharDBCS || !myConverterData->isEscapeAppended ){
+                    /*Shifting from a double byte to single byte mode*/
+                    if(!isTargetUCharDBCS){
+                        len =ESC_LEN;
+                        escSeq = SB_ESCAPE;
+                        CONCAT_ESCAPE_MACRO(args, myTargetIndex, targetLength, escSeq,err,len,mySourceIndex);
+                        myConverterData->isEscapeAppended = TRUE;
+                    }
+                    else{ /* Shifting from a single byte to double byte mode*/
+                        len =ESC_LEN;
+                        escSeq = DB_ESCAPE;
+                        CONCAT_ESCAPE_MACRO(args, myTargetIndex, targetLength, escSeq,err,len,mySourceIndex);
+                        myConverterData->isEscapeAppended = TRUE;
+                        
+                    }
+                }
+            
+                if(isTargetUCharDBCS){
+                    if( myTargetIndex <targetLength){
+                        myTarget[myTargetIndex++] =(char) (targetUniChar >> 8);
+                        if(offsets){
+                            *(offsets++) = mySourceIndex-1;
+                        }
+                        if(myTargetIndex < targetLength){
+                            myTarget[myTargetIndex++] =(char) targetUniChar;
+                            if(offsets){
+                                *(offsets++) = mySourceIndex-1;
+                            }
+                        }else{
+                            args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = (char) targetUniChar;
+                            *err = U_BUFFER_OVERFLOW_ERROR;
+                        } 
+                    }else{
+                        args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] =(char) (targetUniChar >> 8);
+                        args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = (char) targetUniChar;
+                        *err = U_BUFFER_OVERFLOW_ERROR;
+                    }
+
+                }else{
+                    if( myTargetIndex <targetLength){
+                        myTarget[myTargetIndex++] = (char) (targetUniChar );
+                        if(offsets){
+                            *(offsets++) = mySourceIndex-1;
+                        }
+                        
+                    }else{
+                        args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] = (char) targetUniChar;
+                        *err = U_BUFFER_OVERFLOW_ERROR;
+                    }
+                }
+
+            }
+            else{
+                /* oops.. the code point is unassigned */
+                /*Handle surrogates */
+                /*check if the char is a First surrogate*/
+                if(UTF_IS_SURROGATE(mySourceChar)) {
+                    if(UTF_IS_SURROGATE_FIRST(mySourceChar)) {
+                        args->converter->fromUChar32=mySourceChar;
+getTrail:
+                        /*look ahead to find the trail surrogate*/
+                        if(mySourceIndex <  mySourceLength) {
+                            /* test the following code unit */
+                            UChar trail=(UChar) args->source[mySourceIndex];
+                            if(UTF_IS_SECOND_SURROGATE(trail)) {
+                                ++mySourceIndex;
+                                mySourceChar=UTF16_GET_PAIR_VALUE(args->converter->fromUChar32, trail);
+                                args->converter->fromUChar32=0x00;
+                                /* there are no surrogates in GB2312*/
+                                *err = U_INVALID_CHAR_FOUND;
+                                /* exit this condition tree */
+                            } else {
+                                /* this is an unmatched lead code unit (1st surrogate) */
+                                /* callback(illegal) */
+                                *err=U_ILLEGAL_CHAR_FOUND;
+                            }
+                        } else {
+                            /* no more input */
+                            *err = U_ZERO_ERROR;
+                        }
+                    } else {
+                        /* this is an unmatched trail code unit (2nd surrogate) */
+                        /* callback(illegal) */
+                        *err=U_ILLEGAL_CHAR_FOUND;
+                    }
+                } else {
+                    /* callback(unassigned) for a BMP code point */
+                    *err = U_INVALID_CHAR_FOUND;
+                }
+
+                args->converter->fromUChar32=mySourceChar;
+                break;
+            }
+        }
+        else{
+            *err = U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+        targetUniChar=missingCharMarker;
+    }
+
+    args->target += myTargetIndex;
+    args->source += mySourceIndex;
+    myConverterData->isTargetUCharDBCS = isTargetUCharDBCS;
+}
+
+static void
+_HZ_WriteSub(UConverterFromUnicodeArgs *args, int32_t offsetIndex, UErrorCode *err) {
+    UConverter *cnv = args->converter;
+    UConverterDataHZ *convData=(UConverterDataHZ *) cnv->extraInfo;
+    char *p;
+    char buffer[4];
+    p = buffer;
+    
+    if( convData->isTargetUCharDBCS){
+        *p++= UCNV_TILDE;
+        *p++= UCNV_CLOSE_BRACE;
+        convData->isTargetUCharDBCS=FALSE;
+    }
+    *p++= (char)cnv->subChars[0];
+
+    ucnv_cbFromUWriteBytes(args,
+                           buffer, (int32_t)(p - buffer),
+                           offsetIndex, err);
+}
+
+/*
+ * Structure for cloning an HZ converter into a single memory block.
+ * ucnv_safeClone() of the HZ converter will align the entire cloneHZStruct,
+ * and then ucnv_safeClone() of the sub-converter may additionally align
+ * subCnv inside the cloneHZStruct, for which we need the deadSpace after
+ * subCnv. This is because UAlignedMemory may be larger than the actually
+ * necessary alignment size for the platform.
+ * The other cloneHZStruct fields will not be moved around,
+ * and are aligned properly with cloneHZStruct's alignment.
+ */
+struct cloneHZStruct
+{
+    UConverter cnv;
+    UConverter subCnv;
+    UAlignedMemory deadSpace;
+    UConverterDataHZ mydata;
+};
+
+
+static UConverter * 
+_HZ_SafeClone(const UConverter *cnv, 
+              void *stackBuffer, 
+              int32_t *pBufferSize, 
+              UErrorCode *status)
+{
+    struct cloneHZStruct * localClone;
+    int32_t size, bufferSizeNeeded = sizeof(struct cloneHZStruct);
+
+    if (U_FAILURE(*status)){
+        return 0;
+    }
+
+    if (*pBufferSize == 0){ /* 'preflighting' request - set needed size into *pBufferSize */
+        *pBufferSize = bufferSizeNeeded;
+        return 0;
+    }
+
+    localClone = (struct cloneHZStruct *)stackBuffer;
+    /* ucnv.c/ucnv_safeClone() copied the main UConverter already */
+
+    uprv_memcpy(&localClone->mydata, cnv->extraInfo, sizeof(UConverterDataHZ));
+    localClone->cnv.extraInfo = &localClone->mydata;
+    localClone->cnv.isExtraLocal = TRUE;
+
+    /* deep-clone the sub-converter */
+    size = (int32_t)(sizeof(UConverter) + sizeof(UAlignedMemory)); /* include size of padding */
+    ((UConverterDataHZ*)localClone->cnv.extraInfo)->gbConverter =
+        ucnv_safeClone(((UConverterDataHZ*)cnv->extraInfo)->gbConverter, &localClone->subCnv, &size, status);
+
+    return &localClone->cnv;
+}
+
+static void
+_HZ_GetUnicodeSet(const UConverter *cnv,
+                  const USetAdder *sa,
+                  UConverterUnicodeSet which,
+                  UErrorCode *pErrorCode) {
+    /* HZ converts all of ASCII */
+    sa->addRange(sa->set, 0, 0x7f);
+
+    /* add all of the code points that the sub-converter handles */
+    ucnv_MBCSGetFilteredUnicodeSetForUnicode(
+        ((UConverterDataHZ*)cnv->extraInfo)->gbConverter->sharedData,
+        sa, which, UCNV_SET_FILTER_HZ,
+        pErrorCode);
+}
+
+static const UConverterImpl _HZImpl={
+
+    UCNV_HZ,
+    
+    NULL,
+    NULL,
+    
+    _HZOpen,
+    _HZClose,
+    _HZReset,
+    
+    UConverter_toUnicode_HZ_OFFSETS_LOGIC,
+    UConverter_toUnicode_HZ_OFFSETS_LOGIC,
+    UConverter_fromUnicode_HZ_OFFSETS_LOGIC,
+    UConverter_fromUnicode_HZ_OFFSETS_LOGIC,
+    NULL,
+    
+    NULL,
+    NULL,
+    _HZ_WriteSub,
+    _HZ_SafeClone,
+    _HZ_GetUnicodeSet
+};
+
+static const UConverterStaticData _HZStaticData={
+    sizeof(UConverterStaticData),
+        "HZ",
+         0, 
+         UCNV_IBM, 
+         UCNV_HZ, 
+         1, 
+         4,
+        { 0x1a, 0, 0, 0 },
+        1,
+        FALSE, 
+        FALSE,
+        0,
+        0,
+        { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* reserved */
+
+};
+            
+            
+const UConverterSharedData _HZData={
+    sizeof(UConverterSharedData),
+        ~((uint32_t) 0),
+        NULL, 
+        NULL, 
+        &_HZStaticData, 
+        FALSE, 
+        &_HZImpl, 
+        0
+};
+
+#endif /* #if !UCONFIG_NO_LEGACY_CONVERSION */
diff --git a/source/common/ucnvisci.c b/source/common/ucnvisci.c
new file mode 100644
index 0000000..4110852
--- /dev/null
+++ b/source/common/ucnvisci.c
@@ -0,0 +1,1627 @@
+/*
+**********************************************************************
+*   Copyright (C) 2000-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   file name:  ucnvisci.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2001JUN26
+*   created by: Ram Viswanadha
+*
+*   Date        Name        Description
+*   24/7/2001   Ram         Added support for EXT character handling
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION && !UCONFIG_NO_LEGACY_CONVERSION
+
+#include "cmemory.h"
+#include "ucnv_bld.h"
+#include "unicode/ucnv.h"
+#include "ucnv_cnv.h"
+#include "unicode/ucnv_cb.h"
+#include "unicode/uset.h"
+#include "cstring.h"
+
+#define UCNV_OPTIONS_VERSION_MASK 0xf
+#define NUKTA               0x093c
+#define HALANT              0x094d
+#define ZWNJ                0x200c /* Zero Width Non Joiner */
+#define ZWJ                 0x200d /* Zero width Joiner */
+#define INVALID_CHAR        0xffff
+#define ATR                 0xEF   /* Attribute code */
+#define EXT                 0xF0   /* Extension code */
+#define DANDA               0x0964
+#define DOUBLE_DANDA        0x0965
+#define ISCII_NUKTA         0xE9
+#define ISCII_HALANT        0xE8
+#define ISCII_DANDA         0xEA
+#define ISCII_INV           0xD9
+#define ISCII_VOWEL_SIGN_E  0xE0
+#define INDIC_BLOCK_BEGIN   0x0900
+#define INDIC_BLOCK_END     0x0D7F
+#define INDIC_RANGE         (INDIC_BLOCK_END - INDIC_BLOCK_BEGIN)
+#define VOCALLIC_RR         0x0931
+#define LF                  0x0A
+#define ASCII_END           0xA0
+#define NO_CHAR_MARKER      0xFFFE
+#define TELUGU_DELTA        DELTA * TELUGU
+#define DEV_ABBR_SIGN       0x0970
+#define DEV_ANUDATTA        0x0952
+#define EXT_RANGE_BEGIN     0xA1
+#define EXT_RANGE_END       0xEE
+
+#define PNJ_DELTA           0x0100
+#define PNJ_BINDI           0x0A02
+#define PNJ_TIPPI           0x0A70
+#define PNJ_SIGN_VIRAMA     0x0A4D
+#define PNJ_ADHAK           0x0A71
+#define PNJ_HA              0x0A39
+#define PNJ_RRA             0x0A5C
+
+static USet* PNJ_BINDI_TIPPI_SET= NULL;
+static USet* PNJ_CONSONANT_SET= NULL;
+
+typedef enum {
+    DEVANAGARI =0,
+    BENGALI,
+    GURMUKHI,
+    GUJARATI,
+    ORIYA,
+    TAMIL,
+    TELUGU,
+    KANNADA,
+    MALAYALAM,
+    DELTA=0x80
+}UniLang;
+
+/**
+ * Enumeration for switching code pages if <ATR>+<one of below values>
+ * is encountered
+ */
+typedef enum {
+    DEF = 0x40,
+    RMN = 0x41,
+    DEV = 0x42,
+    BNG = 0x43,
+    TML = 0x44,
+    TLG = 0x45,
+    ASM = 0x46,
+    ORI = 0x47,
+    KND = 0x48,
+    MLM = 0x49,
+    GJR = 0x4A,
+    PNJ = 0x4B,
+    ARB = 0x71,
+    PES = 0x72,
+    URD = 0x73,
+    SND = 0x74,
+    KSM = 0x75,
+    PST = 0x76
+}ISCIILang;
+
+typedef enum {
+    DEV_MASK =0x80,
+    PNJ_MASK =0x40,
+    GJR_MASK =0x20,
+    ORI_MASK =0x10,
+    BNG_MASK =0x08,
+    KND_MASK =0x04,
+    MLM_MASK =0x02,
+    TML_MASK =0x01,
+    ZERO =0x00
+}MaskEnum;
+
+#define ISCII_CNV_PREFIX "ISCII,version="
+
+typedef struct {
+    UChar contextCharToUnicode;         /* previous Unicode codepoint for contextual analysis */
+    UChar contextCharFromUnicode;       /* previous Unicode codepoint for contextual analysis */
+    uint16_t defDeltaToUnicode;         /* delta for switching to default state when DEF is encountered  */
+    uint16_t currentDeltaFromUnicode;   /* current delta in Indic block */
+    uint16_t currentDeltaToUnicode;     /* current delta in Indic block */
+    MaskEnum currentMaskFromUnicode;    /* mask for current state in toUnicode */
+    MaskEnum currentMaskToUnicode;      /* mask for current state in toUnicode */
+    MaskEnum defMaskToUnicode;          /* mask for default state in toUnicode */
+    UBool isFirstBuffer;                /* boolean for fromUnicode to see if we need to announce the first script */
+    UBool resetToDefaultToUnicode;      /* boolean for reseting to default delta and mask when a newline is encountered*/
+    char name[sizeof(ISCII_CNV_PREFIX) + 1];
+    UChar32 prevToUnicodeStatus;        /* Hold the previous toUnicodeStatus. This is necessary because we may need to know the last two code points. */
+} UConverterDataISCII;
+
+typedef struct LookupDataStruct {
+    UniLang uniLang;
+    MaskEnum maskEnum;
+    ISCIILang isciiLang;
+} LookupDataStruct;
+
+static const LookupDataStruct lookupInitialData[]={
+    { DEVANAGARI, DEV_MASK,  DEV },
+    { BENGALI,    BNG_MASK,  BNG },
+    { GURMUKHI,   PNJ_MASK,  PNJ },
+    { GUJARATI,   GJR_MASK,  GJR },
+    { ORIYA,      ORI_MASK,  ORI },
+    { TAMIL,      TML_MASK,  TML },
+    { TELUGU,     KND_MASK,  TLG },
+    { KANNADA,    KND_MASK,  KND },
+    { MALAYALAM,  MLM_MASK,  MLM }
+};
+
+static void initializeSets() {
+    /* TODO: Replace the following two lines with PNJ_CONSONANT_SET = uset_openEmpty(); */
+    PNJ_CONSONANT_SET = uset_open(0,0);
+    uset_clear(PNJ_CONSONANT_SET);
+
+    uset_addRange(PNJ_CONSONANT_SET, 0x0A15, 0x0A28);
+    uset_addRange(PNJ_CONSONANT_SET, 0x0A2A, 0x0A30);
+    uset_addRange(PNJ_CONSONANT_SET, 0x0A35, 0x0A36);
+    uset_addRange(PNJ_CONSONANT_SET, 0x0A38, 0x0A39);
+    
+    PNJ_BINDI_TIPPI_SET = uset_clone(PNJ_CONSONANT_SET);
+    uset_add(PNJ_BINDI_TIPPI_SET, 0x0A05);
+    uset_add(PNJ_BINDI_TIPPI_SET, 0x0A07);
+    uset_add(PNJ_BINDI_TIPPI_SET, 0x0A3F);
+    uset_addRange(PNJ_BINDI_TIPPI_SET, 0x0A41, 0x0A42);
+    
+    uset_compact(PNJ_CONSONANT_SET);
+    uset_compact(PNJ_BINDI_TIPPI_SET);
+}
+
+static void _ISCIIOpen(UConverter *cnv, UConverterLoadArgs *pArgs, UErrorCode *errorCode) {
+    if(pArgs->onlyTestIsLoadable) {
+        return;
+    }
+
+    /* Ensure that the sets used in special handling of certain Gurmukhi characters are initialized. */
+    initializeSets();
+    
+    cnv->extraInfo = uprv_malloc(sizeof(UConverterDataISCII));
+
+    if (cnv->extraInfo != NULL) {
+        int32_t len=0;
+        UConverterDataISCII *converterData=
+                (UConverterDataISCII *) cnv->extraInfo;
+        converterData->contextCharToUnicode=NO_CHAR_MARKER;
+        cnv->toUnicodeStatus = missingCharMarker;
+        converterData->contextCharFromUnicode=0x0000;
+        converterData->resetToDefaultToUnicode=FALSE;
+        /* check if the version requested is supported */
+        if ((pArgs->options & UCNV_OPTIONS_VERSION_MASK) < 9) {
+            /* initialize state variables */
+            converterData->currentDeltaFromUnicode
+                    = converterData->currentDeltaToUnicode
+                            = converterData->defDeltaToUnicode = (uint16_t)(lookupInitialData[pArgs->options & UCNV_OPTIONS_VERSION_MASK].uniLang * DELTA);
+
+            converterData->currentMaskFromUnicode
+                    = converterData->currentMaskToUnicode
+                            = converterData->defMaskToUnicode = lookupInitialData[pArgs->options & UCNV_OPTIONS_VERSION_MASK].maskEnum;
+            
+            converterData->isFirstBuffer=TRUE;
+            (void)uprv_strcpy(converterData->name, ISCII_CNV_PREFIX);
+            len = (int32_t)uprv_strlen(converterData->name);
+            converterData->name[len]= (char)((pArgs->options & UCNV_OPTIONS_VERSION_MASK) + '0');
+            converterData->name[len+1]=0;
+            
+            converterData->prevToUnicodeStatus = 0x0000;
+        } else {
+            uprv_free(cnv->extraInfo);
+            cnv->extraInfo = NULL;
+            *errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+
+    } else {
+        *errorCode =U_MEMORY_ALLOCATION_ERROR;
+    }
+}
+
+static void _ISCIIClose(UConverter *cnv) {
+    if (cnv->extraInfo!=NULL) {
+        if (!cnv->isExtraLocal) {
+            uprv_free(cnv->extraInfo);
+        }
+        cnv->extraInfo=NULL;
+    }
+    if (PNJ_CONSONANT_SET != NULL) {
+        uset_close(PNJ_CONSONANT_SET);
+        PNJ_CONSONANT_SET = NULL;
+    }
+    if (PNJ_BINDI_TIPPI_SET != NULL) {
+        uset_close(PNJ_BINDI_TIPPI_SET);
+        PNJ_BINDI_TIPPI_SET = NULL;
+    }
+}
+
+static const char* _ISCIIgetName(const UConverter* cnv) {
+    if (cnv->extraInfo) {
+        UConverterDataISCII* myData= (UConverterDataISCII*)cnv->extraInfo;
+        return myData->name;
+    }
+    return NULL;
+}
+
+static void _ISCIIReset(UConverter *cnv, UConverterResetChoice choice) {
+    UConverterDataISCII* data =(UConverterDataISCII *) (cnv->extraInfo);
+    if (choice<=UCNV_RESET_TO_UNICODE) {
+        cnv->toUnicodeStatus = missingCharMarker;
+        cnv->mode=0;
+        data->currentDeltaToUnicode=data->defDeltaToUnicode;
+        data->currentMaskToUnicode = data->defMaskToUnicode;
+        data->contextCharToUnicode=NO_CHAR_MARKER;
+        data->prevToUnicodeStatus = 0x0000;
+    }
+    if (choice!=UCNV_RESET_TO_UNICODE) {
+        cnv->fromUChar32=0x0000;
+        data->contextCharFromUnicode=0x00;
+        data->currentMaskFromUnicode=data->defMaskToUnicode;
+        data->currentDeltaFromUnicode=data->defDeltaToUnicode;
+        data->isFirstBuffer=TRUE;
+        data->resetToDefaultToUnicode=FALSE;
+    }
+}
+
+/**
+ * The values in validity table are indexed by the lower bits of Unicode
+ * range 0x0900 - 0x09ff. The values have a structure like:
+ *       ---------------------------------------------------------------
+ *      | DEV   | PNJ   | GJR   | ORI   | BNG   | TLG   | MLM   | TML   |
+ *      |       |       |       |       | ASM   | KND   |       |       |
+ *       ---------------------------------------------------------------
+ * If a code point is valid in a particular script
+ * then that bit is turned on
+ *
+ * Unicode does not distinguish between Bengali and Assamese so we use 1 bit for
+ * to represent these languages
+ *
+ * Telugu and Kannada have same codepoints except for Vocallic_RR which we special case
+ * and combine and use 1 bit to represent these languages.
+ *
+ * TODO: It is probably easier to understand and maintain to change this
+ * to use uint16_t and give each of the 9 Unicode/script blocks its own bit.
+ */
+
+static const uint8_t validityTable[128] = {
+/* This state table is tool generated please do not edit unless you know exactly what you are doing */
+/* Note: This table was edited to mirror the Windows XP implementation */
+/*ISCII:Valid:Unicode */
+/*0xa0 : 0x00: 0x900  */ ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0xa1 : 0xb8: 0x901  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + ZERO     + ZERO     + ZERO     ,
+/*0xa2 : 0xfe: 0x902  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xa3 : 0xbf: 0x903  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0x00 : 0x00: 0x904  */ DEV_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0xa4 : 0xff: 0x905  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xa5 : 0xff: 0x906  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xa6 : 0xff: 0x907  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xa7 : 0xff: 0x908  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xa8 : 0xff: 0x909  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xa9 : 0xff: 0x90a  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xaa : 0xfe: 0x90b  */ DEV_MASK + ZERO     + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0x00 : 0x00: 0x90c  */ DEV_MASK + ZERO     + ZERO     + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0xae : 0x80: 0x90d  */ DEV_MASK + ZERO     + GJR_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0xab : 0x87: 0x90e  */ DEV_MASK + ZERO     + ZERO     + ZERO     + ZERO     + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xac : 0xff: 0x90f  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xad : 0xff: 0x910  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xb2 : 0x80: 0x911  */ DEV_MASK + ZERO     + GJR_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0xaf : 0x87: 0x912  */ DEV_MASK + ZERO     + ZERO     + ZERO     + ZERO     + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xb0 : 0xff: 0x913  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xb1 : 0xff: 0x914  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xb3 : 0xff: 0x915  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xb4 : 0xfe: 0x916  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0xb5 : 0xfe: 0x917  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0xb6 : 0xfe: 0x918  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0xb7 : 0xff: 0x919  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xb8 : 0xff: 0x91a  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xb9 : 0xfe: 0x91b  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0xba : 0xff: 0x91c  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xbb : 0xfe: 0x91d  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0xbc : 0xff: 0x91e  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xbd : 0xff: 0x91f  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xbe : 0xfe: 0x920  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0xbf : 0xfe: 0x921  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0xc0 : 0xfe: 0x922  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0xc1 : 0xff: 0x923  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xc2 : 0xff: 0x924  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xc3 : 0xfe: 0x925  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0xc4 : 0xfe: 0x926  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0xc5 : 0xfe: 0x927  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0xc6 : 0xff: 0x928  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xc7 : 0x81: 0x929  */ DEV_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + TML_MASK ,
+/*0xc8 : 0xff: 0x92a  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xc9 : 0xfe: 0x92b  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0xca : 0xfe: 0x92c  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0xcb : 0xfe: 0x92d  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0xcc : 0xfe: 0x92e  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xcd : 0xff: 0x92f  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xcf : 0xff: 0x930  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xd0 : 0x87: 0x931  */ DEV_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + MLM_MASK + TML_MASK ,
+/*0xd1 : 0xff: 0x932  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xd2 : 0xb7: 0x933  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + ZERO     + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xd3 : 0x83: 0x934  */ DEV_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + MLM_MASK + TML_MASK ,
+/*0xd4 : 0xff: 0x935  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + ZERO     + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xd5 : 0xfe: 0x936  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0xd6 : 0xbf: 0x937  */ DEV_MASK + ZERO     + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xd7 : 0xff: 0x938  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xd8 : 0xff: 0x939  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0x00 : 0x00: 0x93A  */ ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0x00 : 0x00: 0x93B  */ ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0xe9 : 0xda: 0x93c  */ DEV_MASK + PNJ_MASK + ZERO     + ORI_MASK + BNG_MASK + ZERO     + ZERO     + ZERO     ,
+/*0x00 : 0x00: 0x93d  */ DEV_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0xda : 0xff: 0x93e  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xdb : 0xff: 0x93f  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xdc : 0xff: 0x940  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xdd : 0xff: 0x941  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xde : 0xff: 0x942  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xdf : 0xbe: 0x943  */ DEV_MASK + ZERO     + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0x00 : 0x00: 0x944  */ DEV_MASK + ZERO     + GJR_MASK + ZERO     + BNG_MASK + KND_MASK + ZERO     + ZERO     ,
+/*0xe3 : 0x80: 0x945  */ DEV_MASK + ZERO     + GJR_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0xe0 : 0x87: 0x946  */ DEV_MASK + ZERO     + ZERO     + ZERO     + ZERO     + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xe1 : 0xff: 0x947  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xe2 : 0xff: 0x948  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xe7 : 0x80: 0x949  */ DEV_MASK + ZERO     + GJR_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0xe4 : 0x87: 0x94a  */ DEV_MASK + ZERO     + ZERO     + ZERO     + ZERO     + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xe5 : 0xff: 0x94b  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xe6 : 0xff: 0x94c  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xe8 : 0xff: 0x94d  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xec : 0x00: 0x94e  */ ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0xed : 0x00: 0x94f  */ ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0x00 : 0x00: 0x950  */ DEV_MASK + ZERO     + GJR_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0x00 : 0x00: 0x951  */ DEV_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0x00 : 0x00: 0x952  */ DEV_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0x00 : 0x00: 0x953  */ DEV_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0x00 : 0x00: 0x954  */ DEV_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0x00 : 0x00: 0x955  */ ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + KND_MASK + ZERO     + ZERO     ,
+/*0x00 : 0x00: 0x956  */ ZERO     + ZERO     + ZERO     + ORI_MASK + ZERO     + KND_MASK + ZERO     + ZERO     ,
+/*0x00 : 0x00: 0x957  */ ZERO     + ZERO     + ZERO     + ORI_MASK + BNG_MASK + ZERO     + MLM_MASK + ZERO     ,
+/*0x00 : 0x00: 0x958  */ DEV_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0x00 : 0x00: 0x959  */ DEV_MASK + PNJ_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0x00 : 0x00: 0x95a  */ DEV_MASK + PNJ_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0x00 : 0x00: 0x95b  */ DEV_MASK + PNJ_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0x00 : 0x00: 0x95c  */ DEV_MASK + PNJ_MASK + ZERO     + ZERO     + BNG_MASK + ZERO     + ZERO     + ZERO     ,
+/*0x00 : 0x00: 0x95d  */ DEV_MASK + ZERO     + ZERO     + ORI_MASK + BNG_MASK + ZERO     + ZERO     + ZERO     ,
+/*0x00 : 0x00: 0x95e  */ DEV_MASK + PNJ_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0xce : 0x98: 0x95f  */ DEV_MASK + ZERO     + ZERO     + ORI_MASK + BNG_MASK + ZERO     + ZERO     + ZERO     ,
+/*0x00 : 0x00: 0x960  */ DEV_MASK + ZERO     + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0x00 : 0x00: 0x961  */ DEV_MASK + ZERO     + ZERO     + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + ZERO     ,
+/*0x00 : 0x00: 0x962  */ DEV_MASK + ZERO     + ZERO     + ZERO     + BNG_MASK + ZERO     + ZERO     + ZERO     ,
+/*0x00 : 0x00: 0x963  */ DEV_MASK + ZERO     + ZERO     + ZERO     + BNG_MASK + ZERO     + ZERO     + ZERO     ,
+/*0xea : 0xf8: 0x964  */ DEV_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0xeaea : 0x00: 0x965*/ DEV_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*0xf1 : 0xff: 0x966  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xf2 : 0xff: 0x967  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xf3 : 0xff: 0x968  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xf4 : 0xff: 0x969  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xf5 : 0xff: 0x96a  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xf6 : 0xff: 0x96b  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xf7 : 0xff: 0x96c  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xf8 : 0xff: 0x96d  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xf9 : 0xff: 0x96e  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0xfa : 0xff: 0x96f  */ DEV_MASK + PNJ_MASK + GJR_MASK + ORI_MASK + BNG_MASK + KND_MASK + MLM_MASK + TML_MASK ,
+/*0x00 : 0x80: 0x970  */ DEV_MASK + PNJ_MASK + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     ,
+/*
+ * The length of the array is 128 to provide values for 0x900..0x97f.
+ * The last 15 entries for 0x971..0x97f of the validity table are all zero
+ * because no Indic script uses such Unicode code points.
+ */
+/*0x00 : 0x00: 0x9yz  */ ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO     + ZERO
+};
+
+static const uint16_t fromUnicodeTable[128]={
+    0x00a0 ,/* 0x0900 */
+    0x00a1 ,/* 0x0901 */
+    0x00a2 ,/* 0x0902 */
+    0x00a3 ,/* 0x0903 */
+    0xa4e0 ,/* 0x0904 */
+    0x00a4 ,/* 0x0905 */
+    0x00a5 ,/* 0x0906 */
+    0x00a6 ,/* 0x0907 */
+    0x00a7 ,/* 0x0908 */
+    0x00a8 ,/* 0x0909 */
+    0x00a9 ,/* 0x090a */
+    0x00aa ,/* 0x090b */
+    0xA6E9 ,/* 0x090c */
+    0x00ae ,/* 0x090d */
+    0x00ab ,/* 0x090e */
+    0x00ac ,/* 0x090f */
+    0x00ad ,/* 0x0910 */
+    0x00b2 ,/* 0x0911 */
+    0x00af ,/* 0x0912 */
+    0x00b0 ,/* 0x0913 */
+    0x00b1 ,/* 0x0914 */
+    0x00b3 ,/* 0x0915 */
+    0x00b4 ,/* 0x0916 */
+    0x00b5 ,/* 0x0917 */
+    0x00b6 ,/* 0x0918 */
+    0x00b7 ,/* 0x0919 */
+    0x00b8 ,/* 0x091a */
+    0x00b9 ,/* 0x091b */
+    0x00ba ,/* 0x091c */
+    0x00bb ,/* 0x091d */
+    0x00bc ,/* 0x091e */
+    0x00bd ,/* 0x091f */
+    0x00be ,/* 0x0920 */
+    0x00bf ,/* 0x0921 */
+    0x00c0 ,/* 0x0922 */
+    0x00c1 ,/* 0x0923 */
+    0x00c2 ,/* 0x0924 */
+    0x00c3 ,/* 0x0925 */
+    0x00c4 ,/* 0x0926 */
+    0x00c5 ,/* 0x0927 */
+    0x00c6 ,/* 0x0928 */
+    0x00c7 ,/* 0x0929 */
+    0x00c8 ,/* 0x092a */
+    0x00c9 ,/* 0x092b */
+    0x00ca ,/* 0x092c */
+    0x00cb ,/* 0x092d */
+    0x00cc ,/* 0x092e */
+    0x00cd ,/* 0x092f */
+    0x00cf ,/* 0x0930 */
+    0x00d0 ,/* 0x0931 */
+    0x00d1 ,/* 0x0932 */
+    0x00d2 ,/* 0x0933 */
+    0x00d3 ,/* 0x0934 */
+    0x00d4 ,/* 0x0935 */
+    0x00d5 ,/* 0x0936 */
+    0x00d6 ,/* 0x0937 */
+    0x00d7 ,/* 0x0938 */
+    0x00d8 ,/* 0x0939 */
+    0xFFFF ,/* 0x093A */
+    0xFFFF ,/* 0x093B */
+    0x00e9 ,/* 0x093c */
+    0xEAE9 ,/* 0x093d */
+    0x00da ,/* 0x093e */
+    0x00db ,/* 0x093f */
+    0x00dc ,/* 0x0940 */
+    0x00dd ,/* 0x0941 */
+    0x00de ,/* 0x0942 */
+    0x00df ,/* 0x0943 */
+    0xDFE9 ,/* 0x0944 */
+    0x00e3 ,/* 0x0945 */
+    0x00e0 ,/* 0x0946 */
+    0x00e1 ,/* 0x0947 */
+    0x00e2 ,/* 0x0948 */
+    0x00e7 ,/* 0x0949 */
+    0x00e4 ,/* 0x094a */
+    0x00e5 ,/* 0x094b */
+    0x00e6 ,/* 0x094c */
+    0x00e8 ,/* 0x094d */
+    0x00ec ,/* 0x094e */
+    0x00ed ,/* 0x094f */
+    0xA1E9 ,/* 0x0950 */ /* OM Symbol */
+    0xFFFF ,/* 0x0951 */
+    0xF0B8 ,/* 0x0952 */
+    0xFFFF ,/* 0x0953 */
+    0xFFFF ,/* 0x0954 */
+    0xFFFF ,/* 0x0955 */
+    0xFFFF ,/* 0x0956 */
+    0xFFFF ,/* 0x0957 */
+    0xb3e9 ,/* 0x0958 */
+    0xb4e9 ,/* 0x0959 */
+    0xb5e9 ,/* 0x095a */
+    0xbae9 ,/* 0x095b */
+    0xbfe9 ,/* 0x095c */
+    0xC0E9 ,/* 0x095d */
+    0xc9e9 ,/* 0x095e */
+    0x00ce ,/* 0x095f */
+    0xAAe9 ,/* 0x0960 */
+    0xA7E9 ,/* 0x0961 */
+    0xDBE9 ,/* 0x0962 */
+    0xDCE9 ,/* 0x0963 */
+    0x00ea ,/* 0x0964 */
+    0xeaea ,/* 0x0965 */
+    0x00f1 ,/* 0x0966 */
+    0x00f2 ,/* 0x0967 */
+    0x00f3 ,/* 0x0968 */
+    0x00f4 ,/* 0x0969 */
+    0x00f5 ,/* 0x096a */
+    0x00f6 ,/* 0x096b */
+    0x00f7 ,/* 0x096c */
+    0x00f8 ,/* 0x096d */
+    0x00f9 ,/* 0x096e */
+    0x00fa ,/* 0x096f */
+    0xF0BF ,/* 0x0970 */
+    0xFFFF ,/* 0x0971 */
+    0xFFFF ,/* 0x0972 */
+    0xFFFF ,/* 0x0973 */
+    0xFFFF ,/* 0x0974 */
+    0xFFFF ,/* 0x0975 */
+    0xFFFF ,/* 0x0976 */
+    0xFFFF ,/* 0x0977 */
+    0xFFFF ,/* 0x0978 */
+    0xFFFF ,/* 0x0979 */
+    0xFFFF ,/* 0x097a */
+    0xFFFF ,/* 0x097b */
+    0xFFFF ,/* 0x097c */
+    0xFFFF ,/* 0x097d */
+    0xFFFF ,/* 0x097e */
+    0xFFFF ,/* 0x097f */
+};
+static const uint16_t toUnicodeTable[256]={
+    0x0000,/* 0x00 */
+    0x0001,/* 0x01 */
+    0x0002,/* 0x02 */
+    0x0003,/* 0x03 */
+    0x0004,/* 0x04 */
+    0x0005,/* 0x05 */
+    0x0006,/* 0x06 */
+    0x0007,/* 0x07 */
+    0x0008,/* 0x08 */
+    0x0009,/* 0x09 */
+    0x000a,/* 0x0a */
+    0x000b,/* 0x0b */
+    0x000c,/* 0x0c */
+    0x000d,/* 0x0d */
+    0x000e,/* 0x0e */
+    0x000f,/* 0x0f */
+    0x0010,/* 0x10 */
+    0x0011,/* 0x11 */
+    0x0012,/* 0x12 */
+    0x0013,/* 0x13 */
+    0x0014,/* 0x14 */
+    0x0015,/* 0x15 */
+    0x0016,/* 0x16 */
+    0x0017,/* 0x17 */
+    0x0018,/* 0x18 */
+    0x0019,/* 0x19 */
+    0x001a,/* 0x1a */
+    0x001b,/* 0x1b */
+    0x001c,/* 0x1c */
+    0x001d,/* 0x1d */
+    0x001e,/* 0x1e */
+    0x001f,/* 0x1f */
+    0x0020,/* 0x20 */
+    0x0021,/* 0x21 */
+    0x0022,/* 0x22 */
+    0x0023,/* 0x23 */
+    0x0024,/* 0x24 */
+    0x0025,/* 0x25 */
+    0x0026,/* 0x26 */
+    0x0027,/* 0x27 */
+    0x0028,/* 0x28 */
+    0x0029,/* 0x29 */
+    0x002a,/* 0x2a */
+    0x002b,/* 0x2b */
+    0x002c,/* 0x2c */
+    0x002d,/* 0x2d */
+    0x002e,/* 0x2e */
+    0x002f,/* 0x2f */
+    0x0030,/* 0x30 */
+    0x0031,/* 0x31 */
+    0x0032,/* 0x32 */
+    0x0033,/* 0x33 */
+    0x0034,/* 0x34 */
+    0x0035,/* 0x35 */
+    0x0036,/* 0x36 */
+    0x0037,/* 0x37 */
+    0x0038,/* 0x38 */
+    0x0039,/* 0x39 */
+    0x003A,/* 0x3A */
+    0x003B,/* 0x3B */
+    0x003c,/* 0x3c */
+    0x003d,/* 0x3d */
+    0x003e,/* 0x3e */
+    0x003f,/* 0x3f */
+    0x0040,/* 0x40 */
+    0x0041,/* 0x41 */
+    0x0042,/* 0x42 */
+    0x0043,/* 0x43 */
+    0x0044,/* 0x44 */
+    0x0045,/* 0x45 */
+    0x0046,/* 0x46 */
+    0x0047,/* 0x47 */
+    0x0048,/* 0x48 */
+    0x0049,/* 0x49 */
+    0x004a,/* 0x4a */
+    0x004b,/* 0x4b */
+    0x004c,/* 0x4c */
+    0x004d,/* 0x4d */
+    0x004e,/* 0x4e */
+    0x004f,/* 0x4f */
+    0x0050,/* 0x50 */
+    0x0051,/* 0x51 */
+    0x0052,/* 0x52 */
+    0x0053,/* 0x53 */
+    0x0054,/* 0x54 */
+    0x0055,/* 0x55 */
+    0x0056,/* 0x56 */
+    0x0057,/* 0x57 */
+    0x0058,/* 0x58 */
+    0x0059,/* 0x59 */
+    0x005a,/* 0x5a */
+    0x005b,/* 0x5b */
+    0x005c,/* 0x5c */
+    0x005d,/* 0x5d */
+    0x005e,/* 0x5e */
+    0x005f,/* 0x5f */
+    0x0060,/* 0x60 */
+    0x0061,/* 0x61 */
+    0x0062,/* 0x62 */
+    0x0063,/* 0x63 */
+    0x0064,/* 0x64 */
+    0x0065,/* 0x65 */
+    0x0066,/* 0x66 */
+    0x0067,/* 0x67 */
+    0x0068,/* 0x68 */
+    0x0069,/* 0x69 */
+    0x006a,/* 0x6a */
+    0x006b,/* 0x6b */
+    0x006c,/* 0x6c */
+    0x006d,/* 0x6d */
+    0x006e,/* 0x6e */
+    0x006f,/* 0x6f */
+    0x0070,/* 0x70 */
+    0x0071,/* 0x71 */
+    0x0072,/* 0x72 */
+    0x0073,/* 0x73 */
+    0x0074,/* 0x74 */
+    0x0075,/* 0x75 */
+    0x0076,/* 0x76 */
+    0x0077,/* 0x77 */
+    0x0078,/* 0x78 */
+    0x0079,/* 0x79 */
+    0x007a,/* 0x7a */
+    0x007b,/* 0x7b */
+    0x007c,/* 0x7c */
+    0x007d,/* 0x7d */
+    0x007e,/* 0x7e */
+    0x007f,/* 0x7f */
+    0x0080,/* 0x80 */
+    0x0081,/* 0x81 */
+    0x0082,/* 0x82 */
+    0x0083,/* 0x83 */
+    0x0084,/* 0x84 */
+    0x0085,/* 0x85 */
+    0x0086,/* 0x86 */
+    0x0087,/* 0x87 */
+    0x0088,/* 0x88 */
+    0x0089,/* 0x89 */
+    0x008a,/* 0x8a */
+    0x008b,/* 0x8b */
+    0x008c,/* 0x8c */
+    0x008d,/* 0x8d */
+    0x008e,/* 0x8e */
+    0x008f,/* 0x8f */
+    0x0090,/* 0x90 */
+    0x0091,/* 0x91 */
+    0x0092,/* 0x92 */
+    0x0093,/* 0x93 */
+    0x0094,/* 0x94 */
+    0x0095,/* 0x95 */
+    0x0096,/* 0x96 */
+    0x0097,/* 0x97 */
+    0x0098,/* 0x98 */
+    0x0099,/* 0x99 */
+    0x009a,/* 0x9a */
+    0x009b,/* 0x9b */
+    0x009c,/* 0x9c */
+    0x009d,/* 0x9d */
+    0x009e,/* 0x9e */
+    0x009f,/* 0x9f */
+    0x00A0,/* 0xa0 */
+    0x0901,/* 0xa1 */
+    0x0902,/* 0xa2 */
+    0x0903,/* 0xa3 */
+    0x0905,/* 0xa4 */
+    0x0906,/* 0xa5 */
+    0x0907,/* 0xa6 */
+    0x0908,/* 0xa7 */
+    0x0909,/* 0xa8 */
+    0x090a,/* 0xa9 */
+    0x090b,/* 0xaa */
+    0x090e,/* 0xab */
+    0x090f,/* 0xac */
+    0x0910,/* 0xad */
+    0x090d,/* 0xae */
+    0x0912,/* 0xaf */
+    0x0913,/* 0xb0 */
+    0x0914,/* 0xb1 */
+    0x0911,/* 0xb2 */
+    0x0915,/* 0xb3 */
+    0x0916,/* 0xb4 */
+    0x0917,/* 0xb5 */
+    0x0918,/* 0xb6 */
+    0x0919,/* 0xb7 */
+    0x091a,/* 0xb8 */
+    0x091b,/* 0xb9 */
+    0x091c,/* 0xba */
+    0x091d,/* 0xbb */
+    0x091e,/* 0xbc */
+    0x091f,/* 0xbd */
+    0x0920,/* 0xbe */
+    0x0921,/* 0xbf */
+    0x0922,/* 0xc0 */
+    0x0923,/* 0xc1 */
+    0x0924,/* 0xc2 */
+    0x0925,/* 0xc3 */
+    0x0926,/* 0xc4 */
+    0x0927,/* 0xc5 */
+    0x0928,/* 0xc6 */
+    0x0929,/* 0xc7 */
+    0x092a,/* 0xc8 */
+    0x092b,/* 0xc9 */
+    0x092c,/* 0xca */
+    0x092d,/* 0xcb */
+    0x092e,/* 0xcc */
+    0x092f,/* 0xcd */
+    0x095f,/* 0xce */
+    0x0930,/* 0xcf */
+    0x0931,/* 0xd0 */
+    0x0932,/* 0xd1 */
+    0x0933,/* 0xd2 */
+    0x0934,/* 0xd3 */
+    0x0935,/* 0xd4 */
+    0x0936,/* 0xd5 */
+    0x0937,/* 0xd6 */
+    0x0938,/* 0xd7 */
+    0x0939,/* 0xd8 */
+    0x200D,/* 0xd9 */
+    0x093e,/* 0xda */
+    0x093f,/* 0xdb */
+    0x0940,/* 0xdc */
+    0x0941,/* 0xdd */
+    0x0942,/* 0xde */
+    0x0943,/* 0xdf */
+    0x0946,/* 0xe0 */
+    0x0947,/* 0xe1 */
+    0x0948,/* 0xe2 */
+    0x0945,/* 0xe3 */
+    0x094a,/* 0xe4 */
+    0x094b,/* 0xe5 */
+    0x094c,/* 0xe6 */
+    0x0949,/* 0xe7 */
+    0x094d,/* 0xe8 */
+    0x093c,/* 0xe9 */
+    0x0964,/* 0xea */
+    0xFFFF,/* 0xeb */
+    0xFFFF,/* 0xec */
+    0xFFFF,/* 0xed */
+    0xFFFF,/* 0xee */
+    0xFFFF,/* 0xef */
+    0xFFFF,/* 0xf0 */
+    0x0966,/* 0xf1 */
+    0x0967,/* 0xf2 */
+    0x0968,/* 0xf3 */
+    0x0969,/* 0xf4 */
+    0x096a,/* 0xf5 */
+    0x096b,/* 0xf6 */
+    0x096c,/* 0xf7 */
+    0x096d,/* 0xf8 */
+    0x096e,/* 0xf9 */
+    0x096f,/* 0xfa */
+    0xFFFF,/* 0xfb */
+    0xFFFF,/* 0xfc */
+    0xFFFF,/* 0xfd */
+    0xFFFF,/* 0xfe */
+    0xFFFF /* 0xff */
+};
+
+static const uint16_t vowelSignESpecialCases[][2]={
+	{ 2 /*length of array*/    , 0      },
+	{ 0xA4 , 0x0904 },
+};
+
+static const uint16_t nuktaSpecialCases[][2]={
+    { 16 /*length of array*/   , 0      },
+    { 0xA6 , 0x090c },
+    { 0xEA , 0x093D },
+    { 0xDF , 0x0944 },
+    { 0xA1 , 0x0950 },
+    { 0xb3 , 0x0958 },
+    { 0xb4 , 0x0959 },
+    { 0xb5 , 0x095a },
+    { 0xba , 0x095b },
+    { 0xbf , 0x095c },
+    { 0xC0 , 0x095d },
+    { 0xc9 , 0x095e },
+    { 0xAA , 0x0960 },
+    { 0xA7 , 0x0961 },
+    { 0xDB , 0x0962 },
+    { 0xDC , 0x0963 },
+};
+
+
+#define WRITE_TO_TARGET_FROM_U(args,offsets,source,target,targetLimit,targetByteUnit,err){      \
+    int32_t offset = (int32_t)(source - args->source-1);                                        \
+      /* write the targetUniChar  to target */                                                  \
+    if(target < targetLimit){                                                                   \
+        if(targetByteUnit <= 0xFF){                                                             \
+            *(target)++ = (uint8_t)(targetByteUnit);                                            \
+            if(offsets){                                                                        \
+                *(offsets++) = offset;                                                          \
+            }                                                                                   \
+        }else{                                                                                  \
+            if (targetByteUnit > 0xFFFF) {                                                      \
+                *(target)++ = (uint8_t)(targetByteUnit>>16);                                    \
+                if (offsets) {                                                                  \
+                    --offset;                                                                   \
+                    *(offsets++) = offset;                                                      \
+                }                                                                               \
+            }                                                                                   \
+            if (!(target < targetLimit)) {                                                      \
+                args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] =    \
+                                (uint8_t)(targetByteUnit >> 8);                                 \
+                args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] =    \
+                                (uint8_t)targetByteUnit;                                        \
+                *err = U_BUFFER_OVERFLOW_ERROR;                                                 \
+            } else {                                                                            \
+                *(target)++ = (uint8_t)(targetByteUnit>>8);                                     \
+                if(offsets){                                                                    \
+                    *(offsets++) = offset;                                                      \
+                }                                                                               \
+                if(target < targetLimit){                                                       \
+                    *(target)++ = (uint8_t)  targetByteUnit;                                    \
+                    if(offsets){                                                                \
+                        *(offsets++) = offset                            ;                      \
+                    }                                                                           \
+                }else{                                                                          \
+                    args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] =\
+                                (uint8_t) (targetByteUnit);                                     \
+                    *err = U_BUFFER_OVERFLOW_ERROR;                                             \
+                }                                                                               \
+            }                                                                                   \
+        }                                                                                       \
+    }else{                                                                                      \
+        if (targetByteUnit & 0xFF0000) {                                                        \
+            args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] =        \
+                        (uint8_t) (targetByteUnit >>16);                                        \
+        }                                                                                       \
+        if(targetByteUnit & 0xFF00){                                                            \
+            args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] =        \
+                        (uint8_t) (targetByteUnit >>8);                                         \
+        }                                                                                       \
+        args->converter->charErrorBuffer[args->converter->charErrorBufferLength++] =            \
+                        (uint8_t) (targetByteUnit);                                             \
+        *err = U_BUFFER_OVERFLOW_ERROR;                                                         \
+    }                                                                                           \
+}
+
+/* Rules:
+ *    Explicit Halant :
+ *                      <HALANT> + <ZWNJ>
+ *    Soft Halant :
+ *                      <HALANT> + <ZWJ>
+ */
+
+static void UConverter_fromUnicode_ISCII_OFFSETS_LOGIC(
+        UConverterFromUnicodeArgs * args, UErrorCode * err) {
+    const UChar *source = args->source;
+    const UChar *sourceLimit = args->sourceLimit;
+    unsigned char *target = (unsigned char *) args->target;
+    unsigned char *targetLimit = (unsigned char *) args->targetLimit;
+    int32_t* offsets = args->offsets;
+    uint32_t targetByteUnit = 0x0000;
+    UChar32 sourceChar = 0x0000;
+    UChar32 tempContextFromUnicode = 0x0000;    /* For special handling of the Gurmukhi script. */
+    UConverterDataISCII *converterData;
+    uint16_t newDelta=0;
+    uint16_t range = 0;
+    UBool deltaChanged = FALSE;
+
+    if ((args->converter == NULL) || (args->targetLimit < args->target) || (args->sourceLimit < args->source)) {
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    /* initialize data */
+    converterData=(UConverterDataISCII*)args->converter->extraInfo;
+    newDelta=converterData->currentDeltaFromUnicode;
+    range = (uint16_t)(newDelta/DELTA);
+
+    if ((sourceChar = args->converter->fromUChar32)!=0) {
+        goto getTrail;
+    }
+
+    /*writing the char to the output stream */
+    while (source < sourceLimit) {
+        /* Write the language code following LF only if LF is not the last character. */
+        if (args->converter->fromUnicodeStatus == LF) {
+            targetByteUnit = ATR<<8;
+            targetByteUnit += (uint8_t) lookupInitialData[range].isciiLang;
+            args->converter->fromUnicodeStatus = 0x0000;
+            /* now append ATR and language code */
+            WRITE_TO_TARGET_FROM_U(args,offsets,source,target,targetLimit,targetByteUnit,err);
+            if (U_FAILURE(*err)) {
+                break;
+            }
+        }
+        
+        sourceChar = *source++;
+        tempContextFromUnicode = converterData->contextCharFromUnicode;
+        
+        targetByteUnit = missingCharMarker;
+        
+        /*check if input is in ASCII and C0 control codes range*/
+        if (sourceChar <= ASCII_END) {
+            args->converter->fromUnicodeStatus = sourceChar;
+            WRITE_TO_TARGET_FROM_U(args,offsets,source,target,targetLimit,sourceChar,err);
+            if (U_FAILURE(*err)) {
+                break;
+            }
+            continue;
+        }
+        switch (sourceChar) {
+        case ZWNJ:
+            /* contextChar has HALANT */
+            if (converterData->contextCharFromUnicode) {
+                converterData->contextCharFromUnicode = 0x00;
+                targetByteUnit = ISCII_HALANT;
+            } else {
+                /* consume ZWNJ and continue */
+                converterData->contextCharFromUnicode = 0x00;
+                continue;
+            }
+            break;
+        case ZWJ:
+            /* contextChar has HALANT */
+            if (converterData->contextCharFromUnicode) {
+                targetByteUnit = ISCII_NUKTA;
+            } else {
+                targetByteUnit =ISCII_INV;
+            }
+            converterData->contextCharFromUnicode = 0x00;
+            break;
+        default:
+            /* is the sourceChar in the INDIC_RANGE? */
+            if ((uint16_t)(INDIC_BLOCK_END-sourceChar) <= INDIC_RANGE) {
+                /* Danda and Double Danda are valid in Northern scripts.. since Unicode
+                 * does not include these codepoints in all Northern scrips we need to
+                 * filter them out
+                 */
+                if (sourceChar!= DANDA && sourceChar != DOUBLE_DANDA) {
+                    /* find out to which block the souceChar belongs*/
+                    range =(uint16_t)((sourceChar-INDIC_BLOCK_BEGIN)/DELTA);
+                    newDelta =(uint16_t)(range*DELTA);
+
+                    /* Now are we in the same block as the previous? */
+                    if (newDelta!= converterData->currentDeltaFromUnicode || converterData->isFirstBuffer) {
+                        converterData->currentDeltaFromUnicode = newDelta;
+                        converterData->currentMaskFromUnicode = lookupInitialData[range].maskEnum;
+                        deltaChanged =TRUE;
+                        converterData->isFirstBuffer=FALSE;
+                    }
+                    
+                    if (converterData->currentDeltaFromUnicode == PNJ_DELTA) { 
+                        if (sourceChar == PNJ_TIPPI) {
+                            /* Make sure Tippi is converterd to Bindi. */
+                            sourceChar = PNJ_BINDI;
+                        } else if (sourceChar == PNJ_ADHAK) {
+                            /* This is for consonant cluster handling. */
+                            converterData->contextCharFromUnicode = PNJ_ADHAK;
+                        }
+                        
+                    }
+                    /* Normalize all Indic codepoints to Devanagari and map them to ISCII */
+                    /* now subtract the new delta from sourceChar*/
+                    sourceChar -= converterData->currentDeltaFromUnicode;
+                }
+
+                /* get the target byte unit */
+                targetByteUnit=fromUnicodeTable[(uint8_t)sourceChar];
+
+                /* is the code point valid in current script? */
+                if ((validityTable[(uint8_t)sourceChar] & converterData->currentMaskFromUnicode)==0) {
+                    /* Vocallic RR is assigned in ISCII Telugu and Unicode */
+                    if (converterData->currentDeltaFromUnicode!=(TELUGU_DELTA) || sourceChar!=VOCALLIC_RR) {
+                        targetByteUnit=missingCharMarker;
+                    }
+                }
+
+                if (deltaChanged) {
+                    /* we are in a script block which is different than
+                     * previous sourceChar's script block write ATR and language codes
+                     */
+                    uint32_t temp=0;
+                    temp =(uint16_t)(ATR<<8);
+                    temp += (uint16_t)((uint8_t) lookupInitialData[range].isciiLang);
+                    /* reset */
+                    deltaChanged=FALSE;
+                    /* now append ATR and language code */
+                    WRITE_TO_TARGET_FROM_U(args,offsets,source,target,targetLimit,temp,err);
+                    if (U_FAILURE(*err)) {
+                        break;
+                    }
+                }
+                
+                if (converterData->currentDeltaFromUnicode == PNJ_DELTA && (sourceChar + PNJ_DELTA) == PNJ_ADHAK) {
+                    continue;
+                }
+            }
+            /* reset context char */
+            converterData->contextCharFromUnicode = 0x00;
+            break;
+        }
+        if (converterData->currentDeltaFromUnicode == PNJ_DELTA && tempContextFromUnicode == PNJ_ADHAK && uset_contains(PNJ_CONSONANT_SET, (sourceChar + PNJ_DELTA))) {
+            /* If the previous codepoint is Adhak and the current codepoint is a consonant, the targetByteUnit should be C + Halant + C. */
+            /* reset context char */
+            converterData->contextCharFromUnicode = 0x0000;
+            targetByteUnit = targetByteUnit << 16 | ISCII_HALANT << 8 | targetByteUnit;
+            /* write targetByteUnit to target */
+            WRITE_TO_TARGET_FROM_U(args, offsets, source, target, targetLimit, targetByteUnit,err);
+            if (U_FAILURE(*err)) {
+                break;
+            }
+        } else if (targetByteUnit != missingCharMarker) {
+            if (targetByteUnit==ISCII_HALANT) {
+                converterData->contextCharFromUnicode = (UChar)targetByteUnit;
+            }
+            /* write targetByteUnit to target*/
+            WRITE_TO_TARGET_FROM_U(args,offsets,source,target,targetLimit,targetByteUnit,err);
+            if (U_FAILURE(*err)) {
+                break;
+            }
+        } else {
+            /* oops.. the code point is unassigned */
+            /*check if the char is a First surrogate*/
+            if (UTF_IS_SURROGATE(sourceChar)) {
+                if (UTF_IS_SURROGATE_FIRST(sourceChar)) {
+getTrail:
+                    /*look ahead to find the trail surrogate*/
+                    if (source < sourceLimit) {
+                        /* test the following code unit */
+                        UChar trail= (*source);
+                        if (UTF_IS_SECOND_SURROGATE(trail)) {
+                            source++;
+                            sourceChar=UTF16_GET_PAIR_VALUE(sourceChar, trail);
+                            *err =U_INVALID_CHAR_FOUND;
+                            /* convert this surrogate code point */
+                            /* exit this condition tree */
+                        } else {
+                            /* this is an unmatched lead code unit (1st surrogate) */
+                            /* callback(illegal) */
+                            *err=U_ILLEGAL_CHAR_FOUND;
+                        }
+                    } else {
+                        /* no more input */
+                        *err = U_ZERO_ERROR;
+                    }
+                } else {
+                    /* this is an unmatched trail code unit (2nd surrogate) */
+                    /* callback(illegal) */
+                    *err=U_ILLEGAL_CHAR_FOUND;
+                }
+            } else {
+                /* callback(unassigned) for a BMP code point */
+                *err = U_INVALID_CHAR_FOUND;
+            }
+
+            args->converter->fromUChar32=sourceChar;
+            break;
+        }
+    }/* end while(mySourceIndex<mySourceLength) */
+
+    /*save the state and return */
+    args->source = source;
+    args->target = (char*)target;
+}
+
+static const uint16_t lookupTable[][2]={
+    { ZERO,       ZERO     },     /*DEFALT*/
+    { ZERO,       ZERO     },     /*ROMAN*/
+    { DEVANAGARI, DEV_MASK },
+    { BENGALI,    BNG_MASK },
+    { TAMIL,      TML_MASK },
+    { TELUGU,     KND_MASK },
+    { BENGALI,    BNG_MASK },
+    { ORIYA,      ORI_MASK },
+    { KANNADA,    KND_MASK },
+    { MALAYALAM,  MLM_MASK },
+    { GUJARATI,   GJR_MASK },
+    { GURMUKHI,   PNJ_MASK }
+};
+
+#define WRITE_TO_TARGET_TO_U(args,source,target,offsets,offset,targetUniChar,delta, err){\
+    /* add offset to current Indic Block */                                              \
+    if(targetUniChar>ASCII_END &&                                                        \
+           targetUniChar != ZWJ &&                                                       \
+           targetUniChar != ZWNJ &&                                                      \
+           targetUniChar != DANDA &&                                                     \
+           targetUniChar != DOUBLE_DANDA){                                               \
+                                                                                         \
+           targetUniChar+=(uint16_t)(delta);                                             \
+    }                                                                                    \
+    /* now write the targetUniChar */                                                    \
+    if(target<args->targetLimit){                                                        \
+        *(target)++ = (UChar)targetUniChar;                                              \
+        if(offsets){                                                                     \
+            *(offsets)++ = (int32_t)(offset);                                            \
+        }                                                                                \
+    }else{                                                                               \
+        args->converter->UCharErrorBuffer[args->converter->UCharErrorBufferLength++] =   \
+            (UChar)targetUniChar;                                                        \
+        *err = U_BUFFER_OVERFLOW_ERROR;                                                  \
+    }                                                                                    \
+}
+
+#define GET_MAPPING(sourceChar,targetUniChar,data){                                      \
+    targetUniChar = toUnicodeTable[(sourceChar)] ;                                       \
+    /* is the code point valid in current script? */                                     \
+    if(sourceChar> ASCII_END &&                                                          \
+            (validityTable[(uint8_t)targetUniChar] & data->currentMaskToUnicode)==0){    \
+        /* Vocallic RR is assigne in ISCII Telugu and Unicode */                         \
+        if(data->currentDeltaToUnicode!=(TELUGU_DELTA) ||                                \
+                    targetUniChar!=VOCALLIC_RR){                                         \
+            targetUniChar=missingCharMarker;                                             \
+        }                                                                                \
+    }                                                                                    \
+}
+
+/***********
+ *  Rules for ISCII to Unicode converter
+ *  ISCII is stateful encoding. To convert ISCII bytes to Unicode,
+ *  which has both precomposed and decomposed forms characters
+ *  pre-context and post-context need to be considered.
+ *
+ *  Post context
+ *  i)  ATR : Attribute code is used to declare the font and script switching.
+ *      Currently we only switch scripts and font codes consumed without generating an error
+ *  ii) EXT : Extention code is used to declare switching to Sanskrit and for obscure,
+ *      obsolete characters
+ *  Pre context
+ *  i)  Halant: if preceeded by a halant then it is a explicit halant
+ *  ii) Nukta :
+ *       a) if preceeded by a halant then it is a soft halant
+ *       b) if preceeded by specific consonants and the ligatures have pre-composed
+ *          characters in Unicode then convert to pre-composed characters
+ *  iii) Danda: If Danda is preceeded by a Danda then convert to Double Danda
+ *
+ */
+
+static void UConverter_toUnicode_ISCII_OFFSETS_LOGIC(UConverterToUnicodeArgs *args, UErrorCode* err) {
+    const char *source = ( char *) args->source;
+    UChar *target = args->target;
+    const char *sourceLimit = args->sourceLimit;
+    const UChar* targetLimit = args->targetLimit;
+    uint32_t targetUniChar = 0x0000;
+    uint8_t sourceChar = 0x0000;
+    UConverterDataISCII* data;
+    UChar32* toUnicodeStatus=NULL;
+    UChar32 tempTargetUniChar = 0x0000;
+    UChar* contextCharToUnicode= NULL;
+    UBool found;
+    int i; 
+    int offset = 0;
+
+    if ((args->converter == NULL) || (target < args->target) || (source < args->source)) {
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    data = (UConverterDataISCII*)(args->converter->extraInfo);
+    contextCharToUnicode = &data->contextCharToUnicode; /* contains previous ISCII codepoint visited */
+    toUnicodeStatus = (UChar32*)&args->converter->toUnicodeStatus;/* contains the mapping to Unicode of the above codepoint*/
+
+    while (U_SUCCESS(*err) && source<sourceLimit) {
+
+        targetUniChar = missingCharMarker;
+
+        if (target < targetLimit) {
+            sourceChar = (unsigned char)*(source)++;
+
+            /* look at the post-context preform special processing */
+            if (*contextCharToUnicode==ATR) {
+
+                /* If we have ATR in *contextCharToUnicode then we need to change our
+                 * state to the Indic Script specified by sourceChar
+                 */
+
+                /* check if the sourceChar is supported script range*/
+                if ((uint8_t)(PNJ-sourceChar)<=PNJ-DEV) {
+                    data->currentDeltaToUnicode = (uint16_t)(lookupTable[sourceChar & 0x0F][0] * DELTA);
+                    data->currentMaskToUnicode = (MaskEnum)lookupTable[sourceChar & 0x0F][1];
+                } else if (sourceChar==DEF) {
+                    /* switch back to default */
+                    data->currentDeltaToUnicode = data->defDeltaToUnicode;
+                    data->currentMaskToUnicode = data->defMaskToUnicode;
+                } else {
+                    if ((sourceChar >= 0x21 && sourceChar <= 0x3F)) {
+                        /* these are display codes consume and continue */
+                    } else {
+                        *err =U_ILLEGAL_CHAR_FOUND;
+                        /* reset */
+                        *contextCharToUnicode=NO_CHAR_MARKER;
+                        goto CALLBACK;
+                    }
+                }
+
+                /* reset */
+                *contextCharToUnicode=NO_CHAR_MARKER;
+
+                continue;
+
+            } else if (*contextCharToUnicode==EXT) {
+                /* check if sourceChar is in 0xA1-0xEE range */
+                if ((uint8_t) (EXT_RANGE_END - sourceChar) <= (EXT_RANGE_END - EXT_RANGE_BEGIN)) {
+                    /* We currently support only Anudatta and Devanagari abbreviation sign */
+                    if (sourceChar==0xBF || sourceChar == 0xB8) {
+                        targetUniChar = (sourceChar==0xBF) ? DEV_ABBR_SIGN : DEV_ANUDATTA;
+                        
+                        /* find out if the mapping is valid in this state */
+                        if (validityTable[(uint8_t)targetUniChar] & data->currentMaskToUnicode) {
+                            *contextCharToUnicode= NO_CHAR_MARKER;
+
+                            /* Write the previous toUnicodeStatus, this was delayed to handle consonant clustering for Gurmukhi script. */
+                            if (data->prevToUnicodeStatus) {
+                                WRITE_TO_TARGET_TO_U(args,source,target,args->offsets,(source-args->source -1),data->prevToUnicodeStatus,0,err);
+                                data->prevToUnicodeStatus = 0x0000;
+                            }
+                            /* write to target */
+                            WRITE_TO_TARGET_TO_U(args,source,target,args->offsets,(source-args->source -2),targetUniChar,data->currentDeltaToUnicode,err);
+
+                            continue;
+                        }
+                    }
+                    /* byte unit is unassigned */
+                    targetUniChar = missingCharMarker;
+                    *err= U_INVALID_CHAR_FOUND;
+                } else {
+                    /* only 0xA1 - 0xEE are legal after EXT char */
+                    *contextCharToUnicode= NO_CHAR_MARKER;
+                    *err = U_ILLEGAL_CHAR_FOUND;
+                }
+                goto CALLBACK;
+            } else if (*contextCharToUnicode==ISCII_INV) {
+                if (sourceChar==ISCII_HALANT) {
+                    targetUniChar = 0x0020; /* replace with space accoding to Indic FAQ */
+                } else {
+                    targetUniChar = ZWJ;
+                }
+
+                /* Write the previous toUnicodeStatus, this was delayed to handle consonant clustering for Gurmukhi script. */
+                if (data->prevToUnicodeStatus) {
+                    WRITE_TO_TARGET_TO_U(args,source,target,args->offsets,(source-args->source -1),data->prevToUnicodeStatus,0,err);
+                    data->prevToUnicodeStatus = 0x0000;
+                }
+                /* write to target */
+                WRITE_TO_TARGET_TO_U(args,source,target,args->offsets,(source-args->source -2),targetUniChar,data->currentDeltaToUnicode,err);
+                /* reset */
+                *contextCharToUnicode=NO_CHAR_MARKER;
+            }
+
+            /* look at the pre-context and perform special processing */
+            switch (sourceChar) {
+            case ISCII_INV:
+            case EXT: /*falls through*/
+            case ATR:
+                *contextCharToUnicode = (UChar)sourceChar;
+
+                if (*toUnicodeStatus != missingCharMarker) {
+                    /* Write the previous toUnicodeStatus, this was delayed to handle consonant clustering for Gurmukhi script. */
+                    if (data->prevToUnicodeStatus) {
+                        WRITE_TO_TARGET_TO_U(args,source,target,args->offsets,(source-args->source -1),data->prevToUnicodeStatus,0,err);
+                        data->prevToUnicodeStatus = 0x0000;
+                    }
+                    WRITE_TO_TARGET_TO_U(args,source,target,args->offsets,(source-args->source -2),*toUnicodeStatus,data->currentDeltaToUnicode,err);
+                    *toUnicodeStatus = missingCharMarker;
+                }
+                continue;
+            case ISCII_DANDA:
+                /* handle double danda*/
+                if (*contextCharToUnicode== ISCII_DANDA) {
+                    targetUniChar = DOUBLE_DANDA;
+                    /* clear the context */
+                    *contextCharToUnicode = NO_CHAR_MARKER;
+                    *toUnicodeStatus = missingCharMarker;
+                } else {
+                    GET_MAPPING(sourceChar,targetUniChar,data);
+                    *contextCharToUnicode = sourceChar;
+                }
+                break;
+            case ISCII_HALANT:
+                /* handle explicit halant */
+                if (*contextCharToUnicode == ISCII_HALANT) {
+                    targetUniChar = ZWNJ;
+                    /* clear the context */
+                    *contextCharToUnicode = NO_CHAR_MARKER;
+                } else {
+                    GET_MAPPING(sourceChar,targetUniChar,data);
+                    *contextCharToUnicode = sourceChar;
+                }
+                break;
+            case 0x0A:
+                /* fall through */
+            case 0x0D:
+                data->resetToDefaultToUnicode = TRUE;
+                GET_MAPPING(sourceChar,targetUniChar,data)
+                ;
+                *contextCharToUnicode = sourceChar;
+                break;
+
+            case ISCII_VOWEL_SIGN_E:
+                i=1;
+                found=FALSE;
+                for (; i<vowelSignESpecialCases[0][0]; i++) {
+                    if (vowelSignESpecialCases[i][0]==(uint8_t)*contextCharToUnicode) {
+                        targetUniChar=vowelSignESpecialCases[i][1];
+                        found=TRUE;
+                        break;
+                    }
+                }
+                if (found) {
+                    /* find out if the mapping is valid in this state */
+                    if (validityTable[(uint8_t)targetUniChar] & data->currentMaskToUnicode) {
+                        /*targetUniChar += data->currentDeltaToUnicode ;*/
+                        *contextCharToUnicode= NO_CHAR_MARKER;
+                        *toUnicodeStatus = missingCharMarker;
+                        break;
+                    }
+                }
+                GET_MAPPING(sourceChar,targetUniChar,data);
+                *contextCharToUnicode = sourceChar;
+                break;
+
+            case ISCII_NUKTA:
+                /* handle soft halant */
+                if (*contextCharToUnicode == ISCII_HALANT) {
+                    targetUniChar = ZWJ;
+                    /* clear the context */
+                    *contextCharToUnicode = NO_CHAR_MARKER;
+                    break;
+                } else if (data->currentDeltaToUnicode == PNJ_DELTA && data->contextCharToUnicode == 0xc0) {
+                    /* Write the previous toUnicodeStatus, this was delayed to handle consonant clustering for Gurmukhi script. */
+                    if (data->prevToUnicodeStatus) {
+                        WRITE_TO_TARGET_TO_U(args,source,target,args->offsets,(source-args->source -1),data->prevToUnicodeStatus,0,err);
+                        data->prevToUnicodeStatus = 0x0000;
+                    }
+                    /* We got here because ISCII_NUKTA was preceded by 0xc0 and we are converting Gurmukhi.
+                     * In that case we must convert (0xc0 0xe9) to (\u0a5c\u0a4d\u0a39).
+                     */
+                    targetUniChar = PNJ_RRA;
+                    WRITE_TO_TARGET_TO_U(args, source, target, args->offsets, (source-args->source)-2, targetUniChar, 0, err);
+                    if (U_SUCCESS(*err)) {
+                        targetUniChar = PNJ_SIGN_VIRAMA;
+                        WRITE_TO_TARGET_TO_U(args, source, target, args->offsets, (source-args->source)-2, targetUniChar, 0, err);
+                        if (U_SUCCESS(*err)) {
+                            targetUniChar = PNJ_HA;
+                            WRITE_TO_TARGET_TO_U(args, source, target, args->offsets, (source-args->source)-2, targetUniChar, 0, err);
+                        } else {
+                            args->converter->UCharErrorBuffer[args->converter->UCharErrorBufferLength++]= PNJ_HA;
+                        }
+                    } else {
+                        args->converter->UCharErrorBuffer[args->converter->UCharErrorBufferLength++]= PNJ_SIGN_VIRAMA;
+                        args->converter->UCharErrorBuffer[args->converter->UCharErrorBufferLength++]= PNJ_HA;
+                    }
+                    *toUnicodeStatus = missingCharMarker;
+                    data->contextCharToUnicode = NO_CHAR_MARKER;
+                    continue;
+                } else {
+                    /* try to handle <CHAR> + ISCII_NUKTA special mappings */
+                    i=1;
+                    found =FALSE;
+                    for (; i<nuktaSpecialCases[0][0]; i++) {
+                        if (nuktaSpecialCases[i][0]==(uint8_t)
+                                *contextCharToUnicode) {
+                            targetUniChar=nuktaSpecialCases[i][1];
+                            found =TRUE;
+                            break;
+                        }
+                    }
+                    if (found) {
+                        /* find out if the mapping is valid in this state */
+                        if (validityTable[(uint8_t)targetUniChar] & data->currentMaskToUnicode) {
+                            /*targetUniChar += data->currentDeltaToUnicode ;*/
+                            *contextCharToUnicode= NO_CHAR_MARKER;
+                            *toUnicodeStatus = missingCharMarker;
+                            if (data->currentDeltaToUnicode == PNJ_DELTA) {
+                                /* Write the previous toUnicodeStatus, this was delayed to handle consonant clustering for Gurmukhi script. */
+                                if (data->prevToUnicodeStatus) {
+                                    WRITE_TO_TARGET_TO_U(args,source,target,args->offsets,(source-args->source -1),data->prevToUnicodeStatus,0,err);
+                                    data->prevToUnicodeStatus = 0x0000;
+                                }
+                                WRITE_TO_TARGET_TO_U(args,source,target,args->offsets,(source-args->source -2),targetUniChar,data->currentDeltaToUnicode,err);
+                                continue;
+                            }
+                            break;
+                        }
+                        /* else fall through to default */
+                    }
+                    /* else fall through to default */
+                }
+            default:GET_MAPPING(sourceChar,targetUniChar,data)
+                ;
+                *contextCharToUnicode = sourceChar;
+                break;
+            }
+
+            if (*toUnicodeStatus != missingCharMarker) {
+                /* Check to make sure that consonant clusters are handled correct for Gurmukhi script. */
+                if (data->currentDeltaToUnicode == PNJ_DELTA && data->prevToUnicodeStatus != 0 && uset_contains(PNJ_CONSONANT_SET, data->prevToUnicodeStatus) &&
+                        (*toUnicodeStatus + PNJ_DELTA) == PNJ_SIGN_VIRAMA && (targetUniChar + PNJ_DELTA) == data->prevToUnicodeStatus) {
+                    /* Consonant clusters C + HALANT + C should be encoded as ADHAK + C */
+                    offset = (int)(source-args->source - 3);
+                    tempTargetUniChar = PNJ_ADHAK; /* This is necessary to avoid some compiler warnings. */
+                    WRITE_TO_TARGET_TO_U(args,source,target,args->offsets,offset,tempTargetUniChar,0,err);
+                    WRITE_TO_TARGET_TO_U(args,source,target,args->offsets,offset,data->prevToUnicodeStatus,0,err);
+                    data->prevToUnicodeStatus = 0x0000; /* reset the previous unicode code point */
+                    *toUnicodeStatus = missingCharMarker;
+                    continue;
+                } else {
+                    /* Write the previous toUnicodeStatus, this was delayed to handle consonant clustering for Gurmukhi script. */
+                    if (data->prevToUnicodeStatus) {
+                        WRITE_TO_TARGET_TO_U(args,source,target,args->offsets,(source-args->source -1),data->prevToUnicodeStatus,0,err);
+                        data->prevToUnicodeStatus = 0x0000;
+                    }
+                    /* Check to make sure that Bindi and Tippi are handled correctly for Gurmukhi script. 
+                     * If 0xA2 is preceded by a codepoint in the PNJ_BINDI_TIPPI_SET then the target codepoint should be Tippi instead of Bindi.
+                     */
+                    if (data->currentDeltaToUnicode == PNJ_DELTA && (targetUniChar + PNJ_DELTA) == PNJ_BINDI && uset_contains(PNJ_BINDI_TIPPI_SET, (*toUnicodeStatus + PNJ_DELTA))) {
+                        targetUniChar = PNJ_TIPPI - PNJ_DELTA;
+                        WRITE_TO_TARGET_TO_U(args,source,target,args->offsets,(source-args->source -2),*toUnicodeStatus,PNJ_DELTA,err);
+                    } else if (data->currentDeltaToUnicode == PNJ_DELTA && (targetUniChar + PNJ_DELTA) == PNJ_SIGN_VIRAMA && uset_contains(PNJ_CONSONANT_SET, (*toUnicodeStatus + PNJ_DELTA))) {
+                        /* Store the current toUnicodeStatus code point for later handling of consonant cluster in Gurmukhi. */
+                        data->prevToUnicodeStatus = *toUnicodeStatus + PNJ_DELTA;
+                    } else {
+                        /* write the previously mapped codepoint */
+                        WRITE_TO_TARGET_TO_U(args,source,target,args->offsets,(source-args->source -2),*toUnicodeStatus,data->currentDeltaToUnicode,err);
+                    }
+                }
+                *toUnicodeStatus = missingCharMarker;
+            }
+
+            if (targetUniChar != missingCharMarker) {
+                /* now save the targetUniChar for delayed write */
+                *toUnicodeStatus = (UChar) targetUniChar;
+                if (data->resetToDefaultToUnicode==TRUE) {
+                    data->currentDeltaToUnicode = data->defDeltaToUnicode;
+                    data->currentMaskToUnicode = data->defMaskToUnicode;
+                    data->resetToDefaultToUnicode=FALSE;
+                }
+            } else {
+
+                /* we reach here only if targetUniChar == missingCharMarker
+                 * so assign codes to reason and err
+                 */
+                *err = U_INVALID_CHAR_FOUND;
+CALLBACK:
+                args->converter->toUBytes[0] = (uint8_t) sourceChar;
+                args->converter->toULength = 1;
+                break;
+            }
+
+        } else {
+            *err =U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+    }
+
+    if (U_SUCCESS(*err) && args->flush && source == sourceLimit) {
+        /* end of the input stream */
+        UConverter *cnv = args->converter;
+
+        if (*contextCharToUnicode==ATR || *contextCharToUnicode==EXT || *contextCharToUnicode==ISCII_INV) {
+            /* set toUBytes[] */
+            cnv->toUBytes[0] = (uint8_t)*contextCharToUnicode;
+            cnv->toULength = 1;
+
+            /* avoid looping on truncated sequences */
+            *contextCharToUnicode = NO_CHAR_MARKER;
+        } else {
+            cnv->toULength = 0;
+        }
+
+        if (*toUnicodeStatus != missingCharMarker) {
+            /* output a remaining target character */
+            WRITE_TO_TARGET_TO_U(args,source,target,args->offsets,(source - args->source -1),*toUnicodeStatus,data->currentDeltaToUnicode,err);
+            *toUnicodeStatus = missingCharMarker;
+        }
+    }
+
+    args->target = target;
+    args->source = source;
+}
+
+/* structure for SafeClone calculations */
+struct cloneISCIIStruct {
+    UConverter cnv;
+    UConverterDataISCII mydata;
+};
+
+static UConverter *
+_ISCII_SafeClone(const UConverter *cnv,
+              void *stackBuffer,
+              int32_t *pBufferSize,
+              UErrorCode *status)
+{
+    struct cloneISCIIStruct * localClone;
+    int32_t bufferSizeNeeded = sizeof(struct cloneISCIIStruct);
+
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+
+    if (*pBufferSize == 0) { /* 'preflighting' request - set needed size into *pBufferSize */
+        *pBufferSize = bufferSizeNeeded;
+        return 0;
+    }
+
+    localClone = (struct cloneISCIIStruct *)stackBuffer;
+    /* ucnv.c/ucnv_safeClone() copied the main UConverter already */
+
+    uprv_memcpy(&localClone->mydata, cnv->extraInfo, sizeof(UConverterDataISCII));
+    localClone->cnv.extraInfo = &localClone->mydata;
+    localClone->cnv.isExtraLocal = TRUE;
+
+    return &localClone->cnv;
+}
+
+static void
+_ISCIIGetUnicodeSet(const UConverter *cnv,
+                    const USetAdder *sa,
+                    UConverterUnicodeSet which,
+                    UErrorCode *pErrorCode)
+{
+    int32_t idx, script;
+    uint8_t mask;
+
+    /* Since all ISCII versions allow switching to other ISCII
+    scripts, we add all roundtrippable characters to this set. */
+    sa->addRange(sa->set, 0, ASCII_END);
+    for (script = DEVANAGARI; script <= MALAYALAM; script++) {
+        mask = (uint8_t)(lookupInitialData[script].maskEnum);
+        for (idx = 0; idx < DELTA; idx++) {
+            /* added check for TELUGU character */
+            if ((validityTable[idx] & mask) || (script==TELUGU && idx==0x31)) {
+                sa->add(sa->set, idx + (script * DELTA) + INDIC_BLOCK_BEGIN);
+            }
+        }
+    }
+    sa->add(sa->set, DANDA);
+    sa->add(sa->set, DOUBLE_DANDA);
+    sa->add(sa->set, ZWNJ);
+    sa->add(sa->set, ZWJ);
+}
+
+static const UConverterImpl _ISCIIImpl={
+
+    UCNV_ISCII,
+
+    NULL,
+    NULL,
+
+    _ISCIIOpen,
+    _ISCIIClose,
+    _ISCIIReset,
+
+    UConverter_toUnicode_ISCII_OFFSETS_LOGIC,
+    UConverter_toUnicode_ISCII_OFFSETS_LOGIC,
+    UConverter_fromUnicode_ISCII_OFFSETS_LOGIC,
+    UConverter_fromUnicode_ISCII_OFFSETS_LOGIC,
+    NULL,
+
+    NULL,
+    _ISCIIgetName,
+    NULL,
+    _ISCII_SafeClone,
+    _ISCIIGetUnicodeSet
+};
+
+static const UConverterStaticData _ISCIIStaticData={
+    sizeof(UConverterStaticData),
+        "ISCII",
+         0,
+         UCNV_IBM,
+         UCNV_ISCII,
+         1,
+         4,
+        { 0x1a, 0, 0, 0 },
+        0x1,
+        FALSE,
+        FALSE,
+        0x0,
+        0x0,
+        { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* reserved */
+
+};
+
+const UConverterSharedData _ISCIIData={
+    sizeof(UConverterSharedData),
+        ~((uint32_t) 0),
+        NULL,
+        NULL,
+        &_ISCIIStaticData,
+        FALSE,
+        &_ISCIIImpl,
+        0
+};
+
+#endif /* #if !UCONFIG_NO_LEGACY_CONVERSION */
diff --git a/source/common/ucnvlat1.c b/source/common/ucnvlat1.c
new file mode 100644
index 0000000..4e682df
--- /dev/null
+++ b/source/common/ucnvlat1.c
@@ -0,0 +1,743 @@
+/* 
+**********************************************************************
+*   Copyright (C) 2000-2007, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   file name:  ucnvlat1.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2000feb07
+*   created by: Markus W. Scherer
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ucnv.h"
+#include "unicode/uset.h"
+#include "ucnv_bld.h"
+#include "ucnv_cnv.h"
+
+/* control optimizations according to the platform */
+#define LATIN1_UNROLL_FROM_UNICODE 1
+
+/* ISO 8859-1 --------------------------------------------------------------- */
+
+/* This is a table-less and callback-less version of ucnv_MBCSSingleToBMPWithOffsets(). */
+static void
+_Latin1ToUnicodeWithOffsets(UConverterToUnicodeArgs *pArgs,
+                            UErrorCode *pErrorCode) {
+    const uint8_t *source;
+    UChar *target;
+    int32_t targetCapacity, length;
+    int32_t *offsets;
+
+    int32_t sourceIndex;
+
+    /* set up the local pointers */
+    source=(const uint8_t *)pArgs->source;
+    target=pArgs->target;
+    targetCapacity=(int32_t)(pArgs->targetLimit-pArgs->target);
+    offsets=pArgs->offsets;
+
+    sourceIndex=0;
+
+    /*
+     * since the conversion here is 1:1 UChar:uint8_t, we need only one counter
+     * for the minimum of the sourceLength and targetCapacity
+     */
+    length=(int32_t)((const uint8_t *)pArgs->sourceLimit-source);
+    if(length<=targetCapacity) {
+        targetCapacity=length;
+    } else {
+        /* target will be full */
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+        length=targetCapacity;
+    }
+
+    if(targetCapacity>=8) {
+        /* This loop is unrolled for speed and improved pipelining. */
+        int32_t count, loops;
+
+        loops=count=targetCapacity>>3;
+        length=targetCapacity&=0x7;
+        do {
+            target[0]=source[0];
+            target[1]=source[1];
+            target[2]=source[2];
+            target[3]=source[3];
+            target[4]=source[4];
+            target[5]=source[5];
+            target[6]=source[6];
+            target[7]=source[7];
+            target+=8;
+            source+=8;
+        } while(--count>0);
+
+        if(offsets!=NULL) {
+            do {
+                offsets[0]=sourceIndex++;
+                offsets[1]=sourceIndex++;
+                offsets[2]=sourceIndex++;
+                offsets[3]=sourceIndex++;
+                offsets[4]=sourceIndex++;
+                offsets[5]=sourceIndex++;
+                offsets[6]=sourceIndex++;
+                offsets[7]=sourceIndex++;
+                offsets+=8;
+            } while(--loops>0);
+        }
+    }
+
+    /* conversion loop */
+    while(targetCapacity>0) {
+        *target++=*source++;
+        --targetCapacity;
+    }
+
+    /* write back the updated pointers */
+    pArgs->source=(const char *)source;
+    pArgs->target=target;
+
+    /* set offsets */
+    if(offsets!=NULL) {
+        while(length>0) {
+            *offsets++=sourceIndex++;
+            --length;
+        }
+        pArgs->offsets=offsets;
+    }
+}
+
+/* This is a table-less and callback-less version of ucnv_MBCSSingleGetNextUChar(). */
+static UChar32
+_Latin1GetNextUChar(UConverterToUnicodeArgs *pArgs,
+                    UErrorCode *pErrorCode) {
+    const uint8_t *source=(const uint8_t *)pArgs->source;
+    if(source<(const uint8_t *)pArgs->sourceLimit) {
+        pArgs->source=(const char *)(source+1);
+        return *source;
+    }
+
+    /* no output because of empty input */
+    *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+    return 0xffff;
+}
+
+/* This is a table-less version of ucnv_MBCSSingleFromBMPWithOffsets(). */
+static void
+_Latin1FromUnicodeWithOffsets(UConverterFromUnicodeArgs *pArgs,
+                              UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const UChar *source, *sourceLimit;
+    uint8_t *target, *oldTarget;
+    int32_t targetCapacity, length;
+    int32_t *offsets;
+
+    UChar32 cp;
+    UChar c, max;
+
+    int32_t sourceIndex;
+
+    /* set up the local pointers */
+    cnv=pArgs->converter;
+    source=pArgs->source;
+    sourceLimit=pArgs->sourceLimit;
+    target=oldTarget=(uint8_t *)pArgs->target;
+    targetCapacity=(int32_t)(pArgs->targetLimit-pArgs->target);
+    offsets=pArgs->offsets;
+
+    if(cnv->sharedData==&_Latin1Data) {
+        max=0xff; /* Latin-1 */
+    } else {
+        max=0x7f; /* US-ASCII */
+    }
+
+    /* get the converter state from UConverter */
+    cp=cnv->fromUChar32;
+
+    /* sourceIndex=-1 if the current character began in the previous buffer */
+    sourceIndex= cp==0 ? 0 : -1;
+
+    /*
+     * since the conversion here is 1:1 UChar:uint8_t, we need only one counter
+     * for the minimum of the sourceLength and targetCapacity
+     */
+    length=(int32_t)(sourceLimit-source);
+    if(length<targetCapacity) {
+        targetCapacity=length;
+    }
+
+    /* conversion loop */
+    if(cp!=0 && targetCapacity>0) {
+        goto getTrail;
+    }
+
+#if LATIN1_UNROLL_FROM_UNICODE
+    /* unroll the loop with the most common case */
+    if(targetCapacity>=16) {
+        int32_t count, loops;
+        UChar u, oredChars;
+
+        loops=count=targetCapacity>>4;
+        do {
+            oredChars=u=*source++;
+            *target++=(uint8_t)u;
+            oredChars|=u=*source++;
+            *target++=(uint8_t)u;
+            oredChars|=u=*source++;
+            *target++=(uint8_t)u;
+            oredChars|=u=*source++;
+            *target++=(uint8_t)u;
+            oredChars|=u=*source++;
+            *target++=(uint8_t)u;
+            oredChars|=u=*source++;
+            *target++=(uint8_t)u;
+            oredChars|=u=*source++;
+            *target++=(uint8_t)u;
+            oredChars|=u=*source++;
+            *target++=(uint8_t)u;
+            oredChars|=u=*source++;
+            *target++=(uint8_t)u;
+            oredChars|=u=*source++;
+            *target++=(uint8_t)u;
+            oredChars|=u=*source++;
+            *target++=(uint8_t)u;
+            oredChars|=u=*source++;
+            *target++=(uint8_t)u;
+            oredChars|=u=*source++;
+            *target++=(uint8_t)u;
+            oredChars|=u=*source++;
+            *target++=(uint8_t)u;
+            oredChars|=u=*source++;
+            *target++=(uint8_t)u;
+            oredChars|=u=*source++;
+            *target++=(uint8_t)u;
+
+            /* were all 16 entries really valid? */
+            if(oredChars>max) {
+                /* no, return to the first of these 16 */
+                source-=16;
+                target-=16;
+                break;
+            }
+        } while(--count>0);
+        count=loops-count;
+        targetCapacity-=16*count;
+
+        if(offsets!=NULL) {
+            oldTarget+=16*count;
+            while(count>0) {
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                --count;
+            }
+        }
+    }
+#endif
+
+    /* conversion loop */
+    c=0;
+    while(targetCapacity>0 && (c=*source++)<=max) {
+        /* convert the Unicode code point */
+        *target++=(uint8_t)c;
+        --targetCapacity;
+    }
+
+    if(c>max) {
+        cp=c;
+        if(!U_IS_SURROGATE(cp)) {
+            /* callback(unassigned) */
+        } else if(U_IS_SURROGATE_LEAD(cp)) {
+getTrail:
+            if(source<sourceLimit) {
+                /* test the following code unit */
+                UChar trail=*source;
+                if(U16_IS_TRAIL(trail)) {
+                    ++source;
+                    cp=U16_GET_SUPPLEMENTARY(cp, trail);
+                    /* this codepage does not map supplementary code points */
+                    /* callback(unassigned) */
+                } else {
+                    /* this is an unmatched lead code unit (1st surrogate) */
+                    /* callback(illegal) */
+                }
+            } else {
+                /* no more input */
+                cnv->fromUChar32=cp;
+                goto noMoreInput;
+            }
+        } else {
+            /* this is an unmatched trail code unit (2nd surrogate) */
+            /* callback(illegal) */
+        }
+
+        *pErrorCode= U_IS_SURROGATE(cp) ? U_ILLEGAL_CHAR_FOUND : U_INVALID_CHAR_FOUND;
+        cnv->fromUChar32=cp;
+    }
+noMoreInput:
+
+    /* set offsets since the start */
+    if(offsets!=NULL) {
+        size_t count=target-oldTarget;
+        while(count>0) {
+            *offsets++=sourceIndex++;
+            --count;
+        }
+    }
+
+    if(U_SUCCESS(*pErrorCode) && source<sourceLimit && target>=(uint8_t *)pArgs->targetLimit) {
+        /* target is full */
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    /* write back the updated pointers */
+    pArgs->source=source;
+    pArgs->target=(char *)target;
+    pArgs->offsets=offsets;
+}
+
+/* Convert UTF-8 to Latin-1. Adapted from ucnv_SBCSFromUTF8(). */
+static void
+ucnv_Latin1FromUTF8(UConverterFromUnicodeArgs *pFromUArgs,
+                    UConverterToUnicodeArgs *pToUArgs,
+                    UErrorCode *pErrorCode) {
+    UConverter *utf8;
+    const uint8_t *source, *sourceLimit;
+    uint8_t *target;
+    int32_t targetCapacity;
+
+    UChar32 c;
+    uint8_t b, t1;
+
+    /* set up the local pointers */
+    utf8=pToUArgs->converter;
+    source=(uint8_t *)pToUArgs->source;
+    sourceLimit=(uint8_t *)pToUArgs->sourceLimit;
+    target=(uint8_t *)pFromUArgs->target;
+    targetCapacity=(int32_t)(pFromUArgs->targetLimit-pFromUArgs->target);
+
+    /* get the converter state from the UTF-8 UConverter */
+    c=(UChar32)utf8->toUnicodeStatus;
+    if(c!=0 && source<sourceLimit) {
+        if(targetCapacity==0) {
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            return;
+        } else if(c>=0xc2 && c<=0xc3 && (t1=(uint8_t)(*source-0x80)) <= 0x3f) {
+            ++source;
+            *target++=(uint8_t)(((c&3)<<6)|t1);
+            --targetCapacity;
+
+            utf8->toUnicodeStatus=0;
+            utf8->toULength=0;
+        } else {
+            /* complicated, illegal or unmappable input: fall back to the pivoting implementation */
+            *pErrorCode=U_USING_DEFAULT_WARNING;
+            return;
+        }
+    }
+
+    /*
+     * Make sure that the last byte sequence before sourceLimit is complete
+     * or runs into a lead byte.
+     * In the conversion loop compare source with sourceLimit only once
+     * per multi-byte character.
+     * For Latin-1, adjust sourceLimit only for 1 trail byte because
+     * the conversion loop handles at most 2-byte sequences.
+     */
+    if(source<sourceLimit && U8_IS_LEAD(*(sourceLimit-1))) {
+        --sourceLimit;
+    }
+
+    /* conversion loop */
+    while(source<sourceLimit) {
+        if(targetCapacity>0) {
+            b=*source++;
+            if((int8_t)b>=0) {
+                /* convert ASCII */
+                *target++=(uint8_t)b;
+                --targetCapacity;
+            } else if( /* handle U+0080..U+00FF inline */
+                       b>=0xc2 && b<=0xc3 &&
+                       (t1=(uint8_t)(*source-0x80)) <= 0x3f
+            ) {
+                ++source;
+                *target++=(uint8_t)(((b&3)<<6)|t1);
+                --targetCapacity;
+            } else {
+                /* complicated, illegal or unmappable input: fall back to the pivoting implementation */
+                pToUArgs->source=(char *)(source-1);
+                pFromUArgs->target=(char *)target;
+                *pErrorCode=U_USING_DEFAULT_WARNING;
+                return;
+            }
+        } else {
+            /* target is full */
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+    }
+
+    /*
+     * The sourceLimit may have been adjusted before the conversion loop
+     * to stop before a truncated sequence.
+     * If so, then collect the truncated sequence now.
+     * For Latin-1, there is at most exactly one lead byte because of the
+     * smaller sourceLimit adjustment logic.
+     */
+    if(U_SUCCESS(*pErrorCode) && source<(sourceLimit=(uint8_t *)pToUArgs->sourceLimit)) {
+        utf8->toUnicodeStatus=utf8->toUBytes[0]=b=*source++;
+        utf8->toULength=1;
+        utf8->mode=utf8_countTrailBytes[b]+1;
+    }
+
+    /* write back the updated pointers */
+    pToUArgs->source=(char *)source;
+    pFromUArgs->target=(char *)target;
+}
+
+static void
+_Latin1GetUnicodeSet(const UConverter *cnv,
+                     const USetAdder *sa,
+                     UConverterUnicodeSet which,
+                     UErrorCode *pErrorCode) {
+    sa->addRange(sa->set, 0, 0xff);
+}
+
+static const UConverterImpl _Latin1Impl={
+    UCNV_LATIN_1,
+
+    NULL,
+    NULL,
+
+    NULL,
+    NULL,
+    NULL,
+
+    _Latin1ToUnicodeWithOffsets,
+    _Latin1ToUnicodeWithOffsets,
+    _Latin1FromUnicodeWithOffsets,
+    _Latin1FromUnicodeWithOffsets,
+    _Latin1GetNextUChar,
+
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    _Latin1GetUnicodeSet,
+
+    NULL,
+    ucnv_Latin1FromUTF8
+};
+
+static const UConverterStaticData _Latin1StaticData={
+    sizeof(UConverterStaticData),
+    "ISO-8859-1",
+    819, UCNV_IBM, UCNV_LATIN_1, 1, 1,
+    { 0x1a, 0, 0, 0 }, 1, FALSE, FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+
+const UConverterSharedData _Latin1Data={
+    sizeof(UConverterSharedData), ~((uint32_t) 0),
+    NULL, NULL, &_Latin1StaticData, FALSE, &_Latin1Impl, 
+    0
+};
+
+/* US-ASCII ----------------------------------------------------------------- */
+
+/* This is a table-less version of ucnv_MBCSSingleToBMPWithOffsets(). */
+static void
+_ASCIIToUnicodeWithOffsets(UConverterToUnicodeArgs *pArgs,
+                           UErrorCode *pErrorCode) {
+    const uint8_t *source, *sourceLimit;
+    UChar *target, *oldTarget;
+    int32_t targetCapacity, length;
+    int32_t *offsets;
+
+    int32_t sourceIndex;
+
+    uint8_t c;
+
+    /* set up the local pointers */
+    source=(const uint8_t *)pArgs->source;
+    sourceLimit=(const uint8_t *)pArgs->sourceLimit;
+    target=oldTarget=pArgs->target;
+    targetCapacity=(int32_t)(pArgs->targetLimit-pArgs->target);
+    offsets=pArgs->offsets;
+
+    /* sourceIndex=-1 if the current character began in the previous buffer */
+    sourceIndex=0;
+
+    /*
+     * since the conversion here is 1:1 UChar:uint8_t, we need only one counter
+     * for the minimum of the sourceLength and targetCapacity
+     */
+    length=(int32_t)(sourceLimit-source);
+    if(length<targetCapacity) {
+        targetCapacity=length;
+    }
+
+    if(targetCapacity>=8) {
+        /* This loop is unrolled for speed and improved pipelining. */
+        int32_t count, loops;
+        UChar oredChars;
+
+        loops=count=targetCapacity>>3;
+        do {
+            oredChars=target[0]=source[0];
+            oredChars|=target[1]=source[1];
+            oredChars|=target[2]=source[2];
+            oredChars|=target[3]=source[3];
+            oredChars|=target[4]=source[4];
+            oredChars|=target[5]=source[5];
+            oredChars|=target[6]=source[6];
+            oredChars|=target[7]=source[7];
+
+            /* were all 16 entries really valid? */
+            if(oredChars>0x7f) {
+                /* no, return to the first of these 16 */
+                break;
+            }
+            source+=8;
+            target+=8;
+        } while(--count>0);
+        count=loops-count;
+        targetCapacity-=count*8;
+
+        if(offsets!=NULL) {
+            oldTarget+=count*8;
+            while(count>0) {
+                offsets[0]=sourceIndex++;
+                offsets[1]=sourceIndex++;
+                offsets[2]=sourceIndex++;
+                offsets[3]=sourceIndex++;
+                offsets[4]=sourceIndex++;
+                offsets[5]=sourceIndex++;
+                offsets[6]=sourceIndex++;
+                offsets[7]=sourceIndex++;
+                offsets+=8;
+                --count;
+            }
+        }
+    }
+
+    /* conversion loop */
+    c=0;
+    while(targetCapacity>0 && (c=*source++)<=0x7f) {
+        *target++=c;
+        --targetCapacity;
+    }
+
+    if(c>0x7f) {
+        /* callback(illegal); copy the current bytes to toUBytes[] */
+        UConverter *cnv=pArgs->converter;
+        cnv->toUBytes[0]=c;
+        cnv->toULength=1;
+        *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+    } else if(source<sourceLimit && target>=pArgs->targetLimit) {
+        /* target is full */
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    /* set offsets since the start */
+    if(offsets!=NULL) {
+        size_t count=target-oldTarget;
+        while(count>0) {
+            *offsets++=sourceIndex++;
+            --count;
+        }
+    }
+
+    /* write back the updated pointers */
+    pArgs->source=(const char *)source;
+    pArgs->target=target;
+    pArgs->offsets=offsets;
+}
+
+/* This is a table-less version of ucnv_MBCSSingleGetNextUChar(). */
+static UChar32
+_ASCIIGetNextUChar(UConverterToUnicodeArgs *pArgs,
+                   UErrorCode *pErrorCode) {
+    const uint8_t *source;
+    uint8_t b;
+
+    source=(const uint8_t *)pArgs->source;
+    if(source<(const uint8_t *)pArgs->sourceLimit) {
+        b=*source++;
+        pArgs->source=(const char *)source;
+        if(b<=0x7f) {
+            return b;
+        } else {
+            UConverter *cnv=pArgs->converter;
+            cnv->toUBytes[0]=b;
+            cnv->toULength=1;
+            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+            return 0xffff;
+        }
+    }
+
+    /* no output because of empty input */
+    *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+    return 0xffff;
+}
+
+/* "Convert" UTF-8 to US-ASCII: Validate and copy. */
+static void
+ucnv_ASCIIFromUTF8(UConverterFromUnicodeArgs *pFromUArgs,
+                   UConverterToUnicodeArgs *pToUArgs,
+                   UErrorCode *pErrorCode) {
+    const uint8_t *source, *sourceLimit;
+    uint8_t *target;
+    int32_t targetCapacity, length;
+
+    uint8_t c;
+
+    if(pToUArgs->converter->toUnicodeStatus!=0) {
+        /* no handling of partial UTF-8 characters here, fall back to pivoting */
+        *pErrorCode=U_USING_DEFAULT_WARNING;
+        return;
+    }
+
+    /* set up the local pointers */
+    source=(const uint8_t *)pToUArgs->source;
+    sourceLimit=(const uint8_t *)pToUArgs->sourceLimit;
+    target=(uint8_t *)pFromUArgs->target;
+    targetCapacity=(int32_t)(pFromUArgs->targetLimit-pFromUArgs->target);
+
+    /*
+     * since the conversion here is 1:1 uint8_t:uint8_t, we need only one counter
+     * for the minimum of the sourceLength and targetCapacity
+     */
+    length=(int32_t)(sourceLimit-source);
+    if(length<targetCapacity) {
+        targetCapacity=length;
+    }
+
+    /* unroll the loop with the most common case */
+    if(targetCapacity>=16) {
+        int32_t count, loops;
+        uint8_t oredChars;
+
+        loops=count=targetCapacity>>4;
+        do {
+            oredChars=*target++=*source++;
+            oredChars|=*target++=*source++;
+            oredChars|=*target++=*source++;
+            oredChars|=*target++=*source++;
+            oredChars|=*target++=*source++;
+            oredChars|=*target++=*source++;
+            oredChars|=*target++=*source++;
+            oredChars|=*target++=*source++;
+            oredChars|=*target++=*source++;
+            oredChars|=*target++=*source++;
+            oredChars|=*target++=*source++;
+            oredChars|=*target++=*source++;
+            oredChars|=*target++=*source++;
+            oredChars|=*target++=*source++;
+            oredChars|=*target++=*source++;
+            oredChars|=*target++=*source++;
+
+            /* were all 16 entries really valid? */
+            if(oredChars>0x7f) {
+                /* no, return to the first of these 16 */
+                source-=16;
+                target-=16;
+                break;
+            }
+        } while(--count>0);
+        count=loops-count;
+        targetCapacity-=16*count;
+    }
+
+    /* conversion loop */
+    c=0;
+    while(targetCapacity>0 && (c=*source)<=0x7f) {
+        ++source;
+        *target++=c;
+        --targetCapacity;
+    }
+
+    if(c>0x7f) {
+        /* non-ASCII character, handle in standard converter */
+        *pErrorCode=U_USING_DEFAULT_WARNING;
+    } else if(source<sourceLimit && target>=(const uint8_t *)pFromUArgs->targetLimit) {
+        /* target is full */
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    /* write back the updated pointers */
+    pToUArgs->source=(const char *)source;
+    pFromUArgs->target=(char *)target;
+}
+
+static void
+_ASCIIGetUnicodeSet(const UConverter *cnv,
+                    const USetAdder *sa,
+                    UConverterUnicodeSet which,
+                    UErrorCode *pErrorCode) {
+    sa->addRange(sa->set, 0, 0x7f);
+}
+
+static const UConverterImpl _ASCIIImpl={
+    UCNV_US_ASCII,
+
+    NULL,
+    NULL,
+
+    NULL,
+    NULL,
+    NULL,
+
+    _ASCIIToUnicodeWithOffsets,
+    _ASCIIToUnicodeWithOffsets,
+    _Latin1FromUnicodeWithOffsets,
+    _Latin1FromUnicodeWithOffsets,
+    _ASCIIGetNextUChar,
+
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    _ASCIIGetUnicodeSet,
+
+    NULL,
+    ucnv_ASCIIFromUTF8
+};
+
+static const UConverterStaticData _ASCIIStaticData={
+    sizeof(UConverterStaticData),
+    "US-ASCII",
+    367, UCNV_IBM, UCNV_US_ASCII, 1, 1,
+    { 0x1a, 0, 0, 0 }, 1, FALSE, FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+
+const UConverterSharedData _ASCIIData={
+    sizeof(UConverterSharedData), ~((uint32_t) 0),
+    NULL, NULL, &_ASCIIStaticData, FALSE, &_ASCIIImpl, 
+    0
+};
+
+#endif
diff --git a/source/common/ucnvmbcs.c b/source/common/ucnvmbcs.c
new file mode 100644
index 0000000..538a18c
--- /dev/null
+++ b/source/common/ucnvmbcs.c
@@ -0,0 +1,5659 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2000-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  ucnvmbcs.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2000jul03
+*   created by: Markus W. Scherer
+*
+*   The current code in this file replaces the previous implementation
+*   of conversion code from multi-byte codepages to Unicode and back.
+*   This implementation supports the following:
+*   - legacy variable-length codepages with up to 4 bytes per character
+*   - all Unicode code points (up to 0x10ffff)
+*   - efficient distinction of unassigned vs. illegal byte sequences
+*   - it is possible in fromUnicode() to directly deal with simple
+*     stateful encodings (used for EBCDIC_STATEFUL)
+*   - it is possible to convert Unicode code points
+*     to a single zero byte (but not as a fallback except for SBCS)
+*
+*   Remaining limitations in fromUnicode:
+*   - byte sequences must not have leading zero bytes
+*   - except for SBCS codepages: no fallback mapping from Unicode to a zero byte
+*   - limitation to up to 4 bytes per character
+*
+*   ICU 2.8 (late 2003) adds a secondary data structure which lifts some of these
+*   limitations and adds m:n character mappings and other features.
+*   See ucnv_ext.h for details.
+*
+*   Change history: 
+*
+*    5/6/2001       Ram       Moved  MBCS_SINGLE_RESULT_FROM_U,MBCS_STAGE_2_FROM_U,
+*                             MBCS_VALUE_2_FROM_STAGE_2, MBCS_VALUE_4_FROM_STAGE_2
+*                             macros to ucnvmbcs.h file
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION && !UCONFIG_NO_LEGACY_CONVERSION
+
+#include "unicode/ucnv.h"
+#include "unicode/ucnv_cb.h"
+#include "unicode/udata.h"
+#include "unicode/uset.h"
+#include "ucnv_bld.h"
+#include "ucnvmbcs.h"
+#include "ucnv_ext.h"
+#include "ucnv_cnv.h"
+#include "umutex.h"
+#include "cmemory.h"
+#include "cstring.h"
+
+/* control optimizations according to the platform */
+#define MBCS_UNROLL_SINGLE_TO_BMP 1
+#define MBCS_UNROLL_SINGLE_FROM_BMP 0
+
+/*
+ * _MBCSHeader versions 5.3 & 4.3
+ * (Note that the _MBCSHeader version is in addition to the converter formatVersion.)
+ *
+ * This version is optional. Version 5 is used for incompatible data format changes.
+ * makeconv will continue to generate version 4 files if possible.
+ *
+ * Changes from version 4:
+ *
+ * The main difference is an additional _MBCSHeader field with
+ * - the length (number of uint32_t) of the _MBCSHeader
+ * - flags for further incompatible data format changes
+ * - flags for further, backward compatible data format changes
+ *
+ * The MBCS_OPT_FROM_U flag indicates that most of the fromUnicode data is omitted from
+ * the file and needs to be reconstituted at load time.
+ * This requires a utf8Friendly format with an additional mbcsIndex table for fast
+ * (and UTF-8-friendly) fromUnicode conversion for Unicode code points up to maxFastUChar.
+ * (For details about these structures see below, and see ucnvmbcs.h.)
+ *
+ *   utf8Friendly also implies that the fromUnicode mappings are stored in ascending order
+ *   of the Unicode code points. (This requires that the .ucm file has the |0 etc.
+ *   precision markers for all mappings.)
+ *
+ *   All fallbacks have been moved to the extension table, leaving only roundtrips in the
+ *   omitted data that can be reconstituted from the toUnicode data.
+ *
+ *   Of the stage 2 table, the part corresponding to maxFastUChar and below is omitted.
+ *   With only roundtrip mappings in the base fromUnicode data, this part is fully
+ *   redundant with the mbcsIndex and will be reconstituted from that (also using the
+ *   stage 1 table which contains the information about how stage 2 was compacted).
+ *
+ *   The rest of the stage 2 table, the part for code points above maxFastUChar,
+ *   is stored in the file and will be appended to the reconstituted part.
+ *
+ *   The entire fromUBytes array is omitted from the file and will be reconstitued.
+ *   This is done by enumerating all toUnicode roundtrip mappings, performing
+ *   each mapping (using the stage 1 and reconstituted stage 2 tables) and
+ *   writing instead of reading the byte values.
+ *
+ * _MBCSHeader version 4.3
+ *
+ * Change from version 4.2:
+ * - Optional utf8Friendly data structures, with 64-entry stage 3 block
+ *   allocation for parts of the BMP, and an additional mbcsIndex in non-SBCS
+ *   files which can be used instead of stages 1 & 2.
+ *   Faster lookups for roundtrips from most commonly used characters,
+ *   and lookups from UTF-8 byte sequences with a natural bit distribution.
+ *   See ucnvmbcs.h for more details.
+ *
+ * Change from version 4.1:
+ * - Added an optional extension table structure at the end of the .cnv file.
+ *   It is present if the upper bits of the header flags field contains a non-zero
+ *   byte offset to it.
+ *   Files that contain only a conversion table and no base table
+ *   use the special outputType MBCS_OUTPUT_EXT_ONLY.
+ *   These contain the base table name between the MBCS header and the extension
+ *   data.
+ *
+ * Change from version 4.0:
+ * - Replace header.reserved with header.fromUBytesLength so that all
+ *   fields in the data have length.
+ *
+ * Changes from version 3 (for performance improvements):
+ * - new bit distribution for state table entries
+ * - reordered action codes
+ * - new data structure for single-byte fromUnicode
+ *   + stage 2 only contains indexes
+ *   + stage 3 stores 16 bits per character with classification bits 15..8
+ * - no multiplier for stage 1 entries
+ * - stage 2 for non-single-byte codepages contains the index and the flags in
+ *   one 32-bit value
+ * - 2-byte and 4-byte fromUnicode results are stored directly as 16/32-bit integers
+ *
+ * For more details about old versions of the MBCS data structure, see
+ * the corresponding versions of this file.
+ *
+ * Converting stateless codepage data ---------------------------------------***
+ * (or codepage data with simple states) to Unicode.
+ *
+ * Data structure and algorithm for converting from complex legacy codepages
+ * to Unicode. (Designed before 2000-may-22.)
+ *
+ * The basic idea is that the structure of legacy codepages can be described
+ * with state tables.
+ * When reading a byte stream, each input byte causes a state transition.
+ * Some transitions result in the output of a code point, some result in
+ * "unassigned" or "illegal" output.
+ * This is used here for character conversion.
+ *
+ * The data structure begins with a state table consisting of a row
+ * per state, with 256 entries (columns) per row for each possible input
+ * byte value.
+ * Each entry is 32 bits wide, with two formats distinguished by
+ * the sign bit (bit 31):
+ *
+ * One format for transitional entries (bit 31 not set) for non-final bytes, and
+ * one format for final entries (bit 31 set).
+ * Both formats contain the number of the next state in the same bit
+ * positions.
+ * State 0 is the initial state.
+ *
+ * Most of the time, the offset values of subsequent states are added
+ * up to a scalar value. This value will eventually be the index of
+ * the Unicode code point in a table that follows the state table.
+ * The effect is that the code points for final state table rows
+ * are contiguous. The code points of final state rows follow each other
+ * in the order of the references to those final states by previous
+ * states, etc.
+ *
+ * For some terminal states, the offset is itself the output Unicode
+ * code point (16 bits for a BMP code point or 20 bits for a supplementary
+ * code point (stored as code point minus 0x10000 so that 20 bits are enough).
+ * For others, the code point in the Unicode table is stored with either
+ * one or two code units: one for BMP code points, two for a pair of
+ * surrogates.
+ * All code points for a final state entry take up the same number of code
+ * units, regardless of whether they all actually _use_ the same number
+ * of code units. This is necessary for simple array access.
+ *
+ * An additional feature comes in with what in ICU is called "fallback"
+ * mappings:
+ *
+ * In addition to round-trippable, precise, 1:1 mappings, there are often
+ * mappings defined between similar, though not the same, characters.
+ * Typically, such mappings occur only in fromUnicode mapping tables because
+ * Unicode has a superset repertoire of most other codepages. However, it
+ * is possible to provide such mappings in the toUnicode tables, too.
+ * In this case, the fallback mappings are partly integrated into the
+ * general state tables because the structure of the encoding includes their
+ * byte sequences.
+ * For final entries in an initial state, fallback mappings are stored in
+ * the entry itself like with roundtrip mappings.
+ * For other final entries, they are stored in the code units table if
+ * the entry is for a pair of code units.
+ * For single-unit results in the code units table, there is no space to
+ * alternatively hold a fallback mapping; in this case, the code unit
+ * is stored as U+fffe (unassigned), and the fallback mapping needs to
+ * be looked up by the scalar offset value in a separate table.
+ *
+ * "Unassigned" state entries really mean "structurally unassigned",
+ * i.e., such a byte sequence will never have a mapping result.
+ *
+ * The interpretation of the bits in each entry is as follows:
+ *
+ * Bit 31 not set, not a terminal entry ("transitional"):
+ * 30..24 next state
+ * 23..0  offset delta, to be added up
+ *
+ * Bit 31 set, terminal ("final") entry:
+ * 30..24 next state (regardless of action code)
+ * 23..20 action code:
+ *        action codes 0 and 1 result in precise-mapping Unicode code points
+ *        0  valid byte sequence
+ *           19..16 not used, 0
+ *           15..0  16-bit Unicode BMP code point
+ *                  never U+fffe or U+ffff
+ *        1  valid byte sequence
+ *           19..0  20-bit Unicode supplementary code point
+ *                  never U+fffe or U+ffff
+ *
+ *        action codes 2 and 3 result in fallback (unidirectional-mapping) Unicode code points
+ *        2  valid byte sequence (fallback)
+ *           19..16 not used, 0
+ *           15..0  16-bit Unicode BMP code point as fallback result
+ *        3  valid byte sequence (fallback)
+ *           19..0  20-bit Unicode supplementary code point as fallback result
+ *
+ *        action codes 4 and 5 may result in roundtrip/fallback/unassigned/illegal results
+ *        depending on the code units they result in
+ *        4  valid byte sequence
+ *           19..9  not used, 0
+ *            8..0  final offset delta
+ *                  pointing to one 16-bit code unit which may be
+ *                  fffe  unassigned -- look for a fallback for this offset
+ *                  ffff  illegal
+ *        5  valid byte sequence
+ *           19..9  not used, 0
+ *            8..0  final offset delta
+ *                  pointing to two 16-bit code units
+ *                  (typically UTF-16 surrogates)
+ *                  the result depends on the first code unit as follows:
+ *                  0000..d7ff  roundtrip BMP code point (1st alone)
+ *                  d800..dbff  roundtrip surrogate pair (1st, 2nd)
+ *                  dc00..dfff  fallback surrogate pair (1st-400, 2nd)
+ *                  e000        roundtrip BMP code point (2nd alone)
+ *                  e001        fallback BMP code point (2nd alone)
+ *                  fffe        unassigned
+ *                  ffff        illegal
+ *           (the final offset deltas are at most 255 * 2,
+ *            times 2 because of storing code unit pairs)
+ *
+ *        6  unassigned byte sequence
+ *           19..16 not used, 0
+ *           15..0  16-bit Unicode BMP code point U+fffe (new with version 2)
+ *                  this does not contain a final offset delta because the main
+ *                  purpose of this action code is to save scalar offset values;
+ *                  therefore, fallback values cannot be assigned to byte
+ *                  sequences that result in this action code
+ *        7  illegal byte sequence
+ *           19..16 not used, 0
+ *           15..0  16-bit Unicode BMP code point U+ffff (new with version 2)
+ *        8  state change only
+ *           19..0  not used, 0
+ *           useful for state changes in simple stateful encodings,
+ *           at Shift-In/Shift-Out codes
+ *
+ *
+ *        9..15 reserved for future use
+ *           current implementations will only perform a state change
+ *           and ignore bits 19..0
+ *
+ * An encoding with contiguous ranges of unassigned byte sequences, like
+ * Shift-JIS and especially EUC-TW, can be stored efficiently by having
+ * at least two states for the trail bytes:
+ * One trail byte state that results in code points, and one that only
+ * has "unassigned" and "illegal" terminal states.
+ *
+ * Note: partly by accident, this data structure supports simple stateful
+ * encodings without any additional logic.
+ * Currently, only simple Shift-In/Shift-Out schemes are handled with
+ * appropriate state tables (especially EBCDIC_STATEFUL!).
+ *
+ * MBCS version 2 added:
+ * unassigned and illegal action codes have U+fffe and U+ffff
+ * instead of unused bits; this is useful for _MBCS_SINGLE_SIMPLE_GET_NEXT_BMP()
+ *
+ * Converting from Unicode to codepage bytes --------------------------------***
+ *
+ * The conversion data structure for fromUnicode is designed for the known
+ * structure of Unicode. It maps from 21-bit code points (0..0x10ffff) to
+ * a sequence of 1..4 bytes, in addition to a flag that indicates if there is
+ * a roundtrip mapping.
+ *
+ * The lookup is done with a 3-stage trie, using 11/6/4 bits for stage 1/2/3
+ * like in the character properties table.
+ * The beginning of the trie is at offsetFromUTable, the beginning of stage 3
+ * with the resulting bytes is at offsetFromUBytes.
+ *
+ * Beginning with version 4, single-byte codepages have a significantly different
+ * trie compared to other codepages.
+ * In all cases, the entry in stage 1 is directly the index of the block of
+ * 64 entries in stage 2.
+ *
+ * Single-byte lookup:
+ *
+ * Stage 2 only contains 16-bit indexes directly to the 16-blocks in stage 3.
+ * Stage 3 contains one 16-bit word per result:
+ * Bits 15..8 indicate the kind of result:
+ *    f  roundtrip result
+ *    c  fallback result from private-use code point
+ *    8  fallback result from other code points
+ *    0  unassigned
+ * Bits 7..0 contain the codepage byte. A zero byte is always possible.
+ *
+ * In version 4.3, the runtime code can build an sbcsIndex for a utf8Friendly
+ * file. For 2-byte UTF-8 byte sequences and some 3-byte sequences the lookup
+ * becomes a 2-stage (single-index) trie lookup with 6 bits for stage 3.
+ * ASCII code points can be looked up with a linear array access into stage 3.
+ * See maxFastUChar and other details in ucnvmbcs.h.
+ *
+ * Multi-byte lookup:
+ *
+ * Stage 2 contains a 32-bit word for each 16-block in stage 3:
+ * Bits 31..16 contain flags for which stage 3 entries contain roundtrip results
+ *             test: MBCS_FROM_U_IS_ROUNDTRIP(stage2Entry, c)
+ *             If this test is false, then a non-zero result will be interpreted as
+ *             a fallback mapping.
+ * Bits 15..0  contain the index to stage 3, which must be multiplied by 16*(bytes per char)
+ *
+ * Stage 3 contains 2, 3, or 4 bytes per result.
+ * 2 or 4 bytes are stored as uint16_t/uint32_t in platform endianness,
+ * while 3 bytes are stored as bytes in big-endian order.
+ * Leading zero bytes are ignored, and the number of bytes is counted.
+ * A zero byte mapping result is possible as a roundtrip result.
+ * For some output types, the actual result is processed from this;
+ * see ucnv_MBCSFromUnicodeWithOffsets().
+ *
+ * Note that stage 1 always contains 0x440=1088 entries (0x440==0x110000>>10),
+ * or (version 3 and up) for BMP-only codepages, it contains 64 entries.
+ *
+ * In version 4.3, a utf8Friendly file contains an mbcsIndex table.
+ * For 2-byte UTF-8 byte sequences and most 3-byte sequences the lookup
+ * becomes a 2-stage (single-index) trie lookup with 6 bits for stage 3.
+ * ASCII code points can be looked up with a linear array access into stage 3.
+ * See maxFastUChar, mbcsIndex and other details in ucnvmbcs.h.
+ *
+ * In version 3, stage 2 blocks may overlap by multiples of the multiplier
+ * for compaction.
+ * In version 4, stage 2 blocks (and for single-byte codepages, stage 3 blocks)
+ * may overlap by any number of entries.
+ *
+ * MBCS version 2 added:
+ * the converter checks for known output types, which allows
+ * adding new ones without crashing an unaware converter
+ */
+
+static const UConverterImpl _SBCSUTF8Impl;
+static const UConverterImpl _DBCSUTF8Impl;
+
+/* GB 18030 data ------------------------------------------------------------ */
+
+/* helper macros for linear values for GB 18030 four-byte sequences */
+#define LINEAR_18030(a, b, c, d) ((((a)*10+(b))*126L+(c))*10L+(d))
+
+#define LINEAR_18030_BASE LINEAR_18030(0x81, 0x30, 0x81, 0x30)
+
+#define LINEAR(x) LINEAR_18030(x>>24, (x>>16)&0xff, (x>>8)&0xff, x&0xff)
+
+/*
+ * Some ranges of GB 18030 where both the Unicode code points and the
+ * GB four-byte sequences are contiguous and are handled algorithmically by
+ * the special callback functions below.
+ * The values are start & end of Unicode & GB codes.
+ *
+ * Note that single surrogates are not mapped by GB 18030
+ * as of the re-released mapping tables from 2000-nov-30.
+ */
+static const uint32_t
+gb18030Ranges[13][4]={
+    {0x10000, 0x10FFFF, LINEAR(0x90308130), LINEAR(0xE3329A35)},
+    {0x9FA6, 0xD7FF, LINEAR(0x82358F33), LINEAR(0x8336C738)},
+    {0x0452, 0x200F, LINEAR(0x8130D330), LINEAR(0x8136A531)},
+    {0xE865, 0xF92B, LINEAR(0x8336D030), LINEAR(0x84308534)},
+    {0x2643, 0x2E80, LINEAR(0x8137A839), LINEAR(0x8138FD38)},
+    {0xFA2A, 0xFE2F, LINEAR(0x84309C38), LINEAR(0x84318537)},
+    {0x3CE1, 0x4055, LINEAR(0x8231D438), LINEAR(0x8232AF32)},
+    {0x361B, 0x3917, LINEAR(0x8230A633), LINEAR(0x8230F237)},
+    {0x49B8, 0x4C76, LINEAR(0x8234A131), LINEAR(0x8234E733)},
+    {0x4160, 0x4336, LINEAR(0x8232C937), LINEAR(0x8232F837)},
+    {0x478E, 0x4946, LINEAR(0x8233E838), LINEAR(0x82349638)},
+    {0x44D7, 0x464B, LINEAR(0x8233A339), LINEAR(0x8233C931)},
+    {0xFFE6, 0xFFFF, LINEAR(0x8431A234), LINEAR(0x8431A439)}
+};
+
+/* bit flag for UConverter.options indicating GB 18030 special handling */
+#define _MBCS_OPTION_GB18030 0x8000
+
+/* bit flag for UConverter.options indicating KEIS,JEF,JIF special handling */
+#define _MBCS_OPTION_KEIS 0x01000
+#define _MBCS_OPTION_JEF  0x02000
+#define _MBCS_OPTION_JIPS 0x04000
+
+#define KEIS_SO_CHAR_1 0x0A
+#define KEIS_SO_CHAR_2 0x42
+#define KEIS_SI_CHAR_1 0x0A
+#define KEIS_SI_CHAR_2 0x41
+
+#define JEF_SO_CHAR 0x28
+#define JEF_SI_CHAR 0x29
+
+#define JIPS_SO_CHAR_1 0x1A
+#define JIPS_SO_CHAR_2 0x70
+#define JIPS_SI_CHAR_1 0x1A
+#define JIPS_SI_CHAR_2 0x71
+
+enum SISO_Option {
+    SI,
+    SO
+};
+typedef enum SISO_Option SISO_Option;
+
+static int32_t getSISOBytes(SISO_Option option, uint32_t cnvOption, uint8_t *value) {
+    int32_t SISOLength = 0;
+
+    switch (option) {
+        case SI:
+            if ((cnvOption&_MBCS_OPTION_KEIS)!=0) {
+                value[0] = KEIS_SI_CHAR_1;
+                value[1] = KEIS_SI_CHAR_2;
+                SISOLength = 2;
+            } else if ((cnvOption&_MBCS_OPTION_JEF)!=0) {
+                value[0] = JEF_SI_CHAR;
+                SISOLength = 1;
+            } else if ((cnvOption&_MBCS_OPTION_JIPS)!=0) {
+                value[0] = JIPS_SI_CHAR_1;
+                value[1] = JIPS_SI_CHAR_2;
+                SISOLength = 2;
+            } else {
+                value[0] = UCNV_SI;
+                SISOLength = 1;
+            }
+            break;
+        case SO:
+            if ((cnvOption&_MBCS_OPTION_KEIS)!=0) {
+                value[0] = KEIS_SO_CHAR_1;
+                value[1] = KEIS_SO_CHAR_2;
+                SISOLength = 2;
+            } else if ((cnvOption&_MBCS_OPTION_JEF)!=0) {
+                value[0] = JEF_SO_CHAR;
+                SISOLength = 1;
+            } else if ((cnvOption&_MBCS_OPTION_JIPS)!=0) {
+                value[0] = JIPS_SO_CHAR_1;
+                value[1] = JIPS_SO_CHAR_2;
+                SISOLength = 2;
+            } else {
+                value[0] = UCNV_SO;
+                SISOLength = 1;
+            }
+            break;
+        default:
+            /* Should never happen. */
+            break;
+    }
+
+    return SISOLength;
+}
+
+/* Miscellaneous ------------------------------------------------------------ */
+
+/**
+ * Callback from ucnv_MBCSEnumToUnicode(), takes 32 mappings from
+ * consecutive sequences of bytes, starting from the one encoded in value,
+ * to Unicode code points. (Multiple mappings to reduce per-function call overhead.)
+ * Does not currently support m:n mappings or reverse fallbacks.
+ * This function will not be called for sequences of bytes with leading zeros.
+ *
+ * @param context an opaque pointer, as passed into ucnv_MBCSEnumToUnicode()
+ * @param value contains 1..4 bytes of the first byte sequence, right-aligned
+ * @param codePoints resulting Unicode code points, or negative if a byte sequence does
+ *        not map to anything
+ * @return TRUE to continue enumeration, FALSE to stop
+ */
+typedef UBool U_CALLCONV
+UConverterEnumToUCallback(const void *context, uint32_t value, UChar32 codePoints[32]);
+
+/* similar to ucnv_MBCSGetNextUChar() but recursive */
+static UBool
+enumToU(UConverterMBCSTable *mbcsTable, int8_t stateProps[],
+        int32_t state, uint32_t offset,
+        uint32_t value,
+        UConverterEnumToUCallback *callback, const void *context,
+        UErrorCode *pErrorCode) {
+    UChar32 codePoints[32];
+    const int32_t *row;
+    const uint16_t *unicodeCodeUnits;
+    UChar32 anyCodePoints;
+    int32_t b, limit;
+
+    row=mbcsTable->stateTable[state];
+    unicodeCodeUnits=mbcsTable->unicodeCodeUnits;
+
+    value<<=8;
+    anyCodePoints=-1;  /* becomes non-negative if there is a mapping */
+
+    b=(stateProps[state]&0x38)<<2;
+    if(b==0 && stateProps[state]>=0x40) {
+        /* skip byte sequences with leading zeros because they are not stored in the fromUnicode table */
+        codePoints[0]=U_SENTINEL;
+        b=1;
+    }
+    limit=((stateProps[state]&7)+1)<<5;
+    while(b<limit) {
+        int32_t entry=row[b];
+        if(MBCS_ENTRY_IS_TRANSITION(entry)) {
+            int32_t nextState=MBCS_ENTRY_TRANSITION_STATE(entry);
+            if(stateProps[nextState]>=0) {
+                /* recurse to a state with non-ignorable actions */
+                if(!enumToU(
+                        mbcsTable, stateProps, nextState,
+                        offset+MBCS_ENTRY_TRANSITION_OFFSET(entry),
+                        value|(uint32_t)b,
+                        callback, context,
+                        pErrorCode)) {
+                    return FALSE;
+                }
+            }
+            codePoints[b&0x1f]=U_SENTINEL;
+        } else {
+            UChar32 c;
+            int32_t action;
+
+            /*
+             * An if-else-if chain provides more reliable performance for
+             * the most common cases compared to a switch.
+             */
+            action=MBCS_ENTRY_FINAL_ACTION(entry);
+            if(action==MBCS_STATE_VALID_DIRECT_16) {
+                /* output BMP code point */
+                c=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            } else if(action==MBCS_STATE_VALID_16) {
+                int32_t finalOffset=offset+MBCS_ENTRY_FINAL_VALUE_16(entry);
+                c=unicodeCodeUnits[finalOffset];
+                if(c<0xfffe) {
+                    /* output BMP code point */
+                } else {
+                    c=U_SENTINEL;
+                }
+            } else if(action==MBCS_STATE_VALID_16_PAIR) {
+                int32_t finalOffset=offset+MBCS_ENTRY_FINAL_VALUE_16(entry);
+                c=unicodeCodeUnits[finalOffset++];
+                if(c<0xd800) {
+                    /* output BMP code point below 0xd800 */
+                } else if(c<=0xdbff) {
+                    /* output roundtrip or fallback supplementary code point */
+                    c=((c&0x3ff)<<10)+unicodeCodeUnits[finalOffset]+(0x10000-0xdc00);
+                } else if(c==0xe000) {
+                    /* output roundtrip BMP code point above 0xd800 or fallback BMP code point */
+                    c=unicodeCodeUnits[finalOffset];
+                } else {
+                    c=U_SENTINEL;
+                }
+            } else if(action==MBCS_STATE_VALID_DIRECT_20) {
+                /* output supplementary code point */
+                c=(UChar32)(MBCS_ENTRY_FINAL_VALUE(entry)+0x10000);
+            } else {
+                c=U_SENTINEL;
+            }
+
+            codePoints[b&0x1f]=c;
+            anyCodePoints&=c;
+        }
+        if(((++b)&0x1f)==0) {
+            if(anyCodePoints>=0) {
+                if(!callback(context, value|(uint32_t)(b-0x20), codePoints)) {
+                    return FALSE;
+                }
+                anyCodePoints=-1;
+            }
+        }
+    }
+    return TRUE;
+}
+
+/*
+ * Only called if stateProps[state]==-1.
+ * A recursive call may do stateProps[state]|=0x40 if this state is the target of an
+ * MBCS_STATE_CHANGE_ONLY.
+ */
+static int8_t
+getStateProp(const int32_t (*stateTable)[256], int8_t stateProps[], int state) {
+    const int32_t *row;
+    int32_t min, max, entry, nextState;
+
+    row=stateTable[state];
+    stateProps[state]=0;
+
+    /* find first non-ignorable state */
+    for(min=0;; ++min) {
+        entry=row[min];
+        nextState=MBCS_ENTRY_STATE(entry);
+        if(stateProps[nextState]==-1) {
+            getStateProp(stateTable, stateProps, nextState);
+        }
+        if(MBCS_ENTRY_IS_TRANSITION(entry)) {
+            if(stateProps[nextState]>=0) {
+                break;
+            }
+        } else if(MBCS_ENTRY_FINAL_ACTION(entry)<MBCS_STATE_UNASSIGNED) {
+            break;
+        }
+        if(min==0xff) {
+            stateProps[state]=-0x40;  /* (int8_t)0xc0 */
+            return stateProps[state];
+        }
+    }
+    stateProps[state]|=(int8_t)((min>>5)<<3);
+
+    /* find last non-ignorable state */
+    for(max=0xff; min<max; --max) {
+        entry=row[max];
+        nextState=MBCS_ENTRY_STATE(entry);
+        if(stateProps[nextState]==-1) {
+            getStateProp(stateTable, stateProps, nextState);
+        }
+        if(MBCS_ENTRY_IS_TRANSITION(entry)) {
+            if(stateProps[nextState]>=0) {
+                break;
+            }
+        } else if(MBCS_ENTRY_FINAL_ACTION(entry)<MBCS_STATE_UNASSIGNED) {
+            break;
+        }
+    }
+    stateProps[state]|=(int8_t)(max>>5);
+
+    /* recurse further and collect direct-state information */
+    while(min<=max) {
+        entry=row[min];
+        nextState=MBCS_ENTRY_STATE(entry);
+        if(stateProps[nextState]==-1) {
+            getStateProp(stateTable, stateProps, nextState);
+        }
+        if(MBCS_ENTRY_IS_FINAL(entry)) {
+            stateProps[nextState]|=0x40;
+            if(MBCS_ENTRY_FINAL_ACTION(entry)<=MBCS_STATE_FALLBACK_DIRECT_20) {
+                stateProps[state]|=0x40;
+            }
+        }
+        ++min;
+    }
+    return stateProps[state];
+}
+
+/*
+ * Internal function enumerating the toUnicode data of an MBCS converter.
+ * Currently only used for reconstituting data for a MBCS_OPT_NO_FROM_U
+ * table, but could also be used for a future ucnv_getUnicodeSet() option
+ * that includes reverse fallbacks (after updating this function's implementation).
+ * Currently only handles roundtrip mappings.
+ * Does not currently handle extensions.
+ */
+static void
+ucnv_MBCSEnumToUnicode(UConverterMBCSTable *mbcsTable,
+                       UConverterEnumToUCallback *callback, const void *context,
+                       UErrorCode *pErrorCode) {
+    /*
+     * Properties for each state, to speed up the enumeration.
+     * Ignorable actions are unassigned/illegal/state-change-only:
+     * They do not lead to mappings.
+     *
+     * Bits 7..6:
+     * 1 direct/initial state (stateful converters have multiple)
+     * 0 non-initial state with transitions or with non-ignorable result actions
+     * -1 final state with only ignorable actions
+     *
+     * Bits 5..3:
+     * The lowest byte value with non-ignorable actions is
+     * value<<5 (rounded down).
+     *
+     * Bits 2..0:
+     * The highest byte value with non-ignorable actions is
+     * (value<<5)&0x1f (rounded up).
+     */
+    int8_t stateProps[MBCS_MAX_STATE_COUNT];
+    int32_t state;
+
+    uprv_memset(stateProps, -1, sizeof(stateProps));
+
+    /* recurse from state 0 and set all stateProps */
+    getStateProp(mbcsTable->stateTable, stateProps, 0);
+
+    for(state=0; state<mbcsTable->countStates; ++state) {
+        /*if(stateProps[state]==-1) {
+            printf("unused/unreachable <icu:state> %d\n", state);
+        }*/
+        if(stateProps[state]>=0x40) {
+            /* start from each direct state */
+            enumToU(
+                mbcsTable, stateProps, state, 0, 0,
+                callback, context,
+                pErrorCode);
+        }
+    }
+}
+
+U_CFUNC void
+ucnv_MBCSGetFilteredUnicodeSetForUnicode(const UConverterSharedData *sharedData,
+                                         const USetAdder *sa,
+                                         UConverterUnicodeSet which,
+                                         UConverterSetFilter filter,
+                                         UErrorCode *pErrorCode) {
+    const UConverterMBCSTable *mbcsTable;
+    const uint16_t *table;
+
+    uint32_t st3;
+    uint16_t st1, maxStage1, st2;
+
+    UChar32 c;
+
+    /* enumerate the from-Unicode trie table */
+    mbcsTable=&sharedData->mbcs;
+    table=mbcsTable->fromUnicodeTable;
+    if(mbcsTable->unicodeMask&UCNV_HAS_SUPPLEMENTARY) {
+        maxStage1=0x440;
+    } else {
+        maxStage1=0x40;
+    }
+
+    c=0; /* keep track of the current code point while enumerating */
+
+    if(mbcsTable->outputType==MBCS_OUTPUT_1) {
+        const uint16_t *stage2, *stage3, *results;
+        uint16_t minValue;
+
+        results=(const uint16_t *)mbcsTable->fromUnicodeBytes;
+
+        /*
+         * Set a threshold variable for selecting which mappings to use.
+         * See ucnv_MBCSSingleFromBMPWithOffsets() and
+         * MBCS_SINGLE_RESULT_FROM_U() for details.
+         */
+        if(which==UCNV_ROUNDTRIP_SET) {
+            /* use only roundtrips */
+            minValue=0xf00;
+        } else /* UCNV_ROUNDTRIP_AND_FALLBACK_SET */ {
+            /* use all roundtrip and fallback results */
+            minValue=0x800;
+        }
+
+        for(st1=0; st1<maxStage1; ++st1) {
+            st2=table[st1];
+            if(st2>maxStage1) {
+                stage2=table+st2;
+                for(st2=0; st2<64; ++st2) {
+                    if((st3=stage2[st2])!=0) {
+                        /* read the stage 3 block */
+                        stage3=results+st3;
+
+                        do {
+                            if(*stage3++>=minValue) {
+                                sa->add(sa->set, c);
+                            }
+                        } while((++c&0xf)!=0);
+                    } else {
+                        c+=16; /* empty stage 3 block */
+                    }
+                }
+            } else {
+                c+=1024; /* empty stage 2 block */
+            }
+        }
+    } else {
+        const uint32_t *stage2;
+        const uint8_t *stage3, *bytes;
+        uint32_t st3Multiplier;
+        uint32_t value;
+        UBool useFallback;
+
+        bytes=mbcsTable->fromUnicodeBytes;
+
+        useFallback=(UBool)(which==UCNV_ROUNDTRIP_AND_FALLBACK_SET);
+
+        switch(mbcsTable->outputType) {
+        case MBCS_OUTPUT_3:
+        case MBCS_OUTPUT_4_EUC:
+            st3Multiplier=3;
+            break;
+        case MBCS_OUTPUT_4:
+            st3Multiplier=4;
+            break;
+        default:
+            st3Multiplier=2;
+            break;
+        }
+
+        for(st1=0; st1<maxStage1; ++st1) {
+            st2=table[st1];
+            if(st2>(maxStage1>>1)) {
+                stage2=(const uint32_t *)table+st2;
+                for(st2=0; st2<64; ++st2) {
+                    if((st3=stage2[st2])!=0) {
+                        /* read the stage 3 block */
+                        stage3=bytes+st3Multiplier*16*(uint32_t)(uint16_t)st3;
+
+                        /* get the roundtrip flags for the stage 3 block */
+                        st3>>=16;
+
+                        /*
+                         * Add code points for which the roundtrip flag is set,
+                         * or which map to non-zero bytes if we use fallbacks.
+                         * See ucnv_MBCSFromUnicodeWithOffsets() for details.
+                         */
+                        switch(filter) {
+                        case UCNV_SET_FILTER_NONE:
+                            do {
+                                if(st3&1) {
+                                    sa->add(sa->set, c);
+                                    stage3+=st3Multiplier;
+                                } else if(useFallback) {
+                                    uint8_t b=0;
+                                    switch(st3Multiplier) {
+                                    case 4:
+                                        b|=*stage3++;
+                                    case 3:
+                                        b|=*stage3++;
+                                    case 2:
+                                        b|=stage3[0]|stage3[1];
+                                        stage3+=2;
+                                    default:
+                                        break;
+                                    }
+                                    if(b!=0) {
+                                        sa->add(sa->set, c);
+                                    }
+                                }
+                                st3>>=1;
+                            } while((++c&0xf)!=0);
+                            break;
+                        case UCNV_SET_FILTER_DBCS_ONLY:
+                             /* Ignore single-byte results (<0x100). */
+                            do {
+                                if(((st3&1)!=0 || useFallback) && *((const uint16_t *)stage3)>=0x100) {
+                                    sa->add(sa->set, c);
+                                }
+                                st3>>=1;
+                                stage3+=2;  /* +=st3Multiplier */
+                            } while((++c&0xf)!=0);
+                            break;
+                        case UCNV_SET_FILTER_2022_CN:
+                             /* Only add code points that map to CNS 11643 planes 1 & 2 for non-EXT ISO-2022-CN. */
+                            do {
+                                if(((st3&1)!=0 || useFallback) && ((value=*stage3)==0x81 || value==0x82)) {
+                                    sa->add(sa->set, c);
+                                }
+                                st3>>=1;
+                                stage3+=3;  /* +=st3Multiplier */
+                            } while((++c&0xf)!=0);
+                            break;
+                        case UCNV_SET_FILTER_SJIS:
+                             /* Only add code points that map to Shift-JIS codes corresponding to JIS X 0208. */
+                            do {
+                                if(((st3&1)!=0 || useFallback) && (value=*((const uint16_t *)stage3))>=0x8140 && value<=0xeffc) {
+                                    sa->add(sa->set, c);
+                                }
+                                st3>>=1;
+                                stage3+=2;  /* +=st3Multiplier */
+                            } while((++c&0xf)!=0);
+                            break;
+                        case UCNV_SET_FILTER_GR94DBCS:
+                            /* Only add code points that map to ISO 2022 GR 94 DBCS codes (each byte A1..FE). */
+                            do {
+                                if( ((st3&1)!=0 || useFallback) &&
+                                    (uint16_t)((value=*((const uint16_t *)stage3)) - 0xa1a1)<=(0xfefe - 0xa1a1) &&
+                                    (uint8_t)(value-0xa1)<=(0xfe - 0xa1)
+                                ) {
+                                    sa->add(sa->set, c);
+                                }
+                                st3>>=1;
+                                stage3+=2;  /* +=st3Multiplier */
+                            } while((++c&0xf)!=0);
+                            break;
+                        case UCNV_SET_FILTER_HZ:
+                            /* Only add code points that are suitable for HZ DBCS (lead byte A1..FD). */
+                            do {
+                                if( ((st3&1)!=0 || useFallback) &&
+                                    (uint16_t)((value=*((const uint16_t *)stage3))-0xa1a1)<=(0xfdfe - 0xa1a1) &&
+                                    (uint8_t)(value-0xa1)<=(0xfe - 0xa1)
+                                ) {
+                                    sa->add(sa->set, c);
+                                }
+                                st3>>=1;
+                                stage3+=2;  /* +=st3Multiplier */
+                            } while((++c&0xf)!=0);
+                            break;
+                        default:
+                            *pErrorCode=U_INTERNAL_PROGRAM_ERROR;
+                            return;
+                        }
+                    } else {
+                        c+=16; /* empty stage 3 block */
+                    }
+                }
+            } else {
+                c+=1024; /* empty stage 2 block */
+            }
+        }
+    }
+
+    ucnv_extGetUnicodeSet(sharedData, sa, which, filter, pErrorCode);
+}
+
+U_CFUNC void
+ucnv_MBCSGetUnicodeSetForUnicode(const UConverterSharedData *sharedData,
+                                 const USetAdder *sa,
+                                 UConverterUnicodeSet which,
+                                 UErrorCode *pErrorCode) {
+    ucnv_MBCSGetFilteredUnicodeSetForUnicode(
+        sharedData, sa, which,
+        sharedData->mbcs.outputType==MBCS_OUTPUT_DBCS_ONLY ?
+            UCNV_SET_FILTER_DBCS_ONLY :
+            UCNV_SET_FILTER_NONE,
+        pErrorCode);
+}
+
+static void
+ucnv_MBCSGetUnicodeSet(const UConverter *cnv,
+                   const USetAdder *sa,
+                   UConverterUnicodeSet which,
+                   UErrorCode *pErrorCode) {
+    if(cnv->options&_MBCS_OPTION_GB18030) {
+        sa->addRange(sa->set, 0, 0xd7ff);
+        sa->addRange(sa->set, 0xe000, 0x10ffff);
+    } else {
+        ucnv_MBCSGetUnicodeSetForUnicode(cnv->sharedData, sa, which, pErrorCode);
+    }
+}
+
+/* conversion extensions for input not in the main table -------------------- */
+
+/*
+ * Hardcoded extension handling for GB 18030.
+ * Definition of LINEAR macros and gb18030Ranges see near the beginning of the file.
+ *
+ * In the future, conversion extensions may handle m:n mappings and delta tables,
+ * see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/conversion/conversion_extensions.html
+ *
+ * If an input character cannot be mapped, then these functions set an error
+ * code. The framework will then call the callback function.
+ */
+
+/*
+ * @return if(U_FAILURE) return the code point for cnv->fromUChar32
+ *         else return 0 after output has been written to the target
+ */
+static UChar32
+_extFromU(UConverter *cnv, const UConverterSharedData *sharedData,
+          UChar32 cp,
+          const UChar **source, const UChar *sourceLimit,
+          uint8_t **target, const uint8_t *targetLimit,
+          int32_t **offsets, int32_t sourceIndex,
+          UBool flush,
+          UErrorCode *pErrorCode) {
+    const int32_t *cx;
+
+    cnv->useSubChar1=FALSE;
+
+    if( (cx=sharedData->mbcs.extIndexes)!=NULL &&
+        ucnv_extInitialMatchFromU(
+            cnv, cx,
+            cp, source, sourceLimit,
+            (char **)target, (char *)targetLimit,
+            offsets, sourceIndex,
+            flush,
+            pErrorCode)
+    ) {
+        return 0; /* an extension mapping handled the input */
+    }
+
+    /* GB 18030 */
+    if((cnv->options&_MBCS_OPTION_GB18030)!=0) {
+        const uint32_t *range;
+        int32_t i;
+
+        range=gb18030Ranges[0];
+        for(i=0; i<sizeof(gb18030Ranges)/sizeof(gb18030Ranges[0]); range+=4, ++i) {
+            if(range[0]<=(uint32_t)cp && (uint32_t)cp<=range[1]) {
+                /* found the Unicode code point, output the four-byte sequence for it */
+                uint32_t linear;
+                char bytes[4];
+
+                /* get the linear value of the first GB 18030 code in this range */
+                linear=range[2]-LINEAR_18030_BASE;
+
+                /* add the offset from the beginning of the range */
+                linear+=((uint32_t)cp-range[0]);
+
+                /* turn this into a four-byte sequence */
+                bytes[3]=(char)(0x30+linear%10); linear/=10;
+                bytes[2]=(char)(0x81+linear%126); linear/=126;
+                bytes[1]=(char)(0x30+linear%10); linear/=10;
+                bytes[0]=(char)(0x81+linear);
+
+                /* output this sequence */
+                ucnv_fromUWriteBytes(cnv,
+                                     bytes, 4, (char **)target, (char *)targetLimit,
+                                     offsets, sourceIndex, pErrorCode);
+                return 0;
+            }
+        }
+    }
+
+    /* no mapping */
+    *pErrorCode=U_INVALID_CHAR_FOUND;
+    return cp;
+}
+
+/*
+ * Input sequence: cnv->toUBytes[0..length[
+ * @return if(U_FAILURE) return the length (toULength, byteIndex) for the input
+ *         else return 0 after output has been written to the target
+ */
+static int8_t
+_extToU(UConverter *cnv, const UConverterSharedData *sharedData,
+        int8_t length,
+        const uint8_t **source, const uint8_t *sourceLimit,
+        UChar **target, const UChar *targetLimit,
+        int32_t **offsets, int32_t sourceIndex,
+        UBool flush,
+        UErrorCode *pErrorCode) {
+    const int32_t *cx;
+
+    if( (cx=sharedData->mbcs.extIndexes)!=NULL &&
+        ucnv_extInitialMatchToU(
+            cnv, cx,
+            length, (const char **)source, (const char *)sourceLimit,
+            target, targetLimit,
+            offsets, sourceIndex,
+            flush,
+            pErrorCode)
+    ) {
+        return 0; /* an extension mapping handled the input */
+    }
+
+    /* GB 18030 */
+    if(length==4 && (cnv->options&_MBCS_OPTION_GB18030)!=0) {
+        const uint32_t *range;
+        uint32_t linear;
+        int32_t i;
+
+        linear=LINEAR_18030(cnv->toUBytes[0], cnv->toUBytes[1], cnv->toUBytes[2], cnv->toUBytes[3]);
+        range=gb18030Ranges[0];
+        for(i=0; i<sizeof(gb18030Ranges)/sizeof(gb18030Ranges[0]); range+=4, ++i) {
+            if(range[2]<=linear && linear<=range[3]) {
+                /* found the sequence, output the Unicode code point for it */
+                *pErrorCode=U_ZERO_ERROR;
+
+                /* add the linear difference between the input and start sequences to the start code point */
+                linear=range[0]+(linear-range[2]);
+
+                /* output this code point */
+                ucnv_toUWriteCodePoint(cnv, linear, target, targetLimit, offsets, sourceIndex, pErrorCode);
+
+                return 0;
+            }
+        }
+    }
+
+    /* no mapping */
+    *pErrorCode=U_INVALID_CHAR_FOUND;
+    return length;
+}
+
+/* EBCDIC swap LF<->NL ------------------------------------------------------ */
+
+/*
+ * This code modifies a standard EBCDIC<->Unicode mapping table for
+ * OS/390 (z/OS) Unix System Services (Open Edition).
+ * The difference is in the mapping of Line Feed and New Line control codes:
+ * Standard EBCDIC maps
+ *
+ *   <U000A> \x25 |0
+ *   <U0085> \x15 |0
+ *
+ * but OS/390 USS EBCDIC swaps the control codes for LF and NL,
+ * mapping
+ *
+ *   <U000A> \x15 |0
+ *   <U0085> \x25 |0
+ *
+ * This code modifies a loaded standard EBCDIC<->Unicode mapping table
+ * by copying it into allocated memory and swapping the LF and NL values.
+ * It allows to support the same EBCDIC charset in both versions without
+ * duplicating the entire installed table.
+ */
+
+/* standard EBCDIC codes */
+#define EBCDIC_LF 0x25
+#define EBCDIC_NL 0x15
+
+/* standard EBCDIC codes with roundtrip flag as stored in Unicode-to-single-byte tables */
+#define EBCDIC_RT_LF 0xf25
+#define EBCDIC_RT_NL 0xf15
+
+/* Unicode code points */
+#define U_LF 0x0a
+#define U_NL 0x85
+
+static UBool
+_EBCDICSwapLFNL(UConverterSharedData *sharedData, UErrorCode *pErrorCode) {
+    UConverterMBCSTable *mbcsTable;
+
+    const uint16_t *table, *results;
+    const uint8_t *bytes;
+
+    int32_t (*newStateTable)[256];
+    uint16_t *newResults;
+    uint8_t *p;
+    char *name;
+
+    uint32_t stage2Entry;
+    uint32_t size, sizeofFromUBytes;
+
+    mbcsTable=&sharedData->mbcs;
+
+    table=mbcsTable->fromUnicodeTable;
+    bytes=mbcsTable->fromUnicodeBytes;
+    results=(const uint16_t *)bytes;
+
+    /*
+     * Check that this is an EBCDIC table with SBCS portion -
+     * SBCS or EBCDIC_STATEFUL with standard EBCDIC LF and NL mappings.
+     *
+     * If not, ignore the option. Options are always ignored if they do not apply.
+     */
+    if(!(
+         (mbcsTable->outputType==MBCS_OUTPUT_1 || mbcsTable->outputType==MBCS_OUTPUT_2_SISO) &&
+         mbcsTable->stateTable[0][EBCDIC_LF]==MBCS_ENTRY_FINAL(0, MBCS_STATE_VALID_DIRECT_16, U_LF) &&
+         mbcsTable->stateTable[0][EBCDIC_NL]==MBCS_ENTRY_FINAL(0, MBCS_STATE_VALID_DIRECT_16, U_NL)
+    )) {
+        return FALSE;
+    }
+
+    if(mbcsTable->outputType==MBCS_OUTPUT_1) {
+        if(!(
+             EBCDIC_RT_LF==MBCS_SINGLE_RESULT_FROM_U(table, results, U_LF) &&
+             EBCDIC_RT_NL==MBCS_SINGLE_RESULT_FROM_U(table, results, U_NL)
+        )) {
+            return FALSE;
+        }
+    } else /* MBCS_OUTPUT_2_SISO */ {
+        stage2Entry=MBCS_STAGE_2_FROM_U(table, U_LF);
+        if(!(
+             MBCS_FROM_U_IS_ROUNDTRIP(stage2Entry, U_LF)!=0 &&
+             EBCDIC_LF==MBCS_VALUE_2_FROM_STAGE_2(bytes, stage2Entry, U_LF)
+        )) {
+            return FALSE;
+        }
+
+        stage2Entry=MBCS_STAGE_2_FROM_U(table, U_NL);
+        if(!(
+             MBCS_FROM_U_IS_ROUNDTRIP(stage2Entry, U_NL)!=0 &&
+             EBCDIC_NL==MBCS_VALUE_2_FROM_STAGE_2(bytes, stage2Entry, U_NL)
+        )) {
+            return FALSE;
+        }
+    }
+
+    if(mbcsTable->fromUBytesLength>0) {
+        /*
+         * We _know_ the number of bytes in the fromUnicodeBytes array
+         * starting with header.version 4.1.
+         */
+        sizeofFromUBytes=mbcsTable->fromUBytesLength;
+    } else {
+        /*
+         * Otherwise:
+         * There used to be code to enumerate the fromUnicode
+         * trie and find the highest entry, but it was removed in ICU 3.2
+         * because it was not tested and caused a low code coverage number.
+         * See Jitterbug 3674.
+         * This affects only some .cnv file formats with a header.version
+         * below 4.1, and only when swaplfnl is requested.
+         *
+         * ucnvmbcs.c revision 1.99 is the last one with the
+         * ucnv_MBCSSizeofFromUBytes() function.
+         */
+        *pErrorCode=U_INVALID_FORMAT_ERROR;
+        return FALSE;
+    }
+
+    /*
+     * The table has an appropriate format.
+     * Allocate and build
+     * - a modified to-Unicode state table
+     * - a modified from-Unicode output array
+     * - a converter name string with the swap option appended
+     */
+    size=
+        mbcsTable->countStates*1024+
+        sizeofFromUBytes+
+        UCNV_MAX_CONVERTER_NAME_LENGTH+20;
+    p=(uint8_t *)uprv_malloc(size);
+    if(p==NULL) {
+        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+        return FALSE;
+    }
+
+    /* copy and modify the to-Unicode state table */
+    newStateTable=(int32_t (*)[256])p;
+    uprv_memcpy(newStateTable, mbcsTable->stateTable, mbcsTable->countStates*1024);
+
+    newStateTable[0][EBCDIC_LF]=MBCS_ENTRY_FINAL(0, MBCS_STATE_VALID_DIRECT_16, U_NL);
+    newStateTable[0][EBCDIC_NL]=MBCS_ENTRY_FINAL(0, MBCS_STATE_VALID_DIRECT_16, U_LF);
+
+    /* copy and modify the from-Unicode result table */
+    newResults=(uint16_t *)newStateTable[mbcsTable->countStates];
+    uprv_memcpy(newResults, bytes, sizeofFromUBytes);
+
+    /* conveniently, the table access macros work on the left side of expressions */
+    if(mbcsTable->outputType==MBCS_OUTPUT_1) {
+        MBCS_SINGLE_RESULT_FROM_U(table, newResults, U_LF)=EBCDIC_RT_NL;
+        MBCS_SINGLE_RESULT_FROM_U(table, newResults, U_NL)=EBCDIC_RT_LF;
+    } else /* MBCS_OUTPUT_2_SISO */ {
+        stage2Entry=MBCS_STAGE_2_FROM_U(table, U_LF);
+        MBCS_VALUE_2_FROM_STAGE_2(newResults, stage2Entry, U_LF)=EBCDIC_NL;
+
+        stage2Entry=MBCS_STAGE_2_FROM_U(table, U_NL);
+        MBCS_VALUE_2_FROM_STAGE_2(newResults, stage2Entry, U_NL)=EBCDIC_LF;
+    }
+
+    /* set the canonical converter name */
+    name=(char *)newResults+sizeofFromUBytes;
+    uprv_strcpy(name, sharedData->staticData->name);
+    uprv_strcat(name, UCNV_SWAP_LFNL_OPTION_STRING);
+
+    /* set the pointers */
+    umtx_lock(NULL);
+    if(mbcsTable->swapLFNLStateTable==NULL) {
+        mbcsTable->swapLFNLStateTable=newStateTable;
+        mbcsTable->swapLFNLFromUnicodeBytes=(uint8_t *)newResults;
+        mbcsTable->swapLFNLName=name;
+
+        newStateTable=NULL;
+    }
+    umtx_unlock(NULL);
+
+    /* release the allocated memory if another thread beat us to it */
+    if(newStateTable!=NULL) {
+        uprv_free(newStateTable);
+    }
+    return TRUE;
+}
+
+/* reconstitute omitted fromUnicode data ------------------------------------ */
+
+/* for details, compare with genmbcs.c MBCSAddFromUnicode() and transformEUC() */
+static UBool U_CALLCONV
+writeStage3Roundtrip(const void *context, uint32_t value, UChar32 codePoints[32]) {
+    UConverterMBCSTable *mbcsTable=(UConverterMBCSTable *)context;
+    const uint16_t *table;
+    uint32_t *stage2;
+    uint8_t *bytes, *p;
+    UChar32 c;
+    int32_t i, st3;
+
+    table=mbcsTable->fromUnicodeTable;
+    bytes=(uint8_t *)mbcsTable->fromUnicodeBytes;
+
+    /* for EUC outputTypes, modify the value like genmbcs.c's transformEUC() */
+    switch(mbcsTable->outputType) {
+    case MBCS_OUTPUT_3_EUC:
+        if(value<=0xffff) {
+            /* short sequences are stored directly */
+            /* code set 0 or 1 */
+        } else if(value<=0x8effff) {
+            /* code set 2 */
+            value&=0x7fff;
+        } else /* first byte is 0x8f */ {
+            /* code set 3 */
+            value&=0xff7f;
+        }
+        break;
+    case MBCS_OUTPUT_4_EUC:
+        if(value<=0xffffff) {
+            /* short sequences are stored directly */
+            /* code set 0 or 1 */
+        } else if(value<=0x8effffff) {
+            /* code set 2 */
+            value&=0x7fffff;
+        } else /* first byte is 0x8f */ {
+            /* code set 3 */
+            value&=0xff7fff;
+        }
+        break;
+    default:
+        break;
+    }
+
+    for(i=0; i<=0x1f; ++value, ++i) {
+        c=codePoints[i];
+        if(c<0) {
+            continue;
+        }
+
+        /* locate the stage 2 & 3 data */
+        stage2=((uint32_t *)table)+table[c>>10]+((c>>4)&0x3f);
+        p=bytes;
+        st3=(int32_t)(uint16_t)*stage2*16+(c&0xf);
+
+        /* write the codepage bytes into stage 3 */
+        switch(mbcsTable->outputType) {
+        case MBCS_OUTPUT_3:
+        case MBCS_OUTPUT_4_EUC:
+            p+=st3*3;
+            p[0]=(uint8_t)(value>>16);
+            p[1]=(uint8_t)(value>>8);
+            p[2]=(uint8_t)value;
+            break;
+        case MBCS_OUTPUT_4:
+            ((uint32_t *)p)[st3]=value;
+            break;
+        default:
+            /* 2 bytes per character */
+            ((uint16_t *)p)[st3]=(uint16_t)value;
+            break;
+        }
+
+        /* set the roundtrip flag */
+        *stage2|=(1UL<<(16+(c&0xf)));
+    }
+    return TRUE;
+ }
+
+static void
+reconstituteData(UConverterMBCSTable *mbcsTable,
+                 uint32_t stage1Length, uint32_t stage2Length,
+                 uint32_t fullStage2Length,  /* lengths are numbers of units, not bytes */
+                 UErrorCode *pErrorCode) {
+    uint16_t *stage1;
+    uint32_t *stage2;
+    uint8_t *bytes;
+    uint32_t dataLength=stage1Length*2+fullStage2Length*4+mbcsTable->fromUBytesLength;
+    mbcsTable->reconstitutedData=(uint8_t *)uprv_malloc(dataLength);
+    if(mbcsTable->reconstitutedData==NULL) {
+        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    uprv_memset(mbcsTable->reconstitutedData, 0, dataLength);
+
+    /* copy existing data and reroute the pointers */
+    stage1=(uint16_t *)mbcsTable->reconstitutedData;
+    uprv_memcpy(stage1, mbcsTable->fromUnicodeTable, stage1Length*2);
+
+    stage2=(uint32_t *)(stage1+stage1Length);
+    uprv_memcpy(stage2+(fullStage2Length-stage2Length),
+                mbcsTable->fromUnicodeTable+stage1Length,
+                stage2Length*4);
+
+    mbcsTable->fromUnicodeTable=stage1;
+    mbcsTable->fromUnicodeBytes=bytes=(uint8_t *)(stage2+fullStage2Length);
+
+    /* indexes into stage 2 count from the bottom of the fromUnicodeTable */
+    stage2=(uint32_t *)stage1;
+
+    /* reconstitute the initial part of stage 2 from the mbcsIndex */
+    {
+        int32_t stageUTF8Length=((int32_t)mbcsTable->maxFastUChar+1)>>6;
+        int32_t stageUTF8Index=0;
+        int32_t st1, st2, st3, i;
+
+        for(st1=0; stageUTF8Index<stageUTF8Length; ++st1) {
+            st2=stage1[st1];
+            if(st2!=stage1Length/2) {
+                /* each stage 2 block has 64 entries corresponding to 16 entries in the mbcsIndex */
+                for(i=0; i<16; ++i) {
+                    st3=mbcsTable->mbcsIndex[stageUTF8Index++];
+                    if(st3!=0) {
+                        /* an stage 2 entry's index is per stage 3 16-block, not per stage 3 entry */
+                        st3>>=4;
+                        /*
+                         * 4 stage 2 entries point to 4 consecutive stage 3 16-blocks which are
+                         * allocated together as a single 64-block for access from the mbcsIndex
+                         */
+                        stage2[st2++]=st3++;
+                        stage2[st2++]=st3++;
+                        stage2[st2++]=st3++;
+                        stage2[st2++]=st3;
+                    } else {
+                        /* no stage 3 block, skip */
+                        st2+=4;
+                    }
+                }
+            } else {
+                /* no stage 2 block, skip */
+                stageUTF8Index+=16;
+            }
+        }
+    }
+
+    /* reconstitute fromUnicodeBytes with roundtrips from toUnicode data */
+    ucnv_MBCSEnumToUnicode(mbcsTable, writeStage3Roundtrip, mbcsTable, pErrorCode);
+}
+
+/* MBCS setup functions ----------------------------------------------------- */
+
+static void
+ucnv_MBCSLoad(UConverterSharedData *sharedData,
+          UConverterLoadArgs *pArgs,
+          const uint8_t *raw,
+          UErrorCode *pErrorCode) {
+    UDataInfo info;
+    UConverterMBCSTable *mbcsTable=&sharedData->mbcs;
+    _MBCSHeader *header=(_MBCSHeader *)raw;
+    uint32_t offset;
+    uint32_t headerLength;
+    UBool noFromU=FALSE;
+
+    if(header->version[0]==4) {
+        headerLength=MBCS_HEADER_V4_LENGTH;
+    } else if(header->version[0]==5 && header->version[1]>=3 &&
+              (header->options&MBCS_OPT_UNKNOWN_INCOMPATIBLE_MASK)==0) {
+        headerLength=header->options&MBCS_OPT_LENGTH_MASK;
+        noFromU=(UBool)((header->options&MBCS_OPT_NO_FROM_U)!=0);
+    } else {
+        *pErrorCode=U_INVALID_TABLE_FORMAT;
+        return;
+    }
+
+    mbcsTable->outputType=(uint8_t)header->flags;
+    if(noFromU && mbcsTable->outputType==MBCS_OUTPUT_1) {
+        *pErrorCode=U_INVALID_TABLE_FORMAT;
+        return;
+    }
+
+    /* extension data, header version 4.2 and higher */
+    offset=header->flags>>8;
+    if(offset!=0) {
+        mbcsTable->extIndexes=(const int32_t *)(raw+offset);
+    }
+
+    if(mbcsTable->outputType==MBCS_OUTPUT_EXT_ONLY) {
+        UConverterLoadArgs args={ 0 };
+        UConverterSharedData *baseSharedData;
+        const int32_t *extIndexes;
+        const char *baseName;
+
+        /* extension-only file, load the base table and set values appropriately */
+        if((extIndexes=mbcsTable->extIndexes)==NULL) {
+            /* extension-only file without extension */
+            *pErrorCode=U_INVALID_TABLE_FORMAT;
+            return;
+        }
+
+        if(pArgs->nestedLoads!=1) {
+            /* an extension table must not be loaded as a base table */
+            *pErrorCode=U_INVALID_TABLE_FILE;
+            return;
+        }
+
+        /* load the base table */
+        baseName=(const char *)header+headerLength*4;
+        if(0==uprv_strcmp(baseName, sharedData->staticData->name)) {
+            /* forbid loading this same extension-only file */
+            *pErrorCode=U_INVALID_TABLE_FORMAT;
+            return;
+        }
+
+        /* TODO parse package name out of the prefix of the base name in the extension .cnv file? */
+        args.size=sizeof(UConverterLoadArgs);
+        args.nestedLoads=2;
+        args.onlyTestIsLoadable=pArgs->onlyTestIsLoadable;
+        args.reserved=pArgs->reserved;
+        args.options=pArgs->options;
+        args.pkg=pArgs->pkg;
+        args.name=baseName;
+        baseSharedData=ucnv_load(&args, pErrorCode);
+        if(U_FAILURE(*pErrorCode)) {
+            return;
+        }
+        if( baseSharedData->staticData->conversionType!=UCNV_MBCS ||
+            baseSharedData->mbcs.baseSharedData!=NULL
+        ) {
+            ucnv_unload(baseSharedData);
+            *pErrorCode=U_INVALID_TABLE_FORMAT;
+            return;
+        }
+        if(pArgs->onlyTestIsLoadable) {
+            /*
+             * Exit as soon as we know that we can load the converter
+             * and the format is valid and supported.
+             * The worst that can happen in the following code is a memory
+             * allocation error.
+             */
+            ucnv_unload(baseSharedData);
+            return;
+        }
+
+        /* copy the base table data */
+        uprv_memcpy(mbcsTable, &baseSharedData->mbcs, sizeof(UConverterMBCSTable));
+
+        /* overwrite values with relevant ones for the extension converter */
+        mbcsTable->baseSharedData=baseSharedData;
+        mbcsTable->extIndexes=extIndexes;
+
+        /*
+         * It would be possible to share the swapLFNL data with a base converter,
+         * but the generated name would have to be different, and the memory
+         * would have to be free'd only once.
+         * It is easier to just create the data for the extension converter
+         * separately when it is requested.
+         */
+        mbcsTable->swapLFNLStateTable=NULL;
+        mbcsTable->swapLFNLFromUnicodeBytes=NULL;
+        mbcsTable->swapLFNLName=NULL;
+
+        /*
+         * The reconstitutedData must be deleted only when the base converter
+         * is unloaded.
+         */
+        mbcsTable->reconstitutedData=NULL;
+
+        /*
+         * Set a special, runtime-only outputType if the extension converter
+         * is a DBCS version of a base converter that also maps single bytes.
+         */
+        if( sharedData->staticData->conversionType==UCNV_DBCS ||
+                (sharedData->staticData->conversionType==UCNV_MBCS &&
+                 sharedData->staticData->minBytesPerChar>=2)
+        ) {
+            if(baseSharedData->mbcs.outputType==MBCS_OUTPUT_2_SISO) {
+                /* the base converter is SI/SO-stateful */
+                int32_t entry;
+
+                /* get the dbcs state from the state table entry for SO=0x0e */
+                entry=mbcsTable->stateTable[0][0xe];
+                if( MBCS_ENTRY_IS_FINAL(entry) &&
+                    MBCS_ENTRY_FINAL_ACTION(entry)==MBCS_STATE_CHANGE_ONLY &&
+                    MBCS_ENTRY_FINAL_STATE(entry)!=0
+                ) {
+                    mbcsTable->dbcsOnlyState=(uint8_t)MBCS_ENTRY_FINAL_STATE(entry);
+
+                    mbcsTable->outputType=MBCS_OUTPUT_DBCS_ONLY;
+                }
+            } else if(
+                baseSharedData->staticData->conversionType==UCNV_MBCS &&
+                baseSharedData->staticData->minBytesPerChar==1 &&
+                baseSharedData->staticData->maxBytesPerChar==2 &&
+                mbcsTable->countStates<=127
+            ) {
+                /* non-stateful base converter, need to modify the state table */
+                int32_t (*newStateTable)[256];
+                int32_t *state;
+                int32_t i, count;
+
+                /* allocate a new state table and copy the base state table contents */
+                count=mbcsTable->countStates;
+                newStateTable=(int32_t (*)[256])uprv_malloc((count+1)*1024);
+                if(newStateTable==NULL) {
+                    ucnv_unload(baseSharedData);
+                    *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+                    return;
+                }
+
+                uprv_memcpy(newStateTable, mbcsTable->stateTable, count*1024);
+
+                /* change all final single-byte entries to go to a new all-illegal state */
+                state=newStateTable[0];
+                for(i=0; i<256; ++i) {
+                    if(MBCS_ENTRY_IS_FINAL(state[i])) {
+                        state[i]=MBCS_ENTRY_TRANSITION(count, 0);
+                    }
+                }
+
+                /* build the new all-illegal state */
+                state=newStateTable[count];
+                for(i=0; i<256; ++i) {
+                    state[i]=MBCS_ENTRY_FINAL(0, MBCS_STATE_ILLEGAL, 0);
+                }
+                mbcsTable->stateTable=(const int32_t (*)[256])newStateTable;
+                mbcsTable->countStates=(uint8_t)(count+1);
+                mbcsTable->stateTableOwned=TRUE;
+
+                mbcsTable->outputType=MBCS_OUTPUT_DBCS_ONLY;
+            }
+        }
+
+        /*
+         * unlike below for files with base tables, do not get the unicodeMask
+         * from the sharedData; instead, use the base table's unicodeMask,
+         * which we copied in the memcpy above;
+         * this is necessary because the static data unicodeMask, especially
+         * the UCNV_HAS_SUPPLEMENTARY flag, is part of the base table data
+         */
+    } else {
+        /* conversion file with a base table; an additional extension table is optional */
+        /* make sure that the output type is known */
+        switch(mbcsTable->outputType) {
+        case MBCS_OUTPUT_1:
+        case MBCS_OUTPUT_2:
+        case MBCS_OUTPUT_3:
+        case MBCS_OUTPUT_4:
+        case MBCS_OUTPUT_3_EUC:
+        case MBCS_OUTPUT_4_EUC:
+        case MBCS_OUTPUT_2_SISO:
+            /* OK */
+            break;
+        default:
+            *pErrorCode=U_INVALID_TABLE_FORMAT;
+            return;
+        }
+        if(pArgs->onlyTestIsLoadable) {
+            /*
+             * Exit as soon as we know that we can load the converter
+             * and the format is valid and supported.
+             * The worst that can happen in the following code is a memory
+             * allocation error.
+             */
+            return;
+        }
+
+        mbcsTable->countStates=(uint8_t)header->countStates;
+        mbcsTable->countToUFallbacks=header->countToUFallbacks;
+        mbcsTable->stateTable=(const int32_t (*)[256])(raw+headerLength*4);
+        mbcsTable->toUFallbacks=(const _MBCSToUFallback *)(mbcsTable->stateTable+header->countStates);
+        mbcsTable->unicodeCodeUnits=(const uint16_t *)(raw+header->offsetToUCodeUnits);
+
+        mbcsTable->fromUnicodeTable=(const uint16_t *)(raw+header->offsetFromUTable);
+        mbcsTable->fromUnicodeBytes=(const uint8_t *)(raw+header->offsetFromUBytes);
+        mbcsTable->fromUBytesLength=header->fromUBytesLength;
+
+        /*
+         * converter versions 6.1 and up contain a unicodeMask that is
+         * used here to select the most efficient function implementations
+         */
+        info.size=sizeof(UDataInfo);
+        udata_getInfo((UDataMemory *)sharedData->dataMemory, &info);
+        if(info.formatVersion[0]>6 || (info.formatVersion[0]==6 && info.formatVersion[1]>=1)) {
+            /* mask off possible future extensions to be safe */
+            mbcsTable->unicodeMask=(uint8_t)(sharedData->staticData->unicodeMask&3);
+        } else {
+            /* for older versions, assume worst case: contains anything possible (prevent over-optimizations) */
+            mbcsTable->unicodeMask=UCNV_HAS_SUPPLEMENTARY|UCNV_HAS_SURROGATES;
+        }
+
+        /*
+         * _MBCSHeader.version 4.3 adds utf8Friendly data structures.
+         * Check for the header version, SBCS vs. MBCS, and for whether the
+         * data structures are optimized for code points as high as what the
+         * runtime code is designed for.
+         * The implementation does not handle mapping tables with entries for
+         * unpaired surrogates.
+         */
+        if( header->version[1]>=3 &&
+            (mbcsTable->unicodeMask&UCNV_HAS_SURROGATES)==0 &&
+            (mbcsTable->countStates==1 ?
+                (header->version[2]>=(SBCS_FAST_MAX>>8)) :
+                (header->version[2]>=(MBCS_FAST_MAX>>8))
+            )
+        ) {
+            mbcsTable->utf8Friendly=TRUE;
+
+            if(mbcsTable->countStates==1) {
+                /*
+                 * SBCS: Stage 3 is allocated in 64-entry blocks for U+0000..SBCS_FAST_MAX or higher.
+                 * Build a table with indexes to each block, to be used instead of
+                 * the regular stage 1/2 table.
+                 */
+                int32_t i;
+                for(i=0; i<(SBCS_FAST_LIMIT>>6); ++i) {
+                    mbcsTable->sbcsIndex[i]=mbcsTable->fromUnicodeTable[mbcsTable->fromUnicodeTable[i>>4]+((i<<2)&0x3c)];
+                }
+                /* set SBCS_FAST_MAX to reflect the reach of sbcsIndex[] even if header->version[2]>(SBCS_FAST_MAX>>8) */
+                mbcsTable->maxFastUChar=SBCS_FAST_MAX;
+            } else {
+                /*
+                 * MBCS: Stage 3 is allocated in 64-entry blocks for U+0000..MBCS_FAST_MAX or higher.
+                 * The .cnv file is prebuilt with an additional stage table with indexes
+                 * to each block.
+                 */
+                mbcsTable->mbcsIndex=(const uint16_t *)
+                    (mbcsTable->fromUnicodeBytes+
+                     (noFromU ? 0 : mbcsTable->fromUBytesLength));
+                mbcsTable->maxFastUChar=(((UChar)header->version[2])<<8)|0xff;
+            }
+        }
+
+        /* calculate a bit set of 4 ASCII characters per bit that round-trip to ASCII bytes */
+        {
+            uint32_t asciiRoundtrips=0xffffffff;
+            int32_t i;
+
+            for(i=0; i<0x80; ++i) {
+                if(mbcsTable->stateTable[0][i]!=MBCS_ENTRY_FINAL(0, MBCS_STATE_VALID_DIRECT_16, i)) {
+                    asciiRoundtrips&=~((uint32_t)1<<(i>>2));
+                }
+            }
+            mbcsTable->asciiRoundtrips=asciiRoundtrips;
+        }
+
+        if(noFromU) {
+            uint32_t stage1Length=
+                mbcsTable->unicodeMask&UCNV_HAS_SUPPLEMENTARY ?
+                    0x440 : 0x40;
+            uint32_t stage2Length=
+                (header->offsetFromUBytes-header->offsetFromUTable)/4-
+                stage1Length/2;
+            reconstituteData(mbcsTable, stage1Length, stage2Length, header->fullStage2Length, pErrorCode);
+        }
+    }
+
+    /* Set the impl pointer here so that it is set for both extension-only and base tables. */
+    if(mbcsTable->utf8Friendly) {
+        if(mbcsTable->countStates==1) {
+            sharedData->impl=&_SBCSUTF8Impl;
+        } else {
+            if(mbcsTable->outputType==MBCS_OUTPUT_2) {
+                sharedData->impl=&_DBCSUTF8Impl;
+            }
+        }
+    }
+
+    if(mbcsTable->outputType==MBCS_OUTPUT_DBCS_ONLY || mbcsTable->outputType==MBCS_OUTPUT_2_SISO) {
+        /*
+         * MBCS_OUTPUT_DBCS_ONLY: No SBCS mappings, therefore ASCII does not roundtrip.
+         * MBCS_OUTPUT_2_SISO: Bypass the ASCII fastpath to handle prevLength correctly.
+         */
+        mbcsTable->asciiRoundtrips=0;
+    }
+}
+
+static void
+ucnv_MBCSUnload(UConverterSharedData *sharedData) {
+    UConverterMBCSTable *mbcsTable=&sharedData->mbcs;
+
+    if(mbcsTable->swapLFNLStateTable!=NULL) {
+        uprv_free(mbcsTable->swapLFNLStateTable);
+    }
+    if(mbcsTable->stateTableOwned) {
+        uprv_free((void *)mbcsTable->stateTable);
+    }
+    if(mbcsTable->baseSharedData!=NULL) {
+        ucnv_unload(mbcsTable->baseSharedData);
+    }
+    if(mbcsTable->reconstitutedData!=NULL) {
+        uprv_free(mbcsTable->reconstitutedData);
+    }
+}
+
+static void
+ucnv_MBCSOpen(UConverter *cnv,
+              UConverterLoadArgs *pArgs,
+              UErrorCode *pErrorCode) {
+    UConverterMBCSTable *mbcsTable;
+    const int32_t *extIndexes;
+    uint8_t outputType;
+    int8_t maxBytesPerUChar;
+
+    if(pArgs->onlyTestIsLoadable) {
+        return;
+    }
+
+    mbcsTable=&cnv->sharedData->mbcs;
+    outputType=mbcsTable->outputType;
+
+    if(outputType==MBCS_OUTPUT_DBCS_ONLY) {
+        /* the swaplfnl option does not apply, remove it */
+        cnv->options=pArgs->options&=~UCNV_OPTION_SWAP_LFNL;
+    }
+
+    if((pArgs->options&UCNV_OPTION_SWAP_LFNL)!=0) {
+        /* do this because double-checked locking is broken */
+        UBool isCached;
+
+        umtx_lock(NULL);
+        isCached=mbcsTable->swapLFNLStateTable!=NULL;
+        umtx_unlock(NULL);
+
+        if(!isCached) {
+            if(!_EBCDICSwapLFNL(cnv->sharedData, pErrorCode)) {
+                if(U_FAILURE(*pErrorCode)) {
+                    return; /* something went wrong */
+                }
+
+                /* the option does not apply, remove it */
+                cnv->options=pArgs->options&=~UCNV_OPTION_SWAP_LFNL;
+            }
+        }
+    }
+
+    if(uprv_strstr(pArgs->name, "18030")!=NULL) {
+        if(uprv_strstr(pArgs->name, "gb18030")!=NULL || uprv_strstr(pArgs->name, "GB18030")!=NULL) {
+            /* set a flag for GB 18030 mode, which changes the callback behavior */
+            cnv->options|=_MBCS_OPTION_GB18030;
+        }
+    } else if((uprv_strstr(pArgs->name, "KEIS")!=NULL) || (uprv_strstr(pArgs->name, "keis")!=NULL)) {
+        /* set a flag for KEIS converter, which changes the SI/SO character sequence */
+        cnv->options|=_MBCS_OPTION_KEIS;
+    } else if((uprv_strstr(pArgs->name, "JEF")!=NULL) || (uprv_strstr(pArgs->name, "jef")!=NULL)) {
+        /* set a flag for JEF converter, which changes the SI/SO character sequence */
+        cnv->options|=_MBCS_OPTION_JEF;
+    } else if((uprv_strstr(pArgs->name, "JIPS")!=NULL) || (uprv_strstr(pArgs->name, "jips")!=NULL)) {
+        /* set a flag for JIPS converter, which changes the SI/SO character sequence */
+        cnv->options|=_MBCS_OPTION_JIPS;
+    }
+
+    /* fix maxBytesPerUChar depending on outputType and options etc. */
+    if(outputType==MBCS_OUTPUT_2_SISO) {
+        cnv->maxBytesPerUChar=3; /* SO+DBCS */
+    }
+
+    extIndexes=mbcsTable->extIndexes;
+    if(extIndexes!=NULL) {
+        maxBytesPerUChar=(int8_t)UCNV_GET_MAX_BYTES_PER_UCHAR(extIndexes);
+        if(outputType==MBCS_OUTPUT_2_SISO) {
+            ++maxBytesPerUChar; /* SO + multiple DBCS */
+        }
+
+        if(maxBytesPerUChar>cnv->maxBytesPerUChar) {
+            cnv->maxBytesPerUChar=maxBytesPerUChar;
+        }
+    }
+
+#if 0
+    /*
+     * documentation of UConverter fields used for status
+     * all of these fields are (re)set to 0 by ucnv_bld.c and ucnv_reset()
+     */
+
+    /* toUnicode */
+    cnv->toUnicodeStatus=0;     /* offset */
+    cnv->mode=0;                /* state */
+    cnv->toULength=0;           /* byteIndex */
+
+    /* fromUnicode */
+    cnv->fromUChar32=0;
+    cnv->fromUnicodeStatus=1;   /* prevLength */
+#endif
+}
+
+static const char *
+ucnv_MBCSGetName(const UConverter *cnv) {
+    if((cnv->options&UCNV_OPTION_SWAP_LFNL)!=0 && cnv->sharedData->mbcs.swapLFNLName!=NULL) {
+        return cnv->sharedData->mbcs.swapLFNLName;
+    } else {
+        return cnv->sharedData->staticData->name;
+    }
+}
+
+/* MBCS-to-Unicode conversion functions ------------------------------------- */
+
+static UChar32
+ucnv_MBCSGetFallback(UConverterMBCSTable *mbcsTable, uint32_t offset) {
+    const _MBCSToUFallback *toUFallbacks;
+    uint32_t i, start, limit;
+
+    limit=mbcsTable->countToUFallbacks;
+    if(limit>0) {
+        /* do a binary search for the fallback mapping */
+        toUFallbacks=mbcsTable->toUFallbacks;
+        start=0;
+        while(start<limit-1) {
+            i=(start+limit)/2;
+            if(offset<toUFallbacks[i].offset) {
+                limit=i;
+            } else {
+                start=i;
+            }
+        }
+
+        /* did we really find it? */
+        if(offset==toUFallbacks[start].offset) {
+            return toUFallbacks[start].codePoint;
+        }
+    }
+
+    return 0xfffe;
+}
+
+/* This version of ucnv_MBCSToUnicodeWithOffsets() is optimized for single-byte, single-state codepages. */
+static void
+ucnv_MBCSSingleToUnicodeWithOffsets(UConverterToUnicodeArgs *pArgs,
+                                UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const uint8_t *source, *sourceLimit;
+    UChar *target;
+    const UChar *targetLimit;
+    int32_t *offsets;
+
+    const int32_t (*stateTable)[256];
+
+    int32_t sourceIndex;
+
+    int32_t entry;
+    UChar c;
+    uint8_t action;
+
+    /* set up the local pointers */
+    cnv=pArgs->converter;
+    source=(const uint8_t *)pArgs->source;
+    sourceLimit=(const uint8_t *)pArgs->sourceLimit;
+    target=pArgs->target;
+    targetLimit=pArgs->targetLimit;
+    offsets=pArgs->offsets;
+
+    if((cnv->options&UCNV_OPTION_SWAP_LFNL)!=0) {
+        stateTable=(const int32_t (*)[256])cnv->sharedData->mbcs.swapLFNLStateTable;
+    } else {
+        stateTable=cnv->sharedData->mbcs.stateTable;
+    }
+
+    /* sourceIndex=-1 if the current character began in the previous buffer */
+    sourceIndex=0;
+
+    /* conversion loop */
+    while(source<sourceLimit) {
+        /*
+         * This following test is to see if available input would overflow the output.
+         * It does not catch output of more than one code unit that
+         * overflows as a result of a surrogate pair or callback output
+         * from the last source byte.
+         * Therefore, those situations also test for overflows and will
+         * then break the loop, too.
+         */
+        if(target>=targetLimit) {
+            /* target is full */
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+
+        entry=stateTable[0][*source++];
+        /* MBCS_ENTRY_IS_FINAL(entry) */
+
+        /* test the most common case first */
+        if(MBCS_ENTRY_FINAL_IS_VALID_DIRECT_16(entry)) {
+            /* output BMP code point */
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            if(offsets!=NULL) {
+                *offsets++=sourceIndex;
+            }
+
+            /* normal end of action codes: prepare for a new character */
+            ++sourceIndex;
+            continue;
+        }
+
+        /*
+         * An if-else-if chain provides more reliable performance for
+         * the most common cases compared to a switch.
+         */
+        action=(uint8_t)(MBCS_ENTRY_FINAL_ACTION(entry));
+        if(action==MBCS_STATE_VALID_DIRECT_20 ||
+           (action==MBCS_STATE_FALLBACK_DIRECT_20 && UCNV_TO_U_USE_FALLBACK(cnv))
+        ) {
+            entry=MBCS_ENTRY_FINAL_VALUE(entry);
+            /* output surrogate pair */
+            *target++=(UChar)(0xd800|(UChar)(entry>>10));
+            if(offsets!=NULL) {
+                *offsets++=sourceIndex;
+            }
+            c=(UChar)(0xdc00|(UChar)(entry&0x3ff));
+            if(target<targetLimit) {
+                *target++=c;
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                }
+            } else {
+                /* target overflow */
+                cnv->UCharErrorBuffer[0]=c;
+                cnv->UCharErrorBufferLength=1;
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                break;
+            }
+
+            ++sourceIndex;
+            continue;
+        } else if(action==MBCS_STATE_FALLBACK_DIRECT_16) {
+            if(UCNV_TO_U_USE_FALLBACK(cnv)) {
+                /* output BMP code point */
+                *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                }
+
+                ++sourceIndex;
+                continue;
+            }
+        } else if(action==MBCS_STATE_UNASSIGNED) {
+            /* just fall through */
+        } else if(action==MBCS_STATE_ILLEGAL) {
+            /* callback(illegal) */
+            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+        } else {
+            /* reserved, must never occur */
+            ++sourceIndex;
+            continue;
+        }
+
+        if(U_FAILURE(*pErrorCode)) {
+            /* callback(illegal) */
+            break;
+        } else /* unassigned sequences indicated with byteIndex>0 */ {
+            /* try an extension mapping */
+            pArgs->source=(const char *)source;
+            cnv->toUBytes[0]=*(source-1);
+            cnv->toULength=_extToU(cnv, cnv->sharedData,
+                                    1, &source, sourceLimit,
+                                    &target, targetLimit,
+                                    &offsets, sourceIndex,
+                                    pArgs->flush,
+                                    pErrorCode);
+            sourceIndex+=1+(int32_t)(source-(const uint8_t *)pArgs->source);
+
+            if(U_FAILURE(*pErrorCode)) {
+                /* not mappable or buffer overflow */
+                break;
+            }
+        }
+    }
+
+    /* write back the updated pointers */
+    pArgs->source=(const char *)source;
+    pArgs->target=target;
+    pArgs->offsets=offsets;
+}
+
+/*
+ * This version of ucnv_MBCSSingleToUnicodeWithOffsets() is optimized for single-byte, single-state codepages
+ * that only map to and from the BMP.
+ * In addition to single-byte optimizations, the offset calculations
+ * become much easier.
+ */
+static void
+ucnv_MBCSSingleToBMPWithOffsets(UConverterToUnicodeArgs *pArgs,
+                            UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const uint8_t *source, *sourceLimit, *lastSource;
+    UChar *target;
+    int32_t targetCapacity, length;
+    int32_t *offsets;
+
+    const int32_t (*stateTable)[256];
+
+    int32_t sourceIndex;
+
+    int32_t entry;
+    uint8_t action;
+
+    /* set up the local pointers */
+    cnv=pArgs->converter;
+    source=(const uint8_t *)pArgs->source;
+    sourceLimit=(const uint8_t *)pArgs->sourceLimit;
+    target=pArgs->target;
+    targetCapacity=(int32_t)(pArgs->targetLimit-pArgs->target);
+    offsets=pArgs->offsets;
+
+    if((cnv->options&UCNV_OPTION_SWAP_LFNL)!=0) {
+        stateTable=(const int32_t (*)[256])cnv->sharedData->mbcs.swapLFNLStateTable;
+    } else {
+        stateTable=cnv->sharedData->mbcs.stateTable;
+    }
+
+    /* sourceIndex=-1 if the current character began in the previous buffer */
+    sourceIndex=0;
+    lastSource=source;
+
+    /*
+     * since the conversion here is 1:1 UChar:uint8_t, we need only one counter
+     * for the minimum of the sourceLength and targetCapacity
+     */
+    length=(int32_t)(sourceLimit-source);
+    if(length<targetCapacity) {
+        targetCapacity=length;
+    }
+
+#if MBCS_UNROLL_SINGLE_TO_BMP
+    /* unrolling makes it faster on Pentium III/Windows 2000 */
+    /* unroll the loop with the most common case */
+unrolled:
+    if(targetCapacity>=16) {
+        int32_t count, loops, oredEntries;
+
+        loops=count=targetCapacity>>4;
+        do {
+            oredEntries=entry=stateTable[0][*source++];
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            oredEntries|=entry=stateTable[0][*source++];
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            oredEntries|=entry=stateTable[0][*source++];
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            oredEntries|=entry=stateTable[0][*source++];
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            oredEntries|=entry=stateTable[0][*source++];
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            oredEntries|=entry=stateTable[0][*source++];
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            oredEntries|=entry=stateTable[0][*source++];
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            oredEntries|=entry=stateTable[0][*source++];
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            oredEntries|=entry=stateTable[0][*source++];
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            oredEntries|=entry=stateTable[0][*source++];
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            oredEntries|=entry=stateTable[0][*source++];
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            oredEntries|=entry=stateTable[0][*source++];
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            oredEntries|=entry=stateTable[0][*source++];
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            oredEntries|=entry=stateTable[0][*source++];
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            oredEntries|=entry=stateTable[0][*source++];
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            oredEntries|=entry=stateTable[0][*source++];
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+
+            /* were all 16 entries really valid? */
+            if(!MBCS_ENTRY_FINAL_IS_VALID_DIRECT_16(oredEntries)) {
+                /* no, return to the first of these 16 */
+                source-=16;
+                target-=16;
+                break;
+            }
+        } while(--count>0);
+        count=loops-count;
+        targetCapacity-=16*count;
+
+        if(offsets!=NULL) {
+            lastSource+=16*count;
+            while(count>0) {
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                --count;
+            }
+        }
+    }
+#endif
+
+    /* conversion loop */
+    while(targetCapacity > 0 && source < sourceLimit) {
+        entry=stateTable[0][*source++];
+        /* MBCS_ENTRY_IS_FINAL(entry) */
+
+        /* test the most common case first */
+        if(MBCS_ENTRY_FINAL_IS_VALID_DIRECT_16(entry)) {
+            /* output BMP code point */
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            --targetCapacity;
+            continue;
+        }
+
+        /*
+         * An if-else-if chain provides more reliable performance for
+         * the most common cases compared to a switch.
+         */
+        action=(uint8_t)(MBCS_ENTRY_FINAL_ACTION(entry));
+        if(action==MBCS_STATE_FALLBACK_DIRECT_16) {
+            if(UCNV_TO_U_USE_FALLBACK(cnv)) {
+                /* output BMP code point */
+                *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+                --targetCapacity;
+                continue;
+            }
+        } else if(action==MBCS_STATE_UNASSIGNED) {
+            /* just fall through */
+        } else if(action==MBCS_STATE_ILLEGAL) {
+            /* callback(illegal) */
+            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+        } else {
+            /* reserved, must never occur */
+            continue;
+        }
+
+        /* set offsets since the start or the last extension */
+        if(offsets!=NULL) {
+            int32_t count=(int32_t)(source-lastSource);
+
+            /* predecrement: do not set the offset for the callback-causing character */
+            while(--count>0) {
+                *offsets++=sourceIndex++;
+            }
+            /* offset and sourceIndex are now set for the current character */
+        }
+
+        if(U_FAILURE(*pErrorCode)) {
+            /* callback(illegal) */
+            break;
+        } else /* unassigned sequences indicated with byteIndex>0 */ {
+            /* try an extension mapping */
+            lastSource=source;
+            cnv->toUBytes[0]=*(source-1);
+            cnv->toULength=_extToU(cnv, cnv->sharedData,
+                                    1, &source, sourceLimit,
+                                    &target, pArgs->targetLimit,
+                                    &offsets, sourceIndex,
+                                    pArgs->flush,
+                                    pErrorCode);
+            sourceIndex+=1+(int32_t)(source-lastSource);
+
+            if(U_FAILURE(*pErrorCode)) {
+                /* not mappable or buffer overflow */
+                break;
+            }
+
+            /* recalculate the targetCapacity after an extension mapping */
+            targetCapacity=(int32_t)(pArgs->targetLimit-target);
+            length=(int32_t)(sourceLimit-source);
+            if(length<targetCapacity) {
+                targetCapacity=length;
+            }
+        }
+
+#if MBCS_UNROLL_SINGLE_TO_BMP
+        /* unrolling makes it faster on Pentium III/Windows 2000 */
+        goto unrolled;
+#endif
+    }
+
+    if(U_SUCCESS(*pErrorCode) && source<sourceLimit && target>=pArgs->targetLimit) {
+        /* target is full */
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    /* set offsets since the start or the last callback */
+    if(offsets!=NULL) {
+        size_t count=source-lastSource;
+        while(count>0) {
+            *offsets++=sourceIndex++;
+            --count;
+        }
+    }
+
+    /* write back the updated pointers */
+    pArgs->source=(const char *)source;
+    pArgs->target=target;
+    pArgs->offsets=offsets;
+}
+
+static UBool
+hasValidTrailBytes(const int32_t (*stateTable)[256], uint8_t state) {
+    const int32_t *row=stateTable[state];
+    int32_t b, entry;
+    /* First test for final entries in this state for some commonly valid byte values. */
+    entry=row[0xa1];
+    if( !MBCS_ENTRY_IS_TRANSITION(entry) &&
+        MBCS_ENTRY_FINAL_ACTION(entry)!=MBCS_STATE_ILLEGAL
+    ) {
+        return TRUE;
+    }
+    entry=row[0x41];
+    if( !MBCS_ENTRY_IS_TRANSITION(entry) &&
+        MBCS_ENTRY_FINAL_ACTION(entry)!=MBCS_STATE_ILLEGAL
+    ) {
+        return TRUE;
+    }
+    /* Then test for final entries in this state. */
+    for(b=0; b<=0xff; ++b) {
+        entry=row[b];
+        if( !MBCS_ENTRY_IS_TRANSITION(entry) &&
+            MBCS_ENTRY_FINAL_ACTION(entry)!=MBCS_STATE_ILLEGAL
+        ) {
+            return TRUE;
+        }
+    }
+    /* Then recurse for transition entries. */
+    for(b=0; b<=0xff; ++b) {
+        entry=row[b];
+        if( MBCS_ENTRY_IS_TRANSITION(entry) &&
+            hasValidTrailBytes(stateTable, (uint8_t)MBCS_ENTRY_TRANSITION_STATE(entry))
+        ) {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+/*
+ * Is byte b a single/lead byte in this state?
+ * Recurse for transition states, because here we don't want to say that
+ * b is a lead byte if all byte sequences that start with b are illegal.
+ */
+static UBool
+isSingleOrLead(const int32_t (*stateTable)[256], uint8_t state, UBool isDBCSOnly, uint8_t b) {
+    const int32_t *row=stateTable[state];
+    int32_t entry=row[b];
+    if(MBCS_ENTRY_IS_TRANSITION(entry)) {   /* lead byte */
+        return hasValidTrailBytes(stateTable, (uint8_t)MBCS_ENTRY_TRANSITION_STATE(entry));
+    } else {
+        uint8_t action=(uint8_t)(MBCS_ENTRY_FINAL_ACTION(entry));
+        if(action==MBCS_STATE_CHANGE_ONLY && isDBCSOnly) {
+            return FALSE;   /* SI/SO are illegal for DBCS-only conversion */
+        } else {
+            return action!=MBCS_STATE_ILLEGAL;
+        }
+    }
+}
+
+U_CFUNC void
+ucnv_MBCSToUnicodeWithOffsets(UConverterToUnicodeArgs *pArgs,
+                          UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const uint8_t *source, *sourceLimit;
+    UChar *target;
+    const UChar *targetLimit;
+    int32_t *offsets;
+
+    const int32_t (*stateTable)[256];
+    const uint16_t *unicodeCodeUnits;
+
+    uint32_t offset;
+    uint8_t state;
+    int8_t byteIndex;
+    uint8_t *bytes;
+
+    int32_t sourceIndex, nextSourceIndex;
+
+    int32_t entry;
+    UChar c;
+    uint8_t action;
+
+    /* use optimized function if possible */
+    cnv=pArgs->converter;
+
+    if(cnv->preToULength>0) {
+        /*
+         * pass sourceIndex=-1 because we continue from an earlier buffer
+         * in the future, this may change with continuous offsets
+         */
+        ucnv_extContinueMatchToU(cnv, pArgs, -1, pErrorCode);
+
+        if(U_FAILURE(*pErrorCode) || cnv->preToULength<0) {
+            return;
+        }
+    }
+
+    if(cnv->sharedData->mbcs.countStates==1) {
+        if(!(cnv->sharedData->mbcs.unicodeMask&UCNV_HAS_SUPPLEMENTARY)) {
+            ucnv_MBCSSingleToBMPWithOffsets(pArgs, pErrorCode);
+        } else {
+            ucnv_MBCSSingleToUnicodeWithOffsets(pArgs, pErrorCode);
+        }
+        return;
+    }
+
+    /* set up the local pointers */
+    source=(const uint8_t *)pArgs->source;
+    sourceLimit=(const uint8_t *)pArgs->sourceLimit;
+    target=pArgs->target;
+    targetLimit=pArgs->targetLimit;
+    offsets=pArgs->offsets;
+
+    if((cnv->options&UCNV_OPTION_SWAP_LFNL)!=0) {
+        stateTable=(const int32_t (*)[256])cnv->sharedData->mbcs.swapLFNLStateTable;
+    } else {
+        stateTable=cnv->sharedData->mbcs.stateTable;
+    }
+    unicodeCodeUnits=cnv->sharedData->mbcs.unicodeCodeUnits;
+
+    /* get the converter state from UConverter */
+    offset=cnv->toUnicodeStatus;
+    byteIndex=cnv->toULength;
+    bytes=cnv->toUBytes;
+
+    /*
+     * if we are in the SBCS state for a DBCS-only converter,
+     * then load the DBCS state from the MBCS data
+     * (dbcsOnlyState==0 if it is not a DBCS-only converter)
+     */
+    if((state=(uint8_t)(cnv->mode))==0) {
+        state=cnv->sharedData->mbcs.dbcsOnlyState;
+    }
+
+    /* sourceIndex=-1 if the current character began in the previous buffer */
+    sourceIndex=byteIndex==0 ? 0 : -1;
+    nextSourceIndex=0;
+
+    /* conversion loop */
+    while(source<sourceLimit) {
+        /*
+         * This following test is to see if available input would overflow the output.
+         * It does not catch output of more than one code unit that
+         * overflows as a result of a surrogate pair or callback output
+         * from the last source byte.
+         * Therefore, those situations also test for overflows and will
+         * then break the loop, too.
+         */
+        if(target>=targetLimit) {
+            /* target is full */
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+
+        if(byteIndex==0) {
+            /* optimized loop for 1/2-byte input and BMP output */
+            if(offsets==NULL) {
+                do {
+                    entry=stateTable[state][*source];
+                    if(MBCS_ENTRY_IS_TRANSITION(entry)) {
+                        state=(uint8_t)MBCS_ENTRY_TRANSITION_STATE(entry);
+                        offset=MBCS_ENTRY_TRANSITION_OFFSET(entry);
+
+                        ++source;
+                        if( source<sourceLimit &&
+                            MBCS_ENTRY_IS_FINAL(entry=stateTable[state][*source]) &&
+                            MBCS_ENTRY_FINAL_ACTION(entry)==MBCS_STATE_VALID_16 &&
+                            (c=unicodeCodeUnits[offset+MBCS_ENTRY_FINAL_VALUE_16(entry)])<0xfffe
+                        ) {
+                            ++source;
+                            *target++=c;
+                            state=(uint8_t)MBCS_ENTRY_FINAL_STATE(entry); /* typically 0 */
+                            offset=0;
+                        } else {
+                            /* set the state and leave the optimized loop */
+                            bytes[0]=*(source-1);
+                            byteIndex=1;
+                            break;
+                        }
+                    } else {
+                        if(MBCS_ENTRY_FINAL_IS_VALID_DIRECT_16(entry)) {
+                            /* output BMP code point */
+                            ++source;
+                            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+                            state=(uint8_t)MBCS_ENTRY_FINAL_STATE(entry); /* typically 0 */
+                        } else {
+                            /* leave the optimized loop */
+                            break;
+                        }
+                    }
+                } while(source<sourceLimit && target<targetLimit);
+            } else /* offsets!=NULL */ {
+                do {
+                    entry=stateTable[state][*source];
+                    if(MBCS_ENTRY_IS_TRANSITION(entry)) {
+                        state=(uint8_t)MBCS_ENTRY_TRANSITION_STATE(entry);
+                        offset=MBCS_ENTRY_TRANSITION_OFFSET(entry);
+
+                        ++source;
+                        if( source<sourceLimit &&
+                            MBCS_ENTRY_IS_FINAL(entry=stateTable[state][*source]) &&
+                            MBCS_ENTRY_FINAL_ACTION(entry)==MBCS_STATE_VALID_16 &&
+                            (c=unicodeCodeUnits[offset+MBCS_ENTRY_FINAL_VALUE_16(entry)])<0xfffe
+                        ) {
+                            ++source;
+                            *target++=c;
+                            if(offsets!=NULL) {
+                                *offsets++=sourceIndex;
+                                sourceIndex=(nextSourceIndex+=2);
+                            }
+                            state=(uint8_t)MBCS_ENTRY_FINAL_STATE(entry); /* typically 0 */
+                            offset=0;
+                        } else {
+                            /* set the state and leave the optimized loop */
+                            ++nextSourceIndex;
+                            bytes[0]=*(source-1);
+                            byteIndex=1;
+                            break;
+                        }
+                    } else {
+                        if(MBCS_ENTRY_FINAL_IS_VALID_DIRECT_16(entry)) {
+                            /* output BMP code point */
+                            ++source;
+                            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+                            if(offsets!=NULL) {
+                                *offsets++=sourceIndex;
+                                sourceIndex=++nextSourceIndex;
+                            }
+                            state=(uint8_t)MBCS_ENTRY_FINAL_STATE(entry); /* typically 0 */
+                        } else {
+                            /* leave the optimized loop */
+                            break;
+                        }
+                    }
+                } while(source<sourceLimit && target<targetLimit);
+            }
+
+            /*
+             * these tests and break statements could be put inside the loop
+             * if C had "break outerLoop" like Java
+             */
+            if(source>=sourceLimit) {
+                break;
+            }
+            if(target>=targetLimit) {
+                /* target is full */
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                break;
+            }
+
+            ++nextSourceIndex;
+            bytes[byteIndex++]=*source++;
+        } else /* byteIndex>0 */ {
+            ++nextSourceIndex;
+            entry=stateTable[state][bytes[byteIndex++]=*source++];
+        }
+
+        if(MBCS_ENTRY_IS_TRANSITION(entry)) {
+            state=(uint8_t)MBCS_ENTRY_TRANSITION_STATE(entry);
+            offset+=MBCS_ENTRY_TRANSITION_OFFSET(entry);
+            continue;
+        }
+
+        /* save the previous state for proper extension mapping with SI/SO-stateful converters */
+        cnv->mode=state;
+
+        /* set the next state early so that we can reuse the entry variable */
+        state=(uint8_t)MBCS_ENTRY_FINAL_STATE(entry); /* typically 0 */
+
+        /*
+         * An if-else-if chain provides more reliable performance for
+         * the most common cases compared to a switch.
+         */
+        action=(uint8_t)(MBCS_ENTRY_FINAL_ACTION(entry));
+        if(action==MBCS_STATE_VALID_16) {
+            offset+=MBCS_ENTRY_FINAL_VALUE_16(entry);
+            c=unicodeCodeUnits[offset];
+            if(c<0xfffe) {
+                /* output BMP code point */
+                *target++=c;
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                }
+                byteIndex=0;
+            } else if(c==0xfffe) {
+                if(UCNV_TO_U_USE_FALLBACK(cnv) && (entry=(int32_t)ucnv_MBCSGetFallback(&cnv->sharedData->mbcs, offset))!=0xfffe) {
+                    /* output fallback BMP code point */
+                    *target++=(UChar)entry;
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex;
+                    }
+                    byteIndex=0;
+                }
+            } else {
+                /* callback(illegal) */
+                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+            }
+        } else if(action==MBCS_STATE_VALID_DIRECT_16) {
+            /* output BMP code point */
+            *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            if(offsets!=NULL) {
+                *offsets++=sourceIndex;
+            }
+            byteIndex=0;
+        } else if(action==MBCS_STATE_VALID_16_PAIR) {
+            offset+=MBCS_ENTRY_FINAL_VALUE_16(entry);
+            c=unicodeCodeUnits[offset++];
+            if(c<0xd800) {
+                /* output BMP code point below 0xd800 */
+                *target++=c;
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                }
+                byteIndex=0;
+            } else if(UCNV_TO_U_USE_FALLBACK(cnv) ? c<=0xdfff : c<=0xdbff) {
+                /* output roundtrip or fallback surrogate pair */
+                *target++=(UChar)(c&0xdbff);
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                }
+                byteIndex=0;
+                if(target<targetLimit) {
+                    *target++=unicodeCodeUnits[offset];
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex;
+                    }
+                } else {
+                    /* target overflow */
+                    cnv->UCharErrorBuffer[0]=unicodeCodeUnits[offset];
+                    cnv->UCharErrorBufferLength=1;
+                    *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+
+                    offset=0;
+                    break;
+                }
+            } else if(UCNV_TO_U_USE_FALLBACK(cnv) ? (c&0xfffe)==0xe000 : c==0xe000) {
+                /* output roundtrip BMP code point above 0xd800 or fallback BMP code point */
+                *target++=unicodeCodeUnits[offset];
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                }
+                byteIndex=0;
+            } else if(c==0xffff) {
+                /* callback(illegal) */
+                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+            }
+        } else if(action==MBCS_STATE_VALID_DIRECT_20 ||
+                  (action==MBCS_STATE_FALLBACK_DIRECT_20 && UCNV_TO_U_USE_FALLBACK(cnv))
+        ) {
+            entry=MBCS_ENTRY_FINAL_VALUE(entry);
+            /* output surrogate pair */
+            *target++=(UChar)(0xd800|(UChar)(entry>>10));
+            if(offsets!=NULL) {
+                *offsets++=sourceIndex;
+            }
+            byteIndex=0;
+            c=(UChar)(0xdc00|(UChar)(entry&0x3ff));
+            if(target<targetLimit) {
+                *target++=c;
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                }
+            } else {
+                /* target overflow */
+                cnv->UCharErrorBuffer[0]=c;
+                cnv->UCharErrorBufferLength=1;
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+
+                offset=0;
+                break;
+            }
+        } else if(action==MBCS_STATE_CHANGE_ONLY) {
+            /*
+             * This serves as a state change without any output.
+             * It is useful for reading simple stateful encodings,
+             * for example using just Shift-In/Shift-Out codes.
+             * The 21 unused bits may later be used for more sophisticated
+             * state transitions.
+             */
+            if(cnv->sharedData->mbcs.dbcsOnlyState==0) {
+                byteIndex=0;
+            } else {
+                /* SI/SO are illegal for DBCS-only conversion */
+                state=(uint8_t)(cnv->mode); /* restore the previous state */
+
+                /* callback(illegal) */
+                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+            }
+        } else if(action==MBCS_STATE_FALLBACK_DIRECT_16) {
+            if(UCNV_TO_U_USE_FALLBACK(cnv)) {
+                /* output BMP code point */
+                *target++=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                }
+                byteIndex=0;
+            }
+        } else if(action==MBCS_STATE_UNASSIGNED) {
+            /* just fall through */
+        } else if(action==MBCS_STATE_ILLEGAL) {
+            /* callback(illegal) */
+            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+        } else {
+            /* reserved, must never occur */
+            byteIndex=0;
+        }
+
+        /* end of action codes: prepare for a new character */
+        offset=0;
+
+        if(byteIndex==0) {
+            sourceIndex=nextSourceIndex;
+        } else if(U_FAILURE(*pErrorCode)) {
+            /* callback(illegal) */
+            if(byteIndex>1) {
+                /*
+                 * Ticket 5691: consistent illegal sequences:
+                 * - We include at least the first byte in the illegal sequence.
+                 * - If any of the non-initial bytes could be the start of a character,
+                 *   we stop the illegal sequence before the first one of those.
+                 */
+                UBool isDBCSOnly=(UBool)(cnv->sharedData->mbcs.dbcsOnlyState!=0);
+                int8_t i;
+                for(i=1;
+                    i<byteIndex && !isSingleOrLead(stateTable, state, isDBCSOnly, bytes[i]);
+                    ++i) {}
+                if(i<byteIndex) {
+                    /* Back out some bytes. */
+                    int8_t backOutDistance=byteIndex-i;
+                    int32_t bytesFromThisBuffer=(int32_t)(source-(const uint8_t *)pArgs->source);
+                    byteIndex=i;  /* length of reported illegal byte sequence */
+                    if(backOutDistance<=bytesFromThisBuffer) {
+                        source-=backOutDistance;
+                    } else {
+                        /* Back out bytes from the previous buffer: Need to replay them. */
+                        cnv->preToULength=(int8_t)(bytesFromThisBuffer-backOutDistance);
+                        /* preToULength is negative! */
+                        uprv_memcpy(cnv->preToU, bytes+i, -cnv->preToULength);
+                        source=(const uint8_t *)pArgs->source;
+                    }
+                }
+            }
+            break;
+        } else /* unassigned sequences indicated with byteIndex>0 */ {
+            /* try an extension mapping */
+            pArgs->source=(const char *)source;
+            byteIndex=_extToU(cnv, cnv->sharedData,
+                              byteIndex, &source, sourceLimit,
+                              &target, targetLimit,
+                              &offsets, sourceIndex,
+                              pArgs->flush,
+                              pErrorCode);
+            sourceIndex=nextSourceIndex+=(int32_t)(source-(const uint8_t *)pArgs->source);
+
+            if(U_FAILURE(*pErrorCode)) {
+                /* not mappable or buffer overflow */
+                break;
+            }
+        }
+    }
+
+    /* set the converter state back into UConverter */
+    cnv->toUnicodeStatus=offset;
+    cnv->mode=state;
+    cnv->toULength=byteIndex;
+
+    /* write back the updated pointers */
+    pArgs->source=(const char *)source;
+    pArgs->target=target;
+    pArgs->offsets=offsets;
+}
+
+/*
+ * This version of ucnv_MBCSGetNextUChar() is optimized for single-byte, single-state codepages.
+ * We still need a conversion loop in case we find reserved action codes, which are to be ignored.
+ */
+static UChar32
+ucnv_MBCSSingleGetNextUChar(UConverterToUnicodeArgs *pArgs,
+                        UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const int32_t (*stateTable)[256];
+    const uint8_t *source, *sourceLimit;
+
+    int32_t entry;
+    uint8_t action;
+
+    /* set up the local pointers */
+    cnv=pArgs->converter;
+    source=(const uint8_t *)pArgs->source;
+    sourceLimit=(const uint8_t *)pArgs->sourceLimit;
+    if((cnv->options&UCNV_OPTION_SWAP_LFNL)!=0) {
+        stateTable=(const int32_t (*)[256])cnv->sharedData->mbcs.swapLFNLStateTable;
+    } else {
+        stateTable=cnv->sharedData->mbcs.stateTable;
+    }
+
+    /* conversion loop */
+    while(source<sourceLimit) {
+        entry=stateTable[0][*source++];
+        /* MBCS_ENTRY_IS_FINAL(entry) */
+
+        /* write back the updated pointer early so that we can return directly */
+        pArgs->source=(const char *)source;
+
+        if(MBCS_ENTRY_FINAL_IS_VALID_DIRECT_16(entry)) {
+            /* output BMP code point */
+            return (UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+        }
+
+        /*
+         * An if-else-if chain provides more reliable performance for
+         * the most common cases compared to a switch.
+         */
+        action=(uint8_t)(MBCS_ENTRY_FINAL_ACTION(entry));
+        if( action==MBCS_STATE_VALID_DIRECT_20 ||
+            (action==MBCS_STATE_FALLBACK_DIRECT_20 && UCNV_TO_U_USE_FALLBACK(cnv))
+        ) {
+            /* output supplementary code point */
+            return (UChar32)(MBCS_ENTRY_FINAL_VALUE(entry)+0x10000);
+        } else if(action==MBCS_STATE_FALLBACK_DIRECT_16) {
+            if(UCNV_TO_U_USE_FALLBACK(cnv)) {
+                /* output BMP code point */
+                return (UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+            }
+        } else if(action==MBCS_STATE_UNASSIGNED) {
+            /* just fall through */
+        } else if(action==MBCS_STATE_ILLEGAL) {
+            /* callback(illegal) */
+            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+        } else {
+            /* reserved, must never occur */
+            continue;
+        }
+
+        if(U_FAILURE(*pErrorCode)) {
+            /* callback(illegal) */
+            break;
+        } else /* unassigned sequence */ {
+            /* defer to the generic implementation */
+            pArgs->source=(const char *)source-1;
+            return UCNV_GET_NEXT_UCHAR_USE_TO_U;
+        }
+    }
+
+    /* no output because of empty input or only state changes */
+    *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+    return 0xffff;
+}
+
+/*
+ * Version of _MBCSToUnicodeWithOffsets() optimized for single-character
+ * conversion without offset handling.
+ *
+ * When a character does not have a mapping to Unicode, then we return to the
+ * generic ucnv_getNextUChar() code for extension/GB 18030 and error/callback
+ * handling.
+ * We also defer to the generic code in other complicated cases and have them
+ * ultimately handled by _MBCSToUnicodeWithOffsets() itself.
+ *
+ * All normal mappings and errors are handled here.
+ */
+static UChar32
+ucnv_MBCSGetNextUChar(UConverterToUnicodeArgs *pArgs,
+                  UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const uint8_t *source, *sourceLimit, *lastSource;
+
+    const int32_t (*stateTable)[256];
+    const uint16_t *unicodeCodeUnits;
+
+    uint32_t offset;
+    uint8_t state;
+
+    int32_t entry;
+    UChar32 c;
+    uint8_t action;
+
+    /* use optimized function if possible */
+    cnv=pArgs->converter;
+
+    if(cnv->preToULength>0) {
+        /* use the generic code in ucnv_getNextUChar() to continue with a partial match */
+        return UCNV_GET_NEXT_UCHAR_USE_TO_U;
+    }
+
+    if(cnv->sharedData->mbcs.unicodeMask&UCNV_HAS_SURROGATES) {
+        /*
+         * Using the generic ucnv_getNextUChar() code lets us deal correctly
+         * with the rare case of a codepage that maps single surrogates
+         * without adding the complexity to this already complicated function here.
+         */
+        return UCNV_GET_NEXT_UCHAR_USE_TO_U;
+    } else if(cnv->sharedData->mbcs.countStates==1) {
+        return ucnv_MBCSSingleGetNextUChar(pArgs, pErrorCode);
+    }
+
+    /* set up the local pointers */
+    source=lastSource=(const uint8_t *)pArgs->source;
+    sourceLimit=(const uint8_t *)pArgs->sourceLimit;
+
+    if((cnv->options&UCNV_OPTION_SWAP_LFNL)!=0) {
+        stateTable=(const int32_t (*)[256])cnv->sharedData->mbcs.swapLFNLStateTable;
+    } else {
+        stateTable=cnv->sharedData->mbcs.stateTable;
+    }
+    unicodeCodeUnits=cnv->sharedData->mbcs.unicodeCodeUnits;
+
+    /* get the converter state from UConverter */
+    offset=cnv->toUnicodeStatus;
+
+    /*
+     * if we are in the SBCS state for a DBCS-only converter,
+     * then load the DBCS state from the MBCS data
+     * (dbcsOnlyState==0 if it is not a DBCS-only converter)
+     */
+    if((state=(uint8_t)(cnv->mode))==0) {
+        state=cnv->sharedData->mbcs.dbcsOnlyState;
+    }
+
+    /* conversion loop */
+    c=U_SENTINEL;
+    while(source<sourceLimit) {
+        entry=stateTable[state][*source++];
+        if(MBCS_ENTRY_IS_TRANSITION(entry)) {
+            state=(uint8_t)MBCS_ENTRY_TRANSITION_STATE(entry);
+            offset+=MBCS_ENTRY_TRANSITION_OFFSET(entry);
+
+            /* optimization for 1/2-byte input and BMP output */
+            if( source<sourceLimit &&
+                MBCS_ENTRY_IS_FINAL(entry=stateTable[state][*source]) &&
+                MBCS_ENTRY_FINAL_ACTION(entry)==MBCS_STATE_VALID_16 &&
+                (c=unicodeCodeUnits[offset+MBCS_ENTRY_FINAL_VALUE_16(entry)])<0xfffe
+            ) {
+                ++source;
+                state=(uint8_t)MBCS_ENTRY_FINAL_STATE(entry); /* typically 0 */
+                /* output BMP code point */
+                break;
+            }
+        } else {
+            /* save the previous state for proper extension mapping with SI/SO-stateful converters */
+            cnv->mode=state;
+
+            /* set the next state early so that we can reuse the entry variable */
+            state=(uint8_t)MBCS_ENTRY_FINAL_STATE(entry); /* typically 0 */
+
+            /*
+             * An if-else-if chain provides more reliable performance for
+             * the most common cases compared to a switch.
+             */
+            action=(uint8_t)(MBCS_ENTRY_FINAL_ACTION(entry));
+            if(action==MBCS_STATE_VALID_DIRECT_16) {
+                /* output BMP code point */
+                c=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+                break;
+            } else if(action==MBCS_STATE_VALID_16) {
+                offset+=MBCS_ENTRY_FINAL_VALUE_16(entry);
+                c=unicodeCodeUnits[offset];
+                if(c<0xfffe) {
+                    /* output BMP code point */
+                    break;
+                } else if(c==0xfffe) {
+                    if(UCNV_TO_U_USE_FALLBACK(cnv) && (c=ucnv_MBCSGetFallback(&cnv->sharedData->mbcs, offset))!=0xfffe) {
+                        break;
+                    }
+                } else {
+                    /* callback(illegal) */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                }
+            } else if(action==MBCS_STATE_VALID_16_PAIR) {
+                offset+=MBCS_ENTRY_FINAL_VALUE_16(entry);
+                c=unicodeCodeUnits[offset++];
+                if(c<0xd800) {
+                    /* output BMP code point below 0xd800 */
+                    break;
+                } else if(UCNV_TO_U_USE_FALLBACK(cnv) ? c<=0xdfff : c<=0xdbff) {
+                    /* output roundtrip or fallback supplementary code point */
+                    c=((c&0x3ff)<<10)+unicodeCodeUnits[offset]+(0x10000-0xdc00);
+                    break;
+                } else if(UCNV_TO_U_USE_FALLBACK(cnv) ? (c&0xfffe)==0xe000 : c==0xe000) {
+                    /* output roundtrip BMP code point above 0xd800 or fallback BMP code point */
+                    c=unicodeCodeUnits[offset];
+                    break;
+                } else if(c==0xffff) {
+                    /* callback(illegal) */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                }
+            } else if(action==MBCS_STATE_VALID_DIRECT_20 ||
+                      (action==MBCS_STATE_FALLBACK_DIRECT_20 && UCNV_TO_U_USE_FALLBACK(cnv))
+            ) {
+                /* output supplementary code point */
+                c=(UChar32)(MBCS_ENTRY_FINAL_VALUE(entry)+0x10000);
+                break;
+            } else if(action==MBCS_STATE_CHANGE_ONLY) {
+                /*
+                 * This serves as a state change without any output.
+                 * It is useful for reading simple stateful encodings,
+                 * for example using just Shift-In/Shift-Out codes.
+                 * The 21 unused bits may later be used for more sophisticated
+                 * state transitions.
+                 */
+                if(cnv->sharedData->mbcs.dbcsOnlyState!=0) {
+                    /* SI/SO are illegal for DBCS-only conversion */
+                    state=(uint8_t)(cnv->mode); /* restore the previous state */
+
+                    /* callback(illegal) */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                }
+            } else if(action==MBCS_STATE_FALLBACK_DIRECT_16) {
+                if(UCNV_TO_U_USE_FALLBACK(cnv)) {
+                    /* output BMP code point */
+                    c=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+                    break;
+                }
+            } else if(action==MBCS_STATE_UNASSIGNED) {
+                /* just fall through */
+            } else if(action==MBCS_STATE_ILLEGAL) {
+                /* callback(illegal) */
+                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+            } else {
+                /* reserved (must never occur), or only state change */
+                offset=0;
+                lastSource=source;
+                continue;
+            }
+
+            /* end of action codes: prepare for a new character */
+            offset=0;
+
+            if(U_FAILURE(*pErrorCode)) {
+                /* callback(illegal) */
+                break;
+            } else /* unassigned sequence */ {
+                /* defer to the generic implementation */
+                cnv->toUnicodeStatus=0;
+                cnv->mode=state;
+                pArgs->source=(const char *)lastSource;
+                return UCNV_GET_NEXT_UCHAR_USE_TO_U;
+            }
+        }
+    }
+
+    if(c<0) {
+        if(U_SUCCESS(*pErrorCode) && source==sourceLimit && lastSource<source) {
+            /* incomplete character byte sequence */
+            uint8_t *bytes=cnv->toUBytes;
+            cnv->toULength=(int8_t)(source-lastSource);
+            do {
+                *bytes++=*lastSource++;
+            } while(lastSource<source);
+            *pErrorCode=U_TRUNCATED_CHAR_FOUND;
+        } else if(U_FAILURE(*pErrorCode)) {
+            /* callback(illegal) */
+            /*
+             * Ticket 5691: consistent illegal sequences:
+             * - We include at least the first byte in the illegal sequence.
+             * - If any of the non-initial bytes could be the start of a character,
+             *   we stop the illegal sequence before the first one of those.
+             */
+            UBool isDBCSOnly=(UBool)(cnv->sharedData->mbcs.dbcsOnlyState!=0);
+            uint8_t *bytes=cnv->toUBytes;
+            *bytes++=*lastSource++;     /* first byte */
+            if(lastSource==source) {
+                cnv->toULength=1;
+            } else /* lastSource<source: multi-byte character */ {
+                int8_t i;
+                for(i=1;
+                    lastSource<source && !isSingleOrLead(stateTable, state, isDBCSOnly, *lastSource);
+                    ++i
+                ) {
+                    *bytes++=*lastSource++;
+                }
+                cnv->toULength=i;
+                source=lastSource;
+            }
+        } else {
+            /* no output because of empty input or only state changes */
+            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+        }
+        c=0xffff;
+    }
+
+    /* set the converter state back into UConverter, ready for a new character */
+    cnv->toUnicodeStatus=0;
+    cnv->mode=state;
+
+    /* write back the updated pointer */
+    pArgs->source=(const char *)source;
+    return c;
+}
+
+#if 0
+/*
+ * Code disabled 2002dec09 (ICU 2.4) because it is not currently used in ICU. markus
+ * Removal improves code coverage.
+ */
+/**
+ * This version of ucnv_MBCSSimpleGetNextUChar() is optimized for single-byte, single-state codepages.
+ * It does not handle the EBCDIC swaplfnl option (set in UConverter).
+ * It does not handle conversion extensions (_extToU()).
+ */
+U_CFUNC UChar32
+ucnv_MBCSSingleSimpleGetNextUChar(UConverterSharedData *sharedData,
+                              uint8_t b, UBool useFallback) {
+    int32_t entry;
+    uint8_t action;
+
+    entry=sharedData->mbcs.stateTable[0][b];
+    /* MBCS_ENTRY_IS_FINAL(entry) */
+
+    if(MBCS_ENTRY_FINAL_IS_VALID_DIRECT_16(entry)) {
+        /* output BMP code point */
+        return (UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+    }
+
+    /*
+     * An if-else-if chain provides more reliable performance for
+     * the most common cases compared to a switch.
+     */
+    action=(uint8_t)(MBCS_ENTRY_FINAL_ACTION(entry));
+    if(action==MBCS_STATE_VALID_DIRECT_20) {
+        /* output supplementary code point */
+        return 0x10000+MBCS_ENTRY_FINAL_VALUE(entry);
+    } else if(action==MBCS_STATE_FALLBACK_DIRECT_16) {
+        if(!TO_U_USE_FALLBACK(useFallback)) {
+            return 0xfffe;
+        }
+        /* output BMP code point */
+        return (UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+    } else if(action==MBCS_STATE_FALLBACK_DIRECT_20) {
+        if(!TO_U_USE_FALLBACK(useFallback)) {
+            return 0xfffe;
+        }
+        /* output supplementary code point */
+        return 0x10000+MBCS_ENTRY_FINAL_VALUE(entry);
+    } else if(action==MBCS_STATE_UNASSIGNED) {
+        return 0xfffe;
+    } else if(action==MBCS_STATE_ILLEGAL) {
+        return 0xffff;
+    } else {
+        /* reserved, must never occur */
+        return 0xffff;
+    }
+}
+#endif
+
+/*
+ * This is a simple version of _MBCSGetNextUChar() that is used
+ * by other converter implementations.
+ * It only returns an "assigned" result if it consumes the entire input.
+ * It does not use state from the converter, nor error codes.
+ * It does not handle the EBCDIC swaplfnl option (set in UConverter).
+ * It handles conversion extensions but not GB 18030.
+ *
+ * Return value:
+ * U+fffe   unassigned
+ * U+ffff   illegal
+ * otherwise the Unicode code point
+ */
+U_CFUNC UChar32
+ucnv_MBCSSimpleGetNextUChar(UConverterSharedData *sharedData,
+                        const char *source, int32_t length,
+                        UBool useFallback) {
+    const int32_t (*stateTable)[256];
+    const uint16_t *unicodeCodeUnits;
+
+    uint32_t offset;
+    uint8_t state, action;
+
+    UChar32 c;
+    int32_t i, entry;
+
+    if(length<=0) {
+        /* no input at all: "illegal" */
+        return 0xffff;
+    }
+
+#if 0
+/*
+ * Code disabled 2002dec09 (ICU 2.4) because it is not currently used in ICU. markus
+ * TODO In future releases, verify that this function is never called for SBCS
+ * conversions, i.e., that sharedData->mbcs.countStates==1 is still true.
+ * Removal improves code coverage.
+ */
+    /* use optimized function if possible */
+    if(sharedData->mbcs.countStates==1) {
+        if(length==1) {
+            return ucnv_MBCSSingleSimpleGetNextUChar(sharedData, (uint8_t)*source, useFallback);
+        } else {
+            return 0xffff; /* illegal: more than a single byte for an SBCS converter */
+        }
+    }
+#endif
+
+    /* set up the local pointers */
+    stateTable=sharedData->mbcs.stateTable;
+    unicodeCodeUnits=sharedData->mbcs.unicodeCodeUnits;
+
+    /* converter state */
+    offset=0;
+    state=sharedData->mbcs.dbcsOnlyState;
+
+    /* conversion loop */
+    for(i=0;;) {
+        entry=stateTable[state][(uint8_t)source[i++]];
+        if(MBCS_ENTRY_IS_TRANSITION(entry)) {
+            state=(uint8_t)MBCS_ENTRY_TRANSITION_STATE(entry);
+            offset+=MBCS_ENTRY_TRANSITION_OFFSET(entry);
+
+            if(i==length) {
+                return 0xffff; /* truncated character */
+            }
+        } else {
+            /*
+             * An if-else-if chain provides more reliable performance for
+             * the most common cases compared to a switch.
+             */
+            action=(uint8_t)(MBCS_ENTRY_FINAL_ACTION(entry));
+            if(action==MBCS_STATE_VALID_16) {
+                offset+=MBCS_ENTRY_FINAL_VALUE_16(entry);
+                c=unicodeCodeUnits[offset];
+                if(c!=0xfffe) {
+                    /* done */
+                } else if(UCNV_TO_U_USE_FALLBACK(cnv)) {
+                    c=ucnv_MBCSGetFallback(&sharedData->mbcs, offset);
+                /* else done with 0xfffe */
+                }
+                break;
+            } else if(action==MBCS_STATE_VALID_DIRECT_16) {
+                /* output BMP code point */
+                c=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+                break;
+            } else if(action==MBCS_STATE_VALID_16_PAIR) {
+                offset+=MBCS_ENTRY_FINAL_VALUE_16(entry);
+                c=unicodeCodeUnits[offset++];
+                if(c<0xd800) {
+                    /* output BMP code point below 0xd800 */
+                } else if(UCNV_TO_U_USE_FALLBACK(cnv) ? c<=0xdfff : c<=0xdbff) {
+                    /* output roundtrip or fallback supplementary code point */
+                    c=(UChar32)(((c&0x3ff)<<10)+unicodeCodeUnits[offset]+(0x10000-0xdc00));
+                } else if(UCNV_TO_U_USE_FALLBACK(cnv) ? (c&0xfffe)==0xe000 : c==0xe000) {
+                    /* output roundtrip BMP code point above 0xd800 or fallback BMP code point */
+                    c=unicodeCodeUnits[offset];
+                } else if(c==0xffff) {
+                    return 0xffff;
+                } else {
+                    c=0xfffe;
+                }
+                break;
+            } else if(action==MBCS_STATE_VALID_DIRECT_20) {
+                /* output supplementary code point */
+                c=0x10000+MBCS_ENTRY_FINAL_VALUE(entry);
+                break;
+            } else if(action==MBCS_STATE_FALLBACK_DIRECT_16) {
+                if(!TO_U_USE_FALLBACK(useFallback)) {
+                    c=0xfffe;
+                    break;
+                }
+                /* output BMP code point */
+                c=(UChar)MBCS_ENTRY_FINAL_VALUE_16(entry);
+                break;
+            } else if(action==MBCS_STATE_FALLBACK_DIRECT_20) {
+                if(!TO_U_USE_FALLBACK(useFallback)) {
+                    c=0xfffe;
+                    break;
+                }
+                /* output supplementary code point */
+                c=0x10000+MBCS_ENTRY_FINAL_VALUE(entry);
+                break;
+            } else if(action==MBCS_STATE_UNASSIGNED) {
+                c=0xfffe;
+                break;
+            }
+
+            /*
+             * forbid MBCS_STATE_CHANGE_ONLY for this function,
+             * and MBCS_STATE_ILLEGAL and reserved action codes
+             */
+            return 0xffff;
+        }
+    }
+
+    if(i!=length) {
+        /* illegal for this function: not all input consumed */
+        return 0xffff;
+    }
+
+    if(c==0xfffe) {
+        /* try an extension mapping */
+        const int32_t *cx=sharedData->mbcs.extIndexes;
+        if(cx!=NULL) {
+            return ucnv_extSimpleMatchToU(cx, source, length, useFallback);
+        }
+    }
+
+    return c;
+}
+
+/* MBCS-from-Unicode conversion functions ----------------------------------- */
+
+/* This version of ucnv_MBCSFromUnicodeWithOffsets() is optimized for double-byte codepages. */
+static void
+ucnv_MBCSDoubleFromUnicodeWithOffsets(UConverterFromUnicodeArgs *pArgs,
+                                  UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const UChar *source, *sourceLimit;
+    uint8_t *target;
+    int32_t targetCapacity;
+    int32_t *offsets;
+
+    const uint16_t *table;
+    const uint16_t *mbcsIndex;
+    const uint8_t *bytes;
+
+    UChar32 c;
+
+    int32_t sourceIndex, nextSourceIndex;
+
+    uint32_t stage2Entry;
+    uint32_t asciiRoundtrips;
+    uint32_t value;
+    uint8_t unicodeMask;
+
+    /* use optimized function if possible */
+    cnv=pArgs->converter;
+    unicodeMask=cnv->sharedData->mbcs.unicodeMask;
+
+    /* set up the local pointers */
+    source=pArgs->source;
+    sourceLimit=pArgs->sourceLimit;
+    target=(uint8_t *)pArgs->target;
+    targetCapacity=(int32_t)(pArgs->targetLimit-pArgs->target);
+    offsets=pArgs->offsets;
+
+    table=cnv->sharedData->mbcs.fromUnicodeTable;
+    mbcsIndex=cnv->sharedData->mbcs.mbcsIndex;
+    if((cnv->options&UCNV_OPTION_SWAP_LFNL)!=0) {
+        bytes=cnv->sharedData->mbcs.swapLFNLFromUnicodeBytes;
+    } else {
+        bytes=cnv->sharedData->mbcs.fromUnicodeBytes;
+    }
+    asciiRoundtrips=cnv->sharedData->mbcs.asciiRoundtrips;
+
+    /* get the converter state from UConverter */
+    c=cnv->fromUChar32;
+
+    /* sourceIndex=-1 if the current character began in the previous buffer */
+    sourceIndex= c==0 ? 0 : -1;
+    nextSourceIndex=0;
+
+    /* conversion loop */
+    if(c!=0 && targetCapacity>0) {
+        goto getTrail;
+    }
+
+    while(source<sourceLimit) {
+        /*
+         * This following test is to see if available input would overflow the output.
+         * It does not catch output of more than one byte that
+         * overflows as a result of a multi-byte character or callback output
+         * from the last source character.
+         * Therefore, those situations also test for overflows and will
+         * then break the loop, too.
+         */
+        if(targetCapacity>0) {
+            /*
+             * Get a correct Unicode code point:
+             * a single UChar for a BMP code point or
+             * a matched surrogate pair for a "supplementary code point".
+             */
+            c=*source++;
+            ++nextSourceIndex;
+            if(c<=0x7f && IS_ASCII_ROUNDTRIP(c, asciiRoundtrips)) {
+                *target++=(uint8_t)c;
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                    sourceIndex=nextSourceIndex;
+                }
+                --targetCapacity;
+                c=0;
+                continue;
+            }
+            /*
+             * utf8Friendly table: Test for <=0xd7ff rather than <=MBCS_FAST_MAX
+             * to avoid dealing with surrogates.
+             * MBCS_FAST_MAX must be >=0xd7ff.
+             */
+            if(c<=0xd7ff) {
+                value=DBCS_RESULT_FROM_MOST_BMP(mbcsIndex, (const uint16_t *)bytes, c);
+                /* There are only roundtrips (!=0) and no-mapping (==0) entries. */
+                if(value==0) {
+                    goto unassigned;
+                }
+                /* output the value */
+            } else {
+                /*
+                 * This also tests if the codepage maps single surrogates.
+                 * If it does, then surrogates are not paired but mapped separately.
+                 * Note that in this case unmatched surrogates are not detected.
+                 */
+                if(UTF_IS_SURROGATE(c) && !(unicodeMask&UCNV_HAS_SURROGATES)) {
+                    if(UTF_IS_SURROGATE_FIRST(c)) {
+getTrail:
+                        if(source<sourceLimit) {
+                            /* test the following code unit */
+                            UChar trail=*source;
+                            if(UTF_IS_SECOND_SURROGATE(trail)) {
+                                ++source;
+                                ++nextSourceIndex;
+                                c=UTF16_GET_PAIR_VALUE(c, trail);
+                                if(!(unicodeMask&UCNV_HAS_SUPPLEMENTARY)) {
+                                    /* BMP-only codepages are stored without stage 1 entries for supplementary code points */
+                                    /* callback(unassigned) */
+                                    goto unassigned;
+                                }
+                                /* convert this supplementary code point */
+                                /* exit this condition tree */
+                            } else {
+                                /* this is an unmatched lead code unit (1st surrogate) */
+                                /* callback(illegal) */
+                                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                                break;
+                            }
+                        } else {
+                            /* no more input */
+                            break;
+                        }
+                    } else {
+                        /* this is an unmatched trail code unit (2nd surrogate) */
+                        /* callback(illegal) */
+                        *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                        break;
+                    }
+                }
+
+                /* convert the Unicode code point in c into codepage bytes */
+                stage2Entry=MBCS_STAGE_2_FROM_U(table, c);
+
+                /* get the bytes and the length for the output */
+                /* MBCS_OUTPUT_2 */
+                value=MBCS_VALUE_2_FROM_STAGE_2(bytes, stage2Entry, c);
+
+                /* is this code point assigned, or do we use fallbacks? */
+                if(!(MBCS_FROM_U_IS_ROUNDTRIP(stage2Entry, c) ||
+                     (UCNV_FROM_U_USE_FALLBACK(cnv, c) && value!=0))
+                ) {
+                    /*
+                     * We allow a 0 byte output if the "assigned" bit is set for this entry.
+                     * There is no way with this data structure for fallback output
+                     * to be a zero byte.
+                     */
+
+unassigned:
+                    /* try an extension mapping */
+                    pArgs->source=source;
+                    c=_extFromU(cnv, cnv->sharedData,
+                                c, &source, sourceLimit,
+                                &target, target+targetCapacity,
+                                &offsets, sourceIndex,
+                                pArgs->flush,
+                                pErrorCode);
+                    nextSourceIndex+=(int32_t)(source-pArgs->source);
+
+                    if(U_FAILURE(*pErrorCode)) {
+                        /* not mappable or buffer overflow */
+                        break;
+                    } else {
+                        /* a mapping was written to the target, continue */
+
+                        /* recalculate the targetCapacity after an extension mapping */
+                        targetCapacity=(int32_t)(pArgs->targetLimit-(char *)target);
+
+                        /* normal end of conversion: prepare for a new character */
+                        sourceIndex=nextSourceIndex;
+                        continue;
+                    }
+                }
+            }
+
+            /* write the output character bytes from value and length */
+            /* from the first if in the loop we know that targetCapacity>0 */
+            if(value<=0xff) {
+                /* this is easy because we know that there is enough space */
+                *target++=(uint8_t)value;
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                }
+                --targetCapacity;
+            } else /* length==2 */ {
+                *target++=(uint8_t)(value>>8);
+                if(2<=targetCapacity) {
+                    *target++=(uint8_t)value;
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex;
+                        *offsets++=sourceIndex;
+                    }
+                    targetCapacity-=2;
+                } else {
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex;
+                    }
+                    cnv->charErrorBuffer[0]=(char)value;
+                    cnv->charErrorBufferLength=1;
+
+                    /* target overflow */
+                    targetCapacity=0;
+                    *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                    c=0;
+                    break;
+                }
+            }
+
+            /* normal end of conversion: prepare for a new character */
+            c=0;
+            sourceIndex=nextSourceIndex;
+            continue;
+        } else {
+            /* target is full */
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+    }
+
+    /* set the converter state back into UConverter */
+    cnv->fromUChar32=c;
+
+    /* write back the updated pointers */
+    pArgs->source=source;
+    pArgs->target=(char *)target;
+    pArgs->offsets=offsets;
+}
+
+/* This version of ucnv_MBCSFromUnicodeWithOffsets() is optimized for single-byte codepages. */
+static void
+ucnv_MBCSSingleFromUnicodeWithOffsets(UConverterFromUnicodeArgs *pArgs,
+                                  UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const UChar *source, *sourceLimit;
+    uint8_t *target;
+    int32_t targetCapacity;
+    int32_t *offsets;
+
+    const uint16_t *table;
+    const uint16_t *results;
+
+    UChar32 c;
+
+    int32_t sourceIndex, nextSourceIndex;
+
+    uint16_t value, minValue;
+    UBool hasSupplementary;
+
+    /* set up the local pointers */
+    cnv=pArgs->converter;
+    source=pArgs->source;
+    sourceLimit=pArgs->sourceLimit;
+    target=(uint8_t *)pArgs->target;
+    targetCapacity=(int32_t)(pArgs->targetLimit-pArgs->target);
+    offsets=pArgs->offsets;
+
+    table=cnv->sharedData->mbcs.fromUnicodeTable;
+    if((cnv->options&UCNV_OPTION_SWAP_LFNL)!=0) {
+        results=(uint16_t *)cnv->sharedData->mbcs.swapLFNLFromUnicodeBytes;
+    } else {
+        results=(uint16_t *)cnv->sharedData->mbcs.fromUnicodeBytes;
+    }
+
+    if(cnv->useFallback) {
+        /* use all roundtrip and fallback results */
+        minValue=0x800;
+    } else {
+        /* use only roundtrips and fallbacks from private-use characters */
+        minValue=0xc00;
+    }
+    hasSupplementary=(UBool)(cnv->sharedData->mbcs.unicodeMask&UCNV_HAS_SUPPLEMENTARY);
+
+    /* get the converter state from UConverter */
+    c=cnv->fromUChar32;
+
+    /* sourceIndex=-1 if the current character began in the previous buffer */
+    sourceIndex= c==0 ? 0 : -1;
+    nextSourceIndex=0;
+
+    /* conversion loop */
+    if(c!=0 && targetCapacity>0) {
+        goto getTrail;
+    }
+
+    while(source<sourceLimit) {
+        /*
+         * This following test is to see if available input would overflow the output.
+         * It does not catch output of more than one byte that
+         * overflows as a result of a multi-byte character or callback output
+         * from the last source character.
+         * Therefore, those situations also test for overflows and will
+         * then break the loop, too.
+         */
+        if(targetCapacity>0) {
+            /*
+             * Get a correct Unicode code point:
+             * a single UChar for a BMP code point or
+             * a matched surrogate pair for a "supplementary code point".
+             */
+            c=*source++;
+            ++nextSourceIndex;
+            if(UTF_IS_SURROGATE(c)) {
+                if(UTF_IS_SURROGATE_FIRST(c)) {
+getTrail:
+                    if(source<sourceLimit) {
+                        /* test the following code unit */
+                        UChar trail=*source;
+                        if(UTF_IS_SECOND_SURROGATE(trail)) {
+                            ++source;
+                            ++nextSourceIndex;
+                            c=UTF16_GET_PAIR_VALUE(c, trail);
+                            if(!hasSupplementary) {
+                                /* BMP-only codepages are stored without stage 1 entries for supplementary code points */
+                                /* callback(unassigned) */
+                                goto unassigned;
+                            }
+                            /* convert this supplementary code point */
+                            /* exit this condition tree */
+                        } else {
+                            /* this is an unmatched lead code unit (1st surrogate) */
+                            /* callback(illegal) */
+                            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                            break;
+                        }
+                    } else {
+                        /* no more input */
+                        break;
+                    }
+                } else {
+                    /* this is an unmatched trail code unit (2nd surrogate) */
+                    /* callback(illegal) */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                    break;
+                }
+            }
+
+            /* convert the Unicode code point in c into codepage bytes */
+            value=MBCS_SINGLE_RESULT_FROM_U(table, results, c);
+
+            /* is this code point assigned, or do we use fallbacks? */
+            if(value>=minValue) {
+                /* assigned, write the output character bytes from value and length */
+                /* length==1 */
+                /* this is easy because we know that there is enough space */
+                *target++=(uint8_t)value;
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                }
+                --targetCapacity;
+
+                /* normal end of conversion: prepare for a new character */
+                c=0;
+                sourceIndex=nextSourceIndex;
+            } else { /* unassigned */
+unassigned:
+                /* try an extension mapping */
+                pArgs->source=source;
+                c=_extFromU(cnv, cnv->sharedData,
+                            c, &source, sourceLimit,
+                            &target, target+targetCapacity,
+                            &offsets, sourceIndex,
+                            pArgs->flush,
+                            pErrorCode);
+                nextSourceIndex+=(int32_t)(source-pArgs->source);
+
+                if(U_FAILURE(*pErrorCode)) {
+                    /* not mappable or buffer overflow */
+                    break;
+                } else {
+                    /* a mapping was written to the target, continue */
+
+                    /* recalculate the targetCapacity after an extension mapping */
+                    targetCapacity=(int32_t)(pArgs->targetLimit-(char *)target);
+
+                    /* normal end of conversion: prepare for a new character */
+                    sourceIndex=nextSourceIndex;
+                }
+            }
+        } else {
+            /* target is full */
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+    }
+
+    /* set the converter state back into UConverter */
+    cnv->fromUChar32=c;
+
+    /* write back the updated pointers */
+    pArgs->source=source;
+    pArgs->target=(char *)target;
+    pArgs->offsets=offsets;
+}
+
+/*
+ * This version of ucnv_MBCSFromUnicode() is optimized for single-byte codepages
+ * that map only to and from the BMP.
+ * In addition to single-byte/state optimizations, the offset calculations
+ * become much easier.
+ * It would be possible to use the sbcsIndex for UTF-8-friendly tables,
+ * but measurements have shown that this diminishes performance
+ * in more cases than it improves it.
+ * See SVN revision 21013 (2007-feb-06) for the last version with #if switches
+ * for various MBCS and SBCS optimizations.
+ */
+static void
+ucnv_MBCSSingleFromBMPWithOffsets(UConverterFromUnicodeArgs *pArgs,
+                              UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const UChar *source, *sourceLimit, *lastSource;
+    uint8_t *target;
+    int32_t targetCapacity, length;
+    int32_t *offsets;
+
+    const uint16_t *table;
+    const uint16_t *results;
+
+    UChar32 c;
+
+    int32_t sourceIndex;
+
+    uint32_t asciiRoundtrips;
+    uint16_t value, minValue;
+
+    /* set up the local pointers */
+    cnv=pArgs->converter;
+    source=pArgs->source;
+    sourceLimit=pArgs->sourceLimit;
+    target=(uint8_t *)pArgs->target;
+    targetCapacity=(int32_t)(pArgs->targetLimit-pArgs->target);
+    offsets=pArgs->offsets;
+
+    table=cnv->sharedData->mbcs.fromUnicodeTable;
+    if((cnv->options&UCNV_OPTION_SWAP_LFNL)!=0) {
+        results=(uint16_t *)cnv->sharedData->mbcs.swapLFNLFromUnicodeBytes;
+    } else {
+        results=(uint16_t *)cnv->sharedData->mbcs.fromUnicodeBytes;
+    }
+    asciiRoundtrips=cnv->sharedData->mbcs.asciiRoundtrips;
+
+    if(cnv->useFallback) {
+        /* use all roundtrip and fallback results */
+        minValue=0x800;
+    } else {
+        /* use only roundtrips and fallbacks from private-use characters */
+        minValue=0xc00;
+    }
+
+    /* get the converter state from UConverter */
+    c=cnv->fromUChar32;
+
+    /* sourceIndex=-1 if the current character began in the previous buffer */
+    sourceIndex= c==0 ? 0 : -1;
+    lastSource=source;
+
+    /*
+     * since the conversion here is 1:1 UChar:uint8_t, we need only one counter
+     * for the minimum of the sourceLength and targetCapacity
+     */
+    length=(int32_t)(sourceLimit-source);
+    if(length<targetCapacity) {
+        targetCapacity=length;
+    }
+
+    /* conversion loop */
+    if(c!=0 && targetCapacity>0) {
+        goto getTrail;
+    }
+
+#if MBCS_UNROLL_SINGLE_FROM_BMP
+    /* unrolling makes it slower on Pentium III/Windows 2000?! */
+    /* unroll the loop with the most common case */
+unrolled:
+    if(targetCapacity>=4) {
+        int32_t count, loops;
+        uint16_t andedValues;
+
+        loops=count=targetCapacity>>2;
+        do {
+            c=*source++;
+            andedValues=value=MBCS_SINGLE_RESULT_FROM_U(table, results, c);
+            *target++=(uint8_t)value;
+            c=*source++;
+            andedValues&=value=MBCS_SINGLE_RESULT_FROM_U(table, results, c);
+            *target++=(uint8_t)value;
+            c=*source++;
+            andedValues&=value=MBCS_SINGLE_RESULT_FROM_U(table, results, c);
+            *target++=(uint8_t)value;
+            c=*source++;
+            andedValues&=value=MBCS_SINGLE_RESULT_FROM_U(table, results, c);
+            *target++=(uint8_t)value;
+
+            /* were all 4 entries really valid? */
+            if(andedValues<minValue) {
+                /* no, return to the first of these 4 */
+                source-=4;
+                target-=4;
+                break;
+            }
+        } while(--count>0);
+        count=loops-count;
+        targetCapacity-=4*count;
+
+        if(offsets!=NULL) {
+            lastSource+=4*count;
+            while(count>0) {
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                *offsets++=sourceIndex++;
+                --count;
+            }
+        }
+
+        c=0;
+    }
+#endif
+
+    while(targetCapacity>0) {
+        /*
+         * Get a correct Unicode code point:
+         * a single UChar for a BMP code point or
+         * a matched surrogate pair for a "supplementary code point".
+         */
+        c=*source++;
+        /*
+         * Do not immediately check for single surrogates:
+         * Assume that they are unassigned and check for them in that case.
+         * This speeds up the conversion of assigned characters.
+         */
+        /* convert the Unicode code point in c into codepage bytes */
+        if(c<=0x7f && IS_ASCII_ROUNDTRIP(c, asciiRoundtrips)) {
+            *target++=(uint8_t)c;
+            --targetCapacity;
+            c=0;
+            continue;
+        }
+        value=MBCS_SINGLE_RESULT_FROM_U(table, results, c);
+        /* is this code point assigned, or do we use fallbacks? */
+        if(value>=minValue) {
+            /* assigned, write the output character bytes from value and length */
+            /* length==1 */
+            /* this is easy because we know that there is enough space */
+            *target++=(uint8_t)value;
+            --targetCapacity;
+
+            /* normal end of conversion: prepare for a new character */
+            c=0;
+            continue;
+        } else if(!UTF_IS_SURROGATE(c)) {
+            /* normal, unassigned BMP character */
+        } else if(UTF_IS_SURROGATE_FIRST(c)) {
+getTrail:
+            if(source<sourceLimit) {
+                /* test the following code unit */
+                UChar trail=*source;
+                if(UTF_IS_SECOND_SURROGATE(trail)) {
+                    ++source;
+                    c=UTF16_GET_PAIR_VALUE(c, trail);
+                    /* this codepage does not map supplementary code points */
+                    /* callback(unassigned) */
+                } else {
+                    /* this is an unmatched lead code unit (1st surrogate) */
+                    /* callback(illegal) */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                    break;
+                }
+            } else {
+                /* no more input */
+                if (pArgs->flush) {
+                    *pErrorCode=U_TRUNCATED_CHAR_FOUND;
+                }
+                break;
+            }
+        } else {
+            /* this is an unmatched trail code unit (2nd surrogate) */
+            /* callback(illegal) */
+            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+            break;
+        }
+
+        /* c does not have a mapping */
+
+        /* get the number of code units for c to correctly advance sourceIndex */
+        length=U16_LENGTH(c);
+
+        /* set offsets since the start or the last extension */
+        if(offsets!=NULL) {
+            int32_t count=(int32_t)(source-lastSource);
+
+            /* do not set the offset for this character */
+            count-=length;
+
+            while(count>0) {
+                *offsets++=sourceIndex++;
+                --count;
+            }
+            /* offsets and sourceIndex are now set for the current character */
+        }
+
+        /* try an extension mapping */
+        lastSource=source;
+        c=_extFromU(cnv, cnv->sharedData,
+                    c, &source, sourceLimit,
+                    &target, (const uint8_t *)(pArgs->targetLimit),
+                    &offsets, sourceIndex,
+                    pArgs->flush,
+                    pErrorCode);
+        sourceIndex+=length+(int32_t)(source-lastSource);
+        lastSource=source;
+
+        if(U_FAILURE(*pErrorCode)) {
+            /* not mappable or buffer overflow */
+            break;
+        } else {
+            /* a mapping was written to the target, continue */
+
+            /* recalculate the targetCapacity after an extension mapping */
+            targetCapacity=(int32_t)(pArgs->targetLimit-(char *)target);
+            length=(int32_t)(sourceLimit-source);
+            if(length<targetCapacity) {
+                targetCapacity=length;
+            }
+        }
+
+#if MBCS_UNROLL_SINGLE_FROM_BMP
+        /* unrolling makes it slower on Pentium III/Windows 2000?! */
+        goto unrolled;
+#endif
+    }
+
+    if(U_SUCCESS(*pErrorCode) && source<sourceLimit && target>=(uint8_t *)pArgs->targetLimit) {
+        /* target is full */
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+
+    /* set offsets since the start or the last callback */
+    if(offsets!=NULL) {
+        size_t count=source-lastSource;
+        if (count > 0 && *pErrorCode == U_TRUNCATED_CHAR_FOUND) {
+            /*
+            Caller gave us a partial supplementary character,
+            which this function couldn't convert in any case.
+            The callback will handle the offset.
+            */
+            count--;
+        }
+        while(count>0) {
+            *offsets++=sourceIndex++;
+            --count;
+        }
+    }
+
+    /* set the converter state back into UConverter */
+    cnv->fromUChar32=c;
+
+    /* write back the updated pointers */
+    pArgs->source=source;
+    pArgs->target=(char *)target;
+    pArgs->offsets=offsets;
+}
+
+U_CFUNC void
+ucnv_MBCSFromUnicodeWithOffsets(UConverterFromUnicodeArgs *pArgs,
+                            UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    const UChar *source, *sourceLimit;
+    uint8_t *target;
+    int32_t targetCapacity;
+    int32_t *offsets;
+
+    const uint16_t *table;
+    const uint16_t *mbcsIndex;
+    const uint8_t *p, *bytes;
+    uint8_t outputType;
+
+    UChar32 c;
+
+    int32_t prevSourceIndex, sourceIndex, nextSourceIndex;
+
+    uint32_t stage2Entry;
+    uint32_t asciiRoundtrips;
+    uint32_t value;
+    uint8_t si_value[2] = {0, 0}; 
+    uint8_t so_value[2] = {0, 0}; 
+    uint8_t si_value_length, so_value_length;
+    int32_t length = 0, prevLength;
+    uint8_t unicodeMask;
+
+    cnv=pArgs->converter;
+
+    if(cnv->preFromUFirstCP>=0) {
+        /*
+         * pass sourceIndex=-1 because we continue from an earlier buffer
+         * in the future, this may change with continuous offsets
+         */
+        ucnv_extContinueMatchFromU(cnv, pArgs, -1, pErrorCode);
+
+        if(U_FAILURE(*pErrorCode) || cnv->preFromULength<0) {
+            return;
+        }
+    }
+
+    /* use optimized function if possible */
+    outputType=cnv->sharedData->mbcs.outputType;
+    unicodeMask=cnv->sharedData->mbcs.unicodeMask;
+    if(outputType==MBCS_OUTPUT_1 && !(unicodeMask&UCNV_HAS_SURROGATES)) {
+        if(!(unicodeMask&UCNV_HAS_SUPPLEMENTARY)) {
+            ucnv_MBCSSingleFromBMPWithOffsets(pArgs, pErrorCode);
+        } else {
+            ucnv_MBCSSingleFromUnicodeWithOffsets(pArgs, pErrorCode);
+        }
+        return;
+    } else if(outputType==MBCS_OUTPUT_2 && cnv->sharedData->mbcs.utf8Friendly) {
+        ucnv_MBCSDoubleFromUnicodeWithOffsets(pArgs, pErrorCode);
+        return;
+    }
+
+    /* set up the local pointers */
+    source=pArgs->source;
+    sourceLimit=pArgs->sourceLimit;
+    target=(uint8_t *)pArgs->target;
+    targetCapacity=(int32_t)(pArgs->targetLimit-pArgs->target);
+    offsets=pArgs->offsets;
+
+    table=cnv->sharedData->mbcs.fromUnicodeTable;
+    if(cnv->sharedData->mbcs.utf8Friendly) {
+        mbcsIndex=cnv->sharedData->mbcs.mbcsIndex;
+    } else {
+        mbcsIndex=NULL;
+    }
+    if((cnv->options&UCNV_OPTION_SWAP_LFNL)!=0) {
+        bytes=cnv->sharedData->mbcs.swapLFNLFromUnicodeBytes;
+    } else {
+        bytes=cnv->sharedData->mbcs.fromUnicodeBytes;
+    }
+    asciiRoundtrips=cnv->sharedData->mbcs.asciiRoundtrips;
+
+    /* get the converter state from UConverter */
+    c=cnv->fromUChar32;
+
+    if(outputType==MBCS_OUTPUT_2_SISO) {
+        prevLength=cnv->fromUnicodeStatus;
+        if(prevLength==0) {
+            /* set the real value */
+            prevLength=1;
+        }
+    } else {
+        /* prevent fromUnicodeStatus from being set to something non-0 */
+        prevLength=0;
+    }
+
+    /* sourceIndex=-1 if the current character began in the previous buffer */
+    prevSourceIndex=-1;
+    sourceIndex= c==0 ? 0 : -1;
+    nextSourceIndex=0;
+
+    /* Get the SI/SO character for the converter */
+    si_value_length = getSISOBytes(SI, cnv->options, si_value);
+    so_value_length = getSISOBytes(SO, cnv->options, so_value);
+
+    /* conversion loop */
+    /*
+     * This is another piece of ugly code:
+     * A goto into the loop if the converter state contains a first surrogate
+     * from the previous function call.
+     * It saves me to check in each loop iteration a check of if(c==0)
+     * and duplicating the trail-surrogate-handling code in the else
+     * branch of that check.
+     * I could not find any other way to get around this other than
+     * using a function call for the conversion and callback, which would
+     * be even more inefficient.
+     *
+     * Markus Scherer 2000-jul-19
+     */
+    if(c!=0 && targetCapacity>0) {
+        goto getTrail;
+    }
+
+    while(source<sourceLimit) {
+        /*
+         * This following test is to see if available input would overflow the output.
+         * It does not catch output of more than one byte that
+         * overflows as a result of a multi-byte character or callback output
+         * from the last source character.
+         * Therefore, those situations also test for overflows and will
+         * then break the loop, too.
+         */
+        if(targetCapacity>0) {
+            /*
+             * Get a correct Unicode code point:
+             * a single UChar for a BMP code point or
+             * a matched surrogate pair for a "supplementary code point".
+             */
+            c=*source++;
+            ++nextSourceIndex;
+            if(c<=0x7f && IS_ASCII_ROUNDTRIP(c, asciiRoundtrips)) {
+                *target++=(uint8_t)c;
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                    prevSourceIndex=sourceIndex;
+                    sourceIndex=nextSourceIndex;
+                }
+                --targetCapacity;
+                c=0;
+                continue;
+            }
+            /*
+             * utf8Friendly table: Test for <=0xd7ff rather than <=MBCS_FAST_MAX
+             * to avoid dealing with surrogates.
+             * MBCS_FAST_MAX must be >=0xd7ff.
+             */
+            if(c<=0xd7ff && mbcsIndex!=NULL) {
+                value=mbcsIndex[c>>6];
+
+                /* get the bytes and the length for the output (copied from below and adapted for utf8Friendly data) */
+                /* There are only roundtrips (!=0) and no-mapping (==0) entries. */
+                switch(outputType) {
+                case MBCS_OUTPUT_2:
+                    value=((const uint16_t *)bytes)[value +(c&0x3f)];
+                    if(value<=0xff) {
+                        if(value==0) {
+                            goto unassigned;
+                        } else {
+                            length=1;
+                        }
+                    } else {
+                        length=2;
+                    }
+                    break;
+                case MBCS_OUTPUT_2_SISO:
+                    /* 1/2-byte stateful with Shift-In/Shift-Out */
+                    /*
+                     * Save the old state in the converter object
+                     * right here, then change the local prevLength state variable if necessary.
+                     * Then, if this character turns out to be unassigned or a fallback that
+                     * is not taken, the callback code must not save the new state in the converter
+                     * because the new state is for a character that is not output.
+                     * However, the callback must still restore the state from the converter
+                     * in case the callback function changed it for its output.
+                     */
+                    cnv->fromUnicodeStatus=prevLength; /* save the old state */
+                    value=((const uint16_t *)bytes)[value +(c&0x3f)];
+                    if(value<=0xff) {
+                        if(value==0) {
+                            goto unassigned;
+                        } else if(prevLength<=1) {
+                            length=1;
+                        } else {
+                            /* change from double-byte mode to single-byte */
+                            if (si_value_length == 1) {
+                                value|=(uint32_t)si_value[0]<<8;
+                                length = 2;
+                            } else if (si_value_length == 2) {
+                                value|=(uint32_t)si_value[1]<<8;
+                                value|=(uint32_t)si_value[0]<<16;
+                                length = 3;
+                            }
+                            prevLength=1;
+                        }
+                    } else {
+                        if(prevLength==2) {
+                            length=2;
+                        } else {
+                            /* change from single-byte mode to double-byte */
+                            if (so_value_length == 1) {
+                                value|=(uint32_t)so_value[0]<<16;
+                                length = 3;
+                            } else if (so_value_length == 2) {
+                                value|=(uint32_t)so_value[1]<<16;
+                                value|=(uint32_t)so_value[0]<<24;
+                                length = 4;
+                            }
+                            prevLength=2;
+                        }
+                    }
+                    break;
+                case MBCS_OUTPUT_DBCS_ONLY:
+                    /* table with single-byte results, but only DBCS mappings used */
+                    value=((const uint16_t *)bytes)[value +(c&0x3f)];
+                    if(value<=0xff) {
+                        /* no mapping or SBCS result, not taken for DBCS-only */
+                        goto unassigned;
+                    } else {
+                        length=2;
+                    }
+                    break;
+                case MBCS_OUTPUT_3:
+                    p=bytes+(value+(c&0x3f))*3;
+                    value=((uint32_t)*p<<16)|((uint32_t)p[1]<<8)|p[2];
+                    if(value<=0xff) {
+                        if(value==0) {
+                            goto unassigned;
+                        } else {
+                            length=1;
+                        }
+                    } else if(value<=0xffff) {
+                        length=2;
+                    } else {
+                        length=3;
+                    }
+                    break;
+                case MBCS_OUTPUT_4:
+                    value=((const uint32_t *)bytes)[value +(c&0x3f)];
+                    if(value<=0xff) {
+                        if(value==0) {
+                            goto unassigned;
+                        } else {
+                            length=1;
+                        }
+                    } else if(value<=0xffff) {
+                        length=2;
+                    } else if(value<=0xffffff) {
+                        length=3;
+                    } else {
+                        length=4;
+                    }
+                    break;
+                case MBCS_OUTPUT_3_EUC:
+                    value=((const uint16_t *)bytes)[value +(c&0x3f)];
+                    /* EUC 16-bit fixed-length representation */
+                    if(value<=0xff) {
+                        if(value==0) {
+                            goto unassigned;
+                        } else {
+                            length=1;
+                        }
+                    } else if((value&0x8000)==0) {
+                        value|=0x8e8000;
+                        length=3;
+                    } else if((value&0x80)==0) {
+                        value|=0x8f0080;
+                        length=3;
+                    } else {
+                        length=2;
+                    }
+                    break;
+                case MBCS_OUTPUT_4_EUC:
+                    p=bytes+(value+(c&0x3f))*3;
+                    value=((uint32_t)*p<<16)|((uint32_t)p[1]<<8)|p[2];
+                    /* EUC 16-bit fixed-length representation applied to the first two bytes */
+                    if(value<=0xff) {
+                        if(value==0) {
+                            goto unassigned;
+                        } else {
+                            length=1;
+                        }
+                    } else if(value<=0xffff) {
+                        length=2;
+                    } else if((value&0x800000)==0) {
+                        value|=0x8e800000;
+                        length=4;
+                    } else if((value&0x8000)==0) {
+                        value|=0x8f008000;
+                        length=4;
+                    } else {
+                        length=3;
+                    }
+                    break;
+                default:
+                    /* must not occur */
+                    /*
+                     * To avoid compiler warnings that value & length may be
+                     * used without having been initialized, we set them here.
+                     * In reality, this is unreachable code.
+                     * Not having a default branch also causes warnings with
+                     * some compilers.
+                     */
+                    value=0;
+                    length=0;
+                    break;
+                }
+                /* output the value */
+            } else {
+                /*
+                 * This also tests if the codepage maps single surrogates.
+                 * If it does, then surrogates are not paired but mapped separately.
+                 * Note that in this case unmatched surrogates are not detected.
+                 */
+                if(UTF_IS_SURROGATE(c) && !(unicodeMask&UCNV_HAS_SURROGATES)) {
+                    if(UTF_IS_SURROGATE_FIRST(c)) {
+getTrail:
+                        if(source<sourceLimit) {
+                            /* test the following code unit */
+                            UChar trail=*source;
+                            if(UTF_IS_SECOND_SURROGATE(trail)) {
+                                ++source;
+                                ++nextSourceIndex;
+                                c=UTF16_GET_PAIR_VALUE(c, trail);
+                                if(!(unicodeMask&UCNV_HAS_SUPPLEMENTARY)) {
+                                    /* BMP-only codepages are stored without stage 1 entries for supplementary code points */
+                                    cnv->fromUnicodeStatus=prevLength; /* save the old state */
+                                    /* callback(unassigned) */
+                                    goto unassigned;
+                                }
+                                /* convert this supplementary code point */
+                                /* exit this condition tree */
+                            } else {
+                                /* this is an unmatched lead code unit (1st surrogate) */
+                                /* callback(illegal) */
+                                *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                                break;
+                            }
+                        } else {
+                            /* no more input */
+                            break;
+                        }
+                    } else {
+                        /* this is an unmatched trail code unit (2nd surrogate) */
+                        /* callback(illegal) */
+                        *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                        break;
+                    }
+                }
+
+                /* convert the Unicode code point in c into codepage bytes */
+
+                /*
+                 * The basic lookup is a triple-stage compact array (trie) lookup.
+                 * For details see the beginning of this file.
+                 *
+                 * Single-byte codepages are handled with a different data structure
+                 * by _MBCSSingle... functions.
+                 *
+                 * The result consists of a 32-bit value from stage 2 and
+                 * a pointer to as many bytes as are stored per character.
+                 * The pointer points to the character's bytes in stage 3.
+                 * Bits 15..0 of the stage 2 entry contain the stage 3 index
+                 * for that pointer, while bits 31..16 are flags for which of
+                 * the 16 characters in the block are roundtrip-assigned.
+                 *
+                 * For 2-byte and 4-byte codepages, the bytes are stored as uint16_t
+                 * respectively as uint32_t, in the platform encoding.
+                 * For 3-byte codepages, the bytes are always stored in big-endian order.
+                 *
+                 * For EUC encodings that use only either 0x8e or 0x8f as the first
+                 * byte of their longest byte sequences, the first two bytes in
+                 * this third stage indicate with their 7th bits whether these bytes
+                 * are to be written directly or actually need to be preceeded by
+                 * one of the two Single-Shift codes. With this, the third stage
+                 * stores one byte fewer per character than the actual maximum length of
+                 * EUC byte sequences.
+                 *
+                 * Other than that, leading zero bytes are removed and the other
+                 * bytes output. A single zero byte may be output if the "assigned"
+                 * bit in stage 2 was on.
+                 * The data structure does not support zero byte output as a fallback,
+                 * and also does not allow output of leading zeros.
+                 */
+                stage2Entry=MBCS_STAGE_2_FROM_U(table, c);
+
+                /* get the bytes and the length for the output */
+                switch(outputType) {
+                case MBCS_OUTPUT_2:
+                    value=MBCS_VALUE_2_FROM_STAGE_2(bytes, stage2Entry, c);
+                    if(value<=0xff) {
+                        length=1;
+                    } else {
+                        length=2;
+                    }
+                    break;
+                case MBCS_OUTPUT_2_SISO:
+                    /* 1/2-byte stateful with Shift-In/Shift-Out */
+                    /*
+                     * Save the old state in the converter object
+                     * right here, then change the local prevLength state variable if necessary.
+                     * Then, if this character turns out to be unassigned or a fallback that
+                     * is not taken, the callback code must not save the new state in the converter
+                     * because the new state is for a character that is not output.
+                     * However, the callback must still restore the state from the converter
+                     * in case the callback function changed it for its output.
+                     */
+                    cnv->fromUnicodeStatus=prevLength; /* save the old state */
+                    value=MBCS_VALUE_2_FROM_STAGE_2(bytes, stage2Entry, c);
+                    if(value<=0xff) {
+                        if(value==0 && MBCS_FROM_U_IS_ROUNDTRIP(stage2Entry, c)==0) {
+                            /* no mapping, leave value==0 */
+                            length=0;
+                        } else if(prevLength<=1) {
+                            length=1;
+                        } else {
+                            /* change from double-byte mode to single-byte */
+                            if (si_value_length == 1) {
+                                value|=(uint32_t)si_value[0]<<8;
+                                length = 2;
+                            } else if (si_value_length == 2) {
+                                value|=(uint32_t)si_value[1]<<8;
+                                value|=(uint32_t)si_value[0]<<16;
+                                length = 3;
+                            }
+                            prevLength=1;
+                        }
+                    } else {
+                        if(prevLength==2) {
+                            length=2;
+                        } else {
+                            /* change from single-byte mode to double-byte */
+                            if (so_value_length == 1) {
+                                value|=(uint32_t)so_value[0]<<16;
+                                length = 3;
+                            } else if (so_value_length == 2) {
+                                value|=(uint32_t)so_value[1]<<16;
+                                value|=(uint32_t)so_value[0]<<24;
+                                length = 4;
+                            }
+                            prevLength=2;
+                        }
+                    }
+                    break;
+                case MBCS_OUTPUT_DBCS_ONLY:
+                    /* table with single-byte results, but only DBCS mappings used */
+                    value=MBCS_VALUE_2_FROM_STAGE_2(bytes, stage2Entry, c);
+                    if(value<=0xff) {
+                        /* no mapping or SBCS result, not taken for DBCS-only */
+                        value=stage2Entry=0; /* stage2Entry=0 to reset roundtrip flags */
+                        length=0;
+                    } else {
+                        length=2;
+                    }
+                    break;
+                case MBCS_OUTPUT_3:
+                    p=MBCS_POINTER_3_FROM_STAGE_2(bytes, stage2Entry, c);
+                    value=((uint32_t)*p<<16)|((uint32_t)p[1]<<8)|p[2];
+                    if(value<=0xff) {
+                        length=1;
+                    } else if(value<=0xffff) {
+                        length=2;
+                    } else {
+                        length=3;
+                    }
+                    break;
+                case MBCS_OUTPUT_4:
+                    value=MBCS_VALUE_4_FROM_STAGE_2(bytes, stage2Entry, c);
+                    if(value<=0xff) {
+                        length=1;
+                    } else if(value<=0xffff) {
+                        length=2;
+                    } else if(value<=0xffffff) {
+                        length=3;
+                    } else {
+                        length=4;
+                    }
+                    break;
+                case MBCS_OUTPUT_3_EUC:
+                    value=MBCS_VALUE_2_FROM_STAGE_2(bytes, stage2Entry, c);
+                    /* EUC 16-bit fixed-length representation */
+                    if(value<=0xff) {
+                        length=1;
+                    } else if((value&0x8000)==0) {
+                        value|=0x8e8000;
+                        length=3;
+                    } else if((value&0x80)==0) {
+                        value|=0x8f0080;
+                        length=3;
+                    } else {
+                        length=2;
+                    }
+                    break;
+                case MBCS_OUTPUT_4_EUC:
+                    p=MBCS_POINTER_3_FROM_STAGE_2(bytes, stage2Entry, c);
+                    value=((uint32_t)*p<<16)|((uint32_t)p[1]<<8)|p[2];
+                    /* EUC 16-bit fixed-length representation applied to the first two bytes */
+                    if(value<=0xff) {
+                        length=1;
+                    } else if(value<=0xffff) {
+                        length=2;
+                    } else if((value&0x800000)==0) {
+                        value|=0x8e800000;
+                        length=4;
+                    } else if((value&0x8000)==0) {
+                        value|=0x8f008000;
+                        length=4;
+                    } else {
+                        length=3;
+                    }
+                    break;
+                default:
+                    /* must not occur */
+                    /*
+                     * To avoid compiler warnings that value & length may be
+                     * used without having been initialized, we set them here.
+                     * In reality, this is unreachable code.
+                     * Not having a default branch also causes warnings with
+                     * some compilers.
+                     */
+                    value=stage2Entry=0; /* stage2Entry=0 to reset roundtrip flags */
+                    length=0;
+                    break;
+                }
+
+                /* is this code point assigned, or do we use fallbacks? */
+                if(!(MBCS_FROM_U_IS_ROUNDTRIP(stage2Entry, c)!=0 ||
+                     (UCNV_FROM_U_USE_FALLBACK(cnv, c) && value!=0))
+                ) {
+                    /*
+                     * We allow a 0 byte output if the "assigned" bit is set for this entry.
+                     * There is no way with this data structure for fallback output
+                     * to be a zero byte.
+                     */
+
+unassigned:
+                    /* try an extension mapping */
+                    pArgs->source=source;
+                    c=_extFromU(cnv, cnv->sharedData,
+                                c, &source, sourceLimit,
+                                &target, target+targetCapacity,
+                                &offsets, sourceIndex,
+                                pArgs->flush,
+                                pErrorCode);
+                    nextSourceIndex+=(int32_t)(source-pArgs->source);
+                    prevLength=cnv->fromUnicodeStatus; /* restore SISO state */
+
+                    if(U_FAILURE(*pErrorCode)) {
+                        /* not mappable or buffer overflow */
+                        break;
+                    } else {
+                        /* a mapping was written to the target, continue */
+
+                        /* recalculate the targetCapacity after an extension mapping */
+                        targetCapacity=(int32_t)(pArgs->targetLimit-(char *)target);
+
+                        /* normal end of conversion: prepare for a new character */
+                        if(offsets!=NULL) {
+                            prevSourceIndex=sourceIndex;
+                            sourceIndex=nextSourceIndex;
+                        }
+                        continue;
+                    }
+                }
+            }
+
+            /* write the output character bytes from value and length */
+            /* from the first if in the loop we know that targetCapacity>0 */
+            if(length<=targetCapacity) {
+                if(offsets==NULL) {
+                    switch(length) {
+                        /* each branch falls through to the next one */
+                    case 4:
+                        *target++=(uint8_t)(value>>24);
+                    case 3:
+                        *target++=(uint8_t)(value>>16);
+                    case 2:
+                        *target++=(uint8_t)(value>>8);
+                    case 1:
+                        *target++=(uint8_t)value;
+                    default:
+                        /* will never occur */
+                        break;
+                    }
+                } else {
+                    switch(length) {
+                        /* each branch falls through to the next one */
+                    case 4:
+                        *target++=(uint8_t)(value>>24);
+                        *offsets++=sourceIndex;
+                    case 3:
+                        *target++=(uint8_t)(value>>16);
+                        *offsets++=sourceIndex;
+                    case 2:
+                        *target++=(uint8_t)(value>>8);
+                        *offsets++=sourceIndex;
+                    case 1:
+                        *target++=(uint8_t)value;
+                        *offsets++=sourceIndex;
+                    default:
+                        /* will never occur */
+                        break;
+                    }
+                }
+                targetCapacity-=length;
+            } else {
+                uint8_t *charErrorBuffer;
+
+                /*
+                 * We actually do this backwards here:
+                 * In order to save an intermediate variable, we output
+                 * first to the overflow buffer what does not fit into the
+                 * regular target.
+                 */
+                /* we know that 1<=targetCapacity<length<=4 */
+                length-=targetCapacity;
+                charErrorBuffer=(uint8_t *)cnv->charErrorBuffer;
+                switch(length) {
+                    /* each branch falls through to the next one */
+                case 3:
+                    *charErrorBuffer++=(uint8_t)(value>>16);
+                case 2:
+                    *charErrorBuffer++=(uint8_t)(value>>8);
+                case 1:
+                    *charErrorBuffer=(uint8_t)value;
+                default:
+                    /* will never occur */
+                    break;
+                }
+                cnv->charErrorBufferLength=(int8_t)length;
+
+                /* now output what fits into the regular target */
+                value>>=8*length; /* length was reduced by targetCapacity */
+                switch(targetCapacity) {
+                    /* each branch falls through to the next one */
+                case 3:
+                    *target++=(uint8_t)(value>>16);
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex;
+                    }
+                case 2:
+                    *target++=(uint8_t)(value>>8);
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex;
+                    }
+                case 1:
+                    *target++=(uint8_t)value;
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex;
+                    }
+                default:
+                    /* will never occur */
+                    break;
+                }
+
+                /* target overflow */
+                targetCapacity=0;
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                c=0;
+                break;
+            }
+
+            /* normal end of conversion: prepare for a new character */
+            c=0;
+            if(offsets!=NULL) {
+                prevSourceIndex=sourceIndex;
+                sourceIndex=nextSourceIndex;
+            }
+            continue;
+        } else {
+            /* target is full */
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+    }
+
+    /*
+     * the end of the input stream and detection of truncated input
+     * are handled by the framework, but for EBCDIC_STATEFUL conversion
+     * we need to emit an SI at the very end
+     *
+     * conditions:
+     *   successful
+     *   EBCDIC_STATEFUL in DBCS mode
+     *   end of input and no truncated input
+     */
+    if( U_SUCCESS(*pErrorCode) &&
+        outputType==MBCS_OUTPUT_2_SISO && prevLength==2 &&
+        pArgs->flush && source>=sourceLimit && c==0
+    ) {
+        /* EBCDIC_STATEFUL ending with DBCS: emit an SI to return the output stream to SBCS */
+        if(targetCapacity>0) {
+            *target++=(uint8_t)si_value[0];
+            if (si_value_length == 2) {
+                if (targetCapacity<2) {
+                    cnv->charErrorBuffer[0]=(uint8_t)si_value[1];
+                    cnv->charErrorBufferLength=1;
+                    *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                } else {
+                    *target++=(uint8_t)si_value[1];
+                }
+            }
+            if(offsets!=NULL) {
+                /* set the last source character's index (sourceIndex points at sourceLimit now) */
+                *offsets++=prevSourceIndex;
+            }
+        } else {
+            /* target is full */
+            cnv->charErrorBuffer[0]=(uint8_t)si_value[0];
+            if (si_value_length == 2) {
+                cnv->charErrorBuffer[1]=(uint8_t)si_value[1];
+            }
+            cnv->charErrorBufferLength=si_value_length;
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+        }
+        prevLength=1; /* we switched into SBCS */
+    }
+
+    /* set the converter state back into UConverter */
+    cnv->fromUChar32=c;
+    cnv->fromUnicodeStatus=prevLength;
+
+    /* write back the updated pointers */
+    pArgs->source=source;
+    pArgs->target=(char *)target;
+    pArgs->offsets=offsets;
+}
+
+/*
+ * This is another simple conversion function for internal use by other
+ * conversion implementations.
+ * It does not use the converter state nor call callbacks.
+ * It does not handle the EBCDIC swaplfnl option (set in UConverter).
+ * It handles conversion extensions but not GB 18030.
+ *
+ * It converts one single Unicode code point into codepage bytes, encoded
+ * as one 32-bit value. The function returns the number of bytes in *pValue:
+ * 1..4 the number of bytes in *pValue
+ * 0    unassigned (*pValue undefined)
+ * -1   illegal (currently not used, *pValue undefined)
+ *
+ * *pValue will contain the resulting bytes with the last byte in bits 7..0,
+ * the second to last byte in bits 15..8, etc.
+ * Currently, the function assumes but does not check that 0<=c<=0x10ffff.
+ */
+U_CFUNC int32_t
+ucnv_MBCSFromUChar32(UConverterSharedData *sharedData,
+                 UChar32 c, uint32_t *pValue,
+                 UBool useFallback) {
+    const int32_t *cx;
+    const uint16_t *table;
+#if 0
+/* #if 0 because this is not currently used in ICU - reduce code, increase code coverage */
+    const uint8_t *p;
+#endif
+    uint32_t stage2Entry;
+    uint32_t value;
+    int32_t length;
+
+    /* BMP-only codepages are stored without stage 1 entries for supplementary code points */
+    if(c<=0xffff || (sharedData->mbcs.unicodeMask&UCNV_HAS_SUPPLEMENTARY)) {
+        table=sharedData->mbcs.fromUnicodeTable;
+
+        /* convert the Unicode code point in c into codepage bytes (same as in _MBCSFromUnicodeWithOffsets) */
+        if(sharedData->mbcs.outputType==MBCS_OUTPUT_1) {
+            value=MBCS_SINGLE_RESULT_FROM_U(table, (uint16_t *)sharedData->mbcs.fromUnicodeBytes, c);
+            /* is this code point assigned, or do we use fallbacks? */
+            if(useFallback ? value>=0x800 : value>=0xc00) {
+                *pValue=value&0xff;
+                return 1;
+            }
+        } else /* outputType!=MBCS_OUTPUT_1 */ {
+            stage2Entry=MBCS_STAGE_2_FROM_U(table, c);
+
+            /* get the bytes and the length for the output */
+            switch(sharedData->mbcs.outputType) {
+            case MBCS_OUTPUT_2:
+                value=MBCS_VALUE_2_FROM_STAGE_2(sharedData->mbcs.fromUnicodeBytes, stage2Entry, c);
+                if(value<=0xff) {
+                    length=1;
+                } else {
+                    length=2;
+                }
+                break;
+#if 0
+/* #if 0 because this is not currently used in ICU - reduce code, increase code coverage */
+            case MBCS_OUTPUT_DBCS_ONLY:
+                /* table with single-byte results, but only DBCS mappings used */
+                value=MBCS_VALUE_2_FROM_STAGE_2(sharedData->mbcs.fromUnicodeBytes, stage2Entry, c);
+                if(value<=0xff) {
+                    /* no mapping or SBCS result, not taken for DBCS-only */
+                    value=stage2Entry=0; /* stage2Entry=0 to reset roundtrip flags */
+                    length=0;
+                } else {
+                    length=2;
+                }
+                break;
+            case MBCS_OUTPUT_3:
+                p=MBCS_POINTER_3_FROM_STAGE_2(sharedData->mbcs.fromUnicodeBytes, stage2Entry, c);
+                value=((uint32_t)*p<<16)|((uint32_t)p[1]<<8)|p[2];
+                if(value<=0xff) {
+                    length=1;
+                } else if(value<=0xffff) {
+                    length=2;
+                } else {
+                    length=3;
+                }
+                break;
+            case MBCS_OUTPUT_4:
+                value=MBCS_VALUE_4_FROM_STAGE_2(sharedData->mbcs.fromUnicodeBytes, stage2Entry, c);
+                if(value<=0xff) {
+                    length=1;
+                } else if(value<=0xffff) {
+                    length=2;
+                } else if(value<=0xffffff) {
+                    length=3;
+                } else {
+                    length=4;
+                }
+                break;
+            case MBCS_OUTPUT_3_EUC:
+                value=MBCS_VALUE_2_FROM_STAGE_2(sharedData->mbcs.fromUnicodeBytes, stage2Entry, c);
+                /* EUC 16-bit fixed-length representation */
+                if(value<=0xff) {
+                    length=1;
+                } else if((value&0x8000)==0) {
+                    value|=0x8e8000;
+                    length=3;
+                } else if((value&0x80)==0) {
+                    value|=0x8f0080;
+                    length=3;
+                } else {
+                    length=2;
+                }
+                break;
+            case MBCS_OUTPUT_4_EUC:
+                p=MBCS_POINTER_3_FROM_STAGE_2(sharedData->mbcs.fromUnicodeBytes, stage2Entry, c);
+                value=((uint32_t)*p<<16)|((uint32_t)p[1]<<8)|p[2];
+                /* EUC 16-bit fixed-length representation applied to the first two bytes */
+                if(value<=0xff) {
+                    length=1;
+                } else if(value<=0xffff) {
+                    length=2;
+                } else if((value&0x800000)==0) {
+                    value|=0x8e800000;
+                    length=4;
+                } else if((value&0x8000)==0) {
+                    value|=0x8f008000;
+                    length=4;
+                } else {
+                    length=3;
+                }
+                break;
+#endif
+            default:
+                /* must not occur */
+                return -1;
+            }
+
+            /* is this code point assigned, or do we use fallbacks? */
+            if( MBCS_FROM_U_IS_ROUNDTRIP(stage2Entry, c) ||
+                (FROM_U_USE_FALLBACK(useFallback, c) && value!=0)
+            ) {
+                /*
+                 * We allow a 0 byte output if the "assigned" bit is set for this entry.
+                 * There is no way with this data structure for fallback output
+                 * to be a zero byte.
+                 */
+                /* assigned */
+                *pValue=value;
+                return length;
+            }
+        }
+    }
+
+    cx=sharedData->mbcs.extIndexes;
+    if(cx!=NULL) {
+        length=ucnv_extSimpleMatchFromU(cx, c, pValue, useFallback);
+        return length>=0 ? length : -length;  /* return abs(length); */
+    }
+
+    /* unassigned */
+    return 0;
+}
+
+
+#if 0
+/*
+ * This function has been moved to ucnv2022.c for inlining.
+ * This implementation is here only for documentation purposes
+ */
+
+/**
+ * This version of ucnv_MBCSFromUChar32() is optimized for single-byte codepages.
+ * It does not handle the EBCDIC swaplfnl option (set in UConverter).
+ * It does not handle conversion extensions (_extFromU()).
+ *
+ * It returns the codepage byte for the code point, or -1 if it is unassigned.
+ */
+U_CFUNC int32_t
+ucnv_MBCSSingleFromUChar32(UConverterSharedData *sharedData,
+                       UChar32 c,
+                       UBool useFallback) {
+    const uint16_t *table;
+    int32_t value;
+
+    /* BMP-only codepages are stored without stage 1 entries for supplementary code points */
+    if(c>=0x10000 && !(sharedData->mbcs.unicodeMask&UCNV_HAS_SUPPLEMENTARY)) {
+        return -1;
+    }
+
+    /* convert the Unicode code point in c into codepage bytes (same as in _MBCSFromUnicodeWithOffsets) */
+    table=sharedData->mbcs.fromUnicodeTable;
+
+    /* get the byte for the output */
+    value=MBCS_SINGLE_RESULT_FROM_U(table, (uint16_t *)sharedData->mbcs.fromUnicodeBytes, c);
+    /* is this code point assigned, or do we use fallbacks? */
+    if(useFallback ? value>=0x800 : value>=0xc00) {
+        return value&0xff;
+    } else {
+        return -1;
+    }
+}
+#endif
+
+/* MBCS-from-UTF-8 conversion functions ------------------------------------- */
+
+/* minimum code point values for n-byte UTF-8 sequences, n=0..4 */
+static const UChar32
+utf8_minLegal[5]={ 0, 0, 0x80, 0x800, 0x10000 };
+
+/* offsets for n-byte UTF-8 sequences that were calculated with ((lead<<6)+trail)<<6+trail... */
+static const UChar32
+utf8_offsets[7]={ 0, 0, 0x3080, 0xE2080, 0x3C82080 };
+
+static void
+ucnv_SBCSFromUTF8(UConverterFromUnicodeArgs *pFromUArgs,
+                  UConverterToUnicodeArgs *pToUArgs,
+                  UErrorCode *pErrorCode) {
+    UConverter *utf8, *cnv;
+    const uint8_t *source, *sourceLimit;
+    uint8_t *target;
+    int32_t targetCapacity;
+
+    const uint16_t *table, *sbcsIndex;
+    const uint16_t *results;
+
+    int8_t oldToULength, toULength, toULimit;
+
+    UChar32 c;
+    uint8_t b, t1, t2;
+
+    uint32_t asciiRoundtrips;
+    uint16_t value, minValue;
+    UBool hasSupplementary;
+
+    /* set up the local pointers */
+    utf8=pToUArgs->converter;
+    cnv=pFromUArgs->converter;
+    source=(uint8_t *)pToUArgs->source;
+    sourceLimit=(uint8_t *)pToUArgs->sourceLimit;
+    target=(uint8_t *)pFromUArgs->target;
+    targetCapacity=(int32_t)(pFromUArgs->targetLimit-pFromUArgs->target);
+
+    table=cnv->sharedData->mbcs.fromUnicodeTable;
+    sbcsIndex=cnv->sharedData->mbcs.sbcsIndex;
+    if((cnv->options&UCNV_OPTION_SWAP_LFNL)!=0) {
+        results=(uint16_t *)cnv->sharedData->mbcs.swapLFNLFromUnicodeBytes;
+    } else {
+        results=(uint16_t *)cnv->sharedData->mbcs.fromUnicodeBytes;
+    }
+    asciiRoundtrips=cnv->sharedData->mbcs.asciiRoundtrips;
+
+    if(cnv->useFallback) {
+        /* use all roundtrip and fallback results */
+        minValue=0x800;
+    } else {
+        /* use only roundtrips and fallbacks from private-use characters */
+        minValue=0xc00;
+    }
+    hasSupplementary=(UBool)(cnv->sharedData->mbcs.unicodeMask&UCNV_HAS_SUPPLEMENTARY);
+
+    /* get the converter state from the UTF-8 UConverter */
+    c=(UChar32)utf8->toUnicodeStatus;
+    if(c!=0) {
+        toULength=oldToULength=utf8->toULength;
+        toULimit=(int8_t)utf8->mode;
+    } else {
+        toULength=oldToULength=toULimit=0;
+    }
+
+    /*
+     * Make sure that the last byte sequence before sourceLimit is complete
+     * or runs into a lead byte.
+     * Do not go back into the bytes that will be read for finishing a partial
+     * sequence from the previous buffer.
+     * In the conversion loop compare source with sourceLimit only once
+     * per multi-byte character.
+     */
+    {
+        int32_t i, length;
+
+        length=(int32_t)(sourceLimit-source) - (toULimit-oldToULength);
+        for(i=0; i<3 && i<length;) {
+            b=*(sourceLimit-i-1);
+            if(U8_IS_TRAIL(b)) {
+                ++i;
+            } else {
+                if(i<utf8_countTrailBytes[b]) {
+                    /* exit the conversion loop before the lead byte if there are not enough trail bytes for it */
+                    sourceLimit-=i+1;
+                }
+                break;
+            }
+        }
+    }
+
+    if(c!=0 && targetCapacity>0) {
+        utf8->toUnicodeStatus=0;
+        utf8->toULength=0;
+        goto moreBytes;
+        /*
+         * Note: We could avoid the goto by duplicating some of the moreBytes
+         * code, but only up to the point of collecting a complete UTF-8
+         * sequence; then recurse for the toUBytes[toULength]
+         * and then continue with normal conversion.
+         *
+         * If so, move this code to just after initializing the minimum
+         * set of local variables for reading the UTF-8 input
+         * (utf8, source, target, limits but not cnv, table, minValue, etc.).
+         *
+         * Potential advantages:
+         * - avoid the goto
+         * - oldToULength could become a local variable in just those code blocks
+         *   that deal with buffer boundaries
+         * - possibly faster if the goto prevents some compiler optimizations
+         *   (this would need measuring to confirm)
+         * Disadvantage:
+         * - code duplication
+         */
+    }
+
+    /* conversion loop */
+    while(source<sourceLimit) {
+        if(targetCapacity>0) {
+            b=*source++;
+            if((int8_t)b>=0) {
+                /* convert ASCII */
+                if(IS_ASCII_ROUNDTRIP(b, asciiRoundtrips)) {
+                    *target++=(uint8_t)b;
+                    --targetCapacity;
+                    continue;
+                } else {
+                    c=b;
+                    value=SBCS_RESULT_FROM_UTF8(sbcsIndex, results, 0, c);
+                }
+            } else {
+                if(b<0xe0) {
+                    if( /* handle U+0080..U+07FF inline */
+                        b>=0xc2 &&
+                        (t1=(uint8_t)(*source-0x80)) <= 0x3f
+                    ) {
+                        c=b&0x1f;
+                        ++source;
+                        value=SBCS_RESULT_FROM_UTF8(sbcsIndex, results, c, t1);
+                        if(value>=minValue) {
+                            *target++=(uint8_t)value;
+                            --targetCapacity;
+                            continue;
+                        } else {
+                            c=(c<<6)|t1;
+                        }
+                    } else {
+                        c=-1;
+                    }
+                } else if(b==0xe0) {
+                    if( /* handle U+0800..U+0FFF inline */
+                        (t1=(uint8_t)(source[0]-0x80)) <= 0x3f && t1 >= 0x20 &&
+                        (t2=(uint8_t)(source[1]-0x80)) <= 0x3f
+                    ) {
+                        c=t1;
+                        source+=2;
+                        value=SBCS_RESULT_FROM_UTF8(sbcsIndex, results, c, t2);
+                        if(value>=minValue) {
+                            *target++=(uint8_t)value;
+                            --targetCapacity;
+                            continue;
+                        } else {
+                            c=(c<<6)|t2;
+                        }
+                    } else {
+                        c=-1;
+                    }
+                } else {
+                    c=-1;
+                }
+
+                if(c<0) {
+                    /* handle "complicated" and error cases, and continuing partial characters */
+                    oldToULength=0;
+                    toULength=1;
+                    toULimit=utf8_countTrailBytes[b]+1;
+                    c=b;
+moreBytes:
+                    while(toULength<toULimit) {
+                        /*
+                         * The sourceLimit may have been adjusted before the conversion loop
+                         * to stop before a truncated sequence.
+                         * Here we need to use the real limit in case we have two truncated
+                         * sequences at the end.
+                         * See ticket #7492.
+                         */
+                        if(source<(uint8_t *)pToUArgs->sourceLimit) {
+                            b=*source;
+                            if(U8_IS_TRAIL(b)) {
+                                ++source;
+                                ++toULength;
+                                c=(c<<6)+b;
+                            } else {
+                                break; /* sequence too short, stop with toULength<toULimit */
+                            }
+                        } else {
+                            /* store the partial UTF-8 character, compatible with the regular UTF-8 converter */
+                            source-=(toULength-oldToULength);
+                            while(oldToULength<toULength) {
+                                utf8->toUBytes[oldToULength++]=*source++;
+                            }
+                            utf8->toUnicodeStatus=c;
+                            utf8->toULength=toULength;
+                            utf8->mode=toULimit;
+                            pToUArgs->source=(char *)source;
+                            pFromUArgs->target=(char *)target;
+                            return;
+                        }
+                    }
+
+                    if( toULength==toULimit &&      /* consumed all trail bytes */
+                        (toULength==3 || toULength==2) &&             /* BMP */
+                        (c-=utf8_offsets[toULength])>=utf8_minLegal[toULength] &&
+                        (c<=0xd7ff || 0xe000<=c)    /* not a surrogate */
+                    ) {
+                        value=MBCS_SINGLE_RESULT_FROM_U(table, results, c);
+                    } else if(
+                        toULength==toULimit && toULength==4 &&
+                        (0x10000<=(c-=utf8_offsets[4]) && c<=0x10ffff)
+                    ) {
+                        /* supplementary code point */
+                        if(!hasSupplementary) {
+                            /* BMP-only codepages are stored without stage 1 entries for supplementary code points */
+                            value=0;
+                        } else {
+                            value=MBCS_SINGLE_RESULT_FROM_U(table, results, c);
+                        }
+                    } else {
+                        /* error handling: illegal UTF-8 byte sequence */
+                        source-=(toULength-oldToULength);
+                        while(oldToULength<toULength) {
+                            utf8->toUBytes[oldToULength++]=*source++;
+                        }
+                        utf8->toULength=toULength;
+                        pToUArgs->source=(char *)source;
+                        pFromUArgs->target=(char *)target;
+                        *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                        return;
+                    }
+                }
+            }
+
+            if(value>=minValue) {
+                /* output the mapping for c */
+                *target++=(uint8_t)value;
+                --targetCapacity;
+            } else {
+                /* value<minValue means c is unassigned (unmappable) */
+                /*
+                 * Try an extension mapping.
+                 * Pass in no source because we don't have UTF-16 input.
+                 * If we have a partial match on c, we will return and revert
+                 * to UTF-8->UTF-16->charset conversion.
+                 */
+                static const UChar nul=0;
+                const UChar *noSource=&nul;
+                c=_extFromU(cnv, cnv->sharedData,
+                            c, &noSource, noSource,
+                            &target, target+targetCapacity,
+                            NULL, -1,
+                            pFromUArgs->flush,
+                            pErrorCode);
+
+                if(U_FAILURE(*pErrorCode)) {
+                    /* not mappable or buffer overflow */
+                    cnv->fromUChar32=c;
+                    break;
+                } else if(cnv->preFromUFirstCP>=0) {
+                    /*
+                     * Partial match, return and revert to pivoting.
+                     * In normal from-UTF-16 conversion, we would just continue
+                     * but then exit the loop because the extension match would
+                     * have consumed the source.
+                     */
+                    break;
+                } else {
+                    /* a mapping was written to the target, continue */
+
+                    /* recalculate the targetCapacity after an extension mapping */
+                    targetCapacity=(int32_t)(pFromUArgs->targetLimit-(char *)target);
+                }
+            }
+        } else {
+            /* target is full */
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+    }
+
+    /*
+     * The sourceLimit may have been adjusted before the conversion loop
+     * to stop before a truncated sequence.
+     * If so, then collect the truncated sequence now.
+     */
+    if(U_SUCCESS(*pErrorCode) && source<(sourceLimit=(uint8_t *)pToUArgs->sourceLimit)) {
+        c=utf8->toUBytes[0]=b=*source++;
+        toULength=1;
+        toULimit=utf8_countTrailBytes[b]+1;
+        while(source<sourceLimit) {
+            utf8->toUBytes[toULength++]=b=*source++;
+            c=(c<<6)+b;
+        }
+        utf8->toUnicodeStatus=c;
+        utf8->toULength=toULength;
+        utf8->mode=toULimit;
+    }
+
+    /* write back the updated pointers */
+    pToUArgs->source=(char *)source;
+    pFromUArgs->target=(char *)target;
+}
+
+static void
+ucnv_DBCSFromUTF8(UConverterFromUnicodeArgs *pFromUArgs,
+                  UConverterToUnicodeArgs *pToUArgs,
+                  UErrorCode *pErrorCode) {
+    UConverter *utf8, *cnv;
+    const uint8_t *source, *sourceLimit;
+    uint8_t *target;
+    int32_t targetCapacity;
+
+    const uint16_t *table, *mbcsIndex;
+    const uint16_t *results;
+
+    int8_t oldToULength, toULength, toULimit;
+
+    UChar32 c;
+    uint8_t b, t1, t2;
+
+    uint32_t stage2Entry;
+    uint32_t asciiRoundtrips;
+    uint16_t value, minValue;
+    UBool hasSupplementary;
+
+    /* set up the local pointers */
+    utf8=pToUArgs->converter;
+    cnv=pFromUArgs->converter;
+    source=(uint8_t *)pToUArgs->source;
+    sourceLimit=(uint8_t *)pToUArgs->sourceLimit;
+    target=(uint8_t *)pFromUArgs->target;
+    targetCapacity=(int32_t)(pFromUArgs->targetLimit-pFromUArgs->target);
+
+    table=cnv->sharedData->mbcs.fromUnicodeTable;
+    mbcsIndex=cnv->sharedData->mbcs.mbcsIndex;
+    if((cnv->options&UCNV_OPTION_SWAP_LFNL)!=0) {
+        results=(uint16_t *)cnv->sharedData->mbcs.swapLFNLFromUnicodeBytes;
+    } else {
+        results=(uint16_t *)cnv->sharedData->mbcs.fromUnicodeBytes;
+    }
+    asciiRoundtrips=cnv->sharedData->mbcs.asciiRoundtrips;
+
+    if(cnv->useFallback) {
+        /* use all roundtrip and fallback results */
+        minValue=0x800;
+    } else {
+        /* use only roundtrips and fallbacks from private-use characters */
+        minValue=0xc00;
+    }
+    hasSupplementary=(UBool)(cnv->sharedData->mbcs.unicodeMask&UCNV_HAS_SUPPLEMENTARY);
+
+    /* get the converter state from the UTF-8 UConverter */
+    c=(UChar32)utf8->toUnicodeStatus;
+    if(c!=0) {
+        toULength=oldToULength=utf8->toULength;
+        toULimit=(int8_t)utf8->mode;
+    } else {
+        toULength=oldToULength=toULimit=0;
+    }
+
+    /*
+     * Make sure that the last byte sequence before sourceLimit is complete
+     * or runs into a lead byte.
+     * Do not go back into the bytes that will be read for finishing a partial
+     * sequence from the previous buffer.
+     * In the conversion loop compare source with sourceLimit only once
+     * per multi-byte character.
+     */
+    {
+        int32_t i, length;
+
+        length=(int32_t)(sourceLimit-source) - (toULimit-oldToULength);
+        for(i=0; i<3 && i<length;) {
+            b=*(sourceLimit-i-1);
+            if(U8_IS_TRAIL(b)) {
+                ++i;
+            } else {
+                if(i<utf8_countTrailBytes[b]) {
+                    /* exit the conversion loop before the lead byte if there are not enough trail bytes for it */
+                    sourceLimit-=i+1;
+                }
+                break;
+            }
+        }
+    }
+
+    if(c!=0 && targetCapacity>0) {
+        utf8->toUnicodeStatus=0;
+        utf8->toULength=0;
+        goto moreBytes;
+        /* See note in ucnv_SBCSFromUTF8() about this goto. */
+    }
+
+    /* conversion loop */
+    while(source<sourceLimit) {
+        if(targetCapacity>0) {
+            b=*source++;
+            if((int8_t)b>=0) {
+                /* convert ASCII */
+                if(IS_ASCII_ROUNDTRIP(b, asciiRoundtrips)) {
+                    *target++=b;
+                    --targetCapacity;
+                    continue;
+                } else {
+                    value=DBCS_RESULT_FROM_UTF8(mbcsIndex, results, 0, b);
+                    if(value==0) {
+                        c=b;
+                        goto unassigned;
+                    }
+                }
+            } else {
+                if(b>0xe0) {
+                    if( /* handle U+1000..U+D7FF inline */
+                        (((t1=(uint8_t)(source[0]-0x80), b<0xed) && (t1 <= 0x3f)) ||
+                                                        (b==0xed && (t1 <= 0x1f))) &&
+                        (t2=(uint8_t)(source[1]-0x80)) <= 0x3f
+                    ) {
+                        c=((b&0xf)<<6)|t1;
+                        source+=2;
+                        value=DBCS_RESULT_FROM_UTF8(mbcsIndex, results, c, t2);
+                        if(value==0) {
+                            c=(c<<6)|t2;
+                            goto unassigned;
+                        }
+                    } else {
+                        c=-1;
+                    }
+                } else if(b<0xe0) {
+                    if( /* handle U+0080..U+07FF inline */
+                        b>=0xc2 &&
+                        (t1=(uint8_t)(*source-0x80)) <= 0x3f
+                    ) {
+                        c=b&0x1f;
+                        ++source;
+                        value=DBCS_RESULT_FROM_UTF8(mbcsIndex, results, c, t1);
+                        if(value==0) {
+                            c=(c<<6)|t1;
+                            goto unassigned;
+                        }
+                    } else {
+                        c=-1;
+                    }
+                } else {
+                    c=-1;
+                }
+
+                if(c<0) {
+                    /* handle "complicated" and error cases, and continuing partial characters */
+                    oldToULength=0;
+                    toULength=1;
+                    toULimit=utf8_countTrailBytes[b]+1;
+                    c=b;
+moreBytes:
+                    while(toULength<toULimit) {
+                        /*
+                         * The sourceLimit may have been adjusted before the conversion loop
+                         * to stop before a truncated sequence.
+                         * Here we need to use the real limit in case we have two truncated
+                         * sequences at the end.
+                         * See ticket #7492.
+                         */
+                        if(source<(uint8_t *)pToUArgs->sourceLimit) {
+                            b=*source;
+                            if(U8_IS_TRAIL(b)) {
+                                ++source;
+                                ++toULength;
+                                c=(c<<6)+b;
+                            } else {
+                                break; /* sequence too short, stop with toULength<toULimit */
+                            }
+                        } else {
+                            /* store the partial UTF-8 character, compatible with the regular UTF-8 converter */
+                            source-=(toULength-oldToULength);
+                            while(oldToULength<toULength) {
+                                utf8->toUBytes[oldToULength++]=*source++;
+                            }
+                            utf8->toUnicodeStatus=c;
+                            utf8->toULength=toULength;
+                            utf8->mode=toULimit;
+                            pToUArgs->source=(char *)source;
+                            pFromUArgs->target=(char *)target;
+                            return;
+                        }
+                    }
+
+                    if( toULength==toULimit &&      /* consumed all trail bytes */
+                        (toULength==3 || toULength==2) &&             /* BMP */
+                        (c-=utf8_offsets[toULength])>=utf8_minLegal[toULength] &&
+                        (c<=0xd7ff || 0xe000<=c)    /* not a surrogate */
+                    ) {
+                        stage2Entry=MBCS_STAGE_2_FROM_U(table, c);
+                    } else if(
+                        toULength==toULimit && toULength==4 &&
+                        (0x10000<=(c-=utf8_offsets[4]) && c<=0x10ffff)
+                    ) {
+                        /* supplementary code point */
+                        if(!hasSupplementary) {
+                            /* BMP-only codepages are stored without stage 1 entries for supplementary code points */
+                            stage2Entry=0;
+                        } else {
+                            stage2Entry=MBCS_STAGE_2_FROM_U(table, c);
+                        }
+                    } else {
+                        /* error handling: illegal UTF-8 byte sequence */
+                        source-=(toULength-oldToULength);
+                        while(oldToULength<toULength) {
+                            utf8->toUBytes[oldToULength++]=*source++;
+                        }
+                        utf8->toULength=toULength;
+                        pToUArgs->source=(char *)source;
+                        pFromUArgs->target=(char *)target;
+                        *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                        return;
+                    }
+
+                    /* get the bytes and the length for the output */
+                    /* MBCS_OUTPUT_2 */
+                    value=MBCS_VALUE_2_FROM_STAGE_2(results, stage2Entry, c);
+
+                    /* is this code point assigned, or do we use fallbacks? */
+                    if(!(MBCS_FROM_U_IS_ROUNDTRIP(stage2Entry, c) ||
+                         (UCNV_FROM_U_USE_FALLBACK(cnv, c) && value!=0))
+                    ) {
+                        goto unassigned;
+                    }
+                }
+            }
+
+            /* write the output character bytes from value and length */
+            /* from the first if in the loop we know that targetCapacity>0 */
+            if(value<=0xff) {
+                /* this is easy because we know that there is enough space */
+                *target++=(uint8_t)value;
+                --targetCapacity;
+            } else /* length==2 */ {
+                *target++=(uint8_t)(value>>8);
+                if(2<=targetCapacity) {
+                    *target++=(uint8_t)value;
+                    targetCapacity-=2;
+                } else {
+                    cnv->charErrorBuffer[0]=(char)value;
+                    cnv->charErrorBufferLength=1;
+
+                    /* target overflow */
+                    *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                    break;
+                }
+            }
+            continue;
+
+unassigned:
+            {
+                /*
+                 * Try an extension mapping.
+                 * Pass in no source because we don't have UTF-16 input.
+                 * If we have a partial match on c, we will return and revert
+                 * to UTF-8->UTF-16->charset conversion.
+                 */
+                static const UChar nul=0;
+                const UChar *noSource=&nul;
+                c=_extFromU(cnv, cnv->sharedData,
+                            c, &noSource, noSource,
+                            &target, target+targetCapacity,
+                            NULL, -1,
+                            pFromUArgs->flush,
+                            pErrorCode);
+
+                if(U_FAILURE(*pErrorCode)) {
+                    /* not mappable or buffer overflow */
+                    cnv->fromUChar32=c;
+                    break;
+                } else if(cnv->preFromUFirstCP>=0) {
+                    /*
+                     * Partial match, return and revert to pivoting.
+                     * In normal from-UTF-16 conversion, we would just continue
+                     * but then exit the loop because the extension match would
+                     * have consumed the source.
+                     */
+                    break;
+                } else {
+                    /* a mapping was written to the target, continue */
+
+                    /* recalculate the targetCapacity after an extension mapping */
+                    targetCapacity=(int32_t)(pFromUArgs->targetLimit-(char *)target);
+                    continue;
+                }
+            }
+        } else {
+            /* target is full */
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            break;
+        }
+    }
+
+    /*
+     * The sourceLimit may have been adjusted before the conversion loop
+     * to stop before a truncated sequence.
+     * If so, then collect the truncated sequence now.
+     */
+    if(U_SUCCESS(*pErrorCode) && source<(sourceLimit=(uint8_t *)pToUArgs->sourceLimit)) {
+        c=utf8->toUBytes[0]=b=*source++;
+        toULength=1;
+        toULimit=utf8_countTrailBytes[b]+1;
+        while(source<sourceLimit) {
+            utf8->toUBytes[toULength++]=b=*source++;
+            c=(c<<6)+b;
+        }
+        utf8->toUnicodeStatus=c;
+        utf8->toULength=toULength;
+        utf8->mode=toULimit;
+    }
+
+    /* write back the updated pointers */
+    pToUArgs->source=(char *)source;
+    pFromUArgs->target=(char *)target;
+}
+
+/* miscellaneous ------------------------------------------------------------ */
+
+static void
+ucnv_MBCSGetStarters(const UConverter* cnv,
+                 UBool starters[256],
+                 UErrorCode *pErrorCode) {
+    const int32_t *state0;
+    int i;
+
+    state0=cnv->sharedData->mbcs.stateTable[cnv->sharedData->mbcs.dbcsOnlyState];
+    for(i=0; i<256; ++i) {
+        /* all bytes that cause a state transition from state 0 are lead bytes */
+        starters[i]= (UBool)MBCS_ENTRY_IS_TRANSITION(state0[i]);
+    }
+}
+
+/*
+ * This is an internal function that allows other converter implementations
+ * to check whether a byte is a lead byte.
+ */
+U_CFUNC UBool
+ucnv_MBCSIsLeadByte(UConverterSharedData *sharedData, char byte) {
+    return (UBool)MBCS_ENTRY_IS_TRANSITION(sharedData->mbcs.stateTable[0][(uint8_t)byte]);
+}
+
+static void
+ucnv_MBCSWriteSub(UConverterFromUnicodeArgs *pArgs,
+              int32_t offsetIndex,
+              UErrorCode *pErrorCode) {
+    UConverter *cnv=pArgs->converter;
+    char *p, *subchar;
+    char buffer[4];
+    int32_t length;
+
+    /* first, select between subChar and subChar1 */
+    if( cnv->subChar1!=0 &&
+        (cnv->sharedData->mbcs.extIndexes!=NULL ?
+            cnv->useSubChar1 :
+            (cnv->invalidUCharBuffer[0]<=0xff))
+    ) {
+        /* select subChar1 if it is set (not 0) and the unmappable Unicode code point is up to U+00ff (IBM MBCS behavior) */
+        subchar=(char *)&cnv->subChar1;
+        length=1;
+    } else {
+        /* select subChar in all other cases */
+        subchar=(char *)cnv->subChars;
+        length=cnv->subCharLen;
+    }
+
+    /* reset the selector for the next code point */
+    cnv->useSubChar1=FALSE;
+
+    if (cnv->sharedData->mbcs.outputType == MBCS_OUTPUT_2_SISO) {
+        p=buffer;
+
+        /* fromUnicodeStatus contains prevLength */
+        switch(length) {
+        case 1:
+            if(cnv->fromUnicodeStatus==2) {
+                /* DBCS mode and SBCS sub char: change to SBCS */
+                cnv->fromUnicodeStatus=1;
+                *p++=UCNV_SI;
+            }
+            *p++=subchar[0];
+            break;
+        case 2:
+            if(cnv->fromUnicodeStatus<=1) {
+                /* SBCS mode and DBCS sub char: change to DBCS */
+                cnv->fromUnicodeStatus=2;
+                *p++=UCNV_SO;
+            }
+            *p++=subchar[0];
+            *p++=subchar[1];
+            break;
+        default:
+            *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+            return;
+        }
+        subchar=buffer;
+        length=(int32_t)(p-buffer);
+    }
+
+    ucnv_cbFromUWriteBytes(pArgs, subchar, length, offsetIndex, pErrorCode);
+}
+
+U_CFUNC UConverterType
+ucnv_MBCSGetType(const UConverter* converter) {
+    /* SBCS, DBCS, and EBCDIC_STATEFUL are replaced by MBCS, but here we cheat a little */
+    if(converter->sharedData->mbcs.countStates==1) {
+        return (UConverterType)UCNV_SBCS;
+    } else if((converter->sharedData->mbcs.outputType&0xff)==MBCS_OUTPUT_2_SISO) {
+        return (UConverterType)UCNV_EBCDIC_STATEFUL;
+    } else if(converter->sharedData->staticData->minBytesPerChar==2 && converter->sharedData->staticData->maxBytesPerChar==2) {
+        return (UConverterType)UCNV_DBCS;
+    }
+    return (UConverterType)UCNV_MBCS;
+}
+
+static const UConverterImpl _SBCSUTF8Impl={
+    UCNV_MBCS,
+
+    ucnv_MBCSLoad,
+    ucnv_MBCSUnload,
+
+    ucnv_MBCSOpen,
+    NULL,
+    NULL,
+
+    ucnv_MBCSToUnicodeWithOffsets,
+    ucnv_MBCSToUnicodeWithOffsets,
+    ucnv_MBCSFromUnicodeWithOffsets,
+    ucnv_MBCSFromUnicodeWithOffsets,
+    ucnv_MBCSGetNextUChar,
+
+    ucnv_MBCSGetStarters,
+    ucnv_MBCSGetName,
+    ucnv_MBCSWriteSub,
+    NULL,
+    ucnv_MBCSGetUnicodeSet,
+
+    NULL,
+    ucnv_SBCSFromUTF8
+};
+
+static const UConverterImpl _DBCSUTF8Impl={
+    UCNV_MBCS,
+
+    ucnv_MBCSLoad,
+    ucnv_MBCSUnload,
+
+    ucnv_MBCSOpen,
+    NULL,
+    NULL,
+
+    ucnv_MBCSToUnicodeWithOffsets,
+    ucnv_MBCSToUnicodeWithOffsets,
+    ucnv_MBCSFromUnicodeWithOffsets,
+    ucnv_MBCSFromUnicodeWithOffsets,
+    ucnv_MBCSGetNextUChar,
+
+    ucnv_MBCSGetStarters,
+    ucnv_MBCSGetName,
+    ucnv_MBCSWriteSub,
+    NULL,
+    ucnv_MBCSGetUnicodeSet,
+
+    NULL,
+    ucnv_DBCSFromUTF8
+};
+
+static const UConverterImpl _MBCSImpl={
+    UCNV_MBCS,
+
+    ucnv_MBCSLoad,
+    ucnv_MBCSUnload,
+
+    ucnv_MBCSOpen,
+    NULL,
+    NULL,
+
+    ucnv_MBCSToUnicodeWithOffsets,
+    ucnv_MBCSToUnicodeWithOffsets,
+    ucnv_MBCSFromUnicodeWithOffsets,
+    ucnv_MBCSFromUnicodeWithOffsets,
+    ucnv_MBCSGetNextUChar,
+
+    ucnv_MBCSGetStarters,
+    ucnv_MBCSGetName,
+    ucnv_MBCSWriteSub,
+    NULL,
+    ucnv_MBCSGetUnicodeSet
+};
+
+
+/* Static data is in tools/makeconv/ucnvstat.c for data-based
+ * converters. Be sure to update it as well.
+ */
+
+const UConverterSharedData _MBCSData={
+    sizeof(UConverterSharedData), 1,
+    NULL, NULL, NULL, FALSE, &_MBCSImpl, 
+    0
+};
+
+#endif /* #if !UCONFIG_NO_LEGACY_CONVERSION */
diff --git a/source/common/ucnvmbcs.h b/source/common/ucnvmbcs.h
new file mode 100644
index 0000000..9e4f295
--- /dev/null
+++ b/source/common/ucnvmbcs.h
@@ -0,0 +1,563 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2000-2007, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  ucnvmbcs.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2000jul07
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __UCNVMBCS_H__
+#define __UCNVMBCS_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ucnv.h"
+#include "ucnv_cnv.h"
+#include "ucnv_ext.h"
+
+/**
+ * ICU conversion (.cnv) data file structure, following the usual UDataInfo
+ * header.
+ *
+ * Format version: 6.2
+ *
+ * struct UConverterStaticData -- struct containing the converter name, IBM CCSID,
+ *                                min/max bytes per character, etc.
+ *                                see ucnv_bld.h
+ *
+ * --------------------
+ *
+ * The static data is followed by conversionType-specific data structures.
+ * At the moment, there are only variations of MBCS converters. They all have
+ * the same toUnicode structures, while the fromUnicode structures for SBCS
+ * differ from those for other MBCS-style converters.
+ *
+ * _MBCSHeader.version 5 is optional and not backward-compatible
+ * (as usual for changes in the major version field).
+ *
+ * Versions 5.m work like versions 4.m except:
+ * - The _MBCSHeader has variable length (and is always longer than in version 4).
+ *   See the struct _MBCSHeader further description below.
+ * - There is a set of flags which indicate further incompatible changes.
+ *   (Reader code must reject the file if it does not recognize them all.)
+ * - In particular, one of these flags indicates that most of the fromUnicode
+ *   data is missing and must be reconstituted from the toUnicode data
+ *   and from the utf8Friendly mbcsIndex at load time.
+ *   (This only works with a utf8Friendly table.)
+ *   In this case, makeconv may increase maxFastUChar automatically to U+FFFF.
+ *
+ * The first of these versions is 5.3, which is like 4.3 except for the differences above.
+ *
+ * When possible, makeconv continues to generate version 4.m files.
+ *
+ * _MBCSHeader.version 4.3 optionally modifies the fromUnicode data structures
+ * slightly and optionally adds a table for conversion to MBCS (non-SBCS)
+ * charsets.
+ *
+ * The modifications are to make the data utf8Friendly. Not every 4.3 file
+ * file contains utf8Friendly data.
+ * It is utf8Friendly if _MBCSHeader.version[2]!=0.
+ * In this case, the data structures are utf8Friendly up to the code point
+ *   maxFastUChar=((_MBCSHeader.version[2]<<8)|0xff)
+ *
+ * A utf8Friendly file has fromUnicode stage 3 entries for code points up to
+ * maxFastUChar allocated in blocks of 64 for indexing with the 6 bits from
+ * a UTF-8 trail byte. ASCII is allocated linearly with 128 contiguous entries.
+ *
+ * In addition, a utf8Friendly MBCS file contains an additional
+ *   uint16_t mbcsIndex[(maxFastUChar+1)>>6];
+ * which replaces the stage 1 and 2 tables for indexing with bits from the
+ * UTF-8 lead byte and middle trail byte. Unlike the older MBCS stage 2 table,
+ * the mbcsIndex does not contain roundtrip flags. Therefore, all fallbacks
+ * from code points up to maxFastUChar (and roundtrips to 0x00) are moved to
+ * the extension data structure. This also allows for faster roundtrip
+ * conversion from UTF-16.
+ *
+ * SBCS files do not contain an additional sbcsIndex[] array because the
+ * proportional size increase would be noticeable, but the runtime
+ * code builds one for the code point range for which the runtime conversion
+ * code is optimized.
+ *
+ * For SBCS, maxFastUChar should be at least U+0FFF. The initial makeconv
+ * implementation sets it to U+1FFF. Because the sbcsIndex is not stored in
+ * the file, a larger maxFastUChar only affects stage 3 block allocation size
+ * and is free in empty blocks. (Larger blocks with sparse contents cause larger
+ * files.) U+1FFF includes almost all of the small scripts.
+ * U+0FFF covers UTF-8 two-byte sequences and three-byte sequences starting with
+ * 0xe0. This includes most scripts with legacy SBCS charsets.
+ * The initial runtime implementation using 4.3 files only builds an sbcsIndex
+ * for code points up to U+0FFF.
+ *
+ * For MBCS, maxFastUChar should be at least U+D7FF (=initial value).
+ * This boundary is convenient because practically all of the commonly used
+ * characters are below it, and because it is the boundary to surrogate
+ * code points, above which special handling is necessary anyway.
+ * (Surrogate pair assembly for UTF-16, validity checking for UTF-8.)
+ *
+ * maxFastUChar could be up to U+FFFF to cover the whole BMP, which could be
+ * useful especially for conversion from UTF-8 when the input can be assumed
+ * to be valid, because the surrogate range would then not have to be
+ * checked.
+ * (With maxFastUChar=0xffff, makeconv would have to check for mbcsIndex value
+ * overflow because with the all-unassigned block 0 and nearly full mappings
+ * from the BMP it is theoretically possible that an index into stage 3
+ * exceeds 16 bits.)
+ *
+ * _MBCSHeader.version 4.2 adds an optional conversion extension data structure.
+ * If it is present, then an ICU version reading header versions 4.0 or 4.1
+ * will be able to use the base table and ignore the extension.
+ *
+ * The unicodeMask in the static data is part of the base table data structure.
+ * Especially, the UCNV_HAS_SUPPLEMENTARY flag determines the length of the
+ * fromUnicode stage 1 array.
+ * The static data unicodeMask refers only to the base table's properties if
+ * a base table is included.
+ * In an extension-only file, the static data unicodeMask is 0.
+ * The extension data indexes have a separate field with the unicodeMask flags.
+ *
+ * MBCS-style data structure following the static data.
+ * Offsets are counted in bytes from the beginning of the MBCS header structure.
+ * Details about usage in comments in ucnvmbcs.c.
+ *
+ * struct _MBCSHeader (see the definition in this header file below)
+ * contains 32-bit fields as follows:
+ * 8 values:
+ *  0   uint8_t[4]  MBCS version in UVersionInfo format (currently 4.3.x.0)
+ *  1   uint32_t    countStates
+ *  2   uint32_t    countToUFallbacks
+ *  3   uint32_t    offsetToUCodeUnits
+ *  4   uint32_t    offsetFromUTable
+ *  5   uint32_t    offsetFromUBytes
+ *  6   uint32_t    flags, bits:
+ *                      31.. 8 offsetExtension -- _MBCSHeader.version 4.2 (ICU 2.8) and higher
+ *                                                0 for older versions and if
+ *                                                there is not extension structure
+ *                       7.. 0 outputType
+ *  7   uint32_t    fromUBytesLength -- _MBCSHeader.version 4.1 (ICU 2.4) and higher
+ *                  counts bytes in fromUBytes[]
+ *
+ * New and required in version 5:
+ *  8   uint32_t    options, bits:
+ *                      31..16 reserved for flags that can be added without breaking
+ *                                 backward compatibility
+ *                      15.. 6 reserved for flags whose addition will break
+ *                                 backward compatibility
+ *                           6 MBCS_OPT_FROM_U -- if set,
+ *                                 then most of the fromUnicode data is omitted;
+ *                                 fullStage2Length is present and the missing
+ *                                 bottom part of stage 2 must be reconstituted from
+ *                                 the toUnicode data;
+ *                                 stage 3 is missing completely as well;
+ *                                 not used for SBCS tables
+ *                       5.. 0 length of the _MBCSHeader (number of uint32_t)
+ *
+ * New and optional in version 5:
+ *  9   uint32_t    fullStage2Length: used if MBCS_OPT_FROM_U is set
+ *                                 specifies the full length of stage 2
+ *                                 including the omitted part
+ *
+ * if(outputType==MBCS_OUTPUT_EXT_ONLY) {
+ *     -- base table name for extension-only table
+ *     char baseTableName[variable]; -- with NUL plus padding for 4-alignment
+ *
+ *     -- all _MBCSHeader fields except for version and flags are 0
+ * } else {
+ *     -- normal base table with optional extension
+ *
+ *     int32_t stateTable[countStates][256];
+ *    
+ *     struct _MBCSToUFallback { (fallbacks are sorted by offset)
+ *         uint32_t offset;
+ *         UChar32 codePoint;
+ *     } toUFallbacks[countToUFallbacks];
+ *    
+ *     uint16_t unicodeCodeUnits[(offsetFromUTable-offsetToUCodeUnits)/2];
+ *                  (padded to an even number of units)
+ *    
+ *     -- stage 1 tables
+ *     if(staticData.unicodeMask&UCNV_HAS_SUPPLEMENTARY) {
+ *         -- stage 1 table for all of Unicode
+ *         uint16_t fromUTable[0x440]; (32-bit-aligned)
+ *     } else {
+ *         -- BMP-only tables have a smaller stage 1 table
+ *         uint16_t fromUTable[0x40]; (32-bit-aligned)
+ *     }
+ *
+ *     -- stage 2 tables
+ *        length determined by top of stage 1 and bottom of stage 3 tables
+ *     if(outputType==MBCS_OUTPUT_1) {
+ *         -- SBCS: pure indexes
+ *         uint16_t stage 2 indexes[?];
+ *     } else {
+ *         -- DBCS, MBCS, EBCDIC_STATEFUL, ...: roundtrip flags and indexes
+ *         uint32_t stage 2 flags and indexes[?];
+ *         if(options&MBCS_OPT_NO_FROM_U) {
+ *             stage 2 really has length fullStage2Length
+ *             and the omitted lower part must be reconstituted from
+ *             the toUnicode data
+ *         }
+ *     }
+ *
+ *     -- stage 3 tables with byte results
+ *     if(outputType==MBCS_OUTPUT_1) {
+ *         -- SBCS: each 16-bit result contains flags and the result byte, see ucnvmbcs.c
+ *         uint16_t fromUBytes[fromUBytesLength/2];
+ *     } else if(!(options&MBCS_OPT_NO_FROM_U)) {
+ *         -- DBCS, MBCS, EBCDIC_STATEFUL, ... 2/3/4 bytes result, see ucnvmbcs.c
+ *         uint8_t fromUBytes[fromUBytesLength]; or
+ *         uint16_t fromUBytes[fromUBytesLength/2]; or
+ *         uint32_t fromUBytes[fromUBytesLength/4];
+ *     } else {
+ *         fromUBytes[] must be reconstituted from the toUnicode data
+ *     }
+ *
+ *     -- optional utf8Friendly mbcsIndex -- _MBCSHeader.version 4.3 (ICU 3.8) and higher
+ *     if(outputType!=MBCS_OUTPUT_1 &&
+ *        _MBCSHeader.version[1]>=3 &&
+ *        (maxFastUChar=_MBCSHeader.version[2])!=0
+ *     ) {
+ *         maxFastUChar=(maxFastUChar<<8)|0xff;
+ *         uint16_t mbcsIndex[(maxFastUChar+1)>>6];
+ *     }
+ * }
+ *
+ * -- extension table, details see ucnv_ext.h
+ * int32_t indexes[>=32]; ...
+ */
+
+/* MBCS converter data and state -------------------------------------------- */
+
+enum {
+    MBCS_MAX_STATE_COUNT=128
+};
+
+/**
+ * MBCS action codes for conversions to Unicode.
+ * These values are in bits 23..20 of the state table entries.
+ */
+enum {
+    MBCS_STATE_VALID_DIRECT_16,
+    MBCS_STATE_VALID_DIRECT_20,
+
+    MBCS_STATE_FALLBACK_DIRECT_16,
+    MBCS_STATE_FALLBACK_DIRECT_20,
+
+    MBCS_STATE_VALID_16,
+    MBCS_STATE_VALID_16_PAIR,
+
+    MBCS_STATE_UNASSIGNED,
+    MBCS_STATE_ILLEGAL,
+
+    MBCS_STATE_CHANGE_ONLY
+};
+
+/* Macros for state table entries */
+#define MBCS_ENTRY_TRANSITION(state, offset) (int32_t)(((int32_t)(state)<<24L)|(offset))
+#define MBCS_ENTRY_TRANSITION_SET_OFFSET(entry, offset) (int32_t)(((entry)&0xff000000)|(offset))
+#define MBCS_ENTRY_TRANSITION_ADD_OFFSET(entry, offset) (int32_t)((entry)+(offset))
+
+#define MBCS_ENTRY_FINAL(state, action, value) (int32_t)(0x80000000|((int32_t)(state)<<24L)|((action)<<20L)|(value))
+#define MBCS_ENTRY_SET_FINAL(entry) (int32_t)((entry)|0x80000000)
+#define MBCS_ENTRY_FINAL_SET_ACTION(entry, action) (int32_t)(((entry)&0xff0fffff)|((int32_t)(action)<<20L))
+#define MBCS_ENTRY_FINAL_SET_VALUE(entry, value) (int32_t)(((entry)&0xfff00000)|(value))
+#define MBCS_ENTRY_FINAL_SET_ACTION_VALUE(entry, action, value) (int32_t)(((entry)&0xff000000)|((int32_t)(action)<<20L)|(value))
+
+#define MBCS_ENTRY_SET_STATE(entry, state) (int32_t)(((entry)&0x80ffffff)|((int32_t)(state)<<24L))
+
+#define MBCS_ENTRY_STATE(entry) (((entry)>>24)&0x7f)
+
+#define MBCS_ENTRY_IS_TRANSITION(entry) ((entry)>=0)
+#define MBCS_ENTRY_IS_FINAL(entry) ((entry)<0)
+
+#define MBCS_ENTRY_TRANSITION_STATE(entry) ((entry)>>24)
+#define MBCS_ENTRY_TRANSITION_OFFSET(entry) ((entry)&0xffffff)
+
+#define MBCS_ENTRY_FINAL_STATE(entry) (((entry)>>24)&0x7f)
+#define MBCS_ENTRY_FINAL_IS_VALID_DIRECT_16(entry) ((entry)<(int32_t)0x80100000)
+#define MBCS_ENTRY_FINAL_ACTION(entry) (((entry)>>20)&0xf)
+#define MBCS_ENTRY_FINAL_VALUE(entry) ((entry)&0xfffff)
+#define MBCS_ENTRY_FINAL_VALUE_16(entry) (uint16_t)(entry)
+
+#define IS_ASCII_ROUNDTRIP(b, asciiRoundtrips) (((asciiRoundtrips) & (1<<((b)>>2)))!=0)
+
+/* single-byte fromUnicode: get the 16-bit result word */
+#define MBCS_SINGLE_RESULT_FROM_U(table, results, c) (results)[ (table)[ (table)[(c)>>10] +(((c)>>4)&0x3f) ] +((c)&0xf) ]
+
+/* single-byte fromUnicode using the sbcsIndex */
+#define SBCS_RESULT_FROM_LOW_BMP(table, results, c) (results)[ (table)[(c)>>6] +((c)&0x3f) ]
+
+/* single-byte fromUTF8 using the sbcsIndex; l and t must be masked externally; can be l=0 and t<=0x7f */
+#define SBCS_RESULT_FROM_UTF8(table, results, l, t) (results)[ (table)[l] +(t) ]
+
+/* multi-byte fromUnicode: get the 32-bit stage 2 entry */
+#define MBCS_STAGE_2_FROM_U(table, c) ((const uint32_t *)(table))[ (table)[(c)>>10] +(((c)>>4)&0x3f) ]
+#define MBCS_FROM_U_IS_ROUNDTRIP(stage2Entry, c) ( ((stage2Entry) & ((uint32_t)1<< (16+((c)&0xf)) )) !=0)
+
+#define MBCS_VALUE_2_FROM_STAGE_2(bytes, stage2Entry, c) ((uint16_t *)(bytes))[16*(uint32_t)(uint16_t)(stage2Entry)+((c)&0xf)]
+#define MBCS_VALUE_4_FROM_STAGE_2(bytes, stage2Entry, c) ((uint32_t *)(bytes))[16*(uint32_t)(uint16_t)(stage2Entry)+((c)&0xf)]
+
+#define MBCS_POINTER_3_FROM_STAGE_2(bytes, stage2Entry, c) ((bytes)+(16*(uint32_t)(uint16_t)(stage2Entry)+((c)&0xf))*3)
+
+/* double-byte fromUnicode using the mbcsIndex */
+#define DBCS_RESULT_FROM_MOST_BMP(table, results, c) (results)[ (table)[(c)>>6] +((c)&0x3f) ]
+
+/* double-byte fromUTF8 using the mbcsIndex; l and t1 combined into lt1; lt1 and t2 must be masked externally */
+#define DBCS_RESULT_FROM_UTF8(table, results, lt1, t2) (results)[ (table)[lt1] +(t2) ]
+
+
+/**
+ * MBCS output types for conversions from Unicode.
+ * These per-converter types determine the storage method in stage 3 of the lookup table,
+ * mostly how many bytes are stored per entry.
+ */
+enum {
+    MBCS_OUTPUT_1,          /* 0 */
+    MBCS_OUTPUT_2,          /* 1 */
+    MBCS_OUTPUT_3,          /* 2 */
+    MBCS_OUTPUT_4,          /* 3 */
+
+    MBCS_OUTPUT_3_EUC=8,    /* 8 */
+    MBCS_OUTPUT_4_EUC,      /* 9 */
+
+    MBCS_OUTPUT_2_SISO=12,  /* c */
+    MBCS_OUTPUT_2_HZ,       /* d */
+
+    MBCS_OUTPUT_EXT_ONLY,   /* e */
+
+    MBCS_OUTPUT_COUNT,
+
+    MBCS_OUTPUT_DBCS_ONLY=0xdb  /* runtime-only type for DBCS-only handling of SISO tables */
+};
+
+/**
+ * Fallbacks to Unicode are stored outside the normal state table and code point structures
+ * in a vector of items of this type. They are sorted by offset.
+ */
+typedef struct {
+    uint32_t offset;
+    UChar32 codePoint;
+} _MBCSToUFallback;
+
+/** Constants for fast and UTF-8-friendly conversion. */
+enum {
+    SBCS_FAST_MAX=0x0fff,               /* maximum code point with UTF-8-friendly SBCS runtime code, see makeconv SBCS_UTF8_MAX */
+    SBCS_FAST_LIMIT=SBCS_FAST_MAX+1,    /* =0x1000 */
+    MBCS_FAST_MAX=0xd7ff,               /* maximum code point with UTF-8-friendly MBCS runtime code, see makeconv MBCS_UTF8_MAX */
+    MBCS_FAST_LIMIT=MBCS_FAST_MAX+1     /* =0xd800 */
+};
+
+/**
+ * This is the MBCS part of the UConverterTable union (a runtime data structure).
+ * It keeps all the per-converter data and points into the loaded mapping tables.
+ *
+ * utf8Friendly data structures added with _MBCSHeader.version 4.3
+ */
+typedef struct UConverterMBCSTable {
+    /* toUnicode */
+    uint8_t countStates, dbcsOnlyState, stateTableOwned;
+    uint32_t countToUFallbacks;
+
+    const int32_t (*stateTable)/*[countStates]*/[256];
+    int32_t (*swapLFNLStateTable)/*[countStates]*/[256]; /* for swaplfnl */
+    const uint16_t *unicodeCodeUnits/*[countUnicodeResults]*/;
+    const _MBCSToUFallback *toUFallbacks;
+
+    /* fromUnicode */
+    const uint16_t *fromUnicodeTable;
+    const uint16_t *mbcsIndex;              /* for fast conversion from most of BMP to MBCS (utf8Friendly data) */
+    uint16_t sbcsIndex[SBCS_FAST_LIMIT>>6]; /* for fast conversion from low BMP to SBCS (utf8Friendly data) */
+    const uint8_t *fromUnicodeBytes;
+    uint8_t *swapLFNLFromUnicodeBytes;      /* for swaplfnl */
+    uint32_t fromUBytesLength;
+    uint8_t outputType, unicodeMask;
+    UBool utf8Friendly;                     /* for utf8Friendly data */
+    UChar maxFastUChar;                     /* for utf8Friendly data */
+
+    /* roundtrips */
+    uint32_t asciiRoundtrips;
+
+    /* reconstituted data that was omitted from the .cnv file */
+    uint8_t *reconstitutedData;
+
+    /* converter name for swaplfnl */
+    char *swapLFNLName;
+
+    /* extension data */
+    struct UConverterSharedData *baseSharedData;
+    const int32_t *extIndexes;
+} UConverterMBCSTable;
+
+enum {
+    MBCS_OPT_LENGTH_MASK=0x3f,
+    MBCS_OPT_NO_FROM_U=0x40,
+    /*
+     * If any of the following options bits are set,
+     * then the file must be rejected.
+     */
+    MBCS_OPT_INCOMPATIBLE_MASK=0xffc0,
+    /*
+     * Remove bits from this mask as more options are recognized
+     * by all implementations that use this constant.
+     */
+    MBCS_OPT_UNKNOWN_INCOMPATIBLE_MASK=0xff80
+};
+
+enum {
+    MBCS_HEADER_V4_LENGTH=8,
+    MBCS_HEADER_V5_MIN_LENGTH=9
+};
+
+/**
+ * MBCS data header. See data format description above.
+ */
+typedef struct {
+    UVersionInfo version;
+    uint32_t countStates,
+             countToUFallbacks,
+             offsetToUCodeUnits,
+             offsetFromUTable,
+             offsetFromUBytes,
+             flags,
+             fromUBytesLength;
+
+    /* new and required in version 5 */
+    uint32_t options;
+
+    /* new and optional in version 5; used if options&MBCS_OPT_NO_FROM_U */
+    uint32_t fullStage2Length;  /* number of 32-bit units */
+} _MBCSHeader;
+
+/*
+ * This is a simple version of _MBCSGetNextUChar() that is used
+ * by other converter implementations.
+ * It only returns an "assigned" result if it consumes the entire input.
+ * It does not use state from the converter, nor error codes.
+ * It does not handle the EBCDIC swaplfnl option (set in UConverter).
+ * It handles conversion extensions but not GB 18030.
+ *
+ * Return value:
+ * U+fffe   unassigned
+ * U+ffff   illegal
+ * otherwise the Unicode code point
+ */
+U_CFUNC UChar32
+ucnv_MBCSSimpleGetNextUChar(UConverterSharedData *sharedData,
+                        const char *source, int32_t length,
+                        UBool useFallback);
+
+/**
+ * This version of _MBCSSimpleGetNextUChar() is optimized for single-byte, single-state codepages.
+ * It does not handle the EBCDIC swaplfnl option (set in UConverter).
+ * It does not handle conversion extensions (_extToU()).
+ */
+U_CFUNC UChar32
+ucnv_MBCSSingleSimpleGetNextUChar(UConverterSharedData *sharedData,
+                              uint8_t b, UBool useFallback);
+
+/**
+ * This macro version of _MBCSSingleSimpleGetNextUChar() gets a code point from a byte.
+ * It works for single-byte, single-state codepages that only map
+ * to and from BMP code points, and it always
+ * returns fallback values.
+ */
+#define _MBCS_SINGLE_SIMPLE_GET_NEXT_BMP(sharedData, b) \
+    (UChar)MBCS_ENTRY_FINAL_VALUE_16((sharedData)->mbcs.stateTable[0][(uint8_t)(b)])
+
+/**
+ * This is an internal function that allows other converter implementations
+ * to check whether a byte is a lead byte.
+ */
+U_CFUNC UBool
+ucnv_MBCSIsLeadByte(UConverterSharedData *sharedData, char byte);
+
+/** This is a macro version of _MBCSIsLeadByte(). */
+#define _MBCS_IS_LEAD_BYTE(sharedData, byte) \
+    (UBool)MBCS_ENTRY_IS_TRANSITION((sharedData)->mbcs.stateTable[0][(uint8_t)(byte)])
+
+/*
+ * This is another simple conversion function for internal use by other
+ * conversion implementations.
+ * It does not use the converter state nor call callbacks.
+ * It does not handle the EBCDIC swaplfnl option (set in UConverter).
+ * It handles conversion extensions but not GB 18030.
+ *
+ * It converts one single Unicode code point into codepage bytes, encoded
+ * as one 32-bit value. The function returns the number of bytes in *pValue:
+ * 1..4 the number of bytes in *pValue
+ * 0    unassigned (*pValue undefined)
+ * -1   illegal (currently not used, *pValue undefined)
+ *
+ * *pValue will contain the resulting bytes with the last byte in bits 7..0,
+ * the second to last byte in bits 15..8, etc.
+ * Currently, the function assumes but does not check that 0<=c<=0x10ffff.
+ */
+U_CFUNC int32_t
+ucnv_MBCSFromUChar32(UConverterSharedData *sharedData,
+                 UChar32 c, uint32_t *pValue,
+                 UBool useFallback);
+
+/**
+ * This version of _MBCSFromUChar32() is optimized for single-byte codepages.
+ * It does not handle the EBCDIC swaplfnl option (set in UConverter).
+ *
+ * It returns the codepage byte for the code point, or -1 if it is unassigned.
+ */
+U_CFUNC int32_t
+ucnv_MBCSSingleFromUChar32(UConverterSharedData *sharedData,
+                       UChar32 c,
+                       UBool useFallback);
+
+/**
+ * SBCS, DBCS, and EBCDIC_STATEFUL are replaced by MBCS, but
+ * we cheat a little about the type, returning the old types if appropriate.
+ */
+U_CFUNC UConverterType
+ucnv_MBCSGetType(const UConverter* converter);
+
+U_CFUNC void 
+ucnv_MBCSFromUnicodeWithOffsets(UConverterFromUnicodeArgs *pArgs,
+                            UErrorCode *pErrorCode);
+U_CFUNC void 
+ucnv_MBCSToUnicodeWithOffsets(UConverterToUnicodeArgs *pArgs,
+                          UErrorCode *pErrorCode);
+
+/*
+ * Internal function returning a UnicodeSet for toUnicode() conversion.
+ * Currently only used for ISO-2022-CN, and only handles roundtrip mappings.
+ * In the future, if we add support for fallback sets, this function
+ * needs to be updated.
+ * Handles extensions.
+ * Does not empty the set first.
+ */
+U_CFUNC void
+ucnv_MBCSGetUnicodeSetForUnicode(const UConverterSharedData *sharedData,
+                                 const USetAdder *sa,
+                                 UConverterUnicodeSet which,
+                                 UErrorCode *pErrorCode);
+
+/*
+ * Same as ucnv_MBCSGetUnicodeSetForUnicode() but
+ * the set can be filtered by encoding scheme.
+ * Used by stateful converters which share regular conversion tables
+ * but only use a subset of their mappings.
+ */
+U_CFUNC void
+ucnv_MBCSGetFilteredUnicodeSetForUnicode(const UConverterSharedData *sharedData,
+                                         const USetAdder *sa,
+                                         UConverterUnicodeSet which,
+                                         UConverterSetFilter filter,
+                                         UErrorCode *pErrorCode);
+
+#endif
+
+#endif
diff --git a/source/common/ucnvscsu.c b/source/common/ucnvscsu.c
new file mode 100644
index 0000000..76e973d
--- /dev/null
+++ b/source/common/ucnvscsu.c
@@ -0,0 +1,2017 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2000-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  ucnvscsu.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2000nov18
+*   created by: Markus W. Scherer
+*
+*   This is an implementation of the Standard Compression Scheme for Unicode
+*   as defined in http://www.unicode.org/unicode/reports/tr6/ .
+*   Reserved commands and window settings are treated as illegal sequences and
+*   will result in callback calls.
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ucnv.h"
+#include "unicode/ucnv_cb.h"
+#include "ucnv_bld.h"
+#include "ucnv_cnv.h"
+#include "cmemory.h"
+
+/* SCSU definitions --------------------------------------------------------- */
+
+/* SCSU command byte values */
+enum {
+    SQ0=0x01, /* Quote from window pair 0 */
+    SQ7=0x08, /* Quote from window pair 7 */
+    SDX=0x0B, /* Define a window as extended */
+    Srs=0x0C, /* reserved */
+    SQU=0x0E, /* Quote a single Unicode character */
+    SCU=0x0F, /* Change to Unicode mode */
+    SC0=0x10, /* Select window 0 */
+    SC7=0x17, /* Select window 7 */
+    SD0=0x18, /* Define and select window 0 */
+    SD7=0x1F, /* Define and select window 7 */
+
+    UC0=0xE0, /* Select window 0 */
+    UC7=0xE7, /* Select window 7 */
+    UD0=0xE8, /* Define and select window 0 */
+    UD7=0xEF, /* Define and select window 7 */
+    UQU=0xF0, /* Quote a single Unicode character */
+    UDX=0xF1, /* Define a Window as extended */
+    Urs=0xF2  /* reserved */
+};
+
+enum {
+    /*
+     * Unicode code points from 3400 to E000 are not adressible by
+     * dynamic window, since in these areas no short run alphabets are
+     * found. Therefore add gapOffset to all values from gapThreshold.
+     */
+    gapThreshold=0x68,
+    gapOffset=0xAC00,
+
+    /* values between reservedStart and fixedThreshold are reserved */
+    reservedStart=0xA8,
+
+    /* use table of predefined fixed offsets for values from fixedThreshold */
+    fixedThreshold=0xF9
+};
+
+/* constant offsets for the 8 static windows */
+static const uint32_t staticOffsets[8]={
+    0x0000, /* ASCII for quoted tags */
+    0x0080, /* Latin - 1 Supplement (for access to punctuation) */
+    0x0100, /* Latin Extended-A */
+    0x0300, /* Combining Diacritical Marks */
+    0x2000, /* General Punctuation */
+    0x2080, /* Currency Symbols */
+    0x2100, /* Letterlike Symbols and Number Forms */
+    0x3000  /* CJK Symbols and punctuation */
+};
+
+/* initial offsets for the 8 dynamic (sliding) windows */
+static const uint32_t initialDynamicOffsets[8]={
+    0x0080, /* Latin-1 */
+    0x00C0, /* Latin Extended A */
+    0x0400, /* Cyrillic */
+    0x0600, /* Arabic */
+    0x0900, /* Devanagari */
+    0x3040, /* Hiragana */
+    0x30A0, /* Katakana */
+    0xFF00  /* Fullwidth ASCII */
+};
+
+/* Table of fixed predefined Offsets */
+static const uint32_t fixedOffsets[]={
+    /* 0xF9 */ 0x00C0, /* Latin-1 Letters + half of Latin Extended A */
+    /* 0xFA */ 0x0250, /* IPA extensions */
+    /* 0xFB */ 0x0370, /* Greek */
+    /* 0xFC */ 0x0530, /* Armenian */
+    /* 0xFD */ 0x3040, /* Hiragana */
+    /* 0xFE */ 0x30A0, /* Katakana */
+    /* 0xFF */ 0xFF60  /* Halfwidth Katakana */
+};
+
+/* state values */
+enum {
+    readCommand,
+    quotePairOne,
+    quotePairTwo,
+    quoteOne,
+    definePairOne,
+    definePairTwo,
+    defineOne
+};
+
+typedef struct SCSUData {
+    /* dynamic window offsets, intitialize to default values from initialDynamicOffsets */
+    uint32_t toUDynamicOffsets[8];
+    uint32_t fromUDynamicOffsets[8];
+
+    /* state machine state - toUnicode */
+    UBool toUIsSingleByteMode;
+    uint8_t toUState;
+    int8_t toUQuoteWindow, toUDynamicWindow;
+    uint8_t toUByteOne;
+    uint8_t toUPadding[3];
+
+    /* state machine state - fromUnicode */
+    UBool fromUIsSingleByteMode;
+    int8_t fromUDynamicWindow;
+
+    /*
+     * windowUse[] keeps track of the use of the dynamic windows:
+     * At nextWindowUseIndex there is the least recently used window,
+     * and the following windows (in a wrapping manner) are more and more
+     * recently used.
+     * At nextWindowUseIndex-1 there is the most recently used window.
+     */
+    uint8_t locale;
+    int8_t nextWindowUseIndex;
+    int8_t windowUse[8];
+} SCSUData;
+
+static const int8_t initialWindowUse[8]={ 7, 0, 3, 2, 4, 5, 6, 1 };
+static const int8_t initialWindowUse_ja[8]={ 3, 2, 4, 1, 0, 7, 5, 6 };
+
+enum {
+    lGeneric, l_ja
+};
+
+/* SCSU setup functions ----------------------------------------------------- */
+
+static void
+_SCSUReset(UConverter *cnv, UConverterResetChoice choice) {
+    SCSUData *scsu=(SCSUData *)cnv->extraInfo;
+
+    if(choice<=UCNV_RESET_TO_UNICODE) {
+        /* reset toUnicode */
+        uprv_memcpy(scsu->toUDynamicOffsets, initialDynamicOffsets, 32);
+
+        scsu->toUIsSingleByteMode=TRUE;
+        scsu->toUState=readCommand;
+        scsu->toUQuoteWindow=scsu->toUDynamicWindow=0;
+        scsu->toUByteOne=0;
+
+        cnv->toULength=0;
+    }
+    if(choice!=UCNV_RESET_TO_UNICODE) {
+        /* reset fromUnicode */
+        uprv_memcpy(scsu->fromUDynamicOffsets, initialDynamicOffsets, 32);
+
+        scsu->fromUIsSingleByteMode=TRUE;
+        scsu->fromUDynamicWindow=0;
+
+        scsu->nextWindowUseIndex=0;
+        switch(scsu->locale) {
+        case l_ja:
+            uprv_memcpy(scsu->windowUse, initialWindowUse_ja, 8);
+            break;
+        default:
+            uprv_memcpy(scsu->windowUse, initialWindowUse, 8);
+            break;
+        }
+
+        cnv->fromUChar32=0;
+    }
+}
+
+static void
+_SCSUOpen(UConverter *cnv,
+          UConverterLoadArgs *pArgs,
+          UErrorCode *pErrorCode) {
+    const char *locale=pArgs->locale;
+    if(pArgs->onlyTestIsLoadable) {
+        return;
+    }
+    cnv->extraInfo=uprv_malloc(sizeof(SCSUData));
+    if(cnv->extraInfo!=NULL) {
+        if(locale!=NULL && locale[0]=='j' && locale[1]=='a' && (locale[2]==0 || locale[2]=='_')) {
+            ((SCSUData *)cnv->extraInfo)->locale=l_ja;
+        } else {
+            ((SCSUData *)cnv->extraInfo)->locale=lGeneric;
+        }
+        _SCSUReset(cnv, UCNV_RESET_BOTH);
+    } else {
+        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+    }
+
+    /* Set the substitution character U+fffd as a Unicode string. */
+    cnv->subUChars[0]=0xfffd;
+    cnv->subCharLen=-1;
+}
+
+static void
+_SCSUClose(UConverter *cnv) {
+    if(cnv->extraInfo!=NULL) {
+        if(!cnv->isExtraLocal) {
+            uprv_free(cnv->extraInfo);
+        }
+        cnv->extraInfo=NULL;
+    }
+}
+
+/* SCSU-to-Unicode conversion functions ------------------------------------- */
+
+static void
+_SCSUToUnicodeWithOffsets(UConverterToUnicodeArgs *pArgs,
+                          UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    SCSUData *scsu;
+    const uint8_t *source, *sourceLimit;
+    UChar *target;
+    const UChar *targetLimit;
+    int32_t *offsets;
+    UBool isSingleByteMode;
+    uint8_t state, byteOne;
+    int8_t quoteWindow, dynamicWindow;
+
+    int32_t sourceIndex, nextSourceIndex;
+
+    uint8_t b;
+
+    /* set up the local pointers */
+    cnv=pArgs->converter;
+    scsu=(SCSUData *)cnv->extraInfo;
+
+    source=(const uint8_t *)pArgs->source;
+    sourceLimit=(const uint8_t *)pArgs->sourceLimit;
+    target=pArgs->target;
+    targetLimit=pArgs->targetLimit;
+    offsets=pArgs->offsets;
+
+    /* get the state machine state */
+    isSingleByteMode=scsu->toUIsSingleByteMode;
+    state=scsu->toUState;
+    quoteWindow=scsu->toUQuoteWindow;
+    dynamicWindow=scsu->toUDynamicWindow;
+    byteOne=scsu->toUByteOne;
+
+    /* sourceIndex=-1 if the current character began in the previous buffer */
+    sourceIndex=state==readCommand ? 0 : -1;
+    nextSourceIndex=0;
+
+    /*
+     * conversion "loop"
+     *
+     * For performance, this is not a normal C loop.
+     * Instead, there are two code blocks for the two SCSU modes.
+     * The function branches to either one, and a change of the mode is done with a goto to
+     * the other branch.
+     *
+     * Each branch has two conventional loops:
+     * - a fast-path loop for the most common codes in the mode
+     * - a loop for all other codes in the mode
+     * When the fast-path runs into a code that it cannot handle, its loop ends and it
+     * runs into the following loop to handle the other codes.
+     * The end of the input or output buffer is also handled by the slower loop.
+     * The slow loop jumps (goto) to the fast-path loop again as soon as possible.
+     *
+     * The callback handling is done by returning with an error code.
+     * The conversion framework actually calls the callback function.
+     */
+    if(isSingleByteMode) {
+        /* fast path for single-byte mode */
+        if(state==readCommand) {
+fastSingle:
+            while(source<sourceLimit && target<targetLimit && (b=*source)>=0x20) {
+                ++source;
+                ++nextSourceIndex;
+                if(b<=0x7f) {
+                    /* write US-ASCII graphic character or DEL */
+                    *target++=(UChar)b;
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex;
+                    }
+                } else {
+                    /* write from dynamic window */
+                    uint32_t c=scsu->toUDynamicOffsets[dynamicWindow]+(b&0x7f);
+                    if(c<=0xffff) {
+                        *target++=(UChar)c;
+                        if(offsets!=NULL) {
+                            *offsets++=sourceIndex;
+                        }
+                    } else {
+                        /* output surrogate pair */
+                        *target++=(UChar)(0xd7c0+(c>>10));
+                        if(target<targetLimit) {
+                            *target++=(UChar)(0xdc00|(c&0x3ff));
+                            if(offsets!=NULL) {
+                                *offsets++=sourceIndex;
+                                *offsets++=sourceIndex;
+                            }
+                        } else {
+                            /* target overflow */
+                            if(offsets!=NULL) {
+                                *offsets++=sourceIndex;
+                            }
+                            cnv->UCharErrorBuffer[0]=(UChar)(0xdc00|(c&0x3ff));
+                            cnv->UCharErrorBufferLength=1;
+                            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                            goto endloop;
+                        }
+                    }
+                }
+                sourceIndex=nextSourceIndex;
+            }
+        }
+
+        /* normal state machine for single-byte mode, minus handling for what fastSingle covers */
+singleByteMode:
+        while(source<sourceLimit) {
+            if(target>=targetLimit) {
+                /* target is full */
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                break;
+            }
+            b=*source++;
+            ++nextSourceIndex;
+            switch(state) {
+            case readCommand:
+                /* redundant conditions are commented out */
+                /* here: b<0x20 because otherwise we would be in fastSingle */
+                if((1UL<<b)&0x2601 /* binary 0010 0110 0000 0001, check for b==0xd || b==0xa || b==9 || b==0 */) {
+                    /* CR/LF/TAB/NUL */
+                    *target++=(UChar)b;
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex;
+                    }
+                    sourceIndex=nextSourceIndex;
+                    goto fastSingle;
+                } else if(SC0<=b) {
+                    if(b<=SC7) {
+                        dynamicWindow=(int8_t)(b-SC0);
+                        sourceIndex=nextSourceIndex;
+                        goto fastSingle;
+                    } else /* if(SD0<=b && b<=SD7) */ {
+                        dynamicWindow=(int8_t)(b-SD0);
+                        state=defineOne;
+                    }
+                } else if(/* SQ0<=b && */ b<=SQ7) {
+                    quoteWindow=(int8_t)(b-SQ0);
+                    state=quoteOne;
+                } else if(b==SDX) {
+                    state=definePairOne;
+                } else if(b==SQU) {
+                    state=quotePairOne;
+                } else if(b==SCU) {
+                    sourceIndex=nextSourceIndex;
+                    isSingleByteMode=FALSE;
+                    goto fastUnicode;
+                } else /* Srs */ {
+                    /* callback(illegal) */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                    cnv->toUBytes[0]=b;
+                    cnv->toULength=1;
+                    goto endloop;
+                }
+
+                /* store the first byte of a multibyte sequence in toUBytes[] */
+                cnv->toUBytes[0]=b;
+                cnv->toULength=1;
+                break;
+            case quotePairOne:
+                byteOne=b;
+                cnv->toUBytes[1]=b;
+                cnv->toULength=2;
+                state=quotePairTwo;
+                break;
+            case quotePairTwo:
+                *target++=(UChar)((byteOne<<8)|b);
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                }
+                sourceIndex=nextSourceIndex;
+                state=readCommand;
+                goto fastSingle;
+            case quoteOne:
+                if(b<0x80) {
+                    /* all static offsets are in the BMP */
+                    *target++=(UChar)(staticOffsets[quoteWindow]+b);
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex;
+                    }
+                } else {
+                    /* write from dynamic window */
+                    uint32_t c=scsu->toUDynamicOffsets[quoteWindow]+(b&0x7f);
+                    if(c<=0xffff) {
+                        *target++=(UChar)c;
+                        if(offsets!=NULL) {
+                            *offsets++=sourceIndex;
+                        }
+                    } else {
+                        /* output surrogate pair */
+                        *target++=(UChar)(0xd7c0+(c>>10));
+                        if(target<targetLimit) {
+                            *target++=(UChar)(0xdc00|(c&0x3ff));
+                            if(offsets!=NULL) {
+                                *offsets++=sourceIndex;
+                                *offsets++=sourceIndex;
+                            }
+                        } else {
+                            /* target overflow */
+                            if(offsets!=NULL) {
+                                *offsets++=sourceIndex;
+                            }
+                            cnv->UCharErrorBuffer[0]=(UChar)(0xdc00|(c&0x3ff));
+                            cnv->UCharErrorBufferLength=1;
+                            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                            goto endloop;
+                        }
+                    }
+                }
+                sourceIndex=nextSourceIndex;
+                state=readCommand;
+                goto fastSingle;
+            case definePairOne:
+                dynamicWindow=(int8_t)((b>>5)&7);
+                byteOne=(uint8_t)(b&0x1f);
+                cnv->toUBytes[1]=b;
+                cnv->toULength=2;
+                state=definePairTwo;
+                break;
+            case definePairTwo:
+                scsu->toUDynamicOffsets[dynamicWindow]=0x10000+(byteOne<<15UL | b<<7UL);
+                sourceIndex=nextSourceIndex;
+                state=readCommand;
+                goto fastSingle;
+            case defineOne:
+                if(b==0) {
+                    /* callback(illegal): Reserved window offset value 0 */
+                    cnv->toUBytes[1]=b;
+                    cnv->toULength=2;
+                    goto endloop;
+                } else if(b<gapThreshold) {
+                    scsu->toUDynamicOffsets[dynamicWindow]=b<<7UL;
+                } else if((uint8_t)(b-gapThreshold)<(reservedStart-gapThreshold)) {
+                    scsu->toUDynamicOffsets[dynamicWindow]=(b<<7UL)+gapOffset;
+                } else if(b>=fixedThreshold) {
+                    scsu->toUDynamicOffsets[dynamicWindow]=fixedOffsets[b-fixedThreshold];
+                } else {
+                    /* callback(illegal): Reserved window offset value 0xa8..0xf8 */
+                    cnv->toUBytes[1]=b;
+                    cnv->toULength=2;
+                    goto endloop;
+                }
+                sourceIndex=nextSourceIndex;
+                state=readCommand;
+                goto fastSingle;
+            }
+        }
+    } else {
+        /* fast path for Unicode mode */
+        if(state==readCommand) {
+fastUnicode:
+            while(source+1<sourceLimit && target<targetLimit && (uint8_t)((b=*source)-UC0)>(Urs-UC0)) {
+                *target++=(UChar)((b<<8)|source[1]);
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                }
+                sourceIndex=nextSourceIndex;
+                nextSourceIndex+=2;
+                source+=2;
+            }
+        }
+
+        /* normal state machine for Unicode mode */
+/* unicodeByteMode: */
+        while(source<sourceLimit) {
+            if(target>=targetLimit) {
+                /* target is full */
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                break;
+            }
+            b=*source++;
+            ++nextSourceIndex;
+            switch(state) {
+            case readCommand:
+                if((uint8_t)(b-UC0)>(Urs-UC0)) {
+                    byteOne=b;
+                    cnv->toUBytes[0]=b;
+                    cnv->toULength=1;
+                    state=quotePairTwo;
+                } else if(/* UC0<=b && */ b<=UC7) {
+                    dynamicWindow=(int8_t)(b-UC0);
+                    sourceIndex=nextSourceIndex;
+                    isSingleByteMode=TRUE;
+                    goto fastSingle;
+                } else if(/* UD0<=b && */ b<=UD7) {
+                    dynamicWindow=(int8_t)(b-UD0);
+                    isSingleByteMode=TRUE;
+                    cnv->toUBytes[0]=b;
+                    cnv->toULength=1;
+                    state=defineOne;
+                    goto singleByteMode;
+                } else if(b==UDX) {
+                    isSingleByteMode=TRUE;
+                    cnv->toUBytes[0]=b;
+                    cnv->toULength=1;
+                    state=definePairOne;
+                    goto singleByteMode;
+                } else if(b==UQU) {
+                    cnv->toUBytes[0]=b;
+                    cnv->toULength=1;
+                    state=quotePairOne;
+                } else /* Urs */ {
+                    /* callback(illegal) */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                    cnv->toUBytes[0]=b;
+                    cnv->toULength=1;
+                    goto endloop;
+                }
+                break;
+            case quotePairOne:
+                byteOne=b;
+                cnv->toUBytes[1]=b;
+                cnv->toULength=2;
+                state=quotePairTwo;
+                break;
+            case quotePairTwo:
+                *target++=(UChar)((byteOne<<8)|b);
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                }
+                sourceIndex=nextSourceIndex;
+                state=readCommand;
+                goto fastUnicode;
+            }
+        }
+    }
+endloop:
+
+    /* set the converter state back into UConverter */
+    if(U_FAILURE(*pErrorCode) && *pErrorCode!=U_BUFFER_OVERFLOW_ERROR) {
+        /* reset to deal with the next character */
+        state=readCommand;
+    } else if(state==readCommand) {
+        /* not in a multi-byte sequence, reset toULength */
+        cnv->toULength=0;
+    }
+    scsu->toUIsSingleByteMode=isSingleByteMode;
+    scsu->toUState=state;
+    scsu->toUQuoteWindow=quoteWindow;
+    scsu->toUDynamicWindow=dynamicWindow;
+    scsu->toUByteOne=byteOne;
+
+    /* write back the updated pointers */
+    pArgs->source=(const char *)source;
+    pArgs->target=target;
+    pArgs->offsets=offsets;
+    return;
+}
+
+/*
+ * Identical to _SCSUToUnicodeWithOffsets but without offset handling.
+ * If a change is made in the original function, then either
+ * change this function the same way or
+ * re-copy the original function and remove the variables
+ * offsets, sourceIndex, and nextSourceIndex.
+ */
+static void
+_SCSUToUnicode(UConverterToUnicodeArgs *pArgs,
+               UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    SCSUData *scsu;
+    const uint8_t *source, *sourceLimit;
+    UChar *target;
+    const UChar *targetLimit;
+    UBool isSingleByteMode;
+    uint8_t state, byteOne;
+    int8_t quoteWindow, dynamicWindow;
+
+    uint8_t b;
+
+    /* set up the local pointers */
+    cnv=pArgs->converter;
+    scsu=(SCSUData *)cnv->extraInfo;
+
+    source=(const uint8_t *)pArgs->source;
+    sourceLimit=(const uint8_t *)pArgs->sourceLimit;
+    target=pArgs->target;
+    targetLimit=pArgs->targetLimit;
+
+    /* get the state machine state */
+    isSingleByteMode=scsu->toUIsSingleByteMode;
+    state=scsu->toUState;
+    quoteWindow=scsu->toUQuoteWindow;
+    dynamicWindow=scsu->toUDynamicWindow;
+    byteOne=scsu->toUByteOne;
+
+    /*
+     * conversion "loop"
+     *
+     * For performance, this is not a normal C loop.
+     * Instead, there are two code blocks for the two SCSU modes.
+     * The function branches to either one, and a change of the mode is done with a goto to
+     * the other branch.
+     *
+     * Each branch has two conventional loops:
+     * - a fast-path loop for the most common codes in the mode
+     * - a loop for all other codes in the mode
+     * When the fast-path runs into a code that it cannot handle, its loop ends and it
+     * runs into the following loop to handle the other codes.
+     * The end of the input or output buffer is also handled by the slower loop.
+     * The slow loop jumps (goto) to the fast-path loop again as soon as possible.
+     *
+     * The callback handling is done by returning with an error code.
+     * The conversion framework actually calls the callback function.
+     */
+    if(isSingleByteMode) {
+        /* fast path for single-byte mode */
+        if(state==readCommand) {
+fastSingle:
+            while(source<sourceLimit && target<targetLimit && (b=*source)>=0x20) {
+                ++source;
+                if(b<=0x7f) {
+                    /* write US-ASCII graphic character or DEL */
+                    *target++=(UChar)b;
+                } else {
+                    /* write from dynamic window */
+                    uint32_t c=scsu->toUDynamicOffsets[dynamicWindow]+(b&0x7f);
+                    if(c<=0xffff) {
+                        *target++=(UChar)c;
+                    } else {
+                        /* output surrogate pair */
+                        *target++=(UChar)(0xd7c0+(c>>10));
+                        if(target<targetLimit) {
+                            *target++=(UChar)(0xdc00|(c&0x3ff));
+                        } else {
+                            /* target overflow */
+                            cnv->UCharErrorBuffer[0]=(UChar)(0xdc00|(c&0x3ff));
+                            cnv->UCharErrorBufferLength=1;
+                            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                            goto endloop;
+                        }
+                    }
+                }
+            }
+        }
+
+        /* normal state machine for single-byte mode, minus handling for what fastSingle covers */
+singleByteMode:
+        while(source<sourceLimit) {
+            if(target>=targetLimit) {
+                /* target is full */
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                break;
+            }
+            b=*source++;
+            switch(state) {
+            case readCommand:
+                /* redundant conditions are commented out */
+                /* here: b<0x20 because otherwise we would be in fastSingle */
+                if((1UL<<b)&0x2601 /* binary 0010 0110 0000 0001, check for b==0xd || b==0xa || b==9 || b==0 */) {
+                    /* CR/LF/TAB/NUL */
+                    *target++=(UChar)b;
+                    goto fastSingle;
+                } else if(SC0<=b) {
+                    if(b<=SC7) {
+                        dynamicWindow=(int8_t)(b-SC0);
+                        goto fastSingle;
+                    } else /* if(SD0<=b && b<=SD7) */ {
+                        dynamicWindow=(int8_t)(b-SD0);
+                        state=defineOne;
+                    }
+                } else if(/* SQ0<=b && */ b<=SQ7) {
+                    quoteWindow=(int8_t)(b-SQ0);
+                    state=quoteOne;
+                } else if(b==SDX) {
+                    state=definePairOne;
+                } else if(b==SQU) {
+                    state=quotePairOne;
+                } else if(b==SCU) {
+                    isSingleByteMode=FALSE;
+                    goto fastUnicode;
+                } else /* Srs */ {
+                    /* callback(illegal) */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                    cnv->toUBytes[0]=b;
+                    cnv->toULength=1;
+                    goto endloop;
+                }
+
+                /* store the first byte of a multibyte sequence in toUBytes[] */
+                cnv->toUBytes[0]=b;
+                cnv->toULength=1;
+                break;
+            case quotePairOne:
+                byteOne=b;
+                cnv->toUBytes[1]=b;
+                cnv->toULength=2;
+                state=quotePairTwo;
+                break;
+            case quotePairTwo:
+                *target++=(UChar)((byteOne<<8)|b);
+                state=readCommand;
+                goto fastSingle;
+            case quoteOne:
+                if(b<0x80) {
+                    /* all static offsets are in the BMP */
+                    *target++=(UChar)(staticOffsets[quoteWindow]+b);
+                } else {
+                    /* write from dynamic window */
+                    uint32_t c=scsu->toUDynamicOffsets[quoteWindow]+(b&0x7f);
+                    if(c<=0xffff) {
+                        *target++=(UChar)c;
+                    } else {
+                        /* output surrogate pair */
+                        *target++=(UChar)(0xd7c0+(c>>10));
+                        if(target<targetLimit) {
+                            *target++=(UChar)(0xdc00|(c&0x3ff));
+                        } else {
+                            /* target overflow */
+                            cnv->UCharErrorBuffer[0]=(UChar)(0xdc00|(c&0x3ff));
+                            cnv->UCharErrorBufferLength=1;
+                            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                            goto endloop;
+                        }
+                    }
+                }
+                state=readCommand;
+                goto fastSingle;
+            case definePairOne:
+                dynamicWindow=(int8_t)((b>>5)&7);
+                byteOne=(uint8_t)(b&0x1f);
+                cnv->toUBytes[1]=b;
+                cnv->toULength=2;
+                state=definePairTwo;
+                break;
+            case definePairTwo:
+                scsu->toUDynamicOffsets[dynamicWindow]=0x10000+(byteOne<<15UL | b<<7UL);
+                state=readCommand;
+                goto fastSingle;
+            case defineOne:
+                if(b==0) {
+                    /* callback(illegal): Reserved window offset value 0 */
+                    cnv->toUBytes[1]=b;
+                    cnv->toULength=2;
+                    goto endloop;
+                } else if(b<gapThreshold) {
+                    scsu->toUDynamicOffsets[dynamicWindow]=b<<7UL;
+                } else if((uint8_t)(b-gapThreshold)<(reservedStart-gapThreshold)) {
+                    scsu->toUDynamicOffsets[dynamicWindow]=(b<<7UL)+gapOffset;
+                } else if(b>=fixedThreshold) {
+                    scsu->toUDynamicOffsets[dynamicWindow]=fixedOffsets[b-fixedThreshold];
+                } else {
+                    /* callback(illegal): Reserved window offset value 0xa8..0xf8 */
+                    cnv->toUBytes[1]=b;
+                    cnv->toULength=2;
+                    goto endloop;
+                }
+                state=readCommand;
+                goto fastSingle;
+            }
+        }
+    } else {
+        /* fast path for Unicode mode */
+        if(state==readCommand) {
+fastUnicode:
+            while(source+1<sourceLimit && target<targetLimit && (uint8_t)((b=*source)-UC0)>(Urs-UC0)) {
+                *target++=(UChar)((b<<8)|source[1]);
+                source+=2;
+            }
+        }
+
+        /* normal state machine for Unicode mode */
+/* unicodeByteMode: */
+        while(source<sourceLimit) {
+            if(target>=targetLimit) {
+                /* target is full */
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                break;
+            }
+            b=*source++;
+            switch(state) {
+            case readCommand:
+                if((uint8_t)(b-UC0)>(Urs-UC0)) {
+                    byteOne=b;
+                    cnv->toUBytes[0]=b;
+                    cnv->toULength=1;
+                    state=quotePairTwo;
+                } else if(/* UC0<=b && */ b<=UC7) {
+                    dynamicWindow=(int8_t)(b-UC0);
+                    isSingleByteMode=TRUE;
+                    goto fastSingle;
+                } else if(/* UD0<=b && */ b<=UD7) {
+                    dynamicWindow=(int8_t)(b-UD0);
+                    isSingleByteMode=TRUE;
+                    cnv->toUBytes[0]=b;
+                    cnv->toULength=1;
+                    state=defineOne;
+                    goto singleByteMode;
+                } else if(b==UDX) {
+                    isSingleByteMode=TRUE;
+                    cnv->toUBytes[0]=b;
+                    cnv->toULength=1;
+                    state=definePairOne;
+                    goto singleByteMode;
+                } else if(b==UQU) {
+                    cnv->toUBytes[0]=b;
+                    cnv->toULength=1;
+                    state=quotePairOne;
+                } else /* Urs */ {
+                    /* callback(illegal) */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                    cnv->toUBytes[0]=b;
+                    cnv->toULength=1;
+                    goto endloop;
+                }
+                break;
+            case quotePairOne:
+                byteOne=b;
+                cnv->toUBytes[1]=b;
+                cnv->toULength=2;
+                state=quotePairTwo;
+                break;
+            case quotePairTwo:
+                *target++=(UChar)((byteOne<<8)|b);
+                state=readCommand;
+                goto fastUnicode;
+            }
+        }
+    }
+endloop:
+
+    /* set the converter state back into UConverter */
+    if(U_FAILURE(*pErrorCode) && *pErrorCode!=U_BUFFER_OVERFLOW_ERROR) {
+        /* reset to deal with the next character */
+        state=readCommand;
+    } else if(state==readCommand) {
+        /* not in a multi-byte sequence, reset toULength */
+        cnv->toULength=0;
+    }
+    scsu->toUIsSingleByteMode=isSingleByteMode;
+    scsu->toUState=state;
+    scsu->toUQuoteWindow=quoteWindow;
+    scsu->toUDynamicWindow=dynamicWindow;
+    scsu->toUByteOne=byteOne;
+
+    /* write back the updated pointers */
+    pArgs->source=(const char *)source;
+    pArgs->target=target;
+    return;
+}
+
+/* SCSU-from-Unicode conversion functions ----------------------------------- */
+
+/*
+ * This SCSU Encoder is fairly simple but uses all SCSU commands to achieve
+ * reasonable results. The lookahead is minimal.
+ * Many cases are simple:
+ * A character fits directly into the current mode, a dynamic or static window,
+ * or is not compressible. These cases are tested first.
+ * Real compression heuristics are applied to the rest, in code branches for
+ * single/Unicode mode and BMP/supplementary code points.
+ * The heuristics used here are extremely simple.
+ */
+
+/* get the number of the window that this character is in, or -1 */
+static int8_t
+getWindow(const uint32_t offsets[8], uint32_t c) {
+    int i;
+    for(i=0; i<8; ++i) {
+        if((uint32_t)(c-offsets[i])<=0x7f) {
+            return (int8_t)(i);
+        }
+    }
+    return -1;
+}
+
+/* is the character in the dynamic window starting at the offset, or in the direct-encoded range? */
+static UBool
+isInOffsetWindowOrDirect(uint32_t offset, uint32_t c) {
+    return (UBool)(c<=offset+0x7f &&
+          (c>=offset || (c<=0x7f &&
+                        (c>=0x20 || (1UL<<c)&0x2601))));
+                                /* binary 0010 0110 0000 0001,
+                                   check for b==0xd || b==0xa || b==9 || b==0 */
+}
+
+/*
+ * getNextDynamicWindow returns the next dynamic window to be redefined
+ */
+static int8_t
+getNextDynamicWindow(SCSUData *scsu) {
+    int8_t window=scsu->windowUse[scsu->nextWindowUseIndex];
+    if(++scsu->nextWindowUseIndex==8) {
+        scsu->nextWindowUseIndex=0;
+    }
+    return window;
+}
+
+/*
+ * useDynamicWindow() adjusts
+ * windowUse[] and nextWindowUseIndex for the algorithm to choose
+ * the next dynamic window to be defined;
+ * a subclass may override it and provide its own algorithm.
+ */
+static void
+useDynamicWindow(SCSUData *scsu, int8_t window) {
+    /*
+     * move the existing window, which just became the most recently used one,
+     * up in windowUse[] to nextWindowUseIndex-1
+     */
+
+    /* first, find the index of the window - backwards to favor the more recently used windows */
+    int i, j;
+
+    i=scsu->nextWindowUseIndex;
+    do {
+        if(--i<0) {
+            i=7;
+        }
+    } while(scsu->windowUse[i]!=window);
+
+    /* now copy each windowUse[i+1] to [i] */
+    j=i+1;
+    if(j==8) {
+        j=0;
+    }
+    while(j!=scsu->nextWindowUseIndex) {
+        scsu->windowUse[i]=scsu->windowUse[j];
+        i=j;
+        if(++j==8) { j=0; }
+    }
+
+    /* finally, set the window into the most recently used index */
+    scsu->windowUse[i]=window;
+}
+
+/*
+ * calculate the offset and the code for a dynamic window that contains the character
+ * takes fixed offsets into account
+ * the offset of the window is stored in the offset variable,
+ * the code is returned
+ *
+ * return offset code: -1 none  <=0xff code for SDn/UDn  else code for SDX/UDX, subtract 0x200 to get the true code
+ */
+static int
+getDynamicOffset(uint32_t c, uint32_t *pOffset) {
+    int i;
+
+    for(i=0; i<7; ++i) {
+        if((uint32_t)(c-fixedOffsets[i])<=0x7f) {
+            *pOffset=fixedOffsets[i];
+            return 0xf9+i;
+        }
+    }
+
+    if(c<0x80) {
+        /* No dynamic window for US-ASCII. */
+        return -1;
+    } else if(c<0x3400 ||
+              (uint32_t)(c-0x10000)<(0x14000-0x10000) ||
+              (uint32_t)(c-0x1d000)<=(0x1ffff-0x1d000)
+    ) {
+        /* This character is in a code range for a "small", i.e., reasonably windowable, script. */
+        *pOffset=c&0x7fffff80;
+        return (int)(c>>7);
+    } else if(0xe000<=c && c!=0xfeff && c<0xfff0) {
+        /* For these characters we need to take the gapOffset into account. */
+        *pOffset=c&0x7fffff80;
+        return (int)((c-gapOffset)>>7);
+    } else {
+        return -1;
+    }
+}
+
+/*
+ * Idea for compression:
+ *  - save SCSUData and other state before really starting work
+ *  - at endloop, see if compression could be better with just unicode mode
+ *  - don't do this if a callback has been called
+ *  - if unicode mode would be smaller, then override the results with it - may need SCU at the beginning
+ *  - different buffer handling!
+ *
+ * Drawback or need for corrective handling:
+ * it is desirable to encode U+feff as SQU fe ff for the SCSU signature, and
+ * it is desirable to start a document in US-ASCII/Latin-1 for as long as possible
+ * not only for compression but also for HTML/XML documents with following charset/encoding announcers.
+ *
+ * How to achieve both?
+ *  - Only replace the result after an SDX or SCU?
+ */
+
+static void
+_SCSUFromUnicodeWithOffsets(UConverterFromUnicodeArgs *pArgs,
+                            UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    SCSUData *scsu;
+    const UChar *source, *sourceLimit;
+    uint8_t *target;
+    int32_t targetCapacity;
+    int32_t *offsets;
+
+    UBool isSingleByteMode;
+    uint8_t dynamicWindow;
+    uint32_t currentOffset;
+
+    uint32_t c, delta;
+
+    int32_t sourceIndex, nextSourceIndex;
+
+    int32_t length;
+
+    /* variables for compression heuristics */
+    uint32_t offset;
+    UChar lead, trail;
+    int code;
+    int8_t window;
+
+    /* set up the local pointers */
+    cnv=pArgs->converter;
+    scsu=(SCSUData *)cnv->extraInfo;
+
+    /* set up the local pointers */
+    source=pArgs->source;
+    sourceLimit=pArgs->sourceLimit;
+    target=(uint8_t *)pArgs->target;
+    targetCapacity=(int32_t)(pArgs->targetLimit-pArgs->target);
+    offsets=pArgs->offsets;
+
+    /* get the state machine state */
+    isSingleByteMode=scsu->fromUIsSingleByteMode;
+    dynamicWindow=scsu->fromUDynamicWindow;
+    currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
+
+    c=cnv->fromUChar32;
+
+    /* sourceIndex=-1 if the current character began in the previous buffer */
+    sourceIndex= c==0 ? 0 : -1;
+    nextSourceIndex=0;
+
+    /* similar conversion "loop" as in toUnicode */
+loop:
+    if(isSingleByteMode) {
+        if(c!=0 && targetCapacity>0) {
+            goto getTrailSingle;
+        }
+
+        /* state machine for single-byte mode */
+/* singleByteMode: */
+        while(source<sourceLimit) {
+            if(targetCapacity<=0) {
+                /* target is full */
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                break;
+            }
+            c=*source++;
+            ++nextSourceIndex;
+
+            if((c-0x20)<=0x5f) {
+                /* pass US-ASCII graphic character through */
+                *target++=(uint8_t)c;
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                }
+                --targetCapacity;
+            } else if(c<0x20) {
+                if((1UL<<c)&0x2601 /* binary 0010 0110 0000 0001, check for b==0xd || b==0xa || b==9 || b==0 */) {
+                    /* CR/LF/TAB/NUL */
+                    *target++=(uint8_t)c;
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex;
+                    }
+                    --targetCapacity;
+                } else {
+                    /* quote C0 control character */
+                    c|=SQ0<<8;
+                    length=2;
+                    goto outputBytes;
+                }
+            } else if((delta=c-currentOffset)<=0x7f) {
+                /* use the current dynamic window */
+                *target++=(uint8_t)(delta|0x80);
+                if(offsets!=NULL) {
+                    *offsets++=sourceIndex;
+                }
+                --targetCapacity;
+            } else if(UTF_IS_SURROGATE(c)) {
+                if(UTF_IS_SURROGATE_FIRST(c)) {
+getTrailSingle:
+                    lead=(UChar)c;
+                    if(source<sourceLimit) {
+                        /* test the following code unit */
+                        trail=*source;
+                        if(UTF_IS_SECOND_SURROGATE(trail)) {
+                            ++source;
+                            ++nextSourceIndex;
+                            c=UTF16_GET_PAIR_VALUE(c, trail);
+                            /* convert this surrogate code point */
+                            /* exit this condition tree */
+                        } else {
+                            /* this is an unmatched lead code unit (1st surrogate) */
+                            /* callback(illegal) */
+                            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                            goto endloop;
+                        }
+                    } else {
+                        /* no more input */
+                        break;
+                    }
+                } else {
+                    /* this is an unmatched trail code unit (2nd surrogate) */
+                    /* callback(illegal) */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                    goto endloop;
+                }
+
+                /* compress supplementary character U+10000..U+10ffff */
+                if((delta=c-currentOffset)<=0x7f) {
+                    /* use the current dynamic window */
+                    *target++=(uint8_t)(delta|0x80);
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex;
+                    }
+                    --targetCapacity;
+                } else if((window=getWindow(scsu->fromUDynamicOffsets, c))>=0) {
+                    /* there is a dynamic window that contains this character, change to it */
+                    dynamicWindow=window;
+                    currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
+                    useDynamicWindow(scsu, dynamicWindow);
+                    c=((uint32_t)(SC0+dynamicWindow)<<8)|(c-currentOffset)|0x80;
+                    length=2;
+                    goto outputBytes;
+                } else if((code=getDynamicOffset(c, &offset))>=0) {
+                    /* might check if there are more characters in this window to come */
+                    /* define an extended window with this character */
+                    code-=0x200;
+                    dynamicWindow=getNextDynamicWindow(scsu);
+                    currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
+                    useDynamicWindow(scsu, dynamicWindow);
+                    c=((uint32_t)SDX<<24)|((uint32_t)dynamicWindow<<21)|((uint32_t)code<<8)|(c-currentOffset)|0x80;
+                    length=4;
+                    goto outputBytes;
+                } else {
+                    /* change to Unicode mode and output this (lead, trail) pair */
+                    isSingleByteMode=FALSE;
+                    *target++=(uint8_t)SCU;
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex;
+                    }
+                    --targetCapacity;
+                    c=((uint32_t)lead<<16)|trail;
+                    length=4;
+                    goto outputBytes;
+                }
+            } else if(c<0xa0) {
+                /* quote C1 control character */
+                c=(c&0x7f)|(SQ0+1)<<8; /* SQ0+1==SQ1 */
+                length=2;
+                goto outputBytes;
+            } else if(c==0xfeff || c>=0xfff0) {
+                /* quote signature character=byte order mark and specials */
+                c|=SQU<<16;
+                length=3;
+                goto outputBytes;
+            } else {
+                /* compress all other BMP characters */
+                if((window=getWindow(scsu->fromUDynamicOffsets, c))>=0) {
+                    /* there is a window defined that contains this character - switch to it or quote from it? */
+                    if(source>=sourceLimit || isInOffsetWindowOrDirect(scsu->fromUDynamicOffsets[window], *source)) {
+                        /* change to dynamic window */
+                        dynamicWindow=window;
+                        currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
+                        useDynamicWindow(scsu, dynamicWindow);
+                        c=((uint32_t)(SC0+dynamicWindow)<<8)|(c-currentOffset)|0x80;
+                        length=2;
+                        goto outputBytes;
+                    } else {
+                        /* quote from dynamic window */
+                        c=((uint32_t)(SQ0+window)<<8)|(c-scsu->fromUDynamicOffsets[window])|0x80;
+                        length=2;
+                        goto outputBytes;
+                    }
+                } else if((window=getWindow(staticOffsets, c))>=0) {
+                    /* quote from static window */
+                    c=((uint32_t)(SQ0+window)<<8)|(c-staticOffsets[window]);
+                    length=2;
+                    goto outputBytes;
+                } else if((code=getDynamicOffset(c, &offset))>=0) {
+                    /* define a dynamic window with this character */
+                    dynamicWindow=getNextDynamicWindow(scsu);
+                    currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
+                    useDynamicWindow(scsu, dynamicWindow);
+                    c=((uint32_t)(SD0+dynamicWindow)<<16)|((uint32_t)code<<8)|(c-currentOffset)|0x80;
+                    length=3;
+                    goto outputBytes;
+                } else if((uint32_t)(c-0x3400)<(0xd800-0x3400) &&
+                          (source>=sourceLimit || (uint32_t)(*source-0x3400)<(0xd800-0x3400))
+                ) {
+                    /*
+                     * this character is not compressible (a BMP ideograph or similar);
+                     * switch to Unicode mode if this is the last character in the block
+                     * or there is at least one more ideograph following immediately
+                     */
+                    isSingleByteMode=FALSE;
+                    c|=SCU<<16;
+                    length=3;
+                    goto outputBytes;
+                } else {
+                    /* quote Unicode */
+                    c|=SQU<<16;
+                    length=3;
+                    goto outputBytes;
+                }
+            }
+
+            /* normal end of conversion: prepare for a new character */
+            c=0;
+            sourceIndex=nextSourceIndex;
+        }
+    } else {
+        if(c!=0 && targetCapacity>0) {
+            goto getTrailUnicode;
+        }
+
+        /* state machine for Unicode mode */
+/* unicodeByteMode: */
+        while(source<sourceLimit) {
+            if(targetCapacity<=0) {
+                /* target is full */
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                break;
+            }
+            c=*source++;
+            ++nextSourceIndex;
+
+            if((uint32_t)(c-0x3400)<(0xd800-0x3400)) {
+                /* not compressible, write character directly */
+                if(targetCapacity>=2) {
+                    *target++=(uint8_t)(c>>8);
+                    *target++=(uint8_t)c;
+                    if(offsets!=NULL) {
+                        *offsets++=sourceIndex;
+                        *offsets++=sourceIndex;
+                    }
+                    targetCapacity-=2;
+                } else {
+                    length=2;
+                    goto outputBytes;
+                }
+            } else if((uint32_t)(c-0x3400)>=(0xf300-0x3400) /* c<0x3400 || c>=0xf300 */) {
+                /* compress BMP character if the following one is not an uncompressible ideograph */
+                if(!(source<sourceLimit && (uint32_t)(*source-0x3400)<(0xd800-0x3400))) {
+                    if(((uint32_t)(c-0x30)<10 || (uint32_t)(c-0x61)<26 || (uint32_t)(c-0x41)<26)) {
+                        /* ASCII digit or letter */
+                        isSingleByteMode=TRUE;
+                        c|=((uint32_t)(UC0+dynamicWindow)<<8)|c;
+                        length=2;
+                        goto outputBytes;
+                    } else if((window=getWindow(scsu->fromUDynamicOffsets, c))>=0) {
+                        /* there is a dynamic window that contains this character, change to it */
+                        isSingleByteMode=TRUE;
+                        dynamicWindow=window;
+                        currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
+                        useDynamicWindow(scsu, dynamicWindow);
+                        c=((uint32_t)(UC0+dynamicWindow)<<8)|(c-currentOffset)|0x80;
+                        length=2;
+                        goto outputBytes;
+                    } else if((code=getDynamicOffset(c, &offset))>=0) {
+                        /* define a dynamic window with this character */
+                        isSingleByteMode=TRUE;
+                        dynamicWindow=getNextDynamicWindow(scsu);
+                        currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
+                        useDynamicWindow(scsu, dynamicWindow);
+                        c=((uint32_t)(UD0+dynamicWindow)<<16)|((uint32_t)code<<8)|(c-currentOffset)|0x80;
+                        length=3;
+                        goto outputBytes;
+                    }
+                }
+
+                /* don't know how to compress this character, just write it directly */
+                length=2;
+                goto outputBytes;
+            } else if(c<0xe000) {
+                /* c is a surrogate */
+                if(UTF_IS_SURROGATE_FIRST(c)) {
+getTrailUnicode:
+                    lead=(UChar)c;
+                    if(source<sourceLimit) {
+                        /* test the following code unit */
+                        trail=*source;
+                        if(UTF_IS_SECOND_SURROGATE(trail)) {
+                            ++source;
+                            ++nextSourceIndex;
+                            c=UTF16_GET_PAIR_VALUE(c, trail);
+                            /* convert this surrogate code point */
+                            /* exit this condition tree */
+                        } else {
+                            /* this is an unmatched lead code unit (1st surrogate) */
+                            /* callback(illegal) */
+                            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                            goto endloop;
+                        }
+                    } else {
+                        /* no more input */
+                        break;
+                    }
+                } else {
+                    /* this is an unmatched trail code unit (2nd surrogate) */
+                    /* callback(illegal) */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                    goto endloop;
+                }
+
+                /* compress supplementary character */
+                if( (window=getWindow(scsu->fromUDynamicOffsets, c))>=0 &&
+                    !(source<sourceLimit && (uint32_t)(*source-0x3400)<(0xd800-0x3400))
+                ) {
+                    /*
+                     * there is a dynamic window that contains this character and
+                     * the following character is not uncompressible,
+                     * change to the window
+                     */
+                    isSingleByteMode=TRUE;
+                    dynamicWindow=window;
+                    currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
+                    useDynamicWindow(scsu, dynamicWindow);
+                    c=((uint32_t)(UC0+dynamicWindow)<<8)|(c-currentOffset)|0x80;
+                    length=2;
+                    goto outputBytes;
+                } else if(source<sourceLimit && lead==*source && /* too lazy to check trail in same window as source[1] */
+                          (code=getDynamicOffset(c, &offset))>=0
+                ) {
+                    /* two supplementary characters in (probably) the same window - define an extended one */
+                    isSingleByteMode=TRUE;
+                    code-=0x200;
+                    dynamicWindow=getNextDynamicWindow(scsu);
+                    currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
+                    useDynamicWindow(scsu, dynamicWindow);
+                    c=((uint32_t)UDX<<24)|((uint32_t)dynamicWindow<<21)|((uint32_t)code<<8)|(c-currentOffset)|0x80;
+                    length=4;
+                    goto outputBytes;
+                } else {
+                    /* don't know how to compress this character, just write it directly */
+                    c=((uint32_t)lead<<16)|trail;
+                    length=4;
+                    goto outputBytes;
+                }
+            } else /* 0xe000<=c<0xf300 */ {
+                /* quote to avoid SCSU tags */
+                c|=UQU<<16;
+                length=3;
+                goto outputBytes;
+            }
+
+            /* normal end of conversion: prepare for a new character */
+            c=0;
+            sourceIndex=nextSourceIndex;
+        }
+    }
+endloop:
+
+    /* set the converter state back into UConverter */
+    scsu->fromUIsSingleByteMode=isSingleByteMode;
+    scsu->fromUDynamicWindow=dynamicWindow;
+
+    cnv->fromUChar32=c;
+
+    /* write back the updated pointers */
+    pArgs->source=source;
+    pArgs->target=(char *)target;
+    pArgs->offsets=offsets;
+    return;
+
+outputBytes:
+    /* write the output character bytes from c and length [code copied from ucnvmbcs.c] */
+    /* from the first if in the loop we know that targetCapacity>0 */
+    if(length<=targetCapacity) {
+        if(offsets==NULL) {
+            switch(length) {
+                /* each branch falls through to the next one */
+            case 4:
+                *target++=(uint8_t)(c>>24);
+            case 3:
+                *target++=(uint8_t)(c>>16);
+            case 2:
+                *target++=(uint8_t)(c>>8);
+            case 1:
+                *target++=(uint8_t)c;
+            default:
+                /* will never occur */
+                break;
+            }
+        } else {
+            switch(length) {
+                /* each branch falls through to the next one */
+            case 4:
+                *target++=(uint8_t)(c>>24);
+                *offsets++=sourceIndex;
+            case 3:
+                *target++=(uint8_t)(c>>16);
+                *offsets++=sourceIndex;
+            case 2:
+                *target++=(uint8_t)(c>>8);
+                *offsets++=sourceIndex;
+            case 1:
+                *target++=(uint8_t)c;
+                *offsets++=sourceIndex;
+            default:
+                /* will never occur */
+                break;
+            }
+        }
+        targetCapacity-=length;
+
+        /* normal end of conversion: prepare for a new character */
+        c=0;
+        sourceIndex=nextSourceIndex;
+        goto loop;
+    } else {
+        uint8_t *p;
+
+        /*
+         * We actually do this backwards here:
+         * In order to save an intermediate variable, we output
+         * first to the overflow buffer what does not fit into the
+         * regular target.
+         */
+        /* we know that 0<=targetCapacity<length<=4 */
+        /* targetCapacity==0 when SCU+supplementary where SCU used up targetCapacity==1 */
+        length-=targetCapacity;
+        p=(uint8_t *)cnv->charErrorBuffer;
+        switch(length) {
+            /* each branch falls through to the next one */
+        case 4:
+            *p++=(uint8_t)(c>>24);
+        case 3:
+            *p++=(uint8_t)(c>>16);
+        case 2:
+            *p++=(uint8_t)(c>>8);
+        case 1:
+            *p=(uint8_t)c;
+        default:
+            /* will never occur */
+            break;
+        }
+        cnv->charErrorBufferLength=(int8_t)length;
+
+        /* now output what fits into the regular target */
+        c>>=8*length; /* length was reduced by targetCapacity */
+        switch(targetCapacity) {
+            /* each branch falls through to the next one */
+        case 3:
+            *target++=(uint8_t)(c>>16);
+            if(offsets!=NULL) {
+                *offsets++=sourceIndex;
+            }
+        case 2:
+            *target++=(uint8_t)(c>>8);
+            if(offsets!=NULL) {
+                *offsets++=sourceIndex;
+            }
+        case 1:
+            *target++=(uint8_t)c;
+            if(offsets!=NULL) {
+                *offsets++=sourceIndex;
+            }
+        default:
+            break;
+        }
+
+        /* target overflow */
+        targetCapacity=0;
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+        c=0;
+        goto endloop;
+    }
+}
+
+/*
+ * Identical to _SCSUFromUnicodeWithOffsets but without offset handling.
+ * If a change is made in the original function, then either
+ * change this function the same way or
+ * re-copy the original function and remove the variables
+ * offsets, sourceIndex, and nextSourceIndex.
+ */
+static void
+_SCSUFromUnicode(UConverterFromUnicodeArgs *pArgs,
+                 UErrorCode *pErrorCode) {
+    UConverter *cnv;
+    SCSUData *scsu;
+    const UChar *source, *sourceLimit;
+    uint8_t *target;
+    int32_t targetCapacity;
+
+    UBool isSingleByteMode;
+    uint8_t dynamicWindow;
+    uint32_t currentOffset;
+
+    uint32_t c, delta;
+
+    int32_t length;
+
+    /* variables for compression heuristics */
+    uint32_t offset;
+    UChar lead, trail;
+    int code;
+    int8_t window;
+
+    /* set up the local pointers */
+    cnv=pArgs->converter;
+    scsu=(SCSUData *)cnv->extraInfo;
+
+    /* set up the local pointers */
+    source=pArgs->source;
+    sourceLimit=pArgs->sourceLimit;
+    target=(uint8_t *)pArgs->target;
+    targetCapacity=(int32_t)(pArgs->targetLimit-pArgs->target);
+
+    /* get the state machine state */
+    isSingleByteMode=scsu->fromUIsSingleByteMode;
+    dynamicWindow=scsu->fromUDynamicWindow;
+    currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
+
+    c=cnv->fromUChar32;
+
+    /* similar conversion "loop" as in toUnicode */
+loop:
+    if(isSingleByteMode) {
+        if(c!=0 && targetCapacity>0) {
+            goto getTrailSingle;
+        }
+
+        /* state machine for single-byte mode */
+/* singleByteMode: */
+        while(source<sourceLimit) {
+            if(targetCapacity<=0) {
+                /* target is full */
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                break;
+            }
+            c=*source++;
+
+            if((c-0x20)<=0x5f) {
+                /* pass US-ASCII graphic character through */
+                *target++=(uint8_t)c;
+                --targetCapacity;
+            } else if(c<0x20) {
+                if((1UL<<c)&0x2601 /* binary 0010 0110 0000 0001, check for b==0xd || b==0xa || b==9 || b==0 */) {
+                    /* CR/LF/TAB/NUL */
+                    *target++=(uint8_t)c;
+                    --targetCapacity;
+                } else {
+                    /* quote C0 control character */
+                    c|=SQ0<<8;
+                    length=2;
+                    goto outputBytes;
+                }
+            } else if((delta=c-currentOffset)<=0x7f) {
+                /* use the current dynamic window */
+                *target++=(uint8_t)(delta|0x80);
+                --targetCapacity;
+            } else if(UTF_IS_SURROGATE(c)) {
+                if(UTF_IS_SURROGATE_FIRST(c)) {
+getTrailSingle:
+                    lead=(UChar)c;
+                    if(source<sourceLimit) {
+                        /* test the following code unit */
+                        trail=*source;
+                        if(UTF_IS_SECOND_SURROGATE(trail)) {
+                            ++source;
+                            c=UTF16_GET_PAIR_VALUE(c, trail);
+                            /* convert this surrogate code point */
+                            /* exit this condition tree */
+                        } else {
+                            /* this is an unmatched lead code unit (1st surrogate) */
+                            /* callback(illegal) */
+                            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                            goto endloop;
+                        }
+                    } else {
+                        /* no more input */
+                        break;
+                    }
+                } else {
+                    /* this is an unmatched trail code unit (2nd surrogate) */
+                    /* callback(illegal) */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                    goto endloop;
+                }
+
+                /* compress supplementary character U+10000..U+10ffff */
+                if((delta=c-currentOffset)<=0x7f) {
+                    /* use the current dynamic window */
+                    *target++=(uint8_t)(delta|0x80);
+                    --targetCapacity;
+                } else if((window=getWindow(scsu->fromUDynamicOffsets, c))>=0) {
+                    /* there is a dynamic window that contains this character, change to it */
+                    dynamicWindow=window;
+                    currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
+                    useDynamicWindow(scsu, dynamicWindow);
+                    c=((uint32_t)(SC0+dynamicWindow)<<8)|(c-currentOffset)|0x80;
+                    length=2;
+                    goto outputBytes;
+                } else if((code=getDynamicOffset(c, &offset))>=0) {
+                    /* might check if there are more characters in this window to come */
+                    /* define an extended window with this character */
+                    code-=0x200;
+                    dynamicWindow=getNextDynamicWindow(scsu);
+                    currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
+                    useDynamicWindow(scsu, dynamicWindow);
+                    c=((uint32_t)SDX<<24)|((uint32_t)dynamicWindow<<21)|((uint32_t)code<<8)|(c-currentOffset)|0x80;
+                    length=4;
+                    goto outputBytes;
+                } else {
+                    /* change to Unicode mode and output this (lead, trail) pair */
+                    isSingleByteMode=FALSE;
+                    *target++=(uint8_t)SCU;
+                    --targetCapacity;
+                    c=((uint32_t)lead<<16)|trail;
+                    length=4;
+                    goto outputBytes;
+                }
+            } else if(c<0xa0) {
+                /* quote C1 control character */
+                c=(c&0x7f)|(SQ0+1)<<8; /* SQ0+1==SQ1 */
+                length=2;
+                goto outputBytes;
+            } else if(c==0xfeff || c>=0xfff0) {
+                /* quote signature character=byte order mark and specials */
+                c|=SQU<<16;
+                length=3;
+                goto outputBytes;
+            } else {
+                /* compress all other BMP characters */
+                if((window=getWindow(scsu->fromUDynamicOffsets, c))>=0) {
+                    /* there is a window defined that contains this character - switch to it or quote from it? */
+                    if(source>=sourceLimit || isInOffsetWindowOrDirect(scsu->fromUDynamicOffsets[window], *source)) {
+                        /* change to dynamic window */
+                        dynamicWindow=window;
+                        currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
+                        useDynamicWindow(scsu, dynamicWindow);
+                        c=((uint32_t)(SC0+dynamicWindow)<<8)|(c-currentOffset)|0x80;
+                        length=2;
+                        goto outputBytes;
+                    } else {
+                        /* quote from dynamic window */
+                        c=((uint32_t)(SQ0+window)<<8)|(c-scsu->fromUDynamicOffsets[window])|0x80;
+                        length=2;
+                        goto outputBytes;
+                    }
+                } else if((window=getWindow(staticOffsets, c))>=0) {
+                    /* quote from static window */
+                    c=((uint32_t)(SQ0+window)<<8)|(c-staticOffsets[window]);
+                    length=2;
+                    goto outputBytes;
+                } else if((code=getDynamicOffset(c, &offset))>=0) {
+                    /* define a dynamic window with this character */
+                    dynamicWindow=getNextDynamicWindow(scsu);
+                    currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
+                    useDynamicWindow(scsu, dynamicWindow);
+                    c=((uint32_t)(SD0+dynamicWindow)<<16)|((uint32_t)code<<8)|(c-currentOffset)|0x80;
+                    length=3;
+                    goto outputBytes;
+                } else if((uint32_t)(c-0x3400)<(0xd800-0x3400) &&
+                          (source>=sourceLimit || (uint32_t)(*source-0x3400)<(0xd800-0x3400))
+                ) {
+                    /*
+                     * this character is not compressible (a BMP ideograph or similar);
+                     * switch to Unicode mode if this is the last character in the block
+                     * or there is at least one more ideograph following immediately
+                     */
+                    isSingleByteMode=FALSE;
+                    c|=SCU<<16;
+                    length=3;
+                    goto outputBytes;
+                } else {
+                    /* quote Unicode */
+                    c|=SQU<<16;
+                    length=3;
+                    goto outputBytes;
+                }
+            }
+
+            /* normal end of conversion: prepare for a new character */
+            c=0;
+        }
+    } else {
+        if(c!=0 && targetCapacity>0) {
+            goto getTrailUnicode;
+        }
+
+        /* state machine for Unicode mode */
+/* unicodeByteMode: */
+        while(source<sourceLimit) {
+            if(targetCapacity<=0) {
+                /* target is full */
+                *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                break;
+            }
+            c=*source++;
+
+            if((uint32_t)(c-0x3400)<(0xd800-0x3400)) {
+                /* not compressible, write character directly */
+                if(targetCapacity>=2) {
+                    *target++=(uint8_t)(c>>8);
+                    *target++=(uint8_t)c;
+                    targetCapacity-=2;
+                } else {
+                    length=2;
+                    goto outputBytes;
+                }
+            } else if((uint32_t)(c-0x3400)>=(0xf300-0x3400) /* c<0x3400 || c>=0xf300 */) {
+                /* compress BMP character if the following one is not an uncompressible ideograph */
+                if(!(source<sourceLimit && (uint32_t)(*source-0x3400)<(0xd800-0x3400))) {
+                    if(((uint32_t)(c-0x30)<10 || (uint32_t)(c-0x61)<26 || (uint32_t)(c-0x41)<26)) {
+                        /* ASCII digit or letter */
+                        isSingleByteMode=TRUE;
+                        c|=((uint32_t)(UC0+dynamicWindow)<<8)|c;
+                        length=2;
+                        goto outputBytes;
+                    } else if((window=getWindow(scsu->fromUDynamicOffsets, c))>=0) {
+                        /* there is a dynamic window that contains this character, change to it */
+                        isSingleByteMode=TRUE;
+                        dynamicWindow=window;
+                        currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
+                        useDynamicWindow(scsu, dynamicWindow);
+                        c=((uint32_t)(UC0+dynamicWindow)<<8)|(c-currentOffset)|0x80;
+                        length=2;
+                        goto outputBytes;
+                    } else if((code=getDynamicOffset(c, &offset))>=0) {
+                        /* define a dynamic window with this character */
+                        isSingleByteMode=TRUE;
+                        dynamicWindow=getNextDynamicWindow(scsu);
+                        currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
+                        useDynamicWindow(scsu, dynamicWindow);
+                        c=((uint32_t)(UD0+dynamicWindow)<<16)|((uint32_t)code<<8)|(c-currentOffset)|0x80;
+                        length=3;
+                        goto outputBytes;
+                    }
+                }
+
+                /* don't know how to compress this character, just write it directly */
+                length=2;
+                goto outputBytes;
+            } else if(c<0xe000) {
+                /* c is a surrogate */
+                if(UTF_IS_SURROGATE_FIRST(c)) {
+getTrailUnicode:
+                    lead=(UChar)c;
+                    if(source<sourceLimit) {
+                        /* test the following code unit */
+                        trail=*source;
+                        if(UTF_IS_SECOND_SURROGATE(trail)) {
+                            ++source;
+                            c=UTF16_GET_PAIR_VALUE(c, trail);
+                            /* convert this surrogate code point */
+                            /* exit this condition tree */
+                        } else {
+                            /* this is an unmatched lead code unit (1st surrogate) */
+                            /* callback(illegal) */
+                            *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                            goto endloop;
+                        }
+                    } else {
+                        /* no more input */
+                        break;
+                    }
+                } else {
+                    /* this is an unmatched trail code unit (2nd surrogate) */
+                    /* callback(illegal) */
+                    *pErrorCode=U_ILLEGAL_CHAR_FOUND;
+                    goto endloop;
+                }
+
+                /* compress supplementary character */
+                if( (window=getWindow(scsu->fromUDynamicOffsets, c))>=0 &&
+                    !(source<sourceLimit && (uint32_t)(*source-0x3400)<(0xd800-0x3400))
+                ) {
+                    /*
+                     * there is a dynamic window that contains this character and
+                     * the following character is not uncompressible,
+                     * change to the window
+                     */
+                    isSingleByteMode=TRUE;
+                    dynamicWindow=window;
+                    currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
+                    useDynamicWindow(scsu, dynamicWindow);
+                    c=((uint32_t)(UC0+dynamicWindow)<<8)|(c-currentOffset)|0x80;
+                    length=2;
+                    goto outputBytes;
+                } else if(source<sourceLimit && lead==*source && /* too lazy to check trail in same window as source[1] */
+                          (code=getDynamicOffset(c, &offset))>=0
+                ) {
+                    /* two supplementary characters in (probably) the same window - define an extended one */
+                    isSingleByteMode=TRUE;
+                    code-=0x200;
+                    dynamicWindow=getNextDynamicWindow(scsu);
+                    currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
+                    useDynamicWindow(scsu, dynamicWindow);
+                    c=((uint32_t)UDX<<24)|((uint32_t)dynamicWindow<<21)|((uint32_t)code<<8)|(c-currentOffset)|0x80;
+                    length=4;
+                    goto outputBytes;
+                } else {
+                    /* don't know how to compress this character, just write it directly */
+                    c=((uint32_t)lead<<16)|trail;
+                    length=4;
+                    goto outputBytes;
+                }
+            } else /* 0xe000<=c<0xf300 */ {
+                /* quote to avoid SCSU tags */
+                c|=UQU<<16;
+                length=3;
+                goto outputBytes;
+            }
+
+            /* normal end of conversion: prepare for a new character */
+            c=0;
+        }
+    }
+endloop:
+
+    /* set the converter state back into UConverter */
+    scsu->fromUIsSingleByteMode=isSingleByteMode;
+    scsu->fromUDynamicWindow=dynamicWindow;
+
+    cnv->fromUChar32=c;
+
+    /* write back the updated pointers */
+    pArgs->source=source;
+    pArgs->target=(char *)target;
+    return;
+
+outputBytes:
+    /* write the output character bytes from c and length [code copied from ucnvmbcs.c] */
+    /* from the first if in the loop we know that targetCapacity>0 */
+    if(length<=targetCapacity) {
+        switch(length) {
+            /* each branch falls through to the next one */
+        case 4:
+            *target++=(uint8_t)(c>>24);
+        case 3:
+            *target++=(uint8_t)(c>>16);
+        case 2:
+            *target++=(uint8_t)(c>>8);
+        case 1:
+            *target++=(uint8_t)c;
+        default:
+            /* will never occur */
+            break;
+        }
+        targetCapacity-=length;
+
+        /* normal end of conversion: prepare for a new character */
+        c=0;
+        goto loop;
+    } else {
+        uint8_t *p;
+
+        /*
+         * We actually do this backwards here:
+         * In order to save an intermediate variable, we output
+         * first to the overflow buffer what does not fit into the
+         * regular target.
+         */
+        /* we know that 0<=targetCapacity<length<=4 */
+        /* targetCapacity==0 when SCU+supplementary where SCU used up targetCapacity==1 */
+        length-=targetCapacity;
+        p=(uint8_t *)cnv->charErrorBuffer;
+        switch(length) {
+            /* each branch falls through to the next one */
+        case 4:
+            *p++=(uint8_t)(c>>24);
+        case 3:
+            *p++=(uint8_t)(c>>16);
+        case 2:
+            *p++=(uint8_t)(c>>8);
+        case 1:
+            *p=(uint8_t)c;
+        default:
+            /* will never occur */
+            break;
+        }
+        cnv->charErrorBufferLength=(int8_t)length;
+
+        /* now output what fits into the regular target */
+        c>>=8*length; /* length was reduced by targetCapacity */
+        switch(targetCapacity) {
+            /* each branch falls through to the next one */
+        case 3:
+            *target++=(uint8_t)(c>>16);
+        case 2:
+            *target++=(uint8_t)(c>>8);
+        case 1:
+            *target++=(uint8_t)c;
+        default:
+            break;
+        }
+
+        /* target overflow */
+        targetCapacity=0;
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+        c=0;
+        goto endloop;
+    }
+}
+
+/* miscellaneous ------------------------------------------------------------ */
+
+static const char *
+_SCSUGetName(const UConverter *cnv) {
+    SCSUData *scsu=(SCSUData *)cnv->extraInfo;
+
+    switch(scsu->locale) {
+    case l_ja:
+        return "SCSU,locale=ja";
+    default:
+        return "SCSU";
+    }
+}
+
+/* structure for SafeClone calculations */
+struct cloneSCSUStruct
+{
+    UConverter cnv;
+    SCSUData mydata;
+};
+
+static UConverter * 
+_SCSUSafeClone(const UConverter *cnv, 
+               void *stackBuffer, 
+               int32_t *pBufferSize, 
+               UErrorCode *status)
+{
+    struct cloneSCSUStruct * localClone;
+    int32_t bufferSizeNeeded = sizeof(struct cloneSCSUStruct);
+
+    if (U_FAILURE(*status)){
+        return 0;
+    }
+
+    if (*pBufferSize == 0){ /* 'preflighting' request - set needed size into *pBufferSize */
+        *pBufferSize = bufferSizeNeeded;
+        return 0;
+    }
+
+    localClone = (struct cloneSCSUStruct *)stackBuffer;
+    /* ucnv.c/ucnv_safeClone() copied the main UConverter already */
+
+    uprv_memcpy(&localClone->mydata, cnv->extraInfo, sizeof(SCSUData));
+    localClone->cnv.extraInfo = &localClone->mydata;
+    localClone->cnv.isExtraLocal = TRUE;
+
+    return &localClone->cnv;
+}
+
+
+static const UConverterImpl _SCSUImpl={
+    UCNV_SCSU,
+
+    NULL,
+    NULL,
+
+    _SCSUOpen,
+    _SCSUClose,
+    _SCSUReset,
+
+    _SCSUToUnicode,
+    _SCSUToUnicodeWithOffsets,
+    _SCSUFromUnicode,
+    _SCSUFromUnicodeWithOffsets,
+    NULL,
+
+    NULL,
+    _SCSUGetName,
+    NULL,
+    _SCSUSafeClone,
+    ucnv_getCompleteUnicodeSet
+};
+
+static const UConverterStaticData _SCSUStaticData={
+    sizeof(UConverterStaticData),
+    "SCSU",
+    1212, /* CCSID for SCSU */
+    UCNV_IBM, UCNV_SCSU,
+    1, 3, /* one UChar generates at least 1 byte and at most 3 bytes */
+    /*
+     * The subchar here is ignored because _SCSUOpen() sets U+fffd as a Unicode
+     * substitution string.
+     */
+    { 0x0e, 0xff, 0xfd, 0 }, 3,
+    FALSE, FALSE,
+    0,
+    0,
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
+};
+
+const UConverterSharedData _SCSUData={
+    sizeof(UConverterSharedData), ~((uint32_t)0),
+    NULL, NULL, &_SCSUStaticData, FALSE, &_SCSUImpl,
+    0
+};
+
+#endif
diff --git a/source/common/ucnvsel.cpp b/source/common/ucnvsel.cpp
new file mode 100644
index 0000000..cc626ee
--- /dev/null
+++ b/source/common/ucnvsel.cpp
@@ -0,0 +1,811 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2008-2009, International Business Machines
+*   Corporation, Google and others.  All Rights Reserved.
+*
+*******************************************************************************
+*/
+// Author : eldawy@google.com (Mohamed Eldawy)
+// ucnvsel.cpp
+//
+// Purpose: To generate a list of encodings capable of handling
+// a given Unicode text
+//
+// Started 09-April-2008
+
+/**
+ * \file
+ *
+ * This is an implementation of an encoding selector.
+ * The goal is, given a unicode string, find the encodings
+ * this string can be mapped to. To make processing faster
+ * a trie is built when you call ucnvsel_open() that
+ * stores all encodings a codepoint can map to
+ */
+
+#include "unicode/ucnvsel.h"
+
+#include <string.h>
+
+#include "unicode/uchar.h"
+#include "unicode/uniset.h"
+#include "unicode/ucnv.h"
+#include "unicode/ustring.h"
+#include "unicode/uchriter.h"
+#include "utrie2.h"
+#include "propsvec.h"
+#include "uassert.h"
+#include "ucmndata.h"
+#include "uenumimp.h"
+#include "cmemory.h"
+#include "cstring.h"
+
+U_NAMESPACE_USE
+
+struct UConverterSelector {
+  UTrie2 *trie;              // 16 bit trie containing offsets into pv
+  uint32_t* pv;              // table of bits!
+  int32_t pvCount;
+  char** encodings;          // which encodings did user ask to use?
+  int32_t encodingsCount;
+  int32_t encodingStrLength;
+  uint8_t* swapped;
+  UBool ownPv, ownEncodingStrings;
+};
+
+static void generateSelectorData(UConverterSelector* result,
+                                 UPropsVectors *upvec,
+                                 const USet* excludedCodePoints,
+                                 const UConverterUnicodeSet whichSet,
+                                 UErrorCode* status) {
+  if (U_FAILURE(*status)) {
+    return;
+  }
+
+  int32_t columns = (result->encodingsCount+31)/32;
+
+  // set errorValue to all-ones
+  for (int32_t col = 0; col < columns; col++) {
+    upvec_setValue(upvec, UPVEC_ERROR_VALUE_CP, UPVEC_ERROR_VALUE_CP,
+                   col, ~0, ~0, status);
+  }
+
+  for (int32_t i = 0; i < result->encodingsCount; ++i) {
+    uint32_t mask;
+    uint32_t column;
+    int32_t item_count;
+    int32_t j;
+    UConverter* test_converter = ucnv_open(result->encodings[i], status);
+    if (U_FAILURE(*status)) {
+      return;
+    }
+    USet* unicode_point_set;
+    unicode_point_set = uset_open(1, 0);  // empty set
+
+    ucnv_getUnicodeSet(test_converter, unicode_point_set,
+                       whichSet, status);
+    if (U_FAILURE(*status)) {
+      ucnv_close(test_converter);
+      return;
+    }
+
+    column = i / 32;
+    mask = 1 << (i%32);
+    // now iterate over intervals on set i!
+    item_count = uset_getItemCount(unicode_point_set);
+
+    for (j = 0; j < item_count; ++j) {
+      UChar32 start_char;
+      UChar32 end_char;
+      UErrorCode smallStatus = U_ZERO_ERROR;
+      uset_getItem(unicode_point_set, j, &start_char, &end_char, NULL, 0,
+                   &smallStatus);
+      if (U_FAILURE(smallStatus)) {
+        // this will be reached for the converters that fill the set with
+        // strings. Those should be ignored by our system
+      } else {
+        upvec_setValue(upvec, start_char, end_char, column, ~0, mask,
+                       status);
+      }
+    }
+    ucnv_close(test_converter);
+    uset_close(unicode_point_set);
+    if (U_FAILURE(*status)) {
+      return;
+    }
+  }
+
+  // handle excluded encodings! Simply set their values to all 1's in the upvec
+  if (excludedCodePoints) {
+    int32_t item_count = uset_getItemCount(excludedCodePoints);
+    for (int32_t j = 0; j < item_count; ++j) {
+      UChar32 start_char;
+      UChar32 end_char;
+
+      uset_getItem(excludedCodePoints, j, &start_char, &end_char, NULL, 0,
+                   status);
+      for (int32_t col = 0; col < columns; col++) {
+        upvec_setValue(upvec, start_char, end_char, col, ~0, ~0,
+                      status);
+      }
+    }
+  }
+
+  // alright. Now, let's put things in the same exact form you'd get when you
+  // unserialize things.
+  result->trie = upvec_compactToUTrie2WithRowIndexes(upvec, status);
+  result->pv = upvec_cloneArray(upvec, &result->pvCount, NULL, status);
+  result->pvCount *= columns;  // number of uint32_t = rows * columns
+  result->ownPv = TRUE;
+}
+
+/* open a selector. If converterListSize is 0, build for all converters.
+   If excludedCodePoints is NULL, don't exclude any codepoints */
+U_CAPI UConverterSelector* U_EXPORT2
+ucnvsel_open(const char* const*  converterList, int32_t converterListSize,
+             const USet* excludedCodePoints,
+             const UConverterUnicodeSet whichSet, UErrorCode* status) {
+  // check if already failed
+  if (U_FAILURE(*status)) {
+    return NULL;
+  }
+  // ensure args make sense!
+  if (converterListSize < 0 || (converterList == NULL && converterListSize != 0)) {
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+    return NULL;
+  }
+
+  // allocate a new converter
+  LocalUConverterSelectorPointer newSelector(
+    (UConverterSelector*)uprv_malloc(sizeof(UConverterSelector)));
+  if (newSelector.isNull()) {
+    *status = U_MEMORY_ALLOCATION_ERROR;
+    return NULL;
+  }
+  uprv_memset(newSelector.getAlias(), 0, sizeof(UConverterSelector));
+
+  if (converterListSize == 0) {
+    converterList = NULL;
+    converterListSize = ucnv_countAvailable();
+  }
+  newSelector->encodings =
+    (char**)uprv_malloc(converterListSize * sizeof(char*));
+  if (!newSelector->encodings) {
+    *status = U_MEMORY_ALLOCATION_ERROR;
+    return NULL;
+  }
+  newSelector->encodings[0] = NULL;  // now we can call ucnvsel_close()
+
+  // make a backup copy of the list of converters
+  int32_t totalSize = 0;
+  int32_t i;
+  for (i = 0; i < converterListSize; i++) {
+    totalSize +=
+      (int32_t)uprv_strlen(converterList != NULL ? converterList[i] : ucnv_getAvailableName(i)) + 1;
+  }
+  // 4-align the totalSize to 4-align the size of the serialized form
+  int32_t encodingStrPadding = totalSize & 3;
+  if (encodingStrPadding != 0) {
+    encodingStrPadding = 4 - encodingStrPadding;
+  }
+  newSelector->encodingStrLength = totalSize += encodingStrPadding;
+  char* allStrings = (char*) uprv_malloc(totalSize);
+  if (!allStrings) {
+    *status = U_MEMORY_ALLOCATION_ERROR;
+    return NULL;
+  }
+
+  for (i = 0; i < converterListSize; i++) {
+    newSelector->encodings[i] = allStrings;
+    uprv_strcpy(newSelector->encodings[i],
+                converterList != NULL ? converterList[i] : ucnv_getAvailableName(i));
+    allStrings += uprv_strlen(newSelector->encodings[i]) + 1;
+  }
+  while (encodingStrPadding > 0) {
+    *allStrings++ = 0;
+    --encodingStrPadding;
+  }
+
+  newSelector->ownEncodingStrings = TRUE;
+  newSelector->encodingsCount = converterListSize;
+  UPropsVectors *upvec = upvec_open((converterListSize+31)/32, status);
+  generateSelectorData(newSelector.getAlias(), upvec, excludedCodePoints, whichSet, status);
+  upvec_close(upvec);
+
+  if (U_FAILURE(*status)) {
+    return NULL;
+  }
+
+  return newSelector.orphan();
+}
+
+/* close opened selector */
+U_CAPI void U_EXPORT2
+ucnvsel_close(UConverterSelector *sel) {
+  if (!sel) {
+    return;
+  }
+  if (sel->ownEncodingStrings) {
+    uprv_free(sel->encodings[0]);
+  }
+  uprv_free(sel->encodings);
+  if (sel->ownPv) {
+    uprv_free(sel->pv);
+  }
+  utrie2_close(sel->trie);
+  uprv_free(sel->swapped);
+  uprv_free(sel);
+}
+
+static const UDataInfo dataInfo = {
+  sizeof(UDataInfo),
+  0,
+
+  U_IS_BIG_ENDIAN,
+  U_CHARSET_FAMILY,
+  U_SIZEOF_UCHAR,
+  0,
+
+  { 0x43, 0x53, 0x65, 0x6c },   /* dataFormat="CSel" */
+  { 1, 0, 0, 0 },               /* formatVersion */
+  { 0, 0, 0, 0 }                /* dataVersion */
+};
+
+enum {
+  UCNVSEL_INDEX_TRIE_SIZE,      // trie size in bytes
+  UCNVSEL_INDEX_PV_COUNT,       // number of uint32_t in the bit vectors
+  UCNVSEL_INDEX_NAMES_COUNT,    // number of encoding names
+  UCNVSEL_INDEX_NAMES_LENGTH,   // number of encoding name bytes including padding
+  UCNVSEL_INDEX_SIZE = 15,      // bytes following the DataHeader
+  UCNVSEL_INDEX_COUNT = 16
+};
+
+/*
+ * Serialized form of a UConverterSelector, formatVersion 1:
+ *
+ * The serialized form begins with a standard ICU DataHeader with a UDataInfo
+ * as the template above.
+ * This is followed by:
+ *   int32_t indexes[UCNVSEL_INDEX_COUNT];          // see index entry constants above
+ *   serialized UTrie2;                             // indexes[UCNVSEL_INDEX_TRIE_SIZE] bytes
+ *   uint32_t pv[indexes[UCNVSEL_INDEX_PV_COUNT]];  // bit vectors
+ *   char* encodingNames[indexes[UCNVSEL_INDEX_NAMES_LENGTH]];  // NUL-terminated strings + padding
+ */
+
+/* serialize a selector */
+U_CAPI int32_t U_EXPORT2
+ucnvsel_serialize(const UConverterSelector* sel,
+                  void* buffer, int32_t bufferCapacity, UErrorCode* status) {
+  // check if already failed
+  if (U_FAILURE(*status)) {
+    return 0;
+  }
+  // ensure args make sense!
+  uint8_t *p = (uint8_t *)buffer;
+  if (bufferCapacity < 0 ||
+      (bufferCapacity > 0 && (p == NULL || (U_POINTER_MASK_LSB(p, 3) != 0)))
+  ) {
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+    return 0;
+  }
+  // add up the size of the serialized form
+  int32_t serializedTrieSize = utrie2_serialize(sel->trie, NULL, 0, status);
+  if (*status != U_BUFFER_OVERFLOW_ERROR && U_FAILURE(*status)) {
+    return 0;
+  }
+  *status = U_ZERO_ERROR;
+
+  DataHeader header;
+  uprv_memset(&header, 0, sizeof(header));
+  header.dataHeader.headerSize = (uint16_t)((sizeof(header) + 15) & ~15);
+  header.dataHeader.magic1 = 0xda;
+  header.dataHeader.magic2 = 0x27;
+  uprv_memcpy(&header.info, &dataInfo, sizeof(dataInfo));
+
+  int32_t indexes[UCNVSEL_INDEX_COUNT] = {
+    serializedTrieSize,
+    sel->pvCount,
+    sel->encodingsCount,
+    sel->encodingStrLength
+  };
+
+  int32_t totalSize =
+    header.dataHeader.headerSize +
+    (int32_t)sizeof(indexes) +
+    serializedTrieSize +
+    sel->pvCount * 4 +
+    sel->encodingStrLength;
+  indexes[UCNVSEL_INDEX_SIZE] = totalSize - header.dataHeader.headerSize;
+  if (totalSize > bufferCapacity) {
+    *status = U_BUFFER_OVERFLOW_ERROR;
+    return totalSize;
+  }
+  // ok, save!
+  int32_t length = header.dataHeader.headerSize;
+  uprv_memcpy(p, &header, sizeof(header));
+  uprv_memset(p + sizeof(header), 0, length - sizeof(header));
+  p += length;
+
+  length = (int32_t)sizeof(indexes);
+  uprv_memcpy(p, indexes, length);
+  p += length;
+
+  utrie2_serialize(sel->trie, p, serializedTrieSize, status);
+  p += serializedTrieSize;
+
+  length = sel->pvCount * 4;
+  uprv_memcpy(p, sel->pv, length);
+  p += length;
+
+  uprv_memcpy(p, sel->encodings[0], sel->encodingStrLength);
+  p += sel->encodingStrLength;
+
+  return totalSize;
+}
+
+/**
+ * swap a selector into the desired Endianness and Asciiness of
+ * the system. Just as FYI, selectors are always saved in the format
+ * of the system that created them. They are only converted if used
+ * on another system. In other words, selectors created on different
+ * system can be different even if the params are identical (endianness
+ * and Asciiness differences only)
+ *
+ * @param ds pointer to data swapper containing swapping info
+ * @param inData pointer to incoming data
+ * @param length length of inData in bytes
+ * @param outData pointer to output data. Capacity should
+ *                be at least equal to capacity of inData
+ * @param status an in/out ICU UErrorCode
+ * @return 0 on failure, number of bytes swapped on success
+ *         number of bytes swapped can be smaller than length
+ */
+static int32_t
+ucnvsel_swap(const UDataSwapper *ds,
+             const void *inData, int32_t length,
+             void *outData, UErrorCode *status) {
+  /* udata_swapDataHeader checks the arguments */
+  int32_t headerSize = udata_swapDataHeader(ds, inData, length, outData, status);
+  if(U_FAILURE(*status)) {
+    return 0;
+  }
+
+  /* check data format and format version */
+  const UDataInfo *pInfo = (const UDataInfo *)((const char *)inData + 4);
+  if(!(
+    pInfo->dataFormat[0] == 0x43 &&  /* dataFormat="CSel" */
+    pInfo->dataFormat[1] == 0x53 &&
+    pInfo->dataFormat[2] == 0x65 &&
+    pInfo->dataFormat[3] == 0x6c
+  )) {
+    udata_printError(ds, "ucnvsel_swap(): data format %02x.%02x.%02x.%02x is not recognized as UConverterSelector data\n",
+                     pInfo->dataFormat[0], pInfo->dataFormat[1],
+                     pInfo->dataFormat[2], pInfo->dataFormat[3]);
+    *status = U_INVALID_FORMAT_ERROR;
+    return 0;
+  }
+  if(pInfo->formatVersion[0] != 1) {
+    udata_printError(ds, "ucnvsel_swap(): format version %02x is not supported\n",
+                     pInfo->formatVersion[0]);
+    *status = U_UNSUPPORTED_ERROR;
+    return 0;
+  }
+
+  if(length >= 0) {
+    length -= headerSize;
+    if(length < 16*4) {
+      udata_printError(ds, "ucnvsel_swap(): too few bytes (%d after header) for UConverterSelector data\n",
+                       length);
+      *status = U_INDEX_OUTOFBOUNDS_ERROR;
+      return 0;
+    }
+  }
+
+  const uint8_t *inBytes = (const uint8_t *)inData + headerSize;
+  uint8_t *outBytes = (uint8_t *)outData + headerSize;
+
+  /* read the indexes */
+  const int32_t *inIndexes = (const int32_t *)inBytes;
+  int32_t indexes[16];
+  int32_t i;
+  for(i = 0; i < 16; ++i) {
+    indexes[i] = udata_readInt32(ds, inIndexes[i]);
+  }
+
+  /* get the total length of the data */
+  int32_t size = indexes[UCNVSEL_INDEX_SIZE];
+  if(length >= 0) {
+    if(length < size) {
+      udata_printError(ds, "ucnvsel_swap(): too few bytes (%d after header) for all of UConverterSelector data\n",
+                       length);
+      *status = U_INDEX_OUTOFBOUNDS_ERROR;
+      return 0;
+    }
+
+    /* copy the data for inaccessible bytes */
+    if(inBytes != outBytes) {
+      uprv_memcpy(outBytes, inBytes, size);
+    }
+
+    int32_t offset = 0, count;
+
+    /* swap the int32_t indexes[] */
+    count = UCNVSEL_INDEX_COUNT*4;
+    ds->swapArray32(ds, inBytes, count, outBytes, status);
+    offset += count;
+
+    /* swap the UTrie2 */
+    count = indexes[UCNVSEL_INDEX_TRIE_SIZE];
+    utrie2_swap(ds, inBytes + offset, count, outBytes + offset, status);
+    offset += count;
+
+    /* swap the uint32_t pv[] */
+    count = indexes[UCNVSEL_INDEX_PV_COUNT]*4;
+    ds->swapArray32(ds, inBytes + offset, count, outBytes + offset, status);
+    offset += count;
+
+    /* swap the encoding names */
+    count = indexes[UCNVSEL_INDEX_NAMES_LENGTH];
+    ds->swapInvChars(ds, inBytes + offset, count, outBytes + offset, status);
+    offset += count;
+
+    U_ASSERT(offset == size);
+  }
+
+  return headerSize + size;
+}
+
+/* unserialize a selector */
+U_CAPI UConverterSelector* U_EXPORT2
+ucnvsel_openFromSerialized(const void* buffer, int32_t length, UErrorCode* status) {
+  // check if already failed
+  if (U_FAILURE(*status)) {
+    return NULL;
+  }
+  // ensure args make sense!
+  const uint8_t *p = (const uint8_t *)buffer;
+  if (length <= 0 ||
+      (length > 0 && (p == NULL || (U_POINTER_MASK_LSB(p, 3) != 0)))
+  ) {
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+    return NULL;
+  }
+  // header
+  if (length < 32) {
+    // not even enough space for a minimal header
+    *status = U_INDEX_OUTOFBOUNDS_ERROR;
+    return NULL;
+  }
+  const DataHeader *pHeader = (const DataHeader *)p;
+  if (!(
+    pHeader->dataHeader.magic1==0xda &&
+    pHeader->dataHeader.magic2==0x27 &&
+    pHeader->info.dataFormat[0] == 0x43 &&
+    pHeader->info.dataFormat[1] == 0x53 &&
+    pHeader->info.dataFormat[2] == 0x65 &&
+    pHeader->info.dataFormat[3] == 0x6c
+  )) {
+    /* header not valid or dataFormat not recognized */
+    *status = U_INVALID_FORMAT_ERROR;
+    return NULL;
+  }
+  if (pHeader->info.formatVersion[0] != 1) {
+    *status = U_UNSUPPORTED_ERROR;
+    return NULL;
+  }
+  uint8_t* swapped = NULL;
+  if (pHeader->info.isBigEndian != U_IS_BIG_ENDIAN ||
+      pHeader->info.charsetFamily != U_CHARSET_FAMILY
+  ) {
+    // swap the data
+    UDataSwapper *ds =
+      udata_openSwapperForInputData(p, length, U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, status);
+    int32_t totalSize = ucnvsel_swap(ds, p, -1, NULL, status);
+    if (U_FAILURE(*status)) {
+      udata_closeSwapper(ds);
+      return NULL;
+    }
+    if (length < totalSize) {
+      udata_closeSwapper(ds);
+      *status = U_INDEX_OUTOFBOUNDS_ERROR;
+      return NULL;
+    }
+    swapped = (uint8_t*)uprv_malloc(totalSize);
+    if (swapped == NULL) {
+      udata_closeSwapper(ds);
+      *status = U_MEMORY_ALLOCATION_ERROR;
+      return NULL;
+    }
+    ucnvsel_swap(ds, p, length, swapped, status);
+    udata_closeSwapper(ds);
+    if (U_FAILURE(*status)) {
+      uprv_free(swapped);
+      return NULL;
+    }
+    p = swapped;
+    pHeader = (const DataHeader *)p;
+  }
+  if (length < (pHeader->dataHeader.headerSize + 16 * 4)) {
+    // not even enough space for the header and the indexes
+    uprv_free(swapped);
+    *status = U_INDEX_OUTOFBOUNDS_ERROR;
+    return NULL;
+  }
+  p += pHeader->dataHeader.headerSize;
+  length -= pHeader->dataHeader.headerSize;
+  // indexes
+  const int32_t *indexes = (const int32_t *)p;
+  if (length < indexes[UCNVSEL_INDEX_SIZE]) {
+    uprv_free(swapped);
+    *status = U_INDEX_OUTOFBOUNDS_ERROR;
+    return NULL;
+  }
+  p += UCNVSEL_INDEX_COUNT * 4;
+  // create and populate the selector object
+  UConverterSelector* sel = (UConverterSelector*)uprv_malloc(sizeof(UConverterSelector));
+  char **encodings =
+    (char **)uprv_malloc(
+      indexes[UCNVSEL_INDEX_NAMES_COUNT] * sizeof(char *));
+  if (sel == NULL || encodings == NULL) {
+    uprv_free(swapped);
+    uprv_free(sel);
+    uprv_free(encodings);
+    *status = U_MEMORY_ALLOCATION_ERROR;
+    return NULL;
+  }
+  uprv_memset(sel, 0, sizeof(UConverterSelector));
+  sel->pvCount = indexes[UCNVSEL_INDEX_PV_COUNT];
+  sel->encodings = encodings;
+  sel->encodingsCount = indexes[UCNVSEL_INDEX_NAMES_COUNT];
+  sel->encodingStrLength = indexes[UCNVSEL_INDEX_NAMES_LENGTH];
+  sel->swapped = swapped;
+  // trie
+  sel->trie = utrie2_openFromSerialized(UTRIE2_16_VALUE_BITS,
+                                        p, indexes[UCNVSEL_INDEX_TRIE_SIZE], NULL,
+                                        status);
+  p += indexes[UCNVSEL_INDEX_TRIE_SIZE];
+  if (U_FAILURE(*status)) {
+    ucnvsel_close(sel);
+    return NULL;
+  }
+  // bit vectors
+  sel->pv = (uint32_t *)p;
+  p += sel->pvCount * 4;
+  // encoding names
+  char* s = (char*)p;
+  for (int32_t i = 0; i < sel->encodingsCount; ++i) {
+    sel->encodings[i] = s;
+    s += uprv_strlen(s) + 1;
+  }
+  p += sel->encodingStrLength;
+
+  return sel;
+}
+
+// a bunch of functions for the enumeration thingie! Nothing fancy here. Just
+// iterate over the selected encodings
+struct Enumerator {
+  int16_t* index;
+  int16_t length;
+  int16_t cur;
+  const UConverterSelector* sel;
+};
+
+U_CDECL_BEGIN
+
+static void U_CALLCONV
+ucnvsel_close_selector_iterator(UEnumeration *enumerator) {
+  uprv_free(((Enumerator*)(enumerator->context))->index);
+  uprv_free(enumerator->context);
+  uprv_free(enumerator);
+}
+
+
+static int32_t U_CALLCONV
+ucnvsel_count_encodings(UEnumeration *enumerator, UErrorCode *status) {
+  // check if already failed
+  if (U_FAILURE(*status)) {
+    return 0;
+  }
+  return ((Enumerator*)(enumerator->context))->length;
+}
+
+
+static const char* U_CALLCONV ucnvsel_next_encoding(UEnumeration* enumerator,
+                                                 int32_t* resultLength,
+                                                 UErrorCode* status) {
+  // check if already failed
+  if (U_FAILURE(*status)) {
+    return NULL;
+  }
+
+  int16_t cur = ((Enumerator*)(enumerator->context))->cur;
+  const UConverterSelector* sel;
+  const char* result;
+  if (cur >= ((Enumerator*)(enumerator->context))->length) {
+    return NULL;
+  }
+  sel = ((Enumerator*)(enumerator->context))->sel;
+  result = sel->encodings[((Enumerator*)(enumerator->context))->index[cur] ];
+  ((Enumerator*)(enumerator->context))->cur++;
+  if (resultLength) {
+    *resultLength = (int32_t)uprv_strlen(result);
+  }
+  return result;
+}
+
+static void U_CALLCONV ucnvsel_reset_iterator(UEnumeration* enumerator,
+                                           UErrorCode* status) {
+  // check if already failed
+  if (U_FAILURE(*status)) {
+    return ;
+  }
+  ((Enumerator*)(enumerator->context))->cur = 0;
+}
+
+U_CDECL_END
+
+
+static const UEnumeration defaultEncodings = {
+  NULL,
+    NULL,
+    ucnvsel_close_selector_iterator,
+    ucnvsel_count_encodings,
+    uenum_unextDefault,
+    ucnvsel_next_encoding, 
+    ucnvsel_reset_iterator
+};
+
+
+// internal fn to intersect two sets of masks
+// returns whether the mask has reduced to all zeros
+static UBool intersectMasks(uint32_t* dest, const uint32_t* source1, int32_t len) {
+  int32_t i;
+  uint32_t oredDest = 0;
+  for (i = 0 ; i < len ; ++i) {
+    oredDest |= (dest[i] &= source1[i]);
+  }
+  return oredDest == 0;
+}
+
+// internal fn to count how many 1's are there in a mask
+// algorithm taken from  http://graphics.stanford.edu/~seander/bithacks.html
+static int16_t countOnes(uint32_t* mask, int32_t len) {
+  int32_t i, totalOnes = 0;
+  for (i = 0 ; i < len ; ++i) {
+    uint32_t ent = mask[i];
+    for (; ent; totalOnes++)
+    {
+      ent &= ent - 1; // clear the least significant bit set
+    }
+  }
+  return totalOnes;
+}
+
+
+/* internal function! */
+static UEnumeration *selectForMask(const UConverterSelector* sel,
+                                   uint32_t *mask, UErrorCode *status) {
+  // this is the context we will use. Store a table of indices to which
+  // encodings are legit.
+  struct Enumerator* result = (Enumerator*)uprv_malloc(sizeof(Enumerator));
+  if (result == NULL) {
+    uprv_free(mask);
+    *status = U_MEMORY_ALLOCATION_ERROR;
+    return NULL;
+  }
+  result->index = NULL;  // this will be allocated later!
+  result->length = result->cur = 0;
+  result->sel = sel;
+
+  UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
+  if (en == NULL) {
+    // TODO(markus): Combine Enumerator and UEnumeration into one struct.
+    uprv_free(mask);
+    uprv_free(result);
+    *status = U_MEMORY_ALLOCATION_ERROR;
+    return NULL;
+  }
+  memcpy(en, &defaultEncodings, sizeof(UEnumeration));
+  en->context = result;
+
+  int32_t columns = (sel->encodingsCount+31)/32;
+  int16_t numOnes = countOnes(mask, columns);
+  // now, we know the exact space we need for index
+  if (numOnes > 0) {
+    result->index = (int16_t*) uprv_malloc(numOnes * sizeof(int16_t));
+
+    int32_t i, j;
+    int16_t k = 0;
+    for (j = 0 ; j < columns; j++) {
+      uint32_t v = mask[j];
+      for (i = 0 ; i < 32 && k < sel->encodingsCount; i++, k++) {
+        if ((v & 1) != 0) {
+          result->index[result->length++] = k;
+        }
+        v >>= 1;
+      }
+    }
+  } //otherwise, index will remain NULL (and will never be touched by
+    //the enumerator code anyway)
+  uprv_free(mask);
+  return en;
+}
+
+/* check a string against the selector - UTF16 version */
+U_CAPI UEnumeration * U_EXPORT2
+ucnvsel_selectForString(const UConverterSelector* sel,
+                        const UChar *s, int32_t length, UErrorCode *status) {
+  // check if already failed
+  if (U_FAILURE(*status)) {
+    return NULL;
+  }
+  // ensure args make sense!
+  if (sel == NULL || (s == NULL && length != 0)) {
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+    return NULL;
+  }
+
+  int32_t columns = (sel->encodingsCount+31)/32;
+  uint32_t* mask = (uint32_t*) uprv_malloc(columns * 4);
+  if (mask == NULL) {
+    *status = U_MEMORY_ALLOCATION_ERROR;
+    return NULL;
+  }
+  uprv_memset(mask, ~0, columns *4);
+
+  const UChar *limit;
+  if (length >= 0) {
+    limit = s + length;
+  } else {
+    limit = NULL;
+  }
+
+  while (limit == NULL ? *s != 0 : s != limit) {
+    UChar32 c;
+    uint16_t pvIndex;
+    UTRIE2_U16_NEXT16(sel->trie, s, limit, c, pvIndex);
+    if (intersectMasks(mask, sel->pv+pvIndex, columns)) {
+      break;
+    }
+  }
+  return selectForMask(sel, mask, status);
+}
+
+/* check a string against the selector - UTF8 version */
+U_CAPI UEnumeration * U_EXPORT2
+ucnvsel_selectForUTF8(const UConverterSelector* sel,
+                      const char *s, int32_t length, UErrorCode *status) {
+  // check if already failed
+  if (U_FAILURE(*status)) {
+    return NULL;
+  }
+  // ensure args make sense!
+  if (sel == NULL || (s == NULL && length != 0)) {
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+    return NULL;
+  }
+
+  int32_t columns = (sel->encodingsCount+31)/32;
+  uint32_t* mask = (uint32_t*) uprv_malloc(columns * 4);
+  if (mask == NULL) {
+    *status = U_MEMORY_ALLOCATION_ERROR;
+    return NULL;
+  }
+  uprv_memset(mask, ~0, columns *4);
+
+  if (length < 0) {
+    length = (int32_t)uprv_strlen(s);
+  }
+  const char *limit = s + length;
+
+  while (s != limit) {
+    uint16_t pvIndex;
+    UTRIE2_U8_NEXT16(sel->trie, s, limit, pvIndex);
+    if (intersectMasks(mask, sel->pv+pvIndex, columns)) {
+      break;
+    }
+  }
+  return selectForMask(sel, mask, status);
+}
diff --git a/source/common/ucol_swp.cpp b/source/common/ucol_swp.cpp
new file mode 100644
index 0000000..c59a610
--- /dev/null
+++ b/source/common/ucol_swp.cpp
@@ -0,0 +1,469 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2003-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  ucol_swp.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2003sep10
+*   created by: Markus W. Scherer
+*
+*   Swap collation binaries.
+*/
+
+#include "unicode/udata.h" /* UDataInfo */
+#include "utrie.h"
+#include "udataswp.h"
+#include "cmemory.h"
+#include "ucol_imp.h"
+#include "ucol_swp.h"
+
+/* swapping ----------------------------------------------------------------- */
+
+/*
+ * This performs data swapping for a folded trie (see utrie.c for details).
+ */
+
+U_CAPI int32_t U_EXPORT2
+utrie_swap(const UDataSwapper *ds,
+           const void *inData, int32_t length, void *outData,
+           UErrorCode *pErrorCode) {
+    const UTrieHeader *inTrie;
+    UTrieHeader trie;
+    int32_t size;
+    UBool dataIs32;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(ds==NULL || inData==NULL || (length>=0 && outData==NULL)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* setup and swapping */
+    if(length>=0 && (uint32_t)length<sizeof(UTrieHeader)) {
+        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0;
+    }
+
+    inTrie=(const UTrieHeader *)inData;
+    trie.signature=ds->readUInt32(inTrie->signature);
+    trie.options=ds->readUInt32(inTrie->options);
+    trie.indexLength=udata_readInt32(ds, inTrie->indexLength);
+    trie.dataLength=udata_readInt32(ds, inTrie->dataLength);
+
+    if( trie.signature!=0x54726965 ||
+        (trie.options&UTRIE_OPTIONS_SHIFT_MASK)!=UTRIE_SHIFT ||
+        ((trie.options>>UTRIE_OPTIONS_INDEX_SHIFT)&UTRIE_OPTIONS_SHIFT_MASK)!=UTRIE_INDEX_SHIFT ||
+        trie.indexLength<UTRIE_BMP_INDEX_LENGTH ||
+        (trie.indexLength&(UTRIE_SURROGATE_BLOCK_COUNT-1))!=0 ||
+        trie.dataLength<UTRIE_DATA_BLOCK_LENGTH ||
+        (trie.dataLength&(UTRIE_DATA_GRANULARITY-1))!=0 ||
+        ((trie.options&UTRIE_OPTIONS_LATIN1_IS_LINEAR)!=0 && trie.dataLength<(UTRIE_DATA_BLOCK_LENGTH+0x100))
+    ) {
+        *pErrorCode=U_INVALID_FORMAT_ERROR; /* not a UTrie */
+        return 0;
+    }
+
+    dataIs32=(UBool)((trie.options&UTRIE_OPTIONS_DATA_IS_32_BIT)!=0);
+    size=sizeof(UTrieHeader)+trie.indexLength*2+trie.dataLength*(dataIs32?4:2);
+
+    if(length>=0) {
+        UTrieHeader *outTrie;
+
+        if(length<size) {
+            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+            return 0;
+        }
+
+        outTrie=(UTrieHeader *)outData;
+
+        /* swap the header */
+        ds->swapArray32(ds, inTrie, sizeof(UTrieHeader), outTrie, pErrorCode);
+
+        /* swap the index and the data */
+        if(dataIs32) {
+            ds->swapArray16(ds, inTrie+1, trie.indexLength*2, outTrie+1, pErrorCode);
+            ds->swapArray32(ds, (const uint16_t *)(inTrie+1)+trie.indexLength, trie.dataLength*4,
+                                     (uint16_t *)(outTrie+1)+trie.indexLength, pErrorCode);
+        } else {
+            ds->swapArray16(ds, inTrie+1, (trie.indexLength+trie.dataLength)*2, outTrie+1, pErrorCode);
+        }
+    }
+
+    return size;
+}
+
+#if !UCONFIG_NO_COLLATION
+
+/* Modified copy of the beginning of ucol_swapBinary(). */
+U_CAPI UBool U_EXPORT2
+ucol_looksLikeCollationBinary(const UDataSwapper *ds,
+                              const void *inData, int32_t length) {
+    const uint8_t *inBytes;
+    const UCATableHeader *inHeader;
+    UCATableHeader header;
+
+    if(ds==NULL || inData==NULL || length<-1) {
+        return FALSE;
+    }
+
+    inBytes=(const uint8_t *)inData;
+    inHeader=(const UCATableHeader *)inData;
+
+    /*
+     * The collation binary must contain at least the UCATableHeader,
+     * starting with its size field.
+     * sizeof(UCATableHeader)==42*4 in ICU 2.8
+     * check the length against the header size before reading the size field
+     */
+    uprv_memset(&header, 0, sizeof(header));
+    if(length<0) {
+        header.size=udata_readInt32(ds, inHeader->size);
+    } else if((length<(42*4) || length<(header.size=udata_readInt32(ds, inHeader->size)))) {
+        return FALSE;
+    }
+
+    header.magic=ds->readUInt32(inHeader->magic);
+    if(!(
+        header.magic==UCOL_HEADER_MAGIC &&
+        inHeader->formatVersion[0]==3 /*&&
+        inHeader->formatVersion[1]>=0*/
+    )) {
+        return FALSE;
+    }
+
+    if(inHeader->isBigEndian!=ds->inIsBigEndian || inHeader->charSetFamily!=ds->inCharset) {
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+/* swap a header-less collation binary, inside a resource bundle or ucadata.icu */
+U_CAPI int32_t U_EXPORT2
+ucol_swapBinary(const UDataSwapper *ds,
+                const void *inData, int32_t length, void *outData,
+                UErrorCode *pErrorCode) {
+    const uint8_t *inBytes;
+    uint8_t *outBytes;
+
+    const UCATableHeader *inHeader;
+    UCATableHeader *outHeader;
+    UCATableHeader header;
+
+    uint32_t count;
+
+    /* argument checking in case we were not called from ucol_swap() */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(ds==NULL || inData==NULL || length<-1 || (length>0 && outData==NULL)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    inBytes=(const uint8_t *)inData;
+    outBytes=(uint8_t *)outData;
+
+    inHeader=(const UCATableHeader *)inData;
+    outHeader=(UCATableHeader *)outData;
+
+    /*
+     * The collation binary must contain at least the UCATableHeader,
+     * starting with its size field.
+     * sizeof(UCATableHeader)==42*4 in ICU 2.8
+     * check the length against the header size before reading the size field
+     */
+    uprv_memset(&header, 0, sizeof(header));
+    if(length<0) {
+        header.size=udata_readInt32(ds, inHeader->size);
+    } else if((length<(42*4) || length<(header.size=udata_readInt32(ds, inHeader->size)))) {
+        udata_printError(ds, "ucol_swapBinary(): too few bytes (%d after header) for collation data\n",
+                         length);
+        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0;
+    }
+
+    header.magic=ds->readUInt32(inHeader->magic);
+    if(!(
+        header.magic==UCOL_HEADER_MAGIC &&
+        inHeader->formatVersion[0]==3 /*&&
+        inHeader->formatVersion[1]>=0*/
+    )) {
+        udata_printError(ds, "ucol_swapBinary(): magic 0x%08x or format version %02x.%02x is not a collation binary\n",
+                         header.magic,
+                         inHeader->formatVersion[0], inHeader->formatVersion[1]);
+        *pErrorCode=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    if(inHeader->isBigEndian!=ds->inIsBigEndian || inHeader->charSetFamily!=ds->inCharset) {
+        udata_printError(ds, "ucol_swapBinary(): endianness %d or charset %d does not match the swapper\n",
+                         inHeader->isBigEndian, inHeader->charSetFamily);
+        *pErrorCode=U_INVALID_FORMAT_ERROR;
+        return 0;
+    }
+
+    if(length>=0) {
+        /* copy everything, takes care of data that needs no swapping */
+        if(inBytes!=outBytes) {
+            uprv_memcpy(outBytes, inBytes, header.size);
+        }
+
+        /* swap the necessary pieces in the order of their occurrence in the data */
+
+        /* read more of the UCATableHeader (the size field was read above) */
+        header.options=                 ds->readUInt32(inHeader->options);
+        header.UCAConsts=               ds->readUInt32(inHeader->UCAConsts);
+        header.contractionUCACombos=    ds->readUInt32(inHeader->contractionUCACombos);
+        header.mappingPosition=         ds->readUInt32(inHeader->mappingPosition);
+        header.expansion=               ds->readUInt32(inHeader->expansion);
+        header.contractionIndex=        ds->readUInt32(inHeader->contractionIndex);
+        header.contractionCEs=          ds->readUInt32(inHeader->contractionCEs);
+        header.contractionSize=         ds->readUInt32(inHeader->contractionSize);
+        header.endExpansionCE=          ds->readUInt32(inHeader->endExpansionCE);
+        header.expansionCESize=         ds->readUInt32(inHeader->expansionCESize);
+        header.endExpansionCECount=     udata_readInt32(ds, inHeader->endExpansionCECount);
+        header.contractionUCACombosSize=udata_readInt32(ds, inHeader->contractionUCACombosSize);
+        header.scriptToLeadByte=        ds->readUInt32(inHeader->scriptToLeadByte);
+        header.leadByteToScript=        ds->readUInt32(inHeader->leadByteToScript);
+        
+        /* swap the 32-bit integers in the header */
+        ds->swapArray32(ds, inHeader, (int32_t)((const char *)&inHeader->jamoSpecial-(const char *)inHeader),
+                           outHeader, pErrorCode);
+        ds->swapArray32(ds, &(inHeader->scriptToLeadByte), sizeof(header.scriptToLeadByte) + sizeof(header.leadByteToScript),
+                           &(outHeader->scriptToLeadByte), pErrorCode);
+        /* set the output platform properties */
+        outHeader->isBigEndian=ds->outIsBigEndian;
+        outHeader->charSetFamily=ds->outCharset;
+
+        /* swap the options */
+        if(header.options!=0) {
+            ds->swapArray32(ds, inBytes+header.options, header.expansion-header.options,
+                               outBytes+header.options, pErrorCode);
+        }
+
+        /* swap the expansions */
+        if(header.mappingPosition!=0 && header.expansion!=0) {
+            if(header.contractionIndex!=0) {
+                /* expansions bounded by contractions */
+                count=header.contractionIndex-header.expansion;
+            } else {
+                /* no contractions: expansions bounded by the main trie */
+                count=header.mappingPosition-header.expansion;
+            }
+            ds->swapArray32(ds, inBytes+header.expansion, (int32_t)count,
+                               outBytes+header.expansion, pErrorCode);
+        }
+
+        /* swap the contractions */
+        if(header.contractionSize!=0) {
+            /* contractionIndex: UChar[] */
+            ds->swapArray16(ds, inBytes+header.contractionIndex, header.contractionSize*2,
+                               outBytes+header.contractionIndex, pErrorCode);
+
+            /* contractionCEs: CEs[] */
+            ds->swapArray32(ds, inBytes+header.contractionCEs, header.contractionSize*4,
+                               outBytes+header.contractionCEs, pErrorCode);
+        }
+
+        /* swap the main trie */
+        if(header.mappingPosition!=0) {
+            count=header.endExpansionCE-header.mappingPosition;
+            utrie_swap(ds, inBytes+header.mappingPosition, (int32_t)count,
+                          outBytes+header.mappingPosition, pErrorCode);
+        }
+
+        /* swap the max expansion table */
+        if(header.endExpansionCECount!=0) {
+            ds->swapArray32(ds, inBytes+header.endExpansionCE, header.endExpansionCECount*4,
+                               outBytes+header.endExpansionCE, pErrorCode);
+        }
+
+        /* expansionCESize, unsafeCP, contrEndCP: uint8_t[], no need to swap */
+
+        /* swap UCA constants */
+        if(header.UCAConsts!=0) {
+            /*
+             * if UCAConsts!=0 then contractionUCACombos because we are swapping
+             * the UCA data file, and we know that the UCA contains contractions
+             */
+            count=header.contractionUCACombos-header.UCAConsts;
+            ds->swapArray32(ds, inBytes+header.UCAConsts, header.contractionUCACombos-header.UCAConsts,
+                               outBytes+header.UCAConsts, pErrorCode);
+        }
+
+        /* swap UCA contractions */
+        if(header.contractionUCACombosSize!=0) {
+            count=header.contractionUCACombosSize*inHeader->contractionUCACombosWidth*U_SIZEOF_UCHAR;
+            ds->swapArray16(ds, inBytes+header.contractionUCACombos, (int32_t)count,
+                               outBytes+header.contractionUCACombos, pErrorCode);
+        }
+        
+        /* swap the script to lead bytes */
+        if(header.scriptToLeadByte!=0) {
+            int indexCount = ds->readUInt16(*((uint16_t*)(inBytes+header.scriptToLeadByte))); // each entry = 2 * uint16
+            int dataCount = ds->readUInt16(*((uint16_t*)(inBytes+header.scriptToLeadByte + 2))); // each entry = uint16
+            ds->swapArray16(ds, inBytes+header.scriptToLeadByte, 
+                                4 + (4 * indexCount) + (2 * dataCount),
+                                outBytes+header.scriptToLeadByte, pErrorCode);
+        }
+        
+        /* swap the lead byte to scripts */
+        if(header.leadByteToScript!=0) {
+            int indexCount = ds->readUInt16(*((uint16_t*)(inBytes+header.leadByteToScript))); // each entry = uint16
+            int dataCount = ds->readUInt16(*((uint16_t*)(inBytes+header.leadByteToScript + 2))); // each entry = uint16
+            ds->swapArray16(ds, inBytes+header.leadByteToScript, 
+                                4 + (2 * indexCount) + (2 * dataCount),
+                                outBytes+header.leadByteToScript, pErrorCode);
+        }
+    }
+
+    return header.size;
+}
+
+/* swap ICU collation data like ucadata.icu */
+U_CAPI int32_t U_EXPORT2
+ucol_swap(const UDataSwapper *ds,
+          const void *inData, int32_t length, void *outData,
+          UErrorCode *pErrorCode) {
+          
+    const UDataInfo *pInfo;
+    int32_t headerSize, collationSize;
+
+    /* udata_swapDataHeader checks the arguments */
+    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    /* check data format and format version */
+    pInfo=(const UDataInfo *)((const char *)inData+4);
+    if(!(
+        pInfo->dataFormat[0]==0x55 &&   /* dataFormat="UCol" */
+        pInfo->dataFormat[1]==0x43 &&
+        pInfo->dataFormat[2]==0x6f &&
+        pInfo->dataFormat[3]==0x6c &&
+        pInfo->formatVersion[0]==3 /*&&
+        pInfo->formatVersion[1]>=0*/
+    )) {
+        udata_printError(ds, "ucol_swap(): data format %02x.%02x.%02x.%02x (format version %02x.%02x) is not a collation file\n",
+                         pInfo->dataFormat[0], pInfo->dataFormat[1],
+                         pInfo->dataFormat[2], pInfo->dataFormat[3],
+                         pInfo->formatVersion[0], pInfo->formatVersion[1]);
+        *pErrorCode=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    collationSize=ucol_swapBinary(ds,
+                        (const char *)inData+headerSize,
+                        length>=0 ? length-headerSize : -1,
+                        (char *)outData+headerSize,
+                        pErrorCode);
+    if(U_SUCCESS(*pErrorCode)) {
+        return headerSize+collationSize;
+    } else {
+        return 0;
+    }
+}
+
+/* swap inverse UCA collation data (invuca.icu) */
+U_CAPI int32_t U_EXPORT2
+ucol_swapInverseUCA(const UDataSwapper *ds,
+                    const void *inData, int32_t length, void *outData,
+                    UErrorCode *pErrorCode) {
+    const UDataInfo *pInfo;
+    int32_t headerSize;
+
+    const uint8_t *inBytes;
+    uint8_t *outBytes;
+
+    const InverseUCATableHeader *inHeader;
+    InverseUCATableHeader *outHeader;
+    InverseUCATableHeader header={ 0,0,0,0,0,{0,0,0,0},{0,0,0,0,0,0,0,0} };
+
+    /* udata_swapDataHeader checks the arguments */
+    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    /* check data format and format version */
+    pInfo=(const UDataInfo *)((const char *)inData+4);
+    if(!(
+        pInfo->dataFormat[0]==0x49 &&   /* dataFormat="InvC" */
+        pInfo->dataFormat[1]==0x6e &&
+        pInfo->dataFormat[2]==0x76 &&
+        pInfo->dataFormat[3]==0x43 &&
+        pInfo->formatVersion[0]==2 &&
+        pInfo->formatVersion[1]>=1
+    )) {
+        udata_printError(ds, "ucol_swapInverseUCA(): data format %02x.%02x.%02x.%02x (format version %02x.%02x) is not an inverse UCA collation file\n",
+                         pInfo->dataFormat[0], pInfo->dataFormat[1],
+                         pInfo->dataFormat[2], pInfo->dataFormat[3],
+                         pInfo->formatVersion[0], pInfo->formatVersion[1]);
+        *pErrorCode=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    inBytes=(const uint8_t *)inData+headerSize;
+    outBytes=(uint8_t *)outData+headerSize;
+
+    inHeader=(const InverseUCATableHeader *)inBytes;
+    outHeader=(InverseUCATableHeader *)outBytes;
+
+    /*
+     * The inverse UCA collation binary must contain at least the InverseUCATableHeader,
+     * starting with its size field.
+     * sizeof(UCATableHeader)==8*4 in ICU 2.8
+     * check the length against the header size before reading the size field
+     */
+    if(length<0) {
+        header.byteSize=udata_readInt32(ds, inHeader->byteSize);
+    } else if(
+        ((length-headerSize)<(8*4) ||
+         (uint32_t)(length-headerSize)<(header.byteSize=udata_readInt32(ds, inHeader->byteSize)))
+    ) {
+        udata_printError(ds, "ucol_swapInverseUCA(): too few bytes (%d after header) for inverse UCA collation data\n",
+                         length);
+        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0;
+    }
+
+    if(length>=0) {
+        /* copy everything, takes care of data that needs no swapping */
+        if(inBytes!=outBytes) {
+            uprv_memcpy(outBytes, inBytes, header.byteSize);
+        }
+
+        /* swap the necessary pieces in the order of their occurrence in the data */
+
+        /* read more of the InverseUCATableHeader (the byteSize field was read above) */
+        header.tableSize=   ds->readUInt32(inHeader->tableSize);
+        header.contsSize=   ds->readUInt32(inHeader->contsSize);
+        header.table=       ds->readUInt32(inHeader->table);
+        header.conts=       ds->readUInt32(inHeader->conts);
+
+        /* swap the 32-bit integers in the header */
+        ds->swapArray32(ds, inHeader, 5*4, outHeader, pErrorCode);
+
+        /* swap the inverse table; tableSize counts uint32_t[3] rows */
+        ds->swapArray32(ds, inBytes+header.table, header.tableSize*3*4,
+                           outBytes+header.table, pErrorCode);
+
+        /* swap the continuation table; contsSize counts UChars */
+        ds->swapArray16(ds, inBytes+header.conts, header.contsSize*U_SIZEOF_UCHAR,
+                           outBytes+header.conts, pErrorCode);
+    }
+
+    return headerSize+header.byteSize;
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/source/common/ucol_swp.h b/source/common/ucol_swp.h
new file mode 100644
index 0000000..cb5ef15
--- /dev/null
+++ b/source/common/ucol_swp.h
@@ -0,0 +1,66 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2003-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  ucol_swp.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2003sep10
+*   created by: Markus W. Scherer
+*
+*   Swap collation binaries.
+*/
+
+#ifndef __UCOL_SWP_H__
+#define __UCOL_SWP_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "udataswp.h"
+
+/*
+ * Does the data look like a collation binary?
+ * @internal
+ */
+U_INTERNAL UBool U_EXPORT2
+ucol_looksLikeCollationBinary(const UDataSwapper *ds,
+                              const void *inData, int32_t length);
+
+/**
+ * Swap a header-less collation binary, inside a resource bundle or ucadata.icu.
+ * See udataswp.h.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+ucol_swapBinary(const UDataSwapper *ds,
+                const void *inData, int32_t length, void *outData,
+                UErrorCode *pErrorCode);
+
+/**
+ * Swap ICU collation data like ucadata.icu. See udataswp.h.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+ucol_swap(const UDataSwapper *ds,
+          const void *inData, int32_t length, void *outData,
+          UErrorCode *pErrorCode);
+
+/**
+ * Swap inverse UCA collation data (invuca.icu). See udataswp.h.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+ucol_swapInverseUCA(const UDataSwapper *ds,
+                    const void *inData, int32_t length, void *outData,
+                    UErrorCode *pErrorCode);
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/source/common/udata.cpp b/source/common/udata.cpp
new file mode 100644
index 0000000..be2b16e
--- /dev/null
+++ b/source/common/udata.cpp
@@ -0,0 +1,1358 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  udata.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999oct25
+*   created by: Markus W. Scherer
+*/
+
+#include "unicode/utypes.h"  /* U_LINUX */
+
+#ifdef U_LINUX
+/* if gcc
+#define ATTRIBUTE_WEAK __attribute__ ((weak))
+might have to #include some other header
+*/
+#endif
+
+#include "unicode/putil.h"
+#include "unicode/udata.h"
+#include "unicode/uversion.h"
+#include "charstr.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "putilimp.h"
+#include "ucln_cmn.h"
+#include "ucmndata.h"
+#include "udatamem.h"
+#include "uhash.h"
+#include "umapfile.h"
+#include "umutex.h"
+
+/***********************************************************************
+*
+*   Notes on the organization of the ICU data implementation
+*
+*      All of the public API is defined in udata.h
+*
+*      The implementation is split into several files...
+*
+*         - udata.c  (this file) contains higher level code that knows about
+*                     the search paths for locating data, caching opened data, etc.
+*
+*         - umapfile.c  contains the low level platform-specific code for actually loading
+*                     (memory mapping, file reading, whatever) data into memory.
+*
+*         - ucmndata.c  deals with the tables of contents of ICU data items within
+*                     an ICU common format data file.  The implementation includes
+*                     an abstract interface and support for multiple TOC formats.
+*                     All knowledge of any specific TOC format is encapsulated here.
+*
+*         - udatamem.c has code for managing UDataMemory structs.  These are little
+*                     descriptor objects for blocks of memory holding ICU data of
+*                     various types.
+*/
+
+/* configuration ---------------------------------------------------------- */
+
+/* If you are excruciatingly bored turn this on .. */
+/* #define UDATA_DEBUG 1 */
+
+#if defined(UDATA_DEBUG)
+#   include <stdio.h>
+#endif
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+U_NAMESPACE_USE
+
+/***********************************************************************
+*
+*    static (Global) data
+*
+************************************************************************/
+
+/*
+ * Pointers to the common ICU data.
+ *
+ * We store multiple pointers to ICU data packages and iterate through them
+ * when looking for a data item.
+ *
+ * It is possible to combine this with dependency inversion:
+ * One or more data package libraries may export
+ * functions that each return a pointer to their piece of the ICU data,
+ * and this file would import them as weak functions, without a
+ * strong linker dependency from the common library on the data library.
+ *
+ * Then we can have applications depend on only that part of ICU's data
+ * that they really need, reducing the size of binaries that take advantage
+ * of this.
+ */
+static UDataMemory *gCommonICUDataArray[10] = { NULL };
+
+static UBool gHaveTriedToLoadCommonData = FALSE;  /* See extendICUData(). */
+
+static UHashtable  *gCommonDataCache = NULL;  /* Global hash table of opened ICU data files.  */
+
+static UDataFileAccess  gDataFileAccess = UDATA_DEFAULT_ACCESS;
+
+static UBool U_CALLCONV
+udata_cleanup(void)
+{
+    int32_t i;
+
+    if (gCommonDataCache) {             /* Delete the cache of user data mappings.  */
+        uhash_close(gCommonDataCache);  /*   Table owns the contents, and will delete them. */
+        gCommonDataCache = NULL;        /*   Cleanup is not thread safe.                */
+    }
+
+    for (i = 0; i < LENGTHOF(gCommonICUDataArray) && gCommonICUDataArray[i] != NULL; ++i) {
+        udata_close(gCommonICUDataArray[i]);
+        gCommonICUDataArray[i] = NULL;
+    }
+    gHaveTriedToLoadCommonData = FALSE;
+
+    return TRUE;                   /* Everything was cleaned up */
+}
+
+
+
+
+/*
+ * setCommonICUData.   Set a UDataMemory to be the global ICU Data
+ */
+static UBool
+setCommonICUData(UDataMemory *pData,     /*  The new common data.  Belongs to caller, we copy it. */
+                 UBool       warn,       /*  If true, set USING_DEFAULT warning if ICUData was    */
+                                         /*    changed by another thread before we got to it.     */
+                 UErrorCode *pErr)
+{
+    UDataMemory  *newCommonData = UDataMemory_createNewInstance(pErr);
+    int32_t i;
+    UBool didUpdate = FALSE;
+    if (U_FAILURE(*pErr)) {
+        return FALSE;
+    }
+
+    /*  For the assignment, other threads must cleanly see either the old            */
+    /*    or the new, not some partially initialized new.  The old can not be        */
+    /*    deleted - someone may still have a pointer to it lying around in           */
+    /*    their locals.                                                              */
+    UDatamemory_assign(newCommonData, pData);
+    umtx_lock(NULL);
+    for (i = 0; i < LENGTHOF(gCommonICUDataArray); ++i) {
+        if (gCommonICUDataArray[i] == NULL) {
+            gCommonICUDataArray[i] = newCommonData;
+            ucln_common_registerCleanup(UCLN_COMMON_UDATA, udata_cleanup);
+            didUpdate = TRUE;
+            break;
+        } else if (gCommonICUDataArray[i]->pHeader == pData->pHeader) {
+            /* The same data pointer is already in the array. */
+            break;
+        }
+    }
+    umtx_unlock(NULL);
+
+    if (i == LENGTHOF(gCommonICUDataArray) && warn) {
+        *pErr = U_USING_DEFAULT_WARNING;
+    }
+    if (!didUpdate) {
+        uprv_free(newCommonData);
+    }
+    return didUpdate;
+}
+
+static UBool
+setCommonICUDataPointer(const void *pData, UBool /*warn*/, UErrorCode *pErrorCode) {
+    UDataMemory tData;
+    UDataMemory_init(&tData);
+    tData.pHeader = (const DataHeader *)pData;
+    udata_checkCommonData(&tData, pErrorCode);
+    return setCommonICUData(&tData, FALSE, pErrorCode);
+}
+
+static const char *
+findBasename(const char *path) {
+    const char *basename=uprv_strrchr(path, U_FILE_SEP_CHAR);
+    if(basename==NULL) {
+        return path;
+    } else {
+        return basename+1;
+    }
+}
+
+#ifdef UDATA_DEBUG
+static const char *
+packageNameFromPath(const char *path)
+{
+    if((path == NULL) || (*path == 0)) {
+        return U_ICUDATA_NAME;
+    }
+
+    path = findBasename(path);
+
+    if((path == NULL) || (*path == 0)) {
+        return U_ICUDATA_NAME;
+    }
+
+    return path;
+}
+#endif
+
+/*----------------------------------------------------------------------*
+ *                                                                      *
+ *   Cache for common data                                              *
+ *      Functions for looking up or adding entries to a cache of        *
+ *      data that has been previously opened.  Avoids a potentially     *
+ *      expensive operation of re-opening the data for subsequent       *
+ *      uses.                                                           *
+ *                                                                      *
+ *      Data remains cached for the duration of the process.            *
+ *                                                                      *
+ *----------------------------------------------------------------------*/
+
+typedef struct DataCacheElement {
+    char          *name;
+    UDataMemory   *item;
+} DataCacheElement;
+
+
+
+/*
+ * Deleter function for DataCacheElements.
+ *         udata cleanup function closes the hash table; hash table in turn calls back to
+ *         here for each entry.
+ */
+static void U_CALLCONV DataCacheElement_deleter(void *pDCEl) {
+    DataCacheElement *p = (DataCacheElement *)pDCEl;
+    udata_close(p->item);              /* unmaps storage */
+    uprv_free(p->name);                /* delete the hash key string. */
+    uprv_free(pDCEl);                  /* delete 'this'          */
+}
+
+ /*   udata_getCacheHashTable()
+ *     Get the hash table used to store the data cache entries.
+ *     Lazy create it if it doesn't yet exist.
+ */
+static UHashtable *udata_getHashTable() {
+    UErrorCode   err = U_ZERO_ERROR;
+    UBool        cacheIsInitialized;
+    UHashtable  *tHT = NULL;
+
+    UMTX_CHECK(NULL, (gCommonDataCache != NULL), cacheIsInitialized);
+
+    if (cacheIsInitialized) {
+        return gCommonDataCache;
+    }
+
+    tHT = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &err);
+    /* Check for null pointer. */
+    if (tHT == NULL) {
+    	return NULL; /* TODO:  Handle this error better. */
+    }
+    uhash_setValueDeleter(tHT, DataCacheElement_deleter);
+
+    umtx_lock(NULL);
+    if (gCommonDataCache == NULL) {
+        gCommonDataCache = tHT;
+        tHT = NULL;
+        ucln_common_registerCleanup(UCLN_COMMON_UDATA, udata_cleanup);
+    }
+    umtx_unlock(NULL);
+    if (tHT != NULL) {
+        uhash_close(tHT);
+    }
+
+    if (U_FAILURE(err)) {
+        return NULL;      /* TODO:  handle this error better.  */
+    }
+    return gCommonDataCache;
+}
+
+
+
+static UDataMemory *udata_findCachedData(const char *path)
+{
+    UHashtable        *htable;
+    UDataMemory       *retVal = NULL;
+    DataCacheElement  *el;
+    const char        *baseName;
+
+    baseName = findBasename(path);   /* Cache remembers only the base name, not the full path. */
+    htable = udata_getHashTable();
+    umtx_lock(NULL);
+    el = (DataCacheElement *)uhash_get(htable, baseName);
+    umtx_unlock(NULL);
+    if (el != NULL) {
+        retVal = el->item;
+    }
+#ifdef UDATA_DEBUG
+    fprintf(stderr, "Cache: [%s] -> %p\n", baseName, retVal);
+#endif
+    return retVal;
+}
+
+
+static UDataMemory *udata_cacheDataItem(const char *path, UDataMemory *item, UErrorCode *pErr) {
+    DataCacheElement *newElement;
+    const char       *baseName;
+    int32_t           nameLen;
+    UHashtable       *htable;
+    DataCacheElement *oldValue = NULL;
+    UErrorCode        subErr = U_ZERO_ERROR;
+
+    if (U_FAILURE(*pErr)) {
+        return NULL;
+    }
+
+    /* Create a new DataCacheElement - the thingy we store in the hash table -
+     * and copy the supplied path and UDataMemoryItems into it.
+     */
+    newElement = (DataCacheElement *)uprv_malloc(sizeof(DataCacheElement));
+    if (newElement == NULL) {
+        *pErr = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    newElement->item = UDataMemory_createNewInstance(pErr);
+    if (U_FAILURE(*pErr)) {
+        uprv_free(newElement);
+        return NULL;
+    }
+    UDatamemory_assign(newElement->item, item);
+
+    baseName = findBasename(path);
+    nameLen = (int32_t)uprv_strlen(baseName);
+    newElement->name = (char *)uprv_malloc(nameLen+1);
+    if (newElement->name == NULL) {
+        *pErr = U_MEMORY_ALLOCATION_ERROR;
+        uprv_free(newElement->item);
+        uprv_free(newElement);
+        return NULL;
+    }
+    uprv_strcpy(newElement->name, baseName);
+
+    /* Stick the new DataCacheElement into the hash table.
+    */
+    htable = udata_getHashTable();
+    umtx_lock(NULL);
+    oldValue = (DataCacheElement *)uhash_get(htable, path);
+    if (oldValue != NULL) {
+        subErr = U_USING_DEFAULT_WARNING;
+    }
+    else {
+        uhash_put(
+            htable,
+            newElement->name,               /* Key   */
+            newElement,                     /* Value */
+            &subErr);
+    }
+    umtx_unlock(NULL);
+
+#ifdef UDATA_DEBUG
+    fprintf(stderr, "Cache: [%s] <<< %p : %s. vFunc=%p\n", newElement->name, 
+    newElement->item, u_errorName(subErr), newElement->item->vFuncs);
+#endif
+
+    if (subErr == U_USING_DEFAULT_WARNING || U_FAILURE(subErr)) {
+        *pErr = subErr; /* copy sub err unto fillin ONLY if something happens. */
+        uprv_free(newElement->name);
+        uprv_free(newElement->item);
+        uprv_free(newElement);
+        return oldValue ? oldValue->item : NULL;
+    }
+
+    return newElement->item;
+}
+
+/*----------------------------------------------------------------------*==============
+ *                                                                      *
+ *  Path management.  Could be shared with other tools/etc if need be   *
+ * later on.                                                            *
+ *                                                                      *
+ *----------------------------------------------------------------------*/
+
+#define U_DATA_PATHITER_BUFSIZ  128        /* Size of local buffer for paths         */
+                                           /*   Overflow causes malloc of larger buf */
+
+U_NAMESPACE_BEGIN
+
+class UDataPathIterator
+{
+public:
+    UDataPathIterator(const char *path, const char *pkg,
+                      const char *item, const char *suffix, UBool doCheckLastFour,
+                      UErrorCode *pErrorCode);
+    const char *next(UErrorCode *pErrorCode);
+
+private:
+    const char *path;                              /* working path (u_icudata_Dir) */
+    const char *nextPath;                          /* path following this one */
+    const char *basename;                          /* item's basename (icudt22e_mt.res)*/
+    const char *suffix;                            /* item suffix (can be null) */
+
+    uint32_t    basenameLen;                       /* length of basename */
+
+    CharString  itemPath;                          /* path passed in with item name */
+    CharString  pathBuffer;                        /* output path for this it'ion */
+    CharString  packageStub;                       /* example:  "/icudt28b". Will ignore that leaf in set paths. */
+
+    UBool       checkLastFour;                     /* if TRUE then allow paths such as '/foo/myapp.dat'
+                                                    * to match, checks last 4 chars of suffix with
+                                                    * last 4 of path, then previous chars. */
+};
+
+/**
+ * @param iter  The iterator to be initialized. Its current state does not matter. 
+ * @param path  The full pathname to be iterated over.  If NULL, defaults to U_ICUDATA_NAME 
+ * @param pkg   Package which is being searched for, ex "icudt28l".  Will ignore leave directories such as /icudt28l 
+ * @param item  Item to be searched for.  Can include full path, such as /a/b/foo.dat 
+ * @param suffix  Optional item suffix, if not-null (ex. ".dat") then 'path' can contain 'item' explicitly.
+ *               Ex:   'stuff.dat' would be found in '/a/foo:/tmp/stuff.dat:/bar/baz' as item #2.   
+ *                     '/blarg/stuff.dat' would also be found.
+ */
+UDataPathIterator::UDataPathIterator(const char *inPath, const char *pkg,
+                                     const char *item, const char *inSuffix, UBool doCheckLastFour,
+                                     UErrorCode *pErrorCode)
+{
+#ifdef UDATA_DEBUG
+        fprintf(stderr, "SUFFIX1=%s PATH=%s\n", inSuffix, inPath);
+#endif
+    /** Path **/
+    if(inPath == NULL) {
+        path = u_getDataDirectory();
+    } else {
+        path = inPath;
+    }
+
+    /** Package **/
+    if(pkg != NULL) {
+      packageStub.append(U_FILE_SEP_CHAR, *pErrorCode).append(pkg, *pErrorCode);
+#ifdef UDATA_DEBUG
+      fprintf(stderr, "STUB=%s [%d]\n", packageStub.data(), packageStub.length());
+#endif
+    }
+
+    /** Item **/
+    basename = findBasename(item);
+    basenameLen = (int32_t)uprv_strlen(basename);
+
+    /** Item path **/
+    if(basename == item) {
+        nextPath = path;
+    } else {
+        itemPath.append(item, (int32_t)(basename-item), *pErrorCode);
+        nextPath = itemPath.data();
+    }
+#ifdef UDATA_DEBUG
+    fprintf(stderr, "SUFFIX=%s [%p]\n", inSuffix, inSuffix);
+#endif
+
+    /** Suffix  **/
+    if(inSuffix != NULL) {
+        suffix = inSuffix;
+    } else {
+        suffix = "";
+    }
+
+    checkLastFour = doCheckLastFour;
+
+    /* pathBuffer will hold the output path strings returned by this iterator */
+
+#ifdef UDATA_DEBUG
+    fprintf(stderr, "%p: init %s -> [path=%s], [base=%s], [suff=%s], [itempath=%s], [nextpath=%s], [checklast4=%s]\n",
+            iter,
+            item,
+            path,
+            basename,
+            suffix,
+            itemPath.data(),
+            nextPath,
+            checkLastFour?"TRUE":"false");
+#endif
+}
+
+/**
+ * Get the next path on the list.
+ *
+ * @param iter The Iter to be used 
+ * @param len  If set, pointer to the length of the returned path, for convenience. 
+ * @return Pointer to the next path segment, or NULL if there are no more.
+ */
+const char *UDataPathIterator::next(UErrorCode *pErrorCode)
+{
+    if(U_FAILURE(*pErrorCode)) {
+        return NULL;
+    }
+
+    const char *currentPath = NULL;
+    int32_t     pathLen = 0;
+    const char *pathBasename;
+
+    do
+    {
+        if( nextPath == NULL ) {
+            break;
+        }
+        currentPath = nextPath;
+
+        if(nextPath == itemPath.data()) { /* we were processing item's path. */
+            nextPath = path; /* start with regular path next tm. */
+            pathLen = (int32_t)uprv_strlen(currentPath);
+        } else {
+            /* fix up next for next time */
+            nextPath = uprv_strchr(currentPath, U_PATH_SEP_CHAR);
+            if(nextPath == NULL) {
+                /* segment: entire path */
+                pathLen = (int32_t)uprv_strlen(currentPath); 
+            } else {
+                /* segment: until next segment */
+                pathLen = (int32_t)(nextPath - currentPath);
+                /* skip divider */
+                nextPath ++;
+            }
+        }
+
+        if(pathLen == 0) {
+            continue;
+        }
+
+#ifdef UDATA_DEBUG
+        fprintf(stderr, "rest of path (IDD) = %s\n", currentPath);
+        fprintf(stderr, "                     ");
+        { 
+            uint32_t qqq;
+            for(qqq=0;qqq<pathLen;qqq++)
+            {
+                fprintf(stderr, " ");
+            }
+
+            fprintf(stderr, "^\n");
+        }
+#endif
+        pathBuffer.clear().append(currentPath, pathLen, *pErrorCode);
+
+        /* check for .dat files */
+        pathBasename = findBasename(pathBuffer.data());
+
+        if(checkLastFour == TRUE && 
+           (pathLen>=4) &&
+           uprv_strncmp(pathBuffer.data() +(pathLen-4), suffix, 4)==0 && /* suffix matches */
+           uprv_strncmp(findBasename(pathBuffer.data()), basename, basenameLen)==0  && /* base matches */
+           uprv_strlen(pathBasename)==(basenameLen+4)) { /* base+suffix = full len */
+
+#ifdef UDATA_DEBUG
+            fprintf(stderr, "Have %s file on the path: %s\n", suffix, pathBuffer.data());
+#endif
+            /* do nothing */
+        }
+        else 
+        {       /* regular dir path */
+            if(pathBuffer[pathLen-1] != U_FILE_SEP_CHAR) {
+                if((pathLen>=4) &&
+                   uprv_strncmp(pathBuffer.data()+(pathLen-4), ".dat", 4) == 0)
+                {
+#ifdef UDATA_DEBUG
+                    fprintf(stderr, "skipping non-directory .dat file %s\n", pathBuffer.data());
+#endif
+                    continue;
+                }
+
+                /* Check if it is a directory with the same name as our package */
+                if(!packageStub.isEmpty() &&
+                   (pathLen > packageStub.length()) &&
+                   !uprv_strcmp(pathBuffer.data() + pathLen - packageStub.length(), packageStub.data())) {
+#ifdef UDATA_DEBUG
+                  fprintf(stderr, "Found stub %s (will add package %s of len %d)\n", packageStub.data(), basename, basenameLen);
+#endif
+                  pathBuffer.truncate(pathLen - packageStub.length());
+                }
+                pathBuffer.append(U_FILE_SEP_CHAR, *pErrorCode);
+            }
+
+            /* + basename */
+            pathBuffer.append(packageStub.data()+1, packageStub.length()-1, *pErrorCode);
+
+            if(*suffix)  /* tack on suffix */
+            {
+                pathBuffer.append(suffix, *pErrorCode);
+            }
+        }
+
+#ifdef UDATA_DEBUG
+        fprintf(stderr, " -->  %s\n", pathBuffer.data());
+#endif
+
+        return pathBuffer.data();
+
+    } while(path);
+
+    /* fell way off the end */
+    return NULL;
+}
+
+U_NAMESPACE_END
+
+/* ==================================================================================*/
+
+
+/*----------------------------------------------------------------------*
+ *                                                                      *
+ *  Add a static reference to the common data  library                  *
+ *   Unless overridden by an explicit udata_setCommonData, this will be *
+ *      our common data.                                                *
+ *                                                                      *
+ *----------------------------------------------------------------------*/
+extern "C" const DataHeader U_DATA_API U_ICUDATA_ENTRY_POINT;
+
+/*
+ * This would be a good place for weak-linkage declarations of
+ * partial-data-library access functions where each returns a pointer
+ * to its data package, if it is linked in.
+ */
+/*
+extern const void *uprv_getICUData_collation(void) ATTRIBUTE_WEAK;
+extern const void *uprv_getICUData_conversion(void) ATTRIBUTE_WEAK;
+*/
+
+/*----------------------------------------------------------------------*
+ *                                                                      *
+ *   openCommonData   Attempt to open a common format (.dat) file       *
+ *                    Map it into memory (if it's not there already)    *
+ *                    and return a UDataMemory object for it.           *
+ *                                                                      *
+ *                    If the requested data is already open and cached  *
+ *                       just return the cached UDataMem object.        *
+ *                                                                      *
+ *----------------------------------------------------------------------*/
+static UDataMemory *
+openCommonData(const char *path,          /*  Path from OpenChoice?          */
+               int32_t commonDataIndex,   /*  ICU Data (index >= 0) if path == NULL */
+               UErrorCode *pErrorCode)
+{
+    UDataMemory tData;
+    const char *pathBuffer;
+    const char *inBasename;
+
+    if (U_FAILURE(*pErrorCode)) {
+        return NULL;
+    }
+
+    UDataMemory_init(&tData);
+
+    /* ??????? TODO revisit this */ 
+    if (commonDataIndex >= 0) {
+        /* "mini-cache" for common ICU data */
+        if(commonDataIndex >= LENGTHOF(gCommonICUDataArray)) {
+            return NULL;
+        }
+        if(gCommonICUDataArray[commonDataIndex] == NULL) {
+            int32_t i;
+            for(i = 0; i < commonDataIndex; ++i) {
+                if(gCommonICUDataArray[i]->pHeader == &U_ICUDATA_ENTRY_POINT) {
+                    /* The linked-in data is already in the list. */
+                    return NULL;
+                }
+            }
+
+            /* Add the linked-in data to the list. */
+            /*
+             * This is where we would check and call weakly linked partial-data-library
+             * access functions.
+             */
+            /*
+            if (uprv_getICUData_collation) {
+                setCommonICUDataPointer(uprv_getICUData_collation(), FALSE, pErrorCode);
+            }
+            if (uprv_getICUData_conversion) {
+                setCommonICUDataPointer(uprv_getICUData_conversion(), FALSE, pErrorCode);
+            }
+            */
+            setCommonICUDataPointer(&U_ICUDATA_ENTRY_POINT, FALSE, pErrorCode);
+        }
+        return gCommonICUDataArray[commonDataIndex];
+    }
+
+
+    /* request is NOT for ICU Data.  */
+
+    /* Find the base name portion of the supplied path.   */
+    /*   inBasename will be left pointing somewhere within the original path string.      */
+    inBasename = findBasename(path);
+#ifdef UDATA_DEBUG
+    fprintf(stderr, "inBasename = %s\n", inBasename);
+#endif
+
+    if(*inBasename==0) {
+        /* no basename.     This will happen if the original path was a directory name,   */
+        /*    like  "a/b/c/".   (Fallback to separate files will still work.)             */
+#ifdef UDATA_DEBUG
+        fprintf(stderr, "ocd: no basename in %s, bailing.\n", path);
+#endif
+        *pErrorCode=U_FILE_ACCESS_ERROR;
+        return NULL;
+    }
+
+   /* Is the requested common data file already open and cached?                     */
+   /*   Note that the cache is keyed by the base name only.  The rest of the path,   */
+   /*     if any, is not considered.                                                 */
+   {
+        UDataMemory  *dataToReturn = udata_findCachedData(inBasename);
+        if (dataToReturn != NULL) {
+            return dataToReturn;
+        }
+    }
+
+    /* Requested item is not in the cache.
+     * Hunt it down, trying all the path locations
+     */
+
+    UDataPathIterator iter(u_getDataDirectory(), inBasename, path, ".dat", TRUE, pErrorCode);
+
+    while((UDataMemory_isLoaded(&tData)==FALSE) && (pathBuffer = iter.next(pErrorCode)) != NULL)
+    {
+#ifdef UDATA_DEBUG
+        fprintf(stderr, "ocd: trying path %s - ", pathBuffer);
+#endif
+        uprv_mapFile(&tData, pathBuffer);
+#ifdef UDATA_DEBUG
+        fprintf(stderr, "%s\n", UDataMemory_isLoaded(&tData)?"LOADED":"not loaded");
+#endif
+    }
+
+#if defined(OS390_STUBDATA) && defined(OS390BATCH)
+    if (!UDataMemory_isLoaded(&tData)) {
+        char ourPathBuffer[1024];
+        /* One more chance, for extendCommonData() */
+        uprv_strncpy(ourPathBuffer, path, 1019);
+        ourPathBuffer[1019]=0;
+        uprv_strcat(ourPathBuffer, ".dat");
+        uprv_mapFile(&tData, ourPathBuffer);
+    }
+#endif
+
+    if (!UDataMemory_isLoaded(&tData)) {
+        /* no common data */
+        *pErrorCode=U_FILE_ACCESS_ERROR;
+        return NULL;
+    }
+
+    /* we have mapped a file, check its header */
+    udata_checkCommonData(&tData, pErrorCode);
+
+
+    /* Cache the UDataMemory struct for this .dat file,
+     *   so we won't need to hunt it down and map it again next time
+     *   something is needed from it.                */
+    return udata_cacheDataItem(inBasename, &tData, pErrorCode);
+}
+
+
+/*----------------------------------------------------------------------*
+ *                                                                      *
+ *   extendICUData   If the full set of ICU data was not loaded at      *
+ *                   program startup, load it now.  This function will  *
+ *                   be called when the lookup of an ICU data item in   *
+ *                   the common ICU data fails.                         *
+ *                                                                      *
+ *                   return true if new data is loaded, false otherwise.*
+ *                                                                      *
+ *----------------------------------------------------------------------*/
+static UBool extendICUData(UErrorCode *pErr)
+{
+    UDataMemory   *pData;
+    UDataMemory   copyPData;
+    UBool         didUpdate = FALSE;
+
+    /*
+     * There is a chance for a race condition here.
+     * Normally, ICU data is loaded from a DLL or via mmap() and
+     * setCommonICUData() will detect if the same address is set twice.
+     * If ICU is built with data loading via fread() then the address will
+     * be different each time the common data is loaded and we may add
+     * multiple copies of the data.
+     * In this case, use a mutex to prevent the race.
+     * Use a specific mutex to avoid nested locks of the global mutex.
+     */
+#if MAP_IMPLEMENTATION==MAP_STDIO
+    static UMTX extendICUDataMutex = NULL;
+    umtx_lock(&extendICUDataMutex);
+#endif
+    if(!gHaveTriedToLoadCommonData) {
+        gHaveTriedToLoadCommonData = TRUE;
+
+        /* See if we can explicitly open a .dat file for the ICUData. */
+        pData = openCommonData(
+                   U_ICUDATA_NAME,            /*  "icudt20l" , for example.          */
+                   -1,                        /*  Pretend we're not opening ICUData  */
+                   pErr);
+
+        /* How about if there is no pData, eh... */
+
+       UDataMemory_init(&copyPData);
+       if(pData != NULL) {
+          UDatamemory_assign(&copyPData, pData);
+          copyPData.map = 0;              /* The mapping for this data is owned by the hash table */
+          copyPData.mapAddr = 0;          /*   which will unmap it when ICU is shut down.         */
+                                          /* CommonICUData is also unmapped when ICU is shut down.*/
+                                          /* To avoid unmapping the data twice, zero out the map  */
+                                          /*   fields in the UDataMemory that we're assigning     */
+                                          /*   to CommonICUData.                                  */
+
+          didUpdate =
+              setCommonICUData(&copyPData,/*  The new common data.                                */
+                       FALSE,             /*  No warnings if write didn't happen                  */
+                       pErr);             /*  setCommonICUData honors errors; NOP if error set    */
+        }
+    }
+#if MAP_IMPLEMENTATION==MAP_STDIO
+    umtx_unlock(&extendICUDataMutex);
+#endif
+    return didUpdate;               /* Return true if ICUData pointer was updated.   */
+                                    /*   (Could potentialy have been done by another thread racing */
+                                    /*   us through here, but that's fine, we still return true    */
+                                    /*   so that current thread will also examine extended data.   */
+}
+
+/*----------------------------------------------------------------------*
+ *                                                                      *
+ *   udata_setCommonData                                                *
+ *                                                                      *
+ *----------------------------------------------------------------------*/
+U_CAPI void U_EXPORT2
+udata_setCommonData(const void *data, UErrorCode *pErrorCode) {
+    UDataMemory dataMemory;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return;
+    }
+
+    if(data==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    /* set the data pointer and test for validity */
+    UDataMemory_init(&dataMemory);
+    UDataMemory_setData(&dataMemory, data);
+    udata_checkCommonData(&dataMemory, pErrorCode);
+    if (U_FAILURE(*pErrorCode)) {return;}
+
+    /* we have good data */
+    /* Set it up as the ICU Common Data.  */
+    setCommonICUData(&dataMemory, TRUE, pErrorCode);
+}
+
+/*---------------------------------------------------------------------------
+ *
+ *  udata_setAppData
+ *
+ *---------------------------------------------------------------------------- */
+U_CAPI void U_EXPORT2
+udata_setAppData(const char *path, const void *data, UErrorCode *err)
+{
+    UDataMemory     udm;
+
+    if(err==NULL || U_FAILURE(*err)) {
+        return;
+    }
+    if(data==NULL) {
+        *err=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    UDataMemory_init(&udm);
+    UDataMemory_setData(&udm, data);
+    udata_checkCommonData(&udm, err);
+    udata_cacheDataItem(path, &udm, err);
+}
+
+/*----------------------------------------------------------------------------*
+ *                                                                            *
+ *  checkDataItem     Given a freshly located/loaded data item, either        *
+ *                    an entry in a common file or a separately loaded file,  *
+ *                    sanity check its header, and see if the data is         *
+ *                    acceptable to the app.                                  *
+ *                    If the data is good, create and return a UDataMemory    *
+ *                    object that can be returned to the application.         *
+ *                    Return NULL on any sort of failure.                     *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+static UDataMemory *
+checkDataItem
+(
+ const DataHeader         *pHeader,         /* The data item to be checked.                */
+ UDataMemoryIsAcceptable  *isAcceptable,    /* App's call-back function                    */
+ void                     *context,         /*   pass-thru param for above.                */
+ const char               *type,            /*   pass-thru param for above.                */
+ const char               *name,            /*   pass-thru param for above.                */
+ UErrorCode               *nonFatalErr,     /* Error code if this data was not acceptable  */
+                                            /*   but openChoice should continue with       */
+                                            /*   trying to get data from fallback path.    */
+ UErrorCode               *fatalErr         /* Bad error, caller should return immediately */
+ )
+{
+    UDataMemory  *rDataMem = NULL;          /* the new UDataMemory, to be returned.        */
+
+    if (U_FAILURE(*fatalErr)) {
+        return NULL;
+    }
+
+    if(pHeader->dataHeader.magic1==0xda &&
+        pHeader->dataHeader.magic2==0x27 &&
+        (isAcceptable==NULL || isAcceptable(context, type, name, &pHeader->info))
+    ) {
+        rDataMem=UDataMemory_createNewInstance(fatalErr);
+        if (U_FAILURE(*fatalErr)) {
+            return NULL;
+        }
+        rDataMem->pHeader = pHeader;
+    } else {
+        /* the data is not acceptable, look further */
+        /* If we eventually find something good, this errorcode will be */
+        /*    cleared out.                                              */
+        *nonFatalErr=U_INVALID_FORMAT_ERROR;
+    }
+    return rDataMem;
+}
+
+/**
+ * @return 0 if not loaded, 1 if loaded or err 
+ */
+static UDataMemory *doLoadFromIndividualFiles(const char *pkgName, 
+        const char *dataPath, const char *tocEntryPathSuffix,
+            /* following arguments are the same as doOpenChoice itself */
+            const char *path, const char *type, const char *name,
+             UDataMemoryIsAcceptable *isAcceptable, void *context,
+             UErrorCode *subErrorCode,
+             UErrorCode *pErrorCode)
+{
+    const char         *pathBuffer;
+    UDataMemory         dataMemory;
+    UDataMemory *pEntryData;
+
+    /* look in ind. files: package\nam.typ  ========================= */
+    /* init path iterator for individual files */
+    UDataPathIterator iter(dataPath, pkgName, path, tocEntryPathSuffix, FALSE, pErrorCode);
+
+    while((pathBuffer = iter.next(pErrorCode)))
+    {
+#ifdef UDATA_DEBUG
+        fprintf(stderr, "UDATA: trying individual file %s\n", pathBuffer);
+#endif
+        if(uprv_mapFile(&dataMemory, pathBuffer))
+        {
+            pEntryData = checkDataItem(dataMemory.pHeader, isAcceptable, context, type, name, subErrorCode, pErrorCode);
+            if (pEntryData != NULL) {
+                /* Data is good.
+                *  Hand off ownership of the backing memory to the user's UDataMemory.
+                *  and return it.   */
+                pEntryData->mapAddr = dataMemory.mapAddr;
+                pEntryData->map     = dataMemory.map;
+
+#ifdef UDATA_DEBUG
+                fprintf(stderr, "** Mapped file: %s\n", pathBuffer);
+#endif
+                return pEntryData;
+            }
+
+            /* the data is not acceptable, or some error occured.  Either way, unmap the memory */
+            udata_close(&dataMemory);
+
+            /* If we had a nasty error, bail out completely.  */
+            if (U_FAILURE(*pErrorCode)) {
+                return NULL;
+            }
+
+            /* Otherwise remember that we found data but didn't like it for some reason  */
+            *subErrorCode=U_INVALID_FORMAT_ERROR;
+        }
+#ifdef UDATA_DEBUG
+        fprintf(stderr, "%s\n", UDataMemory_isLoaded(&dataMemory)?"LOADED":"not loaded");
+#endif
+    }
+    return NULL;
+}
+
+/**
+ * @return 0 if not loaded, 1 if loaded or err 
+ */
+static UDataMemory *doLoadFromCommonData(UBool isICUData, const char * /*pkgName*/, 
+        const char * /*dataPath*/, const char * /*tocEntryPathSuffix*/, const char *tocEntryName,
+            /* following arguments are the same as doOpenChoice itself */
+            const char *path, const char *type, const char *name,
+             UDataMemoryIsAcceptable *isAcceptable, void *context,
+             UErrorCode *subErrorCode,
+             UErrorCode *pErrorCode)
+{
+    UDataMemory        *pEntryData;
+    const DataHeader   *pHeader;
+    UDataMemory        *pCommonData;
+    int32_t            commonDataIndex;
+    /* try to get common data.  The loop is for platforms such as the 390 that do
+     *  not initially load the full set of ICU data.  If the lookup of an ICU data item
+     *  fails, the full (but slower to load) set is loaded, the and the loop repeats,
+     *  trying the lookup again.  Once the full set of ICU data is loaded, the loop wont
+     *  repeat because the full set will be checked the first time through.
+     *
+     *  The loop also handles the fallback to a .dat file if the application linked
+     *   to the stub data library rather than a real library.
+     */
+    for (commonDataIndex = isICUData ? 0 : -1;;) {
+        pCommonData=openCommonData(path, commonDataIndex, subErrorCode); /** search for pkg **/
+
+        if(U_SUCCESS(*subErrorCode) && pCommonData!=NULL) {
+            int32_t length;
+
+            /* look up the data piece in the common data */
+            pHeader=pCommonData->vFuncs->Lookup(pCommonData, tocEntryName, &length, subErrorCode);
+#ifdef UDATA_DEBUG
+            fprintf(stderr, "%s: pHeader=%p - %s\n", tocEntryName, pHeader, u_errorName(*subErrorCode));
+#endif
+
+            if(pHeader!=NULL) {
+                pEntryData = checkDataItem(pHeader, isAcceptable, context, type, name, subErrorCode, pErrorCode);
+#ifdef UDATA_DEBUG
+                fprintf(stderr, "pEntryData=%p\n", pEntryData);
+#endif
+                if (U_FAILURE(*pErrorCode)) {
+                    return NULL;
+                }
+                if (pEntryData != NULL) {
+                    pEntryData->length = length;
+                    return pEntryData;
+                }
+            }
+        }
+        /* Data wasn't found.  If we were looking for an ICUData item and there is
+         * more data available, load it and try again,
+         * otherwise break out of this loop. */
+        if (!isICUData) {
+            return NULL;
+        } else if (pCommonData != NULL) {
+            ++commonDataIndex;  /* try the next data package */
+        } else if (extendICUData(subErrorCode)) {
+            /* try this data package slot again: it changed from NULL to non-NULL */
+        } else {
+            return NULL;
+        }
+    }
+}
+
+/*
+ *  A note on the ownership of Mapped Memory
+ *
+ *  For common format files, ownership resides with the UDataMemory object
+ *    that lives in the cache of opened common data.  These UDataMemorys are private
+ *    to the udata implementation, and are never seen directly by users.
+ *
+ *    The UDataMemory objects returned to users will have the address of some desired
+ *    data within the mapped region, but they wont have the mapping info itself, and thus
+ *    won't cause anything to be removed from memory when they are closed.
+ *
+ *  For individual data files, the UDataMemory returned to the user holds the
+ *  information necessary to unmap the data on close.  If the user independently
+ *  opens the same data file twice, two completely independent mappings will be made.
+ *  (There is no cache of opened data items from individual files, only a cache of
+ *   opened Common Data files, that is, files containing a collection of data items.)
+ *
+ *  For common data passed in from the user via udata_setAppData() or
+ *  udata_setCommonData(), ownership remains with the user.
+ *
+ *  UDataMemory objects themselves, as opposed to the memory they describe,
+ *  can be anywhere - heap, stack/local or global.
+ *  They have a flag to indicate when they're heap allocated and thus
+ *  must be deleted when closed.
+ */
+
+
+/*----------------------------------------------------------------------------*
+ *                                                                            *
+ * main data loading functions                                                *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+static UDataMemory *
+doOpenChoice(const char *path, const char *type, const char *name,
+             UDataMemoryIsAcceptable *isAcceptable, void *context,
+             UErrorCode *pErrorCode)
+{
+    UDataMemory         *retVal = NULL;
+
+    const char         *dataPath;
+
+    int32_t             tocEntrySuffixIndex;
+    const char         *tocEntryPathSuffix;
+    UErrorCode          subErrorCode=U_ZERO_ERROR;
+    const char         *treeChar;
+
+    UBool               isICUData = FALSE;
+
+
+    /* Is this path ICU data? */
+    if(path == NULL ||
+       !strcmp(path, U_ICUDATA_ALIAS) ||  /* "ICUDATA" */
+       !uprv_strncmp(path, U_ICUDATA_NAME U_TREE_SEPARATOR_STRING, /* "icudt26e-" */
+                     uprv_strlen(U_ICUDATA_NAME U_TREE_SEPARATOR_STRING)) ||  
+       !uprv_strncmp(path, U_ICUDATA_ALIAS U_TREE_SEPARATOR_STRING, /* "ICUDATA-" */
+                     uprv_strlen(U_ICUDATA_ALIAS U_TREE_SEPARATOR_STRING))) {
+      isICUData = TRUE;
+    }
+
+#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)  /* Windows:  try "foo\bar" and "foo/bar" */
+    /* remap from alternate path char to the main one */
+    CharString altSepPath;
+    if(path) {
+        if(uprv_strchr(path,U_FILE_ALT_SEP_CHAR) != NULL) {
+            altSepPath.append(path, *pErrorCode);
+            char *p;
+            while((p=uprv_strchr(altSepPath.data(), U_FILE_ALT_SEP_CHAR))) {
+                *p = U_FILE_SEP_CHAR;
+            }
+#if defined (UDATA_DEBUG)
+            fprintf(stderr, "Changed path from [%s] to [%s]\n", path, altSepPath.s);
+#endif
+            path = altSepPath.data();
+        }
+    }
+#endif
+
+    CharString tocEntryName; /* entry name in tree format. ex:  'icudt28b/coll/ar.res' */
+    CharString tocEntryPath; /* entry name in path format. ex:  'icudt28b\\coll\\ar.res' */
+
+    CharString pkgName;
+    CharString treeName;
+
+    /* ======= Set up strings */
+    if(path==NULL) {
+        pkgName.append(U_ICUDATA_NAME, *pErrorCode);
+    } else {
+        const char *pkg;
+        const char *first;
+        pkg = uprv_strrchr(path, U_FILE_SEP_CHAR);
+        first = uprv_strchr(path, U_FILE_SEP_CHAR);
+        if(uprv_pathIsAbsolute(path) || (pkg != first)) { /* more than one slash in the path- not a tree name */
+            /* see if this is an /absolute/path/to/package  path */
+            if(pkg) {
+                pkgName.append(pkg+1, *pErrorCode);
+            } else {
+                pkgName.append(path, *pErrorCode);
+            }
+        } else {
+            treeChar = uprv_strchr(path, U_TREE_SEPARATOR);
+            if(treeChar) { 
+                treeName.append(treeChar+1, *pErrorCode); /* following '-' */
+                if(isICUData) {
+                    pkgName.append(U_ICUDATA_NAME, *pErrorCode);
+                } else {
+                    pkgName.append(path, (int32_t)(treeChar-path), *pErrorCode);
+                    if (first == NULL) {
+                        /*
+                        This user data has no path, but there is a tree name.
+                        Look up the correct path from the data cache later.
+                        */
+                        path = pkgName.data();
+                    }
+                }
+            } else {
+                if(isICUData) {
+                    pkgName.append(U_ICUDATA_NAME, *pErrorCode);
+                } else {
+                    pkgName.append(path, *pErrorCode);
+                }
+            }
+        }
+    }
+
+#ifdef UDATA_DEBUG
+    fprintf(stderr, " P=%s T=%s\n", pkgName.data(), treeName.data());
+#endif
+
+    /* setting up the entry name and file name 
+     * Make up a full name by appending the type to the supplied
+     *  name, assuming that a type was supplied.
+     */
+
+    /* prepend the package */
+    tocEntryName.append(pkgName, *pErrorCode);
+    tocEntryPath.append(pkgName, *pErrorCode);
+    tocEntrySuffixIndex = tocEntryName.length();
+
+    if(!treeName.isEmpty()) {
+        tocEntryName.append(U_TREE_ENTRY_SEP_CHAR, *pErrorCode).append(treeName, *pErrorCode);
+        tocEntryPath.append(U_FILE_SEP_CHAR, *pErrorCode).append(treeName, *pErrorCode);
+    }
+
+    tocEntryName.append(U_TREE_ENTRY_SEP_CHAR, *pErrorCode).append(name, *pErrorCode);
+    tocEntryPath.append(U_FILE_SEP_CHAR, *pErrorCode).append(name, *pErrorCode);
+    if(type!=NULL && *type!=0) {
+        tocEntryName.append(".", *pErrorCode).append(type, *pErrorCode);
+        tocEntryPath.append(".", *pErrorCode).append(type, *pErrorCode);
+    }
+    tocEntryPathSuffix = tocEntryPath.data()+tocEntrySuffixIndex; /* suffix starts here */
+
+#ifdef UDATA_DEBUG
+    fprintf(stderr, " tocEntryName = %s\n", tocEntryName.data());
+    fprintf(stderr, " tocEntryPath = %s\n", tocEntryName.data());
+#endif
+
+    if(path == NULL) {
+        path = COMMON_DATA_NAME; /* "icudt26e" */
+    }
+
+    /************************ Begin loop looking for ind. files ***************/
+#ifdef UDATA_DEBUG
+    fprintf(stderr, "IND: inBasename = %s, pkg=%s\n", "(n/a)", packageNameFromPath(path));
+#endif
+
+    /* End of dealing with a null basename */
+    dataPath = u_getDataDirectory();
+
+    /****    COMMON PACKAGE  - only if packages are first. */
+    if(gDataFileAccess == UDATA_PACKAGES_FIRST) {
+#ifdef UDATA_DEBUG
+        fprintf(stderr, "Trying packages (UDATA_PACKAGES_FIRST)\n");
+#endif
+        /* #2 */
+        retVal = doLoadFromCommonData(isICUData, 
+                            pkgName.data(), dataPath, tocEntryPathSuffix, tocEntryName.data(),
+                            path, type, name, isAcceptable, context, &subErrorCode, pErrorCode);
+        if((retVal != NULL) || U_FAILURE(*pErrorCode)) {
+            return retVal;
+        }
+    }
+
+    /****    INDIVIDUAL FILES  */
+    if((gDataFileAccess==UDATA_PACKAGES_FIRST) ||
+       (gDataFileAccess==UDATA_FILES_FIRST)) {
+#ifdef UDATA_DEBUG
+        fprintf(stderr, "Trying individual files\n");
+#endif
+        /* Check to make sure that there is a dataPath to iterate over */
+        if ((dataPath && *dataPath) || !isICUData) {
+            retVal = doLoadFromIndividualFiles(pkgName.data(), dataPath, tocEntryPathSuffix,
+                            path, type, name, isAcceptable, context, &subErrorCode, pErrorCode);
+            if((retVal != NULL) || U_FAILURE(*pErrorCode)) {
+                return retVal;
+            }
+        }
+    }
+
+    /****    COMMON PACKAGE  */
+    if((gDataFileAccess==UDATA_ONLY_PACKAGES) || 
+       (gDataFileAccess==UDATA_FILES_FIRST)) {
+#ifdef UDATA_DEBUG
+        fprintf(stderr, "Trying packages (UDATA_ONLY_PACKAGES || UDATA_FILES_FIRST)\n");
+#endif
+        retVal = doLoadFromCommonData(isICUData,
+                            pkgName.data(), dataPath, tocEntryPathSuffix, tocEntryName.data(),
+                            path, type, name, isAcceptable, context, &subErrorCode, pErrorCode);
+        if((retVal != NULL) || U_FAILURE(*pErrorCode)) {
+            return retVal;
+        }
+    }
+    
+    /* Load from DLL.  If we haven't attempted package load, we also haven't had any chance to
+        try a DLL (static or setCommonData/etc)  load.
+         If we ever have a "UDATA_ONLY_FILES", add it to the or list here.  */  
+    if(gDataFileAccess==UDATA_NO_FILES) {
+#ifdef UDATA_DEBUG
+        fprintf(stderr, "Trying common data (UDATA_NO_FILES)\n");
+#endif
+        retVal = doLoadFromCommonData(isICUData,
+                            pkgName.data(), "", tocEntryPathSuffix, tocEntryName.data(),
+                            path, type, name, isAcceptable, context, &subErrorCode, pErrorCode);
+        if((retVal != NULL) || U_FAILURE(*pErrorCode)) {
+            return retVal;
+        }
+    }
+
+    /* data not found */
+    if(U_SUCCESS(*pErrorCode)) {
+        if(U_SUCCESS(subErrorCode)) {
+            /* file not found */
+            *pErrorCode=U_FILE_ACCESS_ERROR;
+        } else {
+            /* entry point not found or rejected */
+            *pErrorCode=subErrorCode;
+        }
+    }
+    return retVal;
+}
+
+
+
+/* API ---------------------------------------------------------------------- */
+
+U_CAPI UDataMemory * U_EXPORT2
+udata_open(const char *path, const char *type, const char *name,
+           UErrorCode *pErrorCode) {
+#ifdef UDATA_DEBUG
+  fprintf(stderr, "udata_open(): Opening: %s : %s . %s\n", (path?path:"NULL"), name, type);
+    fflush(stderr);
+#endif
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return NULL;
+    } else if(name==NULL || *name==0) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    } else {
+        return doOpenChoice(path, type, name, NULL, NULL, pErrorCode);
+    }
+}
+
+
+
+U_CAPI UDataMemory * U_EXPORT2
+udata_openChoice(const char *path, const char *type, const char *name,
+                 UDataMemoryIsAcceptable *isAcceptable, void *context,
+                 UErrorCode *pErrorCode) {
+#ifdef UDATA_DEBUG
+  fprintf(stderr, "udata_openChoice(): Opening: %s : %s . %s\n", (path?path:"NULL"), name, type);
+#endif
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return NULL;
+    } else if(name==NULL || *name==0 || isAcceptable==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    } else {
+        return doOpenChoice(path, type, name, isAcceptable, context, pErrorCode);
+    }
+}
+
+
+
+U_CAPI void U_EXPORT2
+udata_getInfo(UDataMemory *pData, UDataInfo *pInfo) {
+    if(pInfo!=NULL) {
+        if(pData!=NULL && pData->pHeader!=NULL) {
+            const UDataInfo *info=&pData->pHeader->info;
+            uint16_t dataInfoSize=udata_getInfoSize(info);
+            if(pInfo->size>dataInfoSize) {
+                pInfo->size=dataInfoSize;
+            }
+            uprv_memcpy((uint16_t *)pInfo+1, (const uint16_t *)info+1, pInfo->size-2);
+            if(info->isBigEndian!=U_IS_BIG_ENDIAN) {
+                /* opposite endianness */
+                uint16_t x=info->reservedWord;
+                pInfo->reservedWord=(uint16_t)((x<<8)|(x>>8));
+            }
+        } else {
+            pInfo->size=0;
+        }
+    }
+}
+
+
+U_CAPI void U_EXPORT2 udata_setFileAccess(UDataFileAccess access, UErrorCode * /*status*/)
+{
+    gDataFileAccess = access;
+}
diff --git a/source/common/udatamem.c b/source/common/udatamem.c
new file mode 100644
index 0000000..2c9741e
--- /dev/null
+++ b/source/common/udatamem.c
@@ -0,0 +1,159 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************/
+
+
+/*----------------------------------------------------------------------------------
+ *
+ *  UDataMemory     A class-like struct that serves as a handle to a piece of memory
+ *                  that contains some ICU data (resource, converters, whatever.)
+ *
+ *                  When an application opens ICU data (with udata_open, for example,
+ *                  a UDataMemory * is returned.
+ *
+ *----------------------------------------------------------------------------------*/
+
+#include "unicode/utypes.h"
+#include "cmemory.h"
+#include "unicode/udata.h"
+
+#include "udatamem.h"
+
+U_CFUNC void UDataMemory_init(UDataMemory *This) {
+    uprv_memset(This, 0, sizeof(UDataMemory));
+    This->length=-1;
+}
+
+
+U_CFUNC void UDatamemory_assign(UDataMemory *dest, UDataMemory *source) {
+    /* UDataMemory Assignment.  Destination UDataMemory must be initialized first.  */
+    UBool mallocedFlag = dest->heapAllocated;
+    uprv_memcpy(dest, source, sizeof(UDataMemory));
+    dest->heapAllocated = mallocedFlag;
+}
+
+U_CFUNC UDataMemory *UDataMemory_createNewInstance(UErrorCode *pErr) {
+    UDataMemory *This;
+
+    if (U_FAILURE(*pErr)) {
+        return NULL;
+    }
+    This = uprv_malloc(sizeof(UDataMemory));
+    if (This == NULL) {
+        *pErr = U_MEMORY_ALLOCATION_ERROR; }
+    else {
+        UDataMemory_init(This);
+        This->heapAllocated = TRUE;
+    }
+    return This;
+}
+
+
+U_CFUNC const DataHeader *
+UDataMemory_normalizeDataPointer(const void *p) {
+    /* allow the data to be optionally prepended with an alignment-forcing double value */
+    const DataHeader *pdh = (const DataHeader *)p;
+    if(pdh==NULL || (pdh->dataHeader.magic1==0xda && pdh->dataHeader.magic2==0x27)) {
+        return pdh;
+    } else {
+#ifdef OS400
+        /*
+        TODO: Fix this once the compiler implements this feature. Keep in sync with genccode.c
+
+        This is here because this platform can't currently put
+        const data into the read-only pages of an object or
+        shared library (service program). Only strings are allowed in read-only
+        pages, so we use char * strings to store the data.
+
+        In order to prevent the beginning of the data from ever matching the
+        magic numbers we must skip the initial double.
+        [grhoten 4/24/2003]
+        */
+        return (const DataHeader *)*((const void **)p+1);
+#else
+        return (const DataHeader *)((const double *)p+1);
+#endif
+    }
+}
+
+
+U_CFUNC void UDataMemory_setData (UDataMemory *This, const void *dataAddr) {
+    This->pHeader = UDataMemory_normalizeDataPointer(dataAddr);
+}
+
+
+U_CAPI void U_EXPORT2
+udata_close(UDataMemory *pData) {
+    if(pData!=NULL) {
+        uprv_unmapFile(pData);
+        if(pData->heapAllocated ) {
+            uprv_free(pData);
+        } else {
+            UDataMemory_init(pData);
+        }
+    }
+}
+
+U_CAPI const void * U_EXPORT2
+udata_getMemory(UDataMemory *pData) {
+    if(pData!=NULL && pData->pHeader!=NULL) {
+        return (char *)(pData->pHeader)+udata_getHeaderSize(pData->pHeader);
+    } else {
+        return NULL;
+    }
+}
+
+/**
+ * Get the length of the data item if possible.
+ * The length may be up to 15 bytes larger than the actual data.
+ *
+ * TODO Consider making this function public.
+ * It would have to return the actual length in more cases.
+ * For example, the length of the last item in a .dat package could be
+ * computed from the size of the whole .dat package minus the offset of the
+ * last item.
+ * The size of a file that was directly memory-mapped could be determined
+ * using some system API.
+ *
+ * In order to get perfect values for all data items, we may have to add a
+ * length field to UDataInfo, but that complicates data generation
+ * and may be overkill.
+ *
+ * @param pData The data item.
+ * @return the length of the data item, or -1 if not known
+ * @internal Currently used only in cintltst/udatatst.c
+ */
+U_CAPI int32_t U_EXPORT2
+udata_getLength(const UDataMemory *pData) {
+    if(pData!=NULL && pData->pHeader!=NULL && pData->length>=0) {
+        /*
+         * subtract the header size,
+         * return only the size of the actual data starting at udata_getMemory()
+         */
+        return pData->length-udata_getHeaderSize(pData->pHeader);
+    } else {
+        return -1;
+    }
+}
+
+/**
+ * Get the memory including the data header.
+ * Used in cintltst/udatatst.c
+ * @internal
+ */
+U_CAPI const void * U_EXPORT2
+udata_getRawMemory(const UDataMemory *pData) {
+    if(pData!=NULL && pData->pHeader!=NULL) {
+        return pData->pHeader;
+    } else {
+        return NULL;
+    }
+}
+
+U_CFUNC UBool UDataMemory_isLoaded(const UDataMemory *This) {
+    return This->pHeader != NULL;
+}
diff --git a/source/common/udatamem.h b/source/common/udatamem.h
new file mode 100644
index 0000000..5137285
--- /dev/null
+++ b/source/common/udatamem.h
@@ -0,0 +1,59 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************/
+
+
+/*----------------------------------------------------------------------------------
+ *
+ *  UDataMemory     A class-like struct that serves as a handle to a piece of memory
+ *                  that contains some ICU data (resource, converters, whatever.)
+ *
+ *                  When an application opens ICU data (with udata_open, for example,
+ *                  a UDataMemory * is returned.
+ *
+ *----------------------------------------------------------------------------------*/
+#ifndef __UDATAMEM_H__
+#define __UDATAMEM_H__
+
+#include "unicode/udata.h"
+#include "ucmndata.h"
+
+struct UDataMemory {
+    const commonDataFuncs  *vFuncs;      /* Function Pointers for accessing TOC             */
+
+    const DataHeader *pHeader;     /* Header of the memory being described by this    */
+                                   /*   UDataMemory object.                           */
+    const void       *toc;         /* For common memory, table of contents for        */
+                                   /*   the pieces within.                            */
+    UBool             heapAllocated;  /* True if this UDataMemory Object is on the    */
+                                   /*  heap and thus needs to be deleted when closed. */
+
+    void             *mapAddr;     /* For mapped or allocated memory, the start addr. */
+                                   /* Only non-null if a close operation should unmap */
+                                   /*  the associated data.                           */
+    void             *map;         /* Handle, or other data, OS dependent.            */
+                                   /* Only non-null if a close operation should unmap */
+                                   /*  the associated data, and additional info       */
+                                   /*   beyond the mapAddr is needed to do that.      */
+    int32_t           length;      /* Length of the data in bytes; -1 if unknown.     */
+};
+
+U_CFUNC UDataMemory *UDataMemory_createNewInstance(UErrorCode *pErr);
+U_CFUNC void         UDatamemory_assign  (UDataMemory *dest, UDataMemory *source);
+U_CFUNC void         UDataMemory_init    (UDataMemory *This);
+U_CFUNC UBool        UDataMemory_isLoaded(const UDataMemory *This);
+U_CFUNC void         UDataMemory_setData (UDataMemory *This, const void *dataAddr);
+
+U_CFUNC const DataHeader *UDataMemory_normalizeDataPointer(const void *p);
+
+U_CAPI int32_t U_EXPORT2
+udata_getLength(const UDataMemory *pData);
+
+U_CAPI const void * U_EXPORT2
+udata_getRawMemory(const UDataMemory *pData);
+
+#endif
diff --git a/source/common/udataswp.c b/source/common/udataswp.c
new file mode 100644
index 0000000..cacf716
--- /dev/null
+++ b/source/common/udataswp.c
@@ -0,0 +1,415 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2003, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  udataswp.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2003jun05
+*   created by: Markus W. Scherer
+*
+*   Definitions for ICU data transformations for different platforms,
+*   changing between big- and little-endian data and/or between
+*   charset families (ASCII<->EBCDIC).
+*/
+
+#include <stdarg.h>
+#include "unicode/utypes.h"
+#include "unicode/udata.h" /* UDataInfo */
+#include "ucmndata.h" /* DataHeader */
+#include "cmemory.h"
+#include "udataswp.h"
+
+/* swapping primitives ------------------------------------------------------ */
+
+static int32_t U_CALLCONV
+uprv_swapArray16(const UDataSwapper *ds,
+                 const void *inData, int32_t length, void *outData,
+                 UErrorCode *pErrorCode) {
+    const uint16_t *p;
+    uint16_t *q;
+    int32_t count;
+    uint16_t x;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(ds==NULL || inData==NULL || length<0 || (length&1)!=0 || outData==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* setup and swapping */
+    p=(const uint16_t *)inData;
+    q=(uint16_t *)outData;
+    count=length/2;
+    while(count>0) {
+        x=*p++;
+        *q++=(uint16_t)((x<<8)|(x>>8));
+        --count;
+    }
+
+    return length;
+}
+
+static int32_t U_CALLCONV
+uprv_copyArray16(const UDataSwapper *ds,
+                 const void *inData, int32_t length, void *outData,
+                 UErrorCode *pErrorCode) {
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(ds==NULL || inData==NULL || length<0 || (length&1)!=0 || outData==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    if(length>0 && inData!=outData) {
+        uprv_memcpy(outData, inData, length);
+    }
+    return length;
+}
+
+static int32_t U_CALLCONV
+uprv_swapArray32(const UDataSwapper *ds,
+                 const void *inData, int32_t length, void *outData,
+                 UErrorCode *pErrorCode) {
+    const uint32_t *p;
+    uint32_t *q;
+    int32_t count;
+    uint32_t x;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(ds==NULL || inData==NULL || length<0 || (length&3)!=0 || outData==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* setup and swapping */
+    p=(const uint32_t *)inData;
+    q=(uint32_t *)outData;
+    count=length/4;
+    while(count>0) {
+        x=*p++;
+        *q++=(uint32_t)((x<<24)|((x<<8)&0xff0000)|((x>>8)&0xff00)|(x>>24));
+        --count;
+    }
+
+    return length;
+}
+
+static int32_t U_CALLCONV
+uprv_copyArray32(const UDataSwapper *ds,
+                 const void *inData, int32_t length, void *outData,
+                 UErrorCode *pErrorCode) {
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(ds==NULL || inData==NULL || length<0 || (length&3)!=0 || outData==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    if(length>0 && inData!=outData) {
+        uprv_memcpy(outData, inData, length);
+    }
+    return length;
+}
+
+static uint16_t U_CALLCONV
+uprv_readSwapUInt16(uint16_t x) {
+    return (uint16_t)((x<<8)|(x>>8));
+}
+
+static uint16_t U_CALLCONV
+uprv_readDirectUInt16(uint16_t x) {
+    return x;
+}
+
+static uint32_t U_CALLCONV
+uprv_readSwapUInt32(uint32_t x) {
+    return (uint32_t)((x<<24)|((x<<8)&0xff0000)|((x>>8)&0xff00)|(x>>24));
+}
+
+static uint32_t U_CALLCONV
+uprv_readDirectUInt32(uint32_t x) {
+    return x;
+}
+
+static void U_CALLCONV
+uprv_writeSwapUInt16(uint16_t *p, uint16_t x) {
+    *p=(uint16_t)((x<<8)|(x>>8));
+}
+
+static void U_CALLCONV
+uprv_writeDirectUInt16(uint16_t *p, uint16_t x) {
+    *p=x;
+}
+
+static void U_CALLCONV
+uprv_writeSwapUInt32(uint32_t *p, uint32_t x) {
+    *p=(uint32_t)((x<<24)|((x<<8)&0xff0000)|((x>>8)&0xff00)|(x>>24));
+}
+
+static void U_CALLCONV
+uprv_writeDirectUInt32(uint32_t *p, uint32_t x) {
+    *p=x;
+}
+
+U_CAPI int16_t U_EXPORT2
+udata_readInt16(const UDataSwapper *ds, int16_t x) {
+    return (int16_t)ds->readUInt16((uint16_t)x);
+}
+
+U_CAPI int32_t U_EXPORT2
+udata_readInt32(const UDataSwapper *ds, int32_t x) {
+    return (int32_t)ds->readUInt32((uint32_t)x);
+}
+
+/**
+ * Swap a block of invariant, NUL-terminated strings, but not padding
+ * bytes after the last string.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+udata_swapInvStringBlock(const UDataSwapper *ds,
+                         const void *inData, int32_t length, void *outData,
+                         UErrorCode *pErrorCode) {
+    const char *inChars;
+    int32_t stringsLength;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(ds==NULL || inData==NULL || length<0 || (length>0 && outData==NULL)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* reduce the strings length to not include bytes after the last NUL */
+    inChars=(const char *)inData;
+    stringsLength=length;
+    while(stringsLength>0 && inChars[stringsLength-1]!=0) {
+        --stringsLength;
+    }
+
+    /* swap up to the last NUL */
+    ds->swapInvChars(ds, inData, stringsLength, outData, pErrorCode);
+
+    /* copy the bytes after the last NUL */
+    if(inData!=outData && length>stringsLength) {
+        uprv_memcpy((char *)outData+stringsLength, inChars+stringsLength, length-stringsLength);
+    }
+
+    /* return the length including padding bytes */
+    if(U_SUCCESS(*pErrorCode)) {
+        return length;
+    } else {
+        return 0;
+    }
+}
+
+U_CAPI void U_EXPORT2
+udata_printError(const UDataSwapper *ds,
+                 const char *fmt,
+                 ...) {
+    va_list args;
+
+    if(ds->printError!=NULL) {
+        va_start(args, fmt);
+        ds->printError(ds->printErrorContext, fmt, args);
+        va_end(args);
+    }
+}
+
+/* swap a data header ------------------------------------------------------- */
+
+U_CAPI int32_t U_EXPORT2
+udata_swapDataHeader(const UDataSwapper *ds,
+                     const void *inData, int32_t length, void *outData,
+                     UErrorCode *pErrorCode) {
+    const DataHeader *pHeader;
+    uint16_t headerSize, infoSize;
+
+    /* argument checking */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(ds==NULL || inData==NULL || length<-1 || (length>0 && outData==NULL)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* check minimum length and magic bytes */
+    pHeader=(const DataHeader *)inData;
+    if( (length>=0 && length<sizeof(DataHeader)) ||
+        pHeader->dataHeader.magic1!=0xda ||
+        pHeader->dataHeader.magic2!=0x27 ||
+        pHeader->info.sizeofUChar!=2
+    ) {
+        udata_printError(ds, "udata_swapDataHeader(): initial bytes do not look like ICU data\n");
+        *pErrorCode=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    headerSize=ds->readUInt16(pHeader->dataHeader.headerSize);
+    infoSize=ds->readUInt16(pHeader->info.size);
+
+    if( headerSize<sizeof(DataHeader) ||
+        infoSize<sizeof(UDataInfo) ||
+        headerSize<(sizeof(pHeader->dataHeader)+infoSize) ||
+        (length>=0 && length<headerSize)
+    ) {
+        udata_printError(ds, "udata_swapDataHeader(): header size mismatch - headerSize %d infoSize %d length %d\n",
+                         headerSize, infoSize, length);
+        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0;
+    }
+
+    if(length>0) {
+        DataHeader *outHeader;
+        const char *s;
+        int32_t maxLength;
+
+        /* Most of the fields are just bytes and need no swapping. */
+        if(inData!=outData) {
+            uprv_memcpy(outData, inData, headerSize);
+        }
+        outHeader=(DataHeader *)outData;
+
+        outHeader->info.isBigEndian = ds->outIsBigEndian;
+        outHeader->info.charsetFamily = ds->outCharset;
+
+        /* swap headerSize */
+        ds->swapArray16(ds, &pHeader->dataHeader.headerSize, 2, &outHeader->dataHeader.headerSize, pErrorCode);
+
+        /* swap UDataInfo size and reservedWord */
+        ds->swapArray16(ds, &pHeader->info.size, 4, &outHeader->info.size, pErrorCode);
+
+        /* swap copyright statement after the UDataInfo */
+        infoSize+=sizeof(pHeader->dataHeader);
+        s=(const char *)inData+infoSize;
+        maxLength=headerSize-infoSize;
+        /* get the length of the string */
+        for(length=0; length<maxLength && s[length]!=0; ++length) {}
+        /* swap the string contents */
+        ds->swapInvChars(ds, s, length, (char *)outData+infoSize, pErrorCode);
+    }
+
+    return headerSize;
+}
+
+/* API functions ------------------------------------------------------------ */
+
+U_CAPI UDataSwapper * U_EXPORT2
+udata_openSwapper(UBool inIsBigEndian, uint8_t inCharset,
+                  UBool outIsBigEndian, uint8_t outCharset,
+                  UErrorCode *pErrorCode) {
+    UDataSwapper *swapper;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return NULL;
+    }
+    if(inCharset>U_EBCDIC_FAMILY || outCharset>U_EBCDIC_FAMILY) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    /* allocate the swapper */
+    swapper=uprv_malloc(sizeof(UDataSwapper));
+    if(swapper==NULL) {
+        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    uprv_memset(swapper, 0, sizeof(UDataSwapper));
+
+    /* set values and functions pointers according to in/out parameters */
+    swapper->inIsBigEndian=inIsBigEndian;
+    swapper->inCharset=inCharset;
+    swapper->outIsBigEndian=outIsBigEndian;
+    swapper->outCharset=outCharset;
+
+    swapper->readUInt16= inIsBigEndian==U_IS_BIG_ENDIAN ? uprv_readDirectUInt16 : uprv_readSwapUInt16;
+    swapper->readUInt32= inIsBigEndian==U_IS_BIG_ENDIAN ? uprv_readDirectUInt32 : uprv_readSwapUInt32;
+
+    swapper->writeUInt16= outIsBigEndian==U_IS_BIG_ENDIAN ? uprv_writeDirectUInt16 : uprv_writeSwapUInt16;
+    swapper->writeUInt32= outIsBigEndian==U_IS_BIG_ENDIAN ? uprv_writeDirectUInt32 : uprv_writeSwapUInt32;
+
+    swapper->compareInvChars= outCharset==U_ASCII_FAMILY ? uprv_compareInvAscii : uprv_compareInvEbcdic;
+
+    swapper->swapArray16= inIsBigEndian==outIsBigEndian ? uprv_copyArray16 : uprv_swapArray16;
+    swapper->swapArray32= inIsBigEndian==outIsBigEndian ? uprv_copyArray32 : uprv_swapArray32;
+
+    if(inCharset==U_ASCII_FAMILY) {
+        swapper->swapInvChars= outCharset==U_ASCII_FAMILY ? uprv_copyAscii : uprv_ebcdicFromAscii;
+    } else /* U_EBCDIC_FAMILY */ {
+        swapper->swapInvChars= outCharset==U_EBCDIC_FAMILY ? uprv_copyEbcdic : uprv_asciiFromEbcdic;
+    }
+
+    return swapper;
+}
+
+U_CAPI UDataSwapper * U_EXPORT2
+udata_openSwapperForInputData(const void *data, int32_t length,
+                              UBool outIsBigEndian, uint8_t outCharset,
+                              UErrorCode *pErrorCode) {
+    const DataHeader *pHeader;
+    uint16_t headerSize, infoSize;
+    UBool inIsBigEndian;
+    int8_t inCharset;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return NULL;
+    }
+    if( data==NULL ||
+        (length>=0 && length<sizeof(DataHeader)) ||
+        outCharset>U_EBCDIC_FAMILY
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    pHeader=(const DataHeader *)data;
+    if( (length>=0 && length<sizeof(DataHeader)) ||
+        pHeader->dataHeader.magic1!=0xda ||
+        pHeader->dataHeader.magic2!=0x27 ||
+        pHeader->info.sizeofUChar!=2
+    ) {
+        *pErrorCode=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    inIsBigEndian=(UBool)pHeader->info.isBigEndian;
+    inCharset=pHeader->info.charsetFamily;
+
+    if(inIsBigEndian==U_IS_BIG_ENDIAN) {
+        headerSize=pHeader->dataHeader.headerSize;
+        infoSize=pHeader->info.size;
+    } else {
+        headerSize=uprv_readSwapUInt16(pHeader->dataHeader.headerSize);
+        infoSize=uprv_readSwapUInt16(pHeader->info.size);
+    }
+
+    if( headerSize<sizeof(DataHeader) ||
+        infoSize<sizeof(UDataInfo) ||
+        headerSize<(sizeof(pHeader->dataHeader)+infoSize) ||
+        (length>=0 && length<headerSize)
+    ) {
+        *pErrorCode=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    return udata_openSwapper(inIsBigEndian, inCharset, outIsBigEndian, outCharset, pErrorCode);
+}
+
+U_CAPI void U_EXPORT2
+udata_closeSwapper(UDataSwapper *ds) {
+    uprv_free(ds);
+}
diff --git a/source/common/udataswp.h b/source/common/udataswp.h
new file mode 100644
index 0000000..52b99aa
--- /dev/null
+++ b/source/common/udataswp.h
@@ -0,0 +1,349 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2003-2005, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  udataswp.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2003jun05
+*   created by: Markus W. Scherer
+*
+*   Definitions for ICU data transformations for different platforms,
+*   changing between big- and little-endian data and/or between
+*   charset families (ASCII<->EBCDIC).
+*/
+
+#ifndef __UDATASWP_H__
+#define __UDATASWP_H__
+
+#include <stdarg.h>
+#include "unicode/utypes.h"
+
+/* forward declaration */
+
+U_CDECL_BEGIN
+
+struct UDataSwapper;
+typedef struct UDataSwapper UDataSwapper;
+
+/**
+ * Function type for data transformation.
+ * Transforms data, or just returns the length of the data if
+ * the input length is -1.
+ * Swap functions assume that their data pointers are aligned properly.
+ *
+ * Quick implementation outline:
+ * (best to copy and adapt and existing swapper implementation)
+ * check that the data looks like the expected format
+ * if(length<0) {
+ *   preflight:
+ *   never dereference outData
+ *   read inData and determine the data size
+ *   assume that inData is long enough for this
+ * } else {
+ *   outData can be NULL if length==0
+ *   inData==outData (in-place swapping) possible but not required!
+ *   verify that length>=(actual size)
+ *   if there is a chance that not every byte up to size is reached
+ *     due to padding etc.:
+ *   if(inData!=outData) {
+ *     memcpy(outData, inData, actual size);
+ *   }
+ *   swap contents
+ * }
+ * return actual size
+ *
+ * Further implementation notes:
+ * - read integers from inData before swapping them
+ *   because in-place swapping can make them unreadable
+ * - compareInvChars compares a local Unicode string with already-swapped
+ *   output charset strings
+ *
+ * @param ds Pointer to UDataSwapper containing global data about the
+ *           transformation and function pointers for handling primitive
+ *           types.
+ * @param inData Pointer to the input data to be transformed or examined.
+ * @param length Length of the data, counting bytes. May be -1 for preflighting.
+ *               If length>=0, then transform the data.
+ *               If length==-1, then only determine the length of the data.
+ *               The length cannot be determined from the data itself for all
+ *               types of data (e.g., not for simple arrays of integers).
+ * @param outData Pointer to the output data buffer.
+ *                If length>=0 (transformation), then the output buffer must
+ *                have a capacity of at least length.
+ *                If length==-1, then outData will not be used and can be NULL.
+ * @param pErrorCode ICU UErrorCode parameter, must not be NULL and must
+ *                   fulfill U_SUCCESS on input.
+ * @return The actual length of the data.
+ *
+ * @see UDataSwapper
+ * @internal ICU 2.8
+ */
+typedef int32_t U_CALLCONV
+UDataSwapFn(const UDataSwapper *ds,
+            const void *inData, int32_t length, void *outData,
+            UErrorCode *pErrorCode);
+
+/**
+ * Convert one uint16_t from input to platform endianness.
+ * @internal ICU 2.8
+ */
+typedef uint16_t U_CALLCONV
+UDataReadUInt16(uint16_t x);
+
+/**
+ * Convert one uint32_t from input to platform endianness.
+ * @internal ICU 2.8
+ */
+typedef uint32_t U_CALLCONV
+UDataReadUInt32(uint32_t x);
+
+/**
+ * Convert one uint16_t from platform to input endianness.
+ * @internal ICU 2.8
+ */
+typedef void U_CALLCONV
+UDataWriteUInt16(uint16_t *p, uint16_t x);
+
+/**
+ * Convert one uint32_t from platform to input endianness.
+ * @internal ICU 2.8
+ */
+typedef void U_CALLCONV
+UDataWriteUInt32(uint32_t *p, uint32_t x);
+
+/**
+ * Compare invariant-character strings, one in the output data and the
+ * other one caller-provided in Unicode.
+ * An output data string is compared because strings are usually swapped
+ * before the rest of the data, to allow for sorting of string tables
+ * according to the output charset.
+ * You can use -1 for the length parameters of NUL-terminated strings as usual.
+ * Returns Unicode code point order for invariant characters.
+ * @internal ICU 2.8
+ */
+typedef int32_t U_CALLCONV
+UDataCompareInvChars(const UDataSwapper *ds,
+                     const char *outString, int32_t outLength,
+                     const UChar *localString, int32_t localLength);
+
+/**
+ * Function for message output when an error occurs during data swapping.
+ * A format string and variable number of arguments are passed
+ * like for vprintf().
+ *
+ * @param context A function-specific context pointer.
+ * @param fmt The format string.
+ * @param args The arguments for format string inserts.
+ *
+ * @internal ICU 2.8
+ */
+typedef void U_CALLCONV
+UDataPrintError(void *context, const char *fmt, va_list args);
+
+struct UDataSwapper {
+    /** Input endianness. @internal ICU 2.8 */
+    UBool inIsBigEndian;
+    /** Input charset family. @see U_CHARSET_FAMILY @internal ICU 2.8 */
+    uint8_t inCharset;
+    /** Output endianness. @internal ICU 2.8 */
+    UBool outIsBigEndian;
+    /** Output charset family. @see U_CHARSET_FAMILY @internal ICU 2.8 */
+    uint8_t outCharset;
+
+    /* basic functions for reading data values */
+
+    /** Convert one uint16_t from input to platform endianness. @internal ICU 2.8 */
+    UDataReadUInt16 *readUInt16;
+    /** Convert one uint32_t from input to platform endianness. @internal ICU 2.8 */
+    UDataReadUInt32 *readUInt32;
+    /** Compare an invariant-character output string with a local one. @internal ICU 2.8 */
+    UDataCompareInvChars *compareInvChars;
+
+    /* basic functions for writing data values */
+
+    /** Convert one uint16_t from platform to input endianness. @internal ICU 2.8 */
+    UDataWriteUInt16 *writeUInt16;
+    /** Convert one uint32_t from platform to input endianness. @internal ICU 2.8 */
+    UDataWriteUInt32 *writeUInt32;
+
+    /* basic functions for data transformations */
+
+    /** Transform an array of 16-bit integers. @internal ICU 2.8 */
+    UDataSwapFn *swapArray16;
+    /** Transform an array of 32-bit integers. @internal ICU 2.8 */
+    UDataSwapFn *swapArray32;
+    /** Transform an invariant-character string. @internal ICU 2.8 */
+    UDataSwapFn *swapInvChars;
+
+    /**
+     * Function for message output when an error occurs during data swapping.
+     * Can be NULL.
+     * @internal ICU 2.8
+     */
+    UDataPrintError *printError;
+    /** Context pointer for printError. @internal ICU 2.8 */
+    void *printErrorContext;
+};
+
+U_CDECL_END
+
+U_CAPI UDataSwapper * U_EXPORT2
+udata_openSwapper(UBool inIsBigEndian, uint8_t inCharset,
+                  UBool outIsBigEndian, uint8_t outCharset,
+                  UErrorCode *pErrorCode);
+
+/**
+ * Open a UDataSwapper for the given input data and the specified output
+ * characteristics.
+ * Values of -1 for any of the characteristics mean the local platform's
+ * characteristics.
+ *
+ * @see udata_swap
+ * @internal ICU 2.8
+ */
+U_CAPI UDataSwapper * U_EXPORT2
+udata_openSwapperForInputData(const void *data, int32_t length,
+                              UBool outIsBigEndian, uint8_t outCharset,
+                              UErrorCode *pErrorCode);
+
+U_CAPI void U_EXPORT2
+udata_closeSwapper(UDataSwapper *ds);
+
+/**
+ * Read the beginning of an ICU data piece, recognize magic bytes,
+ * swap the structure.
+ * Set a U_UNSUPPORTED_ERROR if it does not look like an ICU data piece.
+ *
+ * @return The size of the data header, in bytes.
+ *
+ * @internal ICU 2.8
+ */
+U_CAPI int32_t U_EXPORT2
+udata_swapDataHeader(const UDataSwapper *ds,
+                     const void *inData, int32_t length, void *outData,
+                     UErrorCode *pErrorCode);
+
+/**
+ * Convert one int16_t from input to platform endianness.
+ * @internal ICU 2.8
+ */
+U_CAPI int16_t U_EXPORT2
+udata_readInt16(const UDataSwapper *ds, int16_t x);
+
+/**
+ * Convert one int32_t from input to platform endianness.
+ * @internal ICU 2.8
+ */
+U_CAPI int32_t U_EXPORT2
+udata_readInt32(const UDataSwapper *ds, int32_t x);
+
+/**
+ * Swap a block of invariant, NUL-terminated strings, but not padding
+ * bytes after the last string.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+udata_swapInvStringBlock(const UDataSwapper *ds,
+                         const void *inData, int32_t length, void *outData,
+                         UErrorCode *pErrorCode);
+
+U_CAPI void U_EXPORT2
+udata_printError(const UDataSwapper *ds,
+                 const char *fmt,
+                 ...);
+
+/* internal exports from putil.c -------------------------------------------- */
+
+/* declared here to keep them out of the public putil.h */
+
+/**
+ * Swap invariant char * strings ASCII->EBCDIC.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+uprv_ebcdicFromAscii(const UDataSwapper *ds,
+                     const void *inData, int32_t length, void *outData,
+                     UErrorCode *pErrorCode);
+
+/**
+ * Copy invariant ASCII char * strings and verify they are invariant.
+ * @internal
+ */
+U_CFUNC int32_t
+uprv_copyAscii(const UDataSwapper *ds,
+               const void *inData, int32_t length, void *outData,
+               UErrorCode *pErrorCode);
+
+/**
+ * Swap invariant char * strings EBCDIC->ASCII.
+ * @internal
+ */
+U_CFUNC int32_t
+uprv_asciiFromEbcdic(const UDataSwapper *ds,
+                     const void *inData, int32_t length, void *outData,
+                     UErrorCode *pErrorCode);
+
+/**
+ * Copy invariant EBCDIC char * strings and verify they are invariant.
+ * @internal
+ */
+U_CFUNC int32_t
+uprv_copyEbcdic(const UDataSwapper *ds,
+                const void *inData, int32_t length, void *outData,
+                UErrorCode *pErrorCode);
+
+/**
+ * Compare ASCII invariant char * with Unicode invariant UChar *
+ * @internal
+ */
+U_CFUNC int32_t
+uprv_compareInvAscii(const UDataSwapper *ds,
+                     const char *outString, int32_t outLength,
+                     const UChar *localString, int32_t localLength);
+
+/**
+ * Compare EBCDIC invariant char * with Unicode invariant UChar *
+ * @internal
+ */
+U_CFUNC int32_t
+uprv_compareInvEbcdic(const UDataSwapper *ds,
+                      const char *outString, int32_t outLength,
+                      const UChar *localString, int32_t localLength);
+
+/* material... -------------------------------------------------------------- */
+
+#if 0
+
+/* udata.h */
+
+/**
+ * Public API function in udata.c
+ *
+ * Same as udata_openChoice() but automatically swaps the data.
+ * isAcceptable, if not NULL, may accept data with endianness and charset family
+ * different from the current platform's properties.
+ * If the data is acceptable and the platform properties do not match, then
+ * the swap function is called to swap an allocated version of the data.
+ * Preflighting may or may not be performed depending on whether the size of
+ * the loaded data item is known.
+ *
+ * @param isAcceptable Same as for udata_openChoice(). May be NULL.
+ *
+ * @internal ICU 2.8
+ */
+U_CAPI UDataMemory * U_EXPORT2
+udata_openSwap(const char *path, const char *type, const char *name,
+               UDataMemoryIsAcceptable *isAcceptable, void *isAcceptableContext,
+               UDataSwapFn *swap,
+               UDataPrintError *printError, void *printErrorContext,
+               UErrorCode *pErrorCode);
+
+#endif
+
+#endif
diff --git a/source/common/uenum.c b/source/common/uenum.c
new file mode 100644
index 0000000..549769c
--- /dev/null
+++ b/source/common/uenum.c
@@ -0,0 +1,181 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2002-2004, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  uenum.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:2
+*
+*   created on: 2002jul08
+*   created by: Vladimir Weinstein
+*/
+
+#include "unicode/putil.h"
+#include "uenumimp.h"
+#include "cmemory.h"
+
+/* Layout of the baseContext buffer. */
+typedef struct {
+    int32_t len;  /* number of bytes available starting at 'data' */
+    char    data; /* actual data starts here */
+} _UEnumBuffer;
+
+/* Extra bytes to allocate in the baseContext buffer. */
+static const int32_t PAD = 8;
+
+/* Return a pointer to the baseContext buffer, possibly allocating
+   or reallocating it if at least 'capacity' bytes are not available. */
+static void* _getBuffer(UEnumeration* en, int32_t capacity) {
+
+    if (en->baseContext != NULL) {
+        if (((_UEnumBuffer*) en->baseContext)->len < capacity) {
+            capacity += PAD;
+            en->baseContext = uprv_realloc(en->baseContext,
+                                           sizeof(int32_t) + capacity);
+            if (en->baseContext == NULL) {
+                return NULL;
+            }
+            ((_UEnumBuffer*) en->baseContext)->len = capacity;
+        }
+    } else {
+        capacity += PAD;
+        en->baseContext = uprv_malloc(sizeof(int32_t) + capacity);
+        if (en->baseContext == NULL) {
+            return NULL;
+        }
+        ((_UEnumBuffer*) en->baseContext)->len = capacity;
+    }
+    
+    return (void*) & ((_UEnumBuffer*) en->baseContext)->data;
+}
+
+U_CAPI void U_EXPORT2
+uenum_close(UEnumeration* en)
+{
+    if (en) {
+        if (en->close != NULL) {
+            if (en->baseContext) {
+                uprv_free(en->baseContext);
+            }
+            en->close(en);
+        } else { /* this seems dangerous, but we better kill the object */
+            uprv_free(en);
+        }
+    }
+}
+
+U_CAPI int32_t U_EXPORT2
+uenum_count(UEnumeration* en, UErrorCode* status)
+{
+    if (!en || U_FAILURE(*status)) {
+        return -1;
+    }
+    if (en->count != NULL) {
+        return en->count(en, status);
+    } else {
+        *status = U_UNSUPPORTED_ERROR;
+        return -1;
+    }
+}
+
+/* Don't call this directly. Only uenum_unext should be calling this. */
+U_CAPI const UChar* U_EXPORT2
+uenum_unextDefault(UEnumeration* en,
+            int32_t* resultLength,
+            UErrorCode* status)
+{
+    UChar *ustr = NULL;
+    int32_t len = 0;
+    if (en->next != NULL) {
+        const char *cstr = en->next(en, &len, status);
+        if (cstr != NULL) {
+            ustr = (UChar*) _getBuffer(en, (len+1) * sizeof(UChar));
+            if (ustr == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+            } else {
+                u_charsToUChars(cstr, ustr, len+1);
+            }
+        }
+    } else {
+        *status = U_UNSUPPORTED_ERROR;
+    }
+    if (resultLength) {
+        *resultLength = len;
+    }
+    return ustr;
+}
+
+/* Don't call this directly. Only uenum_next should be calling this. */
+U_CAPI const char* U_EXPORT2
+uenum_nextDefault(UEnumeration* en,
+            int32_t* resultLength,
+            UErrorCode* status)
+{
+    if (en->uNext != NULL) {
+        char *tempCharVal;
+        const UChar *tempUCharVal = en->uNext(en, resultLength, status);
+        if (tempUCharVal == NULL) {
+            return NULL;
+        }
+        tempCharVal = (char*)
+            _getBuffer(en, (*resultLength+1) * sizeof(char));
+        if (!tempCharVal) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return NULL;
+        }
+        u_UCharsToChars(tempUCharVal, tempCharVal, *resultLength + 1);
+        return tempCharVal;
+    } else {
+        *status = U_UNSUPPORTED_ERROR;
+        return NULL;
+    }
+}
+
+U_CAPI const UChar* U_EXPORT2
+uenum_unext(UEnumeration* en,
+            int32_t* resultLength,
+            UErrorCode* status)
+{
+    if (!en || U_FAILURE(*status)) {
+        return NULL;
+    }
+    if (en->uNext != NULL) {
+        return en->uNext(en, resultLength, status);
+    } else {
+        *status = U_UNSUPPORTED_ERROR;
+        return NULL;
+    }
+}
+
+U_CAPI const char* U_EXPORT2
+uenum_next(UEnumeration* en,
+          int32_t* resultLength,
+          UErrorCode* status)
+{
+    if (!en || U_FAILURE(*status)) {
+        return NULL;
+    }
+    if (en->next != NULL) {
+        return en->next(en, resultLength, status);
+    } else {
+        *status = U_UNSUPPORTED_ERROR;
+        return NULL;
+    }
+}
+
+U_CAPI void U_EXPORT2
+uenum_reset(UEnumeration* en, UErrorCode* status)
+{
+    if (!en || U_FAILURE(*status)) {
+        return;
+    }
+    if (en->reset != NULL) {
+        en->reset(en, status);
+    } else {
+        *status = U_UNSUPPORTED_ERROR;
+    }
+}
diff --git a/source/common/uenumimp.h b/source/common/uenumimp.h
new file mode 100644
index 0000000..664bc68
--- /dev/null
+++ b/source/common/uenumimp.h
@@ -0,0 +1,153 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2002-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  uenumimp.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:2
+*
+*   created on: 2002jul08
+*   created by: Vladimir Weinstein
+*/
+
+#ifndef __UENUMIMP_H
+#define __UENUMIMP_H
+
+#include "unicode/uenum.h"
+
+U_CDECL_BEGIN
+
+/** 
+ * following are the type declarations for 
+ * implementations of APIs. If any of these
+ * functions are NULL, U_UNSUPPORTED_ERROR
+ * is returned. If close is NULL, the enumeration
+ * object is going to be released.
+ * Initial error checking is done in the body
+ * of API function, so the implementations 
+ * need not to check the initial error condition.
+ */
+
+/**
+ * Function type declaration for uenum_close().
+ *
+ * This function should cleanup the enumerator object
+ *
+ * @param en enumeration to be closed
+ */
+typedef void U_CALLCONV
+UEnumClose(UEnumeration *en);
+
+/**
+ * Function type declaration for uenum_count().
+ *
+ * This function should count the number of elements
+ * in this enumeration
+ *
+ * @param en enumeration to be counted
+ * @param status pointer to UErrorCode variable
+ * @return number of elements in enumeration
+ */
+typedef int32_t U_CALLCONV
+UEnumCount(UEnumeration *en, UErrorCode *status);
+
+/**
+ * Function type declaration for uenum_unext().
+ *
+ * This function returns the next element as a UChar *,
+ * or NULL after all elements haven been enumerated.
+ *
+ * @param en enumeration 
+ * @param resultLength pointer to result length
+ * @param status pointer to UErrorCode variable
+ * @return next element as UChar *,
+ *         or NULL after all elements haven been enumerated
+ */
+typedef const UChar* U_CALLCONV 
+UEnumUNext(UEnumeration* en,
+            int32_t* resultLength,
+            UErrorCode* status);
+
+/**
+ * Function type declaration for uenum_next().
+ *
+ * This function returns the next element as a char *,
+ * or NULL after all elements haven been enumerated.
+ *
+ * @param en enumeration 
+ * @param resultLength pointer to result length
+ * @param status pointer to UErrorCode variable
+ * @return next element as char *,
+ *         or NULL after all elements haven been enumerated
+ */
+typedef const char* U_CALLCONV 
+UEnumNext(UEnumeration* en,
+           int32_t* resultLength,
+           UErrorCode* status);
+
+/**
+ * Function type declaration for uenum_reset().
+ *
+ * This function should reset the enumeration 
+ * object
+ *
+ * @param en enumeration 
+ * @param status pointer to UErrorCode variable
+ */
+typedef void U_CALLCONV 
+UEnumReset(UEnumeration* en, 
+            UErrorCode* status);
+
+
+struct UEnumeration {
+    /* baseContext. For the base class only. Don't touch! */
+    void *baseContext;
+
+    /* context. Use it for what you need */
+    void *context;
+
+    /** 
+     * these are functions that will 
+     * be used for APIs
+     */
+    /* called from uenum_close */
+    UEnumClose *close;
+    /* called from uenum_count */
+    UEnumCount *count;
+    /* called from uenum_unext */
+    UEnumUNext *uNext;
+    /* called from uenum_next */
+    UEnumNext  *next;
+    /* called from uenum_reset */
+    UEnumReset *reset;
+};
+
+U_CDECL_END
+
+/* This is the default implementation for uenum_unext().
+ * It automatically converts the char * string to UChar *.
+ * Don't call this directly.  This is called internally by uenum_unext
+ * when a UEnumeration is defined with 'uNext' pointing to this
+ * function.
+ */
+U_CAPI const UChar* U_EXPORT2
+uenum_unextDefault(UEnumeration* en,
+            int32_t* resultLength,
+            UErrorCode* status);
+
+/* This is the default implementation for uenum_next().
+ * It automatically converts the UChar * string to char *.
+ * Don't call this directly.  This is called internally by uenum_next
+ * when a UEnumeration is defined with 'next' pointing to this
+ * function.
+ */
+U_CAPI const char* U_EXPORT2
+uenum_nextDefault(UEnumeration* en,
+            int32_t* resultLength,
+            UErrorCode* status);
+
+#endif
diff --git a/source/common/uhash.c b/source/common/uhash.c
new file mode 100644
index 0000000..0018167
--- /dev/null
+++ b/source/common/uhash.c
@@ -0,0 +1,1009 @@
+/*
+******************************************************************************
+*   Copyright (C) 1997-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+******************************************************************************
+*   Date        Name        Description
+*   03/22/00    aliu        Adapted from original C++ ICU Hashtable.
+*   07/06/01    aliu        Modified to support int32_t keys on
+*                           platforms with sizeof(void*) < 32.
+******************************************************************************
+*/
+
+#include "uhash.h"
+#include "unicode/ustring.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include "uassert.h"
+
+/* This hashtable is implemented as a double hash.  All elements are
+ * stored in a single array with no secondary storage for collision
+ * resolution (no linked list, etc.).  When there is a hash collision
+ * (when two unequal keys have the same hashcode) we resolve this by
+ * using a secondary hash.  The secondary hash is an increment
+ * computed as a hash function (a different one) of the primary
+ * hashcode.  This increment is added to the initial hash value to
+ * obtain further slots assigned to the same hash code.  For this to
+ * work, the length of the array and the increment must be relatively
+ * prime.  The easiest way to achieve this is to have the length of
+ * the array be prime, and the increment be any value from
+ * 1..length-1.
+ *
+ * Hashcodes are 32-bit integers.  We make sure all hashcodes are
+ * non-negative by masking off the top bit.  This has two effects: (1)
+ * modulo arithmetic is simplified.  If we allowed negative hashcodes,
+ * then when we computed hashcode % length, we could get a negative
+ * result, which we would then have to adjust back into range.  It's
+ * simpler to just make hashcodes non-negative. (2) It makes it easy
+ * to check for empty vs. occupied slots in the table.  We just mark
+ * empty or deleted slots with a negative hashcode.
+ *
+ * The central function is _uhash_find().  This function looks for a
+ * slot matching the given key and hashcode.  If one is found, it
+ * returns a pointer to that slot.  If the table is full, and no match
+ * is found, it returns NULL -- in theory.  This would make the code
+ * more complicated, since all callers of _uhash_find() would then
+ * have to check for a NULL result.  To keep this from happening, we
+ * don't allow the table to fill.  When there is only one
+ * empty/deleted slot left, uhash_put() will refuse to increase the
+ * count, and fail.  This simplifies the code.  In practice, one will
+ * seldom encounter this using default UHashtables.  However, if a
+ * hashtable is set to a U_FIXED resize policy, or if memory is
+ * exhausted, then the table may fill.
+ *
+ * High and low water ratios control rehashing.  They establish levels
+ * of fullness (from 0 to 1) outside of which the data array is
+ * reallocated and repopulated.  Setting the low water ratio to zero
+ * means the table will never shrink.  Setting the high water ratio to
+ * one means the table will never grow.  The ratios should be
+ * coordinated with the ratio between successive elements of the
+ * PRIMES table, so that when the primeIndex is incremented or
+ * decremented during rehashing, it brings the ratio of count / length
+ * back into the desired range (between low and high water ratios).
+ */
+
+/********************************************************************
+ * PRIVATE Constants, Macros
+ ********************************************************************/
+
+/* This is a list of non-consecutive primes chosen such that
+ * PRIMES[i+1] ~ 2*PRIMES[i].  (Currently, the ratio ranges from 1.81
+ * to 2.18; the inverse ratio ranges from 0.459 to 0.552.)  If this
+ * ratio is changed, the low and high water ratios should also be
+ * adjusted to suit.
+ *
+ * These prime numbers were also chosen so that they are the largest
+ * prime number while being less than a power of two.
+ */
+static const int32_t PRIMES[] = {
+    13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191, 16381, 32749,
+    65521, 131071, 262139, 524287, 1048573, 2097143, 4194301, 8388593,
+    16777213, 33554393, 67108859, 134217689, 268435399, 536870909,
+    1073741789, 2147483647 /*, 4294967291 */
+};
+
+#define PRIMES_LENGTH (sizeof(PRIMES) / sizeof(PRIMES[0]))
+#define DEFAULT_PRIME_INDEX 3
+
+/* These ratios are tuned to the PRIMES array such that a resize
+ * places the table back into the zone of non-resizing.  That is,
+ * after a call to _uhash_rehash(), a subsequent call to
+ * _uhash_rehash() should do nothing (should not churn).  This is only
+ * a potential problem with U_GROW_AND_SHRINK.
+ */
+static const float RESIZE_POLICY_RATIO_TABLE[6] = {
+    /* low, high water ratio */
+    0.0F, 0.5F, /* U_GROW: Grow on demand, do not shrink */
+    0.1F, 0.5F, /* U_GROW_AND_SHRINK: Grow and shrink on demand */
+    0.0F, 1.0F  /* U_FIXED: Never change size */
+};
+
+/*
+  Invariants for hashcode values:
+
+  * DELETED < 0
+  * EMPTY < 0
+  * Real hashes >= 0
+
+  Hashcodes may not start out this way, but internally they are
+  adjusted so that they are always positive.  We assume 32-bit
+  hashcodes; adjust these constants for other hashcode sizes.
+*/
+#define HASH_DELETED    ((int32_t) 0x80000000)
+#define HASH_EMPTY      ((int32_t) HASH_DELETED + 1)
+
+#define IS_EMPTY_OR_DELETED(x) ((x) < 0)
+
+/* This macro expects a UHashTok.pointer as its keypointer and
+   valuepointer parameters */
+#define HASH_DELETE_KEY_VALUE(hash, keypointer, valuepointer) \
+            if (hash->keyDeleter != NULL && keypointer != NULL) { \
+                (*hash->keyDeleter)(keypointer); \
+            } \
+            if (hash->valueDeleter != NULL && valuepointer != NULL) { \
+                (*hash->valueDeleter)(valuepointer); \
+            }
+
+/*
+ * Constants for hinting whether a key or value is an integer
+ * or a pointer.  If a hint bit is zero, then the associated
+ * token is assumed to be an integer.
+ */
+#define HINT_KEY_POINTER   (1)
+#define HINT_VALUE_POINTER (2)
+
+/********************************************************************
+ * PRIVATE Implementation
+ ********************************************************************/
+
+static UHashTok
+_uhash_setElement(UHashtable *hash, UHashElement* e,
+                  int32_t hashcode,
+                  UHashTok key, UHashTok value, int8_t hint) {
+
+    UHashTok oldValue = e->value;
+    if (hash->keyDeleter != NULL && e->key.pointer != NULL &&
+        e->key.pointer != key.pointer) { /* Avoid double deletion */
+        (*hash->keyDeleter)(e->key.pointer);
+    }
+    if (hash->valueDeleter != NULL) {
+        if (oldValue.pointer != NULL &&
+            oldValue.pointer != value.pointer) { /* Avoid double deletion */
+            (*hash->valueDeleter)(oldValue.pointer);
+        }
+        oldValue.pointer = NULL;
+    }
+    /* Compilers should copy the UHashTok union correctly, but even if
+     * they do, memory heap tools (e.g. BoundsChecker) can get
+     * confused when a pointer is cloaked in a union and then copied.
+     * TO ALLEVIATE THIS, we use hints (based on what API the user is
+     * calling) to copy pointers when we know the user thinks
+     * something is a pointer. */
+    if (hint & HINT_KEY_POINTER) {
+        e->key.pointer = key.pointer;
+    } else {
+        e->key = key;
+    }
+    if (hint & HINT_VALUE_POINTER) {
+        e->value.pointer = value.pointer;
+    } else {
+        e->value = value;
+    }
+    e->hashcode = hashcode;
+    return oldValue;
+}
+
+/**
+ * Assumes that the given element is not empty or deleted.
+ */
+static UHashTok
+_uhash_internalRemoveElement(UHashtable *hash, UHashElement* e) {
+    UHashTok empty;
+    U_ASSERT(!IS_EMPTY_OR_DELETED(e->hashcode));
+    --hash->count;
+    empty.pointer = NULL; empty.integer = 0;
+    return _uhash_setElement(hash, e, HASH_DELETED, empty, empty, 0);
+}
+
+static void
+_uhash_internalSetResizePolicy(UHashtable *hash, enum UHashResizePolicy policy) {
+    U_ASSERT(hash != NULL);
+    U_ASSERT(((int32_t)policy) >= 0);
+    U_ASSERT(((int32_t)policy) < 3);
+    hash->lowWaterRatio  = RESIZE_POLICY_RATIO_TABLE[policy * 2];
+    hash->highWaterRatio = RESIZE_POLICY_RATIO_TABLE[policy * 2 + 1];
+}
+
+/**
+ * Allocate internal data array of a size determined by the given
+ * prime index.  If the index is out of range it is pinned into range.
+ * If the allocation fails the status is set to
+ * U_MEMORY_ALLOCATION_ERROR and all array storage is freed.  In
+ * either case the previous array pointer is overwritten.
+ *
+ * Caller must ensure primeIndex is in range 0..PRIME_LENGTH-1.
+ */
+static void
+_uhash_allocate(UHashtable *hash,
+                int32_t primeIndex,
+                UErrorCode *status) {
+
+    UHashElement *p, *limit;
+    UHashTok emptytok;
+
+    if (U_FAILURE(*status)) return;
+
+    U_ASSERT(primeIndex >= 0 && primeIndex < PRIMES_LENGTH);
+
+    hash->primeIndex = primeIndex;
+    hash->length = PRIMES[primeIndex];
+
+    p = hash->elements = (UHashElement*)
+        uprv_malloc(sizeof(UHashElement) * hash->length);
+
+    if (hash->elements == NULL) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+
+    emptytok.pointer = NULL; /* Only one of these two is needed */
+    emptytok.integer = 0;    /* but we don't know which one. */
+    
+    limit = p + hash->length;
+    while (p < limit) {
+        p->key = emptytok;
+        p->value = emptytok;
+        p->hashcode = HASH_EMPTY;
+        ++p;
+    }
+
+    hash->count = 0;
+    hash->lowWaterMark = (int32_t)(hash->length * hash->lowWaterRatio);
+    hash->highWaterMark = (int32_t)(hash->length * hash->highWaterRatio);
+}
+
+static UHashtable*
+_uhash_init(UHashtable *result,
+              UHashFunction *keyHash, 
+              UKeyComparator *keyComp,
+              UValueComparator *valueComp,
+              int32_t primeIndex,
+              UErrorCode *status)
+{
+    if (U_FAILURE(*status)) return NULL;
+    U_ASSERT(keyHash != NULL);
+    U_ASSERT(keyComp != NULL);
+
+    result->keyHasher       = keyHash;
+    result->keyComparator   = keyComp;
+    result->valueComparator = valueComp;
+    result->keyDeleter      = NULL;
+    result->valueDeleter    = NULL;
+    result->allocated       = FALSE;
+    _uhash_internalSetResizePolicy(result, U_GROW);
+
+    _uhash_allocate(result, primeIndex, status);
+
+    if (U_FAILURE(*status)) {
+        return NULL;
+    }
+
+    return result;
+}
+
+static UHashtable*
+_uhash_create(UHashFunction *keyHash, 
+              UKeyComparator *keyComp,
+              UValueComparator *valueComp,
+              int32_t primeIndex,
+              UErrorCode *status) {
+    UHashtable *result;
+
+    if (U_FAILURE(*status)) return NULL;
+
+    result = (UHashtable*) uprv_malloc(sizeof(UHashtable));
+    if (result == NULL) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+
+    _uhash_init(result, keyHash, keyComp, valueComp, primeIndex, status);
+    result->allocated       = TRUE;
+
+    if (U_FAILURE(*status)) {
+        uprv_free(result);
+        return NULL;
+    }
+
+    return result;
+}
+
+/**
+ * Look for a key in the table, or if no such key exists, the first
+ * empty slot matching the given hashcode.  Keys are compared using
+ * the keyComparator function.
+ *
+ * First find the start position, which is the hashcode modulo
+ * the length.  Test it to see if it is:
+ *
+ * a. identical:  First check the hash values for a quick check,
+ *    then compare keys for equality using keyComparator.
+ * b. deleted
+ * c. empty
+ *
+ * Stop if it is identical or empty, otherwise continue by adding a
+ * "jump" value (moduloing by the length again to keep it within
+ * range) and retesting.  For efficiency, there need enough empty
+ * values so that the searchs stop within a reasonable amount of time.
+ * This can be changed by changing the high/low water marks.
+ *
+ * In theory, this function can return NULL, if it is full (no empty
+ * or deleted slots) and if no matching key is found.  In practice, we
+ * prevent this elsewhere (in uhash_put) by making sure the last slot
+ * in the table is never filled.
+ *
+ * The size of the table should be prime for this algorithm to work;
+ * otherwise we are not guaranteed that the jump value (the secondary
+ * hash) is relatively prime to the table length.
+ */
+static UHashElement*
+_uhash_find(const UHashtable *hash, UHashTok key,
+            int32_t hashcode) {
+
+    int32_t firstDeleted = -1;  /* assume invalid index */
+    int32_t theIndex, startIndex;
+    int32_t jump = 0; /* lazy evaluate */
+    int32_t tableHash;
+    UHashElement *elements = hash->elements;
+
+    hashcode &= 0x7FFFFFFF; /* must be positive */
+    startIndex = theIndex = (hashcode ^ 0x4000000) % hash->length;
+
+    do {
+        tableHash = elements[theIndex].hashcode;
+        if (tableHash == hashcode) {          /* quick check */
+            if ((*hash->keyComparator)(key, elements[theIndex].key)) {
+                return &(elements[theIndex]);
+            }
+        } else if (!IS_EMPTY_OR_DELETED(tableHash)) {
+            /* We have hit a slot which contains a key-value pair,
+             * but for which the hash code does not match.  Keep
+             * looking.
+             */
+        } else if (tableHash == HASH_EMPTY) { /* empty, end o' the line */
+            break;
+        } else if (firstDeleted < 0) { /* remember first deleted */
+            firstDeleted = theIndex;
+        }
+        if (jump == 0) { /* lazy compute jump */
+            /* The jump value must be relatively prime to the table
+             * length.  As long as the length is prime, then any value
+             * 1..length-1 will be relatively prime to it.
+             */
+            jump = (hashcode % (hash->length - 1)) + 1;
+        }
+        theIndex = (theIndex + jump) % hash->length;
+    } while (theIndex != startIndex);
+
+    if (firstDeleted >= 0) {
+        theIndex = firstDeleted; /* reset if had deleted slot */
+    } else if (tableHash != HASH_EMPTY) {
+        /* We get to this point if the hashtable is full (no empty or
+         * deleted slots), and we've failed to find a match.  THIS
+         * WILL NEVER HAPPEN as long as uhash_put() makes sure that
+         * count is always < length.
+         */
+        U_ASSERT(FALSE);
+        return NULL; /* Never happens if uhash_put() behaves */
+    }
+    return &(elements[theIndex]);
+}
+
+/**
+ * Attempt to grow or shrink the data arrays in order to make the
+ * count fit between the high and low water marks.  hash_put() and
+ * hash_remove() call this method when the count exceeds the high or
+ * low water marks.  This method may do nothing, if memory allocation
+ * fails, or if the count is already in range, or if the length is
+ * already at the low or high limit.  In any case, upon return the
+ * arrays will be valid.
+ */
+static void
+_uhash_rehash(UHashtable *hash, UErrorCode *status) {
+
+    UHashElement *old = hash->elements;
+    int32_t oldLength = hash->length;
+    int32_t newPrimeIndex = hash->primeIndex;
+    int32_t i;
+
+    if (hash->count > hash->highWaterMark) {
+        if (++newPrimeIndex >= PRIMES_LENGTH) {
+            return;
+        }
+    } else if (hash->count < hash->lowWaterMark) {
+        if (--newPrimeIndex < 0) {
+            return;
+        }
+    } else {
+        return;
+    }
+
+    _uhash_allocate(hash, newPrimeIndex, status);
+
+    if (U_FAILURE(*status)) {
+        hash->elements = old;
+        hash->length = oldLength;       
+        return;
+    }
+
+    for (i = oldLength - 1; i >= 0; --i) {
+        if (!IS_EMPTY_OR_DELETED(old[i].hashcode)) {
+            UHashElement *e = _uhash_find(hash, old[i].key, old[i].hashcode);
+            U_ASSERT(e != NULL);
+            U_ASSERT(e->hashcode == HASH_EMPTY);
+            e->key = old[i].key;
+            e->value = old[i].value;
+            e->hashcode = old[i].hashcode;
+            ++hash->count;
+        }
+    }
+
+    uprv_free(old);
+}
+
+static UHashTok
+_uhash_remove(UHashtable *hash,
+              UHashTok key) {
+    /* First find the position of the key in the table.  If the object
+     * has not been removed already, remove it.  If the user wanted
+     * keys deleted, then delete it also.  We have to put a special
+     * hashcode in that position that means that something has been
+     * deleted, since when we do a find, we have to continue PAST any
+     * deleted values.
+     */
+    UHashTok result;
+    UHashElement* e = _uhash_find(hash, key, hash->keyHasher(key));
+    U_ASSERT(e != NULL);
+    result.pointer = NULL;
+    result.integer = 0;
+    if (!IS_EMPTY_OR_DELETED(e->hashcode)) {
+        result = _uhash_internalRemoveElement(hash, e);
+        if (hash->count < hash->lowWaterMark) {
+            UErrorCode status = U_ZERO_ERROR;
+            _uhash_rehash(hash, &status);
+        }
+    }
+    return result;
+}
+
+static UHashTok
+_uhash_put(UHashtable *hash,
+           UHashTok key,
+           UHashTok value,
+           int8_t hint,
+           UErrorCode *status) {
+
+    /* Put finds the position in the table for the new value.  If the
+     * key is already in the table, it is deleted, if there is a
+     * non-NULL keyDeleter.  Then the key, the hash and the value are
+     * all put at the position in their respective arrays.
+     */
+    int32_t hashcode;
+    UHashElement* e;
+    UHashTok emptytok;
+
+    if (U_FAILURE(*status)) {
+        goto err;
+    }
+    U_ASSERT(hash != NULL);
+    /* Cannot always check pointer here or iSeries sees NULL every time. */
+    if ((hint & HINT_VALUE_POINTER) && value.pointer == NULL) {
+        /* Disallow storage of NULL values, since NULL is returned by
+         * get() to indicate an absent key.  Storing NULL == removing.
+         */
+        return _uhash_remove(hash, key);
+    }
+    if (hash->count > hash->highWaterMark) {
+        _uhash_rehash(hash, status);
+        if (U_FAILURE(*status)) {
+            goto err;
+        }
+    }
+
+    hashcode = (*hash->keyHasher)(key);
+    e = _uhash_find(hash, key, hashcode);
+    U_ASSERT(e != NULL);
+
+    if (IS_EMPTY_OR_DELETED(e->hashcode)) {
+        /* Important: We must never actually fill the table up.  If we
+         * do so, then _uhash_find() will return NULL, and we'll have
+         * to check for NULL after every call to _uhash_find().  To
+         * avoid this we make sure there is always at least one empty
+         * or deleted slot in the table.  This only is a problem if we
+         * are out of memory and rehash isn't working.
+         */
+        ++hash->count;
+        if (hash->count == hash->length) {
+            /* Don't allow count to reach length */
+            --hash->count;
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            goto err;
+        }
+    }
+
+    /* We must in all cases handle storage properly.  If there was an
+     * old key, then it must be deleted (if the deleter != NULL).
+     * Make hashcodes stored in table positive.
+     */
+    return _uhash_setElement(hash, e, hashcode & 0x7FFFFFFF, key, value, hint);
+
+ err:
+    /* If the deleters are non-NULL, this method adopts its key and/or
+     * value arguments, and we must be sure to delete the key and/or
+     * value in all cases, even upon failure.
+     */
+    HASH_DELETE_KEY_VALUE(hash, key.pointer, value.pointer);
+    emptytok.pointer = NULL; emptytok.integer = 0;
+    return emptytok;
+}
+
+
+/********************************************************************
+ * PUBLIC API
+ ********************************************************************/
+
+U_CAPI UHashtable* U_EXPORT2
+uhash_open(UHashFunction *keyHash, 
+           UKeyComparator *keyComp,
+           UValueComparator *valueComp,
+           UErrorCode *status) {
+
+    return _uhash_create(keyHash, keyComp, valueComp, DEFAULT_PRIME_INDEX, status);
+}
+
+U_CAPI UHashtable* U_EXPORT2
+uhash_openSize(UHashFunction *keyHash, 
+               UKeyComparator *keyComp,
+               UValueComparator *valueComp,
+               int32_t size,
+               UErrorCode *status) {
+
+    /* Find the smallest index i for which PRIMES[i] >= size. */
+    int32_t i = 0;
+    while (i<(PRIMES_LENGTH-1) && PRIMES[i]<size) {
+        ++i;
+    }
+
+    return _uhash_create(keyHash, keyComp, valueComp, i, status);
+}
+
+U_CAPI UHashtable* U_EXPORT2
+uhash_init(UHashtable *fillinResult,
+           UHashFunction *keyHash, 
+           UKeyComparator *keyComp,
+           UValueComparator *valueComp,
+           UErrorCode *status) {
+
+    return _uhash_init(fillinResult, keyHash, keyComp, valueComp, DEFAULT_PRIME_INDEX, status);
+}
+
+U_CAPI void U_EXPORT2
+uhash_close(UHashtable *hash) {
+    if (hash == NULL) {
+        return;
+    }
+    if (hash->elements != NULL) {
+        if (hash->keyDeleter != NULL || hash->valueDeleter != NULL) {
+            int32_t pos=-1;
+            UHashElement *e;
+            while ((e = (UHashElement*) uhash_nextElement(hash, &pos)) != NULL) {
+                HASH_DELETE_KEY_VALUE(hash, e->key.pointer, e->value.pointer);
+            }
+        }
+        uprv_free(hash->elements);
+        hash->elements = NULL;
+    }
+    if (hash->allocated) {
+        uprv_free(hash);
+    }
+}
+
+U_CAPI UHashFunction *U_EXPORT2
+uhash_setKeyHasher(UHashtable *hash, UHashFunction *fn) {
+    UHashFunction *result = hash->keyHasher;
+    hash->keyHasher = fn;
+    return result;
+}
+
+U_CAPI UKeyComparator *U_EXPORT2
+uhash_setKeyComparator(UHashtable *hash, UKeyComparator *fn) {
+    UKeyComparator *result = hash->keyComparator;
+    hash->keyComparator = fn;
+    return result;
+}
+U_CAPI UValueComparator *U_EXPORT2 
+uhash_setValueComparator(UHashtable *hash, UValueComparator *fn){
+    UValueComparator *result = hash->valueComparator;
+    hash->valueComparator = fn;
+    return result;
+}
+
+U_CAPI UObjectDeleter *U_EXPORT2
+uhash_setKeyDeleter(UHashtable *hash, UObjectDeleter *fn) {
+    UObjectDeleter *result = hash->keyDeleter;
+    hash->keyDeleter = fn;
+    return result;
+}
+
+U_CAPI UObjectDeleter *U_EXPORT2
+uhash_setValueDeleter(UHashtable *hash, UObjectDeleter *fn) {
+    UObjectDeleter *result = hash->valueDeleter;
+    hash->valueDeleter = fn;
+    return result;
+}
+
+U_CAPI void U_EXPORT2
+uhash_setResizePolicy(UHashtable *hash, enum UHashResizePolicy policy) {
+    UErrorCode status = U_ZERO_ERROR;
+    _uhash_internalSetResizePolicy(hash, policy);
+    hash->lowWaterMark  = (int32_t)(hash->length * hash->lowWaterRatio);
+    hash->highWaterMark = (int32_t)(hash->length * hash->highWaterRatio);    
+    _uhash_rehash(hash, &status);
+}
+
+U_CAPI int32_t U_EXPORT2
+uhash_count(const UHashtable *hash) {
+    return hash->count;
+}
+
+U_CAPI void* U_EXPORT2
+uhash_get(const UHashtable *hash,
+          const void* key) {
+    UHashTok keyholder;
+    keyholder.pointer = (void*) key;
+    return _uhash_find(hash, keyholder, hash->keyHasher(keyholder))->value.pointer;
+}
+
+U_CAPI void* U_EXPORT2
+uhash_iget(const UHashtable *hash,
+           int32_t key) {
+    UHashTok keyholder;
+    keyholder.integer = key;
+    return _uhash_find(hash, keyholder, hash->keyHasher(keyholder))->value.pointer;
+}
+
+U_CAPI int32_t U_EXPORT2
+uhash_geti(const UHashtable *hash,
+           const void* key) {
+    UHashTok keyholder;
+    keyholder.pointer = (void*) key;
+    return _uhash_find(hash, keyholder, hash->keyHasher(keyholder))->value.integer;
+}
+
+U_CAPI int32_t U_EXPORT2
+uhash_igeti(const UHashtable *hash,
+           int32_t key) {
+    UHashTok keyholder;
+    keyholder.integer = key;
+    return _uhash_find(hash, keyholder, hash->keyHasher(keyholder))->value.integer;
+}
+
+U_CAPI void* U_EXPORT2
+uhash_put(UHashtable *hash,
+          void* key,
+          void* value,
+          UErrorCode *status) {
+    UHashTok keyholder, valueholder;
+    keyholder.pointer = key;
+    valueholder.pointer = value;
+    return _uhash_put(hash, keyholder, valueholder,
+                      HINT_KEY_POINTER | HINT_VALUE_POINTER,
+                      status).pointer;
+}
+
+U_CAPI void* U_EXPORT2
+uhash_iput(UHashtable *hash,
+           int32_t key,
+           void* value,
+           UErrorCode *status) {
+    UHashTok keyholder, valueholder;
+    keyholder.integer = key;
+    valueholder.pointer = value;
+    return _uhash_put(hash, keyholder, valueholder,
+                      HINT_VALUE_POINTER,
+                      status).pointer;
+}
+
+U_CAPI int32_t U_EXPORT2
+uhash_puti(UHashtable *hash,
+           void* key,
+           int32_t value,
+           UErrorCode *status) {
+    UHashTok keyholder, valueholder;
+    keyholder.pointer = key;
+    valueholder.integer = value;
+    return _uhash_put(hash, keyholder, valueholder,
+                      HINT_KEY_POINTER,
+                      status).integer;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uhash_iputi(UHashtable *hash,
+           int32_t key,
+           int32_t value,
+           UErrorCode *status) {
+    UHashTok keyholder, valueholder;
+    keyholder.integer = key;
+    valueholder.integer = value;
+    return _uhash_put(hash, keyholder, valueholder,
+                      0, /* neither is a ptr */
+                      status).integer;
+}
+
+U_CAPI void* U_EXPORT2
+uhash_remove(UHashtable *hash,
+             const void* key) {
+    UHashTok keyholder;
+    keyholder.pointer = (void*) key;
+    return _uhash_remove(hash, keyholder).pointer;
+}
+
+U_CAPI void* U_EXPORT2
+uhash_iremove(UHashtable *hash,
+              int32_t key) {
+    UHashTok keyholder;
+    keyholder.integer = key;
+    return _uhash_remove(hash, keyholder).pointer;
+}
+
+U_CAPI int32_t U_EXPORT2
+uhash_removei(UHashtable *hash,
+              const void* key) {
+    UHashTok keyholder;
+    keyholder.pointer = (void*) key;
+    return _uhash_remove(hash, keyholder).integer;
+}
+
+U_CAPI int32_t U_EXPORT2
+uhash_iremovei(UHashtable *hash,
+               int32_t key) {
+    UHashTok keyholder;
+    keyholder.integer = key;
+    return _uhash_remove(hash, keyholder).integer;
+}
+
+U_CAPI void U_EXPORT2
+uhash_removeAll(UHashtable *hash) {
+    int32_t pos = -1;
+    const UHashElement *e;
+    U_ASSERT(hash != NULL);
+    if (hash->count != 0) {
+        while ((e = uhash_nextElement(hash, &pos)) != NULL) {
+            uhash_removeElement(hash, e);
+        }
+    }
+    U_ASSERT(hash->count == 0);
+}
+
+U_CAPI const UHashElement* U_EXPORT2
+uhash_find(const UHashtable *hash, const void* key) {
+    UHashTok keyholder;
+    const UHashElement *e;
+    keyholder.pointer = (void*) key;
+    e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder));
+    return IS_EMPTY_OR_DELETED(e->hashcode) ? NULL : e;
+}
+
+U_CAPI const UHashElement* U_EXPORT2
+uhash_nextElement(const UHashtable *hash, int32_t *pos) {
+    /* Walk through the array until we find an element that is not
+     * EMPTY and not DELETED.
+     */
+    int32_t i;
+    U_ASSERT(hash != NULL);
+    for (i = *pos + 1; i < hash->length; ++i) {
+        if (!IS_EMPTY_OR_DELETED(hash->elements[i].hashcode)) {
+            *pos = i;
+            return &(hash->elements[i]);
+        }
+    }
+
+    /* No more elements */
+    return NULL;
+}
+
+U_CAPI void* U_EXPORT2
+uhash_removeElement(UHashtable *hash, const UHashElement* e) {
+    U_ASSERT(hash != NULL);
+    U_ASSERT(e != NULL);
+    if (!IS_EMPTY_OR_DELETED(e->hashcode)) {
+        UHashElement *nce = (UHashElement *)e;
+        return _uhash_internalRemoveElement(hash, nce).pointer;
+    }
+    return NULL;
+}
+
+/********************************************************************
+ * UHashTok convenience
+ ********************************************************************/
+
+/**
+ * Return a UHashTok for an integer.
+ */
+/*U_CAPI UHashTok U_EXPORT2
+uhash_toki(int32_t i) {
+    UHashTok tok;
+    tok.integer = i;
+    return tok;
+}*/
+
+/**
+ * Return a UHashTok for a pointer.
+ */
+/*U_CAPI UHashTok U_EXPORT2
+uhash_tokp(void* p) {
+    UHashTok tok;
+    tok.pointer = p;
+    return tok;
+}*/
+
+/********************************************************************
+ * PUBLIC Key Hash Functions
+ ********************************************************************/
+
+/*
+  Compute the hash by iterating sparsely over about 32 (up to 63)
+  characters spaced evenly through the string.  For each character,
+  multiply the previous hash value by a prime number and add the new
+  character in, like a linear congruential random number generator,
+  producing a pseudorandom deterministic value well distributed over
+  the output range. [LIU]
+*/
+
+#define STRING_HASH(TYPE, STR, STRLEN, DEREF) \
+    int32_t hash = 0;                         \
+    const TYPE *p = (const TYPE*) STR;        \
+    if (p != NULL) {                          \
+        int32_t len = (int32_t)(STRLEN);      \
+        int32_t inc = ((len - 32) / 32) + 1;  \
+        const TYPE *limit = p + len;          \
+        while (p<limit) {                     \
+            hash = (hash * 37) + DEREF;       \
+            p += inc;                         \
+        }                                     \
+    }                                         \
+    return hash
+
+U_CAPI int32_t U_EXPORT2
+uhash_hashUChars(const UHashTok key) {
+    STRING_HASH(UChar, key.pointer, u_strlen(p), *p);
+}
+
+/* Used by UnicodeString to compute its hashcode - Not public API. */
+U_CAPI int32_t U_EXPORT2
+uhash_hashUCharsN(const UChar *str, int32_t length) {
+    STRING_HASH(UChar, str, length, *p);
+}
+
+U_CAPI int32_t U_EXPORT2
+uhash_hashChars(const UHashTok key) {
+    STRING_HASH(uint8_t, key.pointer, uprv_strlen((char*)p), *p);
+}
+
+U_CAPI int32_t U_EXPORT2
+uhash_hashIChars(const UHashTok key) {
+    STRING_HASH(uint8_t, key.pointer, uprv_strlen((char*)p), uprv_tolower(*p));
+}
+
+U_CAPI UBool U_EXPORT2 
+uhash_equals(const UHashtable* hash1, const UHashtable* hash2){
+    
+    int32_t count1, count2, pos, i;
+
+    if(hash1==hash2){
+        return TRUE;
+    }
+
+    /*
+     * Make sure that we are comparing 2 valid hashes of the same type
+     * with valid comparison functions.
+     * Without valid comparison functions, a binary comparison
+     * of the hash values will yield random results on machines
+     * with 64-bit pointers and 32-bit integer hashes.
+     * A valueComparator is normally optional.
+     */
+    if (hash1==NULL || hash2==NULL ||
+        hash1->keyComparator != hash2->keyComparator ||
+        hash1->valueComparator != hash2->valueComparator ||
+        hash1->valueComparator == NULL)
+    {
+        /*
+        Normally we would return an error here about incompatible hash tables,
+        but we return FALSE instead.
+        */
+        return FALSE;
+    }
+
+    count1 = uhash_count(hash1);
+    count2 = uhash_count(hash2);
+    if(count1!=count2){
+        return FALSE;
+    }
+    
+    pos=-1;
+    for(i=0; i<count1; i++){
+        const UHashElement* elem1 = uhash_nextElement(hash1, &pos);
+        const UHashTok key1 = elem1->key;
+        const UHashTok val1 = elem1->value;
+        /* here the keys are not compared, instead the key form hash1 is used to fetch
+         * value from hash2. If the hashes are equal then then both hashes should 
+         * contain equal values for the same key!
+         */
+        const UHashElement* elem2 = _uhash_find(hash2, key1, hash2->keyHasher(key1));
+        const UHashTok val2 = elem2->value;
+        if(hash1->valueComparator(val1, val2)==FALSE){
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+/********************************************************************
+ * PUBLIC Comparator Functions
+ ********************************************************************/
+
+U_CAPI UBool U_EXPORT2
+uhash_compareUChars(const UHashTok key1, const UHashTok key2) {
+    const UChar *p1 = (const UChar*) key1.pointer;
+    const UChar *p2 = (const UChar*) key2.pointer;
+    if (p1 == p2) {
+        return TRUE;
+    }
+    if (p1 == NULL || p2 == NULL) {
+        return FALSE;
+    }
+    while (*p1 != 0 && *p1 == *p2) {
+        ++p1;
+        ++p2;
+    }
+    return (UBool)(*p1 == *p2);
+}
+
+U_CAPI UBool U_EXPORT2
+uhash_compareChars(const UHashTok key1, const UHashTok key2) {
+    const char *p1 = (const char*) key1.pointer;
+    const char *p2 = (const char*) key2.pointer;
+    if (p1 == p2) {
+        return TRUE;
+    }
+    if (p1 == NULL || p2 == NULL) {
+        return FALSE;
+    }
+    while (*p1 != 0 && *p1 == *p2) {
+        ++p1;
+        ++p2;
+    }
+    return (UBool)(*p1 == *p2);
+}
+
+U_CAPI UBool U_EXPORT2
+uhash_compareIChars(const UHashTok key1, const UHashTok key2) {
+    const char *p1 = (const char*) key1.pointer;
+    const char *p2 = (const char*) key2.pointer;
+    if (p1 == p2) {
+        return TRUE;
+    }
+    if (p1 == NULL || p2 == NULL) {
+        return FALSE;
+    }
+    while (*p1 != 0 && uprv_tolower(*p1) == uprv_tolower(*p2)) {
+        ++p1;
+        ++p2;
+    }
+    return (UBool)(*p1 == *p2);
+}
+
+/********************************************************************
+ * PUBLIC int32_t Support Functions
+ ********************************************************************/
+
+U_CAPI int32_t U_EXPORT2
+uhash_hashLong(const UHashTok key) {
+    return key.integer;
+}
+
+U_CAPI UBool U_EXPORT2
+uhash_compareLong(const UHashTok key1, const UHashTok key2) {
+    return (UBool)(key1.integer == key2.integer);
+}
+
+/********************************************************************
+ * PUBLIC Deleter Functions
+ ********************************************************************/
+
+U_CAPI void U_EXPORT2
+uhash_freeBlock(void *obj) {
+    uprv_free(obj);
+}
+
diff --git a/source/common/uhash.h b/source/common/uhash.h
new file mode 100644
index 0000000..c1c50ed
--- /dev/null
+++ b/source/common/uhash.h
@@ -0,0 +1,729 @@
+/*
+******************************************************************************
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+******************************************************************************
+*   Date        Name        Description
+*   03/22/00    aliu        Adapted from original C++ ICU Hashtable.
+*   07/06/01    aliu        Modified to support int32_t keys on
+*                           platforms with sizeof(void*) < 32.
+******************************************************************************
+*/
+
+#ifndef UHASH_H
+#define UHASH_H
+
+#include "unicode/utypes.h"
+
+/**
+ * UHashtable stores key-value pairs and does moderately fast lookup
+ * based on keys.  It provides a good tradeoff between access time and
+ * storage space.  As elements are added to it, it grows to accomodate
+ * them.  By default, the table never shrinks, even if all elements
+ * are removed from it.
+ *
+ * Keys and values are stored as void* pointers.  These void* pointers
+ * may be actual pointers to strings, objects, or any other structure
+ * in memory, or they may simply be integral values cast to void*.
+ * UHashtable doesn't care and manipulates them via user-supplied
+ * functions.  These functions hash keys, compare keys, delete keys,
+ * and delete values.  Some function pointers are optional (may be
+ * NULL); others must be supplied.  Several prebuilt functions exist
+ * to handle common key types.
+ *
+ * UHashtable ownership of keys and values is flexible, and controlled
+ * by whether or not the key deleter and value deleter functions are
+ * set.  If a void* key is actually a pointer to a deletable object,
+ * then UHashtable can be made to delete that object by setting the
+ * key deleter function pointer to a non-NULL value.  If this is done,
+ * then keys passed to uhash_put() are owned by the hashtable and will
+ * be deleted by it at some point, either as keys are replaced, or
+ * when uhash_close() is finally called.  The same is true of values
+ * and the value deleter function pointer.  Keys passed to methods
+ * other than uhash_put() are never owned by the hashtable.
+ *
+ * NULL values are not allowed.  uhash_get() returns NULL to indicate
+ * a key that is not in the table, and having a NULL value in the
+ * table would generate an ambiguous result.  If a key and a NULL
+ * value is passed to uhash_put(), this has the effect of doing a
+ * uhash_remove() on that key.  This keeps uhash_get(), uhash_count(),
+ * and uhash_nextElement() consistent with one another.
+ *
+ * To see everything in a hashtable, use uhash_nextElement() to
+ * iterate through its contents.  Each call to this function returns a
+ * UHashElement pointer.  A hash element contains a key, value, and
+ * hashcode.  During iteration an element may be deleted by calling
+ * uhash_removeElement(); iteration may safely continue thereafter.
+ * The uhash_remove() function may also be safely called in
+ * mid-iteration.  However, if uhash_put() is called during iteration
+ * then the iteration will be out of sync.  Under no circumstances
+ * should the UHashElement returned by uhash_nextElement be modified
+ * directly.
+ *
+ * By default, the hashtable grows when necessary, but never shrinks,
+ * even if all items are removed.  For most applications this is
+ * optimal.  However, in a highly dynamic usage where memory is at a
+ * premium, the table can be set to both grow and shrink by calling
+ * uhash_setResizePolicy() with the policy U_GROW_AND_SHRINK.  In a
+ * situation where memory is critical and the client wants a table
+ * that does not grow at all, the constant U_FIXED can be used.
+ */
+
+/********************************************************************
+ * Data Structures
+ ********************************************************************/
+
+U_CDECL_BEGIN
+
+/**
+ * A key or value within the hashtable.  It may be either a 32-bit
+ * integral value or an opaque void* pointer.  The void* pointer may
+ * be smaller than 32 bits (e.g. 24 bits) or may be larger (e.g. 64
+ * bits).  The hashing and comparison functions take a pointer to a
+ * UHashTok, but the deleter receives the void* pointer within it.
+ *
+ * Because a UHashTok is the size of a native pointer or a 32-bit
+ * integer, we pass it around by value.
+ */
+union UHashTok {
+    void*   pointer;
+    int32_t integer;
+};
+typedef union UHashTok UHashTok;
+
+/**
+ * This is a single hash element.
+ */
+struct UHashElement {
+    /* Reorder these elements to pack nicely if necessary */
+    int32_t  hashcode;
+    UHashTok value;
+    UHashTok key;
+};
+typedef struct UHashElement UHashElement;
+
+/**
+ * A hashing function.
+ * @param key A key stored in a hashtable
+ * @return A NON-NEGATIVE hash code for parm.
+ */
+typedef int32_t U_CALLCONV UHashFunction(const UHashTok key);
+
+/**
+ * A key comparison function.
+ * @param key1 A key stored in a hashtable
+ * @param key2 A key stored in a hashtable
+ * @return TRUE if the two keys are equal.
+ */
+typedef UBool U_CALLCONV UKeyComparator(const UHashTok key1,
+                                        const UHashTok key2);
+/**
+ * A key comparison function.
+ * @param val1 A key stored in a hashtable
+ * @param val2 A key stored in a hashtable
+ * @return TRUE if the two keys are equal.
+ */
+typedef UBool U_CALLCONV UValueComparator(const UHashTok val1,
+                                          const UHashTok val2);
+/**
+ * A function called by <TT>uhash_remove</TT>,
+ * <TT>uhash_close</TT>, or <TT>uhash_put</TT> to delete
+ * an existing key or value.
+ * @param obj A key or value stored in a hashtable
+ * @see uhash_deleteUObject
+ */
+typedef void U_CALLCONV UObjectDeleter(void* obj);
+
+/**
+ * This specifies whether or not, and how, the hastable resizes itself.
+ * See uhash_setResizePolicy().
+ */
+enum UHashResizePolicy {
+    U_GROW,            /* Grow on demand, do not shrink */
+    U_GROW_AND_SHRINK, /* Grow and shrink on demand */
+    U_FIXED            /* Never change size */
+};
+
+/**
+ * The UHashtable struct.  Clients should treat this as an opaque data
+ * type and manipulate it only through the uhash_... API.
+ */
+struct UHashtable {
+
+    /* Main key-value pair storage array */
+
+    UHashElement *elements;
+
+    /* Function pointers */
+
+    UHashFunction *keyHasher;      /* Computes hash from key.
+                                   * Never null. */
+    UKeyComparator *keyComparator; /* Compares keys for equality.
+                                   * Never null. */
+    UValueComparator *valueComparator; /* Compares the values for equality */
+
+    UObjectDeleter *keyDeleter;    /* Deletes keys when required.
+                                   * If NULL won't do anything */
+    UObjectDeleter *valueDeleter;  /* Deletes values when required.
+                                   * If NULL won't do anything */
+
+    /* Size parameters */
+  
+    int32_t     count;      /* The number of key-value pairs in this table.
+                             * 0 <= count <= length.  In practice we
+                             * never let count == length (see code). */
+    int32_t     length;     /* The physical size of the arrays hashes, keys
+                             * and values.  Must be prime. */
+
+    /* Rehashing thresholds */
+    
+    int32_t     highWaterMark;  /* If count > highWaterMark, rehash */
+    int32_t     lowWaterMark;   /* If count < lowWaterMark, rehash */
+    float       highWaterRatio; /* 0..1; high water as a fraction of length */
+    float       lowWaterRatio;  /* 0..1; low water as a fraction of length */
+    
+    int8_t      primeIndex;     /* Index into our prime table for length.
+                                 * length == PRIMES[primeIndex] */
+    UBool       allocated; /* Was this UHashtable allocated? */
+};
+typedef struct UHashtable UHashtable;
+
+U_CDECL_END
+
+/********************************************************************
+ * API
+ ********************************************************************/
+
+/**
+ * Initialize a new UHashtable.
+ * @param keyHash A pointer to the key hashing function.  Must not be
+ * NULL.
+ * @param keyComp A pointer to the function that compares keys.  Must
+ * not be NULL.
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return A pointer to a UHashtable, or 0 if an error occurred.
+ * @see uhash_openSize
+ */
+U_CAPI UHashtable* U_EXPORT2 
+uhash_open(UHashFunction *keyHash,
+           UKeyComparator *keyComp,
+           UValueComparator *valueComp,
+           UErrorCode *status);
+
+/**
+ * Initialize a new UHashtable with a given initial size.
+ * @param keyHash A pointer to the key hashing function.  Must not be
+ * NULL.
+ * @param keyComp A pointer to the function that compares keys.  Must
+ * not be NULL.
+ * @param size The initial capacity of this hash table.
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return A pointer to a UHashtable, or 0 if an error occurred.
+ * @see uhash_open
+ */
+U_CAPI UHashtable* U_EXPORT2 
+uhash_openSize(UHashFunction *keyHash,
+               UKeyComparator *keyComp,
+               UValueComparator *valueComp,
+               int32_t size,
+               UErrorCode *status);
+
+/**
+ * Initialize an existing UHashtable.
+ * @param keyHash A pointer to the key hashing function.  Must not be
+ * NULL.
+ * @param keyComp A pointer to the function that compares keys.  Must
+ * not be NULL.
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return A pointer to a UHashtable, or 0 if an error occurred.
+ * @see uhash_openSize
+ */
+U_CAPI UHashtable* U_EXPORT2 
+uhash_init(UHashtable *hash,
+           UHashFunction *keyHash,
+           UKeyComparator *keyComp,
+           UValueComparator *valueComp,
+           UErrorCode *status);
+
+/**
+ * Close a UHashtable, releasing the memory used.
+ * @param hash The UHashtable to close. If hash is NULL no operation is performed.
+ */
+U_CAPI void U_EXPORT2 
+uhash_close(UHashtable *hash);
+
+
+
+/**
+ * Set the function used to hash keys.
+ * @param hash The UHashtable to set
+ * @param fn the function to be used hash keys; must not be NULL
+ * @return the previous key hasher; non-NULL
+ */
+U_CAPI UHashFunction *U_EXPORT2 
+uhash_setKeyHasher(UHashtable *hash, UHashFunction *fn);
+
+/**
+ * Set the function used to compare keys.  The default comparison is a
+ * void* pointer comparison.
+ * @param hash The UHashtable to set
+ * @param fn the function to be used compare keys; must not be NULL
+ * @return the previous key comparator; non-NULL
+ */
+U_CAPI UKeyComparator *U_EXPORT2 
+uhash_setKeyComparator(UHashtable *hash, UKeyComparator *fn);
+
+/**
+ * Set the function used to compare values.  The default comparison is a
+ * void* pointer comparison.
+ * @param hash The UHashtable to set
+ * @param fn the function to be used compare keys; must not be NULL
+ * @return the previous key comparator; non-NULL
+ */
+U_CAPI UValueComparator *U_EXPORT2 
+uhash_setValueComparator(UHashtable *hash, UValueComparator *fn);
+
+/**
+ * Set the function used to delete keys.  If this function pointer is
+ * NULL, this hashtable does not delete keys.  If it is non-NULL, this
+ * hashtable does delete keys.  This function should be set once
+ * before any elements are added to the hashtable and should not be
+ * changed thereafter.
+ * @param hash The UHashtable to set
+ * @param fn the function to be used delete keys, or NULL
+ * @return the previous key deleter; may be NULL
+ */
+U_CAPI UObjectDeleter *U_EXPORT2 
+uhash_setKeyDeleter(UHashtable *hash, UObjectDeleter *fn);
+
+/**
+ * Set the function used to delete values.  If this function pointer
+ * is NULL, this hashtable does not delete values.  If it is non-NULL,
+ * this hashtable does delete values.  This function should be set
+ * once before any elements are added to the hashtable and should not
+ * be changed thereafter.
+ * @param hash The UHashtable to set
+ * @param fn the function to be used delete values, or NULL
+ * @return the previous value deleter; may be NULL
+ */
+U_CAPI UObjectDeleter *U_EXPORT2 
+uhash_setValueDeleter(UHashtable *hash, UObjectDeleter *fn);
+
+/**
+ * Specify whether or not, and how, the hastable resizes itself.
+ * By default, tables grow but do not shrink (policy U_GROW).
+ * See enum UHashResizePolicy.
+ * @param hash The UHashtable to set
+ * @param policy The way the hashtable resizes itself, {U_GROW, U_GROW_AND_SHRINK, U_FIXED}
+ */
+U_CAPI void U_EXPORT2 
+uhash_setResizePolicy(UHashtable *hash, enum UHashResizePolicy policy);
+
+/**
+ * Get the number of key-value pairs stored in a UHashtable.
+ * @param hash The UHashtable to query.
+ * @return The number of key-value pairs stored in hash.
+ */
+U_CAPI int32_t U_EXPORT2 
+uhash_count(const UHashtable *hash);
+
+/**
+ * Put a (key=pointer, value=pointer) item in a UHashtable.  If the
+ * keyDeleter is non-NULL, then the hashtable owns 'key' after this
+ * call.  If the valueDeleter is non-NULL, then the hashtable owns
+ * 'value' after this call.  Storing a NULL value is the same as
+ * calling uhash_remove().
+ * @param hash The target UHashtable.
+ * @param key The key to store.
+ * @param value The value to store, may be NULL (see above).
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return The previous value, or NULL if none.
+ * @see uhash_get
+ */
+U_CAPI void* U_EXPORT2 
+uhash_put(UHashtable *hash,
+          void *key,
+          void *value,
+          UErrorCode *status);
+
+/**
+ * Put a (key=integer, value=pointer) item in a UHashtable.
+ * keyDeleter must be NULL.  If the valueDeleter is non-NULL, then the
+ * hashtable owns 'value' after this call.  Storing a NULL value is
+ * the same as calling uhash_remove().
+ * @param hash The target UHashtable.
+ * @param key The integer key to store.
+ * @param value The value to store, may be NULL (see above).
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return The previous value, or NULL if none.
+ * @see uhash_get
+ */
+U_CAPI void* U_EXPORT2 
+uhash_iput(UHashtable *hash,
+           int32_t key,
+           void* value,
+           UErrorCode *status);
+
+/**
+ * Put a (key=pointer, value=integer) item in a UHashtable.  If the
+ * keyDeleter is non-NULL, then the hashtable owns 'key' after this
+ * call.  valueDeleter must be NULL.  Storing a 0 value is the same as
+ * calling uhash_remove().
+ * @param hash The target UHashtable.
+ * @param key The key to store.
+ * @param value The integer value to store.
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return The previous value, or 0 if none.
+ * @see uhash_get
+ */
+U_CAPI int32_t U_EXPORT2 
+uhash_puti(UHashtable *hash,
+           void* key,
+           int32_t value,
+           UErrorCode *status);
+
+/**
+ * Put a (key=integer, value=integer) item in a UHashtable.  If the
+ * keyDeleter is non-NULL, then the hashtable owns 'key' after this
+ * call.  valueDeleter must be NULL.  Storing a 0 value is the same as
+ * calling uhash_remove().
+ * @param hash The target UHashtable.
+ * @param key The key to store.
+ * @param value The integer value to store.
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return The previous value, or 0 if none.
+ * @see uhash_get
+ */
+U_CAPI int32_t U_EXPORT2 
+uhash_iputi(UHashtable *hash,
+           int32_t key,
+           int32_t value,
+           UErrorCode *status);
+
+/**
+ * Retrieve a pointer value from a UHashtable using a pointer key,
+ * as previously stored by uhash_put().
+ * @param hash The target UHashtable.
+ * @param key A pointer key stored in a hashtable
+ * @return The requested item, or NULL if not found.
+ */
+U_CAPI void* U_EXPORT2 
+uhash_get(const UHashtable *hash, 
+          const void *key);
+
+/**
+ * Retrieve a pointer value from a UHashtable using a integer key,
+ * as previously stored by uhash_iput().
+ * @param hash The target UHashtable.
+ * @param key An integer key stored in a hashtable
+ * @return The requested item, or NULL if not found.
+ */
+U_CAPI void* U_EXPORT2 
+uhash_iget(const UHashtable *hash,
+           int32_t key);
+
+/**
+ * Retrieve an integer value from a UHashtable using a pointer key,
+ * as previously stored by uhash_puti().
+ * @param hash The target UHashtable.
+ * @param key A pointer key stored in a hashtable
+ * @return The requested item, or 0 if not found.
+ */
+U_CAPI int32_t U_EXPORT2 
+uhash_geti(const UHashtable *hash,
+           const void* key);
+/**
+ * Retrieve an integer value from a UHashtable using an integer key,
+ * as previously stored by uhash_iputi().
+ * @param hash The target UHashtable.
+ * @param key An integer key stored in a hashtable
+ * @return The requested item, or 0 if not found.
+ */
+U_CAPI int32_t U_EXPORT2 
+uhash_igeti(const UHashtable *hash,
+           int32_t key);
+
+/**
+ * Remove an item from a UHashtable stored by uhash_put().
+ * @param hash The target UHashtable.
+ * @param key A key stored in a hashtable
+ * @return The item removed, or NULL if not found.
+ */
+U_CAPI void* U_EXPORT2 
+uhash_remove(UHashtable *hash,
+             const void *key);
+
+/**
+ * Remove an item from a UHashtable stored by uhash_iput().
+ * @param hash The target UHashtable.
+ * @param key An integer key stored in a hashtable
+ * @return The item removed, or NULL if not found.
+ */
+U_CAPI void* U_EXPORT2 
+uhash_iremove(UHashtable *hash,
+              int32_t key);
+
+/**
+ * Remove an item from a UHashtable stored by uhash_puti().
+ * @param hash The target UHashtable.
+ * @param key An key stored in a hashtable
+ * @return The item removed, or 0 if not found.
+ */
+U_CAPI int32_t U_EXPORT2 
+uhash_removei(UHashtable *hash,
+              const void* key);
+
+/**
+ * Remove an item from a UHashtable stored by uhash_iputi().
+ * @param hash The target UHashtable.
+ * @param key An integer key stored in a hashtable
+ * @return The item removed, or 0 if not found.
+ */
+U_CAPI int32_t U_EXPORT2 
+uhash_iremovei(UHashtable *hash,
+               int32_t key);
+
+/**
+ * Remove all items from a UHashtable.
+ * @param hash The target UHashtable.
+ */
+U_CAPI void U_EXPORT2 
+uhash_removeAll(UHashtable *hash);
+
+/**
+ * Locate an element of a UHashtable.  The caller must not modify the
+ * returned object.  The primary use of this function is to obtain the
+ * stored key when it may not be identical to the search key.  For
+ * example, if the compare function is a case-insensitive string
+ * compare, then the hash key may be desired in order to obtain the
+ * canonical case corresponding to a search key.
+ * @param hash The target UHashtable.
+ * @param key A key stored in a hashtable
+ * @return a hash element, or NULL if the key is not found.
+ */
+U_CAPI const UHashElement* U_EXPORT2 
+uhash_find(const UHashtable *hash, const void* key);
+
+/**
+ * Iterate through the elements of a UHashtable.  The caller must not
+ * modify the returned object.  However, uhash_removeElement() may be
+ * called during iteration to remove an element from the table.
+ * Iteration may safely be resumed afterwards.  If uhash_put() is
+ * called during iteration the iteration will then be out of sync and
+ * should be restarted.
+ * @param hash The target UHashtable.
+ * @param pos This should be set to -1 initially, and left untouched
+ * thereafter.
+ * @return a hash element, or NULL if no further key-value pairs
+ * exist in the table.
+ */
+U_CAPI const UHashElement* U_EXPORT2 
+uhash_nextElement(const UHashtable *hash,
+                  int32_t *pos);
+
+/**
+ * Remove an element, returned by uhash_nextElement(), from the table.
+ * Iteration may be safely continued afterwards.
+ * @param hash The hashtable
+ * @param e The element, returned by uhash_nextElement(), to remove.
+ * Must not be NULL.  Must not be an empty or deleted element (as long
+ * as this was returned by uhash_nextElement() it will not be empty or
+ * deleted).  Note: Although this parameter is const, it will be
+ * modified.
+ * @return the value that was removed.
+ */
+U_CAPI void* U_EXPORT2 
+uhash_removeElement(UHashtable *hash, const UHashElement* e);
+
+/********************************************************************
+ * UHashTok convenience
+ ********************************************************************/
+
+/**
+ * Return a UHashTok for an integer.
+ * @param i The given integer
+ * @return a UHashTok for an integer.
+ */
+/*U_CAPI UHashTok U_EXPORT2 
+uhash_toki(int32_t i);*/
+
+/**
+ * Return a UHashTok for a pointer.
+ * @param p The given pointer
+ * @return a UHashTok for a pointer.
+ */
+/*U_CAPI UHashTok U_EXPORT2 
+uhash_tokp(void* p);*/
+
+/********************************************************************
+ * UChar* and char* Support Functions
+ ********************************************************************/
+
+/**
+ * Generate a hash code for a null-terminated UChar* string.  If the
+ * string is not null-terminated do not use this function.  Use
+ * together with uhash_compareUChars.
+ * @param key The string (const UChar*) to hash.
+ * @return A hash code for the key.
+ */
+U_CAPI int32_t U_EXPORT2 
+uhash_hashUChars(const UHashTok key);
+
+/**
+ * Generate a hash code for a null-terminated char* string.  If the
+ * string is not null-terminated do not use this function.  Use
+ * together with uhash_compareChars.
+ * @param key The string (const char*) to hash.
+ * @return A hash code for the key.
+ */
+U_CAPI int32_t U_EXPORT2 
+uhash_hashChars(const UHashTok key);
+
+/* Used by UnicodeString to compute its hashcode - Not public API. */
+U_CAPI int32_t U_EXPORT2 
+uhash_hashUCharsN(const UChar *key, int32_t length);
+
+/**
+ * Generate a case-insensitive hash code for a null-terminated char*
+ * string.  If the string is not null-terminated do not use this
+ * function.  Use together with uhash_compareIChars.
+ * @param key The string (const char*) to hash.
+ * @return A hash code for the key.
+ */
+U_CAPI int32_t U_EXPORT2
+uhash_hashIChars(const UHashTok key);
+
+/**
+ * Comparator for null-terminated UChar* strings.  Use together with
+ * uhash_hashUChars.
+ * @param key1 The string for comparison
+ * @param key2 The string for comparison
+ * @return true if key1 and key2 are equal, return false otherwise.
+ */
+U_CAPI UBool U_EXPORT2 
+uhash_compareUChars(const UHashTok key1, const UHashTok key2);
+
+/**
+ * Comparator for null-terminated char* strings.  Use together with
+ * uhash_hashChars.
+ * @param key1 The string for comparison
+ * @param key2 The string for comparison
+ * @return true if key1 and key2 are equal, return false otherwise.
+ */
+U_CAPI UBool U_EXPORT2 
+uhash_compareChars(const UHashTok key1, const UHashTok key2);
+
+/**
+ * Case-insensitive comparator for null-terminated char* strings.  Use
+ * together with uhash_hashIChars.
+ * @param key1 The string for comparison
+ * @param key2 The string for comparison
+ * @return true if key1 and key2 are equal, return false otherwise.
+ */
+U_CAPI UBool U_EXPORT2 
+uhash_compareIChars(const UHashTok key1, const UHashTok key2);
+
+/********************************************************************
+ * UnicodeString Support Functions
+ ********************************************************************/
+
+/**
+ * Hash function for UnicodeString* keys.
+ * @param key The string (const char*) to hash.
+ * @return A hash code for the key.
+ */
+U_CAPI int32_t U_EXPORT2 
+uhash_hashUnicodeString(const UHashTok key);
+
+/**
+ * Hash function for UnicodeString* keys (case insensitive).
+ * Make sure to use together with uhash_compareCaselessUnicodeString.
+ * @param key The string (const char*) to hash.
+ * @return A hash code for the key.
+ */
+U_CAPI int32_t U_EXPORT2 
+uhash_hashCaselessUnicodeString(const UHashTok key);
+
+/**
+ * Comparator function for UnicodeString* keys.
+ * @param key1 The string for comparison
+ * @param key2 The string for comparison
+ * @return true if key1 and key2 are equal, return false otherwise.
+ */
+U_CAPI UBool U_EXPORT2 
+uhash_compareUnicodeString(const UHashTok key1, const UHashTok key2);
+
+/**
+ * Comparator function for UnicodeString* keys (case insensitive).
+ * Make sure to use together with uhash_hashCaselessUnicodeString.
+ * @param key1 The string for comparison
+ * @param key2 The string for comparison
+ * @return true if key1 and key2 are equal, return false otherwise.
+ */
+U_CAPI UBool U_EXPORT2 
+uhash_compareCaselessUnicodeString(const UHashTok key1, const UHashTok key2);
+
+/**
+ * Deleter function for UnicodeString* keys or values.
+ * @param obj The object to be deleted
+ */
+U_CAPI void U_EXPORT2 
+uhash_deleteUnicodeString(void *obj);
+
+/********************************************************************
+ * int32_t Support Functions
+ ********************************************************************/
+
+/**
+ * Hash function for 32-bit integer keys.
+ * @param key The string (const char*) to hash.
+ * @return A hash code for the key.
+ */
+U_CAPI int32_t U_EXPORT2 
+uhash_hashLong(const UHashTok key);
+
+/**
+ * Comparator function for 32-bit integer keys.
+ * @param key1 The integer for comparison
+ * @param Key2 The integer for comparison
+ * @return true if key1 and key2 are equal, return false otherwise
+ */
+U_CAPI UBool U_EXPORT2 
+uhash_compareLong(const UHashTok key1, const UHashTok key2);
+
+/********************************************************************
+ * Other Support Functions
+ ********************************************************************/
+
+/**
+ * Deleter for Hashtable objects.
+ * @param obj The object to be deleted
+ */
+U_CAPI void U_EXPORT2 
+uhash_deleteHashtable(void *obj);
+
+/**
+ * Deleter for UObject instances.
+ * @param obj The object to be deleted
+ */
+U_CAPI void U_EXPORT2 
+uhash_deleteUObject(void *obj);
+
+/**
+ * Deleter for any key or value allocated using uprv_malloc.  Calls
+ * uprv_free.
+ * @param obj The object to be deleted
+ */
+U_CAPI void U_EXPORT2 
+uhash_freeBlock(void *obj);
+
+/**
+ * Checks if the given hash tables are equal or not.
+ * @param hash1
+ * @param hash2
+ * @return true if the hashtables are equal and false if not.
+ */
+U_CAPI UBool U_EXPORT2 
+uhash_equals(const UHashtable* hash1, const UHashtable* hash2);
+
+#endif
diff --git a/source/common/uhash_us.cpp b/source/common/uhash_us.cpp
new file mode 100644
index 0000000..c4ca3ca
--- /dev/null
+++ b/source/common/uhash_us.cpp
@@ -0,0 +1,68 @@
+/*
+******************************************************************************
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+******************************************************************************
+*   Date        Name        Description
+*   03/22/00    aliu        Creation.
+*   07/06/01    aliu        Modified to support int32_t keys on
+*                           platforms with sizeof(void*) < 32.
+******************************************************************************
+*/
+
+#include "uhash.h"
+#include "hash.h"
+#include "uvector.h"
+#include "unicode/unistr.h"
+#include "unicode/uchar.h"
+
+/********************************************************************
+ * PUBLIC UnicodeString support functions for UHashtable
+ ********************************************************************/
+
+U_CAPI int32_t U_EXPORT2
+uhash_hashUnicodeString(const UHashTok key) {
+    U_NAMESPACE_USE
+    const UnicodeString *str = (const UnicodeString*) key.pointer;
+    return (str == NULL) ? 0 : str->hashCode();
+}
+
+U_CAPI void U_EXPORT2
+uhash_deleteUnicodeString(void *obj) {
+    U_NAMESPACE_USE
+    delete (UnicodeString*) obj;
+}
+
+U_CAPI UBool U_EXPORT2
+uhash_compareUnicodeString(const UHashTok key1, const UHashTok key2) {
+    U_NAMESPACE_USE
+    const UnicodeString *str1 = (const UnicodeString*) key1.pointer;
+    const UnicodeString *str2 = (const UnicodeString*) key2.pointer;
+    if (str1 == str2) {
+        return TRUE;
+    }
+    if (str1 == NULL || str2 == NULL) {
+        return FALSE;
+    }
+    return *str1 == *str2;
+}
+
+/**
+ * Deleter for Hashtable objects.
+ */
+U_CAPI void U_EXPORT2
+uhash_deleteHashtable(void *obj) {
+    U_NAMESPACE_USE
+    delete (Hashtable*) obj;
+}
+
+/**
+ * Deleter for UObject instances.
+ */
+U_CAPI void U_EXPORT2
+uhash_deleteUObject(void *obj) {
+    U_NAMESPACE_USE
+    delete (UObject*) obj;
+}
+
+//eof
diff --git a/source/common/uidna.cpp b/source/common/uidna.cpp
new file mode 100644
index 0000000..b7780b8
--- /dev/null
+++ b/source/common/uidna.cpp
@@ -0,0 +1,921 @@
+/*
+ *******************************************************************************
+ *
+ *   Copyright (C) 2003-2009, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ *
+ *******************************************************************************
+ *   file name:  uidna.cpp
+ *   encoding:   US-ASCII
+ *   tab size:   8 (not used)
+ *   indentation:4
+ *
+ *   created on: 2003feb1
+ *   created by: Ram Viswanadha
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_IDNA
+
+#include "unicode/uidna.h"
+#include "unicode/ustring.h"
+#include "unicode/usprep.h"
+#include "punycode.h"
+#include "ustr_imp.h"
+#include "cmemory.h"
+#include "uassert.h"
+#include "sprpimpl.h"
+
+/* it is official IDNA ACE Prefix is "xn--" */
+static const UChar ACE_PREFIX[] ={ 0x0078,0x006E,0x002d,0x002d } ;
+#define ACE_PREFIX_LENGTH 4
+
+#define MAX_LABEL_LENGTH 63
+/* The Max length of the labels should not be more than MAX_LABEL_LENGTH */
+#define MAX_LABEL_BUFFER_SIZE 100
+
+#define MAX_DOMAIN_NAME_LENGTH 255
+/* The Max length of the domain names should not be more than MAX_DOMAIN_NAME_LENGTH */
+#define MAX_IDN_BUFFER_SIZE   MAX_DOMAIN_NAME_LENGTH+1
+
+#define LOWER_CASE_DELTA 0x0020
+#define HYPHEN           0x002D
+#define FULL_STOP        0x002E
+#define CAPITAL_A        0x0041
+#define CAPITAL_Z        0x005A
+
+inline static UChar 
+toASCIILower(UChar ch){
+    if(CAPITAL_A <= ch && ch <= CAPITAL_Z){
+        return ch + LOWER_CASE_DELTA;
+    }
+    return ch;
+}
+
+inline static UBool 
+startsWithPrefix(const UChar* src , int32_t srcLength){
+    UBool startsWithPrefix = TRUE;
+
+    if(srcLength < ACE_PREFIX_LENGTH){
+        return FALSE;
+    }
+
+    for(int8_t i=0; i< ACE_PREFIX_LENGTH; i++){
+        if(toASCIILower(src[i]) != ACE_PREFIX[i]){
+            startsWithPrefix = FALSE;
+        }
+    }
+    return startsWithPrefix;
+}
+
+
+inline static int32_t
+compareCaseInsensitiveASCII(const UChar* s1, int32_t s1Len, 
+                            const UChar* s2, int32_t s2Len){
+    
+    int32_t minLength;
+    int32_t lengthResult;
+
+    // are we comparing different lengths?
+    if(s1Len != s2Len) {
+        if(s1Len < s2Len) {
+            minLength = s1Len;
+            lengthResult = -1;
+        } else {
+            minLength = s2Len;
+            lengthResult = 1;
+        }
+    } else {
+        // ok the lengths are equal
+        minLength = s1Len;
+        lengthResult = 0;
+    }
+
+    UChar c1,c2;
+    int32_t rc;
+
+    for(int32_t i =0;/* no condition */;i++) {
+
+        /* If we reach the ends of both strings then they match */
+        if(i == minLength) {
+            return lengthResult;
+        }
+        
+        c1 = s1[i];
+        c2 = s2[i];
+        
+        /* Case-insensitive comparison */
+        if(c1!=c2) {
+            rc=(int32_t)toASCIILower(c1)-(int32_t)toASCIILower(c2);
+            if(rc!=0) {
+                lengthResult=rc;
+                break;
+            }
+        }
+    }
+    return lengthResult;
+}
+
+
+/**
+ * Ascertain if the given code point is a label separator as 
+ * defined by the IDNA RFC
+ * 
+ * @param ch The code point to be ascertained
+ * @return true if the char is a label separator
+ * @stable ICU 2.8
+ */
+static inline UBool isLabelSeparator(UChar ch){
+    switch(ch){
+        case 0x002e:
+        case 0x3002:
+        case 0xFF0E:
+        case 0xFF61:
+            return TRUE;
+        default:
+            return FALSE;           
+    }
+}
+
+// returns the length of the label excluding the separator
+// if *limit == separator then the length returned does not include 
+// the separtor.
+static inline int32_t
+getNextSeparator(UChar *src, int32_t srcLength,
+                 UChar **limit, UBool *done){
+    if(srcLength == -1){
+        int32_t i;
+        for(i=0 ; ;i++){
+            if(src[i] == 0){
+                *limit = src + i; // point to null
+                *done = TRUE;
+                return i;
+            }
+            if(isLabelSeparator(src[i])){
+                *limit = src + (i+1); // go past the delimiter
+                return i;
+                
+            }
+        }
+    }else{
+        int32_t i;
+        for(i=0;i<srcLength;i++){
+            if(isLabelSeparator(src[i])){
+                *limit = src + (i+1); // go past the delimiter
+                return i;
+            }
+        }
+        // we have not found the delimiter
+        // if(i==srcLength)
+        *limit = src+srcLength;
+        *done = TRUE;
+
+        return i;
+    }
+}
+static inline UBool isLDHChar(UChar ch){
+    // high runner case
+    if(ch>0x007A){
+        return FALSE;
+    }
+    //[\\u002D \\u0030-\\u0039 \\u0041-\\u005A \\u0061-\\u007A]
+    if( (ch==0x002D) || 
+        (0x0030 <= ch && ch <= 0x0039) ||
+        (0x0041 <= ch && ch <= 0x005A) ||
+        (0x0061 <= ch && ch <= 0x007A)
+      ){
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static int32_t 
+_internal_toASCII(const UChar* src, int32_t srcLength, 
+                  UChar* dest, int32_t destCapacity,
+                  int32_t options,
+                  UStringPrepProfile* nameprep,
+                  UParseError* parseError,
+                  UErrorCode* status)
+{
+
+    // TODO Revisit buffer handling. The label should not be over 63 ASCII characters. ICU4J may need to be updated too.
+    UChar b1Stack[MAX_LABEL_BUFFER_SIZE], b2Stack[MAX_LABEL_BUFFER_SIZE];
+    //initialize pointers to stack buffers
+    UChar  *b1 = b1Stack, *b2 = b2Stack;
+    int32_t b1Len=0, b2Len, 
+            b1Capacity = MAX_LABEL_BUFFER_SIZE, 
+            b2Capacity = MAX_LABEL_BUFFER_SIZE ,
+            reqLength=0;
+
+    int32_t namePrepOptions = ((options & UIDNA_ALLOW_UNASSIGNED) != 0) ? USPREP_ALLOW_UNASSIGNED: 0;
+    UBool* caseFlags = NULL;
+    
+    // the source contains all ascii codepoints
+    UBool srcIsASCII  = TRUE;
+    // assume the source contains all LDH codepoints
+    UBool srcIsLDH = TRUE; 
+
+    int32_t j=0;
+
+    //get the options
+    UBool useSTD3ASCIIRules = (UBool)((options & UIDNA_USE_STD3_RULES) != 0);
+
+    int32_t failPos = -1;
+    
+    if(srcLength == -1){
+        srcLength = u_strlen(src);
+    }
+    
+    if(srcLength > b1Capacity){
+        b1 = (UChar*) uprv_malloc(srcLength * U_SIZEOF_UCHAR);
+        if(b1==NULL){
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            goto CLEANUP;
+        }
+        b1Capacity = srcLength;
+    }
+
+    // step 1 
+    for( j=0;j<srcLength;j++){
+        if(src[j] > 0x7F){
+            srcIsASCII = FALSE;
+        }
+        b1[b1Len++] = src[j];
+    }
+    
+    // step 2 is performed only if the source contains non ASCII
+    if(srcIsASCII == FALSE){
+        
+        // step 2    
+        b1Len = usprep_prepare(nameprep, src, srcLength, b1, b1Capacity, namePrepOptions, parseError, status);
+
+        if(*status == U_BUFFER_OVERFLOW_ERROR){
+            // redo processing of string
+            // we do not have enough room so grow the buffer
+            if(b1 != b1Stack){
+                uprv_free(b1);
+            }
+            b1 = (UChar*) uprv_malloc(b1Len * U_SIZEOF_UCHAR);
+            if(b1==NULL){
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                goto CLEANUP;
+            }
+
+            *status = U_ZERO_ERROR; // reset error
+            
+            b1Len = usprep_prepare(nameprep, src, srcLength, b1, b1Len, namePrepOptions, parseError, status);
+        }
+    }
+    // error bail out
+    if(U_FAILURE(*status)){
+        goto CLEANUP;
+    }
+    if(b1Len == 0){
+        *status = U_IDNA_ZERO_LENGTH_LABEL_ERROR;
+        goto CLEANUP;
+    }
+
+    // for step 3 & 4
+    srcIsASCII = TRUE;
+    for( j=0;j<b1Len;j++){
+        // check if output of usprep_prepare is all ASCII 
+        if(b1[j] > 0x7F){
+            srcIsASCII = FALSE;
+        }else if(isLDHChar(b1[j])==FALSE){  // if the char is in ASCII range verify that it is an LDH character
+            srcIsLDH = FALSE;
+            failPos = j;
+        }
+    }
+    if(useSTD3ASCIIRules == TRUE){
+        // verify 3a and 3b
+        // 3(a) Verify the absence of non-LDH ASCII code points; that is, the
+        //  absence of 0..2C, 2E..2F, 3A..40, 5B..60, and 7B..7F.
+        // 3(b) Verify the absence of leading and trailing hyphen-minus; that
+        //  is, the absence of U+002D at the beginning and end of the
+        //  sequence.
+        if( srcIsLDH == FALSE /* source at this point should not contain anyLDH characters */
+            || b1[0] ==  HYPHEN || b1[b1Len-1] == HYPHEN){
+            *status = U_IDNA_STD3_ASCII_RULES_ERROR;
+
+            /* populate the parseError struct */
+            if(srcIsLDH==FALSE){
+                // failPos is always set the index of failure
+                uprv_syntaxError(b1,failPos, b1Len,parseError);
+            }else if(b1[0] == HYPHEN){
+                // fail position is 0 
+                uprv_syntaxError(b1,0,b1Len,parseError);
+            }else{
+                // the last index in the source is always length-1
+                uprv_syntaxError(b1, (b1Len>0) ? b1Len-1 : b1Len, b1Len,parseError);
+            }
+
+            goto CLEANUP;
+        }
+    }
+    // Step 4: if the source is ASCII then proceed to step 8
+    if(srcIsASCII){
+        if(b1Len <= destCapacity){
+            uprv_memmove(dest, b1, b1Len * U_SIZEOF_UCHAR);
+            reqLength = b1Len;
+        }else{
+            reqLength = b1Len;
+            goto CLEANUP;
+        }
+    }else{
+        // step 5 : verify the sequence does not begin with ACE prefix
+        if(!startsWithPrefix(b1,b1Len)){
+
+            //step 6: encode the sequence with punycode
+
+            // do not preserve the case flags for now!
+            // TODO: Preserve the case while implementing the RFE
+            // caseFlags = (UBool*) uprv_malloc(b1Len * sizeof(UBool));
+            // uprv_memset(caseFlags,TRUE,b1Len);
+
+            b2Len = u_strToPunycode(b1,b1Len,b2,b2Capacity,caseFlags, status);
+
+            if(*status == U_BUFFER_OVERFLOW_ERROR){
+                // redo processing of string
+                /* we do not have enough room so grow the buffer*/
+                b2 = (UChar*) uprv_malloc(b2Len * U_SIZEOF_UCHAR); 
+                if(b2 == NULL){
+                    *status = U_MEMORY_ALLOCATION_ERROR;
+                    goto CLEANUP;
+                }
+
+                *status = U_ZERO_ERROR; // reset error
+                
+                b2Len = u_strToPunycode(b1,b1Len,b2,b2Len,caseFlags, status);
+            }
+            //error bail out
+            if(U_FAILURE(*status)){
+                goto CLEANUP;
+            }
+            // TODO : Reconsider while implementing the case preserve RFE
+            // convert all codepoints to lower case ASCII
+            // toASCIILower(b2,b2Len);
+            reqLength = b2Len+ACE_PREFIX_LENGTH;
+
+            if(reqLength > destCapacity){
+                *status = U_BUFFER_OVERFLOW_ERROR;
+                goto CLEANUP;
+            }
+            //Step 7: prepend the ACE prefix
+            uprv_memcpy(dest,ACE_PREFIX,ACE_PREFIX_LENGTH * U_SIZEOF_UCHAR);
+            //Step 6: copy the contents in b2 into dest
+            uprv_memcpy(dest+ACE_PREFIX_LENGTH, b2, b2Len * U_SIZEOF_UCHAR);
+
+        }else{
+            *status = U_IDNA_ACE_PREFIX_ERROR; 
+            //position of failure is 0
+            uprv_syntaxError(b1,0,b1Len,parseError);
+            goto CLEANUP;
+        }
+    }
+    // step 8: verify the length of label
+    if(reqLength > MAX_LABEL_LENGTH){
+        *status = U_IDNA_LABEL_TOO_LONG_ERROR;
+    }
+
+CLEANUP:
+    if(b1 != b1Stack){
+        uprv_free(b1);
+    }
+    if(b2 != b2Stack){
+        uprv_free(b2);
+    }
+    uprv_free(caseFlags);
+    
+    return u_terminateUChars(dest, destCapacity, reqLength, status);
+}
+
+static int32_t
+_internal_toUnicode(const UChar* src, int32_t srcLength,
+                    UChar* dest, int32_t destCapacity,
+                    int32_t options,
+                    UStringPrepProfile* nameprep,
+                    UParseError* parseError,
+                    UErrorCode* status)
+{
+
+    //get the options
+    //UBool useSTD3ASCIIRules = (UBool)((options & UIDNA_USE_STD3_RULES) != 0);
+    int32_t namePrepOptions = ((options & UIDNA_ALLOW_UNASSIGNED) != 0) ? USPREP_ALLOW_UNASSIGNED: 0; 
+
+    // TODO Revisit buffer handling. The label should not be over 63 ASCII characters. ICU4J may need to be updated too.
+    UChar b1Stack[MAX_LABEL_BUFFER_SIZE], b2Stack[MAX_LABEL_BUFFER_SIZE], b3Stack[MAX_LABEL_BUFFER_SIZE];
+
+    //initialize pointers to stack buffers
+    UChar  *b1 = b1Stack, *b2 = b2Stack, *b1Prime=NULL, *b3=b3Stack;
+    int32_t b1Len, b2Len, b1PrimeLen, b3Len,
+            b1Capacity = MAX_LABEL_BUFFER_SIZE, 
+            b2Capacity = MAX_LABEL_BUFFER_SIZE,
+            b3Capacity = MAX_LABEL_BUFFER_SIZE,
+            reqLength=0;
+
+    b1Len = 0;
+    UBool* caseFlags = NULL;
+
+    UBool srcIsASCII = TRUE;
+    /*UBool srcIsLDH = TRUE;
+    int32_t failPos =0;*/
+
+    // step 1: find out if all the codepoints in src are ASCII  
+    if(srcLength==-1){
+        srcLength = 0;
+        for(;src[srcLength]!=0;){
+            if(src[srcLength]> 0x7f){
+                srcIsASCII = FALSE;
+            }/*else if(isLDHChar(src[srcLength])==FALSE){
+                // here we do not assemble surrogates
+                // since we know that LDH code points
+                // are in the ASCII range only
+                srcIsLDH = FALSE;
+                failPos = srcLength;
+            }*/
+            srcLength++;
+        }
+    }else if(srcLength > 0){
+        for(int32_t j=0; j<srcLength; j++){
+            if(src[j]> 0x7f){
+                srcIsASCII = FALSE;
+            }/*else if(isLDHChar(src[j])==FALSE){
+                // here we do not assemble surrogates
+                // since we know that LDH code points
+                // are in the ASCII range only
+                srcIsLDH = FALSE;
+                failPos = j;
+            }*/
+        }
+    }else{
+        return 0;
+    }
+    
+    if(srcIsASCII == FALSE){
+        // step 2: process the string
+        b1Len = usprep_prepare(nameprep, src, srcLength, b1, b1Capacity, namePrepOptions, parseError, status);
+        if(*status == U_BUFFER_OVERFLOW_ERROR){
+            // redo processing of string
+            /* we do not have enough room so grow the buffer*/
+            b1 = (UChar*) uprv_malloc(b1Len * U_SIZEOF_UCHAR);
+            if(b1==NULL){
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                goto CLEANUP;
+            }
+
+            *status = U_ZERO_ERROR; // reset error
+            
+            b1Len = usprep_prepare(nameprep, src, srcLength, b1, b1Len, namePrepOptions, parseError, status);
+        }
+        //bail out on error
+        if(U_FAILURE(*status)){
+            goto CLEANUP;
+        }
+    }else{
+
+        //just point src to b1
+        b1 = (UChar*) src;
+        b1Len = srcLength;
+    }
+
+    // The RFC states that 
+    // <quote>
+    // ToUnicode never fails. If any step fails, then the original input
+    // is returned immediately in that step.
+    // </quote>
+
+    //step 3: verify ACE Prefix
+    if(startsWithPrefix(b1,b1Len)){
+
+        //step 4: Remove the ACE Prefix
+        b1Prime = b1 + ACE_PREFIX_LENGTH;
+        b1PrimeLen  = b1Len - ACE_PREFIX_LENGTH;
+
+        //step 5: Decode using punycode
+        b2Len = u_strFromPunycode(b1Prime, b1PrimeLen, b2, b2Capacity, caseFlags,status);
+
+        if(*status == U_BUFFER_OVERFLOW_ERROR){
+            // redo processing of string
+            /* we do not have enough room so grow the buffer*/
+            b2 = (UChar*) uprv_malloc(b2Len * U_SIZEOF_UCHAR);
+            if(b2==NULL){
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                goto CLEANUP;
+            }
+
+            *status = U_ZERO_ERROR; // reset error
+
+            b2Len =  u_strFromPunycode(b1Prime, b1PrimeLen, b2, b2Len, caseFlags, status);
+        }
+
+
+        //step 6:Apply toASCII
+        b3Len = uidna_toASCII(b2, b2Len, b3, b3Capacity, options, parseError, status);
+
+        if(*status == U_BUFFER_OVERFLOW_ERROR){
+            // redo processing of string
+            /* we do not have enough room so grow the buffer*/
+            b3 = (UChar*) uprv_malloc(b3Len * U_SIZEOF_UCHAR);
+            if(b3==NULL){
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                goto CLEANUP;
+            }
+
+            *status = U_ZERO_ERROR; // reset error
+
+            b3Len =  uidna_toASCII(b2,b2Len,b3,b3Len,options,parseError, status);
+
+        }
+        //bail out on error
+        if(U_FAILURE(*status)){
+            goto CLEANUP;
+        }
+
+        //step 7: verify
+        if(compareCaseInsensitiveASCII(b1, b1Len, b3, b3Len) !=0){
+            // Cause the original to be returned.
+            *status = U_IDNA_VERIFICATION_ERROR;
+            goto CLEANUP;
+        }
+
+        //step 8: return output of step 5
+        reqLength = b2Len;
+        if(b2Len <= destCapacity) {
+            uprv_memmove(dest, b2, b2Len * U_SIZEOF_UCHAR);
+        }
+    }
+    else{
+        // See the start of this if statement for why this is commented out.
+        // verify that STD3 ASCII rules are satisfied
+        /*if(useSTD3ASCIIRules == TRUE){
+            if( srcIsLDH == FALSE // source contains some non-LDH characters
+                || src[0] ==  HYPHEN || src[srcLength-1] == HYPHEN){
+                *status = U_IDNA_STD3_ASCII_RULES_ERROR;
+
+                // populate the parseError struct
+                if(srcIsLDH==FALSE){
+                    // failPos is always set the index of failure
+                    uprv_syntaxError(src,failPos, srcLength,parseError);
+                }else if(src[0] == HYPHEN){
+                    // fail position is 0 
+                    uprv_syntaxError(src,0,srcLength,parseError);
+                }else{
+                    // the last index in the source is always length-1
+                    uprv_syntaxError(src, (srcLength>0) ? srcLength-1 : srcLength, srcLength,parseError);
+                }
+
+                goto CLEANUP;
+            }
+        }*/
+        // just return the source
+        //copy the source to destination
+        if(srcLength <= destCapacity){
+            uprv_memmove(dest,src,srcLength * U_SIZEOF_UCHAR);
+        }
+        reqLength = srcLength;
+    }
+
+
+CLEANUP:
+
+    if(b1 != b1Stack && b1!=src){
+        uprv_free(b1);
+    }
+    if(b2 != b2Stack){
+        uprv_free(b2);
+    }
+    uprv_free(caseFlags);
+
+    // The RFC states that 
+    // <quote>
+    // ToUnicode never fails. If any step fails, then the original input
+    // is returned immediately in that step.
+    // </quote>
+    // So if any step fails lets copy source to destination
+    if(U_FAILURE(*status)){
+        //copy the source to destination
+        if(dest && srcLength <= destCapacity){
+            // srcLength should have already been set earlier.
+            U_ASSERT(srcLength >= 0);
+            uprv_memmove(dest,src,srcLength * U_SIZEOF_UCHAR);
+        }
+        reqLength = srcLength;
+        *status = U_ZERO_ERROR;
+    }
+
+    return u_terminateUChars(dest, destCapacity, reqLength, status);
+}
+
+U_CAPI int32_t U_EXPORT2
+uidna_toASCII(const UChar* src, int32_t srcLength, 
+              UChar* dest, int32_t destCapacity,
+              int32_t options,
+              UParseError* parseError,
+              UErrorCode* status){
+    
+    if(status == NULL || U_FAILURE(*status)){
+        return 0;
+    }
+    if((src==NULL) || (srcLength < -1) || (destCapacity<0) || (!dest && destCapacity > 0)){
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    UStringPrepProfile* nameprep = usprep_openByType(USPREP_RFC3491_NAMEPREP, status);
+    
+    if(U_FAILURE(*status)){
+        return -1;
+    }
+    
+    int32_t retLen = _internal_toASCII(src, srcLength, dest, destCapacity, options, nameprep, parseError, status);
+    
+    /* close the profile*/
+    usprep_close(nameprep);
+    
+    return retLen;
+}
+
+U_CAPI int32_t U_EXPORT2
+uidna_toUnicode(const UChar* src, int32_t srcLength,
+                UChar* dest, int32_t destCapacity,
+                int32_t options,
+                UParseError* parseError,
+                UErrorCode* status){
+
+    if(status == NULL || U_FAILURE(*status)){
+        return 0;
+    }
+    if( (src==NULL) || (srcLength < -1) || (destCapacity<0) || (!dest && destCapacity > 0)){
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }  
+
+    UStringPrepProfile* nameprep = usprep_openByType(USPREP_RFC3491_NAMEPREP, status);
+    
+    if(U_FAILURE(*status)){
+        return -1;
+    }
+    
+    int32_t retLen = _internal_toUnicode(src, srcLength, dest, destCapacity, options, nameprep, parseError, status);
+
+    usprep_close(nameprep);
+    
+    return retLen;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uidna_IDNToASCII(  const UChar *src, int32_t srcLength,
+                   UChar* dest, int32_t destCapacity,
+                   int32_t options,
+                   UParseError *parseError,
+                   UErrorCode *status){
+
+    if(status == NULL || U_FAILURE(*status)){
+        return 0;
+    }
+    if((src==NULL) || (srcLength < -1) || (destCapacity<0) || (!dest && destCapacity > 0)){
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    int32_t reqLength = 0;
+
+    UStringPrepProfile* nameprep = usprep_openByType(USPREP_RFC3491_NAMEPREP, status);
+    
+    if(U_FAILURE(*status)){
+        return 0;
+    }
+
+    //initialize pointers 
+    UChar *delimiter = (UChar*)src;
+    UChar *labelStart = (UChar*)src;
+    UChar *currentDest = (UChar*) dest;
+    int32_t remainingLen = srcLength;
+    int32_t remainingDestCapacity = destCapacity;
+    int32_t labelLen = 0, labelReqLength = 0;
+    UBool done = FALSE;
+
+
+    for(;;){
+
+        labelLen = getNextSeparator(labelStart,remainingLen, &delimiter,&done);
+        labelReqLength = 0;
+        if(!(labelLen==0 && done)){// make sure this is not a root label separator.
+        
+            labelReqLength = _internal_toASCII( labelStart, labelLen, 
+                                                currentDest, remainingDestCapacity, 
+                                                options, nameprep, 
+                                                parseError, status);
+    
+            if(*status == U_BUFFER_OVERFLOW_ERROR){
+                
+                *status = U_ZERO_ERROR; // reset error
+                remainingDestCapacity = 0;
+            }
+        }
+
+    
+        if(U_FAILURE(*status)){
+            break;
+        }
+        
+        reqLength +=labelReqLength;
+        // adjust the destination pointer
+        if(labelReqLength < remainingDestCapacity){
+            currentDest = currentDest + labelReqLength;
+            remainingDestCapacity -= labelReqLength;
+        }else{
+            // should never occur
+            remainingDestCapacity = 0;
+        }
+
+        if(done == TRUE){
+            break;
+        }
+
+        // add the label separator
+        if(remainingDestCapacity > 0){
+            *currentDest++ = FULL_STOP;
+            remainingDestCapacity--;
+        }
+        reqLength++;
+
+        labelStart = delimiter;
+        if(remainingLen >0 ){
+            remainingLen = (int32_t)(srcLength - (delimiter - src));
+        }
+
+    }
+
+    if(reqLength > MAX_DOMAIN_NAME_LENGTH){
+        *status = U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR;
+    }
+
+    usprep_close(nameprep);
+    
+    return u_terminateUChars(dest, destCapacity, reqLength, status);
+}
+
+U_CAPI int32_t U_EXPORT2
+uidna_IDNToUnicode(  const UChar* src, int32_t srcLength,
+                     UChar* dest, int32_t destCapacity,
+                     int32_t options,
+                     UParseError* parseError,
+                     UErrorCode* status){
+    
+    if(status == NULL || U_FAILURE(*status)){
+        return 0;
+    }
+    if((src==NULL) || (srcLength < -1) || (destCapacity<0) || (!dest && destCapacity > 0)){
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    int32_t reqLength = 0;
+
+    UStringPrepProfile* nameprep = usprep_openByType(USPREP_RFC3491_NAMEPREP, status);
+    
+    if(U_FAILURE(*status)){
+        return 0;
+    }
+
+    //initialize pointers
+    UChar *delimiter = (UChar*)src;
+    UChar *labelStart = (UChar*)src;
+    UChar *currentDest = (UChar*) dest;
+    int32_t remainingLen = srcLength;
+    int32_t remainingDestCapacity = destCapacity;
+    int32_t labelLen = 0, labelReqLength = 0;
+    UBool done = FALSE;
+
+    for(;;){
+
+        labelLen = getNextSeparator(labelStart,remainingLen, &delimiter,&done);
+        
+        // The RFC states that 
+        // <quote>
+        // ToUnicode never fails. If any step fails, then the original input
+        // is returned immediately in that step.
+        // </quote>
+        // _internal_toUnicode will copy the label.
+        /*if(labelLen==0 && done==FALSE){ 
+            *status = U_IDNA_ZERO_LENGTH_LABEL_ERROR;
+            break;
+        }*/
+        
+        labelReqLength = _internal_toUnicode(labelStart, labelLen, 
+                                             currentDest, remainingDestCapacity, 
+                                             options, nameprep, 
+                                             parseError, status);
+
+        if(*status == U_BUFFER_OVERFLOW_ERROR){
+            *status = U_ZERO_ERROR; // reset error
+            remainingDestCapacity = 0;
+        }
+
+        if(U_FAILURE(*status)){
+            break;
+        }
+        
+        reqLength +=labelReqLength;
+        // adjust the destination pointer
+        if(labelReqLength < remainingDestCapacity){
+            currentDest = currentDest + labelReqLength;
+            remainingDestCapacity -= labelReqLength;
+        }else{
+            // should never occur
+            remainingDestCapacity = 0;
+        }
+
+        if(done == TRUE){
+            break;
+        }
+
+        // add the label separator
+        // Unlike the ToASCII operation we don't normalize the label separators
+        if(remainingDestCapacity > 0){
+            *currentDest++ = *(labelStart + labelLen);
+            remainingDestCapacity--;
+        }
+        reqLength++;
+
+        labelStart = delimiter;
+        if(remainingLen >0 ){
+            remainingLen = (int32_t)(srcLength - (delimiter - src));
+        }
+
+    }
+
+    if(reqLength > MAX_DOMAIN_NAME_LENGTH){
+        *status = U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR;
+    }
+
+    usprep_close(nameprep);
+    
+    return u_terminateUChars(dest, destCapacity, reqLength, status);
+}
+
+U_CAPI int32_t U_EXPORT2
+uidna_compare(  const UChar *s1, int32_t length1,
+                const UChar *s2, int32_t length2,
+                int32_t options,
+                UErrorCode* status){
+
+    if(status == NULL || U_FAILURE(*status)){
+        return -1;
+    }
+
+    UChar b1Stack[MAX_IDN_BUFFER_SIZE], b2Stack[MAX_IDN_BUFFER_SIZE];
+    UChar *b1 = b1Stack, *b2 = b2Stack;
+    int32_t b1Len, b2Len, b1Capacity = MAX_IDN_BUFFER_SIZE, b2Capacity = MAX_IDN_BUFFER_SIZE;
+    int32_t result=-1;
+    
+    UParseError parseError;
+
+    b1Len = uidna_IDNToASCII(s1, length1, b1, b1Capacity, options, &parseError, status);
+    if(*status == U_BUFFER_OVERFLOW_ERROR){
+        // redo processing of string
+        b1 = (UChar*) uprv_malloc(b1Len * U_SIZEOF_UCHAR);
+        if(b1==NULL){
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            goto CLEANUP;
+        }
+
+        *status = U_ZERO_ERROR; // reset error
+        
+        b1Len = uidna_IDNToASCII(s1,length1,b1,b1Len, options, &parseError, status);
+        
+    }
+
+    b2Len = uidna_IDNToASCII(s2,length2, b2,b2Capacity, options, &parseError, status);
+    if(*status == U_BUFFER_OVERFLOW_ERROR){
+        // redo processing of string
+        b2 = (UChar*) uprv_malloc(b2Len * U_SIZEOF_UCHAR);
+        if(b2==NULL){
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            goto CLEANUP;
+        }
+
+        *status = U_ZERO_ERROR; // reset error
+        
+        b2Len = uidna_IDNToASCII(s2, length2, b2, b2Len, options, &parseError, status);
+        
+    }
+    // when toASCII is applied all label separators are replaced with FULL_STOP
+    result = compareCaseInsensitiveASCII(b1,b1Len,b2,b2Len);
+
+CLEANUP:
+    if(b1 != b1Stack){
+        uprv_free(b1);
+    }
+
+    if(b2 != b2Stack){
+        uprv_free(b2);
+    }
+
+    return result;
+}
+
+#endif /* #if !UCONFIG_NO_IDNA */
diff --git a/source/common/uinit.c b/source/common/uinit.c
new file mode 100644
index 0000000..530d213
--- /dev/null
+++ b/source/common/uinit.c
@@ -0,0 +1,91 @@
+/*
+******************************************************************************
+*                                                                            *
+* Copyright (C) 2001-2010, International Business Machines                   *
+*                Corporation and others. All Rights Reserved.                *
+*                                                                            *
+******************************************************************************
+*   file name:  uinit.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2001July05
+*   created by: George Rhoten
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/icuplug.h"
+#include "unicode/uclean.h"
+#include "cmemory.h"
+#include "icuplugimp.h"
+#include "uassert.h"
+#include "ucln.h"
+#include "ucln_cmn.h"
+#include "ucnv_io.h"
+#include "umutex.h"
+#include "utracimp.h"
+
+static UBool gICUInitialized = FALSE;
+static UMTX  gICUInitMutex   = NULL;
+
+
+/************************************************
+ The cleanup order is important in this function.
+ Please be sure that you have read ucln.h
+ ************************************************/
+U_CAPI void U_EXPORT2
+u_cleanup(void)
+{
+    UTRACE_ENTRY_OC(UTRACE_U_CLEANUP);
+    umtx_lock(NULL);     /* Force a memory barrier, so that we are sure to see   */
+    umtx_unlock(NULL);   /*   all state left around by any other threads.        */
+
+    ucln_lib_cleanup();
+
+    umtx_destroy(&gICUInitMutex);
+    umtx_cleanup();
+    cmemory_cleanup();       /* undo any heap functions set by u_setMemoryFunctions(). */
+    gICUInitialized = FALSE;
+    UTRACE_EXIT();           /* Must be before utrace_cleanup(), which turns off tracing. */
+/*#if U_ENABLE_TRACING*/
+    utrace_cleanup();
+/*#endif*/
+}
+
+/*
+ * ICU Initialization Function. Need not be called.
+ */
+U_CAPI void U_EXPORT2
+u_init(UErrorCode *status) {
+    UTRACE_ENTRY_OC(UTRACE_U_INIT);
+    /* initialize plugins */
+    uplug_init(status);
+
+    umtx_lock(&gICUInitMutex);
+    if (gICUInitialized || U_FAILURE(*status)) {
+        umtx_unlock(&gICUInitMutex);
+        UTRACE_EXIT_STATUS(*status);
+        return;
+    }
+
+    /*
+     * 2005-may-02
+     *
+     * ICU4C 3.4 (jitterbug 4497) hardcodes the data for Unicode character
+     * properties for APIs that want to be fast.
+     * Therefore, we need not load them here nor check for errors.
+     * Instead, we load the converter alias table to see if any ICU data
+     * is available.
+     * Users should really open the service objects they need and check
+     * for errors there, to make sure that the actual items they need are
+     * available.
+     */
+#if !UCONFIG_NO_CONVERSION
+    ucnv_io_countKnownConverters(status);
+#endif
+
+    gICUInitialized = TRUE;    /* TODO:  don't set if U_FAILURE? */
+    umtx_unlock(&gICUInitMutex);
+    UTRACE_EXIT_STATUS(*status);
+}
diff --git a/source/common/uinvchar.c b/source/common/uinvchar.c
new file mode 100644
index 0000000..d465b2e
--- /dev/null
+++ b/source/common/uinvchar.c
@@ -0,0 +1,584 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  uinvchar.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:2
+*
+*   created on: 2004sep14
+*   created by: Markus W. Scherer
+*
+*   Functions for handling invariant characters, moved here from putil.c
+*   for better modularization.
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/ustring.h"
+#include "udataswp.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include "uassert.h"
+#include "uinvchar.h"
+
+/* invariant-character handling --------------------------------------------- */
+
+/*
+ * These maps for ASCII to/from EBCDIC map invariant characters (see utypes.h)
+ * appropriately for most EBCDIC codepages.
+ *
+ * They currently also map most other ASCII graphic characters,
+ * appropriately for codepages 37 and 1047.
+ * Exceptions: The characters for []^ have different codes in 37 & 1047.
+ * Both versions are mapped to ASCII.
+ *
+ *    ASCII 37 1047
+ * [     5B BA   AD
+ * ]     5D BB   BD
+ * ^     5E B0   5F
+ *
+ * There are no mappings for variant characters from Unicode to EBCDIC.
+ *
+ * Currently, C0 control codes are also included in these maps.
+ * Exceptions: S/390 Open Edition swaps LF and NEL codes compared with other
+ * EBCDIC platforms; both codes (15 and 25) are mapped to ASCII LF (0A),
+ * but there is no mapping for ASCII LF back to EBCDIC.
+ *
+ *    ASCII EBCDIC S/390-OE
+ * LF    0A     25       15
+ * NEL   85     15       25
+ *
+ * The maps below explicitly exclude the variant
+ * control and graphical characters that are in ASCII-based
+ * codepages at 0x80 and above.
+ * "No mapping" is expressed by mapping to a 00 byte.
+ *
+ * These tables do not establish a converter or a codepage.
+ */
+
+static const uint8_t asciiFromEbcdic[256]={
+    0x00, 0x01, 0x02, 0x03, 0x00, 0x09, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x00, 0x0a, 0x08, 0x00, 0x18, 0x19, 0x00, 0x00, 0x1c, 0x1d, 0x1e, 0x1f,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x17, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x06, 0x07,
+    0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x00, 0x1a,
+
+    0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x3c, 0x28, 0x2b, 0x7c,
+    0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x5e,
+    0x2d, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22,
+
+    0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x7e, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00,
+    0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x5d, 0x00, 0x5d, 0x00, 0x00,
+
+    0x7b, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x7d, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5c, 0x00, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t ebcdicFromAscii[256]={
+    0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, 0x16, 0x05, 0x00, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, 0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
+    0x40, 0x00, 0x7f, 0x00, 0x00, 0x6c, 0x50, 0x7d, 0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f,
+
+    0x00, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
+    0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x6d,
+    0x00, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+    0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0x00, 0x00, 0x00, 0x00, 0x07,
+
+    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,
+    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,
+    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
+};
+
+/*
+ * Bit sets indicating which characters of the ASCII repertoire
+ * (by ASCII/Unicode code) are "invariant".
+ * See utypes.h for more details.
+ *
+ * As invariant are considered the characters of the ASCII repertoire except
+ * for the following:
+ * 21  '!' <exclamation mark>
+ * 23  '#' <number sign>
+ * 24  '$' <dollar sign>
+ *
+ * 40  '@' <commercial at>
+ *
+ * 5b  '[' <left bracket>
+ * 5c  '\' <backslash>
+ * 5d  ']' <right bracket>
+ * 5e  '^' <circumflex>
+ *
+ * 60  '`' <grave accent>
+ *
+ * 7b  '{' <left brace>
+ * 7c  '|' <vertical line>
+ * 7d  '}' <right brace>
+ * 7e  '~' <tilde>
+ */
+static const uint32_t invariantChars[4]={
+    0xfffffbff, /* 00..1f but not 0a */
+    0xffffffe5, /* 20..3f but not 21 23 24 */
+    0x87fffffe, /* 40..5f but not 40 5b..5e */
+    0x87fffffe  /* 60..7f but not 60 7b..7e */
+};
+
+/*
+ * test unsigned types (or values known to be non-negative) for invariant characters,
+ * tests ASCII-family character values
+ */
+#define UCHAR_IS_INVARIANT(c) (((c)<=0x7f) && (invariantChars[(c)>>5]&((uint32_t)1<<((c)&0x1f)))!=0)
+
+/* test signed types for invariant characters, adds test for positive values */
+#define SCHAR_IS_INVARIANT(c) ((0<=(c)) && UCHAR_IS_INVARIANT(c))
+
+#if U_CHARSET_FAMILY==U_ASCII_FAMILY
+#define CHAR_TO_UCHAR(c) c
+#define UCHAR_TO_CHAR(c) c
+#elif U_CHARSET_FAMILY==U_EBCDIC_FAMILY
+#define CHAR_TO_UCHAR(u) asciiFromEbcdic[u]
+#define UCHAR_TO_CHAR(u) ebcdicFromAscii[u]
+#else
+#   error U_CHARSET_FAMILY is not valid
+#endif
+
+
+U_CAPI void U_EXPORT2
+u_charsToUChars(const char *cs, UChar *us, int32_t length) {
+    UChar u;
+    uint8_t c;
+
+    /*
+     * Allow the entire ASCII repertoire to be mapped _to_ Unicode.
+     * For EBCDIC systems, this works for characters with codes from
+     * codepages 37 and 1047 or compatible.
+     */
+    while(length>0) {
+        c=(uint8_t)(*cs++);
+        u=(UChar)CHAR_TO_UCHAR(c);
+        U_ASSERT((u!=0 || c==0)); /* only invariant chars converted? */
+        *us++=u;
+        --length;
+    }
+}
+
+U_CAPI void U_EXPORT2
+u_UCharsToChars(const UChar *us, char *cs, int32_t length) {
+    UChar u;
+
+    while(length>0) {
+        u=*us++;
+        if(!UCHAR_IS_INVARIANT(u)) {
+            U_ASSERT(FALSE); /* Variant characters were used. These are not portable in ICU. */
+            u=0;
+        }
+        *cs++=(char)UCHAR_TO_CHAR(u);
+        --length;
+    }
+}
+
+U_CAPI UBool U_EXPORT2
+uprv_isInvariantString(const char *s, int32_t length) {
+    uint8_t c;
+
+    for(;;) {
+        if(length<0) {
+            /* NUL-terminated */
+            c=(uint8_t)*s++;
+            if(c==0) {
+                break;
+            }
+        } else {
+            /* count length */
+            if(length==0) {
+                break;
+            }
+            --length;
+            c=(uint8_t)*s++;
+            if(c==0) {
+                continue; /* NUL is invariant */
+            }
+        }
+        /* c!=0 now, one branch below checks c==0 for variant characters */
+
+        /*
+         * no assertions here because these functions are legitimately called
+         * for strings with variant characters
+         */
+#if U_CHARSET_FAMILY==U_ASCII_FAMILY
+        if(!UCHAR_IS_INVARIANT(c)) {
+            return FALSE; /* found a variant char */
+        }
+#elif U_CHARSET_FAMILY==U_EBCDIC_FAMILY
+        c=CHAR_TO_UCHAR(c);
+        if(c==0 || !UCHAR_IS_INVARIANT(c)) {
+            return FALSE; /* found a variant char */
+        }
+#else
+#   error U_CHARSET_FAMILY is not valid
+#endif
+    }
+    return TRUE;
+}
+
+U_CAPI UBool U_EXPORT2
+uprv_isInvariantUString(const UChar *s, int32_t length) {
+    UChar c;
+
+    for(;;) {
+        if(length<0) {
+            /* NUL-terminated */
+            c=*s++;
+            if(c==0) {
+                break;
+            }
+        } else {
+            /* count length */
+            if(length==0) {
+                break;
+            }
+            --length;
+            c=*s++;
+        }
+
+        /*
+         * no assertions here because these functions are legitimately called
+         * for strings with variant characters
+         */
+        if(!UCHAR_IS_INVARIANT(c)) {
+            return FALSE; /* found a variant char */
+        }
+    }
+    return TRUE;
+}
+
+/* UDataSwapFn implementations used in udataswp.c ------- */
+
+/* convert ASCII to EBCDIC and verify that all characters are invariant */
+U_CAPI int32_t U_EXPORT2
+uprv_ebcdicFromAscii(const UDataSwapper *ds,
+                     const void *inData, int32_t length, void *outData,
+                     UErrorCode *pErrorCode) {
+    const uint8_t *s;
+    uint8_t *t;
+    uint8_t c;
+
+    int32_t count;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(ds==NULL || inData==NULL || length<0 || (length>0 && outData==NULL)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* setup and swapping */
+    s=(const uint8_t *)inData;
+    t=(uint8_t *)outData;
+    count=length;
+    while(count>0) {
+        c=*s++;
+        if(!UCHAR_IS_INVARIANT(c)) {
+            udata_printError(ds, "uprv_ebcdicFromAscii() string[%d] contains a variant character in position %d\n",
+                             length, length-count);
+            *pErrorCode=U_INVALID_CHAR_FOUND;
+            return 0;
+        }
+        *t++=ebcdicFromAscii[c];
+        --count;
+    }
+
+    return length;
+}
+
+/* this function only checks and copies ASCII strings without conversion */
+U_CFUNC int32_t
+uprv_copyAscii(const UDataSwapper *ds,
+               const void *inData, int32_t length, void *outData,
+               UErrorCode *pErrorCode) {
+    const uint8_t *s;
+    uint8_t c;
+
+    int32_t count;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(ds==NULL || inData==NULL || length<0 || (length>0 && outData==NULL)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* setup and checking */
+    s=(const uint8_t *)inData;
+    count=length;
+    while(count>0) {
+        c=*s++;
+        if(!UCHAR_IS_INVARIANT(c)) {
+            udata_printError(ds, "uprv_copyFromAscii() string[%d] contains a variant character in position %d\n",
+                             length, length-count);
+            *pErrorCode=U_INVALID_CHAR_FOUND;
+            return 0;
+        }
+        --count;
+    }
+
+    if(length>0 && inData!=outData) {
+        uprv_memcpy(outData, inData, length);
+    }
+
+    return length;
+}
+
+/* convert EBCDIC to ASCII and verify that all characters are invariant */
+U_CFUNC int32_t
+uprv_asciiFromEbcdic(const UDataSwapper *ds,
+                     const void *inData, int32_t length, void *outData,
+                     UErrorCode *pErrorCode) {
+    const uint8_t *s;
+    uint8_t *t;
+    uint8_t c;
+
+    int32_t count;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(ds==NULL || inData==NULL || length<0 ||  (length>0 && outData==NULL)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* setup and swapping */
+    s=(const uint8_t *)inData;
+    t=(uint8_t *)outData;
+    count=length;
+    while(count>0) {
+        c=*s++;
+        if(c!=0 && ((c=asciiFromEbcdic[c])==0 || !UCHAR_IS_INVARIANT(c))) {
+            udata_printError(ds, "uprv_asciiFromEbcdic() string[%d] contains a variant character in position %d\n",
+                             length, length-count);
+            *pErrorCode=U_INVALID_CHAR_FOUND;
+            return 0;
+        }
+        *t++=c;
+        --count;
+    }
+
+    return length;
+}
+
+/* this function only checks and copies EBCDIC strings without conversion */
+U_CFUNC int32_t
+uprv_copyEbcdic(const UDataSwapper *ds,
+                const void *inData, int32_t length, void *outData,
+                UErrorCode *pErrorCode) {
+    const uint8_t *s;
+    uint8_t c;
+
+    int32_t count;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(ds==NULL || inData==NULL || length<0 || (length>0 && outData==NULL)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* setup and checking */
+    s=(const uint8_t *)inData;
+    count=length;
+    while(count>0) {
+        c=*s++;
+        if(c!=0 && ((c=asciiFromEbcdic[c])==0 || !UCHAR_IS_INVARIANT(c))) {
+            udata_printError(ds, "uprv_copyEbcdic() string[%] contains a variant character in position %d\n",
+                             length, length-count);
+            *pErrorCode=U_INVALID_CHAR_FOUND;
+            return 0;
+        }
+        --count;
+    }
+
+    if(length>0 && inData!=outData) {
+        uprv_memcpy(outData, inData, length);
+    }
+
+    return length;
+}
+
+/* compare invariant strings; variant characters compare less than others and unlike each other */
+U_CFUNC int32_t
+uprv_compareInvAscii(const UDataSwapper *ds,
+                     const char *outString, int32_t outLength,
+                     const UChar *localString, int32_t localLength) {
+    int32_t minLength;
+    UChar32 c1, c2;
+    uint8_t c;
+
+    if(outString==NULL || outLength<-1 || localString==NULL || localLength<-1) {
+        return 0;
+    }
+
+    if(outLength<0) {
+        outLength=(int32_t)uprv_strlen(outString);
+    }
+    if(localLength<0) {
+        localLength=u_strlen(localString);
+    }
+
+    minLength= outLength<localLength ? outLength : localLength;
+
+    while(minLength>0) {
+        c=(uint8_t)*outString++;
+        if(UCHAR_IS_INVARIANT(c)) {
+            c1=c;
+        } else {
+            c1=-1;
+        }
+
+        c2=*localString++;
+        if(!UCHAR_IS_INVARIANT(c2)) {
+            c2=-2;
+        }
+
+        if((c1-=c2)!=0) {
+            return c1;
+        }
+
+        --minLength;
+    }
+
+    /* strings start with same prefix, compare lengths */
+    return outLength-localLength;
+}
+
+U_CFUNC int32_t
+uprv_compareInvEbcdic(const UDataSwapper *ds,
+                      const char *outString, int32_t outLength,
+                      const UChar *localString, int32_t localLength) {
+    int32_t minLength;
+    UChar32 c1, c2;
+    uint8_t c;
+
+    if(outString==NULL || outLength<-1 || localString==NULL || localLength<-1) {
+        return 0;
+    }
+
+    if(outLength<0) {
+        outLength=(int32_t)uprv_strlen(outString);
+    }
+    if(localLength<0) {
+        localLength=u_strlen(localString);
+    }
+
+    minLength= outLength<localLength ? outLength : localLength;
+
+    while(minLength>0) {
+        c=(uint8_t)*outString++;
+        if(c==0) {
+            c1=0;
+        } else if((c1=asciiFromEbcdic[c])!=0 && UCHAR_IS_INVARIANT(c1)) {
+            /* c1 is set */
+        } else {
+            c1=-1;
+        }
+
+        c2=*localString++;
+        if(!UCHAR_IS_INVARIANT(c2)) {
+            c2=-2;
+        }
+
+        if((c1-=c2)!=0) {
+            return c1;
+        }
+
+        --minLength;
+    }
+
+    /* strings start with same prefix, compare lengths */
+    return outLength-localLength;
+}
+
+U_CAPI int32_t U_EXPORT2
+uprv_compareInvEbcdicAsAscii(const char *s1, const char *s2) {
+    int32_t c1, c2;
+
+    for(;; ++s1, ++s2) {
+        c1=(uint8_t)*s1;
+        c2=(uint8_t)*s2;
+        if(c1!=c2) {
+            if(c1!=0 && ((c1=asciiFromEbcdic[c1])==0 || !UCHAR_IS_INVARIANT(c1))) {
+                c1=-(int32_t)(uint8_t)*s1;
+            }
+            if(c2!=0 && ((c2=asciiFromEbcdic[c2])==0 || !UCHAR_IS_INVARIANT(c2))) {
+                c2=-(int32_t)(uint8_t)*s2;
+            }
+            return c1-c2;
+        } else if(c1==0) {
+            return 0;
+        }
+    }
+}
+
+
+U_INTERNAL uint8_t* U_EXPORT2
+uprv_aestrncpy(uint8_t *dst, const uint8_t *src, int32_t n)
+{
+  uint8_t *orig_dst = dst;
+
+  if(n==-1) { 
+    n = uprv_strlen((const char*)src)+1; /* copy NUL */
+  }
+  /* copy non-null */
+  while(*src && n>0) {
+    *(dst++) = asciiFromEbcdic[*(src++)];
+    n--;
+  }
+  /* pad */
+  while(n>0) {
+    *(dst++) = 0;
+    n--;
+  }
+  return orig_dst;
+}
+
+U_INTERNAL uint8_t* U_EXPORT2
+uprv_eastrncpy(uint8_t *dst, const uint8_t *src, int32_t n)
+{
+  uint8_t *orig_dst = dst;
+
+  if(n==-1) { 
+    n = uprv_strlen((const char*)src)+1; /* copy NUL */
+  }
+  /* copy non-null */
+  while(*src && n>0) {
+    char ch = ebcdicFromAscii[*(src++)];
+    if(ch == 0) {
+      ch = ebcdicFromAscii[0x3f]; /* questionmark (subchar) */
+    }
+    *(dst++) = ch;
+    n--;
+  }
+  /* pad */
+  while(n>0) {
+    *(dst++) = 0;
+    n--;
+  }
+  return orig_dst;
+}
+
diff --git a/source/common/uinvchar.h b/source/common/uinvchar.h
new file mode 100644
index 0000000..0f40572
--- /dev/null
+++ b/source/common/uinvchar.h
@@ -0,0 +1,105 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  uinvchar.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:2
+*
+*   created on: 2004sep14
+*   created by: Markus W. Scherer
+*
+*   Definitions for handling invariant characters, moved here from putil.c
+*   for better modularization.
+*/
+
+#ifndef __UINVCHAR_H__
+#define __UINVCHAR_H__
+
+#include "unicode/utypes.h"
+
+/**
+ * Check if a char string only contains invariant characters.
+ * See utypes.h for details.
+ *
+ * @param s Input string pointer.
+ * @param length Length of the string, can be -1 if NUL-terminated.
+ * @return TRUE if s contains only invariant characters.
+ *
+ * @internal (ICU 2.8)
+ */
+U_INTERNAL UBool U_EXPORT2
+uprv_isInvariantString(const char *s, int32_t length);
+
+/**
+ * Check if a Unicode string only contains invariant characters.
+ * See utypes.h for details.
+ *
+ * @param s Input string pointer.
+ * @param length Length of the string, can be -1 if NUL-terminated.
+ * @return TRUE if s contains only invariant characters.
+ *
+ * @internal (ICU 2.8)
+ */
+U_INTERNAL UBool U_EXPORT2
+uprv_isInvariantUString(const UChar *s, int32_t length);
+
+/**
+ * \def U_UPPER_ORDINAL
+ * Get the ordinal number of an uppercase invariant character
+ * @internal
+ */
+#if U_CHARSET_FAMILY==U_ASCII_FAMILY
+#   define U_UPPER_ORDINAL(x) ((x)-'A')
+#elif U_CHARSET_FAMILY==U_EBCDIC_FAMILY
+#   define U_UPPER_ORDINAL(x) (((x) < 'J') ? ((x)-'A') : \
+                              (((x) < 'S') ? ((x)-'J'+9) : \
+                               ((x)-'S'+18)))
+#else
+#   error Unknown charset family!
+#endif
+
+/**
+ * Compare two EBCDIC invariant-character strings in ASCII order.
+ * @internal
+ */
+U_INTERNAL int32_t U_EXPORT2
+uprv_compareInvEbcdicAsAscii(const char *s1, const char *s2);
+
+/**
+ * \def uprv_compareInvCharsAsAscii
+ * Compare two invariant-character strings in ASCII order.
+ * @internal
+ */
+#if U_CHARSET_FAMILY==U_ASCII_FAMILY
+#   define uprv_compareInvCharsAsAscii(s1, s2) uprv_strcmp(s1, s2)
+#elif U_CHARSET_FAMILY==U_EBCDIC_FAMILY
+#   define uprv_compareInvCharsAsAscii(s1, s2) uprv_compareInvEbcdicAsAscii(s1, s2)
+#else
+#   error Unknown charset family!
+#endif
+
+/**
+ * Copy EBCDIC to ASCII
+ * @internal
+ * @see uprv_strncpy
+ */
+U_INTERNAL uint8_t* U_EXPORT2
+uprv_aestrncpy(uint8_t *dst, const uint8_t *src, int32_t n);
+
+
+/**
+ * Copy ASCII to EBCDIC
+ * @internal
+ * @see uprv_strncpy
+ */
+U_INTERNAL uint8_t* U_EXPORT2
+uprv_eastrncpy(uint8_t *dst, const uint8_t *src, int32_t n);
+
+
+
+#endif
diff --git a/source/common/uiter.cpp b/source/common/uiter.cpp
new file mode 100644
index 0000000..bec7190
--- /dev/null
+++ b/source/common/uiter.cpp
@@ -0,0 +1,1121 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2002-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  uiter.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002jan18
+*   created by: Markus W. Scherer
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/ustring.h"
+#include "unicode/chariter.h"
+#include "unicode/rep.h"
+#include "unicode/uiter.h"
+#include "cstring.h"
+
+U_NAMESPACE_USE
+
+#define IS_EVEN(n) (((n)&1)==0)
+#define IS_POINTER_EVEN(p) IS_EVEN((size_t)p)
+
+U_CDECL_BEGIN
+
+/* No-Op UCharIterator implementation for illegal input --------------------- */
+
+static int32_t U_CALLCONV
+noopGetIndex(UCharIterator * /*iter*/, UCharIteratorOrigin /*origin*/) {
+    return 0;
+}
+
+static int32_t U_CALLCONV
+noopMove(UCharIterator * /*iter*/, int32_t /*delta*/, UCharIteratorOrigin /*origin*/) {
+    return 0;
+}
+
+static UBool U_CALLCONV
+noopHasNext(UCharIterator * /*iter*/) {
+    return FALSE;
+}
+
+static UChar32 U_CALLCONV
+noopCurrent(UCharIterator * /*iter*/) {
+    return U_SENTINEL;
+}
+
+static uint32_t U_CALLCONV
+noopGetState(const UCharIterator * /*iter*/) {
+    return UITER_NO_STATE;
+}
+
+static void U_CALLCONV
+noopSetState(UCharIterator * /*iter*/, uint32_t /*state*/, UErrorCode *pErrorCode) {
+    *pErrorCode=U_UNSUPPORTED_ERROR;
+}
+
+static const UCharIterator noopIterator={
+    0, 0, 0, 0, 0, 0,
+    noopGetIndex,
+    noopMove,
+    noopHasNext,
+    noopHasNext,
+    noopCurrent,
+    noopCurrent,
+    noopCurrent,
+    NULL,
+    noopGetState,
+    noopSetState
+};
+
+/* UCharIterator implementation for simple strings -------------------------- */
+
+/*
+ * This is an implementation of a code unit (UChar) iterator
+ * for UChar * strings.
+ *
+ * The UCharIterator.context field holds a pointer to the string.
+ */
+
+static int32_t U_CALLCONV
+stringIteratorGetIndex(UCharIterator *iter, UCharIteratorOrigin origin) {
+    switch(origin) {
+    case UITER_ZERO:
+        return 0;
+    case UITER_START:
+        return iter->start;
+    case UITER_CURRENT:
+        return iter->index;
+    case UITER_LIMIT:
+        return iter->limit;
+    case UITER_LENGTH:
+        return iter->length;
+    default:
+        /* not a valid origin */
+        /* Should never get here! */
+        return -1;
+    }
+}
+
+static int32_t U_CALLCONV
+stringIteratorMove(UCharIterator *iter, int32_t delta, UCharIteratorOrigin origin) {
+    int32_t pos;
+
+    switch(origin) {
+    case UITER_ZERO:
+        pos=delta;
+        break;
+    case UITER_START:
+        pos=iter->start+delta;
+        break;
+    case UITER_CURRENT:
+        pos=iter->index+delta;
+        break;
+    case UITER_LIMIT:
+        pos=iter->limit+delta;
+        break;
+    case UITER_LENGTH:
+        pos=iter->length+delta;
+        break;
+    default:
+        return -1;  /* Error */
+    }
+
+    if(pos<iter->start) {
+        pos=iter->start;
+    } else if(pos>iter->limit) {
+        pos=iter->limit;
+    }
+
+    return iter->index=pos;
+}
+
+static UBool U_CALLCONV
+stringIteratorHasNext(UCharIterator *iter) {
+    return iter->index<iter->limit;
+}
+
+static UBool U_CALLCONV
+stringIteratorHasPrevious(UCharIterator *iter) {
+    return iter->index>iter->start;
+}
+
+static UChar32 U_CALLCONV
+stringIteratorCurrent(UCharIterator *iter) {
+    if(iter->index<iter->limit) {
+        return ((const UChar *)(iter->context))[iter->index];
+    } else {
+        return U_SENTINEL;
+    }
+}
+
+static UChar32 U_CALLCONV
+stringIteratorNext(UCharIterator *iter) {
+    if(iter->index<iter->limit) {
+        return ((const UChar *)(iter->context))[iter->index++];
+    } else {
+        return U_SENTINEL;
+    }
+}
+
+static UChar32 U_CALLCONV
+stringIteratorPrevious(UCharIterator *iter) {
+    if(iter->index>iter->start) {
+        return ((const UChar *)(iter->context))[--iter->index];
+    } else {
+        return U_SENTINEL;
+    }
+}
+
+static uint32_t U_CALLCONV
+stringIteratorGetState(const UCharIterator *iter) {
+    return (uint32_t)iter->index;
+}
+
+static void U_CALLCONV
+stringIteratorSetState(UCharIterator *iter, uint32_t state, UErrorCode *pErrorCode) {
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        /* do nothing */
+    } else if(iter==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+    } else if((int32_t)state<iter->start || iter->limit<(int32_t)state) {
+        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+    } else {
+        iter->index=(int32_t)state;
+    }
+}
+
+static const UCharIterator stringIterator={
+    0, 0, 0, 0, 0, 0,
+    stringIteratorGetIndex,
+    stringIteratorMove,
+    stringIteratorHasNext,
+    stringIteratorHasPrevious,
+    stringIteratorCurrent,
+    stringIteratorNext,
+    stringIteratorPrevious,
+    NULL,
+    stringIteratorGetState,
+    stringIteratorSetState
+};
+
+U_CAPI void U_EXPORT2
+uiter_setString(UCharIterator *iter, const UChar *s, int32_t length) {
+    if(iter!=0) {
+        if(s!=0 && length>=-1) {
+            *iter=stringIterator;
+            iter->context=s;
+            if(length>=0) {
+                iter->length=length;
+            } else {
+                iter->length=u_strlen(s);
+            }
+            iter->limit=iter->length;
+        } else {
+            *iter=noopIterator;
+        }
+    }
+}
+
+/* UCharIterator implementation for UTF-16BE strings ------------------------ */
+
+/*
+ * This is an implementation of a code unit (UChar) iterator
+ * for UTF-16BE strings, i.e., strings in byte-vectors where
+ * each UChar is stored as a big-endian pair of bytes.
+ *
+ * The UCharIterator.context field holds a pointer to the string.
+ * Everything works just like with a normal UChar iterator (uiter_setString),
+ * except that UChars are assembled from byte pairs.
+ */
+
+/* internal helper function */
+static inline UChar32
+utf16BEIteratorGet(UCharIterator *iter, int32_t index) {
+    const uint8_t *p=(const uint8_t *)iter->context;
+    return ((UChar)p[2*index]<<8)|(UChar)p[2*index+1];
+}
+
+static UChar32 U_CALLCONV
+utf16BEIteratorCurrent(UCharIterator *iter) {
+    int32_t index;
+
+    if((index=iter->index)<iter->limit) {
+        return utf16BEIteratorGet(iter, index);
+    } else {
+        return U_SENTINEL;
+    }
+}
+
+static UChar32 U_CALLCONV
+utf16BEIteratorNext(UCharIterator *iter) {
+    int32_t index;
+
+    if((index=iter->index)<iter->limit) {
+        iter->index=index+1;
+        return utf16BEIteratorGet(iter, index);
+    } else {
+        return U_SENTINEL;
+    }
+}
+
+static UChar32 U_CALLCONV
+utf16BEIteratorPrevious(UCharIterator *iter) {
+    int32_t index;
+
+    if((index=iter->index)>iter->start) {
+        iter->index=--index;
+        return utf16BEIteratorGet(iter, index);
+    } else {
+        return U_SENTINEL;
+    }
+}
+
+static const UCharIterator utf16BEIterator={
+    0, 0, 0, 0, 0, 0,
+    stringIteratorGetIndex,
+    stringIteratorMove,
+    stringIteratorHasNext,
+    stringIteratorHasPrevious,
+    utf16BEIteratorCurrent,
+    utf16BEIteratorNext,
+    utf16BEIteratorPrevious,
+    NULL,
+    stringIteratorGetState,
+    stringIteratorSetState
+};
+
+/*
+ * Count the number of UChars in a UTF-16BE string before a terminating UChar NUL,
+ * i.e., before a pair of 0 bytes where the first 0 byte is at an even
+ * offset from s.
+ */
+static int32_t
+utf16BE_strlen(const char *s) {
+    if(IS_POINTER_EVEN(s)) {
+        /*
+         * even-aligned, call u_strlen(s)
+         * we are probably on a little-endian machine, but searching for UChar NUL
+         * does not care about endianness
+         */
+        return u_strlen((const UChar *)s);
+    } else {
+        /* odd-aligned, search for pair of 0 bytes */
+        const char *p=s;
+
+        while(!(*p==0 && p[1]==0)) {
+            p+=2;
+        }
+        return (int32_t)((p-s)/2);
+    }
+}
+
+U_CAPI void U_EXPORT2
+uiter_setUTF16BE(UCharIterator *iter, const char *s, int32_t length) {
+    if(iter!=NULL) {
+        /* allow only even-length strings (the input length counts bytes) */
+        if(s!=NULL && (length==-1 || (length>=0 && IS_EVEN(length)))) {
+            /* length/=2, except that >>=1 also works for -1 (-1/2==0, -1>>1==-1) */
+            length>>=1;
+
+            if(U_IS_BIG_ENDIAN && IS_POINTER_EVEN(s)) {
+                /* big-endian machine and 2-aligned UTF-16BE string: use normal UChar iterator */
+                uiter_setString(iter, (const UChar *)s, length);
+                return;
+            }
+
+            *iter=utf16BEIterator;
+            iter->context=s;
+            if(length>=0) {
+                iter->length=length;
+            } else {
+                iter->length=utf16BE_strlen(s);
+            }
+            iter->limit=iter->length;
+        } else {
+            *iter=noopIterator;
+        }
+    }
+}
+
+/* UCharIterator wrapper around CharacterIterator --------------------------- */
+
+/*
+ * This is wrapper code around a C++ CharacterIterator to
+ * look like a C UCharIterator.
+ *
+ * The UCharIterator.context field holds a pointer to the CharacterIterator.
+ */
+
+static int32_t U_CALLCONV
+characterIteratorGetIndex(UCharIterator *iter, UCharIteratorOrigin origin) {
+    switch(origin) {
+    case UITER_ZERO:
+        return 0;
+    case UITER_START:
+        return ((CharacterIterator *)(iter->context))->startIndex();
+    case UITER_CURRENT:
+        return ((CharacterIterator *)(iter->context))->getIndex();
+    case UITER_LIMIT:
+        return ((CharacterIterator *)(iter->context))->endIndex();
+    case UITER_LENGTH:
+        return ((CharacterIterator *)(iter->context))->getLength();
+    default:
+        /* not a valid origin */
+        /* Should never get here! */
+        return -1;
+    }
+}
+
+static int32_t U_CALLCONV
+characterIteratorMove(UCharIterator *iter, int32_t delta, UCharIteratorOrigin origin) {
+    switch(origin) {
+    case UITER_ZERO:
+        ((CharacterIterator *)(iter->context))->setIndex(delta);
+        return ((CharacterIterator *)(iter->context))->getIndex();
+    case UITER_START:
+    case UITER_CURRENT:
+    case UITER_LIMIT:
+        return ((CharacterIterator *)(iter->context))->move(delta, (CharacterIterator::EOrigin)origin);
+    case UITER_LENGTH:
+        ((CharacterIterator *)(iter->context))->setIndex(((CharacterIterator *)(iter->context))->getLength()+delta);
+        return ((CharacterIterator *)(iter->context))->getIndex();
+    default:
+        /* not a valid origin */
+        /* Should never get here! */
+        return -1;
+    }
+}
+
+static UBool U_CALLCONV
+characterIteratorHasNext(UCharIterator *iter) {
+    return ((CharacterIterator *)(iter->context))->hasNext();
+}
+
+static UBool U_CALLCONV
+characterIteratorHasPrevious(UCharIterator *iter) {
+    return ((CharacterIterator *)(iter->context))->hasPrevious();
+}
+
+static UChar32 U_CALLCONV
+characterIteratorCurrent(UCharIterator *iter) {
+    UChar32 c;
+
+    c=((CharacterIterator *)(iter->context))->current();
+    if(c!=0xffff || ((CharacterIterator *)(iter->context))->hasNext()) {
+        return c;
+    } else {
+        return U_SENTINEL;
+    }
+}
+
+static UChar32 U_CALLCONV
+characterIteratorNext(UCharIterator *iter) {
+    if(((CharacterIterator *)(iter->context))->hasNext()) {
+        return ((CharacterIterator *)(iter->context))->nextPostInc();
+    } else {
+        return U_SENTINEL;
+    }
+}
+
+static UChar32 U_CALLCONV
+characterIteratorPrevious(UCharIterator *iter) {
+    if(((CharacterIterator *)(iter->context))->hasPrevious()) {
+        return ((CharacterIterator *)(iter->context))->previous();
+    } else {
+        return U_SENTINEL;
+    }
+}
+
+static uint32_t U_CALLCONV
+characterIteratorGetState(const UCharIterator *iter) {
+    return ((CharacterIterator *)(iter->context))->getIndex();
+}
+
+static void U_CALLCONV
+characterIteratorSetState(UCharIterator *iter, uint32_t state, UErrorCode *pErrorCode) {
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        /* do nothing */
+    } else if(iter==NULL || iter->context==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+    } else if((int32_t)state<((CharacterIterator *)(iter->context))->startIndex() || ((CharacterIterator *)(iter->context))->endIndex()<(int32_t)state) {
+        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+    } else {
+        ((CharacterIterator *)(iter->context))->setIndex((int32_t)state);
+    }
+}
+
+static const UCharIterator characterIteratorWrapper={
+    0, 0, 0, 0, 0, 0,
+    characterIteratorGetIndex,
+    characterIteratorMove,
+    characterIteratorHasNext,
+    characterIteratorHasPrevious,
+    characterIteratorCurrent,
+    characterIteratorNext,
+    characterIteratorPrevious,
+    NULL,
+    characterIteratorGetState,
+    characterIteratorSetState
+};
+
+U_CAPI void U_EXPORT2
+uiter_setCharacterIterator(UCharIterator *iter, CharacterIterator *charIter) {
+    if(iter!=0) {
+        if(charIter!=0) {
+            *iter=characterIteratorWrapper;
+            iter->context=charIter;
+        } else {
+            *iter=noopIterator;
+        }
+    }
+}
+
+/* UCharIterator wrapper around Replaceable --------------------------------- */
+
+/*
+ * This is an implementation of a code unit (UChar) iterator
+ * based on a Replaceable object.
+ *
+ * The UCharIterator.context field holds a pointer to the Replaceable.
+ * UCharIterator.length and UCharIterator.index hold Replaceable.length()
+ * and the iteration index.
+ */
+
+static UChar32 U_CALLCONV
+replaceableIteratorCurrent(UCharIterator *iter) {
+    if(iter->index<iter->limit) {
+        return ((Replaceable *)(iter->context))->charAt(iter->index);
+    } else {
+        return U_SENTINEL;
+    }
+}
+
+static UChar32 U_CALLCONV
+replaceableIteratorNext(UCharIterator *iter) {
+    if(iter->index<iter->limit) {
+        return ((Replaceable *)(iter->context))->charAt(iter->index++);
+    } else {
+        return U_SENTINEL;
+    }
+}
+
+static UChar32 U_CALLCONV
+replaceableIteratorPrevious(UCharIterator *iter) {
+    if(iter->index>iter->start) {
+        return ((Replaceable *)(iter->context))->charAt(--iter->index);
+    } else {
+        return U_SENTINEL;
+    }
+}
+
+static const UCharIterator replaceableIterator={
+    0, 0, 0, 0, 0, 0,
+    stringIteratorGetIndex,
+    stringIteratorMove,
+    stringIteratorHasNext,
+    stringIteratorHasPrevious,
+    replaceableIteratorCurrent,
+    replaceableIteratorNext,
+    replaceableIteratorPrevious,
+    NULL,
+    stringIteratorGetState,
+    stringIteratorSetState
+};
+
+U_CAPI void U_EXPORT2
+uiter_setReplaceable(UCharIterator *iter, const Replaceable *rep) {
+    if(iter!=0) {
+        if(rep!=0) {
+            *iter=replaceableIterator;
+            iter->context=rep;
+            iter->limit=iter->length=rep->length();
+        } else {
+            *iter=noopIterator;
+        }
+    }
+}
+
+/* UCharIterator implementation for UTF-8 strings --------------------------- */
+
+/*
+ * Possible, probably necessary only for an implementation for arbitrary
+ * converters:
+ * Maintain a buffer (ring buffer?) for a piece of converted 16-bit text.
+ * This would require to turn reservedFn into a close function and
+ * to introduce a uiter_close(iter).
+ */
+
+#define UITER_CNV_CAPACITY 16
+
+/*
+ * Minimal implementation:
+ * Maintain a single-UChar buffer for an additional surrogate.
+ * The caller must not modify start and limit because they are used internally.
+ *
+ * Use UCharIterator fields as follows:
+ *   context        pointer to UTF-8 string
+ *   length         UTF-16 length of the string; -1 until lazy evaluation
+ *   start          current UTF-8 index
+ *   index          current UTF-16 index; may be -1="unknown" after setState()
+ *   limit          UTF-8 length of the string
+ *   reservedField  supplementary code point
+ *
+ * Since UCharIterator delivers 16-bit code units, the iteration can be
+ * currently in the middle of the byte sequence for a supplementary code point.
+ * In this case, reservedField will contain that code point and start will
+ * point to after the corresponding byte sequence. The UTF-16 index will be
+ * one less than what it would otherwise be corresponding to the UTF-8 index.
+ * Otherwise, reservedField will be 0.
+ */
+
+/*
+ * Possible optimization for NUL-terminated UTF-8 and UTF-16 strings:
+ * Add implementations that do not call strlen() for iteration but check for NUL.
+ */
+
+static int32_t U_CALLCONV
+utf8IteratorGetIndex(UCharIterator *iter, UCharIteratorOrigin origin) {
+    switch(origin) {
+    case UITER_ZERO:
+    case UITER_START:
+        return 0;
+    case UITER_CURRENT:
+        if(iter->index<0) {
+            /* the current UTF-16 index is unknown after setState(), count from the beginning */
+            const uint8_t *s;
+            UChar32 c;
+            int32_t i, limit, index;
+
+            s=(const uint8_t *)iter->context;
+            i=index=0;
+            limit=iter->start; /* count up to the UTF-8 index */
+            while(i<limit) {
+                U8_NEXT(s, i, limit, c);
+                if(c<=0xffff) {
+                    ++index;
+                } else {
+                    index+=2;
+                }
+            }
+
+            iter->start=i; /* just in case setState() did not get us to a code point boundary */
+            if(i==iter->limit) {
+                iter->length=index; /* in case it was <0 or wrong */
+            }
+            if(iter->reservedField!=0) {
+                --index; /* we are in the middle of a supplementary code point */
+            }
+            iter->index=index;
+        }
+        return iter->index;
+    case UITER_LIMIT:
+    case UITER_LENGTH:
+        if(iter->length<0) {
+            const uint8_t *s;
+            UChar32 c;
+            int32_t i, limit, length;
+
+            s=(const uint8_t *)iter->context;
+            if(iter->index<0) {
+                /*
+                 * the current UTF-16 index is unknown after setState(),
+                 * we must first count from the beginning to here
+                 */
+                i=length=0;
+                limit=iter->start;
+
+                /* count from the beginning to the current index */
+                while(i<limit) {
+                    U8_NEXT(s, i, limit, c);
+                    if(c<=0xffff) {
+                        ++length;
+                    } else {
+                        length+=2;
+                    }
+                }
+
+                /* assume i==limit==iter->start, set the UTF-16 index */
+                iter->start=i; /* just in case setState() did not get us to a code point boundary */
+                iter->index= iter->reservedField!=0 ? length-1 : length;
+            } else {
+                i=iter->start;
+                length=iter->index;
+                if(iter->reservedField!=0) {
+                    ++length;
+                }
+            }
+
+            /* count from the current index to the end */
+            limit=iter->limit;
+            while(i<limit) {
+                U8_NEXT(s, i, limit, c);
+                if(c<=0xffff) {
+                    ++length;
+                } else {
+                    length+=2;
+                }
+            }
+            iter->length=length;
+        }
+        return iter->length;
+    default:
+        /* not a valid origin */
+        /* Should never get here! */
+        return -1;
+    }
+}
+
+static int32_t U_CALLCONV
+utf8IteratorMove(UCharIterator *iter, int32_t delta, UCharIteratorOrigin origin) {
+    const uint8_t *s;
+    UChar32 c;
+    int32_t pos; /* requested UTF-16 index */
+    int32_t i; /* UTF-8 index */
+    UBool havePos;
+
+    /* calculate the requested UTF-16 index */
+    switch(origin) {
+    case UITER_ZERO:
+    case UITER_START:
+        pos=delta;
+        havePos=TRUE;
+        /* iter->index<0 (unknown) is possible */
+        break;
+    case UITER_CURRENT:
+        if(iter->index>=0) {
+            pos=iter->index+delta;
+            havePos=TRUE;
+        } else {
+            /* the current UTF-16 index is unknown after setState(), use only delta */
+            pos=0;
+            havePos=FALSE;
+        }
+        break;
+    case UITER_LIMIT:
+    case UITER_LENGTH:
+        if(iter->length>=0) {
+            pos=iter->length+delta;
+            havePos=TRUE;
+        } else {
+            /* pin to the end, avoid counting the length */
+            iter->index=-1;
+            iter->start=iter->limit;
+            iter->reservedField=0;
+            if(delta>=0) {
+                return UITER_UNKNOWN_INDEX;
+            } else {
+                /* the current UTF-16 index is unknown, use only delta */
+                pos=0;
+                havePos=FALSE;
+            }
+        }
+        break;
+    default:
+        return -1;  /* Error */
+    }
+
+    if(havePos) {
+        /* shortcuts: pinning to the edges of the string */
+        if(pos<=0) {
+            iter->index=iter->start=iter->reservedField=0;
+            return 0;
+        } else if(iter->length>=0 && pos>=iter->length) {
+            iter->index=iter->length;
+            iter->start=iter->limit;
+            iter->reservedField=0;
+            return iter->index;
+        }
+
+        /* minimize the number of U8_NEXT/PREV operations */
+        if(iter->index<0 || pos<iter->index/2) {
+            /* go forward from the start instead of backward from the current index */
+            iter->index=iter->start=iter->reservedField=0;
+        } else if(iter->length>=0 && (iter->length-pos)<(pos-iter->index)) {
+            /*
+             * if we have the UTF-16 index and length and the new position is
+             * closer to the end than the current index,
+             * then go backward from the end instead of forward from the current index
+             */
+            iter->index=iter->length;
+            iter->start=iter->limit;
+            iter->reservedField=0;
+        }
+
+        delta=pos-iter->index;
+        if(delta==0) {
+            return iter->index; /* nothing to do */
+        }
+    } else {
+        /* move relative to unknown UTF-16 index */
+        if(delta==0) {
+            return UITER_UNKNOWN_INDEX; /* nothing to do */
+        } else if(-delta>=iter->start) {
+            /* moving backwards by more UChars than there are UTF-8 bytes, pin to 0 */
+            iter->index=iter->start=iter->reservedField=0;
+            return 0;
+        } else if(delta>=(iter->limit-iter->start)) {
+            /* moving forward by more UChars than the remaining UTF-8 bytes, pin to the end */
+            iter->index=iter->length; /* may or may not be <0 (unknown) */
+            iter->start=iter->limit;
+            iter->reservedField=0;
+            return iter->index>=0 ? iter->index : (int32_t)UITER_UNKNOWN_INDEX;
+        }
+    }
+
+    /* delta!=0 */
+
+    /* move towards the requested position, pin to the edges of the string */
+    s=(const uint8_t *)iter->context;
+    pos=iter->index; /* could be <0 (unknown) */
+    i=iter->start;
+    if(delta>0) {
+        /* go forward */
+        int32_t limit=iter->limit;
+        if(iter->reservedField!=0) {
+            iter->reservedField=0;
+            ++pos;
+            --delta;
+        }
+        while(delta>0 && i<limit) {
+            U8_NEXT(s, i, limit, c);
+            if(c<0xffff) {
+                ++pos;
+                --delta;
+            } else if(delta>=2) {
+                pos+=2;
+                delta-=2;
+            } else /* delta==1 */ {
+                /* stop in the middle of a supplementary code point */
+                iter->reservedField=c;
+                ++pos;
+                break; /* delta=0; */
+            }
+        }
+        if(i==limit) {
+            if(iter->length<0 && iter->index>=0) {
+                iter->length= iter->reservedField==0 ? pos : pos+1;
+            } else if(iter->index<0 && iter->length>=0) {
+                iter->index= iter->reservedField==0 ? iter->length : iter->length-1;
+            }
+        }
+    } else /* delta<0 */ {
+        /* go backward */
+        if(iter->reservedField!=0) {
+            iter->reservedField=0;
+            i-=4; /* we stayed behind the supplementary code point; go before it now */
+            --pos;
+            ++delta;
+        }
+        while(delta<0 && i>0) {
+            U8_PREV(s, 0, i, c);
+            if(c<0xffff) {
+                --pos;
+                ++delta;
+            } else if(delta<=-2) {
+                pos-=2;
+                delta+=2;
+            } else /* delta==-1 */ {
+                /* stop in the middle of a supplementary code point */
+                i+=4; /* back to behind this supplementary code point for consistent state */
+                iter->reservedField=c;
+                --pos;
+                break; /* delta=0; */
+            }
+        }
+    }
+
+    iter->start=i;
+    if(iter->index>=0) {
+        return iter->index=pos;
+    } else {
+        /* we started with index<0 (unknown) so pos is bogus */
+        if(i<=1) {
+            return iter->index=i; /* reached the beginning */
+        } else {
+            /* we still don't know the UTF-16 index */
+            return UITER_UNKNOWN_INDEX;
+        }
+    }
+}
+
+static UBool U_CALLCONV
+utf8IteratorHasNext(UCharIterator *iter) {
+    return iter->start<iter->limit || iter->reservedField!=0;
+}
+
+static UBool U_CALLCONV
+utf8IteratorHasPrevious(UCharIterator *iter) {
+    return iter->start>0;
+}
+
+static UChar32 U_CALLCONV
+utf8IteratorCurrent(UCharIterator *iter) {
+    if(iter->reservedField!=0) {
+        return U16_TRAIL(iter->reservedField);
+    } else if(iter->start<iter->limit) {
+        const uint8_t *s=(const uint8_t *)iter->context;
+        UChar32 c;
+        int32_t i=iter->start;
+
+        U8_NEXT(s, i, iter->limit, c);
+        if(c<0) {
+            return 0xfffd;
+        } else if(c<=0xffff) {
+            return c;
+        } else {
+            return U16_LEAD(c);
+        }
+    } else {
+        return U_SENTINEL;
+    }
+}
+
+static UChar32 U_CALLCONV
+utf8IteratorNext(UCharIterator *iter) {
+    int32_t index;
+
+    if(iter->reservedField!=0) {
+        UChar trail=U16_TRAIL(iter->reservedField);
+        iter->reservedField=0;
+        if((index=iter->index)>=0) {
+            iter->index=index+1;
+        }
+        return trail;
+    } else if(iter->start<iter->limit) {
+        const uint8_t *s=(const uint8_t *)iter->context;
+        UChar32 c;
+
+        U8_NEXT(s, iter->start, iter->limit, c);
+        if((index=iter->index)>=0) {
+            iter->index=++index;
+            if(iter->length<0 && iter->start==iter->limit) {
+                iter->length= c<=0xffff ? index : index+1;
+            }
+        } else if(iter->start==iter->limit && iter->length>=0) {
+            iter->index= c<=0xffff ? iter->length : iter->length-1;
+        }
+        if(c<0) {
+            return 0xfffd;
+        } else if(c<=0xffff) {
+            return c;
+        } else {
+            iter->reservedField=c;
+            return U16_LEAD(c);
+        }
+    } else {
+        return U_SENTINEL;
+    }
+}
+
+static UChar32 U_CALLCONV
+utf8IteratorPrevious(UCharIterator *iter) {
+    int32_t index;
+
+    if(iter->reservedField!=0) {
+        UChar lead=U16_LEAD(iter->reservedField);
+        iter->reservedField=0;
+        iter->start-=4; /* we stayed behind the supplementary code point; go before it now */
+        if((index=iter->index)>0) {
+            iter->index=index-1;
+        }
+        return lead;
+    } else if(iter->start>0) {
+        const uint8_t *s=(const uint8_t *)iter->context;
+        UChar32 c;
+
+        U8_PREV(s, 0, iter->start, c);
+        if((index=iter->index)>0) {
+            iter->index=index-1;
+        } else if(iter->start<=1) {
+            iter->index= c<=0xffff ? iter->start : iter->start+1;
+        }
+        if(c<0) {
+            return 0xfffd;
+        } else if(c<=0xffff) {
+            return c;
+        } else {
+            iter->start+=4; /* back to behind this supplementary code point for consistent state */
+            iter->reservedField=c;
+            return U16_TRAIL(c);
+        }
+    } else {
+        return U_SENTINEL;
+    }
+}
+
+static uint32_t U_CALLCONV
+utf8IteratorGetState(const UCharIterator *iter) {
+    uint32_t state=(uint32_t)(iter->start<<1);
+    if(iter->reservedField!=0) {
+        state|=1;
+    }
+    return state;
+}
+
+static void U_CALLCONV
+utf8IteratorSetState(UCharIterator *iter,
+                     uint32_t state,
+                     UErrorCode *pErrorCode)
+{
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        /* do nothing */
+    } else if(iter==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+    } else if(state==utf8IteratorGetState(iter)) {
+        /* setting to the current state: no-op */
+    } else {
+        int32_t index=(int32_t)(state>>1); /* UTF-8 index */
+        state&=1; /* 1 if in surrogate pair, must be index>=4 */
+
+        if((state==0 ? index<0 : index<4) || iter->limit<index) {
+            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+        } else {
+            iter->start=index; /* restore UTF-8 byte index */
+            if(index<=1) {
+                iter->index=index;
+            } else {
+                iter->index=-1; /* unknown UTF-16 index */
+            }
+            if(state==0) {
+                iter->reservedField=0;
+            } else {
+                /* verified index>=4 above */
+                UChar32 c;
+                U8_PREV((const uint8_t *)iter->context, 0, index, c);
+                if(c<=0xffff) {
+                    *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+                } else {
+                    iter->reservedField=c;
+                }
+            }
+        }
+    }
+}
+
+static const UCharIterator utf8Iterator={
+    0, 0, 0, 0, 0, 0,
+    utf8IteratorGetIndex,
+    utf8IteratorMove,
+    utf8IteratorHasNext,
+    utf8IteratorHasPrevious,
+    utf8IteratorCurrent,
+    utf8IteratorNext,
+    utf8IteratorPrevious,
+    NULL,
+    utf8IteratorGetState,
+    utf8IteratorSetState
+};
+
+U_CAPI void U_EXPORT2
+uiter_setUTF8(UCharIterator *iter, const char *s, int32_t length) {
+    if(iter!=0) {
+        if(s!=0 && length>=-1) {
+            *iter=utf8Iterator;
+            iter->context=s;
+            if(length>=0) {
+                iter->limit=length;
+            } else {
+                iter->limit=(int32_t)uprv_strlen(s);
+            }
+            iter->length= iter->limit<=1 ? iter->limit : -1;
+        } else {
+            *iter=noopIterator;
+        }
+    }
+}
+
+/* Helper functions --------------------------------------------------------- */
+
+U_CAPI UChar32 U_EXPORT2
+uiter_current32(UCharIterator *iter) {
+    UChar32 c, c2;
+
+    c=iter->current(iter);
+    if(UTF_IS_SURROGATE(c)) {
+        if(UTF_IS_SURROGATE_FIRST(c)) {
+            /*
+             * go to the next code unit
+             * we know that we are not at the limit because c!=U_SENTINEL
+             */
+            iter->move(iter, 1, UITER_CURRENT);
+            if(UTF_IS_SECOND_SURROGATE(c2=iter->current(iter))) {
+                c=UTF16_GET_PAIR_VALUE(c, c2);
+            }
+
+            /* undo index movement */
+            iter->move(iter, -1, UITER_CURRENT);
+        } else {
+            if(UTF_IS_FIRST_SURROGATE(c2=iter->previous(iter))) {
+                c=UTF16_GET_PAIR_VALUE(c2, c);
+            }
+            if(c2>=0) {
+                /* undo index movement */
+                iter->move(iter, 1, UITER_CURRENT);
+            }
+        }
+    }
+    return c;
+}
+
+U_CAPI UChar32 U_EXPORT2
+uiter_next32(UCharIterator *iter) {
+    UChar32 c, c2;
+
+    c=iter->next(iter);
+    if(UTF_IS_FIRST_SURROGATE(c)) {
+        if(UTF_IS_SECOND_SURROGATE(c2=iter->next(iter))) {
+            c=UTF16_GET_PAIR_VALUE(c, c2);
+        } else if(c2>=0) {
+            /* unmatched first surrogate, undo index movement */
+            iter->move(iter, -1, UITER_CURRENT);
+        }
+    }
+    return c;
+}
+
+U_CAPI UChar32 U_EXPORT2
+uiter_previous32(UCharIterator *iter) {
+    UChar32 c, c2;
+
+    c=iter->previous(iter);
+    if(UTF_IS_SECOND_SURROGATE(c)) {
+        if(UTF_IS_FIRST_SURROGATE(c2=iter->previous(iter))) {
+            c=UTF16_GET_PAIR_VALUE(c2, c);
+        } else if(c2>=0) {
+            /* unmatched second surrogate, undo index movement */
+            iter->move(iter, 1, UITER_CURRENT);
+        }
+    }
+    return c;
+}
+
+U_CAPI uint32_t U_EXPORT2
+uiter_getState(const UCharIterator *iter) {
+    if(iter==NULL || iter->getState==NULL) {
+        return UITER_NO_STATE;
+    } else {
+        return iter->getState(iter);
+    }
+}
+
+U_CAPI void U_EXPORT2
+uiter_setState(UCharIterator *iter, uint32_t state, UErrorCode *pErrorCode) {
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        /* do nothing */
+    } else if(iter==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+    } else if(iter->setState==NULL) {
+        *pErrorCode=U_UNSUPPORTED_ERROR;
+    } else {
+        iter->setState(iter, state, pErrorCode);
+    }
+}
+
+U_CDECL_END
diff --git a/source/common/ulist.c b/source/common/ulist.c
new file mode 100644
index 0000000..1ef3704
--- /dev/null
+++ b/source/common/ulist.c
@@ -0,0 +1,233 @@
+/*
+******************************************************************************
+*   Copyright (C) 2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+******************************************************************************
+*/
+
+#include "ulist.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uenumimp.h"
+
+typedef struct UListNode UListNode;
+struct UListNode {
+    void *data;
+    
+    UListNode *next;
+    UListNode *previous;
+    
+    /* When data is created with uprv_malloc, needs to be freed during deleteList function. */
+    UBool forceDelete;
+};
+
+struct UList {
+    UListNode *curr;
+    UListNode *head;
+    UListNode *tail;
+    
+    int32_t size;
+    int32_t currentIndex;
+};
+
+static void ulist_addFirstItem(UList *list, UListNode *newItem);
+
+U_CAPI UList *U_EXPORT2 ulist_createEmptyList(UErrorCode *status) {
+    UList *newList = NULL;
+    
+    if (U_FAILURE(*status)) {
+        return NULL;
+    }
+    
+    newList = (UList *)uprv_malloc(sizeof(UList));
+    if (newList == NULL) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    
+    newList->curr = NULL;
+    newList->head = NULL;
+    newList->tail = NULL;
+    newList->size = 0;
+    newList->currentIndex = -1;
+    
+    return newList;
+}
+
+/*
+ * Function called by addItemEndList or addItemBeginList when the first item is added to the list.
+ * This function properly sets the pointers for the first item added.
+ */
+static void ulist_addFirstItem(UList *list, UListNode *newItem) {
+    newItem->next = NULL;
+    newItem->previous = NULL;
+    list->head = newItem;
+    list->tail = newItem;
+    list->currentIndex = 0;
+}
+
+U_CAPI void U_EXPORT2 ulist_addItemEndList(UList *list, const void *data, UBool forceDelete, UErrorCode *status) {
+    UListNode *newItem = NULL;
+    
+    if (U_FAILURE(*status) || list == NULL || data == NULL) {
+        return;
+    }
+    
+    newItem = (UListNode *)uprv_malloc(sizeof(UListNode));
+    if (newItem == NULL) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    newItem->data = (void *)(data);
+    newItem->forceDelete = forceDelete;
+    
+    if (list->size == 0) {
+        ulist_addFirstItem(list, newItem);
+    } else {
+        newItem->next = NULL;
+        newItem->previous = list->tail;
+        list->tail->next = newItem;
+        list->tail = newItem;
+    }
+    
+    list->size++;
+}
+
+U_CAPI void U_EXPORT2 ulist_addItemBeginList(UList *list, const void *data, UBool forceDelete, UErrorCode *status) {
+    UListNode *newItem = NULL;
+    
+    if (U_FAILURE(*status) || list == NULL || data == NULL) {
+        return;
+    }
+    
+    newItem = (UListNode *)uprv_malloc(sizeof(UListNode));
+    if (newItem == NULL) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    newItem->data = (void *)(data);
+    newItem->forceDelete = forceDelete;
+    
+    if (list->size == 0) {
+        ulist_addFirstItem(list, newItem);
+    } else {
+        newItem->previous = NULL;
+        newItem->next = list->head;
+        list->head->previous = newItem;
+        list->head = newItem;
+        list->currentIndex++;
+    }
+    
+    list->size++;
+}
+
+U_CAPI UBool U_EXPORT2 ulist_containsString(const UList *list, const char *data, int32_t length) {
+    UBool result = FALSE;
+    const UListNode *pointer = NULL;
+    
+    if (list != NULL && list->size != 0) {
+        pointer = list->head;
+        
+        while (pointer != NULL) {
+            if (length == uprv_strlen(pointer->data)) {
+                if (uprv_memcmp(data, pointer->data, length) == 0) {
+                    result = TRUE;
+                    break;
+                }
+            }
+            
+            pointer = pointer->next;
+        }
+    }
+    
+    return result;
+}
+
+U_CAPI void *U_EXPORT2 ulist_getNext(UList *list) {
+    UListNode *curr = NULL;
+    
+    if (list == NULL || list->curr == NULL) {
+        return NULL;
+    }
+    
+    curr = list->curr;
+    list->curr = curr->next;
+    list->currentIndex++;
+    
+    return curr->data;
+}
+
+U_CAPI int32_t U_EXPORT2 ulist_getListSize(const UList *list) {
+    if (list != NULL) {
+        return list->size;
+    }
+    
+    return -1;
+}
+
+U_CAPI void U_EXPORT2 ulist_resetList(UList *list) {
+    if (list != NULL) {
+        list->curr = list->head;
+        list->currentIndex = 0;
+    }
+}
+
+U_CAPI void U_EXPORT2 ulist_deleteList(UList *list) {
+    UListNode *listHead = NULL;
+    UListNode *listPointer = NULL;
+    
+    if (list != NULL) {
+        listHead = list->head;
+        listPointer = listHead;
+        while (listHead != NULL) {
+            listPointer = listHead->next;
+            
+            if (listHead->forceDelete) {
+                uprv_free(listHead->data);
+            }
+            
+            uprv_free(listHead);
+            listHead = listPointer;
+        }
+        uprv_free(list);
+        list = NULL;
+    }
+}
+
+U_CAPI void U_EXPORT2 ulist_close_keyword_values_iterator(UEnumeration *en) {
+    if (en != NULL) {
+        ulist_deleteList((UList *)(en->context));
+        uprv_free(en);
+    }
+}
+
+U_CAPI int32_t U_EXPORT2 ulist_count_keyword_values(UEnumeration *en, UErrorCode *status) {
+    if (U_FAILURE(*status)) {
+        return -1;
+    }
+    
+    return ulist_getListSize((UList *)(en->context));
+}
+
+U_CAPI const char * U_EXPORT2 ulist_next_keyword_value(UEnumeration *en, int32_t *resultLength, UErrorCode *status) {
+    if (U_FAILURE(*status)) {
+        return NULL;
+    }
+    
+    /* TODO: resultLength; */
+    
+    return (const char *)ulist_getNext((UList *)(en->context));
+}
+
+U_CAPI void U_EXPORT2 ulist_reset_keyword_values_iterator(UEnumeration *en, UErrorCode *status) {
+    if (U_FAILURE(*status)) {
+        return ;
+    }
+    
+    ulist_resetList((UList *)(en->context));
+}
+
+U_CAPI UList * U_EXPORT2 ulist_getListFromEnum(UEnumeration *en) {
+    return (UList *)(en->context);
+}
+
diff --git a/source/common/ulist.h b/source/common/ulist.h
new file mode 100644
index 0000000..4789247
--- /dev/null
+++ b/source/common/ulist.h
@@ -0,0 +1,46 @@
+/*
+******************************************************************************
+*   Copyright (C) 2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+******************************************************************************
+*/
+
+#ifndef ULIST_H
+#define ULIST_H
+
+#include "unicode/utypes.h"
+#include "unicode/uenum.h"
+
+struct UList;
+typedef struct UList UList;
+
+U_CAPI UList * U_EXPORT2 ulist_createEmptyList(UErrorCode *status);
+
+U_CAPI void U_EXPORT2 ulist_addItemEndList(UList *list, const void *data, UBool forceDelete, UErrorCode *status);
+
+U_CAPI void U_EXPORT2 ulist_addItemBeginList(UList *list, const void *data, UBool forceDelete, UErrorCode *status);
+
+U_CAPI UBool U_EXPORT2 ulist_containsString(const UList *list, const char *data, int32_t length);
+
+U_CAPI void *U_EXPORT2 ulist_getNext(UList *list);
+
+U_CAPI int32_t U_EXPORT2 ulist_getListSize(const UList *list);
+
+U_CAPI void U_EXPORT2 ulist_resetList(UList *list);
+
+U_CAPI void U_EXPORT2 ulist_deleteList(UList *list);
+
+/*
+ * The following are for use when creating UEnumeration object backed by UList.
+ */
+U_CAPI void U_EXPORT2 ulist_close_keyword_values_iterator(UEnumeration *en);
+
+U_CAPI int32_t U_EXPORT2 ulist_count_keyword_values(UEnumeration *en, UErrorCode *status);
+
+U_CAPI const char * U_EXPORT2 ulist_next_keyword_value(UEnumeration* en, int32_t *resultLength, UErrorCode* status);
+
+U_CAPI void U_EXPORT2 ulist_reset_keyword_values_iterator(UEnumeration* en, UErrorCode* status);
+
+U_CAPI UList * U_EXPORT2 ulist_getListFromEnum(UEnumeration *en);
+
+#endif
diff --git a/source/common/uloc.c b/source/common/uloc.c
new file mode 100644
index 0000000..6446503
--- /dev/null
+++ b/source/common/uloc.c
@@ -0,0 +1,2501 @@
+/*
+**********************************************************************
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*
+* File ULOC.CPP
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   04/01/97    aliu        Creation.
+*   08/21/98    stephen     JDK 1.2 sync
+*   12/08/98    rtg         New Locale implementation and C API
+*   03/15/99    damiba      overhaul.
+*   04/06/99    stephen     changed setDefault() to realloc and copy
+*   06/14/99    stephen     Changed calls to ures_open for new params
+*   07/21/99    stephen     Modified setDefault() to propagate to C++
+*   05/14/04    alan        7 years later: refactored, cleaned up, fixed bugs,
+*                           brought canonicalization code into line with spec
+*****************************************************************************/
+
+/*
+   POSIX's locale format, from putil.c: [no spaces]
+
+     ll [ _CC ] [ . MM ] [ @ VV]
+
+     l = lang, C = ctry, M = charmap, V = variant
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/ustring.h"
+#include "unicode/uloc.h"
+
+#include "putilimp.h"
+#include "ustr_imp.h"
+#include "ulocimp.h"
+#include "umutex.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include "ucln_cmn.h"
+#include "locmap.h"
+#include "uarrsort.h"
+#include "uenumimp.h"
+#include "uassert.h"
+
+#include <stdio.h> /* for sprintf */
+
+/* ### Declarations **************************************************/
+
+/* Locale stuff from locid.cpp */
+U_CFUNC void locale_set_default(const char *id);
+U_CFUNC const char *locale_get_default(void);
+U_CFUNC int32_t
+locale_getKeywords(const char *localeID,
+            char prev,
+            char *keywords, int32_t keywordCapacity,
+            char *values, int32_t valuesCapacity, int32_t *valLen,
+            UBool valuesToo,
+            UErrorCode *status);
+
+/* ### Data tables **************************************************/
+
+/**
+ * Table of language codes, both 2- and 3-letter, with preference
+ * given to 2-letter codes where possible.  Includes 3-letter codes
+ * that lack a 2-letter equivalent.
+ *
+ * This list must be in sorted order.  This list is returned directly
+ * to the user by some API.
+ *
+ * This list must be kept in sync with LANGUAGES_3, with corresponding
+ * entries matched.
+ *
+ * This table should be terminated with a NULL entry, followed by a
+ * second list, and another NULL entry.  The first list is visible to
+ * user code when this array is returned by API.  The second list
+ * contains codes we support, but do not expose through user API.
+ *
+ * Notes
+ *
+ * Tables updated per http://lcweb.loc.gov/standards/iso639-2/ to
+ * include the revisions up to 2001/7/27 *CWB*
+ *
+ * The 3 character codes are the terminology codes like RFC 3066.  This
+ * is compatible with prior ICU codes
+ *
+ * "in" "iw" "ji" "jw" & "sh" have been withdrawn but are still in the
+ * table but now at the end of the table because 3 character codes are
+ * duplicates.  This avoids bad searches going from 3 to 2 character
+ * codes.
+ *
+ * The range qaa-qtz is reserved for local use
+ */
+static const char * const LANGUAGES[] = {
+    "aa",  "ab",  "ace", "ach", "ada", "ady", "ae",  "af",  "afa",
+    "afh", "ain", "ak",  "akk", "ale", "alg", "alt", "am",  "an",  
+    "ang", "anp", "apa",
+    "ar",  "arc", "arn", "arp", "art", "arw", "as",  "ast",
+    "ath", "aus", "av",  "awa", "ay",  "az",  "ba",  "bad",
+    "bai", "bal", "ban", "bas", "bat", "be",  "bej",
+    "bem", "ber", "bg",  "bh",  "bho", "bi",  "bik", "bin",
+    "bla", "bm",  "bn",  "bnt", "bo",  "br",  "bra", "bs",
+    "btk", "bua", "bug", "byn", "ca",  "cad", "cai", "car", "cau",
+    "cch", "ce",  "ceb", "cel", "ch",  "chb", "chg", "chk", "chm",
+    "chn", "cho", "chp", "chr", "chy", "cmc", "co",  "cop",
+    "cpe", "cpf", "cpp", "cr",  "crh", "crp", "cs",  "csb", "cu",  "cus",
+    "cv",  "cy",  "da",  "dak", "dar", "day", "de",  "del", "den",
+    "dgr", "din", "doi", "dra", "dsb", "dua", "dum", "dv",  "dyu",
+    "dz",  "ee",  "efi", "egy", "eka", "el",  "elx", "en",
+    "enm", "eo",  "es",  "et",  "eu",  "ewo", "fa",
+    "fan", "fat", "ff",  "fi",  "fil", "fiu", "fj",  "fo",  "fon",
+    "fr",  "frm", "fro", "frr", "frs", "fur", "fy",  
+    "ga",  "gaa", "gay", "gba", "gd",  "gem", "gez", "gil", 
+    "gl",  "gmh", "gn",  "goh", "gon", "gor", "got", "grb", 
+    "grc", "gsw", "gu",  "gv", "gwi", 
+    "ha",  "hai", "haw", "he",  "hi",  "hil", "him",
+    "hit", "hmn", "ho",  "hr",  "hsb", "ht",  "hu",  "hup", "hy",  "hz",
+    "ia",  "iba", "id",  "ie",  "ig",  "ii",  "ijo", "ik",
+    "ilo", "inc", "ine", "inh", "io",  "ira", "iro", "is",  "it",
+    "iu",  "ja",  "jbo", "jpr", "jrb", "jv",  "ka",  "kaa", "kab",
+    "kac", "kaj", "kam", "kar", "kaw", "kbd", "kcg", "kfo", "kg",  "kha", "khi",
+    "kho", "ki",  "kj",  "kk",  "kl",  "km",  "kmb", "kn",
+    "ko",  "kok", "kos", "kpe", "kr",  "krc", "krl", "kro", "kru", "ks",
+    "ku",  "kum", "kut", "kv",  "kw",  "ky",  "la",  "lad",
+    "lah", "lam", "lb",  "lez", "lg",  "li",  "ln",  "lo",  "lol",
+    "loz", "lt",  "lu",  "lua", "lui", "lun", "luo", "lus",
+    "lv",  "mad", "mag", "mai", "mak", "man", "map", "mas",
+    "mdf", "mdr", "men", "mfe", "mg",  "mga", "mh",  "mi",  "mic", "min",
+    "mis", "mk",  "mkh", "ml",  "mn",  "mnc", "mni", "mno",
+    "mo",  "moh", "mos", "mr",  "ms",  "mt",  "mul", "mun",
+    "mus", "mwl", "mwr", "my",  "myn", "myv", "na",  "nah", "nai", "nap",
+    "nb",  "nd",  "nds", "ne",  "new", "ng",  "nia", "nic",
+    "niu", "nl",  "nn",  "no",  "nog", "non", "nqo", "nr",  "nso", "nub",
+    "nv",  "nwc", "ny",  "nym", "nyn", "nyo", "nzi", "oc",  "oj",
+    "om",  "or",  "os",  "osa", "ota", "oto", "pa",  "paa",
+    "pag", "pal", "pam", "pap", "pau", "peo", "phi", "phn",
+    "pi",  "pl",  "pon", "pra", "pro", "ps",  "pt",  "qu",
+    "raj", "rap", "rar", "rm",  "rn",  "ro",  "roa", "rom",
+    "ru",  "rup", "rw",  "sa",  "sad", "sah", "sai", "sal", "sam",
+    "sas", "sat", "sc",  "scn", "sco", "sd",  "se",  "sel", "sem",
+    "sg",  "sga", "sgn", "shn", "si",  "sid", "sio", "sit",
+    "sk",  "sl",  "sla", "sm",  "sma", "smi", "smj", "smn",
+    "sms", "sn",  "snk", "so",  "sog", "son", "sq",  "sr",
+    "srn", "srr", "ss",  "ssa", "st",  "su",  "suk", "sus", "sux",
+    "sv",  "sw",  "syc", "syr", "ta",  "tai", "te",  "tem", "ter",
+    "tet", "tg",  "th",  "ti",  "tig", "tiv", "tk",  "tkl",
+    "tl",  "tlh", "tli", "tmh", "tn",  "to",  "tog", "tpi", "tr", "trv",
+    "ts",  "tsi", "tt",  "tum", "tup", "tut", "tvl", "tw",
+    "ty",  "tyv", "udm", "ug",  "uga", "uk",  "umb", "und", "ur",
+    "uz",  "vai", "ve",  "vi",  "vo",  "vot", "wa",  "wak",
+    "wal", "war", "was", "wen", "wo",  "xal", "xh",  "yao", "yap",
+    "yi",  "yo",  "ypk", "za",  "zap", "zbl", "zen", "zh",  "znd",
+    "zu",  "zun", "zxx", "zza",
+NULL,
+    "in",  "iw",  "ji",  "jw",  "sh",    /* obsolete language codes */
+NULL
+};
+static const char* const DEPRECATED_LANGUAGES[]={
+    "in", "iw", "ji", "jw", NULL, NULL
+};
+static const char* const REPLACEMENT_LANGUAGES[]={
+    "id", "he", "yi", "jv", NULL, NULL
+};
+
+/**
+ * Table of 3-letter language codes.
+ *
+ * This is a lookup table used to convert 3-letter language codes to
+ * their 2-letter equivalent, where possible.  It must be kept in sync
+ * with LANGUAGES.  For all valid i, LANGUAGES[i] must refer to the
+ * same language as LANGUAGES_3[i].  The commented-out lines are
+ * copied from LANGUAGES to make eyeballing this baby easier.
+ *
+ * Where a 3-letter language code has no 2-letter equivalent, the
+ * 3-letter code occupies both LANGUAGES[i] and LANGUAGES_3[i].
+ *
+ * This table should be terminated with a NULL entry, followed by a
+ * second list, and another NULL entry.  The two lists correspond to
+ * the two lists in LANGUAGES.
+ */
+static const char * const LANGUAGES_3[] = {
+/*  "aa",  "ab",  "ace", "ach", "ada", "ady", "ae",  "af",  "afa",    */
+    "aar", "abk", "ace", "ach", "ada", "ady", "ave", "afr", "afa",
+/*  "afh", "ain", "ak",  "akk", "ale", "alg", "alt", "am",  "an",  "ang", "anp", "apa",    */
+    "afh", "ain", "aka", "akk", "ale", "alg", "alt", "amh", "arg", "ang", "anp", "apa",
+/*  "ar",  "arc", "arn", "arp", "art", "arw", "as",  "ast",    */
+    "ara", "arc", "arn", "arp", "art", "arw", "asm", "ast",
+/*  "ath", "aus", "av",  "awa", "ay",  "az",  "ba",  "bad",    */
+    "ath", "aus", "ava", "awa", "aym", "aze", "bak", "bad",
+/*  "bai", "bal", "ban", "bas", "bat", "be",  "bej",    */
+    "bai", "bal", "ban", "bas", "bat", "bel", "bej",
+/*  "bem", "ber", "bg",  "bh",  "bho", "bi",  "bik", "bin",    */
+    "bem", "ber", "bul", "bih", "bho", "bis", "bik", "bin",
+/*  "bla", "bm",  "bn",  "bnt", "bo",  "br",  "bra", "bs",     */
+    "bla", "bam", "ben", "bnt", "bod", "bre", "bra", "bos",
+/*  "btk", "bua", "bug", "byn", "ca",  "cad", "cai", "car", "cau",    */
+    "btk", "bua", "bug", "byn", "cat", "cad", "cai", "car", "cau",
+/*  "cch", "ce",  "ceb", "cel", "ch",  "chb", "chg", "chk", "chm",    */
+    "cch", "che", "ceb", "cel", "cha", "chb", "chg", "chk", "chm",
+/*  "chn", "cho", "chp", "chr", "chy", "cmc", "co",  "cop",    */
+    "chn", "cho", "chp", "chr", "chy", "cmc", "cos", "cop",
+/*  "cpe", "cpf", "cpp", "cr",  "crh", "crp", "cs",  "csb", "cu",  "cus",    */
+    "cpe", "cpf", "cpp", "cre", "crh", "crp", "ces", "csb", "chu", "cus",
+/*  "cv",  "cy",  "da",  "dak", "dar", "day", "de",  "del", "den",    */
+    "chv", "cym", "dan", "dak", "dar", "day", "deu", "del", "den",
+/*  "dgr", "din", "doi", "dra", "dsb", "dua", "dum", "dv",  "dyu",    */
+    "dgr", "din", "doi", "dra", "dsb", "dua", "dum", "div", "dyu",
+/*  "dz",  "ee",  "efi", "egy", "eka", "el",  "elx", "en",     */
+    "dzo", "ewe", "efi", "egy", "eka", "ell", "elx", "eng",
+/*  "enm", "eo",  "es",  "et",  "eu",  "ewo", "fa",     */
+    "enm", "epo", "spa", "est", "eus", "ewo", "fas",
+/*  "fan", "fat", "ff",  "fi",  "fil", "fiu", "fj",  "fo",  "fon",    */
+    "fan", "fat", "ful", "fin", "fil", "fiu", "fij", "fao", "fon",
+/*  "fr",  "frm", "fro", "frr", "frs", "fur", "fy",  "ga",  "gaa", "gay",    */
+    "fra", "frm", "fro", "frr", "frs", "fur", "fry", "gle", "gaa", "gay",
+/*  "gba", "gd",  "gem", "gez", "gil", "gl",  "gmh", "gn",     */
+    "gba", "gla", "gem", "gez", "gil", "glg", "gmh", "grn",
+/*  "goh", "gon", "gor", "got", "grb", "grc", "gsw", "gu",  "gv",     */
+    "goh", "gon", "gor", "got", "grb", "grc", "gsw", "guj", "glv",
+/*  "gwi", "ha",  "hai", "haw", "he",  "hi",  "hil", "him",    */
+    "gwi", "hau", "hai", "haw", "heb", "hin", "hil", "him",
+/*  "hit", "hmn", "ho",  "hr",  "hsb", "ht",  "hu",  "hup", "hy",  "hz",     */
+    "hit", "hmn", "hmo", "hrv", "hsb", "hat", "hun", "hup", "hye", "her",
+/*  "ia",  "iba", "id",  "ie",  "ig",  "ii",  "ijo", "ik",     */
+    "ina", "iba", "ind", "ile", "ibo", "iii", "ijo", "ipk",
+/*  "ilo", "inc", "ine", "inh", "io",  "ira", "iro", "is",  "it",      */
+    "ilo", "inc", "ine", "inh", "ido", "ira", "iro", "isl", "ita",
+/*  "iu",  "ja",  "jbo", "jpr", "jrb", "jv",  "ka",  "kaa", "kab",   */
+    "iku", "jpn", "jbo", "jpr", "jrb", "jav", "kat", "kaa", "kab",
+/*  "kac", "kaj", "kam", "kar", "kaw", "kbd", "kcg", "kfo", "kg",  "kha", "khi",*/
+    "kac", "kaj", "kam", "kar", "kaw", "kbd", "kcg", "kfo", "kg",  "kha", "khi",
+/*  "kho", "ki",  "kj",  "kk",  "kl",  "km",  "kmb", "kn",     */
+    "kho", "kik", "kua", "kaz", "kal", "khm", "kmb", "kan",
+/*  "ko",  "kok", "kos", "kpe", "kr",  "krc", "krl", "kro", "kru", "ks",     */
+    "kor", "kok", "kos", "kpe", "kau", "krc", "krl", "kro", "kru", "kas",
+/*  "ku",  "kum", "kut", "kv",  "kw",  "ky",  "la",  "lad",    */
+    "kur", "kum", "kut", "kom", "cor", "kir", "lat", "lad",
+/*  "lah", "lam", "lb",  "lez", "lg",  "li",  "ln",  "lo",  "lol",    */
+    "lah", "lam", "ltz", "lez", "lug", "lim", "lin", "lao", "lol",
+/*  "loz", "lt",  "lu",  "lua", "lui", "lun", "luo", "lus",    */
+    "loz", "lit", "lub", "lua", "lui", "lun", "luo", "lus",
+/*  "lv",  "mad", "mag", "mai", "mak", "man", "map", "mas",    */
+    "lav", "mad", "mag", "mai", "mak", "man", "map", "mas",
+/*  "mdf", "mdr", "men", "mfe", "mg",  "mga", "mh",  "mi",  "mic", "min",    */
+    "mdf", "mdr", "men", "mfe", "mlg", "mga", "mah", "mri", "mic", "min",
+/*  "mis", "mk",  "mkh", "ml",  "mn",  "mnc", "mni", "mno",    */
+    "mis", "mkd", "mkh", "mal", "mon", "mnc", "mni", "mno",
+/*  "mo",  "moh", "mos", "mr",  "ms",  "mt",  "mul", "mun",    */
+    "mol", "moh", "mos", "mar", "msa", "mlt", "mul", "mun",
+/*  "mus", "mwl", "mwr", "my",  "myn", "myv", "na",  "nah", "nai", "nap",    */
+    "mus", "mwl", "mwr", "mya", "myn", "myv", "nau", "nah", "nai", "nap",
+/*  "nb",  "nd",  "nds", "ne",  "new", "ng",  "nia", "nic",    */
+    "nob", "nde", "nds", "nep", "new", "ndo", "nia", "nic",
+/*  "niu", "nl",  "nn",  "no",  "nog", "non", "nqo", "nr",  "nso", "nub",    */
+    "niu", "nld", "nno", "nor", "nog", "non", "nqo", "nbl", "nso", "nub",
+/*  "nv",  "nwc", "ny",  "nym", "nyn", "nyo", "nzi", "oc",  "oj",     */
+    "nav", "nwc", "nya", "nym", "nyn", "nyo", "nzi", "oci", "oji",
+/*  "om",  "or",  "os",  "osa", "ota", "oto", "pa",  "paa",    */
+    "orm", "ori", "oss", "osa", "ota", "oto", "pan", "paa",
+/*  "pag", "pal", "pam", "pap", "pau", "peo", "phi", "phn",    */
+    "pag", "pal", "pam", "pap", "pau", "peo", "phi", "phn",
+/*  "pi",  "pl",  "pon", "pra", "pro", "ps",  "pt",  "qu",     */
+    "pli", "pol", "pon", "pra", "pro", "pus", "por", "que",
+/*  "raj", "rap", "rar", "rm",  "rn",  "ro",  "roa", "rom",    */
+    "raj", "rap", "rar", "roh", "run", "ron", "roa", "rom",
+/*  "ru",  "rup", "rw",  "sa",  "sad", "sah", "sai", "sal", "sam",    */
+    "rus", "rup", "kin", "san", "sad", "sah", "sai", "sal", "sam",
+/*  "sas", "sat", "sc",  "scn", "sco", "sd",  "se",  "sel", "sem",    */
+    "sas", "sat", "srd", "scn", "sco", "snd", "sme", "sel", "sem",
+/*  "sg",  "sga", "sgn", "shn", "si",  "sid", "sio", "sit",    */
+    "sag", "sga", "sgn", "shn", "sin", "sid", "sio", "sit",
+/*  "sk",  "sl",  "sla", "sm",  "sma", "smi", "smj", "smn",    */
+    "slk", "slv", "sla", "smo", "sma", "smi", "smj", "smn",
+/*  "sms", "sn",  "snk", "so",  "sog", "son", "sq",  "sr",     */
+    "sms", "sna", "snk", "som", "sog", "son", "sqi", "srp",
+/*  "srn", "srr", "ss",  "ssa", "st",  "su",  "suk", "sus", "sux",    */
+    "srn", "srr", "ssw", "ssa", "sot", "sun", "suk", "sus", "sux",
+/*  "sv",  "sw",  "syc", "syr", "ta",  "tai", "te",  "tem", "ter",    */
+    "swe", "swa", "syc", "syr", "tam", "tai", "tel", "tem", "ter",
+/*  "tet", "tg",  "th",  "ti",  "tig", "tiv", "tk",  "tkl",    */
+    "tet", "tgk", "tha", "tir", "tig", "tiv", "tuk", "tkl",
+/*  "tl",  "tlh", "tli", "tmh", "tn",  "to",  "tog", "tpi", "tr", "trv",    */
+    "tgl", "tlh", "tli", "tmh", "tsn", "ton", "tog", "tpi", "tur", "trv",
+/*  "ts",  "tsi", "tt",  "tum", "tup", "tut", "tvl", "tw",     */
+    "tso", "tsi", "tat", "tum", "tup", "tut", "tvl", "twi",
+/*  "ty",  "tyv", "udm", "ug",  "uga", "uk",  "umb", "und", "ur",     */
+    "tah", "tyv", "udm", "uig", "uga", "ukr", "umb", "und", "urd",
+/*  "uz",  "vai", "ve",  "vi",  "vo",  "vot", "wa",  "wak",    */
+    "uzb", "vai", "ven", "vie", "vol", "vot", "wln", "wak",
+/*  "wal", "war", "was", "wen", "wo",  "xal", "xh",  "yao", "yap",    */
+    "wal", "war", "was", "wen", "wol", "xal", "xho", "yao", "yap",
+/*  "yi",  "yo",  "ypk", "za",  "zap", "zbl", "zen", "zh",  "znd",    */
+    "yid", "yor", "ypk", "zha", "zap", "zbl", "zen", "zho", "znd",
+/*  "zu",  "zun", "zxx", "zza",                                         */
+    "zul", "zun", "zxx", "zza",
+NULL,
+/*  "in",  "iw",  "ji",  "jw",  "sh",                          */
+    "ind", "heb", "yid", "jaw", "srp",
+NULL
+};
+
+/**
+ * Table of 2-letter country codes.
+ *
+ * This list must be in sorted order.  This list is returned directly
+ * to the user by some API.
+ *
+ * This list must be kept in sync with COUNTRIES_3, with corresponding
+ * entries matched.
+ *
+ * This table should be terminated with a NULL entry, followed by a
+ * second list, and another NULL entry.  The first list is visible to
+ * user code when this array is returned by API.  The second list
+ * contains codes we support, but do not expose through user API.
+ *
+ * Notes:
+ *
+ * ZR(ZAR) is now CD(COD) and FX(FXX) is PS(PSE) as per
+ * http://www.evertype.com/standards/iso3166/iso3166-1-en.html added
+ * new codes keeping the old ones for compatibility updated to include
+ * 1999/12/03 revisions *CWB*
+ *
+ * RO(ROM) is now RO(ROU) according to
+ * http://www.iso.org/iso/en/prods-services/iso3166ma/03updates-on-iso-3166/nlv3e-rou.html
+ */
+static const char * const COUNTRIES[] = {
+    "AD",  "AE",  "AF",  "AG",  "AI",  "AL",  "AM",  "AN",
+    "AO",  "AQ",  "AR",  "AS",  "AT",  "AU",  "AW",  "AX",  "AZ",
+    "BA",  "BB",  "BD",  "BE",  "BF",  "BG",  "BH",  "BI",
+    "BJ",  "BL",  "BM",  "BN",  "BO",  "BR",  "BS",  "BT",  "BV",
+    "BW",  "BY",  "BZ",  "CA",  "CC",  "CD",  "CF",  "CG",
+    "CH",  "CI",  "CK",  "CL",  "CM",  "CN",  "CO",  "CR",
+    "CU",  "CV",  "CX",  "CY",  "CZ",  "DE",  "DJ",  "DK",
+    "DM",  "DO",  "DZ",  "EC",  "EE",  "EG",  "EH",  "ER",
+    "ES",  "ET",  "FI",  "FJ",  "FK",  "FM",  "FO",  "FR",
+    "GA",  "GB",  "GD",  "GE",  "GF",  "GG",  "GH",  "GI",  "GL",
+    "GM",  "GN",  "GP",  "GQ",  "GR",  "GS",  "GT",  "GU",
+    "GW",  "GY",  "HK",  "HM",  "HN",  "HR",  "HT",  "HU",
+    "ID",  "IE",  "IL",  "IM",  "IN",  "IO",  "IQ",  "IR",  "IS",
+    "IT",  "JE",  "JM",  "JO",  "JP",  "KE",  "KG",  "KH",  "KI",
+    "KM",  "KN",  "KP",  "KR",  "KW",  "KY",  "KZ",  "LA",
+    "LB",  "LC",  "LI",  "LK",  "LR",  "LS",  "LT",  "LU",
+    "LV",  "LY",  "MA",  "MC",  "MD",  "ME",  "MF",  "MG",  "MH",  "MK",
+    "ML",  "MM",  "MN",  "MO",  "MP",  "MQ",  "MR",  "MS",
+    "MT",  "MU",  "MV",  "MW",  "MX",  "MY",  "MZ",  "NA",
+    "NC",  "NE",  "NF",  "NG",  "NI",  "NL",  "NO",  "NP",
+    "NR",  "NU",  "NZ",  "OM",  "PA",  "PE",  "PF",  "PG",
+    "PH",  "PK",  "PL",  "PM",  "PN",  "PR",  "PS",  "PT",
+    "PW",  "PY",  "QA",  "RE",  "RO",  "RS",  "RU",  "RW",  "SA",
+    "SB",  "SC",  "SD",  "SE",  "SG",  "SH",  "SI",  "SJ",
+    "SK",  "SL",  "SM",  "SN",  "SO",  "SR",  "ST",  "SV",
+    "SY",  "SZ",  "TC",  "TD",  "TF",  "TG",  "TH",  "TJ",
+    "TK",  "TL",  "TM",  "TN",  "TO",  "TR",  "TT",  "TV",
+    "TW",  "TZ",  "UA",  "UG",  "UM",  "US",  "UY",  "UZ",
+    "VA",  "VC",  "VE",  "VG",  "VI",  "VN",  "VU",  "WF",
+    "WS",  "YE",  "YT",  "ZA",  "ZM",  "ZW",
+NULL,
+    "FX",  "CS",  "RO",  "TP",  "YU",  "ZR",   /* obsolete country codes */
+NULL
+};
+
+static const char* const DEPRECATED_COUNTRIES[] ={
+    "BU", "CS", "DY", "FX", "HV", "NH", "RH", "TP", "YU", "ZR", NULL, NULL /* deprecated country list */
+};
+static const char* const REPLACEMENT_COUNTRIES[] = {
+/*  "BU", "CS", "DY", "FX", "HV", "NH", "RH", "TP", "YU", "ZR" */
+    "MM", "RS", "BJ", "FR", "BF", "VU", "ZW", "TL", "RS", "CD", NULL, NULL  /* replacement country codes */      
+};
+    
+/**
+ * Table of 3-letter country codes.
+ *
+ * This is a lookup table used to convert 3-letter country codes to
+ * their 2-letter equivalent.  It must be kept in sync with COUNTRIES.
+ * For all valid i, COUNTRIES[i] must refer to the same country as
+ * COUNTRIES_3[i].  The commented-out lines are copied from COUNTRIES
+ * to make eyeballing this baby easier.
+ *
+ * This table should be terminated with a NULL entry, followed by a
+ * second list, and another NULL entry.  The two lists correspond to
+ * the two lists in COUNTRIES.
+ */
+static const char * const COUNTRIES_3[] = {
+/*  "AD",  "AE",  "AF",  "AG",  "AI",  "AL",  "AM",  "AN",     */
+    "AND", "ARE", "AFG", "ATG", "AIA", "ALB", "ARM", "ANT",
+/*  "AO",  "AQ",  "AR",  "AS",  "AT",  "AU",  "AW",  "AX",  "AZ",     */
+    "AGO", "ATA", "ARG", "ASM", "AUT", "AUS", "ABW", "ALA", "AZE",
+/*  "BA",  "BB",  "BD",  "BE",  "BF",  "BG",  "BH",  "BI",     */
+    "BIH", "BRB", "BGD", "BEL", "BFA", "BGR", "BHR", "BDI",
+/*  "BJ",  "BL",  "BM",  "BN",  "BO",  "BR",  "BS",  "BT",  "BV",     */
+    "BEN", "BLM", "BMU", "BRN", "BOL", "BRA", "BHS", "BTN", "BVT",
+/*  "BW",  "BY",  "BZ",  "CA",  "CC",  "CD",  "CF",  "CG",     */
+    "BWA", "BLR", "BLZ", "CAN", "CCK", "COD", "CAF", "COG",
+/*  "CH",  "CI",  "CK",  "CL",  "CM",  "CN",  "CO",  "CR",     */
+    "CHE", "CIV", "COK", "CHL", "CMR", "CHN", "COL", "CRI",
+/*  "CU",  "CV",  "CX",  "CY",  "CZ",  "DE",  "DJ",  "DK",     */
+    "CUB", "CPV", "CXR", "CYP", "CZE", "DEU", "DJI", "DNK",
+/*  "DM",  "DO",  "DZ",  "EC",  "EE",  "EG",  "EH",  "ER",     */
+    "DMA", "DOM", "DZA", "ECU", "EST", "EGY", "ESH", "ERI",
+/*  "ES",  "ET",  "FI",  "FJ",  "FK",  "FM",  "FO",  "FR",     */
+    "ESP", "ETH", "FIN", "FJI", "FLK", "FSM", "FRO", "FRA",
+/*  "GA",  "GB",  "GD",  "GE",  "GF",  "GG",  "GH",  "GI",  "GL",     */
+    "GAB", "GBR", "GRD", "GEO", "GUF", "GGY", "GHA", "GIB", "GRL",
+/*  "GM",  "GN",  "GP",  "GQ",  "GR",  "GS",  "GT",  "GU",     */
+    "GMB", "GIN", "GLP", "GNQ", "GRC", "SGS", "GTM", "GUM",
+/*  "GW",  "GY",  "HK",  "HM",  "HN",  "HR",  "HT",  "HU",     */
+    "GNB", "GUY", "HKG", "HMD", "HND", "HRV", "HTI", "HUN",
+/*  "ID",  "IE",  "IL",  "IM",  "IN",  "IO",  "IQ",  "IR",  "IS" */
+    "IDN", "IRL", "ISR", "IMN", "IND", "IOT", "IRQ", "IRN", "ISL",
+/*  "IT",  "JE",  "JM",  "JO",  "JP",  "KE",  "KG",  "KH",  "KI",     */
+    "ITA", "JEY", "JAM", "JOR", "JPN", "KEN", "KGZ", "KHM", "KIR",
+/*  "KM",  "KN",  "KP",  "KR",  "KW",  "KY",  "KZ",  "LA",     */
+    "COM", "KNA", "PRK", "KOR", "KWT", "CYM", "KAZ", "LAO",
+/*  "LB",  "LC",  "LI",  "LK",  "LR",  "LS",  "LT",  "LU",     */
+    "LBN", "LCA", "LIE", "LKA", "LBR", "LSO", "LTU", "LUX",
+/*  "LV",  "LY",  "MA",  "MC",  "MD",  "ME",  "MF",  "MG",  "MH",  "MK",     */
+    "LVA", "LBY", "MAR", "MCO", "MDA", "MNE", "MAF", "MDG", "MHL", "MKD",
+/*  "ML",  "MM",  "MN",  "MO",  "MP",  "MQ",  "MR",  "MS",     */
+    "MLI", "MMR", "MNG", "MAC", "MNP", "MTQ", "MRT", "MSR",
+/*  "MT",  "MU",  "MV",  "MW",  "MX",  "MY",  "MZ",  "NA",     */
+    "MLT", "MUS", "MDV", "MWI", "MEX", "MYS", "MOZ", "NAM",
+/*  "NC",  "NE",  "NF",  "NG",  "NI",  "NL",  "NO",  "NP",     */
+    "NCL", "NER", "NFK", "NGA", "NIC", "NLD", "NOR", "NPL",
+/*  "NR",  "NU",  "NZ",  "OM",  "PA",  "PE",  "PF",  "PG",     */
+    "NRU", "NIU", "NZL", "OMN", "PAN", "PER", "PYF", "PNG",
+/*  "PH",  "PK",  "PL",  "PM",  "PN",  "PR",  "PS",  "PT",     */
+    "PHL", "PAK", "POL", "SPM", "PCN", "PRI", "PSE", "PRT",
+/*  "PW",  "PY",  "QA",  "RE",  "RO",  "RS",  "RU",  "RW",  "SA",     */
+    "PLW", "PRY", "QAT", "REU", "ROU", "SRB", "RUS", "RWA", "SAU",
+/*  "SB",  "SC",  "SD",  "SE",  "SG",  "SH",  "SI",  "SJ",     */
+    "SLB", "SYC", "SDN", "SWE", "SGP", "SHN", "SVN", "SJM",
+/*  "SK",  "SL",  "SM",  "SN",  "SO",  "SR",  "ST",  "SV",     */
+    "SVK", "SLE", "SMR", "SEN", "SOM", "SUR", "STP", "SLV",
+/*  "SY",  "SZ",  "TC",  "TD",  "TF",  "TG",  "TH",  "TJ",     */
+    "SYR", "SWZ", "TCA", "TCD", "ATF", "TGO", "THA", "TJK",
+/*  "TK",  "TL",  "TM",  "TN",  "TO",  "TR",  "TT",  "TV",     */
+    "TKL", "TLS", "TKM", "TUN", "TON", "TUR", "TTO", "TUV",
+/*  "TW",  "TZ",  "UA",  "UG",  "UM",  "US",  "UY",  "UZ",     */
+    "TWN", "TZA", "UKR", "UGA", "UMI", "USA", "URY", "UZB",
+/*  "VA",  "VC",  "VE",  "VG",  "VI",  "VN",  "VU",  "WF",     */
+    "VAT", "VCT", "VEN", "VGB", "VIR", "VNM", "VUT", "WLF",
+/*  "WS",  "YE",  "YT",  "ZA",  "ZM",  "ZW",          */
+    "WSM", "YEM", "MYT", "ZAF", "ZMB", "ZWE",
+NULL,
+/*  "FX",  "CS",  "RO",  "TP",  "YU",  "ZR",   */
+    "FXX", "SCG", "ROM", "TMP", "YUG", "ZAR",
+NULL
+};
+
+typedef struct CanonicalizationMap {
+    const char *id;          /* input ID */
+    const char *canonicalID; /* canonicalized output ID */
+    const char *keyword;     /* keyword, or NULL if none */
+    const char *value;       /* keyword value, or NULL if kw==NULL */
+} CanonicalizationMap;
+
+/**
+ * A map to canonicalize locale IDs.  This handles a variety of
+ * different semantic kinds of transformations.
+ */
+static const CanonicalizationMap CANONICALIZE_MAP[] = {
+    { "",               "en_US_POSIX", NULL, NULL }, /* .NET name */
+    { "c",              "en_US_POSIX", NULL, NULL }, /* POSIX name */
+    { "posix",          "en_US_POSIX", NULL, NULL }, /* POSIX name (alias of C) */
+    { "art_LOJBAN",     "jbo", NULL, NULL }, /* registered name */
+    { "az_AZ_CYRL",     "az_Cyrl_AZ", NULL, NULL }, /* .NET name */
+    { "az_AZ_LATN",     "az_Latn_AZ", NULL, NULL }, /* .NET name */
+    { "ca_ES_PREEURO",  "ca_ES", "currency", "ESP" },
+    { "cel_GAULISH",    "cel__GAULISH", NULL, NULL }, /* registered name */
+    { "de_1901",        "de__1901", NULL, NULL }, /* registered name */
+    { "de_1906",        "de__1906", NULL, NULL }, /* registered name */
+    { "de__PHONEBOOK",  "de", "collation", "phonebook" }, /* Old ICU name */
+    { "de_AT_PREEURO",  "de_AT", "currency", "ATS" },
+    { "de_DE_PREEURO",  "de_DE", "currency", "DEM" },
+    { "de_LU_PREEURO",  "de_LU", "currency", "LUF" },
+    { "el_GR_PREEURO",  "el_GR", "currency", "GRD" },
+    { "en_BOONT",       "en__BOONT", NULL, NULL }, /* registered name */
+    { "en_SCOUSE",      "en__SCOUSE", NULL, NULL }, /* registered name */
+    { "en_BE_PREEURO",  "en_BE", "currency", "BEF" },
+    { "en_IE_PREEURO",  "en_IE", "currency", "IEP" },
+    { "es__TRADITIONAL", "es", "collation", "traditional" }, /* Old ICU name */
+    { "es_ES_PREEURO",  "es_ES", "currency", "ESP" },
+    { "eu_ES_PREEURO",  "eu_ES", "currency", "ESP" },
+    { "fi_FI_PREEURO",  "fi_FI", "currency", "FIM" },
+    { "fr_BE_PREEURO",  "fr_BE", "currency", "BEF" },
+    { "fr_FR_PREEURO",  "fr_FR", "currency", "FRF" },
+    { "fr_LU_PREEURO",  "fr_LU", "currency", "LUF" },
+    { "ga_IE_PREEURO",  "ga_IE", "currency", "IEP" },
+    { "gl_ES_PREEURO",  "gl_ES", "currency", "ESP" },
+    { "hi__DIRECT",     "hi", "collation", "direct" }, /* Old ICU name */
+    { "it_IT_PREEURO",  "it_IT", "currency", "ITL" },
+    { "ja_JP_TRADITIONAL", "ja_JP", "calendar", "japanese" }, /* Old ICU name */
+    { "nb_NO_NY",       "nn_NO", NULL, NULL },  /* "markus said this was ok" :-) */
+    { "nl_BE_PREEURO",  "nl_BE", "currency", "BEF" },
+    { "nl_NL_PREEURO",  "nl_NL", "currency", "NLG" },
+    { "pt_PT_PREEURO",  "pt_PT", "currency", "PTE" },
+    { "sl_ROZAJ",       "sl__ROZAJ", NULL, NULL }, /* registered name */
+    { "sr_SP_CYRL",     "sr_Cyrl_RS", NULL, NULL }, /* .NET name */
+    { "sr_SP_LATN",     "sr_Latn_RS", NULL, NULL }, /* .NET name */
+    { "sr_YU_CYRILLIC", "sr_Cyrl_RS", NULL, NULL }, /* Linux name */
+    { "th_TH_TRADITIONAL", "th_TH", "calendar", "buddhist" }, /* Old ICU name */
+    { "uz_UZ_CYRILLIC", "uz_Cyrl_UZ", NULL, NULL }, /* Linux name */
+    { "uz_UZ_CYRL",     "uz_Cyrl_UZ", NULL, NULL }, /* .NET name */
+    { "uz_UZ_LATN",     "uz_Latn_UZ", NULL, NULL }, /* .NET name */
+    { "zh_CHS",         "zh_Hans", NULL, NULL }, /* .NET name */
+    { "zh_CHT",         "zh_Hant", NULL, NULL }, /* .NET name */
+    { "zh_GAN",         "zh__GAN", NULL, NULL }, /* registered name */
+    { "zh_GUOYU",       "zh", NULL, NULL }, /* registered name */
+    { "zh_HAKKA",       "zh__HAKKA", NULL, NULL }, /* registered name */
+    { "zh_MIN",         "zh__MIN", NULL, NULL }, /* registered name */
+    { "zh_MIN_NAN",     "zh__MINNAN", NULL, NULL }, /* registered name */
+    { "zh_WUU",         "zh__WUU", NULL, NULL }, /* registered name */
+    { "zh_XIANG",       "zh__XIANG", NULL, NULL }, /* registered name */
+    { "zh_YUE",         "zh__YUE", NULL, NULL }, /* registered name */
+};
+
+typedef struct VariantMap {
+    const char *variant;          /* input ID */
+    const char *keyword;     /* keyword, or NULL if none */
+    const char *value;       /* keyword value, or NULL if kw==NULL */
+} VariantMap;
+
+static const VariantMap VARIANT_MAP[] = {
+    { "EURO",   "currency", "EUR" },
+    { "PINYIN", "collation", "pinyin" }, /* Solaris variant */
+    { "STROKE", "collation", "stroke" }  /* Solaris variant */
+};
+
+/* ### BCP47 Conversion *******************************************/
+/* Test if the locale id has BCP47 u extension and does not have '@' */
+#define _hasBCP47Extension(id) (id && uprv_strstr(id, "@") == NULL && getShortestSubtagLength(localeID) == 1)
+/* Converts the BCP47 id to Unicode id. Does nothing to id if conversion fails */
+#define _ConvertBCP47(finalID, id, buffer, length,err) \
+        if (uloc_forLanguageTag(id, buffer, length, NULL, err) <= 0 || U_FAILURE(*err)) { \
+            finalID=id; \
+        } else { \
+            finalID=buffer; \
+        }
+/* Gets the size of the shortest subtag in the given localeID. */
+static int32_t getShortestSubtagLength(const char *localeID) {
+    int32_t localeIDLength = uprv_strlen(localeID);
+    int32_t length = localeIDLength;
+    int32_t tmpLength = 0;
+    int32_t i;
+    UBool reset = TRUE;
+
+    for (i = 0; i < localeIDLength; i++) {
+        if (localeID[i] != '_' && localeID[i] != '-') {
+            if (reset) {
+                tmpLength = 0;
+                reset = FALSE;
+            }
+            tmpLength++;
+        } else {
+            if (tmpLength != 0 && tmpLength < length) {
+                length = tmpLength;
+            }
+            reset = TRUE;
+        }
+    }
+
+    return length;
+}
+
+/* ### Keywords **************************************************/
+
+#define ULOC_KEYWORD_BUFFER_LEN 25
+#define ULOC_MAX_NO_KEYWORDS 25
+
+U_CAPI const char * U_EXPORT2
+locale_getKeywordsStart(const char *localeID) {
+    const char *result = NULL;
+    if((result = uprv_strchr(localeID, '@')) != NULL) {
+        return result;
+    }
+#if (U_CHARSET_FAMILY == U_EBCDIC_FAMILY)
+    else {
+        /* We do this because the @ sign is variant, and the @ sign used on one
+        EBCDIC machine won't be compiled the same way on other EBCDIC based
+        machines. */
+        static const uint8_t ebcdicSigns[] = { 0x7C, 0x44, 0x66, 0x80, 0xAC, 0xAE, 0xAF, 0xB5, 0xEC, 0xEF, 0x00 };
+        const uint8_t *charToFind = ebcdicSigns;
+        while(*charToFind) {
+            if((result = uprv_strchr(localeID, *charToFind)) != NULL) {
+                return result;
+            }
+            charToFind++;
+        }
+    }
+#endif
+    return NULL;
+}
+
+/**
+ * @param buf buffer of size [ULOC_KEYWORD_BUFFER_LEN]
+ * @param keywordName incoming name to be canonicalized
+ * @param status return status (keyword too long)
+ * @return length of the keyword name
+ */
+static int32_t locale_canonKeywordName(char *buf, const char *keywordName, UErrorCode *status)
+{
+  int32_t i;
+  int32_t keywordNameLen = (int32_t)uprv_strlen(keywordName);
+  
+  if(keywordNameLen >= ULOC_KEYWORD_BUFFER_LEN) {
+    /* keyword name too long for internal buffer */
+    *status = U_INTERNAL_PROGRAM_ERROR;
+          return 0;
+  }
+  
+  /* normalize the keyword name */
+  for(i = 0; i < keywordNameLen; i++) {
+    buf[i] = uprv_tolower(keywordName[i]);
+  }
+  buf[i] = 0;
+    
+  return keywordNameLen;
+}
+
+typedef struct {
+    char keyword[ULOC_KEYWORD_BUFFER_LEN];
+    int32_t keywordLen;
+    const char *valueStart;
+    int32_t valueLen;
+} KeywordStruct;
+
+static int32_t U_CALLCONV
+compareKeywordStructs(const void *context, const void *left, const void *right) {
+    const char* leftString = ((const KeywordStruct *)left)->keyword;
+    const char* rightString = ((const KeywordStruct *)right)->keyword;
+    return uprv_strcmp(leftString, rightString);
+}
+
+/**
+ * Both addKeyword and addValue must already be in canonical form.
+ * Either both addKeyword and addValue are NULL, or neither is NULL.
+ * If they are not NULL they must be zero terminated.
+ * If addKeyword is not NULL is must have length small enough to fit in KeywordStruct.keyword.
+ */
+static int32_t
+_getKeywords(const char *localeID,
+             char prev,
+             char *keywords, int32_t keywordCapacity,
+             char *values, int32_t valuesCapacity, int32_t *valLen,
+             UBool valuesToo,
+             const char* addKeyword,
+             const char* addValue,
+             UErrorCode *status)
+{
+    KeywordStruct keywordList[ULOC_MAX_NO_KEYWORDS];
+    
+    int32_t maxKeywords = ULOC_MAX_NO_KEYWORDS;
+    int32_t numKeywords = 0;
+    const char* pos = localeID;
+    const char* equalSign = NULL;
+    const char* semicolon = NULL;
+    int32_t i = 0, j, n;
+    int32_t keywordsLen = 0;
+    int32_t valuesLen = 0;
+
+    if(prev == '@') { /* start of keyword definition */
+        /* we will grab pairs, trim spaces, lowercase keywords, sort and return */
+        do {
+            UBool duplicate = FALSE;
+            /* skip leading spaces */
+            while(*pos == ' ') {
+                pos++;
+            }
+            if (!*pos) { /* handle trailing "; " */
+                break;
+            }
+            if(numKeywords == maxKeywords) {
+                *status = U_INTERNAL_PROGRAM_ERROR;
+                return 0;
+            }
+            equalSign = uprv_strchr(pos, '=');
+            semicolon = uprv_strchr(pos, ';');
+            /* lack of '=' [foo@currency] is illegal */
+            /* ';' before '=' [foo@currency;collation=pinyin] is illegal */
+            if(!equalSign || (semicolon && semicolon<equalSign)) {
+                *status = U_INVALID_FORMAT_ERROR;
+                return 0;
+            }
+            /* need to normalize both keyword and keyword name */
+            if(equalSign - pos >= ULOC_KEYWORD_BUFFER_LEN) {
+                /* keyword name too long for internal buffer */
+                *status = U_INTERNAL_PROGRAM_ERROR;
+                return 0;
+            }
+            for(i = 0, n = 0; i < equalSign - pos; ++i) {
+                if (pos[i] != ' ') {
+                    keywordList[numKeywords].keyword[n++] = uprv_tolower(pos[i]);
+                }
+            }
+            keywordList[numKeywords].keyword[n] = 0;
+            keywordList[numKeywords].keywordLen = n;
+            /* now grab the value part. First we skip the '=' */
+            equalSign++;
+            /* then we leading spaces */
+            while(*equalSign == ' ') {
+                equalSign++;
+            }
+            keywordList[numKeywords].valueStart = equalSign;
+            
+            pos = semicolon;
+            i = 0;
+            if(pos) {
+                while(*(pos - i - 1) == ' ') {
+                    i++;
+                }
+                keywordList[numKeywords].valueLen = (int32_t)(pos - equalSign - i);
+                pos++;
+            } else {
+                i = (int32_t)uprv_strlen(equalSign);
+                while(equalSign[i-1] == ' ') {
+                    i--;
+                }
+                keywordList[numKeywords].valueLen = i;
+            }
+            /* If this is a duplicate keyword, then ignore it */
+            for (j=0; j<numKeywords; ++j) {
+                if (uprv_strcmp(keywordList[j].keyword, keywordList[numKeywords].keyword) == 0) {
+                    duplicate = TRUE;
+                    break;
+                }
+            }
+            if (!duplicate) {
+                ++numKeywords;
+            }
+        } while(pos);
+
+        /* Handle addKeyword/addValue. */
+        if (addKeyword != NULL) {
+            UBool duplicate = FALSE;
+            U_ASSERT(addValue != NULL);
+            /* Search for duplicate; if found, do nothing. Explicit keyword
+               overrides addKeyword. */
+            for (j=0; j<numKeywords; ++j) {
+                if (uprv_strcmp(keywordList[j].keyword, addKeyword) == 0) {
+                    duplicate = TRUE;
+                    break;
+                }
+            }
+            if (!duplicate) {
+                if (numKeywords == maxKeywords) {
+                    *status = U_INTERNAL_PROGRAM_ERROR;
+                    return 0;
+                }
+                uprv_strcpy(keywordList[numKeywords].keyword, addKeyword);
+                keywordList[numKeywords].keywordLen = (int32_t)uprv_strlen(addKeyword);
+                keywordList[numKeywords].valueStart = addValue;
+                keywordList[numKeywords].valueLen = (int32_t)uprv_strlen(addValue);
+                ++numKeywords;
+            }
+        } else {
+            U_ASSERT(addValue == NULL);
+        }
+
+        /* now we have a list of keywords */
+        /* we need to sort it */
+        uprv_sortArray(keywordList, numKeywords, sizeof(KeywordStruct), compareKeywordStructs, NULL, FALSE, status);
+        
+        /* Now construct the keyword part */
+        for(i = 0; i < numKeywords; i++) {
+            if(keywordsLen + keywordList[i].keywordLen + 1< keywordCapacity) {
+                uprv_strcpy(keywords+keywordsLen, keywordList[i].keyword);
+                if(valuesToo) {
+                    keywords[keywordsLen + keywordList[i].keywordLen] = '=';
+                } else {
+                    keywords[keywordsLen + keywordList[i].keywordLen] = 0;
+                }
+            }
+            keywordsLen += keywordList[i].keywordLen + 1;
+            if(valuesToo) {
+                if(keywordsLen + keywordList[i].valueLen < keywordCapacity) {
+                    uprv_strncpy(keywords+keywordsLen, keywordList[i].valueStart, keywordList[i].valueLen);
+                }
+                keywordsLen += keywordList[i].valueLen;
+                
+                if(i < numKeywords - 1) {
+                    if(keywordsLen < keywordCapacity) {       
+                        keywords[keywordsLen] = ';';
+                    }
+                    keywordsLen++;
+                }
+            }
+            if(values) {
+                if(valuesLen + keywordList[i].valueLen + 1< valuesCapacity) {
+                    uprv_strcpy(values+valuesLen, keywordList[i].valueStart);
+                    values[valuesLen + keywordList[i].valueLen] = 0;
+                }
+                valuesLen += keywordList[i].valueLen + 1;
+            }
+        }
+        if(values) {
+            values[valuesLen] = 0;
+            if(valLen) {
+                *valLen = valuesLen;
+            }
+        }
+        return u_terminateChars(keywords, keywordCapacity, keywordsLen, status);   
+    } else {
+        return 0;
+    }
+}
+
+U_CFUNC int32_t
+locale_getKeywords(const char *localeID,
+                   char prev,
+                   char *keywords, int32_t keywordCapacity,
+                   char *values, int32_t valuesCapacity, int32_t *valLen,
+                   UBool valuesToo,
+                   UErrorCode *status) {
+    return _getKeywords(localeID, prev, keywords, keywordCapacity,
+                        values, valuesCapacity, valLen, valuesToo,
+                        NULL, NULL, status);
+}
+
+U_CAPI int32_t U_EXPORT2
+uloc_getKeywordValue(const char* localeID,
+                     const char* keywordName,
+                     char* buffer, int32_t bufferCapacity,
+                     UErrorCode* status)
+{ 
+    const char* startSearchHere = NULL;
+    const char* nextSeparator = NULL;
+    char keywordNameBuffer[ULOC_KEYWORD_BUFFER_LEN];
+    char localeKeywordNameBuffer[ULOC_KEYWORD_BUFFER_LEN];
+    int32_t i = 0;
+    int32_t result = 0;
+
+    if(status && U_SUCCESS(*status) && localeID) {
+      char tempBuffer[ULOC_FULLNAME_CAPACITY];
+      const char* tmpLocaleID;
+
+      if (_hasBCP47Extension(localeID)) {
+          _ConvertBCP47(tmpLocaleID, localeID, tempBuffer, sizeof(tempBuffer), status);
+      } else {
+          tmpLocaleID=localeID;
+      }
+    
+      startSearchHere = uprv_strchr(tmpLocaleID, '@'); /* TODO: REVISIT: shouldn't this be locale_getKeywordsStart ? */
+      if(startSearchHere == NULL) {
+          /* no keywords, return at once */
+          return 0;
+      }
+
+      locale_canonKeywordName(keywordNameBuffer, keywordName, status);
+      if(U_FAILURE(*status)) {
+        return 0;
+      }
+    
+      /* find the first keyword */
+      while(startSearchHere) {
+          startSearchHere++;
+          /* skip leading spaces (allowed?) */
+          while(*startSearchHere == ' ') {
+              startSearchHere++;
+          }
+          nextSeparator = uprv_strchr(startSearchHere, '=');
+          /* need to normalize both keyword and keyword name */
+          if(!nextSeparator) {
+              break;
+          }
+          if(nextSeparator - startSearchHere >= ULOC_KEYWORD_BUFFER_LEN) {
+              /* keyword name too long for internal buffer */
+              *status = U_INTERNAL_PROGRAM_ERROR;
+              return 0;
+          }
+          for(i = 0; i < nextSeparator - startSearchHere; i++) {
+              localeKeywordNameBuffer[i] = uprv_tolower(startSearchHere[i]);
+          }
+          /* trim trailing spaces */
+          while(startSearchHere[i-1] == ' ') {
+              i--;
+          }
+          localeKeywordNameBuffer[i] = 0;
+        
+          startSearchHere = uprv_strchr(nextSeparator, ';');
+        
+          if(uprv_strcmp(keywordNameBuffer, localeKeywordNameBuffer) == 0) {
+              nextSeparator++;
+              while(*nextSeparator == ' ') {
+                  nextSeparator++;
+              }
+              /* we actually found the keyword. Copy the value */
+              if(startSearchHere && startSearchHere - nextSeparator < bufferCapacity) {
+                  while(*(startSearchHere-1) == ' ') {
+                      startSearchHere--;
+                  }
+                  uprv_strncpy(buffer, nextSeparator, startSearchHere - nextSeparator);
+                  result = u_terminateChars(buffer, bufferCapacity, (int32_t)(startSearchHere - nextSeparator), status);
+              } else if(!startSearchHere && (int32_t)uprv_strlen(nextSeparator) < bufferCapacity) { /* last item in string */
+                  i = (int32_t)uprv_strlen(nextSeparator);
+                  while(nextSeparator[i - 1] == ' ') {
+                      i--;
+                  }
+                  uprv_strncpy(buffer, nextSeparator, i);
+                  result = u_terminateChars(buffer, bufferCapacity, i, status);
+              } else {
+                  /* give a bigger buffer, please */
+                  *status = U_BUFFER_OVERFLOW_ERROR;
+                  if(startSearchHere) {
+                      result = (int32_t)(startSearchHere - nextSeparator);
+                  } else {
+                      result = (int32_t)uprv_strlen(nextSeparator); 
+                  }
+              }
+              return result;
+          }
+      }
+    }
+    return 0;
+}
+
+U_CAPI int32_t U_EXPORT2
+uloc_setKeywordValue(const char* keywordName,
+                     const char* keywordValue,
+                     char* buffer, int32_t bufferCapacity,
+                     UErrorCode* status)
+{
+    /* TODO: sorting. removal. */
+    int32_t keywordNameLen;
+    int32_t keywordValueLen;
+    int32_t bufLen;
+    int32_t needLen = 0;
+    int32_t foundValueLen;
+    int32_t keywordAtEnd = 0; /* is the keyword at the end of the string? */
+    char keywordNameBuffer[ULOC_KEYWORD_BUFFER_LEN];
+    char localeKeywordNameBuffer[ULOC_KEYWORD_BUFFER_LEN];
+    int32_t i = 0;
+    int32_t rc;
+    char* nextSeparator = NULL;
+    char* nextEqualsign = NULL;
+    char* startSearchHere = NULL;
+    char* keywordStart = NULL;
+    char *insertHere = NULL;
+    if(U_FAILURE(*status)) { 
+        return -1; 
+    }
+    if(bufferCapacity>1) {
+        bufLen = (int32_t)uprv_strlen(buffer);
+    } else {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    if(bufferCapacity<bufLen) {
+        /* The capacity is less than the length?! Is this NULL terminated? */
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    if(keywordValue && !*keywordValue) { 
+        keywordValue = NULL;
+    }
+    if(keywordValue) {
+        keywordValueLen = (int32_t)uprv_strlen(keywordValue);
+    } else { 
+        keywordValueLen = 0;
+    }
+    keywordNameLen = locale_canonKeywordName(keywordNameBuffer, keywordName, status);
+    if(U_FAILURE(*status)) {
+        return 0;
+    }
+    startSearchHere = (char*)locale_getKeywordsStart(buffer);
+    if(startSearchHere == NULL || (startSearchHere[1]==0)) {
+        if(!keywordValue) { /* no keywords = nothing to remove */
+            return bufLen; 
+        }
+
+        needLen = bufLen+1+keywordNameLen+1+keywordValueLen;
+        if(startSearchHere) { /* had a single @ */ 
+            needLen--; /* already had the @ */
+            /* startSearchHere points at the @ */
+        } else {
+            startSearchHere=buffer+bufLen;
+        }
+        if(needLen >= bufferCapacity) {
+            *status = U_BUFFER_OVERFLOW_ERROR;
+            return needLen; /* no change */
+        }
+        *startSearchHere = '@';
+        startSearchHere++;
+        uprv_strcpy(startSearchHere, keywordNameBuffer);
+        startSearchHere += keywordNameLen;
+        *startSearchHere = '=';
+        startSearchHere++;
+        uprv_strcpy(startSearchHere, keywordValue);
+        startSearchHere+=keywordValueLen;
+        return needLen;
+    } /* end shortcut - no @ */
+    
+    keywordStart = startSearchHere;
+    /* search for keyword */
+    while(keywordStart) {
+        keywordStart++;
+        /* skip leading spaces (allowed?) */
+        while(*keywordStart == ' ') {
+            keywordStart++;
+        }
+        nextEqualsign = uprv_strchr(keywordStart, '=');
+        /* need to normalize both keyword and keyword name */
+        if(!nextEqualsign) {
+            break;
+        }
+        if(nextEqualsign - keywordStart >= ULOC_KEYWORD_BUFFER_LEN) {
+            /* keyword name too long for internal buffer */
+            *status = U_INTERNAL_PROGRAM_ERROR;
+            return 0;
+        }
+        for(i = 0; i < nextEqualsign - keywordStart; i++) {
+            localeKeywordNameBuffer[i] = uprv_tolower(keywordStart[i]);
+        }
+        /* trim trailing spaces */
+        while(keywordStart[i-1] == ' ') {
+            i--;
+        }
+        localeKeywordNameBuffer[i] = 0;
+
+        nextSeparator = uprv_strchr(nextEqualsign, ';');
+        rc = uprv_strcmp(keywordNameBuffer, localeKeywordNameBuffer);
+        if(rc == 0) {
+            nextEqualsign++;
+            while(*nextEqualsign == ' ') {
+                nextEqualsign++;
+            }
+            /* we actually found the keyword. Change the value */
+            if (nextSeparator) {
+                keywordAtEnd = 0;
+                foundValueLen = (int32_t)(nextSeparator - nextEqualsign);
+            } else {
+                keywordAtEnd = 1;
+                foundValueLen = (int32_t)uprv_strlen(nextEqualsign);
+            }
+            if(keywordValue) { /* adding a value - not removing */
+              if(foundValueLen == keywordValueLen) {
+                uprv_strncpy(nextEqualsign, keywordValue, keywordValueLen);
+                return bufLen; /* no change in size */
+              } else if(foundValueLen > keywordValueLen) {
+                int32_t delta = foundValueLen - keywordValueLen;
+                if(nextSeparator) { /* RH side */
+                  uprv_memmove(nextSeparator - delta, nextSeparator, bufLen-(nextSeparator-buffer));
+                }
+                uprv_strncpy(nextEqualsign, keywordValue, keywordValueLen);
+                bufLen -= delta;
+                buffer[bufLen]=0;
+                return bufLen;
+              } else { /* FVL < KVL */
+                int32_t delta = keywordValueLen - foundValueLen;
+                if((bufLen+delta) >= bufferCapacity) {
+                  *status = U_BUFFER_OVERFLOW_ERROR;
+                  return bufLen+delta;
+                }
+                if(nextSeparator) { /* RH side */
+                  uprv_memmove(nextSeparator+delta,nextSeparator, bufLen-(nextSeparator-buffer));
+                }
+                uprv_strncpy(nextEqualsign, keywordValue, keywordValueLen);
+                bufLen += delta;
+                buffer[bufLen]=0;
+                return bufLen;
+              }
+            } else { /* removing a keyword */
+              if(keywordAtEnd) {
+                /* zero out the ';' or '@' just before startSearchhere */
+                keywordStart[-1] = 0;
+                return (int32_t)((keywordStart-buffer)-1); /* (string length without keyword) minus separator */
+              } else {
+                uprv_memmove(keywordStart, nextSeparator+1, bufLen-((nextSeparator+1)-buffer));
+                keywordStart[bufLen-((nextSeparator+1)-buffer)]=0;
+                return (int32_t)(bufLen-((nextSeparator+1)-keywordStart));
+              }
+            }
+        } else if(rc<0){ /* end match keyword */
+          /* could insert at this location. */
+          insertHere = keywordStart;
+        }
+        keywordStart = nextSeparator;
+    } /* end loop searching */
+    
+    if(!keywordValue) {
+      return bufLen; /* removal of non-extant keyword - no change */
+    }
+
+    /* we know there is at least one keyword. */
+    needLen = bufLen+1+keywordNameLen+1+keywordValueLen;
+    if(needLen >= bufferCapacity) {
+        *status = U_BUFFER_OVERFLOW_ERROR;
+        return needLen; /* no change */
+    }
+    
+    if(insertHere) {
+      uprv_memmove(insertHere+(1+keywordNameLen+1+keywordValueLen), insertHere, bufLen-(insertHere-buffer));
+      keywordStart = insertHere;
+    } else {
+      keywordStart = buffer+bufLen;
+      *keywordStart = ';';
+      keywordStart++;
+    }
+    uprv_strncpy(keywordStart, keywordNameBuffer, keywordNameLen);
+    keywordStart += keywordNameLen;
+    *keywordStart = '=';
+    keywordStart++;
+    uprv_strncpy(keywordStart, keywordValue, keywordValueLen); /* terminates. */
+    keywordStart+=keywordValueLen;
+    if(insertHere) {
+      *keywordStart = ';';
+      keywordStart++;
+    }
+    buffer[needLen]=0;
+    return needLen;
+}
+
+/* ### ID parsing implementation **************************************************/
+
+#define _isPrefixLetter(a) ((a=='x')||(a=='X')||(a=='i')||(a=='I'))
+
+/*returns TRUE if one of the special prefixes is here (s=string)
+  'x-' or 'i-' */
+#define _isIDPrefix(s) (_isPrefixLetter(s[0])&&_isIDSeparator(s[1]))
+
+/* Dot terminates it because of POSIX form  where dot precedes the codepage
+ * except for variant
+ */
+#define _isTerminator(a)  ((a==0)||(a=='.')||(a=='@'))
+
+static char* _strnchr(const char* str, int32_t len, char c) {
+    U_ASSERT(str != 0 && len >= 0);
+    while (len-- != 0) {
+        char d = *str;
+        if (d == c) {
+            return (char*) str;
+        } else if (d == 0) {
+            break;
+        }
+        ++str;
+    }
+    return NULL;
+}
+
+/**
+ * Lookup 'key' in the array 'list'.  The array 'list' should contain
+ * a NULL entry, followed by more entries, and a second NULL entry.
+ *
+ * The 'list' param should be LANGUAGES, LANGUAGES_3, COUNTRIES, or
+ * COUNTRIES_3.
+ */
+static int16_t _findIndex(const char* const* list, const char* key)
+{
+    const char* const* anchor = list;
+    int32_t pass = 0;
+
+    /* Make two passes through two NULL-terminated arrays at 'list' */
+    while (pass++ < 2) {
+        while (*list) {
+            if (uprv_strcmp(key, *list) == 0) {
+                return (int16_t)(list - anchor);
+            }
+            list++;
+        }
+        ++list;     /* skip final NULL *CWB*/
+    }
+    return -1;
+}
+
+/* count the length of src while copying it to dest; return strlen(src) */
+static U_INLINE int32_t
+_copyCount(char *dest, int32_t destCapacity, const char *src) {
+    const char *anchor;
+    char c;
+
+    anchor=src;
+    for(;;) {
+        if((c=*src)==0) {
+            return (int32_t)(src-anchor);
+        }
+        if(destCapacity<=0) {
+            return (int32_t)((src-anchor)+uprv_strlen(src));
+        }
+        ++src;
+        *dest++=c;
+        --destCapacity;
+    }
+}
+
+U_CFUNC const char* 
+uloc_getCurrentCountryID(const char* oldID){
+    int32_t offset = _findIndex(DEPRECATED_COUNTRIES, oldID);
+    if (offset >= 0) {
+        return REPLACEMENT_COUNTRIES[offset];
+    }
+    return oldID;
+}
+U_CFUNC const char* 
+uloc_getCurrentLanguageID(const char* oldID){
+    int32_t offset = _findIndex(DEPRECATED_LANGUAGES, oldID);
+    if (offset >= 0) {
+        return REPLACEMENT_LANGUAGES[offset];
+    }
+    return oldID;        
+}
+/*
+ * the internal functions _getLanguage(), _getCountry(), _getVariant()
+ * avoid duplicating code to handle the earlier locale ID pieces
+ * in the functions for the later ones by
+ * setting the *pEnd pointer to where they stopped parsing
+ *
+ * TODO try to use this in Locale
+ */
+U_CFUNC int32_t
+ulocimp_getLanguage(const char *localeID,
+                    char *language, int32_t languageCapacity,
+                    const char **pEnd) {
+    int32_t i=0;
+    int32_t offset;
+    char lang[4]={ 0, 0, 0, 0 }; /* temporary buffer to hold language code for searching */
+
+    /* if it starts with i- or x- then copy that prefix */
+    if(_isIDPrefix(localeID)) {
+        if(i<languageCapacity) {
+            language[i]=(char)uprv_tolower(*localeID);
+        }
+        if(i<languageCapacity) {
+            language[i+1]='-';
+        }
+        i+=2;
+        localeID+=2;
+    }
+    
+    /* copy the language as far as possible and count its length */
+    while(!_isTerminator(*localeID) && !_isIDSeparator(*localeID)) {
+        if(i<languageCapacity) {
+            language[i]=(char)uprv_tolower(*localeID);
+        }
+        if(i<3) {
+            lang[i]=(char)uprv_tolower(*localeID);
+        }
+        i++;
+        localeID++;
+    }
+
+    if(i==3) {
+        /* convert 3 character code to 2 character code if possible *CWB*/
+        offset=_findIndex(LANGUAGES_3, lang);
+        if(offset>=0) {
+            i=_copyCount(language, languageCapacity, LANGUAGES[offset]);
+        }
+    }
+
+    if(pEnd!=NULL) {
+        *pEnd=localeID;
+    }
+    return i;
+}
+
+U_CFUNC int32_t
+ulocimp_getScript(const char *localeID,
+                  char *script, int32_t scriptCapacity,
+                  const char **pEnd)
+{
+    int32_t idLen = 0;
+
+    if (pEnd != NULL) {
+        *pEnd = localeID;
+    }
+
+    /* copy the second item as far as possible and count its length */
+    while(!_isTerminator(localeID[idLen]) && !_isIDSeparator(localeID[idLen])) {
+        idLen++;
+    }
+
+    /* If it's exactly 4 characters long, then it's a script and not a country. */
+    if (idLen == 4) {
+        int32_t i;
+        if (pEnd != NULL) {
+            *pEnd = localeID+idLen;
+        }
+        if(idLen > scriptCapacity) {
+            idLen = scriptCapacity;
+        }
+        if (idLen >= 1) {
+            script[0]=(char)uprv_toupper(*(localeID++));
+        }
+        for (i = 1; i < idLen; i++) {
+            script[i]=(char)uprv_tolower(*(localeID++));
+        }
+    }
+    else {
+        idLen = 0;
+    }
+    return idLen;
+}
+
+U_CFUNC int32_t
+ulocimp_getCountry(const char *localeID,
+                   char *country, int32_t countryCapacity,
+                   const char **pEnd)
+{
+    int32_t idLen=0;
+    char cnty[ULOC_COUNTRY_CAPACITY]={ 0, 0, 0, 0 };
+    int32_t offset;
+
+    /* copy the country as far as possible and count its length */
+    while(!_isTerminator(localeID[idLen]) && !_isIDSeparator(localeID[idLen])) {
+        if(idLen<(ULOC_COUNTRY_CAPACITY-1)) {   /*CWB*/
+            cnty[idLen]=(char)uprv_toupper(localeID[idLen]);
+        }
+        idLen++;
+    }
+
+    /* the country should be either length 2 or 3 */
+    if (idLen == 2 || idLen == 3) {
+        UBool gotCountry = FALSE;
+        /* convert 3 character code to 2 character code if possible *CWB*/
+        if(idLen==3) {
+            offset=_findIndex(COUNTRIES_3, cnty);
+            if(offset>=0) {
+                idLen=_copyCount(country, countryCapacity, COUNTRIES[offset]);
+                gotCountry = TRUE;
+            }
+        }
+        if (!gotCountry) {
+            int32_t i = 0;
+            for (i = 0; i < idLen; i++) {
+                if (i < countryCapacity) {
+                    country[i]=(char)uprv_toupper(localeID[i]);
+                }
+            }
+        }
+        localeID+=idLen;
+    } else {
+        idLen = 0;
+    }
+
+    if(pEnd!=NULL) {
+        *pEnd=localeID;
+    }
+
+    return idLen;
+}
+
+/**
+ * @param needSeparator if true, then add leading '_' if any variants
+ * are added to 'variant'
+ */
+static int32_t
+_getVariantEx(const char *localeID,
+              char prev,
+              char *variant, int32_t variantCapacity,
+              UBool needSeparator) {
+    int32_t i=0;
+
+    /* get one or more variant tags and separate them with '_' */
+    if(_isIDSeparator(prev)) {
+        /* get a variant string after a '-' or '_' */
+        while(!_isTerminator(*localeID)) {
+            if (needSeparator) {
+                if (i<variantCapacity) {
+                    variant[i] = '_';
+                }
+                ++i;
+                needSeparator = FALSE;
+            }
+            if(i<variantCapacity) {
+                variant[i]=(char)uprv_toupper(*localeID);
+                if(variant[i]=='-') {
+                    variant[i]='_';
+                }
+            }
+            i++;
+            localeID++;
+        }
+    }
+
+    /* if there is no variant tag after a '-' or '_' then look for '@' */
+    if(i==0) {
+        if(prev=='@') {
+            /* keep localeID */
+        } else if((localeID=locale_getKeywordsStart(localeID))!=NULL) {
+            ++localeID; /* point after the '@' */
+        } else {
+            return 0;
+        }
+        while(!_isTerminator(*localeID)) {
+            if (needSeparator) {
+                if (i<variantCapacity) {
+                    variant[i] = '_';
+                }
+                ++i;
+                needSeparator = FALSE;
+            }
+            if(i<variantCapacity) {
+                variant[i]=(char)uprv_toupper(*localeID);
+                if(variant[i]=='-' || variant[i]==',') {
+                    variant[i]='_';
+                }
+            }
+            i++;
+            localeID++;
+        }
+    }
+    
+    return i;
+}
+
+static int32_t
+_getVariant(const char *localeID,
+            char prev,
+            char *variant, int32_t variantCapacity) {
+    return _getVariantEx(localeID, prev, variant, variantCapacity, FALSE);
+}
+
+/**
+ * Delete ALL instances of a variant from the given list of one or
+ * more variants.  Example: "FOO_EURO_BAR_EURO" => "FOO_BAR".
+ * @param variants the source string of one or more variants,
+ * separated by '_'.  This will be MODIFIED IN PLACE.  Not zero
+ * terminated; if it is, trailing zero will NOT be maintained.
+ * @param variantsLen length of variants
+ * @param toDelete variant to delete, without separators, e.g.  "EURO"
+ * or "PREEURO"; not zero terminated
+ * @param toDeleteLen length of toDelete
+ * @return number of characters deleted from variants
+ */
+static int32_t
+_deleteVariant(char* variants, int32_t variantsLen,
+               const char* toDelete, int32_t toDeleteLen)
+{
+    int32_t delta = 0; /* number of chars deleted */
+    for (;;) {
+        UBool flag = FALSE;
+        if (variantsLen < toDeleteLen) {
+            return delta;
+        }
+        if (uprv_strncmp(variants, toDelete, toDeleteLen) == 0 &&
+            (variantsLen == toDeleteLen ||
+             (flag=(variants[toDeleteLen] == '_'))))
+        {
+            int32_t d = toDeleteLen + (flag?1:0);
+            variantsLen -= d;
+            delta += d;
+            if (variantsLen > 0) {
+                uprv_memmove(variants, variants+d, variantsLen);
+            }
+        } else {
+            char* p = _strnchr(variants, variantsLen, '_');
+            if (p == NULL) {
+                return delta;
+            }
+            ++p;
+            variantsLen -= (int32_t)(p - variants);
+            variants = p;
+        }
+    }
+}
+
+/* Keyword enumeration */
+
+typedef struct UKeywordsContext {
+    char* keywords;
+    char* current;
+} UKeywordsContext;
+
+static void U_CALLCONV
+uloc_kw_closeKeywords(UEnumeration *enumerator) {
+    uprv_free(((UKeywordsContext *)enumerator->context)->keywords);
+    uprv_free(enumerator->context);
+    uprv_free(enumerator);
+}
+
+static int32_t U_CALLCONV
+uloc_kw_countKeywords(UEnumeration *en, UErrorCode *status) {
+    char *kw = ((UKeywordsContext *)en->context)->keywords;
+    int32_t result = 0;
+    while(*kw) {
+        result++;
+        kw += uprv_strlen(kw)+1;
+    }
+    return result;
+}
+
+static const char* U_CALLCONV 
+uloc_kw_nextKeyword(UEnumeration* en,
+                    int32_t* resultLength,
+                    UErrorCode* status) {
+    const char* result = ((UKeywordsContext *)en->context)->current;
+    int32_t len = 0;
+    if(*result) {
+        len = (int32_t)uprv_strlen(((UKeywordsContext *)en->context)->current);
+        ((UKeywordsContext *)en->context)->current += len+1;
+    } else {
+        result = NULL;
+    }
+    if (resultLength) {
+        *resultLength = len;
+    }
+    return result;
+}
+
+static void U_CALLCONV 
+uloc_kw_resetKeywords(UEnumeration* en, 
+                      UErrorCode* status) {
+    ((UKeywordsContext *)en->context)->current = ((UKeywordsContext *)en->context)->keywords;
+}
+
+static const UEnumeration gKeywordsEnum = {
+    NULL,
+    NULL,
+    uloc_kw_closeKeywords,
+    uloc_kw_countKeywords,
+    uenum_unextDefault,
+    uloc_kw_nextKeyword,
+    uloc_kw_resetKeywords
+};
+
+U_CAPI UEnumeration* U_EXPORT2
+uloc_openKeywordList(const char *keywordList, int32_t keywordListSize, UErrorCode* status)
+{
+    UKeywordsContext *myContext = NULL;
+    UEnumeration *result = NULL;
+
+    if(U_FAILURE(*status)) {
+        return NULL;
+    }
+    result = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
+    /* Null pointer test */
+    if (result == NULL) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    uprv_memcpy(result, &gKeywordsEnum, sizeof(UEnumeration));
+    myContext = uprv_malloc(sizeof(UKeywordsContext));
+    if (myContext == NULL) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        uprv_free(result);
+        return NULL;
+    }
+    myContext->keywords = (char *)uprv_malloc(keywordListSize+1);
+    uprv_memcpy(myContext->keywords, keywordList, keywordListSize);
+    myContext->keywords[keywordListSize] = 0;
+    myContext->current = myContext->keywords;
+    result->context = myContext;
+    return result;
+}
+
+U_CAPI UEnumeration* U_EXPORT2
+uloc_openKeywords(const char* localeID,
+                        UErrorCode* status) 
+{
+    int32_t i=0;
+    char keywords[256];
+    int32_t keywordsCapacity = 256;
+    char tempBuffer[ULOC_FULLNAME_CAPACITY];
+    const char* tmpLocaleID;
+
+    if(status==NULL || U_FAILURE(*status)) {
+        return 0;
+    }
+    
+    if (_hasBCP47Extension(localeID)) {
+        _ConvertBCP47(tmpLocaleID, localeID, tempBuffer, sizeof(tempBuffer), status);
+    } else {
+        if (localeID==NULL) {
+           localeID=uloc_getDefault();
+        }
+        tmpLocaleID=localeID;
+    }
+
+    /* Skip the language */
+    ulocimp_getLanguage(tmpLocaleID, NULL, 0, &tmpLocaleID);
+    if(_isIDSeparator(*tmpLocaleID)) {
+        const char *scriptID;
+        /* Skip the script if available */
+        ulocimp_getScript(tmpLocaleID+1, NULL, 0, &scriptID);
+        if(scriptID != tmpLocaleID+1) {
+            /* Found optional script */
+            tmpLocaleID = scriptID;
+        }
+        /* Skip the Country */
+        if (_isIDSeparator(*tmpLocaleID)) {
+            ulocimp_getCountry(tmpLocaleID+1, NULL, 0, &tmpLocaleID);
+            if(_isIDSeparator(*tmpLocaleID)) {
+                _getVariant(tmpLocaleID+1, *tmpLocaleID, NULL, 0);
+            }
+        }
+    }
+
+    /* keywords are located after '@' */
+    if((tmpLocaleID = locale_getKeywordsStart(tmpLocaleID)) != NULL) {
+        i=locale_getKeywords(tmpLocaleID+1, '@', keywords, keywordsCapacity, NULL, 0, NULL, FALSE, status);
+    }
+
+    if(i) {
+        return uloc_openKeywordList(keywords, i, status);
+    } else {
+        return NULL;
+    }
+}
+
+
+/* bit-flags for 'options' parameter of _canonicalize */
+#define _ULOC_STRIP_KEYWORDS 0x2
+#define _ULOC_CANONICALIZE   0x1
+
+#define OPTION_SET(options, mask) ((options & mask) != 0)
+
+static const char i_default[] = {'i', '-', 'd', 'e', 'f', 'a', 'u', 'l', 't'};
+#define I_DEFAULT_LENGTH (sizeof i_default / sizeof i_default[0])
+
+/**
+ * Canonicalize the given localeID, to level 1 or to level 2,
+ * depending on the options.  To specify level 1, pass in options=0.
+ * To specify level 2, pass in options=_ULOC_CANONICALIZE.
+ *
+ * This is the code underlying uloc_getName and uloc_canonicalize.
+ */
+static int32_t
+_canonicalize(const char* localeID,
+              char* result,
+              int32_t resultCapacity,
+              uint32_t options,
+              UErrorCode* err) {
+    int32_t j, len, fieldCount=0, scriptSize=0, variantSize=0, nameCapacity;
+    char localeBuffer[ULOC_FULLNAME_CAPACITY];
+    char tempBuffer[ULOC_FULLNAME_CAPACITY];
+    const char* origLocaleID;
+    const char* tmpLocaleID;
+    const char* keywordAssign = NULL;
+    const char* separatorIndicator = NULL;
+    const char* addKeyword = NULL;
+    const char* addValue = NULL;
+    char* name;
+    char* variant = NULL; /* pointer into name, or NULL */
+
+    if (U_FAILURE(*err)) {
+        return 0;
+    }
+    
+    if (_hasBCP47Extension(localeID)) {
+        _ConvertBCP47(tmpLocaleID, localeID, tempBuffer, sizeof(tempBuffer), err);
+    } else {
+        if (localeID==NULL) {
+           localeID=uloc_getDefault();
+        }
+        tmpLocaleID=localeID;
+    }
+
+    origLocaleID=tmpLocaleID;
+
+    /* if we are doing a full canonicalization, then put results in
+       localeBuffer, if necessary; otherwise send them to result. */
+    if (/*OPTION_SET(options, _ULOC_CANONICALIZE) &&*/
+        (result == NULL || resultCapacity <  sizeof(localeBuffer))) {
+        name = localeBuffer;
+        nameCapacity = sizeof(localeBuffer);
+    } else {
+        name = result;
+        nameCapacity = resultCapacity;
+    }
+
+    /* get all pieces, one after another, and separate with '_' */
+    len=ulocimp_getLanguage(tmpLocaleID, name, nameCapacity, &tmpLocaleID);
+
+    if(len == I_DEFAULT_LENGTH && uprv_strncmp(origLocaleID, i_default, len) == 0) {
+        const char *d = uloc_getDefault();
+        
+        len = (int32_t)uprv_strlen(d);
+
+        if (name != NULL) {
+            uprv_strncpy(name, d, len);
+        }
+    } else if(_isIDSeparator(*tmpLocaleID)) {
+        const char *scriptID;
+
+        ++fieldCount;
+        if(len<nameCapacity) {
+            name[len]='_';
+        }
+        ++len;
+
+        scriptSize=ulocimp_getScript(tmpLocaleID+1, name+len, nameCapacity-len, &scriptID);
+        if(scriptSize > 0) {
+            /* Found optional script */
+            tmpLocaleID = scriptID;
+            ++fieldCount;
+            len+=scriptSize;
+            if (_isIDSeparator(*tmpLocaleID)) {
+                /* If there is something else, then we add the _ */
+                if(len<nameCapacity) {
+                    name[len]='_';
+                }
+                ++len;
+            }
+        }
+
+        if (_isIDSeparator(*tmpLocaleID)) {
+            const char *cntryID;
+            int32_t cntrySize = ulocimp_getCountry(tmpLocaleID+1, name+len, nameCapacity-len, &cntryID);
+            if (cntrySize > 0) {
+                /* Found optional country */
+                tmpLocaleID = cntryID;
+                len+=cntrySize;
+            }
+            if(_isIDSeparator(*tmpLocaleID)) {
+                /* If there is something else, then we add the _  if we found country before.*/
+                if (cntrySize > 0) {
+                    ++fieldCount;
+                    if(len<nameCapacity) {
+                        name[len]='_';
+                    }
+                    ++len;
+                }
+
+                variantSize = _getVariant(tmpLocaleID+1, *tmpLocaleID, name+len, nameCapacity-len);
+                if (variantSize > 0) {
+                    variant = name+len;
+                    len += variantSize;
+                    tmpLocaleID += variantSize + 1; /* skip '_' and variant */
+                }
+            }
+        }
+    }
+
+    /* Copy POSIX-style charset specifier, if any [mr.utf8] */
+    if (!OPTION_SET(options, _ULOC_CANONICALIZE) && *tmpLocaleID == '.') {
+        UBool done = FALSE;
+        do {
+            char c = *tmpLocaleID;
+            switch (c) {
+            case 0:
+            case '@':
+                done = TRUE;
+                break;
+            default:
+                if (len<nameCapacity) {
+                    name[len] = c;
+                }
+                ++len;
+                ++tmpLocaleID;
+                break;
+            }
+        } while (!done);
+    }
+
+    /* Scan ahead to next '@' and determine if it is followed by '=' and/or ';'
+       After this, tmpLocaleID either points to '@' or is NULL */
+    if ((tmpLocaleID=locale_getKeywordsStart(tmpLocaleID))!=NULL) {
+        keywordAssign = uprv_strchr(tmpLocaleID, '=');
+        separatorIndicator = uprv_strchr(tmpLocaleID, ';');
+    }
+
+    /* Copy POSIX-style variant, if any [mr@FOO] */
+    if (!OPTION_SET(options, _ULOC_CANONICALIZE) &&
+        tmpLocaleID != NULL && keywordAssign == NULL) {
+        for (;;) {
+            char c = *tmpLocaleID;
+            if (c == 0) {
+                break;
+            }
+            if (len<nameCapacity) {
+                name[len] = c;
+            }
+            ++len;
+            ++tmpLocaleID;
+        }
+    }
+
+    if (OPTION_SET(options, _ULOC_CANONICALIZE)) {
+        /* Handle @FOO variant if @ is present and not followed by = */
+        if (tmpLocaleID!=NULL && keywordAssign==NULL) {
+            int32_t posixVariantSize;
+            /* Add missing '_' if needed */
+            if (fieldCount < 2 || (fieldCount < 3 && scriptSize > 0)) {
+                do {
+                    if(len<nameCapacity) {
+                        name[len]='_';
+                    }
+                    ++len;
+                    ++fieldCount;
+                } while(fieldCount<2);
+            }
+            posixVariantSize = _getVariantEx(tmpLocaleID+1, '@', name+len, nameCapacity-len,
+                                             (UBool)(variantSize > 0));
+            if (posixVariantSize > 0) {
+                if (variant == NULL) {
+                    variant = name+len;
+                }
+                len += posixVariantSize;
+                variantSize += posixVariantSize;
+            }
+        }
+
+        /* Handle generic variants first */
+        if (variant) {
+            for (j=0; j<(int32_t)(sizeof(VARIANT_MAP)/sizeof(VARIANT_MAP[0])); j++) {
+                const char* variantToCompare = VARIANT_MAP[j].variant;
+                int32_t n = (int32_t)uprv_strlen(variantToCompare);
+                int32_t variantLen = _deleteVariant(variant, uprv_min(variantSize, (nameCapacity-len)), variantToCompare, n);
+                len -= variantLen;
+                if (variantLen > 0) {
+                    if (name[len-1] == '_') { /* delete trailing '_' */
+                        --len;
+                    }
+                    addKeyword = VARIANT_MAP[j].keyword;
+                    addValue = VARIANT_MAP[j].value;
+                    break;
+                }
+            }
+            if (name[len-1] == '_') { /* delete trailing '_' */
+                --len;
+            }
+        }
+
+        /* Look up the ID in the canonicalization map */
+        for (j=0; j<(int32_t)(sizeof(CANONICALIZE_MAP)/sizeof(CANONICALIZE_MAP[0])); j++) {
+            const char* id = CANONICALIZE_MAP[j].id;
+            int32_t n = (int32_t)uprv_strlen(id);
+            if (len == n && uprv_strncmp(name, id, n) == 0) {
+                if (n == 0 && tmpLocaleID != NULL) {
+                    break; /* Don't remap "" if keywords present */
+                }
+                len = _copyCount(name, nameCapacity, CANONICALIZE_MAP[j].canonicalID);
+                if (CANONICALIZE_MAP[j].keyword) {
+                    addKeyword = CANONICALIZE_MAP[j].keyword;
+                    addValue = CANONICALIZE_MAP[j].value;
+                }
+                break;
+            }
+        }
+    }
+
+    if (!OPTION_SET(options, _ULOC_STRIP_KEYWORDS)) {
+        if (tmpLocaleID!=NULL && keywordAssign!=NULL &&
+            (!separatorIndicator || separatorIndicator > keywordAssign)) {
+            if(len<nameCapacity) {
+                name[len]='@';
+            }
+            ++len;
+            ++fieldCount;
+            len += _getKeywords(tmpLocaleID+1, '@', name+len, nameCapacity-len, NULL, 0, NULL, TRUE,
+                                addKeyword, addValue, err);
+        } else if (addKeyword != NULL) {
+            U_ASSERT(addValue != NULL);
+            /* inelegant but works -- later make _getKeywords do this? */
+            len += _copyCount(name+len, nameCapacity-len, "@");
+            len += _copyCount(name+len, nameCapacity-len, addKeyword);
+            len += _copyCount(name+len, nameCapacity-len, "=");
+            len += _copyCount(name+len, nameCapacity-len, addValue);
+        }
+    }
+
+    if (U_SUCCESS(*err) && result != NULL && name == localeBuffer) {
+        uprv_strncpy(result, localeBuffer, (len > resultCapacity) ? resultCapacity : len);
+    }
+
+    return u_terminateChars(result, resultCapacity, len, err);
+}
+
+/* ### ID parsing API **************************************************/
+
+U_CAPI int32_t  U_EXPORT2
+uloc_getParent(const char*    localeID,
+               char* parent,
+               int32_t parentCapacity,
+               UErrorCode* err)
+{
+    const char *lastUnderscore;
+    int32_t i;
+    
+    if (U_FAILURE(*err))
+        return 0;
+    
+    if (localeID == NULL)
+        localeID = uloc_getDefault();
+
+    lastUnderscore=uprv_strrchr(localeID, '_');
+    if(lastUnderscore!=NULL) {
+        i=(int32_t)(lastUnderscore-localeID);
+    } else {
+        i=0;
+    }
+
+    if(i>0 && parent != localeID) {
+        uprv_memcpy(parent, localeID, uprv_min(i, parentCapacity));
+    }
+    return u_terminateChars(parent, parentCapacity, i, err);
+}
+
+U_CAPI int32_t U_EXPORT2
+uloc_getLanguage(const char*    localeID,
+         char* language,
+         int32_t languageCapacity,
+         UErrorCode* err)
+{
+    /* uloc_getLanguage will return a 2 character iso-639 code if one exists. *CWB*/
+    int32_t i=0;
+
+    if (err==NULL || U_FAILURE(*err)) {
+        return 0;
+    }
+    
+    if(localeID==NULL) {
+        localeID=uloc_getDefault();
+    }
+
+    i=ulocimp_getLanguage(localeID, language, languageCapacity, NULL);
+    return u_terminateChars(language, languageCapacity, i, err);
+}
+
+U_CAPI int32_t U_EXPORT2
+uloc_getScript(const char*    localeID,
+         char* script,
+         int32_t scriptCapacity,
+         UErrorCode* err)
+{
+    int32_t i=0;
+
+    if(err==NULL || U_FAILURE(*err)) {
+        return 0;
+    }
+
+    if(localeID==NULL) {
+        localeID=uloc_getDefault();
+    }
+
+    /* skip the language */
+    ulocimp_getLanguage(localeID, NULL, 0, &localeID);
+    if(_isIDSeparator(*localeID)) {
+        i=ulocimp_getScript(localeID+1, script, scriptCapacity, NULL);
+    }
+    return u_terminateChars(script, scriptCapacity, i, err);
+}
+
+U_CAPI int32_t  U_EXPORT2
+uloc_getCountry(const char* localeID,
+            char* country,
+            int32_t countryCapacity,
+            UErrorCode* err) 
+{
+    int32_t i=0;
+
+    if(err==NULL || U_FAILURE(*err)) {
+        return 0;
+    }
+
+    if(localeID==NULL) {
+        localeID=uloc_getDefault();
+    }
+
+    /* Skip the language */
+    ulocimp_getLanguage(localeID, NULL, 0, &localeID);
+    if(_isIDSeparator(*localeID)) {
+        const char *scriptID;
+        /* Skip the script if available */
+        ulocimp_getScript(localeID+1, NULL, 0, &scriptID);
+        if(scriptID != localeID+1) {
+            /* Found optional script */
+            localeID = scriptID;
+        }
+        if(_isIDSeparator(*localeID)) {
+            i=ulocimp_getCountry(localeID+1, country, countryCapacity, NULL);
+        }
+    }
+    return u_terminateChars(country, countryCapacity, i, err);
+}
+
+U_CAPI int32_t  U_EXPORT2
+uloc_getVariant(const char* localeID,
+                char* variant,
+                int32_t variantCapacity,
+                UErrorCode* err) 
+{
+    char tempBuffer[ULOC_FULLNAME_CAPACITY];
+    const char* tmpLocaleID;
+    int32_t i=0;
+    
+    if(err==NULL || U_FAILURE(*err)) {
+        return 0;
+    }
+    
+    if (_hasBCP47Extension(localeID)) {
+        _ConvertBCP47(tmpLocaleID, localeID, tempBuffer, sizeof(tempBuffer), err);
+    } else {
+        if (localeID==NULL) {
+           localeID=uloc_getDefault();
+        }
+        tmpLocaleID=localeID;
+    }
+    
+    /* Skip the language */
+    ulocimp_getLanguage(tmpLocaleID, NULL, 0, &tmpLocaleID);
+    if(_isIDSeparator(*tmpLocaleID)) {
+        const char *scriptID;
+        /* Skip the script if available */
+        ulocimp_getScript(tmpLocaleID+1, NULL, 0, &scriptID);
+        if(scriptID != tmpLocaleID+1) {
+            /* Found optional script */
+            tmpLocaleID = scriptID;
+        }
+        /* Skip the Country */
+        if (_isIDSeparator(*tmpLocaleID)) {
+            const char *cntryID;
+            ulocimp_getCountry(tmpLocaleID+1, NULL, 0, &cntryID);
+            if (cntryID != tmpLocaleID+1) {
+                /* Found optional country */
+                tmpLocaleID = cntryID;
+            }
+            if(_isIDSeparator(*tmpLocaleID)) {
+                /* If there was no country ID, skip a possible extra IDSeparator */
+                if (tmpLocaleID != cntryID && _isIDSeparator(tmpLocaleID[1])) {
+                    tmpLocaleID++;
+                }
+                i=_getVariant(tmpLocaleID+1, *tmpLocaleID, variant, variantCapacity);
+            }
+        }
+    }
+    
+    /* removed by weiv. We don't want to handle POSIX variants anymore. Use canonicalization function */
+    /* if we do not have a variant tag yet then try a POSIX variant after '@' */
+/*
+    if(!haveVariant && (localeID=uprv_strrchr(localeID, '@'))!=NULL) {
+        i=_getVariant(localeID+1, '@', variant, variantCapacity);
+    }
+*/
+    return u_terminateChars(variant, variantCapacity, i, err);
+}
+
+U_CAPI int32_t  U_EXPORT2
+uloc_getName(const char* localeID,
+             char* name,
+             int32_t nameCapacity,
+             UErrorCode* err)  
+{
+    return _canonicalize(localeID, name, nameCapacity, 0, err);
+}
+
+U_CAPI int32_t  U_EXPORT2
+uloc_getBaseName(const char* localeID,
+                 char* name,
+                 int32_t nameCapacity,
+                 UErrorCode* err)  
+{
+    return _canonicalize(localeID, name, nameCapacity, _ULOC_STRIP_KEYWORDS, err);
+}
+
+U_CAPI int32_t  U_EXPORT2
+uloc_canonicalize(const char* localeID,
+                  char* name,
+                  int32_t nameCapacity,
+                  UErrorCode* err)  
+{
+    return _canonicalize(localeID, name, nameCapacity, _ULOC_CANONICALIZE, err);
+}
+  
+U_CAPI const char*  U_EXPORT2
+uloc_getISO3Language(const char* localeID) 
+{
+    int16_t offset;
+    char lang[ULOC_LANG_CAPACITY];
+    UErrorCode err = U_ZERO_ERROR;
+    
+    if (localeID == NULL)
+    {
+        localeID = uloc_getDefault();
+    }
+    uloc_getLanguage(localeID, lang, ULOC_LANG_CAPACITY, &err);
+    if (U_FAILURE(err))
+        return "";
+    offset = _findIndex(LANGUAGES, lang);
+    if (offset < 0)
+        return "";
+    return LANGUAGES_3[offset];
+}
+
+U_CAPI const char*  U_EXPORT2
+uloc_getISO3Country(const char* localeID) 
+{
+    int16_t offset;
+    char cntry[ULOC_LANG_CAPACITY];
+    UErrorCode err = U_ZERO_ERROR;
+    
+    if (localeID == NULL)
+    {
+        localeID = uloc_getDefault();
+    }
+    uloc_getCountry(localeID, cntry, ULOC_LANG_CAPACITY, &err);
+    if (U_FAILURE(err))
+        return "";
+    offset = _findIndex(COUNTRIES, cntry);
+    if (offset < 0)
+        return "";
+    
+    return COUNTRIES_3[offset];
+}
+
+U_CAPI uint32_t  U_EXPORT2
+uloc_getLCID(const char* localeID) 
+{
+    UErrorCode status = U_ZERO_ERROR;
+    char       langID[ULOC_FULLNAME_CAPACITY];
+
+    uloc_getLanguage(localeID, langID, sizeof(langID), &status);
+    if (U_FAILURE(status)) {
+        return 0;
+    }
+
+    return uprv_convertToLCID(langID, localeID, &status);
+}
+
+U_CAPI int32_t U_EXPORT2
+uloc_getLocaleForLCID(uint32_t hostid, char *locale, int32_t localeCapacity,
+                UErrorCode *status)
+{
+    int32_t length;
+    const char *posix = uprv_convertToPosix(hostid, status);
+    if (U_FAILURE(*status) || posix == NULL) {
+        return 0;
+    }
+    length = (int32_t)uprv_strlen(posix);
+    if (length+1 > localeCapacity) {
+        *status = U_BUFFER_OVERFLOW_ERROR;
+    }
+    else {
+        uprv_strcpy(locale, posix);
+    }
+    return length;
+}
+
+/* ### Default locale **************************************************/
+
+U_CAPI const char*  U_EXPORT2
+uloc_getDefault()
+{
+    return locale_get_default();
+}
+
+U_CAPI void  U_EXPORT2
+uloc_setDefault(const char*   newDefaultLocale,
+             UErrorCode* err) 
+{
+    if (U_FAILURE(*err))
+        return;
+    /* the error code isn't currently used for anything by this function*/
+    
+    /* propagate change to C++ */
+    locale_set_default(newDefaultLocale);
+}
+
+/**
+ * Returns a list of all language codes defined in ISO 639.  This is a pointer
+ * to an array of pointers to arrays of char.  All of these pointers are owned
+ * by ICU-- do not delete them, and do not write through them.  The array is
+ * terminated with a null pointer.
+ */
+U_CAPI const char* const*  U_EXPORT2
+uloc_getISOLanguages() 
+{
+    return LANGUAGES;
+}
+
+/**
+ * Returns a list of all 2-letter country codes defined in ISO 639.  This is a
+ * pointer to an array of pointers to arrays of char.  All of these pointers are
+ * owned by ICU-- do not delete them, and do not write through them.  The array is
+ * terminated with a null pointer.
+ */
+U_CAPI const char* const*  U_EXPORT2
+uloc_getISOCountries() 
+{
+    return COUNTRIES;
+}
+
+
+/* this function to be moved into cstring.c later */
+static char gDecimal = 0;
+
+static /* U_CAPI */
+double
+/* U_EXPORT2 */
+_uloc_strtod(const char *start, char **end) {
+    char *decimal;
+    char *myEnd;
+    char buf[30];
+    double rv;
+    if (!gDecimal) {
+        char rep[5];
+        /* 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(gDecimal == '.') {
+        return uprv_strtod(start, end); /* fall through to OS */
+    } else {
+        uprv_strncpy(buf, start, 29);
+        buf[29]=0;
+        decimal = uprv_strchr(buf, '.');
+        if(decimal) {
+            *decimal = gDecimal;
+        } else {
+            return uprv_strtod(start, end); /* no decimal point */
+        }
+        rv = uprv_strtod(buf, &myEnd);
+        if(end) {
+            *end = (char*)(start+(myEnd-buf)); /* cast away const (to follow uprv_strtod API.) */
+        }
+        return rv;
+    }
+}
+
+typedef struct { 
+    float q;
+    int32_t dummy;  /* to avoid uninitialized memory copy from qsort */
+    char *locale;
+} _acceptLangItem;
+
+static int32_t U_CALLCONV
+uloc_acceptLanguageCompare(const void *context, const void *a, const void *b)
+{
+    const _acceptLangItem *aa = (const _acceptLangItem*)a;
+    const _acceptLangItem *bb = (const _acceptLangItem*)b;
+
+    int32_t rc = 0;
+    if(bb->q < aa->q) {
+        rc = -1;  /* A > B */
+    } else if(bb->q > aa->q) {
+        rc = 1;   /* A < B */
+    } else {
+        rc = 0;   /* A = B */
+    }
+
+    if(rc==0) {
+        rc = uprv_stricmp(aa->locale, bb->locale);
+    }
+
+#if defined(ULOC_DEBUG)
+    /*  fprintf(stderr, "a:[%s:%g], b:[%s:%g] -> %d\n", 
+    aa->locale, aa->q, 
+    bb->locale, bb->q,
+    rc);*/
+#endif
+
+    return rc;
+}
+
+/* 
+mt-mt, ja;q=0.76, en-us;q=0.95, en;q=0.92, en-gb;q=0.89, fr;q=0.87, iu-ca;q=0.84, iu;q=0.82, ja-jp;q=0.79, mt;q=0.97, de-de;q=0.74, de;q=0.71, es;q=0.68, it-it;q=0.66, it;q=0.63, vi-vn;q=0.61, vi;q=0.58, nl-nl;q=0.55, nl;q=0.53
+*/
+
+U_CAPI int32_t U_EXPORT2
+uloc_acceptLanguageFromHTTP(char *result, int32_t resultAvailable, UAcceptResult *outResult,
+                            const char *httpAcceptLanguage,
+                            UEnumeration* availableLocales,
+                            UErrorCode *status)
+{
+    _acceptLangItem *j;
+    _acceptLangItem smallBuffer[30];
+    char **strs;
+    char tmp[ULOC_FULLNAME_CAPACITY +1];
+    int32_t n = 0;
+    const char *itemEnd;
+    const char *paramEnd;
+    const char *s;
+    const char *t;
+    int32_t res;
+    int32_t i;
+    int32_t l = (int32_t)uprv_strlen(httpAcceptLanguage);
+    int32_t jSize;
+    char *tempstr; /* Use for null pointer check */
+
+    j = smallBuffer;
+    jSize = sizeof(smallBuffer)/sizeof(smallBuffer[0]);
+    if(U_FAILURE(*status)) {
+        return -1;
+    }
+
+    for(s=httpAcceptLanguage;s&&*s;) {
+        while(isspace(*s)) /* eat space at the beginning */
+            s++;
+        itemEnd=uprv_strchr(s,',');
+        paramEnd=uprv_strchr(s,';');
+        if(!itemEnd) {
+            itemEnd = httpAcceptLanguage+l; /* end of string */
+        }
+        if(paramEnd && paramEnd<itemEnd) { 
+            /* semicolon (;) is closer than end (,) */
+            t = paramEnd+1;
+            if(*t=='q') {
+                t++;
+            }
+            while(isspace(*t)) {
+                t++;
+            }
+            if(*t=='=') {
+                t++;
+            }
+            while(isspace(*t)) {
+                t++;
+            }
+            j[n].q = (float)_uloc_strtod(t,NULL);
+        } else {
+            /* no semicolon - it's 1.0 */
+            j[n].q = 1.0f;
+            paramEnd = itemEnd;
+        }
+        j[n].dummy=0;
+        /* eat spaces prior to semi */
+        for(t=(paramEnd-1);(paramEnd>s)&&isspace(*t);t--)
+            ;
+        /* Check for null pointer from uprv_strndup */
+        tempstr = uprv_strndup(s,(int32_t)((t+1)-s));
+        if (tempstr == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return -1;
+        }
+        j[n].locale = tempstr;
+        uloc_canonicalize(j[n].locale,tmp,sizeof(tmp)/sizeof(tmp[0]),status);
+        if(strcmp(j[n].locale,tmp)) {
+            uprv_free(j[n].locale);
+            j[n].locale=uprv_strdup(tmp);
+        }
+#if defined(ULOC_DEBUG)
+        /*fprintf(stderr,"%d: s <%s> q <%g>\n", n, j[n].locale, j[n].q);*/
+#endif
+        n++;
+        s = itemEnd;
+        while(*s==',') { /* eat duplicate commas */
+            s++;
+        }
+        if(n>=jSize) {
+            if(j==smallBuffer) {  /* overflowed the small buffer. */
+                j = uprv_malloc(sizeof(j[0])*(jSize*2));
+                if(j!=NULL) {
+                    uprv_memcpy(j,smallBuffer,sizeof(j[0])*jSize);
+                }
+#if defined(ULOC_DEBUG)
+                fprintf(stderr,"malloced at size %d\n", jSize);
+#endif
+            } else {
+                j = uprv_realloc(j, sizeof(j[0])*jSize*2);
+#if defined(ULOC_DEBUG)
+                fprintf(stderr,"re-alloced at size %d\n", jSize);
+#endif
+            }
+            jSize *= 2;
+            if(j==NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                return -1;
+            }
+        }
+    }
+    uprv_sortArray(j, n, sizeof(j[0]), uloc_acceptLanguageCompare, NULL, TRUE, status);
+    if(U_FAILURE(*status)) {
+        if(j != smallBuffer) {
+#if defined(ULOC_DEBUG)
+            fprintf(stderr,"freeing j %p\n", j);
+#endif
+            uprv_free(j);
+        }
+        return -1;
+    }
+    strs = uprv_malloc((size_t)(sizeof(strs[0])*n));
+    /* Check for null pointer */
+    if (strs == NULL) {
+        uprv_free(j); /* Free to avoid memory leak */
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return -1;
+    }
+    for(i=0;i<n;i++) {
+#if defined(ULOC_DEBUG)
+        /*fprintf(stderr,"%d: s <%s> q <%g>\n", i, j[i].locale, j[i].q);*/
+#endif
+        strs[i]=j[i].locale;
+    }
+    res =  uloc_acceptLanguage(result, resultAvailable, outResult, 
+        (const char**)strs, n, availableLocales, status);
+    for(i=0;i<n;i++) {
+        uprv_free(strs[i]);
+    }
+    uprv_free(strs);
+    if(j != smallBuffer) {
+#if defined(ULOC_DEBUG)
+        fprintf(stderr,"freeing j %p\n", j);
+#endif
+        uprv_free(j);
+    }
+    return res;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uloc_acceptLanguage(char *result, int32_t resultAvailable, 
+                    UAcceptResult *outResult, const char **acceptList,
+                    int32_t acceptListCount,
+                    UEnumeration* availableLocales,
+                    UErrorCode *status)
+{
+    int32_t i,j;
+    int32_t len;
+    int32_t maxLen=0;
+    char tmp[ULOC_FULLNAME_CAPACITY+1];
+    const char *l;
+    char **fallbackList;
+    if(U_FAILURE(*status)) {
+        return -1;
+    }
+    fallbackList = uprv_malloc((size_t)(sizeof(fallbackList[0])*acceptListCount));
+    if(fallbackList==NULL) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return -1;
+    }
+    for(i=0;i<acceptListCount;i++) {
+#if defined(ULOC_DEBUG)
+        fprintf(stderr,"%02d: %s\n", i, acceptList[i]);
+#endif
+        while((l=uenum_next(availableLocales, NULL, status))) {
+#if defined(ULOC_DEBUG)
+            fprintf(stderr,"  %s\n", l);
+#endif
+            len = (int32_t)uprv_strlen(l);
+            if(!uprv_strcmp(acceptList[i], l)) {
+                if(outResult) { 
+                    *outResult = ULOC_ACCEPT_VALID;
+                }
+#if defined(ULOC_DEBUG)
+                fprintf(stderr, "MATCH! %s\n", l);
+#endif
+                if(len>0) {
+                    uprv_strncpy(result, l, uprv_min(len, resultAvailable));
+                }
+                for(j=0;j<i;j++) {
+                    uprv_free(fallbackList[j]);
+                }
+                uprv_free(fallbackList);
+                return u_terminateChars(result, resultAvailable, len, status);   
+            }
+            if(len>maxLen) {
+                maxLen = len;
+            }
+        }
+        uenum_reset(availableLocales, status);    
+        /* save off parent info */
+        if(uloc_getParent(acceptList[i], tmp, sizeof(tmp)/sizeof(tmp[0]), status)!=0) {
+            fallbackList[i] = uprv_strdup(tmp);
+        } else {
+            fallbackList[i]=0;
+        }
+    }
+
+    for(maxLen--;maxLen>0;maxLen--) {
+        for(i=0;i<acceptListCount;i++) {
+            if(fallbackList[i] && ((int32_t)uprv_strlen(fallbackList[i])==maxLen)) {
+#if defined(ULOC_DEBUG)
+                fprintf(stderr,"Try: [%s]", fallbackList[i]);
+#endif
+                while((l=uenum_next(availableLocales, NULL, status))) {
+#if defined(ULOC_DEBUG)
+                    fprintf(stderr,"  %s\n", l);
+#endif
+                    len = (int32_t)uprv_strlen(l);
+                    if(!uprv_strcmp(fallbackList[i], l)) {
+                        if(outResult) { 
+                            *outResult = ULOC_ACCEPT_FALLBACK;
+                        }
+#if defined(ULOC_DEBUG)
+                        fprintf(stderr, "fallback MATCH! %s\n", l);
+#endif
+                        if(len>0) {
+                            uprv_strncpy(result, l, uprv_min(len, resultAvailable));
+                        }
+                        for(j=0;j<acceptListCount;j++) {
+                            uprv_free(fallbackList[j]);
+                        }
+                        uprv_free(fallbackList);
+                        return u_terminateChars(result, resultAvailable, len, status);
+                    }
+                }
+                uenum_reset(availableLocales, status);    
+
+                if(uloc_getParent(fallbackList[i], tmp, sizeof(tmp)/sizeof(tmp[0]), status)!=0) {
+                    uprv_free(fallbackList[i]);
+                    fallbackList[i] = uprv_strdup(tmp);
+                } else {
+                    uprv_free(fallbackList[i]);
+                    fallbackList[i]=0;
+                }
+            }
+        }
+        if(outResult) { 
+            *outResult = ULOC_ACCEPT_FAILED;
+        }
+    }
+    for(i=0;i<acceptListCount;i++) {
+        uprv_free(fallbackList[i]);
+    }
+    uprv_free(fallbackList);
+    return -1;
+}
+
+/*eof*/
diff --git a/source/common/uloc_tag.c b/source/common/uloc_tag.c
new file mode 100644
index 0000000..26a9d99
--- /dev/null
+++ b/source/common/uloc_tag.c
@@ -0,0 +1,2386 @@
+/*
+**********************************************************************
+*   Copyright (C) 2009-2011, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/ures.h"
+#include "unicode/putil.h"
+#include "unicode/uloc.h"
+#include "ustr_imp.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "putilimp.h"
+#include "uinvchar.h"
+#include "ulocimp.h"
+
+/* struct holding a single variant */
+typedef struct VariantListEntry {
+    const char              *variant;
+    struct VariantListEntry *next;
+} VariantListEntry;
+
+/* struct holding a single extension */
+typedef struct ExtensionListEntry {
+    const char                  *key;
+    const char                  *value;
+    struct ExtensionListEntry   *next;
+} ExtensionListEntry;
+
+#define MAXEXTLANG 3
+typedef struct ULanguageTag {
+    char                *buf;   /* holding parsed subtags */
+    const char          *language;
+    const char          *extlang[MAXEXTLANG];
+    const char          *script;
+    const char          *region;
+    VariantListEntry    *variants;
+    ExtensionListEntry  *extensions;
+    const char          *privateuse;
+    const char          *grandfathered;
+} ULanguageTag;
+
+#define MINLEN 2
+#define SEP '-'
+#define PRIVATEUSE 'x'
+#define LDMLEXT 'u'
+
+#define LOCALE_SEP '_'
+#define LOCALE_EXT_SEP '@'
+#define LOCALE_KEYWORD_SEP ';'
+#define LOCALE_KEY_TYPE_SEP '='
+
+#define ISALPHA(c) (((c)>='A' && (c)<='Z') || ((c)>='a' && (c)<='z'))
+#define ISNUMERIC(c) ((c)>='0' && (c)<='9')
+
+static const char* EMPTY = "";
+static const char* LANG_UND = "und";
+static const char* PRIVATEUSE_KEY = "x";
+static const char* _POSIX = "_POSIX";
+static const char* POSIX_KEY = "va";
+static const char* POSIX_VALUE = "posix";
+
+#define LANG_UND_LEN 3
+
+static const char* GRANDFATHERED[] = {
+/*  grandfathered   preferred */
+    "art-lojban",   "jbo",
+    "cel-gaulish",  "",
+    "en-GB-oed",    "",
+    "i-ami",        "ami",
+    "i-bnn",        "bnn",
+    "i-default",    "",
+    "i-enochian",   "",
+    "i-hak",        "hak",
+    "i-klingon",    "tlh",
+    "i-lux",        "lb",
+    "i-mingo",      "",
+    "i-navajo",     "nv",
+    "i-pwn",        "pwn",
+    "i-tao",        "tao",
+    "i-tay",        "tay",
+    "i-tsu",        "tsu",
+    "no-bok",       "nb",
+    "no-nyn",       "nn",
+    "sgn-be-fr",    "sfb",
+    "sgn-be-nl",    "vgt",
+    "sgn-ch-de",    "sgg",
+    "zh-guoyu",     "cmn",
+    "zh-hakka",     "hak",
+    "zh-min",       "",
+    "zh-min-nan",   "nan",
+    "zh-xiang",     "hsn",
+    NULL,           NULL
+};
+
+static const char* DEPRECATEDLANGS[] = {
+/*  deprecated  new */
+    "iw",       "he",
+    "ji",       "yi",
+    "in",       "id",
+    NULL,       NULL
+};
+
+/*
+* -------------------------------------------------
+*
+* These ultag_ functions may be exposed as APIs later
+*
+* -------------------------------------------------
+*/
+
+static ULanguageTag*
+ultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode* status);
+
+static void
+ultag_close(ULanguageTag* langtag);
+
+static const char*
+ultag_getLanguage(const ULanguageTag* langtag);
+
+#if 0
+static const char*
+ultag_getJDKLanguage(const ULanguageTag* langtag);
+#endif
+
+static const char*
+ultag_getExtlang(const ULanguageTag* langtag, int32_t idx);
+
+static int32_t
+ultag_getExtlangSize(const ULanguageTag* langtag);
+
+static const char*
+ultag_getScript(const ULanguageTag* langtag);
+
+static const char*
+ultag_getRegion(const ULanguageTag* langtag);
+
+static const char*
+ultag_getVariant(const ULanguageTag* langtag, int32_t idx);
+
+static int32_t
+ultag_getVariantsSize(const ULanguageTag* langtag);
+
+static const char*
+ultag_getExtensionKey(const ULanguageTag* langtag, int32_t idx);
+
+static const char*
+ultag_getExtensionValue(const ULanguageTag* langtag, int32_t idx);
+
+static int32_t
+ultag_getExtensionsSize(const ULanguageTag* langtag);
+
+static const char*
+ultag_getPrivateUse(const ULanguageTag* langtag);
+
+#if 0
+static const char*
+ultag_getGrandfathered(const ULanguageTag* langtag);
+#endif
+
+/*
+* -------------------------------------------------
+*
+* Language subtag syntax validation functions
+*
+* -------------------------------------------------
+*/
+
+static UBool
+_isAlphaString(const char* s, int32_t len) {
+    int32_t i;
+    for (i = 0; i < len; i++) {
+        if (!ISALPHA(*(s + i))) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+static UBool
+_isNumericString(const char* s, int32_t len) {
+    int32_t i;
+    for (i = 0; i < len; i++) {
+        if (!ISNUMERIC(*(s + i))) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+static UBool
+_isAlphaNumericString(const char* s, int32_t len) {
+    int32_t i;
+    for (i = 0; i < len; i++) {
+        if (!ISALPHA(*(s + i)) && !ISNUMERIC(*(s + i))) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+static UBool
+_isLanguageSubtag(const char* s, int32_t len) {
+    /*
+     * language      = 2*3ALPHA            ; shortest ISO 639 code
+     *                 ["-" extlang]       ; sometimes followed by
+     *                                     ;   extended language subtags
+     *               / 4ALPHA              ; or reserved for future use
+     *               / 5*8ALPHA            ; or registered language subtag
+     */
+    if (len < 0) {
+        len = (int32_t)uprv_strlen(s);
+    }
+    if (len >= 2 && len <= 8 && _isAlphaString(s, len)) {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static UBool
+_isExtlangSubtag(const char* s, int32_t len) {
+    /*
+     * extlang       = 3ALPHA              ; selected ISO 639 codes
+     *                 *2("-" 3ALPHA)      ; permanently reserved
+     */
+    if (len < 0) {
+        len = (int32_t)uprv_strlen(s);
+    }
+    if (len == 3 && _isAlphaString(s, len)) {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static UBool
+_isScriptSubtag(const char* s, int32_t len) {
+    /*
+     * script        = 4ALPHA              ; ISO 15924 code
+     */
+    if (len < 0) {
+        len = (int32_t)uprv_strlen(s);
+    }
+    if (len == 4 && _isAlphaString(s, len)) {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static UBool
+_isRegionSubtag(const char* s, int32_t len) {
+    /*
+     * region        = 2ALPHA              ; ISO 3166-1 code
+     *               / 3DIGIT              ; UN M.49 code
+     */
+    if (len < 0) {
+        len = (int32_t)uprv_strlen(s);
+    }
+    if (len == 2 && _isAlphaString(s, len)) {
+        return TRUE;
+    }
+    if (len == 3 && _isNumericString(s, len)) {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static UBool
+_isVariantSubtag(const char* s, int32_t len) {
+    /*
+     * variant       = 5*8alphanum         ; registered variants
+     *               / (DIGIT 3alphanum)
+     */
+    if (len < 0) {
+        len = (int32_t)uprv_strlen(s);
+    }
+    if (len >= 5 && len <= 8 && _isAlphaString(s, len)) {
+        return TRUE;
+    }
+    if (len == 4 && ISNUMERIC(*s) && _isAlphaNumericString(s + 1, 3)) {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static UBool
+_isExtensionSingleton(const char* s, int32_t len) {
+    /*
+     * extension     = singleton 1*("-" (2*8alphanum))
+     */
+    if (len < 0) {
+        len = (int32_t)uprv_strlen(s);
+    }
+    if (len == 1 && ISALPHA(*s) && (uprv_tolower(*s) != PRIVATEUSE)) {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static UBool
+_isExtensionSubtag(const char* s, int32_t len) {
+    /*
+     * extension     = singleton 1*("-" (2*8alphanum))
+     */
+    if (len < 0) {
+        len = (int32_t)uprv_strlen(s);
+    }
+    if (len >= 2 && len <= 8 && _isAlphaNumericString(s, len)) {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static UBool
+_isExtensionSubtags(const char* s, int32_t len) {
+    const char *p = s;
+    const char *pSubtag = NULL;
+
+    if (len < 0) {
+        len = (int32_t)uprv_strlen(s);
+    }
+
+    while ((p - s) < len) {
+        if (*p == SEP) {
+            if (pSubtag == NULL) {
+                return FALSE;
+            }
+            if (!_isExtensionSubtag(pSubtag, (int32_t)(p - pSubtag))) {
+                return FALSE;
+            }
+            pSubtag = NULL;
+        } else if (pSubtag == NULL) {
+            pSubtag = p;
+        }
+        p++;
+    }
+    if (pSubtag == NULL) {
+        return FALSE;
+    }
+    return _isExtensionSubtag(pSubtag, (int32_t)(p - pSubtag));
+}
+
+static UBool
+_isPrivateuseValueSubtag(const char* s, int32_t len) {
+    /*
+     * privateuse    = "x" 1*("-" (1*8alphanum))
+     */
+    if (len < 0) {
+        len = (int32_t)uprv_strlen(s);
+    }
+    if (len >= 1 && len <= 8 && _isAlphaNumericString(s, len)) {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static UBool
+_isPrivateuseValueSubtags(const char* s, int32_t len) {
+    const char *p = s;
+    const char *pSubtag = NULL;
+
+    if (len < 0) {
+        len = (int32_t)uprv_strlen(s);
+    }
+
+    while ((p - s) < len) {
+        if (*p == SEP) {
+            if (pSubtag == NULL) {
+                return FALSE;
+            }
+            if (!_isPrivateuseValueSubtag(pSubtag, (int32_t)(p - pSubtag))) {
+                return FALSE;
+            }
+            pSubtag = NULL;
+        } else if (pSubtag == NULL) {
+            pSubtag = p;
+        }
+        p++;
+    }
+    if (pSubtag == NULL) {
+        return FALSE;
+    }
+    return _isPrivateuseValueSubtag(pSubtag, (int32_t)(p - pSubtag));
+}
+
+static UBool
+_isLDMLKey(const char* s, int32_t len) {
+    if (len < 0) {
+        len = (int32_t)uprv_strlen(s);
+    }
+    if (len == 2 && _isAlphaNumericString(s, len)) {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static UBool
+_isLDMLType(const char* s, int32_t len) {
+    if (len < 0) {
+        len = (int32_t)uprv_strlen(s);
+    }
+    if (len >= 3 && len <= 8 && _isAlphaNumericString(s, len)) {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+/*
+* -------------------------------------------------
+*
+* Helper functions
+*
+* -------------------------------------------------
+*/
+
+static UBool
+_addVariantToList(VariantListEntry **first, VariantListEntry *var) {
+    UBool bAdded = TRUE;
+
+    if (*first == NULL) {
+        var->next = NULL;
+        *first = var;
+    } else {
+        VariantListEntry *prev, *cur;
+        int32_t cmp;
+
+        /* reorder variants in alphabetical order */
+        prev = NULL;
+        cur = *first;
+        while (TRUE) {
+            if (cur == NULL) {
+                prev->next = var;
+                var->next = NULL;
+                break;
+            }
+            cmp = uprv_compareInvCharsAsAscii(var->variant, cur->variant);
+            if (cmp < 0) {
+                if (prev == NULL) {
+                    *first = var;
+                } else {
+                    prev->next = var;
+                }
+                var->next = cur;
+                break;
+            }
+            if (cmp == 0) {
+                /* duplicated variant */
+                bAdded = FALSE;
+                break;
+            }
+            prev = cur;
+            cur = cur->next;
+        }
+    }
+
+    return bAdded;
+}
+
+
+static UBool
+_addExtensionToList(ExtensionListEntry **first, ExtensionListEntry *ext, UBool localeToBCP) {
+    UBool bAdded = TRUE;
+
+    if (*first == NULL) {
+        ext->next = NULL;
+        *first = ext;
+    } else {
+        ExtensionListEntry *prev, *cur;
+        int32_t cmp;
+
+        /* reorder variants in alphabetical order */
+        prev = NULL;
+        cur = *first;
+        while (TRUE) {
+            if (cur == NULL) {
+                prev->next = ext;
+                ext->next = NULL;
+                break;
+            }
+            if (localeToBCP) {
+                /* special handling for locale to bcp conversion */
+                int32_t len, curlen;
+
+                len = (int32_t)uprv_strlen(ext->key);
+                curlen = (int32_t)uprv_strlen(cur->key);
+
+                if (len == 1 && curlen == 1) {
+                    if (*(ext->key) == *(cur->key)) {
+                        cmp = 0;
+                    } else if (*(ext->key) == PRIVATEUSE) {
+                        cmp = 1;
+                    } else if (*(cur->key) == PRIVATEUSE) {
+                        cmp = -1;
+                    } else {
+                        cmp = *(ext->key) - *(cur->key);
+                    }
+                } else if (len == 1) {
+                    cmp = *(ext->key) - LDMLEXT; 
+                } else if (curlen == 1) {
+                    cmp = LDMLEXT - *(cur->key);
+                } else {
+                    cmp = uprv_compareInvCharsAsAscii(ext->key, cur->key);
+                }
+            } else {
+                cmp = uprv_compareInvCharsAsAscii(ext->key, cur->key);
+            }
+            if (cmp < 0) {
+                if (prev == NULL) {
+                    *first = ext;
+                } else {
+                    prev->next = ext;
+                }
+                ext->next = cur;
+                break;
+            }
+            if (cmp == 0) {
+                /* duplicated extension key */
+                bAdded = FALSE;
+                break;
+            }
+            prev = cur;
+            cur = cur->next;
+        }
+    }
+
+    return bAdded;
+}
+
+static void
+_initializeULanguageTag(ULanguageTag* langtag) {
+    int32_t i;
+
+    langtag->buf = NULL;
+
+    langtag->language = EMPTY;
+    for (i = 0; i < MAXEXTLANG; i++) {
+        langtag->extlang[i] = NULL;
+    }
+
+    langtag->script = EMPTY;
+    langtag->region = EMPTY;
+
+    langtag->variants = NULL;
+    langtag->extensions = NULL;
+
+    langtag->grandfathered = EMPTY;
+    langtag->privateuse = EMPTY;
+}
+
+#define KEYTYPEDATA     "keyTypeData"
+#define KEYMAP          "keyMap"
+#define TYPEMAP         "typeMap"
+#define TYPEALIAS       "typeAlias"
+#define MAX_BCP47_SUBTAG_LEN    9   /* including null terminator */
+#define MAX_LDML_KEY_LEN        22
+#define MAX_LDML_TYPE_LEN       32
+
+static int32_t
+_ldmlKeyToBCP47(const char* key, int32_t keyLen,
+                char* bcpKey, int32_t bcpKeyCapacity,
+                UErrorCode *status) {
+    UResourceBundle *rb;
+    char keyBuf[MAX_LDML_KEY_LEN];
+    char bcpKeyBuf[MAX_BCP47_SUBTAG_LEN];
+    int32_t resultLen = 0;
+    int32_t i;
+    UErrorCode tmpStatus = U_ZERO_ERROR;
+    const UChar *uBcpKey;
+    int32_t bcpKeyLen;
+
+    if (keyLen < 0) {
+        keyLen = (int32_t)uprv_strlen(key);
+    }
+
+    if (keyLen >= sizeof(keyBuf)) {
+        /* no known valid LDML key exceeding 21 */
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    uprv_memcpy(keyBuf, key, keyLen);
+    keyBuf[keyLen] = 0;
+
+    /* to lower case */
+    for (i = 0; i < keyLen; i++) {
+        keyBuf[i] = uprv_tolower(keyBuf[i]);
+    }
+
+    rb = ures_openDirect(NULL, KEYTYPEDATA, status);
+    ures_getByKey(rb, KEYMAP, rb, status);
+
+    if (U_FAILURE(*status)) {
+        ures_close(rb);
+        return 0;
+    }
+
+    uBcpKey = ures_getStringByKey(rb, keyBuf, &bcpKeyLen, &tmpStatus);
+    if (U_SUCCESS(tmpStatus)) {
+        u_UCharsToChars(uBcpKey, bcpKeyBuf, bcpKeyLen);
+        bcpKeyBuf[bcpKeyLen] = 0;
+        resultLen = bcpKeyLen;
+    } else {
+        if (_isLDMLKey(key, keyLen)) {
+            uprv_memcpy(bcpKeyBuf, key, keyLen);
+            bcpKeyBuf[keyLen] = 0;
+            resultLen = keyLen;
+        } else {
+            /* mapping not availabe */
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+    }
+    ures_close(rb);
+
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+
+    uprv_memcpy(bcpKey, bcpKeyBuf, uprv_min(resultLen, bcpKeyCapacity));
+    return u_terminateChars(bcpKey, bcpKeyCapacity, resultLen, status);
+}
+
+static int32_t
+_bcp47ToLDMLKey(const char* bcpKey, int32_t bcpKeyLen,
+                char* key, int32_t keyCapacity,
+                UErrorCode *status) {
+    UResourceBundle *rb;
+    char bcpKeyBuf[MAX_BCP47_SUBTAG_LEN];
+    int32_t resultLen = 0;
+    int32_t i;
+    const char *resKey = NULL;
+    UResourceBundle *mapData;
+
+    if (bcpKeyLen < 0) {
+        bcpKeyLen = (int32_t)uprv_strlen(bcpKey);
+    }
+
+    if (bcpKeyLen >= sizeof(bcpKeyBuf)) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    uprv_memcpy(bcpKeyBuf, bcpKey, bcpKeyLen);
+    bcpKeyBuf[bcpKeyLen] = 0;
+
+    /* to lower case */
+    for (i = 0; i < bcpKeyLen; i++) {
+        bcpKeyBuf[i] = uprv_tolower(bcpKeyBuf[i]);
+    }
+
+    rb = ures_openDirect(NULL, KEYTYPEDATA, status);
+    ures_getByKey(rb, KEYMAP, rb, status);
+    if (U_FAILURE(*status)) {
+        ures_close(rb);
+        return 0;
+    }
+
+    mapData = ures_getNextResource(rb, NULL, status);
+    while (U_SUCCESS(*status)) {
+        const UChar *uBcpKey;
+        char tmpBcpKeyBuf[MAX_BCP47_SUBTAG_LEN];
+        int32_t tmpBcpKeyLen;
+
+        uBcpKey = ures_getString(mapData, &tmpBcpKeyLen, status);
+        if (U_FAILURE(*status)) {
+            break;
+        }
+        u_UCharsToChars(uBcpKey, tmpBcpKeyBuf, tmpBcpKeyLen);
+        tmpBcpKeyBuf[tmpBcpKeyLen] = 0;
+        if (uprv_compareInvCharsAsAscii(bcpKeyBuf, tmpBcpKeyBuf) == 0) {
+            /* found a matching BCP47 key */
+            resKey = ures_getKey(mapData);
+            resultLen = (int32_t)uprv_strlen(resKey);
+            break;
+        }
+        if (!ures_hasNext(rb)) {
+            break;
+        }
+        ures_getNextResource(rb, mapData, status);
+    }
+    ures_close(mapData);
+    ures_close(rb);
+
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+
+    if (resKey == NULL) {
+        resKey = bcpKeyBuf;
+        resultLen = bcpKeyLen;
+    }
+
+    uprv_memcpy(key, resKey, uprv_min(resultLen, keyCapacity));
+    return u_terminateChars(key, keyCapacity, resultLen, status);
+}
+
+static int32_t
+_ldmlTypeToBCP47(const char* key, int32_t keyLen,
+                 const char* type, int32_t typeLen,
+                 char* bcpType, int32_t bcpTypeCapacity,
+                 UErrorCode *status) {
+    UResourceBundle *rb, *keyTypeData, *typeMapForKey;
+    char keyBuf[MAX_LDML_KEY_LEN];
+    char typeBuf[MAX_LDML_TYPE_LEN];
+    char bcpTypeBuf[MAX_BCP47_SUBTAG_LEN];
+    int32_t resultLen = 0;
+    int32_t i;
+    UErrorCode tmpStatus = U_ZERO_ERROR;
+    const UChar *uBcpType, *uCanonicalType;
+    int32_t bcpTypeLen, canonicalTypeLen;
+    UBool isTimezone = FALSE;
+
+    if (keyLen < 0) {
+        keyLen = (int32_t)uprv_strlen(key);
+    }
+    if (keyLen >= sizeof(keyBuf)) {
+        /* no known valid LDML key exceeding 21 */
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    uprv_memcpy(keyBuf, key, keyLen);
+    keyBuf[keyLen] = 0;
+
+    /* to lower case */
+    for (i = 0; i < keyLen; i++) {
+        keyBuf[i] = uprv_tolower(keyBuf[i]);
+    }
+    if (uprv_compareInvCharsAsAscii(keyBuf, "timezone") == 0) {
+        isTimezone = TRUE;
+    }
+
+    if (typeLen < 0) {
+        typeLen = (int32_t)uprv_strlen(type);
+    }
+    if (typeLen >= sizeof(typeBuf)) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    if (isTimezone) {
+        /* replace '/' with ':' */
+        for (i = 0; i < typeLen; i++) {
+            if (*(type + i) == '/') {
+                typeBuf[i] = ':';
+            } else {
+                typeBuf[i] = *(type + i);
+            }
+        }
+        typeBuf[typeLen] = 0;
+        type = &typeBuf[0];
+    }
+
+    keyTypeData = ures_openDirect(NULL, KEYTYPEDATA, status);
+    rb = ures_getByKey(keyTypeData, TYPEMAP, NULL, status);
+    if (U_FAILURE(*status)) {
+        ures_close(rb);
+        ures_close(keyTypeData);
+        return 0;
+    }
+
+    typeMapForKey = ures_getByKey(rb, keyBuf, NULL, &tmpStatus);
+    uBcpType = ures_getStringByKey(typeMapForKey, type, &bcpTypeLen, &tmpStatus);
+    if (U_SUCCESS(tmpStatus)) {
+        u_UCharsToChars(uBcpType, bcpTypeBuf, bcpTypeLen);
+        resultLen = bcpTypeLen;
+    } else if (tmpStatus == U_MISSING_RESOURCE_ERROR) {
+        /* is this type alias? */
+        tmpStatus = U_ZERO_ERROR;
+        ures_getByKey(keyTypeData, TYPEALIAS, rb, &tmpStatus);
+        ures_getByKey(rb, keyBuf, rb, &tmpStatus);
+        uCanonicalType = ures_getStringByKey(rb, type, &canonicalTypeLen, &tmpStatus);
+        if (U_SUCCESS(tmpStatus)) {
+            u_UCharsToChars(uCanonicalType, typeBuf, canonicalTypeLen);
+            if (isTimezone) {
+                /* replace '/' with ':' */
+                for (i = 0; i < canonicalTypeLen; i++) {
+                    if (typeBuf[i] == '/') {
+                        typeBuf[i] = ':';
+                    }
+                }
+            }
+            typeBuf[canonicalTypeLen] = 0;
+
+            /* look up the canonical type */
+            uBcpType = ures_getStringByKey(typeMapForKey, typeBuf, &bcpTypeLen, &tmpStatus);
+            if (U_SUCCESS(tmpStatus)) {
+                u_UCharsToChars(uBcpType, bcpTypeBuf, bcpTypeLen);
+                resultLen = bcpTypeLen;
+            }
+        }
+        if (tmpStatus == U_MISSING_RESOURCE_ERROR) {
+            if (_isLDMLType(type, typeLen)) {
+                uprv_memcpy(bcpTypeBuf, type, typeLen);
+                resultLen = typeLen;
+            } else {
+                /* mapping not availabe */
+                *status = U_ILLEGAL_ARGUMENT_ERROR;
+            }
+        }
+    } else {
+        *status = tmpStatus;
+    }
+    ures_close(rb);
+    ures_close(typeMapForKey);
+    ures_close(keyTypeData);
+
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+
+    uprv_memcpy(bcpType, bcpTypeBuf, uprv_min(resultLen, bcpTypeCapacity));
+    return u_terminateChars(bcpType, bcpTypeCapacity, resultLen, status);
+}
+
+static int32_t
+_bcp47ToLDMLType(const char* key, int32_t keyLen,
+                 const char* bcpType, int32_t bcpTypeLen,
+                 char* type, int32_t typeCapacity,
+                 UErrorCode *status) {
+    UResourceBundle *rb;
+    char keyBuf[MAX_LDML_KEY_LEN];
+    char bcpTypeBuf[MAX_BCP47_SUBTAG_LEN];
+    int32_t resultLen = 0;
+    int32_t i;
+    const char *resType = NULL;
+    UResourceBundle *mapData;
+    UErrorCode tmpStatus = U_ZERO_ERROR;
+    int32_t copyLen;
+
+    if (keyLen < 0) {
+        keyLen = (int32_t)uprv_strlen(key);
+    }
+
+    if (keyLen >= sizeof(keyBuf)) {
+        /* no known valid LDML key exceeding 21 */
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    uprv_memcpy(keyBuf, key, keyLen);
+    keyBuf[keyLen] = 0;
+
+    /* to lower case */
+    for (i = 0; i < keyLen; i++) {
+        keyBuf[i] = uprv_tolower(keyBuf[i]);
+    }
+
+
+    if (bcpTypeLen < 0) {
+        bcpTypeLen = (int32_t)uprv_strlen(bcpType);
+    }
+
+    if (bcpTypeLen >= sizeof(bcpTypeBuf)) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    uprv_memcpy(bcpTypeBuf, bcpType, bcpTypeLen);
+    bcpTypeBuf[bcpTypeLen] = 0;
+
+    /* to lower case */
+    for (i = 0; i < bcpTypeLen; i++) {
+        bcpTypeBuf[i] = uprv_tolower(bcpTypeBuf[i]);
+    }
+
+    rb = ures_openDirect(NULL, KEYTYPEDATA, status);
+    ures_getByKey(rb, TYPEMAP, rb, status);
+    if (U_FAILURE(*status)) {
+        ures_close(rb);
+        return 0;
+    }
+
+    ures_getByKey(rb, keyBuf, rb, &tmpStatus);
+    mapData = ures_getNextResource(rb, NULL, &tmpStatus);
+    while (U_SUCCESS(tmpStatus)) {
+        const UChar *uBcpType;
+        char tmpBcpTypeBuf[MAX_BCP47_SUBTAG_LEN];
+        int32_t tmpBcpTypeLen;
+
+        uBcpType = ures_getString(mapData, &tmpBcpTypeLen, &tmpStatus);
+        if (U_FAILURE(tmpStatus)) {
+            break;
+        }
+        u_UCharsToChars(uBcpType, tmpBcpTypeBuf, tmpBcpTypeLen);
+        tmpBcpTypeBuf[tmpBcpTypeLen] = 0;
+        if (uprv_compareInvCharsAsAscii(bcpTypeBuf, tmpBcpTypeBuf) == 0) {
+            /* found a matching BCP47 type */
+            resType = ures_getKey(mapData);
+            resultLen = (int32_t)uprv_strlen(resType);
+            break;
+        }
+        if (!ures_hasNext(rb)) {
+            break;
+        }
+        ures_getNextResource(rb, mapData, &tmpStatus);
+    }
+    ures_close(mapData);
+    ures_close(rb);
+
+    if (U_FAILURE(tmpStatus) && tmpStatus != U_MISSING_RESOURCE_ERROR) {
+        *status = tmpStatus;
+        return 0;
+    }
+
+    if (resType == NULL) {
+        resType = bcpTypeBuf;
+        resultLen = bcpTypeLen;
+    }
+
+    copyLen = uprv_min(resultLen, typeCapacity);
+    uprv_memcpy(type, resType, copyLen);
+
+    if (uprv_compareInvCharsAsAscii(keyBuf, "timezone") == 0) {
+        for (i = 0; i < copyLen; i++) {
+            if (*(type + i) == ':') {
+                *(type + i) = '/';
+            }
+        }
+    }
+
+    return u_terminateChars(type, typeCapacity, resultLen, status);
+}
+
+static int32_t
+_appendLanguageToLanguageTag(const char* localeID, char* appendAt, int32_t capacity, UBool strict, UErrorCode* status) {
+    char buf[ULOC_LANG_CAPACITY];
+    UErrorCode tmpStatus = U_ZERO_ERROR;
+    int32_t len, i;
+    int32_t reslen = 0;
+
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+
+    len = uloc_getLanguage(localeID, buf, sizeof(buf), &tmpStatus);
+    if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
+        if (strict) {
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+            return 0;
+        }
+        len = 0;
+    }
+
+    /* Note: returned language code is in lower case letters */
+
+    if (len == 0) {
+        if (reslen < capacity) {
+            uprv_memcpy(appendAt + reslen, LANG_UND, uprv_min(LANG_UND_LEN, capacity - reslen));
+        }
+        reslen += LANG_UND_LEN;
+    } else if (!_isLanguageSubtag(buf, len)) {
+            /* invalid language code */
+        if (strict) {
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+            return 0;
+        }
+        if (reslen < capacity) {
+            uprv_memcpy(appendAt + reslen, LANG_UND, uprv_min(LANG_UND_LEN, capacity - reslen));
+        }
+        reslen += LANG_UND_LEN;
+    } else {
+        /* resolve deprecated */
+        for (i = 0; DEPRECATEDLANGS[i] != NULL; i += 2) {
+            if (uprv_compareInvCharsAsAscii(buf, DEPRECATEDLANGS[i]) == 0) {
+                uprv_strcpy(buf, DEPRECATEDLANGS[i + 1]);
+                len = (int32_t)uprv_strlen(buf);
+                break;
+            }
+        }
+        if (reslen < capacity) {
+            uprv_memcpy(appendAt + reslen, buf, uprv_min(len, capacity - reslen));
+        }
+        reslen += len;
+    }
+    u_terminateChars(appendAt, capacity, reslen, status);
+    return reslen;
+}
+
+static int32_t
+_appendScriptToLanguageTag(const char* localeID, char* appendAt, int32_t capacity, UBool strict, UErrorCode* status) {
+    char buf[ULOC_SCRIPT_CAPACITY];
+    UErrorCode tmpStatus = U_ZERO_ERROR;
+    int32_t len;
+    int32_t reslen = 0;
+
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+
+    len = uloc_getScript(localeID, buf, sizeof(buf), &tmpStatus);
+    if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
+        if (strict) {
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+        return 0;
+    }
+
+    if (len > 0) {
+        if (!_isScriptSubtag(buf, len)) {
+            /* invalid script code */
+            if (strict) {
+                *status = U_ILLEGAL_ARGUMENT_ERROR;
+            }
+            return 0;
+        } else {
+            if (reslen < capacity) {
+                *(appendAt + reslen) = SEP;
+            }
+            reslen++;
+
+            if (reslen < capacity) {
+                uprv_memcpy(appendAt + reslen, buf, uprv_min(len, capacity - reslen));
+            }
+            reslen += len;
+        }
+    }
+    u_terminateChars(appendAt, capacity, reslen, status);
+    return reslen;
+}
+
+static int32_t
+_appendRegionToLanguageTag(const char* localeID, char* appendAt, int32_t capacity, UBool strict, UErrorCode* status) {
+    char buf[ULOC_COUNTRY_CAPACITY];
+    UErrorCode tmpStatus = U_ZERO_ERROR;
+    int32_t len;
+    int32_t reslen = 0;
+
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+
+    len = uloc_getCountry(localeID, buf, sizeof(buf), &tmpStatus);
+    if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
+        if (strict) {
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+        return 0;
+    }
+
+    if (len > 0) {
+        if (!_isRegionSubtag(buf, len)) {
+            /* invalid region code */
+            if (strict) {
+                *status = U_ILLEGAL_ARGUMENT_ERROR;
+            }
+            return 0;
+        } else {
+            if (reslen < capacity) {
+                *(appendAt + reslen) = SEP;
+            }
+            reslen++;
+
+            if (reslen < capacity) {
+                uprv_memcpy(appendAt + reslen, buf, uprv_min(len, capacity - reslen));
+            }
+            reslen += len;
+        }
+    }
+    u_terminateChars(appendAt, capacity, reslen, status);
+    return reslen;
+}
+
+static int32_t
+_appendVariantsToLanguageTag(const char* localeID, char* appendAt, int32_t capacity, UBool strict, UBool *hadPosix, UErrorCode* status) {
+    char buf[ULOC_FULLNAME_CAPACITY];
+    UErrorCode tmpStatus = U_ZERO_ERROR;
+    int32_t len, i;
+    int32_t reslen = 0;
+
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+
+    len = uloc_getVariant(localeID, buf, sizeof(buf), &tmpStatus);
+    if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
+        if (strict) {
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+        return 0;
+    }
+
+    if (len > 0) {
+        char *p, *pVar;
+        UBool bNext = TRUE;
+        VariantListEntry *var;
+        VariantListEntry *varFirst = NULL;
+
+        pVar = NULL;
+        p = buf;
+        while (bNext) {
+            if (*p == SEP || *p == LOCALE_SEP || *p == 0) {
+                if (*p == 0) {
+                    bNext = FALSE;
+                } else {
+                    *p = 0; /* terminate */
+                }
+                if (pVar == NULL) {
+                    if (strict) {
+                        *status = U_ILLEGAL_ARGUMENT_ERROR;
+                        break;
+                    }
+                    /* ignore empty variant */
+                } else {
+                    /* ICU uses upper case letters for variants, but
+                       the canonical format is lowercase in BCP47 */
+                    for (i = 0; *(pVar + i) != 0; i++) {
+                        *(pVar + i) = uprv_tolower(*(pVar + i));
+                    }
+
+                    /* validate */
+                    if (_isVariantSubtag(pVar, -1)) {
+                        if (uprv_strcmp(pVar,POSIX_VALUE)) {
+                            /* emit the variant to the list */
+                            var = uprv_malloc(sizeof(VariantListEntry));
+                            if (var == NULL) {
+                                *status = U_MEMORY_ALLOCATION_ERROR;
+                                break;
+                            }
+                            var->variant = pVar;
+                            if (!_addVariantToList(&varFirst, var)) {
+                                /* duplicated variant */
+                                uprv_free(var);
+                                if (strict) {
+                                    *status = U_ILLEGAL_ARGUMENT_ERROR;
+                                    break;
+                                }
+                            }
+                        } else {
+                            /* Special handling for POSIX variant, need to remember that we had it and then */
+                            /* treat it like an extension later. */
+                            *hadPosix = TRUE;
+                        }
+                    } else if (strict) {
+                        *status = U_ILLEGAL_ARGUMENT_ERROR;
+                        break;
+                    }
+                }
+                /* reset variant starting position */
+                pVar = NULL;
+            } else if (pVar == NULL) {
+                pVar = p;
+            }
+            p++;
+        }
+
+        if (U_SUCCESS(*status)) {
+            if (varFirst != NULL) {
+                int32_t varLen;
+
+                /* write out sorted/validated/normalized variants to the target */
+                var = varFirst;
+                while (var != NULL) {
+                    if (reslen < capacity) {
+                        *(appendAt + reslen) = SEP;
+                    }
+                    reslen++;
+                    varLen = (int32_t)uprv_strlen(var->variant);
+                    if (reslen < capacity) {
+                        uprv_memcpy(appendAt + reslen, var->variant, uprv_min(varLen, capacity - reslen));
+                    }
+                    reslen += varLen;
+                    var = var->next;
+                }
+            }
+        }
+
+        /* clean up */
+        var = varFirst;
+        while (var != NULL) {
+            VariantListEntry *tmpVar = var->next;
+            uprv_free(var);
+            var = tmpVar;
+        }
+
+        if (U_FAILURE(*status)) {
+            return 0;
+        }
+    }
+
+    u_terminateChars(appendAt, capacity, reslen, status);
+    return reslen;
+}
+
+static int32_t
+_appendKeywordsToLanguageTag(const char* localeID, char* appendAt, int32_t capacity, UBool strict, UBool hadPosix, UErrorCode* status) {
+    char buf[ULOC_KEYWORD_AND_VALUES_CAPACITY];
+    UEnumeration *keywordEnum = NULL;
+    int32_t reslen = 0;
+
+    keywordEnum = uloc_openKeywords(localeID, status);
+    if (U_FAILURE(*status) && !hadPosix) {
+        uenum_close(keywordEnum);
+        return 0;
+    }
+    if (keywordEnum != NULL || hadPosix) {
+        /* reorder extensions */
+        int32_t len;
+        const char *key;
+        ExtensionListEntry *firstExt = NULL;
+        ExtensionListEntry *ext;
+        char extBuf[ULOC_KEYWORD_AND_VALUES_CAPACITY];
+        char *pExtBuf = extBuf;
+        int32_t extBufCapacity = sizeof(extBuf);
+        const char *bcpKey, *bcpValue;
+        UErrorCode tmpStatus = U_ZERO_ERROR;
+        int32_t keylen;
+        UBool isLDMLKeyword;
+
+        while (TRUE) {
+            key = uenum_next(keywordEnum, NULL, status);
+            if (key == NULL) {
+                break;
+            }
+            len = uloc_getKeywordValue(localeID, key, buf, sizeof(buf), &tmpStatus);
+            if (U_FAILURE(tmpStatus)) {
+                if (strict) {
+                    *status = U_ILLEGAL_ARGUMENT_ERROR;
+                    break;
+                }
+                /* ignore this keyword */
+                tmpStatus = U_ZERO_ERROR;
+                continue;
+            }
+
+            keylen = (int32_t)uprv_strlen(key);
+            isLDMLKeyword = (keylen > 1);
+
+            if (isLDMLKeyword) {
+                int32_t modKeyLen;
+
+                /* transform key and value to bcp47 style */
+                modKeyLen = _ldmlKeyToBCP47(key, keylen, pExtBuf, extBufCapacity, &tmpStatus);
+                if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
+                    if (strict) {
+                        *status = U_ILLEGAL_ARGUMENT_ERROR;
+                        break;
+                    }
+                    tmpStatus = U_ZERO_ERROR;
+                    continue;
+                }
+
+                bcpKey = pExtBuf;
+                pExtBuf += (modKeyLen + 1);
+                extBufCapacity -= (modKeyLen + 1);
+
+                len = _ldmlTypeToBCP47(key, keylen, buf, len, pExtBuf, extBufCapacity, &tmpStatus);
+                if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
+                    if (strict) {
+                        *status = U_ILLEGAL_ARGUMENT_ERROR;
+                        break;
+                    }
+                    tmpStatus = U_ZERO_ERROR;
+                    continue;
+                }
+                bcpValue = pExtBuf;
+                pExtBuf += (len + 1);
+                extBufCapacity -= (len + 1);
+            } else {
+                if (*key == PRIVATEUSE) {
+                    if (!_isPrivateuseValueSubtags(buf, len)) {
+                        if (strict) {
+                            *status = U_ILLEGAL_ARGUMENT_ERROR;
+                            break;
+                        }
+                        continue;
+                    }
+                } else {
+                    if (!_isExtensionSingleton(key, keylen) || !_isExtensionSubtags(buf, len)) {
+                        if (strict) {
+                            *status = U_ILLEGAL_ARGUMENT_ERROR;
+                            break;
+                        }
+                        continue;
+                    }
+                }
+                bcpKey = key;
+                if ((len + 1) < extBufCapacity) {
+                    uprv_memcpy(pExtBuf, buf, len);
+                    bcpValue = pExtBuf;
+
+                    pExtBuf += len;
+
+                    *pExtBuf = 0;
+                    pExtBuf++;
+
+                    extBufCapacity -= (len + 1);
+                } else {
+                    *status = U_ILLEGAL_ARGUMENT_ERROR;
+                    break;
+                }
+            }
+
+            /* create ExtensionListEntry */
+            ext = uprv_malloc(sizeof(ExtensionListEntry));
+            if (ext == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                break;
+            }
+            ext->key = bcpKey;
+            ext->value = bcpValue;
+
+            if (!_addExtensionToList(&firstExt, ext, TRUE)) {
+                uprv_free(ext);
+                if (strict) {
+                    *status = U_ILLEGAL_ARGUMENT_ERROR;
+                    break;
+                }
+            }
+        }
+
+        /* Special handling for POSIX variant - add the keywords for POSIX */
+        if (hadPosix) {
+            /* create ExtensionListEntry for POSIX */
+            ext = uprv_malloc(sizeof(ExtensionListEntry));
+            if (ext == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+            }
+            ext->key = POSIX_KEY;
+            ext->value = POSIX_VALUE;
+
+            if (!_addExtensionToList(&firstExt, ext, TRUE)) {
+                uprv_free(ext);
+            }
+        }
+
+        if (U_SUCCESS(*status) && (firstExt != NULL)) {
+            UBool startLDMLExtension = FALSE;
+
+            /* write out the sorted BCP47 extensions and private use */
+            ext = firstExt;
+            while (ext != NULL) {
+                if ((int32_t)uprv_strlen(ext->key) > 1 && !startLDMLExtension) {
+                    /* write LDML singleton extension */
+                    if (reslen < capacity) {
+                        *(appendAt + reslen) = SEP;
+                    }
+                    reslen++;
+                    if (reslen < capacity) {
+                        *(appendAt + reslen) = LDMLEXT;
+                    }
+                    reslen++;
+                    startLDMLExtension = TRUE;
+                }
+
+                if (reslen < capacity) {
+                    *(appendAt + reslen) = SEP;
+                }
+                reslen++;
+                len = (int32_t)uprv_strlen(ext->key);
+                if (reslen < capacity) {
+                    uprv_memcpy(appendAt + reslen, ext->key, uprv_min(len, capacity - reslen));
+                }
+                reslen += len;
+                if (reslen < capacity) {
+                    *(appendAt + reslen) = SEP;
+                }
+                reslen++;
+                len = (int32_t)uprv_strlen(ext->value);
+                if (reslen < capacity) {
+                    uprv_memcpy(appendAt + reslen, ext->value, uprv_min(len, capacity - reslen));
+                }
+                reslen += len;
+
+                ext = ext->next;
+            }
+        }
+        /* clean up */
+        ext = firstExt;
+        while (ext != NULL) {
+            ExtensionListEntry *tmpExt = ext->next;
+            uprv_free(ext);
+            ext = tmpExt;
+        }
+
+        uenum_close(keywordEnum);
+
+        if (U_FAILURE(*status)) {
+            return 0;
+        }
+    }
+
+    return u_terminateChars(appendAt, capacity, reslen, status);
+}
+
+/**
+ * Append keywords parsed from LDML extension value
+ * e.g. "u-ca-gregory-co-trad" -> {calendar = gregorian} {collation = traditional}
+ * Note: char* buf is used for storing keywords
+ */
+static void
+_appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendTo, char* buf, int32_t bufSize, UBool *posixVariant, UErrorCode *status) {
+    const char *p, *pNext, *pSep;
+    const char *pBcpKey, *pBcpType;
+    const char *pKey, *pType;
+    int32_t bcpKeyLen = 0, bcpTypeLen;
+    ExtensionListEntry *kwd, *nextKwd;
+    ExtensionListEntry *kwdFirst = NULL;
+    int32_t bufIdx = 0;
+    int32_t  len;
+
+    pNext = ldmlext;
+    pBcpKey = pBcpType = NULL;
+    while (pNext) {
+        p = pSep = pNext;
+
+        /* locate next separator char */
+        while (*pSep) {
+            if (*pSep == SEP) {
+                break;
+            }
+            pSep++;
+        }
+        if (*pSep == 0) {
+            /* last subtag */
+            pNext = NULL;
+        } else {
+            pNext = pSep + 1;
+        }
+
+        if (pBcpKey == NULL) {
+            pBcpKey = p;
+            bcpKeyLen = (int32_t)(pSep - p);
+        } else {
+            pBcpType = p;
+            bcpTypeLen = (int32_t)(pSep - p);
+
+            /* BCP key to locale key */
+            len = _bcp47ToLDMLKey(pBcpKey, bcpKeyLen, buf + bufIdx, bufSize - bufIdx - 1, status);
+            if (U_FAILURE(*status)) {
+                goto cleanup;
+            }
+            pKey = buf + bufIdx;
+            bufIdx += len;
+            *(buf + bufIdx) = 0;
+            bufIdx++;
+
+            /* BCP type to locale type */
+            len = _bcp47ToLDMLType(pKey, -1, pBcpType, bcpTypeLen, buf + bufIdx, bufSize - bufIdx - 1, status);
+            if (U_FAILURE(*status)) {
+                goto cleanup;
+            }
+            pType = buf + bufIdx;
+            bufIdx += len;
+            *(buf + bufIdx) = 0;
+            bufIdx++;
+
+            /* Special handling for u-va-posix, since we want to treat this as a variant, not */
+            /* as a keyword.                                                                  */
+
+            if ( !uprv_strcmp(pKey,POSIX_KEY) && !uprv_strcmp(pType,POSIX_VALUE) ) {
+                *posixVariant = TRUE;
+            } else {
+                /* create an ExtensionListEntry for this keyword */
+                kwd = uprv_malloc(sizeof(ExtensionListEntry));
+                if (kwd == NULL) {
+                    *status = U_MEMORY_ALLOCATION_ERROR;
+                    goto cleanup;
+                }
+
+                kwd->key = pKey;
+                kwd->value = pType;
+
+                if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
+                    *status = U_ILLEGAL_ARGUMENT_ERROR;
+                    uprv_free(kwd);
+                    goto cleanup;
+                }
+            }
+
+            /* for next pair */
+            pBcpKey = NULL;
+            pBcpType = NULL;
+        }
+    }
+
+    if (pBcpKey != NULL) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        goto cleanup;
+    }
+
+    kwd = kwdFirst;
+    while (kwd != NULL) {
+        nextKwd = kwd->next;
+        _addExtensionToList(appendTo, kwd, FALSE);
+        kwd = nextKwd;
+    }
+
+    return;
+
+cleanup:
+    kwd = kwdFirst;
+    while (kwd != NULL) {
+        nextKwd = kwd->next;
+        uprv_free(kwd);
+        kwd = nextKwd;
+    }
+}
+
+
+static int32_t
+_appendKeywords(ULanguageTag* langtag, char* appendAt, int32_t capacity, UErrorCode* status) {
+    int32_t reslen = 0;
+    int32_t i, n;
+    int32_t len;
+    ExtensionListEntry *kwdFirst = NULL;
+    ExtensionListEntry *kwd;
+    const char *key, *type;
+    char kwdBuf[ULOC_KEYWORDS_CAPACITY];
+    UBool posixVariant = FALSE;
+
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+
+    n = ultag_getExtensionsSize(langtag);
+
+    /* resolve locale keywords and reordering keys */
+    for (i = 0; i < n; i++) {
+        key = ultag_getExtensionKey(langtag, i);
+        type = ultag_getExtensionValue(langtag, i);
+        if (*key == LDMLEXT) {
+            _appendLDMLExtensionAsKeywords(type, &kwdFirst, kwdBuf, sizeof(kwdBuf), &posixVariant, status);
+            if (U_FAILURE(*status)) {
+                break;
+            }
+        } else {
+            kwd = uprv_malloc(sizeof(ExtensionListEntry));
+            if (kwd == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                break;
+            }
+            kwd->key = key;
+            kwd->value = type;
+            if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
+                uprv_free(kwd);
+                *status = U_ILLEGAL_ARGUMENT_ERROR;
+                break;
+            }
+        }
+    }
+
+    if (U_SUCCESS(*status)) {
+        type = ultag_getPrivateUse(langtag);
+        if ((int32_t)uprv_strlen(type) > 0) {
+            /* add private use as a keyword */
+            kwd = uprv_malloc(sizeof(ExtensionListEntry));
+            if (kwd == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+            } else {
+                kwd->key = PRIVATEUSE_KEY;
+                kwd->value = type;
+                if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
+                    uprv_free(kwd);
+                    *status = U_ILLEGAL_ARGUMENT_ERROR;
+                }
+            }
+        }
+    }
+
+    /* If a POSIX variant was in the extensions, write it out before writing the keywords. */
+
+    if (U_SUCCESS(*status) && posixVariant) {
+        len = (int32_t) uprv_strlen(_POSIX);
+        if (reslen < capacity) {
+            uprv_memcpy(appendAt + reslen, _POSIX, uprv_min(len, capacity - reslen));
+        }
+        reslen += len;
+    }
+
+    if (U_SUCCESS(*status) && kwdFirst != NULL) {
+        /* write out the sorted keywords */
+        kwd = kwdFirst;
+        while (kwd != NULL) {
+            if (reslen < capacity) {
+                if (kwd == kwdFirst) {
+                    /* '@' */
+                    *(appendAt + reslen) = LOCALE_EXT_SEP;
+                } else {
+                    /* ';' */
+                    *(appendAt + reslen) = LOCALE_KEYWORD_SEP;
+                }
+            }
+            reslen++;
+
+            /* key */
+            len = (int32_t)uprv_strlen(kwd->key);
+            if (reslen < capacity) {
+                uprv_memcpy(appendAt + reslen, kwd->key, uprv_min(len, capacity - reslen));
+            }
+            reslen += len;
+
+            /* '=' */
+            if (reslen < capacity) {
+                *(appendAt + reslen) = LOCALE_KEY_TYPE_SEP;
+            }
+            reslen++;
+
+            /* type */
+            len = (int32_t)uprv_strlen(kwd->value);
+            if (reslen < capacity) {
+                uprv_memcpy(appendAt + reslen, kwd->value, uprv_min(len, capacity - reslen));
+            }
+            reslen += len;
+
+            kwd = kwd->next;
+        }
+    }
+
+    /* clean up */
+    kwd = kwdFirst;
+    while (kwd != NULL) {
+        ExtensionListEntry *tmpKwd = kwd->next;
+        uprv_free(kwd);
+        kwd = tmpKwd;
+    }
+
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+
+    return u_terminateChars(appendAt, capacity, reslen, status);
+}
+
+/*
+* -------------------------------------------------
+*
+* ultag_ functions
+*
+* -------------------------------------------------
+*/
+
+/* Bit flags used by the parser */
+#define LANG 0x0001
+#define EXTL 0x0002
+#define SCRT 0x0004
+#define REGN 0x0008
+#define VART 0x0010
+#define EXTS 0x0020
+#define EXTV 0x0040
+#define PRIV 0x0080
+
+static ULanguageTag*
+ultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode* status) {
+    ULanguageTag *t;
+    char *tagBuf;
+    int16_t next;
+    char *pSubtag, *pNext, *pLastGoodPosition;
+    int32_t subtagLen;
+    int32_t extlangIdx;
+    ExtensionListEntry *pExtension;
+    char *pExtValueSubtag, *pExtValueSubtagEnd;
+    int32_t i;
+    UBool isLDMLExtension, reqLDMLType;
+
+    if (parsedLen != NULL) {
+        *parsedLen = 0;
+    }
+
+    if (U_FAILURE(*status)) {
+        return NULL;
+    }
+
+    if (tagLen < 0) {
+        tagLen = (int32_t)uprv_strlen(tag);
+    }
+
+    /* copy the entire string */
+    tagBuf = (char*)uprv_malloc(tagLen + 1);
+    if (tagBuf == NULL) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    uprv_memcpy(tagBuf, tag, tagLen);
+    *(tagBuf + tagLen) = 0;
+
+    /* create a ULanguageTag */
+    t = (ULanguageTag*)uprv_malloc(sizeof(ULanguageTag));
+    _initializeULanguageTag(t);
+    t->buf = tagBuf;
+    if (t == NULL) {
+        uprv_free(tagBuf);
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+
+    if (tagLen < MINLEN) {
+        /* the input tag is too short - return empty ULanguageTag */
+        return t;
+    }
+
+    /* check if the tag is grandfathered */
+    for (i = 0; GRANDFATHERED[i] != NULL; i += 2) {
+        if (T_CString_stricmp(GRANDFATHERED[i], tagBuf) == 0) {
+            /* a grandfathered tag is always longer than its preferred mapping */
+            uprv_strcpy(t->buf, GRANDFATHERED[i + 1]);
+            t->language = t->buf;
+            if (parsedLen != NULL) {
+                *parsedLen = tagLen;
+            }
+            return t;
+        }
+    }
+
+    /*
+     * langtag      =   language
+     *                  ["-" script]
+     *                  ["-" region]
+     *                  *("-" variant)
+     *                  *("-" extension)
+     *                  ["-" privateuse]
+     */
+
+    next = LANG | PRIV;
+    pNext = pLastGoodPosition = tagBuf;
+    extlangIdx = 0;
+    pExtension = NULL;
+    pExtValueSubtag = NULL;
+    pExtValueSubtagEnd = NULL;
+    isLDMLExtension = FALSE;
+    reqLDMLType = FALSE;
+
+    while (pNext) {
+        char *pSep;
+
+        pSubtag = pNext;
+
+        /* locate next separator char */
+        pSep = pSubtag;
+        while (*pSep) {
+            if (*pSep == SEP) {
+                break;
+            }
+            pSep++;
+        }
+        if (*pSep == 0) {
+            /* last subtag */
+            pNext = NULL;
+        } else {
+            pNext = pSep + 1;
+        }
+        subtagLen = (int32_t)(pSep - pSubtag);
+
+        if (next & LANG) {
+            if (_isLanguageSubtag(pSubtag, subtagLen)) {
+                *pSep = 0;  /* terminate */
+                t->language = T_CString_toLowerCase(pSubtag);
+
+                pLastGoodPosition = pSep;
+                next = EXTL | SCRT | REGN | VART | EXTS | PRIV;
+                continue;
+            }
+        }
+        if (next & EXTL) {
+            if (_isExtlangSubtag(pSubtag, subtagLen)) {
+                *pSep = 0;
+                t->extlang[extlangIdx++] = T_CString_toLowerCase(pSubtag);
+
+                pLastGoodPosition = pSep;
+                if (extlangIdx < 3) {
+                    next = EXTL | SCRT | REGN | VART | EXTS | PRIV;
+                } else {
+                    next = SCRT | REGN | VART | EXTS | PRIV;
+                }
+                continue;
+            }
+        }
+        if (next & SCRT) {
+            if (_isScriptSubtag(pSubtag, subtagLen)) {
+                char *p = pSubtag;
+
+                *pSep = 0;
+
+                /* to title case */
+                *p = uprv_toupper(*p);
+                p++;
+                for (; *p; p++) {
+                    *p = uprv_tolower(*p);
+                }
+
+                t->script = pSubtag;
+
+                pLastGoodPosition = pSep;
+                next = REGN | VART | EXTS | PRIV;
+                continue;
+            }
+        }
+        if (next & REGN) {
+            if (_isRegionSubtag(pSubtag, subtagLen)) {
+                *pSep = 0;
+                t->region = T_CString_toUpperCase(pSubtag);
+
+                pLastGoodPosition = pSep;
+                next = VART | EXTS | PRIV;
+                continue;
+            }
+        }
+        if (next & VART) {
+            if (_isVariantSubtag(pSubtag, subtagLen)) {
+                VariantListEntry *var;
+                UBool isAdded;
+
+                var = (VariantListEntry*)uprv_malloc(sizeof(VariantListEntry));
+                if (var == NULL) {
+                    *status = U_MEMORY_ALLOCATION_ERROR;
+                    goto error;
+                }
+                *pSep = 0;
+                var->variant = T_CString_toUpperCase(pSubtag);
+                isAdded = _addVariantToList(&(t->variants), var);
+                if (!isAdded) {
+                    /* duplicated variant entry */
+                    uprv_free(var);
+                    break;
+                }
+                pLastGoodPosition = pSep;
+                next = VART | EXTS | PRIV;
+                continue;
+            }
+        }
+        if (next & EXTS) {
+            if (_isExtensionSingleton(pSubtag, subtagLen)) {
+                if (pExtension != NULL) {
+                    if (pExtValueSubtag == NULL || pExtValueSubtagEnd == NULL) {
+                        /* the previous extension is incomplete */
+                        uprv_free(pExtension);
+                        pExtension = NULL;
+                        break;
+                    }
+
+                    /* terminate the previous extension value */
+                    *pExtValueSubtagEnd = 0;
+                    pExtension->value = T_CString_toLowerCase(pExtValueSubtag);
+
+                    /* insert the extension to the list */
+                    if (_addExtensionToList(&(t->extensions), pExtension, FALSE)) {
+                        pLastGoodPosition = pExtValueSubtagEnd;
+                    } else {
+                        /* stop parsing here */
+                        uprv_free(pExtension);
+                        pExtension = NULL;
+                        break;
+                    }
+
+                    if (isLDMLExtension && reqLDMLType) {
+                        /* incomplete LDML extension key and type pair */
+                        pExtension = NULL;
+                        break;
+                    }
+                }
+
+                isLDMLExtension = (uprv_tolower(*pSubtag) == LDMLEXT);
+
+                /* create a new extension */
+                pExtension = uprv_malloc(sizeof(ExtensionListEntry));
+                if (pExtension == NULL) {
+                    *status = U_MEMORY_ALLOCATION_ERROR;
+                    goto error;
+                }
+                *pSep = 0;
+                pExtension->key = T_CString_toLowerCase(pSubtag);
+                pExtension->value = NULL;   /* will be set later */
+
+                /*
+                 * reset the start and the end location of extension value
+                 * subtags for this extension
+                 */
+                pExtValueSubtag = NULL;
+                pExtValueSubtagEnd = NULL;
+
+                next = EXTV;
+                continue;
+            }
+        }
+        if (next & EXTV) {
+            if (_isExtensionSubtag(pSubtag, subtagLen)) {
+                if (isLDMLExtension) {
+                    if (reqLDMLType) {
+                        /* already saw an LDML key */
+                        if (!_isLDMLType(pSubtag, subtagLen)) {
+                            /* stop parsing here and let the valid LDML extension key/type
+                               pairs processed by the code out of this while loop */
+                            break;
+                        }
+                        pExtValueSubtagEnd = pSep;
+                        reqLDMLType = FALSE;
+                        next = EXTS | EXTV | PRIV;
+                    } else {
+                        /* LDML key */
+                        if (!_isLDMLKey(pSubtag, subtagLen)) {
+                            /* stop parsing here and let the valid LDML extension key/type
+                               pairs processed by the code out of this while loop */
+                            break;
+                        }
+                        reqLDMLType = TRUE;
+                        next = EXTV;
+                    }
+                } else {
+                    /* Mark the end of this subtag */
+                    pExtValueSubtagEnd = pSep;
+                    next = EXTS | EXTV | PRIV;
+                }
+
+                if (pExtValueSubtag == NULL) {
+                    /* if the start postion of this extension's value is not yet,
+                       this one is the first value subtag */
+                    pExtValueSubtag = pSubtag;
+                }
+                continue;
+            }
+        }
+        if (next & PRIV) {
+            if (uprv_tolower(*pSubtag) == PRIVATEUSE) {
+                char *pPrivuseVal;
+
+                if (pExtension != NULL) {
+                    /* Process the last extension */
+                    if (pExtValueSubtag == NULL || pExtValueSubtagEnd == NULL) {
+                        /* the previous extension is incomplete */
+                        uprv_free(pExtension);
+                        pExtension = NULL;
+                        break;
+                    } else {
+                        /* terminate the previous extension value */
+                        *pExtValueSubtagEnd = 0;
+                        pExtension->value = T_CString_toLowerCase(pExtValueSubtag);
+
+                        /* insert the extension to the list */
+                        if (_addExtensionToList(&(t->extensions), pExtension, FALSE)) {
+                            pLastGoodPosition = pExtValueSubtagEnd;
+                            pExtension = NULL;
+                        } else {
+                        /* stop parsing here */
+                            uprv_free(pExtension);
+                            pExtension = NULL;
+                            break;
+                        }
+                    }
+                }
+
+                /* The rest of part will be private use value subtags */
+                if (pNext == NULL) {
+                    /* empty private use subtag */
+                    break;
+                }
+                /* back up the private use value start position */
+                pPrivuseVal = pNext;
+
+                /* validate private use value subtags */
+                while (pNext) {
+                    pSubtag = pNext;
+                    pSep = pSubtag;
+                    while (*pSep) {
+                        if (*pSep == SEP) {
+                            break;
+                        }
+                        pSep++;
+                    }
+                    if (*pSep == 0) {
+                        /* last subtag */
+                        pNext = NULL;
+                    } else {
+                        pNext = pSep + 1;
+                    }
+                    subtagLen = (int32_t)(pSep - pSubtag);
+
+                    if (_isPrivateuseValueSubtag(pSubtag, subtagLen)) {
+                        pLastGoodPosition = pSep;
+                    } else {
+                        break;
+                    }
+                }
+                if (pLastGoodPosition - pPrivuseVal > 0) {
+                    *pLastGoodPosition = 0;
+                    t->privateuse = T_CString_toLowerCase(pPrivuseVal);
+                }
+                /* No more subtags, exiting the parse loop */
+                break;
+            }
+            break;
+        }
+        /* If we fell through here, it means this subtag is illegal - quit parsing */
+        break;
+    }
+
+    if (pExtension != NULL) {
+        /* Process the last extension */
+        if (pExtValueSubtag == NULL || pExtValueSubtagEnd == NULL) {
+            /* the previous extension is incomplete */
+            uprv_free(pExtension);
+        } else {
+            /* terminate the previous extension value */
+            *pExtValueSubtagEnd = 0;
+            pExtension->value = T_CString_toLowerCase(pExtValueSubtag);
+            /* insert the extension to the list */
+            if (_addExtensionToList(&(t->extensions), pExtension, FALSE)) {
+                pLastGoodPosition = pExtValueSubtagEnd;
+            } else {
+                uprv_free(pExtension);
+            }
+        }
+    }
+
+    if (parsedLen != NULL) {
+        *parsedLen = (int32_t)(pLastGoodPosition - t->buf);
+    }
+
+    return t;
+
+error:
+    uprv_free(t);
+    return NULL;
+}
+
+static void
+ultag_close(ULanguageTag* langtag) {
+
+    if (langtag == NULL) {
+        return;
+    }
+
+    uprv_free(langtag->buf);
+
+    if (langtag->variants) {
+        VariantListEntry *curVar = langtag->variants;
+        while (curVar) {
+            VariantListEntry *nextVar = curVar->next;
+            uprv_free(curVar);
+            curVar = nextVar;
+        }
+    }
+
+    if (langtag->extensions) {
+        ExtensionListEntry *curExt = langtag->extensions;
+        while (curExt) {
+            ExtensionListEntry *nextExt = curExt->next;
+            uprv_free(curExt);
+            curExt = nextExt;
+        }
+    }
+
+    uprv_free(langtag);
+}
+
+static const char*
+ultag_getLanguage(const ULanguageTag* langtag) {
+    return langtag->language;
+}
+
+#if 0
+static const char*
+ultag_getJDKLanguage(const ULanguageTag* langtag) {
+    int32_t i;
+    for (i = 0; DEPRECATEDLANGS[i] != NULL; i += 2) {
+        if (uprv_compareInvCharsAsAscii(DEPRECATEDLANGS[i], langtag->language) == 0) {
+            return DEPRECATEDLANGS[i + 1];
+        }
+    }
+    return langtag->language;
+}
+#endif
+
+static const char*
+ultag_getExtlang(const ULanguageTag* langtag, int32_t idx) {
+    if (idx >= 0 && idx < MAXEXTLANG) {
+        return langtag->extlang[idx];
+    }
+    return NULL;
+}
+
+static int32_t
+ultag_getExtlangSize(const ULanguageTag* langtag) {
+    int32_t size = 0;
+    int32_t i;
+    for (i = 0; i < MAXEXTLANG; i++) {
+        if (langtag->extlang[i]) {
+            size++;
+        }
+    }
+    return size;
+}
+
+static const char*
+ultag_getScript(const ULanguageTag* langtag) {
+    return langtag->script;
+}
+
+static const char*
+ultag_getRegion(const ULanguageTag* langtag) {
+    return langtag->region;
+}
+
+static const char*
+ultag_getVariant(const ULanguageTag* langtag, int32_t idx) {
+    const char *var = NULL;
+    VariantListEntry *cur = langtag->variants;
+    int32_t i = 0;
+    while (cur) {
+        if (i == idx) {
+            var = cur->variant;
+            break;
+        }
+        cur = cur->next;
+        i++;
+    }
+    return var;
+}
+
+static int32_t
+ultag_getVariantsSize(const ULanguageTag* langtag) {
+    int32_t size = 0;
+    VariantListEntry *cur = langtag->variants;
+    while (TRUE) {
+        if (cur == NULL) {
+            break;
+        }
+        size++;
+        cur = cur->next;
+    }
+    return size;
+}
+
+static const char*
+ultag_getExtensionKey(const ULanguageTag* langtag, int32_t idx) {
+    const char *key = NULL;
+    ExtensionListEntry *cur = langtag->extensions;
+    int32_t i = 0;
+    while (cur) {
+        if (i == idx) {
+            key = cur->key;
+            break;
+        }
+        cur = cur->next;
+        i++;
+    }
+    return key;
+}
+
+static const char*
+ultag_getExtensionValue(const ULanguageTag* langtag, int32_t idx) {
+    const char *val = NULL;
+    ExtensionListEntry *cur = langtag->extensions;
+    int32_t i = 0;
+    while (cur) {
+        if (i == idx) {
+            val = cur->value;
+            break;
+        }
+        cur = cur->next;
+        i++;
+    }
+    return val;
+}
+
+static int32_t
+ultag_getExtensionsSize(const ULanguageTag* langtag) {
+    int32_t size = 0;
+    ExtensionListEntry *cur = langtag->extensions;
+    while (TRUE) {
+        if (cur == NULL) {
+            break;
+        }
+        size++;
+        cur = cur->next;
+    }
+    return size;
+}
+
+static const char*
+ultag_getPrivateUse(const ULanguageTag* langtag) {
+    return langtag->privateuse;
+}
+
+#if 0
+static const char*
+ultag_getGrandfathered(const ULanguageTag* langtag) {
+    return langtag->grandfathered;
+}
+#endif
+
+
+/*
+* -------------------------------------------------
+*
+* Locale/BCP47 conversion APIs, exposed as uloc_*
+*
+* -------------------------------------------------
+*/
+U_DRAFT int32_t U_EXPORT2
+uloc_toLanguageTag(const char* localeID,
+                   char* langtag,
+                   int32_t langtagCapacity,
+                   UBool strict,
+                   UErrorCode* status) {
+    /* char canonical[ULOC_FULLNAME_CAPACITY]; */ /* See #6822 */
+    char canonical[256];
+    int32_t reslen = 0;
+    UErrorCode tmpStatus = U_ZERO_ERROR;
+    UBool hadPosix = FALSE;
+    const char* pKeywordStart;
+
+    /* Note: uloc_canonicalize returns "en_US_POSIX" for input locale ID "".  See #6835 */
+    canonical[0] = 0;
+    if (uprv_strlen(localeID) > 0) {
+        uloc_canonicalize(localeID, canonical, sizeof(canonical), &tmpStatus);
+        if (tmpStatus != U_ZERO_ERROR) {
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+            return 0;
+        }
+    }
+
+    /* For handling special case - private use only tag */
+    pKeywordStart = locale_getKeywordsStart(canonical);
+    if (pKeywordStart == canonical) {
+        UEnumeration *kwdEnum;
+        int kwdCnt = 0;
+        UBool done = FALSE;
+
+        kwdEnum = uloc_openKeywords((const char*)canonical, &tmpStatus);
+        if (kwdEnum != NULL) {
+            kwdCnt = uenum_count(kwdEnum, &tmpStatus);
+            if (kwdCnt == 1) {
+                const char *key;
+                int32_t len = 0;
+
+                key = uenum_next(kwdEnum, &len, &tmpStatus);
+                if (len == 1 && *key == PRIVATEUSE) {
+                    char buf[ULOC_KEYWORD_AND_VALUES_CAPACITY];
+                    buf[0] = PRIVATEUSE;
+                    buf[1] = SEP;
+                    len = uloc_getKeywordValue(localeID, key, &buf[2], sizeof(buf) - 2, &tmpStatus);
+                    if (U_SUCCESS(tmpStatus)) {
+                        if (_isPrivateuseValueSubtags(&buf[2], len)) {
+                            /* return private use only tag */
+                            reslen = len + 2;
+                            uprv_memcpy(langtag, buf, uprv_min(reslen, langtagCapacity));
+                            u_terminateChars(langtag, langtagCapacity, reslen, status);
+                            done = TRUE;
+                        } else if (strict) {
+                            *status = U_ILLEGAL_ARGUMENT_ERROR;
+                            done = TRUE;
+                        }
+                        /* if not strict mode, then "und" will be returned */
+                    } else {
+                        *status = U_ILLEGAL_ARGUMENT_ERROR;
+                        done = TRUE;
+                    }
+                }
+            }
+            uenum_close(kwdEnum);
+            if (done) {
+                return reslen;
+            }
+        }
+    }
+
+    reslen += _appendLanguageToLanguageTag(canonical, langtag, langtagCapacity, strict, status);
+    reslen += _appendScriptToLanguageTag(canonical, langtag + reslen, langtagCapacity - reslen, strict, status);
+    reslen += _appendRegionToLanguageTag(canonical, langtag + reslen, langtagCapacity - reslen, strict, status);
+    reslen += _appendVariantsToLanguageTag(canonical, langtag + reslen, langtagCapacity - reslen, strict, &hadPosix, status);
+    reslen += _appendKeywordsToLanguageTag(canonical, langtag + reslen, langtagCapacity - reslen, strict, hadPosix, status);
+
+    return reslen;
+}
+
+
+U_DRAFT int32_t U_EXPORT2
+uloc_forLanguageTag(const char* langtag,
+                    char* localeID,
+                    int32_t localeIDCapacity,
+                    int32_t* parsedLength,
+                    UErrorCode* status) {
+    ULanguageTag *lt;
+    int32_t reslen = 0;
+    const char *subtag, *p;
+    int32_t len;
+    int32_t i, n;
+    UBool noRegion = TRUE;
+
+    lt = ultag_parse(langtag, -1, parsedLength, status);
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+
+    /* language */
+    subtag = ultag_getExtlangSize(lt) > 0 ? ultag_getExtlang(lt, 0) : ultag_getLanguage(lt);
+    if (uprv_compareInvCharsAsAscii(subtag, LANG_UND) != 0) {
+        len = (int32_t)uprv_strlen(subtag);
+        if (len > 0) {
+            if (reslen < localeIDCapacity) {
+                uprv_memcpy(localeID, subtag, uprv_min(len, localeIDCapacity - reslen));
+            }
+            reslen += len;
+        }
+    }
+
+    /* script */
+    subtag = ultag_getScript(lt);
+    len = (int32_t)uprv_strlen(subtag);
+    if (len > 0) {
+        if (reslen < localeIDCapacity) {
+            *(localeID + reslen) = LOCALE_SEP;
+        }
+        reslen++;
+
+        /* write out the script in title case */
+        p = subtag;
+        while (*p) {
+            if (reslen < localeIDCapacity) {
+                if (p == subtag) {
+                    *(localeID + reslen) = uprv_toupper(*p);
+                } else {
+                    *(localeID + reslen) = *p;
+                }
+            }
+            reslen++;
+            p++;
+        }
+    }
+
+    /* region */
+    subtag = ultag_getRegion(lt);
+    len = (int32_t)uprv_strlen(subtag);
+    if (len > 0) {
+        if (reslen < localeIDCapacity) {
+            *(localeID + reslen) = LOCALE_SEP;
+        }
+        reslen++;
+        /* write out the retion in upper case */
+        p = subtag;
+        while (*p) {
+            if (reslen < localeIDCapacity) {
+                *(localeID + reslen) = uprv_toupper(*p);
+            }
+            reslen++;
+            p++;
+        }
+        noRegion = FALSE;
+    }
+
+    /* variants */
+    n = ultag_getVariantsSize(lt);
+    if (n > 0) {
+        if (noRegion) {
+            if (reslen < localeIDCapacity) {
+                *(localeID + reslen) = LOCALE_SEP;
+            }
+            reslen++;
+        }
+
+        for (i = 0; i < n; i++) {
+            subtag = ultag_getVariant(lt, i);
+            if (reslen < localeIDCapacity) {
+                *(localeID + reslen) = LOCALE_SEP;
+            }
+            reslen++;
+            /* write out the variant in upper case */
+            p = subtag;
+            while (*p) {
+                if (reslen < localeIDCapacity) {
+                    *(localeID + reslen) = uprv_toupper(*p);
+                }
+                reslen++;
+                p++;
+            }
+        }
+    }
+
+    /* keywords */
+    n = ultag_getExtensionsSize(lt);
+    subtag = ultag_getPrivateUse(lt);
+    if (n > 0 || uprv_strlen(subtag) > 0) {
+        if (reslen == 0 && n > 0) {
+            /* need a language */
+            if (reslen < localeIDCapacity) {
+                uprv_memcpy(localeID + reslen, LANG_UND, uprv_min(LANG_UND_LEN, localeIDCapacity - reslen));
+            }
+            reslen += LANG_UND_LEN;
+        }
+        len = _appendKeywords(lt, localeID + reslen, localeIDCapacity - reslen, status);
+        reslen += len;
+    }
+
+    ultag_close(lt);
+    return u_terminateChars(localeID, localeIDCapacity, reslen, status);
+}
+
+
diff --git a/source/common/ulocimp.h b/source/common/ulocimp.h
new file mode 100644
index 0000000..ebc525e
--- /dev/null
+++ b/source/common/ulocimp.h
@@ -0,0 +1,65 @@
+/*
+**********************************************************************
+*   Copyright (C) 2004-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+
+#ifndef ULOCIMP_H
+#define ULOCIMP_H
+
+#include "unicode/uloc.h"
+
+/**
+ * Create an iterator over the specified keywords list
+ * @param keywordList double-null terminated list. Will be copied.
+ * @param keywordListSize size in bytes of keywordList
+ * @param status err code
+ * @return enumeration (owned by caller) of the keyword list.
+ * @internal ICU 3.0
+ */
+U_CAPI UEnumeration* U_EXPORT2
+uloc_openKeywordList(const char *keywordList, int32_t keywordListSize, UErrorCode* status);
+
+/**
+ * Look up a resource bundle table item with fallback on the table level.
+ * This is accessible so it can be called by C++ code.
+ */
+U_CAPI const UChar * U_EXPORT2
+uloc_getTableStringWithFallback(
+    const char *path,
+    const char *locale,
+    const char *tableKey,
+    const char *subTableKey,
+    const char *itemKey,
+    int32_t *pLength,
+    UErrorCode *pErrorCode);
+
+/*returns TRUE if a is an ID separator FALSE otherwise*/
+#define _isIDSeparator(a) (a == '_' || a == '-')
+
+U_CFUNC const char* 
+uloc_getCurrentCountryID(const char* oldID);
+
+U_CFUNC const char* 
+uloc_getCurrentLanguageID(const char* oldID);
+
+U_CFUNC int32_t
+ulocimp_getLanguage(const char *localeID,
+                    char *language, int32_t languageCapacity,
+                    const char **pEnd);
+
+U_CFUNC int32_t
+ulocimp_getScript(const char *localeID,
+                   char *script, int32_t scriptCapacity,
+                   const char **pEnd);
+
+U_CFUNC int32_t
+ulocimp_getCountry(const char *localeID,
+                   char *country, int32_t countryCapacity,
+                   const char **pEnd);
+
+U_CAPI const char * U_EXPORT2
+locale_getKeywordsStart(const char *localeID);
+
+#endif
diff --git a/source/common/umapfile.c b/source/common/umapfile.c
new file mode 100644
index 0000000..f9f857e
--- /dev/null
+++ b/source/common/umapfile.c
@@ -0,0 +1,465 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************/
+
+
+/*----------------------------------------------------------------------------
+ *
+ *       Memory mapped file wrappers for use by the ICU Data Implementation
+ *       All of the platform-specific implementation for mapping data files
+ *         is here.  The rest of the ICU Data implementation uses only the
+ *         wrapper functions.
+ *
+ *----------------------------------------------------------------------------*/
+
+#include "unicode/putil.h"
+#include "udatamem.h"
+#include "umapfile.h"
+
+/* memory-mapping base definitions ------------------------------------------ */
+
+#if MAP_IMPLEMENTATION==MAP_WIN32
+#   define WIN32_LEAN_AND_MEAN
+#   define VC_EXTRALEAN
+#   define NOUSER
+#   define NOSERVICE
+#   define NOIME
+#   define NOMCX
+#   include <windows.h>
+#   include "cmemory.h"
+
+    typedef HANDLE MemoryMap;
+
+#   define IS_MAP(map) ((map)!=NULL)
+#elif MAP_IMPLEMENTATION==MAP_POSIX || MAP_IMPLEMENTATION==MAP_390DLL
+    typedef size_t MemoryMap;
+
+#   define IS_MAP(map) ((map)!=0)
+
+#   include <unistd.h>
+#   include <sys/mman.h>
+#   include <sys/stat.h>
+#   include <fcntl.h>
+
+#   ifndef MAP_FAILED
+#       define MAP_FAILED ((void*)-1)
+#   endif
+
+#   if MAP_IMPLEMENTATION==MAP_390DLL
+        /*   No memory mapping for 390 batch mode.  Fake it using dll loading.  */
+#       include <dll.h>
+#       include "cstring.h"
+#       include "cmemory.h"
+#       include "unicode/udata.h"
+#       define LIB_PREFIX "lib"
+#       define LIB_SUFFIX ".dll"
+        /* This is inconvienient until we figure out what to do with U_ICUDATA_NAME in utypes.h */
+#       define U_ICUDATA_ENTRY_NAME "icudt" U_ICU_VERSION_SHORT U_LIB_SUFFIX_C_NAME_STRING "_dat"
+#   else
+#       if defined(U_DARWIN)
+#           include <TargetConditionals.h>
+#       endif
+#   endif
+#elif MAP_IMPLEMENTATION==MAP_STDIO
+#   include <stdio.h>
+#   include "cmemory.h"
+
+    typedef void *MemoryMap;
+
+#   define IS_MAP(map) ((map)!=NULL)
+#endif
+
+/*----------------------------------------------------------------------------*
+ *                                                                            *
+ *   Memory Mapped File support.  Platform dependent implementation of        *
+ *                           functions used by the rest of the implementation.*
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+#if MAP_IMPLEMENTATION==MAP_NONE
+    U_CFUNC UBool
+    uprv_mapFile(UDataMemory *pData, const char *path) {
+        UDataMemory_init(pData); /* Clear the output struct. */
+        return FALSE;            /* no file access */
+    }
+
+    U_CFUNC void uprv_unmapFile(UDataMemory *pData) {
+        /* nothing to do */
+    }
+#elif MAP_IMPLEMENTATION==MAP_WIN32
+    U_CFUNC UBool
+    uprv_mapFile(
+         UDataMemory *pData,    /* Fill in with info on the result doing the mapping. */
+                                /*   Output only; any original contents are cleared.  */
+         const char *path       /* File path to be opened/mapped                      */
+         )
+    {
+        HANDLE map;
+        HANDLE file;
+        SECURITY_ATTRIBUTES mappingAttributes;
+        SECURITY_ATTRIBUTES *mappingAttributesPtr = NULL;
+        SECURITY_DESCRIPTOR securityDesc;
+
+        UDataMemory_init(pData); /* Clear the output struct.        */
+
+        /* open the input file */
+        file=CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL,
+            OPEN_EXISTING,
+            FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, NULL);
+        if(file==INVALID_HANDLE_VALUE) {
+            return FALSE;
+        }
+
+        /* Declare and initialize a security descriptor.
+           This is required for multiuser systems on Windows 2000 SP4 and beyond */
+        if (InitializeSecurityDescriptor(&securityDesc, SECURITY_DESCRIPTOR_REVISION)) {
+            /* give the security descriptor a Null Dacl done using the  "TRUE, (PACL)NULL" here	*/
+            if (SetSecurityDescriptorDacl(&securityDesc, TRUE, (PACL)NULL, FALSE)) {
+                /* Make the security attributes point to the security descriptor */
+                uprv_memset(&mappingAttributes, 0, sizeof(mappingAttributes));
+                mappingAttributes.nLength = sizeof(mappingAttributes);
+                mappingAttributes.lpSecurityDescriptor = &securityDesc;
+                mappingAttributes.bInheritHandle = FALSE; /* object uninheritable */
+                mappingAttributesPtr = &mappingAttributes;
+            }
+        }
+        /* else creating security descriptors can fail when we are on Windows 98,
+           and mappingAttributesPtr == NULL for that case. */
+
+        /* create an unnamed Windows file-mapping object for the specified file */
+        map=CreateFileMapping(file, mappingAttributesPtr, PAGE_READONLY, 0, 0, NULL);
+        CloseHandle(file);
+        if(map==NULL) {
+            return FALSE;
+        }
+
+        /* map a view of the file into our address space */
+        pData->pHeader=(const DataHeader *)MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
+        if(pData->pHeader==NULL) {
+            CloseHandle(map);
+            return FALSE;
+        }
+        pData->map=map;
+        return TRUE;
+    }
+
+    U_CFUNC void
+    uprv_unmapFile(UDataMemory *pData) {
+        if(pData!=NULL && pData->map!=NULL) {
+            UnmapViewOfFile(pData->pHeader);
+            CloseHandle(pData->map);
+            pData->pHeader=NULL;
+            pData->map=NULL;
+        }
+    }
+
+
+
+#elif MAP_IMPLEMENTATION==MAP_POSIX
+    U_CFUNC UBool
+    uprv_mapFile(UDataMemory *pData, const char *path) {
+        int fd;
+        int length;
+        struct stat mystat;
+        void *data;
+
+        UDataMemory_init(pData); /* Clear the output struct.        */
+
+        /* determine the length of the file */
+        if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
+            return FALSE;
+        }
+        length=mystat.st_size;
+
+        /* open the file */
+        fd=open(path, O_RDONLY);
+        if(fd==-1) {
+            return FALSE;
+        }
+
+        /* get a view of the mapping */
+#ifndef U_HPUX
+        data=mmap(0, length, PROT_READ, MAP_SHARED,  fd, 0);
+#else
+        data=mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0);
+#endif
+        close(fd); /* no longer needed */
+        if(data==MAP_FAILED) {
+            return FALSE;
+        }
+
+        pData->map = (char *)data + length;
+        pData->pHeader=(const DataHeader *)data;
+        pData->mapAddr = data;
+#if defined(U_DARWIN) && TARGET_OS_IPHONE
+        posix_madvise(data, length, POSIX_MADV_RANDOM);
+#endif
+        return TRUE;
+    }
+
+    U_CFUNC void
+    uprv_unmapFile(UDataMemory *pData) {
+        if(pData!=NULL && pData->map!=NULL) {
+            size_t dataLen = (char *)pData->map - (char *)pData->mapAddr;
+            if(munmap(pData->mapAddr, dataLen)==-1) {
+            }
+            pData->pHeader=NULL;
+            pData->map=0;
+            pData->mapAddr=NULL;
+        }
+    }
+
+
+
+#elif MAP_IMPLEMENTATION==MAP_STDIO
+    /* copy of the filestrm.c/T_FileStream_size() implementation */
+    static int32_t
+    umap_fsize(FILE *f) {
+        int32_t savedPos = ftell(f);
+        int32_t size = 0;
+
+        /*Changes by Bertrand A. D. doesn't affect the current position
+        goes to the end of the file before ftell*/
+        fseek(f, 0, SEEK_END);
+        size = (int32_t)ftell(f);
+        fseek(f, savedPos, SEEK_SET);
+        return size;
+    }
+
+    U_CFUNC UBool
+    uprv_mapFile(UDataMemory *pData, const char *path) {
+        FILE *file;
+        int32_t fileLength;
+        void *p;
+
+        UDataMemory_init(pData); /* Clear the output struct.        */
+        /* open the input file */
+        file=fopen(path, "rb");
+        if(file==NULL) {
+            return FALSE;
+        }
+
+        /* get the file length */
+        fileLength=umap_fsize(file);
+        if(ferror(file) || fileLength<=20) {
+            fclose(file);
+            return FALSE;
+        }
+
+        /* allocate the memory to hold the file data */
+        p=uprv_malloc(fileLength);
+        if(p==NULL) {
+            fclose(file);
+            return FALSE;
+        }
+
+        /* read the file */
+        if(fileLength!=fread(p, 1, fileLength, file)) {
+            uprv_free(p);
+            fclose(file);
+            return FALSE;
+        }
+
+        fclose(file);
+        pData->map=p;
+        pData->pHeader=(const DataHeader *)p;
+        pData->mapAddr=p;
+        return TRUE;
+    }
+
+    U_CFUNC void
+    uprv_unmapFile(UDataMemory *pData) {
+        if(pData!=NULL && pData->map!=NULL) {
+            uprv_free(pData->map);
+            pData->map     = NULL;
+            pData->mapAddr = NULL;
+            pData->pHeader = NULL;
+        }
+    }
+
+
+#elif MAP_IMPLEMENTATION==MAP_390DLL
+    /*  390 specific Library Loading.
+     *  This is the only platform left that dynamically loads an ICU Data Library.
+     *  All other platforms use .data files when dynamic loading is required, but
+     *  this turn out to be awkward to support in 390 batch mode.
+     *
+     *  The idea here is to hide the fact that 390 is using dll loading from the
+     *   rest of ICU, and make it look like there is file loading happening.
+     *
+     */
+
+    static char *strcpy_returnEnd(char *dest, const char *src)
+    {
+        while((*dest=*src)!=0) {
+            ++dest;
+            ++src;
+        }
+        return dest;
+    }
+    
+    /*------------------------------------------------------------------------------
+     *                                                                              
+     *  computeDirPath   given a user-supplied path of an item to be opened,             
+     *                         compute and return 
+     *                            - the full directory path to be used 
+     *                              when opening the file.
+     *                            - Pointer to null at end of above returned path    
+     *
+     *                       Parameters:
+     *                          path:        input path.  Buffer is not altered.
+     *                          pathBuffer:  Output buffer.  Any contents are overwritten.
+     *
+     *                       Returns:
+     *                          Pointer to null termination in returned pathBuffer.
+     *
+     *                    TODO:  This works the way ICU historically has, but the
+     *                           whole data fallback search path is so complicated that
+     *                           proabably almost no one will ever really understand it,
+     *                           the potential for confusion is large.  (It's not just 
+     *                           this one function, but the whole scheme.)
+     *                            
+     *------------------------------------------------------------------------------*/
+    static char *uprv_computeDirPath(const char *path, char *pathBuffer)
+    {
+        char   *finalSlash;       /* Ptr to last dir separator in input path, or null if none. */
+        int32_t pathLen;          /* Length of the returned directory path                     */
+        
+        finalSlash = 0;
+        if (path != 0) {
+            finalSlash = uprv_strrchr(path, U_FILE_SEP_CHAR);
+        }
+        
+        *pathBuffer = 0;
+        if (finalSlash == 0) {
+        /* No user-supplied path.  
+            * Copy the ICU_DATA path to the path buffer and return that*/
+            const char *icuDataDir;
+            icuDataDir=u_getDataDirectory();
+            if(icuDataDir!=NULL && *icuDataDir!=0) {
+                return strcpy_returnEnd(pathBuffer, icuDataDir);
+            } else {
+                /* there is no icuDataDir either.  Just return the empty pathBuffer. */
+                return pathBuffer;
+            }
+        } 
+        
+        /* User supplied path did contain a directory portion.
+        * Copy it to the output path buffer */
+        pathLen = (int32_t)(finalSlash - path + 1);
+        uprv_memcpy(pathBuffer, path, pathLen);
+        *(pathBuffer+pathLen) = 0;
+        return pathBuffer+pathLen;
+    }
+    
+
+#   define DATA_TYPE "dat"
+
+    U_CFUNC UBool uprv_mapFile(UDataMemory *pData, const char *path) {
+        const char *inBasename;
+        char *basename;
+        char pathBuffer[1024];
+        const DataHeader *pHeader;
+        dllhandle *handle;
+        void *val=0;
+
+        inBasename=uprv_strrchr(path, U_FILE_SEP_CHAR);
+        if(inBasename==NULL) {
+            inBasename = path;
+        } else {
+            inBasename++;
+        }
+        basename=uprv_computeDirPath(path, pathBuffer);
+        if(uprv_strcmp(inBasename, U_ICUDATA_NAME".dat") != 0) {
+            /* must mmap file... for build */
+            int fd;
+            int length;
+            struct stat mystat;
+            void *data;
+            UDataMemory_init(pData); /* Clear the output struct. */
+
+            /* determine the length of the file */
+            if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
+                return FALSE;
+            }
+            length=mystat.st_size;
+
+            /* open the file */
+            fd=open(path, O_RDONLY);
+            if(fd==-1) {
+                return FALSE;
+            }
+
+            /* get a view of the mapping */
+            data=mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0);
+            close(fd); /* no longer needed */
+            if(data==MAP_FAILED) {
+                return FALSE;
+            }
+            pData->map = (char *)data + length;
+            pData->pHeader=(const DataHeader *)data;
+            pData->mapAddr = data;
+            return TRUE;
+        }
+
+#       ifdef OS390BATCH
+            /* ### hack: we still need to get u_getDataDirectory() fixed
+            for OS/390 (batch mode - always return "//"? )
+            and this here straightened out with LIB_PREFIX and LIB_SUFFIX (both empty?!)
+            This is probably due to the strange file system on OS/390.  It's more like
+            a database with short entry names than a typical file system. */
+            /* U_ICUDATA_NAME should always have the correct name */
+            /* BUT FOR BATCH MODE IT IS AN EXCEPTION BECAUSE */
+            /* THE FIRST THREE LETTERS ARE PREASSIGNED TO THE */
+            /* PROJECT!!!!! */
+            uprv_strcpy(pathBuffer, "IXMI" U_ICU_VERSION_SHORT "DA");
+#       else
+            /* set up the library name */
+            uprv_strcpy(basename, LIB_PREFIX U_LIBICUDATA_NAME U_ICU_VERSION_SHORT LIB_SUFFIX);
+#       endif
+
+#       ifdef UDATA_DEBUG
+             fprintf(stderr, "dllload: %s ", pathBuffer);
+#       endif
+
+        handle=dllload(pathBuffer);
+
+#       ifdef UDATA_DEBUG
+               fprintf(stderr, " -> %08X\n", handle );
+#       endif
+
+        if(handle != NULL) {
+               /* we have a data DLL - what kind of lookup do we need here? */
+               /* try to find the Table of Contents */
+               UDataMemory_init(pData); /* Clear the output struct.        */
+               val=dllqueryvar((dllhandle*)handle, U_ICUDATA_ENTRY_NAME);
+               if(val == 0) {
+                    /* failed... so keep looking */
+                    return FALSE;
+               }
+#              ifdef UDATA_DEBUG
+                    fprintf(stderr, "dllqueryvar(%08X, %s) -> %08X\n", handle, U_ICUDATA_ENTRY_NAME, val);
+#              endif
+
+               pData->pHeader=(const DataHeader *)val;
+               return TRUE;
+         } else {
+               return FALSE; /* no handle */
+         }
+    }
+
+    U_CFUNC void uprv_unmapFile(UDataMemory *pData) {
+        if(pData!=NULL && pData->map!=NULL) {
+            uprv_free(pData->map);
+            pData->map     = NULL;
+            pData->mapAddr = NULL;
+            pData->pHeader = NULL;
+        }   
+    }
+
+#else
+#   error MAP_IMPLEMENTATION is set incorrectly
+#endif
diff --git a/source/common/umapfile.h b/source/common/umapfile.h
new file mode 100644
index 0000000..f8bf77b
--- /dev/null
+++ b/source/common/umapfile.h
@@ -0,0 +1,54 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************/
+
+/*----------------------------------------------------------------------------------
+ *
+ *       Memory mapped file wrappers for use by the ICU Data Implementation
+ *
+ *           Porting note:  The implementation of these functions is very platform specific.
+ *             Not all platforms can do real memory mapping.  Those that can't
+ *             still must implement these functions, getting the data into memory using
+ *             whatever means are available.
+ *
+ *            These functions are part of the ICU internal implementation, and
+ *            are not inteded to be used directly by applications.
+ *
+ *----------------------------------------------------------------------------------*/
+
+#ifndef __UMAPFILE_H__
+#define __UMAPFILE_H__
+
+#include "unicode/putil.h"
+#include "unicode/udata.h"
+
+U_CFUNC UBool uprv_mapFile(UDataMemory *pdm, const char *path);
+U_CFUNC void  uprv_unmapFile(UDataMemory *pData);
+
+/* MAP_NONE: no memory mapping, no file access at all */
+#define MAP_NONE        0
+#define MAP_WIN32       1
+#define MAP_POSIX       2
+#define MAP_STDIO       3
+#define MAP_390DLL      4
+
+#if UCONFIG_NO_FILE_IO
+#   define MAP_IMPLEMENTATION MAP_NONE
+#elif defined(U_WINDOWS)
+#   define MAP_IMPLEMENTATION MAP_WIN32
+#elif U_HAVE_MMAP || defined(OS390)
+#   if defined(OS390) && defined (OS390_STUBDATA)
+        /*   No memory mapping for 390 batch mode.  Fake it using dll loading.  */
+#       define MAP_IMPLEMENTATION MAP_390DLL
+#   else
+#       define MAP_IMPLEMENTATION MAP_POSIX
+#   endif
+#else /* unknown platform, no memory map implementation: use stdio.h and uprv_malloc() instead */
+#   define MAP_IMPLEMENTATION MAP_STDIO
+#endif
+
+#endif
diff --git a/source/common/umath.c b/source/common/umath.c
new file mode 100644
index 0000000..4a57114
--- /dev/null
+++ b/source/common/umath.c
@@ -0,0 +1,24 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1997-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+* This file contains platform independent math.
+*/
+
+#include "putilimp.h"
+
+U_CAPI int32_t U_EXPORT2
+uprv_max(int32_t x, int32_t y)
+{
+    return (x > y ? x : y);
+}
+
+U_CAPI int32_t U_EXPORT2
+uprv_min(int32_t x, int32_t y)
+{
+    return (x > y ? y : x);
+}
+
diff --git a/source/common/umutex.c b/source/common/umutex.c
new file mode 100644
index 0000000..0226a8a
--- /dev/null
+++ b/source/common/umutex.c
@@ -0,0 +1,635 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1997-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File umutex.c
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   04/02/97    aliu        Creation.
+*   04/07/99    srl         updated
+*   05/13/99    stephen     Changed to umutex (from cmutex).
+*   11/22/99    aliu        Make non-global mutex autoinitialize [j151]
+******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+#include "uassert.h"
+#include "ucln_cmn.h"
+
+/*
+ * ICU Mutex wrappers.  Wrap operating system mutexes, giving the rest of ICU a
+ * platform independent set of mutex operations.  For internal ICU use only.
+ */
+
+#if defined(U_DARWIN)
+#include <AvailabilityMacros.h>
+#if (ICU_USE_THREADS == 1) && defined(MAC_OS_X_VERSION_10_4) && defined(MAC_OS_X_VERSION_MIN_REQUIRED) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
+#if defined(__STRICT_ANSI__)
+#define UPRV_REMAP_INLINE
+#define inline
+#endif
+#include <libkern/OSAtomic.h>
+#define USE_MAC_OS_ATOMIC_INCREMENT 1
+#if defined(UPRV_REMAP_INLINE)
+#undef inline
+#undef UPRV_REMAP_INLINE
+#endif
+#endif
+#endif
+
+/* Assume POSIX, and modify as necessary below */
+#define POSIX
+
+#if defined(U_WINDOWS)
+#undef POSIX
+#endif
+#if defined(macintosh)
+#undef POSIX
+#endif
+#if defined(OS2)
+#undef POSIX
+#endif
+
+#if defined(POSIX) && (ICU_USE_THREADS==1)
+# include <pthread.h> /* must be first, so that we get the multithread versions of things. */
+
+#endif /* POSIX && (ICU_USE_THREADS==1) */
+
+#ifdef U_WINDOWS
+# define WIN32_LEAN_AND_MEAN
+# define VC_EXTRALEAN
+# define NOUSER
+# define NOSERVICE
+# define NOIME
+# define NOMCX
+# include <windows.h>
+#endif
+
+#include "umutex.h"
+#include "cmemory.h"
+
+/*
+ * A note on ICU Mutex Initialization and ICU startup:
+ *
+ *   ICU mutexes, as used through the rest of the ICU code, are self-initializing.
+ *   To make this work, ICU uses the _ICU GLobal Mutex_ to synchronize the lazy init
+ *   of other ICU mutexes.  For the global mutex itself, we need some other mechanism
+ *   to safely initialize it on first use.  This becomes important when two or more
+ *   threads are more or less simultaenously the first to use ICU in a process, and
+ *   are racing into the mutex initialization code.
+ *
+ *
+ *   The solution for the global mutex init is platform dependent.
+ *   On POSIX systems, plain C-style initialization can be used on a mutex, with the 
+ *   macro PTHREAD_MUTEX_INITIALIZER.  The mutex is then ready for use, without
+ *   first calling pthread_mutex_init().
+ *
+ *   Windows has no equivalent statically initialized mutex or CRITICAL SECION.
+ *   InitializeCriticalSection() must be called.  If the global mutex does not
+ *   appear to be initialized, a thread will create and initialize a new
+ *   CRITICAL_SECTION, then use a Windows InterlockedCompareAndExchange to
+ *   swap it in as the global mutex while avoid problems with race conditions.
+ */ 
+
+/* On WIN32 mutexes are reentrant.  On POSIX platforms they are not, and a deadlock
+ *  will occur if a thread attempts to acquire a mutex it already has locked.
+ *  ICU mutexes (in debug builds) include checking code that will cause an assertion
+ *  failure if a mutex is reentered.  If you are having deadlock problems
+ *  on a POSIX machine, debugging may be easier on Windows.
+ */
+
+
+#if (ICU_USE_THREADS == 0)
+#define MUTEX_TYPE void *
+#define PLATFORM_MUTEX_INIT(m) 
+#define PLATFORM_MUTEX_LOCK(m) 
+#define PLATFORM_MUTEX_UNLOCK(m) 
+#define PLATFORM_MUTEX_DESTROY(m) 
+#define PLATFORM_MUTEX_INITIALIZER NULL
+#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
+            mutexed_compare_and_swap(dest, newval, oldval)
+
+
+#elif defined(U_WINDOWS)
+#define MUTEX_TYPE CRITICAL_SECTION
+#define PLATFORM_MUTEX_INIT(m) InitializeCriticalSection(m)
+#define PLATFORM_MUTEX_LOCK(m) EnterCriticalSection(m)
+#define PLATFORM_MUTEX_UNLOCK(m) LeaveCriticalSection(m)
+#define PLATFORM_MUTEX_DESTROY(m) DeleteCriticalSection(m)
+#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
+            InterlockedCompareExchangePointer(dest, newval, oldval)
+
+
+#elif defined(POSIX)
+#define MUTEX_TYPE pthread_mutex_t   
+#define PLATFORM_MUTEX_INIT(m) pthread_mutex_init(m, NULL)
+#define PLATFORM_MUTEX_LOCK(m) pthread_mutex_lock(m)
+#define PLATFORM_MUTEX_UNLOCK(m) pthread_mutex_unlock(m)
+#define PLATFORM_MUTEX_DESTROY(m) pthread_mutex_destroy(m)
+#define PLATFORM_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#if (U_HAVE_GCC_ATOMICS == 1)
+#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
+            __sync_val_compare_and_swap(dest, oldval, newval)
+#else
+#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
+            mutexed_compare_and_swap(dest, newval, oldval)
+#endif
+
+
+#else   
+/* Unknown platform.  Note that user can still set mutex functions at run time. */
+#define MUTEX_TYPE void *
+#define PLATFORM_MUTEX_INIT(m) 
+#define PLATFORM_MUTEX_LOCK(m)
+#define PLATFORM_MUTEX_UNLOCK(m) 
+#define PLATFORM_MUTEX_DESTROY(m) 
+#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
+            mutexed_compare_and_swap(dest, newval, oldval)
+
+#endif
+
+/*  Forward declarations */
+static void *mutexed_compare_and_swap(void **dest, void *newval, void *oldval);
+typedef struct ICUMutex ICUMutex;
+
+/*
+ * ICUMutex   One of these is set up for each UMTX that is used by other ICU code.
+ *            The opaque UMTX points to the corresponding ICUMutex struct.
+ *            
+ *            Because the total number of ICU mutexes is quite small, no effort has
+ *            been made to squeeze every byte out of this struct.
+ */
+struct ICUMutex {
+    UMTX        *owner;             /* Points back to the UMTX corrsponding to this   */
+                                    /*    ICUMutex object.                            */
+    
+    UBool        heapAllocated;     /* Set if this ICUMutex is heap allocated, and    */
+                                    /*   will need to be deleted.  The global mutex   */
+                                    /*   is static on POSIX platforms; all others     */
+                                    /*   will be heap allocated.                      */
+
+    ICUMutex    *next;              /* All ICUMutexes are chained into a list so that  */
+                                    /*   they can be found and deleted by u_cleanup(). */
+
+    int32_t      recursionCount;    /* For debugging, detect recursive mutex locks.    */
+
+    MUTEX_TYPE   platformMutex;     /* The underlying OS mutex being wrapped.          */
+
+    UMTX         userMutex;         /* For use with u_setMutexFunctions operations,    */
+                                    /*    corresponds to platformMutex.                */
+};
+
+
+/*   The global ICU mutex.
+ *   For POSIX platforms, it gets a C style initialization, and is ready to use
+ *        at program startup.
+ *   For Windows, it will be lazily instantiated on first use.
+ */
+
+#if defined(POSIX)
+static UMTX  globalUMTX;
+static ICUMutex globalMutex = {&globalUMTX, FALSE, NULL, 0, PLATFORM_MUTEX_INITIALIZER, NULL};
+static UMTX  globalUMTX = &globalMutex;
+#else
+static UMTX  globalUMTX = NULL;
+#endif
+
+/* Head of the list of all ICU mutexes.
+ * Linked list is through ICUMutex::next
+ * Modifications to the list are synchronized with the global mutex.
+ * The list is used by u_cleanup(), which needs to dispose of all of the ICU mutexes.
+ *
+ * The statically initialized global mutex on POSIX platforms does not get added to this
+ * mutex list, but that's not a problem - the global mutex gets special handling
+ * during u_cleanup().
+ */
+static ICUMutex *mutexListHead;
+
+
+/*
+ *  User mutex implementation functions.  If non-null, call back to these rather than
+ *  directly using the system (Posix or Windows) APIs.  See u_setMutexFunctions().
+ *    (declarations are in uclean.h)
+ */
+static UMtxInitFn    *pMutexInitFn    = NULL;
+static UMtxFn        *pMutexDestroyFn = NULL;
+static UMtxFn        *pMutexLockFn    = NULL;
+static UMtxFn        *pMutexUnlockFn  = NULL;
+static const void    *gMutexContext   = NULL;
+
+
+/*
+ *   umtx_lock
+ */
+U_CAPI void  U_EXPORT2
+umtx_lock(UMTX *mutex)
+{
+    ICUMutex *m;
+
+    if (mutex == NULL) {
+        mutex = &globalUMTX;
+    }
+    m = (ICUMutex *)*mutex;
+    if (m == NULL) {
+        /* See note on lazy initialization, above.  We can get away with it here, with mutexes,
+         * where we couldn't with normal user level data.
+         */
+        umtx_init(mutex);    
+        m = (ICUMutex *)*mutex;
+    }
+    U_ASSERT(m->owner == mutex);
+
+    if (pMutexLockFn != NULL) {
+        (*pMutexLockFn)(gMutexContext, &m->userMutex);
+    } else {
+        PLATFORM_MUTEX_LOCK(&m->platformMutex);
+    }
+
+#if defined(U_DEBUG)
+    m->recursionCount++;              /* Recursion causes deadlock on Unixes.               */
+    U_ASSERT(m->recursionCount == 1); /* Recursion detection works on Windows.              */
+                                      /* Assertion failure on non-Windows indicates a       */
+                                      /*   problem with the mutex implementation itself.    */
+#endif
+}
+
+
+
+/*
+ * umtx_unlock
+ */
+U_CAPI void  U_EXPORT2
+umtx_unlock(UMTX* mutex)
+{
+    ICUMutex *m;
+    if(mutex == NULL) {
+        mutex = &globalUMTX;
+    }
+    m = (ICUMutex *)*mutex;
+    if (m == NULL) {
+        U_ASSERT(FALSE);  /* This mutex is not initialized.     */
+        return; 
+    }
+    U_ASSERT(m->owner == mutex);
+
+#if defined (U_DEBUG)
+    m->recursionCount--;
+    U_ASSERT(m->recursionCount == 0);  /* Detect unlock of an already unlocked mutex */
+#endif
+
+    if (pMutexUnlockFn) {
+        (*pMutexUnlockFn)(gMutexContext, &m->userMutex);
+    } else {
+        PLATFORM_MUTEX_UNLOCK(&m->platformMutex);
+    }
+}
+
+
+/* umtx_ct   Allocate and initialize a new ICUMutex.
+ *           If a non-null pointer is supplied, initialize an existing ICU Mutex.
+ */
+static ICUMutex *umtx_ct(ICUMutex *m) {
+    if (m == NULL) {
+        m = (ICUMutex *)uprv_malloc(sizeof(ICUMutex));
+        m->heapAllocated = TRUE;
+    }
+    m->next = NULL;    /* List of mutexes is maintained at a higher level.  */
+    m->recursionCount = 0;
+    m->userMutex = NULL;
+    if (pMutexInitFn != NULL) {
+        UErrorCode status = U_ZERO_ERROR;
+        (*pMutexInitFn)(gMutexContext, &m->userMutex, &status);
+        U_ASSERT(U_SUCCESS(status));
+    } else {
+        PLATFORM_MUTEX_INIT(&m->platformMutex);
+    }
+    return m;
+}
+
+
+/* umtx_dt   Delete a ICUMutex.  Destroy the underlying OS Platform mutex.
+ *           Does not touch the linked list of ICU Mutexes.
+ */
+static void umtx_dt(ICUMutex *m) {
+    if (pMutexDestroyFn != NULL) {
+        (*pMutexDestroyFn)(gMutexContext, &m->userMutex);
+        m->userMutex = NULL;
+    } else {
+        PLATFORM_MUTEX_DESTROY(&m->platformMutex);
+    }
+
+    if (m->heapAllocated) {
+        uprv_free(m);
+    }
+}
+    
+
+U_CAPI void  U_EXPORT2
+umtx_init(UMTX *mutex) {
+    ICUMutex *m = NULL;
+    void *originalValue;
+
+    if (*mutex != NULL) {
+        /* Mutex is already initialized.  
+         * Multiple umtx_init()s of a UMTX by other ICU code are explicitly permitted.
+         */
+        return;
+    }
+#if defined(POSIX)
+    if (mutex == &globalUMTX) {
+        m = &globalMutex;
+    }
+#endif
+
+    m = umtx_ct(m);
+    originalValue = SYNC_COMPARE_AND_SWAP(mutex, NULL, m);
+    if (originalValue != NULL) {
+        umtx_dt(m);
+        return;
+    }
+
+    m->owner = mutex;
+
+    /* Hook the new mutex into the list of all ICU mutexes, so that we can find and
+     * delete it for u_cleanup().
+     */
+
+    umtx_lock(NULL);
+    m->next = mutexListHead;
+    mutexListHead = m;
+    umtx_unlock(NULL);
+    return;
+}
+
+
+/*
+ *  umtx_destroy.    Un-initialize a mutex, releasing any underlying resources
+ *                   that it may be holding.  Destroying an already destroyed
+ *                   mutex has no effect.  Unlike umtx_init(), this function
+ *                   is not thread safe;  two threads must not concurrently try to
+ *                   destroy the same mutex.
+ */                  
+U_CAPI void  U_EXPORT2
+umtx_destroy(UMTX *mutex) {
+    ICUMutex *m;
+    
+    /* No one should be deleting the global ICU mutex. 
+     *   (u_cleanup() does delete it, but does so explicitly, not by passing NULL)
+     */
+    U_ASSERT(mutex != NULL);
+    if (mutex == NULL) { 
+        return;
+    }
+    
+    m = (ICUMutex *)*mutex;
+    if (m == NULL) {  /* Mutex not initialized, or already destroyed.  */
+        return;
+    }
+
+    U_ASSERT(m->owner == mutex);
+    if (m->owner != mutex) {
+        return;
+    }
+
+    /* Remove this mutex from the linked list of mutexes.  */
+    umtx_lock(NULL);
+    if (mutexListHead == m) {
+        mutexListHead = m->next;
+    } else {
+        ICUMutex *prev;
+        for (prev = mutexListHead; prev!=NULL && prev->next!=m; prev = prev->next);
+            /*  Empty for loop body */
+        if (prev != NULL) {
+            prev->next = m->next;
+        }
+    }
+    umtx_unlock(NULL);
+
+    umtx_dt(m);        /* Delete the internal ICUMutex   */
+    *mutex = NULL;     /* Clear the caller's UMTX        */
+}
+
+
+
+U_CAPI void U_EXPORT2 
+u_setMutexFunctions(const void *context, UMtxInitFn *i, UMtxFn *d, UMtxFn *l, UMtxFn *u,
+                    UErrorCode *status) {
+    if (U_FAILURE(*status)) {
+        return;
+    }
+
+    /* Can not set a mutex function to a NULL value  */
+    if (i==NULL || d==NULL || l==NULL || u==NULL) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    /* If ICU is not in an initial state, disallow this operation. */
+    if (cmemory_inUse()) {
+        *status = U_INVALID_STATE_ERROR;
+        return;
+    }
+    
+    /* Kill any existing global mutex.  POSIX platforms have a global mutex
+     * even before any other part of ICU is initialized.
+     */
+    umtx_destroy(&globalUMTX);
+
+    /* Swap in the mutex function pointers.  */
+    pMutexInitFn    = i;
+    pMutexDestroyFn = d;
+    pMutexLockFn    = l;
+    pMutexUnlockFn  = u;
+    gMutexContext   = context;
+
+#if defined (POSIX) 
+    /* POSIX platforms must have a pre-initialized global mutex 
+     * to allow other mutexes to initialize safely. */
+    umtx_init(&globalUMTX);
+#endif
+}
+
+
+/*   synchronized compare and swap function, for use when OS or compiler built-in
+ *   equivalents aren't available.
+ *
+ *   This operation relies on the ICU global mutex for synchronization.
+ *
+ *   There are two cases where this function can be entered when the global mutex is not
+ *   yet initialized - at the end  u_cleanup(), and at the end of u_setMutexFunctions, both
+ *   of which re-init the global mutex.  But neither function is thread-safe, so the lack of
+ *   synchronization at these points doesn't matter.
+ */
+static void *mutexed_compare_and_swap(void **dest, void *newval, void *oldval) {
+    void *temp;
+    UBool needUnlock = FALSE;
+
+    if (globalUMTX != NULL) {
+        umtx_lock(&globalUMTX);
+        needUnlock = TRUE;
+    }
+
+    temp = *dest;
+    if (temp == oldval) {
+        *dest = newval;
+    }
+    
+    if (needUnlock) {
+        umtx_unlock(&globalUMTX);
+    }
+    return temp;
+}
+
+
+
+/*-----------------------------------------------------------------
+ *
+ *  Atomic Increment and Decrement
+ *     umtx_atomic_inc
+ *     umtx_atomic_dec
+ *
+ *----------------------------------------------------------------*/
+
+/* Pointers to user-supplied inc/dec functions.  Null if no funcs have been set.  */
+static UMtxAtomicFn  *pIncFn = NULL;
+static UMtxAtomicFn  *pDecFn = NULL;
+static const void *gIncDecContext  = NULL;
+
+static UMTX    gIncDecMutex = NULL;
+
+U_CAPI int32_t U_EXPORT2
+umtx_atomic_inc(int32_t *p)  {
+    int32_t retVal;
+    if (pIncFn) {
+        retVal = (*pIncFn)(gIncDecContext, p);
+    } else {
+        #if defined (U_WINDOWS) && ICU_USE_THREADS == 1
+            retVal = InterlockedIncrement((LONG*)p);
+        #elif defined(USE_MAC_OS_ATOMIC_INCREMENT)
+            retVal = OSAtomicIncrement32Barrier(p);
+        #elif (U_HAVE_GCC_ATOMICS == 1)
+            retVal = __sync_add_and_fetch(p, 1);
+        #elif defined (POSIX) && ICU_USE_THREADS == 1
+            umtx_lock(&gIncDecMutex);
+            retVal = ++(*p);
+            umtx_unlock(&gIncDecMutex);
+        #else
+            /* Unknown Platform, or ICU thread support compiled out. */
+            retVal = ++(*p);
+        #endif
+    }
+    return retVal;
+}
+
+U_CAPI int32_t U_EXPORT2
+umtx_atomic_dec(int32_t *p) {
+    int32_t retVal;
+    if (pDecFn) {
+        retVal = (*pDecFn)(gIncDecContext, p);
+    } else {
+        #if defined (U_WINDOWS) && ICU_USE_THREADS == 1
+            retVal = InterlockedDecrement((LONG*)p);
+        #elif defined(USE_MAC_OS_ATOMIC_INCREMENT)
+            retVal = OSAtomicDecrement32Barrier(p);
+        #elif (U_HAVE_GCC_ATOMICS == 1)
+            retVal = __sync_sub_and_fetch(p, 1);
+        #elif defined (POSIX) && ICU_USE_THREADS == 1
+            umtx_lock(&gIncDecMutex);
+            retVal = --(*p);
+            umtx_unlock(&gIncDecMutex);
+        #else
+            /* Unknown Platform, or ICU thread support compiled out. */
+            retVal = --(*p);
+        #endif
+    }
+    return retVal;
+}
+
+
+
+U_CAPI void U_EXPORT2
+u_setAtomicIncDecFunctions(const void *context, UMtxAtomicFn *ip, UMtxAtomicFn *dp,
+                                UErrorCode *status) {
+    if (U_FAILURE(*status)) {
+        return;
+    }
+    /* Can not set a mutex function to a NULL value  */
+    if (ip==NULL || dp==NULL) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    /* If ICU is not in an initial state, disallow this operation. */
+    if (cmemory_inUse()) {
+        *status = U_INVALID_STATE_ERROR;
+        return;
+    }
+
+    pIncFn = ip;
+    pDecFn = dp;
+    gIncDecContext = context;
+
+#if !U_RELEASE
+    {
+        int32_t   testInt = 0;
+        U_ASSERT(umtx_atomic_inc(&testInt) == 1);     /* Sanity Check.    Do the functions work at all? */
+        U_ASSERT(testInt == 1);
+        U_ASSERT(umtx_atomic_dec(&testInt) == 0);
+        U_ASSERT(testInt == 0);
+    }
+#endif
+}
+
+
+
+/*
+ *  Mutex Cleanup Function
+ *
+ *      Destroy the global mutex(es), and reset the mutex function callback pointers.
+ */
+U_CFUNC UBool umtx_cleanup(void) {
+    ICUMutex *thisMutex = NULL;
+    ICUMutex *nextMutex = NULL;
+
+    /* Extra, do-nothing function call to suppress compiler warnings on platforms where
+     *   mutexed_compare_and_swap is not otherwise used.  */
+    mutexed_compare_and_swap(&globalUMTX, NULL, NULL);
+
+    /* Delete all of the ICU mutexes.  Do the global mutex last because it is used during
+     * the umtx_destroy operation of other mutexes.
+     */
+    for (thisMutex=mutexListHead; thisMutex!=NULL; thisMutex=nextMutex) {
+        UMTX *umtx = thisMutex->owner;
+        nextMutex = thisMutex->next;
+        U_ASSERT(*umtx = (void *)thisMutex);
+        if (umtx != &globalUMTX) {
+            umtx_destroy(umtx);
+        }
+    }
+    umtx_destroy(&globalUMTX);
+        
+    pMutexInitFn    = NULL;
+    pMutexDestroyFn = NULL;
+    pMutexLockFn    = NULL;
+    pMutexUnlockFn  = NULL;
+    gMutexContext   = NULL;
+    pIncFn          = NULL;
+    pDecFn          = NULL;
+    gIncDecContext  = NULL;
+    gIncDecMutex    = NULL;
+
+#if defined (POSIX) 
+    /* POSIX platforms must come out of u_cleanup() with a functioning global mutex 
+     * to permit the safe resumption of use of ICU in multi-threaded environments. 
+     */
+    umtx_init(&globalUMTX);
+#endif
+    return TRUE;
+}
+
+
diff --git a/source/common/umutex.h b/source/common/umutex.h
new file mode 100644
index 0000000..9336fe8
--- /dev/null
+++ b/source/common/umutex.h
@@ -0,0 +1,150 @@
+/*
+**********************************************************************
+*   Copyright (C) 1997-2008, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*
+* File UMUTEX.H
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   04/02/97  aliu        Creation.
+*   04/07/99  srl         rewrite - C interface, multiple mutices
+*   05/13/99  stephen     Changed to umutex (from cmutex)
+******************************************************************************
+*/
+
+#ifndef UMUTEX_H
+#define UMUTEX_H
+
+#include "unicode/utypes.h"
+#include "unicode/uclean.h"  
+
+
+/* APP_NO_THREADS is an old symbol. We'll honour it if present. */
+#ifdef APP_NO_THREADS
+# define ICU_USE_THREADS 0
+#endif
+
+/* ICU_USE_THREADS
+ *
+ *   Allows thread support (use of mutexes) to be compiled out of ICU.
+ *   Default: use threads.
+ *   Even with thread support compiled out, applications may override the
+ *   (empty) mutex implementation with the u_setMutexFunctions() functions.
+ */ 
+#ifndef ICU_USE_THREADS
+# define ICU_USE_THREADS 1
+#endif
+
+/**
+ * By default assume that we are on a machine with a weak memory model,
+ * and the double check lock won't work reliably.
+ */
+#if !defined(UMTX_STRONG_MEMORY_MODEL)
+#define UMTX_STRONG_MEMORY_MODEL 0
+#endif
+
+/**
+ * \def UMTX_CHECK
+ * Encapsulates a safe check of an expression 
+ * for use with double-checked lazy inititialization.
+ * On CPUs with weak memory models, this must use memory fence instructions
+ * or mutexes.
+ * The expression must involve only a  _single_ variable, typically
+ *    a possibly null pointer or a boolean that indicates whether some service
+ *    is initialized or not.
+ * The setting of the variable involved in the test must be the last step of
+ *    the initialization process.
+ *
+ * 
+ * @internal
+ */
+#if UMTX_STRONG_MEMORY_MODEL
+
+#define UMTX_CHECK(pMutex, expression, result) \
+    (result)=(expression)
+
+#else
+
+#define UMTX_CHECK(pMutex, expression, result) \
+    umtx_lock(pMutex); \
+    (result)=(expression); \
+    umtx_unlock(pMutex)
+
+#endif
+
+/*
+ * Code within ICU that accesses shared static or global data should
+ * instantiate a Mutex object while doing so.  The unnamed global mutex
+ * is used throughout ICU, so keep locking short and sweet.
+ *
+ * For example:
+ *
+ * void Function(int arg1, int arg2)
+ * {
+ *   static Object* foo;     // Shared read-write object
+ *   umtx_lock(NULL);        // Lock the ICU global mutex
+ *   foo->Method();
+ *   umtx_unlock(NULL);
+ * }
+ *
+ * an alternative C++ mutex API is defined in the file common/mutex.h
+ */
+
+/* Lock a mutex. 
+ * @param mutex The given mutex to be locked.  Pass NULL to specify
+ *              the global ICU mutex.  Recursive locks are an error
+ *              and may cause a deadlock on some platforms.
+ */
+U_CAPI void U_EXPORT2 umtx_lock   ( UMTX* mutex ); 
+
+/* Unlock a mutex. Pass in NULL if you want the single global
+   mutex. 
+ * @param mutex The given mutex to be unlocked.  Pass NULL to specify
+ *              the global ICU mutex.
+ */
+U_CAPI void U_EXPORT2 umtx_unlock ( UMTX* mutex );
+
+/* Initialize a mutex. Use it this way:
+   umtx_init( &aMutex ); 
+ * ICU Mutexes do not need explicit initialization before use.  Use of this
+ *   function is not necessary.
+ * Initialization of an already initialized mutex has no effect, and is safe to do.
+ * Initialization of mutexes is thread safe.  Two threads can concurrently 
+ *   initialize the same mutex without causing problems.
+ * @param mutex The given mutex to be initialized
+ */
+U_CAPI void U_EXPORT2 umtx_init   ( UMTX* mutex );
+
+/* Destroy a mutex. This will free the resources of a mutex.
+ * Use it this way:
+ *   umtx_destroy( &aMutex ); 
+ * Destroying an already destroyed mutex has no effect, and causes no problems.
+ * This function is not thread safe.  Two threads must not attempt to concurrently
+ *   destroy the same mutex.
+ * @param mutex The given mutex to be destroyed.
+ */
+U_CAPI void U_EXPORT2 umtx_destroy( UMTX *mutex );
+
+
+
+/*
+ * Atomic Increment and Decrement of an int32_t value.
+ *
+ * Return Values:
+ *   If the result of the operation is zero, the return zero.
+ *   If the result of the operation is not zero, the sign of returned value
+ *      is the same as the sign of the result, but the returned value itself may
+ *      be different from the result of the operation.
+ */
+U_CAPI int32_t U_EXPORT2 umtx_atomic_inc(int32_t *);
+U_CAPI int32_t U_EXPORT2 umtx_atomic_dec(int32_t *);
+
+
+#endif /*_CMUTEX*/
+/*eof*/
+
+
+
diff --git a/source/common/unames.c b/source/common/unames.c
new file mode 100644
index 0000000..e02c6a8
--- /dev/null
+++ b/source/common/unames.c
@@ -0,0 +1,2113 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  unames.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999oct04
+*   created by: Markus W. Scherer
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/putil.h"
+#include "unicode/uchar.h"
+#include "unicode/udata.h"
+#include "ustr_imp.h"
+#include "umutex.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "ucln_cmn.h"
+#include "udataswp.h"
+#include "uprops.h"
+
+/* prototypes ------------------------------------------------------------- */
+
+#define LENGTHOF(array) (sizeof(array)/sizeof((array)[0]))
+
+static const char DATA_NAME[] = "unames";
+static const char DATA_TYPE[] = "icu";
+
+#define GROUP_SHIFT 5
+#define LINES_PER_GROUP (1UL<<GROUP_SHIFT)
+#define GROUP_MASK (LINES_PER_GROUP-1)
+
+/*
+ * This struct was replaced by explicitly accessing equivalent
+ * fields from triples of uint16_t.
+ * The Group struct was padded to 8 bytes on compilers for early ARM CPUs,
+ * which broke the assumption that sizeof(Group)==6 and that the ++ operator
+ * would advance by 6 bytes (3 uint16_t).
+ *
+ * We can't just change the data structure because it's loaded from a data file,
+ * and we don't want to make it less compact, so we changed the access code.
+ *
+ * For details see ICU tickets 6331 and 6008.
+typedef struct {
+    uint16_t groupMSB,
+             offsetHigh, offsetLow; / * avoid padding * /
+} Group;
+ */
+enum {
+    GROUP_MSB,
+    GROUP_OFFSET_HIGH,
+    GROUP_OFFSET_LOW,
+    GROUP_LENGTH
+};
+
+/*
+ * Get the 32-bit group offset.
+ * @param group (const uint16_t *) pointer to a Group triple of uint16_t
+ * @return group offset (int32_t)
+ */
+#define GET_GROUP_OFFSET(group) ((int32_t)(group)[GROUP_OFFSET_HIGH]<<16|(group)[GROUP_OFFSET_LOW])
+
+#define NEXT_GROUP(group) ((group)+GROUP_LENGTH)
+#define PREV_GROUP(group) ((group)-GROUP_LENGTH)
+
+typedef struct {
+    uint32_t start, end;
+    uint8_t type, variant;
+    uint16_t size;
+} AlgorithmicRange;
+
+typedef struct {
+    uint32_t tokenStringOffset, groupsOffset, groupStringOffset, algNamesOffset;
+} UCharNames;
+
+/*
+ * Get the groups table from a UCharNames struct.
+ * The groups table consists of one uint16_t groupCount followed by
+ * groupCount groups. Each group is a triple of uint16_t, see GROUP_LENGTH
+ * and the comment for the old struct Group above.
+ *
+ * @param names (const UCharNames *) pointer to the UCharNames indexes
+ * @return (const uint16_t *) pointer to the groups table
+ */
+#define GET_GROUPS(names) (const uint16_t *)((const char *)names+names->groupsOffset)
+
+typedef struct {
+    const char *otherName;
+    UChar32 code;
+} FindName;
+
+#define DO_FIND_NAME NULL
+
+static UDataMemory *uCharNamesData=NULL;
+static UCharNames *uCharNames=NULL;
+static UErrorCode gLoadErrorCode=U_ZERO_ERROR;
+
+/*
+ * Maximum length of character names (regular & 1.0).
+ */
+static int32_t gMaxNameLength=0;
+
+/*
+ * Set of chars used in character names (regular & 1.0).
+ * Chars are platform-dependent (can be EBCDIC).
+ */
+static uint32_t gNameSet[8]={ 0 };
+
+#define U_NONCHARACTER_CODE_POINT U_CHAR_CATEGORY_COUNT
+#define U_LEAD_SURROGATE U_CHAR_CATEGORY_COUNT + 1
+#define U_TRAIL_SURROGATE U_CHAR_CATEGORY_COUNT + 2
+
+#define U_CHAR_EXTENDED_CATEGORY_COUNT (U_CHAR_CATEGORY_COUNT + 3)
+
+static const char * const charCatNames[U_CHAR_EXTENDED_CATEGORY_COUNT] = {
+    "unassigned",
+    "uppercase letter",
+    "lowercase letter",
+    "titlecase letter",
+    "modifier letter",
+    "other letter",
+    "non spacing mark",
+    "enclosing mark",
+    "combining spacing mark",
+    "decimal digit number",
+    "letter number",
+    "other number",
+    "space separator",
+    "line separator",
+    "paragraph separator",
+    "control",
+    "format",
+    "private use area",
+    "surrogate",
+    "dash punctuation",   
+    "start punctuation",
+    "end punctuation",
+    "connector punctuation",
+    "other punctuation",
+    "math symbol",
+    "currency symbol",
+    "modifier symbol",
+    "other symbol",
+    "initial punctuation",
+    "final punctuation",
+    "noncharacter",
+    "lead surrogate",
+    "trail surrogate"
+};
+
+/* implementation ----------------------------------------------------------- */
+
+static UBool U_CALLCONV unames_cleanup(void)
+{
+    if(uCharNamesData) {
+        udata_close(uCharNamesData);
+        uCharNamesData = NULL;
+    }
+    if(uCharNames) {
+        uCharNames = NULL;
+    }
+    gMaxNameLength=0;
+    return TRUE;
+}
+
+static UBool U_CALLCONV
+isAcceptable(void *context,
+             const char *type, const char *name,
+             const UDataInfo *pInfo) {
+    return (UBool)(
+        pInfo->size>=20 &&
+        pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
+        pInfo->charsetFamily==U_CHARSET_FAMILY &&
+        pInfo->dataFormat[0]==0x75 &&   /* dataFormat="unam" */
+        pInfo->dataFormat[1]==0x6e &&
+        pInfo->dataFormat[2]==0x61 &&
+        pInfo->dataFormat[3]==0x6d &&
+        pInfo->formatVersion[0]==1);
+}
+
+static UBool
+isDataLoaded(UErrorCode *pErrorCode) {
+    /* load UCharNames from file if necessary */
+    UBool isCached;
+
+    /* do this because double-checked locking is broken */
+    UMTX_CHECK(NULL, (uCharNames!=NULL), isCached);
+
+    if(!isCached) {
+        UCharNames *names;
+        UDataMemory *data;
+
+        /* check error code from previous attempt */
+        if(U_FAILURE(gLoadErrorCode)) {
+            *pErrorCode=gLoadErrorCode;
+            return FALSE;
+        }
+
+        /* open the data outside the mutex block */
+        data=udata_openChoice(NULL, DATA_TYPE, DATA_NAME, isAcceptable, NULL, pErrorCode);
+        if(U_FAILURE(*pErrorCode)) {
+            gLoadErrorCode=*pErrorCode;
+            return FALSE;
+        }
+
+        names=(UCharNames *)udata_getMemory(data);
+
+        /* in the mutex block, set the data for this process */
+        {
+            umtx_lock(NULL);
+            if(uCharNames==NULL) {
+                uCharNamesData=data;
+                uCharNames=names;
+                data=NULL;
+                names=NULL;
+                ucln_common_registerCleanup(UCLN_COMMON_UNAMES, unames_cleanup);
+            }
+            umtx_unlock(NULL);
+        }
+
+        /* if a different thread set it first, then close the extra data */
+        if(data!=NULL) {
+            udata_close(data); /* NULL if it was set correctly */
+        }
+    }
+    return TRUE;
+}
+
+#define WRITE_CHAR(buffer, bufferLength, bufferPos, c) { \
+    if((bufferLength)>0) { \
+        *(buffer)++=c; \
+        --(bufferLength); \
+    } \
+    ++(bufferPos); \
+}
+
+#define U_ISO_COMMENT U_CHAR_NAME_CHOICE_COUNT
+
+/*
+ * Important: expandName() and compareName() are almost the same -
+ * apply fixes to both.
+ *
+ * UnicodeData.txt uses ';' as a field separator, so no
+ * field can contain ';' as part of its contents.
+ * In unames.dat, it is marked as token[';']==-1 only if the
+ * semicolon is used in the data file - which is iff we
+ * have Unicode 1.0 names or ISO comments or aliases.
+ * So, it will be token[';']==-1 if we store U1.0 names/ISO comments/aliases
+ * although we know that it will never be part of a name.
+ */
+static uint16_t
+expandName(UCharNames *names,
+           const uint8_t *name, uint16_t nameLength, UCharNameChoice nameChoice,
+           char *buffer, uint16_t bufferLength) {
+    uint16_t *tokens=(uint16_t *)names+8;
+    uint16_t token, tokenCount=*tokens++, bufferPos=0;
+    uint8_t *tokenStrings=(uint8_t *)names+names->tokenStringOffset;
+    uint8_t c;
+
+    if(nameChoice!=U_UNICODE_CHAR_NAME && nameChoice!=U_EXTENDED_CHAR_NAME) {
+        /*
+         * skip the modern name if it is not requested _and_
+         * if the semicolon byte value is a character, not a token number
+         */
+        if((uint8_t)';'>=tokenCount || tokens[(uint8_t)';']==(uint16_t)(-1)) {
+            int fieldIndex= nameChoice==U_ISO_COMMENT ? 2 : nameChoice;
+            do {
+                while(nameLength>0) {
+                    --nameLength;
+                    if(*name++==';') {
+                        break;
+                    }
+                }
+            } while(--fieldIndex>0);
+        } else {
+            /*
+             * the semicolon byte value is a token number, therefore
+             * only modern names are stored in unames.dat and there is no
+             * such requested alternate name here
+             */
+            nameLength=0;
+        }
+    }
+
+    /* write each letter directly, and write a token word per token */
+    while(nameLength>0) {
+        --nameLength;
+        c=*name++;
+
+        if(c>=tokenCount) {
+            if(c!=';') {
+                /* implicit letter */
+                WRITE_CHAR(buffer, bufferLength, bufferPos, c);
+            } else {
+                /* finished */
+                break;
+            }
+        } else {
+            token=tokens[c];
+            if(token==(uint16_t)(-2)) {
+                /* this is a lead byte for a double-byte token */
+                token=tokens[c<<8|*name++];
+                --nameLength;
+            }
+            if(token==(uint16_t)(-1)) {
+                if(c!=';') {
+                    /* explicit letter */
+                    WRITE_CHAR(buffer, bufferLength, bufferPos, c);
+                } else {
+                    /* stop, but skip the semicolon if we are seeking
+                       extended names and there was no 2.0 name but there
+                       is a 1.0 name. */
+                    if(!bufferPos && nameChoice == U_EXTENDED_CHAR_NAME) {
+                        if ((uint8_t)';'>=tokenCount || tokens[(uint8_t)';']==(uint16_t)(-1)) {
+                            continue;
+                        }
+                    }
+                    /* finished */
+                    break;
+                }
+            } else {
+                /* write token word */
+                uint8_t *tokenString=tokenStrings+token;
+                while((c=*tokenString++)!=0) {
+                    WRITE_CHAR(buffer, bufferLength, bufferPos, c);
+                }
+            }
+        }
+    }
+
+    /* zero-terminate */
+    if(bufferLength>0) {
+        *buffer=0;
+    }
+
+    return bufferPos;
+}
+
+/*
+ * compareName() is almost the same as expandName() except that it compares
+ * the currently expanded name to an input name.
+ * It returns the match/no match result as soon as possible.
+ */
+static UBool
+compareName(UCharNames *names,
+            const uint8_t *name, uint16_t nameLength, UCharNameChoice nameChoice,
+            const char *otherName) {
+    uint16_t *tokens=(uint16_t *)names+8;
+    uint16_t token, tokenCount=*tokens++;
+    uint8_t *tokenStrings=(uint8_t *)names+names->tokenStringOffset;
+    uint8_t c;
+    const char *origOtherName = otherName;
+
+    if(nameChoice!=U_UNICODE_CHAR_NAME && nameChoice!=U_EXTENDED_CHAR_NAME) {
+        /*
+         * skip the modern name if it is not requested _and_
+         * if the semicolon byte value is a character, not a token number
+         */
+        if((uint8_t)';'>=tokenCount || tokens[(uint8_t)';']==(uint16_t)(-1)) {
+            int fieldIndex= nameChoice==U_ISO_COMMENT ? 2 : nameChoice;
+            do {
+                while(nameLength>0) {
+                    --nameLength;
+                    if(*name++==';') {
+                        break;
+                    }
+                }
+            } while(--fieldIndex>0);
+        } else {
+            /*
+             * the semicolon byte value is a token number, therefore
+             * only modern names are stored in unames.dat and there is no
+             * such requested alternate name here
+             */
+            nameLength=0;
+        }
+    }
+
+    /* compare each letter directly, and compare a token word per token */
+    while(nameLength>0) {
+        --nameLength;
+        c=*name++;
+
+        if(c>=tokenCount) {
+            if(c!=';') {
+                /* implicit letter */
+                if((char)c!=*otherName++) {
+                    return FALSE;
+                }
+            } else {
+                /* finished */
+                break;
+            }
+        } else {
+            token=tokens[c];
+            if(token==(uint16_t)(-2)) {
+                /* this is a lead byte for a double-byte token */
+                token=tokens[c<<8|*name++];
+                --nameLength;
+            }
+            if(token==(uint16_t)(-1)) {
+                if(c!=';') {
+                    /* explicit letter */
+                    if((char)c!=*otherName++) {
+                        return FALSE;
+                    }
+                } else {
+                    /* stop, but skip the semicolon if we are seeking
+                       extended names and there was no 2.0 name but there
+                       is a 1.0 name. */
+                    if(otherName == origOtherName && nameChoice == U_EXTENDED_CHAR_NAME) {
+                        if ((uint8_t)';'>=tokenCount || tokens[(uint8_t)';']==(uint16_t)(-1)) {
+                            continue;
+                        }
+                    }
+                    /* finished */
+                    break;
+                }
+            } else {
+                /* write token word */
+                uint8_t *tokenString=tokenStrings+token;
+                while((c=*tokenString++)!=0) {
+                    if((char)c!=*otherName++) {
+                        return FALSE;
+                    }
+                }
+            }
+        }
+    }
+
+    /* complete match? */
+    return (UBool)(*otherName==0);
+}
+
+static uint8_t getCharCat(UChar32 cp) {
+    uint8_t cat;
+
+    if (UTF_IS_UNICODE_NONCHAR(cp)) {
+        return U_NONCHARACTER_CODE_POINT;
+    }
+
+    if ((cat = u_charType(cp)) == U_SURROGATE) {
+        cat = UTF_IS_LEAD(cp) ? U_LEAD_SURROGATE : U_TRAIL_SURROGATE;
+    }
+
+    return cat;
+}
+
+static const char *getCharCatName(UChar32 cp) {
+    uint8_t cat = getCharCat(cp);
+
+    /* Return unknown if the table of names above is not up to
+       date. */
+
+    if (cat >= LENGTHOF(charCatNames)) {
+        return "unknown";
+    } else {
+        return charCatNames[cat];
+    }
+}
+
+static uint16_t getExtName(uint32_t code, char *buffer, uint16_t bufferLength) {
+    const char *catname = getCharCatName(code);
+    uint16_t length = 0;
+
+    UChar32 cp;
+    int ndigits, i;
+    
+    WRITE_CHAR(buffer, bufferLength, length, '<');
+    while (catname[length - 1]) {
+        WRITE_CHAR(buffer, bufferLength, length, catname[length - 1]);
+    }
+    WRITE_CHAR(buffer, bufferLength, length, '-');
+    for (cp = code, ndigits = 0; cp; ++ndigits, cp >>= 4)
+        ;
+    if (ndigits < 4)
+        ndigits = 4;
+    for (cp = code, i = ndigits; (cp || i > 0) && bufferLength; cp >>= 4, bufferLength--) {
+        uint8_t v = (uint8_t)(cp & 0xf);
+        buffer[--i] = (v < 10 ? '0' + v : 'A' + v - 10);
+    }
+    buffer += ndigits;
+    length += ndigits;
+    WRITE_CHAR(buffer, bufferLength, length, '>');
+
+    return length;
+}
+
+/*
+ * getGroup() does a binary search for the group that contains the
+ * Unicode code point "code".
+ * The return value is always a valid Group* that may contain "code"
+ * or else is the highest group before "code".
+ * If the lowest group is after "code", then that one is returned.
+ */
+static const uint16_t *
+getGroup(UCharNames *names, uint32_t code) {
+    const uint16_t *groups=GET_GROUPS(names);
+    uint16_t groupMSB=(uint16_t)(code>>GROUP_SHIFT),
+             start=0,
+             limit=*groups++,
+             number;
+
+    /* binary search for the group of names that contains the one for code */
+    while(start<limit-1) {
+        number=(uint16_t)((start+limit)/2);
+        if(groupMSB<groups[number*GROUP_LENGTH+GROUP_MSB]) {
+            limit=number;
+        } else {
+            start=number;
+        }
+    }
+
+    /* return this regardless of whether it is an exact match */
+    return groups+start*GROUP_LENGTH;
+}
+
+/*
+ * expandGroupLengths() reads a block of compressed lengths of 32 strings and
+ * expands them into offsets and lengths for each string.
+ * Lengths are stored with a variable-width encoding in consecutive nibbles:
+ * If a nibble<0xc, then it is the length itself (0=empty string).
+ * If a nibble>=0xc, then it forms a length value with the following nibble.
+ * Calculation see below.
+ * The offsets and lengths arrays must be at least 33 (one more) long because
+ * there is no check here at the end if the last nibble is still used.
+ */
+static const uint8_t *
+expandGroupLengths(const uint8_t *s,
+                   uint16_t offsets[LINES_PER_GROUP+1], uint16_t lengths[LINES_PER_GROUP+1]) {
+    /* read the lengths of the 32 strings in this group and get each string's offset */
+    uint16_t i=0, offset=0, length=0;
+    uint8_t lengthByte;
+
+    /* all 32 lengths must be read to get the offset of the first group string */
+    while(i<LINES_PER_GROUP) {
+        lengthByte=*s++;
+
+        /* read even nibble - MSBs of lengthByte */
+        if(length>=12) {
+            /* double-nibble length spread across two bytes */
+            length=(uint16_t)(((length&0x3)<<4|lengthByte>>4)+12);
+            lengthByte&=0xf;
+        } else if((lengthByte /* &0xf0 */)>=0xc0) {
+            /* double-nibble length spread across this one byte */
+            length=(uint16_t)((lengthByte&0x3f)+12);
+        } else {
+            /* single-nibble length in MSBs */
+            length=(uint16_t)(lengthByte>>4);
+            lengthByte&=0xf;
+        }
+
+        *offsets++=offset;
+        *lengths++=length;
+
+        offset+=length;
+        ++i;
+
+        /* read odd nibble - LSBs of lengthByte */
+        if((lengthByte&0xf0)==0) {
+            /* this nibble was not consumed for a double-nibble length above */
+            length=lengthByte;
+            if(length<12) {
+                /* single-nibble length in LSBs */
+                *offsets++=offset;
+                *lengths++=length;
+
+                offset+=length;
+                ++i;
+            }
+        } else {
+            length=0;   /* prevent double-nibble detection in the next iteration */
+        }
+    }
+
+    /* now, s is at the first group string */
+    return s;
+}
+
+static uint16_t
+expandGroupName(UCharNames *names, const uint16_t *group,
+                uint16_t lineNumber, UCharNameChoice nameChoice,
+                char *buffer, uint16_t bufferLength) {
+    uint16_t offsets[LINES_PER_GROUP+2], lengths[LINES_PER_GROUP+2];
+    const uint8_t *s=(uint8_t *)names+names->groupStringOffset+GET_GROUP_OFFSET(group);
+    s=expandGroupLengths(s, offsets, lengths);
+    return expandName(names, s+offsets[lineNumber], lengths[lineNumber], nameChoice,
+                      buffer, bufferLength);
+}
+
+static uint16_t
+getName(UCharNames *names, uint32_t code, UCharNameChoice nameChoice,
+        char *buffer, uint16_t bufferLength) {
+    const uint16_t *group=getGroup(names, code);
+    if((uint16_t)(code>>GROUP_SHIFT)==group[GROUP_MSB]) {
+        return expandGroupName(names, group, (uint16_t)(code&GROUP_MASK), nameChoice,
+                               buffer, bufferLength);
+    } else {
+        /* group not found */
+        /* zero-terminate */
+        if(bufferLength>0) {
+            *buffer=0;
+        }
+        return 0;
+    }
+}
+
+/*
+ * enumGroupNames() enumerates all the names in a 32-group
+ * and either calls the enumerator function or finds a given input name.
+ */
+static UBool
+enumGroupNames(UCharNames *names, const uint16_t *group,
+               UChar32 start, UChar32 end,
+               UEnumCharNamesFn *fn, void *context,
+               UCharNameChoice nameChoice) {
+    uint16_t offsets[LINES_PER_GROUP+2], lengths[LINES_PER_GROUP+2];
+    const uint8_t *s=(uint8_t *)names+names->groupStringOffset+GET_GROUP_OFFSET(group);
+
+    s=expandGroupLengths(s, offsets, lengths);
+    if(fn!=DO_FIND_NAME) {
+        char buffer[200];
+        uint16_t length;
+
+        while(start<=end) {
+            length=expandName(names, s+offsets[start&GROUP_MASK], lengths[start&GROUP_MASK], nameChoice, buffer, sizeof(buffer));
+            if (!length && nameChoice == U_EXTENDED_CHAR_NAME) {
+                buffer[length = getExtName(start, buffer, sizeof(buffer))] = 0;
+            }
+            /* here, we assume that the buffer is large enough */
+            if(length>0) {
+                if(!fn(context, start, nameChoice, buffer, length)) {
+                    return FALSE;
+                }
+            }
+            ++start;
+        }
+    } else {
+        const char *otherName=((FindName *)context)->otherName;
+        while(start<=end) {
+            if(compareName(names, s+offsets[start&GROUP_MASK], lengths[start&GROUP_MASK], nameChoice, otherName)) {
+                ((FindName *)context)->code=start;
+                return FALSE;
+            }
+            ++start;
+        }
+    }
+    return TRUE;
+}
+
+/*
+ * enumExtNames enumerate extended names.
+ * It only needs to do it if it is called with a real function and not
+ * with the dummy DO_FIND_NAME, because u_charFromName() does a check
+ * for extended names by itself.
+ */ 
+static UBool
+enumExtNames(UChar32 start, UChar32 end,
+             UEnumCharNamesFn *fn, void *context)
+{
+    if(fn!=DO_FIND_NAME) {
+        char buffer[200];
+        uint16_t length;
+        
+        while(start<=end) {
+            buffer[length = getExtName(start, buffer, sizeof(buffer))] = 0;
+            /* here, we assume that the buffer is large enough */
+            if(length>0) {
+                if(!fn(context, start, U_EXTENDED_CHAR_NAME, buffer, length)) {
+                    return FALSE;
+                }
+            }
+            ++start;
+        }
+    }
+
+    return TRUE;
+}
+
+static UBool
+enumNames(UCharNames *names,
+          UChar32 start, UChar32 limit,
+          UEnumCharNamesFn *fn, void *context,
+          UCharNameChoice nameChoice) {
+    uint16_t startGroupMSB, endGroupMSB, groupCount;
+    const uint16_t *group, *groupLimit;
+
+    startGroupMSB=(uint16_t)(start>>GROUP_SHIFT);
+    endGroupMSB=(uint16_t)((limit-1)>>GROUP_SHIFT);
+
+    /* find the group that contains start, or the highest before it */
+    group=getGroup(names, start);
+
+    if(startGroupMSB==endGroupMSB) {
+        if(startGroupMSB==group[GROUP_MSB]) {
+            /* if start and limit-1 are in the same group, then enumerate only in that one */
+            return enumGroupNames(names, group, start, limit-1, fn, context, nameChoice);
+        }
+    } else {
+        const uint16_t *groups=GET_GROUPS(names);
+        groupCount=*groups++;
+        groupLimit=groups+groupCount*GROUP_LENGTH;
+
+        if(startGroupMSB==group[GROUP_MSB]) {
+            /* enumerate characters in the partial start group */
+            if((start&GROUP_MASK)!=0) {
+                if(!enumGroupNames(names, group,
+                                   start, ((UChar32)startGroupMSB<<GROUP_SHIFT)+LINES_PER_GROUP-1,
+                                   fn, context, nameChoice)) {
+                    return FALSE;
+                }
+                group=NEXT_GROUP(group); /* continue with the next group */
+            }
+        } else if(startGroupMSB>group[GROUP_MSB]) {
+            /* make sure that we start enumerating with the first group after start */
+            const uint16_t *nextGroup=NEXT_GROUP(group);
+            if (nextGroup < groupLimit && nextGroup[GROUP_MSB] > startGroupMSB && nameChoice == U_EXTENDED_CHAR_NAME) {
+                UChar32 end = nextGroup[GROUP_MSB] << GROUP_SHIFT;
+                if (end > limit) {
+                    end = limit;
+                }
+                if (!enumExtNames(start, end - 1, fn, context)) {
+                    return FALSE;
+                }
+            }
+            group=nextGroup;
+        }
+
+        /* enumerate entire groups between the start- and end-groups */
+        while(group<groupLimit && group[GROUP_MSB]<endGroupMSB) {
+            const uint16_t *nextGroup;
+            start=(UChar32)group[GROUP_MSB]<<GROUP_SHIFT;
+            if(!enumGroupNames(names, group, start, start+LINES_PER_GROUP-1, fn, context, nameChoice)) {
+                return FALSE;
+            }
+            nextGroup=NEXT_GROUP(group);
+            if (nextGroup < groupLimit && nextGroup[GROUP_MSB] > group[GROUP_MSB] + 1 && nameChoice == U_EXTENDED_CHAR_NAME) {
+                UChar32 end = nextGroup[GROUP_MSB] << GROUP_SHIFT;
+                if (end > limit) {
+                    end = limit;
+                }
+                if (!enumExtNames((group[GROUP_MSB] + 1) << GROUP_SHIFT, end - 1, fn, context)) {
+                    return FALSE;
+                }
+            }
+            group=nextGroup;
+        }
+
+        /* enumerate within the end group (group[GROUP_MSB]==endGroupMSB) */
+        if(group<groupLimit && group[GROUP_MSB]==endGroupMSB) {
+            return enumGroupNames(names, group, (limit-1)&~GROUP_MASK, limit-1, fn, context, nameChoice);
+        } else if (nameChoice == U_EXTENDED_CHAR_NAME && group == groupLimit) {
+            UChar32 next = (PREV_GROUP(group)[GROUP_MSB] + 1) << GROUP_SHIFT;
+            if (next > start) {
+                start = next;
+            }
+        } else {
+            return TRUE;
+        }
+    }
+
+    /* we have not found a group, which means everything is made of
+       extended names. */
+    if (nameChoice == U_EXTENDED_CHAR_NAME) {
+        if (limit > UCHAR_MAX_VALUE + 1) {
+            limit = UCHAR_MAX_VALUE + 1;
+        }
+        return enumExtNames(start, limit - 1, fn, context);
+    }
+    
+    return TRUE;
+}
+
+static uint16_t
+writeFactorSuffix(const uint16_t *factors, uint16_t count,
+                  const char *s, /* suffix elements */
+                  uint32_t code,
+                  uint16_t indexes[8], /* output fields from here */
+                  const char *elementBases[8], const char *elements[8],
+                  char *buffer, uint16_t bufferLength) {
+    uint16_t i, factor, bufferPos=0;
+    char c;
+
+    /* write elements according to the factors */
+
+    /*
+     * the factorized elements are determined by modulo arithmetic
+     * with the factors of this algorithm
+     *
+     * note that for fewer operations, count is decremented here
+     */
+    --count;
+    for(i=count; i>0; --i) {
+        factor=factors[i];
+        indexes[i]=(uint16_t)(code%factor);
+        code/=factor;
+    }
+    /*
+     * we don't need to calculate the last modulus because start<=code<=end
+     * guarantees here that code<=factors[0]
+     */
+    indexes[0]=(uint16_t)code;
+
+    /* write each element */
+    for(;;) {
+        if(elementBases!=NULL) {
+            *elementBases++=s;
+        }
+
+        /* skip indexes[i] strings */
+        factor=indexes[i];
+        while(factor>0) {
+            while(*s++!=0) {}
+            --factor;
+        }
+        if(elements!=NULL) {
+            *elements++=s;
+        }
+
+        /* write element */
+        while((c=*s++)!=0) {
+            WRITE_CHAR(buffer, bufferLength, bufferPos, c);
+        }
+
+        /* we do not need to perform the rest of this loop for i==count - break here */
+        if(i>=count) {
+            break;
+        }
+
+        /* skip the rest of the strings for this factors[i] */
+        factor=(uint16_t)(factors[i]-indexes[i]-1);
+        while(factor>0) {
+            while(*s++!=0) {}
+            --factor;
+        }
+
+        ++i;
+    }
+
+    /* zero-terminate */
+    if(bufferLength>0) {
+        *buffer=0;
+    }
+
+    return bufferPos;
+}
+
+/*
+ * Important:
+ * Parts of findAlgName() are almost the same as some of getAlgName().
+ * Fixes must be applied to both.
+ */
+static uint16_t
+getAlgName(AlgorithmicRange *range, uint32_t code, UCharNameChoice nameChoice,
+        char *buffer, uint16_t bufferLength) {
+    uint16_t bufferPos=0;
+
+    /* Only the normative character name can be algorithmic. */
+    if(nameChoice!=U_UNICODE_CHAR_NAME && nameChoice!=U_EXTENDED_CHAR_NAME) {
+        /* zero-terminate */
+        if(bufferLength>0) {
+            *buffer=0;
+        }
+        return 0;
+    }
+
+    switch(range->type) {
+    case 0: {
+        /* name = prefix hex-digits */
+        const char *s=(const char *)(range+1);
+        char c;
+
+        uint16_t i, count;
+
+        /* copy prefix */
+        while((c=*s++)!=0) {
+            WRITE_CHAR(buffer, bufferLength, bufferPos, c);
+        }
+
+        /* write hexadecimal code point value */
+        count=range->variant;
+
+        /* zero-terminate */
+        if(count<bufferLength) {
+            buffer[count]=0;
+        }
+
+        for(i=count; i>0;) {
+            if(--i<bufferLength) {
+                c=(char)(code&0xf);
+                if(c<10) {
+                    c+='0';
+                } else {
+                    c+='A'-10;
+                }
+                buffer[i]=c;
+            }
+            code>>=4;
+        }
+
+        bufferPos+=count;
+        break;
+    }
+    case 1: {
+        /* name = prefix factorized-elements */
+        uint16_t indexes[8];
+        const uint16_t *factors=(const uint16_t *)(range+1);
+        uint16_t count=range->variant;
+        const char *s=(const char *)(factors+count);
+        char c;
+
+        /* copy prefix */
+        while((c=*s++)!=0) {
+            WRITE_CHAR(buffer, bufferLength, bufferPos, c);
+        }
+
+        bufferPos+=writeFactorSuffix(factors, count,
+                                     s, code-range->start, indexes, NULL, NULL, buffer, bufferLength);
+        break;
+    }
+    default:
+        /* undefined type */
+        /* zero-terminate */
+        if(bufferLength>0) {
+            *buffer=0;
+        }
+        break;
+    }
+
+    return bufferPos;
+}
+
+/*
+ * Important: enumAlgNames() and findAlgName() are almost the same.
+ * Any fix must be applied to both.
+ */
+static UBool
+enumAlgNames(AlgorithmicRange *range,
+             UChar32 start, UChar32 limit,
+             UEnumCharNamesFn *fn, void *context,
+             UCharNameChoice nameChoice) {
+    char buffer[200];
+    uint16_t length;
+
+    if(nameChoice!=U_UNICODE_CHAR_NAME && nameChoice!=U_EXTENDED_CHAR_NAME) {
+        return TRUE;
+    }
+
+    switch(range->type) {
+    case 0: {
+        char *s, *end;
+        char c;
+
+        /* get the full name of the start character */
+        length=getAlgName(range, (uint32_t)start, nameChoice, buffer, sizeof(buffer));
+        if(length<=0) {
+            return TRUE;
+        }
+
+        /* call the enumerator function with this first character */
+        if(!fn(context, start, nameChoice, buffer, length)) {
+            return FALSE;
+        }
+
+        /* go to the end of the name; all these names have the same length */
+        end=buffer;
+        while(*end!=0) {
+            ++end;
+        }
+
+        /* enumerate the rest of the names */
+        while(++start<limit) {
+            /* increment the hexadecimal number on a character-basis */
+            s=end;
+            for (;;) {
+                c=*--s;
+                if(('0'<=c && c<'9') || ('A'<=c && c<'F')) {
+                    *s=(char)(c+1);
+                    break;
+                } else if(c=='9') {
+                    *s='A';
+                    break;
+                } else if(c=='F') {
+                    *s='0';
+                }
+            }
+
+            if(!fn(context, start, nameChoice, buffer, length)) {
+                return FALSE;
+            }
+        }
+        break;
+    }
+    case 1: {
+        uint16_t indexes[8];
+        const char *elementBases[8], *elements[8];
+        const uint16_t *factors=(const uint16_t *)(range+1);
+        uint16_t count=range->variant;
+        const char *s=(const char *)(factors+count);
+        char *suffix, *t;
+        uint16_t prefixLength, i, idx;
+
+        char c;
+
+        /* name = prefix factorized-elements */
+
+        /* copy prefix */
+        suffix=buffer;
+        prefixLength=0;
+        while((c=*s++)!=0) {
+            *suffix++=c;
+            ++prefixLength;
+        }
+
+        /* append the suffix of the start character */
+        length=(uint16_t)(prefixLength+writeFactorSuffix(factors, count,
+                                              s, (uint32_t)start-range->start,
+                                              indexes, elementBases, elements,
+                                              suffix, (uint16_t)(sizeof(buffer)-prefixLength)));
+
+        /* call the enumerator function with this first character */
+        if(!fn(context, start, nameChoice, buffer, length)) {
+            return FALSE;
+        }
+
+        /* enumerate the rest of the names */
+        while(++start<limit) {
+            /* increment the indexes in lexical order bound by the factors */
+            i=count;
+            for (;;) {
+                idx=(uint16_t)(indexes[--i]+1);
+                if(idx<factors[i]) {
+                    /* skip one index and its element string */
+                    indexes[i]=idx;
+                    s=elements[i];
+                    while(*s++!=0) {
+                    }
+                    elements[i]=s;
+                    break;
+                } else {
+                    /* reset this index to 0 and its element string to the first one */
+                    indexes[i]=0;
+                    elements[i]=elementBases[i];
+                }
+            }
+
+            /* to make matters a little easier, just append all elements to the suffix */
+            t=suffix;
+            length=prefixLength;
+            for(i=0; i<count; ++i) {
+                s=elements[i];
+                while((c=*s++)!=0) {
+                    *t++=c;
+                    ++length;
+                }
+            }
+            /* zero-terminate */
+            *t=0;
+
+            if(!fn(context, start, nameChoice, buffer, length)) {
+                return FALSE;
+            }
+        }
+        break;
+    }
+    default:
+        /* undefined type */
+        break;
+    }
+
+    return TRUE;
+}
+
+/*
+ * findAlgName() is almost the same as enumAlgNames() except that it
+ * returns the code point for a name if it fits into the range.
+ * It returns 0xffff otherwise.
+ */
+static UChar32
+findAlgName(AlgorithmicRange *range, UCharNameChoice nameChoice, const char *otherName) {
+    UChar32 code;
+
+    if(nameChoice!=U_UNICODE_CHAR_NAME && nameChoice!=U_EXTENDED_CHAR_NAME) {
+        return 0xffff;
+    }
+
+    switch(range->type) {
+    case 0: {
+        /* name = prefix hex-digits */
+        const char *s=(const char *)(range+1);
+        char c;
+
+        uint16_t i, count;
+
+        /* compare prefix */
+        while((c=*s++)!=0) {
+            if((char)c!=*otherName++) {
+                return 0xffff;
+            }
+        }
+
+        /* read hexadecimal code point value */
+        count=range->variant;
+        code=0;
+        for(i=0; i<count; ++i) {
+            c=*otherName++;
+            if('0'<=c && c<='9') {
+                code=(code<<4)|(c-'0');
+            } else if('A'<=c && c<='F') {
+                code=(code<<4)|(c-'A'+10);
+            } else {
+                return 0xffff;
+            }
+        }
+
+        /* does it fit into the range? */
+        if(*otherName==0 && range->start<=(uint32_t)code && (uint32_t)code<=range->end) {
+            return code;
+        }
+        break;
+    }
+    case 1: {
+        char buffer[64];
+        uint16_t indexes[8];
+        const char *elementBases[8], *elements[8];
+        const uint16_t *factors=(const uint16_t *)(range+1);
+        uint16_t count=range->variant;
+        const char *s=(const char *)(factors+count), *t;
+        UChar32 start, limit;
+        uint16_t i, idx;
+
+        char c;
+
+        /* name = prefix factorized-elements */
+
+        /* compare prefix */
+        while((c=*s++)!=0) {
+            if((char)c!=*otherName++) {
+                return 0xffff;
+            }
+        }
+
+        start=(UChar32)range->start;
+        limit=(UChar32)(range->end+1);
+
+        /* initialize the suffix elements for enumeration; indexes should all be set to 0 */
+        writeFactorSuffix(factors, count, s, 0,
+                          indexes, elementBases, elements, buffer, sizeof(buffer));
+
+        /* compare the first suffix */
+        if(0==uprv_strcmp(otherName, buffer)) {
+            return start;
+        }
+
+        /* enumerate and compare the rest of the suffixes */
+        while(++start<limit) {
+            /* increment the indexes in lexical order bound by the factors */
+            i=count;
+            for (;;) {
+                idx=(uint16_t)(indexes[--i]+1);
+                if(idx<factors[i]) {
+                    /* skip one index and its element string */
+                    indexes[i]=idx;
+                    s=elements[i];
+                    while(*s++!=0) {}
+                    elements[i]=s;
+                    break;
+                } else {
+                    /* reset this index to 0 and its element string to the first one */
+                    indexes[i]=0;
+                    elements[i]=elementBases[i];
+                }
+            }
+
+            /* to make matters a little easier, just compare all elements of the suffix */
+            t=otherName;
+            for(i=0; i<count; ++i) {
+                s=elements[i];
+                while((c=*s++)!=0) {
+                    if(c!=*t++) {
+                        s=""; /* does not match */
+                        i=99;
+                    }
+                }
+            }
+            if(i<99 && *t==0) {
+                return start;
+            }
+        }
+        break;
+    }
+    default:
+        /* undefined type */
+        break;
+    }
+
+    return 0xffff;
+}
+
+/* sets of name characters, maximum name lengths ---------------------------- */
+
+#define SET_ADD(set, c) ((set)[(uint8_t)c>>5]|=((uint32_t)1<<((uint8_t)c&0x1f)))
+#define SET_CONTAINS(set, c) (((set)[(uint8_t)c>>5]&((uint32_t)1<<((uint8_t)c&0x1f)))!=0)
+
+static int32_t
+calcStringSetLength(uint32_t set[8], const char *s) {
+    int32_t length=0;
+    char c;
+
+    while((c=*s++)!=0) {
+        SET_ADD(set, c);
+        ++length;
+    }
+    return length;
+}
+
+static int32_t
+calcAlgNameSetsLengths(int32_t maxNameLength) {
+    AlgorithmicRange *range;
+    uint32_t *p;
+    uint32_t rangeCount;
+    int32_t length;
+
+    /* enumerate algorithmic ranges */
+    p=(uint32_t *)((uint8_t *)uCharNames+uCharNames->algNamesOffset);
+    rangeCount=*p;
+    range=(AlgorithmicRange *)(p+1);
+    while(rangeCount>0) {
+        switch(range->type) {
+        case 0:
+            /* name = prefix + (range->variant times) hex-digits */
+            /* prefix */
+            length=calcStringSetLength(gNameSet, (const char *)(range+1))+range->variant;
+            if(length>maxNameLength) {
+                maxNameLength=length;
+            }
+            break;
+        case 1: {
+            /* name = prefix factorized-elements */
+            const uint16_t *factors=(const uint16_t *)(range+1);
+            const char *s;
+            int32_t i, count=range->variant, factor, factorLength, maxFactorLength;
+
+            /* prefix length */
+            s=(const char *)(factors+count);
+            length=calcStringSetLength(gNameSet, s);
+            s+=length+1; /* start of factor suffixes */
+
+            /* get the set and maximum factor suffix length for each factor */
+            for(i=0; i<count; ++i) {
+                maxFactorLength=0;
+                for(factor=factors[i]; factor>0; --factor) {
+                    factorLength=calcStringSetLength(gNameSet, s);
+                    s+=factorLength+1;
+                    if(factorLength>maxFactorLength) {
+                        maxFactorLength=factorLength;
+                    }
+                }
+                length+=maxFactorLength;
+            }
+
+            if(length>maxNameLength) {
+                maxNameLength=length;
+            }
+            break;
+        }
+        default:
+            /* unknown type */
+            break;
+        }
+
+        range=(AlgorithmicRange *)((uint8_t *)range+range->size);
+        --rangeCount;
+    }
+    return maxNameLength;
+}
+
+static int32_t
+calcExtNameSetsLengths(int32_t maxNameLength) {
+    int32_t i, length;
+
+    for(i=0; i<LENGTHOF(charCatNames); ++i) {
+        /*
+         * for each category, count the length of the category name
+         * plus 9=
+         * 2 for <>
+         * 1 for -
+         * 6 for most hex digits per code point
+         */
+        length=9+calcStringSetLength(gNameSet, charCatNames[i]);
+        if(length>maxNameLength) {
+            maxNameLength=length;
+        }
+    }
+    return maxNameLength;
+}
+
+static int32_t
+calcNameSetLength(const uint16_t *tokens, uint16_t tokenCount, const uint8_t *tokenStrings, int8_t *tokenLengths,
+                  uint32_t set[8],
+                  const uint8_t **pLine, const uint8_t *lineLimit) {
+    const uint8_t *line=*pLine;
+    int32_t length=0, tokenLength;
+    uint16_t c, token;
+
+    while(line!=lineLimit && (c=*line++)!=(uint8_t)';') {
+        if(c>=tokenCount) {
+            /* implicit letter */
+            SET_ADD(set, c);
+            ++length;
+        } else {
+            token=tokens[c];
+            if(token==(uint16_t)(-2)) {
+                /* this is a lead byte for a double-byte token */
+                c=c<<8|*line++;
+                token=tokens[c];
+            }
+            if(token==(uint16_t)(-1)) {
+                /* explicit letter */
+                SET_ADD(set, c);
+                ++length;
+            } else {
+                /* count token word */
+                if(tokenLengths!=NULL) {
+                    /* use cached token length */
+                    tokenLength=tokenLengths[c];
+                    if(tokenLength==0) {
+                        tokenLength=calcStringSetLength(set, (const char *)tokenStrings+token);
+                        tokenLengths[c]=(int8_t)tokenLength;
+                    }
+                } else {
+                    tokenLength=calcStringSetLength(set, (const char *)tokenStrings+token);
+                }
+                length+=tokenLength;
+            }
+        }
+    }
+
+    *pLine=line;
+    return length;
+}
+
+static void
+calcGroupNameSetsLengths(int32_t maxNameLength) {
+    uint16_t offsets[LINES_PER_GROUP+2], lengths[LINES_PER_GROUP+2];
+
+    uint16_t *tokens=(uint16_t *)uCharNames+8;
+    uint16_t tokenCount=*tokens++;
+    uint8_t *tokenStrings=(uint8_t *)uCharNames+uCharNames->tokenStringOffset;
+
+    int8_t *tokenLengths;
+
+    const uint16_t *group;
+    const uint8_t *s, *line, *lineLimit;
+
+    int32_t groupCount, lineNumber, length;
+
+    tokenLengths=(int8_t *)uprv_malloc(tokenCount);
+    if(tokenLengths!=NULL) {
+        uprv_memset(tokenLengths, 0, tokenCount);
+    }
+
+    group=GET_GROUPS(uCharNames);
+    groupCount=*group++;
+
+    /* enumerate all groups */
+    while(groupCount>0) {
+        s=(uint8_t *)uCharNames+uCharNames->groupStringOffset+GET_GROUP_OFFSET(group);
+        s=expandGroupLengths(s, offsets, lengths);
+
+        /* enumerate all lines in each group */
+        for(lineNumber=0; lineNumber<LINES_PER_GROUP; ++lineNumber) {
+            line=s+offsets[lineNumber];
+            length=lengths[lineNumber];
+            if(length==0) {
+                continue;
+            }
+
+            lineLimit=line+length;
+
+            /* read regular name */
+            length=calcNameSetLength(tokens, tokenCount, tokenStrings, tokenLengths, gNameSet, &line, lineLimit);
+            if(length>maxNameLength) {
+                maxNameLength=length;
+            }
+            if(line==lineLimit) {
+                continue;
+            }
+
+            /* read Unicode 1.0 name */
+            length=calcNameSetLength(tokens, tokenCount, tokenStrings, tokenLengths, gNameSet, &line, lineLimit);
+            if(length>maxNameLength) {
+                maxNameLength=length;
+            }
+            if(line==lineLimit) {
+                continue;
+            }
+
+            /* read ISO comment */
+            /*length=calcNameSetLength(tokens, tokenCount, tokenStrings, tokenLengths, gISOCommentSet, &line, lineLimit);*/
+        }
+
+        group=NEXT_GROUP(group);
+        --groupCount;
+    }
+
+    if(tokenLengths!=NULL) {
+        uprv_free(tokenLengths);
+    }
+
+    /* set gMax... - name length last for threading */
+    gMaxNameLength=maxNameLength;
+}
+
+static UBool
+calcNameSetsLengths(UErrorCode *pErrorCode) {
+    static const char extChars[]="0123456789ABCDEF<>-";
+    int32_t i, maxNameLength;
+
+    if(gMaxNameLength!=0) {
+        return TRUE;
+    }
+
+    if(!isDataLoaded(pErrorCode)) {
+        return FALSE;
+    }
+
+    /* set hex digits, used in various names, and <>-, used in extended names */
+    for(i=0; i<sizeof(extChars)-1; ++i) {
+        SET_ADD(gNameSet, extChars[i]);
+    }
+
+    /* set sets and lengths from algorithmic names */
+    maxNameLength=calcAlgNameSetsLengths(0);
+
+    /* set sets and lengths from extended names */
+    maxNameLength=calcExtNameSetsLengths(maxNameLength);
+
+    /* set sets and lengths from group names, set global maximum values */
+    calcGroupNameSetsLengths(maxNameLength);
+
+    return TRUE;
+}
+
+/* public API --------------------------------------------------------------- */
+
+U_CAPI int32_t U_EXPORT2
+u_charName(UChar32 code, UCharNameChoice nameChoice,
+           char *buffer, int32_t bufferLength,
+           UErrorCode *pErrorCode) {
+    AlgorithmicRange *algRange;
+    uint32_t *p;
+    uint32_t i;
+    int32_t length;
+
+    /* check the argument values */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    } else if(nameChoice>=U_CHAR_NAME_CHOICE_COUNT ||
+              bufferLength<0 || (bufferLength>0 && buffer==NULL)
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    if((uint32_t)code>UCHAR_MAX_VALUE || !isDataLoaded(pErrorCode)) {
+        return u_terminateChars(buffer, bufferLength, 0, pErrorCode);
+    }
+
+    length=0;
+
+    /* try algorithmic names first */
+    p=(uint32_t *)((uint8_t *)uCharNames+uCharNames->algNamesOffset);
+    i=*p;
+    algRange=(AlgorithmicRange *)(p+1);
+    while(i>0) {
+        if(algRange->start<=(uint32_t)code && (uint32_t)code<=algRange->end) {
+            length=getAlgName(algRange, (uint32_t)code, nameChoice, buffer, (uint16_t)bufferLength);
+            break;
+        }
+        algRange=(AlgorithmicRange *)((uint8_t *)algRange+algRange->size);
+        --i;
+    }
+
+    if(i==0) {
+        if (nameChoice == U_EXTENDED_CHAR_NAME) {
+            length = getName(uCharNames, (uint32_t )code, U_EXTENDED_CHAR_NAME, buffer, (uint16_t) bufferLength);
+            if (!length) {
+                /* extended character name */
+                length = getExtName((uint32_t) code, buffer, (uint16_t) bufferLength);
+            }
+        } else {
+            /* normal character name */
+            length=getName(uCharNames, (uint32_t)code, nameChoice, buffer, (uint16_t)bufferLength);
+        }
+    }
+
+    return u_terminateChars(buffer, bufferLength, length, pErrorCode);
+}
+
+U_CAPI int32_t U_EXPORT2
+u_getISOComment(UChar32 c,
+                char *dest, int32_t destCapacity,
+                UErrorCode *pErrorCode) {
+    int32_t length;
+
+    /* check the argument values */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    } else if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    if((uint32_t)c>UCHAR_MAX_VALUE || !isDataLoaded(pErrorCode)) {
+        return u_terminateChars(dest, destCapacity, 0, pErrorCode);
+    }
+
+    /* the ISO comment is stored like a normal character name */
+    length=getName(uCharNames, (uint32_t)c, U_ISO_COMMENT, dest, (uint16_t)destCapacity);
+    return u_terminateChars(dest, destCapacity, length, pErrorCode);
+}
+
+U_CAPI UChar32 U_EXPORT2
+u_charFromName(UCharNameChoice nameChoice,
+               const char *name,
+               UErrorCode *pErrorCode) {
+    char upper[120], lower[120];
+    FindName findName;
+    AlgorithmicRange *algRange;
+    uint32_t *p;
+    uint32_t i;
+    UChar32 cp = 0;
+    char c0;
+    UChar32 error = 0xffff;     /* Undefined, but use this for backwards compatibility. */
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return error;
+    }
+
+    if(nameChoice>=U_CHAR_NAME_CHOICE_COUNT || name==NULL || *name==0) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return error;
+    }
+
+    if(!isDataLoaded(pErrorCode)) {
+        return error;
+    }
+
+    /* construct the uppercase and lowercase of the name first */
+    for(i=0; i<sizeof(upper); ++i) {
+        if((c0=*name++)!=0) {
+            upper[i]=uprv_toupper(c0);
+            lower[i]=uprv_tolower(c0);
+        } else {
+            upper[i]=lower[i]=0;
+            break;
+        }
+    }
+    if(i==sizeof(upper)) {
+        /* name too long, there is no such character */
+        *pErrorCode = U_ILLEGAL_CHAR_FOUND;
+        return error;
+    }
+
+    /* try extended names first */
+    if (lower[0] == '<') {
+        if (nameChoice == U_EXTENDED_CHAR_NAME) {
+            if (lower[--i] == '>') {
+                for (--i; lower[i] && lower[i] != '-'; --i) {
+                }
+
+                if (lower[i] == '-') { /* We've got a category. */
+                    uint32_t cIdx;
+
+                    lower[i] = 0;
+
+                    for (++i; lower[i] != '>'; ++i) {
+                        if (lower[i] >= '0' && lower[i] <= '9') {
+                            cp = (cp << 4) + lower[i] - '0';
+                        } else if (lower[i] >= 'a' && lower[i] <= 'f') {
+                            cp = (cp << 4) + lower[i] - 'a' + 10;
+                        } else {
+                            *pErrorCode = U_ILLEGAL_CHAR_FOUND;
+                            return error;
+                        }
+                    }
+
+                    /* Now validate the category name.
+                       We could use a binary search, or a trie, if
+                       we really wanted to. */
+
+                    for (lower[i] = 0, cIdx = 0; cIdx < LENGTHOF(charCatNames); ++cIdx) {
+
+                        if (!uprv_strcmp(lower + 1, charCatNames[cIdx])) {
+                            if (getCharCat(cp) == cIdx) {
+                                return cp;
+                            }
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        *pErrorCode = U_ILLEGAL_CHAR_FOUND;
+        return error;
+    }
+
+    /* try algorithmic names now */
+    p=(uint32_t *)((uint8_t *)uCharNames+uCharNames->algNamesOffset);
+    i=*p;
+    algRange=(AlgorithmicRange *)(p+1);
+    while(i>0) {
+        if((cp=findAlgName(algRange, nameChoice, upper))!=0xffff) {
+            return cp;
+        }
+        algRange=(AlgorithmicRange *)((uint8_t *)algRange+algRange->size);
+        --i;
+    }
+
+    /* normal character name */
+    findName.otherName=upper;
+    findName.code=error;
+    enumNames(uCharNames, 0, UCHAR_MAX_VALUE + 1, DO_FIND_NAME, &findName, nameChoice);
+    if (findName.code == error) {
+         *pErrorCode = U_ILLEGAL_CHAR_FOUND;
+    }
+    return findName.code;
+}
+
+U_CAPI void U_EXPORT2
+u_enumCharNames(UChar32 start, UChar32 limit,
+                UEnumCharNamesFn *fn,
+                void *context,
+                UCharNameChoice nameChoice,
+                UErrorCode *pErrorCode) {
+    AlgorithmicRange *algRange;
+    uint32_t *p;
+    uint32_t i;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return;
+    }
+
+    if(nameChoice>=U_CHAR_NAME_CHOICE_COUNT || fn==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    if((uint32_t) limit > UCHAR_MAX_VALUE + 1) {
+        limit = UCHAR_MAX_VALUE + 1;
+    }
+    if((uint32_t)start>=(uint32_t)limit) {
+        return;
+    }
+
+    if(!isDataLoaded(pErrorCode)) {
+        return;
+    }
+
+    /* interleave the data-driven ones with the algorithmic ones */
+    /* iterate over all algorithmic ranges; assume that they are in ascending order */
+    p=(uint32_t *)((uint8_t *)uCharNames+uCharNames->algNamesOffset);
+    i=*p;
+    algRange=(AlgorithmicRange *)(p+1);
+    while(i>0) {
+        /* enumerate the character names before the current algorithmic range */
+        /* here: start<limit */
+        if((uint32_t)start<algRange->start) {
+            if((uint32_t)limit<=algRange->start) {
+                enumNames(uCharNames, start, limit, fn, context, nameChoice);
+                return;
+            }
+            if(!enumNames(uCharNames, start, (UChar32)algRange->start, fn, context, nameChoice)) {
+                return;
+            }
+            start=(UChar32)algRange->start;
+        }
+        /* enumerate the character names in the current algorithmic range */
+        /* here: algRange->start<=start<limit */
+        if((uint32_t)start<=algRange->end) {
+            if((uint32_t)limit<=(algRange->end+1)) {
+                enumAlgNames(algRange, start, limit, fn, context, nameChoice);
+                return;
+            }
+            if(!enumAlgNames(algRange, start, (UChar32)algRange->end+1, fn, context, nameChoice)) {
+                return;
+            }
+            start=(UChar32)algRange->end+1;
+        }
+        /* continue to the next algorithmic range (here: start<limit) */
+        algRange=(AlgorithmicRange *)((uint8_t *)algRange+algRange->size);
+        --i;
+    }
+    /* enumerate the character names after the last algorithmic range */
+    enumNames(uCharNames, start, limit, fn, context, nameChoice);
+}
+
+U_CAPI int32_t U_EXPORT2
+uprv_getMaxCharNameLength() {
+    UErrorCode errorCode=U_ZERO_ERROR;
+    if(calcNameSetsLengths(&errorCode)) {
+        return gMaxNameLength;
+    } else {
+        return 0;
+    }
+}
+
+/**
+ * Converts the char set cset into a Unicode set uset.
+ * @param cset Set of 256 bit flags corresponding to a set of chars.
+ * @param uset USet to receive characters. Existing contents are deleted.
+ */
+static void
+charSetToUSet(uint32_t cset[8], const USetAdder *sa) {
+    UChar us[256];
+    char cs[256];
+
+    int32_t i, length;
+    UErrorCode errorCode;
+
+    errorCode=U_ZERO_ERROR;
+
+    if(!calcNameSetsLengths(&errorCode)) {
+        return;
+    }
+
+    /* build a char string with all chars that are used in character names */
+    length=0;
+    for(i=0; i<256; ++i) {
+        if(SET_CONTAINS(cset, i)) {
+            cs[length++]=(char)i;
+        }
+    }
+
+    /* convert the char string to a UChar string */
+    u_charsToUChars(cs, us, length);
+
+    /* add each UChar to the USet */
+    for(i=0; i<length; ++i) {
+        if(us[i]!=0 || cs[i]==0) { /* non-invariant chars become (UChar)0 */
+            sa->add(sa->set, us[i]);
+        }
+    }
+}
+
+/**
+ * Fills set with characters that are used in Unicode character names.
+ * @param set USet to receive characters.
+ */
+U_CAPI void U_EXPORT2
+uprv_getCharNameCharacters(const USetAdder *sa) {
+    charSetToUSet(gNameSet, sa);
+}
+
+/* data swapping ------------------------------------------------------------ */
+
+/*
+ * The token table contains non-negative entries for token bytes,
+ * and -1 for bytes that represent themselves in the data file's charset.
+ * -2 entries are used for lead bytes.
+ *
+ * Direct bytes (-1 entries) must be translated from the input charset family
+ * to the output charset family.
+ * makeTokenMap() writes a permutation mapping for this.
+ * Use it once for single-/lead-byte tokens and once more for all trail byte
+ * tokens. (';' is an unused trail byte marked with -1.)
+ */
+static void
+makeTokenMap(const UDataSwapper *ds,
+             int16_t tokens[], uint16_t tokenCount,
+             uint8_t map[256],
+             UErrorCode *pErrorCode) {
+    UBool usedOutChar[256];
+    uint16_t i, j;
+    uint8_t c1, c2;
+
+    if(U_FAILURE(*pErrorCode)) {
+        return;
+    }
+
+    if(ds->inCharset==ds->outCharset) {
+        /* Same charset family: identity permutation */
+        for(i=0; i<256; ++i) {
+            map[i]=(uint8_t)i;
+        }
+    } else {
+        uprv_memset(map, 0, 256);
+        uprv_memset(usedOutChar, 0, 256);
+
+        if(tokenCount>256) {
+            tokenCount=256;
+        }
+
+        /* set the direct bytes (byte 0 always maps to itself) */
+        for(i=1; i<tokenCount; ++i) {
+            if(tokens[i]==-1) {
+                /* convert the direct byte character */
+                c1=(uint8_t)i;
+                ds->swapInvChars(ds, &c1, 1, &c2, pErrorCode);
+                if(U_FAILURE(*pErrorCode)) {
+                    udata_printError(ds, "unames/makeTokenMap() finds variant character 0x%02x used (input charset family %d)\n",
+                                     i, ds->inCharset);
+                    return;
+                }
+
+                /* enter the converted character into the map and mark it used */
+                map[c1]=c2;
+                usedOutChar[c2]=TRUE;
+            }
+        }
+
+        /* set the mappings for the rest of the permutation */
+        for(i=j=1; i<tokenCount; ++i) {
+            /* set mappings that were not set for direct bytes */
+            if(map[i]==0) {
+                /* set an output byte value that was not used as an output byte above */
+                while(usedOutChar[j]) {
+                    ++j;
+                }
+                map[i]=(uint8_t)j++;
+            }
+        }
+
+        /*
+         * leave mappings at tokenCount and above unset if tokenCount<256
+         * because they won't be used
+         */
+    }
+}
+
+U_CAPI int32_t U_EXPORT2
+uchar_swapNames(const UDataSwapper *ds,
+                const void *inData, int32_t length, void *outData,
+                UErrorCode *pErrorCode) {
+    const UDataInfo *pInfo;
+    int32_t headerSize;
+
+    const uint8_t *inBytes;
+    uint8_t *outBytes;
+
+    uint32_t tokenStringOffset, groupsOffset, groupStringOffset, algNamesOffset,
+             offset, i, count, stringsCount;
+
+    const AlgorithmicRange *inRange;
+    AlgorithmicRange *outRange;
+
+    /* udata_swapDataHeader checks the arguments */
+    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    /* check data format and format version */
+    pInfo=(const UDataInfo *)((const char *)inData+4);
+    if(!(
+        pInfo->dataFormat[0]==0x75 &&   /* dataFormat="unam" */
+        pInfo->dataFormat[1]==0x6e &&
+        pInfo->dataFormat[2]==0x61 &&
+        pInfo->dataFormat[3]==0x6d &&
+        pInfo->formatVersion[0]==1
+    )) {
+        udata_printError(ds, "uchar_swapNames(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as unames.icu\n",
+                         pInfo->dataFormat[0], pInfo->dataFormat[1],
+                         pInfo->dataFormat[2], pInfo->dataFormat[3],
+                         pInfo->formatVersion[0]);
+        *pErrorCode=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    inBytes=(const uint8_t *)inData+headerSize;
+    outBytes=(uint8_t *)outData+headerSize;
+    if(length<0) {
+        algNamesOffset=ds->readUInt32(((const uint32_t *)inBytes)[3]);
+    } else {
+        length-=headerSize;
+        if( length<20 ||
+            (uint32_t)length<(algNamesOffset=ds->readUInt32(((const uint32_t *)inBytes)[3]))
+        ) {
+            udata_printError(ds, "uchar_swapNames(): too few bytes (%d after header) for unames.icu\n",
+                             length);
+            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+            return 0;
+        }
+    }
+
+    if(length<0) {
+        /* preflighting: iterate through algorithmic ranges */
+        offset=algNamesOffset;
+        count=ds->readUInt32(*((const uint32_t *)(inBytes+offset)));
+        offset+=4;
+
+        for(i=0; i<count; ++i) {
+            inRange=(const AlgorithmicRange *)(inBytes+offset);
+            offset+=ds->readUInt16(inRange->size);
+        }
+    } else {
+        /* swap data */
+        const uint16_t *p;
+        uint16_t *q, *temp;
+
+        int16_t tokens[512];
+        uint16_t tokenCount;
+
+        uint8_t map[256], trailMap[256];
+
+        /* copy the data for inaccessible bytes */
+        if(inBytes!=outBytes) {
+            uprv_memcpy(outBytes, inBytes, length);
+        }
+
+        /* the initial 4 offsets first */
+        tokenStringOffset=ds->readUInt32(((const uint32_t *)inBytes)[0]);
+        groupsOffset=ds->readUInt32(((const uint32_t *)inBytes)[1]);
+        groupStringOffset=ds->readUInt32(((const uint32_t *)inBytes)[2]);
+        ds->swapArray32(ds, inBytes, 16, outBytes, pErrorCode);
+
+        /*
+         * now the tokens table
+         * it needs to be permutated along with the compressed name strings
+         */
+        p=(const uint16_t *)(inBytes+16);
+        q=(uint16_t *)(outBytes+16);
+
+        /* read and swap the tokenCount */
+        tokenCount=ds->readUInt16(*p);
+        ds->swapArray16(ds, p, 2, q, pErrorCode);
+        ++p;
+        ++q;
+
+        /* read the first 512 tokens and make the token maps */
+        if(tokenCount<=512) {
+            count=tokenCount;
+        } else {
+            count=512;
+        }
+        for(i=0; i<count; ++i) {
+            tokens[i]=udata_readInt16(ds, p[i]);
+        }
+        for(; i<512; ++i) {
+            tokens[i]=0; /* fill the rest of the tokens array if tokenCount<512 */
+        }
+        makeTokenMap(ds, tokens, tokenCount, map, pErrorCode);
+        makeTokenMap(ds, tokens+256, (uint16_t)(tokenCount>256 ? tokenCount-256 : 0), trailMap, pErrorCode);
+        if(U_FAILURE(*pErrorCode)) {
+            return 0;
+        }
+
+        /*
+         * swap and permutate the tokens
+         * go through a temporary array to support in-place swapping
+         */
+        temp=(uint16_t *)uprv_malloc(tokenCount*2);
+        if(temp==NULL) {
+            udata_printError(ds, "out of memory swapping %u unames.icu tokens\n",
+                             tokenCount);
+            *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+
+        /* swap and permutate single-/lead-byte tokens */
+        for(i=0; i<tokenCount && i<256; ++i) {
+            ds->swapArray16(ds, p+i, 2, temp+map[i], pErrorCode);
+        }
+
+        /* swap and permutate trail-byte tokens */
+        for(; i<tokenCount; ++i) {
+            ds->swapArray16(ds, p+i, 2, temp+(i&0xffffff00)+trailMap[i&0xff], pErrorCode);
+        }
+
+        /* copy the result into the output and free the temporary array */
+        uprv_memcpy(q, temp, tokenCount*2);
+        uprv_free(temp);
+
+        /*
+         * swap the token strings but not a possible padding byte after
+         * the terminating NUL of the last string
+         */
+        udata_swapInvStringBlock(ds, inBytes+tokenStringOffset, (int32_t)(groupsOffset-tokenStringOffset),
+                                    outBytes+tokenStringOffset, pErrorCode);
+        if(U_FAILURE(*pErrorCode)) {
+            udata_printError(ds, "uchar_swapNames(token strings) failed\n");
+            return 0;
+        }
+
+        /* swap the group table */
+        count=ds->readUInt16(*((const uint16_t *)(inBytes+groupsOffset)));
+        ds->swapArray16(ds, inBytes+groupsOffset, (int32_t)((1+count*3)*2),
+                           outBytes+groupsOffset, pErrorCode);
+
+        /*
+         * swap the group strings
+         * swap the string bytes but not the nibble-encoded string lengths
+         */
+        if(ds->inCharset!=ds->outCharset) {
+            uint16_t offsets[LINES_PER_GROUP+1], lengths[LINES_PER_GROUP+1];
+
+            const uint8_t *inStrings, *nextInStrings;
+            uint8_t *outStrings;
+
+            uint8_t c;
+
+            inStrings=inBytes+groupStringOffset;
+            outStrings=outBytes+groupStringOffset;
+
+            stringsCount=algNamesOffset-groupStringOffset;
+
+            /* iterate through string groups until only a few padding bytes are left */
+            while(stringsCount>32) {
+                nextInStrings=expandGroupLengths(inStrings, offsets, lengths);
+
+                /* move past the length bytes */
+                stringsCount-=(uint32_t)(nextInStrings-inStrings);
+                outStrings+=nextInStrings-inStrings;
+                inStrings=nextInStrings;
+
+                count=offsets[31]+lengths[31]; /* total number of string bytes in this group */
+                stringsCount-=count;
+
+                /* swap the string bytes using map[] and trailMap[] */
+                while(count>0) {
+                    c=*inStrings++;
+                    *outStrings++=map[c];
+                    if(tokens[c]!=-2) {
+                        --count;
+                    } else {
+                        /* token lead byte: swap the trail byte, too */
+                        *outStrings++=trailMap[*inStrings++];
+                        count-=2;
+                    }
+                }
+            }
+        }
+
+        /* swap the algorithmic ranges */
+        offset=algNamesOffset;
+        count=ds->readUInt32(*((const uint32_t *)(inBytes+offset)));
+        ds->swapArray32(ds, inBytes+offset, 4, outBytes+offset, pErrorCode);
+        offset+=4;
+
+        for(i=0; i<count; ++i) {
+            if(offset>(uint32_t)length) {
+                udata_printError(ds, "uchar_swapNames(): too few bytes (%d after header) for unames.icu algorithmic range %u\n",
+                                 length, i);
+                *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+                return 0;
+            }
+
+            inRange=(const AlgorithmicRange *)(inBytes+offset);
+            outRange=(AlgorithmicRange *)(outBytes+offset);
+            offset+=ds->readUInt16(inRange->size);
+
+            ds->swapArray32(ds, inRange, 8, outRange, pErrorCode);
+            ds->swapArray16(ds, &inRange->size, 2, &outRange->size, pErrorCode);
+            switch(inRange->type) {
+            case 0:
+                /* swap prefix string */
+                ds->swapInvChars(ds, inRange+1, (int32_t)uprv_strlen((const char *)(inRange+1)),
+                                    outRange+1, pErrorCode);
+                if(U_FAILURE(*pErrorCode)) {
+                    udata_printError(ds, "uchar_swapNames(prefix string of algorithmic range %u) failed\n",
+                                     i);
+                    return 0;
+                }
+                break;
+            case 1:
+                {
+                    /* swap factors and the prefix and factor strings */
+                    uint32_t factorsCount;
+
+                    factorsCount=inRange->variant;
+                    p=(const uint16_t *)(inRange+1);
+                    q=(uint16_t *)(outRange+1);
+                    ds->swapArray16(ds, p, (int32_t)(factorsCount*2), q, pErrorCode);
+
+                    /* swap the strings, up to the last terminating NUL */
+                    p+=factorsCount;
+                    q+=factorsCount;
+                    stringsCount=(uint32_t)((inBytes+offset)-(const uint8_t *)p);
+                    while(stringsCount>0 && ((const uint8_t *)p)[stringsCount-1]!=0) {
+                        --stringsCount;
+                    }
+                    ds->swapInvChars(ds, p, (int32_t)stringsCount, q, pErrorCode);
+                }
+                break;
+            default:
+                udata_printError(ds, "uchar_swapNames(): unknown type %u of algorithmic range %u\n",
+                                 inRange->type, i);
+                *pErrorCode=U_UNSUPPORTED_ERROR;
+                return 0;
+            }
+        }
+    }
+
+    return headerSize+(int32_t)offset;
+}
+
+/*
+ * Hey, Emacs, please set the following:
+ *
+ * Local Variables:
+ * indent-tabs-mode: nil
+ * End:
+ *
+ */
diff --git a/source/common/unicode/brkiter.h b/source/common/unicode/brkiter.h
new file mode 100644
index 0000000..bdd3cc7
--- /dev/null
+++ b/source/common/unicode/brkiter.h
@@ -0,0 +1,557 @@
+/*
+********************************************************************************
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+********************************************************************************
+*
+* File brkiter.h
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   02/18/97    aliu        Added typedef for TextCount.  Made DONE const.
+*   05/07/97    aliu        Fixed DLL declaration.
+*   07/09/97    jfitz       Renamed BreakIterator and interface synced with JDK
+*   08/11/98    helena      Sync-up JDK1.2.
+*   01/13/2000  helena      Added UErrorCode parameter to createXXXInstance methods.
+********************************************************************************
+*/
+
+#ifndef BRKITER_H
+#define BRKITER_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Break Iterator.
+ */
+
+#if UCONFIG_NO_BREAK_ITERATION
+
+U_NAMESPACE_BEGIN
+
+/*
+ * Allow the declaration of APIs with pointers to BreakIterator
+ * even when break iteration is removed from the build.
+ */
+class BreakIterator;
+
+U_NAMESPACE_END
+
+#else
+
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+#include "unicode/chariter.h"
+#include "unicode/locid.h"
+#include "unicode/ubrk.h"
+#include "unicode/strenum.h"
+#include "unicode/utext.h"
+#include "unicode/umisc.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * The BreakIterator class implements methods for finding the location
+ * of boundaries in text. BreakIterator is an abstract base class.
+ * Instances of BreakIterator maintain a current position and scan over
+ * text returning the index of characters where boundaries occur.
+ * <p>
+ * Line boundary analysis determines where a text string can be broken
+ * when line-wrapping. The mechanism correctly handles punctuation and
+ * hyphenated words.
+ * <p>
+ * Sentence boundary analysis allows selection with correct
+ * interpretation of periods within numbers and abbreviations, and
+ * trailing punctuation marks such as quotation marks and parentheses.
+ * <p>
+ * Word boundary analysis is used by search and replace functions, as
+ * well as within text editing applications that allow the user to
+ * select words with a double click. Word selection provides correct
+ * interpretation of punctuation marks within and following
+ * words. Characters that are not part of a word, such as symbols or
+ * punctuation marks, have word-breaks on both sides.
+ * <p>
+ * Character boundary analysis allows users to interact with
+ * characters as they expect to, for example, when moving the cursor
+ * through a text string. Character boundary analysis provides correct
+ * navigation of through character strings, regardless of how the
+ * character is stored.  For example, an accented character might be
+ * stored as a base character and a diacritical mark. What users
+ * consider to be a character can differ between languages.
+ * <p>
+ * The text boundary positions are found according to the rules
+ * described in Unicode Standard Annex #29, Text Boundaries, and
+ * Unicode Standard Annex #14, Line Breaking Properties.  These
+ * are available at http://www.unicode.org/reports/tr14/ and
+ * http://www.unicode.org/reports/tr29/.
+ * <p>
+ * In addition to the C++ API defined in this header file, a
+ * plain C API with equivalent functionality is defined in the
+ * file ubrk.h
+ * <p>
+ * Code snippets illustrating the use of the Break Iterator APIs
+ * are available in the ICU User Guide,
+ * http://icu-project.org/userguide/boundaryAnalysis.html
+ * and in the sample program icu/source/samples/break/break.cpp
+ *
+ */
+class U_COMMON_API BreakIterator : public UObject {
+public:
+    /**
+     *  destructor
+     *  @stable ICU 2.0
+     */
+    virtual ~BreakIterator();
+
+    /**
+     * Return true if another object is semantically equal to this
+     * one. The other object should be an instance of the same subclass of
+     * BreakIterator. Objects of different subclasses are considered
+     * unequal.
+     * <P>
+     * Return true if this BreakIterator is at the same position in the
+     * same text, and is the same class and type (word, line, etc.) of
+     * BreakIterator, as the argument.  Text is considered the same if
+     * it contains the same characters, it need not be the same
+     * object, and styles are not considered.
+     * @stable ICU 2.0
+     */
+    virtual UBool operator==(const BreakIterator&) const = 0;
+
+    /**
+     * Returns the complement of the result of operator==
+     * @param rhs The BreakIterator to be compared for inequality
+     * @return the complement of the result of operator==
+     * @stable ICU 2.0
+     */
+    UBool operator!=(const BreakIterator& rhs) const { return !operator==(rhs); }
+
+    /**
+     * Return a polymorphic copy of this object.  This is an abstract
+     * method which subclasses implement.
+     * @stable ICU 2.0
+     */
+    virtual BreakIterator* clone(void) const = 0;
+
+    /**
+     * Return a polymorphic class ID for this object. Different subclasses
+     * will return distinct unequal values.
+     * @stable ICU 2.0
+     */
+    virtual UClassID getDynamicClassID(void) const = 0;
+
+    /**
+     * Return a CharacterIterator over the text being analyzed.
+     * @stable ICU 2.0
+     */
+    virtual CharacterIterator& getText(void) const = 0;
+
+
+    /**
+      *  Get a UText for the text being analyzed.
+      *  The returned UText is a shallow clone of the UText used internally
+      *  by the break iterator implementation.  It can safely be used to
+      *  access the text without impacting any break iterator operations,
+      *  but the underlying text itself must not be altered.
+      *
+      * @param fillIn A UText to be filled in.  If NULL, a new UText will be
+      *           allocated to hold the result.
+      * @param status receives any error codes.
+      * @return   The current UText for this break iterator.  If an input
+      *           UText was provided, it will always be returned.
+      * @stable ICU 3.4
+      */
+     virtual UText *getUText(UText *fillIn, UErrorCode &status) const = 0;
+
+    /**
+     * Change the text over which this operates. The text boundary is
+     * reset to the start.
+     * @param text The UnicodeString used to change the text.
+     * @stable ICU 2.0
+     */
+    virtual void  setText(const UnicodeString &text) = 0;
+
+    /**
+     * Reset the break iterator to operate over the text represented by
+     * the UText.  The iterator position is reset to the start.
+     *
+     * This function makes a shallow clone of the supplied UText.  This means
+     * that the caller is free to immediately close or otherwise reuse the
+     * Utext that was passed as a parameter, but that the underlying text itself
+     * must not be altered while being referenced by the break iterator.
+     *
+     * @param text The UText used to change the text.
+     * @param status receives any error codes.
+     * @stable ICU 3.4
+     */
+    virtual void  setText(UText *text, UErrorCode &status) = 0;
+
+    /**
+     * Change the text over which this operates. The text boundary is
+     * reset to the start.
+     * Note that setText(UText *) provides similar functionality to this function,
+     * and is more efficient.
+     * @param it The CharacterIterator used to change the text.
+     * @stable ICU 2.0
+     */
+    virtual void  adoptText(CharacterIterator* it) = 0;
+
+    enum {
+        /**
+         * DONE is returned by previous() and next() after all valid
+         * boundaries have been returned.
+         * @stable ICU 2.0
+         */
+        DONE = (int32_t)-1
+    };
+
+    /**
+     * Return the index of the first character in the text being scanned.
+     * @stable ICU 2.0
+     */
+    virtual int32_t first(void) = 0;
+
+    /**
+     * Return the index immediately BEYOND the last character in the text being scanned.
+     * @stable ICU 2.0
+     */
+    virtual int32_t last(void) = 0;
+
+    /**
+     * Return the boundary preceding the current boundary.
+     * @return The character index of the previous text boundary or DONE if all
+     * boundaries have been returned.
+     * @stable ICU 2.0
+     */
+    virtual int32_t previous(void) = 0;
+
+    /**
+     * Return the boundary following the current boundary.
+     * @return The character index of the next text boundary or DONE if all
+     * boundaries have been returned.
+     * @stable ICU 2.0
+     */
+    virtual int32_t next(void) = 0;
+
+    /**
+     * Return character index of the current interator position within the text.
+     * @return The boundary most recently returned.
+     * @stable ICU 2.0
+     */
+    virtual int32_t current(void) const = 0;
+
+    /**
+     * Return the first boundary following the specified offset.
+     * The value returned is always greater than the offset or
+     * the value BreakIterator.DONE
+     * @param offset the offset to begin scanning.
+     * @return The first boundary after the specified offset.
+     * @stable ICU 2.0
+     */
+    virtual int32_t following(int32_t offset) = 0;
+
+    /**
+     * Return the first boundary preceding the specified offset.
+     * The value returned is always smaller than the offset or
+     * the value BreakIterator.DONE
+     * @param offset the offset to begin scanning.
+     * @return The first boundary before the specified offset.
+     * @stable ICU 2.0
+     */
+    virtual int32_t preceding(int32_t offset) = 0;
+
+    /**
+     * Return true if the specfied position is a boundary position.
+     * As a side effect, the current position of the iterator is set
+     * to the first boundary position at or following the specified offset.
+     * @param offset the offset to check.
+     * @return True if "offset" is a boundary position.
+     * @stable ICU 2.0
+     */
+    virtual UBool isBoundary(int32_t offset) = 0;
+
+    /**
+     * Return the nth boundary from the current boundary
+     * @param n which boundary to return.  A value of 0
+     * does nothing.  Negative values move to previous boundaries
+     * and positive values move to later boundaries.
+     * @return The index of the nth boundary from the current position, or
+     * DONE if there are fewer than |n| boundaries in the specfied direction.
+     * @stable ICU 2.0
+     */
+    virtual int32_t next(int32_t n) = 0;
+
+    /**
+     * Create BreakIterator for word-breaks using the given locale.
+     * Returns an instance of a BreakIterator implementing word breaks.
+     * WordBreak is useful for word selection (ex. double click)
+     * @param where the locale.
+     * @param status the error code
+     * @return A BreakIterator for word-breaks.  The UErrorCode& status
+     * 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_WARNING 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_WARNING 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.
+     * @stable ICU 2.0
+     */
+    static BreakIterator* U_EXPORT2
+    createWordInstance(const Locale& where, UErrorCode& status);
+
+    /**
+     * Create BreakIterator for line-breaks using specified locale.
+     * Returns an instance of a BreakIterator implementing line breaks. Line
+     * breaks are logically possible line breaks, actual line breaks are
+     * usually determined based on display width.
+     * LineBreak is useful for word wrapping text.
+     * @param where the locale.
+     * @param status The error code.
+     * @return A BreakIterator for line-breaks.  The UErrorCode& status
+     * 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_WARNING 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_WARNING 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.
+     * @stable ICU 2.0
+     */
+    static BreakIterator* U_EXPORT2
+    createLineInstance(const Locale& where, UErrorCode& status);
+
+    /**
+     * Create BreakIterator for character-breaks using specified locale
+     * Returns an instance of a BreakIterator implementing character breaks.
+     * Character breaks are boundaries of combining character sequences.
+     * @param where the locale.
+     * @param status The error code.
+     * @return A BreakIterator for character-breaks.  The UErrorCode& status
+     * 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_WARNING 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_WARNING 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.
+     * @stable ICU 2.0
+     */
+    static BreakIterator* U_EXPORT2
+    createCharacterInstance(const Locale& where, UErrorCode& status);
+
+    /**
+     * Create BreakIterator for sentence-breaks using specified locale
+     * Returns an instance of a BreakIterator implementing sentence breaks.
+     * @param where the locale.
+     * @param status The error code.
+     * @return A BreakIterator for sentence-breaks.  The UErrorCode& status
+     * 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_WARNING 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_WARNING 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.
+     * @stable ICU 2.0
+     */
+    static BreakIterator* U_EXPORT2
+    createSentenceInstance(const Locale& where, UErrorCode& status);
+
+    /**
+     * Create BreakIterator for title-casing breaks using the specified locale
+     * Returns an instance of a BreakIterator implementing title breaks.
+     * The iterator returned locates title boundaries as described for
+     * Unicode 3.2 only. For Unicode 4.0 and above title boundary iteration,
+     * please use Word Boundary iterator.{@link #createWordInstance }
+     *
+     * @param where the locale.
+     * @param status The error code.
+     * @return A BreakIterator for title-breaks.  The UErrorCode& status
+     * 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_WARNING 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_WARNING 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.
+     * @stable ICU 2.1
+     */
+    static BreakIterator* U_EXPORT2
+    createTitleInstance(const Locale& where, UErrorCode& status);
+
+    /**
+     * Get the set of Locales for which TextBoundaries are installed.
+     * <p><b>Note:</b> this will not return locales added through the register
+     * call. To see the registered locales too, use the getAvailableLocales
+     * function that returns a StringEnumeration object </p>
+     * @param count the output parameter of number of elements in the locale list
+     * @return available locales
+     * @stable ICU 2.0
+     */
+    static const Locale* U_EXPORT2 getAvailableLocales(int32_t& count);
+
+    /**
+     * 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
+     * Uses best match.
+     * @return user-displayable name
+     * @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 getMatchingLocales
+     * @param name the fill-in parameter of the return value
+     * @return user-displayable name
+     * @stable ICU 2.0
+     */
+    static UnicodeString& U_EXPORT2 getDisplayName(const Locale& objectLocale,
+                                         UnicodeString& name);
+
+    /**
+     * Thread safe client-buffer-based cloning operation
+     *    Do NOT call delete on a safeclone, since 'new' is not used to create it.
+     * @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.
+     * @param BufferSize reference to size of allocated space.
+     * If BufferSize == 0, a sufficient size for use in cloning will
+     * be returned ('pre-flighting')
+     * If BufferSize 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
+     *
+     * @stable ICU 2.0
+     */
+    virtual BreakIterator *  createBufferClone(void *stackBuffer,
+                                               int32_t &BufferSize,
+                                               UErrorCode &status) = 0;
+
+    /**
+     *   Determine whether the BreakIterator was created in user memory by
+     *   createBufferClone(), and thus should not be deleted.  Such objects
+     *   must be closed by an explicit call to the destructor (not delete).
+     *  @stable ICU 2.0
+     */
+    inline UBool isBufferClone(void);
+
+#if !UCONFIG_NO_SERVICE
+    /**
+     * Register a new break iterator of the indicated kind, to use in the given locale.
+     * The break iterator will be adopted.  Clones of the iterator will be returned
+     * if a request for a break iterator of the given kind matches or falls back to
+     * this locale.
+     * @param toAdopt the BreakIterator instance to be adopted
+     * @param locale the Locale for which this instance is to be registered
+     * @param kind the type of iterator for which this instance is to be registered
+     * @param status the in/out status code, no special meanings are assigned
+     * @return a registry key that can be used to unregister this instance
+     * @stable ICU 2.4
+     */
+    static URegistryKey U_EXPORT2 registerInstance(BreakIterator* toAdopt,
+                                        const Locale& locale,
+                                        UBreakIteratorType kind,
+                                        UErrorCode& status);
+
+    /**
+     * Unregister a previously-registered BreakIterator using the key returned from the
+     * register call.  Key becomes invalid after a successful call and should not be used again.
+     * The BreakIterator 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 iterator for the key was successfully unregistered
+     * @stable ICU 2.4
+     */
+    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.4
+     */
+    static StringEnumeration* U_EXPORT2 getAvailableLocales(void);
+#endif
+
+    /**
+     * Returns the locale for this break iterator. Two flavors are available: valid and
+     * actual locale.
+     * @stable ICU 2.8
+     */
+    Locale getLocale(ULocDataLocaleType type, UErrorCode& status) const;
+
+    /** Get the locale for this break iterator 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;
+
+ private:
+    static BreakIterator* buildInstance(const Locale& loc, const char *type, int32_t kind, UErrorCode& status);
+    static BreakIterator* createInstance(const Locale& loc, int32_t kind, UErrorCode& status);
+    static BreakIterator* makeInstance(const Locale& loc, int32_t kind, UErrorCode& status);
+
+    friend class ICUBreakIteratorFactory;
+    friend class ICUBreakIteratorService;
+
+protected:
+    /** @internal */
+    BreakIterator();
+    /** @internal */
+    UBool fBufferClone;
+    /** @internal */
+    BreakIterator (const BreakIterator &other) : UObject(other), fBufferClone(FALSE) {}
+
+private:
+
+    /** @internal */
+    char actualLocale[ULOC_FULLNAME_CAPACITY];
+    char validLocale[ULOC_FULLNAME_CAPACITY];
+
+    /**
+     * The assignment operator has no real implementation.
+     * It's provided to make the compiler happy. Do not call.
+     */
+    BreakIterator& operator=(const BreakIterator&);
+};
+
+inline UBool BreakIterator::isBufferClone()
+{
+    return fBufferClone;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
+
+#endif // _BRKITER
+//eof
+
diff --git a/source/common/unicode/bytestream.h b/source/common/unicode/bytestream.h
new file mode 100644
index 0000000..fb9e07a
--- /dev/null
+++ b/source/common/unicode/bytestream.h
@@ -0,0 +1,252 @@
+// Copyright (C) 2009-2010, International Business Machines
+// Corporation and others. All Rights Reserved.
+//
+// Copyright 2007 Google Inc. All Rights Reserved.
+// Author: sanjay@google.com (Sanjay Ghemawat)
+//
+// Abstract interface that consumes a sequence of bytes (ByteSink).
+//
+// Used so that we can write a single piece of code that can operate
+// on a variety of output string types.
+//
+// Various implementations of this interface are provided:
+//   ByteSink:
+//      CheckedArrayByteSink    Write to a flat array, with bounds checking
+//      StringByteSink          Write to an STL string
+
+// This code is a contribution of Google code, and the style used here is
+// a compromise between the original Google code and the ICU coding guidelines.
+// For example, data types are ICU-ified (size_t,int->int32_t),
+// and API comments doxygen-ified, but function names and behavior are
+// as in the original, if possible.
+// Assertion-style error handling, not available in ICU, was changed to
+// parameter "pinning" similar to UnicodeString.
+//
+// In addition, this is only a partial port of the original Google code,
+// limited to what was needed so far. The (nearly) complete original code
+// is in the ICU svn repository at icuhtml/trunk/design/strings/contrib
+// (see ICU ticket 6765, r25517).
+
+#ifndef __BYTESTREAM_H__
+#define __BYTESTREAM_H__
+
+/**
+ * \file
+ * \brief C++ API: Interface for writing bytes, and implementation classes.
+ */
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/std_string.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A ByteSink can be filled with bytes.
+ * @stable ICU 4.2
+ */
+class U_COMMON_API ByteSink : public UMemory {
+public:
+  /**
+   * Default constructor.
+   * @stable ICU 4.2
+   */
+  ByteSink() { }
+  /**
+   * Virtual destructor.
+   * @stable ICU 4.2
+   */
+  virtual ~ByteSink() { }
+
+  /**
+   * Append "bytes[0,n-1]" to this.
+   * @param bytes the pointer to the bytes
+   * @param n the number of bytes; must be non-negative
+   * @stable ICU 4.2
+   */
+  virtual void Append(const char* bytes, int32_t n) = 0;
+
+  /**
+   * Returns a writable buffer for appending and writes the buffer's capacity to
+   * *result_capacity. Guarantees *result_capacity>=min_capacity.
+   * May return a pointer to the caller-owned scratch buffer which must have
+   * scratch_capacity>=min_capacity.
+   * The returned buffer is only valid until the next operation
+   * on this ByteSink.
+   *
+   * After writing at most *result_capacity bytes, call Append() with the
+   * pointer returned from this function and the number of bytes written.
+   * Many Append() implementations will avoid copying bytes if this function
+   * returned an internal buffer.
+   *
+   * Partial usage example:
+   *  int32_t capacity;
+   *  char* buffer = sink->GetAppendBuffer(..., &capacity);
+   *  ... Write n bytes into buffer, with n <= capacity.
+   *  sink->Append(buffer, n);
+   * In many implementations, that call to Append will avoid copying bytes.
+   *
+   * If the ByteSink allocates or reallocates an internal buffer, it should use
+   * the desired_capacity_hint if appropriate.
+   * If a caller cannot provide a reasonable guess at the desired capacity,
+   * it should pass desired_capacity_hint=0.
+   *
+   * If a non-scratch buffer is returned, the caller may only pass
+   * a prefix to it to Append().
+   * That is, it is not correct to pass an interior pointer to Append().
+   *
+   * The default implementation always returns the scratch buffer.
+   *
+   * @param min_capacity required minimum capacity of the returned buffer;
+   *                     must be non-negative
+   * @param desired_capacity_hint desired capacity of the returned buffer;
+   *                              must be non-negative
+   * @param scratch default caller-owned buffer
+   * @param scratch_capacity capacity of the scratch buffer
+   * @param result_capacity pointer to an integer which will be set to the
+   *                        capacity of the returned buffer
+   * @return a buffer with *result_capacity>=min_capacity
+   * @stable ICU 4.2
+   */
+  virtual char* GetAppendBuffer(int32_t min_capacity,
+                                int32_t desired_capacity_hint,
+                                char* scratch, int32_t scratch_capacity,
+                                int32_t* result_capacity);
+
+  /**
+   * Flush internal buffers.
+   * Some byte sinks use internal buffers or provide buffering
+   * and require calling Flush() at the end of the stream.
+   * The ByteSink should be ready for further Append() calls after Flush().
+   * The default implementation of Flush() does nothing.
+   * @stable ICU 4.2
+   */
+  virtual void Flush();
+
+private:
+  ByteSink(const ByteSink &); // copy constructor not implemented
+  ByteSink &operator=(const ByteSink &); // assignment operator not implemented
+};
+
+// -------------------------------------------------------------
+// Some standard implementations
+
+/** 
+ * Implementation of ByteSink that writes to a flat byte array,
+ * with bounds-checking:
+ * This sink will not write more than capacity bytes to outbuf.
+ * If more than capacity bytes are Append()ed, then excess bytes are ignored,
+ * and Overflowed() will return true.
+ * Overflow does not cause a runtime error.
+ * @stable ICU 4.2
+ */
+class U_COMMON_API CheckedArrayByteSink : public ByteSink {
+public:
+  /**
+   * Constructs a ByteSink that will write to outbuf[0..capacity-1].
+   * @param outbuf buffer to write to
+   * @param capacity size of the buffer
+   * @stable ICU 4.2
+   */
+  CheckedArrayByteSink(char* outbuf, int32_t capacity);
+  /**
+   * Returns the sink to its original state, without modifying the buffer.
+   * Useful for reusing both the buffer and the sink for multiple streams.
+   * Resets the state to NumberOfBytesWritten()=NumberOfBytesAppended()=0
+   * and Overflowed()=FALSE.
+   * @return *this
+   * @draft ICU 4.6
+   */
+  virtual CheckedArrayByteSink& Reset();
+  /**
+   * Append "bytes[0,n-1]" to this.
+   * @param bytes the pointer to the bytes
+   * @param n the number of bytes; must be non-negative
+   * @stable ICU 4.2
+   */
+  virtual void Append(const char* bytes, int32_t n);
+  /**
+   * Returns a writable buffer for appending and writes the buffer's capacity to
+   * *result_capacity. For details see the base class documentation.
+   * @param min_capacity required minimum capacity of the returned buffer;
+   *                     must be non-negative
+   * @param desired_capacity_hint desired capacity of the returned buffer;
+   *                              must be non-negative
+   * @param scratch default caller-owned buffer
+   * @param scratch_capacity capacity of the scratch buffer
+   * @param result_capacity pointer to an integer which will be set to the
+   *                        capacity of the returned buffer
+   * @return a buffer with *result_capacity>=min_capacity
+   * @stable ICU 4.2
+   */
+  virtual char* GetAppendBuffer(int32_t min_capacity,
+                                int32_t desired_capacity_hint,
+                                char* scratch, int32_t scratch_capacity,
+                                int32_t* result_capacity);
+  /**
+   * Returns the number of bytes actually written to the sink.
+   * @return number of bytes written to the buffer
+   * @stable ICU 4.2
+   */
+  int32_t NumberOfBytesWritten() const { return size_; }
+  /**
+   * Returns true if any bytes were discarded, i.e., if there was an
+   * attempt to write more than 'capacity' bytes.
+   * @return TRUE if more than 'capacity' bytes were Append()ed
+   * @stable ICU 4.2
+   */
+  UBool Overflowed() const { return overflowed_; }
+  /**
+   * Returns the number of bytes appended to the sink.
+   * If Overflowed() then NumberOfBytesAppended()>NumberOfBytesWritten()
+   * else they return the same number.
+   * @return number of bytes written to the buffer
+   * @draft ICU 4.6
+   */
+  int32_t NumberOfBytesAppended() const { return appended_; }
+private:
+  char* outbuf_;
+  const int32_t capacity_;
+  int32_t size_;
+  int32_t appended_;
+  UBool overflowed_;
+  CheckedArrayByteSink(); ///< default constructor not implemented 
+  CheckedArrayByteSink(const CheckedArrayByteSink &); ///< copy constructor not implemented
+  CheckedArrayByteSink &operator=(const CheckedArrayByteSink &); ///< assignment operator not implemented
+};
+
+#if U_HAVE_STD_STRING
+
+/** 
+ * Implementation of ByteSink that writes to a "string".
+ * The StringClass is usually instantiated with a std::string.
+ * @stable ICU 4.2
+ */
+template<typename StringClass>
+class StringByteSink : public ByteSink {
+ public:
+  /**
+   * Constructs a ByteSink that will append bytes to the dest string.
+   * @param dest pointer to string object to append to
+   * @stable ICU 4.2
+   */
+  StringByteSink(StringClass* dest) : dest_(dest) { }
+  /**
+   * Append "bytes[0,n-1]" to this.
+   * @param data the pointer to the bytes
+   * @param n the number of bytes; must be non-negative
+   * @stable ICU 4.2
+   */
+  virtual void Append(const char* data, int32_t n) { dest_->append(data, n); }
+ private:
+  StringClass* dest_;
+  StringByteSink(); ///< default constructor not implemented 
+  StringByteSink(const StringByteSink &); ///< copy constructor not implemented
+  StringByteSink &operator=(const StringByteSink &); ///< assignment operator not implemented
+};
+
+#endif
+
+U_NAMESPACE_END
+
+#endif  // __BYTESTREAM_H__
diff --git a/source/common/unicode/caniter.h b/source/common/unicode/caniter.h
new file mode 100644
index 0000000..446d73d
--- /dev/null
+++ b/source/common/unicode/caniter.h
@@ -0,0 +1,206 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2010, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+
+#ifndef CANITER_H
+#define CANITER_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+
+/**
+ * \file
+ * \brief C++ API: Canonical Iterator
+ */
+ 
+/** Should permutation skip characters with combining class zero
+ *  Should be either TRUE or FALSE. This is a compile time option
+ *  @stable ICU 2.4
+ */
+#ifndef CANITER_SKIP_ZEROES
+#define CANITER_SKIP_ZEROES TRUE
+#endif
+
+U_NAMESPACE_BEGIN
+
+class Hashtable;
+class Normalizer2;
+class Normalizer2Impl;
+
+/**
+ * This class allows one to iterate through all the strings that are canonically equivalent to a given
+ * string. For example, here are some sample results:
+Results for: {LATIN CAPITAL LETTER A WITH RING ABOVE}{LATIN SMALL LETTER D}{COMBINING DOT ABOVE}{COMBINING CEDILLA}
+1: \\u0041\\u030A\\u0064\\u0307\\u0327
+ = {LATIN CAPITAL LETTER A}{COMBINING RING ABOVE}{LATIN SMALL LETTER D}{COMBINING DOT ABOVE}{COMBINING CEDILLA}
+2: \\u0041\\u030A\\u0064\\u0327\\u0307
+ = {LATIN CAPITAL LETTER A}{COMBINING RING ABOVE}{LATIN SMALL LETTER D}{COMBINING CEDILLA}{COMBINING DOT ABOVE}
+3: \\u0041\\u030A\\u1E0B\\u0327
+ = {LATIN CAPITAL LETTER A}{COMBINING RING ABOVE}{LATIN SMALL LETTER D WITH DOT ABOVE}{COMBINING CEDILLA}
+4: \\u0041\\u030A\\u1E11\\u0307
+ = {LATIN CAPITAL LETTER A}{COMBINING RING ABOVE}{LATIN SMALL LETTER D WITH CEDILLA}{COMBINING DOT ABOVE}
+5: \\u00C5\\u0064\\u0307\\u0327
+ = {LATIN CAPITAL LETTER A WITH RING ABOVE}{LATIN SMALL LETTER D}{COMBINING DOT ABOVE}{COMBINING CEDILLA}
+6: \\u00C5\\u0064\\u0327\\u0307
+ = {LATIN CAPITAL LETTER A WITH RING ABOVE}{LATIN SMALL LETTER D}{COMBINING CEDILLA}{COMBINING DOT ABOVE}
+7: \\u00C5\\u1E0B\\u0327
+ = {LATIN CAPITAL LETTER A WITH RING ABOVE}{LATIN SMALL LETTER D WITH DOT ABOVE}{COMBINING CEDILLA}
+8: \\u00C5\\u1E11\\u0307
+ = {LATIN CAPITAL LETTER A WITH RING ABOVE}{LATIN SMALL LETTER D WITH CEDILLA}{COMBINING DOT ABOVE}
+9: \\u212B\\u0064\\u0307\\u0327
+ = {ANGSTROM SIGN}{LATIN SMALL LETTER D}{COMBINING DOT ABOVE}{COMBINING CEDILLA}
+10: \\u212B\\u0064\\u0327\\u0307
+ = {ANGSTROM SIGN}{LATIN SMALL LETTER D}{COMBINING CEDILLA}{COMBINING DOT ABOVE}
+11: \\u212B\\u1E0B\\u0327
+ = {ANGSTROM SIGN}{LATIN SMALL LETTER D WITH DOT ABOVE}{COMBINING CEDILLA}
+12: \\u212B\\u1E11\\u0307
+ = {ANGSTROM SIGN}{LATIN SMALL LETTER D WITH CEDILLA}{COMBINING DOT ABOVE}
+ *<br>Note: the code is intended for use with small strings, and is not suitable for larger ones,
+ * since it has not been optimized for that situation.
+ * Note, CanonicalIterator is not intended to be subclassed.
+ * @author M. Davis
+ * @author C++ port by V. Weinstein
+ * @stable ICU 2.4
+ */
+class U_COMMON_API CanonicalIterator : public UObject {
+public:
+    /**
+     * Construct a CanonicalIterator object
+     * @param source    string to get results for
+     * @param status    Fill-in parameter which receives the status of this operation.
+     * @stable ICU 2.4
+     */
+    CanonicalIterator(const UnicodeString &source, UErrorCode &status);
+
+    /** Destructor
+     *  Cleans pieces
+     * @stable ICU 2.4
+     */
+    virtual ~CanonicalIterator();
+
+    /**
+     * Gets the NFD form of the current source we are iterating over.
+     * @return gets the source: NOTE: it is the NFD form of source
+     * @stable ICU 2.4
+     */
+    UnicodeString getSource();
+
+    /**
+     * Resets the iterator so that one can start again from the beginning.
+     * @stable ICU 2.4
+     */
+    void reset();
+
+    /**
+     * Get the next canonically equivalent string.
+     * <br><b>Warning: The strings are not guaranteed to be in any particular order.</b>
+     * @return the next string that is canonically equivalent. A bogus string is returned when
+     * the iteration is done.
+     * @stable ICU 2.4
+     */
+    UnicodeString next();
+
+    /**
+     * Set a new source for this iterator. Allows object reuse.
+     * @param newSource     the source string to iterate against. This allows the same iterator to be used
+     *                     while changing the source string, saving object creation.
+     * @param status        Fill-in parameter which receives the status of this operation.
+     * @stable ICU 2.4
+     */
+    void setSource(const UnicodeString &newSource, UErrorCode &status);
+
+    /**
+     * Dumb recursive implementation of permutation.
+     * TODO: optimize
+     * @param source     the string to find permutations for
+     * @param skipZeros  determine if skip zeros
+     * @param result     the results in a set.
+     * @param status       Fill-in parameter which receives the status of this operation.
+     * @internal
+     */
+    static void U_EXPORT2 permute(UnicodeString &source, UBool skipZeros, Hashtable *result, UErrorCode &status);
+
+    /**
+     * 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:
+    // ===================== PRIVATES ==============================
+    // private default constructor
+    CanonicalIterator();
+
+
+    /**
+     * Copy constructor. Private for now.
+     * @internal
+     */
+    CanonicalIterator(const CanonicalIterator& other);
+
+    /**
+     * Assignment operator. Private for now.
+     * @internal
+     */
+    CanonicalIterator& operator=(const CanonicalIterator& other);
+
+    // fields
+    UnicodeString source;
+    UBool done;
+
+    // 2 dimensional array holds the pieces of the string with
+    // their different canonically equivalent representations
+    UnicodeString **pieces;
+    int32_t pieces_length;
+    int32_t *pieces_lengths;
+
+    // current is used in iterating to combine pieces
+    int32_t *current;
+    int32_t current_length;
+
+    // transient fields
+    UnicodeString buffer;
+
+    const Normalizer2 &nfd;
+    const Normalizer2Impl &nfcImpl;
+
+    // we have a segment, in NFD. Find all the strings that are canonically equivalent to it.
+    UnicodeString *getEquivalents(const UnicodeString &segment, int32_t &result_len, UErrorCode &status); //private String[] getEquivalents(String segment)
+
+    //Set getEquivalents2(String segment);
+    Hashtable *getEquivalents2(Hashtable *fillinResult, const UChar *segment, int32_t segLen, UErrorCode &status);
+    //Hashtable *getEquivalents2(const UnicodeString &segment, int32_t segLen, UErrorCode &status);
+
+    /**
+     * See if the decomposition of cp2 is at segment starting at segmentPos
+     * (with canonical rearrangment!)
+     * If so, take the remainder, and return the equivalents
+     */
+    //Set extract(int comp, String segment, int segmentPos, StringBuffer buffer);
+    Hashtable *extract(Hashtable *fillinResult, UChar32 comp, const UChar *segment, int32_t segLen, int32_t segmentPos, UErrorCode &status);
+    //Hashtable *extract(UChar32 comp, const UnicodeString &segment, int32_t segLen, int32_t segmentPos, UErrorCode &status);
+
+    void cleanPieces();
+
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_NORMALIZATION */
+
+#endif
diff --git a/source/common/unicode/chariter.h b/source/common/unicode/chariter.h
new file mode 100644
index 0000000..12fc924
--- /dev/null
+++ b/source/common/unicode/chariter.h
@@ -0,0 +1,716 @@
+/*
+********************************************************************
+*
+*   Copyright (C) 1997-2005, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+********************************************************************
+*/
+
+#ifndef CHARITER_H
+#define CHARITER_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+/**
+ * \file
+ * \brief C++ API: Character Iterator
+ */
+ 
+U_NAMESPACE_BEGIN
+/**
+ * Abstract class that defines an API for forward-only iteration
+ * on text objects.
+ * This is a minimal interface for iteration without random access
+ * or backwards iteration. It is especially useful for wrapping
+ * streams with converters into an object for collation or
+ * normalization.
+ *
+ * <p>Characters can be accessed in two ways: as code units or as
+ * code points.
+ * Unicode code points are 21-bit integers and are the scalar values
+ * of Unicode characters. ICU uses the type UChar32 for them.
+ * Unicode code units are the storage units of a given
+ * Unicode/UCS Transformation Format (a character encoding scheme).
+ * With UTF-16, all code points can be represented with either one
+ * or two code units ("surrogates").
+ * String storage is typically based on code units, while properties
+ * of characters are typically determined using code point values.
+ * Some processes may be designed to work with sequences of code units,
+ * or it may be known that all characters that are important to an
+ * algorithm can be represented with single code units.
+ * Other processes will need to use the code point access functions.</p>
+ *
+ * <p>ForwardCharacterIterator provides nextPostInc() to access
+ * a code unit and advance an internal position into the text object,
+ * similar to a <code>return text[position++]</code>.<br>
+ * It provides next32PostInc() to access a code point and advance an internal
+ * position.</p>
+ *
+ * <p>next32PostInc() assumes that the current position is that of
+ * the beginning of a code point, i.e., of its first code unit.
+ * After next32PostInc(), this will be true again.
+ * In general, access to code units and code points in the same
+ * iteration loop should not be mixed. In UTF-16, if the current position
+ * is on a second code unit (Low Surrogate), then only that code unit
+ * is returned even by next32PostInc().</p>
+ *
+ * <p>For iteration with either function, there are two ways to
+ * check for the end of the iteration. When there are no more
+ * characters in the text object:
+ * <ul>
+ * <li>The hasNext() function returns FALSE.</li>
+ * <li>nextPostInc() and next32PostInc() return DONE
+ *     when one attempts to read beyond the end of the text object.</li>
+ * </ul>
+ *
+ * Example:
+ * \code 
+ * void function1(ForwardCharacterIterator &it) {
+ *     UChar32 c;
+ *     while(it.hasNext()) {
+ *         c=it.next32PostInc();
+ *         // use c
+ *     }
+ * }
+ *
+ * void function1(ForwardCharacterIterator &it) {
+ *     UChar c;
+ *     while((c=it.nextPostInc())!=ForwardCharacterIterator::DONE) {
+ *         // use c
+ *      }
+ *  }
+ * \endcode
+ * </p>
+ *
+ * @stable ICU 2.0
+ */
+class U_COMMON_API ForwardCharacterIterator : public UObject {
+public:
+    /**
+     * Value returned by most of ForwardCharacterIterator's functions
+     * when the iterator has reached the limits of its iteration.
+     * @stable ICU 2.0
+     */
+    enum { DONE = 0xffff };
+    
+    /**
+     * Destructor.  
+     * @stable ICU 2.0
+     */
+    virtual ~ForwardCharacterIterator();
+    
+    /**
+     * Returns true when both iterators refer to the same
+     * character in the same character-storage object.  
+     * @param that The ForwardCharacterIterator to be compared for equality
+     * @return true when both iterators refer to the same
+     * character in the same character-storage object
+     * @stable ICU 2.0
+     */
+    virtual UBool operator==(const ForwardCharacterIterator& that) const = 0;
+    
+    /**
+     * Returns true when the iterators refer to different
+     * text-storage objects, or to different characters in the
+     * same text-storage object.  
+     * @param that The ForwardCharacterIterator to be compared for inequality
+     * @return true when the iterators refer to different
+     * text-storage objects, or to different characters in the
+     * same text-storage object
+     * @stable ICU 2.0
+     */
+    inline UBool operator!=(const ForwardCharacterIterator& that) const;
+    
+    /**
+     * Generates a hash code for this iterator.  
+     * @return the hash code.
+     * @stable ICU 2.0
+     */
+    virtual int32_t hashCode(void) const = 0;
+    
+    /**
+     * Returns a UClassID for this ForwardCharacterIterator ("poor man's
+     * RTTI").<P> Despite the fact that this function is public,
+     * DO NOT CONSIDER IT PART OF CHARACTERITERATOR'S API! 
+     * @return a UClassID for this ForwardCharacterIterator 
+     * @stable ICU 2.0
+     */
+    virtual UClassID getDynamicClassID(void) const = 0;
+    
+    /**
+     * Gets the current code unit for returning and advances to the next code unit
+     * in the iteration range
+     * (toward endIndex()).  If there are
+     * no more code units to return, returns DONE.
+     * @return the current code unit.
+     * @stable ICU 2.0
+     */
+    virtual UChar         nextPostInc(void) = 0;
+    
+    /**
+     * Gets the current code point for returning and advances to the next code point
+     * in the iteration range
+     * (toward endIndex()).  If there are
+     * no more code points to return, returns DONE.
+     * @return the current code point.
+     * @stable ICU 2.0
+     */
+    virtual UChar32       next32PostInc(void) = 0;
+    
+    /**
+     * Returns FALSE if there are no more code units or code points
+     * at or after the current position in the iteration range.
+     * This is used with nextPostInc() or next32PostInc() in forward
+     * iteration.
+     * @returns FALSE if there are no more code units or code points
+     * at or after the current position in the iteration range.
+     * @stable ICU 2.0
+     */
+    virtual UBool        hasNext() = 0;
+    
+protected:
+    /** Default constructor to be overridden in the implementing class. @stable ICU 2.0*/
+    ForwardCharacterIterator();
+    
+    /** Copy constructor to be overridden in the implementing class. @stable ICU 2.0*/
+    ForwardCharacterIterator(const ForwardCharacterIterator &other);
+    
+    /**
+     * Assignment operator to be overridden in the implementing class.
+     * @stable ICU 2.0
+     */
+    ForwardCharacterIterator &operator=(const ForwardCharacterIterator&) { return *this; }
+};
+
+/**
+ * Abstract class that defines an API for iteration
+ * on text objects.
+ * This is an interface for forward and backward iteration
+ * and random access into a text object.
+ *
+ * <p>The API provides backward compatibility to the Java and older ICU
+ * CharacterIterator classes but extends them significantly:
+ * <ol>
+ * <li>CharacterIterator is now a subclass of ForwardCharacterIterator.</li>
+ * <li>While the old API functions provided forward iteration with
+ *     "pre-increment" semantics, the new one also provides functions
+ *     with "post-increment" semantics. They are more efficient and should
+ *     be the preferred iterator functions for new implementations.
+ *     The backward iteration always had "pre-decrement" semantics, which
+ *     are efficient.</li>
+ * <li>Just like ForwardCharacterIterator, it provides access to
+ *     both code units and code points. Code point access versions are available
+ *     for the old and the new iteration semantics.</li>
+ * <li>There are new functions for setting and moving the current position
+ *     without returning a character, for efficiency.</li>
+ * </ol>
+ *
+ * See ForwardCharacterIterator for examples for using the new forward iteration
+ * functions. For backward iteration, there is also a hasPrevious() function
+ * that can be used analogously to hasNext().
+ * The old functions work as before and are shown below.</p>
+ *
+ * <p>Examples for some of the new functions:</p>
+ *
+ * Forward iteration with hasNext():
+ * \code
+ * void forward1(CharacterIterator &it) {
+ *     UChar32 c;
+ *     for(it.setToStart(); it.hasNext();) {
+ *         c=it.next32PostInc();
+ *         // use c
+ *     }
+ *  }
+ * \endcode
+ * Forward iteration more similar to loops with the old forward iteration,
+ * showing a way to convert simple for() loops:
+ * \code
+ * void forward2(CharacterIterator &it) {
+ *     UChar c;
+ *     for(c=it.firstPostInc(); c!=CharacterIterator::DONE; c=it.nextPostInc()) {
+ *          // use c
+ *      }
+ * }
+ * \endcode
+ * Backward iteration with setToEnd() and hasPrevious():
+ * \code
+ *  void backward1(CharacterIterator &it) {
+ *      UChar32 c;
+ *      for(it.setToEnd(); it.hasPrevious();) {
+ *         c=it.previous32();
+ *          // use c
+ *      }
+ *  }
+ * \endcode
+ * Backward iteration with a more traditional for() loop:
+ * \code
+ * void backward2(CharacterIterator &it) {
+ *     UChar c;
+ *     for(c=it.last(); c!=CharacterIterator::DONE; c=it.previous()) {
+ *         // use c
+ *      }
+ *  }
+ * \endcode
+ *
+ * Example for random access:
+ * \code
+ *  void random(CharacterIterator &it) {
+ *      // set to the third code point from the beginning
+ *      it.move32(3, CharacterIterator::kStart);
+ *      // get a code point from here without moving the position
+ *      UChar32 c=it.current32();
+ *      // get the position
+ *      int32_t pos=it.getIndex();
+ *      // get the previous code unit
+ *      UChar u=it.previous();
+ *      // move back one more code unit
+ *      it.move(-1, CharacterIterator::kCurrent);
+ *      // set the position back to where it was
+ *      // and read the same code point c and move beyond it
+ *      it.setIndex(pos);
+ *      if(c!=it.next32PostInc()) {
+ *          exit(1); // CharacterIterator inconsistent
+ *      }
+ *  }
+ * \endcode
+ *
+ * <p>Examples, especially for the old API:</p>
+ *
+ * Function processing characters, in this example simple output
+ * <pre>
+ * \code
+ *  void processChar( UChar c )
+ *  {
+ *      cout << " " << c;
+ *  }
+ * \endcode
+ * </pre>
+ * Traverse the text from start to finish
+ * <pre> 
+ * \code
+ *  void traverseForward(CharacterIterator& iter)
+ *  {
+ *      for(UChar c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
+ *          processChar(c);
+ *      }
+ *  }
+ * \endcode
+ * </pre>
+ * Traverse the text backwards, from end to start
+ * <pre>
+ * \code
+ *  void traverseBackward(CharacterIterator& iter)
+ *  {
+ *      for(UChar c = iter.last(); c != CharacterIterator.DONE; c = iter.previous()) {
+ *          processChar(c);
+ *      }
+ *  }
+ * \endcode
+ * </pre>
+ * Traverse both forward and backward from a given position in the text. 
+ * Calls to notBoundary() in this example represents some additional stopping criteria.
+ * <pre>
+ * \code
+ * void traverseOut(CharacterIterator& iter, int32_t pos)
+ * {
+ *      UChar c;
+ *      for (c = iter.setIndex(pos);
+ *      c != CharacterIterator.DONE && (Unicode::isLetter(c) || Unicode::isDigit(c));
+ *          c = iter.next()) {}
+ *      int32_t end = iter.getIndex();
+ *      for (c = iter.setIndex(pos);
+ *          c != CharacterIterator.DONE && (Unicode::isLetter(c) || Unicode::isDigit(c));
+ *          c = iter.previous()) {}
+ *      int32_t start = iter.getIndex() + 1;
+ *  
+ *      cout << "start: " << start << " end: " << end << endl;
+ *      for (c = iter.setIndex(start); iter.getIndex() < end; c = iter.next() ) {
+ *          processChar(c);
+ *     }
+ *  }
+ * \endcode
+ * </pre>
+ * Creating a StringCharacterIterator and calling the test functions
+ * <pre>
+ * \code
+ *  void CharacterIterator_Example( void )
+ *   {
+ *       cout << endl << "===== CharacterIterator_Example: =====" << endl;
+ *       UnicodeString text("Ein kleiner Satz.");
+ *       StringCharacterIterator iterator(text);
+ *       cout << "----- traverseForward: -----------" << endl;
+ *       traverseForward( iterator );
+ *       cout << endl << endl << "----- traverseBackward: ----------" << endl;
+ *       traverseBackward( iterator );
+ *       cout << endl << endl << "----- traverseOut: ---------------" << endl;
+ *       traverseOut( iterator, 7 );
+ *       cout << endl << endl << "-----" << endl;
+ *   }
+ * \endcode
+ * </pre>
+ *
+ * @stable ICU 2.0
+ */
+class U_COMMON_API CharacterIterator : public ForwardCharacterIterator {
+public:
+    /**
+     * Origin enumeration for the move() and move32() functions.
+     * @stable ICU 2.0
+     */
+    enum EOrigin { kStart, kCurrent, kEnd };
+
+    /**
+     * Returns a pointer to a new CharacterIterator of the same
+     * concrete class as this one, and referring to the same
+     * character in the same text-storage object as this one.  The
+     * caller is responsible for deleting the new clone.  
+     * @return a pointer to a new CharacterIterator
+     * @stable ICU 2.0
+     */
+    virtual CharacterIterator* clone(void) const = 0;
+
+    /**
+     * Sets the iterator to refer to the first code unit in its
+     * iteration range, and returns that code unit.
+     * This can be used to begin an iteration with next().
+     * @return the first code unit in its iteration range.
+     * @stable ICU 2.0
+     */
+    virtual UChar         first(void) = 0;
+
+    /**
+     * Sets the iterator to refer to the first code unit in its
+     * iteration range, returns that code unit, and moves the position
+     * to the second code unit. This is an alternative to setToStart()
+     * for forward iteration with nextPostInc().
+     * @return the first code unit in its iteration range.
+     * @stable ICU 2.0
+     */
+    virtual UChar         firstPostInc(void);
+
+    /**
+     * Sets the iterator to refer to the first code point in its
+     * iteration range, and returns that code unit,
+     * This can be used to begin an iteration with next32().
+     * Note that an iteration with next32PostInc(), beginning with,
+     * e.g., setToStart() or firstPostInc(), is more efficient.
+     * @return the first code point in its iteration range.
+     * @stable ICU 2.0
+     */
+    virtual UChar32       first32(void) = 0;
+
+    /**
+     * Sets the iterator to refer to the first code point in its
+     * iteration range, returns that code point, and moves the position
+     * to the second code point. This is an alternative to setToStart()
+     * for forward iteration with next32PostInc().
+     * @return the first code point in its iteration range.
+     * @stable ICU 2.0
+     */
+    virtual UChar32       first32PostInc(void);
+
+    /**
+     * Sets the iterator to refer to the first code unit or code point in its
+     * iteration range. This can be used to begin a forward
+     * iteration with nextPostInc() or next32PostInc().
+     * @return the start position of the iteration range
+     * @stable ICU 2.0
+     */
+    inline int32_t    setToStart();
+
+    /**
+     * Sets the iterator to refer to the last code unit in its
+     * iteration range, and returns that code unit.
+     * This can be used to begin an iteration with previous().
+     * @return the last code unit.
+     * @stable ICU 2.0
+     */
+    virtual UChar         last(void) = 0;
+        
+    /**
+     * Sets the iterator to refer to the last code point in its
+     * iteration range, and returns that code unit.
+     * This can be used to begin an iteration with previous32().
+     * @return the last code point.
+     * @stable ICU 2.0
+     */
+    virtual UChar32       last32(void) = 0;
+
+    /**
+     * Sets the iterator to the end of its iteration range, just behind
+     * the last code unit or code point. This can be used to begin a backward
+     * iteration with previous() or previous32().
+     * @return the end position of the iteration range
+     * @stable ICU 2.0
+     */
+    inline int32_t    setToEnd();
+
+    /**
+     * Sets the iterator to refer to the "position"-th code unit
+     * in the text-storage object the iterator refers to, and
+     * returns that code unit.  
+     * @param position the "position"-th code unit in the text-storage object
+     * @return the "position"-th code unit.
+     * @stable ICU 2.0
+     */
+    virtual UChar         setIndex(int32_t position) = 0;
+
+    /**
+     * Sets the iterator to refer to the beginning of the code point
+     * that contains the "position"-th code unit
+     * in the text-storage object the iterator refers to, and
+     * returns that code point.
+     * The current position is adjusted to the beginning of the code point
+     * (its first code unit).
+     * @param position the "position"-th code unit in the text-storage object
+     * @return the "position"-th code point.
+     * @stable ICU 2.0
+     */
+    virtual UChar32       setIndex32(int32_t position) = 0;
+
+    /**
+     * Returns the code unit the iterator currently refers to. 
+     * @return the current code unit. 
+     * @stable ICU 2.0
+     */
+    virtual UChar         current(void) const = 0;
+        
+    /**
+     * Returns the code point the iterator currently refers to.  
+     * @return the current code point.
+     * @stable ICU 2.0
+     */
+    virtual UChar32       current32(void) const = 0;
+        
+    /**
+     * Advances to the next code unit in the iteration range
+     * (toward endIndex()), and returns that code unit.  If there are
+     * no more code units to return, returns DONE.
+     * @return the next code unit.
+     * @stable ICU 2.0
+     */
+    virtual UChar         next(void) = 0;
+        
+    /**
+     * Advances to the next code point in the iteration range
+     * (toward endIndex()), and returns that code point.  If there are
+     * no more code points to return, returns DONE.
+     * Note that iteration with "pre-increment" semantics is less
+     * efficient than iteration with "post-increment" semantics
+     * that is provided by next32PostInc().
+     * @return the next code point.
+     * @stable ICU 2.0
+     */
+    virtual UChar32       next32(void) = 0;
+        
+    /**
+     * Advances to the previous code unit in the iteration range
+     * (toward startIndex()), and returns that code unit.  If there are
+     * no more code units to return, returns DONE.  
+     * @return the previous code unit.
+     * @stable ICU 2.0
+     */
+    virtual UChar         previous(void) = 0;
+
+    /**
+     * Advances to the previous code point in the iteration range
+     * (toward startIndex()), and returns that code point.  If there are
+     * no more code points to return, returns DONE. 
+     * @return the previous code point. 
+     * @stable ICU 2.0
+     */
+    virtual UChar32       previous32(void) = 0;
+
+    /**
+     * Returns FALSE if there are no more code units or code points
+     * before the current position in the iteration range.
+     * This is used with previous() or previous32() in backward
+     * iteration.
+     * @return FALSE if there are no more code units or code points
+     * before the current position in the iteration range, return TRUE otherwise.
+     * @stable ICU 2.0
+     */
+    virtual UBool        hasPrevious() = 0;
+
+    /**
+     * Returns the numeric index in the underlying text-storage
+     * object of the character returned by first().  Since it's
+     * possible to create an iterator that iterates across only
+     * part of a text-storage object, this number isn't
+     * necessarily 0.  
+     * @returns the numeric index in the underlying text-storage
+     * object of the character returned by first().
+     * @stable ICU 2.0
+     */
+    inline int32_t       startIndex(void) const;
+        
+    /**
+     * Returns the numeric index in the underlying text-storage
+     * object of the position immediately BEYOND the character
+     * returned by last().  
+     * @return the numeric index in the underlying text-storage
+     * object of the position immediately BEYOND the character
+     * returned by last().
+     * @stable ICU 2.0
+     */
+    inline int32_t       endIndex(void) const;
+        
+    /**
+     * Returns the numeric index in the underlying text-storage
+     * object of the character the iterator currently refers to
+     * (i.e., the character returned by current()).  
+     * @return the numberic index in the text-storage object of 
+     * the character the iterator currently refers to
+     * @stable ICU 2.0
+     */
+    inline int32_t       getIndex(void) const;
+
+    /**
+     * Returns the length of the entire text in the underlying
+     * text-storage object.
+     * @return the length of the entire text in the text-storage object
+     * @stable ICU 2.0
+     */
+    inline int32_t           getLength() const;
+
+    /**
+     * Moves the current position relative to the start or end of the
+     * iteration range, or relative to the current position itself.
+     * The movement is expressed in numbers of code units forward
+     * or backward by specifying a positive or negative delta.
+     * @param delta the position relative to origin. A positive delta means forward;
+     * a negative delta means backward.
+     * @param origin Origin enumeration {kStart, kCurrent, kEnd}
+     * @return the new position
+     * @stable ICU 2.0
+     */
+    virtual int32_t      move(int32_t delta, EOrigin origin) = 0;
+
+    /**
+     * Moves the current position relative to the start or end of the
+     * iteration range, or relative to the current position itself.
+     * The movement is expressed in numbers of code points forward
+     * or backward by specifying a positive or negative delta.
+     * @param delta the position relative to origin. A positive delta means forward;
+     * a negative delta means backward.
+     * @param origin Origin enumeration {kStart, kCurrent, kEnd}
+     * @return the new position
+     * @stable ICU 2.0
+     */
+    virtual int32_t      move32(int32_t delta, EOrigin origin) = 0;
+
+    /**
+     * Copies the text under iteration into the UnicodeString
+     * referred to by "result".  
+     * @param result Receives a copy of the text under iteration.  
+     * @stable ICU 2.0
+     */
+    virtual void            getText(UnicodeString&  result) = 0;
+
+protected:
+    /**
+     * Empty constructor.
+     * @stable ICU 2.0
+     */
+    CharacterIterator();
+
+    /**
+     * Constructor, just setting the length field in this base class.
+     * @stable ICU 2.0
+     */
+    CharacterIterator(int32_t length);
+
+    /**
+     * Constructor, just setting the length and position fields in this base class.
+     * @stable ICU 2.0
+     */
+    CharacterIterator(int32_t length, int32_t position);
+
+    /**
+     * Constructor, just setting the length, start, end, and position fields in this base class.
+     * @stable ICU 2.0
+     */
+    CharacterIterator(int32_t length, int32_t textBegin, int32_t textEnd, int32_t position);
+  
+    /**
+     * Copy constructor.
+     *
+     * @param that The CharacterIterator to be copied
+     * @stable ICU 2.0
+     */
+    CharacterIterator(const CharacterIterator &that);
+
+    /**
+     * Assignment operator.  Sets this CharacterIterator to have the same behavior,
+     * as the one passed in.
+     * @param that The CharacterIterator passed in.
+     * @return the newly set CharacterIterator.
+     * @stable ICU 2.0
+     */
+    CharacterIterator &operator=(const CharacterIterator &that);
+
+    /**
+     * Base class text length field.
+     * Necessary this for correct getText() and hashCode().
+     * @stable ICU 2.0
+     */
+    int32_t textLength;
+
+    /**
+     * Base class field for the current position.
+     * @stable ICU 2.0
+     */
+    int32_t  pos;
+
+    /**
+     * Base class field for the start of the iteration range.
+     * @stable ICU 2.0
+     */
+    int32_t  begin;
+
+    /**
+     * Base class field for the end of the iteration range.
+     * @stable ICU 2.0
+     */
+    int32_t  end;
+};
+
+inline UBool
+ForwardCharacterIterator::operator!=(const ForwardCharacterIterator& that) const {
+    return !operator==(that);
+}
+
+inline int32_t
+CharacterIterator::setToStart() {
+    return move(0, kStart);
+}
+
+inline int32_t
+CharacterIterator::setToEnd() {
+    return move(0, kEnd);
+}
+
+inline int32_t
+CharacterIterator::startIndex(void) const {
+    return begin;
+}
+
+inline int32_t
+CharacterIterator::endIndex(void) const {
+    return end;
+}
+
+inline int32_t
+CharacterIterator::getIndex(void) const {
+    return pos;
+}
+
+inline int32_t
+CharacterIterator::getLength(void) const {
+    return textLength;
+}
+
+U_NAMESPACE_END
+#endif
diff --git a/source/common/unicode/dbbi.h b/source/common/unicode/dbbi.h
new file mode 100644
index 0000000..c7984ef
--- /dev/null
+++ b/source/common/unicode/dbbi.h
@@ -0,0 +1,41 @@
+/*
+**********************************************************************
+*   Copyright (C) 1999-2006 IBM Corp. All rights reserved.
+**********************************************************************
+*   Date        Name        Description
+*   12/1/99    rgillam     Complete port from Java.
+*   01/13/2000 helena      Added UErrorCode to ctors.
+**********************************************************************
+*/
+
+#ifndef DBBI_H
+#define DBBI_H
+
+#include "unicode/rbbi.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+/**
+ * \file
+ * \brief C++ API: Dictionary Based Break Iterator
+ */
+ 
+U_NAMESPACE_BEGIN
+
+/**
+ * An obsolete subclass of RuleBasedBreakIterator. Handling of dictionary-
+ * based break iteration has been folded into the base class. This class
+ * is deprecated as of ICU 3.6.
+ */
+ 
+#ifndef U_HIDE_DEPRECATED_API
+
+typedef RuleBasedBreakIterator DictionaryBasedBreakIterator;
+
+#endif
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
+
+#endif
diff --git a/source/common/unicode/docmain.h b/source/common/unicode/docmain.h
new file mode 100644
index 0000000..bf45c51
--- /dev/null
+++ b/source/common/unicode/docmain.h
@@ -0,0 +1,207 @@
+/********************************************************************
+ * COPYRIGHT: 
+ * Copyright (c) 1997-2010, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ *
+ *  FILE NAME: DOCMAIN.h
+ *
+ *   Date          Name        Description
+ *   12/11/2000    Ram        Creation.
+ */
+
+/* This file contains documentation for Doxygen and doesnot have
+ * any significance with respect to C or C++ API
+ */
+
+/*! \mainpage
+ *
+ * \section API API Reference Usage
+ * 
+ * <h3>C++ Programmers:</h3>
+ * <p>Use <a href="hierarchy.html">Class Hierarchy</a> or <a href="classes.html"> Alphabetical List </a>
+ * or <a href="annotated.html"> Compound List</a>
+ * to find the class you are interested in. For example, to find BreakIterator,
+ * you can go to the <a href="classes.html"> Alphabetical List</a>, then click on
+ * "BreakIterator". Once you are at the class, you will find an inheritance
+ * chart, a list of the public members, a detailed description of the class,
+ * then detailed member descriptions.</p>
+ * 
+ * <h3>C Programmers:</h3>
+ * <p>Use <a href="#Module">Module List</a> or <a href="globals.html">File Members</a>
+ * to find a list of all the functions and constants.
+ * For example, to find BreakIterator functions you would click on
+ * <a href="files.html"> File List</a>,
+ * then find "ubrk.h" and click on it. You will find descriptions of Defines,
+ * Typedefs, Enumerations, and Functions, with detailed descriptions below.
+ * If you want to find a specific function, such as ubrk_next(), then click
+ * first on <a href="globals.html"> File Members</a>, then use your browser
+ * Find dialog to search for "ubrk_next()".</p>
+ *
+ *
+ * <h3>API References for Previous Releases</h3>
+ * <p>The API References for each release of ICU are also available as
+ * a zip file from the ICU 
+ * <a href="http://icu-project.org/download/">download page</a>.</p>
+ *
+ * <hr>
+ *
+ * <h2>Architecture (User's Guide)</h2>
+ * <ul>
+ *   <li><a href="http://icu-project.org/userguide/">Introduction</a></li>
+ *   <li><a href="http://icu-project.org/userguide/i18n.html">Internationalization</a></li>
+ *   <li><a href="http://icu-project.org/userguide/design.html">Locale Model</a></li>
+ *   <li><a href="http://icu-project.org/userguide/design.html">Multithreading</a></li>
+ *   <li><a href="http://icu-project.org/userguide/conversion.html">Conversion</a></li>
+ *   <li><a href="http://icu-project.org/userguide/design.html">Error Handling</a></li>
+ * </ul>
+ *
+ * <hr>
+ *\htmlonly <h2><a NAME="Module">Module List</a></h2> \endhtmlonly
+ * <table border="1" cols="3" align="center">
+ *   <tr>
+ *     <td><strong>Module Name</strong></td>
+ *     <td><strong>C</strong></td>
+ *     <td><strong>C++</strong></td>
+ *   </tr>
+ *   <tr>
+ *     <td>Basic Types and Constants</td>
+ *     <td>utypes.h</td>
+ *     <td>utypes.h</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Strings and Character Iteration</td>
+ *     <td>ustring.h, utf.h</td>
+ *     <td>UnicodeString, CharacterIterator</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Unicode Character<br>Properties and Names</td>
+ *     <td>uchar.h</td>
+ *     <td>uchar.h C API</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Codepage Conversion</td>
+ *     <td>ucnv.h</td>
+ *     <td>ucnv.h C API</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Unicode Text Compression</td>
+ *     <td>ucnv.h <br> (encoding name "SCSU" or "BOCU-1")</td>
+ *     <td>ucnv.h C API</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Locales </td>
+ *     <td>uloc.h</a></td>
+ *     <td>Locale</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Resource Bundles</td>
+ *     <td>ures.h</td>
+ *     <td>ResourceBundle</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Normalization</td>
+ *     <td>unorm.h</td>
+ *     <td>Normalizer</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Calendars</td>
+ *     <td>ucal.h</td>
+ *     <td>Calendar</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Date and Time Formatting</td>
+ *     <td>udat.h</td>
+ *     <td>DateFormat</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Message Formatting</td>
+ *     <td>umsg.h</td>
+ *     <td>MessageFormat</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Number Formatting</td>
+ *     <td>unum.h</td>
+ *     <td>NumberFormat</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Number Spellout <br> (Rule Based Number Formatting)</td>
+ *     <td>unum.h <br> (use UNUM_SPELLOUT)</td>
+ *     <td>RuleBasedNumberFormat</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Text Transformation <br> (Transliteration)</td>
+ *     <td>utrans.h</td>
+ *     <td>Transliterator</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Bidirectional Algorithm</td>
+ *     <td>ubidi.h</td>
+ *     <td>ubidi.h C API</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Arabic Shaping</td>
+ *     <td>ushape.h</td>
+ *     <td>ushape.h C API</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Collation</td>
+ *     <td>ucol.h</td>
+ *     <td>Collator</td>
+ *   </tr>
+ *   <tr>
+ *     <td>String Searching</td>
+ *     <td>usearch.h</td>
+ *     <td>StringSearch</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Text Boundary Analysis <br> (Break Iteration)</td>
+ *     <td>ubrk.h</td>
+ *     <td>BreakIterator</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Unicode Set</td>
+ *     <td>uset.h</td>
+ *     <td>UnicodeSet</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Regular Expressions</td>
+ *     <td>uregex.h</td>
+ *     <td>RegexPattern, RegexMatcher</td>
+ *   </tr>
+ *   <tr>
+ *     <td>StringPrep</td>
+ *     <td>usprep.h</td>
+ *     <td>usprep.h C API</td>
+ *   </tr>
+ *   <tr>
+ *     <td>International Domain Names in Applications</td>
+ *     <td>uidna.h</td>
+ *     <td>uidna.h C API</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Identifier Spoofing & Confusability</td>
+ *     <td>uspoof.h</td>
+ *     <td>uspoof.h C API</td>
+ *   <tr>
+ *     <td>Universal Time Scale</td>
+ *     <td>utmscale.h</td>
+ *     <td>utmscale.h C API</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Basic Layout Engine Types and Constants</td>
+ *     <td>(no C API)</td>
+ *     <td>LETypes.h</td>
+ *   </tr>
+ *   <tr>
+ *     <td>Complex Text Layout</td>
+ *     <td>(no C API)</td>
+ *     <td>LayoutEngine, ParagraphLayout</td>
+ *   </tr>
+ *   <tr>
+ *     <td>ICU I/O</td>
+ *     <td>ustdio.h</td>
+ *     <td>ustream.h</td>
+ *   </tr>
+ * </table>
+ * <i>This main page is generated from docmain.h</i>
+ */
diff --git a/source/common/unicode/dtintrv.h b/source/common/unicode/dtintrv.h
new file mode 100644
index 0000000..5bacce8
--- /dev/null
+++ b/source/common/unicode/dtintrv.h
@@ -0,0 +1,158 @@
+/*
+*******************************************************************************
+* Copyright (C) 2008-2009, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File DTINTRV.H 
+*
+*******************************************************************************
+*/
+
+#ifndef __DTINTRV_H__
+#define __DTINTRV_H__
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+
+/**
+ * \file
+ * \brief C++ API: Date Interval data type
+ */
+
+
+U_NAMESPACE_BEGIN
+
+
+/**
+ * This class represents a date interval.
+ * It is a pair of UDate representing from UDate 1 to UDate 2.
+ * @stable ICU 4.0
+**/
+class U_COMMON_API DateInterval : public UObject {
+public:
+
+    /** 
+     * Construct a DateInterval given a from date and a to date.
+     * @param fromDate  The from date in date interval.
+     * @param toDate    The to date in date interval.
+     * @stable ICU 4.0
+     */
+    DateInterval(UDate fromDate, UDate toDate);
+
+    /**
+     * destructor
+     * @stable ICU 4.0
+     */
+    virtual ~DateInterval();
+ 
+    /** 
+     * Get the from date.
+     * @return  the from date in dateInterval.
+     * @stable ICU 4.0
+     */
+    UDate getFromDate() const;
+
+    /** 
+     * Get the to date.
+     * @return  the to date in dateInterval.
+     * @stable ICU 4.0
+     */
+    UDate getToDate() 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;
+
+    
+    /**
+     * Copy constructor.
+     * @stable ICU 4.0
+     */
+    DateInterval(const DateInterval& other);
+
+    /**
+     * Default assignment operator
+     * @stable ICU 4.0
+     */
+    DateInterval& operator=(const DateInterval&);
+
+    /**
+     * Equality operator.
+     * @return TRUE if the two DateIntervals are the same
+     * @stable ICU 4.0
+     */
+    virtual UBool operator==(const DateInterval& other) const;
+
+    /**
+     * Non-equality operator
+     * @return TRUE if the two DateIntervals are not the same
+     * @stable ICU 4.0
+     */
+    UBool operator!=(const DateInterval& other) const;
+
+
+    /**
+     * clone this object. 
+     * The caller owns the result and should delete it when done.
+     * @return a cloned DateInterval
+     * @stable ICU 4.0
+     */
+     virtual DateInterval* clone() const;
+
+private:
+    /** 
+     * Default constructor, not implemented.
+     */
+    DateInterval();
+
+    UDate fromDate;
+    UDate toDate;
+
+} ;// end class DateInterval
+
+
+inline UDate 
+DateInterval::getFromDate() const { 
+    return fromDate; 
+}
+
+
+inline UDate 
+DateInterval::getToDate() const { 
+    return toDate; 
+}
+
+
+inline UBool 
+DateInterval::operator!=(const DateInterval& other) const { 
+    return ( !operator==(other) );
+}
+
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/unicode/errorcode.h b/source/common/unicode/errorcode.h
new file mode 100644
index 0000000..0d9d2bd
--- /dev/null
+++ b/source/common/unicode/errorcode.h
@@ -0,0 +1,137 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2009-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  errorcode.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2009mar10
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __ERRORCODE_H__
+#define __ERRORCODE_H__
+
+/**
+ * \file 
+ * \brief C++ API: ErrorCode class intended to make it easier to use
+ *                 ICU C and C++ APIs from C++ user code.
+ */
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Wrapper class for UErrorCode, with conversion operators for direct use
+ * in ICU C and C++ APIs.
+ * Intended to be used as a base class, where a subclass overrides
+ * the handleFailure() function so that it throws an exception,
+ * does an assert(), logs an error, etc.
+ * This is not an abstract base class. This class can be used and instantiated
+ * by itself, although it will be more useful when subclassed.
+ *
+ * Features:
+ * - The constructor initializes the internal UErrorCode to U_ZERO_ERROR,
+ *   removing one common source of errors.
+ * - Same use in C APIs taking a UErrorCode * (pointer)
+ *   and C++ taking UErrorCode & (reference) via conversion operators.
+ * - Possible automatic checking for success when it goes out of scope.
+ *
+ * Note: For automatic checking for success in the destructor, a subclass
+ * must implement such logic in its own destructor because the base class
+ * destructor cannot call a subclass function (like handleFailure()).
+ * The ErrorCode base class destructor does nothing.
+ *
+ * Note also: While it is possible for a destructor to throw an exception,
+ * it is generally unsafe to do so. This means that in a subclass the destructor
+ * and the handleFailure() function may need to take different actions.
+ *
+ * Sample code:
+ * \code
+ *   class IcuErrorCode: public icu::ErrorCode {
+ *   public:
+ *     virtual ~IcuErrorCode() {
+ *       // Safe because our handleFailure() does not throw exceptions.
+ *       if(isFailure()) { handleFailure(); }
+ *     }
+ *   protected:
+ *     virtual void handleFailure() const {
+ *       log_failure(u_errorName(errorCode));
+ *       exit(errorCode);
+ *     }
+ *   };
+ *   IcuErrorCode error_code;
+ *   UConverter *cnv = ucnv_open("Shift-JIS", error_code);
+ *   length = ucnv_fromUChars(dest, capacity, src, length, error_code);
+ *   ucnv_close(cnv);
+ *   // IcuErrorCode destructor checks for success.
+ * \endcode
+ *
+ * @stable ICU 4.2
+ */
+class U_COMMON_API ErrorCode: public UMemory {
+public:
+    /**
+     * Default constructor. Initializes its UErrorCode to U_ZERO_ERROR.
+     * @stable ICU 4.2
+     */
+    ErrorCode() : errorCode(U_ZERO_ERROR) {}
+    /** Destructor, does nothing. See class documentation for details. @stable ICU 4.2 */
+    virtual ~ErrorCode() {}
+    /** Conversion operator, returns a reference. @stable ICU 4.2 */
+    operator UErrorCode & () { return errorCode; }
+    /** Conversion operator, returns a pointer. @stable ICU 4.2 */
+    operator UErrorCode * () { return &errorCode; }
+    /** Tests for U_SUCCESS(). @stable ICU 4.2 */
+    UBool isSuccess() const { return U_SUCCESS(errorCode); }
+    /** Tests for U_FAILURE(). @stable ICU 4.2 */
+    UBool isFailure() const { return U_FAILURE(errorCode); }
+    /** Returns the UErrorCode value. @stable ICU 4.2 */
+    UErrorCode get() const { return errorCode; }
+    /** Sets the UErrorCode value. @stable ICU 4.2 */
+    void set(UErrorCode value) { errorCode=value; }
+    /** Returns the UErrorCode value and resets it to U_ZERO_ERROR. @stable ICU 4.2 */
+    UErrorCode reset();
+    /**
+     * Asserts isSuccess().
+     * In other words, this method checks for a failure code,
+     * and the base class handles it like this:
+     * \code
+     *   if(isFailure()) { handleFailure(); }
+     * \endcode
+     * @stable ICU 4.4
+     */
+    void assertSuccess() const;
+    /**
+     * Return a string for the UErrorCode value.
+     * The string will be the same as the name of the error code constant
+     * in the UErrorCode enum.
+     * @stable ICU 4.4
+     */
+    const char* errorName() const;
+
+protected:
+    /**
+     * Internal UErrorCode, accessible to subclasses.
+     * @stable ICU 4.2
+     */
+    UErrorCode errorCode;
+    /**
+     * Called by assertSuccess() if isFailure() is true.
+     * A subclass should override this function to deal with a failure code:
+     * Throw an exception, log an error, terminate the program, or similar.
+     * @stable ICU 4.2
+     */
+    virtual void handleFailure() const {}
+};
+
+U_NAMESPACE_END
+
+#endif  // __ERRORCODE_H__
diff --git a/source/common/unicode/icudataver.h b/source/common/unicode/icudataver.h
new file mode 100644
index 0000000..0f12c97
--- /dev/null
+++ b/source/common/unicode/icudataver.h
@@ -0,0 +1,57 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2009-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*/
+
+#ifndef __ICU_DATA_VER_H__
+#define __ICU_DATA_VER_H__
+
+#include "unicode/utypes.h"
+
+/**
+ * @internal ICU 4.4
+ */
+#define U_ICU_VERSION_BUNDLE "icuver"
+
+/**
+ * @internal ICU 4.4
+ */
+#define U_ICU_STD_BUNDLE "icustd"
+
+/**
+ * @internal ICU 4.4
+ */
+#define U_ICU_DATA_KEY "DataVersion"
+
+/**
+ * This function loads up icuver and compares the data version to the wired-in U_ICU_DATA_VERSION.
+ * If icuver shows something less than U_ICU_DATA_VERSION it returns TRUE, else FALSE. The version
+ * found will be returned in the first fillin parameter (if non-null), and *isModified will be set
+ * to TRUE if "icustd" is NOT found. Thus, if the data has been repackaged or modified, "icustd"
+ * (standard ICU) will be missing, and the function will alert the caller that the data is not standard.
+ * 
+ * @param dataVersionFillin icuver data version information to be filled in if not-null
+ * @param isModifiedFillin if the data is not standard if not-null
+ * @param status stores the error code from the calls to resource bundle
+ *
+ * @return TRUE if U_ICU_DATA_VERSION is newer than icuver, else FALSE
+ * 
+ * @internal ICU 4.4
+ */
+U_INTERNAL UBool U_EXPORT2 u_isDataOlder(UVersionInfo dataVersionFillin, UBool *isModifiedFillin, UErrorCode *status);
+
+/**
+ * Retrieves the data version from icuver and stores it in dataVersionFillin.
+ * 
+ * @param dataVersionFillin icuver data version information to be filled in if not-null
+ * @param status stores the error code from the calls to resource bundle
+ * 
+ * @internal ICU 4.4
+ */
+U_INTERNAL void U_EXPORT2 u_getDataVersion(UVersionInfo dataVersionFillin, UErrorCode *status);
+
+#endif
diff --git a/source/common/unicode/icuplug.h b/source/common/unicode/icuplug.h
new file mode 100644
index 0000000..ac413b9
--- /dev/null
+++ b/source/common/unicode/icuplug.h
@@ -0,0 +1,370 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2009-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+*  FILE NAME : icuplug.h
+*
+*   Date         Name        Description
+*   10/29/2009   sl          New.
+******************************************************************************
+*/
+
+/**
+ * \file
+ * \brief C API: ICU Plugin API 
+ *
+ * <h2>C API: ICU Plugin API</h2>
+ *
+ * <p>C API allowing run-time loadable modules that extend or modify ICU functionality.</p>
+ *
+ * <h3>Loading and Configuration</h3>
+ *
+ * <p>At ICU startup time, the environment variable "ICU_PLUGINS" will be 
+ * queried for a directory name.  If it is not set, the preprocessor symbol 
+ * "DEFAULT_ICU_PLUGINS" will be checked for a default value.</p>
+ *
+ * <p>Within the above-named directory, the file  "icuplugins##.txt" will be 
+ * opened, if present, where ## is the major+minor number of the currently 
+ * running ICU (such as, 44 for ICU 4.4, thus icuplugins44.txt)</p>
+ *
+ * <p>The configuration file has this format:</p>
+ *
+ * <ul>
+ * <li>Hash (#) begins a comment line</li>
+ * 
+ * <li>Non-comment lines have two or three components:
+ * LIBRARYNAME     ENTRYPOINT     [ CONFIGURATION .. ]</li>
+ *
+ * <li>Tabs or spaces separate the three items.</li>
+ *
+ * <li>LIBRARYNAME is the name of a shared library, either a short name if 
+ * it is on the loader path,  or a full pathname.</li>
+ *
+ * <li>ENTRYPOINT is the short (undecorated) symbol name of the plugin's 
+ * entrypoint, as above.</li>
+ *
+ * <li>CONFIGURATION is the entire rest of the line . It's passed as-is to 
+ * the plugin.</li>
+ * </ul>
+ *
+ * <p>An example configuration file is, in its entirety:</p>
+ *
+ * \code
+ * # this is icuplugins44.txt
+ * testplug.dll    myPlugin        hello=world
+ * \endcode
+ * <p>Plugins are categorized as "high" or "low" level.  Low level are those 
+ * which must be run BEFORE high level plugins, and before any operations 
+ * which cause ICU to be 'initialized'.  If a plugin is low level but 
+ * causes ICU to allocate memory or become initialized, that plugin is said 
+ * to cause a 'level change'. </p>
+ *
+ * <p>At load time, ICU first queries all plugins to determine their level, 
+ * then loads all 'low' plugins first, and then loads all 'high' plugins.  
+ * Plugins are otherwise loaded in the order listed in the configuration file.</p>
+ * 
+ * <h3>Implementing a Plugin</h3>
+ * \code
+ * U_CAPI UPlugTokenReturn U_EXPORT2 
+ * myPlugin (UPlugData *plug, UPlugReason reason, UErrorCode *status) {
+ *   if(reason==UPLUG_REASON_QUERY) {
+ *      uplug_setPlugName(plug, "Simple Plugin");
+ *      uplug_setPlugLevel(plug, UPLUG_LEVEL_HIGH);
+ *    } else if(reason==UPLUG_REASON_LOAD) {
+ *       ... Set up some ICU things here.... 
+ *    } else if(reason==UPLUG_REASON_UNLOAD) {
+ *       ... unload, clean up ...
+ *    }
+ *   return UPLUG_TOKEN;
+ *  }
+ * \endcode
+ *
+ * <p>The UPlugData*  is an opaque pointer to the plugin-specific data, and is 
+ * used in all other API calls.</p>
+ *
+ * <p>The API contract is:</p>
+ * <ol><li>The plugin MUST always return UPLUG_TOKEN as a return value- to 
+ * indicate that it is a valid plugin.</li>
+ *
+ * <li>When the 'reason' parameter is set to UPLUG_REASON_QUERY,  the 
+ * plugin MUST call uplug_setPlugLevel() to indicate whether it is a high 
+ * level or low level plugin.</li>
+ *
+ * <li>When the 'reason' parameter is UPLUG_REASON_QUERY, the plugin 
+ * SHOULD call uplug_setPlugName to indicate a human readable plugin name.</li></ol>
+ * 
+ *
+ * \internal ICU 4.4 Technology Preview
+ */
+
+
+#ifndef ICUPLUG_H
+#define ICUPLUG_H
+
+#include "unicode/utypes.h"
+
+
+/* === Basic types === */
+
+/**
+ * @{
+ * Opaque structure passed to/from a plugin. 
+ * use the APIs to access it.
+ * @internal ICU 4.4 Technology Preview
+ */
+
+struct UPlugData;
+typedef struct UPlugData UPlugData;
+
+/** @} */
+
+/**
+ * Random Token to identify a valid ICU plugin. Plugins must return this 
+ * from the entrypoint.
+ * @internal ICU 4.4 Technology Preview
+ */
+#define UPLUG_TOKEN 0x54762486
+
+/**
+ * Max width of names, symbols, and configuration strings
+ * @internal ICU 4.4 Technology Preview
+ */
+#define UPLUG_NAME_MAX              100
+
+
+/**
+ * Return value from a plugin entrypoint. 
+ * Must always be set to UPLUG_TOKEN
+ * @see UPLUG_TOKEN
+ * @internal ICU 4.4 Technology Preview
+ */
+typedef uint32_t UPlugTokenReturn;
+
+/**
+ * Reason code for the entrypoint's call
+ * @internal ICU 4.4 Technology Preview
+ */
+typedef enum {
+    UPLUG_REASON_QUERY = 0,     /**< The plugin is being queried for info. **/
+    UPLUG_REASON_LOAD = 1,     /**< The plugin is being loaded. **/
+    UPLUG_REASON_UNLOAD = 2,   /**< The plugin is being unloaded. **/
+    UPLUG_REASON_COUNT         /**< count of known reasons **/
+} UPlugReason;
+
+
+/**
+ * Level of plugin loading
+ *     INITIAL:  UNKNOWN
+ *       QUERY:   INVALID ->  { LOW | HIGH }
+ *     ERR -> INVALID
+ * @internal ICU 4.4 Technology Preview
+ */
+typedef enum {
+    UPLUG_LEVEL_INVALID = 0,     /**< The plugin is invalid, hasn't called uplug_setLevel, or can't load. **/
+    UPLUG_LEVEL_UNKNOWN = 1,     /**< The plugin is waiting to be installed. **/
+    UPLUG_LEVEL_LOW     = 2,     /**< The plugin must be called before u_init completes **/
+    UPLUG_LEVEL_HIGH    = 3,     /**< The plugin can run at any time. **/
+    UPLUG_LEVEL_COUNT         /**< count of known reasons **/
+} UPlugLevel;
+
+/**
+ * Entrypoint for an ICU plugin.
+ * @param plug the UPlugData handle. 
+ * @param status the plugin's extended status code.
+ * @return A valid plugin must return UPLUG_TOKEN
+ * @internal ICU 4.4 Technology Preview
+ */
+typedef UPlugTokenReturn (U_EXPORT2 UPlugEntrypoint) (
+                  UPlugData *plug,
+                  UPlugReason reason,
+                  UErrorCode *status);
+
+/* === Needed for Implementing === */
+
+/**
+ * Request that this plugin not be unloaded at cleanup time.
+ * This is appropriate for plugins which cannot be cleaned up.
+ * @see u_cleanup()
+ * @param plug plugin
+ * @param dontUnload  set true if this plugin can't be unloaded
+ * @internal ICU 4.4 Technology Preview
+ */
+U_CAPI void U_EXPORT2 
+uplug_setPlugNoUnload(UPlugData *plug, UBool dontUnload);
+
+/**
+ * Set the level of this plugin.
+ * @param plug plugin data handle
+ * @param level the level of this plugin
+ * @internal ICU 4.4 Technology Preview
+ */
+U_CAPI void U_EXPORT2
+uplug_setPlugLevel(UPlugData *plug, UPlugLevel level);
+
+/**
+ * Get the level of this plugin.
+ * @param plug plugin data handle
+ * @return the level of this plugin
+ * @internal ICU 4.4 Technology Preview
+ */
+U_CAPI UPlugLevel U_EXPORT2
+uplug_getPlugLevel(UPlugData *plug);
+
+/**
+ * Get the lowest level of plug which can currently load.
+ * For example, if UPLUG_LEVEL_LOW is returned, then low level plugins may load
+ * if UPLUG_LEVEL_HIGH is returned, then only high level plugins may load.
+ * @return the lowest level of plug which can currently load
+ * @internal ICU 4.4 Technology Preview
+ */
+U_CAPI UPlugLevel U_EXPORT2
+uplug_getCurrentLevel(void);
+
+
+/**
+ * Get plug load status
+ * @return The error code of this plugin's load attempt.
+ * @internal ICU 4.4 Technology Preview
+ */
+U_CAPI UErrorCode U_EXPORT2
+uplug_getPlugLoadStatus(UPlugData *plug); 
+
+/**
+ * Set the human-readable name of this plugin.
+ * @param plug plugin data handle
+ * @param name the name of this plugin. The first UPLUG_NAME_MAX characters willi be copied into a new buffer.
+ * @internal ICU 4.4 Technology Preview
+ */
+U_CAPI void U_EXPORT2
+uplug_setPlugName(UPlugData *plug, const char *name);
+
+/**
+ * Get the human-readable name of this plugin.
+ * @param plug plugin data handle
+ * @return the name of this plugin
+ * @internal ICU 4.4 Technology Preview
+ */
+U_CAPI const char * U_EXPORT2
+uplug_getPlugName(UPlugData *plug);
+
+/**
+ * Return the symbol name for this plugin, if known.
+ * @param plug plugin data handle
+ * @return the symbol name, or NULL
+ * @internal ICU 4.4 Technology Preview
+ */
+U_CAPI const char * U_EXPORT2
+uplug_getSymbolName(UPlugData *plug);
+
+/**
+ * Return the library name for this plugin, if known.
+ * @param plug plugin data handle
+ * @param status error code
+ * @return the library name, or NULL
+ * @internal ICU 4.4 Technology Preview
+ */
+U_CAPI const char * U_EXPORT2
+uplug_getLibraryName(UPlugData *plug, UErrorCode *status);
+
+/**
+ * Return the library used for this plugin, if known.
+ * Plugins could use this to load data out of their 
+ * @param plug plugin data handle
+ * @return the library, or NULL
+ * @internal ICU 4.4 Technology Preview
+ */
+U_CAPI void * U_EXPORT2
+uplug_getLibrary(UPlugData *plug);
+
+/**
+ * Return the plugin-specific context data.
+ * @param plug plugin data handle
+ * @return the context, or NULL if not set
+ * @internal ICU 4.4 Technology Preview
+ */
+U_CAPI void * U_EXPORT2
+uplug_getContext(UPlugData *plug);
+
+/**
+ * Set the plugin-specific context data.
+ * @param plug plugin data handle
+ * @param context new context to set
+ * @internal ICU 4.4 Technology Preview
+ */
+U_CAPI void U_EXPORT2
+uplug_setContext(UPlugData *plug, void *context);
+
+
+/**
+ * Get the configuration string, if available.
+ * The string is in the platform default codepage.
+ * @param plug plugin data handle
+ * @return configuration string, or else null.
+ * @internal ICU 4.4 Technology Preview
+ */
+U_CAPI const char * U_EXPORT2
+uplug_getConfiguration(UPlugData *plug);
+
+/**
+ * Return all currently installed plugins, from newest to oldest
+ * Usage Example:
+ * \code
+ *    UPlugData *plug = NULL;
+ *    while(plug=uplug_nextPlug(plug)) {
+ *        ... do something with 'plug' ...
+ *    }
+ * \endcode
+ * Not thread safe- do not call while plugs are added or removed.
+ * @param prior pass in 'NULL' to get the first (most recent) plug, 
+ *  otherwise pass the value returned on a prior call to uplug_nextPlug
+ * @return the next oldest plugin, or NULL if no more.
+ * @internal ICU 4.4 Technology Preview
+ */
+U_CAPI UPlugData* U_EXPORT2
+uplug_nextPlug(UPlugData *prior);
+
+/**
+ * Inject a plugin as if it were loaded from a library.
+ * This is useful for testing plugins. 
+ * Note that it will have a 'NULL' library pointer associated
+ * with it, and therefore no llibrary will be closed at cleanup time.
+ * Low level plugins may not be able to load, as ordering can't be enforced.
+ * @param entrypoint entrypoint to install
+ * @param config user specified configuration string, if available, or NULL.
+ * @param status error result
+ * @return the new UPlugData associated with this plugin, or NULL if error.
+ * @internal ICU 4.4 Technology Preview
+ */
+U_CAPI UPlugData* U_EXPORT2
+uplug_loadPlugFromEntrypoint(UPlugEntrypoint *entrypoint, const char *config, UErrorCode *status);
+
+
+/**
+ * Inject a plugin from a library, as if the information came from a config file.
+ * Low level plugins may not be able to load, and ordering can't be enforced.
+ * @param libName DLL name to load
+ * @param sym symbol of plugin (UPlugEntrypoint function)
+ * @param config configuration string, or NULL
+ * @param status error result
+ * @return the new UPlugData associated with this plugin, or NULL if error.
+ * @internal ICU 4.4 Technology Preview
+ */
+U_CAPI UPlugData* U_EXPORT2
+uplug_loadPlugFromLibrary(const char *libName, const char *sym, const char *config, UErrorCode *status);
+
+/**
+ * Remove a plugin. 
+ * Will request the plugin to be unloaded, and close the library if needed
+ * @param plug plugin handle to close
+ * @param status error result
+ * @internal ICU 4.4 Technology Preview
+ */
+U_CAPI void U_EXPORT2
+uplug_removePlug(UPlugData *plug, UErrorCode *status);
+
+
+#endif
diff --git a/source/common/unicode/idna.h b/source/common/unicode/idna.h
new file mode 100644
index 0000000..4047d96
--- /dev/null
+++ b/source/common/unicode/idna.h
@@ -0,0 +1,321 @@
+/*
+*******************************************************************************
+*   Copyright (C) 2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*******************************************************************************
+*   file name:  idna.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2010mar05
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __IDNA_H__
+#define __IDNA_H__
+
+/**
+ * \file
+ * \brief C++ API: Internationalizing Domain Names in Applications (IDNA)
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_IDNA
+
+#include "unicode/bytestream.h"
+#include "unicode/stringpiece.h"
+#include "unicode/uidna.h"
+#include "unicode/unistr.h"
+
+U_NAMESPACE_BEGIN
+
+class U_COMMON_API IDNAInfo;
+
+/**
+ * Abstract base class for IDNA processing.
+ * See http://www.unicode.org/reports/tr46/
+ * and http://www.ietf.org/rfc/rfc3490.txt
+ *
+ * The IDNA class is not intended for public subclassing.
+ *
+ * This C++ API currently only implements UTS #46.
+ * The uidna.h C API implements both UTS #46 (functions using UIDNA service object)
+ * and IDNA2003 (functions that do not use a service object).
+ * @draft ICU 4.6
+ */
+class U_COMMON_API IDNA : public UObject {
+public:
+    /**
+     * Returns an IDNA instance which implements UTS #46.
+     * Returns an unmodifiable instance, owned by the caller.
+     * Cache it for multiple operations, and delete it when done.
+     * The instance is thread-safe, that is, it can be used concurrently.
+     *
+     * UTS #46 defines Unicode IDNA Compatibility Processing,
+     * updated to the latest version of Unicode and compatible with both
+     * IDNA2003 and IDNA2008.
+     *
+     * The worker functions use transitional processing, including deviation mappings,
+     * unless UIDNA_NONTRANSITIONAL_TO_ASCII or UIDNA_NONTRANSITIONAL_TO_UNICODE
+     * is used in which case the deviation characters are passed through without change.
+     *
+     * Disallowed characters are mapped to U+FFFD.
+     *
+     * For available options see the uidna.h header.
+     * Operations with the UTS #46 instance do not support the
+     * UIDNA_ALLOW_UNASSIGNED option.
+     *
+     * By default, the UTS #46 implementation allows all ASCII characters (as valid or mapped).
+     * When the UIDNA_USE_STD3_RULES option is used, ASCII characters other than
+     * letters, digits, hyphen (LDH) and dot/full stop are disallowed and mapped to U+FFFD.
+     *
+     * @param options Bit set to modify the processing and error checking.
+     *                See option bit set values in uidna.h.
+     * @param errorCode 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 UTS #46 IDNA instance, if successful
+     * @draft ICU 4.6
+     */
+    static IDNA *
+    createUTS46Instance(uint32_t options, UErrorCode &errorCode);
+
+    /**
+     * Converts a single domain name label into its ASCII form for DNS lookup.
+     * If any processing step fails, then info.hasErrors() will be TRUE and
+     * the result might not be an ASCII string.
+     * The label might be modified according to the types of errors.
+     * Labels with severe errors will be left in (or turned into) their Unicode form.
+     *
+     * The UErrorCode indicates an error only in exceptional cases,
+     * such as a U_MEMORY_ALLOCATION_ERROR.
+     *
+     * @param label Input domain name label
+     * @param dest Destination string object
+     * @param info Output container of IDNA processing details.
+     * @param errorCode 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 dest
+     * @draft ICU 4.6
+     */
+    virtual UnicodeString &
+    labelToASCII(const UnicodeString &label, UnicodeString &dest,
+                 IDNAInfo &info, UErrorCode &errorCode) const = 0;
+
+    /**
+     * Converts a single domain name label into its Unicode form for human-readable display.
+     * If any processing step fails, then info.hasErrors() will be TRUE.
+     * The label might be modified according to the types of errors.
+     *
+     * The UErrorCode indicates an error only in exceptional cases,
+     * such as a U_MEMORY_ALLOCATION_ERROR.
+     *
+     * @param label Input domain name label
+     * @param dest Destination string object
+     * @param info Output container of IDNA processing details.
+     * @param errorCode 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 dest
+     * @draft ICU 4.6
+     */
+    virtual UnicodeString &
+    labelToUnicode(const UnicodeString &label, UnicodeString &dest,
+                   IDNAInfo &info, UErrorCode &errorCode) const = 0;
+
+    /**
+     * Converts a whole domain name into its ASCII form for DNS lookup.
+     * If any processing step fails, then info.hasErrors() will be TRUE and
+     * the result might not be an ASCII string.
+     * The domain name might be modified according to the types of errors.
+     * Labels with severe errors will be left in (or turned into) their Unicode form.
+     *
+     * The UErrorCode indicates an error only in exceptional cases,
+     * such as a U_MEMORY_ALLOCATION_ERROR.
+     *
+     * @param name Input domain name
+     * @param dest Destination string object
+     * @param info Output container of IDNA processing details.
+     * @param errorCode 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 dest
+     * @draft ICU 4.6
+     */
+    virtual UnicodeString &
+    nameToASCII(const UnicodeString &name, UnicodeString &dest,
+                IDNAInfo &info, UErrorCode &errorCode) const = 0;
+
+    /**
+     * Converts a whole domain name into its Unicode form for human-readable display.
+     * If any processing step fails, then info.hasErrors() will be TRUE.
+     * The domain name might be modified according to the types of errors.
+     *
+     * The UErrorCode indicates an error only in exceptional cases,
+     * such as a U_MEMORY_ALLOCATION_ERROR.
+     *
+     * @param name Input domain name
+     * @param dest Destination string object
+     * @param info Output container of IDNA processing details.
+     * @param errorCode 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 dest
+     * @draft ICU 4.6
+     */
+    virtual UnicodeString &
+    nameToUnicode(const UnicodeString &name, UnicodeString &dest,
+                  IDNAInfo &info, UErrorCode &errorCode) const = 0;
+
+    // UTF-8 versions of the processing methods ---------------------------- ***
+
+    /**
+     * Converts a single domain name label into its ASCII form for DNS lookup.
+     * UTF-8 version of labelToASCII(), same behavior.
+     *
+     * @param label Input domain name label
+     * @param dest Destination byte sink; Flush()ed if successful
+     * @param info Output container of IDNA processing details.
+     * @param errorCode 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 dest
+     * @draft ICU 4.6
+     */
+    virtual void
+    labelToASCII_UTF8(const StringPiece &label, ByteSink &dest,
+                      IDNAInfo &info, UErrorCode &errorCode) const;
+
+    /**
+     * Converts a single domain name label into its Unicode form for human-readable display.
+     * UTF-8 version of labelToUnicode(), same behavior.
+     *
+     * @param label Input domain name label
+     * @param dest Destination byte sink; Flush()ed if successful
+     * @param info Output container of IDNA processing details.
+     * @param errorCode 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 dest
+     * @draft ICU 4.6
+     */
+    virtual void
+    labelToUnicodeUTF8(const StringPiece &label, ByteSink &dest,
+                       IDNAInfo &info, UErrorCode &errorCode) const;
+
+    /**
+     * Converts a whole domain name into its ASCII form for DNS lookup.
+     * UTF-8 version of nameToASCII(), same behavior.
+     *
+     * @param name Input domain name
+     * @param dest Destination byte sink; Flush()ed if successful
+     * @param info Output container of IDNA processing details.
+     * @param errorCode 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 dest
+     * @draft ICU 4.6
+     */
+    virtual void
+    nameToASCII_UTF8(const StringPiece &name, ByteSink &dest,
+                     IDNAInfo &info, UErrorCode &errorCode) const;
+
+    /**
+     * Converts a whole domain name into its Unicode form for human-readable display.
+     * UTF-8 version of nameToUnicode(), same behavior.
+     *
+     * @param name Input domain name
+     * @param dest Destination byte sink; Flush()ed if successful
+     * @param info Output container of IDNA processing details.
+     * @param errorCode 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 dest
+     * @draft ICU 4.6
+     */
+    virtual void
+    nameToUnicodeUTF8(const StringPiece &name, ByteSink &dest,
+                      IDNAInfo &info, UErrorCode &errorCode) const;
+
+private:
+    // No ICU "poor man's RTTI" for this class nor its subclasses.
+    virtual UClassID getDynamicClassID() const;
+};
+
+class UTS46;
+
+/**
+ * Output container for IDNA processing errors.
+ * The IDNAInfo class is not suitable for subclassing.
+ * @draft ICU 4.6
+ */
+class U_COMMON_API IDNAInfo : public UMemory {
+public:
+    /**
+     * Constructor for stack allocation.
+     * @draft ICU 4.6
+     */
+    IDNAInfo() : errors(0), labelErrors(0), isTransDiff(FALSE), isBiDi(FALSE), isOkBiDi(TRUE) {}
+    /**
+     * Were there IDNA processing errors?
+     * @return TRUE if there were processing errors
+     * @draft ICU 4.6
+     */
+    UBool hasErrors() const { return errors!=0; }
+    /**
+     * Returns a bit set indicating IDNA processing errors.
+     * See UIDNA_ERROR_... constants in uidna.h.
+     * @return bit set of processing errors
+     * @draft ICU 4.6
+     */
+    uint32_t getErrors() const { return errors; }
+    /**
+     * Returns TRUE if transitional and nontransitional processing produce different results.
+     * This is the case when the input label or domain name contains
+     * one or more deviation characters outside a Punycode label (see UTS #46).
+     * <ul>
+     * <li>With nontransitional processing, such characters are
+     * copied to the destination string.
+     * <li>With transitional processing, such characters are
+     * mapped (sharp s/sigma) or removed (joiner/nonjoiner).
+     * </ul>
+     * @return TRUE if transitional and nontransitional processing produce different results
+     * @draft ICU 4.6
+     */
+    UBool isTransitionalDifferent() const { return isTransDiff; }
+
+private:
+    friend class UTS46;
+
+    IDNAInfo(const IDNAInfo &other);  // no copying
+    IDNAInfo &operator=(const IDNAInfo &other);  // no copying
+
+    void reset() {
+        errors=labelErrors=0;
+        isTransDiff=FALSE;
+        isBiDi=FALSE;
+        isOkBiDi=TRUE;
+    }
+
+    uint32_t errors, labelErrors;
+    UBool isTransDiff;
+    UBool isBiDi;
+    UBool isOkBiDi;
+};
+
+U_NAMESPACE_END
+
+#endif  // UCONFIG_NO_IDNA
+#endif  // __IDNA_H__
diff --git a/source/common/unicode/localpointer.h b/source/common/unicode/localpointer.h
new file mode 100644
index 0000000..b76a1f8
--- /dev/null
+++ b/source/common/unicode/localpointer.h
@@ -0,0 +1,300 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2009-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  localpointer.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2009nov13
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __LOCALPOINTER_H__
+#define __LOCALPOINTER_H__
+
+/**
+ * \file 
+ * \brief C++ API: "Smart pointers" for use with and in ICU4C C++ code.
+ *
+ * These classes are inspired by
+ * - std::auto_ptr
+ * - boost::scoped_ptr & boost::scoped_array
+ * - Taligent Safe Pointers (TOnlyPointerTo)
+ *
+ * but none of those provide for all of the goals for ICU smart pointers:
+ * - Smart pointer owns the object and releases it when it goes out of scope.
+ * - No transfer of ownership via copy/assignment to reduce misuse. Simpler & more robust.
+ * - ICU-compatible: No exceptions.
+ * - Need to be able to orphan/release the pointer and its ownership.
+ * - Need variants for normal C++ object pointers, C++ arrays, and ICU C service objects.
+ *
+ * For details see http://site.icu-project.org/design/cpp/scoped_ptr
+ */
+
+#include "unicode/utypes.h"
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * "Smart pointer" base class; do not use directly: use LocalPointer etc.
+ *
+ * Base class for smart pointer classes that do not throw exceptions.
+ *
+ * Do not use this base class directly, since it does not delete its pointer.
+ * A subclass must implement methods that delete the pointer:
+ * Destructor and adoptInstead().
+ *
+ * There is no operator T *() provided because the programmer must decide
+ * whether to use getAlias() (without transfer of ownership) or orpan()
+ * (with transfer of ownership and NULLing of the pointer).
+ *
+ * @see LocalPointer
+ * @see LocalArray
+ * @see U_DEFINE_LOCAL_OPEN_POINTER
+ * @stable ICU 4.4
+ */
+template<typename T>
+class LocalPointerBase {
+public:
+    /**
+     * Constructor takes ownership.
+     * @param p simple pointer to an object that is adopted
+     * @stable ICU 4.4
+     */
+    explicit LocalPointerBase(T *p=NULL) : ptr(p) {}
+    /**
+     * Destructor deletes the object it owns.
+     * Subclass must override: Base class does nothing.
+     * @stable ICU 4.4
+     */
+    ~LocalPointerBase() { /* delete ptr; */ }
+    /**
+     * NULL check.
+     * @return TRUE if ==NULL
+     * @stable ICU 4.4
+     */
+    UBool isNull() const { return ptr==NULL; }
+    /**
+     * NULL check.
+     * @return TRUE if !=NULL
+     * @stable ICU 4.4
+     */
+    UBool isValid() const { return ptr!=NULL; }
+    /**
+     * Comparison with a simple pointer, so that existing code
+     * with ==NULL need not be changed.
+     * @param other simple pointer for comparison
+     * @return true if this pointer value equals other
+     * @stable ICU 4.4
+     */
+    bool operator==(const T *other) const { return ptr==other; }
+    /**
+     * Comparison with a simple pointer, so that existing code
+     * with !=NULL need not be changed.
+     * @param other simple pointer for comparison
+     * @return true if this pointer value differs from other
+     * @stable ICU 4.4
+     */
+    bool operator!=(const T *other) const { return ptr!=other; }
+    /**
+     * Access without ownership change.
+     * @return the pointer value
+     * @stable ICU 4.4
+     */
+    T *getAlias() const { return ptr; }
+    /**
+     * Access without ownership change.
+     * @return the pointer value as a reference
+     * @stable ICU 4.4
+     */
+    T &operator*() const { return *ptr; }
+    /**
+     * Access without ownership change.
+     * @return the pointer value
+     * @stable ICU 4.4
+     */
+    T *operator->() const { return ptr; }
+    /**
+     * Gives up ownership; the internal pointer becomes NULL.
+     * @return the pointer value;
+     *         caller becomes responsible for deleting the object
+     * @stable ICU 4.4
+     */
+    T *orphan() {
+        T *p=ptr;
+        ptr=NULL;
+        return p;
+    }
+    /**
+     * Deletes the object it owns,
+     * and adopts (takes ownership of) the one passed in.
+     * Subclass must override: Base class does not delete the object.
+     * @param p simple pointer to an object that is adopted
+     * @stable ICU 4.4
+     */
+    void adoptInstead(T *p) {
+        // delete ptr;
+        ptr=p;
+    }
+protected:
+    T *ptr;
+private:
+    // No comparison operators with other LocalPointerBases.
+    bool operator==(const LocalPointerBase &other);
+    bool operator!=(const LocalPointerBase &other);
+    // No ownership transfer: No copy constructor, no assignment operator.
+    LocalPointerBase(const LocalPointerBase &other);
+    void operator=(const LocalPointerBase &other);
+    // No heap allocation. Use only on the stack.
+    static void * U_EXPORT2 operator new(size_t size);
+    static void * U_EXPORT2 operator new[](size_t size);
+#if U_HAVE_PLACEMENT_NEW
+    static void * U_EXPORT2 operator new(size_t, void *ptr);
+#endif
+};
+
+/**
+ * "Smart pointer" class, deletes objects via the standard C++ delete operator.
+ * For most methods see the LocalPointerBase base class.
+ *
+ * Usage example:
+ * \code
+ * LocalPointer<UnicodeString> s(new UnicodeString((UChar32)0x50005));
+ * int32_t length=s->length();  // 2
+ * UChar lead=s->charAt(0);  // 0xd900
+ * if(some condition) { return; }  // no need to explicitly delete the pointer
+ * s.adoptInstead(new UnicodeString((UChar)0xfffc));
+ * length=s->length();  // 1
+ * // no need to explicitly delete the pointer
+ * \endcode
+ *
+ * @see LocalPointerBase
+ * @stable ICU 4.4
+ */
+template<typename T>
+class LocalPointer : public LocalPointerBase<T> {
+public:
+    /**
+     * Constructor takes ownership.
+     * @param p simple pointer to an object that is adopted
+     * @stable ICU 4.4
+     */
+    explicit LocalPointer(T *p=NULL) : LocalPointerBase<T>(p) {}
+    /**
+     * Destructor deletes the object it owns.
+     * @stable ICU 4.4
+     */
+    ~LocalPointer() {
+        delete LocalPointerBase<T>::ptr;
+    }
+    /**
+     * Deletes the object it owns,
+     * and adopts (takes ownership of) the one passed in.
+     * @param p simple pointer to an object that is adopted
+     * @stable ICU 4.4
+     */
+    void adoptInstead(T *p) {
+        delete LocalPointerBase<T>::ptr;
+        LocalPointerBase<T>::ptr=p;
+    }
+};
+
+/**
+ * "Smart pointer" class, deletes objects via the C++ array delete[] operator.
+ * For most methods see the LocalPointerBase base class.
+ * Adds operator[] for array item access.
+ *
+ * Usage example:
+ * \code
+ * LocalArray<UnicodeString> a(new UnicodeString[2]);
+ * a[0].append((UChar)0x61);
+ * if(some condition) { return; }  // no need to explicitly delete the array
+ * a.adoptInstead(new UnicodeString[4]);
+ * a[3].append((UChar)0x62).append((UChar)0x63).reverse();
+ * // no need to explicitly delete the array
+ * \endcode
+ *
+ * @see LocalPointerBase
+ * @stable ICU 4.4
+ */
+template<typename T>
+class LocalArray : public LocalPointerBase<T> {
+public:
+    /**
+     * Constructor takes ownership.
+     * @param p simple pointer to an array of T objects that is adopted
+     * @stable ICU 4.4
+     */
+    explicit LocalArray(T *p=NULL) : LocalPointerBase<T>(p) {}
+    /**
+     * Destructor deletes the array it owns.
+     * @stable ICU 4.4
+     */
+    ~LocalArray() {
+        delete[] LocalPointerBase<T>::ptr;
+    }
+    /**
+     * Deletes the array it owns,
+     * and adopts (takes ownership of) the one passed in.
+     * @param p simple pointer to an array of T objects that is adopted
+     * @stable ICU 4.4
+     */
+    void adoptInstead(T *p) {
+        delete[] LocalPointerBase<T>::ptr;
+        LocalPointerBase<T>::ptr=p;
+    }
+    /**
+     * Array item access (writable).
+     * No index bounds check.
+     * @param i array index
+     * @return reference to the array item
+     * @stable ICU 4.4
+     */
+    T &operator[](ptrdiff_t i) const { return LocalPointerBase<T>::ptr[i]; }
+};
+
+/**
+ * \def U_DEFINE_LOCAL_OPEN_POINTER
+ * "Smart pointer" definition macro, deletes objects via the closeFunction.
+ * Defines a subclass of LocalPointerBase which works just
+ * like LocalPointer<Type> except that this subclass will use the closeFunction
+ * rather than the C++ delete operator.
+ *
+ * Requirement: The closeFunction must tolerate a NULL pointer.
+ * (We could add a NULL check here but it is normally redundant.)
+ *
+ * Usage example:
+ * \code
+ * LocalUCaseMapPointer csm(ucasemap_open(localeID, options, &errorCode));
+ * utf8OutLength=ucasemap_utf8ToLower(csm.getAlias(),
+ *     utf8Out, (int32_t)sizeof(utf8Out),
+ *     utf8In, utf8InLength, &errorCode);
+ * if(U_FAILURE(errorCode)) { return; }  // no need to explicitly delete the UCaseMap
+ * \endcode
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+#define U_DEFINE_LOCAL_OPEN_POINTER(LocalPointerClassName, Type, closeFunction) \
+    class LocalPointerClassName : public LocalPointerBase<Type> { \
+    public: \
+        explicit LocalPointerClassName(Type *p=NULL) : LocalPointerBase<Type>(p) {} \
+        ~LocalPointerClassName() { closeFunction(ptr); } \
+        void adoptInstead(Type *p) { \
+            closeFunction(ptr); \
+            ptr=p; \
+        } \
+    }
+
+U_NAMESPACE_END
+
+#endif  /* U_SHOW_CPLUSPLUS_API */
+#endif  /* __LOCALPOINTER_H__ */
diff --git a/source/common/unicode/locid.h b/source/common/unicode/locid.h
new file mode 100644
index 0000000..14f5285
--- /dev/null
+++ b/source/common/unicode/locid.h
@@ -0,0 +1,781 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1996-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File locid.h
+*
+* Created by: Helena Shih
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   02/11/97    aliu        Changed gLocPath to fgLocPath and added methods to
+*                           get and set it.
+*   04/02/97    aliu        Made operator!= inline; fixed return value of getName().
+*   04/15/97    aliu        Cleanup for AIX/Win32.
+*   04/24/97    aliu        Numerous changes per code review.
+*   08/18/98    stephen     Added tokenizeString(),changed getDisplayName()
+*   09/08/98    stephen     Moved definition of kEmptyString for Mac Port
+*   11/09/99    weiv        Added const char * getName() const;
+*   04/12/00    srl         removing unicodestring api's and cached hash code
+*   08/10/01    grhoten     Change the static Locales to accessor functions
+******************************************************************************
+*/
+
+#ifndef LOCID_H
+#define LOCID_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+#include "unicode/putil.h"
+#include "unicode/uloc.h"
+#include "unicode/strenum.h"
+
+/**
+ * \file
+ * \brief C++ API: Locale ID object.
+ */
+
+/**
+ * A <code>Locale</code> object represents a specific geographical, political,
+ * or cultural region. An operation that requires a <code>Locale</code> to perform
+ * its task is called <em>locale-sensitive</em> and uses the <code>Locale</code>
+ * to tailor information for the user. For example, displaying a number
+ * is a locale-sensitive operation--the number should be formatted
+ * according to the customs/conventions of the user's native country,
+ * region, or culture.
+ *
+ * The Locale class is not suitable for subclassing.
+ *
+ * <P>
+ * You can create a <code>Locale</code> object using the constructor in
+ * this class:
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ *       Locale( const   char*  language,
+ *               const   char*  country,
+ *               const   char*  variant);
+ * </pre>
+ * \htmlonly</blockquote>\endhtmlonly
+ * The first argument to the constructors is a valid <STRONG>ISO
+ * Language Code.</STRONG> These codes are the lower-case two-letter
+ * codes as defined by ISO-639.
+ * You can find a full list of these codes at:
+ * <BR><a href ="http://www.loc.gov/standards/iso639-2/">
+ * http://www.loc.gov/standards/iso639-2/</a>
+ *
+ * <P>
+ * The second argument to the constructors is a valid <STRONG>ISO Country
+ * Code.</STRONG> These codes are the upper-case two-letter codes
+ * as defined by ISO-3166.
+ * You can find a full list of these codes at a number of sites, such as:
+ * <BR><a href="http://www.iso.org/iso/en/prods-services/iso3166ma/index.html">
+ * http://www.iso.org/iso/en/prods-services/iso3166ma/index.html</a>
+ *
+ * <P>
+ * The third constructor requires a third argument--the <STRONG>Variant.</STRONG>
+ * The Variant codes are vendor and browser-specific.
+ * For example, use REVISED for a langauge's revised script orthography, and POSIX for POSIX.
+ * Where there are two variants, separate them with an underscore, and
+ * put the most important one first. For
+ * example, a Traditional Spanish collation might be referenced, with
+ * "ES", "ES", "Traditional_POSIX".
+ *
+ * <P>
+ * Because a <code>Locale</code> object is just an identifier for a region,
+ * no validity check is performed when you construct a <code>Locale</code>.
+ * If you want to see whether particular resources are available for the
+ * <code>Locale</code> you construct, you must query those resources. For
+ * example, ask the <code>NumberFormat</code> for the locales it supports
+ * using its <code>getAvailableLocales</code> method.
+ * <BR><STRONG>Note:</STRONG> When you ask for a resource for a particular
+ * locale, you get back the best available match, not necessarily
+ * precisely what you asked for. For more information, look at
+ * <code>ResourceBundle</code>.
+ *
+ * <P>
+ * The <code>Locale</code> class provides a number of convenient constants
+ * that you can use to create <code>Locale</code> objects for commonly used
+ * locales. For example, the following refers to a <code>Locale</code> object
+ * for the United States:
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ *       Locale::getUS()
+ * </pre>
+ * \htmlonly</blockquote>\endhtmlonly
+ *
+ * <P>
+ * Once you've created a <code>Locale</code> you can query it for information about
+ * itself. Use <code>getCountry</code> to get the ISO Country Code and
+ * <code>getLanguage</code> to get the ISO Language Code. You can
+ * use <code>getDisplayCountry</code> to get the
+ * name of the country suitable for displaying to the user. Similarly,
+ * you can use <code>getDisplayLanguage</code> to get the name of
+ * the language suitable for displaying to the user. Interestingly,
+ * the <code>getDisplayXXX</code> methods are themselves locale-sensitive
+ * and have two versions: one that uses the default locale and one
+ * that takes a locale as an argument and displays the name or country in
+ * a language appropriate to that locale.
+ *
+ * <P>
+ * ICU provides a number of classes that perform locale-sensitive
+ * operations. For example, the <code>NumberFormat</code> class formats
+ * numbers, currency, or percentages in a locale-sensitive manner. Classes
+ * such as <code>NumberFormat</code> have a number of convenience methods
+ * for creating a default object of that type. For example, the
+ * <code>NumberFormat</code> class provides these three convenience methods
+ * for creating a default <code>NumberFormat</code> object:
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ *     UErrorCode success = U_ZERO_ERROR;
+ *     Locale myLocale;
+ *     NumberFormat *nf;
+ *
+ *     nf = NumberFormat::createInstance( success );          delete nf;
+ *     nf = NumberFormat::createCurrencyInstance( success );  delete nf;
+ *     nf = NumberFormat::createPercentInstance( success );   delete nf;
+ * </pre>
+ * \htmlonly</blockquote>\endhtmlonly
+ * Each of these methods has two variants; one with an explicit locale
+ * and one without; the latter using the default locale.
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ *     nf = NumberFormat::createInstance( myLocale, success );          delete nf;
+ *     nf = NumberFormat::createCurrencyInstance( myLocale, success );  delete nf;
+ *     nf = NumberFormat::createPercentInstance( myLocale, success );   delete nf;
+ * </pre>
+ * \htmlonly</blockquote>\endhtmlonly
+ * A <code>Locale</code> is the mechanism for identifying the kind of object
+ * (<code>NumberFormat</code>) that you would like to get. The locale is
+ * <STRONG>just</STRONG> a mechanism for identifying objects,
+ * <STRONG>not</STRONG> a container for the objects themselves.
+ *
+ * <P>
+ * Each class that performs locale-sensitive operations allows you
+ * to get all the available objects of that type. You can sift
+ * through these objects by language, country, or variant,
+ * and use the display names to present a menu to the user.
+ * For example, you can create a menu of all the collation objects
+ * suitable for a given language. Such classes implement these
+ * three class methods:
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ *       static Locale* getAvailableLocales(int32_t& numLocales)
+ *       static UnicodeString& getDisplayName(const Locale&  objectLocale,
+ *                                            const Locale&  displayLocale,
+ *                                            UnicodeString& displayName)
+ *       static UnicodeString& getDisplayName(const Locale&  objectLocale,
+ *                                            UnicodeString& displayName)
+ * </pre>
+ * \htmlonly</blockquote>\endhtmlonly
+ *
+ * @stable ICU 2.0
+ * @see ResourceBundle
+ */
+U_NAMESPACE_BEGIN
+class U_COMMON_API Locale : public UObject {
+public:
+    /** Useful constant for the Root locale. @stable ICU 4.4 */
+    static const Locale &U_EXPORT2 getRoot(void);
+    /** Useful constant for this language. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getEnglish(void);
+    /** Useful constant for this language. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getFrench(void);
+    /** Useful constant for this language. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getGerman(void);
+    /** Useful constant for this language. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getItalian(void);
+    /** Useful constant for this language. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getJapanese(void);
+    /** Useful constant for this language. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getKorean(void);
+    /** Useful constant for this language. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getChinese(void);
+    /** Useful constant for this language. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getSimplifiedChinese(void);
+    /** Useful constant for this language. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getTraditionalChinese(void);
+
+    /** Useful constant for this country/region. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getFrance(void);
+    /** Useful constant for this country/region. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getGermany(void);
+    /** Useful constant for this country/region. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getItaly(void);
+    /** Useful constant for this country/region. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getJapan(void);
+    /** Useful constant for this country/region. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getKorea(void);
+    /** Useful constant for this country/region. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getChina(void);
+    /** Useful constant for this country/region. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getPRC(void);
+    /** Useful constant for this country/region. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getTaiwan(void);
+    /** Useful constant for this country/region. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getUK(void);
+    /** Useful constant for this country/region. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getUS(void);
+    /** Useful constant for this country/region. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getCanada(void);
+    /** Useful constant for this country/region. @stable ICU 2.0 */
+    static const Locale &U_EXPORT2 getCanadaFrench(void);
+
+
+    /**
+     * Construct a default locale object, a Locale for the default locale ID.
+     *
+     * @see getDefault
+     * @see uloc_getDefault
+     * @stable ICU 2.0
+     */
+    Locale();
+
+    /**
+     * Construct a locale from language, country, variant.
+     * If an error occurs, then the constructed object will be "bogus"
+     * (isBogus() will return TRUE).
+     *
+     * @param language Lowercase two-letter or three-letter ISO-639 code.
+     *  This parameter can instead be an ICU style C locale (e.g. "en_US"),
+     *  but the other parameters must not be used.
+     *  This parameter can be NULL; if so,
+     *  the locale is initialized to match the current default locale.
+     *  (This is the same as using the default constructor.)
+     *  Please note: The Java Locale class does NOT accept the form
+     *  'new Locale("en_US")' but only 'new Locale("en","US")'
+     *
+     * @param country  Uppercase two-letter ISO-3166 code. (optional)
+     * @param variant  Uppercase vendor and browser specific code. See class
+     *                 description. (optional)
+     * @param keywordsAndValues A string consisting of keyword/values pairs, such as
+     *                 "collation=phonebook;currency=euro"
+     *
+     * @see getDefault
+     * @see uloc_getDefault
+     * @stable ICU 2.0
+     */
+    Locale( const   char * language,
+            const   char * country  = 0,
+            const   char * variant  = 0,
+            const   char * keywordsAndValues = 0);
+
+    /**
+     * Initializes a Locale object from another Locale object.
+     *
+     * @param other The Locale object being copied in.
+     * @stable ICU 2.0
+     */
+    Locale(const    Locale& other);
+
+
+    /**
+     * Destructor
+     * @stable ICU 2.0
+     */
+    virtual ~Locale() ;
+
+    /**
+     * Replaces the entire contents of *this with the specified value.
+     *
+     * @param other The Locale object being copied in.
+     * @return      *this
+     * @stable ICU 2.0
+     */
+    Locale& operator=(const Locale& other);
+
+    /**
+     * Checks if two locale keys are the same.
+     *
+     * @param other The locale key object to be compared with this.
+     * @return      True if the two locale keys are the same, false otherwise.
+     * @stable ICU 2.0
+     */
+    UBool   operator==(const    Locale&     other) const;
+
+    /**
+     * Checks if two locale keys are not the same.
+     *
+     * @param other The locale key object to be compared with this.
+     * @return      True if the two locale keys are not the same, false
+     *              otherwise.
+     * @stable ICU 2.0
+     */
+    UBool   operator!=(const    Locale&     other) 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
+     */
+    Locale *clone() const;
+
+    /**
+     * Common methods of getting the current default Locale. Used for the
+     * presentation: menus, dialogs, etc. Generally set once when your applet or
+     * application is initialized, then never reset. (If you do reset the
+     * default locale, you probably want to reload your GUI, so that the change
+     * is reflected in your interface.)
+     *
+     * More advanced programs will allow users to use different locales for
+     * different fields, e.g. in a spreadsheet.
+     *
+     * Note that the initial setting will match the host system.
+     * @return a reference to the Locale object for the default locale ID
+     * @system
+     * @stable ICU 2.0
+     */
+    static const Locale& U_EXPORT2 getDefault(void);
+
+    /**
+     * Sets the default. Normally set once at the beginning of a process,
+     * then never reset.
+     * setDefault() only changes ICU's default locale ID, <strong>not</strong>
+     * the default locale ID of the runtime environment.
+     *
+     * @param newLocale Locale to set to.  If NULL, set to the value obtained
+     *                  from the runtime environement.
+     * @param success The error code.
+     * @system
+     * @stable ICU 2.0
+     */
+    static void U_EXPORT2 setDefault(const Locale& newLocale,
+                                     UErrorCode&   success);
+
+    /**
+     * Creates a locale which has had minimal canonicalization
+     * as per uloc_getName().
+     * @param name The name to create from.  If name is null,
+     *  the default Locale is used.
+     * @return new locale object
+     * @stable ICU 2.0
+     * @see uloc_getName
+     */
+    static Locale U_EXPORT2 createFromName(const char *name);
+
+    /**
+     * Creates a locale from the given string after canonicalizing
+     * the string by calling uloc_canonicalize().
+     * @param name the locale ID to create from.  Must not be NULL.
+     * @return a new locale object corresponding to the given name
+     * @stable ICU 3.0
+     * @see uloc_canonicalize
+     */
+    static Locale U_EXPORT2 createCanonical(const char* name);
+
+    /**
+     * Returns the locale's ISO-639 language code.
+     * @return      An alias to the code
+     * @stable ICU 2.0
+     */
+    inline const char *  getLanguage( ) const;
+
+    /**
+     * Returns the locale's ISO-15924 abbreviation script code.
+     * @return      An alias to the code
+     * @see uscript_getShortName
+     * @see uscript_getCode
+     * @stable ICU 2.8
+     */
+    inline const char *  getScript( ) const;
+
+    /**
+     * Returns the locale's ISO-3166 country code.
+     * @return      An alias to the code
+     * @stable ICU 2.0
+     */
+    inline const char *  getCountry( ) const;
+
+    /**
+     * Returns the locale's variant code.
+     * @return      An alias to the code
+     * @stable ICU 2.0
+     */
+    inline const char *  getVariant( ) const;
+
+    /**
+     * Returns the programmatic name of the entire locale, with the language,
+     * country and variant separated by underbars. If a field is missing, up
+     * to two leading underbars will occur. Example: "en", "de_DE", "en_US_WIN",
+     * "de__POSIX", "fr__MAC", "__MAC", "_MT", "_FR_EURO"
+     * @return      A pointer to "name".
+     * @stable ICU 2.0
+     */
+    inline const char * getName() const;
+
+    /**
+     * Returns the programmatic name of the entire locale as getName would return,
+     * but without keywords.
+     * @return      A pointer to "name".
+     * @see getName
+     * @stable ICU 2.8
+     */
+    const char * getBaseName() const;
+
+
+    /**
+     * Gets the list of keywords for the specified locale.
+     *
+     * @param status the status code
+     * @return pointer to StringEnumeration class, or NULL if there are no keywords. 
+     * Client must dispose of it by calling delete.
+     * @stable ICU 2.8
+     */
+    StringEnumeration * createKeywords(UErrorCode &status) const;
+
+    /**
+     * Get the value for a keyword.
+     *
+     * @param keywordName name of the keyword for which we want the value. Case insensitive.
+     * @param buffer The buffer to receive the keyword value.
+     * @param bufferCapacity The capacity of receiving buffer
+     * @param status Returns any error information while performing this operation.
+     * @return the length of the keyword value
+     *
+     * @stable ICU 2.8
+     */
+    int32_t getKeywordValue(const char* keywordName, char *buffer, int32_t bufferCapacity, UErrorCode &status) const;
+
+    /**
+     * Set the value for a keyword.
+     *
+     * @param keywordName name of the keyword to be set. Case insensitive.
+     * @param keywordValue value of the keyword to be set. If 0-length or
+     *  NULL, will result in the keyword being removed. No error is given if
+     *  that keyword does not exist.
+     * @param status Returns any error information while performing this operation.
+     *
+     * @internal 
+     */
+    void setKeywordValue(const char* keywordName, const char* keywordValue, UErrorCode &status);
+
+    /**
+     * returns the locale's three-letter language code, as specified
+     * in ISO draft standard ISO-639-2.
+     * @return      An alias to the code, or NULL
+     * @stable ICU 2.0
+     */
+    const char * getISO3Language() const;
+
+    /**
+     * Fills in "name" with the locale's three-letter ISO-3166 country code.
+     * @return      An alias to the code, or NULL
+     * @stable ICU 2.0
+     */
+    const char * getISO3Country() const;
+
+    /**
+     * Returns the Windows LCID value corresponding to this locale.
+     * This value is stored in the resource data for the locale as a one-to-four-digit
+     * hexadecimal number.  If the resource is missing, in the wrong format, or
+     * there is no Windows LCID value that corresponds to this locale, returns 0.
+     * @stable ICU 2.0
+     */
+    uint32_t        getLCID(void) const;
+
+    /**
+     * Fills in "dispLang" with the name of this locale's language in a format suitable for
+     * user display in the default locale.  For example, if the locale's language code is
+     * "fr" and the default locale's language code is "en", this function would set
+     * dispLang to "French".
+     * @param dispLang  Receives the language's display name.
+     * @return          A reference to "dispLang".
+     * @stable ICU 2.0
+     */
+    UnicodeString&  getDisplayLanguage(UnicodeString&   dispLang) const;
+
+    /**
+     * Fills in "dispLang" with the name of this locale's language in a format suitable for
+     * user display in the locale specified by "displayLocale".  For example, if the locale's
+     * language code is "en" and displayLocale's language code is "fr", this function would set
+     * dispLang to "Anglais".
+     * @param displayLocale  Specifies the locale to be used to display the name.  In other words,
+     *                  if the locale's language code is "en", passing Locale::getFrench() for
+     *                  displayLocale would result in "Anglais", while passing Locale::getGerman()
+     *                  for displayLocale would result in "Englisch".
+     * @param dispLang  Receives the language's display name.
+     * @return          A reference to "dispLang".
+     * @stable ICU 2.0
+     */
+    UnicodeString&  getDisplayLanguage( const   Locale&         displayLocale,
+                                                UnicodeString&  dispLang) const;
+
+    /**
+     * Fills in "dispScript" with the name of this locale's script in a format suitable
+     * for user display in the default locale.  For example, if the locale's script code
+     * is "LATN" and the default locale's language code is "en", this function would set
+     * dispScript to "Latin".
+     * @param dispScript    Receives the scripts's display name.
+     * @return              A reference to "dispScript".
+     * @stable ICU 2.8
+     */
+    UnicodeString&  getDisplayScript(          UnicodeString& dispScript) const;
+
+    /**
+     * Fills in "dispScript" with the name of this locale's country in a format suitable
+     * for user display in the locale specified by "displayLocale".  For example, if the locale's
+     * script code is "LATN" and displayLocale's language code is "en", this function would set
+     * dispScript to "Latin".
+     * @param displayLocale      Specifies the locale to be used to display the name.  In other
+     *                      words, if the locale's script code is "LATN", passing
+     *                      Locale::getFrench() for displayLocale would result in "", while
+     *                      passing Locale::getGerman() for displayLocale would result in
+     *                      "".
+     * @param dispScript    Receives the scripts's display name.
+     * @return              A reference to "dispScript".
+     * @stable ICU 2.8
+     */
+    UnicodeString&  getDisplayScript(  const   Locale&         displayLocale,
+                                               UnicodeString&  dispScript) const;
+
+    /**
+     * Fills in "dispCountry" with the name of this locale's country in a format suitable
+     * for user display in the default locale.  For example, if the locale's country code
+     * is "FR" and the default locale's language code is "en", this function would set
+     * dispCountry to "France".
+     * @param dispCountry   Receives the country's display name.
+     * @return              A reference to "dispCountry".
+     * @stable ICU 2.0
+     */
+    UnicodeString&  getDisplayCountry(          UnicodeString& dispCountry) const;
+
+    /**
+     * Fills in "dispCountry" with the name of this locale's country in a format suitable
+     * for user display in the locale specified by "displayLocale".  For example, if the locale's
+     * country code is "US" and displayLocale's language code is "fr", this function would set
+     * dispCountry to "&Eacute;tats-Unis".
+     * @param displayLocale      Specifies the locale to be used to display the name.  In other
+     *                      words, if the locale's country code is "US", passing
+     *                      Locale::getFrench() for displayLocale would result in "&Eacute;tats-Unis", while
+     *                      passing Locale::getGerman() for displayLocale would result in
+     *                      "Vereinigte Staaten".
+     * @param dispCountry   Receives the country's display name.
+     * @return              A reference to "dispCountry".
+     * @stable ICU 2.0
+     */
+    UnicodeString&  getDisplayCountry(  const   Locale&         displayLocale,
+                                                UnicodeString&  dispCountry) const;
+
+    /**
+     * Fills in "dispVar" with the name of this locale's variant code in a format suitable
+     * for user display in the default locale.
+     * @param dispVar   Receives the variant's name.
+     * @return          A reference to "dispVar".
+     * @stable ICU 2.0
+     */
+    UnicodeString&  getDisplayVariant(      UnicodeString& dispVar) const;
+
+    /**
+     * Fills in "dispVar" with the name of this locale's variant code in a format
+     * suitable for user display in the locale specified by "displayLocale".
+     * @param displayLocale  Specifies the locale to be used to display the name.
+     * @param dispVar   Receives the variant's display name.
+     * @return          A reference to "dispVar".
+     * @stable ICU 2.0
+     */
+    UnicodeString&  getDisplayVariant(  const   Locale&         displayLocale,
+                                                UnicodeString&  dispVar) const;
+
+    /**
+     * Fills in "name" with the name of this locale in a format suitable for user display
+     * in the default locale.  This function uses getDisplayLanguage(), getDisplayCountry(),
+     * and getDisplayVariant() to do its work, and outputs the display name in the format
+     * "language (country[,variant])".  For example, if the default locale is en_US, then
+     * fr_FR's display name would be "French (France)", and es_MX_Traditional's display name
+     * would be "Spanish (Mexico,Traditional)".
+     * @param name  Receives the locale's display name.
+     * @return      A reference to "name".
+     * @stable ICU 2.0
+     */
+    UnicodeString&  getDisplayName(         UnicodeString&  name) const;
+
+    /**
+     * Fills in "name" with the name of this locale in a format suitable for user display
+     * in the locale specfied by "displayLocale".  This function uses getDisplayLanguage(),
+     * getDisplayCountry(), and getDisplayVariant() to do its work, and outputs the display
+     * name in the format "language (country[,variant])".  For example, if displayLocale is
+     * fr_FR, then en_US's display name would be "Anglais (&Eacute;tats-Unis)", and no_NO_NY's
+     * display name would be "norv&eacute;gien (Norv&egrave;ge,NY)".
+     * @param displayLocale  Specifies the locale to be used to display the name.
+     * @param name      Receives the locale's display name.
+     * @return          A reference to "name".
+     * @stable ICU 2.0
+     */
+    UnicodeString&  getDisplayName( const   Locale&         displayLocale,
+                                            UnicodeString&  name) const;
+
+    /**
+     * Generates a hash code for the locale.
+     * @stable ICU 2.0
+     */
+    int32_t         hashCode(void) const;
+
+    /**
+     * Sets the locale to bogus
+     * A bogus locale represents a non-existing locale associated
+     * with services that can be instantiated from non-locale data
+     * in addition to locale (for example, collation can be
+     * instantiated from a locale and from a rule set).
+     * @stable ICU 2.1
+     */
+    void setToBogus();
+
+    /**
+     * Gets the bogus state. Locale object can be bogus if it doesn't exist
+     * @return FALSE if it is a real locale, TRUE if it is a bogus locale
+     * @stable ICU 2.1
+     */
+    UBool isBogus(void) const;
+
+    /**
+     * Returns a list of all installed locales.
+     * @param count Receives the number of locales in the list.
+     * @return      A pointer to an array of Locale objects.  This array is the list
+     *              of all locales with installed resource files.  The called does NOT
+     *              get ownership of this list, and must NOT delete it.
+     * @stable ICU 2.0
+     */
+    static const Locale* U_EXPORT2 getAvailableLocales(int32_t& count);
+
+    /**
+     * Gets a list of all available 2-letter country codes defined in ISO 3166.  This is a
+     * pointer to an array of pointers to arrays of char.  All of these pointers are
+     * owned by ICU-- do not delete them, and do not write through them.  The array is
+     * terminated with a null pointer.
+     * @return a list of all available country codes
+     * @stable ICU 2.0
+     */
+    static const char* const* U_EXPORT2 getISOCountries();
+
+    /**
+     * Gets a list of all available language codes defined in ISO 639.  This is a pointer
+     * to an array of pointers to arrays of char.  All of these pointers are owned
+     * by ICU-- do not delete them, and do not write through them.  The array is
+     * terminated with a null pointer.
+     * @return a list of all available language codes
+     * @stable ICU 2.0
+     */
+    static const char* const* U_EXPORT2 getISOLanguages();
+
+    /**
+     * 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;
+
+protected: /* only protected for testing purposes. DO NOT USE. */
+    /**
+     * Set this from a single POSIX style locale string.
+     * @internal
+     */
+    void setFromPOSIXID(const char *posixID);
+
+private:
+    /**
+     * Initialize the locale object with a new name.
+     * Was deprecated - used in implementation - moved internal
+     *
+     * @param cLocaleID The new locale name.
+     */
+    Locale& init(const char* cLocaleID, UBool canonicalize);
+
+    /*
+     * Internal constructor to allow construction of a locale object with
+     *   NO side effects.   (Default constructor tries to get
+     *   the default locale.)
+     */
+    enum ELocaleType {
+        eBOGUS
+    };
+    Locale(ELocaleType);
+
+    /**
+     * Initialize the locale cache for commonly used locales
+     */
+    static Locale *getLocaleCache(void);
+
+    char language[ULOC_LANG_CAPACITY];
+    char script[ULOC_SCRIPT_CAPACITY];
+    char country[ULOC_COUNTRY_CAPACITY];
+    int32_t variantBegin;
+    char* fullName;
+    char fullNameBuffer[ULOC_FULLNAME_CAPACITY];
+    // name without keywords
+    char* baseName;
+    char baseNameBuffer[ULOC_FULLNAME_CAPACITY];
+
+    UBool fIsBogus;
+
+    static const Locale &getLocale(int locid);
+
+    /**
+     * A friend to allow the default locale to be set by either the C or C++ API.
+     * @internal
+     */
+    friend void locale_set_default_internal(const char *);
+};
+
+inline UBool
+Locale::operator!=(const    Locale&     other) const
+{
+    return !operator==(other);
+}
+
+inline const char *
+Locale::getCountry() const
+{
+    return country;
+}
+
+inline const char *
+Locale::getLanguage() const
+{
+    return language;
+}
+
+inline const char *
+Locale::getScript() const
+{
+    return script;
+}
+
+inline const char *
+Locale::getVariant() const
+{
+    getBaseName(); // lazy init
+    return &baseName[variantBegin];
+}
+
+inline const char *
+Locale::getName() const
+{
+    return fullName;
+}
+
+inline UBool
+Locale::isBogus(void) const {
+    return fIsBogus;
+}
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/unicode/normalizer2.h b/source/common/unicode/normalizer2.h
new file mode 100644
index 0000000..f448cc4
--- /dev/null
+++ b/source/common/unicode/normalizer2.h
@@ -0,0 +1,482 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2009-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  normalizer2.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2009nov22
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __NORMALIZER2_H__
+#define __NORMALIZER2_H__
+
+/**
+ * \file
+ * \brief C++ API: New API for Unicode Normalization.
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/uniset.h"
+#include "unicode/unistr.h"
+#include "unicode/unorm2.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Unicode normalization functionality for standard Unicode normalization or
+ * for using custom mapping tables.
+ * All instances of this class are unmodifiable/immutable.
+ * Instances returned by getInstance() are singletons that must not be deleted by the caller.
+ * The Normalizer2 class is not intended for public subclassing.
+ *
+ * The primary functions are to produce a normalized string and to detect whether
+ * a string is already normalized.
+ * The most commonly used normalization forms are those defined in
+ * http://www.unicode.org/unicode/reports/tr15/
+ * However, this API supports additional normalization forms for specialized purposes.
+ * For example, NFKC_Casefold is provided via getInstance("nfkc_cf", COMPOSE)
+ * and can be used in implementations of UTS #46.
+ *
+ * Not only are the standard compose and decompose modes supplied,
+ * but additional modes are provided as documented in the Mode enum.
+ *
+ * Some of the functions in this class identify normalization boundaries.
+ * At a normalization boundary, the portions of the string
+ * before it and starting from it do not interact and can be handled independently.
+ *
+ * The spanQuickCheckYes() stops at a normalization boundary.
+ * When the goal is a normalized string, then the text before the boundary
+ * can be copied, and the remainder can be processed with normalizeSecondAndAppend().
+ *
+ * The hasBoundaryBefore(), hasBoundaryAfter() and isInert() functions test whether
+ * a character is guaranteed to be at a normalization boundary,
+ * regardless of context.
+ * This is used for moving from one normalization boundary to the next
+ * or preceding boundary, and for performing iterative normalization.
+ *
+ * Iterative normalization is useful when only a small portion of a
+ * longer string needs to be processed.
+ * For example, in ICU, iterative normalization is used by the NormalizationTransliterator
+ * (to avoid replacing already-normalized text) and ucol_nextSortKeyPart()
+ * (to process only the substring for which sort key bytes are computed).
+ *
+ * The set of normalization boundaries returned by these functions may not be
+ * complete: There may be more boundaries that could be returned.
+ * Different functions may return different boundaries.
+ * @stable ICU 4.4
+ */
+class U_COMMON_API Normalizer2 : public UObject {
+public:
+    /**
+     * Returns a Normalizer2 instance which uses the specified data file
+     * (packageName/name similar to ucnv_openPackage() and ures_open()/ResourceBundle)
+     * and which composes or decomposes text according to the specified mode.
+     * Returns an unmodifiable singleton instance. Do not delete it.
+     *
+     * Use packageName=NULL for data files that are part of ICU's own data.
+     * Use name="nfc" and UNORM2_COMPOSE/UNORM2_DECOMPOSE for Unicode standard NFC/NFD.
+     * Use name="nfkc" and UNORM2_COMPOSE/UNORM2_DECOMPOSE for Unicode standard NFKC/NFKD.
+     * Use name="nfkc_cf" and UNORM2_COMPOSE for Unicode standard NFKC_CF=NFKC_Casefold.
+     *
+     * @param packageName NULL for ICU built-in data, otherwise application data package name
+     * @param name "nfc" or "nfkc" or "nfkc_cf" or name of custom data file
+     * @param mode normalization mode (compose or decompose etc.)
+     * @param errorCode 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 requested Normalizer2, if successful
+     * @stable ICU 4.4
+     */
+    static const Normalizer2 *
+    getInstance(const char *packageName,
+                const char *name,
+                UNormalization2Mode mode,
+                UErrorCode &errorCode);
+
+    /**
+     * Returns the normalized form of the source string.
+     * @param src source string
+     * @param errorCode 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 normalized src
+     * @stable ICU 4.4
+     */
+    UnicodeString
+    normalize(const UnicodeString &src, UErrorCode &errorCode) const {
+        UnicodeString result;
+        normalize(src, result, errorCode);
+        return result;
+    }
+    /**
+     * Writes the normalized form of the source string to the destination string
+     * (replacing its contents) and returns the destination string.
+     * The source and destination strings must be different objects.
+     * @param src source string
+     * @param dest destination string; its contents is replaced with normalized src
+     * @param errorCode 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 dest
+     * @stable ICU 4.4
+     */
+    virtual UnicodeString &
+    normalize(const UnicodeString &src,
+              UnicodeString &dest,
+              UErrorCode &errorCode) const = 0;
+    /**
+     * Appends the normalized form of the second string to the first string
+     * (merging them at the boundary) and returns the first string.
+     * The result is normalized if the first string was normalized.
+     * The first and second strings must be different objects.
+     * @param first string, should be normalized
+     * @param second string, will be normalized
+     * @param errorCode 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 first
+     * @stable ICU 4.4
+     */
+    virtual UnicodeString &
+    normalizeSecondAndAppend(UnicodeString &first,
+                             const UnicodeString &second,
+                             UErrorCode &errorCode) const = 0;
+    /**
+     * Appends the second string to the first string
+     * (merging them at the boundary) and returns the first string.
+     * The result is normalized if both the strings were normalized.
+     * The first and second strings must be different objects.
+     * @param first string, should be normalized
+     * @param second string, should be normalized
+     * @param errorCode 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 first
+     * @stable ICU 4.4
+     */
+    virtual UnicodeString &
+    append(UnicodeString &first,
+           const UnicodeString &second,
+           UErrorCode &errorCode) const = 0;
+
+    /**
+     * Gets the decomposition mapping of c. Equivalent to normalize(UnicodeString(c))
+     * on a UNORM2_DECOMPOSE Normalizer2 instance, but much faster.
+     * This function is independent of the mode of the Normalizer2.
+     * @param c code point
+     * @param decomposition String object which will be set to c's
+     *                      decomposition mapping, if there is one.
+     * @return TRUE if c has a decomposition, otherwise FALSE
+     * @draft ICU 4.6
+     */
+    virtual UBool
+    getDecomposition(UChar32 c, UnicodeString &decomposition) const = 0;
+
+    /**
+     * Tests if the string is normalized.
+     * Internally, in cases where the quickCheck() method would return "maybe"
+     * (which is only possible for the two COMPOSE modes) this method
+     * resolves to "yes" or "no" to provide a definitive result,
+     * at the cost of doing more work in those cases.
+     * @param s input string
+     * @param errorCode 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 TRUE if s is normalized
+     * @stable ICU 4.4
+     */
+    virtual UBool
+    isNormalized(const UnicodeString &s, UErrorCode &errorCode) const = 0;
+
+    /**
+     * Tests if the string is normalized.
+     * For the two COMPOSE modes, the result could be "maybe" in cases that
+     * would take a little more work to resolve definitively.
+     * Use spanQuickCheckYes() and normalizeSecondAndAppend() for a faster
+     * combination of quick check + normalization, to avoid
+     * re-checking the "yes" prefix.
+     * @param s input string
+     * @param errorCode 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 UNormalizationCheckResult
+     * @stable ICU 4.4
+     */
+    virtual UNormalizationCheckResult
+    quickCheck(const UnicodeString &s, UErrorCode &errorCode) const = 0;
+
+    /**
+     * Returns the end of the normalized substring of the input string.
+     * In other words, with <code>end=spanQuickCheckYes(s, ec);</code>
+     * the substring <code>UnicodeString(s, 0, end)</code>
+     * will pass the quick check with a "yes" result.
+     *
+     * The returned end index is usually one or more characters before the
+     * "no" or "maybe" character: The end index is at a normalization boundary.
+     * (See the class documentation for more about normalization boundaries.)
+     *
+     * When the goal is a normalized string and most input strings are expected
+     * to be normalized already, then call this method,
+     * and if it returns a prefix shorter than the input string,
+     * copy that prefix and use normalizeSecondAndAppend() for the remainder.
+     * @param s input string
+     * @param errorCode 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 "yes" span end index
+     * @stable ICU 4.4
+     */
+    virtual int32_t
+    spanQuickCheckYes(const UnicodeString &s, UErrorCode &errorCode) const = 0;
+
+    /**
+     * Tests if the character always has a normalization boundary before it,
+     * regardless of context.
+     * If true, then the character does not normalization-interact with
+     * preceding characters.
+     * In other words, a string containing this character can be normalized
+     * by processing portions before this character and starting from this
+     * character independently.
+     * This is used for iterative normalization. See the class documentation for details.
+     * @param c character to test
+     * @return TRUE if c has a normalization boundary before it
+     * @stable ICU 4.4
+     */
+    virtual UBool hasBoundaryBefore(UChar32 c) const = 0;
+
+    /**
+     * Tests if the character always has a normalization boundary after it,
+     * regardless of context.
+     * If true, then the character does not normalization-interact with
+     * following characters.
+     * In other words, a string containing this character can be normalized
+     * by processing portions up to this character and after this
+     * character independently.
+     * This is used for iterative normalization. See the class documentation for details.
+     * Note that this operation may be significantly slower than hasBoundaryBefore().
+     * @param c character to test
+     * @return TRUE if c has a normalization boundary after it
+     * @stable ICU 4.4
+     */
+    virtual UBool hasBoundaryAfter(UChar32 c) const = 0;
+
+    /**
+     * Tests if the character is normalization-inert.
+     * If true, then the character does not change, nor normalization-interact with
+     * preceding or following characters.
+     * In other words, a string containing this character can be normalized
+     * by processing portions before this character and after this
+     * character independently.
+     * This is used for iterative normalization. See the class documentation for details.
+     * Note that this operation may be significantly slower than hasBoundaryBefore().
+     * @param c character to test
+     * @return TRUE if c is normalization-inert
+     * @stable ICU 4.4
+     */
+    virtual UBool isInert(UChar32 c) const = 0;
+
+private:
+    // No ICU "poor man's RTTI" for this class nor its subclasses.
+    virtual UClassID getDynamicClassID() const;
+};
+
+/**
+ * Normalization filtered by a UnicodeSet.
+ * Normalizes portions of the text contained in the filter set and leaves
+ * portions not contained in the filter set unchanged.
+ * Filtering is done via UnicodeSet::span(..., USET_SPAN_SIMPLE).
+ * Not-in-the-filter text is treated as "is normalized" and "quick check yes".
+ * This class implements all of (and only) the Normalizer2 API.
+ * An instance of this class is unmodifiable/immutable but is constructed and
+ * must be destructed by the owner.
+ * @stable ICU 4.4
+ */
+class U_COMMON_API FilteredNormalizer2 : public Normalizer2 {
+public:
+    /**
+     * Constructs a filtered normalizer wrapping any Normalizer2 instance
+     * and a filter set.
+     * Both are aliased and must not be modified or deleted while this object
+     * is used.
+     * The filter set should be frozen; otherwise the performance will suffer greatly.
+     * @param n2 wrapped Normalizer2 instance
+     * @param filterSet UnicodeSet which determines the characters to be normalized
+     * @stable ICU 4.4
+     */
+    FilteredNormalizer2(const Normalizer2 &n2, const UnicodeSet &filterSet) :
+            norm2(n2), set(filterSet) {}
+
+    /**
+     * Writes the normalized form of the source string to the destination string
+     * (replacing its contents) and returns the destination string.
+     * The source and destination strings must be different objects.
+     * @param src source string
+     * @param dest destination string; its contents is replaced with normalized src
+     * @param errorCode 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 dest
+     * @stable ICU 4.4
+     */
+    virtual UnicodeString &
+    normalize(const UnicodeString &src,
+              UnicodeString &dest,
+              UErrorCode &errorCode) const;
+    /**
+     * Appends the normalized form of the second string to the first string
+     * (merging them at the boundary) and returns the first string.
+     * The result is normalized if the first string was normalized.
+     * The first and second strings must be different objects.
+     * @param first string, should be normalized
+     * @param second string, will be normalized
+     * @param errorCode 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 first
+     * @stable ICU 4.4
+     */
+    virtual UnicodeString &
+    normalizeSecondAndAppend(UnicodeString &first,
+                             const UnicodeString &second,
+                             UErrorCode &errorCode) const;
+    /**
+     * Appends the second string to the first string
+     * (merging them at the boundary) and returns the first string.
+     * The result is normalized if both the strings were normalized.
+     * The first and second strings must be different objects.
+     * @param first string, should be normalized
+     * @param second string, should be normalized
+     * @param errorCode 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 first
+     * @stable ICU 4.4
+     */
+    virtual UnicodeString &
+    append(UnicodeString &first,
+           const UnicodeString &second,
+           UErrorCode &errorCode) const;
+
+    /**
+     * Gets the decomposition mapping of c. Equivalent to normalize(UnicodeString(c))
+     * on a UNORM2_DECOMPOSE Normalizer2 instance, but much faster.
+     * This function is independent of the mode of the Normalizer2.
+     * @param c code point
+     * @param decomposition String object which will be set to c's
+     *                      decomposition mapping, if there is one.
+     * @return TRUE if c has a decomposition, otherwise FALSE
+     * @draft ICU 4.6
+     */
+    virtual UBool
+    getDecomposition(UChar32 c, UnicodeString &decomposition) const;
+
+    /**
+     * Tests if the string is normalized.
+     * For details see the Normalizer2 base class documentation.
+     * @param s input string
+     * @param errorCode 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 TRUE if s is normalized
+     * @stable ICU 4.4
+     */
+    virtual UBool
+    isNormalized(const UnicodeString &s, UErrorCode &errorCode) const;
+    /**
+     * Tests if the string is normalized.
+     * For details see the Normalizer2 base class documentation.
+     * @param s input string
+     * @param errorCode 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 UNormalizationCheckResult
+     * @stable ICU 4.4
+     */
+    virtual UNormalizationCheckResult
+    quickCheck(const UnicodeString &s, UErrorCode &errorCode) const;
+    /**
+     * Returns the end of the normalized substring of the input string.
+     * For details see the Normalizer2 base class documentation.
+     * @param s input string
+     * @param errorCode 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 "yes" span end index
+     * @stable ICU 4.4
+     */
+    virtual int32_t
+    spanQuickCheckYes(const UnicodeString &s, UErrorCode &errorCode) const;
+
+    /**
+     * Tests if the character always has a normalization boundary before it,
+     * regardless of context.
+     * For details see the Normalizer2 base class documentation.
+     * @param c character to test
+     * @return TRUE if c has a normalization boundary before it
+     * @stable ICU 4.4
+     */
+    virtual UBool hasBoundaryBefore(UChar32 c) const;
+
+    /**
+     * Tests if the character always has a normalization boundary after it,
+     * regardless of context.
+     * For details see the Normalizer2 base class documentation.
+     * @param c character to test
+     * @return TRUE if c has a normalization boundary after it
+     * @stable ICU 4.4
+     */
+    virtual UBool hasBoundaryAfter(UChar32 c) const;
+
+    /**
+     * Tests if the character is normalization-inert.
+     * For details see the Normalizer2 base class documentation.
+     * @param c character to test
+     * @return TRUE if c is normalization-inert
+     * @stable ICU 4.4
+     */
+    virtual UBool isInert(UChar32 c) const;
+private:
+    UnicodeString &
+    normalize(const UnicodeString &src,
+              UnicodeString &dest,
+              USetSpanCondition spanCondition,
+              UErrorCode &errorCode) const;
+
+    UnicodeString &
+    normalizeSecondAndAppend(UnicodeString &first,
+                             const UnicodeString &second,
+                             UBool doNormalize,
+                             UErrorCode &errorCode) const;
+
+    const Normalizer2 &norm2;
+    const UnicodeSet &set;
+};
+
+U_NAMESPACE_END
+
+#endif  // !UCONFIG_NO_NORMALIZATION
+#endif  // __NORMALIZER2_H__
diff --git a/source/common/unicode/normlzr.h b/source/common/unicode/normlzr.h
new file mode 100644
index 0000000..475f830
--- /dev/null
+++ b/source/common/unicode/normlzr.h
@@ -0,0 +1,797 @@
+/*
+ ********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1996-2010, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************
+ */
+
+#ifndef NORMLZR_H
+#define NORMLZR_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file 
+ * \brief C++ API: Unicode Normalization
+ */
+ 
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/chariter.h"
+#include "unicode/normalizer2.h"
+#include "unicode/unistr.h"
+#include "unicode/unorm.h"
+#include "unicode/uobject.h"
+
+U_NAMESPACE_BEGIN
+/**
+ * The Normalizer class supports the standard normalization forms described in
+ * <a href="http://www.unicode.org/unicode/reports/tr15/" target="unicode">
+ * Unicode Standard Annex #15: Unicode Normalization Forms</a>.
+ *
+ * Note: This API has been replaced by the Normalizer2 class and is only available
+ * for backward compatibility. This class simply delegates to the Normalizer2 class.
+ * There is one exception: The new API does not provide a replacement for Normalizer::compare().
+ *
+ * The Normalizer class consists of two parts:
+ * - static functions that normalize strings or test if strings are normalized
+ * - a Normalizer object is an iterator that takes any kind of text and
+ *   provides iteration over its normalized form
+ *
+ * The Normalizer class is not suitable for subclassing.
+ *
+ * For basic information about normalization forms and details about the C API
+ * please see the documentation in unorm.h.
+ *
+ * The iterator API with the Normalizer constructors and the non-static functions
+ * use a CharacterIterator as input. It is possible to pass a string which
+ * is then internally wrapped in a CharacterIterator.
+ * The input text is not normalized all at once, but incrementally where needed
+ * (providing efficient random access).
+ * This allows to pass in a large text but spend only a small amount of time
+ * normalizing a small part of that text.
+ * However, if the entire text is normalized, then the iterator will be
+ * slower than normalizing the entire text at once and iterating over the result.
+ * A possible use of the Normalizer iterator is also to report an index into the
+ * original text that is close to where the normalized characters come from.
+ *
+ * <em>Important:</em> The iterator API was cleaned up significantly for ICU 2.0.
+ * The earlier implementation reported the getIndex() inconsistently,
+ * and previous() could not be used after setIndex(), next(), first(), and current().
+ *
+ * Normalizer allows to start normalizing from anywhere in the input text by
+ * calling setIndexOnly(), first(), or last().
+ * Without calling any of these, the iterator will start at the beginning of the text.
+ *
+ * At any time, next() returns the next normalized code point (UChar32),
+ * with post-increment semantics (like CharacterIterator::next32PostInc()).
+ * previous() returns the previous normalized code point (UChar32),
+ * with pre-decrement semantics (like CharacterIterator::previous32()).
+ *
+ * current() returns the current code point
+ * (respectively the one at the newly set index) without moving
+ * the getIndex(). Note that if the text at the current position
+ * needs to be normalized, then these functions will do that.
+ * (This is why current() is not const.)
+ * It is more efficient to call setIndexOnly() instead, which does not
+ * normalize.
+ *
+ * getIndex() always refers to the position in the input text where the normalized
+ * code points are returned from. It does not always change with each returned
+ * code point.
+ * The code point that is returned from any of the functions
+ * corresponds to text at or after getIndex(), according to the
+ * function's iteration semantics (post-increment or pre-decrement).
+ *
+ * next() returns a code point from at or after the getIndex()
+ * from before the next() call. After the next() call, the getIndex()
+ * might have moved to where the next code point will be returned from
+ * (from a next() or current() call).
+ * This is semantically equivalent to array access with array[index++]
+ * (post-increment semantics).
+ *
+ * previous() returns a code point from at or after the getIndex()
+ * from after the previous() call.
+ * This is semantically equivalent to array access with array[--index]
+ * (pre-decrement semantics).
+ *
+ * Internally, the Normalizer iterator normalizes a small piece of text
+ * starting at the getIndex() and ending at a following "safe" index.
+ * The normalized results is stored in an internal string buffer, and
+ * the code points are iterated from there.
+ * With multiple iteration calls, this is repeated until the next piece
+ * of text needs to be normalized, and the getIndex() needs to be moved.
+ *
+ * The following "safe" index, the internal buffer, and the secondary
+ * iteration index into that buffer are not exposed on the API.
+ * This also means that it is currently not practical to return to
+ * a particular, arbitrary position in the text because one would need to
+ * know, and be able to set, in addition to the getIndex(), at least also the
+ * current index into the internal buffer.
+ * It is currently only possible to observe when getIndex() changes
+ * (with careful consideration of the iteration semantics),
+ * at which time the internal index will be 0.
+ * For example, if getIndex() is different after next() than before it,
+ * then the internal index is 0 and one can return to this getIndex()
+ * later with setIndexOnly().
+ *
+ * Note: While the setIndex() and getIndex() refer to indices in the
+ * underlying Unicode input text, the next() and previous() methods
+ * iterate through characters in the normalized output.
+ * This means that there is not necessarily a one-to-one correspondence
+ * between characters returned by next() and previous() and the indices
+ * passed to and returned from setIndex() and getIndex().
+ * It is for this reason that Normalizer does not implement the CharacterIterator interface.
+ *
+ * @author Laura Werner, Mark Davis, Markus Scherer
+ * @stable ICU 2.0
+ */
+class U_COMMON_API Normalizer : public UObject {
+public:
+  /**
+   * If DONE is returned from an iteration function that returns a code point,
+   * then there are no more normalization results available.
+   * @stable ICU 2.0
+   */
+  enum {
+      DONE=0xffff
+  };
+
+  // Constructors
+
+  /**
+   * Creates a new <code>Normalizer</code> object for iterating over the
+   * normalized form of a given string.
+   * <p>
+   * @param str   The string to be normalized.  The normalization
+   *              will start at the beginning of the string.
+   *
+   * @param mode  The normalization mode.
+   * @stable ICU 2.0
+   */
+  Normalizer(const UnicodeString& str, UNormalizationMode mode);
+
+  /**
+   * Creates a new <code>Normalizer</code> object for iterating over the
+   * normalized form of a given string.
+   * <p>
+   * @param str   The string to be normalized.  The normalization
+   *              will start at the beginning of the string.
+   *
+   * @param length Length of the string, or -1 if NUL-terminated.
+   * @param mode  The normalization mode.
+   * @stable ICU 2.0
+   */
+  Normalizer(const UChar* str, int32_t length, UNormalizationMode mode);
+
+  /**
+   * Creates a new <code>Normalizer</code> object for iterating over the
+   * normalized form of the given text.
+   * <p>
+   * @param iter  The input text to be normalized.  The normalization
+   *              will start at the beginning of the string.
+   *
+   * @param mode  The normalization mode.
+   * @stable ICU 2.0
+   */
+  Normalizer(const CharacterIterator& iter, UNormalizationMode mode);
+
+  /**
+   * Copy constructor.
+   * @param copy The object to be copied.
+   * @stable ICU 2.0
+   */
+  Normalizer(const Normalizer& copy);
+
+  /**
+   * Destructor
+   * @stable ICU 2.0
+   */
+  virtual ~Normalizer();
+
+
+  //-------------------------------------------------------------------------
+  // Static utility methods
+  //-------------------------------------------------------------------------
+
+  /**
+   * Normalizes a <code>UnicodeString</code> according to the specified normalization mode.
+   * This is a wrapper for unorm_normalize(), using UnicodeString's.
+   *
+   * The <code>options</code> parameter specifies which optional
+   * <code>Normalizer</code> features are to be enabled for this operation.
+   *
+   * @param source    the input string to be normalized.
+   * @param mode      the normalization mode
+   * @param options   the optional features to be enabled (0 for no options)
+   * @param result    The normalized string (on output).
+   * @param status    The error code.
+   * @stable ICU 2.0
+   */
+  static void U_EXPORT2 normalize(const UnicodeString& source,
+                        UNormalizationMode mode, int32_t options,
+                        UnicodeString& result,
+                        UErrorCode &status);
+
+  /**
+   * Compose a <code>UnicodeString</code>.
+   * This is equivalent to normalize() with mode UNORM_NFC or UNORM_NFKC.
+   * This is a wrapper for unorm_normalize(), using UnicodeString's.
+   *
+   * The <code>options</code> parameter specifies which optional
+   * <code>Normalizer</code> features are to be enabled for this operation.
+   *
+   * @param source    the string to be composed.
+   * @param compat    Perform compatibility decomposition before composition.
+   *                  If this argument is <code>FALSE</code>, only canonical
+   *                  decomposition will be performed.
+   * @param options   the optional features to be enabled (0 for no options)
+   * @param result    The composed string (on output).
+   * @param status    The error code.
+   * @stable ICU 2.0
+   */
+  static void U_EXPORT2 compose(const UnicodeString& source,
+                      UBool compat, int32_t options,
+                      UnicodeString& result,
+                      UErrorCode &status);
+
+  /**
+   * Static method to decompose a <code>UnicodeString</code>.
+   * This is equivalent to normalize() with mode UNORM_NFD or UNORM_NFKD.
+   * This is a wrapper for unorm_normalize(), using UnicodeString's.
+   *
+   * The <code>options</code> parameter specifies which optional
+   * <code>Normalizer</code> features are to be enabled for this operation.
+   *
+   * @param source    the string to be decomposed.
+   * @param compat    Perform compatibility decomposition.
+   *                  If this argument is <code>FALSE</code>, only canonical
+   *                  decomposition will be performed.
+   * @param options   the optional features to be enabled (0 for no options)
+   * @param result    The decomposed string (on output).
+   * @param status    The error code.
+   * @stable ICU 2.0
+   */
+  static void U_EXPORT2 decompose(const UnicodeString& source,
+                        UBool compat, int32_t options,
+                        UnicodeString& result,
+                        UErrorCode &status);
+
+  /**
+   * Performing quick check on a string, to quickly determine if the string is
+   * in a particular normalization format.
+   * This is a wrapper for unorm_quickCheck(), using a UnicodeString.
+   *
+   * Three types of result can be returned UNORM_YES, UNORM_NO or
+   * UNORM_MAYBE. Result UNORM_YES indicates that the argument
+   * string is in the desired normalized format, UNORM_NO determines that
+   * argument string is not in the desired normalized format. A
+   * UNORM_MAYBE result indicates that a more thorough check is required,
+   * the user may have to put the string in its normalized form and compare the
+   * results.
+   * @param source       string for determining if it is in a normalized format
+   * @param mode         normalization format
+   * @param status A reference to a UErrorCode to receive any errors
+   * @return UNORM_YES, UNORM_NO or UNORM_MAYBE
+   *
+   * @see isNormalized
+   * @stable ICU 2.0
+   */
+  static inline UNormalizationCheckResult
+  quickCheck(const UnicodeString &source, UNormalizationMode mode, UErrorCode &status);
+
+  /**
+   * Performing quick check on a string; same as the other version of quickCheck
+   * but takes an extra options parameter like most normalization functions.
+   *
+   * @param source       string for determining if it is in a normalized format
+   * @param mode         normalization format
+   * @param options      the optional features to be enabled (0 for no options)
+   * @param status A reference to a UErrorCode to receive any errors
+   * @return UNORM_YES, UNORM_NO or UNORM_MAYBE
+   *
+   * @see isNormalized
+   * @stable ICU 2.6
+   */
+  static UNormalizationCheckResult
+  quickCheck(const UnicodeString &source, UNormalizationMode mode, int32_t options, UErrorCode &status);
+
+  /**
+   * Test if a string is in a given normalization form.
+   * This is semantically equivalent to source.equals(normalize(source, mode)) .
+   *
+   * Unlike unorm_quickCheck(), this function returns a definitive result,
+   * never a "maybe".
+   * For NFD, NFKD, and FCD, both functions work exactly the same.
+   * For NFC and NFKC where quickCheck may return "maybe", this function will
+   * perform further tests to arrive at a TRUE/FALSE result.
+   *
+   * @param src        String that is to be tested if it is in a normalization format.
+   * @param mode       Which normalization form to test for.
+   * @param errorCode  ICU error code in/out parameter.
+   *                   Must fulfill U_SUCCESS before the function call.
+   * @return Boolean value indicating whether the source string is in the
+   *         "mode" normalization form.
+   *
+   * @see quickCheck
+   * @stable ICU 2.2
+   */
+  static inline UBool
+  isNormalized(const UnicodeString &src, UNormalizationMode mode, UErrorCode &errorCode);
+
+  /**
+   * Test if a string is in a given normalization form; same as the other version of isNormalized
+   * but takes an extra options parameter like most normalization functions.
+   *
+   * @param src        String that is to be tested if it is in a normalization format.
+   * @param mode       Which normalization form to test for.
+   * @param options      the optional features to be enabled (0 for no options)
+   * @param errorCode  ICU error code in/out parameter.
+   *                   Must fulfill U_SUCCESS before the function call.
+   * @return Boolean value indicating whether the source string is in the
+   *         "mode" normalization form.
+   *
+   * @see quickCheck
+   * @stable ICU 2.6
+   */
+  static UBool
+  isNormalized(const UnicodeString &src, UNormalizationMode mode, int32_t options, UErrorCode &errorCode);
+
+  /**
+   * Concatenate normalized strings, making sure that the result is normalized as well.
+   *
+   * If both the left and the right strings are in
+   * the normalization form according to "mode/options",
+   * then the result will be
+   *
+   * \code
+   *     dest=normalize(left+right, mode, options)
+   * \endcode
+   *
+   * For details see unorm_concatenate in unorm.h.
+   *
+   * @param left Left source string.
+   * @param right Right source string.
+   * @param result The output string.
+   * @param mode The normalization mode.
+   * @param options A bit set of normalization options.
+   * @param errorCode ICU error code in/out parameter.
+   *                   Must fulfill U_SUCCESS before the function call.
+   * @return result
+   *
+   * @see unorm_concatenate
+   * @see normalize
+   * @see unorm_next
+   * @see unorm_previous
+   *
+   * @stable ICU 2.1
+   */
+  static UnicodeString &
+  U_EXPORT2 concatenate(UnicodeString &left, UnicodeString &right,
+              UnicodeString &result,
+              UNormalizationMode mode, int32_t options,
+              UErrorCode &errorCode);
+
+  /**
+   * Compare two strings for canonical equivalence.
+   * Further options include case-insensitive comparison and
+   * code point order (as opposed to code unit order).
+   *
+   * Canonical equivalence between two strings is defined as their normalized
+   * forms (NFD or NFC) being identical.
+   * This function compares strings incrementally instead of normalizing
+   * (and optionally case-folding) both strings entirely,
+   * improving performance significantly.
+   *
+   * Bulk normalization is only necessary if the strings do not fulfill the FCD
+   * conditions. Only in this case, and only if the strings are relatively long,
+   * is memory allocated temporarily.
+   * For FCD strings and short non-FCD strings there is no memory allocation.
+   *
+   * Semantically, this is equivalent to
+   *   strcmp[CodePointOrder](NFD(foldCase(s1)), NFD(foldCase(s2)))
+   * where code point order and foldCase are all optional.
+   *
+   * UAX 21 2.5 Caseless Matching specifies that for a canonical caseless match
+   * the case folding must be performed first, then the normalization.
+   *
+   * @param s1 First source string.
+   * @param s2 Second source string.
+   *
+   * @param options A bit set of options:
+   *   - U_FOLD_CASE_DEFAULT or 0 is used for default options:
+   *     Case-sensitive comparison in code unit order, and the input strings
+   *     are quick-checked for FCD.
+   *
+   *   - UNORM_INPUT_IS_FCD
+   *     Set if the caller knows that both s1 and s2 fulfill the FCD conditions.
+   *     If not set, the function will quickCheck for FCD
+   *     and normalize if necessary.
+   *
+   *   - U_COMPARE_CODE_POINT_ORDER
+   *     Set to choose code point order instead of code unit order
+   *     (see u_strCompare for details).
+   *
+   *   - U_COMPARE_IGNORE_CASE
+   *     Set to compare strings case-insensitively using case folding,
+   *     instead of case-sensitively.
+   *     If set, then the following case folding options are used.
+   *
+   *   - Options as used with case-insensitive comparisons, currently:
+   *
+   *   - U_FOLD_CASE_EXCLUDE_SPECIAL_I
+   *    (see u_strCaseCompare for details)
+   *
+   *   - regular normalization options shifted left by UNORM_COMPARE_NORM_OPTIONS_SHIFT
+   *
+   * @param errorCode ICU error code in/out parameter.
+   *                  Must fulfill U_SUCCESS before the function call.
+   * @return <0 or 0 or >0 as usual for string comparisons
+   *
+   * @see unorm_compare
+   * @see normalize
+   * @see UNORM_FCD
+   * @see u_strCompare
+   * @see u_strCaseCompare
+   *
+   * @stable ICU 2.2
+   */
+  static inline int32_t
+  compare(const UnicodeString &s1, const UnicodeString &s2,
+          uint32_t options,
+          UErrorCode &errorCode);
+
+  //-------------------------------------------------------------------------
+  // Iteration API
+  //-------------------------------------------------------------------------
+
+  /**
+   * Return the current character in the normalized text.
+   * current() may need to normalize some text at getIndex().
+   * The getIndex() is not changed.
+   *
+   * @return the current normalized code point
+   * @stable ICU 2.0
+   */
+  UChar32              current(void);
+
+  /**
+   * Return the first character in the normalized text.
+   * This is equivalent to setIndexOnly(startIndex()) followed by next().
+   * (Post-increment semantics.)
+   *
+   * @return the first normalized code point
+   * @stable ICU 2.0
+   */
+  UChar32              first(void);
+
+  /**
+   * Return the last character in the normalized text.
+   * This is equivalent to setIndexOnly(endIndex()) followed by previous().
+   * (Pre-decrement semantics.)
+   *
+   * @return the last normalized code point
+   * @stable ICU 2.0
+   */
+  UChar32              last(void);
+
+  /**
+   * Return the next character in the normalized text.
+   * (Post-increment semantics.)
+   * If the end of the text has already been reached, DONE is returned.
+   * The DONE value could be confused with a U+FFFF non-character code point
+   * in the text. If this is possible, you can test getIndex()<endIndex()
+   * before calling next(), or (getIndex()<endIndex() || last()!=DONE)
+   * after calling next(). (Calling last() will change the iterator state!)
+   *
+   * The C API unorm_next() is more efficient and does not have this ambiguity.
+   *
+   * @return the next normalized code point
+   * @stable ICU 2.0
+   */
+  UChar32              next(void);
+
+  /**
+   * Return the previous character in the normalized text and decrement.
+   * (Pre-decrement semantics.)
+   * If the beginning of the text has already been reached, DONE is returned.
+   * The DONE value could be confused with a U+FFFF non-character code point
+   * in the text. If this is possible, you can test
+   * (getIndex()>startIndex() || first()!=DONE). (Calling first() will change
+   * the iterator state!)
+   *
+   * The C API unorm_previous() is more efficient and does not have this ambiguity.
+   *
+   * @return the previous normalized code point
+   * @stable ICU 2.0
+   */
+  UChar32              previous(void);
+
+  /**
+   * Set the iteration position in the input text that is being normalized,
+   * without any immediate normalization.
+   * After setIndexOnly(), getIndex() will return the same index that is
+   * specified here.
+   *
+   * @param index the desired index in the input text.
+   * @stable ICU 2.0
+   */
+  void                 setIndexOnly(int32_t index);
+
+  /**
+   * Reset the index to the beginning of the text.
+   * This is equivalent to setIndexOnly(startIndex)).
+   * @stable ICU 2.0
+   */
+  void                reset(void);
+
+  /**
+   * Retrieve the current iteration position in the input text that is
+   * being normalized.
+   *
+   * A following call to next() will return a normalized code point from
+   * the input text at or after this index.
+   *
+   * After a call to previous(), getIndex() will point at or before the
+   * position in the input text where the normalized code point
+   * was returned from with previous().
+   *
+   * @return the current index in the input text
+   * @stable ICU 2.0
+   */
+  int32_t            getIndex(void) const;
+
+  /**
+   * Retrieve the index of the start of the input text. This is the begin index
+   * of the <code>CharacterIterator</code> or the start (i.e. index 0) of the string
+   * over which this <code>Normalizer</code> is iterating.
+   *
+   * @return the smallest index in the input text where the Normalizer operates
+   * @stable ICU 2.0
+   */
+  int32_t            startIndex(void) const;
+
+  /**
+   * Retrieve the index of the end of the input text. This is the end index
+   * of the <code>CharacterIterator</code> or the length of the string
+   * over which this <code>Normalizer</code> is iterating.
+   * This end index is exclusive, i.e., the Normalizer operates only on characters
+   * before this index.
+   *
+   * @return the first index in the input text where the Normalizer does not operate
+   * @stable ICU 2.0
+   */
+  int32_t            endIndex(void) const;
+
+  /**
+   * Returns TRUE when both iterators refer to the same character in the same
+   * input text.
+   *
+   * @param that a Normalizer object to compare this one to
+   * @return comparison result
+   * @stable ICU 2.0
+   */
+  UBool        operator==(const Normalizer& that) const;
+
+  /**
+   * Returns FALSE when both iterators refer to the same character in the same
+   * input text.
+   *
+   * @param that a Normalizer object to compare this one to
+   * @return comparison result
+   * @stable ICU 2.0
+   */
+  inline UBool        operator!=(const Normalizer& that) const;
+
+  /**
+   * Returns a pointer to a new Normalizer that is a clone of this one.
+   * The caller is responsible for deleting the new clone.
+   * @return a pointer to a new Normalizer
+   * @stable ICU 2.0
+   */
+  Normalizer*        clone(void) const;
+
+  /**
+   * Generates a hash code for this iterator.
+   *
+   * @return the hash code
+   * @stable ICU 2.0
+   */
+  int32_t                hashCode(void) const;
+
+  //-------------------------------------------------------------------------
+  // Property access methods
+  //-------------------------------------------------------------------------
+
+  /**
+   * Set the normalization mode for this object.
+   * <p>
+   * <b>Note:</b>If the normalization mode is changed while iterating
+   * over a string, calls to {@link #next() } and {@link #previous() } may
+   * return previously buffers characters in the old normalization mode
+   * until the iteration is able to re-sync at the next base character.
+   * It is safest to call {@link #setIndexOnly }, {@link #reset() },
+   * {@link #setText }, {@link #first() },
+   * {@link #last() }, etc. after calling <code>setMode</code>.
+   * <p>
+   * @param newMode the new mode for this <code>Normalizer</code>.
+   * @see #getUMode
+   * @stable ICU 2.0
+   */
+  void setMode(UNormalizationMode newMode);
+
+  /**
+   * Return the normalization mode for this object.
+   *
+   * This is an unusual name because there used to be a getMode() that
+   * returned a different type.
+   *
+   * @return the mode for this <code>Normalizer</code>
+   * @see #setMode
+   * @stable ICU 2.0
+   */
+  UNormalizationMode getUMode(void) const;
+
+  /**
+   * Set options that affect this <code>Normalizer</code>'s operation.
+   * Options do not change the basic composition or decomposition operation
+   * that is being performed, but they control whether
+   * certain optional portions of the operation are done.
+   * Currently the only available option is obsolete.
+   *
+   * It is possible to specify multiple options that are all turned on or off.
+   *
+   * @param   option  the option(s) whose value is/are to be set.
+   * @param   value   the new setting for the option.  Use <code>TRUE</code> to
+   *                  turn the option(s) on and <code>FALSE</code> to turn it/them off.
+   *
+   * @see #getOption
+   * @stable ICU 2.0
+   */
+  void setOption(int32_t option,
+         UBool value);
+
+  /**
+   * Determine whether an option is turned on or off.
+   * If multiple options are specified, then the result is TRUE if any
+   * of them are set.
+   * <p>
+   * @param option the option(s) that are to be checked
+   * @return TRUE if any of the option(s) are set
+   * @see #setOption
+   * @stable ICU 2.0
+   */
+  UBool getOption(int32_t option) const;
+
+  /**
+   * Set the input text over which this <code>Normalizer</code> will iterate.
+   * The iteration position is set to the beginning.
+   *
+   * @param newText a string that replaces the current input text
+   * @param status a UErrorCode
+   * @stable ICU 2.0
+   */
+  void setText(const UnicodeString& newText,
+           UErrorCode &status);
+
+  /**
+   * Set the input text over which this <code>Normalizer</code> will iterate.
+   * The iteration position is set to the beginning.
+   *
+   * @param newText a CharacterIterator object that replaces the current input text
+   * @param status a UErrorCode
+   * @stable ICU 2.0
+   */
+  void setText(const CharacterIterator& newText,
+           UErrorCode &status);
+
+  /**
+   * Set the input text over which this <code>Normalizer</code> will iterate.
+   * The iteration position is set to the beginning.
+   *
+   * @param newText a string that replaces the current input text
+   * @param length the length of the string, or -1 if NUL-terminated
+   * @param status a UErrorCode
+   * @stable ICU 2.0
+   */
+  void setText(const UChar* newText,
+                    int32_t length,
+            UErrorCode &status);
+  /**
+   * Copies the input text into the UnicodeString argument.
+   *
+   * @param result Receives a copy of the text under iteration.
+   * @stable ICU 2.0
+   */
+  void            getText(UnicodeString&  result);
+
+  /**
+   * ICU "poor man's RTTI", returns a UClassID for this class.
+   * @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.
+   * @return a UClassID for the actual class.
+   * @stable ICU 2.2
+   */
+  virtual UClassID getDynamicClassID() const;
+
+private:
+  //-------------------------------------------------------------------------
+  // Private functions
+  //-------------------------------------------------------------------------
+
+  Normalizer(); // default constructor not implemented
+  Normalizer &operator=(const Normalizer &that); // assignment operator not implemented
+
+  // Private utility methods for iteration
+  // For documentation, see the source code
+  UBool nextNormalize();
+  UBool previousNormalize();
+
+  void    init();
+  void    clearBuffer(void);
+
+  //-------------------------------------------------------------------------
+  // Private data
+  //-------------------------------------------------------------------------
+
+  FilteredNormalizer2*fFilteredNorm2;  // owned if not NULL
+  const Normalizer2  *fNorm2;  // not owned; may be equal to fFilteredNorm2
+  UNormalizationMode  fUMode;
+  int32_t             fOptions;
+
+  // The input text and our position in it
+  CharacterIterator  *text;
+
+  // The normalization buffer is the result of normalization
+  // of the source in [currentIndex..nextIndex[ .
+  int32_t         currentIndex, nextIndex;
+
+  // A buffer for holding intermediate results
+  UnicodeString       buffer;
+  int32_t         bufferPos;
+};
+
+//-------------------------------------------------------------------------
+// Inline implementations
+//-------------------------------------------------------------------------
+
+inline UBool
+Normalizer::operator!= (const Normalizer& other) const
+{ return ! operator==(other); }
+
+inline UNormalizationCheckResult
+Normalizer::quickCheck(const UnicodeString& source,
+                       UNormalizationMode mode,
+                       UErrorCode &status) {
+    return quickCheck(source, mode, 0, status);
+}
+
+inline UBool
+Normalizer::isNormalized(const UnicodeString& source,
+                         UNormalizationMode mode,
+                         UErrorCode &status) {
+    return isNormalized(source, mode, 0, status);
+}
+
+inline int32_t
+Normalizer::compare(const UnicodeString &s1, const UnicodeString &s2,
+                    uint32_t options,
+                    UErrorCode &errorCode) {
+  // all argument checking is done in unorm_compare
+  return unorm_compare(s1.getBuffer(), s1.length(),
+                       s2.getBuffer(), s2.length(),
+                       options,
+                       &errorCode);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_NORMALIZATION */
+
+#endif // NORMLZR_H
diff --git a/source/common/unicode/parseerr.h b/source/common/unicode/parseerr.h
new file mode 100644
index 0000000..44ff008
--- /dev/null
+++ b/source/common/unicode/parseerr.h
@@ -0,0 +1,92 @@
+/*
+**********************************************************************
+*   Copyright (C) 1999-2005, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   Date        Name        Description
+*   03/14/00    aliu        Creation.
+*   06/27/00    aliu        Change from C++ class to C struct
+**********************************************************************
+*/
+#ifndef PARSEERR_H
+#define PARSEERR_H
+
+#include "unicode/utypes.h"
+
+
+/**
+ * \file
+ * \brief C API: Parse Error Information
+ */
+/**
+ * The capacity of the context strings in UParseError.
+ * @stable ICU 2.0
+ */ 
+enum { U_PARSE_CONTEXT_LEN = 16 };
+
+/**
+ * A UParseError struct is used to returned detailed information about
+ * parsing errors.  It is used by ICU parsing engines that parse long
+ * rules, patterns, or programs, where the text being parsed is long
+ * enough that more information than a UErrorCode is needed to
+ * localize the error.
+ *
+ * <p>The line, offset, and context fields are optional; parsing
+ * engines may choose not to use to use them.
+ *
+ * <p>The preContext and postContext strings include some part of the
+ * context surrounding the error.  If the source text is "let for=7"
+ * and "for" is the error (e.g., because it is a reserved word), then
+ * some examples of what a parser might produce are the following:
+ *
+ * <pre>
+ * preContext   postContext
+ * ""           ""            The parser does not support context
+ * "let "       "=7"          Pre- and post-context only
+ * "let "       "for=7"       Pre- and post-context and error text
+ * ""           "for"         Error text only
+ * </pre>
+ *
+ * <p>Examples of engines which use UParseError (or may use it in the
+ * future) are Transliterator, RuleBasedBreakIterator, and
+ * RegexPattern.
+ * 
+ * @stable ICU 2.0
+ */
+typedef struct UParseError {
+
+    /**
+     * The line on which the error occured.  If the parser uses this
+     * field, it sets it to the line number of the source text line on
+     * which the error appears, which will be be a value >= 1.  If the
+     * parse does not support line numbers, the value will be <= 0.
+     * @stable ICU 2.0
+     */
+    int32_t        line;
+
+    /**
+     * The character offset to the error.  If the line field is >= 1,
+     * then this is the offset from the start of the line.  Otherwise,
+     * this is the offset from the start of the text.  If the parser
+     * does not support this field, it will have a value < 0.
+     * @stable ICU 2.0
+     */
+    int32_t        offset;
+
+    /**
+     * Textual context before the error.  Null-terminated.  The empty
+     * string if not supported by parser.
+     * @stable ICU 2.0   
+     */
+    UChar          preContext[U_PARSE_CONTEXT_LEN];
+
+    /**
+     * The error itself and/or textual context after the error.
+     * Null-terminated.  The empty string if not supported by parser.
+     * @stable ICU 2.0   
+     */
+    UChar          postContext[U_PARSE_CONTEXT_LEN];
+
+} UParseError;
+
+#endif
diff --git a/source/common/unicode/parsepos.h b/source/common/unicode/parsepos.h
new file mode 100644
index 0000000..cdf49e0
--- /dev/null
+++ b/source/common/unicode/parsepos.h
@@ -0,0 +1,230 @@
+/*
+* Copyright (C) 1997-2005, International Business Machines Corporation and others. All Rights Reserved.
+*******************************************************************************
+*
+* File PARSEPOS.H
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   07/09/97    helena      Converted from java.
+*   07/17/98    stephen     Added errorIndex support.
+*   05/11/99    stephen     Cleaned up.
+*******************************************************************************
+*/
+
+#ifndef PARSEPOS_H
+#define PARSEPOS_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+
+ 
+U_NAMESPACE_BEGIN
+
+/**
+ * \file
+ * \brief C++ API: Canonical Iterator
+ */
+/** 
+ * <code>ParsePosition</code> is a simple class used by <code>Format</code>
+ * and its subclasses to keep track of the current position during parsing.
+ * The <code>parseObject</code> method in the various <code>Format</code>
+ * classes requires a <code>ParsePosition</code> object as an argument.
+ *
+ * <p>
+ * By design, as you parse through a string with different formats,
+ * you can use the same <code>ParsePosition</code>, since the index parameter
+ * records the current position.
+ *
+ * The ParsePosition class is not suitable for subclassing.
+ *
+ * @version     1.3 10/30/97
+ * @author      Mark Davis, Helena Shih
+ * @see         java.text.Format
+ */
+
+class U_COMMON_API ParsePosition : public UObject {
+public:
+    /**
+     * Default constructor, the index starts with 0 as default.
+     * @stable ICU 2.0
+     */
+    ParsePosition()
+        : UObject(),
+        index(0),
+        errorIndex(-1)
+      {}
+
+    /**
+     * Create a new ParsePosition with the given initial index.
+     * @param newIndex the new text offset.
+     * @stable ICU 2.0
+     */
+    ParsePosition(int32_t newIndex)
+        : UObject(),
+        index(newIndex),
+        errorIndex(-1)
+      {}
+
+    /**
+     * Copy constructor
+     * @param copy the object to be copied from.
+     * @stable ICU 2.0
+     */
+    ParsePosition(const ParsePosition& copy)
+        : UObject(copy),
+        index(copy.index),
+        errorIndex(copy.errorIndex)
+      {}
+
+    /**
+     * Destructor
+     * @stable ICU 2.0
+     */
+    virtual ~ParsePosition();
+
+    /**
+     * Assignment operator
+     * @stable ICU 2.0
+     */
+    ParsePosition&      operator=(const ParsePosition& copy);
+
+    /**
+     * Equality operator.
+     * @return TRUE if the two parse positions are equal, FALSE otherwise.
+     * @stable ICU 2.0
+     */
+    UBool              operator==(const ParsePosition& that) const;
+
+    /**
+     * Equality operator.
+     * @return TRUE if the two parse positions are not equal, FALSE otherwise.
+     * @stable ICU 2.0
+     */
+    UBool              operator!=(const ParsePosition& 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
+     */
+    ParsePosition *clone() const;
+
+    /**
+     * Retrieve the current parse position.  On input to a parse method, this
+     * is the index of the character at which parsing will begin; on output, it
+     * is the index of the character following the last character parsed.
+     * @return the current index.
+     * @stable ICU 2.0
+     */
+    int32_t getIndex(void) const;
+
+    /**
+     * Set the current parse position.
+     * @param index the new index.
+     * @stable ICU 2.0
+     */
+    void setIndex(int32_t index);
+
+    /**
+     * Set the index at which a parse error occurred.  Formatters
+     * should set this before returning an error code from their
+     * parseObject method.  The default value is -1 if this is not
+     * set.
+     * @stable ICU 2.0
+     */
+    void setErrorIndex(int32_t ei);
+
+    /**
+     * Retrieve the index at which an error occurred, or -1 if the
+     * error index has not been set.
+     * @stable ICU 2.0
+     */
+    int32_t getErrorIndex(void) const;
+
+    /**
+     * 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:
+    /**
+     * Input: the place you start parsing.
+     * <br>Output: position where the parse stopped.
+     * This is designed to be used serially,
+     * with each call setting index up for the next one.
+     */
+    int32_t index;
+
+    /**
+     * The index at which a parse error occurred.
+     */
+    int32_t errorIndex;
+
+};
+
+inline ParsePosition&
+ParsePosition::operator=(const ParsePosition& copy)
+{
+  index = copy.index;
+  errorIndex = copy.errorIndex;
+  return *this;
+}
+
+inline UBool
+ParsePosition::operator==(const ParsePosition& copy) const
+{
+  if(index != copy.index || errorIndex != copy.errorIndex)
+  return FALSE;
+  else
+  return TRUE;
+}
+
+inline UBool
+ParsePosition::operator!=(const ParsePosition& copy) const
+{
+  return !operator==(copy);
+}
+
+inline int32_t
+ParsePosition::getIndex() const
+{
+  return index;
+}
+
+inline void
+ParsePosition::setIndex(int32_t offset)
+{
+  this->index = offset;
+}
+
+inline int32_t
+ParsePosition::getErrorIndex() const
+{
+  return errorIndex;
+}
+
+inline void
+ParsePosition::setErrorIndex(int32_t ei)
+{
+  this->errorIndex = ei;
+}
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/unicode/platform.h.in b/source/common/unicode/platform.h.in
new file mode 100644
index 0000000..f7b1338
--- /dev/null
+++ b/source/common/unicode/platform.h.in
@@ -0,0 +1,401 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* Note: autoconf creates platform.h from platform.h.in at configure time.
+*
+******************************************************************************
+*
+*  FILE NAME : platform.h
+*
+*   Date        Name        Description
+*   05/13/98    nos         Creation (content moved here from ptypes.h).
+*   03/02/99    stephen     Added AS400 support.
+*   03/30/99    stephen     Added Linux support.
+*   04/13/99    stephen     Reworked for autoconf.
+******************************************************************************
+*/
+
+#ifndef _PLATFORM_H
+#define _PLATFORM_H
+
+/**
+ * \file 
+ * \brief Basic types for the platform 
+ */
+
+/* This file should be included before uvernum.h. */
+#if defined(UVERNUM_H)
+# error Do not include unicode/uvernum.h before #including unicode/platform.h.  Instead of unicode/uvernum.h, #include unicode/uversion.h
+#endif
+
+/**
+ * Determine wheter to enable auto cleanup of libraries. 
+ * @internal
+ */
+#ifndef UCLN_NO_AUTO_CLEANUP
+#define UCLN_NO_AUTO_CLEANUP @UCLN_NO_AUTO_CLEANUP@
+#endif
+
+/* Need platform.h when using CYGWINMSVC to get definitions above. Ignore everything else. */
+#ifndef CYGWINMSVC
+
+/** Define the platform we're on. */
+#ifndef @platform@
+#define @platform@
+#endif
+
+/**
+ * \def U_HAVE_DIRENT_H
+ * Define whether dirent.h is available 
+ * @internal
+ */
+#ifndef U_HAVE_DIRENT_H
+#define U_HAVE_DIRENT_H @U_HAVE_DIRENT_H@
+#endif
+
+/** Define whether inttypes.h is available */
+#ifndef U_HAVE_INTTYPES_H
+#define U_HAVE_INTTYPES_H @U_HAVE_INTTYPES_H@
+#endif
+
+/**
+ * Define what support for C++ streams is available.
+ *     If U_IOSTREAM_SOURCE is set to 199711, then &lt;iostream&gt; is available
+ * (1997711 is the date the ISO/IEC C++ FDIS was published), and then
+ * one should qualify streams using the std namespace in ICU header
+ * files.
+ *     If U_IOSTREAM_SOURCE is set to 198506, then &lt;iostream.h&gt; is
+ * available instead (198506 is the date when Stroustrup published
+ * "An Extensible I/O Facility for C++" at the summer USENIX conference).
+ *     If U_IOSTREAM_SOURCE is 0, then C++ streams are not available and
+ * support for them will be silently suppressed in ICU.
+ *
+ */
+
+#ifndef U_IOSTREAM_SOURCE
+#define U_IOSTREAM_SOURCE @U_IOSTREAM_SOURCE@
+#endif
+
+/**
+ * \def U_HAVE_STD_STRING
+ * Define whether the standard C++ (STL) &lt;string&gt; header is available.
+ * For platforms that do not use platform.h and do not define this constant
+ * in their platform-specific headers, std_string.h defaults
+ * U_HAVE_STD_STRING to 1.
+ * @internal
+ */
+#ifndef U_HAVE_STD_STRING
+#define U_HAVE_STD_STRING @U_HAVE_STD_STRING@
+#endif
+
+/** @{ Determines whether specific types are available */
+#ifndef U_HAVE_INT8_T
+#define U_HAVE_INT8_T @HAVE_INT8_T@
+#endif
+
+#ifndef U_HAVE_UINT8_T
+#define U_HAVE_UINT8_T @HAVE_UINT8_T@
+#endif
+
+#ifndef U_HAVE_INT16_T
+#define U_HAVE_INT16_T @HAVE_INT16_T@
+#endif
+
+#ifndef U_HAVE_UINT16_T
+#define U_HAVE_UINT16_T @HAVE_UINT16_T@
+#endif
+
+#ifndef U_HAVE_INT32_T
+#define U_HAVE_INT32_T @HAVE_INT32_T@
+#endif
+
+#ifndef U_HAVE_UINT32_T
+#define U_HAVE_UINT32_T @HAVE_UINT32_T@
+#endif
+
+#ifndef U_HAVE_INT64_T
+#define U_HAVE_INT64_T @HAVE_INT64_T@
+#endif
+
+#ifndef U_HAVE_UINT64_T
+#define U_HAVE_UINT64_T @HAVE_UINT64_T@
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/** @{ Compiler and environment features                                     */
+/*===========================================================================*/
+
+/* Define whether namespace is supported */
+#ifndef U_HAVE_NAMESPACE
+#define U_HAVE_NAMESPACE @U_HAVE_NAMESPACE@
+#endif
+
+/* Determines the endianness of the platform
+   It's done this way in case multiple architectures are being built at once.
+   For example, Darwin supports fat binaries, which can be both PPC and x86 based. */
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN)
+#define U_IS_BIG_ENDIAN (BYTE_ORDER == BIG_ENDIAN)
+#else
+#define U_IS_BIG_ENDIAN @U_IS_BIG_ENDIAN@
+#endif
+
+/* 1 or 0 to enable or disable threads.  If undefined, default is: enable threads. */
+#ifndef ICU_USE_THREADS 
+#define ICU_USE_THREADS @ICU_USE_THREADS@
+#endif
+
+/* On strong memory model CPUs (e.g. x86 CPUs), we use a safe & quick double check lock. */
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+#define UMTX_STRONG_MEMORY_MODEL 1
+#endif
+
+#ifndef U_DEBUG
+#define U_DEBUG @ENABLE_DEBUG@
+#endif
+
+#ifndef U_RELEASE
+#define U_RELEASE @ENABLE_RELEASE@
+#endif
+
+/* Determine whether to disable renaming or not. This overrides the
+   setting in umachine.h which is for all platforms. */
+#ifndef U_DISABLE_RENAMING
+#define U_DISABLE_RENAMING @U_DISABLE_RENAMING@
+#endif
+
+/* Determine whether to override new and delete. */
+#ifndef U_OVERRIDE_CXX_ALLOCATION
+#define U_OVERRIDE_CXX_ALLOCATION @U_OVERRIDE_CXX_ALLOCATION@
+#endif
+/* Determine whether to override placement new and delete for STL. */
+#ifndef U_HAVE_PLACEMENT_NEW
+#define U_HAVE_PLACEMENT_NEW @U_HAVE_PLACEMENT_NEW@
+#endif
+
+/* Determine whether to enable tracing. */
+#ifndef U_ENABLE_TRACING
+#define U_ENABLE_TRACING @U_ENABLE_TRACING@
+#endif
+
+/**
+ * Whether to enable Dynamic loading in ICU
+ * @internal
+ */
+#ifndef U_ENABLE_DYLOAD
+#define U_ENABLE_DYLOAD @U_ENABLE_DYLOAD@
+#endif
+
+/**
+ * Whether to test Dynamic loading as an OS capabilty
+ * @internal
+ */
+#ifndef U_CHECK_DYLOAD
+#define U_CHECK_DYLOAD @U_CHECK_DYLOAD@
+#endif
+
+
+/** Do we allow ICU users to use the draft APIs by default? */
+#ifndef U_DEFAULT_SHOW_DRAFT
+#define U_DEFAULT_SHOW_DRAFT @U_DEFAULT_SHOW_DRAFT@
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/** @{ Character data types                                                      */
+/*===========================================================================*/
+
+#if ((defined(OS390) && (!defined(__CHARSET_LIB) || !__CHARSET_LIB))) || defined(OS400)
+#   define U_CHARSET_FAMILY 1
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/** @{ Information about wchar support                                           */
+/*===========================================================================*/
+
+#ifndef U_HAVE_WCHAR_H
+#define U_HAVE_WCHAR_H      @U_HAVE_WCHAR_H@
+#endif
+
+#ifndef U_SIZEOF_WCHAR_T
+#define U_SIZEOF_WCHAR_T    @U_SIZEOF_WCHAR_T@
+#endif
+
+#ifndef U_HAVE_WCSCPY
+#define U_HAVE_WCSCPY       @U_HAVE_WCSCPY@
+#endif
+
+/** @} */
+
+/**
+ * @{
+ * \def U_DECLARE_UTF16
+ * Do not use this macro. Use the UNICODE_STRING or U_STRING_DECL macros
+ * instead.
+ * @internal
+ *
+ * \def U_GNUC_UTF16_STRING
+ * @internal
+ */
+#ifndef U_GNUC_UTF16_STRING
+#define U_GNUC_UTF16_STRING @U_CHECK_GNUC_UTF16_STRING@
+#endif
+#if @U_CHECK_UTF16_STRING@ || defined(U_CHECK_UTF16_STRING)
+#if (defined(__xlC__) && defined(__IBM_UTF_LITERAL) && U_SIZEOF_WCHAR_T != 2) \
+    || (defined(__HP_aCC) && __HP_aCC >= 035000) \
+    || (defined(__HP_cc) && __HP_cc >= 111106) \
+    || U_GNUC_UTF16_STRING
+#define U_DECLARE_UTF16(string) u ## string
+#elif (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x550)
+/* || (defined(__SUNPRO_C) && __SUNPRO_C >= 0x580) */
+/* Sun's C compiler has issues with this notation, and it's unreliable. */
+#define U_DECLARE_UTF16(string) U ## string
+#elif U_SIZEOF_WCHAR_T == 2 \
+    && (U_CHARSET_FAMILY == 0 || ((defined(OS390) || defined(OS400)) && defined(__UCS2__)))
+#define U_DECLARE_UTF16(string) L ## string
+#endif
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/** @{ Information about POSIX support                                           */
+/*===========================================================================*/
+
+#ifndef U_HAVE_NL_LANGINFO_CODESET
+#define U_HAVE_NL_LANGINFO_CODESET  @U_HAVE_NL_LANGINFO_CODESET@
+#endif
+
+#ifndef U_NL_LANGINFO_CODESET
+#define U_NL_LANGINFO_CODESET       @U_NL_LANGINFO_CODESET@
+#endif
+
+#if @U_HAVE_TZSET@
+#define U_TZSET         @U_TZSET@
+#endif
+#if @U_HAVE_TIMEZONE@
+#define U_TIMEZONE      @U_TIMEZONE@
+#endif
+#if @U_HAVE_TZNAME@
+#define U_TZNAME        @U_TZNAME@
+#endif
+
+#define U_HAVE_MMAP     @HAVE_MMAP@
+#define U_HAVE_POPEN    @U_HAVE_POPEN@
+
+/** @} */
+
+/*===========================================================================*/
+/** @{ Symbol import-export control                                              */
+/*===========================================================================*/
+
+#if @U_USE_GCC_VISIBILITY_ATTRIBUTE@
+#define U_EXPORT __attribute__((visibility("default")))
+#elif (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x550) \
+   || (defined(__SUNPRO_C) && __SUNPRO_C >= 0x550) 
+#define U_EXPORT __global
+/*#elif defined(__HP_aCC) || defined(__HP_cc)
+#define U_EXPORT __declspec(dllexport)*/
+#else
+#define U_EXPORT
+#endif
+
+/* U_CALLCONV is releated to U_EXPORT2 */
+#define U_EXPORT2
+
+/* cygwin needs to export/import data */
+#if defined(U_CYGWIN) && !defined(__GNUC__)
+#define U_IMPORT __declspec(dllimport)
+#else
+#define U_IMPORT 
+#endif
+
+/* @} */
+
+/*===========================================================================*/
+/** @{ Code alignment and C function inlining                                    */
+/*===========================================================================*/
+
+#ifndef U_INLINE
+#   ifdef __cplusplus
+#       define U_INLINE inline
+#   else
+#       define U_INLINE @U_INLINE@
+#   endif
+#endif
+
+#ifndef U_ALIGN_CODE
+#define U_ALIGN_CODE(n) 
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/** @{ GCC built in functions for atomic memory operations                       */
+/*===========================================================================*/
+
+/**
+ * \def U_HAVE_GCC_ATOMICS
+ * @internal
+ */
+#ifndef U_HAVE_GCC_ATOMICS
+#define U_HAVE_GCC_ATOMICS @U_HAVE_GCC_ATOMICS@
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/** @{ Programs used by ICU code                                                 */
+/*===========================================================================*/
+
+/**
+ * \def U_MAKE
+ * What program to execute to run 'make'
+ */
+#ifndef U_MAKE
+#define U_MAKE  "@U_MAKE@"
+#endif
+
+/** @} */
+
+#endif /* CYGWINMSVC */
+
+/*===========================================================================*/
+/* Custom icu entry point renaming                                                  */
+/*===========================================================================*/
+
+/**
+ * Define the library suffix with C syntax.
+ * @internal
+ */
+# define U_LIB_SUFFIX_C_NAME @ICULIBSUFFIXCNAME@
+/**
+ * Define the library suffix as a string with C syntax
+ * @internal
+ */
+# define U_LIB_SUFFIX_C_NAME_STRING "@ICULIBSUFFIXCNAME@"
+/**
+ * 1 if a custom library suffix is set
+ * @internal
+ */
+# define U_HAVE_LIB_SUFFIX @U_HAVE_LIB_SUFFIX@
+
+#if U_HAVE_LIB_SUFFIX
+# ifndef U_ICU_ENTRY_POINT_RENAME
+/* Renaming pattern:    u_strcpy_41_suffix */
+#  define U_ICU_ENTRY_POINT_RENAME(x)    x ## _ ## @LIB_VERSION_MAJOR@ ## @ICULIBSUFFIXCNAME@
+#  define U_DEF_ICUDATA_ENTRY_POINT(major, minor) icudt##@ICULIBSUFFIXCNAME@##major##minor##_dat
+
+# endif
+#endif
+
+#endif
diff --git a/source/common/unicode/ppalmos.h b/source/common/unicode/ppalmos.h
new file mode 100644
index 0000000..c15b2ce
--- /dev/null
+++ b/source/common/unicode/ppalmos.h
@@ -0,0 +1,273 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1997-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+*  FILE NAME : ppalmos.h
+*
+*   Date        Name        Description
+*   05/10/04    Ken Krugler Creation (copied from pwin32.h & modified).
+******************************************************************************
+*/
+
+#ifndef U_PPALMOS_H
+#define U_PPALMOS_H
+
+ /**
+  * \file
+  * \brief Configuration constants for the Palm OS platform
+  */
+  
+/* Define the platform we're on. */
+#ifndef U_PALMOS
+#define U_PALMOS
+#endif
+
+/* _MSC_VER is used to detect the Microsoft compiler. */
+#if defined(_MSC_VER)
+#define U_INT64_IS_LONG_LONG 0
+#else
+#define U_INT64_IS_LONG_LONG 1
+#endif
+
+/* Define whether inttypes.h is available */
+#ifndef U_HAVE_INTTYPES_H
+#define U_HAVE_INTTYPES_H 1
+#endif
+
+/*
+ * Define what support for C++ streams is available.
+ *     If U_IOSTREAM_SOURCE is set to 199711, then <iostream> is available
+ * (1997711 is the date the ISO/IEC C++ FDIS was published), and then
+ * one should qualify streams using the std namespace in ICU header
+ * files.
+ *     If U_IOSTREAM_SOURCE is set to 198506, then <iostream.h> is
+ * available instead (198506 is the date when Stroustrup published
+ * "An Extensible I/O Facility for C++" at the summer USENIX conference).
+ *     If U_IOSTREAM_SOURCE is 0, then C++ streams are not available and
+ * support for them will be silently suppressed in ICU.
+ *
+ */
+
+#ifndef U_IOSTREAM_SOURCE
+#define U_IOSTREAM_SOURCE 199711
+#endif
+
+/* Determines whether specific types are available */
+#ifndef U_HAVE_INT8_T
+#define U_HAVE_INT8_T U_HAVE_INTTYPES_H
+#endif
+
+#ifndef U_HAVE_UINT8_T
+#define U_HAVE_UINT8_T U_HAVE_INTTYPES_H
+#endif
+
+#ifndef U_HAVE_INT16_T
+#define U_HAVE_INT16_T U_HAVE_INTTYPES_H
+#endif
+
+#ifndef U_HAVE_UINT16_T
+#define U_HAVE_UINT16_T U_HAVE_INTTYPES_H
+#endif
+
+#ifndef U_HAVE_INT32_T
+#define U_HAVE_INT32_T U_HAVE_INTTYPES_H
+#endif
+
+#ifndef U_HAVE_UINT32_T
+#define U_HAVE_UINT32_T U_HAVE_INTTYPES_H
+#endif
+
+#ifndef U_HAVE_INT64_T
+#define U_HAVE_INT64_T U_HAVE_INTTYPES_H
+#endif
+
+#ifndef U_HAVE_UINT64_T
+#define U_HAVE_UINT64_T U_HAVE_INTTYPES_H
+#endif
+
+
+/*===========================================================================*/
+/* Generic data types                                                        */
+/*===========================================================================*/
+
+/* If your platform does not have the <inttypes.h> header, you may
+   need to edit the typedefs below. */
+#if U_HAVE_INTTYPES_H
+#include <inttypes.h>
+#else /* U_HAVE_INTTYPES_H */
+
+#if ! U_HAVE_INT8_T
+typedef signed char int8_t;
+#endif
+
+#if ! U_HAVE_UINT8_T
+typedef unsigned char uint8_t;
+#endif
+
+#if ! U_HAVE_INT16_T
+typedef signed short int16_t;
+#endif
+
+#if ! U_HAVE_UINT16_T
+typedef unsigned short uint16_t;
+#endif
+
+#if ! U_HAVE_INT32_T
+typedef signed int int32_t;
+#endif
+
+#if ! U_HAVE_UINT32_T
+typedef unsigned int uint32_t;
+#endif
+
+#if ! U_HAVE_INT64_T
+#if U_INT64_IS_LONG_LONG
+    typedef signed long long int64_t;
+#else
+    typedef signed __int64 int64_t;
+#endif
+#endif
+
+#if ! U_HAVE_UINT64_T
+#if U_INT64_IS_LONG_LONG
+    typedef unsigned long long uint64_t;
+#else
+    typedef unsigned __int64 uint64_t;
+#endif
+#endif
+#endif
+
+/*===========================================================================*/
+/* Compiler and environment features                                         */
+/*===========================================================================*/
+
+/* Define whether namespace is supported */
+#ifndef U_HAVE_NAMESPACE
+#define U_HAVE_NAMESPACE 1
+#endif
+
+/* Determines the endianness of the platform */
+#define U_IS_BIG_ENDIAN 0
+
+/* 1 or 0 to enable or disable threads.  If undefined, default is: enable threads. */
+#define ICU_USE_THREADS 1
+
+#ifndef U_DEBUG
+#ifdef _DEBUG
+#define U_DEBUG 1
+#else
+#define U_DEBUG 0
+#endif
+#endif
+
+#ifndef U_RELEASE
+#ifdef NDEBUG
+#define U_RELEASE 1
+#else
+#define U_RELEASE 0
+#endif
+#endif
+
+/* Determine whether to disable renaming or not. This overrides the
+   setting in umachine.h which is for all platforms. */
+#ifndef U_DISABLE_RENAMING
+#define U_DISABLE_RENAMING 0
+#endif
+
+/* Determine whether to override new and delete. */
+#ifndef U_OVERRIDE_CXX_ALLOCATION
+#define U_OVERRIDE_CXX_ALLOCATION 1
+#endif
+/* Determine whether to override placement new and delete for STL. */
+#ifndef U_HAVE_PLACEMENT_NEW
+#define U_HAVE_PLACEMENT_NEW 0
+#endif
+/* Determine whether to override new and delete for MFC. */
+#if !defined(U_HAVE_DEBUG_LOCATION_NEW) && defined(_MSC_VER)
+#define U_HAVE_DEBUG_LOCATION_NEW 0
+#endif
+
+/* Determine whether to enable tracing. */
+#ifndef U_ENABLE_TRACING
+#define U_ENABLE_TRACING 1
+#endif
+
+/* Do we allow ICU users to use the draft APIs by default? */
+#ifndef U_DEFAULT_SHOW_DRAFT
+#define U_DEFAULT_SHOW_DRAFT 1
+#endif
+
+/* Define the library suffix in a C syntax. */
+#define U_HAVE_LIB_SUFFIX 0
+#define U_LIB_SUFFIX_C_NAME 
+#define U_LIB_SUFFIX_C_NAME_STRING ""
+
+/*===========================================================================*/
+/* Information about wchar support                                           */
+/*===========================================================================*/
+
+#define U_HAVE_WCHAR_H 1
+#define U_SIZEOF_WCHAR_T 2
+
+#define U_HAVE_WCSCPY    0
+
+/*===========================================================================*/
+/* Information about POSIX support                                           */
+/*===========================================================================*/
+
+
+/* TODO: Fix Palm OS's determination of a timezone */
+#if 0
+#define U_TZSET         _tzset
+#endif
+#if 0
+#define U_TIMEZONE      _timezone
+#endif
+#if 0
+#define U_TZNAME        _tzname
+#endif
+
+#define U_HAVE_MMAP 0
+#define U_HAVE_POPEN 0
+
+/*===========================================================================*/
+/* Symbol import-export control                                              */
+/*===========================================================================*/
+
+#define U_EXPORT
+#define U_EXPORT2
+#define U_IMPORT
+
+/*===========================================================================*/
+/* Code alignment and C function inlining                                    */
+/*===========================================================================*/
+
+#ifndef U_INLINE
+#   ifdef __cplusplus
+#       define U_INLINE inline
+#   else
+#       define U_INLINE __inline
+#   endif
+#endif
+
+#if defined(_MSC_VER) && defined(_M_IX86)
+#define U_ALIGN_CODE(val)    __asm      align val
+#else
+#define U_ALIGN_CODE(val)
+#endif
+
+
+/*===========================================================================*/
+/* Programs used by ICU code                                                 */
+/*===========================================================================*/
+
+#ifndef U_MAKE
+#define U_MAKE  "nmake"
+#define U_MAKE_IS_NMAKE 1
+#endif
+
+#endif
diff --git a/source/common/unicode/ptypes.h b/source/common/unicode/ptypes.h
new file mode 100644
index 0000000..1f34d2f
--- /dev/null
+++ b/source/common/unicode/ptypes.h
@@ -0,0 +1,92 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+*  FILE NAME : ptypes.h
+*
+*   Date        Name        Description
+*   05/13/98    nos         Creation (content moved here from ptypes.h).
+*   03/02/99    stephen     Added AS400 support.
+*   03/30/99    stephen     Added Linux support.
+*   04/13/99    stephen     Reworked for autoconf.
+*   09/18/08    srl         Moved basic types back to ptypes.h from platform.h
+******************************************************************************
+*/
+
+#ifndef _PTYPES_H
+#define _PTYPES_H
+
+#include <sys/types.h>
+
+#include "unicode/platform.h"
+
+/*===========================================================================*/
+/* Generic data types                                                        */
+/*===========================================================================*/
+
+/* If your platform does not have the <inttypes.h> header, you may
+   need to edit the typedefs below. */
+#if U_HAVE_INTTYPES_H
+
+/* autoconf 2.13 sometimes can't properly find the data types in <inttypes.h> */
+/* os/390 needs <inttypes.h>, but it doesn't have int8_t, and it sometimes */
+/* doesn't have uint8_t depending on the OS version. */
+/* So we have this work around. */
+#ifdef OS390
+/* The features header is needed to get (u)int64_t sometimes. */
+#include <features.h>
+#if ! U_HAVE_INT8_T
+typedef signed char int8_t;
+#endif
+#if !defined(__uint8_t)
+#define __uint8_t 1
+typedef unsigned char uint8_t;
+#endif
+#endif /* OS390 */
+
+#include <inttypes.h>
+
+#else /* U_HAVE_INTTYPES_H */
+
+#if ! U_HAVE_INT8_T
+typedef signed char int8_t;
+#endif
+
+#if ! U_HAVE_UINT8_T
+typedef unsigned char uint8_t;
+#endif
+
+#if ! U_HAVE_INT16_T
+typedef signed short int16_t;
+#endif
+
+#if ! U_HAVE_UINT16_T
+typedef unsigned short uint16_t;
+#endif
+
+#if ! U_HAVE_INT32_T
+typedef signed int int32_t;
+#endif
+
+#if ! U_HAVE_UINT32_T
+typedef unsigned int uint32_t;
+#endif
+
+#if ! U_HAVE_INT64_T
+    typedef signed long long int64_t;
+/* else we may not have a 64-bit type */
+#endif
+
+#if ! U_HAVE_UINT64_T
+    typedef unsigned long long uint64_t;
+/* else we may not have a 64-bit type */
+#endif
+
+#endif /* U_HAVE_INTTYPES_H */
+
+#endif /* _PTYPES_H */
+
diff --git a/source/common/unicode/putil.h b/source/common/unicode/putil.h
new file mode 100644
index 0000000..090b226
--- /dev/null
+++ b/source/common/unicode/putil.h
@@ -0,0 +1,193 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1997-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+*  FILE NAME : putil.h
+*
+*   Date        Name        Description
+*   05/14/98    nos         Creation (content moved here from utypes.h).
+*   06/17/99    erm         Added IEEE_754
+*   07/22/98    stephen     Added IEEEremainder, max, min, trunc
+*   08/13/98    stephen     Added isNegativeInfinity, isPositiveInfinity
+*   08/24/98    stephen     Added longBitsFromDouble
+*   03/02/99    stephen     Removed openFile().  Added AS400 support.
+*   04/15/99    stephen     Converted to C
+*   11/15/99    helena      Integrated S/390 changes for IEEE support.
+*   01/11/00    helena      Added u_getVersion.
+******************************************************************************
+*/
+
+#ifndef PUTIL_H
+#define PUTIL_H
+
+#include "unicode/utypes.h"
+ /**
+  * \file
+  * \brief C API: Platform Utilities
+  */
+
+/** Define this to 1 if your platform supports IEEE 754 floating point,
+   to 0 if it does not. */
+#ifndef IEEE_754
+#   define IEEE_754 1
+#endif
+
+/*==========================================================================*/
+/* Platform utilities                                                       */
+/*==========================================================================*/
+
+/**
+ * Platform utilities isolates the platform dependencies of the
+ * libarary.  For each platform which this code is ported to, these
+ * functions may have to be re-implemented.
+ */
+
+/**
+ * Return the ICU data directory. 
+ * The data directory is where common format ICU data files (.dat files)
+ *   are loaded from.  Note that normal use of the built-in ICU
+ *   facilities does not require loading of an external data file;
+ *   unless you are adding custom data to ICU, the data directory
+ *   does not need to be set.
+ *
+ * The data directory is determined as follows:
+ *    If u_setDataDirectory() has been called, that is it, otherwise
+ *    if the ICU_DATA environment variable is set, use that, otherwise
+ *    If a data directory was specifed at ICU build time
+ *      <code>
+ * \code
+ *        #define ICU_DATA_DIR "path" 
+ * \endcode
+ * </code> use that,
+ *    otherwise no data directory is available.
+ *
+ * @return the data directory, or an empty string ("") if no data directory has
+ *         been specified.
+ *   
+ * @stable ICU 2.0
+ */
+U_STABLE const char* U_EXPORT2 u_getDataDirectory(void);
+
+/** 
+ * Set the ICU data directory. 
+ * The data directory is where common format ICU data files (.dat files)
+ *   are loaded from.  Note that normal use of the built-in ICU
+ *   facilities does not require loading of an external data file;
+ *   unless you are adding custom data to ICU, the data directory
+ *   does not need to be set.
+ *
+ * This function should be called at most once in a process, before the
+ * first ICU operation (e.g., u_init()) that will require the loading of an
+ * ICU data file.
+ * This function is not thread-safe. Use it before calling ICU APIs from
+ * multiple threads.
+ *
+ * @param directory The directory to be set.
+ *
+ * @see u_init
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 u_setDataDirectory(const char *directory);
+
+#if !U_CHARSET_IS_UTF8
+/**
+ * Please use ucnv_getDefaultName() instead.
+ * Return the default codepage for this platform and locale.
+ * This function can call setlocale() on Unix platforms. Please read the
+ * platform documentation on setlocale() before calling this function.
+ * @return the default codepage for this platform 
+ * @internal
+ */
+U_INTERNAL const char*  U_EXPORT2 uprv_getDefaultCodepage(void);
+#endif
+
+/**
+ * Please use uloc_getDefault() instead.
+ * Return the default locale ID string by querying ths system, or
+ *     zero if one cannot be found. 
+ * This function can call setlocale() on Unix platforms. Please read the
+ * platform documentation on setlocale() before calling this function.
+ * @return the default locale ID string
+ * @internal
+ */
+U_INTERNAL const char*  U_EXPORT2 uprv_getDefaultLocaleID(void);
+
+/**
+ * @{
+ * Filesystem file and path separator characters.
+ * Example: '/' and ':' on Unix, '\\' and ';' on Windows.
+ * @stable ICU 2.0
+ */
+#ifdef XP_MAC
+#   define U_FILE_SEP_CHAR ':'
+#   define U_FILE_ALT_SEP_CHAR ':'
+#   define U_PATH_SEP_CHAR ';'
+#   define U_FILE_SEP_STRING ":"
+#   define U_FILE_ALT_SEP_STRING ":"
+#   define U_PATH_SEP_STRING ";"
+#elif defined(U_WINDOWS)
+#   define U_FILE_SEP_CHAR '\\'
+#   define U_FILE_ALT_SEP_CHAR '/'
+#   define U_PATH_SEP_CHAR ';'
+#   define U_FILE_SEP_STRING "\\"
+#   define U_FILE_ALT_SEP_STRING "/"
+#   define U_PATH_SEP_STRING ";"
+#else
+#   define U_FILE_SEP_CHAR '/'
+#   define U_FILE_ALT_SEP_CHAR '/'
+#   define U_PATH_SEP_CHAR ':'
+#   define U_FILE_SEP_STRING "/"
+#   define U_FILE_ALT_SEP_STRING "/"
+#   define U_PATH_SEP_STRING ":"
+#endif
+
+/** @} */
+
+/**
+ * Convert char characters to UChar characters.
+ * This utility function is useful only for "invariant characters"
+ * that are encoded in the platform default encoding.
+ * They are a small, constant subset of the encoding and include
+ * just the latin letters, digits, and some punctuation.
+ * For details, see U_CHARSET_FAMILY.
+ *
+ * @param cs Input string, points to <code>length</code>
+ *           character bytes from a subset of the platform encoding.
+ * @param us Output string, points to memory for <code>length</code>
+ *           Unicode characters.
+ * @param length The number of characters to convert; this may
+ *               include the terminating <code>NUL</code>.
+ *
+ * @see U_CHARSET_FAMILY
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+u_charsToUChars(const char *cs, UChar *us, int32_t length);
+
+/**
+ * Convert UChar characters to char characters.
+ * This utility function is useful only for "invariant characters"
+ * that can be encoded in the platform default encoding.
+ * They are a small, constant subset of the encoding and include
+ * just the latin letters, digits, and some punctuation.
+ * For details, see U_CHARSET_FAMILY.
+ *
+ * @param us Input string, points to <code>length</code>
+ *           Unicode characters that can be encoded with the
+ *           codepage-invariant subset of the platform encoding.
+ * @param cs Output string, points to memory for <code>length</code>
+ *           character bytes.
+ * @param length The number of characters to convert; this may
+ *               include the terminating <code>NUL</code>.
+ *
+ * @see U_CHARSET_FAMILY
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+u_UCharsToChars(const UChar *us, char *cs, int32_t length);
+
+#endif
diff --git a/source/common/unicode/pwin32.h b/source/common/unicode/pwin32.h
new file mode 100644
index 0000000..1c04e86
--- /dev/null
+++ b/source/common/unicode/pwin32.h
@@ -0,0 +1,372 @@
+/*
+ ******************************************************************************
+ *
+ *   Copyright (C) 1997-2010, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ *
+ ******************************************************************************
+ *
+ *  FILE NAME : platform.h
+ *
+ *   Date        Name        Description
+ *   05/13/98    nos         Creation (content moved here from ptypes.h).
+ *   03/02/99    stephen     Added AS400 support.
+ *   03/30/99    stephen     Added Linux support.
+ *   04/13/99    stephen     Reworked for autoconf.
+ ******************************************************************************
+ */
+
+ /**
+  * \file
+  * \brief Configuration constants for the Windows platform
+  */
+  
+/** Define the platform we're on. */
+#ifndef U_WINDOWS
+#define U_WINDOWS
+#endif
+
+#if defined(__BORLANDC__)
+#define U_HAVE_PLACEMENT_NEW 0
+#define __STDC_CONSTANT_MACROS
+#endif
+
+/** _MSC_VER is used to detect the Microsoft compiler. */
+#if defined(_MSC_VER)
+#define U_INT64_IS_LONG_LONG 0
+#else
+#define U_INT64_IS_LONG_LONG 1
+#endif
+
+/** Define whether inttypes.h is available */
+#ifndef U_HAVE_INTTYPES_H
+#   if defined(__BORLANDC__) || defined(__MINGW32__)
+#       define U_HAVE_INTTYPES_H 1
+#   else
+#       define U_HAVE_INTTYPES_H 0
+#   endif
+#endif
+
+/**
+ * Define what support for C++ streams is available.
+ *     If U_IOSTREAM_SOURCE is set to 199711, then &lt;iostream&gt; is available
+ * (1997711 is the date the ISO/IEC C++ FDIS was published), and then
+ * one should qualify streams using the std namespace in ICU header
+ * files.
+ *     If U_IOSTREAM_SOURCE is set to 198506, then &lt;iostream.h&gt; is
+ * available instead (198506 is the date when Stroustrup published
+ * "An Extensible I/O Facility for C++" at the summer USENIX conference).
+ *     If U_IOSTREAM_SOURCE is 0, then C++ streams are not available and
+ * support for them will be silently suppressed in ICU.
+ *
+ */
+
+#ifndef U_IOSTREAM_SOURCE
+#define U_IOSTREAM_SOURCE 199711
+#endif
+
+/** @{
+ * Determines whether specific types are available */
+#ifndef U_HAVE_INT8_T
+#define U_HAVE_INT8_T U_HAVE_INTTYPES_H
+#endif
+
+#ifndef U_HAVE_UINT8_T
+#define U_HAVE_UINT8_T U_HAVE_INTTYPES_H
+#endif
+
+#ifndef U_HAVE_INT16_T
+#define U_HAVE_INT16_T U_HAVE_INTTYPES_H
+#endif
+
+#ifndef U_HAVE_UINT16_T
+#define U_HAVE_UINT16_T U_HAVE_INTTYPES_H
+#endif
+
+#ifndef U_HAVE_INT32_T
+#define U_HAVE_INT32_T U_HAVE_INTTYPES_H
+#endif
+
+#ifndef U_HAVE_UINT32_T
+#define U_HAVE_UINT32_T U_HAVE_INTTYPES_H
+#endif
+
+#ifndef U_HAVE_INT64_T
+#define U_HAVE_INT64_T U_HAVE_INTTYPES_H
+#endif
+
+#ifndef U_HAVE_UINT64_T
+#define U_HAVE_UINT64_T U_HAVE_INTTYPES_H
+#endif
+
+/** @} */
+
+/** Define 64 bit limits */
+#if !U_INT64_IS_LONG_LONG
+# ifndef INT64_C
+#  define INT64_C(x) ((int64_t)x)
+# endif
+# ifndef UINT64_C
+#  define UINT64_C(x) ((uint64_t)x)
+# endif
+/** else use the umachine.h definition */
+#endif
+
+/*===========================================================================*/
+/** @{
+ * Generic data types                                                        */
+/*===========================================================================*/
+
+/** If your platform does not have the <inttypes.h> header, you may
+   need to edit the typedefs below. */
+#if U_HAVE_INTTYPES_H
+#include <inttypes.h>
+#else /* U_HAVE_INTTYPES_H */
+
+#if ! U_HAVE_INT8_T
+typedef signed char int8_t;
+#endif
+
+#if ! U_HAVE_UINT8_T
+typedef unsigned char uint8_t;
+#endif
+
+#if ! U_HAVE_INT16_T
+typedef signed short int16_t;
+#endif
+
+#if ! U_HAVE_UINT16_T
+typedef unsigned short uint16_t;
+#endif
+
+#if ! U_HAVE_INT32_T
+typedef signed int int32_t;
+#endif
+
+#if ! U_HAVE_UINT32_T
+typedef unsigned int uint32_t;
+#endif
+
+#if ! U_HAVE_INT64_T
+#if U_INT64_IS_LONG_LONG
+    typedef signed long long int64_t;
+#else
+    typedef signed __int64 int64_t;
+#endif
+#endif
+
+#if ! U_HAVE_UINT64_T
+#if U_INT64_IS_LONG_LONG
+    typedef unsigned long long uint64_t;
+#else
+    typedef unsigned __int64 uint64_t;
+#endif
+#endif
+#endif
+
+/**
+ * @}
+ */
+
+/*===========================================================================*/
+/** Compiler and environment features                                         */
+/*===========================================================================*/
+
+/** Define whether namespace is supported */
+#ifndef U_HAVE_NAMESPACE
+#define U_HAVE_NAMESPACE 1
+#endif
+
+/** Determines the endianness of the platform */
+#define U_IS_BIG_ENDIAN 0
+
+/** 1 or 0 to enable or disable threads.  If undefined, default is: enable threads. */
+#ifndef ICU_USE_THREADS
+#define ICU_USE_THREADS 1
+#endif
+
+/** 0 or 1 to enable or disable auto cleanup of libraries. If undefined, default is: disabled. */
+#ifndef UCLN_NO_AUTO_CLEANUP
+#define UCLN_NO_AUTO_CLEANUP 1
+#endif
+
+/* On strong memory model CPUs (e.g. x86 CPUs), we use a safe & quick double check mutex lock. */
+/**
+Microsoft can define _M_IX86, _M_AMD64 (before Visual Studio 8) or _M_X64 (starting in Visual Studio 8). 
+Intel can define _M_IX86 or _M_X64
+*/
+#if defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64) || (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
+#define UMTX_STRONG_MEMORY_MODEL 1
+#endif
+
+/** Enable or disable debugging options **/
+#ifndef U_DEBUG
+#ifdef _DEBUG
+#define U_DEBUG 1
+#else
+#define U_DEBUG 0
+#endif
+#endif
+
+/** Enable or disable release options **/
+#ifndef U_RELEASE
+#ifdef NDEBUG
+#define U_RELEASE 1
+#else
+#define U_RELEASE 0
+#endif
+#endif
+
+/** Determine whether to disable renaming or not. This overrides the
+   setting in umachine.h which is for all platforms. */
+#ifndef U_DISABLE_RENAMING
+#define U_DISABLE_RENAMING 0
+#endif
+
+/** Determine whether to override new and delete. */
+#ifndef U_OVERRIDE_CXX_ALLOCATION
+#define U_OVERRIDE_CXX_ALLOCATION 1
+#endif
+/** Determine whether to override placement new and delete for STL. */
+#ifndef U_HAVE_PLACEMENT_NEW
+#define U_HAVE_PLACEMENT_NEW 1
+#endif
+/** Determine whether to override new and delete for MFC. */
+#if !defined(U_HAVE_DEBUG_LOCATION_NEW) && defined(_MSC_VER)
+#define U_HAVE_DEBUG_LOCATION_NEW 1
+#endif
+
+/** Determine whether to enable tracing. */
+#ifndef U_ENABLE_TRACING
+#define U_ENABLE_TRACING 0
+#endif
+
+/** Do we allow ICU users to use the draft APIs by default? */
+#ifndef U_DEFAULT_SHOW_DRAFT
+#define U_DEFAULT_SHOW_DRAFT 1
+#endif
+
+/** @{ Define the library suffix in a C syntax. */
+#ifndef U_HAVE_LIB_SUFFIX
+#define U_HAVE_LIB_SUFFIX 0
+#endif
+#ifndef U_LIB_SUFFIX_C_NAME
+#define U_LIB_SUFFIX_C_NAME
+#endif
+#ifndef U_LIB_SUFFIX_C_NAME_STRING
+#define U_LIB_SUFFIX_C_NAME_STRING ""
+#endif
+/** @} */
+
+/*===========================================================================*/
+/** @{ Information about wchar support                                           */
+/*===========================================================================*/
+
+#define U_HAVE_WCHAR_H 1
+#define U_SIZEOF_WCHAR_T 2
+
+#define U_HAVE_WCSCPY 1
+
+/** @} */
+
+/**
+ * \def U_DECLARE_UTF16
+ * Do not use this macro. Use the UNICODE_STRING or U_STRING_DECL macros
+ * instead.
+ * @internal
+ */
+#if 1
+#define U_DECLARE_UTF16(string) L ## string
+#endif
+
+/*===========================================================================*/
+/** @{ Information about POSIX support                                           */
+/*===========================================================================*/
+
+/**
+ * @internal 
+ */
+#if 1
+#define U_TZSET         _tzset
+#endif
+/**
+ * @internal 
+ */
+#if 1
+#define U_TIMEZONE      _timezone
+#endif
+/**
+ * @internal 
+ */
+#if 1
+#define U_TZNAME        _tzname
+#endif
+/**
+ * @internal 
+ */
+#if 1
+#define U_DAYLIGHT      _daylight
+#endif
+
+#define U_HAVE_MMAP 0
+#define U_HAVE_POPEN 0
+
+#ifndef U_ENABLE_DYLOAD
+#define U_ENABLE_DYLOAD 1
+#endif
+
+
+/** @} */
+
+/*===========================================================================*/
+/** @{ Symbol import-export control                                              */
+/*===========================================================================*/
+
+#ifdef U_STATIC_IMPLEMENTATION
+#define U_EXPORT
+#else
+#define U_EXPORT __declspec(dllexport)
+#endif
+#define U_EXPORT2 __cdecl
+#define U_IMPORT __declspec(dllimport)
+/** @} */
+
+/*===========================================================================*/
+/** @{ Code alignment and C function inlining                                    */
+/*===========================================================================*/
+
+#ifndef U_INLINE
+#   ifdef __cplusplus
+#       define U_INLINE inline
+#   else
+#       define U_INLINE __inline
+#   endif
+#endif
+
+#if defined(_MSC_VER) && defined(_M_IX86) && !defined(_MANAGED)
+#define U_ALIGN_CODE(val)    __asm      align val
+#else
+#define U_ALIGN_CODE(val)
+#endif
+
+/**
+ * Flag for workaround of MSVC 2003 optimization bugs
+ */
+#if defined(_MSC_VER) && (_MSC_VER < 1400)
+#define U_HAVE_MSVC_2003_OR_EARLIER
+#endif
+
+
+/** @} */
+
+/*===========================================================================*/
+/** @{ Programs used by ICU code                                                 */
+/*===========================================================================*/
+
+#ifndef U_MAKE
+#define U_MAKE  "nmake"
+#define U_MAKE_IS_NMAKE 1
+#endif
+
+/** @} */
+
diff --git a/source/common/unicode/rbbi.h b/source/common/unicode/rbbi.h
new file mode 100644
index 0000000..90ec6e6
--- /dev/null
+++ b/source/common/unicode/rbbi.h
@@ -0,0 +1,722 @@
+/*
+***************************************************************************
+*   Copyright (C) 1999-2008 International Business Machines Corporation   *
+*   and others. All rights reserved.                                      *
+***************************************************************************
+
+**********************************************************************
+*   Date        Name        Description
+*   10/22/99    alan        Creation.
+*   11/11/99    rgillam     Complete port from Java.
+**********************************************************************
+*/
+
+#ifndef RBBI_H
+#define RBBI_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Rule Based Break Iterator
+ */
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/brkiter.h"
+#include "unicode/udata.h"
+#include "unicode/parseerr.h"
+#include "unicode/schriter.h"
+#include "unicode/uchriter.h"
+
+
+struct UTrie;
+
+U_NAMESPACE_BEGIN
+
+/** @internal */
+struct RBBIDataHeader;
+class  RuleBasedBreakIteratorTables;
+class  BreakIterator;
+class  RBBIDataWrapper;
+class  UStack;
+class  LanguageBreakEngine;
+class  UnhandledEngine;
+struct RBBIStateTable;
+
+
+
+
+/**
+ *
+ * A subclass of BreakIterator whose behavior is specified using a list of rules.
+ * <p>Instances of this class are most commonly created by the factory methods of
+ *  BreakIterator::createWordInstance(), BreakIterator::createLineInstance(), etc.,
+ *  and then used via the abstract API in class BreakIterator</p>
+ *
+ * <p>See the ICU User Guide for information on Break Iterator Rules.</p>
+ *
+ * <p>This class is not intended to be subclassed.  (Class DictionaryBasedBreakIterator
+ *    is a subclass, but that relationship is effectively internal to the ICU
+ *    implementation.  The subclassing interface to RulesBasedBreakIterator is
+ *    not part of the ICU API, and may not remain stable.</p>
+ *
+ */
+class U_COMMON_API RuleBasedBreakIterator : public BreakIterator {
+
+protected:
+    /**
+     * The UText through which this BreakIterator accesses the text
+     * @internal
+     */
+    UText  *fText;
+
+    /**
+     *   A character iterator that refers to the same text as the UText, above.
+     *   Only included for compatibility with old API, which was based on CharacterIterators.
+     *   Value may be adopted from outside, or one of fSCharIter or fDCharIter, below.
+     */
+    CharacterIterator  *fCharIter;
+
+    /**
+     *   When the input text is provided by a UnicodeString, this will point to
+     *    a characterIterator that wraps that data.  Needed only for the
+     *    implementation of getText(), a backwards compatibility issue.
+     */
+    StringCharacterIterator *fSCharIter;
+
+    /**
+     *  When the input text is provided by a UText, this
+     *    dummy CharacterIterator over an empty string will
+     *    be returned from getText()
+     */
+    UCharCharacterIterator *fDCharIter;
+
+    /**
+     * The rule data for this BreakIterator instance
+     * @internal
+     */
+    RBBIDataWrapper    *fData;
+
+    /** Index of the Rule {tag} values for the most recent match.
+     *  @internal
+    */
+    int32_t             fLastRuleStatusIndex;
+
+    /**
+     * Rule tag value valid flag.
+     * Some iterator operations don't intrinsically set the correct tag value.
+     * This flag lets us lazily compute the value if we are ever asked for it.
+     * @internal
+     */
+    UBool               fLastStatusIndexValid;
+
+    /**
+     * Counter for the number of characters encountered with the "dictionary"
+     *   flag set.
+     * @internal
+     */
+    uint32_t            fDictionaryCharCount;
+
+    /**
+     * When a range of characters is divided up using the dictionary, the break
+     * positions that are discovered are stored here, preventing us from having
+     * to use either the dictionary or the state table again until the iterator
+     * leaves this range of text. Has the most impact for line breaking.
+     * @internal
+     */
+    int32_t*            fCachedBreakPositions;
+
+    /**
+     * The number of elements in fCachedBreakPositions
+     * @internal
+     */
+    int32_t             fNumCachedBreakPositions;
+
+    /**
+     * if fCachedBreakPositions is not null, this indicates which item in the
+     * cache the current iteration position refers to
+     * @internal
+     */
+    int32_t             fPositionInCache;
+    
+    /**
+     *
+     * If present, UStack of LanguageBreakEngine objects that might handle
+     * dictionary characters. Searched from top to bottom to find an object to
+     * handle a given character.
+     * @internal
+     */
+    UStack              *fLanguageBreakEngines;
+    
+    /**
+     *
+     * If present, the special LanguageBreakEngine used for handling
+     * characters that are in the dictionary set, but not handled by any
+     * LangugageBreakEngine.
+     * @internal
+     */
+    UnhandledEngine     *fUnhandledBreakEngine;
+    
+    /**
+     *
+     * The type of the break iterator, or -1 if it has not been set.
+     * @internal
+     */
+    int32_t             fBreakType;
+    
+protected:
+    //=======================================================================
+    // constructors
+    //=======================================================================
+
+    /**
+     * Constant to be used in the constructor
+     * RuleBasedBreakIterator(RBBIDataHeader*, EDontAdopt, UErrorCode &);
+     * which does not adopt the memory indicated by the RBBIDataHeader*
+     * parameter.
+     *
+     * @internal
+     */
+    enum EDontAdopt {
+        kDontAdopt
+    };
+
+    /**
+     * Constructor from a flattened set of RBBI data in malloced memory.
+     *             RulesBasedBreakIterators built from a custom set of rules
+     *             are created via this constructor; the rules are compiled
+     *             into memory, then the break iterator is constructed here.
+     *
+     *             The break iterator adopts the memory, and will
+     *             free it when done.
+     * @internal
+     */
+    RuleBasedBreakIterator(RBBIDataHeader* data, UErrorCode &status);
+
+    /**
+     * Constructor from a flattened set of RBBI data in memory which need not
+     *             be malloced (e.g. it may be a memory-mapped file, etc.).
+     *
+     *             This version does not adopt the memory, and does not
+     *             free it when done.
+     * @internal
+     */
+    RuleBasedBreakIterator(const RBBIDataHeader* data, enum EDontAdopt dontAdopt, UErrorCode &status);
+
+
+    friend class RBBIRuleBuilder;
+    /** @internal */
+    friend class BreakIterator;
+
+
+
+public:
+
+    /** Default constructor.  Creates an empty shell of an iterator, with no
+     *  rules or text to iterate over.   Object can subsequently be assigned to.
+     *  @stable ICU 2.2
+     */
+    RuleBasedBreakIterator();
+
+    /**
+     * Copy constructor.  Will produce a break iterator with the same behavior,
+     * and which iterates over the same text, as the one passed in.
+     * @param that The RuleBasedBreakIterator passed to be copied
+     * @stable ICU 2.0
+     */
+    RuleBasedBreakIterator(const RuleBasedBreakIterator& that);
+
+    /**
+     * Construct a RuleBasedBreakIterator from a set of rules supplied as a string.
+     * @param rules The break rules to be used.
+     * @param parseError  In the event of a syntax error in the rules, provides the location
+     *                    within the rules of the problem.
+     * @param status Information on any errors encountered.
+     * @stable ICU 2.2
+     */
+    RuleBasedBreakIterator( const UnicodeString    &rules,
+                             UParseError           &parseError,
+                             UErrorCode            &status);
+
+
+    /**
+     * This constructor uses the udata interface to create a BreakIterator
+     * whose internal tables live in a memory-mapped file.  "image" is an
+     * ICU UDataMemory handle for the pre-compiled break iterator tables.
+     * @param image handle to the memory image for the break iterator data.
+     *        Ownership of the UDataMemory handle passes to the Break Iterator,
+     *        which will be responsible for closing it when it is no longer needed.
+     * @param status Information on any errors encountered.
+     * @see udata_open
+     * @see #getBinaryRules
+     * @stable ICU 2.8
+     */
+    RuleBasedBreakIterator(UDataMemory* image, UErrorCode &status);
+
+    /**
+     * Destructor
+     *  @stable ICU 2.0
+     */
+    virtual ~RuleBasedBreakIterator();
+
+    /**
+     * Assignment operator.  Sets this iterator to have the same behavior,
+     * and iterate over the same text, as the one passed in.
+     * @param that The RuleBasedBreakItertor passed in
+     * @return the newly created RuleBasedBreakIterator
+     *  @stable ICU 2.0
+     */
+    RuleBasedBreakIterator& operator=(const RuleBasedBreakIterator& that);
+
+    /**
+     * Equality operator.  Returns TRUE if both BreakIterators are of the
+     * same class, have the same behavior, and iterate over the same text.
+     * @param that The BreakIterator to be compared for equality
+     * @return TRUE if both BreakIterators are of the
+     * same class, have the same behavior, and iterate over the same text.
+     *  @stable ICU 2.0
+     */
+    virtual UBool operator==(const BreakIterator& that) const;
+
+    /**
+     * Not-equal operator.  If operator== returns TRUE, this returns FALSE,
+     * and vice versa.
+     * @param that The BreakIterator to be compared for inequality
+     * @return TRUE if both BreakIterators are not same.
+     *  @stable ICU 2.0
+     */
+    UBool operator!=(const BreakIterator& that) const;
+
+    /**
+     * Returns a newly-constructed RuleBasedBreakIterator with the same
+     * behavior, and iterating over the same text, as this one.
+     * Differs from the copy constructor in that it is polymorphic, and
+     * will correctly clone (copy) a derived class.
+     * clone() is thread safe.  Multiple threads may simultaeneously
+     * clone the same source break iterator.
+     * @return a newly-constructed RuleBasedBreakIterator
+     * @stable ICU 2.0
+     */
+    virtual BreakIterator* clone() const;
+
+    /**
+     * Compute a hash code for this BreakIterator
+     * @return A hash code
+     *  @stable ICU 2.0
+     */
+    virtual int32_t hashCode(void) const;
+
+    /**
+     * Returns the description used to create this iterator
+     * @return the description used to create this iterator
+     *  @stable ICU 2.0
+     */
+    virtual const UnicodeString& getRules(void) const;
+
+    //=======================================================================
+    // BreakIterator overrides
+    //=======================================================================
+
+    /**
+     * <p>
+     * Return a CharacterIterator over the text being analyzed.
+     * The returned character iterator is owned by the break iterator, and must
+     * not be deleted by the caller.  Repeated calls to this function may
+     * return the same CharacterIterator.
+     * </p>
+     * <p>
+     * The returned character iterator must not be used concurrently with
+     * the break iterator.  If concurrent operation is needed, clone the
+     * returned character iterator first and operate on the clone.
+     * </p>
+     * <p>
+     * When the break iterator is operating on text supplied via a UText,
+     * this function will fail.  Lacking any way to signal failures, it
+     * returns an CharacterIterator containing no text.
+     * The function getUText() provides similar functionality,
+     * is reliable, and is more efficient.
+     * </p>
+     *
+     * TODO:  deprecate this function?
+     *
+     * @return An iterator over the text being analyzed.
+     * @stable ICU 2.0
+     */
+    virtual  CharacterIterator& getText(void) const;
+
+
+    /**
+      *  Get a UText for the text being analyzed.
+      *  The returned UText is a shallow clone of the UText used internally
+      *  by the break iterator implementation.  It can safely be used to
+      *  access the text without impacting any break iterator operations,
+      *  but the underlying text itself must not be altered.
+      *
+      * @param fillIn A UText to be filled in.  If NULL, a new UText will be
+      *           allocated to hold the result.
+      * @param status receives any error codes.
+      * @return   The current UText for this break iterator.  If an input
+      *           UText was provided, it will always be returned.
+      * @stable ICU 3.4
+      */
+     virtual UText *getUText(UText *fillIn, UErrorCode &status) const;
+
+    /**
+     * Set the iterator to analyze a new piece of text.  This function resets
+     * the current iteration position to the beginning of the text.
+     * @param newText An iterator over the text to analyze.  The BreakIterator
+     * takes ownership of the character iterator.  The caller MUST NOT delete it!
+     *  @stable ICU 2.0
+     */
+    virtual void adoptText(CharacterIterator* newText);
+
+    /**
+     * Set the iterator to analyze a new piece of text.  This function resets
+     * the current iteration position to the beginning of the text.
+     * @param newText The text to analyze.
+     *  @stable ICU 2.0
+     */
+    virtual void setText(const UnicodeString& newText);
+
+    /**
+     * Reset the break iterator to operate over the text represented by
+     * the UText.  The iterator position is reset to the start.
+     *
+     * This function makes a shallow clone of the supplied UText.  This means
+     * that the caller is free to immediately close or otherwise reuse the
+     * Utext that was passed as a parameter, but that the underlying text itself
+     * must not be altered while being referenced by the break iterator.
+     *
+     * @param text    The UText used to change the text.
+     * @param status  Receives any error codes.
+     * @stable ICU 3.4
+     */
+    virtual void  setText(UText *text, UErrorCode &status);
+
+    /**
+     * Sets the current iteration position to the beginning of the text.
+     * @return The offset of the beginning of the text.
+     *  @stable ICU 2.0
+     */
+    virtual int32_t first(void);
+
+    /**
+     * Sets the current iteration position to the end of the text.
+     * @return The text's past-the-end offset.
+     *  @stable ICU 2.0
+     */
+    virtual int32_t last(void);
+
+    /**
+     * Advances the iterator either forward or backward the specified number of steps.
+     * Negative values move backward, and positive values move forward.  This is
+     * equivalent to repeatedly calling next() or previous().
+     * @param n The number of steps to move.  The sign indicates the direction
+     * (negative is backwards, and positive is forwards).
+     * @return The character offset of the boundary position n boundaries away from
+     * the current one.
+     *  @stable ICU 2.0
+     */
+    virtual int32_t next(int32_t n);
+
+    /**
+     * Advances the iterator to the next boundary position.
+     * @return The position of the first boundary after this one.
+     *  @stable ICU 2.0
+     */
+    virtual int32_t next(void);
+
+    /**
+     * Moves the iterator backwards, to the last boundary preceding this one.
+     * @return The position of the last boundary position preceding this one.
+     *  @stable ICU 2.0
+     */
+    virtual int32_t previous(void);
+
+    /**
+     * Sets the iterator to refer to the first boundary position following
+     * the specified position.
+     * @param offset The position from which to begin searching for a break position.
+     * @return The position of the first break after the current position.
+     *  @stable ICU 2.0
+     */
+    virtual int32_t following(int32_t offset);
+
+    /**
+     * Sets the iterator to refer to the last boundary position before the
+     * specified position.
+     * @param offset The position to begin searching for a break from.
+     * @return The position of the last boundary before the starting position.
+     *  @stable ICU 2.0
+     */
+    virtual int32_t preceding(int32_t offset);
+
+    /**
+     * Returns true if the specfied position is a boundary position.  As a side
+     * effect, leaves the iterator pointing to the first boundary position at
+     * or after "offset".
+     * @param offset the offset to check.
+     * @return True if "offset" is a boundary position.
+     *  @stable ICU 2.0
+     */
+    virtual UBool isBoundary(int32_t offset);
+
+    /**
+     * Returns the current iteration position.
+     * @return The current iteration position.
+     * @stable ICU 2.0
+     */
+    virtual int32_t current(void) const;
+
+
+    /**
+     * Return the status tag from the break rule that determined the most recently
+     * returned break position.  For break rules that do not specify a
+     * status, a default value of 0 is returned.  If more than one break rule
+     * would cause a boundary to be located at some position in the text,
+     * the numerically largest of the applicable status values is returned.
+     * <p>
+     * Of the standard types of ICU break iterators, only word break and
+     * line break provide status values.  The values are defined in
+     * the header file ubrk.h.  For Word breaks, the status allows distinguishing between words
+     * that contain alphabetic letters, "words" that appear to be numbers,
+     * punctuation and spaces, words containing ideographic characters, and
+     * more.  For Line Break, the status distinguishes between hard (mandatory) breaks
+     * and soft (potential) break positions.
+     * <p>
+     * <code>getRuleStatus()</code> can be called after obtaining a boundary
+     * position from <code>next()</code>, <code>previous()</code>, or
+     * any other break iterator functions that returns a boundary position.
+     * <p>
+     * When creating custom break rules, one is free to define whatever
+     * status values may be convenient for the application.
+     * <p>
+     * Note: this function is not thread safe.  It should not have been
+     *       declared const, and the const remains only for compatibility
+     *       reasons.  (The function is logically const, but not bit-wise const).
+     * <p>
+     * @return the status from the break rule that determined the most recently
+     * returned break position.
+     *
+     * @see UWordBreak
+     * @stable ICU 2.2
+     */
+    virtual int32_t getRuleStatus() const;
+
+   /**
+    * Get the status (tag) values from the break rule(s) that determined the most
+    * recently returned break position.
+    * <p>
+    * The returned status value(s) are stored into an array provided by the caller.
+    * The values are stored in sorted (ascending) order.
+    * If the capacity of the output array is insufficient to hold the data,
+    *  the output will be truncated to the available length, and a
+    *  U_BUFFER_OVERFLOW_ERROR will be signaled.
+    *
+    * @param fillInVec an array to be filled in with the status values.
+    * @param capacity  the length of the supplied vector.  A length of zero causes
+    *                  the function to return the number of status values, in the
+    *                  normal way, without attemtping to store any values.
+    * @param status    receives error codes.
+    * @return          The number of rule status values from rules that determined
+    *                  the most recent boundary returned by the break iterator.
+    *                  In the event of a U_BUFFER_OVERFLOW_ERROR, the return value
+    *                  is the total number of status values that were available,
+    *                  not the reduced number that were actually returned.
+    * @see getRuleStatus
+    * @stable ICU 3.0
+    */
+    virtual int32_t getRuleStatusVec(int32_t *fillInVec, int32_t capacity, UErrorCode &status);
+
+    /**
+     * Returns a unique class ID POLYMORPHICALLY.  Pure virtual override.
+     * This method is to implement a simple version of RTTI, since not all
+     * C++ compilers support genuine RTTI.  Polymorphic operator==() and
+     * clone() methods call this method.
+     *
+     * @return          The class ID for this object. All objects of a
+     *                  given class have the same class ID.  Objects of
+     *                  other classes have different class IDs.
+     * @stable ICU 2.0
+     */
+    virtual UClassID getDynamicClassID(void) const;
+
+    /**
+     * Returns 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);
+
+    /*
+     * Create a clone (copy) of this break iterator in memory provided
+     *  by the caller.  The idea is to increase performance by avoiding
+     *  a storage allocation.  Use of this functoin is NOT RECOMMENDED.
+     *  Performance gains are minimal, and correct buffer management is
+     *  tricky.  Use clone() instead.
+     *
+     * @param stackBuffer  The pointer to the memory into which the cloned object
+     *                     should be placed.  If NULL,  allocate heap memory
+     *                     for the cloned object.
+     * @param BufferSize   The size of the buffer.  If zero, return the required
+     *                     buffer size, but do not clone the object.  If the
+     *                     size was too small (but not zero), allocate heap
+     *                     storage for the cloned object.
+     *
+     * @param status       Error status.  U_SAFECLONE_ALLOCATED_WARNING will be
+     *                     returned if the the provided buffer was too small, and
+     *                     the clone was therefore put on the heap.
+     *
+     * @return  Pointer to the clone object.  This may differ from the stackBuffer
+     *          address if the byte alignment of the stack buffer was not suitable
+     *          or if the stackBuffer was too small to hold the clone.
+     * @stable ICU 2.0
+     */
+    virtual BreakIterator *  createBufferClone(void *stackBuffer,
+                                               int32_t &BufferSize,
+                                               UErrorCode &status);
+
+
+    /**
+     * Return the binary form of compiled break rules,
+     * which can then be used to create a new break iterator at some
+     * time in the future.  Creating a break iterator from pre-compiled rules
+     * is much faster than building one from the source form of the
+     * break rules.
+     *
+     * The binary data can only be used with the same version of ICU
+     *  and on the same platform type (processor endian-ness)
+     *
+     * @param length Returns the length of the binary data.  (Out paramter.)
+     *
+     * @return   A pointer to the binary (compiled) rule data.  The storage
+     *           belongs to the RulesBasedBreakIterator object, not the
+     *           caller, and must not be modified or deleted.
+     * @internal
+     */
+    virtual const uint8_t *getBinaryRules(uint32_t &length);
+
+
+protected:
+    //=======================================================================
+    // implementation
+    //=======================================================================
+    /**
+     * Dumps caches and performs other actions associated with a complete change
+     * in text or iteration position.
+     * @internal
+     */
+    virtual void reset(void);
+
+#if 0
+    /**
+      * Return true if the category lookup for this char
+      * indicates that it is in the set of dictionary lookup chars.
+      * This function is intended for use by dictionary based break iterators.
+      * @return true if the category lookup for this char
+      * indicates that it is in the set of dictionary lookup chars.
+      * @internal
+      */
+    virtual UBool isDictionaryChar(UChar32);
+
+    /**
+      * Get the type of the break iterator.
+      * @internal
+      */
+    virtual int32_t getBreakType() const;
+#endif
+
+    /**
+      * Set the type of the break iterator.
+      * @internal
+      */
+    virtual void setBreakType(int32_t type);
+
+    /**
+      * Common initialization function, used by constructors and bufferClone.
+      *   (Also used by DictionaryBasedBreakIterator::createBufferClone().)
+      * @internal
+      */
+    void init();
+
+private:
+
+    /**
+     * This method backs the iterator back up to a "safe position" in the text.
+     * This is a position that we know, without any context, must be a break position.
+     * The various calling methods then iterate forward from this safe position to
+     * the appropriate position to return.  (For more information, see the description
+     * of buildBackwardsStateTable() in RuleBasedBreakIterator.Builder.)
+     * @param statetable state table used of moving backwards
+     * @internal
+     */
+    int32_t handlePrevious(const RBBIStateTable *statetable);
+
+    /**
+     * This method is the actual implementation of the next() method.  All iteration
+     * vectors through here.  This method initializes the state machine to state 1
+     * and advances through the text character by character until we reach the end
+     * of the text or the state machine transitions to state 0.  We update our return
+     * value every time the state machine passes through a possible end state.
+     * @param statetable state table used of moving forwards
+     * @internal
+     */
+    int32_t handleNext(const RBBIStateTable *statetable);
+
+protected:
+
+    /**
+     * This is the function that actually implements dictionary-based
+     * breaking.  Covering at least the range from startPos to endPos,
+     * it checks for dictionary characters, and if it finds them determines
+     * the appropriate object to deal with them. It may cache found breaks in
+     * fCachedBreakPositions as it goes. It may well also look at text outside
+     * the range startPos to endPos.
+     * If going forward, endPos is the normal Unicode break result, and
+     * if goind in reverse, startPos is the normal Unicode break result
+     * @param startPos  The start position of a range of text
+     * @param endPos    The end position of a range of text
+     * @param reverse   The call is for the reverse direction
+     * @internal
+     */
+    int32_t checkDictionary(int32_t startPos, int32_t endPos, UBool reverse);
+
+private:
+
+    /**
+     * This function returns the appropriate LanguageBreakEngine for a
+     * given character c.
+     * @param c         A character in the dictionary set
+     * @internal
+     */
+    const LanguageBreakEngine *getLanguageBreakEngine(UChar32 c);
+
+    /**
+     *  @internal
+     */
+    void makeRuleStatusValid();
+
+};
+
+//------------------------------------------------------------------------------
+//
+//   Inline Functions Definitions ...
+//
+//------------------------------------------------------------------------------
+
+inline UBool RuleBasedBreakIterator::operator!=(const BreakIterator& that) const {
+    return !operator==(that);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
+
+#endif
diff --git a/source/common/unicode/rep.h b/source/common/unicode/rep.h
new file mode 100644
index 0000000..3fab6fa
--- /dev/null
+++ b/source/common/unicode/rep.h
@@ -0,0 +1,259 @@
+/*
+**************************************************************************
+* Copyright (C) 1999-2005, International Business Machines Corporation and
+* others. All Rights Reserved.
+**************************************************************************
+*   Date        Name        Description
+*   11/17/99    aliu        Creation.  Ported from java.  Modified to
+*                           match current UnicodeString API.  Forced
+*                           to use name "handleReplaceBetween" because
+*                           of existing methods in UnicodeString.
+**************************************************************************
+*/
+
+#ifndef REP_H
+#define REP_H
+
+#include "unicode/uobject.h"
+
+/**
+ * \file 
+ * \brief C++ API: Replaceable String
+ */
+ 
+U_NAMESPACE_BEGIN
+
+class UnicodeString;
+
+/**
+ * <code>Replaceable</code> is an abstract base class representing a
+ * string of characters that supports the replacement of a range of
+ * itself with a new string of characters.  It is used by APIs that
+ * change a piece of text while retaining metadata.  Metadata is data
+ * other than the Unicode characters returned by char32At().  One
+ * example of metadata is style attributes; another is an edit
+ * history, marking each character with an author and revision number.
+ *
+ * <p>An implicit aspect of the <code>Replaceable</code> API is that
+ * during a replace operation, new characters take on the metadata of
+ * the old characters.  For example, if the string "the <b>bold</b>
+ * font" has range (4, 8) replaced with "strong", then it becomes "the
+ * <b>strong</b> font".
+ *
+ * <p><code>Replaceable</code> specifies ranges using a start
+ * offset and a limit offset.  The range of characters thus specified
+ * includes the characters at offset start..limit-1.  That is, the
+ * start offset is inclusive, and the limit offset is exclusive.
+ *
+ * <p><code>Replaceable</code> also includes API to access characters
+ * in the string: <code>length()</code>, <code>charAt()</code>,
+ * <code>char32At()</code>, and <code>extractBetween()</code>.
+ *
+ * <p>For a subclass to support metadata, typical behavior of
+ * <code>replace()</code> is the following:
+ * <ul>
+ *   <li>Set the metadata of the new text to the metadata of the first
+ *   character replaced</li>
+ *   <li>If no characters are replaced, use the metadata of the
+ *   previous character</li>
+ *   <li>If there is no previous character (i.e. start == 0), use the
+ *   following character</li>
+ *   <li>If there is no following character (i.e. the replaceable was
+ *   empty), use default metadata.<br>
+ *   <li>If the code point U+FFFF is seen, it should be interpreted as
+ *   a special marker having no metadata<li>
+ *   </li>
+ * </ul>
+ * If this is not the behavior, the subclass should document any differences.
+ * @author Alan Liu
+ * @stable ICU 2.0
+ */
+class U_COMMON_API Replaceable : public UObject {
+
+public:
+    /**
+     * Destructor.
+     * @stable ICU 2.0
+     */
+    virtual ~Replaceable();
+
+    /**
+     * Returns the number of 16-bit code units in the text.
+     * @return number of 16-bit code units in text
+     * @stable ICU 1.8
+     */ 
+    inline int32_t length() const;
+
+    /**
+     * Returns the 16-bit code unit at the given offset into the text.
+     * @param offset an integer between 0 and <code>length()</code>-1
+     * inclusive
+     * @return 16-bit code unit of text at given offset
+     * @stable ICU 1.8
+     */
+    inline UChar charAt(int32_t offset) const;
+
+    /**
+     * Returns the 32-bit code point at the given 16-bit offset into
+     * the text.  This assumes the text is stored as 16-bit code units
+     * with surrogate pairs intermixed.  If the offset of a leading or
+     * trailing code unit of a surrogate pair is given, return the
+     * code point of the surrogate pair.
+     *
+     * @param offset an integer between 0 and <code>length()</code>-1
+     * inclusive
+     * @return 32-bit code point of text at given offset
+     * @stable ICU 1.8
+     */
+    inline UChar32 char32At(int32_t offset) const;
+
+    /**
+     * Copies characters in the range [<tt>start</tt>, <tt>limit</tt>) 
+     * into the UnicodeString <tt>target</tt>.
+     * @param start offset of first character which will be copied
+     * @param limit offset immediately following the last character to
+     * be copied
+     * @param target UnicodeString into which to copy characters.
+     * @return A reference to <TT>target</TT>
+     * @stable ICU 2.1
+     */
+    virtual void extractBetween(int32_t start,
+                                int32_t limit,
+                                UnicodeString& target) const = 0;
+
+    /**
+     * Replaces a substring of this object with the given text.  If the
+     * characters being replaced have metadata, the new characters
+     * that replace them should be given the same metadata.
+     *
+     * <p>Subclasses must ensure that if the text between start and
+     * limit is equal to the replacement text, that replace has no
+     * effect. That is, any metadata
+     * should be unaffected. In addition, subclasses are encouraged to
+     * check for initial and trailing identical characters, and make a
+     * smaller replacement if possible. This will preserve as much
+     * metadata as possible.
+     * @param start the beginning index, inclusive; <code>0 <= start
+     * <= limit</code>.
+     * @param limit the ending index, exclusive; <code>start <= limit
+     * <= length()</code>.
+     * @param text the text to replace characters <code>start</code>
+     * to <code>limit - 1</code> 
+     * @stable ICU 2.0
+     */
+    virtual void handleReplaceBetween(int32_t start,
+                                      int32_t limit,
+                                      const UnicodeString& text) = 0;
+    // Note: All other methods in this class take the names of
+    // existing UnicodeString methods.  This method is the exception.
+    // It is named differently because all replace methods of
+    // UnicodeString return a UnicodeString&.  The 'between' is
+    // required in order to conform to the UnicodeString naming
+    // convention; API taking start/length are named <operation>, and
+    // those taking start/limit are named <operationBetween>.  The
+    // 'handle' is added because 'replaceBetween' and
+    // 'doReplaceBetween' are already taken.
+
+    /**
+     * Copies a substring of this object, retaining metadata.
+     * This method is used to duplicate or reorder substrings.
+     * The destination index must not overlap the source range.
+     * 
+     * @param start the beginning index, inclusive; <code>0 <= start <=
+     * limit</code>.
+     * @param limit the ending index, exclusive; <code>start <= limit <=
+     * length()</code>.
+     * @param dest the destination index.  The characters from
+     * <code>start..limit-1</code> will be copied to <code>dest</code>.
+     * Implementations of this method may assume that <code>dest <= start ||
+     * dest >= limit</code>.
+     * @stable ICU 2.0
+     */
+    virtual void copy(int32_t start, int32_t limit, int32_t dest) = 0;
+
+    /**
+     * Returns true if this object contains metadata.  If a
+     * Replaceable object has metadata, calls to the Replaceable API
+     * must be made so as to preserve metadata.  If it does not, calls
+     * to the Replaceable API may be optimized to improve performance.
+     * The default implementation returns true.
+     * @return true if this object contains metadata
+     * @stable ICU 2.2
+     */
+    virtual UBool hasMetaData() const;
+
+    /**
+     * Clone this object, an instance of a subclass of Replaceable.
+     * Clones can be used concurrently in multiple threads.
+     * If a subclass does not implement clone(), or if an error occurs,
+     * then NULL is returned.
+     * The clone functions in all subclasses return a pointer to a Replaceable
+     * because some compilers do not support covariant (same-as-this)
+     * return types; cast to the appropriate subclass if necessary.
+     * The caller must delete the clone.
+     *
+     * @return a clone of this object
+     *
+     * @see getDynamicClassID
+     * @stable ICU 2.6
+     */
+    virtual Replaceable *clone() const;
+
+protected:
+
+    /**
+     * Default constructor.
+     * @stable ICU 2.4
+     */
+    Replaceable();
+
+    /*
+     * Assignment operator not declared. The compiler will provide one
+     * which does nothing since this class does not contain any data members.
+     * API/code coverage may show the assignment operator as present and
+     * untested - ignore.
+     * Subclasses need this assignment operator if they use compiler-provided
+     * assignment operators of their own. An alternative to not declaring one
+     * here would be to declare and empty-implement a protected or public one.
+    Replaceable &Replaceable::operator=(const Replaceable &);
+     */
+
+    /**
+     * Virtual version of length().
+     * @stable ICU 2.4
+     */ 
+    virtual int32_t getLength() const = 0;
+
+    /**
+     * Virtual version of charAt().
+     * @stable ICU 2.4
+     */
+    virtual UChar getCharAt(int32_t offset) const = 0;
+
+    /**
+     * Virtual version of char32At().
+     * @stable ICU 2.4
+     */
+    virtual UChar32 getChar32At(int32_t offset) const = 0;
+};
+
+inline int32_t
+Replaceable::length() const {
+    return getLength();
+}
+
+inline UChar
+Replaceable::charAt(int32_t offset) const {
+    return getCharAt(offset);
+}
+
+inline UChar32
+Replaceable::char32At(int32_t offset) const {
+    return getChar32At(offset);
+}
+
+// There is no rep.cpp, see unistr.cpp for Replaceable function implementations.
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/unicode/resbund.h b/source/common/unicode/resbund.h
new file mode 100644
index 0000000..6d6b991
--- /dev/null
+++ b/source/common/unicode/resbund.h
@@ -0,0 +1,485 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1996-2007, International Business Machines Corporation
+*   and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File resbund.h
+*
+*   CREATED BY
+*       Richard Gillam
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   2/5/97      aliu        Added scanForLocaleInFile.  Added
+*                           constructor which attempts to read resource bundle
+*                           from a specific file, without searching other files.
+*   2/11/97     aliu        Added UErrorCode return values to constructors.  Fixed
+*                           infinite loops in scanForFile and scanForLocale.
+*                           Modified getRawResourceData to not delete storage
+*                           in localeData and resourceData which it doesn't own.
+*                           Added Mac compatibility #ifdefs for tellp() and
+*                           ios::nocreate.
+*   2/18/97     helena      Updated with 100% documentation coverage.
+*   3/13/97     aliu        Rewrote to load in entire resource bundle and store
+*                           it as a Hashtable of ResourceBundleData objects.
+*                           Added state table to govern parsing of files.
+*                           Modified to load locale index out of new file
+*                           distinct from default.txt.
+*   3/25/97     aliu        Modified to support 2-d arrays, needed for timezone
+*                           data. Added support for custom file suffixes.  Again,
+*                           needed to support timezone data.
+*   4/7/97      aliu        Cleaned up.
+* 03/02/99      stephen     Removed dependency on FILE*.
+* 03/29/99      helena      Merged Bertrand and Stephen's changes.
+* 06/11/99      stephen     Removed parsing of .txt files.
+*                           Reworked to use new binary format.
+*                           Cleaned up.
+* 06/14/99      stephen     Removed methods taking a filename suffix.
+* 11/09/99      weiv        Added getLocale(), fRealLocale, removed fRealLocaleID
+******************************************************************************
+*/
+
+#ifndef RESBUND_H
+#define RESBUND_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/ures.h"
+#include "unicode/unistr.h"
+#include "unicode/locid.h"
+
+/**
+ * \file 
+ * \brief C++ API: Resource Bundle
+ */
+ 
+U_NAMESPACE_BEGIN
+
+/**
+ * A class representing a collection of resource information pertaining to a given
+ * locale. A resource bundle provides a way of accessing locale- specfic information in
+ * a data file. You create a resource bundle that manages the resources for a given
+ * locale and then ask it for individual resources.
+ * <P>
+ * Resource bundles in ICU4C are currently defined using text files which conform to the following
+ * <a href="http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt">BNF definition</a>.
+ * More on resource bundle concepts and syntax can be found in the
+ * <a href="http://icu-project.org/userguide/ResourceManagement.html">Users Guide</a>.
+ * <P>
+ *
+ * The ResourceBundle class is not suitable for subclassing.
+ *
+ * @stable ICU 2.0
+ */
+class U_COMMON_API ResourceBundle : public UObject {
+public:
+    /**
+     * Constructor
+     *
+     * @param packageName   The packageName and locale together point to an ICU udata object, 
+     *                      as defined by <code> udata_open( packageName, "res", locale, err) </code> 
+     *                      or equivalent.  Typically, packageName will refer to a (.dat) file, or to
+     *                      a package registered with udata_setAppData(). Using a full file or directory
+     *                      pathname for packageName is deprecated.
+     * @param locale  This is the locale this resource bundle is for. To get resources
+     *                for the French locale, for example, you would create a
+     *                ResourceBundle passing Locale::FRENCH for the "locale" parameter,
+     *                and all subsequent calls to that resource bundle will return
+     *                resources that pertain to the French locale. If the caller doesn't
+     *                pass a locale parameter, the default locale for the system (as
+     *                returned by Locale::getDefault()) will be used.
+     * @param err     The Error Code.
+     * 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_WARNING
+     * 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_WARNING indicates that
+     * the default locale data was used; neither the requested locale nor any of its
+     * fall back locales could be found.
+     * @stable ICU 2.0
+     */
+    ResourceBundle(const UnicodeString&    packageName,
+                   const Locale&           locale,
+                   UErrorCode&              err);
+
+    /**
+     * Construct a resource bundle for the default bundle in the specified package.
+     *
+     * @param packageName   The packageName and locale together point to an ICU udata object, 
+     *                      as defined by <code> udata_open( packageName, "res", locale, err) </code> 
+     *                      or equivalent.  Typically, packageName will refer to a (.dat) file, or to
+     *                      a package registered with udata_setAppData(). Using a full file or directory
+     *                      pathname for packageName is deprecated.
+     * @param err A UErrorCode value
+     * @stable ICU 2.0
+     */
+    ResourceBundle(const UnicodeString&    packageName,
+                   UErrorCode&              err);
+
+    /**
+     * Construct a resource bundle for the ICU default bundle.
+     *
+     * @param err A UErrorCode value
+     * @stable ICU 2.0
+     */
+    ResourceBundle(UErrorCode &err);
+
+    /**
+     * Standard constructor, onstructs a resource bundle for the locale-specific
+     * bundle in the specified package.
+     *
+     * @param packageName   The packageName and locale together point to an ICU udata object, 
+     *                      as defined by <code> udata_open( packageName, "res", locale, err) </code> 
+     *                      or equivalent.  Typically, packageName will refer to a (.dat) file, or to
+     *                      a package registered with udata_setAppData(). Using a full file or directory
+     *                      pathname for packageName is deprecated.
+     *                      NULL is used to refer to ICU data.
+     * @param locale The locale for which to open a resource bundle.
+     * @param err A UErrorCode value
+     * @stable ICU 2.0
+     */
+    ResourceBundle(const char* packageName,
+                   const Locale& locale,
+                   UErrorCode& err);
+
+    /**
+     * Copy constructor.
+     *
+     * @param original The resource bundle to copy.
+     * @stable ICU 2.0
+     */
+    ResourceBundle(const ResourceBundle &original);
+
+    /**
+     * Constructor from a C UResourceBundle. The resource bundle is
+     * copied and not adopted. ures_close will still need to be used on the
+     * original resource bundle.
+     *
+     * @param res A pointer to the C resource bundle.
+     * @param status A UErrorCode value.
+     * @stable ICU 2.0
+     */
+    ResourceBundle(UResourceBundle *res,
+                   UErrorCode &status);
+
+    /**
+     * Assignment operator.
+     *
+     * @param other The resource bundle to copy.
+     * @stable ICU 2.0
+     */
+    ResourceBundle&
+      operator=(const ResourceBundle& other);
+
+    /** Destructor.
+     * @stable ICU 2.0
+     */
+    virtual ~ResourceBundle();
+
+    /**
+     * 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
+     */
+    ResourceBundle *clone() const;
+
+    /**
+     * Returns the size of a resource. Size for scalar types is always 1, and for vector/table types is
+     * the number of child resources.
+     * @warning Integer array is treated as a scalar type. There are no
+     *          APIs to access individual members of an integer array. It
+     *          is always returned as a whole.
+     *
+     * @return number of resources in a given resource.
+     * @stable ICU 2.0
+     */
+    int32_t
+      getSize(void) const;
+
+    /**
+     * returns a string from a string resource type
+     *
+     * @param status  fills in the outgoing error code
+     *                could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found
+     *                could be a warning
+     *                e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT>
+     * @return a pointer to a zero-terminated UChar array which lives in a memory mapped/DLL file.
+     * @stable ICU 2.0
+     */
+    UnicodeString
+      getString(UErrorCode& status) const;
+
+    /**
+     * returns a binary data from a resource. Can be used at most primitive resource types (binaries,
+     * strings, ints)
+     *
+     * @param len     fills in the length of resulting byte chunk
+     * @param status  fills in the outgoing error code
+     *                could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found
+     *                could be a warning
+     *                e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT>
+     * @return a pointer to a chunk of unsigned bytes which live in a memory mapped/DLL file.
+     * @stable ICU 2.0
+     */
+    const uint8_t*
+      getBinary(int32_t& len, UErrorCode& status) const;
+
+
+    /**
+     * returns an integer vector from a resource.
+     *
+     * @param len     fills in the length of resulting integer vector
+     * @param status  fills in the outgoing error code
+     *                could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found
+     *                could be a warning
+     *                e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT>
+     * @return a pointer to a vector of integers that lives in a memory mapped/DLL file.
+     * @stable ICU 2.0
+     */
+    const int32_t*
+      getIntVector(int32_t& len, UErrorCode& status) const;
+
+    /**
+     * returns an unsigned integer from a resource.
+     * This integer is originally 28 bits.
+     *
+     * @param status  fills in the outgoing error code
+     *                could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found
+     *                could be a warning
+     *                e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT>
+     * @return an unsigned integer value
+     * @stable ICU 2.0
+     */
+    uint32_t
+      getUInt(UErrorCode& status) const;
+
+    /**
+     * returns a signed integer from a resource.
+     * This integer is originally 28 bit and the sign gets propagated.
+     *
+     * @param status  fills in the outgoing error code
+     *                could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found
+     *                could be a warning
+     *                e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT>
+     * @return a signed integer value
+     * @stable ICU 2.0
+     */
+    int32_t
+      getInt(UErrorCode& status) const;
+
+    /**
+     * Checks whether the resource has another element to iterate over.
+     *
+     * @return TRUE if there are more elements, FALSE if there is no more elements
+     * @stable ICU 2.0
+     */
+    UBool
+      hasNext(void) const;
+
+    /**
+     * Resets the internal context of a resource so that iteration starts from the first element.
+     *
+     * @stable ICU 2.0
+     */
+    void
+      resetIterator(void);
+
+    /**
+     * Returns the key associated with this resource. Not all the resources have a key - only
+     * those that are members of a table.
+     *
+     * @return a key associated to this resource, or NULL if it doesn't have a key
+     * @stable ICU 2.0
+     */
+    const char*
+      getKey(void) const;
+
+    /**
+     * Gets the locale ID of the resource bundle as a string.
+     * Same as getLocale().getName() .
+     *
+     * @return the locale ID of the resource bundle as a string
+     * @stable ICU 2.0
+     */
+    const char*
+      getName(void) const;
+
+
+    /**
+     * Returns the type of a resource. Available types are defined in enum UResType
+     *
+     * @return type of the given resource.
+     * @stable ICU 2.0
+     */
+    UResType
+      getType(void) const;
+
+    /**
+     * Returns the next resource in a given resource or NULL if there are no more resources
+     *
+     * @param status            fills in the outgoing error code
+     * @return                  ResourceBundle object.
+     * @stable ICU 2.0
+     */
+    ResourceBundle
+      getNext(UErrorCode& status);
+
+    /**
+     * Returns the next string in a resource or NULL if there are no more resources
+     * to iterate over.
+     *
+     * @param status            fills in the outgoing error code
+     * @return an UnicodeString object.
+     * @stable ICU 2.0
+     */
+    UnicodeString
+      getNextString(UErrorCode& status);
+
+    /**
+     * Returns the next string in a resource or NULL if there are no more resources
+     * to iterate over.
+     *
+     * @param key               fill in for key associated with this string
+     * @param status            fills in the outgoing error code
+     * @return an UnicodeString object.
+     * @stable ICU 2.0
+     */
+    UnicodeString
+      getNextString(const char ** key,
+                    UErrorCode& status);
+
+    /**
+     * Returns the resource in a resource at the specified index.
+     *
+     * @param index             an index to the wanted resource.
+     * @param status            fills in the outgoing error code
+     * @return                  ResourceBundle object. If there is an error, resource is invalid.
+     * @stable ICU 2.0
+     */
+    ResourceBundle
+      get(int32_t index,
+          UErrorCode& status) const;
+
+    /**
+     * Returns the string in a given resource at the specified index.
+     *
+     * @param index             an index to the wanted string.
+     * @param status            fills in the outgoing error code
+     * @return                  an UnicodeString object. If there is an error, string is bogus
+     * @stable ICU 2.0
+     */
+    UnicodeString
+      getStringEx(int32_t index,
+                  UErrorCode& status) const;
+
+    /**
+     * Returns a resource in a resource that has a given key. This procedure works only with table
+     * resources.
+     *
+     * @param key               a key associated with the wanted resource
+     * @param status            fills in the outgoing error code.
+     * @return                  ResourceBundle object. If there is an error, resource is invalid.
+     * @stable ICU 2.0
+     */
+    ResourceBundle
+      get(const char* key,
+          UErrorCode& status) const;
+
+    /**
+     * Returns a string in a resource that has a given key. This procedure works only with table
+     * resources.
+     *
+     * @param key               a key associated with the wanted string
+     * @param status            fills in the outgoing error code
+     * @return                  an UnicodeString object. If there is an error, string is bogus
+     * @stable ICU 2.0
+     */
+    UnicodeString
+      getStringEx(const char* key,
+                  UErrorCode& status) const;
+
+    /**
+     * Return the version number associated with this ResourceBundle as a string. Please
+     * use getVersion, as this method is going to be deprecated.
+     *
+     * @return  A version number string as specified in the resource bundle or its parent.
+     *          The caller does not own this string.
+     * @see getVersion
+     * @deprecated ICU 2.8 Use getVersion instead.
+     */
+    const char*
+      getVersionNumber(void) const;
+
+    /**
+     * Return the version number associated with this ResourceBundle as a UVersionInfo array.
+     *
+     * @param versionInfo A UVersionInfo array that is filled with the version number
+     *                    as specified in the resource bundle or its parent.
+     * @stable ICU 2.0
+     */
+    void
+      getVersion(UVersionInfo versionInfo) const;
+
+    /**
+     * Return the Locale associated with this ResourceBundle.
+     *
+     * @return a Locale object
+     * @deprecated ICU 2.8 Use getLocale(ULocDataLocaleType type, UErrorCode &status) overload instead.
+     */
+    const Locale&
+      getLocale(void) const;
+
+    /**
+     * Return the Locale associated with this ResourceBundle.
+     * @param type You can choose between requested, valid and actual
+     *             locale. For description see the definition of
+     *             ULocDataLocaleType in uloc.h
+     * @param status just for catching illegal arguments
+     *
+     * @return a Locale object
+     * @stable ICU 2.8
+     */
+    const Locale
+      getLocale(ULocDataLocaleType type, UErrorCode &status) const;
+    /**
+     * This API implements multilevel fallback
+     * @internal
+     */
+    ResourceBundle
+        getWithFallback(const char* key, 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();
+
+private:
+    ResourceBundle(); // default constructor not implemented
+
+    UResourceBundle *fResource;
+    void constructForLocale(const UnicodeString& path, const Locale& locale, UErrorCode& error);
+    Locale *fLocale;
+
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/common/unicode/schriter.h b/source/common/unicode/schriter.h
new file mode 100644
index 0000000..d0b5e22
--- /dev/null
+++ b/source/common/unicode/schriter.h
@@ -0,0 +1,187 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1998-2005, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File schriter.h
+*
+* Modification History:
+*
+*   Date        Name        Description
+*  05/05/99     stephen     Cleaned up.
+******************************************************************************
+*/
+
+#ifndef SCHRITER_H
+#define SCHRITER_H
+
+#include "unicode/utypes.h"
+#include "unicode/chariter.h"
+#include "unicode/uchriter.h"
+
+/**
+ * \file 
+ * \brief C++ API: String Character Iterator
+ */
+ 
+U_NAMESPACE_BEGIN
+/**
+ * A concrete subclass of CharacterIterator that iterates over the
+ * characters (code units or code points) in a UnicodeString.
+ * It's possible not only to create an
+ * iterator that iterates over an entire UnicodeString, but also to
+ * create one that iterates over only a subrange of a UnicodeString
+ * (iterators over different subranges of the same UnicodeString don't
+ * compare equal).
+ * @see CharacterIterator
+ * @see ForwardCharacterIterator
+ * @stable ICU 2.0
+ */
+class U_COMMON_API StringCharacterIterator : public UCharCharacterIterator {
+public:
+  /**
+   * Create an iterator over the UnicodeString referred to by "textStr".
+   * The UnicodeString object is copied.
+   * The iteration range is the whole string, and the starting position is 0.
+   * @param textStr The unicode string used to create an iterator
+   * @stable ICU 2.0
+   */
+  StringCharacterIterator(const UnicodeString& textStr);
+
+  /**
+   * Create an iterator over the UnicodeString referred to by "textStr".
+   * The iteration range is the whole string, and the starting
+   * position is specified by "textPos".  If "textPos" is outside the valid
+   * iteration range, the behavior of this object is undefined.
+   * @param textStr The unicode string used to create an iterator
+   * @param textPos The starting position of the iteration
+   * @stable ICU 2.0
+   */
+  StringCharacterIterator(const UnicodeString&    textStr,
+              int32_t              textPos);
+
+  /**
+   * Create an iterator over the UnicodeString referred to by "textStr".
+   * The UnicodeString object is copied.
+   * The iteration range begins with the code unit specified by
+   * "textBegin" and ends with the code unit BEFORE the code unit specfied
+   * by "textEnd".  The starting position is specified by "textPos".  If
+   * "textBegin" and "textEnd" don't form a valid range on "text" (i.e.,
+   * textBegin >= textEnd or either is negative or greater than text.size()),
+   * or "textPos" is outside the range defined by "textBegin" and "textEnd",
+   * the behavior of this iterator is undefined.
+   * @param textStr    The unicode string used to create the StringCharacterIterator
+   * @param textBegin  The begin position of the iteration range
+   * @param textEnd    The end position of the iteration range
+   * @param textPos    The starting position of the iteration
+   * @stable ICU 2.0
+   */
+  StringCharacterIterator(const UnicodeString&    textStr,
+              int32_t              textBegin,
+              int32_t              textEnd,
+              int32_t              textPos);
+
+  /**
+   * Copy constructor.  The new iterator iterates over the same range
+   * of the same string as "that", and its initial position is the
+   * same as "that"'s current position.
+   * The UnicodeString object in "that" is copied.
+   * @param that The StringCharacterIterator to be copied
+   * @stable ICU 2.0
+   */
+  StringCharacterIterator(const StringCharacterIterator&  that);
+
+  /**
+   * Destructor.
+   * @stable ICU 2.0
+   */
+  virtual ~StringCharacterIterator();
+
+  /**
+   * Assignment operator.  *this is altered to iterate over the same
+   * range of the same string as "that", and refers to the same
+   * character within that string as "that" does.
+   * @param that The object to be copied.
+   * @return the newly created object.
+   * @stable ICU 2.0
+   */
+  StringCharacterIterator&
+  operator=(const StringCharacterIterator&    that);
+
+  /**
+   * Returns true if the iterators iterate over the same range of the
+   * same string and are pointing at the same character.
+   * @param that The ForwardCharacterIterator to be compared for equality
+   * @return true if the iterators iterate over the same range of the
+   * same string and are pointing at the same character.
+   * @stable ICU 2.0
+   */
+  virtual UBool          operator==(const ForwardCharacterIterator& that) const;
+
+  /**
+   * Returns a new StringCharacterIterator referring to the same
+   * character in the same range of the same string as this one.  The
+   * caller must delete the new iterator.
+   * @return the newly cloned object.
+   * @stable ICU 2.0
+   */
+  virtual CharacterIterator* clone(void) const;
+
+  /**
+   * Sets the iterator to iterate over the provided string.
+   * @param newText The string to be iterated over
+   * @stable ICU 2.0
+   */
+  void setText(const UnicodeString& newText);
+
+  /**
+   * Copies the UnicodeString under iteration into the UnicodeString
+   * referred to by "result".  Even if this iterator iterates across
+   * only a part of this string, the whole string is copied.
+   * @param result Receives a copy of the text under iteration.
+   * @stable ICU 2.0
+   */
+  virtual void            getText(UnicodeString& result);
+
+  /**
+   * Return a class ID for this object (not really public)
+   * @return a class ID for this object.
+   * @stable ICU 2.0
+   */
+  virtual UClassID         getDynamicClassID(void) const;
+
+  /**
+   * Return a class ID for this class (not really public)
+   * @return a class ID for this class
+   * @stable ICU 2.0
+   */
+  static UClassID   U_EXPORT2 getStaticClassID(void);
+
+protected:
+  /**
+   * Default constructor, iteration over empty string.
+   * @stable ICU 2.0
+   */
+  StringCharacterIterator();
+
+  /**
+   * Sets the iterator to iterate over the provided string.
+   * @param newText The string to be iterated over
+   * @param newTextLength The length of the String
+   * @stable ICU 2.0
+   */
+  void setText(const UChar* newText, int32_t newTextLength);
+
+  /**
+   * Copy of the iterated string object.
+   * @stable ICU 2.0
+   */
+  UnicodeString            text;
+
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/common/unicode/std_string.h b/source/common/unicode/std_string.h
new file mode 100644
index 0000000..dd43b74
--- /dev/null
+++ b/source/common/unicode/std_string.h
@@ -0,0 +1,78 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2009-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  std_string.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2009feb19
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __STD_STRING_H__
+#define __STD_STRING_H__
+
+/**
+ * \file 
+ * \brief C++ API: Central ICU header for including the C++ standard &lt;string&gt;
+ *                 header and for related definitions.
+ */
+
+#include "unicode/utypes.h"
+
+/**
+ * \def U_HAVE_STD_STRING
+ * Define whether the standard C++ (STL) &lt;string&gt; header is available.
+ * @internal
+ */
+#ifndef U_HAVE_STD_STRING
+#define U_HAVE_STD_STRING 1
+#endif
+
+#if U_HAVE_STD_STRING
+
+#include <string>
+
+/**
+ * \def U_STD_NS
+ * Define the namespace to use for standard C++ (STL) classes.
+ * Either std or empty.
+ * @draft ICU 4.2
+ */
+
+/**
+ * \def U_STD_NSQ
+ * Define the namespace qualifier to use for standard C++ (STL) classes.
+ * Either std:: or empty.
+ * For example,
+ *   U_STD_NSQ string StringFromUnicodeString(const UnicodeString &unistr);
+ * @draft ICU 4.2
+ */
+
+/**
+ * \def U_STD_NS_USE
+ * This is used to specify that the rest of the code uses the
+ * standard (STL) namespace.
+ * Either "using namespace std;" or empty.
+ * @draft ICU 4.2
+ */
+#ifndef U_STD_NSQ
+#   if U_HAVE_NAMESPACE
+#       define U_STD_NS std
+#       define U_STD_NSQ U_STD_NS::
+#       define U_STD_NS_USE using namespace U_STD_NS;
+#   else
+#       define U_STD_NS
+#       define U_STD_NSQ
+#       define U_STD_NS_USE
+#   endif
+#endif
+
+#endif  // U_HAVE_STD_STRING
+
+#endif  // __STD_STRING_H__
diff --git a/source/common/unicode/strenum.h b/source/common/unicode/strenum.h
new file mode 100644
index 0000000..ce42195
--- /dev/null
+++ b/source/common/unicode/strenum.h
@@ -0,0 +1,271 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2002-2007, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*/
+
+#ifndef STRENUM_H
+#define STRENUM_H
+
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+
+/**
+ * \file 
+ * \brief C++ API: String Enumeration
+ */
+ 
+U_NAMESPACE_BEGIN
+
+/**
+ * Base class for 'pure' C++ implementations of uenum api.  Adds a
+ * method that returns the next UnicodeString since in C++ this can
+ * be a common storage format for strings.
+ *
+ * <p>The model is that the enumeration is over strings maintained by
+ * a 'service.'  At any point, the service might change, invalidating
+ * the enumerator (though this is expected to be rare).  The iterator
+ * returns an error if this has occurred.  Lack of the error is no
+ * guarantee that the service didn't change immediately after the
+ * call, so the returned string still might not be 'valid' on
+ * subsequent use.</p>
+ *
+ * <p>Strings may take the form of const char*, const UChar*, or const
+ * UnicodeString*.  The type you get is determine by the variant of
+ * 'next' that you call.  In general the StringEnumeration is
+ * optimized for one of these types, but all StringEnumerations can
+ * return all types.  Returned strings are each terminated with a NUL.
+ * Depending on the service data, they might also include embedded NUL
+ * characters, so API is provided to optionally return the true
+ * length, counting the embedded NULs but not counting the terminating
+ * NUL.</p>
+ *
+ * <p>The pointers returned by next, unext, and snext become invalid
+ * upon any subsequent call to the enumeration's destructor, next,
+ * unext, snext, or reset.</p>
+ *
+ * ICU 2.8 adds some default implementations and helper functions
+ * for subclasses.
+ *
+ * @stable ICU 2.4 
+ */
+class U_COMMON_API StringEnumeration : public UObject { 
+public:
+    /**
+     * Destructor.
+     * @stable ICU 2.4
+     */
+    virtual ~StringEnumeration();
+
+    /**
+     * Clone this object, an instance of a subclass of StringEnumeration.
+     * Clones can be used concurrently in multiple threads.
+     * If a subclass does not implement clone(), or if an error occurs,
+     * then NULL is returned.
+     * The clone functions in all subclasses return a base class pointer
+     * because some compilers do not support covariant (same-as-this)
+     * return types; cast to the appropriate subclass if necessary.
+     * The caller must delete the clone.
+     *
+     * @return a clone of this object
+     *
+     * @see getDynamicClassID
+     * @stable ICU 2.8
+     */
+    virtual StringEnumeration *clone() const;
+
+    /**
+     * <p>Return the number of elements that the iterator traverses.  If
+     * the iterator is out of sync with its service, status is set to
+     * U_ENUM_OUT_OF_SYNC_ERROR, and the return value is zero.</p>
+     *
+     * <p>The return value will not change except possibly as a result of
+     * a subsequent call to reset, or if the iterator becomes out of sync.</p>
+     *
+     * <p>This is a convenience function. It can end up being very
+     * expensive as all the items might have to be pre-fetched
+     * (depending on the storage format of the data being
+     * traversed).</p>
+     *
+     * @param status the error code.
+     * @return number of elements in the iterator.
+     *
+     * @stable ICU 2.4 */
+    virtual int32_t count(UErrorCode& status) const = 0;
+
+    /**
+     * <p>Returns the next element as a NUL-terminated char*.  If there
+     * are no more elements, returns NULL.  If the resultLength pointer
+     * is not NULL, the length of the string (not counting the
+     * terminating NUL) is returned at that address.  If an error
+     * status is returned, the value at resultLength is undefined.</p>
+     *
+     * <p>The returned pointer is owned by this iterator and must not be
+     * deleted by the caller.  The pointer is valid until the next call
+     * to next, unext, snext, reset, or the enumerator's destructor.</p>
+     *
+     * <p>If the iterator is out of sync with its service, status is set
+     * to U_ENUM_OUT_OF_SYNC_ERROR and NULL is returned.</p>
+     *
+     * <p>If the native service string is a UChar* string, it is
+     * converted to char* with the invariant converter.  If the
+     * conversion fails (because a character cannot be converted) then
+     * status is set to U_INVARIANT_CONVERSION_ERROR and the return
+     * value is undefined (though not NULL).</p>
+     *
+     * Starting with ICU 2.8, the default implementation calls snext()
+     * and handles the conversion.
+     *
+     * @param status the error code.
+     * @param resultLength a pointer to receive the length, can be NULL.
+     * @return a pointer to the string, or NULL.
+     *
+     * @stable ICU 2.4 
+     */
+    virtual const char* next(int32_t *resultLength, UErrorCode& status);
+
+    /**
+     * <p>Returns the next element as a NUL-terminated UChar*.  If there
+     * are no more elements, returns NULL.  If the resultLength pointer
+     * is not NULL, the length of the string (not counting the
+     * terminating NUL) is returned at that address.  If an error
+     * status is returned, the value at resultLength is undefined.</p>
+     *
+     * <p>The returned pointer is owned by this iterator and must not be
+     * deleted by the caller.  The pointer is valid until the next call
+     * to next, unext, snext, reset, or the enumerator's destructor.</p>
+     *
+     * <p>If the iterator is out of sync with its service, status is set
+     * to U_ENUM_OUT_OF_SYNC_ERROR and NULL is returned.</p>
+     *
+     * Starting with ICU 2.8, the default implementation calls snext()
+     * and handles the conversion.
+     *
+     * @param status the error code.
+     * @param resultLength a ponter to receive the length, can be NULL.
+     * @return a pointer to the string, or NULL.
+     *
+     * @stable ICU 2.4 
+     */
+    virtual const UChar* unext(int32_t *resultLength, UErrorCode& status);
+
+    /**
+     * <p>Returns the next element a UnicodeString*.  If there are no
+     * more elements, returns NULL.</p>
+     *
+     * <p>The returned pointer is owned by this iterator and must not be
+     * deleted by the caller.  The pointer is valid until the next call
+     * to next, unext, snext, reset, or the enumerator's destructor.</p>
+     *
+     * <p>If the iterator is out of sync with its service, status is set
+     * to U_ENUM_OUT_OF_SYNC_ERROR and NULL is returned.</p>
+     *
+     * @param status the error code.
+     * @return a pointer to the string, or NULL.
+     *
+     * @stable ICU 2.4 
+     */
+    virtual const UnicodeString* snext(UErrorCode& status) = 0;
+
+    /**
+     * <p>Resets the iterator.  This re-establishes sync with the
+     * service and rewinds the iterator to start at the first
+     * element.</p>
+     *
+     * <p>Previous pointers returned by next, unext, or snext become
+     * invalid, and the value returned by count might change.</p>
+     *
+     * @param status the error code.
+     *
+     * @stable ICU 2.4 
+     */
+    virtual void reset(UErrorCode& status) = 0;
+
+    /**
+     * Compares this enumeration to other to check if both are equal
+     *
+     * @param that The other string enumeration to compare this object to
+     * @return TRUE if the enumerations are equal. FALSE if not.
+     * @stable ICU 3.6 
+     */
+    virtual UBool operator==(const StringEnumeration& that)const;
+    /**
+     * Compares this enumeration to other to check if both are not equal
+     *
+     * @param that The other string enumeration to compare this object to
+     * @return TRUE if the enumerations are equal. FALSE if not.
+     * @stable ICU 3.6 
+     */
+    virtual UBool operator!=(const StringEnumeration& that)const;
+
+protected:
+    /**
+     * UnicodeString field for use with default implementations and subclasses.
+     * @stable ICU 2.8
+     */
+    UnicodeString unistr;
+    /**
+     * char * default buffer for use with default implementations and subclasses.
+     * @stable ICU 2.8
+     */
+    char charsBuffer[32];
+    /**
+     * char * buffer for use with default implementations and subclasses.
+     * Allocated in constructor and in ensureCharsCapacity().
+     * @stable ICU 2.8
+     */
+    char *chars;
+    /**
+     * Capacity of chars, for use with default implementations and subclasses.
+     * @stable ICU 2.8
+     */
+    int32_t charsCapacity;
+
+    /**
+     * Default constructor for use with default implementations and subclasses.
+     * @stable ICU 2.8
+     */
+    StringEnumeration();
+
+    /**
+     * Ensures that chars is at least as large as the requested capacity.
+     * For use with default implementations and subclasses.
+     *
+     * @param capacity Requested capacity.
+     * @param status ICU in/out error code.
+     * @stable ICU 2.8
+     */
+    void ensureCharsCapacity(int32_t capacity, UErrorCode &status);
+
+    /**
+     * Converts s to Unicode and sets unistr to the result.
+     * For use with default implementations and subclasses,
+     * especially for implementations of snext() in terms of next().
+     * This is provided with a helper function instead of a default implementation
+     * of snext() to avoid potential infinite loops between next() and snext().
+     *
+     * For example:
+     * \code
+     * const UnicodeString* snext(UErrorCode& status) {
+     *   int32_t resultLength=0;
+     *   const char *s=next(&resultLength, status);
+     *   return setChars(s, resultLength, status);
+     * }
+     * \endcode
+     *
+     * @param s String to be converted to Unicode.
+     * @param length Length of the string.
+     * @param status ICU in/out error code.
+     * @return A pointer to unistr.
+     * @stable ICU 2.8
+     */
+    UnicodeString *setChars(const char *s, int32_t length, UErrorCode &status);
+};
+
+U_NAMESPACE_END
+
+/* STRENUM_H */
+#endif
diff --git a/source/common/unicode/stringpiece.h b/source/common/unicode/stringpiece.h
new file mode 100644
index 0000000..79d5a05
--- /dev/null
+++ b/source/common/unicode/stringpiece.h
@@ -0,0 +1,224 @@
+// Copyright (C) 2010, International Business Machines
+// Corporation and others. All Rights Reserved.
+//
+// Copyright 2001 and onwards Google Inc.
+// Author: Sanjay Ghemawat
+
+// This code is a contribution of Google code, and the style used here is
+// a compromise between the original Google code and the ICU coding guidelines.
+// For example, data types are ICU-ified (size_t,int->int32_t),
+// and API comments doxygen-ified, but function names and behavior are
+// as in the original, if possible.
+// Assertion-style error handling, not available in ICU, was changed to
+// parameter "pinning" similar to UnicodeString.
+//
+// In addition, this is only a partial port of the original Google code,
+// limited to what was needed so far. The (nearly) complete original code
+// is in the ICU svn repository at icuhtml/trunk/design/strings/contrib
+// (see ICU ticket 6765, r25517).
+
+#ifndef __STRINGPIECE_H__
+#define __STRINGPIECE_H__
+
+/**
+ * \file 
+ * \brief C++ API: StringPiece: Read-only byte string wrapper class.
+ */
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/std_string.h"
+
+// Arghh!  I wish C++ literals were "string".
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A string-like object that points to a sized piece of memory.
+ *
+ * We provide non-explicit singleton constructors so users can pass
+ * in a "const char*" or a "string" wherever a "StringPiece" is
+ * expected.
+ *
+ * Functions or methods may use const StringPiece& parameters to accept either
+ * a "const char*" or a "string" value that will be implicitly converted to
+ * a StringPiece.
+ *
+ * Systematic usage of StringPiece is encouraged as it will reduce unnecessary
+ * conversions from "const char*" to "string" and back again.
+ *
+ * @stable ICU 4.2
+ */
+class U_COMMON_API StringPiece : public UMemory {
+ private:
+  const char*   ptr_;
+  int32_t       length_;
+
+ public:
+  /**
+   * Default constructor, creates an empty StringPiece.
+   * @stable ICU 4.2
+   */
+  StringPiece() : ptr_(NULL), length_(0) { }
+  /**
+   * Constructs from a NUL-terminated const char * pointer.
+   * @param str a NUL-terminated const char * pointer
+   * @stable ICU 4.2
+   */
+  StringPiece(const char* str);
+#if U_HAVE_STD_STRING
+  /**
+   * Constructs from a std::string.
+   * @stable ICU 4.2
+   */
+  StringPiece(const U_STD_NSQ string& str)
+    : ptr_(str.data()), length_(static_cast<int32_t>(str.size())) { }
+#endif
+  /**
+   * Constructs from a const char * pointer and a specified length.
+   * @param offset a const char * pointer (need not be terminated)
+   * @param len the length of the string; must be non-negative
+   * @stable ICU 4.2
+   */
+  StringPiece(const char* offset, int32_t len) : ptr_(offset), length_(len) { }
+  /**
+   * Substring of another StringPiece.
+   * @param x the other StringPiece
+   * @param pos start position in x; must be non-negative and <= x.length().
+   * @stable ICU 4.2
+   */
+  StringPiece(const StringPiece& x, int32_t pos);
+  /**
+   * Substring of another StringPiece.
+   * @param x the other StringPiece
+   * @param pos start position in x; must be non-negative and <= x.length().
+   * @param len length of the substring;
+   *            must be non-negative and will be pinned to at most x.length() - pos.
+   * @stable ICU 4.2
+   */
+  StringPiece(const StringPiece& x, int32_t pos, int32_t len);
+
+  /**
+   * Returns the string pointer. May be NULL if it is empty.
+   *
+   * data() may return a pointer to a buffer with embedded NULs, and the
+   * returned buffer may or may not be null terminated.  Therefore it is
+   * typically a mistake to pass data() to a routine that expects a NUL
+   * terminated string.
+   * @return the string pointer
+   * @stable ICU 4.2
+   */
+  const char* data() const { return ptr_; }
+  /**
+   * Returns the string length. Same as length().
+   * @return the string length
+   * @stable ICU 4.2
+   */
+  int32_t size() const { return length_; }
+  /**
+   * Returns the string length. Same as size().
+   * @return the string length
+   * @stable ICU 4.2
+   */
+  int32_t length() const { return length_; }
+  /**
+   * Returns whether the string is empty.
+   * @return TRUE if the string is empty
+   * @stable ICU 4.2
+   */
+  UBool empty() const { return length_ == 0; }
+
+  /**
+   * Sets to an empty string.
+   * @stable ICU 4.2
+   */
+  void clear() { ptr_ = NULL; length_ = 0; }
+
+  /**
+   * Reset the stringpiece to refer to new data.
+   * @param data pointer the new string data.  Need not be nul terminated.
+   * @param len the length of the new data
+   * @internal
+   */
+  void set(const char* data, int32_t len) { ptr_ = data; length_ = len; }
+
+  /**
+   * Reset the stringpiece to refer to new data.
+   * @param str a pointer to a NUL-terminated string. 
+   * @internal
+   */
+  void set(const char* str);
+
+  /**
+   * Removes the first n string units.
+   * @param n prefix length, must be non-negative and <=length()
+   * @stable ICU 4.2
+   */
+  void remove_prefix(int32_t n) {
+    if (n >= 0) {
+      if (n > length_) {
+        n = length_;
+      }
+      ptr_ += n;
+      length_ -= n;
+    }
+  }
+
+  /**
+   * Removes the last n string units.
+   * @param n suffix length, must be non-negative and <=length()
+   * @stable ICU 4.2
+   */
+  void remove_suffix(int32_t n) {
+    if (n >= 0) {
+      if (n <= length_) {
+        length_ -= n;
+      } else {
+        length_ = 0;
+      }
+    }
+  }
+
+  /**
+   * Maximum integer, used as a default value for substring methods.
+   * @stable ICU 4.2
+   */
+  static const int32_t npos = 0x7fffffff;
+
+  /**
+   * Returns a substring of this StringPiece.
+   * @param pos start position; must be non-negative and <= length().
+   * @param len length of the substring;
+   *            must be non-negative and will be pinned to at most length() - pos.
+   * @return the substring StringPiece
+   * @stable ICU 4.2
+   */
+  StringPiece substr(int32_t pos, int32_t len = npos) const {
+    return StringPiece(*this, pos, len);
+  }
+};
+
+/**
+ * Global operator == for StringPiece
+ * @param x The first StringPiece to compare.
+ * @param y The second StringPiece to compare.
+ * @return TRUE if the string data is equal
+ * @internal
+ */
+U_EXPORT UBool U_EXPORT2 
+operator==(const StringPiece& x, const StringPiece& y);
+
+/**
+ * Global operator != for StringPiece
+ * @param x The first StringPiece to compare.
+ * @param y The second StringPiece to compare.
+ * @return TRUE if the string data is not equal
+ * @internal
+ */
+inline UBool operator!=(const StringPiece& x, const StringPiece& y) {
+  return !(x == y);
+}
+
+U_NAMESPACE_END
+
+#endif  // __STRINGPIECE_H__
diff --git a/source/common/unicode/symtable.h b/source/common/unicode/symtable.h
new file mode 100644
index 0000000..428f8bf
--- /dev/null
+++ b/source/common/unicode/symtable.h
@@ -0,0 +1,112 @@
+/*
+**********************************************************************
+*   Copyright (c) 2000-2005, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   Date        Name        Description
+*   02/04/00    aliu        Creation.
+**********************************************************************
+*/
+#ifndef SYMTABLE_H
+#define SYMTABLE_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+
+/**
+ * \file 
+ * \brief C++ API: An interface that defines both lookup protocol and parsing of
+ * symbolic names.
+ */
+ 
+U_NAMESPACE_BEGIN
+
+class ParsePosition;
+class UnicodeFunctor;
+class UnicodeSet;
+class UnicodeString;
+
+/**
+ * An interface that defines both lookup protocol and parsing of
+ * symbolic names.
+ *
+ * <p>A symbol table maintains two kinds of mappings.  The first is
+ * between symbolic names and their values.  For example, if the
+ * variable with the name "start" is set to the value "alpha"
+ * (perhaps, though not necessarily, through an expression such as
+ * "$start=alpha"), then the call lookup("start") will return the
+ * char[] array ['a', 'l', 'p', 'h', 'a'].
+ *
+ * <p>The second kind of mapping is between character values and
+ * UnicodeMatcher objects.  This is used by RuleBasedTransliterator,
+ * which uses characters in the private use area to represent objects
+ * such as UnicodeSets.  If U+E015 is mapped to the UnicodeSet [a-z],
+ * then lookupMatcher(0xE015) will return the UnicodeSet [a-z].
+ *
+ * <p>Finally, a symbol table defines parsing behavior for symbolic
+ * names.  All symbolic names start with the SYMBOL_REF character.
+ * When a parser encounters this character, it calls parseReference()
+ * with the position immediately following the SYMBOL_REF.  The symbol
+ * table parses the name, if there is one, and returns it.
+ *
+ * @stable ICU 2.8
+ */
+class U_COMMON_API SymbolTable /* not : public UObject because this is an interface/mixin class */ {
+public:
+
+    /**
+     * The character preceding a symbol reference name.
+     * @stable ICU 2.8
+     */
+    enum { SYMBOL_REF = 0x0024 /*$*/ };
+
+    /**
+     * Destructor.
+     * @stable ICU 2.8
+     */
+    virtual ~SymbolTable();
+
+    /**
+     * Lookup the characters associated with this string and return it.
+     * Return <tt>NULL</tt> if no such name exists.  The resultant
+     * string may have length zero.
+     * @param s the symbolic name to lookup
+     * @return a string containing the name's value, or <tt>NULL</tt> if
+     * there is no mapping for s.
+     * @stable ICU 2.8
+     */
+    virtual const UnicodeString* lookup(const UnicodeString& s) const = 0;
+
+    /**
+     * Lookup the UnicodeMatcher associated with the given character, and
+     * return it.  Return <tt>NULL</tt> if not found.
+     * @param ch a 32-bit code point from 0 to 0x10FFFF inclusive.
+     * @return the UnicodeMatcher object represented by the given
+     * character, or NULL if there is no mapping for ch.
+     * @stable ICU 2.8
+     */
+    virtual const UnicodeFunctor* lookupMatcher(UChar32 ch) const = 0;
+
+    /**
+     * Parse a symbol reference name from the given string, starting
+     * at the given position.  If no valid symbol reference name is
+     * found, return the empty string and leave pos unchanged.  That is, if the
+     * character at pos cannot start a name, or if pos is at or after
+     * text.length(), then return an empty string.  This indicates an
+     * isolated SYMBOL_REF character.
+     * @param text the text to parse for the name
+     * @param pos on entry, the index of the first character to parse.
+     * This is the character following the SYMBOL_REF character.  On
+     * exit, the index after the last parsed character.  If the parse
+     * failed, pos is unchanged on exit.
+     * @param limit the index after the last character to be parsed.
+     * @return the parsed name, or an empty string if there is no
+     * valid symbolic name at the given position.
+     * @stable ICU 2.8
+     */
+    virtual UnicodeString parseReference(const UnicodeString& text,
+                                         ParsePosition& pos, int32_t limit) const = 0;
+};
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/unicode/ubidi.h b/source/common/unicode/ubidi.h
new file mode 100644
index 0000000..1cef221
--- /dev/null
+++ b/source/common/unicode/ubidi.h
@@ -0,0 +1,2096 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  ubidi.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999jul27
+*   created by: Markus W. Scherer, updated by Matitiahu Allouche
+*/
+
+#ifndef UBIDI_H
+#define UBIDI_H
+
+#include "unicode/utypes.h"
+#include "unicode/uchar.h"
+#include "unicode/localpointer.h"
+
+/**
+ *\file
+ * \brief C API: Bidi algorithm
+ *
+ * <h2>Bidi algorithm for ICU</h2>
+ *
+ * This is an implementation of the Unicode Bidirectional Algorithm.
+ * The algorithm is defined in the
+ * <a href="http://www.unicode.org/unicode/reports/tr9/">Unicode Standard Annex #9</a>.<p>
+ *
+ * Note: Libraries that perform a bidirectional algorithm and
+ * reorder strings accordingly are sometimes called "Storage Layout Engines".
+ * ICU's Bidi and shaping (u_shapeArabic()) APIs can be used at the core of such
+ * "Storage Layout Engines".
+ *
+ * <h3>General remarks about the API:</h3>
+ *
+ * In functions with an error code parameter,
+ * the <code>pErrorCode</code> pointer must be valid
+ * and the value that it points to must not indicate a failure before
+ * the function call. Otherwise, the function returns immediately.
+ * After the function call, the value indicates success or failure.<p>
+ *
+ * The &quot;limit&quot; of a sequence of characters is the position just after their
+ * last character, i.e., one more than that position.<p>
+ *
+ * Some of the API functions provide access to &quot;runs&quot;.
+ * Such a &quot;run&quot; is defined as a sequence of characters
+ * that are at the same embedding level
+ * after performing the Bidi algorithm.<p>
+ *
+ * @author Markus W. Scherer
+ * @version 1.0
+ *
+ *
+ * <h4> Sample code for the ICU Bidi API </h4>
+ *
+ * <h5>Rendering a paragraph with the ICU Bidi API</h5>
+ *
+ * This is (hypothetical) sample code that illustrates
+ * how the ICU Bidi API could be used to render a paragraph of text.
+ * Rendering code depends highly on the graphics system,
+ * therefore this sample code must make a lot of assumptions,
+ * which may or may not match any existing graphics system's properties.
+ *
+ * <p>The basic assumptions are:</p>
+ * <ul>
+ * <li>Rendering is done from left to right on a horizontal line.</li>
+ * <li>A run of single-style, unidirectional text can be rendered at once.</li>
+ * <li>Such a run of text is passed to the graphics system with
+ *     characters (code units) in logical order.</li>
+ * <li>The line-breaking algorithm is very complicated
+ *     and Locale-dependent -
+ *     and therefore its implementation omitted from this sample code.</li>
+ * </ul>
+ *
+ * <pre>
+ * \code
+ *#include "unicode/ubidi.h"
+ *
+ *typedef enum {
+ *     styleNormal=0, styleSelected=1,
+ *     styleBold=2, styleItalics=4,
+ *     styleSuper=8, styleSub=16
+ *} Style;
+ *
+ *typedef struct { int32_t limit; Style style; } StyleRun;
+ *
+ *int getTextWidth(const UChar *text, int32_t start, int32_t limit,
+ *                  const StyleRun *styleRuns, int styleRunCount);
+ *
+ * // set *pLimit and *pStyleRunLimit for a line
+ * // from text[start] and from styleRuns[styleRunStart]
+ * // using ubidi_getLogicalRun(para, ...)
+ *void getLineBreak(const UChar *text, int32_t start, int32_t *pLimit,
+ *                  UBiDi *para,
+ *                  const StyleRun *styleRuns, int styleRunStart, int *pStyleRunLimit,
+ *                  int *pLineWidth);
+ *
+ * // render runs on a line sequentially, always from left to right
+ *
+ * // prepare rendering a new line
+ * void startLine(UBiDiDirection textDirection, int lineWidth);
+ *
+ * // render a run of text and advance to the right by the run width
+ * // the text[start..limit-1] is always in logical order
+ * void renderRun(const UChar *text, int32_t start, int32_t limit,
+ *               UBiDiDirection textDirection, Style style);
+ *
+ * // We could compute a cross-product
+ * // from the style runs with the directional runs
+ * // and then reorder it.
+ * // Instead, here we iterate over each run type
+ * // and render the intersections -
+ * // with shortcuts in simple (and common) cases.
+ * // renderParagraph() is the main function.
+ *
+ * // render a directional run with
+ * // (possibly) multiple style runs intersecting with it
+ * void renderDirectionalRun(const UChar *text,
+ *                           int32_t start, int32_t limit,
+ *                           UBiDiDirection direction,
+ *                           const StyleRun *styleRuns, int styleRunCount) {
+ *     int i;
+ *
+ *     // iterate over style runs
+ *     if(direction==UBIDI_LTR) {
+ *         int styleLimit;
+ *
+ *         for(i=0; i<styleRunCount; ++i) {
+ *             styleLimit=styleRun[i].limit;
+ *             if(start<styleLimit) {
+ *                 if(styleLimit>limit) { styleLimit=limit; }
+ *                 renderRun(text, start, styleLimit,
+ *                           direction, styleRun[i].style);
+ *                 if(styleLimit==limit) { break; }
+ *                 start=styleLimit;
+ *             }
+ *         }
+ *     } else {
+ *         int styleStart;
+ *
+ *         for(i=styleRunCount-1; i>=0; --i) {
+ *             if(i>0) {
+ *                 styleStart=styleRun[i-1].limit;
+ *             } else {
+ *                 styleStart=0;
+ *             }
+ *             if(limit>=styleStart) {
+ *                 if(styleStart<start) { styleStart=start; }
+ *                 renderRun(text, styleStart, limit,
+ *                           direction, styleRun[i].style);
+ *                 if(styleStart==start) { break; }
+ *                 limit=styleStart;
+ *             }
+ *         }
+ *     }
+ * }
+ *
+ * // the line object represents text[start..limit-1]
+ * void renderLine(UBiDi *line, const UChar *text,
+ *                 int32_t start, int32_t limit,
+ *                 const StyleRun *styleRuns, int styleRunCount) {
+ *     UBiDiDirection direction=ubidi_getDirection(line);
+ *     if(direction!=UBIDI_MIXED) {
+ *         // unidirectional
+ *         if(styleRunCount<=1) {
+ *             renderRun(text, start, limit, direction, styleRuns[0].style);
+ *         } else {
+ *             renderDirectionalRun(text, start, limit,
+ *                                  direction, styleRuns, styleRunCount);
+ *         }
+ *     } else {
+ *         // mixed-directional
+ *         int32_t count, i, length;
+ *         UBiDiLevel level;
+ *
+ *         count=ubidi_countRuns(para, pErrorCode);
+ *         if(U_SUCCESS(*pErrorCode)) {
+ *             if(styleRunCount<=1) {
+ *                 Style style=styleRuns[0].style;
+ *
+ *                 // iterate over directional runs
+ *                for(i=0; i<count; ++i) {
+ *                    direction=ubidi_getVisualRun(para, i, &start, &length);
+ *                     renderRun(text, start, start+length, direction, style);
+ *                }
+ *             } else {
+ *                 int32_t j;
+ *
+ *                 // iterate over both directional and style runs
+ *                 for(i=0; i<count; ++i) {
+ *                     direction=ubidi_getVisualRun(line, i, &start, &length);
+ *                     renderDirectionalRun(text, start, start+length,
+ *                                          direction, styleRuns, styleRunCount);
+ *                 }
+ *             }
+ *         }
+ *     }
+ * }
+ *
+ *void renderParagraph(const UChar *text, int32_t length,
+ *                     UBiDiDirection textDirection,
+ *                      const StyleRun *styleRuns, int styleRunCount,
+ *                      int lineWidth,
+ *                      UErrorCode *pErrorCode) {
+ *     UBiDi *para;
+ *
+ *     if(pErrorCode==NULL || U_FAILURE(*pErrorCode) || length<=0) {
+ *         return;
+ *     }
+ *
+ *     para=ubidi_openSized(length, 0, pErrorCode);
+ *     if(para==NULL) { return; }
+ *
+ *     ubidi_setPara(para, text, length,
+ *                   textDirection ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR,
+ *                   NULL, pErrorCode);
+ *     if(U_SUCCESS(*pErrorCode)) {
+ *         UBiDiLevel paraLevel=1&ubidi_getParaLevel(para);
+ *         StyleRun styleRun={ length, styleNormal };
+ *         int width;
+ *
+ *         if(styleRuns==NULL || styleRunCount<=0) {
+ *            styleRunCount=1;
+ *             styleRuns=&styleRun;
+ *         }
+ *
+ *        // assume styleRuns[styleRunCount-1].limit>=length
+ *
+ *         width=getTextWidth(text, 0, length, styleRuns, styleRunCount);
+ *         if(width<=lineWidth) {
+ *             // everything fits onto one line
+ *
+ *            // prepare rendering a new line from either left or right
+ *             startLine(paraLevel, width);
+ *
+ *             renderLine(para, text, 0, length,
+ *                        styleRuns, styleRunCount);
+ *         } else {
+ *             UBiDi *line;
+ *
+ *             // we need to render several lines
+ *             line=ubidi_openSized(length, 0, pErrorCode);
+ *             if(line!=NULL) {
+ *                 int32_t start=0, limit;
+ *                 int styleRunStart=0, styleRunLimit;
+ *
+ *                 for(;;) {
+ *                     limit=length;
+ *                     styleRunLimit=styleRunCount;
+ *                     getLineBreak(text, start, &limit, para,
+ *                                  styleRuns, styleRunStart, &styleRunLimit,
+ *                                 &width);
+ *                     ubidi_setLine(para, start, limit, line, pErrorCode);
+ *                     if(U_SUCCESS(*pErrorCode)) {
+ *                         // prepare rendering a new line
+ *                         // from either left or right
+ *                         startLine(paraLevel, width);
+ *
+ *                         renderLine(line, text, start, limit,
+ *                                    styleRuns+styleRunStart,
+ *                                    styleRunLimit-styleRunStart);
+ *                     }
+ *                     if(limit==length) { break; }
+ *                     start=limit;
+ *                     styleRunStart=styleRunLimit-1;
+ *                     if(start>=styleRuns[styleRunStart].limit) {
+ *                         ++styleRunStart;
+ *                     }
+ *                 }
+ *
+ *                 ubidi_close(line);
+ *             }
+ *        }
+ *    }
+ *
+ *     ubidi_close(para);
+ *}
+ *\endcode
+ * </pre>
+ */
+
+/*DOCXX_TAG*/
+/*@{*/
+
+/**
+ * UBiDiLevel is the type of the level values in this
+ * Bidi implementation.
+ * It holds an embedding level and indicates the visual direction
+ * by its bit&nbsp;0 (even/odd value).<p>
+ *
+ * It can also hold non-level values for the
+ * <code>paraLevel</code> and <code>embeddingLevels</code>
+ * arguments of <code>ubidi_setPara()</code>; there:
+ * <ul>
+ * <li>bit&nbsp;7 of an <code>embeddingLevels[]</code>
+ * value indicates whether the using application is
+ * specifying the level of a character to <i>override</i> whatever the
+ * Bidi implementation would resolve it to.</li>
+ * <li><code>paraLevel</code> can be set to the
+ * pseudo-level values <code>UBIDI_DEFAULT_LTR</code>
+ * and <code>UBIDI_DEFAULT_RTL</code>.</li>
+ * </ul>
+ *
+ * @see ubidi_setPara
+ *
+ * <p>The related constants are not real, valid level values.
+ * <code>UBIDI_DEFAULT_XXX</code> can be used to specify
+ * a default for the paragraph level for
+ * when the <code>ubidi_setPara()</code> function
+ * shall determine it but there is no
+ * strongly typed character in the input.<p>
+ *
+ * Note that the value for <code>UBIDI_DEFAULT_LTR</code> is even
+ * and the one for <code>UBIDI_DEFAULT_RTL</code> is odd,
+ * just like with normal LTR and RTL level values -
+ * these special values are designed that way. Also, the implementation
+ * assumes that UBIDI_MAX_EXPLICIT_LEVEL is odd.
+ *
+ * @see UBIDI_DEFAULT_LTR
+ * @see UBIDI_DEFAULT_RTL
+ * @see UBIDI_LEVEL_OVERRIDE
+ * @see UBIDI_MAX_EXPLICIT_LEVEL
+ * @stable ICU 2.0
+ */
+typedef uint8_t UBiDiLevel;
+
+/** Paragraph level setting.<p>
+ *
+ * Constant indicating that the base direction depends on the first strong
+ * directional character in the text according to the Unicode Bidirectional
+ * Algorithm. If no strong directional character is present,
+ * then set the paragraph level to 0 (left-to-right).<p>
+ *
+ * If this value is used in conjunction with reordering modes
+ * <code>UBIDI_REORDER_INVERSE_LIKE_DIRECT</code> or
+ * <code>UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL</code>, the text to reorder
+ * is assumed to be visual LTR, and the text after reordering is required
+ * to be the corresponding logical string with appropriate contextual
+ * direction. The direction of the result string will be RTL if either
+ * the righmost or leftmost strong character of the source text is RTL
+ * or Arabic Letter, the direction will be LTR otherwise.<p>
+ *
+ * If reordering option <code>UBIDI_OPTION_INSERT_MARKS</code> is set, an RLM may
+ * be added at the beginning of the result string to ensure round trip
+ * (that the result string, when reordered back to visual, will produce
+ * the original source text).
+ * @see UBIDI_REORDER_INVERSE_LIKE_DIRECT
+ * @see UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL
+ * @stable ICU 2.0
+ */
+#define UBIDI_DEFAULT_LTR 0xfe
+
+/** Paragraph level setting.<p>
+ *
+ * Constant indicating that the base direction depends on the first strong
+ * directional character in the text according to the Unicode Bidirectional
+ * Algorithm. If no strong directional character is present,
+ * then set the paragraph level to 1 (right-to-left).<p>
+ *
+ * If this value is used in conjunction with reordering modes
+ * <code>UBIDI_REORDER_INVERSE_LIKE_DIRECT</code> or
+ * <code>UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL</code>, the text to reorder
+ * is assumed to be visual LTR, and the text after reordering is required
+ * to be the corresponding logical string with appropriate contextual
+ * direction. The direction of the result string will be RTL if either
+ * the righmost or leftmost strong character of the source text is RTL
+ * or Arabic Letter, or if the text contains no strong character;
+ * the direction will be LTR otherwise.<p>
+ *
+ * If reordering option <code>UBIDI_OPTION_INSERT_MARKS</code> is set, an RLM may
+ * be added at the beginning of the result string to ensure round trip
+ * (that the result string, when reordered back to visual, will produce
+ * the original source text).
+ * @see UBIDI_REORDER_INVERSE_LIKE_DIRECT
+ * @see UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL
+ * @stable ICU 2.0
+ */
+#define UBIDI_DEFAULT_RTL 0xff
+
+/**
+ * Maximum explicit embedding level.
+ * (The maximum resolved level can be up to <code>UBIDI_MAX_EXPLICIT_LEVEL+1</code>).
+ * @stable ICU 2.0
+ */
+#define UBIDI_MAX_EXPLICIT_LEVEL 61
+
+/** Bit flag for level input.
+ *  Overrides directional properties.
+ * @stable ICU 2.0
+ */
+#define UBIDI_LEVEL_OVERRIDE 0x80
+
+/**
+ * Special value which can be returned by the mapping functions when a logical
+ * index has no corresponding visual index or vice-versa. This may happen
+ * for the logical-to-visual mapping of a Bidi control when option
+ * <code>#UBIDI_OPTION_REMOVE_CONTROLS</code> is specified. This can also happen
+ * for the visual-to-logical mapping of a Bidi mark (LRM or RLM) inserted
+ * by option <code>#UBIDI_OPTION_INSERT_MARKS</code>.
+ * @see ubidi_getVisualIndex
+ * @see ubidi_getVisualMap
+ * @see ubidi_getLogicalIndex
+ * @see ubidi_getLogicalMap
+ * @stable ICU 3.6
+ */
+#define UBIDI_MAP_NOWHERE   (-1)
+
+/**
+ * <code>UBiDiDirection</code> values indicate the text direction.
+ * @stable ICU 2.0
+ */
+enum UBiDiDirection {
+  /** Left-to-right text. This is a 0 value.
+   * <ul>
+   * <li>As return value for <code>ubidi_getDirection()</code>, it means
+   *     that the source string contains no right-to-left characters, or
+   *     that the source string is empty and the paragraph level is even.
+   * <li> As return value for <code>ubidi_getBaseDirection()</code>, it
+   *      means that the first strong character of the source string has
+   *      a left-to-right direction.
+   * </ul>
+   * @stable ICU 2.0
+   */
+  UBIDI_LTR,
+  /** Right-to-left text. This is a 1 value.
+   * <ul>
+   * <li>As return value for <code>ubidi_getDirection()</code>, it means
+   *     that the source string contains no left-to-right characters, or
+   *     that the source string is empty and the paragraph level is odd.
+   * <li> As return value for <code>ubidi_getBaseDirection()</code>, it
+   *      means that the first strong character of the source string has
+   *      a right-to-left direction.
+   * </ul>
+   * @stable ICU 2.0
+   */
+  UBIDI_RTL,
+  /** Mixed-directional text.
+   * <p>As return value for <code>ubidi_getDirection()</code>, it means
+   *    that the source string contains both left-to-right and
+   *    right-to-left characters.
+   * @stable ICU 2.0
+   */
+  UBIDI_MIXED,
+  /** No strongly directional text.
+   * <p>As return value for <code>ubidi_getBaseDirection()</code>, it means
+   *    that the source string is missing or empty, or contains neither left-to-right
+   *    nor right-to-left characters.
+   * @draft ICU 4.6
+   */
+  UBIDI_NEUTRAL
+};
+
+/** @stable ICU 2.0 */
+typedef enum UBiDiDirection UBiDiDirection;
+
+/**
+ * Forward declaration of the <code>UBiDi</code> structure for the declaration of
+ * the API functions. Its fields are implementation-specific.<p>
+ * This structure holds information about a paragraph (or multiple paragraphs)
+ * of text with Bidi-algorithm-related details, or about one line of
+ * such a paragraph.<p>
+ * Reordering can be done on a line, or on one or more paragraphs which are
+ * then interpreted each as one single line.
+ * @stable ICU 2.0
+ */
+struct UBiDi;
+
+/** @stable ICU 2.0 */
+typedef struct UBiDi UBiDi;
+
+/**
+ * Allocate a <code>UBiDi</code> structure.
+ * Such an object is initially empty. It is assigned
+ * the Bidi properties of a piece of text containing one or more paragraphs
+ * by <code>ubidi_setPara()</code>
+ * or the Bidi properties of a line within a paragraph by
+ * <code>ubidi_setLine()</code>.<p>
+ * This object can be reused for as long as it is not deallocated
+ * by calling <code>ubidi_close()</code>.<p>
+ * <code>ubidi_setPara()</code> and <code>ubidi_setLine()</code> will allocate
+ * additional memory for internal structures as necessary.
+ *
+ * @return An empty <code>UBiDi</code> object.
+ * @stable ICU 2.0
+ */
+U_STABLE UBiDi * U_EXPORT2
+ubidi_open(void);
+
+/**
+ * Allocate a <code>UBiDi</code> structure with preallocated memory
+ * for internal structures.
+ * This function provides a <code>UBiDi</code> object like <code>ubidi_open()</code>
+ * with no arguments, but it also preallocates memory for internal structures
+ * according to the sizings supplied by the caller.<p>
+ * Subsequent functions will not allocate any more memory, and are thus
+ * guaranteed not to fail because of lack of memory.<p>
+ * The preallocation can be limited to some of the internal memory
+ * by setting some values to 0 here. That means that if, e.g.,
+ * <code>maxRunCount</code> cannot be reasonably predetermined and should not
+ * be set to <code>maxLength</code> (the only failproof value) to avoid
+ * wasting memory, then <code>maxRunCount</code> could be set to 0 here
+ * and the internal structures that are associated with it will be allocated
+ * on demand, just like with <code>ubidi_open()</code>.
+ *
+ * @param maxLength is the maximum text or line length that internal memory
+ *        will be preallocated for. An attempt to associate this object with a
+ *        longer text will fail, unless this value is 0, which leaves the allocation
+ *        up to the implementation.
+ *
+ * @param maxRunCount is the maximum anticipated number of same-level runs
+ *        that internal memory will be preallocated for. An attempt to access
+ *        visual runs on an object that was not preallocated for as many runs
+ *        as the text was actually resolved to will fail,
+ *        unless this value is 0, which leaves the allocation up to the implementation.<br><br>
+ *        The number of runs depends on the actual text and maybe anywhere between
+ *        1 and <code>maxLength</code>. It is typically small.
+ *
+ * @param pErrorCode must be a valid pointer to an error code value.
+ *
+ * @return An empty <code>UBiDi</code> object with preallocated memory.
+ * @stable ICU 2.0
+ */
+U_STABLE UBiDi * U_EXPORT2
+ubidi_openSized(int32_t maxLength, int32_t maxRunCount, UErrorCode *pErrorCode);
+
+/**
+ * <code>ubidi_close()</code> must be called to free the memory
+ * associated with a UBiDi object.<p>
+ *
+ * <strong>Important: </strong>
+ * A parent <code>UBiDi</code> object must not be destroyed or reused if
+ * it still has children.
+ * If a <code>UBiDi</code> object has become the <i>child</i>
+ * of another one (its <i>parent</i>) by calling
+ * <code>ubidi_setLine()</code>, then the child object must
+ * be destroyed (closed) or reused (by calling
+ * <code>ubidi_setPara()</code> or <code>ubidi_setLine()</code>)
+ * before the parent object.
+ *
+ * @param pBiDi is a <code>UBiDi</code> object.
+ *
+ * @see ubidi_setPara
+ * @see ubidi_setLine
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ubidi_close(UBiDi *pBiDi);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUBiDiPointer
+ * "Smart pointer" class, closes a UBiDi via ubidi_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUBiDiPointer, UBiDi, ubidi_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Modify the operation of the Bidi algorithm such that it
+ * approximates an "inverse Bidi" algorithm. This function
+ * must be called before <code>ubidi_setPara()</code>.
+ *
+ * <p>The normal operation of the Bidi algorithm as described
+ * in the Unicode Technical Report is to take text stored in logical
+ * (keyboard, typing) order and to determine the reordering of it for visual
+ * rendering.
+ * Some legacy systems store text in visual order, and for operations
+ * with standard, Unicode-based algorithms, the text needs to be transformed
+ * to logical order. This is effectively the inverse algorithm of the
+ * described Bidi algorithm. Note that there is no standard algorithm for
+ * this "inverse Bidi" and that the current implementation provides only an
+ * approximation of "inverse Bidi".</p>
+ *
+ * <p>With <code>isInverse</code> set to <code>TRUE</code>,
+ * this function changes the behavior of some of the subsequent functions
+ * in a way that they can be used for the inverse Bidi algorithm.
+ * Specifically, runs of text with numeric characters will be treated in a
+ * special way and may need to be surrounded with LRM characters when they are
+ * written in reordered sequence.</p>
+ *
+ * <p>Output runs should be retrieved using <code>ubidi_getVisualRun()</code>.
+ * Since the actual input for "inverse Bidi" is visually ordered text and
+ * <code>ubidi_getVisualRun()</code> gets the reordered runs, these are actually
+ * the runs of the logically ordered output.</p>
+ *
+ * <p>Calling this function with argument <code>isInverse</code> set to
+ * <code>TRUE</code> is equivalent to calling
+ * <code>ubidi_setReorderingMode</code> with argument
+ * <code>reorderingMode</code>
+ * set to <code>#UBIDI_REORDER_INVERSE_NUMBERS_AS_L</code>.<br>
+ * Calling this function with argument <code>isInverse</code> set to
+ * <code>FALSE</code> is equivalent to calling
+ * <code>ubidi_setReorderingMode</code> with argument
+ * <code>reorderingMode</code>
+ * set to <code>#UBIDI_REORDER_DEFAULT</code>.
+ *
+ * @param pBiDi is a <code>UBiDi</code> object.
+ *
+ * @param isInverse specifies "forward" or "inverse" Bidi operation.
+ *
+ * @see ubidi_setPara
+ * @see ubidi_writeReordered
+ * @see ubidi_setReorderingMode
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ubidi_setInverse(UBiDi *pBiDi, UBool isInverse);
+
+/**
+ * Is this Bidi object set to perform the inverse Bidi algorithm?
+ * <p>Note: calling this function after setting the reordering mode with
+ * <code>ubidi_setReorderingMode</code> will return <code>TRUE</code> if the
+ * reordering mode was set to <code>#UBIDI_REORDER_INVERSE_NUMBERS_AS_L</code>,
+ * <code>FALSE</code> for all other values.</p>
+ *
+ * @param pBiDi is a <code>UBiDi</code> object.
+ * @return TRUE if the Bidi object is set to perform the inverse Bidi algorithm
+ * by handling numbers as L.
+ *
+ * @see ubidi_setInverse
+ * @see ubidi_setReorderingMode
+ * @stable ICU 2.0
+ */
+
+U_STABLE UBool U_EXPORT2
+ubidi_isInverse(UBiDi *pBiDi);
+
+/**
+ * Specify whether block separators must be allocated level zero,
+ * so that successive paragraphs will progress from left to right.
+ * This function must be called before <code>ubidi_setPara()</code>.
+ * Paragraph separators (B) may appear in the text.  Setting them to level zero
+ * means that all paragraph separators (including one possibly appearing
+ * in the last text position) are kept in the reordered text after the text
+ * that they follow in the source text.
+ * When this feature is not enabled, a paragraph separator at the last
+ * position of the text before reordering will go to the first position
+ * of the reordered text when the paragraph level is odd.
+ *
+ * @param pBiDi is a <code>UBiDi</code> object.
+ *
+ * @param orderParagraphsLTR specifies whether paragraph separators (B) must
+ * receive level 0, so that successive paragraphs progress from left to right.
+ *
+ * @see ubidi_setPara
+ * @stable ICU 3.4
+ */
+U_STABLE void U_EXPORT2
+ubidi_orderParagraphsLTR(UBiDi *pBiDi, UBool orderParagraphsLTR);
+
+/**
+ * Is this Bidi object set to allocate level 0 to block separators so that
+ * successive paragraphs progress from left to right?
+ *
+ * @param pBiDi is a <code>UBiDi</code> object.
+ * @return TRUE if the Bidi object is set to allocate level 0 to block
+ *         separators.
+ *
+ * @see ubidi_orderParagraphsLTR
+ * @stable ICU 3.4
+ */
+U_STABLE UBool U_EXPORT2
+ubidi_isOrderParagraphsLTR(UBiDi *pBiDi);
+
+/**
+ * <code>UBiDiReorderingMode</code> values indicate which variant of the Bidi
+ * algorithm to use.
+ *
+ * @see ubidi_setReorderingMode
+ * @stable ICU 3.6
+ */
+typedef enum UBiDiReorderingMode {
+    /** Regular Logical to Visual Bidi algorithm according to Unicode.
+      * This is a 0 value.
+      * @stable ICU 3.6 */
+    UBIDI_REORDER_DEFAULT = 0,
+    /** Logical to Visual algorithm which handles numbers in a way which
+      * mimicks the behavior of Windows XP.
+      * @stable ICU 3.6 */
+    UBIDI_REORDER_NUMBERS_SPECIAL,
+    /** Logical to Visual algorithm grouping numbers with adjacent R characters
+      * (reversible algorithm).
+      * @stable ICU 3.6 */
+    UBIDI_REORDER_GROUP_NUMBERS_WITH_R,
+    /** Reorder runs only to transform a Logical LTR string to the Logical RTL
+      * string with the same display, or vice-versa.<br>
+      * If this mode is set together with option
+      * <code>#UBIDI_OPTION_INSERT_MARKS</code>, some Bidi controls in the source
+      * text may be removed and other controls may be added to produce the
+      * minimum combination which has the required display.
+      * @stable ICU 3.6 */
+    UBIDI_REORDER_RUNS_ONLY,
+    /** Visual to Logical algorithm which handles numbers like L
+      * (same algorithm as selected by <code>ubidi_setInverse(TRUE)</code>.
+      * @see ubidi_setInverse
+      * @stable ICU 3.6 */
+    UBIDI_REORDER_INVERSE_NUMBERS_AS_L,
+    /** Visual to Logical algorithm equivalent to the regular Logical to Visual
+      * algorithm.
+      * @stable ICU 3.6 */
+    UBIDI_REORDER_INVERSE_LIKE_DIRECT,
+    /** Inverse Bidi (Visual to Logical) algorithm for the
+      * <code>UBIDI_REORDER_NUMBERS_SPECIAL</code> Bidi algorithm.
+      * @stable ICU 3.6 */
+    UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL,
+    /** Number of values for reordering mode.
+      * @stable ICU 3.6 */
+    UBIDI_REORDER_COUNT
+} UBiDiReorderingMode;
+
+/**
+ * Modify the operation of the Bidi algorithm such that it implements some
+ * variant to the basic Bidi algorithm or approximates an "inverse Bidi"
+ * algorithm, depending on different values of the "reordering mode".
+ * This function must be called before <code>ubidi_setPara()</code>, and stays
+ * in effect until called again with a different argument.
+ *
+ * <p>The normal operation of the Bidi algorithm as described
+ * in the Unicode Standard Annex #9 is to take text stored in logical
+ * (keyboard, typing) order and to determine how to reorder it for visual
+ * rendering.</p>
+ *
+ * <p>With the reordering mode set to a value other than
+ * <code>#UBIDI_REORDER_DEFAULT</code>, this function changes the behavior of
+ * some of the subsequent functions in a way such that they implement an
+ * inverse Bidi algorithm or some other algorithm variants.</p>
+ *
+ * <p>Some legacy systems store text in visual order, and for operations
+ * with standard, Unicode-based algorithms, the text needs to be transformed
+ * into logical order. This is effectively the inverse algorithm of the
+ * described Bidi algorithm. Note that there is no standard algorithm for
+ * this "inverse Bidi", so a number of variants are implemented here.</p>
+ *
+ * <p>In other cases, it may be desirable to emulate some variant of the
+ * Logical to Visual algorithm (e.g. one used in MS Windows), or perform a
+ * Logical to Logical transformation.</p>
+ *
+ * <ul>
+ * <li>When the reordering mode is set to <code>#UBIDI_REORDER_DEFAULT</code>,
+ * the standard Bidi Logical to Visual algorithm is applied.</li>
+ *
+ * <li>When the reordering mode is set to
+ * <code>#UBIDI_REORDER_NUMBERS_SPECIAL</code>,
+ * the algorithm used to perform Bidi transformations when calling
+ * <code>ubidi_setPara</code> should approximate the algorithm used in
+ * Microsoft Windows XP rather than strictly conform to the Unicode Bidi
+ * algorithm.
+ * <br>
+ * The differences between the basic algorithm and the algorithm addressed
+ * by this option are as follows:
+ * <ul>
+ *   <li>Within text at an even embedding level, the sequence "123AB"
+ *   (where AB represent R or AL letters) is transformed to "123BA" by the
+ *   Unicode algorithm and to "BA123" by the Windows algorithm.</li>
+ *   <li>Arabic-Indic numbers (AN) are handled by the Windows algorithm just
+ *   like regular numbers (EN).</li>
+ * </ul></li>
+ *
+ * <li>When the reordering mode is set to
+ * <code>#UBIDI_REORDER_GROUP_NUMBERS_WITH_R</code>,
+ * numbers located between LTR text and RTL text are associated with the RTL
+ * text. For instance, an LTR paragraph with content "abc 123 DEF" (where
+ * upper case letters represent RTL characters) will be transformed to
+ * "abc FED 123" (and not "abc 123 FED"), "DEF 123 abc" will be transformed
+ * to "123 FED abc" and "123 FED abc" will be transformed to "DEF 123 abc".
+ * This makes the algorithm reversible and makes it useful when round trip
+ * (from visual to logical and back to visual) must be achieved without
+ * adding LRM characters. However, this is a variation from the standard
+ * Unicode Bidi algorithm.<br>
+ * The source text should not contain Bidi control characters other than LRM
+ * or RLM.</li>
+ *
+ * <li>When the reordering mode is set to
+ * <code>#UBIDI_REORDER_RUNS_ONLY</code>,
+ * a "Logical to Logical" transformation must be performed:
+ * <ul>
+ * <li>If the default text level of the source text (argument <code>paraLevel</code>
+ * in <code>ubidi_setPara</code>) is even, the source text will be handled as
+ * LTR logical text and will be transformed to the RTL logical text which has
+ * the same LTR visual display.</li>
+ * <li>If the default level of the source text is odd, the source text
+ * will be handled as RTL logical text and will be transformed to the
+ * LTR logical text which has the same LTR visual display.</li>
+ * </ul>
+ * This mode may be needed when logical text which is basically Arabic or
+ * Hebrew, with possible included numbers or phrases in English, has to be
+ * displayed as if it had an even embedding level (this can happen if the
+ * displaying application treats all text as if it was basically LTR).
+ * <br>
+ * This mode may also be needed in the reverse case, when logical text which is
+ * basically English, with possible included phrases in Arabic or Hebrew, has to
+ * be displayed as if it had an odd embedding level.
+ * <br>
+ * Both cases could be handled by adding LRE or RLE at the head of the text,
+ * if the display subsystem supports these formatting controls. If it does not,
+ * the problem may be handled by transforming the source text in this mode
+ * before displaying it, so that it will be displayed properly.<br>
+ * The source text should not contain Bidi control characters other than LRM
+ * or RLM.</li>
+ *
+ * <li>When the reordering mode is set to
+ * <code>#UBIDI_REORDER_INVERSE_NUMBERS_AS_L</code>, an "inverse Bidi" algorithm
+ * is applied.
+ * Runs of text with numeric characters will be treated like LTR letters and
+ * may need to be surrounded with LRM characters when they are written in
+ * reordered sequence (the option <code>#UBIDI_INSERT_LRM_FOR_NUMERIC</code> can
+ * be used with function <code>ubidi_writeReordered</code> to this end. This
+ * mode is equivalent to calling <code>ubidi_setInverse()</code> with
+ * argument <code>isInverse</code> set to <code>TRUE</code>.</li>
+ *
+ * <li>When the reordering mode is set to
+ * <code>#UBIDI_REORDER_INVERSE_LIKE_DIRECT</code>, the "direct" Logical to Visual
+ * Bidi algorithm is used as an approximation of an "inverse Bidi" algorithm.
+ * This mode is similar to mode <code>#UBIDI_REORDER_INVERSE_NUMBERS_AS_L</code>
+ * but is closer to the regular Bidi algorithm.
+ * <br>
+ * For example, an LTR paragraph with the content "FED 123 456 CBA" (where
+ * upper case represents RTL characters) will be transformed to
+ * "ABC 456 123 DEF", as opposed to "DEF 123 456 ABC"
+ * with mode <code>UBIDI_REORDER_INVERSE_NUMBERS_AS_L</code>.<br>
+ * When used in conjunction with option
+ * <code>#UBIDI_OPTION_INSERT_MARKS</code>, this mode generally
+ * adds Bidi marks to the output significantly more sparingly than mode
+ * <code>#UBIDI_REORDER_INVERSE_NUMBERS_AS_L</code> with option
+ * <code>#UBIDI_INSERT_LRM_FOR_NUMERIC</code> in calls to
+ * <code>ubidi_writeReordered</code>.</li>
+ *
+ * <li>When the reordering mode is set to
+ * <code>#UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL</code>, the Logical to Visual
+ * Bidi algorithm used in Windows XP is used as an approximation of an "inverse Bidi" algorithm.
+ * <br>
+ * For example, an LTR paragraph with the content "abc FED123" (where
+ * upper case represents RTL characters) will be transformed to "abc 123DEF."</li>
+ * </ul>
+ *
+ * <p>In all the reordering modes specifying an "inverse Bidi" algorithm
+ * (i.e. those with a name starting with <code>UBIDI_REORDER_INVERSE</code>),
+ * output runs should be retrieved using
+ * <code>ubidi_getVisualRun()</code>, and the output text with
+ * <code>ubidi_writeReordered()</code>. The caller should keep in mind that in
+ * "inverse Bidi" modes the input is actually visually ordered text and
+ * reordered output returned by <code>ubidi_getVisualRun()</code> or
+ * <code>ubidi_writeReordered()</code> are actually runs or character string
+ * of logically ordered output.<br>
+ * For all the "inverse Bidi" modes, the source text should not contain
+ * Bidi control characters other than LRM or RLM.</p>
+ *
+ * <p>Note that option <code>#UBIDI_OUTPUT_REVERSE</code> of
+ * <code>ubidi_writeReordered</code> has no useful meaning and should not be
+ * used in conjunction with any value of the reordering mode specifying
+ * "inverse Bidi" or with value <code>UBIDI_REORDER_RUNS_ONLY</code>.
+ *
+ * @param pBiDi is a <code>UBiDi</code> object.
+ * @param reorderingMode specifies the required variant of the Bidi algorithm.
+ *
+ * @see UBiDiReorderingMode
+ * @see ubidi_setInverse
+ * @see ubidi_setPara
+ * @see ubidi_writeReordered
+ * @stable ICU 3.6
+ */
+U_STABLE void U_EXPORT2
+ubidi_setReorderingMode(UBiDi *pBiDi, UBiDiReorderingMode reorderingMode);
+
+/**
+ * What is the requested reordering mode for a given Bidi object?
+ *
+ * @param pBiDi is a <code>UBiDi</code> object.
+ * @return the current reordering mode of the Bidi object
+ * @see ubidi_setReorderingMode
+ * @stable ICU 3.6
+ */
+U_STABLE UBiDiReorderingMode U_EXPORT2
+ubidi_getReorderingMode(UBiDi *pBiDi);
+
+/**
+ * <code>UBiDiReorderingOption</code> values indicate which options are
+ * specified to affect the Bidi algorithm.
+ *
+ * @see ubidi_setReorderingOptions
+ * @stable ICU 3.6
+ */
+typedef enum UBiDiReorderingOption {
+    /**
+     * option value for <code>ubidi_setReorderingOptions</code>:
+     * disable all the options which can be set with this function
+     * @see ubidi_setReorderingOptions
+     * @stable ICU 3.6
+     */
+    UBIDI_OPTION_DEFAULT = 0,
+
+    /**
+     * option bit for <code>ubidi_setReorderingOptions</code>:
+     * insert Bidi marks (LRM or RLM) when needed to ensure correct result of
+     * a reordering to a Logical order
+     *
+     * <p>This option must be set or reset before calling
+     * <code>ubidi_setPara</code>.</p>
+     *
+     * <p>This option is significant only with reordering modes which generate
+     * a result with Logical order, specifically:</p>
+     * <ul>
+     *   <li><code>#UBIDI_REORDER_RUNS_ONLY</code></li>
+     *   <li><code>#UBIDI_REORDER_INVERSE_NUMBERS_AS_L</code></li>
+     *   <li><code>#UBIDI_REORDER_INVERSE_LIKE_DIRECT</code></li>
+     *   <li><code>#UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL</code></li>
+     * </ul>
+     *
+     * <p>If this option is set in conjunction with reordering mode
+     * <code>#UBIDI_REORDER_INVERSE_NUMBERS_AS_L</code> or with calling
+     * <code>ubidi_setInverse(TRUE)</code>, it implies
+     * option <code>#UBIDI_INSERT_LRM_FOR_NUMERIC</code>
+     * in calls to function <code>ubidi_writeReordered()</code>.</p>
+     *
+     * <p>For other reordering modes, a minimum number of LRM or RLM characters
+     * will be added to the source text after reordering it so as to ensure
+     * round trip, i.e. when applying the inverse reordering mode on the
+     * resulting logical text with removal of Bidi marks
+     * (option <code>#UBIDI_OPTION_REMOVE_CONTROLS</code> set before calling
+     * <code>ubidi_setPara()</code> or option <code>#UBIDI_REMOVE_BIDI_CONTROLS</code>
+     * in <code>ubidi_writeReordered</code>), the result will be identical to the
+     * source text in the first transformation.
+     *
+     * <p>This option will be ignored if specified together with option
+     * <code>#UBIDI_OPTION_REMOVE_CONTROLS</code>. It inhibits option
+     * <code>UBIDI_REMOVE_BIDI_CONTROLS</code> in calls to function
+     * <code>ubidi_writeReordered()</code> and it implies option
+     * <code>#UBIDI_INSERT_LRM_FOR_NUMERIC</code> in calls to function
+     * <code>ubidi_writeReordered()</code> if the reordering mode is
+     * <code>#UBIDI_REORDER_INVERSE_NUMBERS_AS_L</code>.</p>
+     *
+     * @see ubidi_setReorderingMode
+     * @see ubidi_setReorderingOptions
+     * @stable ICU 3.6
+     */
+    UBIDI_OPTION_INSERT_MARKS = 1,
+
+    /**
+     * option bit for <code>ubidi_setReorderingOptions</code>:
+     * remove Bidi control characters
+     *
+     * <p>This option must be set or reset before calling
+     * <code>ubidi_setPara</code>.</p>
+     *
+     * <p>This option nullifies option <code>#UBIDI_OPTION_INSERT_MARKS</code>.
+     * It inhibits option <code>#UBIDI_INSERT_LRM_FOR_NUMERIC</code> in calls
+     * to function <code>ubidi_writeReordered()</code> and it implies option
+     * <code>#UBIDI_REMOVE_BIDI_CONTROLS</code> in calls to that function.</p>
+     *
+     * @see ubidi_setReorderingMode
+     * @see ubidi_setReorderingOptions
+     * @stable ICU 3.6
+     */
+    UBIDI_OPTION_REMOVE_CONTROLS = 2,
+
+    /**
+     * option bit for <code>ubidi_setReorderingOptions</code>:
+     * process the output as part of a stream to be continued
+     *
+     * <p>This option must be set or reset before calling
+     * <code>ubidi_setPara</code>.</p>
+     *
+     * <p>This option specifies that the caller is interested in processing large
+     * text object in parts.
+     * The results of the successive calls are expected to be concatenated by the
+     * caller. Only the call for the last part will have this option bit off.</p>
+     *
+     * <p>When this option bit is on, <code>ubidi_setPara()</code> may process
+     * less than the full source text in order to truncate the text at a meaningful
+     * boundary. The caller should call <code>ubidi_getProcessedLength()</code>
+     * immediately after calling <code>ubidi_setPara()</code> in order to
+     * determine how much of the source text has been processed.
+     * Source text beyond that length should be resubmitted in following calls to
+     * <code>ubidi_setPara</code>. The processed length may be less than
+     * the length of the source text if a character preceding the last character of
+     * the source text constitutes a reasonable boundary (like a block separator)
+     * for text to be continued.<br>
+     * If the last character of the source text constitutes a reasonable
+     * boundary, the whole text will be processed at once.<br>
+     * If nowhere in the source text there exists
+     * such a reasonable boundary, the processed length will be zero.<br>
+     * The caller should check for such an occurrence and do one of the following:
+     * <ul><li>submit a larger amount of text with a better chance to include
+     *         a reasonable boundary.</li>
+     *     <li>resubmit the same text after turning off option
+     *         <code>UBIDI_OPTION_STREAMING</code>.</li></ul>
+     * In all cases, this option should be turned off before processing the last
+     * part of the text.</p>
+     *
+     * <p>When the <code>UBIDI_OPTION_STREAMING</code> option is used,
+     * it is recommended to call <code>ubidi_orderParagraphsLTR()</code> with
+     * argument <code>orderParagraphsLTR</code> set to <code>TRUE</code> before
+     * calling <code>ubidi_setPara</code> so that later paragraphs may be
+     * concatenated to previous paragraphs on the right.</p>
+     *
+     * @see ubidi_setReorderingMode
+     * @see ubidi_setReorderingOptions
+     * @see ubidi_getProcessedLength
+     * @see ubidi_orderParagraphsLTR
+     * @stable ICU 3.6
+     */
+    UBIDI_OPTION_STREAMING = 4
+} UBiDiReorderingOption;
+
+/**
+ * Specify which of the reordering options
+ * should be applied during Bidi transformations.
+ *
+ * @param pBiDi is a <code>UBiDi</code> object.
+ * @param reorderingOptions is a combination of zero or more of the following
+ * options:
+ * <code>#UBIDI_OPTION_DEFAULT</code>, <code>#UBIDI_OPTION_INSERT_MARKS</code>,
+ * <code>#UBIDI_OPTION_REMOVE_CONTROLS</code>, <code>#UBIDI_OPTION_STREAMING</code>.
+ *
+ * @see ubidi_getReorderingOptions
+ * @stable ICU 3.6
+ */
+U_STABLE void U_EXPORT2
+ubidi_setReorderingOptions(UBiDi *pBiDi, uint32_t reorderingOptions);
+
+/**
+ * What are the reordering options applied to a given Bidi object?
+ *
+ * @param pBiDi is a <code>UBiDi</code> object.
+ * @return the current reordering options of the Bidi object
+ * @see ubidi_setReorderingOptions
+ * @stable ICU 3.6
+ */
+U_STABLE uint32_t U_EXPORT2
+ubidi_getReorderingOptions(UBiDi *pBiDi);
+
+/**
+ * Perform the Unicode Bidi algorithm. It is defined in the
+ * <a href="http://www.unicode.org/unicode/reports/tr9/">Unicode Standard Anned #9</a>,
+ * version 13,
+ * also described in The Unicode Standard, Version 4.0 .<p>
+ *
+ * This function takes a piece of plain text containing one or more paragraphs,
+ * with or without externally specified embedding levels from <i>styled</i>
+ * text and computes the left-right-directionality of each character.<p>
+ *
+ * If the entire text is all of the same directionality, then
+ * the function may not perform all the steps described by the algorithm,
+ * i.e., some levels may not be the same as if all steps were performed.
+ * This is not relevant for unidirectional text.<br>
+ * For example, in pure LTR text with numbers the numbers would get
+ * a resolved level of 2 higher than the surrounding text according to
+ * the algorithm. This implementation may set all resolved levels to
+ * the same value in such a case.<p>
+ *
+ * The text can be composed of multiple paragraphs. Occurrence of a block
+ * separator in the text terminates a paragraph, and whatever comes next starts
+ * a new paragraph. The exception to this rule is when a Carriage Return (CR)
+ * is followed by a Line Feed (LF). Both CR and LF are block separators, but
+ * in that case, the pair of characters is considered as terminating the
+ * preceding paragraph, and a new paragraph will be started by a character
+ * coming after the LF.
+ *
+ * @param pBiDi A <code>UBiDi</code> object allocated with <code>ubidi_open()</code>
+ *        which will be set to contain the reordering information,
+ *        especially the resolved levels for all the characters in <code>text</code>.
+ *
+ * @param text is a pointer to the text that the Bidi algorithm will be performed on.
+ *        This pointer is stored in the UBiDi object and can be retrieved
+ *        with <code>ubidi_getText()</code>.<br>
+ *        <strong>Note:</strong> the text must be (at least) <code>length</code> long.
+ *
+ * @param length is the length of the text; if <code>length==-1</code> then
+ *        the text must be zero-terminated.
+ *
+ * @param paraLevel specifies the default level for the text;
+ *        it is typically 0 (LTR) or 1 (RTL).
+ *        If the function shall determine the paragraph level from the text,
+ *        then <code>paraLevel</code> can be set to
+ *        either <code>#UBIDI_DEFAULT_LTR</code>
+ *        or <code>#UBIDI_DEFAULT_RTL</code>; if the text contains multiple
+ *        paragraphs, the paragraph level shall be determined separately for
+ *        each paragraph; if a paragraph does not include any strongly typed
+ *        character, then the desired default is used (0 for LTR or 1 for RTL).
+ *        Any other value between 0 and <code>#UBIDI_MAX_EXPLICIT_LEVEL</code>
+ *        is also valid, with odd levels indicating RTL.
+ *
+ * @param embeddingLevels (in) may be used to preset the embedding and override levels,
+ *        ignoring characters like LRE and PDF in the text.
+ *        A level overrides the directional property of its corresponding
+ *        (same index) character if the level has the
+ *        <code>#UBIDI_LEVEL_OVERRIDE</code> bit set.<br><br>
+ *        Except for that bit, it must be
+ *        <code>paraLevel<=embeddingLevels[]<=UBIDI_MAX_EXPLICIT_LEVEL</code>,
+ *        with one exception: a level of zero may be specified for a paragraph
+ *        separator even if <code>paraLevel>0</code> when multiple paragraphs
+ *        are submitted in the same call to <code>ubidi_setPara()</code>.<br><br>
+ *        <strong>Caution: </strong>A copy of this pointer, not of the levels,
+ *        will be stored in the <code>UBiDi</code> object;
+ *        the <code>embeddingLevels</code> array must not be
+ *        deallocated before the <code>UBiDi</code> structure is destroyed or reused,
+ *        and the <code>embeddingLevels</code>
+ *        should not be modified to avoid unexpected results on subsequent Bidi operations.
+ *        However, the <code>ubidi_setPara()</code> and
+ *        <code>ubidi_setLine()</code> functions may modify some or all of the levels.<br><br>
+ *        After the <code>UBiDi</code> object is reused or destroyed, the caller
+ *        must take care of the deallocation of the <code>embeddingLevels</code> array.<br><br>
+ *        <strong>Note:</strong> the <code>embeddingLevels</code> array must be
+ *        at least <code>length</code> long.
+ *        This pointer can be <code>NULL</code> if this
+ *        value is not necessary.
+ *
+ * @param pErrorCode must be a valid pointer to an error code value.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ubidi_setPara(UBiDi *pBiDi, const UChar *text, int32_t length,
+              UBiDiLevel paraLevel, UBiDiLevel *embeddingLevels,
+              UErrorCode *pErrorCode);
+
+/**
+ * <code>ubidi_setLine()</code> sets a <code>UBiDi</code> to
+ * contain the reordering information, especially the resolved levels,
+ * for all the characters in a line of text. This line of text is
+ * specified by referring to a <code>UBiDi</code> object representing
+ * this information for a piece of text containing one or more paragraphs,
+ * and by specifying a range of indexes in this text.<p>
+ * In the new line object, the indexes will range from 0 to <code>limit-start-1</code>.<p>
+ *
+ * This is used after calling <code>ubidi_setPara()</code>
+ * for a piece of text, and after line-breaking on that text.
+ * It is not necessary if each paragraph is treated as a single line.<p>
+ *
+ * After line-breaking, rules (L1) and (L2) for the treatment of
+ * trailing WS and for reordering are performed on
+ * a <code>UBiDi</code> object that represents a line.<p>
+ *
+ * <strong>Important: </strong><code>pLineBiDi</code> shares data with
+ * <code>pParaBiDi</code>.
+ * You must destroy or reuse <code>pLineBiDi</code> before <code>pParaBiDi</code>.
+ * In other words, you must destroy or reuse the <code>UBiDi</code> object for a line
+ * before the object for its parent paragraph.<p>
+ *
+ * The text pointer that was stored in <code>pParaBiDi</code> is also copied,
+ * and <code>start</code> is added to it so that it points to the beginning of the
+ * line for this object.
+ *
+ * @param pParaBiDi is the parent paragraph object. It must have been set
+ * by a successful call to ubidi_setPara.
+ *
+ * @param start is the line's first index into the text.
+ *
+ * @param limit is just behind the line's last index into the text
+ *        (its last index +1).<br>
+ *        It must be <code>0<=start<limit<=</code>containing paragraph limit.
+ *        If the specified line crosses a paragraph boundary, the function
+ *        will terminate with error code U_ILLEGAL_ARGUMENT_ERROR.
+ *
+ * @param pLineBiDi is the object that will now represent a line of the text.
+ *
+ * @param pErrorCode must be a valid pointer to an error code value.
+ *
+ * @see ubidi_setPara
+ * @see ubidi_getProcessedLength
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ubidi_setLine(const UBiDi *pParaBiDi,
+              int32_t start, int32_t limit,
+              UBiDi *pLineBiDi,
+              UErrorCode *pErrorCode);
+
+/**
+ * Get the directionality of the text.
+ *
+ * @param pBiDi is the paragraph or line <code>UBiDi</code> object.
+ *
+ * @return a value of <code>UBIDI_LTR</code>, <code>UBIDI_RTL</code>
+ *         or <code>UBIDI_MIXED</code>
+ *         that indicates if the entire text
+ *         represented by this object is unidirectional,
+ *         and which direction, or if it is mixed-directional.
+ * Note -  The value <code>UBIDI_NEUTRAL</code> is never returned from this method.
+ *
+ * @see UBiDiDirection
+ * @stable ICU 2.0
+ */
+U_STABLE UBiDiDirection U_EXPORT2
+ubidi_getDirection(const UBiDi *pBiDi);
+
+/**
+ * Gets the base direction of the text provided according
+ * to the Unicode Bidirectional Algorithm. The base direction
+ * is derived from the first character in the string with bidirectional
+ * character type L, R, or AL. If the first such character has type L,
+ * <code>UBIDI_LTR</code> is returned. If the first such character has
+ * type R or AL, <code>UBIDI_RTL</code> is returned. If the string does
+ * not contain any character of these types, then
+ * <code>UBIDI_NEUTRAL</code> is returned.
+ *
+ * This is a lightweight function for use when only the base direction
+ * is needed and no further bidi processing of the text is needed.
+ *
+ * @param text is a pointer to the text whose base
+ *             direction is needed.
+ * Note: the text must be (at least) @c length long.
+ *
+ * @param length is the length of the text;
+ *               if <code>length==-1</code> then the text
+ *               must be zero-terminated.
+ *
+ * @return  <code>UBIDI_LTR</code>, <code>UBIDI_RTL</code>,
+ *          <code>UBIDI_NEUTRAL</code>
+ *
+ * @see UBiDiDirection
+ * @draft ICU 4.6
+ */
+U_DRAFT UBiDiDirection U_EXPORT2
+ubidi_getBaseDirection(const UChar *text,  int32_t length );
+
+/**
+ * Get the pointer to the text.
+ *
+ * @param pBiDi is the paragraph or line <code>UBiDi</code> object.
+ *
+ * @return The pointer to the text that the UBiDi object was created for.
+ *
+ * @see ubidi_setPara
+ * @see ubidi_setLine
+ * @stable ICU 2.0
+ */
+U_STABLE const UChar * U_EXPORT2
+ubidi_getText(const UBiDi *pBiDi);
+
+/**
+ * Get the length of the text.
+ *
+ * @param pBiDi is the paragraph or line <code>UBiDi</code> object.
+ *
+ * @return The length of the text that the UBiDi object was created for.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ubidi_getLength(const UBiDi *pBiDi);
+
+/**
+ * Get the paragraph level of the text.
+ *
+ * @param pBiDi is the paragraph or line <code>UBiDi</code> object.
+ *
+ * @return The paragraph level. If there are multiple paragraphs, their
+ *         level may vary if the required paraLevel is UBIDI_DEFAULT_LTR or
+ *         UBIDI_DEFAULT_RTL.  In that case, the level of the first paragraph
+ *         is returned.
+ *
+ * @see UBiDiLevel
+ * @see ubidi_getParagraph
+ * @see ubidi_getParagraphByIndex
+ * @stable ICU 2.0
+ */
+U_STABLE UBiDiLevel U_EXPORT2
+ubidi_getParaLevel(const UBiDi *pBiDi);
+
+/**
+ * Get the number of paragraphs.
+ *
+ * @param pBiDi is the paragraph or line <code>UBiDi</code> object.
+ *
+ * @return The number of paragraphs.
+ * @stable ICU 3.4
+ */
+U_STABLE int32_t U_EXPORT2
+ubidi_countParagraphs(UBiDi *pBiDi);
+
+/**
+ * Get a paragraph, given a position within the text.
+ * This function returns information about a paragraph.<br>
+ * Note: if the paragraph index is known, it is more efficient to
+ * retrieve the paragraph information using ubidi_getParagraphByIndex().<p>
+ *
+ * @param pBiDi is the paragraph or line <code>UBiDi</code> object.
+ *
+ * @param charIndex is the index of a character within the text, in the
+ *        range <code>[0..ubidi_getProcessedLength(pBiDi)-1]</code>.
+ *
+ * @param pParaStart will receive the index of the first character of the
+ *        paragraph in the text.
+ *        This pointer can be <code>NULL</code> if this
+ *        value is not necessary.
+ *
+ * @param pParaLimit will receive the limit of the paragraph.
+ *        The l-value that you point to here may be the
+ *        same expression (variable) as the one for
+ *        <code>charIndex</code>.
+ *        This pointer can be <code>NULL</code> if this
+ *        value is not necessary.
+ *
+ * @param pParaLevel will receive the level of the paragraph.
+ *        This pointer can be <code>NULL</code> if this
+ *        value is not necessary.
+ *
+ * @param pErrorCode must be a valid pointer to an error code value.
+ *
+ * @return The index of the paragraph containing the specified position.
+ *
+ * @see ubidi_getProcessedLength
+ * @stable ICU 3.4
+ */
+U_STABLE int32_t U_EXPORT2
+ubidi_getParagraph(const UBiDi *pBiDi, int32_t charIndex, int32_t *pParaStart,
+                   int32_t *pParaLimit, UBiDiLevel *pParaLevel,
+                   UErrorCode *pErrorCode);
+
+/**
+ * Get a paragraph, given the index of this paragraph.
+ *
+ * This function returns information about a paragraph.<p>
+ *
+ * @param pBiDi is the paragraph <code>UBiDi</code> object.
+ *
+ * @param paraIndex is the number of the paragraph, in the
+ *        range <code>[0..ubidi_countParagraphs(pBiDi)-1]</code>.
+ *
+ * @param pParaStart will receive the index of the first character of the
+ *        paragraph in the text.
+ *        This pointer can be <code>NULL</code> if this
+ *        value is not necessary.
+ *
+ * @param pParaLimit will receive the limit of the paragraph.
+ *        This pointer can be <code>NULL</code> if this
+ *        value is not necessary.
+ *
+ * @param pParaLevel will receive the level of the paragraph.
+ *        This pointer can be <code>NULL</code> if this
+ *        value is not necessary.
+ *
+ * @param pErrorCode must be a valid pointer to an error code value.
+ *
+ * @stable ICU 3.4
+ */
+U_STABLE void U_EXPORT2
+ubidi_getParagraphByIndex(const UBiDi *pBiDi, int32_t paraIndex,
+                          int32_t *pParaStart, int32_t *pParaLimit,
+                          UBiDiLevel *pParaLevel, UErrorCode *pErrorCode);
+
+/**
+ * Get the level for one character.
+ *
+ * @param pBiDi is the paragraph or line <code>UBiDi</code> object.
+ *
+ * @param charIndex the index of a character. It must be in the range
+ *         [0..ubidi_getProcessedLength(pBiDi)].
+ *
+ * @return The level for the character at charIndex (0 if charIndex is not
+ *         in the valid range).
+ *
+ * @see UBiDiLevel
+ * @see ubidi_getProcessedLength
+ * @stable ICU 2.0
+ */
+U_STABLE UBiDiLevel U_EXPORT2
+ubidi_getLevelAt(const UBiDi *pBiDi, int32_t charIndex);
+
+/**
+ * Get an array of levels for each character.<p>
+ *
+ * Note that this function may allocate memory under some
+ * circumstances, unlike <code>ubidi_getLevelAt()</code>.
+ *
+ * @param pBiDi is the paragraph or line <code>UBiDi</code> object, whose
+ *        text length must be strictly positive.
+ *
+ * @param pErrorCode must be a valid pointer to an error code value.
+ *
+ * @return The levels array for the text,
+ *         or <code>NULL</code> if an error occurs.
+ *
+ * @see UBiDiLevel
+ * @see ubidi_getProcessedLength
+ * @stable ICU 2.0
+ */
+U_STABLE const UBiDiLevel * U_EXPORT2
+ubidi_getLevels(UBiDi *pBiDi, UErrorCode *pErrorCode);
+
+/**
+ * Get a logical run.
+ * This function returns information about a run and is used
+ * to retrieve runs in logical order.<p>
+ * This is especially useful for line-breaking on a paragraph.
+ *
+ * @param pBiDi is the paragraph or line <code>UBiDi</code> object.
+ *
+ * @param logicalPosition is a logical position within the source text.
+ *
+ * @param pLogicalLimit will receive the limit of the corresponding run.
+ *        The l-value that you point to here may be the
+ *        same expression (variable) as the one for
+ *        <code>logicalPosition</code>.
+ *        This pointer can be <code>NULL</code> if this
+ *        value is not necessary.
+ *
+ * @param pLevel will receive the level of the corresponding run.
+ *        This pointer can be <code>NULL</code> if this
+ *        value is not necessary.
+ *
+ * @see ubidi_getProcessedLength
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ubidi_getLogicalRun(const UBiDi *pBiDi, int32_t logicalPosition,
+                    int32_t *pLogicalLimit, UBiDiLevel *pLevel);
+
+/**
+ * Get the number of runs.
+ * This function may invoke the actual reordering on the
+ * <code>UBiDi</code> object, after <code>ubidi_setPara()</code>
+ * may have resolved only the levels of the text. Therefore,
+ * <code>ubidi_countRuns()</code> may have to allocate memory,
+ * and may fail doing so.
+ *
+ * @param pBiDi is the paragraph or line <code>UBiDi</code> object.
+ *
+ * @param pErrorCode must be a valid pointer to an error code value.
+ *
+ * @return The number of runs.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ubidi_countRuns(UBiDi *pBiDi, UErrorCode *pErrorCode);
+
+/**
+ * Get one run's logical start, length, and directionality,
+ * which can be 0 for LTR or 1 for RTL.
+ * In an RTL run, the character at the logical start is
+ * visually on the right of the displayed run.
+ * The length is the number of characters in the run.<p>
+ * <code>ubidi_countRuns()</code> should be called
+ * before the runs are retrieved.
+ *
+ * @param pBiDi is the paragraph or line <code>UBiDi</code> object.
+ *
+ * @param runIndex is the number of the run in visual order, in the
+ *        range <code>[0..ubidi_countRuns(pBiDi)-1]</code>.
+ *
+ * @param pLogicalStart is the first logical character index in the text.
+ *        The pointer may be <code>NULL</code> if this index is not needed.
+ *
+ * @param pLength is the number of characters (at least one) in the run.
+ *        The pointer may be <code>NULL</code> if this is not needed.
+ *
+ * @return the directionality of the run,
+ *         <code>UBIDI_LTR==0</code> or <code>UBIDI_RTL==1</code>,
+ *         never <code>UBIDI_MIXED</code>,
+ *         never <code>UBIDI_NEUTRAL</code>.
+ *
+ * @see ubidi_countRuns
+ *
+ * Example:
+ * <pre>
+ * \code
+ * int32_t i, count=ubidi_countRuns(pBiDi),
+ *         logicalStart, visualIndex=0, length;
+ * for(i=0; i<count; ++i) {
+ *    if(UBIDI_LTR==ubidi_getVisualRun(pBiDi, i, &logicalStart, &length)) {
+ *         do { // LTR
+ *             show_char(text[logicalStart++], visualIndex++);
+ *         } while(--length>0);
+ *     } else {
+ *         logicalStart+=length;  // logicalLimit
+ *         do { // RTL
+ *             show_char(text[--logicalStart], visualIndex++);
+ *         } while(--length>0);
+ *     }
+ * }
+ *\endcode
+ * </pre>
+ *
+ * Note that in right-to-left runs, code like this places
+ * second surrogates before first ones (which is generally a bad idea)
+ * and combining characters before base characters.
+ * <p>
+ * Use of <code>ubidi_writeReordered()</code>, optionally with the
+ * <code>#UBIDI_KEEP_BASE_COMBINING</code> option, can be considered in order
+ * to avoid these issues.
+ * @stable ICU 2.0
+ */
+U_STABLE UBiDiDirection U_EXPORT2
+ubidi_getVisualRun(UBiDi *pBiDi, int32_t runIndex,
+                   int32_t *pLogicalStart, int32_t *pLength);
+
+/**
+ * Get the visual position from a logical text position.
+ * If such a mapping is used many times on the same
+ * <code>UBiDi</code> object, then calling
+ * <code>ubidi_getLogicalMap()</code> is more efficient.<p>
+ *
+ * The value returned may be <code>#UBIDI_MAP_NOWHERE</code> if there is no
+ * visual position because the corresponding text character is a Bidi control
+ * removed from output by the option <code>#UBIDI_OPTION_REMOVE_CONTROLS</code>.
+ * <p>
+ * When the visual output is altered by using options of
+ * <code>ubidi_writeReordered()</code> such as <code>UBIDI_INSERT_LRM_FOR_NUMERIC</code>,
+ * <code>UBIDI_KEEP_BASE_COMBINING</code>, <code>UBIDI_OUTPUT_REVERSE</code>,
+ * <code>UBIDI_REMOVE_BIDI_CONTROLS</code>, the visual position returned may not
+ * be correct. It is advised to use, when possible, reordering options
+ * such as <code>UBIDI_OPTION_INSERT_MARKS</code> and <code>UBIDI_OPTION_REMOVE_CONTROLS</code>.
+ * <p>
+ * Note that in right-to-left runs, this mapping places
+ * second surrogates before first ones (which is generally a bad idea)
+ * and combining characters before base characters.
+ * Use of <code>ubidi_writeReordered()</code>, optionally with the
+ * <code>#UBIDI_KEEP_BASE_COMBINING</code> option can be considered instead
+ * of using the mapping, in order to avoid these issues.
+ *
+ * @param pBiDi is the paragraph or line <code>UBiDi</code> object.
+ *
+ * @param logicalIndex is the index of a character in the text.
+ *
+ * @param pErrorCode must be a valid pointer to an error code value.
+ *
+ * @return The visual position of this character.
+ *
+ * @see ubidi_getLogicalMap
+ * @see ubidi_getLogicalIndex
+ * @see ubidi_getProcessedLength
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ubidi_getVisualIndex(UBiDi *pBiDi, int32_t logicalIndex, UErrorCode *pErrorCode);
+
+/**
+ * Get the logical text position from a visual position.
+ * If such a mapping is used many times on the same
+ * <code>UBiDi</code> object, then calling
+ * <code>ubidi_getVisualMap()</code> is more efficient.<p>
+ *
+ * The value returned may be <code>#UBIDI_MAP_NOWHERE</code> if there is no
+ * logical position because the corresponding text character is a Bidi mark
+ * inserted in the output by option <code>#UBIDI_OPTION_INSERT_MARKS</code>.
+ * <p>
+ * This is the inverse function to <code>ubidi_getVisualIndex()</code>.
+ * <p>
+ * When the visual output is altered by using options of
+ * <code>ubidi_writeReordered()</code> such as <code>UBIDI_INSERT_LRM_FOR_NUMERIC</code>,
+ * <code>UBIDI_KEEP_BASE_COMBINING</code>, <code>UBIDI_OUTPUT_REVERSE</code>,
+ * <code>UBIDI_REMOVE_BIDI_CONTROLS</code>, the logical position returned may not
+ * be correct. It is advised to use, when possible, reordering options
+ * such as <code>UBIDI_OPTION_INSERT_MARKS</code> and <code>UBIDI_OPTION_REMOVE_CONTROLS</code>.
+ *
+ * @param pBiDi is the paragraph or line <code>UBiDi</code> object.
+ *
+ * @param visualIndex is the visual position of a character.
+ *
+ * @param pErrorCode must be a valid pointer to an error code value.
+ *
+ * @return The index of this character in the text.
+ *
+ * @see ubidi_getVisualMap
+ * @see ubidi_getVisualIndex
+ * @see ubidi_getResultLength
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ubidi_getLogicalIndex(UBiDi *pBiDi, int32_t visualIndex, UErrorCode *pErrorCode);
+
+/**
+ * Get a logical-to-visual index map (array) for the characters in the UBiDi
+ * (paragraph or line) object.
+ * <p>
+ * Some values in the map may be <code>#UBIDI_MAP_NOWHERE</code> if the
+ * corresponding text characters are Bidi controls removed from the visual
+ * output by the option <code>#UBIDI_OPTION_REMOVE_CONTROLS</code>.
+ * <p>
+ * When the visual output is altered by using options of
+ * <code>ubidi_writeReordered()</code> such as <code>UBIDI_INSERT_LRM_FOR_NUMERIC</code>,
+ * <code>UBIDI_KEEP_BASE_COMBINING</code>, <code>UBIDI_OUTPUT_REVERSE</code>,
+ * <code>UBIDI_REMOVE_BIDI_CONTROLS</code>, the visual positions returned may not
+ * be correct. It is advised to use, when possible, reordering options
+ * such as <code>UBIDI_OPTION_INSERT_MARKS</code> and <code>UBIDI_OPTION_REMOVE_CONTROLS</code>.
+ * <p>
+ * Note that in right-to-left runs, this mapping places
+ * second surrogates before first ones (which is generally a bad idea)
+ * and combining characters before base characters.
+ * Use of <code>ubidi_writeReordered()</code>, optionally with the
+ * <code>#UBIDI_KEEP_BASE_COMBINING</code> option can be considered instead
+ * of using the mapping, in order to avoid these issues.
+ *
+ * @param pBiDi is the paragraph or line <code>UBiDi</code> object.
+ *
+ * @param indexMap is a pointer to an array of <code>ubidi_getProcessedLength()</code>
+ *        indexes which will reflect the reordering of the characters.
+ *        If option <code>#UBIDI_OPTION_INSERT_MARKS</code> is set, the number
+ *        of elements allocated in <code>indexMap</code> must be no less than
+ *        <code>ubidi_getResultLength()</code>.
+ *        The array does not need to be initialized.<br><br>
+ *        The index map will result in <code>indexMap[logicalIndex]==visualIndex</code>.
+ *
+ * @param pErrorCode must be a valid pointer to an error code value.
+ *
+ * @see ubidi_getVisualMap
+ * @see ubidi_getVisualIndex
+ * @see ubidi_getProcessedLength
+ * @see ubidi_getResultLength
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ubidi_getLogicalMap(UBiDi *pBiDi, int32_t *indexMap, UErrorCode *pErrorCode);
+
+/**
+ * Get a visual-to-logical index map (array) for the characters in the UBiDi
+ * (paragraph or line) object.
+ * <p>
+ * Some values in the map may be <code>#UBIDI_MAP_NOWHERE</code> if the
+ * corresponding text characters are Bidi marks inserted in the visual output
+ * by the option <code>#UBIDI_OPTION_INSERT_MARKS</code>.
+ * <p>
+ * When the visual output is altered by using options of
+ * <code>ubidi_writeReordered()</code> such as <code>UBIDI_INSERT_LRM_FOR_NUMERIC</code>,
+ * <code>UBIDI_KEEP_BASE_COMBINING</code>, <code>UBIDI_OUTPUT_REVERSE</code>,
+ * <code>UBIDI_REMOVE_BIDI_CONTROLS</code>, the logical positions returned may not
+ * be correct. It is advised to use, when possible, reordering options
+ * such as <code>UBIDI_OPTION_INSERT_MARKS</code> and <code>UBIDI_OPTION_REMOVE_CONTROLS</code>.
+ *
+ * @param pBiDi is the paragraph or line <code>UBiDi</code> object.
+ *
+ * @param indexMap is a pointer to an array of <code>ubidi_getResultLength()</code>
+ *        indexes which will reflect the reordering of the characters.
+ *        If option <code>#UBIDI_OPTION_REMOVE_CONTROLS</code> is set, the number
+ *        of elements allocated in <code>indexMap</code> must be no less than
+ *        <code>ubidi_getProcessedLength()</code>.
+ *        The array does not need to be initialized.<br><br>
+ *        The index map will result in <code>indexMap[visualIndex]==logicalIndex</code>.
+ *
+ * @param pErrorCode must be a valid pointer to an error code value.
+ *
+ * @see ubidi_getLogicalMap
+ * @see ubidi_getLogicalIndex
+ * @see ubidi_getProcessedLength
+ * @see ubidi_getResultLength
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ubidi_getVisualMap(UBiDi *pBiDi, int32_t *indexMap, UErrorCode *pErrorCode);
+
+/**
+ * This is a convenience function that does not use a UBiDi object.
+ * It is intended to be used for when an application has determined the levels
+ * of objects (character sequences) and just needs to have them reordered (L2).
+ * This is equivalent to using <code>ubidi_getLogicalMap()</code> on a
+ * <code>UBiDi</code> object.
+ *
+ * @param levels is an array with <code>length</code> levels that have been determined by
+ *        the application.
+ *
+ * @param length is the number of levels in the array, or, semantically,
+ *        the number of objects to be reordered.
+ *        It must be <code>length>0</code>.
+ *
+ * @param indexMap is a pointer to an array of <code>length</code>
+ *        indexes which will reflect the reordering of the characters.
+ *        The array does not need to be initialized.<p>
+ *        The index map will result in <code>indexMap[logicalIndex]==visualIndex</code>.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ubidi_reorderLogical(const UBiDiLevel *levels, int32_t length, int32_t *indexMap);
+
+/**
+ * This is a convenience function that does not use a UBiDi object.
+ * It is intended to be used for when an application has determined the levels
+ * of objects (character sequences) and just needs to have them reordered (L2).
+ * This is equivalent to using <code>ubidi_getVisualMap()</code> on a
+ * <code>UBiDi</code> object.
+ *
+ * @param levels is an array with <code>length</code> levels that have been determined by
+ *        the application.
+ *
+ * @param length is the number of levels in the array, or, semantically,
+ *        the number of objects to be reordered.
+ *        It must be <code>length>0</code>.
+ *
+ * @param indexMap is a pointer to an array of <code>length</code>
+ *        indexes which will reflect the reordering of the characters.
+ *        The array does not need to be initialized.<p>
+ *        The index map will result in <code>indexMap[visualIndex]==logicalIndex</code>.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ubidi_reorderVisual(const UBiDiLevel *levels, int32_t length, int32_t *indexMap);
+
+/**
+ * Invert an index map.
+ * The index mapping of the first map is inverted and written to
+ * the second one.
+ *
+ * @param srcMap is an array with <code>length</code> elements
+ *        which defines the original mapping from a source array containing
+ *        <code>length</code> elements to a destination array.
+ *        Some elements of the source array may have no mapping in the
+ *        destination array. In that case, their value will be
+ *        the special value <code>UBIDI_MAP_NOWHERE</code>.
+ *        All elements must be >=0 or equal to <code>UBIDI_MAP_NOWHERE</code>.
+ *        Some elements may have a value >= <code>length</code>, if the
+ *        destination array has more elements than the source array.
+ *        There must be no duplicate indexes (two or more elements with the
+ *        same value except <code>UBIDI_MAP_NOWHERE</code>).
+ *
+ * @param destMap is an array with a number of elements equal to 1 + the highest
+ *        value in <code>srcMap</code>.
+ *        <code>destMap</code> will be filled with the inverse mapping.
+ *        If element with index i in <code>srcMap</code> has a value k different
+ *        from <code>UBIDI_MAP_NOWHERE</code>, this means that element i of
+ *        the source array maps to element k in the destination array.
+ *        The inverse map will have value i in its k-th element.
+ *        For all elements of the destination array which do not map to
+ *        an element in the source array, the corresponding element in the
+ *        inverse map will have a value equal to <code>UBIDI_MAP_NOWHERE</code>.
+ *
+ * @param length is the length of each array.
+ * @see UBIDI_MAP_NOWHERE
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ubidi_invertMap(const int32_t *srcMap, int32_t *destMap, int32_t length);
+
+/** option flags for ubidi_writeReordered() */
+
+/**
+ * option bit for ubidi_writeReordered():
+ * keep combining characters after their base characters in RTL runs
+ *
+ * @see ubidi_writeReordered
+ * @stable ICU 2.0
+ */
+#define UBIDI_KEEP_BASE_COMBINING       1
+
+/**
+ * option bit for ubidi_writeReordered():
+ * replace characters with the "mirrored" property in RTL runs
+ * by their mirror-image mappings
+ *
+ * @see ubidi_writeReordered
+ * @stable ICU 2.0
+ */
+#define UBIDI_DO_MIRRORING              2
+
+/**
+ * option bit for ubidi_writeReordered():
+ * surround the run with LRMs if necessary;
+ * this is part of the approximate "inverse Bidi" algorithm
+ *
+ * <p>This option does not imply corresponding adjustment of the index
+ * mappings.</p>
+ *
+ * @see ubidi_setInverse
+ * @see ubidi_writeReordered
+ * @stable ICU 2.0
+ */
+#define UBIDI_INSERT_LRM_FOR_NUMERIC    4
+
+/**
+ * option bit for ubidi_writeReordered():
+ * remove Bidi control characters
+ * (this does not affect #UBIDI_INSERT_LRM_FOR_NUMERIC)
+ *
+ * <p>This option does not imply corresponding adjustment of the index
+ * mappings.</p>
+ *
+ * @see ubidi_writeReordered
+ * @stable ICU 2.0
+ */
+#define UBIDI_REMOVE_BIDI_CONTROLS      8
+
+/**
+ * option bit for ubidi_writeReordered():
+ * write the output in reverse order
+ *
+ * <p>This has the same effect as calling <code>ubidi_writeReordered()</code>
+ * first without this option, and then calling
+ * <code>ubidi_writeReverse()</code> without mirroring.
+ * Doing this in the same step is faster and avoids a temporary buffer.
+ * An example for using this option is output to a character terminal that
+ * is designed for RTL scripts and stores text in reverse order.</p>
+ *
+ * @see ubidi_writeReordered
+ * @stable ICU 2.0
+ */
+#define UBIDI_OUTPUT_REVERSE            16
+
+/**
+ * Get the length of the source text processed by the last call to
+ * <code>ubidi_setPara()</code>. This length may be different from the length
+ * of the source text if option <code>#UBIDI_OPTION_STREAMING</code>
+ * has been set.
+ * <br>
+ * Note that whenever the length of the text affects the execution or the
+ * result of a function, it is the processed length which must be considered,
+ * except for <code>ubidi_setPara</code> (which receives unprocessed source
+ * text) and <code>ubidi_getLength</code> (which returns the original length
+ * of the source text).<br>
+ * In particular, the processed length is the one to consider in the following
+ * cases:
+ * <ul>
+ * <li>maximum value of the <code>limit</code> argument of
+ * <code>ubidi_setLine</code></li>
+ * <li>maximum value of the <code>charIndex</code> argument of
+ * <code>ubidi_getParagraph</code></li>
+ * <li>maximum value of the <code>charIndex</code> argument of
+ * <code>ubidi_getLevelAt</code></li>
+ * <li>number of elements in the array returned by <code>ubidi_getLevels</code></li>
+ * <li>maximum value of the <code>logicalStart</code> argument of
+ * <code>ubidi_getLogicalRun</code></li>
+ * <li>maximum value of the <code>logicalIndex</code> argument of
+ * <code>ubidi_getVisualIndex</code></li>
+ * <li>number of elements filled in the <code>*indexMap</code> argument of
+ * <code>ubidi_getLogicalMap</code></li>
+ * <li>length of text processed by <code>ubidi_writeReordered</code></li>
+ * </ul>
+ *
+ * @param pBiDi is the paragraph <code>UBiDi</code> object.
+ *
+ * @return The length of the part of the source text processed by
+ *         the last call to <code>ubidi_setPara</code>.
+ * @see ubidi_setPara
+ * @see UBIDI_OPTION_STREAMING
+ * @stable ICU 3.6
+ */
+U_STABLE int32_t U_EXPORT2
+ubidi_getProcessedLength(const UBiDi *pBiDi);
+
+/**
+ * Get the length of the reordered text resulting from the last call to
+ * <code>ubidi_setPara()</code>. This length may be different from the length
+ * of the source text if option <code>#UBIDI_OPTION_INSERT_MARKS</code>
+ * or option <code>#UBIDI_OPTION_REMOVE_CONTROLS</code> has been set.
+ * <br>
+ * This resulting length is the one to consider in the following cases:
+ * <ul>
+ * <li>maximum value of the <code>visualIndex</code> argument of
+ * <code>ubidi_getLogicalIndex</code></li>
+ * <li>number of elements of the <code>*indexMap</code> argument of
+ * <code>ubidi_getVisualMap</code></li>
+ * </ul>
+ * Note that this length stays identical to the source text length if
+ * Bidi marks are inserted or removed using option bits of
+ * <code>ubidi_writeReordered</code>, or if option
+ * <code>#UBIDI_REORDER_INVERSE_NUMBERS_AS_L</code> has been set.
+ *
+ * @param pBiDi is the paragraph <code>UBiDi</code> object.
+ *
+ * @return The length of the reordered text resulting from
+ *         the last call to <code>ubidi_setPara</code>.
+ * @see ubidi_setPara
+ * @see UBIDI_OPTION_INSERT_MARKS
+ * @see UBIDI_OPTION_REMOVE_CONTROLS
+ * @stable ICU 3.6
+ */
+U_STABLE int32_t U_EXPORT2
+ubidi_getResultLength(const UBiDi *pBiDi);
+
+U_CDECL_BEGIN
+/**
+ * value returned by <code>UBiDiClassCallback</code> callbacks when
+ * there is no need to override the standard Bidi class for a given code point.
+ * @see UBiDiClassCallback
+ * @stable ICU 3.6
+ */
+#define U_BIDI_CLASS_DEFAULT  U_CHAR_DIRECTION_COUNT
+
+/**
+ * Callback type declaration for overriding default Bidi class values with
+ * custom ones.
+ * <p>Usually, the function pointer will be propagated to a <code>UBiDi</code>
+ * object by calling the <code>ubidi_setClassCallback()</code> function;
+ * then the callback will be invoked by the UBA implementation any time the
+ * class of a character is to be determined.</p>
+ *
+ * @param context is a pointer to the callback private data.
+ *
+ * @param c       is the code point to get a Bidi class for.
+ *
+ * @return The directional property / Bidi class for the given code point
+ *         <code>c</code> if the default class has been overridden, or
+ *         <code>#U_BIDI_CLASS_DEFAULT</code> if the standard Bidi class value
+ *         for <code>c</code> is to be used.
+ * @see ubidi_setClassCallback
+ * @see ubidi_getClassCallback
+ * @stable ICU 3.6
+ */
+typedef UCharDirection U_CALLCONV
+UBiDiClassCallback(const void *context, UChar32 c);
+
+U_CDECL_END
+
+/**
+ * Retrieve the Bidi class for a given code point.
+ * <p>If a <code>#UBiDiClassCallback</code> callback is defined and returns a
+ * value other than <code>#U_BIDI_CLASS_DEFAULT</code>, that value is used;
+ * otherwise the default class determination mechanism is invoked.</p>
+ *
+ * @param pBiDi is the paragraph <code>UBiDi</code> object.
+ *
+ * @param c     is the code point whose Bidi class must be retrieved.
+ *
+ * @return The Bidi class for character <code>c</code> based
+ *         on the given <code>pBiDi</code> instance.
+ * @see UBiDiClassCallback
+ * @stable ICU 3.6
+ */
+U_STABLE UCharDirection U_EXPORT2
+ubidi_getCustomizedClass(UBiDi *pBiDi, UChar32 c);
+
+/**
+ * Set the callback function and callback data used by the UBA
+ * implementation for Bidi class determination.
+ * <p>This may be useful for assigning Bidi classes to PUA characters, or
+ * for special application needs. For instance, an application may want to
+ * handle all spaces like L or R characters (according to the base direction)
+ * when creating the visual ordering of logical lines which are part of a report
+ * organized in columns: there should not be interaction between adjacent
+ * cells.<p>
+ *
+ * @param pBiDi is the paragraph <code>UBiDi</code> object.
+ *
+ * @param newFn is the new callback function pointer.
+ *
+ * @param newContext is the new callback context pointer. This can be NULL.
+ *
+ * @param oldFn fillin: Returns the old callback function pointer. This can be
+ *                      NULL.
+ *
+ * @param oldContext fillin: Returns the old callback's context. This can be
+ *                           NULL.
+ *
+ * @param pErrorCode must be a valid pointer to an error code value.
+ *
+ * @see ubidi_getClassCallback
+ * @stable ICU 3.6
+ */
+U_STABLE void U_EXPORT2
+ubidi_setClassCallback(UBiDi *pBiDi, UBiDiClassCallback *newFn,
+                       const void *newContext, UBiDiClassCallback **oldFn,
+                       const void **oldContext, UErrorCode *pErrorCode);
+
+/**
+ * Get the current callback function used for Bidi class determination.
+ *
+ * @param pBiDi is the paragraph <code>UBiDi</code> object.
+ *
+ * @param fn fillin: Returns the callback function pointer.
+ *
+ * @param context fillin: Returns the callback's private context.
+ *
+ * @see ubidi_setClassCallback
+ * @stable ICU 3.6
+ */
+U_STABLE void U_EXPORT2
+ubidi_getClassCallback(UBiDi *pBiDi, UBiDiClassCallback **fn, const void **context);
+
+/**
+ * Take a <code>UBiDi</code> object containing the reordering
+ * information for a piece of text (one or more paragraphs) set by
+ * <code>ubidi_setPara()</code> or for a line of text set by
+ * <code>ubidi_setLine()</code> and write a reordered string to the
+ * destination buffer.
+ *
+ * This function preserves the integrity of characters with multiple
+ * code units and (optionally) combining characters.
+ * Characters in RTL runs can be replaced by mirror-image characters
+ * in the destination buffer. Note that "real" mirroring has
+ * to be done in a rendering engine by glyph selection
+ * and that for many "mirrored" characters there are no
+ * Unicode characters as mirror-image equivalents.
+ * There are also options to insert or remove Bidi control
+ * characters; see the description of the <code>destSize</code>
+ * and <code>options</code> parameters and of the option bit flags.
+ *
+ * @param pBiDi A pointer to a <code>UBiDi</code> object that
+ *              is set by <code>ubidi_setPara()</code> or
+ *              <code>ubidi_setLine()</code> and contains the reordering
+ *              information for the text that it was defined for,
+ *              as well as a pointer to that text.<br><br>
+ *              The text was aliased (only the pointer was stored
+ *              without copying the contents) and must not have been modified
+ *              since the <code>ubidi_setPara()</code> call.
+ *
+ * @param dest A pointer to where the reordered text is to be copied.
+ *             The source text and <code>dest[destSize]</code>
+ *             must not overlap.
+ *
+ * @param destSize The size of the <code>dest</code> buffer,
+ *                 in number of UChars.
+ *                 If the <code>UBIDI_INSERT_LRM_FOR_NUMERIC</code>
+ *                 option is set, then the destination length could be
+ *                 as large as
+ *                 <code>ubidi_getLength(pBiDi)+2*ubidi_countRuns(pBiDi)</code>.
+ *                 If the <code>UBIDI_REMOVE_BIDI_CONTROLS</code> option
+ *                 is set, then the destination length may be less than
+ *                 <code>ubidi_getLength(pBiDi)</code>.
+ *                 If none of these options is set, then the destination length
+ *                 will be exactly <code>ubidi_getProcessedLength(pBiDi)</code>.
+ *
+ * @param options A bit set of options for the reordering that control
+ *                how the reordered text is written.
+ *                The options include mirroring the characters on a code
+ *                point basis and inserting LRM characters, which is used
+ *                especially for transforming visually stored text
+ *                to logically stored text (although this is still an
+ *                imperfect implementation of an "inverse Bidi" algorithm
+ *                because it uses the "forward Bidi" algorithm at its core).
+ *                The available options are:
+ *                <code>#UBIDI_DO_MIRRORING</code>,
+ *                <code>#UBIDI_INSERT_LRM_FOR_NUMERIC</code>,
+ *                <code>#UBIDI_KEEP_BASE_COMBINING</code>,
+ *                <code>#UBIDI_OUTPUT_REVERSE</code>,
+ *                <code>#UBIDI_REMOVE_BIDI_CONTROLS</code>
+ *
+ * @param pErrorCode must be a valid pointer to an error code value.
+ *
+ * @return The length of the output string.
+ *
+ * @see ubidi_getProcessedLength
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ubidi_writeReordered(UBiDi *pBiDi,
+                     UChar *dest, int32_t destSize,
+                     uint16_t options,
+                     UErrorCode *pErrorCode);
+
+/**
+ * Reverse a Right-To-Left run of Unicode text.
+ *
+ * This function preserves the integrity of characters with multiple
+ * code units and (optionally) combining characters.
+ * Characters can be replaced by mirror-image characters
+ * in the destination buffer. Note that "real" mirroring has
+ * to be done in a rendering engine by glyph selection
+ * and that for many "mirrored" characters there are no
+ * Unicode characters as mirror-image equivalents.
+ * There are also options to insert or remove Bidi control
+ * characters.
+ *
+ * This function is the implementation for reversing RTL runs as part
+ * of <code>ubidi_writeReordered()</code>. For detailed descriptions
+ * of the parameters, see there.
+ * Since no Bidi controls are inserted here, the output string length
+ * will never exceed <code>srcLength</code>.
+ *
+ * @see ubidi_writeReordered
+ *
+ * @param src A pointer to the RTL run text.
+ *
+ * @param srcLength The length of the RTL run.
+ *
+ * @param dest A pointer to where the reordered text is to be copied.
+ *             <code>src[srcLength]</code> and <code>dest[destSize]</code>
+ *             must not overlap.
+ *
+ * @param destSize The size of the <code>dest</code> buffer,
+ *                 in number of UChars.
+ *                 If the <code>UBIDI_REMOVE_BIDI_CONTROLS</code> option
+ *                 is set, then the destination length may be less than
+ *                 <code>srcLength</code>.
+ *                 If this option is not set, then the destination length
+ *                 will be exactly <code>srcLength</code>.
+ *
+ * @param options A bit set of options for the reordering that control
+ *                how the reordered text is written.
+ *                See the <code>options</code> parameter in <code>ubidi_writeReordered()</code>.
+ *
+ * @param pErrorCode must be a valid pointer to an error code value.
+ *
+ * @return The length of the output string.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ubidi_writeReverse(const UChar *src, int32_t srcLength,
+                   UChar *dest, int32_t destSize,
+                   uint16_t options,
+                   UErrorCode *pErrorCode);
+
+/*#define BIDI_SAMPLE_CODE*/
+/*@}*/
+
+#endif
diff --git a/source/common/unicode/ubrk.h b/source/common/unicode/ubrk.h
new file mode 100644
index 0000000..f8304a6
--- /dev/null
+++ b/source/common/unicode/ubrk.h
@@ -0,0 +1,501 @@
+/*
+******************************************************************************
+* Copyright (C) 1996-2010, International Business Machines Corporation and others.
+* All Rights Reserved.
+******************************************************************************
+*/
+
+#ifndef UBRK_H
+#define UBRK_H
+
+#include "unicode/utypes.h"
+#include "unicode/uloc.h"
+#include "unicode/utext.h"
+#include "unicode/localpointer.h"
+
+/**
+ * A text-break iterator.
+ *  For usage in C programs.
+ */
+#ifndef UBRK_TYPEDEF_UBREAK_ITERATOR
+#   define UBRK_TYPEDEF_UBREAK_ITERATOR
+    /**
+     *  Opaque type representing an ICU Break iterator object.
+     *  @stable ICU 2.0
+     */
+    typedef struct UBreakIterator UBreakIterator;
+#endif
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/parseerr.h"
+
+/**
+ * \file
+ * \brief C API: BreakIterator
+ *
+ * <h2> BreakIterator C API </h2>
+ *
+ * The BreakIterator C API defines  methods for finding the location
+ * of boundaries in text. Pointer to a UBreakIterator maintain a
+ * current position and scan over text returning the index of characters
+ * where boundaries occur.
+ * <p>
+ * Line boundary analysis determines where a text string can be broken
+ * when line-wrapping. The mechanism correctly handles punctuation and
+ * hyphenated words.
+ * <p>
+ * Sentence boundary analysis allows selection with correct
+ * interpretation of periods within numbers and abbreviations, and
+ * trailing punctuation marks such as quotation marks and parentheses.
+ * <p>
+ * Word boundary analysis is used by search and replace functions, as
+ * well as within text editing applications that allow the user to
+ * select words with a double click. Word selection provides correct
+ * interpretation of punctuation marks within and following
+ * words. Characters that are not part of a word, such as symbols or
+ * punctuation marks, have word-breaks on both sides.
+ * <p>
+ * Character boundary analysis identifies the boundaries of
+ * "Extended Grapheme Clusters", which are groupings of codepoints
+ * that should be treated as character-like units for many text operations.
+ * Please see Unicode Standard Annex #29, Unicode Text Segmentation,
+ * http://www.unicode.org/reports/tr29/ for additional information 
+ * on grapheme clusters and guidelines on their use.
+ * <p>
+ * Title boundary analysis locates all positions,
+ * typically starts of words, that should be set to Title Case
+ * when title casing the text.
+ * <p>
+ * The text boundary positions are found according to the rules
+ * described in Unicode Standard Annex #29, Text Boundaries, and
+ * Unicode Standard Annex #14, Line Breaking Properties.  These
+ * are available at http://www.unicode.org/reports/tr14/ and
+ * http://www.unicode.org/reports/tr29/.
+ * <p>
+ * In addition to the plain C API defined in this header file, an
+ * object oriented C++ API with equivalent functionality is defined in the
+ * file brkiter.h.
+ * <p>
+ * Code snippets illustrating the use of the Break Iterator APIs
+ * are available in the ICU User Guide,
+ * http://icu-project.org/userguide/boundaryAnalysis.html
+ * and in the sample program icu/source/samples/break/break.cpp
+ */
+
+/** The possible types of text boundaries.  @stable ICU 2.0 */
+typedef enum UBreakIteratorType {
+  /** Character breaks  @stable ICU 2.0 */
+  UBRK_CHARACTER = 0,
+  /** Word breaks @stable ICU 2.0 */
+  UBRK_WORD = 1,
+  /** Line breaks @stable ICU 2.0 */
+  UBRK_LINE = 2,
+  /** Sentence breaks @stable ICU 2.0 */
+  UBRK_SENTENCE = 3,
+
+#ifndef U_HIDE_DEPRECATED_API
+  /**
+   * Title Case breaks
+   * The iterator created using this type locates title boundaries as described for
+   * Unicode 3.2 only. For Unicode 4.0 and above title boundary iteration,
+   * please use Word Boundary iterator.
+   *
+   * @deprecated ICU 2.8 Use the word break iterator for titlecasing for Unicode 4 and later.
+   */
+  UBRK_TITLE = 4,
+#endif /* U_HIDE_DEPRECATED_API */
+  UBRK_COUNT = 5
+} UBreakIteratorType;
+
+/** Value indicating all text boundaries have been returned.
+ *  @stable ICU 2.0
+ */
+#define UBRK_DONE ((int32_t) -1)
+
+
+/**
+ *  Enum constants for the word break tags returned by
+ *  getRuleStatus().  A range of values is defined for each category of
+ *  word, to allow for further subdivisions of a category in future releases.
+ *  Applications should check for tag values falling within the range, rather
+ *  than for single individual values.
+ *  @stable ICU 2.2
+*/
+typedef enum UWordBreak {
+    /** Tag value for "words" that do not fit into any of other categories.
+     *  Includes spaces and most punctuation. */
+    UBRK_WORD_NONE           = 0,
+    /** Upper bound for tags for uncategorized words. */
+    UBRK_WORD_NONE_LIMIT     = 100,
+    /** Tag value for words that appear to be numbers, lower limit.    */
+    UBRK_WORD_NUMBER         = 100,
+    /** Tag value for words that appear to be numbers, upper limit.    */
+    UBRK_WORD_NUMBER_LIMIT   = 200,
+    /** Tag value for words that contain letters, excluding
+     *  hiragana, katakana or ideographic characters, lower limit.    */
+    UBRK_WORD_LETTER         = 200,
+    /** Tag value for words containing letters, upper limit  */
+    UBRK_WORD_LETTER_LIMIT   = 300,
+    /** Tag value for words containing kana characters, lower limit */
+    UBRK_WORD_KANA           = 300,
+    /** Tag value for words containing kana characters, upper limit */
+    UBRK_WORD_KANA_LIMIT     = 400,
+    /** Tag value for words containing ideographic characters, lower limit */
+    UBRK_WORD_IDEO           = 400,
+    /** Tag value for words containing ideographic characters, upper limit */
+    UBRK_WORD_IDEO_LIMIT     = 500
+} UWordBreak;
+
+/**
+ *  Enum constants for the line break tags returned by getRuleStatus().
+ *  A range of values is defined for each category of
+ *  word, to allow for further subdivisions of a category in future releases.
+ *  Applications should check for tag values falling within the range, rather
+ *  than for single individual values.
+ *  @stable ICU 2.8
+*/
+typedef enum ULineBreakTag {
+    /** Tag value for soft line breaks, positions at which a line break
+      *  is acceptable but not required                */
+    UBRK_LINE_SOFT            = 0,
+    /** Upper bound for soft line breaks.              */
+    UBRK_LINE_SOFT_LIMIT      = 100,
+    /** Tag value for a hard, or mandatory line break  */
+    UBRK_LINE_HARD            = 100,
+    /** Upper bound for hard line breaks.              */
+    UBRK_LINE_HARD_LIMIT      = 200
+} ULineBreakTag;
+
+
+
+/**
+ *  Enum constants for the sentence break tags returned by getRuleStatus().
+ *  A range of values is defined for each category of
+ *  sentence, to allow for further subdivisions of a category in future releases.
+ *  Applications should check for tag values falling within the range, rather
+ *  than for single individual values.
+ *  @stable ICU 2.8
+*/
+typedef enum USentenceBreakTag {
+    /** Tag value for for sentences  ending with a sentence terminator
+      * ('.', '?', '!', etc.) character, possibly followed by a
+      * hard separator (CR, LF, PS, etc.)
+      */
+    UBRK_SENTENCE_TERM       = 0,
+    /** Upper bound for tags for sentences ended by sentence terminators.    */
+    UBRK_SENTENCE_TERM_LIMIT = 100,
+    /** Tag value for for sentences that do not contain an ending
+      * sentence terminator ('.', '?', '!', etc.) character, but
+      * are ended only by a hard separator (CR, LF, PS, etc.) or end of input.
+      */
+    UBRK_SENTENCE_SEP        = 100,
+    /** Upper bound for tags for sentences ended by a separator.              */
+    UBRK_SENTENCE_SEP_LIMIT  = 200
+    /** Tag value for a hard, or mandatory line break  */
+} USentenceBreakTag;
+
+
+/**
+ * Open a new UBreakIterator for locating text boundaries for a specified locale.
+ * A UBreakIterator may be used for detecting character, line, word,
+ * and sentence breaks in text.
+ * @param type The type of UBreakIterator to open: one of UBRK_CHARACTER, UBRK_WORD,
+ * UBRK_LINE, UBRK_SENTENCE
+ * @param locale The locale specifying the text-breaking conventions.
+ * @param text The text to be iterated over.
+ * @param textLength The number of characters in text, or -1 if null-terminated.
+ * @param status A UErrorCode to receive any errors.
+ * @return A UBreakIterator for the specified locale.
+ * @see ubrk_openRules
+ * @stable ICU 2.0
+ */
+U_STABLE UBreakIterator* U_EXPORT2
+ubrk_open(UBreakIteratorType type,
+      const char *locale,
+      const UChar *text,
+      int32_t textLength,
+      UErrorCode *status);
+
+/**
+ * Open a new UBreakIterator for locating text boundaries using specified breaking rules.
+ * The rule syntax is ... (TBD)
+ * @param rules A set of rules specifying the text breaking conventions.
+ * @param rulesLength The number of characters in rules, or -1 if null-terminated.
+ * @param text The text to be iterated over.  May be null, in which case ubrk_setText() is
+ *        used to specify the text to be iterated.
+ * @param textLength The number of characters in text, or -1 if null-terminated.
+ * @param parseErr   Receives position and context information for any syntax errors
+ *                   detected while parsing the rules.
+ * @param status A UErrorCode to receive any errors.
+ * @return A UBreakIterator for the specified rules.
+ * @see ubrk_open
+ * @stable ICU 2.2
+ */
+U_STABLE UBreakIterator* U_EXPORT2
+ubrk_openRules(const UChar     *rules,
+               int32_t         rulesLength,
+               const UChar     *text,
+               int32_t          textLength,
+               UParseError     *parseErr,
+               UErrorCode      *status);
+
+/**
+ * Thread safe cloning operation
+ * @param bi iterator 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_BRK_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
+ * @stable ICU 2.0
+ */
+U_STABLE UBreakIterator * U_EXPORT2
+ubrk_safeClone(
+          const UBreakIterator *bi,
+          void *stackBuffer,
+          int32_t *pBufferSize,
+          UErrorCode *status);
+
+/**
+  * A recommended size (in bytes) for the memory buffer to be passed to ubrk_saveClone().
+  * @stable ICU 2.0
+  */
+#define U_BRK_SAFECLONE_BUFFERSIZE 512
+
+/**
+* Close a UBreakIterator.
+* Once closed, a UBreakIterator may no longer be used.
+* @param bi The break iterator to close.
+ * @stable ICU 2.0
+*/
+U_STABLE void U_EXPORT2
+ubrk_close(UBreakIterator *bi);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUBreakIteratorPointer
+ * "Smart pointer" class, closes a UBreakIterator via ubrk_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUBreakIteratorPointer, UBreakIterator, ubrk_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Sets an existing iterator to point to a new piece of text
+ * @param bi The iterator to use
+ * @param text The text to be set
+ * @param textLength The length of the text
+ * @param status The error code
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ubrk_setText(UBreakIterator* bi,
+             const UChar*    text,
+             int32_t         textLength,
+             UErrorCode*     status);
+
+
+/**
+ * Sets an existing iterator to point to a new piece of text
+ * @param bi The iterator to use
+ * @param text The text to be set.
+ *             This function makes a shallow clone of the supplied UText.  This means
+ *             that the caller is free to immediately close or otherwise reuse the
+ *             UText that was passed as a parameter, but that the underlying text itself
+ *             must not be altered while being referenced by the break iterator.
+ * @param status The error code
+ * @stable ICU 3.4
+ */
+U_STABLE void U_EXPORT2
+ubrk_setUText(UBreakIterator* bi,
+             UText*          text,
+             UErrorCode*     status);
+
+
+
+/**
+ * Determine the most recently-returned text boundary.
+ *
+ * @param bi The break iterator to use.
+ * @return The character index most recently returned by \ref ubrk_next, \ref ubrk_previous,
+ * \ref ubrk_first, or \ref ubrk_last.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ubrk_current(const UBreakIterator *bi);
+
+/**
+ * Determine the text boundary following the current text boundary.
+ *
+ * @param bi The break iterator to use.
+ * @return The character index of the next text boundary, or UBRK_DONE
+ * if all text boundaries have been returned.
+ * @see ubrk_previous
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ubrk_next(UBreakIterator *bi);
+
+/**
+ * Determine the text boundary preceding the current text boundary.
+ *
+ * @param bi The break iterator to use.
+ * @return The character index of the preceding text boundary, or UBRK_DONE
+ * if all text boundaries have been returned.
+ * @see ubrk_next
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ubrk_previous(UBreakIterator *bi);
+
+/**
+ * Determine the index of the first character in the text being scanned.
+ * This is not always the same as index 0 of the text.
+ * @param bi The break iterator to use.
+ * @return The character index of the first character in the text being scanned.
+ * @see ubrk_last
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ubrk_first(UBreakIterator *bi);
+
+/**
+ * Determine the index immediately <EM>beyond</EM> the last character in the text being
+ * scanned.
+ * This is not the same as the last character.
+ * @param bi The break iterator to use.
+ * @return The character offset immediately <EM>beyond</EM> the last character in the
+ * text being scanned.
+ * @see ubrk_first
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ubrk_last(UBreakIterator *bi);
+
+/**
+ * Determine the text boundary preceding the specified offset.
+ * The value returned is always smaller than offset, or UBRK_DONE.
+ * @param bi The break iterator to use.
+ * @param offset The offset to begin scanning.
+ * @return The text boundary preceding offset, or UBRK_DONE.
+ * @see ubrk_following
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ubrk_preceding(UBreakIterator *bi,
+           int32_t offset);
+
+/**
+ * Determine the text boundary following the specified offset.
+ * The value returned is always greater than offset, or UBRK_DONE.
+ * @param bi The break iterator to use.
+ * @param offset The offset to begin scanning.
+ * @return The text boundary following offset, or UBRK_DONE.
+ * @see ubrk_preceding
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ubrk_following(UBreakIterator *bi,
+           int32_t offset);
+
+/**
+* Get a locale for which text breaking information is available.
+* A UBreakIterator in a locale returned by this function will perform the correct
+* text breaking for the locale.
+* @param index The index of the desired locale.
+* @return A locale for which number text breaking information is available, or 0 if none.
+* @see ubrk_countAvailable
+* @stable ICU 2.0
+*/
+U_STABLE const char* U_EXPORT2
+ubrk_getAvailable(int32_t index);
+
+/**
+* Determine how many locales have text breaking information available.
+* This function is most useful as determining the loop ending condition for
+* calls to \ref ubrk_getAvailable.
+* @return The number of locales for which text breaking information is available.
+* @see ubrk_getAvailable
+* @stable ICU 2.0
+*/
+U_STABLE int32_t U_EXPORT2
+ubrk_countAvailable(void);
+
+
+/**
+* Returns true if the specfied position is a boundary position.  As a side
+* effect, leaves the iterator pointing to the first boundary position at
+* or after "offset".
+* @param bi The break iterator to use.
+* @param offset the offset to check.
+* @return True if "offset" is a boundary position.
+* @stable ICU 2.0
+*/
+U_STABLE  UBool U_EXPORT2
+ubrk_isBoundary(UBreakIterator *bi, int32_t offset);
+
+/**
+ * Return the status from the break rule that determined the most recently
+ * returned break position.  The values appear in the rule source
+ * within brackets, {123}, for example.  For rules that do not specify a
+ * status, a default value of 0 is returned.
+ * <p>
+ * For word break iterators, the possible values are defined in enum UWordBreak.
+ * @stable ICU 2.2
+ */
+U_STABLE  int32_t U_EXPORT2
+ubrk_getRuleStatus(UBreakIterator *bi);
+
+/**
+ * Get the statuses from the break rules that determined the most recently
+ * returned break position.  The values appear in the rule source
+ * within brackets, {123}, for example.  The default status value for rules
+ * that do not explicitly provide one is zero.
+ * <p>
+ * For word break iterators, the possible values are defined in enum UWordBreak.
+ * @param bi        The break iterator to use
+ * @param fillInVec an array to be filled in with the status values.
+ * @param capacity  the length of the supplied vector.  A length of zero causes
+ *                  the function to return the number of status values, in the
+ *                  normal way, without attemtping to store any values.
+ * @param status    receives error codes.
+ * @return          The number of rule status values from rules that determined
+ *                  the most recent boundary returned by the break iterator.
+ * @stable ICU 3.0
+ */
+U_STABLE  int32_t U_EXPORT2
+ubrk_getRuleStatusVec(UBreakIterator *bi, int32_t *fillInVec, int32_t capacity, UErrorCode *status);
+
+/**
+ * Return the locale of the break iterator. You can choose between the valid and
+ * the actual locale.
+ * @param bi break iterator
+ * @param type locale type (valid or actual)
+ * @param status error code
+ * @return locale string
+ * @stable ICU 2.8
+ */
+U_STABLE const char* U_EXPORT2
+ubrk_getLocaleByType(const UBreakIterator *bi, ULocDataLocaleType type, UErrorCode* status);
+
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
+
+#endif
diff --git a/source/common/unicode/ucasemap.h b/source/common/unicode/ucasemap.h
new file mode 100644
index 0000000..483f84f
--- /dev/null
+++ b/source/common/unicode/ucasemap.h
@@ -0,0 +1,421 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2005-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  ucasemap.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2005may06
+*   created by: Markus W. Scherer
+*
+*   Case mapping service object and functions using it.
+*/
+
+#ifndef __UCASEMAP_H__
+#define __UCASEMAP_H__
+
+#include "unicode/utypes.h"
+#include "unicode/ustring.h"
+#include "unicode/localpointer.h"
+
+/**
+ * \file
+ * \brief C API: Unicode case mapping functions using a UCaseMap service object.
+ *
+ * The service object takes care of memory allocations, data loading, and setup
+ * for the attributes, as usual.
+ *
+ * Currently, the functionality provided here does not overlap with uchar.h
+ * and ustring.h, except for ucasemap_toTitle().
+ *
+ * ucasemap_utf8XYZ() functions operate directly on UTF-8 strings.
+ */
+
+/**
+ * UCaseMap is an opaque service object for newer ICU case mapping functions.
+ * Older functions did not use a service object.
+ * @stable ICU 3.4
+ */
+struct UCaseMap;
+typedef struct UCaseMap UCaseMap; /**< C typedef for struct UCaseMap. @stable ICU 3.4 */
+
+/**
+ * Open a UCaseMap service object for a locale and a set of options.
+ * The locale ID and options are preprocessed so that functions using the
+ * service object need not process them in each call.
+ *
+ * @param locale ICU locale ID, used for language-dependent
+ *               upper-/lower-/title-casing according to the Unicode standard.
+ *               Usual semantics: ""=root, NULL=default locale, etc.
+ * @param options Options bit set, used for case folding and string comparisons.
+ *                Same flags as for u_foldCase(), u_strFoldCase(),
+ *                u_strCaseCompare(), etc.
+ *                Use 0 or U_FOLD_CASE_DEFAULT for default behavior.
+ * @param pErrorCode Must be a valid pointer to an error code value,
+ *                   which must not indicate a failure before the function call.
+ * @return Pointer to a UCaseMap service object, if successful.
+ *
+ * @see U_FOLD_CASE_DEFAULT
+ * @see U_FOLD_CASE_EXCLUDE_SPECIAL_I
+ * @see U_TITLECASE_NO_LOWERCASE
+ * @see U_TITLECASE_NO_BREAK_ADJUSTMENT
+ * @stable ICU 3.4
+ */
+U_STABLE UCaseMap * U_EXPORT2
+ucasemap_open(const char *locale, uint32_t options, UErrorCode *pErrorCode);
+
+/**
+ * Close a UCaseMap service object.
+ * @param csm Object to be closed.
+ * @stable ICU 3.4
+ */
+U_STABLE void U_EXPORT2
+ucasemap_close(UCaseMap *csm);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUCaseMapPointer
+ * "Smart pointer" class, closes a UCaseMap via ucasemap_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUCaseMapPointer, UCaseMap, ucasemap_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Get the locale ID that is used for language-dependent case mappings.
+ * @param csm UCaseMap service object.
+ * @return locale ID
+ * @stable ICU 3.4
+ */
+U_STABLE const char * U_EXPORT2
+ucasemap_getLocale(const UCaseMap *csm);
+
+/**
+ * Get the options bit set that is used for case folding and string comparisons.
+ * @param csm UCaseMap service object.
+ * @return options bit set
+ * @stable ICU 3.4
+ */
+U_STABLE uint32_t U_EXPORT2
+ucasemap_getOptions(const UCaseMap *csm);
+
+/**
+ * Set the locale ID that is used for language-dependent case mappings.
+ *
+ * @param csm UCaseMap service object.
+ * @param locale Locale ID, see ucasemap_open().
+ * @param pErrorCode Must be a valid pointer to an error code value,
+ *                   which must not indicate a failure before the function call.
+ *
+ * @see ucasemap_open
+ * @stable ICU 3.4
+ */
+U_STABLE void U_EXPORT2
+ucasemap_setLocale(UCaseMap *csm, const char *locale, UErrorCode *pErrorCode);
+
+/**
+ * Set the options bit set that is used for case folding and string comparisons.
+ *
+ * @param csm UCaseMap service object.
+ * @param options Options bit set, see ucasemap_open().
+ * @param pErrorCode Must be a valid pointer to an error code value,
+ *                   which must not indicate a failure before the function call.
+ *
+ * @see ucasemap_open
+ * @stable ICU 3.4
+ */
+U_STABLE void U_EXPORT2
+ucasemap_setOptions(UCaseMap *csm, uint32_t options, UErrorCode *pErrorCode);
+
+/**
+ * Do not lowercase non-initial parts of words when titlecasing.
+ * Option bit for titlecasing APIs that take an options bit set.
+ *
+ * By default, titlecasing will titlecase the first cased character
+ * of a word and lowercase all other characters.
+ * With this option, the other characters will not be modified.
+ *
+ * @see ucasemap_setOptions
+ * @see ucasemap_toTitle
+ * @see ucasemap_utf8ToTitle
+ * @see UnicodeString::toTitle
+ * @stable ICU 3.8
+ */
+#define U_TITLECASE_NO_LOWERCASE 0x100
+
+/**
+ * Do not adjust the titlecasing indexes from BreakIterator::next() indexes;
+ * titlecase exactly the characters at breaks from the iterator.
+ * Option bit for titlecasing APIs that take an options bit set.
+ *
+ * By default, titlecasing will take each break iterator index,
+ * adjust it by looking for the next cased character, and titlecase that one.
+ * Other characters are lowercased.
+ *
+ * This follows Unicode 4 & 5 section 3.13 Default Case Operations:
+ *
+ * R3  toTitlecase(X): Find the word boundaries based on Unicode Standard Annex
+ * #29, "Text Boundaries." Between each pair of word boundaries, find the first
+ * cased character F. If F exists, map F to default_title(F); then map each
+ * subsequent character C to default_lower(C).
+ *
+ * @see ucasemap_setOptions
+ * @see ucasemap_toTitle
+ * @see ucasemap_utf8ToTitle
+ * @see UnicodeString::toTitle
+ * @see U_TITLECASE_NO_LOWERCASE
+ * @stable ICU 3.8
+ */
+#define U_TITLECASE_NO_BREAK_ADJUSTMENT 0x200
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+/**
+ * Get the break iterator that is used for titlecasing.
+ * Do not modify the returned break iterator.
+ * @param csm UCaseMap service object.
+ * @return titlecasing break iterator
+ * @stable ICU 3.8
+ */
+U_STABLE const UBreakIterator * U_EXPORT2
+ucasemap_getBreakIterator(const UCaseMap *csm);
+
+/**
+ * Set the break iterator that is used for titlecasing.
+ * The UCaseMap service object releases a previously set break iterator
+ * and "adopts" this new one, taking ownership of it.
+ * It will be released in a subsequent call to ucasemap_setBreakIterator()
+ * or ucasemap_close().
+ *
+ * Break iterator operations are not thread-safe. Therefore, titlecasing
+ * functions use non-const UCaseMap objects. It is not possible to titlecase
+ * strings concurrently using the same UCaseMap.
+ *
+ * @param csm UCaseMap service object.
+ * @param iterToAdopt Break iterator to be adopted for titlecasing.
+ * @param pErrorCode Must be a valid pointer to an error code value,
+ *                   which must not indicate a failure before the function call.
+ *
+ * @see ucasemap_toTitle
+ * @see ucasemap_utf8ToTitle
+ * @stable ICU 3.8
+ */
+U_STABLE void U_EXPORT2
+ucasemap_setBreakIterator(UCaseMap *csm, UBreakIterator *iterToAdopt, UErrorCode *pErrorCode);
+
+/**
+ * Titlecase a UTF-16 string. This function is almost a duplicate of u_strToTitle(),
+ * except that it takes ucasemap_setOptions() into account and has performance
+ * advantages from being able to use a UCaseMap object for multiple case mapping
+ * operations, saving setup time.
+ *
+ * Casing is locale-dependent and context-sensitive.
+ * Titlecasing uses a break iterator to find the first characters of words
+ * that are to be titlecased. It titlecases those characters and lowercases
+ * all others. (This can be modified with ucasemap_setOptions().)
+ *
+ * Note: This function takes a non-const UCaseMap pointer because it will
+ * open a default break iterator if no break iterator was set yet,
+ * and effectively call ucasemap_setBreakIterator();
+ * also because the break iterator is stateful and will be modified during
+ * the iteration.
+ *
+ * The titlecase break iterator can be provided to customize for arbitrary
+ * styles, using rules and dictionaries beyond the standard iterators.
+ * The standard titlecase iterator for the root locale implements the
+ * algorithm of Unicode TR 21.
+ *
+ * This function uses only the setUText(), first(), next() and close() methods of the
+ * provided break iterator.
+ *
+ * The result may be longer or shorter than the original.
+ * The source string and the destination buffer must not overlap.
+ *
+ * @param csm       UCaseMap service object. This pointer is non-const!
+ *                  See the note above for details.
+ * @param dest      A buffer for the result string. The result will be NUL-terminated if
+ *                  the buffer is large enough.
+ *                  The contents is undefined in case of failure.
+ * @param destCapacity The size of the buffer (number of bytes). 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.
+ * @param src       The original string.
+ * @param srcLength The length of the original string. If -1, then src must be NUL-terminated.
+ * @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 result string, if successful - or in case of a buffer overflow,
+ *         in which case it will be greater than destCapacity.
+ *
+ * @see u_strToTitle
+ * @stable ICU 3.8
+ */
+U_STABLE int32_t U_EXPORT2
+ucasemap_toTitle(UCaseMap *csm,
+                 UChar *dest, int32_t destCapacity,
+                 const UChar *src, int32_t srcLength,
+                 UErrorCode *pErrorCode);
+
+#endif
+
+/**
+ * Lowercase the characters in a UTF-8 string.
+ * Casing is locale-dependent and context-sensitive.
+ * The result may be longer or shorter than the original.
+ * The source string and the destination buffer must not overlap.
+ *
+ * @param csm       UCaseMap service object.
+ * @param dest      A buffer for the result string. The result will be NUL-terminated if
+ *                  the buffer is large enough.
+ *                  The contents is undefined in case of failure.
+ * @param destCapacity The size of the buffer (number of bytes). 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.
+ * @param src       The original string.
+ * @param srcLength The length of the original string. If -1, then src must be NUL-terminated.
+ * @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 result string, if successful - or in case of a buffer overflow,
+ *         in which case it will be greater than destCapacity.
+ *
+ * @see u_strToLower
+ * @stable ICU 3.4
+ */
+U_STABLE int32_t U_EXPORT2
+ucasemap_utf8ToLower(const UCaseMap *csm,
+                     char *dest, int32_t destCapacity,
+                     const char *src, int32_t srcLength,
+                     UErrorCode *pErrorCode);
+
+/**
+ * Uppercase the characters in a UTF-8 string.
+ * Casing is locale-dependent and context-sensitive.
+ * The result may be longer or shorter than the original.
+ * The source string and the destination buffer must not overlap.
+ *
+ * @param csm       UCaseMap service object.
+ * @param dest      A buffer for the result string. The result will be NUL-terminated if
+ *                  the buffer is large enough.
+ *                  The contents is undefined in case of failure.
+ * @param destCapacity The size of the buffer (number of bytes). 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.
+ * @param src       The original string.
+ * @param srcLength The length of the original string. If -1, then src must be NUL-terminated.
+ * @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 result string, if successful - or in case of a buffer overflow,
+ *         in which case it will be greater than destCapacity.
+ *
+ * @see u_strToUpper
+ * @stable ICU 3.4
+ */
+U_STABLE int32_t U_EXPORT2
+ucasemap_utf8ToUpper(const UCaseMap *csm,
+                     char *dest, int32_t destCapacity,
+                     const char *src, int32_t srcLength,
+                     UErrorCode *pErrorCode);
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+/**
+ * Titlecase a UTF-8 string.
+ * Casing is locale-dependent and context-sensitive.
+ * Titlecasing uses a break iterator to find the first characters of words
+ * that are to be titlecased. It titlecases those characters and lowercases
+ * all others. (This can be modified with ucasemap_setOptions().)
+ *
+ * Note: This function takes a non-const UCaseMap pointer because it will
+ * open a default break iterator if no break iterator was set yet,
+ * and effectively call ucasemap_setBreakIterator();
+ * also because the break iterator is stateful and will be modified during
+ * the iteration.
+ *
+ * The titlecase break iterator can be provided to customize for arbitrary
+ * styles, using rules and dictionaries beyond the standard iterators.
+ * The standard titlecase iterator for the root locale implements the
+ * algorithm of Unicode TR 21.
+ *
+ * This function uses only the setUText(), first(), next() and close() methods of the
+ * provided break iterator.
+ *
+ * The result may be longer or shorter than the original.
+ * The source string and the destination buffer must not overlap.
+ *
+ * @param csm       UCaseMap service object. This pointer is non-const!
+ *                  See the note above for details.
+ * @param dest      A buffer for the result string. The result will be NUL-terminated if
+ *                  the buffer is large enough.
+ *                  The contents is undefined in case of failure.
+ * @param destCapacity The size of the buffer (number of bytes). 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.
+ * @param src       The original string.
+ * @param srcLength The length of the original string. If -1, then src must be NUL-terminated.
+ * @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 result string, if successful - or in case of a buffer overflow,
+ *         in which case it will be greater than destCapacity.
+ *
+ * @see u_strToTitle
+ * @see U_TITLECASE_NO_LOWERCASE
+ * @see U_TITLECASE_NO_BREAK_ADJUSTMENT
+ * @stable ICU 3.8
+ */
+U_STABLE int32_t U_EXPORT2
+ucasemap_utf8ToTitle(UCaseMap *csm,
+                    char *dest, int32_t destCapacity,
+                    const char *src, int32_t srcLength,
+                    UErrorCode *pErrorCode);
+
+#endif
+
+/**
+ * Case-fold the characters in a UTF-8 string.
+ * Case-folding is locale-independent and not context-sensitive,
+ * but there is an option for whether to include or exclude mappings for dotted I
+ * and dotless i that are marked with 'I' in CaseFolding.txt.
+ * The result may be longer or shorter than the original.
+ * The source string and the destination buffer must not overlap.
+ *
+ * @param csm       UCaseMap service object.
+ * @param dest      A buffer for the result string. The result will be NUL-terminated if
+ *                  the buffer is large enough.
+ *                  The contents is undefined in case of failure.
+ * @param destCapacity The size of the buffer (number of bytes). 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.
+ * @param src       The original string.
+ * @param srcLength The length of the original string. If -1, then src must be NUL-terminated.
+ * @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 result string, if successful - or in case of a buffer overflow,
+ *         in which case it will be greater than destCapacity.
+ *
+ * @see u_strFoldCase
+ * @see ucasemap_setOptions
+ * @see U_FOLD_CASE_DEFAULT
+ * @see U_FOLD_CASE_EXCLUDE_SPECIAL_I
+ * @stable ICU 3.8
+ */
+U_STABLE int32_t U_EXPORT2
+ucasemap_utf8FoldCase(const UCaseMap *csm,
+                      char *dest, int32_t destCapacity,
+                      const char *src, int32_t srcLength,
+                      UErrorCode *pErrorCode);
+
+#endif
diff --git a/source/common/unicode/ucat.h b/source/common/unicode/ucat.h
new file mode 100644
index 0000000..ad9f037
--- /dev/null
+++ b/source/common/unicode/ucat.h
@@ -0,0 +1,158 @@
+/*
+**********************************************************************
+* Copyright (c) 2003-2004, International Business Machines
+* Corporation and others.  All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: March 19 2003
+* Since: ICU 2.6
+**********************************************************************
+*/
+#ifndef UCAT_H
+#define UCAT_H
+
+#include "unicode/utypes.h"
+#include "unicode/ures.h"
+
+/**
+ * \file
+ * \brief C API: Message Catalog Wrappers
+ *
+ * This C API provides look-alike functions that deliberately resemble
+ * the POSIX catopen, catclose, and catgets functions.  The underlying
+ * implementation is in terms of ICU resource bundles, rather than
+ * POSIX message catalogs.
+ *
+ * The ICU resource bundles obey standard ICU inheritance policies.
+ * To facilitate this, sets and messages are flattened into one tier.
+ * This is done by creating resource bundle keys of the form
+ * &lt;set_num&gt;%&lt;msg_num&gt; where set_num is the set number and msg_num is
+ * the message number, formatted as decimal strings.
+ *
+ * Example:  Consider a message catalog containing two sets:
+ *
+ * Set 1: Message 4  = "Good morning."
+ *        Message 5  = "Good afternoon."
+ *        Message 7  = "Good evening."
+ *        Message 8  = "Good night."
+ * Set 4: Message 14 = "Please "
+ *        Message 19 = "Thank you."
+ *        Message 20 = "Sincerely,"
+ *
+ * The ICU resource bundle source file would, assuming it is named
+ * "greet.txt", would look like this:
+ *
+ * greet
+ * {
+ *     1%4  { "Good morning." }
+ *     1%5  { "Good afternoon." }
+ *     1%7  { "Good evening." }
+ *     1%8  { "Good night." }
+ * 
+ *     4%14 { "Please " }
+ *     4%19 { "Thank you." }
+ *     4%20 { "Sincerely," }
+ * }
+ *
+ * The catgets function is commonly used in combination with functions
+ * like printf and strftime.  ICU components like message format can
+ * be used instead, although they use a different format syntax.
+ * There is an ICU package, icuio, that provides some of
+ * the POSIX-style formatting API.
+ */
+
+U_CDECL_BEGIN
+
+/**
+ * An ICU message catalog descriptor, analogous to nl_catd.
+ * 
+ * @stable ICU 2.6
+ */
+typedef UResourceBundle* u_nl_catd;
+
+/**
+ * Open and return an ICU message catalog descriptor. The descriptor
+ * may be passed to u_catgets() to retrieve localized strings.
+ *
+ * @param name string containing the full path pointing to the
+ * directory where the resources reside followed by the package name
+ * e.g. "/usr/resource/my_app/resources/guimessages" on a Unix system.
+ * If NULL, ICU default data files will be used.
+ *
+ * Unlike POSIX, environment variables are not interpolated within the
+ * name.
+ *
+ * @param locale the locale for which we want to open the resource. If
+ * NULL, the default ICU locale will be used (see uloc_getDefault). If
+ * strlen(locale) == 0, the root locale will be used.
+ *
+ * @param ec input/output error code. Upon output,
+ * U_USING_FALLBACK_WARNING indicates that a fallback locale was
+ * used. For example, 'de_CH' was requested, but nothing was found
+ * there, so 'de' was used. U_USING_DEFAULT_WARNING indicates that the
+ * default locale data or root locale data was used; neither the
+ * requested locale nor any of its fallback locales were found.
+ *
+ * @return a message catalog descriptor that may be passed to
+ * u_catgets(). If the ec parameter indicates success, then the caller
+ * is responsible for calling u_catclose() to close the message
+ * catalog. If the ec parameter indicates failure, then NULL will be
+ * returned.
+ * 
+ * @stable ICU 2.6
+ */
+U_STABLE u_nl_catd U_EXPORT2
+u_catopen(const char* name, const char* locale, UErrorCode* ec);
+
+/**
+ * Close an ICU message catalog, given its descriptor.
+ *
+ * @param catd a message catalog descriptor to be closed. May be NULL,
+ * in which case no action is taken.
+ * 
+ * @stable ICU 2.6
+ */
+U_STABLE void U_EXPORT2
+u_catclose(u_nl_catd catd);
+
+/**
+ * Retrieve a localized string from an ICU message catalog.
+ *
+ * @param catd a message catalog descriptor returned by u_catopen.
+ *
+ * @param set_num the message catalog set number. Sets need not be
+ * numbered consecutively.
+ *
+ * @param msg_num the message catalog message number within the
+ * set. Messages need not be numbered consecutively.
+ *
+ * @param s the default string. This is returned if the string
+ * specified by the set_num and msg_num is not found. It must be
+ * zero-terminated.
+ *
+ * @param len fill-in parameter to receive the length of the result.
+ * May be NULL, in which case it is ignored.
+ *
+ * @param ec input/output error code. May be U_USING_FALLBACK_WARNING
+ * or U_USING_DEFAULT_WARNING. U_MISSING_RESOURCE_ERROR indicates that
+ * the set_num/msg_num tuple does not specify a valid message string
+ * in this catalog.
+ *
+ * @return a pointer to a zero-terminated UChar array which lives in
+ * an internal buffer area, typically a memory mapped/DLL file. The
+ * caller must NOT delete this pointer. If the call is unsuccessful
+ * for any reason, then s is returned.  This includes the situation in
+ * which ec indicates a failing error code upon entry to this
+ * function.
+ * 
+ * @stable ICU 2.6
+ */
+U_STABLE const UChar* U_EXPORT2
+u_catgets(u_nl_catd catd, int32_t set_num, int32_t msg_num,
+          const UChar* s,
+          int32_t* len, UErrorCode* ec);
+
+U_CDECL_END
+
+#endif /*UCAT_H*/
+/*eof*/
diff --git a/source/common/unicode/uchar.h b/source/common/unicode/uchar.h
new file mode 100644
index 0000000..93aa663
--- /dev/null
+++ b/source/common/unicode/uchar.h
@@ -0,0 +1,3168 @@
+/*
+**********************************************************************
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*
+* File UCHAR.H
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   04/02/97    aliu        Creation.
+*   03/29/99    helena      Updated for C APIs.
+*   4/15/99     Madhu       Updated for C Implementation and Javadoc
+*   5/20/99     Madhu       Added the function u_getVersion()
+*   8/19/1999   srl         Upgraded scripts to Unicode 3.0
+*   8/27/1999   schererm    UCharDirection constants: U_...
+*   11/11/1999  weiv        added u_isalnum(), cleaned comments
+*   01/11/2000  helena      Renamed u_getVersion to u_getUnicodeVersion().
+******************************************************************************
+*/
+
+#ifndef UCHAR_H
+#define UCHAR_H
+
+#include "unicode/utypes.h"
+
+U_CDECL_BEGIN
+
+/*==========================================================================*/
+/* Unicode version number                                                   */
+/*==========================================================================*/
+/**
+ * Unicode version number, default for the current ICU version.
+ * The actual Unicode Character Database (UCD) data is stored in uprops.dat
+ * and may be generated from UCD files from a different Unicode version.
+ * Call u_getUnicodeVersion to get the actual Unicode version of the data.
+ *
+ * @see u_getUnicodeVersion
+ * @stable ICU 2.0
+ */
+#define U_UNICODE_VERSION "6.0"
+
+/**
+ * \file
+ * \brief C API: Unicode Properties
+ *
+ * This C API provides low-level access to the Unicode Character Database.
+ * In addition to raw property values, some convenience functions calculate
+ * derived properties, for example for Java-style programming.
+ *
+ * Unicode assigns each code point (not just assigned character) values for
+ * many properties.
+ * Most of them are simple boolean flags, or constants from a small enumerated list.
+ * For some properties, values are strings or other relatively more complex types.
+ *
+ * For more information see
+ * "About the Unicode Character Database" (http://www.unicode.org/ucd/)
+ * and the ICU User Guide chapter on Properties (http://icu-project.org/userguide/properties.html).
+ *
+ * Many functions are designed to match java.lang.Character functions.
+ * See the individual function documentation,
+ * and see the JDK 1.4 java.lang.Character documentation
+ * at http://java.sun.com/j2se/1.4/docs/api/java/lang/Character.html
+ *
+ * There are also functions that provide easy migration from C/POSIX functions
+ * like isblank(). Their use is generally discouraged because the C/POSIX
+ * standards do not define their semantics beyond the ASCII range, which means
+ * that different implementations exhibit very different behavior.
+ * Instead, Unicode properties should be used directly.
+ *
+ * There are also only a few, broad C/POSIX character classes, and they tend
+ * to be used for conflicting purposes. For example, the "isalpha()" class
+ * is sometimes used to determine word boundaries, while a more sophisticated
+ * approach would at least distinguish initial letters from continuation
+ * characters (the latter including combining marks).
+ * (In ICU, BreakIterator is the most sophisticated API for word boundaries.)
+ * Another example: There is no "istitle()" class for titlecase characters.
+ *
+ * ICU 3.4 and later provides API access for all twelve C/POSIX character classes.
+ * ICU implements them according to the Standard Recommendations in
+ * Annex C: Compatibility Properties of UTS #18 Unicode Regular Expressions
+ * (http://www.unicode.org/reports/tr18/#Compatibility_Properties).
+ *
+ * API access for C/POSIX character classes is as follows:
+ * - alpha:     u_isUAlphabetic(c) or u_hasBinaryProperty(c, UCHAR_ALPHABETIC)
+ * - lower:     u_isULowercase(c) or u_hasBinaryProperty(c, UCHAR_LOWERCASE)
+ * - upper:     u_isUUppercase(c) or u_hasBinaryProperty(c, UCHAR_UPPERCASE)
+ * - punct:     u_ispunct(c)
+ * - digit:     u_isdigit(c) or u_charType(c)==U_DECIMAL_DIGIT_NUMBER
+ * - xdigit:    u_isxdigit(c) or u_hasBinaryProperty(c, UCHAR_POSIX_XDIGIT)
+ * - alnum:     u_hasBinaryProperty(c, UCHAR_POSIX_ALNUM)
+ * - space:     u_isUWhiteSpace(c) or u_hasBinaryProperty(c, UCHAR_WHITE_SPACE)
+ * - blank:     u_isblank(c) or u_hasBinaryProperty(c, UCHAR_POSIX_BLANK)
+ * - cntrl:     u_charType(c)==U_CONTROL_CHAR
+ * - graph:     u_hasBinaryProperty(c, UCHAR_POSIX_GRAPH)
+ * - print:     u_hasBinaryProperty(c, UCHAR_POSIX_PRINT)
+ *
+ * Note: Some of the u_isxyz() functions in uchar.h predate, and do not match,
+ * the Standard Recommendations in UTS #18. Instead, they match Java
+ * functions according to their API documentation.
+ *
+ * \htmlonly
+ * The C/POSIX character classes are also available in UnicodeSet patterns,
+ * using patterns like [:graph:] or \p{graph}.
+ * \endhtmlonly
+ *
+ * Note: There are several ICU whitespace functions.
+ * Comparison:
+ * - u_isUWhiteSpace=UCHAR_WHITE_SPACE: Unicode White_Space property;
+ *       most of general categories "Z" (separators) + most whitespace ISO controls
+ *       (including no-break spaces, but excluding IS1..IS4 and ZWSP)
+ * - u_isWhitespace: Java isWhitespace; Z + whitespace ISO controls but excluding no-break spaces
+ * - u_isJavaSpaceChar: Java isSpaceChar; just Z (including no-break spaces)
+ * - u_isspace: Z + whitespace ISO controls (including no-break spaces)
+ * - u_isblank: "horizontal spaces" = TAB + Zs - ZWSP
+ */
+
+/**
+ * Constants.
+ */
+
+/** The lowest Unicode code point value. Code points are non-negative. @stable ICU 2.0 */
+#define UCHAR_MIN_VALUE 0
+
+/**
+ * The highest Unicode code point value (scalar value) according to
+ * The Unicode Standard. This is a 21-bit value (20.1 bits, rounded up).
+ * For a single character, UChar32 is a simple type that can hold any code point value.
+ *
+ * @see UChar32
+ * @stable ICU 2.0
+ */
+#define UCHAR_MAX_VALUE 0x10ffff
+
+/**
+ * Get a single-bit bit set (a flag) from a bit number 0..31.
+ * @stable ICU 2.1
+ */
+#define U_MASK(x) ((uint32_t)1<<(x))
+
+/*
+ * !! Note: Several comments in this file are machine-read by the
+ * genpname tool.  These comments describe the correspondence between
+ * icu enum constants and UCD entities.  Do not delete them.  Update
+ * these comments as needed.
+ *
+ * Any comment of the form "/ *[name]* /" (spaces added) is such
+ * a comment.
+ *
+ * The U_JG_* and U_GC_*_MASK constants are matched by their symbolic
+ * name, which must match PropertyValueAliases.txt.
+ */
+
+/**
+ * Selection constants for Unicode properties.
+ * These constants are used in functions like u_hasBinaryProperty to select
+ * one of the Unicode properties.
+ *
+ * The properties APIs are intended to reflect Unicode properties as defined
+ * in the Unicode Character Database (UCD) and Unicode Technical Reports (UTR).
+ * For details about the properties see http://www.unicode.org/ucd/ .
+ * For names of Unicode properties see the UCD file PropertyAliases.txt.
+ *
+ * Important: If ICU is built with UCD files from Unicode versions below, e.g., 3.2,
+ * then properties marked with "new in Unicode 3.2" are not or not fully available.
+ * Check u_getUnicodeVersion to be sure.
+ *
+ * @see u_hasBinaryProperty
+ * @see u_getIntPropertyValue
+ * @see u_getUnicodeVersion
+ * @stable ICU 2.1
+ */
+typedef enum UProperty {
+    /*  See note !!.  Comments of the form "Binary property Dash",
+        "Enumerated property Script", "Double property Numeric_Value",
+        and "String property Age" are read by genpname. */
+
+    /*  Note: Place UCHAR_ALPHABETIC before UCHAR_BINARY_START so that
+    debuggers display UCHAR_ALPHABETIC as the symbolic name for 0,
+    rather than UCHAR_BINARY_START.  Likewise for other *_START
+    identifiers. */
+
+    /** Binary property Alphabetic. Same as u_isUAlphabetic, different from u_isalpha.
+        Lu+Ll+Lt+Lm+Lo+Nl+Other_Alphabetic @stable ICU 2.1 */
+    UCHAR_ALPHABETIC=0,
+    /** First constant for binary Unicode properties. @stable ICU 2.1 */
+    UCHAR_BINARY_START=UCHAR_ALPHABETIC,
+    /** Binary property ASCII_Hex_Digit. 0-9 A-F a-f @stable ICU 2.1 */
+    UCHAR_ASCII_HEX_DIGIT=1,
+    /** Binary property Bidi_Control.
+        Format controls which have specific functions
+        in the Bidi Algorithm. @stable ICU 2.1 */
+    UCHAR_BIDI_CONTROL=2,
+    /** Binary property Bidi_Mirrored.
+        Characters that may change display in RTL text.
+        Same as u_isMirrored.
+        See Bidi Algorithm, UTR 9. @stable ICU 2.1 */
+    UCHAR_BIDI_MIRRORED=3,
+    /** Binary property Dash. Variations of dashes. @stable ICU 2.1 */
+    UCHAR_DASH=4,
+    /** Binary property Default_Ignorable_Code_Point (new in Unicode 3.2).
+        Ignorable in most processing.
+        <2060..206F, FFF0..FFFB, E0000..E0FFF>+Other_Default_Ignorable_Code_Point+(Cf+Cc+Cs-White_Space) @stable ICU 2.1 */
+    UCHAR_DEFAULT_IGNORABLE_CODE_POINT=5,
+    /** Binary property Deprecated (new in Unicode 3.2).
+        The usage of deprecated characters is strongly discouraged. @stable ICU 2.1 */
+    UCHAR_DEPRECATED=6,
+    /** Binary property Diacritic. Characters that linguistically modify
+        the meaning of another character to which they apply. @stable ICU 2.1 */
+    UCHAR_DIACRITIC=7,
+    /** Binary property Extender.
+        Extend the value or shape of a preceding alphabetic character,
+        e.g., length and iteration marks. @stable ICU 2.1 */
+    UCHAR_EXTENDER=8,
+    /** Binary property Full_Composition_Exclusion.
+        CompositionExclusions.txt+Singleton Decompositions+
+        Non-Starter Decompositions. @stable ICU 2.1 */
+    UCHAR_FULL_COMPOSITION_EXCLUSION=9,
+    /** Binary property Grapheme_Base (new in Unicode 3.2).
+        For programmatic determination of grapheme cluster boundaries.
+        [0..10FFFF]-Cc-Cf-Cs-Co-Cn-Zl-Zp-Grapheme_Link-Grapheme_Extend-CGJ @stable ICU 2.1 */
+    UCHAR_GRAPHEME_BASE=10,
+    /** Binary property Grapheme_Extend (new in Unicode 3.2).
+        For programmatic determination of grapheme cluster boundaries.
+        Me+Mn+Mc+Other_Grapheme_Extend-Grapheme_Link-CGJ @stable ICU 2.1 */
+    UCHAR_GRAPHEME_EXTEND=11,
+    /** Binary property Grapheme_Link (new in Unicode 3.2).
+        For programmatic determination of grapheme cluster boundaries. @stable ICU 2.1 */
+    UCHAR_GRAPHEME_LINK=12,
+    /** Binary property Hex_Digit.
+        Characters commonly used for hexadecimal numbers. @stable ICU 2.1 */
+    UCHAR_HEX_DIGIT=13,
+    /** Binary property Hyphen. Dashes used to mark connections
+        between pieces of words, plus the Katakana middle dot. @stable ICU 2.1 */
+    UCHAR_HYPHEN=14,
+    /** Binary property ID_Continue.
+        Characters that can continue an identifier.
+        DerivedCoreProperties.txt also says "NOTE: Cf characters should be filtered out."
+        ID_Start+Mn+Mc+Nd+Pc @stable ICU 2.1 */
+    UCHAR_ID_CONTINUE=15,
+    /** Binary property ID_Start.
+        Characters that can start an identifier.
+        Lu+Ll+Lt+Lm+Lo+Nl @stable ICU 2.1 */
+    UCHAR_ID_START=16,
+    /** Binary property Ideographic.
+        CJKV ideographs. @stable ICU 2.1 */
+    UCHAR_IDEOGRAPHIC=17,
+    /** Binary property IDS_Binary_Operator (new in Unicode 3.2).
+        For programmatic determination of
+        Ideographic Description Sequences. @stable ICU 2.1 */
+    UCHAR_IDS_BINARY_OPERATOR=18,
+    /** Binary property IDS_Trinary_Operator (new in Unicode 3.2).
+        For programmatic determination of
+        Ideographic Description Sequences. @stable ICU 2.1 */
+    UCHAR_IDS_TRINARY_OPERATOR=19,
+    /** Binary property Join_Control.
+        Format controls for cursive joining and ligation. @stable ICU 2.1 */
+    UCHAR_JOIN_CONTROL=20,
+    /** Binary property Logical_Order_Exception (new in Unicode 3.2).
+        Characters that do not use logical order and
+        require special handling in most processing. @stable ICU 2.1 */
+    UCHAR_LOGICAL_ORDER_EXCEPTION=21,
+    /** Binary property Lowercase. Same as u_isULowercase, different from u_islower.
+        Ll+Other_Lowercase @stable ICU 2.1 */
+    UCHAR_LOWERCASE=22,
+    /** Binary property Math. Sm+Other_Math @stable ICU 2.1 */
+    UCHAR_MATH=23,
+    /** Binary property Noncharacter_Code_Point.
+        Code points that are explicitly defined as illegal
+        for the encoding of characters. @stable ICU 2.1 */
+    UCHAR_NONCHARACTER_CODE_POINT=24,
+    /** Binary property Quotation_Mark. @stable ICU 2.1 */
+    UCHAR_QUOTATION_MARK=25,
+    /** Binary property Radical (new in Unicode 3.2).
+        For programmatic determination of
+        Ideographic Description Sequences. @stable ICU 2.1 */
+    UCHAR_RADICAL=26,
+    /** Binary property Soft_Dotted (new in Unicode 3.2).
+        Characters with a "soft dot", like i or j.
+        An accent placed on these characters causes
+        the dot to disappear. @stable ICU 2.1 */
+    UCHAR_SOFT_DOTTED=27,
+    /** Binary property Terminal_Punctuation.
+        Punctuation characters that generally mark
+        the end of textual units. @stable ICU 2.1 */
+    UCHAR_TERMINAL_PUNCTUATION=28,
+    /** Binary property Unified_Ideograph (new in Unicode 3.2).
+        For programmatic determination of
+        Ideographic Description Sequences. @stable ICU 2.1 */
+    UCHAR_UNIFIED_IDEOGRAPH=29,
+    /** Binary property Uppercase. Same as u_isUUppercase, different from u_isupper.
+        Lu+Other_Uppercase @stable ICU 2.1 */
+    UCHAR_UPPERCASE=30,
+    /** Binary property White_Space.
+        Same as u_isUWhiteSpace, different from u_isspace and u_isWhitespace.
+        Space characters+TAB+CR+LF-ZWSP-ZWNBSP @stable ICU 2.1 */
+    UCHAR_WHITE_SPACE=31,
+    /** Binary property XID_Continue.
+        ID_Continue modified to allow closure under
+        normalization forms NFKC and NFKD. @stable ICU 2.1 */
+    UCHAR_XID_CONTINUE=32,
+    /** Binary property XID_Start. ID_Start modified to allow
+        closure under normalization forms NFKC and NFKD. @stable ICU 2.1 */
+    UCHAR_XID_START=33,
+    /** Binary property Case_Sensitive. Either the source of a case
+        mapping or _in_ the target of a case mapping. Not the same as
+        the general category Cased_Letter. @stable ICU 2.6 */
+   UCHAR_CASE_SENSITIVE=34,
+    /** Binary property STerm (new in Unicode 4.0.1).
+        Sentence Terminal. Used in UAX #29: Text Boundaries
+        (http://www.unicode.org/reports/tr29/)
+        @stable ICU 3.0 */
+    UCHAR_S_TERM=35,
+    /** Binary property Variation_Selector (new in Unicode 4.0.1).
+        Indicates all those characters that qualify as Variation Selectors.
+        For details on the behavior of these characters,
+        see StandardizedVariants.html and 15.6 Variation Selectors.
+        @stable ICU 3.0 */
+    UCHAR_VARIATION_SELECTOR=36,
+    /** Binary property NFD_Inert.
+        ICU-specific property for characters that are inert under NFD,
+        i.e., they do not interact with adjacent characters.
+        See the documentation for the Normalizer2 class and the
+        Normalizer2::isInert() method.
+        @stable ICU 3.0 */
+    UCHAR_NFD_INERT=37,
+    /** Binary property NFKD_Inert.
+        ICU-specific property for characters that are inert under NFKD,
+        i.e., they do not interact with adjacent characters.
+        See the documentation for the Normalizer2 class and the
+        Normalizer2::isInert() method.
+        @stable ICU 3.0 */
+    UCHAR_NFKD_INERT=38,
+    /** Binary property NFC_Inert.
+        ICU-specific property for characters that are inert under NFC,
+        i.e., they do not interact with adjacent characters.
+        See the documentation for the Normalizer2 class and the
+        Normalizer2::isInert() method.
+        @stable ICU 3.0 */
+    UCHAR_NFC_INERT=39,
+    /** Binary property NFKC_Inert.
+        ICU-specific property for characters that are inert under NFKC,
+        i.e., they do not interact with adjacent characters.
+        See the documentation for the Normalizer2 class and the
+        Normalizer2::isInert() method.
+        @stable ICU 3.0 */
+    UCHAR_NFKC_INERT=40,
+    /** Binary Property Segment_Starter.
+        ICU-specific property for characters that are starters in terms of
+        Unicode normalization and combining character sequences.
+        They have ccc=0 and do not occur in non-initial position of the
+        canonical decomposition of any character
+        (like a-umlaut in NFD and a Jamo T in an NFD(Hangul LVT)).
+        ICU uses this property for segmenting a string for generating a set of
+        canonically equivalent strings, e.g. for canonical closure while
+        processing collation tailoring rules.
+        @stable ICU 3.0 */
+    UCHAR_SEGMENT_STARTER=41,
+    /** Binary property Pattern_Syntax (new in Unicode 4.1).
+        See UAX #31 Identifier and Pattern Syntax
+        (http://www.unicode.org/reports/tr31/)
+        @stable ICU 3.4 */
+    UCHAR_PATTERN_SYNTAX=42,
+    /** Binary property Pattern_White_Space (new in Unicode 4.1).
+        See UAX #31 Identifier and Pattern Syntax
+        (http://www.unicode.org/reports/tr31/)
+        @stable ICU 3.4 */
+    UCHAR_PATTERN_WHITE_SPACE=43,
+    /** Binary property alnum (a C/POSIX character class).
+        Implemented according to the UTS #18 Annex C Standard Recommendation.
+        See the uchar.h file documentation.
+        @stable ICU 3.4 */
+    UCHAR_POSIX_ALNUM=44,
+    /** Binary property blank (a C/POSIX character class).
+        Implemented according to the UTS #18 Annex C Standard Recommendation.
+        See the uchar.h file documentation.
+        @stable ICU 3.4 */
+    UCHAR_POSIX_BLANK=45,
+    /** Binary property graph (a C/POSIX character class).
+        Implemented according to the UTS #18 Annex C Standard Recommendation.
+        See the uchar.h file documentation.
+        @stable ICU 3.4 */
+    UCHAR_POSIX_GRAPH=46,
+    /** Binary property print (a C/POSIX character class).
+        Implemented according to the UTS #18 Annex C Standard Recommendation.
+        See the uchar.h file documentation.
+        @stable ICU 3.4 */
+    UCHAR_POSIX_PRINT=47,
+    /** Binary property xdigit (a C/POSIX character class).
+        Implemented according to the UTS #18 Annex C Standard Recommendation.
+        See the uchar.h file documentation.
+        @stable ICU 3.4 */
+    UCHAR_POSIX_XDIGIT=48,
+    /** Binary property Cased. For Lowercase, Uppercase and Titlecase characters. @stable ICU 4.4 */
+    UCHAR_CASED=49,
+    /** Binary property Case_Ignorable. Used in context-sensitive case mappings. @stable ICU 4.4 */
+    UCHAR_CASE_IGNORABLE=50,
+    /** Binary property Changes_When_Lowercased. @stable ICU 4.4 */
+    UCHAR_CHANGES_WHEN_LOWERCASED=51,
+    /** Binary property Changes_When_Uppercased. @stable ICU 4.4 */
+    UCHAR_CHANGES_WHEN_UPPERCASED=52,
+    /** Binary property Changes_When_Titlecased. @stable ICU 4.4 */
+    UCHAR_CHANGES_WHEN_TITLECASED=53,
+    /** Binary property Changes_When_Casefolded. @stable ICU 4.4 */
+    UCHAR_CHANGES_WHEN_CASEFOLDED=54,
+    /** Binary property Changes_When_Casemapped. @stable ICU 4.4 */
+    UCHAR_CHANGES_WHEN_CASEMAPPED=55,
+    /** Binary property Changes_When_NFKC_Casefolded. @stable ICU 4.4 */
+    UCHAR_CHANGES_WHEN_NFKC_CASEFOLDED=56,
+    /** One more than the last constant for binary Unicode properties. @stable ICU 2.1 */
+    UCHAR_BINARY_LIMIT=57,
+
+    /** Enumerated property Bidi_Class.
+        Same as u_charDirection, returns UCharDirection values. @stable ICU 2.2 */
+    UCHAR_BIDI_CLASS=0x1000,
+    /** First constant for enumerated/integer Unicode properties. @stable ICU 2.2 */
+    UCHAR_INT_START=UCHAR_BIDI_CLASS,
+    /** Enumerated property Block.
+        Same as ublock_getCode, returns UBlockCode values. @stable ICU 2.2 */
+    UCHAR_BLOCK=0x1001,
+    /** Enumerated property Canonical_Combining_Class.
+        Same as u_getCombiningClass, returns 8-bit numeric values. @stable ICU 2.2 */
+    UCHAR_CANONICAL_COMBINING_CLASS=0x1002,
+    /** Enumerated property Decomposition_Type.
+        Returns UDecompositionType values. @stable ICU 2.2 */
+    UCHAR_DECOMPOSITION_TYPE=0x1003,
+    /** Enumerated property East_Asian_Width.
+        See http://www.unicode.org/reports/tr11/
+        Returns UEastAsianWidth values. @stable ICU 2.2 */
+    UCHAR_EAST_ASIAN_WIDTH=0x1004,
+    /** Enumerated property General_Category.
+        Same as u_charType, returns UCharCategory values. @stable ICU 2.2 */
+    UCHAR_GENERAL_CATEGORY=0x1005,
+    /** Enumerated property Joining_Group.
+        Returns UJoiningGroup values. @stable ICU 2.2 */
+    UCHAR_JOINING_GROUP=0x1006,
+    /** Enumerated property Joining_Type.
+        Returns UJoiningType values. @stable ICU 2.2 */
+    UCHAR_JOINING_TYPE=0x1007,
+    /** Enumerated property Line_Break.
+        Returns ULineBreak values. @stable ICU 2.2 */
+    UCHAR_LINE_BREAK=0x1008,
+    /** Enumerated property Numeric_Type.
+        Returns UNumericType values. @stable ICU 2.2 */
+    UCHAR_NUMERIC_TYPE=0x1009,
+    /** Enumerated property Script.
+        Same as uscript_getScript, returns UScriptCode values. @stable ICU 2.2 */
+    UCHAR_SCRIPT=0x100A,
+    /** Enumerated property Hangul_Syllable_Type, new in Unicode 4.
+        Returns UHangulSyllableType values. @stable ICU 2.6 */
+    UCHAR_HANGUL_SYLLABLE_TYPE=0x100B,
+    /** Enumerated property NFD_Quick_Check.
+        Returns UNormalizationCheckResult values. @stable ICU 3.0 */
+    UCHAR_NFD_QUICK_CHECK=0x100C,
+    /** Enumerated property NFKD_Quick_Check.
+        Returns UNormalizationCheckResult values. @stable ICU 3.0 */
+    UCHAR_NFKD_QUICK_CHECK=0x100D,
+    /** Enumerated property NFC_Quick_Check.
+        Returns UNormalizationCheckResult values. @stable ICU 3.0 */
+    UCHAR_NFC_QUICK_CHECK=0x100E,
+    /** Enumerated property NFKC_Quick_Check.
+        Returns UNormalizationCheckResult values. @stable ICU 3.0 */
+    UCHAR_NFKC_QUICK_CHECK=0x100F,
+    /** Enumerated property Lead_Canonical_Combining_Class.
+        ICU-specific property for the ccc of the first code point
+        of the decomposition, or lccc(c)=ccc(NFD(c)[0]).
+        Useful for checking for canonically ordered text;
+        see UNORM_FCD and http://www.unicode.org/notes/tn5/#FCD .
+        Returns 8-bit numeric values like UCHAR_CANONICAL_COMBINING_CLASS. @stable ICU 3.0 */
+    UCHAR_LEAD_CANONICAL_COMBINING_CLASS=0x1010,
+    /** Enumerated property Trail_Canonical_Combining_Class.
+        ICU-specific property for the ccc of the last code point
+        of the decomposition, or tccc(c)=ccc(NFD(c)[last]).
+        Useful for checking for canonically ordered text;
+        see UNORM_FCD and http://www.unicode.org/notes/tn5/#FCD .
+        Returns 8-bit numeric values like UCHAR_CANONICAL_COMBINING_CLASS. @stable ICU 3.0 */
+    UCHAR_TRAIL_CANONICAL_COMBINING_CLASS=0x1011,
+    /** Enumerated property Grapheme_Cluster_Break (new in Unicode 4.1).
+        Used in UAX #29: Text Boundaries
+        (http://www.unicode.org/reports/tr29/)
+        Returns UGraphemeClusterBreak values. @stable ICU 3.4 */
+    UCHAR_GRAPHEME_CLUSTER_BREAK=0x1012,
+    /** Enumerated property Sentence_Break (new in Unicode 4.1).
+        Used in UAX #29: Text Boundaries
+        (http://www.unicode.org/reports/tr29/)
+        Returns USentenceBreak values. @stable ICU 3.4 */
+    UCHAR_SENTENCE_BREAK=0x1013,
+    /** Enumerated property Word_Break (new in Unicode 4.1).
+        Used in UAX #29: Text Boundaries
+        (http://www.unicode.org/reports/tr29/)
+        Returns UWordBreakValues values. @stable ICU 3.4 */
+    UCHAR_WORD_BREAK=0x1014,
+    /** One more than the last constant for enumerated/integer Unicode properties. @stable ICU 2.2 */
+    UCHAR_INT_LIMIT=0x1015,
+
+    /** Bitmask property General_Category_Mask.
+        This is the General_Category property returned as a bit mask.
+        When used in u_getIntPropertyValue(c), same as U_MASK(u_charType(c)),
+        returns bit masks for UCharCategory values where exactly one bit is set.
+        When used with u_getPropertyValueName() and u_getPropertyValueEnum(),
+        a multi-bit mask is used for sets of categories like "Letters".
+        Mask values should be cast to uint32_t.
+        @stable ICU 2.4 */
+    UCHAR_GENERAL_CATEGORY_MASK=0x2000,
+    /** First constant for bit-mask Unicode properties. @stable ICU 2.4 */
+    UCHAR_MASK_START=UCHAR_GENERAL_CATEGORY_MASK,
+    /** One more than the last constant for bit-mask Unicode properties. @stable ICU 2.4 */
+    UCHAR_MASK_LIMIT=0x2001,
+
+    /** Double property Numeric_Value.
+        Corresponds to u_getNumericValue. @stable ICU 2.4 */
+    UCHAR_NUMERIC_VALUE=0x3000,
+    /** First constant for double Unicode properties. @stable ICU 2.4 */
+    UCHAR_DOUBLE_START=UCHAR_NUMERIC_VALUE,
+    /** One more than the last constant for double Unicode properties. @stable ICU 2.4 */
+    UCHAR_DOUBLE_LIMIT=0x3001,
+
+    /** String property Age.
+        Corresponds to u_charAge. @stable ICU 2.4 */
+    UCHAR_AGE=0x4000,
+    /** First constant for string Unicode properties. @stable ICU 2.4 */
+    UCHAR_STRING_START=UCHAR_AGE,
+    /** String property Bidi_Mirroring_Glyph.
+        Corresponds to u_charMirror. @stable ICU 2.4 */
+    UCHAR_BIDI_MIRRORING_GLYPH=0x4001,
+    /** String property Case_Folding.
+        Corresponds to u_strFoldCase in ustring.h. @stable ICU 2.4 */
+    UCHAR_CASE_FOLDING=0x4002,
+    /** String property ISO_Comment.
+        Corresponds to u_getISOComment. @stable ICU 2.4 */
+    UCHAR_ISO_COMMENT=0x4003,
+    /** String property Lowercase_Mapping.
+        Corresponds to u_strToLower in ustring.h. @stable ICU 2.4 */
+    UCHAR_LOWERCASE_MAPPING=0x4004,
+    /** String property Name.
+        Corresponds to u_charName. @stable ICU 2.4 */
+    UCHAR_NAME=0x4005,
+    /** String property Simple_Case_Folding.
+        Corresponds to u_foldCase. @stable ICU 2.4 */
+    UCHAR_SIMPLE_CASE_FOLDING=0x4006,
+    /** String property Simple_Lowercase_Mapping.
+        Corresponds to u_tolower. @stable ICU 2.4 */
+    UCHAR_SIMPLE_LOWERCASE_MAPPING=0x4007,
+    /** String property Simple_Titlecase_Mapping.
+        Corresponds to u_totitle. @stable ICU 2.4 */
+    UCHAR_SIMPLE_TITLECASE_MAPPING=0x4008,
+    /** String property Simple_Uppercase_Mapping.
+        Corresponds to u_toupper. @stable ICU 2.4 */
+    UCHAR_SIMPLE_UPPERCASE_MAPPING=0x4009,
+    /** String property Titlecase_Mapping.
+        Corresponds to u_strToTitle in ustring.h. @stable ICU 2.4 */
+    UCHAR_TITLECASE_MAPPING=0x400A,
+    /** String property Unicode_1_Name.
+        Corresponds to u_charName. @stable ICU 2.4 */
+    UCHAR_UNICODE_1_NAME=0x400B,
+    /** String property Uppercase_Mapping.
+        Corresponds to u_strToUpper in ustring.h. @stable ICU 2.4 */
+    UCHAR_UPPERCASE_MAPPING=0x400C,
+    /** One more than the last constant for string Unicode properties. @stable ICU 2.4 */
+    UCHAR_STRING_LIMIT=0x400D,
+
+    /** Provisional property Script_Extensions (new in Unicode 6.0).
+        As a provisional property, it may be modified or removed
+        in future versions of the Unicode Standard, and thus in ICU.
+        Some characters are commonly used in multiple scripts.
+        For more information, see UAX #24: http://www.unicode.org/reports/tr24/.
+        Corresponds to uscript_hasScript and uscript_getScriptExtensions in uscript.h.
+        @draft ICU 4.6 */
+    UCHAR_SCRIPT_EXTENSIONS=0x7000,
+    /** First constant for Unicode properties with unusual value types. @draft ICU 4.6 */
+    UCHAR_OTHER_PROPERTY_START=UCHAR_SCRIPT_EXTENSIONS,
+    /** One more than the last constant for Unicode properties with unusual value types.
+     * @draft ICU 4.6 */
+    UCHAR_OTHER_PROPERTY_LIMIT=0x7001,
+
+    /** Represents a nonexistent or invalid property or property value. @stable ICU 2.4 */
+    UCHAR_INVALID_CODE = -1
+} UProperty;
+
+/**
+ * Data for enumerated Unicode general category types.
+ * See http://www.unicode.org/Public/UNIDATA/UnicodeData.html .
+ * @stable ICU 2.0
+ */
+typedef enum UCharCategory
+{
+    /** See note !!.  Comments of the form "Cn" are read by genpname. */
+
+    /** Non-category for unassigned and non-character code points. @stable ICU 2.0 */
+    U_UNASSIGNED              = 0,
+    /** Cn "Other, Not Assigned (no characters in [UnicodeData.txt] have this property)" (same as U_UNASSIGNED!) @stable ICU 2.0 */
+    U_GENERAL_OTHER_TYPES     = 0,
+    /** Lu @stable ICU 2.0 */
+    U_UPPERCASE_LETTER        = 1,
+    /** Ll @stable ICU 2.0 */
+    U_LOWERCASE_LETTER        = 2,
+    /** Lt @stable ICU 2.0 */
+    U_TITLECASE_LETTER        = 3,
+    /** Lm @stable ICU 2.0 */
+    U_MODIFIER_LETTER         = 4,
+    /** Lo @stable ICU 2.0 */
+    U_OTHER_LETTER            = 5,
+    /** Mn @stable ICU 2.0 */
+    U_NON_SPACING_MARK        = 6,
+    /** Me @stable ICU 2.0 */
+    U_ENCLOSING_MARK          = 7,
+    /** Mc @stable ICU 2.0 */
+    U_COMBINING_SPACING_MARK  = 8,
+    /** Nd @stable ICU 2.0 */
+    U_DECIMAL_DIGIT_NUMBER    = 9,
+    /** Nl @stable ICU 2.0 */
+    U_LETTER_NUMBER           = 10,
+    /** No @stable ICU 2.0 */
+    U_OTHER_NUMBER            = 11,
+    /** Zs @stable ICU 2.0 */
+    U_SPACE_SEPARATOR         = 12,
+    /** Zl @stable ICU 2.0 */
+    U_LINE_SEPARATOR          = 13,
+    /** Zp @stable ICU 2.0 */
+    U_PARAGRAPH_SEPARATOR     = 14,
+    /** Cc @stable ICU 2.0 */
+    U_CONTROL_CHAR            = 15,
+    /** Cf @stable ICU 2.0 */
+    U_FORMAT_CHAR             = 16,
+    /** Co @stable ICU 2.0 */
+    U_PRIVATE_USE_CHAR        = 17,
+    /** Cs @stable ICU 2.0 */
+    U_SURROGATE               = 18,
+    /** Pd @stable ICU 2.0 */
+    U_DASH_PUNCTUATION        = 19,
+    /** Ps @stable ICU 2.0 */
+    U_START_PUNCTUATION       = 20,
+    /** Pe @stable ICU 2.0 */
+    U_END_PUNCTUATION         = 21,
+    /** Pc @stable ICU 2.0 */
+    U_CONNECTOR_PUNCTUATION   = 22,
+    /** Po @stable ICU 2.0 */
+    U_OTHER_PUNCTUATION       = 23,
+    /** Sm @stable ICU 2.0 */
+    U_MATH_SYMBOL             = 24,
+    /** Sc @stable ICU 2.0 */
+    U_CURRENCY_SYMBOL         = 25,
+    /** Sk @stable ICU 2.0 */
+    U_MODIFIER_SYMBOL         = 26,
+    /** So @stable ICU 2.0 */
+    U_OTHER_SYMBOL            = 27,
+    /** Pi @stable ICU 2.0 */
+    U_INITIAL_PUNCTUATION     = 28,
+    /** Pf @stable ICU 2.0 */
+    U_FINAL_PUNCTUATION       = 29,
+    /** One higher than the last enum UCharCategory constant. @stable ICU 2.0 */
+    U_CHAR_CATEGORY_COUNT
+} UCharCategory;
+
+/**
+ * U_GC_XX_MASK constants are bit flags corresponding to Unicode
+ * general category values.
+ * For each category, the nth bit is set if the numeric value of the
+ * corresponding UCharCategory constant is n.
+ *
+ * There are also some U_GC_Y_MASK constants for groups of general categories
+ * like L for all letter categories.
+ *
+ * @see u_charType
+ * @see U_GET_GC_MASK
+ * @see UCharCategory
+ * @stable ICU 2.1
+ */
+#define U_GC_CN_MASK    U_MASK(U_GENERAL_OTHER_TYPES)
+
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_LU_MASK    U_MASK(U_UPPERCASE_LETTER)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_LL_MASK    U_MASK(U_LOWERCASE_LETTER)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_LT_MASK    U_MASK(U_TITLECASE_LETTER)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_LM_MASK    U_MASK(U_MODIFIER_LETTER)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_LO_MASK    U_MASK(U_OTHER_LETTER)
+
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_MN_MASK    U_MASK(U_NON_SPACING_MARK)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_ME_MASK    U_MASK(U_ENCLOSING_MARK)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_MC_MASK    U_MASK(U_COMBINING_SPACING_MARK)
+
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_ND_MASK    U_MASK(U_DECIMAL_DIGIT_NUMBER)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_NL_MASK    U_MASK(U_LETTER_NUMBER)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_NO_MASK    U_MASK(U_OTHER_NUMBER)
+
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_ZS_MASK    U_MASK(U_SPACE_SEPARATOR)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_ZL_MASK    U_MASK(U_LINE_SEPARATOR)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_ZP_MASK    U_MASK(U_PARAGRAPH_SEPARATOR)
+
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_CC_MASK    U_MASK(U_CONTROL_CHAR)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_CF_MASK    U_MASK(U_FORMAT_CHAR)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_CO_MASK    U_MASK(U_PRIVATE_USE_CHAR)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_CS_MASK    U_MASK(U_SURROGATE)
+
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_PD_MASK    U_MASK(U_DASH_PUNCTUATION)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_PS_MASK    U_MASK(U_START_PUNCTUATION)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_PE_MASK    U_MASK(U_END_PUNCTUATION)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_PC_MASK    U_MASK(U_CONNECTOR_PUNCTUATION)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_PO_MASK    U_MASK(U_OTHER_PUNCTUATION)
+
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_SM_MASK    U_MASK(U_MATH_SYMBOL)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_SC_MASK    U_MASK(U_CURRENCY_SYMBOL)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_SK_MASK    U_MASK(U_MODIFIER_SYMBOL)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_SO_MASK    U_MASK(U_OTHER_SYMBOL)
+
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_PI_MASK    U_MASK(U_INITIAL_PUNCTUATION)
+/** Mask constant for a UCharCategory. @stable ICU 2.1 */
+#define U_GC_PF_MASK    U_MASK(U_FINAL_PUNCTUATION)
+
+
+/** Mask constant for multiple UCharCategory bits (L Letters). @stable ICU 2.1 */
+#define U_GC_L_MASK \
+            (U_GC_LU_MASK|U_GC_LL_MASK|U_GC_LT_MASK|U_GC_LM_MASK|U_GC_LO_MASK)
+
+/** Mask constant for multiple UCharCategory bits (LC Cased Letters). @stable ICU 2.1 */
+#define U_GC_LC_MASK \
+            (U_GC_LU_MASK|U_GC_LL_MASK|U_GC_LT_MASK)
+
+/** Mask constant for multiple UCharCategory bits (M Marks). @stable ICU 2.1 */
+#define U_GC_M_MASK (U_GC_MN_MASK|U_GC_ME_MASK|U_GC_MC_MASK)
+
+/** Mask constant for multiple UCharCategory bits (N Numbers). @stable ICU 2.1 */
+#define U_GC_N_MASK (U_GC_ND_MASK|U_GC_NL_MASK|U_GC_NO_MASK)
+
+/** Mask constant for multiple UCharCategory bits (Z Separators). @stable ICU 2.1 */
+#define U_GC_Z_MASK (U_GC_ZS_MASK|U_GC_ZL_MASK|U_GC_ZP_MASK)
+
+/** Mask constant for multiple UCharCategory bits (C Others). @stable ICU 2.1 */
+#define U_GC_C_MASK \
+            (U_GC_CN_MASK|U_GC_CC_MASK|U_GC_CF_MASK|U_GC_CO_MASK|U_GC_CS_MASK)
+
+/** Mask constant for multiple UCharCategory bits (P Punctuation). @stable ICU 2.1 */
+#define U_GC_P_MASK \
+            (U_GC_PD_MASK|U_GC_PS_MASK|U_GC_PE_MASK|U_GC_PC_MASK|U_GC_PO_MASK| \
+             U_GC_PI_MASK|U_GC_PF_MASK)
+
+/** Mask constant for multiple UCharCategory bits (S Symbols). @stable ICU 2.1 */
+#define U_GC_S_MASK (U_GC_SM_MASK|U_GC_SC_MASK|U_GC_SK_MASK|U_GC_SO_MASK)
+
+/**
+ * This specifies the language directional property of a character set.
+ * @stable ICU 2.0
+ */
+typedef enum UCharDirection {
+    /** See note !!.  Comments of the form "EN" are read by genpname. */
+
+    /** L @stable ICU 2.0 */
+    U_LEFT_TO_RIGHT               = 0,
+    /** R @stable ICU 2.0 */
+    U_RIGHT_TO_LEFT               = 1,
+    /** EN @stable ICU 2.0 */
+    U_EUROPEAN_NUMBER             = 2,
+    /** ES @stable ICU 2.0 */
+    U_EUROPEAN_NUMBER_SEPARATOR   = 3,
+    /** ET @stable ICU 2.0 */
+    U_EUROPEAN_NUMBER_TERMINATOR  = 4,
+    /** AN @stable ICU 2.0 */
+    U_ARABIC_NUMBER               = 5,
+    /** CS @stable ICU 2.0 */
+    U_COMMON_NUMBER_SEPARATOR     = 6,
+    /** B @stable ICU 2.0 */
+    U_BLOCK_SEPARATOR             = 7,
+    /** S @stable ICU 2.0 */
+    U_SEGMENT_SEPARATOR           = 8,
+    /** WS @stable ICU 2.0 */
+    U_WHITE_SPACE_NEUTRAL         = 9,
+    /** ON @stable ICU 2.0 */
+    U_OTHER_NEUTRAL               = 10,
+    /** LRE @stable ICU 2.0 */
+    U_LEFT_TO_RIGHT_EMBEDDING     = 11,
+    /** LRO @stable ICU 2.0 */
+    U_LEFT_TO_RIGHT_OVERRIDE      = 12,
+    /** AL @stable ICU 2.0 */
+    U_RIGHT_TO_LEFT_ARABIC        = 13,
+    /** RLE @stable ICU 2.0 */
+    U_RIGHT_TO_LEFT_EMBEDDING     = 14,
+    /** RLO @stable ICU 2.0 */
+    U_RIGHT_TO_LEFT_OVERRIDE      = 15,
+    /** PDF @stable ICU 2.0 */
+    U_POP_DIRECTIONAL_FORMAT      = 16,
+    /** NSM @stable ICU 2.0 */
+    U_DIR_NON_SPACING_MARK        = 17,
+    /** BN @stable ICU 2.0 */
+    U_BOUNDARY_NEUTRAL            = 18,
+    /** @stable ICU 2.0 */
+    U_CHAR_DIRECTION_COUNT
+} UCharDirection;
+
+/**
+ * Constants for Unicode blocks, see the Unicode Data file Blocks.txt
+ * @stable ICU 2.0
+ */
+enum UBlockCode {
+
+    /** New No_Block value in Unicode 4. @stable ICU 2.6 */
+    UBLOCK_NO_BLOCK = 0, /*[none]*/ /* Special range indicating No_Block */
+
+    /** @stable ICU 2.0 */
+    UBLOCK_BASIC_LATIN = 1, /*[0000]*/ /*See note !!*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_LATIN_1_SUPPLEMENT=2, /*[0080]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_LATIN_EXTENDED_A =3, /*[0100]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_LATIN_EXTENDED_B =4, /*[0180]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_IPA_EXTENSIONS =5, /*[0250]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_SPACING_MODIFIER_LETTERS =6, /*[02B0]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_COMBINING_DIACRITICAL_MARKS =7, /*[0300]*/
+
+    /**
+     * Unicode 3.2 renames this block to "Greek and Coptic".
+     * @stable ICU 2.0
+     */
+    UBLOCK_GREEK =8, /*[0370]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_CYRILLIC =9, /*[0400]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_ARMENIAN =10, /*[0530]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_HEBREW =11, /*[0590]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_ARABIC =12, /*[0600]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_SYRIAC =13, /*[0700]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_THAANA =14, /*[0780]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_DEVANAGARI =15, /*[0900]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_BENGALI =16, /*[0980]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_GURMUKHI =17, /*[0A00]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_GUJARATI =18, /*[0A80]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_ORIYA =19, /*[0B00]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_TAMIL =20, /*[0B80]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_TELUGU =21, /*[0C00]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_KANNADA =22, /*[0C80]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_MALAYALAM =23, /*[0D00]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_SINHALA =24, /*[0D80]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_THAI =25, /*[0E00]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_LAO =26, /*[0E80]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_TIBETAN =27, /*[0F00]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_MYANMAR =28, /*[1000]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_GEORGIAN =29, /*[10A0]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_HANGUL_JAMO =30, /*[1100]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_ETHIOPIC =31, /*[1200]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_CHEROKEE =32, /*[13A0]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS =33, /*[1400]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_OGHAM =34, /*[1680]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_RUNIC =35, /*[16A0]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_KHMER =36, /*[1780]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_MONGOLIAN =37, /*[1800]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_LATIN_EXTENDED_ADDITIONAL =38, /*[1E00]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_GREEK_EXTENDED =39, /*[1F00]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_GENERAL_PUNCTUATION =40, /*[2000]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_SUPERSCRIPTS_AND_SUBSCRIPTS =41, /*[2070]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_CURRENCY_SYMBOLS =42, /*[20A0]*/
+
+    /**
+     * Unicode 3.2 renames this block to "Combining Diacritical Marks for Symbols".
+     * @stable ICU 2.0
+     */
+    UBLOCK_COMBINING_MARKS_FOR_SYMBOLS =43, /*[20D0]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_LETTERLIKE_SYMBOLS =44, /*[2100]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_NUMBER_FORMS =45, /*[2150]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_ARROWS =46, /*[2190]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_MATHEMATICAL_OPERATORS =47, /*[2200]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_MISCELLANEOUS_TECHNICAL =48, /*[2300]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_CONTROL_PICTURES =49, /*[2400]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_OPTICAL_CHARACTER_RECOGNITION =50, /*[2440]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_ENCLOSED_ALPHANUMERICS =51, /*[2460]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_BOX_DRAWING =52, /*[2500]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_BLOCK_ELEMENTS =53, /*[2580]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_GEOMETRIC_SHAPES =54, /*[25A0]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_MISCELLANEOUS_SYMBOLS =55, /*[2600]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_DINGBATS =56, /*[2700]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_BRAILLE_PATTERNS =57, /*[2800]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_CJK_RADICALS_SUPPLEMENT =58, /*[2E80]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_KANGXI_RADICALS =59, /*[2F00]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_IDEOGRAPHIC_DESCRIPTION_CHARACTERS =60, /*[2FF0]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION =61, /*[3000]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_HIRAGANA =62, /*[3040]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_KATAKANA =63, /*[30A0]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_BOPOMOFO =64, /*[3100]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_HANGUL_COMPATIBILITY_JAMO =65, /*[3130]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_KANBUN =66, /*[3190]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_BOPOMOFO_EXTENDED =67, /*[31A0]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS =68, /*[3200]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_CJK_COMPATIBILITY =69, /*[3300]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A =70, /*[3400]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_CJK_UNIFIED_IDEOGRAPHS =71, /*[4E00]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_YI_SYLLABLES =72, /*[A000]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_YI_RADICALS =73, /*[A490]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_HANGUL_SYLLABLES =74, /*[AC00]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_HIGH_SURROGATES =75, /*[D800]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_HIGH_PRIVATE_USE_SURROGATES =76, /*[DB80]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_LOW_SURROGATES =77, /*[DC00]*/
+
+    /**
+     * Same as UBLOCK_PRIVATE_USE_AREA.
+     * Until Unicode 3.1.1, the corresponding block name was "Private Use",
+     * and multiple code point ranges had this block.
+     * Unicode 3.2 renames the block for the BMP PUA to "Private Use Area" and
+     * adds separate blocks for the supplementary PUAs.
+     *
+     * @stable ICU 2.0
+     */
+    UBLOCK_PRIVATE_USE = 78,
+    /**
+     * Same as UBLOCK_PRIVATE_USE.
+     * Until Unicode 3.1.1, the corresponding block name was "Private Use",
+     * and multiple code point ranges had this block.
+     * Unicode 3.2 renames the block for the BMP PUA to "Private Use Area" and
+     * adds separate blocks for the supplementary PUAs.
+     *
+     * @stable ICU 2.0
+     */
+    UBLOCK_PRIVATE_USE_AREA =UBLOCK_PRIVATE_USE, /*[E000]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS =79, /*[F900]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_ALPHABETIC_PRESENTATION_FORMS =80, /*[FB00]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_ARABIC_PRESENTATION_FORMS_A =81, /*[FB50]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_COMBINING_HALF_MARKS =82, /*[FE20]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_CJK_COMPATIBILITY_FORMS =83, /*[FE30]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_SMALL_FORM_VARIANTS =84, /*[FE50]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_ARABIC_PRESENTATION_FORMS_B =85, /*[FE70]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_SPECIALS =86, /*[FFF0]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_HALFWIDTH_AND_FULLWIDTH_FORMS =87, /*[FF00]*/
+
+    /* New blocks in Unicode 3.1 */
+
+    /** @stable ICU 2.0 */
+    UBLOCK_OLD_ITALIC = 88  , /*[10300]*/
+    /** @stable ICU 2.0 */
+    UBLOCK_GOTHIC = 89 , /*[10330]*/
+    /** @stable ICU 2.0 */
+    UBLOCK_DESERET = 90 , /*[10400]*/
+    /** @stable ICU 2.0 */
+    UBLOCK_BYZANTINE_MUSICAL_SYMBOLS = 91 , /*[1D000]*/
+    /** @stable ICU 2.0 */
+    UBLOCK_MUSICAL_SYMBOLS = 92 , /*[1D100]*/
+    /** @stable ICU 2.0 */
+    UBLOCK_MATHEMATICAL_ALPHANUMERIC_SYMBOLS = 93  , /*[1D400]*/
+    /** @stable ICU 2.0 */
+    UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B  = 94 , /*[20000]*/
+    /** @stable ICU 2.0 */
+    UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT = 95 , /*[2F800]*/
+    /** @stable ICU 2.0 */
+    UBLOCK_TAGS = 96, /*[E0000]*/
+
+    /* New blocks in Unicode 3.2 */
+
+    /**
+     * Unicode 4.0.1 renames the "Cyrillic Supplementary" block to "Cyrillic Supplement".
+     * @stable ICU 2.2
+     */
+    UBLOCK_CYRILLIC_SUPPLEMENTARY = 97, 
+    /** @stable ICU 3.0  */
+    UBLOCK_CYRILLIC_SUPPLEMENT = UBLOCK_CYRILLIC_SUPPLEMENTARY, /*[0500]*/
+    /** @stable ICU 2.2 */
+    UBLOCK_TAGALOG = 98, /*[1700]*/
+    /** @stable ICU 2.2 */
+    UBLOCK_HANUNOO = 99, /*[1720]*/
+    /** @stable ICU 2.2 */
+    UBLOCK_BUHID = 100, /*[1740]*/
+    /** @stable ICU 2.2 */
+    UBLOCK_TAGBANWA = 101, /*[1760]*/
+    /** @stable ICU 2.2 */
+    UBLOCK_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A = 102, /*[27C0]*/
+    /** @stable ICU 2.2 */
+    UBLOCK_SUPPLEMENTAL_ARROWS_A = 103, /*[27F0]*/
+    /** @stable ICU 2.2 */
+    UBLOCK_SUPPLEMENTAL_ARROWS_B = 104, /*[2900]*/
+    /** @stable ICU 2.2 */
+    UBLOCK_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B = 105, /*[2980]*/
+    /** @stable ICU 2.2 */
+    UBLOCK_SUPPLEMENTAL_MATHEMATICAL_OPERATORS = 106, /*[2A00]*/
+    /** @stable ICU 2.2 */
+    UBLOCK_KATAKANA_PHONETIC_EXTENSIONS = 107, /*[31F0]*/
+    /** @stable ICU 2.2 */
+    UBLOCK_VARIATION_SELECTORS = 108, /*[FE00]*/
+    /** @stable ICU 2.2 */
+    UBLOCK_SUPPLEMENTARY_PRIVATE_USE_AREA_A = 109, /*[F0000]*/
+    /** @stable ICU 2.2 */
+    UBLOCK_SUPPLEMENTARY_PRIVATE_USE_AREA_B = 110, /*[100000]*/
+
+    /* New blocks in Unicode 4 */
+
+    /** @stable ICU 2.6 */
+    UBLOCK_LIMBU = 111, /*[1900]*/
+    /** @stable ICU 2.6 */
+    UBLOCK_TAI_LE = 112, /*[1950]*/
+    /** @stable ICU 2.6 */
+    UBLOCK_KHMER_SYMBOLS = 113, /*[19E0]*/
+    /** @stable ICU 2.6 */
+    UBLOCK_PHONETIC_EXTENSIONS = 114, /*[1D00]*/
+    /** @stable ICU 2.6 */
+    UBLOCK_MISCELLANEOUS_SYMBOLS_AND_ARROWS = 115, /*[2B00]*/
+    /** @stable ICU 2.6 */
+    UBLOCK_YIJING_HEXAGRAM_SYMBOLS = 116, /*[4DC0]*/
+    /** @stable ICU 2.6 */
+    UBLOCK_LINEAR_B_SYLLABARY = 117, /*[10000]*/
+    /** @stable ICU 2.6 */
+    UBLOCK_LINEAR_B_IDEOGRAMS = 118, /*[10080]*/
+    /** @stable ICU 2.6 */
+    UBLOCK_AEGEAN_NUMBERS = 119, /*[10100]*/
+    /** @stable ICU 2.6 */
+    UBLOCK_UGARITIC = 120, /*[10380]*/
+    /** @stable ICU 2.6 */
+    UBLOCK_SHAVIAN = 121, /*[10450]*/
+    /** @stable ICU 2.6 */
+    UBLOCK_OSMANYA = 122, /*[10480]*/
+    /** @stable ICU 2.6 */
+    UBLOCK_CYPRIOT_SYLLABARY = 123, /*[10800]*/
+    /** @stable ICU 2.6 */
+    UBLOCK_TAI_XUAN_JING_SYMBOLS = 124, /*[1D300]*/
+    /** @stable ICU 2.6 */
+    UBLOCK_VARIATION_SELECTORS_SUPPLEMENT = 125, /*[E0100]*/
+
+    /* New blocks in Unicode 4.1 */
+
+    /** @stable ICU 3.4 */
+    UBLOCK_ANCIENT_GREEK_MUSICAL_NOTATION = 126, /*[1D200]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_ANCIENT_GREEK_NUMBERS = 127, /*[10140]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_ARABIC_SUPPLEMENT = 128, /*[0750]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_BUGINESE = 129, /*[1A00]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_CJK_STROKES = 130, /*[31C0]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_COMBINING_DIACRITICAL_MARKS_SUPPLEMENT = 131, /*[1DC0]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_COPTIC = 132, /*[2C80]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_ETHIOPIC_EXTENDED = 133, /*[2D80]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_ETHIOPIC_SUPPLEMENT = 134, /*[1380]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_GEORGIAN_SUPPLEMENT = 135, /*[2D00]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_GLAGOLITIC = 136, /*[2C00]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_KHAROSHTHI = 137, /*[10A00]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_MODIFIER_TONE_LETTERS = 138, /*[A700]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_NEW_TAI_LUE = 139, /*[1980]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_OLD_PERSIAN = 140, /*[103A0]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_PHONETIC_EXTENSIONS_SUPPLEMENT = 141, /*[1D80]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_SUPPLEMENTAL_PUNCTUATION = 142, /*[2E00]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_SYLOTI_NAGRI = 143, /*[A800]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_TIFINAGH = 144, /*[2D30]*/
+    /** @stable ICU 3.4 */
+    UBLOCK_VERTICAL_FORMS = 145, /*[FE10]*/
+
+    /* New blocks in Unicode 5.0 */
+
+    /** @stable ICU 3.6 */
+    UBLOCK_NKO = 146, /*[07C0]*/
+    /** @stable ICU 3.6 */
+    UBLOCK_BALINESE = 147, /*[1B00]*/
+    /** @stable ICU 3.6 */
+    UBLOCK_LATIN_EXTENDED_C = 148, /*[2C60]*/
+    /** @stable ICU 3.6 */
+    UBLOCK_LATIN_EXTENDED_D = 149, /*[A720]*/
+    /** @stable ICU 3.6 */
+    UBLOCK_PHAGS_PA = 150, /*[A840]*/
+    /** @stable ICU 3.6 */
+    UBLOCK_PHOENICIAN = 151, /*[10900]*/
+    /** @stable ICU 3.6 */
+    UBLOCK_CUNEIFORM = 152, /*[12000]*/
+    /** @stable ICU 3.6 */
+    UBLOCK_CUNEIFORM_NUMBERS_AND_PUNCTUATION = 153, /*[12400]*/
+    /** @stable ICU 3.6 */
+    UBLOCK_COUNTING_ROD_NUMERALS = 154, /*[1D360]*/
+
+    /* New blocks in Unicode 5.1 */
+
+    /** @stable ICU 4.0 */
+    UBLOCK_SUNDANESE = 155, /*[1B80]*/
+    /** @stable ICU 4.0 */
+    UBLOCK_LEPCHA = 156, /*[1C00]*/
+    /** @stable ICU 4.0 */
+    UBLOCK_OL_CHIKI = 157, /*[1C50]*/
+    /** @stable ICU 4.0 */
+    UBLOCK_CYRILLIC_EXTENDED_A = 158, /*[2DE0]*/
+    /** @stable ICU 4.0 */
+    UBLOCK_VAI = 159, /*[A500]*/
+    /** @stable ICU 4.0 */
+    UBLOCK_CYRILLIC_EXTENDED_B = 160, /*[A640]*/
+    /** @stable ICU 4.0 */
+    UBLOCK_SAURASHTRA = 161, /*[A880]*/
+    /** @stable ICU 4.0 */
+    UBLOCK_KAYAH_LI = 162, /*[A900]*/
+    /** @stable ICU 4.0 */
+    UBLOCK_REJANG = 163, /*[A930]*/
+    /** @stable ICU 4.0 */
+    UBLOCK_CHAM = 164, /*[AA00]*/
+    /** @stable ICU 4.0 */
+    UBLOCK_ANCIENT_SYMBOLS = 165, /*[10190]*/
+    /** @stable ICU 4.0 */
+    UBLOCK_PHAISTOS_DISC = 166, /*[101D0]*/
+    /** @stable ICU 4.0 */
+    UBLOCK_LYCIAN = 167, /*[10280]*/
+    /** @stable ICU 4.0 */
+    UBLOCK_CARIAN = 168, /*[102A0]*/
+    /** @stable ICU 4.0 */
+    UBLOCK_LYDIAN = 169, /*[10920]*/
+    /** @stable ICU 4.0 */
+    UBLOCK_MAHJONG_TILES = 170, /*[1F000]*/
+    /** @stable ICU 4.0 */
+    UBLOCK_DOMINO_TILES = 171, /*[1F030]*/
+
+    /* New blocks in Unicode 5.2 */
+
+    /** @stable ICU 4.4 */
+    UBLOCK_SAMARITAN = 172, /*[0800]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED = 173, /*[18B0]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_TAI_THAM = 174, /*[1A20]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_VEDIC_EXTENSIONS = 175, /*[1CD0]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_LISU = 176, /*[A4D0]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_BAMUM = 177, /*[A6A0]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_COMMON_INDIC_NUMBER_FORMS = 178, /*[A830]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_DEVANAGARI_EXTENDED = 179, /*[A8E0]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_HANGUL_JAMO_EXTENDED_A = 180, /*[A960]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_JAVANESE = 181, /*[A980]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_MYANMAR_EXTENDED_A = 182, /*[AA60]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_TAI_VIET = 183, /*[AA80]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_MEETEI_MAYEK = 184, /*[ABC0]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_HANGUL_JAMO_EXTENDED_B = 185, /*[D7B0]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_IMPERIAL_ARAMAIC = 186, /*[10840]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_OLD_SOUTH_ARABIAN = 187, /*[10A60]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_AVESTAN = 188, /*[10B00]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_INSCRIPTIONAL_PARTHIAN = 189, /*[10B40]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_INSCRIPTIONAL_PAHLAVI = 190, /*[10B60]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_OLD_TURKIC = 191, /*[10C00]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_RUMI_NUMERAL_SYMBOLS = 192, /*[10E60]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_KAITHI = 193, /*[11080]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_EGYPTIAN_HIEROGLYPHS = 194, /*[13000]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_ENCLOSED_ALPHANUMERIC_SUPPLEMENT = 195, /*[1F100]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_ENCLOSED_IDEOGRAPHIC_SUPPLEMENT = 196, /*[1F200]*/
+    /** @stable ICU 4.4 */
+    UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C = 197, /*[2A700]*/
+
+    /* New blocks in Unicode 6.0 */
+
+    /** @stable ICU 4.6 */
+    UBLOCK_MANDAIC = 198, /*[0840]*/
+    /** @stable ICU 4.6 */
+    UBLOCK_BATAK = 199, /*[1BC0]*/
+    /** @stable ICU 4.6 */
+    UBLOCK_ETHIOPIC_EXTENDED_A = 200, /*[AB00]*/
+    /** @stable ICU 4.6 */
+    UBLOCK_BRAHMI = 201, /*[11000]*/
+    /** @stable ICU 4.6 */
+    UBLOCK_BAMUM_SUPPLEMENT = 202, /*[16800]*/
+    /** @stable ICU 4.6 */
+    UBLOCK_KANA_SUPPLEMENT = 203, /*[1B000]*/
+    /** @stable ICU 4.6 */
+    UBLOCK_PLAYING_CARDS = 204, /*[1F0A0]*/
+    /** @stable ICU 4.6 */
+    UBLOCK_MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS = 205, /*[1F300]*/
+    /** @stable ICU 4.6 */
+    UBLOCK_EMOTICONS = 206, /*[1F600]*/
+    /** @stable ICU 4.6 */
+    UBLOCK_TRANSPORT_AND_MAP_SYMBOLS = 207, /*[1F680]*/
+    /** @stable ICU 4.6 */
+    UBLOCK_ALCHEMICAL_SYMBOLS = 208, /*[1F700]*/
+    /** @stable ICU 4.6 */
+    UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D = 209, /*[2B740]*/
+
+    /** @stable ICU 2.0 */
+    UBLOCK_COUNT = 210,
+
+    /** @stable ICU 2.0 */
+    UBLOCK_INVALID_CODE=-1
+};
+
+/** @stable ICU 2.0 */
+typedef enum UBlockCode UBlockCode;
+
+/**
+ * East Asian Width constants.
+ *
+ * @see UCHAR_EAST_ASIAN_WIDTH
+ * @see u_getIntPropertyValue
+ * @stable ICU 2.2
+ */
+typedef enum UEastAsianWidth {
+    U_EA_NEUTRAL,   /*[N]*/ /*See note !!*/
+    U_EA_AMBIGUOUS, /*[A]*/
+    U_EA_HALFWIDTH, /*[H]*/
+    U_EA_FULLWIDTH, /*[F]*/
+    U_EA_NARROW,    /*[Na]*/
+    U_EA_WIDE,      /*[W]*/
+    U_EA_COUNT
+} UEastAsianWidth;
+/*
+ * Implementation note:
+ * Keep UEastAsianWidth constant values in sync with names list in genprops/props2.c.
+ */
+
+/**
+ * Selector constants for u_charName().
+ * u_charName() returns the "modern" name of a
+ * Unicode character; or the name that was defined in
+ * Unicode version 1.0, before the Unicode standard merged
+ * with ISO-10646; or an "extended" name that gives each
+ * Unicode code point a unique name.
+ *
+ * @see u_charName
+ * @stable ICU 2.0
+ */
+typedef enum UCharNameChoice {
+    U_UNICODE_CHAR_NAME,
+    U_UNICODE_10_CHAR_NAME,
+    U_EXTENDED_CHAR_NAME,
+    U_CHAR_NAME_ALIAS,          /**< Corrected name from NameAliases.txt. @stable ICU 4.4 */
+    U_CHAR_NAME_CHOICE_COUNT
+} UCharNameChoice;
+
+/**
+ * Selector constants for u_getPropertyName() and
+ * u_getPropertyValueName().  These selectors are used to choose which
+ * name is returned for a given property or value.  All properties and
+ * values have a long name.  Most have a short name, but some do not.
+ * Unicode allows for additional names, beyond the long and short
+ * name, which would be indicated by U_LONG_PROPERTY_NAME + i, where
+ * i=1, 2,...
+ *
+ * @see u_getPropertyName()
+ * @see u_getPropertyValueName()
+ * @stable ICU 2.4
+ */
+typedef enum UPropertyNameChoice {
+    U_SHORT_PROPERTY_NAME,
+    U_LONG_PROPERTY_NAME,
+    U_PROPERTY_NAME_CHOICE_COUNT
+} UPropertyNameChoice;
+
+/**
+ * Decomposition Type constants.
+ *
+ * @see UCHAR_DECOMPOSITION_TYPE
+ * @stable ICU 2.2
+ */
+typedef enum UDecompositionType {
+    U_DT_NONE,              /*[none]*/ /*See note !!*/
+    U_DT_CANONICAL,         /*[can]*/
+    U_DT_COMPAT,            /*[com]*/
+    U_DT_CIRCLE,            /*[enc]*/
+    U_DT_FINAL,             /*[fin]*/
+    U_DT_FONT,              /*[font]*/
+    U_DT_FRACTION,          /*[fra]*/
+    U_DT_INITIAL,           /*[init]*/
+    U_DT_ISOLATED,          /*[iso]*/
+    U_DT_MEDIAL,            /*[med]*/
+    U_DT_NARROW,            /*[nar]*/
+    U_DT_NOBREAK,           /*[nb]*/
+    U_DT_SMALL,             /*[sml]*/
+    U_DT_SQUARE,            /*[sqr]*/
+    U_DT_SUB,               /*[sub]*/
+    U_DT_SUPER,             /*[sup]*/
+    U_DT_VERTICAL,          /*[vert]*/
+    U_DT_WIDE,              /*[wide]*/
+    U_DT_COUNT /* 18 */
+} UDecompositionType;
+
+/**
+ * Joining Type constants.
+ *
+ * @see UCHAR_JOINING_TYPE
+ * @stable ICU 2.2
+ */
+typedef enum UJoiningType {
+    U_JT_NON_JOINING,       /*[U]*/ /*See note !!*/
+    U_JT_JOIN_CAUSING,      /*[C]*/
+    U_JT_DUAL_JOINING,      /*[D]*/
+    U_JT_LEFT_JOINING,      /*[L]*/
+    U_JT_RIGHT_JOINING,     /*[R]*/
+    U_JT_TRANSPARENT,       /*[T]*/
+    U_JT_COUNT /* 6 */
+} UJoiningType;
+
+/**
+ * Joining Group constants.
+ *
+ * @see UCHAR_JOINING_GROUP
+ * @stable ICU 2.2
+ */
+typedef enum UJoiningGroup {
+    U_JG_NO_JOINING_GROUP,
+    U_JG_AIN,
+    U_JG_ALAPH,
+    U_JG_ALEF,
+    U_JG_BEH,
+    U_JG_BETH,
+    U_JG_DAL,
+    U_JG_DALATH_RISH,
+    U_JG_E,
+    U_JG_FEH,
+    U_JG_FINAL_SEMKATH,
+    U_JG_GAF,
+    U_JG_GAMAL,
+    U_JG_HAH,
+    U_JG_TEH_MARBUTA_GOAL,  /**< @stable ICU 4.6 */
+    U_JG_HAMZA_ON_HEH_GOAL=U_JG_TEH_MARBUTA_GOAL,
+    U_JG_HE,
+    U_JG_HEH,
+    U_JG_HEH_GOAL,
+    U_JG_HETH,
+    U_JG_KAF,
+    U_JG_KAPH,
+    U_JG_KNOTTED_HEH,
+    U_JG_LAM,
+    U_JG_LAMADH,
+    U_JG_MEEM,
+    U_JG_MIM,
+    U_JG_NOON,
+    U_JG_NUN,
+    U_JG_PE,
+    U_JG_QAF,
+    U_JG_QAPH,
+    U_JG_REH,
+    U_JG_REVERSED_PE,
+    U_JG_SAD,
+    U_JG_SADHE,
+    U_JG_SEEN,
+    U_JG_SEMKATH,
+    U_JG_SHIN,
+    U_JG_SWASH_KAF,
+    U_JG_SYRIAC_WAW,
+    U_JG_TAH,
+    U_JG_TAW,
+    U_JG_TEH_MARBUTA,
+    U_JG_TETH,
+    U_JG_WAW,
+    U_JG_YEH,
+    U_JG_YEH_BARREE,
+    U_JG_YEH_WITH_TAIL,
+    U_JG_YUDH,
+    U_JG_YUDH_HE,
+    U_JG_ZAIN,
+    U_JG_FE,        /**< @stable ICU 2.6 */
+    U_JG_KHAPH,     /**< @stable ICU 2.6 */
+    U_JG_ZHAIN,     /**< @stable ICU 2.6 */
+    U_JG_BURUSHASKI_YEH_BARREE, /**< @stable ICU 4.0 */
+    U_JG_FARSI_YEH, /**< @stable ICU 4.4 */
+    U_JG_NYA,       /**< @stable ICU 4.4 */
+    U_JG_COUNT
+} UJoiningGroup;
+
+/**
+ * Grapheme Cluster Break constants.
+ *
+ * @see UCHAR_GRAPHEME_CLUSTER_BREAK
+ * @stable ICU 3.4
+ */
+typedef enum UGraphemeClusterBreak {
+    U_GCB_OTHER = 0,            /*[XX]*/ /*See note !!*/
+    U_GCB_CONTROL = 1,          /*[CN]*/
+    U_GCB_CR = 2,               /*[CR]*/
+    U_GCB_EXTEND = 3,           /*[EX]*/
+    U_GCB_L = 4,                /*[L]*/
+    U_GCB_LF = 5,               /*[LF]*/
+    U_GCB_LV = 6,               /*[LV]*/
+    U_GCB_LVT = 7,              /*[LVT]*/
+    U_GCB_T = 8,                /*[T]*/
+    U_GCB_V = 9,                /*[V]*/
+    U_GCB_SPACING_MARK = 10,    /*[SM]*/ /* from here on: new in Unicode 5.1/ICU 4.0 */
+    U_GCB_PREPEND = 11,         /*[PP]*/
+    U_GCB_COUNT = 12
+} UGraphemeClusterBreak;
+
+/**
+ * Word Break constants.
+ * (UWordBreak is a pre-existing enum type in ubrk.h for word break status tags.)
+ *
+ * @see UCHAR_WORD_BREAK
+ * @stable ICU 3.4
+ */
+typedef enum UWordBreakValues {
+    U_WB_OTHER = 0,             /*[XX]*/ /*See note !!*/
+    U_WB_ALETTER = 1,           /*[LE]*/
+    U_WB_FORMAT = 2,            /*[FO]*/
+    U_WB_KATAKANA = 3,          /*[KA]*/
+    U_WB_MIDLETTER = 4,         /*[ML]*/
+    U_WB_MIDNUM = 5,            /*[MN]*/
+    U_WB_NUMERIC = 6,           /*[NU]*/
+    U_WB_EXTENDNUMLET = 7,      /*[EX]*/
+    U_WB_CR = 8,                /*[CR]*/ /* from here on: new in Unicode 5.1/ICU 4.0 */
+    U_WB_EXTEND = 9,            /*[Extend]*/
+    U_WB_LF = 10,               /*[LF]*/
+    U_WB_MIDNUMLET =11,         /*[MB]*/
+    U_WB_NEWLINE =12,           /*[NL]*/
+    U_WB_COUNT = 13
+} UWordBreakValues;
+
+/**
+ * Sentence Break constants.
+ *
+ * @see UCHAR_SENTENCE_BREAK
+ * @stable ICU 3.4
+ */
+typedef enum USentenceBreak {
+    U_SB_OTHER = 0,             /*[XX]*/ /*See note !!*/
+    U_SB_ATERM = 1,             /*[AT]*/
+    U_SB_CLOSE = 2,             /*[CL]*/
+    U_SB_FORMAT = 3,            /*[FO]*/
+    U_SB_LOWER = 4,             /*[LO]*/
+    U_SB_NUMERIC = 5,           /*[NU]*/
+    U_SB_OLETTER = 6,           /*[LE]*/
+    U_SB_SEP = 7,               /*[SE]*/
+    U_SB_SP = 8,                /*[SP]*/
+    U_SB_STERM = 9,             /*[ST]*/
+    U_SB_UPPER = 10,            /*[UP]*/
+    U_SB_CR = 11,               /*[CR]*/ /* from here on: new in Unicode 5.1/ICU 4.0 */
+    U_SB_EXTEND = 12,           /*[EX]*/
+    U_SB_LF = 13,               /*[LF]*/
+    U_SB_SCONTINUE = 14,        /*[SC]*/
+    U_SB_COUNT = 15
+} USentenceBreak;
+
+/**
+ * Line Break constants.
+ *
+ * @see UCHAR_LINE_BREAK
+ * @stable ICU 2.2
+ */
+typedef enum ULineBreak {
+    U_LB_UNKNOWN = 0,           /*[XX]*/ /*See note !!*/
+    U_LB_AMBIGUOUS = 1,         /*[AI]*/
+    U_LB_ALPHABETIC = 2,        /*[AL]*/
+    U_LB_BREAK_BOTH = 3,        /*[B2]*/
+    U_LB_BREAK_AFTER = 4,       /*[BA]*/
+    U_LB_BREAK_BEFORE = 5,      /*[BB]*/
+    U_LB_MANDATORY_BREAK = 6,   /*[BK]*/
+    U_LB_CONTINGENT_BREAK = 7,  /*[CB]*/
+    U_LB_CLOSE_PUNCTUATION = 8, /*[CL]*/
+    U_LB_COMBINING_MARK = 9,    /*[CM]*/
+    U_LB_CARRIAGE_RETURN = 10,   /*[CR]*/
+    U_LB_EXCLAMATION = 11,       /*[EX]*/
+    U_LB_GLUE = 12,              /*[GL]*/
+    U_LB_HYPHEN = 13,            /*[HY]*/
+    U_LB_IDEOGRAPHIC = 14,       /*[ID]*/
+    U_LB_INSEPERABLE = 15,
+    /** Renamed from the misspelled "inseperable" in Unicode 4.0.1/ICU 3.0 @stable ICU 3.0 */
+    U_LB_INSEPARABLE=U_LB_INSEPERABLE,/*[IN]*/
+    U_LB_INFIX_NUMERIC = 16,     /*[IS]*/
+    U_LB_LINE_FEED = 17,         /*[LF]*/
+    U_LB_NONSTARTER = 18,        /*[NS]*/
+    U_LB_NUMERIC = 19,           /*[NU]*/
+    U_LB_OPEN_PUNCTUATION = 20,  /*[OP]*/
+    U_LB_POSTFIX_NUMERIC = 21,   /*[PO]*/
+    U_LB_PREFIX_NUMERIC = 22,    /*[PR]*/
+    U_LB_QUOTATION = 23,         /*[QU]*/
+    U_LB_COMPLEX_CONTEXT = 24,   /*[SA]*/
+    U_LB_SURROGATE = 25,         /*[SG]*/
+    U_LB_SPACE = 26,             /*[SP]*/
+    U_LB_BREAK_SYMBOLS = 27,     /*[SY]*/
+    U_LB_ZWSPACE = 28,           /*[ZW]*/
+    U_LB_NEXT_LINE = 29,         /*[NL]*/ /* from here on: new in Unicode 4/ICU 2.6 */
+    U_LB_WORD_JOINER = 30,       /*[WJ]*/
+    U_LB_H2 = 31,                /*[H2]*/ /* from here on: new in Unicode 4.1/ICU 3.4 */
+    U_LB_H3 = 32,                /*[H3]*/
+    U_LB_JL = 33,                /*[JL]*/
+    U_LB_JT = 34,                /*[JT]*/
+    U_LB_JV = 35,                /*[JV]*/
+    U_LB_CLOSE_PARENTHESIS = 36, /*[CP]*/ /* new in Unicode 5.2/ICU 4.4 */
+    U_LB_COUNT = 37
+} ULineBreak;
+
+/**
+ * Numeric Type constants.
+ *
+ * @see UCHAR_NUMERIC_TYPE
+ * @stable ICU 2.2
+ */
+typedef enum UNumericType {
+    U_NT_NONE,              /*[None]*/ /*See note !!*/
+    U_NT_DECIMAL,           /*[de]*/
+    U_NT_DIGIT,             /*[di]*/
+    U_NT_NUMERIC,           /*[nu]*/
+    U_NT_COUNT
+} UNumericType;
+
+/**
+ * Hangul Syllable Type constants.
+ *
+ * @see UCHAR_HANGUL_SYLLABLE_TYPE
+ * @stable ICU 2.6
+ */
+typedef enum UHangulSyllableType {
+    U_HST_NOT_APPLICABLE,   /*[NA]*/ /*See note !!*/
+    U_HST_LEADING_JAMO,     /*[L]*/
+    U_HST_VOWEL_JAMO,       /*[V]*/
+    U_HST_TRAILING_JAMO,    /*[T]*/
+    U_HST_LV_SYLLABLE,      /*[LV]*/
+    U_HST_LVT_SYLLABLE,     /*[LVT]*/
+    U_HST_COUNT
+} UHangulSyllableType;
+
+/**
+ * Check a binary Unicode property for a code point.
+ *
+ * Unicode, especially in version 3.2, defines many more properties than the
+ * original set in UnicodeData.txt.
+ *
+ * The properties APIs are intended to reflect Unicode properties as defined
+ * in the Unicode Character Database (UCD) and Unicode Technical Reports (UTR).
+ * For details about the properties see http://www.unicode.org/ucd/ .
+ * For names of Unicode properties see the UCD file PropertyAliases.txt.
+ *
+ * Important: If ICU is built with UCD files from Unicode versions below 3.2,
+ * then properties marked with "new in Unicode 3.2" are not or not fully available.
+ *
+ * @param c Code point to test.
+ * @param which UProperty selector constant, identifies which binary property to check.
+ *        Must be UCHAR_BINARY_START<=which<UCHAR_BINARY_LIMIT.
+ * @return TRUE or FALSE according to the binary Unicode property value for c.
+ *         Also FALSE if 'which' is out of bounds or if the Unicode version
+ *         does not have data for the property at all, or not for this code point.
+ *
+ * @see UProperty
+ * @see u_getIntPropertyValue
+ * @see u_getUnicodeVersion
+ * @stable ICU 2.1
+ */
+U_STABLE UBool U_EXPORT2
+u_hasBinaryProperty(UChar32 c, UProperty which);
+
+/**
+ * Check if a code point has the Alphabetic Unicode property.
+ * Same as u_hasBinaryProperty(c, UCHAR_ALPHABETIC).
+ * This is different from u_isalpha!
+ * @param c Code point to test
+ * @return true if the code point has the Alphabetic Unicode property, false otherwise
+ *
+ * @see UCHAR_ALPHABETIC
+ * @see u_isalpha
+ * @see u_hasBinaryProperty
+ * @stable ICU 2.1
+ */
+U_STABLE UBool U_EXPORT2
+u_isUAlphabetic(UChar32 c);
+
+/**
+ * Check if a code point has the Lowercase Unicode property.
+ * Same as u_hasBinaryProperty(c, UCHAR_LOWERCASE).
+ * This is different from u_islower!
+ * @param c Code point to test
+ * @return true if the code point has the Lowercase Unicode property, false otherwise
+ *
+ * @see UCHAR_LOWERCASE
+ * @see u_islower
+ * @see u_hasBinaryProperty
+ * @stable ICU 2.1
+ */
+U_STABLE UBool U_EXPORT2
+u_isULowercase(UChar32 c);
+
+/**
+ * Check if a code point has the Uppercase Unicode property.
+ * Same as u_hasBinaryProperty(c, UCHAR_UPPERCASE).
+ * This is different from u_isupper!
+ * @param c Code point to test
+ * @return true if the code point has the Uppercase Unicode property, false otherwise
+ *
+ * @see UCHAR_UPPERCASE
+ * @see u_isupper
+ * @see u_hasBinaryProperty
+ * @stable ICU 2.1
+ */
+U_STABLE UBool U_EXPORT2
+u_isUUppercase(UChar32 c);
+
+/**
+ * Check if a code point has the White_Space Unicode property.
+ * Same as u_hasBinaryProperty(c, UCHAR_WHITE_SPACE).
+ * This is different from both u_isspace and u_isWhitespace!
+ *
+ * Note: There are several ICU whitespace functions; please see the uchar.h
+ * file documentation for a detailed comparison.
+ *
+ * @param c Code point to test
+ * @return true if the code point has the White_Space Unicode property, false otherwise.
+ *
+ * @see UCHAR_WHITE_SPACE
+ * @see u_isWhitespace
+ * @see u_isspace
+ * @see u_isJavaSpaceChar
+ * @see u_hasBinaryProperty
+ * @stable ICU 2.1
+ */
+U_STABLE UBool U_EXPORT2
+u_isUWhiteSpace(UChar32 c);
+
+/**
+ * Get the property value for an enumerated or integer Unicode property for a code point.
+ * Also returns binary and mask property values.
+ *
+ * Unicode, especially in version 3.2, defines many more properties than the
+ * original set in UnicodeData.txt.
+ *
+ * The properties APIs are intended to reflect Unicode properties as defined
+ * in the Unicode Character Database (UCD) and Unicode Technical Reports (UTR).
+ * For details about the properties see http://www.unicode.org/ .
+ * For names of Unicode properties see the UCD file PropertyAliases.txt.
+ *
+ * Sample usage:
+ * UEastAsianWidth ea=(UEastAsianWidth)u_getIntPropertyValue(c, UCHAR_EAST_ASIAN_WIDTH);
+ * UBool b=(UBool)u_getIntPropertyValue(c, UCHAR_IDEOGRAPHIC);
+ *
+ * @param c Code point to test.
+ * @param which UProperty selector constant, identifies which property to check.
+ *        Must be UCHAR_BINARY_START<=which<UCHAR_BINARY_LIMIT
+ *        or UCHAR_INT_START<=which<UCHAR_INT_LIMIT
+ *        or UCHAR_MASK_START<=which<UCHAR_MASK_LIMIT.
+ * @return Numeric value that is directly the property value or,
+ *         for enumerated properties, corresponds to the numeric value of the enumerated
+ *         constant of the respective property value enumeration type
+ *         (cast to enum type if necessary).
+ *         Returns 0 or 1 (for FALSE/TRUE) for binary Unicode properties.
+ *         Returns a bit-mask for mask properties.
+ *         Returns 0 if 'which' is out of bounds or if the Unicode version
+ *         does not have data for the property at all, or not for this code point.
+ *
+ * @see UProperty
+ * @see u_hasBinaryProperty
+ * @see u_getIntPropertyMinValue
+ * @see u_getIntPropertyMaxValue
+ * @see u_getUnicodeVersion
+ * @stable ICU 2.2
+ */
+U_STABLE int32_t U_EXPORT2
+u_getIntPropertyValue(UChar32 c, UProperty which);
+
+/**
+ * Get the minimum value for an enumerated/integer/binary Unicode property.
+ * Can be used together with u_getIntPropertyMaxValue
+ * to allocate arrays of UnicodeSet or similar.
+ *
+ * @param which UProperty selector constant, identifies which binary property to check.
+ *        Must be UCHAR_BINARY_START<=which<UCHAR_BINARY_LIMIT
+ *        or UCHAR_INT_START<=which<UCHAR_INT_LIMIT.
+ * @return Minimum value returned by u_getIntPropertyValue for a Unicode property.
+ *         0 if the property selector is out of range.
+ *
+ * @see UProperty
+ * @see u_hasBinaryProperty
+ * @see u_getUnicodeVersion
+ * @see u_getIntPropertyMaxValue
+ * @see u_getIntPropertyValue
+ * @stable ICU 2.2
+ */
+U_STABLE int32_t U_EXPORT2
+u_getIntPropertyMinValue(UProperty which);
+
+/**
+ * Get the maximum value for an enumerated/integer/binary Unicode property.
+ * Can be used together with u_getIntPropertyMinValue
+ * to allocate arrays of UnicodeSet or similar.
+ *
+ * Examples for min/max values (for Unicode 3.2):
+ *
+ * - UCHAR_BIDI_CLASS:    0/18 (U_LEFT_TO_RIGHT/U_BOUNDARY_NEUTRAL)
+ * - UCHAR_SCRIPT:        0/45 (USCRIPT_COMMON/USCRIPT_TAGBANWA)
+ * - UCHAR_IDEOGRAPHIC:   0/1  (FALSE/TRUE)
+ *
+ * For undefined UProperty constant values, min/max values will be 0/-1.
+ *
+ * @param which UProperty selector constant, identifies which binary property to check.
+ *        Must be UCHAR_BINARY_START<=which<UCHAR_BINARY_LIMIT
+ *        or UCHAR_INT_START<=which<UCHAR_INT_LIMIT.
+ * @return Maximum value returned by u_getIntPropertyValue for a Unicode property.
+ *         <=0 if the property selector is out of range.
+ *
+ * @see UProperty
+ * @see u_hasBinaryProperty
+ * @see u_getUnicodeVersion
+ * @see u_getIntPropertyMaxValue
+ * @see u_getIntPropertyValue
+ * @stable ICU 2.2
+ */
+U_STABLE int32_t U_EXPORT2
+u_getIntPropertyMaxValue(UProperty which);
+
+/**
+ * Get the numeric value for a Unicode code point as defined in the
+ * Unicode Character Database.
+ *
+ * A "double" return type is necessary because
+ * some numeric values are fractions, negative, or too large for int32_t.
+ *
+ * For characters without any numeric values in the Unicode Character Database,
+ * this function will return U_NO_NUMERIC_VALUE.
+ *
+ * Similar to java.lang.Character.getNumericValue(), but u_getNumericValue()
+ * also supports negative values, large values, and fractions,
+ * while Java's getNumericValue() returns values 10..35 for ASCII letters.
+ *
+ * @param c Code point to get the numeric value for.
+ * @return Numeric value of c, or U_NO_NUMERIC_VALUE if none is defined.
+ *
+ * @see U_NO_NUMERIC_VALUE
+ * @stable ICU 2.2
+ */
+U_STABLE double U_EXPORT2
+u_getNumericValue(UChar32 c);
+
+/**
+ * Special value that is returned by u_getNumericValue when
+ * no numeric value is defined for a code point.
+ *
+ * @see u_getNumericValue
+ * @stable ICU 2.2
+ */
+#define U_NO_NUMERIC_VALUE ((double)-123456789.)
+
+/**
+ * Determines whether the specified code point has the general category "Ll"
+ * (lowercase letter).
+ *
+ * Same as java.lang.Character.isLowerCase().
+ *
+ * This misses some characters that are also lowercase but
+ * have a different general category value.
+ * In order to include those, use UCHAR_LOWERCASE.
+ *
+ * In addition to being equivalent to a Java function, this also serves
+ * as a C/POSIX migration function.
+ * See the comments about C/POSIX character classification functions in the
+ * documentation at the top of this header file.
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point is an Ll lowercase letter
+ *
+ * @see UCHAR_LOWERCASE
+ * @see u_isupper
+ * @see u_istitle
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+u_islower(UChar32 c);
+
+/**
+ * Determines whether the specified code point has the general category "Lu"
+ * (uppercase letter).
+ *
+ * Same as java.lang.Character.isUpperCase().
+ *
+ * This misses some characters that are also uppercase but
+ * have a different general category value.
+ * In order to include those, use UCHAR_UPPERCASE.
+ *
+ * In addition to being equivalent to a Java function, this also serves
+ * as a C/POSIX migration function.
+ * See the comments about C/POSIX character classification functions in the
+ * documentation at the top of this header file.
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point is an Lu uppercase letter
+ *
+ * @see UCHAR_UPPERCASE
+ * @see u_islower
+ * @see u_istitle
+ * @see u_tolower
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+u_isupper(UChar32 c);
+
+/**
+ * Determines whether the specified code point is a titlecase letter.
+ * True for general category "Lt" (titlecase letter).
+ *
+ * Same as java.lang.Character.isTitleCase().
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point is an Lt titlecase letter
+ *
+ * @see u_isupper
+ * @see u_islower
+ * @see u_totitle
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+u_istitle(UChar32 c);
+
+/**
+ * Determines whether the specified code point is a digit character according to Java.
+ * True for characters with general category "Nd" (decimal digit numbers).
+ * Beginning with Unicode 4, this is the same as
+ * testing for the Numeric_Type of Decimal.
+ *
+ * Same as java.lang.Character.isDigit().
+ *
+ * In addition to being equivalent to a Java function, this also serves
+ * as a C/POSIX migration function.
+ * See the comments about C/POSIX character classification functions in the
+ * documentation at the top of this header file.
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point is a digit character according to Character.isDigit()
+ *
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+u_isdigit(UChar32 c);
+
+/**
+ * Determines whether the specified code point is a letter character.
+ * True for general categories "L" (letters).
+ *
+ * Same as java.lang.Character.isLetter().
+ *
+ * In addition to being equivalent to a Java function, this also serves
+ * as a C/POSIX migration function.
+ * See the comments about C/POSIX character classification functions in the
+ * documentation at the top of this header file.
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point is a letter character
+ *
+ * @see u_isdigit
+ * @see u_isalnum
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+u_isalpha(UChar32 c);
+
+/**
+ * Determines whether the specified code point is an alphanumeric character
+ * (letter or digit) according to Java.
+ * True for characters with general categories
+ * "L" (letters) and "Nd" (decimal digit numbers).
+ *
+ * Same as java.lang.Character.isLetterOrDigit().
+ *
+ * In addition to being equivalent to a Java function, this also serves
+ * as a C/POSIX migration function.
+ * See the comments about C/POSIX character classification functions in the
+ * documentation at the top of this header file.
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point is an alphanumeric character according to Character.isLetterOrDigit()
+ *
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+u_isalnum(UChar32 c);
+
+/**
+ * Determines whether the specified code point is a hexadecimal digit.
+ * This is equivalent to u_digit(c, 16)>=0.
+ * True for characters with general category "Nd" (decimal digit numbers)
+ * as well as Latin letters a-f and A-F in both ASCII and Fullwidth ASCII.
+ * (That is, for letters with code points
+ * 0041..0046, 0061..0066, FF21..FF26, FF41..FF46.)
+ *
+ * In order to narrow the definition of hexadecimal digits to only ASCII
+ * characters, use (c<=0x7f && u_isxdigit(c)).
+ *
+ * This is a C/POSIX migration function.
+ * See the comments about C/POSIX character classification functions in the
+ * documentation at the top of this header file.
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point is a hexadecimal digit
+ *
+ * @stable ICU 2.6
+ */
+U_STABLE UBool U_EXPORT2
+u_isxdigit(UChar32 c);
+
+/**
+ * Determines whether the specified code point is a punctuation character.
+ * True for characters with general categories "P" (punctuation).
+ *
+ * This is a C/POSIX migration function.
+ * See the comments about C/POSIX character classification functions in the
+ * documentation at the top of this header file.
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point is a punctuation character
+ *
+ * @stable ICU 2.6
+ */
+U_STABLE UBool U_EXPORT2
+u_ispunct(UChar32 c);
+
+/**
+ * Determines whether the specified code point is a "graphic" character
+ * (printable, excluding spaces).
+ * TRUE for all characters except those with general categories
+ * "Cc" (control codes), "Cf" (format controls), "Cs" (surrogates),
+ * "Cn" (unassigned), and "Z" (separators).
+ *
+ * This is a C/POSIX migration function.
+ * See the comments about C/POSIX character classification functions in the
+ * documentation at the top of this header file.
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point is a "graphic" character
+ *
+ * @stable ICU 2.6
+ */
+U_STABLE UBool U_EXPORT2
+u_isgraph(UChar32 c);
+
+/**
+ * Determines whether the specified code point is a "blank" or "horizontal space",
+ * a character that visibly separates words on a line.
+ * The following are equivalent definitions:
+ *
+ * TRUE for Unicode White_Space characters except for "vertical space controls"
+ * where "vertical space controls" are the following characters:
+ * U+000A (LF) U+000B (VT) U+000C (FF) U+000D (CR) U+0085 (NEL) U+2028 (LS) U+2029 (PS)
+ *
+ * same as
+ *
+ * TRUE for U+0009 (TAB) and characters with general category "Zs" (space separators)
+ * except Zero Width Space (ZWSP, U+200B).
+ *
+ * Note: There are several ICU whitespace functions; please see the uchar.h
+ * file documentation for a detailed comparison.
+ *
+ * This is a C/POSIX migration function.
+ * See the comments about C/POSIX character classification functions in the
+ * documentation at the top of this header file.
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point is a "blank"
+ *
+ * @stable ICU 2.6
+ */
+U_STABLE UBool U_EXPORT2
+u_isblank(UChar32 c);
+
+/**
+ * Determines whether the specified code point is "defined",
+ * which usually means that it is assigned a character.
+ * True for general categories other than "Cn" (other, not assigned),
+ * i.e., true for all code points mentioned in UnicodeData.txt.
+ *
+ * Note that non-character code points (e.g., U+FDD0) are not "defined"
+ * (they are Cn), but surrogate code points are "defined" (Cs).
+ *
+ * Same as java.lang.Character.isDefined().
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point is assigned a character
+ *
+ * @see u_isdigit
+ * @see u_isalpha
+ * @see u_isalnum
+ * @see u_isupper
+ * @see u_islower
+ * @see u_istitle
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+u_isdefined(UChar32 c);
+
+/**
+ * Determines if the specified character is a space character or not.
+ *
+ * Note: There are several ICU whitespace functions; please see the uchar.h
+ * file documentation for a detailed comparison.
+ *
+ * This is a C/POSIX migration function.
+ * See the comments about C/POSIX character classification functions in the
+ * documentation at the top of this header file.
+ *
+ * @param c    the character to be tested
+ * @return  true if the character is a space character; false otherwise.
+ *
+ * @see u_isJavaSpaceChar
+ * @see u_isWhitespace
+ * @see u_isUWhiteSpace
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+u_isspace(UChar32 c);
+
+/**
+ * Determine if the specified code point is a space character according to Java.
+ * True for characters with general categories "Z" (separators),
+ * which does not include control codes (e.g., TAB or Line Feed).
+ *
+ * Same as java.lang.Character.isSpaceChar().
+ *
+ * Note: There are several ICU whitespace functions; please see the uchar.h
+ * file documentation for a detailed comparison.
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point is a space character according to Character.isSpaceChar()
+ *
+ * @see u_isspace
+ * @see u_isWhitespace
+ * @see u_isUWhiteSpace
+ * @stable ICU 2.6
+ */
+U_STABLE UBool U_EXPORT2
+u_isJavaSpaceChar(UChar32 c);
+
+/**
+ * Determines if the specified code point is a whitespace character according to Java/ICU.
+ * A character is considered to be a Java whitespace character if and only
+ * if it satisfies one of the following criteria:
+ *
+ * - It is a Unicode Separator character (categories "Z" = "Zs" or "Zl" or "Zp"), but is not
+ *      also a non-breaking space (U+00A0 NBSP or U+2007 Figure Space or U+202F Narrow NBSP).
+ * - It is U+0009 HORIZONTAL TABULATION.
+ * - It is U+000A LINE FEED.
+ * - It is U+000B VERTICAL TABULATION.
+ * - It is U+000C FORM FEED.
+ * - It is U+000D CARRIAGE RETURN.
+ * - It is U+001C FILE SEPARATOR.
+ * - It is U+001D GROUP SEPARATOR.
+ * - It is U+001E RECORD SEPARATOR.
+ * - It is U+001F UNIT SEPARATOR.
+ *
+ * This API tries to sync with the semantics of Java's
+ * java.lang.Character.isWhitespace(), but it may not return
+ * the exact same results because of the Unicode version
+ * difference.
+ *
+ * Note: Unicode 4.0.1 changed U+200B ZERO WIDTH SPACE from a Space Separator (Zs)
+ * to a Format Control (Cf). Since then, isWhitespace(0x200b) returns false.
+ * See http://www.unicode.org/versions/Unicode4.0.1/
+ *
+ * Note: There are several ICU whitespace functions; please see the uchar.h
+ * file documentation for a detailed comparison.
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point is a whitespace character according to Java/ICU
+ *
+ * @see u_isspace
+ * @see u_isJavaSpaceChar
+ * @see u_isUWhiteSpace
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+u_isWhitespace(UChar32 c);
+
+/**
+ * Determines whether the specified code point is a control character
+ * (as defined by this function).
+ * A control character is one of the following:
+ * - ISO 8-bit control character (U+0000..U+001f and U+007f..U+009f)
+ * - U_CONTROL_CHAR (Cc)
+ * - U_FORMAT_CHAR (Cf)
+ * - U_LINE_SEPARATOR (Zl)
+ * - U_PARAGRAPH_SEPARATOR (Zp)
+ *
+ * This is a C/POSIX migration function.
+ * See the comments about C/POSIX character classification functions in the
+ * documentation at the top of this header file.
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point is a control character
+ *
+ * @see UCHAR_DEFAULT_IGNORABLE_CODE_POINT
+ * @see u_isprint
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+u_iscntrl(UChar32 c);
+
+/**
+ * Determines whether the specified code point is an ISO control code.
+ * True for U+0000..U+001f and U+007f..U+009f (general category "Cc").
+ *
+ * Same as java.lang.Character.isISOControl().
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point is an ISO control code
+ *
+ * @see u_iscntrl
+ * @stable ICU 2.6
+ */
+U_STABLE UBool U_EXPORT2
+u_isISOControl(UChar32 c);
+
+/**
+ * Determines whether the specified code point is a printable character.
+ * True for general categories <em>other</em> than "C" (controls).
+ *
+ * This is a C/POSIX migration function.
+ * See the comments about C/POSIX character classification functions in the
+ * documentation at the top of this header file.
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point is a printable character
+ *
+ * @see UCHAR_DEFAULT_IGNORABLE_CODE_POINT
+ * @see u_iscntrl
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+u_isprint(UChar32 c);
+
+/**
+ * Determines whether the specified code point is a base character.
+ * True for general categories "L" (letters), "N" (numbers),
+ * "Mc" (spacing combining marks), and "Me" (enclosing marks).
+ *
+ * Note that this is different from the Unicode definition in
+ * chapter 3.5, conformance clause D13,
+ * which defines base characters to be all characters (not Cn)
+ * that do not graphically combine with preceding characters (M)
+ * and that are neither control (Cc) or format (Cf) characters.
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point is a base character according to this function
+ *
+ * @see u_isalpha
+ * @see u_isdigit
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+u_isbase(UChar32 c);
+
+/**
+ * Returns the bidirectional category value for the code point,
+ * which is used in the Unicode bidirectional algorithm
+ * (UAX #9 http://www.unicode.org/reports/tr9/).
+ * Note that some <em>unassigned</em> code points have bidi values
+ * of R or AL because they are in blocks that are reserved
+ * for Right-To-Left scripts.
+ *
+ * Same as java.lang.Character.getDirectionality()
+ *
+ * @param c the code point to be tested
+ * @return the bidirectional category (UCharDirection) value
+ *
+ * @see UCharDirection
+ * @stable ICU 2.0
+ */
+U_STABLE UCharDirection U_EXPORT2
+u_charDirection(UChar32 c);
+
+/**
+ * Determines whether the code point has the Bidi_Mirrored property.
+ * This property is set for characters that are commonly used in
+ * Right-To-Left contexts and need to be displayed with a "mirrored"
+ * glyph.
+ *
+ * Same as java.lang.Character.isMirrored().
+ * Same as UCHAR_BIDI_MIRRORED
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the character has the Bidi_Mirrored property
+ *
+ * @see UCHAR_BIDI_MIRRORED
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+u_isMirrored(UChar32 c);
+
+/**
+ * Maps the specified character to a "mirror-image" character.
+ * For characters with the Bidi_Mirrored property, implementations
+ * sometimes need a "poor man's" mapping to another Unicode
+ * character (code point) such that the default glyph may serve
+ * as the mirror-image of the default glyph of the specified
+ * character. This is useful for text conversion to and from
+ * codepages with visual order, and for displays without glyph
+ * selecetion capabilities.
+ *
+ * @param c the code point to be mapped
+ * @return another Unicode code point that may serve as a mirror-image
+ *         substitute, or c itself if there is no such mapping or c
+ *         does not have the Bidi_Mirrored property
+ *
+ * @see UCHAR_BIDI_MIRRORED
+ * @see u_isMirrored
+ * @stable ICU 2.0
+ */
+U_STABLE UChar32 U_EXPORT2
+u_charMirror(UChar32 c);
+
+/**
+ * Returns the general category value for the code point.
+ *
+ * Same as java.lang.Character.getType().
+ *
+ * @param c the code point to be tested
+ * @return the general category (UCharCategory) value
+ *
+ * @see UCharCategory
+ * @stable ICU 2.0
+ */
+U_STABLE int8_t U_EXPORT2
+u_charType(UChar32 c);
+
+/**
+ * Get a single-bit bit set for the general category of a character.
+ * This bit set can be compared bitwise with U_GC_SM_MASK, U_GC_L_MASK, etc.
+ * Same as U_MASK(u_charType(c)).
+ *
+ * @param c the code point to be tested
+ * @return a single-bit mask corresponding to the general category (UCharCategory) value
+ *
+ * @see u_charType
+ * @see UCharCategory
+ * @see U_GC_CN_MASK
+ * @stable ICU 2.1
+ */
+#define U_GET_GC_MASK(c) U_MASK(u_charType(c))
+
+/**
+ * Callback from u_enumCharTypes(), is called for each contiguous range
+ * of code points c (where start<=c<limit)
+ * with the same Unicode general category ("character type").
+ *
+ * The callback function can stop the enumeration by returning FALSE.
+ *
+ * @param context an opaque pointer, as passed into utrie_enum()
+ * @param start the first code point in a contiguous range with value
+ * @param limit one past the last code point in a contiguous range with value
+ * @param type the general category for all code points in [start..limit[
+ * @return FALSE to stop the enumeration
+ *
+ * @stable ICU 2.1
+ * @see UCharCategory
+ * @see u_enumCharTypes
+ */
+typedef UBool U_CALLCONV
+UCharEnumTypeRange(const void *context, UChar32 start, UChar32 limit, UCharCategory type);
+
+/**
+ * Enumerate efficiently all code points with their Unicode general categories.
+ *
+ * This is useful for building data structures (e.g., UnicodeSet's),
+ * for enumerating all assigned code points (type!=U_UNASSIGNED), etc.
+ *
+ * For each contiguous range of code points with a given general category ("character type"),
+ * the UCharEnumTypeRange function is called.
+ * Adjacent ranges have different types.
+ * The Unicode Standard guarantees that the numeric value of the type is 0..31.
+ *
+ * @param enumRange a pointer to a function that is called for each contiguous range
+ *                  of code points with the same general category
+ * @param context an opaque pointer that is passed on to the callback function
+ *
+ * @stable ICU 2.1
+ * @see UCharCategory
+ * @see UCharEnumTypeRange
+ */
+U_STABLE void U_EXPORT2
+u_enumCharTypes(UCharEnumTypeRange *enumRange, const void *context);
+
+#if !UCONFIG_NO_NORMALIZATION
+
+/**
+ * Returns the combining class of the code point as specified in UnicodeData.txt.
+ *
+ * @param c the code point of the character
+ * @return the combining class of the character
+ * @stable ICU 2.0
+ */
+U_STABLE uint8_t U_EXPORT2
+u_getCombiningClass(UChar32 c);
+
+#endif
+
+/**
+ * Returns the decimal digit value of a decimal digit character.
+ * Such characters have the general category "Nd" (decimal digit numbers)
+ * and a Numeric_Type of Decimal.
+ *
+ * Unlike ICU releases before 2.6, no digit values are returned for any
+ * Han characters because Han number characters are often used with a special
+ * Chinese-style number format (with characters for powers of 10 in between)
+ * instead of in decimal-positional notation.
+ * Unicode 4 explicitly assigns Han number characters the Numeric_Type
+ * Numeric instead of Decimal.
+ * See Jitterbug 1483 for more details.
+ *
+ * Use u_getIntPropertyValue(c, UCHAR_NUMERIC_TYPE) and u_getNumericValue()
+ * for complete numeric Unicode properties.
+ *
+ * @param c the code point for which to get the decimal digit value
+ * @return the decimal digit value of c,
+ *         or -1 if c is not a decimal digit character
+ *
+ * @see u_getNumericValue
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_charDigitValue(UChar32 c);
+
+/**
+ * Returns the Unicode allocation block that contains the character.
+ *
+ * @param c the code point to be tested
+ * @return the block value (UBlockCode) for c
+ *
+ * @see UBlockCode
+ * @stable ICU 2.0
+ */
+U_STABLE UBlockCode U_EXPORT2
+ublock_getCode(UChar32 c);
+
+/**
+ * Retrieve the name of a Unicode character.
+ * Depending on <code>nameChoice</code>, the character name written
+ * into the buffer is the "modern" name or the name that was defined
+ * in Unicode version 1.0.
+ * The name contains only "invariant" characters
+ * like A-Z, 0-9, space, and '-'.
+ * Unicode 1.0 names are only retrieved if they are different from the modern
+ * names and if the data file contains the data for them. gennames may or may
+ * not be called with a command line option to include 1.0 names in unames.dat.
+ *
+ * @param code The character (code point) for which to get the name.
+ *             It must be <code>0<=code<=0x10ffff</code>.
+ * @param nameChoice Selector for which name to get.
+ * @param buffer Destination address for copying the name.
+ *               The name will always be zero-terminated.
+ *               If there is no name, then the buffer will be set to the empty string.
+ * @param bufferLength <code>==sizeof(buffer)</code>
+ * @param pErrorCode Pointer to a UErrorCode variable;
+ *        check for <code>U_SUCCESS()</code> after <code>u_charName()</code>
+ *        returns.
+ * @return The length of the name, or 0 if there is no name for this character.
+ *         If the bufferLength is less than or equal to the length, then the buffer
+ *         contains the truncated name and the returned length indicates the full
+ *         length of the name.
+ *         The length does not include the zero-termination.
+ *
+ * @see UCharNameChoice
+ * @see u_charFromName
+ * @see u_enumCharNames
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_charName(UChar32 code, UCharNameChoice nameChoice,
+           char *buffer, int32_t bufferLength,
+           UErrorCode *pErrorCode);
+
+/**
+ * Get the ISO 10646 comment for a character.
+ * The ISO 10646 comment is an informative field in the Unicode Character
+ * Database (UnicodeData.txt field 11) and is from the ISO 10646 names list.
+ *
+ * Note: Unicode 5.2 removes all ISO comment data, resulting in empty strings
+ * returned for all characters.
+ *
+ * @param c The character (code point) for which to get the ISO comment.
+ *             It must be <code>0<=c<=0x10ffff</code>.
+ * @param dest Destination address for copying the comment.
+ *             The comment will be zero-terminated if possible.
+ *             If there is no comment, then the buffer will be set to the empty string.
+ * @param destCapacity <code>==sizeof(dest)</code>
+ * @param pErrorCode Pointer to a UErrorCode variable;
+ *        check for <code>U_SUCCESS()</code> after <code>u_getISOComment()</code>
+ *        returns.
+ * @return The length of the comment, or 0 if there is no comment for this character.
+ *         If the destCapacity is less than or equal to the length, then the buffer
+ *         contains the truncated name and the returned length indicates the full
+ *         length of the name.
+ *         The length does not include the zero-termination.
+ *
+ * @stable ICU 2.2
+ */
+U_STABLE int32_t U_EXPORT2
+u_getISOComment(UChar32 c,
+                char *dest, int32_t destCapacity,
+                UErrorCode *pErrorCode);
+
+/**
+ * Find a Unicode character by its name and return its code point value.
+ * The name is matched exactly and completely.
+ * If the name does not correspond to a code point, <i>pErrorCode</i>
+ * is set to <code>U_INVALID_CHAR_FOUND</code>.
+ * A Unicode 1.0 name is matched only if it differs from the modern name.
+ * Unicode names are all uppercase. Extended names are lowercase followed
+ * by an uppercase hexadecimal number, and within angle brackets.
+ *
+ * @param nameChoice Selector for which name to match.
+ * @param name The name to match.
+ * @param pErrorCode Pointer to a UErrorCode variable
+ * @return The Unicode value of the code point with the given name,
+ *         or an undefined value if there is no such code point.
+ *
+ * @see UCharNameChoice
+ * @see u_charName
+ * @see u_enumCharNames
+ * @stable ICU 1.7
+ */
+U_STABLE UChar32 U_EXPORT2
+u_charFromName(UCharNameChoice nameChoice,
+               const char *name,
+               UErrorCode *pErrorCode);
+
+/**
+ * Type of a callback function for u_enumCharNames() that gets called
+ * for each Unicode character with the code point value and
+ * the character name.
+ * If such a function returns FALSE, then the enumeration is stopped.
+ *
+ * @param context The context pointer that was passed to u_enumCharNames().
+ * @param code The Unicode code point for the character with this name.
+ * @param nameChoice Selector for which kind of names is enumerated.
+ * @param name The character's name, zero-terminated.
+ * @param length The length of the name.
+ * @return TRUE if the enumeration should continue, FALSE to stop it.
+ *
+ * @see UCharNameChoice
+ * @see u_enumCharNames
+ * @stable ICU 1.7
+ */
+typedef UBool U_CALLCONV UEnumCharNamesFn(void *context,
+                               UChar32 code,
+                               UCharNameChoice nameChoice,
+                               const char *name,
+                               int32_t length);
+
+/**
+ * Enumerate all assigned Unicode characters between the start and limit
+ * code points (start inclusive, limit exclusive) and call a function
+ * for each, passing the code point value and the character name.
+ * For Unicode 1.0 names, only those are enumerated that differ from the
+ * modern names.
+ *
+ * @param start The first code point in the enumeration range.
+ * @param limit One more than the last code point in the enumeration range
+ *              (the first one after the range).
+ * @param fn The function that is to be called for each character name.
+ * @param context An arbitrary pointer that is passed to the function.
+ * @param nameChoice Selector for which kind of names to enumerate.
+ * @param pErrorCode Pointer to a UErrorCode variable
+ *
+ * @see UCharNameChoice
+ * @see UEnumCharNamesFn
+ * @see u_charName
+ * @see u_charFromName
+ * @stable ICU 1.7
+ */
+U_STABLE void U_EXPORT2
+u_enumCharNames(UChar32 start, UChar32 limit,
+                UEnumCharNamesFn *fn,
+                void *context,
+                UCharNameChoice nameChoice,
+                UErrorCode *pErrorCode);
+
+/**
+ * Return the Unicode name for a given property, as given in the
+ * Unicode database file PropertyAliases.txt.
+ *
+ * In addition, this function maps the property
+ * UCHAR_GENERAL_CATEGORY_MASK to the synthetic names "gcm" /
+ * "General_Category_Mask".  These names are not in
+ * PropertyAliases.txt.
+ *
+ * @param property UProperty selector other than UCHAR_INVALID_CODE.
+ *         If out of range, NULL is returned.
+ *
+ * @param nameChoice selector for which name to get.  If out of range,
+ *         NULL is returned.  All properties have a long name.  Most
+ *         have a short name, but some do not.  Unicode allows for
+ *         additional names; if present these will be returned by
+ *         U_LONG_PROPERTY_NAME + i, where i=1, 2,...
+ *
+ * @return a pointer to the name, or NULL if either the
+ *         property or the nameChoice is out of range.  If a given
+ *         nameChoice returns NULL, then all larger values of
+ *         nameChoice will return NULL, with one exception: if NULL is
+ *         returned for U_SHORT_PROPERTY_NAME, then
+ *         U_LONG_PROPERTY_NAME (and higher) may still return a
+ *         non-NULL value.  The returned pointer is valid until
+ *         u_cleanup() is called.
+ *
+ * @see UProperty
+ * @see UPropertyNameChoice
+ * @stable ICU 2.4
+ */
+U_STABLE const char* U_EXPORT2
+u_getPropertyName(UProperty property,
+                  UPropertyNameChoice nameChoice);
+
+/**
+ * Return the UProperty enum for a given property name, as specified
+ * in the Unicode database file PropertyAliases.txt.  Short, long, and
+ * any other variants are recognized.
+ *
+ * In addition, this function maps the synthetic names "gcm" /
+ * "General_Category_Mask" to the property
+ * UCHAR_GENERAL_CATEGORY_MASK.  These names are not in
+ * PropertyAliases.txt.
+ *
+ * @param alias the property name to be matched.  The name is compared
+ *         using "loose matching" as described in PropertyAliases.txt.
+ *
+ * @return a UProperty enum, or UCHAR_INVALID_CODE if the given name
+ *         does not match any property.
+ *
+ * @see UProperty
+ * @stable ICU 2.4
+ */
+U_STABLE UProperty U_EXPORT2
+u_getPropertyEnum(const char* alias);
+
+/**
+ * Return the Unicode name for a given property value, as given in the
+ * Unicode database file PropertyValueAliases.txt.
+ *
+ * Note: Some of the names in PropertyValueAliases.txt can only be
+ * retrieved using UCHAR_GENERAL_CATEGORY_MASK, not
+ * UCHAR_GENERAL_CATEGORY.  These include: "C" / "Other", "L" /
+ * "Letter", "LC" / "Cased_Letter", "M" / "Mark", "N" / "Number", "P"
+ * / "Punctuation", "S" / "Symbol", and "Z" / "Separator".
+ *
+ * @param property UProperty selector constant.
+ *        Must be UCHAR_BINARY_START<=which<UCHAR_BINARY_LIMIT
+ *        or UCHAR_INT_START<=which<UCHAR_INT_LIMIT
+ *        or UCHAR_MASK_START<=which<UCHAR_MASK_LIMIT.
+ *        If out of range, NULL is returned.
+ *
+ * @param value selector for a value for the given property.  If out
+ *         of range, NULL is returned.  In general, valid values range
+ *         from 0 up to some maximum.  There are a few exceptions:
+ *         (1.) UCHAR_BLOCK values begin at the non-zero value
+ *         UBLOCK_BASIC_LATIN.  (2.)  UCHAR_CANONICAL_COMBINING_CLASS
+ *         values are not contiguous and range from 0..240.  (3.)
+ *         UCHAR_GENERAL_CATEGORY_MASK values are not values of
+ *         UCharCategory, but rather mask values produced by
+ *         U_GET_GC_MASK().  This allows grouped categories such as
+ *         [:L:] to be represented.  Mask values range
+ *         non-contiguously from 1..U_GC_P_MASK.
+ *
+ * @param nameChoice selector for which name to get.  If out of range,
+ *         NULL is returned.  All values have a long name.  Most have
+ *         a short name, but some do not.  Unicode allows for
+ *         additional names; if present these will be returned by
+ *         U_LONG_PROPERTY_NAME + i, where i=1, 2,...
+
+ * @return a pointer to the name, or NULL if either the
+ *         property or the nameChoice is out of range.  If a given
+ *         nameChoice returns NULL, then all larger values of
+ *         nameChoice will return NULL, with one exception: if NULL is
+ *         returned for U_SHORT_PROPERTY_NAME, then
+ *         U_LONG_PROPERTY_NAME (and higher) may still return a
+ *         non-NULL value.  The returned pointer is valid until
+ *         u_cleanup() is called.
+ *
+ * @see UProperty
+ * @see UPropertyNameChoice
+ * @stable ICU 2.4
+ */
+U_STABLE const char* U_EXPORT2
+u_getPropertyValueName(UProperty property,
+                       int32_t value,
+                       UPropertyNameChoice nameChoice);
+
+/**
+ * Return the property value integer for a given value name, as
+ * specified in the Unicode database file PropertyValueAliases.txt.
+ * Short, long, and any other variants are recognized.
+ *
+ * Note: Some of the names in PropertyValueAliases.txt will only be
+ * recognized with UCHAR_GENERAL_CATEGORY_MASK, not
+ * UCHAR_GENERAL_CATEGORY.  These include: "C" / "Other", "L" /
+ * "Letter", "LC" / "Cased_Letter", "M" / "Mark", "N" / "Number", "P"
+ * / "Punctuation", "S" / "Symbol", and "Z" / "Separator".
+ *
+ * @param property UProperty selector constant.
+ *        Must be UCHAR_BINARY_START<=which<UCHAR_BINARY_LIMIT
+ *        or UCHAR_INT_START<=which<UCHAR_INT_LIMIT
+ *        or UCHAR_MASK_START<=which<UCHAR_MASK_LIMIT.
+ *        If out of range, UCHAR_INVALID_CODE is returned.
+ *
+ * @param alias the value name to be matched.  The name is compared
+ *         using "loose matching" as described in
+ *         PropertyValueAliases.txt.
+ *
+ * @return a value integer or UCHAR_INVALID_CODE if the given name
+ *         does not match any value of the given property, or if the
+ *         property is invalid.  Note: UCHAR_GENERAL_CATEGORY_MASK values
+ *         are not values of UCharCategory, but rather mask values
+ *         produced by U_GET_GC_MASK().  This allows grouped
+ *         categories such as [:L:] to be represented.
+ *
+ * @see UProperty
+ * @stable ICU 2.4
+ */
+U_STABLE int32_t U_EXPORT2
+u_getPropertyValueEnum(UProperty property,
+                       const char* alias);
+
+/**
+ * Determines if the specified character is permissible as the
+ * first character in an identifier according to Unicode
+ * (The Unicode Standard, Version 3.0, chapter 5.16 Identifiers).
+ * True for characters with general categories "L" (letters) and "Nl" (letter numbers).
+ *
+ * Same as java.lang.Character.isUnicodeIdentifierStart().
+ * Same as UCHAR_ID_START
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point may start an identifier
+ *
+ * @see UCHAR_ID_START
+ * @see u_isalpha
+ * @see u_isIDPart
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+u_isIDStart(UChar32 c);
+
+/**
+ * Determines if the specified character is permissible
+ * in an identifier according to Java.
+ * True for characters with general categories "L" (letters),
+ * "Nl" (letter numbers), "Nd" (decimal digits),
+ * "Mc" and "Mn" (combining marks), "Pc" (connecting punctuation), and
+ * u_isIDIgnorable(c).
+ *
+ * Same as java.lang.Character.isUnicodeIdentifierPart().
+ * Almost the same as Unicode's ID_Continue (UCHAR_ID_CONTINUE)
+ * except that Unicode recommends to ignore Cf which is less than
+ * u_isIDIgnorable(c).
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point may occur in an identifier according to Java
+ *
+ * @see UCHAR_ID_CONTINUE
+ * @see u_isIDStart
+ * @see u_isIDIgnorable
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+u_isIDPart(UChar32 c);
+
+/**
+ * Determines if the specified character should be regarded
+ * as an ignorable character in an identifier,
+ * according to Java.
+ * True for characters with general category "Cf" (format controls) as well as
+ * non-whitespace ISO controls
+ * (U+0000..U+0008, U+000E..U+001B, U+007F..U+009F).
+ *
+ * Same as java.lang.Character.isIdentifierIgnorable().
+ *
+ * Note that Unicode just recommends to ignore Cf (format controls).
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point is ignorable in identifiers according to Java
+ *
+ * @see UCHAR_DEFAULT_IGNORABLE_CODE_POINT
+ * @see u_isIDStart
+ * @see u_isIDPart
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+u_isIDIgnorable(UChar32 c);
+
+/**
+ * Determines if the specified character is permissible as the
+ * first character in a Java identifier.
+ * In addition to u_isIDStart(c), true for characters with
+ * general categories "Sc" (currency symbols) and "Pc" (connecting punctuation).
+ *
+ * Same as java.lang.Character.isJavaIdentifierStart().
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point may start a Java identifier
+ *
+ * @see     u_isJavaIDPart
+ * @see     u_isalpha
+ * @see     u_isIDStart
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+u_isJavaIDStart(UChar32 c);
+
+/**
+ * Determines if the specified character is permissible
+ * in a Java identifier.
+ * In addition to u_isIDPart(c), true for characters with
+ * general category "Sc" (currency symbols).
+ *
+ * Same as java.lang.Character.isJavaIdentifierPart().
+ *
+ * @param c the code point to be tested
+ * @return TRUE if the code point may occur in a Java identifier
+ *
+ * @see     u_isIDIgnorable
+ * @see     u_isJavaIDStart
+ * @see     u_isalpha
+ * @see     u_isdigit
+ * @see     u_isIDPart
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+u_isJavaIDPart(UChar32 c);
+
+/**
+ * The given character is mapped to its lowercase equivalent according to
+ * UnicodeData.txt; if the character has no lowercase equivalent, the character
+ * itself is returned.
+ *
+ * Same as java.lang.Character.toLowerCase().
+ *
+ * This function only returns the simple, single-code point case mapping.
+ * Full case mappings should be used whenever possible because they produce
+ * better results by working on whole strings.
+ * They take into account the string context and the language and can map
+ * to a result string with a different length as appropriate.
+ * Full case mappings are applied by the string case mapping functions,
+ * see ustring.h and the UnicodeString class.
+ * See also the User Guide chapter on C/POSIX migration:
+ * http://icu-project.org/userguide/posix.html#case_mappings
+ *
+ * @param c the code point to be mapped
+ * @return the Simple_Lowercase_Mapping of the code point, if any;
+ *         otherwise the code point itself.
+ * @stable ICU 2.0
+ */
+U_STABLE UChar32 U_EXPORT2
+u_tolower(UChar32 c);
+
+/**
+ * The given character is mapped to its uppercase equivalent according to UnicodeData.txt;
+ * if the character has no uppercase equivalent, the character itself is
+ * returned.
+ *
+ * Same as java.lang.Character.toUpperCase().
+ *
+ * This function only returns the simple, single-code point case mapping.
+ * Full case mappings should be used whenever possible because they produce
+ * better results by working on whole strings.
+ * They take into account the string context and the language and can map
+ * to a result string with a different length as appropriate.
+ * Full case mappings are applied by the string case mapping functions,
+ * see ustring.h and the UnicodeString class.
+ * See also the User Guide chapter on C/POSIX migration:
+ * http://icu-project.org/userguide/posix.html#case_mappings
+ *
+ * @param c the code point to be mapped
+ * @return the Simple_Uppercase_Mapping of the code point, if any;
+ *         otherwise the code point itself.
+ * @stable ICU 2.0
+ */
+U_STABLE UChar32 U_EXPORT2
+u_toupper(UChar32 c);
+
+/**
+ * The given character is mapped to its titlecase equivalent
+ * according to UnicodeData.txt;
+ * if none is defined, the character itself is returned.
+ *
+ * Same as java.lang.Character.toTitleCase().
+ *
+ * This function only returns the simple, single-code point case mapping.
+ * Full case mappings should be used whenever possible because they produce
+ * better results by working on whole strings.
+ * They take into account the string context and the language and can map
+ * to a result string with a different length as appropriate.
+ * Full case mappings are applied by the string case mapping functions,
+ * see ustring.h and the UnicodeString class.
+ * See also the User Guide chapter on C/POSIX migration:
+ * http://icu-project.org/userguide/posix.html#case_mappings
+ *
+ * @param c the code point to be mapped
+ * @return the Simple_Titlecase_Mapping of the code point, if any;
+ *         otherwise the code point itself.
+ * @stable ICU 2.0
+ */
+U_STABLE UChar32 U_EXPORT2
+u_totitle(UChar32 c);
+
+/** Option value for case folding: use default mappings defined in CaseFolding.txt. @stable ICU 2.0 */
+#define U_FOLD_CASE_DEFAULT 0
+
+/**
+ * Option value for case folding:
+ *
+ * Use the modified set of mappings provided in CaseFolding.txt to handle dotted I
+ * and dotless i appropriately for Turkic languages (tr, az).
+ *
+ * Before Unicode 3.2, CaseFolding.txt contains mappings marked with 'I' that
+ * are to be included for default mappings and
+ * excluded for the Turkic-specific mappings.
+ *
+ * Unicode 3.2 CaseFolding.txt instead contains mappings marked with 'T' that
+ * are to be excluded for default mappings and
+ * included for the Turkic-specific mappings.
+ *
+ * @stable ICU 2.0
+ */
+#define U_FOLD_CASE_EXCLUDE_SPECIAL_I 1
+
+/**
+ * The given character is mapped to its case folding equivalent according to
+ * UnicodeData.txt and CaseFolding.txt;
+ * if the character has no case folding equivalent, the character
+ * itself is returned.
+ *
+ * This function only returns the simple, single-code point case mapping.
+ * Full case mappings should be used whenever possible because they produce
+ * better results by working on whole strings.
+ * They take into account the string context and the language and can map
+ * to a result string with a different length as appropriate.
+ * Full case mappings are applied by the string case mapping functions,
+ * see ustring.h and the UnicodeString class.
+ * See also the User Guide chapter on C/POSIX migration:
+ * http://icu-project.org/userguide/posix.html#case_mappings
+ *
+ * @param c the code point to be mapped
+ * @param options Either U_FOLD_CASE_DEFAULT or U_FOLD_CASE_EXCLUDE_SPECIAL_I
+ * @return the Simple_Case_Folding of the code point, if any;
+ *         otherwise the code point itself.
+ * @stable ICU 2.0
+ */
+U_STABLE UChar32 U_EXPORT2
+u_foldCase(UChar32 c, uint32_t options);
+
+/**
+ * Returns the decimal digit value of the code point in the
+ * specified radix.
+ *
+ * If the radix is not in the range <code>2<=radix<=36</code> or if the
+ * value of <code>c</code> is not a valid digit in the specified
+ * radix, <code>-1</code> is returned. A character is a valid digit
+ * if at least one of the following is true:
+ * <ul>
+ * <li>The character has a decimal digit value.
+ *     Such characters have the general category "Nd" (decimal digit numbers)
+ *     and a Numeric_Type of Decimal.
+ *     In this case the value is the character's decimal digit value.</li>
+ * <li>The character is one of the uppercase Latin letters
+ *     <code>'A'</code> through <code>'Z'</code>.
+ *     In this case the value is <code>c-'A'+10</code>.</li>
+ * <li>The character is one of the lowercase Latin letters
+ *     <code>'a'</code> through <code>'z'</code>.
+ *     In this case the value is <code>ch-'a'+10</code>.</li>
+ * <li>Latin letters from both the ASCII range (0061..007A, 0041..005A)
+ *     as well as from the Fullwidth ASCII range (FF41..FF5A, FF21..FF3A)
+ *     are recognized.</li>
+ * </ul>
+ *
+ * Same as java.lang.Character.digit().
+ *
+ * @param   ch      the code point to be tested.
+ * @param   radix   the radix.
+ * @return  the numeric value represented by the character in the
+ *          specified radix,
+ *          or -1 if there is no value or if the value exceeds the radix.
+ *
+ * @see     UCHAR_NUMERIC_TYPE
+ * @see     u_forDigit
+ * @see     u_charDigitValue
+ * @see     u_isdigit
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_digit(UChar32 ch, int8_t radix);
+
+/**
+ * Determines the character representation for a specific digit in
+ * the specified radix. If the value of <code>radix</code> is not a
+ * valid radix, or the value of <code>digit</code> is not a valid
+ * digit in the specified radix, the null character
+ * (<code>U+0000</code>) is returned.
+ * <p>
+ * The <code>radix</code> argument is valid if it is greater than or
+ * equal to 2 and less than or equal to 36.
+ * The <code>digit</code> argument is valid if
+ * <code>0 <= digit < radix</code>.
+ * <p>
+ * If the digit is less than 10, then
+ * <code>'0' + digit</code> is returned. Otherwise, the value
+ * <code>'a' + digit - 10</code> is returned.
+ *
+ * Same as java.lang.Character.forDigit().
+ *
+ * @param   digit   the number to convert to a character.
+ * @param   radix   the radix.
+ * @return  the <code>char</code> representation of the specified digit
+ *          in the specified radix.
+ *
+ * @see     u_digit
+ * @see     u_charDigitValue
+ * @see     u_isdigit
+ * @stable ICU 2.0
+ */
+U_STABLE UChar32 U_EXPORT2
+u_forDigit(int32_t digit, int8_t radix);
+
+/**
+ * Get the "age" of the code point.
+ * The "age" is the Unicode version when the code point was first
+ * designated (as a non-character or for Private Use)
+ * or assigned a character.
+ * This can be useful to avoid emitting code points to receiving
+ * processes that do not accept newer characters.
+ * The data is from the UCD file DerivedAge.txt.
+ *
+ * @param c The code point.
+ * @param versionArray The Unicode version number array, to be filled in.
+ *
+ * @stable ICU 2.1
+ */
+U_STABLE void U_EXPORT2
+u_charAge(UChar32 c, UVersionInfo versionArray);
+
+/**
+ * Gets the Unicode version information.
+ * The version array is filled in with the version information
+ * for the Unicode standard that is currently used by ICU.
+ * For example, Unicode version 3.1.1 is represented as an array with
+ * the values { 3, 1, 1, 0 }.
+ *
+ * @param versionArray an output array that will be filled in with
+ *                     the Unicode version number
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+u_getUnicodeVersion(UVersionInfo versionArray);
+
+#if !UCONFIG_NO_NORMALIZATION
+/**
+ * Get the FC_NFKC_Closure property string for a character.
+ * See Unicode Standard Annex #15 for details, search for "FC_NFKC_Closure"
+ * or for "FNC": http://www.unicode.org/reports/tr15/
+ *
+ * @param c The character (code point) for which to get the FC_NFKC_Closure string.
+ *             It must be <code>0<=c<=0x10ffff</code>.
+ * @param dest Destination address for copying the string.
+ *             The string will be zero-terminated if possible.
+ *             If there is no FC_NFKC_Closure string,
+ *             then the buffer will be set to the empty string.
+ * @param destCapacity <code>==sizeof(dest)</code>
+ * @param pErrorCode Pointer to a UErrorCode variable.
+ * @return The length of the string, or 0 if there is no FC_NFKC_Closure string for this character.
+ *         If the destCapacity is less than or equal to the length, then the buffer
+ *         contains the truncated name and the returned length indicates the full
+ *         length of the name.
+ *         The length does not include the zero-termination.
+ *
+ * @stable ICU 2.2
+ */
+U_STABLE int32_t U_EXPORT2
+u_getFC_NFKC_Closure(UChar32 c, UChar *dest, int32_t destCapacity, UErrorCode *pErrorCode);
+
+#endif
+
+
+U_CDECL_END
+
+#endif /*_UCHAR*/
+/*eof*/
diff --git a/source/common/unicode/uchriter.h b/source/common/unicode/uchriter.h
new file mode 100644
index 0000000..6d5a990
--- /dev/null
+++ b/source/common/unicode/uchriter.h
@@ -0,0 +1,381 @@
+/*
+**********************************************************************
+*   Copyright (C) 1998-2005, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+
+#ifndef UCHRITER_H
+#define UCHRITER_H
+
+#include "unicode/utypes.h"
+#include "unicode/chariter.h"
+
+/**
+ * \file 
+ * \brief C++ API: UChar Character Iterator
+ */
+ 
+U_NAMESPACE_BEGIN
+
+/**
+ * A concrete subclass of CharacterIterator that iterates over the
+ * characters (code units or code points) in a UChar array.
+ * It's possible not only to create an
+ * iterator that iterates over an entire UChar array, but also to
+ * create one that iterates over only a subrange of a UChar array
+ * (iterators over different subranges of the same UChar array don't
+ * compare equal).
+ * @see CharacterIterator
+ * @see ForwardCharacterIterator
+ * @stable ICU 2.0
+ */
+class U_COMMON_API UCharCharacterIterator : public CharacterIterator {
+public:
+  /**
+   * Create an iterator over the UChar array referred to by "textPtr".
+   * The iteration range is 0 to <code>length-1</code>.
+   * text is only aliased, not adopted (the
+   * destructor will not delete it).
+   * @param textPtr The UChar array to be iterated over
+   * @param length The length of the UChar array
+   * @stable ICU 2.0
+   */
+  UCharCharacterIterator(const UChar* textPtr, int32_t length);
+
+  /**
+   * Create an iterator over the UChar array referred to by "textPtr".
+   * The iteration range is 0 to <code>length-1</code>.
+   * text is only aliased, not adopted (the
+   * destructor will not delete it).
+   * The starting
+   * position is specified by "position". If "position" is outside the valid
+   * iteration range, the behavior of this object is undefined.
+   * @param textPtr The UChar array to be iteratd over
+   * @param length The length of the UChar array
+   * @param position The starting position of the iteration
+   * @stable ICU 2.0
+   */
+  UCharCharacterIterator(const UChar* textPtr, int32_t length,
+                         int32_t position);
+
+  /**
+   * Create an iterator over the UChar array referred to by "textPtr".
+   * The iteration range is 0 to <code>end-1</code>.
+   * text is only aliased, not adopted (the
+   * destructor will not delete it).
+   * The starting
+   * position is specified by "position". If begin and end do not
+   * form a valid iteration range or "position" is outside the valid
+   * iteration range, the behavior of this object is undefined.
+   * @param textPtr The UChar array to be iterated over
+   * @param length The length of the UChar array
+   * @param textBegin  The begin position of the iteration range
+   * @param textEnd    The end position of the iteration range
+   * @param position    The starting position of the iteration
+   * @stable ICU 2.0
+   */
+  UCharCharacterIterator(const UChar* textPtr, int32_t length,
+                         int32_t textBegin,
+                         int32_t textEnd,
+                         int32_t position);
+
+  /**
+   * Copy constructor.  The new iterator iterates over the same range
+   * of the same string as "that", and its initial position is the
+   * same as "that"'s current position.
+   * @param that The UCharCharacterIterator to be copied
+   * @stable ICU 2.0
+   */
+  UCharCharacterIterator(const UCharCharacterIterator&  that);
+
+  /**
+   * Destructor.
+   * @stable ICU 2.0
+   */
+  virtual ~UCharCharacterIterator();
+
+  /**
+   * Assignment operator.  *this is altered to iterate over the sane
+   * range of the same string as "that", and refers to the same
+   * character within that string as "that" does.
+   * @param that The object to be copied
+   * @return the newly created object
+   * @stable ICU 2.0
+   */
+  UCharCharacterIterator&
+  operator=(const UCharCharacterIterator&    that);
+
+  /**
+   * Returns true if the iterators iterate over the same range of the
+   * same string and are pointing at the same character.
+   * @param that The ForwardCharacterIterator used to be compared for equality
+   * @return true if the iterators iterate over the same range of the
+   * same string and are pointing at the same character.
+   * @stable ICU 2.0
+   */
+  virtual UBool          operator==(const ForwardCharacterIterator& that) const;
+
+  /**
+   * Generates a hash code for this iterator.
+   * @return the hash code.
+   * @stable ICU 2.0
+   */
+  virtual int32_t         hashCode(void) const;
+
+  /**
+   * Returns a new UCharCharacterIterator referring to the same
+   * character in the same range of the same string as this one.  The
+   * caller must delete the new iterator.
+   * @return the CharacterIterator newly created
+   * @stable ICU 2.0
+   */
+  virtual CharacterIterator* clone(void) const;
+
+  /**
+   * Sets the iterator to refer to the first code unit in its
+   * iteration range, and returns that code unit.
+   * This can be used to begin an iteration with next().
+   * @return the first code unit in its iteration range.
+   * @stable ICU 2.0
+   */
+  virtual UChar         first(void);
+
+  /**
+   * Sets the iterator to refer to the first code unit in its
+   * iteration range, returns that code unit, and moves the position
+   * to the second code unit. This is an alternative to setToStart()
+   * for forward iteration with nextPostInc().
+   * @return the first code unit in its iteration range
+   * @stable ICU 2.0
+   */
+  virtual UChar         firstPostInc(void);
+
+  /**
+   * Sets the iterator to refer to the first code point in its
+   * iteration range, and returns that code unit,
+   * This can be used to begin an iteration with next32().
+   * Note that an iteration with next32PostInc(), beginning with,
+   * e.g., setToStart() or firstPostInc(), is more efficient.
+   * @return the first code point in its iteration range
+   * @stable ICU 2.0
+   */
+  virtual UChar32       first32(void);
+
+  /**
+   * Sets the iterator to refer to the first code point in its
+   * iteration range, returns that code point, and moves the position
+   * to the second code point. This is an alternative to setToStart()
+   * for forward iteration with next32PostInc().
+   * @return the first code point in its iteration range.
+   * @stable ICU 2.0
+   */
+  virtual UChar32       first32PostInc(void);
+
+  /**
+   * Sets the iterator to refer to the last code unit in its
+   * iteration range, and returns that code unit.
+   * This can be used to begin an iteration with previous().
+   * @return the last code unit in its iteration range.
+   * @stable ICU 2.0
+   */
+  virtual UChar         last(void);
+
+  /**
+   * Sets the iterator to refer to the last code point in its
+   * iteration range, and returns that code unit.
+   * This can be used to begin an iteration with previous32().
+   * @return the last code point in its iteration range.
+   * @stable ICU 2.0
+   */
+  virtual UChar32       last32(void);
+
+  /**
+   * Sets the iterator to refer to the "position"-th code unit
+   * in the text-storage object the iterator refers to, and
+   * returns that code unit.
+   * @param position the position within the text-storage object
+   * @return the code unit
+   * @stable ICU 2.0
+   */
+  virtual UChar         setIndex(int32_t position);
+
+  /**
+   * Sets the iterator to refer to the beginning of the code point
+   * that contains the "position"-th code unit
+   * in the text-storage object the iterator refers to, and
+   * returns that code point.
+   * The current position is adjusted to the beginning of the code point
+   * (its first code unit).
+   * @param position the position within the text-storage object
+   * @return the code unit
+   * @stable ICU 2.0
+   */
+  virtual UChar32       setIndex32(int32_t position);
+
+  /**
+   * Returns the code unit the iterator currently refers to.
+   * @return the code unit the iterator currently refers to.
+   * @stable ICU 2.0
+   */
+  virtual UChar         current(void) const;
+
+  /**
+   * Returns the code point the iterator currently refers to.
+   * @return the code point the iterator currently refers to.
+   * @stable ICU 2.0
+   */
+  virtual UChar32       current32(void) const;
+
+  /**
+   * Advances to the next code unit in the iteration range (toward
+   * endIndex()), and returns that code unit.  If there are no more
+   * code units to return, returns DONE.
+   * @return the next code unit in the iteration range.
+   * @stable ICU 2.0
+   */
+  virtual UChar         next(void);
+
+  /**
+   * Gets the current code unit for returning and advances to the next code unit
+   * in the iteration range
+   * (toward endIndex()).  If there are
+   * no more code units to return, returns DONE.
+   * @return the current code unit.
+   * @stable ICU 2.0
+   */
+  virtual UChar         nextPostInc(void);
+
+  /**
+   * Advances to the next code point in the iteration range (toward
+   * endIndex()), and returns that code point.  If there are no more
+   * code points to return, returns DONE.
+   * Note that iteration with "pre-increment" semantics is less
+   * efficient than iteration with "post-increment" semantics
+   * that is provided by next32PostInc().
+   * @return the next code point in the iteration range.
+   * @stable ICU 2.0
+   */
+  virtual UChar32       next32(void);
+
+  /**
+   * Gets the current code point for returning and advances to the next code point
+   * in the iteration range
+   * (toward endIndex()).  If there are
+   * no more code points to return, returns DONE.
+   * @return the current point.
+   * @stable ICU 2.0
+   */
+  virtual UChar32       next32PostInc(void);
+
+  /**
+   * Returns FALSE if there are no more code units or code points
+   * at or after the current position in the iteration range.
+   * This is used with nextPostInc() or next32PostInc() in forward
+   * iteration.
+   * @return FALSE if there are no more code units or code points
+   * at or after the current position in the iteration range.
+   * @stable ICU 2.0
+   */
+  virtual UBool        hasNext();
+
+  /**
+   * Advances to the previous code unit in the iteration range (toward
+   * startIndex()), and returns that code unit.  If there are no more
+   * code units to return, returns DONE.
+   * @return the previous code unit in the iteration range.
+   * @stable ICU 2.0
+   */
+  virtual UChar         previous(void);
+
+  /**
+   * Advances to the previous code point in the iteration range (toward
+   * startIndex()), and returns that code point.  If there are no more
+   * code points to return, returns DONE.
+   * @return the previous code point in the iteration range.
+   * @stable ICU 2.0
+   */
+  virtual UChar32       previous32(void);
+
+  /**
+   * Returns FALSE if there are no more code units or code points
+   * before the current position in the iteration range.
+   * This is used with previous() or previous32() in backward
+   * iteration.
+   * @return FALSE if there are no more code units or code points
+   * before the current position in the iteration range.
+   * @stable ICU 2.0
+   */
+  virtual UBool        hasPrevious();
+
+  /**
+   * Moves the current position relative to the start or end of the
+   * iteration range, or relative to the current position itself.
+   * The movement is expressed in numbers of code units forward
+   * or backward by specifying a positive or negative delta.
+   * @param delta the position relative to origin. A positive delta means forward;
+   * a negative delta means backward.
+   * @param origin Origin enumeration {kStart, kCurrent, kEnd}
+   * @return the new position
+   * @stable ICU 2.0
+   */
+  virtual int32_t      move(int32_t delta, EOrigin origin);
+
+  /**
+   * Moves the current position relative to the start or end of the
+   * iteration range, or relative to the current position itself.
+   * The movement is expressed in numbers of code points forward
+   * or backward by specifying a positive or negative delta.
+   * @param delta the position relative to origin. A positive delta means forward;
+   * a negative delta means backward.
+   * @param origin Origin enumeration {kStart, kCurrent, kEnd}
+   * @return the new position
+   * @stable ICU 2.0
+   */
+  virtual int32_t      move32(int32_t delta, EOrigin origin);
+
+  /**
+   * Sets the iterator to iterate over a new range of text
+   * @stable ICU 2.0
+   */
+  void setText(const UChar* newText, int32_t newTextLength);
+
+  /**
+   * Copies the UChar array under iteration into the UnicodeString
+   * referred to by "result".  Even if this iterator iterates across
+   * only a part of this string, the whole string is copied.
+   * @param result Receives a copy of the text under iteration.
+   * @stable ICU 2.0
+   */
+  virtual void            getText(UnicodeString& result);
+
+  /**
+   * Return a class ID for this class (not really public)
+   * @return a class ID for this class
+   * @stable ICU 2.0
+   */
+  static UClassID         U_EXPORT2 getStaticClassID(void);
+
+  /**
+   * Return a class ID for this object (not really public)
+   * @return a class ID for this object.
+   * @stable ICU 2.0
+   */
+  virtual UClassID        getDynamicClassID(void) const;
+
+protected:
+  /**
+   * Protected constructor
+   * @stable ICU 2.0
+   */
+  UCharCharacterIterator();
+  /**
+   * Protected member text
+   * @stable ICU 2.0
+   */
+  const UChar*            text;
+
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/common/unicode/uclean.h b/source/common/unicode/uclean.h
new file mode 100644
index 0000000..de6d736
--- /dev/null
+++ b/source/common/unicode/uclean.h
@@ -0,0 +1,251 @@
+/*
+******************************************************************************
+*                                                                            *
+* Copyright (C) 2001-2009, International Business Machines                   *
+*                Corporation and others. All Rights Reserved.                *
+*                                                                            *
+******************************************************************************
+*   file name:  uclean.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2001July05
+*   created by: George Rhoten
+*/
+
+#ifndef __UCLEAN_H__
+#define __UCLEAN_H__
+
+#include "unicode/utypes.h"
+/**
+ * \file
+ * \brief C API: Initialize and clean up ICU
+ */
+ 
+/**
+ *  Initialize ICU.
+ *
+ *  Use of this function is optional.  It is OK to simply use ICU
+ *  services and functions without first having initialized
+ *  ICU by calling u_init().
+ *
+ *  u_init() will attempt to load some part of ICU's data, and is
+ *  useful as a test for configuration or installation problems that
+ *  leave the ICU data inaccessible.  A successful invocation of u_init()
+ *  does not, however, guarantee that all ICU data is accessible.
+ *
+ *  Multiple calls to u_init() cause no harm, aside from the small amount
+ *  of time required.
+ *
+ *  In old versions of ICU, u_init() was required in multi-threaded applications
+ *  to ensure the thread safety of ICU.  u_init() is no longer needed for this purpose.
+ *
+ * @param status An ICU UErrorCode parameter. It must not be <code>NULL</code>.
+ *    An Error will be returned if some required part of ICU data can not
+ *    be loaded or initialized.
+ *    The function returns immediately if the input error code indicates a
+ *    failure, as usual.
+ *
+ * @stable ICU 2.6
+ */  
+U_STABLE void U_EXPORT2 
+u_init(UErrorCode *status);
+
+/**
+ * Clean up the system resources, such as allocated memory or open files,
+ * used in all ICU libraries. This will free/delete all memory owned by the
+ * ICU libraries, and return them to their original load state. All open ICU
+ * items (collators, resource bundles, converters, etc.) must be closed before
+ * calling this function, otherwise ICU may not free its allocated memory
+ * (e.g. close your converters and resource bundles before calling this
+ * function). Generally, this function should be called once just before
+ * an application exits. For applications that dynamically load and unload
+ * the ICU libraries (relatively uncommon), u_cleanup() should be called
+ * just before the library unload.
+ * <p>
+ * u_cleanup() also clears any ICU heap functions, mutex functions or
+ * trace functions that may have been set for the process.  
+ * This has the effect of restoring ICU to its initial condition, before
+ * any of these override functions were installed.  Refer to
+ * u_setMemoryFunctions(), u_setMutexFunctions and 
+ * utrace_setFunctions().  If ICU is to be reinitialized after after
+ * calling u_cleanup(), these runtime override functions will need to
+ * be set up again if they are still required.
+ * <p>
+ * u_cleanup() is not thread safe.  All other threads should stop using ICU
+ * before calling this function.
+ * <p>
+ * Any open ICU items will be left in an undefined state by u_cleanup(),
+ * and any subsequent attempt to use such an item will give unpredictable
+ * results.
+ * <p>
+ * After calling u_cleanup(), an application may continue to use ICU by
+ * calling u_init().  An application must invoke u_init() first from one single
+ * thread before allowing other threads call u_init().  All threads existing
+ * at the time of the first thread's call to u_init() must also call
+ * u_init() themselves before continuing with other ICU operations.  
+ * <p>
+ * The use of u_cleanup() just before an application terminates is optional,
+ * but it should be called only once for performance reasons. The primary
+ * benefit is to eliminate reports of memory or resource leaks originating
+ * in ICU code from the results generated by heap analysis tools.
+ * <p>
+ * <strong>Use this function with great care!</strong>
+ * </p>
+ *
+ * @stable ICU 2.0
+ * @system
+ */
+U_STABLE void U_EXPORT2 
+u_cleanup(void);
+
+
+
+
+/**
+  * An opaque pointer type that represents an ICU mutex.
+  * For user-implemented mutexes, the value will typically point to a
+  *  struct or object that implements the mutex.
+  * @stable ICU 2.8
+  * @system
+  */
+typedef void *UMTX;
+
+/**
+  *  Function Pointer type for a user supplied mutex initialization function.
+  *  The user-supplied function will be called by ICU whenever ICU needs to create a
+  *  new mutex.  The function implementation should create a mutex, and store a pointer
+  *  to something that uniquely identifies the mutex into the UMTX that is supplied
+  *  as a paramter.
+  *  @param context user supplied value, obtained from from u_setMutexFunctions().
+  *  @param mutex   Receives a pointer that identifies the new mutex.
+  *                 The mutex init function must set the UMTX to a non-null value.   
+  *                 Subsequent calls by ICU to lock, unlock, or destroy a mutex will 
+  *                 identify the mutex by the UMTX value.
+  *  @param status  Error status.  Report errors back to ICU by setting this variable
+  *                 with an error code.
+  *  @stable ICU 2.8
+  *  @system
+  */
+typedef void U_CALLCONV UMtxInitFn (const void *context, UMTX  *mutex, UErrorCode* status);
+
+
+/**
+  *  Function Pointer type for a user supplied mutex functions.
+  *  One of the  user-supplied functions with this signature will be called by ICU
+  *  whenever ICU needs to lock, unlock, or destroy a mutex.
+  *  @param context user supplied value, obtained from from u_setMutexFunctions().
+  *  @param mutex   specify the mutex on which to operate.
+  *  @stable ICU 2.8
+  *  @system
+  */
+typedef void U_CALLCONV UMtxFn   (const void *context, UMTX  *mutex);
+
+
+/**
+  *  Set the functions that ICU will use for mutex operations
+  *  Use of this function is optional; by default (without this function), ICU will
+  *  directly access system functions for mutex operations
+  *  This function can only be used when ICU is in an initial, unused state, before
+  *  u_init() has been called.
+  *  This function may be used even when ICU has been built without multi-threaded
+  *  support  (see ICU_USE_THREADS pre-processor variable, umutex.h)
+  *  @param context This pointer value will be saved, and then (later) passed as
+  *                 a parameter to the user-supplied mutex functions each time they
+  *                 are called. 
+  *  @param init    Pointer to a mutex initialization function.  Must be non-null.
+  *  @param destroy Pointer to the mutex destroy function.  Must be non-null.
+  *  @param lock    pointer to the mutex lock function.  Must be non-null.
+  *  @param unlock  Pointer to the mutex unlock function.  Must be non-null.
+  *  @param status  Receives error values.
+  *  @stable ICU 2.8
+  *  @system
+  */  
+U_STABLE void U_EXPORT2 
+u_setMutexFunctions(const void *context, UMtxInitFn *init, UMtxFn *destroy, UMtxFn *lock, UMtxFn *unlock,
+                    UErrorCode *status);
+
+
+/**
+  *  Pointer type for a user supplied atomic increment or decrement function.
+  *  @param context user supplied value, obtained from from u_setAtomicIncDecFunctions().
+  *  @param p   Pointer to a 32 bit int to be incremented or decremented
+  *  @return    The value of the variable after the inc or dec operation.
+  *  @stable ICU 2.8
+  *  @system
+  */
+typedef int32_t U_CALLCONV UMtxAtomicFn(const void *context, int32_t *p);
+
+/**
+ *  Set the functions that ICU will use for atomic increment and decrement of int32_t values.
+ *  Use of this function is optional; by default (without this function), ICU will
+ *  use its own internal implementation of atomic increment/decrement.
+ *  This function can only be used when ICU is in an initial, unused state, before
+ *  u_init() has been called.
+ *  @param context This pointer value will be saved, and then (later) passed as
+ *                 a parameter to the increment and decrement functions each time they
+ *                 are called.  This function can only be called 
+ *  @param inc     Pointer to a function to do an atomic increment operation.  Must be non-null.
+ *  @param dec     Pointer to a function to do an atomic decrement operation.  Must be non-null.
+ *  @param status  Receives error values.
+ *  @stable ICU 2.8
+ *  @system
+ */  
+U_STABLE void U_EXPORT2 
+u_setAtomicIncDecFunctions(const void *context, UMtxAtomicFn *inc, UMtxAtomicFn *dec,
+                    UErrorCode *status);
+
+
+
+/**
+  *  Pointer type for a user supplied memory allocation function.
+  *  @param context user supplied value, obtained from from u_setMemoryFunctions().
+  *  @param size    The number of bytes to be allocated
+  *  @return        Pointer to the newly allocated memory, or NULL if the allocation failed.
+  *  @stable ICU 2.8
+  *  @system
+  */
+typedef void *U_CALLCONV UMemAllocFn(const void *context, size_t size);
+/**
+  *  Pointer type for a user supplied memory re-allocation function.
+  *  @param context user supplied value, obtained from from u_setMemoryFunctions().
+  *  @param size    The number of bytes to be allocated
+  *  @return        Pointer to the newly allocated memory, or NULL if the allocation failed.
+  *  @stable ICU 2.8
+  *  @system
+  */
+typedef void *U_CALLCONV UMemReallocFn(const void *context, void *mem, size_t size);
+/**
+  *  Pointer type for a user supplied memory free  function.  Behavior should be
+  *  similar the standard C library free().
+  *  @param context user supplied value, obtained from from u_setMemoryFunctions().
+  *  @param mem     Pointer to the memory block to be resized
+  *  @param size    The new size for the block
+  *  @return        Pointer to the resized memory block, or NULL if the resizing failed.
+  *  @stable ICU 2.8
+  *  @system
+  */
+typedef void  U_CALLCONV UMemFreeFn (const void *context, void *mem);
+
+/**
+ *  Set the functions that ICU will use for memory allocation.
+ *  Use of this function is optional; by default (without this function), ICU will
+ *  use the standard C library malloc() and free() functions.
+ *  This function can only be used when ICU is in an initial, unused state, before
+ *  u_init() has been called.
+ *  @param context This pointer value will be saved, and then (later) passed as
+ *                 a parameter to the memory functions each time they
+ *                 are called.
+ *  @param a       Pointer to a user-supplied malloc function.
+ *  @param r       Pointer to a user-supplied realloc function.
+ *  @param f       Pointer to a user-supplied free function.
+ *  @param status  Receives error values.
+ *  @stable ICU 2.8
+ *  @system
+ */  
+U_STABLE void U_EXPORT2 
+u_setMemoryFunctions(const void *context, UMemAllocFn *a, UMemReallocFn *r, UMemFreeFn *f, 
+                    UErrorCode *status);
+
+#endif
diff --git a/source/common/unicode/ucnv.h b/source/common/unicode/ucnv.h
new file mode 100644
index 0000000..98da8ff
--- /dev/null
+++ b/source/common/unicode/ucnv.h
@@ -0,0 +1,1997 @@
+/*
+**********************************************************************
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+ *  ucnv.h:
+ *  External APIs for the ICU's codeset conversion library
+ *  Bertrand A. Damiba
+ *
+ * Modification History:
+ *
+ *   Date        Name        Description
+ *   04/04/99    helena      Fixed internal header inclusion.
+ *   05/11/00    helena      Added setFallback and usesFallback APIs.
+ *   06/29/2000  helena      Major rewrite of the callback APIs.
+ *   12/07/2000  srl         Update of documentation
+ */
+
+/**
+ * \file
+ * \brief C API: Character conversion 
+ *
+ * <h2>Character Conversion C API</h2>
+ *
+ * <p>This API is used to convert codepage or character encoded data to and
+ * from UTF-16. You can open a converter with {@link ucnv_open() }. With that
+ * converter, you can get its properties, set options, convert your data and
+ * close the converter.</p>
+ *
+ * <p>Since many software programs recogize different converter names for
+ * different types of converters, there are other functions in this API to
+ * iterate over the converter aliases. The functions {@link ucnv_getAvailableName() },
+ * {@link ucnv_getAlias() } and {@link ucnv_getStandardName() } are some of the
+ * more frequently used alias functions to get this information.</p>
+ *
+ * <p>When a converter encounters an illegal, irregular, invalid or unmappable character
+ * its default behavior is to use a substitution character to replace the
+ * bad byte sequence. This behavior can be changed by using {@link ucnv_setFromUCallBack() }
+ * or {@link ucnv_setToUCallBack() } on the converter. The header ucnv_err.h defines
+ * many other callback actions that can be used instead of a character substitution.</p>
+ *
+ * <p>More information about this API can be found in our 
+ * <a href="http://icu-project.org/userguide/conversion.html">User's
+ * Guide</a>.</p>
+ */
+
+#ifndef UCNV_H
+#define UCNV_H
+
+#include "unicode/ucnv_err.h"
+#include "unicode/uenum.h"
+#include "unicode/localpointer.h"
+
+#ifndef __USET_H__
+
+/**
+ * USet is the C API type for Unicode sets.
+ * It is forward-declared here to avoid including the header file if related
+ * conversion APIs are not used.
+ * See unicode/uset.h
+ *
+ * @see ucnv_getUnicodeSet
+ * @stable ICU 2.6
+ */
+struct USet;
+/** @stable ICU 2.6 */
+typedef struct USet USet;
+
+#endif
+
+#if !UCONFIG_NO_CONVERSION
+
+U_CDECL_BEGIN
+
+/** Maximum length of a converter name including the terminating NULL @stable ICU 2.0 */
+#define UCNV_MAX_CONVERTER_NAME_LENGTH 60
+/** Maximum length of a converter name including path and terminating NULL @stable ICU 2.0 */
+#define UCNV_MAX_FULL_FILE_NAME_LENGTH (600+UCNV_MAX_CONVERTER_NAME_LENGTH)
+
+/** Shift in for EBDCDIC_STATEFUL and iso2022 states @stable ICU 2.0 */
+#define  UCNV_SI 0x0F
+/** Shift out for EBDCDIC_STATEFUL and iso2022 states @stable ICU 2.0 */
+#define  UCNV_SO 0x0E
+
+/**
+ * Enum for specifying basic types of converters
+ * @see ucnv_getType
+ * @stable ICU 2.0
+ */
+typedef enum {
+    UCNV_UNSUPPORTED_CONVERTER = -1,
+    UCNV_SBCS = 0,
+    UCNV_DBCS = 1,
+    UCNV_MBCS = 2,
+    UCNV_LATIN_1 = 3,
+    UCNV_UTF8 = 4,
+    UCNV_UTF16_BigEndian = 5,
+    UCNV_UTF16_LittleEndian = 6,
+    UCNV_UTF32_BigEndian = 7,
+    UCNV_UTF32_LittleEndian = 8,
+    UCNV_EBCDIC_STATEFUL = 9,
+    UCNV_ISO_2022 = 10,
+
+    UCNV_LMBCS_1 = 11,
+    UCNV_LMBCS_2, 
+    UCNV_LMBCS_3,
+    UCNV_LMBCS_4,
+    UCNV_LMBCS_5,
+    UCNV_LMBCS_6,
+    UCNV_LMBCS_8,
+    UCNV_LMBCS_11,
+    UCNV_LMBCS_16,
+    UCNV_LMBCS_17,
+    UCNV_LMBCS_18,
+    UCNV_LMBCS_19,
+    UCNV_LMBCS_LAST = UCNV_LMBCS_19,
+    UCNV_HZ,
+    UCNV_SCSU,
+    UCNV_ISCII,
+    UCNV_US_ASCII,
+    UCNV_UTF7,
+    UCNV_BOCU1,
+    UCNV_UTF16,
+    UCNV_UTF32,
+    UCNV_CESU8,
+    UCNV_IMAP_MAILBOX,
+
+    /* Number of converter types for which we have conversion routines. */
+    UCNV_NUMBER_OF_SUPPORTED_CONVERTER_TYPES
+
+} UConverterType;
+
+/**
+ * Enum for specifying which platform a converter ID refers to.
+ * The use of platform/CCSID is not recommended. See ucnv_openCCSID().
+ *
+ * @see ucnv_getPlatform
+ * @see ucnv_openCCSID
+ * @see ucnv_getCCSID
+ * @stable ICU 2.0
+ */
+typedef enum {
+    UCNV_UNKNOWN = -1,
+    UCNV_IBM = 0
+} UConverterPlatform;
+
+/**
+ * Function pointer for error callback in the codepage to unicode direction.
+ * Called when an error has occured in conversion to unicode, or on open/close of the callback (see reason).
+ * @param context Pointer to the callback's private data
+ * @param args Information about the conversion in progress
+ * @param codeUnits Points to 'length' bytes of the concerned codepage sequence
+ * @param length Size (in bytes) of the concerned codepage sequence
+ * @param reason Defines the reason the callback was invoked
+ * @param pErrorCode    ICU error code in/out parameter.
+ *                      For converter callback functions, set to a conversion error
+ *                      before the call, and the callback may reset it to U_ZERO_ERROR.
+ * @see ucnv_setToUCallBack
+ * @see UConverterToUnicodeArgs
+ * @stable ICU 2.0
+ */
+typedef void (U_EXPORT2 *UConverterToUCallback) (
+                  const void* context,
+                  UConverterToUnicodeArgs *args,
+                  const char *codeUnits,
+                  int32_t length,
+                  UConverterCallbackReason reason,
+                  UErrorCode *pErrorCode);
+
+/**
+ * Function pointer for error callback in the unicode to codepage direction.
+ * Called when an error has occured in conversion from unicode, or on open/close of the callback (see reason).
+ * @param context Pointer to the callback's private data
+ * @param args Information about the conversion in progress
+ * @param codeUnits Points to 'length' UChars of the concerned Unicode sequence
+ * @param length Size (in bytes) of the concerned codepage sequence
+ * @param codePoint Single UChar32 (UTF-32) containing the concerend Unicode codepoint.
+ * @param reason Defines the reason the callback was invoked
+ * @param pErrorCode    ICU error code in/out parameter.
+ *                      For converter callback functions, set to a conversion error
+ *                      before the call, and the callback may reset it to U_ZERO_ERROR.
+ * @see ucnv_setFromUCallBack
+ * @stable ICU 2.0
+ */
+typedef void (U_EXPORT2 *UConverterFromUCallback) (
+                    const void* context,
+                    UConverterFromUnicodeArgs *args,
+                    const UChar* codeUnits,
+                    int32_t length,
+                    UChar32 codePoint,
+                    UConverterCallbackReason reason,
+                    UErrorCode *pErrorCode);
+
+U_CDECL_END
+
+/**
+ * Character that separates converter names from options and options from each other.
+ * @see ucnv_open
+ * @stable ICU 2.0
+ */
+#define UCNV_OPTION_SEP_CHAR ','
+
+/**
+ * String version of UCNV_OPTION_SEP_CHAR. 
+ * @see ucnv_open
+ * @stable ICU 2.0
+ */
+#define UCNV_OPTION_SEP_STRING ","
+
+/**
+ * Character that separates a converter option from its value.
+ * @see ucnv_open
+ * @stable ICU 2.0
+ */
+#define UCNV_VALUE_SEP_CHAR '='
+
+/**
+ * String version of UCNV_VALUE_SEP_CHAR. 
+ * @see ucnv_open
+ * @stable ICU 2.0
+ */
+#define UCNV_VALUE_SEP_STRING "="
+
+/**
+ * Converter option for specifying a locale.
+ * For example, ucnv_open("SCSU,locale=ja", &errorCode);
+ * See convrtrs.txt.
+ *
+ * @see ucnv_open
+ * @stable ICU 2.0
+ */
+#define UCNV_LOCALE_OPTION_STRING ",locale="
+
+/**
+ * Converter option for specifying a version selector (0..9) for some converters.
+ * For example, 
+ * \code
+ *   ucnv_open("UTF-7,version=1", &errorCode);
+ * \endcode
+ * See convrtrs.txt.
+ *
+ * @see ucnv_open
+ * @stable ICU 2.4
+ */
+#define UCNV_VERSION_OPTION_STRING ",version="
+
+/**
+ * Converter option for EBCDIC SBCS or mixed-SBCS/DBCS (stateful) codepages.
+ * Swaps Unicode mappings for EBCDIC LF and NL codes, as used on
+ * S/390 (z/OS) Unix System Services (Open Edition).
+ * For example, ucnv_open("ibm-1047,swaplfnl", &errorCode);
+ * See convrtrs.txt.
+ *
+ * @see ucnv_open
+ * @stable ICU 2.4
+ */
+#define UCNV_SWAP_LFNL_OPTION_STRING ",swaplfnl"
+
+/**
+ * Do a fuzzy compare of two converter/alias names.
+ * The comparison is case-insensitive, ignores leading zeroes if they are not
+ * followed by further digits, and ignores all but letters and digits.
+ * Thus the strings "UTF-8", "utf_8", "u*T@f08" and "Utf 8" are exactly equivalent.
+ * See section 1.4, Charset Alias Matching in Unicode Technical Standard #22
+ * at http://www.unicode.org/reports/tr22/
+ *
+ * @param name1 a converter name or alias, zero-terminated
+ * @param name2 a converter name or alias, zero-terminated
+ * @return 0 if the names match, or a negative value if the name1
+ * lexically precedes name2, or a positive value if the name1
+ * lexically follows name2.
+ * @stable ICU 2.0
+ */
+U_STABLE int U_EXPORT2
+ucnv_compareNames(const char *name1, const char *name2);
+
+
+/**
+ * Creates a UConverter object with the name of a coded character set specified as a C string.
+ * The actual name will be resolved with the alias file
+ * using a case-insensitive string comparison that ignores
+ * leading zeroes and all non-alphanumeric characters.
+ * E.g., the names "UTF8", "utf-8", "u*T@f08" and "Utf 8" are all equivalent.
+ * (See also ucnv_compareNames().)
+ * If <code>NULL</code> is passed for the converter name, it will create one with the
+ * getDefaultName return value.
+ *
+ * <p>A converter name for ICU 1.5 and above may contain options
+ * like a locale specification to control the specific behavior of
+ * the newly instantiated converter.
+ * The meaning of the options depends on the particular converter.
+ * If an option is not defined for or recognized by a given converter, then it is ignored.</p>
+ *
+ * <p>Options are appended to the converter name string, with a
+ * <code>UCNV_OPTION_SEP_CHAR</code> between the name and the first option and
+ * also between adjacent options.</p>
+ *
+ * <p>If the alias is ambiguous, then the preferred converter is used
+ * and the status is set to U_AMBIGUOUS_ALIAS_WARNING.</p>
+ *
+ * <p>The conversion behavior and names can vary between platforms. ICU may
+ * convert some characters differently from other platforms. Details on this topic
+ * are in the <a href="http://icu-project.org/userguide/conversion.html">User's
+ * Guide</a>. Aliases starting with a "cp" prefix have no specific meaning
+ * other than its an alias starting with the letters "cp". Please do not
+ * associate any meaning to these aliases.</p>
+ *
+ * @param converterName Name of the coded character set table.
+ *          This may have options appended to the string.
+ *          IANA alias character set names, IBM CCSIDs starting with "ibm-",
+ *          Windows codepage numbers starting with "windows-" are frequently
+ *          used for this parameter. See ucnv_getAvailableName and
+ *          ucnv_getAlias for a complete list that is available.
+ *          If this parameter is NULL, the default converter will be used.
+ * @param err outgoing error status <TT>U_MEMORY_ALLOCATION_ERROR, U_FILE_ACCESS_ERROR</TT>
+ * @return the created Unicode converter object, or <TT>NULL</TT> if an error occured
+ * @see ucnv_openU
+ * @see ucnv_openCCSID
+ * @see ucnv_getAvailableName
+ * @see ucnv_getAlias
+ * @see ucnv_getDefaultName
+ * @see ucnv_close
+ * @see ucnv_compareNames
+ * @stable ICU 2.0
+ */
+U_STABLE UConverter* U_EXPORT2 
+ucnv_open(const char *converterName, UErrorCode *err);
+
+
+/**
+ * Creates a Unicode converter with the names specified as unicode string. 
+ * The name should be limited to the ASCII-7 alphanumerics range.
+ * The actual name will be resolved with the alias file
+ * using a case-insensitive string comparison that ignores
+ * leading zeroes and all non-alphanumeric characters.
+ * E.g., the names "UTF8", "utf-8", "u*T@f08" and "Utf 8" are all equivalent.
+ * (See also ucnv_compareNames().)
+ * If <TT>NULL</TT> is passed for the converter name, it will create 
+ * one with the ucnv_getDefaultName() return value.
+ * If the alias is ambiguous, then the preferred converter is used
+ * and the status is set to U_AMBIGUOUS_ALIAS_WARNING.
+ *
+ * <p>See ucnv_open for the complete details</p>
+ * @param name Name of the UConverter table in a zero terminated 
+ *        Unicode string
+ * @param err outgoing error status <TT>U_MEMORY_ALLOCATION_ERROR, 
+ *        U_FILE_ACCESS_ERROR</TT>
+ * @return the created Unicode converter object, or <TT>NULL</TT> if an 
+ *        error occured
+ * @see ucnv_open
+ * @see ucnv_openCCSID
+ * @see ucnv_close
+ * @see ucnv_compareNames
+ * @stable ICU 2.0
+ */
+U_STABLE UConverter* U_EXPORT2 
+ucnv_openU(const UChar *name,
+           UErrorCode *err);
+
+/**
+ * Creates a UConverter object from a CCSID number and platform pair.
+ * Note that the usefulness of this function is limited to platforms with numeric
+ * encoding IDs. Only IBM and Microsoft platforms use numeric (16-bit) identifiers for
+ * encodings.
+ *
+ * In addition, IBM CCSIDs and Unicode conversion tables are not 1:1 related.
+ * For many IBM CCSIDs there are multiple (up to six) Unicode conversion tables, and
+ * for some Unicode conversion tables there are multiple CCSIDs.
+ * Some "alternate" Unicode conversion tables are provided by the
+ * IBM CDRA conversion table registry.
+ * The most prominent example of a systematic modification of conversion tables that is
+ * not provided in the form of conversion table files in the repository is
+ * that S/390 Unix System Services swaps the codes for Line Feed and New Line in all
+ * EBCDIC codepages, which requires such a swap in the Unicode conversion tables as well.
+ *
+ * Only IBM default conversion tables are accessible with ucnv_openCCSID().
+ * ucnv_getCCSID() will return the same CCSID for all conversion tables that are associated
+ * with that CCSID.
+ *
+ * Currently, the only "platform" supported in the ICU converter API is UCNV_IBM.
+ *
+ * In summary, the use of CCSIDs and the associated API functions is not recommended.
+ *
+ * In order to open a converter with the default IBM CDRA Unicode conversion table,
+ * you can use this function or use the prefix "ibm-":
+ * \code
+ *     char name[20];
+ *     sprintf(name, "ibm-%hu", ccsid);
+ *     cnv=ucnv_open(name, &errorCode);
+ * \endcode
+ *
+ * In order to open a converter with the IBM S/390 Unix System Services variant
+ * of a Unicode/EBCDIC conversion table,
+ * you can use the prefix "ibm-" together with the option string UCNV_SWAP_LFNL_OPTION_STRING:
+ * \code
+ *     char name[20];
+ *     sprintf(name, "ibm-%hu" UCNV_SWAP_LFNL_OPTION_STRING, ccsid);
+ *     cnv=ucnv_open(name, &errorCode);
+ * \endcode
+ *
+ * In order to open a converter from a Microsoft codepage number, use the prefix "cp":
+ * \code
+ *     char name[20];
+ *     sprintf(name, "cp%hu", codepageID);
+ *     cnv=ucnv_open(name, &errorCode);
+ * \endcode
+ *
+ * If the alias is ambiguous, then the preferred converter is used
+ * and the status is set to U_AMBIGUOUS_ALIAS_WARNING.
+ *
+ * @param codepage codepage number to create
+ * @param platform the platform in which the codepage number exists
+ * @param err error status <TT>U_MEMORY_ALLOCATION_ERROR, U_FILE_ACCESS_ERROR</TT>
+ * @return the created Unicode converter object, or <TT>NULL</TT> if an error
+ *   occured.
+ * @see ucnv_open
+ * @see ucnv_openU
+ * @see ucnv_close
+ * @see ucnv_getCCSID
+ * @see ucnv_getPlatform
+ * @see UConverterPlatform
+ * @stable ICU 2.0
+ */
+U_STABLE UConverter* U_EXPORT2
+ucnv_openCCSID(int32_t codepage,
+               UConverterPlatform platform,
+               UErrorCode * err);
+
+/**
+ * <p>Creates a UConverter object specified from a packageName and a converterName.</p>
+ * 
+ * <p>The packageName and converterName must point to an ICU udata object, as defined by
+ *   <code> udata_open( packageName, "cnv", converterName, err) </code> or equivalent.
+ * Typically, packageName will refer to a (.dat) file, or to a package registered with
+ * udata_setAppData(). Using a full file or directory pathname for packageName is deprecated.</p>
+ * 
+ * <p>The name will NOT be looked up in the alias mechanism, nor will the converter be
+ * stored in the converter cache or the alias table. The only way to open further converters
+ * is call this function multiple times, or use the ucnv_safeClone() function to clone a 
+ * 'master' converter.</p>
+ *
+ * <p>A future version of ICU may add alias table lookups and/or caching
+ * to this function.</p>
+ * 
+ * <p>Example Use:
+ *      <code>cnv = ucnv_openPackage("myapp", "myconverter", &err);</code>
+ * </p>
+ *
+ * @param packageName name of the package (equivalent to 'path' in udata_open() call)
+ * @param converterName name of the data item to be used, without suffix.
+ * @param err outgoing error status <TT>U_MEMORY_ALLOCATION_ERROR, U_FILE_ACCESS_ERROR</TT>
+ * @return the created Unicode converter object, or <TT>NULL</TT> if an error occured
+ * @see udata_open
+ * @see ucnv_open
+ * @see ucnv_safeClone
+ * @see ucnv_close
+ * @stable ICU 2.2
+ */
+U_STABLE UConverter* U_EXPORT2 
+ucnv_openPackage(const char *packageName, const char *converterName, UErrorCode *err);
+
+/**
+ * Thread safe converter cloning operation.
+ * For most efficient operation, pass in a stackBuffer (and a *pBufferSize)
+ * with at least U_CNV_SAFECLONE_BUFFERSIZE bytes of space.
+ * If the buffer size is sufficient, then the clone will use the stack buffer;
+ * otherwise, it will be allocated, and *pBufferSize will indicate
+ * the actual size. (This should not occur with U_CNV_SAFECLONE_BUFFERSIZE.)
+ *
+ * You must ucnv_close() the clone in any case.
+ *
+ * If *pBufferSize==0, (regardless of whether stackBuffer==NULL or not)
+ * then *pBufferSize will be changed to a sufficient size
+ * for cloning this converter,
+ * without actually cloning the converter ("pure pre-flighting").
+ *
+ * If *pBufferSize is greater than zero but not large enough for a stack-based
+ * clone, then the converter is cloned using newly allocated memory
+ * and *pBufferSize is changed to the necessary size.
+ *
+ * If the converter clone fits into the stack buffer but the stack buffer is not
+ * sufficiently aligned for the clone, then the clone will use an
+ * adjusted pointer and use an accordingly smaller buffer size.
+ *
+ * @param cnv converter 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_CNV_SAFECLONE_BUFFERSIZE. This will probably be enough to avoid memory allocations.
+ * @param pBufferSize pointer to size of allocated space. pBufferSize must not be NULL.
+ * @param status to indicate whether the operation went on smoothly or there were errors
+ *  An informational status value, U_SAFECLONE_ALLOCATED_WARNING,
+ *  is used if any allocations were necessary.
+ *  However, it is better to check if *pBufferSize grew for checking for
+ *  allocations because warning codes can be overridden by subsequent
+ *  function calls.
+ * @return pointer to the new clone
+ * @stable ICU 2.0
+ */
+U_STABLE UConverter * U_EXPORT2 
+ucnv_safeClone(const UConverter *cnv, 
+               void             *stackBuffer,
+               int32_t          *pBufferSize, 
+               UErrorCode       *status);
+
+/**
+ * \def U_CNV_SAFECLONE_BUFFERSIZE
+ * Definition of a buffer size that is designed to be large enough for
+ * converters to be cloned with ucnv_safeClone().
+ * @stable ICU 2.0
+ */
+#define U_CNV_SAFECLONE_BUFFERSIZE  1024
+
+/**
+ * Deletes the unicode converter and releases resources associated
+ * with just this instance.
+ * Does not free up shared converter tables.
+ *
+ * @param converter the converter object to be deleted
+ * @see ucnv_open
+ * @see ucnv_openU
+ * @see ucnv_openCCSID
+ * @stable ICU 2.0
+ */
+U_STABLE void  U_EXPORT2
+ucnv_close(UConverter * converter);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUConverterPointer
+ * "Smart pointer" class, closes a UConverter via ucnv_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUConverterPointer, UConverter, ucnv_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Fills in the output parameter, subChars, with the substitution characters
+ * as multiple bytes.
+ * If ucnv_setSubstString() set a Unicode string because the converter is
+ * stateful, then subChars will be an empty string.
+ *
+ * @param converter the Unicode converter
+ * @param subChars the subsitution characters
+ * @param len on input the capacity of subChars, on output the number 
+ * of bytes copied to it
+ * @param  err the outgoing error status code.
+ * If the substitution character array is too small, an
+ * <TT>U_INDEX_OUTOFBOUNDS_ERROR</TT> will be returned.
+ * @see ucnv_setSubstString
+ * @see ucnv_setSubstChars
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucnv_getSubstChars(const UConverter *converter,
+                   char *subChars,
+                   int8_t *len,
+                   UErrorCode *err);
+
+/**
+ * Sets the substitution chars when converting from unicode to a codepage. The
+ * substitution is specified as a string of 1-4 bytes, and may contain
+ * <TT>NULL</TT> bytes.
+ * The subChars must represent a single character. The caller needs to know the
+ * byte sequence of a valid character in the converter's charset.
+ * For some converters, for example some ISO 2022 variants, only single-byte
+ * substitution characters may be supported.
+ * The newer ucnv_setSubstString() function relaxes these limitations.
+ *
+ * @param converter the Unicode converter
+ * @param subChars the substitution character byte sequence we want set
+ * @param len the number of bytes in subChars
+ * @param err the error status code.  <TT>U_INDEX_OUTOFBOUNDS_ERROR </TT> if
+ * len is bigger than the maximum number of bytes allowed in subchars
+ * @see ucnv_setSubstString
+ * @see ucnv_getSubstChars
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucnv_setSubstChars(UConverter *converter,
+                   const char *subChars,
+                   int8_t len,
+                   UErrorCode *err);
+
+/**
+ * Set a substitution string for converting from Unicode to a charset.
+ * The caller need not know the charset byte sequence for each charset.
+ *
+ * Unlike ucnv_setSubstChars() which is designed to set a charset byte sequence
+ * for a single character, this function takes a Unicode string with
+ * zero, one or more characters, and immediately verifies that the string can be
+ * converted to the charset.
+ * If not, or if the result is too long (more than 32 bytes as of ICU 3.6),
+ * then the function returns with an error accordingly.
+ *
+ * Also unlike ucnv_setSubstChars(), this function works for stateful charsets
+ * by converting on the fly at the point of substitution rather than setting
+ * a fixed byte sequence.
+ *
+ * @param cnv The UConverter object.
+ * @param s The Unicode string.
+ * @param length The number of UChars in s, or -1 for a NUL-terminated string.
+ * @param err 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 ucnv_setSubstChars
+ * @see ucnv_getSubstChars
+ * @stable ICU 3.6
+ */
+U_STABLE void U_EXPORT2
+ucnv_setSubstString(UConverter *cnv,
+                    const UChar *s,
+                    int32_t length,
+                    UErrorCode *err);
+
+/**
+ * Fills in the output parameter, errBytes, with the error characters from the
+ * last failing conversion.
+ *
+ * @param converter the Unicode converter
+ * @param errBytes the codepage bytes which were in error
+ * @param len on input the capacity of errBytes, on output the number of
+ *  bytes which were copied to it
+ * @param err the error status code.
+ * If the substitution character array is too small, an
+ * <TT>U_INDEX_OUTOFBOUNDS_ERROR</TT> will be returned.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucnv_getInvalidChars(const UConverter *converter,
+                     char *errBytes,
+                     int8_t *len,
+                     UErrorCode *err);
+
+/**
+ * Fills in the output parameter, errChars, with the error characters from the
+ * last failing conversion.
+ *
+ * @param converter the Unicode converter
+ * @param errUChars the UChars which were in error
+ * @param len on input the capacity of errUChars, on output the number of 
+ *  UChars which were copied to it
+ * @param err the error status code.
+ * If the substitution character array is too small, an
+ * <TT>U_INDEX_OUTOFBOUNDS_ERROR</TT> will be returned.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucnv_getInvalidUChars(const UConverter *converter,
+                      UChar *errUChars,
+                      int8_t *len,
+                      UErrorCode *err);
+
+/**
+ * Resets the state of a converter to the default state. This is used
+ * in the case of an error, to restart a conversion from a known default state.
+ * It will also empty the internal output buffers.
+ * @param converter the Unicode converter
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucnv_reset(UConverter *converter);
+
+/**
+ * Resets the to-Unicode part of a converter state to the default state.
+ * This is used in the case of an error to restart a conversion to
+ * Unicode to a known default state. It will also empty the internal
+ * output buffers used for the conversion to Unicode codepoints.
+ * @param converter the Unicode converter
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 
+ucnv_resetToUnicode(UConverter *converter);
+
+/**
+ * Resets the from-Unicode part of a converter state to the default state.
+ * This is used in the case of an error to restart a conversion from
+ * Unicode to a known default state. It will also empty the internal output
+ * buffers used for the conversion from Unicode codepoints.
+ * @param converter the Unicode converter
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 
+ucnv_resetFromUnicode(UConverter *converter);
+
+/**
+ * Returns the maximum number of bytes that are output per UChar in conversion
+ * from Unicode using this converter.
+ * The returned number can be used with UCNV_GET_MAX_BYTES_FOR_STRING
+ * to calculate the size of a target buffer for conversion from Unicode.
+ *
+ * Note: Before ICU 2.8, this function did not return reliable numbers for
+ * some stateful converters (EBCDIC_STATEFUL, ISO-2022) and LMBCS.
+ *
+ * This number may not be the same as the maximum number of bytes per
+ * "conversion unit". In other words, it may not be the intuitively expected
+ * number of bytes per character that would be published for a charset,
+ * and may not fulfill any other purpose than the allocation of an output
+ * buffer of guaranteed sufficient size for a given input length and converter.
+ *
+ * Examples for special cases that are taken into account:
+ * - Supplementary code points may convert to more bytes than BMP code points.
+ *   This function returns bytes per UChar (UTF-16 code unit), not per
+ *   Unicode code point, for efficient buffer allocation.
+ * - State-shifting output (SI/SO, escapes, etc.) from stateful converters.
+ * - When m input UChars are converted to n output bytes, then the maximum m/n
+ *   is taken into account.
+ *
+ * The number returned here does not take into account
+ * (see UCNV_GET_MAX_BYTES_FOR_STRING):
+ * - callbacks which output more than one charset character sequence per call,
+ *   like escape callbacks
+ * - initial and final non-character bytes that are output by some converters
+ *   (automatic BOMs, initial escape sequence, final SI, etc.)
+ *
+ * Examples for returned values:
+ * - SBCS charsets: 1
+ * - Shift-JIS: 2
+ * - UTF-16: 2 (2 per BMP, 4 per surrogate _pair_, BOM not counted)
+ * - UTF-8: 3 (3 per BMP, 4 per surrogate _pair_)
+ * - EBCDIC_STATEFUL (EBCDIC mixed SBCS/DBCS): 3 (SO + DBCS)
+ * - ISO-2022: 3 (always outputs UTF-8)
+ * - ISO-2022-JP: 6 (4-byte escape sequences + DBCS)
+ * - ISO-2022-CN: 8 (4-byte designator sequences + 2-byte SS2/SS3 + DBCS)
+ *
+ * @param converter The Unicode converter.
+ * @return The maximum number of bytes per UChar that are output by ucnv_fromUnicode(),
+ *         to be used together with UCNV_GET_MAX_BYTES_FOR_STRING for buffer allocation.
+ *
+ * @see UCNV_GET_MAX_BYTES_FOR_STRING
+ * @see ucnv_getMinCharSize
+ * @stable ICU 2.0
+ */
+U_STABLE int8_t U_EXPORT2
+ucnv_getMaxCharSize(const UConverter *converter);
+
+/**
+ * Calculates the size of a buffer for conversion from Unicode to a charset.
+ * The calculated size is guaranteed to be sufficient for this conversion.
+ *
+ * It takes into account initial and final non-character bytes that are output
+ * by some converters.
+ * It does not take into account callbacks which output more than one charset
+ * character sequence per call, like escape callbacks.
+ * The default (substitution) callback only outputs one charset character sequence.
+ *
+ * @param length Number of UChars to be converted.
+ * @param maxCharSize Return value from ucnv_getMaxCharSize() for the converter
+ *                    that will be used.
+ * @return Size of a buffer that will be large enough to hold the output bytes of
+ *         converting length UChars with the converter that returned the maxCharSize.
+ *
+ * @see ucnv_getMaxCharSize
+ * @stable ICU 2.8
+ */
+#define UCNV_GET_MAX_BYTES_FOR_STRING(length, maxCharSize) \
+     (((int32_t)(length)+10)*(int32_t)(maxCharSize))
+
+/**
+ * Returns the minimum byte length for characters in this codepage. 
+ * This is usually either 1 or 2.
+ * @param converter the Unicode converter
+ * @return the minimum number of bytes allowed by this particular converter
+ * @see ucnv_getMaxCharSize
+ * @stable ICU 2.0
+ */
+U_STABLE int8_t U_EXPORT2
+ucnv_getMinCharSize(const UConverter *converter);
+
+/**
+ * Returns the display name of the converter passed in based on the Locale 
+ * passed in. If the locale contains no display name, the internal ASCII
+ * name will be filled in.
+ *
+ * @param converter the Unicode converter.
+ * @param displayLocale is the specific Locale we want to localised for
+ * @param displayName user provided buffer to be filled in
+ * @param displayNameCapacity size of displayName Buffer
+ * @param err error status code
+ * @return displayNameLength number of UChar needed in displayName
+ * @see ucnv_getName
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucnv_getDisplayName(const UConverter *converter,
+                    const char *displayLocale,
+                    UChar *displayName,
+                    int32_t displayNameCapacity,
+                    UErrorCode *err);
+
+/**
+ * Gets the internal, canonical name of the converter (zero-terminated).
+ * The lifetime of the returned string will be that of the converter 
+ * passed to this function.
+ * @param converter the Unicode converter
+ * @param err UErrorCode status
+ * @return the internal name of the converter
+ * @see ucnv_getDisplayName
+ * @stable ICU 2.0
+ */
+U_STABLE const char * U_EXPORT2 
+ucnv_getName(const UConverter *converter, UErrorCode *err);
+
+/**
+ * Gets a codepage number associated with the converter. This is not guaranteed
+ * to be the one used to create the converter. Some converters do not represent
+ * platform registered codepages and return zero for the codepage number.
+ * The error code fill-in parameter indicates if the codepage number
+ * is available.
+ * Does not check if the converter is <TT>NULL</TT> or if converter's data
+ * table is <TT>NULL</TT>.
+ *
+ * Important: The use of CCSIDs is not recommended because it is limited
+ * to only two platforms in principle and only one (UCNV_IBM) in the current
+ * ICU converter API.
+ * Also, CCSIDs are insufficient to identify IBM Unicode conversion tables precisely.
+ * For more details see ucnv_openCCSID().
+ *
+ * @param converter the Unicode converter
+ * @param err the error status code.
+ * @return If any error occurrs, -1 will be returned otherwise, the codepage number
+ * will be returned
+ * @see ucnv_openCCSID
+ * @see ucnv_getPlatform
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucnv_getCCSID(const UConverter *converter,
+              UErrorCode *err);
+
+/**
+ * Gets a codepage platform associated with the converter. Currently, 
+ * only <TT>UCNV_IBM</TT> will be returned.
+ * Does not test if the converter is <TT>NULL</TT> or if converter's data 
+ * table is <TT>NULL</TT>. 
+ * @param converter the Unicode converter
+ * @param err the error status code.
+ * @return The codepage platform
+ * @stable ICU 2.0
+ */
+U_STABLE UConverterPlatform U_EXPORT2
+ucnv_getPlatform(const UConverter *converter,
+                 UErrorCode *err);
+
+/**
+ * Gets the type of the converter
+ * e.g. SBCS, MBCS, DBCS, UTF8, UTF16_BE, UTF16_LE, ISO_2022, 
+ * EBCDIC_STATEFUL, LATIN_1
+ * @param converter a valid, opened converter
+ * @return the type of the converter
+ * @stable ICU 2.0
+ */
+U_STABLE UConverterType U_EXPORT2
+ucnv_getType(const UConverter * converter);
+
+/**
+ * Gets the "starter" (lead) bytes for converters of type MBCS.
+ * Will fill in an <TT>U_ILLEGAL_ARGUMENT_ERROR</TT> if converter passed in
+ * is not MBCS. Fills in an array of type UBool, with the value of the byte 
+ * as offset to the array. For example, if (starters[0x20] == TRUE) at return,
+ * it means that the byte 0x20 is a starter byte in this converter.
+ * Context pointers are always owned by the caller.
+ * 
+ * @param converter a valid, opened converter of type MBCS
+ * @param starters an array of size 256 to be filled in
+ * @param err error status, <TT>U_ILLEGAL_ARGUMENT_ERROR</TT> if the 
+ * converter is not a type which can return starters.
+ * @see ucnv_getType
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucnv_getStarters(const UConverter* converter, 
+                 UBool starters[256],
+                 UErrorCode* err);
+
+
+/**
+ * Selectors for Unicode sets that can be returned by ucnv_getUnicodeSet().
+ * @see ucnv_getUnicodeSet
+ * @stable ICU 2.6
+ */
+typedef enum UConverterUnicodeSet {
+    /** Select the set of roundtrippable Unicode code points. @stable ICU 2.6 */
+    UCNV_ROUNDTRIP_SET,
+    /** Select the set of Unicode code points with roundtrip or fallback mappings. @stable ICU 4.0 */
+    UCNV_ROUNDTRIP_AND_FALLBACK_SET,
+    /** Number of UConverterUnicodeSet selectors. @stable ICU 2.6 */
+    UCNV_SET_COUNT
+} UConverterUnicodeSet;
+
+
+/**
+ * Returns the set of Unicode code points that can be converted by an ICU converter.
+ *
+ * Returns one of several kinds of set:
+ *
+ * 1. UCNV_ROUNDTRIP_SET
+ *
+ * The set of all Unicode code points that can be roundtrip-converted
+ * (converted without any data loss) with the converter (ucnv_fromUnicode()).
+ * This set will not include code points that have fallback mappings
+ * or are only the result of reverse fallback mappings.
+ * This set will also not include PUA code points with fallbacks, although
+ * ucnv_fromUnicode() will always uses those mappings despite ucnv_setFallback().
+ * See UTR #22 "Character Mapping Markup Language"
+ * at http://www.unicode.org/reports/tr22/
+ *
+ * This is useful for example for
+ * - checking that a string or document can be roundtrip-converted with a converter,
+ *   without/before actually performing the conversion
+ * - testing if a converter can be used for text for typical text for a certain locale,
+ *   by comparing its roundtrip set with the set of ExemplarCharacters from
+ *   ICU's locale data or other sources
+ *
+ * 2. UCNV_ROUNDTRIP_AND_FALLBACK_SET
+ *
+ * The set of all Unicode code points that can be converted with the converter (ucnv_fromUnicode())
+ * when fallbacks are turned on (see ucnv_setFallback()).
+ * This set includes all code points with roundtrips and fallbacks (but not reverse fallbacks).
+ *
+ * In the future, there may be more UConverterUnicodeSet choices to select
+ * sets with different properties.
+ *
+ * @param cnv The converter for which a set is requested.
+ * @param setFillIn A valid USet *. It will be cleared by this function before
+ *            the converter's specific set is filled into the USet.
+ * @param whichSet A UConverterUnicodeSet selector;
+ *              currently UCNV_ROUNDTRIP_SET is the only supported value.
+ * @param pErrorCode ICU error code in/out parameter.
+ *                   Must fulfill U_SUCCESS before the function call.
+ *
+ * @see UConverterUnicodeSet
+ * @see uset_open
+ * @see uset_close
+ * @stable ICU 2.6
+ */
+U_STABLE void U_EXPORT2
+ucnv_getUnicodeSet(const UConverter *cnv,
+                   USet *setFillIn,
+                   UConverterUnicodeSet whichSet,
+                   UErrorCode *pErrorCode);
+
+/**
+ * Gets the current calback function used by the converter when an illegal
+ *  or invalid codepage sequence is found. 
+ * Context pointers are always owned by the caller.
+ *
+ * @param converter the unicode converter
+ * @param action fillin: returns the callback function pointer
+ * @param context fillin: returns the callback's private void* context
+ * @see ucnv_setToUCallBack
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucnv_getToUCallBack (const UConverter * converter,
+                     UConverterToUCallback *action,
+                     const void **context);
+
+/**
+ * Gets the current callback function used by the converter when illegal 
+ * or invalid Unicode sequence is found.
+ * Context pointers are always owned by the caller.
+ *
+ * @param converter the unicode converter
+ * @param action fillin: returns the callback function pointer
+ * @param context fillin: returns the callback's private void* context
+ * @see ucnv_setFromUCallBack
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucnv_getFromUCallBack (const UConverter * converter,
+                       UConverterFromUCallback *action,
+                       const void **context);
+
+/**
+ * Changes the callback function used by the converter when
+ * an illegal or invalid sequence is found.
+ * Context pointers are always owned by the caller.
+ * Predefined actions and contexts can be found in the ucnv_err.h header.
+ *
+ * @param converter the unicode converter
+ * @param newAction the new callback function
+ * @param newContext the new toUnicode callback context pointer. This can be NULL.
+ * @param oldAction fillin: returns the old callback function pointer. This can be NULL.
+ * @param oldContext fillin: returns the old callback's private void* context. This can be NULL.
+ * @param err The error code status
+ * @see ucnv_getToUCallBack
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucnv_setToUCallBack (UConverter * converter,
+                     UConverterToUCallback newAction,
+                     const void* newContext,
+                     UConverterToUCallback *oldAction,
+                     const void** oldContext,
+                     UErrorCode * err);
+
+/**
+ * Changes the current callback function used by the converter when
+ * an illegal or invalid sequence is found.
+ * Context pointers are always owned by the caller.
+ * Predefined actions and contexts can be found in the ucnv_err.h header.
+ *
+ * @param converter the unicode converter
+ * @param newAction the new callback function
+ * @param newContext the new fromUnicode callback context pointer. This can be NULL.
+ * @param oldAction fillin: returns the old callback function pointer. This can be NULL.
+ * @param oldContext fillin: returns the old callback's private void* context. This can be NULL.
+ * @param err The error code status
+ * @see ucnv_getFromUCallBack
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucnv_setFromUCallBack (UConverter * converter,
+                       UConverterFromUCallback newAction,
+                       const void *newContext,
+                       UConverterFromUCallback *oldAction,
+                       const void **oldContext,
+                       UErrorCode * err);
+
+/**
+ * Converts an array of unicode characters to an array of codepage
+ * characters. This function is optimized for converting a continuous
+ * stream of data in buffer-sized chunks, where the entire source and
+ * target does not fit in available buffers.
+ * 
+ * The source pointer is an in/out parameter. It starts out pointing where the 
+ * conversion is to begin, and ends up pointing after the last UChar consumed. 
+ * 
+ * Target similarly starts out pointer at the first available byte in the output
+ * buffer, and ends up pointing after the last byte written to the output.
+ * 
+ * The converter always attempts to consume the entire source buffer, unless 
+ * (1.) the target buffer is full, or (2.) a failing error is returned from the
+ * current callback function.  When a successful error status has been
+ * returned, it means that all of the source buffer has been
+ *  consumed. At that point, the caller should reset the source and
+ *  sourceLimit pointers to point to the next chunk.
+ * 
+ * At the end of the stream (flush==TRUE), the input is completely consumed
+ * when *source==sourceLimit and no error code is set.
+ * The converter object is then automatically reset by this function.
+ * (This means that a converter need not be reset explicitly between data
+ * streams if it finishes the previous stream without errors.)
+ * 
+ * This is a <I>stateful</I> conversion. Additionally, even when all source data has
+ * been consumed, some data may be in the converters' internal state.
+ * Call this function repeatedly, updating the target pointers with
+ * the next empty chunk of target in case of a
+ * <TT>U_BUFFER_OVERFLOW_ERROR</TT>, and updating the source  pointers
+ *  with the next chunk of source when a successful error status is
+ * returned, until there are no more chunks of source data.
+ * @param converter the Unicode converter
+ * @param target I/O parameter. Input : Points to the beginning of the buffer to copy
+ *  codepage characters to. Output : points to after the last codepage character copied
+ *  to <TT>target</TT>.
+ * @param targetLimit the pointer just after last of the <TT>target</TT> buffer
+ * @param source I/O parameter, pointer to pointer to the source Unicode character buffer. 
+ * @param sourceLimit the pointer just after the last of the source buffer
+ * @param offsets if NULL is passed, nothing will happen to it, otherwise it needs to have the same number
+ * of allocated cells as <TT>target</TT>. Will fill in offsets from target to source pointer
+ * e.g: <TT>offsets[3]</TT> is equal to 6, it means that the <TT>target[3]</TT> was a result of transcoding <TT>source[6]</TT>
+ * For output data carried across calls, and other data without a specific source character
+ * (such as from escape sequences or callbacks)  -1 will be placed for offsets. 
+ * @param flush set to <TT>TRUE</TT> if the current source buffer is the last available
+ * chunk of the source, <TT>FALSE</TT> otherwise. Note that if a failing status is returned,
+ * this function may have to be called multiple times with flush set to <TT>TRUE</TT> until
+ * the source buffer is consumed.
+ * @param err the error status.  <TT>U_ILLEGAL_ARGUMENT_ERROR</TT> will be set if the
+ * converter is <TT>NULL</TT>.
+ * <code>U_BUFFER_OVERFLOW_ERROR</code> will be set if the target is full and there is 
+ * still data to be written to the target.
+ * @see ucnv_fromUChars
+ * @see ucnv_convert
+ * @see ucnv_getMinCharSize
+ * @see ucnv_setToUCallBack
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 
+ucnv_fromUnicode (UConverter * converter,
+                  char **target,
+                  const char *targetLimit,
+                  const UChar ** source,
+                  const UChar * sourceLimit,
+                  int32_t* offsets,
+                  UBool flush,
+                  UErrorCode * err);
+
+/**
+ * Converts a buffer of codepage bytes into an array of unicode UChars
+ * characters. This function is optimized for converting a continuous
+ * stream of data in buffer-sized chunks, where the entire source and
+ * target does not fit in available buffers.
+ * 
+ * The source pointer is an in/out parameter. It starts out pointing where the 
+ * conversion is to begin, and ends up pointing after the last byte of source consumed. 
+ * 
+ * Target similarly starts out pointer at the first available UChar in the output
+ * buffer, and ends up pointing after the last UChar written to the output. 
+ * It does NOT necessarily keep UChar sequences together.
+ * 
+ * The converter always attempts to consume the entire source buffer, unless 
+ * (1.) the target buffer is full, or (2.) a failing error is returned from the
+ * current callback function.  When a successful error status has been
+ * returned, it means that all of the source buffer has been
+ *  consumed. At that point, the caller should reset the source and
+ *  sourceLimit pointers to point to the next chunk.
+ *
+ * At the end of the stream (flush==TRUE), the input is completely consumed
+ * when *source==sourceLimit and no error code is set
+ * The converter object is then automatically reset by this function.
+ * (This means that a converter need not be reset explicitly between data
+ * streams if it finishes the previous stream without errors.)
+ * 
+ * This is a <I>stateful</I> conversion. Additionally, even when all source data has
+ * been consumed, some data may be in the converters' internal state.
+ * Call this function repeatedly, updating the target pointers with
+ * the next empty chunk of target in case of a
+ * <TT>U_BUFFER_OVERFLOW_ERROR</TT>, and updating the source  pointers
+ *  with the next chunk of source when a successful error status is
+ * returned, until there are no more chunks of source data.
+ * @param converter the Unicode converter
+ * @param target I/O parameter. Input : Points to the beginning of the buffer to copy
+ *  UChars into. Output : points to after the last UChar copied.
+ * @param targetLimit the pointer just after the end of the <TT>target</TT> buffer
+ * @param source I/O parameter, pointer to pointer to the source codepage buffer. 
+ * @param sourceLimit the pointer to the byte after the end of the source buffer
+ * @param offsets if NULL is passed, nothing will happen to it, otherwise it needs to have the same number
+ * of allocated cells as <TT>target</TT>. Will fill in offsets from target to source pointer
+ * e.g: <TT>offsets[3]</TT> is equal to 6, it means that the <TT>target[3]</TT> was a result of transcoding <TT>source[6]</TT>
+ * For output data carried across calls, and other data without a specific source character
+ * (such as from escape sequences or callbacks)  -1 will be placed for offsets. 
+ * @param flush set to <TT>TRUE</TT> if the current source buffer is the last available
+ * chunk of the source, <TT>FALSE</TT> otherwise. Note that if a failing status is returned,
+ * this function may have to be called multiple times with flush set to <TT>TRUE</TT> until
+ * the source buffer is consumed.
+ * @param err the error status.  <TT>U_ILLEGAL_ARGUMENT_ERROR</TT> will be set if the
+ * converter is <TT>NULL</TT>.
+ * <code>U_BUFFER_OVERFLOW_ERROR</code> will be set if the target is full and there is 
+ * still data to be written to the target. 
+ * @see ucnv_fromUChars
+ * @see ucnv_convert
+ * @see ucnv_getMinCharSize
+ * @see ucnv_setFromUCallBack
+ * @see ucnv_getNextUChar
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 
+ucnv_toUnicode(UConverter *converter,
+               UChar **target,
+               const UChar *targetLimit,
+               const char **source,
+               const char *sourceLimit,
+               int32_t *offsets,
+               UBool flush,
+               UErrorCode *err);
+
+/**
+ * Convert the Unicode string into a codepage string using an existing UConverter.
+ * The output string is NUL-terminated if possible.
+ *
+ * This function is a more convenient but less powerful version of ucnv_fromUnicode().
+ * It is only useful for whole strings, not for streaming conversion.
+ *
+ * The maximum output buffer capacity required (barring output from callbacks) will be
+ * UCNV_GET_MAX_BYTES_FOR_STRING(srcLength, ucnv_getMaxCharSize(cnv)).
+ *
+ * @param cnv the converter object to be used (ucnv_resetFromUnicode() will be called)
+ * @param src the input Unicode string
+ * @param srcLength the input string length, or -1 if NUL-terminated
+ * @param dest destination string buffer, can be NULL if destCapacity==0
+ * @param destCapacity the number of chars available at dest
+ * @param pErrorCode normal ICU error code;
+ *                  common error codes that may be set by this function include
+ *                  U_BUFFER_OVERFLOW_ERROR, U_STRING_NOT_TERMINATED_WARNING,
+ *                  U_ILLEGAL_ARGUMENT_ERROR, and conversion errors
+ * @return the length of the output string, not counting the terminating NUL;
+ *         if the length is greater than destCapacity, then the string will not fit
+ *         and a buffer of the indicated length would need to be passed in
+ * @see ucnv_fromUnicode
+ * @see ucnv_convert
+ * @see UCNV_GET_MAX_BYTES_FOR_STRING
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucnv_fromUChars(UConverter *cnv,
+                char *dest, int32_t destCapacity,
+                const UChar *src, int32_t srcLength,
+                UErrorCode *pErrorCode);
+
+/**
+ * Convert the codepage string into a Unicode string using an existing UConverter.
+ * The output string is NUL-terminated if possible.
+ *
+ * This function is a more convenient but less powerful version of ucnv_toUnicode().
+ * It is only useful for whole strings, not for streaming conversion.
+ *
+ * The maximum output buffer capacity required (barring output from callbacks) will be
+ * 2*srcLength (each char may be converted into a surrogate pair).
+ *
+ * @param cnv the converter object to be used (ucnv_resetToUnicode() will be called)
+ * @param src the input codepage string
+ * @param srcLength the input string length, or -1 if NUL-terminated
+ * @param dest destination string buffer, can be NULL if destCapacity==0
+ * @param destCapacity the number of UChars available at dest
+ * @param pErrorCode normal ICU error code;
+ *                  common error codes that may be set by this function include
+ *                  U_BUFFER_OVERFLOW_ERROR, U_STRING_NOT_TERMINATED_WARNING,
+ *                  U_ILLEGAL_ARGUMENT_ERROR, and conversion errors
+ * @return the length of the output string, not counting the terminating NUL;
+ *         if the length is greater than destCapacity, then the string will not fit
+ *         and a buffer of the indicated length would need to be passed in
+ * @see ucnv_toUnicode
+ * @see ucnv_convert
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucnv_toUChars(UConverter *cnv,
+              UChar *dest, int32_t destCapacity,
+              const char *src, int32_t srcLength,
+              UErrorCode *pErrorCode);
+
+/**
+ * Convert a codepage buffer into Unicode one character at a time.
+ * The input is completely consumed when the U_INDEX_OUTOFBOUNDS_ERROR is set.
+ *
+ * Advantage compared to ucnv_toUnicode() or ucnv_toUChars():
+ * - Faster for small amounts of data, for most converters, e.g.,
+ *   US-ASCII, ISO-8859-1, UTF-8/16/32, and most "normal" charsets.
+ *   (For complex converters, e.g., SCSU, UTF-7 and ISO 2022 variants,
+ *    it uses ucnv_toUnicode() internally.)
+ * - Convenient.
+ *
+ * Limitations compared to ucnv_toUnicode():
+ * - Always assumes flush=TRUE.
+ *   This makes ucnv_getNextUChar() unsuitable for "streaming" conversion,
+ *   that is, for where the input is supplied in multiple buffers,
+ *   because ucnv_getNextUChar() will assume the end of the input at the end
+ *   of the first buffer.
+ * - Does not provide offset output.
+ *
+ * It is possible to "mix" ucnv_getNextUChar() and ucnv_toUnicode() because
+ * ucnv_getNextUChar() uses the current state of the converter
+ * (unlike ucnv_toUChars() which always resets first).
+ * However, if ucnv_getNextUChar() is called after ucnv_toUnicode()
+ * stopped in the middle of a character sequence (with flush=FALSE),
+ * then ucnv_getNextUChar() will always use the slower ucnv_toUnicode()
+ * internally until the next character boundary.
+ * (This is new in ICU 2.6. In earlier releases, ucnv_getNextUChar() had to
+ * start at a character boundary.)
+ *
+ * Instead of using ucnv_getNextUChar(), it is recommended
+ * to convert using ucnv_toUnicode() or ucnv_toUChars()
+ * and then iterate over the text using U16_NEXT() or a UCharIterator (uiter.h)
+ * or a C++ CharacterIterator or similar.
+ * This allows streaming conversion and offset output, for example.
+ *
+ * <p>Handling of surrogate pairs and supplementary-plane code points:<br>
+ * There are two different kinds of codepages that provide mappings for surrogate characters:
+ * <ul>
+ *   <li>Codepages like UTF-8, UTF-32, and GB 18030 provide direct representations for Unicode
+ *       code points U+10000-U+10ffff as well as for single surrogates U+d800-U+dfff.
+ *       Each valid sequence will result in exactly one returned code point.
+ *       If a sequence results in a single surrogate, then that will be returned
+ *       by itself, even if a neighboring sequence encodes the matching surrogate.</li>
+ *   <li>Codepages like SCSU and LMBCS (and UTF-16) provide direct representations only for BMP code points
+ *       including surrogates. Code points in supplementary planes are represented with
+ *       two sequences, each encoding a surrogate.
+ *       For these codepages, matching pairs of surrogates will be combined into single
+ *       code points for returning from this function.
+ *       (Note that SCSU is actually a mix of these codepage types.)</li>
+ * </ul></p>
+ *
+ * @param converter an open UConverter
+ * @param source the address of a pointer to the codepage buffer, will be
+ *  updated to point after the bytes consumed in the conversion call.
+ * @param sourceLimit points to the end of the input buffer
+ * @param err fills in error status (see ucnv_toUnicode)
+ * <code>U_INDEX_OUTOFBOUNDS_ERROR</code> will be set if the input 
+ * is empty or does not convert to any output (e.g.: pure state-change 
+ * codes SI/SO, escape sequences for ISO 2022,
+ * or if the callback did not output anything, ...).
+ * This function will not set a <code>U_BUFFER_OVERFLOW_ERROR</code> because
+ *  the "buffer" is the return code. However, there might be subsequent output
+ *  stored in the converter object
+ * that will be returned in following calls to this function.
+ * @return a UChar32 resulting from the partial conversion of source
+ * @see ucnv_toUnicode
+ * @see ucnv_toUChars
+ * @see ucnv_convert
+ * @stable ICU 2.0
+ */
+U_STABLE UChar32 U_EXPORT2
+ucnv_getNextUChar(UConverter * converter,
+                  const char **source,
+                  const char * sourceLimit,
+                  UErrorCode * err);
+
+/**
+ * Convert from one external charset to another using two existing UConverters.
+ * Internally, two conversions - ucnv_toUnicode() and ucnv_fromUnicode() -
+ * are used, "pivoting" through 16-bit Unicode.
+ *
+ * Important: For streaming conversion (multiple function calls for successive
+ * parts of a text stream), the caller must provide a pivot buffer explicitly,
+ * and must preserve the pivot buffer and associated pointers from one
+ * call to another. (The buffer may be moved if its contents and the relative
+ * pointer positions are preserved.)
+ *
+ * There is a similar function, ucnv_convert(),
+ * which has the following limitations:
+ * - it takes charset names, not converter objects, so that
+ *   - two converters are opened for each call
+ *   - only single-string conversion is possible, not streaming operation
+ * - it does not provide enough information to find out,
+ *   in case of failure, whether the toUnicode or
+ *   the fromUnicode conversion failed
+ *
+ * By contrast, ucnv_convertEx()
+ * - takes UConverter parameters instead of charset names
+ * - fully exposes the pivot buffer for streaming conversion and complete error handling
+ *
+ * ucnv_convertEx() also provides further convenience:
+ * - an option to reset the converters at the beginning
+ *   (if reset==TRUE, see parameters;
+ *    also sets *pivotTarget=*pivotSource=pivotStart)
+ * - allow NUL-terminated input
+ *   (only a single NUL byte, will not work for charsets with multi-byte NULs)
+ *   (if sourceLimit==NULL, see parameters)
+ * - terminate with a NUL on output
+ *   (only a single NUL byte, not useful for charsets with multi-byte NULs),
+ *   or set U_STRING_NOT_TERMINATED_WARNING if the output exactly fills
+ *   the target buffer
+ * - the pivot buffer can be provided internally;
+ *   possible only for whole-string conversion, not streaming conversion;
+ *   in this case, the caller will not be able to get details about where an
+ *   error occurred
+ *   (if pivotStart==NULL, see below)
+ *
+ * The function returns when one of the following is true:
+ * - the entire source text has been converted successfully to the target buffer
+ * - a target buffer overflow occurred (U_BUFFER_OVERFLOW_ERROR)
+ * - a conversion error occurred
+ *   (other U_FAILURE(), see description of pErrorCode)
+ *
+ * Limitation compared to the direct use of
+ * ucnv_fromUnicode() and ucnv_toUnicode():
+ * ucnv_convertEx() does not provide offset information.
+ *
+ * Limitation compared to ucnv_fromUChars() and ucnv_toUChars():
+ * ucnv_convertEx() does not support preflighting directly.
+ *
+ * Sample code for converting a single string from
+ * one external charset to UTF-8, ignoring the location of errors:
+ *
+ * \code
+ * int32_t
+ * myToUTF8(UConverter *cnv,
+ *          const char *s, int32_t length,
+ *          char *u8, int32_t capacity,
+ *          UErrorCode *pErrorCode) {
+ *     UConverter *utf8Cnv;
+ *     char *target;
+ *
+ *     if(U_FAILURE(*pErrorCode)) {
+ *         return 0;
+ *     }
+ *
+ *     utf8Cnv=myGetCachedUTF8Converter(pErrorCode);
+ *     if(U_FAILURE(*pErrorCode)) {
+ *         return 0;
+ *     }
+ *
+ *     if(length<0) {
+ *         length=strlen(s);
+ *     }
+ *     target=u8;
+ *     ucnv_convertEx(utf8Cnv, cnv,
+ *                    &target, u8+capacity,
+ *                    &s, s+length,
+ *                    NULL, NULL, NULL, NULL,
+ *                    TRUE, TRUE,
+ *                    pErrorCode);
+ * 
+ *     myReleaseCachedUTF8Converter(utf8Cnv);
+ *
+ *     // return the output string length, but without preflighting
+ *     return (int32_t)(target-u8);
+ * }
+ * \endcode
+ *
+ * @param targetCnv     Output converter, used to convert from the UTF-16 pivot
+ *                      to the target using ucnv_fromUnicode().
+ * @param sourceCnv     Input converter, used to convert from the source to
+ *                      the UTF-16 pivot using ucnv_toUnicode().
+ * @param target        I/O parameter, same as for ucnv_fromUChars().
+ *                      Input: *target points to the beginning of the target buffer.
+ *                      Output: *target points to the first unit after the last char written.
+ * @param targetLimit   Pointer to the first unit after the target buffer.
+ * @param source        I/O parameter, same as for ucnv_toUChars().
+ *                      Input: *source points to the beginning of the source buffer.
+ *                      Output: *source points to the first unit after the last char read.
+ * @param sourceLimit   Pointer to the first unit after the source buffer.
+ * @param pivotStart    Pointer to the UTF-16 pivot buffer. If pivotStart==NULL,
+ *                      then an internal buffer is used and the other pivot
+ *                      arguments are ignored and can be NULL as well.
+ * @param pivotSource   I/O parameter, same as source in ucnv_fromUChars() for
+ *                      conversion from the pivot buffer to the target buffer.
+ * @param pivotTarget   I/O parameter, same as target in ucnv_toUChars() for
+ *                      conversion from the source buffer to the pivot buffer.
+ *                      It must be pivotStart<=*pivotSource<=*pivotTarget<=pivotLimit
+ *                      and pivotStart<pivotLimit (unless pivotStart==NULL).
+ * @param pivotLimit    Pointer to the first unit after the pivot buffer.
+ * @param reset         If TRUE, then ucnv_resetToUnicode(sourceCnv) and
+ *                      ucnv_resetFromUnicode(targetCnv) are called, and the
+ *                      pivot pointers are reset (*pivotTarget=*pivotSource=pivotStart).
+ * @param flush         If true, indicates the end of the input.
+ *                      Passed directly to ucnv_toUnicode(), and carried over to
+ *                      ucnv_fromUnicode() when the source is empty as well.
+ * @param pErrorCode    ICU error code in/out parameter.
+ *                      Must fulfill U_SUCCESS before the function call.
+ *                      U_BUFFER_OVERFLOW_ERROR always refers to the target buffer
+ *                      because overflows into the pivot buffer are handled internally.
+ *                      Other conversion errors are from the source-to-pivot
+ *                      conversion if *pivotSource==pivotStart, otherwise from
+ *                      the pivot-to-target conversion.
+ *
+ * @see ucnv_convert
+ * @see ucnv_fromAlgorithmic
+ * @see ucnv_toAlgorithmic
+ * @see ucnv_fromUnicode
+ * @see ucnv_toUnicode
+ * @see ucnv_fromUChars
+ * @see ucnv_toUChars
+ * @stable ICU 2.6
+ */
+U_STABLE void U_EXPORT2
+ucnv_convertEx(UConverter *targetCnv, UConverter *sourceCnv,
+               char **target, const char *targetLimit,
+               const char **source, const char *sourceLimit,
+               UChar *pivotStart, UChar **pivotSource,
+               UChar **pivotTarget, const UChar *pivotLimit,
+               UBool reset, UBool flush,
+               UErrorCode *pErrorCode);
+
+/**
+ * Convert from one external charset to another.
+ * Internally, two converters are opened according to the name arguments,
+ * then the text is converted to and from the 16-bit Unicode "pivot"
+ * using ucnv_convertEx(), then the converters are closed again.
+ *
+ * This is a convenience function, not an efficient way to convert a lot of text:
+ * ucnv_convert()
+ * - takes charset names, not converter objects, so that
+ *   - two converters are opened for each call
+ *   - only single-string conversion is possible, not streaming operation
+ * - does not provide enough information to find out,
+ *   in case of failure, whether the toUnicode or
+ *   the fromUnicode conversion failed
+ * - allows NUL-terminated input
+ *   (only a single NUL byte, will not work for charsets with multi-byte NULs)
+ *   (if sourceLength==-1, see parameters)
+ * - terminate with a NUL on output
+ *   (only a single NUL byte, not useful for charsets with multi-byte NULs),
+ *   or set U_STRING_NOT_TERMINATED_WARNING if the output exactly fills
+ *   the target buffer
+ * - a pivot buffer is provided internally
+ *
+ * The function returns when one of the following is true:
+ * - the entire source text has been converted successfully to the target buffer
+ *   and either the target buffer is terminated with a single NUL byte
+ *   or the error code is set to U_STRING_NOT_TERMINATED_WARNING
+ * - a target buffer overflow occurred (U_BUFFER_OVERFLOW_ERROR)
+ *   and the full output string length is returned ("preflighting")
+ * - a conversion error occurred
+ *   (other U_FAILURE(), see description of pErrorCode)
+ *
+ * @param toConverterName   The name of the converter that is used to convert
+ *                          from the UTF-16 pivot buffer to the target.
+ * @param fromConverterName The name of the converter that is used to convert
+ *                          from the source to the UTF-16 pivot buffer.
+ * @param target            Pointer to the output buffer.
+ * @param targetCapacity    Capacity of the target, in bytes.
+ * @param source            Pointer to the input buffer.
+ * @param sourceLength      Length of the input text, in bytes, or -1 for NUL-terminated input.
+ * @param pErrorCode        ICU error code in/out parameter.
+ *                          Must fulfill U_SUCCESS before the function call.
+ * @return Length of the complete output text in bytes, even if it exceeds the targetCapacity
+ *         and a U_BUFFER_OVERFLOW_ERROR is set.
+ *
+ * @see ucnv_convertEx
+ * @see ucnv_fromAlgorithmic
+ * @see ucnv_toAlgorithmic
+ * @see ucnv_fromUnicode
+ * @see ucnv_toUnicode
+ * @see ucnv_fromUChars
+ * @see ucnv_toUChars
+ * @see ucnv_getNextUChar
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucnv_convert(const char *toConverterName,
+             const char *fromConverterName,
+             char *target,
+             int32_t targetCapacity,
+             const char *source,
+             int32_t sourceLength,
+             UErrorCode *pErrorCode);
+
+/**
+ * Convert from one external charset to another.
+ * Internally, the text is converted to and from the 16-bit Unicode "pivot"
+ * using ucnv_convertEx(). ucnv_toAlgorithmic() works exactly like ucnv_convert()
+ * except that the two converters need not be looked up and opened completely.
+ *
+ * The source-to-pivot conversion uses the cnv converter parameter.
+ * The pivot-to-target conversion uses a purely algorithmic converter
+ * according to the specified type, e.g., UCNV_UTF8 for a UTF-8 converter.
+ *
+ * Internally, the algorithmic converter is opened and closed for each
+ * function call, which is more efficient than using the public ucnv_open()
+ * but somewhat less efficient than only resetting an existing converter
+ * and using ucnv_convertEx().
+ *
+ * This function is more convenient than ucnv_convertEx() for single-string
+ * conversions, especially when "preflighting" is desired (returning the length
+ * of the complete output even if it does not fit into the target buffer;
+ * see the User Guide Strings chapter). See ucnv_convert() for details.
+ *
+ * @param algorithmicType   UConverterType constant identifying the desired target
+ *                          charset as a purely algorithmic converter.
+ *                          Those are converters for Unicode charsets like
+ *                          UTF-8, BOCU-1, SCSU, UTF-7, IMAP-mailbox-name, etc.,
+ *                          as well as US-ASCII and ISO-8859-1.
+ * @param cnv               The converter that is used to convert
+ *                          from the source to the UTF-16 pivot buffer.
+ * @param target            Pointer to the output buffer.
+ * @param targetCapacity    Capacity of the target, in bytes.
+ * @param source            Pointer to the input buffer.
+ * @param sourceLength      Length of the input text, in bytes
+ * @param pErrorCode        ICU error code in/out parameter.
+ *                          Must fulfill U_SUCCESS before the function call.
+ * @return Length of the complete output text in bytes, even if it exceeds the targetCapacity
+ *         and a U_BUFFER_OVERFLOW_ERROR is set.
+ *
+ * @see ucnv_fromAlgorithmic
+ * @see ucnv_convert
+ * @see ucnv_convertEx
+ * @see ucnv_fromUnicode
+ * @see ucnv_toUnicode
+ * @see ucnv_fromUChars
+ * @see ucnv_toUChars
+ * @stable ICU 2.6
+ */
+U_STABLE int32_t U_EXPORT2
+ucnv_toAlgorithmic(UConverterType algorithmicType,
+                   UConverter *cnv,
+                   char *target, int32_t targetCapacity,
+                   const char *source, int32_t sourceLength,
+                   UErrorCode *pErrorCode);
+
+/**
+ * Convert from one external charset to another.
+ * Internally, the text is converted to and from the 16-bit Unicode "pivot"
+ * using ucnv_convertEx(). ucnv_fromAlgorithmic() works exactly like ucnv_convert()
+ * except that the two converters need not be looked up and opened completely.
+ *
+ * The source-to-pivot conversion uses a purely algorithmic converter
+ * according to the specified type, e.g., UCNV_UTF8 for a UTF-8 converter.
+ * The pivot-to-target conversion uses the cnv converter parameter.
+ *
+ * Internally, the algorithmic converter is opened and closed for each
+ * function call, which is more efficient than using the public ucnv_open()
+ * but somewhat less efficient than only resetting an existing converter
+ * and using ucnv_convertEx().
+ *
+ * This function is more convenient than ucnv_convertEx() for single-string
+ * conversions, especially when "preflighting" is desired (returning the length
+ * of the complete output even if it does not fit into the target buffer;
+ * see the User Guide Strings chapter). See ucnv_convert() for details.
+ *
+ * @param cnv               The converter that is used to convert
+ *                          from the UTF-16 pivot buffer to the target.
+ * @param algorithmicType   UConverterType constant identifying the desired source
+ *                          charset as a purely algorithmic converter.
+ *                          Those are converters for Unicode charsets like
+ *                          UTF-8, BOCU-1, SCSU, UTF-7, IMAP-mailbox-name, etc.,
+ *                          as well as US-ASCII and ISO-8859-1.
+ * @param target            Pointer to the output buffer.
+ * @param targetCapacity    Capacity of the target, in bytes.
+ * @param source            Pointer to the input buffer.
+ * @param sourceLength      Length of the input text, in bytes
+ * @param pErrorCode        ICU error code in/out parameter.
+ *                          Must fulfill U_SUCCESS before the function call.
+ * @return Length of the complete output text in bytes, even if it exceeds the targetCapacity
+ *         and a U_BUFFER_OVERFLOW_ERROR is set.
+ *
+ * @see ucnv_fromAlgorithmic
+ * @see ucnv_convert
+ * @see ucnv_convertEx
+ * @see ucnv_fromUnicode
+ * @see ucnv_toUnicode
+ * @see ucnv_fromUChars
+ * @see ucnv_toUChars
+ * @stable ICU 2.6
+ */
+U_STABLE int32_t U_EXPORT2
+ucnv_fromAlgorithmic(UConverter *cnv,
+                     UConverterType algorithmicType,
+                     char *target, int32_t targetCapacity,
+                     const char *source, int32_t sourceLength,
+                     UErrorCode *pErrorCode);
+
+/**
+ * Frees up memory occupied by unused, cached converter shared data.
+ *
+ * @return the number of cached converters successfully deleted
+ * @see ucnv_close
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucnv_flushCache(void);
+
+/**
+ * Returns the number of available converters, as per the alias file.
+ *
+ * @return the number of available converters
+ * @see ucnv_getAvailableName
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucnv_countAvailable(void);
+
+/**
+ * Gets the canonical converter name of the specified converter from a list of
+ * all available converters contaied in the alias file. All converters
+ * in this list can be opened.
+ *
+ * @param n the index to a converter available on the system (in the range <TT>[0..ucnv_countAvaiable()]</TT>)
+ * @return a pointer a string (library owned), or <TT>NULL</TT> if the index is out of bounds.
+ * @see ucnv_countAvailable
+ * @stable ICU 2.0
+ */
+U_STABLE const char* U_EXPORT2
+ucnv_getAvailableName(int32_t n);
+
+/**
+ * Returns a UEnumeration to enumerate all of the canonical converter
+ * names, as per the alias file, regardless of the ability to open each
+ * converter.
+ *
+ * @return A UEnumeration object for getting all the recognized canonical
+ *   converter names.
+ * @see ucnv_getAvailableName
+ * @see uenum_close
+ * @see uenum_next
+ * @stable ICU 2.4
+ */
+U_STABLE UEnumeration * U_EXPORT2
+ucnv_openAllNames(UErrorCode *pErrorCode);
+
+/**
+ * Gives the number of aliases for a given converter or alias name.
+ * If the alias is ambiguous, then the preferred converter is used
+ * and the status is set to U_AMBIGUOUS_ALIAS_WARNING.
+ * This method only enumerates the listed entries in the alias file.
+ * @param alias alias name
+ * @param pErrorCode error status
+ * @return number of names on alias list for given alias
+ * @stable ICU 2.0
+ */
+U_STABLE uint16_t U_EXPORT2 
+ucnv_countAliases(const char *alias, UErrorCode *pErrorCode);
+
+/**
+ * Gives the name of the alias at given index of alias list.
+ * This method only enumerates the listed entries in the alias file.
+ * If the alias is ambiguous, then the preferred converter is used
+ * and the status is set to U_AMBIGUOUS_ALIAS_WARNING.
+ * @param alias alias name
+ * @param n index in alias list
+ * @param pErrorCode result of operation
+ * @return returns the name of the alias at given index
+ * @see ucnv_countAliases
+ * @stable ICU 2.0
+ */
+U_STABLE const char * U_EXPORT2 
+ucnv_getAlias(const char *alias, uint16_t n, UErrorCode *pErrorCode);
+
+/**
+ * Fill-up the list of alias names for the given alias.
+ * This method only enumerates the listed entries in the alias file.
+ * If the alias is ambiguous, then the preferred converter is used
+ * and the status is set to U_AMBIGUOUS_ALIAS_WARNING.
+ * @param alias alias name
+ * @param aliases fill-in list, aliases is a pointer to an array of
+ *        <code>ucnv_countAliases()</code> string-pointers
+ *        (<code>const char *</code>) that will be filled in.
+ *        The strings themselves are owned by the library.
+ * @param pErrorCode result of operation
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 
+ucnv_getAliases(const char *alias, const char **aliases, UErrorCode *pErrorCode);
+
+/**
+ * Return a new UEnumeration object for enumerating all the
+ * alias names for a given converter that are recognized by a standard.
+ * This method only enumerates the listed entries in the alias file.
+ * The convrtrs.txt file can be modified to change the results of
+ * this function.
+ * The first result in this list is the same result given by
+ * <code>ucnv_getStandardName</code>, which is the default alias for
+ * the specified standard name. The returned object must be closed with
+ * <code>uenum_close</code> when you are done with the object.
+ *
+ * @param convName original converter name
+ * @param standard name of the standard governing the names; MIME and IANA
+ *      are such standards
+ * @param pErrorCode The error code
+ * @return A UEnumeration object for getting all aliases that are recognized
+ *      by a standard. If any of the parameters are invalid, NULL
+ *      is returned.
+ * @see ucnv_getStandardName
+ * @see uenum_close
+ * @see uenum_next
+ * @stable ICU 2.2
+ */
+U_STABLE UEnumeration * U_EXPORT2
+ucnv_openStandardNames(const char *convName,
+                       const char *standard,
+                       UErrorCode *pErrorCode);
+
+/**
+ * Gives the number of standards associated to converter names.
+ * @return number of standards
+ * @stable ICU 2.0
+ */
+U_STABLE uint16_t U_EXPORT2
+ucnv_countStandards(void);
+
+/**
+ * Gives the name of the standard at given index of standard list.
+ * @param n index in standard list
+ * @param pErrorCode result of operation
+ * @return returns the name of the standard at given index. Owned by the library.
+ * @stable ICU 2.0
+ */
+U_STABLE const char * U_EXPORT2
+ucnv_getStandard(uint16_t n, UErrorCode *pErrorCode);
+
+/**
+ * Returns a standard name for a given converter name.
+ * <p>
+ * Example alias table:<br>
+ * conv alias1 { STANDARD1 } alias2 { STANDARD1* }
+ * <p>
+ * Result of ucnv_getStandardName("conv", "STANDARD1") from example
+ * alias table:<br>
+ * <b>"alias2"</b>
+ *
+ * @param name original converter name
+ * @param standard name of the standard governing the names; MIME and IANA
+ *        are such standards
+ * @param pErrorCode result of operation
+ * @return returns the standard converter name;
+ *         if a standard converter name cannot be determined,
+ *         then <code>NULL</code> is returned. Owned by the library.
+ * @stable ICU 2.0
+ */
+U_STABLE const char * U_EXPORT2
+ucnv_getStandardName(const char *name, const char *standard, UErrorCode *pErrorCode);
+
+/**
+ * This function will return the internal canonical converter name of the
+ * tagged alias. This is the opposite of ucnv_openStandardNames, which
+ * returns the tagged alias given the canonical name.
+ * <p>
+ * Example alias table:<br>
+ * conv alias1 { STANDARD1 } alias2 { STANDARD1* }
+ * <p>
+ * Result of ucnv_getStandardName("alias1", "STANDARD1") from example
+ * alias table:<br>
+ * <b>"conv"</b>
+ *
+ * @return returns the canonical converter name;
+ *         if a standard or alias name cannot be determined,
+ *         then <code>NULL</code> is returned. The returned string is
+ *         owned by the library.
+ * @see ucnv_getStandardName
+ * @stable ICU 2.4
+ */
+U_STABLE const char * U_EXPORT2
+ucnv_getCanonicalName(const char *alias, const char *standard, UErrorCode *pErrorCode);
+
+/**
+ * Returns the current default converter name. If you want to open
+ * a default converter, you do not need to use this function.
+ * It is faster if you pass a NULL argument to ucnv_open the
+ * default converter.
+ *
+ * If U_CHARSET_IS_UTF8 is defined to 1 in utypes.h then this function
+ * always returns "UTF-8".
+ *
+ * @return returns the current default converter name.
+ *         Storage owned by the library
+ * @see ucnv_setDefaultName
+ * @stable ICU 2.0
+ */
+U_STABLE const char * U_EXPORT2
+ucnv_getDefaultName(void);
+
+/**
+ * This function is not thread safe. DO NOT call this function when ANY ICU
+ * function is being used from more than one thread! This function sets the
+ * current default converter name. If this function needs to be called, it
+ * should be called during application initialization. Most of the time, the
+ * results from ucnv_getDefaultName() or ucnv_open with a NULL string argument
+ * is sufficient for your application.
+ *
+ * If U_CHARSET_IS_UTF8 is defined to 1 in utypes.h then this function
+ * does nothing.
+ *
+ * @param name the converter name to be the default (must be known by ICU).
+ * @see ucnv_getDefaultName
+ * @system
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucnv_setDefaultName(const char *name);
+
+/**
+ * Fixes the backslash character mismapping.  For example, in SJIS, the backslash 
+ * character in the ASCII portion is also used to represent the yen currency sign.  
+ * When mapping from Unicode character 0x005C, it's unclear whether to map the 
+ * character back to yen or backslash in SJIS.  This function will take the input
+ * buffer and replace all the yen sign characters with backslash.  This is necessary
+ * when the user tries to open a file with the input buffer on Windows.
+ * This function will test the converter to see whether such mapping is
+ * required.  You can sometimes avoid using this function by using the correct version
+ * of Shift-JIS.
+ *
+ * @param cnv The converter representing the target codepage.
+ * @param source the input buffer to be fixed
+ * @param sourceLen the length of the input buffer
+ * @see ucnv_isAmbiguous
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucnv_fixFileSeparator(const UConverter *cnv, UChar *source, int32_t sourceLen);
+
+/**
+ * Determines if the converter contains ambiguous mappings of the same
+ * character or not.
+ * @param cnv the converter to be tested
+ * @return TRUE if the converter contains ambiguous mapping of the same 
+ * character, FALSE otherwise.
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+ucnv_isAmbiguous(const UConverter *cnv);
+
+/**
+ * Sets the converter to use fallback mappings or not.
+ * Regardless of this flag, the converter will always use
+ * fallbacks from Unicode Private Use code points, as well as
+ * reverse fallbacks (to Unicode).
+ * For details see ".ucm File Format"
+ * in the Conversion Data chapter of the ICU User Guide:
+ * http://www.icu-project.org/userguide/conversion-data.html#ucmformat
+ *
+ * @param cnv The converter to set the fallback mapping usage on.
+ * @param usesFallback TRUE if the user wants the converter to take advantage of the fallback 
+ * mapping, FALSE otherwise.
+ * @stable ICU 2.0
+ * @see ucnv_usesFallback
+ */
+U_STABLE void U_EXPORT2 
+ucnv_setFallback(UConverter *cnv, UBool usesFallback);
+
+/**
+ * Determines if the converter uses fallback mappings or not.
+ * This flag has restrictions, see ucnv_setFallback().
+ *
+ * @param cnv The converter to be tested
+ * @return TRUE if the converter uses fallback, FALSE otherwise.
+ * @stable ICU 2.0
+ * @see ucnv_setFallback
+ */
+U_STABLE UBool U_EXPORT2 
+ucnv_usesFallback(const UConverter *cnv);
+
+/**
+ * Detects Unicode signature byte sequences at the start of the byte stream
+ * and returns the charset name of the indicated Unicode charset.
+ * NULL is returned when no Unicode signature is recognized.
+ * The number of bytes in the signature is output as well.
+ *
+ * The caller can ucnv_open() a converter using the charset name.
+ * The first code unit (UChar) from the start of the stream will be U+FEFF
+ * (the Unicode BOM/signature character) and can usually be ignored.
+ *
+ * For most Unicode charsets it is also possible to ignore the indicated
+ * number of initial stream bytes and start converting after them.
+ * However, there are stateful Unicode charsets (UTF-7 and BOCU-1) for which
+ * this will not work. Therefore, it is best to ignore the first output UChar
+ * instead of the input signature bytes.
+ * <p>
+ * Usage:
+ * @code     
+ *      UErrorCode err = U_ZERO_ERROR;
+ *      char input[] = { '\xEF','\xBB', '\xBF','\x41','\x42','\x43' };
+ *      int32_t signatureLength = 0;
+ *      char *encoding = ucnv_detectUnicodeSignature(input,sizeof(input),&signatureLength,&err);
+ *      UConverter *conv = NULL;
+ *      UChar output[100];
+ *      UChar *target = output, *out;
+ *      char *source = input;
+ *      if(encoding!=NULL && U_SUCCESS(err)){
+ *          // should signature be discarded ?
+ *          conv = ucnv_open(encoding, &err);
+ *          // do the conversion
+ *          ucnv_toUnicode(conv,
+ *                         target, output + sizeof(output)/U_SIZEOF_UCHAR,
+ *                         source, input + sizeof(input),
+ *                         NULL, TRUE, &err);
+ *          out = output;
+ *          if (discardSignature){
+ *              ++out; // ignore initial U+FEFF
+ *          }
+ *          while(out != target) {
+ *              printf("%04x ", *out++);
+ *          }
+ *          puts("");
+ *      }
+ *     
+ * @endcode
+ *
+ * @param source            The source string in which the signature should be detected.
+ * @param sourceLength      Length of the input string, or -1 if terminated with a NUL byte.
+ * @param signatureLength   A pointer to int32_t to receive the number of bytes that make up the signature 
+ *                          of the detected UTF. 0 if not detected.
+ *                          Can be a NULL pointer.
+ * @param pErrorCode        ICU error code in/out parameter.
+ *                          Must fulfill U_SUCCESS before the function call.
+ * @return The name of the encoding detected. NULL if encoding is not detected. 
+ * @stable ICU 2.4
+ */
+U_STABLE const char* U_EXPORT2
+ucnv_detectUnicodeSignature(const char* source,
+                            int32_t sourceLength,
+                            int32_t *signatureLength,
+                            UErrorCode *pErrorCode);
+
+/**
+ * Returns the number of UChars held in the converter's internal state 
+ * because more input is needed for completing the conversion. This function is 
+ * useful for mapping semantics of ICU's converter interface to those of iconv,
+ * and this information is not needed for normal conversion.
+ * @param cnv       The converter in which the input is held
+ * @param status    ICU error code in/out parameter.
+ *                  Must fulfill U_SUCCESS before the function call.
+ * @return The number of UChars in the state. -1 if an error is encountered.
+ * @stable ICU 3.4
+ */
+U_STABLE int32_t U_EXPORT2
+ucnv_fromUCountPending(const UConverter* cnv, UErrorCode* status);
+
+/**
+ * Returns the number of chars held in the converter's internal state
+ * because more input is needed for completing the conversion. This function is 
+ * useful for mapping semantics of ICU's converter interface to those of iconv,
+ * and this information is not needed for normal conversion.
+ * @param cnv       The converter in which the input is held as internal state
+ * @param status    ICU error code in/out parameter.
+ *                  Must fulfill U_SUCCESS before the function call.
+ * @return The number of chars in the state. -1 if an error is encountered.
+ * @stable ICU 3.4
+ */
+U_STABLE int32_t U_EXPORT2
+ucnv_toUCountPending(const UConverter* cnv, UErrorCode* status);
+
+#endif
+
+#endif
+/*_UCNV*/
diff --git a/source/common/unicode/ucnv_cb.h b/source/common/unicode/ucnv_cb.h
new file mode 100644
index 0000000..f0e67ba
--- /dev/null
+++ b/source/common/unicode/ucnv_cb.h
@@ -0,0 +1,162 @@
+/*
+**********************************************************************
+*   Copyright (C) 2000-2004, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+ *  ucnv_cb.h:
+ *  External APIs for the ICU's codeset conversion library
+ *  Helena Shih
+ * 
+ * Modification History:
+ *
+ *   Date        Name        Description
+ */
+
+/**
+ * \file 
+ * \brief C UConverter functions to aid the writers of callbacks
+ *
+ * <h2> Callback API for UConverter </h2>
+ * 
+ * These functions are provided here for the convenience of the callback
+ * writer. If you are just looking for callback functions to use, please
+ * see ucnv_err.h.  DO NOT call these functions directly when you are 
+ * working with converters, unless your code has been called as a callback
+ * via ucnv_setFromUCallback or ucnv_setToUCallback !!
+ * 
+ * A note about error codes and overflow.  Unlike other ICU functions,
+ * these functions do not expect the error status to be U_ZERO_ERROR.
+ * Callbacks must be much more careful about their error codes.
+ * The error codes used here are in/out parameters, which should be passed
+ * back in the callback's error parameter.
+ * 
+ * For example, if you call ucnv_cbfromUWriteBytes to write data out 
+ * to the output codepage, it may return U_BUFFER_OVERFLOW_ERROR if 
+ * the data did not fit in the target. But this isn't a failing error, 
+ * in fact, ucnv_cbfromUWriteBytes may be called AGAIN with the error
+ * status still U_BUFFER_OVERFLOW_ERROR to attempt to write further bytes,
+ * which will also go into the internal overflow buffers.
+ * 
+ * Concerning offsets, the 'offset' parameters here are relative to the start
+ * of SOURCE.  For example, Suppose the string "ABCD" was being converted 
+ * from Unicode into a codepage which doesn't have a mapping for 'B'.
+ * 'A' will be written out correctly, but
+ * The FromU Callback will be called on an unassigned character for 'B'.
+ * At this point, this is the state of the world:
+ *    Target:    A [..]     [points after A]
+ *    Source:  A B [C] D    [points to C - B has been consumed]
+ *             0 1  2  3 
+ *    codePoint = "B"       [the unassigned codepoint] 
+ * 
+ * Now, suppose a callback wants to write the substitution character '?' to
+ * the target. It calls ucnv_cbFromUWriteBytes() to write the ?. 
+ * It should pass ZERO as the offset, because the offset as far as the 
+ * callback is concerned is relative to the SOURCE pointer [which points 
+ * before 'C'.]  If the callback goes into the args and consumes 'C' also,
+ * it would call FromUWriteBytes with an offset of 1 (and advance the source
+ * pointer).
+ *
+ */
+
+#ifndef UCNV_CB_H
+#define UCNV_CB_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ucnv.h"
+#include "unicode/ucnv_err.h"
+
+/**
+ * ONLY used by FromU callback functions.
+ * Writes out the specified byte output bytes to the target byte buffer or to converter internal buffers.
+ *
+ * @param args callback fromUnicode arguments
+ * @param source source bytes to write
+ * @param length length of bytes to write
+ * @param offsetIndex the relative offset index from callback.
+ * @param err error status. If <TT>U_BUFFER_OVERFLOW</TT> is returned, then U_BUFFER_OVERFLOW <STRONG>must</STRONG> 
+ * be returned to the user, because it means that not all data could be written into the target buffer, and some is 
+ * in the converter error buffer.
+ * @see ucnv_cbFromUWriteSub
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucnv_cbFromUWriteBytes (UConverterFromUnicodeArgs *args,
+                        const char* source,
+                        int32_t length,
+                        int32_t offsetIndex,
+                        UErrorCode * err);
+
+/**
+ * ONLY used by FromU callback functions.  
+ * This function will write out the correct substitution character sequence 
+ * to the target.
+ *
+ * @param args callback fromUnicode arguments
+ * @param offsetIndex the relative offset index from the current source pointer to be used
+ * @param err error status. If <TT>U_BUFFER_OVERFLOW</TT> is returned, then U_BUFFER_OVERFLOW <STRONG>must</STRONG> 
+ * be returned to the user, because it means that not all data could be written into the target buffer, and some is 
+ * in the converter error buffer.
+ * @see ucnv_cbFromUWriteBytes
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 
+ucnv_cbFromUWriteSub (UConverterFromUnicodeArgs *args,
+                      int32_t offsetIndex,
+                      UErrorCode * err);
+
+/**
+ * ONLY used by fromU callback functions.  
+ * This function will write out the error character(s) to the target UChar buffer.
+ *
+ * @param args callback fromUnicode arguments
+ * @param source pointer to pointer to first UChar to write [on exit: 1 after last UChar processed]
+ * @param sourceLimit pointer after last UChar to write
+ * @param offsetIndex the relative offset index from callback which will be set
+ * @param err error status <TT>U_BUFFER_OVERFLOW</TT>
+ * @see ucnv_cbToUWriteSub
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 ucnv_cbFromUWriteUChars(UConverterFromUnicodeArgs *args,
+                             const UChar** source,
+                             const UChar*  sourceLimit,
+                             int32_t offsetIndex,
+                             UErrorCode * err);
+
+/**
+ * ONLY used by ToU callback functions.
+ *  This function will write out the specified characters to the target 
+ * UChar buffer.
+ *
+ * @param args callback toUnicode arguments
+ * @param source source string to write
+ * @param length the length of source string
+ * @param offsetIndex the relative offset index which will be written.
+ * @param err error status <TT>U_BUFFER_OVERFLOW</TT>
+ * @see ucnv_cbToUWriteSub
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 ucnv_cbToUWriteUChars (UConverterToUnicodeArgs *args,
+                                             const UChar* source,
+                                             int32_t length,
+                                             int32_t offsetIndex,
+                                             UErrorCode * err);
+
+/**
+ * ONLY used by ToU  callback functions.  
+ * This function will write out the Unicode substitution character (U+FFFD).
+ *
+ * @param args callback fromUnicode arguments
+ * @param offsetIndex the relative offset index from callback.
+ * @param err error status <TT>U_BUFFER_OVERFLOW</TT>
+ * @see ucnv_cbToUWriteUChars
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 ucnv_cbToUWriteSub (UConverterToUnicodeArgs *args,
+                       int32_t offsetIndex,
+                       UErrorCode * err);
+#endif
+
+#endif
diff --git a/source/common/unicode/ucnv_err.h b/source/common/unicode/ucnv_err.h
new file mode 100644
index 0000000..e092e95
--- /dev/null
+++ b/source/common/unicode/ucnv_err.h
@@ -0,0 +1,463 @@
+/*
+**********************************************************************
+*   Copyright (C) 1999-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+ *
+ *
+ *   ucnv_err.h:
+ */
+
+/**
+ * \file
+ * \brief C UConverter predefined error callbacks
+ *
+ *  <h2>Error Behaviour Functions</h2>
+ *  Defines some error behaviour functions called by ucnv_{from,to}Unicode
+ *  These are provided as part of ICU and many are stable, but they
+ *  can also be considered only as an example of what can be done with
+ *  callbacks.  You may of course write your own.
+ *
+ *  If you want to write your own, you may also find the functions from
+ *  ucnv_cb.h useful when writing your own callbacks.
+ *
+ *  These functions, although public, should NEVER be called directly.
+ *  They should be used as parameters to the ucnv_setFromUCallback
+ *  and ucnv_setToUCallback functions, to set the behaviour of a converter
+ *  when it encounters ILLEGAL/UNMAPPED/INVALID sequences.
+ *
+ *  usage example:  'STOP' doesn't need any context, but newContext
+ *    could be set to something other than 'NULL' if needed. The available
+ *    contexts in this header can modify the default behavior of the callback.
+ *
+ *  \code
+ *  UErrorCode err = U_ZERO_ERROR;
+ *  UConverter *myConverter = ucnv_open("ibm-949", &err);
+ *  const void *oldContext;
+ *  UConverterFromUCallback oldAction;
+ *
+ *
+ *  if (U_SUCCESS(err))
+ *  {
+ *      ucnv_setFromUCallBack(myConverter,
+ *                       UCNV_FROM_U_CALLBACK_STOP,
+ *                       NULL,
+ *                       &oldAction,
+ *                       &oldContext,
+ *                       &status);
+ *  }
+ *  \endcode
+ *
+ *  The code above tells "myConverter" to stop when it encounters an
+ *  ILLEGAL/TRUNCATED/INVALID sequences when it is used to convert from
+ *  Unicode -> Codepage. The behavior from Codepage to Unicode is not changed,
+ *  and ucnv_setToUCallBack would need to be called in order to change
+ *  that behavior too.
+ *
+ *  Here is an example with a context:
+ *
+ *  \code
+ *  UErrorCode err = U_ZERO_ERROR;
+ *  UConverter *myConverter = ucnv_open("ibm-949", &err);
+ *  const void *oldContext;
+ *  UConverterFromUCallback oldAction;
+ *
+ *
+ *  if (U_SUCCESS(err))
+ *  {
+ *      ucnv_setToUCallBack(myConverter,
+ *                       UCNV_TO_U_CALLBACK_SUBSTITUTE,
+ *                       UCNV_SUB_STOP_ON_ILLEGAL,
+ *                       &oldAction,
+ *                       &oldContext,
+ *                       &status);
+ *  }
+ *  \endcode
+ *
+ *  The code above tells "myConverter" to stop when it encounters an
+ *  ILLEGAL/TRUNCATED/INVALID sequences when it is used to convert from
+ *  Codepage -> Unicode. Any unmapped and legal characters will be
+ *  substituted to be the default substitution character.
+ */
+
+#ifndef UCNV_ERR_H
+#define UCNV_ERR_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+/** Forward declaring the UConverter structure. @stable ICU 2.0 */
+struct UConverter;
+
+/** @stable ICU 2.0 */
+typedef struct UConverter UConverter;
+
+/**
+ * FROM_U, TO_U context options for sub callback
+ * @stable ICU 2.0
+ */
+#define UCNV_SUB_STOP_ON_ILLEGAL "i"
+
+/**
+ * FROM_U, TO_U context options for skip callback
+ * @stable ICU 2.0
+ */
+#define UCNV_SKIP_STOP_ON_ILLEGAL "i"
+
+/**
+ * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to ICU (%UXXXX) 
+ * @stable ICU 2.0
+ */
+#define UCNV_ESCAPE_ICU       NULL
+/**
+ * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to JAVA (\\uXXXX)
+ * @stable ICU 2.0
+ */
+#define UCNV_ESCAPE_JAVA      "J"
+/**
+ * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to C (\\uXXXX \\UXXXXXXXX)
+ * TO_U_CALLBACK_ESCAPE option to escape the character value accoding to C (\\xXXXX)
+ * @stable ICU 2.0
+ */
+#define UCNV_ESCAPE_C         "C"
+/**
+ * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to XML Decimal escape \htmlonly(&amp;#DDDD;)\endhtmlonly
+ * TO_U_CALLBACK_ESCAPE context option to escape the character value accoding to XML Decimal escape \htmlonly(&amp;#DDDD;)\endhtmlonly
+ * @stable ICU 2.0
+ */
+#define UCNV_ESCAPE_XML_DEC   "D"
+/**
+ * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to XML Hex escape \htmlonly(&amp;#xXXXX;)\endhtmlonly
+ * TO_U_CALLBACK_ESCAPE context option to escape the character value accoding to XML Hex escape \htmlonly(&amp;#xXXXX;)\endhtmlonly
+ * @stable ICU 2.0
+ */
+#define UCNV_ESCAPE_XML_HEX   "X"
+/**
+ * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to Unicode (U+XXXXX)
+ * @stable ICU 2.0
+ */
+#define UCNV_ESCAPE_UNICODE   "U"
+
+/**
+ * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to CSS2 conventions (\\HH..H<space>, that is,
+ * a backslash, 1..6 hex digits, and a space)
+ * @stable ICU 4.0
+ */
+#define UCNV_ESCAPE_CSS2   "S"
+
+/** 
+ * The process condition code to be used with the callbacks.  
+ * Codes which are greater than UCNV_IRREGULAR should be 
+ * passed on to any chained callbacks.
+ * @stable ICU 2.0
+ */
+typedef enum {
+    UCNV_UNASSIGNED = 0,  /**< The code point is unassigned.
+                             The error code U_INVALID_CHAR_FOUND will be set. */
+    UCNV_ILLEGAL = 1,     /**< The code point is illegal. For example, 
+                             \\x81\\x2E is illegal in SJIS because \\x2E
+                             is not a valid trail byte for the \\x81 
+                             lead byte.
+                             Also, starting with Unicode 3.0.1, non-shortest byte sequences
+                             in UTF-8 (like \\xC1\\xA1 instead of \\x61 for U+0061)
+                             are also illegal, not just irregular.
+                             The error code U_ILLEGAL_CHAR_FOUND will be set. */
+    UCNV_IRREGULAR = 2,   /**< The codepoint is not a regular sequence in 
+                             the encoding. For example, \\xED\\xA0\\x80..\\xED\\xBF\\xBF
+                             are irregular UTF-8 byte sequences for single surrogate
+                             code points.
+                             The error code U_INVALID_CHAR_FOUND will be set. */
+    UCNV_RESET = 3,       /**< The callback is called with this reason when a
+                             'reset' has occured. Callback should reset all
+                             state. */
+    UCNV_CLOSE = 4,        /**< Called when the converter is closed. The
+                             callback should release any allocated memory.*/
+    UCNV_CLONE = 5         /**< Called when ucnv_safeClone() is called on the
+                              converter. the pointer available as the
+                              'context' is an alias to the original converters'
+                              context pointer. If the context must be owned
+                              by the new converter, the callback must clone 
+                              the data and call ucnv_setFromUCallback 
+                              (or setToUCallback) with the correct pointer.
+                              @stable ICU 2.2
+                           */
+} UConverterCallbackReason;
+
+
+/**
+ * The structure for the fromUnicode callback function parameter.
+ * @stable ICU 2.0
+ */
+typedef struct {
+    uint16_t size;              /**< The size of this struct. @stable ICU 2.0 */
+    UBool flush;                /**< The internal state of converter will be reset and data flushed if set to TRUE. @stable ICU 2.0    */
+    UConverter *converter;      /**< Pointer to the converter that is opened and to which this struct is passed as an argument. @stable ICU 2.0  */
+    const UChar *source;        /**< Pointer to the source source buffer. @stable ICU 2.0    */
+    const UChar *sourceLimit;   /**< Pointer to the limit (end + 1) of source buffer. @stable ICU 2.0    */
+    char *target;               /**< Pointer to the target buffer. @stable ICU 2.0    */
+    const char *targetLimit;    /**< Pointer to the limit (end + 1) of target buffer. @stable ICU 2.0     */
+    int32_t *offsets;           /**< Pointer to the buffer that recieves the offsets. *offset = blah ; offset++;. @stable ICU 2.0  */
+} UConverterFromUnicodeArgs;
+
+
+/**
+ * The structure for the toUnicode callback function parameter.
+ * @stable ICU 2.0
+ */
+typedef struct {
+    uint16_t size;              /**< The size of this struct   @stable ICU 2.0 */
+    UBool flush;                /**< The internal state of converter will be reset and data flushed if set to TRUE. @stable ICU 2.0   */
+    UConverter *converter;      /**< Pointer to the converter that is opened and to which this struct is passed as an argument. @stable ICU 2.0 */
+    const char *source;         /**< Pointer to the source source buffer. @stable ICU 2.0    */
+    const char *sourceLimit;    /**< Pointer to the limit (end + 1) of source buffer. @stable ICU 2.0    */
+    UChar *target;              /**< Pointer to the target buffer. @stable ICU 2.0    */
+    const UChar *targetLimit;   /**< Pointer to the limit (end + 1) of target buffer. @stable ICU 2.0     */
+    int32_t *offsets;           /**< Pointer to the buffer that recieves the offsets. *offset = blah ; offset++;. @stable ICU 2.0  */
+} UConverterToUnicodeArgs;
+
+
+/**
+ * DO NOT CALL THIS FUNCTION DIRECTLY!
+ * This From Unicode callback STOPS at the ILLEGAL_SEQUENCE,
+ * returning the error code back to the caller immediately.
+ *
+ * @param context Pointer to the callback's private data
+ * @param fromUArgs Information about the conversion in progress
+ * @param codeUnits Points to 'length' UChars of the concerned Unicode sequence
+ * @param length Size (in bytes) of the concerned codepage sequence
+ * @param codePoint Single UChar32 (UTF-32) containing the concerend Unicode codepoint.
+ * @param reason Defines the reason the callback was invoked
+ * @param err This should always be set to a failure status prior to calling.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 UCNV_FROM_U_CALLBACK_STOP (
+                  const void *context,
+                  UConverterFromUnicodeArgs *fromUArgs,
+                  const UChar* codeUnits,
+                  int32_t length,
+                  UChar32 codePoint,
+                  UConverterCallbackReason reason,
+                  UErrorCode * err);
+
+
+
+/**
+ * DO NOT CALL THIS FUNCTION DIRECTLY!
+ * This To Unicode callback STOPS at the ILLEGAL_SEQUENCE,
+ * returning the error code back to the caller immediately.
+ *
+ * @param context Pointer to the callback's private data
+ * @param toUArgs Information about the conversion in progress
+ * @param codeUnits Points to 'length' bytes of the concerned codepage sequence
+ * @param length Size (in bytes) of the concerned codepage sequence
+ * @param reason Defines the reason the callback was invoked
+ * @param err This should always be set to a failure status prior to calling.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 UCNV_TO_U_CALLBACK_STOP (
+                  const void *context,
+                  UConverterToUnicodeArgs *toUArgs,
+                  const char* codeUnits,
+                  int32_t length,
+                  UConverterCallbackReason reason,
+                  UErrorCode * err);
+
+/**
+ * DO NOT CALL THIS FUNCTION DIRECTLY!
+ * This From Unicode callback skips any ILLEGAL_SEQUENCE, or
+ * skips only UNASSINGED_SEQUENCE depending on the context parameter
+ * simply ignoring those characters. 
+ *
+ * @param context  The function currently recognizes the callback options:
+ *                 UCNV_SKIP_STOP_ON_ILLEGAL: STOPS at the ILLEGAL_SEQUENCE,
+ *                      returning the error code back to the caller immediately.
+ *                 NULL: Skips any ILLEGAL_SEQUENCE
+ * @param fromUArgs Information about the conversion in progress
+ * @param codeUnits Points to 'length' UChars of the concerned Unicode sequence
+ * @param length Size (in bytes) of the concerned codepage sequence
+ * @param codePoint Single UChar32 (UTF-32) containing the concerend Unicode codepoint.
+ * @param reason Defines the reason the callback was invoked
+ * @param err Return value will be set to success if the callback was handled,
+ *      otherwise this value will be set to a failure status.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 UCNV_FROM_U_CALLBACK_SKIP (
+                  const void *context,
+                  UConverterFromUnicodeArgs *fromUArgs,
+                  const UChar* codeUnits,
+                  int32_t length,
+                  UChar32 codePoint,
+                  UConverterCallbackReason reason,
+                  UErrorCode * err);
+
+/**
+ * DO NOT CALL THIS FUNCTION DIRECTLY!
+ * This From Unicode callback will Substitute the ILLEGAL SEQUENCE, or 
+ * UNASSIGNED_SEQUENCE depending on context parameter, with the
+ * current substitution string for the converter. This is the default
+ * callback.
+ *
+ * @param context The function currently recognizes the callback options:
+ *                 UCNV_SUB_STOP_ON_ILLEGAL: STOPS at the ILLEGAL_SEQUENCE,
+ *                      returning the error code back to the caller immediately.
+ *                 NULL: Substitutes any ILLEGAL_SEQUENCE
+ * @param fromUArgs Information about the conversion in progress
+ * @param codeUnits Points to 'length' UChars of the concerned Unicode sequence
+ * @param length Size (in bytes) of the concerned codepage sequence
+ * @param codePoint Single UChar32 (UTF-32) containing the concerend Unicode codepoint.
+ * @param reason Defines the reason the callback was invoked
+ * @param err Return value will be set to success if the callback was handled,
+ *      otherwise this value will be set to a failure status.
+ * @see ucnv_setSubstChars
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 UCNV_FROM_U_CALLBACK_SUBSTITUTE (
+                  const void *context,
+                  UConverterFromUnicodeArgs *fromUArgs,
+                  const UChar* codeUnits,
+                  int32_t length,
+                  UChar32 codePoint,
+                  UConverterCallbackReason reason,
+                  UErrorCode * err);
+
+/**
+ * DO NOT CALL THIS FUNCTION DIRECTLY!
+ * This From Unicode callback will Substitute the ILLEGAL SEQUENCE with the
+ * hexadecimal representation of the illegal codepoints
+ *
+ * @param context The function currently recognizes the callback options:
+ *        <ul>
+ *        <li>UCNV_ESCAPE_ICU: Substitues the  ILLEGAL SEQUENCE with the hexadecimal 
+ *          representation in the format  %UXXXX, e.g. "%uFFFE%u00AC%uC8FE"). 
+ *          In the Event the converter doesn't support the characters {%,U}[A-F][0-9], 
+ *          it will  substitute  the illegal sequence with the substitution characters.
+ *          Note that  codeUnit(32bit int eg: unit of a surrogate pair) is represented as
+ *          %UD84D%UDC56</li>
+ *        <li>UCNV_ESCAPE_JAVA: Substitues the  ILLEGAL SEQUENCE with the hexadecimal 
+ *          representation in the format  \\uXXXX, e.g. "\\uFFFE\\u00AC\\uC8FE"). 
+ *          In the Event the converter doesn't support the characters {\,u}[A-F][0-9], 
+ *          it will  substitute  the illegal sequence with the substitution characters.
+ *          Note that  codeUnit(32bit int eg: unit of a surrogate pair) is represented as
+ *          \\uD84D\\uDC56</li>
+ *        <li>UCNV_ESCAPE_C: Substitues the  ILLEGAL SEQUENCE with the hexadecimal 
+ *          representation in the format  \\uXXXX, e.g. "\\uFFFE\\u00AC\\uC8FE"). 
+ *          In the Event the converter doesn't support the characters {\,u,U}[A-F][0-9], 
+ *          it will  substitute  the illegal sequence with the substitution characters.
+ *          Note that  codeUnit(32bit int eg: unit of a surrogate pair) is represented as
+ *          \\U00023456</li>
+ *        <li>UCNV_ESCAPE_XML_DEC: Substitues the  ILLEGAL SEQUENCE with the decimal 
+ *          representation in the format \htmlonly&amp;#DDDDDDDD;, e.g. "&amp;#65534;&amp;#172;&amp;#51454;")\endhtmlonly. 
+ *          In the Event the converter doesn't support the characters {&amp;,#}[0-9], 
+ *          it will  substitute  the illegal sequence with the substitution characters.
+ *          Note that  codeUnit(32bit int eg: unit of a surrogate pair) is represented as
+ *          &amp;#144470; and Zero padding is ignored.</li>
+ *        <li>UCNV_ESCAPE_XML_HEX:Substitues the  ILLEGAL SEQUENCE with the decimal 
+ *          representation in the format \htmlonly&amp;#xXXXX; e.g. "&amp;#xFFFE;&amp;#x00AC;&amp;#xC8FE;")\endhtmlonly. 
+ *          In the Event the converter doesn't support the characters {&,#,x}[0-9], 
+ *          it will  substitute  the illegal sequence with the substitution characters.
+ *          Note that  codeUnit(32bit int eg: unit of a surrogate pair) is represented as
+ *          \htmlonly&amp;#x23456;\endhtmlonly</li>
+ *        </ul>
+ * @param fromUArgs Information about the conversion in progress
+ * @param codeUnits Points to 'length' UChars of the concerned Unicode sequence
+ * @param length Size (in bytes) of the concerned codepage sequence
+ * @param codePoint Single UChar32 (UTF-32) containing the concerend Unicode codepoint.
+ * @param reason Defines the reason the callback was invoked
+ * @param err Return value will be set to success if the callback was handled,
+ *      otherwise this value will be set to a failure status.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 UCNV_FROM_U_CALLBACK_ESCAPE (
+                  const void *context,
+                  UConverterFromUnicodeArgs *fromUArgs,
+                  const UChar* codeUnits,
+                  int32_t length,
+                  UChar32 codePoint,
+                  UConverterCallbackReason reason,
+                  UErrorCode * err);
+
+
+/**
+ * DO NOT CALL THIS FUNCTION DIRECTLY!
+ * This To Unicode callback skips any ILLEGAL_SEQUENCE, or
+ * skips only UNASSINGED_SEQUENCE depending on the context parameter
+ * simply ignoring those characters. 
+ *
+ * @param context  The function currently recognizes the callback options:
+ *                 UCNV_SKIP_STOP_ON_ILLEGAL: STOPS at the ILLEGAL_SEQUENCE,
+ *                      returning the error code back to the caller immediately.
+ *                 NULL: Skips any ILLEGAL_SEQUENCE
+ * @param toUArgs Information about the conversion in progress
+ * @param codeUnits Points to 'length' bytes of the concerned codepage sequence
+ * @param length Size (in bytes) of the concerned codepage sequence
+ * @param reason Defines the reason the callback was invoked
+ * @param err Return value will be set to success if the callback was handled,
+ *      otherwise this value will be set to a failure status.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 UCNV_TO_U_CALLBACK_SKIP (
+                  const void *context,
+                  UConverterToUnicodeArgs *toUArgs,
+                  const char* codeUnits,
+                  int32_t length,
+                  UConverterCallbackReason reason,
+                  UErrorCode * err);
+
+/**
+ * DO NOT CALL THIS FUNCTION DIRECTLY!
+ * This To Unicode callback will Substitute the ILLEGAL SEQUENCE,or 
+ * UNASSIGNED_SEQUENCE depending on context parameter,  with the
+ * Unicode substitution character, U+FFFD.
+ *
+ * @param context  The function currently recognizes the callback options:
+ *                 UCNV_SUB_STOP_ON_ILLEGAL: STOPS at the ILLEGAL_SEQUENCE,
+ *                      returning the error code back to the caller immediately.
+ *                 NULL: Substitutes any ILLEGAL_SEQUENCE
+ * @param toUArgs Information about the conversion in progress
+ * @param codeUnits Points to 'length' bytes of the concerned codepage sequence
+ * @param length Size (in bytes) of the concerned codepage sequence
+ * @param reason Defines the reason the callback was invoked
+ * @param err Return value will be set to success if the callback was handled,
+ *      otherwise this value will be set to a failure status.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 UCNV_TO_U_CALLBACK_SUBSTITUTE (
+                  const void *context,
+                  UConverterToUnicodeArgs *toUArgs,
+                  const char* codeUnits,
+                  int32_t length,
+                  UConverterCallbackReason reason,
+                  UErrorCode * err);
+
+/**
+ * DO NOT CALL THIS FUNCTION DIRECTLY!
+ * This To Unicode callback will Substitute the ILLEGAL SEQUENCE with the
+ * hexadecimal representation of the illegal bytes
+ *  (in the format  %XNN, e.g. "%XFF%X0A%XC8%X03").
+ *
+ * @param context This function currently recognizes the callback options:
+ *      UCNV_ESCAPE_ICU, UCNV_ESCAPE_JAVA, UCNV_ESCAPE_C, UCNV_ESCAPE_XML_DEC,
+ *      UCNV_ESCAPE_XML_HEX and UCNV_ESCAPE_UNICODE.
+ * @param toUArgs Information about the conversion in progress
+ * @param codeUnits Points to 'length' bytes of the concerned codepage sequence
+ * @param length Size (in bytes) of the concerned codepage sequence
+ * @param reason Defines the reason the callback was invoked
+ * @param err Return value will be set to success if the callback was handled,
+ *      otherwise this value will be set to a failure status.
+ * @stable ICU 2.0
+ */
+
+U_STABLE void U_EXPORT2 UCNV_TO_U_CALLBACK_ESCAPE (
+                  const void *context,
+                  UConverterToUnicodeArgs *toUArgs,
+                  const char* codeUnits,
+                  int32_t length,
+                  UConverterCallbackReason reason,
+                  UErrorCode * err);
+
+#endif
+
+#endif
+
+/*UCNV_ERR_H*/ 
diff --git a/source/common/unicode/ucnvsel.h b/source/common/unicode/ucnvsel.h
new file mode 100644
index 0000000..0830003
--- /dev/null
+++ b/source/common/unicode/ucnvsel.h
@@ -0,0 +1,182 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2008-2010, International Business Machines
+*   Corporation, Google and others.  All Rights Reserved.
+*
+*******************************************************************************
+*/
+/*
+ * Author : eldawy@google.com (Mohamed Eldawy)
+ * ucnvsel.h
+ *
+ * Purpose: To generate a list of encodings capable of handling
+ * a given Unicode text
+ *
+ * Started 09-April-2008
+ */
+
+#ifndef __ICU_UCNV_SEL_H__
+#define __ICU_UCNV_SEL_H__
+
+#include "unicode/uset.h"
+#include "unicode/utypes.h"
+#include "unicode/utf16.h"
+#include "unicode/uenum.h"
+#include "unicode/ucnv.h"
+#include "unicode/localpointer.h"
+
+/**
+ * \file
+ *
+ * A converter selector is built with a set of encoding/charset names
+ * and given an input string returns the set of names of the
+ * corresponding converters which can convert the string.
+ *
+ * A converter selector can be serialized into a buffer and reopened
+ * from the serialized form.
+ */
+
+/**
+ * @{
+ * The selector data structure
+ */
+struct UConverterSelector;
+typedef struct UConverterSelector UConverterSelector;
+/** @} */
+
+/**
+ * Open a selector.
+ * If converterListSize is 0, build for all available converters.
+ * If excludedCodePoints is NULL, don't exclude any code points.
+ *
+ * @param converterList a pointer to encoding names needed to be involved. 
+ *                      Can be NULL if converterListSize==0.
+ *                      The list and the names will be cloned, and the caller
+ *                      retains ownership of the original.
+ * @param converterListSize number of encodings in above list.
+ *                          If 0, builds a selector for all available converters.
+ * @param excludedCodePoints a set of code points to be excluded from consideration.
+ *                           That is, excluded code points in a string do not change
+ *                           the selection result. (They might be handled by a callback.)
+ *                           Use NULL to exclude nothing.
+ * @param whichSet what converter set to use? Use this to determine whether
+ *                 to consider only roundtrip mappings or also fallbacks.
+ * @param status an in/out ICU UErrorCode
+ * @return the new selector
+ *
+ * @stable ICU 4.2
+ */
+U_STABLE UConverterSelector* U_EXPORT2
+ucnvsel_open(const char* const*  converterList, int32_t converterListSize,
+             const USet* excludedCodePoints,
+             const UConverterUnicodeSet whichSet, UErrorCode* status);
+
+/**
+ * Closes a selector.
+ * If any Enumerations were returned by ucnv_select*, they become invalid.
+ * They can be closed before or after calling ucnv_closeSelector,
+ * but should never be used after the selector is closed.
+ *
+ * @see ucnv_selectForString
+ * @see ucnv_selectForUTF8
+ *
+ * @param sel selector to close
+ *
+ * @stable ICU 4.2
+ */
+U_STABLE void U_EXPORT2
+ucnvsel_close(UConverterSelector *sel);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUConverterSelectorPointer
+ * "Smart pointer" class, closes a UConverterSelector via ucnvsel_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUConverterSelectorPointer, UConverterSelector, ucnvsel_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Open a selector from its serialized form.
+ * The buffer must remain valid and unchanged for the lifetime of the selector.
+ * This is much faster than creating a selector from scratch.
+ * Using a serialized form from a different machine (endianness/charset) is supported.
+ *
+ * @param buffer pointer to the serialized form of a converter selector;
+ *               must be 32-bit-aligned
+ * @param length the capacity of this buffer (can be equal to or larger than
+ *               the actual data length)
+ * @param status an in/out ICU UErrorCode
+ * @return the new selector
+ *
+ * @stable ICU 4.2
+ */
+U_STABLE UConverterSelector* U_EXPORT2
+ucnvsel_openFromSerialized(const void* buffer, int32_t length, UErrorCode* status);
+
+/**
+ * Serialize a selector into a linear buffer.
+ * The serialized form is portable to different machines.
+ *
+ * @param sel selector to consider
+ * @param buffer pointer to 32-bit-aligned memory to be filled with the
+ *               serialized form of this converter selector
+ * @param bufferCapacity the capacity of this buffer
+ * @param status an in/out ICU UErrorCode
+ * @return the required buffer capacity to hold serialize data (even if the call fails
+ *         with a U_BUFFER_OVERFLOW_ERROR, it will return the required capacity)
+ *
+ * @stable ICU 4.2
+ */
+U_STABLE int32_t U_EXPORT2
+ucnvsel_serialize(const UConverterSelector* sel,
+                  void* buffer, int32_t bufferCapacity, UErrorCode* status);
+
+/**
+ * Select converters that can map all characters in a UTF-16 string,
+ * ignoring the excluded code points.
+ *
+ * @param sel a selector
+ * @param s UTF-16 string
+ * @param length length of the string, or -1 if NUL-terminated
+ * @param status an in/out ICU UErrorCode
+ * @return an enumeration containing encoding names.
+ *         The returned encoding names and their order will be the same as
+ *         supplied when building the selector.
+ *
+ * @stable ICU 4.2
+ */
+U_STABLE UEnumeration * U_EXPORT2
+ucnvsel_selectForString(const UConverterSelector* sel,
+                        const UChar *s, int32_t length, UErrorCode *status);
+
+/**
+ * Select converters that can map all characters in a UTF-8 string,
+ * ignoring the excluded code points.
+ *
+ * @param sel a selector
+ * @param s UTF-8 string
+ * @param length length of the string, or -1 if NUL-terminated
+ * @param status an in/out ICU UErrorCode
+ * @return an enumeration containing encoding names.
+ *         The returned encoding names and their order will be the same as
+ *         supplied when building the selector.
+ *
+ * @stable ICU 4.2
+ */
+U_STABLE UEnumeration * U_EXPORT2
+ucnvsel_selectForUTF8(const UConverterSelector* sel,
+                      const char *s, int32_t length, UErrorCode *status);
+
+#endif  /* __ICU_UCNV_SEL_H__ */
diff --git a/source/common/unicode/uconfig.h b/source/common/unicode/uconfig.h
new file mode 100644
index 0000000..6521eed
--- /dev/null
+++ b/source/common/unicode/uconfig.h
@@ -0,0 +1,231 @@
+/*  
+**********************************************************************
+*   Copyright (C) 2002-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   file name:  uconfig.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002sep19
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __UCONFIG_H__
+#define __UCONFIG_H__
+
+
+/*!
+ * \file
+ * \brief Switches for excluding parts of ICU library code modules.
+ *
+ * Allows to build partial, smaller libraries for special purposes.
+ * By default, all modules are built.
+ * The switches are fairly coarse, controlling large modules.
+ * Basic services cannot be turned off.
+ *
+ * Building with any of these options does not guarantee that the
+ * ICU build process will completely work. It is recommended that
+ * the ICU libraries and data be built using the normal build.
+ * At that time you should remove the data used by those services.
+ * After building the ICU data library, you should rebuild the ICU
+ * libraries with these switches customized to your needs.
+ *
+ * @stable ICU 2.4
+ */
+
+/**
+ * If this switch is defined, ICU will attempt to load a header file named "uconfig_local.h"
+ * prior to determining default settings for uconfig variables.
+ * 
+ * @internal ICU 4.0
+ * 
+ */
+#if defined(UCONFIG_USE_LOCAL)
+#include "uconfig_local.h"
+#endif
+
+/**
+ * \def UCONFIG_ONLY_COLLATION
+ * This switch turns off modules that are not needed for collation.
+ *
+ * It does not turn off legacy conversion because that is necessary
+ * for ICU to work on EBCDIC platforms (for the default converter).
+ * If you want "only collation" and do not build for EBCDIC,
+ * then you can define UCONFIG_NO_LEGACY_CONVERSION 1 as well.
+ *
+ * @stable ICU 2.4
+ */
+#ifndef UCONFIG_ONLY_COLLATION
+#   define UCONFIG_ONLY_COLLATION 0
+#endif
+
+#if UCONFIG_ONLY_COLLATION
+    /* common library */
+#   define UCONFIG_NO_BREAK_ITERATION 1
+#   define UCONFIG_NO_IDNA 1
+
+    /* i18n library */
+#   if UCONFIG_NO_COLLATION
+#       error Contradictory collation switches in uconfig.h.
+#   endif
+#   define UCONFIG_NO_FORMATTING 1
+#   define UCONFIG_NO_TRANSLITERATION 1
+#   define UCONFIG_NO_REGULAR_EXPRESSIONS 1
+#endif
+
+/* common library switches -------------------------------------------------- */
+
+/**
+ * \def UCONFIG_NO_FILE_IO
+ * This switch turns off all file access in the common library
+ * where file access is only used for data loading.
+ * ICU data must then be provided in the form of a data DLL (or with an
+ * equivalent way to link to the data residing in an executable,
+ * as in building a combined library with both the common library's code and
+ * the data), or via udata_setCommonData().
+ * Application data must be provided via udata_setAppData() or by using
+ * "open" functions that take pointers to data, for example ucol_openBinary().
+ *
+ * File access is not used at all in the i18n library.
+ *
+ * File access cannot be turned off for the icuio library or for the ICU
+ * test suites and ICU tools.
+ *
+ * @stable ICU 3.6
+ */
+#ifndef UCONFIG_NO_FILE_IO
+#   define UCONFIG_NO_FILE_IO 0
+#endif
+
+/**
+ * \def UCONFIG_NO_CONVERSION
+ * ICU will not completely build with this switch turned on.
+ * This switch turns off all converters.
+ *
+ * You may want to use this together with U_CHARSET_IS_UTF8 defined to 1
+ * in utypes.h if char* strings in your environment are always in UTF-8.
+ *
+ * @stable ICU 3.2
+ * @see U_CHARSET_IS_UTF8
+ */
+#ifndef UCONFIG_NO_CONVERSION
+#   define UCONFIG_NO_CONVERSION 0
+#endif
+
+#if UCONFIG_NO_CONVERSION
+#   define UCONFIG_NO_LEGACY_CONVERSION 1
+#endif
+
+/**
+ * \def UCONFIG_NO_LEGACY_CONVERSION
+ * This switch turns off all converters except for
+ * - Unicode charsets (UTF-7/8/16/32, CESU-8, SCSU, BOCU-1)
+ * - US-ASCII
+ * - ISO-8859-1
+ *
+ * Turning off legacy conversion is not possible on EBCDIC platforms
+ * because they need ibm-37 or ibm-1047 default converters.
+ *
+ * @stable ICU 2.4
+ */
+#ifndef UCONFIG_NO_LEGACY_CONVERSION
+#   define UCONFIG_NO_LEGACY_CONVERSION 0
+#endif
+
+/**
+ * \def UCONFIG_NO_NORMALIZATION
+ * This switch turns off normalization.
+ * It implies turning off several other services as well, for example
+ * collation and IDNA.
+ *
+ * @stable ICU 2.6
+ */
+#ifndef UCONFIG_NO_NORMALIZATION
+#   define UCONFIG_NO_NORMALIZATION 0
+#elif UCONFIG_NO_NORMALIZATION
+    /* common library */
+#   define UCONFIG_NO_IDNA 1
+
+    /* i18n library */
+#   if UCONFIG_ONLY_COLLATION
+#       error Contradictory collation switches in uconfig.h.
+#   endif
+#   define UCONFIG_NO_COLLATION 1
+#   define UCONFIG_NO_TRANSLITERATION 1
+#endif
+
+/**
+ * \def UCONFIG_NO_BREAK_ITERATION
+ * This switch turns off break iteration.
+ *
+ * @stable ICU 2.4
+ */
+#ifndef UCONFIG_NO_BREAK_ITERATION
+#   define UCONFIG_NO_BREAK_ITERATION 0
+#endif
+
+/**
+ * \def UCONFIG_NO_IDNA
+ * This switch turns off IDNA.
+ *
+ * @stable ICU 2.6
+ */
+#ifndef UCONFIG_NO_IDNA
+#   define UCONFIG_NO_IDNA 0
+#endif
+
+/* i18n library switches ---------------------------------------------------- */
+
+/**
+ * \def UCONFIG_NO_COLLATION
+ * This switch turns off collation and collation-based string search.
+ *
+ * @stable ICU 2.4
+ */
+#ifndef UCONFIG_NO_COLLATION
+#   define UCONFIG_NO_COLLATION 0
+#endif
+
+/**
+ * \def UCONFIG_NO_FORMATTING
+ * This switch turns off formatting and calendar/timezone services.
+ *
+ * @stable ICU 2.4
+ */
+#ifndef UCONFIG_NO_FORMATTING
+#   define UCONFIG_NO_FORMATTING 0
+#endif
+
+/**
+ * \def UCONFIG_NO_TRANSLITERATION
+ * This switch turns off transliteration.
+ *
+ * @stable ICU 2.4
+ */
+#ifndef UCONFIG_NO_TRANSLITERATION
+#   define UCONFIG_NO_TRANSLITERATION 0
+#endif
+
+/**
+ * \def UCONFIG_NO_REGULAR_EXPRESSIONS
+ * This switch turns off regular expressions.
+ *
+ * @stable ICU 2.4
+ */
+#ifndef UCONFIG_NO_REGULAR_EXPRESSIONS
+#   define UCONFIG_NO_REGULAR_EXPRESSIONS 0
+#endif
+
+/**
+ * \def UCONFIG_NO_SERVICE
+ * This switch turns off service registration.
+ *
+ * @stable ICU 3.2
+ */
+#ifndef UCONFIG_NO_SERVICE
+#   define UCONFIG_NO_SERVICE 0
+#endif
+
+#endif
diff --git a/source/common/unicode/udata.h b/source/common/unicode/udata.h
new file mode 100644
index 0000000..47edbd8
--- /dev/null
+++ b/source/common/unicode/udata.h
@@ -0,0 +1,415 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  udata.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999oct25
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __UDATA_H__
+#define __UDATA_H__
+
+#include "unicode/utypes.h"
+#include "unicode/localpointer.h"
+
+U_CDECL_BEGIN
+
+/**
+ * \file
+ * \brief C API: Data loading interface
+ *
+ * <h2>Information about data loading interface</h2>
+ *
+ * This API is used to find and efficiently load data for ICU and applications
+ * using ICU. It provides an abstract interface that specifies a data type and
+ * name to find and load the data. Normally this API is used by other ICU APIs
+ * to load required data out of the ICU data library, but it can be used to
+ * load data out of other places.
+ *
+ * See the User Guide Data Management chapter.
+ */
+ 
+#ifndef U_HIDE_INTERNAL_API
+/**
+ * Character used to separate package names from tree names 
+ * @internal ICU 3.0
+ */
+#define U_TREE_SEPARATOR '-'
+
+/**
+ * String used to separate package names from tree names 
+ * @internal ICU 3.0
+ */
+#define U_TREE_SEPARATOR_STRING "-"
+
+/**
+ * Character used to separate parts of entry names
+ * @internal ICU 3.0
+ */
+#define U_TREE_ENTRY_SEP_CHAR '/'
+
+/**
+ * String used to separate parts of entry names
+ * @internal ICU 3.0
+ */
+#define U_TREE_ENTRY_SEP_STRING "/"
+
+/**
+ * Alias for standard ICU data 
+ * @internal ICU 3.0
+ */
+#define U_ICUDATA_ALIAS "ICUDATA"
+
+#endif /* U_HIDE_INTERNAL_API */
+
+/**
+ * UDataInfo contains the properties about the requested data.
+ * This is meta data.
+ *
+ * <p>This structure may grow in the future, indicated by the
+ * <code>size</code> field.</p>
+ *
+ * <p>The platform data property fields help determine if a data
+ * file can be efficiently used on a given machine.
+ * The particular fields are of importance only if the data
+ * is affected by the properties - if there is integer data
+ * with word sizes > 1 byte, char* text, or UChar* text.</p>
+ *
+ * <p>The implementation for the <code>udata_open[Choice]()</code>
+ * functions may reject data based on the value in <code>isBigEndian</code>.
+ * No other field is used by the <code>udata</code> API implementation.</p>
+ *
+ * <p>The <code>dataFormat</code> may be used to identify
+ * the kind of data, e.g. a converter table.</p>
+ *
+ * <p>The <code>formatVersion</code> field should be used to
+ * make sure that the format can be interpreted.
+ * I may be a good idea to check only for the one or two highest
+ * of the version elements to allow the data memory to
+ * get more or somewhat rearranged contents, for as long
+ * as the using code can still interpret the older contents.</p>
+ *
+ * <p>The <code>dataVersion</code> field is intended to be a
+ * common place to store the source version of the data;
+ * for data from the Unicode character database, this could
+ * reflect the Unicode version.</p>
+ * @stable ICU 2.0
+ */
+typedef struct {
+    /** sizeof(UDataInfo)
+     *  @stable ICU 2.0 */
+    uint16_t size;
+
+    /** unused, set to 0 
+     *  @stable ICU 2.0*/
+    uint16_t reservedWord;
+
+    /* platform data properties */
+    /** 0 for little-endian machine, 1 for big-endian
+     *  @stable ICU 2.0 */
+    uint8_t isBigEndian;
+
+    /** see U_CHARSET_FAMILY values in utypes.h 
+     *  @stable ICU 2.0*/
+    uint8_t charsetFamily;
+
+    /** sizeof(UChar), one of { 1, 2, 4 } 
+     *  @stable ICU 2.0*/
+    uint8_t sizeofUChar;
+
+    /** unused, set to 0 
+     *  @stable ICU 2.0*/
+    uint8_t reservedByte;
+
+    /** data format identifier 
+     *  @stable ICU 2.0*/
+    uint8_t dataFormat[4];
+
+    /** versions: [0] major [1] minor [2] milli [3] micro 
+     *  @stable ICU 2.0*/
+    uint8_t formatVersion[4];
+
+    /** versions: [0] major [1] minor [2] milli [3] micro 
+     *  @stable ICU 2.0*/
+    uint8_t dataVersion[4];
+} UDataInfo;
+
+/* API for reading data -----------------------------------------------------*/
+
+/**
+ * Forward declaration of the data memory type.
+ * @stable ICU 2.0
+ */
+typedef struct UDataMemory UDataMemory;
+
+/**
+ * Callback function for udata_openChoice().
+ * @param context parameter passed into <code>udata_openChoice()</code>.
+ * @param type The type of the data as passed into <code>udata_openChoice()</code>.
+ *             It may be <code>NULL</code>.
+ * @param name The name of the data as passed into <code>udata_openChoice()</code>.
+ * @param pInfo A pointer to the <code>UDataInfo</code> structure
+ *              of data that has been loaded and will be returned
+ *              by <code>udata_openChoice()</code> if this function
+ *              returns <code>TRUE</code>.
+ * @return TRUE if the current data memory is acceptable
+ * @stable ICU 2.0
+ */
+typedef UBool U_CALLCONV
+UDataMemoryIsAcceptable(void *context,
+                        const char *type, const char *name,
+                        const UDataInfo *pInfo);
+
+
+/**
+ * Convenience function.
+ * This function works the same as <code>udata_openChoice</code>
+ * except that any data that matches the type and name
+ * is assumed to be acceptable.
+ * @param path Specifies an absolute path and/or a basename for the
+ *             finding of the data in the file system.
+ *             <code>NULL</code> for ICU data.
+ * @param type A string that specifies the type of data to be loaded.
+ *             For example, resource bundles are loaded with type "res",
+ *             conversion tables with type "cnv".
+ *             This may be <code>NULL</code> or empty.
+ * @param name A string that specifies the name of the data.
+ * @param pErrorCode An ICU UErrorCode parameter. It must not be <code>NULL</code>.
+ * @return A pointer (handle) to a data memory object, or <code>NULL</code>
+ *         if an error occurs. Call <code>udata_getMemory()</code>
+ *         to get a pointer to the actual data.
+ *
+ * @see udata_openChoice
+ * @stable ICU 2.0
+ */
+U_STABLE UDataMemory * U_EXPORT2
+udata_open(const char *path, const char *type, const char *name,
+           UErrorCode *pErrorCode);
+
+/**
+ * Data loading function.
+ * This function is used to find and load efficiently data for
+ * ICU and applications using ICU.
+ * It provides an abstract interface that allows to specify a data
+ * type and name to find and load the data.
+ *
+ * <p>The implementation depends on platform properties and user preferences
+ * and may involve loading shared libraries (DLLs), mapping
+ * files into memory, or fopen()/fread() files.
+ * It may also involve using static memory or database queries etc.
+ * Several or all data items may be combined into one entity
+ * (DLL, memory-mappable file).</p>
+ *
+ * <p>The data is always preceded by a header that includes
+ * a <code>UDataInfo</code> structure.
+ * The caller's <code>isAcceptable()</code> function is called to make
+ * sure that the data is useful. It may be called several times if it
+ * rejects the data and there is more than one location with data
+ * matching the type and name.</p>
+ *
+ * <p>If <code>path==NULL</code>, then ICU data is loaded.
+ * Otherwise, it is separated into a basename and a basename-less directory string.
+ * The basename is used as the data package name, and the directory is
+ * logically prepended to the ICU data directory string.</p>
+ *
+ * <p>For details about ICU data loading see the User Guide
+ * Data Management chapter. (http://icu-project.org/userguide/icudata.html)</p>
+ *
+ * @param path Specifies an absolute path and/or a basename for the
+ *             finding of the data in the file system.
+ *             <code>NULL</code> for ICU data.
+ * @param type A string that specifies the type of data to be loaded.
+ *             For example, resource bundles are loaded with type "res",
+ *             conversion tables with type "cnv".
+ *             This may be <code>NULL</code> or empty.
+ * @param name A string that specifies the name of the data.
+ * @param isAcceptable This function is called to verify that loaded data
+ *                     is useful for the client code. If it returns FALSE
+ *                     for all data items, then <code>udata_openChoice()</code>
+ *                     will return with an error.
+ * @param context Arbitrary parameter to be passed into isAcceptable.
+ * @param pErrorCode An ICU UErrorCode parameter. It must not be <code>NULL</code>.
+ * @return A pointer (handle) to a data memory object, or <code>NULL</code>
+ *         if an error occurs. Call <code>udata_getMemory()</code>
+ *         to get a pointer to the actual data.
+ * @stable ICU 2.0
+ */
+U_STABLE UDataMemory * U_EXPORT2
+udata_openChoice(const char *path, const char *type, const char *name,
+                 UDataMemoryIsAcceptable *isAcceptable, void *context,
+                 UErrorCode *pErrorCode);
+
+/**
+ * Close the data memory.
+ * This function must be called to allow the system to
+ * release resources associated with this data memory.
+ * @param pData The pointer to data memory object
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+udata_close(UDataMemory *pData);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUDataMemoryPointer
+ * "Smart pointer" class, closes a UDataMemory via udata_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUDataMemoryPointer, UDataMemory, udata_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Get the pointer to the actual data inside the data memory.
+ * The data is read-only.
+ * @param pData The pointer to data memory object
+ * @stable ICU 2.0
+ */
+U_STABLE const void * U_EXPORT2
+udata_getMemory(UDataMemory *pData);
+
+/**
+ * Get the information from the data memory header.
+ * This allows to get access to the header containing
+ * platform data properties etc. which is not part of
+ * the data itself and can therefore not be accessed
+ * via the pointer that <code>udata_getMemory()</code> returns.
+ *
+ * @param pData pointer to the data memory object
+ * @param pInfo pointer to a UDataInfo object;
+ *              its <code>size</code> field must be set correctly,
+ *              typically to <code>sizeof(UDataInfo)</code>.
+ *
+ * <code>*pInfo</code> will be filled with the UDataInfo structure
+ * in the data memory object. If this structure is smaller than
+ * <code>pInfo->size</code>, then the <code>size</code> will be
+ * adjusted and only part of the structure will be filled.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+udata_getInfo(UDataMemory *pData, UDataInfo *pInfo);
+
+/**
+ * This function bypasses the normal ICU data loading process and
+ * allows you to force ICU's system data to come out of a user-specified
+ * area in memory.
+ *
+ * The format of this data is that of the icu common data file, as is
+ * generated by the pkgdata tool with mode=common or mode=dll.
+ * You can read in a whole common mode file and pass the address to the start of the
+ * data, or (with the appropriate link options) pass in the pointer to
+ * the data that has been loaded from a dll by the operating system,
+ * as shown in this code:
+ *
+ *       extern const char U_IMPORT U_ICUDATA_ENTRY_POINT [];
+ *        // U_ICUDATA_ENTRY_POINT is same as entry point specified to pkgdata tool
+ *       UErrorCode  status = U_ZERO_ERROR;
+ *
+ *       udata_setCommonData(&U_ICUDATA_ENTRY_POINT, &status);
+ *
+ * It is important that the declaration be as above. The entry point
+ * must not be declared as an extern void*.
+ *
+ * Starting with ICU 4.4, it is possible to set several data packages,
+ * one per call to this function.
+ * udata_open() will look for data in the multiple data packages in the order
+ * in which they were set.
+ * The position of the linked-in or default-name ICU .data package in the
+ * search list depends on when the first data item is loaded that is not contained
+ * in the already explicitly set packages.
+ * If data was loaded implicitly before the first call to this function
+ * (for example, via opening a converter, constructing a UnicodeString
+ * from default-codepage data, using formatting or collation APIs, etc.),
+ * then the default data will be first in the list.
+ *
+ * This function has no effect on application (non ICU) data.  See udata_setAppData()
+ * for similar functionality for application data.
+ *
+ * @param data pointer to ICU common data
+ * @param err outgoing error status <code>U_USING_DEFAULT_WARNING, U_UNSUPPORTED_ERROR</code>
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+udata_setCommonData(const void *data, UErrorCode *err);
+
+
+/**
+ * This function bypasses the normal ICU data loading process for application-specific
+ * data and allows you to force the it to come out of a user-specified
+ * pointer.
+ *
+ * The format of this data is that of the icu common data file, like 'icudt26l.dat'
+ * or the corresponding shared library (DLL) file.
+ * The application must read in or otherwise construct an image of the data and then
+ * pass the address of it to this function.
+ *
+ *
+ * Warning:  setAppData will set a U_USING_DEFAULT_WARNING code if
+ *           data with the specifed path that has already been opened, or
+ *           if setAppData with the same path has already been called.
+ *           Any such calls to setAppData will have no effect.
+ *
+ *
+ * @param packageName the package name by which the application will refer
+ *             to (open) this data
+ * @param data pointer to the data
+ * @param err outgoing error status <code>U_USING_DEFAULT_WARNING, U_UNSUPPORTED_ERROR</code>
+ * @see udata_setCommonData
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+udata_setAppData(const char *packageName, const void *data, UErrorCode *err);
+
+/**
+ * Possible settings for udata_setFileAccess()
+ * @see udata_setFileAccess
+ * @stable ICU 3.4
+ */
+typedef enum UDataFileAccess {
+    /** ICU looks for data in single files first, then in packages. (default) */
+    UDATA_FILES_FIRST,
+    /** ICU only loads data from packages, not from single files. */
+    UDATA_ONLY_PACKAGES,
+    /** ICU loads data from packages first, and only from single files
+        if the data cannot be found in a package. */
+    UDATA_PACKAGES_FIRST,
+    /** ICU does not access the file system for data loading. */
+    UDATA_NO_FILES,
+    /** An alias for the default access mode. */
+    UDATA_DEFAULT_ACCESS = UDATA_FILES_FIRST,
+    UDATA_FILE_ACCESS_COUNT
+} UDataFileAccess;
+
+/**
+ * This function may be called to control how ICU loads data. It must be called
+ * before any ICU data is loaded, including application data loaded with 
+ * ures/ResourceBundle or udata APIs. This function is not multithread safe.  
+ * The results of calling it while other threads are loading data are undefined.
+ * @param access The type of file access to be used
+ * @param status Error code.
+ * @see UDataFileAccess
+ * @stable ICU 3.4 
+ */
+U_STABLE void U_EXPORT2
+udata_setFileAccess(UDataFileAccess access, UErrorCode *status);
+
+U_CDECL_END
+
+#endif
diff --git a/source/common/unicode/udeprctd.h b/source/common/unicode/udeprctd.h
new file mode 100644
index 0000000..6e435cc
--- /dev/null
+++ b/source/common/unicode/udeprctd.h
@@ -0,0 +1,50 @@
+/*
+*******************************************************************************
+*   Copyright (C) 2004-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*******************************************************************************
+*
+*   file name:  udeprctd.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   Created by: genheaders.pl, a perl script written by Ram Viswanadha
+*
+*  Contains data for commenting out APIs.
+*  Gets included by umachine.h
+*
+*  THIS FILE IS MACHINE-GENERATED, DON'T PLAY WITH IT IF YOU DON'T KNOW WHAT
+*  YOU ARE DOING, OTHERWISE VERY BAD THINGS WILL HAPPEN!
+*/
+
+#ifndef UDEPRCTD_H
+#define UDEPRCTD_H
+
+#ifdef U_HIDE_DEPRECATED_API
+
+#    if U_DISABLE_RENAMING
+#        define ucol_getContractions ucol_getContractions_DEPRECATED_API_DO_NOT_USE
+#        define ucol_getLocale ucol_getLocale_DEPRECATED_API_DO_NOT_USE
+#        define ures_countArrayItems ures_countArrayItems_DEPRECATED_API_DO_NOT_USE
+#        define ures_getLocale ures_getLocale_DEPRECATED_API_DO_NOT_USE
+#        define ures_getVersionNumber ures_getVersionNumber_DEPRECATED_API_DO_NOT_USE
+#        define utrans_getAvailableID utrans_getAvailableID_DEPRECATED_API_DO_NOT_USE
+#        define utrans_getID utrans_getID_DEPRECATED_API_DO_NOT_USE
+#        define utrans_open utrans_open_DEPRECATED_API_DO_NOT_USE
+#        define utrans_unregister utrans_unregister_DEPRECATED_API_DO_NOT_USE
+#    else
+#        define ucol_getContractions_4_6 ucol_getContractions_DEPRECATED_API_DO_NOT_USE
+#        define ucol_getLocale_4_6 ucol_getLocale_DEPRECATED_API_DO_NOT_USE
+#        define ures_countArrayItems_4_6 ures_countArrayItems_DEPRECATED_API_DO_NOT_USE
+#        define ures_getLocale_4_6 ures_getLocale_DEPRECATED_API_DO_NOT_USE
+#        define ures_getVersionNumber_4_6 ures_getVersionNumber_DEPRECATED_API_DO_NOT_USE
+#        define utrans_getAvailableID_4_6 utrans_getAvailableID_DEPRECATED_API_DO_NOT_USE
+#        define utrans_getID_4_6 utrans_getID_DEPRECATED_API_DO_NOT_USE
+#        define utrans_open_4_6 utrans_open_DEPRECATED_API_DO_NOT_USE
+#        define utrans_unregister_4_6 utrans_unregister_DEPRECATED_API_DO_NOT_USE
+#    endif /* U_DISABLE_RENAMING */
+
+#endif /* U_HIDE_DEPRECATED_API */
+#endif /* UDEPRCTD_H */
+
diff --git a/source/common/unicode/udraft.h b/source/common/unicode/udraft.h
new file mode 100644
index 0000000..c825821
--- /dev/null
+++ b/source/common/unicode/udraft.h
@@ -0,0 +1,90 @@
+/*
+*******************************************************************************
+*   Copyright (C) 2004-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*******************************************************************************
+*
+*   file name:  udraft.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   Created by: genheaders.pl, a perl script written by Ram Viswanadha
+*
+*  Contains data for commenting out APIs.
+*  Gets included by umachine.h
+*
+*  THIS FILE IS MACHINE-GENERATED, DON'T PLAY WITH IT IF YOU DON'T KNOW WHAT
+*  YOU ARE DOING, OTHERWISE VERY BAD THINGS WILL HAPPEN!
+*/
+
+#ifndef UDRAFT_H
+#define UDRAFT_H
+
+#ifdef U_HIDE_DRAFT_API
+
+#    if U_DISABLE_RENAMING
+#        define ubidi_getBaseDirection ubidi_getBaseDirection_DRAFT_API_DO_NOT_USE
+#        define uidna_close uidna_close_DRAFT_API_DO_NOT_USE
+#        define uidna_labelToASCII uidna_labelToASCII_DRAFT_API_DO_NOT_USE
+#        define uidna_labelToASCII_UTF8 uidna_labelToASCII_UTF8_DRAFT_API_DO_NOT_USE
+#        define uidna_labelToUnicode uidna_labelToUnicode_DRAFT_API_DO_NOT_USE
+#        define uidna_labelToUnicodeUTF8 uidna_labelToUnicodeUTF8_DRAFT_API_DO_NOT_USE
+#        define uidna_nameToASCII uidna_nameToASCII_DRAFT_API_DO_NOT_USE
+#        define uidna_nameToASCII_UTF8 uidna_nameToASCII_UTF8_DRAFT_API_DO_NOT_USE
+#        define uidna_nameToUnicode uidna_nameToUnicode_DRAFT_API_DO_NOT_USE
+#        define uidna_nameToUnicodeUTF8 uidna_nameToUnicodeUTF8_DRAFT_API_DO_NOT_USE
+#        define uidna_openUTS46 uidna_openUTS46_DRAFT_API_DO_NOT_USE
+#        define uloc_forLanguageTag uloc_forLanguageTag_DRAFT_API_DO_NOT_USE
+#        define uloc_toLanguageTag uloc_toLanguageTag_DRAFT_API_DO_NOT_USE
+#        define unorm2_getDecomposition unorm2_getDecomposition_DRAFT_API_DO_NOT_USE
+#        define uregex_end64 uregex_end64_DRAFT_API_DO_NOT_USE
+#        define uregex_find64 uregex_find64_DRAFT_API_DO_NOT_USE
+#        define uregex_getFindProgressCallback uregex_getFindProgressCallback_DRAFT_API_DO_NOT_USE
+#        define uregex_lookingAt64 uregex_lookingAt64_DRAFT_API_DO_NOT_USE
+#        define uregex_matches64 uregex_matches64_DRAFT_API_DO_NOT_USE
+#        define uregex_patternUText uregex_patternUText_DRAFT_API_DO_NOT_USE
+#        define uregex_regionEnd64 uregex_regionEnd64_DRAFT_API_DO_NOT_USE
+#        define uregex_regionStart64 uregex_regionStart64_DRAFT_API_DO_NOT_USE
+#        define uregex_reset64 uregex_reset64_DRAFT_API_DO_NOT_USE
+#        define uregex_setFindProgressCallback uregex_setFindProgressCallback_DRAFT_API_DO_NOT_USE
+#        define uregex_setRegion64 uregex_setRegion64_DRAFT_API_DO_NOT_USE
+#        define uregex_setRegionAndStart uregex_setRegionAndStart_DRAFT_API_DO_NOT_USE
+#        define uregex_start64 uregex_start64_DRAFT_API_DO_NOT_USE
+#        define uscript_getScriptExtensions uscript_getScriptExtensions_DRAFT_API_DO_NOT_USE
+#        define uscript_hasScript uscript_hasScript_DRAFT_API_DO_NOT_USE
+#    else
+#        define ubidi_getBaseDirection_4_6 ubidi_getBaseDirection_DRAFT_API_DO_NOT_USE
+#        define uidna_close_4_6 uidna_close_DRAFT_API_DO_NOT_USE
+#        define uidna_labelToASCII_4_6 uidna_labelToASCII_DRAFT_API_DO_NOT_USE
+#        define uidna_labelToASCII_UTF8_4_6 uidna_labelToASCII_UTF8_DRAFT_API_DO_NOT_USE
+#        define uidna_labelToUnicodeUTF8_4_6 uidna_labelToUnicodeUTF8_DRAFT_API_DO_NOT_USE
+#        define uidna_labelToUnicode_4_6 uidna_labelToUnicode_DRAFT_API_DO_NOT_USE
+#        define uidna_nameToASCII_4_6 uidna_nameToASCII_DRAFT_API_DO_NOT_USE
+#        define uidna_nameToASCII_UTF8_4_6 uidna_nameToASCII_UTF8_DRAFT_API_DO_NOT_USE
+#        define uidna_nameToUnicodeUTF8_4_6 uidna_nameToUnicodeUTF8_DRAFT_API_DO_NOT_USE
+#        define uidna_nameToUnicode_4_6 uidna_nameToUnicode_DRAFT_API_DO_NOT_USE
+#        define uidna_openUTS46_4_6 uidna_openUTS46_DRAFT_API_DO_NOT_USE
+#        define uloc_forLanguageTag_4_6 uloc_forLanguageTag_DRAFT_API_DO_NOT_USE
+#        define uloc_toLanguageTag_4_6 uloc_toLanguageTag_DRAFT_API_DO_NOT_USE
+#        define unorm2_getDecomposition_4_6 unorm2_getDecomposition_DRAFT_API_DO_NOT_USE
+#        define uregex_end64_4_6 uregex_end64_DRAFT_API_DO_NOT_USE
+#        define uregex_find64_4_6 uregex_find64_DRAFT_API_DO_NOT_USE
+#        define uregex_getFindProgressCallback_4_6 uregex_getFindProgressCallback_DRAFT_API_DO_NOT_USE
+#        define uregex_lookingAt64_4_6 uregex_lookingAt64_DRAFT_API_DO_NOT_USE
+#        define uregex_matches64_4_6 uregex_matches64_DRAFT_API_DO_NOT_USE
+#        define uregex_patternUText_4_6 uregex_patternUText_DRAFT_API_DO_NOT_USE
+#        define uregex_regionEnd64_4_6 uregex_regionEnd64_DRAFT_API_DO_NOT_USE
+#        define uregex_regionStart64_4_6 uregex_regionStart64_DRAFT_API_DO_NOT_USE
+#        define uregex_reset64_4_6 uregex_reset64_DRAFT_API_DO_NOT_USE
+#        define uregex_setFindProgressCallback_4_6 uregex_setFindProgressCallback_DRAFT_API_DO_NOT_USE
+#        define uregex_setRegion64_4_6 uregex_setRegion64_DRAFT_API_DO_NOT_USE
+#        define uregex_setRegionAndStart_4_6 uregex_setRegionAndStart_DRAFT_API_DO_NOT_USE
+#        define uregex_start64_4_6 uregex_start64_DRAFT_API_DO_NOT_USE
+#        define uscript_getScriptExtensions_4_6 uscript_getScriptExtensions_DRAFT_API_DO_NOT_USE
+#        define uscript_hasScript_4_6 uscript_hasScript_DRAFT_API_DO_NOT_USE
+#    endif /* U_DISABLE_RENAMING */
+
+#endif /* U_HIDE_DRAFT_API */
+#endif /* UDRAFT_H */
+
diff --git a/source/common/unicode/uenum.h b/source/common/unicode/uenum.h
new file mode 100644
index 0000000..0e7d90c
--- /dev/null
+++ b/source/common/unicode/uenum.h
@@ -0,0 +1,174 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2002-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  uenum.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:2
+*
+*   created on: 2002jul08
+*   created by: Vladimir Weinstein
+*/
+
+#ifndef __UENUM_H
+#define __UENUM_H
+
+#include "unicode/utypes.h"
+#include "unicode/localpointer.h"
+
+#if U_SHOW_CPLUSPLUS_API
+#include "unicode/strenum.h"
+#endif
+
+/**
+ * \file
+ * \brief C API: String Enumeration 
+ */
+ 
+/**
+ * An enumeration object.
+ * For usage in C programs.
+ * @stable ICU 2.2
+ */
+struct UEnumeration;
+/** structure representing an enumeration object instance @stable ICU 2.2 */
+typedef struct UEnumeration UEnumeration;
+
+/**
+ * Disposes of resources in use by the iterator.  If en is NULL,
+ * does nothing.  After this call, any char* or UChar* pointer
+ * returned by uenum_unext() or uenum_next() is invalid.
+ * @param en UEnumeration structure pointer
+ * @stable ICU 2.2
+ */
+U_STABLE void U_EXPORT2
+uenum_close(UEnumeration* en);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUEnumerationPointer
+ * "Smart pointer" class, closes a UEnumeration via uenum_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUEnumerationPointer, UEnumeration, uenum_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Returns the number of elements that the iterator traverses.  If
+ * the iterator is out-of-sync with its service, status is set to
+ * U_ENUM_OUT_OF_SYNC_ERROR.
+ * This is a convenience function. It can end up being very
+ * expensive as all the items might have to be pre-fetched (depending
+ * on the type of data being traversed). Use with caution and only 
+ * when necessary.
+ * @param en UEnumeration structure pointer
+ * @param status error code, can be U_ENUM_OUT_OF_SYNC_ERROR if the
+ *               iterator is out of sync.
+ * @return number of elements in the iterator
+ * @stable ICU 2.2
+ */
+U_STABLE int32_t U_EXPORT2
+uenum_count(UEnumeration* en, UErrorCode* status);
+
+/**
+ * Returns the next element in the iterator's list.  If there are
+ * no more elements, returns NULL.  If the iterator is out-of-sync
+ * with its service, status is set to U_ENUM_OUT_OF_SYNC_ERROR and
+ * NULL is returned.  If the native service string is a char* string,
+ * it is converted to UChar* with the invariant converter.
+ * The result is terminated by (UChar)0.
+ * @param en the iterator object
+ * @param resultLength pointer to receive the length of the result
+ *                     (not including the terminating \\0).
+ *                     If the pointer is NULL it is ignored.
+ * @param status the error code, set to U_ENUM_OUT_OF_SYNC_ERROR if
+ *               the iterator is out of sync with its service.
+ * @return a pointer to the string.  The string will be
+ *         zero-terminated.  The return pointer is owned by this iterator
+ *         and must not be deleted by the caller.  The pointer is valid
+ *         until the next call to any uenum_... method, including
+ *         uenum_next() or uenum_unext().  When all strings have been
+ *         traversed, returns NULL.
+ * @stable ICU 2.2
+ */
+U_STABLE const UChar* U_EXPORT2
+uenum_unext(UEnumeration* en,
+            int32_t* resultLength,
+            UErrorCode* status);
+
+/**
+ * Returns the next element in the iterator's list.  If there are
+ * no more elements, returns NULL.  If the iterator is out-of-sync
+ * with its service, status is set to U_ENUM_OUT_OF_SYNC_ERROR and
+ * NULL is returned.  If the native service string is a UChar*
+ * string, it is converted to char* with the invariant converter.
+ * The result is terminated by (char)0.  If the conversion fails
+ * (because a character cannot be converted) then status is set to
+ * U_INVARIANT_CONVERSION_ERROR and the return value is undefined
+ * (but non-NULL).
+ * @param en the iterator object
+ * @param resultLength pointer to receive the length of the result
+ *                     (not including the terminating \\0).
+ *                     If the pointer is NULL it is ignored.
+ * @param status the error code, set to U_ENUM_OUT_OF_SYNC_ERROR if
+ *               the iterator is out of sync with its service.  Set to
+ *               U_INVARIANT_CONVERSION_ERROR if the underlying native string is
+ *               UChar* and conversion to char* with the invariant converter
+ *               fails. This error pertains only to current string, so iteration
+ *               might be able to continue successfully.
+ * @return a pointer to the string.  The string will be
+ *         zero-terminated.  The return pointer is owned by this iterator
+ *         and must not be deleted by the caller.  The pointer is valid
+ *         until the next call to any uenum_... method, including
+ *         uenum_next() or uenum_unext().  When all strings have been
+ *         traversed, returns NULL.
+ * @stable ICU 2.2
+ */
+U_STABLE const char* U_EXPORT2
+uenum_next(UEnumeration* en,
+           int32_t* resultLength,
+           UErrorCode* status);
+
+/**
+ * Resets the iterator to the current list of service IDs.  This
+ * re-establishes sync with the service and rewinds the iterator
+ * to start at the first element.
+ * @param en the iterator object
+ * @param status the error code, set to U_ENUM_OUT_OF_SYNC_ERROR if
+ *               the iterator is out of sync with its service.  
+ * @stable ICU 2.2
+ */
+U_STABLE void U_EXPORT2
+uenum_reset(UEnumeration* en, UErrorCode* status);
+
+#if U_SHOW_CPLUSPLUS_API
+
+/**
+ * Given a StringEnumeration, wrap it in a UEnumeration.  The
+ * StringEnumeration is adopted; after this call, the caller must not
+ * delete it (regardless of error status).
+ * @param adopted the C++ StringEnumeration to be wrapped in a UEnumeration.
+ * @param ec the error code.
+ * @return a UEnumeration wrapping the adopted StringEnumeration.
+ * @draft ICU 4.2
+ */
+U_CAPI UEnumeration* U_EXPORT2
+uenum_openFromStringEnumeration(U_NAMESPACE_QUALIFIER StringEnumeration* adopted, UErrorCode* ec);
+
+#endif
+
+#endif
diff --git a/source/common/unicode/uidna.h b/source/common/unicode/uidna.h
new file mode 100644
index 0000000..04b439d
--- /dev/null
+++ b/source/common/unicode/uidna.h
@@ -0,0 +1,733 @@
+/*
+ *******************************************************************************
+ *
+ *   Copyright (C) 2003-2010, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ *
+ *******************************************************************************
+ *   file name:  uidna.h
+ *   encoding:   US-ASCII
+ *   tab size:   8 (not used)
+ *   indentation:4
+ *
+ *   created on: 2003feb1
+ *   created by: Ram Viswanadha
+ */
+
+#ifndef __UIDNA_H__
+#define __UIDNA_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_IDNA
+
+#include "unicode/localpointer.h"
+#include "unicode/parseerr.h"
+
+/**
+ * \file
+ * \brief C API: Internationalizing Domain Names in Applications (IDNA)
+ *
+ * IDNA2008 is implemented according to UTS #46, see the IDNA C++ class in idna.h.
+ *
+ * The C API functions which do take a UIDNA * service object pointer
+ * implement UTS #46 and IDNA2008.
+ * The C API functions which do not take a service object pointer
+ * implement IDNA2003.
+ */
+
+/*
+ * IDNA option bit set values.
+ */
+enum {
+    /**
+     * Default options value: None of the other options are set.
+     * @stable ICU 2.6
+     */
+    UIDNA_DEFAULT=0,
+    /**
+     * Option to allow unassigned code points in domain names and labels.
+     * This option is ignored by the UTS46 implementation.
+     * (UTS #46 disallows unassigned code points.)
+     * @stable ICU 2.6
+     */
+    UIDNA_ALLOW_UNASSIGNED=1,
+    /**
+     * Option to check whether the input conforms to the STD3 ASCII rules,
+     * for example the restriction of labels to LDH characters
+     * (ASCII Letters, Digits and Hyphen-Minus).
+     * @stable ICU 2.6
+     */
+    UIDNA_USE_STD3_RULES=2,
+    /**
+     * IDNA option to check for whether the input conforms to the BiDi rules.
+     * This option is ignored by the IDNA2003 implementation.
+     * (IDNA2003 always performs a BiDi check.)
+     * @draft ICU 4.6
+     */
+    UIDNA_CHECK_BIDI=4,
+    /**
+     * IDNA option to check for whether the input conforms to the CONTEXTJ rules.
+     * This option is ignored by the IDNA2003 implementation.
+     * (The CONTEXTJ check is new in IDNA2008.)
+     * @draft ICU 4.6
+     */
+    UIDNA_CHECK_CONTEXTJ=8,
+    /**
+     * IDNA option for nontransitional processing in ToASCII().
+     * By default, ToASCII() uses transitional processing.
+     * This option is ignored by the IDNA2003 implementation.
+     * (This is only relevant for compatibility of newer IDNA implementations with IDNA2003.)
+     * @draft ICU 4.6
+     */
+    UIDNA_NONTRANSITIONAL_TO_ASCII=0x10,
+    /**
+     * IDNA option for nontransitional processing in ToUnicode().
+     * By default, ToUnicode() uses transitional processing.
+     * This option is ignored by the IDNA2003 implementation.
+     * (This is only relevant for compatibility of newer IDNA implementations with IDNA2003.)
+     * @draft ICU 4.6
+     */
+    UIDNA_NONTRANSITIONAL_TO_UNICODE=0x20
+};
+
+/**
+ * Opaque C service object type for the new IDNA API.
+ * @draft ICU 4.6
+ */
+struct UIDNA;
+typedef struct UIDNA UIDNA;  /**< C typedef for struct UIDNA. @draft ICU 4.6 */
+
+/**
+ * Returns a UIDNA instance which implements UTS #46.
+ * Returns an unmodifiable instance, owned by the caller.
+ * Cache it for multiple operations, and uidna_close() it when done.
+ * The instance is thread-safe, that is, it can be used concurrently.
+ *
+ * For details about the UTS #46 implementation see the IDNA C++ class in idna.h.
+ *
+ * @param options Bit set to modify the processing and error checking.
+ *                See option bit set values in uidna.h.
+ * @param pErrorCode 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 UTS #46 UIDNA instance, if successful
+ * @draft ICU 4.6
+ */
+U_DRAFT UIDNA * U_EXPORT2
+uidna_openUTS46(uint32_t options, UErrorCode *pErrorCode);
+
+/**
+ * Closes a UIDNA instance.
+ * @param idna UIDNA instance to be closed
+ * @draft ICU 4.6
+ */
+U_DRAFT void U_EXPORT2
+uidna_close(UIDNA *idna);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUIDNAPointer
+ * "Smart pointer" class, closes a UIDNA via uidna_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @draft ICU 4.6
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUIDNAPointer, UIDNA, uidna_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Output container for IDNA processing errors.
+ * Initialize with UIDNA_INFO_INITIALIZER:
+ * \code
+ * UIDNAInfo info = UIDNA_INFO_INITIALIZER;
+ * int32_t length = uidna_nameToASCII(..., &info, &errorCode);
+ * if(U_SUCCESS(errorCode) && info.errors!=0) { ... }
+ * \endcode
+ * @draft ICU 4.6
+ */
+struct UIDNAInfo {
+    /** sizeof(UIDNAInfo) @draft ICU 4.6 */
+    int16_t size;
+    /**
+     * Set to TRUE if transitional and nontransitional processing produce different results.
+     * For details see C++ IDNAInfo::isTransitionalDifferent().
+     * @draft ICU 4.6
+     */
+    UBool isTransitionalDifferent;
+    UBool reservedB3;  /**< Reserved field, do not use. @internal */
+    /**
+     * Bit set indicating IDNA processing errors. 0 if no errors.
+     * See UIDNA_ERROR_... constants.
+     * @draft ICU 4.6
+     */
+    uint32_t errors;
+    int32_t reservedI2;  /**< Reserved field, do not use. @internal */
+    int32_t reservedI3;  /**< Reserved field, do not use. @internal */
+};
+typedef struct UIDNAInfo UIDNAInfo;
+
+/**
+ * Static initializer for a UIDNAInfo struct.
+ * @draft ICU 4.6
+ */
+#define UIDNA_INFO_INITIALIZER { \
+    (int16_t)sizeof(UIDNAInfo), \
+    FALSE, FALSE, \
+    0, 0, 0 }
+
+/**
+ * Converts a single domain name label into its ASCII form for DNS lookup.
+ * If any processing step fails, then pInfo->errors will be non-zero and
+ * the result might not be an ASCII string.
+ * The label might be modified according to the types of errors.
+ * Labels with severe errors will be left in (or turned into) their Unicode form.
+ *
+ * The UErrorCode indicates an error only in exceptional cases,
+ * such as a U_MEMORY_ALLOCATION_ERROR.
+ *
+ * @param idna UIDNA instance
+ * @param label Input domain name label
+ * @param length Label length, or -1 if NUL-terminated
+ * @param dest Destination string buffer
+ * @param capacity Destination buffer capacity
+ * @param pInfo Output container of IDNA processing details.
+ * @param pErrorCode 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 destination string length
+ * @draft ICU 4.6
+ */
+U_DRAFT int32_t U_EXPORT2
+uidna_labelToASCII(const UIDNA *idna,
+                   const UChar *label, int32_t length,
+                   UChar *dest, int32_t capacity,
+                   UIDNAInfo *pInfo, UErrorCode *pErrorCode);
+
+/**
+ * Converts a single domain name label into its Unicode form for human-readable display.
+ * If any processing step fails, then pInfo->errors will be non-zero.
+ * The label might be modified according to the types of errors.
+ *
+ * The UErrorCode indicates an error only in exceptional cases,
+ * such as a U_MEMORY_ALLOCATION_ERROR.
+ *
+ * @param idna UIDNA instance
+ * @param label Input domain name label
+ * @param length Label length, or -1 if NUL-terminated
+ * @param dest Destination string buffer
+ * @param capacity Destination buffer capacity
+ * @param pInfo Output container of IDNA processing details.
+ * @param pErrorCode 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 destination string length
+ * @draft ICU 4.6
+ */
+U_DRAFT int32_t U_EXPORT2
+uidna_labelToUnicode(const UIDNA *idna,
+                     const UChar *label, int32_t length,
+                     UChar *dest, int32_t capacity,
+                     UIDNAInfo *pInfo, UErrorCode *pErrorCode);
+
+/**
+ * Converts a whole domain name into its ASCII form for DNS lookup.
+ * If any processing step fails, then pInfo->errors will be non-zero and
+ * the result might not be an ASCII string.
+ * The domain name might be modified according to the types of errors.
+ * Labels with severe errors will be left in (or turned into) their Unicode form.
+ *
+ * The UErrorCode indicates an error only in exceptional cases,
+ * such as a U_MEMORY_ALLOCATION_ERROR.
+ *
+ * @param idna UIDNA instance
+ * @param name Input domain name
+ * @param length Domain name length, or -1 if NUL-terminated
+ * @param dest Destination string buffer
+ * @param capacity Destination buffer capacity
+ * @param pInfo Output container of IDNA processing details.
+ * @param pErrorCode 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 destination string length
+ * @draft ICU 4.6
+ */
+U_DRAFT int32_t U_EXPORT2
+uidna_nameToASCII(const UIDNA *idna,
+                  const UChar *name, int32_t length,
+                  UChar *dest, int32_t capacity,
+                  UIDNAInfo *pInfo, UErrorCode *pErrorCode);
+
+/**
+ * Converts a whole domain name into its Unicode form for human-readable display.
+ * If any processing step fails, then pInfo->errors will be non-zero.
+ * The domain name might be modified according to the types of errors.
+ *
+ * The UErrorCode indicates an error only in exceptional cases,
+ * such as a U_MEMORY_ALLOCATION_ERROR.
+ *
+ * @param idna UIDNA instance
+ * @param name Input domain name
+ * @param length Domain name length, or -1 if NUL-terminated
+ * @param dest Destination string buffer
+ * @param capacity Destination buffer capacity
+ * @param pInfo Output container of IDNA processing details.
+ * @param pErrorCode 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 destination string length
+ * @draft ICU 4.6
+ */
+U_DRAFT int32_t U_EXPORT2
+uidna_nameToUnicode(const UIDNA *idna,
+                    const UChar *name, int32_t length,
+                    UChar *dest, int32_t capacity,
+                    UIDNAInfo *pInfo, UErrorCode *pErrorCode);
+
+/* UTF-8 versions of the processing methods --------------------------------- */
+
+/**
+ * Converts a single domain name label into its ASCII form for DNS lookup.
+ * UTF-8 version of uidna_labelToASCII(), same behavior.
+ *
+ * @param idna UIDNA instance
+ * @param label Input domain name label
+ * @param length Label length, or -1 if NUL-terminated
+ * @param dest Destination string buffer
+ * @param capacity Destination buffer capacity
+ * @param pInfo Output container of IDNA processing details.
+ * @param pErrorCode 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 destination string length
+ * @draft ICU 4.6
+ */
+U_DRAFT int32_t U_EXPORT2
+uidna_labelToASCII_UTF8(const UIDNA *idna,
+                        const char *label, int32_t length,
+                        char *dest, int32_t capacity,
+                        UIDNAInfo *pInfo, UErrorCode *pErrorCode);
+
+/**
+ * Converts a single domain name label into its Unicode form for human-readable display.
+ * UTF-8 version of uidna_labelToUnicode(), same behavior.
+ *
+ * @param idna UIDNA instance
+ * @param label Input domain name label
+ * @param length Label length, or -1 if NUL-terminated
+ * @param dest Destination string buffer
+ * @param capacity Destination buffer capacity
+ * @param pInfo Output container of IDNA processing details.
+ * @param pErrorCode 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 destination string length
+ * @draft ICU 4.6
+ */
+U_DRAFT int32_t U_EXPORT2
+uidna_labelToUnicodeUTF8(const UIDNA *idna,
+                         const char *label, int32_t length,
+                         char *dest, int32_t capacity,
+                         UIDNAInfo *pInfo, UErrorCode *pErrorCode);
+
+/**
+ * Converts a whole domain name into its ASCII form for DNS lookup.
+ * UTF-8 version of uidna_nameToASCII(), same behavior.
+ *
+ * @param idna UIDNA instance
+ * @param name Input domain name
+ * @param length Domain name length, or -1 if NUL-terminated
+ * @param dest Destination string buffer
+ * @param capacity Destination buffer capacity
+ * @param pInfo Output container of IDNA processing details.
+ * @param pErrorCode 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 destination string length
+ * @draft ICU 4.6
+ */
+U_DRAFT int32_t U_EXPORT2
+uidna_nameToASCII_UTF8(const UIDNA *idna,
+                       const char *name, int32_t length,
+                       char *dest, int32_t capacity,
+                       UIDNAInfo *pInfo, UErrorCode *pErrorCode);
+
+/**
+ * Converts a whole domain name into its Unicode form for human-readable display.
+ * UTF-8 version of uidna_nameToUnicode(), same behavior.
+ *
+ * @param idna UIDNA instance
+ * @param name Input domain name
+ * @param length Domain name length, or -1 if NUL-terminated
+ * @param dest Destination string buffer
+ * @param capacity Destination buffer capacity
+ * @param pInfo Output container of IDNA processing details.
+ * @param pErrorCode 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 destination string length
+ * @draft ICU 4.6
+ */
+U_DRAFT int32_t U_EXPORT2
+uidna_nameToUnicodeUTF8(const UIDNA *idna,
+                        const char *name, int32_t length,
+                        char *dest, int32_t capacity,
+                        UIDNAInfo *pInfo, UErrorCode *pErrorCode);
+
+/*
+ * IDNA error bit set values.
+ * When a domain name or label fails a processing step or does not meet the
+ * validity criteria, then one or more of these error bits are set.
+ */
+enum {
+    /**
+     * A non-final domain name label (or the whole domain name) is empty.
+     * @draft ICU 4.6
+     */
+    UIDNA_ERROR_EMPTY_LABEL=1,
+    /**
+     * A domain name label is longer than 63 bytes.
+     * (See STD13/RFC1034 3.1. Name space specifications and terminology.)
+     * This is only checked in ToASCII operations, and only if the output label is all-ASCII.
+     * @draft ICU 4.6
+     */
+    UIDNA_ERROR_LABEL_TOO_LONG=2,
+    /**
+     * A domain name is longer than 255 bytes in its storage form.
+     * (See STD13/RFC1034 3.1. Name space specifications and terminology.)
+     * This is only checked in ToASCII operations, and only if the output domain name is all-ASCII.
+     * @draft ICU 4.6
+     */
+    UIDNA_ERROR_DOMAIN_NAME_TOO_LONG=4,
+    /**
+     * A label starts with a hyphen-minus ('-').
+     * @draft ICU 4.6
+     */
+    UIDNA_ERROR_LEADING_HYPHEN=8,
+    /**
+     * A label ends with a hyphen-minus ('-').
+     * @draft ICU 4.6
+     */
+    UIDNA_ERROR_TRAILING_HYPHEN=0x10,
+    /**
+     * A label contains hyphen-minus ('-') in the third and fourth positions.
+     * @draft ICU 4.6
+     */
+    UIDNA_ERROR_HYPHEN_3_4=0x20,
+    /**
+     * A label starts with a combining mark.
+     * @draft ICU 4.6
+     */
+    UIDNA_ERROR_LEADING_COMBINING_MARK=0x40,
+    /**
+     * A label or domain name contains disallowed characters.
+     * @draft ICU 4.6
+     */
+    UIDNA_ERROR_DISALLOWED=0x80,
+    /**
+     * A label starts with "xn--" but does not contain valid Punycode.
+     * That is, an xn-- label failed Punycode decoding.
+     * @draft ICU 4.6
+     */
+    UIDNA_ERROR_PUNYCODE=0x100,
+    /**
+     * A label contains a dot=full stop.
+     * This can occur in an input string for a single-label function.
+     * @draft ICU 4.6
+     */
+    UIDNA_ERROR_LABEL_HAS_DOT=0x200,
+    /**
+     * An ACE label does not contain a valid label string.
+     * The label was successfully ACE (Punycode) decoded but the resulting
+     * string had severe validation errors. For example,
+     * it might contain characters that are not allowed in ACE labels,
+     * or it might not be normalized.
+     * @draft ICU 4.6
+     */
+    UIDNA_ERROR_INVALID_ACE_LABEL=0x400,
+    /**
+     * A label does not meet the IDNA BiDi requirements (for right-to-left characters).
+     * @draft ICU 4.6
+     */
+    UIDNA_ERROR_BIDI=0x800,
+    /**
+     * A label does not meet the IDNA CONTEXTJ requirements.
+     * @draft ICU 4.6
+     */
+    UIDNA_ERROR_CONTEXTJ=0x1000
+};
+
+/* IDNA2003 API ------------------------------------------------------------- */
+
+/**
+ * IDNA2003: This function implements the ToASCII operation as defined in the IDNA RFC.
+ * This operation is done on <b>single labels</b> before sending it to something that expects
+ * ASCII names. A label is an individual part of a domain name. Labels are usually
+ * separated by dots; e.g. "www.example.com" is composed of 3 labels "www","example", and "com".
+ *
+ * IDNA2003 API Overview:
+ *
+ * The uidna_ API implements the IDNA protocol as defined in the IDNA RFC
+ * (http://www.ietf.org/rfc/rfc3490.txt).
+ * The RFC defines 2 operations: ToASCII and ToUnicode. Domain name labels
+ * containing non-ASCII code points are processed by the
+ * ToASCII operation before passing it to resolver libraries. Domain names
+ * that are obtained from resolver libraries are processed by the
+ * ToUnicode operation before displaying the domain name to the user.
+ * IDNA requires that implementations process input strings with Nameprep
+ * (http://www.ietf.org/rfc/rfc3491.txt),
+ * which is a profile of Stringprep (http://www.ietf.org/rfc/rfc3454.txt),
+ * and then with Punycode (http://www.ietf.org/rfc/rfc3492.txt).
+ * Implementations of IDNA MUST fully implement Nameprep and Punycode;
+ * neither Nameprep nor Punycode are optional.
+ * The input and output of ToASCII and ToUnicode operations are Unicode
+ * and are designed to be chainable, i.e., applying ToASCII or ToUnicode operations
+ * multiple times to an input string will yield the same result as applying the operation
+ * once.
+ * ToUnicode(ToUnicode(ToUnicode...(ToUnicode(string)))) == ToUnicode(string) 
+ * ToASCII(ToASCII(ToASCII...(ToASCII(string))) == ToASCII(string).
+ *
+ * @param src               Input UChar array containing label in Unicode.
+ * @param srcLength         Number of UChars in src, or -1 if NUL-terminated.
+ * @param dest              Output UChar array with ASCII (ACE encoded) label.
+ * @param destCapacity      Size of dest.
+ * @param options           A bit set of options:
+ *
+ *  - UIDNA_DEFAULT             Use default options, i.e., do not process unassigned code points
+ *                              and do not use STD3 ASCII rules
+ *                              If unassigned code points are found the operation fails with 
+ *                              U_UNASSIGNED_ERROR error code.
+ *
+ *  - UIDNA_ALLOW_UNASSIGNED    Unassigned values can be converted to ASCII for query operations
+ *                              If this option is set, the unassigned code points are in the input 
+ *                              are treated as normal Unicode code points.
+ *
+ *  - UIDNA_USE_STD3_RULES      Use STD3 ASCII rules for host name syntax restrictions
+ *                              If this option is set and the input does not satisfy STD3 rules,  
+ *                              the operation will fail with U_IDNA_STD3_ASCII_RULES_ERROR
+ *
+ * @param parseError        Pointer to UParseError struct to receive information on position 
+ *                          of error if an error is encountered. Can be NULL.
+ * @param status            ICU in/out error code parameter.
+ *                          U_INVALID_CHAR_FOUND if src contains
+ *                          unmatched single surrogates.
+ *                          U_INDEX_OUTOFBOUNDS_ERROR if src contains
+ *                          too many code points.
+ *                          U_BUFFER_OVERFLOW_ERROR if destCapacity is not enough
+ * @return The length of the result string, if successful - or in case of a buffer overflow,
+ *         in which case it will be greater than destCapacity.
+ * @stable ICU 2.6
+ */
+U_STABLE int32_t U_EXPORT2
+uidna_toASCII(const UChar* src, int32_t srcLength, 
+              UChar* dest, int32_t destCapacity,
+              int32_t options,
+              UParseError* parseError,
+              UErrorCode* status);
+
+
+/**
+ * IDNA2003: This function implements the ToUnicode operation as defined in the IDNA RFC.
+ * This operation is done on <b>single labels</b> before sending it to something that expects
+ * Unicode names. A label is an individual part of a domain name. Labels are usually
+ * separated by dots; for e.g. "www.example.com" is composed of 3 labels "www","example", and "com".
+ *
+ * @param src               Input UChar array containing ASCII (ACE encoded) label.
+ * @param srcLength         Number of UChars in src, or -1 if NUL-terminated.
+ * @param dest Output       Converted UChar array containing Unicode equivalent of label.
+ * @param destCapacity      Size of dest.
+ * @param options           A bit set of options:
+ *
+ *  - UIDNA_DEFAULT             Use default options, i.e., do not process unassigned code points
+ *                              and do not use STD3 ASCII rules
+ *                              If unassigned code points are found the operation fails with 
+ *                              U_UNASSIGNED_ERROR error code.
+ *
+ *  - UIDNA_ALLOW_UNASSIGNED      Unassigned values can be converted to ASCII for query operations
+ *                              If this option is set, the unassigned code points are in the input 
+ *                              are treated as normal Unicode code points. <b> Note: </b> This option is 
+ *                              required on toUnicode operation because the RFC mandates 
+ *                              verification of decoded ACE input by applying toASCII and comparing
+ *                              its output with source
+ *
+ *  - UIDNA_USE_STD3_RULES      Use STD3 ASCII rules for host name syntax restrictions
+ *                              If this option is set and the input does not satisfy STD3 rules,  
+ *                              the operation will fail with U_IDNA_STD3_ASCII_RULES_ERROR
+ *
+ * @param parseError        Pointer to UParseError struct to receive information on position 
+ *                          of error if an error is encountered. Can be NULL.
+ * @param status            ICU in/out error code parameter.
+ *                          U_INVALID_CHAR_FOUND if src contains
+ *                          unmatched single surrogates.
+ *                          U_INDEX_OUTOFBOUNDS_ERROR if src contains
+ *                          too many code points.
+ *                          U_BUFFER_OVERFLOW_ERROR if destCapacity is not enough
+ * @return The length of the result string, if successful - or in case of a buffer overflow,
+ *         in which case it will be greater than destCapacity.
+ * @stable ICU 2.6
+ */
+U_STABLE int32_t U_EXPORT2
+uidna_toUnicode(const UChar* src, int32_t srcLength,
+                UChar* dest, int32_t destCapacity,
+                int32_t options,
+                UParseError* parseError,
+                UErrorCode* status);
+
+
+/**
+ * IDNA2003: Convenience function that implements the IDNToASCII operation as defined in the IDNA RFC.
+ * This operation is done on complete domain names, e.g: "www.example.com". 
+ * It is important to note that this operation can fail. If it fails, then the input 
+ * domain name cannot be used as an Internationalized Domain Name and the application
+ * should have methods defined to deal with the failure.
+ *
+ * <b>Note:</b> IDNA RFC specifies that a conformant application should divide a domain name
+ * into separate labels, decide whether to apply allowUnassigned and useSTD3ASCIIRules on each, 
+ * and then convert. This function does not offer that level of granularity. The options once  
+ * set will apply to all labels in the domain name
+ *
+ * @param src               Input UChar array containing IDN in Unicode.
+ * @param srcLength         Number of UChars in src, or -1 if NUL-terminated.
+ * @param dest              Output UChar array with ASCII (ACE encoded) IDN.
+ * @param destCapacity      Size of dest.
+ * @param options           A bit set of options:
+ *
+ *  - UIDNA_DEFAULT             Use default options, i.e., do not process unassigned code points
+ *                              and do not use STD3 ASCII rules
+ *                              If unassigned code points are found the operation fails with 
+ *                              U_UNASSIGNED_CODE_POINT_FOUND error code.
+ *
+ *  - UIDNA_ALLOW_UNASSIGNED    Unassigned values can be converted to ASCII for query operations
+ *                              If this option is set, the unassigned code points are in the input 
+ *                              are treated as normal Unicode code points.
+ *
+ *  - UIDNA_USE_STD3_RULES      Use STD3 ASCII rules for host name syntax restrictions
+ *                              If this option is set and the input does not satisfy STD3 rules,  
+ *                              the operation will fail with U_IDNA_STD3_ASCII_RULES_ERROR
+ *
+ * @param parseError        Pointer to UParseError struct to receive information on position 
+ *                          of error if an error is encountered. Can be NULL.
+ * @param status            ICU in/out error code parameter.
+ *                          U_INVALID_CHAR_FOUND if src contains
+ *                          unmatched single surrogates.
+ *                          U_INDEX_OUTOFBOUNDS_ERROR if src contains
+ *                          too many code points.
+ *                          U_BUFFER_OVERFLOW_ERROR if destCapacity is not enough
+ * @return The length of the result string, if successful - or in case of a buffer overflow,
+ *         in which case it will be greater than destCapacity.
+ * @stable ICU 2.6
+ */
+U_STABLE int32_t U_EXPORT2
+uidna_IDNToASCII(  const UChar* src, int32_t srcLength,
+                   UChar* dest, int32_t destCapacity,
+                   int32_t options,
+                   UParseError* parseError,
+                   UErrorCode* status);
+
+/**
+ * IDNA2003: Convenience function that implements the IDNToUnicode operation as defined in the IDNA RFC.
+ * This operation is done on complete domain names, e.g: "www.example.com". 
+ *
+ * <b>Note:</b> IDNA RFC specifies that a conformant application should divide a domain name
+ * into separate labels, decide whether to apply allowUnassigned and useSTD3ASCIIRules on each, 
+ * and then convert. This function does not offer that level of granularity. The options once  
+ * set will apply to all labels in the domain name
+ *
+ * @param src               Input UChar array containing IDN in ASCII (ACE encoded) form.
+ * @param srcLength         Number of UChars in src, or -1 if NUL-terminated.
+ * @param dest Output       UChar array containing Unicode equivalent of source IDN.
+ * @param destCapacity      Size of dest.
+ * @param options           A bit set of options:
+ *
+ *  - UIDNA_DEFAULT             Use default options, i.e., do not process unassigned code points
+ *                              and do not use STD3 ASCII rules
+ *                              If unassigned code points are found the operation fails with 
+ *                              U_UNASSIGNED_CODE_POINT_FOUND error code.
+ *
+ *  - UIDNA_ALLOW_UNASSIGNED    Unassigned values can be converted to ASCII for query operations
+ *                              If this option is set, the unassigned code points are in the input 
+ *                              are treated as normal Unicode code points.
+ *
+ *  - UIDNA_USE_STD3_RULES      Use STD3 ASCII rules for host name syntax restrictions
+ *                              If this option is set and the input does not satisfy STD3 rules,  
+ *                              the operation will fail with U_IDNA_STD3_ASCII_RULES_ERROR
+ *
+ * @param parseError        Pointer to UParseError struct to receive information on position 
+ *                          of error if an error is encountered. Can be NULL.
+ * @param status            ICU in/out error code parameter.
+ *                          U_INVALID_CHAR_FOUND if src contains
+ *                          unmatched single surrogates.
+ *                          U_INDEX_OUTOFBOUNDS_ERROR if src contains
+ *                          too many code points.
+ *                          U_BUFFER_OVERFLOW_ERROR if destCapacity is not enough
+ * @return The length of the result string, if successful - or in case of a buffer overflow,
+ *         in which case it will be greater than destCapacity.
+ * @stable ICU 2.6
+ */
+U_STABLE int32_t U_EXPORT2
+uidna_IDNToUnicode(  const UChar* src, int32_t srcLength,
+                     UChar* dest, int32_t destCapacity,
+                     int32_t options,
+                     UParseError* parseError,
+                     UErrorCode* status);
+
+/**
+ * IDNA2003: Compare two IDN strings for equivalence.
+ * This function splits the domain names into labels and compares them.
+ * According to IDN RFC, whenever two labels are compared, they are 
+ * considered equal if and only if their ASCII forms (obtained by 
+ * applying toASCII) match using an case-insensitive ASCII comparison.
+ * Two domain names are considered a match if and only if all labels 
+ * match regardless of whether label separators match.
+ *
+ * @param s1                First source string.
+ * @param length1           Length of first source string, or -1 if NUL-terminated.
+ *
+ * @param s2                Second source string.
+ * @param length2           Length of second source string, or -1 if NUL-terminated.
+ * @param options           A bit set of options:
+ *
+ *  - UIDNA_DEFAULT             Use default options, i.e., do not process unassigned code points
+ *                              and do not use STD3 ASCII rules
+ *                              If unassigned code points are found the operation fails with 
+ *                              U_UNASSIGNED_CODE_POINT_FOUND error code.
+ *
+ *  - UIDNA_ALLOW_UNASSIGNED    Unassigned values can be converted to ASCII for query operations
+ *                              If this option is set, the unassigned code points are in the input 
+ *                              are treated as normal Unicode code points.
+ *
+ *  - UIDNA_USE_STD3_RULES      Use STD3 ASCII rules for host name syntax restrictions
+ *                              If this option is set and the input does not satisfy STD3 rules,  
+ *                              the operation will fail with U_IDNA_STD3_ASCII_RULES_ERROR
+ *
+ * @param status            ICU error code in/out parameter.
+ *                          Must fulfill U_SUCCESS before the function call.
+ * @return <0 or 0 or >0 as usual for string comparisons
+ * @stable ICU 2.6
+ */
+U_STABLE int32_t U_EXPORT2
+uidna_compare(  const UChar *s1, int32_t length1,
+                const UChar *s2, int32_t length2,
+                int32_t options,
+                UErrorCode* status);
+
+#endif /* #if !UCONFIG_NO_IDNA */
+
+#endif
diff --git a/source/common/unicode/uintrnal.h b/source/common/unicode/uintrnal.h
new file mode 100644
index 0000000..e5da6db
--- /dev/null
+++ b/source/common/unicode/uintrnal.h
@@ -0,0 +1,252 @@
+/*
+*******************************************************************************
+*   Copyright (C) 2004-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*******************************************************************************
+*
+*   file name:  uintrnal.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   Created by: genheaders.pl, a perl script written by Ram Viswanadha
+*
+*  Contains data for commenting out APIs.
+*  Gets included by umachine.h
+*
+*  THIS FILE IS MACHINE-GENERATED, DON'T PLAY WITH IT IF YOU DON'T KNOW WHAT
+*  YOU ARE DOING, OTHERWISE VERY BAD THINGS WILL HAPPEN!
+*/
+
+#ifndef UINTRNAL_H
+#define UINTRNAL_H
+
+#ifdef U_HIDE_INTERNAL_API
+
+#    if U_DISABLE_RENAMING
+#        define RegexPatternDump RegexPatternDump_INTERNAL_API_DO_NOT_USE
+#        define bms_close bms_close_INTERNAL_API_DO_NOT_USE
+#        define bms_empty bms_empty_INTERNAL_API_DO_NOT_USE
+#        define bms_getData bms_getData_INTERNAL_API_DO_NOT_USE
+#        define bms_open bms_open_INTERNAL_API_DO_NOT_USE
+#        define bms_search bms_search_INTERNAL_API_DO_NOT_USE
+#        define bms_setTargetString bms_setTargetString_INTERNAL_API_DO_NOT_USE
+#        define pl_addFontRun pl_addFontRun_INTERNAL_API_DO_NOT_USE
+#        define pl_addLocaleRun pl_addLocaleRun_INTERNAL_API_DO_NOT_USE
+#        define pl_addValueRun pl_addValueRun_INTERNAL_API_DO_NOT_USE
+#        define pl_close pl_close_INTERNAL_API_DO_NOT_USE
+#        define pl_closeFontRuns pl_closeFontRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_closeLine pl_closeLine_INTERNAL_API_DO_NOT_USE
+#        define pl_closeLocaleRuns pl_closeLocaleRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_closeValueRuns pl_closeValueRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_countLineRuns pl_countLineRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_getAscent pl_getAscent_INTERNAL_API_DO_NOT_USE
+#        define pl_getDescent pl_getDescent_INTERNAL_API_DO_NOT_USE
+#        define pl_getFontRunCount pl_getFontRunCount_INTERNAL_API_DO_NOT_USE
+#        define pl_getFontRunFont pl_getFontRunFont_INTERNAL_API_DO_NOT_USE
+#        define pl_getFontRunLastLimit pl_getFontRunLastLimit_INTERNAL_API_DO_NOT_USE
+#        define pl_getFontRunLimit pl_getFontRunLimit_INTERNAL_API_DO_NOT_USE
+#        define pl_getLeading pl_getLeading_INTERNAL_API_DO_NOT_USE
+#        define pl_getLineAscent pl_getLineAscent_INTERNAL_API_DO_NOT_USE
+#        define pl_getLineDescent pl_getLineDescent_INTERNAL_API_DO_NOT_USE
+#        define pl_getLineLeading pl_getLineLeading_INTERNAL_API_DO_NOT_USE
+#        define pl_getLineVisualRun pl_getLineVisualRun_INTERNAL_API_DO_NOT_USE
+#        define pl_getLineWidth pl_getLineWidth_INTERNAL_API_DO_NOT_USE
+#        define pl_getLocaleRunCount pl_getLocaleRunCount_INTERNAL_API_DO_NOT_USE
+#        define pl_getLocaleRunLastLimit pl_getLocaleRunLastLimit_INTERNAL_API_DO_NOT_USE
+#        define pl_getLocaleRunLimit pl_getLocaleRunLimit_INTERNAL_API_DO_NOT_USE
+#        define pl_getLocaleRunLocale pl_getLocaleRunLocale_INTERNAL_API_DO_NOT_USE
+#        define pl_getParagraphLevel pl_getParagraphLevel_INTERNAL_API_DO_NOT_USE
+#        define pl_getTextDirection pl_getTextDirection_INTERNAL_API_DO_NOT_USE
+#        define pl_getValueRunCount pl_getValueRunCount_INTERNAL_API_DO_NOT_USE
+#        define pl_getValueRunLastLimit pl_getValueRunLastLimit_INTERNAL_API_DO_NOT_USE
+#        define pl_getValueRunLimit pl_getValueRunLimit_INTERNAL_API_DO_NOT_USE
+#        define pl_getValueRunValue pl_getValueRunValue_INTERNAL_API_DO_NOT_USE
+#        define pl_getVisualRunAscent pl_getVisualRunAscent_INTERNAL_API_DO_NOT_USE
+#        define pl_getVisualRunDescent pl_getVisualRunDescent_INTERNAL_API_DO_NOT_USE
+#        define pl_getVisualRunDirection pl_getVisualRunDirection_INTERNAL_API_DO_NOT_USE
+#        define pl_getVisualRunFont pl_getVisualRunFont_INTERNAL_API_DO_NOT_USE
+#        define pl_getVisualRunGlyphCount pl_getVisualRunGlyphCount_INTERNAL_API_DO_NOT_USE
+#        define pl_getVisualRunGlyphToCharMap pl_getVisualRunGlyphToCharMap_INTERNAL_API_DO_NOT_USE
+#        define pl_getVisualRunGlyphs pl_getVisualRunGlyphs_INTERNAL_API_DO_NOT_USE
+#        define pl_getVisualRunLeading pl_getVisualRunLeading_INTERNAL_API_DO_NOT_USE
+#        define pl_getVisualRunPositions pl_getVisualRunPositions_INTERNAL_API_DO_NOT_USE
+#        define pl_line pl_line_INTERNAL_API_DO_NOT_USE
+#        define pl_nextLine pl_nextLine_INTERNAL_API_DO_NOT_USE
+#        define pl_openEmptyFontRuns pl_openEmptyFontRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_openEmptyLocaleRuns pl_openEmptyLocaleRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_openEmptyValueRuns pl_openEmptyValueRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_openFontRuns pl_openFontRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_openLocaleRuns pl_openLocaleRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_openValueRuns pl_openValueRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_paragraph pl_paragraph_INTERNAL_API_DO_NOT_USE
+#        define pl_reflow pl_reflow_INTERNAL_API_DO_NOT_USE
+#        define pl_resetFontRuns pl_resetFontRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_resetLocaleRuns pl_resetLocaleRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_resetValueRuns pl_resetValueRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_visualRun pl_visualRun_INTERNAL_API_DO_NOT_USE
+#        define ucd_close ucd_close_INTERNAL_API_DO_NOT_USE
+#        define ucd_flushCache ucd_flushCache_INTERNAL_API_DO_NOT_USE
+#        define ucd_freeCache ucd_freeCache_INTERNAL_API_DO_NOT_USE
+#        define ucd_getCollator ucd_getCollator_INTERNAL_API_DO_NOT_USE
+#        define ucd_open ucd_open_INTERNAL_API_DO_NOT_USE
+#        define ucol_equals ucol_equals_INTERNAL_API_DO_NOT_USE
+#        define ucol_forceHanImplicit ucol_forceHanImplicit_INTERNAL_API_DO_NOT_USE
+#        define ucol_forgetUCA ucol_forgetUCA_INTERNAL_API_DO_NOT_USE
+#        define ucol_getAttributeOrDefault ucol_getAttributeOrDefault_INTERNAL_API_DO_NOT_USE
+#        define ucol_getReorderCodes ucol_getReorderCodes_INTERNAL_API_DO_NOT_USE
+#        define ucol_getUnsafeSet ucol_getUnsafeSet_INTERNAL_API_DO_NOT_USE
+#        define ucol_nextProcessed ucol_nextProcessed_INTERNAL_API_DO_NOT_USE
+#        define ucol_prepareShortStringOpen ucol_prepareShortStringOpen_INTERNAL_API_DO_NOT_USE
+#        define ucol_previousProcessed ucol_previousProcessed_INTERNAL_API_DO_NOT_USE
+#        define ucol_setReorderCodes ucol_setReorderCodes_INTERNAL_API_DO_NOT_USE
+#        define udat_applyPatternRelative udat_applyPatternRelative_INTERNAL_API_DO_NOT_USE
+#        define udat_toPatternRelativeDate udat_toPatternRelativeDate_INTERNAL_API_DO_NOT_USE
+#        define udat_toPatternRelativeTime udat_toPatternRelativeTime_INTERNAL_API_DO_NOT_USE
+#        define uplug_getConfiguration uplug_getConfiguration_INTERNAL_API_DO_NOT_USE
+#        define uplug_getContext uplug_getContext_INTERNAL_API_DO_NOT_USE
+#        define uplug_getCurrentLevel uplug_getCurrentLevel_INTERNAL_API_DO_NOT_USE
+#        define uplug_getLibrary uplug_getLibrary_INTERNAL_API_DO_NOT_USE
+#        define uplug_getLibraryName uplug_getLibraryName_INTERNAL_API_DO_NOT_USE
+#        define uplug_getPlugLevel uplug_getPlugLevel_INTERNAL_API_DO_NOT_USE
+#        define uplug_getPlugLoadStatus uplug_getPlugLoadStatus_INTERNAL_API_DO_NOT_USE
+#        define uplug_getPlugName uplug_getPlugName_INTERNAL_API_DO_NOT_USE
+#        define uplug_getSymbolName uplug_getSymbolName_INTERNAL_API_DO_NOT_USE
+#        define uplug_loadPlugFromEntrypoint uplug_loadPlugFromEntrypoint_INTERNAL_API_DO_NOT_USE
+#        define uplug_loadPlugFromLibrary uplug_loadPlugFromLibrary_INTERNAL_API_DO_NOT_USE
+#        define uplug_nextPlug uplug_nextPlug_INTERNAL_API_DO_NOT_USE
+#        define uplug_removePlug uplug_removePlug_INTERNAL_API_DO_NOT_USE
+#        define uplug_setContext uplug_setContext_INTERNAL_API_DO_NOT_USE
+#        define uplug_setPlugLevel uplug_setPlugLevel_INTERNAL_API_DO_NOT_USE
+#        define uplug_setPlugName uplug_setPlugName_INTERNAL_API_DO_NOT_USE
+#        define uplug_setPlugNoUnload uplug_setPlugNoUnload_INTERNAL_API_DO_NOT_USE
+#        define uprv_getDefaultCodepage uprv_getDefaultCodepage_INTERNAL_API_DO_NOT_USE
+#        define uprv_getDefaultLocaleID uprv_getDefaultLocaleID_INTERNAL_API_DO_NOT_USE
+#        define ures_openFillIn ures_openFillIn_INTERNAL_API_DO_NOT_USE
+#        define usearch_search usearch_search_INTERNAL_API_DO_NOT_USE
+#        define usearch_searchBackwards usearch_searchBackwards_INTERNAL_API_DO_NOT_USE
+#        define utext_caseCompare utext_caseCompare_INTERNAL_API_DO_NOT_USE
+#        define utext_caseCompareNativeLimit utext_caseCompareNativeLimit_INTERNAL_API_DO_NOT_USE
+#        define utext_compare utext_compare_INTERNAL_API_DO_NOT_USE
+#        define utext_compareNativeLimit utext_compareNativeLimit_INTERNAL_API_DO_NOT_USE
+#        define utf8_appendCharSafeBody utf8_appendCharSafeBody_INTERNAL_API_DO_NOT_USE
+#        define utf8_back1SafeBody utf8_back1SafeBody_INTERNAL_API_DO_NOT_USE
+#        define utf8_countTrailBytes utf8_countTrailBytes_INTERNAL_API_DO_NOT_USE
+#        define utf8_nextCharSafeBody utf8_nextCharSafeBody_INTERNAL_API_DO_NOT_USE
+#        define utf8_prevCharSafeBody utf8_prevCharSafeBody_INTERNAL_API_DO_NOT_USE
+#    else
+#        define RegexPatternDump_4_6 RegexPatternDump_INTERNAL_API_DO_NOT_USE
+#        define bms_close_4_6 bms_close_INTERNAL_API_DO_NOT_USE
+#        define bms_empty_4_6 bms_empty_INTERNAL_API_DO_NOT_USE
+#        define bms_getData_4_6 bms_getData_INTERNAL_API_DO_NOT_USE
+#        define bms_open_4_6 bms_open_INTERNAL_API_DO_NOT_USE
+#        define bms_search_4_6 bms_search_INTERNAL_API_DO_NOT_USE
+#        define bms_setTargetString_4_6 bms_setTargetString_INTERNAL_API_DO_NOT_USE
+#        define pl_addFontRun_4_6 pl_addFontRun_INTERNAL_API_DO_NOT_USE
+#        define pl_addLocaleRun_4_6 pl_addLocaleRun_INTERNAL_API_DO_NOT_USE
+#        define pl_addValueRun_4_6 pl_addValueRun_INTERNAL_API_DO_NOT_USE
+#        define pl_close_4_6 pl_close_INTERNAL_API_DO_NOT_USE
+#        define pl_closeFontRuns_4_6 pl_closeFontRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_closeLine_4_6 pl_closeLine_INTERNAL_API_DO_NOT_USE
+#        define pl_closeLocaleRuns_4_6 pl_closeLocaleRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_closeValueRuns_4_6 pl_closeValueRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_countLineRuns_4_6 pl_countLineRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_getAscent_4_6 pl_getAscent_INTERNAL_API_DO_NOT_USE
+#        define pl_getDescent_4_6 pl_getDescent_INTERNAL_API_DO_NOT_USE
+#        define pl_getFontRunCount_4_6 pl_getFontRunCount_INTERNAL_API_DO_NOT_USE
+#        define pl_getFontRunFont_4_6 pl_getFontRunFont_INTERNAL_API_DO_NOT_USE
+#        define pl_getFontRunLastLimit_4_6 pl_getFontRunLastLimit_INTERNAL_API_DO_NOT_USE
+#        define pl_getFontRunLimit_4_6 pl_getFontRunLimit_INTERNAL_API_DO_NOT_USE
+#        define pl_getLeading_4_6 pl_getLeading_INTERNAL_API_DO_NOT_USE
+#        define pl_getLineAscent_4_6 pl_getLineAscent_INTERNAL_API_DO_NOT_USE
+#        define pl_getLineDescent_4_6 pl_getLineDescent_INTERNAL_API_DO_NOT_USE
+#        define pl_getLineLeading_4_6 pl_getLineLeading_INTERNAL_API_DO_NOT_USE
+#        define pl_getLineVisualRun_4_6 pl_getLineVisualRun_INTERNAL_API_DO_NOT_USE
+#        define pl_getLineWidth_4_6 pl_getLineWidth_INTERNAL_API_DO_NOT_USE
+#        define pl_getLocaleRunCount_4_6 pl_getLocaleRunCount_INTERNAL_API_DO_NOT_USE
+#        define pl_getLocaleRunLastLimit_4_6 pl_getLocaleRunLastLimit_INTERNAL_API_DO_NOT_USE
+#        define pl_getLocaleRunLimit_4_6 pl_getLocaleRunLimit_INTERNAL_API_DO_NOT_USE
+#        define pl_getLocaleRunLocale_4_6 pl_getLocaleRunLocale_INTERNAL_API_DO_NOT_USE
+#        define pl_getParagraphLevel_4_6 pl_getParagraphLevel_INTERNAL_API_DO_NOT_USE
+#        define pl_getTextDirection_4_6 pl_getTextDirection_INTERNAL_API_DO_NOT_USE
+#        define pl_getValueRunCount_4_6 pl_getValueRunCount_INTERNAL_API_DO_NOT_USE
+#        define pl_getValueRunLastLimit_4_6 pl_getValueRunLastLimit_INTERNAL_API_DO_NOT_USE
+#        define pl_getValueRunLimit_4_6 pl_getValueRunLimit_INTERNAL_API_DO_NOT_USE
+#        define pl_getValueRunValue_4_6 pl_getValueRunValue_INTERNAL_API_DO_NOT_USE
+#        define pl_getVisualRunAscent_4_6 pl_getVisualRunAscent_INTERNAL_API_DO_NOT_USE
+#        define pl_getVisualRunDescent_4_6 pl_getVisualRunDescent_INTERNAL_API_DO_NOT_USE
+#        define pl_getVisualRunDirection_4_6 pl_getVisualRunDirection_INTERNAL_API_DO_NOT_USE
+#        define pl_getVisualRunFont_4_6 pl_getVisualRunFont_INTERNAL_API_DO_NOT_USE
+#        define pl_getVisualRunGlyphCount_4_6 pl_getVisualRunGlyphCount_INTERNAL_API_DO_NOT_USE
+#        define pl_getVisualRunGlyphToCharMap_4_6 pl_getVisualRunGlyphToCharMap_INTERNAL_API_DO_NOT_USE
+#        define pl_getVisualRunGlyphs_4_6 pl_getVisualRunGlyphs_INTERNAL_API_DO_NOT_USE
+#        define pl_getVisualRunLeading_4_6 pl_getVisualRunLeading_INTERNAL_API_DO_NOT_USE
+#        define pl_getVisualRunPositions_4_6 pl_getVisualRunPositions_INTERNAL_API_DO_NOT_USE
+#        define pl_line_4_6 pl_line_INTERNAL_API_DO_NOT_USE
+#        define pl_nextLine_4_6 pl_nextLine_INTERNAL_API_DO_NOT_USE
+#        define pl_openEmptyFontRuns_4_6 pl_openEmptyFontRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_openEmptyLocaleRuns_4_6 pl_openEmptyLocaleRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_openEmptyValueRuns_4_6 pl_openEmptyValueRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_openFontRuns_4_6 pl_openFontRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_openLocaleRuns_4_6 pl_openLocaleRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_openValueRuns_4_6 pl_openValueRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_paragraph_4_6 pl_paragraph_INTERNAL_API_DO_NOT_USE
+#        define pl_reflow_4_6 pl_reflow_INTERNAL_API_DO_NOT_USE
+#        define pl_resetFontRuns_4_6 pl_resetFontRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_resetLocaleRuns_4_6 pl_resetLocaleRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_resetValueRuns_4_6 pl_resetValueRuns_INTERNAL_API_DO_NOT_USE
+#        define pl_visualRun_4_6 pl_visualRun_INTERNAL_API_DO_NOT_USE
+#        define ucd_close_4_6 ucd_close_INTERNAL_API_DO_NOT_USE
+#        define ucd_flushCache_4_6 ucd_flushCache_INTERNAL_API_DO_NOT_USE
+#        define ucd_freeCache_4_6 ucd_freeCache_INTERNAL_API_DO_NOT_USE
+#        define ucd_getCollator_4_6 ucd_getCollator_INTERNAL_API_DO_NOT_USE
+#        define ucd_open_4_6 ucd_open_INTERNAL_API_DO_NOT_USE
+#        define ucol_equals_4_6 ucol_equals_INTERNAL_API_DO_NOT_USE
+#        define ucol_forceHanImplicit_4_6 ucol_forceHanImplicit_INTERNAL_API_DO_NOT_USE
+#        define ucol_forgetUCA_4_6 ucol_forgetUCA_INTERNAL_API_DO_NOT_USE
+#        define ucol_getAttributeOrDefault_4_6 ucol_getAttributeOrDefault_INTERNAL_API_DO_NOT_USE
+#        define ucol_getReorderCodes_4_6 ucol_getReorderCodes_INTERNAL_API_DO_NOT_USE
+#        define ucol_getUnsafeSet_4_6 ucol_getUnsafeSet_INTERNAL_API_DO_NOT_USE
+#        define ucol_nextProcessed_4_6 ucol_nextProcessed_INTERNAL_API_DO_NOT_USE
+#        define ucol_prepareShortStringOpen_4_6 ucol_prepareShortStringOpen_INTERNAL_API_DO_NOT_USE
+#        define ucol_previousProcessed_4_6 ucol_previousProcessed_INTERNAL_API_DO_NOT_USE
+#        define ucol_setReorderCodes_4_6 ucol_setReorderCodes_INTERNAL_API_DO_NOT_USE
+#        define udat_applyPatternRelative_4_6 udat_applyPatternRelative_INTERNAL_API_DO_NOT_USE
+#        define udat_toPatternRelativeDate_4_6 udat_toPatternRelativeDate_INTERNAL_API_DO_NOT_USE
+#        define udat_toPatternRelativeTime_4_6 udat_toPatternRelativeTime_INTERNAL_API_DO_NOT_USE
+#        define uplug_getConfiguration_4_6 uplug_getConfiguration_INTERNAL_API_DO_NOT_USE
+#        define uplug_getContext_4_6 uplug_getContext_INTERNAL_API_DO_NOT_USE
+#        define uplug_getCurrentLevel_4_6 uplug_getCurrentLevel_INTERNAL_API_DO_NOT_USE
+#        define uplug_getLibrary_4_6 uplug_getLibrary_INTERNAL_API_DO_NOT_USE
+#        define uplug_getLibraryName_4_6 uplug_getLibraryName_INTERNAL_API_DO_NOT_USE
+#        define uplug_getPlugLevel_4_6 uplug_getPlugLevel_INTERNAL_API_DO_NOT_USE
+#        define uplug_getPlugLoadStatus_4_6 uplug_getPlugLoadStatus_INTERNAL_API_DO_NOT_USE
+#        define uplug_getPlugName_4_6 uplug_getPlugName_INTERNAL_API_DO_NOT_USE
+#        define uplug_getSymbolName_4_6 uplug_getSymbolName_INTERNAL_API_DO_NOT_USE
+#        define uplug_loadPlugFromEntrypoint_4_6 uplug_loadPlugFromEntrypoint_INTERNAL_API_DO_NOT_USE
+#        define uplug_loadPlugFromLibrary_4_6 uplug_loadPlugFromLibrary_INTERNAL_API_DO_NOT_USE
+#        define uplug_nextPlug_4_6 uplug_nextPlug_INTERNAL_API_DO_NOT_USE
+#        define uplug_removePlug_4_6 uplug_removePlug_INTERNAL_API_DO_NOT_USE
+#        define uplug_setContext_4_6 uplug_setContext_INTERNAL_API_DO_NOT_USE
+#        define uplug_setPlugLevel_4_6 uplug_setPlugLevel_INTERNAL_API_DO_NOT_USE
+#        define uplug_setPlugName_4_6 uplug_setPlugName_INTERNAL_API_DO_NOT_USE
+#        define uplug_setPlugNoUnload_4_6 uplug_setPlugNoUnload_INTERNAL_API_DO_NOT_USE
+#        define uprv_getDefaultCodepage_4_6 uprv_getDefaultCodepage_INTERNAL_API_DO_NOT_USE
+#        define uprv_getDefaultLocaleID_4_6 uprv_getDefaultLocaleID_INTERNAL_API_DO_NOT_USE
+#        define ures_openFillIn_4_6 ures_openFillIn_INTERNAL_API_DO_NOT_USE
+#        define usearch_search_4_6 usearch_search_INTERNAL_API_DO_NOT_USE
+#        define usearch_searchBackwards_4_6 usearch_searchBackwards_INTERNAL_API_DO_NOT_USE
+#        define utext_caseCompareNativeLimit_4_6 utext_caseCompareNativeLimit_INTERNAL_API_DO_NOT_USE
+#        define utext_caseCompare_4_6 utext_caseCompare_INTERNAL_API_DO_NOT_USE
+#        define utext_compareNativeLimit_4_6 utext_compareNativeLimit_INTERNAL_API_DO_NOT_USE
+#        define utext_compare_4_6 utext_compare_INTERNAL_API_DO_NOT_USE
+#        define utf8_appendCharSafeBody_4_6 utf8_appendCharSafeBody_INTERNAL_API_DO_NOT_USE
+#        define utf8_back1SafeBody_4_6 utf8_back1SafeBody_INTERNAL_API_DO_NOT_USE
+#        define utf8_countTrailBytes_4_6 utf8_countTrailBytes_INTERNAL_API_DO_NOT_USE
+#        define utf8_nextCharSafeBody_4_6 utf8_nextCharSafeBody_INTERNAL_API_DO_NOT_USE
+#        define utf8_prevCharSafeBody_4_6 utf8_prevCharSafeBody_INTERNAL_API_DO_NOT_USE
+#    endif /* U_DISABLE_RENAMING */
+
+#endif /* U_HIDE_INTERNAL_API */
+#endif /* UINTRNAL_H */
+
diff --git a/source/common/unicode/uiter.h b/source/common/unicode/uiter.h
new file mode 100644
index 0000000..b469e24
--- /dev/null
+++ b/source/common/unicode/uiter.h
@@ -0,0 +1,707 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2002-2006,2009 International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  uiter.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002jan18
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __UITER_H__
+#define __UITER_H__
+
+/**
+ * \file
+ * \brief C API: Unicode Character Iteration
+ *
+ * @see UCharIterator
+ */
+
+#include "unicode/utypes.h"
+
+#if U_SHOW_CPLUSPLUS_API
+    U_NAMESPACE_BEGIN
+
+    class CharacterIterator;
+    class Replaceable;
+
+    U_NAMESPACE_END
+#endif
+
+U_CDECL_BEGIN
+
+struct UCharIterator;
+typedef struct UCharIterator UCharIterator; /**< C typedef for struct UCharIterator. @stable ICU 2.1 */
+
+/**
+ * Origin constants for UCharIterator.getIndex() and UCharIterator.move().
+ * @see UCharIteratorMove
+ * @see UCharIterator
+ * @stable ICU 2.1
+ */
+typedef enum UCharIteratorOrigin {
+    UITER_START, UITER_CURRENT, UITER_LIMIT, UITER_ZERO, UITER_LENGTH
+} UCharIteratorOrigin;
+
+/** Constants for UCharIterator. @stable ICU 2.6 */
+enum {
+    /**
+     * Constant value that may be returned by UCharIteratorMove
+     * indicating that the final UTF-16 index is not known, but that the move succeeded.
+     * This can occur when moving relative to limit or length, or
+     * when moving relative to the current index after a setState()
+     * when the current UTF-16 index is not known.
+     *
+     * It would be very inefficient to have to count from the beginning of the text
+     * just to get the current/limit/length index after moving relative to it.
+     * The actual index can be determined with getIndex(UITER_CURRENT)
+     * which will count the UChars if necessary.
+     *
+     * @stable ICU 2.6
+     */
+    UITER_UNKNOWN_INDEX=-2
+};
+
+
+/**
+ * Constant for UCharIterator getState() indicating an error or
+ * an unknown state.
+ * Returned by uiter_getState()/UCharIteratorGetState
+ * when an error occurs.
+ * Also, some UCharIterator implementations may not be able to return
+ * a valid state for each position. This will be clearly documented
+ * for each such iterator (none of the public ones here).
+ *
+ * @stable ICU 2.6
+ */
+#define UITER_NO_STATE ((uint32_t)0xffffffff)
+
+/**
+ * Function type declaration for UCharIterator.getIndex().
+ *
+ * Gets the current position, or the start or limit of the
+ * iteration range.
+ *
+ * This function may perform slowly for UITER_CURRENT after setState() was called,
+ * or for UITER_LENGTH, because an iterator implementation may have to count
+ * UChars if the underlying storage is not UTF-16.
+ *
+ * @param iter the UCharIterator structure ("this pointer")
+ * @param origin get the 0, start, limit, length, or current index
+ * @return the requested index, or U_SENTINEL in an error condition
+ *
+ * @see UCharIteratorOrigin
+ * @see UCharIterator
+ * @stable ICU 2.1
+ */
+typedef int32_t U_CALLCONV
+UCharIteratorGetIndex(UCharIterator *iter, UCharIteratorOrigin origin);
+
+/**
+ * Function type declaration for UCharIterator.move().
+ *
+ * Use iter->move(iter, index, UITER_ZERO) like CharacterIterator::setIndex(index).
+ *
+ * Moves the current position relative to the start or limit of the
+ * iteration range, or relative to the current position itself.
+ * The movement is expressed in numbers of code units forward
+ * or backward by specifying a positive or negative delta.
+ * Out of bounds movement will be pinned to the start or limit.
+ *
+ * This function may perform slowly for moving relative to UITER_LENGTH
+ * because an iterator implementation may have to count the rest of the
+ * UChars if the native storage is not UTF-16.
+ *
+ * When moving relative to the limit or length, or
+ * relative to the current position after setState() was called,
+ * move() may return UITER_UNKNOWN_INDEX (-2) to avoid an inefficient
+ * determination of the actual UTF-16 index.
+ * The actual index can be determined with getIndex(UITER_CURRENT)
+ * which will count the UChars if necessary.
+ * See UITER_UNKNOWN_INDEX for details.
+ *
+ * @param iter the UCharIterator structure ("this pointer")
+ * @param delta can be positive, zero, or negative
+ * @param origin move relative to the 0, start, limit, length, or current index
+ * @return the new index, or U_SENTINEL on an error condition,
+ *         or UITER_UNKNOWN_INDEX when the index is not known.
+ *
+ * @see UCharIteratorOrigin
+ * @see UCharIterator
+ * @see UITER_UNKNOWN_INDEX
+ * @stable ICU 2.1
+ */
+typedef int32_t U_CALLCONV
+UCharIteratorMove(UCharIterator *iter, int32_t delta, UCharIteratorOrigin origin);
+
+/**
+ * Function type declaration for UCharIterator.hasNext().
+ *
+ * Check if current() and next() can still
+ * return another code unit.
+ *
+ * @param iter the UCharIterator structure ("this pointer")
+ * @return boolean value for whether current() and next() can still return another code unit
+ *
+ * @see UCharIterator
+ * @stable ICU 2.1
+ */
+typedef UBool U_CALLCONV
+UCharIteratorHasNext(UCharIterator *iter);
+
+/**
+ * Function type declaration for UCharIterator.hasPrevious().
+ *
+ * Check if previous() can still return another code unit.
+ *
+ * @param iter the UCharIterator structure ("this pointer")
+ * @return boolean value for whether previous() can still return another code unit
+ *
+ * @see UCharIterator
+ * @stable ICU 2.1
+ */
+typedef UBool U_CALLCONV
+UCharIteratorHasPrevious(UCharIterator *iter);
+ 
+/**
+ * Function type declaration for UCharIterator.current().
+ *
+ * Return the code unit at the current position,
+ * or U_SENTINEL if there is none (index is at the limit).
+ *
+ * @param iter the UCharIterator structure ("this pointer")
+ * @return the current code unit
+ *
+ * @see UCharIterator
+ * @stable ICU 2.1
+ */
+typedef UChar32 U_CALLCONV
+UCharIteratorCurrent(UCharIterator *iter);
+
+/**
+ * Function type declaration for UCharIterator.next().
+ *
+ * Return the code unit at the current index and increment
+ * the index (post-increment, like s[i++]),
+ * or return U_SENTINEL if there is none (index is at the limit).
+ *
+ * @param iter the UCharIterator structure ("this pointer")
+ * @return the current code unit (and post-increment the current index)
+ *
+ * @see UCharIterator
+ * @stable ICU 2.1
+ */
+typedef UChar32 U_CALLCONV
+UCharIteratorNext(UCharIterator *iter);
+
+/**
+ * Function type declaration for UCharIterator.previous().
+ *
+ * Decrement the index and return the code unit from there
+ * (pre-decrement, like s[--i]),
+ * or return U_SENTINEL if there is none (index is at the start).
+ *
+ * @param iter the UCharIterator structure ("this pointer")
+ * @return the previous code unit (after pre-decrementing the current index)
+ *
+ * @see UCharIterator
+ * @stable ICU 2.1
+ */
+typedef UChar32 U_CALLCONV
+UCharIteratorPrevious(UCharIterator *iter);
+
+/**
+ * Function type declaration for UCharIterator.reservedFn().
+ * Reserved for future use.
+ *
+ * @param iter the UCharIterator structure ("this pointer")
+ * @param something some integer argument
+ * @return some integer
+ *
+ * @see UCharIterator
+ * @stable ICU 2.1
+ */
+typedef int32_t U_CALLCONV
+UCharIteratorReserved(UCharIterator *iter, int32_t something);
+
+/**
+ * Function type declaration for UCharIterator.getState().
+ *
+ * Get the "state" of the iterator in the form of a single 32-bit word.
+ * It is recommended that the state value be calculated to be as small as
+ * is feasible. For strings with limited lengths, fewer than 32 bits may
+ * be sufficient.
+ *
+ * This is used together with setState()/UCharIteratorSetState
+ * to save and restore the iterator position more efficiently than with
+ * getIndex()/move().
+ *
+ * The iterator state is defined as a uint32_t value because it is designed
+ * for use in ucol_nextSortKeyPart() which provides 32 bits to store the state
+ * of the character iterator.
+ *
+ * With some UCharIterator implementations (e.g., UTF-8),
+ * getting and setting the UTF-16 index with existing functions
+ * (getIndex(UITER_CURRENT) followed by move(pos, UITER_ZERO)) is possible but
+ * relatively slow because the iterator has to "walk" from a known index
+ * to the requested one.
+ * This takes more time the farther it needs to go.
+ *
+ * An opaque state value allows an iterator implementation to provide
+ * an internal index (UTF-8: the source byte array index) for
+ * fast, constant-time restoration.
+ *
+ * After calling setState(), a getIndex(UITER_CURRENT) may be slow because
+ * the UTF-16 index may not be restored as well, but the iterator can deliver
+ * the correct text contents and move relative to the current position
+ * without performance degradation.
+ *
+ * Some UCharIterator implementations may not be able to return
+ * a valid state for each position, in which case they return UITER_NO_STATE instead.
+ * This will be clearly documented for each such iterator (none of the public ones here).
+ *
+ * @param iter the UCharIterator structure ("this pointer")
+ * @return the state word
+ *
+ * @see UCharIterator
+ * @see UCharIteratorSetState
+ * @see UITER_NO_STATE
+ * @stable ICU 2.6
+ */
+typedef uint32_t U_CALLCONV
+UCharIteratorGetState(const UCharIterator *iter);
+
+/**
+ * Function type declaration for UCharIterator.setState().
+ *
+ * Restore the "state" of the iterator using a state word from a getState() call.
+ * The iterator object need not be the same one as for which getState() was called,
+ * but it must be of the same type (set up using the same uiter_setXYZ function)
+ * and it must iterate over the same string
+ * (binary identical regardless of memory address).
+ * For more about the state word see UCharIteratorGetState.
+ *
+ * After calling setState(), a getIndex(UITER_CURRENT) may be slow because
+ * the UTF-16 index may not be restored as well, but the iterator can deliver
+ * the correct text contents and move relative to the current position
+ * without performance degradation.
+ *
+ * @param iter the UCharIterator structure ("this pointer")
+ * @param state the state word from a getState() call
+ *              on a same-type, same-string iterator
+ * @param pErrorCode Must be a valid pointer to an error code value,
+ *                   which must not indicate a failure before the function call.
+ *
+ * @see UCharIterator
+ * @see UCharIteratorGetState
+ * @stable ICU 2.6
+ */
+typedef void U_CALLCONV
+UCharIteratorSetState(UCharIterator *iter, uint32_t state, UErrorCode *pErrorCode);
+
+
+/**
+ * C API for code unit iteration.
+ * This can be used as a C wrapper around
+ * CharacterIterator, Replaceable, or implemented using simple strings, etc.
+ *
+ * There are two roles for using UCharIterator:
+ *
+ * A "provider" sets the necessary function pointers and controls the "protected"
+ * fields of the UCharIterator structure. A "provider" passes a UCharIterator
+ * into C APIs that need a UCharIterator as an abstract, flexible string interface.
+ *
+ * Implementations of such C APIs are "callers" of UCharIterator functions;
+ * they only use the "public" function pointers and never access the "protected"
+ * fields directly.
+ *
+ * The current() and next() functions only check the current index against the
+ * limit, and previous() only checks the current index against the start,
+ * to see if the iterator already reached the end of the iteration range.
+ *
+ * The assumption - in all iterators - is that the index is moved via the API,
+ * which means it won't go out of bounds, or the index is modified by
+ * user code that knows enough about the iterator implementation to set valid
+ * index values.
+ *
+ * UCharIterator functions return code unit values 0..0xffff,
+ * or U_SENTINEL if the iteration bounds are reached.
+ *
+ * @stable ICU 2.1
+ */
+struct UCharIterator {
+    /**
+     * (protected) Pointer to string or wrapped object or similar.
+     * Not used by caller.
+     * @stable ICU 2.1
+     */
+    const void *context;
+
+    /**
+     * (protected) Length of string or similar.
+     * Not used by caller.
+     * @stable ICU 2.1
+     */
+    int32_t length;
+
+    /**
+     * (protected) Start index or similar.
+     * Not used by caller.
+     * @stable ICU 2.1
+     */
+    int32_t start;
+
+    /**
+     * (protected) Current index or similar.
+     * Not used by caller.
+     * @stable ICU 2.1
+     */
+    int32_t index;
+
+    /**
+     * (protected) Limit index or similar.
+     * Not used by caller.
+     * @stable ICU 2.1
+     */
+    int32_t limit;
+
+    /**
+     * (protected) Used by UTF-8 iterators and possibly others.
+     * @stable ICU 2.1
+     */
+    int32_t reservedField;
+
+    /**
+     * (public) Returns the current position or the
+     * start or limit index of the iteration range.
+     *
+     * @see UCharIteratorGetIndex
+     * @stable ICU 2.1
+     */
+    UCharIteratorGetIndex *getIndex;
+
+    /**
+     * (public) Moves the current position relative to the start or limit of the
+     * iteration range, or relative to the current position itself.
+     * The movement is expressed in numbers of code units forward
+     * or backward by specifying a positive or negative delta.
+     *
+     * @see UCharIteratorMove
+     * @stable ICU 2.1
+     */
+    UCharIteratorMove *move;
+
+    /**
+     * (public) Check if current() and next() can still
+     * return another code unit.
+     *
+     * @see UCharIteratorHasNext
+     * @stable ICU 2.1
+     */
+    UCharIteratorHasNext *hasNext;
+
+    /**
+     * (public) Check if previous() can still return another code unit.
+     *
+     * @see UCharIteratorHasPrevious
+     * @stable ICU 2.1
+     */
+    UCharIteratorHasPrevious *hasPrevious;
+
+    /**
+     * (public) Return the code unit at the current position,
+     * or U_SENTINEL if there is none (index is at the limit).
+     *
+     * @see UCharIteratorCurrent
+     * @stable ICU 2.1
+     */
+    UCharIteratorCurrent *current;
+
+    /**
+     * (public) Return the code unit at the current index and increment
+     * the index (post-increment, like s[i++]),
+     * or return U_SENTINEL if there is none (index is at the limit).
+     *
+     * @see UCharIteratorNext
+     * @stable ICU 2.1
+     */
+    UCharIteratorNext *next;
+
+    /**
+     * (public) Decrement the index and return the code unit from there
+     * (pre-decrement, like s[--i]),
+     * or return U_SENTINEL if there is none (index is at the start).
+     *
+     * @see UCharIteratorPrevious
+     * @stable ICU 2.1
+     */
+    UCharIteratorPrevious *previous;
+
+    /**
+     * (public) Reserved for future use. Currently NULL.
+     *
+     * @see UCharIteratorReserved
+     * @stable ICU 2.1
+     */
+    UCharIteratorReserved *reservedFn;
+
+    /**
+     * (public) Return the state of the iterator, to be restored later with setState().
+     * This function pointer is NULL if the iterator does not implement it.
+     *
+     * @see UCharIteratorGet
+     * @stable ICU 2.6
+     */
+    UCharIteratorGetState *getState;
+
+    /**
+     * (public) Restore the iterator state from the state word from a call
+     * to getState().
+     * This function pointer is NULL if the iterator does not implement it.
+     *
+     * @see UCharIteratorSet
+     * @stable ICU 2.6
+     */
+    UCharIteratorSetState *setState;
+};
+
+/**
+ * Helper function for UCharIterator to get the code point
+ * at the current index.
+ *
+ * Return the code point that includes the code unit at the current position,
+ * or U_SENTINEL if there is none (index is at the limit).
+ * If the current code unit is a lead or trail surrogate,
+ * then the following or preceding surrogate is used to form
+ * the code point value.
+ *
+ * @param iter the UCharIterator structure ("this pointer")
+ * @return the current code point
+ *
+ * @see UCharIterator
+ * @see U16_GET
+ * @see UnicodeString::char32At()
+ * @stable ICU 2.1
+ */
+U_STABLE UChar32 U_EXPORT2
+uiter_current32(UCharIterator *iter);
+
+/**
+ * Helper function for UCharIterator to get the next code point.
+ *
+ * Return the code point at the current index and increment
+ * the index (post-increment, like s[i++]),
+ * or return U_SENTINEL if there is none (index is at the limit).
+ *
+ * @param iter the UCharIterator structure ("this pointer")
+ * @return the current code point (and post-increment the current index)
+ *
+ * @see UCharIterator
+ * @see U16_NEXT
+ * @stable ICU 2.1
+ */
+U_STABLE UChar32 U_EXPORT2
+uiter_next32(UCharIterator *iter);
+
+/**
+ * Helper function for UCharIterator to get the previous code point.
+ *
+ * Decrement the index and return the code point from there
+ * (pre-decrement, like s[--i]),
+ * or return U_SENTINEL if there is none (index is at the start).
+ *
+ * @param iter the UCharIterator structure ("this pointer")
+ * @return the previous code point (after pre-decrementing the current index)
+ *
+ * @see UCharIterator
+ * @see U16_PREV
+ * @stable ICU 2.1
+ */
+U_STABLE UChar32 U_EXPORT2
+uiter_previous32(UCharIterator *iter);
+
+/**
+ * Get the "state" of the iterator in the form of a single 32-bit word.
+ * This is a convenience function that calls iter->getState(iter)
+ * if iter->getState is not NULL;
+ * if it is NULL or any other error occurs, then UITER_NO_STATE is returned.
+ *
+ * Some UCharIterator implementations may not be able to return
+ * a valid state for each position, in which case they return UITER_NO_STATE instead.
+ * This will be clearly documented for each such iterator (none of the public ones here).
+ *
+ * @param iter the UCharIterator structure ("this pointer")
+ * @return the state word
+ *
+ * @see UCharIterator
+ * @see UCharIteratorGetState
+ * @see UITER_NO_STATE
+ * @stable ICU 2.6
+ */
+U_STABLE uint32_t U_EXPORT2
+uiter_getState(const UCharIterator *iter);
+
+/**
+ * Restore the "state" of the iterator using a state word from a getState() call.
+ * This is a convenience function that calls iter->setState(iter, state, pErrorCode)
+ * if iter->setState is not NULL; if it is NULL, then U_UNSUPPORTED_ERROR is set.
+ *
+ * @param iter the UCharIterator structure ("this pointer")
+ * @param state the state word from a getState() call
+ *              on a same-type, same-string iterator
+ * @param pErrorCode Must be a valid pointer to an error code value,
+ *                   which must not indicate a failure before the function call.
+ *
+ * @see UCharIterator
+ * @see UCharIteratorSetState
+ * @stable ICU 2.6
+ */
+U_STABLE void U_EXPORT2
+uiter_setState(UCharIterator *iter, uint32_t state, UErrorCode *pErrorCode);
+
+/**
+ * Set up a UCharIterator to iterate over a string.
+ *
+ * Sets the UCharIterator function pointers for iteration over the string s
+ * with iteration boundaries start=index=0 and length=limit=string length.
+ * The "provider" may set the start, index, and limit values at any time
+ * within the range 0..length.
+ * The length field will be ignored.
+ *
+ * The string pointer s is set into UCharIterator.context without copying
+ * or reallocating the string contents.
+ *
+ * getState() simply returns the current index.
+ * move() will always return the final index.
+ *
+ * @param iter UCharIterator structure to be set for iteration
+ * @param s String to iterate over
+ * @param length Length of s, or -1 if NUL-terminated
+ *
+ * @see UCharIterator
+ * @stable ICU 2.1
+ */
+U_STABLE void U_EXPORT2
+uiter_setString(UCharIterator *iter, const UChar *s, int32_t length);
+
+/**
+ * Set up a UCharIterator to iterate over a UTF-16BE string
+ * (byte vector with a big-endian pair of bytes per UChar).
+ *
+ * Everything works just like with a normal UChar iterator (uiter_setString),
+ * except that UChars are assembled from byte pairs,
+ * and that the length argument here indicates an even number of bytes.
+ *
+ * getState() simply returns the current index.
+ * move() will always return the final index.
+ *
+ * @param iter UCharIterator structure to be set for iteration
+ * @param s UTF-16BE string to iterate over
+ * @param length Length of s as an even number of bytes, or -1 if NUL-terminated
+ *               (NUL means pair of 0 bytes at even index from s)
+ *
+ * @see UCharIterator
+ * @see uiter_setString
+ * @stable ICU 2.6
+ */
+U_STABLE void U_EXPORT2
+uiter_setUTF16BE(UCharIterator *iter, const char *s, int32_t length);
+
+/**
+ * Set up a UCharIterator to iterate over a UTF-8 string.
+ *
+ * Sets the UCharIterator function pointers for iteration over the UTF-8 string s
+ * with UTF-8 iteration boundaries 0 and length.
+ * The implementation counts the UTF-16 index on the fly and
+ * lazily evaluates the UTF-16 length of the text.
+ *
+ * The start field is used as the UTF-8 offset, the limit field as the UTF-8 length.
+ * When the reservedField is not 0, then it contains a supplementary code point
+ * and the UTF-16 index is between the two corresponding surrogates.
+ * At that point, the UTF-8 index is behind that code point.
+ *
+ * The UTF-8 string pointer s is set into UCharIterator.context without copying
+ * or reallocating the string contents.
+ *
+ * getState() returns a state value consisting of
+ * - the current UTF-8 source byte index (bits 31..1)
+ * - a flag (bit 0) that indicates whether the UChar position is in the middle
+ *   of a surrogate pair
+ *   (from a 4-byte UTF-8 sequence for the corresponding supplementary code point)
+ *
+ * getState() cannot also encode the UTF-16 index in the state value.
+ * move(relative to limit or length), or
+ * move(relative to current) after setState(), may return UITER_UNKNOWN_INDEX.
+ *
+ * @param iter UCharIterator structure to be set for iteration
+ * @param s UTF-8 string to iterate over
+ * @param length Length of s in bytes, or -1 if NUL-terminated
+ *
+ * @see UCharIterator
+ * @stable ICU 2.6
+ */
+U_STABLE void U_EXPORT2
+uiter_setUTF8(UCharIterator *iter, const char *s, int32_t length);
+
+#if U_SHOW_CPLUSPLUS_API
+
+/**
+ * Set up a UCharIterator to wrap around a C++ CharacterIterator.
+ *
+ * Sets the UCharIterator function pointers for iteration using the
+ * CharacterIterator charIter.
+ *
+ * The CharacterIterator pointer charIter is set into UCharIterator.context
+ * without copying or cloning the CharacterIterator object.
+ * The other "protected" UCharIterator fields are set to 0 and will be ignored.
+ * The iteration index and boundaries are controlled by the CharacterIterator.
+ *
+ * getState() simply returns the current index.
+ * move() will always return the final index.
+ *
+ * @param iter UCharIterator structure to be set for iteration
+ * @param charIter CharacterIterator to wrap
+ *
+ * @see UCharIterator
+ * @stable ICU 2.1
+ */
+U_STABLE void U_EXPORT2
+uiter_setCharacterIterator(UCharIterator *iter, U_NAMESPACE_QUALIFIER CharacterIterator *charIter);
+
+/**
+ * Set up a UCharIterator to iterate over a C++ Replaceable.
+ *
+ * Sets the UCharIterator function pointers for iteration over the
+ * Replaceable rep with iteration boundaries start=index=0 and
+ * length=limit=rep->length().
+ * The "provider" may set the start, index, and limit values at any time
+ * within the range 0..length=rep->length().
+ * The length field will be ignored.
+ *
+ * The Replaceable pointer rep is set into UCharIterator.context without copying
+ * or cloning/reallocating the Replaceable object.
+ *
+ * getState() simply returns the current index.
+ * move() will always return the final index.
+ *
+ * @param iter UCharIterator structure to be set for iteration
+ * @param rep Replaceable to iterate over
+ *
+ * @see UCharIterator
+ * @stable ICU 2.1
+ */
+U_STABLE void U_EXPORT2
+uiter_setReplaceable(UCharIterator *iter, const U_NAMESPACE_QUALIFIER Replaceable *rep);
+
+#endif
+
+U_CDECL_END
+
+#endif
diff --git a/source/common/unicode/uloc.h b/source/common/unicode/uloc.h
new file mode 100644
index 0000000..95758c3
--- /dev/null
+++ b/source/common/unicode/uloc.h
@@ -0,0 +1,1126 @@
+/*
+**********************************************************************
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*
+* File ULOC.H
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   04/01/97    aliu        Creation.
+*   08/22/98    stephen     JDK 1.2 sync.
+*   12/08/98    rtg         New C API for Locale
+*   03/30/99    damiba      overhaul
+*   03/31/99    helena      Javadoc for uloc functions.
+*   04/15/99    Madhu       Updated Javadoc
+********************************************************************************
+*/
+
+#ifndef ULOC_H
+#define ULOC_H
+
+#include "unicode/utypes.h"
+#include "unicode/uenum.h"
+
+/**    
+ * \file
+ * \brief  C API: Locale 
+ *
+ * <h2> ULoc C API for Locale </h2>
+ * A <code>Locale</code> represents a specific geographical, political,
+ * or cultural region. An operation that requires a <code>Locale</code> to perform
+ * its task is called <em>locale-sensitive</em> and uses the <code>Locale</code>
+ * to tailor information for the user. For example, displaying a number
+ * is a locale-sensitive operation--the number should be formatted
+ * according to the customs/conventions of the user's native country,
+ * region, or culture.  In the C APIs, a locales is simply a const char string.
+ *
+ * <P>
+ * You create a <code>Locale</code> with one of the three options listed below.
+ * Each of the component is separated by '_' in the locale string.
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ * \code
+ *       newLanguage
+ * 
+ *       newLanguage + newCountry
+ * 
+ *       newLanguage + newCountry + newVariant
+ * \endcode
+ * </pre>
+ * \htmlonly</blockquote>\endhtmlonly
+ * The first option is a valid <STRONG>ISO
+ * Language Code.</STRONG> These codes are the lower-case two-letter
+ * codes as defined by ISO-639.
+ * You can find a full list of these codes at a number of sites, such as:
+ * <BR><a href ="http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt">
+ * http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt</a>
+ *
+ * <P>
+ * The second option includes an additonal <STRONG>ISO Country
+ * Code.</STRONG> These codes are the upper-case two-letter codes
+ * as defined by ISO-3166.
+ * You can find a full list of these codes at a number of sites, such as:
+ * <BR><a href="http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html">
+ * http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html</a>
+ *
+ * <P>
+ * The third option requires another additonal information--the 
+ * <STRONG>Variant.</STRONG>
+ * The Variant codes are vendor and browser-specific.
+ * For example, use WIN for Windows, MAC for Macintosh, and POSIX for POSIX.
+ * Where there are two variants, separate them with an underscore, and
+ * put the most important one first. For
+ * example, a Traditional Spanish collation might be referenced, with
+ * "ES", "ES", "Traditional_WIN".
+ *
+ * <P>
+ * Because a <code>Locale</code> is just an identifier for a region,
+ * no validity check is performed when you specify a <code>Locale</code>.
+ * If you want to see whether particular resources are available for the
+ * <code>Locale</code> you asked for, you must query those resources. For
+ * example, ask the <code>UNumberFormat</code> for the locales it supports
+ * using its <code>getAvailable</code> method.
+ * <BR><STRONG>Note:</STRONG> When you ask for a resource for a particular
+ * locale, you get back the best available match, not necessarily
+ * precisely what you asked for. For more information, look at
+ * <code>UResourceBundle</code>.
+ *
+ * <P>
+ * The <code>Locale</code> provides a number of convenient constants
+ * that you can use to specify the commonly used
+ * locales. For example, the following refers to a locale
+ * for the United States:
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ * \code
+ *       ULOC_US
+ * \endcode
+ * </pre>
+ * \htmlonly</blockquote>\endhtmlonly
+ *
+ * <P>
+ * Once you've specified a locale you can query it for information about
+ * itself. Use <code>uloc_getCountry</code> to get the ISO Country Code and
+ * <code>uloc_getLanguage</code> to get the ISO Language Code. You can
+ * use <code>uloc_getDisplayCountry</code> to get the
+ * name of the country suitable for displaying to the user. Similarly,
+ * you can use <code>uloc_getDisplayLanguage</code> to get the name of
+ * the language suitable for displaying to the user. Interestingly,
+ * the <code>uloc_getDisplayXXX</code> methods are themselves locale-sensitive
+ * and have two versions: one that uses the default locale and one
+ * that takes a locale as an argument and displays the name or country in
+ * a language appropriate to that locale.
+ *
+ * <P>
+ * The ICU provides a number of services that perform locale-sensitive
+ * operations. For example, the <code>unum_xxx</code> functions format
+ * numbers, currency, or percentages in a locale-sensitive manner. 
+ * </P>
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ * \code
+ *     UErrorCode success = U_ZERO_ERROR;
+ *     UNumberFormat *nf;
+ *     const char* myLocale = "fr_FR";
+ * 
+ *     nf = unum_open( UNUM_DEFAULT, NULL, success );          
+ *     unum_close(nf);
+ *     nf = unum_open( UNUM_CURRENCY, NULL, success );
+ *     unum_close(nf);
+ *     nf = unum_open( UNUM_PERCENT, NULL, success );   
+ *     unum_close(nf);
+ * \endcode
+ * </pre>
+ * \htmlonly</blockquote>\endhtmlonly
+ * Each of these methods has two variants; one with an explicit locale
+ * and one without; the latter using the default locale.
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ * \code 
+ * 
+ *     nf = unum_open( UNUM_DEFAULT, myLocale, success );          
+ *     unum_close(nf);
+ *     nf = unum_open( UNUM_CURRENCY, myLocale, success );
+ *     unum_close(nf);
+ *     nf = unum_open( UNUM_PERCENT, myLocale, success );   
+ *     unum_close(nf);
+ * \endcode
+ * </pre>
+ * \htmlonly</blockquote>\endhtmlonly
+ * A <code>Locale</code> is the mechanism for identifying the kind of services
+ * (<code>UNumberFormat</code>) that you would like to get. The locale is
+ * <STRONG>just</STRONG> a mechanism for identifying these services.
+ *
+ * <P>
+ * Each international serivce that performs locale-sensitive operations 
+ * allows you
+ * to get all the available objects of that type. You can sift
+ * through these objects by language, country, or variant,
+ * and use the display names to present a menu to the user.
+ * For example, you can create a menu of all the collation objects
+ * suitable for a given language. Such classes implement these
+ * three class methods:
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ * \code
+ *       const char* uloc_getAvailable(int32_t index);
+ *       int32_t uloc_countAvailable();
+ *       int32_t
+ *       uloc_getDisplayName(const char* localeID,
+ *                 const char* inLocaleID, 
+ *                 UChar* result,
+ *                 int32_t maxResultSize,
+ *                  UErrorCode* err);
+ * 
+ * \endcode
+ * </pre>
+ * \htmlonly</blockquote>\endhtmlonly
+ * <P>
+ * Concerning POSIX/RFC1766 Locale IDs, 
+ *  the getLanguage/getCountry/getVariant/getName functions do understand
+ * the POSIX type form of  language_COUNTRY.ENCODING\@VARIANT
+ * and if there is not an ICU-stype variant, uloc_getVariant() for example
+ * will return the one listed after the \@at sign. As well, the hyphen
+ * "-" is recognized as a country/variant separator similarly to RFC1766.
+ * So for example, "en-us" will be interpreted as en_US.  
+ * As a result, uloc_getName() is far from a no-op, and will have the
+ * effect of converting POSIX/RFC1766 IDs into ICU form, although it does
+ * NOT map any of the actual codes (i.e. russian->ru) in any way.
+ * Applications should call uloc_getName() at the point where a locale ID
+ * is coming from an external source (user entry, OS, web browser)
+ * and pass the resulting string to other ICU functions.  For example,
+ * don't use de-de\@EURO as an argument to resourcebundle.
+ *
+ * @see UResourceBundle
+ */
+
+/** Useful constant for this language. @stable ICU 2.0 */
+#define ULOC_CHINESE            "zh"
+/** Useful constant for this language. @stable ICU 2.0 */
+#define ULOC_ENGLISH            "en"
+/** Useful constant for this language. @stable ICU 2.0 */
+#define ULOC_FRENCH             "fr"
+/** Useful constant for this language. @stable ICU 2.0 */
+#define ULOC_GERMAN             "de"
+/** Useful constant for this language. @stable ICU 2.0 */
+#define ULOC_ITALIAN            "it"
+/** Useful constant for this language. @stable ICU 2.0 */
+#define ULOC_JAPANESE           "ja"
+/** Useful constant for this language. @stable ICU 2.0 */
+#define ULOC_KOREAN             "ko"
+/** Useful constant for this language. @stable ICU 2.0 */
+#define ULOC_SIMPLIFIED_CHINESE "zh_CN"
+/** Useful constant for this language. @stable ICU 2.0 */
+#define ULOC_TRADITIONAL_CHINESE "zh_TW"
+
+/** Useful constant for this country/region. @stable ICU 2.0 */
+#define ULOC_CANADA         "en_CA"
+/** Useful constant for this country/region. @stable ICU 2.0 */
+#define ULOC_CANADA_FRENCH  "fr_CA"
+/** Useful constant for this country/region. @stable ICU 2.0 */
+#define ULOC_CHINA          "zh_CN"
+/** Useful constant for this country/region. @stable ICU 2.0 */
+#define ULOC_PRC            "zh_CN"
+/** Useful constant for this country/region. @stable ICU 2.0 */
+#define ULOC_FRANCE         "fr_FR"
+/** Useful constant for this country/region. @stable ICU 2.0 */
+#define ULOC_GERMANY        "de_DE"
+/** Useful constant for this country/region. @stable ICU 2.0 */
+#define ULOC_ITALY          "it_IT"
+/** Useful constant for this country/region. @stable ICU 2.0 */
+#define ULOC_JAPAN          "ja_JP"
+/** Useful constant for this country/region. @stable ICU 2.0 */
+#define ULOC_KOREA          "ko_KR"
+/** Useful constant for this country/region. @stable ICU 2.0 */
+#define ULOC_TAIWAN         "zh_TW"
+/** Useful constant for this country/region. @stable ICU 2.0 */
+#define ULOC_UK             "en_GB"
+/** Useful constant for this country/region. @stable ICU 2.0 */
+#define ULOC_US             "en_US"
+
+/**
+ * Useful constant for the maximum size of the language part of a locale ID.
+ * (including the terminating NULL).
+ * @stable ICU 2.0
+ */
+#define ULOC_LANG_CAPACITY 12
+
+/**
+ * Useful constant for the maximum size of the country part of a locale ID
+ * (including the terminating NULL).
+ * @stable ICU 2.0
+ */
+#define ULOC_COUNTRY_CAPACITY 4
+/**
+ * Useful constant for the maximum size of the whole locale ID
+ * (including the terminating NULL and all keywords).
+ * @stable ICU 2.0
+ */
+#define ULOC_FULLNAME_CAPACITY 157
+
+/**
+ * Useful constant for the maximum size of the script part of a locale ID
+ * (including the terminating NULL).
+ * @stable ICU 2.8
+ */
+#define ULOC_SCRIPT_CAPACITY 6
+
+/**
+ * Useful constant for the maximum size of keywords in a locale
+ * @stable ICU 2.8
+ */
+#define ULOC_KEYWORDS_CAPACITY 50
+
+/**
+ * Useful constant for the maximum total size of keywords and their values in a locale
+ * @stable ICU 2.8
+ */
+#define ULOC_KEYWORD_AND_VALUES_CAPACITY 100
+
+/**
+ * Invariant character separating keywords from the locale string
+ * @stable ICU 2.8
+ */
+#define ULOC_KEYWORD_SEPARATOR '@'
+
+/**
+  * Unicode code point for '@' separating keywords from the locale string.
+  * @see ULOC_KEYWORD_SEPARATOR
+  * @draft ICU 4.6
+  */
+#define ULOC_KEYWORD_SEPARATOR_UNICODE 0x40
+
+/**
+ * Invariant character for assigning value to a keyword
+ * @stable ICU 2.8
+ */
+#define ULOC_KEYWORD_ASSIGN '='
+
+/**
+  * Unicode code point for '=' for assigning value to a keyword.
+  * @see ULOC_KEYWORD_ASSIGN
+  * @draft ICU 4.6 
+  */
+#define ULOC_KEYWORD_ASSIGN_UNICODE 0x3D
+
+/**
+ * Invariant character separating keywords
+ * @stable ICU 2.8
+ */
+#define ULOC_KEYWORD_ITEM_SEPARATOR ';'
+
+/**
+  * Unicode code point for ';' separating keywords
+  * @see ULOC_KEYWORD_ITEM_SEPARATOR
+  * @draft ICU 4.6
+  */
+#define ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE 0x3B
+
+/**
+ * Constants for *_getLocale()
+ * Allow user to select whether she wants information on 
+ * requested, valid or actual locale.
+ * For example, a collator for "en_US_CALIFORNIA" was
+ * requested. In the current state of ICU (2.0), 
+ * the requested locale is "en_US_CALIFORNIA",
+ * the valid locale is "en_US" (most specific locale supported by ICU)
+ * and the actual locale is "root" (the collation data comes unmodified 
+ * from the UCA)
+ * The locale is considered supported by ICU if there is a core ICU bundle 
+ * for that locale (although it may be empty).
+ * @stable ICU 2.1
+ */
+typedef enum {
+  /** This is locale the data actually comes from 
+   * @stable ICU 2.1
+   */
+  ULOC_ACTUAL_LOCALE    = 0,
+  /** This is the most specific locale supported by ICU 
+   * @stable ICU 2.1
+   */
+  ULOC_VALID_LOCALE    = 1,
+
+#ifndef U_HIDE_DEPRECATED_API
+  /** This is the requested locale
+   *  @deprecated ICU 2.8 
+   */
+  ULOC_REQUESTED_LOCALE = 2,
+#endif /* U_HIDE_DEPRECATED_API */
+
+  ULOC_DATA_LOCALE_TYPE_LIMIT = 3
+} ULocDataLocaleType ;
+
+
+/**
+ * Gets ICU's default locale.  
+ * The returned string is a snapshot in time, and will remain valid
+ *   and unchanged even when uloc_setDefault() is called.
+ *   The returned storage is owned by ICU, and must not be altered or deleted
+ *   by the caller.
+ *  
+ * @return the ICU default locale
+ * @system
+ * @stable ICU 2.0
+ */
+U_STABLE const char* U_EXPORT2
+uloc_getDefault(void);
+
+/**
+ * Sets ICU's default locale.  
+ *    By default (without calling this function), ICU's default locale will be based
+ *    on information obtained from the underlying system environment.
+ *    <p>
+ *    Changes to ICU's default locale do not propagate back to the
+ *    system environment.
+ *    <p>
+ *    Changes to ICU's default locale to not affect any ICU services that
+ *    may already be open based on the previous default locale value.
+ *
+ * @param localeID the new ICU default locale. A value of NULL will try to get
+ *                 the system's default locale.
+ * @param status the error information if the setting of default locale fails
+ * @system
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+uloc_setDefault(const char* localeID,
+        UErrorCode*       status);
+
+/**
+ * Gets the language code for the specified locale.
+ *
+ * @param localeID the locale to get the ISO language code with
+ * @param language the language code for localeID
+ * @param languageCapacity the size of the language buffer to store the  
+ * language code with
+ * @param err error information if retrieving the language code failed
+ * @return the actual buffer size needed for the language code.  If it's greater 
+ * than languageCapacity, the returned language code will be truncated.  
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_getLanguage(const char*    localeID,
+         char* language,
+         int32_t languageCapacity,
+         UErrorCode* err);
+
+/**
+ * Gets the script code for the specified locale.
+ *
+ * @param localeID the locale to get the ISO language code with
+ * @param script the language code for localeID
+ * @param scriptCapacity the size of the language buffer to store the  
+ * language code with
+ * @param err error information if retrieving the language code failed
+ * @return the actual buffer size needed for the language code.  If it's greater 
+ * than scriptCapacity, the returned language code will be truncated.  
+ * @stable ICU 2.8
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_getScript(const char*    localeID,
+         char* script,
+         int32_t scriptCapacity,
+         UErrorCode* err);
+
+/**
+ * Gets the  country code for the specified locale.
+ *
+ * @param localeID the locale to get the country code with
+ * @param country the country code for localeID
+ * @param countryCapacity the size of the country buffer to store the  
+ * country code with
+ * @param err error information if retrieving the country code failed
+ * @return the actual buffer size needed for the country code.  If it's greater 
+ * than countryCapacity, the returned country code will be truncated.  
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_getCountry(const char*    localeID,
+        char* country,
+        int32_t countryCapacity,
+        UErrorCode* err);
+
+/**
+ * Gets the variant code for the specified locale.
+ *
+ * @param localeID the locale to get the variant code with
+ * @param variant the variant code for localeID
+ * @param variantCapacity the size of the variant buffer to store the 
+ * variant code with
+ * @param err error information if retrieving the variant code failed
+ * @return the actual buffer size needed for the variant code.  If it's greater 
+ * than variantCapacity, the returned variant code will be truncated.  
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_getVariant(const char*    localeID,
+        char* variant,
+        int32_t variantCapacity,
+        UErrorCode* err);
+
+
+/**
+ * Gets the full name for the specified locale.
+ * Note: This has the effect of 'canonicalizing' the ICU locale ID to
+ * a certain extent. Upper and lower case are set as needed.
+ * It does NOT map aliased names in any way.
+ * See the top of this header file.
+ * This API supports preflighting.
+ *
+ * @param localeID the locale to get the full name with
+ * @param name fill in buffer for the name without keywords.
+ * @param nameCapacity capacity of the fill in buffer.
+ * @param err error information if retrieving the full name failed
+ * @return the actual buffer size needed for the full name.  If it's greater 
+ * than nameCapacity, the returned full name will be truncated.  
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_getName(const char*    localeID,
+         char* name,
+         int32_t nameCapacity,
+         UErrorCode* err);
+
+/**
+ * Gets the full name for the specified locale.
+ * Note: This has the effect of 'canonicalizing' the string to
+ * a certain extent. Upper and lower case are set as needed,
+ * and if the components were in 'POSIX' format they are changed to
+ * ICU format.  It does NOT map aliased names in any way.
+ * See the top of this header file.
+ *
+ * @param localeID the locale to get the full name with
+ * @param name the full name for localeID
+ * @param nameCapacity the size of the name buffer to store the 
+ * full name with
+ * @param err error information if retrieving the full name failed
+ * @return the actual buffer size needed for the full name.  If it's greater 
+ * than nameCapacity, the returned full name will be truncated.  
+ * @stable ICU 2.8
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_canonicalize(const char*    localeID,
+         char* name,
+         int32_t nameCapacity,
+         UErrorCode* err);
+
+/**
+ * Gets the ISO language code for the specified locale.
+ *
+ * @param localeID the locale to get the ISO language code with
+ * @return language the ISO language code for localeID
+ * @stable ICU 2.0
+ */
+U_STABLE const char* U_EXPORT2
+uloc_getISO3Language(const char* localeID);
+
+
+/**
+ * Gets the ISO country code for the specified locale.
+ *
+ * @param localeID the locale to get the ISO country code with
+ * @return country the ISO country code for localeID
+ * @stable ICU 2.0
+ */
+U_STABLE const char* U_EXPORT2
+uloc_getISO3Country(const char* localeID);
+
+/**
+ * Gets the Win32 LCID value for the specified locale.
+ * If the ICU locale is not recognized by Windows, 0 will be returned.
+ *
+ * @param localeID the locale to get the Win32 LCID value with
+ * @return country the Win32 LCID for localeID
+ * @stable ICU 2.0
+ */
+U_STABLE uint32_t U_EXPORT2
+uloc_getLCID(const char* localeID);
+
+/**
+ * Gets the language name suitable for display for the specified locale.
+ *
+ * @param locale the locale to get the ISO language code with
+ * @param displayLocale Specifies the locale to be used to display the name.  In other words,
+ *                 if the locale's language code is "en", passing Locale::getFrench() for
+ *                 inLocale would result in "Anglais", while passing Locale::getGerman()
+ *                 for inLocale would result in "Englisch".
+ * @param language the displayable language code for localeID
+ * @param languageCapacity the size of the language buffer to store the  
+ * displayable language code with
+ * @param status error information if retrieving the displayable language code failed
+ * @return the actual buffer size needed for the displayable language code.  If it's greater 
+ * than languageCapacity, the returned language code will be truncated.  
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_getDisplayLanguage(const char* locale,
+            const char* displayLocale,
+            UChar* language,
+            int32_t languageCapacity,
+            UErrorCode* status);
+
+/**
+ * Gets the script name suitable for display for the specified locale.
+ *
+ * @param locale the locale to get the displayable script code with. NULL may be used to specify the default.
+ * @param displayLocale Specifies the locale to be used to display the name.  In other words,
+ *                 if the locale's language code is "en", passing Locale::getFrench() for
+ *                 inLocale would result in "", while passing Locale::getGerman()
+ *                 for inLocale would result in "". NULL may be used to specify the default.
+ * @param script the displayable country code for localeID
+ * @param scriptCapacity the size of the script buffer to store the  
+ * displayable script code with
+ * @param status error information if retrieving the displayable script code failed
+ * @return the actual buffer size needed for the displayable script code.  If it's greater 
+ * than scriptCapacity, the returned displayable script code will be truncated.  
+ * @stable ICU 2.8
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_getDisplayScript(const char* locale,
+            const char* displayLocale,
+            UChar* script,
+            int32_t scriptCapacity,
+            UErrorCode* status);
+
+/**
+ * Gets the country name suitable for display for the specified locale.
+ *
+ * @param locale the locale to get the displayable country code with. NULL may be used to specify the default.
+ * @param displayLocale Specifies the locale to be used to display the name.  In other words,
+ *                 if the locale's language code is "en", passing Locale::getFrench() for
+ *                 inLocale would result in "Anglais", while passing Locale::getGerman()
+ *                 for inLocale would result in "Englisch". NULL may be used to specify the default.
+ * @param country the displayable country code for localeID
+ * @param countryCapacity the size of the country buffer to store the  
+ * displayable country code with
+ * @param status error information if retrieving the displayable country code failed
+ * @return the actual buffer size needed for the displayable country code.  If it's greater 
+ * than countryCapacity, the returned displayable country code will be truncated.  
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_getDisplayCountry(const char* locale,
+                       const char* displayLocale,
+                       UChar* country,
+                       int32_t countryCapacity,
+                       UErrorCode* status);
+
+
+/**
+ * Gets the variant name suitable for display for the specified locale.
+ *
+ * @param locale the locale to get the displayable variant code with. NULL may be used to specify the default.
+ * @param displayLocale Specifies the locale to be used to display the name.  In other words,
+ *                 if the locale's language code is "en", passing Locale::getFrench() for
+ *                 inLocale would result in "Anglais", while passing Locale::getGerman()
+ *                 for inLocale would result in "Englisch". NULL may be used to specify the default.
+ * @param variant the displayable variant code for localeID
+ * @param variantCapacity the size of the variant buffer to store the 
+ * displayable variant code with
+ * @param status error information if retrieving the displayable variant code failed
+ * @return the actual buffer size needed for the displayable variant code.  If it's greater 
+ * than variantCapacity, the returned displayable variant code will be truncated.  
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_getDisplayVariant(const char* locale,
+                       const char* displayLocale,
+                       UChar* variant,
+                       int32_t variantCapacity,
+                       UErrorCode* status);
+
+/**
+ * Gets the keyword name suitable for display for the specified locale.
+ * E.g: for the locale string de_DE\@collation=PHONEBOOK, this API gets the display 
+ * string for the keyword collation. 
+ * Usage:
+ * <code>
+ *    UErrorCode status = U_ZERO_ERROR;
+ *    const char* keyword =NULL;
+ *    int32_t keywordLen = 0;
+ *    int32_t keywordCount = 0;
+ *    UChar displayKeyword[256];
+ *    int32_t displayKeywordLen = 0;
+ *    UEnumeration* keywordEnum = uloc_openKeywords("de_DE@collation=PHONEBOOK;calendar=TRADITIONAL", &status);
+ *    for(keywordCount = uenum_count(keywordEnum, &status); keywordCount > 0 ; keywordCount--){
+ *          if(U_FAILURE(status)){
+ *              ...something went wrong so handle the error...
+ *              break;
+ *          }
+ *          // the uenum_next returns NUL terminated string
+ *          keyword = uenum_next(keywordEnum, &keywordLen, &status);
+ *          displayKeywordLen = uloc_getDisplayKeyword(keyword, "en_US", displayKeyword, 256);
+ *          ... do something interesting .....
+ *    }
+ *    uenum_close(keywordEnum);
+ * </code>
+ * @param keyword           The keyword whose display string needs to be returned.
+ * @param displayLocale     Specifies the locale to be used to display the name.  In other words,
+ *                          if the locale's language code is "en", passing Locale::getFrench() for
+ *                          inLocale would result in "Anglais", while passing Locale::getGerman()
+ *                          for inLocale would result in "Englisch". NULL may be used to specify the default.
+ * @param dest              the buffer to which the displayable keyword should be written.
+ * @param destCapacity      The size of the buffer (number of UChars). If it is 0, then
+ *                          dest may be NULL and the function will only return the length of the 
+ *                          result without writing any of the result string (pre-flighting).
+ * @param status            error information if retrieving the displayable string failed. 
+ *                          Should not be NULL and should not indicate failure on entry.
+ * @return the actual buffer size needed for the displayable variant code.  
+ * @see #uloc_openKeywords
+ * @stable ICU 2.8
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_getDisplayKeyword(const char* keyword,
+                       const char* displayLocale,
+                       UChar* dest,
+                       int32_t destCapacity,
+                       UErrorCode* status);
+/**
+ * Gets the value of the keyword suitable for display for the specified locale.
+ * E.g: for the locale string de_DE\@collation=PHONEBOOK, this API gets the display 
+ * string for PHONEBOOK, in the display locale, when "collation" is specified as the keyword.
+ *
+ * @param locale            The locale to get the displayable variant code with. NULL may be used to specify the default.
+ * @param keyword           The keyword for whose value should be used.
+ * @param displayLocale     Specifies the locale to be used to display the name.  In other words,
+ *                          if the locale's language code is "en", passing Locale::getFrench() for
+ *                          inLocale would result in "Anglais", while passing Locale::getGerman()
+ *                          for inLocale would result in "Englisch". NULL may be used to specify the default.
+ * @param dest              the buffer to which the displayable keyword should be written.
+ * @param destCapacity      The size of the buffer (number of UChars). If it is 0, then
+ *                          dest may be NULL and the function will only return the length of the 
+ *                          result without writing any of the result string (pre-flighting).
+ * @param status            error information if retrieving the displayable string failed. 
+ *                          Should not be NULL and must not indicate failure on entry.
+ * @return the actual buffer size needed for the displayable variant code.  
+ * @stable ICU 2.8
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_getDisplayKeywordValue(   const char* locale,
+                               const char* keyword,
+                               const char* displayLocale,
+                               UChar* dest,
+                               int32_t destCapacity,
+                               UErrorCode* status);
+/**
+ * Gets the full name suitable for display for the specified locale.
+ *
+ * @param localeID the locale to get the displayable name with. NULL may be used to specify the default.
+ * @param inLocaleID Specifies the locale to be used to display the name.  In other words,
+ *                   if the locale's language code is "en", passing Locale::getFrench() for
+ *                   inLocale would result in "Anglais", while passing Locale::getGerman()
+ *                   for inLocale would result in "Englisch". NULL may be used to specify the default.
+ * @param result the displayable name for localeID
+ * @param maxResultSize the size of the name buffer to store the 
+ * displayable full name with
+ * @param err error information if retrieving the displayable name failed
+ * @return the actual buffer size needed for the displayable name.  If it's greater 
+ * than maxResultSize, the returned displayable name will be truncated.  
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_getDisplayName(const char* localeID,
+            const char* inLocaleID,
+            UChar* result,
+            int32_t maxResultSize,
+            UErrorCode* err);
+
+
+/**
+ * Gets the specified locale from a list of all available locales.  
+ * The return value is a pointer to an item of 
+ * a locale name array.  Both this array and the pointers
+ * it contains are owned by ICU and should not be deleted or written through
+ * by the caller.  The locale name is terminated by a null pointer.
+ * @param n the specific locale name index of the available locale list
+ * @return a specified locale name of all available locales
+ * @stable ICU 2.0
+ */
+U_STABLE const char* U_EXPORT2
+uloc_getAvailable(int32_t n);
+
+/**
+ * Gets the size of the all available locale list.
+ *
+ * @return the size of the locale list
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2 uloc_countAvailable(void);
+
+/**
+ *
+ * Gets a list of all available language codes defined in ISO 639.  This is a pointer
+ * to an array of pointers to arrays of char.  All of these pointers are owned
+ * by ICU-- do not delete them, and do not write through them.  The array is
+ * terminated with a null pointer.
+ * @return a list of all available language codes
+ * @stable ICU 2.0
+ */
+U_STABLE const char* const* U_EXPORT2
+uloc_getISOLanguages(void);
+
+/**
+ *
+ * Gets a list of all available 2-letter country codes defined in ISO 639.  This is a
+ * pointer to an array of pointers to arrays of char.  All of these pointers are
+ * owned by ICU-- do not delete them, and do not write through them.  The array is
+ * terminated with a null pointer.
+ * @return a list of all available country codes
+ * @stable ICU 2.0
+ */
+U_STABLE const char* const* U_EXPORT2
+uloc_getISOCountries(void);
+
+/**
+ * Truncate the locale ID string to get the parent locale ID.
+ * Copies the part of the string before the last underscore.
+ * The parent locale ID will be an empty string if there is no
+ * underscore, or if there is only one underscore at localeID[0].
+ *
+ * @param localeID Input locale ID string.
+ * @param parent   Output string buffer for the parent locale ID.
+ * @param parentCapacity Size of the output buffer.
+ * @param err A UErrorCode value.
+ * @return The length of the parent locale ID.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_getParent(const char*    localeID,
+                 char* parent,
+                 int32_t parentCapacity,
+                 UErrorCode* err);
+
+
+
+
+/**
+ * Gets the full name for the specified locale.
+ * Note: This has the effect of 'canonicalizing' the string to
+ * a certain extent. Upper and lower case are set as needed,
+ * and if the components were in 'POSIX' format they are changed to
+ * ICU format.  It does NOT map aliased names in any way.
+ * See the top of this header file.
+ * This API strips off the keyword part, so "de_DE\@collation=phonebook" 
+ * will become "de_DE". 
+ * This API supports preflighting.
+ *
+ * @param localeID the locale to get the full name with
+ * @param name fill in buffer for the name without keywords.
+ * @param nameCapacity capacity of the fill in buffer.
+ * @param err error information if retrieving the full name failed
+ * @return the actual buffer size needed for the full name.  If it's greater 
+ * than nameCapacity, the returned full name will be truncated.  
+ * @stable ICU 2.8
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_getBaseName(const char*    localeID,
+         char* name,
+         int32_t nameCapacity,
+         UErrorCode* err);
+
+/**
+ * Gets an enumeration of keywords for the specified locale. Enumeration
+ * must get disposed of by the client using uenum_close function.
+ *
+ * @param localeID the locale to get the variant code with
+ * @param status error information if retrieving the keywords failed
+ * @return enumeration of keywords or NULL if there are no keywords.
+ * @stable ICU 2.8
+ */
+U_STABLE UEnumeration* U_EXPORT2
+uloc_openKeywords(const char* localeID,
+                        UErrorCode* status);
+
+/**
+ * Get the value for a keyword. Locale name does not need to be normalized.
+ * 
+ * @param localeID locale name containing the keyword ("de_DE@currency=EURO;collation=PHONEBOOK")
+ * @param keywordName name of the keyword for which we want the value. Case insensitive.
+ * @param buffer receiving buffer
+ * @param bufferCapacity capacity of receiving buffer
+ * @param status containing error code - buffer not big enough.
+ * @return the length of keyword value
+ * @stable ICU 2.8
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_getKeywordValue(const char* localeID,
+                     const char* keywordName,
+                     char* buffer, int32_t bufferCapacity,
+                     UErrorCode* status);
+
+
+/**
+ * Set the value of the specified keyword.
+ * NOTE: Unlike almost every other ICU function which takes a
+ * buffer, this function will NOT truncate the output text. If a
+ * BUFFER_OVERFLOW_ERROR is received, it means that the original
+ * buffer is untouched. This is done to prevent incorrect or possibly
+ * even malformed locales from being generated and used.
+ * 
+ * @param keywordName name of the keyword to be set. Case insensitive.
+ * @param keywordValue value of the keyword to be set. If 0-length or
+ *  NULL, will result in the keyword being removed. No error is given if 
+ *  that keyword does not exist.
+ * @param buffer input buffer containing locale to be modified.
+ * @param bufferCapacity capacity of receiving buffer
+ * @param status containing error code - buffer not big enough.
+ * @return the length needed for the buffer
+ * @see uloc_getKeywordValue
+ * @stable ICU 3.2
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_setKeywordValue(const char* keywordName,
+                     const char* keywordValue,
+                     char* buffer, int32_t bufferCapacity,
+                     UErrorCode* status);
+
+/**
+ * enums for the  return value for the character and line orientation
+ * functions.
+ * @stable ICU 4.0
+ */
+typedef enum {
+  ULOC_LAYOUT_LTR   = 0,  /* left-to-right. */
+  ULOC_LAYOUT_RTL    = 1,  /* right-to-left. */
+  ULOC_LAYOUT_TTB    = 2,  /* top-to-bottom. */
+  ULOC_LAYOUT_BTT    = 3,   /* bottom-to-top. */
+  ULOC_LAYOUT_UNKNOWN
+} ULayoutType;
+
+/**
+ * Get the layout character orientation for the specified locale.
+ * 
+ * @param localeId locale name
+ * @param status Error status
+ * @return an enum indicating the layout orientation for characters.
+ * @stable ICU 4.0
+ */
+U_STABLE ULayoutType U_EXPORT2
+uloc_getCharacterOrientation(const char* localeId,
+                             UErrorCode *status);
+
+/**
+ * Get the layout line orientation for the specified locale.
+ * 
+ * @param localeId locale name
+ * @param status Error status
+ * @return an enum indicating the layout orientation for lines.
+ * @stable ICU 4.0
+ */
+U_STABLE ULayoutType U_EXPORT2
+uloc_getLineOrientation(const char* localeId,
+                        UErrorCode *status);
+
+/**
+ * enums for the 'outResult' parameter return value
+ * @see uloc_acceptLanguageFromHTTP
+ * @see uloc_acceptLanguage
+ * @stable ICU 3.2
+ */
+typedef enum {
+  ULOC_ACCEPT_FAILED   = 0,  /* No exact match was found. */
+  ULOC_ACCEPT_VALID    = 1,  /* An exact match was found. */
+  ULOC_ACCEPT_FALLBACK = 2   /* A fallback was found, for example, 
+                                Accept list contained 'ja_JP'
+                                which matched available locale 'ja'. */
+} UAcceptResult;
+
+
+/**
+ * Based on a HTTP header from a web browser and a list of available locales,
+ * determine an acceptable locale for the user.
+ * @param result - buffer to accept the result locale
+ * @param resultAvailable the size of the result buffer.
+ * @param outResult - An out parameter that contains the fallback status
+ * @param httpAcceptLanguage - "Accept-Language:" header as per HTTP.
+ * @param availableLocales - list of available locales to match
+ * @param status Error status, may be BUFFER_OVERFLOW_ERROR
+ * @return length needed for the locale.
+ * @stable ICU 3.2
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_acceptLanguageFromHTTP(char *result, int32_t resultAvailable,
+                            UAcceptResult *outResult,
+                            const char *httpAcceptLanguage,
+                            UEnumeration* availableLocales,
+                            UErrorCode *status);
+
+/**
+ * Based on a list of available locales,
+ * determine an acceptable locale for the user.
+ * @param result - buffer to accept the result locale
+ * @param resultAvailable the size of the result buffer.
+ * @param outResult - An out parameter that contains the fallback status
+ * @param acceptList - list of acceptable languages
+ * @param acceptListCount - count of acceptList items
+ * @param availableLocales - list of available locales to match
+ * @param status Error status, may be BUFFER_OVERFLOW_ERROR
+ * @return length needed for the locale.
+ * @stable ICU 3.2
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_acceptLanguage(char *result, int32_t resultAvailable, 
+                    UAcceptResult *outResult, const char **acceptList,
+                    int32_t acceptListCount,
+                    UEnumeration* availableLocales,
+                    UErrorCode *status);
+
+
+/**
+ * Gets the ICU locale ID for the specified Win32 LCID value.
+ *
+ * @param hostID the Win32 LCID to translate
+ * @param locale the output buffer for the ICU locale ID, which will be NUL-terminated
+ *  if there is room.
+ * @param localeCapacity the size of the output buffer
+ * @param status an error is returned if the LCID is unrecognized or the output buffer
+ *  is too small
+ * @return actual the actual size of the locale ID, not including NUL-termination 
+ * @stable ICU 3.8
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_getLocaleForLCID(uint32_t hostID, char *locale, int32_t localeCapacity,
+                    UErrorCode *status);
+
+
+/**
+ * Add the likely subtags for a provided locale ID, per the algorithm described
+ * in the following CLDR technical report:
+ *
+ *   http://www.unicode.org/reports/tr35/#Likely_Subtags
+ *
+ * If localeID is already in the maximal form, or there is no data available
+ * for maximization, it will be copied to the output buffer.  For example,
+ * "und-Zzzz" cannot be maximized, since there is no reasonable maximization.
+ *
+ * Examples:
+ *
+ * "en" maximizes to "en_Latn_US"
+ *
+ * "de" maximizes to "de_Latn_US"
+ *
+ * "sr" maximizes to "sr_Cyrl_RS"
+ *
+ * "sh" maximizes to "sr_Latn_RS" (Note this will not reverse.)
+ *
+ * "zh_Hani" maximizes to "zh_Hans_CN" (Note this will not reverse.)
+ *
+ * @param localeID The locale to maximize
+ * @param maximizedLocaleID The maximized locale
+ * @param maximizedLocaleIDCapacity The capacity of the maximizedLocaleID buffer
+ * @param err Error information if maximizing the locale failed.  If the length
+ * of the localeID and the null-terminator is greater than the maximum allowed size,
+ * or the localeId is not well-formed, the error code is U_ILLEGAL_ARGUMENT_ERROR.
+ * @return The actual buffer size needed for the maximized locale.  If it's
+ * greater than maximizedLocaleIDCapacity, the returned ID will be truncated.
+ * On error, the return value is -1.
+ * @stable ICU 4.0
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_addLikelySubtags(const char*    localeID,
+         char* maximizedLocaleID,
+         int32_t maximizedLocaleIDCapacity,
+         UErrorCode* err);
+
+
+/**
+ * Minimize the subtags for a provided locale ID, per the algorithm described
+ * in the following CLDR technical report:
+ *
+ *   http://www.unicode.org/reports/tr35/#Likely_Subtags
+ *
+ * If localeID is already in the minimal form, or there is no data available
+ * for minimization, it will be copied to the output buffer.  Since the
+ * minimization algorithm relies on proper maximization, see the comments
+ * for uloc_addLikelySubtags for reasons why there might not be any data.
+ *
+ * Examples:
+ *
+ * "en_Latn_US" minimizes to "en"
+ *
+ * "de_Latn_US" minimizes to "de"
+ *
+ * "sr_Cyrl_RS" minimizes to "sr"
+ *
+ * "zh_Hant_TW" minimizes to "zh_TW" (The region is preferred to the
+ * script, and minimizing to "zh" would imply "zh_Hans_CN".)
+ *
+ * @param localeID The locale to minimize
+ * @param minimizedLocaleID The minimized locale
+ * @param minimizedLocaleIDCapacity The capacity of the minimizedLocaleID buffer
+ * @param err Error information if minimizing the locale failed.  If the length
+ * of the localeID and the null-terminator is greater than the maximum allowed size,
+ * or the localeId is not well-formed, the error code is U_ILLEGAL_ARGUMENT_ERROR.
+ * @return The actual buffer size needed for the minimized locale.  If it's
+ * greater than minimizedLocaleIDCapacity, the returned ID will be truncated.
+ * On error, the return value is -1.
+ * @stable ICU 4.0
+ */
+U_STABLE int32_t U_EXPORT2
+uloc_minimizeSubtags(const char*    localeID,
+         char* minimizedLocaleID,
+         int32_t minimizedLocaleIDCapacity,
+         UErrorCode* err);
+
+/** 
+ * Returns a locale ID for the specified BCP47 language tag string.
+ * If the specified language tag contains any ill-formed subtags,
+ * the first such subtag and all following subtags are ignored.
+ * <p> 
+ * This implements the 'Language-Tag' production of BCP47, and so
+ * supports grandfathered (regular and irregular) as well as private
+ * use language tags.  Private use tags are represented as 'x-whatever',
+ * and grandfathered tags are converted to their canonical replacements
+ * where they exist.  Note that a few grandfathered tags have no modern
+ * replacement, these will be converted using the fallback described in
+ * the first paragraph, so some information might be lost.
+ * @param langtag   the input BCP47 language tag.
+ * @param localeID  the output buffer receiving a locale ID for the
+ *                  specified BCP47 language tag.
+ * @param localeIDCapacity  the size of the locale ID output buffer.
+ * @param parsedLength  if not NULL, succsessfully parsed length
+ *                      for the input language tag is set.
+ * @param err       error information if receiving the locald ID
+ *                  failed.
+ * @return          the length of the locale ID.
+ * @draft ICU 4.2
+ */
+U_DRAFT int32_t U_EXPORT2
+uloc_forLanguageTag(const char* langtag,
+                    char* localeID,
+                    int32_t localeIDCapacity,
+                    int32_t* parsedLength,
+                    UErrorCode* err);
+
+/** 
+ * Returns a well-formed language tag for this locale ID. 
+ * <p> 
+ * <b>Note</b>: When <code>strict</code> is FALSE, any locale
+ * fields which do not satisfy the BCP47 syntax requirement will
+ * be omitted from the result.  When <code>strict</code> is
+ * TRUE, this function sets U_ILLEGAL_ARGUMENT_ERROR to the
+ * <code>err</code> if any locale fields do not satisfy the
+ * BCP47 syntax requirement.
+ * @param localeID  the input lcoale ID
+ * @param langtag   the output buffer receiving BCP47 language
+ *                  tag for the locale ID.
+ * @param langtagCapacity   the size of the BCP47 language tag
+ *                          output buffer.
+ * @param strict    boolean value indicating if the function returns
+ *                  an error for an ill-formed input locale ID.
+ * @param err       error information if receiving the language
+ *                  tag failed.
+ * @return          The length of the BCP47 language tag.
+ * @draft ICU 4.2
+ */
+U_DRAFT int32_t U_EXPORT2
+uloc_toLanguageTag(const char* localeID,
+                   char* langtag,
+                   int32_t langtagCapacity,
+                   UBool strict,
+                   UErrorCode* err);
+
+#endif /*_ULOC*/
diff --git a/source/common/unicode/umachine.h b/source/common/unicode/umachine.h
new file mode 100644
index 0000000..abbdcb7
--- /dev/null
+++ b/source/common/unicode/umachine.h
@@ -0,0 +1,374 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  umachine.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999sep13
+*   created by: Markus W. Scherer
+*
+*   This file defines basic types and constants for utf.h to be
+*   platform-independent. umachine.h and utf.h are included into
+*   utypes.h to provide all the general definitions for ICU.
+*   All of these definitions used to be in utypes.h before
+*   the UTF-handling macros made this unmaintainable.
+*/
+
+#ifndef __UMACHINE_H__
+#define __UMACHINE_H__
+
+
+/**
+ * \file
+ * \brief Basic types and constants for UTF
+ *
+ * <h2> Basic types and constants for UTF </h2>
+ *   This file defines basic types and constants for utf.h to be
+ *   platform-independent. umachine.h and utf.h are included into
+ *   utypes.h to provide all the general definitions for ICU.
+ *   All of these definitions used to be in utypes.h before
+ *   the UTF-handling macros made this unmaintainable.
+ *
+ */
+/*==========================================================================*/
+/* Include platform-dependent definitions                                   */
+/* which are contained in the platform-specific file platform.h             */
+/*==========================================================================*/
+
+#if defined(U_PALMOS)
+#   include "unicode/ppalmos.h"
+#elif !defined(__MINGW32__) && (defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64))
+#ifdef CYGWINMSVC
+#   include "unicode/platform.h"
+#endif
+#   include "unicode/pwin32.h"
+#else
+#   include "unicode/ptypes.h" /* platform.h is included in ptypes.h */
+#endif
+
+/*
+ * ANSI C headers:
+ * stddef.h defines wchar_t
+ */
+#include <stddef.h>
+
+/*==========================================================================*/
+/* XP_CPLUSPLUS is a cross-platform symbol which should be defined when     */
+/* using C++.  It should not be defined when compiling under C.             */
+/*==========================================================================*/
+
+#ifdef __cplusplus
+#   ifndef XP_CPLUSPLUS
+#       define XP_CPLUSPLUS
+#   endif
+#else
+#   undef XP_CPLUSPLUS
+#endif
+
+/*==========================================================================*/
+/* For C wrappers, we use the symbol U_STABLE.                                */
+/* This works properly if the includer is C or C++.                         */
+/* Functions are declared   U_STABLE return-type U_EXPORT2 function-name()... */
+/*==========================================================================*/
+
+/**
+ * \def U_CFUNC
+ * This is used in a declaration of a library private ICU C function.
+ * @stable ICU 2.4
+ */
+
+/**
+ * \def U_CDECL_BEGIN
+ * This is used to begin a declaration of a library private ICU C API.
+ * @stable ICU 2.4
+ */
+
+/**
+ * \def U_CDECL_END
+ * This is used to end a declaration of a library private ICU C API
+ * @stable ICU 2.4
+ */
+
+#ifdef XP_CPLUSPLUS
+#   define U_CFUNC extern "C"
+#   define U_CDECL_BEGIN extern "C" {
+#   define U_CDECL_END   }
+#else
+#   define U_CFUNC extern
+#   define U_CDECL_BEGIN
+#   define U_CDECL_END
+#endif
+
+/**
+ * \def U_ATTRIBUTE_DEPRECATED
+ *  This is used for GCC specific attributes
+ * @internal
+ */
+#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2))
+#    define U_ATTRIBUTE_DEPRECATED __attribute__ ((deprecated))
+/**
+ * \def U_ATTRIBUTE_DEPRECATED
+ * This is used for Visual C++ specific attributes 
+ * @internal
+ */
+#elif defined(U_WINDOWS) && defined(_MSC_VER) && (_MSC_VER >= 1400)
+#    define U_ATTRIBUTE_DEPRECATED __declspec(deprecated)
+#else
+#    define U_ATTRIBUTE_DEPRECATED
+#endif
+/** This is used to declare a function as a public ICU C API @stable ICU 2.0*/
+#define U_CAPI U_CFUNC U_EXPORT
+/** This is used to declare a function as a stable public ICU C API*/
+#define U_STABLE U_CAPI
+/** This is used to declare a function as a draft public ICU C API  */
+#define U_DRAFT  U_CAPI
+/** This is used to declare a function as a deprecated public ICU C API  */
+#define U_DEPRECATED U_CAPI U_ATTRIBUTE_DEPRECATED
+/** This is used to declare a function as an obsolete public ICU C API  */
+#define U_OBSOLETE U_CAPI
+/** This is used to declare a function as an internal ICU C API  */
+#define U_INTERNAL U_CAPI
+
+/*==========================================================================*/
+/* limits for int32_t etc., like in POSIX inttypes.h                        */
+/*==========================================================================*/
+
+#ifndef INT8_MIN
+/** The smallest value an 8 bit signed integer can hold @stable ICU 2.0 */
+#   define INT8_MIN        ((int8_t)(-128))
+#endif
+#ifndef INT16_MIN
+/** The smallest value a 16 bit signed integer can hold @stable ICU 2.0 */
+#   define INT16_MIN       ((int16_t)(-32767-1))
+#endif
+#ifndef INT32_MIN
+/** The smallest value a 32 bit signed integer can hold @stable ICU 2.0 */
+#   define INT32_MIN       ((int32_t)(-2147483647-1))
+#endif
+
+#ifndef INT8_MAX
+/** The largest value an 8 bit signed integer can hold @stable ICU 2.0 */
+#   define INT8_MAX        ((int8_t)(127))
+#endif
+#ifndef INT16_MAX
+/** The largest value a 16 bit signed integer can hold @stable ICU 2.0 */
+#   define INT16_MAX       ((int16_t)(32767))
+#endif
+#ifndef INT32_MAX
+/** The largest value a 32 bit signed integer can hold @stable ICU 2.0 */
+#   define INT32_MAX       ((int32_t)(2147483647))
+#endif
+
+#ifndef UINT8_MAX
+/** The largest value an 8 bit unsigned integer can hold @stable ICU 2.0 */
+#   define UINT8_MAX       ((uint8_t)(255U))
+#endif
+#ifndef UINT16_MAX
+/** The largest value a 16 bit unsigned integer can hold @stable ICU 2.0 */
+#   define UINT16_MAX      ((uint16_t)(65535U))
+#endif
+#ifndef UINT32_MAX
+/** The largest value a 32 bit unsigned integer can hold @stable ICU 2.0 */
+#   define UINT32_MAX      ((uint32_t)(4294967295U))
+#endif
+
+#if defined(U_INT64_T_UNAVAILABLE)
+# error int64_t is required for decimal format and rule-based number format.
+#else
+# ifndef INT64_C
+/**
+ * Provides a platform independent way to specify a signed 64-bit integer constant.
+ * note: may be wrong for some 64 bit platforms - ensure your compiler provides INT64_C
+ * @stable ICU 2.8
+ */
+#   define INT64_C(c) c ## LL
+# endif
+# ifndef UINT64_C
+/**
+ * Provides a platform independent way to specify an unsigned 64-bit integer constant.
+ * note: may be wrong for some 64 bit platforms - ensure your compiler provides UINT64_C
+ * @stable ICU 2.8
+ */
+#   define UINT64_C(c) c ## ULL
+# endif
+# ifndef U_INT64_MIN
+/** The smallest value a 64 bit signed integer can hold @stable ICU 2.8 */
+#     define U_INT64_MIN       ((int64_t)(INT64_C(-9223372036854775807)-1))
+# endif
+# ifndef U_INT64_MAX
+/** The largest value a 64 bit signed integer can hold @stable ICU 2.8 */
+#     define U_INT64_MAX       ((int64_t)(INT64_C(9223372036854775807)))
+# endif
+# ifndef U_UINT64_MAX
+/** The largest value a 64 bit unsigned integer can hold @stable ICU 2.8 */
+#     define U_UINT64_MAX      ((uint64_t)(UINT64_C(18446744073709551615)))
+# endif
+#endif
+
+/*==========================================================================*/
+/* Boolean data type                                                        */
+/*==========================================================================*/
+
+/** The ICU boolean type @stable ICU 2.0 */
+typedef int8_t UBool;
+
+#ifndef TRUE
+/** The TRUE value of a UBool @stable ICU 2.0 */
+#   define TRUE  1
+#endif
+#ifndef FALSE
+/** The FALSE value of a UBool @stable ICU 2.0 */
+#   define FALSE 0
+#endif
+
+
+/*==========================================================================*/
+/* Unicode data types                                                       */
+/*==========================================================================*/
+
+/* wchar_t-related definitions -------------------------------------------- */
+
+/**
+ * \def U_HAVE_WCHAR_H
+ * Indicates whether <wchar.h> is available (1) or not (0). Set to 1 by default.
+ *
+ * @stable ICU 2.0
+ */
+#ifndef U_HAVE_WCHAR_H
+#   define U_HAVE_WCHAR_H 1
+#endif
+
+/**
+ * \def U_SIZEOF_WCHAR_T
+ * U_SIZEOF_WCHAR_T==sizeof(wchar_t) (0 means it is not defined or autoconf could not set it)
+ *
+ * @stable ICU 2.0
+ */
+#if U_SIZEOF_WCHAR_T==0
+#   undef U_SIZEOF_WCHAR_T
+#   define U_SIZEOF_WCHAR_T 4
+#endif
+
+/*
+ * \def U_WCHAR_IS_UTF16
+ * Defined if wchar_t uses UTF-16.
+ *
+ * @stable ICU 2.0
+ */
+/*
+ * \def U_WCHAR_IS_UTF32
+ * Defined if wchar_t uses UTF-32.
+ *
+ * @stable ICU 2.0
+ */
+#if !defined(U_WCHAR_IS_UTF16) && !defined(U_WCHAR_IS_UTF32)
+#   ifdef __STDC_ISO_10646__
+#       if (U_SIZEOF_WCHAR_T==2)
+#           define U_WCHAR_IS_UTF16
+#       elif (U_SIZEOF_WCHAR_T==4)
+#           define  U_WCHAR_IS_UTF32
+#       endif
+#   elif defined __UCS2__
+#       if (__OS390__ || __OS400__) && (U_SIZEOF_WCHAR_T==2)
+#           define U_WCHAR_IS_UTF16
+#       endif
+#   elif defined __UCS4__
+#       if (U_SIZEOF_WCHAR_T==4)
+#           define U_WCHAR_IS_UTF32
+#       endif
+#   elif defined(U_WINDOWS)
+#       define U_WCHAR_IS_UTF16
+#   endif
+#endif
+
+/* UChar and UChar32 definitions -------------------------------------------- */
+
+/** Number of bytes in a UChar. @stable ICU 2.0 */
+#define U_SIZEOF_UCHAR 2
+
+/**
+ * \var UChar
+ * Define UChar to be wchar_t if that is 16 bits wide; always assumed to be unsigned.
+ * If wchar_t is not 16 bits wide, then define UChar to be uint16_t or char16_t because GCC >=4.4
+ * can handle UTF16 string literals.
+ * This makes the definition of UChar platform-dependent
+ * but allows direct string type compatibility with platforms with
+ * 16-bit wchar_t types.
+ *
+ * @draft ICU 4.4
+ */
+
+/* Define UChar to be compatible with wchar_t if possible. */
+#if U_SIZEOF_WCHAR_T==2
+    typedef wchar_t UChar;
+#elif U_GNUC_UTF16_STRING
+#if defined _GCC_
+    typedef __CHAR16_TYPE__ char16_t;
+#endif
+    typedef char16_t UChar;
+#else
+    typedef uint16_t UChar;
+#endif
+
+/**
+ * Define UChar32 as a type for single Unicode code points.
+ * UChar32 is a signed 32-bit integer (same as int32_t).
+ *
+ * The Unicode code point range is 0..0x10ffff.
+ * All other values (negative or >=0x110000) are illegal as Unicode code points.
+ * They may be used as sentinel values to indicate "done", "error"
+ * or similar non-code point conditions.
+ *
+ * Before ICU 2.4 (Jitterbug 2146), UChar32 was defined
+ * to be wchar_t if that is 32 bits wide (wchar_t may be signed or unsigned)
+ * or else to be uint32_t.
+ * That is, the definition of UChar32 was platform-dependent.
+ *
+ * @see U_SENTINEL
+ * @stable ICU 2.4
+ */
+typedef int32_t UChar32;
+
+/*==========================================================================*/
+/* U_INLINE and U_ALIGN_CODE   Set default values if these are not already  */
+/*                             defined.  Definitions normally are in        */
+/*                             platform.h or the corresponding file for     */
+/*                             the OS in use.                               */
+/*==========================================================================*/
+
+#ifndef U_HIDE_INTERNAL_API
+
+/**
+ * \def U_ALIGN_CODE
+ * This is used to align code fragments to a specific byte boundary.
+ * This is useful for getting consistent performance test results.
+ * @internal
+ */
+#ifndef U_ALIGN_CODE
+#   define U_ALIGN_CODE(n)
+#endif
+
+#endif /* U_HIDE_INTERNAL_API */
+
+/**
+ * \def U_INLINE
+ * This is used to request inlining of a function, on platforms and languages which support it.
+ */
+ 
+#ifndef U_INLINE
+#   ifdef XP_CPLUSPLUS
+#       define U_INLINE inline
+#   else
+#       define U_INLINE
+#   endif
+#endif
+
+#include "unicode/urename.h"
+
+#endif
diff --git a/source/common/unicode/umisc.h b/source/common/unicode/umisc.h
new file mode 100644
index 0000000..d85451f
--- /dev/null
+++ b/source/common/unicode/umisc.h
@@ -0,0 +1,60 @@
+/*
+**********************************************************************
+*   Copyright (C) 1999-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   file name:  umisc.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999oct15
+*   created by: Markus W. Scherer
+*/
+
+#ifndef UMISC_H
+#define UMISC_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief  C API:misc definitions 
+ *
+ *  This file contains miscellaneous definitions for the C APIs. 
+ */
+
+U_CDECL_BEGIN
+
+/** A struct representing a range of text containing a specific field 
+ *  @stable ICU 2.0
+ */
+typedef struct UFieldPosition {
+  /**
+   * The field 
+   * @stable ICU 2.0
+   */
+  int32_t field;
+  /**
+   * The start of the text range containing field 
+   * @stable ICU 2.0
+   */
+  int32_t beginIndex;
+  /** 
+   * The limit of the text range containing field 
+   * @stable ICU 2.0
+   */
+  int32_t endIndex;
+} UFieldPosition;
+
+#if !UCONFIG_NO_SERVICE
+/**
+ * Opaque type returned by registerInstance, registerFactory and unregister for service registration.
+ * @stable ICU 2.6
+ */
+typedef const void* URegistryKey;
+#endif
+
+U_CDECL_END
+
+#endif
diff --git a/source/common/unicode/unifilt.h b/source/common/unicode/unifilt.h
new file mode 100644
index 0000000..ce952af
--- /dev/null
+++ b/source/common/unicode/unifilt.h
@@ -0,0 +1,120 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2010, International Business Machines Corporation and others.
+* All Rights Reserved.
+**********************************************************************
+*   Date        Name        Description
+*   11/17/99    aliu        Creation.
+**********************************************************************
+*/
+#ifndef UNIFILT_H
+#define UNIFILT_H
+
+#include "unicode/unifunct.h"
+#include "unicode/unimatch.h"
+
+/**
+ * \file 
+ * \brief C++ API: Unicode Filter
+ */
+
+U_NAMESPACE_BEGIN
+
+/**
+ * U_ETHER is used to represent character values for positions outside
+ * a range.  For example, transliterator uses this to represent
+ * characters outside the range contextStart..contextLimit-1.  This
+ * allows explicit matching by rules and UnicodeSets of text outside a
+ * defined range.
+ * @stable ICU 3.0
+ */
+#define U_ETHER ((UChar)0xFFFF)
+
+/**
+ *
+ * <code>UnicodeFilter</code> defines a protocol for selecting a
+ * subset of the full range (U+0000 to U+10FFFF) of Unicode characters.
+ * Currently, filters are used in conjunction with classes like {@link
+ * Transliterator} to only process selected characters through a
+ * transformation.
+ *
+ * <p>Note: UnicodeFilter currently stubs out two pure virtual methods
+ * of its base class, UnicodeMatcher.  These methods are toPattern()
+ * and matchesIndexValue().  This is done so that filter classes that
+ * are not actually used as matchers -- specifically, those in the
+ * UnicodeFilterLogic component, and those in tests -- can continue to
+ * work without defining these methods.  As long as a filter is not
+ * used in an RBT during real transliteration, these methods will not
+ * be called.  However, this breaks the UnicodeMatcher base class
+ * protocol, and it is not a correct solution.
+ *
+ * <p>In the future we may revisit the UnicodeMatcher / UnicodeFilter
+ * hierarchy and either redesign it, or simply remove the stubs in
+ * UnicodeFilter and force subclasses to implement the full
+ * UnicodeMatcher protocol.
+ *
+ * @see UnicodeFilterLogic
+ * @stable ICU 2.0
+ */
+class U_COMMON_API UnicodeFilter : public UnicodeFunctor, public UnicodeMatcher {
+
+public:
+    /**
+     * Destructor
+     * @stable ICU 2.0
+     */
+    virtual ~UnicodeFilter();
+
+    /**
+     * Returns <tt>true</tt> for characters that are in the selected
+     * subset.  In other words, if a character is <b>to be
+     * filtered</b>, then <tt>contains()</tt> returns
+     * <b><tt>false</tt></b>.
+     * @stable ICU 2.0
+     */
+    virtual UBool contains(UChar32 c) const = 0;
+
+    /**
+     * UnicodeFunctor API.  Cast 'this' to a UnicodeMatcher* pointer
+     * and return the pointer.
+     * @stable ICU 2.4
+     */
+    virtual UnicodeMatcher* toMatcher() const;
+
+    /**
+     * Implement UnicodeMatcher API.
+     * @stable ICU 2.4
+     */
+    virtual UMatchDegree matches(const Replaceable& text,
+                                 int32_t& offset,
+                                 int32_t limit,
+                                 UBool incremental);
+
+    /**
+     * UnicodeFunctor API.  Nothing to do.
+     * @stable ICU 2.4
+     */
+    virtual void setData(const TransliterationRuleData*);
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.2
+     */
+    static UClassID U_EXPORT2 getStaticClassID();
+
+protected:
+
+    /*
+     * Since this class has pure virtual functions,
+     * a constructor can't be used.
+     * @stable ICU 2.0
+     */
+/*    UnicodeFilter();*/
+};
+
+/*inline UnicodeFilter::UnicodeFilter() {}*/
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/unicode/unifunct.h b/source/common/unicode/unifunct.h
new file mode 100644
index 0000000..3aa7b03
--- /dev/null
+++ b/source/common/unicode/unifunct.h
@@ -0,0 +1,125 @@
+/*
+**********************************************************************
+*   Copyright (c) 2002-2005, International Business Machines Corporation
+*   and others.  All Rights Reserved.
+**********************************************************************
+*   Date        Name        Description
+*   01/14/2002  aliu        Creation.
+**********************************************************************
+*/
+#ifndef UNIFUNCT_H
+#define UNIFUNCT_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+
+/**
+ * \file 
+ * \brief C++ API: Unicode Functor
+ */
+ 
+U_NAMESPACE_BEGIN
+
+class UnicodeMatcher;
+class UnicodeReplacer;
+class TransliterationRuleData;
+
+/**
+ * <code>UnicodeFunctor</code> is an abstract base class for objects
+ * that perform match and/or replace operations on Unicode strings.
+ * @author Alan Liu
+ * @stable ICU 2.4
+ */
+class U_COMMON_API UnicodeFunctor : public UObject {
+
+public:
+
+    /**
+     * Destructor
+     * @stable ICU 2.4
+     */
+    virtual ~UnicodeFunctor();
+
+    /**
+     * Return a copy of this object.  All UnicodeFunctor objects
+     * have to support cloning in order to allow classes using
+     * UnicodeFunctor to implement cloning.
+     * @stable ICU 2.4
+     */
+    virtual UnicodeFunctor* clone() const = 0;
+
+    /**
+     * Cast 'this' to a UnicodeMatcher* pointer and return the
+     * pointer, or null if this is not a UnicodeMatcher*.  Subclasses
+     * that mix in UnicodeMatcher as a base class must override this.
+     * This protocol is required because a pointer to a UnicodeFunctor
+     * cannot be cast to a pointer to a UnicodeMatcher, since
+     * UnicodeMatcher is a mixin that does not derive from
+     * UnicodeFunctor.
+     * @stable ICU 2.4
+     */
+    virtual UnicodeMatcher* toMatcher() const;
+
+    /**
+     * Cast 'this' to a UnicodeReplacer* pointer and return the
+     * pointer, or null if this is not a UnicodeReplacer*.  Subclasses
+     * that mix in UnicodeReplacer as a base class must override this.
+     * This protocol is required because a pointer to a UnicodeFunctor
+     * cannot be cast to a pointer to a UnicodeReplacer, since
+     * UnicodeReplacer is a mixin that does not derive from
+     * UnicodeFunctor.
+     * @stable ICU 2.4
+     */
+    virtual UnicodeReplacer* toReplacer() const;
+
+    /**
+     * 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 <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 UnicodeFunctor should use the macro
+     *    UOBJECT_DEFINE_RTTI_IMPLEMENTATION from uobject.h to
+     *    provide definitios getStaticClassID and getDynamicClassID.
+     *
+     * @return The class ID for this object. All objects of a given
+     * class have the same class ID.  Objects of other classes have
+     * different class IDs.
+     * @stable ICU 2.4
+     */
+    virtual UClassID getDynamicClassID(void) const = 0;
+
+    /**
+     * Set the data object associated with this functor.  The data
+     * object provides context for functor-to-standin mapping.  This
+     * method is required when assigning a functor to a different data
+     * object.  This function MAY GO AWAY later if the architecture is
+     * changed to pass data object pointers through the API.
+     * @internal ICU 2.1
+     */
+    virtual void setData(const TransliterationRuleData*) = 0;
+
+protected:
+
+    /**
+     * Since this class has pure virtual functions,
+     * a constructor can't be used.
+     * @stable ICU 2.0
+     */
+    /*UnicodeFunctor();*/
+
+};
+
+/*inline UnicodeFunctor::UnicodeFunctor() {}*/
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/unicode/unimatch.h b/source/common/unicode/unimatch.h
new file mode 100644
index 0000000..0dbb14e
--- /dev/null
+++ b/source/common/unicode/unimatch.h
@@ -0,0 +1,163 @@
+/*
+* Copyright (C) 2001-2005, International Business Machines Corporation and others. All Rights Reserved.
+**********************************************************************
+*   Date        Name        Description
+*   07/18/01    aliu        Creation.
+**********************************************************************
+*/
+#ifndef UNIMATCH_H
+#define UNIMATCH_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file 
+ * \brief C++ API: Unicode Matcher
+ */
+
+
+U_NAMESPACE_BEGIN
+
+class Replaceable;
+class UnicodeString;
+class UnicodeSet;
+
+/**
+ * Constants returned by <code>UnicodeMatcher::matches()</code>
+ * indicating the degree of match.
+ * @stable ICU 2.4
+ */
+enum UMatchDegree {
+    /**
+     * Constant returned by <code>matches()</code> indicating a
+     * mismatch between the text and this matcher.  The text contains
+     * a character which does not match, or the text does not contain
+     * all desired characters for a non-incremental match.
+     * @stable ICU 2.4
+     */
+    U_MISMATCH,
+    
+    /**
+     * Constant returned by <code>matches()</code> indicating a
+     * partial match between the text and this matcher.  This value is
+     * only returned for incremental match operations.  All characters
+     * of the text match, but more characters are required for a
+     * complete match.  Alternatively, for variable-length matchers,
+     * all characters of the text match, and if more characters were
+     * supplied at limit, they might also match.
+     * @stable ICU 2.4
+     */
+    U_PARTIAL_MATCH,
+    
+    /**
+     * Constant returned by <code>matches()</code> indicating a
+     * complete match between the text and this matcher.  For an
+     * incremental variable-length match, this value is returned if
+     * the given text matches, and it is known that additional
+     * characters would not alter the extent of the match.
+     * @stable ICU 2.4
+     */
+    U_MATCH
+};
+
+/**
+ * <code>UnicodeMatcher</code> defines a protocol for objects that can
+ * match a range of characters in a Replaceable string.
+ * @stable ICU 2.4
+ */
+class U_COMMON_API UnicodeMatcher /* not : public UObject because this is an interface/mixin class */ {
+
+public:
+    /**
+     * Destructor.
+     * @stable ICU 2.4
+     */
+    virtual ~UnicodeMatcher();
+
+    /**
+     * Return a UMatchDegree value indicating the degree of match for
+     * the given text at the given offset.  Zero, one, or more
+     * characters may be matched.
+     *
+     * Matching in the forward direction is indicated by limit >
+     * offset.  Characters from offset forwards to limit-1 will be
+     * considered for matching.
+     * 
+     * Matching in the reverse direction is indicated by limit <
+     * offset.  Characters from offset backwards to limit+1 will be
+     * considered for matching.
+     *
+     * If limit == offset then the only match possible is a zero
+     * character match (which subclasses may implement if desired).
+     *
+     * As a side effect, advance the offset parameter to the limit of
+     * the matched substring.  In the forward direction, this will be
+     * the index of the last matched character plus one.  In the
+     * reverse direction, this will be the index of the last matched
+     * character minus one.
+     *
+     * <p>Note:  This method is not const because some classes may
+     * modify their state as the result of a match.
+     *
+     * @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.
+     * @stable ICU 2.4
+     */
+    virtual UMatchDegree matches(const Replaceable& text,
+                                 int32_t& offset,
+                                 int32_t limit,
+                                 UBool incremental) = 0;
+
+    /**
+     * Returns a string representation of this matcher.  If the result of
+     * calling this function is passed to the appropriate parser, it
+     * will produce another matcher 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 those other than
+     * U+000A, U+0020..U+007E.
+     * @stable ICU 2.4
+     */
+    virtual UnicodeString& toPattern(UnicodeString& result,
+                                     UBool escapeUnprintable = FALSE) const = 0;
+
+    /**
+     * 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.
+     * @stable ICU 2.4
+     */
+    virtual UBool matchesIndexValue(uint8_t v) const = 0;
+
+    /**
+     * Union the set of all characters that may be matched by this object
+     * into the given set.
+     * @param toUnionTo the set into which to union the source characters
+     * @stable ICU 2.4
+     */
+    virtual void addMatchSetTo(UnicodeSet& toUnionTo) const = 0;
+};
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/unicode/uniset.h b/source/common/unicode/uniset.h
new file mode 100644
index 0000000..c5fe0ef
--- /dev/null
+++ b/source/common/unicode/uniset.h
@@ -0,0 +1,1673 @@
+/*
+***************************************************************************
+* Copyright (C) 1999-2010, International Business Machines Corporation
+* and others. All Rights Reserved.
+***************************************************************************
+*   Date        Name        Description
+*   10/20/99    alan        Creation.
+***************************************************************************
+*/
+
+#ifndef UNICODESET_H
+#define UNICODESET_H
+
+#include "unicode/unifilt.h"
+#include "unicode/unistr.h"
+#include "unicode/uset.h"
+
+/**
+ * \file
+ * \brief C++ API: Unicode Set
+ */
+
+U_NAMESPACE_BEGIN
+
+class BMPSet;
+class ParsePosition;
+class SymbolTable;
+class UnicodeSetStringSpan;
+class UVector;
+class RuleCharacterIterator;
+
+/**
+ * A mutable set of Unicode characters and multicharacter strings.  Objects of this class
+ * represent <em>character classes</em> used in regular expressions.
+ * A character specifies a subset of Unicode code points.  Legal
+ * code points are U+0000 to U+10FFFF, inclusive.
+ *
+ * <p>The UnicodeSet class is not designed to be subclassed.
+ *
+ * <p><code>UnicodeSet</code> supports two APIs. The first is the
+ * <em>operand</em> API that allows the caller to modify the value of
+ * a <code>UnicodeSet</code> object. It conforms to Java 2's
+ * <code>java.util.Set</code> interface, although
+ * <code>UnicodeSet</code> does not actually implement that
+ * interface. All methods of <code>Set</code> are supported, with the
+ * modification that they take a character range or single character
+ * instead of an <code>Object</code>, and they take a
+ * <code>UnicodeSet</code> instead of a <code>Collection</code>.  The
+ * operand API may be thought of in terms of boolean logic: a boolean
+ * OR is implemented by <code>add</code>, a boolean AND is implemented
+ * by <code>retain</code>, a boolean XOR is implemented by
+ * <code>complement</code> taking an argument, and a boolean NOT is
+ * implemented by <code>complement</code> with no argument.  In terms
+ * of traditional set theory function names, <code>add</code> is a
+ * union, <code>retain</code> is an intersection, <code>remove</code>
+ * is an asymmetric difference, and <code>complement</code> with no
+ * argument is a set complement with respect to the superset range
+ * <code>MIN_VALUE-MAX_VALUE</code>
+ *
+ * <p>The second API is the
+ * <code>applyPattern()</code>/<code>toPattern()</code> API from the
+ * <code>java.text.Format</code>-derived classes.  Unlike the
+ * methods that add characters, add categories, and control the logic
+ * of the set, the method <code>applyPattern()</code> sets all
+ * attributes of a <code>UnicodeSet</code> at once, based on a
+ * string pattern.
+ *
+ * <p><b>Pattern syntax</b></p>
+ *
+ * Patterns are accepted by the constructors and the
+ * <code>applyPattern()</code> methods and returned by the
+ * <code>toPattern()</code> method.  These patterns follow a syntax
+ * similar to that employed by version 8 regular expression character
+ * classes.  Here are some simple examples:
+ *
+ * \htmlonly<blockquote>\endhtmlonly
+ *   <table>
+ *     <tr align="top">
+ *       <td nowrap valign="top" align="left"><code>[]</code></td>
+ *       <td valign="top">No characters</td>
+ *     </tr><tr align="top">
+ *       <td nowrap valign="top" align="left"><code>[a]</code></td>
+ *       <td valign="top">The character 'a'</td>
+ *     </tr><tr align="top">
+ *       <td nowrap valign="top" align="left"><code>[ae]</code></td>
+ *       <td valign="top">The characters 'a' and 'e'</td>
+ *     </tr>
+ *     <tr>
+ *       <td nowrap valign="top" align="left"><code>[a-e]</code></td>
+ *       <td valign="top">The characters 'a' through 'e' inclusive, in Unicode code
+ *       point order</td>
+ *     </tr>
+ *     <tr>
+ *       <td nowrap valign="top" align="left"><code>[\\u4E01]</code></td>
+ *       <td valign="top">The character U+4E01</td>
+ *     </tr>
+ *     <tr>
+ *       <td nowrap valign="top" align="left"><code>[a{ab}{ac}]</code></td>
+ *       <td valign="top">The character 'a' and the multicharacter strings &quot;ab&quot; and
+ *       &quot;ac&quot;</td>
+ *     </tr>
+ *     <tr>
+ *       <td nowrap valign="top" align="left"><code>[\\p{Lu}]</code></td>
+ *       <td valign="top">All characters in the general category Uppercase Letter</td>
+ *     </tr>
+ *   </table>
+ * \htmlonly</blockquote>\endhtmlonly
+ *
+ * Any character may be preceded by a backslash in order to remove any special
+ * meaning.  White space characters, as defined by UCharacter.isWhitespace(), are
+ * ignored, unless they are escaped.
+ *
+ * <p>Property patterns specify a set of characters having a certain
+ * property as defined by the Unicode standard.  Both the POSIX-like
+ * "[:Lu:]" and the Perl-like syntax "\\p{Lu}" are recognized.  For a
+ * complete list of supported property patterns, see the User's Guide
+ * for UnicodeSet at
+ * <a href="http://icu-project.org/userguide/unicodeSet.html">
+ * http://icu-project.org/userguide/unicodeSet.html</a>.
+ * Actual determination of property data is defined by the underlying
+ * Unicode database as implemented by UCharacter.
+ *
+ * <p>Patterns specify individual characters, ranges of characters, and
+ * Unicode property sets.  When elements are concatenated, they
+ * specify their union.  To complement a set, place a '^' immediately
+ * after the opening '['.  Property patterns are inverted by modifying
+ * their delimiters; "[:^foo]" and "\\P{foo}".  In any other location,
+ * '^' has no special meaning.
+ *
+ * <p>Ranges are indicated by placing two a '-' between two
+ * characters, as in "a-z".  This specifies the range of all
+ * characters from the left to the right, in Unicode order.  If the
+ * left character is greater than or equal to the
+ * right character it is a syntax error.  If a '-' occurs as the first
+ * character after the opening '[' or '[^', or if it occurs as the
+ * last character before the closing ']', then it is taken as a
+ * literal.  Thus "[a\-b]", "[-ab]", and "[ab-]" all indicate the same
+ * set of three characters, 'a', 'b', and '-'.
+ *
+ * <p>Sets may be intersected using the '&' operator or the asymmetric
+ * set difference may be taken using the '-' operator, for example,
+ * "[[:L:]&[\\u0000-\\u0FFF]]" indicates the set of all Unicode letters
+ * with values less than 4096.  Operators ('&' and '|') have equal
+ * precedence and bind left-to-right.  Thus
+ * "[[:L:]-[a-z]-[\\u0100-\\u01FF]]" is equivalent to
+ * "[[[:L:]-[a-z]]-[\\u0100-\\u01FF]]".  This only really matters for
+ * difference; intersection is commutative.
+ *
+ * <table>
+ * <tr valign=top><td nowrap><code>[a]</code><td>The set containing 'a'
+ * <tr valign=top><td nowrap><code>[a-z]</code><td>The set containing 'a'
+ * through 'z' and all letters in between, in Unicode order
+ * <tr valign=top><td nowrap><code>[^a-z]</code><td>The set containing
+ * all characters but 'a' through 'z',
+ * that is, U+0000 through 'a'-1 and 'z'+1 through U+10FFFF
+ * <tr valign=top><td nowrap><code>[[<em>pat1</em>][<em>pat2</em>]]</code>
+ * <td>The union of sets specified by <em>pat1</em> and <em>pat2</em>
+ * <tr valign=top><td nowrap><code>[[<em>pat1</em>]&[<em>pat2</em>]]</code>
+ * <td>The intersection of sets specified by <em>pat1</em> and <em>pat2</em>
+ * <tr valign=top><td nowrap><code>[[<em>pat1</em>]-[<em>pat2</em>]]</code>
+ * <td>The asymmetric difference of sets specified by <em>pat1</em> and
+ * <em>pat2</em>
+ * <tr valign=top><td nowrap><code>[:Lu:] or \\p{Lu}</code>
+ * <td>The set of characters having the specified
+ * Unicode property; in
+ * this case, Unicode uppercase letters
+ * <tr valign=top><td nowrap><code>[:^Lu:] or \\P{Lu}</code>
+ * <td>The set of characters <em>not</em> having the given
+ * Unicode property
+ * </table>
+ *
+ * <p><b>Warning</b>: you cannot add an empty string ("") to a UnicodeSet.</p>
+ *
+ * <p><b>Formal syntax</b></p>
+ *
+ * \htmlonly<blockquote>\endhtmlonly
+ *   <table>
+ *     <tr align="top">
+ *       <td nowrap valign="top" align="right"><code>pattern :=&nbsp; </code></td>
+ *       <td valign="top"><code>('[' '^'? item* ']') |
+ *       property</code></td>
+ *     </tr>
+ *     <tr align="top">
+ *       <td nowrap valign="top" align="right"><code>item :=&nbsp; </code></td>
+ *       <td valign="top"><code>char | (char '-' char) | pattern-expr<br>
+ *       </code></td>
+ *     </tr>
+ *     <tr align="top">
+ *       <td nowrap valign="top" align="right"><code>pattern-expr :=&nbsp; </code></td>
+ *       <td valign="top"><code>pattern | pattern-expr pattern |
+ *       pattern-expr op pattern<br>
+ *       </code></td>
+ *     </tr>
+ *     <tr align="top">
+ *       <td nowrap valign="top" align="right"><code>op :=&nbsp; </code></td>
+ *       <td valign="top"><code>'&amp;' | '-'<br>
+ *       </code></td>
+ *     </tr>
+ *     <tr align="top">
+ *       <td nowrap valign="top" align="right"><code>special :=&nbsp; </code></td>
+ *       <td valign="top"><code>'[' | ']' | '-'<br>
+ *       </code></td>
+ *     </tr>
+ *     <tr align="top">
+ *       <td nowrap valign="top" align="right"><code>char :=&nbsp; </code></td>
+ *       <td valign="top"><em>any character that is not</em><code> special<br>
+ *       | ('\' </code><em>any character</em><code>)<br>
+ *       | ('\\u' hex hex hex hex)<br>
+ *       </code></td>
+ *     </tr>
+ *     <tr align="top">
+ *       <td nowrap valign="top" align="right"><code>hex :=&nbsp; </code></td>
+ *       <td valign="top"><em>any character for which
+ *       </em><code>Character.digit(c, 16)</code><em>
+ *       returns a non-negative result</em></td>
+ *     </tr>
+ *     <tr>
+ *       <td nowrap valign="top" align="right"><code>property :=&nbsp; </code></td>
+ *       <td valign="top"><em>a Unicode property set pattern</em></td>
+ *     </tr>
+ *   </table>
+ *   <br>
+ *   <table border="1">
+ *     <tr>
+ *       <td>Legend: <table>
+ *         <tr>
+ *           <td nowrap valign="top"><code>a := b</code></td>
+ *           <td width="20" valign="top">&nbsp; </td>
+ *           <td valign="top"><code>a</code> may be replaced by <code>b</code> </td>
+ *         </tr>
+ *         <tr>
+ *           <td nowrap valign="top"><code>a?</code></td>
+ *           <td valign="top"></td>
+ *           <td valign="top">zero or one instance of <code>a</code><br>
+ *           </td>
+ *         </tr>
+ *         <tr>
+ *           <td nowrap valign="top"><code>a*</code></td>
+ *           <td valign="top"></td>
+ *           <td valign="top">one or more instances of <code>a</code><br>
+ *           </td>
+ *         </tr>
+ *         <tr>
+ *           <td nowrap valign="top"><code>a | b</code></td>
+ *           <td valign="top"></td>
+ *           <td valign="top">either <code>a</code> or <code>b</code><br>
+ *           </td>
+ *         </tr>
+ *         <tr>
+ *           <td nowrap valign="top"><code>'a'</code></td>
+ *           <td valign="top"></td>
+ *           <td valign="top">the literal string between the quotes </td>
+ *         </tr>
+ *       </table>
+ *       </td>
+ *     </tr>
+ *   </table>
+ * \htmlonly</blockquote>\endhtmlonly
+ * 
+ * <p>Note:
+ *  - Most UnicodeSet methods do not take a UErrorCode parameter because
+ *   there are usually very few opportunities for failure other than a shortage
+ *   of memory, error codes in low-level C++ string methods would be inconvenient,
+ *   and the error code as the last parameter (ICU convention) would prevent
+ *   the use of default parameter values.
+ *   Instead, such methods set the UnicodeSet into a "bogus" state
+ *   (see isBogus()) if an error occurs.
+ *
+ * @author Alan Liu
+ * @stable ICU 2.0
+ */
+class U_COMMON_API UnicodeSet : public UnicodeFilter {
+
+    int32_t len; // length of list used; 0 <= len <= capacity
+    int32_t capacity; // capacity of list
+    UChar32* list; // MUST be terminated with HIGH
+    BMPSet *bmpSet; // The set is frozen iff either bmpSet or stringSpan is not NULL.
+    UChar32* buffer; // internal buffer, may be NULL
+    int32_t bufferCapacity; // capacity of buffer
+    int32_t patLen;
+
+    /**
+     * The pattern representation of this set.  This may not be the
+     * most economical pattern.  It is the pattern supplied to
+     * applyPattern(), with variables substituted and whitespace
+     * removed.  For sets constructed without applyPattern(), or
+     * modified using the non-pattern API, this string will be empty,
+     * indicating that toPattern() must generate a pattern
+     * representation from the inversion list.
+     */
+    UChar *pat;
+    UVector* strings; // maintained in sorted order
+    UnicodeSetStringSpan *stringSpan;
+
+private:
+    enum { // constants
+        kIsBogus = 1       // This set is bogus (i.e. not valid)
+    };
+    uint8_t fFlags;         // Bit flag (see constants above)
+public:
+    /**
+     * Determine if this object contains a valid set.
+     * A bogus set has no value. It is different from an empty set.
+     * It can be used to indicate that no set value is available.
+     *
+     * @return TRUE if the set is valid, FALSE otherwise
+     * @see setToBogus()
+     * @stable ICU 4.0
+     */
+    inline UBool isBogus(void) const;
+    
+    /**
+     * Make this UnicodeSet object invalid.
+     * The string will test TRUE with isBogus().
+     *
+     * A bogus set has no value. It is different from an empty set.
+     * It can be used to indicate that no set value is available.
+     *
+     * This utility function is used throughout the UnicodeSet
+     * implementation to indicate that a UnicodeSet operation failed,
+     * and may be used in other functions,
+     * especially but not exclusively when such functions do not
+     * take a UErrorCode for simplicity.
+     *
+     * @see isBogus()
+     * @stable ICU 4.0
+     */
+    void setToBogus();
+
+public:
+
+    enum {
+        /**
+         * Minimum value that can be stored in a UnicodeSet.
+         * @stable ICU 2.4
+         */
+        MIN_VALUE = 0,
+
+        /**
+         * Maximum value that can be stored in a UnicodeSet.
+         * @stable ICU 2.4
+         */
+        MAX_VALUE = 0x10ffff
+    };
+
+    //----------------------------------------------------------------
+    // Constructors &c
+    //----------------------------------------------------------------
+
+public:
+
+    /**
+     * Constructs an empty set.
+     * @stable ICU 2.0
+     */
+    UnicodeSet();
+
+    /**
+     * Constructs a set containing the given range. If <code>end >
+     * start</code> then an empty set is created.
+     *
+     * @param start first character, inclusive, of range
+     * @param end last character, inclusive, of range
+     * @stable ICU 2.4
+     */
+    UnicodeSet(UChar32 start, UChar32 end);
+
+    /**
+     * Constructs a set from the given pattern.  See the class
+     * description for the syntax of the pattern language.
+     * @param pattern a string specifying what characters are in the set
+     * @param status returns <code>U_ILLEGAL_ARGUMENT_ERROR</code> if the pattern
+     * contains a syntax error.
+     * @stable ICU 2.0
+     */
+    UnicodeSet(const UnicodeString& pattern,
+               UErrorCode& status);
+
+    /**
+     * Constructs a set from the given pattern.  See the class
+     * description for the syntax of the pattern language.
+     * @param pattern a string specifying what characters are in the set
+     * @param options bitmask for options to apply to the pattern.
+     * Valid options are USET_IGNORE_SPACE and USET_CASE_INSENSITIVE.
+     * @param symbols a symbol table mapping variable names to values
+     * and stand-in characters to UnicodeSets; may be NULL
+     * @param status returns <code>U_ILLEGAL_ARGUMENT_ERROR</code> if the pattern
+     * contains a syntax error.
+     * @internal
+     */
+    UnicodeSet(const UnicodeString& pattern,
+               uint32_t options,
+               const SymbolTable* symbols,
+               UErrorCode& status);
+
+    /**
+     * Constructs a set from the given pattern.  See the class description
+     * for the syntax of the pattern language.
+     * @param pattern a string specifying what characters are in the set
+     * @param pos on input, the position in pattern at which to start parsing.
+     * On output, the position after the last character parsed.
+     * @param options bitmask for options to apply to the pattern.
+     * Valid options are USET_IGNORE_SPACE and USET_CASE_INSENSITIVE.
+     * @param symbols a symbol table mapping variable names to values
+     * and stand-in characters to UnicodeSets; may be NULL
+     * @param status input-output error code
+     * @stable ICU 2.8
+     */
+    UnicodeSet(const UnicodeString& pattern, ParsePosition& pos,
+               uint32_t options,
+               const SymbolTable* symbols,
+               UErrorCode& status);
+
+    /**
+     * Constructs a set that is identical to the given UnicodeSet.
+     * @stable ICU 2.0
+     */
+    UnicodeSet(const UnicodeSet& o);
+
+    /**
+     * Destructs the set.
+     * @stable ICU 2.0
+     */
+    virtual ~UnicodeSet();
+
+    /**
+     * Assigns this object to be a copy of another.
+     * A frozen set will not be modified.
+     * @stable ICU 2.0
+     */
+    UnicodeSet& operator=(const UnicodeSet& o);
+
+    /**
+     * Compares the specified object with this set for equality.  Returns
+     * <tt>true</tt> if the two sets
+     * have the same size, and every member of the specified set is
+     * contained in this set (or equivalently, every member of this set is
+     * contained in the specified set).
+     *
+     * @param o set to be compared for equality with this set.
+     * @return <tt>true</tt> if the specified set is equal to this set.
+     * @stable ICU 2.0
+     */
+    virtual UBool operator==(const UnicodeSet& o) const;
+
+    /**
+     * Compares the specified object with this set for equality.  Returns
+     * <tt>true</tt> if the specified set is not equal to this set.
+     * @stable ICU 2.0
+     */
+    UBool operator!=(const UnicodeSet& o) const;
+
+    /**
+     * Returns a copy of this object.  All UnicodeFunctor objects have
+     * to support cloning in order to allow classes using
+     * UnicodeFunctors, such as Transliterator, to implement cloning.
+     * If this set is frozen, then the clone will be frozen as well.
+     * Use cloneAsThawed() for a mutable clone of a frozen set.
+     * @see cloneAsThawed
+     * @stable ICU 2.0
+     */
+    virtual UnicodeFunctor* clone() const;
+
+    /**
+     * Returns the hash code value for this set.
+     *
+     * @return the hash code value for this set.
+     * @see Object#hashCode()
+     * @stable ICU 2.0
+     */
+    virtual int32_t hashCode(void) const;
+
+    /**
+     * Get a UnicodeSet pointer from a USet
+     *
+     * @param uset a USet (the ICU plain C type for UnicodeSet)
+     * @return the corresponding UnicodeSet pointer.
+     *
+     * @stable ICU 4.2
+     */
+    inline static UnicodeSet *fromUSet(USet *uset);
+
+    /**
+     * Get a UnicodeSet pointer from a const USet
+     *
+     * @param uset a const USet (the ICU plain C type for UnicodeSet)
+     * @return the corresponding UnicodeSet pointer.
+     *
+     * @stable ICU 4.2
+     */
+    inline static const UnicodeSet *fromUSet(const USet *uset);
+    
+    /**
+     * Produce a USet * pointer for this UnicodeSet.
+     * USet is the plain C type for UnicodeSet
+     *
+     * @return a USet pointer for this UnicodeSet
+     * @stable ICU 4.2
+     */
+    inline USet *toUSet();
+
+
+    /**
+     * Produce a const USet * pointer for this UnicodeSet.
+     * USet is the plain C type for UnicodeSet
+     *
+     * @return a const USet pointer for this UnicodeSet
+     * @stable ICU 4.2
+     */
+    inline const USet * toUSet() const;
+
+
+    //----------------------------------------------------------------
+    // Freezable API
+    //----------------------------------------------------------------
+
+    /**
+     * Determines whether the set has been frozen (made immutable) or not.
+     * See the ICU4J Freezable interface for details.
+     * @return TRUE/FALSE for whether the set has been frozen
+     * @see freeze
+     * @see cloneAsThawed
+     * @stable ICU 3.8
+     */
+    inline UBool isFrozen() const;
+
+    /**
+     * Freeze the set (make it immutable).
+     * Once frozen, it cannot be unfrozen and is therefore thread-safe
+     * until it is deleted.
+     * See the ICU4J Freezable interface for details.
+     * Freezing the set may also make some operations faster, for example
+     * contains() and span().
+     * A frozen set will not be modified. (It remains frozen.)
+     * @return this set.
+     * @see isFrozen
+     * @see cloneAsThawed
+     * @stable ICU 3.8
+     */
+    UnicodeFunctor *freeze();
+
+    /**
+     * Clone the set and make the clone mutable.
+     * See the ICU4J Freezable interface for details.
+     * @return the mutable clone
+     * @see freeze
+     * @see isFrozen
+     * @stable ICU 3.8
+     */
+    UnicodeFunctor *cloneAsThawed() const;
+
+    //----------------------------------------------------------------
+    // Public API
+    //----------------------------------------------------------------
+
+    /**
+     * Make this object represent the range <code>start - end</code>.
+     * If <code>end > start</code> then this object is set to an
+     * an empty range.
+     * A frozen set will not be modified.
+     *
+     * @param start first character in the set, inclusive
+     * @param end last character in the set, inclusive
+     * @stable ICU 2.4
+     */
+    UnicodeSet& set(UChar32 start, UChar32 end);
+
+    /**
+     * Return true if the given position, in the given pattern, appears
+     * to be the start of a UnicodeSet pattern.
+     * @stable ICU 2.4
+     */
+    static UBool resemblesPattern(const UnicodeString& pattern,
+                                  int32_t pos);
+
+    /**
+     * Modifies this set to represent the set specified by the given
+     * pattern, optionally ignoring white space.  See the class
+     * description for the syntax of the pattern language.
+     * A frozen set will not be modified.
+     * @param pattern a string specifying what characters are in the set
+     * @param status returns <code>U_ILLEGAL_ARGUMENT_ERROR</code> if the pattern
+     * contains a syntax error.
+     * <em> Empties the set passed before applying the pattern.</em>
+     * @return a reference to this
+     * @stable ICU 2.0
+     */
+    UnicodeSet& applyPattern(const UnicodeString& pattern,
+                             UErrorCode& status);
+
+    /**
+     * Modifies this set to represent the set specified by the given
+     * pattern, optionally ignoring white space.  See the class
+     * description for the syntax of the pattern language.
+     * A frozen set will not be modified.
+     * @param pattern a string specifying what characters are in the set
+     * @param options bitmask for options to apply to the pattern.
+     * Valid options are USET_IGNORE_SPACE and USET_CASE_INSENSITIVE.
+     * @param symbols a symbol table mapping variable names to
+     * values and stand-ins to UnicodeSets; may be NULL
+     * @param status returns <code>U_ILLEGAL_ARGUMENT_ERROR</code> if the pattern
+     * contains a syntax error.
+     *<em> Empties the set passed before applying the pattern.</em>
+     * @return a reference to this
+     * @internal
+     */
+    UnicodeSet& applyPattern(const UnicodeString& pattern,
+                             uint32_t options,
+                             const SymbolTable* symbols,
+                             UErrorCode& status);
+
+    /**
+     * Parses the given pattern, starting at the given position.  The
+     * character at pattern.charAt(pos.getIndex()) must be '[', or the
+     * parse fails.  Parsing continues until the corresponding closing
+     * ']'.  If a syntax error is encountered between the opening and
+     * closing brace, the parse fails.  Upon return from a successful
+     * parse, the ParsePosition is updated to point to the character
+     * following the closing ']', and a StringBuffer containing a
+     * pairs list for the parsed pattern is returned.  This method calls
+     * itself recursively to parse embedded subpatterns.
+     *<em> Empties the set passed before applying the pattern.</em>
+     * A frozen set will not be modified.
+     *
+     * @param pattern the string containing the pattern to be parsed.
+     * The portion of the string from pos.getIndex(), which must be a
+     * '[', to the corresponding closing ']', is parsed.
+     * @param pos upon entry, the position at which to being parsing.
+     * The character at pattern.charAt(pos.getIndex()) must be a '['.
+     * Upon return from a successful parse, pos.getIndex() is either
+     * the character after the closing ']' of the parsed pattern, or
+     * pattern.length() if the closing ']' is the last character of
+     * the pattern string.
+     * @param options bitmask for options to apply to the pattern.
+     * Valid options are USET_IGNORE_SPACE and USET_CASE_INSENSITIVE.
+     * @param symbols a symbol table mapping variable names to
+     * values and stand-ins to UnicodeSets; may be NULL
+     * @param status returns <code>U_ILLEGAL_ARGUMENT_ERROR</code> if the pattern
+     * contains a syntax error.
+     * @return a reference to this
+     * @stable ICU 2.8
+     */
+    UnicodeSet& applyPattern(const UnicodeString& pattern,
+                             ParsePosition& pos,
+                             uint32_t options,
+                             const SymbolTable* symbols,
+                             UErrorCode& status);
+
+    /**
+     * Returns a string representation of this set.  If the result of
+     * calling this function is passed to a UnicodeSet constructor, it
+     * will produce another set that is equal to this one.
+     * A frozen set will not be modified.
+     * @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& toPattern(UnicodeString& result,
+                             UBool escapeUnprintable = FALSE) const;
+
+    /**
+     * Modifies this set to contain those code points which have the given value
+     * for the given binary or enumerated property, as returned by
+     * u_getIntPropertyValue.  Prior contents of this set are lost.
+     * A frozen set will not be modified.
+     *
+     * @param prop a property in the range UCHAR_BIN_START..UCHAR_BIN_LIMIT-1
+     * or UCHAR_INT_START..UCHAR_INT_LIMIT-1
+     * or UCHAR_MASK_START..UCHAR_MASK_LIMIT-1.
+     *
+     * @param value a value in the range u_getIntPropertyMinValue(prop)..
+     * u_getIntPropertyMaxValue(prop), with one exception.  If prop is
+     * UCHAR_GENERAL_CATEGORY_MASK, then value should not be a UCharCategory, but
+     * rather a mask value produced by U_GET_GC_MASK().  This allows grouped
+     * categories such as [:L:] to be represented.
+     *
+     * @param ec error code input/output parameter
+     *
+     * @return a reference to this set
+     *
+     * @stable ICU 2.4
+     */
+    UnicodeSet& applyIntPropertyValue(UProperty prop,
+                                      int32_t value,
+                                      UErrorCode& ec);
+
+    /**
+     * Modifies this set to contain those code points which have the
+     * given value for the given property.  Prior contents of this
+     * set are lost.
+     * A frozen set will not be modified.
+     *
+     * @param prop a property alias, either short or long.  The name is matched
+     * loosely.  See PropertyAliases.txt for names and a description of loose
+     * matching.  If the value string is empty, then this string is interpreted
+     * as either a General_Category value alias, a Script value alias, a binary
+     * property alias, or a special ID.  Special IDs are matched loosely and
+     * correspond to the following sets:
+     *
+     * "ANY" = [\\u0000-\\U0010FFFF],
+     * "ASCII" = [\\u0000-\\u007F],
+     * "Assigned" = [:^Cn:].
+     *
+     * @param value a value alias, either short or long.  The name is matched
+     * loosely.  See PropertyValueAliases.txt for names and a description of
+     * loose matching.  In addition to aliases listed, numeric values and
+     * canonical combining classes may be expressed numerically, e.g., ("nv",
+     * "0.5") or ("ccc", "220").  The value string may also be empty.
+     *
+     * @param ec error code input/output parameter
+     *
+     * @return a reference to this set
+     *
+     * @stable ICU 2.4
+     */
+    UnicodeSet& applyPropertyAlias(const UnicodeString& prop,
+                                   const UnicodeString& value,
+                                   UErrorCode& ec);
+
+    /**
+     * Returns the number of elements in this set (its cardinality).
+     * Note than the elements of a set may include both individual
+     * codepoints and strings.
+     *
+     * @return the number of elements in this set (its cardinality).
+     * @stable ICU 2.0
+     */
+    virtual int32_t size(void) const;
+
+    /**
+     * Returns <tt>true</tt> if this set contains no elements.
+     *
+     * @return <tt>true</tt> if this set contains no elements.
+     * @stable ICU 2.0
+     */
+    virtual UBool isEmpty(void) const;
+
+    /**
+     * Returns true if this set contains the given character.
+     * This function works faster with a frozen set.
+     * @param c character to be checked for containment
+     * @return true if the test condition is met
+     * @stable ICU 2.0
+     */
+    virtual UBool contains(UChar32 c) const;
+
+    /**
+     * Returns true if this set contains every character
+     * of the given range.
+     * @param start first character, inclusive, of the range
+     * @param end last character, inclusive, of the range
+     * @return true if the test condition is met
+     * @stable ICU 2.0
+     */
+    virtual UBool contains(UChar32 start, UChar32 end) const;
+
+    /**
+     * Returns <tt>true</tt> if this set contains the given
+     * multicharacter string.
+     * @param s string to be checked for containment
+     * @return <tt>true</tt> if this set contains the specified string
+     * @stable ICU 2.4
+     */
+    UBool contains(const UnicodeString& s) const;
+
+    /**
+     * Returns true if this set contains all the characters and strings
+     * of the given set.
+     * @param c set to be checked for containment
+     * @return true if the test condition is met
+     * @stable ICU 2.4
+     */
+    virtual UBool containsAll(const UnicodeSet& c) const;
+
+    /**
+     * Returns true if this set contains all the characters
+     * of the given string.
+     * @param s string containing characters to be checked for containment
+     * @return true if the test condition is met
+     * @stable ICU 2.4
+     */
+    UBool containsAll(const UnicodeString& s) const;
+
+    /**
+     * Returns true if this set contains none of the characters
+     * of the given range.
+     * @param start first character, inclusive, of the range
+     * @param end last character, inclusive, of the range
+     * @return true if the test condition is met
+     * @stable ICU 2.4
+     */
+    UBool containsNone(UChar32 start, UChar32 end) const;
+
+    /**
+     * Returns true if this set contains none of the characters and strings
+     * of the given set.
+     * @param c set to be checked for containment
+     * @return true if the test condition is met
+     * @stable ICU 2.4
+     */
+    UBool containsNone(const UnicodeSet& c) const;
+
+    /**
+     * Returns true if this set contains none of the characters
+     * of the given string.
+     * @param s string containing characters to be checked for containment
+     * @return true if the test condition is met
+     * @stable ICU 2.4
+     */
+    UBool containsNone(const UnicodeString& s) const;
+
+    /**
+     * Returns true if this set contains one or more of the characters
+     * in the given range.
+     * @param start first character, inclusive, of the range
+     * @param end last character, inclusive, of the range
+     * @return true if the condition is met
+     * @stable ICU 2.4
+     */
+    inline UBool containsSome(UChar32 start, UChar32 end) const;
+
+    /**
+     * Returns true if this set contains one or more of the characters
+     * and strings of the given set.
+     * @param s The set to be checked for containment
+     * @return true if the condition is met
+     * @stable ICU 2.4
+     */
+    inline UBool containsSome(const UnicodeSet& s) const;
+
+    /**
+     * Returns true if this set contains one or more of the characters
+     * of the given string.
+     * @param s string containing characters to be checked for containment
+     * @return true if the condition is met
+     * @stable ICU 2.4
+     */
+    inline UBool containsSome(const UnicodeString& s) const;
+
+    /**
+     * Returns the length of the initial substring of the input string which
+     * consists only of characters and strings that are contained in this set
+     * (USET_SPAN_CONTAINED, USET_SPAN_SIMPLE),
+     * or only of characters and strings that are not contained
+     * in this set (USET_SPAN_NOT_CONTAINED).
+     * See USetSpanCondition for details.
+     * Similar to the strspn() C library function.
+     * Unpaired surrogates are treated according to contains() of their surrogate code points.
+     * This function works faster with a frozen set and with a non-negative string length argument.
+     * @param s start of the string
+     * @param length of the string; can be -1 for NUL-terminated
+     * @param spanCondition specifies the containment condition
+     * @return the length of the initial substring according to the spanCondition;
+     *         0 if the start of the string does not fit the spanCondition
+     * @stable ICU 3.8
+     * @see USetSpanCondition
+     */
+    int32_t span(const UChar *s, int32_t length, USetSpanCondition spanCondition) const;
+
+    /**
+     * Returns the end of the substring of the input string according to the USetSpanCondition.
+     * Same as <code>start+span(s.getBuffer()+start, s.length()-start, spanCondition)</code>
+     * after pinning start to 0<=start<=s.length().
+     * @param s the string
+     * @param start the start index in the string for the span operation
+     * @param spanCondition specifies the containment condition
+     * @return the exclusive end of the substring according to the spanCondition;
+     *         the substring s.tempSubStringBetween(start, end) fulfills the spanCondition
+     * @stable ICU 4.4
+     * @see USetSpanCondition
+     */
+    inline int32_t span(const UnicodeString &s, int32_t start, USetSpanCondition spanCondition) const;
+
+    /**
+     * Returns the start of the trailing substring of the input string which
+     * consists only of characters and strings that are contained in this set
+     * (USET_SPAN_CONTAINED, USET_SPAN_SIMPLE),
+     * or only of characters and strings that are not contained
+     * in this set (USET_SPAN_NOT_CONTAINED).
+     * See USetSpanCondition for details.
+     * Unpaired surrogates are treated according to contains() of their surrogate code points.
+     * This function works faster with a frozen set and with a non-negative string length argument.
+     * @param s start of the string
+     * @param length of the string; can be -1 for NUL-terminated
+     * @param spanCondition specifies the containment condition
+     * @return the start of the trailing substring according to the spanCondition;
+     *         the string length if the end of the string does not fit the spanCondition
+     * @stable ICU 3.8
+     * @see USetSpanCondition
+     */
+    int32_t spanBack(const UChar *s, int32_t length, USetSpanCondition spanCondition) const;
+
+    /**
+     * Returns the start of the substring of the input string according to the USetSpanCondition.
+     * Same as <code>spanBack(s.getBuffer(), limit, spanCondition)</code>
+     * after pinning limit to 0<=end<=s.length().
+     * @param s the string
+     * @param limit the exclusive-end index in the string for the span operation
+     *              (use s.length() or INT32_MAX for spanning back from the end of the string)
+     * @param spanCondition specifies the containment condition
+     * @return the start of the substring according to the spanCondition;
+     *         the substring s.tempSubStringBetween(start, limit) fulfills the spanCondition
+     * @stable ICU 4.4
+     * @see USetSpanCondition
+     */
+    inline int32_t spanBack(const UnicodeString &s, int32_t limit, USetSpanCondition spanCondition) const;
+
+    /**
+     * Returns the length of the initial substring of the input string which
+     * consists only of characters and strings that are contained in this set
+     * (USET_SPAN_CONTAINED, USET_SPAN_SIMPLE),
+     * or only of characters and strings that are not contained
+     * in this set (USET_SPAN_NOT_CONTAINED).
+     * See USetSpanCondition for details.
+     * Similar to the strspn() C library function.
+     * Malformed byte sequences are treated according to contains(0xfffd).
+     * This function works faster with a frozen set and with a non-negative string length argument.
+     * @param s start of the string (UTF-8)
+     * @param length of the string; can be -1 for NUL-terminated
+     * @param spanCondition specifies the containment condition
+     * @return the length of the initial substring according to the spanCondition;
+     *         0 if the start of the string does not fit the spanCondition
+     * @stable ICU 3.8
+     * @see USetSpanCondition
+     */
+    int32_t spanUTF8(const char *s, int32_t length, USetSpanCondition spanCondition) const;
+
+    /**
+     * Returns the start of the trailing substring of the input string which
+     * consists only of characters and strings that are contained in this set
+     * (USET_SPAN_CONTAINED, USET_SPAN_SIMPLE),
+     * or only of characters and strings that are not contained
+     * in this set (USET_SPAN_NOT_CONTAINED).
+     * See USetSpanCondition for details.
+     * Malformed byte sequences are treated according to contains(0xfffd).
+     * This function works faster with a frozen set and with a non-negative string length argument.
+     * @param s start of the string (UTF-8)
+     * @param length of the string; can be -1 for NUL-terminated
+     * @param spanCondition specifies the containment condition
+     * @return the start of the trailing substring according to the spanCondition;
+     *         the string length if the end of the string does not fit the spanCondition
+     * @stable ICU 3.8
+     * @see USetSpanCondition
+     */
+    int32_t spanBackUTF8(const char *s, int32_t length, USetSpanCondition spanCondition) const;
+
+    /**
+     * Implement UnicodeMatcher::matches()
+     * @stable ICU 2.4
+     */
+    virtual UMatchDegree matches(const Replaceable& text,
+                         int32_t& offset,
+                         int32_t limit,
+                         UBool incremental);
+
+private:
+    /**
+     * Returns the longest match for s in text at the given position.
+     * If limit > start then match forward from start+1 to limit
+     * matching all characters except s.charAt(0).  If limit < start,
+     * go backward starting from start-1 matching all characters
+     * except s.charAt(s.length()-1).  This method assumes that the
+     * first character, text.charAt(start), matches s, so it does not
+     * check it.
+     * @param text the text to match
+     * @param start the first character to match.  In the forward
+     * direction, text.charAt(start) is matched against s.charAt(0).
+     * In the reverse direction, it is matched against
+     * s.charAt(s.length()-1).
+     * @param limit the limit offset for matching, either last+1 in
+     * the forward direction, or last-1 in the reverse direction,
+     * where last is the index of the last character to match.
+     * @return If part of s matches up to the limit, return |limit -
+     * start|.  If all of s matches before reaching the limit, return
+     * s.length().  If there is a mismatch between s and text, return
+     * 0
+     */
+    static int32_t matchRest(const Replaceable& text,
+                             int32_t start, int32_t limit,
+                             const UnicodeString& s);
+
+    /**
+     * Returns the smallest value i such that c < list[i].  Caller
+     * must ensure that c is a legal value or this method will enter
+     * an infinite loop.  This method performs a binary search.
+     * @param c a character in the range MIN_VALUE..MAX_VALUE
+     * inclusive
+     * @return the smallest integer i in the range 0..len-1,
+     * inclusive, such that c < list[i]
+     */
+    int32_t findCodePoint(UChar32 c) const;
+
+public:
+
+    /**
+     * Implementation of UnicodeMatcher API.  Union the set of all
+     * characters that may be matched by this object into the given
+     * set.
+     * @param toUnionTo the set into which to union the source characters
+     * @stable ICU 2.4
+     */
+    virtual void addMatchSetTo(UnicodeSet& toUnionTo) const;
+
+    /**
+     * Returns the index of the given character within this set, where
+     * the set is ordered by ascending code point.  If the character
+     * is not in this set, return -1.  The inverse of this method is
+     * <code>charAt()</code>.
+     * @return an index from 0..size()-1, or -1
+     * @stable ICU 2.4
+     */
+    int32_t indexOf(UChar32 c) const;
+
+    /**
+     * Returns the character at the given index within this set, where
+     * the set is ordered by ascending code point.  If the index is
+     * out of range, return (UChar32)-1.  The inverse of this method is
+     * <code>indexOf()</code>.
+     * @param index an index from 0..size()-1
+     * @return the character at the given index, or (UChar32)-1.
+     * @stable ICU 2.4
+     */
+    UChar32 charAt(int32_t index) const;
+
+    /**
+     * Adds the specified range to this set if it is not already
+     * present.  If this set already contains the specified range,
+     * the call leaves this set unchanged.  If <code>end > start</code>
+     * then an empty range is added, leaving the set unchanged.
+     * This is equivalent to a boolean logic OR, or a set UNION.
+     * A frozen set will not be modified.
+     *
+     * @param start first character, inclusive, of range to be added
+     * to this set.
+     * @param end last character, inclusive, of range to be added
+     * to this set.
+     * @stable ICU 2.0
+     */
+    virtual UnicodeSet& add(UChar32 start, UChar32 end);
+
+    /**
+     * Adds the specified character to this set if it is not already
+     * present.  If this set already contains the specified character,
+     * the call leaves this set unchanged.
+     * A frozen set will not be modified.
+     * @stable ICU 2.0
+     */
+    UnicodeSet& add(UChar32 c);
+
+    /**
+     * Adds the specified multicharacter to this set if it is not already
+     * present.  If this set already contains the multicharacter,
+     * the call leaves this set unchanged.
+     * Thus "ch" => {"ch"}
+     * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
+     * A frozen set will not be modified.
+     * @param s the source string
+     * @return this object, for chaining
+     * @stable ICU 2.4
+     */
+    UnicodeSet& add(const UnicodeString& s);
+
+ private:
+    /**
+     * @return a code point IF the string consists of a single one.
+     * otherwise returns -1.
+     * @param s string to test
+     */
+    static int32_t getSingleCP(const UnicodeString& s);
+
+    void _add(const UnicodeString& s);
+
+ public:
+    /**
+     * Adds each of the characters in this string to the set. Thus "ch" => {"c", "h"}
+     * If this set already any particular character, it has no effect on that character.
+     * A frozen set will not be modified.
+     * @param s the source string
+     * @return this object, for chaining
+     * @stable ICU 2.4
+     */
+    UnicodeSet& addAll(const UnicodeString& s);
+
+    /**
+     * Retains EACH of the characters in this string. Note: "ch" == {"c", "h"}
+     * If this set already any particular character, it has no effect on that character.
+     * A frozen set will not be modified.
+     * @param s the source string
+     * @return this object, for chaining
+     * @stable ICU 2.4
+     */
+    UnicodeSet& retainAll(const UnicodeString& s);
+
+    /**
+     * Complement EACH of the characters in this string. Note: "ch" == {"c", "h"}
+     * If this set already any particular character, it has no effect on that character.
+     * A frozen set will not be modified.
+     * @param s the source string
+     * @return this object, for chaining
+     * @stable ICU 2.4
+     */
+    UnicodeSet& complementAll(const UnicodeString& s);
+
+    /**
+     * Remove EACH of the characters in this string. Note: "ch" == {"c", "h"}
+     * If this set already any particular character, it has no effect on that character.
+     * A frozen set will not be modified.
+     * @param s the source string
+     * @return this object, for chaining
+     * @stable ICU 2.4
+     */
+    UnicodeSet& removeAll(const UnicodeString& s);
+
+    /**
+     * Makes a set from a multicharacter string. Thus "ch" => {"ch"}
+     * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
+     * @param s the source string
+     * @return a newly created set containing the given string.
+     * The caller owns the return object and is responsible for deleting it.
+     * @stable ICU 2.4
+     */
+    static UnicodeSet* U_EXPORT2 createFrom(const UnicodeString& s);
+
+
+    /**
+     * Makes a set from each of the characters in the string. Thus "ch" => {"c", "h"}
+     * @param s the source string
+     * @return a newly created set containing the given characters
+     * The caller owns the return object and is responsible for deleting it.
+     * @stable ICU 2.4
+     */
+    static UnicodeSet* U_EXPORT2 createFromAll(const UnicodeString& s);
+
+    /**
+     * Retain only the elements in this set that are contained in the
+     * specified range.  If <code>end > start</code> then an empty range is
+     * retained, leaving the set empty.  This is equivalent to
+     * a boolean logic AND, or a set INTERSECTION.
+     * A frozen set will not be modified.
+     *
+     * @param start first character, inclusive, of range to be retained
+     * to this set.
+     * @param end last character, inclusive, of range to be retained
+     * to this set.
+     * @stable ICU 2.0
+     */
+    virtual UnicodeSet& retain(UChar32 start, UChar32 end);
+
+
+    /**
+     * Retain the specified character from this set if it is present.
+     * A frozen set will not be modified.
+     * @stable ICU 2.0
+     */
+    UnicodeSet& retain(UChar32 c);
+
+    /**
+     * Removes the specified range from this set if it is present.
+     * The set will not contain the specified range once the call
+     * returns.  If <code>end > start</code> then an empty range is
+     * removed, leaving the set unchanged.
+     * A frozen set will not be modified.
+     *
+     * @param start first character, inclusive, of range to be removed
+     * from this set.
+     * @param end last character, inclusive, of range to be removed
+     * from this set.
+     * @stable ICU 2.0
+     */
+    virtual UnicodeSet& remove(UChar32 start, UChar32 end);
+
+    /**
+     * Removes the specified character from this set if it is present.
+     * The set will not contain the specified range once the call
+     * returns.
+     * A frozen set will not be modified.
+     * @stable ICU 2.0
+     */
+    UnicodeSet& remove(UChar32 c);
+
+    /**
+     * Removes the specified string from this set if it is present.
+     * The set will not contain the specified character once the call
+     * returns.
+     * A frozen set will not be modified.
+     * @param s the source string
+     * @return this object, for chaining
+     * @stable ICU 2.4
+     */
+    UnicodeSet& remove(const UnicodeString& s);
+
+    /**
+     * Inverts this set.  This operation modifies this set so that
+     * its value is its complement.  This is equivalent to
+     * <code>complement(MIN_VALUE, MAX_VALUE)</code>.
+     * A frozen set will not be modified.
+     * @stable ICU 2.0
+     */
+    virtual UnicodeSet& complement(void);
+
+    /**
+     * Complements the specified range in this set.  Any character in
+     * the range will be removed if it is in this set, or will be
+     * added if it is not in this set.  If <code>end > start</code>
+     * then an empty range is complemented, leaving the set unchanged.
+     * This is equivalent to a boolean logic XOR.
+     * A frozen set will not be modified.
+     *
+     * @param start first character, inclusive, of range to be removed
+     * from this set.
+     * @param end last character, inclusive, of range to be removed
+     * from this set.
+     * @stable ICU 2.0
+     */
+    virtual UnicodeSet& complement(UChar32 start, UChar32 end);
+
+    /**
+     * Complements the specified character in this set.  The character
+     * will be removed if it is in this set, or will be added if it is
+     * not in this set.
+     * A frozen set will not be modified.
+     * @stable ICU 2.0
+     */
+    UnicodeSet& complement(UChar32 c);
+
+    /**
+     * Complement the specified string in this set.
+     * The set will not contain the specified string once the call
+     * returns.
+     * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
+     * A frozen set will not be modified.
+     * @param s the string to complement
+     * @return this object, for chaining
+     * @stable ICU 2.4
+     */
+    UnicodeSet& complement(const UnicodeString& s);
+
+    /**
+     * Adds all of the elements in the specified set to this set if
+     * they're not already present.  This operation effectively
+     * modifies this set so that its value is the <i>union</i> of the two
+     * sets.  The behavior of this operation is unspecified if the specified
+     * collection is modified while the operation is in progress.
+     * A frozen set will not be modified.
+     *
+     * @param c set whose elements are to be added to this set.
+     * @see #add(UChar32, UChar32)
+     * @stable ICU 2.0
+     */
+    virtual UnicodeSet& addAll(const UnicodeSet& c);
+
+    /**
+     * Retains only the elements in this set that are contained in the
+     * specified set.  In other words, removes from this set all of
+     * its elements that are not contained in the specified set.  This
+     * operation effectively modifies this set so that its value is
+     * the <i>intersection</i> of the two sets.
+     * A frozen set will not be modified.
+     *
+     * @param c set that defines which elements this set will retain.
+     * @stable ICU 2.0
+     */
+    virtual UnicodeSet& retainAll(const UnicodeSet& c);
+
+    /**
+     * Removes from this set all of its elements that are contained in the
+     * specified set.  This operation effectively modifies this
+     * set so that its value is the <i>asymmetric set difference</i> of
+     * the two sets.
+     * A frozen set will not be modified.
+     *
+     * @param c set that defines which elements will be removed from
+     *          this set.
+     * @stable ICU 2.0
+     */
+    virtual UnicodeSet& removeAll(const UnicodeSet& c);
+
+    /**
+     * Complements in this set all elements contained in the specified
+     * set.  Any character in the other set will be removed if it is
+     * in this set, or will be added if it is not in this set.
+     * A frozen set will not be modified.
+     *
+     * @param c set that defines which elements will be xor'ed from
+     *          this set.
+     * @stable ICU 2.4
+     */
+    virtual UnicodeSet& complementAll(const UnicodeSet& c);
+
+    /**
+     * Removes all of the elements from this set.  This set will be
+     * empty after this call returns.
+     * A frozen set will not be modified.
+     * @stable ICU 2.0
+     */
+    virtual UnicodeSet& clear(void);
+
+    /**
+     * Close this set over the given attribute.  For the attribute
+     * USET_CASE, the result is to modify this set so that:
+     *
+     * 1. For each character or string 'a' in this set, all strings or
+     * characters 'b' such that foldCase(a) == foldCase(b) are added
+     * to this set.
+     *
+     * 2. For each string 'e' in the resulting set, if e !=
+     * foldCase(e), 'e' will be removed.
+     *
+     * Example: [aq\\u00DF{Bc}{bC}{Fi}] => [aAqQ\\u00DF\\uFB01{ss}{bc}{fi}]
+     *
+     * (Here foldCase(x) refers to the operation u_strFoldCase, and a
+     * == b denotes that the contents are the same, not pointer
+     * comparison.)
+     *
+     * A frozen set will not be modified.
+     *
+     * @param attribute bitmask for attributes to close over.
+     * Currently only the USET_CASE bit is supported.  Any undefined bits
+     * are ignored.
+     * @return a reference to this set.
+     * @stable ICU 4.2
+     */
+    UnicodeSet& closeOver(int32_t attribute);
+
+    /**
+     * Remove all strings from this set.
+     *
+     * @return a reference to this set.
+     * @stable ICU 4.2
+     */
+    virtual UnicodeSet &removeAllStrings();
+
+    /**
+     * Iteration method that returns the number of ranges contained in
+     * this set.
+     * @see #getRangeStart
+     * @see #getRangeEnd
+     * @stable ICU 2.4
+     */
+    virtual int32_t getRangeCount(void) const;
+
+    /**
+     * Iteration method that returns the first character in the
+     * specified range of this set.
+     * @see #getRangeCount
+     * @see #getRangeEnd
+     * @stable ICU 2.4
+     */
+    virtual UChar32 getRangeStart(int32_t index) const;
+
+    /**
+     * Iteration method that returns the last character in the
+     * specified range of this set.
+     * @see #getRangeStart
+     * @see #getRangeEnd
+     * @stable ICU 2.4
+     */
+    virtual UChar32 getRangeEnd(int32_t index) const;
+
+    /**
+     * Serializes this set into an array of 16-bit integers.  Serialization
+     * (currently) only records the characters in the set; multicharacter
+     * strings are ignored.
+     *
+     * The array has following format (each line is one 16-bit
+     * integer):
+     *
+     *  length     = (n+2*m) | (m!=0?0x8000:0)
+     *  bmpLength  = n; present if m!=0
+     *  bmp[0]
+     *  bmp[1]
+     *  ...
+     *  bmp[n-1]
+     *  supp-high[0]
+     *  supp-low[0]
+     *  supp-high[1]
+     *  supp-low[1]
+     *  ...
+     *  supp-high[m-1]
+     *  supp-low[m-1]
+     *
+     * The array starts with a header.  After the header are n bmp
+     * code points, then m supplementary code points.  Either n or m
+     * or both may be zero.  n+2*m is always <= 0x7FFF.
+     *
+     * If there are no supplementary characters (if m==0) then the
+     * header is one 16-bit integer, 'length', with value n.
+     *
+     * If there are supplementary characters (if m!=0) then the header
+     * is two 16-bit integers.  The first, 'length', has value
+     * (n+2*m)|0x8000.  The second, 'bmpLength', has value n.
+     *
+     * After the header the code points are stored in ascending order.
+     * Supplementary code points are stored as most significant 16
+     * bits followed by least significant 16 bits.
+     *
+     * @param dest pointer to buffer of destCapacity 16-bit integers.
+     * May be NULL only if destCapacity is zero.
+     * @param destCapacity size of dest, or zero.  Must not be negative.
+     * @param ec error code.  Will be set to U_INDEX_OUTOFBOUNDS_ERROR
+     * if n+2*m > 0x7FFF.  Will be set to U_BUFFER_OVERFLOW_ERROR if
+     * n+2*m+(m!=0?2:1) > destCapacity.
+     * @return the total length of the serialized format, including
+     * the header, that is, n+2*m+(m!=0?2:1), or 0 on error other
+     * than U_BUFFER_OVERFLOW_ERROR.
+     * @stable ICU 2.4
+     */
+    int32_t serialize(uint16_t *dest, int32_t destCapacity, UErrorCode& ec) const;
+
+    /**
+     * Reallocate this objects internal structures to take up the least
+     * possible space, without changing this object's value.
+     * A frozen set will not be modified.
+     * @stable ICU 2.4
+     */
+    virtual UnicodeSet& compact();
+
+    /**
+     * 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);
+
+    /**
+     * Implement UnicodeFunctor API.
+     *
+     * @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.4
+     */
+    virtual UClassID getDynamicClassID(void) const;
+
+private:
+
+    // Private API for the USet API
+
+    friend class USetAccess;
+
+    int32_t getStringCount() const;
+
+    const UnicodeString* getString(int32_t index) const;
+
+    //----------------------------------------------------------------
+    // RuleBasedTransliterator support
+    //----------------------------------------------------------------
+
+private:
+
+    /**
+     * Returns <tt>true</tt> if this set contains any character whose low byte
+     * is the given value.  This is used by <tt>RuleBasedTransliterator</tt> for
+     * indexing.
+     */
+    virtual UBool matchesIndexValue(uint8_t v) const;
+
+private:
+
+    //----------------------------------------------------------------
+    // Implementation: Clone as thawed (see ICU4J Freezable)
+    //----------------------------------------------------------------
+
+    UnicodeSet(const UnicodeSet& o, UBool /* asThawed */);
+
+    //----------------------------------------------------------------
+    // Implementation: Pattern parsing
+    //----------------------------------------------------------------
+
+    void applyPattern(RuleCharacterIterator& chars,
+                      const SymbolTable* symbols,
+                      UnicodeString& rebuiltPat,
+                      uint32_t options,
+                      UErrorCode& ec);
+
+    //----------------------------------------------------------------
+    // Implementation: Utility methods
+    //----------------------------------------------------------------
+
+    void ensureCapacity(int32_t newLen, UErrorCode& ec);
+
+    void ensureBufferCapacity(int32_t newLen, UErrorCode& ec);
+
+    void swapBuffers(void);
+
+    UBool allocateStrings(UErrorCode &status);
+
+    UnicodeString& _toPattern(UnicodeString& result,
+                              UBool escapeUnprintable) const;
+
+    UnicodeString& _generatePattern(UnicodeString& result,
+                                    UBool escapeUnprintable) const;
+
+    static void _appendToPat(UnicodeString& buf, const UnicodeString& s, UBool escapeUnprintable);
+
+    static void _appendToPat(UnicodeString& buf, UChar32 c, UBool escapeUnprintable);
+
+    //----------------------------------------------------------------
+    // Implementation: Fundamental operators
+    //----------------------------------------------------------------
+
+    void exclusiveOr(const UChar32* other, int32_t otherLen, int8_t polarity);
+
+    void add(const UChar32* other, int32_t otherLen, int8_t polarity);
+
+    void retain(const UChar32* other, int32_t otherLen, int8_t polarity);
+
+    /**
+     * Return true if the given position, in the given pattern, appears
+     * to be the start of a property set pattern [:foo:], \\p{foo}, or
+     * \\P{foo}, or \\N{name}.
+     */
+    static UBool resemblesPropertyPattern(const UnicodeString& pattern,
+                                          int32_t pos);
+
+    static UBool resemblesPropertyPattern(RuleCharacterIterator& chars,
+                                          int32_t iterOpts);
+
+    /**
+     * Parse the given property pattern at the given parse position
+     * and set this UnicodeSet to the result.
+     *
+     * The original design document is out of date, but still useful.
+     * Ignore the property and value names:
+     * http://source.icu-project.org/repos/icu/icuhtml/trunk/design/unicodeset_properties.html
+     *
+     * Recognized syntax:
+     *
+     * [:foo:] [:^foo:] - white space not allowed within "[:" or ":]"
+     * \\p{foo} \\P{foo}  - white space not allowed within "\\p" or "\\P"
+     * \\N{name}         - white space not allowed within "\\N"
+     *
+     * Other than the above restrictions, white space is ignored.  Case
+     * is ignored except in "\\p" and "\\P" and "\\N".  In 'name' leading
+     * and trailing space is deleted, and internal runs of whitespace
+     * are collapsed to a single space.
+     *
+     * We support binary properties, enumerated properties, and the
+     * following non-enumerated properties:
+     *
+     *  Numeric_Value
+     *  Name
+     *  Unicode_1_Name
+     *
+     * @param pattern the pattern string
+     * @param ppos on entry, the position at which to begin parsing.
+     * This should be one of the locations marked '^':
+     *
+     *   [:blah:]     \\p{blah}     \\P{blah}     \\N{name}
+     *   ^       %    ^       %    ^       %    ^       %
+     *
+     * On return, the position after the last character parsed, that is,
+     * the locations marked '%'.  If the parse fails, ppos is returned
+     * unchanged.
+     * @return a reference to this.
+     */
+    UnicodeSet& applyPropertyPattern(const UnicodeString& pattern,
+                                     ParsePosition& ppos,
+                                     UErrorCode &ec);
+
+    void applyPropertyPattern(RuleCharacterIterator& chars,
+                              UnicodeString& rebuiltPat,
+                              UErrorCode& ec);
+
+    static const UnicodeSet* getInclusions(int32_t src, UErrorCode &status);
+
+    /**
+     * A filter that returns TRUE if the given code point should be
+     * included in the UnicodeSet being constructed.
+     */
+    typedef UBool (*Filter)(UChar32 codePoint, void* context);
+
+    /**
+     * Given a filter, set this UnicodeSet to the code points
+     * contained by that filter.  The filter MUST be
+     * property-conformant.  That is, if it returns value v for one
+     * code point, then it must return v for all affiliated code
+     * points, as defined by the inclusions list.  See
+     * getInclusions().
+     * src is a UPropertySource value.
+     */
+    void applyFilter(Filter filter,
+                     void* context,
+                     int32_t src,
+                     UErrorCode &status);
+
+    /**
+     * Set the new pattern to cache.
+     */
+    void setPattern(const UnicodeString& newPat);
+    /**
+     * Release existing cached pattern.
+     */
+    void releasePattern();
+
+    friend class UnicodeSetIterator;
+};
+
+
+
+inline UBool UnicodeSet::operator!=(const UnicodeSet& o) const {
+    return !operator==(o);
+}
+
+inline UBool UnicodeSet::isFrozen() const {
+    return (UBool)(bmpSet!=NULL || stringSpan!=NULL);
+}
+
+inline UBool UnicodeSet::containsSome(UChar32 start, UChar32 end) const {
+    return !containsNone(start, end);
+}
+
+inline UBool UnicodeSet::containsSome(const UnicodeSet& s) const {
+    return !containsNone(s);
+}
+
+inline UBool UnicodeSet::containsSome(const UnicodeString& s) const {
+    return !containsNone(s);
+}
+
+inline UBool UnicodeSet::isBogus() const {
+    return (UBool)(fFlags & kIsBogus);
+}
+
+inline UnicodeSet *UnicodeSet::fromUSet(USet *uset) {
+    return reinterpret_cast<UnicodeSet *>(uset);
+}
+
+inline const UnicodeSet *UnicodeSet::fromUSet(const USet *uset) {
+    return reinterpret_cast<const UnicodeSet *>(uset);
+}
+
+inline USet *UnicodeSet::toUSet() {
+    return reinterpret_cast<USet *>(this);
+}
+
+inline const USet *UnicodeSet::toUSet() const {
+    return reinterpret_cast<const USet *>(this);
+}
+
+inline int32_t UnicodeSet::span(const UnicodeString &s, int32_t start, USetSpanCondition spanCondition) const {
+    int32_t sLength=s.length();
+    if(start<0) {
+        start=0;
+    } else if(start>sLength) {
+        start=sLength;
+    }
+    return start+span(s.getBuffer()+start, sLength-start, spanCondition);
+}
+
+inline int32_t UnicodeSet::spanBack(const UnicodeString &s, int32_t limit, USetSpanCondition spanCondition) const {
+    int32_t sLength=s.length();
+    if(limit<0) {
+        limit=0;
+    } else if(limit>sLength) {
+        limit=sLength;
+    }
+    return spanBack(s.getBuffer(), limit, spanCondition);
+}
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/unicode/unistr.h b/source/common/unicode/unistr.h
new file mode 100644
index 0000000..4fc180f
--- /dev/null
+++ b/source/common/unicode/unistr.h
@@ -0,0 +1,4446 @@
+/*
+**********************************************************************
+*   Copyright (C) 1998-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*
+* File unistr.h
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   09/25/98    stephen     Creation.
+*   11/11/98    stephen     Changed per 11/9 code review.
+*   04/20/99    stephen     Overhauled per 4/16 code review.
+*   11/18/99    aliu        Made to inherit from Replaceable.  Added method
+*                           handleReplaceBetween(); other methods unchanged.
+*   06/25/01    grhoten     Remove dependency on iostream.
+******************************************************************************
+*/
+
+#ifndef UNISTR_H
+#define UNISTR_H
+
+/**
+ * \file 
+ * \brief C++ API: Unicode String 
+ */
+
+#include "unicode/utypes.h"
+#include "unicode/rep.h"
+#include "unicode/std_string.h"
+#include "unicode/stringpiece.h"
+#include "unicode/bytestream.h"
+
+struct UConverter;          // unicode/ucnv.h
+class  StringThreadTest;
+
+#ifndef U_COMPARE_CODE_POINT_ORDER
+/* see also ustring.h and unorm.h */
+/**
+ * Option bit for u_strCaseCompare, u_strcasecmp, unorm_compare, etc:
+ * Compare strings in code point order instead of code unit order.
+ * @stable ICU 2.2
+ */
+#define U_COMPARE_CODE_POINT_ORDER  0x8000
+#endif
+
+#ifndef USTRING_H
+/**
+ * \ingroup ustring_ustrlen
+ */
+U_STABLE int32_t U_EXPORT2
+u_strlen(const UChar *s);
+#endif
+
+U_NAMESPACE_BEGIN
+
+class Locale;               // unicode/locid.h
+class StringCharacterIterator;
+class BreakIterator;        // unicode/brkiter.h
+
+/* The <iostream> include has been moved to unicode/ustream.h */
+
+/**
+ * Constant to be used in the UnicodeString(char *, int32_t, EInvariant) constructor
+ * which constructs a Unicode string from an invariant-character char * string.
+ * About invariant characters see utypes.h.
+ * This constructor has no runtime dependency on conversion code and is
+ * therefore recommended over ones taking a charset name string
+ * (where the empty string "" indicates invariant-character conversion).
+ *
+ * @stable ICU 3.2
+ */
+#define US_INV U_NAMESPACE_QUALIFIER UnicodeString::kInvariant
+
+/**
+ * Unicode String literals in C++.
+ * Dependent on the platform properties, different UnicodeString
+ * constructors should be used to create a UnicodeString object from
+ * a string literal.
+ * The macros are defined for maximum performance.
+ * They work only for strings that contain "invariant characters", i.e.,
+ * only latin letters, digits, and some punctuation.
+ * See utypes.h for details.
+ *
+ * The string parameter must be a C string literal.
+ * The length of the string, not including the terminating
+ * <code>NUL</code>, must be specified as a constant.
+ * The U_STRING_DECL macro should be invoked exactly once for one
+ * such string variable before it is used.
+ * @stable ICU 2.0
+ */
+#if defined(U_DECLARE_UTF16)
+#   define UNICODE_STRING(cs, _length) U_NAMESPACE_QUALIFIER UnicodeString(TRUE, (const UChar *)U_DECLARE_UTF16(cs), _length)
+#elif U_SIZEOF_WCHAR_T==U_SIZEOF_UCHAR && (U_CHARSET_FAMILY==U_ASCII_FAMILY || (U_SIZEOF_UCHAR == 2 && defined(U_WCHAR_IS_UTF16)))
+#   define UNICODE_STRING(cs, _length) U_NAMESPACE_QUALIFIER UnicodeString(TRUE, (const UChar *)L ## cs, _length)
+#elif U_SIZEOF_UCHAR==1 && U_CHARSET_FAMILY==U_ASCII_FAMILY
+#   define UNICODE_STRING(cs, _length) U_NAMESPACE_QUALIFIER UnicodeString(TRUE, (const UChar *)cs, _length)
+#else
+#   define UNICODE_STRING(cs, _length) U_NAMESPACE_QUALIFIER UnicodeString(cs, _length, US_INV)
+#endif
+
+/**
+ * Unicode String literals in C++.
+ * Dependent on the platform properties, different UnicodeString
+ * constructors should be used to create a UnicodeString object from
+ * a string literal.
+ * The macros are defined for improved performance.
+ * They work only for strings that contain "invariant characters", i.e.,
+ * only latin letters, digits, and some punctuation.
+ * See utypes.h for details.
+ *
+ * The string parameter must be a C string literal.
+ * @stable ICU 2.0
+ */
+#define UNICODE_STRING_SIMPLE(cs) UNICODE_STRING(cs, -1)
+
+/**
+ * UnicodeString is a string class that stores Unicode characters directly and provides
+ * similar functionality as the Java String and StringBuffer classes.
+ * It is a concrete implementation of the abstract class Replaceable (for transliteration).
+ *
+ * The UnicodeString class is not suitable for subclassing.
+ *
+ * <p>For an overview of Unicode strings in C and C++ see the
+ * <a href="http://icu-project.org/userguide/strings.html">User Guide Strings chapter</a>.</p>
+ *
+ * <p>In ICU, a Unicode string consists of 16-bit Unicode <em>code units</em>.
+ * A Unicode character may be stored with either one code unit
+ * (the most common case) or with a matched pair of special code units
+ * ("surrogates"). The data type for code units is UChar. 
+ * For single-character handling, a Unicode character code <em>point</em> is a value
+ * in the range 0..0x10ffff. ICU uses the UChar32 type for code points.</p>
+ *
+ * <p>Indexes and offsets into and lengths of strings always count code units, not code points.
+ * This is the same as with multi-byte char* strings in traditional string handling.
+ * Operations on partial strings typically do not test for code point boundaries.
+ * If necessary, the user needs to take care of such boundaries by testing for the code unit
+ * values or by using functions like
+ * UnicodeString::getChar32Start() and UnicodeString::getChar32Limit()
+ * (or, in C, the equivalent macros U16_SET_CP_START() and U16_SET_CP_LIMIT(), see utf.h).</p>
+ *
+ * UnicodeString methods are more lenient with regard to input parameter values
+ * than other ICU APIs. In particular:
+ * - If indexes are out of bounds for a UnicodeString object
+ *   (<0 or >length()) then they are "pinned" to the nearest boundary.
+ * - If primitive string pointer values (e.g., const UChar * or char *)
+ *   for input strings are NULL, then those input string parameters are treated
+ *   as if they pointed to an empty string.
+ *   However, this is <em>not</em> the case for char * parameters for charset names
+ *   or other IDs.
+ * - Most UnicodeString methods do not take a UErrorCode parameter because
+ *   there are usually very few opportunities for failure other than a shortage
+ *   of memory, error codes in low-level C++ string methods would be inconvenient,
+ *   and the error code as the last parameter (ICU convention) would prevent
+ *   the use of default parameter values.
+ *   Instead, such methods set the UnicodeString into a "bogus" state
+ *   (see isBogus()) if an error occurs.
+ *
+ * In string comparisons, two UnicodeString objects that are both "bogus"
+ * compare equal (to be transitive and prevent endless loops in sorting),
+ * and a "bogus" string compares less than any non-"bogus" one.
+ *
+ * Const UnicodeString methods are thread-safe. Multiple threads can use
+ * const methods on the same UnicodeString object simultaneously,
+ * but non-const methods must not be called concurrently (in multiple threads)
+ * with any other (const or non-const) methods.
+ *
+ * Similarly, const UnicodeString & parameters are thread-safe.
+ * One object may be passed in as such a parameter concurrently in multiple threads.
+ * This includes the const UnicodeString & parameters for
+ * copy construction, assignment, and cloning.
+ *
+ * <p>UnicodeString uses several storage methods.
+ * String contents can be stored inside the UnicodeString object itself,
+ * in an allocated and shared buffer, or in an outside buffer that is "aliased".
+ * Most of this is done transparently, but careful aliasing in particular provides
+ * significant performance improvements.
+ * Also, the internal buffer is accessible via special functions.
+ * For details see the
+ * <a href="http://icu-project.org/userguide/strings.html">User Guide Strings chapter</a>.</p>
+ *
+ * @see utf.h
+ * @see CharacterIterator
+ * @stable ICU 2.0
+ */
+class U_COMMON_API UnicodeString : public Replaceable
+{
+public:
+
+  /**
+   * Constant to be used in the UnicodeString(char *, int32_t, EInvariant) constructor
+   * which constructs a Unicode string from an invariant-character char * string.
+   * Use the macro US_INV instead of the full qualification for this value.
+   *
+   * @see US_INV
+   * @stable ICU 3.2
+   */
+  enum EInvariant {
+    /**
+     * @see EInvariant
+     * @stable ICU 3.2
+     */
+    kInvariant
+  };
+
+  //========================================
+  // Read-only operations
+  //========================================
+
+  /* Comparison - bitwise only - for international comparison use collation */
+
+  /**
+   * Equality operator. Performs only bitwise comparison.
+   * @param text The UnicodeString to compare to this one.
+   * @return TRUE if <TT>text</TT> contains the same characters as this one,
+   * FALSE otherwise.
+   * @stable ICU 2.0
+   */
+  inline UBool operator== (const UnicodeString& text) const;
+
+  /**
+   * Inequality operator. Performs only bitwise comparison.
+   * @param text The UnicodeString to compare to this one.
+   * @return FALSE if <TT>text</TT> contains the same characters as this one,
+   * TRUE otherwise.
+   * @stable ICU 2.0
+   */
+  inline UBool operator!= (const UnicodeString& text) const;
+
+  /**
+   * Greater than operator. Performs only bitwise comparison.
+   * @param text The UnicodeString to compare to this one.
+   * @return TRUE if the characters in this are bitwise
+   * greater than the characters in <code>text</code>, FALSE otherwise
+   * @stable ICU 2.0
+   */
+  inline UBool operator> (const UnicodeString& text) const;
+
+  /**
+   * Less than operator. Performs only bitwise comparison.
+   * @param text The UnicodeString to compare to this one.
+   * @return TRUE if the characters in this are bitwise
+   * less than the characters in <code>text</code>, FALSE otherwise
+   * @stable ICU 2.0
+   */
+  inline UBool operator< (const UnicodeString& text) const;
+
+  /**
+   * Greater than or equal operator. Performs only bitwise comparison.
+   * @param text The UnicodeString to compare to this one.
+   * @return TRUE if the characters in this are bitwise
+   * greater than or equal to the characters in <code>text</code>, FALSE otherwise
+   * @stable ICU 2.0
+   */
+  inline UBool operator>= (const UnicodeString& text) const;
+
+  /**
+   * Less than or equal operator. Performs only bitwise comparison.
+   * @param text The UnicodeString to compare to this one.
+   * @return TRUE if the characters in this are bitwise
+   * less than or equal to the characters in <code>text</code>, FALSE otherwise
+   * @stable ICU 2.0
+   */
+  inline UBool operator<= (const UnicodeString& text) const;
+
+  /**
+   * Compare the characters bitwise in this UnicodeString to
+   * the characters in <code>text</code>.
+   * @param text The UnicodeString to compare to this one.
+   * @return The result of bitwise character comparison: 0 if this
+   * contains the same characters as <code>text</code>, -1 if the characters in
+   * this are bitwise less than the characters in <code>text</code>, +1 if the
+   * characters in this are bitwise greater than the characters
+   * in <code>text</code>.
+   * @stable ICU 2.0
+   */
+  inline int8_t compare(const UnicodeString& text) const;
+
+  /**
+   * Compare the characters bitwise in the range
+   * [<TT>start</TT>, <TT>start + length</TT>) with the characters
+   * in <TT>text</TT>
+   * @param start the offset at which the compare operation begins
+   * @param length the number of characters of text to compare.
+   * @param text the other text to be compared against this string.
+   * @return The result of bitwise character comparison: 0 if this
+   * contains the same characters as <code>text</code>, -1 if the characters in
+   * this are bitwise less than the characters in <code>text</code>, +1 if the
+   * characters in this are bitwise greater than the characters
+   * in <code>text</code>.
+   * @stable ICU 2.0
+   */
+  inline int8_t compare(int32_t start,
+         int32_t length,
+         const UnicodeString& text) const;
+
+  /**
+   * Compare the characters bitwise in the range
+   * [<TT>start</TT>, <TT>start + length</TT>) with the characters
+   * in <TT>srcText</TT> in the range
+   * [<TT>srcStart</TT>, <TT>srcStart + srcLength</TT>).
+   * @param start the offset at which the compare operation begins
+   * @param length the number of characters in this to compare.
+   * @param srcText the text to be compared
+   * @param srcStart the offset into <TT>srcText</TT> to start comparison
+   * @param srcLength the number of characters in <TT>src</TT> to compare
+   * @return The result of bitwise character comparison: 0 if this
+   * contains the same characters as <code>srcText</code>, -1 if the characters in
+   * this are bitwise less than the characters in <code>srcText</code>, +1 if the
+   * characters in this are bitwise greater than the characters
+   * in <code>srcText</code>.
+   * @stable ICU 2.0
+   */
+   inline int8_t compare(int32_t start,
+         int32_t length,
+         const UnicodeString& srcText,
+         int32_t srcStart,
+         int32_t srcLength) const;
+
+  /**
+   * Compare the characters bitwise in this UnicodeString with the first
+   * <TT>srcLength</TT> characters in <TT>srcChars</TT>.
+   * @param srcChars The characters to compare to this UnicodeString.
+   * @param srcLength the number of characters in <TT>srcChars</TT> to compare
+   * @return The result of bitwise character comparison: 0 if this
+   * contains the same characters as <code>srcChars</code>, -1 if the characters in
+   * this are bitwise less than the characters in <code>srcChars</code>, +1 if the
+   * characters in this are bitwise greater than the characters
+   * in <code>srcChars</code>.
+   * @stable ICU 2.0
+   */
+  inline int8_t compare(const UChar *srcChars,
+         int32_t srcLength) const;
+
+  /**
+   * Compare the characters bitwise in the range
+   * [<TT>start</TT>, <TT>start + length</TT>) with the first
+   * <TT>length</TT> characters in <TT>srcChars</TT>
+   * @param start the offset at which the compare operation begins
+   * @param length the number of characters to compare.
+   * @param srcChars the characters to be compared
+   * @return The result of bitwise character comparison: 0 if this
+   * contains the same characters as <code>srcChars</code>, -1 if the characters in
+   * this are bitwise less than the characters in <code>srcChars</code>, +1 if the
+   * characters in this are bitwise greater than the characters
+   * in <code>srcChars</code>.
+   * @stable ICU 2.0
+   */
+  inline int8_t compare(int32_t start,
+         int32_t length,
+         const UChar *srcChars) const;
+
+  /**
+   * Compare the characters bitwise in the range
+   * [<TT>start</TT>, <TT>start + length</TT>) with the characters
+   * in <TT>srcChars</TT> in the range
+   * [<TT>srcStart</TT>, <TT>srcStart + srcLength</TT>).
+   * @param start the offset at which the compare operation begins
+   * @param length the number of characters in this to compare
+   * @param srcChars the characters to be compared
+   * @param srcStart the offset into <TT>srcChars</TT> to start comparison
+   * @param srcLength the number of characters in <TT>srcChars</TT> to compare
+   * @return The result of bitwise character comparison: 0 if this
+   * contains the same characters as <code>srcChars</code>, -1 if the characters in
+   * this are bitwise less than the characters in <code>srcChars</code>, +1 if the
+   * characters in this are bitwise greater than the characters
+   * in <code>srcChars</code>.
+   * @stable ICU 2.0
+   */
+  inline int8_t compare(int32_t start,
+         int32_t length,
+         const UChar *srcChars,
+         int32_t srcStart,
+         int32_t srcLength) const;
+
+  /**
+   * Compare the characters bitwise in the range
+   * [<TT>start</TT>, <TT>limit</TT>) with the characters
+   * in <TT>srcText</TT> in the range
+   * [<TT>srcStart</TT>, <TT>srcLimit</TT>).
+   * @param start the offset at which the compare operation begins
+   * @param limit the offset immediately following the compare operation
+   * @param srcText the text to be compared
+   * @param srcStart the offset into <TT>srcText</TT> to start comparison
+   * @param srcLimit the offset into <TT>srcText</TT> to limit comparison
+   * @return The result of bitwise character comparison: 0 if this
+   * contains the same characters as <code>srcText</code>, -1 if the characters in
+   * this are bitwise less than the characters in <code>srcText</code>, +1 if the
+   * characters in this are bitwise greater than the characters
+   * in <code>srcText</code>.
+   * @stable ICU 2.0
+   */
+  inline int8_t compareBetween(int32_t start,
+            int32_t limit,
+            const UnicodeString& srcText,
+            int32_t srcStart,
+            int32_t srcLimit) const;
+
+  /**
+   * Compare two Unicode strings in code point order.
+   * The result may be different from the results of compare(), operator<, etc.
+   * if supplementary characters are present:
+   *
+   * In UTF-16, supplementary characters (with code points U+10000 and above) are
+   * stored with pairs of surrogate code units. These have values from 0xd800 to 0xdfff,
+   * which means that they compare as less than some other BMP characters like U+feff.
+   * This function compares Unicode strings in code point order.
+   * If either of the UTF-16 strings is malformed (i.e., it contains unpaired surrogates), then the result is not defined.
+   *
+   * @param text Another string to compare this one to.
+   * @return a negative/zero/positive integer corresponding to whether
+   * this string is less than/equal to/greater than the second one
+   * in code point order
+   * @stable ICU 2.0
+   */
+  inline int8_t compareCodePointOrder(const UnicodeString& text) const;
+
+  /**
+   * Compare two Unicode strings in code point order.
+   * The result may be different from the results of compare(), operator<, etc.
+   * if supplementary characters are present:
+   *
+   * In UTF-16, supplementary characters (with code points U+10000 and above) are
+   * stored with pairs of surrogate code units. These have values from 0xd800 to 0xdfff,
+   * which means that they compare as less than some other BMP characters like U+feff.
+   * This function compares Unicode strings in code point order.
+   * If either of the UTF-16 strings is malformed (i.e., it contains unpaired surrogates), then the result is not defined.
+   *
+   * @param start The start offset in this string at which the compare operation begins.
+   * @param length The number of code units from this string to compare.
+   * @param srcText Another string to compare this one to.
+   * @return a negative/zero/positive integer corresponding to whether
+   * this string is less than/equal to/greater than the second one
+   * in code point order
+   * @stable ICU 2.0
+   */
+  inline int8_t compareCodePointOrder(int32_t start,
+                                      int32_t length,
+                                      const UnicodeString& srcText) const;
+
+  /**
+   * Compare two Unicode strings in code point order.
+   * The result may be different from the results of compare(), operator<, etc.
+   * if supplementary characters are present:
+   *
+   * In UTF-16, supplementary characters (with code points U+10000 and above) are
+   * stored with pairs of surrogate code units. These have values from 0xd800 to 0xdfff,
+   * which means that they compare as less than some other BMP characters like U+feff.
+   * This function compares Unicode strings in code point order.
+   * If either of the UTF-16 strings is malformed (i.e., it contains unpaired surrogates), then the result is not defined.
+   *
+   * @param start The start offset in this string at which the compare operation begins.
+   * @param length The number of code units from this string to compare.
+   * @param srcText Another string to compare this one to.
+   * @param srcStart The start offset in that string at which the compare operation begins.
+   * @param srcLength The number of code units from that string to compare.
+   * @return a negative/zero/positive integer corresponding to whether
+   * this string is less than/equal to/greater than the second one
+   * in code point order
+   * @stable ICU 2.0
+   */
+   inline int8_t compareCodePointOrder(int32_t start,
+                                       int32_t length,
+                                       const UnicodeString& srcText,
+                                       int32_t srcStart,
+                                       int32_t srcLength) const;
+
+  /**
+   * Compare two Unicode strings in code point order.
+   * The result may be different from the results of compare(), operator<, etc.
+   * if supplementary characters are present:
+   *
+   * In UTF-16, supplementary characters (with code points U+10000 and above) are
+   * stored with pairs of surrogate code units. These have values from 0xd800 to 0xdfff,
+   * which means that they compare as less than some other BMP characters like U+feff.
+   * This function compares Unicode strings in code point order.
+   * If either of the UTF-16 strings is malformed (i.e., it contains unpaired surrogates), then the result is not defined.
+   *
+   * @param srcChars A pointer to another string to compare this one to.
+   * @param srcLength The number of code units from that string to compare.
+   * @return a negative/zero/positive integer corresponding to whether
+   * this string is less than/equal to/greater than the second one
+   * in code point order
+   * @stable ICU 2.0
+   */
+  inline int8_t compareCodePointOrder(const UChar *srcChars,
+                                      int32_t srcLength) const;
+
+  /**
+   * Compare two Unicode strings in code point order.
+   * The result may be different from the results of compare(), operator<, etc.
+   * if supplementary characters are present:
+   *
+   * In UTF-16, supplementary characters (with code points U+10000 and above) are
+   * stored with pairs of surrogate code units. These have values from 0xd800 to 0xdfff,
+   * which means that they compare as less than some other BMP characters like U+feff.
+   * This function compares Unicode strings in code point order.
+   * If either of the UTF-16 strings is malformed (i.e., it contains unpaired surrogates), then the result is not defined.
+   *
+   * @param start The start offset in this string at which the compare operation begins.
+   * @param length The number of code units from this string to compare.
+   * @param srcChars A pointer to another string to compare this one to.
+   * @return a negative/zero/positive integer corresponding to whether
+   * this string is less than/equal to/greater than the second one
+   * in code point order
+   * @stable ICU 2.0
+   */
+  inline int8_t compareCodePointOrder(int32_t start,
+                                      int32_t length,
+                                      const UChar *srcChars) const;
+
+  /**
+   * Compare two Unicode strings in code point order.
+   * The result may be different from the results of compare(), operator<, etc.
+   * if supplementary characters are present:
+   *
+   * In UTF-16, supplementary characters (with code points U+10000 and above) are
+   * stored with pairs of surrogate code units. These have values from 0xd800 to 0xdfff,
+   * which means that they compare as less than some other BMP characters like U+feff.
+   * This function compares Unicode strings in code point order.
+   * If either of the UTF-16 strings is malformed (i.e., it contains unpaired surrogates), then the result is not defined.
+   *
+   * @param start The start offset in this string at which the compare operation begins.
+   * @param length The number of code units from this string to compare.
+   * @param srcChars A pointer to another string to compare this one to.
+   * @param srcStart The start offset in that string at which the compare operation begins.
+   * @param srcLength The number of code units from that string to compare.
+   * @return a negative/zero/positive integer corresponding to whether
+   * this string is less than/equal to/greater than the second one
+   * in code point order
+   * @stable ICU 2.0
+   */
+  inline int8_t compareCodePointOrder(int32_t start,
+                                      int32_t length,
+                                      const UChar *srcChars,
+                                      int32_t srcStart,
+                                      int32_t srcLength) const;
+
+  /**
+   * Compare two Unicode strings in code point order.
+   * The result may be different from the results of compare(), operator<, etc.
+   * if supplementary characters are present:
+   *
+   * In UTF-16, supplementary characters (with code points U+10000 and above) are
+   * stored with pairs of surrogate code units. These have values from 0xd800 to 0xdfff,
+   * which means that they compare as less than some other BMP characters like U+feff.
+   * This function compares Unicode strings in code point order.
+   * If either of the UTF-16 strings is malformed (i.e., it contains unpaired surrogates), then the result is not defined.
+   *
+   * @param start The start offset in this string at which the compare operation begins.
+   * @param limit The offset after the last code unit from this string to compare.
+   * @param srcText Another string to compare this one to.
+   * @param srcStart The start offset in that string at which the compare operation begins.
+   * @param srcLimit The offset after the last code unit from that string to compare.
+   * @return a negative/zero/positive integer corresponding to whether
+   * this string is less than/equal to/greater than the second one
+   * in code point order
+   * @stable ICU 2.0
+   */
+  inline int8_t compareCodePointOrderBetween(int32_t start,
+                                             int32_t limit,
+                                             const UnicodeString& srcText,
+                                             int32_t srcStart,
+                                             int32_t srcLimit) const;
+
+  /**
+   * Compare two strings case-insensitively using full case folding.
+   * This is equivalent to this->foldCase(options).compare(text.foldCase(options)).
+   *
+   * @param text Another string to compare this one to.
+   * @param options A bit set of options:
+   *   - U_FOLD_CASE_DEFAULT or 0 is used for default options:
+   *     Comparison in code unit order with default case folding.
+   *
+   *   - U_COMPARE_CODE_POINT_ORDER
+   *     Set to choose code point order instead of code unit order
+   *     (see u_strCompare for details).
+   *
+   *   - U_FOLD_CASE_EXCLUDE_SPECIAL_I
+   *
+   * @return A negative, zero, or positive integer indicating the comparison result.
+   * @stable ICU 2.0
+   */
+  inline int8_t caseCompare(const UnicodeString& text, uint32_t options) const;
+
+  /**
+   * Compare two strings case-insensitively using full case folding.
+   * This is equivalent to this->foldCase(options).compare(srcText.foldCase(options)).
+   *
+   * @param start The start offset in this string at which the compare operation begins.
+   * @param length The number of code units from this string to compare.
+   * @param srcText Another string to compare this one to.
+   * @param options A bit set of options:
+   *   - U_FOLD_CASE_DEFAULT or 0 is used for default options:
+   *     Comparison in code unit order with default case folding.
+   *
+   *   - U_COMPARE_CODE_POINT_ORDER
+   *     Set to choose code point order instead of code unit order
+   *     (see u_strCompare for details).
+   *
+   *   - U_FOLD_CASE_EXCLUDE_SPECIAL_I
+   *
+   * @return A negative, zero, or positive integer indicating the comparison result.
+   * @stable ICU 2.0
+   */
+  inline int8_t caseCompare(int32_t start,
+         int32_t length,
+         const UnicodeString& srcText,
+         uint32_t options) const;
+
+  /**
+   * Compare two strings case-insensitively using full case folding.
+   * This is equivalent to this->foldCase(options).compare(srcText.foldCase(options)).
+   *
+   * @param start The start offset in this string at which the compare operation begins.
+   * @param length The number of code units from this string to compare.
+   * @param srcText Another string to compare this one to.
+   * @param srcStart The start offset in that string at which the compare operation begins.
+   * @param srcLength The number of code units from that string to compare.
+   * @param options A bit set of options:
+   *   - U_FOLD_CASE_DEFAULT or 0 is used for default options:
+   *     Comparison in code unit order with default case folding.
+   *
+   *   - U_COMPARE_CODE_POINT_ORDER
+   *     Set to choose code point order instead of code unit order
+   *     (see u_strCompare for details).
+   *
+   *   - U_FOLD_CASE_EXCLUDE_SPECIAL_I
+   *
+   * @return A negative, zero, or positive integer indicating the comparison result.
+   * @stable ICU 2.0
+   */
+  inline int8_t caseCompare(int32_t start,
+         int32_t length,
+         const UnicodeString& srcText,
+         int32_t srcStart,
+         int32_t srcLength,
+         uint32_t options) const;
+
+  /**
+   * Compare two strings case-insensitively using full case folding.
+   * This is equivalent to this->foldCase(options).compare(srcChars.foldCase(options)).
+   *
+   * @param srcChars A pointer to another string to compare this one to.
+   * @param srcLength The number of code units from that string to compare.
+   * @param options A bit set of options:
+   *   - U_FOLD_CASE_DEFAULT or 0 is used for default options:
+   *     Comparison in code unit order with default case folding.
+   *
+   *   - U_COMPARE_CODE_POINT_ORDER
+   *     Set to choose code point order instead of code unit order
+   *     (see u_strCompare for details).
+   *
+   *   - U_FOLD_CASE_EXCLUDE_SPECIAL_I
+   *
+   * @return A negative, zero, or positive integer indicating the comparison result.
+   * @stable ICU 2.0
+   */
+  inline int8_t caseCompare(const UChar *srcChars,
+         int32_t srcLength,
+         uint32_t options) const;
+
+  /**
+   * Compare two strings case-insensitively using full case folding.
+   * This is equivalent to this->foldCase(options).compare(srcChars.foldCase(options)).
+   *
+   * @param start The start offset in this string at which the compare operation begins.
+   * @param length The number of code units from this string to compare.
+   * @param srcChars A pointer to another string to compare this one to.
+   * @param options A bit set of options:
+   *   - U_FOLD_CASE_DEFAULT or 0 is used for default options:
+   *     Comparison in code unit order with default case folding.
+   *
+   *   - U_COMPARE_CODE_POINT_ORDER
+   *     Set to choose code point order instead of code unit order
+   *     (see u_strCompare for details).
+   *
+   *   - U_FOLD_CASE_EXCLUDE_SPECIAL_I
+   *
+   * @return A negative, zero, or positive integer indicating the comparison result.
+   * @stable ICU 2.0
+   */
+  inline int8_t caseCompare(int32_t start,
+         int32_t length,
+         const UChar *srcChars,
+         uint32_t options) const;
+
+  /**
+   * Compare two strings case-insensitively using full case folding.
+   * This is equivalent to this->foldCase(options).compare(srcChars.foldCase(options)).
+   *
+   * @param start The start offset in this string at which the compare operation begins.
+   * @param length The number of code units from this string to compare.
+   * @param srcChars A pointer to another string to compare this one to.
+   * @param srcStart The start offset in that string at which the compare operation begins.
+   * @param srcLength The number of code units from that string to compare.
+   * @param options A bit set of options:
+   *   - U_FOLD_CASE_DEFAULT or 0 is used for default options:
+   *     Comparison in code unit order with default case folding.
+   *
+   *   - U_COMPARE_CODE_POINT_ORDER
+   *     Set to choose code point order instead of code unit order
+   *     (see u_strCompare for details).
+   *
+   *   - U_FOLD_CASE_EXCLUDE_SPECIAL_I
+   *
+   * @return A negative, zero, or positive integer indicating the comparison result.
+   * @stable ICU 2.0
+   */
+  inline int8_t caseCompare(int32_t start,
+         int32_t length,
+         const UChar *srcChars,
+         int32_t srcStart,
+         int32_t srcLength,
+         uint32_t options) const;
+
+  /**
+   * Compare two strings case-insensitively using full case folding.
+   * This is equivalent to this->foldCase(options).compareBetween(text.foldCase(options)).
+   *
+   * @param start The start offset in this string at which the compare operation begins.
+   * @param limit The offset after the last code unit from this string to compare.
+   * @param srcText Another string to compare this one to.
+   * @param srcStart The start offset in that string at which the compare operation begins.
+   * @param srcLimit The offset after the last code unit from that string to compare.
+   * @param options A bit set of options:
+   *   - U_FOLD_CASE_DEFAULT or 0 is used for default options:
+   *     Comparison in code unit order with default case folding.
+   *
+   *   - U_COMPARE_CODE_POINT_ORDER
+   *     Set to choose code point order instead of code unit order
+   *     (see u_strCompare for details).
+   *
+   *   - U_FOLD_CASE_EXCLUDE_SPECIAL_I
+   *
+   * @return A negative, zero, or positive integer indicating the comparison result.
+   * @stable ICU 2.0
+   */
+  inline int8_t caseCompareBetween(int32_t start,
+            int32_t limit,
+            const UnicodeString& srcText,
+            int32_t srcStart,
+            int32_t srcLimit,
+            uint32_t options) const;
+
+  /**
+   * Determine if this starts with the characters in <TT>text</TT>
+   * @param text The text to match.
+   * @return TRUE if this starts with the characters in <TT>text</TT>,
+   * FALSE otherwise
+   * @stable ICU 2.0
+   */
+  inline UBool startsWith(const UnicodeString& text) const;
+
+  /**
+   * Determine if this starts with the characters in <TT>srcText</TT>
+   * in the range [<TT>srcStart</TT>, <TT>srcStart + srcLength</TT>).
+   * @param srcText The text to match.
+   * @param srcStart the offset into <TT>srcText</TT> to start matching
+   * @param srcLength the number of characters in <TT>srcText</TT> to match
+   * @return TRUE if this starts with the characters in <TT>text</TT>,
+   * FALSE otherwise
+   * @stable ICU 2.0
+   */
+  inline UBool startsWith(const UnicodeString& srcText,
+            int32_t srcStart,
+            int32_t srcLength) const;
+
+  /**
+   * Determine if this starts with the characters in <TT>srcChars</TT>
+   * @param srcChars The characters to match.
+   * @param srcLength the number of characters in <TT>srcChars</TT>
+   * @return TRUE if this starts with the characters in <TT>srcChars</TT>,
+   * FALSE otherwise
+   * @stable ICU 2.0
+   */
+  inline UBool startsWith(const UChar *srcChars,
+            int32_t srcLength) const;
+
+  /**
+   * Determine if this ends with the characters in <TT>srcChars</TT>
+   * in the range  [<TT>srcStart</TT>, <TT>srcStart + srcLength</TT>).
+   * @param srcChars The characters to match.
+   * @param srcStart the offset into <TT>srcText</TT> to start matching
+   * @param srcLength the number of characters in <TT>srcChars</TT> to match
+   * @return TRUE if this ends with the characters in <TT>srcChars</TT>, FALSE otherwise
+   * @stable ICU 2.0
+   */
+  inline UBool startsWith(const UChar *srcChars,
+            int32_t srcStart,
+            int32_t srcLength) const;
+
+  /**
+   * Determine if this ends with the characters in <TT>text</TT>
+   * @param text The text to match.
+   * @return TRUE if this ends with the characters in <TT>text</TT>,
+   * FALSE otherwise
+   * @stable ICU 2.0
+   */
+  inline UBool endsWith(const UnicodeString& text) const;
+
+  /**
+   * Determine if this ends with the characters in <TT>srcText</TT>
+   * in the range [<TT>srcStart</TT>, <TT>srcStart + srcLength</TT>).
+   * @param srcText The text to match.
+   * @param srcStart the offset into <TT>srcText</TT> to start matching
+   * @param srcLength the number of characters in <TT>srcText</TT> to match
+   * @return TRUE if this ends with the characters in <TT>text</TT>,
+   * FALSE otherwise
+   * @stable ICU 2.0
+   */
+  inline UBool endsWith(const UnicodeString& srcText,
+          int32_t srcStart,
+          int32_t srcLength) const;
+
+  /**
+   * Determine if this ends with the characters in <TT>srcChars</TT>
+   * @param srcChars The characters to match.
+   * @param srcLength the number of characters in <TT>srcChars</TT>
+   * @return TRUE if this ends with the characters in <TT>srcChars</TT>,
+   * FALSE otherwise
+   * @stable ICU 2.0
+   */
+  inline UBool endsWith(const UChar *srcChars,
+          int32_t srcLength) const;
+
+  /**
+   * Determine if this ends with the characters in <TT>srcChars</TT>
+   * in the range  [<TT>srcStart</TT>, <TT>srcStart + srcLength</TT>).
+   * @param srcChars The characters to match.
+   * @param srcStart the offset into <TT>srcText</TT> to start matching
+   * @param srcLength the number of characters in <TT>srcChars</TT> to match
+   * @return TRUE if this ends with the characters in <TT>srcChars</TT>,
+   * FALSE otherwise
+   * @stable ICU 2.0
+   */
+  inline UBool endsWith(const UChar *srcChars,
+          int32_t srcStart,
+          int32_t srcLength) const;
+
+
+  /* Searching - bitwise only */
+
+  /**
+   * Locate in this the first occurrence of the characters in <TT>text</TT>,
+   * using bitwise comparison.
+   * @param text The text to search for.
+   * @return The offset into this of the start of <TT>text</TT>,
+   * or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t indexOf(const UnicodeString& text) const;
+
+  /**
+   * Locate in this the first occurrence of the characters in <TT>text</TT>
+   * starting at offset <TT>start</TT>, using bitwise comparison.
+   * @param text The text to search for.
+   * @param start The offset at which searching will start.
+   * @return The offset into this of the start of <TT>text</TT>,
+   * or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t indexOf(const UnicodeString& text,
+              int32_t start) const;
+
+  /**
+   * Locate in this the first occurrence in the range
+   * [<TT>start</TT>, <TT>start + length</TT>) of the characters
+   * in <TT>text</TT>, using bitwise comparison.
+   * @param text The text to search for.
+   * @param start The offset at which searching will start.
+   * @param length The number of characters to search
+   * @return The offset into this of the start of <TT>text</TT>,
+   * or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t indexOf(const UnicodeString& text,
+              int32_t start,
+              int32_t length) const;
+
+  /**
+   * Locate in this the first occurrence in the range
+   * [<TT>start</TT>, <TT>start + length</TT>) of the characters
+   *  in <TT>srcText</TT> in the range
+   * [<TT>srcStart</TT>, <TT>srcStart + srcLength</TT>),
+   * using bitwise comparison.
+   * @param srcText The text to search for.
+   * @param srcStart the offset into <TT>srcText</TT> at which
+   * to start matching
+   * @param srcLength the number of characters in <TT>srcText</TT> to match
+   * @param start the offset into this at which to start matching
+   * @param length the number of characters in this to search
+   * @return The offset into this of the start of <TT>text</TT>,
+   * or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t indexOf(const UnicodeString& srcText,
+              int32_t srcStart,
+              int32_t srcLength,
+              int32_t start,
+              int32_t length) const;
+
+  /**
+   * Locate in this the first occurrence of the characters in
+   * <TT>srcChars</TT>
+   * starting at offset <TT>start</TT>, using bitwise comparison.
+   * @param srcChars The text to search for.
+   * @param srcLength the number of characters in <TT>srcChars</TT> to match
+   * @param start the offset into this at which to start matching
+   * @return The offset into this of the start of <TT>text</TT>,
+   * or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t indexOf(const UChar *srcChars,
+              int32_t srcLength,
+              int32_t start) const;
+
+  /**
+   * Locate in this the first occurrence in the range
+   * [<TT>start</TT>, <TT>start + length</TT>) of the characters
+   * in <TT>srcChars</TT>, using bitwise comparison.
+   * @param srcChars The text to search for.
+   * @param srcLength the number of characters in <TT>srcChars</TT>
+   * @param start The offset at which searching will start.
+   * @param length The number of characters to search
+   * @return The offset into this of the start of <TT>srcChars</TT>,
+   * or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t indexOf(const UChar *srcChars,
+              int32_t srcLength,
+              int32_t start,
+              int32_t length) const;
+
+  /**
+   * Locate in this the first occurrence in the range
+   * [<TT>start</TT>, <TT>start + length</TT>) of the characters
+   * in <TT>srcChars</TT> in the range
+   * [<TT>srcStart</TT>, <TT>srcStart + srcLength</TT>),
+   * using bitwise comparison.
+   * @param srcChars The text to search for.
+   * @param srcStart the offset into <TT>srcChars</TT> at which
+   * to start matching
+   * @param srcLength the number of characters in <TT>srcChars</TT> to match
+   * @param start the offset into this at which to start matching
+   * @param length the number of characters in this to search
+   * @return The offset into this of the start of <TT>text</TT>,
+   * or -1 if not found.
+   * @stable ICU 2.0
+   */
+  int32_t indexOf(const UChar *srcChars,
+              int32_t srcStart,
+              int32_t srcLength,
+              int32_t start,
+              int32_t length) const;
+
+  /**
+   * Locate in this the first occurrence of the BMP code point <code>c</code>,
+   * using bitwise comparison.
+   * @param c The code unit to search for.
+   * @return The offset into this of <TT>c</TT>, or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t indexOf(UChar c) const;
+
+  /**
+   * Locate in this the first occurrence of the code point <TT>c</TT>,
+   * using bitwise comparison.
+   *
+   * @param c The code point to search for.
+   * @return The offset into this of <TT>c</TT>, or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t indexOf(UChar32 c) const;
+
+  /**
+   * Locate in this the first occurrence of the BMP code point <code>c</code>,
+   * starting at offset <TT>start</TT>, using bitwise comparison.
+   * @param c The code unit to search for.
+   * @param start The offset at which searching will start.
+   * @return The offset into this of <TT>c</TT>, or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t indexOf(UChar c,
+              int32_t start) const;
+
+  /**
+   * Locate in this the first occurrence of the code point <TT>c</TT>
+   * starting at offset <TT>start</TT>, using bitwise comparison.
+   *
+   * @param c The code point to search for.
+   * @param start The offset at which searching will start.
+   * @return The offset into this of <TT>c</TT>, or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t indexOf(UChar32 c,
+              int32_t start) const;
+
+  /**
+   * Locate in this the first occurrence of the BMP code point <code>c</code>
+   * in the range [<TT>start</TT>, <TT>start + length</TT>),
+   * using bitwise comparison.
+   * @param c The code unit to search for.
+   * @param start the offset into this at which to start matching
+   * @param length the number of characters in this to search
+   * @return The offset into this of <TT>c</TT>, or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t indexOf(UChar c,
+              int32_t start,
+              int32_t length) const;
+
+  /**
+   * Locate in this the first occurrence of the code point <TT>c</TT>
+   * in the range [<TT>start</TT>, <TT>start + length</TT>),
+   * using bitwise comparison.
+   *
+   * @param c The code point to search for.
+   * @param start the offset into this at which to start matching
+   * @param length the number of characters in this to search
+   * @return The offset into this of <TT>c</TT>, or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t indexOf(UChar32 c,
+              int32_t start,
+              int32_t length) const;
+
+  /**
+   * Locate in this the last occurrence of the characters in <TT>text</TT>,
+   * using bitwise comparison.
+   * @param text The text to search for.
+   * @return The offset into this of the start of <TT>text</TT>,
+   * or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t lastIndexOf(const UnicodeString& text) const;
+
+  /**
+   * Locate in this the last occurrence of the characters in <TT>text</TT>
+   * starting at offset <TT>start</TT>, using bitwise comparison.
+   * @param text The text to search for.
+   * @param start The offset at which searching will start.
+   * @return The offset into this of the start of <TT>text</TT>,
+   * or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t lastIndexOf(const UnicodeString& text,
+              int32_t start) const;
+
+  /**
+   * Locate in this the last occurrence in the range
+   * [<TT>start</TT>, <TT>start + length</TT>) of the characters
+   * in <TT>text</TT>, using bitwise comparison.
+   * @param text The text to search for.
+   * @param start The offset at which searching will start.
+   * @param length The number of characters to search
+   * @return The offset into this of the start of <TT>text</TT>,
+   * or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t lastIndexOf(const UnicodeString& text,
+              int32_t start,
+              int32_t length) const;
+
+  /**
+   * Locate in this the last occurrence in the range
+   * [<TT>start</TT>, <TT>start + length</TT>) of the characters
+   * in <TT>srcText</TT> in the range
+   * [<TT>srcStart</TT>, <TT>srcStart + srcLength</TT>),
+   * using bitwise comparison.
+   * @param srcText The text to search for.
+   * @param srcStart the offset into <TT>srcText</TT> at which
+   * to start matching
+   * @param srcLength the number of characters in <TT>srcText</TT> to match
+   * @param start the offset into this at which to start matching
+   * @param length the number of characters in this to search
+   * @return The offset into this of the start of <TT>text</TT>,
+   * or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t lastIndexOf(const UnicodeString& srcText,
+              int32_t srcStart,
+              int32_t srcLength,
+              int32_t start,
+              int32_t length) const;
+
+  /**
+   * Locate in this the last occurrence of the characters in <TT>srcChars</TT>
+   * starting at offset <TT>start</TT>, using bitwise comparison.
+   * @param srcChars The text to search for.
+   * @param srcLength the number of characters in <TT>srcChars</TT> to match
+   * @param start the offset into this at which to start matching
+   * @return The offset into this of the start of <TT>text</TT>,
+   * or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t lastIndexOf(const UChar *srcChars,
+              int32_t srcLength,
+              int32_t start) const;
+
+  /**
+   * Locate in this the last occurrence in the range
+   * [<TT>start</TT>, <TT>start + length</TT>) of the characters
+   * in <TT>srcChars</TT>, using bitwise comparison.
+   * @param srcChars The text to search for.
+   * @param srcLength the number of characters in <TT>srcChars</TT>
+   * @param start The offset at which searching will start.
+   * @param length The number of characters to search
+   * @return The offset into this of the start of <TT>srcChars</TT>,
+   * or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t lastIndexOf(const UChar *srcChars,
+              int32_t srcLength,
+              int32_t start,
+              int32_t length) const;
+
+  /**
+   * Locate in this the last occurrence in the range
+   * [<TT>start</TT>, <TT>start + length</TT>) of the characters
+   * in <TT>srcChars</TT> in the range
+   * [<TT>srcStart</TT>, <TT>srcStart + srcLength</TT>),
+   * using bitwise comparison.
+   * @param srcChars The text to search for.
+   * @param srcStart the offset into <TT>srcChars</TT> at which
+   * to start matching
+   * @param srcLength the number of characters in <TT>srcChars</TT> to match
+   * @param start the offset into this at which to start matching
+   * @param length the number of characters in this to search
+   * @return The offset into this of the start of <TT>text</TT>,
+   * or -1 if not found.
+   * @stable ICU 2.0
+   */
+  int32_t lastIndexOf(const UChar *srcChars,
+              int32_t srcStart,
+              int32_t srcLength,
+              int32_t start,
+              int32_t length) const;
+
+  /**
+   * Locate in this the last occurrence of the BMP code point <code>c</code>,
+   * using bitwise comparison.
+   * @param c The code unit to search for.
+   * @return The offset into this of <TT>c</TT>, or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t lastIndexOf(UChar c) const;
+
+  /**
+   * Locate in this the last occurrence of the code point <TT>c</TT>,
+   * using bitwise comparison.
+   *
+   * @param c The code point to search for.
+   * @return The offset into this of <TT>c</TT>, or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t lastIndexOf(UChar32 c) const;
+
+  /**
+   * Locate in this the last occurrence of the BMP code point <code>c</code>
+   * starting at offset <TT>start</TT>, using bitwise comparison.
+   * @param c The code unit to search for.
+   * @param start The offset at which searching will start.
+   * @return The offset into this of <TT>c</TT>, or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t lastIndexOf(UChar c,
+              int32_t start) const;
+
+  /**
+   * Locate in this the last occurrence of the code point <TT>c</TT>
+   * starting at offset <TT>start</TT>, using bitwise comparison.
+   *
+   * @param c The code point to search for.
+   * @param start The offset at which searching will start.
+   * @return The offset into this of <TT>c</TT>, or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t lastIndexOf(UChar32 c,
+              int32_t start) const;
+
+  /**
+   * Locate in this the last occurrence of the BMP code point <code>c</code>
+   * in the range [<TT>start</TT>, <TT>start + length</TT>),
+   * using bitwise comparison.
+   * @param c The code unit to search for.
+   * @param start the offset into this at which to start matching
+   * @param length the number of characters in this to search
+   * @return The offset into this of <TT>c</TT>, or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t lastIndexOf(UChar c,
+              int32_t start,
+              int32_t length) const;
+
+  /**
+   * Locate in this the last occurrence of the code point <TT>c</TT>
+   * in the range [<TT>start</TT>, <TT>start + length</TT>),
+   * using bitwise comparison.
+   *
+   * @param c The code point to search for.
+   * @param start the offset into this at which to start matching
+   * @param length the number of characters in this to search
+   * @return The offset into this of <TT>c</TT>, or -1 if not found.
+   * @stable ICU 2.0
+   */
+  inline int32_t lastIndexOf(UChar32 c,
+              int32_t start,
+              int32_t length) const;
+
+
+  /* Character access */
+
+  /**
+   * Return the code unit at offset <tt>offset</tt>.
+   * If the offset is not valid (0..length()-1) then U+ffff is returned.
+   * @param offset a valid offset into the text
+   * @return the code unit at offset <tt>offset</tt>
+   *         or 0xffff if the offset is not valid for this string
+   * @stable ICU 2.0
+   */
+  inline UChar charAt(int32_t offset) const;
+
+  /**
+   * Return the code unit at offset <tt>offset</tt>.
+   * If the offset is not valid (0..length()-1) then U+ffff is returned.
+   * @param offset a valid offset into the text
+   * @return the code unit at offset <tt>offset</tt>
+   * @stable ICU 2.0
+   */
+  inline UChar operator[] (int32_t offset) const;
+
+  /**
+   * Return the code point that contains the code unit
+   * at offset <tt>offset</tt>.
+   * If the offset is not valid (0..length()-1) then U+ffff is returned.
+   * @param offset a valid offset into the text
+   * that indicates the text offset of any of the code units
+   * that will be assembled into a code point (21-bit value) and returned
+   * @return the code point of text at <tt>offset</tt>
+   *         or 0xffff if the offset is not valid for this string
+   * @stable ICU 2.0
+   */
+  inline UChar32 char32At(int32_t offset) const;
+
+  /**
+   * Adjust a random-access offset so that
+   * it points to the beginning of a Unicode character.
+   * The offset that is passed in points to
+   * any code unit of a code point,
+   * while the returned offset will point to the first code unit
+   * of the same code point.
+   * In UTF-16, if the input offset points to a second surrogate
+   * of a surrogate pair, then the returned offset will point
+   * to the first surrogate.
+   * @param offset a valid offset into one code point of the text
+   * @return offset of the first code unit of the same code point
+   * @see U16_SET_CP_START
+   * @stable ICU 2.0
+   */
+  inline int32_t getChar32Start(int32_t offset) const;
+
+  /**
+   * Adjust a random-access offset so that
+   * it points behind a Unicode character.
+   * The offset that is passed in points behind
+   * any code unit of a code point,
+   * while the returned offset will point behind the last code unit
+   * of the same code point.
+   * In UTF-16, if the input offset points behind the first surrogate
+   * (i.e., to the second surrogate)
+   * of a surrogate pair, then the returned offset will point
+   * behind the second surrogate (i.e., to the first surrogate).
+   * @param offset a valid offset after any code unit of a code point of the text
+   * @return offset of the first code unit after the same code point
+   * @see U16_SET_CP_LIMIT
+   * @stable ICU 2.0
+   */
+  inline int32_t getChar32Limit(int32_t offset) const;
+
+  /**
+   * Move the code unit index along the string by delta code points.
+   * Interpret the input index as a code unit-based offset into the string,
+   * move the index forward or backward by delta code points, and
+   * return the resulting index.
+   * The input index should point to the first code unit of a code point,
+   * if there is more than one.
+   *
+   * Both input and output indexes are code unit-based as for all
+   * string indexes/offsets in ICU (and other libraries, like MBCS char*).
+   * If delta<0 then the index is moved backward (toward the start of the string).
+   * If delta>0 then the index is moved forward (toward the end of the string).
+   *
+   * This behaves like CharacterIterator::move32(delta, kCurrent).
+   *
+   * Behavior for out-of-bounds indexes:
+   * <code>moveIndex32</code> pins the input index to 0..length(), i.e.,
+   * if the input index<0 then it is pinned to 0;
+   * if it is index>length() then it is pinned to length().
+   * Afterwards, the index is moved by <code>delta</code> code points
+   * forward or backward,
+   * but no further backward than to 0 and no further forward than to length().
+   * The resulting index return value will be in between 0 and length(), inclusively.
+   *
+   * Examples:
+   * <pre>
+   * // s has code points 'a' U+10000 'b' U+10ffff U+2029
+   * UnicodeString s=UNICODE_STRING("a\\U00010000b\\U0010ffff\\u2029", 31).unescape();
+   *
+   * // initial index: position of U+10000
+   * int32_t index=1;
+   *
+   * // the following examples will all result in index==4, position of U+10ffff
+   *
+   * // skip 2 code points from some position in the string
+   * index=s.moveIndex32(index, 2); // skips U+10000 and 'b'
+   *
+   * // go to the 3rd code point from the start of s (0-based)
+   * index=s.moveIndex32(0, 3); // skips 'a', U+10000, and 'b'
+   *
+   * // go to the next-to-last code point of s
+   * index=s.moveIndex32(s.length(), -2); // backward-skips U+2029 and U+10ffff
+   * </pre>
+   *
+   * @param index input code unit index
+   * @param delta (signed) code point count to move the index forward or backward
+   *        in the string
+   * @return the resulting code unit index
+   * @stable ICU 2.0
+   */
+  int32_t moveIndex32(int32_t index, int32_t delta) const;
+
+  /* Substring extraction */
+
+  /**
+   * Copy the characters in the range
+   * [<tt>start</tt>, <tt>start + length</tt>) into the array <tt>dst</tt>,
+   * beginning at <tt>dstStart</tt>.
+   * If the string aliases to <code>dst</code> itself as an external buffer,
+   * then extract() will not copy the contents.
+   *
+   * @param start offset of first character which will be copied into the array
+   * @param length the number of characters to extract
+   * @param dst array in which to copy characters.  The length of <tt>dst</tt>
+   * must be at least (<tt>dstStart + length</tt>).
+   * @param dstStart the offset in <TT>dst</TT> where the first character
+   * will be extracted
+   * @stable ICU 2.0
+   */
+  inline void extract(int32_t start,
+           int32_t length,
+           UChar *dst,
+           int32_t dstStart = 0) const;
+
+  /**
+   * Copy the contents of the string into dest.
+   * This is a convenience function that
+   * checks if there is enough space in dest,
+   * extracts the entire string if possible,
+   * and NUL-terminates dest if possible.
+   *
+   * If the string fits into dest but cannot be NUL-terminated
+   * (length()==destCapacity) then the error code is set to U_STRING_NOT_TERMINATED_WARNING.
+   * If the string itself does not fit into dest
+   * (length()>destCapacity) then the error code is set to U_BUFFER_OVERFLOW_ERROR.
+   *
+   * If the string aliases to <code>dest</code> itself as an external buffer,
+   * then extract() will not copy the contents.
+   *
+   * @param dest Destination string buffer.
+   * @param destCapacity Number of UChars available at dest.
+   * @param errorCode ICU error code.
+   * @return length()
+   * @stable ICU 2.0
+   */
+  int32_t
+  extract(UChar *dest, int32_t destCapacity,
+          UErrorCode &errorCode) const;
+
+  /**
+   * Copy the characters in the range
+   * [<tt>start</tt>, <tt>start + length</tt>) into the  UnicodeString
+   * <tt>target</tt>.
+   * @param start offset of first character which will be copied
+   * @param length the number of characters to extract
+   * @param target UnicodeString into which to copy characters.
+   * @return A reference to <TT>target</TT>
+   * @stable ICU 2.0
+   */
+  inline void extract(int32_t start,
+           int32_t length,
+           UnicodeString& target) const;
+
+  /**
+   * Copy the characters in the range [<tt>start</tt>, <tt>limit</tt>)
+   * into the array <tt>dst</tt>, beginning at <tt>dstStart</tt>.
+   * @param start offset of first character which will be copied into the array
+   * @param limit offset immediately following the last character to be copied
+   * @param dst array in which to copy characters.  The length of <tt>dst</tt>
+   * must be at least (<tt>dstStart + (limit - start)</tt>).
+   * @param dstStart the offset in <TT>dst</TT> where the first character
+   * will be extracted
+   * @stable ICU 2.0
+   */
+  inline void extractBetween(int32_t start,
+              int32_t limit,
+              UChar *dst,
+              int32_t dstStart = 0) const;
+
+  /**
+   * Copy the characters in the range [<tt>start</tt>, <tt>limit</tt>)
+   * into the UnicodeString <tt>target</tt>.  Replaceable API.
+   * @param start offset of first character which will be copied
+   * @param limit offset immediately following the last character to be copied
+   * @param target UnicodeString into which to copy characters.
+   * @return A reference to <TT>target</TT>
+   * @stable ICU 2.0
+   */
+  virtual void extractBetween(int32_t start,
+              int32_t limit,
+              UnicodeString& target) const;
+
+  /**
+   * Copy the characters in the range 
+   * [<tt>start</TT>, <tt>start + length</TT>) into an array of characters.
+   * All characters must be invariant (see utypes.h).
+   * Use US_INV as the last, signature-distinguishing parameter.
+   *
+   * This function does not write any more than <code>targetLength</code>
+   * characters but returns the length of the entire output string
+   * so that one can allocate a larger buffer and call the function again
+   * if necessary.
+   * The output string is NUL-terminated if possible.
+   *
+   * @param start offset of first character which will be copied
+   * @param startLength the number of characters to extract
+   * @param target the target buffer for extraction, can be NULL
+   *               if targetLength is 0
+   * @param targetCapacity the length of the target buffer
+   * @param inv Signature-distinguishing paramater, use US_INV.
+   * @return the output string length, not including the terminating NUL
+   * @stable ICU 3.2
+   */
+  int32_t extract(int32_t start,
+           int32_t startLength,
+           char *target,
+           int32_t targetCapacity,
+           enum EInvariant inv) const;
+
+#if U_CHARSET_IS_UTF8 || !UCONFIG_NO_CONVERSION
+
+  /**
+   * Copy the characters in the range
+   * [<tt>start</TT>, <tt>start + length</TT>) into an array of characters
+   * in the platform's default codepage.
+   * This function does not write any more than <code>targetLength</code>
+   * characters but returns the length of the entire output string
+   * so that one can allocate a larger buffer and call the function again
+   * if necessary.
+   * The output string is NUL-terminated if possible.
+   *
+   * @param start offset of first character which will be copied
+   * @param startLength the number of characters to extract
+   * @param target the target buffer for extraction
+   * @param targetLength the length of the target buffer
+   * If <TT>target</TT> is NULL, then the number of bytes required for
+   * <TT>target</TT> is returned.
+   * @return the output string length, not including the terminating NUL
+   * @stable ICU 2.0
+   */
+  int32_t extract(int32_t start,
+           int32_t startLength,
+           char *target,
+           uint32_t targetLength) const;
+
+#endif
+
+#if !UCONFIG_NO_CONVERSION
+
+  /**
+   * Copy the characters in the range
+   * [<tt>start</TT>, <tt>start + length</TT>) into an array of characters
+   * in a specified codepage.
+   * The output string is NUL-terminated.
+   *
+   * Recommendation: For invariant-character strings use
+   * extract(int32_t start, int32_t length, char *target, int32_t targetCapacity, enum EInvariant inv) const
+   * because it avoids object code dependencies of UnicodeString on
+   * the conversion code.
+   *
+   * @param start offset of first character which will be copied
+   * @param startLength the number of characters to extract
+   * @param target the target buffer for extraction
+   * @param codepage the desired codepage for the characters.  0 has
+   * the special meaning of the default codepage
+   * If <code>codepage</code> is an empty string (<code>""</code>),
+   * then a simple conversion is performed on the codepage-invariant
+   * subset ("invariant characters") of the platform encoding. See utypes.h.
+   * If <TT>target</TT> is NULL, then the number of bytes required for
+   * <TT>target</TT> is returned. It is assumed that the target is big enough
+   * to fit all of the characters.
+   * @return the output string length, not including the terminating NUL
+   * @stable ICU 2.0
+   */
+  inline int32_t extract(int32_t start,
+                 int32_t startLength,
+                 char *target,
+                 const char *codepage = 0) const;
+
+  /**
+   * Copy the characters in the range
+   * [<tt>start</TT>, <tt>start + length</TT>) into an array of characters
+   * in a specified codepage.
+   * This function does not write any more than <code>targetLength</code>
+   * characters but returns the length of the entire output string
+   * so that one can allocate a larger buffer and call the function again
+   * if necessary.
+   * The output string is NUL-terminated if possible.
+   *
+   * Recommendation: For invariant-character strings use
+   * extract(int32_t start, int32_t length, char *target, int32_t targetCapacity, enum EInvariant inv) const
+   * because it avoids object code dependencies of UnicodeString on
+   * the conversion code.
+   *
+   * @param start offset of first character which will be copied
+   * @param startLength the number of characters to extract
+   * @param target the target buffer for extraction
+   * @param targetLength the length of the target buffer
+   * @param codepage the desired codepage for the characters.  0 has
+   * the special meaning of the default codepage
+   * If <code>codepage</code> is an empty string (<code>""</code>),
+   * then a simple conversion is performed on the codepage-invariant
+   * subset ("invariant characters") of the platform encoding. See utypes.h.
+   * If <TT>target</TT> is NULL, then the number of bytes required for
+   * <TT>target</TT> is returned.
+   * @return the output string length, not including the terminating NUL
+   * @stable ICU 2.0
+   */
+  int32_t extract(int32_t start,
+           int32_t startLength,
+           char *target,
+           uint32_t targetLength,
+           const char *codepage) const;
+
+  /**
+   * Convert the UnicodeString into a codepage string using an existing UConverter.
+   * The output string is NUL-terminated if possible.
+   *
+   * This function avoids the overhead of opening and closing a converter if
+   * multiple strings are extracted.
+   *
+   * @param dest destination string buffer, can be NULL if destCapacity==0
+   * @param destCapacity the number of chars available at dest
+   * @param cnv the converter object to be used (ucnv_resetFromUnicode() will be called),
+   *        or NULL for the default converter
+   * @param errorCode normal ICU error code
+   * @return the length of the output string, not counting the terminating NUL;
+   *         if the length is greater than destCapacity, then the string will not fit
+   *         and a buffer of the indicated length would need to be passed in
+   * @stable ICU 2.0
+   */
+  int32_t extract(char *dest, int32_t destCapacity,
+                  UConverter *cnv,
+                  UErrorCode &errorCode) const;
+
+#endif
+
+  /**
+   * Create a temporary substring for the specified range.
+   * Unlike the substring constructor and setTo() functions,
+   * the object returned here will be a read-only alias (using getBuffer())
+   * rather than copying the text.
+   * As a result, this substring operation is much faster but requires
+   * that the original string not be modified or deleted during the lifetime
+   * of the returned substring object.
+   * @param start offset of the first character visible in the substring
+   * @param length length of the substring
+   * @return a read-only alias UnicodeString object for the substring
+   * @stable ICU 4.4
+   */
+  UnicodeString tempSubString(int32_t start=0, int32_t length=INT32_MAX) const;
+
+  /**
+   * Create a temporary substring for the specified range.
+   * Same as tempSubString(start, length) except that the substring range
+   * is specified as a (start, limit) pair (with an exclusive limit index)
+   * rather than a (start, length) pair.
+   * @param start offset of the first character visible in the substring
+   * @param limit offset immediately following the last character visible in the substring
+   * @return a read-only alias UnicodeString object for the substring
+   * @stable ICU 4.4
+   */
+  inline UnicodeString tempSubStringBetween(int32_t start, int32_t limit=INT32_MAX) const;
+
+  /**
+   * Convert the UnicodeString to UTF-8 and write the result
+   * to a ByteSink. This is called by toUTF8String().
+   * Unpaired surrogates are replaced with U+FFFD.
+   * Calls u_strToUTF8WithSub().
+   *
+   * @param sink A ByteSink to which the UTF-8 version of the string is written.
+   *             sink.Flush() is called at the end.
+   * @stable ICU 4.2
+   * @see toUTF8String
+   */
+  void toUTF8(ByteSink &sink) const;
+
+#if U_HAVE_STD_STRING
+
+  /**
+   * Convert the UnicodeString to UTF-8 and append the result
+   * to a standard string.
+   * Unpaired surrogates are replaced with U+FFFD.
+   * Calls toUTF8().
+   *
+   * @param result A standard string (or a compatible object)
+   *        to which the UTF-8 version of the string is appended.
+   * @return The string object.
+   * @stable ICU 4.2
+   * @see toUTF8
+   */
+  template<typename StringClass>
+  StringClass &toUTF8String(StringClass &result) const {
+    StringByteSink<StringClass> sbs(&result);
+    toUTF8(sbs);
+    return result;
+  }
+
+#endif
+
+  /**
+   * Convert the UnicodeString to UTF-32.
+   * Unpaired surrogates are replaced with U+FFFD.
+   * Calls u_strToUTF32WithSub().
+   *
+   * @param utf32 destination string buffer, can be NULL if capacity==0
+   * @param capacity the number of UChar32s available at utf32
+   * @param errorCode 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 length of the UTF-32 string.
+   * @see fromUTF32
+   * @stable ICU 4.2
+   */
+  int32_t toUTF32(UChar32 *utf32, int32_t capacity, UErrorCode &errorCode) const;
+
+  /* Length operations */
+
+  /**
+   * Return the length of the UnicodeString object.
+   * The length is the number of UChar code units are in the UnicodeString.
+   * If you want the number of code points, please use countChar32().
+   * @return the length of the UnicodeString object
+   * @see countChar32
+   * @stable ICU 2.0
+   */
+  inline int32_t length(void) const;
+
+  /**
+   * Count Unicode code points in the length UChar code units of the string.
+   * A code point may occupy either one or two UChar code units.
+   * Counting code points involves reading all code units.
+   *
+   * This functions is basically the inverse of moveIndex32().
+   *
+   * @param start the index of the first code unit to check
+   * @param length the number of UChar code units to check
+   * @return the number of code points in the specified code units
+   * @see length
+   * @stable ICU 2.0
+   */
+  int32_t
+  countChar32(int32_t start=0, int32_t length=INT32_MAX) const;
+
+  /**
+   * Check if the length UChar code units of the string
+   * contain more Unicode code points than a certain number.
+   * This is more efficient than counting all code points in this part of the string
+   * and comparing that number with a threshold.
+   * This function may not need to scan the string at all if the length
+   * falls within a certain range, and
+   * never needs to count more than 'number+1' code points.
+   * Logically equivalent to (countChar32(start, length)>number).
+   * A Unicode code point may occupy either one or two UChar code units.
+   *
+   * @param start the index of the first code unit to check (0 for the entire string)
+   * @param length the number of UChar code units to check
+   *               (use INT32_MAX for the entire string; remember that start/length
+   *                values are pinned)
+   * @param number The number of code points in the (sub)string is compared against
+   *               the 'number' parameter.
+   * @return Boolean value for whether the string contains more Unicode code points
+   *         than 'number'. Same as (u_countChar32(s, length)>number).
+   * @see countChar32
+   * @see u_strHasMoreChar32Than
+   * @stable ICU 2.4
+   */
+  UBool
+  hasMoreChar32Than(int32_t start, int32_t length, int32_t number) const;
+
+  /**
+   * Determine if this string is empty.
+   * @return TRUE if this string contains 0 characters, FALSE otherwise.
+   * @stable ICU 2.0
+   */
+  inline UBool isEmpty(void) const;
+
+  /**
+   * Return the capacity of the internal buffer of the UnicodeString object.
+   * This is useful together with the getBuffer functions.
+   * See there for details.
+   *
+   * @return the number of UChars available in the internal buffer
+   * @see getBuffer
+   * @stable ICU 2.0
+   */
+  inline int32_t getCapacity(void) const;
+
+  /* Other operations */
+
+  /**
+   * Generate a hash code for this object.
+   * @return The hash code of this UnicodeString.
+   * @stable ICU 2.0
+   */
+  inline int32_t hashCode(void) const;
+
+  /**
+   * Determine if this object contains a valid string.
+   * A bogus string has no value. It is different from an empty string,
+   * although in both cases isEmpty() returns TRUE and length() returns 0.
+   * setToBogus() and isBogus() can be used to indicate that no string value is available.
+   * For a bogus string, getBuffer() and getTerminatedBuffer() return NULL, and
+   * length() returns 0.
+   *
+   * @return TRUE if the string is valid, FALSE otherwise
+   * @see setToBogus()
+   * @stable ICU 2.0
+   */
+  inline UBool isBogus(void) const;
+
+
+  //========================================
+  // Write operations
+  //========================================
+
+  /* Assignment operations */
+
+  /**
+   * Assignment operator.  Replace the characters in this UnicodeString
+   * with the characters from <TT>srcText</TT>.
+   * @param srcText The text containing the characters to replace
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  UnicodeString &operator=(const UnicodeString &srcText);
+
+  /**
+   * Almost the same as the assignment operator.
+   * Replace the characters in this UnicodeString
+   * with the characters from <code>srcText</code>.
+   *
+   * This function works the same for all strings except for ones that
+   * are readonly aliases.
+   * Starting with ICU 2.4, the assignment operator and the copy constructor
+   * allocate a new buffer and copy the buffer contents even for readonly aliases.
+   * This function implements the old, more efficient but less safe behavior
+   * of making this string also a readonly alias to the same buffer.
+   * The fastCopyFrom function must be used only if it is known that the lifetime of
+   * this UnicodeString is at least as long as the lifetime of the aliased buffer
+   * including its contents, for example for strings from resource bundles
+   * or aliases to string contents.
+   *
+   * @param src The text containing the characters to replace.
+   * @return a reference to this
+   * @stable ICU 2.4
+   */
+  UnicodeString &fastCopyFrom(const UnicodeString &src);
+
+  /**
+   * Assignment operator.  Replace the characters in this UnicodeString
+   * with the code unit <TT>ch</TT>.
+   * @param ch the code unit to replace
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& operator= (UChar ch);
+
+  /**
+   * Assignment operator.  Replace the characters in this UnicodeString
+   * with the code point <TT>ch</TT>.
+   * @param ch the code point to replace
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& operator= (UChar32 ch);
+
+  /**
+   * Set the text in the UnicodeString object to the characters
+   * in <TT>srcText</TT> in the range
+   * [<TT>srcStart</TT>, <TT>srcText.length()</TT>).
+   * <TT>srcText</TT> is not modified.
+   * @param srcText the source for the new characters
+   * @param srcStart the offset into <TT>srcText</TT> where new characters
+   * will be obtained
+   * @return a reference to this
+   * @stable ICU 2.2
+   */
+  inline UnicodeString& setTo(const UnicodeString& srcText,
+               int32_t srcStart);
+
+  /**
+   * Set the text in the UnicodeString object to the characters
+   * in <TT>srcText</TT> in the range
+   * [<TT>srcStart</TT>, <TT>srcStart + srcLength</TT>).
+   * <TT>srcText</TT> is not modified.
+   * @param srcText the source for the new characters
+   * @param srcStart the offset into <TT>srcText</TT> where new characters
+   * will be obtained
+   * @param srcLength the number of characters in <TT>srcText</TT> in the
+   * replace string.
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& setTo(const UnicodeString& srcText,
+               int32_t srcStart,
+               int32_t srcLength);
+
+  /**
+   * Set the text in the UnicodeString object to the characters in
+   * <TT>srcText</TT>.
+   * <TT>srcText</TT> is not modified.
+   * @param srcText the source for the new characters
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& setTo(const UnicodeString& srcText);
+
+  /**
+   * Set the characters in the UnicodeString object to the characters
+   * in <TT>srcChars</TT>. <TT>srcChars</TT> is not modified.
+   * @param srcChars the source for the new characters
+   * @param srcLength the number of Unicode characters in srcChars.
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& setTo(const UChar *srcChars,
+               int32_t srcLength);
+
+  /**
+   * Set the characters in the UnicodeString object to the code unit
+   * <TT>srcChar</TT>.
+   * @param srcChar the code unit which becomes the UnicodeString's character
+   * content
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  UnicodeString& setTo(UChar srcChar);
+
+  /**
+   * Set the characters in the UnicodeString object to the code point
+   * <TT>srcChar</TT>.
+   * @param srcChar the code point which becomes the UnicodeString's character
+   * content
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  UnicodeString& setTo(UChar32 srcChar);
+
+  /**
+   * Aliasing setTo() function, analogous to the readonly-aliasing UChar* constructor.
+   * The text will be used for the UnicodeString object, but
+   * it will not be released when the UnicodeString is destroyed.
+   * This has copy-on-write semantics:
+   * When the string is modified, then the buffer is first copied into
+   * newly allocated memory.
+   * The aliased buffer is never modified.
+   * In an assignment to another UnicodeString, the text will be aliased again,
+   * so that both strings then alias the same readonly-text.
+   *
+   * @param isTerminated specifies if <code>text</code> is <code>NUL</code>-terminated.
+   *                     This must be true if <code>textLength==-1</code>.
+   * @param text The characters to alias for the UnicodeString.
+   * @param textLength The number of Unicode characters in <code>text</code> to alias.
+   *                   If -1, then this constructor will determine the length
+   *                   by calling <code>u_strlen()</code>.
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  UnicodeString &setTo(UBool isTerminated,
+                       const UChar *text,
+                       int32_t textLength);
+
+  /**
+   * Aliasing setTo() function, analogous to the writable-aliasing UChar* constructor.
+   * The text will be used for the UnicodeString object, but
+   * it will not be released when the UnicodeString is destroyed.
+   * This has write-through semantics:
+   * For as long as the capacity of the buffer is sufficient, write operations
+   * will directly affect the buffer. When more capacity is necessary, then
+   * a new buffer will be allocated and the contents copied as with regularly
+   * constructed strings.
+   * In an assignment to another UnicodeString, the buffer will be copied.
+   * The extract(UChar *dst) function detects whether the dst pointer is the same
+   * as the string buffer itself and will in this case not copy the contents.
+   *
+   * @param buffer The characters to alias for the UnicodeString.
+   * @param buffLength The number of Unicode characters in <code>buffer</code> to alias.
+   * @param buffCapacity The size of <code>buffer</code> in UChars.
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  UnicodeString &setTo(UChar *buffer,
+                       int32_t buffLength,
+                       int32_t buffCapacity);
+
+  /**
+   * Make this UnicodeString object invalid.
+   * The string will test TRUE with isBogus().
+   *
+   * A bogus string has no value. It is different from an empty string.
+   * It can be used to indicate that no string value is available.
+   * getBuffer() and getTerminatedBuffer() return NULL, and
+   * length() returns 0.
+   *
+   * This utility function is used throughout the UnicodeString
+   * implementation to indicate that a UnicodeString operation failed,
+   * and may be used in other functions,
+   * especially but not exclusively when such functions do not
+   * take a UErrorCode for simplicity.
+   *
+   * The following methods, and no others, will clear a string object's bogus flag:
+   * - remove()
+   * - remove(0, INT32_MAX)
+   * - truncate(0)
+   * - operator=() (assignment operator)
+   * - setTo(...)
+   *
+   * The simplest ways to turn a bogus string into an empty one
+   * is to use the remove() function.
+   * Examples for other functions that are equivalent to "set to empty string":
+   * \code
+   * if(s.isBogus()) {
+   *   s.remove();           // set to an empty string (remove all), or
+   *   s.remove(0, INT32_MAX); // set to an empty string (remove all), or
+   *   s.truncate(0);        // set to an empty string (complete truncation), or
+   *   s=UnicodeString();    // assign an empty string, or
+   *   s.setTo((UChar32)-1); // set to a pseudo code point that is out of range, or
+   *   static const UChar nul=0;
+   *   s.setTo(&nul, 0);     // set to an empty C Unicode string
+   * }
+   * \endcode
+   *
+   * @see isBogus()
+   * @stable ICU 2.0
+   */
+  void setToBogus();
+
+  /**
+   * Set the character at the specified offset to the specified character.
+   * @param offset A valid offset into the text of the character to set
+   * @param ch The new character
+   * @return A reference to this
+   * @stable ICU 2.0
+   */
+  UnicodeString& setCharAt(int32_t offset,
+               UChar ch);
+
+
+  /* Append operations */
+
+  /**
+   * Append operator. Append the code unit <TT>ch</TT> to the UnicodeString
+   * object.
+   * @param ch the code unit to be appended
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+ inline  UnicodeString& operator+= (UChar ch);
+
+  /**
+   * Append operator. Append the code point <TT>ch</TT> to the UnicodeString
+   * object.
+   * @param ch the code point to be appended
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+ inline  UnicodeString& operator+= (UChar32 ch);
+
+  /**
+   * Append operator. Append the characters in <TT>srcText</TT> to the
+   * UnicodeString object at offset <TT>start</TT>. <TT>srcText</TT> is
+   * not modified.
+   * @param srcText the source for the new characters
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& operator+= (const UnicodeString& srcText);
+
+  /**
+   * Append the characters
+   * in <TT>srcText</TT> in the range
+   * [<TT>srcStart</TT>, <TT>srcStart + srcLength</TT>) to the
+   * UnicodeString object at offset <TT>start</TT>. <TT>srcText</TT>
+   * is not modified.
+   * @param srcText the source for the new characters
+   * @param srcStart the offset into <TT>srcText</TT> where new characters
+   * will be obtained
+   * @param srcLength the number of characters in <TT>srcText</TT> in
+   * the append string
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& append(const UnicodeString& srcText,
+            int32_t srcStart,
+            int32_t srcLength);
+
+  /**
+   * Append the characters in <TT>srcText</TT> to the UnicodeString object at
+   * offset <TT>start</TT>. <TT>srcText</TT> is not modified.
+   * @param srcText the source for the new characters
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& append(const UnicodeString& srcText);
+
+  /**
+   * Append the characters in <TT>srcChars</TT> in the range
+   * [<TT>srcStart</TT>, <TT>srcStart + srcLength</TT>) to the UnicodeString
+   * object at offset
+   * <TT>start</TT>. <TT>srcChars</TT> is not modified.
+   * @param srcChars the source for the new characters
+   * @param srcStart the offset into <TT>srcChars</TT> where new characters
+   * will be obtained
+   * @param srcLength the number of characters in <TT>srcChars</TT> in
+   * the append string
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& append(const UChar *srcChars,
+            int32_t srcStart,
+            int32_t srcLength);
+
+  /**
+   * Append the characters in <TT>srcChars</TT> to the UnicodeString object
+   * at offset <TT>start</TT>. <TT>srcChars</TT> is not modified.
+   * @param srcChars the source for the new characters
+   * @param srcLength the number of Unicode characters in <TT>srcChars</TT>
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& append(const UChar *srcChars,
+            int32_t srcLength);
+
+  /**
+   * Append the code unit <TT>srcChar</TT> to the UnicodeString object.
+   * @param srcChar the code unit to append
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& append(UChar srcChar);
+
+  /**
+   * Append the code point <TT>srcChar</TT> to the UnicodeString object.
+   * @param srcChar the code point to append
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& append(UChar32 srcChar);
+
+
+  /* Insert operations */
+
+  /**
+   * Insert the characters in <TT>srcText</TT> in the range
+   * [<TT>srcStart</TT>, <TT>srcStart + srcLength</TT>) into the UnicodeString
+   * object at offset <TT>start</TT>. <TT>srcText</TT> is not modified.
+   * @param start the offset where the insertion begins
+   * @param srcText the source for the new characters
+   * @param srcStart the offset into <TT>srcText</TT> where new characters
+   * will be obtained
+   * @param srcLength the number of characters in <TT>srcText</TT> in
+   * the insert string
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& insert(int32_t start,
+            const UnicodeString& srcText,
+            int32_t srcStart,
+            int32_t srcLength);
+
+  /**
+   * Insert the characters in <TT>srcText</TT> into the UnicodeString object
+   * at offset <TT>start</TT>. <TT>srcText</TT> is not modified.
+   * @param start the offset where the insertion begins
+   * @param srcText the source for the new characters
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& insert(int32_t start,
+            const UnicodeString& srcText);
+
+  /**
+   * Insert the characters in <TT>srcChars</TT> in the range
+   * [<TT>srcStart</TT>, <TT>srcStart + srcLength</TT>) into the UnicodeString
+   *  object at offset <TT>start</TT>. <TT>srcChars</TT> is not modified.
+   * @param start the offset at which the insertion begins
+   * @param srcChars the source for the new characters
+   * @param srcStart the offset into <TT>srcChars</TT> where new characters
+   * will be obtained
+   * @param srcLength the number of characters in <TT>srcChars</TT>
+   * in the insert string
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& insert(int32_t start,
+            const UChar *srcChars,
+            int32_t srcStart,
+            int32_t srcLength);
+
+  /**
+   * Insert the characters in <TT>srcChars</TT> into the UnicodeString object
+   * at offset <TT>start</TT>. <TT>srcChars</TT> is not modified.
+   * @param start the offset where the insertion begins
+   * @param srcChars the source for the new characters
+   * @param srcLength the number of Unicode characters in srcChars.
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& insert(int32_t start,
+            const UChar *srcChars,
+            int32_t srcLength);
+
+  /**
+   * Insert the code unit <TT>srcChar</TT> into the UnicodeString object at
+   * offset <TT>start</TT>.
+   * @param start the offset at which the insertion occurs
+   * @param srcChar the code unit to insert
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& insert(int32_t start,
+            UChar srcChar);
+
+  /**
+   * Insert the code point <TT>srcChar</TT> into the UnicodeString object at
+   * offset <TT>start</TT>.
+   * @param start the offset at which the insertion occurs
+   * @param srcChar the code point to insert
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& insert(int32_t start,
+            UChar32 srcChar);
+
+
+  /* Replace operations */
+
+  /**
+   * Replace the characters in the range
+   * [<TT>start</TT>, <TT>start + length</TT>) with the characters in
+   * <TT>srcText</TT> in the range
+   * [<TT>srcStart</TT>, <TT>srcStart + srcLength</TT>).
+   * <TT>srcText</TT> is not modified.
+   * @param start the offset at which the replace operation begins
+   * @param length the number of characters to replace. The character at
+   * <TT>start + length</TT> is not modified.
+   * @param srcText the source for the new characters
+   * @param srcStart the offset into <TT>srcText</TT> where new characters
+   * will be obtained
+   * @param srcLength the number of characters in <TT>srcText</TT> in
+   * the replace string
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  UnicodeString& replace(int32_t start,
+             int32_t length,
+             const UnicodeString& srcText,
+             int32_t srcStart,
+             int32_t srcLength);
+
+  /**
+   * Replace the characters in the range
+   * [<TT>start</TT>, <TT>start + length</TT>)
+   * with the characters in <TT>srcText</TT>.  <TT>srcText</TT> is
+   *  not modified.
+   * @param start the offset at which the replace operation begins
+   * @param length the number of characters to replace. The character at
+   * <TT>start + length</TT> is not modified.
+   * @param srcText the source for the new characters
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  UnicodeString& replace(int32_t start,
+             int32_t length,
+             const UnicodeString& srcText);
+
+  /**
+   * Replace the characters in the range
+   * [<TT>start</TT>, <TT>start + length</TT>) with the characters in
+   * <TT>srcChars</TT> in the range
+   * [<TT>srcStart</TT>, <TT>srcStart + srcLength</TT>). <TT>srcChars</TT>
+   * is not modified.
+   * @param start the offset at which the replace operation begins
+   * @param length the number of characters to replace.  The character at
+   * <TT>start + length</TT> is not modified.
+   * @param srcChars the source for the new characters
+   * @param srcStart the offset into <TT>srcChars</TT> where new characters
+   * will be obtained
+   * @param srcLength the number of characters in <TT>srcChars</TT>
+   * in the replace string
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  UnicodeString& replace(int32_t start,
+             int32_t length,
+             const UChar *srcChars,
+             int32_t srcStart,
+             int32_t srcLength);
+
+  /**
+   * Replace the characters in the range
+   * [<TT>start</TT>, <TT>start + length</TT>) with the characters in
+   * <TT>srcChars</TT>.  <TT>srcChars</TT> is not modified.
+   * @param start the offset at which the replace operation begins
+   * @param length number of characters to replace.  The character at
+   * <TT>start + length</TT> is not modified.
+   * @param srcChars the source for the new characters
+   * @param srcLength the number of Unicode characters in srcChars
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& replace(int32_t start,
+             int32_t length,
+             const UChar *srcChars,
+             int32_t srcLength);
+
+  /**
+   * Replace the characters in the range
+   * [<TT>start</TT>, <TT>start + length</TT>) with the code unit
+   * <TT>srcChar</TT>.
+   * @param start the offset at which the replace operation begins
+   * @param length the number of characters to replace.  The character at
+   * <TT>start + length</TT> is not modified.
+   * @param srcChar the new code unit
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& replace(int32_t start,
+             int32_t length,
+             UChar srcChar);
+
+  /**
+   * Replace the characters in the range
+   * [<TT>start</TT>, <TT>start + length</TT>) with the code point
+   * <TT>srcChar</TT>.
+   * @param start the offset at which the replace operation begins
+   * @param length the number of characters to replace.  The character at
+   * <TT>start + length</TT> is not modified.
+   * @param srcChar the new code point
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& replace(int32_t start,
+             int32_t length,
+             UChar32 srcChar);
+
+  /**
+   * Replace the characters in the range [<TT>start</TT>, <TT>limit</TT>)
+   * with the characters in <TT>srcText</TT>. <TT>srcText</TT> is not modified.
+   * @param start the offset at which the replace operation begins
+   * @param limit the offset immediately following the replace range
+   * @param srcText the source for the new characters
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& replaceBetween(int32_t start,
+                int32_t limit,
+                const UnicodeString& srcText);
+
+  /**
+   * Replace the characters in the range [<TT>start</TT>, <TT>limit</TT>)
+   * with the characters in <TT>srcText</TT> in the range
+   * [<TT>srcStart</TT>, <TT>srcLimit</TT>). <TT>srcText</TT> is not modified.
+   * @param start the offset at which the replace operation begins
+   * @param limit the offset immediately following the replace range
+   * @param srcText the source for the new characters
+   * @param srcStart the offset into <TT>srcChars</TT> where new characters
+   * will be obtained
+   * @param srcLimit the offset immediately following the range to copy
+   * in <TT>srcText</TT>
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& replaceBetween(int32_t start,
+                int32_t limit,
+                const UnicodeString& srcText,
+                int32_t srcStart,
+                int32_t srcLimit);
+
+  /**
+   * Replace a substring of this object with the given text.
+   * @param start the beginning index, inclusive; <code>0 <= start
+   * <= limit</code>.
+   * @param limit the ending index, exclusive; <code>start <= limit
+   * <= length()</code>.
+   * @param text the text to replace characters <code>start</code>
+   * to <code>limit - 1</code>
+   * @stable ICU 2.0
+   */
+  virtual void handleReplaceBetween(int32_t start,
+                                    int32_t limit,
+                                    const UnicodeString& text);
+
+  /**
+   * Replaceable API
+   * @return TRUE if it has MetaData
+   * @stable ICU 2.4
+   */
+  virtual UBool hasMetaData() const;
+
+  /**
+   * Copy a substring of this object, retaining attribute (out-of-band)
+   * information.  This method is used to duplicate or reorder substrings.
+   * The destination index must not overlap the source range.
+   *
+   * @param start the beginning index, inclusive; <code>0 <= start <=
+   * limit</code>.
+   * @param limit the ending index, exclusive; <code>start <= limit <=
+   * length()</code>.
+   * @param dest the destination index.  The characters from
+   * <code>start..limit-1</code> will be copied to <code>dest</code>.
+   * Implementations of this method may assume that <code>dest <= start ||
+   * dest >= limit</code>.
+   * @stable ICU 2.0
+   */
+  virtual void copy(int32_t start, int32_t limit, int32_t dest);
+
+  /* Search and replace operations */
+
+  /**
+   * Replace all occurrences of characters in oldText with the characters
+   * in newText
+   * @param oldText the text containing the search text
+   * @param newText the text containing the replacement text
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& findAndReplace(const UnicodeString& oldText,
+                const UnicodeString& newText);
+
+  /**
+   * Replace all occurrences of characters in oldText with characters
+   * in newText
+   * in the range [<TT>start</TT>, <TT>start + length</TT>).
+   * @param start the start of the range in which replace will performed
+   * @param length the length of the range in which replace will be performed
+   * @param oldText the text containing the search text
+   * @param newText the text containing the replacement text
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& findAndReplace(int32_t start,
+                int32_t length,
+                const UnicodeString& oldText,
+                const UnicodeString& newText);
+
+  /**
+   * Replace all occurrences of characters in oldText in the range
+   * [<TT>oldStart</TT>, <TT>oldStart + oldLength</TT>) with the characters
+   * in newText in the range
+   * [<TT>newStart</TT>, <TT>newStart + newLength</TT>)
+   * in the range [<TT>start</TT>, <TT>start + length</TT>).
+   * @param start the start of the range in which replace will performed
+   * @param length the length of the range in which replace will be performed
+   * @param oldText the text containing the search text
+   * @param oldStart the start of the search range in <TT>oldText</TT>
+   * @param oldLength the length of the search range in <TT>oldText</TT>
+   * @param newText the text containing the replacement text
+   * @param newStart the start of the replacement range in <TT>newText</TT>
+   * @param newLength the length of the replacement range in <TT>newText</TT>
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  UnicodeString& findAndReplace(int32_t start,
+                int32_t length,
+                const UnicodeString& oldText,
+                int32_t oldStart,
+                int32_t oldLength,
+                const UnicodeString& newText,
+                int32_t newStart,
+                int32_t newLength);
+
+
+  /* Remove operations */
+
+  /**
+   * Remove all characters from the UnicodeString object.
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& remove(void);
+
+  /**
+   * Remove the characters in the range
+   * [<TT>start</TT>, <TT>start + length</TT>) from the UnicodeString object.
+   * @param start the offset of the first character to remove
+   * @param length the number of characters to remove
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& remove(int32_t start,
+                               int32_t length = (int32_t)INT32_MAX);
+
+  /**
+   * Remove the characters in the range
+   * [<TT>start</TT>, <TT>limit</TT>) from the UnicodeString object.
+   * @param start the offset of the first character to remove
+   * @param limit the offset immediately following the range to remove
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& removeBetween(int32_t start,
+                                      int32_t limit = (int32_t)INT32_MAX);
+
+  /**
+   * Retain only the characters in the range
+   * [<code>start</code>, <code>limit</code>) from the UnicodeString object.
+   * Removes characters before <code>start</code> and at and after <code>limit</code>.
+   * @param start the offset of the first character to retain
+   * @param limit the offset immediately following the range to retain
+   * @return a reference to this
+   * @stable ICU 4.4
+   */
+  inline UnicodeString &retainBetween(int32_t start, int32_t limit = INT32_MAX);
+
+  /* Length operations */
+
+  /**
+   * Pad the start of this UnicodeString with the character <TT>padChar</TT>.
+   * If the length of this UnicodeString is less than targetLength,
+   * length() - targetLength copies of padChar will be added to the
+   * beginning of this UnicodeString.
+   * @param targetLength the desired length of the string
+   * @param padChar the character to use for padding. Defaults to
+   * space (U+0020)
+   * @return TRUE if the text was padded, FALSE otherwise.
+   * @stable ICU 2.0
+   */
+  UBool padLeading(int32_t targetLength,
+                    UChar padChar = 0x0020);
+
+  /**
+   * Pad the end of this UnicodeString with the character <TT>padChar</TT>.
+   * If the length of this UnicodeString is less than targetLength,
+   * length() - targetLength copies of padChar will be added to the
+   * end of this UnicodeString.
+   * @param targetLength the desired length of the string
+   * @param padChar the character to use for padding. Defaults to
+   * space (U+0020)
+   * @return TRUE if the text was padded, FALSE otherwise.
+   * @stable ICU 2.0
+   */
+  UBool padTrailing(int32_t targetLength,
+                     UChar padChar = 0x0020);
+
+  /**
+   * Truncate this UnicodeString to the <TT>targetLength</TT>.
+   * @param targetLength the desired length of this UnicodeString.
+   * @return TRUE if the text was truncated, FALSE otherwise
+   * @stable ICU 2.0
+   */
+  inline UBool truncate(int32_t targetLength);
+
+  /**
+   * Trims leading and trailing whitespace from this UnicodeString.
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  UnicodeString& trim(void);
+
+
+  /* Miscellaneous operations */
+
+  /**
+   * Reverse this UnicodeString in place.
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& reverse(void);
+
+  /**
+   * Reverse the range [<TT>start</TT>, <TT>start + length</TT>) in
+   * this UnicodeString.
+   * @param start the start of the range to reverse
+   * @param length the number of characters to to reverse
+   * @return a reference to this
+   * @stable ICU 2.0
+   */
+  inline UnicodeString& reverse(int32_t start,
+             int32_t length);
+
+  /**
+   * Convert the characters in this to UPPER CASE following the conventions of
+   * the default locale.
+   * @return A reference to this.
+   * @stable ICU 2.0
+   */
+  UnicodeString& toUpper(void);
+
+  /**
+   * Convert the characters in this to UPPER CASE following the conventions of
+   * a specific locale.
+   * @param locale The locale containing the conventions to use.
+   * @return A reference to this.
+   * @stable ICU 2.0
+   */
+  UnicodeString& toUpper(const Locale& locale);
+
+  /**
+   * Convert the characters in this to lower case following the conventions of
+   * the default locale.
+   * @return A reference to this.
+   * @stable ICU 2.0
+   */
+  UnicodeString& toLower(void);
+
+  /**
+   * Convert the characters in this to lower case following the conventions of
+   * a specific locale.
+   * @param locale The locale containing the conventions to use.
+   * @return A reference to this.
+   * @stable ICU 2.0
+   */
+  UnicodeString& toLower(const Locale& locale);
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+  /**
+   * Titlecase this string, convenience function using the default locale.
+   *
+   * Casing is locale-dependent and context-sensitive.
+   * Titlecasing uses a break iterator to find the first characters of words
+   * that are to be titlecased. It titlecases those characters and lowercases
+   * all others.
+   *
+   * The titlecase break iterator can be provided to customize for arbitrary
+   * styles, using rules and dictionaries beyond the standard iterators.
+   * It may be more efficient to always provide an iterator to avoid
+   * opening and closing one for each string.
+   * The standard titlecase iterator for the root locale implements the
+   * algorithm of Unicode TR 21.
+   *
+   * This function uses only the setText(), first() and next() methods of the
+   * provided break iterator.
+   *
+   * @param titleIter A break iterator to find the first characters of words
+   *                  that are to be titlecased.
+   *                  If none is provided (0), then a standard titlecase
+   *                  break iterator is opened.
+   *                  Otherwise the provided iterator is set to the string's text.
+   * @return A reference to this.
+   * @stable ICU 2.1
+   */
+  UnicodeString &toTitle(BreakIterator *titleIter);
+
+  /**
+   * Titlecase this string.
+   *
+   * Casing is locale-dependent and context-sensitive.
+   * Titlecasing uses a break iterator to find the first characters of words
+   * that are to be titlecased. It titlecases those characters and lowercases
+   * all others.
+   *
+   * The titlecase break iterator can be provided to customize for arbitrary
+   * styles, using rules and dictionaries beyond the standard iterators.
+   * It may be more efficient to always provide an iterator to avoid
+   * opening and closing one for each string.
+   * The standard titlecase iterator for the root locale implements the
+   * algorithm of Unicode TR 21.
+   *
+   * This function uses only the setText(), first() and next() methods of the
+   * provided break iterator.
+   *
+   * @param titleIter A break iterator to find the first characters of words
+   *                  that are to be titlecased.
+   *                  If none is provided (0), then a standard titlecase
+   *                  break iterator is opened.
+   *                  Otherwise the provided iterator is set to the string's text.
+   * @param locale    The locale to consider.
+   * @return A reference to this.
+   * @stable ICU 2.1
+   */
+  UnicodeString &toTitle(BreakIterator *titleIter, const Locale &locale);
+
+  /**
+   * Titlecase this string, with options.
+   *
+   * Casing is locale-dependent and context-sensitive.
+   * Titlecasing uses a break iterator to find the first characters of words
+   * that are to be titlecased. It titlecases those characters and lowercases
+   * all others. (This can be modified with options.)
+   *
+   * The titlecase break iterator can be provided to customize for arbitrary
+   * styles, using rules and dictionaries beyond the standard iterators.
+   * It may be more efficient to always provide an iterator to avoid
+   * opening and closing one for each string.
+   * The standard titlecase iterator for the root locale implements the
+   * algorithm of Unicode TR 21.
+   *
+   * This function uses only the setText(), first() and next() methods of the
+   * provided break iterator.
+   *
+   * @param titleIter A break iterator to find the first characters of words
+   *                  that are to be titlecased.
+   *                  If none is provided (0), then a standard titlecase
+   *                  break iterator is opened.
+   *                  Otherwise the provided iterator is set to the string's text.
+   * @param locale    The locale to consider.
+   * @param options Options bit set, see ucasemap_open().
+   * @return A reference to this.
+   * @see U_TITLECASE_NO_LOWERCASE
+   * @see U_TITLECASE_NO_BREAK_ADJUSTMENT
+   * @see ucasemap_open
+   * @stable ICU 3.8
+   */
+  UnicodeString &toTitle(BreakIterator *titleIter, const Locale &locale, uint32_t options);
+
+#endif
+
+  /**
+   * Case-fold the characters in this string.
+   * Case-folding is locale-independent and not context-sensitive,
+   * but there is an option for whether to include or exclude mappings for dotted I
+   * and dotless i that are marked with 'I' in CaseFolding.txt.
+   * The result may be longer or shorter than the original.
+   *
+   * @param options Either U_FOLD_CASE_DEFAULT or U_FOLD_CASE_EXCLUDE_SPECIAL_I
+   * @return A reference to this.
+   * @stable ICU 2.0
+   */
+  UnicodeString &foldCase(uint32_t options=0 /*U_FOLD_CASE_DEFAULT*/);
+
+  //========================================
+  // Access to the internal buffer
+  //========================================
+
+  /**
+   * Get a read/write pointer to the internal buffer.
+   * The buffer is guaranteed to be large enough for at least minCapacity UChars,
+   * writable, and is still owned by the UnicodeString object.
+   * Calls to getBuffer(minCapacity) must not be nested, and
+   * must be matched with calls to releaseBuffer(newLength).
+   * If the string buffer was read-only or shared,
+   * then it will be reallocated and copied.
+   *
+   * An attempted nested call will return 0, and will not further modify the
+   * state of the UnicodeString object.
+   * It also returns 0 if the string is bogus.
+   *
+   * The actual capacity of the string buffer may be larger than minCapacity.
+   * getCapacity() returns the actual capacity.
+   * For many operations, the full capacity should be used to avoid reallocations.
+   *
+   * While the buffer is "open" between getBuffer(minCapacity)
+   * and releaseBuffer(newLength), the following applies:
+   * - The string length is set to 0.
+   * - Any read API call on the UnicodeString object will behave like on a 0-length string.
+   * - Any write API call on the UnicodeString object is disallowed and will have no effect.
+   * - You can read from and write to the returned buffer.
+   * - The previous string contents will still be in the buffer;
+   *   if you want to use it, then you need to call length() before getBuffer(minCapacity).
+   *   If the length() was greater than minCapacity, then any contents after minCapacity
+   *   may be lost.
+   *   The buffer contents is not NUL-terminated by getBuffer().
+   *   If length()<getCapacity() then you can terminate it by writing a NUL
+   *   at index length().
+   * - You must call releaseBuffer(newLength) before and in order to
+   *   return to normal UnicodeString operation.
+   *
+   * @param minCapacity the minimum number of UChars that are to be available
+   *        in the buffer, starting at the returned pointer;
+   *        default to the current string capacity if minCapacity==-1
+   * @return a writable pointer to the internal string buffer,
+   *         or 0 if an error occurs (nested calls, out of memory)
+   *
+   * @see releaseBuffer
+   * @see getTerminatedBuffer()
+   * @stable ICU 2.0
+   */
+  UChar *getBuffer(int32_t minCapacity);
+
+  /**
+   * Release a read/write buffer on a UnicodeString object with an
+   * "open" getBuffer(minCapacity).
+   * This function must be called in a matched pair with getBuffer(minCapacity).
+   * releaseBuffer(newLength) must be called if and only if a getBuffer(minCapacity) is "open".
+   *
+   * It will set the string length to newLength, at most to the current capacity.
+   * If newLength==-1 then it will set the length according to the
+   * first NUL in the buffer, or to the capacity if there is no NUL.
+   *
+   * After calling releaseBuffer(newLength) the UnicodeString is back to normal operation.
+   *
+   * @param newLength the new length of the UnicodeString object;
+   *        defaults to the current capacity if newLength is greater than that;
+   *        if newLength==-1, it defaults to u_strlen(buffer) but not more than
+   *        the current capacity of the string
+   *
+   * @see getBuffer(int32_t minCapacity)
+   * @stable ICU 2.0
+   */
+  void releaseBuffer(int32_t newLength=-1);
+
+  /**
+   * Get a read-only pointer to the internal buffer.
+   * This can be called at any time on a valid UnicodeString.
+   *
+   * It returns 0 if the string is bogus, or
+   * during an "open" getBuffer(minCapacity).
+   *
+   * It can be called as many times as desired.
+   * The pointer that it returns will remain valid until the UnicodeString object is modified,
+   * at which time the pointer is semantically invalidated and must not be used any more.
+   *
+   * The capacity of the buffer can be determined with getCapacity().
+   * The part after length() may or may not be initialized and valid,
+   * depending on the history of the UnicodeString object.
+   *
+   * The buffer contents is (probably) not NUL-terminated.
+   * You can check if it is with
+   * <code>(s.length()<s.getCapacity() && buffer[s.length()]==0)</code>.
+   * (See getTerminatedBuffer().)
+   *
+   * The buffer may reside in read-only memory. Its contents must not
+   * be modified.
+   *
+   * @return a read-only pointer to the internal string buffer,
+   *         or 0 if the string is empty or bogus
+   *
+   * @see getBuffer(int32_t minCapacity)
+   * @see getTerminatedBuffer()
+   * @stable ICU 2.0
+   */
+  inline const UChar *getBuffer() const;
+
+  /**
+   * Get a read-only pointer to the internal buffer,
+   * making sure that it is NUL-terminated.
+   * This can be called at any time on a valid UnicodeString.
+   *
+   * It returns 0 if the string is bogus, or
+   * during an "open" getBuffer(minCapacity), or if the buffer cannot
+   * be NUL-terminated (because memory allocation failed).
+   *
+   * It can be called as many times as desired.
+   * The pointer that it returns will remain valid until the UnicodeString object is modified,
+   * at which time the pointer is semantically invalidated and must not be used any more.
+   *
+   * The capacity of the buffer can be determined with getCapacity().
+   * The part after length()+1 may or may not be initialized and valid,
+   * depending on the history of the UnicodeString object.
+   *
+   * The buffer contents is guaranteed to be NUL-terminated.
+   * getTerminatedBuffer() may reallocate the buffer if a terminating NUL
+   * is written.
+   * For this reason, this function is not const, unlike getBuffer().
+   * Note that a UnicodeString may also contain NUL characters as part of its contents.
+   *
+   * The buffer may reside in read-only memory. Its contents must not
+   * be modified.
+   *
+   * @return a read-only pointer to the internal string buffer,
+   *         or 0 if the string is empty or bogus
+   *
+   * @see getBuffer(int32_t minCapacity)
+   * @see getBuffer()
+   * @stable ICU 2.2
+   */
+  inline const UChar *getTerminatedBuffer();
+
+  //========================================
+  // Constructors
+  //========================================
+
+  /** Construct an empty UnicodeString.
+   * @stable ICU 2.0
+   */
+  UnicodeString();
+
+  /**
+   * Construct a UnicodeString with capacity to hold <TT>capacity</TT> UChars
+   * @param capacity the number of UChars this UnicodeString should hold
+   * before a resize is necessary; if count is greater than 0 and count
+   * code points c take up more space than capacity, then capacity is adjusted
+   * accordingly.
+   * @param c is used to initially fill the string
+   * @param count specifies how many code points c are to be written in the
+   *              string
+   * @stable ICU 2.0
+   */
+  UnicodeString(int32_t capacity, UChar32 c, int32_t count);
+
+  /**
+   * Single UChar (code unit) constructor.
+   * @param ch the character to place in the UnicodeString
+   * @stable ICU 2.0
+   */
+  UnicodeString(UChar ch);
+
+  /**
+   * Single UChar32 (code point) constructor.
+   * @param ch the character to place in the UnicodeString
+   * @stable ICU 2.0
+   */
+  UnicodeString(UChar32 ch);
+
+  /**
+   * UChar* constructor.
+   * @param text The characters to place in the UnicodeString.  <TT>text</TT>
+   * must be NULL (U+0000) terminated.
+   * @stable ICU 2.0
+   */
+  UnicodeString(const UChar *text);
+
+  /**
+   * UChar* constructor.
+   * @param text The characters to place in the UnicodeString.
+   * @param textLength The number of Unicode characters in <TT>text</TT>
+   * to copy.
+   * @stable ICU 2.0
+   */
+  UnicodeString(const UChar *text,
+        int32_t textLength);
+
+  /**
+   * Readonly-aliasing UChar* constructor.
+   * The text will be used for the UnicodeString object, but
+   * it will not be released when the UnicodeString is destroyed.
+   * This has copy-on-write semantics:
+   * When the string is modified, then the buffer is first copied into
+   * newly allocated memory.
+   * The aliased buffer is never modified.
+   * In an assignment to another UnicodeString, the text will be aliased again,
+   * so that both strings then alias the same readonly-text.
+   *
+   * @param isTerminated specifies if <code>text</code> is <code>NUL</code>-terminated.
+   *                     This must be true if <code>textLength==-1</code>.
+   * @param text The characters to alias for the UnicodeString.
+   * @param textLength The number of Unicode characters in <code>text</code> to alias.
+   *                   If -1, then this constructor will determine the length
+   *                   by calling <code>u_strlen()</code>.
+   * @stable ICU 2.0
+   */
+  UnicodeString(UBool isTerminated,
+                const UChar *text,
+                int32_t textLength);
+
+  /**
+   * Writable-aliasing UChar* constructor.
+   * The text will be used for the UnicodeString object, but
+   * it will not be released when the UnicodeString is destroyed.
+   * This has write-through semantics:
+   * For as long as the capacity of the buffer is sufficient, write operations
+   * will directly affect the buffer. When more capacity is necessary, then
+   * a new buffer will be allocated and the contents copied as with regularly
+   * constructed strings.
+   * In an assignment to another UnicodeString, the buffer will be copied.
+   * The extract(UChar *dst) function detects whether the dst pointer is the same
+   * as the string buffer itself and will in this case not copy the contents.
+   *
+   * @param buffer The characters to alias for the UnicodeString.
+   * @param buffLength The number of Unicode characters in <code>buffer</code> to alias.
+   * @param buffCapacity The size of <code>buffer</code> in UChars.
+   * @stable ICU 2.0
+   */
+  UnicodeString(UChar *buffer, int32_t buffLength, int32_t buffCapacity);
+
+#if U_CHARSET_IS_UTF8 || !UCONFIG_NO_CONVERSION
+
+  /**
+   * char* constructor.
+   * @param codepageData an array of bytes, null-terminated,
+   *                     in the platform's default codepage.
+   * @stable ICU 2.0
+   */
+  UnicodeString(const char *codepageData);
+
+  /**
+   * char* constructor.
+   * @param codepageData an array of bytes in the platform's default codepage.
+   * @param dataLength The number of bytes in <TT>codepageData</TT>.
+   * @stable ICU 2.0
+   */
+  UnicodeString(const char *codepageData, int32_t dataLength);
+
+#endif
+
+#if !UCONFIG_NO_CONVERSION
+
+  /**
+   * char* constructor.
+   * @param codepageData an array of bytes, null-terminated
+   * @param codepage the encoding of <TT>codepageData</TT>.  The special
+   * value 0 for <TT>codepage</TT> indicates that the text is in the
+   * platform's default codepage.
+   *
+   * If <code>codepage</code> is an empty string (<code>""</code>),
+   * then a simple conversion is performed on the codepage-invariant
+   * subset ("invariant characters") of the platform encoding. See utypes.h.
+   * Recommendation: For invariant-character strings use the constructor
+   * UnicodeString(const char *src, int32_t length, enum EInvariant inv)
+   * because it avoids object code dependencies of UnicodeString on
+   * the conversion code.
+   *
+   * @stable ICU 2.0
+   */
+  UnicodeString(const char *codepageData, const char *codepage);
+
+  /**
+   * char* constructor.
+   * @param codepageData an array of bytes.
+   * @param dataLength The number of bytes in <TT>codepageData</TT>.
+   * @param codepage the encoding of <TT>codepageData</TT>.  The special
+   * value 0 for <TT>codepage</TT> indicates that the text is in the
+   * platform's default codepage.
+   * If <code>codepage</code> is an empty string (<code>""</code>),
+   * then a simple conversion is performed on the codepage-invariant
+   * subset ("invariant characters") of the platform encoding. See utypes.h.
+   * Recommendation: For invariant-character strings use the constructor
+   * UnicodeString(const char *src, int32_t length, enum EInvariant inv)
+   * because it avoids object code dependencies of UnicodeString on
+   * the conversion code.
+   *
+   * @stable ICU 2.0
+   */
+  UnicodeString(const char *codepageData, int32_t dataLength, const char *codepage);
+
+  /**
+   * char * / UConverter constructor.
+   * This constructor uses an existing UConverter object to
+   * convert the codepage string to Unicode and construct a UnicodeString
+   * from that.
+   *
+   * The converter is reset at first.
+   * If the error code indicates a failure before this constructor is called,
+   * or if an error occurs during conversion or construction,
+   * then the string will be bogus.
+   *
+   * This function avoids the overhead of opening and closing a converter if
+   * multiple strings are constructed.
+   *
+   * @param src input codepage string
+   * @param srcLength length of the input string, can be -1 for NUL-terminated strings
+   * @param cnv converter object (ucnv_resetToUnicode() will be called),
+   *        can be NULL for the default converter
+   * @param errorCode normal ICU error code
+   * @stable ICU 2.0
+   */
+  UnicodeString(
+        const char *src, int32_t srcLength,
+        UConverter *cnv,
+        UErrorCode &errorCode);
+
+#endif
+
+  /**
+   * Constructs a Unicode string from an invariant-character char * string.
+   * About invariant characters see utypes.h.
+   * This constructor has no runtime dependency on conversion code and is
+   * therefore recommended over ones taking a charset name string
+   * (where the empty string "" indicates invariant-character conversion).
+   *
+   * Use the macro US_INV as the third, signature-distinguishing parameter.
+   *
+   * For example:
+   * \code
+   * void fn(const char *s) {
+   *   UnicodeString ustr(s, -1, US_INV);
+   *   // use ustr ...
+   * }
+   * \endcode
+   *
+   * @param src String using only invariant characters.
+   * @param length Length of src, or -1 if NUL-terminated.
+   * @param inv Signature-distinguishing paramater, use US_INV.
+   *
+   * @see US_INV
+   * @stable ICU 3.2
+   */
+  UnicodeString(const char *src, int32_t length, enum EInvariant inv);
+
+
+  /**
+   * Copy constructor.
+   * @param that The UnicodeString object to copy.
+   * @stable ICU 2.0
+   */
+  UnicodeString(const UnicodeString& that);
+
+  /**
+   * 'Substring' constructor from tail of source string.
+   * @param src The UnicodeString object to copy.
+   * @param srcStart The offset into <tt>src</tt> at which to start copying.
+   * @stable ICU 2.2
+   */
+  UnicodeString(const UnicodeString& src, int32_t srcStart);
+
+  /**
+   * 'Substring' constructor from subrange of source string.
+   * @param src The UnicodeString object to copy.
+   * @param srcStart The offset into <tt>src</tt> at which to start copying.
+   * @param srcLength The number of characters from <tt>src</tt> to copy.
+   * @stable ICU 2.2
+   */
+  UnicodeString(const UnicodeString& src, int32_t srcStart, int32_t srcLength);
+
+  /**
+   * Clone this object, an instance of a subclass of Replaceable.
+   * Clones can be used concurrently in multiple threads.
+   * If a subclass does not implement clone(), or if an error occurs,
+   * then NULL is returned.
+   * The clone functions in all subclasses return a pointer to a Replaceable
+   * because some compilers do not support covariant (same-as-this)
+   * return types; cast to the appropriate subclass if necessary.
+   * The caller must delete the clone.
+   *
+   * @return a clone of this object
+   *
+   * @see Replaceable::clone
+   * @see getDynamicClassID
+   * @stable ICU 2.6
+   */
+  virtual Replaceable *clone() const;
+
+  /** Destructor.
+   * @stable ICU 2.0
+   */
+  virtual ~UnicodeString();
+
+  /**
+   * Create a UnicodeString from a UTF-8 string.
+   * Illegal input is replaced with U+FFFD. Otherwise, errors result in a bogus string.
+   * Calls u_strFromUTF8WithSub().
+   *
+   * @param utf8 UTF-8 input string.
+   *             Note that a StringPiece can be implicitly constructed
+   *             from a std::string or a NUL-terminated const char * string.
+   * @return A UnicodeString with equivalent UTF-16 contents.
+   * @see toUTF8
+   * @see toUTF8String
+   * @stable ICU 4.2
+   */
+  static UnicodeString fromUTF8(const StringPiece &utf8);
+
+  /**
+   * Create a UnicodeString from a UTF-32 string.
+   * Illegal input is replaced with U+FFFD. Otherwise, errors result in a bogus string.
+   * Calls u_strFromUTF32WithSub().
+   *
+   * @param utf32 UTF-32 input string. Must not be NULL.
+   * @param length Length of the input string, or -1 if NUL-terminated.
+   * @return A UnicodeString with equivalent UTF-16 contents.
+   * @see toUTF32
+   * @stable ICU 4.2
+   */
+  static UnicodeString fromUTF32(const UChar32 *utf32, int32_t length);
+
+  /* Miscellaneous operations */
+
+  /**
+   * Unescape a string of characters and return a string containing
+   * the result.  The following escape sequences are recognized:
+   *
+   * \\uhhhh       4 hex digits; h in [0-9A-Fa-f]
+   * \\Uhhhhhhhh   8 hex digits
+   * \\xhh         1-2 hex digits
+   * \\ooo         1-3 octal digits; o in [0-7]
+   * \\cX          control-X; X is masked with 0x1F
+   *
+   * as well as the standard ANSI C escapes:
+   *
+   * \\a => U+0007, \\b => U+0008, \\t => U+0009, \\n => U+000A,
+   * \\v => U+000B, \\f => U+000C, \\r => U+000D, \\e => U+001B,
+   * \\&quot; => U+0022, \\' => U+0027, \\? => U+003F, \\\\ => U+005C
+   *
+   * Anything else following a backslash is generically escaped.  For
+   * example, "[a\\-z]" returns "[a-z]".
+   *
+   * If an escape sequence is ill-formed, this method returns an empty
+   * string.  An example of an ill-formed sequence is "\\u" followed by
+   * fewer than 4 hex digits.
+   *
+   * This function is similar to u_unescape() but not identical to it.
+   * The latter takes a source char*, so it does escape recognition
+   * and also invariant conversion.
+   *
+   * @return a string with backslash escapes interpreted, or an
+   * empty string on error.
+   * @see UnicodeString#unescapeAt()
+   * @see u_unescape()
+   * @see u_unescapeAt()
+   * @stable ICU 2.0
+   */
+  UnicodeString unescape() const;
+
+  /**
+   * Unescape a single escape sequence and return the represented
+   * character.  See unescape() for a listing of the recognized escape
+   * sequences.  The character at offset-1 is assumed (without
+   * checking) to be a backslash.  If the escape sequence is
+   * ill-formed, or the offset is out of range, (UChar32)0xFFFFFFFF is
+   * returned.
+   *
+   * @param offset an input output parameter.  On input, it is the
+   * offset into this string where the escape sequence is located,
+   * after the initial backslash.  On output, it is advanced after the
+   * last character parsed.  On error, it is not advanced at all.
+   * @return the character represented by the escape sequence at
+   * offset, or (UChar32)0xFFFFFFFF on error.
+   * @see UnicodeString#unescape()
+   * @see u_unescape()
+   * @see u_unescapeAt()
+   * @stable ICU 2.0
+   */
+  UChar32 unescapeAt(int32_t &offset) const;
+
+  /**
+   * 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;
+
+  //========================================
+  // Implementation methods
+  //========================================
+
+protected:
+  /**
+   * Implement Replaceable::getLength() (see jitterbug 1027).
+   * @stable ICU 2.4
+   */
+  virtual int32_t getLength() const;
+
+  /**
+   * The change in Replaceable to use virtual getCharAt() allows
+   * UnicodeString::charAt() to be inline again (see jitterbug 709).
+   * @stable ICU 2.4
+   */
+  virtual UChar getCharAt(int32_t offset) const;
+
+  /**
+   * The change in Replaceable to use virtual getChar32At() allows
+   * UnicodeString::char32At() to be inline again (see jitterbug 709).
+   * @stable ICU 2.4
+   */
+  virtual UChar32 getChar32At(int32_t offset) const;
+
+private:
+  // For char* constructors. Could be made public.
+  UnicodeString &setToUTF8(const StringPiece &utf8);
+  // For extract(char*).
+  // We could make a toUTF8(target, capacity, errorCode) public but not
+  // this version: New API will be cleaner if we make callers create substrings
+  // rather than having start+length on every method,
+  // and it should take a UErrorCode&.
+  int32_t
+  toUTF8(int32_t start, int32_t len,
+         char *target, int32_t capacity) const;
+
+
+  inline int8_t
+  doCompare(int32_t start,
+           int32_t length,
+           const UnicodeString& srcText,
+           int32_t srcStart,
+           int32_t srcLength) const;
+
+  int8_t doCompare(int32_t start,
+           int32_t length,
+           const UChar *srcChars,
+           int32_t srcStart,
+           int32_t srcLength) const;
+
+  inline int8_t
+  doCompareCodePointOrder(int32_t start,
+                          int32_t length,
+                          const UnicodeString& srcText,
+                          int32_t srcStart,
+                          int32_t srcLength) const;
+
+  int8_t doCompareCodePointOrder(int32_t start,
+                                 int32_t length,
+                                 const UChar *srcChars,
+                                 int32_t srcStart,
+                                 int32_t srcLength) const;
+
+  inline int8_t
+  doCaseCompare(int32_t start,
+                int32_t length,
+                const UnicodeString &srcText,
+                int32_t srcStart,
+                int32_t srcLength,
+                uint32_t options) const;
+
+  int8_t
+  doCaseCompare(int32_t start,
+                int32_t length,
+                const UChar *srcChars,
+                int32_t srcStart,
+                int32_t srcLength,
+                uint32_t options) const;
+
+  int32_t doIndexOf(UChar c,
+            int32_t start,
+            int32_t length) const;
+
+  int32_t doIndexOf(UChar32 c,
+                        int32_t start,
+                        int32_t length) const;
+
+  int32_t doLastIndexOf(UChar c,
+                int32_t start,
+                int32_t length) const;
+
+  int32_t doLastIndexOf(UChar32 c,
+                            int32_t start,
+                            int32_t length) const;
+
+  void doExtract(int32_t start,
+         int32_t length,
+         UChar *dst,
+         int32_t dstStart) const;
+
+  inline void doExtract(int32_t start,
+         int32_t length,
+         UnicodeString& target) const;
+
+  inline UChar doCharAt(int32_t offset)  const;
+
+  UnicodeString& doReplace(int32_t start,
+               int32_t length,
+               const UnicodeString& srcText,
+               int32_t srcStart,
+               int32_t srcLength);
+
+  UnicodeString& doReplace(int32_t start,
+               int32_t length,
+               const UChar *srcChars,
+               int32_t srcStart,
+               int32_t srcLength);
+
+  UnicodeString& doReverse(int32_t start,
+               int32_t length);
+
+  // calculate hash code
+  int32_t doHashCode(void) const;
+
+  // get pointer to start of array
+  // these do not check for kOpenGetBuffer, unlike the public getBuffer() function
+  inline UChar* getArrayStart(void);
+  inline const UChar* getArrayStart(void) const;
+
+  // A UnicodeString object (not necessarily its current buffer)
+  // is writable unless it isBogus() or it has an "open" getBuffer(minCapacity).
+  inline UBool isWritable() const;
+
+  // Is the current buffer writable?
+  inline UBool isBufferWritable() const;
+
+  // None of the following does releaseArray().
+  inline void setLength(int32_t len);        // sets only fShortLength and fLength
+  inline void setToEmpty();                  // sets fFlags=kShortString
+  inline void setArray(UChar *array, int32_t len, int32_t capacity); // does not set fFlags
+
+  // allocate the array; result may be fStackBuffer
+  // sets refCount to 1 if appropriate
+  // sets fArray, fCapacity, and fFlags
+  // returns boolean for success or failure
+  UBool allocate(int32_t capacity);
+
+  // release the array if owned
+  void releaseArray(void);
+
+  // turn a bogus string into an empty one
+  void unBogus();
+
+  // implements assigment operator, copy constructor, and fastCopyFrom()
+  UnicodeString &copyFrom(const UnicodeString &src, UBool fastCopy=FALSE);
+
+  // Pin start and limit to acceptable values.
+  inline void pinIndex(int32_t& start) const;
+  inline void pinIndices(int32_t& start,
+                         int32_t& length) const;
+
+#if !UCONFIG_NO_CONVERSION
+
+  /* Internal extract() using UConverter. */
+  int32_t doExtract(int32_t start, int32_t length,
+                    char *dest, int32_t destCapacity,
+                    UConverter *cnv,
+                    UErrorCode &errorCode) const;
+
+  /*
+   * Real constructor for converting from codepage data.
+   * It assumes that it is called with !fRefCounted.
+   *
+   * If <code>codepage==0</code>, then the default converter
+   * is used for the platform encoding.
+   * If <code>codepage</code> is an empty string (<code>""</code>),
+   * then a simple conversion is performed on the codepage-invariant
+   * subset ("invariant characters") of the platform encoding. See utypes.h.
+   */
+  void doCodepageCreate(const char *codepageData,
+                        int32_t dataLength,
+                        const char *codepage);
+
+  /*
+   * Worker function for creating a UnicodeString from
+   * a codepage string using a UConverter.
+   */
+  void
+  doCodepageCreate(const char *codepageData,
+                   int32_t dataLength,
+                   UConverter *converter,
+                   UErrorCode &status);
+
+#endif
+
+  /*
+   * This function is called when write access to the array
+   * is necessary.
+   *
+   * We need to make a copy of the array if
+   * the buffer is read-only, or
+   * the buffer is refCounted (shared), and refCount>1, or
+   * the buffer is too small.
+   *
+   * Return FALSE if memory could not be allocated.
+   */
+  UBool cloneArrayIfNeeded(int32_t newCapacity = -1,
+                            int32_t growCapacity = -1,
+                            UBool doCopyArray = TRUE,
+                            int32_t **pBufferToDelete = 0,
+                            UBool forceClone = FALSE);
+
+  // common function for case mappings
+  UnicodeString &
+  caseMap(BreakIterator *titleIter,
+          const char *locale,
+          uint32_t options,
+          int32_t toWhichCase);
+
+  // ref counting
+  void addRef(void);
+  int32_t removeRef(void);
+  int32_t refCount(void) const;
+
+  // constants
+  enum {
+    // Set the stack buffer size so that sizeof(UnicodeString) is a multiple of sizeof(pointer):
+    // 32-bit pointers: 4+1+1+13*2 = 32 bytes
+    // 64-bit pointers: 8+1+1+15*2 = 40 bytes
+    US_STACKBUF_SIZE= sizeof(void *)==4 ? 13 : 15, // Size of stack buffer for small strings
+    kInvalidUChar=0xffff, // invalid UChar index
+    kGrowSize=128, // grow size for this buffer
+    kInvalidHashCode=0, // invalid hash code
+    kEmptyHashCode=1, // hash code for empty string
+
+    // bit flag values for fFlags
+    kIsBogus=1,         // this string is bogus, i.e., not valid or NULL
+    kUsingStackBuffer=2,// fArray==fStackBuffer
+    kRefCounted=4,      // there is a refCount field before the characters in fArray
+    kBufferIsReadonly=8,// do not write to this buffer
+    kOpenGetBuffer=16,  // getBuffer(minCapacity) was called (is "open"),
+                        // and releaseBuffer(newLength) must be called
+
+    // combined values for convenience
+    kShortString=kUsingStackBuffer,
+    kLongString=kRefCounted,
+    kReadonlyAlias=kBufferIsReadonly,
+    kWritableAlias=0
+  };
+
+  friend class StringThreadTest;
+
+  union StackBufferOrFields;        // forward declaration necessary before friend declaration
+  friend union StackBufferOrFields; // make US_STACKBUF_SIZE visible inside fUnion
+
+  /*
+   * The following are all the class fields that are stored
+   * in each UnicodeString object.
+   * Note that UnicodeString has virtual functions,
+   * therefore there is an implicit vtable pointer
+   * as the first real field.
+   * The fields should be aligned such that no padding is
+   * necessary, mostly by having larger types first.
+   * On 32-bit machines, the size should be 32 bytes,
+   * on 64-bit machines (8-byte pointers), it should be 40 bytes.
+   */
+  // (implicit) *vtable;
+  int8_t    fShortLength;   // 0..127: length  <0: real length is in fUnion.fFields.fLength
+  uint8_t   fFlags;         // bit flags: see constants above
+  union StackBufferOrFields {
+    // fStackBuffer is used iff (fFlags&kUsingStackBuffer)
+    // else fFields is used
+    UChar     fStackBuffer [US_STACKBUF_SIZE]; // buffer for small strings
+    struct {
+      uint16_t  fPadding;   // align the following field at 8B (32b pointers) or 12B (64b)
+      int32_t   fLength;    // number of characters in fArray if >127; else undefined
+      UChar     *fArray;    // the Unicode data (aligned at 12B (32b pointers) or 16B (64b))
+      int32_t   fCapacity;  // sizeof fArray
+    } fFields;
+  } fUnion;
+};
+
+/**
+ * Create a new UnicodeString with the concatenation of two others.
+ *
+ * @param s1 The first string to be copied to the new one.
+ * @param s2 The second string to be copied to the new one, after s1.
+ * @return UnicodeString(s1).append(s2)
+ * @stable ICU 2.8
+ */
+U_COMMON_API UnicodeString U_EXPORT2
+operator+ (const UnicodeString &s1, const UnicodeString &s2);
+
+//========================================
+// Inline members
+//========================================
+
+//========================================
+// Privates
+//========================================
+
+inline void
+UnicodeString::pinIndex(int32_t& start) const
+{
+  // pin index
+  if(start < 0) {
+    start = 0;
+  } else if(start > length()) {
+    start = length();
+  }
+}
+
+inline void
+UnicodeString::pinIndices(int32_t& start,
+                          int32_t& _length) const
+{
+  // pin indices
+  int32_t len = length();
+  if(start < 0) {
+    start = 0;
+  } else if(start > len) {
+    start = len;
+  }
+  if(_length < 0) {
+    _length = 0;
+  } else if(_length > (len - start)) {
+    _length = (len - start);
+  }
+}
+
+inline UChar*
+UnicodeString::getArrayStart()
+{ return (fFlags&kUsingStackBuffer) ? fUnion.fStackBuffer : fUnion.fFields.fArray; }
+
+inline const UChar*
+UnicodeString::getArrayStart() const
+{ return (fFlags&kUsingStackBuffer) ? fUnion.fStackBuffer : fUnion.fFields.fArray; }
+
+//========================================
+// Read-only implementation methods
+//========================================
+inline int32_t
+UnicodeString::length() const
+{ return fShortLength>=0 ? fShortLength : fUnion.fFields.fLength; }
+
+inline int32_t
+UnicodeString::getCapacity() const
+{ return (fFlags&kUsingStackBuffer) ? US_STACKBUF_SIZE : fUnion.fFields.fCapacity; }
+
+inline int32_t
+UnicodeString::hashCode() const
+{ return doHashCode(); }
+
+inline UBool
+UnicodeString::isBogus() const
+{ return (UBool)(fFlags & kIsBogus); }
+
+inline UBool
+UnicodeString::isWritable() const
+{ return (UBool)!(fFlags&(kOpenGetBuffer|kIsBogus)); }
+
+inline UBool
+UnicodeString::isBufferWritable() const
+{
+  return (UBool)(
+      !(fFlags&(kOpenGetBuffer|kIsBogus|kBufferIsReadonly)) &&
+      (!(fFlags&kRefCounted) || refCount()==1));
+}
+
+inline const UChar *
+UnicodeString::getBuffer() const {
+  if(fFlags&(kIsBogus|kOpenGetBuffer)) {
+    return 0;
+  } else if(fFlags&kUsingStackBuffer) {
+    return fUnion.fStackBuffer;
+  } else {
+    return fUnion.fFields.fArray;
+  }
+}
+
+//========================================
+// Read-only alias methods
+//========================================
+inline int8_t
+UnicodeString::doCompare(int32_t start,
+              int32_t thisLength,
+              const UnicodeString& srcText,
+              int32_t srcStart,
+              int32_t srcLength) const
+{
+  if(srcText.isBogus()) {
+    return (int8_t)!isBogus(); // 0 if both are bogus, 1 otherwise
+  } else {
+    srcText.pinIndices(srcStart, srcLength);
+    return doCompare(start, thisLength, srcText.getArrayStart(), srcStart, srcLength);
+  }
+}
+
+inline UBool
+UnicodeString::operator== (const UnicodeString& text) const
+{
+  if(isBogus()) {
+    return text.isBogus();
+  } else {
+    int32_t len = length(), textLength = text.length();
+    return
+      !text.isBogus() &&
+      len == textLength &&
+      doCompare(0, len, text, 0, textLength) == 0;
+  }
+}
+
+inline UBool
+UnicodeString::operator!= (const UnicodeString& text) const
+{ return (! operator==(text)); }
+
+inline UBool
+UnicodeString::operator> (const UnicodeString& text) const
+{ return doCompare(0, length(), text, 0, text.length()) == 1; }
+
+inline UBool
+UnicodeString::operator< (const UnicodeString& text) const
+{ return doCompare(0, length(), text, 0, text.length()) == -1; }
+
+inline UBool
+UnicodeString::operator>= (const UnicodeString& text) const
+{ return doCompare(0, length(), text, 0, text.length()) != -1; }
+
+inline UBool
+UnicodeString::operator<= (const UnicodeString& text) const
+{ return doCompare(0, length(), text, 0, text.length()) != 1; }
+
+inline int8_t
+UnicodeString::compare(const UnicodeString& text) const
+{ return doCompare(0, length(), text, 0, text.length()); }
+
+inline int8_t
+UnicodeString::compare(int32_t start,
+               int32_t _length,
+               const UnicodeString& srcText) const
+{ return doCompare(start, _length, srcText, 0, srcText.length()); }
+
+inline int8_t
+UnicodeString::compare(const UChar *srcChars,
+               int32_t srcLength) const
+{ return doCompare(0, length(), srcChars, 0, srcLength); }
+
+inline int8_t
+UnicodeString::compare(int32_t start,
+               int32_t _length,
+               const UnicodeString& srcText,
+               int32_t srcStart,
+               int32_t srcLength) const
+{ return doCompare(start, _length, srcText, srcStart, srcLength); }
+
+inline int8_t
+UnicodeString::compare(int32_t start,
+               int32_t _length,
+               const UChar *srcChars) const
+{ return doCompare(start, _length, srcChars, 0, _length); }
+
+inline int8_t
+UnicodeString::compare(int32_t start,
+               int32_t _length,
+               const UChar *srcChars,
+               int32_t srcStart,
+               int32_t srcLength) const
+{ return doCompare(start, _length, srcChars, srcStart, srcLength); }
+
+inline int8_t
+UnicodeString::compareBetween(int32_t start,
+                  int32_t limit,
+                  const UnicodeString& srcText,
+                  int32_t srcStart,
+                  int32_t srcLimit) const
+{ return doCompare(start, limit - start,
+           srcText, srcStart, srcLimit - srcStart); }
+
+inline int8_t
+UnicodeString::doCompareCodePointOrder(int32_t start,
+                                       int32_t thisLength,
+                                       const UnicodeString& srcText,
+                                       int32_t srcStart,
+                                       int32_t srcLength) const
+{
+  if(srcText.isBogus()) {
+    return (int8_t)!isBogus(); // 0 if both are bogus, 1 otherwise
+  } else {
+    srcText.pinIndices(srcStart, srcLength);
+    return doCompareCodePointOrder(start, thisLength, srcText.getArrayStart(), srcStart, srcLength);
+  }
+}
+
+inline int8_t
+UnicodeString::compareCodePointOrder(const UnicodeString& text) const
+{ return doCompareCodePointOrder(0, length(), text, 0, text.length()); }
+
+inline int8_t
+UnicodeString::compareCodePointOrder(int32_t start,
+                                     int32_t _length,
+                                     const UnicodeString& srcText) const
+{ return doCompareCodePointOrder(start, _length, srcText, 0, srcText.length()); }
+
+inline int8_t
+UnicodeString::compareCodePointOrder(const UChar *srcChars,
+                                     int32_t srcLength) const
+{ return doCompareCodePointOrder(0, length(), srcChars, 0, srcLength); }
+
+inline int8_t
+UnicodeString::compareCodePointOrder(int32_t start,
+                                     int32_t _length,
+                                     const UnicodeString& srcText,
+                                     int32_t srcStart,
+                                     int32_t srcLength) const
+{ return doCompareCodePointOrder(start, _length, srcText, srcStart, srcLength); }
+
+inline int8_t
+UnicodeString::compareCodePointOrder(int32_t start,
+                                     int32_t _length,
+                                     const UChar *srcChars) const
+{ return doCompareCodePointOrder(start, _length, srcChars, 0, _length); }
+
+inline int8_t
+UnicodeString::compareCodePointOrder(int32_t start,
+                                     int32_t _length,
+                                     const UChar *srcChars,
+                                     int32_t srcStart,
+                                     int32_t srcLength) const
+{ return doCompareCodePointOrder(start, _length, srcChars, srcStart, srcLength); }
+
+inline int8_t
+UnicodeString::compareCodePointOrderBetween(int32_t start,
+                                            int32_t limit,
+                                            const UnicodeString& srcText,
+                                            int32_t srcStart,
+                                            int32_t srcLimit) const
+{ return doCompareCodePointOrder(start, limit - start,
+           srcText, srcStart, srcLimit - srcStart); }
+
+inline int8_t
+UnicodeString::doCaseCompare(int32_t start,
+                             int32_t thisLength,
+                             const UnicodeString &srcText,
+                             int32_t srcStart,
+                             int32_t srcLength,
+                             uint32_t options) const
+{
+  if(srcText.isBogus()) {
+    return (int8_t)!isBogus(); // 0 if both are bogus, 1 otherwise
+  } else {
+    srcText.pinIndices(srcStart, srcLength);
+    return doCaseCompare(start, thisLength, srcText.getArrayStart(), srcStart, srcLength, options);
+  }
+}
+
+inline int8_t
+UnicodeString::caseCompare(const UnicodeString &text, uint32_t options) const {
+  return doCaseCompare(0, length(), text, 0, text.length(), options);
+}
+
+inline int8_t
+UnicodeString::caseCompare(int32_t start,
+                           int32_t _length,
+                           const UnicodeString &srcText,
+                           uint32_t options) const {
+  return doCaseCompare(start, _length, srcText, 0, srcText.length(), options);
+}
+
+inline int8_t
+UnicodeString::caseCompare(const UChar *srcChars,
+                           int32_t srcLength,
+                           uint32_t options) const {
+  return doCaseCompare(0, length(), srcChars, 0, srcLength, options);
+}
+
+inline int8_t
+UnicodeString::caseCompare(int32_t start,
+                           int32_t _length,
+                           const UnicodeString &srcText,
+                           int32_t srcStart,
+                           int32_t srcLength,
+                           uint32_t options) const {
+  return doCaseCompare(start, _length, srcText, srcStart, srcLength, options);
+}
+
+inline int8_t
+UnicodeString::caseCompare(int32_t start,
+                           int32_t _length,
+                           const UChar *srcChars,
+                           uint32_t options) const {
+  return doCaseCompare(start, _length, srcChars, 0, _length, options);
+}
+
+inline int8_t
+UnicodeString::caseCompare(int32_t start,
+                           int32_t _length,
+                           const UChar *srcChars,
+                           int32_t srcStart,
+                           int32_t srcLength,
+                           uint32_t options) const {
+  return doCaseCompare(start, _length, srcChars, srcStart, srcLength, options);
+}
+
+inline int8_t
+UnicodeString::caseCompareBetween(int32_t start,
+                                  int32_t limit,
+                                  const UnicodeString &srcText,
+                                  int32_t srcStart,
+                                  int32_t srcLimit,
+                                  uint32_t options) const {
+  return doCaseCompare(start, limit - start, srcText, srcStart, srcLimit - srcStart, options);
+}
+
+inline int32_t
+UnicodeString::indexOf(const UnicodeString& srcText,
+               int32_t srcStart,
+               int32_t srcLength,
+               int32_t start,
+               int32_t _length) const
+{
+  if(!srcText.isBogus()) {
+    srcText.pinIndices(srcStart, srcLength);
+    if(srcLength > 0) {
+      return indexOf(srcText.getArrayStart(), srcStart, srcLength, start, _length);
+    }
+  }
+  return -1;
+}
+
+inline int32_t
+UnicodeString::indexOf(const UnicodeString& text) const
+{ return indexOf(text, 0, text.length(), 0, length()); }
+
+inline int32_t
+UnicodeString::indexOf(const UnicodeString& text,
+               int32_t start) const {
+  pinIndex(start);
+  return indexOf(text, 0, text.length(), start, length() - start);
+}
+
+inline int32_t
+UnicodeString::indexOf(const UnicodeString& text,
+               int32_t start,
+               int32_t _length) const
+{ return indexOf(text, 0, text.length(), start, _length); }
+
+inline int32_t
+UnicodeString::indexOf(const UChar *srcChars,
+               int32_t srcLength,
+               int32_t start) const {
+  pinIndex(start);
+  return indexOf(srcChars, 0, srcLength, start, length() - start);
+}
+
+inline int32_t
+UnicodeString::indexOf(const UChar *srcChars,
+               int32_t srcLength,
+               int32_t start,
+               int32_t _length) const
+{ return indexOf(srcChars, 0, srcLength, start, _length); }
+
+inline int32_t
+UnicodeString::indexOf(UChar c,
+               int32_t start,
+               int32_t _length) const
+{ return doIndexOf(c, start, _length); }
+
+inline int32_t
+UnicodeString::indexOf(UChar32 c,
+               int32_t start,
+               int32_t _length) const
+{ return doIndexOf(c, start, _length); }
+
+inline int32_t
+UnicodeString::indexOf(UChar c) const
+{ return doIndexOf(c, 0, length()); }
+
+inline int32_t
+UnicodeString::indexOf(UChar32 c) const
+{ return indexOf(c, 0, length()); }
+
+inline int32_t
+UnicodeString::indexOf(UChar c,
+               int32_t start) const {
+  pinIndex(start);
+  return doIndexOf(c, start, length() - start);
+}
+
+inline int32_t
+UnicodeString::indexOf(UChar32 c,
+               int32_t start) const {
+  pinIndex(start);
+  return indexOf(c, start, length() - start);
+}
+
+inline int32_t
+UnicodeString::lastIndexOf(const UChar *srcChars,
+               int32_t srcLength,
+               int32_t start,
+               int32_t _length) const
+{ return lastIndexOf(srcChars, 0, srcLength, start, _length); }
+
+inline int32_t
+UnicodeString::lastIndexOf(const UChar *srcChars,
+               int32_t srcLength,
+               int32_t start) const {
+  pinIndex(start);
+  return lastIndexOf(srcChars, 0, srcLength, start, length() - start);
+}
+
+inline int32_t
+UnicodeString::lastIndexOf(const UnicodeString& srcText,
+               int32_t srcStart,
+               int32_t srcLength,
+               int32_t start,
+               int32_t _length) const
+{
+  if(!srcText.isBogus()) {
+    srcText.pinIndices(srcStart, srcLength);
+    if(srcLength > 0) {
+      return lastIndexOf(srcText.getArrayStart(), srcStart, srcLength, start, _length);
+    }
+  }
+  return -1;
+}
+
+inline int32_t
+UnicodeString::lastIndexOf(const UnicodeString& text,
+               int32_t start,
+               int32_t _length) const
+{ return lastIndexOf(text, 0, text.length(), start, _length); }
+
+inline int32_t
+UnicodeString::lastIndexOf(const UnicodeString& text,
+               int32_t start) const {
+  pinIndex(start);
+  return lastIndexOf(text, 0, text.length(), start, length() - start);
+}
+
+inline int32_t
+UnicodeString::lastIndexOf(const UnicodeString& text) const
+{ return lastIndexOf(text, 0, text.length(), 0, length()); }
+
+inline int32_t
+UnicodeString::lastIndexOf(UChar c,
+               int32_t start,
+               int32_t _length) const
+{ return doLastIndexOf(c, start, _length); }
+
+inline int32_t
+UnicodeString::lastIndexOf(UChar32 c,
+               int32_t start,
+               int32_t _length) const {
+  return doLastIndexOf(c, start, _length);
+}
+
+inline int32_t
+UnicodeString::lastIndexOf(UChar c) const
+{ return doLastIndexOf(c, 0, length()); }
+
+inline int32_t
+UnicodeString::lastIndexOf(UChar32 c) const {
+  return lastIndexOf(c, 0, length());
+}
+
+inline int32_t
+UnicodeString::lastIndexOf(UChar c,
+               int32_t start) const {
+  pinIndex(start);
+  return doLastIndexOf(c, start, length() - start);
+}
+
+inline int32_t
+UnicodeString::lastIndexOf(UChar32 c,
+               int32_t start) const {
+  pinIndex(start);
+  return lastIndexOf(c, start, length() - start);
+}
+
+inline UBool
+UnicodeString::startsWith(const UnicodeString& text) const
+{ return compare(0, text.length(), text, 0, text.length()) == 0; }
+
+inline UBool
+UnicodeString::startsWith(const UnicodeString& srcText,
+              int32_t srcStart,
+              int32_t srcLength) const
+{ return doCompare(0, srcLength, srcText, srcStart, srcLength) == 0; }
+
+inline UBool
+UnicodeString::startsWith(const UChar *srcChars,
+              int32_t srcLength) const
+{ return doCompare(0, srcLength, srcChars, 0, srcLength) == 0; }
+
+inline UBool
+UnicodeString::startsWith(const UChar *srcChars,
+              int32_t srcStart,
+              int32_t srcLength) const
+{ return doCompare(0, srcLength, srcChars, srcStart, srcLength) == 0;}
+
+inline UBool
+UnicodeString::endsWith(const UnicodeString& text) const
+{ return doCompare(length() - text.length(), text.length(),
+           text, 0, text.length()) == 0; }
+
+inline UBool
+UnicodeString::endsWith(const UnicodeString& srcText,
+            int32_t srcStart,
+            int32_t srcLength) const {
+  srcText.pinIndices(srcStart, srcLength);
+  return doCompare(length() - srcLength, srcLength,
+                   srcText, srcStart, srcLength) == 0;
+}
+
+inline UBool
+UnicodeString::endsWith(const UChar *srcChars,
+            int32_t srcLength) const {
+  if(srcLength < 0) {
+    srcLength = u_strlen(srcChars);
+  }
+  return doCompare(length() - srcLength, srcLength,
+                   srcChars, 0, srcLength) == 0;
+}
+
+inline UBool
+UnicodeString::endsWith(const UChar *srcChars,
+            int32_t srcStart,
+            int32_t srcLength) const {
+  if(srcLength < 0) {
+    srcLength = u_strlen(srcChars + srcStart);
+  }
+  return doCompare(length() - srcLength, srcLength,
+                   srcChars, srcStart, srcLength) == 0;
+}
+
+//========================================
+// replace
+//========================================
+inline UnicodeString&
+UnicodeString::replace(int32_t start,
+               int32_t _length,
+               const UnicodeString& srcText)
+{ return doReplace(start, _length, srcText, 0, srcText.length()); }
+
+inline UnicodeString&
+UnicodeString::replace(int32_t start,
+               int32_t _length,
+               const UnicodeString& srcText,
+               int32_t srcStart,
+               int32_t srcLength)
+{ return doReplace(start, _length, srcText, srcStart, srcLength); }
+
+inline UnicodeString&
+UnicodeString::replace(int32_t start,
+               int32_t _length,
+               const UChar *srcChars,
+               int32_t srcLength)
+{ return doReplace(start, _length, srcChars, 0, srcLength); }
+
+inline UnicodeString&
+UnicodeString::replace(int32_t start,
+               int32_t _length,
+               const UChar *srcChars,
+               int32_t srcStart,
+               int32_t srcLength)
+{ return doReplace(start, _length, srcChars, srcStart, srcLength); }
+
+inline UnicodeString&
+UnicodeString::replace(int32_t start,
+               int32_t _length,
+               UChar srcChar)
+{ return doReplace(start, _length, &srcChar, 0, 1); }
+
+inline UnicodeString&
+UnicodeString::replace(int32_t start,
+               int32_t _length,
+               UChar32 srcChar) {
+  UChar buffer[U16_MAX_LENGTH];
+  int32_t count = 0;
+  UBool isError = FALSE;
+  U16_APPEND(buffer, count, U16_MAX_LENGTH, srcChar, isError);
+  return doReplace(start, _length, buffer, 0, count);
+}
+
+inline UnicodeString&
+UnicodeString::replaceBetween(int32_t start,
+                  int32_t limit,
+                  const UnicodeString& srcText)
+{ return doReplace(start, limit - start, srcText, 0, srcText.length()); }
+
+inline UnicodeString&
+UnicodeString::replaceBetween(int32_t start,
+                  int32_t limit,
+                  const UnicodeString& srcText,
+                  int32_t srcStart,
+                  int32_t srcLimit)
+{ return doReplace(start, limit - start, srcText, srcStart, srcLimit - srcStart); }
+
+inline UnicodeString&
+UnicodeString::findAndReplace(const UnicodeString& oldText,
+                  const UnicodeString& newText)
+{ return findAndReplace(0, length(), oldText, 0, oldText.length(),
+            newText, 0, newText.length()); }
+
+inline UnicodeString&
+UnicodeString::findAndReplace(int32_t start,
+                  int32_t _length,
+                  const UnicodeString& oldText,
+                  const UnicodeString& newText)
+{ return findAndReplace(start, _length, oldText, 0, oldText.length(),
+            newText, 0, newText.length()); }
+
+// ============================
+// extract
+// ============================
+inline void
+UnicodeString::doExtract(int32_t start,
+             int32_t _length,
+             UnicodeString& target) const
+{ target.replace(0, target.length(), *this, start, _length); }
+
+inline void
+UnicodeString::extract(int32_t start,
+               int32_t _length,
+               UChar *target,
+               int32_t targetStart) const
+{ doExtract(start, _length, target, targetStart); }
+
+inline void
+UnicodeString::extract(int32_t start,
+               int32_t _length,
+               UnicodeString& target) const
+{ doExtract(start, _length, target); }
+
+#if !UCONFIG_NO_CONVERSION
+
+inline int32_t
+UnicodeString::extract(int32_t start,
+               int32_t _length,
+               char *dst,
+               const char *codepage) const
+
+{
+  // This dstSize value will be checked explicitly
+#if defined(__GNUC__)
+  // Ticket #7039: Clip length to the maximum valid length to the end of addressable memory given the starting address
+  // This is only an issue when using GCC and certain optimizations are turned on.
+  return extract(start, _length, dst, dst!=0 ? ((dst >= (char*)((size_t)-1) - UINT32_MAX) ? (((char*)UINT32_MAX) - dst) : UINT32_MAX) : 0, codepage);
+#else
+  return extract(start, _length, dst, dst!=0 ? 0xffffffff : 0, codepage);
+#endif
+}
+
+#endif
+
+inline void
+UnicodeString::extractBetween(int32_t start,
+                  int32_t limit,
+                  UChar *dst,
+                  int32_t dstStart) const {
+  pinIndex(start);
+  pinIndex(limit);
+  doExtract(start, limit - start, dst, dstStart);
+}
+
+inline UnicodeString
+UnicodeString::tempSubStringBetween(int32_t start, int32_t limit) const {
+    return tempSubString(start, limit - start);
+}
+
+inline UChar
+UnicodeString::doCharAt(int32_t offset) const
+{
+  if((uint32_t)offset < (uint32_t)length()) {
+    return getArrayStart()[offset];
+  } else {
+    return kInvalidUChar;
+  }
+}
+
+inline UChar
+UnicodeString::charAt(int32_t offset) const
+{ return doCharAt(offset); }
+
+inline UChar
+UnicodeString::operator[] (int32_t offset) const
+{ return doCharAt(offset); }
+
+inline UChar32
+UnicodeString::char32At(int32_t offset) const
+{
+  int32_t len = length();
+  if((uint32_t)offset < (uint32_t)len) {
+    const UChar *array = getArrayStart();
+    UChar32 c;
+    U16_GET(array, 0, offset, len, c);
+    return c;
+  } else {
+    return kInvalidUChar;
+  }
+}
+
+inline int32_t
+UnicodeString::getChar32Start(int32_t offset) const {
+  if((uint32_t)offset < (uint32_t)length()) {
+    const UChar *array = getArrayStart();
+    U16_SET_CP_START(array, 0, offset);
+    return offset;
+  } else {
+    return 0;
+  }
+}
+
+inline int32_t
+UnicodeString::getChar32Limit(int32_t offset) const {
+  int32_t len = length();
+  if((uint32_t)offset < (uint32_t)len) {
+    const UChar *array = getArrayStart();
+    U16_SET_CP_LIMIT(array, 0, offset, len);
+    return offset;
+  } else {
+    return len;
+  }
+}
+
+inline UBool
+UnicodeString::isEmpty() const {
+  return fShortLength == 0;
+}
+
+//========================================
+// Write implementation methods
+//========================================
+inline void
+UnicodeString::setLength(int32_t len) {
+  if(len <= 127) {
+    fShortLength = (int8_t)len;
+  } else {
+    fShortLength = (int8_t)-1;
+    fUnion.fFields.fLength = len;
+  }
+}
+
+inline void
+UnicodeString::setToEmpty() {
+  fShortLength = 0;
+  fFlags = kShortString;
+}
+
+inline void
+UnicodeString::setArray(UChar *array, int32_t len, int32_t capacity) {
+  setLength(len);
+  fUnion.fFields.fArray = array;
+  fUnion.fFields.fCapacity = capacity;
+}
+
+inline const UChar *
+UnicodeString::getTerminatedBuffer() {
+  if(!isWritable()) {
+    return 0;
+  } else {
+    UChar *array = getArrayStart();
+    int32_t len = length();
+    if(len < getCapacity() && ((fFlags&kRefCounted) == 0 || refCount() == 1)) {
+      /*
+       * kRefCounted: Do not write the NUL if the buffer is shared.
+       * That is mostly safe, except when the length of one copy was modified
+       * without copy-on-write, e.g., via truncate(newLength) or remove(void).
+       * Then the NUL would be written into the middle of another copy's string.
+       */
+      if(!(fFlags&kBufferIsReadonly)) {
+        /*
+         * We must not write to a readonly buffer, but it is known to be
+         * NUL-terminated if len<capacity.
+         * A shared, allocated buffer (refCount()>1) must not have its contents
+         * modified, but the NUL at [len] is beyond the string contents,
+         * and multiple string objects and threads writing the same NUL into the
+         * same location is harmless.
+         * In all other cases, the buffer is fully writable and it is anyway safe
+         * to write the NUL.
+         *
+         * Note: An earlier version of this code tested whether there is a NUL
+         * at [len] already, but, while safe, it generated lots of warnings from
+         * tools like valgrind and Purify.
+         */
+        array[len] = 0;
+      }
+      return array;
+    } else if(cloneArrayIfNeeded(len+1)) {
+      array = getArrayStart();
+      array[len] = 0;
+      return array;
+    } else {
+      return 0;
+    }
+  }
+}
+
+inline UnicodeString&
+UnicodeString::operator= (UChar ch)
+{ return doReplace(0, length(), &ch, 0, 1); }
+
+inline UnicodeString&
+UnicodeString::operator= (UChar32 ch)
+{ return replace(0, length(), ch); }
+
+inline UnicodeString&
+UnicodeString::setTo(const UnicodeString& srcText,
+             int32_t srcStart,
+             int32_t srcLength)
+{
+  unBogus();
+  return doReplace(0, length(), srcText, srcStart, srcLength);
+}
+
+inline UnicodeString&
+UnicodeString::setTo(const UnicodeString& srcText,
+             int32_t srcStart)
+{
+  unBogus();
+  srcText.pinIndex(srcStart);
+  return doReplace(0, length(), srcText, srcStart, srcText.length() - srcStart);
+}
+
+inline UnicodeString&
+UnicodeString::setTo(const UnicodeString& srcText)
+{
+  unBogus();
+  return doReplace(0, length(), srcText, 0, srcText.length());
+}
+
+inline UnicodeString&
+UnicodeString::setTo(const UChar *srcChars,
+             int32_t srcLength)
+{
+  unBogus();
+  return doReplace(0, length(), srcChars, 0, srcLength);
+}
+
+inline UnicodeString&
+UnicodeString::setTo(UChar srcChar)
+{
+  unBogus();
+  return doReplace(0, length(), &srcChar, 0, 1);
+}
+
+inline UnicodeString&
+UnicodeString::setTo(UChar32 srcChar)
+{
+  unBogus();
+  return replace(0, length(), srcChar);
+}
+
+inline UnicodeString&
+UnicodeString::append(const UnicodeString& srcText,
+              int32_t srcStart,
+              int32_t srcLength)
+{ return doReplace(length(), 0, srcText, srcStart, srcLength); }
+
+inline UnicodeString&
+UnicodeString::append(const UnicodeString& srcText)
+{ return doReplace(length(), 0, srcText, 0, srcText.length()); }
+
+inline UnicodeString&
+UnicodeString::append(const UChar *srcChars,
+              int32_t srcStart,
+              int32_t srcLength)
+{ return doReplace(length(), 0, srcChars, srcStart, srcLength); }
+
+inline UnicodeString&
+UnicodeString::append(const UChar *srcChars,
+              int32_t srcLength)
+{ return doReplace(length(), 0, srcChars, 0, srcLength); }
+
+inline UnicodeString&
+UnicodeString::append(UChar srcChar)
+{ return doReplace(length(), 0, &srcChar, 0, 1); }
+
+inline UnicodeString&
+UnicodeString::append(UChar32 srcChar) {
+  UChar buffer[U16_MAX_LENGTH];
+  int32_t _length = 0;
+  UBool isError = FALSE;
+  U16_APPEND(buffer, _length, U16_MAX_LENGTH, srcChar, isError);
+  return doReplace(length(), 0, buffer, 0, _length);
+}
+
+inline UnicodeString&
+UnicodeString::operator+= (UChar ch)
+{ return doReplace(length(), 0, &ch, 0, 1); }
+
+inline UnicodeString&
+UnicodeString::operator+= (UChar32 ch) {
+  return append(ch);
+}
+
+inline UnicodeString&
+UnicodeString::operator+= (const UnicodeString& srcText)
+{ return doReplace(length(), 0, srcText, 0, srcText.length()); }
+
+inline UnicodeString&
+UnicodeString::insert(int32_t start,
+              const UnicodeString& srcText,
+              int32_t srcStart,
+              int32_t srcLength)
+{ return doReplace(start, 0, srcText, srcStart, srcLength); }
+
+inline UnicodeString&
+UnicodeString::insert(int32_t start,
+              const UnicodeString& srcText)
+{ return doReplace(start, 0, srcText, 0, srcText.length()); }
+
+inline UnicodeString&
+UnicodeString::insert(int32_t start,
+              const UChar *srcChars,
+              int32_t srcStart,
+              int32_t srcLength)
+{ return doReplace(start, 0, srcChars, srcStart, srcLength); }
+
+inline UnicodeString&
+UnicodeString::insert(int32_t start,
+              const UChar *srcChars,
+              int32_t srcLength)
+{ return doReplace(start, 0, srcChars, 0, srcLength); }
+
+inline UnicodeString&
+UnicodeString::insert(int32_t start,
+              UChar srcChar)
+{ return doReplace(start, 0, &srcChar, 0, 1); }
+
+inline UnicodeString&
+UnicodeString::insert(int32_t start,
+              UChar32 srcChar)
+{ return replace(start, 0, srcChar); }
+
+
+inline UnicodeString&
+UnicodeString::remove()
+{
+  // remove() of a bogus string makes the string empty and non-bogus
+  // we also un-alias a read-only alias to deal with NUL-termination
+  // issues with getTerminatedBuffer()
+  if(fFlags & (kIsBogus|kBufferIsReadonly)) {
+    setToEmpty();
+  } else {
+    fShortLength = 0;
+  }
+  return *this;
+}
+
+inline UnicodeString&
+UnicodeString::remove(int32_t start,
+             int32_t _length)
+{
+    if(start <= 0 && _length == INT32_MAX) {
+        // remove(guaranteed everything) of a bogus string makes the string empty and non-bogus
+        return remove();
+    }
+    return doReplace(start, _length, NULL, 0, 0);
+}
+
+inline UnicodeString&
+UnicodeString::removeBetween(int32_t start,
+                int32_t limit)
+{ return doReplace(start, limit - start, NULL, 0, 0); }
+
+inline UnicodeString &
+UnicodeString::retainBetween(int32_t start, int32_t limit) {
+  truncate(limit);
+  return doReplace(0, start, NULL, 0, 0);
+}
+
+inline UBool
+UnicodeString::truncate(int32_t targetLength)
+{
+  if(isBogus() && targetLength == 0) {
+    // truncate(0) of a bogus string makes the string empty and non-bogus
+    unBogus();
+    return FALSE;
+  } else if((uint32_t)targetLength < (uint32_t)length()) {
+    setLength(targetLength);
+    if(fFlags&kBufferIsReadonly) {
+      fUnion.fFields.fCapacity = targetLength;  // not NUL-terminated any more
+    }
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+inline UnicodeString&
+UnicodeString::reverse()
+{ return doReverse(0, length()); }
+
+inline UnicodeString&
+UnicodeString::reverse(int32_t start,
+               int32_t _length)
+{ return doReverse(start, _length); }
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/unicode/unorm.h b/source/common/unicode/unorm.h
new file mode 100644
index 0000000..fbb7b49
--- /dev/null
+++ b/source/common/unicode/unorm.h
@@ -0,0 +1,561 @@
+/*
+*******************************************************************************
+* Copyright (c) 1996-2010, International Business Machines Corporation
+*               and others. All Rights Reserved.
+*******************************************************************************
+* File unorm.h
+*
+* Created by: Vladimir Weinstein 12052000
+*
+* Modification history :
+*
+* Date        Name        Description
+* 02/01/01    synwee      Added normalization quickcheck enum and method.
+*/
+#ifndef UNORM_H
+#define UNORM_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/uiter.h"
+#include "unicode/unorm2.h"
+
+/**
+ * \file
+ * \brief C API: Unicode Normalization 
+ *
+ * <h2>Unicode normalization API</h2>
+ *
+ * Note: This API has been replaced by the unorm2.h API and is only available
+ * for backward compatibility. The functions here simply delegate to the
+ * unorm2.h functions, for example unorm2_getInstance() and unorm2_normalize().
+ * There is one exception: The new API does not provide a replacement for unorm_compare().
+ *
+ * <code>unorm_normalize</code> transforms Unicode text into an equivalent composed or
+ * decomposed form, allowing for easier sorting and searching of text.
+ * <code>unorm_normalize</code> supports the standard normalization forms described in
+ * <a href="http://www.unicode.org/unicode/reports/tr15/" target="unicode">
+ * Unicode Standard Annex #15: Unicode Normalization Forms</a>.
+ *
+ * Characters with accents or other adornments can be encoded in
+ * several different ways in Unicode.  For example, take the character A-acute.
+ * In Unicode, this can be encoded as a single character (the
+ * "composed" form):
+ *
+ * \code
+ *      00C1    LATIN CAPITAL LETTER A WITH ACUTE
+ * \endcode
+ *
+ * or as two separate characters (the "decomposed" form):
+ *
+ * \code
+ *      0041    LATIN CAPITAL LETTER A
+ *      0301    COMBINING ACUTE ACCENT
+ * \endcode
+ *
+ * To a user of your program, however, both of these sequences should be
+ * treated as the same "user-level" character "A with acute accent".  When you are searching or
+ * comparing text, you must ensure that these two sequences are treated 
+ * equivalently.  In addition, you must handle characters with more than one
+ * accent.  Sometimes the order of a character's combining accents is
+ * significant, while in other cases accent sequences in different orders are
+ * really equivalent.
+ *
+ * Similarly, the string "ffi" can be encoded as three separate letters:
+ *
+ * \code
+ *      0066    LATIN SMALL LETTER F
+ *      0066    LATIN SMALL LETTER F
+ *      0069    LATIN SMALL LETTER I
+ * \endcode
+ *
+ * or as the single character
+ *
+ * \code
+ *      FB03    LATIN SMALL LIGATURE FFI
+ * \endcode
+ *
+ * The ffi ligature is not a distinct semantic character, and strictly speaking
+ * it shouldn't be in Unicode at all, but it was included for compatibility
+ * with existing character sets that already provided it.  The Unicode standard
+ * identifies such characters by giving them "compatibility" decompositions
+ * into the corresponding semantic characters.  When sorting and searching, you
+ * will often want to use these mappings.
+ *
+ * <code>unorm_normalize</code> helps solve these problems by transforming text into the
+ * canonical composed and decomposed forms as shown in the first example above.  
+ * In addition, you can have it perform compatibility decompositions so that 
+ * you can treat compatibility characters the same as their equivalents.
+ * Finally, <code>unorm_normalize</code> rearranges accents into the proper canonical
+ * order, so that you do not have to worry about accent rearrangement on your
+ * own.
+ *
+ * Form FCD, "Fast C or D", is also designed for collation.
+ * It allows to work on strings that are not necessarily normalized
+ * with an algorithm (like in collation) that works under "canonical closure", i.e., it treats precomposed
+ * characters and their decomposed equivalents the same.
+ *
+ * It is not a normalization form because it does not provide for uniqueness of representation. Multiple strings
+ * may be canonically equivalent (their NFDs are identical) and may all conform to FCD without being identical
+ * themselves.
+ *
+ * The form is defined such that the "raw decomposition", the recursive canonical decomposition of each character,
+ * results in a string that is canonically ordered. This means that precomposed characters are allowed for as long
+ * as their decompositions do not need canonical reordering.
+ *
+ * Its advantage for a process like collation is that all NFD and most NFC texts - and many unnormalized texts -
+ * already conform to FCD and do not need to be normalized (NFD) for such a process. The FCD quick check will
+ * return UNORM_YES for most strings in practice.
+ *
+ * unorm_normalize(UNORM_FCD) may be implemented with UNORM_NFD.
+ *
+ * For more details on FCD see the collation design document:
+ * http://source.icu-project.org/repos/icu/icuhtml/trunk/design/collation/ICU_collation_design.htm
+ *
+ * ICU collation performs either NFD or FCD normalization automatically if normalization
+ * is turned on for the collator object.
+ * Beyond collation and string search, normalized strings may be useful for string equivalence comparisons,
+ * transliteration/transcription, unique representations, etc.
+ *
+ * The W3C generally recommends to exchange texts in NFC.
+ * Note also that most legacy character encodings use only precomposed forms and often do not
+ * encode any combining marks by themselves. For conversion to such character encodings the
+ * Unicode text needs to be normalized to NFC.
+ * For more usage examples, see the Unicode Standard Annex.
+ */
+
+/**
+ * Constants for normalization modes.
+ * @stable ICU 2.0
+ */
+typedef enum {
+  /** No decomposition/composition. @stable ICU 2.0 */
+  UNORM_NONE = 1, 
+  /** Canonical decomposition. @stable ICU 2.0 */
+  UNORM_NFD = 2,
+  /** Compatibility decomposition. @stable ICU 2.0 */
+  UNORM_NFKD = 3,
+  /** Canonical decomposition followed by canonical composition. @stable ICU 2.0 */
+  UNORM_NFC = 4,
+  /** Default normalization. @stable ICU 2.0 */
+  UNORM_DEFAULT = UNORM_NFC, 
+  /** Compatibility decomposition followed by canonical composition. @stable ICU 2.0 */
+  UNORM_NFKC =5,
+  /** "Fast C or D" form. @stable ICU 2.0 */
+  UNORM_FCD = 6,
+
+  /** One more than the highest normalization mode constant. @stable ICU 2.0 */
+  UNORM_MODE_COUNT
+} UNormalizationMode;
+
+/**
+ * Constants for options flags for normalization.
+ * Use 0 for default options,
+ * including normalization according to the Unicode version
+ * that is currently supported by ICU (see u_getUnicodeVersion).
+ * @stable ICU 2.6
+ */
+enum {
+    /**
+     * Options bit set value to select Unicode 3.2 normalization
+     * (except NormalizationCorrections).
+     * At most one Unicode version can be selected at a time.
+     * @stable ICU 2.6
+     */
+    UNORM_UNICODE_3_2=0x20
+};
+
+/**
+ * Lowest-order bit number of unorm_compare() options bits corresponding to
+ * normalization options bits.
+ *
+ * The options parameter for unorm_compare() uses most bits for
+ * itself and for various comparison and folding flags.
+ * The most significant bits, however, are shifted down and passed on
+ * to the normalization implementation.
+ * (That is, from unorm_compare(..., options, ...),
+ * options>>UNORM_COMPARE_NORM_OPTIONS_SHIFT will be passed on to the
+ * internal normalization functions.)
+ *
+ * @see unorm_compare
+ * @stable ICU 2.6
+ */
+#define UNORM_COMPARE_NORM_OPTIONS_SHIFT 20
+
+/**
+ * Normalize a string.
+ * The string will be normalized according the specified normalization mode
+ * and options.
+ * The source and result buffers must not be the same, nor overlap.
+ *
+ * @param source The string to normalize.
+ * @param sourceLength The length of source, or -1 if NUL-terminated.
+ * @param mode The normalization mode; one of UNORM_NONE, 
+ *             UNORM_NFD, UNORM_NFC, UNORM_NFKC, UNORM_NFKD, UNORM_DEFAULT.
+ * @param options The normalization options, ORed together (0 for no options).
+ * @param result A pointer to a buffer to receive the result string.
+ *               The result string is NUL-terminated if possible.
+ * @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, and the error code is set to U_BUFFER_OVERFLOW_ERROR.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2 
+unorm_normalize(const UChar *source, int32_t sourceLength,
+                UNormalizationMode mode, int32_t options,
+                UChar *result, int32_t resultLength,
+                UErrorCode *status);
+
+/**
+ * Performing quick check on a string, to quickly determine if the string is 
+ * in a particular normalization format.
+ * Three types of result can be returned UNORM_YES, UNORM_NO or
+ * UNORM_MAYBE. Result UNORM_YES indicates that the argument
+ * string is in the desired normalized format, UNORM_NO determines that
+ * argument string is not in the desired normalized format. A 
+ * UNORM_MAYBE result indicates that a more thorough check is required, 
+ * the user may have to put the string in its normalized form and compare the 
+ * results.
+ *
+ * @param source       string for determining if it is in a normalized format
+ * @param sourcelength length of source to test, or -1 if NUL-terminated
+ * @param mode         which normalization form to test for
+ * @param status       a pointer to a UErrorCode to receive any errors
+ * @return UNORM_YES, UNORM_NO or UNORM_MAYBE
+ *
+ * @see unorm_isNormalized
+ * @stable ICU 2.0
+ */
+U_STABLE UNormalizationCheckResult U_EXPORT2
+unorm_quickCheck(const UChar *source, int32_t sourcelength,
+                 UNormalizationMode mode,
+                 UErrorCode *status);
+
+/**
+ * Performing quick check on a string; same as unorm_quickCheck but
+ * takes an extra options parameter like most normalization functions.
+ *
+ * @param src        String that is to be tested if it is in a normalization format.
+ * @param srcLength  Length of source to test, or -1 if NUL-terminated.
+ * @param mode       Which normalization form to test for.
+ * @param options    The normalization options, ORed together (0 for no options).
+ * @param pErrorCode ICU error code in/out parameter.
+ *                   Must fulfill U_SUCCESS before the function call.
+ * @return UNORM_YES, UNORM_NO or UNORM_MAYBE
+ *
+ * @see unorm_quickCheck
+ * @see unorm_isNormalized
+ * @stable ICU 2.6
+ */
+U_STABLE UNormalizationCheckResult U_EXPORT2
+unorm_quickCheckWithOptions(const UChar *src, int32_t srcLength, 
+                            UNormalizationMode mode, int32_t options,
+                            UErrorCode *pErrorCode);
+
+/**
+ * Test if a string is in a given normalization form.
+ * This is semantically equivalent to source.equals(normalize(source, mode)) .
+ *
+ * Unlike unorm_quickCheck(), this function returns a definitive result,
+ * never a "maybe".
+ * For NFD, NFKD, and FCD, both functions work exactly the same.
+ * For NFC and NFKC where quickCheck may return "maybe", this function will
+ * perform further tests to arrive at a TRUE/FALSE result.
+ *
+ * @param src        String that is to be tested if it is in a normalization format.
+ * @param srcLength  Length of source to test, or -1 if NUL-terminated.
+ * @param mode       Which normalization form to test for.
+ * @param pErrorCode ICU error code in/out parameter.
+ *                   Must fulfill U_SUCCESS before the function call.
+ * @return Boolean value indicating whether the source string is in the
+ *         "mode" normalization form.
+ *
+ * @see unorm_quickCheck
+ * @stable ICU 2.2
+ */
+U_STABLE UBool U_EXPORT2
+unorm_isNormalized(const UChar *src, int32_t srcLength,
+                   UNormalizationMode mode,
+                   UErrorCode *pErrorCode);
+
+/**
+ * Test if a string is in a given normalization form; same as unorm_isNormalized but
+ * takes an extra options parameter like most normalization functions.
+ *
+ * @param src        String that is to be tested if it is in a normalization format.
+ * @param srcLength  Length of source to test, or -1 if NUL-terminated.
+ * @param mode       Which normalization form to test for.
+ * @param options    The normalization options, ORed together (0 for no options).
+ * @param pErrorCode ICU error code in/out parameter.
+ *                   Must fulfill U_SUCCESS before the function call.
+ * @return Boolean value indicating whether the source string is in the
+ *         "mode/options" normalization form.
+ *
+ * @see unorm_quickCheck
+ * @see unorm_isNormalized
+ * @stable ICU 2.6
+ */
+U_STABLE UBool U_EXPORT2
+unorm_isNormalizedWithOptions(const UChar *src, int32_t srcLength,
+                              UNormalizationMode mode, int32_t options,
+                              UErrorCode *pErrorCode);
+
+/**
+ * Iterative normalization forward.
+ * This function (together with unorm_previous) is somewhat
+ * similar to the C++ Normalizer class (see its non-static functions).
+ *
+ * Iterative normalization is useful when only a small portion of a longer
+ * string/text needs to be processed.
+ *
+ * For example, the likelihood may be high that processing the first 10% of some
+ * text will be sufficient to find certain data.
+ * Another example: When one wants to concatenate two normalized strings and get a
+ * normalized result, it is much more efficient to normalize just a small part of
+ * the result around the concatenation place instead of re-normalizing everything.
+ *
+ * The input text is an instance of the C character iteration API UCharIterator.
+ * It may wrap around a simple string, a CharacterIterator, a Replaceable, or any
+ * other kind of text object.
+ *
+ * If a buffer overflow occurs, then the caller needs to reset the iterator to the
+ * old index and call the function again with a larger buffer - if the caller cares
+ * for the actual output.
+ * Regardless of the output buffer, the iterator will always be moved to the next
+ * normalization boundary.
+ *
+ * This function (like unorm_previous) serves two purposes:
+ *
+ * 1) To find the next boundary so that the normalization of the part of the text
+ * from the current position to that boundary does not affect and is not affected
+ * by the part of the text beyond that boundary.
+ *
+ * 2) To normalize the text up to the boundary.
+ *
+ * The second step is optional, per the doNormalize parameter.
+ * It is omitted for operations like string concatenation, where the two adjacent
+ * string ends need to be normalized together.
+ * In such a case, the output buffer will just contain a copy of the text up to the
+ * boundary.
+ *
+ * pNeededToNormalize is an output-only parameter. Its output value is only defined
+ * if normalization was requested (doNormalize) and successful (especially, no
+ * buffer overflow).
+ * It is useful for operations like a normalizing transliterator, where one would
+ * not want to replace a piece of text if it is not modified.
+ *
+ * If doNormalize==TRUE and pNeededToNormalize!=NULL then *pNeeded... is set TRUE
+ * if the normalization was necessary.
+ *
+ * If doNormalize==FALSE then *pNeededToNormalize will be set to FALSE.
+ *
+ * If the buffer overflows, then *pNeededToNormalize will be undefined;
+ * essentially, whenever U_FAILURE is true (like in buffer overflows), this result
+ * will be undefined.
+ *
+ * @param src The input text in the form of a C character iterator.
+ * @param dest The output buffer; can be NULL if destCapacity==0 for pure preflighting.
+ * @param destCapacity The number of UChars that fit into dest.
+ * @param mode The normalization mode.
+ * @param options The normalization options, ORed together (0 for no options).
+ * @param doNormalize Indicates if the source text up to the next boundary
+ *                    is to be normalized (TRUE) or just copied (FALSE).
+ * @param pNeededToNormalize Output flag indicating if the normalization resulted in
+ *                           different text from the input.
+ *                           Not defined if an error occurs including buffer overflow.
+ *                           Always FALSE if !doNormalize.
+ * @param pErrorCode ICU error code in/out parameter.
+ *                   Must fulfill U_SUCCESS before the function call.
+ * @return Length of output (number of UChars) when successful or buffer overflow.
+ *
+ * @see unorm_previous
+ * @see unorm_normalize
+ *
+ * @stable ICU 2.1
+ */
+U_STABLE int32_t U_EXPORT2
+unorm_next(UCharIterator *src,
+           UChar *dest, int32_t destCapacity,
+           UNormalizationMode mode, int32_t options,
+           UBool doNormalize, UBool *pNeededToNormalize,
+           UErrorCode *pErrorCode);
+
+/**
+ * Iterative normalization backward.
+ * This function (together with unorm_next) is somewhat
+ * similar to the C++ Normalizer class (see its non-static functions).
+ * For all details see unorm_next.
+ *
+ * @param src The input text in the form of a C character iterator.
+ * @param dest The output buffer; can be NULL if destCapacity==0 for pure preflighting.
+ * @param destCapacity The number of UChars that fit into dest.
+ * @param mode The normalization mode.
+ * @param options The normalization options, ORed together (0 for no options).
+ * @param doNormalize Indicates if the source text up to the next boundary
+ *                    is to be normalized (TRUE) or just copied (FALSE).
+ * @param pNeededToNormalize Output flag indicating if the normalization resulted in
+ *                           different text from the input.
+ *                           Not defined if an error occurs including buffer overflow.
+ *                           Always FALSE if !doNormalize.
+ * @param pErrorCode ICU error code in/out parameter.
+ *                   Must fulfill U_SUCCESS before the function call.
+ * @return Length of output (number of UChars) when successful or buffer overflow.
+ *
+ * @see unorm_next
+ * @see unorm_normalize
+ *
+ * @stable ICU 2.1
+ */
+U_STABLE int32_t U_EXPORT2
+unorm_previous(UCharIterator *src,
+               UChar *dest, int32_t destCapacity,
+               UNormalizationMode mode, int32_t options,
+               UBool doNormalize, UBool *pNeededToNormalize,
+               UErrorCode *pErrorCode);
+
+/**
+ * Concatenate normalized strings, making sure that the result is normalized as well.
+ *
+ * If both the left and the right strings are in
+ * the normalization form according to "mode/options",
+ * then the result will be
+ *
+ * \code
+ *     dest=normalize(left+right, mode, options)
+ * \endcode
+ *
+ * With the input strings already being normalized,
+ * this function will use unorm_next() and unorm_previous()
+ * to find the adjacent end pieces of the input strings.
+ * Only the concatenation of these end pieces will be normalized and
+ * then concatenated with the remaining parts of the input strings.
+ *
+ * It is allowed to have dest==left to avoid copying the entire left string.
+ *
+ * @param left Left source string, may be same as dest.
+ * @param leftLength Length of left source string, or -1 if NUL-terminated.
+ * @param right Right source string. Must not be the same as dest, nor overlap.
+ * @param rightLength Length of right source string, or -1 if NUL-terminated.
+ * @param dest The output buffer; can be NULL if destCapacity==0 for pure preflighting.
+ * @param destCapacity The number of UChars that fit into dest.
+ * @param mode The normalization mode.
+ * @param options The normalization options, ORed together (0 for no options).
+ * @param pErrorCode ICU error code in/out parameter.
+ *                   Must fulfill U_SUCCESS before the function call.
+ * @return Length of output (number of UChars) when successful or buffer overflow.
+ *
+ * @see unorm_normalize
+ * @see unorm_next
+ * @see unorm_previous
+ *
+ * @stable ICU 2.1
+ */
+U_STABLE int32_t U_EXPORT2
+unorm_concatenate(const UChar *left, int32_t leftLength,
+                  const UChar *right, int32_t rightLength,
+                  UChar *dest, int32_t destCapacity,
+                  UNormalizationMode mode, int32_t options,
+                  UErrorCode *pErrorCode);
+
+/**
+ * Option bit for unorm_compare:
+ * Both input strings are assumed to fulfill FCD conditions.
+ * @stable ICU 2.2
+ */
+#define UNORM_INPUT_IS_FCD          0x20000
+
+/**
+ * Option bit for unorm_compare:
+ * Perform case-insensitive comparison.
+ * @stable ICU 2.2
+ */
+#define U_COMPARE_IGNORE_CASE       0x10000
+
+#ifndef U_COMPARE_CODE_POINT_ORDER
+/* see also unistr.h and ustring.h */
+/**
+ * Option bit for u_strCaseCompare, u_strcasecmp, unorm_compare, etc:
+ * Compare strings in code point order instead of code unit order.
+ * @stable ICU 2.2
+ */
+#define U_COMPARE_CODE_POINT_ORDER  0x8000
+#endif
+
+/**
+ * Compare two strings for canonical equivalence.
+ * Further options include case-insensitive comparison and
+ * code point order (as opposed to code unit order).
+ *
+ * Canonical equivalence between two strings is defined as their normalized
+ * forms (NFD or NFC) being identical.
+ * This function compares strings incrementally instead of normalizing
+ * (and optionally case-folding) both strings entirely,
+ * improving performance significantly.
+ *
+ * Bulk normalization is only necessary if the strings do not fulfill the FCD
+ * conditions. Only in this case, and only if the strings are relatively long,
+ * is memory allocated temporarily.
+ * For FCD strings and short non-FCD strings there is no memory allocation.
+ *
+ * Semantically, this is equivalent to
+ *   strcmp[CodePointOrder](NFD(foldCase(NFD(s1))), NFD(foldCase(NFD(s2))))
+ * where code point order and foldCase are all optional.
+ *
+ * UAX 21 2.5 Caseless Matching specifies that for a canonical caseless match
+ * the case folding must be performed first, then the normalization.
+ *
+ * @param s1 First source string.
+ * @param length1 Length of first source string, or -1 if NUL-terminated.
+ *
+ * @param s2 Second source string.
+ * @param length2 Length of second source string, or -1 if NUL-terminated.
+ *
+ * @param options A bit set of options:
+ *   - U_FOLD_CASE_DEFAULT or 0 is used for default options:
+ *     Case-sensitive comparison in code unit order, and the input strings
+ *     are quick-checked for FCD.
+ *
+ *   - UNORM_INPUT_IS_FCD
+ *     Set if the caller knows that both s1 and s2 fulfill the FCD conditions.
+ *     If not set, the function will quickCheck for FCD
+ *     and normalize if necessary.
+ *
+ *   - U_COMPARE_CODE_POINT_ORDER
+ *     Set to choose code point order instead of code unit order
+ *     (see u_strCompare for details).
+ *
+ *   - U_COMPARE_IGNORE_CASE
+ *     Set to compare strings case-insensitively using case folding,
+ *     instead of case-sensitively.
+ *     If set, then the following case folding options are used.
+ *
+ *   - Options as used with case-insensitive comparisons, currently:
+ *
+ *   - U_FOLD_CASE_EXCLUDE_SPECIAL_I
+ *    (see u_strCaseCompare for details)
+ *
+ *   - regular normalization options shifted left by UNORM_COMPARE_NORM_OPTIONS_SHIFT
+ *
+ * @param pErrorCode ICU error code in/out parameter.
+ *                   Must fulfill U_SUCCESS before the function call.
+ * @return <0 or 0 or >0 as usual for string comparisons
+ *
+ * @see unorm_normalize
+ * @see UNORM_FCD
+ * @see u_strCompare
+ * @see u_strCaseCompare
+ *
+ * @stable ICU 2.2
+ */
+U_STABLE int32_t U_EXPORT2
+unorm_compare(const UChar *s1, int32_t length1,
+              const UChar *s2, int32_t length2,
+              uint32_t options,
+              UErrorCode *pErrorCode);
+
+#endif /* #if !UCONFIG_NO_NORMALIZATION */
+
+#endif
diff --git a/source/common/unicode/unorm2.h b/source/common/unicode/unorm2.h
new file mode 100644
index 0000000..a522b47
--- /dev/null
+++ b/source/common/unicode/unorm2.h
@@ -0,0 +1,391 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2009-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  unorm2.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2009dec15
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __UNORM2_H__
+#define __UNORM2_H__
+
+/**
+ * \file
+ * \brief C API: New API for Unicode Normalization.
+ *
+ * Unicode normalization functionality for standard Unicode normalization or
+ * for using custom mapping tables.
+ * All instances of UNormalizer2 are unmodifiable/immutable.
+ * Instances returned by unorm2_getInstance() are singletons that must not be deleted by the caller.
+ * For more details see the Normalizer2 C++ class.
+ */
+
+#include "unicode/utypes.h"
+#include "unicode/localpointer.h"
+#include "unicode/uset.h"
+
+/**
+ * Constants for normalization modes.
+ * For details about standard Unicode normalization forms
+ * and about the algorithms which are also used with custom mapping tables
+ * see http://www.unicode.org/unicode/reports/tr15/
+ * @stable ICU 4.4
+ */
+typedef enum {
+    /**
+     * Decomposition followed by composition.
+     * Same as standard NFC when using an "nfc" instance.
+     * Same as standard NFKC when using an "nfkc" instance.
+     * For details about standard Unicode normalization forms
+     * see http://www.unicode.org/unicode/reports/tr15/
+     * @stable ICU 4.4
+     */
+    UNORM2_COMPOSE,
+    /**
+     * Map, and reorder canonically.
+     * Same as standard NFD when using an "nfc" instance.
+     * Same as standard NFKD when using an "nfkc" instance.
+     * For details about standard Unicode normalization forms
+     * see http://www.unicode.org/unicode/reports/tr15/
+     * @stable ICU 4.4
+     */
+    UNORM2_DECOMPOSE,
+    /**
+     * "Fast C or D" form.
+     * If a string is in this form, then further decomposition <i>without reordering</i>
+     * would yield the same form as DECOMPOSE.
+     * Text in "Fast C or D" form can be processed efficiently with data tables
+     * that are "canonically closed", that is, that provide equivalent data for
+     * equivalent text, without having to be fully normalized.
+     * Not a standard Unicode normalization form.
+     * Not a unique form: Different FCD strings can be canonically equivalent.
+     * For details see http://www.unicode.org/notes/tn5/#FCD
+     * @stable ICU 4.4
+     */
+    UNORM2_FCD,
+    /**
+     * Compose only contiguously.
+     * Also known as "FCC" or "Fast C Contiguous".
+     * The result will often but not always be in NFC.
+     * The result will conform to FCD which is useful for processing.
+     * Not a standard Unicode normalization form.
+     * For details see http://www.unicode.org/notes/tn5/#FCC
+     * @stable ICU 4.4
+     */
+    UNORM2_COMPOSE_CONTIGUOUS
+} UNormalization2Mode;
+
+/**
+ * Result values for normalization quick check functions.
+ * For details see http://www.unicode.org/reports/tr15/#Detecting_Normalization_Forms
+ * @stable ICU 2.0
+ */
+typedef enum UNormalizationCheckResult {
+  /**
+   * The input string is not in the normalization form.
+   * @stable ICU 2.0
+   */
+  UNORM_NO,
+  /**
+   * The input string is in the normalization form.
+   * @stable ICU 2.0
+   */
+  UNORM_YES,
+  /**
+   * The input string may or may not be in the normalization form.
+   * This value is only returned for composition forms like NFC and FCC,
+   * when a backward-combining character is found for which the surrounding text
+   * would have to be analyzed further.
+   * @stable ICU 2.0
+   */
+  UNORM_MAYBE
+} UNormalizationCheckResult;
+
+/**
+ * Opaque C service object type for the new normalization API.
+ * @stable ICU 4.4
+ */
+struct UNormalizer2;
+typedef struct UNormalizer2 UNormalizer2;  /**< C typedef for struct UNormalizer2. @stable ICU 4.4 */
+
+#if !UCONFIG_NO_NORMALIZATION
+
+/**
+ * Returns a UNormalizer2 instance which uses the specified data file
+ * (packageName/name similar to ucnv_openPackage() and ures_open()/ResourceBundle)
+ * and which composes or decomposes text according to the specified mode.
+ * Returns an unmodifiable singleton instance. Do not delete it.
+ *
+ * Use packageName=NULL for data files that are part of ICU's own data.
+ * Use name="nfc" and UNORM2_COMPOSE/UNORM2_DECOMPOSE for Unicode standard NFC/NFD.
+ * Use name="nfkc" and UNORM2_COMPOSE/UNORM2_DECOMPOSE for Unicode standard NFKC/NFKD.
+ * Use name="nfkc_cf" and UNORM2_COMPOSE for Unicode standard NFKC_CF=NFKC_Casefold.
+ *
+ * @param packageName NULL for ICU built-in data, otherwise application data package name
+ * @param name "nfc" or "nfkc" or "nfkc_cf" or name of custom data file
+ * @param mode normalization mode (compose or decompose etc.)
+ * @param pErrorCode 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 requested UNormalizer2, if successful
+ * @stable ICU 4.4
+ */
+U_STABLE const UNormalizer2 * U_EXPORT2
+unorm2_getInstance(const char *packageName,
+                   const char *name,
+                   UNormalization2Mode mode,
+                   UErrorCode *pErrorCode);
+
+/**
+ * Constructs a filtered normalizer wrapping any UNormalizer2 instance
+ * and a filter set.
+ * Both are aliased and must not be modified or deleted while this object
+ * is used.
+ * The filter set should be frozen; otherwise the performance will suffer greatly.
+ * @param norm2 wrapped UNormalizer2 instance
+ * @param filterSet USet which determines the characters to be normalized
+ * @param pErrorCode 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 requested UNormalizer2, if successful
+ * @stable ICU 4.4
+ */
+U_STABLE UNormalizer2 * U_EXPORT2
+unorm2_openFiltered(const UNormalizer2 *norm2, const USet *filterSet, UErrorCode *pErrorCode);
+
+/**
+ * Closes a UNormalizer2 instance from unorm2_openFiltered().
+ * Do not close instances from unorm2_getInstance()!
+ * @param norm2 UNormalizer2 instance to be closed
+ * @stable ICU 4.4
+ */
+U_STABLE void U_EXPORT2
+unorm2_close(UNormalizer2 *norm2);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUNormalizer2Pointer
+ * "Smart pointer" class, closes a UNormalizer2 via unorm2_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUNormalizer2Pointer, UNormalizer2, unorm2_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Writes the normalized form of the source string to the destination string
+ * (replacing its contents) and returns the length of the destination string.
+ * The source and destination strings must be different buffers.
+ * @param norm2 UNormalizer2 instance
+ * @param src source string
+ * @param length length of the source string, or -1 if NUL-terminated
+ * @param dest destination string; its contents is replaced with normalized src
+ * @param capacity number of UChars that can be written to dest
+ * @param pErrorCode 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 dest
+ * @stable ICU 4.4
+ */
+U_STABLE int32_t U_EXPORT2
+unorm2_normalize(const UNormalizer2 *norm2,
+                 const UChar *src, int32_t length,
+                 UChar *dest, int32_t capacity,
+                 UErrorCode *pErrorCode);
+/**
+ * Appends the normalized form of the second string to the first string
+ * (merging them at the boundary) and returns the length of the first string.
+ * The result is normalized if the first string was normalized.
+ * The first and second strings must be different buffers.
+ * @param norm2 UNormalizer2 instance
+ * @param first string, should be normalized
+ * @param firstLength length of the first string, or -1 if NUL-terminated
+ * @param firstCapacity number of UChars that can be written to first
+ * @param second string, will be normalized
+ * @param secondLength length of the source string, or -1 if NUL-terminated
+ * @param pErrorCode 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 first
+ * @stable ICU 4.4
+ */
+U_STABLE int32_t U_EXPORT2
+unorm2_normalizeSecondAndAppend(const UNormalizer2 *norm2,
+                                UChar *first, int32_t firstLength, int32_t firstCapacity,
+                                const UChar *second, int32_t secondLength,
+                                UErrorCode *pErrorCode);
+/**
+ * Appends the second string to the first string
+ * (merging them at the boundary) and returns the length of the first string.
+ * The result is normalized if both the strings were normalized.
+ * The first and second strings must be different buffers.
+ * @param norm2 UNormalizer2 instance
+ * @param first string, should be normalized
+ * @param firstLength length of the first string, or -1 if NUL-terminated
+ * @param firstCapacity number of UChars that can be written to first
+ * @param second string, should be normalized
+ * @param secondLength length of the source string, or -1 if NUL-terminated
+ * @param pErrorCode 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 first
+ * @stable ICU 4.4
+ */
+U_STABLE int32_t U_EXPORT2
+unorm2_append(const UNormalizer2 *norm2,
+              UChar *first, int32_t firstLength, int32_t firstCapacity,
+              const UChar *second, int32_t secondLength,
+              UErrorCode *pErrorCode);
+
+/**
+ * Gets the decomposition mapping of c. Equivalent to unorm2_normalize(string(c))
+ * on a UNORM2_DECOMPOSE UNormalizer2 instance, but much faster.
+ * This function is independent of the mode of the UNormalizer2.
+ * @param norm2 UNormalizer2 instance
+ * @param c code point
+ * @param decomposition String buffer which will be set to c's
+ *                      decomposition mapping, if there is one.
+ * @param capacity number of UChars that can be written to decomposition
+ * @param pErrorCode 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 non-negative length of c's decomposition, if there is one; otherwise a negative value
+ * @draft ICU 4.6
+ */
+U_DRAFT int32_t U_EXPORT2
+unorm2_getDecomposition(const UNormalizer2 *norm2,
+                        UChar32 c, UChar *decomposition, int32_t capacity,
+                        UErrorCode *pErrorCode);
+
+/**
+ * Tests if the string is normalized.
+ * Internally, in cases where the quickCheck() method would return "maybe"
+ * (which is only possible for the two COMPOSE modes) this method
+ * resolves to "yes" or "no" to provide a definitive result,
+ * at the cost of doing more work in those cases.
+ * @param norm2 UNormalizer2 instance
+ * @param s input string
+ * @param length length of the string, or -1 if NUL-terminated
+ * @param pErrorCode 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 TRUE if s is normalized
+ * @stable ICU 4.4
+ */
+U_STABLE UBool U_EXPORT2
+unorm2_isNormalized(const UNormalizer2 *norm2,
+                    const UChar *s, int32_t length,
+                    UErrorCode *pErrorCode);
+
+/**
+ * Tests if the string is normalized.
+ * For the two COMPOSE modes, the result could be "maybe" in cases that
+ * would take a little more work to resolve definitively.
+ * Use spanQuickCheckYes() and normalizeSecondAndAppend() for a faster
+ * combination of quick check + normalization, to avoid
+ * re-checking the "yes" prefix.
+ * @param norm2 UNormalizer2 instance
+ * @param s input string
+ * @param length length of the string, or -1 if NUL-terminated
+ * @param pErrorCode 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 UNormalizationCheckResult
+ * @stable ICU 4.4
+ */
+U_STABLE UNormalizationCheckResult U_EXPORT2
+unorm2_quickCheck(const UNormalizer2 *norm2,
+                  const UChar *s, int32_t length,
+                  UErrorCode *pErrorCode);
+
+/**
+ * Returns the end of the normalized substring of the input string.
+ * In other words, with <code>end=spanQuickCheckYes(s, ec);</code>
+ * the substring <code>UnicodeString(s, 0, end)</code>
+ * will pass the quick check with a "yes" result.
+ *
+ * The returned end index is usually one or more characters before the
+ * "no" or "maybe" character: The end index is at a normalization boundary.
+ * (See the class documentation for more about normalization boundaries.)
+ *
+ * When the goal is a normalized string and most input strings are expected
+ * to be normalized already, then call this method,
+ * and if it returns a prefix shorter than the input string,
+ * copy that prefix and use normalizeSecondAndAppend() for the remainder.
+ * @param norm2 UNormalizer2 instance
+ * @param s input string
+ * @param length length of the string, or -1 if NUL-terminated
+ * @param pErrorCode 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 "yes" span end index
+ * @stable ICU 4.4
+ */
+U_STABLE int32_t U_EXPORT2
+unorm2_spanQuickCheckYes(const UNormalizer2 *norm2,
+                         const UChar *s, int32_t length,
+                         UErrorCode *pErrorCode);
+
+/**
+ * Tests if the character always has a normalization boundary before it,
+ * regardless of context.
+ * For details see the Normalizer2 base class documentation.
+ * @param norm2 UNormalizer2 instance
+ * @param c character to test
+ * @return TRUE if c has a normalization boundary before it
+ * @stable ICU 4.4
+ */
+U_STABLE UBool U_EXPORT2
+unorm2_hasBoundaryBefore(const UNormalizer2 *norm2, UChar32 c);
+
+/**
+ * Tests if the character always has a normalization boundary after it,
+ * regardless of context.
+ * For details see the Normalizer2 base class documentation.
+ * @param norm2 UNormalizer2 instance
+ * @param c character to test
+ * @return TRUE if c has a normalization boundary after it
+ * @stable ICU 4.4
+ */
+U_STABLE UBool U_EXPORT2
+unorm2_hasBoundaryAfter(const UNormalizer2 *norm2, UChar32 c);
+
+/**
+ * Tests if the character is normalization-inert.
+ * For details see the Normalizer2 base class documentation.
+ * @param norm2 UNormalizer2 instance
+ * @param c character to test
+ * @return TRUE if c is normalization-inert
+ * @stable ICU 4.4
+ */
+U_STABLE UBool U_EXPORT2
+unorm2_isInert(const UNormalizer2 *norm2, UChar32 c);
+
+#endif  /* !UCONFIG_NO_NORMALIZATION */
+#endif  /* __UNORM2_H__ */
diff --git a/source/common/unicode/uobject.h b/source/common/unicode/uobject.h
new file mode 100644
index 0000000..27d4c84
--- /dev/null
+++ b/source/common/unicode/uobject.h
@@ -0,0 +1,352 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2002-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  uobject.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002jun26
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __UOBJECT_H__
+#define __UOBJECT_H__
+
+#include "unicode/utypes.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \file
+ * \brief C++ API: Common ICU base class UObject.
+ */
+
+/**  U_OVERRIDE_CXX_ALLOCATION - Define this to override operator new and
+ *                               delete in UMemory. Enabled by default for ICU.
+ *
+ *         Enabling forces all allocation of ICU object types to use ICU's
+ *         memory allocation. On Windows, this allows the ICU DLL to be used by
+ *         applications that statically link the C Runtime library, meaning that
+ *         the app and ICU will be using different heaps.
+ *
+ * @stable ICU 2.2
+ */                              
+#ifndef U_OVERRIDE_CXX_ALLOCATION
+#define U_OVERRIDE_CXX_ALLOCATION 1
+#endif
+
+/** 
+ * \def U_HAVE_PLACEMENT_NEW
+ *  Define this to define the placement new and
+ *                          delete in UMemory for STL.
+ *
+ * @stable ICU 2.6
+ */                              
+#ifndef U_HAVE_PLACEMENT_NEW
+#define U_HAVE_PLACEMENT_NEW 1
+#endif
+
+
+/** 
+ * \def U_HAVE_DEBUG_LOCATION_NEW 
+ * Define this to define the MFC debug
+ * version of the operator new.
+ *
+ * @stable ICU 3.4
+ */                              
+#ifndef U_HAVE_DEBUG_LOCATION_NEW
+#define U_HAVE_DEBUG_LOCATION_NEW 0
+#endif
+
+/**
+ * @{
+ * \def U_NO_THROW
+ *         Define this to define the throw() specification so
+ *                 certain functions do not throw any exceptions
+ *
+ *         UMemory operator new methods should have the throw() specification 
+ *         appended to them, so that the compiler adds the additional NULL check 
+ *         before calling constructors. Without, if <code>operator new</code> returns NULL the 
+ *         constructor is still called, and if the constructor references member 
+ *         data, (which it typically does), the result is a segmentation violation.
+ *
+ * @draft ICU 4.2
+ */                              
+#ifndef U_NO_THROW
+#define U_NO_THROW throw()
+#endif
+
+/** @} */
+
+/**
+ * UMemory is the common ICU base class.
+ * All other ICU C++ classes are derived from UMemory (starting with ICU 2.4).
+ *
+ * This is primarily to make it possible and simple to override the
+ * C++ memory management by adding new/delete operators to this base class.
+ *
+ * To override ALL ICU memory management, including that from plain C code,
+ * replace the allocation functions declared in cmemory.h
+ *
+ * UMemory does not contain any virtual functions.
+ * Common "boilerplate" functions are defined in UObject.
+ *
+ * @stable ICU 2.4
+ */
+class U_COMMON_API UMemory {
+public:
+
+/* test versions for debugging shaper heap memory problems */
+#ifdef SHAPER_MEMORY_DEBUG  
+    static void * NewArray(int size, int count);
+    static void * GrowArray(void * array, int newSize );
+    static void   FreeArray(void * array );
+#endif
+
+#if U_OVERRIDE_CXX_ALLOCATION
+    /**
+     * Override for ICU4C C++ memory management.
+     * simple, non-class types are allocated using the macros in common/cmemory.h
+     * (uprv_malloc(), uprv_free(), uprv_realloc());
+     * they or something else could be used here to implement C++ new/delete
+     * for ICU4C C++ classes
+     * @stable ICU 2.4
+     */
+    static void * U_EXPORT2 operator new(size_t size) U_NO_THROW;
+
+    /**
+     * Override for ICU4C C++ memory management.
+     * See new().
+     * @stable ICU 2.4
+     */
+    static void * U_EXPORT2 operator new[](size_t size) U_NO_THROW;
+
+    /**
+     * Override for ICU4C C++ memory management.
+     * simple, non-class types are allocated using the macros in common/cmemory.h
+     * (uprv_malloc(), uprv_free(), uprv_realloc());
+     * they or something else could be used here to implement C++ new/delete
+     * for ICU4C C++ classes
+     * @stable ICU 2.4
+     */
+    static void U_EXPORT2 operator delete(void *p) U_NO_THROW;
+
+    /**
+     * Override for ICU4C C++ memory management.
+     * See delete().
+     * @stable ICU 2.4
+     */
+    static void U_EXPORT2 operator delete[](void *p) U_NO_THROW;
+
+#if U_HAVE_PLACEMENT_NEW
+    /**
+     * Override for ICU4C C++ memory management for STL.
+     * See new().
+     * @stable ICU 2.6
+     */
+    static inline void * U_EXPORT2 operator new(size_t, void *ptr) U_NO_THROW { return ptr; }
+
+    /**
+     * Override for ICU4C C++ memory management for STL.
+     * See delete().
+     * @stable ICU 2.6
+     */
+    static inline void U_EXPORT2 operator delete(void *, void *) U_NO_THROW {}
+#endif /* U_HAVE_PLACEMENT_NEW */
+#if U_HAVE_DEBUG_LOCATION_NEW
+    /**
+      * This method overrides the MFC debug version of the operator new
+      * 
+      * @param size   The requested memory size
+      * @param file   The file where the allocation was requested
+      * @param line   The line where the allocation was requested 
+      */ 
+    static void * U_EXPORT2 operator new(size_t size, const char* file, int line) U_NO_THROW;
+    /**
+      * This method provides a matching delete for the MFC debug new
+      * 
+      * @param p      The pointer to the allocated memory
+      * @param file   The file where the allocation was requested
+      * @param line   The line where the allocation was requested 
+      */ 
+    static void U_EXPORT2 operator delete(void* p, const char* file, int line) U_NO_THROW;
+#endif /* U_HAVE_DEBUG_LOCATION_NEW */
+#endif /* U_OVERRIDE_CXX_ALLOCATION */
+
+    /*
+     * Assignment operator not declared. The compiler will provide one
+     * which does nothing since this class does not contain any data members.
+     * API/code coverage may show the assignment operator as present and
+     * untested - ignore.
+     * Subclasses need this assignment operator if they use compiler-provided
+     * assignment operators of their own. An alternative to not declaring one
+     * here would be to declare and empty-implement a protected or public one.
+    UMemory &UMemory::operator=(const UMemory &);
+     */
+};
+
+/**
+ * UObject is the common ICU "boilerplate" class.
+ * UObject inherits UMemory (starting with ICU 2.4),
+ * and all other public ICU C++ classes
+ * are derived from UObject (starting with ICU 2.2).
+ *
+ * UObject contains common virtual functions like for ICU's "poor man's RTTI".
+ * It does not contain default implementations of virtual methods
+ * like getDynamicClassID to allow derived classes such as Format
+ * to declare these as pure virtual.
+ *
+ * The clone() function is not available in UObject because it is not
+ * implemented by all ICU classes.
+ * Many ICU services provide a clone() function for their class trees,
+ * defined on the service's C++ base class, and all subclasses within that
+ * service class tree return a pointer to the service base class
+ * (which itself is a subclass of UObject).
+ * This is because some compilers do not support covariant (same-as-this)
+ * return types; cast to the appropriate subclass if necessary.
+ *
+ * @stable ICU 2.2
+ */
+class U_COMMON_API UObject : public UMemory {
+public:
+    /**
+     * Destructor.
+     *
+     * @stable ICU 2.2
+     */
+    virtual ~UObject();
+
+    /**
+     * ICU4C "poor man's RTTI", returns a UClassID for the actual ICU class.
+     *
+     * @stable ICU 2.2
+     */
+    virtual UClassID getDynamicClassID() const = 0;
+
+protected:
+    // the following functions are protected to prevent instantiation and
+    // direct use of UObject itself
+
+    // default constructor
+    // commented out because UObject is abstract (see getDynamicClassID)
+    // inline UObject() {}
+
+    // copy constructor
+    // commented out because UObject is abstract (see getDynamicClassID)
+    // inline UObject(const UObject &other) {}
+
+#if 0
+    // TODO Sometime in the future. Implement operator==().
+    // (This comment inserted in 2.2)
+    // some or all of the following "boilerplate" functions may be made public
+    // in a future ICU4C release when all subclasses implement them
+
+    // assignment operator
+    // (not virtual, see "Taligent's Guide to Designing Programs" pp.73..74)
+    // commented out because the implementation is the same as a compiler's default
+    // UObject &operator=(const UObject &other) { return *this; }
+
+    // comparison operators
+    virtual inline UBool operator==(const UObject &other) const { return this==&other; }
+    inline UBool operator!=(const UObject &other) const { return !operator==(other); }
+
+    // clone() commented out from the base class:
+    // some compilers do not support co-variant return types
+    // (i.e., subclasses would have to return UObject * as well, instead of SubClass *)
+    // see also UObject class documentation.
+    // virtual UObject *clone() const;
+#endif
+
+    /*
+     * Assignment operator not declared. The compiler will provide one
+     * which does nothing since this class does not contain any data members.
+     * API/code coverage may show the assignment operator as present and
+     * untested - ignore.
+     * Subclasses need this assignment operator if they use compiler-provided
+     * assignment operators of their own. An alternative to not declaring one
+     * here would be to declare and empty-implement a protected or public one.
+    UObject &UObject::operator=(const UObject &);
+     */
+
+// Future implementation for RTTI that support subtyping. [alan]
+// 
+//  public:
+//     /**
+//      * @internal
+//      */
+//     static UClassID getStaticClassID();
+// 
+//     /**
+//      * @internal
+//      */
+//     UBool instanceOf(UClassID type) const;
+};
+
+/**
+ * This is a simple macro to add ICU RTTI to an ICU object implementation.
+ * This does not go into the header. This should only be used in *.cpp files.
+ *
+ * @param myClass The name of the class that needs RTTI defined.
+ * @internal
+ */
+#define UOBJECT_DEFINE_RTTI_IMPLEMENTATION(myClass) \
+    UClassID U_EXPORT2 myClass::getStaticClassID() { \
+        static char classID = 0; \
+        return (UClassID)&classID; \
+    } \
+    UClassID myClass::getDynamicClassID() const \
+    { return myClass::getStaticClassID(); }
+
+
+/**
+ * This macro adds ICU RTTI to an ICU abstract class implementation.
+ * This macro should be invoked in *.cpp files.  The corresponding
+ * header should declare getStaticClassID.
+ *
+ * @param myClass The name of the class that needs RTTI defined.
+ * @internal
+ */
+#define UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(myClass) \
+    UClassID U_EXPORT2 myClass::getStaticClassID() { \
+        static char classID = 0; \
+        return (UClassID)&classID; \
+    }
+
+/**
+ * This is a simple macro to express that a class and its subclasses do not offer
+ * ICU's "poor man's RTTI".
+ * Beginning with ICU 4.6, ICU requires C++ compiler RTTI.
+ * This does not go into the header. This should only be used in *.cpp files.
+ * Use this with a private getDynamicClassID() in an immediate subclass of UObject.
+ *
+ * @param myClass The name of the class that needs RTTI defined.
+ * @internal
+ */
+#define UOBJECT_DEFINE_NO_RTTI_IMPLEMENTATION(myClass) \
+    UClassID myClass::getDynamicClassID() const { return NULL; }
+
+// /**
+//  * This macro adds ICU RTTI to an ICU concrete class implementation.
+//  * This macro should be invoked in *.cpp files.  The corresponding
+//  * header should declare getDynamicClassID and getStaticClassID.
+//  *
+//  * @param myClass The name of the class that needs RTTI defined.
+//  * @param myParent The name of the myClass's parent.
+//  * @internal
+//  */
+/*#define UOBJECT_DEFINE_RTTI_IMPLEMENTATION(myClass, myParent) \
+    UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(myClass, myParent) \
+    UClassID myClass::getDynamicClassID() const { \
+        return myClass::getStaticClassID(); \
+    }
+*/
+
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/unicode/uobslete.h b/source/common/unicode/uobslete.h
new file mode 100644
index 0000000..1ef6e85
--- /dev/null
+++ b/source/common/unicode/uobslete.h
@@ -0,0 +1,32 @@
+/*
+*******************************************************************************
+*   Copyright (C) 2004-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*******************************************************************************
+*
+*   file name:  uobslete.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   Created by: genheaders.pl, a perl script written by Ram Viswanadha
+*
+*  Contains data for commenting out APIs.
+*  Gets included by umachine.h
+*
+*  THIS FILE IS MACHINE-GENERATED, DON'T PLAY WITH IT IF YOU DON'T KNOW WHAT
+*  YOU ARE DOING, OTHERWISE VERY BAD THINGS WILL HAPPEN!
+*/
+
+#ifndef UOBSLETE_H
+#define UOBSLETE_H
+
+#ifdef U_HIDE_OBSOLETE_API
+
+#    if U_DISABLE_RENAMING
+#    else
+#    endif /* U_DISABLE_RENAMING */
+
+#endif /* U_HIDE_OBSOLETE_API */
+#endif /* UOBSLETE_H */
+
diff --git a/source/common/unicode/urename.h b/source/common/unicode/urename.h
new file mode 100644
index 0000000..468bdbd
--- /dev/null
+++ b/source/common/unicode/urename.h
@@ -0,0 +1,2241 @@
+/*
+*******************************************************************************
+*   Copyright (C) 2002-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*******************************************************************************
+*
+*   file name:  urename.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   Created by: Perl script written by Vladimir Weinstein
+*
+*  Contains data for renaming ICU exports.
+*  Gets included by umachine.h
+*
+*  THIS FILE IS MACHINE-GENERATED, DON'T PLAY WITH IT IF YOU DON'T KNOW WHAT
+*  YOU ARE DOING, OTHERWISE VERY BAD THINGS WILL HAPPEN!
+*/
+
+#ifndef URENAME_H
+#define URENAME_H
+
+/* Uncomment the following line to disable renaming on platforms
+   that do not use Autoconf. */
+/* #define U_DISABLE_RENAMING 1 */
+
+#if !U_DISABLE_RENAMING
+
+/* We need the U_ICU_ENTRY_POINT_RENAME definition. There's a default one in unicode/uvernum.h we can use, but we will give
+   the platform a chance to define it first.
+   Normally (if utypes.h or umachine.h was included first) this will not be necessary as it will already be defined.
+ */
+#ifndef U_ICU_ENTRY_POINT_RENAME
+#include "unicode/umachine.h"
+#endif
+
+/* If we still don't have U_ICU_ENTRY_POINT_RENAME use the default. */
+#ifndef U_ICU_ENTRY_POINT_RENAME
+#include "unicode/uvernum.h"
+#endif
+
+/* Error out before the following defines cause very strange and unexpected code breakage */
+#ifndef U_ICU_ENTRY_POINT_RENAME
+#error U_ICU_ENTRY_POINT_RENAME is not defined - cannot continue. Consider defining U_DISABLE_RENAMING if renaming should not be used.
+#endif
+
+
+/* C exports renaming data */
+
+#define DECPOWERS U_ICU_ENTRY_POINT_RENAME(DECPOWERS)
+#define DECSTICKYTAB U_ICU_ENTRY_POINT_RENAME(DECSTICKYTAB)
+#define LNnn U_ICU_ENTRY_POINT_RENAME(LNnn)
+#define T_CString_int64ToString U_ICU_ENTRY_POINT_RENAME(T_CString_int64ToString)
+#define T_CString_integerToString U_ICU_ENTRY_POINT_RENAME(T_CString_integerToString)
+#define T_CString_stricmp U_ICU_ENTRY_POINT_RENAME(T_CString_stricmp)
+#define T_CString_stringToInteger U_ICU_ENTRY_POINT_RENAME(T_CString_stringToInteger)
+#define T_CString_strnicmp U_ICU_ENTRY_POINT_RENAME(T_CString_strnicmp)
+#define T_CString_toLowerCase U_ICU_ENTRY_POINT_RENAME(T_CString_toLowerCase)
+#define T_CString_toUpperCase U_ICU_ENTRY_POINT_RENAME(T_CString_toUpperCase)
+#define UCNV_FROM_U_CALLBACK_ESCAPE U_ICU_ENTRY_POINT_RENAME(UCNV_FROM_U_CALLBACK_ESCAPE)
+#define UCNV_FROM_U_CALLBACK_SKIP U_ICU_ENTRY_POINT_RENAME(UCNV_FROM_U_CALLBACK_SKIP)
+#define UCNV_FROM_U_CALLBACK_STOP U_ICU_ENTRY_POINT_RENAME(UCNV_FROM_U_CALLBACK_STOP)
+#define UCNV_FROM_U_CALLBACK_SUBSTITUTE U_ICU_ENTRY_POINT_RENAME(UCNV_FROM_U_CALLBACK_SUBSTITUTE)
+#define UCNV_TO_U_CALLBACK_ESCAPE U_ICU_ENTRY_POINT_RENAME(UCNV_TO_U_CALLBACK_ESCAPE)
+#define UCNV_TO_U_CALLBACK_SKIP U_ICU_ENTRY_POINT_RENAME(UCNV_TO_U_CALLBACK_SKIP)
+#define UCNV_TO_U_CALLBACK_STOP U_ICU_ENTRY_POINT_RENAME(UCNV_TO_U_CALLBACK_STOP)
+#define UCNV_TO_U_CALLBACK_SUBSTITUTE U_ICU_ENTRY_POINT_RENAME(UCNV_TO_U_CALLBACK_SUBSTITUTE)
+#define UDataMemory_createNewInstance U_ICU_ENTRY_POINT_RENAME(UDataMemory_createNewInstance)
+#define UDataMemory_init U_ICU_ENTRY_POINT_RENAME(UDataMemory_init)
+#define UDataMemory_isLoaded U_ICU_ENTRY_POINT_RENAME(UDataMemory_isLoaded)
+#define UDataMemory_normalizeDataPointer U_ICU_ENTRY_POINT_RENAME(UDataMemory_normalizeDataPointer)
+#define UDataMemory_setData U_ICU_ENTRY_POINT_RENAME(UDataMemory_setData)
+#define UDatamemory_assign U_ICU_ENTRY_POINT_RENAME(UDatamemory_assign)
+#define _ASCIIData U_ICU_ENTRY_POINT_RENAME(_ASCIIData)
+#define _Bocu1Data U_ICU_ENTRY_POINT_RENAME(_Bocu1Data)
+#define _CESU8Data U_ICU_ENTRY_POINT_RENAME(_CESU8Data)
+#define _HZData U_ICU_ENTRY_POINT_RENAME(_HZData)
+#define _IMAPData U_ICU_ENTRY_POINT_RENAME(_IMAPData)
+#define _ISCIIData U_ICU_ENTRY_POINT_RENAME(_ISCIIData)
+#define _ISO2022Data U_ICU_ENTRY_POINT_RENAME(_ISO2022Data)
+#define _LMBCSData1 U_ICU_ENTRY_POINT_RENAME(_LMBCSData1)
+#define _LMBCSData11 U_ICU_ENTRY_POINT_RENAME(_LMBCSData11)
+#define _LMBCSData16 U_ICU_ENTRY_POINT_RENAME(_LMBCSData16)
+#define _LMBCSData17 U_ICU_ENTRY_POINT_RENAME(_LMBCSData17)
+#define _LMBCSData18 U_ICU_ENTRY_POINT_RENAME(_LMBCSData18)
+#define _LMBCSData19 U_ICU_ENTRY_POINT_RENAME(_LMBCSData19)
+#define _LMBCSData2 U_ICU_ENTRY_POINT_RENAME(_LMBCSData2)
+#define _LMBCSData3 U_ICU_ENTRY_POINT_RENAME(_LMBCSData3)
+#define _LMBCSData4 U_ICU_ENTRY_POINT_RENAME(_LMBCSData4)
+#define _LMBCSData5 U_ICU_ENTRY_POINT_RENAME(_LMBCSData5)
+#define _LMBCSData6 U_ICU_ENTRY_POINT_RENAME(_LMBCSData6)
+#define _LMBCSData8 U_ICU_ENTRY_POINT_RENAME(_LMBCSData8)
+#define _Latin1Data U_ICU_ENTRY_POINT_RENAME(_Latin1Data)
+#define _MBCSData U_ICU_ENTRY_POINT_RENAME(_MBCSData)
+#define _SCSUData U_ICU_ENTRY_POINT_RENAME(_SCSUData)
+#define _UTF16BEData U_ICU_ENTRY_POINT_RENAME(_UTF16BEData)
+#define _UTF16Data U_ICU_ENTRY_POINT_RENAME(_UTF16Data)
+#define _UTF16LEData U_ICU_ENTRY_POINT_RENAME(_UTF16LEData)
+#define _UTF32BEData U_ICU_ENTRY_POINT_RENAME(_UTF32BEData)
+#define _UTF32Data U_ICU_ENTRY_POINT_RENAME(_UTF32Data)
+#define _UTF32LEData U_ICU_ENTRY_POINT_RENAME(_UTF32LEData)
+#define _UTF7Data U_ICU_ENTRY_POINT_RENAME(_UTF7Data)
+#define _UTF8Data U_ICU_ENTRY_POINT_RENAME(_UTF8Data)
+#define bms_close U_ICU_ENTRY_POINT_RENAME(bms_close)
+#define bms_empty U_ICU_ENTRY_POINT_RENAME(bms_empty)
+#define bms_getData U_ICU_ENTRY_POINT_RENAME(bms_getData)
+#define bms_open U_ICU_ENTRY_POINT_RENAME(bms_open)
+#define bms_search U_ICU_ENTRY_POINT_RENAME(bms_search)
+#define bms_setTargetString U_ICU_ENTRY_POINT_RENAME(bms_setTargetString)
+#define buildWSConfusableData U_ICU_ENTRY_POINT_RENAME(buildWSConfusableData)
+#define cmemory_cleanup U_ICU_ENTRY_POINT_RENAME(cmemory_cleanup)
+#define cmemory_inUse U_ICU_ENTRY_POINT_RENAME(cmemory_inUse)
+#define d2utable U_ICU_ENTRY_POINT_RENAME(d2utable)
+#define deleteCEList U_ICU_ENTRY_POINT_RENAME(deleteCEList)
+#define deleteChars U_ICU_ENTRY_POINT_RENAME(deleteChars)
+#define deleteCollDataCacheEntry U_ICU_ENTRY_POINT_RENAME(deleteCollDataCacheEntry)
+#define deleteStringList U_ICU_ENTRY_POINT_RENAME(deleteStringList)
+#define deleteUnicodeStringKey U_ICU_ENTRY_POINT_RENAME(deleteUnicodeStringKey)
+#define izrule_clone U_ICU_ENTRY_POINT_RENAME(izrule_clone)
+#define izrule_close U_ICU_ENTRY_POINT_RENAME(izrule_close)
+#define izrule_equals U_ICU_ENTRY_POINT_RENAME(izrule_equals)
+#define izrule_getDSTSavings U_ICU_ENTRY_POINT_RENAME(izrule_getDSTSavings)
+#define izrule_getDynamicClassID U_ICU_ENTRY_POINT_RENAME(izrule_getDynamicClassID)
+#define izrule_getFinalStart U_ICU_ENTRY_POINT_RENAME(izrule_getFinalStart)
+#define izrule_getFirstStart U_ICU_ENTRY_POINT_RENAME(izrule_getFirstStart)
+#define izrule_getName U_ICU_ENTRY_POINT_RENAME(izrule_getName)
+#define izrule_getNextStart U_ICU_ENTRY_POINT_RENAME(izrule_getNextStart)
+#define izrule_getPreviousStart U_ICU_ENTRY_POINT_RENAME(izrule_getPreviousStart)
+#define izrule_getRawOffset U_ICU_ENTRY_POINT_RENAME(izrule_getRawOffset)
+#define izrule_getStaticClassID U_ICU_ENTRY_POINT_RENAME(izrule_getStaticClassID)
+#define izrule_isEquivalentTo U_ICU_ENTRY_POINT_RENAME(izrule_isEquivalentTo)
+#define izrule_open U_ICU_ENTRY_POINT_RENAME(izrule_open)
+#define le_close U_ICU_ENTRY_POINT_RENAME(le_close)
+#define le_create U_ICU_ENTRY_POINT_RENAME(le_create)
+#define le_getCharIndices U_ICU_ENTRY_POINT_RENAME(le_getCharIndices)
+#define le_getCharIndicesWithBase U_ICU_ENTRY_POINT_RENAME(le_getCharIndicesWithBase)
+#define le_getGlyphCount U_ICU_ENTRY_POINT_RENAME(le_getGlyphCount)
+#define le_getGlyphPosition U_ICU_ENTRY_POINT_RENAME(le_getGlyphPosition)
+#define le_getGlyphPositions U_ICU_ENTRY_POINT_RENAME(le_getGlyphPositions)
+#define le_getGlyphs U_ICU_ENTRY_POINT_RENAME(le_getGlyphs)
+#define le_layoutChars U_ICU_ENTRY_POINT_RENAME(le_layoutChars)
+#define le_reset U_ICU_ENTRY_POINT_RENAME(le_reset)
+#define locale_getKeywords U_ICU_ENTRY_POINT_RENAME(locale_getKeywords)
+#define locale_getKeywordsStart U_ICU_ENTRY_POINT_RENAME(locale_getKeywordsStart)
+#define locale_get_default U_ICU_ENTRY_POINT_RENAME(locale_get_default)
+#define locale_set_default U_ICU_ENTRY_POINT_RENAME(locale_set_default)
+#define pl_addFontRun U_ICU_ENTRY_POINT_RENAME(pl_addFontRun)
+#define pl_addLocaleRun U_ICU_ENTRY_POINT_RENAME(pl_addLocaleRun)
+#define pl_addValueRun U_ICU_ENTRY_POINT_RENAME(pl_addValueRun)
+#define pl_close U_ICU_ENTRY_POINT_RENAME(pl_close)
+#define pl_closeFontRuns U_ICU_ENTRY_POINT_RENAME(pl_closeFontRuns)
+#define pl_closeLine U_ICU_ENTRY_POINT_RENAME(pl_closeLine)
+#define pl_closeLocaleRuns U_ICU_ENTRY_POINT_RENAME(pl_closeLocaleRuns)
+#define pl_closeValueRuns U_ICU_ENTRY_POINT_RENAME(pl_closeValueRuns)
+#define pl_countLineRuns U_ICU_ENTRY_POINT_RENAME(pl_countLineRuns)
+#define pl_create U_ICU_ENTRY_POINT_RENAME(pl_create)
+#define pl_getAscent U_ICU_ENTRY_POINT_RENAME(pl_getAscent)
+#define pl_getDescent U_ICU_ENTRY_POINT_RENAME(pl_getDescent)
+#define pl_getFontRunCount U_ICU_ENTRY_POINT_RENAME(pl_getFontRunCount)
+#define pl_getFontRunFont U_ICU_ENTRY_POINT_RENAME(pl_getFontRunFont)
+#define pl_getFontRunLastLimit U_ICU_ENTRY_POINT_RENAME(pl_getFontRunLastLimit)
+#define pl_getFontRunLimit U_ICU_ENTRY_POINT_RENAME(pl_getFontRunLimit)
+#define pl_getLeading U_ICU_ENTRY_POINT_RENAME(pl_getLeading)
+#define pl_getLineAscent U_ICU_ENTRY_POINT_RENAME(pl_getLineAscent)
+#define pl_getLineDescent U_ICU_ENTRY_POINT_RENAME(pl_getLineDescent)
+#define pl_getLineLeading U_ICU_ENTRY_POINT_RENAME(pl_getLineLeading)
+#define pl_getLineVisualRun U_ICU_ENTRY_POINT_RENAME(pl_getLineVisualRun)
+#define pl_getLineWidth U_ICU_ENTRY_POINT_RENAME(pl_getLineWidth)
+#define pl_getLocaleRunCount U_ICU_ENTRY_POINT_RENAME(pl_getLocaleRunCount)
+#define pl_getLocaleRunLastLimit U_ICU_ENTRY_POINT_RENAME(pl_getLocaleRunLastLimit)
+#define pl_getLocaleRunLimit U_ICU_ENTRY_POINT_RENAME(pl_getLocaleRunLimit)
+#define pl_getLocaleRunLocale U_ICU_ENTRY_POINT_RENAME(pl_getLocaleRunLocale)
+#define pl_getParagraphLevel U_ICU_ENTRY_POINT_RENAME(pl_getParagraphLevel)
+#define pl_getTextDirection U_ICU_ENTRY_POINT_RENAME(pl_getTextDirection)
+#define pl_getValueRunCount U_ICU_ENTRY_POINT_RENAME(pl_getValueRunCount)
+#define pl_getValueRunLastLimit U_ICU_ENTRY_POINT_RENAME(pl_getValueRunLastLimit)
+#define pl_getValueRunLimit U_ICU_ENTRY_POINT_RENAME(pl_getValueRunLimit)
+#define pl_getValueRunValue U_ICU_ENTRY_POINT_RENAME(pl_getValueRunValue)
+#define pl_getVisualRunAscent U_ICU_ENTRY_POINT_RENAME(pl_getVisualRunAscent)
+#define pl_getVisualRunDescent U_ICU_ENTRY_POINT_RENAME(pl_getVisualRunDescent)
+#define pl_getVisualRunDirection U_ICU_ENTRY_POINT_RENAME(pl_getVisualRunDirection)
+#define pl_getVisualRunFont U_ICU_ENTRY_POINT_RENAME(pl_getVisualRunFont)
+#define pl_getVisualRunGlyphCount U_ICU_ENTRY_POINT_RENAME(pl_getVisualRunGlyphCount)
+#define pl_getVisualRunGlyphToCharMap U_ICU_ENTRY_POINT_RENAME(pl_getVisualRunGlyphToCharMap)
+#define pl_getVisualRunGlyphs U_ICU_ENTRY_POINT_RENAME(pl_getVisualRunGlyphs)
+#define pl_getVisualRunLeading U_ICU_ENTRY_POINT_RENAME(pl_getVisualRunLeading)
+#define pl_getVisualRunPositions U_ICU_ENTRY_POINT_RENAME(pl_getVisualRunPositions)
+#define pl_isComplex U_ICU_ENTRY_POINT_RENAME(pl_isComplex)
+#define pl_nextLine U_ICU_ENTRY_POINT_RENAME(pl_nextLine)
+#define pl_openEmptyFontRuns U_ICU_ENTRY_POINT_RENAME(pl_openEmptyFontRuns)
+#define pl_openEmptyLocaleRuns U_ICU_ENTRY_POINT_RENAME(pl_openEmptyLocaleRuns)
+#define pl_openEmptyValueRuns U_ICU_ENTRY_POINT_RENAME(pl_openEmptyValueRuns)
+#define pl_openFontRuns U_ICU_ENTRY_POINT_RENAME(pl_openFontRuns)
+#define pl_openLocaleRuns U_ICU_ENTRY_POINT_RENAME(pl_openLocaleRuns)
+#define pl_openValueRuns U_ICU_ENTRY_POINT_RENAME(pl_openValueRuns)
+#define pl_reflow U_ICU_ENTRY_POINT_RENAME(pl_reflow)
+#define pl_resetFontRuns U_ICU_ENTRY_POINT_RENAME(pl_resetFontRuns)
+#define pl_resetLocaleRuns U_ICU_ENTRY_POINT_RENAME(pl_resetLocaleRuns)
+#define pl_resetValueRuns U_ICU_ENTRY_POINT_RENAME(pl_resetValueRuns)
+#define res_countArrayItems U_ICU_ENTRY_POINT_RENAME(res_countArrayItems)
+#define res_findResource U_ICU_ENTRY_POINT_RENAME(res_findResource)
+#define res_getAlias U_ICU_ENTRY_POINT_RENAME(res_getAlias)
+#define res_getArrayItem U_ICU_ENTRY_POINT_RENAME(res_getArrayItem)
+#define res_getBinary U_ICU_ENTRY_POINT_RENAME(res_getBinary)
+#define res_getIntVector U_ICU_ENTRY_POINT_RENAME(res_getIntVector)
+#define res_getPublicType U_ICU_ENTRY_POINT_RENAME(res_getPublicType)
+#define res_getResource U_ICU_ENTRY_POINT_RENAME(res_getResource)
+#define res_getString U_ICU_ENTRY_POINT_RENAME(res_getString)
+#define res_getTableItemByIndex U_ICU_ENTRY_POINT_RENAME(res_getTableItemByIndex)
+#define res_getTableItemByKey U_ICU_ENTRY_POINT_RENAME(res_getTableItemByKey)
+#define res_load U_ICU_ENTRY_POINT_RENAME(res_load)
+#define res_read U_ICU_ENTRY_POINT_RENAME(res_read)
+#define res_unload U_ICU_ENTRY_POINT_RENAME(res_unload)
+#define tmutfmtHashTableValueComparator U_ICU_ENTRY_POINT_RENAME(tmutfmtHashTableValueComparator)
+#define triedict_swap U_ICU_ENTRY_POINT_RENAME(triedict_swap)
+#define u_UCharsToChars U_ICU_ENTRY_POINT_RENAME(u_UCharsToChars)
+#define u_austrcpy U_ICU_ENTRY_POINT_RENAME(u_austrcpy)
+#define u_austrncpy U_ICU_ENTRY_POINT_RENAME(u_austrncpy)
+#define u_catclose U_ICU_ENTRY_POINT_RENAME(u_catclose)
+#define u_catgets U_ICU_ENTRY_POINT_RENAME(u_catgets)
+#define u_catopen U_ICU_ENTRY_POINT_RENAME(u_catopen)
+#define u_charAge U_ICU_ENTRY_POINT_RENAME(u_charAge)
+#define u_charDigitValue U_ICU_ENTRY_POINT_RENAME(u_charDigitValue)
+#define u_charDirection U_ICU_ENTRY_POINT_RENAME(u_charDirection)
+#define u_charFromName U_ICU_ENTRY_POINT_RENAME(u_charFromName)
+#define u_charMirror U_ICU_ENTRY_POINT_RENAME(u_charMirror)
+#define u_charName U_ICU_ENTRY_POINT_RENAME(u_charName)
+#define u_charType U_ICU_ENTRY_POINT_RENAME(u_charType)
+#define u_charsToUChars U_ICU_ENTRY_POINT_RENAME(u_charsToUChars)
+#define u_cleanup U_ICU_ENTRY_POINT_RENAME(u_cleanup)
+#define u_countChar32 U_ICU_ENTRY_POINT_RENAME(u_countChar32)
+#define u_digit U_ICU_ENTRY_POINT_RENAME(u_digit)
+#define u_enumCharNames U_ICU_ENTRY_POINT_RENAME(u_enumCharNames)
+#define u_enumCharTypes U_ICU_ENTRY_POINT_RENAME(u_enumCharTypes)
+#define u_errorName U_ICU_ENTRY_POINT_RENAME(u_errorName)
+#define u_fadopt U_ICU_ENTRY_POINT_RENAME(u_fadopt)
+#define u_fclose U_ICU_ENTRY_POINT_RENAME(u_fclose)
+#define u_feof U_ICU_ENTRY_POINT_RENAME(u_feof)
+#define u_fflush U_ICU_ENTRY_POINT_RENAME(u_fflush)
+#define u_fgetConverter U_ICU_ENTRY_POINT_RENAME(u_fgetConverter)
+#define u_fgetc U_ICU_ENTRY_POINT_RENAME(u_fgetc)
+#define u_fgetcodepage U_ICU_ENTRY_POINT_RENAME(u_fgetcodepage)
+#define u_fgetcx U_ICU_ENTRY_POINT_RENAME(u_fgetcx)
+#define u_fgetfile U_ICU_ENTRY_POINT_RENAME(u_fgetfile)
+#define u_fgetlocale U_ICU_ENTRY_POINT_RENAME(u_fgetlocale)
+#define u_fgets U_ICU_ENTRY_POINT_RENAME(u_fgets)
+#define u_file_read U_ICU_ENTRY_POINT_RENAME(u_file_read)
+#define u_file_write U_ICU_ENTRY_POINT_RENAME(u_file_write)
+#define u_file_write_flush U_ICU_ENTRY_POINT_RENAME(u_file_write_flush)
+#define u_finit U_ICU_ENTRY_POINT_RENAME(u_finit)
+#define u_flushDefaultConverter U_ICU_ENTRY_POINT_RENAME(u_flushDefaultConverter)
+#define u_foldCase U_ICU_ENTRY_POINT_RENAME(u_foldCase)
+#define u_fopen U_ICU_ENTRY_POINT_RENAME(u_fopen)
+#define u_forDigit U_ICU_ENTRY_POINT_RENAME(u_forDigit)
+#define u_formatMessage U_ICU_ENTRY_POINT_RENAME(u_formatMessage)
+#define u_formatMessageWithError U_ICU_ENTRY_POINT_RENAME(u_formatMessageWithError)
+#define u_fprintf U_ICU_ENTRY_POINT_RENAME(u_fprintf)
+#define u_fprintf_u U_ICU_ENTRY_POINT_RENAME(u_fprintf_u)
+#define u_fputc U_ICU_ENTRY_POINT_RENAME(u_fputc)
+#define u_fputs U_ICU_ENTRY_POINT_RENAME(u_fputs)
+#define u_frewind U_ICU_ENTRY_POINT_RENAME(u_frewind)
+#define u_fscanf U_ICU_ENTRY_POINT_RENAME(u_fscanf)
+#define u_fscanf_u U_ICU_ENTRY_POINT_RENAME(u_fscanf_u)
+#define u_fsetcodepage U_ICU_ENTRY_POINT_RENAME(u_fsetcodepage)
+#define u_fsetlocale U_ICU_ENTRY_POINT_RENAME(u_fsetlocale)
+#define u_fsettransliterator U_ICU_ENTRY_POINT_RENAME(u_fsettransliterator)
+#define u_fstropen U_ICU_ENTRY_POINT_RENAME(u_fstropen)
+#define u_fungetc U_ICU_ENTRY_POINT_RENAME(u_fungetc)
+#define u_getCombiningClass U_ICU_ENTRY_POINT_RENAME(u_getCombiningClass)
+#define u_getDataDirectory U_ICU_ENTRY_POINT_RENAME(u_getDataDirectory)
+#define u_getDataVersion U_ICU_ENTRY_POINT_RENAME(u_getDataVersion)
+#define u_getDefaultConverter U_ICU_ENTRY_POINT_RENAME(u_getDefaultConverter)
+#define u_getFC_NFKC_Closure U_ICU_ENTRY_POINT_RENAME(u_getFC_NFKC_Closure)
+#define u_getISOComment U_ICU_ENTRY_POINT_RENAME(u_getISOComment)
+#define u_getIntPropertyMaxValue U_ICU_ENTRY_POINT_RENAME(u_getIntPropertyMaxValue)
+#define u_getIntPropertyMinValue U_ICU_ENTRY_POINT_RENAME(u_getIntPropertyMinValue)
+#define u_getIntPropertyValue U_ICU_ENTRY_POINT_RENAME(u_getIntPropertyValue)
+#define u_getNumericValue U_ICU_ENTRY_POINT_RENAME(u_getNumericValue)
+#define u_getPropertyEnum U_ICU_ENTRY_POINT_RENAME(u_getPropertyEnum)
+#define u_getPropertyName U_ICU_ENTRY_POINT_RENAME(u_getPropertyName)
+#define u_getPropertyValueEnum U_ICU_ENTRY_POINT_RENAME(u_getPropertyValueEnum)
+#define u_getPropertyValueName U_ICU_ENTRY_POINT_RENAME(u_getPropertyValueName)
+#define u_getUnicodeProperties U_ICU_ENTRY_POINT_RENAME(u_getUnicodeProperties)
+#define u_getUnicodeVersion U_ICU_ENTRY_POINT_RENAME(u_getUnicodeVersion)
+#define u_getVersion U_ICU_ENTRY_POINT_RENAME(u_getVersion)
+#define u_hasBinaryProperty U_ICU_ENTRY_POINT_RENAME(u_hasBinaryProperty)
+#define u_init U_ICU_ENTRY_POINT_RENAME(u_init)
+#define u_isDataOlder U_ICU_ENTRY_POINT_RENAME(u_isDataOlder)
+#define u_isIDIgnorable U_ICU_ENTRY_POINT_RENAME(u_isIDIgnorable)
+#define u_isIDPart U_ICU_ENTRY_POINT_RENAME(u_isIDPart)
+#define u_isIDStart U_ICU_ENTRY_POINT_RENAME(u_isIDStart)
+#define u_isISOControl U_ICU_ENTRY_POINT_RENAME(u_isISOControl)
+#define u_isJavaIDPart U_ICU_ENTRY_POINT_RENAME(u_isJavaIDPart)
+#define u_isJavaIDStart U_ICU_ENTRY_POINT_RENAME(u_isJavaIDStart)
+#define u_isJavaSpaceChar U_ICU_ENTRY_POINT_RENAME(u_isJavaSpaceChar)
+#define u_isMirrored U_ICU_ENTRY_POINT_RENAME(u_isMirrored)
+#define u_isUAlphabetic U_ICU_ENTRY_POINT_RENAME(u_isUAlphabetic)
+#define u_isULowercase U_ICU_ENTRY_POINT_RENAME(u_isULowercase)
+#define u_isUUppercase U_ICU_ENTRY_POINT_RENAME(u_isUUppercase)
+#define u_isUWhiteSpace U_ICU_ENTRY_POINT_RENAME(u_isUWhiteSpace)
+#define u_isWhitespace U_ICU_ENTRY_POINT_RENAME(u_isWhitespace)
+#define u_isalnum U_ICU_ENTRY_POINT_RENAME(u_isalnum)
+#define u_isalnumPOSIX U_ICU_ENTRY_POINT_RENAME(u_isalnumPOSIX)
+#define u_isalpha U_ICU_ENTRY_POINT_RENAME(u_isalpha)
+#define u_isbase U_ICU_ENTRY_POINT_RENAME(u_isbase)
+#define u_isblank U_ICU_ENTRY_POINT_RENAME(u_isblank)
+#define u_iscntrl U_ICU_ENTRY_POINT_RENAME(u_iscntrl)
+#define u_isdefined U_ICU_ENTRY_POINT_RENAME(u_isdefined)
+#define u_isdigit U_ICU_ENTRY_POINT_RENAME(u_isdigit)
+#define u_isgraph U_ICU_ENTRY_POINT_RENAME(u_isgraph)
+#define u_isgraphPOSIX U_ICU_ENTRY_POINT_RENAME(u_isgraphPOSIX)
+#define u_islower U_ICU_ENTRY_POINT_RENAME(u_islower)
+#define u_isprint U_ICU_ENTRY_POINT_RENAME(u_isprint)
+#define u_isprintPOSIX U_ICU_ENTRY_POINT_RENAME(u_isprintPOSIX)
+#define u_ispunct U_ICU_ENTRY_POINT_RENAME(u_ispunct)
+#define u_isspace U_ICU_ENTRY_POINT_RENAME(u_isspace)
+#define u_istitle U_ICU_ENTRY_POINT_RENAME(u_istitle)
+#define u_isupper U_ICU_ENTRY_POINT_RENAME(u_isupper)
+#define u_isxdigit U_ICU_ENTRY_POINT_RENAME(u_isxdigit)
+#define u_lengthOfIdenticalLevelRun U_ICU_ENTRY_POINT_RENAME(u_lengthOfIdenticalLevelRun)
+#define u_locbund_close U_ICU_ENTRY_POINT_RENAME(u_locbund_close)
+#define u_locbund_getNumberFormat U_ICU_ENTRY_POINT_RENAME(u_locbund_getNumberFormat)
+#define u_locbund_init U_ICU_ENTRY_POINT_RENAME(u_locbund_init)
+#define u_memcasecmp U_ICU_ENTRY_POINT_RENAME(u_memcasecmp)
+#define u_memchr U_ICU_ENTRY_POINT_RENAME(u_memchr)
+#define u_memchr32 U_ICU_ENTRY_POINT_RENAME(u_memchr32)
+#define u_memcmp U_ICU_ENTRY_POINT_RENAME(u_memcmp)
+#define u_memcmpCodePointOrder U_ICU_ENTRY_POINT_RENAME(u_memcmpCodePointOrder)
+#define u_memcpy U_ICU_ENTRY_POINT_RENAME(u_memcpy)
+#define u_memmove U_ICU_ENTRY_POINT_RENAME(u_memmove)
+#define u_memrchr U_ICU_ENTRY_POINT_RENAME(u_memrchr)
+#define u_memrchr32 U_ICU_ENTRY_POINT_RENAME(u_memrchr32)
+#define u_memset U_ICU_ENTRY_POINT_RENAME(u_memset)
+#define u_parseMessage U_ICU_ENTRY_POINT_RENAME(u_parseMessage)
+#define u_parseMessageWithError U_ICU_ENTRY_POINT_RENAME(u_parseMessageWithError)
+#define u_printf_parse U_ICU_ENTRY_POINT_RENAME(u_printf_parse)
+#define u_releaseDefaultConverter U_ICU_ENTRY_POINT_RENAME(u_releaseDefaultConverter)
+#define u_scanf_parse U_ICU_ENTRY_POINT_RENAME(u_scanf_parse)
+#define u_setAtomicIncDecFunctions U_ICU_ENTRY_POINT_RENAME(u_setAtomicIncDecFunctions)
+#define u_setDataDirectory U_ICU_ENTRY_POINT_RENAME(u_setDataDirectory)
+#define u_setMemoryFunctions U_ICU_ENTRY_POINT_RENAME(u_setMemoryFunctions)
+#define u_setMutexFunctions U_ICU_ENTRY_POINT_RENAME(u_setMutexFunctions)
+#define u_shapeArabic U_ICU_ENTRY_POINT_RENAME(u_shapeArabic)
+#define u_snprintf U_ICU_ENTRY_POINT_RENAME(u_snprintf)
+#define u_snprintf_u U_ICU_ENTRY_POINT_RENAME(u_snprintf_u)
+#define u_sprintf U_ICU_ENTRY_POINT_RENAME(u_sprintf)
+#define u_sprintf_u U_ICU_ENTRY_POINT_RENAME(u_sprintf_u)
+#define u_sscanf U_ICU_ENTRY_POINT_RENAME(u_sscanf)
+#define u_sscanf_u U_ICU_ENTRY_POINT_RENAME(u_sscanf_u)
+#define u_strCaseCompare U_ICU_ENTRY_POINT_RENAME(u_strCaseCompare)
+#define u_strCompare U_ICU_ENTRY_POINT_RENAME(u_strCompare)
+#define u_strCompareIter U_ICU_ENTRY_POINT_RENAME(u_strCompareIter)
+#define u_strFindFirst U_ICU_ENTRY_POINT_RENAME(u_strFindFirst)
+#define u_strFindLast U_ICU_ENTRY_POINT_RENAME(u_strFindLast)
+#define u_strFoldCase U_ICU_ENTRY_POINT_RENAME(u_strFoldCase)
+#define u_strFromJavaModifiedUTF8WithSub U_ICU_ENTRY_POINT_RENAME(u_strFromJavaModifiedUTF8WithSub)
+#define u_strFromPunycode U_ICU_ENTRY_POINT_RENAME(u_strFromPunycode)
+#define u_strFromUTF32 U_ICU_ENTRY_POINT_RENAME(u_strFromUTF32)
+#define u_strFromUTF32WithSub U_ICU_ENTRY_POINT_RENAME(u_strFromUTF32WithSub)
+#define u_strFromUTF8 U_ICU_ENTRY_POINT_RENAME(u_strFromUTF8)
+#define u_strFromUTF8Lenient U_ICU_ENTRY_POINT_RENAME(u_strFromUTF8Lenient)
+#define u_strFromUTF8WithSub U_ICU_ENTRY_POINT_RENAME(u_strFromUTF8WithSub)
+#define u_strFromWCS U_ICU_ENTRY_POINT_RENAME(u_strFromWCS)
+#define u_strHasMoreChar32Than U_ICU_ENTRY_POINT_RENAME(u_strHasMoreChar32Than)
+#define u_strToJavaModifiedUTF8 U_ICU_ENTRY_POINT_RENAME(u_strToJavaModifiedUTF8)
+#define u_strToLower U_ICU_ENTRY_POINT_RENAME(u_strToLower)
+#define u_strToPunycode U_ICU_ENTRY_POINT_RENAME(u_strToPunycode)
+#define u_strToTitle U_ICU_ENTRY_POINT_RENAME(u_strToTitle)
+#define u_strToUTF32 U_ICU_ENTRY_POINT_RENAME(u_strToUTF32)
+#define u_strToUTF32WithSub U_ICU_ENTRY_POINT_RENAME(u_strToUTF32WithSub)
+#define u_strToUTF8 U_ICU_ENTRY_POINT_RENAME(u_strToUTF8)
+#define u_strToUTF8WithSub U_ICU_ENTRY_POINT_RENAME(u_strToUTF8WithSub)
+#define u_strToUpper U_ICU_ENTRY_POINT_RENAME(u_strToUpper)
+#define u_strToWCS U_ICU_ENTRY_POINT_RENAME(u_strToWCS)
+#define u_strcasecmp U_ICU_ENTRY_POINT_RENAME(u_strcasecmp)
+#define u_strcat U_ICU_ENTRY_POINT_RENAME(u_strcat)
+#define u_strchr U_ICU_ENTRY_POINT_RENAME(u_strchr)
+#define u_strchr32 U_ICU_ENTRY_POINT_RENAME(u_strchr32)
+#define u_strcmp U_ICU_ENTRY_POINT_RENAME(u_strcmp)
+#define u_strcmpCodePointOrder U_ICU_ENTRY_POINT_RENAME(u_strcmpCodePointOrder)
+#define u_strcmpFold U_ICU_ENTRY_POINT_RENAME(u_strcmpFold)
+#define u_strcpy U_ICU_ENTRY_POINT_RENAME(u_strcpy)
+#define u_strcspn U_ICU_ENTRY_POINT_RENAME(u_strcspn)
+#define u_strlen U_ICU_ENTRY_POINT_RENAME(u_strlen)
+#define u_strncasecmp U_ICU_ENTRY_POINT_RENAME(u_strncasecmp)
+#define u_strncat U_ICU_ENTRY_POINT_RENAME(u_strncat)
+#define u_strncmp U_ICU_ENTRY_POINT_RENAME(u_strncmp)
+#define u_strncmpCodePointOrder U_ICU_ENTRY_POINT_RENAME(u_strncmpCodePointOrder)
+#define u_strncpy U_ICU_ENTRY_POINT_RENAME(u_strncpy)
+#define u_strpbrk U_ICU_ENTRY_POINT_RENAME(u_strpbrk)
+#define u_strrchr U_ICU_ENTRY_POINT_RENAME(u_strrchr)
+#define u_strrchr32 U_ICU_ENTRY_POINT_RENAME(u_strrchr32)
+#define u_strrstr U_ICU_ENTRY_POINT_RENAME(u_strrstr)
+#define u_strspn U_ICU_ENTRY_POINT_RENAME(u_strspn)
+#define u_strstr U_ICU_ENTRY_POINT_RENAME(u_strstr)
+#define u_strtok_r U_ICU_ENTRY_POINT_RENAME(u_strtok_r)
+#define u_terminateChars U_ICU_ENTRY_POINT_RENAME(u_terminateChars)
+#define u_terminateUChar32s U_ICU_ENTRY_POINT_RENAME(u_terminateUChar32s)
+#define u_terminateUChars U_ICU_ENTRY_POINT_RENAME(u_terminateUChars)
+#define u_terminateWChars U_ICU_ENTRY_POINT_RENAME(u_terminateWChars)
+#define u_tolower U_ICU_ENTRY_POINT_RENAME(u_tolower)
+#define u_totitle U_ICU_ENTRY_POINT_RENAME(u_totitle)
+#define u_toupper U_ICU_ENTRY_POINT_RENAME(u_toupper)
+#define u_uastrcpy U_ICU_ENTRY_POINT_RENAME(u_uastrcpy)
+#define u_uastrncpy U_ICU_ENTRY_POINT_RENAME(u_uastrncpy)
+#define u_unescape U_ICU_ENTRY_POINT_RENAME(u_unescape)
+#define u_unescapeAt U_ICU_ENTRY_POINT_RENAME(u_unescapeAt)
+#define u_versionFromString U_ICU_ENTRY_POINT_RENAME(u_versionFromString)
+#define u_versionFromUString U_ICU_ENTRY_POINT_RENAME(u_versionFromUString)
+#define u_versionToString U_ICU_ENTRY_POINT_RENAME(u_versionToString)
+#define u_vformatMessage U_ICU_ENTRY_POINT_RENAME(u_vformatMessage)
+#define u_vformatMessageWithError U_ICU_ENTRY_POINT_RENAME(u_vformatMessageWithError)
+#define u_vfprintf U_ICU_ENTRY_POINT_RENAME(u_vfprintf)
+#define u_vfprintf_u U_ICU_ENTRY_POINT_RENAME(u_vfprintf_u)
+#define u_vfscanf U_ICU_ENTRY_POINT_RENAME(u_vfscanf)
+#define u_vfscanf_u U_ICU_ENTRY_POINT_RENAME(u_vfscanf_u)
+#define u_vparseMessage U_ICU_ENTRY_POINT_RENAME(u_vparseMessage)
+#define u_vparseMessageWithError U_ICU_ENTRY_POINT_RENAME(u_vparseMessageWithError)
+#define u_vsnprintf U_ICU_ENTRY_POINT_RENAME(u_vsnprintf)
+#define u_vsnprintf_u U_ICU_ENTRY_POINT_RENAME(u_vsnprintf_u)
+#define u_vsprintf U_ICU_ENTRY_POINT_RENAME(u_vsprintf)
+#define u_vsprintf_u U_ICU_ENTRY_POINT_RENAME(u_vsprintf_u)
+#define u_vsscanf U_ICU_ENTRY_POINT_RENAME(u_vsscanf)
+#define u_vsscanf_u U_ICU_ENTRY_POINT_RENAME(u_vsscanf_u)
+#define u_writeDiff U_ICU_ENTRY_POINT_RENAME(u_writeDiff)
+#define u_writeIdenticalLevelRun U_ICU_ENTRY_POINT_RENAME(u_writeIdenticalLevelRun)
+#define u_writeIdenticalLevelRunTwoChars U_ICU_ENTRY_POINT_RENAME(u_writeIdenticalLevelRunTwoChars)
+#define ubidi_addPropertyStarts U_ICU_ENTRY_POINT_RENAME(ubidi_addPropertyStarts)
+#define ubidi_close U_ICU_ENTRY_POINT_RENAME(ubidi_close)
+#define ubidi_countParagraphs U_ICU_ENTRY_POINT_RENAME(ubidi_countParagraphs)
+#define ubidi_countRuns U_ICU_ENTRY_POINT_RENAME(ubidi_countRuns)
+#define ubidi_getBaseDirection U_ICU_ENTRY_POINT_RENAME(ubidi_getBaseDirection)
+#define ubidi_getClass U_ICU_ENTRY_POINT_RENAME(ubidi_getClass)
+#define ubidi_getClassCallback U_ICU_ENTRY_POINT_RENAME(ubidi_getClassCallback)
+#define ubidi_getCustomizedClass U_ICU_ENTRY_POINT_RENAME(ubidi_getCustomizedClass)
+#define ubidi_getDirection U_ICU_ENTRY_POINT_RENAME(ubidi_getDirection)
+#define ubidi_getJoiningGroup U_ICU_ENTRY_POINT_RENAME(ubidi_getJoiningGroup)
+#define ubidi_getJoiningType U_ICU_ENTRY_POINT_RENAME(ubidi_getJoiningType)
+#define ubidi_getLength U_ICU_ENTRY_POINT_RENAME(ubidi_getLength)
+#define ubidi_getLevelAt U_ICU_ENTRY_POINT_RENAME(ubidi_getLevelAt)
+#define ubidi_getLevels U_ICU_ENTRY_POINT_RENAME(ubidi_getLevels)
+#define ubidi_getLogicalIndex U_ICU_ENTRY_POINT_RENAME(ubidi_getLogicalIndex)
+#define ubidi_getLogicalMap U_ICU_ENTRY_POINT_RENAME(ubidi_getLogicalMap)
+#define ubidi_getLogicalRun U_ICU_ENTRY_POINT_RENAME(ubidi_getLogicalRun)
+#define ubidi_getMaxValue U_ICU_ENTRY_POINT_RENAME(ubidi_getMaxValue)
+#define ubidi_getMemory U_ICU_ENTRY_POINT_RENAME(ubidi_getMemory)
+#define ubidi_getMirror U_ICU_ENTRY_POINT_RENAME(ubidi_getMirror)
+#define ubidi_getParaLevel U_ICU_ENTRY_POINT_RENAME(ubidi_getParaLevel)
+#define ubidi_getParagraph U_ICU_ENTRY_POINT_RENAME(ubidi_getParagraph)
+#define ubidi_getParagraphByIndex U_ICU_ENTRY_POINT_RENAME(ubidi_getParagraphByIndex)
+#define ubidi_getProcessedLength U_ICU_ENTRY_POINT_RENAME(ubidi_getProcessedLength)
+#define ubidi_getReorderingMode U_ICU_ENTRY_POINT_RENAME(ubidi_getReorderingMode)
+#define ubidi_getReorderingOptions U_ICU_ENTRY_POINT_RENAME(ubidi_getReorderingOptions)
+#define ubidi_getResultLength U_ICU_ENTRY_POINT_RENAME(ubidi_getResultLength)
+#define ubidi_getRuns U_ICU_ENTRY_POINT_RENAME(ubidi_getRuns)
+#define ubidi_getSingleton U_ICU_ENTRY_POINT_RENAME(ubidi_getSingleton)
+#define ubidi_getText U_ICU_ENTRY_POINT_RENAME(ubidi_getText)
+#define ubidi_getVisualIndex U_ICU_ENTRY_POINT_RENAME(ubidi_getVisualIndex)
+#define ubidi_getVisualMap U_ICU_ENTRY_POINT_RENAME(ubidi_getVisualMap)
+#define ubidi_getVisualRun U_ICU_ENTRY_POINT_RENAME(ubidi_getVisualRun)
+#define ubidi_invertMap U_ICU_ENTRY_POINT_RENAME(ubidi_invertMap)
+#define ubidi_isBidiControl U_ICU_ENTRY_POINT_RENAME(ubidi_isBidiControl)
+#define ubidi_isInverse U_ICU_ENTRY_POINT_RENAME(ubidi_isInverse)
+#define ubidi_isJoinControl U_ICU_ENTRY_POINT_RENAME(ubidi_isJoinControl)
+#define ubidi_isMirrored U_ICU_ENTRY_POINT_RENAME(ubidi_isMirrored)
+#define ubidi_isOrderParagraphsLTR U_ICU_ENTRY_POINT_RENAME(ubidi_isOrderParagraphsLTR)
+#define ubidi_open U_ICU_ENTRY_POINT_RENAME(ubidi_open)
+#define ubidi_openSized U_ICU_ENTRY_POINT_RENAME(ubidi_openSized)
+#define ubidi_orderParagraphsLTR U_ICU_ENTRY_POINT_RENAME(ubidi_orderParagraphsLTR)
+#define ubidi_reorderLogical U_ICU_ENTRY_POINT_RENAME(ubidi_reorderLogical)
+#define ubidi_reorderVisual U_ICU_ENTRY_POINT_RENAME(ubidi_reorderVisual)
+#define ubidi_setClassCallback U_ICU_ENTRY_POINT_RENAME(ubidi_setClassCallback)
+#define ubidi_setInverse U_ICU_ENTRY_POINT_RENAME(ubidi_setInverse)
+#define ubidi_setLine U_ICU_ENTRY_POINT_RENAME(ubidi_setLine)
+#define ubidi_setPara U_ICU_ENTRY_POINT_RENAME(ubidi_setPara)
+#define ubidi_setReorderingMode U_ICU_ENTRY_POINT_RENAME(ubidi_setReorderingMode)
+#define ubidi_setReorderingOptions U_ICU_ENTRY_POINT_RENAME(ubidi_setReorderingOptions)
+#define ubidi_writeReordered U_ICU_ENTRY_POINT_RENAME(ubidi_writeReordered)
+#define ubidi_writeReverse U_ICU_ENTRY_POINT_RENAME(ubidi_writeReverse)
+#define ublock_getCode U_ICU_ENTRY_POINT_RENAME(ublock_getCode)
+#define ubrk_close U_ICU_ENTRY_POINT_RENAME(ubrk_close)
+#define ubrk_countAvailable U_ICU_ENTRY_POINT_RENAME(ubrk_countAvailable)
+#define ubrk_current U_ICU_ENTRY_POINT_RENAME(ubrk_current)
+#define ubrk_first U_ICU_ENTRY_POINT_RENAME(ubrk_first)
+#define ubrk_following U_ICU_ENTRY_POINT_RENAME(ubrk_following)
+#define ubrk_getAvailable U_ICU_ENTRY_POINT_RENAME(ubrk_getAvailable)
+#define ubrk_getLocaleByType U_ICU_ENTRY_POINT_RENAME(ubrk_getLocaleByType)
+#define ubrk_getRuleStatus U_ICU_ENTRY_POINT_RENAME(ubrk_getRuleStatus)
+#define ubrk_getRuleStatusVec U_ICU_ENTRY_POINT_RENAME(ubrk_getRuleStatusVec)
+#define ubrk_isBoundary U_ICU_ENTRY_POINT_RENAME(ubrk_isBoundary)
+#define ubrk_last U_ICU_ENTRY_POINT_RENAME(ubrk_last)
+#define ubrk_next U_ICU_ENTRY_POINT_RENAME(ubrk_next)
+#define ubrk_open U_ICU_ENTRY_POINT_RENAME(ubrk_open)
+#define ubrk_openRules U_ICU_ENTRY_POINT_RENAME(ubrk_openRules)
+#define ubrk_preceding U_ICU_ENTRY_POINT_RENAME(ubrk_preceding)
+#define ubrk_previous U_ICU_ENTRY_POINT_RENAME(ubrk_previous)
+#define ubrk_safeClone U_ICU_ENTRY_POINT_RENAME(ubrk_safeClone)
+#define ubrk_setText U_ICU_ENTRY_POINT_RENAME(ubrk_setText)
+#define ubrk_setUText U_ICU_ENTRY_POINT_RENAME(ubrk_setUText)
+#define ubrk_swap U_ICU_ENTRY_POINT_RENAME(ubrk_swap)
+#define ucal_add U_ICU_ENTRY_POINT_RENAME(ucal_add)
+#define ucal_clear U_ICU_ENTRY_POINT_RENAME(ucal_clear)
+#define ucal_clearField U_ICU_ENTRY_POINT_RENAME(ucal_clearField)
+#define ucal_clone U_ICU_ENTRY_POINT_RENAME(ucal_clone)
+#define ucal_close U_ICU_ENTRY_POINT_RENAME(ucal_close)
+#define ucal_countAvailable U_ICU_ENTRY_POINT_RENAME(ucal_countAvailable)
+#define ucal_equivalentTo U_ICU_ENTRY_POINT_RENAME(ucal_equivalentTo)
+#define ucal_get U_ICU_ENTRY_POINT_RENAME(ucal_get)
+#define ucal_getAttribute U_ICU_ENTRY_POINT_RENAME(ucal_getAttribute)
+#define ucal_getAvailable U_ICU_ENTRY_POINT_RENAME(ucal_getAvailable)
+#define ucal_getCanonicalTimeZoneID U_ICU_ENTRY_POINT_RENAME(ucal_getCanonicalTimeZoneID)
+#define ucal_getDSTSavings U_ICU_ENTRY_POINT_RENAME(ucal_getDSTSavings)
+#define ucal_getDayOfWeekType U_ICU_ENTRY_POINT_RENAME(ucal_getDayOfWeekType)
+#define ucal_getDefaultTimeZone U_ICU_ENTRY_POINT_RENAME(ucal_getDefaultTimeZone)
+#define ucal_getGregorianChange U_ICU_ENTRY_POINT_RENAME(ucal_getGregorianChange)
+#define ucal_getKeywordValuesForLocale U_ICU_ENTRY_POINT_RENAME(ucal_getKeywordValuesForLocale)
+#define ucal_getLimit U_ICU_ENTRY_POINT_RENAME(ucal_getLimit)
+#define ucal_getLocaleByType U_ICU_ENTRY_POINT_RENAME(ucal_getLocaleByType)
+#define ucal_getMillis U_ICU_ENTRY_POINT_RENAME(ucal_getMillis)
+#define ucal_getNow U_ICU_ENTRY_POINT_RENAME(ucal_getNow)
+#define ucal_getTZDataVersion U_ICU_ENTRY_POINT_RENAME(ucal_getTZDataVersion)
+#define ucal_getTimeZoneDisplayName U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneDisplayName)
+#define ucal_getType U_ICU_ENTRY_POINT_RENAME(ucal_getType)
+#define ucal_getWeekendTransition U_ICU_ENTRY_POINT_RENAME(ucal_getWeekendTransition)
+#define ucal_inDaylightTime U_ICU_ENTRY_POINT_RENAME(ucal_inDaylightTime)
+#define ucal_isSet U_ICU_ENTRY_POINT_RENAME(ucal_isSet)
+#define ucal_isWeekend U_ICU_ENTRY_POINT_RENAME(ucal_isWeekend)
+#define ucal_open U_ICU_ENTRY_POINT_RENAME(ucal_open)
+#define ucal_openCountryTimeZones U_ICU_ENTRY_POINT_RENAME(ucal_openCountryTimeZones)
+#define ucal_openTimeZones U_ICU_ENTRY_POINT_RENAME(ucal_openTimeZones)
+#define ucal_roll U_ICU_ENTRY_POINT_RENAME(ucal_roll)
+#define ucal_set U_ICU_ENTRY_POINT_RENAME(ucal_set)
+#define ucal_setAttribute U_ICU_ENTRY_POINT_RENAME(ucal_setAttribute)
+#define ucal_setDate U_ICU_ENTRY_POINT_RENAME(ucal_setDate)
+#define ucal_setDateTime U_ICU_ENTRY_POINT_RENAME(ucal_setDateTime)
+#define ucal_setDefaultTimeZone U_ICU_ENTRY_POINT_RENAME(ucal_setDefaultTimeZone)
+#define ucal_setGregorianChange U_ICU_ENTRY_POINT_RENAME(ucal_setGregorianChange)
+#define ucal_setMillis U_ICU_ENTRY_POINT_RENAME(ucal_setMillis)
+#define ucal_setTimeZone U_ICU_ENTRY_POINT_RENAME(ucal_setTimeZone)
+#define ucase_addCaseClosure U_ICU_ENTRY_POINT_RENAME(ucase_addCaseClosure)
+#define ucase_addPropertyStarts U_ICU_ENTRY_POINT_RENAME(ucase_addPropertyStarts)
+#define ucase_addStringCaseClosure U_ICU_ENTRY_POINT_RENAME(ucase_addStringCaseClosure)
+#define ucase_fold U_ICU_ENTRY_POINT_RENAME(ucase_fold)
+#define ucase_getCaseLocale U_ICU_ENTRY_POINT_RENAME(ucase_getCaseLocale)
+#define ucase_getSingleton U_ICU_ENTRY_POINT_RENAME(ucase_getSingleton)
+#define ucase_getType U_ICU_ENTRY_POINT_RENAME(ucase_getType)
+#define ucase_getTypeOrIgnorable U_ICU_ENTRY_POINT_RENAME(ucase_getTypeOrIgnorable)
+#define ucase_hasBinaryProperty U_ICU_ENTRY_POINT_RENAME(ucase_hasBinaryProperty)
+#define ucase_isCaseSensitive U_ICU_ENTRY_POINT_RENAME(ucase_isCaseSensitive)
+#define ucase_isSoftDotted U_ICU_ENTRY_POINT_RENAME(ucase_isSoftDotted)
+#define ucase_toFullFolding U_ICU_ENTRY_POINT_RENAME(ucase_toFullFolding)
+#define ucase_toFullLower U_ICU_ENTRY_POINT_RENAME(ucase_toFullLower)
+#define ucase_toFullTitle U_ICU_ENTRY_POINT_RENAME(ucase_toFullTitle)
+#define ucase_toFullUpper U_ICU_ENTRY_POINT_RENAME(ucase_toFullUpper)
+#define ucase_tolower U_ICU_ENTRY_POINT_RENAME(ucase_tolower)
+#define ucase_totitle U_ICU_ENTRY_POINT_RENAME(ucase_totitle)
+#define ucase_toupper U_ICU_ENTRY_POINT_RENAME(ucase_toupper)
+#define ucasemap_close U_ICU_ENTRY_POINT_RENAME(ucasemap_close)
+#define ucasemap_getBreakIterator U_ICU_ENTRY_POINT_RENAME(ucasemap_getBreakIterator)
+#define ucasemap_getLocale U_ICU_ENTRY_POINT_RENAME(ucasemap_getLocale)
+#define ucasemap_getOptions U_ICU_ENTRY_POINT_RENAME(ucasemap_getOptions)
+#define ucasemap_open U_ICU_ENTRY_POINT_RENAME(ucasemap_open)
+#define ucasemap_setBreakIterator U_ICU_ENTRY_POINT_RENAME(ucasemap_setBreakIterator)
+#define ucasemap_setLocale U_ICU_ENTRY_POINT_RENAME(ucasemap_setLocale)
+#define ucasemap_setOptions U_ICU_ENTRY_POINT_RENAME(ucasemap_setOptions)
+#define ucasemap_toTitle U_ICU_ENTRY_POINT_RENAME(ucasemap_toTitle)
+#define ucasemap_utf8FoldCase U_ICU_ENTRY_POINT_RENAME(ucasemap_utf8FoldCase)
+#define ucasemap_utf8ToLower U_ICU_ENTRY_POINT_RENAME(ucasemap_utf8ToLower)
+#define ucasemap_utf8ToTitle U_ICU_ENTRY_POINT_RENAME(ucasemap_utf8ToTitle)
+#define ucasemap_utf8ToUpper U_ICU_ENTRY_POINT_RENAME(ucasemap_utf8ToUpper)
+#define ucd_close U_ICU_ENTRY_POINT_RENAME(ucd_close)
+#define ucd_flushCache U_ICU_ENTRY_POINT_RENAME(ucd_flushCache)
+#define ucd_freeCache U_ICU_ENTRY_POINT_RENAME(ucd_freeCache)
+#define ucd_getCollator U_ICU_ENTRY_POINT_RENAME(ucd_getCollator)
+#define ucd_open U_ICU_ENTRY_POINT_RENAME(ucd_open)
+#define uchar_addPropertyStarts U_ICU_ENTRY_POINT_RENAME(uchar_addPropertyStarts)
+#define uchar_swapNames U_ICU_ENTRY_POINT_RENAME(uchar_swapNames)
+#define ucln_cleanupOne U_ICU_ENTRY_POINT_RENAME(ucln_cleanupOne)
+#define ucln_common_registerCleanup U_ICU_ENTRY_POINT_RENAME(ucln_common_registerCleanup)
+#define ucln_i18n_registerCleanup U_ICU_ENTRY_POINT_RENAME(ucln_i18n_registerCleanup)
+#define ucln_io_registerCleanup U_ICU_ENTRY_POINT_RENAME(ucln_io_registerCleanup)
+#define ucln_lib_cleanup U_ICU_ENTRY_POINT_RENAME(ucln_lib_cleanup)
+#define ucln_registerCleanup U_ICU_ENTRY_POINT_RENAME(ucln_registerCleanup)
+#define ucnv_MBCSFromUChar32 U_ICU_ENTRY_POINT_RENAME(ucnv_MBCSFromUChar32)
+#define ucnv_MBCSFromUnicodeWithOffsets U_ICU_ENTRY_POINT_RENAME(ucnv_MBCSFromUnicodeWithOffsets)
+#define ucnv_MBCSGetFilteredUnicodeSetForUnicode U_ICU_ENTRY_POINT_RENAME(ucnv_MBCSGetFilteredUnicodeSetForUnicode)
+#define ucnv_MBCSGetType U_ICU_ENTRY_POINT_RENAME(ucnv_MBCSGetType)
+#define ucnv_MBCSGetUnicodeSetForUnicode U_ICU_ENTRY_POINT_RENAME(ucnv_MBCSGetUnicodeSetForUnicode)
+#define ucnv_MBCSIsLeadByte U_ICU_ENTRY_POINT_RENAME(ucnv_MBCSIsLeadByte)
+#define ucnv_MBCSSimpleGetNextUChar U_ICU_ENTRY_POINT_RENAME(ucnv_MBCSSimpleGetNextUChar)
+#define ucnv_MBCSToUnicodeWithOffsets U_ICU_ENTRY_POINT_RENAME(ucnv_MBCSToUnicodeWithOffsets)
+#define ucnv_bld_countAvailableConverters U_ICU_ENTRY_POINT_RENAME(ucnv_bld_countAvailableConverters)
+#define ucnv_bld_getAvailableConverter U_ICU_ENTRY_POINT_RENAME(ucnv_bld_getAvailableConverter)
+#define ucnv_canCreateConverter U_ICU_ENTRY_POINT_RENAME(ucnv_canCreateConverter)
+#define ucnv_cbFromUWriteBytes U_ICU_ENTRY_POINT_RENAME(ucnv_cbFromUWriteBytes)
+#define ucnv_cbFromUWriteSub U_ICU_ENTRY_POINT_RENAME(ucnv_cbFromUWriteSub)
+#define ucnv_cbFromUWriteUChars U_ICU_ENTRY_POINT_RENAME(ucnv_cbFromUWriteUChars)
+#define ucnv_cbToUWriteSub U_ICU_ENTRY_POINT_RENAME(ucnv_cbToUWriteSub)
+#define ucnv_cbToUWriteUChars U_ICU_ENTRY_POINT_RENAME(ucnv_cbToUWriteUChars)
+#define ucnv_close U_ICU_ENTRY_POINT_RENAME(ucnv_close)
+#define ucnv_compareNames U_ICU_ENTRY_POINT_RENAME(ucnv_compareNames)
+#define ucnv_convert U_ICU_ENTRY_POINT_RENAME(ucnv_convert)
+#define ucnv_convertEx U_ICU_ENTRY_POINT_RENAME(ucnv_convertEx)
+#define ucnv_countAliases U_ICU_ENTRY_POINT_RENAME(ucnv_countAliases)
+#define ucnv_countAvailable U_ICU_ENTRY_POINT_RENAME(ucnv_countAvailable)
+#define ucnv_countStandards U_ICU_ENTRY_POINT_RENAME(ucnv_countStandards)
+#define ucnv_createAlgorithmicConverter U_ICU_ENTRY_POINT_RENAME(ucnv_createAlgorithmicConverter)
+#define ucnv_createConverter U_ICU_ENTRY_POINT_RENAME(ucnv_createConverter)
+#define ucnv_createConverterFromPackage U_ICU_ENTRY_POINT_RENAME(ucnv_createConverterFromPackage)
+#define ucnv_createConverterFromSharedData U_ICU_ENTRY_POINT_RENAME(ucnv_createConverterFromSharedData)
+#define ucnv_detectUnicodeSignature U_ICU_ENTRY_POINT_RENAME(ucnv_detectUnicodeSignature)
+#define ucnv_extContinueMatchFromU U_ICU_ENTRY_POINT_RENAME(ucnv_extContinueMatchFromU)
+#define ucnv_extContinueMatchToU U_ICU_ENTRY_POINT_RENAME(ucnv_extContinueMatchToU)
+#define ucnv_extGetUnicodeSet U_ICU_ENTRY_POINT_RENAME(ucnv_extGetUnicodeSet)
+#define ucnv_extInitialMatchFromU U_ICU_ENTRY_POINT_RENAME(ucnv_extInitialMatchFromU)
+#define ucnv_extInitialMatchToU U_ICU_ENTRY_POINT_RENAME(ucnv_extInitialMatchToU)
+#define ucnv_extSimpleMatchFromU U_ICU_ENTRY_POINT_RENAME(ucnv_extSimpleMatchFromU)
+#define ucnv_extSimpleMatchToU U_ICU_ENTRY_POINT_RENAME(ucnv_extSimpleMatchToU)
+#define ucnv_fixFileSeparator U_ICU_ENTRY_POINT_RENAME(ucnv_fixFileSeparator)
+#define ucnv_flushCache U_ICU_ENTRY_POINT_RENAME(ucnv_flushCache)
+#define ucnv_fromAlgorithmic U_ICU_ENTRY_POINT_RENAME(ucnv_fromAlgorithmic)
+#define ucnv_fromUChars U_ICU_ENTRY_POINT_RENAME(ucnv_fromUChars)
+#define ucnv_fromUCountPending U_ICU_ENTRY_POINT_RENAME(ucnv_fromUCountPending)
+#define ucnv_fromUWriteBytes U_ICU_ENTRY_POINT_RENAME(ucnv_fromUWriteBytes)
+#define ucnv_fromUnicode U_ICU_ENTRY_POINT_RENAME(ucnv_fromUnicode)
+#define ucnv_fromUnicode_UTF8 U_ICU_ENTRY_POINT_RENAME(ucnv_fromUnicode_UTF8)
+#define ucnv_fromUnicode_UTF8_OFFSETS_LOGIC U_ICU_ENTRY_POINT_RENAME(ucnv_fromUnicode_UTF8_OFFSETS_LOGIC)
+#define ucnv_getAlias U_ICU_ENTRY_POINT_RENAME(ucnv_getAlias)
+#define ucnv_getAliases U_ICU_ENTRY_POINT_RENAME(ucnv_getAliases)
+#define ucnv_getAvailableName U_ICU_ENTRY_POINT_RENAME(ucnv_getAvailableName)
+#define ucnv_getCCSID U_ICU_ENTRY_POINT_RENAME(ucnv_getCCSID)
+#define ucnv_getCanonicalName U_ICU_ENTRY_POINT_RENAME(ucnv_getCanonicalName)
+#define ucnv_getCompleteUnicodeSet U_ICU_ENTRY_POINT_RENAME(ucnv_getCompleteUnicodeSet)
+#define ucnv_getDefaultName U_ICU_ENTRY_POINT_RENAME(ucnv_getDefaultName)
+#define ucnv_getDisplayName U_ICU_ENTRY_POINT_RENAME(ucnv_getDisplayName)
+#define ucnv_getFromUCallBack U_ICU_ENTRY_POINT_RENAME(ucnv_getFromUCallBack)
+#define ucnv_getInvalidChars U_ICU_ENTRY_POINT_RENAME(ucnv_getInvalidChars)
+#define ucnv_getInvalidUChars U_ICU_ENTRY_POINT_RENAME(ucnv_getInvalidUChars)
+#define ucnv_getMaxCharSize U_ICU_ENTRY_POINT_RENAME(ucnv_getMaxCharSize)
+#define ucnv_getMinCharSize U_ICU_ENTRY_POINT_RENAME(ucnv_getMinCharSize)
+#define ucnv_getName U_ICU_ENTRY_POINT_RENAME(ucnv_getName)
+#define ucnv_getNextUChar U_ICU_ENTRY_POINT_RENAME(ucnv_getNextUChar)
+#define ucnv_getNonSurrogateUnicodeSet U_ICU_ENTRY_POINT_RENAME(ucnv_getNonSurrogateUnicodeSet)
+#define ucnv_getPlatform U_ICU_ENTRY_POINT_RENAME(ucnv_getPlatform)
+#define ucnv_getStandard U_ICU_ENTRY_POINT_RENAME(ucnv_getStandard)
+#define ucnv_getStandardName U_ICU_ENTRY_POINT_RENAME(ucnv_getStandardName)
+#define ucnv_getStarters U_ICU_ENTRY_POINT_RENAME(ucnv_getStarters)
+#define ucnv_getSubstChars U_ICU_ENTRY_POINT_RENAME(ucnv_getSubstChars)
+#define ucnv_getToUCallBack U_ICU_ENTRY_POINT_RENAME(ucnv_getToUCallBack)
+#define ucnv_getType U_ICU_ENTRY_POINT_RENAME(ucnv_getType)
+#define ucnv_getUnicodeSet U_ICU_ENTRY_POINT_RENAME(ucnv_getUnicodeSet)
+#define ucnv_incrementRefCount U_ICU_ENTRY_POINT_RENAME(ucnv_incrementRefCount)
+#define ucnv_io_countKnownConverters U_ICU_ENTRY_POINT_RENAME(ucnv_io_countKnownConverters)
+#define ucnv_io_getConverterName U_ICU_ENTRY_POINT_RENAME(ucnv_io_getConverterName)
+#define ucnv_io_stripASCIIForCompare U_ICU_ENTRY_POINT_RENAME(ucnv_io_stripASCIIForCompare)
+#define ucnv_io_stripEBCDICForCompare U_ICU_ENTRY_POINT_RENAME(ucnv_io_stripEBCDICForCompare)
+#define ucnv_isAmbiguous U_ICU_ENTRY_POINT_RENAME(ucnv_isAmbiguous)
+#define ucnv_load U_ICU_ENTRY_POINT_RENAME(ucnv_load)
+#define ucnv_loadSharedData U_ICU_ENTRY_POINT_RENAME(ucnv_loadSharedData)
+#define ucnv_open U_ICU_ENTRY_POINT_RENAME(ucnv_open)
+#define ucnv_openAllNames U_ICU_ENTRY_POINT_RENAME(ucnv_openAllNames)
+#define ucnv_openCCSID U_ICU_ENTRY_POINT_RENAME(ucnv_openCCSID)
+#define ucnv_openPackage U_ICU_ENTRY_POINT_RENAME(ucnv_openPackage)
+#define ucnv_openStandardNames U_ICU_ENTRY_POINT_RENAME(ucnv_openStandardNames)
+#define ucnv_openU U_ICU_ENTRY_POINT_RENAME(ucnv_openU)
+#define ucnv_reset U_ICU_ENTRY_POINT_RENAME(ucnv_reset)
+#define ucnv_resetFromUnicode U_ICU_ENTRY_POINT_RENAME(ucnv_resetFromUnicode)
+#define ucnv_resetToUnicode U_ICU_ENTRY_POINT_RENAME(ucnv_resetToUnicode)
+#define ucnv_safeClone U_ICU_ENTRY_POINT_RENAME(ucnv_safeClone)
+#define ucnv_setDefaultName U_ICU_ENTRY_POINT_RENAME(ucnv_setDefaultName)
+#define ucnv_setFallback U_ICU_ENTRY_POINT_RENAME(ucnv_setFallback)
+#define ucnv_setFromUCallBack U_ICU_ENTRY_POINT_RENAME(ucnv_setFromUCallBack)
+#define ucnv_setSubstChars U_ICU_ENTRY_POINT_RENAME(ucnv_setSubstChars)
+#define ucnv_setSubstString U_ICU_ENTRY_POINT_RENAME(ucnv_setSubstString)
+#define ucnv_setToUCallBack U_ICU_ENTRY_POINT_RENAME(ucnv_setToUCallBack)
+#define ucnv_swap U_ICU_ENTRY_POINT_RENAME(ucnv_swap)
+#define ucnv_swapAliases U_ICU_ENTRY_POINT_RENAME(ucnv_swapAliases)
+#define ucnv_toAlgorithmic U_ICU_ENTRY_POINT_RENAME(ucnv_toAlgorithmic)
+#define ucnv_toUChars U_ICU_ENTRY_POINT_RENAME(ucnv_toUChars)
+#define ucnv_toUCountPending U_ICU_ENTRY_POINT_RENAME(ucnv_toUCountPending)
+#define ucnv_toUWriteCodePoint U_ICU_ENTRY_POINT_RENAME(ucnv_toUWriteCodePoint)
+#define ucnv_toUWriteUChars U_ICU_ENTRY_POINT_RENAME(ucnv_toUWriteUChars)
+#define ucnv_toUnicode U_ICU_ENTRY_POINT_RENAME(ucnv_toUnicode)
+#define ucnv_unload U_ICU_ENTRY_POINT_RENAME(ucnv_unload)
+#define ucnv_unloadSharedDataIfReady U_ICU_ENTRY_POINT_RENAME(ucnv_unloadSharedDataIfReady)
+#define ucnv_usesFallback U_ICU_ENTRY_POINT_RENAME(ucnv_usesFallback)
+#define ucnvsel_close U_ICU_ENTRY_POINT_RENAME(ucnvsel_close)
+#define ucnvsel_open U_ICU_ENTRY_POINT_RENAME(ucnvsel_open)
+#define ucnvsel_openFromSerialized U_ICU_ENTRY_POINT_RENAME(ucnvsel_openFromSerialized)
+#define ucnvsel_selectForString U_ICU_ENTRY_POINT_RENAME(ucnvsel_selectForString)
+#define ucnvsel_selectForUTF8 U_ICU_ENTRY_POINT_RENAME(ucnvsel_selectForUTF8)
+#define ucnvsel_serialize U_ICU_ENTRY_POINT_RENAME(ucnvsel_serialize)
+#define ucol_allocWeights U_ICU_ENTRY_POINT_RENAME(ucol_allocWeights)
+#define ucol_assembleTailoringTable U_ICU_ENTRY_POINT_RENAME(ucol_assembleTailoringTable)
+#define ucol_buildPermutationTable U_ICU_ENTRY_POINT_RENAME(ucol_buildPermutationTable)
+#define ucol_calcSortKey U_ICU_ENTRY_POINT_RENAME(ucol_calcSortKey)
+#define ucol_calcSortKeySimpleTertiary U_ICU_ENTRY_POINT_RENAME(ucol_calcSortKeySimpleTertiary)
+#define ucol_cloneBinary U_ICU_ENTRY_POINT_RENAME(ucol_cloneBinary)
+#define ucol_cloneRuleData U_ICU_ENTRY_POINT_RENAME(ucol_cloneRuleData)
+#define ucol_close U_ICU_ENTRY_POINT_RENAME(ucol_close)
+#define ucol_closeElements U_ICU_ENTRY_POINT_RENAME(ucol_closeElements)
+#define ucol_countAvailable U_ICU_ENTRY_POINT_RENAME(ucol_countAvailable)
+#define ucol_createElements U_ICU_ENTRY_POINT_RENAME(ucol_createElements)
+#define ucol_doCE U_ICU_ENTRY_POINT_RENAME(ucol_doCE)
+#define ucol_equal U_ICU_ENTRY_POINT_RENAME(ucol_equal)
+#define ucol_equals U_ICU_ENTRY_POINT_RENAME(ucol_equals)
+#define ucol_findReorderingEntry U_ICU_ENTRY_POINT_RENAME(ucol_findReorderingEntry)
+#define ucol_forceHanImplicit U_ICU_ENTRY_POINT_RENAME(ucol_forceHanImplicit)
+#define ucol_forgetUCA U_ICU_ENTRY_POINT_RENAME(ucol_forgetUCA)
+#define ucol_freeOffsetBuffer U_ICU_ENTRY_POINT_RENAME(ucol_freeOffsetBuffer)
+#define ucol_getAttribute U_ICU_ENTRY_POINT_RENAME(ucol_getAttribute)
+#define ucol_getAttributeOrDefault U_ICU_ENTRY_POINT_RENAME(ucol_getAttributeOrDefault)
+#define ucol_getAvailable U_ICU_ENTRY_POINT_RENAME(ucol_getAvailable)
+#define ucol_getBound U_ICU_ENTRY_POINT_RENAME(ucol_getBound)
+#define ucol_getCEStrengthDifference U_ICU_ENTRY_POINT_RENAME(ucol_getCEStrengthDifference)
+#define ucol_getContractions U_ICU_ENTRY_POINT_RENAME(ucol_getContractions)
+#define ucol_getContractionsAndExpansions U_ICU_ENTRY_POINT_RENAME(ucol_getContractionsAndExpansions)
+#define ucol_getDisplayName U_ICU_ENTRY_POINT_RENAME(ucol_getDisplayName)
+#define ucol_getFirstCE U_ICU_ENTRY_POINT_RENAME(ucol_getFirstCE)
+#define ucol_getFunctionalEquivalent U_ICU_ENTRY_POINT_RENAME(ucol_getFunctionalEquivalent)
+#define ucol_getKeywordValues U_ICU_ENTRY_POINT_RENAME(ucol_getKeywordValues)
+#define ucol_getKeywordValuesForLocale U_ICU_ENTRY_POINT_RENAME(ucol_getKeywordValuesForLocale)
+#define ucol_getKeywords U_ICU_ENTRY_POINT_RENAME(ucol_getKeywords)
+#define ucol_getLeadBytesForReorderCode U_ICU_ENTRY_POINT_RENAME(ucol_getLeadBytesForReorderCode)
+#define ucol_getLocale U_ICU_ENTRY_POINT_RENAME(ucol_getLocale)
+#define ucol_getLocaleByType U_ICU_ENTRY_POINT_RENAME(ucol_getLocaleByType)
+#define ucol_getMaxExpansion U_ICU_ENTRY_POINT_RENAME(ucol_getMaxExpansion)
+#define ucol_getNextCE U_ICU_ENTRY_POINT_RENAME(ucol_getNextCE)
+#define ucol_getOffset U_ICU_ENTRY_POINT_RENAME(ucol_getOffset)
+#define ucol_getPrevCE U_ICU_ENTRY_POINT_RENAME(ucol_getPrevCE)
+#define ucol_getReorderCodes U_ICU_ENTRY_POINT_RENAME(ucol_getReorderCodes)
+#define ucol_getReorderCodesForLeadByte U_ICU_ENTRY_POINT_RENAME(ucol_getReorderCodesForLeadByte)
+#define ucol_getRules U_ICU_ENTRY_POINT_RENAME(ucol_getRules)
+#define ucol_getRulesEx U_ICU_ENTRY_POINT_RENAME(ucol_getRulesEx)
+#define ucol_getShortDefinitionString U_ICU_ENTRY_POINT_RENAME(ucol_getShortDefinitionString)
+#define ucol_getSortKey U_ICU_ENTRY_POINT_RENAME(ucol_getSortKey)
+#define ucol_getSortKeySize U_ICU_ENTRY_POINT_RENAME(ucol_getSortKeySize)
+#define ucol_getSortKeyWithAllocation U_ICU_ENTRY_POINT_RENAME(ucol_getSortKeyWithAllocation)
+#define ucol_getStrength U_ICU_ENTRY_POINT_RENAME(ucol_getStrength)
+#define ucol_getTailoredSet U_ICU_ENTRY_POINT_RENAME(ucol_getTailoredSet)
+#define ucol_getUCAVersion U_ICU_ENTRY_POINT_RENAME(ucol_getUCAVersion)
+#define ucol_getUnsafeSet U_ICU_ENTRY_POINT_RENAME(ucol_getUnsafeSet)
+#define ucol_getVariableTop U_ICU_ENTRY_POINT_RENAME(ucol_getVariableTop)
+#define ucol_getVersion U_ICU_ENTRY_POINT_RENAME(ucol_getVersion)
+#define ucol_greater U_ICU_ENTRY_POINT_RENAME(ucol_greater)
+#define ucol_greaterOrEqual U_ICU_ENTRY_POINT_RENAME(ucol_greaterOrEqual)
+#define ucol_initBuffers U_ICU_ENTRY_POINT_RENAME(ucol_initBuffers)
+#define ucol_initCollator U_ICU_ENTRY_POINT_RENAME(ucol_initCollator)
+#define ucol_initInverseUCA U_ICU_ENTRY_POINT_RENAME(ucol_initInverseUCA)
+#define ucol_initUCA U_ICU_ENTRY_POINT_RENAME(ucol_initUCA)
+#define ucol_inv_getNextCE U_ICU_ENTRY_POINT_RENAME(ucol_inv_getNextCE)
+#define ucol_inv_getPrevCE U_ICU_ENTRY_POINT_RENAME(ucol_inv_getPrevCE)
+#define ucol_isTailored U_ICU_ENTRY_POINT_RENAME(ucol_isTailored)
+#define ucol_keyHashCode U_ICU_ENTRY_POINT_RENAME(ucol_keyHashCode)
+#define ucol_looksLikeCollationBinary U_ICU_ENTRY_POINT_RENAME(ucol_looksLikeCollationBinary)
+#define ucol_mergeSortkeys U_ICU_ENTRY_POINT_RENAME(ucol_mergeSortkeys)
+#define ucol_next U_ICU_ENTRY_POINT_RENAME(ucol_next)
+#define ucol_nextProcessed U_ICU_ENTRY_POINT_RENAME(ucol_nextProcessed)
+#define ucol_nextSortKeyPart U_ICU_ENTRY_POINT_RENAME(ucol_nextSortKeyPart)
+#define ucol_nextWeight U_ICU_ENTRY_POINT_RENAME(ucol_nextWeight)
+#define ucol_normalizeShortDefinitionString U_ICU_ENTRY_POINT_RENAME(ucol_normalizeShortDefinitionString)
+#define ucol_open U_ICU_ENTRY_POINT_RENAME(ucol_open)
+#define ucol_openAvailableLocales U_ICU_ENTRY_POINT_RENAME(ucol_openAvailableLocales)
+#define ucol_openBinary U_ICU_ENTRY_POINT_RENAME(ucol_openBinary)
+#define ucol_openElements U_ICU_ENTRY_POINT_RENAME(ucol_openElements)
+#define ucol_openFromShortString U_ICU_ENTRY_POINT_RENAME(ucol_openFromShortString)
+#define ucol_openRules U_ICU_ENTRY_POINT_RENAME(ucol_openRules)
+#define ucol_openRulesForImport U_ICU_ENTRY_POINT_RENAME(ucol_openRulesForImport)
+#define ucol_open_internal U_ICU_ENTRY_POINT_RENAME(ucol_open_internal)
+#define ucol_prepareShortStringOpen U_ICU_ENTRY_POINT_RENAME(ucol_prepareShortStringOpen)
+#define ucol_previous U_ICU_ENTRY_POINT_RENAME(ucol_previous)
+#define ucol_previousProcessed U_ICU_ENTRY_POINT_RENAME(ucol_previousProcessed)
+#define ucol_primaryOrder U_ICU_ENTRY_POINT_RENAME(ucol_primaryOrder)
+#define ucol_prv_getSpecialCE U_ICU_ENTRY_POINT_RENAME(ucol_prv_getSpecialCE)
+#define ucol_prv_getSpecialPrevCE U_ICU_ENTRY_POINT_RENAME(ucol_prv_getSpecialPrevCE)
+#define ucol_reset U_ICU_ENTRY_POINT_RENAME(ucol_reset)
+#define ucol_restoreVariableTop U_ICU_ENTRY_POINT_RENAME(ucol_restoreVariableTop)
+#define ucol_safeClone U_ICU_ENTRY_POINT_RENAME(ucol_safeClone)
+#define ucol_secondaryOrder U_ICU_ENTRY_POINT_RENAME(ucol_secondaryOrder)
+#define ucol_setAttribute U_ICU_ENTRY_POINT_RENAME(ucol_setAttribute)
+#define ucol_setOffset U_ICU_ENTRY_POINT_RENAME(ucol_setOffset)
+#define ucol_setOptionsFromHeader U_ICU_ENTRY_POINT_RENAME(ucol_setOptionsFromHeader)
+#define ucol_setReorderCodes U_ICU_ENTRY_POINT_RENAME(ucol_setReorderCodes)
+#define ucol_setReqValidLocales U_ICU_ENTRY_POINT_RENAME(ucol_setReqValidLocales)
+#define ucol_setStrength U_ICU_ENTRY_POINT_RENAME(ucol_setStrength)
+#define ucol_setText U_ICU_ENTRY_POINT_RENAME(ucol_setText)
+#define ucol_setVariableTop U_ICU_ENTRY_POINT_RENAME(ucol_setVariableTop)
+#define ucol_strcoll U_ICU_ENTRY_POINT_RENAME(ucol_strcoll)
+#define ucol_strcollIter U_ICU_ENTRY_POINT_RENAME(ucol_strcollIter)
+#define ucol_swap U_ICU_ENTRY_POINT_RENAME(ucol_swap)
+#define ucol_swapBinary U_ICU_ENTRY_POINT_RENAME(ucol_swapBinary)
+#define ucol_swapInverseUCA U_ICU_ENTRY_POINT_RENAME(ucol_swapInverseUCA)
+#define ucol_tertiaryOrder U_ICU_ENTRY_POINT_RENAME(ucol_tertiaryOrder)
+#define ucol_tok_assembleTokenList U_ICU_ENTRY_POINT_RENAME(ucol_tok_assembleTokenList)
+#define ucol_tok_closeTokenList U_ICU_ENTRY_POINT_RENAME(ucol_tok_closeTokenList)
+#define ucol_tok_getNextArgument U_ICU_ENTRY_POINT_RENAME(ucol_tok_getNextArgument)
+#define ucol_tok_getRulesFromBundle U_ICU_ENTRY_POINT_RENAME(ucol_tok_getRulesFromBundle)
+#define ucol_tok_initTokenList U_ICU_ENTRY_POINT_RENAME(ucol_tok_initTokenList)
+#define ucol_tok_parseNextToken U_ICU_ENTRY_POINT_RENAME(ucol_tok_parseNextToken)
+#define ucol_updateInternalState U_ICU_ENTRY_POINT_RENAME(ucol_updateInternalState)
+#define ucsdet_close U_ICU_ENTRY_POINT_RENAME(ucsdet_close)
+#define ucsdet_detect U_ICU_ENTRY_POINT_RENAME(ucsdet_detect)
+#define ucsdet_detectAll U_ICU_ENTRY_POINT_RENAME(ucsdet_detectAll)
+#define ucsdet_enableInputFilter U_ICU_ENTRY_POINT_RENAME(ucsdet_enableInputFilter)
+#define ucsdet_getAllDetectableCharsets U_ICU_ENTRY_POINT_RENAME(ucsdet_getAllDetectableCharsets)
+#define ucsdet_getConfidence U_ICU_ENTRY_POINT_RENAME(ucsdet_getConfidence)
+#define ucsdet_getLanguage U_ICU_ENTRY_POINT_RENAME(ucsdet_getLanguage)
+#define ucsdet_getName U_ICU_ENTRY_POINT_RENAME(ucsdet_getName)
+#define ucsdet_getUChars U_ICU_ENTRY_POINT_RENAME(ucsdet_getUChars)
+#define ucsdet_isInputFilterEnabled U_ICU_ENTRY_POINT_RENAME(ucsdet_isInputFilterEnabled)
+#define ucsdet_open U_ICU_ENTRY_POINT_RENAME(ucsdet_open)
+#define ucsdet_setDeclaredEncoding U_ICU_ENTRY_POINT_RENAME(ucsdet_setDeclaredEncoding)
+#define ucsdet_setText U_ICU_ENTRY_POINT_RENAME(ucsdet_setText)
+#define ucurr_countCurrencies U_ICU_ENTRY_POINT_RENAME(ucurr_countCurrencies)
+#define ucurr_forLocale U_ICU_ENTRY_POINT_RENAME(ucurr_forLocale)
+#define ucurr_forLocaleAndDate U_ICU_ENTRY_POINT_RENAME(ucurr_forLocaleAndDate)
+#define ucurr_getDefaultFractionDigits U_ICU_ENTRY_POINT_RENAME(ucurr_getDefaultFractionDigits)
+#define ucurr_getKeywordValuesForLocale U_ICU_ENTRY_POINT_RENAME(ucurr_getKeywordValuesForLocale)
+#define ucurr_getName U_ICU_ENTRY_POINT_RENAME(ucurr_getName)
+#define ucurr_getPluralName U_ICU_ENTRY_POINT_RENAME(ucurr_getPluralName)
+#define ucurr_getRoundingIncrement U_ICU_ENTRY_POINT_RENAME(ucurr_getRoundingIncrement)
+#define ucurr_openISOCurrencies U_ICU_ENTRY_POINT_RENAME(ucurr_openISOCurrencies)
+#define ucurr_register U_ICU_ENTRY_POINT_RENAME(ucurr_register)
+#define ucurr_unregister U_ICU_ENTRY_POINT_RENAME(ucurr_unregister)
+#define udat_applyPattern U_ICU_ENTRY_POINT_RENAME(udat_applyPattern)
+#define udat_applyPatternRelative U_ICU_ENTRY_POINT_RENAME(udat_applyPatternRelative)
+#define udat_clone U_ICU_ENTRY_POINT_RENAME(udat_clone)
+#define udat_close U_ICU_ENTRY_POINT_RENAME(udat_close)
+#define udat_countAvailable U_ICU_ENTRY_POINT_RENAME(udat_countAvailable)
+#define udat_countSymbols U_ICU_ENTRY_POINT_RENAME(udat_countSymbols)
+#define udat_format U_ICU_ENTRY_POINT_RENAME(udat_format)
+#define udat_get2DigitYearStart U_ICU_ENTRY_POINT_RENAME(udat_get2DigitYearStart)
+#define udat_getAvailable U_ICU_ENTRY_POINT_RENAME(udat_getAvailable)
+#define udat_getCalendar U_ICU_ENTRY_POINT_RENAME(udat_getCalendar)
+#define udat_getLocaleByType U_ICU_ENTRY_POINT_RENAME(udat_getLocaleByType)
+#define udat_getNumberFormat U_ICU_ENTRY_POINT_RENAME(udat_getNumberFormat)
+#define udat_getSymbols U_ICU_ENTRY_POINT_RENAME(udat_getSymbols)
+#define udat_isLenient U_ICU_ENTRY_POINT_RENAME(udat_isLenient)
+#define udat_open U_ICU_ENTRY_POINT_RENAME(udat_open)
+#define udat_parse U_ICU_ENTRY_POINT_RENAME(udat_parse)
+#define udat_parseCalendar U_ICU_ENTRY_POINT_RENAME(udat_parseCalendar)
+#define udat_set2DigitYearStart U_ICU_ENTRY_POINT_RENAME(udat_set2DigitYearStart)
+#define udat_setCalendar U_ICU_ENTRY_POINT_RENAME(udat_setCalendar)
+#define udat_setLenient U_ICU_ENTRY_POINT_RENAME(udat_setLenient)
+#define udat_setNumberFormat U_ICU_ENTRY_POINT_RENAME(udat_setNumberFormat)
+#define udat_setSymbols U_ICU_ENTRY_POINT_RENAME(udat_setSymbols)
+#define udat_toCalendarDateField U_ICU_ENTRY_POINT_RENAME(udat_toCalendarDateField)
+#define udat_toPattern U_ICU_ENTRY_POINT_RENAME(udat_toPattern)
+#define udat_toPatternRelativeDate U_ICU_ENTRY_POINT_RENAME(udat_toPatternRelativeDate)
+#define udat_toPatternRelativeTime U_ICU_ENTRY_POINT_RENAME(udat_toPatternRelativeTime)
+#define udata_checkCommonData U_ICU_ENTRY_POINT_RENAME(udata_checkCommonData)
+#define udata_close U_ICU_ENTRY_POINT_RENAME(udata_close)
+#define udata_closeSwapper U_ICU_ENTRY_POINT_RENAME(udata_closeSwapper)
+#define udata_getHeaderSize U_ICU_ENTRY_POINT_RENAME(udata_getHeaderSize)
+#define udata_getInfo U_ICU_ENTRY_POINT_RENAME(udata_getInfo)
+#define udata_getInfoSize U_ICU_ENTRY_POINT_RENAME(udata_getInfoSize)
+#define udata_getLength U_ICU_ENTRY_POINT_RENAME(udata_getLength)
+#define udata_getMemory U_ICU_ENTRY_POINT_RENAME(udata_getMemory)
+#define udata_getRawMemory U_ICU_ENTRY_POINT_RENAME(udata_getRawMemory)
+#define udata_open U_ICU_ENTRY_POINT_RENAME(udata_open)
+#define udata_openChoice U_ICU_ENTRY_POINT_RENAME(udata_openChoice)
+#define udata_openSwapper U_ICU_ENTRY_POINT_RENAME(udata_openSwapper)
+#define udata_openSwapperForInputData U_ICU_ENTRY_POINT_RENAME(udata_openSwapperForInputData)
+#define udata_printError U_ICU_ENTRY_POINT_RENAME(udata_printError)
+#define udata_readInt16 U_ICU_ENTRY_POINT_RENAME(udata_readInt16)
+#define udata_readInt32 U_ICU_ENTRY_POINT_RENAME(udata_readInt32)
+#define udata_setAppData U_ICU_ENTRY_POINT_RENAME(udata_setAppData)
+#define udata_setCommonData U_ICU_ENTRY_POINT_RENAME(udata_setCommonData)
+#define udata_setFileAccess U_ICU_ENTRY_POINT_RENAME(udata_setFileAccess)
+#define udata_swapDataHeader U_ICU_ENTRY_POINT_RENAME(udata_swapDataHeader)
+#define udata_swapInvStringBlock U_ICU_ENTRY_POINT_RENAME(udata_swapInvStringBlock)
+#define udatpg_addPattern U_ICU_ENTRY_POINT_RENAME(udatpg_addPattern)
+#define udatpg_clone U_ICU_ENTRY_POINT_RENAME(udatpg_clone)
+#define udatpg_close U_ICU_ENTRY_POINT_RENAME(udatpg_close)
+#define udatpg_getAppendItemFormat U_ICU_ENTRY_POINT_RENAME(udatpg_getAppendItemFormat)
+#define udatpg_getAppendItemName U_ICU_ENTRY_POINT_RENAME(udatpg_getAppendItemName)
+#define udatpg_getBaseSkeleton U_ICU_ENTRY_POINT_RENAME(udatpg_getBaseSkeleton)
+#define udatpg_getBestPattern U_ICU_ENTRY_POINT_RENAME(udatpg_getBestPattern)
+#define udatpg_getBestPatternWithOptions U_ICU_ENTRY_POINT_RENAME(udatpg_getBestPatternWithOptions)
+#define udatpg_getDateTimeFormat U_ICU_ENTRY_POINT_RENAME(udatpg_getDateTimeFormat)
+#define udatpg_getDecimal U_ICU_ENTRY_POINT_RENAME(udatpg_getDecimal)
+#define udatpg_getPatternForSkeleton U_ICU_ENTRY_POINT_RENAME(udatpg_getPatternForSkeleton)
+#define udatpg_getSkeleton U_ICU_ENTRY_POINT_RENAME(udatpg_getSkeleton)
+#define udatpg_open U_ICU_ENTRY_POINT_RENAME(udatpg_open)
+#define udatpg_openBaseSkeletons U_ICU_ENTRY_POINT_RENAME(udatpg_openBaseSkeletons)
+#define udatpg_openEmpty U_ICU_ENTRY_POINT_RENAME(udatpg_openEmpty)
+#define udatpg_openSkeletons U_ICU_ENTRY_POINT_RENAME(udatpg_openSkeletons)
+#define udatpg_replaceFieldTypes U_ICU_ENTRY_POINT_RENAME(udatpg_replaceFieldTypes)
+#define udatpg_replaceFieldTypesWithOptions U_ICU_ENTRY_POINT_RENAME(udatpg_replaceFieldTypesWithOptions)
+#define udatpg_setAppendItemFormat U_ICU_ENTRY_POINT_RENAME(udatpg_setAppendItemFormat)
+#define udatpg_setAppendItemName U_ICU_ENTRY_POINT_RENAME(udatpg_setAppendItemName)
+#define udatpg_setDateTimeFormat U_ICU_ENTRY_POINT_RENAME(udatpg_setDateTimeFormat)
+#define udatpg_setDecimal U_ICU_ENTRY_POINT_RENAME(udatpg_setDecimal)
+#define uenum_close U_ICU_ENTRY_POINT_RENAME(uenum_close)
+#define uenum_count U_ICU_ENTRY_POINT_RENAME(uenum_count)
+#define uenum_next U_ICU_ENTRY_POINT_RENAME(uenum_next)
+#define uenum_nextDefault U_ICU_ENTRY_POINT_RENAME(uenum_nextDefault)
+#define uenum_openCharStringsEnumeration U_ICU_ENTRY_POINT_RENAME(uenum_openCharStringsEnumeration)
+#define uenum_openFromStringEnumeration U_ICU_ENTRY_POINT_RENAME(uenum_openFromStringEnumeration)
+#define uenum_reset U_ICU_ENTRY_POINT_RENAME(uenum_reset)
+#define uenum_unext U_ICU_ENTRY_POINT_RENAME(uenum_unext)
+#define uenum_unextDefault U_ICU_ENTRY_POINT_RENAME(uenum_unextDefault)
+#define ufile_close_translit U_ICU_ENTRY_POINT_RENAME(ufile_close_translit)
+#define ufile_fill_uchar_buffer U_ICU_ENTRY_POINT_RENAME(ufile_fill_uchar_buffer)
+#define ufile_flush_io U_ICU_ENTRY_POINT_RENAME(ufile_flush_io)
+#define ufile_flush_translit U_ICU_ENTRY_POINT_RENAME(ufile_flush_translit)
+#define ufile_getch U_ICU_ENTRY_POINT_RENAME(ufile_getch)
+#define ufile_getch32 U_ICU_ENTRY_POINT_RENAME(ufile_getch32)
+#define ufmt_64tou U_ICU_ENTRY_POINT_RENAME(ufmt_64tou)
+#define ufmt_defaultCPToUnicode U_ICU_ENTRY_POINT_RENAME(ufmt_defaultCPToUnicode)
+#define ufmt_digitvalue U_ICU_ENTRY_POINT_RENAME(ufmt_digitvalue)
+#define ufmt_isdigit U_ICU_ENTRY_POINT_RENAME(ufmt_isdigit)
+#define ufmt_ptou U_ICU_ENTRY_POINT_RENAME(ufmt_ptou)
+#define ufmt_uto64 U_ICU_ENTRY_POINT_RENAME(ufmt_uto64)
+#define ufmt_utop U_ICU_ENTRY_POINT_RENAME(ufmt_utop)
+#define uhash_close U_ICU_ENTRY_POINT_RENAME(uhash_close)
+#define uhash_compareCaselessUnicodeString U_ICU_ENTRY_POINT_RENAME(uhash_compareCaselessUnicodeString)
+#define uhash_compareChars U_ICU_ENTRY_POINT_RENAME(uhash_compareChars)
+#define uhash_compareIChars U_ICU_ENTRY_POINT_RENAME(uhash_compareIChars)
+#define uhash_compareLong U_ICU_ENTRY_POINT_RENAME(uhash_compareLong)
+#define uhash_compareUChars U_ICU_ENTRY_POINT_RENAME(uhash_compareUChars)
+#define uhash_compareUnicodeString U_ICU_ENTRY_POINT_RENAME(uhash_compareUnicodeString)
+#define uhash_count U_ICU_ENTRY_POINT_RENAME(uhash_count)
+#define uhash_deleteHashtable U_ICU_ENTRY_POINT_RENAME(uhash_deleteHashtable)
+#define uhash_deleteUObject U_ICU_ENTRY_POINT_RENAME(uhash_deleteUObject)
+#define uhash_deleteUnicodeString U_ICU_ENTRY_POINT_RENAME(uhash_deleteUnicodeString)
+#define uhash_equals U_ICU_ENTRY_POINT_RENAME(uhash_equals)
+#define uhash_find U_ICU_ENTRY_POINT_RENAME(uhash_find)
+#define uhash_freeBlock U_ICU_ENTRY_POINT_RENAME(uhash_freeBlock)
+#define uhash_get U_ICU_ENTRY_POINT_RENAME(uhash_get)
+#define uhash_geti U_ICU_ENTRY_POINT_RENAME(uhash_geti)
+#define uhash_hashCaselessUnicodeString U_ICU_ENTRY_POINT_RENAME(uhash_hashCaselessUnicodeString)
+#define uhash_hashChars U_ICU_ENTRY_POINT_RENAME(uhash_hashChars)
+#define uhash_hashIChars U_ICU_ENTRY_POINT_RENAME(uhash_hashIChars)
+#define uhash_hashLong U_ICU_ENTRY_POINT_RENAME(uhash_hashLong)
+#define uhash_hashUChars U_ICU_ENTRY_POINT_RENAME(uhash_hashUChars)
+#define uhash_hashUCharsN U_ICU_ENTRY_POINT_RENAME(uhash_hashUCharsN)
+#define uhash_hashUnicodeString U_ICU_ENTRY_POINT_RENAME(uhash_hashUnicodeString)
+#define uhash_iget U_ICU_ENTRY_POINT_RENAME(uhash_iget)
+#define uhash_igeti U_ICU_ENTRY_POINT_RENAME(uhash_igeti)
+#define uhash_init U_ICU_ENTRY_POINT_RENAME(uhash_init)
+#define uhash_iput U_ICU_ENTRY_POINT_RENAME(uhash_iput)
+#define uhash_iputi U_ICU_ENTRY_POINT_RENAME(uhash_iputi)
+#define uhash_iremove U_ICU_ENTRY_POINT_RENAME(uhash_iremove)
+#define uhash_iremovei U_ICU_ENTRY_POINT_RENAME(uhash_iremovei)
+#define uhash_nextElement U_ICU_ENTRY_POINT_RENAME(uhash_nextElement)
+#define uhash_open U_ICU_ENTRY_POINT_RENAME(uhash_open)
+#define uhash_openSize U_ICU_ENTRY_POINT_RENAME(uhash_openSize)
+#define uhash_put U_ICU_ENTRY_POINT_RENAME(uhash_put)
+#define uhash_puti U_ICU_ENTRY_POINT_RENAME(uhash_puti)
+#define uhash_remove U_ICU_ENTRY_POINT_RENAME(uhash_remove)
+#define uhash_removeAll U_ICU_ENTRY_POINT_RENAME(uhash_removeAll)
+#define uhash_removeElement U_ICU_ENTRY_POINT_RENAME(uhash_removeElement)
+#define uhash_removei U_ICU_ENTRY_POINT_RENAME(uhash_removei)
+#define uhash_setKeyComparator U_ICU_ENTRY_POINT_RENAME(uhash_setKeyComparator)
+#define uhash_setKeyDeleter U_ICU_ENTRY_POINT_RENAME(uhash_setKeyDeleter)
+#define uhash_setKeyHasher U_ICU_ENTRY_POINT_RENAME(uhash_setKeyHasher)
+#define uhash_setResizePolicy U_ICU_ENTRY_POINT_RENAME(uhash_setResizePolicy)
+#define uhash_setValueComparator U_ICU_ENTRY_POINT_RENAME(uhash_setValueComparator)
+#define uhash_setValueDeleter U_ICU_ENTRY_POINT_RENAME(uhash_setValueDeleter)
+#define uidna_IDNToASCII U_ICU_ENTRY_POINT_RENAME(uidna_IDNToASCII)
+#define uidna_IDNToUnicode U_ICU_ENTRY_POINT_RENAME(uidna_IDNToUnicode)
+#define uidna_close U_ICU_ENTRY_POINT_RENAME(uidna_close)
+#define uidna_compare U_ICU_ENTRY_POINT_RENAME(uidna_compare)
+#define uidna_labelToASCII U_ICU_ENTRY_POINT_RENAME(uidna_labelToASCII)
+#define uidna_labelToASCII_UTF8 U_ICU_ENTRY_POINT_RENAME(uidna_labelToASCII_UTF8)
+#define uidna_labelToUnicode U_ICU_ENTRY_POINT_RENAME(uidna_labelToUnicode)
+#define uidna_labelToUnicodeUTF8 U_ICU_ENTRY_POINT_RENAME(uidna_labelToUnicodeUTF8)
+#define uidna_nameToASCII U_ICU_ENTRY_POINT_RENAME(uidna_nameToASCII)
+#define uidna_nameToASCII_UTF8 U_ICU_ENTRY_POINT_RENAME(uidna_nameToASCII_UTF8)
+#define uidna_nameToUnicode U_ICU_ENTRY_POINT_RENAME(uidna_nameToUnicode)
+#define uidna_nameToUnicodeUTF8 U_ICU_ENTRY_POINT_RENAME(uidna_nameToUnicodeUTF8)
+#define uidna_openUTS46 U_ICU_ENTRY_POINT_RENAME(uidna_openUTS46)
+#define uidna_toASCII U_ICU_ENTRY_POINT_RENAME(uidna_toASCII)
+#define uidna_toUnicode U_ICU_ENTRY_POINT_RENAME(uidna_toUnicode)
+#define uiter_current32 U_ICU_ENTRY_POINT_RENAME(uiter_current32)
+#define uiter_getState U_ICU_ENTRY_POINT_RENAME(uiter_getState)
+#define uiter_next32 U_ICU_ENTRY_POINT_RENAME(uiter_next32)
+#define uiter_previous32 U_ICU_ENTRY_POINT_RENAME(uiter_previous32)
+#define uiter_setCharacterIterator U_ICU_ENTRY_POINT_RENAME(uiter_setCharacterIterator)
+#define uiter_setReplaceable U_ICU_ENTRY_POINT_RENAME(uiter_setReplaceable)
+#define uiter_setState U_ICU_ENTRY_POINT_RENAME(uiter_setState)
+#define uiter_setString U_ICU_ENTRY_POINT_RENAME(uiter_setString)
+#define uiter_setUTF16BE U_ICU_ENTRY_POINT_RENAME(uiter_setUTF16BE)
+#define uiter_setUTF8 U_ICU_ENTRY_POINT_RENAME(uiter_setUTF8)
+#define uldn_close U_ICU_ENTRY_POINT_RENAME(uldn_close)
+#define uldn_getDialectHandling U_ICU_ENTRY_POINT_RENAME(uldn_getDialectHandling)
+#define uldn_getLocale U_ICU_ENTRY_POINT_RENAME(uldn_getLocale)
+#define uldn_keyDisplayName U_ICU_ENTRY_POINT_RENAME(uldn_keyDisplayName)
+#define uldn_keyValueDisplayName U_ICU_ENTRY_POINT_RENAME(uldn_keyValueDisplayName)
+#define uldn_languageDisplayName U_ICU_ENTRY_POINT_RENAME(uldn_languageDisplayName)
+#define uldn_localeDisplayName U_ICU_ENTRY_POINT_RENAME(uldn_localeDisplayName)
+#define uldn_open U_ICU_ENTRY_POINT_RENAME(uldn_open)
+#define uldn_regionDisplayName U_ICU_ENTRY_POINT_RENAME(uldn_regionDisplayName)
+#define uldn_scriptCodeDisplayName U_ICU_ENTRY_POINT_RENAME(uldn_scriptCodeDisplayName)
+#define uldn_scriptDisplayName U_ICU_ENTRY_POINT_RENAME(uldn_scriptDisplayName)
+#define uldn_variantDisplayName U_ICU_ENTRY_POINT_RENAME(uldn_variantDisplayName)
+#define ulist_addItemBeginList U_ICU_ENTRY_POINT_RENAME(ulist_addItemBeginList)
+#define ulist_addItemEndList U_ICU_ENTRY_POINT_RENAME(ulist_addItemEndList)
+#define ulist_close_keyword_values_iterator U_ICU_ENTRY_POINT_RENAME(ulist_close_keyword_values_iterator)
+#define ulist_containsString U_ICU_ENTRY_POINT_RENAME(ulist_containsString)
+#define ulist_count_keyword_values U_ICU_ENTRY_POINT_RENAME(ulist_count_keyword_values)
+#define ulist_createEmptyList U_ICU_ENTRY_POINT_RENAME(ulist_createEmptyList)
+#define ulist_deleteList U_ICU_ENTRY_POINT_RENAME(ulist_deleteList)
+#define ulist_getListFromEnum U_ICU_ENTRY_POINT_RENAME(ulist_getListFromEnum)
+#define ulist_getListSize U_ICU_ENTRY_POINT_RENAME(ulist_getListSize)
+#define ulist_getNext U_ICU_ENTRY_POINT_RENAME(ulist_getNext)
+#define ulist_next_keyword_value U_ICU_ENTRY_POINT_RENAME(ulist_next_keyword_value)
+#define ulist_resetList U_ICU_ENTRY_POINT_RENAME(ulist_resetList)
+#define ulist_reset_keyword_values_iterator U_ICU_ENTRY_POINT_RENAME(ulist_reset_keyword_values_iterator)
+#define uloc_acceptLanguage U_ICU_ENTRY_POINT_RENAME(uloc_acceptLanguage)
+#define uloc_acceptLanguageFromHTTP U_ICU_ENTRY_POINT_RENAME(uloc_acceptLanguageFromHTTP)
+#define uloc_addLikelySubtags U_ICU_ENTRY_POINT_RENAME(uloc_addLikelySubtags)
+#define uloc_canonicalize U_ICU_ENTRY_POINT_RENAME(uloc_canonicalize)
+#define uloc_countAvailable U_ICU_ENTRY_POINT_RENAME(uloc_countAvailable)
+#define uloc_forLanguageTag U_ICU_ENTRY_POINT_RENAME(uloc_forLanguageTag)
+#define uloc_getAvailable U_ICU_ENTRY_POINT_RENAME(uloc_getAvailable)
+#define uloc_getBaseName U_ICU_ENTRY_POINT_RENAME(uloc_getBaseName)
+#define uloc_getCharacterOrientation U_ICU_ENTRY_POINT_RENAME(uloc_getCharacterOrientation)
+#define uloc_getCountry U_ICU_ENTRY_POINT_RENAME(uloc_getCountry)
+#define uloc_getCurrentCountryID U_ICU_ENTRY_POINT_RENAME(uloc_getCurrentCountryID)
+#define uloc_getCurrentLanguageID U_ICU_ENTRY_POINT_RENAME(uloc_getCurrentLanguageID)
+#define uloc_getDefault U_ICU_ENTRY_POINT_RENAME(uloc_getDefault)
+#define uloc_getDisplayCountry U_ICU_ENTRY_POINT_RENAME(uloc_getDisplayCountry)
+#define uloc_getDisplayKeyword U_ICU_ENTRY_POINT_RENAME(uloc_getDisplayKeyword)
+#define uloc_getDisplayKeywordValue U_ICU_ENTRY_POINT_RENAME(uloc_getDisplayKeywordValue)
+#define uloc_getDisplayLanguage U_ICU_ENTRY_POINT_RENAME(uloc_getDisplayLanguage)
+#define uloc_getDisplayName U_ICU_ENTRY_POINT_RENAME(uloc_getDisplayName)
+#define uloc_getDisplayScript U_ICU_ENTRY_POINT_RENAME(uloc_getDisplayScript)
+#define uloc_getDisplayVariant U_ICU_ENTRY_POINT_RENAME(uloc_getDisplayVariant)
+#define uloc_getISO3Country U_ICU_ENTRY_POINT_RENAME(uloc_getISO3Country)
+#define uloc_getISO3Language U_ICU_ENTRY_POINT_RENAME(uloc_getISO3Language)
+#define uloc_getISOCountries U_ICU_ENTRY_POINT_RENAME(uloc_getISOCountries)
+#define uloc_getISOLanguages U_ICU_ENTRY_POINT_RENAME(uloc_getISOLanguages)
+#define uloc_getKeywordValue U_ICU_ENTRY_POINT_RENAME(uloc_getKeywordValue)
+#define uloc_getLCID U_ICU_ENTRY_POINT_RENAME(uloc_getLCID)
+#define uloc_getLanguage U_ICU_ENTRY_POINT_RENAME(uloc_getLanguage)
+#define uloc_getLineOrientation U_ICU_ENTRY_POINT_RENAME(uloc_getLineOrientation)
+#define uloc_getLocaleForLCID U_ICU_ENTRY_POINT_RENAME(uloc_getLocaleForLCID)
+#define uloc_getName U_ICU_ENTRY_POINT_RENAME(uloc_getName)
+#define uloc_getParent U_ICU_ENTRY_POINT_RENAME(uloc_getParent)
+#define uloc_getScript U_ICU_ENTRY_POINT_RENAME(uloc_getScript)
+#define uloc_getTableStringWithFallback U_ICU_ENTRY_POINT_RENAME(uloc_getTableStringWithFallback)
+#define uloc_getVariant U_ICU_ENTRY_POINT_RENAME(uloc_getVariant)
+#define uloc_minimizeSubtags U_ICU_ENTRY_POINT_RENAME(uloc_minimizeSubtags)
+#define uloc_openKeywordList U_ICU_ENTRY_POINT_RENAME(uloc_openKeywordList)
+#define uloc_openKeywords U_ICU_ENTRY_POINT_RENAME(uloc_openKeywords)
+#define uloc_setDefault U_ICU_ENTRY_POINT_RENAME(uloc_setDefault)
+#define uloc_setKeywordValue U_ICU_ENTRY_POINT_RENAME(uloc_setKeywordValue)
+#define uloc_toLanguageTag U_ICU_ENTRY_POINT_RENAME(uloc_toLanguageTag)
+#define ulocdata_close U_ICU_ENTRY_POINT_RENAME(ulocdata_close)
+#define ulocdata_getCLDRVersion U_ICU_ENTRY_POINT_RENAME(ulocdata_getCLDRVersion)
+#define ulocdata_getDelimiter U_ICU_ENTRY_POINT_RENAME(ulocdata_getDelimiter)
+#define ulocdata_getExemplarSet U_ICU_ENTRY_POINT_RENAME(ulocdata_getExemplarSet)
+#define ulocdata_getLocaleDisplayPattern U_ICU_ENTRY_POINT_RENAME(ulocdata_getLocaleDisplayPattern)
+#define ulocdata_getLocaleSeparator U_ICU_ENTRY_POINT_RENAME(ulocdata_getLocaleSeparator)
+#define ulocdata_getMeasurementSystem U_ICU_ENTRY_POINT_RENAME(ulocdata_getMeasurementSystem)
+#define ulocdata_getNoSubstitute U_ICU_ENTRY_POINT_RENAME(ulocdata_getNoSubstitute)
+#define ulocdata_getPaperSize U_ICU_ENTRY_POINT_RENAME(ulocdata_getPaperSize)
+#define ulocdata_open U_ICU_ENTRY_POINT_RENAME(ulocdata_open)
+#define ulocdata_setNoSubstitute U_ICU_ENTRY_POINT_RENAME(ulocdata_setNoSubstitute)
+#define ulocimp_getCountry U_ICU_ENTRY_POINT_RENAME(ulocimp_getCountry)
+#define ulocimp_getLanguage U_ICU_ENTRY_POINT_RENAME(ulocimp_getLanguage)
+#define ulocimp_getScript U_ICU_ENTRY_POINT_RENAME(ulocimp_getScript)
+#define umsg_applyPattern U_ICU_ENTRY_POINT_RENAME(umsg_applyPattern)
+#define umsg_autoQuoteApostrophe U_ICU_ENTRY_POINT_RENAME(umsg_autoQuoteApostrophe)
+#define umsg_clone U_ICU_ENTRY_POINT_RENAME(umsg_clone)
+#define umsg_close U_ICU_ENTRY_POINT_RENAME(umsg_close)
+#define umsg_format U_ICU_ENTRY_POINT_RENAME(umsg_format)
+#define umsg_getLocale U_ICU_ENTRY_POINT_RENAME(umsg_getLocale)
+#define umsg_open U_ICU_ENTRY_POINT_RENAME(umsg_open)
+#define umsg_parse U_ICU_ENTRY_POINT_RENAME(umsg_parse)
+#define umsg_setLocale U_ICU_ENTRY_POINT_RENAME(umsg_setLocale)
+#define umsg_toPattern U_ICU_ENTRY_POINT_RENAME(umsg_toPattern)
+#define umsg_vformat U_ICU_ENTRY_POINT_RENAME(umsg_vformat)
+#define umsg_vparse U_ICU_ENTRY_POINT_RENAME(umsg_vparse)
+#define umtx_atomic_dec U_ICU_ENTRY_POINT_RENAME(umtx_atomic_dec)
+#define umtx_atomic_inc U_ICU_ENTRY_POINT_RENAME(umtx_atomic_inc)
+#define umtx_cleanup U_ICU_ENTRY_POINT_RENAME(umtx_cleanup)
+#define umtx_destroy U_ICU_ENTRY_POINT_RENAME(umtx_destroy)
+#define umtx_init U_ICU_ENTRY_POINT_RENAME(umtx_init)
+#define umtx_lock U_ICU_ENTRY_POINT_RENAME(umtx_lock)
+#define umtx_unlock U_ICU_ENTRY_POINT_RENAME(umtx_unlock)
+#define uniset_getUnicode32Instance U_ICU_ENTRY_POINT_RENAME(uniset_getUnicode32Instance)
+#define unorm2_append U_ICU_ENTRY_POINT_RENAME(unorm2_append)
+#define unorm2_close U_ICU_ENTRY_POINT_RENAME(unorm2_close)
+#define unorm2_getDecomposition U_ICU_ENTRY_POINT_RENAME(unorm2_getDecomposition)
+#define unorm2_getInstance U_ICU_ENTRY_POINT_RENAME(unorm2_getInstance)
+#define unorm2_hasBoundaryAfter U_ICU_ENTRY_POINT_RENAME(unorm2_hasBoundaryAfter)
+#define unorm2_hasBoundaryBefore U_ICU_ENTRY_POINT_RENAME(unorm2_hasBoundaryBefore)
+#define unorm2_isInert U_ICU_ENTRY_POINT_RENAME(unorm2_isInert)
+#define unorm2_isNormalized U_ICU_ENTRY_POINT_RENAME(unorm2_isNormalized)
+#define unorm2_normalize U_ICU_ENTRY_POINT_RENAME(unorm2_normalize)
+#define unorm2_normalizeSecondAndAppend U_ICU_ENTRY_POINT_RENAME(unorm2_normalizeSecondAndAppend)
+#define unorm2_openFiltered U_ICU_ENTRY_POINT_RENAME(unorm2_openFiltered)
+#define unorm2_quickCheck U_ICU_ENTRY_POINT_RENAME(unorm2_quickCheck)
+#define unorm2_spanQuickCheckYes U_ICU_ENTRY_POINT_RENAME(unorm2_spanQuickCheckYes)
+#define unorm2_swap U_ICU_ENTRY_POINT_RENAME(unorm2_swap)
+#define unorm_closeIter U_ICU_ENTRY_POINT_RENAME(unorm_closeIter)
+#define unorm_compare U_ICU_ENTRY_POINT_RENAME(unorm_compare)
+#define unorm_concatenate U_ICU_ENTRY_POINT_RENAME(unorm_concatenate)
+#define unorm_getFCDTrieIndex U_ICU_ENTRY_POINT_RENAME(unorm_getFCDTrieIndex)
+#define unorm_getQuickCheck U_ICU_ENTRY_POINT_RENAME(unorm_getQuickCheck)
+#define unorm_isNormalized U_ICU_ENTRY_POINT_RENAME(unorm_isNormalized)
+#define unorm_isNormalizedWithOptions U_ICU_ENTRY_POINT_RENAME(unorm_isNormalizedWithOptions)
+#define unorm_next U_ICU_ENTRY_POINT_RENAME(unorm_next)
+#define unorm_normalize U_ICU_ENTRY_POINT_RENAME(unorm_normalize)
+#define unorm_openIter U_ICU_ENTRY_POINT_RENAME(unorm_openIter)
+#define unorm_previous U_ICU_ENTRY_POINT_RENAME(unorm_previous)
+#define unorm_quickCheck U_ICU_ENTRY_POINT_RENAME(unorm_quickCheck)
+#define unorm_quickCheckWithOptions U_ICU_ENTRY_POINT_RENAME(unorm_quickCheckWithOptions)
+#define unorm_setIter U_ICU_ENTRY_POINT_RENAME(unorm_setIter)
+#define unum_applyPattern U_ICU_ENTRY_POINT_RENAME(unum_applyPattern)
+#define unum_clone U_ICU_ENTRY_POINT_RENAME(unum_clone)
+#define unum_close U_ICU_ENTRY_POINT_RENAME(unum_close)
+#define unum_countAvailable U_ICU_ENTRY_POINT_RENAME(unum_countAvailable)
+#define unum_format U_ICU_ENTRY_POINT_RENAME(unum_format)
+#define unum_formatDecimal U_ICU_ENTRY_POINT_RENAME(unum_formatDecimal)
+#define unum_formatDouble U_ICU_ENTRY_POINT_RENAME(unum_formatDouble)
+#define unum_formatDoubleCurrency U_ICU_ENTRY_POINT_RENAME(unum_formatDoubleCurrency)
+#define unum_formatInt64 U_ICU_ENTRY_POINT_RENAME(unum_formatInt64)
+#define unum_getAttribute U_ICU_ENTRY_POINT_RENAME(unum_getAttribute)
+#define unum_getAvailable U_ICU_ENTRY_POINT_RENAME(unum_getAvailable)
+#define unum_getDoubleAttribute U_ICU_ENTRY_POINT_RENAME(unum_getDoubleAttribute)
+#define unum_getLocaleByType U_ICU_ENTRY_POINT_RENAME(unum_getLocaleByType)
+#define unum_getSymbol U_ICU_ENTRY_POINT_RENAME(unum_getSymbol)
+#define unum_getTextAttribute U_ICU_ENTRY_POINT_RENAME(unum_getTextAttribute)
+#define unum_open U_ICU_ENTRY_POINT_RENAME(unum_open)
+#define unum_parse U_ICU_ENTRY_POINT_RENAME(unum_parse)
+#define unum_parseDecimal U_ICU_ENTRY_POINT_RENAME(unum_parseDecimal)
+#define unum_parseDouble U_ICU_ENTRY_POINT_RENAME(unum_parseDouble)
+#define unum_parseDoubleCurrency U_ICU_ENTRY_POINT_RENAME(unum_parseDoubleCurrency)
+#define unum_parseInt64 U_ICU_ENTRY_POINT_RENAME(unum_parseInt64)
+#define unum_setAttribute U_ICU_ENTRY_POINT_RENAME(unum_setAttribute)
+#define unum_setDoubleAttribute U_ICU_ENTRY_POINT_RENAME(unum_setDoubleAttribute)
+#define unum_setSymbol U_ICU_ENTRY_POINT_RENAME(unum_setSymbol)
+#define unum_setTextAttribute U_ICU_ENTRY_POINT_RENAME(unum_setTextAttribute)
+#define unum_toPattern U_ICU_ENTRY_POINT_RENAME(unum_toPattern)
+#define uplug_closeLibrary U_ICU_ENTRY_POINT_RENAME(uplug_closeLibrary)
+#define uplug_findLibrary U_ICU_ENTRY_POINT_RENAME(uplug_findLibrary)
+#define uplug_getConfiguration U_ICU_ENTRY_POINT_RENAME(uplug_getConfiguration)
+#define uplug_getContext U_ICU_ENTRY_POINT_RENAME(uplug_getContext)
+#define uplug_getCurrentLevel U_ICU_ENTRY_POINT_RENAME(uplug_getCurrentLevel)
+#define uplug_getLibrary U_ICU_ENTRY_POINT_RENAME(uplug_getLibrary)
+#define uplug_getLibraryName U_ICU_ENTRY_POINT_RENAME(uplug_getLibraryName)
+#define uplug_getPlugInternal U_ICU_ENTRY_POINT_RENAME(uplug_getPlugInternal)
+#define uplug_getPlugLevel U_ICU_ENTRY_POINT_RENAME(uplug_getPlugLevel)
+#define uplug_getPlugLoadStatus U_ICU_ENTRY_POINT_RENAME(uplug_getPlugLoadStatus)
+#define uplug_getPlugName U_ICU_ENTRY_POINT_RENAME(uplug_getPlugName)
+#define uplug_getPluginFile U_ICU_ENTRY_POINT_RENAME(uplug_getPluginFile)
+#define uplug_getSymbolName U_ICU_ENTRY_POINT_RENAME(uplug_getSymbolName)
+#define uplug_init U_ICU_ENTRY_POINT_RENAME(uplug_init)
+#define uplug_loadPlugFromEntrypoint U_ICU_ENTRY_POINT_RENAME(uplug_loadPlugFromEntrypoint)
+#define uplug_loadPlugFromLibrary U_ICU_ENTRY_POINT_RENAME(uplug_loadPlugFromLibrary)
+#define uplug_nextPlug U_ICU_ENTRY_POINT_RENAME(uplug_nextPlug)
+#define uplug_openLibrary U_ICU_ENTRY_POINT_RENAME(uplug_openLibrary)
+#define uplug_removePlug U_ICU_ENTRY_POINT_RENAME(uplug_removePlug)
+#define uplug_setContext U_ICU_ENTRY_POINT_RENAME(uplug_setContext)
+#define uplug_setPlugLevel U_ICU_ENTRY_POINT_RENAME(uplug_setPlugLevel)
+#define uplug_setPlugName U_ICU_ENTRY_POINT_RENAME(uplug_setPlugName)
+#define uplug_setPlugNoUnload U_ICU_ENTRY_POINT_RENAME(uplug_setPlugNoUnload)
+#define upname_swap U_ICU_ENTRY_POINT_RENAME(upname_swap)
+#define uprops_getSource U_ICU_ENTRY_POINT_RENAME(uprops_getSource)
+#define upropsvec_addPropertyStarts U_ICU_ENTRY_POINT_RENAME(upropsvec_addPropertyStarts)
+#define uprv_aestrncpy U_ICU_ENTRY_POINT_RENAME(uprv_aestrncpy)
+#define uprv_asciiFromEbcdic U_ICU_ENTRY_POINT_RENAME(uprv_asciiFromEbcdic)
+#define uprv_asciitolower U_ICU_ENTRY_POINT_RENAME(uprv_asciitolower)
+#define uprv_ceil U_ICU_ENTRY_POINT_RENAME(uprv_ceil)
+#define uprv_cnttab_addContraction U_ICU_ENTRY_POINT_RENAME(uprv_cnttab_addContraction)
+#define uprv_cnttab_changeContraction U_ICU_ENTRY_POINT_RENAME(uprv_cnttab_changeContraction)
+#define uprv_cnttab_changeLastCE U_ICU_ENTRY_POINT_RENAME(uprv_cnttab_changeLastCE)
+#define uprv_cnttab_clone U_ICU_ENTRY_POINT_RENAME(uprv_cnttab_clone)
+#define uprv_cnttab_close U_ICU_ENTRY_POINT_RENAME(uprv_cnttab_close)
+#define uprv_cnttab_constructTable U_ICU_ENTRY_POINT_RENAME(uprv_cnttab_constructTable)
+#define uprv_cnttab_findCE U_ICU_ENTRY_POINT_RENAME(uprv_cnttab_findCE)
+#define uprv_cnttab_findCP U_ICU_ENTRY_POINT_RENAME(uprv_cnttab_findCP)
+#define uprv_cnttab_getCE U_ICU_ENTRY_POINT_RENAME(uprv_cnttab_getCE)
+#define uprv_cnttab_insertContraction U_ICU_ENTRY_POINT_RENAME(uprv_cnttab_insertContraction)
+#define uprv_cnttab_isTailored U_ICU_ENTRY_POINT_RENAME(uprv_cnttab_isTailored)
+#define uprv_cnttab_open U_ICU_ENTRY_POINT_RENAME(uprv_cnttab_open)
+#define uprv_cnttab_setContraction U_ICU_ENTRY_POINT_RENAME(uprv_cnttab_setContraction)
+#define uprv_collIterateAtEnd U_ICU_ENTRY_POINT_RENAME(uprv_collIterateAtEnd)
+#define uprv_compareASCIIPropertyNames U_ICU_ENTRY_POINT_RENAME(uprv_compareASCIIPropertyNames)
+#define uprv_compareEBCDICPropertyNames U_ICU_ENTRY_POINT_RENAME(uprv_compareEBCDICPropertyNames)
+#define uprv_compareInvAscii U_ICU_ENTRY_POINT_RENAME(uprv_compareInvAscii)
+#define uprv_compareInvEbcdic U_ICU_ENTRY_POINT_RENAME(uprv_compareInvEbcdic)
+#define uprv_compareInvEbcdicAsAscii U_ICU_ENTRY_POINT_RENAME(uprv_compareInvEbcdicAsAscii)
+#define uprv_convertToLCID U_ICU_ENTRY_POINT_RENAME(uprv_convertToLCID)
+#define uprv_convertToPosix U_ICU_ENTRY_POINT_RENAME(uprv_convertToPosix)
+#define uprv_copyAscii U_ICU_ENTRY_POINT_RENAME(uprv_copyAscii)
+#define uprv_copyEbcdic U_ICU_ENTRY_POINT_RENAME(uprv_copyEbcdic)
+#define uprv_decContextClearStatus U_ICU_ENTRY_POINT_RENAME(uprv_decContextClearStatus)
+#define uprv_decContextDefault U_ICU_ENTRY_POINT_RENAME(uprv_decContextDefault)
+#define uprv_decContextGetRounding U_ICU_ENTRY_POINT_RENAME(uprv_decContextGetRounding)
+#define uprv_decContextGetStatus U_ICU_ENTRY_POINT_RENAME(uprv_decContextGetStatus)
+#define uprv_decContextRestoreStatus U_ICU_ENTRY_POINT_RENAME(uprv_decContextRestoreStatus)
+#define uprv_decContextSaveStatus U_ICU_ENTRY_POINT_RENAME(uprv_decContextSaveStatus)
+#define uprv_decContextSetRounding U_ICU_ENTRY_POINT_RENAME(uprv_decContextSetRounding)
+#define uprv_decContextSetStatus U_ICU_ENTRY_POINT_RENAME(uprv_decContextSetStatus)
+#define uprv_decContextSetStatusFromString U_ICU_ENTRY_POINT_RENAME(uprv_decContextSetStatusFromString)
+#define uprv_decContextSetStatusFromStringQuiet U_ICU_ENTRY_POINT_RENAME(uprv_decContextSetStatusFromStringQuiet)
+#define uprv_decContextSetStatusQuiet U_ICU_ENTRY_POINT_RENAME(uprv_decContextSetStatusQuiet)
+#define uprv_decContextStatusToString U_ICU_ENTRY_POINT_RENAME(uprv_decContextStatusToString)
+#define uprv_decContextTestEndian U_ICU_ENTRY_POINT_RENAME(uprv_decContextTestEndian)
+#define uprv_decContextTestSavedStatus U_ICU_ENTRY_POINT_RENAME(uprv_decContextTestSavedStatus)
+#define uprv_decContextTestStatus U_ICU_ENTRY_POINT_RENAME(uprv_decContextTestStatus)
+#define uprv_decContextZeroStatus U_ICU_ENTRY_POINT_RENAME(uprv_decContextZeroStatus)
+#define uprv_decNumberAbs U_ICU_ENTRY_POINT_RENAME(uprv_decNumberAbs)
+#define uprv_decNumberAdd U_ICU_ENTRY_POINT_RENAME(uprv_decNumberAdd)
+#define uprv_decNumberAnd U_ICU_ENTRY_POINT_RENAME(uprv_decNumberAnd)
+#define uprv_decNumberClass U_ICU_ENTRY_POINT_RENAME(uprv_decNumberClass)
+#define uprv_decNumberClassToString U_ICU_ENTRY_POINT_RENAME(uprv_decNumberClassToString)
+#define uprv_decNumberCompare U_ICU_ENTRY_POINT_RENAME(uprv_decNumberCompare)
+#define uprv_decNumberCompareSignal U_ICU_ENTRY_POINT_RENAME(uprv_decNumberCompareSignal)
+#define uprv_decNumberCompareTotal U_ICU_ENTRY_POINT_RENAME(uprv_decNumberCompareTotal)
+#define uprv_decNumberCompareTotalMag U_ICU_ENTRY_POINT_RENAME(uprv_decNumberCompareTotalMag)
+#define uprv_decNumberCopy U_ICU_ENTRY_POINT_RENAME(uprv_decNumberCopy)
+#define uprv_decNumberCopyAbs U_ICU_ENTRY_POINT_RENAME(uprv_decNumberCopyAbs)
+#define uprv_decNumberCopyNegate U_ICU_ENTRY_POINT_RENAME(uprv_decNumberCopyNegate)
+#define uprv_decNumberCopySign U_ICU_ENTRY_POINT_RENAME(uprv_decNumberCopySign)
+#define uprv_decNumberDivide U_ICU_ENTRY_POINT_RENAME(uprv_decNumberDivide)
+#define uprv_decNumberDivideInteger U_ICU_ENTRY_POINT_RENAME(uprv_decNumberDivideInteger)
+#define uprv_decNumberExp U_ICU_ENTRY_POINT_RENAME(uprv_decNumberExp)
+#define uprv_decNumberFMA U_ICU_ENTRY_POINT_RENAME(uprv_decNumberFMA)
+#define uprv_decNumberFromInt32 U_ICU_ENTRY_POINT_RENAME(uprv_decNumberFromInt32)
+#define uprv_decNumberFromString U_ICU_ENTRY_POINT_RENAME(uprv_decNumberFromString)
+#define uprv_decNumberFromUInt32 U_ICU_ENTRY_POINT_RENAME(uprv_decNumberFromUInt32)
+#define uprv_decNumberGetBCD U_ICU_ENTRY_POINT_RENAME(uprv_decNumberGetBCD)
+#define uprv_decNumberInvert U_ICU_ENTRY_POINT_RENAME(uprv_decNumberInvert)
+#define uprv_decNumberIsNormal U_ICU_ENTRY_POINT_RENAME(uprv_decNumberIsNormal)
+#define uprv_decNumberIsSubnormal U_ICU_ENTRY_POINT_RENAME(uprv_decNumberIsSubnormal)
+#define uprv_decNumberLn U_ICU_ENTRY_POINT_RENAME(uprv_decNumberLn)
+#define uprv_decNumberLog10 U_ICU_ENTRY_POINT_RENAME(uprv_decNumberLog10)
+#define uprv_decNumberLogB U_ICU_ENTRY_POINT_RENAME(uprv_decNumberLogB)
+#define uprv_decNumberMax U_ICU_ENTRY_POINT_RENAME(uprv_decNumberMax)
+#define uprv_decNumberMaxMag U_ICU_ENTRY_POINT_RENAME(uprv_decNumberMaxMag)
+#define uprv_decNumberMin U_ICU_ENTRY_POINT_RENAME(uprv_decNumberMin)
+#define uprv_decNumberMinMag U_ICU_ENTRY_POINT_RENAME(uprv_decNumberMinMag)
+#define uprv_decNumberMinus U_ICU_ENTRY_POINT_RENAME(uprv_decNumberMinus)
+#define uprv_decNumberMultiply U_ICU_ENTRY_POINT_RENAME(uprv_decNumberMultiply)
+#define uprv_decNumberNextMinus U_ICU_ENTRY_POINT_RENAME(uprv_decNumberNextMinus)
+#define uprv_decNumberNextPlus U_ICU_ENTRY_POINT_RENAME(uprv_decNumberNextPlus)
+#define uprv_decNumberNextToward U_ICU_ENTRY_POINT_RENAME(uprv_decNumberNextToward)
+#define uprv_decNumberNormalize U_ICU_ENTRY_POINT_RENAME(uprv_decNumberNormalize)
+#define uprv_decNumberOr U_ICU_ENTRY_POINT_RENAME(uprv_decNumberOr)
+#define uprv_decNumberPlus U_ICU_ENTRY_POINT_RENAME(uprv_decNumberPlus)
+#define uprv_decNumberPower U_ICU_ENTRY_POINT_RENAME(uprv_decNumberPower)
+#define uprv_decNumberQuantize U_ICU_ENTRY_POINT_RENAME(uprv_decNumberQuantize)
+#define uprv_decNumberReduce U_ICU_ENTRY_POINT_RENAME(uprv_decNumberReduce)
+#define uprv_decNumberRemainder U_ICU_ENTRY_POINT_RENAME(uprv_decNumberRemainder)
+#define uprv_decNumberRemainderNear U_ICU_ENTRY_POINT_RENAME(uprv_decNumberRemainderNear)
+#define uprv_decNumberRescale U_ICU_ENTRY_POINT_RENAME(uprv_decNumberRescale)
+#define uprv_decNumberRotate U_ICU_ENTRY_POINT_RENAME(uprv_decNumberRotate)
+#define uprv_decNumberSameQuantum U_ICU_ENTRY_POINT_RENAME(uprv_decNumberSameQuantum)
+#define uprv_decNumberScaleB U_ICU_ENTRY_POINT_RENAME(uprv_decNumberScaleB)
+#define uprv_decNumberSetBCD U_ICU_ENTRY_POINT_RENAME(uprv_decNumberSetBCD)
+#define uprv_decNumberShift U_ICU_ENTRY_POINT_RENAME(uprv_decNumberShift)
+#define uprv_decNumberSquareRoot U_ICU_ENTRY_POINT_RENAME(uprv_decNumberSquareRoot)
+#define uprv_decNumberSubtract U_ICU_ENTRY_POINT_RENAME(uprv_decNumberSubtract)
+#define uprv_decNumberToEngString U_ICU_ENTRY_POINT_RENAME(uprv_decNumberToEngString)
+#define uprv_decNumberToInt32 U_ICU_ENTRY_POINT_RENAME(uprv_decNumberToInt32)
+#define uprv_decNumberToIntegralExact U_ICU_ENTRY_POINT_RENAME(uprv_decNumberToIntegralExact)
+#define uprv_decNumberToIntegralValue U_ICU_ENTRY_POINT_RENAME(uprv_decNumberToIntegralValue)
+#define uprv_decNumberToString U_ICU_ENTRY_POINT_RENAME(uprv_decNumberToString)
+#define uprv_decNumberToUInt32 U_ICU_ENTRY_POINT_RENAME(uprv_decNumberToUInt32)
+#define uprv_decNumberTrim U_ICU_ENTRY_POINT_RENAME(uprv_decNumberTrim)
+#define uprv_decNumberVersion U_ICU_ENTRY_POINT_RENAME(uprv_decNumberVersion)
+#define uprv_decNumberXor U_ICU_ENTRY_POINT_RENAME(uprv_decNumberXor)
+#define uprv_decNumberZero U_ICU_ENTRY_POINT_RENAME(uprv_decNumberZero)
+#define uprv_delete_collIterate U_ICU_ENTRY_POINT_RENAME(uprv_delete_collIterate)
+#define uprv_dl_close U_ICU_ENTRY_POINT_RENAME(uprv_dl_close)
+#define uprv_dl_open U_ICU_ENTRY_POINT_RENAME(uprv_dl_open)
+#define uprv_dl_sym U_ICU_ENTRY_POINT_RENAME(uprv_dl_sym)
+#define uprv_eastrncpy U_ICU_ENTRY_POINT_RENAME(uprv_eastrncpy)
+#define uprv_ebcdicFromAscii U_ICU_ENTRY_POINT_RENAME(uprv_ebcdicFromAscii)
+#define uprv_ebcdictolower U_ICU_ENTRY_POINT_RENAME(uprv_ebcdictolower)
+#define uprv_fabs U_ICU_ENTRY_POINT_RENAME(uprv_fabs)
+#define uprv_floor U_ICU_ENTRY_POINT_RENAME(uprv_floor)
+#define uprv_fmax U_ICU_ENTRY_POINT_RENAME(uprv_fmax)
+#define uprv_fmin U_ICU_ENTRY_POINT_RENAME(uprv_fmin)
+#define uprv_fmod U_ICU_ENTRY_POINT_RENAME(uprv_fmod)
+#define uprv_free U_ICU_ENTRY_POINT_RENAME(uprv_free)
+#define uprv_getCharNameCharacters U_ICU_ENTRY_POINT_RENAME(uprv_getCharNameCharacters)
+#define uprv_getDefaultCodepage U_ICU_ENTRY_POINT_RENAME(uprv_getDefaultCodepage)
+#define uprv_getDefaultLocaleID U_ICU_ENTRY_POINT_RENAME(uprv_getDefaultLocaleID)
+#define uprv_getInfinity U_ICU_ENTRY_POINT_RENAME(uprv_getInfinity)
+#define uprv_getMaxCharNameLength U_ICU_ENTRY_POINT_RENAME(uprv_getMaxCharNameLength)
+#define uprv_getMaxValues U_ICU_ENTRY_POINT_RENAME(uprv_getMaxValues)
+#define uprv_getNaN U_ICU_ENTRY_POINT_RENAME(uprv_getNaN)
+#define uprv_getRawUTCtime U_ICU_ENTRY_POINT_RENAME(uprv_getRawUTCtime)
+#define uprv_getStaticCurrencyName U_ICU_ENTRY_POINT_RENAME(uprv_getStaticCurrencyName)
+#define uprv_getUTCtime U_ICU_ENTRY_POINT_RENAME(uprv_getUTCtime)
+#define uprv_haveProperties U_ICU_ENTRY_POINT_RENAME(uprv_haveProperties)
+#define uprv_init_collIterate U_ICU_ENTRY_POINT_RENAME(uprv_init_collIterate)
+#define uprv_init_pce U_ICU_ENTRY_POINT_RENAME(uprv_init_pce)
+#define uprv_int32Comparator U_ICU_ENTRY_POINT_RENAME(uprv_int32Comparator)
+#define uprv_isInfinite U_ICU_ENTRY_POINT_RENAME(uprv_isInfinite)
+#define uprv_isInvariantString U_ICU_ENTRY_POINT_RENAME(uprv_isInvariantString)
+#define uprv_isInvariantUString U_ICU_ENTRY_POINT_RENAME(uprv_isInvariantUString)
+#define uprv_isNaN U_ICU_ENTRY_POINT_RENAME(uprv_isNaN)
+#define uprv_isNegativeInfinity U_ICU_ENTRY_POINT_RENAME(uprv_isNegativeInfinity)
+#define uprv_isPositiveInfinity U_ICU_ENTRY_POINT_RENAME(uprv_isPositiveInfinity)
+#define uprv_isRuleWhiteSpace U_ICU_ENTRY_POINT_RENAME(uprv_isRuleWhiteSpace)
+#define uprv_itou U_ICU_ENTRY_POINT_RENAME(uprv_itou)
+#define uprv_log U_ICU_ENTRY_POINT_RENAME(uprv_log)
+#define uprv_malloc U_ICU_ENTRY_POINT_RENAME(uprv_malloc)
+#define uprv_mapFile U_ICU_ENTRY_POINT_RENAME(uprv_mapFile)
+#define uprv_max U_ICU_ENTRY_POINT_RENAME(uprv_max)
+#define uprv_maxMantissa U_ICU_ENTRY_POINT_RENAME(uprv_maxMantissa)
+#define uprv_maximumPtr U_ICU_ENTRY_POINT_RENAME(uprv_maximumPtr)
+#define uprv_min U_ICU_ENTRY_POINT_RENAME(uprv_min)
+#define uprv_modf U_ICU_ENTRY_POINT_RENAME(uprv_modf)
+#define uprv_new_collIterate U_ICU_ENTRY_POINT_RENAME(uprv_new_collIterate)
+#define uprv_openRuleWhiteSpaceSet U_ICU_ENTRY_POINT_RENAME(uprv_openRuleWhiteSpaceSet)
+#define uprv_parseCurrency U_ICU_ENTRY_POINT_RENAME(uprv_parseCurrency)
+#define uprv_pathIsAbsolute U_ICU_ENTRY_POINT_RENAME(uprv_pathIsAbsolute)
+#define uprv_pow U_ICU_ENTRY_POINT_RENAME(uprv_pow)
+#define uprv_pow10 U_ICU_ENTRY_POINT_RENAME(uprv_pow10)
+#define uprv_realloc U_ICU_ENTRY_POINT_RENAME(uprv_realloc)
+#define uprv_round U_ICU_ENTRY_POINT_RENAME(uprv_round)
+#define uprv_sortArray U_ICU_ENTRY_POINT_RENAME(uprv_sortArray)
+#define uprv_strCompare U_ICU_ENTRY_POINT_RENAME(uprv_strCompare)
+#define uprv_strdup U_ICU_ENTRY_POINT_RENAME(uprv_strdup)
+#define uprv_strndup U_ICU_ENTRY_POINT_RENAME(uprv_strndup)
+#define uprv_syntaxError U_ICU_ENTRY_POINT_RENAME(uprv_syntaxError)
+#define uprv_timezone U_ICU_ENTRY_POINT_RENAME(uprv_timezone)
+#define uprv_toupper U_ICU_ENTRY_POINT_RENAME(uprv_toupper)
+#define uprv_trunc U_ICU_ENTRY_POINT_RENAME(uprv_trunc)
+#define uprv_tzname U_ICU_ENTRY_POINT_RENAME(uprv_tzname)
+#define uprv_tzset U_ICU_ENTRY_POINT_RENAME(uprv_tzset)
+#define uprv_uca_addAnElement U_ICU_ENTRY_POINT_RENAME(uprv_uca_addAnElement)
+#define uprv_uca_assembleTable U_ICU_ENTRY_POINT_RENAME(uprv_uca_assembleTable)
+#define uprv_uca_canonicalClosure U_ICU_ENTRY_POINT_RENAME(uprv_uca_canonicalClosure)
+#define uprv_uca_closeTempTable U_ICU_ENTRY_POINT_RENAME(uprv_uca_closeTempTable)
+#define uprv_uca_getCodePointFromRaw U_ICU_ENTRY_POINT_RENAME(uprv_uca_getCodePointFromRaw)
+#define uprv_uca_getImplicitFromRaw U_ICU_ENTRY_POINT_RENAME(uprv_uca_getImplicitFromRaw)
+#define uprv_uca_getRawFromCodePoint U_ICU_ENTRY_POINT_RENAME(uprv_uca_getRawFromCodePoint)
+#define uprv_uca_getRawFromImplicit U_ICU_ENTRY_POINT_RENAME(uprv_uca_getRawFromImplicit)
+#define uprv_uca_initImplicitConstants U_ICU_ENTRY_POINT_RENAME(uprv_uca_initImplicitConstants)
+#define uprv_uca_initTempTable U_ICU_ENTRY_POINT_RENAME(uprv_uca_initTempTable)
+#define uprv_uint16Comparator U_ICU_ENTRY_POINT_RENAME(uprv_uint16Comparator)
+#define uprv_uint32Comparator U_ICU_ENTRY_POINT_RENAME(uprv_uint32Comparator)
+#define uprv_unmapFile U_ICU_ENTRY_POINT_RENAME(uprv_unmapFile)
+#define upvec_cloneArray U_ICU_ENTRY_POINT_RENAME(upvec_cloneArray)
+#define upvec_close U_ICU_ENTRY_POINT_RENAME(upvec_close)
+#define upvec_compact U_ICU_ENTRY_POINT_RENAME(upvec_compact)
+#define upvec_compactToUTrie2Handler U_ICU_ENTRY_POINT_RENAME(upvec_compactToUTrie2Handler)
+#define upvec_compactToUTrie2WithRowIndexes U_ICU_ENTRY_POINT_RENAME(upvec_compactToUTrie2WithRowIndexes)
+#define upvec_getArray U_ICU_ENTRY_POINT_RENAME(upvec_getArray)
+#define upvec_getRow U_ICU_ENTRY_POINT_RENAME(upvec_getRow)
+#define upvec_getValue U_ICU_ENTRY_POINT_RENAME(upvec_getValue)
+#define upvec_open U_ICU_ENTRY_POINT_RENAME(upvec_open)
+#define upvec_setValue U_ICU_ENTRY_POINT_RENAME(upvec_setValue)
+#define uregex_appendReplacement U_ICU_ENTRY_POINT_RENAME(uregex_appendReplacement)
+#define uregex_appendReplacementUText U_ICU_ENTRY_POINT_RENAME(uregex_appendReplacementUText)
+#define uregex_appendTail U_ICU_ENTRY_POINT_RENAME(uregex_appendTail)
+#define uregex_appendTailUText U_ICU_ENTRY_POINT_RENAME(uregex_appendTailUText)
+#define uregex_clone U_ICU_ENTRY_POINT_RENAME(uregex_clone)
+#define uregex_close U_ICU_ENTRY_POINT_RENAME(uregex_close)
+#define uregex_end U_ICU_ENTRY_POINT_RENAME(uregex_end)
+#define uregex_end64 U_ICU_ENTRY_POINT_RENAME(uregex_end64)
+#define uregex_find U_ICU_ENTRY_POINT_RENAME(uregex_find)
+#define uregex_find64 U_ICU_ENTRY_POINT_RENAME(uregex_find64)
+#define uregex_findNext U_ICU_ENTRY_POINT_RENAME(uregex_findNext)
+#define uregex_flags U_ICU_ENTRY_POINT_RENAME(uregex_flags)
+#define uregex_getFindProgressCallback U_ICU_ENTRY_POINT_RENAME(uregex_getFindProgressCallback)
+#define uregex_getMatchCallback U_ICU_ENTRY_POINT_RENAME(uregex_getMatchCallback)
+#define uregex_getStackLimit U_ICU_ENTRY_POINT_RENAME(uregex_getStackLimit)
+#define uregex_getText U_ICU_ENTRY_POINT_RENAME(uregex_getText)
+#define uregex_getTimeLimit U_ICU_ENTRY_POINT_RENAME(uregex_getTimeLimit)
+#define uregex_getUText U_ICU_ENTRY_POINT_RENAME(uregex_getUText)
+#define uregex_group U_ICU_ENTRY_POINT_RENAME(uregex_group)
+#define uregex_groupCount U_ICU_ENTRY_POINT_RENAME(uregex_groupCount)
+#define uregex_groupUText U_ICU_ENTRY_POINT_RENAME(uregex_groupUText)
+#define uregex_groupUTextDeep U_ICU_ENTRY_POINT_RENAME(uregex_groupUTextDeep)
+#define uregex_hasAnchoringBounds U_ICU_ENTRY_POINT_RENAME(uregex_hasAnchoringBounds)
+#define uregex_hasTransparentBounds U_ICU_ENTRY_POINT_RENAME(uregex_hasTransparentBounds)
+#define uregex_hitEnd U_ICU_ENTRY_POINT_RENAME(uregex_hitEnd)
+#define uregex_lookingAt U_ICU_ENTRY_POINT_RENAME(uregex_lookingAt)
+#define uregex_lookingAt64 U_ICU_ENTRY_POINT_RENAME(uregex_lookingAt64)
+#define uregex_matches U_ICU_ENTRY_POINT_RENAME(uregex_matches)
+#define uregex_matches64 U_ICU_ENTRY_POINT_RENAME(uregex_matches64)
+#define uregex_open U_ICU_ENTRY_POINT_RENAME(uregex_open)
+#define uregex_openC U_ICU_ENTRY_POINT_RENAME(uregex_openC)
+#define uregex_openUText U_ICU_ENTRY_POINT_RENAME(uregex_openUText)
+#define uregex_pattern U_ICU_ENTRY_POINT_RENAME(uregex_pattern)
+#define uregex_patternUText U_ICU_ENTRY_POINT_RENAME(uregex_patternUText)
+#define uregex_regionEnd U_ICU_ENTRY_POINT_RENAME(uregex_regionEnd)
+#define uregex_regionEnd64 U_ICU_ENTRY_POINT_RENAME(uregex_regionEnd64)
+#define uregex_regionStart U_ICU_ENTRY_POINT_RENAME(uregex_regionStart)
+#define uregex_regionStart64 U_ICU_ENTRY_POINT_RENAME(uregex_regionStart64)
+#define uregex_replaceAll U_ICU_ENTRY_POINT_RENAME(uregex_replaceAll)
+#define uregex_replaceAllUText U_ICU_ENTRY_POINT_RENAME(uregex_replaceAllUText)
+#define uregex_replaceFirst U_ICU_ENTRY_POINT_RENAME(uregex_replaceFirst)
+#define uregex_replaceFirstUText U_ICU_ENTRY_POINT_RENAME(uregex_replaceFirstUText)
+#define uregex_requireEnd U_ICU_ENTRY_POINT_RENAME(uregex_requireEnd)
+#define uregex_reset U_ICU_ENTRY_POINT_RENAME(uregex_reset)
+#define uregex_reset64 U_ICU_ENTRY_POINT_RENAME(uregex_reset64)
+#define uregex_setFindProgressCallback U_ICU_ENTRY_POINT_RENAME(uregex_setFindProgressCallback)
+#define uregex_setMatchCallback U_ICU_ENTRY_POINT_RENAME(uregex_setMatchCallback)
+#define uregex_setRegion U_ICU_ENTRY_POINT_RENAME(uregex_setRegion)
+#define uregex_setRegion64 U_ICU_ENTRY_POINT_RENAME(uregex_setRegion64)
+#define uregex_setRegionAndStart U_ICU_ENTRY_POINT_RENAME(uregex_setRegionAndStart)
+#define uregex_setStackLimit U_ICU_ENTRY_POINT_RENAME(uregex_setStackLimit)
+#define uregex_setText U_ICU_ENTRY_POINT_RENAME(uregex_setText)
+#define uregex_setTimeLimit U_ICU_ENTRY_POINT_RENAME(uregex_setTimeLimit)
+#define uregex_setUText U_ICU_ENTRY_POINT_RENAME(uregex_setUText)
+#define uregex_split U_ICU_ENTRY_POINT_RENAME(uregex_split)
+#define uregex_splitUText U_ICU_ENTRY_POINT_RENAME(uregex_splitUText)
+#define uregex_start U_ICU_ENTRY_POINT_RENAME(uregex_start)
+#define uregex_start64 U_ICU_ENTRY_POINT_RENAME(uregex_start64)
+#define uregex_ucstr_unescape_charAt U_ICU_ENTRY_POINT_RENAME(uregex_ucstr_unescape_charAt)
+#define uregex_useAnchoringBounds U_ICU_ENTRY_POINT_RENAME(uregex_useAnchoringBounds)
+#define uregex_useTransparentBounds U_ICU_ENTRY_POINT_RENAME(uregex_useTransparentBounds)
+#define uregex_utext_unescape_charAt U_ICU_ENTRY_POINT_RENAME(uregex_utext_unescape_charAt)
+#define ures_close U_ICU_ENTRY_POINT_RENAME(ures_close)
+#define ures_copyResb U_ICU_ENTRY_POINT_RENAME(ures_copyResb)
+#define ures_countArrayItems U_ICU_ENTRY_POINT_RENAME(ures_countArrayItems)
+#define ures_findResource U_ICU_ENTRY_POINT_RENAME(ures_findResource)
+#define ures_findSubResource U_ICU_ENTRY_POINT_RENAME(ures_findSubResource)
+#define ures_getBinary U_ICU_ENTRY_POINT_RENAME(ures_getBinary)
+#define ures_getByIndex U_ICU_ENTRY_POINT_RENAME(ures_getByIndex)
+#define ures_getByKey U_ICU_ENTRY_POINT_RENAME(ures_getByKey)
+#define ures_getByKeyWithFallback U_ICU_ENTRY_POINT_RENAME(ures_getByKeyWithFallback)
+#define ures_getFunctionalEquivalent U_ICU_ENTRY_POINT_RENAME(ures_getFunctionalEquivalent)
+#define ures_getInt U_ICU_ENTRY_POINT_RENAME(ures_getInt)
+#define ures_getIntVector U_ICU_ENTRY_POINT_RENAME(ures_getIntVector)
+#define ures_getKey U_ICU_ENTRY_POINT_RENAME(ures_getKey)
+#define ures_getKeywordValues U_ICU_ENTRY_POINT_RENAME(ures_getKeywordValues)
+#define ures_getLocale U_ICU_ENTRY_POINT_RENAME(ures_getLocale)
+#define ures_getLocaleByType U_ICU_ENTRY_POINT_RENAME(ures_getLocaleByType)
+#define ures_getLocaleInternal U_ICU_ENTRY_POINT_RENAME(ures_getLocaleInternal)
+#define ures_getName U_ICU_ENTRY_POINT_RENAME(ures_getName)
+#define ures_getNextResource U_ICU_ENTRY_POINT_RENAME(ures_getNextResource)
+#define ures_getNextString U_ICU_ENTRY_POINT_RENAME(ures_getNextString)
+#define ures_getSize U_ICU_ENTRY_POINT_RENAME(ures_getSize)
+#define ures_getString U_ICU_ENTRY_POINT_RENAME(ures_getString)
+#define ures_getStringByIndex U_ICU_ENTRY_POINT_RENAME(ures_getStringByIndex)
+#define ures_getStringByKey U_ICU_ENTRY_POINT_RENAME(ures_getStringByKey)
+#define ures_getStringByKeyWithFallback U_ICU_ENTRY_POINT_RENAME(ures_getStringByKeyWithFallback)
+#define ures_getType U_ICU_ENTRY_POINT_RENAME(ures_getType)
+#define ures_getUInt U_ICU_ENTRY_POINT_RENAME(ures_getUInt)
+#define ures_getUTF8String U_ICU_ENTRY_POINT_RENAME(ures_getUTF8String)
+#define ures_getUTF8StringByIndex U_ICU_ENTRY_POINT_RENAME(ures_getUTF8StringByIndex)
+#define ures_getUTF8StringByKey U_ICU_ENTRY_POINT_RENAME(ures_getUTF8StringByKey)
+#define ures_getVersion U_ICU_ENTRY_POINT_RENAME(ures_getVersion)
+#define ures_getVersionByKey U_ICU_ENTRY_POINT_RENAME(ures_getVersionByKey)
+#define ures_getVersionNumber U_ICU_ENTRY_POINT_RENAME(ures_getVersionNumber)
+#define ures_getVersionNumberInternal U_ICU_ENTRY_POINT_RENAME(ures_getVersionNumberInternal)
+#define ures_hasNext U_ICU_ENTRY_POINT_RENAME(ures_hasNext)
+#define ures_initStackObject U_ICU_ENTRY_POINT_RENAME(ures_initStackObject)
+#define ures_open U_ICU_ENTRY_POINT_RENAME(ures_open)
+#define ures_openAvailableLocales U_ICU_ENTRY_POINT_RENAME(ures_openAvailableLocales)
+#define ures_openDirect U_ICU_ENTRY_POINT_RENAME(ures_openDirect)
+#define ures_openFillIn U_ICU_ENTRY_POINT_RENAME(ures_openFillIn)
+#define ures_openU U_ICU_ENTRY_POINT_RENAME(ures_openU)
+#define ures_resetIterator U_ICU_ENTRY_POINT_RENAME(ures_resetIterator)
+#define ures_swap U_ICU_ENTRY_POINT_RENAME(ures_swap)
+#define uscript_closeRun U_ICU_ENTRY_POINT_RENAME(uscript_closeRun)
+#define uscript_getCode U_ICU_ENTRY_POINT_RENAME(uscript_getCode)
+#define uscript_getName U_ICU_ENTRY_POINT_RENAME(uscript_getName)
+#define uscript_getScript U_ICU_ENTRY_POINT_RENAME(uscript_getScript)
+#define uscript_getScriptExtensions U_ICU_ENTRY_POINT_RENAME(uscript_getScriptExtensions)
+#define uscript_getShortName U_ICU_ENTRY_POINT_RENAME(uscript_getShortName)
+#define uscript_hasScript U_ICU_ENTRY_POINT_RENAME(uscript_hasScript)
+#define uscript_nextRun U_ICU_ENTRY_POINT_RENAME(uscript_nextRun)
+#define uscript_openRun U_ICU_ENTRY_POINT_RENAME(uscript_openRun)
+#define uscript_resetRun U_ICU_ENTRY_POINT_RENAME(uscript_resetRun)
+#define uscript_setRunText U_ICU_ENTRY_POINT_RENAME(uscript_setRunText)
+#define usearch_close U_ICU_ENTRY_POINT_RENAME(usearch_close)
+#define usearch_first U_ICU_ENTRY_POINT_RENAME(usearch_first)
+#define usearch_following U_ICU_ENTRY_POINT_RENAME(usearch_following)
+#define usearch_getAttribute U_ICU_ENTRY_POINT_RENAME(usearch_getAttribute)
+#define usearch_getBreakIterator U_ICU_ENTRY_POINT_RENAME(usearch_getBreakIterator)
+#define usearch_getCollator U_ICU_ENTRY_POINT_RENAME(usearch_getCollator)
+#define usearch_getMatchedLength U_ICU_ENTRY_POINT_RENAME(usearch_getMatchedLength)
+#define usearch_getMatchedStart U_ICU_ENTRY_POINT_RENAME(usearch_getMatchedStart)
+#define usearch_getMatchedText U_ICU_ENTRY_POINT_RENAME(usearch_getMatchedText)
+#define usearch_getOffset U_ICU_ENTRY_POINT_RENAME(usearch_getOffset)
+#define usearch_getPattern U_ICU_ENTRY_POINT_RENAME(usearch_getPattern)
+#define usearch_getText U_ICU_ENTRY_POINT_RENAME(usearch_getText)
+#define usearch_handleNextCanonical U_ICU_ENTRY_POINT_RENAME(usearch_handleNextCanonical)
+#define usearch_handleNextExact U_ICU_ENTRY_POINT_RENAME(usearch_handleNextExact)
+#define usearch_handlePreviousCanonical U_ICU_ENTRY_POINT_RENAME(usearch_handlePreviousCanonical)
+#define usearch_handlePreviousExact U_ICU_ENTRY_POINT_RENAME(usearch_handlePreviousExact)
+#define usearch_last U_ICU_ENTRY_POINT_RENAME(usearch_last)
+#define usearch_next U_ICU_ENTRY_POINT_RENAME(usearch_next)
+#define usearch_open U_ICU_ENTRY_POINT_RENAME(usearch_open)
+#define usearch_openFromCollator U_ICU_ENTRY_POINT_RENAME(usearch_openFromCollator)
+#define usearch_preceding U_ICU_ENTRY_POINT_RENAME(usearch_preceding)
+#define usearch_previous U_ICU_ENTRY_POINT_RENAME(usearch_previous)
+#define usearch_reset U_ICU_ENTRY_POINT_RENAME(usearch_reset)
+#define usearch_search U_ICU_ENTRY_POINT_RENAME(usearch_search)
+#define usearch_searchBackwards U_ICU_ENTRY_POINT_RENAME(usearch_searchBackwards)
+#define usearch_setAttribute U_ICU_ENTRY_POINT_RENAME(usearch_setAttribute)
+#define usearch_setBreakIterator U_ICU_ENTRY_POINT_RENAME(usearch_setBreakIterator)
+#define usearch_setCollator U_ICU_ENTRY_POINT_RENAME(usearch_setCollator)
+#define usearch_setOffset U_ICU_ENTRY_POINT_RENAME(usearch_setOffset)
+#define usearch_setPattern U_ICU_ENTRY_POINT_RENAME(usearch_setPattern)
+#define usearch_setText U_ICU_ENTRY_POINT_RENAME(usearch_setText)
+#define uset_add U_ICU_ENTRY_POINT_RENAME(uset_add)
+#define uset_addAll U_ICU_ENTRY_POINT_RENAME(uset_addAll)
+#define uset_addAllCodePoints U_ICU_ENTRY_POINT_RENAME(uset_addAllCodePoints)
+#define uset_addRange U_ICU_ENTRY_POINT_RENAME(uset_addRange)
+#define uset_addString U_ICU_ENTRY_POINT_RENAME(uset_addString)
+#define uset_applyIntPropertyValue U_ICU_ENTRY_POINT_RENAME(uset_applyIntPropertyValue)
+#define uset_applyPattern U_ICU_ENTRY_POINT_RENAME(uset_applyPattern)
+#define uset_applyPropertyAlias U_ICU_ENTRY_POINT_RENAME(uset_applyPropertyAlias)
+#define uset_charAt U_ICU_ENTRY_POINT_RENAME(uset_charAt)
+#define uset_clear U_ICU_ENTRY_POINT_RENAME(uset_clear)
+#define uset_clone U_ICU_ENTRY_POINT_RENAME(uset_clone)
+#define uset_cloneAsThawed U_ICU_ENTRY_POINT_RENAME(uset_cloneAsThawed)
+#define uset_close U_ICU_ENTRY_POINT_RENAME(uset_close)
+#define uset_closeOver U_ICU_ENTRY_POINT_RENAME(uset_closeOver)
+#define uset_compact U_ICU_ENTRY_POINT_RENAME(uset_compact)
+#define uset_complement U_ICU_ENTRY_POINT_RENAME(uset_complement)
+#define uset_complementAll U_ICU_ENTRY_POINT_RENAME(uset_complementAll)
+#define uset_contains U_ICU_ENTRY_POINT_RENAME(uset_contains)
+#define uset_containsAll U_ICU_ENTRY_POINT_RENAME(uset_containsAll)
+#define uset_containsAllCodePoints U_ICU_ENTRY_POINT_RENAME(uset_containsAllCodePoints)
+#define uset_containsNone U_ICU_ENTRY_POINT_RENAME(uset_containsNone)
+#define uset_containsRange U_ICU_ENTRY_POINT_RENAME(uset_containsRange)
+#define uset_containsSome U_ICU_ENTRY_POINT_RENAME(uset_containsSome)
+#define uset_containsString U_ICU_ENTRY_POINT_RENAME(uset_containsString)
+#define uset_equals U_ICU_ENTRY_POINT_RENAME(uset_equals)
+#define uset_freeze U_ICU_ENTRY_POINT_RENAME(uset_freeze)
+#define uset_getItem U_ICU_ENTRY_POINT_RENAME(uset_getItem)
+#define uset_getItemCount U_ICU_ENTRY_POINT_RENAME(uset_getItemCount)
+#define uset_getSerializedRange U_ICU_ENTRY_POINT_RENAME(uset_getSerializedRange)
+#define uset_getSerializedRangeCount U_ICU_ENTRY_POINT_RENAME(uset_getSerializedRangeCount)
+#define uset_getSerializedSet U_ICU_ENTRY_POINT_RENAME(uset_getSerializedSet)
+#define uset_indexOf U_ICU_ENTRY_POINT_RENAME(uset_indexOf)
+#define uset_isEmpty U_ICU_ENTRY_POINT_RENAME(uset_isEmpty)
+#define uset_isFrozen U_ICU_ENTRY_POINT_RENAME(uset_isFrozen)
+#define uset_open U_ICU_ENTRY_POINT_RENAME(uset_open)
+#define uset_openEmpty U_ICU_ENTRY_POINT_RENAME(uset_openEmpty)
+#define uset_openPattern U_ICU_ENTRY_POINT_RENAME(uset_openPattern)
+#define uset_openPatternOptions U_ICU_ENTRY_POINT_RENAME(uset_openPatternOptions)
+#define uset_remove U_ICU_ENTRY_POINT_RENAME(uset_remove)
+#define uset_removeAll U_ICU_ENTRY_POINT_RENAME(uset_removeAll)
+#define uset_removeAllStrings U_ICU_ENTRY_POINT_RENAME(uset_removeAllStrings)
+#define uset_removeRange U_ICU_ENTRY_POINT_RENAME(uset_removeRange)
+#define uset_removeString U_ICU_ENTRY_POINT_RENAME(uset_removeString)
+#define uset_resemblesPattern U_ICU_ENTRY_POINT_RENAME(uset_resemblesPattern)
+#define uset_retain U_ICU_ENTRY_POINT_RENAME(uset_retain)
+#define uset_retainAll U_ICU_ENTRY_POINT_RENAME(uset_retainAll)
+#define uset_serialize U_ICU_ENTRY_POINT_RENAME(uset_serialize)
+#define uset_serializedContains U_ICU_ENTRY_POINT_RENAME(uset_serializedContains)
+#define uset_set U_ICU_ENTRY_POINT_RENAME(uset_set)
+#define uset_setSerializedToOne U_ICU_ENTRY_POINT_RENAME(uset_setSerializedToOne)
+#define uset_size U_ICU_ENTRY_POINT_RENAME(uset_size)
+#define uset_span U_ICU_ENTRY_POINT_RENAME(uset_span)
+#define uset_spanBack U_ICU_ENTRY_POINT_RENAME(uset_spanBack)
+#define uset_spanBackUTF8 U_ICU_ENTRY_POINT_RENAME(uset_spanBackUTF8)
+#define uset_spanUTF8 U_ICU_ENTRY_POINT_RENAME(uset_spanUTF8)
+#define uset_toPattern U_ICU_ENTRY_POINT_RENAME(uset_toPattern)
+#define uspoof_areConfusable U_ICU_ENTRY_POINT_RENAME(uspoof_areConfusable)
+#define uspoof_areConfusableUTF8 U_ICU_ENTRY_POINT_RENAME(uspoof_areConfusableUTF8)
+#define uspoof_areConfusableUnicodeString U_ICU_ENTRY_POINT_RENAME(uspoof_areConfusableUnicodeString)
+#define uspoof_check U_ICU_ENTRY_POINT_RENAME(uspoof_check)
+#define uspoof_checkUTF8 U_ICU_ENTRY_POINT_RENAME(uspoof_checkUTF8)
+#define uspoof_checkUnicodeString U_ICU_ENTRY_POINT_RENAME(uspoof_checkUnicodeString)
+#define uspoof_clone U_ICU_ENTRY_POINT_RENAME(uspoof_clone)
+#define uspoof_close U_ICU_ENTRY_POINT_RENAME(uspoof_close)
+#define uspoof_getAllowedChars U_ICU_ENTRY_POINT_RENAME(uspoof_getAllowedChars)
+#define uspoof_getAllowedLocales U_ICU_ENTRY_POINT_RENAME(uspoof_getAllowedLocales)
+#define uspoof_getAllowedUnicodeSet U_ICU_ENTRY_POINT_RENAME(uspoof_getAllowedUnicodeSet)
+#define uspoof_getChecks U_ICU_ENTRY_POINT_RENAME(uspoof_getChecks)
+#define uspoof_getSkeleton U_ICU_ENTRY_POINT_RENAME(uspoof_getSkeleton)
+#define uspoof_getSkeletonUTF8 U_ICU_ENTRY_POINT_RENAME(uspoof_getSkeletonUTF8)
+#define uspoof_getSkeletonUnicodeString U_ICU_ENTRY_POINT_RENAME(uspoof_getSkeletonUnicodeString)
+#define uspoof_open U_ICU_ENTRY_POINT_RENAME(uspoof_open)
+#define uspoof_openFromSerialized U_ICU_ENTRY_POINT_RENAME(uspoof_openFromSerialized)
+#define uspoof_openFromSource U_ICU_ENTRY_POINT_RENAME(uspoof_openFromSource)
+#define uspoof_serialize U_ICU_ENTRY_POINT_RENAME(uspoof_serialize)
+#define uspoof_setAllowedChars U_ICU_ENTRY_POINT_RENAME(uspoof_setAllowedChars)
+#define uspoof_setAllowedLocales U_ICU_ENTRY_POINT_RENAME(uspoof_setAllowedLocales)
+#define uspoof_setAllowedUnicodeSet U_ICU_ENTRY_POINT_RENAME(uspoof_setAllowedUnicodeSet)
+#define uspoof_setChecks U_ICU_ENTRY_POINT_RENAME(uspoof_setChecks)
+#define uspoof_swap U_ICU_ENTRY_POINT_RENAME(uspoof_swap)
+#define usprep_close U_ICU_ENTRY_POINT_RENAME(usprep_close)
+#define usprep_open U_ICU_ENTRY_POINT_RENAME(usprep_open)
+#define usprep_openByType U_ICU_ENTRY_POINT_RENAME(usprep_openByType)
+#define usprep_prepare U_ICU_ENTRY_POINT_RENAME(usprep_prepare)
+#define usprep_swap U_ICU_ENTRY_POINT_RENAME(usprep_swap)
+#define ustr_foldCase U_ICU_ENTRY_POINT_RENAME(ustr_foldCase)
+#define ustr_toLower U_ICU_ENTRY_POINT_RENAME(ustr_toLower)
+#define ustr_toTitle U_ICU_ENTRY_POINT_RENAME(ustr_toTitle)
+#define ustr_toUpper U_ICU_ENTRY_POINT_RENAME(ustr_toUpper)
+#define utext_caseCompare U_ICU_ENTRY_POINT_RENAME(utext_caseCompare)
+#define utext_caseCompareNativeLimit U_ICU_ENTRY_POINT_RENAME(utext_caseCompareNativeLimit)
+#define utext_char32At U_ICU_ENTRY_POINT_RENAME(utext_char32At)
+#define utext_clone U_ICU_ENTRY_POINT_RENAME(utext_clone)
+#define utext_close U_ICU_ENTRY_POINT_RENAME(utext_close)
+#define utext_compare U_ICU_ENTRY_POINT_RENAME(utext_compare)
+#define utext_compareNativeLimit U_ICU_ENTRY_POINT_RENAME(utext_compareNativeLimit)
+#define utext_copy U_ICU_ENTRY_POINT_RENAME(utext_copy)
+#define utext_current32 U_ICU_ENTRY_POINT_RENAME(utext_current32)
+#define utext_equals U_ICU_ENTRY_POINT_RENAME(utext_equals)
+#define utext_extract U_ICU_ENTRY_POINT_RENAME(utext_extract)
+#define utext_freeze U_ICU_ENTRY_POINT_RENAME(utext_freeze)
+#define utext_getNativeIndex U_ICU_ENTRY_POINT_RENAME(utext_getNativeIndex)
+#define utext_getPreviousNativeIndex U_ICU_ENTRY_POINT_RENAME(utext_getPreviousNativeIndex)
+#define utext_hasMetaData U_ICU_ENTRY_POINT_RENAME(utext_hasMetaData)
+#define utext_isLengthExpensive U_ICU_ENTRY_POINT_RENAME(utext_isLengthExpensive)
+#define utext_isWritable U_ICU_ENTRY_POINT_RENAME(utext_isWritable)
+#define utext_moveIndex32 U_ICU_ENTRY_POINT_RENAME(utext_moveIndex32)
+#define utext_nativeLength U_ICU_ENTRY_POINT_RENAME(utext_nativeLength)
+#define utext_next32 U_ICU_ENTRY_POINT_RENAME(utext_next32)
+#define utext_next32From U_ICU_ENTRY_POINT_RENAME(utext_next32From)
+#define utext_openCharacterIterator U_ICU_ENTRY_POINT_RENAME(utext_openCharacterIterator)
+#define utext_openConstUnicodeString U_ICU_ENTRY_POINT_RENAME(utext_openConstUnicodeString)
+#define utext_openReplaceable U_ICU_ENTRY_POINT_RENAME(utext_openReplaceable)
+#define utext_openUChars U_ICU_ENTRY_POINT_RENAME(utext_openUChars)
+#define utext_openUTF8 U_ICU_ENTRY_POINT_RENAME(utext_openUTF8)
+#define utext_openUnicodeString U_ICU_ENTRY_POINT_RENAME(utext_openUnicodeString)
+#define utext_previous32 U_ICU_ENTRY_POINT_RENAME(utext_previous32)
+#define utext_previous32From U_ICU_ENTRY_POINT_RENAME(utext_previous32From)
+#define utext_replace U_ICU_ENTRY_POINT_RENAME(utext_replace)
+#define utext_setNativeIndex U_ICU_ENTRY_POINT_RENAME(utext_setNativeIndex)
+#define utext_setup U_ICU_ENTRY_POINT_RENAME(utext_setup)
+#define utf8_appendCharSafeBody U_ICU_ENTRY_POINT_RENAME(utf8_appendCharSafeBody)
+#define utf8_back1SafeBody U_ICU_ENTRY_POINT_RENAME(utf8_back1SafeBody)
+#define utf8_countTrailBytes U_ICU_ENTRY_POINT_RENAME(utf8_countTrailBytes)
+#define utf8_nextCharSafeBody U_ICU_ENTRY_POINT_RENAME(utf8_nextCharSafeBody)
+#define utf8_prevCharSafeBody U_ICU_ENTRY_POINT_RENAME(utf8_prevCharSafeBody)
+#define utmscale_fromInt64 U_ICU_ENTRY_POINT_RENAME(utmscale_fromInt64)
+#define utmscale_getTimeScaleValue U_ICU_ENTRY_POINT_RENAME(utmscale_getTimeScaleValue)
+#define utmscale_toInt64 U_ICU_ENTRY_POINT_RENAME(utmscale_toInt64)
+#define utrace_cleanup U_ICU_ENTRY_POINT_RENAME(utrace_cleanup)
+#define utrace_data U_ICU_ENTRY_POINT_RENAME(utrace_data)
+#define utrace_entry U_ICU_ENTRY_POINT_RENAME(utrace_entry)
+#define utrace_exit U_ICU_ENTRY_POINT_RENAME(utrace_exit)
+#define utrace_format U_ICU_ENTRY_POINT_RENAME(utrace_format)
+#define utrace_functionName U_ICU_ENTRY_POINT_RENAME(utrace_functionName)
+#define utrace_getFunctions U_ICU_ENTRY_POINT_RENAME(utrace_getFunctions)
+#define utrace_getLevel U_ICU_ENTRY_POINT_RENAME(utrace_getLevel)
+#define utrace_level U_ICU_ENTRY_POINT_RENAME(utrace_level)
+#define utrace_setFunctions U_ICU_ENTRY_POINT_RENAME(utrace_setFunctions)
+#define utrace_setLevel U_ICU_ENTRY_POINT_RENAME(utrace_setLevel)
+#define utrace_vformat U_ICU_ENTRY_POINT_RENAME(utrace_vformat)
+#define utrans_clone U_ICU_ENTRY_POINT_RENAME(utrans_clone)
+#define utrans_close U_ICU_ENTRY_POINT_RENAME(utrans_close)
+#define utrans_countAvailableIDs U_ICU_ENTRY_POINT_RENAME(utrans_countAvailableIDs)
+#define utrans_getAvailableID U_ICU_ENTRY_POINT_RENAME(utrans_getAvailableID)
+#define utrans_getID U_ICU_ENTRY_POINT_RENAME(utrans_getID)
+#define utrans_getUnicodeID U_ICU_ENTRY_POINT_RENAME(utrans_getUnicodeID)
+#define utrans_open U_ICU_ENTRY_POINT_RENAME(utrans_open)
+#define utrans_openIDs U_ICU_ENTRY_POINT_RENAME(utrans_openIDs)
+#define utrans_openInverse U_ICU_ENTRY_POINT_RENAME(utrans_openInverse)
+#define utrans_openU U_ICU_ENTRY_POINT_RENAME(utrans_openU)
+#define utrans_register U_ICU_ENTRY_POINT_RENAME(utrans_register)
+#define utrans_rep_caseContextIterator U_ICU_ENTRY_POINT_RENAME(utrans_rep_caseContextIterator)
+#define utrans_setFilter U_ICU_ENTRY_POINT_RENAME(utrans_setFilter)
+#define utrans_stripRules U_ICU_ENTRY_POINT_RENAME(utrans_stripRules)
+#define utrans_trans U_ICU_ENTRY_POINT_RENAME(utrans_trans)
+#define utrans_transIncremental U_ICU_ENTRY_POINT_RENAME(utrans_transIncremental)
+#define utrans_transIncrementalUChars U_ICU_ENTRY_POINT_RENAME(utrans_transIncrementalUChars)
+#define utrans_transUChars U_ICU_ENTRY_POINT_RENAME(utrans_transUChars)
+#define utrans_transliterator_cleanup U_ICU_ENTRY_POINT_RENAME(utrans_transliterator_cleanup)
+#define utrans_unregister U_ICU_ENTRY_POINT_RENAME(utrans_unregister)
+#define utrans_unregisterID U_ICU_ENTRY_POINT_RENAME(utrans_unregisterID)
+#define utrie2_clone U_ICU_ENTRY_POINT_RENAME(utrie2_clone)
+#define utrie2_cloneAsThawed U_ICU_ENTRY_POINT_RENAME(utrie2_cloneAsThawed)
+#define utrie2_close U_ICU_ENTRY_POINT_RENAME(utrie2_close)
+#define utrie2_enum U_ICU_ENTRY_POINT_RENAME(utrie2_enum)
+#define utrie2_enumForLeadSurrogate U_ICU_ENTRY_POINT_RENAME(utrie2_enumForLeadSurrogate)
+#define utrie2_freeze U_ICU_ENTRY_POINT_RENAME(utrie2_freeze)
+#define utrie2_fromUTrie U_ICU_ENTRY_POINT_RENAME(utrie2_fromUTrie)
+#define utrie2_get32 U_ICU_ENTRY_POINT_RENAME(utrie2_get32)
+#define utrie2_get32FromLeadSurrogateCodeUnit U_ICU_ENTRY_POINT_RENAME(utrie2_get32FromLeadSurrogateCodeUnit)
+#define utrie2_getVersion U_ICU_ENTRY_POINT_RENAME(utrie2_getVersion)
+#define utrie2_internalU8NextIndex U_ICU_ENTRY_POINT_RENAME(utrie2_internalU8NextIndex)
+#define utrie2_internalU8PrevIndex U_ICU_ENTRY_POINT_RENAME(utrie2_internalU8PrevIndex)
+#define utrie2_isFrozen U_ICU_ENTRY_POINT_RENAME(utrie2_isFrozen)
+#define utrie2_open U_ICU_ENTRY_POINT_RENAME(utrie2_open)
+#define utrie2_openDummy U_ICU_ENTRY_POINT_RENAME(utrie2_openDummy)
+#define utrie2_openFromSerialized U_ICU_ENTRY_POINT_RENAME(utrie2_openFromSerialized)
+#define utrie2_serialize U_ICU_ENTRY_POINT_RENAME(utrie2_serialize)
+#define utrie2_set32 U_ICU_ENTRY_POINT_RENAME(utrie2_set32)
+#define utrie2_set32ForLeadSurrogateCodeUnit U_ICU_ENTRY_POINT_RENAME(utrie2_set32ForLeadSurrogateCodeUnit)
+#define utrie2_setRange32 U_ICU_ENTRY_POINT_RENAME(utrie2_setRange32)
+#define utrie2_swap U_ICU_ENTRY_POINT_RENAME(utrie2_swap)
+#define utrie2_swapAnyVersion U_ICU_ENTRY_POINT_RENAME(utrie2_swapAnyVersion)
+#define utrie_clone U_ICU_ENTRY_POINT_RENAME(utrie_clone)
+#define utrie_close U_ICU_ENTRY_POINT_RENAME(utrie_close)
+#define utrie_defaultGetFoldingOffset U_ICU_ENTRY_POINT_RENAME(utrie_defaultGetFoldingOffset)
+#define utrie_enum U_ICU_ENTRY_POINT_RENAME(utrie_enum)
+#define utrie_get32 U_ICU_ENTRY_POINT_RENAME(utrie_get32)
+#define utrie_getData U_ICU_ENTRY_POINT_RENAME(utrie_getData)
+#define utrie_open U_ICU_ENTRY_POINT_RENAME(utrie_open)
+#define utrie_serialize U_ICU_ENTRY_POINT_RENAME(utrie_serialize)
+#define utrie_set32 U_ICU_ENTRY_POINT_RENAME(utrie_set32)
+#define utrie_setRange32 U_ICU_ENTRY_POINT_RENAME(utrie_setRange32)
+#define utrie_swap U_ICU_ENTRY_POINT_RENAME(utrie_swap)
+#define utrie_unserialize U_ICU_ENTRY_POINT_RENAME(utrie_unserialize)
+#define utrie_unserializeDummy U_ICU_ENTRY_POINT_RENAME(utrie_unserializeDummy)
+#define vzone_clone U_ICU_ENTRY_POINT_RENAME(vzone_clone)
+#define vzone_close U_ICU_ENTRY_POINT_RENAME(vzone_close)
+#define vzone_countTransitionRules U_ICU_ENTRY_POINT_RENAME(vzone_countTransitionRules)
+#define vzone_equals U_ICU_ENTRY_POINT_RENAME(vzone_equals)
+#define vzone_getDynamicClassID U_ICU_ENTRY_POINT_RENAME(vzone_getDynamicClassID)
+#define vzone_getLastModified U_ICU_ENTRY_POINT_RENAME(vzone_getLastModified)
+#define vzone_getNextTransition U_ICU_ENTRY_POINT_RENAME(vzone_getNextTransition)
+#define vzone_getOffset U_ICU_ENTRY_POINT_RENAME(vzone_getOffset)
+#define vzone_getOffset2 U_ICU_ENTRY_POINT_RENAME(vzone_getOffset2)
+#define vzone_getOffset3 U_ICU_ENTRY_POINT_RENAME(vzone_getOffset3)
+#define vzone_getPreviousTransition U_ICU_ENTRY_POINT_RENAME(vzone_getPreviousTransition)
+#define vzone_getRawOffset U_ICU_ENTRY_POINT_RENAME(vzone_getRawOffset)
+#define vzone_getStaticClassID U_ICU_ENTRY_POINT_RENAME(vzone_getStaticClassID)
+#define vzone_getTZURL U_ICU_ENTRY_POINT_RENAME(vzone_getTZURL)
+#define vzone_hasSameRules U_ICU_ENTRY_POINT_RENAME(vzone_hasSameRules)
+#define vzone_inDaylightTime U_ICU_ENTRY_POINT_RENAME(vzone_inDaylightTime)
+#define vzone_openData U_ICU_ENTRY_POINT_RENAME(vzone_openData)
+#define vzone_openID U_ICU_ENTRY_POINT_RENAME(vzone_openID)
+#define vzone_setLastModified U_ICU_ENTRY_POINT_RENAME(vzone_setLastModified)
+#define vzone_setRawOffset U_ICU_ENTRY_POINT_RENAME(vzone_setRawOffset)
+#define vzone_setTZURL U_ICU_ENTRY_POINT_RENAME(vzone_setTZURL)
+#define vzone_useDaylightTime U_ICU_ENTRY_POINT_RENAME(vzone_useDaylightTime)
+#define vzone_write U_ICU_ENTRY_POINT_RENAME(vzone_write)
+#define vzone_writeFromStart U_ICU_ENTRY_POINT_RENAME(vzone_writeFromStart)
+#define vzone_writeSimple U_ICU_ENTRY_POINT_RENAME(vzone_writeSimple)
+#define zrule_close U_ICU_ENTRY_POINT_RENAME(zrule_close)
+#define zrule_equals U_ICU_ENTRY_POINT_RENAME(zrule_equals)
+#define zrule_getDSTSavings U_ICU_ENTRY_POINT_RENAME(zrule_getDSTSavings)
+#define zrule_getName U_ICU_ENTRY_POINT_RENAME(zrule_getName)
+#define zrule_getRawOffset U_ICU_ENTRY_POINT_RENAME(zrule_getRawOffset)
+#define zrule_isEquivalentTo U_ICU_ENTRY_POINT_RENAME(zrule_isEquivalentTo)
+#define ztrans_adoptFrom U_ICU_ENTRY_POINT_RENAME(ztrans_adoptFrom)
+#define ztrans_adoptTo U_ICU_ENTRY_POINT_RENAME(ztrans_adoptTo)
+#define ztrans_clone U_ICU_ENTRY_POINT_RENAME(ztrans_clone)
+#define ztrans_close U_ICU_ENTRY_POINT_RENAME(ztrans_close)
+#define ztrans_equals U_ICU_ENTRY_POINT_RENAME(ztrans_equals)
+#define ztrans_getDynamicClassID U_ICU_ENTRY_POINT_RENAME(ztrans_getDynamicClassID)
+#define ztrans_getFrom U_ICU_ENTRY_POINT_RENAME(ztrans_getFrom)
+#define ztrans_getStaticClassID U_ICU_ENTRY_POINT_RENAME(ztrans_getStaticClassID)
+#define ztrans_getTime U_ICU_ENTRY_POINT_RENAME(ztrans_getTime)
+#define ztrans_getTo U_ICU_ENTRY_POINT_RENAME(ztrans_getTo)
+#define ztrans_open U_ICU_ENTRY_POINT_RENAME(ztrans_open)
+#define ztrans_openEmpty U_ICU_ENTRY_POINT_RENAME(ztrans_openEmpty)
+#define ztrans_setFrom U_ICU_ENTRY_POINT_RENAME(ztrans_setFrom)
+#define ztrans_setTime U_ICU_ENTRY_POINT_RENAME(ztrans_setTime)
+#define ztrans_setTo U_ICU_ENTRY_POINT_RENAME(ztrans_setTo)
+
+
+/* C++ class names renaming defines */
+
+#ifdef XP_CPLUSPLUS
+#if !U_HAVE_NAMESPACE
+
+#define AbsoluteValueSubstitution U_ICU_ENTRY_POINT_RENAME(AbsoluteValueSubstitution)
+#define AlternateSubstitutionSubtable U_ICU_ENTRY_POINT_RENAME(AlternateSubstitutionSubtable)
+#define AnchorTable U_ICU_ENTRY_POINT_RENAME(AnchorTable)
+#define AndConstraint U_ICU_ENTRY_POINT_RENAME(AndConstraint)
+#define AnnualTimeZoneRule U_ICU_ENTRY_POINT_RENAME(AnnualTimeZoneRule)
+#define AnyTransliterator U_ICU_ENTRY_POINT_RENAME(AnyTransliterator)
+#define ArabicOpenTypeLayoutEngine U_ICU_ENTRY_POINT_RENAME(ArabicOpenTypeLayoutEngine)
+#define ArabicShaping U_ICU_ENTRY_POINT_RENAME(ArabicShaping)
+#define ArgExtractor U_ICU_ENTRY_POINT_RENAME(ArgExtractor)
+#define BMPSet U_ICU_ENTRY_POINT_RENAME(BMPSet)
+#define BackwardUTrie2StringIterator U_ICU_ENTRY_POINT_RENAME(BackwardUTrie2StringIterator)
+#define BadCharacterTable U_ICU_ENTRY_POINT_RENAME(BadCharacterTable)
+#define BasicCalendarFactory U_ICU_ENTRY_POINT_RENAME(BasicCalendarFactory)
+#define BasicTimeZone U_ICU_ENTRY_POINT_RENAME(BasicTimeZone)
+#define BinarySearchLookupTable U_ICU_ENTRY_POINT_RENAME(BinarySearchLookupTable)
+#define BoyerMooreSearch U_ICU_ENTRY_POINT_RENAME(BoyerMooreSearch)
+#define BreakIterator U_ICU_ENTRY_POINT_RENAME(BreakIterator)
+#define BreakTransliterator U_ICU_ENTRY_POINT_RENAME(BreakTransliterator)
+#define BuddhistCalendar U_ICU_ENTRY_POINT_RENAME(BuddhistCalendar)
+#define BuildCompactTrieHorizontalNode U_ICU_ENTRY_POINT_RENAME(BuildCompactTrieHorizontalNode)
+#define BuildCompactTrieNode U_ICU_ENTRY_POINT_RENAME(BuildCompactTrieNode)
+#define BuildCompactTrieVerticalNode U_ICU_ENTRY_POINT_RENAME(BuildCompactTrieVerticalNode)
+#define BuilderScriptSet U_ICU_ENTRY_POINT_RENAME(BuilderScriptSet)
+#define ByteSink U_ICU_ENTRY_POINT_RENAME(ByteSink)
+#define CEBuffer U_ICU_ENTRY_POINT_RENAME(CEBuffer)
+#define CECalendar U_ICU_ENTRY_POINT_RENAME(CECalendar)
+#define CEList U_ICU_ENTRY_POINT_RENAME(CEList)
+#define CEToStringsMap U_ICU_ENTRY_POINT_RENAME(CEToStringsMap)
+#define CFactory U_ICU_ENTRY_POINT_RENAME(CFactory)
+#define Calendar U_ICU_ENTRY_POINT_RENAME(Calendar)
+#define CalendarAstronomer U_ICU_ENTRY_POINT_RENAME(CalendarAstronomer)
+#define CalendarCache U_ICU_ENTRY_POINT_RENAME(CalendarCache)
+#define CalendarData U_ICU_ENTRY_POINT_RENAME(CalendarData)
+#define CalendarService U_ICU_ENTRY_POINT_RENAME(CalendarService)
+#define CanonIterData U_ICU_ENTRY_POINT_RENAME(CanonIterData)
+#define CanonIterDataSingleton U_ICU_ENTRY_POINT_RENAME(CanonIterDataSingleton)
+#define CanonMarkFilter U_ICU_ENTRY_POINT_RENAME(CanonMarkFilter)
+#define CanonShaping U_ICU_ENTRY_POINT_RENAME(CanonShaping)
+#define CanonicalIterator U_ICU_ENTRY_POINT_RENAME(CanonicalIterator)
+#define CaseMapTransliterator U_ICU_ENTRY_POINT_RENAME(CaseMapTransliterator)
+#define ChainingContextualSubstitutionFormat1Subtable U_ICU_ENTRY_POINT_RENAME(ChainingContextualSubstitutionFormat1Subtable)
+#define ChainingContextualSubstitutionFormat2Subtable U_ICU_ENTRY_POINT_RENAME(ChainingContextualSubstitutionFormat2Subtable)
+#define ChainingContextualSubstitutionFormat3Subtable U_ICU_ENTRY_POINT_RENAME(ChainingContextualSubstitutionFormat3Subtable)
+#define ChainingContextualSubstitutionSubtable U_ICU_ENTRY_POINT_RENAME(ChainingContextualSubstitutionSubtable)
+#define CharString U_ICU_ENTRY_POINT_RENAME(CharString)
+#define CharSubstitutionFilter U_ICU_ENTRY_POINT_RENAME(CharSubstitutionFilter)
+#define CharacterIterator U_ICU_ENTRY_POINT_RENAME(CharacterIterator)
+#define CharacterNode U_ICU_ENTRY_POINT_RENAME(CharacterNode)
+#define CharsetDetector U_ICU_ENTRY_POINT_RENAME(CharsetDetector)
+#define CharsetMatch U_ICU_ENTRY_POINT_RENAME(CharsetMatch)
+#define CharsetRecog_2022 U_ICU_ENTRY_POINT_RENAME(CharsetRecog_2022)
+#define CharsetRecog_2022CN U_ICU_ENTRY_POINT_RENAME(CharsetRecog_2022CN)
+#define CharsetRecog_2022JP U_ICU_ENTRY_POINT_RENAME(CharsetRecog_2022JP)
+#define CharsetRecog_2022KR U_ICU_ENTRY_POINT_RENAME(CharsetRecog_2022KR)
+#define CharsetRecog_8859_1 U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_1)
+#define CharsetRecog_8859_1_da U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_1_da)
+#define CharsetRecog_8859_1_de U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_1_de)
+#define CharsetRecog_8859_1_en U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_1_en)
+#define CharsetRecog_8859_1_es U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_1_es)
+#define CharsetRecog_8859_1_fr U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_1_fr)
+#define CharsetRecog_8859_1_it U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_1_it)
+#define CharsetRecog_8859_1_nl U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_1_nl)
+#define CharsetRecog_8859_1_no U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_1_no)
+#define CharsetRecog_8859_1_pt U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_1_pt)
+#define CharsetRecog_8859_1_sv U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_1_sv)
+#define CharsetRecog_8859_2 U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_2)
+#define CharsetRecog_8859_2_cs U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_2_cs)
+#define CharsetRecog_8859_2_hu U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_2_hu)
+#define CharsetRecog_8859_2_pl U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_2_pl)
+#define CharsetRecog_8859_2_ro U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_2_ro)
+#define CharsetRecog_8859_5 U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_5)
+#define CharsetRecog_8859_5_ru U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_5_ru)
+#define CharsetRecog_8859_6 U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_6)
+#define CharsetRecog_8859_6_ar U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_6_ar)
+#define CharsetRecog_8859_7 U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_7)
+#define CharsetRecog_8859_7_el U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_7_el)
+#define CharsetRecog_8859_8 U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_8)
+#define CharsetRecog_8859_8_I_he U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_8_I_he)
+#define CharsetRecog_8859_8_he U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_8_he)
+#define CharsetRecog_8859_9 U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_9)
+#define CharsetRecog_8859_9_tr U_ICU_ENTRY_POINT_RENAME(CharsetRecog_8859_9_tr)
+#define CharsetRecog_IBM420_ar U_ICU_ENTRY_POINT_RENAME(CharsetRecog_IBM420_ar)
+#define CharsetRecog_IBM420_ar_ltr U_ICU_ENTRY_POINT_RENAME(CharsetRecog_IBM420_ar_ltr)
+#define CharsetRecog_IBM420_ar_rtl U_ICU_ENTRY_POINT_RENAME(CharsetRecog_IBM420_ar_rtl)
+#define CharsetRecog_IBM424_he U_ICU_ENTRY_POINT_RENAME(CharsetRecog_IBM424_he)
+#define CharsetRecog_IBM424_he_ltr U_ICU_ENTRY_POINT_RENAME(CharsetRecog_IBM424_he_ltr)
+#define CharsetRecog_IBM424_he_rtl U_ICU_ENTRY_POINT_RENAME(CharsetRecog_IBM424_he_rtl)
+#define CharsetRecog_KOI8_R U_ICU_ENTRY_POINT_RENAME(CharsetRecog_KOI8_R)
+#define CharsetRecog_UTF8 U_ICU_ENTRY_POINT_RENAME(CharsetRecog_UTF8)
+#define CharsetRecog_UTF_16_BE U_ICU_ENTRY_POINT_RENAME(CharsetRecog_UTF_16_BE)
+#define CharsetRecog_UTF_16_LE U_ICU_ENTRY_POINT_RENAME(CharsetRecog_UTF_16_LE)
+#define CharsetRecog_UTF_32 U_ICU_ENTRY_POINT_RENAME(CharsetRecog_UTF_32)
+#define CharsetRecog_UTF_32_BE U_ICU_ENTRY_POINT_RENAME(CharsetRecog_UTF_32_BE)
+#define CharsetRecog_UTF_32_LE U_ICU_ENTRY_POINT_RENAME(CharsetRecog_UTF_32_LE)
+#define CharsetRecog_Unicode U_ICU_ENTRY_POINT_RENAME(CharsetRecog_Unicode)
+#define CharsetRecog_big5 U_ICU_ENTRY_POINT_RENAME(CharsetRecog_big5)
+#define CharsetRecog_euc U_ICU_ENTRY_POINT_RENAME(CharsetRecog_euc)
+#define CharsetRecog_euc_jp U_ICU_ENTRY_POINT_RENAME(CharsetRecog_euc_jp)
+#define CharsetRecog_euc_kr U_ICU_ENTRY_POINT_RENAME(CharsetRecog_euc_kr)
+#define CharsetRecog_gb_18030 U_ICU_ENTRY_POINT_RENAME(CharsetRecog_gb_18030)
+#define CharsetRecog_mbcs U_ICU_ENTRY_POINT_RENAME(CharsetRecog_mbcs)
+#define CharsetRecog_sbcs U_ICU_ENTRY_POINT_RENAME(CharsetRecog_sbcs)
+#define CharsetRecog_sjis U_ICU_ENTRY_POINT_RENAME(CharsetRecog_sjis)
+#define CharsetRecog_windows_1251 U_ICU_ENTRY_POINT_RENAME(CharsetRecog_windows_1251)
+#define CharsetRecog_windows_1256 U_ICU_ENTRY_POINT_RENAME(CharsetRecog_windows_1256)
+#define CharsetRecognizer U_ICU_ENTRY_POINT_RENAME(CharsetRecognizer)
+#define CheckedArrayByteSink U_ICU_ENTRY_POINT_RENAME(CheckedArrayByteSink)
+#define ChineseCalendar U_ICU_ENTRY_POINT_RENAME(ChineseCalendar)
+#define ChoiceFormat U_ICU_ENTRY_POINT_RENAME(ChoiceFormat)
+#define ClassDefFormat1Table U_ICU_ENTRY_POINT_RENAME(ClassDefFormat1Table)
+#define ClassDefFormat2Table U_ICU_ENTRY_POINT_RENAME(ClassDefFormat2Table)
+#define ClassDefinitionTable U_ICU_ENTRY_POINT_RENAME(ClassDefinitionTable)
+#define ClockMath U_ICU_ENTRY_POINT_RENAME(ClockMath)
+#define CollData U_ICU_ENTRY_POINT_RENAME(CollData)
+#define CollDataCache U_ICU_ENTRY_POINT_RENAME(CollDataCache)
+#define CollDataCacheEntry U_ICU_ENTRY_POINT_RENAME(CollDataCacheEntry)
+#define CollationElementIterator U_ICU_ENTRY_POINT_RENAME(CollationElementIterator)
+#define CollationKey U_ICU_ENTRY_POINT_RENAME(CollationKey)
+#define CollationLocaleListEnumeration U_ICU_ENTRY_POINT_RENAME(CollationLocaleListEnumeration)
+#define Collator U_ICU_ENTRY_POINT_RENAME(Collator)
+#define CollatorFactory U_ICU_ENTRY_POINT_RENAME(CollatorFactory)
+#define CompactTrieDictionary U_ICU_ENTRY_POINT_RENAME(CompactTrieDictionary)
+#define CompactTrieEnumeration U_ICU_ENTRY_POINT_RENAME(CompactTrieEnumeration)
+#define ComposeNormalizer2 U_ICU_ENTRY_POINT_RENAME(ComposeNormalizer2)
+#define CompoundTransliterator U_ICU_ENTRY_POINT_RENAME(CompoundTransliterator)
+#define ConfusabledataBuilder U_ICU_ENTRY_POINT_RENAME(ConfusabledataBuilder)
+#define ContextualGlyphSubstitutionProcessor U_ICU_ENTRY_POINT_RENAME(ContextualGlyphSubstitutionProcessor)
+#define ContextualSubstitutionBase U_ICU_ENTRY_POINT_RENAME(ContextualSubstitutionBase)
+#define ContextualSubstitutionFormat1Subtable U_ICU_ENTRY_POINT_RENAME(ContextualSubstitutionFormat1Subtable)
+#define ContextualSubstitutionFormat2Subtable U_ICU_ENTRY_POINT_RENAME(ContextualSubstitutionFormat2Subtable)
+#define ContextualSubstitutionFormat3Subtable U_ICU_ENTRY_POINT_RENAME(ContextualSubstitutionFormat3Subtable)
+#define ContextualSubstitutionSubtable U_ICU_ENTRY_POINT_RENAME(ContextualSubstitutionSubtable)
+#define CopticCalendar U_ICU_ENTRY_POINT_RENAME(CopticCalendar)
+#define CoverageFormat1Table U_ICU_ENTRY_POINT_RENAME(CoverageFormat1Table)
+#define CoverageFormat2Table U_ICU_ENTRY_POINT_RENAME(CoverageFormat2Table)
+#define CoverageTable U_ICU_ENTRY_POINT_RENAME(CoverageTable)
+#define CurrencyAmount U_ICU_ENTRY_POINT_RENAME(CurrencyAmount)
+#define CurrencyFormat U_ICU_ENTRY_POINT_RENAME(CurrencyFormat)
+#define CurrencyPluralInfo U_ICU_ENTRY_POINT_RENAME(CurrencyPluralInfo)
+#define CurrencyUnit U_ICU_ENTRY_POINT_RENAME(CurrencyUnit)
+#define CursiveAttachmentSubtable U_ICU_ENTRY_POINT_RENAME(CursiveAttachmentSubtable)
+#define DTRedundantEnumeration U_ICU_ENTRY_POINT_RENAME(DTRedundantEnumeration)
+#define DTSkeletonEnumeration U_ICU_ENTRY_POINT_RENAME(DTSkeletonEnumeration)
+#define DateFormat U_ICU_ENTRY_POINT_RENAME(DateFormat)
+#define DateFormatSymbols U_ICU_ENTRY_POINT_RENAME(DateFormatSymbols)
+#define DateInterval U_ICU_ENTRY_POINT_RENAME(DateInterval)
+#define DateIntervalFormat U_ICU_ENTRY_POINT_RENAME(DateIntervalFormat)
+#define DateIntervalInfo U_ICU_ENTRY_POINT_RENAME(DateIntervalInfo)
+#define DateTimeMatcher U_ICU_ENTRY_POINT_RENAME(DateTimeMatcher)
+#define DateTimePatternGenerator U_ICU_ENTRY_POINT_RENAME(DateTimePatternGenerator)
+#define DateTimeRule U_ICU_ENTRY_POINT_RENAME(DateTimeRule)
+#define DecimalFormat U_ICU_ENTRY_POINT_RENAME(DecimalFormat)
+#define DecimalFormatSymbols U_ICU_ENTRY_POINT_RENAME(DecimalFormatSymbols)
+#define DecomposeNormalizer2 U_ICU_ENTRY_POINT_RENAME(DecomposeNormalizer2)
+#define DefaultCalendarFactory U_ICU_ENTRY_POINT_RENAME(DefaultCalendarFactory)
+#define DefaultCharMapper U_ICU_ENTRY_POINT_RENAME(DefaultCharMapper)
+#define DeviceTable U_ICU_ENTRY_POINT_RENAME(DeviceTable)
+#define DictionaryBreakEngine U_ICU_ENTRY_POINT_RENAME(DictionaryBreakEngine)
+#define DigitList U_ICU_ENTRY_POINT_RENAME(DigitList)
+#define DistanceInfo U_ICU_ENTRY_POINT_RENAME(DistanceInfo)
+#define EnumToOffset U_ICU_ENTRY_POINT_RENAME(EnumToOffset)
+#define ErrorCode U_ICU_ENTRY_POINT_RENAME(ErrorCode)
+#define EscapeTransliterator U_ICU_ENTRY_POINT_RENAME(EscapeTransliterator)
+#define EthiopicCalendar U_ICU_ENTRY_POINT_RENAME(EthiopicCalendar)
+#define EventListener U_ICU_ENTRY_POINT_RENAME(EventListener)
+#define ExtensionSubtable U_ICU_ENTRY_POINT_RENAME(ExtensionSubtable)
+#define FCDNormalizer2 U_ICU_ENTRY_POINT_RENAME(FCDNormalizer2)
+#define FCDTrieSingleton U_ICU_ENTRY_POINT_RENAME(FCDTrieSingleton)
+#define FeatureListTable U_ICU_ENTRY_POINT_RENAME(FeatureListTable)
+#define FieldPosition U_ICU_ENTRY_POINT_RENAME(FieldPosition)
+#define FieldPositionHandler U_ICU_ENTRY_POINT_RENAME(FieldPositionHandler)
+#define FieldPositionIterator U_ICU_ENTRY_POINT_RENAME(FieldPositionIterator)
+#define FieldPositionIteratorHandler U_ICU_ENTRY_POINT_RENAME(FieldPositionIteratorHandler)
+#define FieldPositionOnlyHandler U_ICU_ENTRY_POINT_RENAME(FieldPositionOnlyHandler)
+#define FilteredNormalizer2 U_ICU_ENTRY_POINT_RENAME(FilteredNormalizer2)
+#define FontRuns U_ICU_ENTRY_POINT_RENAME(FontRuns)
+#define Format U_ICU_ENTRY_POINT_RENAME(Format)
+#define Format1AnchorTable U_ICU_ENTRY_POINT_RENAME(Format1AnchorTable)
+#define Format2AnchorTable U_ICU_ENTRY_POINT_RENAME(Format2AnchorTable)
+#define Format3AnchorTable U_ICU_ENTRY_POINT_RENAME(Format3AnchorTable)
+#define FormatNameEnumeration U_ICU_ENTRY_POINT_RENAME(FormatNameEnumeration)
+#define FormatParser U_ICU_ENTRY_POINT_RENAME(FormatParser)
+#define Formattable U_ICU_ENTRY_POINT_RENAME(Formattable)
+#define ForwardCharacterIterator U_ICU_ENTRY_POINT_RENAME(ForwardCharacterIterator)
+#define ForwardUTrie2StringIterator U_ICU_ENTRY_POINT_RENAME(ForwardUTrie2StringIterator)
+#define FractionalPartSubstitution U_ICU_ENTRY_POINT_RENAME(FractionalPartSubstitution)
+#define FunctionReplacer U_ICU_ENTRY_POINT_RENAME(FunctionReplacer)
+#define GDEFMarkFilter U_ICU_ENTRY_POINT_RENAME(GDEFMarkFilter)
+#define GXLayoutEngine U_ICU_ENTRY_POINT_RENAME(GXLayoutEngine)
+#define GlyphDefinitionTableHeader U_ICU_ENTRY_POINT_RENAME(GlyphDefinitionTableHeader)
+#define GlyphIterator U_ICU_ENTRY_POINT_RENAME(GlyphIterator)
+#define GlyphLookupTableHeader U_ICU_ENTRY_POINT_RENAME(GlyphLookupTableHeader)
+#define GlyphPositionAdjustments U_ICU_ENTRY_POINT_RENAME(GlyphPositionAdjustments)
+#define GlyphPositioningLookupProcessor U_ICU_ENTRY_POINT_RENAME(GlyphPositioningLookupProcessor)
+#define GlyphPositioningTableHeader U_ICU_ENTRY_POINT_RENAME(GlyphPositioningTableHeader)
+#define GlyphSubstitutionLookupProcessor U_ICU_ENTRY_POINT_RENAME(GlyphSubstitutionLookupProcessor)
+#define GlyphSubstitutionTableHeader U_ICU_ENTRY_POINT_RENAME(GlyphSubstitutionTableHeader)
+#define GoodSuffixTable U_ICU_ENTRY_POINT_RENAME(GoodSuffixTable)
+#define Grego U_ICU_ENTRY_POINT_RENAME(Grego)
+#define GregorianCalendar U_ICU_ENTRY_POINT_RENAME(GregorianCalendar)
+#define HanOpenTypeLayoutEngine U_ICU_ENTRY_POINT_RENAME(HanOpenTypeLayoutEngine)
+#define HangulOpenTypeLayoutEngine U_ICU_ENTRY_POINT_RENAME(HangulOpenTypeLayoutEngine)
+#define HebrewCalendar U_ICU_ENTRY_POINT_RENAME(HebrewCalendar)
+#define ICUBreakIteratorFactory U_ICU_ENTRY_POINT_RENAME(ICUBreakIteratorFactory)
+#define ICUBreakIteratorService U_ICU_ENTRY_POINT_RENAME(ICUBreakIteratorService)
+#define ICUCollatorFactory U_ICU_ENTRY_POINT_RENAME(ICUCollatorFactory)
+#define ICUCollatorService U_ICU_ENTRY_POINT_RENAME(ICUCollatorService)
+#define ICUDataTable U_ICU_ENTRY_POINT_RENAME(ICUDataTable)
+#define ICULanguageBreakFactory U_ICU_ENTRY_POINT_RENAME(ICULanguageBreakFactory)
+#define ICULocaleService U_ICU_ENTRY_POINT_RENAME(ICULocaleService)
+#define ICUNotifier U_ICU_ENTRY_POINT_RENAME(ICUNotifier)
+#define ICUNumberFormatFactory U_ICU_ENTRY_POINT_RENAME(ICUNumberFormatFactory)
+#define ICUNumberFormatService U_ICU_ENTRY_POINT_RENAME(ICUNumberFormatService)
+#define ICUResourceBundleFactory U_ICU_ENTRY_POINT_RENAME(ICUResourceBundleFactory)
+#define ICUService U_ICU_ENTRY_POINT_RENAME(ICUService)
+#define ICUServiceFactory U_ICU_ENTRY_POINT_RENAME(ICUServiceFactory)
+#define ICUServiceKey U_ICU_ENTRY_POINT_RENAME(ICUServiceKey)
+#define ICU_Utility U_ICU_ENTRY_POINT_RENAME(ICU_Utility)
+#define IDNA U_ICU_ENTRY_POINT_RENAME(IDNA)
+#define IndianCalendar U_ICU_ENTRY_POINT_RENAME(IndianCalendar)
+#define IndicClassTable U_ICU_ENTRY_POINT_RENAME(IndicClassTable)
+#define IndicOpenTypeLayoutEngine U_ICU_ENTRY_POINT_RENAME(IndicOpenTypeLayoutEngine)
+#define IndicRearrangementProcessor U_ICU_ENTRY_POINT_RENAME(IndicRearrangementProcessor)
+#define IndicReordering U_ICU_ENTRY_POINT_RENAME(IndicReordering)
+#define InitialTimeZoneRule U_ICU_ENTRY_POINT_RENAME(InitialTimeZoneRule)
+#define InputText U_ICU_ENTRY_POINT_RENAME(InputText)
+#define IntegralPartSubstitution U_ICU_ENTRY_POINT_RENAME(IntegralPartSubstitution)
+#define IslamicCalendar U_ICU_ENTRY_POINT_RENAME(IslamicCalendar)
+#define IteratedChar U_ICU_ENTRY_POINT_RENAME(IteratedChar)
+#define JapaneseCalendar U_ICU_ENTRY_POINT_RENAME(JapaneseCalendar)
+#define KernTable U_ICU_ENTRY_POINT_RENAME(KernTable)
+#define KeywordEnumeration U_ICU_ENTRY_POINT_RENAME(KeywordEnumeration)
+#define KhmerClassTable U_ICU_ENTRY_POINT_RENAME(KhmerClassTable)
+#define KhmerOpenTypeLayoutEngine U_ICU_ENTRY_POINT_RENAME(KhmerOpenTypeLayoutEngine)
+#define KhmerReordering U_ICU_ENTRY_POINT_RENAME(KhmerReordering)
+#define LECharMapper U_ICU_ENTRY_POINT_RENAME(LECharMapper)
+#define LEFontInstance U_ICU_ENTRY_POINT_RENAME(LEFontInstance)
+#define LEGlyphFilter U_ICU_ENTRY_POINT_RENAME(LEGlyphFilter)
+#define LEGlyphStorage U_ICU_ENTRY_POINT_RENAME(LEGlyphStorage)
+#define LEInsertionCallback U_ICU_ENTRY_POINT_RENAME(LEInsertionCallback)
+#define LEInsertionList U_ICU_ENTRY_POINT_RENAME(LEInsertionList)
+#define LXUtilities U_ICU_ENTRY_POINT_RENAME(LXUtilities)
+#define LanguageBreakEngine U_ICU_ENTRY_POINT_RENAME(LanguageBreakEngine)
+#define LanguageBreakFactory U_ICU_ENTRY_POINT_RENAME(LanguageBreakFactory)
+#define LayoutEngine U_ICU_ENTRY_POINT_RENAME(LayoutEngine)
+#define LigatureSubstitutionProcessor U_ICU_ENTRY_POINT_RENAME(LigatureSubstitutionProcessor)
+#define LigatureSubstitutionSubtable U_ICU_ENTRY_POINT_RENAME(LigatureSubstitutionSubtable)
+#define LocDataParser U_ICU_ENTRY_POINT_RENAME(LocDataParser)
+#define Locale U_ICU_ENTRY_POINT_RENAME(Locale)
+#define LocaleBased U_ICU_ENTRY_POINT_RENAME(LocaleBased)
+#define LocaleDisplayNames U_ICU_ENTRY_POINT_RENAME(LocaleDisplayNames)
+#define LocaleDisplayNamesImpl U_ICU_ENTRY_POINT_RENAME(LocaleDisplayNamesImpl)
+#define LocaleKey U_ICU_ENTRY_POINT_RENAME(LocaleKey)
+#define LocaleKeyFactory U_ICU_ENTRY_POINT_RENAME(LocaleKeyFactory)
+#define LocaleRuns U_ICU_ENTRY_POINT_RENAME(LocaleRuns)
+#define LocaleUtility U_ICU_ENTRY_POINT_RENAME(LocaleUtility)
+#define LocalizationInfo U_ICU_ENTRY_POINT_RENAME(LocalizationInfo)
+#define LookupListTable U_ICU_ENTRY_POINT_RENAME(LookupListTable)
+#define LookupProcessor U_ICU_ENTRY_POINT_RENAME(LookupProcessor)
+#define LookupSubtable U_ICU_ENTRY_POINT_RENAME(LookupSubtable)
+#define LookupTable U_ICU_ENTRY_POINT_RENAME(LookupTable)
+#define LowercaseTransliterator U_ICU_ENTRY_POINT_RENAME(LowercaseTransliterator)
+#define MPreFixups U_ICU_ENTRY_POINT_RENAME(MPreFixups)
+#define MarkArray U_ICU_ENTRY_POINT_RENAME(MarkArray)
+#define MarkToBasePositioningSubtable U_ICU_ENTRY_POINT_RENAME(MarkToBasePositioningSubtable)
+#define MarkToLigaturePositioningSubtable U_ICU_ENTRY_POINT_RENAME(MarkToLigaturePositioningSubtable)
+#define MarkToMarkPositioningSubtable U_ICU_ENTRY_POINT_RENAME(MarkToMarkPositioningSubtable)
+#define Measure U_ICU_ENTRY_POINT_RENAME(Measure)
+#define MeasureFormat U_ICU_ENTRY_POINT_RENAME(MeasureFormat)
+#define MeasureUnit U_ICU_ENTRY_POINT_RENAME(MeasureUnit)
+#define MessageFormat U_ICU_ENTRY_POINT_RENAME(MessageFormat)
+#define MessageFormatAdapter U_ICU_ENTRY_POINT_RENAME(MessageFormatAdapter)
+#define ModulusSubstitution U_ICU_ENTRY_POINT_RENAME(ModulusSubstitution)
+#define MoonRiseSetCoordFunc U_ICU_ENTRY_POINT_RENAME(MoonRiseSetCoordFunc)
+#define MoonTimeAngleFunc U_ICU_ENTRY_POINT_RENAME(MoonTimeAngleFunc)
+#define MorphSubtableHeader U_ICU_ENTRY_POINT_RENAME(MorphSubtableHeader)
+#define MorphTableHeader U_ICU_ENTRY_POINT_RENAME(MorphTableHeader)
+#define MultipleSubstitutionSubtable U_ICU_ENTRY_POINT_RENAME(MultipleSubstitutionSubtable)
+#define MultiplierSubstitution U_ICU_ENTRY_POINT_RENAME(MultiplierSubstitution)
+#define MutableTrieDictionary U_ICU_ENTRY_POINT_RENAME(MutableTrieDictionary)
+#define MutableTrieEnumeration U_ICU_ENTRY_POINT_RENAME(MutableTrieEnumeration)
+#define NFFactory U_ICU_ENTRY_POINT_RENAME(NFFactory)
+#define NFKDBuffer U_ICU_ENTRY_POINT_RENAME(NFKDBuffer)
+#define NFRule U_ICU_ENTRY_POINT_RENAME(NFRule)
+#define NFRuleSet U_ICU_ENTRY_POINT_RENAME(NFRuleSet)
+#define NFSubstitution U_ICU_ENTRY_POINT_RENAME(NFSubstitution)
+#define NGramParser U_ICU_ENTRY_POINT_RENAME(NGramParser)
+#define NameToEnum U_ICU_ENTRY_POINT_RENAME(NameToEnum)
+#define NameUnicodeTransliterator U_ICU_ENTRY_POINT_RENAME(NameUnicodeTransliterator)
+#define NonContextualGlyphSubstitutionProcessor U_ICU_ENTRY_POINT_RENAME(NonContextualGlyphSubstitutionProcessor)
+#define NonContiguousEnumToOffset U_ICU_ENTRY_POINT_RENAME(NonContiguousEnumToOffset)
+#define NoopNormalizer2 U_ICU_ENTRY_POINT_RENAME(NoopNormalizer2)
+#define Norm2AllModes U_ICU_ENTRY_POINT_RENAME(Norm2AllModes)
+#define NormalizationTransliterator U_ICU_ENTRY_POINT_RENAME(NormalizationTransliterator)
+#define Normalizer U_ICU_ENTRY_POINT_RENAME(Normalizer)
+#define Normalizer2 U_ICU_ENTRY_POINT_RENAME(Normalizer2)
+#define Normalizer2Factory U_ICU_ENTRY_POINT_RENAME(Normalizer2Factory)
+#define Normalizer2Impl U_ICU_ENTRY_POINT_RENAME(Normalizer2Impl)
+#define Normalizer2WithImpl U_ICU_ENTRY_POINT_RENAME(Normalizer2WithImpl)
+#define NullSubstitution U_ICU_ENTRY_POINT_RENAME(NullSubstitution)
+#define NullTransliterator U_ICU_ENTRY_POINT_RENAME(NullTransliterator)
+#define NumberFormat U_ICU_ENTRY_POINT_RENAME(NumberFormat)
+#define NumberFormatFactory U_ICU_ENTRY_POINT_RENAME(NumberFormatFactory)
+#define NumberingSystem U_ICU_ENTRY_POINT_RENAME(NumberingSystem)
+#define NumeratorSubstitution U_ICU_ENTRY_POINT_RENAME(NumeratorSubstitution)
+#define OlsonTimeZone U_ICU_ENTRY_POINT_RENAME(OlsonTimeZone)
+#define OpenTypeLayoutEngine U_ICU_ENTRY_POINT_RENAME(OpenTypeLayoutEngine)
+#define OpenTypeUtilities U_ICU_ENTRY_POINT_RENAME(OpenTypeUtilities)
+#define OrConstraint U_ICU_ENTRY_POINT_RENAME(OrConstraint)
+#define PCEBuffer U_ICU_ENTRY_POINT_RENAME(PCEBuffer)
+#define PairPositioningFormat1Subtable U_ICU_ENTRY_POINT_RENAME(PairPositioningFormat1Subtable)
+#define PairPositioningFormat2Subtable U_ICU_ENTRY_POINT_RENAME(PairPositioningFormat2Subtable)
+#define PairPositioningSubtable U_ICU_ENTRY_POINT_RENAME(PairPositioningSubtable)
+#define ParagraphLayout U_ICU_ENTRY_POINT_RENAME(ParagraphLayout)
+#define ParseData U_ICU_ENTRY_POINT_RENAME(ParseData)
+#define ParsePosition U_ICU_ENTRY_POINT_RENAME(ParsePosition)
+#define PatternMap U_ICU_ENTRY_POINT_RENAME(PatternMap)
+#define PatternMapIterator U_ICU_ENTRY_POINT_RENAME(PatternMapIterator)
+#define PersianCalendar U_ICU_ENTRY_POINT_RENAME(PersianCalendar)
+#define PluralFormat U_ICU_ENTRY_POINT_RENAME(PluralFormat)
+#define PluralKeywordEnumeration U_ICU_ENTRY_POINT_RENAME(PluralKeywordEnumeration)
+#define PluralRules U_ICU_ENTRY_POINT_RENAME(PluralRules)
+#define PropertyAliases U_ICU_ENTRY_POINT_RENAME(PropertyAliases)
+#define PtnElem U_ICU_ENTRY_POINT_RENAME(PtnElem)
+#define PtnSkeleton U_ICU_ENTRY_POINT_RENAME(PtnSkeleton)
+#define Quantifier U_ICU_ENTRY_POINT_RENAME(Quantifier)
+#define RBBIDataWrapper U_ICU_ENTRY_POINT_RENAME(RBBIDataWrapper)
+#define RBBINode U_ICU_ENTRY_POINT_RENAME(RBBINode)
+#define RBBIRuleBuilder U_ICU_ENTRY_POINT_RENAME(RBBIRuleBuilder)
+#define RBBIRuleScanner U_ICU_ENTRY_POINT_RENAME(RBBIRuleScanner)
+#define RBBISetBuilder U_ICU_ENTRY_POINT_RENAME(RBBISetBuilder)
+#define RBBIStateDescriptor U_ICU_ENTRY_POINT_RENAME(RBBIStateDescriptor)
+#define RBBISymbolTable U_ICU_ENTRY_POINT_RENAME(RBBISymbolTable)
+#define RBBISymbolTableEntry U_ICU_ENTRY_POINT_RENAME(RBBISymbolTableEntry)
+#define RBBITableBuilder U_ICU_ENTRY_POINT_RENAME(RBBITableBuilder)
+#define RCEBuffer U_ICU_ENTRY_POINT_RENAME(RCEBuffer)
+#define RangeDescriptor U_ICU_ENTRY_POINT_RENAME(RangeDescriptor)
+#define RegexCompile U_ICU_ENTRY_POINT_RENAME(RegexCompile)
+#define RegexMatcher U_ICU_ENTRY_POINT_RENAME(RegexMatcher)
+#define RegexPattern U_ICU_ENTRY_POINT_RENAME(RegexPattern)
+#define RegexStaticSets U_ICU_ENTRY_POINT_RENAME(RegexStaticSets)
+#define RegularExpression U_ICU_ENTRY_POINT_RENAME(RegularExpression)
+#define RelativeDateFormat U_ICU_ENTRY_POINT_RENAME(RelativeDateFormat)
+#define RemoveTransliterator U_ICU_ENTRY_POINT_RENAME(RemoveTransliterator)
+#define ReorderingBuffer U_ICU_ENTRY_POINT_RENAME(ReorderingBuffer)
+#define Replaceable U_ICU_ENTRY_POINT_RENAME(Replaceable)
+#define ReplaceableGlue U_ICU_ENTRY_POINT_RENAME(ReplaceableGlue)
+#define ResourceBundle U_ICU_ENTRY_POINT_RENAME(ResourceBundle)
+#define RiseSetCoordFunc U_ICU_ENTRY_POINT_RENAME(RiseSetCoordFunc)
+#define RuleBasedBreakIterator U_ICU_ENTRY_POINT_RENAME(RuleBasedBreakIterator)
+#define RuleBasedCollator U_ICU_ENTRY_POINT_RENAME(RuleBasedCollator)
+#define RuleBasedNumberFormat U_ICU_ENTRY_POINT_RENAME(RuleBasedNumberFormat)
+#define RuleBasedTimeZone U_ICU_ENTRY_POINT_RENAME(RuleBasedTimeZone)
+#define RuleBasedTransliterator U_ICU_ENTRY_POINT_RENAME(RuleBasedTransliterator)
+#define RuleChain U_ICU_ENTRY_POINT_RENAME(RuleChain)
+#define RuleCharacterIterator U_ICU_ENTRY_POINT_RENAME(RuleCharacterIterator)
+#define RuleHalf U_ICU_ENTRY_POINT_RENAME(RuleHalf)
+#define RuleParser U_ICU_ENTRY_POINT_RENAME(RuleParser)
+#define RunArray U_ICU_ENTRY_POINT_RENAME(RunArray)
+#define SPUString U_ICU_ENTRY_POINT_RENAME(SPUString)
+#define SPUStringPool U_ICU_ENTRY_POINT_RENAME(SPUStringPool)
+#define SafeZoneStringFormatPtr U_ICU_ENTRY_POINT_RENAME(SafeZoneStringFormatPtr)
+#define SameValueSubstitution U_ICU_ENTRY_POINT_RENAME(SameValueSubstitution)
+#define ScriptListTable U_ICU_ENTRY_POINT_RENAME(ScriptListTable)
+#define ScriptRunIterator U_ICU_ENTRY_POINT_RENAME(ScriptRunIterator)
+#define ScriptSet U_ICU_ENTRY_POINT_RENAME(ScriptSet)
+#define ScriptTable U_ICU_ENTRY_POINT_RENAME(ScriptTable)
+#define SearchIterator U_ICU_ENTRY_POINT_RENAME(SearchIterator)
+#define SegmentArrayProcessor U_ICU_ENTRY_POINT_RENAME(SegmentArrayProcessor)
+#define SegmentSingleProcessor U_ICU_ENTRY_POINT_RENAME(SegmentSingleProcessor)
+#define SelectFormat U_ICU_ENTRY_POINT_RENAME(SelectFormat)
+#define ServiceEnumeration U_ICU_ENTRY_POINT_RENAME(ServiceEnumeration)
+#define ServiceListener U_ICU_ENTRY_POINT_RENAME(ServiceListener)
+#define SimpleArrayProcessor U_ICU_ENTRY_POINT_RENAME(SimpleArrayProcessor)
+#define SimpleDateFormat U_ICU_ENTRY_POINT_RENAME(SimpleDateFormat)
+#define SimpleFactory U_ICU_ENTRY_POINT_RENAME(SimpleFactory)
+#define SimpleLocaleKeyFactory U_ICU_ENTRY_POINT_RENAME(SimpleLocaleKeyFactory)
+#define SimpleNumberFormatFactory U_ICU_ENTRY_POINT_RENAME(SimpleNumberFormatFactory)
+#define SimpleSingleton U_ICU_ENTRY_POINT_RENAME(SimpleSingleton)
+#define SimpleTimeZone U_ICU_ENTRY_POINT_RENAME(SimpleTimeZone)
+#define SinglePositioningFormat1Subtable U_ICU_ENTRY_POINT_RENAME(SinglePositioningFormat1Subtable)
+#define SinglePositioningFormat2Subtable U_ICU_ENTRY_POINT_RENAME(SinglePositioningFormat2Subtable)
+#define SinglePositioningSubtable U_ICU_ENTRY_POINT_RENAME(SinglePositioningSubtable)
+#define SingleSubstitutionFormat1Subtable U_ICU_ENTRY_POINT_RENAME(SingleSubstitutionFormat1Subtable)
+#define SingleSubstitutionFormat2Subtable U_ICU_ENTRY_POINT_RENAME(SingleSubstitutionFormat2Subtable)
+#define SingleSubstitutionSubtable U_ICU_ENTRY_POINT_RENAME(SingleSubstitutionSubtable)
+#define SingleTableProcessor U_ICU_ENTRY_POINT_RENAME(SingleTableProcessor)
+#define SpoofData U_ICU_ENTRY_POINT_RENAME(SpoofData)
+#define SpoofImpl U_ICU_ENTRY_POINT_RENAME(SpoofImpl)
+#define StateTableProcessor U_ICU_ENTRY_POINT_RENAME(StateTableProcessor)
+#define StringCharacterIterator U_ICU_ENTRY_POINT_RENAME(StringCharacterIterator)
+#define StringEnumeration U_ICU_ENTRY_POINT_RENAME(StringEnumeration)
+#define StringList U_ICU_ENTRY_POINT_RENAME(StringList)
+#define StringLocalizationInfo U_ICU_ENTRY_POINT_RENAME(StringLocalizationInfo)
+#define StringMatcher U_ICU_ENTRY_POINT_RENAME(StringMatcher)
+#define StringPair U_ICU_ENTRY_POINT_RENAME(StringPair)
+#define StringPiece U_ICU_ENTRY_POINT_RENAME(StringPiece)
+#define StringReplacer U_ICU_ENTRY_POINT_RENAME(StringReplacer)
+#define StringSearch U_ICU_ENTRY_POINT_RENAME(StringSearch)
+#define StringToCEsMap U_ICU_ENTRY_POINT_RENAME(StringToCEsMap)
+#define StyleRuns U_ICU_ENTRY_POINT_RENAME(StyleRuns)
+#define SubstitutionLookup U_ICU_ENTRY_POINT_RENAME(SubstitutionLookup)
+#define SubtableProcessor U_ICU_ENTRY_POINT_RENAME(SubtableProcessor)
+#define SunTimeAngleFunc U_ICU_ENTRY_POINT_RENAME(SunTimeAngleFunc)
+#define SymbolTable U_ICU_ENTRY_POINT_RENAME(SymbolTable)
+#define TZEnumeration U_ICU_ENTRY_POINT_RENAME(TZEnumeration)
+#define TaiwanCalendar U_ICU_ENTRY_POINT_RENAME(TaiwanCalendar)
+#define Target U_ICU_ENTRY_POINT_RENAME(Target)
+#define TernaryNode U_ICU_ENTRY_POINT_RENAME(TernaryNode)
+#define TextTrieMap U_ICU_ENTRY_POINT_RENAME(TextTrieMap)
+#define TextTrieMapSearchResultHandler U_ICU_ENTRY_POINT_RENAME(TextTrieMapSearchResultHandler)
+#define ThaiBreakEngine U_ICU_ENTRY_POINT_RENAME(ThaiBreakEngine)
+#define ThaiLayoutEngine U_ICU_ENTRY_POINT_RENAME(ThaiLayoutEngine)
+#define ThaiShaping U_ICU_ENTRY_POINT_RENAME(ThaiShaping)
+#define TibetanClassTable U_ICU_ENTRY_POINT_RENAME(TibetanClassTable)
+#define TibetanOpenTypeLayoutEngine U_ICU_ENTRY_POINT_RENAME(TibetanOpenTypeLayoutEngine)
+#define TibetanReordering U_ICU_ENTRY_POINT_RENAME(TibetanReordering)
+#define TimeArrayTimeZoneRule U_ICU_ENTRY_POINT_RENAME(TimeArrayTimeZoneRule)
+#define TimeUnit U_ICU_ENTRY_POINT_RENAME(TimeUnit)
+#define TimeUnitAmount U_ICU_ENTRY_POINT_RENAME(TimeUnitAmount)
+#define TimeUnitFormat U_ICU_ENTRY_POINT_RENAME(TimeUnitFormat)
+#define TimeZone U_ICU_ENTRY_POINT_RENAME(TimeZone)
+#define TimeZoneRule U_ICU_ENTRY_POINT_RENAME(TimeZoneRule)
+#define TimeZoneTransition U_ICU_ENTRY_POINT_RENAME(TimeZoneTransition)
+#define TitlecaseTransliterator U_ICU_ENTRY_POINT_RENAME(TitlecaseTransliterator)
+#define TransliterationRule U_ICU_ENTRY_POINT_RENAME(TransliterationRule)
+#define TransliterationRuleData U_ICU_ENTRY_POINT_RENAME(TransliterationRuleData)
+#define TransliterationRuleSet U_ICU_ENTRY_POINT_RENAME(TransliterationRuleSet)
+#define Transliterator U_ICU_ENTRY_POINT_RENAME(Transliterator)
+#define TransliteratorAlias U_ICU_ENTRY_POINT_RENAME(TransliteratorAlias)
+#define TransliteratorEntry U_ICU_ENTRY_POINT_RENAME(TransliteratorEntry)
+#define TransliteratorIDParser U_ICU_ENTRY_POINT_RENAME(TransliteratorIDParser)
+#define TransliteratorParser U_ICU_ENTRY_POINT_RENAME(TransliteratorParser)
+#define TransliteratorRegistry U_ICU_ENTRY_POINT_RENAME(TransliteratorRegistry)
+#define TransliteratorSpec U_ICU_ENTRY_POINT_RENAME(TransliteratorSpec)
+#define TriStateSingleton U_ICU_ENTRY_POINT_RENAME(TriStateSingleton)
+#define TrieWordDictionary U_ICU_ENTRY_POINT_RENAME(TrieWordDictionary)
+#define TrimmedArrayProcessor U_ICU_ENTRY_POINT_RENAME(TrimmedArrayProcessor)
+#define UCharCharacterIterator U_ICU_ENTRY_POINT_RENAME(UCharCharacterIterator)
+#define UCollationPCE U_ICU_ENTRY_POINT_RENAME(UCollationPCE)
+#define UDataPathIterator U_ICU_ENTRY_POINT_RENAME(UDataPathIterator)
+#define ULocRuns U_ICU_ENTRY_POINT_RENAME(ULocRuns)
+#define UMemory U_ICU_ENTRY_POINT_RENAME(UMemory)
+#define UObject U_ICU_ENTRY_POINT_RENAME(UObject)
+#define UStack U_ICU_ENTRY_POINT_RENAME(UStack)
+#define UStringEnumeration U_ICU_ENTRY_POINT_RENAME(UStringEnumeration)
+#define UTS46 U_ICU_ENTRY_POINT_RENAME(UTS46)
+#define UTrie2Singleton U_ICU_ENTRY_POINT_RENAME(UTrie2Singleton)
+#define UVector U_ICU_ENTRY_POINT_RENAME(UVector)
+#define UVector32 U_ICU_ENTRY_POINT_RENAME(UVector32)
+#define UVector64 U_ICU_ENTRY_POINT_RENAME(UVector64)
+#define UnescapeTransliterator U_ICU_ENTRY_POINT_RENAME(UnescapeTransliterator)
+#define UnhandledEngine U_ICU_ENTRY_POINT_RENAME(UnhandledEngine)
+#define UnicodeArabicOpenTypeLayoutEngine U_ICU_ENTRY_POINT_RENAME(UnicodeArabicOpenTypeLayoutEngine)
+#define UnicodeFilter U_ICU_ENTRY_POINT_RENAME(UnicodeFilter)
+#define UnicodeFunctor U_ICU_ENTRY_POINT_RENAME(UnicodeFunctor)
+#define UnicodeMatcher U_ICU_ENTRY_POINT_RENAME(UnicodeMatcher)
+#define UnicodeNameTransliterator U_ICU_ENTRY_POINT_RENAME(UnicodeNameTransliterator)
+#define UnicodeReplacer U_ICU_ENTRY_POINT_RENAME(UnicodeReplacer)
+#define UnicodeSet U_ICU_ENTRY_POINT_RENAME(UnicodeSet)
+#define UnicodeSetIterator U_ICU_ENTRY_POINT_RENAME(UnicodeSetIterator)
+#define UnicodeSetStringSpan U_ICU_ENTRY_POINT_RENAME(UnicodeSetStringSpan)
+#define UnicodeString U_ICU_ENTRY_POINT_RENAME(UnicodeString)
+#define UppercaseTransliterator U_ICU_ENTRY_POINT_RENAME(UppercaseTransliterator)
+#define VTZReader U_ICU_ENTRY_POINT_RENAME(VTZReader)
+#define VTZWriter U_ICU_ENTRY_POINT_RENAME(VTZWriter)
+#define VTimeZone U_ICU_ENTRY_POINT_RENAME(VTimeZone)
+#define ValueRecord U_ICU_ENTRY_POINT_RENAME(ValueRecord)
+#define ValueRuns U_ICU_ENTRY_POINT_RENAME(ValueRuns)
+#define ZSFCache U_ICU_ENTRY_POINT_RENAME(ZSFCache)
+#define ZSFCacheEntry U_ICU_ENTRY_POINT_RENAME(ZSFCacheEntry)
+#define ZSFStringPool U_ICU_ENTRY_POINT_RENAME(ZSFStringPool)
+#define ZSFStringPoolChunk U_ICU_ENTRY_POINT_RENAME(ZSFStringPoolChunk)
+#define ZoneMeta U_ICU_ENTRY_POINT_RENAME(ZoneMeta)
+#define ZoneStringFormat U_ICU_ENTRY_POINT_RENAME(ZoneStringFormat)
+#define ZoneStringInfo U_ICU_ENTRY_POINT_RENAME(ZoneStringInfo)
+#define ZoneStringSearchResultHandler U_ICU_ENTRY_POINT_RENAME(ZoneStringSearchResultHandler)
+#define ZoneStrings U_ICU_ENTRY_POINT_RENAME(ZoneStrings)
+#define collIterate U_ICU_ENTRY_POINT_RENAME(collIterate)
+#define locale_set_default_internal U_ICU_ENTRY_POINT_RENAME(locale_set_default_internal)
+#define util64_fromDouble U_ICU_ENTRY_POINT_RENAME(util64_fromDouble)
+#define util64_pow U_ICU_ENTRY_POINT_RENAME(util64_pow)
+#define util64_tou U_ICU_ENTRY_POINT_RENAME(util64_tou)
+
+#endif
+#endif
+
+#endif
+
+#endif
diff --git a/source/common/unicode/urep.h b/source/common/unicode/urep.h
new file mode 100644
index 0000000..c7b9947
--- /dev/null
+++ b/source/common/unicode/urep.h
@@ -0,0 +1,155 @@
+/*
+******************************************************************************
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+******************************************************************************
+*   Date        Name        Description
+*   06/23/00    aliu        Creation.
+******************************************************************************
+*/
+
+#ifndef __UREP_H
+#define __UREP_H
+
+#include "unicode/utypes.h"
+
+U_CDECL_BEGIN
+
+/********************************************************************
+ * General Notes
+ ********************************************************************
+ * TODO
+ * Add usage scenario
+ * Add test code
+ * Talk about pinning
+ * Talk about "can truncate result if out of memory"
+ */
+
+/********************************************************************
+ * Data Structures
+ ********************************************************************/
+/**
+ * \file
+ * \brief C API: Callbacks for UReplaceable
+ */
+/**
+ * An opaque replaceable text object.  This will be manipulated only
+ * through the caller-supplied UReplaceableFunctor struct.  Related
+ * to the C++ class Replaceable.
+ * This is currently only used in the Transliterator C API, see utrans.h .
+ * @stable ICU 2.0
+ */
+typedef void* UReplaceable;
+
+/**
+ * A set of function pointers that transliterators use to manipulate a
+ * UReplaceable.  The caller should supply the required functions to
+ * manipulate their text appropriately.  Related to the C++ class
+ * Replaceable.
+ * @stable ICU 2.0
+ */
+typedef struct UReplaceableCallbacks {
+
+    /**
+     * Function pointer that returns the number of UChar code units in
+     * this text.
+     *
+     * @param rep A pointer to "this" UReplaceable object.
+     * @return The length of the text.
+     * @stable ICU 2.0
+     */
+    int32_t (*length)(const UReplaceable* rep);
+
+    /**
+     * Function pointer that returns a UChar code units at the given
+     * offset into this text; 0 <= offset < n, where n is the value
+     * returned by (*length)(rep).  See unistr.h for a description of
+     * charAt() vs. char32At().
+     *
+     * @param rep A pointer to "this" UReplaceable object.
+     * @param offset The index at which to fetch the UChar (code unit).
+     * @return The UChar (code unit) at offset, or U+FFFF if the offset is out of bounds.
+     * @stable ICU 2.0
+     */
+    UChar   (*charAt)(const UReplaceable* rep,
+                      int32_t offset);
+
+    /**
+     * Function pointer that returns a UChar32 code point at the given
+     * offset into this text.  See unistr.h for a description of
+     * charAt() vs. char32At().
+     *
+     * @param rep A pointer to "this" UReplaceable object.
+     * @param offset The index at which to fetch the UChar32 (code point).
+     * @return The UChar32 (code point) at offset, or U+FFFF if the offset is out of bounds.
+     * @stable ICU 2.0
+     */
+    UChar32 (*char32At)(const UReplaceable* rep,
+                        int32_t offset);
+    
+    /**
+     * Function pointer that replaces text between start and limit in
+     * this text with the given text.  Attributes (out of band info)
+     * should be retained.
+     *
+     * @param rep A pointer to "this" UReplaceable object.
+     * @param start the starting index of the text to be replaced,
+     * inclusive.
+     * @param limit the ending index of the text to be replaced,
+     * exclusive.
+     * @param text the new text to replace the UChars from
+     * start..limit-1.
+     * @param textLength the number of UChars at text, or -1 if text
+     * is null-terminated.
+     * @stable ICU 2.0
+     */
+    void    (*replace)(UReplaceable* rep,
+                       int32_t start,
+                       int32_t limit,
+                       const UChar* text,
+                       int32_t textLength);
+    
+    /**
+     * Function pointer that copies the characters in the range
+     * [<tt>start</tt>, <tt>limit</tt>) into the array <tt>dst</tt>.
+     *
+     * @param rep A pointer to "this" UReplaceable object.
+     * @param start offset of first character which will be copied
+     * into the array
+     * @param limit offset immediately following the last character to
+     * be copied
+     * @param dst array in which to copy characters.  The length of
+     * <tt>dst</tt> must be at least <tt>(limit - start)</tt>.
+     * @stable ICU 2.1
+     */
+    void    (*extract)(UReplaceable* rep,
+                       int32_t start,
+                       int32_t limit,
+                       UChar* dst);
+
+    /**
+     * Function pointer that copies text between start and limit in
+     * this text to another index in the text.  Attributes (out of
+     * band info) should be retained.  After this call, there will be
+     * (at least) two copies of the characters originally located at
+     * start..limit-1.
+     *
+     * @param rep A pointer to "this" UReplaceable object.
+     * @param start the starting index of the text to be copied,
+     * inclusive.
+     * @param limit the ending index of the text to be copied,
+     * exclusive.
+     * @param dest the index at which the copy of the UChars should be
+     * inserted.
+     * @stable ICU 2.0
+     */
+    void    (*copy)(UReplaceable* rep,
+                    int32_t start,
+                    int32_t limit,
+                    int32_t dest);    
+
+} UReplaceableCallbacks;
+
+U_CDECL_END
+
+#endif
diff --git a/source/common/unicode/ures.h b/source/common/unicode/ures.h
new file mode 100644
index 0000000..38bdfb2
--- /dev/null
+++ b/source/common/unicode/ures.h
@@ -0,0 +1,879 @@
+/*
+**********************************************************************
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*
+* File URES.H (formerly CRESBUND.H)
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   04/01/97    aliu        Creation.
+*   02/22/99    damiba      overhaul.
+*   04/04/99    helena      Fixed internal header inclusion.
+*   04/15/99    Madhu       Updated Javadoc  
+*   06/14/99    stephen     Removed functions taking a filename suffix.
+*   07/20/99    stephen     Language-independent ypedef to void*
+*   11/09/99    weiv        Added ures_getLocale()
+*   06/24/02    weiv        Added support for resource sharing
+******************************************************************************
+*/
+
+#ifndef URES_H
+#define URES_H
+
+#include "unicode/utypes.h"
+#include "unicode/uloc.h"
+#include "unicode/localpointer.h"
+
+/**
+ * \file
+ * \brief C API: Resource Bundle 
+ *
+ * <h2>C API: Resource Bundle</h2>
+ *
+ * C API representing a collection of resource information pertaining to a given
+ * locale. A resource bundle provides a way of accessing locale- specific information in
+ * a data file. You create a resource bundle that manages the resources for a given
+ * locale and then ask it for individual resources.
+ * <P>
+ * Resource bundles in ICU4C are currently defined using text files which conform to the following
+ * <a href="http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt">BNF definition</a>.
+ * More on resource bundle concepts and syntax can be found in the 
+ * <a href="http://icu-project.org/userguide/ResourceManagement.html">Users Guide</a>.
+ * <P>
+ */
+
+/**
+ * UResourceBundle is an opaque type for handles for resource bundles in C APIs.
+ * @stable ICU 2.0
+ */
+struct UResourceBundle;
+
+/**
+ * @stable ICU 2.0
+ */
+typedef struct UResourceBundle UResourceBundle;
+
+/**
+ * Numeric constants for types of resource items.
+ * @see ures_getType
+ * @stable ICU 2.0
+ */
+typedef enum {
+    /** Resource type constant for "no resource". @stable ICU 2.6 */
+    URES_NONE=-1,
+
+    /** Resource type constant for 16-bit Unicode strings. @stable ICU 2.6 */
+    URES_STRING=0,
+
+    /** Resource type constant for binary data. @stable ICU 2.6 */
+    URES_BINARY=1,
+
+    /** Resource type constant for tables of key-value pairs. @stable ICU 2.6 */
+    URES_TABLE=2,
+
+    /**
+     * Resource type constant for aliases;
+     * internally stores a string which identifies the actual resource
+     * storing the data (can be in a different resource bundle).
+     * Resolved internally before delivering the actual resource through the API.
+     * @stable ICU 2.6
+     */
+    URES_ALIAS=3,
+
+    /**
+     * Resource type constant for a single 28-bit integer, interpreted as
+     * signed or unsigned by the ures_getInt() or ures_getUInt() function.
+     * @see ures_getInt
+     * @see ures_getUInt
+     * @stable ICU 2.6
+     */
+    URES_INT=7,
+
+    /** Resource type constant for arrays of resources. @stable ICU 2.6 */
+    URES_ARRAY=8,
+
+    /**
+     * Resource type constant for vectors of 32-bit integers.
+     * @see ures_getIntVector
+     * @stable ICU 2.6
+     */
+    URES_INT_VECTOR = 14,
+#ifndef U_HIDE_DEPRECATED_API
+    /** @deprecated ICU 2.6 Use the URES_ constant instead. */
+    RES_NONE=URES_NONE,
+    /** @deprecated ICU 2.6 Use the URES_ constant instead. */
+    RES_STRING=URES_STRING,
+    /** @deprecated ICU 2.6 Use the URES_ constant instead. */
+    RES_BINARY=URES_BINARY,
+    /** @deprecated ICU 2.6 Use the URES_ constant instead. */
+    RES_TABLE=URES_TABLE,
+    /** @deprecated ICU 2.6 Use the URES_ constant instead. */
+    RES_ALIAS=URES_ALIAS,
+    /** @deprecated ICU 2.6 Use the URES_ constant instead. */
+    RES_INT=URES_INT,
+    /** @deprecated ICU 2.6 Use the URES_ constant instead. */
+    RES_ARRAY=URES_ARRAY,
+    /** @deprecated ICU 2.6 Use the URES_ constant instead. */
+    RES_INT_VECTOR=URES_INT_VECTOR,
+    /** @deprecated ICU 2.6 Not used. */
+    RES_RESERVED=15, 
+#endif /* U_HIDE_DEPRECATED_API */
+
+    URES_LIMIT = 16
+} UResType;
+
+/*
+ * Functions to create and destroy resource bundles.
+ */
+
+/**
+ * Opens a UResourceBundle, from which users can extract strings by using
+ * their corresponding keys.
+ * Note that the caller is responsible of calling <TT>ures_close</TT> on each succesfully
+ * opened resource bundle.
+ * @param packageName   The packageName and locale together point to an ICU udata object, 
+ *                      as defined by <code> udata_open( packageName, "res", locale, err) </code> 
+ *                      or equivalent.  Typically, packageName will refer to a (.dat) file, or to
+ *                      a package registered with udata_setAppData(). Using a full file or directory
+ *                      pathname for packageName is deprecated. If NULL, ICU data will be used.
+ * @param locale  specifies the locale for which we want to open the resource
+ *                if NULL, the default locale will be used. If strlen(locale) == 0
+ *                root locale will be used.
+ *                
+ * @param status  fills in the outgoing error code.
+ * 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 status results which still indicate success. U_USING_FALLBACK_WARNING
+ * 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_WARNING indicates that
+ * the default locale data or root locale data was used; neither the requested locale 
+ * nor any of its fall back locales could be found. Please see the users guide for more 
+ * information on this topic.
+ * @return      a newly allocated resource bundle.
+ * @see ures_close
+ * @stable ICU 2.0
+ */
+U_STABLE UResourceBundle*  U_EXPORT2 
+ures_open(const char*    packageName,
+          const char*  locale, 
+          UErrorCode*     status);
+
+
+/** This function does not care what kind of localeID is passed in. It simply opens a bundle with 
+ *  that name. Fallback mechanism is disabled for the new bundle. If the requested bundle contains
+ *  an %%ALIAS directive, the results are undefined.
+ * @param packageName   The packageName and locale together point to an ICU udata object, 
+ *                      as defined by <code> udata_open( packageName, "res", locale, err) </code> 
+ *                      or equivalent.  Typically, packageName will refer to a (.dat) file, or to
+ *                      a package registered with udata_setAppData(). Using a full file or directory
+ *                      pathname for packageName is deprecated. If NULL, ICU data will be used.
+ * @param locale  specifies the locale for which we want to open the resource
+ *                if NULL, the default locale will be used. If strlen(locale) == 0
+ *                root locale will be used.
+ *                
+ * @param status fills in the outgoing error code. Either U_ZERO_ERROR or U_MISSING_RESOURCE_ERROR
+ * @return      a newly allocated resource bundle or NULL if it doesn't exist.
+ * @see ures_close
+ * @stable ICU 2.0
+ */
+U_STABLE UResourceBundle* U_EXPORT2 
+ures_openDirect(const char* packageName, 
+                const char* locale, 
+                UErrorCode* status);
+
+/**
+ * Same as ures_open() but takes a const UChar *path.
+ * This path will be converted to char * using the default converter,
+ * then ures_open() is called.
+ *
+ * @param packageName   The packageName and locale together point to an ICU udata object, 
+ *                      as defined by <code> udata_open( packageName, "res", locale, err) </code> 
+ *                      or equivalent.  Typically, packageName will refer to a (.dat) file, or to
+ *                      a package registered with udata_setAppData(). Using a full file or directory
+ *                      pathname for packageName is deprecated. If NULL, ICU data will be used.
+ * @param locale  specifies the locale for which we want to open the resource
+ *                if NULL, the default locale will be used. If strlen(locale) == 0
+ *                root locale will be used.
+ * @param status  fills in the outgoing error code.
+ * @return      a newly allocated resource bundle.
+ * @see ures_open
+ * @stable ICU 2.0
+ */
+U_STABLE UResourceBundle* U_EXPORT2 
+ures_openU(const UChar* packageName, 
+           const char* locale, 
+           UErrorCode* status);
+
+/**
+ * Returns the number of strings/arrays in resource bundles.
+ * Better to use ures_getSize, as this function will be deprecated. 
+ *
+ *@param resourceBundle resource bundle containing the desired strings
+ *@param resourceKey key tagging the resource
+ *@param err fills in the outgoing error code
+ *                could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found
+ *                could be a non-failing error 
+ *                e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_FALLBACK_WARNING </TT>
+ *@return: for    <STRONG>Arrays</STRONG>: returns the number of resources in the array
+ *                <STRONG>Tables</STRONG>: returns the number of resources in the table
+ *                <STRONG>single string</STRONG>: returns 1
+ *@see ures_getSize
+ * @deprecated ICU 2.8 User ures_getSize instead
+ */
+U_DEPRECATED int32_t U_EXPORT2 
+ures_countArrayItems(const UResourceBundle* resourceBundle,
+                     const char* resourceKey,
+                     UErrorCode* err);
+/**
+ * Close a resource bundle, all pointers returned from the various ures_getXXX calls
+ * on this particular bundle should be considered invalid henceforth.
+ *
+ * @param resourceBundle a pointer to a resourceBundle struct. Can be NULL.
+ * @see ures_open
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 
+ures_close(UResourceBundle* resourceBundle);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUResourceBundlePointer
+ * "Smart pointer" class, closes a UResourceBundle via ures_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUResourceBundlePointer, UResourceBundle, ures_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Return the version number associated with this ResourceBundle as a string. Please
+ * use ures_getVersion as this function is going to be deprecated.
+ *
+ * @param resourceBundle The resource bundle for which the version is checked.
+ * @return  A version number string as specified in the resource bundle or its parent.
+ *          The caller does not own this string.
+ * @see ures_getVersion
+ * @deprecated ICU 2.8 Use ures_getVersion instead.
+ */
+U_DEPRECATED const char* U_EXPORT2 
+ures_getVersionNumber(const UResourceBundle*   resourceBundle);
+
+/**
+ * Return the version number associated with this ResourceBundle as an 
+ * UVersionInfo array.
+ *
+ * @param resB The resource bundle for which the version is checked.
+ * @param versionInfo A UVersionInfo array that is filled with the version number
+ *                    as specified in the resource bundle or its parent.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 
+ures_getVersion(const UResourceBundle* resB, 
+                UVersionInfo versionInfo);
+
+/**
+ * Return the name of the Locale associated with this ResourceBundle. This API allows
+ * you to query for the real locale of the resource. For example, if you requested 
+ * "en_US_CALIFORNIA" and only "en_US" bundle exists, "en_US" will be returned. 
+ * For subresources, the locale where this resource comes from will be returned.
+ * If fallback has occured, getLocale will reflect this.
+ *
+ * @param resourceBundle resource bundle in question
+ * @param status just for catching illegal arguments
+ * @return  A Locale name
+ * @deprecated ICU 2.8 Use ures_getLocaleByType instead.
+ */
+U_DEPRECATED const char* U_EXPORT2 
+ures_getLocale(const UResourceBundle* resourceBundle, 
+               UErrorCode* status);
+
+
+/**
+ * Return the name of the Locale associated with this ResourceBundle. 
+ * You can choose between requested, valid and real locale.
+ *
+ * @param resourceBundle resource bundle in question
+ * @param type You can choose between requested, valid and actual
+ *             locale. For description see the definition of
+ *             ULocDataLocaleType in uloc.h
+ * @param status just for catching illegal arguments
+ * @return  A Locale name
+ * @stable ICU 2.8
+ */
+U_STABLE const char* U_EXPORT2 
+ures_getLocaleByType(const UResourceBundle* resourceBundle, 
+                     ULocDataLocaleType type, 
+                     UErrorCode* status);
+
+
+/**
+ * Same as ures_open() but uses the fill-in parameter instead of allocating
+ * a bundle, if r!=NULL.
+ * TODO need to revisit usefulness of this function
+ *      and usage model for fillIn parameters without knowing sizeof(UResourceBundle)
+ * @param r The resourcebundle to open
+ * @param packageName   The packageName and locale together point to an ICU udata object, 
+ *                      as defined by <code> udata_open( packageName, "res", locale, err) </code> 
+ *                      or equivalent.  Typically, packageName will refer to a (.dat) file, or to
+ *                      a package registered with udata_setAppData(). Using a full file or directory
+ *                      pathname for packageName is deprecated. If NULL, ICU data will be used.
+ * @param localeID specifies the locale for which we want to open the resource
+ * @param status The error code
+ * @return a newly allocated resource bundle or NULL if it doesn't exist.
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2 
+ures_openFillIn(UResourceBundle *r, 
+                const char* packageName,
+                const char* localeID, 
+                UErrorCode* status);
+
+/**
+ * Returns a string from a string resource type
+ *
+ * @param resourceBundle a string resource
+ * @param len    fills in the length of resulting string
+ * @param status fills in the outgoing error code
+ *                could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found
+ *                Always check the value of status. Don't count on returning NULL.
+ *                could be a non-failing error 
+ *                e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT>
+ * @return a pointer to a zero-terminated UChar array which lives in a memory mapped/DLL file.
+ * @see ures_getBinary
+ * @see ures_getIntVector
+ * @see ures_getInt
+ * @see ures_getUInt
+ * @stable ICU 2.0
+ */
+U_STABLE const UChar* U_EXPORT2 
+ures_getString(const UResourceBundle* resourceBundle, 
+               int32_t* len, 
+               UErrorCode* status);
+
+/**
+ * Returns a UTF-8 string from a string resource.
+ * The UTF-8 string may be returnable directly as a pointer, or
+ * it may need to be copied, or transformed from UTF-16 using u_strToUTF8()
+ * or equivalent.
+ *
+ * If forceCopy==TRUE, then the string is always written to the dest buffer
+ * and dest is returned.
+ *
+ * If forceCopy==FALSE, then the string is returned as a pointer if possible,
+ * without needing a dest buffer (it can be NULL). If the string needs to be
+ * copied or transformed, then it may be placed into dest at an arbitrary offset.
+ *
+ * If the string is to be written to dest, then U_BUFFER_OVERFLOW_ERROR and
+ * U_STRING_NOT_TERMINATED_WARNING are set if appropriate, as usual.
+ *
+ * If the string is transformed from UTF-16, then a conversion error may occur
+ * if an unpaired surrogate is encountered. If the function is successful, then
+ * the output UTF-8 string is always well-formed.
+ *
+ * @param resB Resource bundle.
+ * @param dest Destination buffer. Can be NULL only if capacity=*length==0.
+ * @param length Input: Capacity of destination buffer.
+ *               Output: Actual length of the UTF-8 string, not counting the
+ *               terminating NUL, even in case of U_BUFFER_OVERFLOW_ERROR.
+ *               Can be NULL, meaning capacity=0 and the string length is not
+ *               returned to the caller.
+ * @param forceCopy If TRUE, then the output string will always be written to
+ *                  dest, with U_BUFFER_OVERFLOW_ERROR and
+ *                  U_STRING_NOT_TERMINATED_WARNING set if appropriate.
+ *                  If FALSE, then the dest buffer may or may not contain a
+ *                  copy of the string. dest may or may not be modified.
+ *                  If a copy needs to be written, then the UErrorCode parameter
+ *                  indicates overflow etc. as usual.
+ * @param status 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 pointer to the UTF-8 string. It may be dest, or at some offset
+ *         from dest (only if !forceCopy), or in unrelated memory.
+ *         Always NUL-terminated unless the string was written to dest and
+ *         length==capacity (in which case U_STRING_NOT_TERMINATED_WARNING is set).
+ *
+ * @see ures_getString
+ * @see u_strToUTF8
+ * @stable ICU 3.6
+ */
+U_STABLE const char * U_EXPORT2
+ures_getUTF8String(const UResourceBundle *resB,
+                   char *dest, int32_t *length,
+                   UBool forceCopy,
+                   UErrorCode *status);
+
+/**
+ * Returns a binary data from a binary resource. 
+ *
+ * @param resourceBundle a string resource
+ * @param len    fills in the length of resulting byte chunk
+ * @param status fills in the outgoing error code
+ *                could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found
+ *                Always check the value of status. Don't count on returning NULL.
+ *                could be a non-failing error 
+ *                e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT>
+ * @return a pointer to a chunk of unsigned bytes which live in a memory mapped/DLL file.
+ * @see ures_getString
+ * @see ures_getIntVector
+ * @see ures_getInt
+ * @see ures_getUInt
+ * @stable ICU 2.0
+ */
+U_STABLE const uint8_t* U_EXPORT2 
+ures_getBinary(const UResourceBundle* resourceBundle, 
+               int32_t* len, 
+               UErrorCode* status);
+
+/**
+ * Returns a 32 bit integer array from a resource. 
+ *
+ * @param resourceBundle an int vector resource
+ * @param len    fills in the length of resulting byte chunk
+ * @param status fills in the outgoing error code
+ *                could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found
+ *                Always check the value of status. Don't count on returning NULL.
+ *                could be a non-failing error 
+ *                e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT>
+ * @return a pointer to a chunk of integers which live in a memory mapped/DLL file.
+ * @see ures_getBinary
+ * @see ures_getString
+ * @see ures_getInt
+ * @see ures_getUInt
+ * @stable ICU 2.0
+ */
+U_STABLE const int32_t* U_EXPORT2 
+ures_getIntVector(const UResourceBundle* resourceBundle, 
+                  int32_t* len, 
+                  UErrorCode* status);
+
+/**
+ * Returns an unsigned integer from a resource. 
+ * This integer is originally 28 bits.
+ *
+ * @param resourceBundle a string resource
+ * @param status fills in the outgoing error code
+ *                could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found
+ *                could be a non-failing error 
+ *                e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT>
+ * @return an integer value
+ * @see ures_getInt
+ * @see ures_getIntVector
+ * @see ures_getBinary
+ * @see ures_getString
+ * @stable ICU 2.0
+ */
+U_STABLE uint32_t U_EXPORT2 
+ures_getUInt(const UResourceBundle* resourceBundle, 
+             UErrorCode *status);
+
+/**
+ * Returns a signed integer from a resource. 
+ * This integer is originally 28 bit and the sign gets propagated.
+ *
+ * @param resourceBundle a string resource
+ * @param status  fills in the outgoing error code
+ *                could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found
+ *                could be a non-failing error 
+ *                e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT>
+ * @return an integer value
+ * @see ures_getUInt
+ * @see ures_getIntVector
+ * @see ures_getBinary
+ * @see ures_getString
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2 
+ures_getInt(const UResourceBundle* resourceBundle, 
+            UErrorCode *status);
+
+/**
+ * Returns the size of a resource. Size for scalar types is always 1, 
+ * and for vector/table types is the number of child resources.
+ * @warning Integer array is treated as a scalar type. There are no 
+ *          APIs to access individual members of an integer array. It
+ *          is always returned as a whole.
+ * @param resourceBundle a resource
+ * @return number of resources in a given resource.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2 
+ures_getSize(const UResourceBundle *resourceBundle);
+
+/**
+ * Returns the type of a resource. Available types are defined in enum UResType
+ *
+ * @param resourceBundle a resource
+ * @return type of the given resource.
+ * @see UResType
+ * @stable ICU 2.0
+ */
+U_STABLE UResType U_EXPORT2 
+ures_getType(const UResourceBundle *resourceBundle);
+
+/**
+ * Returns the key associated with a given resource. Not all the resources have a key - only 
+ * those that are members of a table.
+ *
+ * @param resourceBundle a resource
+ * @return a key associated to this resource, or NULL if it doesn't have a key
+ * @stable ICU 2.0
+ */
+U_STABLE const char * U_EXPORT2 
+ures_getKey(const UResourceBundle *resourceBundle);
+
+/* ITERATION API 
+    This API provides means for iterating through a resource
+*/
+
+/**
+ * Resets the internal context of a resource so that iteration starts from the first element.
+ *
+ * @param resourceBundle a resource
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2 
+ures_resetIterator(UResourceBundle *resourceBundle);
+
+/**
+ * Checks whether the given resource has another element to iterate over.
+ *
+ * @param resourceBundle a resource
+ * @return TRUE if there are more elements, FALSE if there is no more elements
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2 
+ures_hasNext(const UResourceBundle *resourceBundle);
+
+/**
+ * Returns the next resource in a given resource or NULL if there are no more resources 
+ * to iterate over. Features a fill-in parameter. 
+ *
+ * @param resourceBundle    a resource
+ * @param fillIn            if NULL a new UResourceBundle struct is allocated and must be closed by the caller.
+ *                          Alternatively, you can supply a struct to be filled by this function.
+ * @param status            fills in the outgoing error code. You may still get a non NULL result even if an
+ *                          error occured. Check status instead.
+ * @return                  a pointer to a UResourceBundle struct. If fill in param was NULL, caller must close it
+ * @stable ICU 2.0
+ */
+U_STABLE UResourceBundle* U_EXPORT2 
+ures_getNextResource(UResourceBundle *resourceBundle, 
+                     UResourceBundle *fillIn, 
+                     UErrorCode *status);
+
+/**
+ * Returns the next string in a given resource or NULL if there are no more resources 
+ * to iterate over. 
+ *
+ * @param resourceBundle    a resource
+ * @param len               fill in length of the string
+ * @param key               fill in for key associated with this string. NULL if no key
+ * @param status            fills in the outgoing error code. If an error occured, we may return NULL, but don't
+ *                          count on it. Check status instead!
+ * @return a pointer to a zero-terminated UChar array which lives in a memory mapped/DLL file.
+ * @stable ICU 2.0
+ */
+U_STABLE const UChar* U_EXPORT2 
+ures_getNextString(UResourceBundle *resourceBundle, 
+                   int32_t* len, 
+                   const char ** key, 
+                   UErrorCode *status);
+
+/**
+ * Returns the resource in a given resource at the specified index. Features a fill-in parameter. 
+ *
+ * @param resourceBundle    the resource bundle from which to get a sub-resource
+ * @param indexR            an index to the wanted resource.
+ * @param fillIn            if NULL a new UResourceBundle struct is allocated and must be closed by the caller.
+ *                          Alternatively, you can supply a struct to be filled by this function.
+ * @param status            fills in the outgoing error code. Don't count on NULL being returned if an error has
+ *                          occured. Check status instead.
+ * @return                  a pointer to a UResourceBundle struct. If fill in param was NULL, caller must close it
+ * @stable ICU 2.0
+ */
+U_STABLE UResourceBundle* U_EXPORT2 
+ures_getByIndex(const UResourceBundle *resourceBundle, 
+                int32_t indexR, 
+                UResourceBundle *fillIn, 
+                UErrorCode *status);
+
+/**
+ * Returns the string in a given resource at the specified index.
+ *
+ * @param resourceBundle    a resource
+ * @param indexS            an index to the wanted string.
+ * @param len               fill in length of the string
+ * @param status            fills in the outgoing error code. If an error occured, we may return NULL, but don't
+ *                          count on it. Check status instead!
+ * @return                  a pointer to a zero-terminated UChar array which lives in a memory mapped/DLL file.
+ * @stable ICU 2.0
+ */
+U_STABLE const UChar* U_EXPORT2 
+ures_getStringByIndex(const UResourceBundle *resourceBundle, 
+                      int32_t indexS, 
+                      int32_t* len, 
+                      UErrorCode *status);
+
+/**
+ * Returns a UTF-8 string from a resource at the specified index.
+ * The UTF-8 string may be returnable directly as a pointer, or
+ * it may need to be copied, or transformed from UTF-16 using u_strToUTF8()
+ * or equivalent.
+ *
+ * If forceCopy==TRUE, then the string is always written to the dest buffer
+ * and dest is returned.
+ *
+ * If forceCopy==FALSE, then the string is returned as a pointer if possible,
+ * without needing a dest buffer (it can be NULL). If the string needs to be
+ * copied or transformed, then it may be placed into dest at an arbitrary offset.
+ *
+ * If the string is to be written to dest, then U_BUFFER_OVERFLOW_ERROR and
+ * U_STRING_NOT_TERMINATED_WARNING are set if appropriate, as usual.
+ *
+ * If the string is transformed from UTF-16, then a conversion error may occur
+ * if an unpaired surrogate is encountered. If the function is successful, then
+ * the output UTF-8 string is always well-formed.
+ *
+ * @param resB Resource bundle.
+ * @param stringIndex An index to the wanted string.
+ * @param dest Destination buffer. Can be NULL only if capacity=*length==0.
+ * @param pLength Input: Capacity of destination buffer.
+ *               Output: Actual length of the UTF-8 string, not counting the
+ *               terminating NUL, even in case of U_BUFFER_OVERFLOW_ERROR.
+ *               Can be NULL, meaning capacity=0 and the string length is not
+ *               returned to the caller.
+ * @param forceCopy If TRUE, then the output string will always be written to
+ *                  dest, with U_BUFFER_OVERFLOW_ERROR and
+ *                  U_STRING_NOT_TERMINATED_WARNING set if appropriate.
+ *                  If FALSE, then the dest buffer may or may not contain a
+ *                  copy of the string. dest may or may not be modified.
+ *                  If a copy needs to be written, then the UErrorCode parameter
+ *                  indicates overflow etc. as usual.
+ * @param status 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 pointer to the UTF-8 string. It may be dest, or at some offset
+ *         from dest (only if !forceCopy), or in unrelated memory.
+ *         Always NUL-terminated unless the string was written to dest and
+ *         length==capacity (in which case U_STRING_NOT_TERMINATED_WARNING is set).
+ *
+ * @see ures_getStringByIndex
+ * @see u_strToUTF8
+ * @stable ICU 3.6
+ */
+U_STABLE const char * U_EXPORT2
+ures_getUTF8StringByIndex(const UResourceBundle *resB,
+                          int32_t stringIndex,
+                          char *dest, int32_t *pLength,
+                          UBool forceCopy,
+                          UErrorCode *status);
+
+/**
+ * Returns a resource in a given resource that has a given key. This procedure works only with table
+ * resources. Features a fill-in parameter. 
+ *
+ * @param resourceBundle    a resource
+ * @param key               a key associated with the wanted resource
+ * @param fillIn            if NULL a new UResourceBundle struct is allocated and must be closed by the caller.
+ *                          Alternatively, you can supply a struct to be filled by this function.
+ * @param status            fills in the outgoing error code.
+ * @return                  a pointer to a UResourceBundle struct. If fill in param was NULL, caller must close it
+ * @stable ICU 2.0
+ */
+U_STABLE UResourceBundle* U_EXPORT2 
+ures_getByKey(const UResourceBundle *resourceBundle, 
+              const char* key, 
+              UResourceBundle *fillIn, 
+              UErrorCode *status);
+
+/**
+ * Returns a string in a given resource that has a given key. This procedure works only with table
+ * resources. 
+ *
+ * @param resB              a resource
+ * @param key               a key associated with the wanted string
+ * @param len               fill in length of the string
+ * @param status            fills in the outgoing error code. If an error occured, we may return NULL, but don't
+ *                          count on it. Check status instead!
+ * @return                  a pointer to a zero-terminated UChar array which lives in a memory mapped/DLL file.
+ * @stable ICU 2.0
+ */
+U_STABLE const UChar* U_EXPORT2 
+ures_getStringByKey(const UResourceBundle *resB, 
+                    const char* key, 
+                    int32_t* len, 
+                    UErrorCode *status);
+
+/**
+ * Returns a UTF-8 string from a resource and a key.
+ * This function works only with table resources.
+ *
+ * The UTF-8 string may be returnable directly as a pointer, or
+ * it may need to be copied, or transformed from UTF-16 using u_strToUTF8()
+ * or equivalent.
+ *
+ * If forceCopy==TRUE, then the string is always written to the dest buffer
+ * and dest is returned.
+ *
+ * If forceCopy==FALSE, then the string is returned as a pointer if possible,
+ * without needing a dest buffer (it can be NULL). If the string needs to be
+ * copied or transformed, then it may be placed into dest at an arbitrary offset.
+ *
+ * If the string is to be written to dest, then U_BUFFER_OVERFLOW_ERROR and
+ * U_STRING_NOT_TERMINATED_WARNING are set if appropriate, as usual.
+ *
+ * If the string is transformed from UTF-16, then a conversion error may occur
+ * if an unpaired surrogate is encountered. If the function is successful, then
+ * the output UTF-8 string is always well-formed.
+ *
+ * @param resB Resource bundle.
+ * @param key  A key associated with the wanted resource
+ * @param dest Destination buffer. Can be NULL only if capacity=*length==0.
+ * @param pLength Input: Capacity of destination buffer.
+ *               Output: Actual length of the UTF-8 string, not counting the
+ *               terminating NUL, even in case of U_BUFFER_OVERFLOW_ERROR.
+ *               Can be NULL, meaning capacity=0 and the string length is not
+ *               returned to the caller.
+ * @param forceCopy If TRUE, then the output string will always be written to
+ *                  dest, with U_BUFFER_OVERFLOW_ERROR and
+ *                  U_STRING_NOT_TERMINATED_WARNING set if appropriate.
+ *                  If FALSE, then the dest buffer may or may not contain a
+ *                  copy of the string. dest may or may not be modified.
+ *                  If a copy needs to be written, then the UErrorCode parameter
+ *                  indicates overflow etc. as usual.
+ * @param status 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 pointer to the UTF-8 string. It may be dest, or at some offset
+ *         from dest (only if !forceCopy), or in unrelated memory.
+ *         Always NUL-terminated unless the string was written to dest and
+ *         length==capacity (in which case U_STRING_NOT_TERMINATED_WARNING is set).
+ *
+ * @see ures_getStringByKey
+ * @see u_strToUTF8
+ * @stable ICU 3.6
+ */
+U_STABLE const char * U_EXPORT2
+ures_getUTF8StringByKey(const UResourceBundle *resB,
+                        const char *key,
+                        char *dest, int32_t *pLength,
+                        UBool forceCopy,
+                        UErrorCode *status);
+
+#if U_SHOW_CPLUSPLUS_API
+#include "unicode/unistr.h"
+
+U_NAMESPACE_BEGIN
+/**
+ * returns a string from a string resource type
+ *
+ * @param resB    a resource
+ * @param status: fills in the outgoing error code
+ *                could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found
+ *                could be a non-failing error 
+ *                e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT>
+ * @return        a UnicodeString object. If there is an error, string is bogus
+ * @stable ICU 2.0
+ */
+inline UnicodeString 
+ures_getUnicodeString(const UResourceBundle *resB, 
+                      UErrorCode* status) 
+{
+    int32_t len = 0;
+    const UChar *r = ures_getString(resB, &len, status);
+    return UnicodeString(TRUE, r, len);
+}
+
+/**
+ * Returns the next string in a resource or NULL if there are no more resources 
+ * to iterate over. 
+ *
+ * @param resB              a resource
+ * @param key               fill in for key associated with this string
+ * @param status            fills in the outgoing error code
+ * @return an UnicodeString object.
+ * @stable ICU 2.0
+ */
+inline UnicodeString 
+ures_getNextUnicodeString(UResourceBundle *resB, 
+                          const char ** key, 
+                          UErrorCode* status) 
+{
+    int32_t len = 0;
+    const UChar* r = ures_getNextString(resB, &len, key, status);
+    return UnicodeString(TRUE, r, len);
+}
+
+/**
+ * Returns the string in a given resource at the specified index.
+ *
+ * @param resB              a resource
+ * @param index             an index to the wanted string.
+ * @param status            fills in the outgoing error code
+ * @return                  an UnicodeString object. If there is an error, string is bogus
+ * @stable ICU 2.0
+ */
+inline UnicodeString 
+ures_getUnicodeStringByIndex(const UResourceBundle *resB, 
+                             int32_t indexS, 
+                             UErrorCode* status) 
+{
+    int32_t len = 0;
+    const UChar* r = ures_getStringByIndex(resB, indexS, &len, status);
+    return UnicodeString(TRUE, r, len);
+}
+
+/**
+ * Returns a string in a resource that has a given key. This procedure works only with table
+ * resources. 
+ *
+ * @param resB              a resource
+ * @param key               a key associated with the wanted string
+ * @param status            fills in the outgoing error code
+ * @return                  an UnicodeString object. If there is an error, string is bogus
+ * @stable ICU 2.0
+ */
+inline UnicodeString 
+ures_getUnicodeStringByKey(const UResourceBundle *resB, 
+                           const char* key, 
+                           UErrorCode* status) 
+{
+    int32_t len = 0;
+    const UChar* r = ures_getStringByKey(resB, key, &len, status);
+    return UnicodeString(TRUE, r, len);
+}
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Create a string enumerator, owned by the caller, of all locales located within 
+ * the specified resource tree.
+ * @param packageName name of the tree, such as (NULL) or U_ICUDATA_ALIAS or  or "ICUDATA-coll"
+ * This call is similar to uloc_getAvailable().
+ * @param status error code
+ * @stable ICU 3.2
+ */
+U_STABLE UEnumeration* U_EXPORT2
+ures_openAvailableLocales(const char *packageName, UErrorCode *status);
+
+
+#endif /*_URES*/
+/*eof*/
diff --git a/source/common/unicode/uscript.h b/source/common/unicode/uscript.h
new file mode 100644
index 0000000..ee21c74
--- /dev/null
+++ b/source/common/unicode/uscript.h
@@ -0,0 +1,326 @@
+/*
+ **********************************************************************
+ *   Copyright (C) 1997-2010, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ **********************************************************************
+ *
+ * File USCRIPT.H
+ *
+ * Modification History:
+ *
+ *   Date        Name        Description
+ *   07/06/2001    Ram         Creation.
+ ******************************************************************************
+ */
+
+#ifndef USCRIPT_H
+#define USCRIPT_H
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C API: Unicode Script Information
+ */
+ 
+/**
+ * Constants for ISO 15924 script codes.
+ *
+ * Many of these script codes - those from Unicode's ScriptNames.txt -
+ * are character property values for Unicode's Script property.
+ * See UAX #24 Script Names (http://www.unicode.org/reports/tr24/).
+ *
+ * Starting with ICU 3.6, constants for most ISO 15924 script codes
+ * are included (currently excluding private-use codes Qaaa..Qabx).
+ * For scripts for which there are codes in ISO 15924 but which are not
+ * used in the Unicode Character Database (UCD), there are no Unicode characters
+ * associated with those scripts.
+ *
+ * For example, there are no characters that have a UCD script code of
+ * Hans or Hant. All Han ideographs have the Hani script code.
+ * The Hans and Hant script codes are used with CLDR data.
+ *
+ * ISO 15924 script codes are included for use with CLDR and similar.
+ *
+ * @stable ICU 2.2
+ */
+typedef enum UScriptCode {
+      USCRIPT_INVALID_CODE = -1,
+      USCRIPT_COMMON       =  0,  /* Zyyy */
+      USCRIPT_INHERITED    =  1,  /* Zinh */ /* "Code for inherited script", for non-spacing combining marks; also Qaai */
+      USCRIPT_ARABIC       =  2,  /* Arab */
+      USCRIPT_ARMENIAN     =  3,  /* Armn */
+      USCRIPT_BENGALI      =  4,  /* Beng */
+      USCRIPT_BOPOMOFO     =  5,  /* Bopo */
+      USCRIPT_CHEROKEE     =  6,  /* Cher */
+      USCRIPT_COPTIC       =  7,  /* Copt */
+      USCRIPT_CYRILLIC     =  8,  /* Cyrl */
+      USCRIPT_DESERET      =  9,  /* Dsrt */
+      USCRIPT_DEVANAGARI   = 10,  /* Deva */
+      USCRIPT_ETHIOPIC     = 11,  /* Ethi */
+      USCRIPT_GEORGIAN     = 12,  /* Geor */
+      USCRIPT_GOTHIC       = 13,  /* Goth */
+      USCRIPT_GREEK        = 14,  /* Grek */
+      USCRIPT_GUJARATI     = 15,  /* Gujr */
+      USCRIPT_GURMUKHI     = 16,  /* Guru */
+      USCRIPT_HAN          = 17,  /* Hani */
+      USCRIPT_HANGUL       = 18,  /* Hang */
+      USCRIPT_HEBREW       = 19,  /* Hebr */
+      USCRIPT_HIRAGANA     = 20,  /* Hira */
+      USCRIPT_KANNADA      = 21,  /* Knda */
+      USCRIPT_KATAKANA     = 22,  /* Kana */
+      USCRIPT_KHMER        = 23,  /* Khmr */
+      USCRIPT_LAO          = 24,  /* Laoo */
+      USCRIPT_LATIN        = 25,  /* Latn */
+      USCRIPT_MALAYALAM    = 26,  /* Mlym */
+      USCRIPT_MONGOLIAN    = 27,  /* Mong */
+      USCRIPT_MYANMAR      = 28,  /* Mymr */
+      USCRIPT_OGHAM        = 29,  /* Ogam */
+      USCRIPT_OLD_ITALIC   = 30,  /* Ital */
+      USCRIPT_ORIYA        = 31,  /* Orya */
+      USCRIPT_RUNIC        = 32,  /* Runr */
+      USCRIPT_SINHALA      = 33,  /* Sinh */
+      USCRIPT_SYRIAC       = 34,  /* Syrc */
+      USCRIPT_TAMIL        = 35,  /* Taml */
+      USCRIPT_TELUGU       = 36,  /* Telu */
+      USCRIPT_THAANA       = 37,  /* Thaa */
+      USCRIPT_THAI         = 38,  /* Thai */
+      USCRIPT_TIBETAN      = 39,  /* Tibt */
+      /** Canadian_Aboriginal script. @stable ICU 2.6 */
+      USCRIPT_CANADIAN_ABORIGINAL = 40,  /* Cans */
+      /** Canadian_Aboriginal script (alias). @stable ICU 2.2 */
+      USCRIPT_UCAS         = USCRIPT_CANADIAN_ABORIGINAL,
+      USCRIPT_YI           = 41,  /* Yiii */
+      USCRIPT_TAGALOG      = 42,  /* Tglg */
+      USCRIPT_HANUNOO      = 43,  /* Hano */
+      USCRIPT_BUHID        = 44,  /* Buhd */
+      USCRIPT_TAGBANWA     = 45,  /* Tagb */
+
+      /* New scripts in Unicode 4 @stable ICU 2.6 */
+      USCRIPT_BRAILLE      = 46,  /* Brai */
+      USCRIPT_CYPRIOT      = 47,  /* Cprt */
+      USCRIPT_LIMBU        = 48,  /* Limb */
+      USCRIPT_LINEAR_B     = 49,  /* Linb */
+      USCRIPT_OSMANYA      = 50,  /* Osma */
+      USCRIPT_SHAVIAN      = 51,  /* Shaw */
+      USCRIPT_TAI_LE       = 52,  /* Tale */
+      USCRIPT_UGARITIC     = 53,  /* Ugar */
+
+      /** New script code in Unicode 4.0.1 @stable ICU 3.0 */
+      USCRIPT_KATAKANA_OR_HIRAGANA = 54,/*Hrkt */
+
+      /* New scripts in Unicode 4.1 @stable ICU 3.4 */
+      USCRIPT_BUGINESE      = 55, /* Bugi */
+      USCRIPT_GLAGOLITIC    = 56, /* Glag */
+      USCRIPT_KHAROSHTHI    = 57, /* Khar */
+      USCRIPT_SYLOTI_NAGRI  = 58, /* Sylo */
+      USCRIPT_NEW_TAI_LUE   = 59, /* Talu */
+      USCRIPT_TIFINAGH      = 60, /* Tfng */
+      USCRIPT_OLD_PERSIAN   = 61, /* Xpeo */
+
+      /* New script codes from ISO 15924 @stable ICU 3.6 */
+      USCRIPT_BALINESE                      = 62, /* Bali */
+      USCRIPT_BATAK                         = 63, /* Batk */
+      USCRIPT_BLISSYMBOLS                   = 64, /* Blis */
+      USCRIPT_BRAHMI                        = 65, /* Brah */
+      USCRIPT_CHAM                          = 66, /* Cham */
+      USCRIPT_CIRTH                         = 67, /* Cirt */
+      USCRIPT_OLD_CHURCH_SLAVONIC_CYRILLIC  = 68, /* Cyrs */
+      USCRIPT_DEMOTIC_EGYPTIAN              = 69, /* Egyd */
+      USCRIPT_HIERATIC_EGYPTIAN             = 70, /* Egyh */
+      USCRIPT_EGYPTIAN_HIEROGLYPHS          = 71, /* Egyp */
+      USCRIPT_KHUTSURI                      = 72, /* Geok */
+      USCRIPT_SIMPLIFIED_HAN                = 73, /* Hans */
+      USCRIPT_TRADITIONAL_HAN               = 74, /* Hant */
+      USCRIPT_PAHAWH_HMONG                  = 75, /* Hmng */
+      USCRIPT_OLD_HUNGARIAN                 = 76, /* Hung */
+      USCRIPT_HARAPPAN_INDUS                = 77, /* Inds */
+      USCRIPT_JAVANESE                      = 78, /* Java */
+      USCRIPT_KAYAH_LI                      = 79, /* Kali */
+      USCRIPT_LATIN_FRAKTUR                 = 80, /* Latf */
+      USCRIPT_LATIN_GAELIC                  = 81, /* Latg */
+      USCRIPT_LEPCHA                        = 82, /* Lepc */
+      USCRIPT_LINEAR_A                      = 83, /* Lina */
+      /** @stable ICU 4.6 */
+      USCRIPT_MANDAIC                       = 84, /* Mand */
+      /** @stable ICU 3.6 */
+      USCRIPT_MANDAEAN                      = USCRIPT_MANDAIC,
+      USCRIPT_MAYAN_HIEROGLYPHS             = 85, /* Maya */
+      /** @stable ICU 4.6 */
+      USCRIPT_MEROITIC_HIEROGLYPHS          = 86, /* Mero */
+      /** @stable ICU 3.6 */
+      USCRIPT_MEROITIC                      = USCRIPT_MEROITIC_HIEROGLYPHS,
+      USCRIPT_NKO                           = 87, /* Nkoo */
+      USCRIPT_ORKHON                        = 88, /* Orkh */
+      USCRIPT_OLD_PERMIC                    = 89, /* Perm */
+      USCRIPT_PHAGS_PA                      = 90, /* Phag */
+      USCRIPT_PHOENICIAN                    = 91, /* Phnx */
+      USCRIPT_PHONETIC_POLLARD              = 92, /* Plrd */
+      USCRIPT_RONGORONGO                    = 93, /* Roro */
+      USCRIPT_SARATI                        = 94, /* Sara */
+      USCRIPT_ESTRANGELO_SYRIAC             = 95, /* Syre */
+      USCRIPT_WESTERN_SYRIAC                = 96, /* Syrj */
+      USCRIPT_EASTERN_SYRIAC                = 97, /* Syrn */
+      USCRIPT_TENGWAR                       = 98, /* Teng */
+      USCRIPT_VAI                           = 99, /* Vaii */
+      USCRIPT_VISIBLE_SPEECH                = 100,/* Visp */
+      USCRIPT_CUNEIFORM                     = 101,/* Xsux */
+      USCRIPT_UNWRITTEN_LANGUAGES           = 102,/* Zxxx */
+      USCRIPT_UNKNOWN                       = 103,/* Zzzz */ /* Unknown="Code for uncoded script", for unassigned code points */
+
+      /* New script codes from ISO 15924 @stable ICU 3.8 */
+      USCRIPT_CARIAN                        = 104,/* Cari */
+      USCRIPT_JAPANESE                      = 105,/* Jpan */
+      USCRIPT_LANNA                         = 106,/* Lana */
+      USCRIPT_LYCIAN                        = 107,/* Lyci */
+      USCRIPT_LYDIAN                        = 108,/* Lydi */
+      USCRIPT_OL_CHIKI                      = 109,/* Olck */
+      USCRIPT_REJANG                        = 110,/* Rjng */
+      USCRIPT_SAURASHTRA                    = 111,/* Saur */
+      USCRIPT_SIGN_WRITING                  = 112,/* Sgnw */
+      USCRIPT_SUNDANESE                     = 113,/* Sund */
+      USCRIPT_MOON                          = 114,/* Moon */
+      USCRIPT_MEITEI_MAYEK                  = 115,/* Mtei */
+
+      /* New script codes from ISO 15924 @stable ICU 4.0 */
+      USCRIPT_IMPERIAL_ARAMAIC              = 116,/* Armi */
+      USCRIPT_AVESTAN                       = 117,/* Avst */
+      USCRIPT_CHAKMA                        = 118,/* Cakm */
+      USCRIPT_KOREAN                        = 119,/* Kore */
+      USCRIPT_KAITHI                        = 120,/* Kthi */
+      USCRIPT_MANICHAEAN                    = 121,/* Mani */
+      USCRIPT_INSCRIPTIONAL_PAHLAVI         = 122,/* Phli */
+      USCRIPT_PSALTER_PAHLAVI               = 123,/* Phlp */
+      USCRIPT_BOOK_PAHLAVI                  = 124,/* Phlv */
+      USCRIPT_INSCRIPTIONAL_PARTHIAN        = 125,/* Prti */
+      USCRIPT_SAMARITAN                     = 126,/* Samr */
+      USCRIPT_TAI_VIET                      = 127,/* Tavt */
+      USCRIPT_MATHEMATICAL_NOTATION         = 128,/* Zmth */
+      USCRIPT_SYMBOLS                       = 129,/* Zsym */
+
+      /* New script codes from ISO 15924 @stable ICU 4.4 */
+      USCRIPT_BAMUM                         = 130,/* Bamu */
+      USCRIPT_LISU                          = 131,/* Lisu */
+      USCRIPT_NAKHI_GEBA                    = 132,/* Nkgb */
+      USCRIPT_OLD_SOUTH_ARABIAN             = 133,/* Sarb */
+
+      /* New script codes from ISO 15924 @stable ICU 4.6 */
+      USCRIPT_BASSA_VAH                     = 134,/* Bass */
+      USCRIPT_DUPLOYAN_SHORTAND             = 135,/* Dupl */
+      USCRIPT_ELBASAN                       = 136,/* Elba */
+      USCRIPT_GRANTHA                       = 137,/* Gran */
+      USCRIPT_KPELLE                        = 138,/* Kpel */
+      USCRIPT_LOMA                          = 139,/* Loma */
+      USCRIPT_MENDE                         = 140,/* Mend */
+      USCRIPT_MEROITIC_CURSIVE              = 141,/* Merc */
+      USCRIPT_OLD_NORTH_ARABIAN             = 142,/* Narb */
+      USCRIPT_NABATAEAN                     = 143,/* Nbat */
+      USCRIPT_PALMYRENE                     = 144,/* Palm */
+      USCRIPT_SINDHI                        = 145,/* Sind */
+      USCRIPT_WARANG_CITI                   = 146,/* Wara */
+
+      /* Private use codes from Qaaa - Qabx are not supported */
+      USCRIPT_CODE_LIMIT    = 147
+} UScriptCode;
+
+/**
+ * Gets script codes associated with the given locale or ISO 15924 abbreviation or name. 
+ * Fills in USCRIPT_MALAYALAM given "Malayam" OR "Mlym".
+ * Fills in USCRIPT_LATIN given "en" OR "en_US" 
+ * If required capacity is greater than capacity of the destination buffer then the error code
+ * is set to U_BUFFER_OVERFLOW_ERROR and the required capacity is returned
+ *
+ * <p>Note: To search by short or long script alias only, use
+ * u_getPropertyValueEnum(UCHAR_SCRIPT, alias) instead.  This does
+ * a fast lookup with no access of the locale data.
+ * @param nameOrAbbrOrLocale name of the script, as given in
+ * PropertyValueAliases.txt, or ISO 15924 code or locale
+ * @param fillIn the UScriptCode buffer to fill in the script code
+ * @param capacity the capacity (size) fo UScriptCode buffer passed in.
+ * @param err the error status code.
+ * @return The number of script codes filled in the buffer passed in 
+ * @stable ICU 2.4
+ */
+U_STABLE int32_t  U_EXPORT2 
+uscript_getCode(const char* nameOrAbbrOrLocale,UScriptCode* fillIn,int32_t capacity,UErrorCode *err);
+
+/**
+ * Gets a script name associated with the given script code. 
+ * Returns  "Malayam" given USCRIPT_MALAYALAM
+ * @param scriptCode UScriptCode enum
+ * @return script long name as given in
+ * PropertyValueAliases.txt, or NULL if scriptCode is invalid
+ * @stable ICU 2.4
+ */
+U_STABLE const char*  U_EXPORT2 
+uscript_getName(UScriptCode scriptCode);
+
+/**
+ * Gets a script name associated with the given script code. 
+ * Returns  "Mlym" given USCRIPT_MALAYALAM
+ * @param scriptCode UScriptCode enum
+ * @return script abbreviated name as given in
+ * PropertyValueAliases.txt, or NULL if scriptCode is invalid
+ * @stable ICU 2.4
+ */
+U_STABLE const char*  U_EXPORT2 
+uscript_getShortName(UScriptCode scriptCode);
+
+/**
+ * Gets the script code associated with the given codepoint.
+ * Returns USCRIPT_MALAYALAM given 0x0D02 
+ * @param codepoint UChar32 codepoint
+ * @param err the error status code.
+ * @return The UScriptCode, or 0 if codepoint is invalid 
+ * @stable ICU 2.4
+ */
+U_STABLE UScriptCode  U_EXPORT2 
+uscript_getScript(UChar32 codepoint, UErrorCode *err);
+
+/**
+ * Is code point c used in script sc?
+ * That is, does code point c have the Script property value sc,
+ * or do code point c's Script_Extensions include script code sc?
+ *
+ * Some characters are commonly used in multiple scripts.
+ * For more information, see UAX #24: http://www.unicode.org/reports/tr24/.
+ *
+ * The Script_Extensions property is provisional. It may be modified or removed
+ * in future versions of the Unicode Standard, and thus in ICU.
+ * @param c code point
+ * @param sc script code
+ * @return TRUE if Script(c)==sc or sc is in Script_Extensions(c)
+ * @draft ICU 4.6
+ */
+U_DRAFT UBool U_EXPORT2
+uscript_hasScript(UChar32 c, UScriptCode sc);
+
+/**
+ * Writes code point c's Script_Extensions as a list of UScriptCode values
+ * to the output scripts array.
+ *
+ * Some characters are commonly used in multiple scripts.
+ * For more information, see UAX #24: http://www.unicode.org/reports/tr24/.
+ *
+ * If there are more than capacity script codes to be written, then
+ * U_BUFFER_OVERFLOW_ERROR is set and the number of Script_Extensions is returned.
+ * (Usual ICU buffer handling behavior.)
+ *
+ * The Script_Extensions property is provisional. It may be modified or removed
+ * in future versions of the Unicode Standard, and thus in ICU.
+ * @param c code point
+ * @param scripts output script code array
+ * @param capacity capacity of the scripts array
+ * @param errorCode 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 number of script codes in c's Script_Extensions,
+ *         written to scripts unless U_BUFFER_OVERFLOW_ERROR indicates insufficient capacity
+ * @draft ICU 4.6
+ */
+U_DRAFT int32_t U_EXPORT2
+uscript_getScriptExtensions(UChar32 c,
+                            UScriptCode *scripts, int32_t capacity,
+                            UErrorCode *pErrorCode);
+
+#endif
diff --git a/source/common/unicode/uset.h b/source/common/unicode/uset.h
new file mode 100644
index 0000000..77ab063
--- /dev/null
+++ b/source/common/unicode/uset.h
@@ -0,0 +1,1120 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2002-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  uset.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002mar07
+*   created by: Markus W. Scherer
+*
+*   C version of UnicodeSet.
+*/
+
+
+/**
+ * \file
+ * \brief C API: Unicode Set
+ *
+ * <p>This is a C wrapper around the C++ UnicodeSet class.</p>
+ */
+
+#ifndef __USET_H__
+#define __USET_H__
+
+#include "unicode/utypes.h"
+#include "unicode/uchar.h"
+#include "unicode/localpointer.h"
+
+#ifndef UCNV_H
+struct USet;
+/**
+ * A UnicodeSet.  Use the uset_* API to manipulate.  Create with
+ * uset_open*, and destroy with uset_close.
+ * @stable ICU 2.4
+ */
+typedef struct USet USet;
+#endif
+
+/**
+ * Bitmask values to be passed to uset_openPatternOptions() or
+ * uset_applyPattern() taking an option parameter.
+ * @stable ICU 2.4
+ */
+enum {
+    /**
+     * Ignore white space within patterns unless quoted or escaped.
+     * @stable ICU 2.4
+     */
+    USET_IGNORE_SPACE = 1,  
+
+    /**
+     * Enable case insensitive matching.  E.g., "[ab]" with this flag
+     * will match 'a', 'A', 'b', and 'B'.  "[^ab]" with this flag will
+     * match all except 'a', 'A', 'b', and 'B'. This performs a full
+     * closure over case mappings, e.g. U+017F for s.
+     *
+     * The resulting set is a superset of the input for the code points but
+     * not for the strings.
+     * It performs a case mapping closure of the code points and adds
+     * full case folding strings for the code points, and reduces strings of
+     * the original set to their full case folding equivalents.
+     *
+     * This is designed for case-insensitive matches, for example
+     * in regular expressions. The full code point case closure allows checking of
+     * an input character directly against the closure set.
+     * Strings are matched by comparing the case-folded form from the closure
+     * set with an incremental case folding of the string in question.
+     *
+     * The closure set will also contain single code points if the original
+     * set contained case-equivalent strings (like U+00DF for "ss" or "Ss" etc.).
+     * This is not necessary (that is, redundant) for the above matching method
+     * but results in the same closure sets regardless of whether the original
+     * set contained the code point or a string.
+     *
+     * @stable ICU 2.4
+     */
+    USET_CASE_INSENSITIVE = 2,  
+
+    /**
+     * Enable case insensitive matching.  E.g., "[ab]" with this flag
+     * will match 'a', 'A', 'b', and 'B'.  "[^ab]" with this flag will
+     * match all except 'a', 'A', 'b', and 'B'. This adds the lower-,
+     * title-, and uppercase mappings as well as the case folding
+     * of each existing element in the set.
+     * @stable ICU 3.2
+     */
+    USET_ADD_CASE_MAPPINGS = 4,
+    
+    /**
+     * Enough for any single-code point set
+     * @internal
+     */
+    USET_SERIALIZED_STATIC_ARRAY_CAPACITY=8
+};
+
+/**
+ * Argument values for whether span() and similar functions continue while
+ * the current character is contained vs. not contained in the set.
+ *
+ * The functionality is straightforward for sets with only single code points,
+ * without strings (which is the common case):
+ * - USET_SPAN_CONTAINED and USET_SPAN_SIMPLE
+ *   work the same.
+ * - span() and spanBack() partition any string the same way when
+ *   alternating between span(USET_SPAN_NOT_CONTAINED) and
+ *   span(either "contained" condition).
+ * - Using a complemented (inverted) set and the opposite span conditions
+ *   yields the same results.
+ *
+ * When a set contains multi-code point strings, then these statements may not
+ * be true, depending on the strings in the set (for example, whether they
+ * overlap with each other) and the string that is processed.
+ * For a set with strings:
+ * - The complement of the set contains the opposite set of code points,
+ *   but the same set of strings.
+ *   Therefore, complementing both the set and the span conditions
+ *   may yield different results.
+ * - When starting spans at different positions in a string
+ *   (span(s, ...) vs. span(s+1, ...)) the ends of the spans may be different
+ *   because a set string may start before the later position.
+ * - span(USET_SPAN_SIMPLE) may be shorter than
+ *   span(USET_SPAN_CONTAINED) because it will not recursively try
+ *   all possible paths.
+ *   For example, with a set which contains the three strings "xy", "xya" and "ax",
+ *   span("xyax", USET_SPAN_CONTAINED) will return 4 but
+ *   span("xyax", USET_SPAN_SIMPLE) will return 3.
+ *   span(USET_SPAN_SIMPLE) will never be longer than
+ *   span(USET_SPAN_CONTAINED).
+ * - With either "contained" condition, span() and spanBack() may partition
+ *   a string in different ways.
+ *   For example, with a set which contains the two strings "ab" and "ba",
+ *   and when processing the string "aba",
+ *   span() will yield contained/not-contained boundaries of { 0, 2, 3 }
+ *   while spanBack() will yield boundaries of { 0, 1, 3 }.
+ *
+ * Note: If it is important to get the same boundaries whether iterating forward
+ * or backward through a string, then either only span() should be used and
+ * the boundaries cached for backward operation, or an ICU BreakIterator
+ * could be used.
+ *
+ * Note: Unpaired surrogates are treated like surrogate code points.
+ * Similarly, set strings match only on code point boundaries,
+ * never in the middle of a surrogate pair.
+ * Illegal UTF-8 sequences are treated like U+FFFD.
+ * When processing UTF-8 strings, malformed set strings
+ * (strings with unpaired surrogates which cannot be converted to UTF-8)
+ * are ignored.
+ *
+ * @stable ICU 3.8
+ */
+typedef enum USetSpanCondition {
+    /**
+     * Continue a span() while there is no set element at the current position.
+     * Stops before the first set element (character or string).
+     * (For code points only, this is like while contains(current)==FALSE).
+     *
+     * When span() returns, the substring between where it started and the position
+     * it returned consists only of characters that are not in the set,
+     * and none of its strings overlap with the span.
+     *
+     * @stable ICU 3.8
+     */
+    USET_SPAN_NOT_CONTAINED = 0,
+    /**
+     * Continue a span() while there is a set element at the current position.
+     * (For characters only, this is like while contains(current)==TRUE).
+     *
+     * When span() returns, the substring between where it started and the position
+     * it returned consists only of set elements (characters or strings) that are in the set.
+     *
+     * If a set contains strings, then the span will be the longest substring
+     * matching any of the possible concatenations of set elements (characters or strings).
+     * (There must be a single, non-overlapping concatenation of characters or strings.)
+     * This is equivalent to a POSIX regular expression for (OR of each set element)*.
+     *
+     * @stable ICU 3.8
+     */
+    USET_SPAN_CONTAINED = 1,
+    /**
+     * Continue a span() while there is a set element at the current position.
+     * (For characters only, this is like while contains(current)==TRUE).
+     *
+     * When span() returns, the substring between where it started and the position
+     * it returned consists only of set elements (characters or strings) that are in the set.
+     *
+     * If a set only contains single characters, then this is the same
+     * as USET_SPAN_CONTAINED.
+     *
+     * If a set contains strings, then the span will be the longest substring
+     * with a match at each position with the longest single set element (character or string).
+     *
+     * Use this span condition together with other longest-match algorithms,
+     * such as ICU converters (ucnv_getUnicodeSet()).
+     *
+     * @stable ICU 3.8
+     */
+    USET_SPAN_SIMPLE = 2,
+    /**
+     * One more than the last span condition.
+     * @stable ICU 3.8
+     */
+    USET_SPAN_CONDITION_COUNT
+} USetSpanCondition;
+
+/**
+ * A serialized form of a Unicode set.  Limited manipulations are
+ * possible directly on a serialized set.  See below.
+ * @stable ICU 2.4
+ */
+typedef struct USerializedSet {
+    /**
+     * The serialized Unicode Set.
+     * @stable ICU 2.4
+     */
+    const uint16_t *array;
+    /**
+     * The length of the array that contains BMP characters.
+     * @stable ICU 2.4
+     */
+    int32_t bmpLength;
+    /**
+     * The total length of the array.
+     * @stable ICU 2.4
+     */
+    int32_t length;
+    /**
+     * A small buffer for the array to reduce memory allocations.
+     * @stable ICU 2.4
+     */
+    uint16_t staticArray[USET_SERIALIZED_STATIC_ARRAY_CAPACITY];
+} USerializedSet;
+
+/*********************************************************************
+ * USet API
+ *********************************************************************/
+
+/**
+ * Create an empty USet object.
+ * Equivalent to uset_open(1, 0).
+ * @return a newly created USet.  The caller must call uset_close() on
+ * it when done.
+ * @stable ICU 4.2
+ */
+U_STABLE USet* U_EXPORT2
+uset_openEmpty();
+
+/**
+ * Creates a USet object that contains the range of characters
+ * start..end, inclusive.  If <code>start > end</code> 
+ * then an empty set is created (same as using uset_openEmpty()).
+ * @param start first character of the range, inclusive
+ * @param end last character of the range, inclusive
+ * @return a newly created USet.  The caller must call uset_close() on
+ * it when done.
+ * @stable ICU 2.4
+ */
+U_STABLE USet* U_EXPORT2
+uset_open(UChar32 start, UChar32 end);
+
+/**
+ * Creates a set from the given pattern.  See the UnicodeSet class
+ * description for the syntax of the pattern language.
+ * @param pattern a string specifying what characters are in the set
+ * @param patternLength the length of the pattern, or -1 if null
+ * terminated
+ * @param ec the error code
+ * @stable ICU 2.4
+ */
+U_STABLE USet* U_EXPORT2
+uset_openPattern(const UChar* pattern, int32_t patternLength,
+                 UErrorCode* ec);
+
+/**
+ * Creates a set from the given pattern.  See the UnicodeSet class
+ * description for the syntax of the pattern language.
+ * @param pattern a string specifying what characters are in the set
+ * @param patternLength the length of the pattern, or -1 if null
+ * terminated
+ * @param options bitmask for options to apply to the pattern.
+ * Valid options are USET_IGNORE_SPACE and USET_CASE_INSENSITIVE.
+ * @param ec the error code
+ * @stable ICU 2.4
+ */
+U_STABLE USet* U_EXPORT2
+uset_openPatternOptions(const UChar* pattern, int32_t patternLength,
+                 uint32_t options,
+                 UErrorCode* ec);
+
+/**
+ * Disposes of the storage used by a USet object.  This function should
+ * be called exactly once for objects returned by uset_open().
+ * @param set the object to dispose of
+ * @stable ICU 2.4
+ */
+U_STABLE void U_EXPORT2
+uset_close(USet* set);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUSetPointer
+ * "Smart pointer" class, closes a USet via uset_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUSetPointer, USet, uset_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Returns a copy of this object.
+ * If this set is frozen, then the clone will be frozen as well.
+ * Use uset_cloneAsThawed() for a mutable clone of a frozen set.
+ * @param set the original set
+ * @return the newly allocated copy of the set
+ * @see uset_cloneAsThawed
+ * @stable ICU 3.8
+ */
+U_STABLE USet * U_EXPORT2
+uset_clone(const USet *set);
+
+/**
+ * Determines whether the set has been frozen (made immutable) or not.
+ * See the ICU4J Freezable interface for details.
+ * @param set the set
+ * @return TRUE/FALSE for whether the set has been frozen
+ * @see uset_freeze
+ * @see uset_cloneAsThawed
+ * @stable ICU 3.8
+ */
+U_STABLE UBool U_EXPORT2
+uset_isFrozen(const USet *set);
+
+/**
+ * Freeze the set (make it immutable).
+ * Once frozen, it cannot be unfrozen and is therefore thread-safe
+ * until it is deleted.
+ * See the ICU4J Freezable interface for details.
+ * Freezing the set may also make some operations faster, for example
+ * uset_contains() and uset_span().
+ * A frozen set will not be modified. (It remains frozen.)
+ * @param set the set
+ * @return the same set, now frozen
+ * @see uset_isFrozen
+ * @see uset_cloneAsThawed
+ * @stable ICU 3.8
+ */
+U_STABLE void U_EXPORT2
+uset_freeze(USet *set);
+
+/**
+ * Clone the set and make the clone mutable.
+ * See the ICU4J Freezable interface for details.
+ * @param set the set
+ * @return the mutable clone
+ * @see uset_freeze
+ * @see uset_isFrozen
+ * @see uset_clone
+ * @stable ICU 3.8
+ */
+U_STABLE USet * U_EXPORT2
+uset_cloneAsThawed(const USet *set);
+
+/**
+ * Causes the USet object to represent the range <code>start - end</code>.
+ * If <code>start > end</code> then this USet is set to an empty range.
+ * A frozen set will not be modified.
+ * @param set the object to set to the given range
+ * @param start first character in the set, inclusive
+ * @param end last character in the set, inclusive
+ * @stable ICU 3.2
+ */
+U_STABLE void U_EXPORT2
+uset_set(USet* set,
+         UChar32 start, UChar32 end);
+
+/**
+ * Modifies the set to represent the set specified by the given
+ * pattern. See the UnicodeSet class description for the syntax of 
+ * the pattern language. See also the User Guide chapter about UnicodeSet.
+ * <em>Empties the set passed before applying the pattern.</em>
+ * A frozen set will not be modified.
+ * @param set               The set to which the pattern is to be applied. 
+ * @param pattern           A pointer to UChar string specifying what characters are in the set.
+ *                          The character at pattern[0] must be a '['.
+ * @param patternLength     The length of the UChar string. -1 if NUL terminated.
+ * @param options           A bitmask for options to apply to the pattern.
+ *                          Valid options are USET_IGNORE_SPACE and USET_CASE_INSENSITIVE.
+ * @param status            Returns an error if the pattern cannot be parsed.
+ * @return                  Upon successful parse, the value is either
+ *                          the index of the character after the closing ']' 
+ *                          of the parsed pattern.
+ *                          If the status code indicates failure, then the return value 
+ *                          is the index of the error in the source.
+ *
+ * @stable ICU 2.8
+ */
+U_STABLE int32_t U_EXPORT2 
+uset_applyPattern(USet *set,
+                  const UChar *pattern, int32_t patternLength,
+                  uint32_t options,
+                  UErrorCode *status);
+
+/**
+ * Modifies the set to contain those code points which have the given value
+ * for the given binary or enumerated property, as returned by
+ * u_getIntPropertyValue.  Prior contents of this set are lost.
+ * A frozen set will not be modified.
+ *
+ * @param set the object to contain the code points defined by the property
+ *
+ * @param prop a property in the range UCHAR_BIN_START..UCHAR_BIN_LIMIT-1
+ * or UCHAR_INT_START..UCHAR_INT_LIMIT-1
+ * or UCHAR_MASK_START..UCHAR_MASK_LIMIT-1.
+ *
+ * @param value a value in the range u_getIntPropertyMinValue(prop)..
+ * u_getIntPropertyMaxValue(prop), with one exception.  If prop is
+ * UCHAR_GENERAL_CATEGORY_MASK, then value should not be a UCharCategory, but
+ * rather a mask value produced by U_GET_GC_MASK().  This allows grouped
+ * categories such as [:L:] to be represented.
+ *
+ * @param ec error code input/output parameter
+ *
+ * @stable ICU 3.2
+ */
+U_STABLE void U_EXPORT2
+uset_applyIntPropertyValue(USet* set,
+                           UProperty prop, int32_t value, UErrorCode* ec);
+
+/**
+ * Modifies the set to contain those code points which have the
+ * given value for the given property.  Prior contents of this
+ * set are lost.
+ * A frozen set will not be modified.
+ *
+ * @param set the object to contain the code points defined by the given
+ * property and value alias
+ *
+ * @param prop a string specifying a property alias, either short or long.
+ * The name is matched loosely.  See PropertyAliases.txt for names and a
+ * description of loose matching.  If the value string is empty, then this
+ * string is interpreted as either a General_Category value alias, a Script
+ * value alias, a binary property alias, or a special ID.  Special IDs are
+ * matched loosely and correspond to the following sets:
+ *
+ * "ANY" = [\\u0000-\\U0010FFFF],
+ * "ASCII" = [\\u0000-\\u007F],
+ * "Assigned" = [:^Cn:].
+ *
+ * @param propLength the length of the prop, or -1 if NULL
+ *
+ * @param value a string specifying a value alias, either short or long.
+ * The name is matched loosely.  See PropertyValueAliases.txt for names
+ * and a description of loose matching.  In addition to aliases listed,
+ * numeric values and canonical combining classes may be expressed
+ * numerically, e.g., ("nv", "0.5") or ("ccc", "220").  The value string
+ * may also be empty.
+ *
+ * @param valueLength the length of the value, or -1 if NULL
+ *
+ * @param ec error code input/output parameter
+ *
+ * @stable ICU 3.2
+ */
+U_STABLE void U_EXPORT2
+uset_applyPropertyAlias(USet* set,
+                        const UChar *prop, int32_t propLength,
+                        const UChar *value, int32_t valueLength,
+                        UErrorCode* ec);
+
+/**
+ * Return true if the given position, in the given pattern, appears
+ * to be the start of a UnicodeSet pattern.
+ *
+ * @param pattern a string specifying the pattern
+ * @param patternLength the length of the pattern, or -1 if NULL
+ * @param pos the given position
+ * @stable ICU 3.2
+ */
+U_STABLE UBool U_EXPORT2
+uset_resemblesPattern(const UChar *pattern, int32_t patternLength,
+                      int32_t pos);
+
+/**
+ * Returns a string representation of this set.  If the result of
+ * calling this function is passed to a uset_openPattern(), it
+ * will produce another set that is equal to this one.
+ * @param set the set
+ * @param result the string to receive the rules, may be NULL
+ * @param resultCapacity the capacity of result, may be 0 if result is NULL
+ * @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.
+ * @param ec error code.
+ * @return length of string, possibly larger than resultCapacity
+ * @stable ICU 2.4
+ */
+U_STABLE int32_t U_EXPORT2
+uset_toPattern(const USet* set,
+               UChar* result, int32_t resultCapacity,
+               UBool escapeUnprintable,
+               UErrorCode* ec);
+
+/**
+ * Adds the given character to the given USet.  After this call,
+ * uset_contains(set, c) will return TRUE.
+ * A frozen set will not be modified.
+ * @param set the object to which to add the character
+ * @param c the character to add
+ * @stable ICU 2.4
+ */
+U_STABLE void U_EXPORT2
+uset_add(USet* set, UChar32 c);
+
+/**
+ * Adds all of the elements in the specified set to this set if
+ * they're not already present.  This operation effectively
+ * modifies this set so that its value is the <i>union</i> of the two
+ * sets.  The behavior of this operation is unspecified if the specified
+ * collection is modified while the operation is in progress.
+ * A frozen set will not be modified.
+ *
+ * @param set the object to which to add the set
+ * @param additionalSet the source set whose elements are to be added to this set.
+ * @stable ICU 2.6
+ */
+U_STABLE void U_EXPORT2
+uset_addAll(USet* set, const USet *additionalSet);
+
+/**
+ * Adds the given range of characters to the given USet.  After this call,
+ * uset_contains(set, start, end) will return TRUE.
+ * A frozen set will not be modified.
+ * @param set the object to which to add the character
+ * @param start the first character of the range to add, inclusive
+ * @param end the last character of the range to add, inclusive
+ * @stable ICU 2.2
+ */
+U_STABLE void U_EXPORT2
+uset_addRange(USet* set, UChar32 start, UChar32 end);
+
+/**
+ * Adds the given string to the given USet.  After this call,
+ * uset_containsString(set, str, strLen) will return TRUE.
+ * A frozen set will not be modified.
+ * @param set the object to which to add the character
+ * @param str the string to add
+ * @param strLen the length of the string or -1 if null terminated.
+ * @stable ICU 2.4
+ */
+U_STABLE void U_EXPORT2
+uset_addString(USet* set, const UChar* str, int32_t strLen);
+
+/**
+ * Adds each of the characters in this string to the set. Thus "ch" => {"c", "h"}
+ * If this set already any particular character, it has no effect on that character.
+ * A frozen set will not be modified.
+ * @param set the object to which to add the character
+ * @param str the source string
+ * @param strLen the length of the string or -1 if null terminated.
+ * @stable ICU 3.4
+ */
+U_STABLE void U_EXPORT2
+uset_addAllCodePoints(USet* set, const UChar *str, int32_t strLen);
+
+/**
+ * Removes the given character from the given USet.  After this call,
+ * uset_contains(set, c) will return FALSE.
+ * A frozen set will not be modified.
+ * @param set the object from which to remove the character
+ * @param c the character to remove
+ * @stable ICU 2.4
+ */
+U_STABLE void U_EXPORT2
+uset_remove(USet* set, UChar32 c);
+
+/**
+ * Removes the given range of characters from the given USet.  After this call,
+ * uset_contains(set, start, end) will return FALSE.
+ * A frozen set will not be modified.
+ * @param set the object to which to add the character
+ * @param start the first character of the range to remove, inclusive
+ * @param end the last character of the range to remove, inclusive
+ * @stable ICU 2.2
+ */
+U_STABLE void U_EXPORT2
+uset_removeRange(USet* set, UChar32 start, UChar32 end);
+
+/**
+ * Removes the given string to the given USet.  After this call,
+ * uset_containsString(set, str, strLen) will return FALSE.
+ * A frozen set will not be modified.
+ * @param set the object to which to add the character
+ * @param str the string to remove
+ * @param strLen the length of the string or -1 if null terminated.
+ * @stable ICU 2.4
+ */
+U_STABLE void U_EXPORT2
+uset_removeString(USet* set, const UChar* str, int32_t strLen);
+
+/**
+ * Removes from this set all of its elements that are contained in the
+ * specified set.  This operation effectively modifies this
+ * set so that its value is the <i>asymmetric set difference</i> of
+ * the two sets.
+ * A frozen set will not be modified.
+ * @param set the object from which the elements are to be removed
+ * @param removeSet the object that defines which elements will be
+ * removed from this set
+ * @stable ICU 3.2
+ */
+U_STABLE void U_EXPORT2
+uset_removeAll(USet* set, const USet* removeSet);
+
+/**
+ * Retain only the elements in this set that are contained in the
+ * specified range.  If <code>start > end</code> then an empty range is
+ * retained, leaving the set empty.  This is equivalent to
+ * a boolean logic AND, or a set INTERSECTION.
+ * A frozen set will not be modified.
+ *
+ * @param set the object for which to retain only the specified range
+ * @param start first character, inclusive, of range to be retained
+ * to this set.
+ * @param end last character, inclusive, of range to be retained
+ * to this set.
+ * @stable ICU 3.2
+ */
+U_STABLE void U_EXPORT2
+uset_retain(USet* set, UChar32 start, UChar32 end);
+
+/**
+ * Retains only the elements in this set that are contained in the
+ * specified set.  In other words, removes from this set all of
+ * its elements that are not contained in the specified set.  This
+ * operation effectively modifies this set so that its value is
+ * the <i>intersection</i> of the two sets.
+ * A frozen set will not be modified.
+ *
+ * @param set the object on which to perform the retain
+ * @param retain set that defines which elements this set will retain
+ * @stable ICU 3.2
+ */
+U_STABLE void U_EXPORT2
+uset_retainAll(USet* set, const USet* retain);
+
+/**
+ * Reallocate this objects internal structures to take up the least
+ * possible space, without changing this object's value.
+ * A frozen set will not be modified.
+ *
+ * @param set the object on which to perfrom the compact
+ * @stable ICU 3.2
+ */
+U_STABLE void U_EXPORT2
+uset_compact(USet* set);
+
+/**
+ * Inverts this set.  This operation modifies this set so that
+ * its value is its complement.  This operation does not affect
+ * the multicharacter strings, if any.
+ * A frozen set will not be modified.
+ * @param set the set
+ * @stable ICU 2.4
+ */
+U_STABLE void U_EXPORT2
+uset_complement(USet* set);
+
+/**
+ * Complements in this set all elements contained in the specified
+ * set.  Any character in the other set will be removed if it is
+ * in this set, or will be added if it is not in this set.
+ * A frozen set will not be modified.
+ *
+ * @param set the set with which to complement
+ * @param complement set that defines which elements will be xor'ed
+ * from this set.
+ * @stable ICU 3.2
+ */
+U_STABLE void U_EXPORT2
+uset_complementAll(USet* set, const USet* complement);
+
+/**
+ * Removes all of the elements from this set.  This set will be
+ * empty after this call returns.
+ * A frozen set will not be modified.
+ * @param set the set
+ * @stable ICU 2.4
+ */
+U_STABLE void U_EXPORT2
+uset_clear(USet* set);
+
+/**
+ * Close this set over the given attribute.  For the attribute
+ * USET_CASE, the result is to modify this set so that:
+ *
+ * 1. For each character or string 'a' in this set, all strings or
+ * characters 'b' such that foldCase(a) == foldCase(b) are added
+ * to this set.
+ *
+ * 2. For each string 'e' in the resulting set, if e !=
+ * foldCase(e), 'e' will be removed.
+ *
+ * Example: [aq\\u00DF{Bc}{bC}{Fi}] => [aAqQ\\u00DF\\uFB01{ss}{bc}{fi}]
+ *
+ * (Here foldCase(x) refers to the operation u_strFoldCase, and a
+ * == b denotes that the contents are the same, not pointer
+ * comparison.)
+ *
+ * A frozen set will not be modified.
+ *
+ * @param set the set
+ *
+ * @param attributes bitmask for attributes to close over.
+ * Currently only the USET_CASE bit is supported.  Any undefined bits
+ * are ignored.
+ * @stable ICU 4.2
+ */
+U_STABLE void U_EXPORT2
+uset_closeOver(USet* set, int32_t attributes);
+
+/**
+ * Remove all strings from this set.
+ *
+ * @param set the set
+ * @stable ICU 4.2
+ */
+U_STABLE void U_EXPORT2
+uset_removeAllStrings(USet* set);
+
+/**
+ * Returns TRUE if the given USet contains no characters and no
+ * strings.
+ * @param set the set
+ * @return true if set is empty
+ * @stable ICU 2.4
+ */
+U_STABLE UBool U_EXPORT2
+uset_isEmpty(const USet* set);
+
+/**
+ * Returns TRUE if the given USet contains the given character.
+ * This function works faster with a frozen set.
+ * @param set the set
+ * @param c The codepoint to check for within the set
+ * @return true if set contains c
+ * @stable ICU 2.4
+ */
+U_STABLE UBool U_EXPORT2
+uset_contains(const USet* set, UChar32 c);
+
+/**
+ * Returns TRUE if the given USet contains all characters c
+ * where start <= c && c <= end.
+ * @param set the set
+ * @param start the first character of the range to test, inclusive
+ * @param end the last character of the range to test, inclusive
+ * @return TRUE if set contains the range
+ * @stable ICU 2.2
+ */
+U_STABLE UBool U_EXPORT2
+uset_containsRange(const USet* set, UChar32 start, UChar32 end);
+
+/**
+ * Returns TRUE if the given USet contains the given string.
+ * @param set the set
+ * @param str the string
+ * @param strLen the length of the string or -1 if null terminated.
+ * @return true if set contains str
+ * @stable ICU 2.4
+ */
+U_STABLE UBool U_EXPORT2
+uset_containsString(const USet* set, const UChar* str, int32_t strLen);
+
+/**
+ * Returns the index of the given character within this set, where
+ * the set is ordered by ascending code point.  If the character
+ * is not in this set, return -1.  The inverse of this method is
+ * <code>charAt()</code>.
+ * @param set the set
+ * @param c the character to obtain the index for
+ * @return an index from 0..size()-1, or -1
+ * @stable ICU 3.2
+ */
+U_STABLE int32_t U_EXPORT2
+uset_indexOf(const USet* set, UChar32 c);
+
+/**
+ * Returns the character at the given index within this set, where
+ * the set is ordered by ascending code point.  If the index is
+ * out of range, return (UChar32)-1.  The inverse of this method is
+ * <code>indexOf()</code>.
+ * @param set the set
+ * @param charIndex an index from 0..size()-1 to obtain the char for
+ * @return the character at the given index, or (UChar32)-1.
+ * @stable ICU 3.2
+ */
+U_STABLE UChar32 U_EXPORT2
+uset_charAt(const USet* set, int32_t charIndex);
+
+/**
+ * Returns the number of characters and strings contained in the given
+ * USet.
+ * @param set the set
+ * @return a non-negative integer counting the characters and strings
+ * contained in set
+ * @stable ICU 2.4
+ */
+U_STABLE int32_t U_EXPORT2
+uset_size(const USet* set);
+
+/**
+ * Returns the number of items in this set.  An item is either a range
+ * of characters or a single multicharacter string.
+ * @param set the set
+ * @return a non-negative integer counting the character ranges
+ * and/or strings contained in set
+ * @stable ICU 2.4
+ */
+U_STABLE int32_t U_EXPORT2
+uset_getItemCount(const USet* set);
+
+/**
+ * Returns an item of this set.  An item is either a range of
+ * characters or a single multicharacter string.
+ * @param set the set
+ * @param itemIndex a non-negative integer in the range 0..
+ * uset_getItemCount(set)-1
+ * @param start pointer to variable to receive first character
+ * in range, inclusive
+ * @param end pointer to variable to receive last character in range,
+ * inclusive
+ * @param str buffer to receive the string, may be NULL
+ * @param strCapacity capacity of str, or 0 if str is NULL
+ * @param ec error code
+ * @return the length of the string (>= 2), or 0 if the item is a
+ * range, in which case it is the range *start..*end, or -1 if
+ * itemIndex is out of range
+ * @stable ICU 2.4
+ */
+U_STABLE int32_t U_EXPORT2
+uset_getItem(const USet* set, int32_t itemIndex,
+             UChar32* start, UChar32* end,
+             UChar* str, int32_t strCapacity,
+             UErrorCode* ec);
+
+/**
+ * Returns true if set1 contains all the characters and strings
+ * of set2. It answers the question, 'Is set1 a superset of set2?'
+ * @param set1 set to be checked for containment
+ * @param set2 set to be checked for containment
+ * @return true if the test condition is met
+ * @stable ICU 3.2
+ */
+U_STABLE UBool U_EXPORT2
+uset_containsAll(const USet* set1, const USet* set2);
+
+/**
+ * Returns true if this set contains all the characters
+ * of the given string. This is does not check containment of grapheme
+ * clusters, like uset_containsString.
+ * @param set set of characters to be checked for containment
+ * @param str string containing codepoints to be checked for containment
+ * @param strLen the length of the string or -1 if null terminated.
+ * @return true if the test condition is met
+ * @stable ICU 3.4
+ */
+U_STABLE UBool U_EXPORT2
+uset_containsAllCodePoints(const USet* set, const UChar *str, int32_t strLen);
+
+/**
+ * Returns true if set1 contains none of the characters and strings
+ * of set2. It answers the question, 'Is set1 a disjoint set of set2?'
+ * @param set1 set to be checked for containment
+ * @param set2 set to be checked for containment
+ * @return true if the test condition is met
+ * @stable ICU 3.2
+ */
+U_STABLE UBool U_EXPORT2
+uset_containsNone(const USet* set1, const USet* set2);
+
+/**
+ * Returns true if set1 contains some of the characters and strings
+ * of set2. It answers the question, 'Does set1 and set2 have an intersection?'
+ * @param set1 set to be checked for containment
+ * @param set2 set to be checked for containment
+ * @return true if the test condition is met
+ * @stable ICU 3.2
+ */
+U_STABLE UBool U_EXPORT2
+uset_containsSome(const USet* set1, const USet* set2);
+
+/**
+ * Returns the length of the initial substring of the input string which
+ * consists only of characters and strings that are contained in this set
+ * (USET_SPAN_CONTAINED, USET_SPAN_SIMPLE),
+ * or only of characters and strings that are not contained
+ * in this set (USET_SPAN_NOT_CONTAINED).
+ * See USetSpanCondition for details.
+ * Similar to the strspn() C library function.
+ * Unpaired surrogates are treated according to contains() of their surrogate code points.
+ * This function works faster with a frozen set and with a non-negative string length argument.
+ * @param set the set
+ * @param s start of the string
+ * @param length of the string; can be -1 for NUL-terminated
+ * @param spanCondition specifies the containment condition
+ * @return the length of the initial substring according to the spanCondition;
+ *         0 if the start of the string does not fit the spanCondition
+ * @stable ICU 3.8
+ * @see USetSpanCondition
+ */
+U_STABLE int32_t U_EXPORT2
+uset_span(const USet *set, const UChar *s, int32_t length, USetSpanCondition spanCondition);
+
+/**
+ * Returns the start of the trailing substring of the input string which
+ * consists only of characters and strings that are contained in this set
+ * (USET_SPAN_CONTAINED, USET_SPAN_SIMPLE),
+ * or only of characters and strings that are not contained
+ * in this set (USET_SPAN_NOT_CONTAINED).
+ * See USetSpanCondition for details.
+ * Unpaired surrogates are treated according to contains() of their surrogate code points.
+ * This function works faster with a frozen set and with a non-negative string length argument.
+ * @param set the set
+ * @param s start of the string
+ * @param length of the string; can be -1 for NUL-terminated
+ * @param spanCondition specifies the containment condition
+ * @return the start of the trailing substring according to the spanCondition;
+ *         the string length if the end of the string does not fit the spanCondition
+ * @stable ICU 3.8
+ * @see USetSpanCondition
+ */
+U_STABLE int32_t U_EXPORT2
+uset_spanBack(const USet *set, const UChar *s, int32_t length, USetSpanCondition spanCondition);
+
+/**
+ * Returns the length of the initial substring of the input string which
+ * consists only of characters and strings that are contained in this set
+ * (USET_SPAN_CONTAINED, USET_SPAN_SIMPLE),
+ * or only of characters and strings that are not contained
+ * in this set (USET_SPAN_NOT_CONTAINED).
+ * See USetSpanCondition for details.
+ * Similar to the strspn() C library function.
+ * Malformed byte sequences are treated according to contains(0xfffd).
+ * This function works faster with a frozen set and with a non-negative string length argument.
+ * @param set the set
+ * @param s start of the string (UTF-8)
+ * @param length of the string; can be -1 for NUL-terminated
+ * @param spanCondition specifies the containment condition
+ * @return the length of the initial substring according to the spanCondition;
+ *         0 if the start of the string does not fit the spanCondition
+ * @stable ICU 3.8
+ * @see USetSpanCondition
+ */
+U_STABLE int32_t U_EXPORT2
+uset_spanUTF8(const USet *set, const char *s, int32_t length, USetSpanCondition spanCondition);
+
+/**
+ * Returns the start of the trailing substring of the input string which
+ * consists only of characters and strings that are contained in this set
+ * (USET_SPAN_CONTAINED, USET_SPAN_SIMPLE),
+ * or only of characters and strings that are not contained
+ * in this set (USET_SPAN_NOT_CONTAINED).
+ * See USetSpanCondition for details.
+ * Malformed byte sequences are treated according to contains(0xfffd).
+ * This function works faster with a frozen set and with a non-negative string length argument.
+ * @param set the set
+ * @param s start of the string (UTF-8)
+ * @param length of the string; can be -1 for NUL-terminated
+ * @param spanCondition specifies the containment condition
+ * @return the start of the trailing substring according to the spanCondition;
+ *         the string length if the end of the string does not fit the spanCondition
+ * @stable ICU 3.8
+ * @see USetSpanCondition
+ */
+U_STABLE int32_t U_EXPORT2
+uset_spanBackUTF8(const USet *set, const char *s, int32_t length, USetSpanCondition spanCondition);
+
+/**
+ * Returns true if set1 contains all of the characters and strings
+ * of set2, and vis versa. It answers the question, 'Is set1 equal to set2?'
+ * @param set1 set to be checked for containment
+ * @param set2 set to be checked for containment
+ * @return true if the test condition is met
+ * @stable ICU 3.2
+ */
+U_STABLE UBool U_EXPORT2
+uset_equals(const USet* set1, const USet* set2);
+
+/*********************************************************************
+ * Serialized set API
+ *********************************************************************/
+
+/**
+ * Serializes this set into an array of 16-bit integers.  Serialization
+ * (currently) only records the characters in the set; multicharacter
+ * strings are ignored.
+ *
+ * The array
+ * has following format (each line is one 16-bit integer):
+ *
+ *  length     = (n+2*m) | (m!=0?0x8000:0)
+ *  bmpLength  = n; present if m!=0
+ *  bmp[0]
+ *  bmp[1]
+ *  ...
+ *  bmp[n-1]
+ *  supp-high[0]
+ *  supp-low[0]
+ *  supp-high[1]
+ *  supp-low[1]
+ *  ...
+ *  supp-high[m-1]
+ *  supp-low[m-1]
+ *
+ * The array starts with a header.  After the header are n bmp
+ * code points, then m supplementary code points.  Either n or m
+ * or both may be zero.  n+2*m is always <= 0x7FFF.
+ *
+ * If there are no supplementary characters (if m==0) then the
+ * header is one 16-bit integer, 'length', with value n.
+ *
+ * If there are supplementary characters (if m!=0) then the header
+ * is two 16-bit integers.  The first, 'length', has value
+ * (n+2*m)|0x8000.  The second, 'bmpLength', has value n.
+ *
+ * After the header the code points are stored in ascending order.
+ * Supplementary code points are stored as most significant 16
+ * bits followed by least significant 16 bits.
+ *
+ * @param set the set
+ * @param dest pointer to buffer of destCapacity 16-bit integers.
+ * May be NULL only if destCapacity is zero.
+ * @param destCapacity size of dest, or zero.  Must not be negative.
+ * @param pErrorCode pointer to the error code.  Will be set to
+ * U_INDEX_OUTOFBOUNDS_ERROR if n+2*m > 0x7FFF.  Will be set to
+ * U_BUFFER_OVERFLOW_ERROR if n+2*m+(m!=0?2:1) > destCapacity.
+ * @return the total length of the serialized format, including
+ * the header, that is, n+2*m+(m!=0?2:1), or 0 on error other
+ * than U_BUFFER_OVERFLOW_ERROR.
+ * @stable ICU 2.4
+ */
+U_STABLE int32_t U_EXPORT2
+uset_serialize(const USet* set, uint16_t* dest, int32_t destCapacity, UErrorCode* pErrorCode);
+
+/**
+ * Given a serialized array, fill in the given serialized set object.
+ * @param fillSet pointer to result
+ * @param src pointer to start of array
+ * @param srcLength length of array
+ * @return true if the given array is valid, otherwise false
+ * @stable ICU 2.4
+ */
+U_STABLE UBool U_EXPORT2
+uset_getSerializedSet(USerializedSet* fillSet, const uint16_t* src, int32_t srcLength);
+
+/**
+ * Set the USerializedSet to contain the given character (and nothing
+ * else).
+ * @param fillSet pointer to result
+ * @param c The codepoint to set
+ * @stable ICU 2.4
+ */
+U_STABLE void U_EXPORT2
+uset_setSerializedToOne(USerializedSet* fillSet, UChar32 c);
+
+/**
+ * Returns TRUE if the given USerializedSet contains the given
+ * character.
+ * @param set the serialized set
+ * @param c The codepoint to check for within the set
+ * @return true if set contains c
+ * @stable ICU 2.4
+ */
+U_STABLE UBool U_EXPORT2
+uset_serializedContains(const USerializedSet* set, UChar32 c);
+
+/**
+ * Returns the number of disjoint ranges of characters contained in
+ * the given serialized set.  Ignores any strings contained in the
+ * set.
+ * @param set the serialized set
+ * @return a non-negative integer counting the character ranges
+ * contained in set
+ * @stable ICU 2.4
+ */
+U_STABLE int32_t U_EXPORT2
+uset_getSerializedRangeCount(const USerializedSet* set);
+
+/**
+ * Returns a range of characters contained in the given serialized
+ * set.
+ * @param set the serialized set
+ * @param rangeIndex a non-negative integer in the range 0..
+ * uset_getSerializedRangeCount(set)-1
+ * @param pStart pointer to variable to receive first character
+ * in range, inclusive
+ * @param pEnd pointer to variable to receive last character in range,
+ * inclusive
+ * @return true if rangeIndex is valid, otherwise false
+ * @stable ICU 2.4
+ */
+U_STABLE UBool U_EXPORT2
+uset_getSerializedRange(const USerializedSet* set, int32_t rangeIndex,
+                        UChar32* pStart, UChar32* pEnd);
+
+#endif
diff --git a/source/common/unicode/usetiter.h b/source/common/unicode/usetiter.h
new file mode 100644
index 0000000..43374b2
--- /dev/null
+++ b/source/common/unicode/usetiter.h
@@ -0,0 +1,318 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2008, International Business Machines
+* Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+#ifndef USETITER_H
+#define USETITER_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+
+/**
+ * \file 
+ * \brief C++ API: UnicodeSetIterator iterates over the contents of a UnicodeSet.
+ */
+
+U_NAMESPACE_BEGIN
+
+class UnicodeSet;
+class UnicodeString;
+
+/**
+ *
+ * UnicodeSetIterator iterates over the contents of a UnicodeSet.  It
+ * iterates over either code points or code point ranges.  After all
+ * code points or ranges have been returned, it returns the
+ * multicharacter strings of the UnicodeSet, if any.
+ *
+ * This class is not intended to be subclassed.  Consider any fields
+ *  or methods declared as "protected" to be private.  The use of
+ *  protected in this class is an artifact of history.
+ *
+ * <p>To iterate over code points and strings, use a loop like this:
+ * <pre>
+ * UnicodeSetIterator it(set);
+ * while (it.next()) {
+ *     processItem(it.getString());
+ * }
+ * </pre>
+ * <p>Each item in the set is accessed as a string.  Set elements
+ *    consisting of single code points are returned as strings containing
+ *    just the one code point.
+ *
+ * <p>To iterate over code point ranges, instead of individual code points,
+ *    use a loop like this:
+ * <pre>
+ * UnicodeSetIterator it(set);
+ * while (it.nextRange()) {
+ *   if (it.isString()) {
+ *     processString(it.getString());
+ *   } else {
+ *     processCodepointRange(it.getCodepoint(), it.getCodepointEnd());
+ *   }
+ * }
+ * </pre>
+ * @author M. Davis
+ * @stable ICU 2.4
+ */
+class U_COMMON_API UnicodeSetIterator : public UObject {
+
+ protected:
+
+    /**
+     * Value of <tt>codepoint</tt> if the iterator points to a string.
+     * If <tt>codepoint == IS_STRING</tt>, then examine
+     * <tt>string</tt> for the current iteration result.
+     * @stable ICU 2.4
+     */
+    enum { IS_STRING = -1 };
+
+    /**
+     * Current code point, or the special value <tt>IS_STRING</tt>, if
+     * the iterator points to a string.
+     * @stable ICU 2.4
+     */
+    UChar32 codepoint;
+
+    /**
+     * When iterating over ranges using <tt>nextRange()</tt>,
+     * <tt>codepointEnd</tt> contains the inclusive end of the
+     * iteration range, if <tt>codepoint != IS_STRING</tt>.  If
+     * iterating over code points using <tt>next()</tt>, or if
+     * <tt>codepoint == IS_STRING</tt>, then the value of
+     * <tt>codepointEnd</tt> is undefined.
+     * @stable ICU 2.4
+     */
+    UChar32 codepointEnd;
+
+    /**
+     * If <tt>codepoint == IS_STRING</tt>, then <tt>string</tt> points
+     * to the current string.  If <tt>codepoint != IS_STRING</tt>, the
+     * value of <tt>string</tt> is undefined.
+     * @stable ICU 2.4
+     */
+    const UnicodeString* string;
+
+ public:
+
+    /**
+     * Create an iterator over the given set.  The iterator is valid
+     * only so long as <tt>set</tt> is valid.
+     * @param set set to iterate over
+     * @stable ICU 2.4
+     */
+    UnicodeSetIterator(const UnicodeSet& set);
+
+    /**
+     * Create an iterator over nothing.  <tt>next()</tt> and
+     * <tt>nextRange()</tt> return false. This is a convenience
+     * constructor allowing the target to be set later.
+     * @stable ICU 2.4
+     */
+    UnicodeSetIterator();
+
+    /**
+     * Destructor.
+     * @stable ICU 2.4
+     */
+    virtual ~UnicodeSetIterator();
+
+    /**
+     * Returns true if the current element is a string.  If so, the
+     * caller can retrieve it with <tt>getString()</tt>.  If this
+     * method returns false, the current element is a code point or
+     * code point range, depending on whether <tt>next()</tt> or
+     * <tt>nextRange()</tt> was called.
+     * Elements of types string and codepoint can both be retrieved
+     * with the function <tt>getString()</tt>.
+     * Elements of type codepoint can also be retrieved with
+     * <tt>getCodepoint()</tt>.
+     * For ranges, <tt>getCodepoint()</tt> returns the starting codepoint
+     * of the range, and <tt>getCodepointEnd()</tt> returns the end
+     * of the range.
+     * @stable ICU 2.4
+     */
+    inline UBool isString() const;
+
+    /**
+     * Returns the current code point, if <tt>isString()</tt> returned
+     * false.  Otherwise returns an undefined result.
+     * @stable ICU 2.4
+     */
+    inline UChar32 getCodepoint() const;
+
+    /**
+     * Returns the end of the current code point range, if
+     * <tt>isString()</tt> returned false and <tt>nextRange()</tt> was
+     * called.  Otherwise returns an undefined result.
+     * @stable ICU 2.4
+     */
+    inline UChar32 getCodepointEnd() const;
+
+    /**
+     * Returns the current string, if <tt>isString()</tt> returned
+     * true.  If the current iteration item is a code point, a UnicodeString
+     * containing that single code point is returned.
+     *
+     * Ownership of the returned string remains with the iterator.
+     * The string is guaranteed to remain valid only until the iterator is
+     *   advanced to the next item, or until the iterator is deleted.
+     * 
+     * @stable ICU 2.4
+     */
+    const UnicodeString& getString();
+
+    /**
+     * Advances the iteration position to the next element in the set, 
+     * which can be either a single code point or a string.  
+     * If there are no more elements in the set, return false.
+     *
+     * <p>
+     * If <tt>isString() == TRUE</tt>, the value is a
+     * string, otherwise the value is a
+     * single code point.  Elements of either type can be retrieved
+     * with the function <tt>getString()</tt>, while elements of
+     * consisting of a single code point can be retrieved with
+     * <tt>getCodepoint()</tt>
+     *
+     * <p>The order of iteration is all code points in sorted order,
+     * followed by all strings sorted order.    Do not mix
+     * calls to <tt>next()</tt> and <tt>nextRange()</tt> without
+     * calling <tt>reset()</tt> between them.  The results of doing so
+     * are undefined.
+     *
+     * @return true if there was another element in the set.
+     * @stable ICU 2.4
+     */
+    UBool next();
+
+    /**
+     * Returns the next element in the set, either a code point range
+     * or a string.  If there are no more elements in the set, return
+     * false.  If <tt>isString() == TRUE</tt>, the value is a
+     * string and can be accessed with <tt>getString()</tt>.  Otherwise the value is a
+     * range of one or more code points from <tt>getCodepoint()</tt> to
+     * <tt>getCodepointeEnd()</tt> inclusive.
+     *
+     * <p>The order of iteration is all code points ranges in sorted
+     * order, followed by all strings sorted order.  Ranges are
+     * disjoint and non-contiguous.  The value returned from <tt>getString()</tt>
+     * is undefined unless <tt>isString() == TRUE</tt>.  Do not mix calls to
+     * <tt>next()</tt> and <tt>nextRange()</tt> without calling
+     * <tt>reset()</tt> between them.  The results of doing so are
+     * undefined.
+     *
+     * @return true if there was another element in the set.
+     * @stable ICU 2.4
+     */
+    UBool nextRange();
+
+    /**
+     * Sets this iterator to visit the elements of the given set and
+     * resets it to the start of that set.  The iterator is valid only
+     * so long as <tt>set</tt> is valid.
+     * @param set the set to iterate over.
+     * @stable ICU 2.4
+     */
+    void reset(const UnicodeSet& set);
+
+    /**
+     * Resets this iterator to the start of the set.
+     * @stable ICU 2.4
+     */
+    void reset();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.4
+     */
+    static UClassID U_EXPORT2 getStaticClassID();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.4
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    // ======================= PRIVATES ===========================
+
+ protected:
+
+    // endElement and nextElements are really UChar32's, but we keep
+    // them as signed int32_t's so we can do comparisons with
+    // endElement set to -1.  Leave them as int32_t's.
+    /** The set
+     * @stable ICU 2.4
+     */
+    const UnicodeSet* set;
+    /** End range
+     * @stable ICU 2.4
+     */
+    int32_t endRange;
+    /** Range
+     * @stable ICU 2.4
+     */
+    int32_t range;
+    /** End element
+     * @stable ICU 2.4
+     */
+    int32_t endElement;
+    /** Next element
+     * @stable ICU 2.4
+     */
+    int32_t nextElement;
+    //UBool abbreviated;
+    /** Next string
+     * @stable ICU 2.4
+     */
+    int32_t nextString;
+    /** String count
+     * @stable ICU 2.4
+     */
+    int32_t stringCount;
+
+    /**
+     *  Points to the string to use when the caller asks for a
+     *  string and the current iteration item is a code point, not a string.
+     *  @internal
+     */
+    UnicodeString *cpString;
+
+    /** Copy constructor. Disallowed.
+     * @stable ICU 2.4
+     */
+    UnicodeSetIterator(const UnicodeSetIterator&); // disallow
+
+    /** Assignment operator. Disallowed.
+     * @stable ICU 2.4
+     */
+    UnicodeSetIterator& operator=(const UnicodeSetIterator&); // disallow
+
+    /** Load range
+     * @stable ICU 2.4
+     */
+    virtual void loadRange(int32_t range);
+
+};
+
+inline UBool UnicodeSetIterator::isString() const {
+    return codepoint == (UChar32)IS_STRING;
+}
+
+inline UChar32 UnicodeSetIterator::getCodepoint() const {
+    return codepoint;
+}
+
+inline UChar32 UnicodeSetIterator::getCodepointEnd() const {
+    return codepointEnd;
+}
+
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/unicode/ushape.h b/source/common/unicode/ushape.h
new file mode 100644
index 0000000..6c3655f
--- /dev/null
+++ b/source/common/unicode/ushape.h
@@ -0,0 +1,474 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2000-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  ushape.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2000jun29
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __USHAPE_H__
+#define __USHAPE_H__
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C API:  Arabic shaping
+ * 
+ */
+
+/**
+ * Shape Arabic text on a character basis.
+ *
+ * <p>This function performs basic operations for "shaping" Arabic text. It is most
+ * useful for use with legacy data formats and legacy display technology
+ * (simple terminals). All operations are performed on Unicode characters.</p>
+ *
+ * <p>Text-based shaping means that some character code points in the text are
+ * replaced by others depending on the context. It transforms one kind of text
+ * into another. In comparison, modern displays for Arabic text select
+ * appropriate, context-dependent font glyphs for each text element, which means
+ * that they transform text into a glyph vector.</p>
+ *
+ * <p>Text transformations are necessary when modern display technology is not
+ * available or when text needs to be transformed to or from legacy formats that
+ * use "shaped" characters. Since the Arabic script is cursive, connecting
+ * adjacent letters to each other, computers select images for each letter based
+ * on the surrounding letters. This usually results in four images per Arabic
+ * letter: initial, middle, final, and isolated forms. In Unicode, on the other
+ * hand, letters are normally stored abstract, and a display system is expected
+ * to select the necessary glyphs. (This makes searching and other text
+ * processing easier because the same letter has only one code.) It is possible
+ * to mimic this with text transformations because there are characters in
+ * Unicode that are rendered as letters with a specific shape
+ * (or cursive connectivity). They were included for interoperability with
+ * legacy systems and codepages, and for unsophisticated display systems.</p>
+ *
+ * <p>A second kind of text transformations is supported for Arabic digits:
+ * For compatibility with legacy codepages that only include European digits,
+ * it is possible to replace one set of digits by another, changing the
+ * character code points. These operations can be performed for either
+ * Arabic-Indic Digits (U+0660...U+0669) or Eastern (Extended) Arabic-Indic
+ * digits (U+06f0...U+06f9).</p>
+ *
+ * <p>Some replacements may result in more or fewer characters (code points).
+ * By default, this means that the destination buffer may receive text with a
+ * length different from the source length. Some legacy systems rely on the
+ * length of the text to be constant. They expect extra spaces to be added
+ * or consumed either next to the affected character or at the end of the
+ * text.</p>
+ *
+ * <p>For details about the available operations, see the description of the
+ * <code>U_SHAPE_...</code> options.</p>
+ *
+ * @param source The input text.
+ *
+ * @param sourceLength The number of UChars in <code>source</code>.
+ *
+ * @param dest The destination buffer that will receive the results of the
+ *             requested operations. It may be <code>NULL</code> only if
+ *             <code>destSize</code> is 0. The source and destination must not
+ *             overlap.
+ *
+ * @param destSize The size (capacity) of the destination buffer in UChars.
+ *                 If <code>destSize</code> is 0, then no output is produced,
+ *                 but the necessary buffer size is returned ("preflighting").
+ *
+ * @param options This is a 32-bit set of flags that specify the operations
+ *                that are performed on the input text. If no error occurs,
+ *                then the result will always be written to the destination
+ *                buffer.
+ *
+ * @param pErrorCode must be a valid pointer to an error code value,
+ *        which must not indicate a failure before the function call.
+ *
+ * @return The number of UChars written to the destination buffer.
+ *         If an error occured, then no output was written, or it may be
+ *         incomplete. If <code>U_BUFFER_OVERFLOW_ERROR</code> is set, then
+ *         the return value indicates the necessary destination buffer size.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_shapeArabic(const UChar *source, int32_t sourceLength,
+              UChar *dest, int32_t destSize,
+              uint32_t options,
+              UErrorCode *pErrorCode);
+
+/**
+ * Memory option: allow the result to have a different length than the source.
+ * Affects: LamAlef options
+ * @stable ICU 2.0
+ */
+#define U_SHAPE_LENGTH_GROW_SHRINK              0
+
+/**
+ * Memory option: allow the result to have a different length than the source.
+ * Affects: LamAlef options
+ * This option is an alias to U_SHAPE_LENGTH_GROW_SHRINK
+ * @stable ICU 4.2
+ */
+#define U_SHAPE_LAMALEF_RESIZE                  0 
+
+/**
+ * Memory option: the result must have the same length as the source.
+ * If more room is necessary, then try to consume spaces next to modified characters.
+ * @stable ICU 2.0
+ */
+#define U_SHAPE_LENGTH_FIXED_SPACES_NEAR        1
+
+/**
+ * Memory option: the result must have the same length as the source.
+ * If more room is necessary, then try to consume spaces next to modified characters.
+ * Affects: LamAlef options
+ * This option is an alias to U_SHAPE_LENGTH_FIXED_SPACES_NEAR
+ * @stable ICU 4.2
+ */
+#define U_SHAPE_LAMALEF_NEAR                    1 
+
+/**
+ * Memory option: the result must have the same length as the source.
+ * If more room is necessary, then try to consume spaces at the end of the text.
+ * @stable ICU 2.0
+ */
+#define U_SHAPE_LENGTH_FIXED_SPACES_AT_END      2
+
+/**
+ * Memory option: the result must have the same length as the source.
+ * If more room is necessary, then try to consume spaces at the end of the text.
+ * Affects: LamAlef options
+ * This option is an alias to U_SHAPE_LENGTH_FIXED_SPACES_AT_END
+ * @stable ICU 4.2
+ */
+#define U_SHAPE_LAMALEF_END                     2 
+
+/**
+ * Memory option: the result must have the same length as the source.
+ * If more room is necessary, then try to consume spaces at the beginning of the text.
+ * @stable ICU 2.0
+ */
+#define U_SHAPE_LENGTH_FIXED_SPACES_AT_BEGINNING 3
+
+/**
+ * Memory option: the result must have the same length as the source.
+ * If more room is necessary, then try to consume spaces at the beginning of the text.
+ * Affects: LamAlef options
+ * This option is an alias to U_SHAPE_LENGTH_FIXED_SPACES_AT_BEGINNING
+ * @stable ICU 4.2
+ */
+#define U_SHAPE_LAMALEF_BEGIN                    3 
+
+
+/**
+ * Memory option: the result must have the same length as the source.
+ * Shaping Mode: For each LAMALEF character found, expand LAMALEF using space at end.
+ *               If there is no space at end, use spaces at beginning of the buffer. If there
+ *               is no space at beginning of the buffer, use spaces at the near (i.e. the space
+ *               after the LAMALEF character).
+ *               If there are no spaces found, an error U_NO_SPACE_AVAILABLE (as defined in utypes.h) 
+ *               will be set in pErrorCode
+ *
+ * Deshaping Mode: Perform the same function as the flag equals U_SHAPE_LAMALEF_END. 
+ * Affects: LamAlef options
+ * @stable ICU 4.2
+ */
+#define U_SHAPE_LAMALEF_AUTO                     0x10000 
+
+/** Bit mask for memory options. @stable ICU 2.0 */
+#define U_SHAPE_LENGTH_MASK                      0x10003 /* Changed old value 3 */
+
+
+/**
+ * Bit mask for LamAlef memory options.
+ * @stable ICU 4.2
+ */
+#define U_SHAPE_LAMALEF_MASK                     0x10003 /* updated */
+
+/** Direction indicator: the source is in logical (keyboard) order. @stable ICU 2.0 */
+#define U_SHAPE_TEXT_DIRECTION_LOGICAL          0
+
+/**
+ * Direction indicator:
+ * the source is in visual RTL order,
+ * the rightmost displayed character stored first.
+ * This option is an alias to U_SHAPE_TEXT_DIRECTION_LOGICAL
+ * @stable ICU 4.2
+ */
+#define U_SHAPE_TEXT_DIRECTION_VISUAL_RTL       0
+
+/**
+ * Direction indicator:
+ * the source is in visual LTR order,
+ * the leftmost displayed character stored first.
+ * @stable ICU 2.0
+ */
+#define U_SHAPE_TEXT_DIRECTION_VISUAL_LTR       4
+
+/** Bit mask for direction indicators. @stable ICU 2.0 */
+#define U_SHAPE_TEXT_DIRECTION_MASK             4
+
+
+/** Letter shaping option: do not perform letter shaping. @stable ICU 2.0 */
+#define U_SHAPE_LETTERS_NOOP                    0
+
+/** Letter shaping option: replace abstract letter characters by "shaped" ones. @stable ICU 2.0 */
+#define U_SHAPE_LETTERS_SHAPE                   8
+
+/** Letter shaping option: replace "shaped" letter characters by abstract ones. @stable ICU 2.0 */
+#define U_SHAPE_LETTERS_UNSHAPE                 0x10
+
+/**
+ * Letter shaping option: replace abstract letter characters by "shaped" ones.
+ * The only difference with U_SHAPE_LETTERS_SHAPE is that Tashkeel letters
+ * are always "shaped" into the isolated form instead of the medial form
+ * (selecting code points from the Arabic Presentation Forms-B block).
+ * @stable ICU 2.0
+ */
+#define U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED 0x18
+
+
+/** Bit mask for letter shaping options. @stable ICU 2.0 */
+#define U_SHAPE_LETTERS_MASK                        0x18
+
+
+/** Digit shaping option: do not perform digit shaping. @stable ICU 2.0 */
+#define U_SHAPE_DIGITS_NOOP                     0
+
+/**
+ * Digit shaping option:
+ * Replace European digits (U+0030...) by Arabic-Indic digits.
+ * @stable ICU 2.0
+ */
+#define U_SHAPE_DIGITS_EN2AN                    0x20
+
+/**
+ * Digit shaping option:
+ * Replace Arabic-Indic digits by European digits (U+0030...).
+ * @stable ICU 2.0
+ */
+#define U_SHAPE_DIGITS_AN2EN                    0x40
+
+/**
+ * Digit shaping option:
+ * Replace European digits (U+0030...) by Arabic-Indic digits if the most recent
+ * strongly directional character is an Arabic letter
+ * (<code>u_charDirection()</code> result <code>U_RIGHT_TO_LEFT_ARABIC</code> [AL]).<br>
+ * The direction of "preceding" depends on the direction indicator option.
+ * For the first characters, the preceding strongly directional character
+ * (initial state) is assumed to be not an Arabic letter
+ * (it is <code>U_LEFT_TO_RIGHT</code> [L] or <code>U_RIGHT_TO_LEFT</code> [R]).
+ * @stable ICU 2.0
+ */
+#define U_SHAPE_DIGITS_ALEN2AN_INIT_LR          0x60
+
+/**
+ * Digit shaping option:
+ * Replace European digits (U+0030...) by Arabic-Indic digits if the most recent
+ * strongly directional character is an Arabic letter
+ * (<code>u_charDirection()</code> result <code>U_RIGHT_TO_LEFT_ARABIC</code> [AL]).<br>
+ * The direction of "preceding" depends on the direction indicator option.
+ * For the first characters, the preceding strongly directional character
+ * (initial state) is assumed to be an Arabic letter.
+ * @stable ICU 2.0
+ */
+#define U_SHAPE_DIGITS_ALEN2AN_INIT_AL          0x80
+
+/** Not a valid option value. May be replaced by a new option. @stable ICU 2.0 */
+#define U_SHAPE_DIGITS_RESERVED                 0xa0
+
+/** Bit mask for digit shaping options. @stable ICU 2.0 */
+#define U_SHAPE_DIGITS_MASK                     0xe0
+
+
+/** Digit type option: Use Arabic-Indic digits (U+0660...U+0669). @stable ICU 2.0 */
+#define U_SHAPE_DIGIT_TYPE_AN                   0
+
+/** Digit type option: Use Eastern (Extended) Arabic-Indic digits (U+06f0...U+06f9). @stable ICU 2.0 */
+#define U_SHAPE_DIGIT_TYPE_AN_EXTENDED          0x100
+
+/** Not a valid option value. May be replaced by a new option. @stable ICU 2.0 */
+#define U_SHAPE_DIGIT_TYPE_RESERVED             0x200
+
+/** Bit mask for digit type options. @stable ICU 2.0 */
+#define U_SHAPE_DIGIT_TYPE_MASK                 0x300 /* I need to change this from 0x3f00 to 0x300 */
+
+/** 
+ * Tashkeel aggregation option:
+ * Replaces any combination of U+0651 with one of
+ * U+064C, U+064D, U+064E, U+064F, U+0650 with
+ * U+FC5E, U+FC5F, U+FC60, U+FC61, U+FC62 consecutively.
+ * @stable ICU 3.6
+ */
+#define U_SHAPE_AGGREGATE_TASHKEEL              0x4000
+/** Tashkeel aggregation option: do not aggregate tashkeels. @stable ICU 3.6 */
+#define U_SHAPE_AGGREGATE_TASHKEEL_NOOP         0
+/** Bit mask for tashkeel aggregation. @stable ICU 3.6 */
+#define U_SHAPE_AGGREGATE_TASHKEEL_MASK         0x4000
+
+/** 
+ * Presentation form option:
+ * Don't replace Arabic Presentation Forms-A and Arabic Presentation Forms-B
+ * characters with 0+06xx characters, before shaping.
+ * @stable ICU 3.6
+ */
+#define U_SHAPE_PRESERVE_PRESENTATION           0x8000
+/** Presentation form option: 
+ * Replace Arabic Presentation Forms-A and Arabic Presentationo Forms-B with 
+ * their unshaped correspondants in range 0+06xx, before shaping.
+ * @stable ICU 3.6 
+ */
+#define U_SHAPE_PRESERVE_PRESENTATION_NOOP      0
+/** Bit mask for preserve presentation form. @stable ICU 3.6 */
+#define U_SHAPE_PRESERVE_PRESENTATION_MASK      0x8000
+
+/* Seen Tail option */ 
+/**
+ * Memory option: the result must have the same length as the source.
+ * Shaping mode: The SEEN family character will expand into two characters using space near 
+ *               the SEEN family character(i.e. the space after the character).
+ *               If there are no spaces found, an error U_NO_SPACE_AVAILABLE (as defined in utypes.h) 
+ *               will be set in pErrorCode
+ *
+ * De-shaping mode: Any Seen character followed by Tail character will be
+ *                  replaced by one cell Seen and a space will replace the Tail.
+ * Affects: Seen options
+ * @stable ICU 4.2
+ */
+#define U_SHAPE_SEEN_TWOCELL_NEAR     0x200000
+
+/**
+ * Bit mask for Seen memory options. 
+ * @stable ICU 4.2
+ */
+#define U_SHAPE_SEEN_MASK             0x700000
+
+/* YehHamza option */ 
+/**
+ * Memory option: the result must have the same length as the source.
+ * Shaping mode: The YEHHAMZA character will expand into two characters using space near it 
+ *              (i.e. the space after the character
+ *               If there are no spaces found, an error U_NO_SPACE_AVAILABLE (as defined in utypes.h) 
+ *               will be set in pErrorCode
+ *
+ * De-shaping mode: Any Yeh (final or isolated) character followed by Hamza character will be
+ *                  replaced by one cell YehHamza and space will replace the Hamza.
+ * Affects: YehHamza options
+ * @stable ICU 4.2
+ */
+#define U_SHAPE_YEHHAMZA_TWOCELL_NEAR      0x1000000
+
+
+/**
+ * Bit mask for YehHamza memory options. 
+ * @stable ICU 4.2
+ */
+#define U_SHAPE_YEHHAMZA_MASK              0x3800000
+
+/* New Tashkeel options */ 
+/**
+ * Memory option: the result must have the same length as the source.
+ * Shaping mode: Tashkeel characters will be replaced by spaces. 
+ *               Spaces will be placed at beginning of the buffer
+ *
+ * De-shaping mode: N/A
+ * Affects: Tashkeel options
+ * @stable ICU 4.2
+ */
+#define U_SHAPE_TASHKEEL_BEGIN                      0x40000
+
+/**
+ * Memory option: the result must have the same length as the source.
+ * Shaping mode: Tashkeel characters will be replaced by spaces. 
+ *               Spaces will be placed at end of the buffer
+ *
+ * De-shaping mode: N/A
+ * Affects: Tashkeel options
+ * @stable ICU 4.2
+ */
+#define U_SHAPE_TASHKEEL_END                        0x60000
+
+/**
+ * Memory option: allow the result to have a different length than the source.
+ * Shaping mode: Tashkeel characters will be removed, buffer length will shrink. 
+ * De-shaping mode: N/A 
+ *
+ * Affect: Tashkeel options
+ * @stable ICU 4.2
+ */
+#define U_SHAPE_TASHKEEL_RESIZE                     0x80000
+
+/**
+ * Memory option: the result must have the same length as the source.
+ * Shaping mode: Tashkeel characters will be replaced by Tatweel if it is connected to adjacent
+ *               characters (i.e. shaped on Tatweel) or replaced by space if it is not connected.
+ *
+ * De-shaping mode: N/A
+ * Affects: YehHamza options
+ * @stable ICU 4.2
+ */
+#define U_SHAPE_TASHKEEL_REPLACE_BY_TATWEEL         0xC0000
+
+/** 
+ * Bit mask for Tashkeel replacement with Space or Tatweel memory options. 
+ * @stable ICU 4.2
+ */
+#define U_SHAPE_TASHKEEL_MASK                       0xE0000
+
+
+/* Space location Control options */ 
+/**
+ * This option affect the meaning of BEGIN and END options. if this option is not used the default
+ * for BEGIN and END will be as following: 
+ * The Default (for both Visual LTR, Visual RTL and Logical Text)
+ *           1. BEGIN always refers to the start address of physical memory.
+ *           2. END always refers to the end address of physical memory.
+ *
+ * If this option is used it will swap the meaning of BEGIN and END only for Visual LTR text. 
+ *
+ * The effect on BEGIN and END Memory Options will be as following:
+ *    A. BEGIN For Visual LTR text: This will be the beginning (right side) of the visual text(
+ *       corresponding to the physical memory address end for Visual LTR text, Same as END in 
+ *       default behavior)
+ *    B. BEGIN For Logical text: Same as BEGIN in default behavior. 
+ *    C. END For Visual LTR text: This will be the end (left side) of the visual text (corresponding
+ *       to the physical memory address beginning for Visual LTR text, Same as BEGIN in default behavior.
+ *    D. END For Logical text: Same as END in default behavior). 
+ * Affects: All LamAlef BEGIN, END and AUTO options.
+ * @stable ICU 4.2
+ */
+#define U_SHAPE_SPACES_RELATIVE_TO_TEXT_BEGIN_END 0x4000000
+
+/**
+ * Bit mask for swapping BEGIN and END for Visual LTR text 
+ * @stable ICU 4.2
+ */
+#define U_SHAPE_SPACES_RELATIVE_TO_TEXT_MASK      0x4000000
+
+/**
+ * If this option is used, shaping will use the new Unicode code point for TAIL (i.e. 0xFE73). 
+ * If this option is not specified (Default), old unofficial Unicode TAIL code point is used (i.e. 0x200B)
+ * De-shaping will not use this option as it will always search for both the new Unicode code point for the 
+ * TAIL (i.e. 0xFE73) or the old unofficial Unicode TAIL code point (i.e. 0x200B) and de-shape the
+ * Seen-Family letter accordingly.
+ *
+ * Shaping Mode: Only shaping.
+ * De-shaping Mode: N/A.
+ * Affects: All Seen options
+ * @draft ICU 4.2
+ */
+#define SHAPE_TAIL_NEW_UNICODE        0x8000000
+
+/**
+ * Bit mask for new Unicode Tail option 
+ * @draft ICU 4.2
+ */
+#define SHAPE_TAIL_TYPE_MASK          0x8000000
+
+#endif
diff --git a/source/common/unicode/usprep.h b/source/common/unicode/usprep.h
new file mode 100644
index 0000000..2a20dd7
--- /dev/null
+++ b/source/common/unicode/usprep.h
@@ -0,0 +1,269 @@
+/*
+ *******************************************************************************
+ *
+ *   Copyright (C) 2003-2010, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ *
+ *******************************************************************************
+ *   file name:  usprep.h
+ *   encoding:   US-ASCII
+ *   tab size:   8 (not used)
+ *   indentation:4
+ *
+ *   created on: 2003jul2
+ *   created by: Ram Viswanadha
+ */
+
+#ifndef __USPREP_H__
+#define __USPREP_H__
+
+/**
+ * \file 
+ * \brief C API: Implements the StringPrep algorithm.
+ */
+
+#include "unicode/utypes.h"
+#include "unicode/localpointer.h"
+
+/**
+ *
+ * StringPrep API implements the StingPrep framework as described by RFC 3454.
+ * StringPrep prepares Unicode strings for use in network protocols.
+ * Profiles of StingPrep are set of rules and data according to with the
+ * Unicode Strings are prepared. Each profiles contains tables which describe
+ * how a code point should be treated. The tables are broadly classied into
+ * <ul>
+ *     <li> Unassinged Table: Contains code points that are unassigned 
+ *          in the Unicode Version supported by StringPrep. Currently 
+ *          RFC 3454 supports Unicode 3.2. </li>
+ *     <li> Prohibited Table: Contains code points that are prohibted from
+ *          the output of the StringPrep processing function. </li>
+ *     <li> Mapping Table: Contains code ponts that are deleted from the output or case mapped. </li>
+ * </ul>
+ * 
+ * The procedure for preparing Unicode strings:
+ * <ol>
+ *      <li> Map: For each character in the input, check if it has a mapping
+ *           and, if so, replace it with its mapping. </li>
+ *      <li> Normalize: Possibly normalize the result of step 1 using Unicode
+ *           normalization. </li>
+ *      <li> Prohibit: Check for any characters that are not allowed in the
+ *        output.  If any are found, return an error.</li>
+ *      <li> Check bidi: Possibly check for right-to-left characters, and if
+ *           any are found, make sure that the whole string satisfies the
+ *           requirements for bidirectional strings.  If the string does not
+ *           satisfy the requirements for bidirectional strings, return an
+ *           error.  </li>
+ * </ol>
+ * @author Ram Viswanadha
+ */
+#if !UCONFIG_NO_IDNA
+
+#include "unicode/parseerr.h"
+
+/**
+ * The StringPrep profile
+ * @stable ICU 2.8
+ */
+typedef struct UStringPrepProfile UStringPrepProfile;
+
+
+/** 
+ * Option to prohibit processing of unassigned code points in the input
+ * 
+ * @see  usprep_prepare
+ * @stable ICU 2.8
+ */
+#define USPREP_DEFAULT 0x0000
+
+/** 
+ * Option to allow processing of unassigned code points in the input
+ * 
+ * @see  usprep_prepare
+ * @stable ICU 2.8
+ */
+#define USPREP_ALLOW_UNASSIGNED 0x0001
+
+/**
+ * enums for the standard stringprep profile types
+ * supported by usprep_openByType.
+ * @see usprep_openByType
+ * @stable ICU 4.2
+ */
+typedef enum UStringPrepProfileType {
+    /**
+     * RFC3491 Nameprep
+     * @stable ICU 4.2
+     */
+    USPREP_RFC3491_NAMEPREP,
+    /**
+     * RFC3530 nfs4_cs_prep
+     * @stable ICU 4.2
+     */
+	USPREP_RFC3530_NFS4_CS_PREP,
+    /**
+     * RFC3530 nfs4_cs_prep with case insensitive option
+     * @stable ICU 4.2
+     */
+	USPREP_RFC3530_NFS4_CS_PREP_CI,
+    /**
+     * RFC3530 nfs4_cis_prep
+     * @stable ICU 4.2
+     */
+	USPREP_RFC3530_NFS4_CIS_PREP,
+    /**
+     * RFC3530 nfs4_mixed_prep for prefix
+     * @stable ICU 4.2
+     */
+	USPREP_RFC3530_NFS4_MIXED_PREP_PREFIX,
+    /**
+     * RFC3530 nfs4_mixed_prep for suffix
+     * @stable ICU 4.2
+     */
+	USPREP_RFC3530_NFS4_MIXED_PREP_SUFFIX,
+    /**
+     * RFC3722 iSCSI
+     * @stable ICU 4.2
+     */
+	USPREP_RFC3722_ISCSI,
+    /**
+     * RFC3920 XMPP Nodeprep
+     * @stable ICU 4.2
+     */
+	USPREP_RFC3920_NODEPREP,
+    /**
+     * RFC3920 XMPP Resourceprep
+     * @stable ICU 4.2
+     */
+	USPREP_RFC3920_RESOURCEPREP,
+    /**
+     * RFC4011 Policy MIB Stringprep
+     * @stable ICU 4.2
+     */
+	USPREP_RFC4011_MIB,
+    /**
+     * RFC4013 SASLprep
+     * @stable ICU 4.2
+     */
+    USPREP_RFC4013_SASLPREP,
+    /**
+     * RFC4505 trace
+     * @stable ICU 4.2
+     */
+	USPREP_RFC4505_TRACE,
+    /**
+     * RFC4518 LDAP
+     * @stable ICU 4.2
+     */
+	USPREP_RFC4518_LDAP,
+    /**
+     * RFC4518 LDAP for case ignore, numeric and stored prefix
+     * matching rules
+     * @stable ICU 4.2
+     */
+	USPREP_RFC4518_LDAP_CI
+} UStringPrepProfileType;
+
+/**
+ * Creates a StringPrep profile from the data file.
+ *
+ * @param path      string containing the full path pointing to the directory
+ *                  where the profile reside followed by the package name
+ *                  e.g. "/usr/resource/my_app/profiles/mydata" on a Unix system.
+ *                  if NULL, ICU default data files will be used.
+ * @param fileName  name of the profile file to be opened
+ * @param status    ICU error code in/out parameter. Must not be NULL.
+ *                  Must fulfill U_SUCCESS before the function call.
+ * @return Pointer to UStringPrepProfile that is opened. Should be closed by
+ * calling usprep_close()
+ * @see usprep_close()
+ * @stable ICU 2.8
+ */
+U_STABLE UStringPrepProfile* U_EXPORT2
+usprep_open(const char* path, 
+            const char* fileName,
+            UErrorCode* status);
+
+/**
+ * Creates a StringPrep profile for the specified profile type.
+ *
+ * @param type		The profile type
+ * @param status    ICU error code in/out parameter. Must not be NULL.
+ *                  Must fulfill U_SUCCESS before the function call.
+ * @return          Pointer to UStringPrepProfile that is opened. Should be closed by
+ *                  calling usprep_close()
+ * @see usprep_close()
+ * @stable ICU 4.2
+ */
+U_STABLE UStringPrepProfile* U_EXPORT2
+usprep_openByType(UStringPrepProfileType type,
+				  UErrorCode* status);
+
+/**
+ * Closes the profile
+ * @param profile The profile to close
+ * @stable ICU 2.8
+ */
+U_STABLE void U_EXPORT2
+usprep_close(UStringPrepProfile* profile);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUStringPrepProfilePointer
+ * "Smart pointer" class, closes a UStringPrepProfile via usprep_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUStringPrepProfilePointer, UStringPrepProfile, usprep_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Prepare the input buffer for use in applications with the given profile. This operation maps, normalizes(NFKC),
+ * checks for prohited and BiDi characters in the order defined by RFC 3454
+ * depending on the options specified in the profile.
+ *
+ * @param prep          The profile to use 
+ * @param src           Pointer to UChar buffer containing the string to prepare
+ * @param srcLength     Number of characters in the source string
+ * @param dest          Pointer to the destination buffer to receive the output
+ * @param destCapacity  The capacity of destination array
+ * @param options       A bit set of options:
+ *
+ *  - USPREP_NONE               Prohibit processing of unassigned code points in the input
+ *
+ *  - USPREP_ALLOW_UNASSIGNED   Treat the unassigned code points are in the input 
+ *                              as normal Unicode code points.
+ *
+ * @param parseError        Pointer to UParseError struct to receive information on position 
+ *                          of error if an error is encountered. Can be NULL.
+ * @param status            ICU in/out error code parameter.
+ *                          U_INVALID_CHAR_FOUND if src contains
+ *                          unmatched single surrogates.
+ *                          U_INDEX_OUTOFBOUNDS_ERROR if src contains
+ *                          too many code points.
+ *                          U_BUFFER_OVERFLOW_ERROR if destCapacity is not enough
+ * @return The number of UChars in the destination buffer
+ * @stable ICU 2.8
+ */
+
+U_STABLE int32_t U_EXPORT2
+usprep_prepare(   const UStringPrepProfile* prep,
+                  const UChar* src, int32_t srcLength, 
+                  UChar* dest, int32_t destCapacity,
+                  int32_t options,
+                  UParseError* parseError,
+                  UErrorCode* status );
+
+
+#endif /* #if !UCONFIG_NO_IDNA */
+
+#endif
diff --git a/source/common/unicode/ustring.h b/source/common/unicode/ustring.h
new file mode 100644
index 0000000..388bc74
--- /dev/null
+++ b/source/common/unicode/ustring.h
@@ -0,0 +1,1696 @@
+/*
+**********************************************************************
+*   Copyright (C) 1998-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*
+* File ustring.h
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   12/07/98    bertrand    Creation.
+******************************************************************************
+*/
+
+#ifndef USTRING_H
+#define USTRING_H
+
+#include "unicode/utypes.h"
+#include "unicode/putil.h"
+#include "unicode/uiter.h"
+
+/** Simple declaration for u_strToTitle() to avoid including unicode/ubrk.h. @stable ICU 2.1*/
+#ifndef UBRK_TYPEDEF_UBREAK_ITERATOR
+#   define UBRK_TYPEDEF_UBREAK_ITERATOR
+    typedef struct UBreakIterator UBreakIterator;
+#endif
+
+/**
+ * \file
+ * \brief C API: Unicode string handling functions
+ *
+ * These C API functions provide general Unicode string handling.
+ *
+ * Some functions are equivalent in name, signature, and behavior to the ANSI C <string.h>
+ * functions. (For example, they do not check for bad arguments like NULL string pointers.)
+ * In some cases, only the thread-safe variant of such a function is implemented here
+ * (see u_strtok_r()).
+ *
+ * Other functions provide more Unicode-specific functionality like locale-specific
+ * upper/lower-casing and string comparison in code point order.
+ *
+ * ICU uses 16-bit Unicode (UTF-16) in the form of arrays of UChar code units.
+ * UTF-16 encodes each Unicode code point with either one or two UChar code units.
+ * (This is the default form of Unicode, and a forward-compatible extension of the original,
+ * fixed-width form that was known as UCS-2. UTF-16 superseded UCS-2 with Unicode 2.0
+ * in 1996.)
+ *
+ * Some APIs accept a 32-bit UChar32 value for a single code point.
+ *
+ * ICU also handles 16-bit Unicode text with unpaired surrogates.
+ * Such text is not well-formed UTF-16.
+ * Code-point-related functions treat unpaired surrogates as surrogate code points,
+ * i.e., as separate units.
+ *
+ * Although UTF-16 is a variable-width encoding form (like some legacy multi-byte encodings),
+ * it is much more efficient even for random access because the code unit values
+ * for single-unit characters vs. lead units vs. trail units are completely disjoint.
+ * This means that it is easy to determine character (code point) boundaries from
+ * random offsets in the string.
+ *
+ * Unicode (UTF-16) string processing is optimized for the single-unit case.
+ * Although it is important to support supplementary characters
+ * (which use pairs of lead/trail code units called "surrogates"),
+ * their occurrence is rare. Almost all characters in modern use require only
+ * a single UChar code unit (i.e., their code point values are <=0xffff).
+ *
+ * For more details see the User Guide Strings chapter (http://icu-project.org/userguide/strings.html).
+ * For a discussion of the handling of unpaired surrogates see also
+ * Jitterbug 2145 and its icu mailing list proposal on 2002-sep-18.
+ */
+
+/**
+ * \defgroup ustring_ustrlen String Length
+ * \ingroup ustring_strlen
+ */
+/*@{*/
+/**
+ * Determine the length of an array of UChar.
+ *
+ * @param s The array of UChars, NULL (U+0000) terminated.
+ * @return The number of UChars in <code>chars</code>, minus the terminator.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_strlen(const UChar *s);
+/*@}*/
+
+/**
+ * Count Unicode code points in the length UChar code units of the string.
+ * A code point may occupy either one or two UChar code units.
+ * Counting code points involves reading all code units.
+ *
+ * This functions is basically the inverse of the U16_FWD_N() macro (see utf.h).
+ *
+ * @param s The input string.
+ * @param length The number of UChar code units to be checked, or -1 to count all
+ *               code points before the first NUL (U+0000).
+ * @return The number of code points in the specified code units.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_countChar32(const UChar *s, int32_t length);
+
+/**
+ * Check if the string contains more Unicode code points than a certain number.
+ * This is more efficient than counting all code points in the entire string
+ * and comparing that number with a threshold.
+ * This function may not need to scan the string at all if the length is known
+ * (not -1 for NUL-termination) and falls within a certain range, and
+ * never needs to count more than 'number+1' code points.
+ * Logically equivalent to (u_countChar32(s, length)>number).
+ * A Unicode code point may occupy either one or two UChar code units.
+ *
+ * @param s The input string.
+ * @param length The length of the string, or -1 if it is NUL-terminated.
+ * @param number The number of code points in the string is compared against
+ *               the 'number' parameter.
+ * @return Boolean value for whether the string contains more Unicode code points
+ *         than 'number'. Same as (u_countChar32(s, length)>number).
+ * @stable ICU 2.4
+ */
+U_STABLE UBool U_EXPORT2
+u_strHasMoreChar32Than(const UChar *s, int32_t length, int32_t number);
+
+/**
+ * Concatenate two ustrings.  Appends a copy of <code>src</code>,
+ * including the null terminator, to <code>dst</code>. The initial copied
+ * character from <code>src</code> overwrites the null terminator in <code>dst</code>.
+ *
+ * @param dst The destination string.
+ * @param src The source string.
+ * @return A pointer to <code>dst</code>.
+ * @stable ICU 2.0
+ */
+U_STABLE UChar* U_EXPORT2
+u_strcat(UChar     *dst, 
+    const UChar     *src);
+
+/**
+ * Concatenate two ustrings.  
+ * Appends at most <code>n</code> characters from <code>src</code> to <code>dst</code>.
+ * Adds a terminating NUL.
+ * If src is too long, then only <code>n-1</code> characters will be copied
+ * before the terminating NUL.
+ * If <code>n&lt;=0</code> then dst is not modified.
+ *
+ * @param dst The destination string.
+ * @param src The source string.
+ * @param n The maximum number of characters to append.
+ * @return A pointer to <code>dst</code>.
+ * @stable ICU 2.0
+ */
+U_STABLE UChar* U_EXPORT2
+u_strncat(UChar     *dst, 
+     const UChar     *src, 
+     int32_t     n);
+
+/**
+ * Find the first occurrence of a substring in a string.
+ * The substring is found at code point boundaries.
+ * That means that if the substring begins with
+ * a trail surrogate or ends with a lead surrogate,
+ * then it is found only if these surrogates stand alone in the text.
+ * Otherwise, the substring edge units would be matched against
+ * halves of surrogate pairs.
+ *
+ * @param s The string to search (NUL-terminated).
+ * @param substring The substring to find (NUL-terminated).
+ * @return A pointer to the first occurrence of <code>substring</code> in <code>s</code>,
+ *         or <code>s</code> itself if the <code>substring</code> is empty,
+ *         or <code>NULL</code> if <code>substring</code> is not in <code>s</code>.
+ * @stable ICU 2.0
+ *
+ * @see u_strrstr
+ * @see u_strFindFirst
+ * @see u_strFindLast
+ */
+U_STABLE UChar * U_EXPORT2
+u_strstr(const UChar *s, const UChar *substring);
+
+/**
+ * Find the first occurrence of a substring in a string.
+ * The substring is found at code point boundaries.
+ * That means that if the substring begins with
+ * a trail surrogate or ends with a lead surrogate,
+ * then it is found only if these surrogates stand alone in the text.
+ * Otherwise, the substring edge units would be matched against
+ * halves of surrogate pairs.
+ *
+ * @param s The string to search.
+ * @param length The length of s (number of UChars), or -1 if it is NUL-terminated.
+ * @param substring The substring to find (NUL-terminated).
+ * @param subLength The length of substring (number of UChars), or -1 if it is NUL-terminated.
+ * @return A pointer to the first occurrence of <code>substring</code> in <code>s</code>,
+ *         or <code>s</code> itself if the <code>substring</code> is empty,
+ *         or <code>NULL</code> if <code>substring</code> is not in <code>s</code>.
+ * @stable ICU 2.4
+ *
+ * @see u_strstr
+ * @see u_strFindLast
+ */
+U_STABLE UChar * U_EXPORT2
+u_strFindFirst(const UChar *s, int32_t length, const UChar *substring, int32_t subLength);
+
+/**
+ * Find the first occurrence of a BMP code point in a string.
+ * A surrogate code point is found only if its match in the text is not
+ * part of a surrogate pair.
+ * A NUL character is found at the string terminator.
+ *
+ * @param s The string to search (NUL-terminated).
+ * @param c The BMP code point to find.
+ * @return A pointer to the first occurrence of <code>c</code> in <code>s</code>
+ *         or <code>NULL</code> if <code>c</code> is not in <code>s</code>.
+ * @stable ICU 2.0
+ *
+ * @see u_strchr32
+ * @see u_memchr
+ * @see u_strstr
+ * @see u_strFindFirst
+ */
+U_STABLE UChar * U_EXPORT2
+u_strchr(const UChar *s, UChar c);
+
+/**
+ * Find the first occurrence of a code point in a string.
+ * A surrogate code point is found only if its match in the text is not
+ * part of a surrogate pair.
+ * A NUL character is found at the string terminator.
+ *
+ * @param s The string to search (NUL-terminated).
+ * @param c The code point to find.
+ * @return A pointer to the first occurrence of <code>c</code> in <code>s</code>
+ *         or <code>NULL</code> if <code>c</code> is not in <code>s</code>.
+ * @stable ICU 2.0
+ *
+ * @see u_strchr
+ * @see u_memchr32
+ * @see u_strstr
+ * @see u_strFindFirst
+ */
+U_STABLE UChar * U_EXPORT2
+u_strchr32(const UChar *s, UChar32 c);
+
+/**
+ * Find the last occurrence of a substring in a string.
+ * The substring is found at code point boundaries.
+ * That means that if the substring begins with
+ * a trail surrogate or ends with a lead surrogate,
+ * then it is found only if these surrogates stand alone in the text.
+ * Otherwise, the substring edge units would be matched against
+ * halves of surrogate pairs.
+ *
+ * @param s The string to search (NUL-terminated).
+ * @param substring The substring to find (NUL-terminated).
+ * @return A pointer to the last occurrence of <code>substring</code> in <code>s</code>,
+ *         or <code>s</code> itself if the <code>substring</code> is empty,
+ *         or <code>NULL</code> if <code>substring</code> is not in <code>s</code>.
+ * @stable ICU 2.4
+ *
+ * @see u_strstr
+ * @see u_strFindFirst
+ * @see u_strFindLast
+ */
+U_STABLE UChar * U_EXPORT2
+u_strrstr(const UChar *s, const UChar *substring);
+
+/**
+ * Find the last occurrence of a substring in a string.
+ * The substring is found at code point boundaries.
+ * That means that if the substring begins with
+ * a trail surrogate or ends with a lead surrogate,
+ * then it is found only if these surrogates stand alone in the text.
+ * Otherwise, the substring edge units would be matched against
+ * halves of surrogate pairs.
+ *
+ * @param s The string to search.
+ * @param length The length of s (number of UChars), or -1 if it is NUL-terminated.
+ * @param substring The substring to find (NUL-terminated).
+ * @param subLength The length of substring (number of UChars), or -1 if it is NUL-terminated.
+ * @return A pointer to the last occurrence of <code>substring</code> in <code>s</code>,
+ *         or <code>s</code> itself if the <code>substring</code> is empty,
+ *         or <code>NULL</code> if <code>substring</code> is not in <code>s</code>.
+ * @stable ICU 2.4
+ *
+ * @see u_strstr
+ * @see u_strFindLast
+ */
+U_STABLE UChar * U_EXPORT2
+u_strFindLast(const UChar *s, int32_t length, const UChar *substring, int32_t subLength);
+
+/**
+ * Find the last occurrence of a BMP code point in a string.
+ * A surrogate code point is found only if its match in the text is not
+ * part of a surrogate pair.
+ * A NUL character is found at the string terminator.
+ *
+ * @param s The string to search (NUL-terminated).
+ * @param c The BMP code point to find.
+ * @return A pointer to the last occurrence of <code>c</code> in <code>s</code>
+ *         or <code>NULL</code> if <code>c</code> is not in <code>s</code>.
+ * @stable ICU 2.4
+ *
+ * @see u_strrchr32
+ * @see u_memrchr
+ * @see u_strrstr
+ * @see u_strFindLast
+ */
+U_STABLE UChar * U_EXPORT2
+u_strrchr(const UChar *s, UChar c);
+
+/**
+ * Find the last occurrence of a code point in a string.
+ * A surrogate code point is found only if its match in the text is not
+ * part of a surrogate pair.
+ * A NUL character is found at the string terminator.
+ *
+ * @param s The string to search (NUL-terminated).
+ * @param c The code point to find.
+ * @return A pointer to the last occurrence of <code>c</code> in <code>s</code>
+ *         or <code>NULL</code> if <code>c</code> is not in <code>s</code>.
+ * @stable ICU 2.4
+ *
+ * @see u_strrchr
+ * @see u_memchr32
+ * @see u_strrstr
+ * @see u_strFindLast
+ */
+U_STABLE UChar * U_EXPORT2
+u_strrchr32(const UChar *s, UChar32 c);
+
+/**
+ * Locates the first occurrence in the string <code>string</code> of any of the characters
+ * in the string <code>matchSet</code>.
+ * Works just like C's strpbrk but with Unicode.
+ *
+ * @param string The string in which to search, NUL-terminated.
+ * @param matchSet A NUL-terminated string defining a set of code points
+ *                 for which to search in the text string.
+ * @return A pointer to the  character in <code>string</code> that matches one of the
+ *         characters in <code>matchSet</code>, or NULL if no such character is found.
+ * @stable ICU 2.0
+ */
+U_STABLE UChar * U_EXPORT2
+u_strpbrk(const UChar *string, const UChar *matchSet);
+
+/**
+ * Returns the number of consecutive characters in <code>string</code>,
+ * beginning with the first, that do not occur somewhere in <code>matchSet</code>.
+ * Works just like C's strcspn but with Unicode.
+ *
+ * @param string The string in which to search, NUL-terminated.
+ * @param matchSet A NUL-terminated string defining a set of code points
+ *                 for which to search in the text string.
+ * @return The number of initial characters in <code>string</code> that do not
+ *         occur in <code>matchSet</code>.
+ * @see u_strspn
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_strcspn(const UChar *string, const UChar *matchSet);
+
+/**
+ * Returns the number of consecutive characters in <code>string</code>,
+ * beginning with the first, that occur somewhere in <code>matchSet</code>.
+ * Works just like C's strspn but with Unicode.
+ *
+ * @param string The string in which to search, NUL-terminated.
+ * @param matchSet A NUL-terminated string defining a set of code points
+ *                 for which to search in the text string.
+ * @return The number of initial characters in <code>string</code> that do
+ *         occur in <code>matchSet</code>.
+ * @see u_strcspn
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_strspn(const UChar *string, const UChar *matchSet);
+
+/**
+ * The string tokenizer API allows an application to break a string into
+ * tokens. Unlike strtok(), the saveState (the current pointer within the
+ * original string) is maintained in saveState. In the first call, the
+ * argument src is a pointer to the string. In subsequent calls to
+ * return successive tokens of that string, src must be specified as
+ * NULL. The value saveState is set by this function to maintain the
+ * function's position within the string, and on each subsequent call
+ * you must give this argument the same variable. This function does
+ * handle surrogate pairs. This function is similar to the strtok_r()
+ * the POSIX Threads Extension (1003.1c-1995) version.
+ *
+ * @param src String containing token(s). This string will be modified.
+ *            After the first call to u_strtok_r(), this argument must
+ *            be NULL to get to the next token.
+ * @param delim Set of delimiter characters (Unicode code points).
+ * @param saveState The current pointer within the original string,
+ *              which is set by this function. The saveState
+ *              parameter should the address of a local variable of type
+ *              UChar *. (i.e. defined "Uhar *myLocalSaveState" and use
+ *              &myLocalSaveState for this parameter).
+ * @return A pointer to the next token found in src, or NULL
+ *         when there are no more tokens.
+ * @stable ICU 2.0
+ */
+U_STABLE UChar * U_EXPORT2
+u_strtok_r(UChar    *src, 
+     const UChar    *delim,
+           UChar   **saveState);
+
+/**
+ * Compare two Unicode strings for bitwise equality (code unit order).
+ *
+ * @param s1 A string to compare.
+ * @param s2 A string to compare.
+ * @return 0 if <code>s1</code> and <code>s2</code> are bitwise equal; a negative
+ * value if <code>s1</code> is bitwise less than <code>s2,</code>; a positive
+ * value if <code>s1</code> is bitwise greater than <code>s2</code>.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t  U_EXPORT2
+u_strcmp(const UChar     *s1, 
+         const UChar     *s2);
+
+/**
+ * Compare two Unicode strings in code point order.
+ * See u_strCompare for details.
+ *
+ * @param s1 A string to compare.
+ * @param s2 A string to compare.
+ * @return a negative/zero/positive integer corresponding to whether
+ * the first string is less than/equal to/greater than the second one
+ * in code point order
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_strcmpCodePointOrder(const UChar *s1, const UChar *s2);
+
+/**
+ * Compare two Unicode strings (binary order).
+ *
+ * The comparison can be done in code unit order or in code point order.
+ * They differ only in UTF-16 when
+ * comparing supplementary code points (U+10000..U+10ffff)
+ * to BMP code points near the end of the BMP (i.e., U+e000..U+ffff).
+ * In code unit order, high BMP code points sort after supplementary code points
+ * because they are stored as pairs of surrogates which are at U+d800..U+dfff.
+ *
+ * This functions works with strings of different explicitly specified lengths
+ * unlike the ANSI C-like u_strcmp() and u_memcmp() etc.
+ * NUL-terminated strings are possible with length arguments of -1.
+ *
+ * @param s1 First source string.
+ * @param length1 Length of first source string, or -1 if NUL-terminated.
+ *
+ * @param s2 Second source string.
+ * @param length2 Length of second source string, or -1 if NUL-terminated.
+ *
+ * @param codePointOrder Choose between code unit order (FALSE)
+ *                       and code point order (TRUE).
+ *
+ * @return <0 or 0 or >0 as usual for string comparisons
+ *
+ * @stable ICU 2.2
+ */
+U_STABLE int32_t U_EXPORT2
+u_strCompare(const UChar *s1, int32_t length1,
+             const UChar *s2, int32_t length2,
+             UBool codePointOrder);
+
+/**
+ * Compare two Unicode strings (binary order)
+ * as presented by UCharIterator objects.
+ * Works otherwise just like u_strCompare().
+ *
+ * Both iterators are reset to their start positions.
+ * When the function returns, it is undefined where the iterators
+ * have stopped.
+ *
+ * @param iter1 First source string iterator.
+ * @param iter2 Second source string iterator.
+ * @param codePointOrder Choose between code unit order (FALSE)
+ *                       and code point order (TRUE).
+ *
+ * @return <0 or 0 or >0 as usual for string comparisons
+ *
+ * @see u_strCompare
+ *
+ * @stable ICU 2.6
+ */
+U_STABLE int32_t U_EXPORT2
+u_strCompareIter(UCharIterator *iter1, UCharIterator *iter2, UBool codePointOrder);
+
+#ifndef U_COMPARE_CODE_POINT_ORDER
+/* see also unistr.h and unorm.h */
+/**
+ * Option bit for u_strCaseCompare, u_strcasecmp, unorm_compare, etc:
+ * Compare strings in code point order instead of code unit order.
+ * @stable ICU 2.2
+ */
+#define U_COMPARE_CODE_POINT_ORDER  0x8000
+#endif
+
+/**
+ * Compare two strings case-insensitively using full case folding.
+ * This is equivalent to
+ *   u_strCompare(u_strFoldCase(s1, options),
+ *                u_strFoldCase(s2, options),
+ *                (options&U_COMPARE_CODE_POINT_ORDER)!=0).
+ *
+ * The comparison can be done in UTF-16 code unit order or in code point order.
+ * They differ only when comparing supplementary code points (U+10000..U+10ffff)
+ * to BMP code points near the end of the BMP (i.e., U+e000..U+ffff).
+ * In code unit order, high BMP code points sort after supplementary code points
+ * because they are stored as pairs of surrogates which are at U+d800..U+dfff.
+ *
+ * This functions works with strings of different explicitly specified lengths
+ * unlike the ANSI C-like u_strcmp() and u_memcmp() etc.
+ * NUL-terminated strings are possible with length arguments of -1.
+ *
+ * @param s1 First source string.
+ * @param length1 Length of first source string, or -1 if NUL-terminated.
+ *
+ * @param s2 Second source string.
+ * @param length2 Length of second source string, or -1 if NUL-terminated.
+ *
+ * @param options A bit set of options:
+ *   - U_FOLD_CASE_DEFAULT or 0 is used for default options:
+ *     Comparison in code unit order with default case folding.
+ *
+ *   - U_COMPARE_CODE_POINT_ORDER
+ *     Set to choose code point order instead of code unit order
+ *     (see u_strCompare for details).
+ *
+ *   - U_FOLD_CASE_EXCLUDE_SPECIAL_I
+ *
+ * @param pErrorCode Must be a valid pointer to an error code value,
+ *                  which must not indicate a failure before the function call.
+ *
+ * @return <0 or 0 or >0 as usual for string comparisons
+ *
+ * @stable ICU 2.2
+ */
+U_STABLE int32_t U_EXPORT2
+u_strCaseCompare(const UChar *s1, int32_t length1,
+                 const UChar *s2, int32_t length2,
+                 uint32_t options,
+                 UErrorCode *pErrorCode);
+
+/**
+ * Compare two ustrings for bitwise equality. 
+ * Compares at most <code>n</code> characters.
+ *
+ * @param ucs1 A string to compare.
+ * @param ucs2 A string to compare.
+ * @param n The maximum number of characters to compare.
+ * @return 0 if <code>s1</code> and <code>s2</code> are bitwise equal; a negative
+ * value if <code>s1</code> is bitwise less than <code>s2</code>; a positive
+ * value if <code>s1</code> is bitwise greater than <code>s2</code>.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_strncmp(const UChar     *ucs1, 
+     const UChar     *ucs2, 
+     int32_t     n);
+
+/**
+ * Compare two Unicode strings in code point order.
+ * This is different in UTF-16 from u_strncmp() if supplementary characters are present.
+ * For details, see u_strCompare().
+ *
+ * @param s1 A string to compare.
+ * @param s2 A string to compare.
+ * @param n The maximum number of characters to compare.
+ * @return a negative/zero/positive integer corresponding to whether
+ * the first string is less than/equal to/greater than the second one
+ * in code point order
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_strncmpCodePointOrder(const UChar *s1, const UChar *s2, int32_t n);
+
+/**
+ * Compare two strings case-insensitively using full case folding.
+ * This is equivalent to u_strcmp(u_strFoldCase(s1, options), u_strFoldCase(s2, options)).
+ *
+ * @param s1 A string to compare.
+ * @param s2 A string to compare.
+ * @param options A bit set of options:
+ *   - U_FOLD_CASE_DEFAULT or 0 is used for default options:
+ *     Comparison in code unit order with default case folding.
+ *
+ *   - U_COMPARE_CODE_POINT_ORDER
+ *     Set to choose code point order instead of code unit order
+ *     (see u_strCompare for details).
+ *
+ *   - U_FOLD_CASE_EXCLUDE_SPECIAL_I
+ *
+ * @return A negative, zero, or positive integer indicating the comparison result.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_strcasecmp(const UChar *s1, const UChar *s2, uint32_t options);
+
+/**
+ * Compare two strings case-insensitively using full case folding.
+ * This is equivalent to u_strcmp(u_strFoldCase(s1, at most n, options),
+ * u_strFoldCase(s2, at most n, options)).
+ *
+ * @param s1 A string to compare.
+ * @param s2 A string to compare.
+ * @param n The maximum number of characters each string to case-fold and then compare.
+ * @param options A bit set of options:
+ *   - U_FOLD_CASE_DEFAULT or 0 is used for default options:
+ *     Comparison in code unit order with default case folding.
+ *
+ *   - U_COMPARE_CODE_POINT_ORDER
+ *     Set to choose code point order instead of code unit order
+ *     (see u_strCompare for details).
+ *
+ *   - U_FOLD_CASE_EXCLUDE_SPECIAL_I
+ *
+ * @return A negative, zero, or positive integer indicating the comparison result.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_strncasecmp(const UChar *s1, const UChar *s2, int32_t n, uint32_t options);
+
+/**
+ * Compare two strings case-insensitively using full case folding.
+ * This is equivalent to u_strcmp(u_strFoldCase(s1, n, options),
+ * u_strFoldCase(s2, n, options)).
+ *
+ * @param s1 A string to compare.
+ * @param s2 A string to compare.
+ * @param length The number of characters in each string to case-fold and then compare.
+ * @param options A bit set of options:
+ *   - U_FOLD_CASE_DEFAULT or 0 is used for default options:
+ *     Comparison in code unit order with default case folding.
+ *
+ *   - U_COMPARE_CODE_POINT_ORDER
+ *     Set to choose code point order instead of code unit order
+ *     (see u_strCompare for details).
+ *
+ *   - U_FOLD_CASE_EXCLUDE_SPECIAL_I
+ *
+ * @return A negative, zero, or positive integer indicating the comparison result.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_memcasecmp(const UChar *s1, const UChar *s2, int32_t length, uint32_t options);
+
+/**
+ * Copy a ustring. Adds a null terminator.
+ *
+ * @param dst The destination string.
+ * @param src The source string.
+ * @return A pointer to <code>dst</code>.
+ * @stable ICU 2.0
+ */
+U_STABLE UChar* U_EXPORT2
+u_strcpy(UChar     *dst, 
+    const UChar     *src);
+
+/**
+ * Copy a ustring.
+ * Copies at most <code>n</code> characters.  The result will be null terminated
+ * if the length of <code>src</code> is less than <code>n</code>.
+ *
+ * @param dst The destination string.
+ * @param src The source string.
+ * @param n The maximum number of characters to copy.
+ * @return A pointer to <code>dst</code>.
+ * @stable ICU 2.0
+ */
+U_STABLE UChar* U_EXPORT2
+u_strncpy(UChar     *dst, 
+     const UChar     *src, 
+     int32_t     n);
+
+#if !UCONFIG_NO_CONVERSION
+
+/**
+ * Copy a byte string encoded in the default codepage to a ustring.
+ * Adds a null terminator.
+ * Performs a host byte to UChar conversion
+ *
+ * @param dst The destination string.
+ * @param src The source string.
+ * @return A pointer to <code>dst</code>.
+ * @stable ICU 2.0
+ */
+U_STABLE UChar* U_EXPORT2 u_uastrcpy(UChar *dst,
+               const char *src );
+
+/**
+ * Copy a byte string encoded in the default codepage to a ustring.
+ * Copies at most <code>n</code> characters.  The result will be null terminated
+ * if the length of <code>src</code> is less than <code>n</code>.
+ * Performs a host byte to UChar conversion
+ *
+ * @param dst The destination string.
+ * @param src The source string.
+ * @param n The maximum number of characters to copy.
+ * @return A pointer to <code>dst</code>.
+ * @stable ICU 2.0
+ */
+U_STABLE UChar* U_EXPORT2 u_uastrncpy(UChar *dst,
+            const char *src,
+            int32_t n);
+
+/**
+ * Copy ustring to a byte string encoded in the default codepage.
+ * Adds a null terminator.
+ * Performs a UChar to host byte conversion
+ *
+ * @param dst The destination string.
+ * @param src The source string.
+ * @return A pointer to <code>dst</code>.
+ * @stable ICU 2.0
+ */
+U_STABLE char* U_EXPORT2 u_austrcpy(char *dst,
+            const UChar *src );
+
+/**
+ * Copy ustring to a byte string encoded in the default codepage.
+ * Copies at most <code>n</code> characters.  The result will be null terminated
+ * if the length of <code>src</code> is less than <code>n</code>.
+ * Performs a UChar to host byte conversion
+ *
+ * @param dst The destination string.
+ * @param src The source string.
+ * @param n The maximum number of characters to copy.
+ * @return A pointer to <code>dst</code>.
+ * @stable ICU 2.0
+ */
+U_STABLE char* U_EXPORT2 u_austrncpy(char *dst,
+            const UChar *src,
+            int32_t n );
+
+#endif
+
+/**
+ * Synonym for memcpy(), but with UChars only.
+ * @param dest The destination string
+ * @param src The source string
+ * @param count The number of characters to copy
+ * @return A pointer to <code>dest</code>
+ * @stable ICU 2.0
+ */
+U_STABLE UChar* U_EXPORT2
+u_memcpy(UChar *dest, const UChar *src, int32_t count);
+
+/**
+ * Synonym for memmove(), but with UChars only.
+ * @param dest The destination string
+ * @param src The source string
+ * @param count The number of characters to move
+ * @return A pointer to <code>dest</code>
+ * @stable ICU 2.0
+ */
+U_STABLE UChar* U_EXPORT2
+u_memmove(UChar *dest, const UChar *src, int32_t count);
+
+/**
+ * Initialize <code>count</code> characters of <code>dest</code> to <code>c</code>.
+ *
+ * @param dest The destination string.
+ * @param c The character to initialize the string.
+ * @param count The maximum number of characters to set.
+ * @return A pointer to <code>dest</code>.
+ * @stable ICU 2.0
+ */
+U_STABLE UChar* U_EXPORT2
+u_memset(UChar *dest, UChar c, int32_t count);
+
+/**
+ * Compare the first <code>count</code> UChars of each buffer.
+ *
+ * @param buf1 The first string to compare.
+ * @param buf2 The second string to compare.
+ * @param count The maximum number of UChars to compare.
+ * @return When buf1 < buf2, a negative number is returned.
+ *      When buf1 == buf2, 0 is returned.
+ *      When buf1 > buf2, a positive number is returned.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_memcmp(const UChar *buf1, const UChar *buf2, int32_t count);
+
+/**
+ * Compare two Unicode strings in code point order.
+ * This is different in UTF-16 from u_memcmp() if supplementary characters are present.
+ * For details, see u_strCompare().
+ *
+ * @param s1 A string to compare.
+ * @param s2 A string to compare.
+ * @param count The maximum number of characters to compare.
+ * @return a negative/zero/positive integer corresponding to whether
+ * the first string is less than/equal to/greater than the second one
+ * in code point order
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_memcmpCodePointOrder(const UChar *s1, const UChar *s2, int32_t count);
+
+/**
+ * Find the first occurrence of a BMP code point in a string.
+ * A surrogate code point is found only if its match in the text is not
+ * part of a surrogate pair.
+ * A NUL character is found at the string terminator.
+ *
+ * @param s The string to search (contains <code>count</code> UChars).
+ * @param c The BMP code point to find.
+ * @param count The length of the string.
+ * @return A pointer to the first occurrence of <code>c</code> in <code>s</code>
+ *         or <code>NULL</code> if <code>c</code> is not in <code>s</code>.
+ * @stable ICU 2.0
+ *
+ * @see u_strchr
+ * @see u_memchr32
+ * @see u_strFindFirst
+ */
+U_STABLE UChar* U_EXPORT2
+u_memchr(const UChar *s, UChar c, int32_t count);
+
+/**
+ * Find the first occurrence of a code point in a string.
+ * A surrogate code point is found only if its match in the text is not
+ * part of a surrogate pair.
+ * A NUL character is found at the string terminator.
+ *
+ * @param s The string to search (contains <code>count</code> UChars).
+ * @param c The code point to find.
+ * @param count The length of the string.
+ * @return A pointer to the first occurrence of <code>c</code> in <code>s</code>
+ *         or <code>NULL</code> if <code>c</code> is not in <code>s</code>.
+ * @stable ICU 2.0
+ *
+ * @see u_strchr32
+ * @see u_memchr
+ * @see u_strFindFirst
+ */
+U_STABLE UChar* U_EXPORT2
+u_memchr32(const UChar *s, UChar32 c, int32_t count);
+
+/**
+ * Find the last occurrence of a BMP code point in a string.
+ * A surrogate code point is found only if its match in the text is not
+ * part of a surrogate pair.
+ * A NUL character is found at the string terminator.
+ *
+ * @param s The string to search (contains <code>count</code> UChars).
+ * @param c The BMP code point to find.
+ * @param count The length of the string.
+ * @return A pointer to the last occurrence of <code>c</code> in <code>s</code>
+ *         or <code>NULL</code> if <code>c</code> is not in <code>s</code>.
+ * @stable ICU 2.4
+ *
+ * @see u_strrchr
+ * @see u_memrchr32
+ * @see u_strFindLast
+ */
+U_STABLE UChar* U_EXPORT2
+u_memrchr(const UChar *s, UChar c, int32_t count);
+
+/**
+ * Find the last occurrence of a code point in a string.
+ * A surrogate code point is found only if its match in the text is not
+ * part of a surrogate pair.
+ * A NUL character is found at the string terminator.
+ *
+ * @param s The string to search (contains <code>count</code> UChars).
+ * @param c The code point to find.
+ * @param count The length of the string.
+ * @return A pointer to the last occurrence of <code>c</code> in <code>s</code>
+ *         or <code>NULL</code> if <code>c</code> is not in <code>s</code>.
+ * @stable ICU 2.4
+ *
+ * @see u_strrchr32
+ * @see u_memrchr
+ * @see u_strFindLast
+ */
+U_STABLE UChar* U_EXPORT2
+u_memrchr32(const UChar *s, UChar32 c, int32_t count);
+
+/**
+ * Unicode String literals in C.
+ * We need one macro to declare a variable for the string
+ * and to statically preinitialize it if possible,
+ * and a second macro to dynamically intialize such a string variable if necessary.
+ *
+ * The macros are defined for maximum performance.
+ * They work only for strings that contain "invariant characters", i.e.,
+ * only latin letters, digits, and some punctuation.
+ * See utypes.h for details.
+ *
+ * A pair of macros for a single string must be used with the same
+ * parameters.
+ * The string parameter must be a C string literal.
+ * The length of the string, not including the terminating
+ * <code>NUL</code>, must be specified as a constant.
+ * The U_STRING_DECL macro should be invoked exactly once for one
+ * such string variable before it is used.
+ *
+ * Usage:
+ * <pre>
+ *    U_STRING_DECL(ustringVar1, "Quick-Fox 2", 11);
+ *    U_STRING_DECL(ustringVar2, "jumps 5%", 8);
+ *    static UBool didInit=FALSE;
+ * 
+ *    int32_t function() {
+ *        if(!didInit) {
+ *            U_STRING_INIT(ustringVar1, "Quick-Fox 2", 11);
+ *            U_STRING_INIT(ustringVar2, "jumps 5%", 8);
+ *            didInit=TRUE;
+ *        }
+ *        return u_strcmp(ustringVar1, ustringVar2);
+ *    }
+ * </pre>
+ * 
+ * Note that the macros will NOT consistently work if their argument is another #define. 
+ *  The following will not work on all platforms, don't use it.
+ * 
+ * <pre>
+ *     #define GLUCK "Mr. Gluck"
+ *     U_STRING_DECL(var, GLUCK, 9)
+ *     U_STRING_INIT(var, GLUCK, 9)
+ * </pre>
+ * 
+ * Instead, use the string literal "Mr. Gluck"  as the argument to both macro
+ * calls.
+ *
+ *
+ * @stable ICU 2.0
+ */
+#if defined(U_DECLARE_UTF16)
+#   define U_STRING_DECL(var, cs, length) static const UChar var[(length)+1]=U_DECLARE_UTF16(cs)
+    /**@stable ICU 2.0 */
+#   define U_STRING_INIT(var, cs, length)
+#elif U_SIZEOF_WCHAR_T==U_SIZEOF_UCHAR && (U_CHARSET_FAMILY==U_ASCII_FAMILY || (U_SIZEOF_UCHAR == 2 && defined(U_WCHAR_IS_UTF16)))
+#   define U_STRING_DECL(var, cs, length) static const UChar var[(length)+1]=L ## cs
+    /**@stable ICU 2.0 */
+#   define U_STRING_INIT(var, cs, length)
+#elif U_SIZEOF_UCHAR==1 && U_CHARSET_FAMILY==U_ASCII_FAMILY
+#   define U_STRING_DECL(var, cs, length) static const UChar var[(length)+1]=cs
+    /**@stable ICU 2.0 */
+#   define U_STRING_INIT(var, cs, length)
+#else
+#   define U_STRING_DECL(var, cs, length) static UChar var[(length)+1]
+    /**@stable ICU 2.0 */
+#   define U_STRING_INIT(var, cs, length) u_charsToUChars(cs, var, length+1)
+#endif
+
+/**
+ * Unescape a string of characters and write the resulting
+ * Unicode characters to the destination buffer.  The following escape
+ * sequences are recognized:
+ *
+ * \\uhhhh       4 hex digits; h in [0-9A-Fa-f]
+ * \\Uhhhhhhhh   8 hex digits
+ * \\xhh         1-2 hex digits
+ * \\x{h...}     1-8 hex digits
+ * \\ooo         1-3 octal digits; o in [0-7]
+ * \\cX          control-X; X is masked with 0x1F
+ *
+ * as well as the standard ANSI C escapes:
+ *
+ * \\a => U+0007, \\b => U+0008, \\t => U+0009, \\n => U+000A,
+ * \\v => U+000B, \\f => U+000C, \\r => U+000D, \\e => U+001B,
+ * \\&quot; => U+0022, \\' => U+0027, \\? => U+003F, \\\\ => U+005C
+ *
+ * Anything else following a backslash is generically escaped.  For
+ * example, "[a\\-z]" returns "[a-z]".
+ *
+ * If an escape sequence is ill-formed, this method returns an empty
+ * string.  An example of an ill-formed sequence is "\\u" followed by
+ * fewer than 4 hex digits.
+ *
+ * The above characters are recognized in the compiler's codepage,
+ * that is, they are coded as 'u', '\\', etc.  Characters that are
+ * not parts of escape sequences are converted using u_charsToUChars().
+ *
+ * This function is similar to UnicodeString::unescape() but not
+ * identical to it.  The latter takes a source UnicodeString, so it
+ * does escape recognition but no conversion.
+ *
+ * @param src a zero-terminated string of invariant characters
+ * @param dest pointer to buffer to receive converted and unescaped
+ * text and, if there is room, a zero terminator.  May be NULL for
+ * preflighting, in which case no UChars will be written, but the
+ * return value will still be valid.  On error, an empty string is
+ * stored here (if possible).
+ * @param destCapacity the number of UChars that may be written at
+ * dest.  Ignored if dest == NULL.
+ * @return the length of unescaped string.
+ * @see u_unescapeAt
+ * @see UnicodeString#unescape()
+ * @see UnicodeString#unescapeAt()
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_unescape(const char *src,
+           UChar *dest, int32_t destCapacity);
+
+U_CDECL_BEGIN
+/**
+ * Callback function for u_unescapeAt() that returns a character of
+ * the source text given an offset and a context pointer.  The context
+ * pointer will be whatever is passed into u_unescapeAt().
+ *
+ * @param offset pointer to the offset that will be passed to u_unescapeAt().
+ * @param context an opaque pointer passed directly into u_unescapeAt()
+ * @return the character represented by the escape sequence at
+ * offset
+ * @see u_unescapeAt
+ * @stable ICU 2.0
+ */
+typedef UChar (U_CALLCONV *UNESCAPE_CHAR_AT)(int32_t offset, void *context);
+U_CDECL_END
+
+/**
+ * Unescape a single sequence. The character at offset-1 is assumed
+ * (without checking) to be a backslash.  This method takes a callback
+ * pointer to a function that returns the UChar at a given offset.  By
+ * varying this callback, ICU functions are able to unescape char*
+ * strings, UnicodeString objects, and UFILE pointers.
+ *
+ * If offset is out of range, or if the escape sequence is ill-formed,
+ * (UChar32)0xFFFFFFFF is returned.  See documentation of u_unescape()
+ * for a list of recognized sequences.
+ *
+ * @param charAt callback function that returns a UChar of the source
+ * text given an offset and a context pointer.
+ * @param offset pointer to the offset that will be passed to charAt.
+ * The offset value will be updated upon return to point after the
+ * last parsed character of the escape sequence.  On error the offset
+ * is unchanged.
+ * @param length the number of characters in the source text.  The
+ * last character of the source text is considered to be at offset
+ * length-1.
+ * @param context an opaque pointer passed directly into charAt.
+ * @return the character represented by the escape sequence at
+ * offset, or (UChar32)0xFFFFFFFF on error.
+ * @see u_unescape()
+ * @see UnicodeString#unescape()
+ * @see UnicodeString#unescapeAt()
+ * @stable ICU 2.0
+ */
+U_STABLE UChar32 U_EXPORT2
+u_unescapeAt(UNESCAPE_CHAR_AT charAt,
+             int32_t *offset,
+             int32_t length,
+             void *context);
+
+/**
+ * Uppercase the characters in a string.
+ * Casing is locale-dependent and context-sensitive.
+ * The result may be longer or shorter than the original.
+ * The source string and the destination buffer are allowed to overlap.
+ *
+ * @param dest      A buffer for the result string. The result will be zero-terminated if
+ *                  the buffer is large enough.
+ * @param destCapacity The size of the buffer (number of UChars). 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.
+ * @param src       The original string
+ * @param srcLength The length of the original string. If -1, then src must be zero-terminated.
+ * @param locale    The locale to consider, or "" for the root locale or NULL for the default locale.
+ * @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 result string. It may be greater than destCapacity. In that case,
+ *         only some of the result was written to the destination buffer.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_strToUpper(UChar *dest, int32_t destCapacity,
+             const UChar *src, int32_t srcLength,
+             const char *locale,
+             UErrorCode *pErrorCode);
+
+/**
+ * Lowercase the characters in a string.
+ * Casing is locale-dependent and context-sensitive.
+ * The result may be longer or shorter than the original.
+ * The source string and the destination buffer are allowed to overlap.
+ *
+ * @param dest      A buffer for the result string. The result will be zero-terminated if
+ *                  the buffer is large enough.
+ * @param destCapacity The size of the buffer (number of UChars). 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.
+ * @param src       The original string
+ * @param srcLength The length of the original string. If -1, then src must be zero-terminated.
+ * @param locale    The locale to consider, or "" for the root locale or NULL for the default locale.
+ * @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 result string. It may be greater than destCapacity. In that case,
+ *         only some of the result was written to the destination buffer.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_strToLower(UChar *dest, int32_t destCapacity,
+             const UChar *src, int32_t srcLength,
+             const char *locale,
+             UErrorCode *pErrorCode);
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+/**
+ * Titlecase a string.
+ * Casing is locale-dependent and context-sensitive.
+ * Titlecasing uses a break iterator to find the first characters of words
+ * that are to be titlecased. It titlecases those characters and lowercases
+ * all others.
+ *
+ * The titlecase break iterator can be provided to customize for arbitrary
+ * styles, using rules and dictionaries beyond the standard iterators.
+ * It may be more efficient to always provide an iterator to avoid
+ * opening and closing one for each string.
+ * The standard titlecase iterator for the root locale implements the
+ * algorithm of Unicode TR 21.
+ *
+ * This function uses only the setText(), first() and next() methods of the
+ * provided break iterator.
+ *
+ * The result may be longer or shorter than the original.
+ * The source string and the destination buffer are allowed to overlap.
+ *
+ * @param dest      A buffer for the result string. The result will be zero-terminated if
+ *                  the buffer is large enough.
+ * @param destCapacity The size of the buffer (number of UChars). 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.
+ * @param src       The original string
+ * @param srcLength The length of the original string. If -1, then src must be zero-terminated.
+ * @param titleIter A break iterator to find the first characters of words
+ *                  that are to be titlecased.
+ *                  If none is provided (NULL), then a standard titlecase
+ *                  break iterator is opened.
+ * @param locale    The locale to consider, or "" for the root locale or NULL for the default locale.
+ * @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 result string. It may be greater than destCapacity. In that case,
+ *         only some of the result was written to the destination buffer.
+ * @stable ICU 2.1
+ */
+U_STABLE int32_t U_EXPORT2
+u_strToTitle(UChar *dest, int32_t destCapacity,
+             const UChar *src, int32_t srcLength,
+             UBreakIterator *titleIter,
+             const char *locale,
+             UErrorCode *pErrorCode);
+
+#endif
+
+/**
+ * Case-fold the characters in a string.
+ * Case-folding is locale-independent and not context-sensitive,
+ * but there is an option for whether to include or exclude mappings for dotted I
+ * and dotless i that are marked with 'I' in CaseFolding.txt.
+ * The result may be longer or shorter than the original.
+ * The source string and the destination buffer are allowed to overlap.
+ *
+ * @param dest      A buffer for the result string. The result will be zero-terminated if
+ *                  the buffer is large enough.
+ * @param destCapacity The size of the buffer (number of UChars). 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.
+ * @param src       The original string
+ * @param srcLength The length of the original string. If -1, then src must be zero-terminated.
+ * @param options   Either U_FOLD_CASE_DEFAULT or U_FOLD_CASE_EXCLUDE_SPECIAL_I
+ * @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 result string. It may be greater than destCapacity. In that case,
+ *         only some of the result was written to the destination buffer.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_strFoldCase(UChar *dest, int32_t destCapacity,
+              const UChar *src, int32_t srcLength,
+              uint32_t options,
+              UErrorCode *pErrorCode);
+
+#if defined(U_WCHAR_IS_UTF16) || defined(U_WCHAR_IS_UTF32) || !UCONFIG_NO_CONVERSION
+/**
+ * Convert a UTF-16 string to a wchar_t string.
+ * If it is known at compile time that wchar_t strings are in UTF-16 or UTF-32, then
+ * this function simply calls the fast, dedicated function for that.
+ * Otherwise, two conversions UTF-16 -> default charset -> wchar_t* are performed.
+ *
+ * @param dest          A buffer for the result string. The result will be zero-terminated if
+ *                      the buffer is large enough.
+ * @param destCapacity  The size of the buffer (number of wchar_t's). 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 pDestLength   A pointer to receive the number of units written to the destination. If 
+ *                      pDestLength!=NULL then *pDestLength is always set to the 
+ *                      number of output units corresponding to the transformation of 
+ *                      all the input units, even in case of a buffer overflow.
+ * @param src           The original source string
+ * @param srcLength     The length of the original string. If -1, then src must be zero-terminated.
+ * @param pErrorCode    Must be a valid pointer to an error code value,
+ *                      which must not indicate a failure before the function call.
+ * @return The pointer to destination buffer.
+ * @stable ICU 2.0
+ */
+U_STABLE wchar_t* U_EXPORT2
+u_strToWCS(wchar_t *dest, 
+           int32_t destCapacity,
+           int32_t *pDestLength,
+           const UChar *src, 
+           int32_t srcLength,
+           UErrorCode *pErrorCode);
+/**
+ * Convert a wchar_t string to UTF-16.
+ * If it is known at compile time that wchar_t strings are in UTF-16 or UTF-32, then
+ * this function simply calls the fast, dedicated function for that.
+ * Otherwise, two conversions wchar_t* -> default charset -> UTF-16 are performed.
+ *
+ * @param dest          A buffer for the result string. The result will be zero-terminated if
+ *                      the buffer is large enough.
+ * @param destCapacity  The size of the buffer (number of UChars). 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 pDestLength   A pointer to receive the number of units written to the destination. If 
+ *                      pDestLength!=NULL then *pDestLength is always set to the 
+ *                      number of output units corresponding to the transformation of 
+ *                      all the input units, even in case of a buffer overflow.
+ * @param src           The original source string
+ * @param srcLength     The length of the original string. If -1, then src must be zero-terminated.
+ * @param pErrorCode    Must be a valid pointer to an error code value,
+ *                      which must not indicate a failure before the function call.
+ * @return The pointer to destination buffer.
+ * @stable ICU 2.0
+ */
+U_STABLE UChar* U_EXPORT2
+u_strFromWCS(UChar   *dest,
+             int32_t destCapacity, 
+             int32_t *pDestLength,
+             const wchar_t *src,
+             int32_t srcLength,
+             UErrorCode *pErrorCode);
+#endif /* defined(U_WCHAR_IS_UTF16) || defined(U_WCHAR_IS_UTF32) || !UCONFIG_NO_CONVERSION */
+
+/**
+ * Convert a UTF-16 string to UTF-8.
+ * If the input string is not well-formed, then the U_INVALID_CHAR_FOUND error code is set.
+ *
+ * @param dest          A buffer for the result string. The result will be zero-terminated if
+ *                      the buffer is large enough.
+ * @param destCapacity  The size of the buffer (number of chars). 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 pDestLength   A pointer to receive the number of units written to the destination. If 
+ *                      pDestLength!=NULL then *pDestLength is always set to the 
+ *                      number of output units corresponding to the transformation of 
+ *                      all the input units, even in case of a buffer overflow.
+ * @param src           The original source string
+ * @param srcLength     The length of the original string. If -1, then src must be zero-terminated.
+ * @param pErrorCode    Must be a valid pointer to an error code value,
+ *                      which must not indicate a failure before the function call.
+ * @return The pointer to destination buffer.
+ * @stable ICU 2.0
+ * @see u_strToUTF8WithSub
+ * @see u_strFromUTF8
+ */
+U_STABLE char* U_EXPORT2 
+u_strToUTF8(char *dest,           
+            int32_t destCapacity,
+            int32_t *pDestLength,
+            const UChar *src, 
+            int32_t srcLength,
+            UErrorCode *pErrorCode);
+
+/**
+ * Convert a UTF-8 string to UTF-16.
+ * If the input string is not well-formed, then the U_INVALID_CHAR_FOUND error code is set.
+ *
+ * @param dest          A buffer for the result string. The result will be zero-terminated if
+ *                      the buffer is large enough.
+ * @param destCapacity  The size of the buffer (number of UChars). 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 pDestLength   A pointer to receive the number of units written to the destination. If 
+ *                      pDestLength!=NULL then *pDestLength is always set to the 
+ *                      number of output units corresponding to the transformation of 
+ *                      all the input units, even in case of a buffer overflow.
+ * @param src           The original source string
+ * @param srcLength     The length of the original string. If -1, then src must be zero-terminated.
+ * @param pErrorCode    Must be a valid pointer to an error code value,
+ *                      which must not indicate a failure before the function call.
+ * @return The pointer to destination buffer.
+ * @stable ICU 2.0
+ * @see u_strFromUTF8WithSub
+ * @see u_strFromUTF8Lenient
+ */
+U_STABLE UChar* U_EXPORT2
+u_strFromUTF8(UChar *dest,             
+              int32_t destCapacity,
+              int32_t *pDestLength,
+              const char *src, 
+              int32_t srcLength,
+              UErrorCode *pErrorCode);
+
+/**
+ * Convert a UTF-16 string to UTF-8.
+ * If the input string is not well-formed, then the U_INVALID_CHAR_FOUND error code is set.
+ *
+ * Same as u_strToUTF8() except for the additional subchar which is output for
+ * illegal input sequences, instead of stopping with the U_INVALID_CHAR_FOUND error code.
+ * With subchar==U_SENTINEL, this function behaves exactly like u_strToUTF8().
+ *
+ * @param dest          A buffer for the result string. The result will be zero-terminated if
+ *                      the buffer is large enough.
+ * @param destCapacity  The size of the buffer (number of chars). 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 pDestLength   A pointer to receive the number of units written to the destination. If 
+ *                      pDestLength!=NULL then *pDestLength is always set to the 
+ *                      number of output units corresponding to the transformation of 
+ *                      all the input units, even in case of a buffer overflow.
+ * @param src           The original source string
+ * @param srcLength     The length of the original string. If -1, then src must be zero-terminated.
+ * @param subchar       The substitution character to use in place of an illegal input sequence,
+ *                      or U_SENTINEL if the function is to return with U_INVALID_CHAR_FOUND instead.
+ *                      A substitution character can be any valid Unicode code point (up to U+10FFFF)
+ *                      except for surrogate code points (U+D800..U+DFFF).
+ *                      The recommended value is U+FFFD "REPLACEMENT CHARACTER".
+ * @param pNumSubstitutions Output parameter receiving the number of substitutions if subchar>=0.
+ *                      Set to 0 if no substitutions occur or subchar<0.
+ *                      pNumSubstitutions can be NULL.
+ * @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 pointer to destination buffer.
+ * @see u_strToUTF8
+ * @see u_strFromUTF8WithSub
+ * @stable ICU 3.6
+ */
+U_STABLE char* U_EXPORT2
+u_strToUTF8WithSub(char *dest,
+            int32_t destCapacity,
+            int32_t *pDestLength,
+            const UChar *src,
+            int32_t srcLength,
+            UChar32 subchar, int32_t *pNumSubstitutions,
+            UErrorCode *pErrorCode);
+
+/**
+ * Convert a UTF-8 string to UTF-16.
+ * If the input string is not well-formed, then the U_INVALID_CHAR_FOUND error code is set.
+ *
+ * Same as u_strFromUTF8() except for the additional subchar which is output for
+ * illegal input sequences, instead of stopping with the U_INVALID_CHAR_FOUND error code.
+ * With subchar==U_SENTINEL, this function behaves exactly like u_strFromUTF8().
+ *
+ * @param dest          A buffer for the result string. The result will be zero-terminated if
+ *                      the buffer is large enough.
+ * @param destCapacity  The size of the buffer (number of UChars). 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 pDestLength   A pointer to receive the number of units written to the destination. If 
+ *                      pDestLength!=NULL then *pDestLength is always set to the 
+ *                      number of output units corresponding to the transformation of 
+ *                      all the input units, even in case of a buffer overflow.
+ * @param src           The original source string
+ * @param srcLength     The length of the original string. If -1, then src must be zero-terminated.
+ * @param subchar       The substitution character to use in place of an illegal input sequence,
+ *                      or U_SENTINEL if the function is to return with U_INVALID_CHAR_FOUND instead.
+ *                      A substitution character can be any valid Unicode code point (up to U+10FFFF)
+ *                      except for surrogate code points (U+D800..U+DFFF).
+ *                      The recommended value is U+FFFD "REPLACEMENT CHARACTER".
+ * @param pNumSubstitutions Output parameter receiving the number of substitutions if subchar>=0.
+ *                      Set to 0 if no substitutions occur or subchar<0.
+ *                      pNumSubstitutions can be NULL.
+ * @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 pointer to destination buffer.
+ * @see u_strFromUTF8
+ * @see u_strFromUTF8Lenient
+ * @see u_strToUTF8WithSub
+ * @stable ICU 3.6
+ */
+U_STABLE UChar* U_EXPORT2
+u_strFromUTF8WithSub(UChar *dest,
+              int32_t destCapacity,
+              int32_t *pDestLength,
+              const char *src,
+              int32_t srcLength,
+              UChar32 subchar, int32_t *pNumSubstitutions,
+              UErrorCode *pErrorCode);
+
+/**
+ * Convert a UTF-8 string to UTF-16.
+ *
+ * Same as u_strFromUTF8() except that this function is designed to be very fast,
+ * which it achieves by being lenient about malformed UTF-8 sequences.
+ * This function is intended for use in environments where UTF-8 text is
+ * expected to be well-formed.
+ *
+ * Its semantics are:
+ * - Well-formed UTF-8 text is correctly converted to well-formed UTF-16 text.
+ * - The function will not read beyond the input string, nor write beyond
+ *   the destCapacity.
+ * - Malformed UTF-8 results in "garbage" 16-bit Unicode strings which may not
+ *   be well-formed UTF-16.
+ *   The function will resynchronize to valid code point boundaries
+ *   within a small number of code points after an illegal sequence.
+ * - Non-shortest forms are not detected and will result in "spoofing" output.
+ *
+ * For further performance improvement, if srcLength is given (>=0),
+ * then it must be destCapacity>=srcLength.
+ *
+ * There is no inverse u_strToUTF8Lenient() function because there is practically
+ * no performance gain from not checking that a UTF-16 string is well-formed.
+ *
+ * @param dest          A buffer for the result string. The result will be zero-terminated if
+ *                      the buffer is large enough.
+ * @param destCapacity  The size of the buffer (number of UChars). 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).
+ *                      Unlike for other ICU functions, if srcLength>=0 then it
+ *                      must be destCapacity>=srcLength.
+ * @param pDestLength   A pointer to receive the number of units written to the destination. If 
+ *                      pDestLength!=NULL then *pDestLength is always set to the 
+ *                      number of output units corresponding to the transformation of 
+ *                      all the input units, even in case of a buffer overflow.
+ *                      Unlike for other ICU functions, if srcLength>=0 but
+ *                      destCapacity<srcLength, then *pDestLength will be set to srcLength
+ *                      (and U_BUFFER_OVERFLOW_ERROR will be set)
+ *                      regardless of the actual result length.
+ * @param src           The original source string
+ * @param srcLength     The length of the original string. If -1, then src must be zero-terminated.
+ * @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 pointer to destination buffer.
+ * @see u_strFromUTF8
+ * @see u_strFromUTF8WithSub
+ * @see u_strToUTF8WithSub
+ * @stable ICU 3.6
+ */
+U_STABLE UChar * U_EXPORT2
+u_strFromUTF8Lenient(UChar *dest,
+                     int32_t destCapacity,
+                     int32_t *pDestLength,
+                     const char *src,
+                     int32_t srcLength,
+                     UErrorCode *pErrorCode);
+
+/**
+ * Convert a UTF-16 string to UTF-32.
+ * If the input string is not well-formed, then the U_INVALID_CHAR_FOUND error code is set.
+ *
+ * @param dest          A buffer for the result string. The result will be zero-terminated if
+ *                      the buffer is large enough.
+ * @param destCapacity  The size of the buffer (number of UChar32s). 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 pDestLength   A pointer to receive the number of units written to the destination. If 
+ *                      pDestLength!=NULL then *pDestLength is always set to the 
+ *                      number of output units corresponding to the transformation of 
+ *                      all the input units, even in case of a buffer overflow.
+ * @param src           The original source string
+ * @param srcLength     The length of the original string. If -1, then src must be zero-terminated.
+ * @param pErrorCode    Must be a valid pointer to an error code value,
+ *                      which must not indicate a failure before the function call.
+ * @return The pointer to destination buffer.
+ * @see u_strToUTF32WithSub
+ * @see u_strFromUTF32
+ * @stable ICU 2.0
+ */
+U_STABLE UChar32* U_EXPORT2 
+u_strToUTF32(UChar32 *dest, 
+             int32_t  destCapacity,
+             int32_t  *pDestLength,
+             const UChar *src, 
+             int32_t  srcLength,
+             UErrorCode *pErrorCode);
+
+/**
+ * Convert a UTF-32 string to UTF-16.
+ * If the input string is not well-formed, then the U_INVALID_CHAR_FOUND error code is set.
+ *
+ * @param dest          A buffer for the result string. The result will be zero-terminated if
+ *                      the buffer is large enough.
+ * @param destCapacity  The size of the buffer (number of UChars). 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 pDestLength   A pointer to receive the number of units written to the destination. If 
+ *                      pDestLength!=NULL then *pDestLength is always set to the 
+ *                      number of output units corresponding to the transformation of 
+ *                      all the input units, even in case of a buffer overflow.
+ * @param src           The original source string
+ * @param srcLength     The length of the original string. If -1, then src must be zero-terminated.
+ * @param pErrorCode    Must be a valid pointer to an error code value,
+ *                      which must not indicate a failure before the function call.
+ * @return The pointer to destination buffer.
+ * @see u_strFromUTF32WithSub
+ * @see u_strToUTF32
+ * @stable ICU 2.0
+ */
+U_STABLE UChar* U_EXPORT2 
+u_strFromUTF32(UChar   *dest,
+               int32_t destCapacity, 
+               int32_t *pDestLength,
+               const UChar32 *src,
+               int32_t srcLength,
+               UErrorCode *pErrorCode);
+
+/**
+ * Convert a UTF-16 string to UTF-32.
+ * If the input string is not well-formed, then the U_INVALID_CHAR_FOUND error code is set.
+ *
+ * Same as u_strToUTF32() except for the additional subchar which is output for
+ * illegal input sequences, instead of stopping with the U_INVALID_CHAR_FOUND error code.
+ * With subchar==U_SENTINEL, this function behaves exactly like u_strToUTF32().
+ *
+ * @param dest          A buffer for the result string. The result will be zero-terminated if
+ *                      the buffer is large enough.
+ * @param destCapacity  The size of the buffer (number of UChar32s). 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 pDestLength   A pointer to receive the number of units written to the destination. If
+ *                      pDestLength!=NULL then *pDestLength is always set to the
+ *                      number of output units corresponding to the transformation of
+ *                      all the input units, even in case of a buffer overflow.
+ * @param src           The original source string
+ * @param srcLength     The length of the original string. If -1, then src must be zero-terminated.
+ * @param subchar       The substitution character to use in place of an illegal input sequence,
+ *                      or U_SENTINEL if the function is to return with U_INVALID_CHAR_FOUND instead.
+ *                      A substitution character can be any valid Unicode code point (up to U+10FFFF)
+ *                      except for surrogate code points (U+D800..U+DFFF).
+ *                      The recommended value is U+FFFD "REPLACEMENT CHARACTER".
+ * @param pNumSubstitutions Output parameter receiving the number of substitutions if subchar>=0.
+ *                      Set to 0 if no substitutions occur or subchar<0.
+ *                      pNumSubstitutions can be NULL.
+ * @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 pointer to destination buffer.
+ * @see u_strToUTF32
+ * @see u_strFromUTF32WithSub
+ * @stable ICU 4.2
+ */
+U_STABLE UChar32* U_EXPORT2
+u_strToUTF32WithSub(UChar32 *dest,
+             int32_t destCapacity,
+             int32_t *pDestLength,
+             const UChar *src,
+             int32_t srcLength,
+             UChar32 subchar, int32_t *pNumSubstitutions,
+             UErrorCode *pErrorCode);
+
+/**
+ * Convert a UTF-32 string to UTF-16.
+ * If the input string is not well-formed, then the U_INVALID_CHAR_FOUND error code is set.
+ *
+ * Same as u_strFromUTF32() except for the additional subchar which is output for
+ * illegal input sequences, instead of stopping with the U_INVALID_CHAR_FOUND error code.
+ * With subchar==U_SENTINEL, this function behaves exactly like u_strFromUTF32().
+ *
+ * @param dest          A buffer for the result string. The result will be zero-terminated if
+ *                      the buffer is large enough.
+ * @param destCapacity  The size of the buffer (number of UChars). 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 pDestLength   A pointer to receive the number of units written to the destination. If
+ *                      pDestLength!=NULL then *pDestLength is always set to the
+ *                      number of output units corresponding to the transformation of
+ *                      all the input units, even in case of a buffer overflow.
+ * @param src           The original source string
+ * @param srcLength     The length of the original string. If -1, then src must be zero-terminated.
+ * @param subchar       The substitution character to use in place of an illegal input sequence,
+ *                      or U_SENTINEL if the function is to return with U_INVALID_CHAR_FOUND instead.
+ *                      A substitution character can be any valid Unicode code point (up to U+10FFFF)
+ *                      except for surrogate code points (U+D800..U+DFFF).
+ *                      The recommended value is U+FFFD "REPLACEMENT CHARACTER".
+ * @param pNumSubstitutions Output parameter receiving the number of substitutions if subchar>=0.
+ *                      Set to 0 if no substitutions occur or subchar<0.
+ *                      pNumSubstitutions can be NULL.
+ * @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 pointer to destination buffer.
+ * @see u_strFromUTF32
+ * @see u_strToUTF32WithSub
+ * @stable ICU 4.2
+ */
+U_STABLE UChar* U_EXPORT2
+u_strFromUTF32WithSub(UChar *dest,
+               int32_t destCapacity,
+               int32_t *pDestLength,
+               const UChar32 *src,
+               int32_t srcLength,
+               UChar32 subchar, int32_t *pNumSubstitutions,
+               UErrorCode *pErrorCode);
+
+/**
+ * Convert a 16-bit Unicode string to Java Modified UTF-8.
+ * See http://java.sun.com/javase/6/docs/api/java/io/DataInput.html#modified-utf-8
+ *
+ * This function behaves according to the documentation for Java DataOutput.writeUTF()
+ * except that it does not encode the output length in the destination buffer
+ * and does not have an output length restriction.
+ * See http://java.sun.com/javase/6/docs/api/java/io/DataOutput.html#writeUTF(java.lang.String)
+ *
+ * The input string need not be well-formed UTF-16.
+ * (Therefore there is no subchar parameter.)
+ *
+ * @param dest          A buffer for the result string. The result will be zero-terminated if
+ *                      the buffer is large enough.
+ * @param destCapacity  The size of the buffer (number of chars). 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 pDestLength   A pointer to receive the number of units written to the destination. If 
+ *                      pDestLength!=NULL then *pDestLength is always set to the 
+ *                      number of output units corresponding to the transformation of 
+ *                      all the input units, even in case of a buffer overflow.
+ * @param src           The original source string
+ * @param srcLength     The length of the original string. If -1, then src must be zero-terminated.
+ * @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 pointer to destination buffer.
+ * @stable ICU 4.4
+ * @see u_strToUTF8WithSub
+ * @see u_strFromJavaModifiedUTF8WithSub
+ */
+U_STABLE char* U_EXPORT2 
+u_strToJavaModifiedUTF8(
+        char *dest,
+        int32_t destCapacity,
+        int32_t *pDestLength,
+        const UChar *src, 
+        int32_t srcLength,
+        UErrorCode *pErrorCode);
+
+/**
+ * Convert a Java Modified UTF-8 string to a 16-bit Unicode string.
+ * If the input string is not well-formed, then the U_INVALID_CHAR_FOUND error code is set.
+ *
+ * This function behaves according to the documentation for Java DataInput.readUTF()
+ * except that it takes a length parameter rather than
+ * interpreting the first two input bytes as the length.
+ * See http://java.sun.com/javase/6/docs/api/java/io/DataInput.html#readUTF()
+ *
+ * The output string may not be well-formed UTF-16.
+ *
+ * @param dest          A buffer for the result string. The result will be zero-terminated if
+ *                      the buffer is large enough.
+ * @param destCapacity  The size of the buffer (number of UChars). 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 pDestLength   A pointer to receive the number of units written to the destination. If 
+ *                      pDestLength!=NULL then *pDestLength is always set to the 
+ *                      number of output units corresponding to the transformation of 
+ *                      all the input units, even in case of a buffer overflow.
+ * @param src           The original source string
+ * @param srcLength     The length of the original string. If -1, then src must be zero-terminated.
+ * @param subchar       The substitution character to use in place of an illegal input sequence,
+ *                      or U_SENTINEL if the function is to return with U_INVALID_CHAR_FOUND instead.
+ *                      A substitution character can be any valid Unicode code point (up to U+10FFFF)
+ *                      except for surrogate code points (U+D800..U+DFFF).
+ *                      The recommended value is U+FFFD "REPLACEMENT CHARACTER".
+ * @param pNumSubstitutions Output parameter receiving the number of substitutions if subchar>=0.
+ *                      Set to 0 if no substitutions occur or subchar<0.
+ *                      pNumSubstitutions can be NULL.
+ * @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 pointer to destination buffer.
+ * @see u_strFromUTF8WithSub
+ * @see u_strFromUTF8Lenient
+ * @see u_strToJavaModifiedUTF8
+ * @stable ICU 4.4
+ */
+U_STABLE UChar* U_EXPORT2
+u_strFromJavaModifiedUTF8WithSub(
+        UChar *dest,
+        int32_t destCapacity,
+        int32_t *pDestLength,
+        const char *src,
+        int32_t srcLength,
+        UChar32 subchar, int32_t *pNumSubstitutions,
+        UErrorCode *pErrorCode);
+
+#endif
diff --git a/source/common/unicode/usystem.h b/source/common/unicode/usystem.h
new file mode 100644
index 0000000..5d83c8d
--- /dev/null
+++ b/source/common/unicode/usystem.h
@@ -0,0 +1,46 @@
+/*
+*******************************************************************************
+*   Copyright (C) 2004-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*******************************************************************************
+*
+*   file name:  usystem.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   Created by: genheaders.pl, a perl script written by Ram Viswanadha
+*
+*  Contains data for commenting out APIs.
+*  Gets included by umachine.h
+*
+*  THIS FILE IS MACHINE-GENERATED, DON'T PLAY WITH IT IF YOU DON'T KNOW WHAT
+*  YOU ARE DOING, OTHERWISE VERY BAD THINGS WILL HAPPEN!
+*/
+
+#ifndef USYSTEM_H
+#define USYSTEM_H
+
+#ifdef U_HIDE_SYSTEM_API
+
+#    if U_DISABLE_RENAMING
+#        define u_cleanup u_cleanup_SYSTEM_API_DO_NOT_USE
+#        define u_setAtomicIncDecFunctions u_setAtomicIncDecFunctions_SYSTEM_API_DO_NOT_USE
+#        define u_setMemoryFunctions u_setMemoryFunctions_SYSTEM_API_DO_NOT_USE
+#        define u_setMutexFunctions u_setMutexFunctions_SYSTEM_API_DO_NOT_USE
+#        define ucnv_setDefaultName ucnv_setDefaultName_SYSTEM_API_DO_NOT_USE
+#        define uloc_getDefault uloc_getDefault_SYSTEM_API_DO_NOT_USE
+#        define uloc_setDefault uloc_setDefault_SYSTEM_API_DO_NOT_USE
+#    else
+#        define u_cleanup_4_6 u_cleanup_SYSTEM_API_DO_NOT_USE
+#        define u_setAtomicIncDecFunctions_4_6 u_setAtomicIncDecFunctions_SYSTEM_API_DO_NOT_USE
+#        define u_setMemoryFunctions_4_6 u_setMemoryFunctions_SYSTEM_API_DO_NOT_USE
+#        define u_setMutexFunctions_4_6 u_setMutexFunctions_SYSTEM_API_DO_NOT_USE
+#        define ucnv_setDefaultName_4_6 ucnv_setDefaultName_SYSTEM_API_DO_NOT_USE
+#        define uloc_getDefault_4_6 uloc_getDefault_SYSTEM_API_DO_NOT_USE
+#        define uloc_setDefault_4_6 uloc_setDefault_SYSTEM_API_DO_NOT_USE
+#    endif /* U_DISABLE_RENAMING */
+
+#endif /* U_HIDE_SYSTEM_API */
+#endif /* USYSTEM_H */
+
diff --git a/source/common/unicode/utext.h b/source/common/unicode/utext.h
new file mode 100644
index 0000000..088a532
--- /dev/null
+++ b/source/common/unicode/utext.h
@@ -0,0 +1,1737 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2004-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  utext.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2004oct06
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __UTEXT_H__
+#define __UTEXT_H__
+
+/**
+ * \file
+ * \brief C API: Abstract Unicode Text API
+ *
+ * The Text Access API provides a means to allow text that is stored in alternative
+ * formats to work with ICU services.  ICU normally operates on text that is
+ * stored in UTF-16 format, in (UChar *) arrays for the C APIs or as type
+ * UnicodeString for C++ APIs.
+ *
+ * ICU Text Access allows other formats, such as UTF-8 or non-contiguous
+ * UTF-16 strings, to be placed in a UText wrapper and then passed to ICU services.
+ *
+ * There are three general classes of usage for UText:
+ *
+ *     Application Level Use.  This is the simplest usage - applications would
+ *     use one of the utext_open() functions on their input text, and pass
+ *     the resulting UText to the desired ICU service.
+ *
+ *     Second is usage in ICU Services, such as break iteration, that will need to
+ *     operate on input presented to them as a UText.  These implementations
+ *     will need to use the iteration and related UText functions to gain
+ *     access to the actual text.
+ *
+ *     The third class of UText users are "text providers."  These are the
+ *     UText implementations for the various text storage formats.  An application
+ *     or system with a unique text storage format can implement a set of
+ *     UText provider functions for that format, which will then allow
+ *     ICU services to operate on that format.
+ *
+ *
+ * <em>Iterating over text</em>
+ *
+ * Here is sample code for a forward iteration over the contents of a UText
+ *
+ * \code
+ *    UChar32  c;
+ *    UText    *ut = whatever();
+ *
+ *    for (c=utext_next32From(ut, 0); c>=0; c=utext_next32(ut)) {
+ *       // do whatever with the codepoint c here.
+ *    }
+ * \endcode
+ *
+ * And here is similar code to iterate in the reverse direction, from the end
+ * of the text towards the beginning.
+ *
+ * \code
+ *    UChar32  c;
+ *    UText    *ut = whatever();
+ *    int      textLength = utext_nativeLength(ut);
+ *    for (c=utext_previous32From(ut, textLength); c>=0; c=utext_previous32(ut)) {
+ *       // do whatever with the codepoint c here.
+ *    }
+ * \endcode
+ *
+ * <em>Characters and Indexing</em>
+ *
+ * Indexing into text by UText functions is nearly always in terms of the native
+ * indexing of the underlying text storage.  The storage format could be UTF-8
+ * or UTF-32, for example.  When coding to the UText access API, no assumptions
+ * can be made regarding the size of characters, or how far an index
+ * may move when iterating between characters.
+ *
+ * All indices supplied to UText functions are pinned to the length of the
+ * text.  An out-of-bounds index is not considered to be an error, but is
+ * adjusted to be in the range  0 <= index <= length of input text.
+ *
+ *
+ * When an index position is returned from a UText function, it will be
+ * a native index to the underlying text.  In the case of multi-unit characters,
+ * it will  always refer to the first position of the character,
+ * never to the interior.  This is essentially the same thing as saying that
+ * a returned index will always point to a boundary between characters.
+ *
+ * When a native index is supplied to a UText function, all indices that
+ * refer to any part of a multi-unit character representation are considered
+ * to be equivalent.  In the case of multi-unit characters, an incoming index
+ * will be logically normalized to refer to the start of the character.
+ * 
+ * It is possible to test whether a native index is on a code point boundary
+ * by doing a utext_setNativeIndex() followed by a utext_getNativeIndex().
+ * If the index is returned unchanged, it was on a code point boundary.  If
+ * an adjusted index is returned, the original index referred to the
+ * interior of a character.
+ *
+ * <em>Conventions for calling UText functions</em>
+ *
+ * Most UText access functions have as their first parameter a (UText *) pointer,
+ * which specifies the UText to be used.  Unless otherwise noted, the
+ * pointer must refer to a valid, open UText.  Attempting to
+ * use a closed UText or passing a NULL pointer is a programming error and
+ * will produce undefined results or NULL pointer exceptions.
+ * 
+ * The UText_Open family of functions can either open an existing (closed)
+ * UText, or heap allocate a new UText.  Here is sample code for creating
+ * a stack-allocated UText.
+ *
+ * \code
+ *    char     *s = whatever();  // A utf-8 string 
+ *    U_ErrorCode status = U_ZERO_ERROR;
+ *    UText    ut = UTEXT_INITIALIZER;
+ *    utext_openUTF8(ut, s, -1, &status);
+ *    if (U_FAILURE(status)) {
+ *        // error handling
+ *    } else {
+ *        // work with the UText
+ *    }
+ * \endcode
+ *
+ * Any existing UText passed to an open function _must_ have been initialized, 
+ * either by the UTEXT_INITIALIZER, or by having been originally heap-allocated
+ * by an open function.  Passing NULL will cause the open function to
+ * heap-allocate and fully initialize a new UText.
+ *
+ */
+
+
+
+#include "unicode/utypes.h"
+#include "unicode/uchar.h"
+#if U_SHOW_CPLUSPLUS_API
+#include "unicode/localpointer.h"
+#include "unicode/rep.h"
+#include "unicode/unistr.h"
+#include "unicode/chariter.h"
+#endif
+
+
+U_CDECL_BEGIN
+
+struct UText;
+typedef struct UText UText; /**< C typedef for struct UText. @stable ICU 3.6 */
+
+
+/***************************************************************************************
+ *
+ *   C Functions for creating UText wrappers around various kinds of text strings.
+ *
+ ****************************************************************************************/
+
+
+/**
+  * Close function for UText instances.
+  * Cleans up, releases any resources being held by an open UText.
+  * <p>
+  *   If the UText was originally allocated by one of the utext_open functions,
+  *   the storage associated with the utext will also be freed.
+  *   If the UText storage originated with the application, as it would with
+  *   a local or static instance, the storage will not be deleted.
+  *
+  *   An open UText can be reset to refer to new string by using one of the utext_open()
+  *   functions without first closing the UText.  
+  *
+  * @param ut  The UText to be closed.
+  * @return    NULL if the UText struct was deleted by the close.  If the UText struct
+  *            was originally provided by the caller to the open function, it is
+  *            returned by this function, and may be safely used again in
+  *            a subsequent utext_open.
+  *
+  * @stable ICU 3.4
+  */
+U_STABLE UText * U_EXPORT2
+utext_close(UText *ut);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUTextPointer
+ * "Smart pointer" class, closes a UText via utext_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUTextPointer, UText, utext_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Open a read-only UText implementation for UTF-8 strings.
+ * 
+ * \htmlonly
+ * Any invalid UTF-8 in the input will be handled in this way:
+ * a sequence of bytes that has the form of a truncated, but otherwise valid,
+ * UTF-8 sequence will be replaced by a single unicode replacement character, \uFFFD. 
+ * Any other illegal bytes will each be replaced by a \uFFFD.
+ * \endhtmlonly
+ * 
+ * @param ut     Pointer to a UText struct.  If NULL, a new UText will be created.
+ *               If non-NULL, must refer to an initialized UText struct, which will then
+ *               be reset to reference the specified UTF-8 string.
+ * @param s      A UTF-8 string.  Must not be NULL.
+ * @param length The length of the UTF-8 string in bytes, or -1 if the string is
+ *               zero terminated.
+ * @param status Errors are returned here.
+ * @return       A pointer to the UText.  If a pre-allocated UText was provided, it
+ *               will always be used and returned.
+ * @stable ICU 3.4
+ */
+U_STABLE UText * U_EXPORT2
+utext_openUTF8(UText *ut, const char *s, int64_t length, UErrorCode *status);
+
+
+/**
+ * Open a read-only UText for UChar * string.
+ * 
+ * @param ut     Pointer to a UText struct.  If NULL, a new UText will be created.
+ *               If non-NULL, must refer to an initialized UText struct, which will then
+ *               be reset to reference the specified UChar string.
+ * @param s      A UChar (UTF-16) string
+ * @param length The number of UChars in the input string, or -1 if the string is
+ *               zero terminated.
+ * @param status Errors are returned here.
+ * @return       A pointer to the UText.  If a pre-allocated UText was provided, it
+ *               will always be used and returned.
+ * @stable ICU 3.4
+ */
+U_STABLE UText * U_EXPORT2
+utext_openUChars(UText *ut, const UChar *s, int64_t length, UErrorCode *status);
+
+
+#if U_SHOW_CPLUSPLUS_API
+/**
+ * Open a writable UText for a non-const UnicodeString. 
+ * 
+ * @param ut      Pointer to a UText struct.  If NULL, a new UText will be created.
+ *                 If non-NULL, must refer to an initialized UText struct, which will then
+ *                 be reset to reference the specified input string.
+ * @param s       A UnicodeString.
+ * @param status Errors are returned here.
+ * @return        Pointer to the UText.  If a UText was supplied as input, this
+ *                 will always be used and returned.
+ * @stable ICU 3.4
+ */
+U_STABLE UText * U_EXPORT2
+utext_openUnicodeString(UText *ut, U_NAMESPACE_QUALIFIER UnicodeString *s, UErrorCode *status);
+
+
+/**
+ * Open a UText for a const UnicodeString.   The resulting UText will not be writable.
+ * 
+ * @param ut    Pointer to a UText struct.  If NULL, a new UText will be created.
+ *               If non-NULL, must refer to an initialized UText struct, which will then
+ *               be reset to reference the specified input string.
+ * @param s      A const UnicodeString to be wrapped.
+ * @param status Errors are returned here.
+ * @return       Pointer to the UText.  If a UText was supplied as input, this
+ *               will always be used and returned.
+ * @stable ICU 3.4
+ */
+U_STABLE UText * U_EXPORT2
+utext_openConstUnicodeString(UText *ut, const U_NAMESPACE_QUALIFIER UnicodeString *s, UErrorCode *status);
+
+
+/**
+ * Open a writable UText implementation for an ICU Replaceable object.
+ * @param ut    Pointer to a UText struct.  If NULL, a new UText will be created.
+ *               If non-NULL, must refer to an already existing UText, which will then
+ *               be reset to reference the specified replaceable text.
+ * @param rep    A Replaceable text object.
+ * @param status Errors are returned here.
+ * @return       Pointer to the UText.  If a UText was supplied as input, this
+ *               will always be used and returned.
+ * @see Replaceable
+ * @stable ICU 3.4
+ */
+U_STABLE UText * U_EXPORT2
+utext_openReplaceable(UText *ut, U_NAMESPACE_QUALIFIER Replaceable *rep, UErrorCode *status);
+
+/**
+ * Open a  UText implementation over an ICU CharacterIterator.
+ * @param ut    Pointer to a UText struct.  If NULL, a new UText will be created.
+ *               If non-NULL, must refer to an already existing UText, which will then
+ *               be reset to reference the specified replaceable text.
+ * @param ci     A Character Iterator.
+ * @param status Errors are returned here.
+ * @return       Pointer to the UText.  If a UText was supplied as input, this
+ *               will always be used and returned.
+ * @see Replaceable
+ * @stable ICU 3.4
+ */
+U_STABLE UText * U_EXPORT2
+utext_openCharacterIterator(UText *ut, U_NAMESPACE_QUALIFIER CharacterIterator *ic, UErrorCode *status);
+
+#endif
+
+
+/**
+  *  Clone a UText.  This is much like opening a UText where the source text is itself
+  *  another UText.
+  *
+  *  A deep clone will copy both the UText data structures and the underlying text.
+  *  The original and cloned UText will operate completely independently; modifications
+  *  made to the text in one will not affect the other.  Text providers are not
+  *  required to support deep clones.  The user of clone() must check the status return
+  *  and be prepared to handle failures.
+  *
+  *  The standard UText implementations for UTF8, UChar *, UnicodeString and
+  *  Replaceable all support deep cloning.
+  *
+  *  The UText returned from a deep clone will be writable, assuming that the text
+  *  provider is able to support writing, even if the source UText had been made
+  *  non-writable by means of UText_freeze().
+  *
+  *  A shallow clone replicates only the UText data structures; it does not make
+  *  a copy of the underlying text.  Shallow clones can be used as an efficient way to 
+  *  have multiple iterators active in a single text string that is not being
+  *  modified.
+  *
+  *  A shallow clone operation will not fail, barring truly exceptional conditions such
+  *  as memory allocation failures.
+  *
+  *  Shallow UText clones should be avoided if the UText functions that modify the
+  *  text are expected to be used, either on the original or the cloned UText.
+  *  Any such modifications  can cause unpredictable behavior.  Read Only
+  *  shallow clones provide some protection against errors of this type by
+  *  disabling text modification via the cloned UText.
+  *
+  *  A shallow clone made with the readOnly parameter == FALSE will preserve the 
+  *  utext_isWritable() state of the source object.  Note, however, that
+  *  write operations must be avoided while more than one UText exists that refer
+  *  to the same underlying text.
+  *
+  *  A UText and its clone may be safely concurrently accessed by separate threads.
+  *  This is true for read access only with shallow clones, and for both read and
+  *  write access with deep clones.
+  *  It is the responsibility of the Text Provider to ensure that this thread safety
+  *  constraint is met.
+  *
+  *  @param dest   A UText struct to be filled in with the result of the clone operation,
+  *                or NULL if the clone function should heap-allocate a new UText struct.
+  *                If non-NULL, must refer to an already existing UText, which will then
+  *                be reset to become the clone.
+  *  @param src    The UText to be cloned.
+  *  @param deep   TRUE to request a deep clone, FALSE for a shallow clone.
+  *  @param readOnly TRUE to request that the cloned UText have read only access to the 
+  *                underlying text.  
+
+  *  @param status Errors are returned here.  For deep clones, U_UNSUPPORTED_ERROR
+  *                will be returned if the text provider is unable to clone the
+  *                original text.
+  *  @return       The newly created clone, or NULL if the clone operation failed.
+  *  @stable ICU 3.4
+  */
+U_STABLE UText * U_EXPORT2
+utext_clone(UText *dest, const UText *src, UBool deep, UBool readOnly, UErrorCode *status);
+
+
+/**
+  *  Compare two UText objects for equality.
+  *  UTexts are equal if they are iterating over the same text, and
+  *    have the same iteration position within the text.
+  *    If either or both of the parameters are NULL, the comparison is FALSE.
+  *
+  *  @param a   The first of the two UTexts to compare.
+  *  @param b   The other UText to be compared.
+  *  @return    TRUE if the two UTexts are equal.
+  *  @stable ICU 3.6
+  */
+U_STABLE UBool U_EXPORT2
+utext_equals(const UText *a, const UText *b);
+
+
+/*****************************************************************************
+ *
+ *   Functions to work with the text represeted by a UText wrapper
+ *
+ *****************************************************************************/
+
+/**
+  * Get the length of the text.  Depending on the characteristics
+  * of the underlying text representation, this may be expensive.  
+  * @see  utext_isLengthExpensive()
+  *
+  *
+  * @param ut  the text to be accessed.
+  * @return the length of the text, expressed in native units.
+  *
+  * @stable ICU 3.4
+  */
+U_STABLE int64_t U_EXPORT2
+utext_nativeLength(UText *ut);
+
+/**
+ *  Return TRUE if calculating the length of the text could be expensive.
+ *  Finding the length of NUL terminated strings is considered to be expensive.
+ *
+ *  Note that the value of this function may change
+ *  as the result of other operations on a UText.
+ *  Once the length of a string has been discovered, it will no longer
+ *  be expensive to report it.
+ *
+ * @param ut the text to be accessed.
+ * @return TRUE if determining the length of the text could be time consuming.
+ * @stable ICU 3.4
+ */
+U_STABLE UBool U_EXPORT2
+utext_isLengthExpensive(const UText *ut);
+
+/**
+ * Returns the code point at the requested index,
+ * or U_SENTINEL (-1) if it is out of bounds.
+ *
+ * If the specified index points to the interior of a multi-unit
+ * character - one of the trail bytes of a UTF-8 sequence, for example -
+ * the complete code point will be returned.
+ *
+ * The iteration position will be set to the start of the returned code point.
+ *
+ * This function is roughly equivalent to the the sequence
+ *    utext_setNativeIndex(index);
+ *    utext_current32();
+ * (There is a subtle difference if the index is out of bounds by being less than zero - 
+ * utext_setNativeIndex(negative value) sets the index to zero, after which utext_current()
+ * will return the char at zero.  utext_char32At(negative index), on the other hand, will
+ * return the U_SENTINEL value of -1.)
+ * 
+ * @param ut the text to be accessed
+ * @param nativeIndex the native index of the character to be accessed.  If the index points
+ *        to other than the first unit of a multi-unit character, it will be adjusted
+ *        to the start of the character.
+ * @return the code point at the specified index.
+ * @stable ICU 3.4
+ */
+U_STABLE UChar32 U_EXPORT2
+utext_char32At(UText *ut, int64_t nativeIndex);
+
+
+/**
+ *
+ * Get the code point at the current iteration position,
+ * or U_SENTINEL (-1) if the iteration has reached the end of
+ * the input text.
+ *
+ * @param ut the text to be accessed.
+ * @return the Unicode code point at the current iterator position.
+ * @stable ICU 3.4
+ */
+U_STABLE UChar32 U_EXPORT2
+utext_current32(UText *ut);
+
+
+/**
+ * Get the code point at the current iteration position of the UText, and
+ * advance the position to the first index following the character.
+ *
+ * If the position is at the end of the text (the index following
+ * the last character, which is also the length of the text), 
+ * return U_SENTINEL (-1) and do not advance the index. 
+ *
+ * This is a post-increment operation.
+ *
+ * An inline macro version of this function, UTEXT_NEXT32(), 
+ * is available for performance critical use.
+ *
+ * @param ut the text to be accessed.
+ * @return the Unicode code point at the iteration position.
+ * @see UTEXT_NEXT32
+ * @stable ICU 3.4
+ */
+U_STABLE UChar32 U_EXPORT2
+utext_next32(UText *ut);
+
+
+/**
+ *  Move the iterator position to the character (code point) whose
+ *  index precedes the current position, and return that character.
+ *  This is a pre-decrement operation.
+ *
+ *  If the initial position is at the start of the text (index of 0) 
+ *  return U_SENTINEL (-1), and leave the position unchanged.
+ *
+ *  An inline macro version of this function, UTEXT_PREVIOUS32(), 
+ *  is available for performance critical use.
+ *
+ *  @param ut the text to be accessed.
+ *  @return the previous UChar32 code point, or U_SENTINEL (-1) 
+ *          if the iteration has reached the start of the text.
+ *  @see UTEXT_PREVIOUS32
+ *  @stable ICU 3.4
+ */
+U_STABLE UChar32 U_EXPORT2
+utext_previous32(UText *ut);
+
+
+/**
+  * Set the iteration index and return the code point at that index. 
+  * Leave the iteration index at the start of the following code point.
+  *
+  * This function is the most efficient and convenient way to
+  * begin a forward iteration.  The results are identical to the those
+  * from the sequence
+  * \code
+  *    utext_setIndex();
+  *    utext_next32();
+  * \endcode
+  *
+  *  @param ut the text to be accessed.
+  *  @param nativeIndex Iteration index, in the native units of the text provider.
+  *  @return Code point which starts at or before index,
+  *         or U_SENTINEL (-1) if it is out of bounds.
+  * @stable ICU 3.4
+  */
+U_STABLE UChar32 U_EXPORT2
+utext_next32From(UText *ut, int64_t nativeIndex);
+
+
+
+/**
+  * Set the iteration index, and return the code point preceding the
+  * one specified by the initial index.  Leave the iteration position
+  * at the start of the returned code point.
+  *
+  * This function is the most efficient and convenient way to
+  * begin a backwards iteration.
+  *
+  * @param ut the text to be accessed.
+  * @param nativeIndex Iteration index in the native units of the text provider.
+  * @return Code point preceding the one at the initial index,
+  *         or U_SENTINEL (-1) if it is out of bounds.
+  *
+  * @stable ICU 3.4
+  */
+U_STABLE UChar32 U_EXPORT2
+utext_previous32From(UText *ut, int64_t nativeIndex);
+
+/**
+  * Get the current iterator position, which can range from 0 to 
+  * the length of the text.
+  * The position is a native index into the input text, in whatever format it
+  * may have (possibly UTF-8 for example), and may not always be the same as
+  * the corresponding UChar (UTF-16) index.
+  * The returned position will always be aligned to a code point boundary. 
+  *
+  * @param ut the text to be accessed.
+  * @return the current index position, in the native units of the text provider.
+  * @stable ICU 3.4
+  */
+U_STABLE int64_t U_EXPORT2
+utext_getNativeIndex(const UText *ut);
+
+/**
+ * Set the current iteration position to the nearest code point
+ * boundary at or preceding the specified index.
+ * The index is in the native units of the original input text.
+ * If the index is out of range, it will be pinned to be within
+ * the range of the input text.
+ * <p>
+ * It will usually be more efficient to begin an iteration
+ * using the functions utext_next32From() or utext_previous32From()
+ * rather than setIndex().
+ * <p>
+ * Moving the index position to an adjacent character is best done
+ * with utext_next32(), utext_previous32() or utext_moveIndex32().
+ * Attempting to do direct arithmetic on the index position is
+ * complicated by the fact that the size (in native units) of a
+ * character depends on the underlying representation of the character
+ * (UTF-8, UTF-16, UTF-32, arbitrary codepage), and is not
+ * easily knowable.
+ *
+ * @param ut the text to be accessed.
+ * @param nativeIndex the native unit index of the new iteration position.
+ * @stable ICU 3.4
+ */
+U_STABLE void U_EXPORT2
+utext_setNativeIndex(UText *ut, int64_t nativeIndex);
+
+/**
+ * Move the iterator postion by delta code points.  The number of code points
+ * is a signed number; a negative delta will move the iterator backwards,
+ * towards the start of the text.
+ * <p>
+ * The index is moved by <code>delta</code> code points
+ * forward or backward, but no further backward than to 0 and
+ * no further forward than to utext_nativeLength().
+ * The resulting index value will be in between 0 and length, inclusive.
+ *
+ * @param ut the text to be accessed.
+ * @param delta the signed number of code points to move the iteration position.
+ * @return TRUE if the position could be moved the requested number of positions while
+ *              staying within the range [0 - text length].
+ * @stable ICU 3.4
+ */
+U_STABLE UBool U_EXPORT2
+utext_moveIndex32(UText *ut, int32_t delta);
+
+/**
+ * Get the native index of the character preceeding the current position.
+ * If the iteration position is already at the start of the text, zero
+ * is returned.
+ * The value returned is the same as that obtained from the following sequence,
+ * but without the side effect of changing the iteration position.
+ *   
+ * \code
+ *    UText  *ut = whatever;
+ *      ...
+ *    utext_previous(ut)
+ *    utext_getNativeIndex(ut);
+ * \endcode
+ *
+ * This function is most useful during forwards iteration, where it will get the
+ *   native index of the character most recently returned from utext_next().
+ *
+ * @param ut the text to be accessed
+ * @return the native index of the character preceeding the current index position,
+ *         or zero if the current position is at the start of the text.
+ * @stable ICU 3.6
+ */
+U_STABLE int64_t U_EXPORT2
+utext_getPreviousNativeIndex(UText *ut); 
+
+
+/**
+ *
+ * Extract text from a UText into a UChar buffer.  The range of text to be extracted
+ * is specified in the native indices of the UText provider.  These may not necessarily
+ * be UTF-16 indices.
+ * <p>
+ * The size (number of 16 bit UChars) of the data to be extracted is returned.  The
+ * full number of UChars is returned, even when the extracted text is truncated
+ * because the specified buffer size is too small.
+ * <p>
+ * The extracted string will (if you are a user) / must (if you are a text provider)
+ * be NUL-terminated if there is sufficient space in the destination buffer.  This
+ * terminating NUL is not included in the returned length.
+ * <p>
+ * The iteration index is left at the position following the last extracted character.
+ *
+ * @param  ut    the UText from which to extract data.
+ * @param  nativeStart the native index of the first character to extract.\
+ *               If the specified index is out of range,
+ *               it will be pinned to to be within 0 <= index <= textLength
+ * @param  nativeLimit the native string index of the position following the last
+ *               character to extract.  If the specified index is out of range,
+ *               it will be pinned to to be within 0 <= index <= textLength.
+ *               nativeLimit must be >= nativeStart.
+ * @param  dest  the UChar (UTF-16) buffer into which the extracted text is placed
+ * @param  destCapacity  The size, in UChars, of the destination buffer.  May be zero
+ *               for precomputing the required size.
+ * @param  status receives any error status.
+ *         U_BUFFER_OVERFLOW_ERROR: the extracted text was truncated because the 
+ *         buffer was too small.  Returns number of UChars for preflighting.
+ * @return Number of UChars in the data to be extracted.  Does not include a trailing NUL.
+ *
+ * @stable ICU 3.4
+ */
+U_STABLE int32_t U_EXPORT2
+utext_extract(UText *ut,
+             int64_t nativeStart, int64_t nativeLimit,
+             UChar *dest, int32_t destCapacity,
+             UErrorCode *status);
+
+
+/**
+ * Compare two UTexts (binary order). The comparison begins at each source text's
+ * iteration position. The iteration position of each UText will be left following
+ * the last character compared.
+ *
+ * The comparison is done in code point order; unlike u_strCompare, you
+ * cannot choose to use code unit order. This is because the characters
+ * in a UText are accessed one code point at a time, and may not be from a UTF-16
+ * context.
+ *
+ * This functions works with strings of different explicitly specified lengths
+ * unlike the ANSI C-like u_strcmp() and u_memcmp() etc.
+ * A length argument of -1 signifies that as much of the string should be used as
+ * is necessary to compare with the other string. If both length arguments are -1,
+ * the entire remaining portionss of both strings are used.
+ *
+ * @param s1 First source string.
+ * @param length1 Length of first source string in UTF-32 code points.
+ *
+ * @param s2 Second source string.
+ * @param length2 Length of second source string in UTF-32 code points.
+ *
+ * @return <0 or 0 or >0 as usual for string comparisons
+ *
+ * @internal ICU 4.4 technology preview
+ */
+U_INTERNAL int32_t U_EXPORT2
+utext_compare(UText *s1, int32_t length1,
+              UText *s2, int32_t length2);    
+
+/**
+ * Compare two UTexts (binary order). The comparison begins at each source text's
+ * iteration position. The iteration position of each UText will be left following
+ * the last character compared. This method differs from utext_compare in that
+ * it accepts native limits rather than lengths for each string.
+ *
+ * The comparison is done in code point order; unlike u_strCompare, you
+ * cannot choose to use code unit order. This is because the characters
+ * in a UText are accessed one code point at a time, and may not be from a UTF-16
+ * context.
+ *
+ * This functions works with strings of different explicitly specified lengths
+ * unlike the ANSI C-like u_strcmp() and u_memcmp() etc.
+ * A limit argument of -1 signifies that as much of the string should be used as
+ * is necessary to compare with the other string. If both limit arguments are -1,
+ * the entire remaining portionss of both strings are used.
+ *
+ * @param s1 First source string.
+ * @param limit1 Native index of the last character in the first source string to be considered.
+ *
+ * @param s2 Second source string.
+ * @param limit2 Native index of the last character in the second source string to be considered.
+ *
+ * @return <0 or 0 or >0 as usual for string comparisons
+ *
+ * @internal ICU 4.4 technology preview
+ */
+U_INTERNAL int32_t U_EXPORT2
+utext_compareNativeLimit(UText *s1, int64_t limit1,
+                         UText *s2, int64_t limit2);    
+
+/**
+ * Compare two UTexts case-insensitively using full case folding. The comparison
+ * begins at each source text's iteration position. The iteration position of each
+ * UText will be left following the last character compared.
+ *
+ * The comparison is done in code point order; this is because the characters
+ * in a UText are accessed one code point at a time, and may not be from a UTF-16
+ * context.
+ *
+ * This functions works with strings of different explicitly specified lengths
+ * unlike the ANSI C-like u_strcmp() and u_memcmp() etc.
+ * A length argument of -1 signifies that as much of the string should be used as
+ * is necessary to compare with the other string. If both length arguments are -1,
+ * the entire remaining portionss of both strings are used.
+ *
+ * @param s1 First source string.
+ * @param length1 Length of first source string in UTF-32 code points.
+ *
+ * @param s2 Second source string.
+ * @param length2 Length of second source string in UTF-32 code points.
+ *
+ * @param options A bit set of options:
+ *   - U_FOLD_CASE_DEFAULT or 0 is used for default options:
+ *     Comparison in code point order with default case folding.
+ *
+ *   - U_FOLD_CASE_EXCLUDE_SPECIAL_I
+ *
+ * @param pErrorCode Must be a valid pointer to an error code value,
+ *                  which must not indicate a failure before the function call.
+ *
+ * @return <0 or 0 or >0 as usual for string comparisons
+ *
+ * @internal ICU 4.4 technology preview
+ */
+U_INTERNAL int32_t U_EXPORT2
+utext_caseCompare(UText *s1, int32_t length1,
+                  UText *s2, int32_t length2,
+                  uint32_t options, UErrorCode *pErrorCode);    
+
+/**
+ * Compare two UTexts case-insensitively using full case folding. The comparison
+ * begins at each source text's iteration position. The iteration position of each
+ * UText will be left following the last character compared. This method differs from
+ * utext_caseCompare in that it accepts native limits rather than lengths for each
+ * string.
+ *
+ * The comparison is done in code point order; this is because the characters
+ * in a UText are accessed one code point at a time, and may not be from a UTF-16
+ * context.
+ *
+ * This functions works with strings of different explicitly specified lengths
+ * unlike the ANSI C-like u_strcmp() and u_memcmp() etc.
+ * A limit argument of -1 signifies that as much of the string should be used as
+ * is necessary to compare with the other string. If both length arguments are -1,
+ * the entire remaining portionss of both strings are used.
+ *
+ * @param s1 First source string.
+ * @param limit1 Native index of the last character in the first source string to be considered.
+ *
+ * @param s2 Second source string.
+ * @param limit2 Native index of the last character in the second source string to be considered.
+ *
+ * @param options A bit set of options:
+ *   - U_FOLD_CASE_DEFAULT or 0 is used for default options:
+ *     Comparison in code point order with default case folding.
+ *
+ *   - U_FOLD_CASE_EXCLUDE_SPECIAL_I
+ *
+ * @param pErrorCode Must be a valid pointer to an error code value,
+ *                  which must not indicate a failure before the function call.
+ *
+ * @return <0 or 0 or >0 as usual for string comparisons
+ *
+ * @internal ICU 4.4 technology preview
+ */
+U_INTERNAL int32_t U_EXPORT2
+utext_caseCompareNativeLimit(UText *s1, int64_t limit1,
+                             UText *s2, int64_t limit2,
+                             uint32_t options, UErrorCode *pErrorCode);    
+
+
+/************************************************************************************
+ *
+ *  #define inline versions of selected performance-critical text access functions
+ *          Caution:  do not use auto increment++ or decrement-- expressions
+ *                    as parameters to these macros.
+ *
+ *          For most use, where there is no extreme performance constraint, the
+ *          normal, non-inline functions are a better choice.  The resulting code
+ *          will be smaller, and, if the need ever arises, easier to debug.
+ *
+ *          These are implemented as #defines rather than real functions
+ *          because there is no fully portable way to do inline functions in plain C.
+ *
+ ************************************************************************************/
+
+/**
+ * inline version of utext_current32(), for performance-critical situations.
+ *
+ * Get the code point at the current iteration position of the UText.
+ * Returns U_SENTINEL (-1) if the position is at the end of the
+ * text.
+ *
+ * @internal ICU 4.4 technology preview
+ */
+#define UTEXT_CURRENT32(ut)  \
+    ((ut)->chunkOffset < (ut)->chunkLength && ((ut)->chunkContents)[(ut)->chunkOffset]<0xd800 ? \
+    ((ut)->chunkContents)[((ut)->chunkOffset)] : utext_current32(ut))
+
+/**
+ * inline version of utext_next32(), for performance-critical situations.
+ *
+ * Get the code point at the current iteration position of the UText, and
+ * advance the position to the first index following the character.
+ * This is a post-increment operation.
+ * Returns U_SENTINEL (-1) if the position is at the end of the
+ * text.
+ *
+ * @stable ICU 3.4
+ */
+#define UTEXT_NEXT32(ut)  \
+    ((ut)->chunkOffset < (ut)->chunkLength && ((ut)->chunkContents)[(ut)->chunkOffset]<0xd800 ? \
+    ((ut)->chunkContents)[((ut)->chunkOffset)++] : utext_next32(ut))
+
+/**
+ * inline version of utext_previous32(), for performance-critical situations.
+ *
+ *  Move the iterator position to the character (code point) whose
+ *  index precedes the current position, and return that character.
+ *  This is a pre-decrement operation.
+ *  Returns U_SENTINEL (-1) if the position is at the start of the  text.
+ *
+ * @stable ICU 3.4
+ */
+#define UTEXT_PREVIOUS32(ut)  \
+    ((ut)->chunkOffset > 0 && \
+     (ut)->chunkContents[(ut)->chunkOffset-1] < 0xd800 ? \
+          (ut)->chunkContents[--((ut)->chunkOffset)]  :  utext_previous32(ut))
+
+/**
+  *  inline version of utext_getNativeIndex(), for performance-critical situations.
+  *
+  * Get the current iterator position, which can range from 0 to 
+  * the length of the text.
+  * The position is a native index into the input text, in whatever format it
+  * may have (possibly UTF-8 for example), and may not always be the same as
+  * the corresponding UChar (UTF-16) index.
+  * The returned position will always be aligned to a code point boundary. 
+  *
+  * @stable ICU 3.6
+  */
+#define UTEXT_GETNATIVEINDEX(ut)                       \
+    ((ut)->chunkOffset <= (ut)->nativeIndexingLimit?   \
+        (ut)->chunkNativeStart+(ut)->chunkOffset :     \
+        (ut)->pFuncs->mapOffsetToNative(ut))    
+
+/**
+  *  inline version of utext_setNativeIndex(), for performance-critical situations.
+  *
+  * Set the current iteration position to the nearest code point
+  * boundary at or preceding the specified index.
+  * The index is in the native units of the original input text.
+  * If the index is out of range, it will be pinned to be within
+  * the range of the input text.
+  *
+  * @stable ICU 3.8
+  */
+#define UTEXT_SETNATIVEINDEX(ut, ix)                       \
+    { int64_t __offset = (ix) - (ut)->chunkNativeStart; \
+      if (__offset>=0 && __offset<=(int64_t)(ut)->nativeIndexingLimit) { \
+          (ut)->chunkOffset=(int32_t)__offset; \
+      } else { \
+          utext_setNativeIndex((ut), (ix)); } }
+
+
+
+/************************************************************************************
+ *
+ *   Functions related to writing or modifying the text.
+ *   These will work only with modifiable UTexts.  Attempting to
+ *   modify a read-only UText will return an error status.
+ *
+ ************************************************************************************/
+
+
+/**
+ *  Return TRUE if the text can be written (modified) with utext_replace() or
+ *  utext_copy().  For the text to be writable, the text provider must
+ *  be of a type that supports writing and the UText must not be frozen.
+ *
+ *  Attempting to modify text when utext_isWriteable() is FALSE will fail -
+ *  the text will not be modified, and an error will be returned from the function
+ *  that attempted the modification.
+ *
+ * @param  ut   the UText to be tested.
+ * @return TRUE if the text is modifiable.
+ *
+ * @see    utext_freeze()
+ * @see    utext_replace()
+ * @see    utext_copy()
+ * @stable ICU 3.4
+ *
+ */
+U_STABLE UBool U_EXPORT2
+utext_isWritable(const UText *ut);
+
+
+/**
+  * Test whether there is meta data associated with the text.
+  * @see Replaceable::hasMetaData()
+  *
+  * @param ut The UText to be tested
+  * @return TRUE if the underlying text includes meta data.
+  * @stable ICU 3.4
+  */
+U_STABLE UBool U_EXPORT2
+utext_hasMetaData(const UText *ut);
+
+
+/**
+ * Replace a range of the original text with a replacement text.
+ *
+ * Leaves the current iteration position at the position following the
+ *  newly inserted replacement text.
+ *
+ * This function is only available on UText types that support writing,
+ * that is, ones where utext_isWritable() returns TRUE.
+ *
+ * When using this function, there should be only a single UText opened onto the
+ * underlying native text string.  Behavior after a replace operation
+ * on a UText is undefined for any other additional UTexts that refer to the
+ * modified string.
+ *
+ * @param ut               the UText representing the text to be operated on.
+ * @param nativeStart      the native index of the start of the region to be replaced
+ * @param nativeLimit      the native index of the character following the region to be replaced.
+ * @param replacementText  pointer to the replacement text
+ * @param replacementLength length of the replacement text, or -1 if the text is NUL terminated.
+ * @param status           receives any error status.  Possible errors include
+ *                         U_NO_WRITE_PERMISSION
+ *
+ * @return The signed number of (native) storage units by which
+ *         the length of the text expanded or contracted.
+ *
+ * @stable ICU 3.4
+ */
+U_STABLE int32_t U_EXPORT2
+utext_replace(UText *ut,
+             int64_t nativeStart, int64_t nativeLimit,
+             const UChar *replacementText, int32_t replacementLength,
+             UErrorCode *status);
+
+
+
+/**
+ *
+ * Copy or move a substring from one position to another within the text,
+ * while retaining any metadata associated with the text.
+ * This function is used to duplicate or reorder substrings.
+ * The destination index must not overlap the source range.
+ *
+ * The text to be copied or moved is inserted at destIndex;
+ * it does not replace or overwrite any existing text.
+ *
+ * The iteration position is left following the newly inserted text
+ * at the destination position.
+ *
+ * This function is only available on UText types that support writing,
+ * that is, ones where utext_isWritable() returns TRUE.
+ *
+ * When using this function, there should be only a single UText opened onto the
+ * underlying native text string.  Behavior after a copy operation
+ * on a UText is undefined in any other additional UTexts that refer to the
+ * modified string.
+ *
+ * @param ut           The UText representing the text to be operated on.
+ * @param nativeStart  The native index of the start of the region to be copied or moved
+ * @param nativeLimit  The native index of the character position following the region
+ *                     to be copied.
+ * @param destIndex    The native destination index to which the source substring is
+ *                     copied or moved.
+ * @param move         If TRUE, then the substring is moved, not copied/duplicated.
+ * @param status       receives any error status.  Possible errors include U_NO_WRITE_PERMISSION
+ *                       
+ * @stable ICU 3.4
+ */
+U_STABLE void U_EXPORT2
+utext_copy(UText *ut,
+          int64_t nativeStart, int64_t nativeLimit,
+          int64_t destIndex,
+          UBool move,
+          UErrorCode *status);
+
+
+/**
+  *  <p>
+  *  Freeze a UText.  This prevents any modification to the underlying text itself
+  *  by means of functions operating on this UText.
+  *  </p>
+  *  <p>
+  *  Once frozen, a UText can not be unfrozen.  The intent is to ensure
+  *  that a the text underlying a frozen UText wrapper cannot be modified via that UText.
+  *  </p>
+  *  <p>
+  *  Caution:  freezing a UText will disable changes made via the specific
+  *   frozen UText wrapper only; it will not have any effect on the ability to
+  *   directly modify the text by bypassing the UText.  Any such backdoor modifications
+  *   are always an error while UText access is occuring because the underlying
+  *   text can get out of sync with UText's buffering.
+  *  </p>
+  *
+  *  @param ut  The UText to be frozen.
+  *  @see   utext_isWritable()
+  *  @stable ICU 3.6
+  */
+U_STABLE void U_EXPORT2
+utext_freeze(UText *ut);
+
+
+/**
+ * UText provider properties (bit field indexes).
+ *
+ * @see UText
+ * @stable ICU 3.4
+ */
+enum {
+    /**
+     * It is potentially time consuming for the provider to determine the length of the text.
+     * @stable ICU 3.4
+     */
+    UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE = 1,
+    /**
+     * Text chunks remain valid and usable until the text object is modified or
+     * deleted, not just until the next time the access() function is called
+     * (which is the default).
+     * @stable ICU 3.4
+     */
+    UTEXT_PROVIDER_STABLE_CHUNKS = 2,
+    /**
+     * The provider supports modifying the text via the replace() and copy()
+     * functions.
+     * @see Replaceable
+     * @stable ICU 3.4
+     */
+    UTEXT_PROVIDER_WRITABLE = 3,
+    /**
+     * There is meta data associated with the text.
+     * @see Replaceable::hasMetaData()
+     * @stable ICU 3.4
+     */ 
+    UTEXT_PROVIDER_HAS_META_DATA = 4,
+    /**
+     * Text provider owns the text storage.
+     *  Generally occurs as the result of a deep clone of the UText.
+     *  When closing the UText, the associated text must
+     *  also be closed/deleted/freed/ whatever is appropriate.
+     * @stable ICU 3.6
+     */
+     UTEXT_PROVIDER_OWNS_TEXT = 5
+};
+
+/**
+  * Function type declaration for UText.clone().
+  *
+  *  clone a UText.  Much like opening a UText where the source text is itself
+  *  another UText.
+  *
+  *  A deep clone will copy both the UText data structures and the underlying text.
+  *  The original and cloned UText will operate completely independently; modifications
+  *  made to the text in one will not effect the other.  Text providers are not
+  *  required to support deep clones.  The user of clone() must check the status return
+  *  and be prepared to handle failures.
+  *
+  *  A shallow clone replicates only the UText data structures; it does not make
+  *  a copy of the underlying text.  Shallow clones can be used as an efficient way to 
+  *  have multiple iterators active in a single text string that is not being
+  *  modified.
+  *
+  *  A shallow clone operation must not fail except for truly exceptional conditions such
+  *  as memory allocation failures.
+  *
+  *  A UText and its clone may be safely concurrently accessed by separate threads.
+  *  This is true for both shallow and deep clones.
+  *  It is the responsibility of the Text Provider to ensure that this thread safety
+  *  constraint is met.
+
+  *
+  *  @param dest   A UText struct to be filled in with the result of the clone operation,
+  *                or NULL if the clone function should heap-allocate a new UText struct.
+  *  @param src    The UText to be cloned.
+  *  @param deep   TRUE to request a deep clone, FALSE for a shallow clone.
+  *  @param status Errors are returned here.  For deep clones, U_UNSUPPORTED_ERROR
+  *                should be returned if the text provider is unable to clone the
+  *                original text.
+  *  @return       The newly created clone, or NULL if the clone operation failed.
+  *
+  * @stable ICU 3.4
+  */
+typedef UText * U_CALLCONV
+UTextClone(UText *dest, const UText *src, UBool deep, UErrorCode *status);
+
+
+/**
+ * Function type declaration for UText.nativeLength().
+ *
+ * @param ut the UText to get the length of.
+ * @return the length, in the native units of the original text string.
+ * @see UText
+ * @stable ICU 3.4
+ */
+typedef int64_t U_CALLCONV
+UTextNativeLength(UText *ut);
+
+/**
+ * Function type declaration for UText.access().  Get the description of the text chunk
+ *  containing the text at a requested native index.  The UText's iteration
+ *  position will be left at the requested index.  If the index is out
+ *  of bounds, the iteration position will be left at the start or end
+ *  of the string, as appropriate.
+ *
+ *  Chunks must begin and end on code point boundaries.  A single code point
+ *  comprised of multiple storage units must never span a chunk boundary.
+ *
+ *
+ * @param ut          the UText being accessed.
+ * @param nativeIndex Requested index of the text to be accessed.
+ * @param forward     If TRUE, then the returned chunk must contain text
+ *                    starting from the index, so that start<=index<limit.
+ *                    If FALSE, then the returned chunk must contain text
+ *                    before the index, so that start<index<=limit.
+ * @return            True if the requested index could be accessed.  The chunk
+ *                    will contain the requested text.
+ *                    False value if a chunk cannot be accessed
+ *                    (the requested index is out of bounds).
+ *
+ * @see UText
+ * @stable ICU 3.4
+ */
+typedef UBool U_CALLCONV
+UTextAccess(UText *ut, int64_t nativeIndex, UBool forward);
+
+/**
+ * Function type declaration for UText.extract().
+ *
+ * Extract text from a UText into a UChar buffer.  The range of text to be extracted
+ * is specified in the native indices of the UText provider.  These may not necessarily
+ * be UTF-16 indices.
+ * <p>
+ * The size (number of 16 bit UChars) in the data to be extracted is returned.  The
+ * full amount is returned, even when the specified buffer size is smaller.
+ * <p>
+ * The extracted string will (if you are a user) / must (if you are a text provider)
+ * be NUL-terminated if there is sufficient space in the destination buffer.
+ *
+ * @param  ut            the UText from which to extract data.
+ * @param  nativeStart   the native index of the first characer to extract.
+ * @param  nativeLimit   the native string index of the position following the last
+ *                       character to extract.
+ * @param  dest          the UChar (UTF-16) buffer into which the extracted text is placed
+ * @param  destCapacity  The size, in UChars, of the destination buffer.  May be zero
+ *                       for precomputing the required size.
+ * @param  status        receives any error status.
+ *                       If U_BUFFER_OVERFLOW_ERROR: Returns number of UChars for
+ *                       preflighting.
+ * @return Number of UChars in the data.  Does not include a trailing NUL.
+ *
+ * @stable ICU 3.4
+ */
+typedef int32_t U_CALLCONV
+UTextExtract(UText *ut,
+             int64_t nativeStart, int64_t nativeLimit,
+             UChar *dest, int32_t destCapacity,
+             UErrorCode *status);
+
+/**
+ * Function type declaration for UText.replace().
+ *
+ * Replace a range of the original text with a replacement text.
+ *
+ * Leaves the current iteration position at the position following the
+ *  newly inserted replacement text.
+ *
+ * This function need only be implemented on UText types that support writing.
+ *
+ * When using this function, there should be only a single UText opened onto the
+ * underlying native text string.  The function is responsible for updating the
+ * text chunk within the UText to reflect the updated iteration position,
+ * taking into account any changes to the underlying string's structure caused
+ * by the replace operation.
+ *
+ * @param ut               the UText representing the text to be operated on.
+ * @param nativeStart      the index of the start of the region to be replaced
+ * @param nativeLimit      the index of the character following the region to be replaced.
+ * @param replacementText  pointer to the replacement text
+ * @param replacmentLength length of the replacement text in UChars, or -1 if the text is NUL terminated.
+ * @param status           receives any error status.  Possible errors include
+ *                         U_NO_WRITE_PERMISSION
+ *
+ * @return The signed number of (native) storage units by which
+ *         the length of the text expanded or contracted.
+ *
+ * @stable ICU 3.4
+ */
+typedef int32_t U_CALLCONV
+UTextReplace(UText *ut,
+             int64_t nativeStart, int64_t nativeLimit,
+             const UChar *replacementText, int32_t replacmentLength,
+             UErrorCode *status);
+
+/**
+ * Function type declaration for UText.copy().
+ *
+ * Copy or move a substring from one position to another within the text,
+ * while retaining any metadata associated with the text.
+ * This function is used to duplicate or reorder substrings.
+ * The destination index must not overlap the source range.
+ *
+ * The text to be copied or moved is inserted at destIndex;
+ * it does not replace or overwrite any existing text.
+ *
+ * This function need only be implemented for UText types that support writing.
+ *
+ * When using this function, there should be only a single UText opened onto the
+ * underlying native text string.  The function is responsible for updating the
+ * text chunk within the UText to reflect the updated iteration position,
+ * taking into account any changes to the underlying string's structure caused
+ * by the replace operation.
+ *
+ * @param ut           The UText representing the text to be operated on.
+ * @param nativeStart  The index of the start of the region to be copied or moved
+ * @param nativeLimit  The index of the character following the region to be replaced.
+ * @param nativeDest   The destination index to which the source substring is copied or moved.
+ * @param move         If TRUE, then the substring is moved, not copied/duplicated.
+ * @param status       receives any error status.  Possible errors include U_NO_WRITE_PERMISSION
+ *
+ * @stable ICU 3.4
+ */
+typedef void U_CALLCONV
+UTextCopy(UText *ut,
+          int64_t nativeStart, int64_t nativeLimit,
+          int64_t nativeDest,
+          UBool move,
+          UErrorCode *status);
+
+/**
+ * Function type declaration for UText.mapOffsetToNative().
+ * Map from the current UChar offset within the current text chunk to
+ *  the corresponding native index in the original source text.
+ *
+ * This is required only for text providers that do not use native UTF-16 indexes.
+ *
+ * @param ut     the UText.
+ * @return Absolute (native) index corresponding to chunkOffset in the current chunk.
+ *         The returned native index should always be to a code point boundary.
+ *
+ * @stable ICU 3.4
+ */
+typedef int64_t U_CALLCONV
+UTextMapOffsetToNative(const UText *ut);
+
+/**
+ * Function type declaration for UText.mapIndexToUTF16().
+ * Map from a native index to a UChar offset within a text chunk.
+ * Behavior is undefined if the native index does not fall within the
+ *   current chunk.
+ *
+ * This function is required only for text providers that do not use native UTF-16 indexes.
+ *
+ * @param ut          The UText containing the text chunk.
+ * @param nativeIndex Absolute (native) text index, chunk->start<=index<=chunk->limit.
+ * @return            Chunk-relative UTF-16 offset corresponding to the specified native
+ *                    index.
+ *
+ * @stable ICU 3.4
+ */
+typedef int32_t U_CALLCONV
+UTextMapNativeIndexToUTF16(const UText *ut, int64_t nativeIndex);
+
+
+/**
+ * Function type declaration for UText.utextClose().
+ *
+ * A Text Provider close function is only required for provider types that make
+ *  allocations in their open function (or other functions) that must be 
+ *  cleaned when the UText is closed.
+ *
+ * The allocation of the UText struct itself and any "extra" storage
+ * associated with the UText is handled by the common UText implementation
+ * and does not require provider specific cleanup in a close function.
+ *
+ * Most UText provider implementations do not need to implement this function.
+ *
+ * @param ut A UText object to be closed.
+ *
+ * @stable ICU 3.4
+ */
+typedef void U_CALLCONV
+UTextClose(UText *ut);
+
+
+/**
+  *   (public)  Function dispatch table for UText.
+  *             Conceptually very much like a C++ Virtual Function Table.
+  *             This struct defines the organization of the table.
+  *             Each text provider implementation must provide an
+  *              actual table that is initialized with the appropriate functions
+  *              for the type of text being handled.
+  *   @stable ICU 3.6
+  */
+struct UTextFuncs {
+    /**
+     *   (public)  Function table size, sizeof(UTextFuncs)
+     *             Intended for use should the table grow to accomodate added
+     *             functions in the future, to allow tests for older format
+     *             function tables that do not contain the extensions.
+     *
+     *             Fields are placed for optimal alignment on
+     *             32/64/128-bit-pointer machines, by normally grouping together
+     *             4 32-bit fields,
+     *             4 pointers,
+     *             2 64-bit fields
+     *             in sequence.
+     *   @stable ICU 3.6
+     */
+    int32_t       tableSize;
+
+    /**
+      *   (private)  Alignment padding.
+      *              Do not use, reserved for use by the UText framework only.
+      *   @internal
+      */
+    int32_t       reserved1, /** @internal */ reserved2, /** @internal */ reserved3;
+
+
+    /**
+     * (public) Function pointer for UTextClone
+     *
+     * @see UTextClone
+     * @stable ICU 3.6
+     */
+    UTextClone *clone;
+
+    /**
+     * (public) function pointer for UTextLength
+     * May be expensive to compute!
+     *
+     * @see UTextLength
+     * @stable ICU 3.6
+     */
+    UTextNativeLength *nativeLength;
+
+    /**
+     * (public) Function pointer for UTextAccess.
+     *
+     * @see UTextAccess
+     * @stable ICU 3.6
+     */
+    UTextAccess *access;
+
+    /**
+     * (public) Function pointer for UTextExtract.
+     *
+     * @see UTextExtract
+     * @stable ICU 3.6
+     */
+    UTextExtract *extract;
+
+    /**
+     * (public) Function pointer for UTextReplace.
+     *
+     * @see UTextReplace
+     * @stable ICU 3.6
+     */
+    UTextReplace *replace;
+
+    /**
+     * (public) Function pointer for UTextCopy.
+     *
+     * @see UTextCopy
+     * @stable ICU 3.6
+     */
+    UTextCopy *copy;
+
+    /**
+     * (public) Function pointer for UTextMapOffsetToNative.
+     *
+     * @see UTextMapOffsetToNative
+     * @stable ICU 3.6
+     */
+    UTextMapOffsetToNative *mapOffsetToNative;
+
+    /**
+     * (public) Function pointer for UTextMapNativeIndexToUTF16.
+     *
+     * @see UTextMapNativeIndexToUTF16
+     * @stable ICU 3.6
+     */
+    UTextMapNativeIndexToUTF16 *mapNativeIndexToUTF16;
+
+    /**
+     * (public) Function pointer for UTextClose.
+      *
+      * @see UTextClose
+      * @stable ICU 3.6
+      */
+    UTextClose  *close;
+
+    /**
+      * (private)  Spare function pointer
+      * @internal
+      */
+    UTextClose  *spare1;
+    
+    /**
+      * (private)  Spare function pointer
+      * @internal
+      */
+    UTextClose  *spare2;
+
+    /**
+      * (private)  Spare function pointer
+      * @internal
+      */
+    UTextClose  *spare3;
+
+};
+/**
+ * Function dispatch table for UText
+ * @see UTextFuncs
+ */
+typedef struct UTextFuncs UTextFuncs;
+
+ /**
+  *   UText struct.  Provides the interface between the generic UText access code
+  *                  and the UText provider code that works on specific kinds of
+  *                  text  (UTF-8, noncontiguous UTF-16, whatever.)
+  *
+  *                  Applications that are using predefined types of text providers
+  *                  to pass text data to ICU services will have no need to view the
+  *                  internals of the UText structs that they open.
+  *
+  * @stable ICU 3.6
+  */
+struct UText {
+    /**
+     *     (private)  Magic.  Used to help detect when UText functions are handed
+     *                        invalid or unitialized UText structs.
+     *                        utext_openXYZ() functions take an initialized,
+     *                        but not necessarily open, UText struct as an
+     *                        optional fill-in parameter.  This magic field
+     *                        is used to check for that initialization.
+     *                        Text provider close functions must NOT clear
+     *                        the magic field because that would prevent
+     *                        reuse of the UText struct.
+     * @internal
+     */
+    uint32_t       magic;
+
+
+    /**
+     *     (private)  Flags for managing the allocation and freeing of
+     *                memory associated with this UText.
+     * @internal
+     */
+    int32_t        flags;
+
+
+    /**
+      *  Text provider properties.  This set of flags is maintainted by the
+      *                             text provider implementation.
+      *  @stable ICU 3.4
+      */
+    int32_t         providerProperties;
+
+    /**
+     * (public) sizeOfStruct=sizeof(UText)
+     * Allows possible backward compatible extension.
+     *
+     * @stable ICU 3.4
+     */
+    int32_t         sizeOfStruct;
+    
+    /* ------ 16 byte alignment boundary -----------  */
+    
+
+    /**
+      *  (protected) Native index of the first character position following
+      *              the current chunk.
+      *  @stable ICU 3.6
+      */
+    int64_t         chunkNativeLimit;
+
+    /**
+     *   (protected)  Size in bytes of the extra space (pExtra).
+     *  @stable ICU 3.4
+     */
+    int32_t        extraSize;
+
+    /**
+      *    (protected) The highest chunk offset where native indexing and
+      *    chunk (UTF-16) indexing correspond.  For UTF-16 sources, value
+      *    will be equal to chunkLength.
+      *
+      *    @stable ICU 3.6
+      */
+    int32_t         nativeIndexingLimit;
+
+    /* ---- 16 byte alignment boundary------ */
+    
+    /**
+     *  (protected) Native index of the first character in the text chunk.
+     *  @stable ICU 3.6
+     */
+    int64_t         chunkNativeStart;
+
+    /**
+     *  (protected) Current iteration position within the text chunk (UTF-16 buffer).
+     *  This is the index to the character that will be returned by utext_next32().
+     *  @stable ICU 3.6
+     */
+    int32_t         chunkOffset;
+
+    /**
+     *  (protected) Length the text chunk (UTF-16 buffer), in UChars.
+     *  @stable ICU 3.6
+     */
+    int32_t         chunkLength;
+
+    /* ---- 16  byte alignment boundary-- */
+    
+
+    /**
+     *  (protected)  pointer to a chunk of text in UTF-16 format.
+     *  May refer either to original storage of the source of the text, or
+     *  if conversion was required, to a buffer owned by the UText.
+     *  @stable ICU 3.6
+     */
+    const UChar    *chunkContents;
+
+     /**
+      * (public)     Pointer to Dispatch table for accessing functions for this UText.
+      * @stable ICU 3.6
+      */
+    const UTextFuncs     *pFuncs;
+
+    /**
+     *  (protected)  Pointer to additional space requested by the
+     *               text provider during the utext_open operation.
+     * @stable ICU 3.4
+     */
+    void          *pExtra;
+
+    /**
+     * (protected) Pointer to string or text-containin object or similar.
+     * This is the source of the text that this UText is wrapping, in a format
+     *  that is known to the text provider functions.
+     * @stable ICU 3.4
+     */
+    const void   *context;
+
+    /* --- 16 byte alignment boundary--- */
+
+    /**
+     * (protected) Pointer fields available for use by the text provider.
+     * Not used by UText common code.
+     * @stable ICU 3.6
+     */
+    const void     *p; 
+    /**
+     * (protected) Pointer fields available for use by the text provider.
+     * Not used by UText common code.
+     * @stable ICU 3.6
+     */
+    const void     *q;
+     /**
+     * (protected) Pointer fields available for use by the text provider.
+     * Not used by UText common code.
+     * @stable ICU 3.6
+      */
+    const void     *r;
+
+    /**
+      *  Private field reserved for future use by the UText framework
+      *     itself.  This is not to be touched by the text providers.
+      * @internal ICU 3.4
+      */
+    void           *privP;
+
+
+    /* --- 16 byte alignment boundary--- */
+    
+
+    /**
+      * (protected) Integer field reserved for use by the text provider.
+      * Not used by the UText framework, or by the client (user) of the UText.
+      * @stable ICU 3.4
+      */
+    int64_t         a;
+
+    /**
+      * (protected) Integer field reserved for use by the text provider.
+      * Not used by the UText framework, or by the client (user) of the UText.
+      * @stable ICU 3.4
+      */
+    int32_t         b;
+
+    /**
+      * (protected) Integer field reserved for use by the text provider.
+      * Not used by the UText framework, or by the client (user) of the UText.
+      * @stable ICU 3.4
+      */
+    int32_t         c;
+
+    /*  ---- 16 byte alignment boundary---- */
+
+
+    /**
+      *  Private field reserved for future use by the UText framework
+      *     itself.  This is not to be touched by the text providers.
+      * @internal ICU 3.4
+      */
+    int64_t         privA;
+    /**
+      *  Private field reserved for future use by the UText framework
+      *     itself.  This is not to be touched by the text providers.
+      * @internal ICU 3.4
+      */
+    int32_t         privB;
+    /**
+      *  Private field reserved for future use by the UText framework
+      *     itself.  This is not to be touched by the text providers.
+      * @internal ICU 3.4
+      */
+    int32_t         privC;
+};
+
+
+/**
+ *  Common function for use by Text Provider implementations to allocate and/or initialize
+ *  a new UText struct.  To be called in the implementation of utext_open() functions.
+ *  If the supplied UText parameter is null, a new UText struct will be allocated on the heap.
+ *  If the supplied UText is already open, the provider's close function will be called
+ *  so that the struct can be reused by the open that is in progress.
+ *
+ * @param ut   pointer to a UText struct to be re-used, or null if a new UText
+ *             should be allocated.
+ * @param extraSpace The amount of additional space to be allocated as part
+ *             of this UText, for use by types of providers that require
+ *             additional storage.
+ * @param status Errors are returned here.
+ * @return pointer to the UText, allocated if necessary, with extra space set up if requested.
+ * @stable ICU 3.4
+ */
+U_STABLE UText * U_EXPORT2
+utext_setup(UText *ut, int32_t extraSpace, UErrorCode *status);
+
+/**
+  * @internal
+  *  Value used to help identify correctly initialized UText structs.
+  *  Note:  must be publicly visible so that UTEXT_INITIALIZER can access it.
+  */
+enum {
+    UTEXT_MAGIC = 0x345ad82c
+};
+
+/**
+ * initializer to be used with local (stack) instances of a UText
+ *  struct.  UText structs must be initialized before passing
+ *  them to one of the utext_open functions.
+ *
+ * @stable ICU 3.6
+ */
+#define UTEXT_INITIALIZER {                                        \
+                  UTEXT_MAGIC,          /* magic                */ \
+                  0,                    /* flags                */ \
+                  0,                    /* providerProps        */ \
+                  sizeof(UText),        /* sizeOfStruct         */ \
+                  0,                    /* chunkNativeLimit     */ \
+                  0,                    /* extraSize            */ \
+                  0,                    /* nativeIndexingLimit  */ \
+                  0,                    /* chunkNativeStart     */ \
+                  0,                    /* chunkOffset          */ \
+                  0,                    /* chunkLength          */ \
+                  NULL,                 /* chunkContents        */ \
+                  NULL,                 /* pFuncs               */ \
+                  NULL,                 /* pExtra               */ \
+                  NULL,                 /* context              */ \
+                  NULL, NULL, NULL,     /* p, q, r              */ \
+                  NULL,                 /* privP                */ \
+                  0, 0, 0,              /* a, b, c              */ \
+                  0, 0, 0               /* privA,B,C,           */ \
+                  }
+
+
+U_CDECL_END
+
+
+
+#endif
diff --git a/source/common/unicode/utf.h b/source/common/unicode/utf.h
new file mode 100644
index 0000000..f794799
--- /dev/null
+++ b/source/common/unicode/utf.h
@@ -0,0 +1,236 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  utf.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999sep09
+*   created by: Markus W. Scherer
+*/
+
+/**
+ * \file
+ * \brief C API: Code point macros
+ *
+ * This file defines macros for checking whether a code point is
+ * a surrogate or a non-character etc.
+ *
+ * The UChar and UChar32 data types for Unicode code units and code points
+ * are defined in umachines.h because they can be machine-dependent.
+ *
+ * utf.h is included by utypes.h and itself includes utf8.h and utf16.h after some
+ * common definitions. Those files define macros for efficiently getting code points
+ * in and out of UTF-8/16 strings.
+ * utf16.h macros have "U16_" prefixes.
+ * utf8.h defines similar macros with "U8_" prefixes for UTF-8 string handling.
+ *
+ * ICU processes 16-bit Unicode strings.
+ * Most of the time, such strings are well-formed UTF-16.
+ * Single, unpaired surrogates must be handled as well, and are treated in ICU
+ * like regular code points where possible.
+ * (Pairs of surrogate code points are indistinguishable from supplementary
+ * code points encoded as pairs of supplementary code units.)
+ *
+ * In fact, almost all Unicode code points in normal text (>99%)
+ * are on the BMP (<=U+ffff) and even <=U+d7ff.
+ * ICU functions handle supplementary code points (U+10000..U+10ffff)
+ * but are optimized for the much more frequently occurring BMP code points.
+ *
+ * utf.h defines UChar to be an unsigned 16-bit integer. If this matches wchar_t, then
+ * UChar is defined to be exactly wchar_t, otherwise uint16_t.
+ *
+ * UChar32 is defined to be a signed 32-bit integer (int32_t), large enough for a 21-bit
+ * Unicode code point (Unicode scalar value, 0..0x10ffff).
+ * Before ICU 2.4, the definition of UChar32 was similarly platform-dependent as
+ * the definition of UChar. For details see the documentation for UChar32 itself.
+ *
+ * utf.h also defines a small number of C macros for single Unicode code points.
+ * These are simple checks for surrogates and non-characters.
+ * For actual Unicode character properties see uchar.h.
+ *
+ * By default, string operations must be done with error checking in case
+ * a string is not well-formed UTF-16.
+ * The macros will detect if a surrogate code unit is unpaired
+ * (lead unit without trail unit or vice versa) and just return the unit itself
+ * as the code point.
+ * (It is an accidental property of Unicode and UTF-16 that all
+ * malformed sequences can be expressed unambiguously with a distinct subrange
+ * of Unicode code points.)
+ *
+ * The regular "safe" macros require that the initial, passed-in string index
+ * is within bounds. They only check the index when they read more than one
+ * code unit. This is usually done with code similar to the following loop:
+ * <pre>while(i<length) {
+ *   U16_NEXT(s, i, length, c);
+ *   // use c
+ * }</pre>
+ *
+ * When it is safe to assume that text is well-formed UTF-16
+ * (does not contain single, unpaired surrogates), then one can use
+ * U16_..._UNSAFE macros.
+ * These do not check for proper code unit sequences or truncated text and may
+ * yield wrong results or even cause a crash if they are used with "malformed"
+ * text.
+ * In practice, U16_..._UNSAFE macros will produce slightly less code but
+ * should not be faster because the processing is only different when a
+ * surrogate code unit is detected, which will be rare.
+ *
+ * Similarly for UTF-8, there are "safe" macros without a suffix,
+ * and U8_..._UNSAFE versions.
+ * The performance differences are much larger here because UTF-8 provides so
+ * many opportunities for malformed sequences.
+ * The unsafe UTF-8 macros are entirely implemented inside the macro definitions
+ * and are fast, while the safe UTF-8 macros call functions for all but the
+ * trivial (ASCII) cases.
+ * (ICU 3.6 optimizes U8_NEXT() and U8_APPEND() to handle most other common
+ * characters inline as well.)
+ *
+ * Unlike with UTF-16, malformed sequences cannot be expressed with distinct
+ * code point values (0..U+10ffff). They are indicated with negative values instead.
+ *
+ * For more information see the ICU User Guide Strings chapter
+ * (http://icu-project.org/userguide/strings.html).
+ *
+ * <em>Usage:</em>
+ * ICU coding guidelines for if() statements should be followed when using these macros.
+ * Compound statements (curly braces {}) must be used  for if-else-while... 
+ * bodies and all macro statements should be terminated with semicolon.
+ *
+ * @stable ICU 2.4
+ */
+
+#ifndef __UTF_H__
+#define __UTF_H__
+
+#include "unicode/utypes.h"
+/* include the utfXX.h after the following definitions */
+
+/* single-code point definitions -------------------------------------------- */
+
+/**
+ * This value is intended for sentinel values for APIs that
+ * (take or) return single code points (UChar32).
+ * It is outside of the Unicode code point range 0..0x10ffff.
+ * 
+ * For example, a "done" or "error" value in a new API
+ * could be indicated with U_SENTINEL.
+ *
+ * ICU APIs designed before ICU 2.4 usually define service-specific "done"
+ * values, mostly 0xffff.
+ * Those may need to be distinguished from
+ * actual U+ffff text contents by calling functions like
+ * CharacterIterator::hasNext() or UnicodeString::length().
+ *
+ * @return -1
+ * @see UChar32
+ * @stable ICU 2.4
+ */
+#define U_SENTINEL (-1)
+
+/**
+ * Is this code point a Unicode noncharacter?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define U_IS_UNICODE_NONCHAR(c) \
+    ((c)>=0xfdd0 && \
+     ((uint32_t)(c)<=0xfdef || ((c)&0xfffe)==0xfffe) && \
+     (uint32_t)(c)<=0x10ffff)
+
+/**
+ * Is c a Unicode code point value (0..U+10ffff)
+ * that can be assigned a character?
+ *
+ * Code points that are not characters include:
+ * - single surrogate code points (U+d800..U+dfff, 2048 code points)
+ * - the last two code points on each plane (U+__fffe and U+__ffff, 34 code points)
+ * - U+fdd0..U+fdef (new with Unicode 3.1, 32 code points)
+ * - the highest Unicode code point value is U+10ffff
+ *
+ * This means that all code points below U+d800 are character code points,
+ * and that boundary is tested first for performance.
+ *
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define U_IS_UNICODE_CHAR(c) \
+    ((uint32_t)(c)<0xd800 || \
+        ((uint32_t)(c)>0xdfff && \
+         (uint32_t)(c)<=0x10ffff && \
+         !U_IS_UNICODE_NONCHAR(c)))
+
+/**
+ * Is this code point a BMP code point (U+0000..U+ffff)?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.8
+ */
+#define U_IS_BMP(c) ((uint32_t)(c)<=0xffff)
+
+/**
+ * Is this code point a supplementary code point (U+10000..U+10ffff)?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.8
+ */
+#define U_IS_SUPPLEMENTARY(c) ((uint32_t)((c)-0x10000)<=0xfffff)
+ 
+/**
+ * Is this code point a lead surrogate (U+d800..U+dbff)?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define U_IS_LEAD(c) (((c)&0xfffffc00)==0xd800)
+
+/**
+ * Is this code point a trail surrogate (U+dc00..U+dfff)?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define U_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00)
+
+/**
+ * Is this code point a surrogate (U+d800..U+dfff)?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define U_IS_SURROGATE(c) (((c)&0xfffff800)==0xd800)
+
+/**
+ * Assuming c is a surrogate code point (U_IS_SURROGATE(c)),
+ * is it a lead surrogate?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define U_IS_SURROGATE_LEAD(c) (((c)&0x400)==0)
+
+/**
+ * Assuming c is a surrogate code point (U_IS_SURROGATE(c)),
+ * is it a trail surrogate?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 4.2
+ */
+#define U_IS_SURROGATE_TRAIL(c) (((c)&0x400)!=0)
+
+/* include the utfXX.h ------------------------------------------------------ */
+
+#include "unicode/utf8.h"
+#include "unicode/utf16.h"
+
+/* utf_old.h contains deprecated, pre-ICU 2.4 definitions */
+#include "unicode/utf_old.h"
+
+#endif
diff --git a/source/common/unicode/utf16.h b/source/common/unicode/utf16.h
new file mode 100644
index 0000000..5079c11
--- /dev/null
+++ b/source/common/unicode/utf16.h
@@ -0,0 +1,614 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  utf16.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999sep09
+*   created by: Markus W. Scherer
+*/
+
+/**
+ * \file
+ * \brief C API: 16-bit Unicode handling macros
+ * 
+ * This file defines macros to deal with 16-bit Unicode (UTF-16) code units and strings.
+ * utf16.h is included by utf.h after unicode/umachine.h
+ * and some common definitions.
+ *
+ * For more information see utf.h and the ICU User Guide Strings chapter
+ * (http://icu-project.org/userguide/strings.html).
+ *
+ * <em>Usage:</em>
+ * ICU coding guidelines for if() statements should be followed when using these macros.
+ * Compound statements (curly braces {}) must be used  for if-else-while... 
+ * bodies and all macro statements should be terminated with semicolon.
+ */
+
+#ifndef __UTF16_H__
+#define __UTF16_H__
+
+/* utf.h must be included first. */
+#ifndef __UTF_H__
+#   include "unicode/utf.h"
+#endif
+
+/* single-code point definitions -------------------------------------------- */
+
+/**
+ * Does this code unit alone encode a code point (BMP, not a surrogate)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define U16_IS_SINGLE(c) !U_IS_SURROGATE(c)
+
+/**
+ * Is this code unit a lead surrogate (U+d800..U+dbff)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define U16_IS_LEAD(c) (((c)&0xfffffc00)==0xd800)
+
+/**
+ * Is this code unit a trail surrogate (U+dc00..U+dfff)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define U16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00)
+
+/**
+ * Is this code unit a surrogate (U+d800..U+dfff)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define U16_IS_SURROGATE(c) U_IS_SURROGATE(c)
+
+/**
+ * Assuming c is a surrogate code point (U16_IS_SURROGATE(c)),
+ * is it a lead surrogate?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define U16_IS_SURROGATE_LEAD(c) (((c)&0x400)==0)
+
+/**
+ * Assuming c is a surrogate code point (U16_IS_SURROGATE(c)),
+ * is it a trail surrogate?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 4.2
+ */
+#define U16_IS_SURROGATE_TRAIL(c) (((c)&0x400)!=0)
+
+/**
+ * Helper constant for U16_GET_SUPPLEMENTARY.
+ * @internal
+ */
+#define U16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000)
+
+/**
+ * Get a supplementary code point value (U+10000..U+10ffff)
+ * from its lead and trail surrogates.
+ * The result is undefined if the input values are not
+ * lead and trail surrogates.
+ *
+ * @param lead lead surrogate (U+d800..U+dbff)
+ * @param trail trail surrogate (U+dc00..U+dfff)
+ * @return supplementary code point (U+10000..U+10ffff)
+ * @stable ICU 2.4
+ */
+#define U16_GET_SUPPLEMENTARY(lead, trail) \
+    (((UChar32)(lead)<<10UL)+(UChar32)(trail)-U16_SURROGATE_OFFSET)
+
+
+/**
+ * Get the lead surrogate (0xd800..0xdbff) for a
+ * supplementary code point (0x10000..0x10ffff).
+ * @param supplementary 32-bit code point (U+10000..U+10ffff)
+ * @return lead surrogate (U+d800..U+dbff) for supplementary
+ * @stable ICU 2.4
+ */
+#define U16_LEAD(supplementary) (UChar)(((supplementary)>>10)+0xd7c0)
+
+/**
+ * Get the trail surrogate (0xdc00..0xdfff) for a
+ * supplementary code point (0x10000..0x10ffff).
+ * @param supplementary 32-bit code point (U+10000..U+10ffff)
+ * @return trail surrogate (U+dc00..U+dfff) for supplementary
+ * @stable ICU 2.4
+ */
+#define U16_TRAIL(supplementary) (UChar)(((supplementary)&0x3ff)|0xdc00)
+
+/**
+ * How many 16-bit code units are used to encode this Unicode code point? (1 or 2)
+ * The result is not defined if c is not a Unicode code point (U+0000..U+10ffff).
+ * @param c 32-bit code point
+ * @return 1 or 2
+ * @stable ICU 2.4
+ */
+#define U16_LENGTH(c) ((uint32_t)(c)<=0xffff ? 1 : 2)
+
+/**
+ * The maximum number of 16-bit code units per Unicode code point (U+0000..U+10ffff).
+ * @return 2
+ * @stable ICU 2.4
+ */
+#define U16_MAX_LENGTH 2
+
+/**
+ * Get a code point from a string at a random-access offset,
+ * without changing the offset.
+ * "Unsafe" macro, assumes well-formed UTF-16.
+ *
+ * The offset may point to either the lead or trail surrogate unit
+ * for a supplementary code point, in which case the macro will read
+ * the adjacent matching surrogate as well.
+ * The result is undefined if the offset points to a single, unpaired surrogate.
+ * Iteration through a string is more efficient with U16_NEXT_UNSAFE or U16_NEXT.
+ *
+ * @param s const UChar * string
+ * @param i string offset
+ * @param c output UChar32 variable
+ * @see U16_GET
+ * @stable ICU 2.4
+ */
+#define U16_GET_UNSAFE(s, i, c) { \
+    (c)=(s)[i]; \
+    if(U16_IS_SURROGATE(c)) { \
+        if(U16_IS_SURROGATE_LEAD(c)) { \
+            (c)=U16_GET_SUPPLEMENTARY((c), (s)[(i)+1]); \
+        } else { \
+            (c)=U16_GET_SUPPLEMENTARY((s)[(i)-1], (c)); \
+        } \
+    } \
+}
+
+/**
+ * Get a code point from a string at a random-access offset,
+ * without changing the offset.
+ * "Safe" macro, handles unpaired surrogates and checks for string boundaries.
+ *
+ * The offset may point to either the lead or trail surrogate unit
+ * for a supplementary code point, in which case the macro will read
+ * the adjacent matching surrogate as well.
+ * If the offset points to a single, unpaired surrogate, then that itself
+ * will be returned as the code point.
+ * Iteration through a string is more efficient with U16_NEXT_UNSAFE or U16_NEXT.
+ *
+ * @param s const UChar * string
+ * @param start starting string offset (usually 0)
+ * @param i string offset, must be start<=i<length
+ * @param length string length
+ * @param c output UChar32 variable
+ * @see U16_GET_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U16_GET(s, start, i, length, c) { \
+    (c)=(s)[i]; \
+    if(U16_IS_SURROGATE(c)) { \
+        uint16_t __c2; \
+        if(U16_IS_SURROGATE_LEAD(c)) { \
+            if((i)+1<(length) && U16_IS_TRAIL(__c2=(s)[(i)+1])) { \
+                (c)=U16_GET_SUPPLEMENTARY((c), __c2); \
+            } \
+        } else { \
+            if((i)>(start) && U16_IS_LEAD(__c2=(s)[(i)-1])) { \
+                (c)=U16_GET_SUPPLEMENTARY(__c2, (c)); \
+            } \
+        } \
+    } \
+}
+
+/* definitions with forward iteration --------------------------------------- */
+
+/**
+ * Get a code point from a string at a code point boundary offset,
+ * and advance the offset to the next code point boundary.
+ * (Post-incrementing forward iteration.)
+ * "Unsafe" macro, assumes well-formed UTF-16.
+ *
+ * The offset may point to the lead surrogate unit
+ * for a supplementary code point, in which case the macro will read
+ * the following trail surrogate as well.
+ * If the offset points to a trail surrogate, then that itself
+ * will be returned as the code point.
+ * The result is undefined if the offset points to a single, unpaired lead surrogate.
+ *
+ * @param s const UChar * string
+ * @param i string offset
+ * @param c output UChar32 variable
+ * @see U16_NEXT
+ * @stable ICU 2.4
+ */
+#define U16_NEXT_UNSAFE(s, i, c) { \
+    (c)=(s)[(i)++]; \
+    if(U16_IS_LEAD(c)) { \
+        (c)=U16_GET_SUPPLEMENTARY((c), (s)[(i)++]); \
+    } \
+}
+
+/**
+ * Get a code point from a string at a code point boundary offset,
+ * and advance the offset to the next code point boundary.
+ * (Post-incrementing forward iteration.)
+ * "Safe" macro, handles unpaired surrogates and checks for string boundaries.
+ *
+ * The offset may point to the lead surrogate unit
+ * for a supplementary code point, in which case the macro will read
+ * the following trail surrogate as well.
+ * If the offset points to a trail surrogate or
+ * to a single, unpaired lead surrogate, then that itself
+ * will be returned as the code point.
+ *
+ * @param s const UChar * string
+ * @param i string offset, must be i<length
+ * @param length string length
+ * @param c output UChar32 variable
+ * @see U16_NEXT_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U16_NEXT(s, i, length, c) { \
+    (c)=(s)[(i)++]; \
+    if(U16_IS_LEAD(c)) { \
+        uint16_t __c2; \
+        if((i)<(length) && U16_IS_TRAIL(__c2=(s)[(i)])) { \
+            ++(i); \
+            (c)=U16_GET_SUPPLEMENTARY((c), __c2); \
+        } \
+    } \
+}
+
+/**
+ * Append a code point to a string, overwriting 1 or 2 code units.
+ * The offset points to the current end of the string contents
+ * and is advanced (post-increment).
+ * "Unsafe" macro, assumes a valid code point and sufficient space in the string.
+ * Otherwise, the result is undefined.
+ *
+ * @param s const UChar * string buffer
+ * @param i string offset
+ * @param c code point to append
+ * @see U16_APPEND
+ * @stable ICU 2.4
+ */
+#define U16_APPEND_UNSAFE(s, i, c) { \
+    if((uint32_t)(c)<=0xffff) { \
+        (s)[(i)++]=(uint16_t)(c); \
+    } else { \
+        (s)[(i)++]=(uint16_t)(((c)>>10)+0xd7c0); \
+        (s)[(i)++]=(uint16_t)(((c)&0x3ff)|0xdc00); \
+    } \
+}
+
+/**
+ * Append a code point to a string, overwriting 1 or 2 code units.
+ * The offset points to the current end of the string contents
+ * and is advanced (post-increment).
+ * "Safe" macro, checks for a valid code point.
+ * If a surrogate pair is written, checks for sufficient space in the string.
+ * If the code point is not valid or a trail surrogate does not fit,
+ * then isError is set to TRUE.
+ *
+ * @param s const UChar * string buffer
+ * @param i string offset, must be i<capacity
+ * @param capacity size of the string buffer
+ * @param c code point to append
+ * @param isError output UBool set to TRUE if an error occurs, otherwise not modified
+ * @see U16_APPEND_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U16_APPEND(s, i, capacity, c, isError) { \
+    if((uint32_t)(c)<=0xffff) { \
+        (s)[(i)++]=(uint16_t)(c); \
+    } else if((uint32_t)(c)<=0x10ffff && (i)+1<(capacity)) { \
+        (s)[(i)++]=(uint16_t)(((c)>>10)+0xd7c0); \
+        (s)[(i)++]=(uint16_t)(((c)&0x3ff)|0xdc00); \
+    } else /* c>0x10ffff or not enough space */ { \
+        (isError)=TRUE; \
+    } \
+}
+
+/**
+ * Advance the string offset from one code point boundary to the next.
+ * (Post-incrementing iteration.)
+ * "Unsafe" macro, assumes well-formed UTF-16.
+ *
+ * @param s const UChar * string
+ * @param i string offset
+ * @see U16_FWD_1
+ * @stable ICU 2.4
+ */
+#define U16_FWD_1_UNSAFE(s, i) { \
+    if(U16_IS_LEAD((s)[(i)++])) { \
+        ++(i); \
+    } \
+}
+
+/**
+ * Advance the string offset from one code point boundary to the next.
+ * (Post-incrementing iteration.)
+ * "Safe" macro, handles unpaired surrogates and checks for string boundaries.
+ *
+ * @param s const UChar * string
+ * @param i string offset, must be i<length
+ * @param length string length
+ * @see U16_FWD_1_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U16_FWD_1(s, i, length) { \
+    if(U16_IS_LEAD((s)[(i)++]) && (i)<(length) && U16_IS_TRAIL((s)[i])) { \
+        ++(i); \
+    } \
+}
+
+/**
+ * Advance the string offset from one code point boundary to the n-th next one,
+ * i.e., move forward by n code points.
+ * (Post-incrementing iteration.)
+ * "Unsafe" macro, assumes well-formed UTF-16.
+ *
+ * @param s const UChar * string
+ * @param i string offset
+ * @param n number of code points to skip
+ * @see U16_FWD_N
+ * @stable ICU 2.4
+ */
+#define U16_FWD_N_UNSAFE(s, i, n) { \
+    int32_t __N=(n); \
+    while(__N>0) { \
+        U16_FWD_1_UNSAFE(s, i); \
+        --__N; \
+    } \
+}
+
+/**
+ * Advance the string offset from one code point boundary to the n-th next one,
+ * i.e., move forward by n code points.
+ * (Post-incrementing iteration.)
+ * "Safe" macro, handles unpaired surrogates and checks for string boundaries.
+ *
+ * @param s const UChar * string
+ * @param i string offset, must be i<length
+ * @param length string length
+ * @param n number of code points to skip
+ * @see U16_FWD_N_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U16_FWD_N(s, i, length, n) { \
+    int32_t __N=(n); \
+    while(__N>0 && (i)<(length)) { \
+        U16_FWD_1(s, i, length); \
+        --__N; \
+    } \
+}
+
+/**
+ * Adjust a random-access offset to a code point boundary
+ * at the start of a code point.
+ * If the offset points to the trail surrogate of a surrogate pair,
+ * then the offset is decremented.
+ * Otherwise, it is not modified.
+ * "Unsafe" macro, assumes well-formed UTF-16.
+ *
+ * @param s const UChar * string
+ * @param i string offset
+ * @see U16_SET_CP_START
+ * @stable ICU 2.4
+ */
+#define U16_SET_CP_START_UNSAFE(s, i) { \
+    if(U16_IS_TRAIL((s)[i])) { \
+        --(i); \
+    } \
+}
+
+/**
+ * Adjust a random-access offset to a code point boundary
+ * at the start of a code point.
+ * If the offset points to the trail surrogate of a surrogate pair,
+ * then the offset is decremented.
+ * Otherwise, it is not modified.
+ * "Safe" macro, handles unpaired surrogates and checks for string boundaries.
+ *
+ * @param s const UChar * string
+ * @param start starting string offset (usually 0)
+ * @param i string offset, must be start<=i
+ * @see U16_SET_CP_START_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U16_SET_CP_START(s, start, i) { \
+    if(U16_IS_TRAIL((s)[i]) && (i)>(start) && U16_IS_LEAD((s)[(i)-1])) { \
+        --(i); \
+    } \
+}
+
+/* definitions with backward iteration -------------------------------------- */
+
+/**
+ * Move the string offset from one code point boundary to the previous one
+ * and get the code point between them.
+ * (Pre-decrementing backward iteration.)
+ * "Unsafe" macro, assumes well-formed UTF-16.
+ *
+ * The input offset may be the same as the string length.
+ * If the offset is behind a trail surrogate unit
+ * for a supplementary code point, then the macro will read
+ * the preceding lead surrogate as well.
+ * If the offset is behind a lead surrogate, then that itself
+ * will be returned as the code point.
+ * The result is undefined if the offset is behind a single, unpaired trail surrogate.
+ *
+ * @param s const UChar * string
+ * @param i string offset
+ * @param c output UChar32 variable
+ * @see U16_PREV
+ * @stable ICU 2.4
+ */
+#define U16_PREV_UNSAFE(s, i, c) { \
+    (c)=(s)[--(i)]; \
+    if(U16_IS_TRAIL(c)) { \
+        (c)=U16_GET_SUPPLEMENTARY((s)[--(i)], (c)); \
+    } \
+}
+
+/**
+ * Move the string offset from one code point boundary to the previous one
+ * and get the code point between them.
+ * (Pre-decrementing backward iteration.)
+ * "Safe" macro, handles unpaired surrogates and checks for string boundaries.
+ *
+ * The input offset may be the same as the string length.
+ * If the offset is behind a trail surrogate unit
+ * for a supplementary code point, then the macro will read
+ * the preceding lead surrogate as well.
+ * If the offset is behind a lead surrogate or behind a single, unpaired
+ * trail surrogate, then that itself
+ * will be returned as the code point.
+ *
+ * @param s const UChar * string
+ * @param start starting string offset (usually 0)
+ * @param i string offset, must be start<i
+ * @param c output UChar32 variable
+ * @see U16_PREV_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U16_PREV(s, start, i, c) { \
+    (c)=(s)[--(i)]; \
+    if(U16_IS_TRAIL(c)) { \
+        uint16_t __c2; \
+        if((i)>(start) && U16_IS_LEAD(__c2=(s)[(i)-1])) { \
+            --(i); \
+            (c)=U16_GET_SUPPLEMENTARY(__c2, (c)); \
+        } \
+    } \
+}
+
+/**
+ * Move the string offset from one code point boundary to the previous one.
+ * (Pre-decrementing backward iteration.)
+ * The input offset may be the same as the string length.
+ * "Unsafe" macro, assumes well-formed UTF-16.
+ *
+ * @param s const UChar * string
+ * @param i string offset
+ * @see U16_BACK_1
+ * @stable ICU 2.4
+ */
+#define U16_BACK_1_UNSAFE(s, i) { \
+    if(U16_IS_TRAIL((s)[--(i)])) { \
+        --(i); \
+    } \
+}
+
+/**
+ * Move the string offset from one code point boundary to the previous one.
+ * (Pre-decrementing backward iteration.)
+ * The input offset may be the same as the string length.
+ * "Safe" macro, handles unpaired surrogates and checks for string boundaries.
+ *
+ * @param s const UChar * string
+ * @param start starting string offset (usually 0)
+ * @param i string offset, must be start<i
+ * @see U16_BACK_1_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U16_BACK_1(s, start, i) { \
+    if(U16_IS_TRAIL((s)[--(i)]) && (i)>(start) && U16_IS_LEAD((s)[(i)-1])) { \
+        --(i); \
+    } \
+}
+
+/**
+ * Move the string offset from one code point boundary to the n-th one before it,
+ * i.e., move backward by n code points.
+ * (Pre-decrementing backward iteration.)
+ * The input offset may be the same as the string length.
+ * "Unsafe" macro, assumes well-formed UTF-16.
+ *
+ * @param s const UChar * string
+ * @param i string offset
+ * @param n number of code points to skip
+ * @see U16_BACK_N
+ * @stable ICU 2.4
+ */
+#define U16_BACK_N_UNSAFE(s, i, n) { \
+    int32_t __N=(n); \
+    while(__N>0) { \
+        U16_BACK_1_UNSAFE(s, i); \
+        --__N; \
+    } \
+}
+
+/**
+ * Move the string offset from one code point boundary to the n-th one before it,
+ * i.e., move backward by n code points.
+ * (Pre-decrementing backward iteration.)
+ * The input offset may be the same as the string length.
+ * "Safe" macro, handles unpaired surrogates and checks for string boundaries.
+ *
+ * @param s const UChar * string
+ * @param start start of string
+ * @param i string offset, must be start<i
+ * @param n number of code points to skip
+ * @see U16_BACK_N_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U16_BACK_N(s, start, i, n) { \
+    int32_t __N=(n); \
+    while(__N>0 && (i)>(start)) { \
+        U16_BACK_1(s, start, i); \
+        --__N; \
+    } \
+}
+
+/**
+ * Adjust a random-access offset to a code point boundary after a code point.
+ * If the offset is behind the lead surrogate of a surrogate pair,
+ * then the offset is incremented.
+ * Otherwise, it is not modified.
+ * The input offset may be the same as the string length.
+ * "Unsafe" macro, assumes well-formed UTF-16.
+ *
+ * @param s const UChar * string
+ * @param i string offset
+ * @see U16_SET_CP_LIMIT
+ * @stable ICU 2.4
+ */
+#define U16_SET_CP_LIMIT_UNSAFE(s, i) { \
+    if(U16_IS_LEAD((s)[(i)-1])) { \
+        ++(i); \
+    } \
+}
+
+/**
+ * Adjust a random-access offset to a code point boundary after a code point.
+ * If the offset is behind the lead surrogate of a surrogate pair,
+ * then the offset is incremented.
+ * Otherwise, it is not modified.
+ * The input offset may be the same as the string length.
+ * "Safe" macro, handles unpaired surrogates and checks for string boundaries.
+ *
+ * @param s const UChar * string
+ * @param start starting string offset (usually 0)
+ * @param i string offset, start<=i<=length
+ * @param length string length
+ * @see U16_SET_CP_LIMIT_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U16_SET_CP_LIMIT(s, start, i, length) { \
+    if((start)<(i) && (i)<(length) && U16_IS_LEAD((s)[(i)-1]) && U16_IS_TRAIL((s)[i])) { \
+        ++(i); \
+    } \
+}
+
+#endif
diff --git a/source/common/unicode/utf32.h b/source/common/unicode/utf32.h
new file mode 100644
index 0000000..bf63e69
--- /dev/null
+++ b/source/common/unicode/utf32.h
@@ -0,0 +1,23 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1999-2001, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  utf32.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999sep20
+*   created by: Markus W. Scherer
+*/
+/**
+ * \file
+ * \brief C API: UTF-32 macros
+ *
+ * This file is obsolete and its contents moved to utf_old.h.
+ * See utf_old.h and Jitterbug 2150 and its discussion on the ICU mailing list
+ * in September 2002.
+ */
diff --git a/source/common/unicode/utf8.h b/source/common/unicode/utf8.h
new file mode 100644
index 0000000..6405795
--- /dev/null
+++ b/source/common/unicode/utf8.h
@@ -0,0 +1,683 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1999-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  utf8.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999sep13
+*   created by: Markus W. Scherer
+*/
+
+/**
+ * \file
+ * \brief C API: 8-bit Unicode handling macros
+ * 
+ * This file defines macros to deal with 8-bit Unicode (UTF-8) code units (bytes) and strings.
+ * utf8.h is included by utf.h after unicode/umachine.h
+ * and some common definitions.
+ *
+ * For more information see utf.h and the ICU User Guide Strings chapter
+ * (http://icu-project.org/userguide/strings.html).
+ *
+ * <em>Usage:</em>
+ * ICU coding guidelines for if() statements should be followed when using these macros.
+ * Compound statements (curly braces {}) must be used  for if-else-while... 
+ * bodies and all macro statements should be terminated with semicolon.
+ */
+
+#ifndef __UTF8_H__
+#define __UTF8_H__
+
+/* utf.h must be included first. */
+#ifndef __UTF_H__
+#   include "unicode/utf.h"
+#endif
+
+/* internal definitions ----------------------------------------------------- */
+
+/**
+ * \var utf8_countTrailBytes
+ * Internal array with numbers of trail bytes for any given byte used in
+ * lead byte position.
+ *
+ * This is internal since it is not meant to be called directly by external clients;
+ * however it is called by public macros in this file and thus must remain stable,
+ * and should not be hidden when other internal functions are hidden (otherwise
+ * public macros would fail to compile).
+ * @internal
+ */
+#ifdef U_UTF8_IMPL
+U_EXPORT const uint8_t 
+#elif defined(U_STATIC_IMPLEMENTATION) || defined(U_COMMON_IMPLEMENTATION)
+U_CFUNC const uint8_t
+#else
+U_CFUNC U_IMPORT const uint8_t /* U_IMPORT2? */ /*U_IMPORT*/ 
+#endif
+utf8_countTrailBytes[256];
+
+/**
+ * Count the trail bytes for a UTF-8 lead byte.
+ *
+ * This is internal since it is not meant to be called directly by external clients;
+ * however it is called by public macros in this file and thus must remain stable.
+ * @internal
+ */
+#define U8_COUNT_TRAIL_BYTES(leadByte) (utf8_countTrailBytes[(uint8_t)leadByte])
+
+/**
+ * Mask a UTF-8 lead byte, leave only the lower bits that form part of the code point value.
+ *
+ * This is internal since it is not meant to be called directly by external clients;
+ * however it is called by public macros in this file and thus must remain stable.
+ * @internal
+ */
+#define U8_MASK_LEAD_BYTE(leadByte, countTrailBytes) ((leadByte)&=(1<<(6-(countTrailBytes)))-1)
+
+/**
+ * Function for handling "next code point" with error-checking.
+ *
+ * This is internal since it is not meant to be called directly by external clients;
+ * however it is U_STABLE (not U_INTERNAL) since it is called by public macros in this
+ * file and thus must remain stable, and should not be hidden when other internal
+ * functions are hidden (otherwise public macros would fail to compile).
+ * @internal
+ */
+U_STABLE UChar32 U_EXPORT2
+utf8_nextCharSafeBody(const uint8_t *s, int32_t *pi, int32_t length, UChar32 c, UBool strict);
+
+/**
+ * Function for handling "append code point" with error-checking.
+ *
+ * This is internal since it is not meant to be called directly by external clients;
+ * however it is U_STABLE (not U_INTERNAL) since it is called by public macros in this
+ * file and thus must remain stable, and should not be hidden when other internal
+ * functions are hidden (otherwise public macros would fail to compile).
+ * @internal
+ */
+U_STABLE int32_t U_EXPORT2
+utf8_appendCharSafeBody(uint8_t *s, int32_t i, int32_t length, UChar32 c, UBool *pIsError);
+
+/**
+ * Function for handling "previous code point" with error-checking.
+ *
+ * This is internal since it is not meant to be called directly by external clients;
+ * however it is U_STABLE (not U_INTERNAL) since it is called by public macros in this
+ * file and thus must remain stable, and should not be hidden when other internal
+ * functions are hidden (otherwise public macros would fail to compile).
+ * @internal
+ */
+U_STABLE UChar32 U_EXPORT2
+utf8_prevCharSafeBody(const uint8_t *s, int32_t start, int32_t *pi, UChar32 c, UBool strict);
+
+/**
+ * Function for handling "skip backward one code point" with error-checking.
+ *
+ * This is internal since it is not meant to be called directly by external clients;
+ * however it is U_STABLE (not U_INTERNAL) since it is called by public macros in this
+ * file and thus must remain stable, and should not be hidden when other internal
+ * functions are hidden (otherwise public macros would fail to compile).
+ * @internal
+ */
+U_STABLE int32_t U_EXPORT2
+utf8_back1SafeBody(const uint8_t *s, int32_t start, int32_t i);
+
+/* single-code point definitions -------------------------------------------- */
+
+/**
+ * Does this code unit (byte) encode a code point by itself (US-ASCII 0..0x7f)?
+ * @param c 8-bit code unit (byte)
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define U8_IS_SINGLE(c) (((c)&0x80)==0)
+
+/**
+ * Is this code unit (byte) a UTF-8 lead byte?
+ * @param c 8-bit code unit (byte)
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define U8_IS_LEAD(c) ((uint8_t)((c)-0xc0)<0x3e)
+
+/**
+ * Is this code unit (byte) a UTF-8 trail byte?
+ * @param c 8-bit code unit (byte)
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define U8_IS_TRAIL(c) (((c)&0xc0)==0x80)
+
+/**
+ * How many code units (bytes) are used for the UTF-8 encoding
+ * of this Unicode code point?
+ * @param c 32-bit code point
+ * @return 1..4, or 0 if c is a surrogate or not a Unicode code point
+ * @stable ICU 2.4
+ */
+#define U8_LENGTH(c) \
+    ((uint32_t)(c)<=0x7f ? 1 : \
+        ((uint32_t)(c)<=0x7ff ? 2 : \
+            ((uint32_t)(c)<=0xd7ff ? 3 : \
+                ((uint32_t)(c)<=0xdfff || (uint32_t)(c)>0x10ffff ? 0 : \
+                    ((uint32_t)(c)<=0xffff ? 3 : 4)\
+                ) \
+            ) \
+        ) \
+    )
+
+/**
+ * The maximum number of UTF-8 code units (bytes) per Unicode code point (U+0000..U+10ffff).
+ * @return 4
+ * @stable ICU 2.4
+ */
+#define U8_MAX_LENGTH 4
+
+/**
+ * Get a code point from a string at a random-access offset,
+ * without changing the offset.
+ * The offset may point to either the lead byte or one of the trail bytes
+ * for a code point, in which case the macro will read all of the bytes
+ * for the code point.
+ * The result is undefined if the offset points to an illegal UTF-8
+ * byte sequence.
+ * Iteration through a string is more efficient with U8_NEXT_UNSAFE or U8_NEXT.
+ *
+ * @param s const uint8_t * string
+ * @param i string offset
+ * @param c output UChar32 variable
+ * @see U8_GET
+ * @stable ICU 2.4
+ */
+#define U8_GET_UNSAFE(s, i, c) { \
+    int32_t _u8_get_unsafe_index=(int32_t)(i); \
+    U8_SET_CP_START_UNSAFE(s, _u8_get_unsafe_index); \
+    U8_NEXT_UNSAFE(s, _u8_get_unsafe_index, c); \
+}
+
+/**
+ * Get a code point from a string at a random-access offset,
+ * without changing the offset.
+ * The offset may point to either the lead byte or one of the trail bytes
+ * for a code point, in which case the macro will read all of the bytes
+ * for the code point.
+ * If the offset points to an illegal UTF-8 byte sequence, then
+ * c is set to a negative value.
+ * Iteration through a string is more efficient with U8_NEXT_UNSAFE or U8_NEXT.
+ *
+ * @param s const uint8_t * string
+ * @param start starting string offset
+ * @param i string offset, must be start<=i<length
+ * @param length string length
+ * @param c output UChar32 variable, set to <0 in case of an error
+ * @see U8_GET_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U8_GET(s, start, i, length, c) { \
+    int32_t _u8_get_index=(int32_t)(i); \
+    U8_SET_CP_START(s, start, _u8_get_index); \
+    U8_NEXT(s, _u8_get_index, length, c); \
+}
+
+/* definitions with forward iteration --------------------------------------- */
+
+/**
+ * Get a code point from a string at a code point boundary offset,
+ * and advance the offset to the next code point boundary.
+ * (Post-incrementing forward iteration.)
+ * "Unsafe" macro, assumes well-formed UTF-8.
+ *
+ * The offset may point to the lead byte of a multi-byte sequence,
+ * in which case the macro will read the whole sequence.
+ * The result is undefined if the offset points to a trail byte
+ * or an illegal UTF-8 sequence.
+ *
+ * @param s const uint8_t * string
+ * @param i string offset
+ * @param c output UChar32 variable
+ * @see U8_NEXT
+ * @stable ICU 2.4
+ */
+#define U8_NEXT_UNSAFE(s, i, c) { \
+    (c)=(uint8_t)(s)[(i)++]; \
+    if((uint8_t)((c)-0xc0)<0x35) { \
+        uint8_t __count=U8_COUNT_TRAIL_BYTES(c); \
+        U8_MASK_LEAD_BYTE(c, __count); \
+        switch(__count) { \
+        /* each following branch falls through to the next one */ \
+        case 3: \
+            (c)=((c)<<6)|((s)[(i)++]&0x3f); \
+        case 2: \
+            (c)=((c)<<6)|((s)[(i)++]&0x3f); \
+        case 1: \
+            (c)=((c)<<6)|((s)[(i)++]&0x3f); \
+        /* no other branches to optimize switch() */ \
+            break; \
+        } \
+    } \
+}
+
+/**
+ * Get a code point from a string at a code point boundary offset,
+ * and advance the offset to the next code point boundary.
+ * (Post-incrementing forward iteration.)
+ * "Safe" macro, checks for illegal sequences and for string boundaries.
+ *
+ * The offset may point to the lead byte of a multi-byte sequence,
+ * in which case the macro will read the whole sequence.
+ * If the offset points to a trail byte or an illegal UTF-8 sequence, then
+ * c is set to a negative value.
+ *
+ * @param s const uint8_t * string
+ * @param i string offset, must be i<length
+ * @param length string length
+ * @param c output UChar32 variable, set to <0 in case of an error
+ * @see U8_NEXT_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U8_NEXT(s, i, length, c) { \
+    (c)=(uint8_t)(s)[(i)++]; \
+    if((c)>=0x80) { \
+        uint8_t __t1, __t2; \
+        if( /* handle U+1000..U+CFFF inline */ \
+            (0xe0<(c) && (c)<=0xec) && \
+            (((i)+1)<(length)) && \
+            (__t1=(uint8_t)((s)[i]-0x80))<=0x3f && \
+            (__t2=(uint8_t)((s)[(i)+1]-0x80))<= 0x3f \
+        ) { \
+            /* no need for (c&0xf) because the upper bits are truncated after <<12 in the cast to (UChar) */ \
+            (c)=(UChar)(((c)<<12)|(__t1<<6)|__t2); \
+            (i)+=2; \
+        } else if( /* handle U+0080..U+07FF inline */ \
+            ((c)<0xe0 && (c)>=0xc2) && \
+            ((i)<(length)) && \
+            (__t1=(uint8_t)((s)[i]-0x80))<=0x3f \
+        ) { \
+            (c)=(UChar)((((c)&0x1f)<<6)|__t1); \
+            ++(i); \
+        } else if(U8_IS_LEAD(c)) { \
+            /* function call for "complicated" and error cases */ \
+            (c)=utf8_nextCharSafeBody((const uint8_t *)s, &(i), (int32_t)(length), c, -1); \
+        } else { \
+            (c)=U_SENTINEL; \
+        } \
+    } \
+}
+
+/**
+ * Append a code point to a string, overwriting 1 to 4 bytes.
+ * The offset points to the current end of the string contents
+ * and is advanced (post-increment).
+ * "Unsafe" macro, assumes a valid code point and sufficient space in the string.
+ * Otherwise, the result is undefined.
+ *
+ * @param s const uint8_t * string buffer
+ * @param i string offset
+ * @param c code point to append
+ * @see U8_APPEND
+ * @stable ICU 2.4
+ */
+#define U8_APPEND_UNSAFE(s, i, c) { \
+    if((uint32_t)(c)<=0x7f) { \
+        (s)[(i)++]=(uint8_t)(c); \
+    } else { \
+        if((uint32_t)(c)<=0x7ff) { \
+            (s)[(i)++]=(uint8_t)(((c)>>6)|0xc0); \
+        } else { \
+            if((uint32_t)(c)<=0xffff) { \
+                (s)[(i)++]=(uint8_t)(((c)>>12)|0xe0); \
+            } else { \
+                (s)[(i)++]=(uint8_t)(((c)>>18)|0xf0); \
+                (s)[(i)++]=(uint8_t)((((c)>>12)&0x3f)|0x80); \
+            } \
+            (s)[(i)++]=(uint8_t)((((c)>>6)&0x3f)|0x80); \
+        } \
+        (s)[(i)++]=(uint8_t)(((c)&0x3f)|0x80); \
+    } \
+}
+
+/**
+ * Append a code point to a string, overwriting 1 to 4 bytes.
+ * The offset points to the current end of the string contents
+ * and is advanced (post-increment).
+ * "Safe" macro, checks for a valid code point.
+ * If a non-ASCII code point is written, checks for sufficient space in the string.
+ * If the code point is not valid or trail bytes do not fit,
+ * then isError is set to TRUE.
+ *
+ * @param s const uint8_t * string buffer
+ * @param i string offset, must be i<capacity
+ * @param capacity size of the string buffer
+ * @param c code point to append
+ * @param isError output UBool set to TRUE if an error occurs, otherwise not modified
+ * @see U8_APPEND_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U8_APPEND(s, i, capacity, c, isError) { \
+    if((uint32_t)(c)<=0x7f) { \
+        (s)[(i)++]=(uint8_t)(c); \
+    } else if((uint32_t)(c)<=0x7ff && (i)+1<(capacity)) { \
+        (s)[(i)++]=(uint8_t)(((c)>>6)|0xc0); \
+        (s)[(i)++]=(uint8_t)(((c)&0x3f)|0x80); \
+    } else if((uint32_t)(c)<=0xd7ff && (i)+2<(capacity)) { \
+        (s)[(i)++]=(uint8_t)(((c)>>12)|0xe0); \
+        (s)[(i)++]=(uint8_t)((((c)>>6)&0x3f)|0x80); \
+        (s)[(i)++]=(uint8_t)(((c)&0x3f)|0x80); \
+    } else { \
+        (i)=utf8_appendCharSafeBody(s, (int32_t)(i), (int32_t)(capacity), c, &(isError)); \
+    } \
+}
+
+/**
+ * Advance the string offset from one code point boundary to the next.
+ * (Post-incrementing iteration.)
+ * "Unsafe" macro, assumes well-formed UTF-8.
+ *
+ * @param s const uint8_t * string
+ * @param i string offset
+ * @see U8_FWD_1
+ * @stable ICU 2.4
+ */
+#define U8_FWD_1_UNSAFE(s, i) { \
+    (i)+=1+U8_COUNT_TRAIL_BYTES((s)[i]); \
+}
+
+/**
+ * Advance the string offset from one code point boundary to the next.
+ * (Post-incrementing iteration.)
+ * "Safe" macro, checks for illegal sequences and for string boundaries.
+ *
+ * @param s const uint8_t * string
+ * @param i string offset, must be i<length
+ * @param length string length
+ * @see U8_FWD_1_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U8_FWD_1(s, i, length) { \
+    uint8_t __b=(uint8_t)(s)[(i)++]; \
+    if(U8_IS_LEAD(__b)) { \
+        uint8_t __count=U8_COUNT_TRAIL_BYTES(__b); \
+        if((i)+__count>(length)) { \
+            __count=(uint8_t)((length)-(i)); \
+        } \
+        while(__count>0 && U8_IS_TRAIL((s)[i])) { \
+            ++(i); \
+            --__count; \
+        } \
+    } \
+}
+
+/**
+ * Advance the string offset from one code point boundary to the n-th next one,
+ * i.e., move forward by n code points.
+ * (Post-incrementing iteration.)
+ * "Unsafe" macro, assumes well-formed UTF-8.
+ *
+ * @param s const uint8_t * string
+ * @param i string offset
+ * @param n number of code points to skip
+ * @see U8_FWD_N
+ * @stable ICU 2.4
+ */
+#define U8_FWD_N_UNSAFE(s, i, n) { \
+    int32_t __N=(n); \
+    while(__N>0) { \
+        U8_FWD_1_UNSAFE(s, i); \
+        --__N; \
+    } \
+}
+
+/**
+ * Advance the string offset from one code point boundary to the n-th next one,
+ * i.e., move forward by n code points.
+ * (Post-incrementing iteration.)
+ * "Safe" macro, checks for illegal sequences and for string boundaries.
+ *
+ * @param s const uint8_t * string
+ * @param i string offset, must be i<length
+ * @param length string length
+ * @param n number of code points to skip
+ * @see U8_FWD_N_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U8_FWD_N(s, i, length, n) { \
+    int32_t __N=(n); \
+    while(__N>0 && (i)<(length)) { \
+        U8_FWD_1(s, i, length); \
+        --__N; \
+    } \
+}
+
+/**
+ * Adjust a random-access offset to a code point boundary
+ * at the start of a code point.
+ * If the offset points to a UTF-8 trail byte,
+ * then the offset is moved backward to the corresponding lead byte.
+ * Otherwise, it is not modified.
+ * "Unsafe" macro, assumes well-formed UTF-8.
+ *
+ * @param s const uint8_t * string
+ * @param i string offset
+ * @see U8_SET_CP_START
+ * @stable ICU 2.4
+ */
+#define U8_SET_CP_START_UNSAFE(s, i) { \
+    while(U8_IS_TRAIL((s)[i])) { --(i); } \
+}
+
+/**
+ * Adjust a random-access offset to a code point boundary
+ * at the start of a code point.
+ * If the offset points to a UTF-8 trail byte,
+ * then the offset is moved backward to the corresponding lead byte.
+ * Otherwise, it is not modified.
+ * "Safe" macro, checks for illegal sequences and for string boundaries.
+ *
+ * @param s const uint8_t * string
+ * @param start starting string offset (usually 0)
+ * @param i string offset, must be start<=i
+ * @see U8_SET_CP_START_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U8_SET_CP_START(s, start, i) { \
+    if(U8_IS_TRAIL((s)[(i)])) { \
+        (i)=utf8_back1SafeBody(s, start, (int32_t)(i)); \
+    } \
+}
+
+/* definitions with backward iteration -------------------------------------- */
+
+/**
+ * Move the string offset from one code point boundary to the previous one
+ * and get the code point between them.
+ * (Pre-decrementing backward iteration.)
+ * "Unsafe" macro, assumes well-formed UTF-8.
+ *
+ * The input offset may be the same as the string length.
+ * If the offset is behind a multi-byte sequence, then the macro will read
+ * the whole sequence.
+ * If the offset is behind a lead byte, then that itself
+ * will be returned as the code point.
+ * The result is undefined if the offset is behind an illegal UTF-8 sequence.
+ *
+ * @param s const uint8_t * string
+ * @param i string offset
+ * @param c output UChar32 variable
+ * @see U8_PREV
+ * @stable ICU 2.4
+ */
+#define U8_PREV_UNSAFE(s, i, c) { \
+    (c)=(uint8_t)(s)[--(i)]; \
+    if(U8_IS_TRAIL(c)) { \
+        uint8_t __b, __count=1, __shift=6; \
+\
+        /* c is a trail byte */ \
+        (c)&=0x3f; \
+        for(;;) { \
+            __b=(uint8_t)(s)[--(i)]; \
+            if(__b>=0xc0) { \
+                U8_MASK_LEAD_BYTE(__b, __count); \
+                (c)|=(UChar32)__b<<__shift; \
+                break; \
+            } else { \
+                (c)|=(UChar32)(__b&0x3f)<<__shift; \
+                ++__count; \
+                __shift+=6; \
+            } \
+        } \
+    } \
+}
+
+/**
+ * Move the string offset from one code point boundary to the previous one
+ * and get the code point between them.
+ * (Pre-decrementing backward iteration.)
+ * "Safe" macro, checks for illegal sequences and for string boundaries.
+ *
+ * The input offset may be the same as the string length.
+ * If the offset is behind a multi-byte sequence, then the macro will read
+ * the whole sequence.
+ * If the offset is behind a lead byte, then that itself
+ * will be returned as the code point.
+ * If the offset is behind an illegal UTF-8 sequence, then c is set to a negative value.
+ *
+ * @param s const uint8_t * string
+ * @param start starting string offset (usually 0)
+ * @param i string offset, must be start<i
+ * @param c output UChar32 variable, set to <0 in case of an error
+ * @see U8_PREV_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U8_PREV(s, start, i, c) { \
+    (c)=(uint8_t)(s)[--(i)]; \
+    if((c)>=0x80) { \
+        if((c)<=0xbf) { \
+            (c)=utf8_prevCharSafeBody((const uint8_t *)s, start, &(i), c, -1); \
+        } else { \
+            (c)=U_SENTINEL; \
+        } \
+    } \
+}
+
+/**
+ * Move the string offset from one code point boundary to the previous one.
+ * (Pre-decrementing backward iteration.)
+ * The input offset may be the same as the string length.
+ * "Unsafe" macro, assumes well-formed UTF-8.
+ *
+ * @param s const uint8_t * string
+ * @param i string offset
+ * @see U8_BACK_1
+ * @stable ICU 2.4
+ */
+#define U8_BACK_1_UNSAFE(s, i) { \
+    while(U8_IS_TRAIL((s)[--(i)])) {} \
+}
+
+/**
+ * Move the string offset from one code point boundary to the previous one.
+ * (Pre-decrementing backward iteration.)
+ * The input offset may be the same as the string length.
+ * "Safe" macro, checks for illegal sequences and for string boundaries.
+ *
+ * @param s const uint8_t * string
+ * @param start starting string offset (usually 0)
+ * @param i string offset, must be start<i
+ * @see U8_BACK_1_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U8_BACK_1(s, start, i) { \
+    if(U8_IS_TRAIL((s)[--(i)])) { \
+        (i)=utf8_back1SafeBody(s, start, (int32_t)(i)); \
+    } \
+}
+
+/**
+ * Move the string offset from one code point boundary to the n-th one before it,
+ * i.e., move backward by n code points.
+ * (Pre-decrementing backward iteration.)
+ * The input offset may be the same as the string length.
+ * "Unsafe" macro, assumes well-formed UTF-8.
+ *
+ * @param s const uint8_t * string
+ * @param i string offset
+ * @param n number of code points to skip
+ * @see U8_BACK_N
+ * @stable ICU 2.4
+ */
+#define U8_BACK_N_UNSAFE(s, i, n) { \
+    int32_t __N=(n); \
+    while(__N>0) { \
+        U8_BACK_1_UNSAFE(s, i); \
+        --__N; \
+    } \
+}
+
+/**
+ * Move the string offset from one code point boundary to the n-th one before it,
+ * i.e., move backward by n code points.
+ * (Pre-decrementing backward iteration.)
+ * The input offset may be the same as the string length.
+ * "Safe" macro, checks for illegal sequences and for string boundaries.
+ *
+ * @param s const uint8_t * string
+ * @param start index of the start of the string
+ * @param i string offset, must be start<i
+ * @param n number of code points to skip
+ * @see U8_BACK_N_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U8_BACK_N(s, start, i, n) { \
+    int32_t __N=(n); \
+    while(__N>0 && (i)>(start)) { \
+        U8_BACK_1(s, start, i); \
+        --__N; \
+    } \
+}
+
+/**
+ * Adjust a random-access offset to a code point boundary after a code point.
+ * If the offset is behind a partial multi-byte sequence,
+ * then the offset is incremented to behind the whole sequence.
+ * Otherwise, it is not modified.
+ * The input offset may be the same as the string length.
+ * "Unsafe" macro, assumes well-formed UTF-8.
+ *
+ * @param s const uint8_t * string
+ * @param i string offset
+ * @see U8_SET_CP_LIMIT
+ * @stable ICU 2.4
+ */
+#define U8_SET_CP_LIMIT_UNSAFE(s, i) { \
+    U8_BACK_1_UNSAFE(s, i); \
+    U8_FWD_1_UNSAFE(s, i); \
+}
+
+/**
+ * Adjust a random-access offset to a code point boundary after a code point.
+ * If the offset is behind a partial multi-byte sequence,
+ * then the offset is incremented to behind the whole sequence.
+ * Otherwise, it is not modified.
+ * The input offset may be the same as the string length.
+ * "Safe" macro, checks for illegal sequences and for string boundaries.
+ *
+ * @param s const uint8_t * string
+ * @param start starting string offset (usually 0)
+ * @param i string offset, must be start<=i<=length
+ * @param length string length
+ * @see U8_SET_CP_LIMIT_UNSAFE
+ * @stable ICU 2.4
+ */
+#define U8_SET_CP_LIMIT(s, start, i, length) { \
+    if((start)<(i) && (i)<(length)) { \
+        U8_BACK_1(s, start, i); \
+        U8_FWD_1(s, i, length); \
+    } \
+}
+
+#endif
diff --git a/source/common/unicode/utf_old.h b/source/common/unicode/utf_old.h
new file mode 100644
index 0000000..b360b34
--- /dev/null
+++ b/source/common/unicode/utf_old.h
@@ -0,0 +1,1173 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2002-2008, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  utf.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002sep21
+*   created by: Markus W. Scherer
+*/
+
+/**
+ * \file 
+ * \brief C API: Deprecated macros for Unicode string handling
+ */
+
+/**
+ * 
+ * The macros in utf_old.h are all deprecated and their use discouraged.
+ * Some of the design principles behind the set of UTF macros
+ * have changed or proved impractical.
+ * Almost all of the old "UTF macros" are at least renamed.
+ * If you are looking for a new equivalent to an old macro, please see the
+ * comment at the old one.
+ *
+ * utf_old.h is included by utf.h after unicode/umachine.h
+ * and some common definitions, to not break old code.
+ *
+ * Brief summary of reasons for deprecation:
+ * - Switch on UTF_SIZE (selection of UTF-8/16/32 default string processing)
+ *   was impractical.
+ * - Switch on UTF_SAFE etc. (selection of unsafe/safe/strict default string processing)
+ *   was of little use and impractical.
+ * - Whole classes of macros became obsolete outside of the UTF_SIZE/UTF_SAFE
+ *   selection framework: UTF32_ macros (all trivial)
+ *   and UTF_ default and intermediate macros (all aliases).
+ * - The selection framework also caused many macro aliases.
+ * - Change in Unicode standard: "irregular" sequences (3.0) became illegal (3.2).
+ * - Change of language in Unicode standard:
+ *   Growing distinction between internal x-bit Unicode strings and external UTF-x
+ *   forms, with the former more lenient.
+ *   Suggests renaming of UTF16_ macros to U16_.
+ * - The prefix "UTF_" without a width number confused some users.
+ * - "Safe" append macros needed the addition of an error indicator output.
+ * - "Safe" UTF-8 macros used legitimate (if rarely used) code point values
+ *   to indicate error conditions.
+ * - The use of the "_CHAR" infix for code point operations confused some users.
+ *
+ * More details:
+ *
+ * Until ICU 2.2, utf.h theoretically allowed to choose among UTF-8/16/32
+ * for string processing, and among unsafe/safe/strict default macros for that.
+ *
+ * It proved nearly impossible to write non-trivial, high-performance code
+ * that is UTF-generic.
+ * Unsafe default macros would be dangerous for default string processing,
+ * and the main reason for the "strict" versions disappeared:
+ * Between Unicode 3.0 and 3.2 all "irregular" UTF-8 sequences became illegal.
+ * The only other conditions that "strict" checked for were non-characters,
+ * which are valid during processing. Only during text input/output should they
+ * be checked, and at that time other well-formedness checks may be
+ * necessary or useful as well.
+ * This can still be done by using U16_NEXT and U_IS_UNICODE_NONCHAR
+ * or U_IS_UNICODE_CHAR.
+ *
+ * The old UTF8_..._SAFE macros also used some normal Unicode code points
+ * to indicate malformed sequences.
+ * The new UTF8_ macros without suffix use negative values instead.
+ *
+ * The entire contents of utf32.h was moved here without replacement
+ * because all those macros were trivial and
+ * were meaningful only in the framework of choosing the UTF size.
+ *
+ * See Jitterbug 2150 and its discussion on the ICU mailing list
+ * in September 2002.
+ *
+ * <hr>
+ *
+ * <em>Obsolete part</em> of pre-ICU 2.4 utf.h file documentation:
+ *
+ * <p>The original concept for these files was for ICU to allow
+ * in principle to set which UTF (UTF-8/16/32) is used internally
+ * by defining UTF_SIZE to either 8, 16, or 32. utf.h would then define the UChar type
+ * accordingly. UTF-16 was the default.</p>
+ *
+ * <p>This concept has been abandoned.
+ * A lot of the ICU source code assumes UChar strings are in UTF-16.
+ * This is especially true for low-level code like
+ * conversion, normalization, and collation.
+ * The utf.h header enforces the default of UTF-16.
+ * The UTF-8 and UTF-32 macros remain for now for completeness and backward compatibility.</p>
+ *
+ * <p>Accordingly, utf.h defines UChar to be an unsigned 16-bit integer. If this matches wchar_t, then
+ * UChar is defined to be exactly wchar_t, otherwise uint16_t.</p>
+ *
+ * <p>UChar32 is defined to be a signed 32-bit integer (int32_t), large enough for a 21-bit
+ * Unicode code point (Unicode scalar value, 0..0x10ffff).
+ * Before ICU 2.4, the definition of UChar32 was similarly platform-dependent as
+ * the definition of UChar. For details see the documentation for UChar32 itself.</p>
+ *
+ * <p>utf.h also defines a number of C macros for handling single Unicode code points and
+ * for using UTF Unicode strings. It includes utf8.h, utf16.h, and utf32.h for the actual
+ * implementations of those macros and then aliases one set of them (for UTF-16) for general use.
+ * The UTF-specific macros have the UTF size in the macro name prefixes (UTF16_...), while
+ * the general alias macros always begin with UTF_...</p>
+ *
+ * <p>Many string operations can be done with or without error checking.
+ * Where such a distinction is useful, there are two versions of the macros, "unsafe" and "safe"
+ * ones with ..._UNSAFE and ..._SAFE suffixes. The unsafe macros are fast but may cause
+ * program failures if the strings are not well-formed. The safe macros have an additional, boolean
+ * parameter "strict". If strict is FALSE, then only illegal sequences are detected.
+ * Otherwise, irregular sequences and non-characters are detected as well (like single surrogates).
+ * Safe macros return special error code points for illegal/irregular sequences:
+ * Typically, U+ffff, or values that would result in a code unit sequence of the same length
+ * as the erroneous input sequence.<br>
+ * Note that _UNSAFE macros have fewer parameters: They do not have the strictness parameter, and
+ * they do not have start/length parameters for boundary checking.</p>
+ *
+ * <p>Here, the macros are aliased in two steps:
+ * In the first step, the UTF-specific macros with UTF16_ prefix and _UNSAFE and _SAFE suffixes are
+ * aliased according to the UTF_SIZE to macros with UTF_ prefix and the same suffixes and signatures.
+ * Then, in a second step, the default, general alias macros are set to use either the unsafe or
+ * the safe/not strict (default) or the safe/strict macro;
+ * these general macros do not have a strictness parameter.</p>
+ *
+ * <p>It is possible to change the default choice for the general alias macros to be unsafe, safe/not strict or safe/strict.
+ * The default is safe/not strict. It is not recommended to select the unsafe macros as the basis for
+ * Unicode string handling in ICU! To select this, define UTF_SAFE, UTF_STRICT, or UTF_UNSAFE.</p>
+ *
+ * <p>For general use, one should use the default, general macros with UTF_ prefix and no _SAFE/_UNSAFE suffix.
+ * Only in some cases it may be necessary to control the choice of macro directly and use a less generic alias.
+ * For example, if it can be assumed that a string is well-formed and the index will stay within the bounds,
+ * then the _UNSAFE version may be used.
+ * If a UTF-8 string is to be processed, then the macros with UTF8_ prefixes need to be used.</p>
+ *
+ * <hr>
+ *
+ * @deprecated ICU 2.4. Use the macros in utf.h, utf16.h, utf8.h instead.
+ */
+
+#ifndef __UTF_OLD_H__
+#define __UTF_OLD_H__
+
+#ifndef U_HIDE_DEPRECATED_API
+
+/* utf.h must be included first. */
+#ifndef __UTF_H__
+#   include "unicode/utf.h"
+#endif
+
+/* Formerly utf.h, part 1 --------------------------------------------------- */
+
+#ifdef U_USE_UTF_DEPRECATES
+/**
+ * Unicode string and array offset and index type.
+ * ICU always counts Unicode code units (UChars) for
+ * string offsets, indexes, and lengths, not Unicode code points.
+ *
+ * @obsolete ICU 2.6. Use int32_t directly instead since this API will be removed in that release.
+ */
+typedef int32_t UTextOffset;
+#endif
+
+/** Number of bits in a Unicode string code unit - ICU uses 16-bit Unicode. @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF_SIZE 16
+
+/**
+ * The default choice for general Unicode string macros is to use the ..._SAFE macro implementations
+ * with strict=FALSE.
+ *
+ * @deprecated ICU 2.4. Obsolete, see utf_old.h.
+ */
+#define UTF_SAFE
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#undef UTF_UNSAFE
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#undef UTF_STRICT
+
+/**
+ * UTF8_ERROR_VALUE_1 and UTF8_ERROR_VALUE_2 are special error values for UTF-8,
+ * which need 1 or 2 bytes in UTF-8:
+ * \code
+ * U+0015 = NAK = Negative Acknowledge, C0 control character
+ * U+009f = highest C1 control character
+ * \endcode
+ *
+ * These are used by UTF8_..._SAFE macros so that they can return an error value
+ * that needs the same number of code units (bytes) as were seen by
+ * a macro. They should be tested with UTF_IS_ERROR() or UTF_IS_VALID().
+ *
+ * @deprecated ICU 2.4. Obsolete, see utf_old.h.
+ */
+#define UTF8_ERROR_VALUE_1 0x15
+
+/**
+ * See documentation on UTF8_ERROR_VALUE_1 for details.
+ *
+ * @deprecated ICU 2.4. Obsolete, see utf_old.h.
+ */
+#define UTF8_ERROR_VALUE_2 0x9f
+
+/**
+ * Error value for all UTFs. This code point value will be set by macros with error
+ * checking if an error is detected.
+ *
+ * @deprecated ICU 2.4. Obsolete, see utf_old.h.
+ */
+#define UTF_ERROR_VALUE 0xffff
+
+/**
+ * Is a given 32-bit code an error value
+ * as returned by one of the macros for any UTF?
+ *
+ * @deprecated ICU 2.4. Obsolete, see utf_old.h.
+ */
+#define UTF_IS_ERROR(c) \
+    (((c)&0xfffe)==0xfffe || (c)==UTF8_ERROR_VALUE_1 || (c)==UTF8_ERROR_VALUE_2)
+
+/**
+ * This is a combined macro: Is c a valid Unicode value _and_ not an error code?
+ *
+ * @deprecated ICU 2.4. Obsolete, see utf_old.h.
+ */
+#define UTF_IS_VALID(c) \
+    (UTF_IS_UNICODE_CHAR(c) && \
+     (c)!=UTF8_ERROR_VALUE_1 && (c)!=UTF8_ERROR_VALUE_2)
+
+/**
+ * Is this code unit or code point a surrogate (U+d800..U+dfff)?
+ * @deprecated ICU 2.4. Renamed to U_IS_SURROGATE and U16_IS_SURROGATE, see utf_old.h.
+ */
+#define UTF_IS_SURROGATE(uchar) (((uchar)&0xfffff800)==0xd800)
+
+/**
+ * Is a given 32-bit code point a Unicode noncharacter?
+ *
+ * @deprecated ICU 2.4. Renamed to U_IS_UNICODE_NONCHAR, see utf_old.h.
+ */
+#define UTF_IS_UNICODE_NONCHAR(c) \
+    ((c)>=0xfdd0 && \
+     ((uint32_t)(c)<=0xfdef || ((c)&0xfffe)==0xfffe) && \
+     (uint32_t)(c)<=0x10ffff)
+
+/**
+ * Is a given 32-bit value a Unicode code point value (0..U+10ffff)
+ * that can be assigned a character?
+ *
+ * Code points that are not characters include:
+ * - single surrogate code points (U+d800..U+dfff, 2048 code points)
+ * - the last two code points on each plane (U+__fffe and U+__ffff, 34 code points)
+ * - U+fdd0..U+fdef (new with Unicode 3.1, 32 code points)
+ * - the highest Unicode code point value is U+10ffff
+ *
+ * This means that all code points below U+d800 are character code points,
+ * and that boundary is tested first for performance.
+ *
+ * @deprecated ICU 2.4. Renamed to U_IS_UNICODE_CHAR, see utf_old.h.
+ */
+#define UTF_IS_UNICODE_CHAR(c) \
+    ((uint32_t)(c)<0xd800 || \
+        ((uint32_t)(c)>0xdfff && \
+         (uint32_t)(c)<=0x10ffff && \
+         !UTF_IS_UNICODE_NONCHAR(c)))
+
+/* Formerly utf8.h ---------------------------------------------------------- */
+
+/**
+ * Count the trail bytes for a UTF-8 lead byte.
+ * @deprecated ICU 2.4. Renamed to U8_COUNT_TRAIL_BYTES, see utf_old.h.
+ */
+#define UTF8_COUNT_TRAIL_BYTES(leadByte) (utf8_countTrailBytes[(uint8_t)leadByte])
+
+/**
+ * Mask a UTF-8 lead byte, leave only the lower bits that form part of the code point value.
+ * @deprecated ICU 2.4. Renamed to U8_MASK_LEAD_BYTE, see utf_old.h.
+ */
+#define UTF8_MASK_LEAD_BYTE(leadByte, countTrailBytes) ((leadByte)&=(1<<(6-(countTrailBytes)))-1)
+
+/** Is this this code point a single code unit (byte)? @deprecated ICU 2.4. Renamed to U8_IS_SINGLE, see utf_old.h. */
+#define UTF8_IS_SINGLE(uchar) (((uchar)&0x80)==0)
+/** Is this this code unit the lead code unit (byte) of a code point? @deprecated ICU 2.4. Renamed to U8_IS_LEAD, see utf_old.h. */
+#define UTF8_IS_LEAD(uchar) ((uint8_t)((uchar)-0xc0)<0x3e)
+/** Is this this code unit a trailing code unit (byte) of a code point? @deprecated ICU 2.4. Renamed to U8_IS_TRAIL, see utf_old.h. */
+#define UTF8_IS_TRAIL(uchar) (((uchar)&0xc0)==0x80)
+
+/** Does this scalar Unicode value need multiple code units for storage? @deprecated ICU 2.4. Use U8_LENGTH or test ((uint32_t)(c)>0x7f) instead, see utf_old.h. */
+#define UTF8_NEED_MULTIPLE_UCHAR(c) ((uint32_t)(c)>0x7f)
+
+/**
+ * Given the lead character, how many bytes are taken by this code point.
+ * ICU does not deal with code points >0x10ffff
+ * unless necessary for advancing in the byte stream.
+ *
+ * These length macros take into account that for values >0x10ffff
+ * the UTF8_APPEND_CHAR_SAFE macros would write the error code point 0xffff
+ * with 3 bytes.
+ * Code point comparisons need to be in uint32_t because UChar32
+ * may be a signed type, and negative values must be recognized.
+ *
+ * @deprecated ICU 2.4. Use U8_LENGTH instead, see utf_old.h.
+ */
+#if 1
+#   define UTF8_CHAR_LENGTH(c) \
+        ((uint32_t)(c)<=0x7f ? 1 : \
+            ((uint32_t)(c)<=0x7ff ? 2 : \
+                ((uint32_t)((c)-0x10000)>0xfffff ? 3 : 4) \
+            ) \
+        )
+#else
+#   define UTF8_CHAR_LENGTH(c) \
+        ((uint32_t)(c)<=0x7f ? 1 : \
+            ((uint32_t)(c)<=0x7ff ? 2 : \
+                ((uint32_t)(c)<=0xffff ? 3 : \
+                    ((uint32_t)(c)<=0x10ffff ? 4 : \
+                        ((uint32_t)(c)<=0x3ffffff ? 5 : \
+                            ((uint32_t)(c)<=0x7fffffff ? 6 : 3) \
+                        ) \
+                    ) \
+                ) \
+            ) \
+        )
+#endif
+
+/** The maximum number of bytes per code point. @deprecated ICU 2.4. Renamed to U8_MAX_LENGTH, see utf_old.h. */
+#define UTF8_MAX_CHAR_LENGTH 4
+
+/** Average number of code units compared to UTF-16. @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF8_ARRAY_SIZE(size) ((5*(size))/2)
+
+/** @deprecated ICU 2.4. Renamed to U8_GET_UNSAFE, see utf_old.h. */
+#define UTF8_GET_CHAR_UNSAFE(s, i, c) { \
+    int32_t _utf8_get_char_unsafe_index=(int32_t)(i); \
+    UTF8_SET_CHAR_START_UNSAFE(s, _utf8_get_char_unsafe_index); \
+    UTF8_NEXT_CHAR_UNSAFE(s, _utf8_get_char_unsafe_index, c); \
+}
+
+/** @deprecated ICU 2.4. Use U8_GET instead, see utf_old.h. */
+#define UTF8_GET_CHAR_SAFE(s, start, i, length, c, strict) { \
+    int32_t _utf8_get_char_safe_index=(int32_t)(i); \
+    UTF8_SET_CHAR_START_SAFE(s, start, _utf8_get_char_safe_index); \
+    UTF8_NEXT_CHAR_SAFE(s, _utf8_get_char_safe_index, length, c, strict); \
+}
+
+/** @deprecated ICU 2.4. Renamed to U8_NEXT_UNSAFE, see utf_old.h. */
+#define UTF8_NEXT_CHAR_UNSAFE(s, i, c) { \
+    (c)=(s)[(i)++]; \
+    if((uint8_t)((c)-0xc0)<0x35) { \
+        uint8_t __count=UTF8_COUNT_TRAIL_BYTES(c); \
+        UTF8_MASK_LEAD_BYTE(c, __count); \
+        switch(__count) { \
+        /* each following branch falls through to the next one */ \
+        case 3: \
+            (c)=((c)<<6)|((s)[(i)++]&0x3f); \
+        case 2: \
+            (c)=((c)<<6)|((s)[(i)++]&0x3f); \
+        case 1: \
+            (c)=((c)<<6)|((s)[(i)++]&0x3f); \
+        /* no other branches to optimize switch() */ \
+            break; \
+        } \
+    } \
+}
+
+/** @deprecated ICU 2.4. Renamed to U8_APPEND_UNSAFE, see utf_old.h. */
+#define UTF8_APPEND_CHAR_UNSAFE(s, i, c) { \
+    if((uint32_t)(c)<=0x7f) { \
+        (s)[(i)++]=(uint8_t)(c); \
+    } else { \
+        if((uint32_t)(c)<=0x7ff) { \
+            (s)[(i)++]=(uint8_t)(((c)>>6)|0xc0); \
+        } else { \
+            if((uint32_t)(c)<=0xffff) { \
+                (s)[(i)++]=(uint8_t)(((c)>>12)|0xe0); \
+            } else { \
+                (s)[(i)++]=(uint8_t)(((c)>>18)|0xf0); \
+                (s)[(i)++]=(uint8_t)((((c)>>12)&0x3f)|0x80); \
+            } \
+            (s)[(i)++]=(uint8_t)((((c)>>6)&0x3f)|0x80); \
+        } \
+        (s)[(i)++]=(uint8_t)(((c)&0x3f)|0x80); \
+    } \
+}
+
+/** @deprecated ICU 2.4. Renamed to U8_FWD_1_UNSAFE, see utf_old.h. */
+#define UTF8_FWD_1_UNSAFE(s, i) { \
+    (i)+=1+UTF8_COUNT_TRAIL_BYTES((s)[i]); \
+}
+
+/** @deprecated ICU 2.4. Renamed to U8_FWD_N_UNSAFE, see utf_old.h. */
+#define UTF8_FWD_N_UNSAFE(s, i, n) { \
+    int32_t __N=(n); \
+    while(__N>0) { \
+        UTF8_FWD_1_UNSAFE(s, i); \
+        --__N; \
+    } \
+}
+
+/** @deprecated ICU 2.4. Renamed to U8_SET_CP_START_UNSAFE, see utf_old.h. */
+#define UTF8_SET_CHAR_START_UNSAFE(s, i) { \
+    while(UTF8_IS_TRAIL((s)[i])) { --(i); } \
+}
+
+/** @deprecated ICU 2.4. Use U8_NEXT instead, see utf_old.h. */
+#define UTF8_NEXT_CHAR_SAFE(s, i, length, c, strict) { \
+    (c)=(s)[(i)++]; \
+    if((c)>=0x80) { \
+        if(UTF8_IS_LEAD(c)) { \
+            (c)=utf8_nextCharSafeBody(s, &(i), (int32_t)(length), c, strict); \
+        } else { \
+            (c)=UTF8_ERROR_VALUE_1; \
+        } \
+    } \
+}
+
+/** @deprecated ICU 2.4. Use U8_APPEND instead, see utf_old.h. */
+#define UTF8_APPEND_CHAR_SAFE(s, i, length, c)  { \
+    if((uint32_t)(c)<=0x7f) { \
+        (s)[(i)++]=(uint8_t)(c); \
+    } else { \
+        (i)=utf8_appendCharSafeBody(s, (int32_t)(i), (int32_t)(length), c, NULL); \
+    } \
+}
+
+/** @deprecated ICU 2.4. Renamed to U8_FWD_1, see utf_old.h. */
+#define UTF8_FWD_1_SAFE(s, i, length) U8_FWD_1(s, i, length)
+
+/** @deprecated ICU 2.4. Renamed to U8_FWD_N, see utf_old.h. */
+#define UTF8_FWD_N_SAFE(s, i, length, n) U8_FWD_N(s, i, length, n)
+
+/** @deprecated ICU 2.4. Renamed to U8_SET_CP_START, see utf_old.h. */
+#define UTF8_SET_CHAR_START_SAFE(s, start, i) U8_SET_CP_START(s, start, i)
+
+/** @deprecated ICU 2.4. Renamed to U8_PREV_UNSAFE, see utf_old.h. */
+#define UTF8_PREV_CHAR_UNSAFE(s, i, c) { \
+    (c)=(s)[--(i)]; \
+    if(UTF8_IS_TRAIL(c)) { \
+        uint8_t __b, __count=1, __shift=6; \
+\
+        /* c is a trail byte */ \
+        (c)&=0x3f; \
+        for(;;) { \
+            __b=(s)[--(i)]; \
+            if(__b>=0xc0) { \
+                UTF8_MASK_LEAD_BYTE(__b, __count); \
+                (c)|=(UChar32)__b<<__shift; \
+                break; \
+            } else { \
+                (c)|=(UChar32)(__b&0x3f)<<__shift; \
+                ++__count; \
+                __shift+=6; \
+            } \
+        } \
+    } \
+}
+
+/** @deprecated ICU 2.4. Renamed to U8_BACK_1_UNSAFE, see utf_old.h. */
+#define UTF8_BACK_1_UNSAFE(s, i) { \
+    while(UTF8_IS_TRAIL((s)[--(i)])) {} \
+}
+
+/** @deprecated ICU 2.4. Renamed to U8_BACK_N_UNSAFE, see utf_old.h. */
+#define UTF8_BACK_N_UNSAFE(s, i, n) { \
+    int32_t __N=(n); \
+    while(__N>0) { \
+        UTF8_BACK_1_UNSAFE(s, i); \
+        --__N; \
+    } \
+}
+
+/** @deprecated ICU 2.4. Renamed to U8_SET_CP_LIMIT_UNSAFE, see utf_old.h. */
+#define UTF8_SET_CHAR_LIMIT_UNSAFE(s, i) { \
+    UTF8_BACK_1_UNSAFE(s, i); \
+    UTF8_FWD_1_UNSAFE(s, i); \
+}
+
+/** @deprecated ICU 2.4. Use U8_PREV instead, see utf_old.h. */
+#define UTF8_PREV_CHAR_SAFE(s, start, i, c, strict) { \
+    (c)=(s)[--(i)]; \
+    if((c)>=0x80) { \
+        if((c)<=0xbf) { \
+            (c)=utf8_prevCharSafeBody(s, start, &(i), c, strict); \
+        } else { \
+            (c)=UTF8_ERROR_VALUE_1; \
+        } \
+    } \
+}
+
+/** @deprecated ICU 2.4. Renamed to U8_BACK_1, see utf_old.h. */
+#define UTF8_BACK_1_SAFE(s, start, i) U8_BACK_1(s, start, i)
+
+/** @deprecated ICU 2.4. Renamed to U8_BACK_N, see utf_old.h. */
+#define UTF8_BACK_N_SAFE(s, start, i, n) U8_BACK_N(s, start, i, n)
+
+/** @deprecated ICU 2.4. Renamed to U8_SET_CP_LIMIT, see utf_old.h. */
+#define UTF8_SET_CHAR_LIMIT_SAFE(s, start, i, length) U8_SET_CP_LIMIT(s, start, i, length)
+
+/* Formerly utf16.h --------------------------------------------------------- */
+
+/** Is uchar a first/lead surrogate? @deprecated ICU 2.4. Renamed to U_IS_LEAD and U16_IS_LEAD, see utf_old.h. */
+#define UTF_IS_FIRST_SURROGATE(uchar) (((uchar)&0xfffffc00)==0xd800)
+
+/** Is uchar a second/trail surrogate? @deprecated ICU 2.4. Renamed to U_IS_TRAIL and U16_IS_TRAIL, see utf_old.h. */
+#define UTF_IS_SECOND_SURROGATE(uchar) (((uchar)&0xfffffc00)==0xdc00)
+
+/** Assuming c is a surrogate, is it a first/lead surrogate? @deprecated ICU 2.4. Renamed to U_IS_SURROGATE_LEAD and U16_IS_SURROGATE_LEAD, see utf_old.h. */
+#define UTF_IS_SURROGATE_FIRST(c) (((c)&0x400)==0)
+
+/** Helper constant for UTF16_GET_PAIR_VALUE. @deprecated ICU 2.4. Renamed to U16_SURROGATE_OFFSET, see utf_old.h. */
+#define UTF_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000)
+
+/** Get the UTF-32 value from the surrogate code units. @deprecated ICU 2.4. Renamed to U16_GET_SUPPLEMENTARY, see utf_old.h. */
+#define UTF16_GET_PAIR_VALUE(first, second) \
+    (((first)<<10UL)+(second)-UTF_SURROGATE_OFFSET)
+
+/** @deprecated ICU 2.4. Renamed to U16_LEAD, see utf_old.h. */
+#define UTF_FIRST_SURROGATE(supplementary) (UChar)(((supplementary)>>10)+0xd7c0)
+
+/** @deprecated ICU 2.4. Renamed to U16_TRAIL, see utf_old.h. */
+#define UTF_SECOND_SURROGATE(supplementary) (UChar)(((supplementary)&0x3ff)|0xdc00)
+
+/** @deprecated ICU 2.4. Renamed to U16_LEAD, see utf_old.h. */
+#define UTF16_LEAD(supplementary) UTF_FIRST_SURROGATE(supplementary)
+
+/** @deprecated ICU 2.4. Renamed to U16_TRAIL, see utf_old.h. */
+#define UTF16_TRAIL(supplementary) UTF_SECOND_SURROGATE(supplementary)
+
+/** @deprecated ICU 2.4. Renamed to U16_IS_SINGLE, see utf_old.h. */
+#define UTF16_IS_SINGLE(uchar) !UTF_IS_SURROGATE(uchar)
+
+/** @deprecated ICU 2.4. Renamed to U16_IS_LEAD, see utf_old.h. */
+#define UTF16_IS_LEAD(uchar) UTF_IS_FIRST_SURROGATE(uchar)
+
+/** @deprecated ICU 2.4. Renamed to U16_IS_TRAIL, see utf_old.h. */
+#define UTF16_IS_TRAIL(uchar) UTF_IS_SECOND_SURROGATE(uchar)
+
+/** Does this scalar Unicode value need multiple code units for storage? @deprecated ICU 2.4. Use U16_LENGTH or test ((uint32_t)(c)>0xffff) instead, see utf_old.h. */
+#define UTF16_NEED_MULTIPLE_UCHAR(c) ((uint32_t)(c)>0xffff)
+
+/** @deprecated ICU 2.4. Renamed to U16_LENGTH, see utf_old.h. */
+#define UTF16_CHAR_LENGTH(c) ((uint32_t)(c)<=0xffff ? 1 : 2)
+
+/** @deprecated ICU 2.4. Renamed to U16_MAX_LENGTH, see utf_old.h. */
+#define UTF16_MAX_CHAR_LENGTH 2
+
+/** Average number of code units compared to UTF-16. @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF16_ARRAY_SIZE(size) (size)
+
+/**
+ * Get a single code point from an offset that points to any
+ * of the code units that belong to that code point.
+ * Assume 0<=i<length.
+ *
+ * This could be used for iteration together with
+ * UTF16_CHAR_LENGTH() and UTF_IS_ERROR(),
+ * but the use of UTF16_NEXT_CHAR[_UNSAFE]() and
+ * UTF16_PREV_CHAR[_UNSAFE]() is more efficient for that.
+ * @deprecated ICU 2.4. Renamed to U16_GET_UNSAFE, see utf_old.h.
+ */
+#define UTF16_GET_CHAR_UNSAFE(s, i, c) { \
+    (c)=(s)[i]; \
+    if(UTF_IS_SURROGATE(c)) { \
+        if(UTF_IS_SURROGATE_FIRST(c)) { \
+            (c)=UTF16_GET_PAIR_VALUE((c), (s)[(i)+1]); \
+        } else { \
+            (c)=UTF16_GET_PAIR_VALUE((s)[(i)-1], (c)); \
+        } \
+    } \
+}
+
+/** @deprecated ICU 2.4. Use U16_GET instead, see utf_old.h. */
+#define UTF16_GET_CHAR_SAFE(s, start, i, length, c, strict) { \
+    (c)=(s)[i]; \
+    if(UTF_IS_SURROGATE(c)) { \
+        uint16_t __c2; \
+        if(UTF_IS_SURROGATE_FIRST(c)) { \
+            if((i)+1<(length) && UTF_IS_SECOND_SURROGATE(__c2=(s)[(i)+1])) { \
+                (c)=UTF16_GET_PAIR_VALUE((c), __c2); \
+                /* strict: ((c)&0xfffe)==0xfffe is caught by UTF_IS_ERROR() and UTF_IS_UNICODE_CHAR() */ \
+            } else if(strict) {\
+                /* unmatched first surrogate */ \
+                (c)=UTF_ERROR_VALUE; \
+            } \
+        } else { \
+            if((i)-1>=(start) && UTF_IS_FIRST_SURROGATE(__c2=(s)[(i)-1])) { \
+                (c)=UTF16_GET_PAIR_VALUE(__c2, (c)); \
+                /* strict: ((c)&0xfffe)==0xfffe is caught by UTF_IS_ERROR() and UTF_IS_UNICODE_CHAR() */ \
+            } else if(strict) {\
+                /* unmatched second surrogate */ \
+                (c)=UTF_ERROR_VALUE; \
+            } \
+        } \
+    } else if((strict) && !UTF_IS_UNICODE_CHAR(c)) { \
+        (c)=UTF_ERROR_VALUE; \
+    } \
+}
+
+/** @deprecated ICU 2.4. Renamed to U16_NEXT_UNSAFE, see utf_old.h. */
+#define UTF16_NEXT_CHAR_UNSAFE(s, i, c) { \
+    (c)=(s)[(i)++]; \
+    if(UTF_IS_FIRST_SURROGATE(c)) { \
+        (c)=UTF16_GET_PAIR_VALUE((c), (s)[(i)++]); \
+    } \
+}
+
+/** @deprecated ICU 2.4. Renamed to U16_APPEND_UNSAFE, see utf_old.h. */
+#define UTF16_APPEND_CHAR_UNSAFE(s, i, c) { \
+    if((uint32_t)(c)<=0xffff) { \
+        (s)[(i)++]=(uint16_t)(c); \
+    } else { \
+        (s)[(i)++]=(uint16_t)(((c)>>10)+0xd7c0); \
+        (s)[(i)++]=(uint16_t)(((c)&0x3ff)|0xdc00); \
+    } \
+}
+
+/** @deprecated ICU 2.4. Renamed to U16_FWD_1_UNSAFE, see utf_old.h. */
+#define UTF16_FWD_1_UNSAFE(s, i) { \
+    if(UTF_IS_FIRST_SURROGATE((s)[(i)++])) { \
+        ++(i); \
+    } \
+}
+
+/** @deprecated ICU 2.4. Renamed to U16_FWD_N_UNSAFE, see utf_old.h. */
+#define UTF16_FWD_N_UNSAFE(s, i, n) { \
+    int32_t __N=(n); \
+    while(__N>0) { \
+        UTF16_FWD_1_UNSAFE(s, i); \
+        --__N; \
+    } \
+}
+
+/** @deprecated ICU 2.4. Renamed to U16_SET_CP_START_UNSAFE, see utf_old.h. */
+#define UTF16_SET_CHAR_START_UNSAFE(s, i) { \
+    if(UTF_IS_SECOND_SURROGATE((s)[i])) { \
+        --(i); \
+    } \
+}
+
+/** @deprecated ICU 2.4. Use U16_NEXT instead, see utf_old.h. */
+#define UTF16_NEXT_CHAR_SAFE(s, i, length, c, strict) { \
+    (c)=(s)[(i)++]; \
+    if(UTF_IS_FIRST_SURROGATE(c)) { \
+        uint16_t __c2; \
+        if((i)<(length) && UTF_IS_SECOND_SURROGATE(__c2=(s)[(i)])) { \
+            ++(i); \
+            (c)=UTF16_GET_PAIR_VALUE((c), __c2); \
+            /* strict: ((c)&0xfffe)==0xfffe is caught by UTF_IS_ERROR() and UTF_IS_UNICODE_CHAR() */ \
+        } else if(strict) {\
+            /* unmatched first surrogate */ \
+            (c)=UTF_ERROR_VALUE; \
+        } \
+    } else if((strict) && !UTF_IS_UNICODE_CHAR(c)) { \
+        /* unmatched second surrogate or other non-character */ \
+        (c)=UTF_ERROR_VALUE; \
+    } \
+}
+
+/** @deprecated ICU 2.4. Use U16_APPEND instead, see utf_old.h. */
+#define UTF16_APPEND_CHAR_SAFE(s, i, length, c) { \
+    if((uint32_t)(c)<=0xffff) { \
+        (s)[(i)++]=(uint16_t)(c); \
+    } else if((uint32_t)(c)<=0x10ffff) { \
+        if((i)+1<(length)) { \
+            (s)[(i)++]=(uint16_t)(((c)>>10)+0xd7c0); \
+            (s)[(i)++]=(uint16_t)(((c)&0x3ff)|0xdc00); \
+        } else /* not enough space */ { \
+            (s)[(i)++]=UTF_ERROR_VALUE; \
+        } \
+    } else /* c>0x10ffff, write error value */ { \
+        (s)[(i)++]=UTF_ERROR_VALUE; \
+    } \
+}
+
+/** @deprecated ICU 2.4. Renamed to U16_FWD_1, see utf_old.h. */
+#define UTF16_FWD_1_SAFE(s, i, length) U16_FWD_1(s, i, length)
+
+/** @deprecated ICU 2.4. Renamed to U16_FWD_N, see utf_old.h. */
+#define UTF16_FWD_N_SAFE(s, i, length, n) U16_FWD_N(s, i, length, n)
+
+/** @deprecated ICU 2.4. Renamed to U16_SET_CP_START, see utf_old.h. */
+#define UTF16_SET_CHAR_START_SAFE(s, start, i) U16_SET_CP_START(s, start, i)
+
+/** @deprecated ICU 2.4. Renamed to U16_PREV_UNSAFE, see utf_old.h. */
+#define UTF16_PREV_CHAR_UNSAFE(s, i, c) { \
+    (c)=(s)[--(i)]; \
+    if(UTF_IS_SECOND_SURROGATE(c)) { \
+        (c)=UTF16_GET_PAIR_VALUE((s)[--(i)], (c)); \
+    } \
+}
+
+/** @deprecated ICU 2.4. Renamed to U16_BACK_1_UNSAFE, see utf_old.h. */
+#define UTF16_BACK_1_UNSAFE(s, i) { \
+    if(UTF_IS_SECOND_SURROGATE((s)[--(i)])) { \
+        --(i); \
+    } \
+}
+
+/** @deprecated ICU 2.4. Renamed to U16_BACK_N_UNSAFE, see utf_old.h. */
+#define UTF16_BACK_N_UNSAFE(s, i, n) { \
+    int32_t __N=(n); \
+    while(__N>0) { \
+        UTF16_BACK_1_UNSAFE(s, i); \
+        --__N; \
+    } \
+}
+
+/** @deprecated ICU 2.4. Renamed to U16_SET_CP_LIMIT_UNSAFE, see utf_old.h. */
+#define UTF16_SET_CHAR_LIMIT_UNSAFE(s, i) { \
+    if(UTF_IS_FIRST_SURROGATE((s)[(i)-1])) { \
+        ++(i); \
+    } \
+}
+
+/** @deprecated ICU 2.4. Use U16_PREV instead, see utf_old.h. */
+#define UTF16_PREV_CHAR_SAFE(s, start, i, c, strict) { \
+    (c)=(s)[--(i)]; \
+    if(UTF_IS_SECOND_SURROGATE(c)) { \
+        uint16_t __c2; \
+        if((i)>(start) && UTF_IS_FIRST_SURROGATE(__c2=(s)[(i)-1])) { \
+            --(i); \
+            (c)=UTF16_GET_PAIR_VALUE(__c2, (c)); \
+            /* strict: ((c)&0xfffe)==0xfffe is caught by UTF_IS_ERROR() and UTF_IS_UNICODE_CHAR() */ \
+        } else if(strict) {\
+            /* unmatched second surrogate */ \
+            (c)=UTF_ERROR_VALUE; \
+        } \
+    } else if((strict) && !UTF_IS_UNICODE_CHAR(c)) { \
+        /* unmatched first surrogate or other non-character */ \
+        (c)=UTF_ERROR_VALUE; \
+    } \
+}
+
+/** @deprecated ICU 2.4. Renamed to U16_BACK_1, see utf_old.h. */
+#define UTF16_BACK_1_SAFE(s, start, i) U16_BACK_1(s, start, i)
+
+/** @deprecated ICU 2.4. Renamed to U16_BACK_N, see utf_old.h. */
+#define UTF16_BACK_N_SAFE(s, start, i, n) U16_BACK_N(s, start, i, n)
+
+/** @deprecated ICU 2.4. Renamed to U16_SET_CP_LIMIT, see utf_old.h. */
+#define UTF16_SET_CHAR_LIMIT_SAFE(s, start, i, length) U16_SET_CP_LIMIT(s, start, i, length)
+
+/* Formerly utf32.h --------------------------------------------------------- */
+
+/*
+* Old documentation:
+*
+*   This file defines macros to deal with UTF-32 code units and code points.
+*   Signatures and semantics are the same as for the similarly named macros
+*   in utf16.h.
+*   utf32.h is included by utf.h after unicode/umachine.h</p>
+*   and some common definitions.
+*   <p><b>Usage:</b>  ICU coding guidelines for if() statements should be followed when using these macros.
+*                  Compound statements (curly braces {}) must be used  for if-else-while...
+*                  bodies and all macro statements should be terminated with semicolon.</p>
+*/
+
+/* internal definitions ----------------------------------------------------- */
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_IS_SAFE(c, strict) \
+    (!(strict) ? \
+        (uint32_t)(c)<=0x10ffff : \
+        UTF_IS_UNICODE_CHAR(c))
+
+/*
+ * For the semantics of all of these macros, see utf16.h.
+ * The UTF-32 versions are trivial because any code point is
+ * encoded using exactly one code unit.
+ */
+
+/* single-code point definitions -------------------------------------------- */
+
+/* classes of code unit values */
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_IS_SINGLE(uchar) 1
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_IS_LEAD(uchar) 0
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_IS_TRAIL(uchar) 0
+
+/* number of code units per code point */
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_NEED_MULTIPLE_UCHAR(c) 0
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_CHAR_LENGTH(c) 1
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_MAX_CHAR_LENGTH 1
+
+/* average number of code units compared to UTF-16 */
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_ARRAY_SIZE(size) (size)
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_GET_CHAR_UNSAFE(s, i, c) { \
+    (c)=(s)[i]; \
+}
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_GET_CHAR_SAFE(s, start, i, length, c, strict) { \
+    (c)=(s)[i]; \
+    if(!UTF32_IS_SAFE(c, strict)) { \
+        (c)=UTF_ERROR_VALUE; \
+    } \
+}
+
+/* definitions with forward iteration --------------------------------------- */
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_NEXT_CHAR_UNSAFE(s, i, c) { \
+    (c)=(s)[(i)++]; \
+}
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_APPEND_CHAR_UNSAFE(s, i, c) { \
+    (s)[(i)++]=(c); \
+}
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_FWD_1_UNSAFE(s, i) { \
+    ++(i); \
+}
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_FWD_N_UNSAFE(s, i, n) { \
+    (i)+=(n); \
+}
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_SET_CHAR_START_UNSAFE(s, i) { \
+}
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_NEXT_CHAR_SAFE(s, i, length, c, strict) { \
+    (c)=(s)[(i)++]; \
+    if(!UTF32_IS_SAFE(c, strict)) { \
+        (c)=UTF_ERROR_VALUE; \
+    } \
+}
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_APPEND_CHAR_SAFE(s, i, length, c) { \
+    if((uint32_t)(c)<=0x10ffff) { \
+        (s)[(i)++]=(c); \
+    } else /* c>0x10ffff, write 0xfffd */ { \
+        (s)[(i)++]=0xfffd; \
+    } \
+}
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_FWD_1_SAFE(s, i, length) { \
+    ++(i); \
+}
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_FWD_N_SAFE(s, i, length, n) { \
+    if(((i)+=(n))>(length)) { \
+        (i)=(length); \
+    } \
+}
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_SET_CHAR_START_SAFE(s, start, i) { \
+}
+
+/* definitions with backward iteration -------------------------------------- */
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_PREV_CHAR_UNSAFE(s, i, c) { \
+    (c)=(s)[--(i)]; \
+}
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_BACK_1_UNSAFE(s, i) { \
+    --(i); \
+}
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_BACK_N_UNSAFE(s, i, n) { \
+    (i)-=(n); \
+}
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_SET_CHAR_LIMIT_UNSAFE(s, i) { \
+}
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_PREV_CHAR_SAFE(s, start, i, c, strict) { \
+    (c)=(s)[--(i)]; \
+    if(!UTF32_IS_SAFE(c, strict)) { \
+        (c)=UTF_ERROR_VALUE; \
+    } \
+}
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_BACK_1_SAFE(s, start, i) { \
+    --(i); \
+}
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_BACK_N_SAFE(s, start, i, n) { \
+    (i)-=(n); \
+    if((i)<(start)) { \
+        (i)=(start); \
+    } \
+}
+
+/** @deprecated ICU 2.4. Obsolete, see utf_old.h. */
+#define UTF32_SET_CHAR_LIMIT_SAFE(s, i, length) { \
+}
+
+/* Formerly utf.h, part 2 --------------------------------------------------- */
+
+/**
+ * Estimate the number of code units for a string based on the number of UTF-16 code units.
+ *
+ * @deprecated ICU 2.4. Obsolete, see utf_old.h.
+ */
+#define UTF_ARRAY_SIZE(size) UTF16_ARRAY_SIZE(size)
+
+/** @deprecated ICU 2.4. Renamed to U16_GET_UNSAFE, see utf_old.h. */
+#define UTF_GET_CHAR_UNSAFE(s, i, c)                 UTF16_GET_CHAR_UNSAFE(s, i, c)
+
+/** @deprecated ICU 2.4. Use U16_GET instead, see utf_old.h. */
+#define UTF_GET_CHAR_SAFE(s, start, i, length, c, strict) UTF16_GET_CHAR_SAFE(s, start, i, length, c, strict)
+
+
+/** @deprecated ICU 2.4. Renamed to U16_NEXT_UNSAFE, see utf_old.h. */
+#define UTF_NEXT_CHAR_UNSAFE(s, i, c)                UTF16_NEXT_CHAR_UNSAFE(s, i, c)
+
+/** @deprecated ICU 2.4. Use U16_NEXT instead, see utf_old.h. */
+#define UTF_NEXT_CHAR_SAFE(s, i, length, c, strict)  UTF16_NEXT_CHAR_SAFE(s, i, length, c, strict)
+
+
+/** @deprecated ICU 2.4. Renamed to U16_APPEND_UNSAFE, see utf_old.h. */
+#define UTF_APPEND_CHAR_UNSAFE(s, i, c)              UTF16_APPEND_CHAR_UNSAFE(s, i, c)
+
+/** @deprecated ICU 2.4. Use U16_APPEND instead, see utf_old.h. */
+#define UTF_APPEND_CHAR_SAFE(s, i, length, c)        UTF16_APPEND_CHAR_SAFE(s, i, length, c)
+
+
+/** @deprecated ICU 2.4. Renamed to U16_FWD_1_UNSAFE, see utf_old.h. */
+#define UTF_FWD_1_UNSAFE(s, i)                       UTF16_FWD_1_UNSAFE(s, i)
+
+/** @deprecated ICU 2.4. Renamed to U16_FWD_1, see utf_old.h. */
+#define UTF_FWD_1_SAFE(s, i, length)                 UTF16_FWD_1_SAFE(s, i, length)
+
+
+/** @deprecated ICU 2.4. Renamed to U16_FWD_N_UNSAFE, see utf_old.h. */
+#define UTF_FWD_N_UNSAFE(s, i, n)                    UTF16_FWD_N_UNSAFE(s, i, n)
+
+/** @deprecated ICU 2.4. Renamed to U16_FWD_N, see utf_old.h. */
+#define UTF_FWD_N_SAFE(s, i, length, n)              UTF16_FWD_N_SAFE(s, i, length, n)
+
+
+/** @deprecated ICU 2.4. Renamed to U16_SET_CP_START_UNSAFE, see utf_old.h. */
+#define UTF_SET_CHAR_START_UNSAFE(s, i)              UTF16_SET_CHAR_START_UNSAFE(s, i)
+
+/** @deprecated ICU 2.4. Renamed to U16_SET_CP_START, see utf_old.h. */
+#define UTF_SET_CHAR_START_SAFE(s, start, i)         UTF16_SET_CHAR_START_SAFE(s, start, i)
+
+
+/** @deprecated ICU 2.4. Renamed to U16_PREV_UNSAFE, see utf_old.h. */
+#define UTF_PREV_CHAR_UNSAFE(s, i, c)                UTF16_PREV_CHAR_UNSAFE(s, i, c)
+
+/** @deprecated ICU 2.4. Use U16_PREV instead, see utf_old.h. */
+#define UTF_PREV_CHAR_SAFE(s, start, i, c, strict)   UTF16_PREV_CHAR_SAFE(s, start, i, c, strict)
+
+
+/** @deprecated ICU 2.4. Renamed to U16_BACK_1_UNSAFE, see utf_old.h. */
+#define UTF_BACK_1_UNSAFE(s, i)                      UTF16_BACK_1_UNSAFE(s, i)
+
+/** @deprecated ICU 2.4. Renamed to U16_BACK_1, see utf_old.h. */
+#define UTF_BACK_1_SAFE(s, start, i)                 UTF16_BACK_1_SAFE(s, start, i)
+
+
+/** @deprecated ICU 2.4. Renamed to U16_BACK_N_UNSAFE, see utf_old.h. */
+#define UTF_BACK_N_UNSAFE(s, i, n)                   UTF16_BACK_N_UNSAFE(s, i, n)
+
+/** @deprecated ICU 2.4. Renamed to U16_BACK_N, see utf_old.h. */
+#define UTF_BACK_N_SAFE(s, start, i, n)              UTF16_BACK_N_SAFE(s, start, i, n)
+
+
+/** @deprecated ICU 2.4. Renamed to U16_SET_CP_LIMIT_UNSAFE, see utf_old.h. */
+#define UTF_SET_CHAR_LIMIT_UNSAFE(s, i)              UTF16_SET_CHAR_LIMIT_UNSAFE(s, i)
+
+/** @deprecated ICU 2.4. Renamed to U16_SET_CP_LIMIT, see utf_old.h. */
+#define UTF_SET_CHAR_LIMIT_SAFE(s, start, i, length) UTF16_SET_CHAR_LIMIT_SAFE(s, start, i, length)
+
+/* Define default macros (UTF-16 "safe") ------------------------------------ */
+
+/**
+ * Does this code unit alone encode a code point (BMP, not a surrogate)?
+ * Same as UTF16_IS_SINGLE.
+ * @deprecated ICU 2.4. Renamed to U_IS_SINGLE and U16_IS_SINGLE, see utf_old.h.
+ */
+#define UTF_IS_SINGLE(uchar) U16_IS_SINGLE(uchar)
+
+/**
+ * Is this code unit the first one of several (a lead surrogate)?
+ * Same as UTF16_IS_LEAD.
+ * @deprecated ICU 2.4. Renamed to U_IS_LEAD and U16_IS_LEAD, see utf_old.h.
+ */
+#define UTF_IS_LEAD(uchar) U16_IS_LEAD(uchar)
+
+/**
+ * Is this code unit one of several but not the first one (a trail surrogate)?
+ * Same as UTF16_IS_TRAIL.
+ * @deprecated ICU 2.4. Renamed to U_IS_TRAIL and U16_IS_TRAIL, see utf_old.h.
+ */
+#define UTF_IS_TRAIL(uchar) U16_IS_TRAIL(uchar)
+
+/**
+ * Does this code point require multiple code units (is it a supplementary code point)?
+ * Same as UTF16_NEED_MULTIPLE_UCHAR.
+ * @deprecated ICU 2.4. Use U16_LENGTH or test ((uint32_t)(c)>0xffff) instead.
+ */
+#define UTF_NEED_MULTIPLE_UCHAR(c) UTF16_NEED_MULTIPLE_UCHAR(c)
+
+/**
+ * How many code units are used to encode this code point (1 or 2)?
+ * Same as UTF16_CHAR_LENGTH.
+ * @deprecated ICU 2.4. Renamed to U16_LENGTH, see utf_old.h.
+ */
+#define UTF_CHAR_LENGTH(c) U16_LENGTH(c)
+
+/**
+ * How many code units are used at most for any Unicode code point (2)?
+ * Same as UTF16_MAX_CHAR_LENGTH.
+ * @deprecated ICU 2.4. Renamed to U16_MAX_LENGTH, see utf_old.h.
+ */
+#define UTF_MAX_CHAR_LENGTH U16_MAX_LENGTH
+
+/**
+ * Set c to the code point that contains the code unit i.
+ * i could point to the lead or the trail surrogate for the code point.
+ * i is not modified.
+ * Same as UTF16_GET_CHAR.
+ * \pre 0<=i<length
+ *
+ * @deprecated ICU 2.4. Renamed to U16_GET, see utf_old.h.
+ */
+#define UTF_GET_CHAR(s, start, i, length, c) U16_GET(s, start, i, length, c)
+
+/**
+ * Set c to the code point that starts at code unit i
+ * and advance i to beyond the code units of this code point (post-increment).
+ * i must point to the first code unit of a code point.
+ * Otherwise c is set to the trail unit (surrogate) itself.
+ * Same as UTF16_NEXT_CHAR.
+ * \pre 0<=i<length
+ * \post 0<i<=length
+ *
+ * @deprecated ICU 2.4. Renamed to U16_NEXT, see utf_old.h.
+ */
+#define UTF_NEXT_CHAR(s, i, length, c) U16_NEXT(s, i, length, c)
+
+/**
+ * Append the code units of code point c to the string at index i
+ * and advance i to beyond the new code units (post-increment).
+ * The code units beginning at index i will be overwritten.
+ * Same as UTF16_APPEND_CHAR.
+ * \pre 0<=c<=0x10ffff
+ * \pre 0<=i<length
+ * \post 0<i<=length
+ *
+ * @deprecated ICU 2.4. Use U16_APPEND instead, see utf_old.h.
+ */
+#define UTF_APPEND_CHAR(s, i, length, c) UTF16_APPEND_CHAR_SAFE(s, i, length, c)
+
+/**
+ * Advance i to beyond the code units of the code point that begins at i.
+ * I.e., advance i by one code point.
+ * Same as UTF16_FWD_1.
+ * \pre 0<=i<length
+ * \post 0<i<=length
+ *
+ * @deprecated ICU 2.4. Renamed to U16_FWD_1, see utf_old.h.
+ */
+#define UTF_FWD_1(s, i, length) U16_FWD_1(s, i, length)
+
+/**
+ * Advance i to beyond the code units of the n code points where the first one begins at i.
+ * I.e., advance i by n code points.
+ * Same as UT16_FWD_N.
+ * \pre 0<=i<length
+ * \post 0<i<=length
+ *
+ * @deprecated ICU 2.4. Renamed to U16_FWD_N, see utf_old.h.
+ */
+#define UTF_FWD_N(s, i, length, n) U16_FWD_N(s, i, length, n)
+
+/**
+ * Take the random-access index i and adjust it so that it points to the beginning
+ * of a code point.
+ * The input index points to any code unit of a code point and is moved to point to
+ * the first code unit of the same code point. i is never incremented.
+ * In other words, if i points to a trail surrogate that is preceded by a matching
+ * lead surrogate, then i is decremented. Otherwise it is not modified.
+ * This can be used to start an iteration with UTF_NEXT_CHAR() from a random index.
+ * Same as UTF16_SET_CHAR_START.
+ * \pre start<=i<length
+ * \post start<=i<length
+ *
+ * @deprecated ICU 2.4. Renamed to U16_SET_CP_START, see utf_old.h.
+ */
+#define UTF_SET_CHAR_START(s, start, i) U16_SET_CP_START(s, start, i)
+
+/**
+ * Set c to the code point that has code units before i
+ * and move i backward (towards the beginning of the string)
+ * to the first code unit of this code point (pre-increment).
+ * i must point to the first code unit after the last unit of a code point (i==length is allowed).
+ * Same as UTF16_PREV_CHAR.
+ * \pre start<i<=length
+ * \post start<=i<length
+ *
+ * @deprecated ICU 2.4. Renamed to U16_PREV, see utf_old.h.
+ */
+#define UTF_PREV_CHAR(s, start, i, c) U16_PREV(s, start, i, c)
+
+/**
+ * Move i backward (towards the beginning of the string)
+ * to the first code unit of the code point that has code units before i.
+ * I.e., move i backward by one code point.
+ * i must point to the first code unit after the last unit of a code point (i==length is allowed).
+ * Same as UTF16_BACK_1.
+ * \pre start<i<=length
+ * \post start<=i<length
+ *
+ * @deprecated ICU 2.4. Renamed to U16_BACK_1, see utf_old.h.
+ */
+#define UTF_BACK_1(s, start, i) U16_BACK_1(s, start, i)
+
+/**
+ * Move i backward (towards the beginning of the string)
+ * to the first code unit of the n code points that have code units before i.
+ * I.e., move i backward by n code points.
+ * i must point to the first code unit after the last unit of a code point (i==length is allowed).
+ * Same as UTF16_BACK_N.
+ * \pre start<i<=length
+ * \post start<=i<length
+ *
+ * @deprecated ICU 2.4. Renamed to U16_BACK_N, see utf_old.h.
+ */
+#define UTF_BACK_N(s, start, i, n) U16_BACK_N(s, start, i, n)
+
+/**
+ * Take the random-access index i and adjust it so that it points beyond
+ * a code point. The input index points beyond any code unit
+ * of a code point and is moved to point beyond the last code unit of the same
+ * code point. i is never decremented.
+ * In other words, if i points to a trail surrogate that is preceded by a matching
+ * lead surrogate, then i is incremented. Otherwise it is not modified.
+ * This can be used to start an iteration with UTF_PREV_CHAR() from a random index.
+ * Same as UTF16_SET_CHAR_LIMIT.
+ * \pre start<i<=length
+ * \post start<i<=length
+ *
+ * @deprecated ICU 2.4. Renamed to U16_SET_CP_LIMIT, see utf_old.h.
+ */
+#define UTF_SET_CHAR_LIMIT(s, start, i, length) U16_SET_CP_LIMIT(s, start, i, length)
+
+#endif /* U_HIDE_DEPRECATED_API */
+
+#endif
+
diff --git a/source/common/unicode/utrace.h b/source/common/unicode/utrace.h
new file mode 100644
index 0000000..3c8be9f
--- /dev/null
+++ b/source/common/unicode/utrace.h
@@ -0,0 +1,358 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2003-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  utrace.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2003aug06
+*   created by: Markus W. Scherer
+*
+*   Definitions for ICU tracing/logging.
+*
+*/
+
+#ifndef __UTRACE_H__
+#define __UTRACE_H__
+
+#include <stdarg.h>
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C API:  Definitions for ICU tracing/logging. 
+ *
+ * This provides API for debugging the internals of ICU without the use of
+ * a traditional debugger.
+ *
+ * By default, tracing is disabled in ICU. If you need to debug ICU with 
+ * tracing, please compile ICU with the --enable-tracing configure option.
+ */
+ 
+U_CDECL_BEGIN
+
+/**
+ * Trace severity levels.  Higher levels increase the verbosity of the trace output.
+ * @see utrace_setLevel
+ * @stable ICU 2.8
+ */
+typedef enum UTraceLevel {
+    /** Disable all tracing  @stable ICU 2.8*/
+    UTRACE_OFF=-1,
+    /** Trace error conditions only  @stable ICU 2.8*/
+    UTRACE_ERROR=0,
+    /** Trace errors and warnings  @stable ICU 2.8*/
+    UTRACE_WARNING=3,
+    /** Trace opens and closes of ICU services  @stable ICU 2.8*/
+    UTRACE_OPEN_CLOSE=5,
+    /** Trace an intermediate number of ICU operations  @stable ICU 2.8*/
+    UTRACE_INFO=7,
+    /** Trace the maximum number of ICU operations  @stable ICU 2.8*/
+    UTRACE_VERBOSE=9
+} UTraceLevel;
+
+/**
+ *  These are the ICU functions that will be traced when tracing is enabled.
+ *  @stable ICU 2.8
+ */
+typedef enum UTraceFunctionNumber {
+    UTRACE_FUNCTION_START=0,
+    UTRACE_U_INIT=UTRACE_FUNCTION_START,
+    UTRACE_U_CLEANUP,
+    UTRACE_FUNCTION_LIMIT,
+
+    UTRACE_CONVERSION_START=0x1000,
+    UTRACE_UCNV_OPEN=UTRACE_CONVERSION_START,
+    UTRACE_UCNV_OPEN_PACKAGE,
+    UTRACE_UCNV_OPEN_ALGORITHMIC,
+    UTRACE_UCNV_CLONE,
+    UTRACE_UCNV_CLOSE,
+    UTRACE_UCNV_FLUSH_CACHE,
+    UTRACE_UCNV_LOAD,
+    UTRACE_UCNV_UNLOAD,
+    UTRACE_CONVERSION_LIMIT,
+
+    UTRACE_COLLATION_START=0x2000,
+    UTRACE_UCOL_OPEN=UTRACE_COLLATION_START,
+    UTRACE_UCOL_CLOSE,
+    UTRACE_UCOL_STRCOLL,
+    UTRACE_UCOL_GET_SORTKEY,
+    UTRACE_UCOL_GETLOCALE,
+    UTRACE_UCOL_NEXTSORTKEYPART,
+    UTRACE_UCOL_STRCOLLITER,
+    UTRACE_UCOL_OPEN_FROM_SHORT_STRING,
+    UTRACE_COLLATION_LIMIT
+} UTraceFunctionNumber;
+
+/**
+ * Setter for the trace level.
+ * @param traceLevel A UTraceLevel value.
+ * @stable ICU 2.8
+ */
+U_STABLE void U_EXPORT2
+utrace_setLevel(int32_t traceLevel);
+
+/**
+ * Getter for the trace level.
+ * @return The UTraceLevel value being used by ICU.
+ * @stable ICU 2.8
+ */
+U_STABLE int32_t U_EXPORT2
+utrace_getLevel(void);
+
+/* Trace function pointers types  ----------------------------- */
+
+/**
+  *  Type signature for the trace function to be called when entering a function.
+  *  @param context value supplied at the time the trace functions are set.
+  *  @param fnNumber Enum value indicating the ICU function being entered.
+  *  @stable ICU 2.8
+  */
+typedef void U_CALLCONV
+UTraceEntry(const void *context, int32_t fnNumber);
+
+/**
+  *  Type signature for the trace function to be called when exiting from a function.
+  *  @param context value supplied at the time the trace functions are set.
+  *  @param fnNumber Enum value indicating the ICU function being exited.
+  *  @param fmt     A formatting string that describes the number and types
+  *                 of arguments included with the variable args.  The fmt
+  *                 string has the same form as the utrace_vformat format
+  *                 string.
+  *  @param args    A variable arguments list.  Contents are described by
+  *                 the fmt parameter.
+  *  @see   utrace_vformat
+  *  @stable ICU 2.8
+  */
+typedef void U_CALLCONV
+UTraceExit(const void *context, int32_t fnNumber, 
+           const char *fmt, va_list args);
+
+/**
+  *  Type signature for the trace function to be called from within an ICU function
+  *  to display data or messages.
+  *  @param context  value supplied at the time the trace functions are set.
+  *  @param fnNumber Enum value indicating the ICU function being exited.
+  *  @param level    The current tracing level
+  *  @param fmt      A format string describing the tracing data that is supplied
+  *                  as variable args
+  *  @param args     The data being traced, passed as variable args.
+  *  @stable ICU 2.8
+  */
+typedef void U_CALLCONV
+UTraceData(const void *context, int32_t fnNumber, int32_t level,
+           const char *fmt, va_list args);
+
+/**
+  *  Set ICU Tracing functions.  Installs application-provided tracing
+  *  functions into ICU.  After doing this, subsequent ICU operations
+  *  will call back to the installed functions, providing a trace
+  *  of the use of ICU.  Passing a NULL pointer for a tracing function
+  *  is allowed, and inhibits tracing action at points where that function
+  *  would be called.
+  *  <p>
+  *  Tracing and Threads:  Tracing functions are global to a process, and
+  *  will be called in response to ICU operations performed by any
+  *  thread.  If tracing of an individual thread is desired, the
+  *  tracing functions must themselves filter by checking that the
+  *  current thread is the desired thread.
+  *
+  *  @param context an uninterpretted pointer.  Whatever is passed in
+  *                 here will in turn be passed to each of the tracing
+  *                 functions UTraceEntry, UTraceExit and UTraceData.
+  *                 ICU does not use or alter this pointer.
+  *  @param e       Callback function to be called on entry to a 
+  *                 a traced ICU function.
+  *  @param x       Callback function to be called on exit from a
+  *                 traced ICU function.
+  *  @param d       Callback function to be called from within a 
+  *                 traced ICU function, for the purpose of providing
+  *                 data to the trace.
+  *
+  *  @stable ICU 2.8
+  */
+U_STABLE void U_EXPORT2
+utrace_setFunctions(const void *context,
+                    UTraceEntry *e, UTraceExit *x, UTraceData *d);
+
+/**
+  * Get the currently installed ICU tracing functions.   Note that a null function
+  *   pointer will be returned if no trace function has been set.
+  *
+  * @param context  The currently installed tracing context.
+  * @param e        The currently installed UTraceEntry function.
+  * @param x        The currently installed UTraceExit function.
+  * @param d        The currently installed UTraceData function.
+  * @stable ICU 2.8
+  */
+U_STABLE void U_EXPORT2
+utrace_getFunctions(const void **context,
+                    UTraceEntry **e, UTraceExit **x, UTraceData **d);
+
+
+
+/*
+ *
+ * ICU trace format string syntax
+ *
+ * Format Strings are passed to UTraceData functions, and define the
+ * number and types of the trace data being passed on each call.
+ *
+ * The UTraceData function, which is supplied by the application,
+ * not by ICU, can either forward the trace data (passed via
+ * varargs) and the format string back to ICU for formatting into
+ * a displayable string, or it can interpret the format itself,
+ * and do as it wishes with the trace data.
+ *
+ *
+ * Goals for the format string
+ * - basic data output
+ * - easy to use for trace programmer
+ * - sufficient provision for data types for trace output readability
+ * - well-defined types and binary portable APIs
+ *
+ * Non-goals
+ * - printf compatibility
+ * - fancy formatting
+ * - argument reordering and other internationalization features
+ *
+ * ICU trace format strings contain plain text with argument inserts,
+ * much like standard printf format strings.
+ * Each insert begins with a '%', then optionally contains a 'v',
+ * then exactly one type character.
+ * Two '%' in a row represent a '%' instead of an insert.
+ * The trace format strings need not have \n at the end.
+ *
+ *
+ * Types
+ * -----
+ *
+ * Type characters:
+ * - c A char character in the default codepage.
+ * - s A NUL-terminated char * string in the default codepage.
+ * - S A UChar * string.  Requires two params, (ptr, length).  Length=-1 for nul term.
+ * - b A byte (8-bit integer).
+ * - h A 16-bit integer.  Also a 16 bit Unicode code unit.
+ * - d A 32-bit integer.  Also a 20 bit Unicode code point value. 
+ * - l A 64-bit integer.
+ * - p A data pointer.
+ *
+ * Vectors
+ * -------
+ *
+ * If the 'v' is not specified, then one item of the specified type
+ * is passed in.
+ * If the 'v' (for "vector") is specified, then a vector of items of the
+ * specified type is passed in, via a pointer to the first item
+ * and an int32_t value for the length of the vector.
+ * Length==-1 means zero or NUL termination.  Works for vectors of all types.
+ *
+ * Note:  %vS is a vector of (UChar *) strings.  The strings must
+ *        be nul terminated as there is no way to provide a
+ *        separate length parameter for each string.  The length
+ *        parameter (required for all vectors) is the number of
+ *        strings, not the length of the strings.
+ *
+ * Examples
+ * --------
+ *
+ * These examples show the parameters that will be passed to an application's
+ *   UTraceData() function for various formats.
+ *
+ * - the precise formatting is up to the application!
+ * - the examples use type casts for arguments only to _show_ the types of
+ *   arguments without needing variable declarations in the examples;
+ *   the type casts will not be necessary in actual code
+ *
+ * UTraceDataFunc(context, fnNumber, level,
+ *              "There is a character %c in the string %s.",   // Format String 
+ *              (char)c, (const char *)s);                     // varargs parameters
+ * ->   There is a character 0x42 'B' in the string "Bravo".
+ *
+ * UTraceDataFunc(context, fnNumber, level,
+ *              "Vector of bytes %vb vector of chars %vc",
+ *              (const uint8_t *)bytes, (int32_t)bytesLength,
+ *              (const char *)chars, (int32_t)charsLength);
+ * ->  Vector of bytes
+ *      42 63 64 3f [4]
+ *     vector of chars
+ *      "Bcd?"[4]
+ *
+ * UTraceDataFunc(context, fnNumber, level,
+ *              "An int32_t %d and a whole bunch of them %vd",
+ *              (int32_t)-5, (const int32_t *)ints, (int32_t)intsLength);
+ * ->   An int32_t 0xfffffffb and a whole bunch of them
+ *      fffffffb 00000005 0000010a [3]
+ *
+ */
+
+
+
+/**
+  *  Trace output Formatter.  An application's UTraceData tracing functions may call
+  *                 back to this function to format the trace output in a
+  *                 human readable form.  Note that a UTraceData function may choose
+  *                 to not format the data;  it could, for example, save it in
+  *                 in the raw form it was received (more compact), leaving
+  *                 formatting for a later trace analyis tool.
+  *  @param outBuf  pointer to a buffer to receive the formatted output.  Output
+  *                 will be nul terminated if there is space in the buffer -
+  *                 if the length of the requested output < the output buffer size.
+  *  @param capacity  Length of the output buffer.
+  *  @param indent  Number of spaces to indent the output.  Intended to allow
+  *                 data displayed from nested functions to be indented for readability.
+  *  @param fmt     Format specification for the data to output
+  *  @param args    Data to be formatted.
+  *  @return        Length of formatted output, including the terminating NUL.
+  *                 If buffer capacity is insufficient, the required capacity is returned. 
+  *  @stable ICU 2.8
+  */
+U_STABLE int32_t U_EXPORT2
+utrace_vformat(char *outBuf, int32_t capacity,
+              int32_t indent, const char *fmt,  va_list args);
+
+/**
+  *  Trace output Formatter.  An application's UTraceData tracing functions may call
+  *                 this function to format any additional trace data, beyond that
+  *                 provided by default, in human readable form with the same
+  *                 formatting conventions used by utrace_vformat().
+  *  @param outBuf  pointer to a buffer to receive the formatted output.  Output
+  *                 will be nul terminated if there is space in the buffer -
+  *                 if the length of the requested output < the output buffer size.
+  *  @param capacity  Length of the output buffer.
+  *  @param indent  Number of spaces to indent the output.  Intended to allow
+  *                 data displayed from nested functions to be indented for readability.
+  *  @param fmt     Format specification for the data to output
+  *  @param ...     Data to be formatted.
+  *  @return        Length of formatted output, including the terminating NUL.
+  *                 If buffer capacity is insufficient, the required capacity is returned. 
+  *  @stable ICU 2.8
+  */
+U_STABLE int32_t U_EXPORT2
+utrace_format(char *outBuf, int32_t capacity,
+              int32_t indent, const char *fmt,  ...);
+
+
+
+/* Trace function numbers --------------------------------------------------- */
+
+/**
+ * Get the name of a function from its trace function number.
+ *
+ * @param fnNumber The trace number for an ICU function.
+ * @return The name string for the function.
+ *
+ * @see UTraceFunctionNumber
+ * @stable ICU 2.8
+ */
+U_STABLE const char * U_EXPORT2
+utrace_functionName(int32_t fnNumber);
+
+U_CDECL_END
+
+#endif
diff --git a/source/common/unicode/utypes.h b/source/common/unicode/utypes.h
new file mode 100644
index 0000000..beb931b
--- /dev/null
+++ b/source/common/unicode/utypes.h
@@ -0,0 +1,865 @@
+/*
+**********************************************************************
+*   Copyright (C) 1996-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*
+*  FILE NAME : UTYPES.H (formerly ptypes.h)
+*
+*   Date        Name        Description
+*   12/11/96    helena      Creation.
+*   02/27/97    aliu        Added typedefs for UClassID, int8, int16, int32,
+*                           uint8, uint16, and uint32.
+*   04/01/97    aliu        Added XP_CPLUSPLUS and modified to work under C as
+*                            well as C++.
+*                           Modified to use memcpy() for uprv_arrayCopy() fns.
+*   04/14/97    aliu        Added TPlatformUtilities.
+*   05/07/97    aliu        Added import/export specifiers (replacing the old
+*                           broken EXT_CLASS).  Added version number for our
+*                           code.  Cleaned up header.
+*    6/20/97    helena      Java class name change.
+*   08/11/98    stephen     UErrorCode changed from typedef to enum
+*   08/12/98    erm         Changed T_ANALYTIC_PACKAGE_VERSION to 3
+*   08/14/98    stephen     Added uprv_arrayCopy() for int8_t, int16_t, int32_t
+*   12/09/98    jfitz       Added BUFFER_OVERFLOW_ERROR (bug 1100066)
+*   04/20/99    stephen     Cleaned up & reworked for autoconf.
+*                           Renamed to utypes.h.
+*   05/05/99    stephen     Changed to use <inttypes.h>
+*   12/07/99    helena      Moved copyright notice string from ucnv_bld.h here.
+*******************************************************************************
+*/
+
+#ifndef UTYPES_H
+#define UTYPES_H
+
+
+#include "unicode/umachine.h"
+#include "unicode/utf.h"
+#include "unicode/uversion.h"
+#include "unicode/uconfig.h"
+
+/*!
+ * \file
+ * \brief Basic definitions for ICU, for both C and C++ APIs
+ *
+ * This file defines basic types, constants, and enumerations directly or
+ * indirectly by including other header files, especially utf.h for the
+ * basic character and string definitions and umachine.h for consistent
+ * integer and other types.
+ */
+
+
+/**
+ * \def U_SHOW_CPLUSPLUS_API
+ * @internal
+ */
+#ifdef XP_CPLUSPLUS
+#   ifndef U_SHOW_CPLUSPLUS_API
+#       define U_SHOW_CPLUSPLUS_API 1
+#   endif
+#else
+#   undef U_SHOW_CPLUSPLUS_API
+#   define U_SHOW_CPLUSPLUS_API 0
+#endif
+
+/** @{ API visibility control */
+
+/**
+ * \def U_HIDE_DRAFT_API
+ * Define this to 1 to request that draft API be "hidden"
+ */
+#if !U_DEFAULT_SHOW_DRAFT && !defined(U_SHOW_DRAFT_API)
+#define U_HIDE_DRAFT_API 1
+#endif
+#if !U_DEFAULT_SHOW_DRAFT && !defined(U_SHOW_INTERNAL_API)
+#define U_HIDE_INTERNAL_API 1
+#endif
+
+#ifdef U_HIDE_DRAFT_API
+#include "unicode/udraft.h"
+#endif
+
+#ifdef U_HIDE_DEPRECATED_API
+#include "unicode/udeprctd.h"
+#endif
+
+#ifdef U_HIDE_DEPRECATED_API
+#include "unicode/uobslete.h"
+#endif
+
+#ifdef U_HIDE_INTERNAL_API
+#include "unicode/uintrnal.h"
+#endif
+
+#ifdef U_HIDE_SYSTEM_API
+#include "unicode/usystem.h"
+#endif
+
+/** @} */
+
+
+/*===========================================================================*/
+/* char Character set family                                                 */
+/*===========================================================================*/
+
+/**
+ * U_CHARSET_FAMILY is equal to this value when the platform is an ASCII based platform.
+ * @stable ICU 2.0
+ */
+#define U_ASCII_FAMILY 0
+
+/**
+ * U_CHARSET_FAMILY is equal to this value when the platform is an EBCDIC based platform.
+ * @stable ICU 2.0
+ */
+#define U_EBCDIC_FAMILY 1
+
+/**
+ * \def U_CHARSET_FAMILY
+ *
+ * <p>These definitions allow to specify the encoding of text
+ * in the char data type as defined by the platform and the compiler.
+ * It is enough to determine the code point values of "invariant characters",
+ * which are the ones shared by all encodings that are in use
+ * on a given platform.</p>
+ *
+ * <p>Those "invariant characters" should be all the uppercase and lowercase
+ * latin letters, the digits, the space, and "basic punctuation".
+ * Also, '\\n', '\\r', '\\t' should be available.</p>
+ *
+ * <p>The list of "invariant characters" is:<br>
+ * \code
+ *    A-Z  a-z  0-9  SPACE  "  %  &amp;  '  (  )  *  +  ,  -  .  /  :  ;  <  =  >  ?  _
+ * \endcode
+ * <br>
+ * (52 letters + 10 numbers + 20 punc/sym/space = 82 total)</p>
+ *
+ * <p>This matches the IBM Syntactic Character Set (CS 640).</p>
+ *
+ * <p>In other words, all the graphic characters in 7-bit ASCII should
+ * be safely accessible except the following:</p>
+ *
+ * \code
+ *    '\' <backslash>
+ *    '[' <left bracket>
+ *    ']' <right bracket>
+ *    '{' <left brace>
+ *    '}' <right brace>
+ *    '^' <circumflex>
+ *    '~' <tilde>
+ *    '!' <exclamation mark>
+ *    '#' <number sign>
+ *    '|' <vertical line>
+ *    '$' <dollar sign>
+ *    '@' <commercial at>
+ *    '`' <grave accent>
+ * \endcode
+ * @stable ICU 2.0
+ */
+
+#ifndef U_CHARSET_FAMILY
+#   define U_CHARSET_FAMILY 0
+#endif
+
+/**
+ * \def U_CHARSET_IS_UTF8
+ *
+ * Hardcode the default charset to UTF-8.
+ *
+ * If this is set to 1, then
+ * - ICU will assume that all non-invariant char*, StringPiece, std::string etc.
+ *   contain UTF-8 text, regardless of what the system API uses
+ * - some ICU code will use fast functions like u_strFromUTF8()
+ *   rather than the more general and more heavy-weight conversion API (ucnv.h)
+ * - ucnv_getDefaultName() always returns "UTF-8"
+ * - ucnv_setDefaultName() is disabled and will not change the default charset
+ * - static builds of ICU are smaller
+ * - more functionality is available with the UCONFIG_NO_CONVERSION build-time
+ *   configuration option (see unicode/uconfig.h)
+ * - the UCONFIG_NO_CONVERSION build option in uconfig.h is more usable
+ *
+ * @stable ICU 4.2
+ * @see UCONFIG_NO_CONVERSION
+ */
+#ifndef U_CHARSET_IS_UTF8
+#   define U_CHARSET_IS_UTF8 0
+#endif
+
+/*===========================================================================*/
+/* ICUDATA naming scheme                                                     */
+/*===========================================================================*/
+
+/**
+ * \def U_ICUDATA_TYPE_LETTER
+ *
+ * This is a platform-dependent string containing one letter:
+ * - b for big-endian, ASCII-family platforms
+ * - l for little-endian, ASCII-family platforms
+ * - e for big-endian, EBCDIC-family platforms
+ * This letter is part of the common data file name.
+ * @stable ICU 2.0
+ */
+
+/**
+ * \def U_ICUDATA_TYPE_LITLETTER
+ * The non-string form of U_ICUDATA_TYPE_LETTER
+ * @stable ICU 2.0
+ */
+#if U_CHARSET_FAMILY
+#   if U_IS_BIG_ENDIAN
+   /* EBCDIC - should always be BE */
+#     define U_ICUDATA_TYPE_LETTER "e"
+#     define U_ICUDATA_TYPE_LITLETTER e
+#   else
+#     error "Don't know what to do with little endian EBCDIC!"
+#     define U_ICUDATA_TYPE_LETTER "x"
+#     define U_ICUDATA_TYPE_LITLETTER x
+#   endif
+#else
+#   if U_IS_BIG_ENDIAN
+      /* Big-endian ASCII */
+#     define U_ICUDATA_TYPE_LETTER "b"
+#     define U_ICUDATA_TYPE_LITLETTER b
+#   else
+      /* Little-endian ASCII */
+#     define U_ICUDATA_TYPE_LETTER "l"
+#     define U_ICUDATA_TYPE_LITLETTER l
+#   endif
+#endif
+
+/**
+ * A single string literal containing the icudata stub name. i.e. 'icudt18e' for
+ * ICU 1.8.x on EBCDIC, etc..
+ * @stable ICU 2.0
+ */
+#define U_ICUDATA_NAME    "icudt" U_ICU_VERSION_SHORT U_ICUDATA_TYPE_LETTER  /**< @internal */
+#define U_USRDATA_NAME    "usrdt" U_ICU_VERSION_SHORT U_ICUDATA_TYPE_LETTER  /**< @internal */
+#define U_USE_USRDATA     1  /**< @internal */
+
+/**
+ *  U_ICU_ENTRY_POINT is the name of the DLL entry point to the ICU data library.
+ *    Defined as a literal, not a string.
+ *    Tricky Preprocessor use - ## operator replaces macro paramters with the literal string
+ *                              from the corresponding macro invocation, _before_ other macro substitutions.
+ *                              Need a nested \#defines to get the actual version numbers rather than
+ *                              the literal text U_ICU_VERSION_MAJOR_NUM into the name.
+ *                              The net result will be something of the form
+ *                                  \#define U_ICU_ENTRY_POINT icudt19_dat
+ * @stable ICU 2.4
+ */
+#define U_ICUDATA_ENTRY_POINT  U_DEF2_ICUDATA_ENTRY_POINT(U_ICU_VERSION_MAJOR_NUM, U_ICU_VERSION_MINOR_NUM)
+
+/**
+ * Do not use.
+ * @internal
+ */
+#define U_DEF2_ICUDATA_ENTRY_POINT(major, minor) U_DEF_ICUDATA_ENTRY_POINT(major, minor)
+/**
+ * Do not use.
+ * @internal
+ */
+#ifndef U_DEF_ICUDATA_ENTRY_POINT
+/* affected by symbol renaming. See platform.h */
+#define U_DEF_ICUDATA_ENTRY_POINT(major, minor) icudt##major##minor##_dat
+#endif
+
+/**
+ * \def U_CALLCONV
+ * Similar to U_CDECL_BEGIN/U_CDECL_END, this qualifier is necessary
+ * in callback function typedefs to make sure that the calling convention
+ * is compatible.
+ *
+ * This is only used for non-ICU-API functions.
+ * When a function is a public ICU API,
+ * you must use the U_CAPI and U_EXPORT2 qualifiers.
+ * @stable ICU 2.0
+ */
+#if defined(OS390) && defined(XP_CPLUSPLUS)
+#    define U_CALLCONV __cdecl
+#else
+#    define U_CALLCONV U_EXPORT2
+#endif
+
+/**
+ * \def NULL
+ * Define NULL if necessary, to 0 for C++ and to ((void *)0) for C.
+ * @stable ICU 2.0
+ */
+#ifndef NULL
+#ifdef XP_CPLUSPLUS
+#define NULL    0
+#else
+#define NULL    ((void *)0)
+#endif
+#endif
+
+/*===========================================================================*/
+/* Calendar/TimeZone data types                                              */
+/*===========================================================================*/
+
+/**
+ * Date and Time data type.
+ * This is a primitive data type that holds the date and time
+ * as the number of milliseconds since 1970-jan-01, 00:00 UTC.
+ * UTC leap seconds are ignored.
+ * @stable ICU 2.0
+ */
+typedef double UDate;
+
+/** The number of milliseconds per second @stable ICU 2.0 */
+#define U_MILLIS_PER_SECOND        (1000)
+/** The number of milliseconds per minute @stable ICU 2.0 */
+#define U_MILLIS_PER_MINUTE       (60000)
+/** The number of milliseconds per hour @stable ICU 2.0 */
+#define U_MILLIS_PER_HOUR       (3600000)
+/** The number of milliseconds per day @stable ICU 2.0 */
+#define U_MILLIS_PER_DAY       (86400000)
+
+
+/*===========================================================================*/
+/* UClassID-based RTTI */
+/*===========================================================================*/
+
+/**
+ * UClassID is used to identify classes without using RTTI, since RTTI
+ * is not yet supported by all C++ compilers.  Each class hierarchy which needs
+ * to implement polymorphic clone() or operator==() defines two methods,
+ * described in detail below.  UClassID values can be compared using
+ * operator==(). Nothing else should be done with them.
+ *
+ * \par
+ * getDynamicClassID() is declared in the base class of the hierarchy as
+ * a pure virtual.  Each concrete subclass implements it in the same way:
+ *
+ * \code
+ *      class Base {
+ *      public:
+ *          virtual UClassID getDynamicClassID() const = 0;
+ *      }
+ *
+ *      class Derived {
+ *      public:
+ *          virtual UClassID getDynamicClassID() const
+ *            { return Derived::getStaticClassID(); }
+ *      }
+ * \endcode
+ *
+ * Each concrete class implements getStaticClassID() as well, which allows
+ * clients to test for a specific type.
+ *
+ * \code
+ *      class Derived {
+ *      public:
+ *          static UClassID U_EXPORT2 getStaticClassID();
+ *      private:
+ *          static char fgClassID;
+ *      }
+ *
+ *      // In Derived.cpp:
+ *      UClassID Derived::getStaticClassID()
+ *        { return (UClassID)&Derived::fgClassID; }
+ *      char Derived::fgClassID = 0; // Value is irrelevant
+ * \endcode
+ * @stable ICU 2.0
+ */
+typedef void* UClassID;
+
+/*===========================================================================*/
+/* Shared library/DLL import-export API control                              */
+/*===========================================================================*/
+
+/*
+ * Control of symbol import/export.
+ * ICU is separated into three libraries.
+ */
+
+/*
+ * \def U_COMBINED_IMPLEMENTATION
+ * Set to export library symbols from inside the ICU library
+ * when all of ICU is in a single library.
+ * This can be set as a compiler option while building ICU, and it
+ * needs to be the first one tested to override U_COMMON_API, U_I18N_API, etc.
+ * @stable ICU 2.0
+ */
+
+/**
+ * \def U_DATA_API
+ * Set to export library symbols from inside the stubdata library,
+ * and to import them from outside.
+ * @stable ICU 3.0
+ */
+
+/**
+ * \def U_COMMON_API
+ * Set to export library symbols from inside the common library,
+ * and to import them from outside.
+ * @stable ICU 2.0
+ */
+
+/**
+ * \def U_I18N_API
+ * Set to export library symbols from inside the i18n library,
+ * and to import them from outside.
+ * @stable ICU 2.0
+ */
+
+/**
+ * \def U_LAYOUT_API
+ * Set to export library symbols from inside the layout engine library,
+ * and to import them from outside.
+ * @stable ICU 2.0
+ */
+
+/**
+ * \def U_LAYOUTEX_API
+ * Set to export library symbols from inside the layout extensions library,
+ * and to import them from outside.
+ * @stable ICU 2.6
+ */
+
+/**
+ * \def U_IO_API
+ * Set to export library symbols from inside the ustdio library,
+ * and to import them from outside.
+ * @stable ICU 2.0
+ */
+
+/**
+ * \def U_TOOLUTIL_API
+ * Set to export library symbols from inside the toolutil library,
+ * and to import them from outside.
+ * @stable ICU 3.4
+ */
+
+#if defined(U_COMBINED_IMPLEMENTATION)
+#define U_DATA_API     U_EXPORT
+#define U_COMMON_API   U_EXPORT
+#define U_I18N_API     U_EXPORT
+#define U_LAYOUT_API   U_EXPORT
+#define U_LAYOUTEX_API U_EXPORT
+#define U_IO_API       U_EXPORT
+#define U_TOOLUTIL_API U_EXPORT
+#elif defined(U_STATIC_IMPLEMENTATION)
+#define U_DATA_API
+#define U_COMMON_API
+#define U_I18N_API
+#define U_LAYOUT_API
+#define U_LAYOUTEX_API
+#define U_IO_API
+#define U_TOOLUTIL_API
+#elif defined(U_COMMON_IMPLEMENTATION)
+#define U_DATA_API     U_IMPORT
+#define U_COMMON_API   U_EXPORT
+#define U_I18N_API     U_IMPORT
+#define U_LAYOUT_API   U_IMPORT
+#define U_LAYOUTEX_API U_IMPORT
+#define U_IO_API       U_IMPORT
+#define U_TOOLUTIL_API U_IMPORT
+#elif defined(U_I18N_IMPLEMENTATION)
+#define U_DATA_API     U_IMPORT
+#define U_COMMON_API   U_IMPORT
+#define U_I18N_API     U_EXPORT
+#define U_LAYOUT_API   U_IMPORT
+#define U_LAYOUTEX_API U_IMPORT
+#define U_IO_API       U_IMPORT
+#define U_TOOLUTIL_API U_IMPORT
+#elif defined(U_LAYOUT_IMPLEMENTATION)
+#define U_DATA_API     U_IMPORT
+#define U_COMMON_API   U_IMPORT
+#define U_I18N_API     U_IMPORT
+#define U_LAYOUT_API   U_EXPORT
+#define U_LAYOUTEX_API U_IMPORT
+#define U_IO_API       U_IMPORT
+#define U_TOOLUTIL_API U_IMPORT
+#elif defined(U_LAYOUTEX_IMPLEMENTATION)
+#define U_DATA_API     U_IMPORT
+#define U_COMMON_API   U_IMPORT
+#define U_I18N_API     U_IMPORT
+#define U_LAYOUT_API   U_IMPORT
+#define U_LAYOUTEX_API U_EXPORT
+#define U_IO_API       U_IMPORT
+#define U_TOOLUTIL_API U_IMPORT
+#elif defined(U_IO_IMPLEMENTATION)
+#define U_DATA_API     U_IMPORT
+#define U_COMMON_API   U_IMPORT
+#define U_I18N_API     U_IMPORT
+#define U_LAYOUT_API   U_IMPORT
+#define U_LAYOUTEX_API U_IMPORT
+#define U_IO_API       U_EXPORT
+#define U_TOOLUTIL_API U_IMPORT
+#elif defined(U_TOOLUTIL_IMPLEMENTATION)
+#define U_DATA_API     U_IMPORT
+#define U_COMMON_API   U_IMPORT
+#define U_I18N_API     U_IMPORT
+#define U_LAYOUT_API   U_IMPORT
+#define U_LAYOUTEX_API U_IMPORT
+#define U_IO_API       U_IMPORT
+#define U_TOOLUTIL_API U_EXPORT
+#else
+#define U_DATA_API     U_IMPORT
+#define U_COMMON_API   U_IMPORT
+#define U_I18N_API     U_IMPORT
+#define U_LAYOUT_API   U_IMPORT
+#define U_LAYOUTEX_API U_IMPORT
+#define U_IO_API       U_IMPORT
+#define U_TOOLUTIL_API U_IMPORT
+#endif
+
+/**
+ * \def U_STANDARD_CPP_NAMESPACE
+ * Control of C++ Namespace
+ * @stable ICU 2.0
+ */
+#ifdef __cplusplus
+#define U_STANDARD_CPP_NAMESPACE        ::
+#else
+#define U_STANDARD_CPP_NAMESPACE
+#endif
+
+
+/*===========================================================================*/
+/* Global delete operator                                                    */
+/*===========================================================================*/
+
+/*
+ * The ICU4C library must not use the global new and delete operators.
+ * These operators here are defined to enable testing for this.
+ * See Jitterbug 2581 for details of why this is necessary.
+ *
+ * Verification that ICU4C's memory usage is correct, i.e.,
+ * that global new/delete are not used:
+ *
+ * a) Check for imports of global new/delete (see uobject.cpp for details)
+ * b) Verify that new is never imported.
+ * c) Verify that delete is only imported from object code for interface/mixin classes.
+ * d) Add global delete and delete[] only for the ICU4C library itself
+ *    and define them in a way that crashes or otherwise easily shows a problem.
+ *
+ * The following implements d).
+ * The operator implementations crash; this is intentional and used for library debugging.
+ *
+ * Note: This is currently only done on Windows because
+ * some Linux/Unix compilers have problems with defining global new/delete.
+ * On Windows, U_WINDOWS is defined, and it is _MSC_VER>=1200 for MSVC 6.0 and higher.
+ */
+#if defined(XP_CPLUSPLUS) && defined(U_WINDOWS) && U_DEBUG && U_OVERRIDE_CXX_ALLOCATION && (_MSC_VER>=1200) && !defined(U_STATIC_IMPLEMENTATION) && (defined(U_COMMON_IMPLEMENTATION) || defined(U_I18N_IMPLEMENTATION) || defined(U_IO_IMPLEMENTATION) || defined(U_LAYOUT_IMPLEMENTATION) || defined(U_LAYOUTEX_IMPLEMENTATION))
+
+#ifndef U_HIDE_INTERNAL_API
+/**
+ * Global operator new, defined only inside ICU4C, must not be used.
+ * Crashes intentionally.
+ * @internal
+ */
+inline void *
+operator new(size_t /*size*/) {
+    char *q=NULL;
+    *q=5; /* break it */
+    return q;
+}
+
+#ifdef _Ret_bytecap_
+/* This is only needed to suppress a Visual C++ 2008 warning for operator new[]. */
+_Ret_bytecap_(_Size)
+#endif
+/**
+ * Global operator new[], defined only inside ICU4C, must not be used.
+ * Crashes intentionally.
+ * @internal
+ */
+inline void *
+operator new[](size_t /*size*/) {
+    char *q=NULL;
+    *q=5; /* break it */
+    return q;
+}
+
+/**
+ * Global operator delete, defined only inside ICU4C, must not be used.
+ * Crashes intentionally.
+ * @internal
+ */
+inline void
+operator delete(void * /*p*/) {
+    char *q=NULL;
+    *q=5; /* break it */
+}
+
+/**
+ * Global operator delete[], defined only inside ICU4C, must not be used.
+ * Crashes intentionally.
+ * @internal
+ */
+inline void
+operator delete[](void * /*p*/) {
+    char *q=NULL;
+    *q=5; /* break it */
+}
+
+#endif /* U_HIDE_INTERNAL_API */
+#endif
+
+/*===========================================================================*/
+/* UErrorCode */
+/*===========================================================================*/
+
+/**
+ * Error code to replace exception handling, so that the code is compatible with all C++ compilers,
+ * and to use the same mechanism for C and C++.
+ *
+ * \par
+ * ICU functions that take a reference (C++) or a pointer (C) to a UErrorCode
+ * first test if(U_FAILURE(errorCode)) { return immediately; }
+ * so that in a chain of such functions the first one that sets an error code
+ * causes the following ones to not perform any operations.
+ *
+ * \par
+ * Error codes should be tested using U_FAILURE() and U_SUCCESS().
+ * @stable ICU 2.0
+ */
+typedef enum UErrorCode {
+    /* The ordering of U_ERROR_INFO_START Vs U_USING_FALLBACK_WARNING looks weird
+     * and is that way because VC++ debugger displays first encountered constant,
+     * which is not the what the code is used for
+     */
+
+    U_USING_FALLBACK_WARNING  = -128,   /**< A resource bundle lookup returned a fallback result (not an error) */
+
+    U_ERROR_WARNING_START     = -128,   /**< Start of information results (semantically successful) */
+
+    U_USING_DEFAULT_WARNING   = -127,   /**< A resource bundle lookup returned a result from the root locale (not an error) */
+
+    U_SAFECLONE_ALLOCATED_WARNING = -126, /**< A SafeClone operation required allocating memory (informational only) */
+
+    U_STATE_OLD_WARNING       = -125,   /**< ICU has to use compatibility layer to construct the service. Expect performance/memory usage degradation. Consider upgrading */
+
+    U_STRING_NOT_TERMINATED_WARNING = -124,/**< An output string could not be NUL-terminated because output length==destCapacity. */
+
+    U_SORT_KEY_TOO_SHORT_WARNING = -123, /**< Number of levels requested in getBound is higher than the number of levels in the sort key */
+
+    U_AMBIGUOUS_ALIAS_WARNING = -122,   /**< This converter alias can go to different converter implementations */
+
+    U_DIFFERENT_UCA_VERSION = -121,     /**< ucol_open encountered a mismatch between UCA version and collator image version, so the collator was constructed from rules. No impact to further function */
+    
+    U_PLUGIN_CHANGED_LEVEL_WARNING = -120, /**< A plugin caused a level change. May not be an error, but later plugins may not load. */
+
+    U_ERROR_WARNING_LIMIT,              /**< This must always be the last warning value to indicate the limit for UErrorCode warnings (last warning code +1) */
+
+
+    U_ZERO_ERROR              =  0,     /**< No error, no warning. */
+
+    U_ILLEGAL_ARGUMENT_ERROR  =  1,     /**< Start of codes indicating failure */
+    U_MISSING_RESOURCE_ERROR  =  2,     /**< The requested resource cannot be found */
+    U_INVALID_FORMAT_ERROR    =  3,     /**< Data format is not what is expected */
+    U_FILE_ACCESS_ERROR       =  4,     /**< The requested file cannot be found */
+    U_INTERNAL_PROGRAM_ERROR  =  5,     /**< Indicates a bug in the library code */
+    U_MESSAGE_PARSE_ERROR     =  6,     /**< Unable to parse a message (message format) */
+    U_MEMORY_ALLOCATION_ERROR =  7,     /**< Memory allocation error */
+    U_INDEX_OUTOFBOUNDS_ERROR =  8,     /**< Trying to access the index that is out of bounds */
+    U_PARSE_ERROR             =  9,     /**< Equivalent to Java ParseException */
+    U_INVALID_CHAR_FOUND      = 10,     /**< Character conversion: Unmappable input sequence. In other APIs: Invalid character. */
+    U_TRUNCATED_CHAR_FOUND    = 11,     /**< Character conversion: Incomplete input sequence. */
+    U_ILLEGAL_CHAR_FOUND      = 12,     /**< Character conversion: Illegal input sequence/combination of input units. */
+    U_INVALID_TABLE_FORMAT    = 13,     /**< Conversion table file found, but corrupted */
+    U_INVALID_TABLE_FILE      = 14,     /**< Conversion table file not found */
+    U_BUFFER_OVERFLOW_ERROR   = 15,     /**< A result would not fit in the supplied buffer */
+    U_UNSUPPORTED_ERROR       = 16,     /**< Requested operation not supported in current context */
+    U_RESOURCE_TYPE_MISMATCH  = 17,     /**< an operation is requested over a resource that does not support it */
+    U_ILLEGAL_ESCAPE_SEQUENCE = 18,     /**< ISO-2022 illlegal escape sequence */
+    U_UNSUPPORTED_ESCAPE_SEQUENCE = 19, /**< ISO-2022 unsupported escape sequence */
+    U_NO_SPACE_AVAILABLE      = 20,     /**< No space available for in-buffer expansion for Arabic shaping */
+    U_CE_NOT_FOUND_ERROR      = 21,     /**< Currently used only while setting variable top, but can be used generally */
+    U_PRIMARY_TOO_LONG_ERROR  = 22,     /**< User tried to set variable top to a primary that is longer than two bytes */
+    U_STATE_TOO_OLD_ERROR     = 23,     /**< ICU cannot construct a service from this state, as it is no longer supported */
+    U_TOO_MANY_ALIASES_ERROR  = 24,     /**< There are too many aliases in the path to the requested resource.
+                                             It is very possible that a circular alias definition has occured */
+    U_ENUM_OUT_OF_SYNC_ERROR  = 25,     /**< UEnumeration out of sync with underlying collection */
+    U_INVARIANT_CONVERSION_ERROR = 26,  /**< Unable to convert a UChar* string to char* with the invariant converter. */
+    U_INVALID_STATE_ERROR     = 27,     /**< Requested operation can not be completed with ICU in its current state */
+    U_COLLATOR_VERSION_MISMATCH = 28,   /**< Collator version is not compatible with the base version */
+    U_USELESS_COLLATOR_ERROR  = 29,     /**< Collator is options only and no base is specified */
+    U_NO_WRITE_PERMISSION     = 30,     /**< Attempt to modify read-only or constant data. */
+
+    U_STANDARD_ERROR_LIMIT,             /**< This must always be the last value to indicate the limit for standard errors */
+    /*
+     * the error code range 0x10000 0x10100 are reserved for Transliterator
+     */
+    U_BAD_VARIABLE_DEFINITION=0x10000,/**< Missing '$' or duplicate variable name */
+    U_PARSE_ERROR_START = 0x10000,    /**< Start of Transliterator errors */
+    U_MALFORMED_RULE,                 /**< Elements of a rule are misplaced */
+    U_MALFORMED_SET,                  /**< A UnicodeSet pattern is invalid*/
+    U_MALFORMED_SYMBOL_REFERENCE,     /**< UNUSED as of ICU 2.4 */
+    U_MALFORMED_UNICODE_ESCAPE,       /**< A Unicode escape pattern is invalid*/
+    U_MALFORMED_VARIABLE_DEFINITION,  /**< A variable definition is invalid */
+    U_MALFORMED_VARIABLE_REFERENCE,   /**< A variable reference is invalid */
+    U_MISMATCHED_SEGMENT_DELIMITERS,  /**< UNUSED as of ICU 2.4 */
+    U_MISPLACED_ANCHOR_START,         /**< A start anchor appears at an illegal position */
+    U_MISPLACED_CURSOR_OFFSET,        /**< A cursor offset occurs at an illegal position */
+    U_MISPLACED_QUANTIFIER,           /**< A quantifier appears after a segment close delimiter */
+    U_MISSING_OPERATOR,               /**< A rule contains no operator */
+    U_MISSING_SEGMENT_CLOSE,          /**< UNUSED as of ICU 2.4 */
+    U_MULTIPLE_ANTE_CONTEXTS,         /**< More than one ante context */
+    U_MULTIPLE_CURSORS,               /**< More than one cursor */
+    U_MULTIPLE_POST_CONTEXTS,         /**< More than one post context */
+    U_TRAILING_BACKSLASH,             /**< A dangling backslash */
+    U_UNDEFINED_SEGMENT_REFERENCE,    /**< A segment reference does not correspond to a defined segment */
+    U_UNDEFINED_VARIABLE,             /**< A variable reference does not correspond to a defined variable */
+    U_UNQUOTED_SPECIAL,               /**< A special character was not quoted or escaped */
+    U_UNTERMINATED_QUOTE,             /**< A closing single quote is missing */
+    U_RULE_MASK_ERROR,                /**< A rule is hidden by an earlier more general rule */
+    U_MISPLACED_COMPOUND_FILTER,      /**< A compound filter is in an invalid location */
+    U_MULTIPLE_COMPOUND_FILTERS,      /**< More than one compound filter */
+    U_INVALID_RBT_SYNTAX,             /**< A "::id" rule was passed to the RuleBasedTransliterator parser */
+    U_INVALID_PROPERTY_PATTERN,       /**< UNUSED as of ICU 2.4 */
+    U_MALFORMED_PRAGMA,               /**< A 'use' pragma is invlalid */
+    U_UNCLOSED_SEGMENT,               /**< A closing ')' is missing */
+    U_ILLEGAL_CHAR_IN_SEGMENT,        /**< UNUSED as of ICU 2.4 */
+    U_VARIABLE_RANGE_EXHAUSTED,       /**< Too many stand-ins generated for the given variable range */
+    U_VARIABLE_RANGE_OVERLAP,         /**< The variable range overlaps characters used in rules */
+    U_ILLEGAL_CHARACTER,              /**< A special character is outside its allowed context */
+    U_INTERNAL_TRANSLITERATOR_ERROR,  /**< Internal transliterator system error */
+    U_INVALID_ID,                     /**< A "::id" rule specifies an unknown transliterator */
+    U_INVALID_FUNCTION,               /**< A "&fn()" rule specifies an unknown transliterator */
+    U_PARSE_ERROR_LIMIT,              /**< The limit for Transliterator errors */
+
+    /*
+     * the error code range 0x10100 0x10200 are reserved for formatting API parsing error
+     */
+    U_UNEXPECTED_TOKEN=0x10100,       /**< Syntax error in format pattern */
+    U_FMT_PARSE_ERROR_START=0x10100,  /**< Start of format library errors */
+    U_MULTIPLE_DECIMAL_SEPARATORS,    /**< More than one decimal separator in number pattern */
+    U_MULTIPLE_DECIMAL_SEPERATORS = U_MULTIPLE_DECIMAL_SEPARATORS, /**< Typo: kept for backward compatibility. Use U_MULTIPLE_DECIMAL_SEPARATORS */
+    U_MULTIPLE_EXPONENTIAL_SYMBOLS,   /**< More than one exponent symbol in number pattern */
+    U_MALFORMED_EXPONENTIAL_PATTERN,  /**< Grouping symbol in exponent pattern */
+    U_MULTIPLE_PERCENT_SYMBOLS,       /**< More than one percent symbol in number pattern */
+    U_MULTIPLE_PERMILL_SYMBOLS,       /**< More than one permill symbol in number pattern */
+    U_MULTIPLE_PAD_SPECIFIERS,        /**< More than one pad symbol in number pattern */
+    U_PATTERN_SYNTAX_ERROR,           /**< Syntax error in format pattern */
+    U_ILLEGAL_PAD_POSITION,           /**< Pad symbol misplaced in number pattern */
+    U_UNMATCHED_BRACES,               /**< Braces do not match in message pattern */
+    U_UNSUPPORTED_PROPERTY,           /**< UNUSED as of ICU 2.4 */
+    U_UNSUPPORTED_ATTRIBUTE,          /**< UNUSED as of ICU 2.4 */
+    U_ARGUMENT_TYPE_MISMATCH,         /**< Argument name and argument index mismatch in MessageFormat functions */
+    U_DUPLICATE_KEYWORD,              /**< Duplicate keyword in PluralFormat */
+    U_UNDEFINED_KEYWORD,              /**< Undefined Plural keyword */
+    U_DEFAULT_KEYWORD_MISSING,        /**< Missing DEFAULT rule in plural rules */
+    U_DECIMAL_NUMBER_SYNTAX_ERROR,    /**< Decimal number syntax error */
+    U_FMT_PARSE_ERROR_LIMIT,          /**< The limit for format library errors */
+
+    /*
+     * the error code range 0x10200 0x102ff are reserved for Break Iterator related error
+     */
+    U_BRK_INTERNAL_ERROR=0x10200,          /**< An internal error (bug) was detected.             */
+    U_BRK_ERROR_START=0x10200,             /**< Start of codes indicating Break Iterator failures */
+    U_BRK_HEX_DIGITS_EXPECTED,             /**< Hex digits expected as part of a escaped char in a rule. */
+    U_BRK_SEMICOLON_EXPECTED,              /**< Missing ';' at the end of a RBBI rule.            */
+    U_BRK_RULE_SYNTAX,                     /**< Syntax error in RBBI rule.                        */
+    U_BRK_UNCLOSED_SET,                    /**< UnicodeSet witing an RBBI rule missing a closing ']'.  */
+    U_BRK_ASSIGN_ERROR,                    /**< Syntax error in RBBI rule assignment statement.   */
+    U_BRK_VARIABLE_REDFINITION,            /**< RBBI rule $Variable redefined.                    */
+    U_BRK_MISMATCHED_PAREN,                /**< Mis-matched parentheses in an RBBI rule.          */
+    U_BRK_NEW_LINE_IN_QUOTED_STRING,       /**< Missing closing quote in an RBBI rule.            */
+    U_BRK_UNDEFINED_VARIABLE,              /**< Use of an undefined $Variable in an RBBI rule.    */
+    U_BRK_INIT_ERROR,                      /**< Initialization failure.  Probable missing ICU Data. */
+    U_BRK_RULE_EMPTY_SET,                  /**< Rule contains an empty Unicode Set.               */
+    U_BRK_UNRECOGNIZED_OPTION,             /**< !!option in RBBI rules not recognized.            */
+    U_BRK_MALFORMED_RULE_TAG,              /**< The {nnn} tag on a rule is mal formed             */
+    U_BRK_ERROR_LIMIT,                     /**< This must always be the last value to indicate the limit for Break Iterator failures */
+
+    /*
+     * The error codes in the range 0x10300-0x103ff are reserved for regular expression related errrs
+     */
+    U_REGEX_INTERNAL_ERROR=0x10300,       /**< An internal error (bug) was detected.              */
+    U_REGEX_ERROR_START=0x10300,          /**< Start of codes indicating Regexp failures          */
+    U_REGEX_RULE_SYNTAX,                  /**< Syntax error in regexp pattern.                    */
+    U_REGEX_INVALID_STATE,                /**< RegexMatcher in invalid state for requested operation */
+    U_REGEX_BAD_ESCAPE_SEQUENCE,          /**< Unrecognized backslash escape sequence in pattern  */
+    U_REGEX_PROPERTY_SYNTAX,              /**< Incorrect Unicode property                         */
+    U_REGEX_UNIMPLEMENTED,                /**< Use of regexp feature that is not yet implemented. */
+    U_REGEX_MISMATCHED_PAREN,             /**< Incorrectly nested parentheses in regexp pattern.  */
+    U_REGEX_NUMBER_TOO_BIG,               /**< Decimal number is too large.                       */
+    U_REGEX_BAD_INTERVAL,                 /**< Error in {min,max} interval                        */
+    U_REGEX_MAX_LT_MIN,                   /**< In {min,max}, max is less than min.                */
+    U_REGEX_INVALID_BACK_REF,             /**< Back-reference to a non-existent capture group.    */
+    U_REGEX_INVALID_FLAG,                 /**< Invalid value for match mode flags.                */
+    U_REGEX_LOOK_BEHIND_LIMIT,            /**< Look-Behind pattern matches must have a bounded maximum length.    */
+    U_REGEX_SET_CONTAINS_STRING,          /**< Regexps cannot have UnicodeSets containing strings.*/
+    U_REGEX_OCTAL_TOO_BIG,                /**< Octal character constants must be <= 0377.         */
+    U_REGEX_MISSING_CLOSE_BRACKET,        /**< Missing closing bracket on a bracket expression.   */
+    U_REGEX_INVALID_RANGE,                /**< In a character range [x-y], x is greater than y.   */
+    U_REGEX_STACK_OVERFLOW,               /**< Regular expression backtrack stack overflow.       */
+    U_REGEX_TIME_OUT,                     /**< Maximum allowed match time exceeded                */
+    U_REGEX_STOPPED_BY_CALLER,            /**< Matching operation aborted by user callback fn.    */
+    U_REGEX_ERROR_LIMIT,                  /**< This must always be the last value to indicate the limit for regexp errors */
+
+    /*
+     * The error code in the range 0x10400-0x104ff are reserved for IDNA related error codes
+     */
+    U_IDNA_PROHIBITED_ERROR=0x10400,
+    U_IDNA_ERROR_START=0x10400,
+    U_IDNA_UNASSIGNED_ERROR,
+    U_IDNA_CHECK_BIDI_ERROR,
+    U_IDNA_STD3_ASCII_RULES_ERROR,
+    U_IDNA_ACE_PREFIX_ERROR,
+    U_IDNA_VERIFICATION_ERROR,
+    U_IDNA_LABEL_TOO_LONG_ERROR,
+    U_IDNA_ZERO_LENGTH_LABEL_ERROR,
+    U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR,
+    U_IDNA_ERROR_LIMIT,
+    /*
+     * Aliases for StringPrep
+     */
+    U_STRINGPREP_PROHIBITED_ERROR = U_IDNA_PROHIBITED_ERROR,
+    U_STRINGPREP_UNASSIGNED_ERROR = U_IDNA_UNASSIGNED_ERROR,
+    U_STRINGPREP_CHECK_BIDI_ERROR = U_IDNA_CHECK_BIDI_ERROR,
+    
+    /*
+     * The error code in the range 0x10500-0x105ff are reserved for Plugin related error codes
+     */
+    U_PLUGIN_ERROR_START=0x10500,         /**< Start of codes indicating plugin failures */
+    U_PLUGIN_TOO_HIGH=0x10500,            /**< The plugin's level is too high to be loaded right now. */
+    U_PLUGIN_DIDNT_SET_LEVEL,             /**< The plugin didn't call uplug_setPlugLevel in response to a QUERY */
+    U_PLUGIN_ERROR_LIMIT,                 /**< This must always be the last value to indicate the limit for plugin errors */
+
+    U_ERROR_LIMIT=U_PLUGIN_ERROR_LIMIT      /**< This must always be the last value to indicate the limit for UErrorCode (last error code +1) */
+} UErrorCode;
+
+/* Use the following to determine if an UErrorCode represents */
+/* operational success or failure. */
+
+#ifdef XP_CPLUSPLUS
+    /**
+     * Does the error code indicate success?
+     * @stable ICU 2.0
+     */
+    static
+    inline UBool U_SUCCESS(UErrorCode code) { return (UBool)(code<=U_ZERO_ERROR); }
+    /**
+     * Does the error code indicate a failure?
+     * @stable ICU 2.0
+     */
+    static
+    inline UBool U_FAILURE(UErrorCode code) { return (UBool)(code>U_ZERO_ERROR); }
+#else
+    /**
+     * Does the error code indicate success?
+     * @stable ICU 2.0
+     */
+#   define U_SUCCESS(x) ((x)<=U_ZERO_ERROR)
+    /**
+     * Does the error code indicate a failure?
+     * @stable ICU 2.0
+     */
+#   define U_FAILURE(x) ((x)>U_ZERO_ERROR)
+#endif
+
+/**
+ * Return a string for a UErrorCode value.
+ * The string will be the same as the name of the error code constant
+ * in the UErrorCode enum above.
+ * @stable ICU 2.0
+ */
+U_STABLE const char * U_EXPORT2
+u_errorName(UErrorCode code);
+
+
+#endif /* _UTYPES */
diff --git a/source/common/unicode/uvernum.h b/source/common/unicode/uvernum.h
new file mode 100644
index 0000000..7221612
--- /dev/null
+++ b/source/common/unicode/uvernum.h
@@ -0,0 +1,138 @@
+/*
+*******************************************************************************
+*   Copyright (C) 2000-2011, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*******************************************************************************
+*
+*   file name:  uvernum.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   Created by: Vladimir Weinstein
+*   Updated by: Steven R. Loomis
+*
+*  Gets included by uversion.h and other files.
+*
+* IMPORTANT: When updating version, the following things need to be done:
+* source/common/unicode/uvernum.h - this file: update major, minor,
+*        patchlevel, suffix, version, short version constants, namespace,
+*                    renaming macro, and copyright
+*
+* The following files need to be updated as well, which can be done
+*  by running the UNIX makefile target 'update-windows-makefiles' in icu/source.
+*
+*
+* source/common/common.vcproj - update 'Output file name' on the link tab so
+*                   that it contains the new major/minor combination
+* source/i18n/i18n.vcproj - same as for the common.vcproj
+* source/layout/layout.vcproj - same as for the common.vcproj
+* source/layoutex/layoutex.vcproj - same
+* source/stubdata/stubdata.vcproj - same as for the common.vcproj
+* source/io/io.vcproj - same as for the common.vcproj
+* source/data/makedata.mak - change U_ICUDATA_NAME so that it contains
+*                            the new major/minor combination and the Unicode version.
+*/
+
+#ifndef UVERNUM_H
+#define UVERNUM_H
+
+/** The standard copyright notice that gets compiled into each library. 
+ *  This value will change in the subsequent releases of ICU
+ *  @stable ICU 2.4
+ */
+#define U_COPYRIGHT_STRING \
+  " Copyright (C) 2011, International Business Machines Corporation and others. All Rights Reserved. "
+
+/** The current ICU major version as an integer. 
+ *  This value will change in the subsequent releases of ICU
+ *  @stable ICU 2.4
+ */
+#define U_ICU_VERSION_MAJOR_NUM 4
+
+/** The current ICU minor version as an integer. 
+ *  This value will change in the subsequent releases of ICU
+ *  @stable ICU 2.6
+ */
+#define U_ICU_VERSION_MINOR_NUM 6
+
+/** The current ICU patchlevel version as an integer.  
+ *  This value will change in the subsequent releases of ICU
+ *  @stable ICU 2.4
+ */
+#define U_ICU_VERSION_PATCHLEVEL_NUM 1
+
+/** The current ICU build level version as an integer.  
+ *  This value is for use by ICU clients. It defaults to 0.
+ *  @stable ICU 4.0
+ */
+#ifndef U_ICU_VERSION_BUILDLEVEL_NUM
+#define U_ICU_VERSION_BUILDLEVEL_NUM 0
+#endif
+
+/** Glued version suffix for renamers 
+ *  This value will change in the subsequent releases of ICU
+ *  @stable ICU 2.6
+ */
+#define U_ICU_VERSION_SUFFIX _46
+
+/** Glued version suffix function for renamers 
+ *  This value will change in the subsequent releases of ICU.
+ *  If a custom suffix (such as matching library suffixes) is desired, this can be modified.
+ *  Note that if present, platform.h may contain an earlier definition of this macro.
+ *  @stable ICU 4.2
+ */
+#ifndef U_ICU_ENTRY_POINT_RENAME
+#define U_ICU_ENTRY_POINT_RENAME(x)    x ## _46
+#endif
+
+/** The current ICU library version as a dotted-decimal string. The patchlevel
+ *  only appears in this string if it non-zero. 
+ *  This value will change in the subsequent releases of ICU
+ *  @stable ICU 2.4
+ */
+#define U_ICU_VERSION "4.6.1"
+
+/** The current ICU library major/minor version as a string without dots, for library name suffixes. 
+ *  This value will change in the subsequent releases of ICU
+ *  @stable ICU 2.6
+ */
+#define U_ICU_VERSION_SHORT "46"
+
+/** Data version in ICU4C.
+ * @internal ICU 4.4 Internal Use Only
+ **/
+#define U_ICU_DATA_VERSION "4.6"
+
+/*===========================================================================
+ * ICU collation framework version information
+ * Version info that can be obtained from a collator is affected by these
+ * numbers in a secret and magic way. Please use collator version as whole
+ *===========================================================================
+ */
+
+/**
+ * Collation runtime version (sort key generator, strcoll).
+ * If the version is different, sort keys for the same string could be different.
+ * This value may change in subsequent releases of ICU.
+ * @stable ICU 2.4
+ */
+#define UCOL_RUNTIME_VERSION 7
+
+/**
+ * Collation builder code version.
+ * When this is different, the same tailoring might result
+ * in assigning different collation elements to code points.
+ * This value may change in subsequent releases of ICU.
+ * @stable ICU 2.4
+ */
+#define UCOL_BUILDER_VERSION 8
+
+/**
+ * This is the version of collation tailorings.
+ * This value may change in subsequent releases of ICU.
+ * @stable ICU 2.4
+ */
+#define UCOL_TAILORINGS_VERSION 1
+
+#endif
diff --git a/source/common/unicode/uversion.h b/source/common/unicode/uversion.h
new file mode 100644
index 0000000..e54cd55
--- /dev/null
+++ b/source/common/unicode/uversion.h
@@ -0,0 +1,195 @@
+/*
+*******************************************************************************
+*   Copyright (C) 2000-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*******************************************************************************
+*
+*   file name:  uversion.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   Created by: Vladimir Weinstein
+*
+*  Gets included by utypes.h and Windows .rc files
+*/
+
+/**
+ * \file
+ * \brief C API: API for accessing ICU version numbers. 
+ */
+/*===========================================================================*/
+/* Main ICU version information                                              */
+/*===========================================================================*/
+
+#ifndef UVERSION_H
+#define UVERSION_H
+
+#include "unicode/umachine.h"
+
+/* Actual version info lives in uvernum.h */
+#include "unicode/uvernum.h"
+
+/** Maximum length of the copyright string.
+ *  @stable ICU 2.4
+ */
+#define U_COPYRIGHT_STRING_LENGTH  128
+
+/** An ICU version consists of up to 4 numbers from 0..255.
+ *  @stable ICU 2.4
+ */
+#define U_MAX_VERSION_LENGTH 4
+
+/** In a string, ICU version fields are delimited by dots.
+ *  @stable ICU 2.4
+ */
+#define U_VERSION_DELIMITER '.'
+
+/** The maximum length of an ICU version string.
+ *  @stable ICU 2.4
+ */
+#define U_MAX_VERSION_STRING_LENGTH 20
+
+/** The binary form of a version on ICU APIs is an array of 4 uint8_t.
+ *  To compare two versions, use memcmp(v1,v2,sizeof(UVersionInfo)).
+ *  @stable ICU 2.4
+ */
+typedef uint8_t UVersionInfo[U_MAX_VERSION_LENGTH];
+
+/*===========================================================================*/
+/* C++ namespace if supported. Versioned unless versioning is disabled.      */
+/*===========================================================================*/
+
+/**
+ * \def U_NAMESPACE_BEGIN
+ * This is used to begin a declaration of a public ICU C++ API.
+ * When not compiling for C++, it does nothing.
+ * When compiling for C++, it begins an extern "C++" linkage block (to protect
+ * against cases in which an external client includes ICU header files inside
+ * an extern "C" linkage block).
+ * If the C++ compiler supports namespaces, it also begins a namespace block.
+ * @stable ICU 2.4
+ */
+
+/**
+ * \def U_NAMESPACE_END
+ * This is used to end a declaration of a public ICU C++ API.
+ * When not compiling for C++, it does nothing.
+ * When compiling for C++, it ends the extern "C++" block begun by
+ * U_NAMESPACE_BEGIN.
+ * If the C++ compiler supports namespaces, it also ends the namespace block
+ * begun by U_NAMESPACE_BEGIN.
+ * @stable ICU 2.4
+ */
+
+/**
+ * \def U_NAMESPACE_USE
+ * This is used to specify that the rest of the code uses the
+ * public ICU C++ API namespace.
+ * If the compiler doesn't support namespaces, this does nothing.
+ * @stable ICU 2.4
+ */
+
+/**
+ * \def U_NAMESPACE_QUALIFIER
+ * This is used to qualify that a function or class is part of
+ * the public ICU C++ API namespace.
+ * If the compiler doesn't support namespaces, this does nothing.
+ * @stable ICU 2.4
+ */
+
+/* Define namespace symbols if the compiler supports it. */
+#ifdef XP_CPLUSPLUS
+#if U_HAVE_NAMESPACE
+#   if U_DISABLE_RENAMING
+#       define U_ICU_NAMESPACE icu
+        namespace U_ICU_NAMESPACE { }
+#   else
+#       define U_ICU_NAMESPACE U_ICU_ENTRY_POINT_RENAME(icu)
+        namespace U_ICU_NAMESPACE { }
+        namespace icu = U_ICU_NAMESPACE;
+#   endif
+
+#   define U_NAMESPACE_BEGIN extern "C++" { namespace U_ICU_NAMESPACE {
+#   define U_NAMESPACE_END } }
+#   define U_NAMESPACE_USE using namespace U_ICU_NAMESPACE;
+#   define U_NAMESPACE_QUALIFIER U_ICU_NAMESPACE::
+
+#   ifndef U_USING_ICU_NAMESPACE
+#       define U_USING_ICU_NAMESPACE 1
+#   endif
+#   if U_USING_ICU_NAMESPACE
+        U_NAMESPACE_USE
+#   endif
+#else
+#   define U_NAMESPACE_BEGIN extern "C++" {
+#   define U_NAMESPACE_END }
+#   define U_NAMESPACE_USE
+#   define U_NAMESPACE_QUALIFIER
+#endif
+#else
+#   define U_NAMESPACE_BEGIN
+#   define U_NAMESPACE_END
+#   define U_NAMESPACE_USE
+#   define U_NAMESPACE_QUALIFIER
+#endif
+
+/*===========================================================================*/
+/* General version helper functions. Definitions in putil.c                  */
+/*===========================================================================*/
+
+/**
+ * Parse a string with dotted-decimal version information and
+ * fill in a UVersionInfo structure with the result.
+ * Definition of this function lives in putil.c
+ *
+ * @param versionArray The destination structure for the version information.
+ * @param versionString A string with dotted-decimal version information,
+ *                      with up to four non-negative number fields with
+ *                      values of up to 255 each.
+ * @stable ICU 2.4
+ */
+U_STABLE void U_EXPORT2
+u_versionFromString(UVersionInfo versionArray, const char *versionString);
+
+/**
+ * Parse a Unicode string with dotted-decimal version information and
+ * fill in a UVersionInfo structure with the result.
+ * Definition of this function lives in putil.c
+ *
+ * @param versionArray The destination structure for the version information.
+ * @param versionString A Unicode string with dotted-decimal version
+ *                      information, with up to four non-negative number
+ *                      fields with values of up to 255 each.
+ * @stable ICU 4.2
+ */
+U_STABLE void U_EXPORT2
+u_versionFromUString(UVersionInfo versionArray, const UChar *versionString);
+
+
+/**
+ * Write a string with dotted-decimal version information according
+ * to the input UVersionInfo.
+ * Definition of this function lives in putil.c
+ *
+ * @param versionArray The version information to be written as a string.
+ * @param versionString A string buffer that will be filled in with
+ *                      a string corresponding to the numeric version
+ *                      information in versionArray.
+ *                      The buffer size must be at least U_MAX_VERSION_STRING_LENGTH.
+ * @stable ICU 2.4
+ */
+U_STABLE void U_EXPORT2
+u_versionToString(UVersionInfo versionArray, char *versionString);
+
+/**
+ * Gets the ICU release version.  The version array stores the version information
+ * for ICU.  For example, release "1.3.31.2" is then represented as 0x01031F02.
+ * Definition of this function lives in putil.c
+ *
+ * @param versionArray the version # information, the result will be filled in
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+u_getVersion(UVersionInfo versionArray);
+#endif
diff --git a/source/common/unifilt.cpp b/source/common/unifilt.cpp
new file mode 100644
index 0000000..69ac307
--- /dev/null
+++ b/source/common/unifilt.cpp
@@ -0,0 +1,68 @@
+/*
+**********************************************************************
+* Copyright (c) 2001-2004, International Business Machines
+* Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   Date        Name        Description
+*   07/18/01    aliu        Creation.
+**********************************************************************
+*/
+
+#include "unicode/unifilt.h"
+#include "unicode/rep.h"
+
+U_NAMESPACE_BEGIN
+UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(UnicodeFilter)
+
+
+/* Define this here due to the lack of another file.
+   It can't be defined in the header */
+UnicodeMatcher::~UnicodeMatcher() {}
+
+UnicodeFilter::~UnicodeFilter() {}
+
+/**
+ * UnicodeFunctor API.  Cast 'this' to a UnicodeMatcher* pointer
+ * and return the pointer.
+ */
+UnicodeMatcher* UnicodeFilter::toMatcher() const {
+    return (UnicodeMatcher*) this;
+}
+
+void UnicodeFilter::setData(const TransliterationRuleData*) {}
+
+/**
+ * Default implementation of UnicodeMatcher::matches() for Unicode
+ * filters.  Matches a single code point at offset (either one or
+ * two 16-bit code units).
+ */
+UMatchDegree UnicodeFilter::matches(const Replaceable& text,
+                                    int32_t& offset,
+                                    int32_t limit,
+                                    UBool incremental) {
+    UChar32 c;
+    if (offset < limit &&
+        contains(c = text.char32At(offset))) {
+        offset += UTF_CHAR_LENGTH(c);
+        return U_MATCH;
+    }
+    if (offset > limit &&
+        contains(c = text.char32At(offset))) {
+        // Backup offset by 1, unless the preceding character is a
+        // surrogate pair -- then backup by 2 (keep offset pointing at
+        // the lead surrogate).
+        --offset;
+        if (offset >= 0) {
+            offset -= UTF_CHAR_LENGTH(text.char32At(offset)) - 1;
+        }
+        return U_MATCH;
+    }
+    if (incremental && offset == limit) {
+        return U_PARTIAL_MATCH;
+    }
+    return U_MISMATCH;
+}
+
+U_NAMESPACE_END
+
+//eof
diff --git a/source/common/unifunct.cpp b/source/common/unifunct.cpp
new file mode 100644
index 0000000..b834eee
--- /dev/null
+++ b/source/common/unifunct.cpp
@@ -0,0 +1,26 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2004, International Business Machines
+* Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+
+#include "unicode/unifunct.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(UnicodeFunctor)
+
+UnicodeFunctor::~UnicodeFunctor() {}
+
+UnicodeMatcher* UnicodeFunctor::toMatcher() const {
+    return 0;
+}
+
+UnicodeReplacer* UnicodeFunctor::toReplacer() const {
+    return 0;
+}
+
+U_NAMESPACE_END
+
+//eof
diff --git a/source/common/uniset.cpp b/source/common/uniset.cpp
new file mode 100644
index 0000000..4ff3f6b
--- /dev/null
+++ b/source/common/uniset.cpp
@@ -0,0 +1,2287 @@
+/*
+**********************************************************************
+*   Copyright (C) 1999-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   Date        Name        Description
+*   10/20/99    alan        Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uniset.h"
+#include "unicode/parsepos.h"
+#include "unicode/symtable.h"
+#include "ruleiter.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uhash.h"
+#include "util.h"
+#include "uvector.h"
+#include "charstr.h"
+#include "ustrfmt.h"
+#include "uassert.h"
+#include "hash.h"
+#include "bmpset.h"
+#include "unisetspan.h"
+
+// Define UChar constants using hex for EBCDIC compatibility
+// Used #define to reduce private static exports and memory access time.
+#define SET_OPEN        ((UChar)0x005B) /*[*/
+#define SET_CLOSE       ((UChar)0x005D) /*]*/
+#define HYPHEN          ((UChar)0x002D) /*-*/
+#define COMPLEMENT      ((UChar)0x005E) /*^*/
+#define COLON           ((UChar)0x003A) /*:*/
+#define BACKSLASH       ((UChar)0x005C) /*\*/
+#define INTERSECTION    ((UChar)0x0026) /*&*/
+#define UPPER_U         ((UChar)0x0055) /*U*/
+#define LOWER_U         ((UChar)0x0075) /*u*/
+#define OPEN_BRACE      ((UChar)123)    /*{*/
+#define CLOSE_BRACE     ((UChar)125)    /*}*/
+#define UPPER_P         ((UChar)0x0050) /*P*/
+#define LOWER_P         ((UChar)0x0070) /*p*/
+#define UPPER_N         ((UChar)78)     /*N*/
+#define EQUALS          ((UChar)0x003D) /*=*/
+
+// HIGH_VALUE > all valid values. 110000 for codepoints
+#define UNICODESET_HIGH 0x0110000
+
+// LOW <= all valid values. ZERO for codepoints
+#define UNICODESET_LOW 0x000000
+
+// initial storage. Must be >= 0
+#define START_EXTRA 16
+
+// extra amount for growth. Must be >= 0
+#define GROW_EXTRA START_EXTRA
+
+U_NAMESPACE_BEGIN
+
+SymbolTable::~SymbolTable() {}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UnicodeSet)
+
+/**
+ * Modify the given UChar32 variable so that it is in range, by
+ * pinning values < UNICODESET_LOW to UNICODESET_LOW, and
+ * pinning values > UNICODESET_HIGH-1 to UNICODESET_HIGH-1.
+ * It modifies its argument in-place and also returns it.
+ */
+static inline UChar32 pinCodePoint(UChar32& c) {
+    if (c < UNICODESET_LOW) {
+        c = UNICODESET_LOW;
+    } else if (c > (UNICODESET_HIGH-1)) {
+        c = (UNICODESET_HIGH-1);
+    }
+    return c;
+}
+
+//----------------------------------------------------------------
+// Debugging
+//----------------------------------------------------------------
+
+// DO NOT DELETE THIS CODE.  This code is used to debug memory leaks.
+// To enable the debugging, define the symbol DEBUG_MEM in the line
+// below.  This will result in text being sent to stdout that looks
+// like this:
+//   DEBUG UnicodeSet: ct 0x00A39B20; 397 [\u0A81-\u0A83\u0A85-
+//   DEBUG UnicodeSet: dt 0x00A39B20; 396 [\u0A81-\u0A83\u0A85-
+// Each line lists a construction (ct) or destruction (dt) event, the
+// object address, the number of outstanding objects after the event,
+// and the pattern of the object in question.
+
+// #define DEBUG_MEM
+
+#ifdef DEBUG_MEM
+#include <stdio.h>
+static int32_t _dbgCount = 0;
+
+static inline void _dbgct(UnicodeSet* set) {
+    UnicodeString str;
+    set->toPattern(str, TRUE);
+    char buf[40];
+    str.extract(0, 39, buf, "");
+    printf("DEBUG UnicodeSet: ct 0x%08X; %d %s\n", set, ++_dbgCount, buf);
+}
+
+static inline void _dbgdt(UnicodeSet* set) {
+    UnicodeString str;
+    set->toPattern(str, TRUE);
+    char buf[40];
+    str.extract(0, 39, buf, "");
+    printf("DEBUG UnicodeSet: dt 0x%08X; %d %s\n", set, --_dbgCount, buf);
+}
+
+#else
+
+#define _dbgct(set)
+#define _dbgdt(set)
+
+#endif
+
+//----------------------------------------------------------------
+// UnicodeString in UVector support
+//----------------------------------------------------------------
+
+static void U_CALLCONV cloneUnicodeString(UHashTok *dst, UHashTok *src) {
+    dst->pointer = new UnicodeString(*(UnicodeString*)src->pointer);
+}
+
+static int8_t U_CALLCONV compareUnicodeString(UHashTok t1, UHashTok t2) {
+    const UnicodeString &a = *(const UnicodeString*)t1.pointer;
+    const UnicodeString &b = *(const UnicodeString*)t2.pointer;
+    return a.compare(b);
+}
+
+//----------------------------------------------------------------
+// Constructors &c
+//----------------------------------------------------------------
+
+/**
+ * Constructs an empty set.
+ */
+UnicodeSet::UnicodeSet() :
+    len(1), capacity(1 + START_EXTRA), list(0), bmpSet(0), buffer(0),
+    bufferCapacity(0), patLen(0), pat(NULL), strings(NULL), stringSpan(NULL),
+    fFlags(0)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    allocateStrings(status);
+    if (U_FAILURE(status)) {
+        return;
+    }
+    list = (UChar32*) uprv_malloc(sizeof(UChar32) * capacity);
+    if(list!=NULL){
+        list[0] = UNICODESET_HIGH;
+    } else { // If memory allocation failed, set to bogus state.
+        setToBogus();
+        return;
+    }
+    _dbgct(this);
+}
+
+/**
+ * Constructs a set containing the given range. If <code>end >
+ * start</code> then an empty set is created.
+ *
+ * @param start first character, inclusive, of range
+ * @param end last character, inclusive, of range
+ */
+UnicodeSet::UnicodeSet(UChar32 start, UChar32 end) :
+    len(1), capacity(1 + START_EXTRA), list(0), bmpSet(0), buffer(0),
+    bufferCapacity(0), patLen(0), pat(NULL), strings(NULL), stringSpan(NULL),
+    fFlags(0)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    allocateStrings(status);
+    if (U_FAILURE(status)) {
+        return;
+    }
+    list = (UChar32*) uprv_malloc(sizeof(UChar32) * capacity);
+    if(list!=NULL){
+        list[0] = UNICODESET_HIGH;
+        complement(start, end);
+    } else { // If memory allocation failed, set to bogus state.
+        setToBogus();
+        return;
+    }
+    _dbgct(this);
+}
+
+/**
+ * Constructs a set that is identical to the given UnicodeSet.
+ */
+UnicodeSet::UnicodeSet(const UnicodeSet& o) :
+    UnicodeFilter(o),
+    len(0), capacity(o.isFrozen() ? o.len : o.len + GROW_EXTRA), list(0),
+    bmpSet(0),
+    buffer(0), bufferCapacity(0),
+    patLen(0), pat(NULL), strings(NULL), stringSpan(NULL),
+    fFlags(0)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    allocateStrings(status);
+    if (U_FAILURE(status)) {
+        return;
+    }
+    list = (UChar32*) uprv_malloc(sizeof(UChar32) * capacity);
+    if(list!=NULL){
+        *this = o;
+    } else { // If memory allocation failed, set to bogus state.
+        setToBogus();
+        return;
+    }
+    _dbgct(this);
+}
+
+// Copy-construct as thawed.
+UnicodeSet::UnicodeSet(const UnicodeSet& o, UBool /* asThawed */) :
+    UnicodeFilter(o),
+    len(0), capacity(o.len + GROW_EXTRA), list(0),
+    bmpSet(0),
+    buffer(0), bufferCapacity(0),
+    patLen(0), pat(NULL), strings(NULL), stringSpan(NULL),
+    fFlags(0)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    allocateStrings(status);
+    if (U_FAILURE(status)) {
+        return;
+    }
+    list = (UChar32*) uprv_malloc(sizeof(UChar32) * capacity);
+    if(list!=NULL){
+        // *this = o except for bmpSet and stringSpan
+        len = o.len;
+        uprv_memcpy(list, o.list, len*sizeof(UChar32));
+        if (strings != NULL && o.strings != NULL) {
+            strings->assign(*o.strings, cloneUnicodeString, status);
+        } else { // Invalid strings.
+            setToBogus();
+            return;
+        }
+        if (o.pat) {
+            setPattern(UnicodeString(o.pat, o.patLen));
+        }
+    } else { // If memory allocation failed, set to bogus state.
+        setToBogus();
+        return;
+    }
+    _dbgct(this);
+}
+
+/**
+ * Destructs the set.
+ */
+UnicodeSet::~UnicodeSet() {
+    _dbgdt(this); // first!
+    uprv_free(list);
+    delete bmpSet;
+    if (buffer) {
+        uprv_free(buffer);
+    }
+    delete strings;
+    delete stringSpan;
+    releasePattern();
+}
+
+/**
+ * Assigns this object to be a copy of another.
+ */
+UnicodeSet& UnicodeSet::operator=(const UnicodeSet& o) {
+    if (this == &o) {
+        return *this;
+    }
+    if (isFrozen()) {
+        return *this;
+    }
+    if (o.isBogus()) {
+        setToBogus();
+        return *this;
+    }
+    UErrorCode ec = U_ZERO_ERROR;
+    ensureCapacity(o.len, ec);
+    if (U_FAILURE(ec)) {
+        return *this; // There is no way to report this error :-(
+    }
+    len = o.len;
+    uprv_memcpy(list, o.list, len*sizeof(UChar32));
+    if (o.bmpSet == NULL) {
+        bmpSet = NULL;
+    } else {
+        bmpSet = new BMPSet(*o.bmpSet, list, len);
+        if (bmpSet == NULL) { // Check for memory allocation error.
+            setToBogus();
+            return *this;
+        }
+    }
+    if (strings != NULL && o.strings != NULL) {
+        strings->assign(*o.strings, cloneUnicodeString, ec);
+    } else { // Invalid strings.
+        setToBogus();
+        return *this;
+    }
+    if (o.stringSpan == NULL) {
+        stringSpan = NULL;
+    } else {
+        stringSpan = new UnicodeSetStringSpan(*o.stringSpan, *strings);
+        if (stringSpan == NULL) { // Check for memory allocation error.
+            setToBogus();
+            return *this;
+        }
+    }
+    releasePattern();
+    if (o.pat) {
+        setPattern(UnicodeString(o.pat, o.patLen));
+    }
+    return *this;
+}
+
+/**
+ * Returns a copy of this object.  All UnicodeMatcher objects have
+ * to support cloning in order to allow classes using
+ * UnicodeMatchers, such as Transliterator, to implement cloning.
+ */
+UnicodeFunctor* UnicodeSet::clone() const {
+    return new UnicodeSet(*this);
+}
+
+UnicodeFunctor *UnicodeSet::cloneAsThawed() const {
+    return new UnicodeSet(*this, TRUE);
+}
+
+/**
+ * Compares the specified object with this set for equality.  Returns
+ * <tt>true</tt> if the two sets
+ * have the same size, and every member of the specified set is
+ * contained in this set (or equivalently, every member of this set is
+ * contained in the specified set).
+ *
+ * @param o set to be compared for equality with this set.
+ * @return <tt>true</tt> if the specified set is equal to this set.
+ */
+UBool UnicodeSet::operator==(const UnicodeSet& o) const {
+    if (len != o.len) return FALSE;
+    for (int32_t i = 0; i < len; ++i) {
+        if (list[i] != o.list[i]) return FALSE;
+    }
+    if (*strings != *o.strings) return FALSE;
+    return TRUE;
+}
+
+/**
+ * Returns the hash code value for this set.
+ *
+ * @return the hash code value for this set.
+ * @see Object#hashCode()
+ */
+int32_t UnicodeSet::hashCode(void) const {
+    int32_t result = len;
+    for (int32_t i = 0; i < len; ++i) {
+        result *= 1000003;
+        result += list[i];
+    }
+    return result;
+}
+
+//----------------------------------------------------------------
+// Public API
+//----------------------------------------------------------------
+
+/**
+ * Returns the number of elements in this set (its cardinality),
+ * Note than the elements of a set may include both individual
+ * codepoints and strings.
+ *
+ * @return the number of elements in this set (its cardinality).
+ */
+int32_t UnicodeSet::size(void) const {
+    int32_t n = 0;
+    int32_t count = getRangeCount();
+    for (int32_t i = 0; i < count; ++i) {
+        n += getRangeEnd(i) - getRangeStart(i) + 1;
+    }
+    return n + strings->size();
+}
+
+/**
+ * Returns <tt>true</tt> if this set contains no elements.
+ *
+ * @return <tt>true</tt> if this set contains no elements.
+ */
+UBool UnicodeSet::isEmpty(void) const {
+    return len == 1 && strings->size() == 0;
+}
+
+/**
+ * Returns true if this set contains the given character.
+ * @param c character to be checked for containment
+ * @return true if the test condition is met
+ */
+UBool UnicodeSet::contains(UChar32 c) const {
+    // Set i to the index of the start item greater than ch
+    // We know we will terminate without length test!
+    // LATER: for large sets, add binary search
+    //int32_t i = -1;
+    //for (;;) {
+    //    if (c < list[++i]) break;
+    //}
+    if (bmpSet != NULL) {
+        return bmpSet->contains(c);
+    }
+    if (stringSpan != NULL) {
+        return stringSpan->contains(c);
+    }
+    if (c >= UNICODESET_HIGH) { // Don't need to check LOW bound
+        return FALSE;
+    }
+    int32_t i = findCodePoint(c);
+    return (UBool)(i & 1); // return true if odd
+}
+
+/**
+ * Returns the smallest value i such that c < list[i].  Caller
+ * must ensure that c is a legal value or this method will enter
+ * an infinite loop.  This method performs a binary search.
+ * @param c a character in the range MIN_VALUE..MAX_VALUE
+ * inclusive
+ * @return the smallest integer i in the range 0..len-1,
+ * inclusive, such that c < list[i]
+ */
+int32_t UnicodeSet::findCodePoint(UChar32 c) const {
+    /* Examples:
+                                       findCodePoint(c)
+       set              list[]         c=0 1 3 4 7 8
+       ===              ==============   ===========
+       []               [110000]         0 0 0 0 0 0
+       [\u0000-\u0003]  [0, 4, 110000]   1 1 1 2 2 2
+       [\u0004-\u0007]  [4, 8, 110000]   0 0 0 1 1 2
+       [:Any:]          [0, 110000]      1 1 1 1 1 1
+     */
+
+    // Return the smallest i such that c < list[i].  Assume
+    // list[len - 1] == HIGH and that c is legal (0..HIGH-1).
+    if (c < list[0])
+        return 0;
+    // High runner test.  c is often after the last range, so an
+    // initial check for this condition pays off.
+    int32_t lo = 0;
+    int32_t hi = len - 1;
+    if (lo >= hi || c >= list[hi-1])
+        return hi;
+    // invariant: c >= list[lo]
+    // invariant: c < list[hi]
+    for (;;) {
+        int32_t i = (lo + hi) >> 1;
+        if (i == lo) {
+            break; // Found!
+        } else if (c < list[i]) {
+            hi = i;
+        } else {
+            lo = i;
+        }
+    }
+    return hi;
+}
+
+/**
+ * Returns true if this set contains every character
+ * of the given range.
+ * @param start first character, inclusive, of the range
+ * @param end last character, inclusive, of the range
+ * @return true if the test condition is met
+ */
+UBool UnicodeSet::contains(UChar32 start, UChar32 end) const {
+    //int32_t i = -1;
+    //for (;;) {
+    //    if (start < list[++i]) break;
+    //}
+    int32_t i = findCodePoint(start);
+    return ((i & 1) != 0 && end < list[i]);
+}
+
+/**
+ * Returns <tt>true</tt> if this set contains the given
+ * multicharacter string.
+ * @param s string to be checked for containment
+ * @return <tt>true</tt> if this set contains the specified string
+ */
+UBool UnicodeSet::contains(const UnicodeString& s) const {
+    if (s.length() == 0) return FALSE;
+    int32_t cp = getSingleCP(s);
+    if (cp < 0) {
+        return strings->contains((void*) &s);
+    } else {
+        return contains((UChar32) cp);
+    }
+}
+
+/**
+ * Returns true if this set contains all the characters and strings
+ * of the given set.
+ * @param c set to be checked for containment
+ * @return true if the test condition is met
+ */
+UBool UnicodeSet::containsAll(const UnicodeSet& c) const {
+    // The specified set is a subset if all of its pairs are contained in
+    // this set.  It's possible to code this more efficiently in terms of
+    // direct manipulation of the inversion lists if the need arises.
+    int32_t n = c.getRangeCount();
+    for (int i=0; i<n; ++i) {
+        if (!contains(c.getRangeStart(i), c.getRangeEnd(i))) {
+            return FALSE;
+        }
+    }
+    if (!strings->containsAll(*c.strings)) return FALSE;
+    return TRUE;
+}
+
+/**
+ * Returns true if this set contains all the characters
+ * of the given string.
+ * @param s string containing characters to be checked for containment
+ * @return true if the test condition is met
+ */
+UBool UnicodeSet::containsAll(const UnicodeString& s) const {
+    return (UBool)(span(s.getBuffer(), s.length(), USET_SPAN_CONTAINED) ==
+                   s.length());
+}
+
+/**
+ * Returns true if this set contains none of the characters
+ * of the given range.
+ * @param start first character, inclusive, of the range
+ * @param end last character, inclusive, of the range
+ * @return true if the test condition is met
+ */
+UBool UnicodeSet::containsNone(UChar32 start, UChar32 end) const {
+    //int32_t i = -1;
+    //for (;;) {
+    //    if (start < list[++i]) break;
+    //}
+    int32_t i = findCodePoint(start);
+    return ((i & 1) == 0 && end < list[i]);
+}
+
+/**
+ * Returns true if this set contains none of the characters and strings
+ * of the given set.
+ * @param c set to be checked for containment
+ * @return true if the test condition is met
+ */
+UBool UnicodeSet::containsNone(const UnicodeSet& c) const {
+    // The specified set is a subset if all of its pairs are contained in
+    // this set.  It's possible to code this more efficiently in terms of
+    // direct manipulation of the inversion lists if the need arises.
+    int32_t n = c.getRangeCount();
+    for (int32_t i=0; i<n; ++i) {
+        if (!containsNone(c.getRangeStart(i), c.getRangeEnd(i))) {
+            return FALSE;
+        }
+    }
+    if (!strings->containsNone(*c.strings)) return FALSE;
+    return TRUE;
+}
+
+/**
+ * Returns true if this set contains none of the characters
+ * of the given string.
+ * @param s string containing characters to be checked for containment
+ * @return true if the test condition is met
+ */
+UBool UnicodeSet::containsNone(const UnicodeString& s) const {
+    return (UBool)(span(s.getBuffer(), s.length(), USET_SPAN_NOT_CONTAINED) ==
+                   s.length());
+}
+
+/**
+ * Returns <tt>true</tt> if this set contains any character whose low byte
+ * is the given value.  This is used by <tt>RuleBasedTransliterator</tt> for
+ * indexing.
+ */
+UBool UnicodeSet::matchesIndexValue(uint8_t v) const {
+    /* The index value v, in the range [0,255], is contained in this set if
+     * it is contained in any pair of this set.  Pairs either have the high
+     * bytes equal, or unequal.  If the high bytes are equal, then we have
+     * aaxx..aayy, where aa is the high byte.  Then v is contained if xx <=
+     * v <= yy.  If the high bytes are unequal we have aaxx..bbyy, bb>aa.
+     * Then v is contained if xx <= v || v <= yy.  (This is identical to the
+     * time zone month containment logic.)
+     */
+    int32_t i;
+    int32_t rangeCount=getRangeCount();
+    for (i=0; i<rangeCount; ++i) {
+        UChar32 low = getRangeStart(i);
+        UChar32 high = getRangeEnd(i);
+        if ((low & ~0xFF) == (high & ~0xFF)) {
+            if ((low & 0xFF) <= v && v <= (high & 0xFF)) {
+                return TRUE;
+            }
+        } else if ((low & 0xFF) <= v || v <= (high & 0xFF)) {
+            return TRUE;
+        }
+    }
+    if (strings->size() != 0) {
+        for (i=0; i<strings->size(); ++i) {
+            const UnicodeString& s = *(const UnicodeString*)strings->elementAt(i);
+            //if (s.length() == 0) {
+            //    // Empty strings match everything
+            //    return TRUE;
+            //}
+            // assert(s.length() != 0); // We enforce this elsewhere
+            UChar32 c = s.char32At(0);
+            if ((c & 0xFF) == v) {
+                return TRUE;
+            }
+        }
+    }
+    return FALSE;
+}
+
+/**
+ * Implementation of UnicodeMatcher::matches().  Always matches the
+ * longest possible multichar string.
+ */
+UMatchDegree UnicodeSet::matches(const Replaceable& text,
+                                 int32_t& offset,
+                                 int32_t limit,
+                                 UBool incremental) {
+    if (offset == limit) {
+        // Strings, if any, have length != 0, so we don't worry
+        // about them here.  If we ever allow zero-length strings
+        // we much check for them here.
+        if (contains(U_ETHER)) {
+            return incremental ? U_PARTIAL_MATCH : U_MATCH;
+        } else {
+            return U_MISMATCH;
+        }
+    } else {
+        if (strings->size() != 0) { // try strings first
+
+            // might separate forward and backward loops later
+            // for now they are combined
+
+            // TODO Improve efficiency of this, at least in the forward
+            // direction, if not in both.  In the forward direction we
+            // can assume the strings are sorted.
+
+            int32_t i;
+            UBool forward = offset < limit;
+
+            // firstChar is the leftmost char to match in the
+            // forward direction or the rightmost char to match in
+            // the reverse direction.
+            UChar firstChar = text.charAt(offset);
+
+            // If there are multiple strings that can match we
+            // return the longest match.
+            int32_t highWaterLength = 0;
+
+            for (i=0; i<strings->size(); ++i) {
+                const UnicodeString& trial = *(const UnicodeString*)strings->elementAt(i);
+
+                //if (trial.length() == 0) {
+                //    return U_MATCH; // null-string always matches
+                //}
+                // assert(trial.length() != 0); // We ensure this elsewhere
+
+                UChar c = trial.charAt(forward ? 0 : trial.length() - 1);
+
+                // Strings are sorted, so we can optimize in the
+                // forward direction.
+                if (forward && c > firstChar) break;
+                if (c != firstChar) continue;
+
+                int32_t matchLen = matchRest(text, offset, limit, trial);
+
+                if (incremental) {
+                    int32_t maxLen = forward ? limit-offset : offset-limit;
+                    if (matchLen == maxLen) {
+                        // We have successfully matched but only up to limit.
+                        return U_PARTIAL_MATCH;
+                    }
+                }
+
+                if (matchLen == trial.length()) {
+                    // We have successfully matched the whole string.
+                    if (matchLen > highWaterLength) {
+                        highWaterLength = matchLen;
+                    }
+                    // In the forward direction we know strings
+                    // are sorted so we can bail early.
+                    if (forward && matchLen < highWaterLength) {
+                        break;
+                    }
+                    continue;
+                }
+            }
+
+            // We've checked all strings without a partial match.
+            // If we have full matches, return the longest one.
+            if (highWaterLength != 0) {
+                offset += forward ? highWaterLength : -highWaterLength;
+                return U_MATCH;
+            }
+        }
+        return UnicodeFilter::matches(text, offset, limit, incremental);
+    }
+}
+
+/**
+ * Returns the longest match for s in text at the given position.
+ * If limit > start then match forward from start+1 to limit
+ * matching all characters except s.charAt(0).  If limit < start,
+ * go backward starting from start-1 matching all characters
+ * except s.charAt(s.length()-1).  This method assumes that the
+ * first character, text.charAt(start), matches s, so it does not
+ * check it.
+ * @param text the text to match
+ * @param start the first character to match.  In the forward
+ * direction, text.charAt(start) is matched against s.charAt(0).
+ * In the reverse direction, it is matched against
+ * s.charAt(s.length()-1).
+ * @param limit the limit offset for matching, either last+1 in
+ * the forward direction, or last-1 in the reverse direction,
+ * where last is the index of the last character to match.
+ * @return If part of s matches up to the limit, return |limit -
+ * start|.  If all of s matches before reaching the limit, return
+ * s.length().  If there is a mismatch between s and text, return
+ * 0
+ */
+int32_t UnicodeSet::matchRest(const Replaceable& text,
+                              int32_t start, int32_t limit,
+                              const UnicodeString& s) {
+    int32_t i;
+    int32_t maxLen;
+    int32_t slen = s.length();
+    if (start < limit) {
+        maxLen = limit - start;
+        if (maxLen > slen) maxLen = slen;
+        for (i = 1; i < maxLen; ++i) {
+            if (text.charAt(start + i) != s.charAt(i)) return 0;
+        }
+    } else {
+        maxLen = start - limit;
+        if (maxLen > slen) maxLen = slen;
+        --slen; // <=> slen = s.length() - 1;
+        for (i = 1; i < maxLen; ++i) {
+            if (text.charAt(start - i) != s.charAt(slen - i)) return 0;
+        }
+    }
+    return maxLen;
+}
+
+/**
+ * Implement of UnicodeMatcher
+ */
+void UnicodeSet::addMatchSetTo(UnicodeSet& toUnionTo) const {
+    toUnionTo.addAll(*this);
+}
+
+/**
+ * Returns the index of the given character within this set, where
+ * the set is ordered by ascending code point.  If the character
+ * is not in this set, return -1.  The inverse of this method is
+ * <code>charAt()</code>.
+ * @return an index from 0..size()-1, or -1
+ */
+int32_t UnicodeSet::indexOf(UChar32 c) const {
+    if (c < MIN_VALUE || c > MAX_VALUE) {
+        return -1;
+    }
+    int32_t i = 0;
+    int32_t n = 0;
+    for (;;) {
+        UChar32 start = list[i++];
+        if (c < start) {
+            return -1;
+        }
+        UChar32 limit = list[i++];
+        if (c < limit) {
+            return n + c - start;
+        }
+        n += limit - start;
+    }
+}
+
+/**
+ * Returns the character at the given index within this set, where
+ * the set is ordered by ascending code point.  If the index is
+ * out of range, return (UChar32)-1.  The inverse of this method is
+ * <code>indexOf()</code>.
+ * @param index an index from 0..size()-1
+ * @return the character at the given index, or (UChar32)-1.
+ */
+UChar32 UnicodeSet::charAt(int32_t index) const {
+    if (index >= 0) {
+        // len2 is the largest even integer <= len, that is, it is len
+        // for even values and len-1 for odd values.  With odd values
+        // the last entry is UNICODESET_HIGH.
+        int32_t len2 = len & ~1;
+        for (int32_t i=0; i < len2;) {
+            UChar32 start = list[i++];
+            int32_t count = list[i++] - start;
+            if (index < count) {
+                return (UChar32)(start + index);
+            }
+            index -= count;
+        }
+    }
+    return (UChar32)-1;
+}
+
+/**
+ * Make this object represent the range <code>start - end</code>.
+ * If <code>end > start</code> then this object is set to an
+ * an empty range.
+ *
+ * @param start first character in the set, inclusive
+ * @rparam end last character in the set, inclusive
+ */
+UnicodeSet& UnicodeSet::set(UChar32 start, UChar32 end) {
+    clear();
+    complement(start, end);
+    return *this;
+}
+
+/**
+ * Adds the specified range to this set if it is not already
+ * present.  If this set already contains the specified range,
+ * the call leaves this set unchanged.  If <code>end > start</code>
+ * then an empty range is added, leaving the set unchanged.
+ *
+ * @param start first character, inclusive, of range to be added
+ * to this set.
+ * @param end last character, inclusive, of range to be added
+ * to this set.
+ */
+UnicodeSet& UnicodeSet::add(UChar32 start, UChar32 end) {
+    if (pinCodePoint(start) < pinCodePoint(end)) {
+        UChar32 range[3] = { start, end+1, UNICODESET_HIGH };
+        add(range, 2, 0);
+    } else if (start == end) {
+        add(start);
+    }
+    return *this;
+}
+
+// #define DEBUG_US_ADD
+
+#ifdef DEBUG_US_ADD
+#include <stdio.h>
+void dump(UChar32 c) {
+    if (c <= 0xFF) {
+        printf("%c", (char)c);
+    } else {
+        printf("U+%04X", c);
+    }
+}
+void dump(const UChar32* list, int32_t len) {
+    printf("[");
+    for (int32_t i=0; i<len; ++i) {
+        if (i != 0) printf(", ");
+        dump(list[i]);
+    }
+    printf("]");
+}
+#endif
+
+/**
+ * Adds the specified character to this set if it is not already
+ * present.  If this set already contains the specified character,
+ * the call leaves this set unchanged.
+ */
+UnicodeSet& UnicodeSet::add(UChar32 c) {
+    // find smallest i such that c < list[i]
+    // if odd, then it is IN the set
+    // if even, then it is OUT of the set
+    int32_t i = findCodePoint(pinCodePoint(c));
+
+    // already in set?
+    if ((i & 1) != 0  || isFrozen() || isBogus()) return *this;
+
+    // HIGH is 0x110000
+    // assert(list[len-1] == HIGH);
+
+    // empty = [HIGH]
+    // [start_0, limit_0, start_1, limit_1, HIGH]
+
+    // [..., start_k-1, limit_k-1, start_k, limit_k, ..., HIGH]
+    //                             ^
+    //                             list[i]
+
+    // i == 0 means c is before the first range
+
+#ifdef DEBUG_US_ADD
+    printf("Add of ");
+    dump(c);
+    printf(" found at %d", i);
+    printf(": ");
+    dump(list, len);
+    printf(" => ");
+#endif
+
+    if (c == list[i]-1) {
+        // c is before start of next range
+        list[i] = c;
+        // if we touched the HIGH mark, then add a new one
+        if (c == (UNICODESET_HIGH - 1)) {
+            UErrorCode status = U_ZERO_ERROR;
+            ensureCapacity(len+1, status);
+            if (U_FAILURE(status)) {
+                return *this; // There is no way to report this error :-(
+            }
+            list[len++] = UNICODESET_HIGH;
+        }
+        if (i > 0 && c == list[i-1]) {
+            // collapse adjacent ranges
+
+            // [..., start_k-1, c, c, limit_k, ..., HIGH]
+            //                     ^
+            //                     list[i]
+
+            //for (int32_t k=i-1; k<len-2; ++k) {
+            //    list[k] = list[k+2];
+            //}
+            UChar32* dst = list + i - 1;
+            UChar32* src = dst + 2;
+            UChar32* srclimit = list + len;
+            while (src < srclimit) *(dst++) = *(src++);
+
+            len -= 2;
+        }
+    }
+
+    else if (i > 0 && c == list[i-1]) {
+        // c is after end of prior range
+        list[i-1]++;
+        // no need to check for collapse here
+    }
+
+    else {
+        // At this point we know the new char is not adjacent to
+        // any existing ranges, and it is not 10FFFF.
+
+
+        // [..., start_k-1, limit_k-1, start_k, limit_k, ..., HIGH]
+        //                             ^
+        //                             list[i]
+
+        // [..., start_k-1, limit_k-1, c, c+1, start_k, limit_k, ..., HIGH]
+        //                             ^
+        //                             list[i]
+
+        UErrorCode status = U_ZERO_ERROR;
+        ensureCapacity(len+2, status);
+        if (U_FAILURE(status)) {
+            return *this; // There is no way to report this error :-(
+        }
+
+        //for (int32_t k=len-1; k>=i; --k) {
+        //    list[k+2] = list[k];
+        //}
+        UChar32* src = list + len;
+        UChar32* dst = src + 2;
+        UChar32* srclimit = list + i;
+        while (src > srclimit) *(--dst) = *(--src);
+
+        list[i] = c;
+        list[i+1] = c+1;
+        len += 2;
+    }
+
+#ifdef DEBUG_US_ADD
+    dump(list, len);
+    printf("\n");
+
+    for (i=1; i<len; ++i) {
+        if (list[i] <= list[i-1]) {
+            // Corrupt array!
+            printf("ERROR: list has been corrupted\n");
+            exit(1);
+        }
+    }
+#endif
+
+    releasePattern();
+    return *this;
+}
+
+/**
+ * Adds the specified multicharacter to this set if it is not already
+ * present.  If this set already contains the multicharacter,
+ * the call leaves this set unchanged.
+ * Thus "ch" => {"ch"}
+ * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
+ * @param s the source string
+ * @return the modified set, for chaining
+ */
+UnicodeSet& UnicodeSet::add(const UnicodeString& s) {
+    if (s.length() == 0 || isFrozen() || isBogus()) return *this;
+    int32_t cp = getSingleCP(s);
+    if (cp < 0) {
+        if (!strings->contains((void*) &s)) {
+            _add(s);
+            releasePattern();
+        }
+    } else {
+        add((UChar32)cp);
+    }
+    return *this;
+}
+
+/**
+ * Adds the given string, in order, to 'strings'.  The given string
+ * must have been checked by the caller to not be empty and to not
+ * already be in 'strings'.
+ */
+void UnicodeSet::_add(const UnicodeString& s) {
+    if (isFrozen() || isBogus()) {
+        return;
+    }
+    UnicodeString* t = new UnicodeString(s);
+    if (t == NULL) { // Check for memory allocation error.
+        setToBogus();
+        return;
+    }
+    UErrorCode ec = U_ZERO_ERROR;
+    strings->sortedInsert(t, compareUnicodeString, ec);
+    if (U_FAILURE(ec)) {
+        setToBogus();
+        delete t;
+    }
+}
+
+/**
+ * @return a code point IF the string consists of a single one.
+ * otherwise returns -1.
+ * @param string to test
+ */
+int32_t UnicodeSet::getSingleCP(const UnicodeString& s) {
+    //if (s.length() < 1) {
+    //    throw new IllegalArgumentException("Can't use zero-length strings in UnicodeSet");
+    //}
+    if (s.length() > 2) return -1;
+    if (s.length() == 1) return s.charAt(0);
+
+    // at this point, len = 2
+    UChar32 cp = s.char32At(0);
+    if (cp > 0xFFFF) { // is surrogate pair
+        return cp;
+    }
+    return -1;
+}
+
+/**
+ * Adds each of the characters in this string to the set. Thus "ch" => {"c", "h"}
+ * If this set already any particular character, it has no effect on that character.
+ * @param the source string
+ * @return the modified set, for chaining
+ */
+UnicodeSet& UnicodeSet::addAll(const UnicodeString& s) {
+    UChar32 cp;
+    for (int32_t i = 0; i < s.length(); i += UTF_CHAR_LENGTH(cp)) {
+        cp = s.char32At(i);
+        add(cp);
+    }
+    return *this;
+}
+
+/**
+ * Retains EACH of the characters in this string. Note: "ch" == {"c", "h"}
+ * If this set already any particular character, it has no effect on that character.
+ * @param the source string
+ * @return the modified set, for chaining
+ */
+UnicodeSet& UnicodeSet::retainAll(const UnicodeString& s) {
+    UnicodeSet set;
+    set.addAll(s);
+    retainAll(set);
+    return *this;
+}
+
+/**
+ * Complement EACH of the characters in this string. Note: "ch" == {"c", "h"}
+ * If this set already any particular character, it has no effect on that character.
+ * @param the source string
+ * @return the modified set, for chaining
+ */
+UnicodeSet& UnicodeSet::complementAll(const UnicodeString& s) {
+    UnicodeSet set;
+    set.addAll(s);
+    complementAll(set);
+    return *this;
+}
+
+/**
+ * Remove EACH of the characters in this string. Note: "ch" == {"c", "h"}
+ * If this set already any particular character, it has no effect on that character.
+ * @param the source string
+ * @return the modified set, for chaining
+ */
+UnicodeSet& UnicodeSet::removeAll(const UnicodeString& s) {
+    UnicodeSet set;
+    set.addAll(s);
+    removeAll(set);
+    return *this;
+}
+
+UnicodeSet& UnicodeSet::removeAllStrings() {
+    strings->removeAllElements();
+    return *this;
+}
+
+
+/**
+ * Makes a set from a multicharacter string. Thus "ch" => {"ch"}
+ * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
+ * @param the source string
+ * @return a newly created set containing the given string
+ */
+UnicodeSet* U_EXPORT2 UnicodeSet::createFrom(const UnicodeString& s) {
+    UnicodeSet *set = new UnicodeSet();
+    if (set != NULL) { // Check for memory allocation error.
+        set->add(s);
+    }
+    return set;
+}
+
+
+/**
+ * Makes a set from each of the characters in the string. Thus "ch" => {"c", "h"}
+ * @param the source string
+ * @return a newly created set containing the given characters
+ */
+UnicodeSet* U_EXPORT2 UnicodeSet::createFromAll(const UnicodeString& s) {
+    UnicodeSet *set = new UnicodeSet();
+    if (set != NULL) { // Check for memory allocation error.
+        set->addAll(s);
+    }
+    return set;
+}
+
+/**
+ * Retain only the elements in this set that are contained in the
+ * specified range.  If <code>end > start</code> then an empty range is
+ * retained, leaving the set empty.
+ *
+ * @param start first character, inclusive, of range to be retained
+ * to this set.
+ * @param end last character, inclusive, of range to be retained
+ * to this set.
+ */
+UnicodeSet& UnicodeSet::retain(UChar32 start, UChar32 end) {
+    if (pinCodePoint(start) <= pinCodePoint(end)) {
+        UChar32 range[3] = { start, end+1, UNICODESET_HIGH };
+        retain(range, 2, 0);
+    } else {
+        clear();
+    }
+    return *this;
+}
+
+UnicodeSet& UnicodeSet::retain(UChar32 c) {
+    return retain(c, c);
+}
+
+/**
+ * Removes the specified range from this set if it is present.
+ * The set will not contain the specified range once the call
+ * returns.  If <code>end > start</code> then an empty range is
+ * removed, leaving the set unchanged.
+ *
+ * @param start first character, inclusive, of range to be removed
+ * from this set.
+ * @param end last character, inclusive, of range to be removed
+ * from this set.
+ */
+UnicodeSet& UnicodeSet::remove(UChar32 start, UChar32 end) {
+    if (pinCodePoint(start) <= pinCodePoint(end)) {
+        UChar32 range[3] = { start, end+1, UNICODESET_HIGH };
+        retain(range, 2, 2);
+    }
+    return *this;
+}
+
+/**
+ * Removes the specified character from this set if it is present.
+ * The set will not contain the specified range once the call
+ * returns.
+ */
+UnicodeSet& UnicodeSet::remove(UChar32 c) {
+    return remove(c, c);
+}
+
+/**
+ * Removes the specified string from this set if it is present.
+ * The set will not contain the specified character once the call
+ * returns.
+ * @param the source string
+ * @return the modified set, for chaining
+ */
+UnicodeSet& UnicodeSet::remove(const UnicodeString& s) {
+    if (s.length() == 0 || isFrozen() || isBogus()) return *this;
+    int32_t cp = getSingleCP(s);
+    if (cp < 0) {
+        strings->removeElement((void*) &s);
+        releasePattern();
+    } else {
+        remove((UChar32)cp, (UChar32)cp);
+    }
+    return *this;
+}
+
+/**
+ * Complements the specified range in this set.  Any character in
+ * the range will be removed if it is in this set, or will be
+ * added if it is not in this set.  If <code>end > start</code>
+ * then an empty range is xor'ed, leaving the set unchanged.
+ *
+ * @param start first character, inclusive, of range to be removed
+ * from this set.
+ * @param end last character, inclusive, of range to be removed
+ * from this set.
+ */
+UnicodeSet& UnicodeSet::complement(UChar32 start, UChar32 end) {
+    if (isFrozen() || isBogus()) {
+        return *this;
+    }
+    if (pinCodePoint(start) <= pinCodePoint(end)) {
+        UChar32 range[3] = { start, end+1, UNICODESET_HIGH };
+        exclusiveOr(range, 2, 0);
+    }
+    releasePattern();
+    return *this;
+}
+
+UnicodeSet& UnicodeSet::complement(UChar32 c) {
+    return complement(c, c);
+}
+
+/**
+ * This is equivalent to
+ * <code>complement(MIN_VALUE, MAX_VALUE)</code>.
+ */
+UnicodeSet& UnicodeSet::complement(void) {
+    if (isFrozen() || isBogus()) {
+        return *this;
+    }
+    UErrorCode status = U_ZERO_ERROR;
+    if (list[0] == UNICODESET_LOW) {
+        ensureBufferCapacity(len-1, status);
+        if (U_FAILURE(status)) {
+            return *this;
+        }
+        uprv_memcpy(buffer, list + 1, (len-1)*sizeof(UChar32));
+        --len;
+    } else {
+        ensureBufferCapacity(len+1, status);
+        if (U_FAILURE(status)) {
+            return *this;
+        }
+        uprv_memcpy(buffer + 1, list, len*sizeof(UChar32));
+        buffer[0] = UNICODESET_LOW;
+        ++len;
+    }
+    swapBuffers();
+    releasePattern();
+    return *this;
+}
+
+/**
+ * Complement the specified string in this set.
+ * The set will not contain the specified string once the call
+ * returns.
+ * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
+ * @param s the string to complement
+ * @return this object, for chaining
+ */
+UnicodeSet& UnicodeSet::complement(const UnicodeString& s) {
+    if (s.length() == 0 || isFrozen() || isBogus()) return *this;
+    int32_t cp = getSingleCP(s);
+    if (cp < 0) {
+        if (strings->contains((void*) &s)) {
+            strings->removeElement((void*) &s);
+        } else {
+            _add(s);
+        }
+        releasePattern();
+    } else {
+        complement((UChar32)cp, (UChar32)cp);
+    }
+    return *this;
+}
+
+/**
+ * Adds all of the elements in the specified set to this set if
+ * they're not already present.  This operation effectively
+ * modifies this set so that its value is the <i>union</i> of the two
+ * sets.  The behavior of this operation is unspecified if the specified
+ * collection is modified while the operation is in progress.
+ *
+ * @param c set whose elements are to be added to this set.
+ * @see #add(char, char)
+ */
+UnicodeSet& UnicodeSet::addAll(const UnicodeSet& c) {
+    if ( c.len>0 && c.list!=NULL ) {
+        add(c.list, c.len, 0);
+    }
+
+    // Add strings in order
+    if ( c.strings!=NULL ) {
+        for (int32_t i=0; i<c.strings->size(); ++i) {
+            const UnicodeString* s = (const UnicodeString*)c.strings->elementAt(i);
+            if (!strings->contains((void*) s)) {
+                _add(*s);
+            }
+        }
+    }
+    return *this;
+}
+
+/**
+ * Retains only the elements in this set that are contained in the
+ * specified set.  In other words, removes from this set all of
+ * its elements that are not contained in the specified set.  This
+ * operation effectively modifies this set so that its value is
+ * the <i>intersection</i> of the two sets.
+ *
+ * @param c set that defines which elements this set will retain.
+ */
+UnicodeSet& UnicodeSet::retainAll(const UnicodeSet& c) {
+    if (isFrozen() || isBogus()) {
+        return *this;
+    }
+    retain(c.list, c.len, 0);
+    strings->retainAll(*c.strings);
+    return *this;
+}
+
+/**
+ * Removes from this set all of its elements that are contained in the
+ * specified set.  This operation effectively modifies this
+ * set so that its value is the <i>asymmetric set difference</i> of
+ * the two sets.
+ *
+ * @param c set that defines which elements will be removed from
+ *          this set.
+ */
+UnicodeSet& UnicodeSet::removeAll(const UnicodeSet& c) {
+    if (isFrozen() || isBogus()) {
+        return *this;
+    }
+    retain(c.list, c.len, 2);
+    strings->removeAll(*c.strings);
+    return *this;
+}
+
+/**
+ * Complements in this set all elements contained in the specified
+ * set.  Any character in the other set will be removed if it is
+ * in this set, or will be added if it is not in this set.
+ *
+ * @param c set that defines which elements will be xor'ed from
+ *          this set.
+ */
+UnicodeSet& UnicodeSet::complementAll(const UnicodeSet& c) {
+    if (isFrozen() || isBogus()) {
+        return *this;
+    }
+    exclusiveOr(c.list, c.len, 0);
+
+    for (int32_t i=0; i<c.strings->size(); ++i) {
+        void* e = c.strings->elementAt(i);
+        if (!strings->removeElement(e)) {
+            _add(*(const UnicodeString*)e);
+        }
+    }
+    return *this;
+}
+
+/**
+ * Removes all of the elements from this set.  This set will be
+ * empty after this call returns.
+ */
+UnicodeSet& UnicodeSet::clear(void) {
+    if (isFrozen()) {
+        return *this;
+    }
+    if (list != NULL) {
+        list[0] = UNICODESET_HIGH;
+    }
+    len = 1;
+    releasePattern();
+    if (strings != NULL) {
+        strings->removeAllElements();
+    }
+    if (list != NULL && strings != NULL) {
+        // Remove bogus
+        fFlags = 0;
+    }
+    return *this;
+}
+
+/**
+ * Iteration method that returns the number of ranges contained in
+ * this set.
+ * @see #getRangeStart
+ * @see #getRangeEnd
+ */
+int32_t UnicodeSet::getRangeCount() const {
+    return len/2;
+}
+
+/**
+ * Iteration method that returns the first character in the
+ * specified range of this set.
+ * @see #getRangeCount
+ * @see #getRangeEnd
+ */
+UChar32 UnicodeSet::getRangeStart(int32_t index) const {
+    return list[index*2];
+}
+
+/**
+ * Iteration method that returns the last character in the
+ * specified range of this set.
+ * @see #getRangeStart
+ * @see #getRangeEnd
+ */
+UChar32 UnicodeSet::getRangeEnd(int32_t index) const {
+    return list[index*2 + 1] - 1;
+}
+
+int32_t UnicodeSet::getStringCount() const {
+    return strings->size();
+}
+
+const UnicodeString* UnicodeSet::getString(int32_t index) const {
+    return (const UnicodeString*) strings->elementAt(index);
+}
+
+/**
+ * Reallocate this objects internal structures to take up the least
+ * possible space, without changing this object's value.
+ */
+UnicodeSet& UnicodeSet::compact() {
+    if (isFrozen() || isBogus()) {
+        return *this;
+    }
+    // Delete buffer first to defragment memory less.
+    if (buffer != NULL) {
+        uprv_free(buffer);
+        buffer = NULL;
+    }
+    if (len < capacity) {
+        // Make the capacity equal to len or 1.
+        // We don't want to realloc of 0 size.
+        int32_t newCapacity = len + (len == 0);
+        UChar32* temp = (UChar32*) uprv_realloc(list, sizeof(UChar32) * newCapacity);
+        if (temp) {
+            list = temp;
+            capacity = newCapacity;
+        }
+        // else what the heck happened?! We allocated less memory!
+        // Oh well. We'll keep our original array.
+    }
+    return *this;
+}
+
+int32_t UnicodeSet::serialize(uint16_t *dest, int32_t destCapacity, UErrorCode& ec) const {
+    int32_t bmpLength, length, destLength;
+
+    if (U_FAILURE(ec)) {
+        return 0;
+    }
+
+    if (destCapacity<0 || (destCapacity>0 && dest==NULL)) {
+        ec=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* count necessary 16-bit units */
+    length=this->len-1; // Subtract 1 to ignore final UNICODESET_HIGH
+    // assert(length>=0);
+    if (length==0) {
+        /* empty set */
+        if (destCapacity>0) {
+            *dest=0;
+        } else {
+            ec=U_BUFFER_OVERFLOW_ERROR;
+        }
+        return 1;
+    }
+    /* now length>0 */
+
+    if (this->list[length-1]<=0xffff) {
+        /* all BMP */
+        bmpLength=length;
+    } else if (this->list[0]>=0x10000) {
+        /* all supplementary */
+        bmpLength=0;
+        length*=2;
+    } else {
+        /* some BMP, some supplementary */
+        for (bmpLength=0; bmpLength<length && this->list[bmpLength]<=0xffff; ++bmpLength) {}
+        length=bmpLength+2*(length-bmpLength);
+    }
+
+    /* length: number of 16-bit array units */
+    if (length>0x7fff) {
+        /* there are only 15 bits for the length in the first serialized word */
+        ec=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0;
+    }
+
+    /*
+     * total serialized length:
+     * number of 16-bit array units (length) +
+     * 1 length unit (always) +
+     * 1 bmpLength unit (if there are supplementary values)
+     */
+    destLength=length+((length>bmpLength)?2:1);
+    if (destLength<=destCapacity) {
+        const UChar32 *p;
+        int32_t i;
+
+        *dest=(uint16_t)length;
+        if (length>bmpLength) {
+            *dest|=0x8000;
+            *++dest=(uint16_t)bmpLength;
+        }
+        ++dest;
+
+        /* write the BMP part of the array */
+        p=this->list;
+        for (i=0; i<bmpLength; ++i) {
+            *dest++=(uint16_t)*p++;
+        }
+
+        /* write the supplementary part of the array */
+        for (; i<length; i+=2) {
+            *dest++=(uint16_t)(*p>>16);
+            *dest++=(uint16_t)*p++;
+        }
+    } else {
+        ec=U_BUFFER_OVERFLOW_ERROR;
+    }
+    return destLength;
+}
+
+//----------------------------------------------------------------
+// Implementation: Utility methods
+//----------------------------------------------------------------
+
+/**
+ * Allocate our strings vector and return TRUE if successful.
+ */
+UBool UnicodeSet::allocateStrings(UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return FALSE;
+    }
+    strings = new UVector(uhash_deleteUnicodeString,
+                          uhash_compareUnicodeString, 1, status);
+    if (strings == NULL) { // Check for memory allocation error.
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return FALSE;
+    }
+    if (U_FAILURE(status)) {
+        delete strings;
+        strings = NULL;
+        return FALSE;
+    } 
+    return TRUE;
+}
+
+void UnicodeSet::ensureCapacity(int32_t newLen, UErrorCode& ec) {
+    if (newLen <= capacity)
+        return;
+    UChar32* temp = (UChar32*) uprv_realloc(list, sizeof(UChar32) * (newLen + GROW_EXTRA));
+    if (temp == NULL) {
+        ec = U_MEMORY_ALLOCATION_ERROR;
+        setToBogus();
+        return;
+    }
+    list = temp;
+    capacity = newLen + GROW_EXTRA;
+    // else we keep the original contents on the memory failure.
+}
+
+void UnicodeSet::ensureBufferCapacity(int32_t newLen, UErrorCode& ec) {
+    if (buffer != NULL && newLen <= bufferCapacity)
+        return;
+    UChar32* temp = (UChar32*) uprv_realloc(buffer, sizeof(UChar32) * (newLen + GROW_EXTRA));
+    if (temp == NULL) {
+        ec = U_MEMORY_ALLOCATION_ERROR;
+        setToBogus();
+        return;
+    }
+    buffer = temp;
+    bufferCapacity = newLen + GROW_EXTRA;
+    // else we keep the original contents on the memory failure.
+}
+
+/**
+ * Swap list and buffer.
+ */
+void UnicodeSet::swapBuffers(void) {
+    // swap list and buffer
+    UChar32* temp = list;
+    list = buffer;
+    buffer = temp;
+
+    int32_t c = capacity;
+    capacity = bufferCapacity;
+    bufferCapacity = c;
+}
+
+void UnicodeSet::setToBogus() {
+    clear(); // Remove everything in the set.
+    fFlags = kIsBogus;
+}
+
+//----------------------------------------------------------------
+// Implementation: Fundamental operators
+//----------------------------------------------------------------
+
+static inline UChar32 max(UChar32 a, UChar32 b) {
+    return (a > b) ? a : b;
+}
+
+// polarity = 0, 3 is normal: x xor y
+// polarity = 1, 2: x xor ~y == x === y
+
+void UnicodeSet::exclusiveOr(const UChar32* other, int32_t otherLen, int8_t polarity) {
+    if (isFrozen() || isBogus()) {
+        return;
+    }
+    UErrorCode status = U_ZERO_ERROR;
+    ensureBufferCapacity(len + otherLen, status);
+    if (U_FAILURE(status)) {
+        return;
+    }
+
+    int32_t i = 0, j = 0, k = 0;
+    UChar32 a = list[i++];
+    UChar32 b;
+    if (polarity == 1 || polarity == 2) {
+        b = UNICODESET_LOW;
+        if (other[j] == UNICODESET_LOW) { // skip base if already LOW
+            ++j;
+            b = other[j];
+        }
+    } else {
+        b = other[j++];
+    }
+    // simplest of all the routines
+    // sort the values, discarding identicals!
+    for (;;) {
+        if (a < b) {
+            buffer[k++] = a;
+            a = list[i++];
+        } else if (b < a) {
+            buffer[k++] = b;
+            b = other[j++];
+        } else if (a != UNICODESET_HIGH) { // at this point, a == b
+            // discard both values!
+            a = list[i++];
+            b = other[j++];
+        } else { // DONE!
+            buffer[k++] = UNICODESET_HIGH;
+            len = k;
+            break;
+        }
+    }
+    swapBuffers();
+    releasePattern();
+}
+
+// polarity = 0 is normal: x union y
+// polarity = 2: x union ~y
+// polarity = 1: ~x union y
+// polarity = 3: ~x union ~y
+
+void UnicodeSet::add(const UChar32* other, int32_t otherLen, int8_t polarity) {
+    if (isFrozen() || isBogus() || other==NULL) {
+        return;
+    }
+    UErrorCode status = U_ZERO_ERROR;
+    ensureBufferCapacity(len + otherLen, status);
+    if (U_FAILURE(status)) {
+        return;
+    }
+
+    int32_t i = 0, j = 0, k = 0;
+    UChar32 a = list[i++];
+    UChar32 b = other[j++];
+    // change from xor is that we have to check overlapping pairs
+    // polarity bit 1 means a is second, bit 2 means b is.
+    for (;;) {
+        switch (polarity) {
+          case 0: // both first; take lower if unequal
+            if (a < b) { // take a
+                // Back up over overlapping ranges in buffer[]
+                if (k > 0 && a <= buffer[k-1]) {
+                    // Pick latter end value in buffer[] vs. list[]
+                    a = max(list[i], buffer[--k]);
+                } else {
+                    // No overlap
+                    buffer[k++] = a;
+                    a = list[i];
+                }
+                i++; // Common if/else code factored out
+                polarity ^= 1;
+            } else if (b < a) { // take b
+                if (k > 0 && b <= buffer[k-1]) {
+                    b = max(other[j], buffer[--k]);
+                } else {
+                    buffer[k++] = b;
+                    b = other[j];
+                }
+                j++;
+                polarity ^= 2;
+            } else { // a == b, take a, drop b
+                if (a == UNICODESET_HIGH) goto loop_end;
+                // This is symmetrical; it doesn't matter if
+                // we backtrack with a or b. - liu
+                if (k > 0 && a <= buffer[k-1]) {
+                    a = max(list[i], buffer[--k]);
+                } else {
+                    // No overlap
+                    buffer[k++] = a;
+                    a = list[i];
+                }
+                i++;
+                polarity ^= 1;
+                b = other[j++];
+                polarity ^= 2;
+            }
+            break;
+          case 3: // both second; take higher if unequal, and drop other
+            if (b <= a) { // take a
+                if (a == UNICODESET_HIGH) goto loop_end;
+                buffer[k++] = a;
+            } else { // take b
+                if (b == UNICODESET_HIGH) goto loop_end;
+                buffer[k++] = b;
+            }
+            a = list[i++];
+            polarity ^= 1;   // factored common code
+            b = other[j++];
+            polarity ^= 2;
+            break;
+          case 1: // a second, b first; if b < a, overlap
+            if (a < b) { // no overlap, take a
+                buffer[k++] = a; a = list[i++]; polarity ^= 1;
+            } else if (b < a) { // OVERLAP, drop b
+                b = other[j++];
+                polarity ^= 2;
+            } else { // a == b, drop both!
+                if (a == UNICODESET_HIGH) goto loop_end;
+                a = list[i++];
+                polarity ^= 1;
+                b = other[j++];
+                polarity ^= 2;
+            }
+            break;
+          case 2: // a first, b second; if a < b, overlap
+            if (b < a) { // no overlap, take b
+                buffer[k++] = b;
+                b = other[j++];
+                polarity ^= 2;
+            } else  if (a < b) { // OVERLAP, drop a
+                a = list[i++];
+                polarity ^= 1;
+            } else { // a == b, drop both!
+                if (a == UNICODESET_HIGH) goto loop_end;
+                a = list[i++];
+                polarity ^= 1;
+                b = other[j++];
+                polarity ^= 2;
+            }
+            break;
+        }
+    }
+ loop_end:
+    buffer[k++] = UNICODESET_HIGH;    // terminate
+    len = k;
+    swapBuffers();
+    releasePattern();
+}
+
+// polarity = 0 is normal: x intersect y
+// polarity = 2: x intersect ~y == set-minus
+// polarity = 1: ~x intersect y
+// polarity = 3: ~x intersect ~y
+
+void UnicodeSet::retain(const UChar32* other, int32_t otherLen, int8_t polarity) {
+    if (isFrozen() || isBogus()) {
+        return;
+    }
+    UErrorCode status = U_ZERO_ERROR;
+    ensureBufferCapacity(len + otherLen, status);
+    if (U_FAILURE(status)) {
+        return;
+    }
+
+    int32_t i = 0, j = 0, k = 0;
+    UChar32 a = list[i++];
+    UChar32 b = other[j++];
+    // change from xor is that we have to check overlapping pairs
+    // polarity bit 1 means a is second, bit 2 means b is.
+    for (;;) {
+        switch (polarity) {
+          case 0: // both first; drop the smaller
+            if (a < b) { // drop a
+                a = list[i++];
+                polarity ^= 1;
+            } else if (b < a) { // drop b
+                b = other[j++];
+                polarity ^= 2;
+            } else { // a == b, take one, drop other
+                if (a == UNICODESET_HIGH) goto loop_end;
+                buffer[k++] = a;
+                a = list[i++];
+                polarity ^= 1;
+                b = other[j++];
+                polarity ^= 2;
+            }
+            break;
+          case 3: // both second; take lower if unequal
+            if (a < b) { // take a
+                buffer[k++] = a;
+                a = list[i++];
+                polarity ^= 1;
+            } else if (b < a) { // take b
+                buffer[k++] = b;
+                b = other[j++];
+                polarity ^= 2;
+            } else { // a == b, take one, drop other
+                if (a == UNICODESET_HIGH) goto loop_end;
+                buffer[k++] = a;
+                a = list[i++];
+                polarity ^= 1;
+                b = other[j++];
+                polarity ^= 2;
+            }
+            break;
+          case 1: // a second, b first;
+            if (a < b) { // NO OVERLAP, drop a
+                a = list[i++];
+                polarity ^= 1;
+            } else if (b < a) { // OVERLAP, take b
+                buffer[k++] = b;
+                b = other[j++];
+                polarity ^= 2;
+            } else { // a == b, drop both!
+                if (a == UNICODESET_HIGH) goto loop_end;
+                a = list[i++];
+                polarity ^= 1;
+                b = other[j++];
+                polarity ^= 2;
+            }
+            break;
+          case 2: // a first, b second; if a < b, overlap
+            if (b < a) { // no overlap, drop b
+                b = other[j++];
+                polarity ^= 2;
+            } else  if (a < b) { // OVERLAP, take a
+                buffer[k++] = a;
+                a = list[i++];
+                polarity ^= 1;
+            } else { // a == b, drop both!
+                if (a == UNICODESET_HIGH) goto loop_end;
+                a = list[i++];
+                polarity ^= 1;
+                b = other[j++];
+                polarity ^= 2;
+            }
+            break;
+        }
+    }
+ loop_end:
+    buffer[k++] = UNICODESET_HIGH;    // terminate
+    len = k;
+    swapBuffers();
+    releasePattern();
+}
+
+/**
+ * Append the <code>toPattern()</code> representation of a
+ * string to the given <code>StringBuffer</code>.
+ */
+void UnicodeSet::_appendToPat(UnicodeString& buf, const UnicodeString& s, UBool
+escapeUnprintable) {
+    UChar32 cp;
+    for (int32_t i = 0; i < s.length(); i += UTF_CHAR_LENGTH(cp)) {
+        _appendToPat(buf, cp = s.char32At(i), escapeUnprintable);
+    }
+}
+
+/**
+ * Append the <code>toPattern()</code> representation of a
+ * character to the given <code>StringBuffer</code>.
+ */
+void UnicodeSet::_appendToPat(UnicodeString& buf, UChar32 c, UBool
+escapeUnprintable) {
+    if (escapeUnprintable && ICU_Utility::isUnprintable(c)) {
+        // Use hex escape notation (\uxxxx or \Uxxxxxxxx) for anything
+        // unprintable
+        if (ICU_Utility::escapeUnprintable(buf, c)) {
+            return;
+        }
+    }
+    // Okay to let ':' pass through
+    switch (c) {
+    case SET_OPEN:
+    case SET_CLOSE:
+    case HYPHEN:
+    case COMPLEMENT:
+    case INTERSECTION:
+    case BACKSLASH:
+    case OPEN_BRACE:
+    case CLOSE_BRACE:
+    case COLON:
+    case SymbolTable::SYMBOL_REF:
+        buf.append(BACKSLASH);
+        break;
+    default:
+        // Escape whitespace
+        if (uprv_isRuleWhiteSpace(c)) {
+            buf.append(BACKSLASH);
+        }
+        break;
+    }
+    buf.append(c);
+}
+
+/**
+ * Append a string representation of this set to result.  This will be
+ * a cleaned version of the string passed to applyPattern(), if there
+ * is one.  Otherwise it will be generated.
+ */
+UnicodeString& UnicodeSet::_toPattern(UnicodeString& result,
+                                      UBool escapeUnprintable) const
+{
+    if (pat != NULL) {
+        int32_t i;
+        int32_t backslashCount = 0;
+        for (i=0; i<patLen; ) {
+            UChar32 c;
+            U16_NEXT(pat, i, patLen, c);
+            if (escapeUnprintable && ICU_Utility::isUnprintable(c)) {
+                // If the unprintable character is preceded by an odd
+                // number of backslashes, then it has been escaped.
+                // Before unescaping it, we delete the final
+                // backslash.
+                if ((backslashCount % 2) == 1) {
+                    result.truncate(result.length() - 1);
+                }
+                ICU_Utility::escapeUnprintable(result, c);
+                backslashCount = 0;
+            } else {
+                result.append(c);
+                if (c == BACKSLASH) {
+                    ++backslashCount;
+                } else {
+                    backslashCount = 0;
+                }
+            }
+        }
+        return result;
+    }
+
+    return _generatePattern(result, escapeUnprintable);
+}
+
+/**
+ * Returns a string representation of this set.  If the result of
+ * calling this function is passed to a UnicodeSet constructor, it
+ * will produce another set that is equal to this one.
+ */
+UnicodeString& UnicodeSet::toPattern(UnicodeString& result,
+                                     UBool escapeUnprintable) const
+{
+    result.truncate(0);
+    return _toPattern(result, escapeUnprintable);
+}
+
+/**
+ * Generate and append a string representation of this set to result.
+ * This does not use this.pat, the cleaned up copy of the string
+ * passed to applyPattern().
+ */
+UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result,
+                                            UBool escapeUnprintable) const
+{
+    result.append(SET_OPEN);
+
+//  // Check against the predefined categories.  We implicitly build
+//  // up ALL category sets the first time toPattern() is called.
+//  for (int8_t cat=0; cat<Unicode::GENERAL_TYPES_COUNT; ++cat) {
+//      if (*this == getCategorySet(cat)) {
+//          result.append(COLON);
+//          result.append(CATEGORY_NAMES, cat*2, 2);
+//          return result.append(CATEGORY_CLOSE);
+//      }
+//  }
+
+    int32_t count = getRangeCount();
+
+    // If the set contains at least 2 intervals and includes both
+    // MIN_VALUE and MAX_VALUE, then the inverse representation will
+    // be more economical.
+    if (count > 1 &&
+        getRangeStart(0) == MIN_VALUE &&
+        getRangeEnd(count-1) == MAX_VALUE) {
+
+        // Emit the inverse
+        result.append(COMPLEMENT);
+
+        for (int32_t i = 1; i < count; ++i) {
+            UChar32 start = getRangeEnd(i-1)+1;
+            UChar32 end = getRangeStart(i)-1;
+            _appendToPat(result, start, escapeUnprintable);
+            if (start != end) {
+                if ((start+1) != end) {
+                    result.append(HYPHEN);
+                }
+                _appendToPat(result, end, escapeUnprintable);
+            }
+        }
+    }
+
+    // Default; emit the ranges as pairs
+    else {
+        for (int32_t i = 0; i < count; ++i) {
+            UChar32 start = getRangeStart(i);
+            UChar32 end = getRangeEnd(i);
+            _appendToPat(result, start, escapeUnprintable);
+            if (start != end) {
+                if ((start+1) != end) {
+                    result.append(HYPHEN);
+                }
+                _appendToPat(result, end, escapeUnprintable);
+            }
+        }
+    }
+
+    for (int32_t i = 0; i<strings->size(); ++i) {
+        result.append(OPEN_BRACE);
+        _appendToPat(result,
+                     *(const UnicodeString*) strings->elementAt(i),
+                     escapeUnprintable);
+        result.append(CLOSE_BRACE);
+    }
+    return result.append(SET_CLOSE);
+}
+
+/**
+* Release existing cached pattern
+*/
+void UnicodeSet::releasePattern() {
+    if (pat) {
+        uprv_free(pat);
+        pat = NULL;
+        patLen = 0;
+    }
+}
+
+/**
+* Set the new pattern to cache.
+*/
+void UnicodeSet::setPattern(const UnicodeString& newPat) {
+    releasePattern();
+    int32_t newPatLen = newPat.length();
+    pat = (UChar *)uprv_malloc((newPatLen + 1) * sizeof(UChar));
+    if (pat) {
+        patLen = newPatLen;
+        newPat.extractBetween(0, patLen, pat);
+        pat[patLen] = 0;
+    }
+    // else we don't care if malloc failed. This was just a nice cache.
+    // We can regenerate an equivalent pattern later when requested.
+}
+
+UnicodeFunctor *UnicodeSet::freeze() {
+    if(!isFrozen() && !isBogus()) {
+        // Do most of what compact() does before freezing because
+        // compact() will not work when the set is frozen.
+        // Small modification: Don't shrink if the savings would be tiny (<=GROW_EXTRA).
+
+        // Delete buffer first to defragment memory less.
+        if (buffer != NULL) {
+            uprv_free(buffer);
+            buffer = NULL;
+        }
+        if (capacity > (len + GROW_EXTRA)) {
+            // Make the capacity equal to len or 1.
+            // We don't want to realloc of 0 size.
+            capacity = len + (len == 0);
+            list = (UChar32*) uprv_realloc(list, sizeof(UChar32) * capacity);
+            if (list == NULL) { // Check for memory allocation error.
+                setToBogus();
+                return this;
+            }
+        }
+
+        // Optimize contains() and span() and similar functions.
+        if (!strings->isEmpty()) {
+            stringSpan = new UnicodeSetStringSpan(*this, *strings, UnicodeSetStringSpan::ALL);
+            if (stringSpan != NULL && !stringSpan->needsStringSpanUTF16()) {
+                // All strings are irrelevant for span() etc. because
+                // all of each string's code points are contained in this set.
+                // Do not check needsStringSpanUTF8() because UTF-8 has at most as
+                // many relevant strings as UTF-16.
+                // (Thus needsStringSpanUTF8() implies needsStringSpanUTF16().)
+                delete stringSpan;
+                stringSpan = NULL;
+            }
+        }
+        if (stringSpan == NULL) {
+            // No span-relevant strings: Optimize for code point spans.
+            bmpSet=new BMPSet(list, len);
+            if (bmpSet == NULL) { // Check for memory allocation error.
+                setToBogus();
+            }
+        }
+    }
+    return this;
+}
+
+int32_t UnicodeSet::span(const UChar *s, int32_t length, USetSpanCondition spanCondition) const {
+    if(length>0 && bmpSet!=NULL) {
+        return (int32_t)(bmpSet->span(s, s+length, spanCondition)-s);
+    }
+    if(length<0) {
+        length=u_strlen(s);
+    }
+    if(length==0) {
+        return 0;
+    }
+    if(stringSpan!=NULL) {
+        return stringSpan->span(s, length, spanCondition);
+    } else if(!strings->isEmpty()) {
+        uint32_t which= spanCondition==USET_SPAN_NOT_CONTAINED ?
+                            UnicodeSetStringSpan::FWD_UTF16_NOT_CONTAINED :
+                            UnicodeSetStringSpan::FWD_UTF16_CONTAINED;
+        UnicodeSetStringSpan strSpan(*this, *strings, which);
+        if(strSpan.needsStringSpanUTF16()) {
+            return strSpan.span(s, length, spanCondition);
+        }
+    }
+
+    if(spanCondition!=USET_SPAN_NOT_CONTAINED) {
+        spanCondition=USET_SPAN_CONTAINED;  // Pin to 0/1 values.
+    }
+
+    UChar32 c;
+    int32_t start=0, prev=0;
+    do {
+        U16_NEXT(s, start, length, c);
+        if(spanCondition!=contains(c)) {
+            break;
+        }
+    } while((prev=start)<length);
+    return prev;
+}
+
+int32_t UnicodeSet::spanBack(const UChar *s, int32_t length, USetSpanCondition spanCondition) const {
+    if(length>0 && bmpSet!=NULL) {
+        return (int32_t)(bmpSet->spanBack(s, s+length, spanCondition)-s);
+    }
+    if(length<0) {
+        length=u_strlen(s);
+    }
+    if(length==0) {
+        return 0;
+    }
+    if(stringSpan!=NULL) {
+        return stringSpan->spanBack(s, length, spanCondition);
+    } else if(!strings->isEmpty()) {
+        uint32_t which= spanCondition==USET_SPAN_NOT_CONTAINED ?
+                            UnicodeSetStringSpan::BACK_UTF16_NOT_CONTAINED :
+                            UnicodeSetStringSpan::BACK_UTF16_CONTAINED;
+        UnicodeSetStringSpan strSpan(*this, *strings, which);
+        if(strSpan.needsStringSpanUTF16()) {
+            return strSpan.spanBack(s, length, spanCondition);
+        }
+    }
+
+    if(spanCondition!=USET_SPAN_NOT_CONTAINED) {
+        spanCondition=USET_SPAN_CONTAINED;  // Pin to 0/1 values.
+    }
+
+    UChar32 c;
+    int32_t prev=length;
+    do {
+        U16_PREV(s, 0, length, c);
+        if(spanCondition!=contains(c)) {
+            break;
+        }
+    } while((prev=length)>0);
+    return prev;
+}
+
+int32_t UnicodeSet::spanUTF8(const char *s, int32_t length, USetSpanCondition spanCondition) const {
+    if(length>0 && bmpSet!=NULL) {
+        const uint8_t *s0=(const uint8_t *)s;
+        return (int32_t)(bmpSet->spanUTF8(s0, length, spanCondition)-s0);
+    }
+    if(length<0) {
+        length=(int32_t)uprv_strlen(s);
+    }
+    if(length==0) {
+        return 0;
+    }
+    if(stringSpan!=NULL) {
+        return stringSpan->spanUTF8((const uint8_t *)s, length, spanCondition);
+    } else if(!strings->isEmpty()) {
+        uint32_t which= spanCondition==USET_SPAN_NOT_CONTAINED ?
+                            UnicodeSetStringSpan::FWD_UTF8_NOT_CONTAINED :
+                            UnicodeSetStringSpan::FWD_UTF8_CONTAINED;
+        UnicodeSetStringSpan strSpan(*this, *strings, which);
+        if(strSpan.needsStringSpanUTF8()) {
+            return strSpan.spanUTF8((const uint8_t *)s, length, spanCondition);
+        }
+    }
+
+    if(spanCondition!=USET_SPAN_NOT_CONTAINED) {
+        spanCondition=USET_SPAN_CONTAINED;  // Pin to 0/1 values.
+    }
+
+    UChar32 c;
+    int32_t start=0, prev=0;
+    do {
+        U8_NEXT(s, start, length, c);
+        if(c<0) {
+            c=0xfffd;
+        }
+        if(spanCondition!=contains(c)) {
+            break;
+        }
+    } while((prev=start)<length);
+    return prev;
+}
+
+int32_t UnicodeSet::spanBackUTF8(const char *s, int32_t length, USetSpanCondition spanCondition) const {
+    if(length>0 && bmpSet!=NULL) {
+        const uint8_t *s0=(const uint8_t *)s;
+        return bmpSet->spanBackUTF8(s0, length, spanCondition);
+    }
+    if(length<0) {
+        length=(int32_t)uprv_strlen(s);
+    }
+    if(length==0) {
+        return 0;
+    }
+    if(stringSpan!=NULL) {
+        return stringSpan->spanBackUTF8((const uint8_t *)s, length, spanCondition);
+    } else if(!strings->isEmpty()) {
+        uint32_t which= spanCondition==USET_SPAN_NOT_CONTAINED ?
+                            UnicodeSetStringSpan::BACK_UTF8_NOT_CONTAINED :
+                            UnicodeSetStringSpan::BACK_UTF8_CONTAINED;
+        UnicodeSetStringSpan strSpan(*this, *strings, which);
+        if(strSpan.needsStringSpanUTF8()) {
+            return strSpan.spanBackUTF8((const uint8_t *)s, length, spanCondition);
+        }
+    }
+
+    if(spanCondition!=USET_SPAN_NOT_CONTAINED) {
+        spanCondition=USET_SPAN_CONTAINED;  // Pin to 0/1 values.
+    }
+
+    UChar32 c;
+    int32_t prev=length;
+    do {
+        U8_PREV(s, 0, length, c);
+        if(c<0) {
+            c=0xfffd;
+        }
+        if(spanCondition!=contains(c)) {
+            break;
+        }
+    } while((prev=length)>0);
+    return prev;
+}
+
+U_NAMESPACE_END
diff --git a/source/common/uniset_props.cpp b/source/common/uniset_props.cpp
new file mode 100644
index 0000000..6f82dfb
--- /dev/null
+++ b/source/common/uniset_props.cpp
@@ -0,0 +1,1504 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  uniset_props.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2004aug25
+*   created by: Markus W. Scherer
+*
+*   Character property dependent functions moved here from uniset.cpp
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uniset.h"
+#include "unicode/parsepos.h"
+#include "unicode/uchar.h"
+#include "unicode/uscript.h"
+#include "unicode/symtable.h"
+#include "unicode/uset.h"
+#include "unicode/locid.h"
+#include "unicode/brkiter.h"
+#include "uset_imp.h"
+#include "ruleiter.h"
+#include "cmemory.h"
+#include "ucln_cmn.h"
+#include "util.h"
+#include "uvector.h"
+#include "uprops.h"
+#include "propname.h"
+#include "normalizer2impl.h"
+#include "ucase.h"
+#include "ubidi_props.h"
+#include "uinvchar.h"
+#include "uprops.h"
+#include "charstr.h"
+#include "cstring.h"
+#include "mutex.h"
+#include "umutex.h"
+#include "uassert.h"
+#include "hash.h"
+
+U_NAMESPACE_USE
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+// initial storage. Must be >= 0
+// *** same as in uniset.cpp ! ***
+#define START_EXTRA 16
+
+// Define UChar constants using hex for EBCDIC compatibility
+// Used #define to reduce private static exports and memory access time.
+#define SET_OPEN        ((UChar)0x005B) /*[*/
+#define SET_CLOSE       ((UChar)0x005D) /*]*/
+#define HYPHEN          ((UChar)0x002D) /*-*/
+#define COMPLEMENT      ((UChar)0x005E) /*^*/
+#define COLON           ((UChar)0x003A) /*:*/
+#define BACKSLASH       ((UChar)0x005C) /*\*/
+#define INTERSECTION    ((UChar)0x0026) /*&*/
+#define UPPER_U         ((UChar)0x0055) /*U*/
+#define LOWER_U         ((UChar)0x0075) /*u*/
+#define OPEN_BRACE      ((UChar)123)    /*{*/
+#define CLOSE_BRACE     ((UChar)125)    /*}*/
+#define UPPER_P         ((UChar)0x0050) /*P*/
+#define LOWER_P         ((UChar)0x0070) /*p*/
+#define UPPER_N         ((UChar)78)     /*N*/
+#define EQUALS          ((UChar)0x003D) /*=*/
+
+//static const UChar POSIX_OPEN[]  = { SET_OPEN,COLON,0 };  // "[:"
+static const UChar POSIX_CLOSE[] = { COLON,SET_CLOSE,0 };  // ":]"
+//static const UChar PERL_OPEN[]   = { BACKSLASH,LOWER_P,0 }; // "\\p"
+static const UChar PERL_CLOSE[]  = { CLOSE_BRACE,0 };    // "}"
+//static const UChar NAME_OPEN[]   = { BACKSLASH,UPPER_N,0 };  // "\\N"
+static const UChar HYPHEN_RIGHT_BRACE[] = {HYPHEN,SET_CLOSE,0}; /*-]*/
+
+// Special property set IDs
+static const char ANY[]   = "ANY";   // [\u0000-\U0010FFFF]
+static const char ASCII[] = "ASCII"; // [\u0000-\u007F]
+static const char ASSIGNED[] = "Assigned"; // [:^Cn:]
+
+// Unicode name property alias
+#define NAME_PROP "na"
+#define NAME_PROP_LENGTH 2
+
+/**
+ * Delimiter string used in patterns to close a category reference:
+ * ":]".  Example: "[:Lu:]".
+ */
+//static const UChar CATEGORY_CLOSE[] = {COLON, SET_CLOSE, 0x0000}; /* ":]" */
+
+// Cached sets ------------------------------------------------------------- ***
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV uset_cleanup();
+U_CDECL_END
+
+// Not a TriStateSingletonWrapper because we think the UnicodeSet constructor
+// can only fail with an out-of-memory error
+// if we have a correct pattern and the properties data is hardcoded and always available.
+class UnicodeSetSingleton : public SimpleSingletonWrapper<UnicodeSet> {
+public:
+    UnicodeSetSingleton(SimpleSingleton &s, const char *pattern) :
+            SimpleSingletonWrapper<UnicodeSet>(s), fPattern(pattern) {}
+    UnicodeSet *getInstance(UErrorCode &errorCode) {
+        return SimpleSingletonWrapper<UnicodeSet>::getInstance(createInstance, fPattern, errorCode);
+    }
+private:
+    static void *createInstance(const void *context, UErrorCode &errorCode) {
+        UnicodeString pattern((const char *)context, -1, US_INV);
+        UnicodeSet *set=new UnicodeSet(pattern, errorCode);
+        if(set==NULL) {
+            errorCode=U_MEMORY_ALLOCATION_ERROR;
+        }
+        set->freeze();
+        ucln_common_registerCleanup(UCLN_COMMON_USET, uset_cleanup);
+        return set;
+    }
+
+    const char *fPattern;
+};
+
+U_CDECL_BEGIN
+
+static UnicodeSet *INCLUSIONS[UPROPS_SRC_COUNT] = { NULL }; // cached getInclusions()
+
+STATIC_SIMPLE_SINGLETON(uni32Singleton);
+
+//----------------------------------------------------------------
+// Inclusions list
+//----------------------------------------------------------------
+
+// USetAdder implementation
+// Does not use uset.h to reduce code dependencies
+static void U_CALLCONV
+_set_add(USet *set, UChar32 c) {
+    ((UnicodeSet *)set)->add(c);
+}
+
+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));
+}
+
+/**
+ * Cleanup function for UnicodeSet
+ */
+static UBool U_CALLCONV uset_cleanup(void) {
+    int32_t i;
+
+    for(i = UPROPS_SRC_NONE; i < UPROPS_SRC_COUNT; ++i) {
+        if (INCLUSIONS[i] != NULL) {
+            delete INCLUSIONS[i];
+            INCLUSIONS[i] = NULL;
+        }
+    }
+    UnicodeSetSingleton(uni32Singleton, NULL).deleteInstance();
+    return TRUE;
+}
+
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+/*
+Reduce excessive reallocation, and make it easier to detect initialization
+problems.
+Usually you don't see smaller sets than this for Unicode 5.0.
+*/
+#define DEFAULT_INCLUSION_CAPACITY 3072
+
+const UnicodeSet* UnicodeSet::getInclusions(int32_t src, UErrorCode &status) {
+    UBool needInit;
+    UMTX_CHECK(NULL, (INCLUSIONS[src] == NULL), needInit);
+    if (needInit) {
+        UnicodeSet* incl = new UnicodeSet();
+        USetAdder sa = {
+            (USet *)incl,
+            _set_add,
+            _set_addRange,
+            _set_addString,
+            NULL, // don't need remove()
+            NULL // don't need removeRange()
+        };
+        incl->ensureCapacity(DEFAULT_INCLUSION_CAPACITY, status);
+        if (incl != NULL) {
+            switch(src) {
+            case UPROPS_SRC_CHAR:
+                uchar_addPropertyStarts(&sa, &status);
+                break;
+            case UPROPS_SRC_PROPSVEC:
+                upropsvec_addPropertyStarts(&sa, &status);
+                break;
+            case UPROPS_SRC_CHAR_AND_PROPSVEC:
+                uchar_addPropertyStarts(&sa, &status);
+                upropsvec_addPropertyStarts(&sa, &status);
+                break;
+#if !UCONFIG_NO_NORMALIZATION
+            case UPROPS_SRC_CASE_AND_NORM: {
+                const Normalizer2Impl *impl=Normalizer2Factory::getNFCImpl(status);
+                if(U_SUCCESS(status)) {
+                    impl->addPropertyStarts(&sa, status);
+                }
+                ucase_addPropertyStarts(ucase_getSingleton(), &sa, &status);
+                break;
+            }
+            case UPROPS_SRC_NFC: {
+                const Normalizer2Impl *impl=Normalizer2Factory::getNFCImpl(status);
+                if(U_SUCCESS(status)) {
+                    impl->addPropertyStarts(&sa, status);
+                }
+                break;
+            }
+            case UPROPS_SRC_NFKC: {
+                const Normalizer2Impl *impl=Normalizer2Factory::getNFKCImpl(status);
+                if(U_SUCCESS(status)) {
+                    impl->addPropertyStarts(&sa, status);
+                }
+                break;
+            }
+            case UPROPS_SRC_NFKC_CF: {
+                const Normalizer2Impl *impl=Normalizer2Factory::getNFKC_CFImpl(status);
+                if(U_SUCCESS(status)) {
+                    impl->addPropertyStarts(&sa, status);
+                }
+                break;
+            }
+            case UPROPS_SRC_NFC_CANON_ITER: {
+                const Normalizer2Impl *impl=Normalizer2Factory::getNFCImpl(status);
+                if(U_SUCCESS(status)) {
+                    impl->addCanonIterPropertyStarts(&sa, status);
+                }
+                break;
+            }
+#endif
+            case UPROPS_SRC_CASE:
+                ucase_addPropertyStarts(ucase_getSingleton(), &sa, &status);
+                break;
+            case UPROPS_SRC_BIDI:
+                ubidi_addPropertyStarts(ubidi_getSingleton(), &sa, &status);
+                break;
+            default:
+                status = U_INTERNAL_PROGRAM_ERROR;
+                break;
+            }
+            if (U_SUCCESS(status)) {
+                // Compact for caching
+                incl->compact();
+                umtx_lock(NULL);
+                if (INCLUSIONS[src] == NULL) {
+                    INCLUSIONS[src] = incl;
+                    incl = NULL;
+                    ucln_common_registerCleanup(UCLN_COMMON_USET, uset_cleanup);
+                }
+                umtx_unlock(NULL);
+            }
+            delete incl;
+        } else {
+            status = U_MEMORY_ALLOCATION_ERROR;
+        }
+    }
+    return INCLUSIONS[src];
+}
+
+// Cache some sets for other services -------------------------------------- ***
+
+U_CFUNC UnicodeSet *
+uniset_getUnicode32Instance(UErrorCode &errorCode) {
+    return UnicodeSetSingleton(uni32Singleton, "[:age=3.2:]").getInstance(errorCode);
+}
+
+// helper functions for matching of pattern syntax pieces ------------------ ***
+// these functions are parallel to the PERL_OPEN etc. strings above
+
+// using these functions is not only faster than UnicodeString::compare() and
+// caseCompare(), but they also make UnicodeSet work for simple patterns when
+// no Unicode properties data is available - when caseCompare() fails
+
+static inline UBool
+isPerlOpen(const UnicodeString &pattern, int32_t pos) {
+    UChar c;
+    return pattern.charAt(pos)==BACKSLASH && ((c=pattern.charAt(pos+1))==LOWER_P || c==UPPER_P);
+}
+
+/*static inline UBool
+isPerlClose(const UnicodeString &pattern, int32_t pos) {
+    return pattern.charAt(pos)==CLOSE_BRACE;
+}*/
+
+static inline UBool
+isNameOpen(const UnicodeString &pattern, int32_t pos) {
+    return pattern.charAt(pos)==BACKSLASH && pattern.charAt(pos+1)==UPPER_N;
+}
+
+static inline UBool
+isPOSIXOpen(const UnicodeString &pattern, int32_t pos) {
+    return pattern.charAt(pos)==SET_OPEN && pattern.charAt(pos+1)==COLON;
+}
+
+/*static inline UBool
+isPOSIXClose(const UnicodeString &pattern, int32_t pos) {
+    return pattern.charAt(pos)==COLON && pattern.charAt(pos+1)==SET_CLOSE;
+}*/
+
+// TODO memory debugging provided inside uniset.cpp
+// could be made available here but probably obsolete with use of modern
+// memory leak checker tools
+#define _dbgct(me)
+
+//----------------------------------------------------------------
+// Constructors &c
+//----------------------------------------------------------------
+
+/**
+ * Constructs a set from the given pattern, optionally ignoring
+ * white space.  See the class description for the syntax of the
+ * pattern language.
+ * @param pattern a string specifying what characters are in the set
+ */
+UnicodeSet::UnicodeSet(const UnicodeString& pattern,
+                       UErrorCode& status) :
+    len(0), capacity(START_EXTRA), list(0), bmpSet(0), buffer(0),
+    bufferCapacity(0), patLen(0), pat(NULL), strings(NULL), stringSpan(NULL),
+    fFlags(0)
+{   
+    if(U_SUCCESS(status)){
+        list = (UChar32*) uprv_malloc(sizeof(UChar32) * capacity);
+        /* test for NULL */
+        if(list == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;  
+        }else{
+            allocateStrings(status);
+            applyPattern(pattern, USET_IGNORE_SPACE, NULL, status);
+        }
+    }
+    _dbgct(this);
+}
+
+/**
+ * Constructs a set from the given pattern, optionally ignoring
+ * white space.  See the class description for the syntax of the
+ * pattern language.
+ * @param pattern a string specifying what characters are in the set
+ * @param options bitmask for options to apply to the pattern.
+ * Valid options are USET_IGNORE_SPACE and USET_CASE_INSENSITIVE.
+ */
+UnicodeSet::UnicodeSet(const UnicodeString& pattern,
+                       uint32_t options,
+                       const SymbolTable* symbols,
+                       UErrorCode& status) :
+    len(0), capacity(START_EXTRA), list(0), bmpSet(0), buffer(0),
+    bufferCapacity(0), patLen(0), pat(NULL), strings(NULL), stringSpan(NULL),
+    fFlags(0)
+{   
+    if(U_SUCCESS(status)){
+        list = (UChar32*) uprv_malloc(sizeof(UChar32) * capacity);
+        /* test for NULL */
+        if(list == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;  
+        }else{
+            allocateStrings(status);
+            applyPattern(pattern, options, symbols, status);
+        }
+    }
+    _dbgct(this);
+}
+
+UnicodeSet::UnicodeSet(const UnicodeString& pattern, ParsePosition& pos,
+                       uint32_t options,
+                       const SymbolTable* symbols,
+                       UErrorCode& status) :
+    len(0), capacity(START_EXTRA), list(0), bmpSet(0), buffer(0),
+    bufferCapacity(0), patLen(0), pat(NULL), strings(NULL), stringSpan(NULL),
+    fFlags(0)
+{
+    if(U_SUCCESS(status)){
+        list = (UChar32*) uprv_malloc(sizeof(UChar32) * capacity);
+        /* test for NULL */
+        if(list == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;   
+        }else{
+            allocateStrings(status);
+            applyPattern(pattern, pos, options, symbols, status);
+        }
+    }
+    _dbgct(this);
+}
+
+//----------------------------------------------------------------
+// Public API
+//----------------------------------------------------------------
+
+/**
+ * Modifies this set to represent the set specified by the given
+ * pattern, optionally ignoring white space.  See the class
+ * description for the syntax of the pattern language.
+ * @param pattern a string specifying what characters are in the set
+ * @param ignoreSpaces if <code>true</code>, all spaces in the
+ * pattern are ignored.  Spaces are those characters for which
+ * <code>uprv_isRuleWhiteSpace()</code> is <code>true</code>.
+ * Characters preceded by '\\' are escaped, losing any special
+ * meaning they otherwise have.  Spaces may be included by
+ * escaping them.
+ * @exception <code>IllegalArgumentException</code> if the pattern
+ * contains a syntax error.
+ */
+UnicodeSet& UnicodeSet::applyPattern(const UnicodeString& pattern,
+                                     UErrorCode& status) {
+    return applyPattern(pattern, USET_IGNORE_SPACE, NULL, status);
+}
+
+
+/**
+ * Modifies this set to represent the set specified by the given
+ * pattern, optionally ignoring white space.  See the class
+ * description for the syntax of the pattern language.
+ * @param pattern a string specifying what characters are in the set
+ * @param options bitmask for options to apply to the pattern.
+ * Valid options are USET_IGNORE_SPACE and USET_CASE_INSENSITIVE.
+ */
+UnicodeSet& UnicodeSet::applyPattern(const UnicodeString& pattern,
+                                     uint32_t options,
+                                     const SymbolTable* symbols,
+                                     UErrorCode& status) {
+    if (U_FAILURE(status) || isFrozen()) {
+        return *this;
+    }
+
+    ParsePosition pos(0);
+    applyPattern(pattern, pos, options, symbols, status);
+    if (U_FAILURE(status)) return *this;
+
+    int32_t i = pos.getIndex();
+
+    if (options & USET_IGNORE_SPACE) {
+        // Skip over trailing whitespace
+        ICU_Utility::skipWhitespace(pattern, i, TRUE);
+    }
+
+    if (i != pattern.length()) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+    }
+    return *this;
+}
+
+UnicodeSet& UnicodeSet::applyPattern(const UnicodeString& pattern,
+                              ParsePosition& pos,
+                              uint32_t options,
+                              const SymbolTable* symbols,
+                              UErrorCode& status) {
+    if (U_FAILURE(status) || isFrozen()) {
+        return *this;
+    }
+    // Need to build the pattern in a temporary string because
+    // _applyPattern calls add() etc., which set pat to empty.
+    UnicodeString rebuiltPat;
+    RuleCharacterIterator chars(pattern, symbols, pos);
+    applyPattern(chars, symbols, rebuiltPat, options, status);
+    if (U_FAILURE(status)) return *this;
+    if (chars.inVariable()) {
+        // syntaxError(chars, "Extra chars in variable value");
+        status = U_MALFORMED_SET;
+        return *this;
+    }
+    setPattern(rebuiltPat);
+    return *this;
+}
+
+/**
+ * Return true if the given position, in the given pattern, appears
+ * to be the start of a UnicodeSet pattern.
+ */
+UBool UnicodeSet::resemblesPattern(const UnicodeString& pattern, int32_t pos) {
+    return ((pos+1) < pattern.length() &&
+            pattern.charAt(pos) == (UChar)91/*[*/) ||
+        resemblesPropertyPattern(pattern, pos);
+}
+
+//----------------------------------------------------------------
+// Implementation: Pattern parsing
+//----------------------------------------------------------------
+
+/**
+ * A small all-inline class to manage a UnicodeSet pointer.  Add
+ * operator->() etc. as needed.
+ */
+class UnicodeSetPointer {
+    UnicodeSet* p;
+public:
+    inline UnicodeSetPointer() : p(0) {}
+    inline ~UnicodeSetPointer() { delete p; }
+    inline UnicodeSet* pointer() { return p; }
+    inline UBool allocate() {
+        if (p == 0) {
+            p = new UnicodeSet();
+        }
+        return p != 0;
+    }
+};
+
+/**
+ * Parse the pattern from the given RuleCharacterIterator.  The
+ * iterator is advanced over the parsed pattern.
+ * @param chars iterator over the pattern characters.  Upon return
+ * it will be advanced to the first character after the parsed
+ * pattern, or the end of the iteration if all characters are
+ * parsed.
+ * @param symbols symbol table to use to parse and dereference
+ * variables, or null if none.
+ * @param rebuiltPat the pattern that was parsed, rebuilt or
+ * copied from the input pattern, as appropriate.
+ * @param options a bit mask of zero or more of the following:
+ * IGNORE_SPACE, CASE.
+ */
+void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
+                              const SymbolTable* symbols,
+                              UnicodeString& rebuiltPat,
+                              uint32_t options,
+                              UErrorCode& ec) {
+    if (U_FAILURE(ec)) return;
+
+    // Syntax characters: [ ] ^ - & { }
+
+    // Recognized special forms for chars, sets: c-c s-s s&s
+
+    int32_t opts = RuleCharacterIterator::PARSE_VARIABLES |
+                   RuleCharacterIterator::PARSE_ESCAPES;
+    if ((options & USET_IGNORE_SPACE) != 0) {
+        opts |= RuleCharacterIterator::SKIP_WHITESPACE;
+    }
+
+    UnicodeString patLocal, buf;
+    UBool usePat = FALSE;
+    UnicodeSetPointer scratch;
+    RuleCharacterIterator::Pos backup;
+
+    // mode: 0=before [, 1=between [...], 2=after ]
+    // lastItem: 0=none, 1=char, 2=set
+    int8_t lastItem = 0, mode = 0;
+    UChar32 lastChar = 0;
+    UChar op = 0;
+
+    UBool invert = FALSE;
+
+    clear();
+
+    while (mode != 2 && !chars.atEnd()) {
+        U_ASSERT((lastItem == 0 && op == 0) ||
+                 (lastItem == 1 && (op == 0 || op == HYPHEN /*'-'*/)) ||
+                 (lastItem == 2 && (op == 0 || op == HYPHEN /*'-'*/ ||
+                                    op == INTERSECTION /*'&'*/)));
+
+        UChar32 c = 0;
+        UBool literal = FALSE;
+        UnicodeSet* nested = 0; // alias - do not delete
+
+        // -------- Check for property pattern
+
+        // setMode: 0=none, 1=unicodeset, 2=propertypat, 3=preparsed
+        int8_t setMode = 0;
+        if (resemblesPropertyPattern(chars, opts)) {
+            setMode = 2;
+        }
+
+        // -------- Parse '[' of opening delimiter OR nested set.
+        // If there is a nested set, use `setMode' to define how
+        // the set should be parsed.  If the '[' is part of the
+        // opening delimiter for this pattern, parse special
+        // strings "[", "[^", "[-", and "[^-".  Check for stand-in
+        // characters representing a nested set in the symbol
+        // table.
+
+        else {
+            // Prepare to backup if necessary
+            chars.getPos(backup);
+            c = chars.next(opts, literal, ec);
+            if (U_FAILURE(ec)) return;
+
+            if (c == 0x5B /*'['*/ && !literal) {
+                if (mode == 1) {
+                    chars.setPos(backup); // backup
+                    setMode = 1;
+                } else {
+                    // Handle opening '[' delimiter
+                    mode = 1;
+                    patLocal.append((UChar) 0x5B /*'['*/);
+                    chars.getPos(backup); // prepare to backup
+                    c = chars.next(opts, literal, ec); 
+                    if (U_FAILURE(ec)) return;
+                    if (c == 0x5E /*'^'*/ && !literal) {
+                        invert = TRUE;
+                        patLocal.append((UChar) 0x5E /*'^'*/);
+                        chars.getPos(backup); // prepare to backup
+                        c = chars.next(opts, literal, ec);
+                        if (U_FAILURE(ec)) return;
+                    }
+                    // Fall through to handle special leading '-';
+                    // otherwise restart loop for nested [], \p{}, etc.
+                    if (c == HYPHEN /*'-'*/) {
+                        literal = TRUE;
+                        // Fall through to handle literal '-' below
+                    } else {
+                        chars.setPos(backup); // backup
+                        continue;
+                    }
+                }
+            } else if (symbols != 0) {
+                const UnicodeFunctor *m = symbols->lookupMatcher(c);
+                if (m != 0) {
+                    const UnicodeSet *ms = dynamic_cast<const UnicodeSet *>(m);
+                    if (ms == NULL) {
+                        ec = U_MALFORMED_SET;
+                        return;
+                    }
+                    // casting away const, but `nested' won't be modified
+                    // (important not to modify stored set)
+                    nested = const_cast<UnicodeSet*>(ms);
+                    setMode = 3;
+                }
+            }
+        }
+
+        // -------- Handle a nested set.  This either is inline in
+        // the pattern or represented by a stand-in that has
+        // previously been parsed and was looked up in the symbol
+        // table.
+
+        if (setMode != 0) {
+            if (lastItem == 1) {
+                if (op != 0) {
+                    // syntaxError(chars, "Char expected after operator");
+                    ec = U_MALFORMED_SET;
+                    return;
+                }
+                add(lastChar, lastChar);
+                _appendToPat(patLocal, lastChar, FALSE);
+                lastItem = 0;
+                op = 0;
+            }
+
+            if (op == HYPHEN /*'-'*/ || op == INTERSECTION /*'&'*/) {
+                patLocal.append(op);
+            }
+
+            if (nested == 0) {
+                // lazy allocation
+                if (!scratch.allocate()) {
+                    ec = U_MEMORY_ALLOCATION_ERROR;
+                    return;
+                }
+                nested = scratch.pointer();
+            }
+            switch (setMode) {
+            case 1:
+                nested->applyPattern(chars, symbols, patLocal, options, ec);
+                break;
+            case 2:
+                chars.skipIgnored(opts);
+                nested->applyPropertyPattern(chars, patLocal, ec);
+                if (U_FAILURE(ec)) return;
+                break;
+            case 3: // `nested' already parsed
+                nested->_toPattern(patLocal, FALSE);
+                break;
+            }
+
+            usePat = TRUE;
+
+            if (mode == 0) {
+                // Entire pattern is a category; leave parse loop
+                *this = *nested;
+                mode = 2;
+                break;
+            }
+
+            switch (op) {
+            case HYPHEN: /*'-'*/
+                removeAll(*nested);
+                break;
+            case INTERSECTION: /*'&'*/
+                retainAll(*nested);
+                break;
+            case 0:
+                addAll(*nested);
+                break;
+            }
+
+            op = 0;
+            lastItem = 2;
+
+            continue;
+        }
+
+        if (mode == 0) {
+            // syntaxError(chars, "Missing '['");
+            ec = U_MALFORMED_SET;
+            return;
+        }
+
+        // -------- Parse special (syntax) characters.  If the
+        // current character is not special, or if it is escaped,
+        // then fall through and handle it below.
+
+        if (!literal) {
+            switch (c) {
+            case 0x5D /*']'*/:
+                if (lastItem == 1) {
+                    add(lastChar, lastChar);
+                    _appendToPat(patLocal, lastChar, FALSE);
+                }
+                // Treat final trailing '-' as a literal
+                if (op == HYPHEN /*'-'*/) {
+                    add(op, op);
+                    patLocal.append(op);
+                } else if (op == INTERSECTION /*'&'*/) {
+                    // syntaxError(chars, "Trailing '&'");
+                    ec = U_MALFORMED_SET;
+                    return;
+                }
+                patLocal.append((UChar) 0x5D /*']'*/);
+                mode = 2;
+                continue;
+            case HYPHEN /*'-'*/:
+                if (op == 0) {
+                    if (lastItem != 0) {
+                        op = (UChar) c;
+                        continue;
+                    } else {
+                        // Treat final trailing '-' as a literal
+                        add(c, c);
+                        c = chars.next(opts, literal, ec);
+                        if (U_FAILURE(ec)) return;
+                        if (c == 0x5D /*']'*/ && !literal) {
+                            patLocal.append(HYPHEN_RIGHT_BRACE);
+                            mode = 2;
+                            continue;
+                        }
+                    }
+                }
+                // syntaxError(chars, "'-' not after char or set");
+                ec = U_MALFORMED_SET;
+                return;
+            case INTERSECTION /*'&'*/:
+                if (lastItem == 2 && op == 0) {
+                    op = (UChar) c;
+                    continue;
+                }
+                // syntaxError(chars, "'&' not after set");
+                ec = U_MALFORMED_SET;
+                return;
+            case 0x5E /*'^'*/:
+                // syntaxError(chars, "'^' not after '['");
+                ec = U_MALFORMED_SET;
+                return;
+            case 0x7B /*'{'*/:
+                if (op != 0) {
+                    // syntaxError(chars, "Missing operand after operator");
+                    ec = U_MALFORMED_SET;
+                    return;
+                }
+                if (lastItem == 1) {
+                    add(lastChar, lastChar);
+                    _appendToPat(patLocal, lastChar, FALSE);
+                }
+                lastItem = 0;
+                buf.truncate(0);
+                {
+                    UBool ok = FALSE;
+                    while (!chars.atEnd()) {
+                        c = chars.next(opts, literal, ec);
+                        if (U_FAILURE(ec)) return;
+                        if (c == 0x7D /*'}'*/ && !literal) {
+                            ok = TRUE;
+                            break;
+                        }
+                        buf.append(c);
+                    }
+                    if (buf.length() < 1 || !ok) {
+                        // syntaxError(chars, "Invalid multicharacter string");
+                        ec = U_MALFORMED_SET;
+                        return;
+                    }
+                }
+                // We have new string. Add it to set and continue;
+                // we don't need to drop through to the further
+                // processing
+                add(buf);
+                patLocal.append((UChar) 0x7B /*'{'*/);
+                _appendToPat(patLocal, buf, FALSE);
+                patLocal.append((UChar) 0x7D /*'}'*/);
+                continue;
+            case SymbolTable::SYMBOL_REF:
+                //         symbols  nosymbols
+                // [a-$]   error    error (ambiguous)
+                // [a$]    anchor   anchor
+                // [a-$x]  var "x"* literal '$'
+                // [a-$.]  error    literal '$'
+                // *We won't get here in the case of var "x"
+                {
+                    chars.getPos(backup);
+                    c = chars.next(opts, literal, ec);
+                    if (U_FAILURE(ec)) return;
+                    UBool anchor = (c == 0x5D /*']'*/ && !literal);
+                    if (symbols == 0 && !anchor) {
+                        c = SymbolTable::SYMBOL_REF;
+                        chars.setPos(backup);
+                        break; // literal '$'
+                    }
+                    if (anchor && op == 0) {
+                        if (lastItem == 1) {
+                            add(lastChar, lastChar);
+                            _appendToPat(patLocal, lastChar, FALSE);
+                        }
+                        add(U_ETHER);
+                        usePat = TRUE;
+                        patLocal.append((UChar) SymbolTable::SYMBOL_REF);
+                        patLocal.append((UChar) 0x5D /*']'*/);
+                        mode = 2;
+                        continue;
+                    }
+                    // syntaxError(chars, "Unquoted '$'");
+                    ec = U_MALFORMED_SET;
+                    return;
+                }
+            default:
+                break;
+            }
+        }
+
+        // -------- Parse literal characters.  This includes both
+        // escaped chars ("\u4E01") and non-syntax characters
+        // ("a").
+
+        switch (lastItem) {
+        case 0:
+            lastItem = 1;
+            lastChar = c;
+            break;
+        case 1:
+            if (op == HYPHEN /*'-'*/) {
+                if (lastChar >= c) {
+                    // Don't allow redundant (a-a) or empty (b-a) ranges;
+                    // these are most likely typos.
+                    // syntaxError(chars, "Invalid range");
+                    ec = U_MALFORMED_SET;
+                    return;
+                }
+                add(lastChar, c);
+                _appendToPat(patLocal, lastChar, FALSE);
+                patLocal.append(op);
+                _appendToPat(patLocal, c, FALSE);
+                lastItem = 0;
+                op = 0;
+            } else {
+                add(lastChar, lastChar);
+                _appendToPat(patLocal, lastChar, FALSE);
+                lastChar = c;
+            }
+            break;
+        case 2:
+            if (op != 0) {
+                // syntaxError(chars, "Set expected after operator");
+                ec = U_MALFORMED_SET;
+                return;
+            }
+            lastChar = c;
+            lastItem = 1;
+            break;
+        }
+    }
+
+    if (mode != 2) {
+        // syntaxError(chars, "Missing ']'");
+        ec = U_MALFORMED_SET;
+        return;
+    }
+
+    chars.skipIgnored(opts);
+
+    /**
+     * Handle global flags (invert, case insensitivity).  If this
+     * pattern should be compiled case-insensitive, then we need
+     * to close over case BEFORE COMPLEMENTING.  This makes
+     * patterns like /[^abc]/i work.
+     */
+    if ((options & USET_CASE_INSENSITIVE) != 0) {
+        closeOver(USET_CASE_INSENSITIVE);
+    }
+    else if ((options & USET_ADD_CASE_MAPPINGS) != 0) {
+        closeOver(USET_ADD_CASE_MAPPINGS);
+    }
+    if (invert) {
+        complement();
+    }
+
+    // Use the rebuilt pattern (patLocal) only if necessary.  Prefer the
+    // generated pattern.
+    if (usePat) {
+        rebuiltPat.append(patLocal);
+    } else {
+        _generatePattern(rebuiltPat, FALSE);
+    }
+    if (isBogus() && U_SUCCESS(ec)) {
+        // We likely ran out of memory. AHHH!
+        ec = U_MEMORY_ALLOCATION_ERROR;
+    }
+}
+
+//----------------------------------------------------------------
+// Property set implementation
+//----------------------------------------------------------------
+
+static UBool numericValueFilter(UChar32 ch, void* context) {
+    return u_getNumericValue(ch) == *(double*)context;
+}
+
+static UBool generalCategoryMaskFilter(UChar32 ch, void* context) {
+    int32_t value = *(int32_t*)context;
+    return (U_GET_GC_MASK((UChar32) ch) & value) != 0;
+}
+
+static UBool versionFilter(UChar32 ch, void* context) {
+    static const UVersionInfo none = { 0, 0, 0, 0 };
+    UVersionInfo v;
+    u_charAge(ch, v);
+    UVersionInfo* version = (UVersionInfo*)context;
+    return uprv_memcmp(&v, &none, sizeof(v)) > 0 && uprv_memcmp(&v, version, sizeof(v)) <= 0;
+}
+
+typedef struct {
+    UProperty prop;
+    int32_t value;
+} IntPropertyContext;
+
+static UBool intPropertyFilter(UChar32 ch, void* context) {
+    IntPropertyContext* c = (IntPropertyContext*)context;
+    return u_getIntPropertyValue((UChar32) ch, c->prop) == c->value;
+}
+
+static UBool scriptExtensionsFilter(UChar32 ch, void* context) {
+    return uscript_hasScript(ch, *(UScriptCode*)context);
+}
+
+/**
+ * Generic filter-based scanning code for UCD property UnicodeSets.
+ */
+void UnicodeSet::applyFilter(UnicodeSet::Filter filter,
+                             void* context,
+                             int32_t src,
+                             UErrorCode &status) {
+    if (U_FAILURE(status)) return;
+
+    // Logically, walk through all Unicode characters, noting the start
+    // and end of each range for which filter.contain(c) is
+    // true.  Add each range to a set.
+    //
+    // To improve performance, use an inclusions set which
+    // encodes information about character ranges that are known
+    // to have identical properties.
+    // getInclusions(src) contains exactly the first characters of
+    // same-value ranges for the given properties "source".
+    const UnicodeSet* inclusions = getInclusions(src, status);
+    if (U_FAILURE(status)) {
+        return;
+    }
+
+    clear();
+
+    UChar32 startHasProperty = -1;
+    int32_t limitRange = inclusions->getRangeCount();
+
+    for (int j=0; j<limitRange; ++j) {
+        // get current range
+        UChar32 start = inclusions->getRangeStart(j);
+        UChar32 end = inclusions->getRangeEnd(j);
+
+        // for all the code points in the range, process
+        for (UChar32 ch = start; ch <= end; ++ch) {
+            // only add to this UnicodeSet on inflection points --
+            // where the hasProperty value changes to false
+            if ((*filter)(ch, context)) {
+                if (startHasProperty < 0) {
+                    startHasProperty = ch;
+                }
+            } else if (startHasProperty >= 0) {
+                add(startHasProperty, ch-1);
+                startHasProperty = -1;
+            }
+        }
+    }
+    if (startHasProperty >= 0) {
+        add((UChar32)startHasProperty, (UChar32)0x10FFFF);
+    }
+    if (isBogus() && U_SUCCESS(status)) {
+        // We likely ran out of memory. AHHH!
+        status = U_MEMORY_ALLOCATION_ERROR;
+    }
+}
+
+static UBool mungeCharName(char* dst, const char* src, int32_t dstCapacity) {
+    /* Note: we use ' ' in compiler code page */
+    int32_t j = 0;
+    char ch;
+    --dstCapacity; /* make room for term. zero */
+    while ((ch = *src++) != 0) {
+        if (ch == ' ' && (j==0 || (j>0 && dst[j-1]==' '))) {
+            continue;
+        }
+        if (j >= dstCapacity) return FALSE;
+        dst[j++] = ch;
+    }
+    if (j > 0 && dst[j-1] == ' ') --j;
+    dst[j] = 0;
+    return TRUE;
+}
+
+//----------------------------------------------------------------
+// Property set API
+//----------------------------------------------------------------
+
+#define FAIL(ec) {ec=U_ILLEGAL_ARGUMENT_ERROR; return *this;}
+
+UnicodeSet&
+UnicodeSet::applyIntPropertyValue(UProperty prop, int32_t value, UErrorCode& ec) {
+    if (U_FAILURE(ec) || isFrozen()) return *this;
+
+    if (prop == UCHAR_GENERAL_CATEGORY_MASK) {
+        applyFilter(generalCategoryMaskFilter, &value, UPROPS_SRC_CHAR, ec);
+    } else if (prop == UCHAR_SCRIPT_EXTENSIONS) {
+        UScriptCode script = (UScriptCode)value;
+        applyFilter(scriptExtensionsFilter, &script, UPROPS_SRC_PROPSVEC, ec);
+    } else {
+        IntPropertyContext c = {prop, value};
+        applyFilter(intPropertyFilter, &c, uprops_getSource(prop), ec);
+    }
+    return *this;
+}
+
+UnicodeSet&
+UnicodeSet::applyPropertyAlias(const UnicodeString& prop,
+                               const UnicodeString& value,
+                               UErrorCode& ec) {
+    if (U_FAILURE(ec) || isFrozen()) return *this;
+
+    // prop and value used to be converted to char * using the default
+    // converter instead of the invariant conversion.
+    // This should not be necessary because all Unicode property and value
+    // names use only invariant characters.
+    // If there are any variant characters, then we won't find them anyway.
+    // Checking first avoids assertion failures in the conversion.
+    if( !uprv_isInvariantUString(prop.getBuffer(), prop.length()) ||
+        !uprv_isInvariantUString(value.getBuffer(), value.length())
+    ) {
+        FAIL(ec);
+    }
+    CharString pname, vname;
+    pname.appendInvariantChars(prop, ec);
+    vname.appendInvariantChars(value, ec);
+    if (U_FAILURE(ec)) return *this;
+
+    UProperty p;
+    int32_t v;
+    UBool mustNotBeEmpty = FALSE, invert = FALSE;
+
+    if (value.length() > 0) {
+        p = u_getPropertyEnum(pname.data());
+        if (p == UCHAR_INVALID_CODE) FAIL(ec);
+
+        // Treat gc as gcm
+        if (p == UCHAR_GENERAL_CATEGORY) {
+            p = UCHAR_GENERAL_CATEGORY_MASK;
+        }
+
+        if ((p >= UCHAR_BINARY_START && p < UCHAR_BINARY_LIMIT) ||
+            (p >= UCHAR_INT_START && p < UCHAR_INT_LIMIT) ||
+            (p >= UCHAR_MASK_START && p < UCHAR_MASK_LIMIT)) {
+            v = u_getPropertyValueEnum(p, vname.data());
+            if (v == UCHAR_INVALID_CODE) {
+                // Handle numeric CCC
+                if (p == UCHAR_CANONICAL_COMBINING_CLASS ||
+                    p == UCHAR_TRAIL_CANONICAL_COMBINING_CLASS ||
+                    p == UCHAR_LEAD_CANONICAL_COMBINING_CLASS) {
+                    char* end;
+                    double value = uprv_strtod(vname.data(), &end);
+                    v = (int32_t) value;
+                    if (v != value || v < 0 || *end != 0) {
+                        // non-integral or negative value, or trailing junk
+                        FAIL(ec);
+                    }
+                    // If the resultant set is empty then the numeric value
+                    // was invalid.
+                    mustNotBeEmpty = TRUE;
+                } else {
+                    FAIL(ec);
+                }
+            }
+        }
+
+        else {
+
+            switch (p) {
+            case UCHAR_NUMERIC_VALUE:
+                {
+                    char* end;
+                    double value = uprv_strtod(vname.data(), &end);
+                    if (*end != 0) {
+                        FAIL(ec);
+                    }
+                    applyFilter(numericValueFilter, &value, UPROPS_SRC_CHAR, ec);
+                    return *this;
+                }
+                break;
+            case UCHAR_NAME:
+            case UCHAR_UNICODE_1_NAME:
+                {
+                    // Must munge name, since u_charFromName() does not do
+                    // 'loose' matching.
+                    char buf[128]; // it suffices that this be > uprv_getMaxCharNameLength
+                    if (!mungeCharName(buf, vname.data(), sizeof(buf))) FAIL(ec);
+                    UCharNameChoice choice = (p == UCHAR_NAME) ?
+                        U_EXTENDED_CHAR_NAME : U_UNICODE_10_CHAR_NAME;
+                    UChar32 ch = u_charFromName(choice, buf, &ec);
+                    if (U_SUCCESS(ec)) {
+                        clear();
+                        add(ch);
+                        return *this;
+                    } else {
+                        FAIL(ec);
+                    }
+                }
+                break;
+            case UCHAR_AGE:
+                {
+                    // Must munge name, since u_versionFromString() does not do
+                    // 'loose' matching.
+                    char buf[128];
+                    if (!mungeCharName(buf, vname.data(), sizeof(buf))) FAIL(ec);
+                    UVersionInfo version;
+                    u_versionFromString(version, buf);
+                    applyFilter(versionFilter, &version, UPROPS_SRC_PROPSVEC, ec);
+                    return *this;
+                }
+                break;
+            case UCHAR_SCRIPT_EXTENSIONS:
+                v = u_getPropertyValueEnum(UCHAR_SCRIPT, vname.data());
+                if (v == UCHAR_INVALID_CODE) {
+                    FAIL(ec);
+                }
+                // fall through to calling applyIntPropertyValue()
+                break;
+            default:
+                // p is a non-binary, non-enumerated property that we
+                // don't support (yet).
+                FAIL(ec);
+            }
+        }
+    }
+
+    else {
+        // value is empty.  Interpret as General Category, Script, or
+        // Binary property.
+        p = UCHAR_GENERAL_CATEGORY_MASK;
+        v = u_getPropertyValueEnum(p, pname.data());
+        if (v == UCHAR_INVALID_CODE) {
+            p = UCHAR_SCRIPT;
+            v = u_getPropertyValueEnum(p, pname.data());
+            if (v == UCHAR_INVALID_CODE) {
+                p = u_getPropertyEnum(pname.data());
+                if (p >= UCHAR_BINARY_START && p < UCHAR_BINARY_LIMIT) {
+                    v = 1;
+                } else if (0 == uprv_comparePropertyNames(ANY, pname.data())) {
+                    set(MIN_VALUE, MAX_VALUE);
+                    return *this;
+                } else if (0 == uprv_comparePropertyNames(ASCII, pname.data())) {
+                    set(0, 0x7F);
+                    return *this;
+                } else if (0 == uprv_comparePropertyNames(ASSIGNED, pname.data())) {
+                    // [:Assigned:]=[:^Cn:]
+                    p = UCHAR_GENERAL_CATEGORY_MASK;
+                    v = U_GC_CN_MASK;
+                    invert = TRUE;
+                } else {
+                    FAIL(ec);
+                }
+            }
+        }
+    }
+
+    applyIntPropertyValue(p, v, ec);
+    if(invert) {
+        complement();
+    }
+
+    if (U_SUCCESS(ec) && (mustNotBeEmpty && isEmpty())) {
+        // mustNotBeEmpty is set to true if an empty set indicates
+        // invalid input.
+        ec = U_ILLEGAL_ARGUMENT_ERROR;
+    }
+
+    if (isBogus() && U_SUCCESS(ec)) {
+        // We likely ran out of memory. AHHH!
+        ec = U_MEMORY_ALLOCATION_ERROR;
+    }
+    return *this;
+}
+
+//----------------------------------------------------------------
+// Property set patterns
+//----------------------------------------------------------------
+
+/**
+ * Return true if the given position, in the given pattern, appears
+ * to be the start of a property set pattern.
+ */
+UBool UnicodeSet::resemblesPropertyPattern(const UnicodeString& pattern,
+                                           int32_t pos) {
+    // Patterns are at least 5 characters long
+    if ((pos+5) > pattern.length()) {
+        return FALSE;
+    }
+
+    // Look for an opening [:, [:^, \p, or \P
+    return isPOSIXOpen(pattern, pos) || isPerlOpen(pattern, pos) || isNameOpen(pattern, pos);
+}
+
+/**
+ * Return true if the given iterator appears to point at a
+ * property pattern.  Regardless of the result, return with the
+ * iterator unchanged.
+ * @param chars iterator over the pattern characters.  Upon return
+ * it will be unchanged.
+ * @param iterOpts RuleCharacterIterator options
+ */
+UBool UnicodeSet::resemblesPropertyPattern(RuleCharacterIterator& chars,
+                                           int32_t iterOpts) {
+    // NOTE: literal will always be FALSE, because we don't parse escapes.
+    UBool result = FALSE, literal;
+    UErrorCode ec = U_ZERO_ERROR;
+    iterOpts &= ~RuleCharacterIterator::PARSE_ESCAPES;
+    RuleCharacterIterator::Pos pos;
+    chars.getPos(pos);
+    UChar32 c = chars.next(iterOpts, literal, ec);
+    if (c == 0x5B /*'['*/ || c == 0x5C /*'\\'*/) {
+        UChar32 d = chars.next(iterOpts & ~RuleCharacterIterator::SKIP_WHITESPACE,
+                               literal, ec);
+        result = (c == 0x5B /*'['*/) ? (d == 0x3A /*':'*/) :
+                 (d == 0x4E /*'N'*/ || d == 0x70 /*'p'*/ || d == 0x50 /*'P'*/);
+    }
+    chars.setPos(pos);
+    return result && U_SUCCESS(ec);
+}
+
+/**
+ * Parse the given property pattern at the given parse position.
+ */
+UnicodeSet& UnicodeSet::applyPropertyPattern(const UnicodeString& pattern,
+                                             ParsePosition& ppos,
+                                             UErrorCode &ec) {
+    int32_t pos = ppos.getIndex();
+
+    UBool posix = FALSE; // true for [:pat:], false for \p{pat} \P{pat} \N{pat}
+    UBool isName = FALSE; // true for \N{pat}, o/w false
+    UBool invert = FALSE;
+
+    if (U_FAILURE(ec)) return *this;
+
+    // Minimum length is 5 characters, e.g. \p{L}
+    if ((pos+5) > pattern.length()) {
+        FAIL(ec);
+    }
+
+    // On entry, ppos should point to one of the following locations:
+    // Look for an opening [:, [:^, \p, or \P
+    if (isPOSIXOpen(pattern, pos)) {
+        posix = TRUE;
+        pos += 2;
+        pos = ICU_Utility::skipWhitespace(pattern, pos);
+        if (pos < pattern.length() && pattern.charAt(pos) == COMPLEMENT) {
+            ++pos;
+            invert = TRUE;
+        }
+    } else if (isPerlOpen(pattern, pos) || isNameOpen(pattern, pos)) {
+        UChar c = pattern.charAt(pos+1);
+        invert = (c == UPPER_P);
+        isName = (c == UPPER_N);
+        pos += 2;
+        pos = ICU_Utility::skipWhitespace(pattern, pos);
+        if (pos == pattern.length() || pattern.charAt(pos++) != OPEN_BRACE) {
+            // Syntax error; "\p" or "\P" not followed by "{"
+            FAIL(ec);
+        }
+    } else {
+        // Open delimiter not seen
+        FAIL(ec);
+    }
+
+    // Look for the matching close delimiter, either :] or }
+    int32_t close = pattern.indexOf(posix ? POSIX_CLOSE : PERL_CLOSE, pos);
+    if (close < 0) {
+        // Syntax error; close delimiter missing
+        FAIL(ec);
+    }
+
+    // Look for an '=' sign.  If this is present, we will parse a
+    // medium \p{gc=Cf} or long \p{GeneralCategory=Format}
+    // pattern.
+    int32_t equals = pattern.indexOf(EQUALS, pos);
+    UnicodeString propName, valueName;
+    if (equals >= 0 && equals < close && !isName) {
+        // Equals seen; parse medium/long pattern
+        pattern.extractBetween(pos, equals, propName);
+        pattern.extractBetween(equals+1, close, valueName);
+    }
+
+    else {
+        // Handle case where no '=' is seen, and \N{}
+        pattern.extractBetween(pos, close, propName);
+            
+        // Handle \N{name}
+        if (isName) {
+            // This is a little inefficient since it means we have to
+            // parse NAME_PROP back to UCHAR_NAME even though we already
+            // know it's UCHAR_NAME.  If we refactor the API to
+            // support args of (UProperty, char*) then we can remove
+            // NAME_PROP and make this a little more efficient.
+            valueName = propName;
+            propName = UnicodeString(NAME_PROP, NAME_PROP_LENGTH, US_INV);
+        }
+    }
+
+    applyPropertyAlias(propName, valueName, ec);
+
+    if (U_SUCCESS(ec)) {
+        if (invert) {
+            complement();
+        }
+            
+        // Move to the limit position after the close delimiter if the
+        // parse succeeded.
+        ppos.setIndex(close + (posix ? 2 : 1));
+    }
+
+    return *this;
+}
+
+/**
+ * Parse a property pattern.
+ * @param chars iterator over the pattern characters.  Upon return
+ * it will be advanced to the first character after the parsed
+ * pattern, or the end of the iteration if all characters are
+ * parsed.
+ * @param rebuiltPat the pattern that was parsed, rebuilt or
+ * copied from the input pattern, as appropriate.
+ */
+void UnicodeSet::applyPropertyPattern(RuleCharacterIterator& chars,
+                                      UnicodeString& rebuiltPat,
+                                      UErrorCode& ec) {
+    if (U_FAILURE(ec)) return;
+    UnicodeString pattern;
+    chars.lookahead(pattern);
+    ParsePosition pos(0);
+    applyPropertyPattern(pattern, pos, ec);
+    if (U_FAILURE(ec)) return;
+    if (pos.getIndex() == 0) {
+        // syntaxError(chars, "Invalid property pattern");
+        ec = U_MALFORMED_SET;
+        return;
+    }
+    chars.jumpahead(pos.getIndex());
+    rebuiltPat.append(pattern, 0, pos.getIndex());
+}
+
+//----------------------------------------------------------------
+// Case folding API
+//----------------------------------------------------------------
+
+// add the result of a full case mapping to the set
+// use str as a temporary string to avoid constructing one
+static inline void
+addCaseMapping(UnicodeSet &set, int32_t result, const UChar *full, UnicodeString &str) {
+    if(result >= 0) {
+        if(result > UCASE_MAX_STRING_LENGTH) {
+            // add a single-code point case mapping
+            set.add(result);
+        } else {
+            // add a string case mapping from full with length result
+            str.setTo((UBool)FALSE, full, result);
+            set.add(str);
+        }
+    }
+    // result < 0: the code point mapped to itself, no need to add it
+    // see ucase.h
+}
+
+UnicodeSet& UnicodeSet::closeOver(int32_t attribute) {
+    if (isFrozen() || isBogus()) {
+        return *this;
+    }
+    if (attribute & (USET_CASE_INSENSITIVE | USET_ADD_CASE_MAPPINGS)) {
+        const UCaseProps *csp = ucase_getSingleton();
+        {
+            UnicodeSet foldSet(*this);
+            UnicodeString str;
+            USetAdder sa = {
+                foldSet.toUSet(),
+                _set_add,
+                _set_addRange,
+                _set_addString,
+                NULL, // don't need remove()
+                NULL // don't need removeRange()
+            };
+
+            // start with input set to guarantee inclusion
+            // USET_CASE: remove strings because the strings will actually be reduced (folded);
+            //            therefore, start with no strings and add only those needed
+            if (attribute & USET_CASE_INSENSITIVE) {
+                foldSet.strings->removeAllElements();
+            }
+
+            int32_t n = getRangeCount();
+            UChar32 result;
+            const UChar *full;
+            int32_t locCache = 0;
+
+            for (int32_t i=0; i<n; ++i) {
+                UChar32 start = getRangeStart(i);
+                UChar32 end   = getRangeEnd(i);
+
+                if (attribute & USET_CASE_INSENSITIVE) {
+                    // full case closure
+                    for (UChar32 cp=start; cp<=end; ++cp) {
+                        ucase_addCaseClosure(csp, cp, &sa);
+                    }
+                } else {
+                    // add case mappings
+                    // (does not add long s for regular s, or Kelvin for k, for example)
+                    for (UChar32 cp=start; cp<=end; ++cp) {
+                        result = ucase_toFullLower(csp, cp, NULL, NULL, &full, "", &locCache);
+                        addCaseMapping(foldSet, result, full, str);
+
+                        result = ucase_toFullTitle(csp, cp, NULL, NULL, &full, "", &locCache);
+                        addCaseMapping(foldSet, result, full, str);
+
+                        result = ucase_toFullUpper(csp, cp, NULL, NULL, &full, "", &locCache);
+                        addCaseMapping(foldSet, result, full, str);
+
+                        result = ucase_toFullFolding(csp, cp, &full, 0);
+                        addCaseMapping(foldSet, result, full, str);
+                    }
+                }
+            }
+            if (strings != NULL && strings->size() > 0) {
+                if (attribute & USET_CASE_INSENSITIVE) {
+                    for (int32_t j=0; j<strings->size(); ++j) {
+                        str = *(const UnicodeString *) strings->elementAt(j);
+                        str.foldCase();
+                        if(!ucase_addStringCaseClosure(csp, str.getBuffer(), str.length(), &sa)) {
+                            foldSet.add(str); // does not map to code points: add the folded string itself
+                        }
+                    }
+                } else {
+                    Locale root("");
+#if !UCONFIG_NO_BREAK_ITERATION
+                    UErrorCode status = U_ZERO_ERROR;
+                    BreakIterator *bi = BreakIterator::createWordInstance(root, status);
+                    if (U_SUCCESS(status)) {
+#endif
+                        const UnicodeString *pStr;
+
+                        for (int32_t j=0; j<strings->size(); ++j) {
+                            pStr = (const UnicodeString *) strings->elementAt(j);
+                            (str = *pStr).toLower(root);
+                            foldSet.add(str);
+#if !UCONFIG_NO_BREAK_ITERATION
+                            (str = *pStr).toTitle(bi, root);
+                            foldSet.add(str);
+#endif
+                            (str = *pStr).toUpper(root);
+                            foldSet.add(str);
+                            (str = *pStr).foldCase();
+                            foldSet.add(str);
+                        }
+#if !UCONFIG_NO_BREAK_ITERATION
+                    }
+                    delete bi;
+#endif
+                }
+            }
+            *this = foldSet;
+        }
+    }
+    return *this;
+}
+
+U_NAMESPACE_END
diff --git a/source/common/unisetspan.cpp b/source/common/unisetspan.cpp
new file mode 100644
index 0000000..0e43dfc
--- /dev/null
+++ b/source/common/unisetspan.cpp
@@ -0,0 +1,1508 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2007, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  unisetspan.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2007mar01
+*   created by: Markus W. Scherer
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uniset.h"
+#include "unicode/ustring.h"
+#include "cmemory.h"
+#include "uvector.h"
+#include "unisetspan.h"
+
+U_NAMESPACE_BEGIN
+
+/*
+ * List of offsets from the current position from where to try matching
+ * a code point or a string.
+ * Store offsets rather than indexes to simplify the code and use the same list
+ * for both increments (in span()) and decrements (in spanBack()).
+ *
+ * Assumption: The maximum offset is limited, and the offsets that are stored
+ * at any one time are relatively dense, that is, there are normally no gaps of
+ * hundreds or thousands of offset values.
+ *
+ * The implementation uses a circular buffer of byte flags,
+ * each indicating whether the corresponding offset is in the list.
+ * This avoids inserting into a sorted list of offsets (or absolute indexes) and
+ * physically moving part of the list.
+ *
+ * Note: In principle, the caller should setMaxLength() to the maximum of the
+ * max string length and U16_LENGTH/U8_LENGTH to account for
+ * "long" single code points.
+ * However, this implementation uses at least a staticList with more than
+ * U8_LENGTH entries anyway.
+ *
+ * Note: If maxLength were guaranteed to be no more than 32 or 64,
+ * the list could be stored as bit flags in a single integer.
+ * Rather than handling a circular buffer with a start list index,
+ * the integer would simply be shifted when lower offsets are removed.
+ * UnicodeSet does not have a limit on the lengths of strings.
+ */
+class OffsetList {  // Only ever stack-allocated, does not need to inherit UMemory.
+public:
+    OffsetList() : list(staticList), capacity(0), length(0), start(0) {}
+
+    ~OffsetList() {
+        if(list!=staticList) {
+            uprv_free(list);
+        }
+    }
+
+    // Call exactly once if the list is to be used.
+    void setMaxLength(int32_t maxLength) {
+        if(maxLength<=(int32_t)sizeof(staticList)) {
+            capacity=(int32_t)sizeof(staticList);
+        } else {
+            UBool *l=(UBool *)uprv_malloc(maxLength);
+            if(l!=NULL) {
+                list=l;
+                capacity=maxLength;
+            }
+        }
+        uprv_memset(list, 0, capacity);
+    }
+
+    void clear() {
+        uprv_memset(list, 0, capacity);
+        start=length=0;
+    }
+
+    UBool isEmpty() const {
+        return (UBool)(length==0);
+    }
+
+    // Reduce all stored offsets by delta, used when the current position
+    // moves by delta.
+    // There must not be any offsets lower than delta.
+    // If there is an offset equal to delta, it is removed.
+    // delta=[1..maxLength]
+    void shift(int32_t delta) {
+        int32_t i=start+delta;
+        if(i>=capacity) {
+            i-=capacity;
+        }
+        if(list[i]) {
+            list[i]=FALSE;
+            --length;
+        }
+        start=i;
+    }
+
+    // Add an offset. The list must not contain it yet.
+    // offset=[1..maxLength]
+    void addOffset(int32_t offset) {
+        int32_t i=start+offset;
+        if(i>=capacity) {
+            i-=capacity;
+        }
+        list[i]=TRUE;
+        ++length;
+    }
+
+    // offset=[1..maxLength]
+    UBool containsOffset(int32_t offset) const {
+        int32_t i=start+offset;
+        if(i>=capacity) {
+            i-=capacity;
+        }
+        return list[i];
+    }
+
+    // Find the lowest stored offset from a non-empty list, remove it,
+    // and reduce all other offsets by this minimum.
+    // Returns [1..maxLength].
+    int32_t popMinimum() {
+        // Look for the next offset in list[start+1..capacity-1].
+        int32_t i=start, result;
+        while(++i<capacity) {
+            if(list[i]) {
+                list[i]=FALSE;
+                --length;
+                result=i-start;
+                start=i;
+                return result;
+            }
+        }
+        // i==capacity
+
+        // Wrap around and look for the next offset in list[0..start].
+        // Since the list is not empty, there will be one.
+        result=capacity-start;
+        i=0;
+        while(!list[i]) {
+            ++i;
+        }
+        list[i]=FALSE;
+        --length;
+        start=i;
+        return result+=i;
+    }
+
+private:
+    UBool *list;
+    int32_t capacity;
+    int32_t length;
+    int32_t start;
+
+    UBool staticList[16];
+};
+
+// Get the number of UTF-8 bytes for a UTF-16 (sub)string.
+static int32_t
+getUTF8Length(const UChar *s, int32_t length) {
+    UErrorCode errorCode=U_ZERO_ERROR;
+    int32_t length8=0;
+    u_strToUTF8(NULL, 0, &length8, s, length, &errorCode);
+    if(U_SUCCESS(errorCode) || errorCode==U_BUFFER_OVERFLOW_ERROR) {
+        return length8;
+    } else {
+        // The string contains an unpaired surrogate.
+        // Ignore this string.
+        return 0;
+    }
+}
+
+// Append the UTF-8 version of the string to t and return the appended UTF-8 length.
+static int32_t
+appendUTF8(const UChar *s, int32_t length, uint8_t *t, int32_t capacity) {
+    UErrorCode errorCode=U_ZERO_ERROR;
+    int32_t length8=0;
+    u_strToUTF8((char *)t, capacity, &length8, s, length, &errorCode);
+    if(U_SUCCESS(errorCode)) {
+        return length8;
+    } else {
+        // The string contains an unpaired surrogate.
+        // Ignore this string.
+        return 0;
+    }
+}
+
+static inline uint8_t
+makeSpanLengthByte(int32_t spanLength) {
+    // 0xfe==UnicodeSetStringSpan::LONG_SPAN
+    return spanLength<0xfe ? (uint8_t)spanLength : (uint8_t)0xfe;
+}
+
+// Construct for all variants of span(), or only for any one variant.
+// Initialize as little as possible, for single use.
+UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSet &set,
+                                           const UVector &setStrings,
+                                           uint32_t which)
+        : spanSet(0, 0x10ffff), pSpanNotSet(NULL), strings(setStrings),
+          utf8Lengths(NULL), spanLengths(NULL), utf8(NULL),
+          utf8Length(0),
+          maxLength16(0), maxLength8(0),
+          all((UBool)(which==ALL)) {
+    spanSet.retainAll(set);
+    if(which&NOT_CONTAINED) {
+        // Default to the same sets.
+        // addToSpanNotSet() will create a separate set if necessary.
+        pSpanNotSet=&spanSet;
+    }
+
+    // Determine if the strings even need to be taken into account at all for span() etc.
+    // If any string is relevant, then all strings need to be used for
+    // span(longest match) but only the relevant ones for span(while contained).
+    // TODO: Possible optimization: Distinguish CONTAINED vs. LONGEST_MATCH
+    //   and do not store UTF-8 strings if !thisRelevant and CONTAINED.
+    //   (Only store irrelevant UTF-8 strings for LONGEST_MATCH where they are relevant after all.)
+    // Also count the lengths of the UTF-8 versions of the strings for memory allocation.
+    int32_t stringsLength=strings.size();
+
+    int32_t i, spanLength;
+    UBool someRelevant=FALSE;
+    for(i=0; i<stringsLength; ++i) {
+        const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
+        const UChar *s16=string.getBuffer();
+        int32_t length16=string.length();
+        UBool thisRelevant;
+        spanLength=spanSet.span(s16, length16, USET_SPAN_CONTAINED);
+        if(spanLength<length16) {  // Relevant string.
+            someRelevant=thisRelevant=TRUE;
+        } else {
+            thisRelevant=FALSE;
+        }
+        if((which&UTF16) && length16>maxLength16) {
+            maxLength16=length16;
+        }
+        if((which&UTF8) && (thisRelevant || (which&CONTAINED))) {
+            int32_t length8=getUTF8Length(s16, length16);
+            utf8Length+=length8;
+            if(length8>maxLength8) {
+                maxLength8=length8;
+            }
+        }
+    }
+    if(!someRelevant) {
+        maxLength16=maxLength8=0;
+        return;
+    }
+
+    // Freeze after checking for the need to use strings at all because freezing
+    // a set takes some time and memory which are wasted if there are no relevant strings.
+    if(all) {
+        spanSet.freeze();
+    }
+
+    uint8_t *spanBackLengths;
+    uint8_t *spanUTF8Lengths;
+    uint8_t *spanBackUTF8Lengths;
+
+    // Allocate a block of meta data.
+    int32_t allocSize;
+    if(all) {
+        // UTF-8 lengths, 4 sets of span lengths, UTF-8 strings.
+        allocSize=stringsLength*(4+1+1+1+1)+utf8Length;
+    } else {
+        allocSize=stringsLength;  // One set of span lengths.
+        if(which&UTF8) {
+            // UTF-8 lengths and UTF-8 strings.
+            allocSize+=stringsLength*4+utf8Length;
+        }
+    }
+    if(allocSize<=(int32_t)sizeof(staticLengths)) {
+        utf8Lengths=staticLengths;
+    } else {
+        utf8Lengths=(int32_t *)uprv_malloc(allocSize);
+        if(utf8Lengths==NULL) {
+            maxLength16=maxLength8=0;  // Prevent usage by making needsStringSpanUTF16/8() return FALSE.
+            return;  // Out of memory.
+        }
+    }
+
+    if(all) {
+        // Store span lengths for all span() variants.
+        spanLengths=(uint8_t *)(utf8Lengths+stringsLength);
+        spanBackLengths=spanLengths+stringsLength;
+        spanUTF8Lengths=spanBackLengths+stringsLength;
+        spanBackUTF8Lengths=spanUTF8Lengths+stringsLength;
+        utf8=spanBackUTF8Lengths+stringsLength;
+    } else {
+        // Store span lengths for only one span() variant.
+        if(which&UTF8) {
+            spanLengths=(uint8_t *)(utf8Lengths+stringsLength);
+            utf8=spanLengths+stringsLength;
+        } else {
+            spanLengths=(uint8_t *)utf8Lengths;
+        }
+        spanBackLengths=spanUTF8Lengths=spanBackUTF8Lengths=spanLengths;
+    }
+
+    // Set the meta data and pSpanNotSet and write the UTF-8 strings.
+    int32_t utf8Count=0;  // Count UTF-8 bytes written so far.
+
+    for(i=0; i<stringsLength; ++i) {
+        const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
+        const UChar *s16=string.getBuffer();
+        int32_t length16=string.length();
+        spanLength=spanSet.span(s16, length16, USET_SPAN_CONTAINED);
+        if(spanLength<length16) {  // Relevant string.
+            if(which&UTF16) {
+                if(which&CONTAINED) {
+                    if(which&FWD) {
+                        spanLengths[i]=makeSpanLengthByte(spanLength);
+                    }
+                    if(which&BACK) {
+                        spanLength=length16-spanSet.spanBack(s16, length16, USET_SPAN_CONTAINED);
+                        spanBackLengths[i]=makeSpanLengthByte(spanLength);
+                    }
+                } else /* not CONTAINED, not all, but NOT_CONTAINED */ {
+                    spanLengths[i]=spanBackLengths[i]=0;  // Only store a relevant/irrelevant flag.
+                }
+            }
+            if(which&UTF8) {
+                uint8_t *s8=utf8+utf8Count;
+                int32_t length8=appendUTF8(s16, length16, s8, utf8Length-utf8Count);
+                utf8Count+=utf8Lengths[i]=length8;
+                if(length8==0) {  // Irrelevant for UTF-8 because not representable in UTF-8.
+                    spanUTF8Lengths[i]=spanBackUTF8Lengths[i]=(uint8_t)ALL_CP_CONTAINED;
+                } else {  // Relevant for UTF-8.
+                    if(which&CONTAINED) {
+                        if(which&FWD) {
+                            spanLength=spanSet.spanUTF8((const char *)s8, length8, USET_SPAN_CONTAINED);
+                            spanUTF8Lengths[i]=makeSpanLengthByte(spanLength);
+                        }
+                        if(which&BACK) {
+                            spanLength=length8-spanSet.spanBackUTF8((const char *)s8, length8, USET_SPAN_CONTAINED);
+                            spanBackUTF8Lengths[i]=makeSpanLengthByte(spanLength);
+                        }
+                    } else /* not CONTAINED, not all, but NOT_CONTAINED */ {
+                        spanUTF8Lengths[i]=spanBackUTF8Lengths[i]=0;  // Only store a relevant/irrelevant flag.
+                    }
+                }
+            }
+            if(which&NOT_CONTAINED) {
+                // Add string start and end code points to the spanNotSet so that
+                // a span(while not contained) stops before any string.
+                UChar32 c;
+                if(which&FWD) {
+                    int32_t len=0;
+                    U16_NEXT(s16, len, length16, c);
+                    addToSpanNotSet(c);
+                }
+                if(which&BACK) {
+                    int32_t len=length16;
+                    U16_PREV(s16, 0, len, c);
+                    addToSpanNotSet(c);
+                }
+            }
+        } else {  // Irrelevant string.
+            if(which&UTF8) {
+                if(which&CONTAINED) {  // Only necessary for LONGEST_MATCH.
+                    uint8_t *s8=utf8+utf8Count;
+                    int32_t length8=appendUTF8(s16, length16, s8, utf8Length-utf8Count);
+                    utf8Count+=utf8Lengths[i]=length8;
+                } else {
+                    utf8Lengths[i]=0;
+                }
+            }
+            if(all) {
+                spanLengths[i]=spanBackLengths[i]=
+                    spanUTF8Lengths[i]=spanBackUTF8Lengths[i]=
+                        (uint8_t)ALL_CP_CONTAINED;
+            } else {
+                // All spanXYZLengths pointers contain the same address.
+                spanLengths[i]=(uint8_t)ALL_CP_CONTAINED;
+            }
+        }
+    }
+
+    // Finish.
+    if(all) {
+        pSpanNotSet->freeze();
+    }
+}
+
+// Copy constructor. Assumes which==ALL for a frozen set.
+UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSetStringSpan &otherStringSpan,
+                                           const UVector &newParentSetStrings)
+        : spanSet(otherStringSpan.spanSet), pSpanNotSet(NULL), strings(newParentSetStrings),
+          utf8Lengths(NULL), spanLengths(NULL), utf8(NULL),
+          utf8Length(otherStringSpan.utf8Length),
+          maxLength16(otherStringSpan.maxLength16), maxLength8(otherStringSpan.maxLength8),
+          all(TRUE) {
+    if(otherStringSpan.pSpanNotSet==&otherStringSpan.spanSet) {
+        pSpanNotSet=&spanSet;
+    } else {
+        pSpanNotSet=(UnicodeSet *)otherStringSpan.pSpanNotSet->clone();
+    }
+
+    // Allocate a block of meta data.
+    // UTF-8 lengths, 4 sets of span lengths, UTF-8 strings.
+    int32_t stringsLength=strings.size();
+    int32_t allocSize=stringsLength*(4+1+1+1+1)+utf8Length;
+    if(allocSize<=(int32_t)sizeof(staticLengths)) {
+        utf8Lengths=staticLengths;
+    } else {
+        utf8Lengths=(int32_t *)uprv_malloc(allocSize);
+        if(utf8Lengths==NULL) {
+            maxLength16=maxLength8=0;  // Prevent usage by making needsStringSpanUTF16/8() return FALSE.
+            return;  // Out of memory.
+        }
+    }
+
+    spanLengths=(uint8_t *)(utf8Lengths+stringsLength);
+    utf8=spanLengths+stringsLength*4;
+    uprv_memcpy(utf8Lengths, otherStringSpan.utf8Lengths, allocSize);
+}
+
+UnicodeSetStringSpan::~UnicodeSetStringSpan() {
+    if(pSpanNotSet!=NULL && pSpanNotSet!=&spanSet) {
+        delete pSpanNotSet;
+    }
+    if(utf8Lengths!=NULL && utf8Lengths!=staticLengths) {
+        uprv_free(utf8Lengths);
+    }
+}
+
+void UnicodeSetStringSpan::addToSpanNotSet(UChar32 c) {
+    if(pSpanNotSet==NULL || pSpanNotSet==&spanSet) {
+        if(spanSet.contains(c)) {
+            return;  // Nothing to do.
+        }
+        UnicodeSet *newSet=(UnicodeSet *)spanSet.cloneAsThawed();
+        if(newSet==NULL) {
+            return;  // Out of memory.
+        } else {
+            pSpanNotSet=newSet;
+        }
+    }
+    pSpanNotSet->add(c);
+}
+
+// Compare strings without any argument checks. Requires length>0.
+static inline UBool
+matches16(const UChar *s, const UChar *t, int32_t length) {
+    do {
+        if(*s++!=*t++) {
+            return FALSE;
+        }
+    } while(--length>0);
+    return TRUE;
+}
+
+static inline UBool
+matches8(const uint8_t *s, const uint8_t *t, int32_t length) {
+    do {
+        if(*s++!=*t++) {
+            return FALSE;
+        }
+    } while(--length>0);
+    return TRUE;
+}
+
+// Compare 16-bit Unicode strings (which may be malformed UTF-16)
+// at code point boundaries.
+// That is, each edge of a match must not be in the middle of a surrogate pair.
+static inline UBool
+matches16CPB(const UChar *s, int32_t start, int32_t limit, const UChar *t, int32_t length) {
+    s+=start;
+    limit-=start;
+    return matches16(s, t, length) &&
+           !(0<start && U16_IS_LEAD(s[-1]) && U16_IS_TRAIL(s[0])) &&
+           !(length<limit && U16_IS_LEAD(s[length-1]) && U16_IS_TRAIL(s[length]));
+}
+
+// Does the set contain the next code point?
+// If so, return its length; otherwise return its negative length.
+static inline int32_t
+spanOne(const UnicodeSet &set, const UChar *s, int32_t length) {
+    UChar c=*s, c2;
+    if(c>=0xd800 && c<=0xdbff && length>=2 && U16_IS_TRAIL(c2=s[1])) {
+        return set.contains(U16_GET_SUPPLEMENTARY(c, c2)) ? 2 : -2;
+    }
+    return set.contains(c) ? 1 : -1;
+}
+
+static inline int32_t
+spanOneBack(const UnicodeSet &set, const UChar *s, int32_t length) {
+    UChar c=s[length-1], c2;
+    if(c>=0xdc00 && c<=0xdfff && length>=2 && U16_IS_LEAD(c2=s[length-2])) {
+        return set.contains(U16_GET_SUPPLEMENTARY(c2, c)) ? 2 : -2;
+    }
+    return set.contains(c) ? 1 : -1;
+}
+
+static inline int32_t
+spanOneUTF8(const UnicodeSet &set, const uint8_t *s, int32_t length) {
+    UChar32 c=*s;
+    if((int8_t)c>=0) {
+        return set.contains(c) ? 1 : -1;
+    }
+    // Take advantage of non-ASCII fastpaths in U8_NEXT().
+    int32_t i=0;
+    U8_NEXT(s, i, length, c);
+    return set.contains(c) ? i : -i;
+}
+
+static inline int32_t
+spanOneBackUTF8(const UnicodeSet &set, const uint8_t *s, int32_t length) {
+    UChar32 c=s[length-1];
+    if((int8_t)c>=0) {
+        return set.contains(c) ? 1 : -1;
+    }
+    int32_t i=length-1;
+    c=utf8_prevCharSafeBody(s, 0, &i, c, -1);
+    length-=i;
+    return set.contains(c) ? length : -length;
+}
+
+/*
+ * Note: In span() when spanLength==0 (after a string match, or at the beginning
+ * after an empty code point span) and in spanNot() and spanNotUTF8(),
+ * string matching could use a binary search
+ * because all string matches are done from the same start index.
+ *
+ * For UTF-8, this would require a comparison function that returns UTF-16 order.
+ *
+ * This optimization should not be necessary for normal UnicodeSets because
+ * most sets have no strings, and most sets with strings have
+ * very few very short strings.
+ * For cases with many strings, it might be better to use a different API
+ * and implementation with a DFA (state machine).
+ */
+
+/*
+ * Algorithm for span(USET_SPAN_CONTAINED)
+ *
+ * Theoretical algorithm:
+ * - Iterate through the string, and at each code point boundary:
+ *   + If the code point there is in the set, then remember to continue after it.
+ *   + If a set string matches at the current position, then remember to continue after it.
+ *   + Either recursively span for each code point or string match,
+ *     or recursively span for all but the shortest one and
+ *     iteratively continue the span with the shortest local match.
+ *   + Remember the longest recursive span (the farthest end point).
+ *   + If there is no match at the current position, neither for the code point there
+ *     nor for any set string, then stop and return the longest recursive span length.
+ *
+ * Optimized implementation:
+ *
+ * (We assume that most sets will have very few very short strings.
+ * A span using a string-less set is extremely fast.)
+ *
+ * Create and cache a spanSet which contains all of the single code points
+ * of the original set but none of its strings.
+ *
+ * - Start with spanLength=spanSet.span(USET_SPAN_CONTAINED).
+ * - Loop:
+ *   + Try to match each set string at the end of the spanLength.
+ *     ~ Set strings that start with set-contained code points must be matched
+ *       with a partial overlap because the recursive algorithm would have tried
+ *       to match them at every position.
+ *     ~ Set strings that entirely consist of set-contained code points
+ *       are irrelevant for span(USET_SPAN_CONTAINED) because the
+ *       recursive algorithm would continue after them anyway
+ *       and find the longest recursive match from their end.
+ *     ~ Rather than recursing, note each end point of a set string match.
+ *   + If no set string matched after spanSet.span(), then return
+ *     with where the spanSet.span() ended.
+ *   + If at least one set string matched after spanSet.span(), then
+ *     pop the shortest string match end point and continue
+ *     the loop, trying to match all set strings from there.
+ *   + If at least one more set string matched after a previous string match,
+ *     then test if the code point after the previous string match is also
+ *     contained in the set.
+ *     Continue the loop with the shortest end point of either this code point
+ *     or a matching set string.
+ *   + If no more set string matched after a previous string match,
+ *     then try another spanLength=spanSet.span(USET_SPAN_CONTAINED).
+ *     Stop if spanLength==0, otherwise continue the loop.
+ *
+ * By noting each end point of a set string match,
+ * the function visits each string position at most once and finishes
+ * in linear time.
+ *
+ * The recursive algorithm may visit the same string position many times
+ * if multiple paths lead to it and finishes in exponential time.
+ */
+
+/*
+ * Algorithm for span(USET_SPAN_SIMPLE)
+ *
+ * Theoretical algorithm:
+ * - Iterate through the string, and at each code point boundary:
+ *   + If the code point there is in the set, then remember to continue after it.
+ *   + If a set string matches at the current position, then remember to continue after it.
+ *   + Continue from the farthest match position and ignore all others.
+ *   + If there is no match at the current position,
+ *     then stop and return the current position.
+ *
+ * Optimized implementation:
+ *
+ * (Same assumption and spanSet as above.)
+ *
+ * - Start with spanLength=spanSet.span(USET_SPAN_CONTAINED).
+ * - Loop:
+ *   + Try to match each set string at the end of the spanLength.
+ *     ~ Set strings that start with set-contained code points must be matched
+ *       with a partial overlap because the standard algorithm would have tried
+ *       to match them earlier.
+ *     ~ Set strings that entirely consist of set-contained code points
+ *       must be matched with a full overlap because the longest-match algorithm
+ *       would hide set string matches that end earlier.
+ *       Such set strings need not be matched earlier inside the code point span
+ *       because the standard algorithm would then have continued after
+ *       the set string match anyway.
+ *     ~ Remember the longest set string match (farthest end point) from the earliest
+ *       starting point.
+ *   + If no set string matched after spanSet.span(), then return
+ *     with where the spanSet.span() ended.
+ *   + If at least one set string matched, then continue the loop after the
+ *     longest match from the earliest position.
+ *   + If no more set string matched after a previous string match,
+ *     then try another spanLength=spanSet.span(USET_SPAN_CONTAINED).
+ *     Stop if spanLength==0, otherwise continue the loop.
+ */
+
+int32_t UnicodeSetStringSpan::span(const UChar *s, int32_t length, USetSpanCondition spanCondition) const {
+    if(spanCondition==USET_SPAN_NOT_CONTAINED) {
+        return spanNot(s, length);
+    }
+    int32_t spanLength=spanSet.span(s, length, USET_SPAN_CONTAINED);
+    if(spanLength==length) {
+        return length;
+    }
+
+    // Consider strings; they may overlap with the span.
+    OffsetList offsets;
+    if(spanCondition==USET_SPAN_CONTAINED) {
+        // Use offset list to try all possibilities.
+        offsets.setMaxLength(maxLength16);
+    }
+    int32_t pos=spanLength, rest=length-pos;
+    int32_t i, stringsLength=strings.size();
+    for(;;) {
+        if(spanCondition==USET_SPAN_CONTAINED) {
+            for(i=0; i<stringsLength; ++i) {
+                int32_t overlap=spanLengths[i];
+                if(overlap==ALL_CP_CONTAINED) {
+                    continue;  // Irrelevant string.
+                }
+                const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
+                const UChar *s16=string.getBuffer();
+                int32_t length16=string.length();
+
+                // Try to match this string at pos-overlap..pos.
+                if(overlap>=LONG_SPAN) {
+                    overlap=length16;
+                    // While contained: No point matching fully inside the code point span.
+                    U16_BACK_1(s16, 0, overlap);  // Length of the string minus the last code point.
+                }
+                if(overlap>spanLength) {
+                    overlap=spanLength;
+                }
+                int32_t inc=length16-overlap;  // Keep overlap+inc==length16.
+                for(;;) {
+                    if(inc>rest) {
+                        break;
+                    }
+                    // Try to match if the increment is not listed already.
+                    if(!offsets.containsOffset(inc) && matches16CPB(s, pos-overlap, length, s16, length16)) {
+                        if(inc==rest) {
+                            return length;  // Reached the end of the string.
+                        }
+                        offsets.addOffset(inc);
+                    }
+                    if(overlap==0) {
+                        break;
+                    }
+                    --overlap;
+                    ++inc;
+                }
+            }
+        } else /* USET_SPAN_SIMPLE */ {
+            int32_t maxInc=0, maxOverlap=0;
+            for(i=0; i<stringsLength; ++i) {
+                int32_t overlap=spanLengths[i];
+                // For longest match, we do need to try to match even an all-contained string
+                // to find the match from the earliest start.
+
+                const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
+                const UChar *s16=string.getBuffer();
+                int32_t length16=string.length();
+
+                // Try to match this string at pos-overlap..pos.
+                if(overlap>=LONG_SPAN) {
+                    overlap=length16;
+                    // Longest match: Need to match fully inside the code point span
+                    // to find the match from the earliest start.
+                }
+                if(overlap>spanLength) {
+                    overlap=spanLength;
+                }
+                int32_t inc=length16-overlap;  // Keep overlap+inc==length16.
+                for(;;) {
+                    if(inc>rest || overlap<maxOverlap) {
+                        break;
+                    }
+                    // Try to match if the string is longer or starts earlier.
+                    if( (overlap>maxOverlap || /* redundant overlap==maxOverlap && */ inc>maxInc) &&
+                        matches16CPB(s, pos-overlap, length, s16, length16)
+                    ) {
+                        maxInc=inc;  // Longest match from earliest start.
+                        maxOverlap=overlap;
+                        break;
+                    }
+                    --overlap;
+                    ++inc;
+                }
+            }
+
+            if(maxInc!=0 || maxOverlap!=0) {
+                // Longest-match algorithm, and there was a string match.
+                // Simply continue after it.
+                pos+=maxInc;
+                rest-=maxInc;
+                if(rest==0) {
+                    return length;  // Reached the end of the string.
+                }
+                spanLength=0;  // Match strings from after a string match.
+                continue;
+            }
+        }
+        // Finished trying to match all strings at pos.
+
+        if(spanLength!=0 || pos==0) {
+            // The position is after an unlimited code point span (spanLength!=0),
+            // not after a string match.
+            // The only position where spanLength==0 after a span is pos==0.
+            // Otherwise, an unlimited code point span is only tried again when no
+            // strings match, and if such a non-initial span fails we stop.
+            if(offsets.isEmpty()) {
+                return pos;  // No strings matched after a span.
+            }
+            // Match strings from after the next string match.
+        } else {
+            // The position is after a string match (or a single code point).
+            if(offsets.isEmpty()) {
+                // No more strings matched after a previous string match.
+                // Try another code point span from after the last string match.
+                spanLength=spanSet.span(s+pos, rest, USET_SPAN_CONTAINED);
+                if( spanLength==rest || // Reached the end of the string, or
+                    spanLength==0       // neither strings nor span progressed.
+                ) {
+                    return pos+spanLength;
+                }
+                pos+=spanLength;
+                rest-=spanLength;
+                continue;  // spanLength>0: Match strings from after a span.
+            } else {
+                // Try to match only one code point from after a string match if some
+                // string matched beyond it, so that we try all possible positions
+                // and don't overshoot.
+                spanLength=spanOne(spanSet, s+pos, rest);
+                if(spanLength>0) {
+                    if(spanLength==rest) {
+                        return length;  // Reached the end of the string.
+                    }
+                    // Match strings after this code point.
+                    // There cannot be any increments below it because UnicodeSet strings
+                    // contain multiple code points.
+                    pos+=spanLength;
+                    rest-=spanLength;
+                    offsets.shift(spanLength);
+                    spanLength=0;
+                    continue;  // Match strings from after a single code point.
+                }
+                // Match strings from after the next string match.
+            }
+        }
+        int32_t minOffset=offsets.popMinimum();
+        pos+=minOffset;
+        rest-=minOffset;
+        spanLength=0;  // Match strings from after a string match.
+    }
+}
+
+int32_t UnicodeSetStringSpan::spanBack(const UChar *s, int32_t length, USetSpanCondition spanCondition) const {
+    if(spanCondition==USET_SPAN_NOT_CONTAINED) {
+        return spanNotBack(s, length);
+    }
+    int32_t pos=spanSet.spanBack(s, length, USET_SPAN_CONTAINED);
+    if(pos==0) {
+        return 0;
+    }
+    int32_t spanLength=length-pos;
+
+    // Consider strings; they may overlap with the span.
+    OffsetList offsets;
+    if(spanCondition==USET_SPAN_CONTAINED) {
+        // Use offset list to try all possibilities.
+        offsets.setMaxLength(maxLength16);
+    }
+    int32_t i, stringsLength=strings.size();
+    uint8_t *spanBackLengths=spanLengths;
+    if(all) {
+        spanBackLengths+=stringsLength;
+    }
+    for(;;) {
+        if(spanCondition==USET_SPAN_CONTAINED) {
+            for(i=0; i<stringsLength; ++i) {
+                int32_t overlap=spanBackLengths[i];
+                if(overlap==ALL_CP_CONTAINED) {
+                    continue;  // Irrelevant string.
+                }
+                const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
+                const UChar *s16=string.getBuffer();
+                int32_t length16=string.length();
+
+                // Try to match this string at pos-(length16-overlap)..pos-length16.
+                if(overlap>=LONG_SPAN) {
+                    overlap=length16;
+                    // While contained: No point matching fully inside the code point span.
+                    int32_t len1=0;
+                    U16_FWD_1(s16, len1, overlap);
+                    overlap-=len1;  // Length of the string minus the first code point.
+                }
+                if(overlap>spanLength) {
+                    overlap=spanLength;
+                }
+                int32_t dec=length16-overlap;  // Keep dec+overlap==length16.
+                for(;;) {
+                    if(dec>pos) {
+                        break;
+                    }
+                    // Try to match if the decrement is not listed already.
+                    if(!offsets.containsOffset(dec) && matches16CPB(s, pos-dec, length, s16, length16)) {
+                        if(dec==pos) {
+                            return 0;  // Reached the start of the string.
+                        }
+                        offsets.addOffset(dec);
+                    }
+                    if(overlap==0) {
+                        break;
+                    }
+                    --overlap;
+                    ++dec;
+                }
+            }
+        } else /* USET_SPAN_SIMPLE */ {
+            int32_t maxDec=0, maxOverlap=0;
+            for(i=0; i<stringsLength; ++i) {
+                int32_t overlap=spanBackLengths[i];
+                // For longest match, we do need to try to match even an all-contained string
+                // to find the match from the latest end.
+
+                const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
+                const UChar *s16=string.getBuffer();
+                int32_t length16=string.length();
+
+                // Try to match this string at pos-(length16-overlap)..pos-length16.
+                if(overlap>=LONG_SPAN) {
+                    overlap=length16;
+                    // Longest match: Need to match fully inside the code point span
+                    // to find the match from the latest end.
+                }
+                if(overlap>spanLength) {
+                    overlap=spanLength;
+                }
+                int32_t dec=length16-overlap;  // Keep dec+overlap==length16.
+                for(;;) {
+                    if(dec>pos || overlap<maxOverlap) {
+                        break;
+                    }
+                    // Try to match if the string is longer or ends later.
+                    if( (overlap>maxOverlap || /* redundant overlap==maxOverlap && */ dec>maxDec) &&
+                        matches16CPB(s, pos-dec, length, s16, length16)
+                    ) {
+                        maxDec=dec;  // Longest match from latest end.
+                        maxOverlap=overlap;
+                        break;
+                    }
+                    --overlap;
+                    ++dec;
+                }
+            }
+
+            if(maxDec!=0 || maxOverlap!=0) {
+                // Longest-match algorithm, and there was a string match.
+                // Simply continue before it.
+                pos-=maxDec;
+                if(pos==0) {
+                    return 0;  // Reached the start of the string.
+                }
+                spanLength=0;  // Match strings from before a string match.
+                continue;
+            }
+        }
+        // Finished trying to match all strings at pos.
+
+        if(spanLength!=0 || pos==length) {
+            // The position is before an unlimited code point span (spanLength!=0),
+            // not before a string match.
+            // The only position where spanLength==0 before a span is pos==length.
+            // Otherwise, an unlimited code point span is only tried again when no
+            // strings match, and if such a non-initial span fails we stop.
+            if(offsets.isEmpty()) {
+                return pos;  // No strings matched before a span.
+            }
+            // Match strings from before the next string match.
+        } else {
+            // The position is before a string match (or a single code point).
+            if(offsets.isEmpty()) {
+                // No more strings matched before a previous string match.
+                // Try another code point span from before the last string match.
+                int32_t oldPos=pos;
+                pos=spanSet.spanBack(s, oldPos, USET_SPAN_CONTAINED);
+                spanLength=oldPos-pos;
+                if( pos==0 ||           // Reached the start of the string, or
+                    spanLength==0       // neither strings nor span progressed.
+                ) {
+                    return pos;
+                }
+                continue;  // spanLength>0: Match strings from before a span.
+            } else {
+                // Try to match only one code point from before a string match if some
+                // string matched beyond it, so that we try all possible positions
+                // and don't overshoot.
+                spanLength=spanOneBack(spanSet, s, pos);
+                if(spanLength>0) {
+                    if(spanLength==pos) {
+                        return 0;  // Reached the start of the string.
+                    }
+                    // Match strings before this code point.
+                    // There cannot be any decrements below it because UnicodeSet strings
+                    // contain multiple code points.
+                    pos-=spanLength;
+                    offsets.shift(spanLength);
+                    spanLength=0;
+                    continue;  // Match strings from before a single code point.
+                }
+                // Match strings from before the next string match.
+            }
+        }
+        pos-=offsets.popMinimum();
+        spanLength=0;  // Match strings from before a string match.
+    }
+}
+
+int32_t UnicodeSetStringSpan::spanUTF8(const uint8_t *s, int32_t length, USetSpanCondition spanCondition) const {
+    if(spanCondition==USET_SPAN_NOT_CONTAINED) {
+        return spanNotUTF8(s, length);
+    }
+    int32_t spanLength=spanSet.spanUTF8((const char *)s, length, USET_SPAN_CONTAINED);
+    if(spanLength==length) {
+        return length;
+    }
+
+    // Consider strings; they may overlap with the span.
+    OffsetList offsets;
+    if(spanCondition==USET_SPAN_CONTAINED) {
+        // Use offset list to try all possibilities.
+        offsets.setMaxLength(maxLength8);
+    }
+    int32_t pos=spanLength, rest=length-pos;
+    int32_t i, stringsLength=strings.size();
+    uint8_t *spanUTF8Lengths=spanLengths;
+    if(all) {
+        spanUTF8Lengths+=2*stringsLength;
+    }
+    for(;;) {
+        const uint8_t *s8=utf8;
+        int32_t length8;
+        if(spanCondition==USET_SPAN_CONTAINED) {
+            for(i=0; i<stringsLength; ++i) {
+                length8=utf8Lengths[i];
+                if(length8==0) {
+                    continue;  // String not representable in UTF-8.
+                }
+                int32_t overlap=spanUTF8Lengths[i];
+                if(overlap==ALL_CP_CONTAINED) {
+                    s8+=length8;
+                    continue;  // Irrelevant string.
+                }
+
+                // Try to match this string at pos-overlap..pos.
+                if(overlap>=LONG_SPAN) {
+                    overlap=length8;
+                    // While contained: No point matching fully inside the code point span.
+                    U8_BACK_1(s8, 0, overlap);  // Length of the string minus the last code point.
+                }
+                if(overlap>spanLength) {
+                    overlap=spanLength;
+                }
+                int32_t inc=length8-overlap;  // Keep overlap+inc==length8.
+                for(;;) {
+                    if(inc>rest) {
+                        break;
+                    }
+                    // Try to match if the increment is not listed already.
+                    // Match at code point boundaries. (The UTF-8 strings were converted
+                    // from UTF-16 and are guaranteed to be well-formed.)
+                    if( !U8_IS_TRAIL(s[pos-overlap]) &&
+                        !offsets.containsOffset(inc) &&
+                        matches8(s+pos-overlap, s8, length8)
+                        
+                    ) {
+                        if(inc==rest) {
+                            return length;  // Reached the end of the string.
+                        }
+                        offsets.addOffset(inc);
+                    }
+                    if(overlap==0) {
+                        break;
+                    }
+                    --overlap;
+                    ++inc;
+                }
+                s8+=length8;
+            }
+        } else /* USET_SPAN_SIMPLE */ {
+            int32_t maxInc=0, maxOverlap=0;
+            for(i=0; i<stringsLength; ++i) {
+                length8=utf8Lengths[i];
+                if(length8==0) {
+                    continue;  // String not representable in UTF-8.
+                }
+                int32_t overlap=spanUTF8Lengths[i];
+                // For longest match, we do need to try to match even an all-contained string
+                // to find the match from the earliest start.
+
+                // Try to match this string at pos-overlap..pos.
+                if(overlap>=LONG_SPAN) {
+                    overlap=length8;
+                    // Longest match: Need to match fully inside the code point span
+                    // to find the match from the earliest start.
+                }
+                if(overlap>spanLength) {
+                    overlap=spanLength;
+                }
+                int32_t inc=length8-overlap;  // Keep overlap+inc==length8.
+                for(;;) {
+                    if(inc>rest || overlap<maxOverlap) {
+                        break;
+                    }
+                    // Try to match if the string is longer or starts earlier.
+                    // Match at code point boundaries. (The UTF-8 strings were converted
+                    // from UTF-16 and are guaranteed to be well-formed.)
+                    if( !U8_IS_TRAIL(s[pos-overlap]) &&
+                        (overlap>maxOverlap || /* redundant overlap==maxOverlap && */ inc>maxInc) &&
+                        matches8(s+pos-overlap, s8, length8)
+                        
+                    ) {
+                        maxInc=inc;  // Longest match from earliest start.
+                        maxOverlap=overlap;
+                        break;
+                    }
+                    --overlap;
+                    ++inc;
+                }
+                s8+=length8;
+            }
+
+            if(maxInc!=0 || maxOverlap!=0) {
+                // Longest-match algorithm, and there was a string match.
+                // Simply continue after it.
+                pos+=maxInc;
+                rest-=maxInc;
+                if(rest==0) {
+                    return length;  // Reached the end of the string.
+                }
+                spanLength=0;  // Match strings from after a string match.
+                continue;
+            }
+        }
+        // Finished trying to match all strings at pos.
+
+        if(spanLength!=0 || pos==0) {
+            // The position is after an unlimited code point span (spanLength!=0),
+            // not after a string match.
+            // The only position where spanLength==0 after a span is pos==0.
+            // Otherwise, an unlimited code point span is only tried again when no
+            // strings match, and if such a non-initial span fails we stop.
+            if(offsets.isEmpty()) {
+                return pos;  // No strings matched after a span.
+            }
+            // Match strings from after the next string match.
+        } else {
+            // The position is after a string match (or a single code point).
+            if(offsets.isEmpty()) {
+                // No more strings matched after a previous string match.
+                // Try another code point span from after the last string match.
+                spanLength=spanSet.spanUTF8((const char *)s+pos, rest, USET_SPAN_CONTAINED);
+                if( spanLength==rest || // Reached the end of the string, or
+                    spanLength==0       // neither strings nor span progressed.
+                ) {
+                    return pos+spanLength;
+                }
+                pos+=spanLength;
+                rest-=spanLength;
+                continue;  // spanLength>0: Match strings from after a span.
+            } else {
+                // Try to match only one code point from after a string match if some
+                // string matched beyond it, so that we try all possible positions
+                // and don't overshoot.
+                spanLength=spanOneUTF8(spanSet, s+pos, rest);
+                if(spanLength>0) {
+                    if(spanLength==rest) {
+                        return length;  // Reached the end of the string.
+                    }
+                    // Match strings after this code point.
+                    // There cannot be any increments below it because UnicodeSet strings
+                    // contain multiple code points.
+                    pos+=spanLength;
+                    rest-=spanLength;
+                    offsets.shift(spanLength);
+                    spanLength=0;
+                    continue;  // Match strings from after a single code point.
+                }
+                // Match strings from after the next string match.
+            }
+        }
+        int32_t minOffset=offsets.popMinimum();
+        pos+=minOffset;
+        rest-=minOffset;
+        spanLength=0;  // Match strings from after a string match.
+    }
+}
+
+int32_t UnicodeSetStringSpan::spanBackUTF8(const uint8_t *s, int32_t length, USetSpanCondition spanCondition) const {
+    if(spanCondition==USET_SPAN_NOT_CONTAINED) {
+        return spanNotBackUTF8(s, length);
+    }
+    int32_t pos=spanSet.spanBackUTF8((const char *)s, length, USET_SPAN_CONTAINED);
+    if(pos==0) {
+        return 0;
+    }
+    int32_t spanLength=length-pos;
+
+    // Consider strings; they may overlap with the span.
+    OffsetList offsets;
+    if(spanCondition==USET_SPAN_CONTAINED) {
+        // Use offset list to try all possibilities.
+        offsets.setMaxLength(maxLength8);
+    }
+    int32_t i, stringsLength=strings.size();
+    uint8_t *spanBackUTF8Lengths=spanLengths;
+    if(all) {
+        spanBackUTF8Lengths+=3*stringsLength;
+    }
+    for(;;) {
+        const uint8_t *s8=utf8;
+        int32_t length8;
+        if(spanCondition==USET_SPAN_CONTAINED) {
+            for(i=0; i<stringsLength; ++i) {
+                length8=utf8Lengths[i];
+                if(length8==0) {
+                    continue;  // String not representable in UTF-8.
+                }
+                int32_t overlap=spanBackUTF8Lengths[i];
+                if(overlap==ALL_CP_CONTAINED) {
+                    s8+=length8;
+                    continue;  // Irrelevant string.
+                }
+
+                // Try to match this string at pos-(length8-overlap)..pos-length8.
+                if(overlap>=LONG_SPAN) {
+                    overlap=length8;
+                    // While contained: No point matching fully inside the code point span.
+                    int32_t len1=0;
+                    U8_FWD_1(s8, len1, overlap);
+                    overlap-=len1;  // Length of the string minus the first code point.
+                }
+                if(overlap>spanLength) {
+                    overlap=spanLength;
+                }
+                int32_t dec=length8-overlap;  // Keep dec+overlap==length8.
+                for(;;) {
+                    if(dec>pos) {
+                        break;
+                    }
+                    // Try to match if the decrement is not listed already.
+                    // Match at code point boundaries. (The UTF-8 strings were converted
+                    // from UTF-16 and are guaranteed to be well-formed.)
+                    if( !U8_IS_TRAIL(s[pos-dec]) &&
+                        !offsets.containsOffset(dec) &&
+                        matches8(s+pos-dec, s8, length8)
+                    ) {
+                        if(dec==pos) {
+                            return 0;  // Reached the start of the string.
+                        }
+                        offsets.addOffset(dec);
+                    }
+                    if(overlap==0) {
+                        break;
+                    }
+                    --overlap;
+                    ++dec;
+                }
+                s8+=length8;
+            }
+        } else /* USET_SPAN_SIMPLE */ {
+            int32_t maxDec=0, maxOverlap=0;
+            for(i=0; i<stringsLength; ++i) {
+                length8=utf8Lengths[i];
+                if(length8==0) {
+                    continue;  // String not representable in UTF-8.
+                }
+                int32_t overlap=spanBackUTF8Lengths[i];
+                // For longest match, we do need to try to match even an all-contained string
+                // to find the match from the latest end.
+
+                // Try to match this string at pos-(length8-overlap)..pos-length8.
+                if(overlap>=LONG_SPAN) {
+                    overlap=length8;
+                    // Longest match: Need to match fully inside the code point span
+                    // to find the match from the latest end.
+                }
+                if(overlap>spanLength) {
+                    overlap=spanLength;
+                }
+                int32_t dec=length8-overlap;  // Keep dec+overlap==length8.
+                for(;;) {
+                    if(dec>pos || overlap<maxOverlap) {
+                        break;
+                    }
+                    // Try to match if the string is longer or ends later.
+                    // Match at code point boundaries. (The UTF-8 strings were converted
+                    // from UTF-16 and are guaranteed to be well-formed.)
+                    if( !U8_IS_TRAIL(s[pos-dec]) &&
+                        (overlap>maxOverlap || /* redundant overlap==maxOverlap && */ dec>maxDec) &&
+                        matches8(s+pos-dec, s8, length8)
+                    ) {
+                        maxDec=dec;  // Longest match from latest end.
+                        maxOverlap=overlap;
+                        break;
+                    }
+                    --overlap;
+                    ++dec;
+                }
+                s8+=length8;
+            }
+
+            if(maxDec!=0 || maxOverlap!=0) {
+                // Longest-match algorithm, and there was a string match.
+                // Simply continue before it.
+                pos-=maxDec;
+                if(pos==0) {
+                    return 0;  // Reached the start of the string.
+                }
+                spanLength=0;  // Match strings from before a string match.
+                continue;
+            }
+        }
+        // Finished trying to match all strings at pos.
+
+        if(spanLength!=0 || pos==length) {
+            // The position is before an unlimited code point span (spanLength!=0),
+            // not before a string match.
+            // The only position where spanLength==0 before a span is pos==length.
+            // Otherwise, an unlimited code point span is only tried again when no
+            // strings match, and if such a non-initial span fails we stop.
+            if(offsets.isEmpty()) {
+                return pos;  // No strings matched before a span.
+            }
+            // Match strings from before the next string match.
+        } else {
+            // The position is before a string match (or a single code point).
+            if(offsets.isEmpty()) {
+                // No more strings matched before a previous string match.
+                // Try another code point span from before the last string match.
+                int32_t oldPos=pos;
+                pos=spanSet.spanBackUTF8((const char *)s, oldPos, USET_SPAN_CONTAINED);
+                spanLength=oldPos-pos;
+                if( pos==0 ||           // Reached the start of the string, or
+                    spanLength==0       // neither strings nor span progressed.
+                ) {
+                    return pos;
+                }
+                continue;  // spanLength>0: Match strings from before a span.
+            } else {
+                // Try to match only one code point from before a string match if some
+                // string matched beyond it, so that we try all possible positions
+                // and don't overshoot.
+                spanLength=spanOneBackUTF8(spanSet, s, pos);
+                if(spanLength>0) {
+                    if(spanLength==pos) {
+                        return 0;  // Reached the start of the string.
+                    }
+                    // Match strings before this code point.
+                    // There cannot be any decrements below it because UnicodeSet strings
+                    // contain multiple code points.
+                    pos-=spanLength;
+                    offsets.shift(spanLength);
+                    spanLength=0;
+                    continue;  // Match strings from before a single code point.
+                }
+                // Match strings from before the next string match.
+            }
+        }
+        pos-=offsets.popMinimum();
+        spanLength=0;  // Match strings from before a string match.
+    }
+}
+
+/*
+ * Algorithm for spanNot()==span(USET_SPAN_NOT_CONTAINED)
+ *
+ * Theoretical algorithm:
+ * - Iterate through the string, and at each code point boundary:
+ *   + If the code point there is in the set, then return with the current position.
+ *   + If a set string matches at the current position, then return with the current position.
+ *
+ * Optimized implementation:
+ *
+ * (Same assumption as for span() above.)
+ *
+ * Create and cache a spanNotSet which contains all of the single code points
+ * of the original set but none of its strings.
+ * For each set string add its initial code point to the spanNotSet.
+ * (Also add its final code point for spanNotBack().)
+ *
+ * - Loop:
+ *   + Do spanLength=spanNotSet.span(USET_SPAN_NOT_CONTAINED).
+ *   + If the current code point is in the original set, then
+ *     return the current position.
+ *   + If any set string matches at the current position, then
+ *     return the current position.
+ *   + If there is no match at the current position, neither for the code point there
+ *     nor for any set string, then skip this code point and continue the loop.
+ *     This happens for set-string-initial code points that were added to spanNotSet
+ *     when there is not actually a match for such a set string.
+ */
+
+int32_t UnicodeSetStringSpan::spanNot(const UChar *s, int32_t length) const {
+    int32_t pos=0, rest=length;
+    int32_t i, stringsLength=strings.size();
+    do {
+        // Span until we find a code point from the set,
+        // or a code point that starts or ends some string.
+        i=pSpanNotSet->span(s+pos, rest, USET_SPAN_NOT_CONTAINED);
+        if(i==rest) {
+            return length;  // Reached the end of the string.
+        }
+        pos+=i;
+        rest-=i;
+
+        // Check whether the current code point is in the original set,
+        // without the string starts and ends.
+        int32_t cpLength=spanOne(spanSet, s+pos, rest);
+        if(cpLength>0) {
+            return pos;  // There is a set element at pos.
+        }
+
+        // Try to match the strings at pos.
+        for(i=0; i<stringsLength; ++i) {
+            if(spanLengths[i]==ALL_CP_CONTAINED) {
+                continue;  // Irrelevant string.
+            }
+            const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
+            const UChar *s16=string.getBuffer();
+            int32_t length16=string.length();
+            if(length16<=rest && matches16CPB(s, pos, length, s16, length16)) {
+                return pos;  // There is a set element at pos.
+            }
+        }
+
+        // The span(while not contained) ended on a string start/end which is
+        // not in the original set. Skip this code point and continue.
+        // cpLength<0
+        pos-=cpLength;
+        rest+=cpLength;
+    } while(rest!=0);
+    return length;  // Reached the end of the string.
+}
+
+int32_t UnicodeSetStringSpan::spanNotBack(const UChar *s, int32_t length) const {
+    int32_t pos=length;
+    int32_t i, stringsLength=strings.size();
+    do {
+        // Span until we find a code point from the set,
+        // or a code point that starts or ends some string.
+        pos=pSpanNotSet->spanBack(s, pos, USET_SPAN_NOT_CONTAINED);
+        if(pos==0) {
+            return 0;  // Reached the start of the string.
+        }
+
+        // Check whether the current code point is in the original set,
+        // without the string starts and ends.
+        int32_t cpLength=spanOneBack(spanSet, s, pos);
+        if(cpLength>0) {
+            return pos;  // There is a set element at pos.
+        }
+
+        // Try to match the strings at pos.
+        for(i=0; i<stringsLength; ++i) {
+            // Use spanLengths rather than a spanBackLengths pointer because
+            // it is easier and we only need to know whether the string is irrelevant
+            // which is the same in either array.
+            if(spanLengths[i]==ALL_CP_CONTAINED) {
+                continue;  // Irrelevant string.
+            }
+            const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
+            const UChar *s16=string.getBuffer();
+            int32_t length16=string.length();
+            if(length16<=pos && matches16CPB(s, pos-length16, length, s16, length16)) {
+                return pos;  // There is a set element at pos.
+            }
+        }
+
+        // The span(while not contained) ended on a string start/end which is
+        // not in the original set. Skip this code point and continue.
+        // cpLength<0
+        pos+=cpLength;
+    } while(pos!=0);
+    return 0;  // Reached the start of the string.
+}
+
+int32_t UnicodeSetStringSpan::spanNotUTF8(const uint8_t *s, int32_t length) const {
+    int32_t pos=0, rest=length;
+    int32_t i, stringsLength=strings.size();
+    uint8_t *spanUTF8Lengths=spanLengths;
+    if(all) {
+        spanUTF8Lengths+=2*stringsLength;
+    }
+    do {
+        // Span until we find a code point from the set,
+        // or a code point that starts or ends some string.
+        i=pSpanNotSet->spanUTF8((const char *)s+pos, rest, USET_SPAN_NOT_CONTAINED);
+        if(i==rest) {
+            return length;  // Reached the end of the string.
+        }
+        pos+=i;
+        rest-=i;
+
+        // Check whether the current code point is in the original set,
+        // without the string starts and ends.
+        int32_t cpLength=spanOneUTF8(spanSet, s+pos, rest);
+        if(cpLength>0) {
+            return pos;  // There is a set element at pos.
+        }
+
+        // Try to match the strings at pos.
+        const uint8_t *s8=utf8;
+        int32_t length8;
+        for(i=0; i<stringsLength; ++i) {
+            length8=utf8Lengths[i];
+            // ALL_CP_CONTAINED: Irrelevant string.
+            if(length8!=0 && spanUTF8Lengths[i]!=ALL_CP_CONTAINED && length8<=rest && matches8(s+pos, s8, length8)) {
+                return pos;  // There is a set element at pos.
+            }
+            s8+=length8;
+        }
+
+        // The span(while not contained) ended on a string start/end which is
+        // not in the original set. Skip this code point and continue.
+        // cpLength<0
+        pos-=cpLength;
+        rest+=cpLength;
+    } while(rest!=0);
+    return length;  // Reached the end of the string.
+}
+
+int32_t UnicodeSetStringSpan::spanNotBackUTF8(const uint8_t *s, int32_t length) const {
+    int32_t pos=length;
+    int32_t i, stringsLength=strings.size();
+    uint8_t *spanBackUTF8Lengths=spanLengths;
+    if(all) {
+        spanBackUTF8Lengths+=3*stringsLength;
+    }
+    do {
+        // Span until we find a code point from the set,
+        // or a code point that starts or ends some string.
+        pos=pSpanNotSet->spanBackUTF8((const char *)s, pos, USET_SPAN_NOT_CONTAINED);
+        if(pos==0) {
+            return 0;  // Reached the start of the string.
+        }
+
+        // Check whether the current code point is in the original set,
+        // without the string starts and ends.
+        int32_t cpLength=spanOneBackUTF8(spanSet, s, pos);
+        if(cpLength>0) {
+            return pos;  // There is a set element at pos.
+        }
+
+        // Try to match the strings at pos.
+        const uint8_t *s8=utf8;
+        int32_t length8;
+        for(i=0; i<stringsLength; ++i) {
+            length8=utf8Lengths[i];
+            // ALL_CP_CONTAINED: Irrelevant string.
+            if(length8!=0 && spanBackUTF8Lengths[i]!=ALL_CP_CONTAINED && length8<=pos && matches8(s+pos-length8, s8, length8)) {
+                return pos;  // There is a set element at pos.
+            }
+            s8+=length8;
+        }
+
+        // The span(while not contained) ended on a string start/end which is
+        // not in the original set. Skip this code point and continue.
+        // cpLength<0
+        pos+=cpLength;
+    } while(pos!=0);
+    return 0;  // Reached the start of the string.
+}
+
+U_NAMESPACE_END
diff --git a/source/common/unisetspan.h b/source/common/unisetspan.h
new file mode 100644
index 0000000..2fe0fc3
--- /dev/null
+++ b/source/common/unisetspan.h
@@ -0,0 +1,155 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2007, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  unisetspan.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2007mar01
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __UNISETSPAN_H__
+#define __UNISETSPAN_H__
+
+#include "unicode/utypes.h"
+#include "unicode/uniset.h"
+
+U_NAMESPACE_BEGIN
+
+/*
+ * Implement span() etc. for a set with strings.
+ * Avoid recursion because of its exponential complexity.
+ * Instead, try multiple paths at once and track them with an IndexList.
+ */
+class UnicodeSetStringSpan : public UMemory {
+public:
+    /*
+     * Which span() variant will be used?
+     * The object is either built for one variant and used once,
+     * or built for all and may be used many times.
+     */
+    enum {
+        FWD             = 0x20,
+        BACK            = 0x10,
+        UTF16           = 8,
+        UTF8            = 4,
+        CONTAINED       = 2,
+        NOT_CONTAINED   = 1,
+
+        ALL             = 0x3f,
+
+        FWD_UTF16_CONTAINED     = FWD  | UTF16 |     CONTAINED,
+        FWD_UTF16_NOT_CONTAINED = FWD  | UTF16 | NOT_CONTAINED,
+        FWD_UTF8_CONTAINED      = FWD  | UTF8  |     CONTAINED,
+        FWD_UTF8_NOT_CONTAINED  = FWD  | UTF8  | NOT_CONTAINED,
+        BACK_UTF16_CONTAINED    = BACK | UTF16 |     CONTAINED,
+        BACK_UTF16_NOT_CONTAINED= BACK | UTF16 | NOT_CONTAINED,
+        BACK_UTF8_CONTAINED     = BACK | UTF8  |     CONTAINED,
+        BACK_UTF8_NOT_CONTAINED = BACK | UTF8  | NOT_CONTAINED
+    };
+
+    UnicodeSetStringSpan(const UnicodeSet &set, const UVector &setStrings, uint32_t which);
+
+    // Copy constructor. Assumes which==ALL for a frozen set.
+    UnicodeSetStringSpan(const UnicodeSetStringSpan &otherStringSpan, const UVector &newParentSetStrings);
+
+    ~UnicodeSetStringSpan();
+
+    /*
+     * Do the strings need to be checked in span() etc.?
+     * @return TRUE if strings need to be checked (call span() here),
+     *         FALSE if not (use a BMPSet for best performance).
+     */
+    inline UBool needsStringSpanUTF16();
+    inline UBool needsStringSpanUTF8();
+
+    // For fast UnicodeSet::contains(c).
+    inline UBool contains(UChar32 c) const;
+
+    int32_t span(const UChar *s, int32_t length, USetSpanCondition spanCondition) const;
+
+    int32_t spanBack(const UChar *s, int32_t length, USetSpanCondition spanCondition) const;
+
+    int32_t spanUTF8(const uint8_t *s, int32_t length, USetSpanCondition spanCondition) const;
+
+    int32_t spanBackUTF8(const uint8_t *s, int32_t length, USetSpanCondition spanCondition) const;
+
+private:
+    // Special spanLength byte values.
+    enum {
+        // The spanLength is >=0xfe.
+        LONG_SPAN=0xfe,
+        // All code points in the string are contained in the parent set.
+        ALL_CP_CONTAINED=0xff
+    };
+
+    // Add a starting or ending string character to the spanNotSet
+    // so that a character span ends before any string.
+    void addToSpanNotSet(UChar32 c);
+
+    int32_t spanNot(const UChar *s, int32_t length) const;
+    int32_t spanNotBack(const UChar *s, int32_t length) const;
+    int32_t spanNotUTF8(const uint8_t *s, int32_t length) const;
+    int32_t spanNotBackUTF8(const uint8_t *s, int32_t length) const;
+
+    // Set for span(). Same as parent but without strings.
+    UnicodeSet spanSet;
+
+    // Set for span(not contained).
+    // Same as spanSet, plus characters that start or end strings.
+    UnicodeSet *pSpanNotSet;
+
+    // The strings of the parent set.
+    const UVector &strings;
+
+    // Pointer to the UTF-8 string lengths.
+    // Also pointer to further allocated storage for meta data and
+    // UTF-8 string contents as necessary.
+    int32_t *utf8Lengths;
+
+    // Pointer to the part of the (utf8Lengths) memory block that stores
+    // the lengths of span(), spanBack() etc. for each string.
+    uint8_t *spanLengths;
+
+    // Pointer to the part of the (utf8Lengths) memory block that stores
+    // the UTF-8 versions of the parent set's strings.
+    uint8_t *utf8;
+
+    // Number of bytes for all UTF-8 versions of strings together.
+    int32_t utf8Length;
+
+    // Maximum lengths of relevant strings.
+    int32_t maxLength16;
+    int32_t maxLength8;
+
+    // Set up for all variants of span()?
+    UBool all;
+
+    // Memory for small numbers and lengths of strings.
+    // For example, for 8 strings:
+    // 8 UTF-8 lengths, 8*4 bytes span lengths, 8*2 3-byte UTF-8 characters
+    // = 112 bytes = int32_t[28].
+    int32_t staticLengths[32];
+};
+
+UBool UnicodeSetStringSpan::needsStringSpanUTF16() {
+    return (UBool)(maxLength16!=0);
+}
+
+UBool UnicodeSetStringSpan::needsStringSpanUTF8() {
+    return (UBool)(maxLength8!=0);
+}
+
+UBool UnicodeSetStringSpan::contains(UChar32 c) const {
+    return spanSet.contains(c);
+}
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/unistr.cpp b/source/common/unistr.cpp
new file mode 100644
index 0000000..627fd47
--- /dev/null
+++ b/source/common/unistr.cpp
@@ -0,0 +1,1633 @@
+/*
+******************************************************************************
+* Copyright (C) 1999-2010, International Business Machines Corporation and   *
+* others. All Rights Reserved.                                               *
+******************************************************************************
+*
+* File unistr.cpp
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   09/25/98    stephen     Creation.
+*   04/20/99    stephen     Overhauled per 4/16 code review.
+*   07/09/99    stephen     Renamed {hi,lo},{byte,word} to icu_X for HP/UX
+*   11/18/99    aliu        Added handleReplaceBetween() to make inherit from
+*                           Replaceable.
+*   06/25/01    grhoten     Removed the dependency on iostream
+******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/putil.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include "unicode/ustring.h"
+#include "unicode/unistr.h"
+#include "uhash.h"
+#include "ustr_imp.h"
+#include "umutex.h"
+
+#if 0
+
+#if U_IOSTREAM_SOURCE >= 199711
+#include <iostream>
+using namespace std;
+#elif U_IOSTREAM_SOURCE >= 198506
+#include <iostream.h>
+#endif
+
+//DEBUGGING
+void
+print(const UnicodeString& s,
+      const char *name)
+{
+  UChar c;
+  cout << name << ":|";
+  for(int i = 0; i < s.length(); ++i) {
+    c = s[i];
+    if(c>= 0x007E || c < 0x0020)
+      cout << "[0x" << hex << s[i] << "]";
+    else
+      cout << (char) s[i];
+  }
+  cout << '|' << endl;
+}
+
+void
+print(const UChar *s,
+      int32_t len,
+      const char *name)
+{
+  UChar c;
+  cout << name << ":|";
+  for(int i = 0; i < len; ++i) {
+    c = s[i];
+    if(c>= 0x007E || c < 0x0020)
+      cout << "[0x" << hex << s[i] << "]";
+    else
+      cout << (char) s[i];
+  }
+  cout << '|' << endl;
+}
+// END DEBUGGING
+#endif
+
+// Local function definitions for now
+
+// need to copy areas that may overlap
+static
+inline void
+us_arrayCopy(const UChar *src, int32_t srcStart,
+         UChar *dst, int32_t dstStart, int32_t count)
+{
+  if(count>0) {
+    uprv_memmove(dst+dstStart, src+srcStart, (size_t)(count*sizeof(*src)));
+  }
+}
+
+// u_unescapeAt() callback to get a UChar from a UnicodeString
+U_CDECL_BEGIN
+static UChar U_CALLCONV
+UnicodeString_charAt(int32_t offset, void *context) {
+    return ((U_NAMESPACE_QUALIFIER UnicodeString*) context)->charAt(offset);
+}
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+/* The Replaceable virtual destructor can't be defined in the header
+   due to how AIX works with multiple definitions of virtual functions.
+*/
+Replaceable::~Replaceable() {}
+Replaceable::Replaceable() {}
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UnicodeString)
+
+UnicodeString U_EXPORT2
+operator+ (const UnicodeString &s1, const UnicodeString &s2) {
+    return
+        UnicodeString(s1.length()+s2.length()+1, (UChar32)0, 0).
+            append(s1).
+                append(s2);
+}
+
+//========================================
+// Reference Counting functions, put at top of file so that optimizing compilers
+//                               have a chance to automatically inline.
+//========================================
+
+void
+UnicodeString::addRef()
+{  umtx_atomic_inc((int32_t *)fUnion.fFields.fArray - 1);}
+
+int32_t
+UnicodeString::removeRef()
+{ return umtx_atomic_dec((int32_t *)fUnion.fFields.fArray - 1);}
+
+int32_t
+UnicodeString::refCount() const 
+{ 
+    umtx_lock(NULL);
+    // Note: without the lock to force a memory barrier, we might see a very
+    //       stale value on some multi-processor systems.
+    int32_t  count = *((int32_t *)fUnion.fFields.fArray - 1);
+    umtx_unlock(NULL);
+    return count;
+ }
+
+void
+UnicodeString::releaseArray() {
+  if((fFlags & kRefCounted) && removeRef() == 0) {
+    uprv_free((int32_t *)fUnion.fFields.fArray - 1);
+  }
+}
+
+
+
+//========================================
+// Constructors
+//========================================
+UnicodeString::UnicodeString()
+  : fShortLength(0),
+    fFlags(kShortString)
+{}
+
+UnicodeString::UnicodeString(int32_t capacity, UChar32 c, int32_t count)
+  : fShortLength(0),
+    fFlags(0)
+{
+  if(count <= 0 || (uint32_t)c > 0x10ffff) {
+    // just allocate and do not do anything else
+    allocate(capacity);
+  } else {
+    // count > 0, allocate and fill the new string with count c's
+    int32_t unitCount = UTF_CHAR_LENGTH(c), length = count * unitCount;
+    if(capacity < length) {
+      capacity = length;
+    }
+    if(allocate(capacity)) {
+      UChar *array = getArrayStart();
+      int32_t i = 0;
+
+      // fill the new string with c
+      if(unitCount == 1) {
+        // fill with length UChars
+        while(i < length) {
+          array[i++] = (UChar)c;
+        }
+      } else {
+        // get the code units for c
+        UChar units[UTF_MAX_CHAR_LENGTH];
+        UTF_APPEND_CHAR_UNSAFE(units, i, c);
+
+        // now it must be i==unitCount
+        i = 0;
+
+        // for Unicode, unitCount can only be 1, 2, 3, or 4
+        // 1 is handled above
+        while(i < length) {
+          int32_t unitIdx = 0;
+          while(unitIdx < unitCount) {
+            array[i++]=units[unitIdx++];
+          }
+        }
+      }
+    }
+    setLength(length);
+  }
+}
+
+UnicodeString::UnicodeString(UChar ch)
+  : fShortLength(1),
+    fFlags(kShortString)
+{
+  fUnion.fStackBuffer[0] = ch;
+}
+
+UnicodeString::UnicodeString(UChar32 ch)
+  : fShortLength(0),
+    fFlags(kShortString)
+{
+  int32_t i = 0;
+  UBool isError = FALSE;
+  U16_APPEND(fUnion.fStackBuffer, i, US_STACKBUF_SIZE, ch, isError);
+  fShortLength = (int8_t)i;
+}
+
+UnicodeString::UnicodeString(const UChar *text)
+  : fShortLength(0),
+    fFlags(kShortString)
+{
+  doReplace(0, 0, text, 0, -1);
+}
+
+UnicodeString::UnicodeString(const UChar *text,
+                             int32_t textLength)
+  : fShortLength(0),
+    fFlags(kShortString)
+{
+  doReplace(0, 0, text, 0, textLength);
+}
+
+UnicodeString::UnicodeString(UBool isTerminated,
+                             const UChar *text,
+                             int32_t textLength)
+  : fShortLength(0),
+    fFlags(kReadonlyAlias)
+{
+  if(text == NULL) {
+    // treat as an empty string, do not alias
+    setToEmpty();
+  } else if(textLength < -1 ||
+            (textLength == -1 && !isTerminated) ||
+            (textLength >= 0 && isTerminated && text[textLength] != 0)
+  ) {
+    setToBogus();
+  } else {
+    if(textLength == -1) {
+      // text is terminated, or else it would have failed the above test
+      textLength = u_strlen(text);
+    }
+    setArray((UChar *)text, textLength, isTerminated ? textLength + 1 : textLength);
+  }
+}
+
+UnicodeString::UnicodeString(UChar *buff,
+                             int32_t buffLength,
+                             int32_t buffCapacity)
+  : fShortLength(0),
+    fFlags(kWritableAlias)
+{
+  if(buff == NULL) {
+    // treat as an empty string, do not alias
+    setToEmpty();
+  } else if(buffLength < -1 || buffCapacity < 0 || buffLength > buffCapacity) {
+    setToBogus();
+  } else {
+    if(buffLength == -1) {
+      // fLength = u_strlen(buff); but do not look beyond buffCapacity
+      const UChar *p = buff, *limit = buff + buffCapacity;
+      while(p != limit && *p != 0) {
+        ++p;
+      }
+      buffLength = (int32_t)(p - buff);
+    }
+    setArray(buff, buffLength, buffCapacity);
+  }
+}
+
+UnicodeString::UnicodeString(const char *src, int32_t length, EInvariant)
+  : fShortLength(0),
+    fFlags(kShortString)
+{
+  if(src==NULL) {
+    // treat as an empty string
+  } else {
+    if(length<0) {
+      length=(int32_t)uprv_strlen(src);
+    }
+    if(cloneArrayIfNeeded(length, length, FALSE)) {
+      u_charsToUChars(src, getArrayStart(), length);
+      setLength(length);
+    } else {
+      setToBogus();
+    }
+  }
+}
+
+#if U_CHARSET_IS_UTF8
+
+UnicodeString::UnicodeString(const char *codepageData)
+  : fShortLength(0),
+    fFlags(kShortString) {
+  if(codepageData != 0) {
+    setToUTF8(codepageData);
+  }
+}
+
+UnicodeString::UnicodeString(const char *codepageData, int32_t dataLength)
+  : fShortLength(0),
+    fFlags(kShortString) {
+  // if there's nothing to convert, do nothing
+  if(codepageData == 0 || dataLength == 0 || dataLength < -1) {
+    return;
+  }
+  if(dataLength == -1) {
+    dataLength = (int32_t)uprv_strlen(codepageData);
+  }
+  setToUTF8(StringPiece(codepageData, dataLength));
+}
+
+// else see unistr_cnv.cpp
+#endif
+
+UnicodeString::UnicodeString(const UnicodeString& that)
+  : Replaceable(),
+    fShortLength(0),
+    fFlags(kShortString)
+{
+  copyFrom(that);
+}
+
+UnicodeString::UnicodeString(const UnicodeString& that,
+                             int32_t srcStart)
+  : Replaceable(),
+    fShortLength(0),
+    fFlags(kShortString)
+{
+  setTo(that, srcStart);
+}
+
+UnicodeString::UnicodeString(const UnicodeString& that,
+                             int32_t srcStart,
+                             int32_t srcLength)
+  : Replaceable(),
+    fShortLength(0),
+    fFlags(kShortString)
+{
+  setTo(that, srcStart, srcLength);
+}
+
+// Replaceable base class clone() default implementation, does not clone
+Replaceable *
+Replaceable::clone() const {
+  return NULL;
+}
+
+// UnicodeString overrides clone() with a real implementation
+Replaceable *
+UnicodeString::clone() const {
+  return new UnicodeString(*this);
+}
+
+//========================================
+// array allocation
+//========================================
+
+UBool
+UnicodeString::allocate(int32_t capacity) {
+  if(capacity <= US_STACKBUF_SIZE) {
+    fFlags = kShortString;
+  } else {
+    // count bytes for the refCounter and the string capacity, and
+    // round up to a multiple of 16; then divide by 4 and allocate int32_t's
+    // to be safely aligned for the refCount
+    // the +1 is for the NUL terminator, to avoid reallocation in getTerminatedBuffer()
+    int32_t words = (int32_t)(((sizeof(int32_t) + (capacity + 1) * U_SIZEOF_UCHAR + 15) & ~15) >> 2);
+    int32_t *array = (int32_t*) uprv_malloc( sizeof(int32_t) * words );
+    if(array != 0) {
+      // set initial refCount and point behind the refCount
+      *array++ = 1;
+
+      // have fArray point to the first UChar
+      fUnion.fFields.fArray = (UChar *)array;
+      fUnion.fFields.fCapacity = (int32_t)((words - 1) * (sizeof(int32_t) / U_SIZEOF_UCHAR));
+      fFlags = kLongString;
+    } else {
+      fShortLength = 0;
+      fUnion.fFields.fArray = 0;
+      fUnion.fFields.fCapacity = 0;
+      fFlags = kIsBogus;
+      return FALSE;
+    }
+  }
+  return TRUE;
+}
+
+//========================================
+// Destructor
+//========================================
+UnicodeString::~UnicodeString()
+{
+  releaseArray();
+}
+
+//========================================
+// Factory methods
+//========================================
+
+UnicodeString UnicodeString::fromUTF8(const StringPiece &utf8) {
+  UnicodeString result;
+  result.setToUTF8(utf8);
+  return result;
+}
+
+UnicodeString UnicodeString::fromUTF32(const UChar32 *utf32, int32_t length) {
+  UnicodeString result;
+  int32_t capacity;
+  // Most UTF-32 strings will be BMP-only and result in a same-length
+  // UTF-16 string. We overestimate the capacity just slightly,
+  // just in case there are a few supplementary characters.
+  if(length <= US_STACKBUF_SIZE) {
+    capacity = US_STACKBUF_SIZE;
+  } else {
+    capacity = length + (length >> 4) + 4;
+  }
+  do {
+    UChar *utf16 = result.getBuffer(capacity);
+    int32_t length16;
+    UErrorCode errorCode = U_ZERO_ERROR;
+    u_strFromUTF32WithSub(utf16, result.getCapacity(), &length16,
+        utf32, length,
+        0xfffd,  // Substitution character.
+        NULL,    // Don't care about number of substitutions.
+        &errorCode);
+    result.releaseBuffer(length16);
+    if(errorCode == U_BUFFER_OVERFLOW_ERROR) {
+      capacity = length16 + 1;  // +1 for the terminating NUL.
+      continue;
+    } else if(U_FAILURE(errorCode)) {
+      result.setToBogus();
+    }
+    break;
+  } while(TRUE);
+  return result;
+}
+
+//========================================
+// Assignment
+//========================================
+
+UnicodeString &
+UnicodeString::operator=(const UnicodeString &src) {
+  return copyFrom(src);
+}
+
+UnicodeString &
+UnicodeString::fastCopyFrom(const UnicodeString &src) {
+  return copyFrom(src, TRUE);
+}
+
+UnicodeString &
+UnicodeString::copyFrom(const UnicodeString &src, UBool fastCopy) {
+  // if assigning to ourselves, do nothing
+  if(this == 0 || this == &src) {
+    return *this;
+  }
+
+  // is the right side bogus?
+  if(&src == 0 || src.isBogus()) {
+    setToBogus();
+    return *this;
+  }
+
+  // delete the current contents
+  releaseArray();
+
+  if(src.isEmpty()) {
+    // empty string - use the stack buffer
+    setToEmpty();
+    return *this;
+  }
+
+  // we always copy the length
+  int32_t srcLength = src.length();
+  setLength(srcLength);
+
+  // fLength>0 and not an "open" src.getBuffer(minCapacity)
+  switch(src.fFlags) {
+  case kShortString:
+    // short string using the stack buffer, do the same
+    fFlags = kShortString;
+    uprv_memcpy(fUnion.fStackBuffer, src.fUnion.fStackBuffer, srcLength * U_SIZEOF_UCHAR);
+    break;
+  case kLongString:
+    // src uses a refCounted string buffer, use that buffer with refCount
+    // src is const, use a cast - we don't really change it
+    ((UnicodeString &)src).addRef();
+    // copy all fields, share the reference-counted buffer
+    fUnion.fFields.fArray = src.fUnion.fFields.fArray;
+    fUnion.fFields.fCapacity = src.fUnion.fFields.fCapacity;
+    fFlags = src.fFlags;
+    break;
+  case kReadonlyAlias:
+    if(fastCopy) {
+      // src is a readonly alias, do the same
+      // -> maintain the readonly alias as such
+      fUnion.fFields.fArray = src.fUnion.fFields.fArray;
+      fUnion.fFields.fCapacity = src.fUnion.fFields.fCapacity;
+      fFlags = src.fFlags;
+      break;
+    }
+    // else if(!fastCopy) fall through to case kWritableAlias
+    // -> allocate a new buffer and copy the contents
+  case kWritableAlias:
+    // src is a writable alias; we make a copy of that instead
+    if(allocate(srcLength)) {
+      uprv_memcpy(getArrayStart(), src.getArrayStart(), srcLength * U_SIZEOF_UCHAR);
+      break;
+    }
+    // if there is not enough memory, then fall through to setting to bogus
+  default:
+    // if src is bogus, set ourselves to bogus
+    // do not call setToBogus() here because fArray and fFlags are not consistent here
+    fShortLength = 0;
+    fUnion.fFields.fArray = 0;
+    fUnion.fFields.fCapacity = 0;
+    fFlags = kIsBogus;
+    break;
+  }
+
+  return *this;
+}
+
+//========================================
+// Miscellaneous operations
+//========================================
+
+UnicodeString UnicodeString::unescape() const {
+    UnicodeString result(length(), (UChar32)0, (int32_t)0); // construct with capacity
+    const UChar *array = getBuffer();
+    int32_t len = length();
+    int32_t prev = 0;
+    for (int32_t i=0;;) {
+        if (i == len) {
+            result.append(array, prev, len - prev);
+            break;
+        }
+        if (array[i++] == 0x5C /*'\\'*/) {
+            result.append(array, prev, (i - 1) - prev);
+            UChar32 c = unescapeAt(i); // advances i
+            if (c < 0) {
+                result.remove(); // return empty string
+                break; // invalid escape sequence
+            }
+            result.append(c);
+            prev = i;
+        }
+    }
+    return result;
+}
+
+UChar32 UnicodeString::unescapeAt(int32_t &offset) const {
+    return u_unescapeAt(UnicodeString_charAt, &offset, length(), (void*)this);
+}
+
+//========================================
+// Read-only implementation
+//========================================
+int8_t
+UnicodeString::doCompare( int32_t start,
+              int32_t length,
+              const UChar *srcChars,
+              int32_t srcStart,
+              int32_t srcLength) const
+{
+  // compare illegal string values
+  // treat const UChar *srcChars==NULL as an empty string
+  if(isBogus()) {
+    return -1;
+  }
+  
+  // pin indices to legal values
+  pinIndices(start, length);
+
+  if(srcChars == NULL) {
+    srcStart = srcLength = 0;
+  }
+
+  // get the correct pointer
+  const UChar *chars = getArrayStart();
+
+  chars += start;
+  srcChars += srcStart;
+
+  int32_t minLength;
+  int8_t lengthResult;
+
+  // get the srcLength if necessary
+  if(srcLength < 0) {
+    srcLength = u_strlen(srcChars + srcStart);
+  }
+
+  // are we comparing different lengths?
+  if(length != srcLength) {
+    if(length < srcLength) {
+      minLength = length;
+      lengthResult = -1;
+    } else {
+      minLength = srcLength;
+      lengthResult = 1;
+    }
+  } else {
+    minLength = length;
+    lengthResult = 0;
+  }
+
+  /*
+   * note that uprv_memcmp() returns an int but we return an int8_t;
+   * we need to take care not to truncate the result -
+   * one way to do this is to right-shift the value to
+   * move the sign bit into the lower 8 bits and making sure that this
+   * does not become 0 itself
+   */
+
+  if(minLength > 0 && chars != srcChars) {
+    int32_t result;
+
+#   if U_IS_BIG_ENDIAN 
+      // big-endian: byte comparison works
+      result = uprv_memcmp(chars, srcChars, minLength * sizeof(UChar));
+      if(result != 0) {
+        return (int8_t)(result >> 15 | 1);
+      }
+#   else
+      // little-endian: compare UChar units
+      do {
+        result = ((int32_t)*(chars++) - (int32_t)*(srcChars++));
+        if(result != 0) {
+          return (int8_t)(result >> 15 | 1);
+        }
+      } while(--minLength > 0);
+#   endif
+  }
+  return lengthResult;
+}
+
+/* String compare in code point order - doCompare() compares in code unit order. */
+int8_t
+UnicodeString::doCompareCodePointOrder(int32_t start,
+                                       int32_t length,
+                                       const UChar *srcChars,
+                                       int32_t srcStart,
+                                       int32_t srcLength) const
+{
+  // compare illegal string values
+  // treat const UChar *srcChars==NULL as an empty string
+  if(isBogus()) {
+    return -1;
+  }
+
+  // pin indices to legal values
+  pinIndices(start, length);
+
+  if(srcChars == NULL) {
+    srcStart = srcLength = 0;
+  }
+
+  int32_t diff = uprv_strCompare(getArrayStart() + start, length, srcChars + srcStart, srcLength, FALSE, TRUE);
+  /* translate the 32-bit result into an 8-bit one */
+  if(diff!=0) {
+    return (int8_t)(diff >> 15 | 1);
+  } else {
+    return 0;
+  }
+}
+
+int32_t
+UnicodeString::getLength() const {
+    return length();
+}
+
+UChar
+UnicodeString::getCharAt(int32_t offset) const {
+  return charAt(offset);
+}
+
+UChar32
+UnicodeString::getChar32At(int32_t offset) const {
+  return char32At(offset);
+}
+
+int32_t
+UnicodeString::countChar32(int32_t start, int32_t length) const {
+  pinIndices(start, length);
+  // if(isBogus()) then fArray==0 and start==0 - u_countChar32() checks for NULL
+  return u_countChar32(getArrayStart()+start, length);
+}
+
+UBool
+UnicodeString::hasMoreChar32Than(int32_t start, int32_t length, int32_t number) const {
+  pinIndices(start, length);
+  // if(isBogus()) then fArray==0 and start==0 - u_strHasMoreChar32Than() checks for NULL
+  return u_strHasMoreChar32Than(getArrayStart()+start, length, number);
+}
+
+int32_t
+UnicodeString::moveIndex32(int32_t index, int32_t delta) const {
+  // pin index
+  int32_t len = length();
+  if(index<0) {
+    index=0;
+  } else if(index>len) {
+    index=len;
+  }
+
+  const UChar *array = getArrayStart();
+  if(delta>0) {
+    UTF_FWD_N(array, index, len, delta);
+  } else {
+    UTF_BACK_N(array, 0, index, -delta);
+  }
+
+  return index;
+}
+
+void
+UnicodeString::doExtract(int32_t start,
+             int32_t length,
+             UChar *dst,
+             int32_t dstStart) const
+{
+  // pin indices to legal values
+  pinIndices(start, length);
+
+  // do not copy anything if we alias dst itself
+  const UChar *array = getArrayStart();
+  if(array + start != dst + dstStart) {
+    us_arrayCopy(array, start, dst, dstStart, length);
+  }
+}
+
+int32_t
+UnicodeString::extract(UChar *dest, int32_t destCapacity,
+                       UErrorCode &errorCode) const {
+  int32_t len = length();
+  if(U_SUCCESS(errorCode)) {
+    if(isBogus() || destCapacity<0 || (destCapacity>0 && dest==0)) {
+      errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+    } else {
+      const UChar *array = getArrayStart();
+      if(len>0 && len<=destCapacity && array!=dest) {
+        uprv_memcpy(dest, array, len*U_SIZEOF_UCHAR);
+      }
+      return u_terminateUChars(dest, destCapacity, len, &errorCode);
+    }
+  }
+
+  return len;
+}
+
+int32_t
+UnicodeString::extract(int32_t start,
+                       int32_t length,
+                       char *target,
+                       int32_t targetCapacity,
+                       enum EInvariant) const
+{
+  // if the arguments are illegal, then do nothing
+  if(targetCapacity < 0 || (targetCapacity > 0 && target == NULL)) {
+    return 0;
+  }
+
+  // pin the indices to legal values
+  pinIndices(start, length);
+
+  if(length <= targetCapacity) {
+    u_UCharsToChars(getArrayStart() + start, target, length);
+  }
+  UErrorCode status = U_ZERO_ERROR;
+  return u_terminateChars(target, targetCapacity, length, &status);
+}
+
+UnicodeString
+UnicodeString::tempSubString(int32_t start, int32_t len) const {
+  pinIndices(start, len);
+  const UChar *array = getBuffer();  // not getArrayStart() to check kIsBogus & kOpenGetBuffer
+  if(array==NULL) {
+    array=fUnion.fStackBuffer;  // anything not NULL because that would make an empty string
+    len=-2;  // bogus result string
+  }
+  return UnicodeString(FALSE, array + start, len);
+}
+
+int32_t
+UnicodeString::toUTF8(int32_t start, int32_t len,
+                      char *target, int32_t capacity) const {
+  pinIndices(start, len);
+  int32_t length8;
+  UErrorCode errorCode = U_ZERO_ERROR;
+  u_strToUTF8WithSub(target, capacity, &length8,
+                     getBuffer() + start, len,
+                     0xFFFD,  // Standard substitution character.
+                     NULL,    // Don't care about number of substitutions.
+                     &errorCode);
+  return length8;
+}
+
+#if U_CHARSET_IS_UTF8
+
+int32_t
+UnicodeString::extract(int32_t start, int32_t len,
+                       char *target, uint32_t dstSize) const {
+  // if the arguments are illegal, then do nothing
+  if(/*dstSize < 0 || */(dstSize > 0 && target == 0)) {
+    return 0;
+  }
+  return toUTF8(start, len, target, dstSize <= 0x7fffffff ? (int32_t)dstSize : 0x7fffffff);
+}
+
+// else see unistr_cnv.cpp
+#endif
+
+void 
+UnicodeString::extractBetween(int32_t start,
+                  int32_t limit,
+                  UnicodeString& target) const {
+  pinIndex(start);
+  pinIndex(limit);
+  doExtract(start, limit - start, target);
+}
+
+// When converting from UTF-16 to UTF-8, the result will have at most 3 times
+// as many bytes as the source has UChars.
+// The "worst cases" are writing systems like Indic, Thai and CJK with
+// 3:1 bytes:UChars.
+void
+UnicodeString::toUTF8(ByteSink &sink) const {
+  int32_t length16 = length();
+  if(length16 != 0) {
+    char stackBuffer[1024];
+    int32_t capacity = (int32_t)sizeof(stackBuffer);
+    UBool utf8IsOwned = FALSE;
+    char *utf8 = sink.GetAppendBuffer(length16 < capacity ? length16 : capacity,
+                                      3*length16,
+                                      stackBuffer, capacity,
+                                      &capacity);
+    int32_t length8 = 0;
+    UErrorCode errorCode = U_ZERO_ERROR;
+    u_strToUTF8WithSub(utf8, capacity, &length8,
+                       getBuffer(), length16,
+                       0xFFFD,  // Standard substitution character.
+                       NULL,    // Don't care about number of substitutions.
+                       &errorCode);
+    if(errorCode == U_BUFFER_OVERFLOW_ERROR) {
+      utf8 = (char *)uprv_malloc(length8);
+      if(utf8 != NULL) {
+        utf8IsOwned = TRUE;
+        errorCode = U_ZERO_ERROR;
+        u_strToUTF8WithSub(utf8, length8, &length8,
+                           getBuffer(), length16,
+                           0xFFFD,  // Standard substitution character.
+                           NULL,    // Don't care about number of substitutions.
+                           &errorCode);
+      } else {
+        errorCode = U_MEMORY_ALLOCATION_ERROR;
+      }
+    }
+    if(U_SUCCESS(errorCode)) {
+      sink.Append(utf8, length8);
+      sink.Flush();
+    }
+    if(utf8IsOwned) {
+      uprv_free(utf8);
+    }
+  }
+}
+
+int32_t
+UnicodeString::toUTF32(UChar32 *utf32, int32_t capacity, UErrorCode &errorCode) const {
+  int32_t length32=0;
+  if(U_SUCCESS(errorCode)) {
+    // getBuffer() and u_strToUTF32WithSub() check for illegal arguments.
+    u_strToUTF32WithSub(utf32, capacity, &length32,
+        getBuffer(), length(),
+        0xfffd,  // Substitution character.
+        NULL,    // Don't care about number of substitutions.
+        &errorCode);
+  }
+  return length32;
+}
+
+int32_t 
+UnicodeString::indexOf(const UChar *srcChars,
+               int32_t srcStart,
+               int32_t srcLength,
+               int32_t start,
+               int32_t length) const
+{
+  if(isBogus() || srcChars == 0 || srcStart < 0 || srcLength == 0) {
+    return -1;
+  }
+
+  // UnicodeString does not find empty substrings
+  if(srcLength < 0 && srcChars[srcStart] == 0) {
+    return -1;
+  }
+
+  // get the indices within bounds
+  pinIndices(start, length);
+
+  // find the first occurrence of the substring
+  const UChar *array = getArrayStart();
+  const UChar *match = u_strFindFirst(array + start, length, srcChars + srcStart, srcLength);
+  if(match == NULL) {
+    return -1;
+  } else {
+    return (int32_t)(match - array);
+  }
+}
+
+int32_t
+UnicodeString::doIndexOf(UChar c,
+             int32_t start,
+             int32_t length) const
+{
+  // pin indices
+  pinIndices(start, length);
+
+  // find the first occurrence of c
+  const UChar *array = getArrayStart();
+  const UChar *match = u_memchr(array + start, c, length);
+  if(match == NULL) {
+    return -1;
+  } else {
+    return (int32_t)(match - array);
+  }
+}
+
+int32_t
+UnicodeString::doIndexOf(UChar32 c,
+                         int32_t start,
+                         int32_t length) const {
+  // pin indices
+  pinIndices(start, length);
+
+  // find the first occurrence of c
+  const UChar *array = getArrayStart();
+  const UChar *match = u_memchr32(array + start, c, length);
+  if(match == NULL) {
+    return -1;
+  } else {
+    return (int32_t)(match - array);
+  }
+}
+
+int32_t 
+UnicodeString::lastIndexOf(const UChar *srcChars,
+               int32_t srcStart,
+               int32_t srcLength,
+               int32_t start,
+               int32_t length) const
+{
+  if(isBogus() || srcChars == 0 || srcStart < 0 || srcLength == 0) {
+    return -1;
+  }
+
+  // UnicodeString does not find empty substrings
+  if(srcLength < 0 && srcChars[srcStart] == 0) {
+    return -1;
+  }
+
+  // get the indices within bounds
+  pinIndices(start, length);
+
+  // find the last occurrence of the substring
+  const UChar *array = getArrayStart();
+  const UChar *match = u_strFindLast(array + start, length, srcChars + srcStart, srcLength);
+  if(match == NULL) {
+    return -1;
+  } else {
+    return (int32_t)(match - array);
+  }
+}
+
+int32_t
+UnicodeString::doLastIndexOf(UChar c,
+                 int32_t start,
+                 int32_t length) const
+{
+  if(isBogus()) {
+    return -1;
+  }
+
+  // pin indices
+  pinIndices(start, length);
+
+  // find the last occurrence of c
+  const UChar *array = getArrayStart();
+  const UChar *match = u_memrchr(array + start, c, length);
+  if(match == NULL) {
+    return -1;
+  } else {
+    return (int32_t)(match - array);
+  }
+}
+
+int32_t
+UnicodeString::doLastIndexOf(UChar32 c,
+                             int32_t start,
+                             int32_t length) const {
+  // pin indices
+  pinIndices(start, length);
+
+  // find the last occurrence of c
+  const UChar *array = getArrayStart();
+  const UChar *match = u_memrchr32(array + start, c, length);
+  if(match == NULL) {
+    return -1;
+  } else {
+    return (int32_t)(match - array);
+  }
+}
+
+//========================================
+// Write implementation
+//========================================
+
+UnicodeString& 
+UnicodeString::findAndReplace(int32_t start,
+                  int32_t length,
+                  const UnicodeString& oldText,
+                  int32_t oldStart,
+                  int32_t oldLength,
+                  const UnicodeString& newText,
+                  int32_t newStart,
+                  int32_t newLength)
+{
+  if(isBogus() || oldText.isBogus() || newText.isBogus()) {
+    return *this;
+  }
+
+  pinIndices(start, length);
+  oldText.pinIndices(oldStart, oldLength);
+  newText.pinIndices(newStart, newLength);
+
+  if(oldLength == 0) {
+    return *this;
+  }
+
+  while(length > 0 && length >= oldLength) {
+    int32_t pos = indexOf(oldText, oldStart, oldLength, start, length);
+    if(pos < 0) {
+      // no more oldText's here: done
+      break;
+    } else {
+      // we found oldText, replace it by newText and go beyond it
+      replace(pos, oldLength, newText, newStart, newLength);
+      length -= pos + oldLength - start;
+      start = pos + newLength;
+    }
+  }
+
+  return *this;
+}
+
+
+void
+UnicodeString::setToBogus()
+{
+  releaseArray();
+
+  fShortLength = 0;
+  fUnion.fFields.fArray = 0;
+  fUnion.fFields.fCapacity = 0;
+  fFlags = kIsBogus;
+}
+
+// turn a bogus string into an empty one
+void
+UnicodeString::unBogus() {
+  if(fFlags & kIsBogus) {
+    setToEmpty();
+  }
+}
+
+// setTo() analogous to the readonly-aliasing constructor with the same signature
+UnicodeString &
+UnicodeString::setTo(UBool isTerminated,
+                     const UChar *text,
+                     int32_t textLength)
+{
+  if(fFlags & kOpenGetBuffer) {
+    // do not modify a string that has an "open" getBuffer(minCapacity)
+    return *this;
+  }
+
+  if(text == NULL) {
+    // treat as an empty string, do not alias
+    releaseArray();
+    setToEmpty();
+    return *this;
+  }
+
+  if( textLength < -1 ||
+      (textLength == -1 && !isTerminated) ||
+      (textLength >= 0 && isTerminated && text[textLength] != 0)
+  ) {
+    setToBogus();
+    return *this;
+  }
+
+  releaseArray();
+
+  if(textLength == -1) {
+    // text is terminated, or else it would have failed the above test
+    textLength = u_strlen(text);
+  }
+  setArray((UChar *)text, textLength, isTerminated ? textLength + 1 : textLength);
+
+  fFlags = kReadonlyAlias;
+  return *this;
+}
+
+// setTo() analogous to the writable-aliasing constructor with the same signature
+UnicodeString &
+UnicodeString::setTo(UChar *buffer,
+                     int32_t buffLength,
+                     int32_t buffCapacity) {
+  if(fFlags & kOpenGetBuffer) {
+    // do not modify a string that has an "open" getBuffer(minCapacity)
+    return *this;
+  }
+
+  if(buffer == NULL) {
+    // treat as an empty string, do not alias
+    releaseArray();
+    setToEmpty();
+    return *this;
+  }
+
+  if(buffLength < -1 || buffCapacity < 0 || buffLength > buffCapacity) {
+    setToBogus();
+    return *this;
+  } else if(buffLength == -1) {
+    // buffLength = u_strlen(buff); but do not look beyond buffCapacity
+    const UChar *p = buffer, *limit = buffer + buffCapacity;
+    while(p != limit && *p != 0) {
+      ++p;
+    }
+    buffLength = (int32_t)(p - buffer);
+  }
+
+  releaseArray();
+
+  setArray(buffer, buffLength, buffCapacity);
+  fFlags = kWritableAlias;
+  return *this;
+}
+
+UnicodeString &UnicodeString::setToUTF8(const StringPiece &utf8) {
+  unBogus();
+  int32_t length = utf8.length();
+  int32_t capacity;
+  // The UTF-16 string will be at most as long as the UTF-8 string.
+  if(length <= US_STACKBUF_SIZE) {
+    capacity = US_STACKBUF_SIZE;
+  } else {
+    capacity = length + 1;  // +1 for the terminating NUL.
+  }
+  UChar *utf16 = getBuffer(capacity);
+  int32_t length16;
+  UErrorCode errorCode = U_ZERO_ERROR;
+  u_strFromUTF8WithSub(utf16, getCapacity(), &length16,
+      utf8.data(), length,
+      0xfffd,  // Substitution character.
+      NULL,    // Don't care about number of substitutions.
+      &errorCode);
+  releaseBuffer(length16);
+  if(U_FAILURE(errorCode)) {
+    setToBogus();
+  }
+  return *this;
+}
+
+UnicodeString&
+UnicodeString::setCharAt(int32_t offset,
+             UChar c)
+{
+  int32_t len = length();
+  if(cloneArrayIfNeeded() && len > 0) {
+    if(offset < 0) {
+      offset = 0;
+    } else if(offset >= len) {
+      offset = len - 1;
+    }
+
+    getArrayStart()[offset] = c;
+  }
+  return *this;
+}
+
+UnicodeString&
+UnicodeString::doReplace( int32_t start,
+              int32_t length,
+              const UnicodeString& src,
+              int32_t srcStart,
+              int32_t srcLength)
+{
+  if(!src.isBogus()) {
+    // pin the indices to legal values
+    src.pinIndices(srcStart, srcLength);
+
+    // get the characters from src
+    // and replace the range in ourselves with them
+    return doReplace(start, length, src.getArrayStart(), srcStart, srcLength);
+  } else {
+    // remove the range
+    return doReplace(start, length, 0, 0, 0);
+  }
+}
+
+UnicodeString&
+UnicodeString::doReplace(int32_t start,
+             int32_t length,
+             const UChar *srcChars,
+             int32_t srcStart,
+             int32_t srcLength)
+{
+  if(!isWritable()) {
+    return *this;
+  }
+
+  int32_t oldLength = this->length();
+
+  // optimize (read-only alias).remove(0, start) and .remove(start, end)
+  if((fFlags&kBufferIsReadonly) && srcLength == 0) {
+    if(start == 0) {
+      // remove prefix by adjusting the array pointer
+      pinIndex(length);
+      fUnion.fFields.fArray += length;
+      fUnion.fFields.fCapacity -= length;
+      setLength(oldLength - length);
+      return *this;
+    } else {
+      pinIndex(start);
+      if(length >= (oldLength - start)) {
+        // remove suffix by reducing the length (like truncate())
+        setLength(start);
+        fUnion.fFields.fCapacity = start;  // not NUL-terminated any more
+        return *this;
+      }
+    }
+  }
+
+  if(srcChars == 0) {
+    srcStart = srcLength = 0;
+  } else if(srcLength < 0) {
+    // get the srcLength if necessary
+    srcLength = u_strlen(srcChars + srcStart);
+  }
+
+  // calculate the size of the string after the replace
+  int32_t newSize;
+
+  // optimize append() onto a large-enough, owned string
+  if(start >= oldLength) {
+    newSize = oldLength + srcLength;
+    if(newSize <= getCapacity() && isBufferWritable()) {
+      us_arrayCopy(srcChars, srcStart, getArrayStart(), oldLength, srcLength);
+      setLength(newSize);
+      return *this;
+    } else {
+      // pin the indices to legal values
+      start = oldLength;
+      length = 0;
+    }
+  } else {
+    // pin the indices to legal values
+    pinIndices(start, length);
+
+    newSize = oldLength - length + srcLength;
+  }
+
+  // the following may change fArray but will not copy the current contents;
+  // therefore we need to keep the current fArray
+  UChar oldStackBuffer[US_STACKBUF_SIZE];
+  UChar *oldArray;
+  if((fFlags&kUsingStackBuffer) && (newSize > US_STACKBUF_SIZE)) {
+    // copy the stack buffer contents because it will be overwritten with
+    // fUnion.fFields values
+    u_memcpy(oldStackBuffer, fUnion.fStackBuffer, oldLength);
+    oldArray = oldStackBuffer;
+  } else {
+    oldArray = getArrayStart();
+  }
+
+  // clone our array and allocate a bigger array if needed
+  int32_t *bufferToDelete = 0;
+  if(!cloneArrayIfNeeded(newSize, newSize + (newSize >> 2) + kGrowSize,
+                         FALSE, &bufferToDelete)
+  ) {
+    return *this;
+  }
+
+  // now do the replace
+
+  UChar *newArray = getArrayStart();
+  if(newArray != oldArray) {
+    // if fArray changed, then we need to copy everything except what will change
+    us_arrayCopy(oldArray, 0, newArray, 0, start);
+    us_arrayCopy(oldArray, start + length,
+                 newArray, start + srcLength,
+                 oldLength - (start + length));
+  } else if(length != srcLength) {
+    // fArray did not change; copy only the portion that isn't changing, leaving a hole
+    us_arrayCopy(oldArray, start + length,
+                 newArray, start + srcLength,
+                 oldLength - (start + length));
+  }
+
+  // now fill in the hole with the new string
+  us_arrayCopy(srcChars, srcStart, newArray, start, srcLength);
+
+  setLength(newSize);
+
+  // delayed delete in case srcChars == fArray when we started, and
+  // to keep oldArray alive for the above operations
+  if (bufferToDelete) {
+    uprv_free(bufferToDelete);
+  }
+
+  return *this;
+}
+
+/**
+ * Replaceable API
+ */
+void
+UnicodeString::handleReplaceBetween(int32_t start,
+                                    int32_t limit,
+                                    const UnicodeString& text) {
+    replaceBetween(start, limit, text);
+}
+
+/**
+ * Replaceable API
+ */
+void 
+UnicodeString::copy(int32_t start, int32_t limit, int32_t dest) {
+    if (limit <= start) {
+        return; // Nothing to do; avoid bogus malloc call
+    }
+    UChar* text = (UChar*) uprv_malloc( sizeof(UChar) * (limit - start) );
+    // Check to make sure text is not null.
+    if (text != NULL) {
+	    extractBetween(start, limit, text, 0);
+	    insert(dest, text, 0, limit - start);    
+	    uprv_free(text);
+    }
+}
+
+/**
+ * Replaceable API
+ *
+ * NOTE: This is for the Replaceable class.  There is no rep.cpp,
+ * so we implement this function here.
+ */
+UBool Replaceable::hasMetaData() const {
+    return TRUE;
+}
+
+/**
+ * Replaceable API
+ */
+UBool UnicodeString::hasMetaData() const {
+    return FALSE;
+}
+
+UnicodeString&
+UnicodeString::doReverse(int32_t start, int32_t length) {
+  if(length <= 1 || !cloneArrayIfNeeded()) {
+    return *this;
+  }
+
+  // pin the indices to legal values
+  pinIndices(start, length);
+  if(length <= 1) {  // pinIndices() might have shrunk the length
+    return *this;
+  }
+
+  UChar *left = getArrayStart() + start;
+  UChar *right = left + length - 1;  // -1 for inclusive boundary (length>=2)
+  UChar swap;
+  UBool hasSupplementary = FALSE;
+
+  // Before the loop we know left<right because length>=2.
+  do {
+    hasSupplementary |= (UBool)U16_IS_LEAD(swap = *left);
+    hasSupplementary |= (UBool)U16_IS_LEAD(*left++ = *right);
+    *right-- = swap;
+  } while(left < right);
+  // Make sure to test the middle code unit of an odd-length string.
+  // Redundant if the length is even.
+  hasSupplementary |= (UBool)U16_IS_LEAD(*left);
+
+  /* if there are supplementary code points in the reversed range, then re-swap their surrogates */
+  if(hasSupplementary) {
+    UChar swap2;
+
+    left = getArrayStart() + start;
+    right = left + length - 1; // -1 so that we can look at *(left+1) if left<right
+    while(left < right) {
+      if(U16_IS_TRAIL(swap = *left) && U16_IS_LEAD(swap2 = *(left + 1))) {
+        *left++ = swap2;
+        *left++ = swap;
+      } else {
+        ++left;
+      }
+    }
+  }
+
+  return *this;
+}
+
+UBool 
+UnicodeString::padLeading(int32_t targetLength,
+                          UChar padChar)
+{
+  int32_t oldLength = length();
+  if(oldLength >= targetLength || !cloneArrayIfNeeded(targetLength)) {
+    return FALSE;
+  } else {
+    // move contents up by padding width
+    UChar *array = getArrayStart();
+    int32_t start = targetLength - oldLength;
+    us_arrayCopy(array, 0, array, start, oldLength);
+
+    // fill in padding character
+    while(--start >= 0) {
+      array[start] = padChar;
+    }
+    setLength(targetLength);
+    return TRUE;
+  }
+}
+
+UBool 
+UnicodeString::padTrailing(int32_t targetLength,
+                           UChar padChar)
+{
+  int32_t oldLength = length();
+  if(oldLength >= targetLength || !cloneArrayIfNeeded(targetLength)) {
+    return FALSE;
+  } else {
+    // fill in padding character
+    UChar *array = getArrayStart();
+    int32_t length = targetLength;
+    while(--length >= oldLength) {
+      array[length] = padChar;
+    }
+    setLength(targetLength);
+    return TRUE;
+  }
+}
+
+//========================================
+// Hashing
+//========================================
+int32_t
+UnicodeString::doHashCode() const
+{
+    /* Delegate hash computation to uhash.  This makes UnicodeString
+     * hashing consistent with UChar* hashing.  */
+    int32_t hashCode = uhash_hashUCharsN(getArrayStart(), length());
+    if (hashCode == kInvalidHashCode) {
+        hashCode = kEmptyHashCode;
+    }
+    return hashCode;
+}
+
+//========================================
+// External Buffer
+//========================================
+
+UChar *
+UnicodeString::getBuffer(int32_t minCapacity) {
+  if(minCapacity>=-1 && cloneArrayIfNeeded(minCapacity)) {
+    fFlags|=kOpenGetBuffer;
+    fShortLength=0;
+    return getArrayStart();
+  } else {
+    return 0;
+  }
+}
+
+void
+UnicodeString::releaseBuffer(int32_t newLength) {
+  if(fFlags&kOpenGetBuffer && newLength>=-1) {
+    // set the new fLength
+    int32_t capacity=getCapacity();
+    if(newLength==-1) {
+      // the new length is the string length, capped by fCapacity
+      const UChar *array=getArrayStart(), *p=array, *limit=array+capacity;
+      while(p<limit && *p!=0) {
+        ++p;
+      }
+      newLength=(int32_t)(p-array);
+    } else if(newLength>capacity) {
+      newLength=capacity;
+    }
+    setLength(newLength);
+    fFlags&=~kOpenGetBuffer;
+  }
+}
+
+//========================================
+// Miscellaneous
+//========================================
+UBool
+UnicodeString::cloneArrayIfNeeded(int32_t newCapacity,
+                                  int32_t growCapacity,
+                                  UBool doCopyArray,
+                                  int32_t **pBufferToDelete,
+                                  UBool forceClone) {
+  // default parameters need to be static, therefore
+  // the defaults are -1 to have convenience defaults
+  if(newCapacity == -1) {
+    newCapacity = getCapacity();
+  }
+
+  // while a getBuffer(minCapacity) is "open",
+  // prevent any modifications of the string by returning FALSE here
+  // if the string is bogus, then only an assignment or similar can revive it
+  if(!isWritable()) {
+    return FALSE;
+  }
+
+  /*
+   * We need to make a copy of the array if
+   * the buffer is read-only, or
+   * the buffer is refCounted (shared), and refCount>1, or
+   * the buffer is too small.
+   * Return FALSE if memory could not be allocated.
+   */
+  if(forceClone ||
+     fFlags & kBufferIsReadonly ||
+     (fFlags & kRefCounted && refCount() > 1) ||
+     newCapacity > getCapacity()
+  ) {
+    // check growCapacity for default value and use of the stack buffer
+    if(growCapacity == -1) {
+      growCapacity = newCapacity;
+    } else if(newCapacity <= US_STACKBUF_SIZE && growCapacity > US_STACKBUF_SIZE) {
+      growCapacity = US_STACKBUF_SIZE;
+    }
+
+    // save old values
+    UChar oldStackBuffer[US_STACKBUF_SIZE];
+    UChar *oldArray;
+    uint8_t flags = fFlags;
+
+    if(flags&kUsingStackBuffer) {
+      if(doCopyArray && growCapacity > US_STACKBUF_SIZE) {
+        // copy the stack buffer contents because it will be overwritten with
+        // fUnion.fFields values
+        us_arrayCopy(fUnion.fStackBuffer, 0, oldStackBuffer, 0, fShortLength);
+        oldArray = oldStackBuffer;
+      } else {
+        oldArray = 0; // no need to copy from stack buffer to itself
+      }
+    } else {
+      oldArray = fUnion.fFields.fArray;
+    }
+
+    // allocate a new array
+    if(allocate(growCapacity) ||
+       (newCapacity < growCapacity && allocate(newCapacity))
+    ) {
+      if(doCopyArray && oldArray != 0) {
+        // copy the contents
+        // do not copy more than what fits - it may be smaller than before
+        int32_t minLength = length();
+        newCapacity = getCapacity();
+        if(newCapacity < minLength) {
+          minLength = newCapacity;
+          setLength(minLength);
+        }
+        us_arrayCopy(oldArray, 0, getArrayStart(), 0, minLength);
+      } else {
+        fShortLength = 0;
+      }
+
+      // release the old array
+      if(flags & kRefCounted) {
+        // the array is refCounted; decrement and release if 0
+        int32_t *pRefCount = ((int32_t *)oldArray - 1);
+        if(umtx_atomic_dec(pRefCount) == 0) {
+          if(pBufferToDelete == 0) {
+            uprv_free(pRefCount);
+          } else {
+            // the caller requested to delete it himself
+            *pBufferToDelete = pRefCount;
+          }
+        }
+      }
+    } else {
+      // not enough memory for growCapacity and not even for the smaller newCapacity
+      // reset the old values for setToBogus() to release the array
+      if(!(flags&kUsingStackBuffer)) {
+        fUnion.fFields.fArray = oldArray;
+      }
+      fFlags = flags;
+      setToBogus();
+      return FALSE;
+    }
+  }
+  return TRUE;
+}
+U_NAMESPACE_END
+
+#ifdef U_STATIC_IMPLEMENTATION
+/*
+This should never be called. It is defined here to make sure that the
+virtual vector deleting destructor is defined within unistr.cpp.
+The vector deleting destructor is already a part of UObject,
+but defining it here makes sure that it is included with this object file.
+This makes sure that static library dependencies are kept to a minimum.
+*/
+static void uprv_UnicodeStringDummy(void) {
+    U_NAMESPACE_USE
+    delete [] (new UnicodeString[2]);
+}
+#endif
diff --git a/source/common/unistr_case.cpp b/source/common/unistr_case.cpp
new file mode 100644
index 0000000..a048c04
--- /dev/null
+++ b/source/common/unistr_case.cpp
@@ -0,0 +1,247 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  unistr_case.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:2
+*
+*   created on: 2004aug19
+*   created by: Markus W. Scherer
+*
+*   Case-mapping functions moved here from unistr.cpp
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/putil.h"
+#include "unicode/locid.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include "unicode/ustring.h"
+#include "unicode/unistr.h"
+#include "unicode/uchar.h"
+#include "unicode/ubrk.h"
+#include "ustr_imp.h"
+#include "uhash.h"
+
+U_NAMESPACE_BEGIN
+
+//========================================
+// Read-only implementation
+//========================================
+
+int8_t
+UnicodeString::doCaseCompare(int32_t start,
+                             int32_t length,
+                             const UChar *srcChars,
+                             int32_t srcStart,
+                             int32_t srcLength,
+                             uint32_t options) const
+{
+  // compare illegal string values
+  // treat const UChar *srcChars==NULL as an empty string
+  if(isBogus()) {
+    return -1;
+  }
+
+  // pin indices to legal values
+  pinIndices(start, length);
+
+  if(srcChars == NULL) {
+    srcStart = srcLength = 0;
+  }
+
+  // get the correct pointer
+  const UChar *chars = getArrayStart();
+
+  chars += start;
+  srcChars += srcStart;
+
+  if(chars != srcChars) {
+    UErrorCode errorCode=U_ZERO_ERROR;
+    int32_t result=u_strcmpFold(chars, length, srcChars, srcLength,
+                                options|U_COMPARE_IGNORE_CASE, &errorCode);
+    if(result!=0) {
+      return (int8_t)(result >> 24 | 1);
+    }
+  } else {
+    // get the srcLength if necessary
+    if(srcLength < 0) {
+      srcLength = u_strlen(srcChars + srcStart);
+    }
+    if(length != srcLength) {
+      return (int8_t)((length - srcLength) >> 24 | 1);
+    }
+  }
+  return 0;
+}
+
+//========================================
+// Write implementation
+//========================================
+
+/*
+ * Implement argument checking and buffer handling
+ * for string case mapping as a common function.
+ */
+
+UnicodeString &
+UnicodeString::caseMap(BreakIterator *titleIter,
+                       const char *locale,
+                       uint32_t options,
+                       int32_t toWhichCase) {
+  if(isEmpty() || !isWritable()) {
+    // nothing to do
+    return *this;
+  }
+
+  const UCaseProps *csp=ucase_getSingleton();
+
+  // We need to allocate a new buffer for the internal string case mapping function.
+  // This is very similar to how doReplace() keeps the old array pointer
+  // and deletes the old array itself after it is done.
+  // In addition, we are forcing cloneArrayIfNeeded() to always allocate a new array.
+  UChar oldStackBuffer[US_STACKBUF_SIZE];
+  UChar *oldArray;
+  int32_t oldLength;
+
+  if(fFlags&kUsingStackBuffer) {
+    // copy the stack buffer contents because it will be overwritten
+    u_memcpy(oldStackBuffer, fUnion.fStackBuffer, fShortLength);
+    oldArray = oldStackBuffer;
+    oldLength = fShortLength;
+  } else {
+    oldArray = getArrayStart();
+    oldLength = length();
+  }
+
+  int32_t capacity;
+  if(oldLength <= US_STACKBUF_SIZE) {
+    capacity = US_STACKBUF_SIZE;
+  } else {
+    capacity = oldLength + 20;
+  }
+  int32_t *bufferToDelete = 0;
+  if(!cloneArrayIfNeeded(capacity, capacity, FALSE, &bufferToDelete, TRUE)) {
+    return *this;
+  }
+
+  // Case-map, and if the result is too long, then reallocate and repeat.
+  UErrorCode errorCode;
+  int32_t newLength;
+  do {
+    errorCode = U_ZERO_ERROR;
+    if(toWhichCase==TO_LOWER) {
+      newLength = ustr_toLower(csp, getArrayStart(), getCapacity(),
+                               oldArray, oldLength,
+                               locale, &errorCode);
+    } else if(toWhichCase==TO_UPPER) {
+      newLength = ustr_toUpper(csp, getArrayStart(), getCapacity(),
+                               oldArray, oldLength,
+                               locale, &errorCode);
+    } else if(toWhichCase==TO_TITLE) {
+#if UCONFIG_NO_BREAK_ITERATION
+        errorCode=U_UNSUPPORTED_ERROR;
+#else
+      newLength = ustr_toTitle(csp, getArrayStart(), getCapacity(),
+                               oldArray, oldLength,
+                               (UBreakIterator *)titleIter, locale, options, &errorCode);
+#endif
+    } else {
+      newLength = ustr_foldCase(csp, getArrayStart(), getCapacity(),
+                                oldArray, oldLength,
+                                options,
+                                &errorCode);
+    }
+    setLength(newLength);
+  } while(errorCode==U_BUFFER_OVERFLOW_ERROR && cloneArrayIfNeeded(newLength, newLength, FALSE));
+
+  if (bufferToDelete) {
+    uprv_free(bufferToDelete);
+  }
+  if(U_FAILURE(errorCode)) {
+    setToBogus();
+  }
+  return *this;
+}
+
+UnicodeString &
+UnicodeString::toLower() {
+  return caseMap(0, Locale::getDefault().getName(), 0, TO_LOWER);
+}
+
+UnicodeString &
+UnicodeString::toLower(const Locale &locale) {
+  return caseMap(0, locale.getName(), 0, TO_LOWER);
+}
+
+UnicodeString &
+UnicodeString::toUpper() {
+  return caseMap(0, Locale::getDefault().getName(), 0, TO_UPPER);
+}
+
+UnicodeString &
+UnicodeString::toUpper(const Locale &locale) {
+  return caseMap(0, locale.getName(), 0, TO_UPPER);
+}
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+UnicodeString &
+UnicodeString::toTitle(BreakIterator *titleIter) {
+  return caseMap(titleIter, Locale::getDefault().getName(), 0, TO_TITLE);
+}
+
+UnicodeString &
+UnicodeString::toTitle(BreakIterator *titleIter, const Locale &locale) {
+  return caseMap(titleIter, locale.getName(), 0, TO_TITLE);
+}
+
+UnicodeString &
+UnicodeString::toTitle(BreakIterator *titleIter, const Locale &locale, uint32_t options) {
+  return caseMap(titleIter, locale.getName(), options, TO_TITLE);
+}
+
+#endif
+
+UnicodeString &
+UnicodeString::foldCase(uint32_t options) {
+    /* The Locale parameter isn't used. Use "" instead. */
+    return caseMap(0, "", options, FOLD_CASE);
+}
+
+U_NAMESPACE_END
+
+// Defined here to reduce dependencies on break iterator
+U_CAPI int32_t U_EXPORT2
+uhash_hashCaselessUnicodeString(const UHashTok key) {
+    U_NAMESPACE_USE
+    const UnicodeString *str = (const UnicodeString*) key.pointer;
+    if (str == NULL) {
+        return 0;
+    }
+    // Inefficient; a better way would be to have a hash function in
+    // UnicodeString that does case folding on the fly.
+    UnicodeString copy(*str);
+    return copy.foldCase().hashCode();
+}
+
+// Defined here to reduce dependencies on break iterator
+U_CAPI UBool U_EXPORT2
+uhash_compareCaselessUnicodeString(const UHashTok key1, const UHashTok key2) {
+    U_NAMESPACE_USE
+    const UnicodeString *str1 = (const UnicodeString*) key1.pointer;
+    const UnicodeString *str2 = (const UnicodeString*) key2.pointer;
+    if (str1 == str2) {
+        return TRUE;
+    }
+    if (str1 == NULL || str2 == NULL) {
+        return FALSE;
+    }
+    return str1->caseCompare(*str2, U_FOLD_CASE_DEFAULT) == 0;
+}
+
diff --git a/source/common/unistr_cnv.cpp b/source/common/unistr_cnv.cpp
new file mode 100644
index 0000000..1626b88
--- /dev/null
+++ b/source/common/unistr_cnv.cpp
@@ -0,0 +1,425 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  unistr_cnv.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:2
+*
+*   created on: 2004aug19
+*   created by: Markus W. Scherer
+*
+*   Character conversion functions moved here from unistr.cpp
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/putil.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include "unicode/ustring.h"
+#include "unicode/unistr.h"
+#include "unicode/ucnv.h"
+#include "ucnv_imp.h"
+#include "putilimp.h"
+#include "ustr_cnv.h"
+#include "ustr_imp.h"
+
+U_NAMESPACE_BEGIN
+
+//========================================
+// Constructors
+//========================================
+
+#if !U_CHARSET_IS_UTF8
+
+UnicodeString::UnicodeString(const char *codepageData)
+  : fShortLength(0),
+    fFlags(kShortString)
+{
+    if(codepageData != 0) {
+        doCodepageCreate(codepageData, (int32_t)uprv_strlen(codepageData), 0);
+    }
+}
+
+UnicodeString::UnicodeString(const char *codepageData,
+                             int32_t dataLength)
+  : fShortLength(0),
+    fFlags(kShortString)
+{
+    if(codepageData != 0) {
+        doCodepageCreate(codepageData, dataLength, 0);
+    }
+}
+
+// else see unistr.cpp
+#endif
+
+UnicodeString::UnicodeString(const char *codepageData,
+                             const char *codepage)
+  : fShortLength(0),
+    fFlags(kShortString)
+{
+    if(codepageData != 0) {
+        doCodepageCreate(codepageData, (int32_t)uprv_strlen(codepageData), codepage);
+    }
+}
+
+UnicodeString::UnicodeString(const char *codepageData,
+                             int32_t dataLength,
+                             const char *codepage)
+  : fShortLength(0),
+    fFlags(kShortString)
+{
+    if(codepageData != 0) {
+        doCodepageCreate(codepageData, dataLength, codepage);
+    }
+}
+
+UnicodeString::UnicodeString(const char *src, int32_t srcLength,
+                             UConverter *cnv,
+                             UErrorCode &errorCode)
+  : fShortLength(0),
+    fFlags(kShortString)
+{
+    if(U_SUCCESS(errorCode)) {
+        // check arguments
+        if(src==NULL) {
+            // treat as an empty string, do nothing more
+        } else if(srcLength<-1) {
+            errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        } else {
+            // get input length
+            if(srcLength==-1) {
+                srcLength=(int32_t)uprv_strlen(src);
+            }
+            if(srcLength>0) {
+                if(cnv!=0) {
+                    // use the provided converter
+                    ucnv_resetToUnicode(cnv);
+                    doCodepageCreate(src, srcLength, cnv, errorCode);
+                } else {
+                    // use the default converter
+                    cnv=u_getDefaultConverter(&errorCode);
+                    doCodepageCreate(src, srcLength, cnv, errorCode);
+                    u_releaseDefaultConverter(cnv);
+                }
+            }
+        }
+
+        if(U_FAILURE(errorCode)) {
+            setToBogus();
+        }
+    }
+}
+
+//========================================
+// Codeset conversion
+//========================================
+
+#if !U_CHARSET_IS_UTF8
+
+int32_t
+UnicodeString::extract(int32_t start,
+                       int32_t length,
+                       char *target,
+                       uint32_t dstSize) const {
+    return extract(start, length, target, dstSize, 0);
+}
+
+// else see unistr.cpp
+#endif
+
+int32_t
+UnicodeString::extract(int32_t start,
+                       int32_t length,
+                       char *target,
+                       uint32_t dstSize,
+                       const char *codepage) const
+{
+    // if the arguments are illegal, then do nothing
+    if(/*dstSize < 0 || */(dstSize > 0 && target == 0)) {
+        return 0;
+    }
+
+    // pin the indices to legal values
+    pinIndices(start, length);
+
+    // We need to cast dstSize to int32_t for all subsequent code.
+    // I don't know why the API was defined with uint32_t but we are stuck with it.
+    // Also, dstSize==0xffffffff means "unlimited" but if we use target+dstSize
+    // as a limit in some functions, it may wrap around and yield a pointer
+    // that compares less-than target.
+    int32_t capacity;
+    if(dstSize < 0x7fffffff) {
+        // Assume that the capacity is real and a limit pointer won't wrap around.
+        capacity = (int32_t)dstSize;
+    } else {
+        // Pin the capacity so that a limit pointer does not wrap around.
+        char *targetLimit = (char *)U_MAX_PTR(target);
+        // U_MAX_PTR(target) returns a targetLimit that is at most 0x7fffffff
+        // greater than target and does not wrap around the top of the address space.
+        capacity = (int32_t)(targetLimit - target);
+    }
+
+    // create the converter
+    UConverter *converter;
+    UErrorCode status = U_ZERO_ERROR;
+
+    // just write the NUL if the string length is 0
+    if(length == 0) {
+        return u_terminateChars(target, capacity, 0, &status);
+    }
+
+    // if the codepage is the default, use our cache
+    // if it is an empty string, then use the "invariant character" conversion
+    if (codepage == 0) {
+        const char *defaultName = ucnv_getDefaultName();
+        if(UCNV_FAST_IS_UTF8(defaultName)) {
+            return toUTF8(start, length, target, capacity);
+        }
+        converter = u_getDefaultConverter(&status);
+    } else if (*codepage == 0) {
+        // use the "invariant characters" conversion
+        int32_t destLength;
+        if(length <= capacity) {
+            destLength = length;
+        } else {
+            destLength = capacity;
+        }
+        u_UCharsToChars(getArrayStart() + start, target, destLength);
+        return u_terminateChars(target, capacity, length, &status);
+    } else {
+        converter = ucnv_open(codepage, &status);
+    }
+
+    length = doExtract(start, length, target, capacity, converter, status);
+
+    // close the converter
+    if (codepage == 0) {
+        u_releaseDefaultConverter(converter);
+    } else {
+        ucnv_close(converter);
+    }
+
+    return length;
+}
+
+int32_t
+UnicodeString::extract(char *dest, int32_t destCapacity,
+                       UConverter *cnv,
+                       UErrorCode &errorCode) const
+{
+    if(U_FAILURE(errorCode)) {
+        return 0;
+    }
+
+    if(isBogus() || destCapacity<0 || (destCapacity>0 && dest==0)) {
+        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    // nothing to do?
+    if(isEmpty()) {
+        return u_terminateChars(dest, destCapacity, 0, &errorCode);
+    }
+
+    // get the converter
+    UBool isDefaultConverter;
+    if(cnv==0) {
+        isDefaultConverter=TRUE;
+        cnv=u_getDefaultConverter(&errorCode);
+        if(U_FAILURE(errorCode)) {
+            return 0;
+        }
+    } else {
+        isDefaultConverter=FALSE;
+        ucnv_resetFromUnicode(cnv);
+    }
+
+    // convert
+    int32_t len=doExtract(0, length(), dest, destCapacity, cnv, errorCode);
+
+    // release the converter
+    if(isDefaultConverter) {
+        u_releaseDefaultConverter(cnv);
+    }
+
+    return len;
+}
+
+int32_t
+UnicodeString::doExtract(int32_t start, int32_t length,
+                         char *dest, int32_t destCapacity,
+                         UConverter *cnv,
+                         UErrorCode &errorCode) const
+{
+    if(U_FAILURE(errorCode)) {
+        if(destCapacity!=0) {
+            *dest=0;
+        }
+        return 0;
+    }
+
+    const UChar *src=getArrayStart()+start, *srcLimit=src+length;
+    char *originalDest=dest;
+    const char *destLimit;
+
+    if(destCapacity==0) {
+        destLimit=dest=0;
+    } else if(destCapacity==-1) {
+        // Pin the limit to U_MAX_PTR if the "magic" destCapacity is used.
+        destLimit=(char*)U_MAX_PTR(dest);
+        // for NUL-termination, translate into highest int32_t
+        destCapacity=0x7fffffff;
+    } else {
+        destLimit=dest+destCapacity;
+    }
+
+    // perform the conversion
+    ucnv_fromUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, &errorCode);
+    length=(int32_t)(dest-originalDest);
+
+    // if an overflow occurs, then get the preflighting length
+    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
+        char buffer[1024];
+
+        destLimit=buffer+sizeof(buffer);
+        do {
+            dest=buffer;
+            errorCode=U_ZERO_ERROR;
+            ucnv_fromUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, &errorCode);
+            length+=(int32_t)(dest-buffer);
+        } while(errorCode==U_BUFFER_OVERFLOW_ERROR);
+    }
+
+    return u_terminateChars(originalDest, destCapacity, length, &errorCode);
+}
+
+void
+UnicodeString::doCodepageCreate(const char *codepageData,
+                                int32_t dataLength,
+                                const char *codepage)
+{
+    // if there's nothing to convert, do nothing
+    if(codepageData == 0 || dataLength == 0 || dataLength < -1) {
+        return;
+    }
+    if(dataLength == -1) {
+        dataLength = (int32_t)uprv_strlen(codepageData);
+    }
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    // create the converter
+    // if the codepage is the default, use our cache
+    // if it is an empty string, then use the "invariant character" conversion
+    UConverter *converter;
+    if (codepage == 0) {
+        const char *defaultName = ucnv_getDefaultName();
+        if(UCNV_FAST_IS_UTF8(defaultName)) {
+            setToUTF8(StringPiece(codepageData, dataLength));
+            return;
+        }
+        converter = u_getDefaultConverter(&status);
+    } else if(*codepage == 0) {
+        // use the "invariant characters" conversion
+        if(cloneArrayIfNeeded(dataLength, dataLength, FALSE)) {
+            u_charsToUChars(codepageData, getArrayStart(), dataLength);
+            setLength(dataLength);
+        } else {
+            setToBogus();
+        }
+        return;
+    } else {
+        converter = ucnv_open(codepage, &status);
+    }
+
+    // if we failed, set the appropriate flags and return
+    if(U_FAILURE(status)) {
+        setToBogus();
+        return;
+    }
+
+    // perform the conversion
+    doCodepageCreate(codepageData, dataLength, converter, status);
+    if(U_FAILURE(status)) {
+        setToBogus();
+    }
+
+    // close the converter
+    if(codepage == 0) {
+        u_releaseDefaultConverter(converter);
+    } else {
+        ucnv_close(converter);
+    }
+}
+
+void
+UnicodeString::doCodepageCreate(const char *codepageData,
+                                int32_t dataLength,
+                                UConverter *converter,
+                                UErrorCode &status)
+{
+    if(U_FAILURE(status)) {
+        return;
+    }
+
+    // set up the conversion parameters
+    const char *mySource     = codepageData;
+    const char *mySourceEnd  = mySource + dataLength;
+    UChar *array, *myTarget;
+
+    // estimate the size needed:
+    int32_t arraySize;
+    if(dataLength <= US_STACKBUF_SIZE) {
+        // try to use the stack buffer
+        arraySize = US_STACKBUF_SIZE;
+    } else {
+        // 1.25 UChar's per source byte should cover most cases
+        arraySize = dataLength + (dataLength >> 2);
+    }
+
+    // we do not care about the current contents
+    UBool doCopyArray = FALSE;
+    for(;;) {
+        if(!cloneArrayIfNeeded(arraySize, arraySize, doCopyArray)) {
+            setToBogus();
+            break;
+        }
+
+        // perform the conversion
+        array = getArrayStart();
+        myTarget = array + length();
+        ucnv_toUnicode(converter, &myTarget,  array + getCapacity(),
+            &mySource, mySourceEnd, 0, TRUE, &status);
+
+        // update the conversion parameters
+        setLength((int32_t)(myTarget - array));
+
+        // allocate more space and copy data, if needed
+        if(status == U_BUFFER_OVERFLOW_ERROR) {
+            // reset the error code
+            status = U_ZERO_ERROR;
+
+            // keep the previous conversion results
+            doCopyArray = TRUE;
+
+            // estimate the new size needed, larger than before
+            // try 2 UChar's per remaining source byte
+            arraySize = (int32_t)(length() + 2 * (mySourceEnd - mySource));
+        } else {
+            break;
+        }
+    }
+}
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/unistr_props.cpp b/source/common/unistr_props.cpp
new file mode 100644
index 0000000..7670de4
--- /dev/null
+++ b/source/common/unistr_props.cpp
@@ -0,0 +1,74 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1999-2007, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  unistr_props.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:2
+*
+*   created on: 2004aug25
+*   created by: Markus W. Scherer
+*
+*   Character property dependent functions moved here from unistr.cpp
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uchar.h"
+#include "unicode/unistr.h"
+
+U_NAMESPACE_BEGIN
+
+UnicodeString& 
+UnicodeString::trim()
+{
+  if(isBogus()) {
+    return *this;
+  }
+
+  UChar *array = getArrayStart();
+  UChar32 c;
+  int32_t oldLength = this->length();
+  int32_t i = oldLength, length;
+
+  // first cut off trailing white space
+  for(;;) {
+    length = i;
+    if(i <= 0) {
+      break;
+    }
+    U16_PREV(array, 0, i, c);
+    if(!(c == 0x20 || u_isWhitespace(c))) {
+      break;
+    }
+  }
+  if(length < oldLength) {
+    setLength(length);
+  }
+
+  // find leading white space
+  int32_t start;
+  i = 0;
+  for(;;) {
+    start = i;
+    if(i >= length) {
+      break;
+    }
+    U16_NEXT(array, i, length, c);
+    if(!(c == 0x20 || u_isWhitespace(c))) {
+      break;
+    }
+  }
+
+  // move string forward over leading white space
+  if(start > 0) {
+    doReplace(0, start, 0, 0, 0);
+  }
+
+  return *this;
+}
+
+U_NAMESPACE_END
diff --git a/source/common/unorm.cpp b/source/common/unorm.cpp
new file mode 100644
index 0000000..8b685ea
--- /dev/null
+++ b/source/common/unorm.cpp
@@ -0,0 +1,266 @@
+/*
+******************************************************************************
+* Copyright (c) 1996-2010, International Business Machines
+* Corporation and others. All Rights Reserved.
+******************************************************************************
+* File unorm.cpp
+*
+* Created by: Vladimir Weinstein 12052000
+*
+* Modification history :
+*
+* Date        Name        Description
+* 02/01/01    synwee      Added normalization quickcheck enum and method.
+* 02/12/01    synwee      Commented out quickcheck util api has been approved
+*                         Added private method for doing FCD checks
+* 02/23/01    synwee      Modified quickcheck and checkFCE to run through 
+*                         string for codepoints < 0x300 for the normalization 
+*                         mode NFC.
+* 05/25/01+   Markus Scherer total rewrite, implement all normalization here
+*                         instead of just wrappers around normlzr.cpp,
+*                         load unorm.dat, support Unicode 3.1 with
+*                         supplementary code points, etc.
+* 2009-nov..2010-jan  Markus Scherer  total rewrite, new Normalizer2 API & code
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/udata.h"
+#include "unicode/ustring.h"
+#include "unicode/uiter.h"
+#include "unicode/unorm.h"
+#include "unicode/unorm2.h"
+#include "normalizer2impl.h"
+#include "unormimp.h"
+#include "uprops.h"
+#include "ustr_imp.h"
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+U_NAMESPACE_USE
+
+/* quick check functions ---------------------------------------------------- */
+
+U_CAPI UNormalizationCheckResult U_EXPORT2
+unorm_quickCheck(const UChar *src,
+                 int32_t srcLength, 
+                 UNormalizationMode mode,
+                 UErrorCode *pErrorCode) {
+    const Normalizer2 *n2=Normalizer2Factory::getInstance(mode, *pErrorCode);
+    return unorm2_quickCheck((const UNormalizer2 *)n2, src, srcLength, pErrorCode);
+}
+
+U_CAPI UNormalizationCheckResult U_EXPORT2
+unorm_quickCheckWithOptions(const UChar *src, int32_t srcLength, 
+                            UNormalizationMode mode, int32_t options,
+                            UErrorCode *pErrorCode) {
+    const Normalizer2 *n2=Normalizer2Factory::getInstance(mode, *pErrorCode);
+    if(options&UNORM_UNICODE_3_2) {
+        FilteredNormalizer2 fn2(*n2, *uniset_getUnicode32Instance(*pErrorCode));
+        return unorm2_quickCheck(
+            reinterpret_cast<const UNormalizer2 *>(static_cast<Normalizer2 *>(&fn2)),
+            src, srcLength, pErrorCode);
+    } else {
+        return unorm2_quickCheck((const UNormalizer2 *)n2, src, srcLength, pErrorCode);
+    }
+}
+
+U_CAPI UBool U_EXPORT2
+unorm_isNormalized(const UChar *src, int32_t srcLength,
+                   UNormalizationMode mode,
+                   UErrorCode *pErrorCode) {
+    const Normalizer2 *n2=Normalizer2Factory::getInstance(mode, *pErrorCode);
+    return unorm2_isNormalized((const UNormalizer2 *)n2, src, srcLength, pErrorCode);
+}
+
+U_CAPI UBool U_EXPORT2
+unorm_isNormalizedWithOptions(const UChar *src, int32_t srcLength,
+                              UNormalizationMode mode, int32_t options,
+                              UErrorCode *pErrorCode) {
+    const Normalizer2 *n2=Normalizer2Factory::getInstance(mode, *pErrorCode);
+    if(options&UNORM_UNICODE_3_2) {
+        FilteredNormalizer2 fn2(*n2, *uniset_getUnicode32Instance(*pErrorCode));
+        return unorm2_isNormalized(
+            reinterpret_cast<const UNormalizer2 *>(static_cast<Normalizer2 *>(&fn2)),
+            src, srcLength, pErrorCode);
+    } else {
+        return unorm2_isNormalized((const UNormalizer2 *)n2, src, srcLength, pErrorCode);
+    }
+}
+
+/* normalize() API ---------------------------------------------------------- */
+
+/** Public API for normalizing. */
+U_CAPI int32_t U_EXPORT2
+unorm_normalize(const UChar *src, int32_t srcLength,
+                UNormalizationMode mode, int32_t options,
+                UChar *dest, int32_t destCapacity,
+                UErrorCode *pErrorCode) {
+    const Normalizer2 *n2=Normalizer2Factory::getInstance(mode, *pErrorCode);
+    if(options&UNORM_UNICODE_3_2) {
+        FilteredNormalizer2 fn2(*n2, *uniset_getUnicode32Instance(*pErrorCode));
+        return unorm2_normalize(
+            reinterpret_cast<const UNormalizer2 *>(static_cast<Normalizer2 *>(&fn2)),
+            src, srcLength, dest, destCapacity, pErrorCode);
+    } else {
+        return unorm2_normalize((const UNormalizer2 *)n2,
+            src, srcLength, dest, destCapacity, pErrorCode);
+    }
+}
+
+
+/* iteration functions ------------------------------------------------------ */
+
+static int32_t
+unorm_iterate(UCharIterator *src, UBool forward,
+              UChar *dest, int32_t destCapacity,
+              UNormalizationMode mode, int32_t options,
+              UBool doNormalize, UBool *pNeededToNormalize,
+              UErrorCode *pErrorCode) {
+    const Normalizer2 *n2=Normalizer2Factory::getInstance(mode, *pErrorCode);
+    const UnicodeSet *uni32;
+    if(options&UNORM_UNICODE_3_2) {
+        uni32=uniset_getUnicode32Instance(*pErrorCode);
+    } else {
+        uni32=NULL;  // unused
+    }
+    FilteredNormalizer2 fn2(*n2, *uni32);
+    if(options&UNORM_UNICODE_3_2) {
+        n2=&fn2;
+    }
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if( destCapacity<0 || (dest==NULL && destCapacity>0) ||
+        src==NULL
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    if(pNeededToNormalize!=NULL) {
+        *pNeededToNormalize=FALSE;
+    }
+    if(!(forward ? src->hasNext(src) : src->hasPrevious(src))) {
+        return u_terminateUChars(dest, destCapacity, 0, pErrorCode);
+    }
+
+    UnicodeString buffer;
+    UChar32 c;
+    if(forward) {
+        /* get one character and ignore its properties */
+        buffer.append(uiter_next32(src));
+        /* get all following characters until we see a boundary */
+        while((c=uiter_next32(src))>=0) {
+            if(n2->hasBoundaryBefore(c)) {
+                /* back out the latest movement to stop at the boundary */
+                src->move(src, -U16_LENGTH(c), UITER_CURRENT);
+                break;
+            } else {
+                buffer.append(c);
+            }
+        }
+    } else {
+        while((c=uiter_previous32(src))>=0) {
+            /* always write this character to the front of the buffer */
+            buffer.insert(0, c);
+            /* stop if this just-copied character is a boundary */
+            if(n2->hasBoundaryBefore(c)) {
+                break;
+            }
+        }
+    }
+
+    UnicodeString destString(dest, 0, destCapacity);
+    if(buffer.length()>0 && doNormalize) {
+        n2->normalize(buffer, destString, *pErrorCode).extract(dest, destCapacity, *pErrorCode);
+        if(pNeededToNormalize!=NULL && U_SUCCESS(*pErrorCode)) {
+            *pNeededToNormalize= destString!=buffer;
+        }
+        return destString.length();
+    } else {
+        /* just copy the source characters */
+        return buffer.extract(dest, destCapacity, *pErrorCode);
+    }
+}
+
+U_CAPI int32_t U_EXPORT2
+unorm_previous(UCharIterator *src,
+               UChar *dest, int32_t destCapacity,
+               UNormalizationMode mode, int32_t options,
+               UBool doNormalize, UBool *pNeededToNormalize,
+               UErrorCode *pErrorCode) {
+    return unorm_iterate(src, FALSE,
+                         dest, destCapacity,
+                         mode, options,
+                         doNormalize, pNeededToNormalize,
+                         pErrorCode);
+}
+
+U_CAPI int32_t U_EXPORT2
+unorm_next(UCharIterator *src,
+           UChar *dest, int32_t destCapacity,
+           UNormalizationMode mode, int32_t options,
+           UBool doNormalize, UBool *pNeededToNormalize,
+           UErrorCode *pErrorCode) {
+    return unorm_iterate(src, TRUE,
+                         dest, destCapacity,
+                         mode, options,
+                         doNormalize, pNeededToNormalize,
+                         pErrorCode);
+}
+
+/* Concatenation of normalized strings -------------------------------------- */
+
+U_CAPI int32_t U_EXPORT2
+unorm_concatenate(const UChar *left, int32_t leftLength,
+                  const UChar *right, int32_t rightLength,
+                  UChar *dest, int32_t destCapacity,
+                  UNormalizationMode mode, int32_t options,
+                  UErrorCode *pErrorCode) {
+    const Normalizer2 *n2=Normalizer2Factory::getInstance(mode, *pErrorCode);
+    const UnicodeSet *uni32;
+    if(options&UNORM_UNICODE_3_2) {
+        uni32=uniset_getUnicode32Instance(*pErrorCode);
+    } else {
+        uni32=NULL;  // unused
+    }
+    FilteredNormalizer2 fn2(*n2, *uni32);
+    if(options&UNORM_UNICODE_3_2) {
+        n2=&fn2;
+    }
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if( destCapacity<0 || (dest==NULL && destCapacity>0) ||
+        left==NULL || leftLength<-1 ||
+        right==NULL || rightLength<-1
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* check for overlapping right and destination */
+    if( dest!=NULL &&
+        ((right>=dest && right<(dest+destCapacity)) ||
+         (rightLength>0 && dest>=right && dest<(right+rightLength)))
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* allow left==dest */
+    UnicodeString destString;
+    if(left==dest) {
+        destString.setTo(dest, leftLength, destCapacity);
+    } else {
+        destString.setTo(dest, 0, destCapacity);
+        destString.append(left, leftLength);
+    }
+    return n2->append(destString, UnicodeString(rightLength<0, right, rightLength), *pErrorCode).
+           extract(dest, destCapacity, *pErrorCode);
+}
+
+#endif /* #if !UCONFIG_NO_NORMALIZATION */
diff --git a/source/common/unorm_it.c b/source/common/unorm_it.c
new file mode 100644
index 0000000..00396bd
--- /dev/null
+++ b/source/common/unorm_it.c
@@ -0,0 +1,645 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2003-2008, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  unorm_it.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2003jan21
+*   created by: Markus W. Scherer
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION && !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/uiter.h"
+#include "unicode/unorm.h"
+#include "unorm_it.h"
+#include "cmemory.h"
+
+/* UNormIterator ------------------------------------------------------------ */
+
+enum {
+    INITIAL_CAPACITY=100
+};
+
+struct UNormIterator {
+    UCharIterator api;
+    UCharIterator *iter;
+
+    /*
+     * chars and states either use the static buffers
+     * or are allocated in the same memory block
+     *
+     * They are parallel arrays with states[] holding the getState() values
+     * from normalization boundaries, and UITER_NO_STATE in between.
+     */
+    UChar *chars;
+    uint32_t *states;
+
+    /*
+     * api.start: first valid character & state in the arrays
+     * api.index: current position
+     * api.limit: one past the last valid character in chars[], but states[limit] is valid
+     * capacity: length of allocated arrays
+     */
+    int32_t capacity;
+
+    /* the current iter->getState(), saved to avoid unnecessary setState() calls; may not correspond to api->index! */
+    uint32_t state;
+
+    /* there are UChars available before start or after limit? */
+    UBool hasPrevious, hasNext, isStackAllocated;
+
+    UNormalizationMode mode;
+
+    UChar charsBuffer[INITIAL_CAPACITY];
+    uint32_t statesBuffer[INITIAL_CAPACITY+1]; /* one more than charsBuffer[]! */
+};
+
+static void
+initIndexes(UNormIterator *uni, UCharIterator *iter) {
+    /* do not pass api so that the compiler knows it's an alias pointer to uni itself */
+    UCharIterator *api=&uni->api;
+
+    if(!iter->hasPrevious(iter)) {
+        /* set indexes to the beginning of the arrays */
+        api->start=api->index=api->limit=0;
+        uni->hasPrevious=FALSE;
+        uni->hasNext=iter->hasNext(iter);
+    } else if(!iter->hasNext(iter)) {
+        /* set indexes to the end of the arrays */
+        api->start=api->index=api->limit=uni->capacity;
+        uni->hasNext=FALSE;
+        uni->hasPrevious=iter->hasPrevious(iter);
+    } else {
+        /* set indexes into the middle of the arrays */
+        api->start=api->index=api->limit=uni->capacity/2;
+        uni->hasPrevious=uni->hasNext=TRUE;
+    }
+}
+
+static UBool
+reallocArrays(UNormIterator *uni, int32_t capacity, UBool addAtStart) {
+    /* do not pass api so that the compiler knows it's an alias pointer to uni itself */
+    UCharIterator *api=&uni->api;
+
+    uint32_t *states;
+    UChar *chars;
+    int32_t start, limit;
+
+    states=(uint32_t *)uprv_malloc((capacity+1)*4+capacity*2);
+    if(states==NULL) {
+        return FALSE;
+    }
+
+    chars=(UChar *)(states+(capacity+1));
+    uni->capacity=capacity;
+
+    start=api->start;
+    limit=api->limit;
+
+    if(addAtStart) {
+        /* copy old contents to the end of the new arrays */
+        int32_t delta;
+
+        delta=capacity-uni->capacity;
+        uprv_memcpy(states+delta+start, uni->states+start, (limit-start+1)*4);
+        uprv_memcpy(chars+delta+start, uni->chars+start, (limit-start)*4);
+
+        api->start=start+delta;
+        api->index+=delta;
+        api->limit=limit+delta;
+    } else {
+        /* copy old contents to the beginning of the new arrays */
+        uprv_memcpy(states+start, uni->states+start, (limit-start+1)*4);
+        uprv_memcpy(chars+start, uni->chars+start, (limit-start)*4);
+    }
+
+    uni->chars=chars;
+    uni->states=states;
+
+    return TRUE;
+}
+
+static void
+moveContentsTowardStart(UCharIterator *api, UChar chars[], uint32_t states[], int32_t delta) {
+    /* move array contents up to make room */
+    int32_t srcIndex, destIndex, limit;
+
+    limit=api->limit;
+    srcIndex=delta;
+    if(srcIndex>api->start) {
+        /* look for a position in the arrays with a known state */
+        while(srcIndex<limit && states[srcIndex]==UITER_NO_STATE) {
+            ++srcIndex;
+        }
+    }
+
+    /* now actually move the array contents */
+    api->start=destIndex=0;
+    while(srcIndex<limit) {
+        chars[destIndex]=chars[srcIndex];
+        states[destIndex++]=states[srcIndex++];
+    }
+
+    /* copy states[limit] as well! */
+    states[destIndex]=states[srcIndex];
+
+    api->limit=destIndex;
+}
+
+static void
+moveContentsTowardEnd(UCharIterator *api, UChar chars[], uint32_t states[], int32_t delta) {
+    /* move array contents up to make room */
+    int32_t srcIndex, destIndex, start;
+
+    start=api->start;
+    destIndex=((UNormIterator *)api)->capacity;
+    srcIndex=destIndex-delta;
+    if(srcIndex<api->limit) {
+        /* look for a position in the arrays with a known state */
+        while(srcIndex>start && states[srcIndex]==UITER_NO_STATE) {
+            --srcIndex;
+        }
+    }
+
+    /* now actually move the array contents */
+    api->limit=destIndex;
+
+    /* copy states[limit] as well! */
+    states[destIndex]=states[srcIndex];
+
+    while(srcIndex>start) {
+        chars[--destIndex]=chars[--srcIndex];
+        states[destIndex]=states[srcIndex];
+    }
+
+    api->start=destIndex;
+}
+
+/* normalize forward from the limit, assume hasNext is true */
+static UBool
+readNext(UNormIterator *uni, UCharIterator *iter) {
+    /* do not pass api so that the compiler knows it's an alias pointer to uni itself */
+    UCharIterator *api=&uni->api;
+
+    /* make capacity/4 room at the end of the arrays */
+    int32_t limit, capacity, room;
+    UErrorCode errorCode;
+
+    limit=api->limit;
+    capacity=uni->capacity;
+    room=capacity/4;
+    if(room>(capacity-limit)) {
+        /* move array contents to make room */
+        moveContentsTowardStart(api, uni->chars, uni->states, room);
+        api->index=limit=api->limit;
+        uni->hasPrevious=TRUE;
+    }
+
+    /* normalize starting from the limit position */
+    errorCode=U_ZERO_ERROR;
+    if(uni->state!=uni->states[limit]) {
+        uiter_setState(iter, uni->states[limit], &errorCode);
+        if(U_FAILURE(errorCode)) {
+            uni->state=UITER_NO_STATE;
+            uni->hasNext=FALSE;
+            return FALSE;
+        }
+    }
+
+    room=unorm_next(iter, uni->chars+limit, capacity-limit, uni->mode, 0, TRUE, NULL, &errorCode);
+    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
+        if(room<=capacity) {
+            /* empty and re-use the arrays */
+            uni->states[0]=uni->states[limit];
+            api->start=api->index=api->limit=limit=0;
+            uni->hasPrevious=TRUE;
+        } else {
+            capacity+=room+100;
+            if(!reallocArrays(uni, capacity, FALSE)) {
+                uni->state=UITER_NO_STATE;
+                uni->hasNext=FALSE;
+                return FALSE;
+            }
+            limit=api->limit;
+        }
+
+        errorCode=U_ZERO_ERROR;
+        uiter_setState(iter, uni->states[limit], &errorCode);
+        room=unorm_next(iter, uni->chars+limit, capacity-limit, uni->mode, 0, TRUE, NULL, &errorCode);
+    }
+    if(U_FAILURE(errorCode) || room==0) {
+        uni->state=UITER_NO_STATE;
+        uni->hasNext=FALSE;
+        return FALSE;
+    }
+
+    /* room>0 */
+    ++limit; /* leave the known states[limit] alone */
+    for(--room; room>0; --room) {
+        /* set unknown states for all but the normalization boundaries */
+        uni->states[limit++]=UITER_NO_STATE;
+    }
+    uni->states[limit]=uni->state=uiter_getState(iter);
+    uni->hasNext=iter->hasNext(iter);
+    api->limit=limit;
+    return TRUE;
+}
+
+/* normalize backward from the start, assume hasPrevious is true */
+static UBool
+readPrevious(UNormIterator *uni, UCharIterator *iter) {
+    /* do not pass api so that the compiler knows it's an alias pointer to uni itself */
+    UCharIterator *api=&uni->api;
+
+    /* make capacity/4 room at the start of the arrays */
+    int32_t start, capacity, room;
+    UErrorCode errorCode;
+
+    start=api->start;
+    capacity=uni->capacity;
+    room=capacity/4;
+    if(room>start) {
+        /* move array contents to make room */
+        moveContentsTowardEnd(api, uni->chars, uni->states, room);
+        api->index=start=api->start;
+        uni->hasNext=TRUE;
+    }
+
+    /* normalize ending at the start position */
+    errorCode=U_ZERO_ERROR;
+    if(uni->state!=uni->states[start]) {
+        uiter_setState(iter, uni->states[start], &errorCode);
+        if(U_FAILURE(errorCode)) {
+            uni->state=UITER_NO_STATE;
+            uni->hasPrevious=FALSE;
+            return FALSE;
+        }
+    }
+
+    room=unorm_previous(iter, uni->chars, start, uni->mode, 0, TRUE, NULL, &errorCode);
+    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
+        if(room<=capacity) {
+            /* empty and re-use the arrays */
+            uni->states[capacity]=uni->states[start];
+            api->start=api->index=api->limit=start=capacity;
+            uni->hasNext=TRUE;
+        } else {
+            capacity+=room+100;
+            if(!reallocArrays(uni, capacity, TRUE)) {
+                uni->state=UITER_NO_STATE;
+                uni->hasPrevious=FALSE;
+                return FALSE;
+            }
+            start=api->start;
+        }
+
+        errorCode=U_ZERO_ERROR;
+        uiter_setState(iter, uni->states[start], &errorCode);
+        room=unorm_previous(iter, uni->chars, start, uni->mode, 0, TRUE, NULL, &errorCode);
+    }
+    if(U_FAILURE(errorCode) || room==0) {
+        uni->state=UITER_NO_STATE;
+        uni->hasPrevious=FALSE;
+        return FALSE;
+    }
+
+    /* room>0 */
+    do {
+        /* copy the UChars from chars[0..room[ to chars[(start-room)..start[ */
+        uni->chars[--start]=uni->chars[--room];
+        /* set unknown states for all but the normalization boundaries */
+        uni->states[start]=UITER_NO_STATE;
+    } while(room>0);
+    uni->states[start]=uni->state=uiter_getState(iter);
+    uni->hasPrevious=iter->hasPrevious(iter);
+    api->start=start;
+    return TRUE;
+}
+
+/* Iterator runtime API functions ------------------------------------------- */
+
+static int32_t U_CALLCONV
+unormIteratorGetIndex(UCharIterator *api, UCharIteratorOrigin origin) {
+    switch(origin) {
+    case UITER_ZERO:
+    case UITER_START:
+        return 0;
+    case UITER_CURRENT:
+    case UITER_LIMIT:
+    case UITER_LENGTH:
+        return UITER_UNKNOWN_INDEX;
+    default:
+        /* not a valid origin */
+        /* Should never get here! */
+        return -1;
+    }
+}
+
+static int32_t U_CALLCONV
+unormIteratorMove(UCharIterator *api, int32_t delta, UCharIteratorOrigin origin) {
+    UNormIterator *uni=(UNormIterator *)api;
+    UCharIterator *iter=uni->iter;
+    int32_t pos;
+
+    switch(origin) {
+    case UITER_ZERO:
+    case UITER_START:
+        /* restart from the beginning */
+        if(uni->hasPrevious) {
+            iter->move(iter, 0, UITER_START);
+            api->start=api->index=api->limit=0;
+            uni->states[api->limit]=uni->state=uiter_getState(iter);
+            uni->hasPrevious=FALSE;
+            uni->hasNext=iter->hasNext(iter);
+        } else {
+            /* we already have the beginning of the normalized text */
+            api->index=api->start;
+        }
+        break;
+    case UITER_CURRENT:
+        break;
+    case UITER_LIMIT:
+    case UITER_LENGTH:
+        /* restart from the end */
+        if(uni->hasNext) {
+            iter->move(iter, 0, UITER_LIMIT);
+            api->start=api->index=api->limit=uni->capacity;
+            uni->states[api->limit]=uni->state=uiter_getState(iter);
+            uni->hasPrevious=iter->hasPrevious(iter);
+            uni->hasNext=FALSE;
+        } else {
+            /* we already have the end of the normalized text */
+            api->index=api->limit;
+        }
+        break;
+    default:
+        return -1;  /* Error */
+    }
+
+    /* move relative to the current position by delta normalized UChars */
+    if(delta==0) {
+        /* nothing to do */
+    } else if(delta>0) {
+        /* go forward until the requested position is in the buffer */
+        for(;;) {
+            pos=api->index+delta;   /* requested position */
+            delta=pos-api->limit;   /* remainder beyond buffered text */
+            if(delta<=0) {
+                api->index=pos;     /* position reached */
+                break;
+            }
+
+            /* go to end of buffer and normalize further */
+            api->index=api->limit;
+            if(!uni->hasNext || !readNext(uni, iter)) {
+                break;              /* reached end of text */
+            }
+        }
+    } else /* delta<0 */ {
+        /* go backward until the requested position is in the buffer */
+        for(;;) {
+            pos=api->index+delta;   /* requested position */
+            delta=pos-api->start;   /* remainder beyond buffered text */
+            if(delta>=0) {
+                api->index=pos;     /* position reached */
+                break;
+            }
+
+            /* go to start of buffer and normalize further */
+            api->index=api->start;
+            if(!uni->hasPrevious || !readPrevious(uni, iter)) {
+                break;              /* reached start of text */
+            }
+        }
+    }
+
+    if(api->index==api->start && !uni->hasPrevious) {
+        return 0;
+    } else {
+        return UITER_UNKNOWN_INDEX;
+    }
+}
+
+static UBool U_CALLCONV
+unormIteratorHasNext(UCharIterator *api) {
+    return api->index<api->limit || ((UNormIterator *)api)->hasNext;
+}
+
+static UBool U_CALLCONV
+unormIteratorHasPrevious(UCharIterator *api) {
+    return api->index>api->start || ((UNormIterator *)api)->hasPrevious;
+}
+
+static UChar32 U_CALLCONV
+unormIteratorCurrent(UCharIterator *api) {
+    UNormIterator *uni=(UNormIterator *)api;
+
+    if( api->index<api->limit ||
+        (uni->hasNext && readNext(uni, uni->iter))
+    ) {
+        return uni->chars[api->index];
+    } else {
+        return U_SENTINEL;
+    }
+}
+
+static UChar32 U_CALLCONV
+unormIteratorNext(UCharIterator *api) {
+    UNormIterator *uni=(UNormIterator *)api;
+
+    if( api->index<api->limit ||
+        (uni->hasNext && readNext(uni, uni->iter))
+    ) {
+        return uni->chars[api->index++];
+    } else {
+        return U_SENTINEL;
+    }
+}
+
+static UChar32 U_CALLCONV
+unormIteratorPrevious(UCharIterator *api) {
+    UNormIterator *uni=(UNormIterator *)api;
+
+    if( api->index>api->start ||
+        (uni->hasPrevious && readPrevious(uni, uni->iter))
+    ) {
+        return uni->chars[--api->index];
+    } else {
+        return U_SENTINEL;
+    }
+}
+
+static uint32_t U_CALLCONV
+unormIteratorGetState(const UCharIterator *api) {
+    /* not uni->state because that may not be at api->index */
+    return ((UNormIterator *)api)->states[api->index];
+}
+
+static void U_CALLCONV
+unormIteratorSetState(UCharIterator *api, uint32_t state, UErrorCode *pErrorCode) {
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        /* do nothing */
+    } else if(api==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+    } else if(state==UITER_NO_STATE) {
+        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+    } else {
+        UNormIterator *uni=(UNormIterator *)api;
+        UCharIterator *iter=((UNormIterator *)api)->iter;
+        if(state!=uni->state) {
+            uni->state=state;
+            uiter_setState(iter, state, pErrorCode);
+        }
+
+        /*
+         * Try shortcuts: If the requested state is in the array contents
+         * then just set the index there.
+         *
+         * We assume that the state is unique per position!
+         */
+        if(state==uni->states[api->index]) {
+            return;
+        } else if(state==uni->states[api->limit]) {
+            api->index=api->limit;
+            return;
+        } else {
+            /* search for the index with this state */
+            int32_t i;
+
+            for(i=api->start; i<api->limit; ++i) {
+                if(state==uni->states[i]) {
+                    api->index=i;
+                    return;
+                }
+            }
+        }
+
+        /* there is no array index for this state, reset for fresh contents */
+        initIndexes((UNormIterator *)api, iter);
+        uni->states[api->limit]=state;
+    }
+}
+
+static const UCharIterator unormIterator={
+    NULL, 0, 0, 0, 0, 0,
+    unormIteratorGetIndex,
+    unormIteratorMove,
+    unormIteratorHasNext,
+    unormIteratorHasPrevious,
+    unormIteratorCurrent,
+    unormIteratorNext,
+    unormIteratorPrevious,
+    NULL,
+    unormIteratorGetState,
+    unormIteratorSetState
+};
+
+/* Setup functions ---------------------------------------------------------- */
+
+U_CAPI UNormIterator * U_EXPORT2
+unorm_openIter(void *stackMem, int32_t stackMemSize, UErrorCode *pErrorCode) {
+    UNormIterator *uni;
+
+    /* argument checking */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return NULL;
+    }
+
+    /* allocate */
+    uni=NULL;
+    if(stackMem!=NULL && stackMemSize>=sizeof(UNormIterator)) {
+        if(U_ALIGNMENT_OFFSET(stackMem)==0) {
+            /* already aligned */
+            uni=(UNormIterator *)stackMem;
+        } else {
+            int32_t align=(int32_t)U_ALIGNMENT_OFFSET_UP(stackMem);
+            if((stackMemSize-=align)>=(int32_t)sizeof(UNormIterator)) {
+                /* needs alignment */
+                uni=(UNormIterator *)((char *)stackMem+align);
+            }
+        }
+        /* else does not fit */
+    }
+
+    if(uni!=NULL) {
+        uni->isStackAllocated=TRUE;
+    } else {
+        uni=(UNormIterator *)uprv_malloc(sizeof(UNormIterator));
+        if(uni==NULL) {
+            *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+            return NULL;
+        }
+        uni->isStackAllocated=FALSE;
+    }
+
+    /*
+     * initialize
+     * do not memset because that would unnecessarily initialize the arrays
+     */
+    uni->iter=NULL;
+    uni->chars=uni->charsBuffer;
+    uni->states=uni->statesBuffer;
+    uni->capacity=INITIAL_CAPACITY;
+    uni->state=UITER_NO_STATE;
+    uni->hasPrevious=uni->hasNext=FALSE;
+    uni->mode=UNORM_NONE;
+
+    /* set a no-op iterator into the api */
+    uiter_setString(&uni->api, NULL, 0);
+    return uni;
+}
+
+U_CAPI void U_EXPORT2
+unorm_closeIter(UNormIterator *uni) {
+    if(uni!=NULL) {
+        if(uni->states!=uni->statesBuffer) {
+            /* chars and states are allocated in the same memory block */
+            uprv_free(uni->states);
+        }
+        if(!uni->isStackAllocated) {
+            uprv_free(uni);
+        }
+    }
+}
+
+U_CAPI UCharIterator * U_EXPORT2
+unorm_setIter(UNormIterator *uni, UCharIterator *iter, UNormalizationMode mode, UErrorCode *pErrorCode) {
+    /* argument checking */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return NULL;
+    }
+    if(uni==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+    if( iter==NULL || iter->getState==NULL || iter->setState==NULL ||
+        mode<UNORM_NONE || UNORM_MODE_COUNT<=mode
+    ) {
+        /* set a no-op iterator into the api */
+        uiter_setString(&uni->api, NULL, 0);
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    /* set the iterator and initialize */
+    uprv_memcpy(&uni->api, &unormIterator, sizeof(unormIterator));
+
+    uni->iter=iter;
+    uni->mode=mode;
+
+    initIndexes(uni, iter);
+    uni->states[uni->api.limit]=uni->state=uiter_getState(iter);
+
+    return &uni->api;
+}
+
+#endif /* uconfig.h switches */
diff --git a/source/common/unorm_it.h b/source/common/unorm_it.h
new file mode 100644
index 0000000..384b7d4
--- /dev/null
+++ b/source/common/unorm_it.h
@@ -0,0 +1,148 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2003, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  unorm_it.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2003jan21
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __UNORM_IT_H__
+#define __UNORM_IT_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION && !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/uiter.h"
+#include "unicode/unorm.h"
+
+/**
+ * Normalizing UCharIterator wrapper.
+ * This internal API basically duplicates the functionality of the C++ Normalizer
+ * but
+ * - it actually implements a character iterator (UCharIterator)
+ *   with few restrictions (see unorm_setIter())
+ * - it supports UCharIterator getState()/setState()
+ * - it uses lower-level APIs and buffers more text and states,
+ *   hopefully resulting in higher performance
+ *
+ * Usage example:
+ * \code
+ * function(UCharIterator *srcIter) {
+ *     UNormIterator *uni;
+ *     UCharIterator *iter;
+ *     UErrorCode errorCode;
+ * 
+ *     errorCode=U_ZERO_ERROR;
+ *     uni=unorm_openIter(&errorCode);
+ *     if(U_FAILURE(errorCode)) {
+ *         // report error
+ *         return;
+ *     }
+ * 
+ *     iter=unorm_setIter(uni, srcIter, UNORM_FCD, &errorCode);
+ *     if(U_FAILURE(errorCode)) {
+ *         // report error
+ *     } else {
+ *         // use iter to iterate over the canonically ordered
+ *         // version of srcIter's text
+ *         uint32_t state;
+ * 
+ *         ...
+ * 
+ *         state=uiter_getState(iter);
+ *         if(state!=UITER_NO_STATE) {
+ *             // use valid state, store it, use iter some more
+ *             ...
+ * 
+ *             // later restore iter to the saved state:
+ *             uiter_setState(iter, state, &errorCode);
+ * 
+ *             ...
+ *         }
+ * 
+ *         ...
+ *     }
+ *     unorm_closeIter(uni);
+ * }
+ * \endcode
+ *
+ * See also the ICU test suites.
+ *
+ * @internal
+ */
+struct UNormIterator;
+typedef struct UNormIterator UNormIterator;
+
+/**
+ * Size of a stack buffer to hold a UNormIterator, see the stackMem parameter
+ * of unorm_openIter().
+ *
+ * @internal
+ */
+#define UNORM_ITER_SIZE 1024
+
+/**
+ * Open a normalizing iterator. Must be closed later.
+ * Use unorm_setIter().
+ *
+ * @param stackMem Pointer to preallocated (stack-allocated) buffer to hold
+ *                 the UNormIterator if possible; can be NULL.
+ * @param stackMemSize Number of bytes at stackMem; can be 0,
+ *                     or should be >= UNORM_ITER_SIZE for a non-NULL stackMem.
+ * @param pErrorCode ICU error code
+ * @return an allocated and pre-initialized UNormIterator
+ * @internal
+ */
+U_CAPI UNormIterator * U_EXPORT2
+unorm_openIter(void *stackMem, int32_t stackMemSize, UErrorCode *pErrorCode);
+
+/**
+ * Close a normalizing iterator.
+ *
+ * @param uni UNormIterator from unorm_openIter()
+ * @internal
+ */
+U_CAPI void U_EXPORT2
+unorm_closeIter(UNormIterator *uni);
+
+/**
+ * Set a UCharIterator and a normalization mode for the normalizing iterator
+ * to wrap. The normalizing iterator will read from the character iterator,
+ * normalize the text, and in turn deliver it with its own wrapper UCharIterator
+ * interface which it returns.
+ *
+ * The source iterator remains at its current position through the unorm_setIter()
+ * call but will be used and moved as soon as the
+ * the returned normalizing iterator is.
+ *
+ * The returned interface pointer is valid for as long as the normalizing iterator
+ * is open and until another unorm_setIter() call is made on it.
+ *
+ * The normalizing iterator's UCharIterator interface has the following properties:
+ * - getIndex() and move() will almost always return UITER_UNKNOWN_INDEX
+ * - getState() will return UITER_NO_STATE for unknown states for positions
+ *              that are not at normalization boundaries
+ *
+ * @param uni UNormIterator from unorm_openIter()
+ * @param iter The source text UCharIterator to be wrapped. It is aliases into the normalizing iterator.
+ *             Must support getState() and setState().
+ * @param mode The normalization mode.
+ * @param pErrorCode ICU error code
+ * @return an alias to the normalizing iterator's UCharIterator interface
+ * @internal
+ */
+U_CAPI UCharIterator * U_EXPORT2
+unorm_setIter(UNormIterator *uni, UCharIterator *iter, UNormalizationMode mode, UErrorCode *pErrorCode);
+
+#endif /* uconfig.h switches */
+
+#endif
diff --git a/source/common/unormcmp.cpp b/source/common/unormcmp.cpp
new file mode 100644
index 0000000..83fbc58
--- /dev/null
+++ b/source/common/unormcmp.cpp
@@ -0,0 +1,639 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2001-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  unormcmp.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2004sep13
+*   created by: Markus W. Scherer
+*
+*   unorm_compare() function moved here from unorm.cpp for better modularization.
+*   Depends on both normalization and case folding.
+*   Allows unorm.cpp to not depend on any character properties code.
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/unorm.h"
+#include "unicode/ustring.h"
+#include "cmemory.h"
+#include "normalizer2impl.h"
+#include "ucase.h"
+#include "uprops.h"
+#include "ustr_imp.h"
+
+U_NAMESPACE_USE
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+/* compare canonically equivalent ------------------------------------------- */
+
+/*
+ * Compare two strings for canonical equivalence.
+ * Further options include case-insensitive comparison and
+ * code point order (as opposed to code unit order).
+ *
+ * In this function, canonical equivalence is optional as well.
+ * If canonical equivalence is tested, then both strings must fulfill
+ * the FCD check.
+ *
+ * Semantically, this is equivalent to
+ *   strcmp[CodePointOrder](NFD(foldCase(s1)), NFD(foldCase(s2)))
+ * where code point order, NFD and foldCase are all optional.
+ *
+ * String comparisons almost always yield results before processing both strings
+ * completely.
+ * They are generally more efficient working incrementally instead of
+ * performing the sub-processing (strlen, normalization, case-folding)
+ * on the entire strings first.
+ *
+ * It is also unnecessary to not normalize identical characters.
+ *
+ * This function works in principle as follows:
+ *
+ * loop {
+ *   get one code unit c1 from s1 (-1 if end of source)
+ *   get one code unit c2 from s2 (-1 if end of source)
+ *
+ *   if(either string finished) {
+ *     return result;
+ *   }
+ *   if(c1==c2) {
+ *     continue;
+ *   }
+ *
+ *   // c1!=c2
+ *   try to decompose/case-fold c1/c2, and continue if one does;
+ *
+ *   // still c1!=c2 and neither decomposes/case-folds, return result
+ *   return c1-c2;
+ * }
+ *
+ * When a character decomposes, then the pointer for that source changes to
+ * the decomposition, pushing the previous pointer onto a stack.
+ * When the end of the decomposition is reached, then the code unit reader
+ * pops the previous source from the stack.
+ * (Same for case-folding.)
+ *
+ * This is complicated further by operating on variable-width UTF-16.
+ * The top part of the loop works on code units, while lookups for decomposition
+ * and case-folding need code points.
+ * Code points are assembled after the equality/end-of-source part.
+ * The source pointer is only advanced beyond all code units when the code point
+ * actually decomposes/case-folds.
+ *
+ * If we were on a trail surrogate unit when assembling a code point,
+ * and the code point decomposes/case-folds, then the decomposition/folding
+ * result must be compared with the part of the other string that corresponds to
+ * this string's lead surrogate.
+ * Since we only assemble a code point when hitting a trail unit when the
+ * preceding lead units were identical, we back up the other string by one unit
+ * in such a case.
+ *
+ * The optional code point order comparison at the end works with
+ * the same fix-up as the other code point order comparison functions.
+ * See ustring.c and the comment near the end of this function.
+ *
+ * Assumption: A decomposition or case-folding result string never contains
+ * a single surrogate. This is a safe assumption in the Unicode Standard.
+ * Therefore, we do not need to check for surrogate pairs across
+ * decomposition/case-folding boundaries.
+ *
+ * Further assumptions (see verifications tstnorm.cpp):
+ * The API function checks for FCD first, while the core function
+ * first case-folds and then decomposes. This requires that case-folding does not
+ * un-FCD any strings.
+ *
+ * The API function may also NFD the input and turn off decomposition.
+ * This requires that case-folding does not un-NFD strings either.
+ *
+ * TODO If any of the above two assumptions is violated,
+ * then this entire code must be re-thought.
+ * If this happens, then a simple solution is to case-fold both strings up front
+ * and to turn off UNORM_INPUT_IS_FCD.
+ * We already do this when not both strings are in FCD because makeFCD
+ * would be a partial NFD before the case folding, which does not work.
+ * Note that all of this is only a problem when case-folding _and_
+ * canonical equivalence come together.
+ * (Comments in unorm_compare() are more up to date than this TODO.)
+ */
+
+/* stack element for previous-level source/decomposition pointers */
+struct CmpEquivLevel {
+    const UChar *start, *s, *limit;
+};
+typedef struct CmpEquivLevel CmpEquivLevel;
+
+/**
+ * Internal option for unorm_cmpEquivFold() for decomposing.
+ * If not set, just do strcasecmp().
+ */
+#define _COMPARE_EQUIV 0x80000
+
+/* internal function */
+static int32_t
+unorm_cmpEquivFold(const UChar *s1, int32_t length1,
+                   const UChar *s2, int32_t length2,
+                   uint32_t options,
+                   UErrorCode *pErrorCode) {
+    const Normalizer2Impl *nfcImpl;
+    const UCaseProps *csp;
+
+    /* current-level start/limit - s1/s2 as current */
+    const UChar *start1, *start2, *limit1, *limit2;
+
+    /* decomposition and case folding variables */
+    const UChar *p;
+    int32_t length;
+
+    /* stacks of previous-level start/current/limit */
+    CmpEquivLevel stack1[2], stack2[2];
+
+    /* buffers for algorithmic decompositions */
+    UChar decomp1[4], decomp2[4];
+
+    /* case folding buffers, only use current-level start/limit */
+    UChar fold1[UCASE_MAX_STRING_LENGTH+1], fold2[UCASE_MAX_STRING_LENGTH+1];
+
+    /* track which is the current level per string */
+    int32_t level1, level2;
+
+    /* current code units, and code points for lookups */
+    UChar32 c1, c2, cp1, cp2;
+
+    /* no argument error checking because this itself is not an API */
+
+    /*
+     * assume that at least one of the options _COMPARE_EQUIV and U_COMPARE_IGNORE_CASE is set
+     * otherwise this function must behave exactly as uprv_strCompare()
+     * not checking for that here makes testing this function easier
+     */
+
+    /* normalization/properties data loaded? */
+    if((options&_COMPARE_EQUIV)!=0) {
+        nfcImpl=Normalizer2Factory::getNFCImpl(*pErrorCode);
+    } else {
+        nfcImpl=NULL;
+    }
+    if((options&U_COMPARE_IGNORE_CASE)!=0) {
+        csp=ucase_getSingleton();
+    } else {
+        csp=NULL;
+    }
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    /* initialize */
+    start1=s1;
+    if(length1==-1) {
+        limit1=NULL;
+    } else {
+        limit1=s1+length1;
+    }
+
+    start2=s2;
+    if(length2==-1) {
+        limit2=NULL;
+    } else {
+        limit2=s2+length2;
+    }
+
+    level1=level2=0;
+    c1=c2=-1;
+
+    /* comparison loop */
+    for(;;) {
+        /*
+         * here a code unit value of -1 means "get another code unit"
+         * below it will mean "this source is finished"
+         */
+
+        if(c1<0) {
+            /* get next code unit from string 1, post-increment */
+            for(;;) {
+                if(s1==limit1 || ((c1=*s1)==0 && (limit1==NULL || (options&_STRNCMP_STYLE)))) {
+                    if(level1==0) {
+                        c1=-1;
+                        break;
+                    }
+                } else {
+                    ++s1;
+                    break;
+                }
+
+                /* reached end of level buffer, pop one level */
+                do {
+                    --level1;
+                    start1=stack1[level1].start;
+                } while(start1==NULL);
+                s1=stack1[level1].s;
+                limit1=stack1[level1].limit;
+            }
+        }
+
+        if(c2<0) {
+            /* get next code unit from string 2, post-increment */
+            for(;;) {
+                if(s2==limit2 || ((c2=*s2)==0 && (limit2==NULL || (options&_STRNCMP_STYLE)))) {
+                    if(level2==0) {
+                        c2=-1;
+                        break;
+                    }
+                } else {
+                    ++s2;
+                    break;
+                }
+
+                /* reached end of level buffer, pop one level */
+                do {
+                    --level2;
+                    start2=stack2[level2].start;
+                } while(start2==NULL);
+                s2=stack2[level2].s;
+                limit2=stack2[level2].limit;
+            }
+        }
+
+        /*
+         * compare c1 and c2
+         * either variable c1, c2 is -1 only if the corresponding string is finished
+         */
+        if(c1==c2) {
+            if(c1<0) {
+                return 0;   /* c1==c2==-1 indicating end of strings */
+            }
+            c1=c2=-1;       /* make us fetch new code units */
+            continue;
+        } else if(c1<0) {
+            return -1;      /* string 1 ends before string 2 */
+        } else if(c2<0) {
+            return 1;       /* string 2 ends before string 1 */
+        }
+        /* c1!=c2 && c1>=0 && c2>=0 */
+
+        /* get complete code points for c1, c2 for lookups if either is a surrogate */
+        cp1=c1;
+        if(U_IS_SURROGATE(c1)) {
+            UChar c;
+
+            if(U_IS_SURROGATE_LEAD(c1)) {
+                if(s1!=limit1 && U16_IS_TRAIL(c=*s1)) {
+                    /* advance ++s1; only below if cp1 decomposes/case-folds */
+                    cp1=U16_GET_SUPPLEMENTARY(c1, c);
+                }
+            } else /* isTrail(c1) */ {
+                if(start1<=(s1-2) && U16_IS_LEAD(c=*(s1-2))) {
+                    cp1=U16_GET_SUPPLEMENTARY(c, c1);
+                }
+            }
+        }
+
+        cp2=c2;
+        if(U_IS_SURROGATE(c2)) {
+            UChar c;
+
+            if(U_IS_SURROGATE_LEAD(c2)) {
+                if(s2!=limit2 && U16_IS_TRAIL(c=*s2)) {
+                    /* advance ++s2; only below if cp2 decomposes/case-folds */
+                    cp2=U16_GET_SUPPLEMENTARY(c2, c);
+                }
+            } else /* isTrail(c2) */ {
+                if(start2<=(s2-2) && U16_IS_LEAD(c=*(s2-2))) {
+                    cp2=U16_GET_SUPPLEMENTARY(c, c2);
+                }
+            }
+        }
+
+        /*
+         * go down one level for each string
+         * continue with the main loop as soon as there is a real change
+         */
+
+        if( level1==0 && (options&U_COMPARE_IGNORE_CASE) &&
+            (length=ucase_toFullFolding(csp, (UChar32)cp1, &p, options))>=0
+        ) {
+            /* cp1 case-folds to the code point "length" or to p[length] */
+            if(U_IS_SURROGATE(c1)) {
+                if(U_IS_SURROGATE_LEAD(c1)) {
+                    /* advance beyond source surrogate pair if it case-folds */
+                    ++s1;
+                } else /* isTrail(c1) */ {
+                    /*
+                     * we got a supplementary code point when hitting its trail surrogate,
+                     * therefore the lead surrogate must have been the same as in the other string;
+                     * compare this decomposition with the lead surrogate in the other string
+                     * remember that this simulates bulk text replacement:
+                     * the decomposition would replace the entire code point
+                     */
+                    --s2;
+                    c2=*(s2-1);
+                }
+            }
+
+            /* push current level pointers */
+            stack1[0].start=start1;
+            stack1[0].s=s1;
+            stack1[0].limit=limit1;
+            ++level1;
+
+            /* copy the folding result to fold1[] */
+            if(length<=UCASE_MAX_STRING_LENGTH) {
+                u_memcpy(fold1, p, length);
+            } else {
+                int32_t i=0;
+                U16_APPEND_UNSAFE(fold1, i, length);
+                length=i;
+            }
+
+            /* set next level pointers to case folding */
+            start1=s1=fold1;
+            limit1=fold1+length;
+
+            /* get ready to read from decomposition, continue with loop */
+            c1=-1;
+            continue;
+        }
+
+        if( level2==0 && (options&U_COMPARE_IGNORE_CASE) &&
+            (length=ucase_toFullFolding(csp, (UChar32)cp2, &p, options))>=0
+        ) {
+            /* cp2 case-folds to the code point "length" or to p[length] */
+            if(U_IS_SURROGATE(c2)) {
+                if(U_IS_SURROGATE_LEAD(c2)) {
+                    /* advance beyond source surrogate pair if it case-folds */
+                    ++s2;
+                } else /* isTrail(c2) */ {
+                    /*
+                     * we got a supplementary code point when hitting its trail surrogate,
+                     * therefore the lead surrogate must have been the same as in the other string;
+                     * compare this decomposition with the lead surrogate in the other string
+                     * remember that this simulates bulk text replacement:
+                     * the decomposition would replace the entire code point
+                     */
+                    --s1;
+                    c1=*(s1-1);
+                }
+            }
+
+            /* push current level pointers */
+            stack2[0].start=start2;
+            stack2[0].s=s2;
+            stack2[0].limit=limit2;
+            ++level2;
+
+            /* copy the folding result to fold2[] */
+            if(length<=UCASE_MAX_STRING_LENGTH) {
+                u_memcpy(fold2, p, length);
+            } else {
+                int32_t i=0;
+                U16_APPEND_UNSAFE(fold2, i, length);
+                length=i;
+            }
+
+            /* set next level pointers to case folding */
+            start2=s2=fold2;
+            limit2=fold2+length;
+
+            /* get ready to read from decomposition, continue with loop */
+            c2=-1;
+            continue;
+        }
+
+        if( level1<2 && (options&_COMPARE_EQUIV) &&
+            0!=(p=nfcImpl->getDecomposition((UChar32)cp1, decomp1, length))
+        ) {
+            /* cp1 decomposes into p[length] */
+            if(U_IS_SURROGATE(c1)) {
+                if(U_IS_SURROGATE_LEAD(c1)) {
+                    /* advance beyond source surrogate pair if it decomposes */
+                    ++s1;
+                } else /* isTrail(c1) */ {
+                    /*
+                     * we got a supplementary code point when hitting its trail surrogate,
+                     * therefore the lead surrogate must have been the same as in the other string;
+                     * compare this decomposition with the lead surrogate in the other string
+                     * remember that this simulates bulk text replacement:
+                     * the decomposition would replace the entire code point
+                     */
+                    --s2;
+                    c2=*(s2-1);
+                }
+            }
+
+            /* push current level pointers */
+            stack1[level1].start=start1;
+            stack1[level1].s=s1;
+            stack1[level1].limit=limit1;
+            ++level1;
+
+            /* set empty intermediate level if skipped */
+            if(level1<2) {
+                stack1[level1++].start=NULL;
+            }
+
+            /* set next level pointers to decomposition */
+            start1=s1=p;
+            limit1=p+length;
+
+            /* get ready to read from decomposition, continue with loop */
+            c1=-1;
+            continue;
+        }
+
+        if( level2<2 && (options&_COMPARE_EQUIV) &&
+            0!=(p=nfcImpl->getDecomposition((UChar32)cp2, decomp2, length))
+        ) {
+            /* cp2 decomposes into p[length] */
+            if(U_IS_SURROGATE(c2)) {
+                if(U_IS_SURROGATE_LEAD(c2)) {
+                    /* advance beyond source surrogate pair if it decomposes */
+                    ++s2;
+                } else /* isTrail(c2) */ {
+                    /*
+                     * we got a supplementary code point when hitting its trail surrogate,
+                     * therefore the lead surrogate must have been the same as in the other string;
+                     * compare this decomposition with the lead surrogate in the other string
+                     * remember that this simulates bulk text replacement:
+                     * the decomposition would replace the entire code point
+                     */
+                    --s1;
+                    c1=*(s1-1);
+                }
+            }
+
+            /* push current level pointers */
+            stack2[level2].start=start2;
+            stack2[level2].s=s2;
+            stack2[level2].limit=limit2;
+            ++level2;
+
+            /* set empty intermediate level if skipped */
+            if(level2<2) {
+                stack2[level2++].start=NULL;
+            }
+
+            /* set next level pointers to decomposition */
+            start2=s2=p;
+            limit2=p+length;
+
+            /* get ready to read from decomposition, continue with loop */
+            c2=-1;
+            continue;
+        }
+
+        /*
+         * no decomposition/case folding, max level for both sides:
+         * return difference result
+         *
+         * code point order comparison must not just return cp1-cp2
+         * because when single surrogates are present then the surrogate pairs
+         * that formed cp1 and cp2 may be from different string indexes
+         *
+         * example: { d800 d800 dc01 } vs. { d800 dc00 }, compare at second code units
+         * c1=d800 cp1=10001 c2=dc00 cp2=10000
+         * cp1-cp2>0 but c1-c2<0 and in fact in UTF-32 it is { d800 10001 } < { 10000 }
+         *
+         * therefore, use same fix-up as in ustring.c/uprv_strCompare()
+         * except: uprv_strCompare() fetches c=*s while this functions fetches c=*s++
+         * so we have slightly different pointer/start/limit comparisons here
+         */
+
+        if(c1>=0xd800 && c2>=0xd800 && (options&U_COMPARE_CODE_POINT_ORDER)) {
+            /* subtract 0x2800 from BMP code points to make them smaller than supplementary ones */
+            if(
+                (c1<=0xdbff && s1!=limit1 && U16_IS_TRAIL(*s1)) ||
+                (U16_IS_TRAIL(c1) && start1!=(s1-1) && U16_IS_LEAD(*(s1-2)))
+            ) {
+                /* part of a surrogate pair, leave >=d800 */
+            } else {
+                /* BMP code point - may be surrogate code point - make <d800 */
+                c1-=0x2800;
+            }
+
+            if(
+                (c2<=0xdbff && s2!=limit2 && U16_IS_TRAIL(*s2)) ||
+                (U16_IS_TRAIL(c2) && start2!=(s2-1) && U16_IS_LEAD(*(s2-2)))
+            ) {
+                /* part of a surrogate pair, leave >=d800 */
+            } else {
+                /* BMP code point - may be surrogate code point - make <d800 */
+                c2-=0x2800;
+            }
+        }
+
+        return c1-c2;
+    }
+}
+
+U_CAPI int32_t U_EXPORT2
+unorm_compare(const UChar *s1, int32_t length1,
+              const UChar *s2, int32_t length2,
+              uint32_t options,
+              UErrorCode *pErrorCode) {
+    /* argument checking */
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(s1==0 || length1<-1 || s2==0 || length2<-1) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    UnicodeString fcd1, fcd2;
+    int32_t normOptions=(int32_t)(options>>UNORM_COMPARE_NORM_OPTIONS_SHIFT);
+    options|=_COMPARE_EQUIV;
+
+    /*
+     * UAX #21 Case Mappings, as fixed for Unicode version 4
+     * (see Jitterbug 2021), defines a canonical caseless match as
+     *
+     * A string X is a canonical caseless match
+     * for a string Y if and only if
+     * NFD(toCasefold(NFD(X))) = NFD(toCasefold(NFD(Y)))
+     *
+     * For better performance, we check for FCD (or let the caller tell us that
+     * both strings are in FCD) for the inner normalization.
+     * BasicNormalizerTest::FindFoldFCDExceptions() makes sure that
+     * case-folding preserves the FCD-ness of a string.
+     * The outer normalization is then only performed by unorm_cmpEquivFold()
+     * when there is a difference.
+     *
+     * Exception: When using the Turkic case-folding option, we do perform
+     * full NFD first. This is because in the Turkic case precomposed characters
+     * with 0049 capital I or 0069 small i fold differently whether they
+     * are first decomposed or not, so an FCD check - a check only for
+     * canonical order - is not sufficient.
+     */
+    if(!(options&UNORM_INPUT_IS_FCD) || (options&U_FOLD_CASE_EXCLUDE_SPECIAL_I)) {
+        const Normalizer2 *n2;
+        if(options&U_FOLD_CASE_EXCLUDE_SPECIAL_I) {
+            n2=Normalizer2Factory::getNFDInstance(*pErrorCode);
+        } else {
+            n2=Normalizer2Factory::getFCDInstance(*pErrorCode);
+        }
+        if (U_FAILURE(*pErrorCode)) {
+            return 0;
+        }
+
+        // check if s1 and/or s2 fulfill the FCD conditions
+        const UnicodeSet *uni32;
+        if(normOptions&UNORM_UNICODE_3_2) {
+            uni32=uniset_getUnicode32Instance(*pErrorCode);
+        } else {
+            uni32=NULL;  // unused
+        }
+        FilteredNormalizer2 fn2(*n2, *uni32);
+        if(normOptions&UNORM_UNICODE_3_2) {
+            n2=&fn2;
+        }
+
+        UnicodeString str1(length1<0, s1, length1);
+        UnicodeString str2(length2<0, s2, length2);
+        int32_t spanQCYes1=n2->spanQuickCheckYes(str1, *pErrorCode);
+        int32_t spanQCYes2=n2->spanQuickCheckYes(str2, *pErrorCode);
+        if(U_FAILURE(*pErrorCode)) {
+            return 0;
+        }
+
+        /*
+         * ICU 2.4 had a further optimization:
+         * If both strings were not in FCD, then they were both NFD'ed,
+         * and the _COMPARE_EQUIV option was turned off.
+         * It is not entirely clear that this is valid with the current
+         * definition of the canonical caseless match.
+         * Therefore, ICU 2.6 removes that optimization.
+         */
+
+        if(spanQCYes1<str1.length()) {
+            UnicodeString unnormalized=str1.tempSubString(spanQCYes1);
+            fcd1.setTo(FALSE, str1.getBuffer(), spanQCYes1);
+            n2->normalizeSecondAndAppend(fcd1, unnormalized, *pErrorCode);
+            s1=fcd1.getBuffer();
+            length1=fcd1.length();
+        }
+        if(spanQCYes2<str2.length()) {
+            UnicodeString unnormalized=str2.tempSubString(spanQCYes2);
+            fcd2.setTo(FALSE, str2.getBuffer(), spanQCYes2);
+            n2->normalizeSecondAndAppend(fcd2, unnormalized, *pErrorCode);
+            s2=fcd2.getBuffer();
+            length2=fcd2.length();
+        }
+    }
+
+    if(U_SUCCESS(*pErrorCode)) {
+        return unorm_cmpEquivFold(s1, length1, s2, length2, options, pErrorCode);
+    } else {
+        return 0;
+    }
+}
+
+#endif /* #if !UCONFIG_NO_NORMALIZATION */
diff --git a/source/common/unormimp.h b/source/common/unormimp.h
new file mode 100644
index 0000000..1e0765e
--- /dev/null
+++ b/source/common/unormimp.h
@@ -0,0 +1,495 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2001-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  unormimp.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2001may25
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __UNORMIMP_H__
+#define __UNORMIMP_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "udataswp.h"
+
+/*
+ * The 2001-2010 implementation of the normalization code loads its data from
+ * unorm.icu, which is generated with the gennorm tool.
+ * The format of that file is described at the end of this file.
+ */
+
+/* norm32 value constants */
+enum {
+    /* quick check flags 0..3 set mean "no" for their forms */
+    _NORM_QC_NFC=0x11,          /* no|maybe */
+    _NORM_QC_NFKC=0x22,         /* no|maybe */
+    _NORM_QC_NFD=4,             /* no */
+    _NORM_QC_NFKD=8,            /* no */
+
+    _NORM_QC_ANY_NO=0xf,
+
+    /* quick check flags 4..5 mean "maybe" for their forms; test flags>=_NORM_QC_MAYBE */
+    _NORM_QC_MAYBE=0x10,
+    _NORM_QC_ANY_MAYBE=0x30,
+
+    _NORM_QC_MASK=0x3f,
+
+    _NORM_COMBINES_FWD=0x40,
+    _NORM_COMBINES_BACK=0x80,
+    _NORM_COMBINES_ANY=0xc0,
+
+    _NORM_CC_SHIFT=8,           /* UnicodeData.txt combining class in bits 15..8 */
+    _NORM_CC_MASK=0xff00,
+
+    _NORM_EXTRA_SHIFT=16,               /* 16 bits for the index to UChars and other extra data */
+    _NORM_EXTRA_INDEX_TOP=0xfc00,       /* start of surrogate specials after shift */
+
+    _NORM_EXTRA_SURROGATE_MASK=0x3ff,
+    _NORM_EXTRA_SURROGATE_TOP=0x3f0,    /* hangul etc. */
+
+    _NORM_EXTRA_HANGUL=_NORM_EXTRA_SURROGATE_TOP,
+    _NORM_EXTRA_JAMO_L,
+    _NORM_EXTRA_JAMO_V,
+    _NORM_EXTRA_JAMO_T
+};
+
+/* norm32 value constants using >16 bits */
+#define _NORM_MIN_SPECIAL       0xfc000000
+#define _NORM_SURROGATES_TOP    0xfff00000
+#define _NORM_MIN_HANGUL        0xfff00000
+#define _NORM_MIN_JAMO_V        0xfff20000
+#define _NORM_JAMO_V_TOP        0xfff30000
+
+/* value constants for auxTrie */
+enum {
+    _NORM_AUX_COMP_EX_SHIFT=10,
+    _NORM_AUX_UNSAFE_SHIFT=11,
+    _NORM_AUX_NFC_SKIPPABLE_F_SHIFT=12
+};
+
+#define _NORM_AUX_MAX_FNC           ((int32_t)1<<_NORM_AUX_COMP_EX_SHIFT)
+
+#define _NORM_AUX_FNC_MASK          (uint32_t)(_NORM_AUX_MAX_FNC-1)
+#define _NORM_AUX_COMP_EX_MASK      ((uint32_t)1<<_NORM_AUX_COMP_EX_SHIFT)
+#define _NORM_AUX_UNSAFE_MASK       ((uint32_t)1<<_NORM_AUX_UNSAFE_SHIFT)
+#define _NORM_AUX_NFC_SKIP_F_MASK   ((uint32_t)1<<_NORM_AUX_NFC_SKIPPABLE_F_SHIFT)
+
+/* canonStartSets[0..31] contains indexes for what is in the array */
+enum {
+    _NORM_SET_INDEX_CANON_SETS_LENGTH,      /* number of uint16_t in canonical starter sets */
+    _NORM_SET_INDEX_CANON_BMP_TABLE_LENGTH, /* number of uint16_t in the BMP search table (contains pairs) */
+    _NORM_SET_INDEX_CANON_SUPP_TABLE_LENGTH,/* number of uint16_t in the supplementary search table (contains triplets) */
+
+    /* from formatVersion 2.3: */
+    _NORM_SET_INDEX_NX_CJK_COMPAT_OFFSET,   /* uint16_t offset from canonStartSets[0] to the
+                                               exclusion set for CJK compatibility characters */
+    _NORM_SET_INDEX_NX_UNICODE32_OFFSET,    /* uint16_t offset from canonStartSets[0] to the
+                                               exclusion set for Unicode 3.2 characters */
+    _NORM_SET_INDEX_NX_RESERVED_OFFSET,     /* uint16_t offset from canonStartSets[0] to the
+                                               end of the previous exclusion set */
+
+    _NORM_SET_INDEX_TOP=32                  /* changing this requires a new formatVersion */
+};
+
+/* more constants for canonical starter sets */
+
+/* 14 bit indexes to canonical USerializedSets */
+#define _NORM_MAX_CANON_SETS            0x4000
+
+/* single-code point BMP sets are encoded directly in the search table except if result=0x4000..0x7fff */
+#define _NORM_CANON_SET_BMP_MASK        0xc000
+#define _NORM_CANON_SET_BMP_IS_INDEX    0x4000
+
+/* indexes[] value names */
+enum {
+    _NORM_INDEX_TRIE_SIZE,              /* number of bytes in normalization trie */
+    _NORM_INDEX_UCHAR_COUNT,            /* number of UChars in extra data */
+
+    _NORM_INDEX_COMBINE_DATA_COUNT,     /* number of uint16_t words for combining data */
+    _NORM_INDEX_COMBINE_FWD_COUNT,      /* number of code points that combine forward */
+    _NORM_INDEX_COMBINE_BOTH_COUNT,     /* number of code points that combine forward and backward */
+    _NORM_INDEX_COMBINE_BACK_COUNT,     /* number of code points that combine backward */
+
+    _NORM_INDEX_MIN_NFC_NO_MAYBE,       /* first code point with quick check NFC NO/MAYBE */
+    _NORM_INDEX_MIN_NFKC_NO_MAYBE,      /* first code point with quick check NFKC NO/MAYBE */
+    _NORM_INDEX_MIN_NFD_NO_MAYBE,       /* first code point with quick check NFD NO/MAYBE */
+    _NORM_INDEX_MIN_NFKD_NO_MAYBE,      /* first code point with quick check NFKD NO/MAYBE */
+
+    _NORM_INDEX_FCD_TRIE_SIZE,          /* number of bytes in FCD trie */
+
+    _NORM_INDEX_AUX_TRIE_SIZE,          /* number of bytes in the auxiliary trie */
+    _NORM_INDEX_CANON_SET_COUNT,        /* number of uint16_t in the array of serialized USet */
+
+    _NORM_INDEX_TOP=32                  /* changing this requires a new formatVersion */
+};
+
+enum {
+    /* FCD check: everything below this code point is known to have a 0 lead combining class */
+    _NORM_MIN_WITH_LEAD_CC=0x300
+};
+
+enum {
+    /**
+     * Bit 7 of the length byte for a decomposition string in extra data is
+     * a flag indicating whether the decomposition string is
+     * preceded by a 16-bit word with the leading and trailing cc
+     * of the decomposition (like for A-umlaut);
+     * if not, then both cc's are zero (like for compatibility ideographs).
+     */
+    _NORM_DECOMP_FLAG_LENGTH_HAS_CC=0x80,
+    /**
+     * Bits 6..0 of the length byte contain the actual length.
+     */
+    _NORM_DECOMP_LENGTH_MASK=0x7f
+};
+
+/* Constants for options flags for normalization. @draft ICU 2.6 */
+enum {
+    /** Options bit 0, do not decompose Hangul syllables. @draft ICU 2.6 */
+    UNORM_NX_HANGUL=1,
+    /** Options bit 1, do not decompose CJK compatibility characters. @draft ICU 2.6 */
+    UNORM_NX_CJK_COMPAT=2
+};
+
+/**
+ * Swap unorm.icu. See udataswp.h.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+unorm_swap(const UDataSwapper *ds,
+           const void *inData, int32_t length, void *outData,
+           UErrorCode *pErrorCode);
+
+/**
+ * Description of the format of unorm.icu version 2.3.
+ *
+ * Main change from version 1 to version 2:
+ * Use of new, common UTrie instead of normalization-specific tries.
+ * Change to version 2.1: add third/auxiliary trie with associated data.
+ * Change to version 2.2: add skippable (f) flag data (_NORM_AUX_NFC_SKIP_F_MASK).
+ * Change to version 2.3: add serialized sets for normalization exclusions
+ *                        stored inside canonStartSets[]
+ *
+ * For more details of how to use the data structures see the code
+ * in unorm.cpp (runtime normalization code) and
+ * in gennorm.c and gennorm/store.c (build-time data generation).
+ *
+ * For the serialized format of UTrie see utrie.c/UTrieHeader.
+ *
+ * - Overall partition
+ *
+ * unorm.dat customarily begins with a UDataInfo structure, see udata.h and .c.
+ * After that there are the following structures:
+ *
+ * int32_t indexes[_NORM_INDEX_TOP];            -- _NORM_INDEX_TOP=32, see enum in this file
+ *
+ * UTrie normTrie;                              -- size in bytes=indexes[_NORM_INDEX_TRIE_SIZE]
+ * 
+ * uint16_t extraData[extraDataTop];            -- extraDataTop=indexes[_NORM_INDEX_UCHAR_COUNT]
+ *                                                 extraData[0] contains the number of units for
+ *                                                 FC_NFKC_Closure (formatVersion>=2.1)
+ *
+ * uint16_t combiningTable[combiningTableTop];  -- combiningTableTop=indexes[_NORM_INDEX_COMBINE_DATA_COUNT]
+ *                                                 combiningTableTop may include one 16-bit padding unit
+ *                                                 to make sure that fcdTrie is 32-bit-aligned
+ *
+ * UTrie fcdTrie;                               -- size in bytes=indexes[_NORM_INDEX_FCD_TRIE_SIZE]
+ *
+ * UTrie auxTrie;                               -- size in bytes=indexes[_NORM_INDEX_AUX_TRIE_SIZE]
+ *
+ * uint16_t canonStartSets[canonStartSetsTop]   -- canonStartSetsTop=indexes[_NORM_INDEX_CANON_SET_COUNT]
+ *                                                 serialized USets and binary search tables, see below
+ *
+ *
+ * The indexes array contains lengths and sizes of the following arrays and structures
+ * as well as the following values:
+ *  indexes[_NORM_INDEX_COMBINE_FWD_COUNT]=combineFwdTop
+ *      -- one more than the highest combining index computed for forward-only-combining characters
+ *  indexes[_NORM_INDEX_COMBINE_BOTH_COUNT]=combineBothTop-combineFwdTop
+ *      -- number of combining indexes computed for both-ways-combining characters
+ *  indexes[_NORM_INDEX_COMBINE_BACK_COUNT]=combineBackTop-combineBothTop
+ *      -- number of combining indexes computed for backward-only-combining characters
+ *
+ *  indexes[_NORM_INDEX_MIN_NF*_NO_MAYBE] (where *={ C, D, KC, KD })
+ *      -- first code point with a quick check NF* value of NO/MAYBE
+ *
+ *
+ * - Tries
+ *
+ * The main structures are two UTrie tables ("compact arrays"),
+ * each with one index array and one data array.
+ * See utrie.h and utrie.c.
+ *
+ *
+ * - Tries in unorm.dat
+ *
+ * The first trie (normTrie above)
+ * provides data for the NF* quick checks and normalization.
+ * The second trie (fcdTrie above) provides data just for FCD checks.
+ *
+ *
+ * - norm32 data words from the first trie
+ *
+ * The norm32Table contains one 32-bit word "norm32" per code point.
+ * It contains the following bit fields:
+ * 31..16   extra data index, _NORM_EXTRA_SHIFT is used to shift this field down
+ *          if this index is <_NORM_EXTRA_INDEX_TOP then it is an index into
+ *              extraData[] where variable-length normalization data for this
+ *              code point is found
+ *          if this index is <_NORM_EXTRA_INDEX_TOP+_NORM_EXTRA_SURROGATE_TOP
+ *              then this is a norm32 for a leading surrogate, and the index
+ *              value is used together with the following trailing surrogate
+ *              code unit in the second trie access
+ *          if this index is >=_NORM_EXTRA_INDEX_TOP+_NORM_EXTRA_SURROGATE_TOP
+ *              then this is a norm32 for a "special" character,
+ *              i.e., the character is a Hangul syllable or a Jamo
+ *              see _NORM_EXTRA_HANGUL etc.
+ *          generally, instead of extracting this index from the norm32 and
+ *              comparing it with the above constants,
+ *              the normalization code compares the entire norm32 value
+ *              with _NORM_MIN_SPECIAL, _NORM_SURROGATES_TOP, _NORM_MIN_HANGUL etc.
+ *
+ * 15..8    combining class (cc) according to UnicodeData.txt
+ *
+ *  7..6    _NORM_COMBINES_ANY flags, used in composition to see if a character
+ *              combines with any following or preceding character(s)
+ *              at all
+ *     7    _NORM_COMBINES_BACK
+ *     6    _NORM_COMBINES_FWD
+ *
+ *  5..0    quick check flags, set for "no" or "maybe", with separate flags for
+ *              each normalization form
+ *              the higher bits are "maybe" flags; for NF*D there are no such flags
+ *              the lower bits are "no" flags for all forms, in the same order
+ *              as the "maybe" flags,
+ *              which is (MSB to LSB): NFKD NFD NFKC NFC
+ *  5..4    _NORM_QC_ANY_MAYBE
+ *  3..0    _NORM_QC_ANY_NO
+ *              see further related constants
+ *
+ *
+ * - Extra data per code point
+ *
+ * "Extra data" is referenced by the index in norm32.
+ * It is variable-length data. It is only present, and only those parts
+ * of it are, as needed for a given character.
+ * The norm32 extra data index is added to the beginning of extraData[]
+ * to get to a vector of 16-bit words with data at the following offsets:
+ *
+ * [-1]     Combining index for composition.
+ *              Stored only if norm32&_NORM_COMBINES_ANY .
+ * [0]      Lengths of the canonical and compatibility decomposition strings.
+ *              Stored only if there are decompositions, i.e.,
+ *              if norm32&(_NORM_QC_NFD|_NORM_QC_NFKD)
+ *          High byte: length of NFKD, or 0 if none
+ *          Low byte: length of NFD, or 0 if none
+ *          Each length byte also has another flag:
+ *              Bit 7 of a length byte is set if there are non-zero
+ *              combining classes (cc's) associated with the respective
+ *              decomposition. If this flag is set, then the decomposition
+ *              is preceded by a 16-bit word that contains the
+ *              leading and trailing cc's.
+ *              Bits 6..0 of a length byte are the length of the
+ *              decomposition string, not counting the cc word.
+ * [1..n]   NFD
+ * [n+1..]  NFKD
+ *
+ * Each of the two decompositions consists of up to two parts:
+ * - The 16-bit words with the leading and trailing cc's.
+ *   This is only stored if bit 7 of the corresponding length byte
+ *   is set. In this case, at least one of the cc's is not zero.
+ *   High byte: leading cc==cc of the first code point in the decomposition string
+ *   Low byte: trailing cc==cc of the last code point in the decomposition string
+ * - The decomposition string in UTF-16, with length code units.
+ *
+ *
+ * - Combining indexes and combiningTable[]
+ *
+ * Combining indexes are stored at the [-1] offset of the extra data
+ * if the character combines forward or backward with any other characters.
+ * They are used for (re)composition in NF*C.
+ * Values of combining indexes are arranged according to whether a character
+ * combines forward, backward, or both ways:
+ *    forward-only < both ways < backward-only
+ *
+ * The index values for forward-only and both-ways combining characters
+ * are indexes into the combiningTable[].
+ * The index values for backward-only combining characters are simply
+ * incremented from the preceding index values to be unique.
+ *
+ * In the combiningTable[], a variable-length list
+ * of variable-length (back-index, code point) pair entries is stored
+ * for each forward-combining character.
+ *
+ * These back-indexes are the combining indexes of both-ways or backward-only
+ * combining characters that the forward-combining character combines with.
+ *
+ * Each list is sorted in ascending order of back-indexes.
+ * Each list is terminated with the last back-index having bit 15 set.
+ *
+ * Each pair (back-index, code point) takes up either 2 or 3
+ * 16-bit words.
+ * The first word of a list entry is the back-index, with its bit 15 set if
+ * this is the last pair in the list.
+ *
+ * The second word contains flags in bits 15..13 that determine
+ * if there is a third word and how the combined character is encoded:
+ * 15   set if there is a third word in this list entry
+ * 14   set if the result is a supplementary character
+ * 13   set if the result itself combines forward
+ *
+ * According to these bits 15..14 of the second word,
+ * the result character is encoded as follows:
+ * 00 or 01 The result is <=0x1fff and stored in bits 12..0 of
+ *          the second word.
+ * 10       The result is 0x2000..0xffff and stored in the third word.
+ *          Bits 12..0 of the second word are not used.
+ * 11       The result is a supplementary character.
+ *          Bits 9..0 of the leading surrogate are in bits 9..0 of
+ *          the second word.
+ *          Add 0xd800 to these bits to get the complete surrogate.
+ *          Bits 12..10 of the second word are not used.
+ *          The trailing surrogate is stored in the third word.
+ *
+ *
+ * - FCD trie
+ *
+ * The FCD trie is very simple.
+ * It is a folded trie with 16-bit data words.
+ * In each word, the high byte contains the leading cc of the character,
+ * and the low byte contains the trailing cc of the character.
+ * These cc's are the cc's of the first and last code points in the
+ * canonical decomposition of the character.
+ *
+ * Since all 16 bits are used for cc's, lead surrogates must be tested
+ * by checking the code unit instead of the trie data.
+ * This is done only if the 16-bit data word is not zero.
+ * If the code unit is a leading surrogate and the data word is not zero,
+ * then instead of cc's it contains the offset for the second trie lookup.
+ *
+ *
+ * - Auxiliary trie and data
+ *
+ * The auxiliary 16-bit trie contains data for additional properties.
+ * Bits
+ * 15..13   reserved
+ *     12   not NFC_Skippable (f) (formatVersion>=2.2)
+ *     11   flag: not a safe starter for canonical closure
+ *     10   composition exclusion
+ *  9.. 0   index into extraData[] to FC_NFKC_Closure string
+ *          (not for lead surrogate),
+ *          or lead surrogate offset (for lead surrogate, if 9..0 not zero)
+ *
+ * - FC_NFKC_Closure strings in extraData[]
+ *
+ * Strings are either stored as a single code unit or as the length
+ * followed by that many units.
+ *   const UChar *s=extraData+(index from auxTrie data bits 9..0);
+ *   int32_t length;
+ *   if(*s<0xff00) {
+ *     // s points to the single-unit string
+ *     length=1;
+ *   } else {
+ *     length=*s&0xff;
+ *     ++s;
+ *   }
+ *
+ * Conditions for "NF* Skippable" from Mark Davis' com.ibm.text.UCD.NFSkippable:
+ * (used in NormalizerTransliterator)
+ *
+ * A skippable character is
+ * a) unassigned, or ALL of the following:
+ * b) of combining class 0.
+ * c) not decomposed by this normalization form.
+ * AND if NFC or NFKC,
+ * d) can never compose with a previous character.
+ * e) can never compose with a following character.
+ * f) can never change if another character is added.
+ *    Example: a-breve might satisfy all but f, but if you
+ *    add an ogonek it changes to a-ogonek + breve
+ *
+ * a)..e) must be tested from norm32.
+ * Since f) is more complicated, the (not-)NFC_Skippable flag (f) is built
+ * into the auxiliary trie.
+ * The same bit is used for NFC and NFKC; (c) differs for them.
+ * As usual, we build the "not skippable" flags so that unassigned
+ * code points get a 0 bit.
+ * This bit is only valid after (a)..(e) test FALSE; test NFD_NO before (f) as well.
+ * Test Hangul LV syllables entirely in code.
+ *
+ *
+ * - structure inside canonStartSets[]
+ *
+ * This array maps from code points c to sets of code points (USerializedSet).
+ * The result sets are the code points whose canonical decompositions start
+ * with c.
+ *
+ * canonStartSets[] contains the following sub-arrays:
+ *
+ * indexes[_NORM_SET_INDEX_TOP]
+ *   - contains lengths of sub-arrays etc.
+ *
+ * startSets[indexes[_NORM_SET_INDEX_CANON_SETS_LENGTH]-_NORM_SET_INDEX_TOP]
+ *   - contains serialized sets (USerializedSet) of canonical starters for
+ *     enumerating canonically equivalent strings
+ *     indexes[_NORM_SET_INDEX_CANON_SETS_LENGTH] includes _NORM_SET_INDEX_TOP
+ *     for details about the structure see uset.c
+ *
+ * bmpTable[indexes[_NORM_SET_INDEX_CANON_BMP_TABLE_LENGTH]]
+ *   - a sorted search table for BMP code points whose results are
+ *     either indexes to USerializedSets or single code points for
+ *     single-code point sets;
+ *     each entry is a pair of { code point, result } with result=(binary) yy xxxxxx xxxxxxxx
+ *     if yy==01 then there is a USerializedSet at canonStartSets+x
+ *     else build a USerializedSet with result as the single code point
+ *
+ * suppTable[indexes[_NORM_SET_INDEX_CANON_SUPP_TABLE_LENGTH]]
+ *   - a sorted search table for supplementary code points whose results are
+ *     either indexes to USerializedSets or single code points for
+ *     single-code point sets;
+ *     each entry is a triplet of { high16(cp), low16(cp), result }
+ *     each code point's high-word may contain extra data in bits 15..5:
+ *     if the high word has bit 15 set, then build a set with a single code point
+ *     which is (((high16(cp)&0x1f00)<<8)|result;
+ *     else there is a USerializedSet at canonStartSets+result
+ *
+ * FormatVersion 2.3 adds 2 serialized sets for normalization exclusions.
+ * They are stored in the data file so that the runtime normalization code need
+ * not depend on other properties and their data and implementation files.
+ * The _NORM_SET_INDEX_NX_..._OFFSET offsets in the canonStartSets index table
+ * give the location for each set.
+ * There is no set stored for UNORM_NX_HANGUL because it's trivial to create
+ * without using properties.
+ *
+ * Set contents:
+ *
+ * _NORM_SET_INDEX_NX_CJK_COMPAT_OFFSET (for UNORM_NX_CJK_COMPAT)
+ *     [[:Ideographic:]&[:NFD_QC=No:]]
+ *     =[CJK Ideographs]&[has canonical decomposition]
+ *
+ * _NORM_SET_INDEX_NX_UNICODE32_OFFSET (for UNORM_UNICODE_3_2)
+ *     [:^Age=3.2:]
+ *     =set with all code points that were not designated by the specified Unicode version
+ *
+ * _NORM_SET_INDEX_NX_RESERVED_OFFSET
+ *     This is an offset that points to where the next, future set would start.
+ *     Currently it indicates where the previous set ends, and thus its length.
+ *     The name for this enum constant may in the future be applied to different
+ *     index slots. In order to get the limit of a set, use its index slot and
+ *     the immediately following one regardless of that one's enum name.
+ */
+
+#endif /* #if !UCONFIG_NO_NORMALIZATION */
+
+#endif
diff --git a/source/common/uobject.cpp b/source/common/uobject.cpp
new file mode 100644
index 0000000..515e943
--- /dev/null
+++ b/source/common/uobject.cpp
@@ -0,0 +1,114 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2002-2008, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  uobject.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002jun26
+*   created by: Markus W. Scherer
+*/
+
+#include "unicode/uobject.h"
+#include "cmemory.h"
+
+U_NAMESPACE_BEGIN
+
+#if U_OVERRIDE_CXX_ALLOCATION
+
+/*
+ * Default implementation of UMemory::new/delete
+ * using uprv_malloc() and uprv_free().
+ *
+ * For testing, this is used together with a list of imported symbols to verify
+ * that ICU is not using the global ::new and ::delete operators.
+ *
+ * These operators can be implemented like this or any other appropriate way
+ * when customizing ICU for certain environments.
+ * Whenever ICU is customized in binary incompatible ways please be sure
+ * to use library name suffixes to distinguish such libraries from
+ * the standard build.
+ *
+ * Instead of just modifying these C++ new/delete operators, it is usually best
+ * to modify the uprv_malloc()/uprv_free()/uprv_realloc() functions in cmemory.c.
+ *
+ * Memory test on Windows/MSVC 6:
+ * The global operators new and delete look as follows:
+ *   04F 00000000 UNDEF  notype ()    External     | ??2@YAPAXI@Z (void * __cdecl operator new(unsigned int))
+ *   03F 00000000 UNDEF  notype ()    External     | ??3@YAXPAX@Z (void __cdecl operator delete(void *))
+ *
+ * These lines are from output generated by the MSVC 6 tool dumpbin with
+ * dumpbin /symbols *.obj
+ *
+ * ??2@YAPAXI@Z and ??3@YAXPAX@Z are the linker symbols in the .obj
+ * files and are imported from msvcrtd.dll (in a debug build).
+ *
+ * Make sure that with the UMemory operators new and delete defined these two symbols
+ * do not appear in the dumpbin /symbols output for the ICU libraries!
+ *
+ * If such a symbol appears in the output then look in the preceding lines in the output
+ * for which file and function calls the global new or delete operator,
+ * and replace with uprv_malloc/uprv_free.
+ */
+
+void * U_EXPORT2 UMemory::operator new(size_t size) U_NO_THROW {
+    return uprv_malloc(size);
+}
+
+void U_EXPORT2 UMemory::operator delete(void *p) U_NO_THROW {
+    if(p!=NULL) {
+        uprv_free(p);
+    }
+}
+
+void * U_EXPORT2 UMemory::operator new[](size_t size) U_NO_THROW {
+    return uprv_malloc(size);
+}
+
+void U_EXPORT2 UMemory::operator delete[](void *p) U_NO_THROW {
+    if(p!=NULL) {
+        uprv_free(p);
+    }
+}
+
+#if U_HAVE_DEBUG_LOCATION_NEW
+void * U_EXPORT2 UMemory::operator new(size_t size, const char* /*file*/, int /*line*/) U_NO_THROW {
+    return UMemory::operator new(size);
+}
+
+void U_EXPORT2 UMemory::operator delete(void* p, const char* /*file*/, int /*line*/) U_NO_THROW {
+    UMemory::operator delete(p);
+}
+#endif /* U_HAVE_DEBUG_LOCATION_NEW */
+
+
+#endif
+
+UObject::~UObject() {}
+
+// Future implementation for RTTI that support subtyping. [alan]
+// 
+// UClassID UObject::getStaticClassID() {
+//     return (UClassID) NULL;
+// }
+// 
+// UBool UObject::instanceOf(UClassID type) const {
+//     UClassID c = getDynamicClassID();
+//     for (;;) {
+//         if (c == type) {
+//             return TRUE;
+//         } else if (c == (UClassID) NULL) {
+//             return FALSE;
+//         }
+//         c = * (UClassID*) c;
+//     }
+// }
+
+U_NAMESPACE_END
+
+
diff --git a/source/common/uprops.cpp b/source/common/uprops.cpp
new file mode 100644
index 0000000..81818b7
--- /dev/null
+++ b/source/common/uprops.cpp
@@ -0,0 +1,630 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2002-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  uprops.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002feb24
+*   created by: Markus W. Scherer
+*
+*   Implementations for mostly non-core Unicode character properties
+*   stored in uprops.icu.
+*
+*   With the APIs implemented here, almost all properties files and
+*   their associated implementation files are used from this file,
+*   including those for normalization and case mappings.
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uchar.h"
+#include "unicode/unorm2.h"
+#include "unicode/uscript.h"
+#include "unicode/ustring.h"
+#include "cstring.h"
+#include "normalizer2impl.h"
+#include "ucln_cmn.h"
+#include "umutex.h"
+#include "ubidi_props.h"
+#include "uprops.h"
+#include "ucase.h"
+#include "ustr_imp.h"
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+U_NAMESPACE_USE
+
+#define GET_BIDI_PROPS() ubidi_getSingleton()
+
+/* general properties API functions ----------------------------------------- */
+
+struct BinaryProperty;
+
+typedef UBool BinaryPropertyContains(const BinaryProperty &prop, UChar32 c, UProperty which);
+
+struct BinaryProperty {
+    int32_t column;  // SRC_PROPSVEC column, or "source" if mask==0
+    uint32_t mask;
+    BinaryPropertyContains *contains;
+};
+
+static UBool defaultContains(const BinaryProperty &prop, UChar32 c, UProperty /*which*/) {
+    /* systematic, directly stored properties */
+    return (u_getUnicodeProperties(c, prop.column)&prop.mask)!=0;
+}
+
+static UBool caseBinaryPropertyContains(const BinaryProperty &/*prop*/, UChar32 c, UProperty which) {
+    return ucase_hasBinaryProperty(c, which);
+}
+
+static UBool isBidiControl(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    return ubidi_isBidiControl(GET_BIDI_PROPS(), c);
+}
+
+static UBool isMirrored(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    return ubidi_isMirrored(GET_BIDI_PROPS(), c);
+}
+
+static UBool isJoinControl(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    return ubidi_isJoinControl(GET_BIDI_PROPS(), c);
+}
+
+#if UCONFIG_NO_NORMALIZATION
+static UBool hasFullCompositionExclusion(const BinaryProperty &, UChar32, UProperty) {
+    return FALSE;
+}
+#else
+static UBool hasFullCompositionExclusion(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    // By definition, Full_Composition_Exclusion is the same as NFC_QC=No.
+    UErrorCode errorCode=U_ZERO_ERROR;
+    const Normalizer2Impl *impl=Normalizer2Factory::getNFCImpl(errorCode);
+    return U_SUCCESS(errorCode) && impl->isCompNo(impl->getNorm16(c));
+}
+#endif
+
+// UCHAR_NF*_INERT properties
+#if UCONFIG_NO_NORMALIZATION
+static UBool isNormInert(const BinaryProperty &, UChar32, UProperty) {
+    return FALSE;
+}
+#else
+static UBool isNormInert(const BinaryProperty &/*prop*/, UChar32 c, UProperty which) {
+    UErrorCode errorCode=U_ZERO_ERROR;
+    const Normalizer2 *norm2=Normalizer2Factory::getInstance(
+        (UNormalizationMode)(which-UCHAR_NFD_INERT+UNORM_NFD), errorCode);
+    return U_SUCCESS(errorCode) && norm2->isInert(c);
+}
+#endif
+
+#if UCONFIG_NO_NORMALIZATION
+static UBool changesWhenCasefolded(const BinaryProperty &, UChar32, UProperty) {
+    return FALSE;
+}
+#else
+static UBool changesWhenCasefolded(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    UnicodeString nfd;
+    UErrorCode errorCode=U_ZERO_ERROR;
+    const Normalizer2 *nfcNorm2=Normalizer2Factory::getNFCInstance(errorCode);
+    if(U_FAILURE(errorCode)) {
+        return FALSE;
+    }
+    if(nfcNorm2->getDecomposition(c, nfd)) {
+        /* c has a decomposition */
+        if(nfd.length()==1) {
+            c=nfd[0];  /* single BMP code point */
+        } else if(nfd.length()<=U16_MAX_LENGTH &&
+                  nfd.length()==U16_LENGTH(c=nfd.char32At(0))
+        ) {
+            /* single supplementary code point */
+        } else {
+            c=U_SENTINEL;
+        }
+    } else if(c<0) {
+        return FALSE;  /* protect against bad input */
+    }
+    if(c>=0) {
+        /* single code point */
+        const UCaseProps *csp=ucase_getSingleton();
+        const UChar *resultString;
+        return (UBool)(ucase_toFullFolding(csp, c, &resultString, U_FOLD_CASE_DEFAULT)>=0);
+    } else {
+        /* guess some large but stack-friendly capacity */
+        UChar dest[2*UCASE_MAX_STRING_LENGTH];
+        int32_t destLength;
+        destLength=u_strFoldCase(dest, LENGTHOF(dest),
+                                  nfd.getBuffer(), nfd.length(),
+                                  U_FOLD_CASE_DEFAULT, &errorCode);
+        return (UBool)(U_SUCCESS(errorCode) &&
+                       0!=u_strCompare(nfd.getBuffer(), nfd.length(),
+                                       dest, destLength, FALSE));
+    }
+}
+#endif
+
+#if UCONFIG_NO_NORMALIZATION
+static UBool changesWhenNFKC_Casefolded(const BinaryProperty &, UChar32, UProperty) {
+    return FALSE;
+}
+#else
+static UBool changesWhenNFKC_Casefolded(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    UErrorCode errorCode=U_ZERO_ERROR;
+    const Normalizer2Impl *kcf=Normalizer2Factory::getNFKC_CFImpl(errorCode);
+    if(U_FAILURE(errorCode)) {
+        return FALSE;
+    }
+    UnicodeString src(c);
+    UnicodeString dest;
+    {
+        // The ReorderingBuffer must be in a block because its destructor
+        // needs to release dest's buffer before we look at its contents.
+        ReorderingBuffer buffer(*kcf, dest);
+        // Small destCapacity for NFKC_CF(c).
+        if(buffer.init(5, errorCode)) {
+            const UChar *srcArray=src.getBuffer();
+            kcf->compose(srcArray, srcArray+src.length(), FALSE,
+                          TRUE, buffer, errorCode);
+        }
+    }
+    return U_SUCCESS(errorCode) && dest!=src;
+}
+#endif
+
+#if UCONFIG_NO_NORMALIZATION
+static UBool isCanonSegmentStarter(const BinaryProperty &, UChar32, UProperty) {
+    return FALSE;
+}
+#else
+static UBool isCanonSegmentStarter(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    UErrorCode errorCode=U_ZERO_ERROR;
+    const Normalizer2Impl *impl=Normalizer2Factory::getNFCImpl(errorCode);
+    return
+        U_SUCCESS(errorCode) && impl->ensureCanonIterData(errorCode) &&
+        impl->isCanonSegmentStarter(c);
+}
+#endif
+
+static UBool isPOSIX_alnum(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    return u_isalnumPOSIX(c);
+}
+
+static UBool isPOSIX_blank(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    return u_isblank(c);
+}
+
+static UBool isPOSIX_graph(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    return u_isgraphPOSIX(c);
+}
+
+static UBool isPOSIX_print(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    return u_isprintPOSIX(c);
+}
+
+static UBool isPOSIX_xdigit(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    return u_isxdigit(c);
+}
+
+static const BinaryProperty binProps[UCHAR_BINARY_LIMIT]={
+    /*
+     * column and mask values for binary properties from u_getUnicodeProperties().
+     * Must be in order of corresponding UProperty,
+     * and there must be exactly one entry per binary UProperty.
+     *
+     * Properties with mask==0 and contains==NULL are handled in code.
+     * For them, column is the UPropertySource value.
+     */
+    { 1,                U_MASK(UPROPS_ALPHABETIC), defaultContains },
+    { 1,                U_MASK(UPROPS_ASCII_HEX_DIGIT), defaultContains },
+    { UPROPS_SRC_BIDI,  0, isBidiControl },
+    { UPROPS_SRC_BIDI,  0, isMirrored },
+    { 1,                U_MASK(UPROPS_DASH), defaultContains },
+    { 1,                U_MASK(UPROPS_DEFAULT_IGNORABLE_CODE_POINT), defaultContains },
+    { 1,                U_MASK(UPROPS_DEPRECATED), defaultContains },
+    { 1,                U_MASK(UPROPS_DIACRITIC), defaultContains },
+    { 1,                U_MASK(UPROPS_EXTENDER), defaultContains },
+    { UPROPS_SRC_NFC,   0, hasFullCompositionExclusion },
+    { 1,                U_MASK(UPROPS_GRAPHEME_BASE), defaultContains },
+    { 1,                U_MASK(UPROPS_GRAPHEME_EXTEND), defaultContains },
+    { 1,                U_MASK(UPROPS_GRAPHEME_LINK), defaultContains },
+    { 1,                U_MASK(UPROPS_HEX_DIGIT), defaultContains },
+    { 1,                U_MASK(UPROPS_HYPHEN), defaultContains },
+    { 1,                U_MASK(UPROPS_ID_CONTINUE), defaultContains },
+    { 1,                U_MASK(UPROPS_ID_START), defaultContains },
+    { 1,                U_MASK(UPROPS_IDEOGRAPHIC), defaultContains },
+    { 1,                U_MASK(UPROPS_IDS_BINARY_OPERATOR), defaultContains },
+    { 1,                U_MASK(UPROPS_IDS_TRINARY_OPERATOR), defaultContains },
+    { UPROPS_SRC_BIDI,  0, isJoinControl },
+    { 1,                U_MASK(UPROPS_LOGICAL_ORDER_EXCEPTION), defaultContains },
+    { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_LOWERCASE
+    { 1,                U_MASK(UPROPS_MATH), defaultContains },
+    { 1,                U_MASK(UPROPS_NONCHARACTER_CODE_POINT), defaultContains },
+    { 1,                U_MASK(UPROPS_QUOTATION_MARK), defaultContains },
+    { 1,                U_MASK(UPROPS_RADICAL), defaultContains },
+    { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_SOFT_DOTTED
+    { 1,                U_MASK(UPROPS_TERMINAL_PUNCTUATION), defaultContains },
+    { 1,                U_MASK(UPROPS_UNIFIED_IDEOGRAPH), defaultContains },
+    { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_UPPERCASE
+    { 1,                U_MASK(UPROPS_WHITE_SPACE), defaultContains },
+    { 1,                U_MASK(UPROPS_XID_CONTINUE), defaultContains },
+    { 1,                U_MASK(UPROPS_XID_START), defaultContains },
+    { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_CASE_SENSITIVE
+    { 1,                U_MASK(UPROPS_S_TERM), defaultContains },
+    { 1,                U_MASK(UPROPS_VARIATION_SELECTOR), defaultContains },
+    { UPROPS_SRC_NFC,   0, isNormInert },  // UCHAR_NFD_INERT
+    { UPROPS_SRC_NFKC,  0, isNormInert },  // UCHAR_NFKD_INERT
+    { UPROPS_SRC_NFC,   0, isNormInert },  // UCHAR_NFC_INERT
+    { UPROPS_SRC_NFKC,  0, isNormInert },  // UCHAR_NFKC_INERT
+    { UPROPS_SRC_NFC_CANON_ITER, 0, isCanonSegmentStarter },
+    { 1,                U_MASK(UPROPS_PATTERN_SYNTAX), defaultContains },
+    { 1,                U_MASK(UPROPS_PATTERN_WHITE_SPACE), defaultContains },
+    { UPROPS_SRC_CHAR_AND_PROPSVEC,  0, isPOSIX_alnum },
+    { UPROPS_SRC_CHAR,  0, isPOSIX_blank },
+    { UPROPS_SRC_CHAR,  0, isPOSIX_graph },
+    { UPROPS_SRC_CHAR,  0, isPOSIX_print },
+    { UPROPS_SRC_CHAR,  0, isPOSIX_xdigit },
+    { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_CASED
+    { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_CASE_IGNORABLE
+    { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_CHANGES_WHEN_LOWERCASED
+    { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_CHANGES_WHEN_UPPERCASED
+    { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_CHANGES_WHEN_TITLECASED
+    { UPROPS_SRC_CASE_AND_NORM,  0, changesWhenCasefolded },
+    { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_CHANGES_WHEN_CASEMAPPED
+    { UPROPS_SRC_NFKC_CF, 0, changesWhenNFKC_Casefolded }
+};
+
+U_CAPI UBool U_EXPORT2
+u_hasBinaryProperty(UChar32 c, UProperty which) {
+    /* c is range-checked in the functions that are called from here */
+    if(which<UCHAR_BINARY_START || UCHAR_BINARY_LIMIT<=which) {
+        /* not a known binary property */
+        return FALSE;
+    } else {
+        const BinaryProperty &prop=binProps[which];
+        return prop.contains(prop, c, which);
+    }
+}
+
+#if !UCONFIG_NO_NORMALIZATION
+
+U_CAPI uint8_t U_EXPORT2
+u_getCombiningClass(UChar32 c) {
+    UErrorCode errorCode=U_ZERO_ERROR;
+    const Normalizer2Impl *impl=Normalizer2Factory::getNFCImpl(errorCode);
+    if(U_SUCCESS(errorCode)) {
+        return impl->getCC(impl->getNorm16(c));
+    } else {
+        return 0;
+    }
+}
+
+static uint16_t
+getFCD16(UChar32 c) {
+    UErrorCode errorCode=U_ZERO_ERROR;
+    const UTrie2 *trie=Normalizer2Factory::getFCDTrie(errorCode);
+    if(U_SUCCESS(errorCode)) {
+        return UTRIE2_GET16(trie, c);
+    } else {
+        return 0;
+    }
+}
+
+#endif
+
+struct IntProperty;
+
+typedef int32_t IntPropertyGetValue(const IntProperty &prop, UChar32 c, UProperty which);
+typedef int32_t IntPropertyGetMaxValue(const IntProperty &prop, UProperty which);
+
+struct IntProperty {
+    int32_t column;  // SRC_PROPSVEC column, or "source" if mask==0
+    uint32_t mask;
+    int32_t shift;  // =maxValue if getMaxValueFromShift() is used
+    IntPropertyGetValue *getValue;
+    IntPropertyGetMaxValue *getMaxValue;
+};
+
+static int32_t defaultGetValue(const IntProperty &prop, UChar32 c, UProperty /*which*/) {
+    /* systematic, directly stored properties */
+    return (int32_t)(u_getUnicodeProperties(c, prop.column)&prop.mask)>>prop.shift;
+}
+
+static int32_t defaultGetMaxValue(const IntProperty &prop, UProperty /*which*/) {
+    return (uprv_getMaxValues(prop.column)&prop.mask)>>prop.shift;
+}
+
+static int32_t getMaxValueFromShift(const IntProperty &prop, UProperty /*which*/) {
+    return prop.shift;
+}
+
+static int32_t getBiDiClass(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    return (int32_t)u_charDirection(c);
+}
+
+static int32_t biDiGetMaxValue(const IntProperty &/*prop*/, UProperty which) {
+    return ubidi_getMaxValue(GET_BIDI_PROPS(), which);
+}
+
+#if UCONFIG_NO_NORMALIZATION
+static int32_t getCombiningClass(const IntProperty &, UChar32, UProperty) {
+    return 0;
+}
+#else
+static int32_t getCombiningClass(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    return u_getCombiningClass(c);
+}
+#endif
+
+static int32_t getGeneralCategory(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    return (int32_t)u_charType(c);
+}
+
+static int32_t getJoiningGroup(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    return ubidi_getJoiningGroup(GET_BIDI_PROPS(), c);
+}
+
+static int32_t getJoiningType(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    return ubidi_getJoiningType(GET_BIDI_PROPS(), c);
+}
+
+static int32_t getNumericType(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    int32_t ntv=(int32_t)GET_NUMERIC_TYPE_VALUE(u_getUnicodeProperties(c, -1));
+    return UPROPS_NTV_GET_TYPE(ntv);
+}
+
+static int32_t getScript(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    UErrorCode errorCode=U_ZERO_ERROR;
+    return (int32_t)uscript_getScript(c, &errorCode);
+}
+
+/*
+ * Map some of the Grapheme Cluster Break values to Hangul Syllable Types.
+ * Hangul_Syllable_Type is fully redundant with a subset of Grapheme_Cluster_Break.
+ */
+static const UHangulSyllableType gcbToHst[]={
+    U_HST_NOT_APPLICABLE,   /* U_GCB_OTHER */
+    U_HST_NOT_APPLICABLE,   /* U_GCB_CONTROL */
+    U_HST_NOT_APPLICABLE,   /* U_GCB_CR */
+    U_HST_NOT_APPLICABLE,   /* U_GCB_EXTEND */
+    U_HST_LEADING_JAMO,     /* U_GCB_L */
+    U_HST_NOT_APPLICABLE,   /* U_GCB_LF */
+    U_HST_LV_SYLLABLE,      /* U_GCB_LV */
+    U_HST_LVT_SYLLABLE,     /* U_GCB_LVT */
+    U_HST_TRAILING_JAMO,    /* U_GCB_T */
+    U_HST_VOWEL_JAMO        /* U_GCB_V */
+    /*
+     * Omit GCB values beyond what we need for hst.
+     * The code below checks for the array length.
+     */
+};
+
+static int32_t getHangulSyllableType(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    /* see comments on gcbToHst[] above */
+    int32_t gcb=(int32_t)(u_getUnicodeProperties(c, 2)&UPROPS_GCB_MASK)>>UPROPS_GCB_SHIFT;
+    if(gcb<LENGTHOF(gcbToHst)) {
+        return gcbToHst[gcb];
+    } else {
+        return U_HST_NOT_APPLICABLE;
+    }
+}
+
+#if UCONFIG_NO_NORMALIZATION
+static int32_t getNormQuickCheck(const IntProperty &, UChar32, UProperty) {
+    return 0;
+}
+#else
+static int32_t getNormQuickCheck(const IntProperty &/*prop*/, UChar32 c, UProperty which) {
+    return (int32_t)unorm_getQuickCheck(c, (UNormalizationMode)(which-UCHAR_NFD_QUICK_CHECK+UNORM_NFD));
+}
+#endif
+
+#if UCONFIG_NO_NORMALIZATION
+static int32_t getLeadCombiningClass(const IntProperty &, UChar32, UProperty) {
+    return 0;
+}
+#else
+static int32_t getLeadCombiningClass(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    return getFCD16(c)>>8;
+}
+#endif
+
+#if UCONFIG_NO_NORMALIZATION
+static int32_t getTrailCombiningClass(const IntProperty &, UChar32, UProperty) {
+    return 0;
+}
+#else
+static int32_t getTrailCombiningClass(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    return getFCD16(c)&0xff;
+}
+#endif
+
+static const IntProperty intProps[UCHAR_INT_LIMIT-UCHAR_INT_START]={
+    /*
+     * column, mask and shift values for int-value properties from u_getUnicodeProperties().
+     * Must be in order of corresponding UProperty,
+     * and there must be exactly one entry per int UProperty.
+     *
+     * Properties with mask==0 and getValue==NULL are handled in code.
+     * For them, column is the UPropertySource value.
+     */
+    { UPROPS_SRC_BIDI,  0, 0,                               getBiDiClass, biDiGetMaxValue },
+    { 0,                UPROPS_BLOCK_MASK, UPROPS_BLOCK_SHIFT, defaultGetValue, defaultGetMaxValue },
+    { UPROPS_SRC_NFC,   0, 0xff,                            getCombiningClass, getMaxValueFromShift },
+    { 2,                UPROPS_DT_MASK, 0,                  defaultGetValue, defaultGetMaxValue },
+    { 0,                UPROPS_EA_MASK, UPROPS_EA_SHIFT,    defaultGetValue, defaultGetMaxValue },
+    { UPROPS_SRC_CHAR,  0, (int32_t)U_CHAR_CATEGORY_COUNT-1,getGeneralCategory, getMaxValueFromShift },
+    { UPROPS_SRC_BIDI,  0, 0,                               getJoiningGroup, biDiGetMaxValue },
+    { UPROPS_SRC_BIDI,  0, 0,                               getJoiningType, biDiGetMaxValue },
+    { 2,                UPROPS_LB_MASK, UPROPS_LB_SHIFT,    defaultGetValue, defaultGetMaxValue },
+    { UPROPS_SRC_CHAR,  0, (int32_t)U_NT_COUNT-1,           getNumericType, getMaxValueFromShift },
+    { 0,                UPROPS_SCRIPT_MASK, 0,              getScript, defaultGetMaxValue },
+    { UPROPS_SRC_PROPSVEC, 0, (int32_t)U_HST_COUNT-1,       getHangulSyllableType, getMaxValueFromShift },
+    // UCHAR_NFD_QUICK_CHECK: max=1=YES -- never "maybe", only "no" or "yes"
+    { UPROPS_SRC_NFC,   0, (int32_t)UNORM_YES,              getNormQuickCheck, getMaxValueFromShift },
+    // UCHAR_NFKD_QUICK_CHECK: max=1=YES -- never "maybe", only "no" or "yes"
+    { UPROPS_SRC_NFKC,  0, (int32_t)UNORM_YES,              getNormQuickCheck, getMaxValueFromShift },
+    // UCHAR_NFC_QUICK_CHECK: max=2=MAYBE
+    { UPROPS_SRC_NFC,   0, (int32_t)UNORM_MAYBE,            getNormQuickCheck, getMaxValueFromShift },
+    // UCHAR_NFKC_QUICK_CHECK: max=2=MAYBE
+    { UPROPS_SRC_NFKC,  0, (int32_t)UNORM_MAYBE,            getNormQuickCheck, getMaxValueFromShift },
+    { UPROPS_SRC_NFC,   0, 0xff,                            getLeadCombiningClass, getMaxValueFromShift },
+    { UPROPS_SRC_NFC,   0, 0xff,                            getTrailCombiningClass, getMaxValueFromShift },
+    { 2,                UPROPS_GCB_MASK, UPROPS_GCB_SHIFT,  defaultGetValue, defaultGetMaxValue },
+    { 2,                UPROPS_SB_MASK, UPROPS_SB_SHIFT,    defaultGetValue, defaultGetMaxValue },
+    { 2,                UPROPS_WB_MASK, UPROPS_WB_SHIFT,    defaultGetValue, defaultGetMaxValue }
+};
+
+U_CAPI int32_t U_EXPORT2
+u_getIntPropertyValue(UChar32 c, UProperty which) {
+    if(which<UCHAR_INT_START) {
+        if(UCHAR_BINARY_START<=which && which<UCHAR_BINARY_LIMIT) {
+            const BinaryProperty &prop=binProps[which];
+            return prop.contains(prop, c, which);
+        }
+    } else if(which<UCHAR_INT_LIMIT) {
+        const IntProperty &prop=intProps[which-UCHAR_INT_START];
+        return prop.getValue(prop, c, which);
+    } else if(which==UCHAR_GENERAL_CATEGORY_MASK) {
+        return U_MASK(u_charType(c));
+    }
+    return 0;  // undefined
+}
+
+U_CAPI int32_t U_EXPORT2
+u_getIntPropertyMinValue(UProperty /*which*/) {
+    return 0; /* all binary/enum/int properties have a minimum value of 0 */
+}
+
+U_CAPI int32_t U_EXPORT2
+u_getIntPropertyMaxValue(UProperty which) {
+    if(which<UCHAR_INT_START) {
+        if(UCHAR_BINARY_START<=which && which<UCHAR_BINARY_LIMIT) {
+            return 1;  // maximum TRUE for all binary properties
+        }
+    } else if(which<UCHAR_INT_LIMIT) {
+        const IntProperty &prop=intProps[which-UCHAR_INT_START];
+        return prop.getMaxValue(prop, which);
+    }
+    return -1;  // undefined
+}
+
+U_CFUNC UPropertySource U_EXPORT2
+uprops_getSource(UProperty which) {
+    if(which<UCHAR_BINARY_START) {
+        return UPROPS_SRC_NONE; /* undefined */
+    } else if(which<UCHAR_BINARY_LIMIT) {
+        const BinaryProperty &prop=binProps[which];
+        if(prop.mask!=0) {
+            return UPROPS_SRC_PROPSVEC;
+        } else {
+            return (UPropertySource)prop.column;
+        }
+    } else if(which<UCHAR_INT_START) {
+        return UPROPS_SRC_NONE; /* undefined */
+    } else if(which<UCHAR_INT_LIMIT) {
+        const IntProperty &prop=intProps[which-UCHAR_INT_START];
+        if(prop.mask!=0) {
+            return UPROPS_SRC_PROPSVEC;
+        } else {
+            return (UPropertySource)prop.column;
+        }
+    } else if(which<UCHAR_STRING_START) {
+        switch(which) {
+        case UCHAR_GENERAL_CATEGORY_MASK:
+        case UCHAR_NUMERIC_VALUE:
+            return UPROPS_SRC_CHAR;
+
+        default:
+            return UPROPS_SRC_NONE;
+        }
+    } else if(which<UCHAR_STRING_LIMIT) {
+        switch(which) {
+        case UCHAR_AGE:
+            return UPROPS_SRC_PROPSVEC;
+
+        case UCHAR_BIDI_MIRRORING_GLYPH:
+            return UPROPS_SRC_BIDI;
+
+        case UCHAR_CASE_FOLDING:
+        case UCHAR_LOWERCASE_MAPPING:
+        case UCHAR_SIMPLE_CASE_FOLDING:
+        case UCHAR_SIMPLE_LOWERCASE_MAPPING:
+        case UCHAR_SIMPLE_TITLECASE_MAPPING:
+        case UCHAR_SIMPLE_UPPERCASE_MAPPING:
+        case UCHAR_TITLECASE_MAPPING:
+        case UCHAR_UPPERCASE_MAPPING:
+            return UPROPS_SRC_CASE;
+
+        case UCHAR_ISO_COMMENT:
+        case UCHAR_NAME:
+        case UCHAR_UNICODE_1_NAME:
+            return UPROPS_SRC_NAMES;
+
+        default:
+            return UPROPS_SRC_NONE;
+        }
+    } else {
+        switch(which) {
+        case UCHAR_SCRIPT_EXTENSIONS:
+            return UPROPS_SRC_PROPSVEC;
+        default:
+            return UPROPS_SRC_NONE; /* undefined */
+        }
+    }
+}
+
+#if !UCONFIG_NO_NORMALIZATION
+
+U_CAPI int32_t U_EXPORT2
+u_getFC_NFKC_Closure(UChar32 c, UChar *dest, int32_t destCapacity, UErrorCode *pErrorCode) {
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(destCapacity<0 || (dest==NULL && destCapacity>0)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    // Compute the FC_NFKC_Closure on the fly:
+    // We have the API for complete coverage of Unicode properties, although
+    // this value by itself is not useful via API.
+    // (What could be useful is a custom normalization table that combines
+    // case folding and NFKC.)
+    // For the derivation, see Unicode's DerivedNormalizationProps.txt.
+    const Normalizer2 *nfkc=Normalizer2Factory::getNFKCInstance(*pErrorCode);
+    const UCaseProps *csp=ucase_getSingleton();
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    // first: b = NFKC(Fold(a))
+    UnicodeString folded1String;
+    const UChar *folded1;
+    int32_t folded1Length=ucase_toFullFolding(csp, c, &folded1, U_FOLD_CASE_DEFAULT);
+    if(folded1Length<0) {
+        const Normalizer2Impl *nfkcImpl=Normalizer2Factory::getImpl(nfkc);
+        if(nfkcImpl->getCompQuickCheck(nfkcImpl->getNorm16(c))!=UNORM_NO) {
+            return u_terminateUChars(dest, destCapacity, 0, pErrorCode);  // c does not change at all under CaseFolding+NFKC
+        }
+        folded1String.setTo(c);
+    } else {
+        if(folded1Length>UCASE_MAX_STRING_LENGTH) {
+            folded1String.setTo(folded1Length);
+        } else {
+            folded1String.setTo(FALSE, folded1, folded1Length);
+        }
+    }
+    UnicodeString kc1=nfkc->normalize(folded1String, *pErrorCode);
+    // second: c = NFKC(Fold(b))
+    UnicodeString folded2String(kc1);
+    UnicodeString kc2=nfkc->normalize(folded2String.foldCase(), *pErrorCode);
+    // if (c != b) add the mapping from a to c
+    if(U_FAILURE(*pErrorCode) || kc1==kc2) {
+        return u_terminateUChars(dest, destCapacity, 0, pErrorCode);
+    } else {
+        return kc2.extract(dest, destCapacity, *pErrorCode);
+    }
+}
+
+#endif
diff --git a/source/common/uprops.h b/source/common/uprops.h
new file mode 100644
index 0000000..43f18af
--- /dev/null
+++ b/source/common/uprops.h
@@ -0,0 +1,432 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2002-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  uprops.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002feb24
+*   created by: Markus W. Scherer
+*
+*   Constants for mostly non-core Unicode character properties
+*   stored in uprops.icu.
+*/
+
+#ifndef __UPROPS_H__
+#define __UPROPS_H__
+
+#include "unicode/utypes.h"
+#include "unicode/uset.h"
+#include "uset_imp.h"
+#include "udataswp.h"
+
+/* indexes[] entries */
+enum {
+    UPROPS_PROPS32_INDEX,
+    UPROPS_EXCEPTIONS_INDEX,
+    UPROPS_EXCEPTIONS_TOP_INDEX,
+
+    UPROPS_ADDITIONAL_TRIE_INDEX,
+    UPROPS_ADDITIONAL_VECTORS_INDEX,
+    UPROPS_ADDITIONAL_VECTORS_COLUMNS_INDEX,
+
+    UPROPS_SCRIPT_EXTENSIONS_INDEX,
+
+    UPROPS_RESERVED_INDEX_7,
+    UPROPS_RESERVED_INDEX_8,
+
+    /* size of the data file (number of 32-bit units after the header) */
+    UPROPS_DATA_TOP_INDEX,
+
+    /* maximum values for code values in vector word 0 */
+    UPROPS_MAX_VALUES_INDEX=10,
+    /* maximum values for code values in vector word 2 */
+    UPROPS_MAX_VALUES_2_INDEX,
+
+    UPROPS_INDEX_COUNT=16
+};
+
+/* definitions for the main properties words */
+enum {
+    /* general category shift==0                                0 (5 bits) */
+    /* reserved                                                 5 (1 bit) */
+    UPROPS_NUMERIC_TYPE_VALUE_SHIFT=6                       /*  6 (10 bits) */
+};
+
+#define GET_CATEGORY(props) ((props)&0x1f)
+#define CAT_MASK(props) U_MASK(GET_CATEGORY(props))
+
+#define GET_NUMERIC_TYPE_VALUE(props) ((props)>>UPROPS_NUMERIC_TYPE_VALUE_SHIFT)
+
+/* constants for the storage form of numeric types and values */
+enum {
+    UPROPS_NTV_NONE=0,
+    UPROPS_NTV_DECIMAL_START=1,
+    UPROPS_NTV_DIGIT_START=11,
+    UPROPS_NTV_NUMERIC_START=21,
+    UPROPS_NTV_FRACTION_START=0xb0,
+    UPROPS_NTV_LARGE_START=0x1e0,
+    UPROPS_NTV_RESERVED_START=0x300,
+
+    UPROPS_NTV_MAX_SMALL_INT=UPROPS_NTV_FRACTION_START-UPROPS_NTV_NUMERIC_START-1
+};
+
+#define UPROPS_NTV_GET_TYPE(ntv) \
+    ((ntv==UPROPS_NTV_NONE) ? U_NT_NONE : \
+    (ntv<UPROPS_NTV_DIGIT_START) ?  U_NT_DECIMAL : \
+    (ntv<UPROPS_NTV_NUMERIC_START) ? U_NT_DIGIT : \
+    U_NT_NUMERIC)
+
+/* number of properties vector words */
+#define UPROPS_VECTOR_WORDS     3
+
+/*
+ * Properties in vector word 0
+ * Bits
+ * 31..24   DerivedAge version major/minor one nibble each
+ * 23..22   3..1: Bits 7..0 = Script_Extensions index
+ *             3: Script value from Script_Extensions
+ *             2: Script=Inherited
+ *             1: Script=Common
+ *             0: Script=bits 7..0
+ * 21..20   reserved
+ * 19..17   East Asian Width
+ * 16.. 8   UBlockCode
+ *  7.. 0   UScriptCode, or index to Script_Extensions
+ */
+
+/* derived age: one nibble each for major and minor version numbers */
+#define UPROPS_AGE_MASK         0xff000000
+#define UPROPS_AGE_SHIFT        24
+
+/* Script_Extensions: mask includes Script */
+#define UPROPS_SCRIPT_X_MASK    0x00c000ff
+#define UPROPS_SCRIPT_X_SHIFT   22
+
+#define UPROPS_EA_MASK          0x000e0000
+#define UPROPS_EA_SHIFT         17
+
+#define UPROPS_BLOCK_MASK       0x0001ff00
+#define UPROPS_BLOCK_SHIFT      8
+
+#define UPROPS_SCRIPT_MASK      0x000000ff
+
+/* UPROPS_SCRIPT_X_WITH_COMMON must be the lowest value that involves Script_Extensions. */
+#define UPROPS_SCRIPT_X_WITH_COMMON     0x400000
+#define UPROPS_SCRIPT_X_WITH_INHERITED  0x800000
+#define UPROPS_SCRIPT_X_WITH_OTHER      0xc00000
+
+/*
+ * Properties in vector word 1
+ * Each bit encodes one binary property.
+ * The following constants represent the bit number, use 1<<UPROPS_XYZ.
+ * UPROPS_BINARY_1_TOP<=32!
+ *
+ * Keep this list of property enums in sync with
+ * propListNames[] in icu/source/tools/genprops/props2.c!
+ *
+ * ICU 2.6/uprops format version 3.2 stores full properties instead of "Other_".
+ */
+enum {
+    UPROPS_WHITE_SPACE,
+    UPROPS_DASH,
+    UPROPS_HYPHEN,
+    UPROPS_QUOTATION_MARK,
+    UPROPS_TERMINAL_PUNCTUATION,
+    UPROPS_MATH,
+    UPROPS_HEX_DIGIT,
+    UPROPS_ASCII_HEX_DIGIT,
+    UPROPS_ALPHABETIC,
+    UPROPS_IDEOGRAPHIC,
+    UPROPS_DIACRITIC,
+    UPROPS_EXTENDER,
+    UPROPS_NONCHARACTER_CODE_POINT,
+    UPROPS_GRAPHEME_EXTEND,
+    UPROPS_GRAPHEME_LINK,
+    UPROPS_IDS_BINARY_OPERATOR,
+    UPROPS_IDS_TRINARY_OPERATOR,
+    UPROPS_RADICAL,
+    UPROPS_UNIFIED_IDEOGRAPH,
+    UPROPS_DEFAULT_IGNORABLE_CODE_POINT,
+    UPROPS_DEPRECATED,
+    UPROPS_LOGICAL_ORDER_EXCEPTION,
+    UPROPS_XID_START,
+    UPROPS_XID_CONTINUE,
+    UPROPS_ID_START,                            /* ICU 2.6, uprops format version 3.2 */
+    UPROPS_ID_CONTINUE,
+    UPROPS_GRAPHEME_BASE,
+    UPROPS_S_TERM,                              /* new in ICU 3.0 and Unicode 4.0.1 */
+    UPROPS_VARIATION_SELECTOR,
+    UPROPS_PATTERN_SYNTAX,                      /* new in ICU 3.4 and Unicode 4.1 */
+    UPROPS_PATTERN_WHITE_SPACE,
+    UPROPS_RESERVED,                            /* reserved & unused */
+    UPROPS_BINARY_1_TOP                         /* ==32 - full! */
+};
+
+/*
+ * Properties in vector word 2
+ * Bits
+ * 31..26   reserved
+ * 25..20   Line Break
+ * 19..15   Sentence Break
+ * 14..10   Word Break
+ *  9.. 5   Grapheme Cluster Break
+ *  4.. 0   Decomposition Type
+ */
+#define UPROPS_LB_MASK          0x03f00000
+#define UPROPS_LB_SHIFT         20
+
+#define UPROPS_SB_MASK          0x000f8000
+#define UPROPS_SB_SHIFT         15
+
+#define UPROPS_WB_MASK          0x00007c00
+#define UPROPS_WB_SHIFT         10
+
+#define UPROPS_GCB_MASK         0x000003e0
+#define UPROPS_GCB_SHIFT        5
+
+#define UPROPS_DT_MASK          0x0000001f
+
+/**
+ * Get a properties vector word for a code point.
+ * Implemented in uchar.c for uprops.c.
+ * column==-1 gets the 32-bit main properties word instead.
+ * @return 0 if no data or illegal argument
+ */
+U_CFUNC uint32_t
+u_getUnicodeProperties(UChar32 c, int32_t column);
+
+/**
+ * Get the the maximum values for some enum/int properties.
+ * Use the same column numbers as for u_getUnicodeProperties().
+ * The returned value will contain maximum values stored in the same bit fields
+ * as where the enum values are stored in the u_getUnicodeProperties()
+ * return values for the same columns.
+ *
+ * Valid columns are those for properties words that contain enumerated values.
+ * (ICU 2.6: columns 0 and 2)
+ * For other column numbers, this function will return 0.
+ *
+ * @internal
+ */
+U_CFUNC int32_t
+uprv_getMaxValues(int32_t column);
+
+/**
+ * Checks if c is alphabetic, or a decimal digit; implements UCHAR_POSIX_ALNUM.
+ * @internal
+ */
+U_CFUNC UBool
+u_isalnumPOSIX(UChar32 c);
+
+/**
+ * Checks if c is in
+ * [^\p{space}\p{gc=Control}\p{gc=Surrogate}\p{gc=Unassigned}]
+ * with space=\p{Whitespace} and Control=Cc.
+ * Implements UCHAR_POSIX_GRAPH.
+ * @internal
+ */
+U_CFUNC UBool
+u_isgraphPOSIX(UChar32 c);
+
+/**
+ * Checks if c is in \p{graph}\p{blank} - \p{cntrl}.
+ * Implements UCHAR_POSIX_PRINT.
+ * @internal
+ */
+U_CFUNC UBool
+u_isprintPOSIX(UChar32 c);
+
+/** Turn a bit index into a bit flag. @internal */
+#define FLAG(n) ((uint32_t)1<<(n))
+
+/** Flags for general categories in the order of UCharCategory. @internal */
+#define _Cn     FLAG(U_GENERAL_OTHER_TYPES)
+#define _Lu     FLAG(U_UPPERCASE_LETTER)
+#define _Ll     FLAG(U_LOWERCASE_LETTER)
+#define _Lt     FLAG(U_TITLECASE_LETTER)
+#define _Lm     FLAG(U_MODIFIER_LETTER)
+/* #define _Lo     FLAG(U_OTHER_LETTER) -- conflicts with MS Visual Studio 9.0 xiosbase */
+#define _Mn     FLAG(U_NON_SPACING_MARK)
+#define _Me     FLAG(U_ENCLOSING_MARK)
+#define _Mc     FLAG(U_COMBINING_SPACING_MARK)
+#define _Nd     FLAG(U_DECIMAL_DIGIT_NUMBER)
+#define _Nl     FLAG(U_LETTER_NUMBER)
+#define _No     FLAG(U_OTHER_NUMBER)
+#define _Zs     FLAG(U_SPACE_SEPARATOR)
+#define _Zl     FLAG(U_LINE_SEPARATOR)
+#define _Zp     FLAG(U_PARAGRAPH_SEPARATOR)
+#define _Cc     FLAG(U_CONTROL_CHAR)
+#define _Cf     FLAG(U_FORMAT_CHAR)
+#define _Co     FLAG(U_PRIVATE_USE_CHAR)
+#define _Cs     FLAG(U_SURROGATE)
+#define _Pd     FLAG(U_DASH_PUNCTUATION)
+#define _Ps     FLAG(U_START_PUNCTUATION)
+/* #define _Pe     FLAG(U_END_PUNCTUATION) -- conflicts with MS Visual Studio 9.0 xlocnum */
+/* #define _Pc     FLAG(U_CONNECTOR_PUNCTUATION) -- conflicts with MS Visual Studio 9.0 streambuf */
+#define _Po     FLAG(U_OTHER_PUNCTUATION)
+#define _Sm     FLAG(U_MATH_SYMBOL)
+#define _Sc     FLAG(U_CURRENCY_SYMBOL)
+#define _Sk     FLAG(U_MODIFIER_SYMBOL)
+#define _So     FLAG(U_OTHER_SYMBOL)
+#define _Pi     FLAG(U_INITIAL_PUNCTUATION)
+/* #define _Pf     FLAG(U_FINAL_PUNCTUATION) -- conflicts with MS Visual Studio 9.0 streambuf */
+
+/** Some code points. @internal */
+enum {
+    TAB     =0x0009,
+    LF      =0x000a,
+    FF      =0x000c,
+    CR      =0x000d,
+    U_A     =0x0041,
+    U_F     =0x0046,
+    U_Z     =0x005a,
+    U_a     =0x0061,
+    U_f     =0x0066,
+    U_z     =0x007a,
+    DEL     =0x007f,
+    NL      =0x0085,
+    NBSP    =0x00a0,
+    CGJ     =0x034f,
+    FIGURESP=0x2007,
+    HAIRSP  =0x200a,
+    ZWNJ    =0x200c,
+    ZWJ     =0x200d,
+    RLM     =0x200f,
+    NNBSP   =0x202f,
+    WJ      =0x2060,
+    INHSWAP =0x206a,
+    NOMDIG  =0x206f,
+    U_FW_A  =0xff21,
+    U_FW_F  =0xff26,
+    U_FW_Z  =0xff3a,
+    U_FW_a  =0xff41,
+    U_FW_f  =0xff46,
+    U_FW_z  =0xff5a,
+    ZWNBSP  =0xfeff
+};
+
+/**
+ * Get the maximum length of a (regular/1.0/extended) character name.
+ * @return 0 if no character names available.
+ */
+U_CAPI int32_t U_EXPORT2
+uprv_getMaxCharNameLength(void);
+
+/**
+ * Fills set with characters that are used in Unicode character names.
+ * Includes all characters that are used in regular/Unicode 1.0/extended names.
+ * Just empties the set if no character names are available.
+ * @param sa USetAdder to receive characters.
+ */
+U_CAPI void U_EXPORT2
+uprv_getCharNameCharacters(const USetAdder *sa);
+
+/**
+ * Constants for which data and implementation files provide which properties.
+ * Used by UnicodeSet for service-specific property enumeration.
+ * @internal
+ */
+enum UPropertySource {
+    /** No source, not a supported property. */
+    UPROPS_SRC_NONE,
+    /** From uchar.c/uprops.icu main trie */
+    UPROPS_SRC_CHAR,
+    /** From uchar.c/uprops.icu properties vectors trie */
+    UPROPS_SRC_PROPSVEC,
+    /** From unames.c/unames.icu */
+    UPROPS_SRC_NAMES,
+    /** From ucase.c/ucase.icu */
+    UPROPS_SRC_CASE,
+    /** From ubidi_props.c/ubidi.icu */
+    UPROPS_SRC_BIDI,
+    /** From uchar.c/uprops.icu main trie as well as properties vectors trie */
+    UPROPS_SRC_CHAR_AND_PROPSVEC,
+    /** From ucase.c/ucase.icu as well as unorm.cpp/unorm.icu */
+    UPROPS_SRC_CASE_AND_NORM,
+    /** From normalizer2impl.cpp/nfc.nrm */
+    UPROPS_SRC_NFC,
+    /** From normalizer2impl.cpp/nfkc.nrm */
+    UPROPS_SRC_NFKC,
+    /** From normalizer2impl.cpp/nfkc_cf.nrm */
+    UPROPS_SRC_NFKC_CF,
+    /** From normalizer2impl.cpp/nfc.nrm canonical iterator data */
+    UPROPS_SRC_NFC_CANON_ITER,
+    /** One more than the highest UPropertySource (UPROPS_SRC_) constant. */
+    UPROPS_SRC_COUNT
+};
+typedef enum UPropertySource UPropertySource;
+
+/**
+ * @see UPropertySource
+ * @internal
+ */
+U_CFUNC UPropertySource U_EXPORT2
+uprops_getSource(UProperty which);
+
+/**
+ * Enumerate uprops.icu's main data trie and add the
+ * start of each range of same properties to the set.
+ * @internal
+ */
+U_CFUNC void U_EXPORT2
+uchar_addPropertyStarts(const USetAdder *sa, UErrorCode *pErrorCode);
+
+/**
+ * Enumerate uprops.icu's properties vectors trie and add the
+ * start of each range of same properties to the set.
+ * @internal
+ */
+U_CFUNC void U_EXPORT2
+upropsvec_addPropertyStarts(const USetAdder *sa, UErrorCode *pErrorCode);
+
+/**
+ * Return a set of characters for property enumeration.
+ * For each two consecutive characters (start, limit) in the set,
+ * all of the properties for start..limit-1 are all the same.
+ *
+ * @param sa USetAdder to receive result. Existing contents are lost.
+ * @internal
+ */
+/*U_CFUNC void U_EXPORT2
+uprv_getInclusions(const USetAdder *sa, UErrorCode *pErrorCode);
+*/
+
+/**
+ * Swap the ICU Unicode properties file. See uchar.c.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+uprops_swap(const UDataSwapper *ds,
+            const void *inData, int32_t length, void *outData,
+            UErrorCode *pErrorCode);
+
+/**
+ * Swap the ICU Unicode character names file. See uchar.c.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+uchar_swapNames(const UDataSwapper *ds,
+                const void *inData, int32_t length, void *outData,
+                UErrorCode *pErrorCode);
+
+#ifdef XP_CPLUSPLUS
+
+U_NAMESPACE_BEGIN
+
+class UnicodeSet;
+
+// implemented in uniset_props.cpp
+U_CFUNC UnicodeSet *
+uniset_getUnicode32Instance(UErrorCode &errorCode);
+
+U_NAMESPACE_END
+
+#endif
+
+#endif
diff --git a/source/common/ures_cnv.c b/source/common/ures_cnv.c
new file mode 100644
index 0000000..c972901
--- /dev/null
+++ b/source/common/ures_cnv.c
@@ -0,0 +1,76 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1997-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  ures_cnv.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2004aug25
+*   created by: Markus W. Scherer
+*
+*   Character conversion functions moved here from uresbund.c
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/putil.h"
+#include "unicode/ustring.h"
+#include "unicode/ucnv.h"
+#include "unicode/ures.h"
+#include "uinvchar.h"
+#include "ustr_cnv.h"
+
+U_CAPI UResourceBundle * U_EXPORT2
+ures_openU(const UChar *myPath, 
+           const char *localeID, 
+           UErrorCode *status)
+{
+    char pathBuffer[1024];
+    int32_t length;
+    char *path = pathBuffer;
+
+    if(status==NULL || U_FAILURE(*status)) {
+        return NULL;
+    }
+    if(myPath==NULL) {
+        path = NULL;
+    }
+    else {
+        length=u_strlen(myPath);
+        if(length>=sizeof(pathBuffer)) {
+            *status=U_ILLEGAL_ARGUMENT_ERROR;
+            return NULL;
+        } else if(uprv_isInvariantUString(myPath, length)) {
+            /*
+             * the invariant converter is sufficient for package and tree names
+             * and is more efficient
+             */
+            u_UCharsToChars(myPath, path, length+1); /* length+1 to include the NUL */
+        } else {
+#if !UCONFIG_NO_CONVERSION
+            /* use the default converter to support variant-character paths */
+            UConverter *cnv=u_getDefaultConverter(status);
+            length=ucnv_fromUChars(cnv, path, (int32_t)sizeof(pathBuffer), myPath, length, status);
+            u_releaseDefaultConverter(cnv);
+            if(U_FAILURE(*status)) {
+                return NULL;
+            }
+            if(length>=sizeof(pathBuffer)) {
+                /* not NUL-terminated - path too long */
+                *status=U_ILLEGAL_ARGUMENT_ERROR;
+                return NULL;
+            }
+#else
+            /* the default converter is not available */
+            *status=U_UNSUPPORTED_ERROR;
+            return NULL;
+#endif
+        }
+    }
+
+    return ures_open(path, localeID, status);
+}
diff --git a/source/common/uresbund.c b/source/common/uresbund.c
new file mode 100644
index 0000000..40c3286
--- /dev/null
+++ b/source/common/uresbund.c
@@ -0,0 +1,2832 @@
+/*
+******************************************************************************
+* Copyright (C) 1997-2010, International Business Machines Corporation and   *
+* others. All Rights Reserved.                                               *
+******************************************************************************
+*
+* File URESBUND.C
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   04/01/97    aliu        Creation.
+*   06/14/99    stephen     Removed functions taking a filename suffix.
+*   07/20/99    stephen     Changed for UResourceBundle typedef'd to void*
+*   11/09/99    weiv            Added ures_getLocale()
+*   March 2000  weiv        Total overhaul - using data in DLLs
+*   06/20/2000  helena      OS/400 port changes; mostly typecast.
+*   06/24/02    weiv        Added support for resource sharing
+******************************************************************************
+*/
+
+#include "unicode/ustring.h"
+#include "unicode/ucnv.h"
+#include "uresimp.h"
+#include "ustr_imp.h"
+#include "cwchar.h"
+#include "ucln_cmn.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uhash.h"
+#include "unicode/uenum.h"
+#include "uenumimp.h"
+#include "ulocimp.h"
+#include "umutex.h"
+#include "putilimp.h"
+
+
+/*
+Static cache for already opened resource bundles - mostly for keeping fallback info
+TODO: This cache should probably be removed when the deprecated code is
+      completely removed.
+*/
+static UHashtable *cache = NULL;
+
+static UMTX resbMutex = NULL;
+
+/* INTERNAL: hashes an entry  */
+static int32_t U_CALLCONV hashEntry(const UHashTok parm) {
+    UResourceDataEntry *b = (UResourceDataEntry *)parm.pointer;
+    UHashTok namekey, pathkey;
+    namekey.pointer = b->fName;
+    pathkey.pointer = b->fPath;
+    return uhash_hashChars(namekey)+37*uhash_hashChars(pathkey);
+}
+
+/* INTERNAL: compares two entries */
+static UBool U_CALLCONV compareEntries(const UHashTok p1, const UHashTok p2) {
+    UResourceDataEntry *b1 = (UResourceDataEntry *)p1.pointer;
+    UResourceDataEntry *b2 = (UResourceDataEntry *)p2.pointer;
+    UHashTok name1, name2, path1, path2;
+    name1.pointer = b1->fName;
+    name2.pointer = b2->fName;
+    path1.pointer = b1->fPath;
+    path2.pointer = b2->fPath;
+    return (UBool)(uhash_compareChars(name1, name2) &&
+        uhash_compareChars(path1, path2));
+}
+
+
+/**
+ *  Internal function, gets parts of locale name according 
+ *  to the position of '_' character
+ */
+static UBool chopLocale(char *name) {
+    char *i = uprv_strrchr(name, '_');
+
+    if(i != NULL) {
+        *i = '\0';
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+/**
+ *  Internal function
+ */
+static void entryIncrease(UResourceDataEntry *entry) {
+    umtx_lock(&resbMutex);
+    entry->fCountExisting++;
+    while(entry->fParent != NULL) {
+      entry = entry->fParent;
+      entry->fCountExisting++;
+    }
+    umtx_unlock(&resbMutex);
+}
+
+/**
+ *  Internal function. Tries to find a resource in given Resource 
+ *  Bundle, as well as in its parents
+ */
+static const ResourceData *getFallbackData(const UResourceBundle* resBundle, const char* * resTag, UResourceDataEntry* *realData, Resource *res, UErrorCode *status) {
+    UResourceDataEntry *resB = resBundle->fData;
+    int32_t indexR = -1;
+    int32_t i = 0;
+    *res = RES_BOGUS;
+    if(resB != NULL) {
+        if(resB->fBogus == U_ZERO_ERROR) { /* if this resource is real, */
+            *res = res_getTableItemByKey(&(resB->fData), resB->fData.rootRes, &indexR, resTag); /* try to get data from there */
+            i++;
+        }
+        if(resBundle->fHasFallback == TRUE) {
+            while(*res == RES_BOGUS && resB->fParent != NULL) { /* Otherwise, we'll look in parents */
+                resB = resB->fParent;
+                if(resB->fBogus == U_ZERO_ERROR) {
+                    i++;
+                    *res = res_getTableItemByKey(&(resB->fData), resB->fData.rootRes, &indexR, resTag);
+                }
+            }
+        }
+
+        if(*res != RES_BOGUS) { /* If the resource is found in parents, we need to adjust the error */
+            if(i>1) {
+                if(uprv_strcmp(resB->fName, uloc_getDefault())==0 || uprv_strcmp(resB->fName, kRootLocaleName)==0) {
+                    *status = U_USING_DEFAULT_WARNING;
+                } else {
+                    *status = U_USING_FALLBACK_WARNING;
+                }
+            }
+            *realData = resB;
+            return (&(resB->fData));
+        } else { /* If resource is not found, we need to give an error */
+            *status = U_MISSING_RESOURCE_ERROR;
+            return NULL;
+        }
+    } else {
+            *status = U_MISSING_RESOURCE_ERROR;
+            return NULL;
+    }
+}
+
+static void
+free_entry(UResourceDataEntry *entry) {
+    UResourceDataEntry *alias;
+    res_unload(&(entry->fData));
+    if(entry->fName != NULL && entry->fName != entry->fNameBuffer) {
+        uprv_free(entry->fName);
+    }
+    if(entry->fPath != NULL) {
+        uprv_free(entry->fPath);
+    }
+    if(entry->fPool != NULL) {
+        --entry->fPool->fCountExisting;
+    }
+    alias = entry->fAlias;
+    if(alias != NULL) {
+        while(alias->fAlias != NULL) {
+            alias = alias->fAlias;
+        }
+        --alias->fCountExisting;
+    }
+    uprv_free(entry);
+}
+
+/* Works just like ucnv_flushCache() */
+static int32_t ures_flushCache()
+{
+    UResourceDataEntry *resB;
+    int32_t pos;
+    int32_t rbDeletedNum = 0;
+    const UHashElement *e;
+    UBool deletedMore;
+
+    /*if shared data hasn't even been lazy evaluated yet
+    * return 0
+    */
+    umtx_lock(&resbMutex);
+    if (cache == NULL) {
+        umtx_unlock(&resbMutex);
+        return 0;
+    }
+
+    do {
+        deletedMore = FALSE;
+        /*creates an enumeration to iterate through every element in the table */
+        pos = -1;
+        while ((e = uhash_nextElement(cache, &pos)) != NULL)
+        {
+            resB = (UResourceDataEntry *) e->value.pointer;
+            /* Deletes only if reference counter == 0
+             * Don't worry about the children of this node.
+             * Those will eventually get deleted too, if not already.
+             * Don't worry about the parents of this node.
+             * Those will eventually get deleted too, if not already.
+             */
+            /* 04/05/2002 [weiv] fCountExisting should now be accurate. If it's not zero, that means that    */
+            /* some resource bundles are still open somewhere. */
+
+            if (resB->fCountExisting == 0) {
+                rbDeletedNum++;
+                deletedMore = TRUE;
+                uhash_removeElement(cache, e);
+                free_entry(resB);
+            }
+        }
+        /*
+         * Do it again to catch bundles (aliases, pool bundle) whose fCountExisting
+         * got decremented by free_entry().
+         */
+    } while(deletedMore);
+    umtx_unlock(&resbMutex);
+
+    return rbDeletedNum;
+}
+
+#ifdef URES_DEBUG
+#include <stdio.h>
+
+U_CAPI UBool U_EXPORT2 ures_dumpCacheContents(void) {
+  UBool cacheNotEmpty = FALSE;
+  int32_t pos = -1;
+  const UHashElement *e;
+  UResourceDataEntry *resB;
+  
+    umtx_lock(&resbMutex);
+    if (cache == NULL) {
+      umtx_unlock(&resbMutex);
+      fprintf(stderr,"%s:%d: RB Cache is NULL.\n", __FILE__, __LINE__);
+      return FALSE;
+    }
+
+    while ((e = uhash_nextElement(cache, &pos)) != NULL) {
+      cacheNotEmpty=TRUE;
+      resB = (UResourceDataEntry *) e->value.pointer;
+      fprintf(stderr,"%s:%d: RB Cache: Entry @0x%p, refcount %d, name %s:%s.  Pool 0x%p, alias 0x%p, parent 0x%p\n",
+              __FILE__, __LINE__,
+              (void*)resB, resB->fCountExisting,
+              resB->fName?resB->fName:"NULL",
+              resB->fPath?resB->fPath:"NULL",
+              (void*)resB->fPool,
+              (void*)resB->fAlias,
+              (void*)resB->fParent);       
+    }
+    
+    fprintf(stderr,"%s:%d: RB Cache still contains %d items.\n", __FILE__, __LINE__, uhash_count(cache));
+
+    umtx_unlock(&resbMutex);
+    
+    return cacheNotEmpty;
+}
+
+#endif
+
+static UBool U_CALLCONV ures_cleanup(void)
+{
+    if (cache != NULL) {
+        ures_flushCache();
+        if (cache != NULL && uhash_count(cache) == 0) {
+            uhash_close(cache);
+            cache = NULL;
+        }
+    }
+    if (cache == NULL && resbMutex != NULL) {
+        umtx_destroy(&resbMutex);
+    }
+    return (cache == NULL);
+}
+
+/** INTERNAL: Initializes the cache for resources */
+static void initCache(UErrorCode *status) {
+    UBool makeCache = FALSE;
+    UMTX_CHECK(&resbMutex, (cache ==  NULL), makeCache);
+    if(makeCache) {
+        UHashtable *newCache = uhash_open(hashEntry, compareEntries, NULL, status);
+        if (U_FAILURE(*status)) {
+            return;
+        }
+        umtx_lock(&resbMutex);
+        if(cache == NULL) {
+            cache = newCache;
+            newCache = NULL;
+            ucln_common_registerCleanup(UCLN_COMMON_URES, ures_cleanup);
+        }
+        umtx_unlock(&resbMutex);
+        if(newCache != NULL) {
+            uhash_close(newCache);
+        }
+    }
+}
+
+/** INTERNAL: sets the name (locale) of the resource bundle to given name */
+
+static void setEntryName(UResourceDataEntry *res, char *name, UErrorCode *status) {
+    int32_t len = (int32_t)uprv_strlen(name);
+    if(res->fName != NULL && res->fName != res->fNameBuffer) {
+        uprv_free(res->fName);
+    }
+    if (len < (int32_t)sizeof(res->fNameBuffer)) {
+        res->fName = res->fNameBuffer;
+    }
+    else {
+        res->fName = (char *)uprv_malloc(len+1);
+    }
+    if(res->fName == NULL) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+    } else {
+        uprv_strcpy(res->fName, name);
+    }
+}
+
+static UResourceDataEntry *
+getPoolEntry(const char *path, UErrorCode *status);
+
+/**
+ *  INTERNAL: Inits and opens an entry from a data DLL.
+ *    CAUTION:  resbMutex must be locked when calling this function.
+ */
+static UResourceDataEntry *init_entry(const char *localeID, const char *path, UErrorCode *status) {
+    UResourceDataEntry *r = NULL;
+    UResourceDataEntry find;
+    /*int32_t hashValue;*/
+    char name[96];
+    char aliasName[100] = { 0 };
+    int32_t aliasLen = 0;
+    /*UBool isAlias = FALSE;*/
+    UHashTok hashkey;
+
+    if(U_FAILURE(*status)) {
+        return NULL;
+    }
+
+    /* here we try to deduce the right locale name */
+    if(localeID == NULL) { /* if localeID is NULL, we're trying to open default locale */
+        uprv_strcpy(name, uloc_getDefault());
+    } else if(*localeID == 0) { /* if localeID is "" then we try to open root locale */
+        uprv_strcpy(name, kRootLocaleName);
+    } else { /* otherwise, we'll open what we're given */
+        uprv_strcpy(name, localeID);
+    }
+
+    find.fName = name;
+    find.fPath = (char *)path;
+
+    /* calculate the hash value of the entry */
+    hashkey.pointer = (void *)&find;
+    /*hashValue = hashEntry(hashkey);*/
+
+    /* check to see if we already have this entry */
+    r = (UResourceDataEntry *)uhash_get(cache, &find);
+    if(r == NULL) {
+        /* if the entry is not yet in the hash table, we'll try to construct a new one */
+        r = (UResourceDataEntry *) uprv_malloc(sizeof(UResourceDataEntry));
+        if(r == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return NULL;
+        }
+
+        uprv_memset(r, 0, sizeof(UResourceDataEntry));
+        /*r->fHashKey = hashValue;*/
+
+        setEntryName(r, name, status);
+        if (U_FAILURE(*status)) {
+            uprv_free(r);
+            return NULL;
+        }
+
+        if(path != NULL) {
+            r->fPath = (char *)uprv_strdup(path);
+            if(r->fPath == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                uprv_free(r);
+                return NULL;
+            }
+        }
+
+        /* this is the actual loading */
+        res_load(&(r->fData), r->fPath, r->fName, status);
+
+        if (U_FAILURE(*status)) { 
+            /* we have no such entry in dll, so it will always use fallback */
+            *status = U_USING_FALLBACK_WARNING;
+            r->fBogus = U_USING_FALLBACK_WARNING;
+        } else { /* if we have a regular entry */
+            Resource aliasres;
+            if (r->fData.usesPoolBundle) {
+                r->fPool = getPoolEntry(r->fPath, status);
+                if (U_SUCCESS(*status)) {
+                    const int32_t *poolIndexes = r->fPool->fData.pRoot + 1;
+                    if(r->fData.pRoot[1 + URES_INDEX_POOL_CHECKSUM] == poolIndexes[URES_INDEX_POOL_CHECKSUM]) {
+                        r->fData.poolBundleKeys = (const char *)(poolIndexes + (poolIndexes[URES_INDEX_LENGTH] & 0xff));
+                    } else {
+                        r->fBogus = *status = U_INVALID_FORMAT_ERROR;
+                    }
+                } else {
+                    r->fBogus = *status;
+                }
+            }
+            if (U_SUCCESS(*status)) {
+                /* handle the alias by trying to get out the %%Alias tag.*/
+                /* We'll try to get alias string from the bundle */
+                aliasres = res_getResource(&(r->fData), "%%ALIAS");
+                if (aliasres != RES_BOGUS) {
+                    const UChar *alias = res_getString(&(r->fData), aliasres, &aliasLen);
+                    if(alias != NULL && aliasLen > 0) { /* if there is actual alias - unload and load new data */
+                        u_UCharsToChars(alias, aliasName, aliasLen+1);
+                        r->fAlias = init_entry(aliasName, path, status);
+                    }
+                }
+            }
+        }
+
+        {
+            UResourceDataEntry *oldR = NULL;
+            if((oldR = (UResourceDataEntry *)uhash_get(cache, r)) == NULL) { /* if the data is not cached */
+                /* just insert it in the cache */
+                UErrorCode cacheStatus = U_ZERO_ERROR;
+                uhash_put(cache, (void *)r, r, &cacheStatus);
+                if (U_FAILURE(cacheStatus)) {
+                    *status = cacheStatus;
+                    free_entry(r);
+                    r = NULL;
+                }
+            } else {
+                /* somebody have already inserted it while we were working, discard newly opened data */
+                /* Also, we could get here IF we opened an alias */
+                free_entry(r);
+                r = oldR;
+            }
+        }
+
+    }
+    if(r != NULL) {
+        /* return the real bundle */
+        while(r->fAlias != NULL) {
+            r = r->fAlias;
+        }
+        r->fCountExisting++; /* we increase its reference count */
+        /* if the resource has a warning */
+        /* we don't want to overwrite a status with no error */
+        if(r->fBogus != U_ZERO_ERROR && U_SUCCESS(*status)) {
+             *status = r->fBogus; /* set the returning status */
+        }
+    }
+    return r;
+}
+
+static UResourceDataEntry *
+getPoolEntry(const char *path, UErrorCode *status) {
+    UResourceDataEntry *poolBundle = init_entry(kPoolBundleName, path, status);
+    if( U_SUCCESS(*status) &&
+        (poolBundle == NULL || poolBundle->fBogus != U_ZERO_ERROR || !poolBundle->fData.isPoolBundle)
+    ) {
+        *status = U_INVALID_FORMAT_ERROR;
+    }
+    return poolBundle;
+}
+
+/* INTERNAL: */
+/*   CAUTION:  resbMutex must be locked when calling this function! */
+static UResourceDataEntry *findFirstExisting(const char* path, char* name, UBool *isRoot, UBool *hasChopped, UBool *isDefault, UErrorCode* status) {
+    UResourceDataEntry *r = NULL;
+    UBool hasRealData = FALSE;
+    const char *defaultLoc = uloc_getDefault();
+    *hasChopped = TRUE; /* we're starting with a fresh name */
+
+    while(*hasChopped && !hasRealData) {
+        r = init_entry(name, path, status);
+        /* Null pointer test */
+        if (U_FAILURE(*status)) {
+            return NULL;
+        }
+        *isDefault = (UBool)(uprv_strncmp(name, defaultLoc, uprv_strlen(name)) == 0);
+        hasRealData = (UBool)(r->fBogus == U_ZERO_ERROR);
+        if(!hasRealData) {
+            /* this entry is not real. We will discard it. */
+            /* However, the parent line for this entry is  */
+            /* not to be used - as there might be parent   */
+            /* lines in cache from previous openings that  */
+            /* are not updated yet. */
+            r->fCountExisting--;
+            /*entryCloseInt(r);*/
+            r = NULL;
+            *status = U_USING_FALLBACK_WARNING;
+        } else {
+            uprv_strcpy(name, r->fName); /* this is needed for supporting aliases */
+        }
+
+        *isRoot = (UBool)(uprv_strcmp(name, kRootLocaleName) == 0);
+
+        /*Fallback data stuff*/
+        *hasChopped = chopLocale(name);
+    }
+    return r;
+}
+
+static void ures_setIsStackObject( UResourceBundle* resB, UBool state) {
+    if(state) {
+        resB->fMagic1 = 0;
+        resB->fMagic2 = 0;
+    } else {
+        resB->fMagic1 = MAGIC1;
+        resB->fMagic2 = MAGIC2;
+    }
+}
+
+static UBool ures_isStackObject(const UResourceBundle* resB) {
+  return((resB->fMagic1 == MAGIC1 && resB->fMagic2 == MAGIC2)?FALSE:TRUE);
+}
+
+
+U_CFUNC void ures_initStackObject(UResourceBundle* resB) {
+  uprv_memset(resB, 0, sizeof(UResourceBundle));
+  ures_setIsStackObject(resB, TRUE);
+}
+
+static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UErrorCode* status) {
+    UErrorCode intStatus = U_ZERO_ERROR;
+    UErrorCode parentStatus = U_ZERO_ERROR;
+    UErrorCode usrStatus = U_ZERO_ERROR;
+    UResourceDataEntry *r = NULL;
+    UResourceDataEntry *t1 = NULL;
+    UResourceDataEntry *t2 = NULL;
+    UResourceDataEntry *u1 = NULL;
+    UResourceDataEntry *u2 = NULL;
+    UBool isDefault = FALSE;
+    UBool isRoot = FALSE;
+    UBool hasRealData = FALSE;
+    UBool hasChopped = TRUE;
+    UBool usingUSRData = U_USE_USRDATA && ( path == NULL || uprv_strncmp(path,U_ICUDATA_NAME,8) == 0);
+
+    char name[96];
+    char usrDataPath[96];
+
+    initCache(status);
+
+    if(U_FAILURE(*status)) {
+        return NULL;
+    }
+
+    uprv_strcpy(name, localeID);
+
+    if ( usingUSRData ) {
+        if ( path == NULL ) {
+           uprv_strcpy(usrDataPath,U_USRDATA_NAME);
+        } else {
+           uprv_strcpy(usrDataPath,path);
+           usrDataPath[0] = 'u';
+           usrDataPath[1] = 's';
+           usrDataPath[2] = 'r';
+        }
+    }
+ 
+    umtx_lock(&resbMutex);
+    { /* umtx_lock */
+        /* We're going to skip all the locales that do not have any data */
+        r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
+
+        if(r != NULL) { /* if there is one real locale, we can look for parents. */
+            t1 = r;
+            hasRealData = TRUE;
+            if ( usingUSRData ) {  /* This code inserts user override data into the inheritance chain */
+               u1 = init_entry(t1->fName, usrDataPath, &usrStatus);
+               if ( u1 != NULL ) {
+                 if(u1->fBogus == U_ZERO_ERROR) {
+                   u1->fParent = t1;
+                   r = u1;
+                 } else {
+                   /* the USR override data wasn't found, set it to be deleted */
+                   u1->fCountExisting = 0;
+                 }
+               }
+            }
+            while (hasChopped && !isRoot && t1->fParent == NULL && !t1->fData.noFallback) {
+                /* insert regular parents */
+                t2 = init_entry(name, t1->fPath, &parentStatus);
+                if ( usingUSRData ) {  /* This code inserts user override data into the inheritance chain */
+                    usrStatus = U_ZERO_ERROR;
+                    u2 = init_entry(name, usrDataPath, &usrStatus);
+                }
+                /* Check for null pointer. */
+                if (t2 == NULL || ( usingUSRData && u2 == NULL)) {
+                    *status = U_MEMORY_ALLOCATION_ERROR;
+                    goto finishUnlock;
+                }
+                
+                if ( res_getResource(&t1->fData,"%%ParentIsRoot") == RES_BOGUS) {
+                    if ( usingUSRData && u2->fBogus == U_ZERO_ERROR ) {
+                        t1->fParent = u2;
+                        u2->fParent = t2;
+                    } else {
+                        t1->fParent = t2;
+                        if(usingUSRData) {
+                            /* the USR override data wasn't found, set it to be deleted */
+                            u2->fCountExisting = 0;
+                        }
+                    }
+                    t1 = t2;
+                } else {
+                    if (usingUSRData) {
+                        /* the USR override data wasn't found, set it to be deleted */
+                        u2->fCountExisting = 0;
+                    }
+                    /* t2->fCountExisting have to be decremented since the call to init_entry increments
+                     * it and if we hit this code, that means it is not set as the parent.
+                     */
+                    t2->fCountExisting--;
+                }
+                hasChopped = chopLocale(name);
+            }
+        }
+
+        /* we could have reached this point without having any real data */
+        /* if that is the case, we need to chain in the default locale   */
+        if(r==NULL && !isDefault && !isRoot /*&& t1->fParent == NULL*/) {
+            /* insert default locale */
+            uprv_strcpy(name, uloc_getDefault());
+            r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
+            intStatus = U_USING_DEFAULT_WARNING;
+            if(r != NULL) { /* the default locale exists */
+                t1 = r;
+                hasRealData = TRUE;
+                isDefault = TRUE;
+                while (hasChopped && t1->fParent == NULL) {
+                    /* insert chopped defaults */
+                    t2 = init_entry(name, t1->fPath, &parentStatus);
+                    /* Check for null pointer. */
+                    if (t2 == NULL) {
+                        *status = U_MEMORY_ALLOCATION_ERROR;
+                        goto finishUnlock;
+                    }
+
+                    if ( res_getResource(&t1->fData,"%%ParentIsRoot") == RES_BOGUS) {
+                        t1->fParent = t2;
+                        t1 = t2;
+                    }
+                    hasChopped = chopLocale(name);
+                }
+            } 
+        }
+
+        /* we could still have r == NULL at this point - maybe even default locale is not */
+        /* present */
+        if(r == NULL) {
+            uprv_strcpy(name, kRootLocaleName);
+            r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
+            if(r != NULL) {
+                t1 = r;
+                intStatus = U_USING_DEFAULT_WARNING;
+                hasRealData = TRUE;
+            } else { /* we don't even have the root locale */
+                *status = U_MISSING_RESOURCE_ERROR;
+                goto finishUnlock;
+            }
+        } else if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName) != 0 && t1->fParent == NULL && !r->fData.noFallback) {
+            /* insert root locale */
+            t2 = init_entry(kRootLocaleName, t1->fPath, &parentStatus);
+            /* Check for null pointer. */
+            if (t2 == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                goto finishUnlock;
+            }
+            if(!hasRealData) {
+                r->fBogus = U_USING_DEFAULT_WARNING;
+            }
+            hasRealData = (UBool)((t2->fBogus == U_ZERO_ERROR) || hasRealData);
+            t1->fParent = t2;
+            t1 = t2;
+        }
+
+        while(r != NULL && !isRoot && t1->fParent != NULL) {
+            t1->fParent->fCountExisting++;
+            t1 = t1->fParent;
+            hasRealData = (UBool)((t1->fBogus == U_ZERO_ERROR) || hasRealData);
+        }
+    } /* umtx_lock */
+finishUnlock:
+    umtx_unlock(&resbMutex);
+
+    if(U_SUCCESS(*status)) {
+        if(U_SUCCESS(parentStatus)) {
+            if(intStatus != U_ZERO_ERROR) {
+                *status = intStatus;  
+            }
+            return r;
+        } else {
+            *status = parentStatus;
+            return NULL;
+        }
+    } else {
+        return NULL;
+    }
+}
+
+
+/**
+ * Functions to create and destroy resource bundles.
+ *     CAUTION:  resbMutex must be locked when calling this function.
+ */
+/* INTERNAL: */
+static void entryCloseInt(UResourceDataEntry *resB) {
+    UResourceDataEntry *p = resB;
+
+    while(resB != NULL) {
+        p = resB->fParent;
+        resB->fCountExisting--;
+
+        /* Entries are left in the cache. TODO: add ures_flushCache() to force a flush
+         of the cache. */
+/*
+        if(resB->fCountExisting <= 0) {
+            uhash_remove(cache, resB);
+            if(resB->fBogus == U_ZERO_ERROR) {
+                res_unload(&(resB->fData));
+            }
+            if(resB->fName != NULL) {
+                uprv_free(resB->fName);
+            }
+            if(resB->fPath != NULL) {
+                uprv_free(resB->fPath);
+            }
+            uprv_free(resB);
+        }
+*/
+
+        resB = p;
+    }
+}
+
+/** 
+ *  API: closes a resource bundle and cleans up.
+ */
+
+static void entryClose(UResourceDataEntry *resB) {
+  umtx_lock(&resbMutex);
+  entryCloseInt(resB);
+  umtx_unlock(&resbMutex);
+}
+
+/*
+U_CFUNC void ures_setResPath(UResourceBundle *resB, const char* toAdd) {
+  if(resB->fResPath == NULL) {
+    resB->fResPath = resB->fResBuf;
+    *(resB->fResPath) = 0;
+  } 
+  resB->fResPathLen = uprv_strlen(toAdd);
+  if(RES_BUFSIZE <= resB->fResPathLen+1) {
+    if(resB->fResPath == resB->fResBuf) {
+      resB->fResPath = (char *)uprv_malloc((resB->fResPathLen+1)*sizeof(char));
+    } else {
+      resB->fResPath = (char *)uprv_realloc(resB->fResPath, (resB->fResPathLen+1)*sizeof(char));
+    }
+  }
+  uprv_strcpy(resB->fResPath, toAdd);
+}
+*/
+static void ures_appendResPath(UResourceBundle *resB, const char* toAdd, int32_t lenToAdd, UErrorCode *status) {
+    int32_t resPathLenOrig = resB->fResPathLen;
+    if(resB->fResPath == NULL) {
+        resB->fResPath = resB->fResBuf;
+        *(resB->fResPath) = 0;
+        resB->fResPathLen = 0;
+    } 
+    resB->fResPathLen += lenToAdd;
+    if(RES_BUFSIZE <= resB->fResPathLen+1) {
+        if(resB->fResPath == resB->fResBuf) {
+            resB->fResPath = (char *)uprv_malloc((resB->fResPathLen+1)*sizeof(char));
+            /* Check that memory was allocated correctly. */
+            if (resB->fResPath == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                return;
+            }
+            uprv_strcpy(resB->fResPath, resB->fResBuf);
+        } else {
+            char *temp = (char *)uprv_realloc(resB->fResPath, (resB->fResPathLen+1)*sizeof(char));
+            /* Check that memory was reallocated correctly. */
+            if (temp == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                return;
+            }
+            resB->fResPath = temp;
+        }
+    }
+    uprv_strcpy(resB->fResPath + resPathLenOrig, toAdd);
+}
+
+static void ures_freeResPath(UResourceBundle *resB) {
+    if (resB->fResPath && resB->fResPath != resB->fResBuf) {
+        uprv_free(resB->fResPath);
+    }
+    resB->fResPath = NULL;
+    resB->fResPathLen = 0;
+}
+
+static void
+ures_closeBundle(UResourceBundle* resB, UBool freeBundleObj)
+{
+    if(resB != NULL) {
+        if(resB->fData != NULL) {
+            entryClose(resB->fData);
+        }
+        if(resB->fVersion != NULL) {
+            uprv_free(resB->fVersion);
+        }
+        ures_freeResPath(resB);
+
+        if(ures_isStackObject(resB) == FALSE && freeBundleObj) {
+            uprv_free(resB);
+        }
+#if 0 /*U_DEBUG*/
+        else {
+            /* poison the data */
+            uprv_memset(resB, -1, sizeof(UResourceBundle));
+        }
+#endif
+    }
+}
+
+U_CAPI void  U_EXPORT2
+ures_close(UResourceBundle* resB)
+{
+    ures_closeBundle(resB, TRUE);
+}
+
+static UResourceBundle *init_resb_result(const ResourceData *rdata, Resource r, 
+                                         const char *key, int32_t idx, UResourceDataEntry *realData, 
+                                         const UResourceBundle *parent, int32_t noAlias,
+                                         UResourceBundle *resB, UErrorCode *status) 
+{
+    if(status == NULL || U_FAILURE(*status)) {
+        return resB;
+    }
+    if (parent == NULL) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+    if(RES_GET_TYPE(r) == URES_ALIAS) { /* This is an alias, need to exchange with real data */
+        if(noAlias < URES_MAX_ALIAS_LEVEL) { 
+            int32_t len = 0;
+            const UChar *alias = res_getAlias(rdata, r, &len); 
+            if(len > 0) {
+                /* we have an alias, now let's cut it up */
+                char stackAlias[200];
+                char *chAlias = NULL, *path = NULL, *locale = NULL, *keyPath = NULL;
+                int32_t capacity;
+
+                /*
+                * Allocate enough space for both the char * version
+                * of the alias and parent->fResPath.
+                *
+                * We do this so that res_findResource() can modify the path,
+                * which allows us to remove redundant _res_findResource() variants
+                * in uresdata.c.
+                * res_findResource() now NUL-terminates each segment so that table keys
+                * can always be compared with strcmp() instead of strncmp().
+                * Saves code there and simplifies testing and code coverage.
+                *
+                * markus 2003oct17
+                */
+                ++len; /* count the terminating NUL */
+                if(parent->fResPath != NULL) {
+                    capacity = (int32_t)uprv_strlen(parent->fResPath) + 1;
+                } else {
+                    capacity = 0;
+                }
+                if(capacity < len) {
+                    capacity = len;
+                }
+                if(capacity <= sizeof(stackAlias)) {
+                    capacity = sizeof(stackAlias);
+                    chAlias = stackAlias;
+                } else {
+                    chAlias = (char *)uprv_malloc(capacity);
+                    /* test for NULL */
+                    if(chAlias == NULL) {
+                        *status = U_MEMORY_ALLOCATION_ERROR;
+                        return NULL;
+                    }
+                }
+                u_UCharsToChars(alias, chAlias, len);
+
+                if(*chAlias == RES_PATH_SEPARATOR) {
+                    /* there is a path included */
+                    locale = uprv_strchr(chAlias+1, RES_PATH_SEPARATOR);
+                    if(locale == NULL) {
+                        locale = uprv_strchr(chAlias, 0); /* avoid locale == NULL to make code below work */
+                    } else {
+                        *locale = 0;
+                        locale++;
+                    }
+                    path = chAlias+1;
+                    if(uprv_strcmp(path, "LOCALE") == 0) {
+                        /* this is an XPath alias, starting with "/LOCALE/" */
+                        /* it contains the path to a resource which should be looked up */
+                        /* starting in the requested locale */
+                        keyPath = locale; 
+                        locale = parent->fTopLevelData->fName; /* this is the requested locale's name */
+                        path = realData->fPath; /* we will be looking in the same package */
+                    } else {
+                        if(uprv_strcmp(path, "ICUDATA") == 0) { /* want ICU data */
+                            path = NULL;
+                        }
+                        keyPath = uprv_strchr(locale, RES_PATH_SEPARATOR);
+                        if(keyPath) {
+                            *keyPath = 0;
+                            keyPath++;
+                        }
+                    }
+                } else {
+                    /* no path, start with a locale */
+                    locale = chAlias;
+                    keyPath = uprv_strchr(locale, RES_PATH_SEPARATOR);
+                    if(keyPath) {
+                        *keyPath = 0;
+                        keyPath++;
+                    }
+                    path = realData->fPath;
+                }
+
+
+                {
+                    /* got almost everything, let's try to open */
+                    /* first, open the bundle with real data */
+                    UResourceBundle *result = resB;
+                    const char* temp = NULL;
+                    UErrorCode intStatus = U_ZERO_ERROR;
+                    UResourceBundle *mainRes = ures_openDirect(path, locale, &intStatus); 
+                    if(U_SUCCESS(intStatus)) {
+                        if(keyPath == NULL) {
+                            /* no key path. This means that we are going to 
+                            * to use the corresponding resource from
+                            * another bundle
+                            */
+                            /* first, we are going to get a corresponding parent 
+                            * resource to the one we are searching.
+                            */
+                            char *aKey = parent->fResPath;
+                            if(aKey) {
+                                uprv_strcpy(chAlias, aKey); /* allocated large enough above */
+                                aKey = chAlias;
+                                r = res_findResource(&(mainRes->fResData), mainRes->fRes, &aKey, &temp);
+                            } else {
+                                r = mainRes->fRes;
+                            }
+                            if(key) {
+                                /* we need to make keyPath from parent's fResPath and
+                                * current key, if there is a key associated
+                                */
+                                len = (int32_t)(uprv_strlen(key) + 1);
+                                if(len > capacity) {
+                                    capacity = len;
+                                    if(chAlias == stackAlias) {
+                                        chAlias = (char *)uprv_malloc(capacity);
+                                    } else {
+                                        chAlias = (char *)uprv_realloc(chAlias, capacity);
+                                    }
+                                    if(chAlias == NULL) {
+                                        ures_close(mainRes);
+                                        *status = U_MEMORY_ALLOCATION_ERROR;
+                                        return NULL;
+                                    }
+                                }
+                                uprv_memcpy(chAlias, key, len);
+                                aKey = chAlias;
+                                r = res_findResource(&(mainRes->fResData), r, &aKey, &temp);
+                            } else if(idx != -1) {
+                                /* if there is no key, but there is an index, try to get by the index */
+                                /* here we have either a table or an array, so get the element */
+                                UResType type = RES_GET_TYPE(r);
+                                if(URES_IS_TABLE(type)) {
+                                    r = res_getTableItemByIndex(&(mainRes->fResData), r, idx, (const char **)&aKey);
+                                } else { /* array */
+                                    r = res_getArrayItem(&(mainRes->fResData), r, idx);
+                                }
+                            }
+                            if(r != RES_BOGUS) {
+                                result = init_resb_result(&(mainRes->fResData), r, temp, -1, mainRes->fData, mainRes, noAlias+1, resB, status);
+                            } else {
+                                *status = U_MISSING_RESOURCE_ERROR;
+                                result = resB;
+                            }
+                        } else {
+                            /* this one is a bit trickier. 
+                            * we start finding keys, but after we resolve one alias, the path might continue.
+                            * Consider: 
+                            *     aliastest:alias { "testtypes/anotheralias/Sequence" }
+                            *     anotheralias:alias { "/ICUDATA/sh/CollationElements" }
+                            * aliastest resource should finally have the sequence, not collation elements.
+                            */
+                            UResourceDataEntry *dataEntry = mainRes->fData;
+                            char stackPath[URES_MAX_BUFFER_SIZE];
+                            char *pathBuf = stackPath, *myPath = pathBuf;
+                            if(uprv_strlen(keyPath) > URES_MAX_BUFFER_SIZE) {
+                                pathBuf = (char *)uprv_malloc((uprv_strlen(keyPath)+1)*sizeof(char));
+                                if(pathBuf == NULL) {
+                                    *status = U_MEMORY_ALLOCATION_ERROR;
+                                    return NULL;
+                                }
+                            }
+                            uprv_strcpy(pathBuf, keyPath);
+                            result = mainRes;
+                            /* now we have fallback following here */
+                            do {
+                                r = dataEntry->fData.rootRes;     
+                                /* this loop handles 'found' resources over several levels */
+                                while(*myPath && U_SUCCESS(*status)) {
+                                    r = res_findResource(&(dataEntry->fData), r, &myPath, &temp);
+                                    if(r != RES_BOGUS) { /* found a resource, but it might be an indirection */
+                                        resB = init_resb_result(&(dataEntry->fData), r, temp, -1, dataEntry, result, noAlias+1, resB, status);
+                                        result = resB;
+                                        if(result) {
+                                            r = result->fRes; /* switch to a new resource, possibly a new tree */
+                                            dataEntry = result->fData;
+                                        }
+                                    } else { /* no resource found, we don't really want to look anymore on this level */
+                                        break;
+                                    }
+                                }
+                                dataEntry = dataEntry->fParent;
+                                uprv_strcpy(pathBuf, keyPath);
+                                myPath = pathBuf;
+                            } while(r == RES_BOGUS && dataEntry != NULL);
+                            if(r == RES_BOGUS) {
+                                *status = U_MISSING_RESOURCE_ERROR;
+                                result = resB;
+                            }
+                            if(pathBuf != stackPath) {
+                                uprv_free(pathBuf);
+                            }
+                        }
+                    } else { /* we failed to open the resource we're aliasing to */
+                        *status = intStatus;
+                    }
+                    if(chAlias != stackAlias) {
+                        uprv_free(chAlias);
+                    }
+                    if(mainRes != result) {
+                        ures_close(mainRes);
+                    }
+                    return result;
+                }
+            } else {
+                /* bad alias, should be an error */ 
+                *status = U_ILLEGAL_ARGUMENT_ERROR;
+                return resB;
+            }
+        } else {
+            *status = U_TOO_MANY_ALIASES_ERROR;
+            return resB;
+        }
+    }
+    if(resB == NULL) {
+        resB = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
+        /* test for NULL */
+        if (resB == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return NULL;
+        }
+        ures_setIsStackObject(resB, FALSE);
+        resB->fResPath = NULL;
+        resB->fResPathLen = 0;
+    } else {
+        if(resB->fData != NULL) {
+            entryClose(resB->fData);
+        }
+        if(resB->fVersion != NULL) {
+            uprv_free(resB->fVersion);
+        }
+        /* 
+        weiv: if stack object was passed in, it doesn't really need to be reinited,
+        since the purpose of initing is to remove stack junk. However, at this point 
+        we would not do anything to an allocated object, so stack object should be
+        treated the same
+        */
+        /*
+        if(ures_isStackObject(resB) != FALSE) {
+        ures_initStackObject(resB);
+        }
+        */
+        if(parent != resB) {
+            ures_freeResPath(resB);
+        }
+    }
+    resB->fData = realData;
+    entryIncrease(resB->fData);
+    resB->fHasFallback = FALSE;
+    resB->fIsTopLevel = FALSE;
+    resB->fIndex = -1;
+    resB->fKey = key; 
+    /*resB->fParentRes = parent;*/
+    resB->fTopLevelData = parent->fTopLevelData;
+    if(parent->fResPath && parent != resB) {
+        ures_appendResPath(resB, parent->fResPath, parent->fResPathLen, status);
+    }
+    if(key != NULL) {
+        ures_appendResPath(resB, key, (int32_t)uprv_strlen(key), status);
+        if(resB->fResPath[resB->fResPathLen-1] != RES_PATH_SEPARATOR) {
+            ures_appendResPath(resB, RES_PATH_SEPARATOR_S, 1, status);
+        }
+    } else if(idx >= 0) {
+        char buf[256];
+        int32_t len = T_CString_integerToString(buf, idx, 10);
+        ures_appendResPath(resB, buf, len, status);
+        if(resB->fResPath[resB->fResPathLen-1] != RES_PATH_SEPARATOR) {
+            ures_appendResPath(resB, RES_PATH_SEPARATOR_S, 1, status);
+        }
+    }
+    /* Make sure that Purify doesn't complain about uninitialized memory copies. */
+    {
+        int32_t usedLen = ((resB->fResBuf == resB->fResPath) ? resB->fResPathLen : 0);
+        uprv_memset(resB->fResBuf + usedLen, 0, sizeof(resB->fResBuf) - usedLen);
+    }
+
+    resB->fVersion = NULL;
+    resB->fRes = r;
+    /*resB->fParent = parent->fRes;*/
+    uprv_memmove(&resB->fResData, rdata, sizeof(ResourceData));
+    resB->fSize = res_countArrayItems(&(resB->fResData), resB->fRes);
+    return resB;
+}
+
+UResourceBundle *ures_copyResb(UResourceBundle *r, const UResourceBundle *original, UErrorCode *status) {
+    UBool isStackObject;
+    if(U_FAILURE(*status) || r == original) {
+        return r;
+    }
+    if(original != NULL) {
+        if(r == NULL) {
+            isStackObject = FALSE;
+            r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
+            /* test for NULL */
+            if (r == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                return NULL;
+            }
+        } else {
+            isStackObject = ures_isStackObject(r);
+            ures_closeBundle(r, FALSE);
+        }
+        uprv_memcpy(r, original, sizeof(UResourceBundle));
+        r->fResPath = NULL;
+        r->fResPathLen = 0;
+        if(original->fResPath) {
+            ures_appendResPath(r, original->fResPath, original->fResPathLen, status);
+        }
+        ures_setIsStackObject(r, isStackObject);
+        if(r->fData != NULL) {
+            entryIncrease(r->fData);
+        }
+    }
+    return r;
+}
+
+/**
+ * Functions to retrieve data from resource bundles.
+ */
+
+U_CAPI const UChar* U_EXPORT2 ures_getString(const UResourceBundle* resB, int32_t* len, UErrorCode* status) {
+    const UChar *s;
+    if (status==NULL || U_FAILURE(*status)) {
+        return NULL;
+    }
+    if(resB == NULL) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+    s = res_getString(&(resB->fResData), resB->fRes, len);
+    if (s == NULL) {
+        *status = U_RESOURCE_TYPE_MISMATCH;
+    }
+    return s;
+}
+
+static const char *
+ures_toUTF8String(const UChar *s16, int32_t length16,
+                  char *dest, int32_t *pLength,
+                  UBool forceCopy,
+                  UErrorCode *status) {
+    int32_t capacity;
+
+    if (U_FAILURE(*status)) {
+        return NULL;
+    }
+    if (pLength != NULL) {
+        capacity = *pLength;
+    } else {
+        capacity = 0;
+    }
+    if (capacity < 0 || (capacity > 0 && dest == NULL)) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    if (length16 == 0) {
+        /* empty string, return as read-only pointer */
+        if (pLength != NULL) {
+            *pLength = 0;
+        }
+        if (forceCopy) {
+            u_terminateChars(dest, capacity, 0, status);
+            return dest;
+        } else {
+            return "";
+        }
+    } else {
+        /* We need to transform the string to the destination buffer. */
+        if (capacity < length16) {
+            /* No chance for the string to fit. Pure preflighting. */
+            return u_strToUTF8(NULL, 0, pLength, s16, length16, status);
+        }
+        if (!forceCopy && (length16 <= 0x2aaaaaaa)) {
+            /*
+             * We know the string will fit into dest because each UChar turns
+             * into at most three UTF-8 bytes. Fill the latter part of dest
+             * so that callers do not expect to use dest as a string pointer,
+             * hopefully leading to more robust code for when resource bundles
+             * may store UTF-8 natively.
+             * (In which case dest would not be used at all.)
+             *
+             * We do not do this if forceCopy=TRUE because then the caller
+             * expects the string to start exactly at dest.
+             *
+             * The test above for <= 0x2aaaaaaa prevents overflows.
+             * The +1 is for the NUL terminator.
+             */
+            int32_t maxLength = 3 * length16 + 1;
+            if (capacity > maxLength) {
+                dest += capacity - maxLength;
+                capacity = maxLength;
+            }
+        }
+        return u_strToUTF8(dest, capacity, pLength, s16, length16, status);
+    }
+}
+
+U_CAPI const char * U_EXPORT2
+ures_getUTF8String(const UResourceBundle *resB,
+                   char *dest, int32_t *pLength,
+                   UBool forceCopy,
+                   UErrorCode *status) {
+    int32_t length16;
+    const UChar *s16 = ures_getString(resB, &length16, status);
+    return ures_toUTF8String(s16, length16, dest, pLength, forceCopy, status);
+}
+
+U_CAPI const uint8_t* U_EXPORT2 ures_getBinary(const UResourceBundle* resB, int32_t* len, 
+                                               UErrorCode*               status) {
+  const uint8_t *p;
+  if (status==NULL || U_FAILURE(*status)) {
+    return NULL;
+  }
+  if(resB == NULL) {
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+    return NULL;
+  }
+  p = res_getBinary(&(resB->fResData), resB->fRes, len);
+  if (p == NULL) {
+    *status = U_RESOURCE_TYPE_MISMATCH;
+  }
+  return p;
+}
+
+U_CAPI const int32_t* U_EXPORT2 ures_getIntVector(const UResourceBundle* resB, int32_t* len, 
+                                                   UErrorCode*               status) {
+  const int32_t *p;
+  if (status==NULL || U_FAILURE(*status)) {
+    return NULL;
+  }
+  if(resB == NULL) {
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+    return NULL;
+  }
+  p = res_getIntVector(&(resB->fResData), resB->fRes, len);
+  if (p == NULL) {
+    *status = U_RESOURCE_TYPE_MISMATCH;
+  }
+  return p;
+}
+
+/* this function returns a signed integer */ 
+/* it performs sign extension */
+U_CAPI int32_t U_EXPORT2 ures_getInt(const UResourceBundle* resB, UErrorCode *status) {
+  if (status==NULL || U_FAILURE(*status)) {
+    return 0xffffffff;
+  }
+  if(resB == NULL) {
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+    return 0xffffffff;
+  }
+  if(RES_GET_TYPE(resB->fRes) != URES_INT) {
+    *status = U_RESOURCE_TYPE_MISMATCH;
+    return 0xffffffff;
+  }
+  return RES_GET_INT(resB->fRes);
+}
+
+U_CAPI uint32_t U_EXPORT2 ures_getUInt(const UResourceBundle* resB, UErrorCode *status) {
+  if (status==NULL || U_FAILURE(*status)) {
+    return 0xffffffff;
+  }
+  if(resB == NULL) {
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+    return 0xffffffff;
+  }
+  if(RES_GET_TYPE(resB->fRes) != URES_INT) {
+    *status = U_RESOURCE_TYPE_MISMATCH;
+    return 0xffffffff;
+  }
+  return RES_GET_UINT(resB->fRes);
+}
+
+U_CAPI UResType U_EXPORT2 ures_getType(const UResourceBundle *resB) {
+  if(resB == NULL) {
+    return URES_NONE;
+  }
+  return res_getPublicType(resB->fRes);
+}
+
+U_CAPI const char * U_EXPORT2 ures_getKey(const UResourceBundle *resB) {
+  if(resB == NULL) {
+    return NULL;
+  }
+  
+  return(resB->fKey);
+}
+
+U_CAPI int32_t U_EXPORT2 ures_getSize(const UResourceBundle *resB) {
+  if(resB == NULL) {
+    return 0;
+  }
+  
+  return resB->fSize;
+}
+
+static const UChar* ures_getStringWithAlias(const UResourceBundle *resB, Resource r, int32_t sIndex, int32_t *len, UErrorCode *status) {
+  if(RES_GET_TYPE(r) == URES_ALIAS) {
+    const UChar* result = 0;
+    UResourceBundle *tempRes = ures_getByIndex(resB, sIndex, NULL, status);
+    result = ures_getString(tempRes, len, status);
+    ures_close(tempRes);
+    return result;
+  } else {
+    return res_getString(&(resB->fResData), r, len); 
+  }
+}
+
+U_CAPI void U_EXPORT2 ures_resetIterator(UResourceBundle *resB){
+  if(resB == NULL) {
+    return;
+  }
+  resB->fIndex = -1;
+}
+
+U_CAPI UBool U_EXPORT2 ures_hasNext(const UResourceBundle *resB) {
+  if(resB == NULL) {
+    return FALSE;
+  }
+  return (UBool)(resB->fIndex < resB->fSize-1);
+}
+
+U_CAPI const UChar* U_EXPORT2 ures_getNextString(UResourceBundle *resB, int32_t* len, const char ** key, UErrorCode *status) {
+  Resource r = RES_BOGUS;
+  
+  if (status==NULL || U_FAILURE(*status)) {
+    return NULL;
+  }
+  if(resB == NULL) {
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+    return NULL;
+  }
+  
+  if(resB->fIndex == resB->fSize-1) {
+    *status = U_INDEX_OUTOFBOUNDS_ERROR;
+  } else {
+    resB->fIndex++;
+    switch(RES_GET_TYPE(resB->fRes)) {
+    case URES_STRING:
+    case URES_STRING_V2:
+      return res_getString(&(resB->fResData), resB->fRes, len); 
+    case URES_TABLE:
+    case URES_TABLE16:
+    case URES_TABLE32:
+      r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, resB->fIndex, key);
+      if(r == RES_BOGUS && resB->fHasFallback) {
+        /* TODO: do the fallback */
+      }
+      return ures_getStringWithAlias(resB, r, resB->fIndex, len, status);
+    case URES_ARRAY:
+    case URES_ARRAY16:
+      r = res_getArrayItem(&(resB->fResData), resB->fRes, resB->fIndex);
+      if(r == RES_BOGUS && resB->fHasFallback) {
+        /* TODO: do the fallback */
+      }
+      return ures_getStringWithAlias(resB, r, resB->fIndex, len, status);
+    case URES_ALIAS:
+      return ures_getStringWithAlias(resB, resB->fRes, resB->fIndex, len, status);
+    case URES_INT:
+    case URES_BINARY:
+    case URES_INT_VECTOR:
+        *status = U_RESOURCE_TYPE_MISMATCH;
+    default:
+      return NULL;
+    }
+  }
+
+  return NULL;
+}
+
+U_CAPI UResourceBundle* U_EXPORT2 ures_getNextResource(UResourceBundle *resB, UResourceBundle *fillIn, UErrorCode *status) {
+    const char *key = NULL;
+    Resource r = RES_BOGUS;
+
+    if (status==NULL || U_FAILURE(*status)) {
+            /*return NULL;*/
+            return fillIn;
+    }
+    if(resB == NULL) {
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+            /*return NULL;*/
+            return fillIn;
+    }
+
+    if(resB->fIndex == resB->fSize-1) {
+      *status = U_INDEX_OUTOFBOUNDS_ERROR;
+      /*return NULL;*/
+    } else {
+        resB->fIndex++;
+        switch(RES_GET_TYPE(resB->fRes)) {
+        case URES_INT:
+        case URES_BINARY:
+        case URES_STRING:
+        case URES_STRING_V2:
+        case URES_INT_VECTOR:
+            return ures_copyResb(fillIn, resB, status);
+        case URES_TABLE:
+        case URES_TABLE16:
+        case URES_TABLE32:
+            r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, resB->fIndex, &key);
+            if(r == RES_BOGUS && resB->fHasFallback) {
+                /* TODO: do the fallback */
+            }
+            return init_resb_result(&(resB->fResData), r, key, resB->fIndex, resB->fData, resB, 0, fillIn, status);
+        case URES_ARRAY:
+        case URES_ARRAY16:
+            r = res_getArrayItem(&(resB->fResData), resB->fRes, resB->fIndex);
+            if(r == RES_BOGUS && resB->fHasFallback) {
+                /* TODO: do the fallback */
+            }
+            return init_resb_result(&(resB->fResData), r, key, resB->fIndex, resB->fData, resB, 0, fillIn, status);
+        default:
+            /*return NULL;*/
+            return fillIn;
+        }
+    }
+    /*return NULL;*/
+    return fillIn;
+}
+
+U_CAPI UResourceBundle* U_EXPORT2 ures_getByIndex(const UResourceBundle *resB, int32_t indexR, UResourceBundle *fillIn, UErrorCode *status) {
+    const char* key = NULL;
+    Resource r = RES_BOGUS;
+
+    if (status==NULL || U_FAILURE(*status)) {
+        /*return NULL;*/
+        return fillIn;
+    }
+    if(resB == NULL) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        /*return NULL;*/
+        return fillIn;
+    }
+
+    if(indexR >= 0 && resB->fSize > indexR) {
+        switch(RES_GET_TYPE(resB->fRes)) {
+        case URES_INT:
+        case URES_BINARY:
+        case URES_STRING:
+        case URES_STRING_V2:
+        case URES_INT_VECTOR:
+            return ures_copyResb(fillIn, resB, status);
+        case URES_TABLE:
+        case URES_TABLE16:
+        case URES_TABLE32:
+            r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, indexR, &key);
+            if(r == RES_BOGUS && resB->fHasFallback) {
+                /* TODO: do the fallback */
+            }
+            return init_resb_result(&(resB->fResData), r, key, indexR, resB->fData, resB, 0, fillIn, status);
+        case URES_ARRAY:
+        case URES_ARRAY16:
+            r = res_getArrayItem(&(resB->fResData), resB->fRes, indexR);
+            if(r == RES_BOGUS && resB->fHasFallback) {
+                /* TODO: do the fallback */
+            }
+            return init_resb_result(&(resB->fResData), r, key, indexR, resB->fData, resB, 0, fillIn, status);
+        default:
+            /*return NULL;*/
+            return fillIn;
+        }
+    } else {
+        *status = U_MISSING_RESOURCE_ERROR;
+    }
+    /*return NULL;*/
+    return fillIn;
+}
+
+U_CAPI const UChar* U_EXPORT2 ures_getStringByIndex(const UResourceBundle *resB, int32_t indexS, int32_t* len, UErrorCode *status) {
+    const char* key = NULL;
+    Resource r = RES_BOGUS;
+
+    if (status==NULL || U_FAILURE(*status)) {
+        return NULL;
+    }
+    if(resB == NULL) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    if(indexS >= 0 && resB->fSize > indexS) {
+        switch(RES_GET_TYPE(resB->fRes)) {
+        case URES_STRING:
+        case URES_STRING_V2:
+            return res_getString(&(resB->fResData), resB->fRes, len);
+        case URES_TABLE:
+        case URES_TABLE16:
+        case URES_TABLE32:
+            r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, indexS, &key);
+            if(r == RES_BOGUS && resB->fHasFallback) {
+                /* TODO: do the fallback */
+            }
+            return ures_getStringWithAlias(resB, r, indexS, len, status);
+        case URES_ARRAY:
+        case URES_ARRAY16:
+            r = res_getArrayItem(&(resB->fResData), resB->fRes, indexS);
+            if(r == RES_BOGUS && resB->fHasFallback) {
+                /* TODO: do the fallback */
+            }
+            return ures_getStringWithAlias(resB, r, indexS, len, status);
+        case URES_ALIAS:
+            return ures_getStringWithAlias(resB, resB->fRes, indexS, len, status);
+        case URES_INT:
+        case URES_BINARY:
+        case URES_INT_VECTOR:
+            *status = U_RESOURCE_TYPE_MISMATCH;
+            break;
+        default:
+          /* must not occur */
+          *status = U_INTERNAL_PROGRAM_ERROR;
+          break;
+        }
+    } else {
+        *status = U_MISSING_RESOURCE_ERROR;
+    }
+    return NULL;
+}
+
+U_CAPI const char * U_EXPORT2
+ures_getUTF8StringByIndex(const UResourceBundle *resB,
+                          int32_t idx,
+                          char *dest, int32_t *pLength,
+                          UBool forceCopy,
+                          UErrorCode *status) {
+    int32_t length16;
+    const UChar *s16 = ures_getStringByIndex(resB, idx, &length16, status);
+    return ures_toUTF8String(s16, length16, dest, pLength, forceCopy, status);
+}
+
+/*U_CAPI const char *ures_getResPath(UResourceBundle *resB) {
+  return resB->fResPath;
+}*/
+
+U_CAPI UResourceBundle* U_EXPORT2
+ures_findResource(const char* path, UResourceBundle *fillIn, UErrorCode *status) 
+{
+  UResourceBundle *first = NULL; 
+  UResourceBundle *result = fillIn;
+  char *packageName = NULL;
+  char *pathToResource = NULL, *save = NULL;
+  char *locale = NULL, *localeEnd = NULL;
+  int32_t length;
+
+  if(status == NULL || U_FAILURE(*status)) {
+    return result;
+  }
+
+  length = (int32_t)(uprv_strlen(path)+1);
+  save = pathToResource = (char *)uprv_malloc(length*sizeof(char));
+  /* test for NULL */
+  if(pathToResource == NULL) {
+    *status = U_MEMORY_ALLOCATION_ERROR;
+    return result;
+  }
+  uprv_memcpy(pathToResource, path, length);
+
+  locale = pathToResource;
+  if(*pathToResource == RES_PATH_SEPARATOR) { /* there is a path specification */
+    pathToResource++;
+    packageName = pathToResource;
+    pathToResource = uprv_strchr(pathToResource, RES_PATH_SEPARATOR);
+    if(pathToResource == NULL) {
+      *status = U_ILLEGAL_ARGUMENT_ERROR;
+    } else {
+      *pathToResource = 0;
+      locale = pathToResource+1;
+    }
+  }
+
+  localeEnd = uprv_strchr(locale, RES_PATH_SEPARATOR);
+  if(localeEnd != NULL) {
+    *localeEnd = 0;
+  }
+
+  first = ures_open(packageName, locale, status);
+
+  if(U_SUCCESS(*status)) {
+    if(localeEnd) {
+      result = ures_findSubResource(first, localeEnd+1, fillIn, status);
+    } else {
+      result = ures_copyResb(fillIn, first, status);
+    }
+    ures_close(first);
+  }
+  uprv_free(save);
+  return result;
+}
+
+U_CAPI UResourceBundle* U_EXPORT2
+ures_findSubResource(const UResourceBundle *resB, char* path, UResourceBundle *fillIn, UErrorCode *status) 
+{
+  Resource res = RES_BOGUS;
+  UResourceBundle *result = fillIn;
+  const char *key;
+
+  if(status == NULL || U_FAILURE(*status)) {
+    return result;
+  }
+
+  /* here we do looping and circular alias checking */
+  /* this loop is here because aliasing is resolved on this level, not on res level */
+  /* so, when we encounter an alias, it is not an aggregate resource, so we return */
+  do {
+    res = res_findResource(&(resB->fResData), resB->fRes, &path, &key); 
+    if(res != RES_BOGUS) {
+        result = init_resb_result(&(resB->fResData), res, key, -1, resB->fData, resB, 0, fillIn, status);
+        resB = result;
+    } else {
+        *status = U_MISSING_RESOURCE_ERROR;
+        break;
+    }
+  } while(*path); /* there is more stuff in the path */
+
+  return result;
+}
+U_INTERNAL const UChar* U_EXPORT2 
+ures_getStringByKeyWithFallback(const UResourceBundle *resB, 
+                                const char* inKey, 
+                                int32_t* len,
+                                UErrorCode *status) {
+
+    UResourceBundle stack;
+    const UChar* retVal = NULL;
+    ures_initStackObject(&stack);
+    ures_getByKeyWithFallback(resB, inKey, &stack, status);
+    retVal = ures_getString(&stack, len, status);
+    ures_close(&stack);
+    return retVal;
+}
+
+U_CAPI UResourceBundle* U_EXPORT2 
+ures_getByKeyWithFallback(const UResourceBundle *resB, 
+                          const char* inKey, 
+                          UResourceBundle *fillIn, 
+                          UErrorCode *status) {
+    Resource res = RES_BOGUS, rootRes = RES_BOGUS;
+    /*UResourceDataEntry *realData = NULL;*/
+    const char *key = inKey;
+    UResourceBundle *helper = NULL;
+    UResType type;
+
+    if (status==NULL || U_FAILURE(*status)) {
+        return fillIn;
+    }
+    if(resB == NULL) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return fillIn;
+    }
+
+    type = RES_GET_TYPE(resB->fRes);
+    if(URES_IS_TABLE(type)) {
+        int32_t t;
+        res = res_getTableItemByKey(&(resB->fResData), resB->fRes, &t, &key);
+        if(res == RES_BOGUS) {
+            UResourceDataEntry *dataEntry = resB->fData;
+            char path[256];
+            char* myPath = path;
+            const char* resPath = resB->fResPath;
+            int32_t len = resB->fResPathLen;
+
+            while(res == RES_BOGUS && dataEntry->fParent != NULL) { /* Otherwise, we'll look in parents */
+                dataEntry = dataEntry->fParent;
+                rootRes = dataEntry->fData.rootRes;
+
+                if(dataEntry->fBogus == U_ZERO_ERROR) {
+                    uprv_strncpy(path, resPath, len);
+                    uprv_strcpy(path+len, inKey);
+                    myPath = path;
+                    key = inKey;
+                    do {
+                        res = res_findResource(&(dataEntry->fData), rootRes, &myPath, &key);
+                        if (RES_GET_TYPE(res) == URES_ALIAS && *myPath) {
+                            /* We hit an alias, but we didn't finish following the path. */
+                            helper = init_resb_result(&(dataEntry->fData), res, NULL, -1, dataEntry, resB, 0, helper, status); 
+                            /*helper = init_resb_result(&(dataEntry->fData), res, inKey, -1, dataEntry, resB, 0, helper, status);*/
+                            if(helper) {
+                              dataEntry = helper->fData;
+                              rootRes = helper->fRes;
+                              resPath = helper->fResPath;
+                              len = helper->fResPathLen;
+
+                            } else {
+                              break;
+                            }
+                        }
+                    } while(*myPath); /* Continue until the whole path is consumed */
+                }
+            }
+            /*const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status);*/
+            if(res != RES_BOGUS) {
+              /* check if resB->fResPath gives the right name here */
+                if(uprv_strcmp(dataEntry->fName, uloc_getDefault())==0 || uprv_strcmp(dataEntry->fName, kRootLocaleName)==0) {
+                    *status = U_USING_DEFAULT_WARNING;
+                } else {
+                    *status = U_USING_FALLBACK_WARNING;
+                }
+
+                fillIn = init_resb_result(&(dataEntry->fData), res, inKey, -1, dataEntry, resB, 0, fillIn, status);
+            } else {
+                *status = U_MISSING_RESOURCE_ERROR;
+            }
+        } else {
+            fillIn = init_resb_result(&(resB->fResData), res, key, -1, resB->fData, resB, 0, fillIn, status);
+        }
+    } 
+    else {
+        *status = U_RESOURCE_TYPE_MISMATCH;
+    }
+    ures_close(helper);
+    return fillIn;
+}
+
+
+U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resB, const char* inKey, UResourceBundle *fillIn, UErrorCode *status) {
+    Resource res = RES_BOGUS;
+    UResourceDataEntry *realData = NULL;
+    const char *key = inKey;
+    UResType type;
+
+    if (status==NULL || U_FAILURE(*status)) {
+        return fillIn;
+    }
+    if(resB == NULL) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return fillIn;
+    }
+
+    type = RES_GET_TYPE(resB->fRes);
+    if(URES_IS_TABLE(type)) {
+        int32_t t;
+        res = res_getTableItemByKey(&(resB->fResData), resB->fRes, &t, &key);
+        if(res == RES_BOGUS) {
+            key = inKey;
+            if(resB->fHasFallback == TRUE) {
+                const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status);
+                if(U_SUCCESS(*status)) {
+                  /* check if resB->fResPath gives the right name here */
+                    return init_resb_result(rd, res, key, -1, realData, resB, 0, fillIn, status);
+                } else {
+                    *status = U_MISSING_RESOURCE_ERROR;
+                }
+            } else {
+                *status = U_MISSING_RESOURCE_ERROR;
+            }
+        } else {
+            return init_resb_result(&(resB->fResData), res, key, -1, resB->fData, resB, 0, fillIn, status);
+        }
+    } 
+#if 0
+    /* this is a kind of TODO item. If we have an array with an index table, we could do this. */
+    /* not currently */
+    else if(RES_GET_TYPE(resB->fRes) == URES_ARRAY && resB->fHasFallback == TRUE) {
+        /* here should go a first attempt to locate the key using index table */
+        const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status);
+        if(U_SUCCESS(*status)) {
+            return init_resb_result(rd, res, key, realData, resB, fillIn, status);
+        } else {
+            *status = U_MISSING_RESOURCE_ERROR;
+        }
+    }
+#endif    
+    else {
+        *status = U_RESOURCE_TYPE_MISMATCH;
+    }
+    return fillIn;
+}
+
+U_CAPI const UChar* U_EXPORT2 ures_getStringByKey(const UResourceBundle *resB, const char* inKey, int32_t* len, UErrorCode *status) {
+    Resource res = RES_BOGUS;
+    UResourceDataEntry *realData = NULL;
+    const char* key = inKey;
+    UResType type;
+
+    if (status==NULL || U_FAILURE(*status)) {
+        return NULL;
+    }
+    if(resB == NULL) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    type = RES_GET_TYPE(resB->fRes);
+    if(URES_IS_TABLE(type)) {
+        int32_t t=0;
+
+        res = res_getTableItemByKey(&(resB->fResData), resB->fRes, &t, &key);
+
+        if(res == RES_BOGUS) {
+            key = inKey;
+            if(resB->fHasFallback == TRUE) {
+                const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status);
+                if(U_SUCCESS(*status)) {
+                    switch (RES_GET_TYPE(res)) {
+                    case URES_STRING:
+                    case URES_STRING_V2:
+                        return res_getString(rd, res, len);
+                    case URES_ALIAS:
+                      {
+                        const UChar* result = 0;
+                        UResourceBundle *tempRes = ures_getByKey(resB, inKey, NULL, status);
+                        result = ures_getString(tempRes, len, status);
+                        ures_close(tempRes);
+                        return result;
+                      }
+                    default:
+                        *status = U_RESOURCE_TYPE_MISMATCH;
+                    }
+                } else {
+                    *status = U_MISSING_RESOURCE_ERROR;
+                }
+            } else {
+                *status = U_MISSING_RESOURCE_ERROR;
+            }
+        } else {
+            switch (RES_GET_TYPE(res)) {
+            case URES_STRING:
+            case URES_STRING_V2:
+                return res_getString(&(resB->fResData), res, len);
+            case URES_ALIAS:
+              {
+                const UChar* result = 0;
+                UResourceBundle *tempRes = ures_getByKey(resB, inKey, NULL, status);
+                result = ures_getString(tempRes, len, status);
+                ures_close(tempRes);
+                return result;
+              }
+            default:
+                *status = U_RESOURCE_TYPE_MISMATCH;
+            }
+        }
+    } 
+#if 0 
+    /* this is a kind of TODO item. If we have an array with an index table, we could do this. */
+    /* not currently */   
+    else if(RES_GET_TYPE(resB->fRes) == URES_ARRAY && resB->fHasFallback == TRUE) {
+        /* here should go a first attempt to locate the key using index table */
+        const ResourceData *rd = getFallbackData(resB, &key, &realData, &res, status);
+        if(U_SUCCESS(*status)) {
+            return res_getString(rd, res, len);
+        } else {
+            *status = U_MISSING_RESOURCE_ERROR;
+        }
+    } 
+#endif    
+    else {
+        *status = U_RESOURCE_TYPE_MISMATCH;
+    }
+    return NULL;
+}
+
+U_CAPI const char * U_EXPORT2
+ures_getUTF8StringByKey(const UResourceBundle *resB,
+                        const char *key,
+                        char *dest, int32_t *pLength,
+                        UBool forceCopy,
+                        UErrorCode *status) {
+    int32_t length16;
+    const UChar *s16 = ures_getStringByKey(resB, key, &length16, status);
+    return ures_toUTF8String(s16, length16, dest, pLength, forceCopy, status);
+}
+
+/* TODO: clean from here down */
+
+/**
+ *  INTERNAL: Get the name of the first real locale (not placeholder) 
+ *  that has resource bundle data.
+ */
+U_INTERNAL const char*  U_EXPORT2
+ures_getLocaleInternal(const UResourceBundle* resourceBundle, UErrorCode* status)
+{
+    if (status==NULL || U_FAILURE(*status)) {
+        return NULL;
+    }
+    if (!resourceBundle) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    } else {
+      return resourceBundle->fData->fName;
+    }
+}
+
+U_CAPI const char* U_EXPORT2 
+ures_getLocale(const UResourceBundle* resourceBundle, 
+               UErrorCode* status)
+{
+  return ures_getLocaleInternal(resourceBundle, status);
+}
+
+
+U_CAPI const char* U_EXPORT2 
+ures_getLocaleByType(const UResourceBundle* resourceBundle, 
+                     ULocDataLocaleType type, 
+                     UErrorCode* status) {
+    if (status==NULL || U_FAILURE(*status)) {
+        return NULL;
+    }
+    if (!resourceBundle) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    } else {
+        switch(type) {
+        case ULOC_ACTUAL_LOCALE:
+            return resourceBundle->fData->fName;
+        case ULOC_VALID_LOCALE:
+            return resourceBundle->fTopLevelData->fName;
+        case ULOC_REQUESTED_LOCALE:
+            return NULL;
+        default:
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+            return NULL;
+        }
+    }
+}
+
+U_CFUNC const char* ures_getName(const UResourceBundle* resB) {
+  if(resB == NULL) {
+    return NULL;
+  }
+
+  return resB->fData->fName;
+}
+
+#ifdef URES_DEBUG
+U_CFUNC const char* ures_getPath(const UResourceBundle* resB) {
+  if(resB == NULL) {
+    return NULL;
+  }
+
+  return resB->fData->fPath;
+}
+#endif
+
+/* OLD API implementation */
+
+/**
+ *  API: This function is used to open a resource bundle 
+ *  proper fallback chaining is executed while initialization. 
+ *  The result is stored in cache for later fallback search.
+ */
+U_CAPI void  U_EXPORT2
+ures_openFillIn(UResourceBundle *r, const char* path,
+                    const char* localeID, UErrorCode* status) {
+    if(r == NULL) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+    } else {
+        UResourceDataEntry *firstData;
+        UBool isStackObject = ures_isStackObject(r);
+
+        ures_closeBundle(r, FALSE);
+        uprv_memset(r, 0, sizeof(UResourceBundle));
+        ures_setIsStackObject(r, isStackObject);
+        r->fHasFallback = TRUE;
+        r->fIsTopLevel = TRUE;
+        r->fIndex = -1;
+        r->fData = entryOpen(path, localeID, status);
+        if(U_FAILURE(*status)) {
+            return;
+        }
+        /* this is a quick fix to get regular data in bundle - until construction is cleaned up */
+        firstData = r->fData;
+        while(firstData->fBogus != U_ZERO_ERROR && firstData->fParent != NULL) {
+            firstData = firstData->fParent;
+        }
+        uprv_memcpy(&r->fResData, &firstData->fData, sizeof(ResourceData));
+        r->fHasFallback=(UBool)!r->fResData.noFallback;
+        r->fRes = r->fResData.rootRes;
+        r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
+        r->fTopLevelData = r->fData;
+    }
+}
+
+U_CAPI UResourceBundle*  U_EXPORT2
+ures_open(const char* path,
+                    const char* localeID,
+                    UErrorCode* status)
+{
+    char canonLocaleID[100];
+    UResourceDataEntry *hasData = NULL;
+    UResourceBundle *r;
+
+    if(status == NULL || U_FAILURE(*status)) {
+        return NULL;
+    }
+
+    /* first "canonicalize" the locale ID */
+    uloc_getBaseName(localeID, canonLocaleID, sizeof(canonLocaleID), status);
+    if(U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
+    if(r == NULL) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+
+    uprv_memset(r, 0, sizeof(UResourceBundle));
+    r->fHasFallback = TRUE;
+    r->fIsTopLevel = TRUE;
+    ures_setIsStackObject(r, FALSE);
+    r->fIndex = -1;
+    r->fData = entryOpen(path, canonLocaleID, status);
+    if(U_FAILURE(*status)) {
+        uprv_free(r);
+        return NULL;
+    }
+    r->fTopLevelData = r->fData;
+
+    hasData = r->fData;
+    while(hasData->fBogus != U_ZERO_ERROR) {
+        hasData = hasData->fParent;
+        if(hasData == NULL) {
+          /* This can happen only if fallback chain gets broken by an act of God */
+          /* TODO: this unlikely to happen, consider removing it */
+            entryClose(r->fData);
+            uprv_free(r);
+            *status = U_MISSING_RESOURCE_ERROR;
+            return NULL;
+        }
+    }
+
+    uprv_memcpy(&r->fResData, &hasData->fData, sizeof(ResourceData));
+    r->fHasFallback=(UBool)!r->fResData.noFallback;
+    r->fRes = r->fResData.rootRes;
+    r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
+    /*
+    if(r->fData->fPath != NULL) {
+      ures_setResPath(r, r->fData->fPath);
+      ures_appendResPath(r, RES_PATH_PACKAGE_S);
+      ures_appendResPath(r, r->fData->fName);
+    } else {
+      ures_setResPath(r, r->fData->fName);
+    }
+    */
+
+
+    return r;
+}
+
+/**
+ *  Opens a resource bundle without "canonicalizing" the locale name. No fallback will be performed 
+ *  or sought. However, alias substitution will happen!
+ */
+U_CAPI UResourceBundle*  U_EXPORT2
+ures_openDirect(const char* path, const char* localeID, UErrorCode* status) {
+    UResourceBundle *r;
+    UErrorCode subStatus = U_ZERO_ERROR;
+
+    if(status == NULL || U_FAILURE(*status)) {
+        return NULL;
+    }
+
+    r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
+    if(r == NULL) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+
+    r->fHasFallback = FALSE;
+    r->fIsTopLevel = TRUE;
+    ures_setIsStackObject(r, FALSE);
+    r->fIndex = -1;
+    r->fData = entryOpen(path, localeID, &subStatus);
+    if(U_FAILURE(subStatus)) {
+        *status = subStatus;
+        uprv_free(r);
+        return NULL;
+    }
+    if(subStatus != U_ZERO_ERROR /*r->fData->fBogus != U_ZERO_ERROR*/) {
+      /* we didn't find one we were looking for - so openDirect */
+      /* should fail */
+        entryClose(r->fData);
+        uprv_free(r);
+        *status = U_MISSING_RESOURCE_ERROR;
+        return NULL;
+    }
+
+    r->fKey = NULL;
+    r->fVersion = NULL;
+    uprv_memcpy(&r->fResData, &r->fData->fData, sizeof(ResourceData));
+    /* r->fHasFallback remains FALSE here in ures_openDirect() */
+    r->fRes = r->fResData.rootRes;
+    /*r->fParent = RES_BOGUS;*/
+    r->fSize = res_countArrayItems(&(r->fResData), r->fRes);
+    r->fResPath = NULL;
+    r->fResPathLen = 0;
+    /*r->fParentRes = NULL;*/
+    r->fTopLevelData = r->fData;
+
+    return r;
+}
+
+/**
+ *  API: Counts members. For arrays and tables, returns number of resources.
+ *  For strings, returns 1.
+ */
+U_CAPI int32_t  U_EXPORT2
+ures_countArrayItems(const UResourceBundle* resourceBundle,
+                  const char* resourceKey,
+                  UErrorCode* status)
+{
+    UResourceBundle resData;
+    ures_initStackObject(&resData);
+    if (status==NULL || U_FAILURE(*status)) {
+        return 0;
+    }
+    if(resourceBundle == NULL) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    ures_getByKey(resourceBundle, resourceKey, &resData, status);
+    
+    if(resData.fResData.data != NULL) {
+        int32_t result = res_countArrayItems(&resData.fResData, resData.fRes);
+        ures_close(&resData);
+        return result;
+    } else {
+        *status = U_MISSING_RESOURCE_ERROR;
+        ures_close(&resData);
+        return 0;
+    }
+}
+
+/**
+ * Internal function.
+ * Return the version number associated with this ResourceBundle as a string.
+ *
+ * @param resourceBundle The resource bundle for which the version is checked.
+ * @return  A version number string as specified in the resource bundle or its parent.
+ *          The caller does not own this string.
+ * @see ures_getVersion
+ * @internal
+ */
+U_INTERNAL const char* U_EXPORT2 
+ures_getVersionNumberInternal(const UResourceBundle *resourceBundle)
+{
+    if (!resourceBundle) return NULL;
+
+    if(resourceBundle->fVersion == NULL) {
+
+        /* If the version ID has not been built yet, then do so.  Retrieve */
+        /* the minor version from the file. */
+        UErrorCode status = U_ZERO_ERROR;
+        int32_t minor_len = 0;
+        int32_t len;
+
+        const UChar* minor_version = ures_getStringByKey(resourceBundle, kVersionTag, &minor_len, &status);
+        
+        /* Determine the length of of the final version string.  This is */
+        /* the length of the major part + the length of the separator */
+        /* (==1) + the length of the minor part (+ 1 for the zero byte at */
+        /* the end). */
+
+        len = (minor_len > 0) ? minor_len : 1;
+    
+        /* Allocate the string, and build it up. */
+        /* + 1 for zero byte */
+
+
+        ((UResourceBundle *)resourceBundle)->fVersion = (char *)uprv_malloc(1 + len); 
+        /* Check for null pointer. */
+        if (((UResourceBundle *)resourceBundle)->fVersion == NULL) {
+            return NULL;
+        }
+       
+        if(minor_len > 0) {
+            u_UCharsToChars(minor_version, resourceBundle->fVersion , minor_len);
+            resourceBundle->fVersion[len] =  '\0';
+        }
+        else {
+            uprv_strcpy(resourceBundle->fVersion, kDefaultMinorVersion);
+        }
+    }
+
+    return resourceBundle->fVersion;
+}
+
+U_CAPI const char*  U_EXPORT2
+ures_getVersionNumber(const UResourceBundle*   resourceBundle)
+{
+    return ures_getVersionNumberInternal(resourceBundle);
+}
+
+U_CAPI void U_EXPORT2 ures_getVersion(const UResourceBundle* resB, UVersionInfo versionInfo) {
+    if (!resB) return;
+
+    u_versionFromString(versionInfo, ures_getVersionNumberInternal(resB));
+}
+
+/** Tree support functions *******************************/
+#define INDEX_LOCALE_NAME "res_index"
+#define INDEX_TAG         "InstalledLocales"
+#define DEFAULT_TAG       "default"
+
+#if defined(URES_TREE_DEBUG)
+#include <stdio.h>
+#endif
+
+typedef struct ULocalesContext {
+    UResourceBundle installed;
+    UResourceBundle curr;
+} ULocalesContext;
+
+static void U_CALLCONV
+ures_loc_closeLocales(UEnumeration *enumerator) {
+    ULocalesContext *ctx = (ULocalesContext *)enumerator->context;
+    ures_close(&ctx->curr);
+    ures_close(&ctx->installed);
+    uprv_free(ctx);
+    uprv_free(enumerator);
+}
+
+static int32_t U_CALLCONV
+ures_loc_countLocales(UEnumeration *en, UErrorCode *status) {
+    ULocalesContext *ctx = (ULocalesContext *)en->context;
+    return ures_getSize(&ctx->installed);
+}
+
+static const char* U_CALLCONV 
+ures_loc_nextLocale(UEnumeration* en,
+                    int32_t* resultLength,
+                    UErrorCode* status) {
+    ULocalesContext *ctx = (ULocalesContext *)en->context;
+    UResourceBundle *res = &(ctx->installed);
+    UResourceBundle *k = NULL;
+    const char *result = NULL;
+    int32_t len = 0;
+    if(ures_hasNext(res) && (k = ures_getNextResource(res, &ctx->curr, status))) {
+        result = ures_getKey(k);
+        len = (int32_t)uprv_strlen(result);
+    }
+    if (resultLength) {
+        *resultLength = len;
+    }
+    return result;
+}
+
+static void U_CALLCONV 
+ures_loc_resetLocales(UEnumeration* en, 
+                      UErrorCode* status) {
+    UResourceBundle *res = &((ULocalesContext *)en->context)->installed;
+    ures_resetIterator(res);
+}
+
+
+static const UEnumeration gLocalesEnum = {
+    NULL,
+        NULL,
+        ures_loc_closeLocales,
+        ures_loc_countLocales,
+        uenum_unextDefault,
+        ures_loc_nextLocale,
+        ures_loc_resetLocales
+};
+
+
+U_CAPI UEnumeration* U_EXPORT2
+ures_openAvailableLocales(const char *path, UErrorCode *status)
+{
+    UResourceBundle *idx = NULL;
+    UEnumeration *en = NULL;
+    ULocalesContext *myContext = NULL;
+    
+    if(U_FAILURE(*status)) {
+        return NULL;
+    }
+    myContext = uprv_malloc(sizeof(ULocalesContext));
+    en =  (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
+    if(!en || !myContext) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        uprv_free(en);
+        uprv_free(myContext);
+        return NULL;
+    }
+    uprv_memcpy(en, &gLocalesEnum, sizeof(UEnumeration));
+    
+    ures_initStackObject(&myContext->installed);
+    ures_initStackObject(&myContext->curr);
+    idx = ures_openDirect(path, INDEX_LOCALE_NAME, status);
+    ures_getByKey(idx, INDEX_TAG, &myContext->installed, status);
+    if(U_SUCCESS(*status)) {
+#if defined(URES_TREE_DEBUG)
+        fprintf(stderr, "Got %s::%s::[%s] : %s\n", 
+            path, INDEX_LOCALE_NAME, INDEX_TAG, ures_getKey(&myContext->installed));
+#endif
+        en->context = myContext;
+    } else {
+#if defined(URES_TREE_DEBUG)
+        fprintf(stderr, "%s open failed - %s\n", path, u_errorName(*status));
+#endif
+        ures_close(&myContext->installed);
+        uprv_free(myContext);
+        uprv_free(en);
+        en = NULL;
+    }
+    
+    ures_close(idx);
+    
+    return en;
+}
+
+static UBool isLocaleInList(UEnumeration *locEnum, const char *locToSearch, UErrorCode *status) {
+    const char *loc;
+    while ((loc = uenum_next(locEnum, NULL, status)) != NULL) {
+        if (uprv_strcmp(loc, locToSearch) == 0) {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+U_CAPI int32_t U_EXPORT2
+ures_getFunctionalEquivalent(char *result, int32_t resultCapacity,
+                             const char *path, const char *resName, const char *keyword, const char *locid,
+                             UBool *isAvailable, UBool omitDefault, UErrorCode *status)
+{
+    char kwVal[1024] = ""; /* value of keyword 'keyword' */
+    char defVal[1024] = ""; /* default value for given locale */
+    char defLoc[1024] = ""; /* default value for given locale */
+    char base[1024] = ""; /* base locale */
+    char found[1024];
+    char parent[1024];
+    char full[1024] = "";
+    UResourceBundle bund1, bund2;
+    UResourceBundle *res = NULL;
+    UErrorCode subStatus = U_ZERO_ERROR;
+    int32_t length = 0;
+    if(U_FAILURE(*status)) return 0;
+    uloc_getKeywordValue(locid, keyword, kwVal, 1024-1,&subStatus);
+    if(!uprv_strcmp(kwVal, DEFAULT_TAG)) {
+        kwVal[0]=0;
+    }
+    uloc_getBaseName(locid, base, 1024-1,&subStatus);
+#if defined(URES_TREE_DEBUG)
+    fprintf(stderr, "getFunctionalEquivalent: \"%s\" [%s=%s] in %s - %s\n", 
+            locid, keyword, kwVal, base, u_errorName(subStatus));
+#endif
+    ures_initStackObject(&bund1);
+    ures_initStackObject(&bund2);
+    
+    
+    uprv_strcpy(parent, base);
+    uprv_strcpy(found, base);
+
+    if(isAvailable) { 
+        UEnumeration *locEnum = ures_openAvailableLocales(path, &subStatus);
+        *isAvailable = TRUE;
+        if (U_SUCCESS(subStatus)) {
+            *isAvailable = isLocaleInList(locEnum, parent, &subStatus);
+        }
+        uenum_close(locEnum);
+    }
+
+    if(U_FAILURE(subStatus)) {
+        *status = subStatus;
+        return 0;
+    }
+    
+    do {
+        subStatus = U_ZERO_ERROR;
+        res = ures_open(path, parent, &subStatus);
+        if(((subStatus == U_USING_FALLBACK_WARNING) ||
+            (subStatus == U_USING_DEFAULT_WARNING)) && isAvailable)
+        {
+            *isAvailable = FALSE;
+        }
+        isAvailable = NULL; /* only want to set this the first time around */
+        
+#if defined(URES_TREE_DEBUG)
+        fprintf(stderr, "%s;%s -> %s [%s]\n", path?path:"ICUDATA", parent, u_errorName(subStatus), ures_getLocale(res, &subStatus));
+#endif
+        if(U_FAILURE(subStatus)) {
+            *status = subStatus;
+        } else if(subStatus == U_ZERO_ERROR) {
+            ures_getByKey(res,resName,&bund1, &subStatus);
+            if(subStatus == U_ZERO_ERROR) {
+                const UChar *defUstr;
+                int32_t defLen;
+                /* look for default item */
+#if defined(URES_TREE_DEBUG)
+                fprintf(stderr, "%s;%s : loaded default -> %s\n",
+                    path?path:"ICUDATA", parent, u_errorName(subStatus));
+#endif
+                defUstr = ures_getStringByKey(&bund1, DEFAULT_TAG, &defLen, &subStatus);
+                if(U_SUCCESS(subStatus) && defLen) {
+                    u_UCharsToChars(defUstr, defVal, u_strlen(defUstr));
+#if defined(URES_TREE_DEBUG)
+                    fprintf(stderr, "%s;%s -> default %s=%s,  %s\n", 
+                        path?path:"ICUDATA", parent, keyword, defVal, u_errorName(subStatus));
+#endif
+                    uprv_strcpy(defLoc, parent);
+                    if(kwVal[0]==0) {
+                        uprv_strcpy(kwVal, defVal);
+#if defined(URES_TREE_DEBUG)
+                        fprintf(stderr, "%s;%s -> kwVal =  %s\n", 
+                            path?path:"ICUDATA", parent, keyword, kwVal);
+#endif
+                    }
+                }
+            }
+        }
+        
+        subStatus = U_ZERO_ERROR;
+
+        if (res != NULL) {
+            uprv_strcpy(found, ures_getLocaleByType(res, ULOC_VALID_LOCALE, &subStatus));
+        }
+
+        uloc_getParent(found,parent,sizeof(parent),&subStatus);
+        ures_close(res);
+    } while(!defVal[0] && *found && uprv_strcmp(found, "root") != 0 && U_SUCCESS(*status));
+    
+    /* Now, see if we can find the kwVal collator.. start the search over.. */
+    uprv_strcpy(parent, base);
+    uprv_strcpy(found, base);
+    
+    do {
+        subStatus = U_ZERO_ERROR;
+        res = ures_open(path, parent, &subStatus);
+        if((subStatus == U_USING_FALLBACK_WARNING) && isAvailable) {
+            *isAvailable = FALSE;
+        }
+        isAvailable = NULL; /* only want to set this the first time around */
+        
+#if defined(URES_TREE_DEBUG)
+        fprintf(stderr, "%s;%s -> %s (looking for %s)\n", 
+            path?path:"ICUDATA", parent, u_errorName(subStatus), kwVal);
+#endif
+        if(U_FAILURE(subStatus)) {
+            *status = subStatus;
+        } else if(subStatus == U_ZERO_ERROR) {
+            ures_getByKey(res,resName,&bund1, &subStatus);
+#if defined(URES_TREE_DEBUG)
+/**/ fprintf(stderr,"@%d [%s] %s\n", __LINE__, resName, u_errorName(subStatus));
+#endif
+            if(subStatus == U_ZERO_ERROR) {
+                ures_getByKey(&bund1, kwVal, &bund2, &subStatus);
+#if defined(URES_TREE_DEBUG)
+/**/ fprintf(stderr,"@%d [%s] %s\n", __LINE__, kwVal, u_errorName(subStatus));
+#endif
+                if(subStatus == U_ZERO_ERROR) {
+#if defined(URES_TREE_DEBUG)
+                    fprintf(stderr, "%s;%s -> full0 %s=%s,  %s\n", 
+                        path?path:"ICUDATA", parent, keyword, kwVal, u_errorName(subStatus));
+#endif
+                    uprv_strcpy(full, parent);
+                    if(*full == 0) {
+                        uprv_strcpy(full, "root");
+                    }
+                        /* now, recalculate default kw if need be */
+                        if(uprv_strlen(defLoc) > uprv_strlen(full)) {
+                          const UChar *defUstr;
+                          int32_t defLen;
+                          /* look for default item */
+#if defined(URES_TREE_DEBUG)
+                            fprintf(stderr, "%s;%s -> recalculating Default0\n", 
+                                    path?path:"ICUDATA", full);
+#endif
+                          defUstr = ures_getStringByKey(&bund1, DEFAULT_TAG, &defLen, &subStatus);
+                          if(U_SUCCESS(subStatus) && defLen) {
+                            u_UCharsToChars(defUstr, defVal, u_strlen(defUstr));
+#if defined(URES_TREE_DEBUG)
+                            fprintf(stderr, "%s;%s -> default0 %s=%s,  %s\n", 
+                                    path?path:"ICUDATA", full, keyword, defVal, u_errorName(subStatus));
+#endif
+                            uprv_strcpy(defLoc, full);
+                          }
+                        } /* end of recalculate default KW */
+#if defined(URES_TREE_DEBUG)
+                        else {
+                          fprintf(stderr, "No trim0,  %s <= %s\n", defLoc, full);
+                        }
+#endif
+                } else {
+#if defined(URES_TREE_DEBUG)
+                    fprintf(stderr, "err=%s in %s looking for %s\n", 
+                        u_errorName(subStatus), parent, kwVal);
+#endif
+                }
+            }
+        }
+        
+        subStatus = U_ZERO_ERROR;
+        
+        uprv_strcpy(found, parent);
+        uloc_getParent(found,parent,1023,&subStatus);
+        ures_close(res);
+    } while(!full[0] && *found && U_SUCCESS(*status));
+    
+    if((full[0]==0) && uprv_strcmp(kwVal, defVal)) {
+#if defined(URES_TREE_DEBUG)
+        fprintf(stderr, "Failed to locate kw %s - try default %s\n", kwVal, defVal);
+#endif
+        uprv_strcpy(kwVal, defVal);
+        uprv_strcpy(parent, base);
+        uprv_strcpy(found, base);
+        
+        do { /* search for 'default' named item */
+            subStatus = U_ZERO_ERROR;
+            res = ures_open(path, parent, &subStatus);
+            if((subStatus == U_USING_FALLBACK_WARNING) && isAvailable) {
+                *isAvailable = FALSE;
+            }
+            isAvailable = NULL; /* only want to set this the first time around */
+            
+#if defined(URES_TREE_DEBUG)
+            fprintf(stderr, "%s;%s -> %s (looking for default %s)\n",
+                path?path:"ICUDATA", parent, u_errorName(subStatus), kwVal);
+#endif
+            if(U_FAILURE(subStatus)) {
+                *status = subStatus;
+            } else if(subStatus == U_ZERO_ERROR) {
+                ures_getByKey(res,resName,&bund1, &subStatus);
+                if(subStatus == U_ZERO_ERROR) {
+                    ures_getByKey(&bund1, kwVal, &bund2, &subStatus);
+                    if(subStatus == U_ZERO_ERROR) {
+#if defined(URES_TREE_DEBUG)
+                        fprintf(stderr, "%s;%s -> full1 %s=%s,  %s\n", path?path:"ICUDATA",
+                            parent, keyword, kwVal, u_errorName(subStatus));
+#endif
+                        uprv_strcpy(full, parent);
+                        if(*full == 0) {
+                            uprv_strcpy(full, "root");
+                        }
+                        
+                        /* now, recalculate default kw if need be */
+                        if(uprv_strlen(defLoc) > uprv_strlen(full)) {
+                          const UChar *defUstr;
+                          int32_t defLen;
+                          /* look for default item */
+#if defined(URES_TREE_DEBUG)
+                            fprintf(stderr, "%s;%s -> recalculating Default1\n", 
+                                    path?path:"ICUDATA", full);
+#endif
+                          defUstr = ures_getStringByKey(&bund1, DEFAULT_TAG, &defLen, &subStatus);
+                          if(U_SUCCESS(subStatus) && defLen) {
+                            u_UCharsToChars(defUstr, defVal, u_strlen(defUstr));
+#if defined(URES_TREE_DEBUG)
+                            fprintf(stderr, "%s;%s -> default %s=%s,  %s\n", 
+                                    path?path:"ICUDATA", full, keyword, defVal, u_errorName(subStatus));
+#endif
+                            uprv_strcpy(defLoc, full);
+                          }
+                        } /* end of recalculate default KW */
+#if defined(URES_TREE_DEBUG)
+                        else {
+                          fprintf(stderr, "No trim1,  %s <= %s\n", defLoc, full);
+                        }
+#endif
+                    }
+                }
+            }
+            subStatus = U_ZERO_ERROR;
+            
+            uprv_strcpy(found, parent);
+            uloc_getParent(found,parent,1023,&subStatus);
+            ures_close(res);
+        } while(!full[0] && *found && U_SUCCESS(*status));
+    }
+    
+    if(U_SUCCESS(*status)) {
+        if(!full[0]) {
+#if defined(URES_TREE_DEBUG)
+          fprintf(stderr, "Still could not load keyword %s=%s\n", keyword, kwVal);
+#endif
+          *status = U_MISSING_RESOURCE_ERROR;
+        } else if(omitDefault) {
+#if defined(URES_TREE_DEBUG)
+          fprintf(stderr,"Trim? full=%s, defLoc=%s, found=%s\n", full, defLoc, found);
+#endif        
+          if(uprv_strlen(defLoc) <= uprv_strlen(full)) {
+            /* found the keyword in a *child* of where the default tag was present. */
+            if(!uprv_strcmp(kwVal, defVal)) { /* if the requested kw is default, */
+              /* and the default is in or in an ancestor of the current locale */
+#if defined(URES_TREE_DEBUG)
+              fprintf(stderr, "Removing unneeded var %s=%s\n", keyword, kwVal);
+#endif
+              kwVal[0]=0;
+            }
+          }
+        }
+        uprv_strcpy(found, full);
+        if(kwVal[0]) {
+            uprv_strcat(found, "@");
+            uprv_strcat(found, keyword);
+            uprv_strcat(found, "=");
+            uprv_strcat(found, kwVal);
+        } else if(!omitDefault) {
+            uprv_strcat(found, "@");
+            uprv_strcat(found, keyword);
+            uprv_strcat(found, "=");
+            uprv_strcat(found, defVal);
+        }
+    }
+    /* we found the default locale - no need to repeat it.*/
+    
+    ures_close(&bund1);
+    ures_close(&bund2);
+    
+    length = (int32_t)uprv_strlen(found);
+
+    if(U_SUCCESS(*status)) {
+        int32_t copyLength = uprv_min(length, resultCapacity);
+        if(copyLength>0) {
+            uprv_strncpy(result, found, copyLength);
+        }
+        if(length == 0) {
+          *status = U_MISSING_RESOURCE_ERROR; 
+        }
+    } else {
+        length = 0;
+        result[0]=0;
+    }
+    return u_terminateChars(result, resultCapacity, length, status);
+}
+
+U_CAPI UEnumeration* U_EXPORT2
+ures_getKeywordValues(const char *path, const char *keyword, UErrorCode *status)
+{
+#define VALUES_BUF_SIZE 2048
+#define VALUES_LIST_SIZE 512
+    
+    char       valuesBuf[VALUES_BUF_SIZE];
+    int32_t    valuesIndex = 0;
+    const char *valuesList[VALUES_LIST_SIZE];
+    int32_t    valuesCount = 0;
+    
+    const char *locale;
+    int32_t     locLen;
+    
+    UEnumeration *locs = NULL;
+    
+    UResourceBundle    item;
+    UResourceBundle    subItem;
+    
+    ures_initStackObject(&item);
+    ures_initStackObject(&subItem);
+    locs = ures_openAvailableLocales(path, status);
+    
+    if(U_FAILURE(*status)) {
+        ures_close(&item);
+        ures_close(&subItem);
+        return NULL;
+    }
+    
+    valuesBuf[0]=0;
+    valuesBuf[1]=0;
+    
+    while((locale = uenum_next(locs, &locLen, status))) {
+        UResourceBundle   *bund = NULL;
+        UResourceBundle   *subPtr = NULL;
+        UErrorCode subStatus = U_ZERO_ERROR; /* don't fail if a bundle is unopenable */
+        bund = ures_openDirect(path, locale, &subStatus);
+        
+#if defined(URES_TREE_DEBUG)
+        if(!bund || U_FAILURE(subStatus)) {
+            fprintf(stderr, "%s-%s values: Can't open %s locale - skipping. (%s)\n", 
+                path?path:"<ICUDATA>", keyword, locale, u_errorName(subStatus));
+        }
+#endif
+        
+        ures_getByKey(bund, keyword, &item, &subStatus);
+        
+        if(!bund || U_FAILURE(subStatus)) {
+#if defined(URES_TREE_DEBUG)
+            fprintf(stderr, "%s-%s values: Can't find in %s - skipping. (%s)\n", 
+                path?path:"<ICUDATA>", keyword, locale, u_errorName(subStatus));
+#endif
+            ures_close(bund);
+            bund = NULL;
+            continue;
+        }
+        
+        while((subPtr = ures_getNextResource(&item,&subItem,&subStatus))
+            && U_SUCCESS(subStatus)) {
+            const char *k;
+            int32_t i;
+            k = ures_getKey(subPtr);
+            
+#if defined(URES_TREE_DEBUG)
+            /* fprintf(stderr, "%s | %s | %s | %s\n", path?path:"<ICUDATA>", keyword, locale, k); */
+#endif
+            for(i=0;k&&i<valuesCount;i++) {
+                if(!uprv_strcmp(valuesList[i],k)) {
+                    k = NULL; /* found duplicate */
+                }
+            }
+            if(k && *k) {
+                int32_t kLen = (int32_t)uprv_strlen(k);
+                if(!uprv_strcmp(k,DEFAULT_TAG)) {
+                    continue; /* don't need 'default'. */
+                }
+                if((valuesCount >= (VALUES_LIST_SIZE-1)) ||       /* no more space in list .. */
+                    ((valuesIndex+kLen+1+1) >= VALUES_BUF_SIZE)) { /* no more space in buffer (string + 2 nulls) */
+                    *status = U_ILLEGAL_ARGUMENT_ERROR; /* out of space.. */
+                } else {
+                    uprv_strcpy(valuesBuf+valuesIndex, k);
+                    valuesList[valuesCount++] = valuesBuf+valuesIndex;
+                    valuesIndex += kLen;
+#if defined(URES_TREE_DEBUG)
+                    fprintf(stderr, "%s | %s | %s | [%s]   (UNIQUE)\n",
+                        path?path:"<ICUDATA>", keyword, locale, k);
+#endif
+                    valuesBuf[valuesIndex++] = 0; /* terminate */
+                }
+            }
+        }
+        ures_close(bund);
+    }
+    valuesBuf[valuesIndex++] = 0; /* terminate */
+    
+    ures_close(&item);
+    ures_close(&subItem);
+    uenum_close(locs);
+#if defined(URES_TREE_DEBUG)
+    fprintf(stderr, "%s:  size %d, #%d\n", u_errorName(*status), 
+        valuesIndex, valuesCount);
+#endif
+    return uloc_openKeywordList(valuesBuf, valuesIndex, status);
+}
+#if 0
+/* This code isn't needed, and given the documentation warnings the implementation is suspect */
+U_INTERNAL UBool U_EXPORT2
+ures_equal(const UResourceBundle* res1, const UResourceBundle* res2){
+    if(res1==NULL || res2==NULL){
+        return res1==res2; /* pointer comparision */
+    }
+    if(res1->fKey==NULL||  res2->fKey==NULL){
+        return (res1->fKey==res2->fKey);
+    }else{
+        if(uprv_strcmp(res1->fKey, res2->fKey)!=0){
+            return FALSE;
+        }
+    }
+    if(uprv_strcmp(res1->fData->fName, res2->fData->fName)!=0){
+        return FALSE;
+    }
+    if(res1->fData->fPath == NULL||  res2->fData->fPath==NULL){
+        return (res1->fData->fPath == res2->fData->fPath);
+    }else{
+        if(uprv_strcmp(res1->fData->fPath, res2->fData->fPath)!=0){
+            return FALSE;
+        }
+    }
+    if(uprv_strcmp(res1->fData->fParent->fName, res2->fData->fParent->fName)!=0){
+        return FALSE;
+    }
+    if(uprv_strcmp(res1->fData->fParent->fPath, res2->fData->fParent->fPath)!=0){
+        return FALSE;
+    }
+    if(uprv_strncmp(res1->fResPath, res2->fResPath, res1->fResPathLen)!=0){
+        return FALSE;
+    }
+    if(res1->fRes != res2->fRes){
+        return FALSE;
+    }
+    return TRUE;
+}
+U_INTERNAL UResourceBundle* U_EXPORT2
+ures_clone(const UResourceBundle* res, UErrorCode* status){
+    UResourceBundle* bundle = NULL;
+    UResourceBundle* ret = NULL;
+    if(U_FAILURE(*status) || res == NULL){
+        return NULL;
+    }
+    bundle = ures_open(res->fData->fPath, res->fData->fName, status);
+    if(res->fResPath!=NULL){
+        ret = ures_findSubResource(bundle, res->fResPath, NULL, status);
+        ures_close(bundle);
+    }else{
+        ret = bundle;
+    }
+    return ret;
+}
+U_INTERNAL const UResourceBundle* U_EXPORT2
+ures_getParentBundle(const UResourceBundle* res){
+    if(res==NULL){
+        return NULL;
+    }
+    return res->fParentRes;
+}
+#endif
+
+U_INTERNAL void U_EXPORT2
+ures_getVersionByKey(const UResourceBundle* res, const char *key, UVersionInfo ver, UErrorCode *status) {
+  const UChar *str;
+  int32_t len;
+  str = ures_getStringByKey(res, key, &len, status);
+  if(U_SUCCESS(*status)) {
+    u_versionFromUString(ver, str);
+  } 
+}
+
+/* eof */
diff --git a/source/common/uresdata.c b/source/common/uresdata.c
new file mode 100644
index 0000000..456f1a3
--- /dev/null
+++ b/source/common/uresdata.c
@@ -0,0 +1,1128 @@
+/*
+*******************************************************************************
+*                                                                             *
+* Copyright (C) 1999-2010, International Business Machines Corporation        *
+*               and others. All Rights Reserved.                              *
+*                                                                             *
+*******************************************************************************
+*   file name:  uresdata.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999dec08
+*   created by: Markus W. Scherer
+* Modification History:
+*
+*   Date        Name        Description
+*   06/20/2000  helena      OS/400 port changes; mostly typecast.
+*   06/24/02    weiv        Added support for resource sharing
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/udata.h"
+#include "unicode/ustring.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uarrsort.h"
+#include "udataswp.h"
+#include "ucol_swp.h"
+#include "uinvchar.h"
+#include "uresdata.h"
+#include "uresimp.h"
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+/*
+ * Resource access helpers
+ */
+
+/* get a const char* pointer to the key with the keyOffset byte offset from pRoot */
+#define RES_GET_KEY16(pResData, keyOffset) \
+    ((keyOffset)<(pResData)->localKeyLimit ? \
+        (const char *)(pResData)->pRoot+(keyOffset) : \
+        (pResData)->poolBundleKeys+(keyOffset)-(pResData)->localKeyLimit)
+
+#define RES_GET_KEY32(pResData, keyOffset) \
+    ((keyOffset)>=0 ? \
+        (const char *)(pResData)->pRoot+(keyOffset) : \
+        (pResData)->poolBundleKeys+((keyOffset)&0x7fffffff))
+
+#define URESDATA_ITEM_NOT_FOUND -1
+
+/* empty resources, returned when the resource offset is 0 */
+static const uint16_t gEmpty16=0;
+static const int32_t gEmpty32=0;
+static const struct {
+    int32_t length;
+    UChar nul;
+    UChar pad;
+} gEmptyString={ 0, 0, 0 };
+
+/*
+ * All the type-access functions assume that
+ * the resource is of the expected type.
+ */
+
+static int32_t
+_res_findTableItem(const ResourceData *pResData, const uint16_t *keyOffsets, int32_t length,
+                   const char *key, const char **realKey) {
+    const char *tableKey;
+    int32_t mid, start, limit;
+    int result;
+
+    /* do a binary search for the key */
+    start=0;
+    limit=length;
+    while(start<limit) {
+        mid = (start + limit) / 2;
+        tableKey = RES_GET_KEY16(pResData, keyOffsets[mid]);
+        if (pResData->useNativeStrcmp) {
+            result = uprv_strcmp(key, tableKey);
+        } else {
+            result = uprv_compareInvCharsAsAscii(key, tableKey);
+        }
+        if (result < 0) {
+            limit = mid;
+        } else if (result > 0) {
+            start = mid + 1;
+        } else {
+            /* We found it! */
+            *realKey=tableKey;
+            return mid;
+        }
+    }
+    return URESDATA_ITEM_NOT_FOUND;  /* not found or table is empty. */
+}
+
+static int32_t
+_res_findTable32Item(const ResourceData *pResData, const int32_t *keyOffsets, int32_t length,
+                     const char *key, const char **realKey) {
+    const char *tableKey;
+    int32_t mid, start, limit;
+    int result;
+
+    /* do a binary search for the key */
+    start=0;
+    limit=length;
+    while(start<limit) {
+        mid = (start + limit) / 2;
+        tableKey = RES_GET_KEY32(pResData, keyOffsets[mid]);
+        if (pResData->useNativeStrcmp) {
+            result = uprv_strcmp(key, tableKey);
+        } else {
+            result = uprv_compareInvCharsAsAscii(key, tableKey);
+        }
+        if (result < 0) {
+            limit = mid;
+        } else if (result > 0) {
+            start = mid + 1;
+        } else {
+            /* We found it! */
+            *realKey=tableKey;
+            return mid;
+        }
+    }
+    return URESDATA_ITEM_NOT_FOUND;  /* not found or table is empty. */
+}
+
+/* helper for res_load() ---------------------------------------------------- */
+
+static UBool U_CALLCONV
+isAcceptable(void *context,
+             const char *type, const char *name,
+             const UDataInfo *pInfo) {
+    uprv_memcpy(context, pInfo->formatVersion, 4);
+    return (UBool)(
+        pInfo->size>=20 &&
+        pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
+        pInfo->charsetFamily==U_CHARSET_FAMILY &&
+        pInfo->sizeofUChar==U_SIZEOF_UCHAR &&
+        pInfo->dataFormat[0]==0x52 &&   /* dataFormat="ResB" */
+        pInfo->dataFormat[1]==0x65 &&
+        pInfo->dataFormat[2]==0x73 &&
+        pInfo->dataFormat[3]==0x42 &&
+        (pInfo->formatVersion[0]==1 || pInfo->formatVersion[0]==2));
+}
+
+/* semi-public functions ---------------------------------------------------- */
+
+static void
+res_init(ResourceData *pResData,
+         UVersionInfo formatVersion, const void *inBytes, int32_t length,
+         UErrorCode *errorCode) {
+    UResType rootType;
+
+    /* get the root resource */
+    pResData->pRoot=(const int32_t *)inBytes;
+    pResData->rootRes=(Resource)*pResData->pRoot;
+    pResData->p16BitUnits=&gEmpty16;
+
+    /* formatVersion 1.1 must have a root item and at least 5 indexes */
+    if(length>=0 && (length/4)<((formatVersion[0]==1 && formatVersion[1]==0) ? 1 : 1+5)) {
+        *errorCode=U_INVALID_FORMAT_ERROR;
+        res_unload(pResData);
+        return;
+    }
+
+    /* currently, we accept only resources that have a Table as their roots */
+    rootType=RES_GET_TYPE(pResData->rootRes);
+    if(!URES_IS_TABLE(rootType)) {
+        *errorCode=U_INVALID_FORMAT_ERROR;
+        res_unload(pResData);
+        return;
+    }
+
+    if(formatVersion[0]==1 && formatVersion[1]==0) {
+        pResData->localKeyLimit=0x10000;  /* greater than any 16-bit key string offset */
+    } else {
+        /* bundles with formatVersion 1.1 and later contain an indexes[] array */
+        const int32_t *indexes=pResData->pRoot+1;
+        int32_t indexLength=indexes[URES_INDEX_LENGTH]&0xff;
+        if(indexLength<=URES_INDEX_MAX_TABLE_LENGTH) {
+            *errorCode=U_INVALID_FORMAT_ERROR;
+            res_unload(pResData);
+            return;
+        }
+        if( length>=0 &&
+            (length<((1+indexLength)<<2) ||
+             length<(indexes[URES_INDEX_BUNDLE_TOP]<<2))
+        ) {
+            *errorCode=U_INVALID_FORMAT_ERROR;
+            res_unload(pResData);
+            return;
+        }
+        if(indexes[URES_INDEX_KEYS_TOP]>(1+indexLength)) {
+            pResData->localKeyLimit=indexes[URES_INDEX_KEYS_TOP]<<2;
+        }
+        if(indexLength>URES_INDEX_ATTRIBUTES) {
+            int32_t att=indexes[URES_INDEX_ATTRIBUTES];
+            pResData->noFallback=(UBool)(att&URES_ATT_NO_FALLBACK);
+            pResData->isPoolBundle=(UBool)((att&URES_ATT_IS_POOL_BUNDLE)!=0);
+            pResData->usesPoolBundle=(UBool)((att&URES_ATT_USES_POOL_BUNDLE)!=0);
+        }
+        if((pResData->isPoolBundle || pResData->usesPoolBundle) && indexLength<=URES_INDEX_POOL_CHECKSUM) {
+            *errorCode=U_INVALID_FORMAT_ERROR;
+            res_unload(pResData);
+            return;
+        }
+        if( indexLength>URES_INDEX_16BIT_TOP &&
+            indexes[URES_INDEX_16BIT_TOP]>indexes[URES_INDEX_KEYS_TOP]
+        ) {
+            pResData->p16BitUnits=(const uint16_t *)(pResData->pRoot+indexes[URES_INDEX_KEYS_TOP]);
+        }
+    }
+
+    if(formatVersion[0]==1 || U_CHARSET_FAMILY==U_ASCII_FAMILY) {
+        /*
+         * formatVersion 1: compare key strings in native-charset order
+         * formatVersion 2 and up: compare key strings in ASCII order
+         */
+        pResData->useNativeStrcmp=TRUE;
+    }
+}
+
+U_CAPI void U_EXPORT2
+res_read(ResourceData *pResData,
+         const UDataInfo *pInfo, const void *inBytes, int32_t length,
+         UErrorCode *errorCode) {
+    UVersionInfo formatVersion;
+
+    uprv_memset(pResData, 0, sizeof(ResourceData));
+    if(U_FAILURE(*errorCode)) {
+        return;
+    }
+    if(!isAcceptable(formatVersion, NULL, NULL, pInfo)) {
+        *errorCode=U_INVALID_FORMAT_ERROR;
+        return;
+    }
+    res_init(pResData, formatVersion, inBytes, length, errorCode);
+}
+
+U_CFUNC void
+res_load(ResourceData *pResData,
+         const char *path, const char *name, UErrorCode *errorCode) {
+    UVersionInfo formatVersion;
+
+    uprv_memset(pResData, 0, sizeof(ResourceData));
+
+    /* load the ResourceBundle file */
+    pResData->data=udata_openChoice(path, "res", name, isAcceptable, formatVersion, errorCode);
+    if(U_FAILURE(*errorCode)) {
+        return;
+    }
+
+    /* get its memory and initialize *pResData */
+    res_init(pResData, formatVersion, udata_getMemory(pResData->data), -1, errorCode);
+}
+
+U_CFUNC void
+res_unload(ResourceData *pResData) {
+    if(pResData->data!=NULL) {
+        udata_close(pResData->data);
+        pResData->data=NULL;
+    }
+}
+
+static const int8_t gPublicTypes[URES_LIMIT] = {
+    URES_STRING,
+    URES_BINARY,
+    URES_TABLE,
+    URES_ALIAS,
+
+    URES_TABLE,     /* URES_TABLE32 */
+    URES_TABLE,     /* URES_TABLE16 */
+    URES_STRING,    /* URES_STRING_V2 */
+    URES_INT,
+
+    URES_ARRAY,
+    URES_ARRAY,     /* URES_ARRAY16 */
+    URES_NONE,
+    URES_NONE,
+
+    URES_NONE,
+    URES_NONE,
+    URES_INT_VECTOR,
+    URES_NONE
+};
+
+U_CAPI UResType U_EXPORT2
+res_getPublicType(Resource res) {
+    return (UResType)gPublicTypes[RES_GET_TYPE(res)];
+}
+
+U_CAPI const UChar * U_EXPORT2
+res_getString(const ResourceData *pResData, Resource res, int32_t *pLength) {
+    const UChar *p;
+    uint32_t offset=RES_GET_OFFSET(res);
+    int32_t length;
+    if(RES_GET_TYPE(res)==URES_STRING_V2) {
+        int32_t first;
+        p=(const UChar *)(pResData->p16BitUnits+offset);
+        first=*p;
+        if(!U16_IS_TRAIL(first)) {
+            length=u_strlen(p);
+        } else if(first<0xdfef) {
+            length=first&0x3ff;
+            ++p;
+        } else if(first<0xdfff) {
+            length=((first-0xdfef)<<16)|p[1];
+            p+=2;
+        } else {
+            length=((int32_t)p[1]<<16)|p[2];
+            p+=3;
+        }
+    } else if(res==offset) /* RES_GET_TYPE(res)==URES_STRING */ {
+        const int32_t *p32= res==0 ? &gEmptyString.length : pResData->pRoot+res;
+        length=*p32++;
+        p=(const UChar *)p32;
+    } else {
+        p=NULL;
+        length=0;
+    }
+    if(pLength) {
+        *pLength=length;
+    }
+    return p;
+}
+
+U_CAPI const UChar * U_EXPORT2
+res_getAlias(const ResourceData *pResData, Resource res, int32_t *pLength) {
+    const UChar *p;
+    uint32_t offset=RES_GET_OFFSET(res);
+    int32_t length;
+    if(RES_GET_TYPE(res)==URES_ALIAS) {
+        const int32_t *p32= offset==0 ? &gEmptyString.length : pResData->pRoot+offset;
+        length=*p32++;
+        p=(const UChar *)p32;
+    } else {
+        p=NULL;
+        length=0;
+    }
+    if(pLength) {
+        *pLength=length;
+    }
+    return p;
+}
+
+U_CAPI const uint8_t * U_EXPORT2
+res_getBinary(const ResourceData *pResData, Resource res, int32_t *pLength) {
+    const uint8_t *p;
+    uint32_t offset=RES_GET_OFFSET(res);
+    int32_t length;
+    if(RES_GET_TYPE(res)==URES_BINARY) {
+        const int32_t *p32= offset==0 ? &gEmpty32 : pResData->pRoot+offset;
+        length=*p32++;
+        p=(const uint8_t *)p32;
+    } else {
+        p=NULL;
+        length=0;
+    }
+    if(pLength) {
+        *pLength=length;
+    }
+    return p;
+}
+
+
+U_CAPI const int32_t * U_EXPORT2
+res_getIntVector(const ResourceData *pResData, Resource res, int32_t *pLength) {
+    const int32_t *p;
+    uint32_t offset=RES_GET_OFFSET(res);
+    int32_t length;
+    if(RES_GET_TYPE(res)==URES_INT_VECTOR) {
+        p= offset==0 ? &gEmpty32 : pResData->pRoot+offset;
+        length=*p++;
+    } else {
+        p=NULL;
+        length=0;
+    }
+    if(pLength) {
+        *pLength=length;
+    }
+    return p;
+}
+
+U_CAPI int32_t U_EXPORT2
+res_countArrayItems(const ResourceData *pResData, Resource res) {
+    uint32_t offset=RES_GET_OFFSET(res);
+    switch(RES_GET_TYPE(res)) {
+    case URES_STRING:
+    case URES_STRING_V2:
+    case URES_BINARY:
+    case URES_ALIAS:
+    case URES_INT:
+    case URES_INT_VECTOR:
+        return 1;
+    case URES_ARRAY:
+    case URES_TABLE32:
+        return offset==0 ? 0 : *(pResData->pRoot+offset);
+    case URES_TABLE:
+        return offset==0 ? 0 : *((const uint16_t *)(pResData->pRoot+offset));
+    case URES_ARRAY16:
+    case URES_TABLE16:
+        return pResData->p16BitUnits[offset];
+    default:
+        return 0;
+    }
+}
+
+U_CAPI Resource U_EXPORT2
+res_getTableItemByKey(const ResourceData *pResData, Resource table,
+                      int32_t *indexR, const char **key) {
+    uint32_t offset=RES_GET_OFFSET(table);
+    int32_t length;
+    int32_t idx;
+    if(key == NULL || *key == NULL) {
+        return RES_BOGUS;
+    }
+    switch(RES_GET_TYPE(table)) {
+    case URES_TABLE: {
+        const uint16_t *p= offset==0 ? &gEmpty16 : (const uint16_t *)(pResData->pRoot+offset);
+        length=*p++;
+        *indexR=idx=_res_findTableItem(pResData, p, length, *key, key);
+        if(idx>=0) {
+            const Resource *p32=(const Resource *)(p+length+(~length&1));
+            return p32[idx];
+        }
+        break;
+    }
+    case URES_TABLE16: {
+        const uint16_t *p=pResData->p16BitUnits+offset;
+        length=*p++;
+        *indexR=idx=_res_findTableItem(pResData, p, length, *key, key);
+        if(idx>=0) {
+            return URES_MAKE_RESOURCE(URES_STRING_V2, p[length+idx]);
+        }
+        break;
+    }
+    case URES_TABLE32: {
+        const int32_t *p= offset==0 ? &gEmpty32 : pResData->pRoot+offset;
+        length=*p++;
+        *indexR=idx=_res_findTable32Item(pResData, p, length, *key, key);
+        if(idx>=0) {
+            return (Resource)p[length+idx];
+        }
+        break;
+    }
+    default:
+        break;
+    }
+    return RES_BOGUS;
+}
+
+U_CAPI Resource U_EXPORT2
+res_getTableItemByIndex(const ResourceData *pResData, Resource table,
+                        int32_t indexR, const char **key) {
+    uint32_t offset=RES_GET_OFFSET(table);
+    int32_t length;
+    switch(RES_GET_TYPE(table)) {
+    case URES_TABLE: {
+        const uint16_t *p= offset==0 ? &gEmpty16 : (const uint16_t *)(pResData->pRoot+offset);
+        length=*p++;
+        if(indexR<length) {
+            const Resource *p32=(const Resource *)(p+length+(~length&1));
+            if(key!=NULL) {
+                *key=RES_GET_KEY16(pResData, p[indexR]);
+            }
+            return p32[indexR];
+        }
+        break;
+    }
+    case URES_TABLE16: {
+        const uint16_t *p=pResData->p16BitUnits+offset;
+        length=*p++;
+        if(indexR<length) {
+            if(key!=NULL) {
+                *key=RES_GET_KEY16(pResData, p[indexR]);
+            }
+            return URES_MAKE_RESOURCE(URES_STRING_V2, p[length+indexR]);
+        }
+        break;
+    }
+    case URES_TABLE32: {
+        const int32_t *p= offset==0 ? &gEmpty32 : pResData->pRoot+offset;
+        length=*p++;
+        if(indexR<length) {
+            if(key!=NULL) {
+                *key=RES_GET_KEY32(pResData, p[indexR]);
+            }
+            return (Resource)p[length+indexR];
+        }
+        break;
+    }
+    default:
+        break;
+    }
+    return RES_BOGUS;
+}
+
+U_CAPI Resource U_EXPORT2
+res_getResource(const ResourceData *pResData, const char *key) {
+    const char *realKey=key;
+    int32_t idx;
+    return res_getTableItemByKey(pResData, pResData->rootRes, &idx, &realKey);
+}
+
+U_CAPI Resource U_EXPORT2
+res_getArrayItem(const ResourceData *pResData, Resource array, int32_t indexR) {
+    uint32_t offset=RES_GET_OFFSET(array);
+    switch(RES_GET_TYPE(array)) {
+    case URES_ARRAY: {
+        const int32_t *p= offset==0 ? &gEmpty32 : pResData->pRoot+offset;
+        if(indexR<*p) {
+            return (Resource)p[1+indexR];
+        }
+        break;
+    }
+    case URES_ARRAY16: {
+        const uint16_t *p=pResData->p16BitUnits+offset;
+        if(indexR<*p) {
+            return URES_MAKE_RESOURCE(URES_STRING_V2, p[1+indexR]);
+        }
+        break;
+    }
+    default:
+        break;
+    }
+    return RES_BOGUS;
+}
+
+U_CFUNC Resource
+res_findResource(const ResourceData *pResData, Resource r, char** path, const char** key) {
+  /* we pass in a path. CollationElements/Sequence or zoneStrings/3/2 etc. 
+   * iterates over a path and stops when a scalar resource is found. This  
+   * CAN be an alias. Path gets set to the part that has not yet been processed. 
+   */
+
+  char *pathP = *path, *nextSepP = *path;
+  char *closeIndex = NULL;
+  Resource t1 = r;
+  Resource t2;
+  int32_t indexR = 0;
+  UResType type = RES_GET_TYPE(t1);
+
+  /* if you come in with an empty path, you'll be getting back the same resource */
+  if(!uprv_strlen(pathP)) {
+      return r;
+  }
+
+  /* one needs to have an aggregate resource in order to search in it */
+  if(!URES_IS_CONTAINER(type)) {
+      return RES_BOGUS;
+  }
+  
+  while(nextSepP && *pathP && t1 != RES_BOGUS && URES_IS_CONTAINER(type)) {
+    /* Iteration stops if: the path has been consumed, we found a non-existing
+     * resource (t1 == RES_BOGUS) or we found a scalar resource (including alias)
+     */
+    nextSepP = uprv_strchr(pathP, RES_PATH_SEPARATOR);
+    /* if there are more separators, terminate string 
+     * and set path to the remaining part of the string
+     */
+    if(nextSepP != NULL) {
+      *nextSepP = 0; /* overwrite the separator with a NUL to terminate the key */
+      *path = nextSepP+1;
+    } else {
+      *path = uprv_strchr(pathP, 0);
+    }
+
+    /* if the resource is a table */
+    /* try the key based access */
+    if(URES_IS_TABLE(type)) {
+      *key = pathP;
+      t2 = res_getTableItemByKey(pResData, t1, &indexR, key);
+      if(t2 == RES_BOGUS) { 
+        /* if we fail to get the resource by key, maybe we got an index */
+        indexR = uprv_strtol(pathP, &closeIndex, 10);
+        if(closeIndex != pathP) {
+          /* if we indeed have an index, try to get the item by index */
+          t2 = res_getTableItemByIndex(pResData, t1, indexR, key);
+        }
+      }
+    } else if(URES_IS_ARRAY(type)) {
+      indexR = uprv_strtol(pathP, &closeIndex, 10);
+      if(closeIndex != pathP) {
+        t2 = res_getArrayItem(pResData, t1, indexR);
+      } else {
+        t2 = RES_BOGUS; /* have an array, but don't have a valid index */
+      }
+      *key = NULL;
+    } else { /* can't do much here, except setting t2 to bogus */
+      t2 = RES_BOGUS;
+    }
+    t1 = t2;
+    type = RES_GET_TYPE(t1);
+    /* position pathP to next resource key/index */
+    pathP = *path;
+  }
+
+  return t1;
+}
+
+/* resource bundle swapping ------------------------------------------------- */
+
+/*
+ * Need to always enumerate the entire item tree,
+ * track the lowest address of any item to use as the limit for char keys[],
+ * track the highest address of any item to return the size of the data.
+ *
+ * We should have thought of storing those in the data...
+ * It is possible to extend the data structure by putting additional values
+ * in places that are inaccessible by ordinary enumeration of the item tree.
+ * For example, additional integers could be stored at the beginning or
+ * end of the key strings; this could be indicated by a minor version number,
+ * and the data swapping would have to know about these values.
+ *
+ * The data structure does not forbid keys to be shared, so we must swap
+ * all keys once instead of each key when it is referenced.
+ *
+ * These swapping functions assume that a resource bundle always has a length
+ * that is a multiple of 4 bytes.
+ * Currently, this is trivially true because genrb writes bundle tree leaves
+ * physically first, before their branches, so that the root table with its
+ * array of resource items (uint32_t values) is always last.
+ */
+
+/* definitions for table sorting ------------------------ */
+
+/*
+ * row of a temporary array
+ *
+ * gets platform-endian key string indexes and sorting indexes;
+ * after sorting this array by keys, the actual key/value arrays are permutated
+ * according to the sorting indexes
+ */
+typedef struct Row {
+    int32_t keyIndex, sortIndex;
+} Row;
+
+static int32_t
+ures_compareRows(const void *context, const void *left, const void *right) {
+    const char *keyChars=(const char *)context;
+    return (int32_t)uprv_strcmp(keyChars+((const Row *)left)->keyIndex,
+                                keyChars+((const Row *)right)->keyIndex);
+}
+
+typedef struct TempTable {
+    const char *keyChars;
+    Row *rows;
+    int32_t *resort;
+    uint32_t *resFlags;
+    int32_t localKeyLimit;
+    uint8_t majorFormatVersion;
+} TempTable;
+
+enum {
+    STACK_ROW_CAPACITY=200
+};
+
+/* The table item key string is not locally available. */
+static const char *const gUnknownKey="";
+
+/* resource table key for collation binaries: "%%CollationBin" */
+static const UChar gCollationBinKey[]={
+    0x25, 0x25,
+    0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+    0x42, 0x69, 0x6e,
+    0
+};
+
+/*
+ * swap one resource item
+ */
+static void
+ures_swapResource(const UDataSwapper *ds,
+                  const Resource *inBundle, Resource *outBundle,
+                  Resource res, /* caller swaps res itself */
+                  const char *key,
+                  TempTable *pTempTable,
+                  UErrorCode *pErrorCode) {
+    const Resource *p;
+    Resource *q;
+    int32_t offset, count;
+
+    switch(RES_GET_TYPE(res)) {
+    case URES_TABLE16:
+    case URES_STRING_V2:
+    case URES_INT:
+    case URES_ARRAY16:
+        /* integer, or points to 16-bit units, nothing to do here */
+        return;
+    default:
+        break;
+    }
+
+    /* all other types use an offset to point to their data */
+    offset=(int32_t)RES_GET_OFFSET(res);
+    if(offset==0) {
+        /* special offset indicating an empty item */
+        return;
+    }
+    if(pTempTable->resFlags[offset>>5]&((uint32_t)1<<(offset&0x1f))) {
+        /* we already swapped this resource item */
+        return;
+    } else {
+        /* mark it as swapped now */
+        pTempTable->resFlags[offset>>5]|=((uint32_t)1<<(offset&0x1f));
+    }
+
+    p=inBundle+offset;
+    q=outBundle+offset;
+
+    switch(RES_GET_TYPE(res)) {
+    case URES_ALIAS:
+        /* physically same value layout as string, fall through */
+    case URES_STRING:
+        count=udata_readInt32(ds, (int32_t)*p);
+        /* swap length */
+        ds->swapArray32(ds, p, 4, q, pErrorCode);
+        /* swap each UChar (the terminating NUL would not change) */
+        ds->swapArray16(ds, p+1, 2*count, q+1, pErrorCode);
+        break;
+    case URES_BINARY:
+        count=udata_readInt32(ds, (int32_t)*p);
+        /* swap length */
+        ds->swapArray32(ds, p, 4, q, pErrorCode);
+        /* no need to swap or copy bytes - ures_swap() copied them all */
+
+        /* swap known formats */
+#if !UCONFIG_NO_COLLATION
+        if( key!=NULL &&  /* the binary is in a table */
+            (key!=gUnknownKey ?
+                /* its table key string is "%%CollationBin" */
+                0==ds->compareInvChars(ds, key, -1,
+                                       gCollationBinKey, LENGTHOF(gCollationBinKey)-1) :
+                /* its table key string is unknown but it looks like a collation binary */
+                ucol_looksLikeCollationBinary(ds, p+1, count))
+        ) {
+            ucol_swapBinary(ds, p+1, count, q+1, pErrorCode);
+        }
+#endif
+        break;
+    case URES_TABLE:
+    case URES_TABLE32:
+        {
+            const uint16_t *pKey16;
+            uint16_t *qKey16;
+
+            const int32_t *pKey32;
+            int32_t *qKey32;
+
+            Resource item;
+            int32_t i, oldIndex;
+
+            if(RES_GET_TYPE(res)==URES_TABLE) {
+                /* get table item count */
+                pKey16=(const uint16_t *)p;
+                qKey16=(uint16_t *)q;
+                count=ds->readUInt16(*pKey16);
+
+                pKey32=qKey32=NULL;
+
+                /* swap count */
+                ds->swapArray16(ds, pKey16++, 2, qKey16++, pErrorCode);
+
+                offset+=((1+count)+1)/2;
+            } else {
+                /* get table item count */
+                pKey32=(const int32_t *)p;
+                qKey32=(int32_t *)q;
+                count=udata_readInt32(ds, *pKey32);
+
+                pKey16=qKey16=NULL;
+
+                /* swap count */
+                ds->swapArray32(ds, pKey32++, 4, qKey32++, pErrorCode);
+
+                offset+=1+count;
+            }
+
+            if(count==0) {
+                break;
+            }
+
+            p=inBundle+offset; /* pointer to table resources */
+            q=outBundle+offset;
+
+            /* recurse */
+            for(i=0; i<count; ++i) {
+                const char *itemKey=gUnknownKey;
+                if(pKey16!=NULL) {
+                    int32_t keyOffset=ds->readUInt16(pKey16[i]);
+                    if(keyOffset<pTempTable->localKeyLimit) {
+                        itemKey=(const char *)outBundle+keyOffset;
+                    }
+                } else {
+                    int32_t keyOffset=udata_readInt32(ds, pKey32[i]);
+                    if(keyOffset>=0) {
+                        itemKey=(const char *)outBundle+keyOffset;
+                    }
+                }
+                item=ds->readUInt32(p[i]);
+                ures_swapResource(ds, inBundle, outBundle, item, itemKey, pTempTable, pErrorCode);
+                if(U_FAILURE(*pErrorCode)) {
+                    udata_printError(ds, "ures_swapResource(table res=%08x)[%d].recurse(%08x) failed\n",
+                                     res, i, item);
+                    return;
+                }
+            }
+
+            if(pTempTable->majorFormatVersion>1 || ds->inCharset==ds->outCharset) {
+                /* no need to sort, just swap the offset/value arrays */
+                if(pKey16!=NULL) {
+                    ds->swapArray16(ds, pKey16, count*2, qKey16, pErrorCode);
+                    ds->swapArray32(ds, p, count*4, q, pErrorCode);
+                } else {
+                    /* swap key offsets and items as one array */
+                    ds->swapArray32(ds, pKey32, count*2*4, qKey32, pErrorCode);
+                }
+                break;
+            }
+
+            /*
+             * We need to sort tables by outCharset key strings because they
+             * sort differently for different charset families.
+             * ures_swap() already set pTempTable->keyChars appropriately.
+             * First we set up a temporary table with the key indexes and
+             * sorting indexes and sort that.
+             * Then we permutate and copy/swap the actual values.
+             */
+            if(pKey16!=NULL) {
+                for(i=0; i<count; ++i) {
+                    pTempTable->rows[i].keyIndex=ds->readUInt16(pKey16[i]);
+                    pTempTable->rows[i].sortIndex=i;
+                }
+            } else {
+                for(i=0; i<count; ++i) {
+                    pTempTable->rows[i].keyIndex=udata_readInt32(ds, pKey32[i]);
+                    pTempTable->rows[i].sortIndex=i;
+                }
+            }
+            uprv_sortArray(pTempTable->rows, count, sizeof(Row),
+                           ures_compareRows, pTempTable->keyChars,
+                           FALSE, pErrorCode);
+            if(U_FAILURE(*pErrorCode)) {
+                udata_printError(ds, "ures_swapResource(table res=%08x).uprv_sortArray(%d items) failed\n",
+                                 res, count);
+                return;
+            }
+
+            /*
+             * copy/swap/permutate items
+             *
+             * If we swap in-place, then the permutation must use another
+             * temporary array (pTempTable->resort)
+             * before the results are copied to the outBundle.
+             */
+            /* keys */
+            if(pKey16!=NULL) {
+                uint16_t *rKey16;
+
+                if(pKey16!=qKey16) {
+                    rKey16=qKey16;
+                } else {
+                    rKey16=(uint16_t *)pTempTable->resort;
+                }
+                for(i=0; i<count; ++i) {
+                    oldIndex=pTempTable->rows[i].sortIndex;
+                    ds->swapArray16(ds, pKey16+oldIndex, 2, rKey16+i, pErrorCode);
+                }
+                if(qKey16!=rKey16) {
+                    uprv_memcpy(qKey16, rKey16, 2*count);
+                }
+            } else {
+                int32_t *rKey32;
+
+                if(pKey32!=qKey32) {
+                    rKey32=qKey32;
+                } else {
+                    rKey32=pTempTable->resort;
+                }
+                for(i=0; i<count; ++i) {
+                    oldIndex=pTempTable->rows[i].sortIndex;
+                    ds->swapArray32(ds, pKey32+oldIndex, 4, rKey32+i, pErrorCode);
+                }
+                if(qKey32!=rKey32) {
+                    uprv_memcpy(qKey32, rKey32, 4*count);
+                }
+            }
+
+            /* resources */
+            {
+                Resource *r;
+
+
+                if(p!=q) {
+                    r=q;
+                } else {
+                    r=(Resource *)pTempTable->resort;
+                }
+                for(i=0; i<count; ++i) {
+                    oldIndex=pTempTable->rows[i].sortIndex;
+                    ds->swapArray32(ds, p+oldIndex, 4, r+i, pErrorCode);
+                }
+                if(q!=r) {
+                    uprv_memcpy(q, r, 4*count);
+                }
+            }
+        }
+        break;
+    case URES_ARRAY:
+        {
+            Resource item;
+            int32_t i;
+
+            count=udata_readInt32(ds, (int32_t)*p);
+            /* swap length */
+            ds->swapArray32(ds, p++, 4, q++, pErrorCode);
+
+            /* recurse */
+            for(i=0; i<count; ++i) {
+                item=ds->readUInt32(p[i]);
+                ures_swapResource(ds, inBundle, outBundle, item, NULL, pTempTable, pErrorCode);
+                if(U_FAILURE(*pErrorCode)) {
+                    udata_printError(ds, "ures_swapResource(array res=%08x)[%d].recurse(%08x) failed\n",
+                                     res, i, item);
+                    return;
+                }
+            }
+
+            /* swap items */
+            ds->swapArray32(ds, p, 4*count, q, pErrorCode);
+        }
+        break;
+    case URES_INT_VECTOR:
+        count=udata_readInt32(ds, (int32_t)*p);
+        /* swap length and each integer */
+        ds->swapArray32(ds, p, 4*(1+count), q, pErrorCode);
+        break;
+    default:
+        /* also catches RES_BOGUS */
+        *pErrorCode=U_UNSUPPORTED_ERROR;
+        break;
+    }
+}
+
+U_CAPI int32_t U_EXPORT2
+ures_swap(const UDataSwapper *ds,
+          const void *inData, int32_t length, void *outData,
+          UErrorCode *pErrorCode) {
+    const UDataInfo *pInfo;
+    const Resource *inBundle;
+    Resource rootRes;
+    int32_t headerSize, maxTableLength;
+
+    Row rows[STACK_ROW_CAPACITY];
+    int32_t resort[STACK_ROW_CAPACITY];
+    TempTable tempTable;
+
+    const int32_t *inIndexes;
+
+    /* the following integers count Resource item offsets (4 bytes each), not bytes */
+    int32_t bundleLength, indexLength, keysBottom, keysTop, resBottom, top;
+
+    /* udata_swapDataHeader checks the arguments */
+    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    /* check data format and format version */
+    pInfo=(const UDataInfo *)((const char *)inData+4);
+    if(!(
+        pInfo->dataFormat[0]==0x52 &&   /* dataFormat="ResB" */
+        pInfo->dataFormat[1]==0x65 &&
+        pInfo->dataFormat[2]==0x73 &&
+        pInfo->dataFormat[3]==0x42 &&
+        ((pInfo->formatVersion[0]==1 && pInfo->formatVersion[1]>=1) ||  /* formatVersion 1.1+ or 2.x */
+         pInfo->formatVersion[0]==2)
+    )) {
+        udata_printError(ds, "ures_swap(): data format %02x.%02x.%02x.%02x (format version %02x.%02x) is not a resource bundle\n",
+                         pInfo->dataFormat[0], pInfo->dataFormat[1],
+                         pInfo->dataFormat[2], pInfo->dataFormat[3],
+                         pInfo->formatVersion[0], pInfo->formatVersion[1]);
+        *pErrorCode=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+    tempTable.majorFormatVersion=pInfo->formatVersion[0];
+
+    /* a resource bundle must contain at least one resource item */
+    if(length<0) {
+        bundleLength=-1;
+    } else {
+        bundleLength=(length-headerSize)/4;
+
+        /* formatVersion 1.1 must have a root item and at least 5 indexes */
+        if(bundleLength<(1+5)) {
+            udata_printError(ds, "ures_swap(): too few bytes (%d after header) for a resource bundle\n",
+                             length-headerSize);
+            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+            return 0;
+        }
+    }
+
+    inBundle=(const Resource *)((const char *)inData+headerSize);
+    rootRes=ds->readUInt32(*inBundle);
+
+    /* formatVersion 1.1 adds the indexes[] array */
+    inIndexes=(const int32_t *)(inBundle+1);
+
+    indexLength=udata_readInt32(ds, inIndexes[URES_INDEX_LENGTH])&0xff;
+    if(indexLength<=URES_INDEX_MAX_TABLE_LENGTH) {
+        udata_printError(ds, "ures_swap(): too few indexes for a 1.1+ resource bundle\n");
+        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0;
+    }
+    keysBottom=1+indexLength;
+    keysTop=udata_readInt32(ds, inIndexes[URES_INDEX_KEYS_TOP]);
+    if(indexLength>URES_INDEX_16BIT_TOP) {
+        resBottom=udata_readInt32(ds, inIndexes[URES_INDEX_16BIT_TOP]);
+    } else {
+        resBottom=keysTop;
+    }
+    top=udata_readInt32(ds, inIndexes[URES_INDEX_BUNDLE_TOP]);
+    maxTableLength=udata_readInt32(ds, inIndexes[URES_INDEX_MAX_TABLE_LENGTH]);
+
+    if(0<=bundleLength && bundleLength<top) {
+        udata_printError(ds, "ures_swap(): resource top %d exceeds bundle length %d\n",
+                         top, bundleLength);
+        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0;
+    }
+    if(keysTop>(1+indexLength)) {
+        tempTable.localKeyLimit=keysTop<<2;
+    } else {
+        tempTable.localKeyLimit=0;
+    }
+
+    if(length>=0) {
+        Resource *outBundle=(Resource *)((char *)outData+headerSize);
+
+        /* track which resources we have already swapped */
+        uint32_t stackResFlags[STACK_ROW_CAPACITY];
+        int32_t resFlagsLength;
+
+        /*
+         * We need one bit per 4 resource bundle bytes so that we can track
+         * every possible Resource for whether we have swapped it already.
+         * Multiple Resource words can refer to the same bundle offsets
+         * for sharing identical values.
+         * We could optimize this by allocating only for locations above
+         * where Resource values are stored (above keys & strings).
+         */
+        resFlagsLength=(length+31)>>5;          /* number of bytes needed */
+        resFlagsLength=(resFlagsLength+3)&~3;   /* multiple of 4 bytes for uint32_t */
+        if(resFlagsLength<=sizeof(stackResFlags)) {
+            tempTable.resFlags=stackResFlags;
+        } else {
+            tempTable.resFlags=(uint32_t *)uprv_malloc(resFlagsLength);
+            if(tempTable.resFlags==NULL) {
+                udata_printError(ds, "ures_swap(): unable to allocate memory for tracking resources\n");
+                *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+                return 0;
+            }
+        }
+        uprv_memset(tempTable.resFlags, 0, resFlagsLength);
+
+        /* copy the bundle for binary and inaccessible data */
+        if(inData!=outData) {
+            uprv_memcpy(outBundle, inBundle, 4*top);
+        }
+
+        /* swap the key strings, but not the padding bytes (0xaa) after the last string and its NUL */
+        udata_swapInvStringBlock(ds, inBundle+keysBottom, 4*(keysTop-keysBottom),
+                                    outBundle+keysBottom, pErrorCode);
+        if(U_FAILURE(*pErrorCode)) {
+            udata_printError(ds, "ures_swap().udata_swapInvStringBlock(keys[%d]) failed\n", 4*(keysTop-keysBottom));
+            return 0;
+        }
+
+        /* swap the 16-bit units (strings, table16, array16) */
+        if(keysTop<resBottom) {
+            ds->swapArray16(ds, inBundle+keysTop, (resBottom-keysTop)*4, outBundle+keysTop, pErrorCode);
+            if(U_FAILURE(*pErrorCode)) {
+                udata_printError(ds, "ures_swap().swapArray16(16-bit units[%d]) failed\n", 2*(resBottom-keysTop));
+                return 0;
+            }
+        }
+
+        /* allocate the temporary table for sorting resource tables */
+        tempTable.keyChars=(const char *)outBundle; /* sort by outCharset */
+        if(tempTable.majorFormatVersion>1 || maxTableLength<=STACK_ROW_CAPACITY) {
+            tempTable.rows=rows;
+            tempTable.resort=resort;
+        } else {
+            tempTable.rows=(Row *)uprv_malloc(maxTableLength*sizeof(Row)+maxTableLength*4);
+            if(tempTable.rows==NULL) {
+                udata_printError(ds, "ures_swap(): unable to allocate memory for sorting tables (max length: %d)\n",
+                                 maxTableLength);
+                *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+                if(tempTable.resFlags!=stackResFlags) {
+                    uprv_free(tempTable.resFlags);
+                }
+                return 0;
+            }
+            tempTable.resort=(int32_t *)(tempTable.rows+maxTableLength);
+        }
+
+        /* swap the resources */
+        ures_swapResource(ds, inBundle, outBundle, rootRes, NULL, &tempTable, pErrorCode);
+        if(U_FAILURE(*pErrorCode)) {
+            udata_printError(ds, "ures_swapResource(root res=%08x) failed\n",
+                             rootRes);
+        }
+
+        if(tempTable.rows!=rows) {
+            uprv_free(tempTable.rows);
+        }
+        if(tempTable.resFlags!=stackResFlags) {
+            uprv_free(tempTable.resFlags);
+        }
+
+        /* swap the root resource and indexes */
+        ds->swapArray32(ds, inBundle, keysBottom*4, outBundle, pErrorCode);
+    }
+
+    return headerSize+4*top;
+}
diff --git a/source/common/uresdata.h b/source/common/uresdata.h
new file mode 100644
index 0000000..6fdc712
--- /dev/null
+++ b/source/common/uresdata.h
@@ -0,0 +1,393 @@
+/*
+******************************************************************************
+*                                                                            *
+* Copyright (C) 1999-2009, International Business Machines                   *
+*                Corporation and others. All Rights Reserved.                *
+*                                                                            *
+******************************************************************************
+*   file name:  uresdata.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999dec08
+*   created by: Markus W. Scherer
+*   06/24/02    weiv        Added support for resource sharing
+*/
+
+#ifndef __RESDATA_H__
+#define __RESDATA_H__
+
+#include "unicode/utypes.h"
+#include "unicode/udata.h"
+#include "unicode/ures.h"
+#include "udataswp.h"
+
+/**
+ * Numeric constants for internal-only types of resource items.
+ * These must use different numeric values than UResType constants
+ * because they are used together.
+ * Internal types are never returned by ures_getType().
+ */
+typedef enum {
+    /** Include a negative value so that the compiler uses the same int type as for UResType. */
+    URES_INTERNAL_NONE=-1,
+
+    /** Resource type constant for tables with 32-bit count, key offsets and values. */
+    URES_TABLE32=4,
+
+    /**
+     * Resource type constant for tables with 16-bit count, key offsets and values.
+     * All values are URES_STRING_V2 strings.
+     */
+    URES_TABLE16=5,
+
+    /** Resource type constant for 16-bit Unicode strings in formatVersion 2. */
+    URES_STRING_V2=6,
+
+    /**
+     * Resource type constant for arrays with 16-bit count and values.
+     * All values are URES_STRING_V2 strings.
+     */
+    URES_ARRAY16=9
+} UResInternalType;
+
+/*
+ * A Resource is a 32-bit value that has 2 bit fields:
+ * 31..28   4-bit type, see enum below
+ * 27..0    28-bit four-byte-offset or value according to the type
+ */
+typedef uint32_t Resource;
+
+#define RES_BOGUS 0xffffffff
+
+#define RES_GET_TYPE(res) ((UResType)((res)>>28UL))
+#define RES_GET_OFFSET(res) ((res)&0x0fffffff)
+#define RES_GET_POINTER(pRoot, res) ((pRoot)+RES_GET_OFFSET(res))
+
+/* get signed and unsigned integer values directly from the Resource handle */
+#define RES_GET_INT(res) (((int32_t)((res)<<4L))>>4L)
+#define RES_GET_UINT(res) ((res)&0x0fffffff)
+
+#define URES_IS_ARRAY(type) ((type)==URES_ARRAY || (type)==URES_ARRAY16)
+#define URES_IS_TABLE(type) ((type)==URES_TABLE || (type)==URES_TABLE16 || (type)==URES_TABLE32)
+#define URES_IS_CONTAINER(type) (URES_IS_TABLE(type) || URES_IS_ARRAY(type))
+
+#define URES_MAKE_RESOURCE(type, offset) (((Resource)(type)<<28)|(Resource)(offset))
+#define URES_MAKE_EMPTY_RESOURCE(type) ((Resource)(type)<<28)
+
+/* indexes[] value names; indexes are generally 32-bit (Resource) indexes */
+enum {
+    URES_INDEX_LENGTH,          /* [0] contains URES_INDEX_TOP==the length of indexes[];
+                                 *     formatVersion==1: all bits contain the length of indexes[]
+                                 *       but the length is much less than 0xff;
+                                 *     formatVersion>1:
+                                 *       only bits  7..0 contain the length of indexes[],
+                                 *            bits 31..8 are reserved and set to 0 */
+    URES_INDEX_KEYS_TOP,        /* [1] contains the top of the key strings, */
+                                /*     same as the bottom of resources or UTF-16 strings, rounded up */
+    URES_INDEX_RESOURCES_TOP,   /* [2] contains the top of all resources */
+    URES_INDEX_BUNDLE_TOP,      /* [3] contains the top of the bundle, */
+                                /*     in case it were ever different from [2] */
+    URES_INDEX_MAX_TABLE_LENGTH,/* [4] max. length of any table */
+    URES_INDEX_ATTRIBUTES,      /* [5] attributes bit set, see URES_ATT_* (new in formatVersion 1.2) */
+    URES_INDEX_16BIT_TOP,       /* [6] top of the 16-bit units (UTF-16 string v2 UChars, URES_TABLE16, URES_ARRAY16),
+                                 *     rounded up (new in formatVersion 2.0, ICU 4.4) */
+    URES_INDEX_POOL_CHECKSUM,   /* [7] checksum of the pool bundle (new in formatVersion 2.0, ICU 4.4) */
+    URES_INDEX_TOP
+};
+
+/*
+ * Nofallback attribute, attribute bit 0 in indexes[URES_INDEX_ATTRIBUTES].
+ * New in formatVersion 1.2 (ICU 3.6).
+ *
+ * If set, then this resource bundle is a standalone bundle.
+ * If not set, then the bundle participates in locale fallback, eventually
+ * all the way to the root bundle.
+ * If indexes[] is missing or too short, then the attribute cannot be determined
+ * reliably. Dependency checking should ignore such bundles, and loading should
+ * use fallbacks.
+ */
+#define URES_ATT_NO_FALLBACK 1
+
+/*
+ * Attributes for bundles that are, or use, a pool bundle.
+ * A pool bundle provides key strings that are shared among several other bundles
+ * to reduce their total size.
+ * New in formatVersion 2 (ICU 4.4).
+ */
+#define URES_ATT_IS_POOL_BUNDLE 2
+#define URES_ATT_USES_POOL_BUNDLE 4
+
+/*
+ * File format for .res resource bundle files (formatVersion=2, ICU 4.4)
+ *
+ * New in formatVersion 2 compared with 1.3: -------------
+ *
+ * Three new resource types -- String-v2, Table16 and Array16 -- have their
+ * values stored in a new array of 16-bit units between the table key strings
+ * and the start of the other resources.
+ *
+ * genrb eliminates duplicates among Unicode string-v2 values.
+ * Multiple Unicode strings may use the same offset and string data,
+ * or a short string may point to the suffix of a longer string. ("Suffix sharing")
+ * For example, one string "abc" may be reused for another string "bc" by pointing
+ * to the second character. (Short strings-v2 are NUL-terminated
+ * and not preceded by an explicit length value.)
+ *
+ * It is allowed for all resource types to share values.
+ * The swapper code (ures_swap()) has been modified so that it swaps each item
+ * exactly once.
+ *
+ * A resource bundle may use a special pool bundle. Some or all of the table key strings
+ * of the using-bundle are omitted, and the key string offsets for such key strings refer
+ * to offsets in the pool bundle.
+ * The using-bundle's and the pool-bundle's indexes[URES_INDEX_POOL_CHECKSUM] values
+ * must match.
+ * Two bits in indexes[URES_INDEX_ATTRIBUTES] indicate whether a resource bundle
+ * is or uses a pool bundle.
+ *
+ * Table key strings must be compared in ASCII order, even if they are not
+ * stored in ASCII.
+ *
+ * New in formatVersion 1.3 compared with 1.2: -------------
+ *
+ * genrb eliminates duplicates among key strings.
+ * Multiple table items may share one key string, or one item may point
+ * to the suffix of another's key string. ("Suffix sharing")
+ * For example, one key "abc" may be reused for another key "bc" by pointing
+ * to the second character. (Key strings are NUL-terminated.)
+ *
+ * -------------
+ *
+ * An ICU4C resource bundle file (.res) is a binary, memory-mappable file
+ * with nested, hierarchical data structures.
+ * It physically contains the following:
+ *
+ *   Resource root; -- 32-bit Resource item, root item for this bundle's tree;
+ *                     currently, the root item must be a table or table32 resource item
+ *   int32_t indexes[indexes[0]]; -- array of indexes for friendly
+ *                                   reading and swapping; see URES_INDEX_* above
+ *                                   new in formatVersion 1.1 (ICU 2.8)
+ *   char keys[]; -- characters for key strings
+ *                   (formatVersion 1.0: up to 65k of characters; 1.1: <2G)
+ *                   (minus the space for root and indexes[]),
+ *                   which consist of invariant characters (ASCII/EBCDIC) and are NUL-terminated;
+ *                   padded to multiple of 4 bytes for 4-alignment of the following data
+ *   uint16_t 16BitUnits[]; -- resources that are stored entirely as sequences of 16-bit units
+ *                             (new in formatVersion 2/ICU 4.4)
+ *                             data is indexed by the offset values in 16-bit resource types,
+ *                             with offset 0 pointing to the beginning of this array;
+ *                             there is a 0 at offset 0, for empty resources;
+ *                             padded to multiple of 4 bytes for 4-alignment of the following data
+ *   data; -- data directly and indirectly indexed by the root item;
+ *            the structure is determined by walking the tree
+ *
+ * Each resource bundle item has a 32-bit Resource handle (see typedef above)
+ * which contains the item type number in its upper 4 bits (31..28) and either
+ * an offset or a direct value in its lower 28 bits (27..0).
+ * The order of items is undefined and only determined by walking the tree.
+ * Leaves of the tree may be stored first or last or anywhere in between,
+ * and it is in theory possible to have unreferenced holes in the file.
+ *
+ * 16-bit-unit values:
+ * Starting with formatVersion 2/ICU 4.4, some resources are stored in a special
+ * array of 16-bit units. Each resource value is a sequence of 16-bit units,
+ * with no per-resource padding to a 4-byte boundary.
+ * 16-bit container types (Table16 and Array16) contain Resource16 values
+ * which are offsets to String-v2 resources in the same 16-bit-units array.
+ *
+ * Direct values:
+ * - Empty Unicode strings have an offset value of 0 in the Resource handle itself.
+ * - Starting with formatVersion 2/ICU 4.4, an offset value of 0 for
+ *   _any_ resource type indicates an empty value.
+ * - Integer values are 28-bit values stored in the Resource handle itself;
+ *   the interpretation of unsigned vs. signed integers is up to the application.
+ *
+ * All other types and values use 28-bit offsets to point to the item's data.
+ * The offset is an index to the first 32-bit word of the value, relative to the
+ * start of the resource data (i.e., the root item handle is at offset 0).
+ * To get byte offsets, the offset is multiplied by 4 (or shifted left by 2 bits).
+ * All resource item values are 4-aligned.
+ *
+ * New in formatVersion 2/ICU 4.4: Some types use offsets into the 16-bit-units array,
+ * indexing 16-bit units in that array.
+ *
+ * The structures (memory layouts) for the values for each item type are listed
+ * in the table below.
+ *
+ * Nested, hierarchical structures: -------------
+ *
+ * Table items contain key-value pairs where the keys are offsets to char * key strings.
+ * The values of these pairs are either Resource handles or
+ * offsets into the 16-bit-units array, depending on the table type.
+ *
+ * Array items are simple vectors of Resource handles,
+ * or of offsets into the 16-bit-units array, depending on the array type.
+ *
+ * Table key string offsets: -------
+ *
+ * Key string offsets are relative to the start of the resource data (of the root handle),
+ * i.e., the first string has an offset of 4+sizeof(indexes).
+ * (After the 4-byte root handle and after the indexes array.)
+ *
+ * If the resource bundle uses a pool bundle, then some key strings are stored
+ * in the pool bundle rather than in the local bundle itself.
+ * - In a Table or Table16, the 16-bit key string offset is local if it is
+ *   less than indexes[URES_INDEX_KEYS_TOP]<<2.
+ *   Otherwise, subtract indexes[URES_INDEX_KEYS_TOP]<<2 to get the offset into
+ *   the pool bundle key strings.
+ * - In a Table32, the 32-bit key string offset is local if it is non-negative.
+ *   Otherwise, reset bit 31 to get the pool key string offset.
+ *
+ * Unlike the local offset, the pool key offset is relative to
+ * the start of the key strings, not to the start of the bundle.
+ *
+ * An alias item is special (and new in ICU 2.4): --------------
+ *
+ * Its memory layout is just like for a UnicodeString, but at runtime it resolves to
+ * another resource bundle's item according to the path in the string.
+ * This is used to share items across bundles that are in different lookup/fallback
+ * chains (e.g., large collation data among zh_TW and zh_HK).
+ * This saves space (for large items) and maintenance effort (less duplication of data).
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Resource types:
+ *
+ * Most resources have their values stored at four-byte offsets from the start
+ * of the resource data. These values are at least 4-aligned.
+ * Some resource values are stored directly in the offset field of the Resource itself.
+ * See UResType in unicode/ures.h for enumeration constants for Resource types.
+ *
+ * Some resources have their values stored as sequences of 16-bit units,
+ * at 2-byte offsets from the start of a contiguous 16-bit-unit array between
+ * the table key strings and the other resources. (new in formatVersion 2/ICU 4.4)
+ * At offset 0 of that array is a 16-bit zero value for empty 16-bit resources.
+ * Resource16 values in Table16 and Array16 are 16-bit offsets to String-v2
+ * resources, with the offsets relative to the start of the 16-bit-units array.
+ *
+ * Type Name            Memory layout of values
+ *                      (in parentheses: scalar, non-offset values)
+ *
+ * 0  Unicode String:   int32_t length, UChar[length], (UChar)0, (padding)
+ *                  or  (empty string ("") if offset==0)
+ * 1  Binary:           int32_t length, uint8_t[length], (padding)
+ *                      - the start of the bytes is 16-aligned -
+ * 2  Table:            uint16_t count, uint16_t keyStringOffsets[count], (uint16_t padding), Resource[count]
+ * 3  Alias:            (physically same value layout as string, new in ICU 2.4)
+ * 4  Table32:          int32_t count, int32_t keyStringOffsets[count], Resource[count]
+ *                      (new in formatVersion 1.1/ICU 2.8)
+ * 5  Table16:          uint16_t count, uint16_t keyStringOffsets[count], Resource16[count]
+ *                      (stored in the 16-bit-units array; new in formatVersion 2/ICU 4.4)
+ * 6  Unicode String-v2:UChar[length], (UChar)0; length determined by the first UChar:
+ *                      - if first is not a trail surrogate, then the length is implicit
+ *                        and u_strlen() needs to be called
+ *                      - if first<0xdfef then length=first&0x3ff (and skip first)
+ *                      - if first<0xdfff then length=((first-0xdfef)<<16) | second UChar
+ *                      - if first==0xdfff then length=((second UChar)<<16) | third UChar
+ *                      (stored in the 16-bit-units array; new in formatVersion 2/ICU 4.4)
+ * 7  Integer:          (28-bit offset is integer value)
+ * 8  Array:            int32_t count, Resource[count]
+ * 9  Array16:          uint16_t count, Resource16[count]
+ *                      (stored in the 16-bit-units array; new in formatVersion 2/ICU 4.4)
+ * 14 Integer Vector:   int32_t length, int32_t[length]
+ * 15 Reserved:         This value denotes special purpose resources and is for internal use.
+ *
+ * Note that there are 3 types with data vector values:
+ * - Vectors of 8-bit bytes stored as type Binary.
+ * - Vectors of 16-bit words stored as type Unicode String or Unicode String-v2
+ *                     (no value restrictions, all values 0..ffff allowed!).
+ * - Vectors of 32-bit words stored as type Integer Vector.
+ */
+
+/*
+ * Structure for a single, memory-mapped ResourceBundle.
+ */
+typedef struct {
+    UDataMemory *data;
+    const int32_t *pRoot;
+    const uint16_t *p16BitUnits;
+    const char *poolBundleKeys;
+    Resource rootRes;
+    int32_t localKeyLimit;
+    UBool noFallback; /* see URES_ATT_NO_FALLBACK */
+    UBool isPoolBundle;
+    UBool usesPoolBundle;
+    UBool useNativeStrcmp;
+} ResourceData;
+
+/*
+ * Read a resource bundle from memory.
+ */
+U_INTERNAL void U_EXPORT2
+res_read(ResourceData *pResData,
+         const UDataInfo *pInfo, const void *inBytes, int32_t length,
+         UErrorCode *errorCode);
+
+/*
+ * Load a resource bundle file.
+ * The ResourceData structure must be allocated externally.
+ */
+U_CFUNC void
+res_load(ResourceData *pResData,
+         const char *path, const char *name, UErrorCode *errorCode);
+
+/*
+ * Release a resource bundle file.
+ * This does not release the ResourceData structure itself.
+ */
+U_CFUNC void
+res_unload(ResourceData *pResData);
+
+U_INTERNAL UResType U_EXPORT2
+res_getPublicType(Resource res);
+
+/*
+ * Return a pointer to a zero-terminated, const UChar* string
+ * and set its length in *pLength.
+ * Returns NULL if not found.
+ */
+U_INTERNAL const UChar * U_EXPORT2
+res_getString(const ResourceData *pResData, Resource res, int32_t *pLength);
+
+U_INTERNAL const UChar * U_EXPORT2
+res_getAlias(const ResourceData *pResData, Resource res, int32_t *pLength);
+
+U_INTERNAL const uint8_t * U_EXPORT2
+res_getBinary(const ResourceData *pResData, Resource res, int32_t *pLength);
+
+U_INTERNAL const int32_t * U_EXPORT2
+res_getIntVector(const ResourceData *pResData, Resource res, int32_t *pLength);
+
+U_INTERNAL Resource U_EXPORT2
+res_getResource(const ResourceData *pResData, const char *key);
+
+U_INTERNAL int32_t U_EXPORT2
+res_countArrayItems(const ResourceData *pResData, Resource res);
+
+U_INTERNAL Resource U_EXPORT2
+res_getArrayItem(const ResourceData *pResData, Resource array, int32_t indexS);
+
+U_INTERNAL Resource U_EXPORT2
+res_getTableItemByIndex(const ResourceData *pResData, Resource table, int32_t indexS, const char ** key);
+
+U_INTERNAL Resource U_EXPORT2
+res_getTableItemByKey(const ResourceData *pResData, Resource table, int32_t *indexS, const char* * key);
+
+/*
+ * Modifies the contents of *path (replacing separators with NULs),
+ * and also moves *path forward while it finds items.
+ */
+U_CFUNC Resource res_findResource(const ResourceData *pResData, Resource r, char** path, const char** key);
+
+/**
+ * Swap an ICU resource bundle. See udataswp.h.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+ures_swap(const UDataSwapper *ds,
+          const void *inData, int32_t length, void *outData,
+          UErrorCode *pErrorCode);
+
+#endif
diff --git a/source/common/uresimp.h b/source/common/uresimp.h
new file mode 100644
index 0000000..fdae486
--- /dev/null
+++ b/source/common/uresimp.h
@@ -0,0 +1,274 @@
+/*
+**********************************************************************
+*   Copyright (C) 2000-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+
+#ifndef URESIMP_H
+#define URESIMP_H
+
+#include "unicode/ures.h"
+
+#include "uresdata.h"
+
+#define kRootLocaleName         "root"
+#define kPoolBundleName         "pool"
+
+/*
+ The default minor version and the version separator must be exactly one
+ character long.
+*/
+
+#define kDefaultMinorVersion    "0"
+#define kVersionSeparator       "."
+#define kVersionTag             "Version"
+
+#define MAGIC1 19700503
+#define MAGIC2 19641227
+
+#define URES_MAX_ALIAS_LEVEL 256
+#define URES_MAX_BUFFER_SIZE 256
+
+/*
+enum UResEntryType {
+    ENTRY_OK = 0,
+    ENTRY_GOTO_ROOT = 1,
+    ENTRY_GOTO_DEFAULT = 2,
+    ENTRY_INVALID = 3
+};
+
+typedef enum UResEntryType UResEntryType;
+*/
+
+struct UResourceDataEntry;
+typedef struct UResourceDataEntry UResourceDataEntry;
+
+/*
+ * Note: If we wanted to make this structure smaller, then we could try
+ * to use one UResourceDataEntry pointer for fAlias and fPool, with a separate
+ * flag to distinguish whether this struct is for a real bundle with a pool,
+ * or for an alias entry for which we won't use the pool after loading.
+ */
+struct UResourceDataEntry {
+    char *fName; /* name of the locale for bundle - still to decide whether it is original or fallback */
+    char *fPath; /* path to bundle - used for distinguishing between resources with the same name */
+    UResourceDataEntry *fParent; /*next resource in fallback chain*/
+    UResourceDataEntry *fAlias;
+    UResourceDataEntry *fPool;
+    ResourceData fData; /* data for low level access */
+    char fNameBuffer[3]; /* A small buffer of free space for fName. The free space is due to struct padding. */
+    uint32_t fCountExisting; /* how much is this resource used */
+    UErrorCode fBogus;
+    /* int32_t fHashKey;*/ /* for faster access in the hashtable */
+};
+
+#define RES_BUFSIZE 64
+#define RES_PATH_SEPARATOR   '/'
+#define RES_PATH_SEPARATOR_S   "/"
+
+struct UResourceBundle {
+    const char *fKey; /*tag*/
+    UResourceDataEntry *fData; /*for low-level access*/
+    char *fVersion;
+    UResourceDataEntry *fTopLevelData; /* for getting the valid locale */
+    char *fResPath; /* full path to the resource: "zh_TW/CollationElements/Sequence" */
+    ResourceData fResData;
+    char fResBuf[RES_BUFSIZE];
+    int32_t fResPathLen;
+    Resource fRes;
+    UBool fHasFallback;
+    UBool fIsTopLevel;
+    uint32_t fMagic1;   /* For determining if it's a stack object */
+    uint32_t fMagic2;   /* For determining if it's a stack object */
+    int32_t fIndex;
+    int32_t fSize;
+
+    /*const UResourceBundle *fParentRes;*/ /* needed to get the actual locale for a child resource */
+};
+
+U_CAPI void U_EXPORT2 ures_initStackObject(UResourceBundle* resB);
+
+/* Some getters used by the copy constructor */
+U_CFUNC const char* ures_getName(const UResourceBundle* resB);
+#ifdef URES_DEBUG
+U_CFUNC const char* ures_getPath(const UResourceBundle* resB);
+/**
+ * If anything was in the RB cache, dump it to the screen.
+ * @return TRUE if there was anything into the cache
+ */
+U_CAPI UBool U_EXPORT2 ures_dumpCacheContents(void);
+#endif
+/*U_CFUNC void ures_appendResPath(UResourceBundle *resB, const char* toAdd, int32_t lenToAdd);*/
+/*U_CFUNC void ures_setResPath(UResourceBundle *resB, const char* toAdd);*/
+/*U_CFUNC void ures_freeResPath(UResourceBundle *resB);*/
+
+/* Candidates for export */
+U_CFUNC UResourceBundle *ures_copyResb(UResourceBundle *r, const UResourceBundle *original, UErrorCode *status);
+
+/**
+ * Returns a resource that can be located using the pathToResource argument. One needs optional package, locale
+ * and path inside the locale, for example: "/myData/en/zoneStrings/3". Keys and indexes are supported. Keys
+ * need to reference data in named structures, while indexes can reference both named and anonymous resources.
+ * Features a fill-in parameter. 
+ * 
+ * Note, this function does NOT have a syntax for specifying items within a tree.  May want to consider a
+ * syntax that delineates between package/tree and resource.  
+ *
+ * @param pathToResource    a path that will lead to the requested resource
+ * @param fillIn            if NULL a new UResourceBundle struct is allocated and must be deleted by the caller.
+ *                          Alternatively, you can supply a struct to be filled by this function.
+ * @param status            fills in the outgoing error code.
+ * @return                  a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it
+ * @draft ICU 2.2
+ */
+U_CAPI UResourceBundle* U_EXPORT2
+ures_findResource(const char* pathToResource, 
+                  UResourceBundle *fillIn, UErrorCode *status); 
+
+/**
+ * Returns a sub resource that can be located using the pathToResource argument. One needs a path inside 
+ * the supplied resource, for example, if you have "en_US" resource bundle opened, you might ask for
+ * "zoneStrings/3". Keys and indexes are supported. Keys
+ * need to reference data in named structures, while indexes can reference both 
+ * named and anonymous resources.
+ * Features a fill-in parameter. 
+ *
+ * @param resourceBundle    a resource
+ * @param pathToResource    a path that will lead to the requested resource
+ * @param fillIn            if NULL a new UResourceBundle struct is allocated and must be deleted by the caller.
+ *                          Alternatively, you can supply a struct to be filled by this function.
+ * @param status            fills in the outgoing error code.
+ * @return                  a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it
+ * @draft ICU 2.2
+ */
+U_CAPI UResourceBundle* U_EXPORT2
+ures_findSubResource(const UResourceBundle *resB, 
+                     char* pathToResource, 
+                     UResourceBundle *fillIn, UErrorCode *status);
+
+/**
+ * Returns a functionally equivalent locale (considering keywords) for the specified keyword.
+ * @param result fillin for the equivalent locale
+ * @param resultCapacity capacity of the fillin buffer
+ * @param path path to the tree, or NULL for ICU data
+ * @param resName top level resource. Example: "collations"
+ * @param keyword locale keyword. Example: "collation"
+ * @param locid The requested locale
+ * @param isAvailable If non-null, pointer to fillin parameter that indicates whether the 
+ * requested locale was available. The locale is defined as 'available' if it physically 
+ * exists within the specified tree.
+ * @param omitDefault if TRUE, omit keyword and value if default. 'de_DE\@collation=standard' -> 'de_DE'
+ * @param status error code
+ * @return  the actual buffer size needed for the full locale.  If it's greater 
+ * than resultCapacity, the returned full name will be truncated and an error code will be returned.
+ * @internal ICU 3.0
+ */
+U_INTERNAL int32_t U_EXPORT2
+ures_getFunctionalEquivalent(char *result, int32_t resultCapacity, 
+                             const char *path, const char *resName, const char *keyword, const char *locid,
+                             UBool *isAvailable, UBool omitDefault, UErrorCode *status);
+
+/**
+ * Given a tree path and keyword, return a string enumeration of all possible values for that keyword.
+ * @param path path to the tree, or NULL for ICU data
+ * @param keyword a particular keyword to consider, must match a top level resource name 
+ * within the tree.
+ * @param status error code
+ * @internal ICU 3.0
+ */
+U_INTERNAL UEnumeration* U_EXPORT2
+ures_getKeywordValues(const char *path, const char *keyword, UErrorCode *status);
+
+
+/**
+ * Get a resource with multi-level fallback. Normally only the top level resources will
+ * fallback to its parent. This performs fallback on subresources. For example, when a table
+ * is defined in a resource bundle and a parent resource bundle, normally no fallback occurs
+ * on the sub-resources because the table is defined in the current resource bundle, but this
+ * function can perform fallback on the sub-resources of the table.
+ * @param resB              a resource
+ * @param inKey             a key associated with the requested resource
+ * @param fillIn            if NULL a new UResourceBundle struct is allocated and must be deleted by the caller.
+ *                          Alternatively, you can supply a struct to be filled by this function.
+ * @param status: fills in the outgoing error code
+ *                could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found
+ *                could be a non-failing error 
+ *                e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT>
+ * @return                  a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it
+ * @internal ICU 3.0
+ */
+U_INTERNAL UResourceBundle* U_EXPORT2 
+ures_getByKeyWithFallback(const UResourceBundle *resB, 
+                          const char* inKey, 
+                          UResourceBundle *fillIn, 
+                          UErrorCode *status);
+
+
+/**
+ * Get a String with multi-level fallback. Normally only the top level resources will
+ * fallback to its parent. This performs fallback on subresources. For example, when a table
+ * is defined in a resource bundle and a parent resource bundle, normally no fallback occurs
+ * on the sub-resources because the table is defined in the current resource bundle, but this
+ * function can perform fallback on the sub-resources of the table.
+ * @param resB              a resource
+ * @param inKey             a key associated with the requested resource
+ * @param status: fills in the outgoing error code
+ *                could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found
+ *                could be a non-failing error 
+ *                e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT>
+ * @return                  a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it
+ * @internal ICU 3.4
+ * @draft ICU 3.4
+ */
+U_INTERNAL const UChar* U_EXPORT2 
+ures_getStringByKeyWithFallback(const UResourceBundle *resB, 
+                          const char* inKey,  
+                          int32_t* len,
+                          UErrorCode *status);
+
+/**
+ * Get a version number by key
+ * @param resB bundle containing version number
+ * @param key the key for the version number
+ * @param ver fillin for the version number
+ * @param status error code
+ * @internal ICU 4.2
+ */
+U_INTERNAL void U_EXPORT2
+ures_getVersionByKey(const UResourceBundle *resB,
+                     const char *key,
+                     UVersionInfo ver,
+                     UErrorCode *status);
+
+
+/**
+ * Internal function.
+ * Return the version number associated with this ResourceBundle as a string.
+ *
+ * @param resourceBundle The resource bundle for which the version is checked.
+ * @return  A version number string as specified in the resource bundle or its parent.
+ *          The caller does not own this string.
+ * @see ures_getVersion
+ * @internal
+ */
+U_INTERNAL const char* U_EXPORT2 
+ures_getVersionNumberInternal(const UResourceBundle *resourceBundle);
+
+/**
+ * Return the name of the Locale associated with this ResourceBundle. This API allows
+ * you to query for the real locale of the resource. For example, if you requested 
+ * "en_US_CALIFORNIA" and only "en_US" bundle exists, "en_US" will be returned. 
+ * For subresources, the locale where this resource comes from will be returned.
+ * If fallback has occured, getLocale will reflect this.
+ *
+ * @param resourceBundle resource bundle in question
+ * @param status just for catching illegal arguments
+ * @return  A Locale name
+ * @deprecated ICU 2.8 Use ures_getLocaleByType instead.
+ */
+U_INTERNAL const char* U_EXPORT2 
+ures_getLocaleInternal(const UResourceBundle* resourceBundle, 
+               UErrorCode* status);
+
+#endif /*URESIMP_H*/
diff --git a/source/common/ureslocs.h b/source/common/ureslocs.h
new file mode 100644
index 0000000..363da26
--- /dev/null
+++ b/source/common/ureslocs.h
@@ -0,0 +1,24 @@
+/*
+**********************************************************************
+*   Copyright (C) 2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+
+#ifndef __URESLOCS_H__
+#define __URESLOCS_H__
+
+#include "unicode/utypes.h"
+#include "unicode/udata.h"
+
+U_CDECL_BEGIN
+
+
+#define U_ICUDATA_LANG U_ICUDATA_NAME U_TREE_SEPARATOR_STRING "lang"
+#define U_ICUDATA_REGION U_ICUDATA_NAME U_TREE_SEPARATOR_STRING "region"
+#define U_ICUDATA_CURR U_ICUDATA_NAME U_TREE_SEPARATOR_STRING "curr"
+#define U_ICUDATA_ZONE U_ICUDATA_NAME U_TREE_SEPARATOR_STRING "zone"
+
+U_CDECL_END
+
+#endif
diff --git a/source/common/usc_impl.c b/source/common/usc_impl.c
new file mode 100644
index 0000000..71fdf94
--- /dev/null
+++ b/source/common/usc_impl.c
@@ -0,0 +1,361 @@
+/*
+**********************************************************************
+*   Copyright (C) 1999-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*
+* File USC_IMPL.C
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   07/08/2002  Eric Mader  Creation.
+******************************************************************************
+*/
+
+#include "unicode/uscript.h"
+#include "usc_impl.h"
+#include "cmemory.h"
+
+#define ARRAY_SIZE(array) (sizeof array  / sizeof array[0])
+
+#define PAREN_STACK_DEPTH 32
+
+#define MOD(sp) ((sp) % PAREN_STACK_DEPTH)
+#define LIMIT_INC(sp) (((sp) < PAREN_STACK_DEPTH)? (sp) + 1 : PAREN_STACK_DEPTH)
+#define INC(sp,count) (MOD((sp) + (count)))
+#define INC1(sp) (INC(sp, 1))
+#define DEC(sp,count) (MOD((sp) + PAREN_STACK_DEPTH - (count)))
+#define DEC1(sp) (DEC(sp, 1))
+#define STACK_IS_EMPTY(scriptRun) ((scriptRun)->pushCount <= 0)
+#define STACK_IS_NOT_EMPTY(scriptRun) (! STACK_IS_EMPTY(scriptRun))
+#define TOP(scriptRun) ((scriptRun)->parenStack[(scriptRun)->parenSP])
+#define SYNC_FIXUP(scriptRun) ((scriptRun)->fixupCount = 0)
+
+struct ParenStackEntry
+{
+    int32_t pairIndex;
+    UScriptCode scriptCode;
+};
+
+struct UScriptRun
+{
+    int32_t textLength;
+    const UChar *textArray;
+
+    int32_t scriptStart;
+    int32_t scriptLimit;
+    UScriptCode scriptCode;
+
+    struct ParenStackEntry parenStack[PAREN_STACK_DEPTH];
+    int32_t parenSP;
+    int32_t pushCount;
+    int32_t fixupCount;
+};
+
+static int8_t highBit(int32_t value);
+
+static const UChar32 pairedChars[] = {
+    0x0028, 0x0029, /* ascii paired punctuation */
+    0x003c, 0x003e,
+    0x005b, 0x005d,
+    0x007b, 0x007d,
+    0x00ab, 0x00bb, /* guillemets */
+    0x2018, 0x2019, /* general punctuation */
+    0x201c, 0x201d,
+    0x2039, 0x203a,
+    0x3008, 0x3009, /* chinese paired punctuation */
+    0x300a, 0x300b,
+    0x300c, 0x300d,
+    0x300e, 0x300f,
+    0x3010, 0x3011,
+    0x3014, 0x3015,
+    0x3016, 0x3017,
+    0x3018, 0x3019,
+    0x301a, 0x301b
+};
+
+static void push(UScriptRun *scriptRun, int32_t pairIndex, UScriptCode scriptCode)
+{
+    scriptRun->pushCount  = LIMIT_INC(scriptRun->pushCount);
+    scriptRun->fixupCount = LIMIT_INC(scriptRun->fixupCount);
+    
+    scriptRun->parenSP = INC1(scriptRun->parenSP);
+    scriptRun->parenStack[scriptRun->parenSP].pairIndex  = pairIndex;
+    scriptRun->parenStack[scriptRun->parenSP].scriptCode = scriptCode;
+}
+
+static void pop(UScriptRun *scriptRun)
+{
+    if (STACK_IS_EMPTY(scriptRun)) {
+        return;
+    }
+    
+    if (scriptRun->fixupCount > 0) {
+        scriptRun->fixupCount -= 1;
+    }
+    
+    scriptRun->pushCount -= 1;
+    scriptRun->parenSP = DEC1(scriptRun->parenSP);
+    
+    /* If the stack is now empty, reset the stack
+       pointers to their initial values.
+     */
+    if (STACK_IS_EMPTY(scriptRun)) {
+        scriptRun->parenSP = -1;
+    }
+}
+
+static void fixup(UScriptRun *scriptRun, UScriptCode scriptCode)
+{
+    int32_t fixupSP = DEC(scriptRun->parenSP, scriptRun->fixupCount);
+    
+    while (scriptRun->fixupCount-- > 0) {
+        fixupSP = INC1(fixupSP);
+        scriptRun->parenStack[fixupSP].scriptCode = scriptCode;
+    }
+}
+
+static int8_t
+highBit(int32_t value)
+{
+    int8_t bit = 0;
+
+    if (value <= 0) {
+        return -32;
+    }
+
+    if (value >= 1 << 16) {
+        value >>= 16;
+        bit += 16;
+    }
+
+    if (value >= 1 << 8) {
+        value >>= 8;
+        bit += 8;
+    }
+
+    if (value >= 1 << 4) {
+        value >>= 4;
+        bit += 4;
+    }
+
+    if (value >= 1 << 2) {
+        value >>= 2;
+        bit += 2;
+    }
+
+    if (value >= 1 << 1) {
+        value >>= 1;
+        bit += 1;
+    }
+
+    return bit;
+}
+
+static int32_t
+getPairIndex(UChar32 ch)
+{
+    int32_t pairedCharCount = ARRAY_SIZE(pairedChars);
+    int32_t pairedCharPower = 1 << highBit(pairedCharCount);
+    int32_t pairedCharExtra = pairedCharCount - pairedCharPower;
+
+    int32_t probe = pairedCharPower;
+    int32_t pairIndex = 0;
+
+    if (ch >= pairedChars[pairedCharExtra]) {
+        pairIndex = pairedCharExtra;
+    }
+
+    while (probe > (1 << 0)) {
+        probe >>= 1;
+
+        if (ch >= pairedChars[pairIndex + probe]) {
+            pairIndex += probe;
+        }
+    }
+
+    if (pairedChars[pairIndex] != ch) {
+        pairIndex = -1;
+    }
+
+    return pairIndex;
+}
+
+static UBool
+sameScript(UScriptCode scriptOne, UScriptCode scriptTwo)
+{
+    return scriptOne <= USCRIPT_INHERITED || scriptTwo <= USCRIPT_INHERITED || scriptOne == scriptTwo;
+}
+
+U_CAPI UScriptRun * U_EXPORT2
+uscript_openRun(const UChar *src, int32_t length, UErrorCode *pErrorCode)
+{
+    UScriptRun *result = NULL;
+
+    if (pErrorCode == NULL || U_FAILURE(*pErrorCode)) {
+        return NULL;
+    }
+
+    result = uprv_malloc(sizeof (UScriptRun));
+
+    if (result == NULL) {
+        *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+
+    uscript_setRunText(result, src, length, pErrorCode);
+
+    /* Release the UScriptRun if uscript_setRunText() returns an error */
+    if (U_FAILURE(*pErrorCode)) {
+        uprv_free(result);
+        result = NULL;
+    }
+
+    return result;
+}
+
+U_CAPI void U_EXPORT2
+uscript_closeRun(UScriptRun *scriptRun)
+{
+    if (scriptRun != NULL) {
+        uprv_free(scriptRun);
+    }
+}
+
+U_CAPI void U_EXPORT2
+uscript_resetRun(UScriptRun *scriptRun)
+{
+    if (scriptRun != NULL) {
+        scriptRun->scriptStart = 0;
+        scriptRun->scriptLimit = 0;
+        scriptRun->scriptCode  = USCRIPT_INVALID_CODE;
+        scriptRun->parenSP     = -1;
+        scriptRun->pushCount   =  0;
+        scriptRun->fixupCount  =  0;
+    }
+}
+
+U_CAPI void U_EXPORT2
+uscript_setRunText(UScriptRun *scriptRun, const UChar *src, int32_t length, UErrorCode *pErrorCode)
+{
+    if (pErrorCode == NULL || U_FAILURE(*pErrorCode)) {
+        return;
+    }
+
+    if (scriptRun == NULL || length < 0 || ((src == NULL) != (length == 0))) {
+        *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    scriptRun->textArray  = src;
+    scriptRun->textLength = length;
+
+    uscript_resetRun(scriptRun);
+}
+
+U_CAPI UBool U_EXPORT2
+uscript_nextRun(UScriptRun *scriptRun, int32_t *pRunStart, int32_t *pRunLimit, UScriptCode *pRunScript)
+{
+    UErrorCode error = U_ZERO_ERROR;
+
+    /* if we've fallen off the end of the text, we're done */
+    if (scriptRun == NULL || scriptRun->scriptLimit >= scriptRun->textLength) {
+        return FALSE;
+    }
+    
+    SYNC_FIXUP(scriptRun);
+    scriptRun->scriptCode = USCRIPT_COMMON;
+
+    for (scriptRun->scriptStart = scriptRun->scriptLimit; scriptRun->scriptLimit < scriptRun->textLength; scriptRun->scriptLimit += 1) {
+        UChar   high = scriptRun->textArray[scriptRun->scriptLimit];
+        UChar32 ch   = high;
+        UScriptCode sc;
+        int32_t pairIndex;
+
+        /*
+         * if the character is a high surrogate and it's not the last one
+         * in the text, see if it's followed by a low surrogate
+         */
+        if (high >= 0xD800 && high <= 0xDBFF && scriptRun->scriptLimit < scriptRun->textLength - 1) {
+            UChar low = scriptRun->textArray[scriptRun->scriptLimit + 1];
+
+            /*
+             * if it is followed by a low surrogate,
+             * consume it and form the full character
+             */
+            if (low >= 0xDC00 && low <= 0xDFFF) {
+                ch = (high - 0xD800) * 0x0400 + low - 0xDC00 + 0x10000;
+                scriptRun->scriptLimit += 1;
+            }
+        }
+
+        sc = uscript_getScript(ch, &error);
+        pairIndex = getPairIndex(ch);
+
+        /*
+         * Paired character handling:
+         *
+         * if it's an open character, push it onto the stack.
+         * if it's a close character, find the matching open on the
+         * stack, and use that script code. Any non-matching open
+         * characters above it on the stack will be poped.
+         */
+        if (pairIndex >= 0) {
+            if ((pairIndex & 1) == 0) {
+                push(scriptRun, pairIndex, scriptRun->scriptCode);
+            } else {
+                int32_t pi = pairIndex & ~1;
+
+                while (STACK_IS_NOT_EMPTY(scriptRun) && TOP(scriptRun).pairIndex != pi) {
+                    pop(scriptRun);
+                }
+
+                if (STACK_IS_NOT_EMPTY(scriptRun)) {
+                    sc = TOP(scriptRun).scriptCode;
+                }
+            }
+        }
+
+        if (sameScript(scriptRun->scriptCode, sc)) {
+            if (scriptRun->scriptCode <= USCRIPT_INHERITED && sc > USCRIPT_INHERITED) {
+                scriptRun->scriptCode = sc;
+
+                fixup(scriptRun, scriptRun->scriptCode);
+            }
+
+            /*
+             * if this character is a close paired character,
+             * pop the matching open character from the stack
+             */
+            if (pairIndex >= 0 && (pairIndex & 1) != 0) {
+                pop(scriptRun);
+            }
+        } else {
+            /*
+             * if the run broke on a surrogate pair,
+             * end it before the high surrogate
+             */
+            if (ch >= 0x10000) {
+                scriptRun->scriptLimit -= 1;
+            }
+
+            break;
+        }
+    }
+
+
+    if (pRunStart != NULL) {
+        *pRunStart = scriptRun->scriptStart;
+    }
+
+    if (pRunLimit != NULL) {
+        *pRunLimit = scriptRun->scriptLimit;
+    }
+
+    if (pRunScript != NULL) {
+        *pRunScript = scriptRun->scriptCode;
+    }
+
+    return TRUE;
+}
diff --git a/source/common/usc_impl.h b/source/common/usc_impl.h
new file mode 100644
index 0000000..790a709
--- /dev/null
+++ b/source/common/usc_impl.h
@@ -0,0 +1,149 @@
+/*
+**********************************************************************
+*   Copyright (C) 1999-2002, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*
+* File USC_IMPL.H
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   07/08/2002  Eric Mader  Creation.
+******************************************************************************
+*/
+
+#ifndef USC_IMPL_H
+#define USC_IMPL_H
+#include "unicode/utypes.h"
+#include "unicode/uscript.h"
+
+/**
+ * <code>UScriptRun</code> is used to find runs of characters in
+ * the same script. It implements a simple iterator over an array
+ * of characters. The iterator will resolve script-neutral characters
+ * like punctuation into the script of the surrounding characters.
+ *
+ * The iterator will try to match paired punctuation. If it sees an
+ * opening punctuation character, it will remember the script that
+ * was assigned to that character, and assign the same script to the
+ * matching closing punctuation.
+ *
+ * Scripts are chosen based on the <code>UScriptCode</code> enumeration.
+ * No attempt is made to combine related scripts into a single run. In
+ * particular, Hiragana, Katakana, and Han characters will appear in seperate
+ * runs.
+
+ * Here is an example of how to iterate over script runs:
+ * <pre>
+ * \code
+ * void printScriptRuns(const UChar *text, int32_t length)
+ * {
+ *     UErrorCode error = U_ZERO_ERROR;
+ *     UScriptRun *scriptRun = uscript_openRun(text, testLength, &error);
+ *     int32_t start = 0, limit = 0;
+ *     UScriptCode code = USCRIPT_INVALID_CODE;
+ *
+ *     while (uscript_nextRun(&start, &limit, &code)) {
+ *         printf("Script '%s' from %d to %d.\n", uscript_getName(code), start, limit);
+ *     }
+ *
+ *     uscript_closeRun(scriptRun);
+ *  }
+ * </pre>
+ *
+ * @draft ICU 2.2
+ */
+struct UScriptRun;
+
+typedef struct UScriptRun UScriptRun;
+
+/**
+ * Create a <code>UScriptRun</code> object for iterating over the given text. This object must
+ * be freed using <code>uscript_closeRun()</code>. Note that this object does not copy the source text,
+ * only the pointer to it. You must make sure that the pointer remains valid until you call
+ * <code>uscript_closeRun()</code> or <code>uscript_setRunText()</code>.
+ *
+ * @param src is the address of the array of characters over which to iterate.
+ *        if <code>src == NULL</code> and <code>length == 0</code>,
+ *        an empty <code>UScriptRun</code> object will be returned.
+ *
+ * @param length is the number of characters over which to iterate.
+ *
+ * @param pErrorCode is a pointer to a valid <code>UErrorCode</code> value. If this value
+ *        indicates a failure on entry, the function will immediately return.
+ *        On exit the value will indicate the success of the operation.
+ *
+ * @return the address of <code>UScriptRun</code> object which will iterate over the text,
+ *         or <code>NULL</code> if the operation failed.
+ *
+ * @draft ICU 2.2
+ */
+U_CAPI UScriptRun * U_EXPORT2
+uscript_openRun(const UChar *src, int32_t length, UErrorCode *pErrorCode);
+
+/**
+ * Frees the given <code>UScriptRun</code> object and any storage associated with it.
+ * On return, scriptRun no longer points to a valid <code>UScriptRun</code> object.
+ *
+ * @param scriptRun is the <code>UScriptRun</code> object which will be freed.
+ *
+ * @draft ICU 2.2
+ */
+U_CAPI void U_EXPORT2
+uscript_closeRun(UScriptRun *scriptRun);
+
+/**
+ * Reset the <code>UScriptRun</code> object so that it will start iterating from
+ * the beginning.
+ *
+ * @param scriptRun is the address of the <code>UScriptRun</code> object to be reset.
+ *
+ * @draft ICU 2.2
+ */
+U_CAPI void U_EXPORT2
+uscript_resetRun(UScriptRun *scriptRun);
+
+/**
+ * Change the text over which the given <code>UScriptRun</code> object iterates.
+ *
+ * @param scriptRun is the <code>UScriptRun</code> object which will be changed.
+ *
+ * @param src is the address of the new array of characters over which to iterate.
+ *        If <code>src == NULL</code> and <code>length == 0</code>,
+ *        the <code>UScriptRun</code> object will become empty.
+ *
+ * @param length is the new number of characters over which to iterate
+ *
+ * @param pErrorCode is a pointer to a valid <code>UErrorCode</code> value. If this value
+ *        indicates a failure on entry, the function will immediately return.
+ *        On exit the value will indicate the success of the operation.
+ *
+ * @draft ICU 2.2
+ */
+U_CAPI void U_EXPORT2
+uscript_setRunText(UScriptRun *scriptRun, const UChar *src, int32_t length, UErrorCode *pErrorCode);
+
+/**
+ * Advance the <code>UScriptRun</code> object to the next script run, return the start and limit
+ * offsets, and the script of the run.
+ *
+ * @param scriptRun is the address of the <code>UScriptRun</code> object.
+ *
+ * @param pRunStart is a pointer to the variable to receive the starting offset of the next run.
+ *        This pointer can be <code>NULL</code> if the value is not needed.
+ *
+ * @param pRunLimit is a pointer to the variable to receive the limit offset of the next run.
+ *        This pointer can be <code>NULL</code> if the value is not needed.
+ *
+ * @param pRunScript is a pointer to the variable to receive the UScriptCode for the
+ *        script of the current run. This pointer can be <code>NULL</code> if the value is not needed.
+ *
+ * @return true if there was another script run.
+ *
+ * @draft ICU 2.2
+ */
+U_CAPI UBool U_EXPORT2
+uscript_nextRun(UScriptRun *scriptRun, int32_t *pRunStart, int32_t *pRunLimit, UScriptCode *pRunScript);
+
+#endif
diff --git a/source/common/uscript.c b/source/common/uscript.c
new file mode 100644
index 0000000..2a70004
--- /dev/null
+++ b/source/common/uscript.c
@@ -0,0 +1,110 @@
+/*
+**********************************************************************
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*
+* File USCRIPT.C
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   07/06/2001    Ram         Creation.
+******************************************************************************
+*/
+
+#include "unicode/uscript.h"
+#include "unicode/ures.h"
+#include "unicode/uchar.h"
+#include "unicode/putil.h"
+#include "uprops.h"
+#include "cmemory.h"
+#include "cstring.h"
+
+static const char kLocaleScript[] = "LocaleScript";
+
+/* TODO: this is a bad API should be deprecated */
+U_CAPI int32_t  U_EXPORT2
+uscript_getCode(const char* nameOrAbbrOrLocale,
+                UScriptCode* fillIn,
+                int32_t capacity,
+                UErrorCode* err){
+
+    UScriptCode code = USCRIPT_INVALID_CODE;
+    int32_t numFilled=0;
+    int32_t len=0;
+    /* check arguments */
+    if(err==NULL ||U_FAILURE(*err)){
+        return numFilled;
+    }
+    if(nameOrAbbrOrLocale==NULL || fillIn == NULL || capacity<0){
+        *err = U_ILLEGAL_ARGUMENT_ERROR;
+        return numFilled;
+    }
+
+    if(uprv_strchr(nameOrAbbrOrLocale, '-')==NULL && uprv_strchr(nameOrAbbrOrLocale, '_')==NULL ){
+        /* try long and abbreviated script names first */
+        code = (UScriptCode) u_getPropertyValueEnum(UCHAR_SCRIPT, nameOrAbbrOrLocale);
+        
+    }
+    if(code==(UScriptCode)UCHAR_INVALID_CODE){
+       /* Do not propagate error codes from just not finding a locale bundle. */
+        UErrorCode localErrorCode = U_ZERO_ERROR;
+        UResourceBundle* resB = ures_open(NULL,nameOrAbbrOrLocale,&localErrorCode);
+        if(U_SUCCESS(localErrorCode)&& localErrorCode != U_USING_DEFAULT_WARNING){
+            UResourceBundle* resD = ures_getByKey(resB,kLocaleScript,NULL,&localErrorCode);
+            if(U_SUCCESS(localErrorCode) ){
+                len =0;
+                while(ures_hasNext(resD)){
+                    const UChar* name = ures_getNextString(resD,&len,NULL,&localErrorCode);
+                    if(U_SUCCESS(localErrorCode)){
+                        char cName[50] = {'\0'};
+                        u_UCharsToChars(name,cName,len);
+                        code = (UScriptCode) u_getPropertyValueEnum(UCHAR_SCRIPT, cName);
+                        /* got the script code now fill in the buffer */
+                        if(numFilled<capacity){ 
+                            *(fillIn)++=code;
+                            numFilled++;
+                        }else{
+                            ures_close(resD);
+                            ures_close(resB);
+                            *err=U_BUFFER_OVERFLOW_ERROR;
+                            return len;
+                        }
+                    }
+                }
+            }
+            ures_close(resD); 
+        }
+        ures_close(resB);
+        code = USCRIPT_INVALID_CODE;
+    }
+    if(code==(UScriptCode)UCHAR_INVALID_CODE){
+       /* still not found .. try long and abbreviated script names again */
+        code = (UScriptCode) u_getPropertyValueEnum(UCHAR_SCRIPT, nameOrAbbrOrLocale);
+    }
+    if(code!=(UScriptCode)UCHAR_INVALID_CODE){
+        /* we found it */
+        if(numFilled<capacity){ 
+            *(fillIn)++=code;
+            numFilled++;
+        }else{
+            *err=U_BUFFER_OVERFLOW_ERROR;
+            return len;
+        }
+    }
+    return numFilled;
+}
+
+U_CAPI const char*  U_EXPORT2
+uscript_getName(UScriptCode scriptCode){
+    return u_getPropertyValueName(UCHAR_SCRIPT, scriptCode,
+                                  U_LONG_PROPERTY_NAME);
+}
+
+U_CAPI const char*  U_EXPORT2
+uscript_getShortName(UScriptCode scriptCode){
+    return u_getPropertyValueName(UCHAR_SCRIPT, scriptCode,
+                                  U_SHORT_PROPERTY_NAME);
+}
+
diff --git a/source/common/uset.cpp b/source/common/uset.cpp
new file mode 100644
index 0000000..f4d3447
--- /dev/null
+++ b/source/common/uset.cpp
@@ -0,0 +1,644 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2002-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  uset.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002mar07
+*   created by: Markus W. Scherer
+*
+*   There are functions to efficiently serialize a USet into an array of uint16_t
+*   and functions to use such a serialized form efficiently without
+*   instantiating a new USet.
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/uset.h"
+#include "unicode/uniset.h"
+#include "cmemory.h"
+#include "unicode/ustring.h"
+#include "unicode/parsepos.h"
+
+U_NAMESPACE_USE
+
+U_CAPI USet* U_EXPORT2
+uset_openEmpty() {
+    return (USet*) new UnicodeSet();
+}
+
+U_CAPI USet* U_EXPORT2
+uset_open(UChar32 start, UChar32 end) {
+    return (USet*) new UnicodeSet(start, end);
+}
+
+U_CAPI void U_EXPORT2
+uset_close(USet* set) {
+    delete (UnicodeSet*) set;
+}
+
+U_CAPI USet * U_EXPORT2
+uset_clone(const USet *set) {
+    return (USet*) (((UnicodeSet*) set)->UnicodeSet::clone());
+}
+
+U_CAPI UBool U_EXPORT2
+uset_isFrozen(const USet *set) {
+    return ((UnicodeSet*) set)->UnicodeSet::isFrozen();
+}
+
+U_CAPI void U_EXPORT2
+uset_freeze(USet *set) {
+    ((UnicodeSet*) set)->UnicodeSet::freeze();
+}
+
+U_CAPI USet * U_EXPORT2
+uset_cloneAsThawed(const USet *set) {
+    return (USet*) (((UnicodeSet*) set)->UnicodeSet::cloneAsThawed());
+}
+
+U_CAPI void U_EXPORT2
+uset_set(USet* set,
+     UChar32 start, UChar32 end) {
+    ((UnicodeSet*) set)->UnicodeSet::set(start, end);
+}
+
+U_CAPI void U_EXPORT2
+uset_addAll(USet* set, const USet *additionalSet) {
+    ((UnicodeSet*) set)->UnicodeSet::addAll(*((const UnicodeSet*)additionalSet));
+}
+
+U_CAPI void U_EXPORT2
+uset_add(USet* set, UChar32 c) {
+    ((UnicodeSet*) set)->UnicodeSet::add(c);
+}
+
+U_CAPI void U_EXPORT2
+uset_addRange(USet* set, UChar32 start, UChar32 end) {
+    ((UnicodeSet*) set)->UnicodeSet::add(start, end);    
+}
+
+U_CAPI void U_EXPORT2
+uset_addString(USet* set, const UChar* str, int32_t strLen) {
+    // UnicodeString handles -1 for strLen
+    UnicodeString s(strLen<0, str, strLen);
+    ((UnicodeSet*) set)->UnicodeSet::add(s);
+}
+
+U_CAPI void U_EXPORT2
+uset_addAllCodePoints(USet* set, const UChar *str, int32_t strLen) {
+    // UnicodeString handles -1 for strLen
+    UnicodeString s(str, strLen);
+    ((UnicodeSet*) set)->UnicodeSet::addAll(s);
+}
+
+U_CAPI void U_EXPORT2
+uset_remove(USet* set, UChar32 c) {
+    ((UnicodeSet*) set)->UnicodeSet::remove(c);
+}
+
+U_CAPI void U_EXPORT2
+uset_removeRange(USet* set, UChar32 start, UChar32 end) {
+    ((UnicodeSet*) set)->UnicodeSet::remove(start, end);
+}
+
+U_CAPI void U_EXPORT2
+uset_removeString(USet* set, const UChar* str, int32_t strLen) {
+    UnicodeString s(strLen==-1, str, strLen);
+    ((UnicodeSet*) set)->UnicodeSet::remove(s);
+}
+
+U_CAPI void U_EXPORT2
+uset_removeAll(USet* set, const USet* remove) {
+    ((UnicodeSet*) set)->UnicodeSet::removeAll(*(const UnicodeSet*)remove);
+}
+
+U_CAPI void U_EXPORT2
+uset_retain(USet* set, UChar32 start, UChar32 end) {
+    ((UnicodeSet*) set)->UnicodeSet::retain(start, end);
+}
+
+U_CAPI void U_EXPORT2
+uset_retainAll(USet* set, const USet* retain) {
+    ((UnicodeSet*) set)->UnicodeSet::retainAll(*(const UnicodeSet*)retain);
+}
+
+U_CAPI void U_EXPORT2
+uset_compact(USet* set) {
+    ((UnicodeSet*) set)->UnicodeSet::compact();
+}
+
+U_CAPI void U_EXPORT2
+uset_complement(USet* set) {
+    ((UnicodeSet*) set)->UnicodeSet::complement();
+}
+
+U_CAPI void U_EXPORT2
+uset_complementAll(USet* set, const USet* complement) {
+    ((UnicodeSet*) set)->UnicodeSet::complementAll(*(const UnicodeSet*)complement);
+}
+
+U_CAPI void U_EXPORT2
+uset_clear(USet* set) {
+    ((UnicodeSet*) set)->UnicodeSet::clear();
+}
+
+U_CAPI void U_EXPORT2
+uset_closeOver(USet* set, int32_t attributes) {
+    ((UnicodeSet*) set)->UnicodeSet::closeOver(attributes);
+}
+
+U_CAPI void U_EXPORT2
+uset_removeAllStrings(USet* set) {
+    ((UnicodeSet*) set)->UnicodeSet::removeAllStrings();
+}
+
+U_CAPI UBool U_EXPORT2
+uset_isEmpty(const USet* set) {
+    return ((const UnicodeSet*) set)->UnicodeSet::isEmpty();
+}
+
+U_CAPI UBool U_EXPORT2
+uset_contains(const USet* set, UChar32 c) {
+    return ((const UnicodeSet*) set)->UnicodeSet::contains(c);
+}
+
+U_CAPI UBool U_EXPORT2
+uset_containsRange(const USet* set, UChar32 start, UChar32 end) {
+    return ((const UnicodeSet*) set)->UnicodeSet::contains(start, end);
+}
+
+U_CAPI UBool U_EXPORT2
+uset_containsString(const USet* set, const UChar* str, int32_t strLen) {
+    UnicodeString s(strLen==-1, str, strLen);
+    return ((const UnicodeSet*) set)->UnicodeSet::contains(s);
+}
+
+U_CAPI UBool U_EXPORT2
+uset_containsAll(const USet* set1, const USet* set2) {
+    return ((const UnicodeSet*) set1)->UnicodeSet::containsAll(* (const UnicodeSet*) set2);
+}
+
+U_CAPI UBool U_EXPORT2
+uset_containsAllCodePoints(const USet* set, const UChar *str, int32_t strLen) {
+    // Create a string alias, since nothing is being added to the set.
+    UnicodeString s(strLen==-1, str, strLen);
+    return ((const UnicodeSet*) set)->UnicodeSet::containsAll(s);
+}
+
+U_CAPI UBool U_EXPORT2
+uset_containsNone(const USet* set1, const USet* set2) {
+    return ((const UnicodeSet*) set1)->UnicodeSet::containsNone(* (const UnicodeSet*) set2);
+}
+
+U_CAPI UBool U_EXPORT2
+uset_containsSome(const USet* set1, const USet* set2) {
+    return ((const UnicodeSet*) set1)->UnicodeSet::containsSome(* (const UnicodeSet*) set2);
+}
+
+U_CAPI int32_t U_EXPORT2
+uset_span(const USet *set, const UChar *s, int32_t length, USetSpanCondition spanCondition) {
+    return ((UnicodeSet*) set)->UnicodeSet::span(s, length, spanCondition);
+}
+
+U_CAPI int32_t U_EXPORT2
+uset_spanBack(const USet *set, const UChar *s, int32_t length, USetSpanCondition spanCondition) {
+    return ((UnicodeSet*) set)->UnicodeSet::spanBack(s, length, spanCondition);
+}
+
+U_CAPI int32_t U_EXPORT2
+uset_spanUTF8(const USet *set, const char *s, int32_t length, USetSpanCondition spanCondition) {
+    return ((UnicodeSet*) set)->UnicodeSet::spanUTF8(s, length, spanCondition);
+}
+
+U_CAPI int32_t U_EXPORT2
+uset_spanBackUTF8(const USet *set, const char *s, int32_t length, USetSpanCondition spanCondition) {
+    return ((UnicodeSet*) set)->UnicodeSet::spanBackUTF8(s, length, spanCondition);
+}
+
+U_CAPI UBool U_EXPORT2
+uset_equals(const USet* set1, const USet* set2) {
+    return *(const UnicodeSet*)set1 == *(const UnicodeSet*)set2;
+}
+
+U_CAPI int32_t U_EXPORT2
+uset_indexOf(const USet* set, UChar32 c) {
+    return ((UnicodeSet*) set)->UnicodeSet::indexOf(c);
+}
+
+U_CAPI UChar32 U_EXPORT2
+uset_charAt(const USet* set, int32_t index) {
+    return ((UnicodeSet*) set)->UnicodeSet::charAt(index);
+}
+
+U_CAPI int32_t U_EXPORT2
+uset_size(const USet* set) {
+    return ((const UnicodeSet*) set)->UnicodeSet::size();
+}
+
+U_NAMESPACE_BEGIN
+/**
+ * This class only exists to provide access to the UnicodeSet private
+ * USet support API.  Declaring a class a friend is more portable than
+ * trying to declare extern "C" functions as friends.
+ */
+class USetAccess /* not : public UObject because all methods are static */ {
+public:
+    /* Try to have the compiler inline these*/
+    inline static int32_t getStringCount(const UnicodeSet& set) {
+        return set.getStringCount();
+    }
+    inline static const UnicodeString* getString(const UnicodeSet& set,
+                                                 int32_t i) {
+        return set.getString(i);
+    }
+private:
+    /* do not instantiate*/
+    USetAccess();
+};
+U_NAMESPACE_END
+
+U_CAPI int32_t U_EXPORT2
+uset_getItemCount(const USet* uset) {
+    const UnicodeSet& set = *(const UnicodeSet*)uset;
+    return set.getRangeCount() + USetAccess::getStringCount(set);
+}
+
+U_CAPI int32_t U_EXPORT2
+uset_getItem(const USet* uset, int32_t itemIndex,
+             UChar32* start, UChar32* end,
+             UChar* str, int32_t strCapacity,
+             UErrorCode* ec) {
+    if (U_FAILURE(*ec)) return 0;
+    const UnicodeSet& set = *(const UnicodeSet*)uset;
+    int32_t rangeCount;
+
+    if (itemIndex < 0) {
+        *ec = U_ILLEGAL_ARGUMENT_ERROR;
+        return -1;
+    } else if (itemIndex < (rangeCount = set.getRangeCount())) {
+        *start = set.getRangeStart(itemIndex);
+        *end = set.getRangeEnd(itemIndex);
+        return 0;
+    } else {
+        itemIndex -= rangeCount;
+        if (itemIndex < USetAccess::getStringCount(set)) {
+            const UnicodeString* s = USetAccess::getString(set, itemIndex);
+            return s->extract(str, strCapacity, *ec);
+        } else {
+            *ec = U_INDEX_OUTOFBOUNDS_ERROR;
+            return -1;
+        }
+    }
+}
+
+//U_CAPI int32_t U_EXPORT2
+//uset_getRangeCount(const USet* set) {
+//    return ((const UnicodeSet*) set)->getRangeCount();
+//}
+//
+//U_CAPI UBool U_EXPORT2
+//uset_getRange(const USet* set, int32_t rangeIndex,
+//              UChar32* pStart, UChar32* pEnd) {
+//    if ((uint32_t) rangeIndex >= (uint32_t) uset_getRangeCount(set)) {
+//        return FALSE;
+//    }
+//    const UnicodeSet* us = (const UnicodeSet*) set;
+//    *pStart = us->getRangeStart(rangeIndex);
+//    *pEnd = us->getRangeEnd(rangeIndex);
+//    return TRUE;
+//}
+
+/*
+ * Serialize a USet into 16-bit units.
+ * Store BMP code points as themselves with one 16-bit unit each.
+ *
+ * Important: the code points in the array are in ascending order,
+ * therefore all BMP code points precede all supplementary code points.
+ *
+ * Store each supplementary code point in 2 16-bit units,
+ * simply with higher-then-lower 16-bit halfs.
+ *
+ * Precede the entire list with the length.
+ * If there are supplementary code points, then set bit 15 in the length
+ * and add the bmpLength between it and the array.
+ *
+ * In other words:
+ * - all BMP:            (length=bmpLength) BMP, .., BMP
+ * - some supplementary: (length|0x8000) (bmpLength<length) BMP, .., BMP, supp-high, supp-low, ..
+ */
+U_CAPI int32_t U_EXPORT2
+uset_serialize(const USet* set, uint16_t* dest, int32_t destCapacity, UErrorCode* ec) {
+    if (ec==NULL || U_FAILURE(*ec)) {
+        return 0;
+    }
+
+    return ((const UnicodeSet*) set)->UnicodeSet::serialize(dest, destCapacity,* ec);
+}
+
+U_CAPI UBool U_EXPORT2
+uset_getSerializedSet(USerializedSet* fillSet, const uint16_t* src, int32_t srcLength) {
+    int32_t length;
+
+    if(fillSet==NULL) {
+        return FALSE;
+    }
+    if(src==NULL || srcLength<=0) {
+        fillSet->length=fillSet->bmpLength=0;
+        return FALSE;
+    }
+
+    length=*src++;
+    if(length&0x8000) {
+        /* there are supplementary values */
+        length&=0x7fff;
+        if(srcLength<(2+length)) {
+            fillSet->length=fillSet->bmpLength=0;
+            return FALSE;
+        }
+        fillSet->bmpLength=*src++;
+    } else {
+        /* only BMP values */
+        if(srcLength<(1+length)) {
+            fillSet->length=fillSet->bmpLength=0;
+            return FALSE;
+        }
+        fillSet->bmpLength=length;
+    }
+    fillSet->array=src;
+    fillSet->length=length;
+    return TRUE;
+}
+
+U_CAPI void U_EXPORT2
+uset_setSerializedToOne(USerializedSet* fillSet, UChar32 c) {
+    if(fillSet==NULL || (uint32_t)c>0x10ffff) {
+        return;
+    }
+
+    fillSet->array=fillSet->staticArray;
+    if(c<0xffff) {
+        fillSet->bmpLength=fillSet->length=2;
+        fillSet->staticArray[0]=(uint16_t)c;
+        fillSet->staticArray[1]=(uint16_t)c+1;
+    } else if(c==0xffff) {
+        fillSet->bmpLength=1;
+        fillSet->length=3;
+        fillSet->staticArray[0]=0xffff;
+        fillSet->staticArray[1]=1;
+        fillSet->staticArray[2]=0;
+    } else if(c<0x10ffff) {
+        fillSet->bmpLength=0;
+        fillSet->length=4;
+        fillSet->staticArray[0]=(uint16_t)(c>>16);
+        fillSet->staticArray[1]=(uint16_t)c;
+        ++c;
+        fillSet->staticArray[2]=(uint16_t)(c>>16);
+        fillSet->staticArray[3]=(uint16_t)c;
+    } else /* c==0x10ffff */ {
+        fillSet->bmpLength=0;
+        fillSet->length=2;
+        fillSet->staticArray[0]=0x10;
+        fillSet->staticArray[1]=0xffff;
+    }
+}
+
+U_CAPI UBool U_EXPORT2
+uset_serializedContains(const USerializedSet* set, UChar32 c) {
+    const uint16_t* array;
+
+    if(set==NULL || (uint32_t)c>0x10ffff) {
+        return FALSE;
+    }
+
+    array=set->array;
+    if(c<=0xffff) {
+        /* find c in the BMP part */
+        int32_t lo = 0;
+        int32_t hi = set->bmpLength-1;
+        if (c < array[0]) {
+            hi = 0;
+        } else if (c < array[hi]) {
+            for(;;) {
+                int32_t i = (lo + hi) >> 1;
+                if (i == lo) {
+                    break;  // Done!
+                } else if (c < array[i]) {
+                    hi = i;
+                } else {
+                    lo = i;
+                }
+            }
+        } else {
+            hi += 1;
+        }
+        return (UBool)(hi&1);
+    } else {
+        /* find c in the supplementary part */
+        uint16_t high=(uint16_t)(c>>16), low=(uint16_t)c;
+        int32_t base = set->bmpLength;
+        int32_t lo = 0;
+        int32_t hi = set->length - 2 - base;
+        if (high < array[base] || (high==array[base] && low<array[base+1])) {
+            hi = 0;
+        } else if (high < array[base+hi] || (high==array[base+hi] && low<array[base+hi+1])) {
+            for (;;) {
+                int32_t i = ((lo + hi) >> 1) & ~1;  // Guarantee even result
+                int32_t iabs = i + base;
+                if (i == lo) {
+                    break;  // Done!
+                } else if (high < array[iabs] || (high==array[iabs] && low<array[iabs+1])) {
+                    hi = i;
+                } else {
+                    lo = i;
+                }
+            }
+        } else {
+            hi += 2;
+        }
+        /* count pairs of 16-bit units even per BMP and check if the number of pairs is odd */
+        return (UBool)(((hi+(base<<1))&2)!=0);
+    }
+}
+
+U_CAPI int32_t U_EXPORT2
+uset_getSerializedRangeCount(const USerializedSet* set) {
+    if(set==NULL) {
+        return 0;
+    }
+
+    return (set->bmpLength+(set->length-set->bmpLength)/2+1)/2;
+}
+
+U_CAPI UBool U_EXPORT2
+uset_getSerializedRange(const USerializedSet* set, int32_t rangeIndex,
+                        UChar32* pStart, UChar32* pEnd) {
+    const uint16_t* array;
+    int32_t bmpLength, length;
+
+    if(set==NULL || rangeIndex<0 || pStart==NULL || pEnd==NULL) {
+        return FALSE;
+    }
+
+    array=set->array;
+    length=set->length;
+    bmpLength=set->bmpLength;
+
+    rangeIndex*=2; /* address start/limit pairs */
+    if(rangeIndex<bmpLength) {
+        *pStart=array[rangeIndex++];
+        if(rangeIndex<bmpLength) {
+            *pEnd=array[rangeIndex]-1;
+        } else if(rangeIndex<length) {
+            *pEnd=((((int32_t)array[rangeIndex])<<16)|array[rangeIndex+1])-1;
+        } else {
+            *pEnd=0x10ffff;
+        }
+        return TRUE;
+    } else {
+        rangeIndex-=bmpLength;
+        rangeIndex*=2; /* address pairs of pairs of units */
+        length-=bmpLength;
+        if(rangeIndex<length) {
+            array+=bmpLength;
+            *pStart=(((int32_t)array[rangeIndex])<<16)|array[rangeIndex+1];
+            rangeIndex+=2;
+            if(rangeIndex<length) {
+                *pEnd=((((int32_t)array[rangeIndex])<<16)|array[rangeIndex+1])-1;
+            } else {
+                *pEnd=0x10ffff;
+            }
+            return TRUE;
+        } else {
+            return FALSE;
+        }
+    }
+}
+
+// TODO The old, internal uset.c had an efficient uset_containsOne function.
+// Returned the one and only code point, or else -1 or something.
+// Consider adding such a function to both C and C++ UnicodeSet/uset.
+// See tools/gennorm/store.c for usage, now usetContainsOne there.
+
+// TODO Investigate incorporating this code into UnicodeSet to improve
+// efficiency.
+// ---
+// #define USET_GROW_DELTA 20
+// 
+// static U_INLINE int32_t
+// findChar(const UChar32* array, int32_t length, UChar32 c) {
+//     int32_t i;
+// 
+//     /* check the last range limit first for more efficient appending */
+//     if(length>0) {
+//         if(c>=array[length-1]) {
+//             return length;
+//         }
+// 
+//         /* do not check the last range limit again in the loop below */
+//         --length;
+//     }
+// 
+//     for(i=0; i<length && c>=array[i]; ++i) {}
+//     return i;
+// }
+// 
+// static UBool
+// addRemove(USet* set, UChar32 c, int32_t doRemove) {
+//     int32_t i, length, more;
+// 
+//     if(set==NULL || (uint32_t)c>0x10ffff) {
+//         return FALSE;
+//     }
+// 
+//     length=set->length;
+//     i=findChar(set->array, length, c);
+//     if((i&1)^doRemove) {
+//         /* c is already in the set */
+//         return TRUE;
+//     }
+// 
+//     /* how many more array items do we need? */
+//     if(i<length && (c+1)==set->array[i]) {
+//         /* c is just before the following range, extend that in-place by one */
+//         set->array[i]=c;
+//         if(i>0) {
+//             --i;
+//             if(c==set->array[i]) {
+//                 /* the previous range collapsed, remove it */
+//                 set->length=length-=2;
+//                 if(i<length) {
+//                     uprv_memmove(set->array+i, set->array+i+2, (length-i)*4);
+//                 }
+//             }
+//         }
+//         return TRUE;
+//     } else if(i>0 && c==set->array[i-1]) {
+//         /* c is just after the previous range, extend that in-place by one */
+//         if(++c<=0x10ffff) {
+//             set->array[i-1]=c;
+//             if(i<length && c==set->array[i]) {
+//                 /* the following range collapsed, remove it */
+//                 --i;
+//                 set->length=length-=2;
+//                 if(i<length) {
+//                     uprv_memmove(set->array+i, set->array+i+2, (length-i)*4);
+//                 }
+//             }
+//         } else {
+//             /* extend the previous range (had limit 0x10ffff) to the end of Unicode */
+//             set->length=i-1;
+//         }
+//         return TRUE;
+//     } else if(i==length && c==0x10ffff) {
+//         /* insert one range limit c */
+//         more=1;
+//     } else {
+//         /* insert two range limits c, c+1 */
+//         more=2;
+//     }
+// 
+//     /* insert <more> range limits */
+//     if(length+more>set->capacity) {
+//         /* reallocate */
+//         int32_t newCapacity=set->capacity+set->capacity/2+USET_GROW_DELTA;
+//         UChar32* newArray=(UChar32* )uprv_malloc(newCapacity*4);
+//         if(newArray==NULL) {
+//             return FALSE;
+//         }
+//         set->capacity=newCapacity;
+//         uprv_memcpy(newArray, set->array, length*4);
+// 
+//         if(set->array!=set->staticBuffer) {
+//             uprv_free(set->array);
+//         }
+//         set->array=newArray;
+//     }
+// 
+//     if(i<length) {
+//         uprv_memmove(set->array+i+more, set->array+i, (length-i)*4);
+//     }
+//     set->array[i]=c;
+//     if(more==2) {
+//         set->array[i+1]=c+1;
+//     }
+//     set->length+=more;
+// 
+//     return TRUE;
+// }
+// 
+// U_CAPI UBool U_EXPORT2
+// uset_add(USet* set, UChar32 c) {
+//     return addRemove(set, c, 0);
+// }
+// 
+// U_CAPI void U_EXPORT2
+// uset_remove(USet* set, UChar32 c) {
+//     addRemove(set, c, 1);
+// }
diff --git a/source/common/uset_imp.h b/source/common/uset_imp.h
new file mode 100644
index 0000000..07a7381
--- /dev/null
+++ b/source/common/uset_imp.h
@@ -0,0 +1,60 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2004-2007, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  uset_imp.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2004sep07
+*   created by: Markus W. Scherer
+*
+*   Internal USet definitions.
+*/
+
+#ifndef __USET_IMP_H__
+#define __USET_IMP_H__
+
+#include "unicode/utypes.h"
+#include "unicode/uset.h"
+
+U_CDECL_BEGIN
+
+typedef void U_CALLCONV
+USetAdd(USet *set, UChar32 c);
+
+typedef void U_CALLCONV
+USetAddRange(USet *set, UChar32 start, UChar32 end);
+
+typedef void U_CALLCONV
+USetAddString(USet *set, const UChar *str, int32_t length);
+
+typedef void U_CALLCONV
+USetRemove(USet *set, UChar32 c);
+
+typedef void U_CALLCONV
+USetRemoveRange(USet *set, UChar32 start, UChar32 end);
+
+/**
+ * Interface for adding items to a USet, to keep low-level code from
+ * statically depending on the USet implementation.
+ * Calls will look like sa->add(sa->set, c);
+ */
+struct USetAdder {
+    USet *set;
+    USetAdd *add;
+    USetAddRange *addRange;
+    USetAddString *addString;
+    USetRemove *remove;
+    USetRemoveRange *removeRange;
+};
+typedef struct USetAdder USetAdder;
+
+U_CDECL_END
+
+#endif
+
diff --git a/source/common/uset_props.cpp b/source/common/uset_props.cpp
new file mode 100644
index 0000000..fb60739
--- /dev/null
+++ b/source/common/uset_props.cpp
@@ -0,0 +1,136 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2002-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  uset_props.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2004aug30
+*   created by: Markus W. Scherer
+*
+*   C wrappers around UnicodeSet functions that are implemented in
+*   uniset_props.cpp, split off for modularization.
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/uset.h"
+#include "unicode/uniset.h"
+#include "cmemory.h"
+#include "unicode/ustring.h"
+#include "unicode/parsepos.h"
+
+U_NAMESPACE_USE
+
+U_CAPI USet* U_EXPORT2
+uset_openPattern(const UChar* pattern, int32_t patternLength,
+                 UErrorCode* ec)
+{
+    UnicodeString pat(patternLength==-1, pattern, patternLength);
+    UnicodeSet* set = new UnicodeSet(pat, *ec);
+    /* test for NULL */
+    if(set == 0) {
+        *ec = U_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
+    
+    if (U_FAILURE(*ec)) {
+        delete set;
+        set = NULL;
+    }
+    return (USet*) set;
+}
+
+U_CAPI USet* U_EXPORT2
+uset_openPatternOptions(const UChar* pattern, int32_t patternLength,
+                 uint32_t options,
+                 UErrorCode* ec)
+{
+    UnicodeString pat(patternLength==-1, pattern, patternLength);
+    UnicodeSet* set = new UnicodeSet(pat, options, NULL, *ec);
+    /* test for NULL */
+    if(set == 0) {
+        *ec = U_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
+    
+    if (U_FAILURE(*ec)) {
+        delete set;
+        set = NULL;
+    }
+    return (USet*) set;
+}
+
+
+U_CAPI int32_t U_EXPORT2 
+uset_applyPattern(USet *set,
+                  const UChar *pattern, int32_t patternLength,
+                  uint32_t options,
+                  UErrorCode *status){
+
+    // status code needs to be checked since we 
+    // dereference it
+    if(status == NULL || U_FAILURE(*status)){
+        return 0;
+    }
+
+    // check only the set paramenter
+    // if pattern is NULL or null terminate
+    // UnicodeString constructor takes care of it
+    if(set == NULL){
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    UnicodeString pat(pattern, patternLength);
+
+    ParsePosition pos;
+   
+    ((UnicodeSet*) set)->applyPattern(pat, pos, options, NULL, *status);
+    
+    return pos.getIndex();
+}
+
+U_CAPI void U_EXPORT2
+uset_applyIntPropertyValue(USet* set,
+               UProperty prop, int32_t value, UErrorCode* ec) {
+    ((UnicodeSet*) set)->applyIntPropertyValue(prop, value, *ec);
+}
+
+U_CAPI void U_EXPORT2
+uset_applyPropertyAlias(USet* set,
+                        const UChar *prop, int32_t propLength,
+                        const UChar *value, int32_t valueLength,
+            UErrorCode* ec) {
+
+    UnicodeString p(prop, propLength);
+    UnicodeString v(value, valueLength);
+
+    ((UnicodeSet*) set)->applyPropertyAlias(p, v, *ec);
+}
+
+U_CAPI UBool U_EXPORT2
+uset_resemblesPattern(const UChar *pattern, int32_t patternLength,
+                      int32_t pos) {
+
+    UnicodeString pat(pattern, patternLength);
+
+    return ((pos+1) < pat.length() &&
+            pat.charAt(pos) == (UChar)91/*[*/) ||
+            UnicodeSet::resemblesPattern(pat, pos);
+}
+
+U_CAPI int32_t U_EXPORT2
+uset_toPattern(const USet* set,
+               UChar* result, int32_t resultCapacity,
+               UBool escapeUnprintable,
+               UErrorCode* ec) {
+    UnicodeString pat;
+    ((const UnicodeSet*) set)->toPattern(pat, escapeUnprintable);
+    return pat.extract(result, resultCapacity, *ec);
+}
diff --git a/source/common/usetiter.cpp b/source/common/usetiter.cpp
new file mode 100644
index 0000000..44858ed
--- /dev/null
+++ b/source/common/usetiter.cpp
@@ -0,0 +1,150 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2006, International Business Machines
+* Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+#include "unicode/usetiter.h"
+#include "unicode/uniset.h"
+#include "unicode/unistr.h"
+#include "uvector.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UnicodeSetIterator)
+
+/**
+ * Create an iterator
+ * @param set set to iterate over
+ */
+UnicodeSetIterator::UnicodeSetIterator(const UnicodeSet& uSet) {
+    cpString  = NULL;
+    reset(uSet);
+}
+
+/**
+ * Create an iterator. Convenience for when the contents are to be set later.
+ */
+UnicodeSetIterator::UnicodeSetIterator() {
+    this->set = NULL;
+    cpString  = NULL;
+    reset();
+}
+
+UnicodeSetIterator::~UnicodeSetIterator() {
+    delete cpString;
+}
+
+/**
+ * Returns the next element in the set.
+ * @return true if there was another element in the set.
+ * if so, if codepoint == IS_STRING, the value is a string in the string field
+ * else the value is a single code point in the codepoint field.
+ * <br>You are guaranteed that the codepoints are in sorted order, and the strings are in sorted order,
+ * and that all code points are returned before any strings are returned.
+ * <br>Note also that the codepointEnd is undefined after calling this method.
+ */
+UBool UnicodeSetIterator::next() {
+    if (nextElement <= endElement) {
+        codepoint = codepointEnd = nextElement++;
+        string = NULL;
+        return TRUE;
+    }
+    if (range < endRange) {
+        loadRange(++range);
+        codepoint = codepointEnd = nextElement++;
+        string = NULL;
+        return TRUE;
+    }
+
+    if (nextString >= stringCount) return FALSE;
+    codepoint = (UChar32)IS_STRING; // signal that value is actually a string
+    string = (const UnicodeString*) set->strings->elementAt(nextString++);
+    return TRUE;
+}
+
+/**
+ * @return true if there was another element in the set.
+ * if so, if codepoint == IS_STRING, the value is a string in the string field
+ * else the value is a range of codepoints in the <codepoint, codepointEnd> fields.
+ * <br>Note that the codepoints are in sorted order, and the strings are in sorted order,
+ * and that all code points are returned before any strings are returned.
+ * <br>You are guaranteed that the ranges are in sorted order, and the strings are in sorted order,
+ * and that all ranges are returned before any strings are returned.
+ * <br>You are also guaranteed that ranges are disjoint and non-contiguous.
+ * <br>Note also that the codepointEnd is undefined after calling this method.
+ */
+UBool UnicodeSetIterator::nextRange() {
+    string = NULL;
+    if (nextElement <= endElement) {
+        codepointEnd = endElement;
+        codepoint = nextElement;
+        nextElement = endElement+1;
+        return TRUE;
+    }
+    if (range < endRange) {
+        loadRange(++range);
+        codepointEnd = endElement;
+        codepoint = nextElement;
+        nextElement = endElement+1;
+        return TRUE;
+    }
+
+    if (nextString >= stringCount) return FALSE;
+    codepoint = (UChar32)IS_STRING; // signal that value is actually a string
+    string = (const UnicodeString*) set->strings->elementAt(nextString++);
+    return TRUE;
+}
+
+/**
+ *@param set the set to iterate over. This allows reuse of the iterator.
+ */
+void UnicodeSetIterator::reset(const UnicodeSet& uSet) {
+    this->set = &uSet;
+    reset();
+}
+
+/**
+ * Resets to the start, to allow the iteration to start over again.
+ */
+void UnicodeSetIterator::reset() {
+    if (set == NULL) {
+        // Set up indices to empty iteration
+        endRange = -1;
+        stringCount = 0;
+    } else {
+        endRange = set->getRangeCount() - 1;
+        stringCount = set->strings->size();
+    }
+    range = 0;
+    endElement = -1;
+    nextElement = 0;            
+    if (endRange >= 0) {
+        loadRange(range);
+    }
+    nextString = 0;
+    string = NULL;
+}
+
+void UnicodeSetIterator::loadRange(int32_t iRange) {
+    nextElement = set->getRangeStart(iRange);
+    endElement = set->getRangeEnd(iRange);
+}
+
+
+const UnicodeString& UnicodeSetIterator::getString()  {
+    if (string==NULL && codepoint!=(UChar32)IS_STRING) {
+       if (cpString == NULL) {
+          cpString = new UnicodeString();
+       }
+       if (cpString != NULL) {
+          cpString->setTo((UChar32)codepoint);
+       }
+       string = cpString;
+    }
+    return *string;
+}
+
+U_NAMESPACE_END
+
+//eof
diff --git a/source/common/ushape.c b/source/common/ushape.c
new file mode 100644
index 0000000..05940bc
--- /dev/null
+++ b/source/common/ushape.c
@@ -0,0 +1,1712 @@
+/*
+ ******************************************************************************
+ *
+ *   Copyright (C) 2000-2010, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ *
+ ******************************************************************************
+ *   file name:  ushape.c
+ *   encoding:   US-ASCII
+ *   tab size:   8 (not used)
+ *   indentation:4
+ *
+ *   created on: 2000jun29
+ *   created by: Markus W. Scherer
+ *
+ *   Arabic letter shaping implemented by Ayman Roshdy
+ */
+
+#include "unicode/utypes.h"
+#include "unicode/uchar.h"
+#include "unicode/ustring.h"
+#include "unicode/ushape.h"
+#include "cmemory.h"
+#include "putilimp.h"
+#include "ustr_imp.h"
+#include "ubidi_props.h"
+
+#if UTF_SIZE<16
+    /*
+     * This implementation assumes that the internal encoding is UTF-16
+     * or UTF-32, not UTF-8.
+     * The main assumption is that the Arabic characters and their
+     * presentation forms each fit into a single UChar.
+     * With UTF-8, they occupy 2 or 3 bytes, and more than the ASCII
+     * characters.
+     */
+#   error This implementation assumes UTF-16 or UTF-32 (check UTF_SIZE)
+#endif
+
+/*
+ * ### TODO in general for letter shaping:
+ * - the letter shaping code is UTF-16-unaware; needs update
+ *   + especially invertBuffer()?!
+ * - needs to handle the "Arabic Tail" that is used in some legacy codepages
+ *   as a glyph fragment of wide-glyph letters
+ *   + IBM Unicode conversion tables map it to U+200B (ZWSP)
+ *   + IBM Egypt has proposed to encode the tail in Unicode among Arabic Presentation Forms
+ */
+
+/* definitions for Arabic letter shaping ------------------------------------ */
+
+#define IRRELEVANT 4
+#define LAMTYPE    16
+#define ALEFTYPE   32
+#define LINKR      1
+#define LINKL      2
+#define APRESENT   8
+#define SHADDA     64
+#define CSHADDA    128
+#define COMBINE    (SHADDA+CSHADDA)
+
+#define HAMZAFE_CHAR       0xfe80
+#define HAMZA06_CHAR       0x0621
+#define YEH_HAMZA_CHAR     0x0626
+#define YEH_HAMZAFE_CHAR   0xFE89
+#define LAMALEF_SPACE_SUB  0xFFFF
+#define TASHKEEL_SPACE_SUB 0xFFFE
+#define NEW_TAIL_CHAR      0xFE73
+#define OLD_TAIL_CHAR      0x200B
+#define LAM_CHAR           0x0644
+#define SPACE_CHAR         0x0020
+#define SHADDA_CHAR        0xFE7C
+#define TATWEEL_CHAR       0x0640
+#define SHADDA_TATWEEL_CHAR  0xFE7D
+
+#define SHAPE_MODE   0
+#define DESHAPE_MODE 1
+
+static UChar tailChar = OLD_TAIL_CHAR;
+static uint32_t uShapeLamalefBegin = U_SHAPE_LAMALEF_BEGIN;
+static uint32_t uShapeLamalefEnd    = U_SHAPE_LAMALEF_END;        
+static uint32_t uShapeTashkeelBegin = U_SHAPE_TASHKEEL_BEGIN;
+static uint32_t uShapeTashkeelEnd = U_SHAPE_TASHKEEL_END;
+static int spacesRelativeToTextBeginEnd = 0;
+
+static const uint8_t tailFamilyIsolatedFinal[] = {
+    /* FEB1 */ 1,
+    /* FEB2 */ 1,
+    /* FEB3 */ 0,
+    /* FEB4 */ 0,
+    /* FEB5 */ 1,
+    /* FEB6 */ 1,
+    /* FEB7 */ 0,
+    /* FEB8 */ 0,
+    /* FEB9 */ 1,
+    /* FEBA */ 1,
+    /* FEBB */ 0,
+    /* FEBC */ 0,
+    /* FEBD */ 1,
+    /* FEBE */ 1
+};
+
+static const uint8_t tashkeelMedial[] = {
+    /* FE70 */ 0,
+    /* FE71 */ 1,
+    /* FE72 */ 0,
+    /* FE73 */ 0,
+    /* FE74 */ 0,
+    /* FE75 */ 0,
+    /* FE76 */ 0,
+    /* FE77 */ 1,
+    /* FE78 */ 0,
+    /* FE79 */ 1,
+    /* FE7A */ 0,
+    /* FE7B */ 1,
+    /* FE7C */ 0,
+    /* FE7D */ 1,
+    /* FE7E */ 0,
+    /* FE7F */ 1
+};
+
+static const UChar yehHamzaToYeh[] =
+{
+/* isolated*/ 0xFEEF,
+/* final   */ 0xFEF0
+};
+
+static const uint8_t IrrelevantPos[] = {
+    0x0, 0x2, 0x4, 0x6,
+    0x8, 0xA, 0xC, 0xE
+};
+
+
+static const UChar convertLamAlef[] =
+{
+/*FEF5*/    0x0622,
+/*FEF6*/    0x0622,
+/*FEF7*/    0x0623,
+/*FEF8*/    0x0623,
+/*FEF9*/    0x0625,
+/*FEFA*/    0x0625,
+/*FEFB*/    0x0627,
+/*FEFC*/    0x0627
+};
+
+static const UChar araLink[178]=
+{
+  1           + 32 + 256 * 0x11,/*0x0622*/
+  1           + 32 + 256 * 0x13,/*0x0623*/
+  1                + 256 * 0x15,/*0x0624*/
+  1           + 32 + 256 * 0x17,/*0x0625*/
+  1 + 2            + 256 * 0x19,/*0x0626*/
+  1           + 32 + 256 * 0x1D,/*0x0627*/
+  1 + 2            + 256 * 0x1F,/*0x0628*/
+  1                + 256 * 0x23,/*0x0629*/
+  1 + 2            + 256 * 0x25,/*0x062A*/
+  1 + 2            + 256 * 0x29,/*0x062B*/
+  1 + 2            + 256 * 0x2D,/*0x062C*/
+  1 + 2            + 256 * 0x31,/*0x062D*/
+  1 + 2            + 256 * 0x35,/*0x062E*/
+  1                + 256 * 0x39,/*0x062F*/
+  1                + 256 * 0x3B,/*0x0630*/
+  1                + 256 * 0x3D,/*0x0631*/
+  1                + 256 * 0x3F,/*0x0632*/
+  1 + 2            + 256 * 0x41,/*0x0633*/
+  1 + 2            + 256 * 0x45,/*0x0634*/
+  1 + 2            + 256 * 0x49,/*0x0635*/
+  1 + 2            + 256 * 0x4D,/*0x0636*/
+  1 + 2            + 256 * 0x51,/*0x0637*/
+  1 + 2            + 256 * 0x55,/*0x0638*/
+  1 + 2            + 256 * 0x59,/*0x0639*/
+  1 + 2            + 256 * 0x5D,/*0x063A*/
+  0, 0, 0, 0, 0,                /*0x063B-0x063F*/
+  1 + 2,                        /*0x0640*/
+  1 + 2            + 256 * 0x61,/*0x0641*/
+  1 + 2            + 256 * 0x65,/*0x0642*/
+  1 + 2            + 256 * 0x69,/*0x0643*/
+  1 + 2       + 16 + 256 * 0x6D,/*0x0644*/
+  1 + 2            + 256 * 0x71,/*0x0645*/
+  1 + 2            + 256 * 0x75,/*0x0646*/
+  1 + 2            + 256 * 0x79,/*0x0647*/
+  1                + 256 * 0x7D,/*0x0648*/
+  1                + 256 * 0x7F,/*0x0649*/
+  1 + 2            + 256 * 0x81,/*0x064A*/
+         4         + 256 * 1,   /*0x064B*/
+         4 + 128   + 256 * 1,   /*0x064C*/
+         4 + 128   + 256 * 1,   /*0x064D*/
+         4 + 128   + 256 * 1,   /*0x064E*/
+         4 + 128   + 256 * 1,   /*0x064F*/
+         4 + 128   + 256 * 1,   /*0x0650*/
+         4 + 64    + 256 * 3,   /*0x0651*/
+         4         + 256 * 1,   /*0x0652*/
+         4         + 256 * 7,   /*0x0653*/
+         4         + 256 * 8,   /*0x0654*/
+         4         + 256 * 8,   /*0x0655*/ 
+         4         + 256 * 1,   /*0x0656*/
+  0, 0, 0, 0, 0,                /*0x0657-0x065B*/
+  1                + 256 * 0x85,/*0x065C*/
+  1                + 256 * 0x87,/*0x065D*/
+  1                + 256 * 0x89,/*0x065E*/
+  1                + 256 * 0x8B,/*0x065F*/
+  0, 0, 0, 0, 0,                /*0x0660-0x0664*/
+  0, 0, 0, 0, 0,                /*0x0665-0x0669*/
+  0, 0, 0, 0, 0, 0,             /*0x066A-0x066F*/
+         4         + 256 * 6,   /*0x0670*/
+  1        + 8     + 256 * 0x00,/*0x0671*/
+  1            + 32,            /*0x0672*/
+  1            + 32,            /*0x0673*/
+  0,                            /*0x0674*/
+  1            + 32,            /*0x0675*/
+  1, 1,                         /*0x0676-0x0677*/
+  1+2, 1+2, 1+2, 1+2, 1+2, 1+2, /*0x0678-0x067D*/
+  1+2+8+256 * 0x06, 1+2, 1+2, 1+2, 1+2, 1+2, /*0x067E-0x0683*/
+  1+2, 1+2, 1+2+8+256 * 0x2A, 1+2,           /*0x0684-0x0687*/
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*0x0688-0x0691*/
+  1, 1, 1, 1, 1, 1, 1+8+256 * 0x3A, 1,       /*0x0692-0x0699*/
+  1+2, 1+2, 1+2, 1+2, 1+2, 1+2, /*0x069A-0x06A3*/
+  1+2, 1+2, 1+2, 1+2,           /*0x069A-0x06A3*/
+  1+2, 1+2, 1+2, 1+2, 1+2, 1+2+8+256 * 0x3E, /*0x06A4-0x06AD*/
+  1+2, 1+2, 1+2, 1+2,           /*0x06A4-0x06AD*/
+  1+2, 1+2+8+256 * 0x42, 1+2, 1+2, 1+2, 1+2, /*0x06AE-0x06B7*/
+  1+2, 1+2, 1+2, 1+2,           /*0x06AE-0x06B7*/
+  1+2, 1+2, 1+2, 1+2, 1+2, 1+2, /*0x06B8-0x06BF*/
+  1+2, 1+2,                     /*0x06B8-0x06BF*/
+  1,                            /*0x06C0*/
+  1+2,                          /*0x06C1*/
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*0x06C2-0x06CB*/
+  1+2+8+256 * 0xAC,             /*0x06CC*/
+  1,                            /*0x06CD*/
+  1+2, 1+2, 1+2, 1+2,           /*0x06CE-0x06D1*/
+  1, 1                          /*0x06D2-0x06D3*/
+};
+
+static const uint8_t presALink[] = {
+/***********0*****1*****2*****3*****4*****5*****6*****7*****8*****9*****A*****B*****C*****D*****E*****F*/
+/*FB5*/    0,    1,    0,    0,    0,    0,    0,    1,    2,1 + 2,    0,    0,    0,    0,    0,    0,
+/*FB6*/    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+/*FB7*/    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,    2,1 + 2,    0,    0,
+/*FB8*/    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,    0,    0,    0,    1,
+/*FB9*/    2,1 + 2,    0,    1,    2,1 + 2,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+/*FBA*/    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+/*FBB*/    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+/*FBC*/    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+/*FBD*/    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+/*FBE*/    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+/*FBF*/    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,    2,1 + 2,
+/*FC0*/    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+/*FC1*/    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+/*FC2*/    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+/*FC3*/    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+/*FC4*/    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+/*FC5*/    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    4,    4,
+/*FC6*/    4,    4,    4
+};
+
+static const uint8_t presBLink[]=
+{
+/***********0*****1*****2*****3*****4*****5*****6*****7*****8*****9*****A*****B*****C*****D*****E*****F*/
+/*FE7*/1 + 2,1 + 2,1 + 2,    0,1 + 2,    0,1 + 2,1 + 2,1 + 2,1 + 2,1 + 2,1 + 2,1 + 2,1 + 2,1 + 2,1 + 2, 
+/*FE8*/    0,    0,    1,    0,    1,    0,    1,    0,    1,    0,    1,    2,1 + 2,    0,    1,    0,
+/*FE9*/    1,    2,1 + 2,    0,    1,    0,    1,    2,1 + 2,    0,    1,    2,1 + 2,    0,    1,    2,
+/*FEA*/1 + 2,    0,    1,    2,1 + 2,    0,    1,    2,1 + 2,    0,    1,    0,    1,    0,    1,    0,  
+/*FEB*/    1,    0,    1,    2,1 + 2,    0,    1,    2,1 + 2,    0,    1,    2,1 + 2,    0,    1,    2,
+/*FEC*/1 + 2,    0,    1,    2,1 + 2,    0,    1,    2,1 + 2,    0,    1,    2,1 + 2,    0,    1,    2,
+/*FED*/1 + 2,    0,    1,    2,1 + 2,    0,    1,    2,1 + 2,    0,    1,    2,1 + 2,    0,    1,    2,
+/*FEE*/1 + 2,    0,    1,    2,1 + 2,    0,    1,    2,1 + 2,    0,    1,    2,1 + 2,    0,    1,    0,
+/*FEF*/    1,    0,    1,    2,1 + 2,    0,    1,    0,    1,    0,    1,    0,    1,    0,    0,    0
+};
+
+static const UChar convertFBto06[] =
+{
+/***********0******1******2******3******4******5******6******7******8******9******A******B******C******D******E******F***/
+/*FB5*/   0x671, 0x671,     0,     0,     0,     0, 0x07E, 0x07E, 0x07E, 0x07E,     0,     0,     0,     0,     0,     0,
+/*FB6*/       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+/*FB7*/       0,     0,     0,     0,     0,     0,     0,     0,     0,     0, 0x686, 0x686, 0x686, 0x686,     0,     0,
+/*FB8*/       0,     0,     0,     0,     0,     0,     0,     0,     0,     0, 0x698, 0x698,     0,     0, 0x6A9, 0x6A9,
+/*FB9*/   0x6A9, 0x6A9, 0x6AF, 0x6AF, 0x6AF, 0x6AF,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+/*FBA*/       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+/*FBB*/       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+/*FBC*/       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+/*FBD*/       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+/*FBE*/       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+/*FBF*/       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0, 0x6CC, 0x6CC, 0x6CC, 0x6CC
+};
+
+static const UChar convertFEto06[] =
+{
+/***********0******1******2******3******4******5******6******7******8******9******A******B******C******D******E******F***/
+/*FE7*/   0x64B, 0x64B, 0x64C, 0x64C, 0x64D, 0x64D, 0x64E, 0x64E, 0x64F, 0x64F, 0x650, 0x650, 0x651, 0x651, 0x652, 0x652,
+/*FE8*/   0x621, 0x622, 0x622, 0x623, 0x623, 0x624, 0x624, 0x625, 0x625, 0x626, 0x626, 0x626, 0x626, 0x627, 0x627, 0x628,
+/*FE9*/   0x628, 0x628, 0x628, 0x629, 0x629, 0x62A, 0x62A, 0x62A, 0x62A, 0x62B, 0x62B, 0x62B, 0x62B, 0x62C, 0x62C, 0x62C,
+/*FEA*/   0x62C, 0x62D, 0x62D, 0x62D, 0x62D, 0x62E, 0x62E, 0x62E, 0x62E, 0x62F, 0x62F, 0x630, 0x630, 0x631, 0x631, 0x632,
+/*FEB*/   0x632, 0x633, 0x633, 0x633, 0x633, 0x634, 0x634, 0x634, 0x634, 0x635, 0x635, 0x635, 0x635, 0x636, 0x636, 0x636,
+/*FEC*/   0x636, 0x637, 0x637, 0x637, 0x637, 0x638, 0x638, 0x638, 0x638, 0x639, 0x639, 0x639, 0x639, 0x63A, 0x63A, 0x63A,
+/*FED*/   0x63A, 0x641, 0x641, 0x641, 0x641, 0x642, 0x642, 0x642, 0x642, 0x643, 0x643, 0x643, 0x643, 0x644, 0x644, 0x644,
+/*FEE*/   0x644, 0x645, 0x645, 0x645, 0x645, 0x646, 0x646, 0x646, 0x646, 0x647, 0x647, 0x647, 0x647, 0x648, 0x648, 0x649,
+/*FEF*/   0x649, 0x64A, 0x64A, 0x64A, 0x64A, 0x65C, 0x65C, 0x65D, 0x65D, 0x65E, 0x65E, 0x65F, 0x65F
+};
+
+static const uint8_t shapeTable[4][4][4]=
+{
+  { {0,0,0,0}, {0,0,0,0}, {0,1,0,3}, {0,1,0,1} },
+  { {0,0,2,2}, {0,0,1,2}, {0,1,1,2}, {0,1,1,3} },
+  { {0,0,0,0}, {0,0,0,0}, {0,1,0,3}, {0,1,0,3} },
+  { {0,0,1,2}, {0,0,1,2}, {0,1,1,2}, {0,1,1,3} }
+};
+
+/*
+ * This function shapes European digits to Arabic-Indic digits
+ * in-place, writing over the input characters.
+ * Since we know that we are only looking for BMP code points,
+ * we can safely just work with code units (again, at least UTF-16).
+ */
+static void
+_shapeToArabicDigitsWithContext(UChar *s, int32_t length,
+                                UChar digitBase,
+                                UBool isLogical, UBool lastStrongWasAL) {
+    const UBiDiProps *bdp;
+    int32_t i;
+    UChar c;
+
+    bdp=ubidi_getSingleton();
+    digitBase-=0x30;
+
+    /* the iteration direction depends on the type of input */
+    if(isLogical) {
+        for(i=0; i<length; ++i) {
+            c=s[i];
+            switch(ubidi_getClass(bdp, c)) {
+            case U_LEFT_TO_RIGHT: /* L */
+            case U_RIGHT_TO_LEFT: /* R */
+                lastStrongWasAL=FALSE;
+                break;
+            case U_RIGHT_TO_LEFT_ARABIC: /* AL */
+                lastStrongWasAL=TRUE;
+                break;
+            case U_EUROPEAN_NUMBER: /* EN */
+                if(lastStrongWasAL && (uint32_t)(c-0x30)<10) {
+                    s[i]=(UChar)(digitBase+c); /* digitBase+(c-0x30) - digitBase was modified above */
+                }
+                break;
+            default :
+                break;
+            }
+        }
+    } else {
+        for(i=length; i>0; /* pre-decrement in the body */) {
+            c=s[--i];
+            switch(ubidi_getClass(bdp, c)) {
+            case U_LEFT_TO_RIGHT: /* L */
+            case U_RIGHT_TO_LEFT: /* R */
+                lastStrongWasAL=FALSE;
+                break;
+            case U_RIGHT_TO_LEFT_ARABIC: /* AL */
+                lastStrongWasAL=TRUE;
+                break;
+            case U_EUROPEAN_NUMBER: /* EN */
+                if(lastStrongWasAL && (uint32_t)(c-0x30)<10) {
+                    s[i]=(UChar)(digitBase+c); /* digitBase+(c-0x30) - digitBase was modified above */
+                }
+                break;
+            default :
+                break;
+            }
+        }
+    }
+}
+
+/*
+ *Name     : invertBuffer
+ *Function : This function inverts the buffer, it's used
+ *           in case the user specifies the buffer to be
+ *           U_SHAPE_TEXT_DIRECTION_LOGICAL
+ */
+static void 
+invertBuffer(UChar *buffer,int32_t size,uint32_t options,int32_t lowlimit,int32_t highlimit) {
+    UChar temp;
+    int32_t i=0,j=0;
+    for(i=lowlimit,j=size-highlimit-1;i<j;i++,j--) {
+        temp = buffer[i];
+        buffer[i] = buffer[j];
+        buffer[j] = temp;
+    }
+}
+
+/*
+ *Name     : changeLamAlef
+ *Function : Converts the Alef characters into an equivalent
+ *           LamAlef location in the 0x06xx Range, this is an
+ *           intermediate stage in the operation of the program
+ *           later it'll be converted into the 0xFExx LamAlefs
+ *           in the shaping function.
+ */
+static U_INLINE UChar
+changeLamAlef(UChar ch) {
+    switch(ch) {
+    case 0x0622 :
+        return 0x065C;
+    case 0x0623 :
+        return 0x065D;
+    case 0x0625 :
+        return 0x065E;
+    case 0x0627 :
+        return 0x065F;
+    }
+    return 0;
+}
+
+/*
+ *Name     : getLink
+ *Function : Resolves the link between the characters as
+ *           Arabic characters have four forms :
+ *           Isolated, Initial, Middle and Final Form
+ */
+static UChar
+getLink(UChar ch) {
+    if(ch >= 0x0622 && ch <= 0x06D3) {
+        return(araLink[ch-0x0622]);
+    } else if(ch == 0x200D) {
+        return(3);
+    } else if(ch >= 0x206D && ch <= 0x206F) {
+        return(4);
+    }else if(ch >= 0xFB50 && ch <= 0xFC62) {
+        return(presALink[ch-0xFB50]);
+    } else if(ch >= 0xFE70 && ch <= 0xFEFC) {
+        return(presBLink[ch-0xFE70]);
+    }else {
+        return(0);
+    }
+}
+
+/*
+ *Name     : countSpaces
+ *Function : Counts the number of spaces
+ *           at each end of the logical buffer
+ */
+static void
+countSpaces(UChar *dest,int32_t size,uint32_t options,int32_t *spacesCountl,int32_t *spacesCountr) {
+    int32_t i = 0;
+    int32_t countl = 0,countr = 0;
+    while(dest[i] == SPACE_CHAR) {
+       countl++;
+       i++;
+    }
+    while(dest[size-1] == SPACE_CHAR) {
+       countr++;
+       size--;
+    }
+    *spacesCountl = countl;
+    *spacesCountr = countr;
+}
+
+/*
+ *Name     : isTashkeelChar
+ *Function : Returns 1 for Tashkeel characters in 06 range else return 0
+ */
+static U_INLINE int32_t
+isTashkeelChar(UChar ch) {
+    return (int32_t)( ch>=0x064B && ch<= 0x0652 );
+}
+
+/*
+ *Name     : isTashkeelCharFE
+ *Function : Returns 1 for Tashkeel characters in FE range else return 0
+ */
+static U_INLINE int32_t
+isTashkeelCharFE(UChar ch) {
+    return (int32_t)( ch>=0xFE70 && ch<= 0xFE7F );
+}
+
+/*
+ *Name     : isAlefChar
+ *Function : Returns 1 for Alef characters else return 0
+ */
+static U_INLINE int32_t
+isAlefChar(UChar ch) {
+    return (int32_t)( (ch==0x0622)||(ch==0x0623)||(ch==0x0625)||(ch==0x0627) );
+}
+
+/*
+ *Name     : isLamAlefChar
+ *Function : Returns 1 for LamAlef characters else return 0
+ */
+static U_INLINE int32_t
+isLamAlefChar(UChar ch) {
+    return (int32_t)((ch>=0xFEF5)&&(ch<=0xFEFC) );
+}
+
+/*BIDI
+ *Name     : isTailChar
+ *Function : returns 1 if the character matches one of the tail characters (0xfe73 or 0x200b) otherwise returns 0 
+ */
+
+static U_INLINE int32_t
+isTailChar(UChar ch) {
+    if(ch == OLD_TAIL_CHAR || ch == NEW_TAIL_CHAR){
+            return 1;
+    }else{
+            return 0;
+    }
+}
+
+/*BIDI
+ *Name     : isSeenTailFamilyChar
+ *Function : returns 1 if the character is a seen family isolated character 
+ *           in the FE range otherwise returns 0
+ */
+
+static U_INLINE int32_t
+isSeenTailFamilyChar(UChar ch) {
+    if(ch >= 0xfeb1 && ch < 0xfebf){
+            return tailFamilyIsolatedFinal [ch - 0xFEB1];
+    }else{
+            return 0;
+    }
+}
+
+ /* Name     : isSeenFamilyChar
+  * Function : returns 1 if the character is a seen family character in the Unicode
+  *            06 range otherwise returns 0
+ */
+
+static U_INLINE int32_t
+isSeenFamilyChar(UChar  ch){
+    if(ch >= 0x633 && ch <= 0x636){
+        return 1;
+    }else {
+        return 0;
+    }
+}
+
+/*Start of BIDI*/
+/*
+ *Name     : isAlefMaksouraChar
+ *Function : returns 1 if the character is a Alef Maksoura Final or isolated 
+ *           otherwise returns 0 
+ */
+static U_INLINE int32_t
+isAlefMaksouraChar(UChar ch) {
+    return (int32_t)( (ch == 0xFEEF) || ( ch == 0xFEF0) || (ch == 0x0649));
+} 
+
+/*
+ * Name     : isYehHamzaChar
+ * Function : returns 1 if the character is a yehHamza isolated or yehhamza
+ *            final is found otherwise returns 0 
+ */
+static U_INLINE int32_t
+isYehHamzaChar(UChar ch) {
+    if((ch==0xFE89)||(ch==0xFE8A)){
+        return 1;
+    }else{
+        return 0;
+    }
+} 
+
+ /* 
+ * Name: isTashkeelOnTatweelChar
+ * Function: Checks if the Tashkeel Character is on Tatweel or not,if the 
+ *           Tashkeel on tatweel (FE range), it returns 1 else if the 
+ *           Tashkeel with shadda on tatweel (FC range)return 2 otherwise 
+ *           returns 0
+ */
+static U_INLINE int32_t
+isTashkeelOnTatweelChar(UChar ch){
+    if(ch >= 0xfe70 && ch <= 0xfe7f && ch != NEW_TAIL_CHAR && ch != 0xFE75 && ch != SHADDA_TATWEEL_CHAR)
+    {
+        return tashkeelMedial [ch - 0xFE70];
+    }else if( (ch >= 0xfcf2 && ch <= 0xfcf4) || (ch == SHADDA_TATWEEL_CHAR)) {
+        return 2;
+    }else{
+        return 0;
+    }
+}
+
+/*
+ * Name: isIsolatedTashkeelChar
+ * Function: Checks if the Tashkeel Character is in the isolated form 
+ *           (i.e. Unicode FE range) returns 1 else if the Tashkeel 
+ *           with shadda is in the isolated form (i.e. Unicode FC range)
+ *           returns 2 otherwise returns 0
+ */
+static U_INLINE int32_t
+isIsolatedTashkeelChar(UChar ch){
+    if(ch >= 0xfe70 && ch <= 0xfe7f && ch != NEW_TAIL_CHAR && ch != 0xFE75){
+        return (1 - tashkeelMedial [ch - 0xFE70]);
+    }else if(ch >= 0xfc5e && ch <= 0xfc63){
+        return 1;
+    }else{
+        return 0;
+    }
+}
+
+
+
+
+/*
+ *Name     : calculateSize
+ *Function : This function calculates the destSize to be used in preflighting 
+ *           when the destSize is equal to 0
+ *           It is used also to calculate the new destsize in case the 
+ *           destination buffer will be resized.
+ */
+
+static int32_t
+calculateSize(const UChar *source, int32_t sourceLength,
+int32_t destSize,uint32_t options) {
+    int32_t i = 0;
+    
+    int lamAlefOption = 0;
+    int tashkeelOption = 0;
+
+    destSize = sourceLength;
+    
+    if (((options&U_SHAPE_LETTERS_MASK) == U_SHAPE_LETTERS_SHAPE ||
+        ((options&U_SHAPE_LETTERS_MASK) == U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED )) &&
+        ((options&U_SHAPE_LAMALEF_MASK) == U_SHAPE_LAMALEF_RESIZE )){
+            lamAlefOption = 1;
+    }
+    if((options&U_SHAPE_LETTERS_MASK) == U_SHAPE_LETTERS_SHAPE &&
+       ((options&U_SHAPE_TASHKEEL_MASK) == U_SHAPE_TASHKEEL_RESIZE ) ){
+            tashkeelOption = 1;
+        }
+    
+    if(lamAlefOption || tashkeelOption){
+        if((options&U_SHAPE_TEXT_DIRECTION_MASK)==U_SHAPE_TEXT_DIRECTION_VISUAL_LTR) {
+            for(i=0;i<sourceLength;i++) {
+                if( ((isAlefChar(source[i]))&& (i<(sourceLength-1)) &&(source[i+1] == LAM_CHAR)) || (isTashkeelCharFE(source[i])) ) {
+                        destSize--;
+                    }
+                }
+            }else if((options&U_SHAPE_TEXT_DIRECTION_MASK)==U_SHAPE_TEXT_DIRECTION_LOGICAL) {
+                for(i=0;i<sourceLength;i++) {
+                    if( ( (source[i] == LAM_CHAR) && (i<(sourceLength-1)) && (isAlefChar(source[i+1]))) || (isTashkeelCharFE(source[i])) ) {
+                        destSize--;
+                    }
+                }
+            }
+        }
+    
+    if ((options&U_SHAPE_LETTERS_MASK) == U_SHAPE_LETTERS_UNSHAPE){
+        if ( (options&U_SHAPE_LAMALEF_MASK) == U_SHAPE_LAMALEF_RESIZE){
+            for(i=0;i<sourceLength;i++) {
+                if(isLamAlefChar(source[i]))
+                destSize++;
+            }
+        }
+    }
+
+    return destSize;
+}
+
+/*
+ *Name     : handleTashkeelWithTatweel
+ *Function : Replaces Tashkeel as following: 
+ *            Case 1 :if the Tashkeel on tatweel, replace it with Tatweel.   
+ *            Case 2 :if the Tashkeel aggregated with Shadda on Tatweel, replace 
+ *                   it with Shadda on Tatweel.
+ *            Case 3: if the Tashkeel is isolated replace it with Space.
+ *
+ */
+static int32_t
+handleTashkeelWithTatweel(UChar *dest, int32_t sourceLength,
+             int32_t destSize,uint32_t options,
+             UErrorCode *pErrorCode) {
+                 int i;
+                 for(i = 0; i < sourceLength; i++){
+                     if((isTashkeelOnTatweelChar(dest[i]) == 1)){
+                         dest[i] = TATWEEL_CHAR;
+                    }else if((isTashkeelOnTatweelChar(dest[i]) == 2)){
+                         dest[i] = SHADDA_TATWEEL_CHAR;
+                    }else if(isIsolatedTashkeelChar(dest[i]) && dest[i] != SHADDA_CHAR){
+                         dest[i] = SPACE_CHAR;
+                    }
+                 }
+                 return sourceLength;
+}
+
+
+
+/*
+ *Name     : handleGeneratedSpaces
+ *Function : The shapeUnicode function converts Lam + Alef into LamAlef + space,
+ *           and Tashkeel to space. 
+ *           handleGeneratedSpaces function puts these generated spaces 
+ *           according to the options the user specifies. LamAlef and Tashkeel
+ *           spaces can be replaced at begin, at end, at near or decrease the 
+ *           buffer size.
+ *
+ *           There is also Auto option for LamAlef and tashkeel, which will put
+ *           the spaces at end of the buffer (or end of text if the user used 
+ *           the option U_SHAPE_SPACES_RELATIVE_TO_TEXT_BEGIN_END).
+ *
+ *           If the text type was visual_LTR and the option 
+ *           U_SHAPE_SPACES_RELATIVE_TO_TEXT_BEGIN_END was selected the END 
+ *           option will place the space at the beginning of the buffer and
+ *           BEGIN will place the space at the end of the buffer. 
+ */
+
+static int32_t
+handleGeneratedSpaces(UChar *dest, int32_t sourceLength,
+                    int32_t destSize,
+                    uint32_t options,
+                    UErrorCode *pErrorCode ) {
+
+    int32_t i = 0, j = 0;
+    int32_t count = 0;
+    UChar *tempbuffer=NULL;
+
+    int lamAlefOption = 0;
+    int tashkeelOption = 0;
+    int shapingMode = SHAPE_MODE;
+
+    if (shapingMode == 0){
+        if ( (options&U_SHAPE_LAMALEF_MASK) == U_SHAPE_LAMALEF_RESIZE ){
+            lamAlefOption = 1;
+        }
+        if ( (options&U_SHAPE_TASHKEEL_MASK) == U_SHAPE_TASHKEEL_RESIZE ){
+            tashkeelOption = 1;
+        }
+    }
+
+    if (lamAlefOption || tashkeelOption){
+        tempbuffer = (UChar *)uprv_malloc((sourceLength+1)*U_SIZEOF_UCHAR);
+        /* Test for NULL */
+        if(tempbuffer == NULL) {
+            *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+
+        uprv_memset(tempbuffer, 0, (sourceLength+1)*U_SIZEOF_UCHAR);
+
+        i = j = 0; count = 0;
+        while(i < sourceLength) {
+            if ( (lamAlefOption && dest[i] == LAMALEF_SPACE_SUB) ||
+               (tashkeelOption && dest[i] == TASHKEEL_SPACE_SUB) ){ 
+                j--;
+                count++;
+            } else {
+                tempbuffer[j] = dest[i];
+            }
+            i++;
+            j++;
+        }
+
+        while(count >= 0) {
+            tempbuffer[i] = 0x0000;
+            i--;
+            count--;
+        }
+
+        uprv_memcpy(dest, tempbuffer, sourceLength*U_SIZEOF_UCHAR);
+        destSize = u_strlen(dest);
+    }
+
+      lamAlefOption = 0;
+
+    if (shapingMode == 0){
+        if ( (options&U_SHAPE_LAMALEF_MASK) == U_SHAPE_LAMALEF_NEAR ){
+            lamAlefOption = 1;
+        }
+    }
+    
+    if (lamAlefOption){
+        /* Lam+Alef is already shaped into LamAlef + FFFF */
+        i = 0;
+        while(i < sourceLength) {
+            if(lamAlefOption&&dest[i] == LAMALEF_SPACE_SUB){
+                dest[i] = SPACE_CHAR;
+            }
+            i++;
+        }
+        destSize = sourceLength;
+    }
+    lamAlefOption = 0;
+    tashkeelOption = 0;
+
+    if (shapingMode == 0) {
+        if ( ((options&U_SHAPE_LAMALEF_MASK) == uShapeLamalefBegin) || 
+              (((options&U_SHAPE_LAMALEF_MASK) == U_SHAPE_LAMALEF_AUTO )
+              && (spacesRelativeToTextBeginEnd==1)) ) {
+            lamAlefOption = 1;
+        }
+        if ( (options&U_SHAPE_TASHKEEL_MASK) == uShapeTashkeelBegin ) {
+            tashkeelOption = 1;
+        }
+    }
+
+    if(lamAlefOption || tashkeelOption){
+        tempbuffer = (UChar *)uprv_malloc((sourceLength+1)*U_SIZEOF_UCHAR);
+        
+        /* Test for NULL */
+        if(tempbuffer == NULL) {
+            *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+
+        uprv_memset(tempbuffer, 0, (sourceLength+1)*U_SIZEOF_UCHAR);
+        i = j = sourceLength; count = 0;
+        while(i >= 0) {
+            if ( (lamAlefOption && dest[i] == LAMALEF_SPACE_SUB) ||
+                 (tashkeelOption && dest[i] == TASHKEEL_SPACE_SUB) ){
+                j++;
+                count++;
+            }else {
+                tempbuffer[j] = dest[i];
+            }
+            i--;
+            j--;
+        }
+        
+        for(i=0 ;i < count; i++){
+                tempbuffer[i] = SPACE_CHAR;
+        }
+        
+        uprv_memcpy(dest, tempbuffer, sourceLength*U_SIZEOF_UCHAR);
+        destSize = sourceLength;
+    }
+
+
+
+    lamAlefOption = 0;
+    tashkeelOption = 0;
+
+    if (shapingMode == 0) {
+        if ( ((options&U_SHAPE_LAMALEF_MASK) == uShapeLamalefEnd) || 
+              (((options&U_SHAPE_LAMALEF_MASK) == U_SHAPE_LAMALEF_AUTO )
+              && (spacesRelativeToTextBeginEnd==0)) ) {
+            lamAlefOption = 1;
+        }
+        if ( (options&U_SHAPE_TASHKEEL_MASK) == uShapeTashkeelEnd ){
+            tashkeelOption = 1;
+        }
+    }
+            
+    if(lamAlefOption || tashkeelOption){
+        tempbuffer = (UChar *)uprv_malloc((sourceLength+1)*U_SIZEOF_UCHAR);
+       /* Test for NULL */
+        if(tempbuffer == NULL) {
+            *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+
+        uprv_memset(tempbuffer, 0, (sourceLength+1)*U_SIZEOF_UCHAR);
+
+        i = j = 0; count = 0;
+        while(i < sourceLength) {
+            if ( (lamAlefOption && dest[i] == LAMALEF_SPACE_SUB) ||
+                 (tashkeelOption && dest[i] == TASHKEEL_SPACE_SUB) ){
+                j--;
+                count++;
+            }else {
+                tempbuffer[j] = dest[i];
+            }
+            i++;
+            j++;
+        }
+
+        while(count >= 0) {
+            tempbuffer[i] = SPACE_CHAR;
+            i--;
+            count--;
+        }
+
+        uprv_memcpy(dest,tempbuffer, sourceLength*U_SIZEOF_UCHAR);
+        destSize = sourceLength;
+    }
+
+    
+    if(tempbuffer){
+        uprv_free(tempbuffer);
+    }
+
+    return destSize;
+}
+
+/*
+ *Name     :expandCompositCharAtBegin
+ *Function :Expands the LamAlef character to Lam and Alef consuming the required
+ *         space from beginning of the buffer. If the text type was visual_LTR 
+ *         and the option U_SHAPE_SPACES_RELATIVE_TO_TEXT_BEGIN_END was selected
+ *         the spaces will be located at end of buffer.
+ *         If there are no spaces to expand the LamAlef, an error
+ *         will be set to U_NO_SPACE_AVAILABLE as defined in utypes.h 
+ */
+
+static int32_t
+expandCompositCharAtBegin(UChar *dest, int32_t sourceLength, int32_t destSize,UErrorCode *pErrorCode) {
+    int32_t      i = 0,j = 0;
+    int32_t      countl = 0;
+    UChar    *tempbuffer=NULL;
+    
+    tempbuffer = (UChar *)uprv_malloc((sourceLength+1)*U_SIZEOF_UCHAR);
+
+    /* Test for NULL */
+    if(tempbuffer == NULL) {
+        *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
+
+        uprv_memset(tempbuffer, 0, (sourceLength+1)*U_SIZEOF_UCHAR);
+
+        i = 0;
+        while(dest[i] == SPACE_CHAR) {
+            countl++;
+            i++;
+        }
+
+        i = j = sourceLength-1;
+        
+        while(i >= 0 && j >= 0) {
+            if( countl>0 && isLamAlefChar(dest[i])) {
+                tempbuffer[j] = LAM_CHAR;
+                tempbuffer[j-1] = convertLamAlef[ dest[i] - 0xFEF5 ];
+                j--;
+                countl--;
+            }else {
+                 if( countl == 0 && isLamAlefChar(dest[i]) ) {
+                     *pErrorCode=U_NO_SPACE_AVAILABLE;
+                     }
+                 tempbuffer[j] = dest[i];
+            }
+            i--;
+            j--;
+        }
+        uprv_memcpy(dest, tempbuffer, sourceLength*U_SIZEOF_UCHAR);
+        
+        uprv_free(tempbuffer);
+        
+        destSize = sourceLength;
+        return destSize;
+}
+
+/*
+ *Name     : expandCompositCharAtEnd
+ *Function : Expands the LamAlef character to Lam and Alef consuming the 
+ *           required space from end of the buffer. If the text type was
+ *           Visual LTR and the option U_SHAPE_SPACES_RELATIVE_TO_TEXT_BEGIN_END
+ *           was used, the spaces will be consumed from begin of buffer. If 
+ *           there are no spaces to expand the LamAlef, an error
+ *           will be set to U_NO_SPACE_AVAILABLE as defined in utypes.h 
+ */
+
+static int32_t
+expandCompositCharAtEnd(UChar *dest, int32_t sourceLength, int32_t destSize,UErrorCode *pErrorCode) {
+    int32_t      i = 0,j = 0;
+
+    int32_t      countr = 0;
+    int32_t  inpsize = sourceLength;
+
+    UChar    *tempbuffer=NULL;
+    tempbuffer = (UChar *)uprv_malloc((sourceLength+1)*U_SIZEOF_UCHAR);
+
+    /* Test for NULL */
+    if(tempbuffer == NULL) {
+        *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+         return 0;
+    }
+    
+    uprv_memset(tempbuffer, 0, (sourceLength+1)*U_SIZEOF_UCHAR);
+    
+    while(dest[inpsize-1] == SPACE_CHAR) {
+        countr++;
+        inpsize--;
+    }
+    
+    i = sourceLength - countr - 1;
+    j = sourceLength - 1;
+    
+    while(i >= 0 && j >= 0) {
+        if( countr>0 && isLamAlefChar(dest[i]) ) {
+            tempbuffer[j] = LAM_CHAR;
+            tempbuffer[j-1] = convertLamAlef[ dest[i] - 0xFEF5 ];
+            j--;
+            countr--;
+        }else {
+            if ((countr == 0) && isLamAlefChar(dest[i]) ) {
+                *pErrorCode=U_NO_SPACE_AVAILABLE;
+            }
+            tempbuffer[j] = dest[i];
+        }
+        i--;
+        j--;
+    }
+    
+    if(countr > 0) {
+        uprv_memmove(tempbuffer, tempbuffer+countr, sourceLength*U_SIZEOF_UCHAR);
+        if(u_strlen(tempbuffer) < sourceLength) {
+            for(i=sourceLength-1;i>=sourceLength-countr;i--) {
+                tempbuffer[i] = SPACE_CHAR;
+            }
+        }
+    }
+    uprv_memcpy(dest, tempbuffer, sourceLength*U_SIZEOF_UCHAR);
+
+    uprv_free(tempbuffer);
+    
+    destSize = sourceLength;
+    return destSize;
+}
+
+/*
+ *Name     : expandCompositCharAtNear
+ *Function : Expands the LamAlef character into Lam + Alef, YehHamza character
+ *           into Yeh + Hamza, SeenFamily character into SeenFamily character 
+ *           + Tail, while consuming the space next to the character. 
+ *           If there are no spaces next to the character, an error
+ *           will be set to U_NO_SPACE_AVAILABLE as defined in utypes.h 
+ */
+
+static int32_t
+expandCompositCharAtNear(UChar *dest, int32_t sourceLength, int32_t destSize,UErrorCode *pErrorCode,
+                         int yehHamzaOption, int seenTailOption, int lamAlefOption) {
+    int32_t      i = 0;
+
+
+    UChar    lamalefChar, yehhamzaChar;
+
+    for(i = 0 ;i<=sourceLength-1;i++) {
+            if (seenTailOption && isSeenTailFamilyChar(dest[i])) {
+                if ((i>0) && (dest[i-1] == SPACE_CHAR) ) {
+                    dest[i-1] = tailChar;
+                }else {
+                    *pErrorCode=U_NO_SPACE_AVAILABLE;
+                }
+            }else if(yehHamzaOption && (isYehHamzaChar(dest[i])) ) {
+                if ((i>0) && (dest[i-1] == SPACE_CHAR) ) {
+                    yehhamzaChar = dest[i];
+                    dest[i] = yehHamzaToYeh[yehhamzaChar - YEH_HAMZAFE_CHAR];
+                    dest[i-1] = HAMZAFE_CHAR;
+                }else {
+                    
+                    *pErrorCode=U_NO_SPACE_AVAILABLE;
+                }
+            }else if(lamAlefOption && isLamAlefChar(dest[i+1])) {
+                if(dest[i] == SPACE_CHAR){
+                    lamalefChar = dest[i+1];
+                    dest[i+1] = LAM_CHAR;
+                    dest[i] = convertLamAlef[ lamalefChar - 0xFEF5 ];
+                }else {
+                    *pErrorCode=U_NO_SPACE_AVAILABLE;
+                }
+            }
+       }
+       destSize = sourceLength;
+       return destSize;
+}
+ /* 
+ * Name     : expandCompositChar
+ * Function : LamAlef, need special handling, since it expands from one 
+ *            character into two characters while shaping or deshaping. 
+ *            In order to expand it, near or far spaces according to the
+ *            options user specifies. Also buffer size can be increased.
+ *
+ *            For SeenFamily characters and YehHamza only the near option is
+ *            supported, while for LamAlef we can take spaces from begin, end,
+ *            near or even increase the buffer size.
+ *            There is also the Auto option for LamAlef only, which will first 
+ *            search for a space at end, begin then near, respectively.
+ *            If there are no spaces to expand these characters, an error will be set to 
+ *            U_NO_SPACE_AVAILABLE as defined in utypes.h 
+ */
+ 
+static int32_t
+expandCompositChar(UChar *dest, int32_t sourceLength,
+              int32_t destSize,uint32_t options,
+              UErrorCode *pErrorCode, int shapingMode) {
+
+    int32_t      i = 0,j = 0;
+
+    UChar    *tempbuffer=NULL;
+    int yehHamzaOption = 0;
+    int seenTailOption = 0;
+    int lamAlefOption = 0;
+    
+    if (shapingMode == 1){
+        if ( (options&U_SHAPE_LAMALEF_MASK) == U_SHAPE_LAMALEF_AUTO){
+            
+            if(spacesRelativeToTextBeginEnd == 0) {
+                destSize = expandCompositCharAtEnd(dest, sourceLength, destSize, pErrorCode);
+                
+                if(*pErrorCode == U_NO_SPACE_AVAILABLE) {
+                    *pErrorCode = U_ZERO_ERROR;
+                    destSize = expandCompositCharAtBegin(dest, sourceLength, destSize, pErrorCode);
+                }
+            }else {
+                destSize = expandCompositCharAtBegin(dest, sourceLength, destSize, pErrorCode);
+                
+                if(*pErrorCode == U_NO_SPACE_AVAILABLE) {
+                    *pErrorCode = U_ZERO_ERROR;
+                    destSize = expandCompositCharAtEnd(dest, sourceLength, destSize, pErrorCode);
+                }
+            }
+            
+            if(*pErrorCode == U_NO_SPACE_AVAILABLE) {
+                *pErrorCode = U_ZERO_ERROR;
+                destSize = expandCompositCharAtNear(dest, sourceLength, destSize, pErrorCode, yehHamzaOption, 
+                                                seenTailOption, 1);
+            }
+        }
+    }
+
+    if (shapingMode == 1){
+        if ( (options&U_SHAPE_LAMALEF_MASK) == uShapeLamalefEnd){
+            destSize = expandCompositCharAtEnd(dest, sourceLength, destSize, pErrorCode);
+        }
+    }
+
+    if (shapingMode == 1){
+        if ( (options&U_SHAPE_LAMALEF_MASK) == uShapeLamalefBegin){
+            destSize = expandCompositCharAtBegin(dest, sourceLength, destSize, pErrorCode);
+        }
+    }
+    
+    if (shapingMode == 0){
+         if ((options&U_SHAPE_YEHHAMZA_MASK) == U_SHAPE_YEHHAMZA_TWOCELL_NEAR){
+             yehHamzaOption = 1;
+         }
+         if ((options&U_SHAPE_SEEN_MASK) == U_SHAPE_SEEN_TWOCELL_NEAR){
+            seenTailOption = 1;
+         }
+    }
+    if (shapingMode == 1) {
+        if ( (options&U_SHAPE_LAMALEF_MASK) == U_SHAPE_LAMALEF_NEAR) {
+            lamAlefOption = 1;
+        }
+    }
+
+
+    if (yehHamzaOption || seenTailOption || lamAlefOption){
+        destSize = expandCompositCharAtNear(dest, sourceLength, destSize, pErrorCode, yehHamzaOption, 
+                                            seenTailOption,lamAlefOption); 
+    }
+ 
+    
+    if (shapingMode == 1){
+        if ( (options&U_SHAPE_LAMALEF_MASK) == U_SHAPE_LAMALEF_RESIZE){
+            destSize = calculateSize(dest,sourceLength,destSize,options);
+            tempbuffer = (UChar *)uprv_malloc((destSize+1)*U_SIZEOF_UCHAR);
+            
+            /* Test for NULL */
+            if(tempbuffer == NULL) {
+                *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+                return 0;
+            }
+            
+            uprv_memset(tempbuffer, 0, (destSize+1)*U_SIZEOF_UCHAR);
+            
+            i = j = 0;
+            while(i < destSize && j < destSize) {
+                if(isLamAlefChar(dest[i]) ) {
+                    tempbuffer[j] = convertLamAlef[ dest[i] - 0xFEF5 ];
+                    tempbuffer[j+1] = LAM_CHAR;
+                    j++;
+                }else {
+                    tempbuffer[j] = dest[i];
+                }
+                i++;
+                j++;
+            }
+            
+            uprv_memcpy(dest, tempbuffer, destSize*U_SIZEOF_UCHAR);
+        }
+    }
+    
+    if(tempbuffer) {
+        uprv_free(tempbuffer);
+    }
+    return destSize;
+}
+
+/*
+ *Name     : shapeUnicode
+ *Function : Converts an Arabic Unicode buffer in 06xx Range into a shaped
+ *           arabic Unicode buffer in FExx Range
+ */
+static int32_t
+shapeUnicode(UChar *dest, int32_t sourceLength,
+             int32_t destSize,uint32_t options,
+             UErrorCode *pErrorCode,
+             int tashkeelFlag) {
+
+    int32_t          i, iend;
+    int32_t          step;
+    int32_t          lastPos,Nx, Nw;
+    unsigned int     Shape;
+    int32_t          lamalef_found = 0;
+    int32_t seenfamFound = 0, yehhamzaFound =0, tashkeelFound  = 0;
+    UChar            prevLink = 0, lastLink = 0, currLink, nextLink = 0;
+    UChar            wLamalef;
+
+    /*
+     * Converts the input buffer from FExx Range into 06xx Range
+     * to make sure that all characters are in the 06xx range
+     * even the lamalef is converted to the special region in
+     * the 06xx range
+     */
+    if ((options & U_SHAPE_PRESERVE_PRESENTATION_MASK)  == U_SHAPE_PRESERVE_PRESENTATION_NOOP) {
+        for (i = 0; i < sourceLength; i++) {
+            UChar inputChar  = dest[i];
+            if ( (inputChar >= 0xFB50) && (inputChar <= 0xFBFF)) {
+                UChar c = convertFBto06 [ (inputChar - 0xFB50) ];
+                if (c != 0)
+                    dest[i] = c;
+            } else if ( (inputChar >= 0xFE70) && (inputChar <= 0xFEFC)) {
+                dest[i] = convertFEto06 [ (inputChar - 0xFE70) ] ;
+            } else {
+                dest[i] = inputChar ;
+            }
+        }
+    }
+
+
+    /* sets the index to the end of the buffer, together with the step point to -1 */
+    i = sourceLength - 1;
+    iend = -1;
+    step = -1;
+
+    /*
+     * This function resolves the link between the characters .
+     * Arabic characters have four forms :
+     * Isolated Form, Initial Form, Middle Form and Final Form
+     */
+    currLink = getLink(dest[i]);
+
+    lastPos = i;
+    Nx = -2, Nw = 0;
+
+    while (i != iend) {
+        /* If high byte of currLink > 0 then more than one shape */
+        if ((currLink & 0xFF00) > 0 || (getLink(dest[i]) & IRRELEVANT) != 0) {
+            Nw = i + step;
+            while (Nx < 0) {         /* we need to know about next char */
+                if(Nw == iend) {
+                    nextLink = 0;
+                    Nx = 3000;
+                } else {
+                    nextLink = getLink(dest[Nw]);
+                    if((nextLink & IRRELEVANT) == 0) {
+                        Nx = Nw;
+                    } else {
+                        Nw = Nw + step;
+                    }
+                }
+            }
+
+            if ( ((currLink & ALEFTYPE) > 0)  &&  ((lastLink & LAMTYPE) > 0) ) {
+                lamalef_found = 1;
+                wLamalef = changeLamAlef(dest[i]); /*get from 0x065C-0x065f */
+                if ( wLamalef != 0) {
+                    dest[i] = LAMALEF_SPACE_SUB;            /* The default case is to drop the Alef and replace */
+                    dest[lastPos] =wLamalef;     /* it by LAMALEF_SPACE_SUB which is the last character in the  */
+                    i=lastPos;                   /* unicode private use area, this is done to make   */
+                }                                /* sure that removeLamAlefSpaces() handles only the */
+                lastLink = prevLink;             /* spaces generated during lamalef generation.      */
+                currLink = getLink(wLamalef);    /* LAMALEF_SPACE_SUB is added here and is replaced by spaces   */
+            }                                    /* in removeLamAlefSpaces()                         */
+            
+			if ((i > 0) && (dest[i-1] == SPACE_CHAR)){
+             if ( isSeenFamilyChar(dest[i])){
+                    seenfamFound = 1;
+                } else if (dest[i] == YEH_HAMZA_CHAR) {
+                    yehhamzaFound = 1;
+                }
+			}
+			else if(i==0){
+				if ( isSeenFamilyChar(dest[i])){
+                    seenfamFound = 1;
+                } else if (dest[i] == YEH_HAMZA_CHAR) {
+                    yehhamzaFound = 1;
+                }
+			}
+
+            /*  
+             * get the proper shape according to link ability of neighbors
+             * and of character; depends on the order of the shapes
+             * (isolated, initial, middle, final) in the compatibility area
+             */
+            Shape = shapeTable[nextLink & (LINKR + LINKL)]
+                              [lastLink & (LINKR + LINKL)]
+                              [currLink & (LINKR + LINKL)]; 
+
+            if ((currLink & (LINKR+LINKL)) == 1) {
+                Shape &= 1;
+            } else if(isTashkeelChar(dest[i])) {
+                if( (lastLink & LINKL) && (nextLink & LINKR) && (tashkeelFlag == 1) &&
+                     dest[i] != 0x064C && dest[i] != 0x064D )
+                {
+                    Shape = 1; 
+                    if( (nextLink&ALEFTYPE) == ALEFTYPE && (lastLink&LAMTYPE) == LAMTYPE ) {
+                        Shape = 0; 
+                    }
+                }
+                else {
+                    Shape = 0;
+                }
+            }
+            if ((dest[i] ^ 0x0600) < 0x100) {
+                if ( isTashkeelChar(dest[i]) ){
+                    if (tashkeelFlag == 2){
+                        dest[i] = TASHKEEL_SPACE_SUB;
+                        tashkeelFound  = 1;
+                    }else {
+                    dest[i] =  0xFE70 + IrrelevantPos[(dest[i] - 0x064B)] + Shape;
+                    }
+                }else if ((currLink & APRESENT) > 0) {
+                    dest[i] = (UChar)(0xFB50 + (currLink >> 8) + Shape);
+                }else if ((currLink >> 8) > 0 && (currLink & IRRELEVANT) == 0) {
+                    dest[i] = (UChar)(0xFE70 + (currLink >> 8) + Shape);
+                }
+            }
+        }
+
+        /* move one notch forward */
+        if ((currLink & IRRELEVANT) == 0) {
+            prevLink = lastLink;
+            lastLink = currLink;
+            lastPos = i;
+        }
+
+        i = i + step;
+        if (i == Nx) {
+            currLink = nextLink;
+            Nx = -2;
+        } else if(i != iend) {
+            currLink = getLink(dest[i]);
+        }
+    }
+    destSize = sourceLength;
+    if ( (lamalef_found != 0 ) || (tashkeelFound  != 0) ){
+        destSize = handleGeneratedSpaces(dest,sourceLength,destSize,options,pErrorCode);
+    }
+
+    if ( (seenfamFound != 0) || (yehhamzaFound != 0) ) {
+        destSize = expandCompositChar(dest, sourceLength,destSize,options,pErrorCode, SHAPE_MODE);
+    }
+    return destSize;
+}
+
+/*
+ *Name     : deShapeUnicode
+ *Function : Converts an Arabic Unicode buffer in FExx Range into unshaped
+ *           arabic Unicode buffer in 06xx Range
+ */
+static int32_t
+deShapeUnicode(UChar *dest, int32_t sourceLength,
+               int32_t destSize,uint32_t options,
+               UErrorCode *pErrorCode) {
+    int32_t i = 0;
+    int32_t lamalef_found = 0;
+    int32_t yehHamzaComposeEnabled = 0;
+    int32_t seenComposeEnabled = 0;
+
+    yehHamzaComposeEnabled = ((options&U_SHAPE_YEHHAMZA_MASK) == U_SHAPE_YEHHAMZA_TWOCELL_NEAR) ? 1 : 0;
+    seenComposeEnabled = ((options&U_SHAPE_SEEN_MASK) == U_SHAPE_SEEN_TWOCELL_NEAR)? 1 : 0;
+
+    /*
+     *This for loop changes the buffer from the Unicode FE range to
+     *the Unicode 06 range
+     */
+    
+    for(i = 0; i < sourceLength; i++) {
+        UChar  inputChar = dest[i];
+        if ( (inputChar >= 0xFB50) && (inputChar <= 0xFBFF)) { /* FBxx Arabic range */
+            UChar c = convertFBto06 [ (inputChar - 0xFB50) ];
+            if (c != 0)
+                dest[i] = c;
+        } else if( (yehHamzaComposeEnabled == 1) && ((inputChar == HAMZA06_CHAR) || (inputChar == HAMZAFE_CHAR)) 
+                && (i < (sourceLength - 1)) && isAlefMaksouraChar(dest[i+1] )) {
+                 dest[i] = SPACE_CHAR;
+                 dest[i+1] = YEH_HAMZA_CHAR;
+        } else if ( (seenComposeEnabled == 1) && (isTailChar(inputChar)) && (i< (sourceLength - 1)) 
+                        && (isSeenTailFamilyChar(dest[i+1])) ) {
+                dest[i] = SPACE_CHAR;
+        } else if (( inputChar >= 0xFE70) && (inputChar <= 0xFEF4 )) { /* FExx Arabic range */
+                dest[i] = convertFEto06 [ (inputChar - 0xFE70) ];
+        } else {
+            dest[i] = inputChar ;
+        }
+
+        if( isLamAlefChar(dest[i]) )
+            lamalef_found = 1;
+    }
+  
+   destSize = sourceLength;
+   if (lamalef_found != 0){
+          destSize = expandCompositChar(dest,sourceLength,destSize,options,pErrorCode,DESHAPE_MODE);
+   }
+   return destSize;
+}
+
+/* 
+ ****************************************
+ * u_shapeArabic
+ ****************************************
+ */    
+
+U_CAPI int32_t U_EXPORT2
+u_shapeArabic(const UChar *source, int32_t sourceLength,
+              UChar *dest, int32_t destCapacity,
+              uint32_t options,
+              UErrorCode *pErrorCode) {
+
+    int32_t destLength;
+    
+    spacesRelativeToTextBeginEnd = 0;
+    uShapeLamalefBegin = U_SHAPE_LAMALEF_BEGIN;
+    uShapeLamalefEnd = U_SHAPE_LAMALEF_END;
+    uShapeTashkeelBegin = U_SHAPE_TASHKEEL_BEGIN;
+    uShapeTashkeelEnd = U_SHAPE_TASHKEEL_END;
+
+    /* usual error checking */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    /* make sure that no reserved options values are used; allow dest==NULL only for preflighting */
+    if( source==NULL || sourceLength<-1 || (dest==NULL && destCapacity!=0) || destCapacity<0 ||
+                (((options&U_SHAPE_TASHKEEL_MASK) > 0) &&
+                 ((options&U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED) == U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED) ) ||
+                (((options&U_SHAPE_TASHKEEL_MASK) > 0) &&
+                 ((options&U_SHAPE_LETTERS_MASK) == U_SHAPE_LETTERS_UNSHAPE)) ||
+                (options&U_SHAPE_DIGIT_TYPE_RESERVED)==U_SHAPE_DIGIT_TYPE_RESERVED ||
+                (options&U_SHAPE_DIGITS_MASK)==U_SHAPE_DIGITS_RESERVED ||
+                ((options&U_SHAPE_LAMALEF_MASK) != U_SHAPE_LAMALEF_RESIZE  &&
+                (options&U_SHAPE_AGGREGATE_TASHKEEL_MASK) != 0) ||
+                ((options&U_SHAPE_AGGREGATE_TASHKEEL_MASK) == U_SHAPE_AGGREGATE_TASHKEEL &&
+                (options&U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED) != U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED)
+    ) 
+    {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+	/* Validate  lamalef options */
+	if(((options&U_SHAPE_LAMALEF_MASK) > 0)&&
+              !(((options & U_SHAPE_LAMALEF_MASK)==U_SHAPE_LAMALEF_BEGIN) ||
+                ((options & U_SHAPE_LAMALEF_MASK)==U_SHAPE_LAMALEF_END ) ||
+                ((options & U_SHAPE_LAMALEF_MASK)==U_SHAPE_LAMALEF_RESIZE )||
+                 ((options & U_SHAPE_LAMALEF_MASK)==U_SHAPE_LAMALEF_AUTO) ||
+                 ((options & U_SHAPE_LAMALEF_MASK)==U_SHAPE_LAMALEF_NEAR)))
+	{
+		 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+	}
+	/* Validate  Tashkeel options */
+	if(((options&U_SHAPE_TASHKEEL_MASK) > 0)&&
+                   !(((options & U_SHAPE_TASHKEEL_MASK)==U_SHAPE_TASHKEEL_BEGIN) ||
+                     ((options & U_SHAPE_TASHKEEL_MASK)==U_SHAPE_TASHKEEL_END )
+                    ||((options & U_SHAPE_TASHKEEL_MASK)==U_SHAPE_TASHKEEL_RESIZE )||
+					((options & U_SHAPE_TASHKEEL_MASK)==U_SHAPE_TASHKEEL_REPLACE_BY_TATWEEL)))
+	{
+		 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+	}
+    /* determine the source length */
+    if(sourceLength==-1) {
+        sourceLength=u_strlen(source);
+    }
+    if(sourceLength<=0) {
+        return u_terminateUChars(dest, destCapacity, 0, pErrorCode);
+    }
+
+    /* check that source and destination do not overlap */
+    if( dest!=NULL &&
+        ((source<=dest && dest<source+sourceLength) ||
+         (dest<=source && source<dest+destCapacity))) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    
+    /* Does Options contain the new Seen Tail Unicode code point option */
+    if ( (options&SHAPE_TAIL_TYPE_MASK) == SHAPE_TAIL_NEW_UNICODE){
+        tailChar = NEW_TAIL_CHAR;
+    }else {
+        tailChar = OLD_TAIL_CHAR;
+    }
+
+    if((options&U_SHAPE_LETTERS_MASK)!=U_SHAPE_LETTERS_NOOP) {
+        UChar buffer[300];
+        UChar *tempbuffer, *tempsource = NULL;
+        int32_t outputSize, spacesCountl=0, spacesCountr=0;
+
+        if((options&U_SHAPE_AGGREGATE_TASHKEEL_MASK)>0) {
+            int32_t logical_order = (options&U_SHAPE_TEXT_DIRECTION_MASK) == U_SHAPE_TEXT_DIRECTION_LOGICAL;
+            int32_t aggregate_tashkeel = 
+                        (options&(U_SHAPE_AGGREGATE_TASHKEEL_MASK+U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED)) == 
+                        (U_SHAPE_AGGREGATE_TASHKEEL+U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED);
+            int step=logical_order?1:-1;
+            int j=logical_order?-1:2*sourceLength;
+            int i=logical_order?-1:sourceLength;
+            int end=logical_order?sourceLength:-1;
+            int aggregation_possible = 1;
+            UChar prev = 0;
+            UChar prevLink, currLink = 0;
+            int newSourceLength = 0;
+            tempsource = (UChar *)uprv_malloc(2*sourceLength*U_SIZEOF_UCHAR);
+            if(tempsource == NULL) {
+                *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+                return 0;
+            }
+
+            while ((i+=step) != end) {
+                prevLink = currLink;
+                currLink = getLink(source[i]);
+                if (aggregate_tashkeel && ((prevLink|currLink)&COMBINE) == COMBINE && aggregation_possible) {
+                    aggregation_possible = 0; 
+                    tempsource[j] = (prev<source[i]?prev:source[i])-0x064C+0xFC5E;
+                    currLink = getLink(tempsource[j]);
+                } else {
+                    aggregation_possible = 1;
+                    tempsource[j+=step] = source[i];
+                    prev = source[i];
+                    newSourceLength++;
+                }
+            }
+            source = tempsource+(logical_order?0:j);
+            sourceLength = newSourceLength;
+        }
+
+        /* calculate destination size */
+        /* TODO: do we ever need to do this pure preflighting? */
+        if(((options&U_SHAPE_LAMALEF_MASK)==U_SHAPE_LAMALEF_RESIZE) || 
+           ((options&U_SHAPE_TASHKEEL_MASK)==U_SHAPE_TASHKEEL_RESIZE)) {
+            outputSize=calculateSize(source,sourceLength,destCapacity,options);
+        } else {
+            outputSize=sourceLength;
+        }
+
+        if(outputSize>destCapacity) {
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+                if (tempsource != NULL) uprv_free(tempsource);
+            return outputSize;
+        }
+
+        /*
+         * need a temporary buffer of size max(outputSize, sourceLength)
+         * because at first we copy source->temp
+         */
+        if(sourceLength>outputSize) {
+            outputSize=sourceLength;
+        }
+
+        /* Start of Arabic letter shaping part */
+        if(outputSize<=sizeof(buffer)/U_SIZEOF_UCHAR) {
+            outputSize=sizeof(buffer)/U_SIZEOF_UCHAR;
+            tempbuffer=buffer;
+        } else {
+            tempbuffer = (UChar *)uprv_malloc(outputSize*U_SIZEOF_UCHAR);
+
+            /*Test for NULL*/
+            if(tempbuffer == NULL) {
+                *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+                if (tempsource != NULL) uprv_free(tempsource);
+                return 0;
+            }
+        }
+        uprv_memcpy(tempbuffer, source, sourceLength*U_SIZEOF_UCHAR);
+        if (tempsource != NULL){
+            uprv_free(tempsource);
+        }
+
+        if(sourceLength<outputSize) {
+            uprv_memset(tempbuffer+sourceLength, 0, (outputSize-sourceLength)*U_SIZEOF_UCHAR);
+        }
+
+        if((options&U_SHAPE_TEXT_DIRECTION_MASK) == U_SHAPE_TEXT_DIRECTION_LOGICAL) {
+            countSpaces(tempbuffer,sourceLength,options,&spacesCountl,&spacesCountr);
+            invertBuffer(tempbuffer,sourceLength,options,spacesCountl,spacesCountr);
+        }
+
+        if((options&U_SHAPE_TEXT_DIRECTION_MASK) == U_SHAPE_TEXT_DIRECTION_VISUAL_LTR) {
+            if((options&U_SHAPE_SPACES_RELATIVE_TO_TEXT_MASK) == U_SHAPE_SPACES_RELATIVE_TO_TEXT_BEGIN_END) {
+                spacesRelativeToTextBeginEnd = 1;
+                uShapeLamalefBegin = U_SHAPE_LAMALEF_END;
+                uShapeLamalefEnd = U_SHAPE_LAMALEF_BEGIN;
+
+                uShapeTashkeelBegin = U_SHAPE_TASHKEEL_END;
+                uShapeTashkeelEnd = U_SHAPE_TASHKEEL_BEGIN;
+            }
+        }
+
+        switch(options&U_SHAPE_LETTERS_MASK) {
+        case U_SHAPE_LETTERS_SHAPE :
+             if( (options&U_SHAPE_TASHKEEL_MASK)> 0 
+                 && ((options&U_SHAPE_TASHKEEL_MASK) !=U_SHAPE_TASHKEEL_REPLACE_BY_TATWEEL)) {
+                /* Call the shaping function with tashkeel flag == 2 for removal of tashkeel */
+                destLength = shapeUnicode(tempbuffer,sourceLength,destCapacity,options,pErrorCode,2);
+             }else {
+                /* default Call the shaping function with tashkeel flag == 1 */
+                destLength = shapeUnicode(tempbuffer,sourceLength,destCapacity,options,pErrorCode,1);
+
+                /*After shaping text check if user wants to remove tashkeel and replace it with tatweel*/
+                if( (options&U_SHAPE_TASHKEEL_MASK) == U_SHAPE_TASHKEEL_REPLACE_BY_TATWEEL){
+                  destLength = handleTashkeelWithTatweel(tempbuffer,destLength,destCapacity,options,pErrorCode);
+                }
+            }
+            break;
+        case U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED :
+            /* Call the shaping function with tashkeel flag == 0 */
+            destLength = shapeUnicode(tempbuffer,sourceLength,destCapacity,options,pErrorCode,0);
+            break;
+
+        case U_SHAPE_LETTERS_UNSHAPE :
+            /* Call the deshaping function */
+            destLength = deShapeUnicode(tempbuffer,sourceLength,destCapacity,options,pErrorCode);
+            break;
+        default :
+            /* will never occur because of validity checks above */
+            destLength = 0;
+            break;
+        }
+
+        /*
+         * TODO: (markus 2002aug01)
+         * For as long as we always preflight the outputSize above
+         * we should U_ASSERT(outputSize==destLength)
+         * except for the adjustment above before the tempbuffer allocation
+         */
+
+        if((options&U_SHAPE_TEXT_DIRECTION_MASK) == U_SHAPE_TEXT_DIRECTION_LOGICAL) {
+            countSpaces(tempbuffer,destLength,options,&spacesCountl,&spacesCountr);
+            invertBuffer(tempbuffer,destLength,options,spacesCountl,spacesCountr);
+        }
+        uprv_memcpy(dest, tempbuffer, uprv_min(destLength, destCapacity)*U_SIZEOF_UCHAR);
+
+        if(tempbuffer!=buffer) {
+            uprv_free(tempbuffer);
+        }
+
+        if(destLength>destCapacity) {
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            return destLength;
+        }
+
+        /* End of Arabic letter shaping part */
+    } else {
+        /*
+         * No letter shaping:
+         * just make sure the destination is large enough and copy the string.
+         */
+        if(destCapacity<sourceLength) {
+            /* this catches preflighting, too */
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+            return sourceLength;
+        }
+        uprv_memcpy(dest, source, sourceLength*U_SIZEOF_UCHAR);
+        destLength=sourceLength;
+    }
+
+    /*
+     * Perform number shaping.
+     * With UTF-16 or UTF-32, the length of the string is constant.
+     * The easiest way to do this is to operate on the destination and
+     * "shape" the digits in-place.
+     */
+    if((options&U_SHAPE_DIGITS_MASK)!=U_SHAPE_DIGITS_NOOP) {
+        UChar digitBase;
+        int32_t i;
+
+        /* select the requested digit group */
+        switch(options&U_SHAPE_DIGIT_TYPE_MASK) {
+        case U_SHAPE_DIGIT_TYPE_AN:
+            digitBase=0x660; /* Unicode: "Arabic-Indic digits" */
+            break;
+        case U_SHAPE_DIGIT_TYPE_AN_EXTENDED:
+            digitBase=0x6f0; /* Unicode: "Eastern Arabic-Indic digits (Persian and Urdu)" */
+            break;
+        default:
+            /* will never occur because of validity checks above */
+            digitBase=0;
+            break;
+        }
+
+        /* perform the requested operation */
+        switch(options&U_SHAPE_DIGITS_MASK) {
+        case U_SHAPE_DIGITS_EN2AN:
+            /* add (digitBase-'0') to each European (ASCII) digit code point */
+            digitBase-=0x30;
+            for(i=0; i<destLength; ++i) {
+                if(((uint32_t)dest[i]-0x30)<10) {
+                    dest[i]+=digitBase;
+                }
+            }
+            break;
+        case U_SHAPE_DIGITS_AN2EN:
+            /* subtract (digitBase-'0') from each Arabic digit code point */
+            for(i=0; i<destLength; ++i) {
+                if(((uint32_t)dest[i]-(uint32_t)digitBase)<10) {
+                    dest[i]-=digitBase-0x30;
+                }
+            }
+            break;
+        case U_SHAPE_DIGITS_ALEN2AN_INIT_LR:
+            _shapeToArabicDigitsWithContext(dest, destLength,
+                                            digitBase,
+                                            (UBool)((options&U_SHAPE_TEXT_DIRECTION_MASK)==U_SHAPE_TEXT_DIRECTION_LOGICAL),
+                                            FALSE);
+            break;
+        case U_SHAPE_DIGITS_ALEN2AN_INIT_AL:
+            _shapeToArabicDigitsWithContext(dest, destLength,
+                                            digitBase,
+                                            (UBool)((options&U_SHAPE_TEXT_DIRECTION_MASK)==U_SHAPE_TEXT_DIRECTION_LOGICAL),
+                                            TRUE);
+            break;
+        default:
+            /* will never occur because of validity checks above */
+            break;
+        }
+    }
+
+    return u_terminateUChars(dest, destCapacity, destLength, pErrorCode);
+}
diff --git a/source/common/usprep.cpp b/source/common/usprep.cpp
new file mode 100644
index 0000000..415253c
--- /dev/null
+++ b/source/common/usprep.cpp
@@ -0,0 +1,921 @@
+/*
+ *******************************************************************************
+ *
+ *   Copyright (C) 2003-2010, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ *
+ *******************************************************************************
+ *   file name:  usprep.cpp
+ *   encoding:   US-ASCII
+ *   tab size:   8 (not used)
+ *   indentation:4
+ *
+ *   created on: 2003jul2
+ *   created by: Ram Viswanadha
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_IDNA
+
+#include "unicode/usprep.h"
+
+#include "unicode/unorm.h"
+#include "unicode/ustring.h"
+#include "unicode/uchar.h"
+#include "unicode/uversion.h"
+#include "umutex.h"
+#include "cmemory.h"
+#include "sprpimpl.h"
+#include "ustr_imp.h"
+#include "uhash.h"
+#include "cstring.h"
+#include "udataswp.h"
+#include "ucln_cmn.h"
+#include "ubidi_props.h"
+
+U_NAMESPACE_USE
+
+U_CDECL_BEGIN
+
+/*
+Static cache for already opened StringPrep profiles
+*/
+static UHashtable *SHARED_DATA_HASHTABLE = NULL;
+
+static UMTX usprepMutex = NULL;
+
+/* format version of spp file */
+static uint8_t formatVersion[4]={ 0, 0, 0, 0 };
+
+/* the Unicode version of the sprep data */
+static UVersionInfo dataVersion={ 0, 0, 0, 0 };
+
+/* Profile names must be aligned to UStringPrepProfileType */
+static const char *PROFILE_NAMES[] = {
+    "rfc3491",      /* USPREP_RFC3491_NAMEPREP */
+    "rfc3530cs",    /* USPREP_RFC3530_NFS4_CS_PREP */
+    "rfc3530csci",  /* USPREP_RFC3530_NFS4_CS_PREP_CI */
+    "rfc3491",      /* USPREP_RFC3530_NSF4_CIS_PREP */
+    "rfc3530mixp",  /* USPREP_RFC3530_NSF4_MIXED_PREP_PREFIX */
+    "rfc3491",      /* USPREP_RFC3530_NSF4_MIXED_PREP_SUFFIX */
+    "rfc3722",      /* USPREP_RFC3722_ISCSI */
+    "rfc3920node",  /* USPREP_RFC3920_NODEPREP */
+    "rfc3920res",   /* USPREP_RFC3920_RESOURCEPREP */
+    "rfc4011",      /* USPREP_RFC4011_MIB */
+    "rfc4013",      /* USPREP_RFC4013_SASLPREP */
+    "rfc4505",      /* USPREP_RFC4505_TRACE */
+    "rfc4518",      /* USPREP_RFC4518_LDAP */
+    "rfc4518ci",    /* USPREP_RFC4518_LDAP_CI */
+};
+
+static UBool U_CALLCONV
+isSPrepAcceptable(void * /* context */,
+             const char * /* type */, 
+             const char * /* name */,
+             const UDataInfo *pInfo) {
+    if(
+        pInfo->size>=20 &&
+        pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
+        pInfo->charsetFamily==U_CHARSET_FAMILY &&
+        pInfo->dataFormat[0]==0x53 &&   /* dataFormat="SPRP" */
+        pInfo->dataFormat[1]==0x50 &&
+        pInfo->dataFormat[2]==0x52 &&
+        pInfo->dataFormat[3]==0x50 &&
+        pInfo->formatVersion[0]==3 &&
+        pInfo->formatVersion[2]==UTRIE_SHIFT &&
+        pInfo->formatVersion[3]==UTRIE_INDEX_SHIFT
+    ) {
+        uprv_memcpy(formatVersion, pInfo->formatVersion, 4);
+        uprv_memcpy(dataVersion, pInfo->dataVersion, 4);
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+}
+
+static int32_t U_CALLCONV
+getSPrepFoldingOffset(uint32_t data) {
+
+    return (int32_t)data;
+
+}
+
+/* hashes an entry  */
+static int32_t U_CALLCONV 
+hashEntry(const UHashTok parm) {
+    UStringPrepKey *b = (UStringPrepKey *)parm.pointer;
+    UHashTok namekey, pathkey;
+    namekey.pointer = b->name;
+    pathkey.pointer = b->path;
+    return uhash_hashChars(namekey)+37*uhash_hashChars(pathkey);
+}
+
+/* compares two entries */
+static UBool U_CALLCONV 
+compareEntries(const UHashTok p1, const UHashTok p2) {
+    UStringPrepKey *b1 = (UStringPrepKey *)p1.pointer;
+    UStringPrepKey *b2 = (UStringPrepKey *)p2.pointer;
+    UHashTok name1, name2, path1, path2;
+    name1.pointer = b1->name;
+    name2.pointer = b2->name;
+    path1.pointer = b1->path;
+    path2.pointer = b2->path;
+    return ((UBool)(uhash_compareChars(name1, name2) & 
+        uhash_compareChars(path1, path2)));
+}
+
+static void 
+usprep_unload(UStringPrepProfile* data){
+    udata_close(data->sprepData);
+}
+
+static int32_t 
+usprep_internal_flushCache(UBool noRefCount){
+    UStringPrepProfile *profile = NULL;
+    UStringPrepKey  *key  = NULL;
+    int32_t pos = -1;
+    int32_t deletedNum = 0;
+    const UHashElement *e;
+
+    /*
+     * if shared data hasn't even been lazy evaluated yet
+     * return 0
+     */
+    umtx_lock(&usprepMutex);
+    if (SHARED_DATA_HASHTABLE == NULL) {
+        umtx_unlock(&usprepMutex);
+        return 0;
+    }
+
+    /*creates an enumeration to iterate through every element in the table */
+    while ((e = uhash_nextElement(SHARED_DATA_HASHTABLE, &pos)) != NULL)
+    {
+        profile = (UStringPrepProfile *) e->value.pointer;
+        key  = (UStringPrepKey *) e->key.pointer;
+
+        if ((noRefCount== FALSE && profile->refCount == 0) || 
+             noRefCount== TRUE) {
+            deletedNum++;
+            uhash_removeElement(SHARED_DATA_HASHTABLE, e);
+
+            /* unload the data */
+            usprep_unload(profile);
+
+            if(key->name != NULL) {
+                uprv_free(key->name);
+                key->name=NULL;
+            }
+            if(key->path != NULL) {
+                uprv_free(key->path);
+                key->path=NULL;
+            }
+            uprv_free(profile);
+            uprv_free(key);
+        }
+       
+    }
+    umtx_unlock(&usprepMutex);
+
+    return deletedNum;
+}
+
+/* Works just like ucnv_flushCache() 
+static int32_t 
+usprep_flushCache(){
+    return usprep_internal_flushCache(FALSE);
+}
+*/
+
+static UBool U_CALLCONV usprep_cleanup(void){
+    if (SHARED_DATA_HASHTABLE != NULL) {
+        usprep_internal_flushCache(TRUE);
+        if (SHARED_DATA_HASHTABLE != NULL && uhash_count(SHARED_DATA_HASHTABLE) == 0) {
+            uhash_close(SHARED_DATA_HASHTABLE);
+            SHARED_DATA_HASHTABLE = NULL;
+        }
+    }
+
+    umtx_destroy(&usprepMutex);             /* Don't worry about destroying the mutex even  */
+                                            /*  if the hash table still exists.  The mutex  */
+                                            /*  will lazily re-init  itself if needed.      */
+    return (SHARED_DATA_HASHTABLE == NULL);
+}
+U_CDECL_END
+
+
+/** Initializes the cache for resources */
+static void 
+initCache(UErrorCode *status) {
+    UBool makeCache;
+    UMTX_CHECK(&usprepMutex, (SHARED_DATA_HASHTABLE ==  NULL), makeCache);
+    if(makeCache) {
+        UHashtable *newCache = uhash_open(hashEntry, compareEntries, NULL, status);
+        if (U_SUCCESS(*status)) {
+            umtx_lock(&usprepMutex);
+            if(SHARED_DATA_HASHTABLE == NULL) {
+                SHARED_DATA_HASHTABLE = newCache;
+                ucln_common_registerCleanup(UCLN_COMMON_USPREP, usprep_cleanup);
+                newCache = NULL;
+            }
+            umtx_unlock(&usprepMutex);
+        }
+        if(newCache != NULL) {
+            uhash_close(newCache);
+        }
+    }
+}
+
+static UBool U_CALLCONV
+loadData(UStringPrepProfile* profile, 
+         const char* path, 
+         const char* name, 
+         const char* type, 
+         UErrorCode* errorCode) {
+    /* load Unicode SPREP data from file */    
+    UTrie _sprepTrie={ 0,0,0,0,0,0,0 };
+    UDataMemory *dataMemory;
+    const int32_t *p=NULL;
+    const uint8_t *pb;
+    UVersionInfo normUnicodeVersion;
+    int32_t normUniVer, sprepUniVer, normCorrVer;
+
+    if(errorCode==NULL || U_FAILURE(*errorCode)) {
+        return 0;
+    }
+
+    /* open the data outside the mutex block */
+    //TODO: change the path
+    dataMemory=udata_openChoice(path, type, name, isSPrepAcceptable, NULL, errorCode);
+    if(U_FAILURE(*errorCode)) {
+        return FALSE;
+    }
+
+    p=(const int32_t *)udata_getMemory(dataMemory);
+    pb=(const uint8_t *)(p+_SPREP_INDEX_TOP);
+    utrie_unserialize(&_sprepTrie, pb, p[_SPREP_INDEX_TRIE_SIZE], errorCode);
+    _sprepTrie.getFoldingOffset=getSPrepFoldingOffset;
+
+
+    if(U_FAILURE(*errorCode)) {
+        udata_close(dataMemory);
+        return FALSE;
+    }
+
+    /* in the mutex block, set the data for this process */
+    umtx_lock(&usprepMutex);
+    if(profile->sprepData==NULL) {
+        profile->sprepData=dataMemory;
+        dataMemory=NULL;
+        uprv_memcpy(&profile->indexes, p, sizeof(profile->indexes));
+        uprv_memcpy(&profile->sprepTrie, &_sprepTrie, sizeof(UTrie));
+    } else {
+        p=(const int32_t *)udata_getMemory(profile->sprepData);
+    }
+    umtx_unlock(&usprepMutex);
+    /* initialize some variables */
+    profile->mappingData=(uint16_t *)((uint8_t *)(p+_SPREP_INDEX_TOP)+profile->indexes[_SPREP_INDEX_TRIE_SIZE]);
+    
+    u_getUnicodeVersion(normUnicodeVersion);
+    normUniVer = (normUnicodeVersion[0] << 24) + (normUnicodeVersion[1] << 16) + 
+                 (normUnicodeVersion[2] << 8 ) + (normUnicodeVersion[3]);
+    sprepUniVer = (dataVersion[0] << 24) + (dataVersion[1] << 16) + 
+                  (dataVersion[2] << 8 ) + (dataVersion[3]);
+    normCorrVer = profile->indexes[_SPREP_NORM_CORRECTNS_LAST_UNI_VERSION];
+    
+    if(U_FAILURE(*errorCode)){
+        udata_close(dataMemory);
+        return FALSE;
+    }
+    if( normUniVer < sprepUniVer && /* the Unicode version of SPREP file must be less than the Unicode Vesion of the normalization data */
+        normUniVer < normCorrVer && /* the Unicode version of the NormalizationCorrections.txt file should be less than the Unicode Vesion of the normalization data */
+        ((profile->indexes[_SPREP_OPTIONS] & _SPREP_NORMALIZATION_ON) > 0) /* normalization turned on*/
+      ){
+        *errorCode = U_INVALID_FORMAT_ERROR;
+        udata_close(dataMemory);
+        return FALSE;
+    }
+    profile->isDataLoaded = TRUE;
+
+    /* if a different thread set it first, then close the extra data */
+    if(dataMemory!=NULL) {
+        udata_close(dataMemory); /* NULL if it was set correctly */
+    }
+
+
+    return profile->isDataLoaded;
+}
+
+static UStringPrepProfile* 
+usprep_getProfile(const char* path, 
+                  const char* name,
+                  UErrorCode *status){
+
+    UStringPrepProfile* profile = NULL;
+
+    initCache(status);
+
+    if(U_FAILURE(*status)){
+        return NULL;
+    }
+
+    UStringPrepKey stackKey;
+    /* 
+     * const is cast way to save malloc, strcpy and free calls 
+     * we use the passed in pointers for fetching the data from the 
+     * hash table which is safe
+     */
+    stackKey.name = (char*) name;
+    stackKey.path = (char*) path;
+
+    /* fetch the data from the cache */
+    umtx_lock(&usprepMutex);
+    profile = (UStringPrepProfile*) (uhash_get(SHARED_DATA_HASHTABLE,&stackKey));
+    if(profile != NULL) {
+        profile->refCount++;
+    }
+    umtx_unlock(&usprepMutex);
+    
+    if(profile == NULL) {
+        /* else load the data and put the data in the cache */
+        LocalMemory<UStringPrepProfile> newProfile;
+        if(newProfile.allocateInsteadAndReset() == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return NULL;
+        }
+
+        /* load the data */
+        if(!loadData(newProfile.getAlias(), path, name, _SPREP_DATA_TYPE, status) || U_FAILURE(*status) ){
+            return NULL;
+        }
+
+        /* get the options */
+        newProfile->doNFKC = (UBool)((newProfile->indexes[_SPREP_OPTIONS] & _SPREP_NORMALIZATION_ON) > 0);
+        newProfile->checkBiDi = (UBool)((newProfile->indexes[_SPREP_OPTIONS] & _SPREP_CHECK_BIDI_ON) > 0);
+
+        if(newProfile->checkBiDi) {
+            newProfile->bdp = ubidi_getSingleton();
+        }
+
+        LocalMemory<UStringPrepKey> key;
+        LocalMemory<char> keyName;
+        LocalMemory<char> keyPath;
+        if( key.allocateInsteadAndReset() == NULL ||
+            keyName.allocateInsteadAndCopy(uprv_strlen(name)+1) == NULL ||
+            (path != NULL &&
+             keyPath.allocateInsteadAndCopy(uprv_strlen(path)+1) == NULL)
+         ) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            usprep_unload(newProfile.getAlias());
+            return NULL;
+        }
+
+        umtx_lock(&usprepMutex);
+        // If another thread already inserted the same key/value, refcount and cleanup our thread data
+        profile = (UStringPrepProfile*) (uhash_get(SHARED_DATA_HASHTABLE,&stackKey));
+        if(profile != NULL) {
+            profile->refCount++;
+            usprep_unload(newProfile.getAlias());
+        }
+        else {
+            /* initialize the key members */
+            key->name = keyName.orphan();
+            uprv_strcpy(key->name, name);
+            if(path != NULL){
+                key->path = keyPath.orphan();
+                uprv_strcpy(key->path, path);
+            }        
+            profile = newProfile.orphan();
+    
+            /* add the data object to the cache */
+            profile->refCount = 1;
+            uhash_put(SHARED_DATA_HASHTABLE, key.orphan(), profile, status);
+        }
+        umtx_unlock(&usprepMutex);
+    }
+
+    return profile;
+}
+
+U_CAPI UStringPrepProfile* U_EXPORT2
+usprep_open(const char* path, 
+            const char* name,
+            UErrorCode* status){
+
+    if(status == NULL || U_FAILURE(*status)){
+        return NULL;
+    }
+       
+    /* initialize the profile struct members */
+    return usprep_getProfile(path,name,status);
+}
+
+U_CAPI UStringPrepProfile* U_EXPORT2
+usprep_openByType(UStringPrepProfileType type,
+				  UErrorCode* status) {
+    if(status == NULL || U_FAILURE(*status)){
+        return NULL;
+    }
+    int32_t index = (int32_t)type;
+    if (index < 0 || index >= (int32_t)(sizeof(PROFILE_NAMES)/sizeof(PROFILE_NAMES[0]))) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+    return usprep_open(NULL, PROFILE_NAMES[index], status);
+}
+
+U_CAPI void U_EXPORT2
+usprep_close(UStringPrepProfile* profile){
+    if(profile==NULL){
+        return;
+    }
+
+    umtx_lock(&usprepMutex);
+    /* decrement the ref count*/
+    if(profile->refCount > 0){
+        profile->refCount--;
+    }
+    umtx_unlock(&usprepMutex);
+    
+}
+
+U_CFUNC void 
+uprv_syntaxError(const UChar* rules, 
+                 int32_t pos,
+                 int32_t rulesLen,
+                 UParseError* parseError){
+    if(parseError == NULL){
+        return;
+    }
+    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 limit = pos;
+    
+    u_memcpy(parseError->preContext,rules+start,limit-start);
+    //null terminate the buffer
+    parseError->preContext[limit-start] = 0;
+    
+    // for post-context; include error rules[pos]
+    start = pos;
+    limit = start + (U_PARSE_CONTEXT_LEN-1);
+    if (limit > rulesLen) {
+        limit = rulesLen;
+    }
+    if (start < rulesLen) {
+        u_memcpy(parseError->postContext,rules+start,limit-start);
+    }
+    //null terminate the buffer
+    parseError->postContext[limit-start]= 0;
+}
+
+
+static inline UStringPrepType
+getValues(uint16_t trieWord, int16_t& value, UBool& isIndex){
+
+    UStringPrepType type;
+    if(trieWord == 0){
+        /* 
+         * Initial value stored in the mapping table 
+         * just return USPREP_TYPE_LIMIT .. so that
+         * the source codepoint is copied to the destination
+         */
+        type = USPREP_TYPE_LIMIT;
+        isIndex =FALSE;
+        value = 0;
+    }else if(trieWord >= _SPREP_TYPE_THRESHOLD){
+        type = (UStringPrepType) (trieWord - _SPREP_TYPE_THRESHOLD);
+        isIndex =FALSE;
+        value = 0;
+    }else{
+        /* get the type */
+        type = USPREP_MAP;
+        /* ascertain if the value is index or delta */
+        if(trieWord & 0x02){
+            isIndex = TRUE;
+            value = trieWord  >> 2; //mask off the lower 2 bits and shift
+        }else{
+            isIndex = FALSE;
+            value = (int16_t)trieWord;
+            value =  (value >> 2);
+        }
+ 
+        if((trieWord>>2) == _SPREP_MAX_INDEX_VALUE){
+            type = USPREP_DELETE;
+            isIndex =FALSE;
+            value = 0;
+        }
+    }
+    return type;
+}
+
+
+
+static int32_t 
+usprep_map(  const UStringPrepProfile* profile, 
+             const UChar* src, int32_t srcLength, 
+             UChar* dest, int32_t destCapacity,
+             int32_t options,
+             UParseError* parseError,
+             UErrorCode* status ){
+    
+    uint16_t result;
+    int32_t destIndex=0;
+    int32_t srcIndex;
+    UBool allowUnassigned = (UBool) ((options & USPREP_ALLOW_UNASSIGNED)>0);
+    UStringPrepType type;
+    int16_t value;
+    UBool isIndex;
+    const int32_t* indexes = profile->indexes;
+
+    // no error checking the caller check for error and arguments
+    // no string length check the caller finds out the string length
+
+    for(srcIndex=0;srcIndex<srcLength;){
+        UChar32 ch;
+
+        U16_NEXT(src,srcIndex,srcLength,ch);
+        
+        result=0;
+
+        UTRIE_GET16(&profile->sprepTrie,ch,result);
+        
+        type = getValues(result, value, isIndex);
+
+        // check if the source codepoint is unassigned
+        if(type == USPREP_UNASSIGNED && allowUnassigned == FALSE){
+
+            uprv_syntaxError(src,srcIndex-U16_LENGTH(ch), srcLength,parseError);
+            *status = U_STRINGPREP_UNASSIGNED_ERROR;
+            return 0;
+            
+        }else if(type == USPREP_MAP){
+            
+            int32_t index, length;
+
+            if(isIndex){
+                index = value;
+                if(index >= indexes[_SPREP_ONE_UCHAR_MAPPING_INDEX_START] &&
+                         index < indexes[_SPREP_TWO_UCHARS_MAPPING_INDEX_START]){
+                    length = 1;
+                }else if(index >= indexes[_SPREP_TWO_UCHARS_MAPPING_INDEX_START] &&
+                         index < indexes[_SPREP_THREE_UCHARS_MAPPING_INDEX_START]){
+                    length = 2;
+                }else if(index >= indexes[_SPREP_THREE_UCHARS_MAPPING_INDEX_START] &&
+                         index < indexes[_SPREP_FOUR_UCHARS_MAPPING_INDEX_START]){
+                    length = 3;
+                }else{
+                    length = profile->mappingData[index++];
+         
+                }
+
+                /* copy mapping to destination */
+                for(int32_t i=0; i< length; i++){
+                    if(destIndex < destCapacity  ){
+                        dest[destIndex] = profile->mappingData[index+i];
+                    }
+                    destIndex++; /* for pre-flighting */
+                }  
+                continue;
+            }else{
+                // subtract the delta to arrive at the code point
+                ch -= value;
+            }
+
+        }else if(type==USPREP_DELETE){
+             // just consume the codepoint and contine
+            continue;
+        }
+        //copy the code point into destination
+        if(ch <= 0xFFFF){
+            if(destIndex < destCapacity ){
+                dest[destIndex] = (UChar)ch;
+            }
+            destIndex++;
+        }else{
+            if(destIndex+1 < destCapacity ){
+                dest[destIndex]   = U16_LEAD(ch);
+                dest[destIndex+1] = U16_TRAIL(ch);
+            }
+            destIndex +=2;
+        }
+       
+    }
+        
+    return u_terminateUChars(dest, destCapacity, destIndex, status);
+}
+
+
+static int32_t 
+usprep_normalize(   const UChar* src, int32_t srcLength, 
+                    UChar* dest, int32_t destCapacity,
+                    UErrorCode* status ){
+    return unorm_normalize(
+        src, srcLength,
+        UNORM_NFKC, UNORM_UNICODE_3_2,
+        dest, destCapacity,
+        status);
+}
+
+
+ /*
+   1) Map -- For each character in the input, check if it has a mapping
+      and, if so, replace it with its mapping.  
+
+   2) Normalize -- Possibly normalize the result of step 1 using Unicode
+      normalization. 
+
+   3) Prohibit -- Check for any characters that are not allowed in the
+      output.  If any are found, return an error.  
+
+   4) Check bidi -- Possibly check for right-to-left characters, and if
+      any are found, make sure that the whole string satisfies the
+      requirements for bidirectional strings.  If the string does not
+      satisfy the requirements for bidirectional strings, return an
+      error.  
+      [Unicode3.2] defines several bidirectional categories; each character
+       has one bidirectional category assigned to it.  For the purposes of
+       the requirements below, an "RandALCat character" is a character that
+       has Unicode bidirectional categories "R" or "AL"; an "LCat character"
+       is a character that has Unicode bidirectional category "L".  Note
+
+
+       that there are many characters which fall in neither of the above
+       definitions; Latin digits (<U+0030> through <U+0039>) are examples of
+       this because they have bidirectional category "EN".
+
+       In any profile that specifies bidirectional character handling, all
+       three of the following requirements MUST be met:
+
+       1) The characters in section 5.8 MUST be prohibited.
+
+       2) If a string contains any RandALCat character, the string MUST NOT
+          contain any LCat character.
+
+       3) If a string contains any RandALCat character, a RandALCat
+          character MUST be the first character of the string, and a
+          RandALCat character MUST be the last character of the string.
+*/
+
+#define MAX_STACK_BUFFER_SIZE 300
+
+
+U_CAPI int32_t U_EXPORT2
+usprep_prepare(   const UStringPrepProfile* profile,
+                  const UChar* src, int32_t srcLength, 
+                  UChar* dest, int32_t destCapacity,
+                  int32_t options,
+                  UParseError* parseError,
+                  UErrorCode* status ){
+
+    // check error status
+    if(status == NULL || U_FAILURE(*status)){
+        return 0;
+    }
+    
+    //check arguments
+    if(profile==NULL || src==NULL || srcLength<-1 || (dest==NULL && destCapacity!=0)) {
+        *status=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    UChar b1Stack[MAX_STACK_BUFFER_SIZE], b2Stack[MAX_STACK_BUFFER_SIZE];
+    UChar *b1 = b1Stack, *b2 = b2Stack;
+    int32_t b1Len, b2Len=0,
+            b1Capacity = MAX_STACK_BUFFER_SIZE , 
+            b2Capacity = MAX_STACK_BUFFER_SIZE;
+    uint16_t result;
+    int32_t b2Index = 0;
+    UCharDirection direction=U_CHAR_DIRECTION_COUNT, firstCharDir=U_CHAR_DIRECTION_COUNT;
+    UBool leftToRight=FALSE, rightToLeft=FALSE;
+    int32_t rtlPos =-1, ltrPos =-1;
+
+    //get the string length
+    if(srcLength == -1){
+        srcLength = u_strlen(src);
+    }
+    // map
+    b1Len = usprep_map(profile, src, srcLength, b1, b1Capacity, options, parseError, status);
+
+    if(*status == U_BUFFER_OVERFLOW_ERROR){
+        // redo processing of string
+        /* we do not have enough room so grow the buffer*/
+        b1 = (UChar*) uprv_malloc(b1Len * U_SIZEOF_UCHAR);
+        if(b1==NULL){
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            goto CLEANUP;
+        }
+
+        *status = U_ZERO_ERROR; // reset error
+        
+        b1Len = usprep_map(profile, src, srcLength, b1, b1Len, options, parseError, status);
+        
+    }
+
+    // normalize
+    if(profile->doNFKC == TRUE){
+        b2Len = usprep_normalize(b1,b1Len, b2,b2Capacity,status);
+        
+        if(*status == U_BUFFER_OVERFLOW_ERROR){
+            // redo processing of string
+            /* we do not have enough room so grow the buffer*/
+            b2 = (UChar*) uprv_malloc(b2Len * U_SIZEOF_UCHAR);
+            if(b2==NULL){
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                goto CLEANUP;
+            }
+
+            *status = U_ZERO_ERROR; // reset error
+        
+            b2Len = usprep_normalize(b1,b1Len, b2,b2Len,status);
+        
+        }
+
+    }else{
+        b2 = b1;
+        b2Len = b1Len;
+    }
+    
+
+    if(U_FAILURE(*status)){
+        goto CLEANUP;
+    }
+
+    UChar32 ch;
+    UStringPrepType type;
+    int16_t value;
+    UBool isIndex;
+    
+    // Prohibit and checkBiDi in one pass
+    for(b2Index=0; b2Index<b2Len;){
+        
+        ch = 0;
+
+        U16_NEXT(b2, b2Index, b2Len, ch);
+
+        UTRIE_GET16(&profile->sprepTrie,ch,result);
+        
+        type = getValues(result, value, isIndex);
+
+        if( type == USPREP_PROHIBITED || 
+            ((result < _SPREP_TYPE_THRESHOLD) && (result & 0x01) /* first bit says it the code point is prohibited*/)
+           ){
+            *status = U_STRINGPREP_PROHIBITED_ERROR;
+            uprv_syntaxError(b1, b2Index-U16_LENGTH(ch), b2Len, parseError);
+            goto CLEANUP;
+        }
+
+        if(profile->checkBiDi) {
+            direction = ubidi_getClass(profile->bdp, ch);
+            if(firstCharDir == U_CHAR_DIRECTION_COUNT){
+                firstCharDir = direction;
+            }
+            if(direction == U_LEFT_TO_RIGHT){
+                leftToRight = TRUE;
+                ltrPos = b2Index-1;
+            }
+            if(direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC){
+                rightToLeft = TRUE;
+                rtlPos = b2Index-1;
+            }
+        }
+    }           
+    if(profile->checkBiDi == TRUE){
+        // satisfy 2
+        if( leftToRight == TRUE && rightToLeft == TRUE){
+            *status = U_STRINGPREP_CHECK_BIDI_ERROR;
+            uprv_syntaxError(b2,(rtlPos>ltrPos) ? rtlPos : ltrPos, b2Len, parseError);
+            goto CLEANUP;
+        }
+
+        //satisfy 3
+        if( rightToLeft == TRUE && 
+            !((firstCharDir == U_RIGHT_TO_LEFT || firstCharDir == U_RIGHT_TO_LEFT_ARABIC) &&
+              (direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC))
+           ){
+            *status = U_STRINGPREP_CHECK_BIDI_ERROR;
+            uprv_syntaxError(b2, rtlPos, b2Len, parseError);
+            return FALSE;
+        }
+    }
+    if(b2Len>0 && b2Len <= destCapacity){
+        uprv_memmove(dest,b2, b2Len*U_SIZEOF_UCHAR);
+    }
+
+CLEANUP:
+    if(b1!=b1Stack){
+        uprv_free(b1);
+        b1=NULL;
+    }
+
+    if(b2!=b1Stack && b2!=b2Stack && b2!=b1 /* b1 should not be freed twice */){
+        uprv_free(b2);
+        b2=NULL;
+    }
+    return u_terminateUChars(dest, destCapacity, b2Len, status);
+}
+
+
+/* data swapping ------------------------------------------------------------ */
+
+U_CAPI int32_t U_EXPORT2
+usprep_swap(const UDataSwapper *ds,
+            const void *inData, int32_t length, void *outData,
+            UErrorCode *pErrorCode) {
+    const UDataInfo *pInfo;
+    int32_t headerSize;
+
+    const uint8_t *inBytes;
+    uint8_t *outBytes;
+
+    const int32_t *inIndexes;
+    int32_t indexes[16];
+
+    int32_t i, offset, count, size;
+
+    /* udata_swapDataHeader checks the arguments */
+    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    /* check data format and format version */
+    pInfo=(const UDataInfo *)((const char *)inData+4);
+    if(!(
+        pInfo->dataFormat[0]==0x53 &&   /* dataFormat="SPRP" */
+        pInfo->dataFormat[1]==0x50 &&
+        pInfo->dataFormat[2]==0x52 &&
+        pInfo->dataFormat[3]==0x50 &&
+        pInfo->formatVersion[0]==3
+    )) {
+        udata_printError(ds, "usprep_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as StringPrep .spp data\n",
+                         pInfo->dataFormat[0], pInfo->dataFormat[1],
+                         pInfo->dataFormat[2], pInfo->dataFormat[3],
+                         pInfo->formatVersion[0]);
+        *pErrorCode=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    inBytes=(const uint8_t *)inData+headerSize;
+    outBytes=(uint8_t *)outData+headerSize;
+
+    inIndexes=(const int32_t *)inBytes;
+
+    if(length>=0) {
+        length-=headerSize;
+        if(length<16*4) {
+            udata_printError(ds, "usprep_swap(): too few bytes (%d after header) for StringPrep .spp data\n",
+                             length);
+            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+            return 0;
+        }
+    }
+
+    /* read the first 16 indexes (ICU 2.8/format version 3: _SPREP_INDEX_TOP==16, might grow) */
+    for(i=0; i<16; ++i) {
+        indexes[i]=udata_readInt32(ds, inIndexes[i]);
+    }
+
+    /* calculate the total length of the data */
+    size=
+        16*4+ /* size of indexes[] */
+        indexes[_SPREP_INDEX_TRIE_SIZE]+
+        indexes[_SPREP_INDEX_MAPPING_DATA_SIZE];
+
+    if(length>=0) {
+        if(length<size) {
+            udata_printError(ds, "usprep_swap(): too few bytes (%d after header) for all of StringPrep .spp data\n",
+                             length);
+            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+            return 0;
+        }
+
+        /* copy the data for inaccessible bytes */
+        if(inBytes!=outBytes) {
+            uprv_memcpy(outBytes, inBytes, size);
+        }
+
+        offset=0;
+
+        /* swap the int32_t indexes[] */
+        count=16*4;
+        ds->swapArray32(ds, inBytes, count, outBytes, pErrorCode);
+        offset+=count;
+
+        /* swap the UTrie */
+        count=indexes[_SPREP_INDEX_TRIE_SIZE];
+        utrie_swap(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
+        offset+=count;
+
+        /* swap the uint16_t mappingTable[] */
+        count=indexes[_SPREP_INDEX_MAPPING_DATA_SIZE];
+        ds->swapArray16(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
+        offset+=count;
+    }
+
+    return headerSize+size;
+}
+
+#endif /* #if !UCONFIG_NO_IDNA */
diff --git a/source/common/ustack.cpp b/source/common/ustack.cpp
new file mode 100644
index 0000000..76118bc
--- /dev/null
+++ b/source/common/ustack.cpp
@@ -0,0 +1,61 @@
+/*
+**********************************************************************
+*   Copyright (C) 2003-2004, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+
+#include "uvector.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UStack)
+
+UStack::UStack(UErrorCode &status) :
+    UVector(status)
+{
+}
+
+UStack::UStack(int32_t initialCapacity, UErrorCode &status) :
+    UVector(initialCapacity, status)
+{
+}
+
+UStack::UStack(UObjectDeleter *d, UKeyComparator *c, UErrorCode &status) :
+    UVector(d, c, status)
+{
+}
+
+UStack::UStack(UObjectDeleter *d, UKeyComparator *c, int32_t initialCapacity, UErrorCode &status) :
+    UVector(d, c, initialCapacity, status)
+{
+}
+
+UStack::~UStack() {}
+
+void* UStack::pop(void) {
+    int32_t n = size() - 1;
+    void* result = 0;
+    if (n >= 0) {
+        result = elementAt(n);
+        removeElementAt(n);
+    }
+    return result;
+}
+
+int32_t UStack::popi(void) {
+    int32_t n = size() - 1;
+    int32_t result = 0;
+    if (n >= 0) {
+        result = elementAti(n);
+        removeElementAt(n);
+    }
+    return result;
+}
+
+int32_t UStack::search(void* obj) const {
+    int32_t i = indexOf(obj);
+    return (i >= 0) ? size() - i : i;
+}
+
+U_NAMESPACE_END
diff --git a/source/common/ustr_cnv.c b/source/common/ustr_cnv.c
new file mode 100644
index 0000000..0f11991
--- /dev/null
+++ b/source/common/ustr_cnv.c
@@ -0,0 +1,253 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1998-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  ustr_cnv.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2004aug24
+*   created by: Markus W. Scherer
+*
+*   Character conversion functions moved here from ustring.c
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ustring.h"
+#include "unicode/ucnv.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include "umutex.h"
+#include "ustr_cnv.h"
+
+/* mutexed access to a shared default converter ----------------------------- */
+
+static UConverter *gDefaultConverter = NULL;
+
+U_CAPI UConverter* U_EXPORT2
+u_getDefaultConverter(UErrorCode *status)
+{
+    UConverter *converter = NULL;
+    
+    if (gDefaultConverter != NULL) {
+        umtx_lock(NULL);
+        
+        /* need to check to make sure it wasn't taken out from under us */
+        if (gDefaultConverter != NULL) {
+            converter = gDefaultConverter;
+            gDefaultConverter = NULL;
+        }
+        umtx_unlock(NULL);
+    }
+
+    /* if the cache was empty, create a converter */
+    if(converter == NULL) {
+        converter = ucnv_open(NULL, status);
+        if(U_FAILURE(*status)) {
+            ucnv_close(converter);
+            converter = NULL;
+        }
+    }
+
+    return converter;
+}
+
+U_CAPI void U_EXPORT2
+u_releaseDefaultConverter(UConverter *converter)
+{
+    if(gDefaultConverter == NULL) {
+        if (converter != NULL) {
+            ucnv_reset(converter);
+        }
+        umtx_lock(NULL);
+
+        if(gDefaultConverter == NULL) {
+            gDefaultConverter = converter;
+            converter = NULL;
+        }
+        umtx_unlock(NULL);
+    }
+
+    if(converter != NULL) {
+        ucnv_close(converter);
+    }
+}
+
+U_CAPI void U_EXPORT2
+u_flushDefaultConverter()
+{
+    UConverter *converter = NULL;
+    
+    if (gDefaultConverter != NULL) {
+        umtx_lock(NULL);
+        
+        /* need to check to make sure it wasn't taken out from under us */
+        if (gDefaultConverter != NULL) {
+            converter = gDefaultConverter;
+            gDefaultConverter = NULL;
+        }
+        umtx_unlock(NULL);
+    }
+
+    /* if the cache was populated, flush it */
+    if(converter != NULL) {
+         ucnv_close(converter);
+    }
+}
+
+
+/* conversions between char* and UChar* ------------------------------------- */
+
+/* maximum string length for u_uastrcpy() and u_austrcpy() implementations */
+#define MAX_STRLEN 0x0FFFFFFF
+
+/*
+ returns the minimum of (the length of the null-terminated string) and n.
+*/
+static int32_t u_astrnlen(const char *s1, int32_t n)
+{
+    int32_t len = 0;
+
+    if (s1)
+    {
+        while (n-- && *(s1++))
+        {
+            len++;
+        }
+    }
+    return len;
+}
+
+U_CAPI UChar*  U_EXPORT2
+u_uastrncpy(UChar *ucs1,
+           const char *s2,
+           int32_t n)
+{
+  UChar *target = ucs1;
+  UErrorCode err = U_ZERO_ERROR;
+  UConverter *cnv = u_getDefaultConverter(&err);
+  if(U_SUCCESS(err) && cnv != NULL) {
+    ucnv_reset(cnv);
+    ucnv_toUnicode(cnv,
+                   &target,
+                   ucs1+n,
+                   &s2,
+                   s2+u_astrnlen(s2, n),
+                   NULL,
+                   TRUE,
+                   &err);
+    ucnv_reset(cnv); /* be good citizens */
+    u_releaseDefaultConverter(cnv);
+    if(U_FAILURE(err) && (err != U_BUFFER_OVERFLOW_ERROR) ) {
+      *ucs1 = 0; /* failure */
+    }
+    if(target < (ucs1+n)) { /* U_BUFFER_OVERFLOW_ERROR isn't an err, just means no termination will happen. */
+      *target = 0;  /* terminate */
+    }
+  } else {
+    *ucs1 = 0;
+  }
+  return ucs1;
+}
+
+U_CAPI UChar*  U_EXPORT2
+u_uastrcpy(UChar *ucs1,
+          const char *s2 )
+{
+  UErrorCode err = U_ZERO_ERROR;
+  UConverter *cnv = u_getDefaultConverter(&err);
+  if(U_SUCCESS(err) && cnv != NULL) {
+    ucnv_toUChars(cnv,
+                    ucs1,
+                    MAX_STRLEN,
+                    s2,
+                    (int32_t)uprv_strlen(s2),
+                    &err);
+    u_releaseDefaultConverter(cnv);
+    if(U_FAILURE(err)) {
+      *ucs1 = 0;
+    }
+  } else {
+    *ucs1 = 0;
+  }
+  return ucs1;
+}
+
+/*
+ returns the minimum of (the length of the null-terminated string) and n.
+*/
+static int32_t u_ustrnlen(const UChar *ucs1, int32_t n)
+{
+    int32_t len = 0;
+
+    if (ucs1)
+    {
+        while (n-- && *(ucs1++))
+        {
+            len++;
+        }
+    }
+    return len;
+}
+
+U_CAPI char*  U_EXPORT2
+u_austrncpy(char *s1,
+        const UChar *ucs2,
+        int32_t n)
+{
+  char *target = s1;
+  UErrorCode err = U_ZERO_ERROR;
+  UConverter *cnv = u_getDefaultConverter(&err);
+  if(U_SUCCESS(err) && cnv != NULL) {
+    ucnv_reset(cnv);
+    ucnv_fromUnicode(cnv,
+                  &target,
+                  s1+n,
+                  &ucs2,
+                  ucs2+u_ustrnlen(ucs2, n),
+                  NULL,
+                  TRUE,
+                  &err);
+    ucnv_reset(cnv); /* be good citizens */
+    u_releaseDefaultConverter(cnv);
+    if(U_FAILURE(err) && (err != U_BUFFER_OVERFLOW_ERROR) ) {
+      *s1 = 0; /* failure */
+    }
+    if(target < (s1+n)) { /* U_BUFFER_OVERFLOW_ERROR isn't an err, just means no termination will happen. */
+      *target = 0;  /* terminate */
+    }
+  } else {
+    *s1 = 0;
+  }
+  return s1;
+}
+
+U_CAPI char*  U_EXPORT2
+u_austrcpy(char *s1,
+         const UChar *ucs2 )
+{
+  UErrorCode err = U_ZERO_ERROR;
+  UConverter *cnv = u_getDefaultConverter(&err);
+  if(U_SUCCESS(err) && cnv != NULL) {
+    int32_t len = ucnv_fromUChars(cnv,
+                  s1,
+                  MAX_STRLEN,
+                  ucs2,
+                  -1,
+                  &err);
+    u_releaseDefaultConverter(cnv);
+    s1[len] = 0;
+  } else {
+    *s1 = 0;
+  }
+  return s1;
+}
+
+#endif
diff --git a/source/common/ustr_cnv.h b/source/common/ustr_cnv.h
new file mode 100644
index 0000000..abcd3d8
--- /dev/null
+++ b/source/common/ustr_cnv.h
@@ -0,0 +1,49 @@
+/*  
+**********************************************************************
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   file name:  ustr_cnv.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2004Aug27
+*   created by: George Rhoten
+*/
+
+#ifndef USTR_CNV_IMP_H
+#define USTR_CNV_IMP_H
+
+#include "unicode/utypes.h"
+#include "unicode/ucnv.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+/**
+ * Get the default converter. This is a commonly used converter
+ * that is used for the ustring and UnicodeString API.
+ * Remember to use the u_releaseDefaultConverter when you are done.
+ * @internal
+ */
+U_CAPI UConverter* U_EXPORT2
+u_getDefaultConverter(UErrorCode *status);
+
+
+/**
+ * Release the default converter to the converter cache.
+ * @internal
+ */
+U_CAPI void U_EXPORT2
+u_releaseDefaultConverter(UConverter *converter);
+
+/**
+ * Flush the default converter, if cached. 
+ * @internal
+ */
+U_CAPI void U_EXPORT2
+u_flushDefaultConverter(void);
+
+#endif
+
+#endif
diff --git a/source/common/ustr_imp.h b/source/common/ustr_imp.h
new file mode 100644
index 0000000..01c7901
--- /dev/null
+++ b/source/common/ustr_imp.h
@@ -0,0 +1,204 @@
+/*  
+**********************************************************************
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   file name:  ustr_imp.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2001jan30
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __USTR_IMP_H__
+#define __USTR_IMP_H__
+
+#include "unicode/utypes.h"
+#include "unicode/uiter.h"
+#include "ucase.h"
+
+/** Simple declaration for u_strToTitle() to avoid including unicode/ubrk.h. */
+#ifndef UBRK_TYPEDEF_UBREAK_ITERATOR
+#   define UBRK_TYPEDEF_UBREAK_ITERATOR
+    typedef struct UBreakIterator UBreakIterator;
+#endif
+
+#ifndef U_COMPARE_IGNORE_CASE
+/* see also unorm.h */
+/**
+ * Option bit for unorm_compare:
+ * Perform case-insensitive comparison.
+ * @draft ICU 2.2
+ */
+#define U_COMPARE_IGNORE_CASE       0x10000
+#endif
+
+/**
+ * Internal option for unorm_cmpEquivFold() for strncmp style.
+ * If set, checks for both string length and terminating NUL.
+ * @internal
+ */
+#define _STRNCMP_STYLE 0x1000
+
+/**
+ * Compare two strings in code point order or code unit order.
+ * Works in strcmp style (both lengths -1),
+ * strncmp style (lengths equal and >=0, flag TRUE),
+ * and memcmp/UnicodeString style (at least one length >=0).
+ * @internal
+ */
+U_CFUNC int32_t U_EXPORT2
+uprv_strCompare(const UChar *s1, int32_t length1,
+                const UChar *s2, int32_t length2,
+                UBool strncmpStyle, UBool codePointOrder);
+
+/**
+ * Internal API, used by u_strcasecmp() etc.
+ * Compare strings case-insensitively,
+ * in code point order or code unit order.
+ * @internal
+ */
+U_CFUNC int32_t
+u_strcmpFold(const UChar *s1, int32_t length1,
+             const UChar *s2, int32_t length2,
+             uint32_t options,
+             UErrorCode *pErrorCode);
+
+/**
+ * Are the Unicode properties loaded?
+ * This must be used before internal functions are called that do
+ * not perform this check.
+ * Generate a debug assertion failure if data is not loaded.
+ * @internal
+ */
+U_CFUNC UBool
+uprv_haveProperties(UErrorCode *pErrorCode);
+
+/**
+  * Load the Unicode property data.
+  * Intended primarily for use from u_init().
+  * Has no effect if property data is already loaded.
+  * NOT thread safe.
+  * @internal
+  */
+/*U_CFUNC int8_t
+uprv_loadPropsData(UErrorCode *errorCode);*/
+
+/*
+ * Internal string casing functions implementing
+ * ustring.h/ustrcase.c and UnicodeString case mapping functions.
+ */
+
+/**
+ * @internal
+ */
+struct UCaseMap {
+    const UCaseProps *csp;
+#if !UCONFIG_NO_BREAK_ITERATION
+    UBreakIterator *iter;  /* We adopt the iterator, so we own it. */
+#endif
+    char locale[32];
+    int32_t locCache;
+    uint32_t options;
+};
+
+#ifndef __UCASEMAP_H__
+typedef struct UCaseMap UCaseMap;
+#endif
+
+/**
+ * @internal
+ */
+enum {
+    TO_LOWER,
+    TO_UPPER,
+    TO_TITLE,
+    FOLD_CASE
+};
+
+/**
+ * @internal
+ */
+U_CFUNC int32_t
+ustr_toLower(const UCaseProps *csp,
+             UChar *dest, int32_t destCapacity,
+             const UChar *src, int32_t srcLength,
+             const char *locale,
+             UErrorCode *pErrorCode);
+
+/**
+ * @internal
+ */
+U_CFUNC int32_t
+ustr_toUpper(const UCaseProps *csp,
+             UChar *dest, int32_t destCapacity,
+             const UChar *src, int32_t srcLength,
+             const char *locale,
+             UErrorCode *pErrorCode);
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+/**
+ * @internal
+ */
+U_CFUNC int32_t
+ustr_toTitle(const UCaseProps *csp,
+             UChar *dest, int32_t destCapacity,
+             const UChar *src, int32_t srcLength,
+             UBreakIterator *titleIter,
+             const char *locale, uint32_t options,
+             UErrorCode *pErrorCode);
+
+#endif
+
+/**
+ * Internal case folding function.
+ * @internal
+ */
+U_CFUNC int32_t
+ustr_foldCase(const UCaseProps *csp,
+              UChar *dest, int32_t destCapacity,
+              const UChar *src, int32_t srcLength,
+              uint32_t options,
+              UErrorCode *pErrorCode);
+
+/**
+ * NUL-terminate a UChar * string if possible.
+ * If length  < destCapacity then NUL-terminate.
+ * If length == destCapacity then do not terminate but set U_STRING_NOT_TERMINATED_WARNING.
+ * If length  > destCapacity then do not terminate but set U_BUFFER_OVERFLOW_ERROR.
+ *
+ * @param dest Destination buffer, can be NULL if destCapacity==0.
+ * @param destCapacity Number of UChars available at dest.
+ * @param length Number of UChars that were (to be) written to dest.
+ * @param pErrorCode ICU error code.
+ * @return length
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+u_terminateUChars(UChar *dest, int32_t destCapacity, int32_t length, UErrorCode *pErrorCode);
+
+/**
+ * NUL-terminate a char * string if possible.
+ * Same as u_terminateUChars() but for a different string type.
+ */
+U_CAPI int32_t U_EXPORT2
+u_terminateChars(char *dest, int32_t destCapacity, int32_t length, UErrorCode *pErrorCode);
+
+/**
+ * NUL-terminate a UChar32 * string if possible.
+ * Same as u_terminateUChars() but for a different string type.
+ */
+U_CAPI int32_t U_EXPORT2
+u_terminateUChar32s(UChar32 *dest, int32_t destCapacity, int32_t length, UErrorCode *pErrorCode);
+
+/**
+ * NUL-terminate a wchar_t * string if possible.
+ * Same as u_terminateUChars() but for a different string type.
+ */
+U_CAPI int32_t U_EXPORT2
+u_terminateWChars(wchar_t *dest, int32_t destCapacity, int32_t length, UErrorCode *pErrorCode);
+
+#endif
diff --git a/source/common/ustr_wcs.c b/source/common/ustr_wcs.c
new file mode 100644
index 0000000..9de5e22
--- /dev/null
+++ b/source/common/ustr_wcs.c
@@ -0,0 +1,526 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2001-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  ustr_wcs.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2004sep07
+*   created by: Markus W. Scherer
+*
+*   u_strToWCS() and u_strFromWCS() functions
+*   moved here from ustrtrns.c for better modularization.
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/ustring.h"
+#include "cstring.h"
+#include "cwchar.h"
+#include "cmemory.h"
+#include "ustr_imp.h"
+#include "ustr_cnv.h"
+
+#if defined(U_WCHAR_IS_UTF16) || defined(U_WCHAR_IS_UTF32) || !UCONFIG_NO_CONVERSION
+
+#define _STACK_BUFFER_CAPACITY 1000
+#define _BUFFER_CAPACITY_MULTIPLIER 2
+
+#if !defined(U_WCHAR_IS_UTF16) && !defined(U_WCHAR_IS_UTF32)
+static U_INLINE UBool 
+u_growAnyBufferFromStatic(void *context,
+                       void **pBuffer, int32_t *pCapacity, int32_t reqCapacity,
+                       int32_t length, int32_t size) {
+
+    void *newBuffer=uprv_malloc(reqCapacity*size);
+    if(newBuffer!=NULL) {
+        if(length>0) {
+            uprv_memcpy(newBuffer, *pBuffer, length*size);
+        }
+        *pCapacity=reqCapacity;
+    } else {
+        *pCapacity=0;
+    }
+
+    /* release the old pBuffer if it was not statically allocated */
+    if(*pBuffer!=(void *)context) {
+        uprv_free(*pBuffer);
+    }
+
+    *pBuffer=newBuffer;
+    return (UBool)(newBuffer!=NULL);
+}
+
+/* helper function */
+static wchar_t* 
+_strToWCS(wchar_t *dest, 
+           int32_t destCapacity,
+           int32_t *pDestLength,
+           const UChar *src, 
+           int32_t srcLength,
+           UErrorCode *pErrorCode){
+
+    char stackBuffer [_STACK_BUFFER_CAPACITY];
+    char* tempBuf = stackBuffer;
+    int32_t tempBufCapacity = _STACK_BUFFER_CAPACITY;
+    char* tempBufLimit = stackBuffer + tempBufCapacity;
+    UConverter* conv = NULL;
+    char* saveBuf = tempBuf;
+    wchar_t* intTarget=NULL;
+    int32_t intTargetCapacity=0;
+    int count=0,retVal=0;
+    
+    const UChar *pSrcLimit =NULL;
+    const UChar *pSrc = src;
+
+    conv = u_getDefaultConverter(pErrorCode);
+    
+    if(U_FAILURE(*pErrorCode)){
+        return NULL;
+    }
+    
+    if(srcLength == -1){
+        srcLength = u_strlen(pSrc);
+    }
+    
+    pSrcLimit = pSrc + srcLength;
+
+    for(;;) {
+        /* reset the error state */
+        *pErrorCode = U_ZERO_ERROR;
+
+        /* convert to chars using default converter */
+        ucnv_fromUnicode(conv,&tempBuf,tempBufLimit,&pSrc,pSrcLimit,NULL,(UBool)(pSrc==pSrcLimit),pErrorCode);
+        count =(tempBuf - saveBuf);
+        
+        /* This should rarely occur */
+        if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR){
+            tempBuf = saveBuf;
+            
+            /* we dont have enough room on the stack grow the buffer */
+            if(!u_growAnyBufferFromStatic(stackBuffer,(void**) &tempBuf, &tempBufCapacity, 
+                (_BUFFER_CAPACITY_MULTIPLIER * (srcLength)), count,sizeof(char))){
+                goto cleanup;
+            }
+          
+           saveBuf = tempBuf;
+           tempBufLimit = tempBuf + tempBufCapacity;
+           tempBuf = tempBuf + count;
+
+        } else {
+            break;
+        }
+    }
+
+    if(U_FAILURE(*pErrorCode)){
+        goto cleanup;
+    }
+
+    /* done with conversion null terminate the char buffer */
+    if(count>=tempBufCapacity){
+        tempBuf = saveBuf;
+        /* we dont have enough room on the stack grow the buffer */
+        if(!u_growAnyBufferFromStatic(stackBuffer,(void**) &tempBuf, &tempBufCapacity, 
+            tempBufCapacity-count+1, count,sizeof(char))){
+            goto cleanup;
+        }              
+       saveBuf = tempBuf;
+    }
+    
+    saveBuf[count]=0;
+      
+
+    /* allocate more space than required 
+     * here we assume that every char requires 
+     * no more than 2 wchar_ts
+     */
+    intTargetCapacity =  (count * _BUFFER_CAPACITY_MULTIPLIER + 1) /*for null termination */;
+    intTarget = (wchar_t*)uprv_malloc( intTargetCapacity * sizeof(wchar_t) );
+
+    if(intTarget){
+
+        int32_t nulLen = 0;
+        int32_t remaining = intTargetCapacity;
+        wchar_t* pIntTarget=intTarget;
+        tempBuf = saveBuf;
+        
+        /* now convert the mbs to wcs */
+        for(;;){
+            
+            /* we can call the system API since we are sure that
+             * there is atleast 1 null in the input
+             */
+            retVal = uprv_mbstowcs(pIntTarget,(tempBuf+nulLen),remaining);
+            
+            if(retVal==-1){
+                *pErrorCode = U_INVALID_CHAR_FOUND;
+                break;
+            }else if(retVal== remaining){/* should never occur */
+                int numWritten = (pIntTarget-intTarget);
+                u_growAnyBufferFromStatic(NULL,(void**) &intTarget,
+                                          &intTargetCapacity,
+                                          intTargetCapacity * _BUFFER_CAPACITY_MULTIPLIER,
+                                          numWritten,
+                                          sizeof(wchar_t));
+                pIntTarget = intTarget;
+                remaining=intTargetCapacity;
+
+                if(nulLen!=count){ /*there are embedded nulls*/
+                    pIntTarget+=numWritten;
+                    remaining-=numWritten;
+                }
+
+            }else{
+                int32_t nulVal;
+                /*scan for nulls */
+                /* we donot check for limit since tempBuf is null terminated */
+                while(tempBuf[nulLen++] != 0){
+                }
+                nulVal = (nulLen < srcLength) ? 1 : 0; 
+                pIntTarget = pIntTarget + retVal+nulVal;
+                remaining -=(retVal+nulVal);
+            
+                /* check if we have reached the source limit*/
+                if(nulLen>=(count)){
+                    break;
+                }
+            }
+        }
+        count = (int32_t)(pIntTarget-intTarget);
+       
+        if(0 < count && count <= destCapacity){
+            uprv_memcpy(dest,intTarget,count*sizeof(wchar_t));
+        }  
+
+        if(pDestLength){
+            *pDestLength = count;
+        }
+
+        /* free the allocated memory */
+        uprv_free(intTarget);
+
+    }else{
+        *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+    }
+cleanup:
+    /* are we still using stack buffer */
+    if(stackBuffer != saveBuf){
+        uprv_free(saveBuf);
+    }
+    u_terminateWChars(dest,destCapacity,count,pErrorCode);
+
+    u_releaseDefaultConverter(conv);
+
+    return dest;
+}
+#endif
+
+U_CAPI wchar_t* U_EXPORT2
+u_strToWCS(wchar_t *dest, 
+           int32_t destCapacity,
+           int32_t *pDestLength,
+           const UChar *src, 
+           int32_t srcLength,
+           UErrorCode *pErrorCode){
+
+    /* args check */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)){
+        return NULL;
+    }
+        
+    if( (src==NULL && srcLength!=0) || srcLength < -1 ||
+        (destCapacity<0) || (dest == NULL && destCapacity > 0)
+    ) {
+        *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+    
+#ifdef U_WCHAR_IS_UTF16
+    /* wchar_t is UTF-16 just do a memcpy */
+    if(srcLength == -1){
+        srcLength = u_strlen(src);
+    }
+    if(0 < srcLength && srcLength <= destCapacity){
+        uprv_memcpy(dest,src,srcLength*U_SIZEOF_UCHAR);
+    }
+    if(pDestLength){
+       *pDestLength = srcLength;
+    }
+
+    u_terminateUChars(dest,destCapacity,srcLength,pErrorCode);
+
+    return dest;
+
+#elif defined U_WCHAR_IS_UTF32
+    
+    return (wchar_t*)u_strToUTF32((UChar32*)dest, destCapacity, pDestLength,
+                                  src, srcLength, pErrorCode);
+
+#else
+    
+    return _strToWCS(dest,destCapacity,pDestLength,src,srcLength, pErrorCode);
+    
+#endif
+
+}
+
+#if !defined(U_WCHAR_IS_UTF16) && !defined(U_WCHAR_IS_UTF32)
+/* helper function */
+static UChar* 
+_strFromWCS( UChar   *dest,
+             int32_t destCapacity, 
+             int32_t *pDestLength,
+             const wchar_t *src,
+             int32_t srcLength,
+             UErrorCode *pErrorCode)
+{
+    int32_t retVal =0, count =0 ;
+    UConverter* conv = NULL;
+    UChar* pTarget = NULL;
+    UChar* pTargetLimit = NULL;
+    UChar* target = NULL;
+    
+    UChar uStack [_STACK_BUFFER_CAPACITY];
+
+    wchar_t wStack[_STACK_BUFFER_CAPACITY];
+    wchar_t* pWStack = wStack;
+
+
+    char cStack[_STACK_BUFFER_CAPACITY];
+    int32_t cStackCap = _STACK_BUFFER_CAPACITY;
+    char* pCSrc=cStack;
+    char* pCSave=pCSrc;
+    char* pCSrcLimit=NULL;
+
+    const wchar_t* pSrc = src;
+    const wchar_t* pSrcLimit = NULL;
+
+    if(srcLength ==-1){
+        /* if the wchar_t source is null terminated we can safely
+         * assume that there are no embedded nulls, this is a fast
+         * path for null terminated strings.
+         */
+        for(;;){
+            /* convert wchars  to chars */
+            retVal = uprv_wcstombs(pCSrc,src, cStackCap);
+    
+            if(retVal == -1){
+                *pErrorCode = U_ILLEGAL_CHAR_FOUND;
+                goto cleanup;
+            }else if(retVal >= (cStackCap-1)){
+                /* Should rarely occur */
+                u_growAnyBufferFromStatic(cStack,(void**)&pCSrc,&cStackCap,
+                    cStackCap * _BUFFER_CAPACITY_MULTIPLIER, 0, sizeof(char));
+                pCSave = pCSrc;
+            }else{
+                /* converted every thing */
+                pCSrc = pCSrc+retVal;
+                break;
+            }
+        }
+        
+    }else{
+        /* here the source is not null terminated 
+         * so it may have nulls embeded and we need to
+         * do some extra processing 
+         */
+        int32_t remaining =cStackCap;
+        
+        pSrcLimit = src + srcLength;
+
+        for(;;){
+            register int32_t nulLen = 0;
+
+            /* find nulls in the string */
+            while(nulLen<srcLength && pSrc[nulLen++]!=0){
+            }
+
+            if((pSrc+nulLen) < pSrcLimit){
+                /* check if we have enough room in pCSrc */
+                if(remaining < (nulLen * MB_CUR_MAX)){
+                    /* should rarely occur */
+                    int32_t len = (pCSrc-pCSave);
+                    pCSrc = pCSave;
+                    /* we do not have enough room so grow the buffer*/
+                    u_growAnyBufferFromStatic(cStack,(void**)&pCSrc,&cStackCap,
+                           _BUFFER_CAPACITY_MULTIPLIER*cStackCap+(nulLen*MB_CUR_MAX),len,sizeof(char));
+
+                    pCSave = pCSrc;
+                    pCSrc = pCSave+len;
+                    remaining = cStackCap-(pCSrc - pCSave);
+                }
+
+                /* we have found a null  so convert the 
+                 * chunk from begining of non-null char to null
+                 */
+                retVal = uprv_wcstombs(pCSrc,pSrc,remaining);
+
+                if(retVal==-1){
+                    /* an error occurred bail out */
+                    *pErrorCode = U_ILLEGAL_CHAR_FOUND;
+                    goto cleanup;
+                }
+
+                pCSrc += retVal+1 /* already null terminated */;
+
+                pSrc += nulLen; /* skip past the null */
+                srcLength-=nulLen; /* decrement the srcLength */
+                remaining -= (pCSrc-pCSave);
+
+
+            }else{
+                /* the source is not null terminated and we are 
+                 * end of source so we copy the source to a temp buffer
+                 * null terminate it and convert wchar_ts to chars
+                 */
+                if(nulLen >= _STACK_BUFFER_CAPACITY){
+                    /* Should rarely occcur */
+                    /* allocate new buffer buffer */
+                    pWStack =(wchar_t*) uprv_malloc(sizeof(wchar_t) * (nulLen + 1));
+                    if(pWStack==NULL){
+                        *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+                        goto cleanup;
+                    }
+                }
+                if(nulLen>0){
+                    /* copy the contents to tempStack */
+                    uprv_memcpy(pWStack,pSrc,nulLen*sizeof(wchar_t));
+                }
+            
+                /* null terminate the tempBuffer */
+                pWStack[nulLen] =0 ;
+            
+                if(remaining < (nulLen * MB_CUR_MAX)){
+                    /* Should rarely occur */
+                    int32_t len = (pCSrc-pCSave);
+                    pCSrc = pCSave;
+                    /* we do not have enough room so grow the buffer*/
+                    u_growAnyBufferFromStatic(cStack,(void**)&pCSrc,&cStackCap,
+                           cStackCap+(nulLen*MB_CUR_MAX),len,sizeof(char));
+
+                    pCSave = pCSrc;
+                    pCSrc = pCSave+len;
+                    remaining = cStackCap-(pCSrc - pCSave);
+                }
+                /* convert to chars */
+                retVal = uprv_wcstombs(pCSrc,pWStack,remaining);
+            
+                pCSrc += retVal;
+                pSrc  += nulLen;
+                srcLength-=nulLen; /* decrement the srcLength */
+                break;
+            }
+        }
+    }
+
+    /* OK..now we have converted from wchar_ts to chars now 
+     * convert chars to UChars 
+     */
+    pCSrcLimit = pCSrc;
+    pCSrc = pCSave;
+    pTarget = target= dest;
+    pTargetLimit = dest + destCapacity;    
+    
+    conv= u_getDefaultConverter(pErrorCode);
+    
+    if(U_FAILURE(*pErrorCode)|| conv==NULL){
+        goto cleanup;
+    }
+    
+    for(;;) {
+        
+        *pErrorCode = U_ZERO_ERROR;
+        
+        /* convert to stack buffer*/
+        ucnv_toUnicode(conv,&pTarget,pTargetLimit,(const char**)&pCSrc,pCSrcLimit,NULL,(UBool)(pCSrc==pCSrcLimit),pErrorCode);
+        
+        /* increment count to number written to stack */
+        count+= pTarget - target;
+        
+        if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR){
+            target = uStack;
+            pTarget = uStack;
+            pTargetLimit = uStack + _STACK_BUFFER_CAPACITY;
+        } else {
+            break;
+        }
+        
+    }
+    
+    if(pDestLength){
+        *pDestLength =count;
+    }
+
+    u_terminateUChars(dest,destCapacity,count,pErrorCode);
+    
+cleanup:
+ 
+    if(cStack != pCSave){
+        uprv_free(pCSave);
+    }
+
+    if(wStack != pWStack){
+        uprv_free(pWStack);
+    }
+    
+    u_releaseDefaultConverter(conv);
+
+    return dest;
+}
+#endif
+
+U_CAPI UChar* U_EXPORT2
+u_strFromWCS(UChar   *dest,
+             int32_t destCapacity, 
+             int32_t *pDestLength,
+             const wchar_t *src,
+             int32_t srcLength,
+             UErrorCode *pErrorCode)
+{
+
+    /* args check */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)){
+        return NULL;
+    }
+
+    if( (src==NULL && srcLength!=0) || srcLength < -1 ||
+        (destCapacity<0) || (dest == NULL && destCapacity > 0)
+    ) {
+        *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+#ifdef U_WCHAR_IS_UTF16
+    /* wchar_t is UTF-16 just do a memcpy */
+    if(srcLength == -1){
+        srcLength = u_strlen(src);
+    }
+    if(0 < srcLength && srcLength <= destCapacity){
+        uprv_memcpy(dest,src,srcLength*U_SIZEOF_UCHAR);
+    }
+    if(pDestLength){
+       *pDestLength = srcLength;
+    }
+
+    u_terminateUChars(dest,destCapacity,srcLength,pErrorCode);
+
+    return dest;
+
+#elif defined U_WCHAR_IS_UTF32
+    
+    return u_strFromUTF32(dest, destCapacity, pDestLength,
+                          (UChar32*)src, srcLength, pErrorCode);
+
+#else
+
+    return _strFromWCS(dest,destCapacity,pDestLength,src,srcLength,pErrorCode);  
+
+#endif
+
+}
+
+#endif /* #if !defined(U_WCHAR_IS_UTF16) && !defined(U_WCHAR_IS_UTF32) && !UCONFIG_NO_CONVERSION */
diff --git a/source/common/ustrcase.c b/source/common/ustrcase.c
new file mode 100644
index 0000000..4b62fb9
--- /dev/null
+++ b/source/common/ustrcase.c
@@ -0,0 +1,987 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2001-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  ustrcase.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2002feb20
+*   created by: Markus W. Scherer
+*
+*   Implementation file for string casing C API functions.
+*   Uses functions from uchar.c for basic functionality that requires access
+*   to the Unicode Character Database (uprops.dat).
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uloc.h"
+#include "unicode/ustring.h"
+#include "unicode/ucasemap.h"
+#include "unicode/ubrk.h"
+#include "cmemory.h"
+#include "ucase.h"
+#include "ustr_imp.h"
+
+/* string casing ------------------------------------------------------------ */
+
+/* append a full case mapping result, see UCASE_MAX_STRING_LENGTH */
+static U_INLINE int32_t
+appendResult(UChar *dest, int32_t destIndex, int32_t destCapacity,
+             int32_t result, const UChar *s) {
+    UChar32 c;
+    int32_t length;
+
+    /* decode the result */
+    if(result<0) {
+        /* (not) original code point */
+        c=~result;
+        length=-1;
+    } else if(result<=UCASE_MAX_STRING_LENGTH) {
+        c=U_SENTINEL;
+        length=result;
+    } else {
+        c=result;
+        length=-1;
+    }
+
+    if(destIndex<destCapacity) {
+        /* append the result */
+        if(length<0) {
+            /* code point */
+            UBool isError=FALSE;
+            U16_APPEND(dest, destIndex, destCapacity, c, isError);
+            if(isError) {
+                /* overflow, nothing written */
+                destIndex+=U16_LENGTH(c);
+            }
+        } else {
+            /* string */
+            if((destIndex+length)<=destCapacity) {
+                while(length>0) {
+                    dest[destIndex++]=*s++;
+                    --length;
+                }
+            } else {
+                /* overflow */
+                destIndex+=length;
+            }
+        }
+    } else {
+        /* preflight */
+        if(length<0) {
+            destIndex+=U16_LENGTH(c);
+        } else {
+            destIndex+=length;
+        }
+    }
+    return destIndex;
+}
+
+static UChar32 U_CALLCONV
+utf16_caseContextIterator(void *context, int8_t dir) {
+    UCaseContext *csc=(UCaseContext *)context;
+    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;
+    }
+
+    if(dir<0) {
+        if(csc->start<csc->index) {
+            U16_PREV((const UChar *)csc->p, csc->start, csc->index, c);
+            return c;
+        }
+    } else {
+        if(csc->index<csc->limit) {
+            U16_NEXT((const UChar *)csc->p, csc->index, csc->limit, c);
+            return c;
+        }
+    }
+    return U_SENTINEL;
+}
+
+/*
+ * Case-maps [srcStart..srcLimit[ but takes
+ * context [0..srcLength[ into account.
+ */
+static int32_t
+_caseMap(const UCaseMap *csm, UCaseMapFull *map,
+         UChar *dest, int32_t destCapacity,
+         const UChar *src, UCaseContext *csc,
+         int32_t srcStart, int32_t srcLimit,
+         UErrorCode *pErrorCode) {
+    const UChar *s;
+    UChar32 c, c2 = 0;
+    int32_t srcIndex, destIndex;
+    int32_t locCache;
+
+    locCache=csm->locCache;
+
+    /* case mapping loop */
+    srcIndex=srcStart;
+    destIndex=0;
+    while(srcIndex<srcLimit) {
+        csc->cpStart=srcIndex;
+        U16_NEXT(src, srcIndex, srcLimit, c);
+        csc->cpLimit=srcIndex;
+        c=map(csm->csp, c, utf16_caseContextIterator, csc, &s, csm->locale, &locCache);
+        if((destIndex<destCapacity) && (c<0 ? (c2=~c)<=0xffff : UCASE_MAX_STRING_LENGTH<c && (c2=c)<=0xffff)) {
+            /* fast path version of appendResult() for BMP results */
+            dest[destIndex++]=(UChar)c2;
+        } else {
+            destIndex=appendResult(dest, destIndex, destCapacity, c, s);
+        }
+    }
+
+    if(destIndex>destCapacity) {
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+    return destIndex;
+}
+
+static void
+setTempCaseMapLocale(UCaseMap *csm, const char *locale, UErrorCode *pErrorCode) {
+    /*
+     * We could call ucasemap_setLocale(), but here we really only care about
+     * the initial language subtag, we need not return the real string via
+     * ucasemap_getLocale(), and we don't care about only getting "x" from
+     * "x-some-thing" etc.
+     *
+     * We ignore locales with a longer-than-3 initial subtag.
+     *
+     * We also do not fill in the locCache because it is rarely used,
+     * and not worth setting unless we reuse it for many case mapping operations.
+     * (That's why UCaseMap was created.)
+     */
+    int i;
+    char c;
+
+    /* the internal functions require locale!=NULL */
+    if(locale==NULL) {
+        locale=uloc_getDefault();
+    }
+    for(i=0; i<4 && (c=locale[i])!=0 && c!='-' && c!='_'; ++i) {
+        csm->locale[i]=c;
+    }
+    if(i<=3) {
+        csm->locale[i]=0;  /* Up to 3 non-separator characters. */
+    } else {
+        csm->locale[0]=0;  /* Longer-than-3 initial subtag: Ignore. */
+    }
+}
+
+/*
+ * Set parameters on an empty UCaseMap, for UCaseMap-less API functions.
+ * Do this fast because it is called with every function call.
+ */
+static U_INLINE void
+setTempCaseMap(UCaseMap *csm, const char *locale, UErrorCode *pErrorCode) {
+    if(csm->csp==NULL) {
+        csm->csp=ucase_getSingleton();
+    }
+    if(locale!=NULL && locale[0]==0) {
+        csm->locale[0]=0;
+    } else {
+        setTempCaseMapLocale(csm, locale, pErrorCode);
+    }
+}
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+/*
+ * Internal titlecasing function.
+ */
+static int32_t
+_toTitle(UCaseMap *csm,
+         UChar *dest, int32_t destCapacity,
+         const UChar *src, UCaseContext *csc,
+         int32_t srcLength,
+         UErrorCode *pErrorCode) {
+    const UChar *s;
+    UChar32 c;
+    int32_t prev, titleStart, titleLimit, idx, destIndex, length;
+    UBool isFirstIndex;
+
+    if(csm->iter!=NULL) {
+        ubrk_setText(csm->iter, src, srcLength, pErrorCode);
+    } else {
+        csm->iter=ubrk_open(UBRK_WORD, csm->locale,
+                            src, srcLength,
+                            pErrorCode);
+    }
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    /* set up local variables */
+    destIndex=0;
+    prev=0;
+    isFirstIndex=TRUE;
+
+    /* titlecasing loop */
+    while(prev<srcLength) {
+        /* find next index where to titlecase */
+        if(isFirstIndex) {
+            isFirstIndex=FALSE;
+            idx=ubrk_first(csm->iter);
+        } else {
+            idx=ubrk_next(csm->iter);
+        }
+        if(idx==UBRK_DONE || idx>srcLength) {
+            idx=srcLength;
+        }
+
+        /*
+         * Unicode 4 & 5 section 3.13 Default Case Operations:
+         *
+         * R3  toTitlecase(X): Find the word boundaries based on Unicode Standard Annex
+         * #29, "Text Boundaries." Between each pair of word boundaries, find the first
+         * cased character F. If F exists, map F to default_title(F); then map each
+         * subsequent character C to default_lower(C).
+         *
+         * In this implementation, segment [prev..index[ into 3 parts:
+         * a) uncased characters (copy as-is) [prev..titleStart[
+         * b) first case letter (titlecase)         [titleStart..titleLimit[
+         * c) subsequent characters (lowercase)                 [titleLimit..index[
+         */
+        if(prev<idx) {
+            /* find and copy uncased characters [prev..titleStart[ */
+            titleStart=titleLimit=prev;
+            U16_NEXT(src, titleLimit, idx, c);
+            if((csm->options&U_TITLECASE_NO_BREAK_ADJUSTMENT)==0 && UCASE_NONE==ucase_getType(csm->csp, c)) {
+                /* Adjust the titlecasing index (titleStart) to the next cased character. */
+                for(;;) {
+                    titleStart=titleLimit;
+                    if(titleLimit==idx) {
+                        /*
+                         * only uncased characters in [prev..index[
+                         * stop with titleStart==titleLimit==index
+                         */
+                        break;
+                    }
+                    U16_NEXT(src, titleLimit, idx, c);
+                    if(UCASE_NONE!=ucase_getType(csm->csp, c)) {
+                        break; /* cased letter at [titleStart..titleLimit[ */
+                    }
+                }
+                length=titleStart-prev;
+                if(length>0) {
+                    if((destIndex+length)<=destCapacity) {
+                        uprv_memcpy(dest+destIndex, src+prev, length*U_SIZEOF_UCHAR);
+                    }
+                    destIndex+=length;
+                }
+            }
+
+            if(titleStart<titleLimit) {
+                /* titlecase c which is from [titleStart..titleLimit[ */
+                csc->cpStart=titleStart;
+                csc->cpLimit=titleLimit;
+                c=ucase_toFullTitle(csm->csp, c, utf16_caseContextIterator, csc, &s, csm->locale, &csm->locCache);
+                destIndex=appendResult(dest, destIndex, destCapacity, c, s); 
+
+                /* Special case Dutch IJ titlecasing */
+                if ( titleStart+1 < idx && 
+                     ucase_getCaseLocale(csm->locale,&csm->locCache) == UCASE_LOC_DUTCH &&
+                     ( src[titleStart] == (UChar32) 0x0049 || src[titleStart] == (UChar32) 0x0069 ) &&
+                     ( src[titleStart+1] == (UChar32) 0x004A || src[titleStart+1] == (UChar32) 0x006A )) { 
+                            c=(UChar32) 0x004A;
+                            destIndex=appendResult(dest, destIndex, destCapacity, c, s);
+                            titleLimit++;
+                }
+
+                /* lowercase [titleLimit..index[ */
+                if(titleLimit<idx) {
+                    if((csm->options&U_TITLECASE_NO_LOWERCASE)==0) {
+                        /* Normal operation: Lowercase the rest of the word. */
+                        destIndex+=
+                            _caseMap(
+                                csm, ucase_toFullLower,
+                                dest+destIndex, destCapacity-destIndex,
+                                src, csc,
+                                titleLimit, idx,
+                                pErrorCode);
+                    } else {
+                        /* Optionally just copy the rest of the word unchanged. */
+                        length=idx-titleLimit;
+                        if((destIndex+length)<=destCapacity) {
+                            uprv_memcpy(dest+destIndex, src+titleLimit, length*U_SIZEOF_UCHAR);
+                        }
+                        destIndex+=length;
+                    }
+                }
+            }
+        }
+
+        prev=idx;
+    }
+
+    if(destIndex>destCapacity) {
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+    return destIndex;
+}
+
+#endif
+
+/* functions available in the common library (for unistr_case.cpp) */
+
+U_CFUNC int32_t
+ustr_toLower(const UCaseProps *csp,
+             UChar *dest, int32_t destCapacity,
+             const UChar *src, int32_t srcLength,
+             const char *locale,
+             UErrorCode *pErrorCode) {
+    UCaseMap csm={ NULL };
+    UCaseContext csc={ NULL };
+
+    csm.csp=csp;
+    setTempCaseMap(&csm, locale, pErrorCode);
+    csc.p=(void *)src;
+    csc.limit=srcLength;
+
+    return _caseMap(&csm, ucase_toFullLower,
+                    dest, destCapacity,
+                    src, &csc, 0, srcLength,
+                    pErrorCode);
+}
+
+U_CFUNC int32_t
+ustr_toUpper(const UCaseProps *csp,
+             UChar *dest, int32_t destCapacity,
+             const UChar *src, int32_t srcLength,
+             const char *locale,
+             UErrorCode *pErrorCode) {
+    UCaseMap csm={ NULL };
+    UCaseContext csc={ NULL };
+
+    csm.csp=csp;
+    setTempCaseMap(&csm, locale, pErrorCode);
+    csc.p=(void *)src;
+    csc.limit=srcLength;
+
+    return _caseMap(&csm, ucase_toFullUpper,
+                    dest, destCapacity,
+                    src, &csc, 0, srcLength,
+                    pErrorCode);
+}
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+U_CFUNC int32_t
+ustr_toTitle(const UCaseProps *csp,
+             UChar *dest, int32_t destCapacity,
+             const UChar *src, int32_t srcLength,
+             UBreakIterator *titleIter,
+             const char *locale, uint32_t options,
+             UErrorCode *pErrorCode) {
+    UCaseMap csm={ NULL };
+    UCaseContext csc={ NULL };
+    int32_t length;
+
+    csm.csp=csp;
+    csm.iter=titleIter;
+    csm.options=options;
+    setTempCaseMap(&csm, locale, pErrorCode);
+    csc.p=(void *)src;
+    csc.limit=srcLength;
+
+    length=_toTitle(&csm,
+                    dest, destCapacity,
+                    src, &csc, srcLength,
+                    pErrorCode);
+    if(titleIter==NULL && csm.iter!=NULL) {
+        ubrk_close(csm.iter);
+    }
+    return length;
+}
+
+#endif
+
+U_CFUNC int32_t
+ustr_foldCase(const UCaseProps *csp,
+              UChar *dest, int32_t destCapacity,
+              const UChar *src, int32_t srcLength,
+              uint32_t options,
+              UErrorCode *pErrorCode) {
+    int32_t srcIndex, destIndex;
+
+    const UChar *s;
+    UChar32 c, c2 = 0;
+
+    /* case mapping loop */
+    srcIndex=destIndex=0;
+    while(srcIndex<srcLength) {
+        U16_NEXT(src, srcIndex, srcLength, c);
+        c=ucase_toFullFolding(csp, c, &s, options);
+        if((destIndex<destCapacity) && (c<0 ? (c2=~c)<=0xffff : UCASE_MAX_STRING_LENGTH<c && (c2=c)<=0xffff)) {
+            /* fast path version of appendResult() for BMP results */
+            dest[destIndex++]=(UChar)c2;
+        } else {
+            destIndex=appendResult(dest, destIndex, destCapacity, c, s);
+        }
+    }
+
+    if(destIndex>destCapacity) {
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+    return destIndex;
+}
+
+/*
+ * Implement argument checking and buffer handling
+ * for string case mapping as a common function.
+ */
+
+/* common internal function for public API functions */
+
+static int32_t
+caseMap(const UCaseMap *csm,
+        UChar *dest, int32_t destCapacity,
+        const UChar *src, int32_t srcLength,
+        int32_t toWhichCase,
+        UErrorCode *pErrorCode) {
+    UChar buffer[300];
+    UChar *temp;
+
+    int32_t destLength;
+
+    /* check argument values */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if( destCapacity<0 ||
+        (dest==NULL && destCapacity>0) ||
+        src==NULL ||
+        srcLength<-1
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* get the string length */
+    if(srcLength==-1) {
+        srcLength=u_strlen(src);
+    }
+
+    /* check for overlapping source and destination */
+    if( dest!=NULL &&
+        ((src>=dest && src<(dest+destCapacity)) ||
+         (dest>=src && dest<(src+srcLength)))
+    ) {
+        /* overlap: provide a temporary destination buffer and later copy the result */
+        if(destCapacity<=(sizeof(buffer)/U_SIZEOF_UCHAR)) {
+            /* the stack buffer is large enough */
+            temp=buffer;
+        } else {
+            /* allocate a buffer */
+            temp=(UChar *)uprv_malloc(destCapacity*U_SIZEOF_UCHAR);
+            if(temp==NULL) {
+                *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+                return 0;
+            }
+        }
+    } else {
+        temp=dest;
+    }
+
+    destLength=0;
+
+    if(toWhichCase==FOLD_CASE) {
+        destLength=ustr_foldCase(csm->csp, temp, destCapacity, src, srcLength,
+                                 csm->options, pErrorCode);
+    } else {
+        UCaseContext csc={ NULL };
+
+        csc.p=(void *)src;
+        csc.limit=srcLength;
+
+        if(toWhichCase==TO_LOWER) {
+            destLength=_caseMap(csm, ucase_toFullLower,
+                                temp, destCapacity,
+                                src, &csc,
+                                0, srcLength,
+                                pErrorCode);
+        } else if(toWhichCase==TO_UPPER) {
+            destLength=_caseMap(csm, ucase_toFullUpper,
+                                temp, destCapacity,
+                                src, &csc,
+                                0, srcLength,
+                                pErrorCode);
+        } else /* if(toWhichCase==TO_TITLE) */ {
+#if UCONFIG_NO_BREAK_ITERATION
+            *pErrorCode=U_UNSUPPORTED_ERROR;
+#else
+            /* UCaseMap is actually non-const in toTitle() APIs. */
+            destLength=_toTitle((UCaseMap *)csm, temp, destCapacity,
+                                src, &csc, srcLength,
+                                pErrorCode);
+#endif
+        }
+    }
+    if(temp!=dest) {
+        /* copy the result string to the destination buffer */
+        if(destLength>0) {
+            int32_t copyLength= destLength<=destCapacity ? destLength : destCapacity;
+            if(copyLength>0) {
+                uprv_memmove(dest, temp, copyLength*U_SIZEOF_UCHAR);
+            }
+        }
+        if(temp!=buffer) {
+            uprv_free(temp);
+        }
+    }
+
+    return u_terminateUChars(dest, destCapacity, destLength, pErrorCode);
+}
+
+/* public API functions */
+
+U_CAPI int32_t U_EXPORT2
+u_strToLower(UChar *dest, int32_t destCapacity,
+             const UChar *src, int32_t srcLength,
+             const char *locale,
+             UErrorCode *pErrorCode) {
+    UCaseMap csm={ NULL };
+    setTempCaseMap(&csm, locale, pErrorCode);
+    return caseMap(&csm,
+                   dest, destCapacity,
+                   src, srcLength,
+                   TO_LOWER, pErrorCode);
+}
+
+U_CAPI int32_t U_EXPORT2
+u_strToUpper(UChar *dest, int32_t destCapacity,
+             const UChar *src, int32_t srcLength,
+             const char *locale,
+             UErrorCode *pErrorCode) {
+    UCaseMap csm={ NULL };
+    setTempCaseMap(&csm, locale, pErrorCode);
+    return caseMap(&csm,
+                   dest, destCapacity,
+                   src, srcLength,
+                   TO_UPPER, pErrorCode);
+}
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+U_CAPI int32_t U_EXPORT2
+u_strToTitle(UChar *dest, int32_t destCapacity,
+             const UChar *src, int32_t srcLength,
+             UBreakIterator *titleIter,
+             const char *locale,
+             UErrorCode *pErrorCode) {
+    UCaseMap csm={ NULL };
+    int32_t length;
+
+    csm.iter=titleIter;
+    setTempCaseMap(&csm, locale, pErrorCode);
+    length=caseMap(&csm,
+                   dest, destCapacity,
+                   src, srcLength,
+                   TO_TITLE, pErrorCode);
+    if(titleIter==NULL && csm.iter!=NULL) {
+        ubrk_close(csm.iter);
+    }
+    return length;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucasemap_toTitle(UCaseMap *csm,
+                 UChar *dest, int32_t destCapacity,
+                 const UChar *src, int32_t srcLength,
+                 UErrorCode *pErrorCode) {
+    return caseMap(csm,
+                   dest, destCapacity,
+                   src, srcLength,
+                   TO_TITLE, pErrorCode);
+}
+
+#endif
+
+U_CAPI int32_t U_EXPORT2
+u_strFoldCase(UChar *dest, int32_t destCapacity,
+              const UChar *src, int32_t srcLength,
+              uint32_t options,
+              UErrorCode *pErrorCode) {
+    UCaseMap csm={ NULL };
+    csm.csp=ucase_getSingleton();
+    csm.options=options;
+    return caseMap(&csm,
+                   dest, destCapacity,
+                   src, srcLength,
+                   FOLD_CASE, pErrorCode);
+}
+
+/* case-insensitive string comparisons -------------------------------------- */
+
+/*
+ * This function is a copy of unorm_cmpEquivFold() minus the parts for
+ * canonical equivalence.
+ * Keep the functions in sync, and see there for how this works.
+ * The duplication is for modularization:
+ * It makes caseless (but not canonical caseless) matches independent of
+ * the normalization code.
+ */
+
+/* stack element for previous-level source/decomposition pointers */
+struct CmpEquivLevel {
+    const UChar *start, *s, *limit;
+};
+typedef struct CmpEquivLevel CmpEquivLevel;
+
+/* internal function */
+U_CFUNC int32_t
+u_strcmpFold(const UChar *s1, int32_t length1,
+             const UChar *s2, int32_t length2,
+             uint32_t options,
+             UErrorCode *pErrorCode) {
+    const UCaseProps *csp;
+
+    /* current-level start/limit - s1/s2 as current */
+    const UChar *start1, *start2, *limit1, *limit2;
+
+    /* case folding variables */
+    const UChar *p;
+    int32_t length;
+
+    /* stacks of previous-level start/current/limit */
+    CmpEquivLevel stack1[2], stack2[2];
+
+    /* case folding buffers, only use current-level start/limit */
+    UChar fold1[UCASE_MAX_STRING_LENGTH+1], fold2[UCASE_MAX_STRING_LENGTH+1];
+
+    /* track which is the current level per string */
+    int32_t level1, level2;
+
+    /* current code units, and code points for lookups */
+    UChar32 c1, c2, cp1, cp2;
+
+    /* no argument error checking because this itself is not an API */
+
+    /*
+     * assume that at least the option U_COMPARE_IGNORE_CASE is set
+     * otherwise this function would have to behave exactly as uprv_strCompare()
+     */
+    csp=ucase_getSingleton();
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    /* initialize */
+    start1=s1;
+    if(length1==-1) {
+        limit1=NULL;
+    } else {
+        limit1=s1+length1;
+    }
+
+    start2=s2;
+    if(length2==-1) {
+        limit2=NULL;
+    } else {
+        limit2=s2+length2;
+    }
+
+    level1=level2=0;
+    c1=c2=-1;
+
+    /* comparison loop */
+    for(;;) {
+        /*
+         * here a code unit value of -1 means "get another code unit"
+         * below it will mean "this source is finished"
+         */
+
+        if(c1<0) {
+            /* get next code unit from string 1, post-increment */
+            for(;;) {
+                if(s1==limit1 || ((c1=*s1)==0 && (limit1==NULL || (options&_STRNCMP_STYLE)))) {
+                    if(level1==0) {
+                        c1=-1;
+                        break;
+                    }
+                } else {
+                    ++s1;
+                    break;
+                }
+
+                /* reached end of level buffer, pop one level */
+                do {
+                    --level1;
+                    start1=stack1[level1].start;
+                } while(start1==NULL);
+                s1=stack1[level1].s;
+                limit1=stack1[level1].limit;
+            }
+        }
+
+        if(c2<0) {
+            /* get next code unit from string 2, post-increment */
+            for(;;) {
+                if(s2==limit2 || ((c2=*s2)==0 && (limit2==NULL || (options&_STRNCMP_STYLE)))) {
+                    if(level2==0) {
+                        c2=-1;
+                        break;
+                    }
+                } else {
+                    ++s2;
+                    break;
+                }
+
+                /* reached end of level buffer, pop one level */
+                do {
+                    --level2;
+                    start2=stack2[level2].start;
+                } while(start2==NULL);
+                s2=stack2[level2].s;
+                limit2=stack2[level2].limit;
+            }
+        }
+
+        /*
+         * compare c1 and c2
+         * either variable c1, c2 is -1 only if the corresponding string is finished
+         */
+        if(c1==c2) {
+            if(c1<0) {
+                return 0;   /* c1==c2==-1 indicating end of strings */
+            }
+            c1=c2=-1;       /* make us fetch new code units */
+            continue;
+        } else if(c1<0) {
+            return -1;      /* string 1 ends before string 2 */
+        } else if(c2<0) {
+            return 1;       /* string 2 ends before string 1 */
+        }
+        /* c1!=c2 && c1>=0 && c2>=0 */
+
+        /* get complete code points for c1, c2 for lookups if either is a surrogate */
+        cp1=c1;
+        if(U_IS_SURROGATE(c1)) {
+            UChar c;
+
+            if(U_IS_SURROGATE_LEAD(c1)) {
+                if(s1!=limit1 && U16_IS_TRAIL(c=*s1)) {
+                    /* advance ++s1; only below if cp1 decomposes/case-folds */
+                    cp1=U16_GET_SUPPLEMENTARY(c1, c);
+                }
+            } else /* isTrail(c1) */ {
+                if(start1<=(s1-2) && U16_IS_LEAD(c=*(s1-2))) {
+                    cp1=U16_GET_SUPPLEMENTARY(c, c1);
+                }
+            }
+        }
+
+        cp2=c2;
+        if(U_IS_SURROGATE(c2)) {
+            UChar c;
+
+            if(U_IS_SURROGATE_LEAD(c2)) {
+                if(s2!=limit2 && U16_IS_TRAIL(c=*s2)) {
+                    /* advance ++s2; only below if cp2 decomposes/case-folds */
+                    cp2=U16_GET_SUPPLEMENTARY(c2, c);
+                }
+            } else /* isTrail(c2) */ {
+                if(start2<=(s2-2) && U16_IS_LEAD(c=*(s2-2))) {
+                    cp2=U16_GET_SUPPLEMENTARY(c, c2);
+                }
+            }
+        }
+
+        /*
+         * go down one level for each string
+         * continue with the main loop as soon as there is a real change
+         */
+
+        if( level1==0 &&
+            (length=ucase_toFullFolding(csp, (UChar32)cp1, &p, options))>=0
+        ) {
+            /* cp1 case-folds to the code point "length" or to p[length] */
+            if(U_IS_SURROGATE(c1)) {
+                if(U_IS_SURROGATE_LEAD(c1)) {
+                    /* advance beyond source surrogate pair if it case-folds */
+                    ++s1;
+                } else /* isTrail(c1) */ {
+                    /*
+                     * we got a supplementary code point when hitting its trail surrogate,
+                     * therefore the lead surrogate must have been the same as in the other string;
+                     * compare this decomposition with the lead surrogate in the other string
+                     * remember that this simulates bulk text replacement:
+                     * the decomposition would replace the entire code point
+                     */
+                    --s2;
+                    c2=*(s2-1);
+                }
+            }
+
+            /* push current level pointers */
+            stack1[0].start=start1;
+            stack1[0].s=s1;
+            stack1[0].limit=limit1;
+            ++level1;
+
+            /* copy the folding result to fold1[] */
+            if(length<=UCASE_MAX_STRING_LENGTH) {
+                u_memcpy(fold1, p, length);
+            } else {
+                int32_t i=0;
+                U16_APPEND_UNSAFE(fold1, i, length);
+                length=i;
+            }
+
+            /* set next level pointers to case folding */
+            start1=s1=fold1;
+            limit1=fold1+length;
+
+            /* get ready to read from decomposition, continue with loop */
+            c1=-1;
+            continue;
+        }
+
+        if( level2==0 &&
+            (length=ucase_toFullFolding(csp, (UChar32)cp2, &p, options))>=0
+        ) {
+            /* cp2 case-folds to the code point "length" or to p[length] */
+            if(U_IS_SURROGATE(c2)) {
+                if(U_IS_SURROGATE_LEAD(c2)) {
+                    /* advance beyond source surrogate pair if it case-folds */
+                    ++s2;
+                } else /* isTrail(c2) */ {
+                    /*
+                     * we got a supplementary code point when hitting its trail surrogate,
+                     * therefore the lead surrogate must have been the same as in the other string;
+                     * compare this decomposition with the lead surrogate in the other string
+                     * remember that this simulates bulk text replacement:
+                     * the decomposition would replace the entire code point
+                     */
+                    --s1;
+                    c1=*(s1-1);
+                }
+            }
+
+            /* push current level pointers */
+            stack2[0].start=start2;
+            stack2[0].s=s2;
+            stack2[0].limit=limit2;
+            ++level2;
+
+            /* copy the folding result to fold2[] */
+            if(length<=UCASE_MAX_STRING_LENGTH) {
+                u_memcpy(fold2, p, length);
+            } else {
+                int32_t i=0;
+                U16_APPEND_UNSAFE(fold2, i, length);
+                length=i;
+            }
+
+            /* set next level pointers to case folding */
+            start2=s2=fold2;
+            limit2=fold2+length;
+
+            /* get ready to read from decomposition, continue with loop */
+            c2=-1;
+            continue;
+        }
+
+        /*
+         * no decomposition/case folding, max level for both sides:
+         * return difference result
+         *
+         * code point order comparison must not just return cp1-cp2
+         * because when single surrogates are present then the surrogate pairs
+         * that formed cp1 and cp2 may be from different string indexes
+         *
+         * example: { d800 d800 dc01 } vs. { d800 dc00 }, compare at second code units
+         * c1=d800 cp1=10001 c2=dc00 cp2=10000
+         * cp1-cp2>0 but c1-c2<0 and in fact in UTF-32 it is { d800 10001 } < { 10000 }
+         *
+         * therefore, use same fix-up as in ustring.c/uprv_strCompare()
+         * except: uprv_strCompare() fetches c=*s while this functions fetches c=*s++
+         * so we have slightly different pointer/start/limit comparisons here
+         */
+
+        if(c1>=0xd800 && c2>=0xd800 && (options&U_COMPARE_CODE_POINT_ORDER)) {
+            /* subtract 0x2800 from BMP code points to make them smaller than supplementary ones */
+            if(
+                (c1<=0xdbff && s1!=limit1 && U16_IS_TRAIL(*s1)) ||
+                (U16_IS_TRAIL(c1) && start1!=(s1-1) && U16_IS_LEAD(*(s1-2)))
+            ) {
+                /* part of a surrogate pair, leave >=d800 */
+            } else {
+                /* BMP code point - may be surrogate code point - make <d800 */
+                c1-=0x2800;
+            }
+
+            if(
+                (c2<=0xdbff && s2!=limit2 && U16_IS_TRAIL(*s2)) ||
+                (U16_IS_TRAIL(c2) && start2!=(s2-1) && U16_IS_LEAD(*(s2-2)))
+            ) {
+                /* part of a surrogate pair, leave >=d800 */
+            } else {
+                /* BMP code point - may be surrogate code point - make <d800 */
+                c2-=0x2800;
+            }
+        }
+
+        return c1-c2;
+    }
+}
+
+/* public API functions */
+
+U_CAPI int32_t U_EXPORT2
+u_strCaseCompare(const UChar *s1, int32_t length1,
+                 const UChar *s2, int32_t length2,
+                 uint32_t options,
+                 UErrorCode *pErrorCode) {
+    /* argument checking */
+    if(pErrorCode==0 || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(s1==NULL || length1<-1 || s2==NULL || length2<-1) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    return u_strcmpFold(s1, length1, s2, length2,
+                        options|U_COMPARE_IGNORE_CASE,
+                        pErrorCode);
+}
+
+U_CAPI int32_t U_EXPORT2
+u_strcasecmp(const UChar *s1, const UChar *s2, uint32_t options) {
+    UErrorCode errorCode=U_ZERO_ERROR;
+    return u_strcmpFold(s1, -1, s2, -1,
+                        options|U_COMPARE_IGNORE_CASE,
+                        &errorCode);
+}
+
+U_CAPI int32_t U_EXPORT2
+u_memcasecmp(const UChar *s1, const UChar *s2, int32_t length, uint32_t options) {
+    UErrorCode errorCode=U_ZERO_ERROR;
+    return u_strcmpFold(s1, length, s2, length,
+                        options|U_COMPARE_IGNORE_CASE,
+                        &errorCode);
+}
+
+U_CAPI int32_t U_EXPORT2
+u_strncasecmp(const UChar *s1, const UChar *s2, int32_t n, uint32_t options) {
+    UErrorCode errorCode=U_ZERO_ERROR;
+    return u_strcmpFold(s1, n, s2, n,
+                        options|(U_COMPARE_IGNORE_CASE|_STRNCMP_STYLE),
+                        &errorCode);
+}
diff --git a/source/common/ustrenum.cpp b/source/common/ustrenum.cpp
new file mode 100644
index 0000000..8ae7d7e
--- /dev/null
+++ b/source/common/ustrenum.cpp
@@ -0,0 +1,325 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2010, International Business Machines
+* Corporation and others.  All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: November 11 2002
+* Since: ICU 2.4
+**********************************************************************
+*/
+#include <typeinfo>  // for 'typeid' to work 
+
+#include "unicode/ustring.h"
+#include "unicode/strenum.h"
+#include "unicode/putil.h"
+#include "uenumimp.h"
+#include "ustrenum.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include "uassert.h"
+
+U_NAMESPACE_BEGIN
+// StringEnumeration implementation ---------------------------------------- ***
+
+StringEnumeration::StringEnumeration()
+    : chars(charsBuffer), charsCapacity(sizeof(charsBuffer)) {
+}
+
+StringEnumeration::~StringEnumeration() {
+    if (chars != NULL && chars != charsBuffer) {
+        uprv_free(chars);
+    }
+}
+
+// StringEnumeration base class clone() default implementation, does not clone
+StringEnumeration *
+StringEnumeration::clone() const {
+  return NULL;
+}
+
+const char *
+StringEnumeration::next(int32_t *resultLength, UErrorCode &status) {
+    const UnicodeString *s=snext(status);
+    if(s!=NULL) {
+        unistr=*s;
+        ensureCharsCapacity(unistr.length()+1, status);
+        if(U_SUCCESS(status)) {
+            if(resultLength!=NULL) {
+                *resultLength=unistr.length();
+            }
+            unistr.extract(0, INT32_MAX, chars, charsCapacity, US_INV);
+            return chars;
+        }
+    }
+
+    return NULL;
+}
+
+const UChar *
+StringEnumeration::unext(int32_t *resultLength, UErrorCode &status) {
+    const UnicodeString *s=snext(status);
+    if(s!=NULL) {
+        unistr=*s;
+        if(U_SUCCESS(status)) {
+            if(resultLength!=NULL) {
+                *resultLength=unistr.length();
+            }
+            return unistr.getTerminatedBuffer();
+        }
+    }
+
+    return NULL;
+}
+
+void
+StringEnumeration::ensureCharsCapacity(int32_t capacity, UErrorCode &status) {
+    if(U_SUCCESS(status) && capacity>charsCapacity) {
+        if(capacity<(charsCapacity+charsCapacity/2)) {
+            // avoid allocation thrashing
+            capacity=charsCapacity+charsCapacity/2;
+        }
+        if(chars!=charsBuffer) {
+            uprv_free(chars);
+        }
+        chars=(char *)uprv_malloc(capacity);
+        if(chars==NULL) {
+            chars=charsBuffer;
+            charsCapacity=sizeof(charsBuffer);
+            status=U_MEMORY_ALLOCATION_ERROR;
+        } else {
+            charsCapacity=capacity;
+        }
+    }
+}
+
+UnicodeString *
+StringEnumeration::setChars(const char *s, int32_t length, UErrorCode &status) {
+    if(U_SUCCESS(status) && s!=NULL) {
+        if(length<0) {
+            length=(int32_t)uprv_strlen(s);
+        }
+
+        UChar *buffer=unistr.getBuffer(length+1);
+        if(buffer!=NULL) {
+            u_charsToUChars(s, buffer, length);
+            buffer[length]=0;
+            unistr.releaseBuffer(length);
+            return &unistr;
+        } else {
+            status=U_MEMORY_ALLOCATION_ERROR;
+        }
+    }
+
+    return NULL;
+}
+UBool 
+StringEnumeration::operator==(const StringEnumeration& that)const {
+    return typeid(*this) == typeid(that); 
+}
+
+UBool
+StringEnumeration::operator!=(const StringEnumeration& that)const {
+    return !operator==(that);
+}
+
+// UStringEnumeration implementation --------------------------------------- ***
+
+UStringEnumeration::UStringEnumeration(UEnumeration* _uenum) :
+    uenum(_uenum) {
+    U_ASSERT(_uenum != 0);
+}
+
+UStringEnumeration::~UStringEnumeration() {
+    uenum_close(uenum);
+}
+
+int32_t UStringEnumeration::count(UErrorCode& status) const {
+    return uenum_count(uenum, &status);
+}
+
+const UnicodeString* UStringEnumeration::snext(UErrorCode& status) {
+    int32_t length;
+    const UChar* str = uenum_unext(uenum, &length, &status);
+    if (str == 0 || U_FAILURE(status)) {
+        return 0;
+    }
+    return &unistr.setTo(str, length);
+}
+
+void UStringEnumeration::reset(UErrorCode& status) {
+    uenum_reset(uenum, &status);
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UStringEnumeration)
+U_NAMESPACE_END
+
+// C wrapper --------------------------------------------------------------- ***
+
+#define THIS(en) ((U_NAMESPACE_QUALIFIER StringEnumeration*)(en->context))
+
+U_CDECL_BEGIN
+
+/**
+ * Wrapper API to make StringEnumeration look like UEnumeration.
+ */
+static void U_CALLCONV
+ustrenum_close(UEnumeration* en) {
+    delete THIS(en);
+    uprv_free(en);
+}
+
+/**
+ * Wrapper API to make StringEnumeration look like UEnumeration.
+ */
+static int32_t U_CALLCONV
+ustrenum_count(UEnumeration* en,
+               UErrorCode* ec)
+{
+    return THIS(en)->count(*ec);
+}
+
+/**
+ * Wrapper API to make StringEnumeration look like UEnumeration.
+ */
+static const UChar* U_CALLCONV
+ustrenum_unext(UEnumeration* en,
+               int32_t* resultLength,
+               UErrorCode* ec)
+{
+    return THIS(en)->unext(resultLength, *ec);
+}
+
+/**
+ * Wrapper API to make StringEnumeration look like UEnumeration.
+ */
+static const char* U_CALLCONV
+ustrenum_next(UEnumeration* en,
+              int32_t* resultLength,
+              UErrorCode* ec)
+{
+    return THIS(en)->next(resultLength, *ec);
+}
+
+/**
+ * Wrapper API to make StringEnumeration look like UEnumeration.
+ */
+static void U_CALLCONV
+ustrenum_reset(UEnumeration* en,
+               UErrorCode* ec)
+{
+    THIS(en)->reset(*ec);
+}
+
+/**
+ * Pseudo-vtable for UEnumeration wrapper around StringEnumeration.
+ * The StringEnumeration pointer will be stored in 'context'.
+ */
+static const UEnumeration USTRENUM_VT = {
+    NULL,
+    NULL, // store StringEnumeration pointer here
+    ustrenum_close,
+    ustrenum_count,
+    ustrenum_unext,
+    ustrenum_next,
+    ustrenum_reset
+};
+
+U_CDECL_END
+
+/**
+ * Given a StringEnumeration, wrap it in a UEnumeration.  The
+ * StringEnumeration is adopted; after this call, the caller must not
+ * delete it (regardless of error status).
+ */
+U_CAPI UEnumeration* U_EXPORT2
+uenum_openFromStringEnumeration(U_NAMESPACE_QUALIFIER StringEnumeration* adopted, UErrorCode* ec) { 
+    UEnumeration* result = NULL;
+    if (U_SUCCESS(*ec) && adopted != NULL) {
+        result = (UEnumeration*) uprv_malloc(sizeof(UEnumeration));
+        if (result == NULL) {
+            *ec = U_MEMORY_ALLOCATION_ERROR;
+        } else {
+            uprv_memcpy(result, &USTRENUM_VT, sizeof(USTRENUM_VT));
+            result->context = adopted;
+        }
+    }
+    if (result == NULL) {
+        delete adopted;
+    }
+    return result;
+}
+
+// C wrapper --------------------------------------------------------------- ***
+
+U_CDECL_BEGIN
+
+typedef struct UCharStringEnumeration {
+    UEnumeration uenum;
+    int32_t index, count;
+} UCharStringEnumeration;
+
+static void U_CALLCONV
+ucharstrenum_close(UEnumeration* en) {
+    uprv_free(en);
+}
+
+static int32_t U_CALLCONV
+ucharstrenum_count(UEnumeration* en,
+                   UErrorCode* /*ec*/) {
+    return ((UCharStringEnumeration*)en)->count;
+}
+
+static const char* U_CALLCONV
+ucharstrenum_next(UEnumeration* en,
+                  int32_t* resultLength,
+                  UErrorCode* /*ec*/) {
+    UCharStringEnumeration *e = (UCharStringEnumeration*) en;
+    if (e->index >= e->count) {
+        return NULL;
+    }
+    const char* result = ((const char**)e->uenum.context)[e->index++];
+    if (resultLength) {
+        *resultLength = (int32_t)uprv_strlen(result);
+    }
+    return result;
+}
+
+static void U_CALLCONV
+ucharstrenum_reset(UEnumeration* en,
+                   UErrorCode* /*ec*/) {
+    ((UCharStringEnumeration*)en)->index = 0;
+}
+
+static const UEnumeration UCHARSTRENUM_VT = {
+    NULL,
+    NULL, // store StringEnumeration pointer here
+    ucharstrenum_close,
+    ucharstrenum_count,
+    uenum_unextDefault,
+    ucharstrenum_next,
+    ucharstrenum_reset
+};
+
+U_CDECL_END
+
+U_CAPI UEnumeration* U_EXPORT2
+uenum_openCharStringsEnumeration(const char* const* strings, int32_t count,
+                                 UErrorCode* ec) {
+    UCharStringEnumeration* result = NULL;
+    if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) {
+        result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration));
+        if (result == NULL) {
+            *ec = U_MEMORY_ALLOCATION_ERROR;
+        } else {
+            U_ASSERT((char*)result==(char*)(&result->uenum));
+            uprv_memcpy(result, &UCHARSTRENUM_VT, sizeof(UCHARSTRENUM_VT));
+            result->uenum.context = (void*)strings;
+            result->index = 0;
+            result->count = count;
+        }
+    }
+    return (UEnumeration*) result;
+}
+
+
diff --git a/source/common/ustrenum.h b/source/common/ustrenum.h
new file mode 100644
index 0000000..21b1683
--- /dev/null
+++ b/source/common/ustrenum.h
@@ -0,0 +1,90 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2009, International Business Machines
+* Corporation and others.  All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: November 11 2002
+* Since: ICU 2.4
+**********************************************************************
+*/
+#ifndef _USTRENUM_H_
+#define _USTRENUM_H_
+
+#include "unicode/uenum.h"
+#include "unicode/strenum.h"
+
+/**
+ * Given an array of const char* strings (invariant chars only),
+ * return a UEnumeration.  Must have strings[i] != 0 for i in
+ * 0..count-1.
+ */
+U_CAPI UEnumeration* U_EXPORT2
+uenum_openCharStringsEnumeration(const char* const* strings, int32_t count,
+                                 UErrorCode* ec);
+
+//----------------------------------------------------------------------
+U_NAMESPACE_BEGIN
+
+/**
+ * A wrapper to make a UEnumeration into a StringEnumeration.  The
+ * wrapper adopts the UEnumeration is wraps.
+ */
+class U_COMMON_API UStringEnumeration : public StringEnumeration {
+
+public:
+    /**
+     * Constructor.  This constructor adopts its UEnumeration
+     * argument.
+     * @param uenum a UEnumeration object.  This object takes
+     * ownership of 'uenum' and will close it in its destructor.  The
+     * caller must not call uenum_close on 'uenum' after calling this
+     * constructor.
+     */
+    UStringEnumeration(UEnumeration* uenum);
+
+    /**
+     * Destructor.  This closes the UEnumeration passed in to the
+     * constructor.
+     */
+    virtual ~UStringEnumeration();
+
+    /**
+     * Return the number of elements that the iterator traverses.
+     * @param status the error code.
+     * @return number of elements in the iterator.
+     */
+    virtual int32_t count(UErrorCode& status) const;
+
+    /**
+     * Returns the next element a UnicodeString*.  If there are no
+     * more elements, returns NULL.
+     * @param status the error code.
+     * @return a pointer to the string, or NULL.
+     */
+    virtual const UnicodeString* snext(UErrorCode& status);
+
+    /**
+     * Resets the iterator.
+     * @param status the error code.
+     */
+    virtual void reset(UErrorCode& status);
+
+    /**
+     * ICU4C "poor man's RTTI", returns a UClassID for the actual ICU class.
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU4C "poor man's RTTI", returns a UClassID for this ICU class.
+     */
+    static UClassID U_EXPORT2 getStaticClassID();
+
+private:
+    UEnumeration *uenum; // owned
+};
+
+U_NAMESPACE_END
+
+#endif
+
diff --git a/source/common/ustrfmt.c b/source/common/ustrfmt.c
new file mode 100644
index 0000000..5e9fb92
--- /dev/null
+++ b/source/common/ustrfmt.c
@@ -0,0 +1,57 @@
+/*
+**********************************************************************
+*   Copyright (C) 2001-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+
+#include "cstring.h"
+#include "ustrfmt.h"
+
+
+/***
+ * Fills in a UChar* string with the radix-based representation of a
+ * uint32_t number padded with zeroes to minwidth.  The result
+ * will be null terminated if there is room.
+ *
+ * @param buffer UChar buffer to receive result
+ * @param capacity capacity of buffer
+ * @param i the unsigned number to be formatted
+ * @param radix the radix from 2..36
+ * @param minwidth the minimum width.  If the result is narrower than
+ *        this, '0's will be added on the left.  Must be <=
+ *        capacity.
+ * @return the length of the result, not including any terminating
+ *        null
+ */
+U_CAPI int32_t U_EXPORT2
+uprv_itou (UChar * buffer, int32_t capacity,
+           uint32_t i, uint32_t radix, int32_t minwidth)
+{
+    int32_t length = 0;
+    int digit;
+    int32_t j;
+    UChar temp;
+
+    do{
+        digit = (int)(i % radix);
+        buffer[length++]=(UChar)(digit<=9?(0x0030+digit):(0x0030+digit+7));
+        i=i/radix;
+    } while(i && length<capacity);
+
+    while (length < minwidth){
+        buffer[length++] = (UChar) 0x0030;/*zero padding */
+    }
+    /* null terminate the buffer */
+    if(length<capacity){
+        buffer[length] = (UChar) 0x0000;
+    }
+
+    /* Reverses the string */
+    for (j = 0; j < (length / 2); j++){
+        temp = buffer[(length-1) - j];
+        buffer[(length-1) - j] = buffer[j];
+        buffer[j] = temp;
+    }
+    return length;
+}
diff --git a/source/common/ustrfmt.h b/source/common/ustrfmt.h
new file mode 100644
index 0000000..f1891bd
--- /dev/null
+++ b/source/common/ustrfmt.h
@@ -0,0 +1,17 @@
+/*
+**********************************************************************
+*   Copyright (C) 2001-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+
+#ifndef USTRFMT_H
+#define USTRFMT_H
+
+#include "unicode/utypes.h"
+
+U_CAPI int32_t U_EXPORT2
+uprv_itou (UChar * buffer, int32_t capacity, uint32_t i, uint32_t radix, int32_t minwidth);
+
+
+#endif
diff --git a/source/common/ustring.c b/source/common/ustring.c
new file mode 100644
index 0000000..e9f917d
--- /dev/null
+++ b/source/common/ustring.c
@@ -0,0 +1,1465 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1998-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File ustring.h
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   12/07/98    bertrand    Creation.
+******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/putil.h"
+#include "unicode/ustring.h"
+#include "cstring.h"
+#include "cwchar.h"
+#include "cmemory.h"
+#include "ustr_imp.h"
+
+/* ANSI string.h - style functions ------------------------------------------ */
+
+/* U+ffff is the highest BMP code point, the highest one that fits into a 16-bit UChar */
+#define U_BMP_MAX 0xffff
+
+/* Forward binary string search functions ----------------------------------- */
+
+/*
+ * Test if a substring match inside a string is at code point boundaries.
+ * All pointers refer to the same buffer.
+ * The limit pointer may be NULL, all others must be real pointers.
+ */
+static U_INLINE UBool
+isMatchAtCPBoundary(const UChar *start, const UChar *match, const UChar *matchLimit, const UChar *limit) {
+    if(U16_IS_TRAIL(*match) && start!=match && U16_IS_LEAD(*(match-1))) {
+        /* the leading edge of the match is in the middle of a surrogate pair */
+        return FALSE;
+    }
+    if(U16_IS_LEAD(*(matchLimit-1)) && match!=limit && U16_IS_TRAIL(*matchLimit)) {
+        /* the trailing edge of the match is in the middle of a surrogate pair */
+        return FALSE;
+    }
+    return TRUE;
+}
+
+U_CAPI UChar * U_EXPORT2
+u_strFindFirst(const UChar *s, int32_t length,
+               const UChar *sub, int32_t subLength) {
+    const UChar *start, *p, *q, *subLimit;
+    UChar c, cs, cq;
+
+    if(sub==NULL || subLength<-1) {
+        return (UChar *)s;
+    }
+    if(s==NULL || length<-1) {
+        return NULL;
+    }
+
+    start=s;
+
+    if(length<0 && subLength<0) {
+        /* both strings are NUL-terminated */
+        if((cs=*sub++)==0) {
+            return (UChar *)s;
+        }
+        if(*sub==0 && !U16_IS_SURROGATE(cs)) {
+            /* the substring consists of a single, non-surrogate BMP code point */
+            return u_strchr(s, cs);
+        }
+
+        while((c=*s++)!=0) {
+            if(c==cs) {
+                /* found first substring UChar, compare rest */
+                p=s;
+                q=sub;
+                for(;;) {
+                    if((cq=*q)==0) {
+                        if(isMatchAtCPBoundary(start, s-1, p, NULL)) {
+                            return (UChar *)(s-1); /* well-formed match */
+                        } else {
+                            break; /* no match because surrogate pair is split */
+                        }
+                    }
+                    if((c=*p)==0) {
+                        return NULL; /* no match, and none possible after s */
+                    }
+                    if(c!=cq) {
+                        break; /* no match */
+                    }
+                    ++p;
+                    ++q;
+                }
+            }
+        }
+
+        /* not found */
+        return NULL;
+    }
+
+    if(subLength<0) {
+        subLength=u_strlen(sub);
+    }
+    if(subLength==0) {
+        return (UChar *)s;
+    }
+
+    /* get sub[0] to search for it fast */
+    cs=*sub++;
+    --subLength;
+    subLimit=sub+subLength;
+
+    if(subLength==0 && !U16_IS_SURROGATE(cs)) {
+        /* the substring consists of a single, non-surrogate BMP code point */
+        return length<0 ? u_strchr(s, cs) : u_memchr(s, cs, length);
+    }
+
+    if(length<0) {
+        /* s is NUL-terminated */
+        while((c=*s++)!=0) {
+            if(c==cs) {
+                /* found first substring UChar, compare rest */
+                p=s;
+                q=sub;
+                for(;;) {
+                    if(q==subLimit) {
+                        if(isMatchAtCPBoundary(start, s-1, p, NULL)) {
+                            return (UChar *)(s-1); /* well-formed match */
+                        } else {
+                            break; /* no match because surrogate pair is split */
+                        }
+                    }
+                    if((c=*p)==0) {
+                        return NULL; /* no match, and none possible after s */
+                    }
+                    if(c!=*q) {
+                        break; /* no match */
+                    }
+                    ++p;
+                    ++q;
+                }
+            }
+        }
+    } else {
+        const UChar *limit, *preLimit;
+
+        /* subLength was decremented above */
+        if(length<=subLength) {
+            return NULL; /* s is shorter than sub */
+        }
+
+        limit=s+length;
+
+        /* the substring must start before preLimit */
+        preLimit=limit-subLength;
+
+        while(s!=preLimit) {
+            c=*s++;
+            if(c==cs) {
+                /* found first substring UChar, compare rest */
+                p=s;
+                q=sub;
+                for(;;) {
+                    if(q==subLimit) {
+                        if(isMatchAtCPBoundary(start, s-1, p, limit)) {
+                            return (UChar *)(s-1); /* well-formed match */
+                        } else {
+                            break; /* no match because surrogate pair is split */
+                        }
+                    }
+                    if(*p!=*q) {
+                        break; /* no match */
+                    }
+                    ++p;
+                    ++q;
+                }
+            }
+        }
+    }
+
+    /* not found */
+    return NULL;
+}
+
+U_CAPI UChar * U_EXPORT2
+u_strstr(const UChar *s, const UChar *substring) {
+    return u_strFindFirst(s, -1, substring, -1);
+}
+
+U_CAPI UChar * U_EXPORT2
+u_strchr(const UChar *s, UChar c) {
+    if(U16_IS_SURROGATE(c)) {
+        /* make sure to not find half of a surrogate pair */
+        return u_strFindFirst(s, -1, &c, 1);
+    } else {
+        UChar cs;
+
+        /* trivial search for a BMP code point */
+        for(;;) {
+            if((cs=*s)==c) {
+                return (UChar *)s;
+            }
+            if(cs==0) {
+                return NULL;
+            }
+            ++s;
+        }
+    }
+}
+
+U_CAPI UChar * U_EXPORT2
+u_strchr32(const UChar *s, UChar32 c) {
+    if((uint32_t)c<=U_BMP_MAX) {
+        /* find BMP code point */
+        return u_strchr(s, (UChar)c);
+    } else if((uint32_t)c<=UCHAR_MAX_VALUE) {
+        /* find supplementary code point as surrogate pair */
+        UChar cs, lead=U16_LEAD(c), trail=U16_TRAIL(c);
+
+        while((cs=*s++)!=0) {
+            if(cs==lead && *s==trail) {
+                return (UChar *)(s-1);
+            }
+        }
+        return NULL;
+    } else {
+        /* not a Unicode code point, not findable */
+        return NULL;
+    }
+}
+
+U_CAPI UChar * U_EXPORT2
+u_memchr(const UChar *s, UChar c, int32_t count) {
+    if(count<=0) {
+        return NULL; /* no string */
+    } else if(U16_IS_SURROGATE(c)) {
+        /* make sure to not find half of a surrogate pair */
+        return u_strFindFirst(s, count, &c, 1);
+    } else {
+        /* trivial search for a BMP code point */
+        const UChar *limit=s+count;
+        do {
+            if(*s==c) {
+                return (UChar *)s;
+            }
+        } while(++s!=limit);
+        return NULL;
+    }
+}
+
+U_CAPI UChar * U_EXPORT2
+u_memchr32(const UChar *s, UChar32 c, int32_t count) {
+    if((uint32_t)c<=U_BMP_MAX) {
+        /* find BMP code point */
+        return u_memchr(s, (UChar)c, count);
+    } else if(count<2) {
+        /* too short for a surrogate pair */
+        return NULL;
+    } else if((uint32_t)c<=UCHAR_MAX_VALUE) {
+        /* find supplementary code point as surrogate pair */
+        const UChar *limit=s+count-1; /* -1 so that we do not need a separate check for the trail unit */
+        UChar lead=U16_LEAD(c), trail=U16_TRAIL(c);
+
+        do {
+            if(*s==lead && *(s+1)==trail) {
+                return (UChar *)s;
+            }
+        } while(++s!=limit);
+        return NULL;
+    } else {
+        /* not a Unicode code point, not findable */
+        return NULL;
+    }
+}
+
+/* Backward binary string search functions ---------------------------------- */
+
+U_CAPI UChar * U_EXPORT2
+u_strFindLast(const UChar *s, int32_t length,
+              const UChar *sub, int32_t subLength) {
+    const UChar *start, *limit, *p, *q, *subLimit;
+    UChar c, cs;
+
+    if(sub==NULL || subLength<-1) {
+        return (UChar *)s;
+    }
+    if(s==NULL || length<-1) {
+        return NULL;
+    }
+
+    /*
+     * This implementation is more lazy than the one for u_strFindFirst():
+     * There is no special search code for NUL-terminated strings.
+     * It does not seem to be worth it for searching substrings to
+     * search forward and find all matches like in u_strrchr() and similar.
+     * Therefore, we simply get both string lengths and search backward.
+     *
+     * markus 2002oct23
+     */
+
+    if(subLength<0) {
+        subLength=u_strlen(sub);
+    }
+    if(subLength==0) {
+        return (UChar *)s;
+    }
+
+    /* get sub[subLength-1] to search for it fast */
+    subLimit=sub+subLength;
+    cs=*(--subLimit);
+    --subLength;
+
+    if(subLength==0 && !U16_IS_SURROGATE(cs)) {
+        /* the substring consists of a single, non-surrogate BMP code point */
+        return length<0 ? u_strrchr(s, cs) : u_memrchr(s, cs, length);
+    }
+
+    if(length<0) {
+        length=u_strlen(s);
+    }
+
+    /* subLength was decremented above */
+    if(length<=subLength) {
+        return NULL; /* s is shorter than sub */
+    }
+
+    start=s;
+    limit=s+length;
+
+    /* the substring must start no later than s+subLength */
+    s+=subLength;
+
+    while(s!=limit) {
+        c=*(--limit);
+        if(c==cs) {
+            /* found last substring UChar, compare rest */
+            p=limit;
+            q=subLimit;
+            for(;;) {
+                if(q==sub) {
+                    if(isMatchAtCPBoundary(start, p, limit+1, start+length)) {
+                        return (UChar *)p; /* well-formed match */
+                    } else {
+                        break; /* no match because surrogate pair is split */
+                    }
+                }
+                if(*(--p)!=*(--q)) {
+                    break; /* no match */
+                }
+            }
+        }
+    }
+
+    /* not found */
+    return NULL;
+}
+
+U_CAPI UChar * U_EXPORT2
+u_strrstr(const UChar *s, const UChar *substring) {
+    return u_strFindLast(s, -1, substring, -1);
+}
+
+U_CAPI UChar * U_EXPORT2
+u_strrchr(const UChar *s, UChar c) {
+    if(U16_IS_SURROGATE(c)) {
+        /* make sure to not find half of a surrogate pair */
+        return u_strFindLast(s, -1, &c, 1);
+    } else {
+        const UChar *result=NULL;
+        UChar cs;
+
+        /* trivial search for a BMP code point */
+        for(;;) {
+            if((cs=*s)==c) {
+                result=s;
+            }
+            if(cs==0) {
+                return (UChar *)result;
+            }
+            ++s;
+        }
+    }
+}
+
+U_CAPI UChar * U_EXPORT2
+u_strrchr32(const UChar *s, UChar32 c) {
+    if((uint32_t)c<=U_BMP_MAX) {
+        /* find BMP code point */
+        return u_strrchr(s, (UChar)c);
+    } else if((uint32_t)c<=UCHAR_MAX_VALUE) {
+        /* find supplementary code point as surrogate pair */
+        const UChar *result=NULL;
+        UChar cs, lead=U16_LEAD(c), trail=U16_TRAIL(c);
+
+        while((cs=*s++)!=0) {
+            if(cs==lead && *s==trail) {
+                result=s-1;
+            }
+        }
+        return (UChar *)result;
+    } else {
+        /* not a Unicode code point, not findable */
+        return NULL;
+    }
+}
+
+U_CAPI UChar * U_EXPORT2
+u_memrchr(const UChar *s, UChar c, int32_t count) {
+    if(count<=0) {
+        return NULL; /* no string */
+    } else if(U16_IS_SURROGATE(c)) {
+        /* make sure to not find half of a surrogate pair */
+        return u_strFindLast(s, count, &c, 1);
+    } else {
+        /* trivial search for a BMP code point */
+        const UChar *limit=s+count;
+        do {
+            if(*(--limit)==c) {
+                return (UChar *)limit;
+            }
+        } while(s!=limit);
+        return NULL;
+    }
+}
+
+U_CAPI UChar * U_EXPORT2
+u_memrchr32(const UChar *s, UChar32 c, int32_t count) {
+    if((uint32_t)c<=U_BMP_MAX) {
+        /* find BMP code point */
+        return u_memrchr(s, (UChar)c, count);
+    } else if(count<2) {
+        /* too short for a surrogate pair */
+        return NULL;
+    } else if((uint32_t)c<=UCHAR_MAX_VALUE) {
+        /* find supplementary code point as surrogate pair */
+        const UChar *limit=s+count-1;
+        UChar lead=U16_LEAD(c), trail=U16_TRAIL(c);
+
+        do {
+            if(*limit==trail && *(limit-1)==lead) {
+                return (UChar *)(limit-1);
+            }
+        } while(s!=--limit);
+        return NULL;
+    } else {
+        /* not a Unicode code point, not findable */
+        return NULL;
+    }
+}
+
+/* Tokenization functions --------------------------------------------------- */
+
+/*
+ * Match each code point in a string against each code point in the matchSet.
+ * Return the index of the first string code point that
+ * is (polarity==TRUE) or is not (FALSE) contained in the matchSet.
+ * Return -(string length)-1 if there is no such code point.
+ */
+static int32_t
+_matchFromSet(const UChar *string, const UChar *matchSet, UBool polarity) {
+    int32_t matchLen, matchBMPLen, strItr, matchItr;
+    UChar32 stringCh, matchCh;
+    UChar c, c2;
+
+    /* first part of matchSet contains only BMP code points */
+    matchBMPLen = 0;
+    while((c = matchSet[matchBMPLen]) != 0 && U16_IS_SINGLE(c)) {
+        ++matchBMPLen;
+    }
+
+    /* second part of matchSet contains BMP and supplementary code points */
+    matchLen = matchBMPLen;
+    while(matchSet[matchLen] != 0) {
+        ++matchLen;
+    }
+
+    for(strItr = 0; (c = string[strItr]) != 0;) {
+        ++strItr;
+        if(U16_IS_SINGLE(c)) {
+            if(polarity) {
+                for(matchItr = 0; matchItr < matchLen; ++matchItr) {
+                    if(c == matchSet[matchItr]) {
+                        return strItr - 1; /* one matches */
+                    }
+                }
+            } else {
+                for(matchItr = 0; matchItr < matchLen; ++matchItr) {
+                    if(c == matchSet[matchItr]) {
+                        goto endloop;
+                    }
+                }
+                return strItr - 1; /* none matches */
+            }
+        } else {
+            /*
+             * No need to check for string length before U16_IS_TRAIL
+             * because c2 could at worst be the terminating NUL.
+             */
+            if(U16_IS_SURROGATE_LEAD(c) && U16_IS_TRAIL(c2 = string[strItr])) {
+                ++strItr;
+                stringCh = U16_GET_SUPPLEMENTARY(c, c2);
+            } else {
+                stringCh = c; /* unpaired trail surrogate */
+            }
+
+            if(polarity) {
+                for(matchItr = matchBMPLen; matchItr < matchLen;) {
+                    U16_NEXT(matchSet, matchItr, matchLen, matchCh);
+                    if(stringCh == matchCh) {
+                        return strItr - U16_LENGTH(stringCh); /* one matches */
+                    }
+                }
+            } else {
+                for(matchItr = matchBMPLen; matchItr < matchLen;) {
+                    U16_NEXT(matchSet, matchItr, matchLen, matchCh);
+                    if(stringCh == matchCh) {
+                        goto endloop;
+                    }
+                }
+                return strItr - U16_LENGTH(stringCh); /* none matches */
+            }
+        }
+endloop:
+        /* wish C had continue with labels like Java... */;
+    }
+
+    /* Didn't find it. */
+    return -strItr-1;
+}
+
+/* Search for a codepoint in a string that matches one of the matchSet codepoints. */
+U_CAPI UChar * U_EXPORT2
+u_strpbrk(const UChar *string, const UChar *matchSet)
+{
+    int32_t idx = _matchFromSet(string, matchSet, TRUE);
+    if(idx >= 0) {
+        return (UChar *)string + idx;
+    } else {
+        return NULL;
+    }
+}
+
+/* Search for a codepoint in a string that matches one of the matchSet codepoints. */
+U_CAPI int32_t U_EXPORT2
+u_strcspn(const UChar *string, const UChar *matchSet)
+{
+    int32_t idx = _matchFromSet(string, matchSet, TRUE);
+    if(idx >= 0) {
+        return idx;
+    } else {
+        return -idx - 1; /* == u_strlen(string) */
+    }
+}
+
+/* Search for a codepoint in a string that does not match one of the matchSet codepoints. */
+U_CAPI int32_t U_EXPORT2
+u_strspn(const UChar *string, const UChar *matchSet)
+{
+    int32_t idx = _matchFromSet(string, matchSet, FALSE);
+    if(idx >= 0) {
+        return idx;
+    } else {
+        return -idx - 1; /* == u_strlen(string) */
+    }
+}
+
+/* ----- Text manipulation functions --- */
+
+U_CAPI UChar* U_EXPORT2
+u_strtok_r(UChar    *src, 
+     const UChar    *delim,
+           UChar   **saveState)
+{
+    UChar *tokSource;
+    UChar *nextToken;
+    uint32_t nonDelimIdx;
+
+    /* If saveState is NULL, the user messed up. */
+    if (src != NULL) {
+        tokSource = src;
+        *saveState = src; /* Set to "src" in case there are no delimiters */
+    }
+    else if (*saveState) {
+        tokSource = *saveState;
+    }
+    else {
+        /* src == NULL && *saveState == NULL */
+        /* This shouldn't happen. We already finished tokenizing. */
+        return NULL;
+    }
+
+    /* Skip initial delimiters */
+    nonDelimIdx = u_strspn(tokSource, delim);
+    tokSource = &tokSource[nonDelimIdx];
+
+    if (*tokSource) {
+        nextToken = u_strpbrk(tokSource, delim);
+        if (nextToken != NULL) {
+            /* Create a token */
+            *(nextToken++) = 0;
+            *saveState = nextToken;
+            return tokSource;
+        }
+        else if (*saveState) {
+            /* Return the last token */
+            *saveState = NULL;
+            return tokSource;
+        }
+    }
+    else {
+        /* No tokens were found. Only delimiters were left. */
+        *saveState = NULL;
+    }
+    return NULL;
+}
+
+/* Miscellaneous functions -------------------------------------------------- */
+
+U_CAPI UChar* U_EXPORT2
+u_strcat(UChar     *dst, 
+    const UChar     *src)
+{
+    UChar *anchor = dst;            /* save a pointer to start of dst */
+
+    while(*dst != 0) {              /* To end of first string          */
+        ++dst;
+    }
+    while((*(dst++) = *(src++)) != 0) {     /* copy string 2 over              */
+    }
+
+    return anchor;
+}
+
+U_CAPI UChar*  U_EXPORT2
+u_strncat(UChar     *dst, 
+     const UChar     *src, 
+     int32_t     n ) 
+{
+    if(n > 0) {
+        UChar *anchor = dst;            /* save a pointer to start of dst */
+
+        while(*dst != 0) {              /* To end of first string          */
+            ++dst;
+        }
+        while((*dst = *src) != 0) {     /* copy string 2 over              */
+            ++dst;
+            if(--n == 0) {
+                *dst = 0;
+                break;
+            }
+            ++src;
+        }
+
+        return anchor;
+    } else {
+        return dst;
+    }
+}
+
+/* ----- Text property functions --- */
+
+U_CAPI int32_t   U_EXPORT2
+u_strcmp(const UChar *s1, 
+    const UChar *s2) 
+{
+    UChar  c1, c2;
+
+    for(;;) {
+        c1=*s1++;
+        c2=*s2++;
+        if (c1 != c2 || c1 == 0) {
+            break;
+        }
+    }
+    return (int32_t)c1 - (int32_t)c2;
+}
+
+U_CFUNC int32_t U_EXPORT2
+uprv_strCompare(const UChar *s1, int32_t length1,
+                const UChar *s2, int32_t length2,
+                UBool strncmpStyle, UBool codePointOrder) {
+    const UChar *start1, *start2, *limit1, *limit2;
+    UChar c1, c2;
+
+    /* setup for fix-up */
+    start1=s1;
+    start2=s2;
+
+    /* compare identical prefixes - they do not need to be fixed up */
+    if(length1<0 && length2<0) {
+        /* strcmp style, both NUL-terminated */
+        if(s1==s2) {
+            return 0;
+        }
+
+        for(;;) {
+            c1=*s1;
+            c2=*s2;
+            if(c1!=c2) {
+                break;
+            }
+            if(c1==0) {
+                return 0;
+            }
+            ++s1;
+            ++s2;
+        }
+
+        /* setup for fix-up */
+        limit1=limit2=NULL;
+    } else if(strncmpStyle) {
+        /* special handling for strncmp, assume length1==length2>=0 but also check for NUL */
+        if(s1==s2) {
+            return 0;
+        }
+
+        limit1=start1+length1;
+
+        for(;;) {
+            /* both lengths are same, check only one limit */
+            if(s1==limit1) {
+                return 0;
+            }
+
+            c1=*s1;
+            c2=*s2;
+            if(c1!=c2) {
+                break;
+            }
+            if(c1==0) {
+                return 0;
+            }
+            ++s1;
+            ++s2;
+        }
+
+        /* setup for fix-up */
+        limit2=start2+length1; /* use length1 here, too, to enforce assumption */
+    } else {
+        /* memcmp/UnicodeString style, both length-specified */
+        int32_t lengthResult;
+
+        if(length1<0) {
+            length1=u_strlen(s1);
+        }
+        if(length2<0) {
+            length2=u_strlen(s2);
+        }
+
+        /* limit1=start1+min(lenght1, length2) */
+        if(length1<length2) {
+            lengthResult=-1;
+            limit1=start1+length1;
+        } else if(length1==length2) {
+            lengthResult=0;
+            limit1=start1+length1;
+        } else /* length1>length2 */ {
+            lengthResult=1;
+            limit1=start1+length2;
+        }
+
+        if(s1==s2) {
+            return lengthResult;
+        }
+
+        for(;;) {
+            /* check pseudo-limit */
+            if(s1==limit1) {
+                return lengthResult;
+            }
+
+            c1=*s1;
+            c2=*s2;
+            if(c1!=c2) {
+                break;
+            }
+            ++s1;
+            ++s2;
+        }
+
+        /* setup for fix-up */
+        limit1=start1+length1;
+        limit2=start2+length2;
+    }
+
+    /* if both values are in or above the surrogate range, fix them up */
+    if(c1>=0xd800 && c2>=0xd800 && codePointOrder) {
+        /* subtract 0x2800 from BMP code points to make them smaller than supplementary ones */
+        if(
+            (c1<=0xdbff && (s1+1)!=limit1 && UTF_IS_TRAIL(*(s1+1))) ||
+            (UTF_IS_TRAIL(c1) && start1!=s1 && UTF_IS_LEAD(*(s1-1)))
+        ) {
+            /* part of a surrogate pair, leave >=d800 */
+        } else {
+            /* BMP code point - may be surrogate code point - make <d800 */
+            c1-=0x2800;
+        }
+
+        if(
+            (c2<=0xdbff && (s2+1)!=limit2 && UTF_IS_TRAIL(*(s2+1))) ||
+            (UTF_IS_TRAIL(c2) && start2!=s2 && UTF_IS_LEAD(*(s2-1)))
+        ) {
+            /* part of a surrogate pair, leave >=d800 */
+        } else {
+            /* BMP code point - may be surrogate code point - make <d800 */
+            c2-=0x2800;
+        }
+    }
+
+    /* now c1 and c2 are in the requested (code unit or code point) order */
+    return (int32_t)c1-(int32_t)c2;
+}
+
+/*
+ * Compare two strings as presented by UCharIterators.
+ * Use code unit or code point order.
+ * When the function returns, it is undefined where the iterators
+ * have stopped.
+ */
+U_CAPI int32_t U_EXPORT2
+u_strCompareIter(UCharIterator *iter1, UCharIterator *iter2, UBool codePointOrder) {
+    UChar32 c1, c2;
+
+    /* argument checking */
+    if(iter1==NULL || iter2==NULL) {
+        return 0; /* bad arguments */
+    }
+    if(iter1==iter2) {
+        return 0; /* identical iterators */
+    }
+
+    /* reset iterators to start? */
+    iter1->move(iter1, 0, UITER_START);
+    iter2->move(iter2, 0, UITER_START);
+
+    /* compare identical prefixes - they do not need to be fixed up */
+    for(;;) {
+        c1=iter1->next(iter1);
+        c2=iter2->next(iter2);
+        if(c1!=c2) {
+            break;
+        }
+        if(c1==-1) {
+            return 0;
+        }
+    }
+
+    /* if both values are in or above the surrogate range, fix them up */
+    if(c1>=0xd800 && c2>=0xd800 && codePointOrder) {
+        /* subtract 0x2800 from BMP code points to make them smaller than supplementary ones */
+        if(
+            (c1<=0xdbff && UTF_IS_TRAIL(iter1->current(iter1))) ||
+            (UTF_IS_TRAIL(c1) && (iter1->previous(iter1), UTF_IS_LEAD(iter1->previous(iter1))))
+        ) {
+            /* part of a surrogate pair, leave >=d800 */
+        } else {
+            /* BMP code point - may be surrogate code point - make <d800 */
+            c1-=0x2800;
+        }
+
+        if(
+            (c2<=0xdbff && UTF_IS_TRAIL(iter2->current(iter2))) ||
+            (UTF_IS_TRAIL(c2) && (iter2->previous(iter2), UTF_IS_LEAD(iter2->previous(iter2))))
+        ) {
+            /* part of a surrogate pair, leave >=d800 */
+        } else {
+            /* BMP code point - may be surrogate code point - make <d800 */
+            c2-=0x2800;
+        }
+    }
+
+    /* now c1 and c2 are in the requested (code unit or code point) order */
+    return (int32_t)c1-(int32_t)c2;
+}
+
+#if 0
+/*
+ * u_strCompareIter() does not leave the iterators _on_ the different units.
+ * This is possible but would cost a few extra indirect function calls to back
+ * up if the last unit (c1 or c2 respectively) was >=0.
+ *
+ * Consistently leaving them _behind_ the different units is not an option
+ * because the current "unit" is the end of the string if that is reached,
+ * and in such a case the iterator does not move.
+ * For example, when comparing "ab" with "abc", both iterators rest _on_ the end
+ * of their strings. Calling previous() on each does not move them to where
+ * the comparison fails.
+ *
+ * So the simplest semantics is to not define where the iterators end up.
+ *
+ * The following fragment is part of what would need to be done for backing up.
+ */
+void fragment {
+        /* iff a surrogate is part of a surrogate pair, leave >=d800 */
+        if(c1<=0xdbff) {
+            if(!UTF_IS_TRAIL(iter1->current(iter1))) {
+                /* lead surrogate code point - make <d800 */
+                c1-=0x2800;
+            }
+        } else if(c1<=0xdfff) {
+            int32_t idx=iter1->getIndex(iter1, UITER_CURRENT);
+            iter1->previous(iter1); /* ==c1 */
+            if(!UTF_IS_LEAD(iter1->previous(iter1))) {
+                /* trail surrogate code point - make <d800 */
+                c1-=0x2800;
+            }
+            /* go back to behind where the difference is */
+            iter1->move(iter1, idx, UITER_ZERO);
+        } else /* 0xe000<=c1<=0xffff */ {
+            /* BMP code point - make <d800 */
+            c1-=0x2800;
+        }
+}
+#endif
+
+U_CAPI int32_t U_EXPORT2
+u_strCompare(const UChar *s1, int32_t length1,
+             const UChar *s2, int32_t length2,
+             UBool codePointOrder) {
+    /* argument checking */
+    if(s1==NULL || length1<-1 || s2==NULL || length2<-1) {
+        return 0;
+    }
+    return uprv_strCompare(s1, length1, s2, length2, FALSE, codePointOrder);
+}
+
+/* String compare in code point order - u_strcmp() compares in code unit order. */
+U_CAPI int32_t U_EXPORT2
+u_strcmpCodePointOrder(const UChar *s1, const UChar *s2) {
+    return uprv_strCompare(s1, -1, s2, -1, FALSE, TRUE);
+}
+
+U_CAPI int32_t   U_EXPORT2
+u_strncmp(const UChar     *s1, 
+     const UChar     *s2, 
+     int32_t     n) 
+{
+    if(n > 0) {
+        int32_t rc;
+        for(;;) {
+            rc = (int32_t)*s1 - (int32_t)*s2;
+            if(rc != 0 || *s1 == 0 || --n == 0) {
+                return rc;
+            }
+            ++s1;
+            ++s2;
+        }
+    } else {
+        return 0;
+    }
+}
+
+U_CAPI int32_t U_EXPORT2
+u_strncmpCodePointOrder(const UChar *s1, const UChar *s2, int32_t n) {
+    return uprv_strCompare(s1, n, s2, n, TRUE, TRUE);
+}
+
+U_CAPI UChar* U_EXPORT2
+u_strcpy(UChar     *dst, 
+    const UChar     *src) 
+{
+    UChar *anchor = dst;            /* save a pointer to start of dst */
+
+    while((*(dst++) = *(src++)) != 0) {     /* copy string 2 over              */
+    }
+
+    return anchor;
+}
+
+U_CAPI UChar*  U_EXPORT2
+u_strncpy(UChar     *dst, 
+     const UChar     *src, 
+     int32_t     n) 
+{
+    UChar *anchor = dst;            /* save a pointer to start of dst */
+
+    /* copy string 2 over */
+    while(n > 0 && (*(dst++) = *(src++)) != 0) {
+        --n;
+    }
+
+    return anchor;
+}
+
+U_CAPI int32_t   U_EXPORT2
+u_strlen(const UChar *s) 
+{
+#if U_SIZEOF_WCHAR_T == U_SIZEOF_UCHAR
+    return (int32_t)uprv_wcslen(s);
+#else
+    const UChar *t = s;
+    while(*t != 0) {
+      ++t;
+    }
+    return t - s;
+#endif
+}
+
+U_CAPI int32_t U_EXPORT2
+u_countChar32(const UChar *s, int32_t length) {
+    int32_t count;
+
+    if(s==NULL || length<-1) {
+        return 0;
+    }
+
+    count=0;
+    if(length>=0) {
+        while(length>0) {
+            ++count;
+            if(UTF_IS_LEAD(*s) && length>=2 && UTF_IS_TRAIL(*(s+1))) {
+                s+=2;
+                length-=2;
+            } else {
+                ++s;
+                --length;
+            }
+        }
+    } else /* length==-1 */ {
+        UChar c;
+
+        for(;;) {
+            if((c=*s++)==0) {
+                break;
+            }
+            ++count;
+
+            /*
+             * sufficient to look ahead one because of UTF-16;
+             * safe to look ahead one because at worst that would be the terminating NUL
+             */
+            if(UTF_IS_LEAD(c) && UTF_IS_TRAIL(*s)) {
+                ++s;
+            }
+        }
+    }
+    return count;
+}
+
+U_CAPI UBool U_EXPORT2
+u_strHasMoreChar32Than(const UChar *s, int32_t length, int32_t number) {
+
+    if(number<0) {
+        return TRUE;
+    }
+    if(s==NULL || length<-1) {
+        return FALSE;
+    }
+
+    if(length==-1) {
+        /* s is NUL-terminated */
+        UChar c;
+
+        /* count code points until they exceed */
+        for(;;) {
+            if((c=*s++)==0) {
+                return FALSE;
+            }
+            if(number==0) {
+                return TRUE;
+            }
+            if(U16_IS_LEAD(c) && U16_IS_TRAIL(*s)) {
+                ++s;
+            }
+            --number;
+        }
+    } else {
+        /* length>=0 known */
+        const UChar *limit;
+        int32_t maxSupplementary;
+
+        /* s contains at least (length+1)/2 code points: <=2 UChars per cp */
+        if(((length+1)/2)>number) {
+            return TRUE;
+        }
+
+        /* check if s does not even contain enough UChars */
+        maxSupplementary=length-number;
+        if(maxSupplementary<=0) {
+            return FALSE;
+        }
+        /* there are maxSupplementary=length-number more UChars than asked-for code points */
+
+        /*
+         * count code points until they exceed and also check that there are
+         * no more than maxSupplementary supplementary code points (UChar pairs)
+         */
+        limit=s+length;
+        for(;;) {
+            if(s==limit) {
+                return FALSE;
+            }
+            if(number==0) {
+                return TRUE;
+            }
+            if(U16_IS_LEAD(*s++) && s!=limit && U16_IS_TRAIL(*s)) {
+                ++s;
+                if(--maxSupplementary<=0) {
+                    /* too many pairs - too few code points */
+                    return FALSE;
+                }
+            }
+            --number;
+        }
+    }
+}
+
+U_CAPI UChar * U_EXPORT2
+u_memcpy(UChar *dest, const UChar *src, int32_t count) {
+    return (UChar *)uprv_memcpy(dest, src, count*U_SIZEOF_UCHAR);
+}
+
+U_CAPI UChar * U_EXPORT2
+u_memmove(UChar *dest, const UChar *src, int32_t count) {
+    return (UChar *)uprv_memmove(dest, src, count*U_SIZEOF_UCHAR);
+}
+
+U_CAPI UChar * U_EXPORT2
+u_memset(UChar *dest, UChar c, int32_t count) {
+    if(count > 0) {
+        UChar *ptr = dest;
+        UChar *limit = dest + count;
+
+        while (ptr < limit) {
+            *(ptr++) = c;
+        }
+    }
+    return dest;
+}
+
+U_CAPI int32_t U_EXPORT2
+u_memcmp(const UChar *buf1, const UChar *buf2, int32_t count) {
+    if(count > 0) {
+        const UChar *limit = buf1 + count;
+        int32_t result;
+
+        while (buf1 < limit) {
+            result = (int32_t)(uint16_t)*buf1 - (int32_t)(uint16_t)*buf2;
+            if (result != 0) {
+                return result;
+            }
+            buf1++;
+            buf2++;
+        }
+    }
+    return 0;
+}
+
+U_CAPI int32_t U_EXPORT2
+u_memcmpCodePointOrder(const UChar *s1, const UChar *s2, int32_t count) {
+    return uprv_strCompare(s1, count, s2, count, FALSE, TRUE);
+}
+
+/* u_unescape & support fns ------------------------------------------------- */
+
+/* This map must be in ASCENDING ORDER OF THE ESCAPE CODE */
+static const UChar UNESCAPE_MAP[] = {
+    /*"   0x22, 0x22 */
+    /*'   0x27, 0x27 */
+    /*?   0x3F, 0x3F */
+    /*\   0x5C, 0x5C */
+    /*a*/ 0x61, 0x07,
+    /*b*/ 0x62, 0x08,
+    /*e*/ 0x65, 0x1b,
+    /*f*/ 0x66, 0x0c,
+    /*n*/ 0x6E, 0x0a,
+    /*r*/ 0x72, 0x0d,
+    /*t*/ 0x74, 0x09,
+    /*v*/ 0x76, 0x0b
+};
+enum { UNESCAPE_MAP_LENGTH = sizeof(UNESCAPE_MAP) / sizeof(UNESCAPE_MAP[0]) };
+
+/* Convert one octal digit to a numeric value 0..7, or -1 on failure */
+static int8_t _digit8(UChar c) {
+    if (c >= 0x0030 && c <= 0x0037) {
+        return (int8_t)(c - 0x0030);
+    }
+    return -1;
+}
+
+/* Convert one hex digit to a numeric value 0..F, or -1 on failure */
+static int8_t _digit16(UChar c) {
+    if (c >= 0x0030 && c <= 0x0039) {
+        return (int8_t)(c - 0x0030);
+    }
+    if (c >= 0x0041 && c <= 0x0046) {
+        return (int8_t)(c - (0x0041 - 10));
+    }
+    if (c >= 0x0061 && c <= 0x0066) {
+        return (int8_t)(c - (0x0061 - 10));
+    }
+    return -1;
+}
+
+/* Parse a single escape sequence.  Although this method deals in
+ * UChars, it does not use C++ or UnicodeString.  This allows it to
+ * be used from C contexts. */
+U_CAPI UChar32 U_EXPORT2
+u_unescapeAt(UNESCAPE_CHAR_AT charAt,
+             int32_t *offset,
+             int32_t length,
+             void *context) {
+
+    int32_t start = *offset;
+    UChar c;
+    UChar32 result = 0;
+    int8_t n = 0;
+    int8_t minDig = 0;
+    int8_t maxDig = 0;
+    int8_t bitsPerDigit = 4; 
+    int8_t dig;
+    int32_t i;
+    UBool braces = FALSE;
+
+    /* Check that offset is in range */
+    if (*offset < 0 || *offset >= length) {
+        goto err;
+    }
+
+    /* Fetch first UChar after '\\' */
+    c = charAt((*offset)++, context);
+
+    /* Convert hexadecimal and octal escapes */
+    switch (c) {
+    case 0x0075 /*'u'*/:
+        minDig = maxDig = 4;
+        break;
+    case 0x0055 /*'U'*/:
+        minDig = maxDig = 8;
+        break;
+    case 0x0078 /*'x'*/:
+        minDig = 1;
+        if (*offset < length && charAt(*offset, context) == 0x7B /*{*/) {
+            ++(*offset);
+            braces = TRUE;
+            maxDig = 8;
+        } else {
+            maxDig = 2;
+        }
+        break;
+    default:
+        dig = _digit8(c);
+        if (dig >= 0) {
+            minDig = 1;
+            maxDig = 3;
+            n = 1; /* Already have first octal digit */
+            bitsPerDigit = 3;
+            result = dig;
+        }
+        break;
+    }
+    if (minDig != 0) {
+        while (*offset < length && n < maxDig) {
+            c = charAt(*offset, context);
+            dig = (int8_t)((bitsPerDigit == 3) ? _digit8(c) : _digit16(c));
+            if (dig < 0) {
+                break;
+            }
+            result = (result << bitsPerDigit) | dig;
+            ++(*offset);
+            ++n;
+        }
+        if (n < minDig) {
+            goto err;
+        }
+        if (braces) {
+            if (c != 0x7D /*}*/) {
+                goto err;
+            }
+            ++(*offset);
+        }
+        if (result < 0 || result >= 0x110000) {
+            goto err;
+        }
+        /* If an escape sequence specifies a lead surrogate, see if
+         * there is a trail surrogate after it, either as an escape or
+         * as a literal.  If so, join them up into a supplementary.
+         */
+        if (*offset < length && U16_IS_LEAD(result)) {
+            int32_t ahead = *offset + 1;
+            c = charAt(*offset, context);
+            if (c == 0x5C /*'\\'*/ && ahead < length) {
+                c = (UChar) u_unescapeAt(charAt, &ahead, length, context);
+            }
+            if (U16_IS_TRAIL(c)) {
+                *offset = ahead;
+                result = U16_GET_SUPPLEMENTARY(result, c);
+            }
+        }
+        return result;
+    }
+
+    /* Convert C-style escapes in table */
+    for (i=0; i<UNESCAPE_MAP_LENGTH; i+=2) {
+        if (c == UNESCAPE_MAP[i]) {
+            return UNESCAPE_MAP[i+1];
+        } else if (c < UNESCAPE_MAP[i]) {
+            break;
+        }
+    }
+
+    /* Map \cX to control-X: X & 0x1F */
+    if (c == 0x0063 /*'c'*/ && *offset < length) {
+        c = charAt((*offset)++, context);
+        if (UTF_IS_FIRST_SURROGATE(c) && *offset < length) {
+            UChar c2 = charAt(*offset, context);
+            if (UTF_IS_SECOND_SURROGATE(c2)) {
+                ++(*offset);
+                c = (UChar) UTF16_GET_PAIR_VALUE(c, c2); /* [sic] */
+            }
+        }
+        return 0x1F & c;
+    }
+
+    /* If no special forms are recognized, then consider
+     * the backslash to generically escape the next character.
+     * Deal with surrogate pairs. */
+    if (UTF_IS_FIRST_SURROGATE(c) && *offset < length) {
+        UChar c2 = charAt(*offset, context);
+        if (UTF_IS_SECOND_SURROGATE(c2)) {
+            ++(*offset);
+            return UTF16_GET_PAIR_VALUE(c, c2);
+        }
+    }
+    return c;
+
+ err:
+    /* Invalid escape sequence */
+    *offset = start; /* Reset to initial value */
+    return (UChar32)0xFFFFFFFF;
+}
+
+/* u_unescapeAt() callback to return a UChar from a char* */
+static UChar U_CALLCONV
+_charPtr_charAt(int32_t offset, void *context) {
+    UChar c16;
+    /* It would be more efficient to access the invariant tables
+     * directly but there is no API for that. */
+    u_charsToUChars(((char*) context) + offset, &c16, 1);
+    return c16;
+}
+
+/* Append an escape-free segment of the text; used by u_unescape() */
+static void _appendUChars(UChar *dest, int32_t destCapacity,
+                          const char *src, int32_t srcLen) {
+    if (destCapacity < 0) {
+        destCapacity = 0;
+    }
+    if (srcLen > destCapacity) {
+        srcLen = destCapacity;
+    }
+    u_charsToUChars(src, dest, srcLen);
+}
+
+/* Do an invariant conversion of char* -> UChar*, with escape parsing */
+U_CAPI int32_t U_EXPORT2
+u_unescape(const char *src, UChar *dest, int32_t destCapacity) {
+    const char *segment = src;
+    int32_t i = 0;
+    char c;
+
+    while ((c=*src) != 0) {
+        /* '\\' intentionally written as compiler-specific
+         * character constant to correspond to compiler-specific
+         * char* constants. */
+        if (c == '\\') {
+            int32_t lenParsed = 0;
+            UChar32 c32;
+            if (src != segment) {
+                if (dest != NULL) {
+                    _appendUChars(dest + i, destCapacity - i,
+                                  segment, (int32_t)(src - segment));
+                }
+                i += (int32_t)(src - segment);
+            }
+            ++src; /* advance past '\\' */
+            c32 = (UChar32)u_unescapeAt(_charPtr_charAt, &lenParsed, (int32_t)uprv_strlen(src), (void*)src);
+            if (lenParsed == 0) {
+                goto err;
+            }
+            src += lenParsed; /* advance past escape seq. */
+            if (dest != NULL && UTF_CHAR_LENGTH(c32) <= (destCapacity - i)) {
+                UTF_APPEND_CHAR_UNSAFE(dest, i, c32);
+            } else {
+                i += UTF_CHAR_LENGTH(c32);
+            }
+            segment = src;
+        } else {
+            ++src;
+        }
+    }
+    if (src != segment) {
+        if (dest != NULL) {
+            _appendUChars(dest + i, destCapacity - i,
+                          segment, (int32_t)(src - segment));
+        }
+        i += (int32_t)(src - segment);
+    }
+    if (dest != NULL && i < destCapacity) {
+        dest[i] = 0;
+    }
+    return i;
+
+ err:
+    if (dest != NULL && destCapacity > 0) {
+        *dest = 0;
+    }
+    return 0;
+}
+
+/* NUL-termination of strings ----------------------------------------------- */
+
+/**
+ * NUL-terminate a string no matter what its type.
+ * Set warning and error codes accordingly.
+ */
+#define __TERMINATE_STRING(dest, destCapacity, length, pErrorCode)      \
+    if(pErrorCode!=NULL && U_SUCCESS(*pErrorCode)) {                    \
+        /* not a public function, so no complete argument checking */   \
+                                                                        \
+        if(length<0) {                                                  \
+            /* assume that the caller handles this */                   \
+        } else if(length<destCapacity) {                                \
+            /* NUL-terminate the string, the NUL fits */                \
+            dest[length]=0;                                             \
+            /* unset the not-terminated warning but leave all others */ \
+            if(*pErrorCode==U_STRING_NOT_TERMINATED_WARNING) {          \
+                *pErrorCode=U_ZERO_ERROR;                               \
+            }                                                           \
+        } else if(length==destCapacity) {                               \
+            /* unable to NUL-terminate, but the string itself fit - set a warning code */ \
+            *pErrorCode=U_STRING_NOT_TERMINATED_WARNING;                \
+        } else /* length>destCapacity */ {                              \
+            /* even the string itself did not fit - set an error code */ \
+            *pErrorCode=U_BUFFER_OVERFLOW_ERROR;                        \
+        }                                                               \
+    }
+
+U_CAPI int32_t U_EXPORT2
+u_terminateUChars(UChar *dest, int32_t destCapacity, int32_t length, UErrorCode *pErrorCode) {
+    __TERMINATE_STRING(dest, destCapacity, length, pErrorCode);
+    return length;
+}
+
+U_CAPI int32_t U_EXPORT2
+u_terminateChars(char *dest, int32_t destCapacity, int32_t length, UErrorCode *pErrorCode) {
+    __TERMINATE_STRING(dest, destCapacity, length, pErrorCode);
+    return length;
+}
+
+U_CAPI int32_t U_EXPORT2
+u_terminateUChar32s(UChar32 *dest, int32_t destCapacity, int32_t length, UErrorCode *pErrorCode) {
+    __TERMINATE_STRING(dest, destCapacity, length, pErrorCode);
+    return length;
+}
+
+U_CAPI int32_t U_EXPORT2
+u_terminateWChars(wchar_t *dest, int32_t destCapacity, int32_t length, UErrorCode *pErrorCode) {
+    __TERMINATE_STRING(dest, destCapacity, length, pErrorCode);
+    return length;
+}
diff --git a/source/common/ustrtrns.c b/source/common/ustrtrns.c
new file mode 100644
index 0000000..aa18ef5
--- /dev/null
+++ b/source/common/ustrtrns.c
@@ -0,0 +1,1640 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2001-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File ustrtrns.c
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   9/10/2001    Ram    Creation.
+******************************************************************************
+*/
+
+/*******************************************************************************
+ *
+ * u_strTo* and u_strFrom* APIs
+ * WCS functions moved to ustr_wcs.c for better modularization
+ *
+ *******************************************************************************
+ */
+
+
+#include "unicode/putil.h"
+#include "unicode/ustring.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include "ustr_imp.h"
+
+U_CAPI UChar* U_EXPORT2 
+u_strFromUTF32WithSub(UChar *dest,
+               int32_t destCapacity,
+               int32_t *pDestLength,
+               const UChar32 *src,
+               int32_t srcLength,
+               UChar32 subchar, int32_t *pNumSubstitutions,
+               UErrorCode *pErrorCode) {
+    const UChar32 *srcLimit;
+    UChar32 ch;
+    UChar *destLimit;
+    UChar *pDest;
+    int32_t reqLength;
+    int32_t numSubstitutions;
+
+    /* args check */
+    if(U_FAILURE(*pErrorCode)){
+        return NULL;
+    }
+    if( (src==NULL && srcLength!=0) || srcLength < -1 ||
+        (destCapacity<0) || (dest == NULL && destCapacity > 0) ||
+        subchar > 0x10ffff || U_IS_SURROGATE(subchar)
+    ) {
+        *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    if(pNumSubstitutions != NULL) {
+        *pNumSubstitutions = 0;
+    }
+
+    pDest = dest;
+    destLimit = dest + destCapacity;
+    reqLength = 0;
+    numSubstitutions = 0;
+
+    if(srcLength < 0) {
+        /* simple loop for conversion of a NUL-terminated BMP string */
+        while((ch=*src) != 0 &&
+              ((uint32_t)ch < 0xd800 || (0xe000 <= ch && ch <= 0xffff))) {
+            ++src;
+            if(pDest < destLimit) {
+                *pDest++ = (UChar)ch;
+            } else {
+                ++reqLength;
+            }
+        }
+        srcLimit = src;
+        if(ch != 0) {
+            /* "complicated" case, find the end of the remaining string */
+            while(*++srcLimit != 0) {}
+        }
+    } else {
+        srcLimit = src + srcLength;
+    }
+
+    /* convert with length */
+    while(src < srcLimit) {
+        ch = *src++;
+        do {
+            /* usually "loops" once; twice only for writing subchar */
+            if((uint32_t)ch < 0xd800 || (0xe000 <= ch && ch <= 0xffff)) {
+                if(pDest < destLimit) {
+                    *pDest++ = (UChar)ch;
+                } else {
+                    ++reqLength;
+                }
+                break;
+            } else if(0x10000 <= ch && ch <= 0x10ffff) {
+                if((pDest + 2) <= destLimit) {
+                    *pDest++ = U16_LEAD(ch);
+                    *pDest++ = U16_TRAIL(ch);
+                } else {
+                    reqLength += 2;
+                }
+                break;
+            } else if((ch = subchar) < 0) {
+                /* surrogate code point, or not a Unicode code point at all */
+                *pErrorCode = U_INVALID_CHAR_FOUND;
+                return NULL;
+            } else {
+                ++numSubstitutions;
+            }
+        } while(TRUE);
+    }
+
+    reqLength += (int32_t)(pDest - dest);
+    if(pDestLength) {
+        *pDestLength = reqLength;
+    }
+    if(pNumSubstitutions != NULL) {
+        *pNumSubstitutions = numSubstitutions;
+    }
+
+    /* Terminate the buffer */
+    u_terminateUChars(dest, destCapacity, reqLength, pErrorCode);
+    
+    return dest;
+}
+
+U_CAPI UChar* U_EXPORT2 
+u_strFromUTF32(UChar *dest,
+               int32_t destCapacity, 
+               int32_t *pDestLength,
+               const UChar32 *src,
+               int32_t srcLength,
+               UErrorCode *pErrorCode) {
+    return u_strFromUTF32WithSub(
+            dest, destCapacity, pDestLength,
+            src, srcLength,
+            U_SENTINEL, NULL,
+            pErrorCode);
+}
+
+U_CAPI UChar32* U_EXPORT2 
+u_strToUTF32WithSub(UChar32 *dest,
+             int32_t destCapacity,
+             int32_t *pDestLength,
+             const UChar *src,
+             int32_t srcLength,
+             UChar32 subchar, int32_t *pNumSubstitutions,
+             UErrorCode *pErrorCode) {
+    const UChar *srcLimit;
+    UChar32 ch;
+    UChar ch2;
+    UChar32 *destLimit;
+    UChar32 *pDest;
+    int32_t reqLength;
+    int32_t numSubstitutions;
+
+    /* args check */
+    if(U_FAILURE(*pErrorCode)){
+        return NULL;
+    }
+    if( (src==NULL && srcLength!=0) || srcLength < -1 ||
+        (destCapacity<0) || (dest == NULL && destCapacity > 0) ||
+        subchar > 0x10ffff || U_IS_SURROGATE(subchar)
+    ) {
+        *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    if(pNumSubstitutions != NULL) {
+        *pNumSubstitutions = 0;
+    }
+
+    pDest = dest;
+    destLimit = dest + destCapacity;
+    reqLength = 0;
+    numSubstitutions = 0;
+
+    if(srcLength < 0) {
+        /* simple loop for conversion of a NUL-terminated BMP string */
+        while((ch=*src) != 0 && !U16_IS_SURROGATE(ch)) {
+            ++src;
+            if(pDest < destLimit) {
+                *pDest++ = ch;
+            } else {
+                ++reqLength;
+            }
+        }
+        srcLimit = src;
+        if(ch != 0) {
+            /* "complicated" case, find the end of the remaining string */
+            while(*++srcLimit != 0) {}
+        }
+    } else {
+        srcLimit = src + srcLength;
+    }
+
+    /* convert with length */
+    while(src < srcLimit) {
+        ch = *src++;
+        if(!U16_IS_SURROGATE(ch)) {
+            /* write or count ch below */
+        } else if(U16_IS_SURROGATE_LEAD(ch) && src < srcLimit && U16_IS_TRAIL(ch2 = *src)) {
+            ++src;
+            ch = U16_GET_SUPPLEMENTARY(ch, ch2);
+        } else if((ch = subchar) < 0) {
+            /* unpaired surrogate */
+            *pErrorCode = U_INVALID_CHAR_FOUND;
+            return NULL;
+        } else {
+            ++numSubstitutions;
+        }
+        if(pDest < destLimit) {
+            *pDest++ = ch;
+        } else {
+            ++reqLength;
+        }
+    }
+
+    reqLength += (int32_t)(pDest - dest);
+    if(pDestLength) {
+        *pDestLength = reqLength;
+    }
+    if(pNumSubstitutions != NULL) {
+        *pNumSubstitutions = numSubstitutions;
+    }
+
+    /* Terminate the buffer */
+    u_terminateUChar32s(dest, destCapacity, reqLength, pErrorCode);
+
+    return dest;
+}
+
+U_CAPI UChar32* U_EXPORT2 
+u_strToUTF32(UChar32 *dest, 
+             int32_t destCapacity,
+             int32_t *pDestLength,
+             const UChar *src, 
+             int32_t srcLength,
+             UErrorCode *pErrorCode) {
+    return u_strToUTF32WithSub(
+            dest, destCapacity, pDestLength,
+            src, srcLength,
+            U_SENTINEL, NULL,
+            pErrorCode);
+}
+
+/* for utf8_nextCharSafeBodyTerminated() */
+static const UChar32
+utf8_minLegal[4]={ 0, 0x80, 0x800, 0x10000 };
+
+/*
+ * Version of utf8_nextCharSafeBody() with the following differences:
+ * - checks for NUL termination instead of length
+ * - works with pointers instead of indexes
+ * - always strict (strict==-1)
+ *
+ * *ps points to after the lead byte and will be moved to after the last trail byte.
+ * c is the lead byte.
+ * @return the code point, or U_SENTINEL
+ */
+static UChar32
+utf8_nextCharSafeBodyTerminated(const uint8_t **ps, UChar32 c) {
+    const uint8_t *s=*ps;
+    uint8_t trail, illegal=0;
+    uint8_t count=UTF8_COUNT_TRAIL_BYTES(c);
+    UTF8_MASK_LEAD_BYTE((c), count);
+    /* count==0 for illegally leading trail bytes and the illegal bytes 0xfe and 0xff */
+    switch(count) {
+    /* each branch falls through to the next one */
+    case 5:
+    case 4:
+        /* count>=4 is always illegal: no more than 3 trail bytes in Unicode's UTF-8 */
+        illegal=1;
+        break;
+    case 3:
+        trail=(uint8_t)(*s++ - 0x80);
+        c=(c<<6)|trail;
+        if(trail>0x3f || c>=0x110) {
+            /* not a trail byte, or code point>0x10ffff (outside Unicode) */
+            illegal=1;
+            break;
+        }
+    case 2:
+        trail=(uint8_t)(*s++ - 0x80);
+        if(trail>0x3f) {
+            /* not a trail byte */
+            illegal=1;
+            break;
+        }
+        c=(c<<6)|trail;
+    case 1:
+        trail=(uint8_t)(*s++ - 0x80);
+        if(trail>0x3f) {
+            /* not a trail byte */
+            illegal=1;
+        }
+        c=(c<<6)|trail;
+        break;
+    case 0:
+        return U_SENTINEL;
+    /* no default branch to optimize switch()  - all values are covered */
+    }
+
+    /* correct sequence - all trail bytes have (b7..b6)==(10)? */
+    /* illegal is also set if count>=4 */
+    if(illegal || c<utf8_minLegal[count] || UTF_IS_SURROGATE(c)) {
+        /* error handling */
+        /* don't go beyond this sequence */
+        s=*ps;
+        while(count>0 && UTF8_IS_TRAIL(*s)) {
+            ++s;
+            --count;
+        }
+        c=U_SENTINEL;
+    }
+    *ps=s;
+    return c;
+}
+
+/*
+ * Version of utf8_nextCharSafeBody() with the following differences:
+ * - works with pointers instead of indexes
+ * - always strict (strict==-1)
+ *
+ * *ps points to after the lead byte and will be moved to after the last trail byte.
+ * c is the lead byte.
+ * @return the code point, or U_SENTINEL
+ */
+static UChar32
+utf8_nextCharSafeBodyPointer(const uint8_t **ps, const uint8_t *limit, UChar32 c) {
+    const uint8_t *s=*ps;
+    uint8_t trail, illegal=0;
+    uint8_t count=UTF8_COUNT_TRAIL_BYTES(c);
+    if((limit-s)>=count) {
+        UTF8_MASK_LEAD_BYTE((c), count);
+        /* count==0 for illegally leading trail bytes and the illegal bytes 0xfe and 0xff */
+        switch(count) {
+        /* each branch falls through to the next one */
+        case 5:
+        case 4:
+            /* count>=4 is always illegal: no more than 3 trail bytes in Unicode's UTF-8 */
+            illegal=1;
+            break;
+        case 3:
+            trail=*s++;
+            c=(c<<6)|(trail&0x3f);
+            if(c<0x110) {
+                illegal|=(trail&0xc0)^0x80;
+            } else {
+                /* code point>0x10ffff, outside Unicode */
+                illegal=1;
+                break;
+            }
+        case 2:
+            trail=*s++;
+            c=(c<<6)|(trail&0x3f);
+            illegal|=(trail&0xc0)^0x80;
+        case 1:
+            trail=*s++;
+            c=(c<<6)|(trail&0x3f);
+            illegal|=(trail&0xc0)^0x80;
+            break;
+        case 0:
+            return U_SENTINEL;
+        /* no default branch to optimize switch()  - all values are covered */
+        }
+    } else {
+        illegal=1; /* too few bytes left */
+    }
+
+    /* correct sequence - all trail bytes have (b7..b6)==(10)? */
+    /* illegal is also set if count>=4 */
+    if(illegal || c<utf8_minLegal[count] || UTF_IS_SURROGATE(c)) {
+        /* error handling */
+        /* don't go beyond this sequence */
+        s=*ps;
+        while(count>0 && s<limit && UTF8_IS_TRAIL(*s)) {
+            ++s;
+            --count;
+        }
+        c=U_SENTINEL;
+    }
+    *ps=s;
+    return c;
+}
+
+U_CAPI UChar* U_EXPORT2
+u_strFromUTF8WithSub(UChar *dest,
+              int32_t destCapacity,
+              int32_t *pDestLength,
+              const char* src,
+              int32_t srcLength,
+              UChar32 subchar, int32_t *pNumSubstitutions,
+              UErrorCode *pErrorCode){
+    UChar *pDest = dest;
+    UChar *pDestLimit = dest+destCapacity;
+    UChar32 ch;
+    int32_t reqLength = 0;
+    const uint8_t* pSrc = (const uint8_t*) src;
+    uint8_t t1, t2; /* trail bytes */
+    int32_t numSubstitutions;
+
+    /* args check */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)){
+        return NULL;
+    }
+        
+    if( (src==NULL && srcLength!=0) || srcLength < -1 ||
+        (destCapacity<0) || (dest == NULL && destCapacity > 0) ||
+        subchar > 0x10ffff || U_IS_SURROGATE(subchar)
+    ) {
+        *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    if(pNumSubstitutions!=NULL) {
+        *pNumSubstitutions=0;
+    }
+    numSubstitutions=0;
+
+    /*
+     * Inline processing of UTF-8 byte sequences:
+     *
+     * Byte sequences for the most common characters are handled inline in
+     * the conversion loops. In order to reduce the path lengths for those
+     * characters, the tests are arranged in a kind of binary search.
+     * ASCII (<=0x7f) is checked first, followed by the dividing point
+     * between 2- and 3-byte sequences (0xe0).
+     * The 3-byte branch is tested first to speed up CJK text.
+     * The compiler should combine the subtractions for the two tests for 0xe0.
+     * Each branch then tests for the other end of its range.
+     */
+
+    if(srcLength < 0){
+        /*
+         * Transform a NUL-terminated string.
+         * The code explicitly checks for NULs only in the lead byte position.
+         * A NUL byte in the trail byte position fails the trail byte range check anyway.
+         */
+        while(((ch = *pSrc) != 0) && (pDest < pDestLimit)) {
+            if(ch <= 0x7f){
+                *pDest++=(UChar)ch;
+                ++pSrc;
+            } else {
+                if(ch > 0xe0) {
+                    if( /* handle U+1000..U+CFFF inline */
+                        ch <= 0xec &&
+                        (t1 = (uint8_t)(pSrc[1] - 0x80)) <= 0x3f &&
+                        (t2 = (uint8_t)(pSrc[2] - 0x80)) <= 0x3f
+                    ) {
+                        /* no need for (ch & 0xf) because the upper bits are truncated after <<12 in the cast to (UChar) */
+                        *pDest++ = (UChar)((ch << 12) | (t1 << 6) | t2);
+                        pSrc += 3;
+                        continue;
+                    }
+                } else if(ch < 0xe0) {
+                    if( /* handle U+0080..U+07FF inline */
+                        ch >= 0xc2 &&
+                        (t1 = (uint8_t)(pSrc[1] - 0x80)) <= 0x3f
+                    ) {
+                        *pDest++ = (UChar)(((ch & 0x1f) << 6) | t1);
+                        pSrc += 2;
+                        continue;
+                    }
+                }
+
+                /* function call for "complicated" and error cases */
+                ++pSrc; /* continue after the lead byte */
+                ch=utf8_nextCharSafeBodyTerminated(&pSrc, ch);
+                if(ch<0 && (++numSubstitutions, ch = subchar) < 0) {
+                    *pErrorCode = U_INVALID_CHAR_FOUND;
+                    return NULL;
+                } else if(ch<=0xFFFF) {
+                    *(pDest++)=(UChar)ch;
+                } else {
+                    *(pDest++)=UTF16_LEAD(ch);
+                    if(pDest<pDestLimit) {
+                        *(pDest++)=UTF16_TRAIL(ch);
+                    } else {
+                        reqLength++;
+                        break;
+                    }
+                }
+            }
+        }
+
+        /* Pre-flight the rest of the string. */
+        while((ch = *pSrc) != 0) {
+            if(ch <= 0x7f){
+                ++reqLength;
+                ++pSrc;
+            } else {
+                if(ch > 0xe0) {
+                    if( /* handle U+1000..U+CFFF inline */
+                        ch <= 0xec &&
+                        (uint8_t)(pSrc[1] - 0x80) <= 0x3f &&
+                        (uint8_t)(pSrc[2] - 0x80) <= 0x3f
+                    ) {
+                        ++reqLength;
+                        pSrc += 3;
+                        continue;
+                    }
+                } else if(ch < 0xe0) {
+                    if( /* handle U+0080..U+07FF inline */
+                        ch >= 0xc2 &&
+                        (uint8_t)(pSrc[1] - 0x80) <= 0x3f
+                    ) {
+                        ++reqLength;
+                        pSrc += 2;
+                        continue;
+                    }
+                }
+
+                /* function call for "complicated" and error cases */
+                ++pSrc; /* continue after the lead byte */
+                ch=utf8_nextCharSafeBodyTerminated(&pSrc, ch);
+                if(ch<0 && (++numSubstitutions, ch = subchar) < 0) {
+                    *pErrorCode = U_INVALID_CHAR_FOUND;
+                    return NULL;
+                }
+                reqLength += U16_LENGTH(ch);
+            }
+        }
+    } else /* srcLength >= 0 */ {
+        const uint8_t *pSrcLimit = pSrc + srcLength;
+        int32_t count;
+
+        /* Faster loop without ongoing checking for pSrcLimit and pDestLimit. */
+        for(;;) {
+            /*
+             * Each iteration of the inner loop progresses by at most 3 UTF-8
+             * bytes and one UChar, for most characters.
+             * For supplementary code points (4 & 2), which are rare,
+             * there is an additional adjustment.
+             */
+            count = (int32_t)(pDestLimit - pDest);
+            srcLength = (int32_t)((pSrcLimit - pSrc) / 3);
+            if(count > srcLength) {
+                count = srcLength; /* min(remaining dest, remaining src/3) */
+            }
+            if(count < 3) {
+                /*
+                 * Too much overhead if we get near the end of the string,
+                 * continue with the next loop.
+                 */
+                break;
+            }
+
+            do {
+                ch = *pSrc;
+                if(ch <= 0x7f){
+                    *pDest++=(UChar)ch;
+                    ++pSrc;
+                } else {
+                    if(ch > 0xe0) {
+                        if( /* handle U+1000..U+CFFF inline */
+                            ch <= 0xec &&
+                            (t1 = (uint8_t)(pSrc[1] - 0x80)) <= 0x3f &&
+                            (t2 = (uint8_t)(pSrc[2] - 0x80)) <= 0x3f
+                        ) {
+                            /* no need for (ch & 0xf) because the upper bits are truncated after <<12 in the cast to (UChar) */
+                            *pDest++ = (UChar)((ch << 12) | (t1 << 6) | t2);
+                            pSrc += 3;
+                            continue;
+                        }
+                    } else if(ch < 0xe0) {
+                        if( /* handle U+0080..U+07FF inline */
+                            ch >= 0xc2 &&
+                            (t1 = (uint8_t)(pSrc[1] - 0x80)) <= 0x3f
+                        ) {
+                            *pDest++ = (UChar)(((ch & 0x1f) << 6) | t1);
+                            pSrc += 2;
+                            continue;
+                        }
+                    }
+
+                    if(ch >= 0xf0 || subchar > 0xffff) {
+                        /*
+                         * We may read up to six bytes and write up to two UChars,
+                         * which we didn't account for with computing count,
+                         * so we adjust it here.
+                         */
+                        if(--count == 0) {
+                            break;
+                        }
+                    }
+
+                    /* function call for "complicated" and error cases */
+                    ++pSrc; /* continue after the lead byte */
+                    ch=utf8_nextCharSafeBodyPointer(&pSrc, pSrcLimit, ch);
+                    if(ch<0 && (++numSubstitutions, ch = subchar) < 0){
+                        *pErrorCode = U_INVALID_CHAR_FOUND;
+                        return NULL;
+                    }else if(ch<=0xFFFF){
+                        *(pDest++)=(UChar)ch;
+                    }else{
+                        *(pDest++)=UTF16_LEAD(ch);
+                        *(pDest++)=UTF16_TRAIL(ch);
+                    }
+                }
+            } while(--count > 0);
+        }
+
+        while((pSrc<pSrcLimit) && (pDest<pDestLimit)) {
+            ch = *pSrc;
+            if(ch <= 0x7f){
+                *pDest++=(UChar)ch;
+                ++pSrc;
+            } else {
+                if(ch > 0xe0) {
+                    if( /* handle U+1000..U+CFFF inline */
+                        ch <= 0xec &&
+                        ((pSrcLimit - pSrc) >= 3) &&
+                        (t1 = (uint8_t)(pSrc[1] - 0x80)) <= 0x3f &&
+                        (t2 = (uint8_t)(pSrc[2] - 0x80)) <= 0x3f
+                    ) {
+                        /* no need for (ch & 0xf) because the upper bits are truncated after <<12 in the cast to (UChar) */
+                        *pDest++ = (UChar)((ch << 12) | (t1 << 6) | t2);
+                        pSrc += 3;
+                        continue;
+                    }
+                } else if(ch < 0xe0) {
+                    if( /* handle U+0080..U+07FF inline */
+                        ch >= 0xc2 &&
+                        ((pSrcLimit - pSrc) >= 2) &&
+                        (t1 = (uint8_t)(pSrc[1] - 0x80)) <= 0x3f
+                    ) {
+                        *pDest++ = (UChar)(((ch & 0x1f) << 6) | t1);
+                        pSrc += 2;
+                        continue;
+                    }
+                }
+
+                /* function call for "complicated" and error cases */
+                ++pSrc; /* continue after the lead byte */
+                ch=utf8_nextCharSafeBodyPointer(&pSrc, pSrcLimit, ch);
+                if(ch<0 && (++numSubstitutions, ch = subchar) < 0){
+                    *pErrorCode = U_INVALID_CHAR_FOUND;
+                    return NULL;
+                }else if(ch<=0xFFFF){
+                    *(pDest++)=(UChar)ch;
+                }else{
+                    *(pDest++)=UTF16_LEAD(ch);
+                    if(pDest<pDestLimit){
+                        *(pDest++)=UTF16_TRAIL(ch);
+                    }else{
+                        reqLength++;
+                        break;
+                    }
+                }
+            }
+        }
+        /* do not fill the dest buffer just count the UChars needed */
+        while(pSrc < pSrcLimit){
+            ch = *pSrc;
+            if(ch <= 0x7f){
+                reqLength++;
+                ++pSrc;
+            } else {
+                if(ch > 0xe0) {
+                    if( /* handle U+1000..U+CFFF inline */
+                        ch <= 0xec &&
+                        ((pSrcLimit - pSrc) >= 3) &&
+                        (uint8_t)(pSrc[1] - 0x80) <= 0x3f &&
+                        (uint8_t)(pSrc[2] - 0x80) <= 0x3f
+                    ) {
+                        reqLength++;
+                        pSrc += 3;
+                        continue;
+                    }
+                } else if(ch < 0xe0) {
+                    if( /* handle U+0080..U+07FF inline */
+                        ch >= 0xc2 &&
+                        ((pSrcLimit - pSrc) >= 2) &&
+                        (uint8_t)(pSrc[1] - 0x80) <= 0x3f
+                    ) {
+                        reqLength++;
+                        pSrc += 2;
+                        continue;
+                    }
+                }
+
+                /* function call for "complicated" and error cases */
+                ++pSrc; /* continue after the lead byte */
+                ch=utf8_nextCharSafeBodyPointer(&pSrc, pSrcLimit, ch);
+                if(ch<0 && (++numSubstitutions, ch = subchar) < 0){
+                    *pErrorCode = U_INVALID_CHAR_FOUND;
+                    return NULL;
+                }
+                reqLength+=UTF_CHAR_LENGTH(ch);
+            }
+        }
+    }
+
+    reqLength+=(int32_t)(pDest - dest);
+
+    if(pNumSubstitutions!=NULL) {
+        *pNumSubstitutions=numSubstitutions;
+    }
+
+    if(pDestLength){
+        *pDestLength = reqLength;
+    }
+
+    /* Terminate the buffer */
+    u_terminateUChars(dest,destCapacity,reqLength,pErrorCode);
+
+    return dest;
+}
+
+U_CAPI UChar* U_EXPORT2
+u_strFromUTF8(UChar *dest,
+              int32_t destCapacity,
+              int32_t *pDestLength,
+              const char* src,
+              int32_t srcLength,
+              UErrorCode *pErrorCode){
+    return u_strFromUTF8WithSub(
+            dest, destCapacity, pDestLength,
+            src, srcLength,
+            U_SENTINEL, NULL,
+            pErrorCode);
+}
+
+U_CAPI UChar * U_EXPORT2
+u_strFromUTF8Lenient(UChar *dest,
+                     int32_t destCapacity,
+                     int32_t *pDestLength,
+                     const char *src,
+                     int32_t srcLength,
+                     UErrorCode *pErrorCode) {
+    UChar *pDest = dest;
+    UChar32 ch;
+    int32_t reqLength = 0;
+    uint8_t* pSrc = (uint8_t*) src;
+
+    /* args check */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)){
+        return NULL;
+    }
+        
+    if( (src==NULL && srcLength!=0) || srcLength < -1 ||
+        (destCapacity<0) || (dest == NULL && destCapacity > 0)
+    ) {
+        *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    if(srcLength < 0) {
+        /* Transform a NUL-terminated string. */
+        UChar *pDestLimit = dest+destCapacity;
+        uint8_t t1, t2, t3; /* trail bytes */
+
+        while(((ch = *pSrc) != 0) && (pDest < pDestLimit)) {
+            if(ch < 0xc0) {
+                /*
+                 * ASCII, or a trail byte in lead position which is treated like
+                 * a single-byte sequence for better character boundary
+                 * resynchronization after illegal sequences.
+                 */
+                *pDest++=(UChar)ch;
+                ++pSrc;
+                continue;
+            } else if(ch < 0xe0) { /* U+0080..U+07FF */
+                if((t1 = pSrc[1]) != 0) {
+                    /* 0x3080 = (0xc0 << 6) + 0x80 */
+                    *pDest++ = (UChar)((ch << 6) + t1 - 0x3080);
+                    pSrc += 2;
+                    continue;
+                }
+            } else if(ch < 0xf0) { /* U+0800..U+FFFF */
+                if((t1 = pSrc[1]) != 0 && (t2 = pSrc[2]) != 0) {
+                    /* no need for (ch & 0xf) because the upper bits are truncated after <<12 in the cast to (UChar) */
+                    /* 0x2080 = (0x80 << 6) + 0x80 */
+                    *pDest++ = (UChar)((ch << 12) + (t1 << 6) + t2 - 0x2080);
+                    pSrc += 3;
+                    continue;
+                }
+            } else /* f0..f4 */ { /* U+10000..U+10FFFF */
+                if((t1 = pSrc[1]) != 0 && (t2 = pSrc[2]) != 0 && (t3 = pSrc[3]) != 0) {
+                    pSrc += 4;
+                    /* 0x3c82080 = (0xf0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */
+                    ch = (ch << 18) + (t1 << 12) + (t2 << 6) + t3 - 0x3c82080;
+                    *(pDest++) = U16_LEAD(ch);
+                    if(pDest < pDestLimit) {
+                        *(pDest++) = U16_TRAIL(ch);
+                    } else {
+                        reqLength = 1;
+                        break;
+                    }
+                    continue;
+                }
+            }
+
+            /* truncated character at the end */
+            *pDest++ = 0xfffd;
+            while(*++pSrc != 0) {}
+            break;
+        }
+
+        /* Pre-flight the rest of the string. */
+        while((ch = *pSrc) != 0) {
+            if(ch < 0xc0) {
+                /*
+                 * ASCII, or a trail byte in lead position which is treated like
+                 * a single-byte sequence for better character boundary
+                 * resynchronization after illegal sequences.
+                 */
+                ++reqLength;
+                ++pSrc;
+                continue;
+            } else if(ch < 0xe0) { /* U+0080..U+07FF */
+                if(pSrc[1] != 0) {
+                    ++reqLength;
+                    pSrc += 2;
+                    continue;
+                }
+            } else if(ch < 0xf0) { /* U+0800..U+FFFF */
+                if(pSrc[1] != 0 && pSrc[2] != 0) {
+                    ++reqLength;
+                    pSrc += 3;
+                    continue;
+                }
+            } else /* f0..f4 */ { /* U+10000..U+10FFFF */
+                if(pSrc[1] != 0 && pSrc[2] != 0 && pSrc[3] != 0) {
+                    reqLength += 2;
+                    pSrc += 4;
+                    continue;
+                }
+            }
+
+            /* truncated character at the end */
+            ++reqLength;
+            break;
+        }
+    } else /* srcLength >= 0 */ {
+        const uint8_t *pSrcLimit = pSrc + srcLength;
+
+        /*
+         * This function requires that if srcLength is given, then it must be
+         * destCapatity >= srcLength so that we need not check for
+         * destination buffer overflow in the loop.
+         */
+        if(destCapacity < srcLength) {
+            if(pDestLength != NULL) {
+                *pDestLength = srcLength; /* this likely overestimates the true destLength! */
+            }
+            *pErrorCode = U_BUFFER_OVERFLOW_ERROR;
+            return NULL;
+        }
+
+        if((pSrcLimit - pSrc) >= 4) {
+            pSrcLimit -= 3; /* temporarily reduce pSrcLimit */
+
+            /* in this loop, we can always access at least 4 bytes, up to pSrc+3 */
+            do {
+                ch = *pSrc++;
+                if(ch < 0xc0) {
+                    /*
+                     * ASCII, or a trail byte in lead position which is treated like
+                     * a single-byte sequence for better character boundary
+                     * resynchronization after illegal sequences.
+                     */
+                    *pDest++=(UChar)ch;
+                } else if(ch < 0xe0) { /* U+0080..U+07FF */
+                    /* 0x3080 = (0xc0 << 6) + 0x80 */
+                    *pDest++ = (UChar)((ch << 6) + *pSrc++ - 0x3080);
+                } else if(ch < 0xf0) { /* U+0800..U+FFFF */
+                    /* no need for (ch & 0xf) because the upper bits are truncated after <<12 in the cast to (UChar) */
+                    /* 0x2080 = (0x80 << 6) + 0x80 */
+                    ch = (ch << 12) + (*pSrc++ << 6);
+                    *pDest++ = (UChar)(ch + *pSrc++ - 0x2080);
+                } else /* f0..f4 */ { /* U+10000..U+10FFFF */
+                    /* 0x3c82080 = (0xf0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */
+                    ch = (ch << 18) + (*pSrc++ << 12);
+                    ch += *pSrc++ << 6;
+                    ch += *pSrc++ - 0x3c82080;
+                    *(pDest++) = U16_LEAD(ch);
+                    *(pDest++) = U16_TRAIL(ch);
+                }
+            } while(pSrc < pSrcLimit);
+
+            pSrcLimit += 3; /* restore original pSrcLimit */
+        }
+
+        while(pSrc < pSrcLimit) {
+            ch = *pSrc++;
+            if(ch < 0xc0) {
+                /*
+                 * ASCII, or a trail byte in lead position which is treated like
+                 * a single-byte sequence for better character boundary
+                 * resynchronization after illegal sequences.
+                 */
+                *pDest++=(UChar)ch;
+                continue;
+            } else if(ch < 0xe0) { /* U+0080..U+07FF */
+                if(pSrc < pSrcLimit) {
+                    /* 0x3080 = (0xc0 << 6) + 0x80 */
+                    *pDest++ = (UChar)((ch << 6) + *pSrc++ - 0x3080);
+                    continue;
+                }
+            } else if(ch < 0xf0) { /* U+0800..U+FFFF */
+                if((pSrcLimit - pSrc) >= 2) {
+                    /* no need for (ch & 0xf) because the upper bits are truncated after <<12 in the cast to (UChar) */
+                    /* 0x2080 = (0x80 << 6) + 0x80 */
+                    ch = (ch << 12) + (*pSrc++ << 6);
+                    *pDest++ = (UChar)(ch + *pSrc++ - 0x2080);
+                    pSrc += 3;
+                    continue;
+                }
+            } else /* f0..f4 */ { /* U+10000..U+10FFFF */
+                if((pSrcLimit - pSrc) >= 3) {
+                    /* 0x3c82080 = (0xf0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */
+                    ch = (ch << 18) + (*pSrc++ << 12);
+                    ch += *pSrc++ << 6;
+                    ch += *pSrc++ - 0x3c82080;
+                    *(pDest++) = U16_LEAD(ch);
+                    *(pDest++) = U16_TRAIL(ch);
+                    pSrc += 4;
+                    continue;
+                }
+            }
+
+            /* truncated character at the end */
+            *pDest++ = 0xfffd;
+            break;
+        }
+    }
+
+    reqLength+=(int32_t)(pDest - dest);
+
+    if(pDestLength){
+        *pDestLength = reqLength;
+    }
+
+    /* Terminate the buffer */
+    u_terminateUChars(dest,destCapacity,reqLength,pErrorCode);
+
+    return dest;
+}
+
+static U_INLINE uint8_t *
+_appendUTF8(uint8_t *pDest, UChar32 c) {
+    /* it is 0<=c<=0x10ffff and not a surrogate if called by a validating function */
+    if((c)<=0x7f) {
+        *pDest++=(uint8_t)c;
+    } else if(c<=0x7ff) {
+        *pDest++=(uint8_t)((c>>6)|0xc0);
+        *pDest++=(uint8_t)((c&0x3f)|0x80);
+    } else if(c<=0xffff) {
+        *pDest++=(uint8_t)((c>>12)|0xe0);
+        *pDest++=(uint8_t)(((c>>6)&0x3f)|0x80);
+        *pDest++=(uint8_t)(((c)&0x3f)|0x80);
+    } else /* if((uint32_t)(c)<=0x10ffff) */ {
+        *pDest++=(uint8_t)(((c)>>18)|0xf0);
+        *pDest++=(uint8_t)((((c)>>12)&0x3f)|0x80);
+        *pDest++=(uint8_t)((((c)>>6)&0x3f)|0x80);
+        *pDest++=(uint8_t)(((c)&0x3f)|0x80);
+    }
+    return pDest;
+}
+
+   
+U_CAPI char* U_EXPORT2 
+u_strToUTF8WithSub(char *dest,
+            int32_t destCapacity,
+            int32_t *pDestLength,
+            const UChar *pSrc,
+            int32_t srcLength,
+            UChar32 subchar, int32_t *pNumSubstitutions,
+            UErrorCode *pErrorCode){
+    int32_t reqLength=0;
+    uint32_t ch=0,ch2=0;
+    uint8_t *pDest = (uint8_t *)dest;
+    uint8_t *pDestLimit = pDest + destCapacity;
+    int32_t numSubstitutions;
+
+    /* args check */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)){
+        return NULL;
+    }
+        
+    if( (pSrc==NULL && srcLength!=0) || srcLength < -1 ||
+        (destCapacity<0) || (dest == NULL && destCapacity > 0) ||
+        subchar > 0x10ffff || U_IS_SURROGATE(subchar)
+    ) {
+        *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    if(pNumSubstitutions!=NULL) {
+        *pNumSubstitutions=0;
+    }
+    numSubstitutions=0;
+
+    if(srcLength==-1) {
+        while((ch=*pSrc)!=0) {
+            ++pSrc;
+            if(ch <= 0x7f) {
+                if(pDest<pDestLimit) {
+                    *pDest++ = (uint8_t)ch;
+                } else {
+                    reqLength = 1;
+                    break;
+                }
+            } else if(ch <= 0x7ff) {
+                if((pDestLimit - pDest) >= 2) {
+                    *pDest++=(uint8_t)((ch>>6)|0xc0);
+                    *pDest++=(uint8_t)((ch&0x3f)|0x80);
+                } else {
+                    reqLength = 2;
+                    break;
+                }
+            } else if(ch <= 0xd7ff || ch >= 0xe000) {
+                if((pDestLimit - pDest) >= 3) {
+                    *pDest++=(uint8_t)((ch>>12)|0xe0);
+                    *pDest++=(uint8_t)(((ch>>6)&0x3f)|0x80);
+                    *pDest++=(uint8_t)((ch&0x3f)|0x80);
+                } else {
+                    reqLength = 3;
+                    break;
+                }
+            } else /* ch is a surrogate */ {
+                int32_t length;
+
+                /*need not check for NUL because NUL fails UTF_IS_TRAIL() anyway*/
+                if(UTF_IS_SURROGATE_FIRST(ch) && UTF_IS_TRAIL(ch2=*pSrc)) { 
+                    ++pSrc;
+                    ch=UTF16_GET_PAIR_VALUE(ch, ch2);
+                } else if(subchar>=0) {
+                    ch=subchar;
+                    ++numSubstitutions;
+                } else {
+                    /* Unicode 3.2 forbids surrogate code points in UTF-8 */
+                    *pErrorCode = U_INVALID_CHAR_FOUND;
+                    return NULL;
+                }
+
+                length = U8_LENGTH(ch);
+                if((pDestLimit - pDest) >= length) {
+                    /* convert and append*/
+                    pDest=_appendUTF8(pDest, ch);
+                } else {
+                    reqLength = length;
+                    break;
+                }
+            }
+        }
+        while((ch=*pSrc++)!=0) {
+            if(ch<=0x7f) {
+                ++reqLength;
+            } else if(ch<=0x7ff) {
+                reqLength+=2;
+            } else if(!UTF_IS_SURROGATE(ch)) {
+                reqLength+=3;
+            } else if(UTF_IS_SURROGATE_FIRST(ch) && UTF_IS_TRAIL(ch2=*pSrc)) {
+                ++pSrc;
+                reqLength+=4;
+            } else if(subchar>=0) {
+                reqLength+=U8_LENGTH(subchar);
+                ++numSubstitutions;
+            } else {
+                /* Unicode 3.2 forbids surrogate code points in UTF-8 */
+                *pErrorCode = U_INVALID_CHAR_FOUND;
+                return NULL;
+            }
+        }
+    } else {
+        const UChar *pSrcLimit = pSrc+srcLength;
+        int32_t count;
+
+        /* Faster loop without ongoing checking for pSrcLimit and pDestLimit. */
+        for(;;) {
+            /*
+             * Each iteration of the inner loop progresses by at most 3 UTF-8
+             * bytes and one UChar, for most characters.
+             * For supplementary code points (4 & 2), which are rare,
+             * there is an additional adjustment.
+             */
+            count = (int32_t)((pDestLimit - pDest) / 3);
+            srcLength = (int32_t)(pSrcLimit - pSrc);
+            if(count > srcLength) {
+                count = srcLength; /* min(remaining dest/3, remaining src) */
+            }
+            if(count < 3) {
+                /*
+                 * Too much overhead if we get near the end of the string,
+                 * continue with the next loop.
+                 */
+                break;
+            }
+            do {
+                ch=*pSrc++;
+                if(ch <= 0x7f) {
+                    *pDest++ = (uint8_t)ch;
+                } else if(ch <= 0x7ff) {
+                    *pDest++=(uint8_t)((ch>>6)|0xc0);
+                    *pDest++=(uint8_t)((ch&0x3f)|0x80);
+                } else if(ch <= 0xd7ff || ch >= 0xe000) {
+                    *pDest++=(uint8_t)((ch>>12)|0xe0);
+                    *pDest++=(uint8_t)(((ch>>6)&0x3f)|0x80);
+                    *pDest++=(uint8_t)((ch&0x3f)|0x80);
+                } else /* ch is a surrogate */ {
+                    /*
+                     * We will read two UChars and probably output four bytes,
+                     * which we didn't account for with computing count,
+                     * so we adjust it here.
+                     */
+                    if(--count == 0) {
+                        --pSrc; /* undo ch=*pSrc++ for the lead surrogate */
+                        break;  /* recompute count */
+                    }
+
+                    if(UTF_IS_SURROGATE_FIRST(ch) && UTF_IS_TRAIL(ch2=*pSrc)) { 
+                        ++pSrc;
+                        ch=UTF16_GET_PAIR_VALUE(ch, ch2);
+
+                        /* writing 4 bytes per 2 UChars is ok */
+                        *pDest++=(uint8_t)((ch>>18)|0xf0);
+                        *pDest++=(uint8_t)(((ch>>12)&0x3f)|0x80);
+                        *pDest++=(uint8_t)(((ch>>6)&0x3f)|0x80);
+                        *pDest++=(uint8_t)((ch&0x3f)|0x80);
+                    } else  {
+                        /* Unicode 3.2 forbids surrogate code points in UTF-8 */
+                        if(subchar>=0) {
+                            ch=subchar;
+                            ++numSubstitutions;
+                        } else {
+                            *pErrorCode = U_INVALID_CHAR_FOUND;
+                            return NULL;
+                        }
+
+                        /* convert and append*/
+                        pDest=_appendUTF8(pDest, ch);
+                    }
+                }
+            } while(--count > 0);
+        }
+
+        while(pSrc<pSrcLimit) {
+            ch=*pSrc++;
+            if(ch <= 0x7f) {
+                if(pDest<pDestLimit) {
+                    *pDest++ = (uint8_t)ch;
+                } else {
+                    reqLength = 1;
+                    break;
+                }
+            } else if(ch <= 0x7ff) {
+                if((pDestLimit - pDest) >= 2) {
+                    *pDest++=(uint8_t)((ch>>6)|0xc0);
+                    *pDest++=(uint8_t)((ch&0x3f)|0x80);
+                } else {
+                    reqLength = 2;
+                    break;
+                }
+            } else if(ch <= 0xd7ff || ch >= 0xe000) {
+                if((pDestLimit - pDest) >= 3) {
+                    *pDest++=(uint8_t)((ch>>12)|0xe0);
+                    *pDest++=(uint8_t)(((ch>>6)&0x3f)|0x80);
+                    *pDest++=(uint8_t)((ch&0x3f)|0x80);
+                } else {
+                    reqLength = 3;
+                    break;
+                }
+            } else /* ch is a surrogate */ {
+                int32_t length;
+
+                if(UTF_IS_SURROGATE_FIRST(ch) && pSrc<pSrcLimit && UTF_IS_TRAIL(ch2=*pSrc)) { 
+                    ++pSrc;
+                    ch=UTF16_GET_PAIR_VALUE(ch, ch2);
+                } else if(subchar>=0) {
+                    ch=subchar;
+                    ++numSubstitutions;
+                } else {
+                    /* Unicode 3.2 forbids surrogate code points in UTF-8 */
+                    *pErrorCode = U_INVALID_CHAR_FOUND;
+                    return NULL;
+                }
+
+                length = U8_LENGTH(ch);
+                if((pDestLimit - pDest) >= length) {
+                    /* convert and append*/
+                    pDest=_appendUTF8(pDest, ch);
+                } else {
+                    reqLength = length;
+                    break;
+                }
+            }
+        }
+        while(pSrc<pSrcLimit) {
+            ch=*pSrc++;
+            if(ch<=0x7f) {
+                ++reqLength;
+            } else if(ch<=0x7ff) {
+                reqLength+=2;
+            } else if(!UTF_IS_SURROGATE(ch)) {
+                reqLength+=3;
+            } else if(UTF_IS_SURROGATE_FIRST(ch) && pSrc<pSrcLimit && UTF_IS_TRAIL(ch2=*pSrc)) {
+                ++pSrc;
+                reqLength+=4;
+            } else if(subchar>=0) {
+                reqLength+=U8_LENGTH(subchar);
+                ++numSubstitutions;
+            } else {
+                /* Unicode 3.2 forbids surrogate code points in UTF-8 */
+                *pErrorCode = U_INVALID_CHAR_FOUND;
+                return NULL;
+            }
+        }
+    }
+
+    reqLength+=(int32_t)(pDest - (uint8_t *)dest);
+
+    if(pNumSubstitutions!=NULL) {
+        *pNumSubstitutions=numSubstitutions;
+    }
+
+    if(pDestLength){
+        *pDestLength = reqLength;
+    }
+
+    /* Terminate the buffer */
+    u_terminateChars(dest, destCapacity, reqLength, pErrorCode);
+    return dest;
+}
+
+U_CAPI char* U_EXPORT2 
+u_strToUTF8(char *dest,
+            int32_t destCapacity,
+            int32_t *pDestLength,
+            const UChar *pSrc,
+            int32_t srcLength,
+            UErrorCode *pErrorCode){
+    return u_strToUTF8WithSub(
+            dest, destCapacity, pDestLength,
+            pSrc, srcLength,
+            U_SENTINEL, NULL,
+            pErrorCode);
+}
+
+U_CAPI UChar* U_EXPORT2
+u_strFromJavaModifiedUTF8WithSub(
+        UChar *dest,
+        int32_t destCapacity,
+        int32_t *pDestLength,
+        const char *src,
+        int32_t srcLength,
+        UChar32 subchar, int32_t *pNumSubstitutions,
+        UErrorCode *pErrorCode) {
+    UChar *pDest = dest;
+    UChar *pDestLimit = dest+destCapacity;
+    UChar32 ch;
+    int32_t reqLength = 0;
+    const uint8_t* pSrc = (const uint8_t*) src;
+    const uint8_t *pSrcLimit;
+    int32_t count;
+    uint8_t t1, t2; /* trail bytes */
+    int32_t numSubstitutions;
+
+    /* args check */
+    if(U_FAILURE(*pErrorCode)){
+        return NULL;
+    }
+    if( (src==NULL && srcLength!=0) || srcLength < -1 ||
+        (dest==NULL && destCapacity!=0) || destCapacity<0 ||
+        subchar > 0x10ffff || U_IS_SURROGATE(subchar)
+    ) {
+        *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    if(pNumSubstitutions!=NULL) {
+        *pNumSubstitutions=0;
+    }
+    numSubstitutions=0;
+
+    if(srcLength < 0) {
+        /*
+         * Transform a NUL-terminated ASCII string.
+         * Handle non-ASCII strings with slower code.
+         */
+        while(((ch = *pSrc) != 0) && ch <= 0x7f && (pDest < pDestLimit)) {
+            *pDest++=(UChar)ch;
+            ++pSrc;
+        }
+        if(ch == 0) {
+            reqLength=(int32_t)(pDest - dest);
+            if(pDestLength) {
+                *pDestLength = reqLength;
+            }
+
+            /* Terminate the buffer */
+            u_terminateUChars(dest, destCapacity, reqLength, pErrorCode);
+            return dest;
+        }
+        srcLength = uprv_strlen((const char *)pSrc);
+    }
+
+    /* Faster loop without ongoing checking for pSrcLimit and pDestLimit. */
+    pSrcLimit = pSrc + srcLength;
+    for(;;) {
+        count = (int32_t)(pDestLimit - pDest);
+        srcLength = (int32_t)(pSrcLimit - pSrc);
+        if(count >= srcLength && srcLength > 0 && *pSrc <= 0x7f) {
+            /* fast ASCII loop */
+            const uint8_t *prevSrc = pSrc;
+            int32_t delta;
+            while(pSrc < pSrcLimit && (ch = *pSrc) <= 0x7f) {
+                *pDest++=(UChar)ch;
+                ++pSrc;
+            }
+            delta = (int32_t)(pSrc - prevSrc);
+            count -= delta;
+            srcLength -= delta;
+        }
+        /*
+         * Each iteration of the inner loop progresses by at most 3 UTF-8
+         * bytes and one UChar.
+         */
+        srcLength /= 3;
+        if(count > srcLength) {
+            count = srcLength; /* min(remaining dest, remaining src/3) */
+        }
+        if(count < 3) {
+            /*
+             * Too much overhead if we get near the end of the string,
+             * continue with the next loop.
+             */
+            break;
+        }
+        do {
+            ch = *pSrc;
+            if(ch <= 0x7f){
+                *pDest++=(UChar)ch;
+                ++pSrc;
+            } else {
+                if(ch >= 0xe0) {
+                    if( /* handle U+0000..U+FFFF inline */
+                        ch <= 0xef &&
+                        (t1 = (uint8_t)(pSrc[1] - 0x80)) <= 0x3f &&
+                        (t2 = (uint8_t)(pSrc[2] - 0x80)) <= 0x3f
+                    ) {
+                        /* no need for (ch & 0xf) because the upper bits are truncated after <<12 in the cast to (UChar) */
+                        *pDest++ = (UChar)((ch << 12) | (t1 << 6) | t2);
+                        pSrc += 3;
+                        continue;
+                    }
+                } else {
+                    if( /* handle U+0000..U+07FF inline */
+                        ch >= 0xc0 &&
+                        (t1 = (uint8_t)(pSrc[1] - 0x80)) <= 0x3f
+                    ) {
+                        *pDest++ = (UChar)(((ch & 0x1f) << 6) | t1);
+                        pSrc += 2;
+                        continue;
+                    }
+                }
+
+                if(subchar < 0) {
+                    *pErrorCode = U_INVALID_CHAR_FOUND;
+                    return NULL;
+                } else if(subchar > 0xffff && --count == 0) {
+                    /*
+                     * We need to write two UChars, adjusted count for that,
+                     * and ran out of space.
+                     */
+                    break;
+                } else {
+                    /* function call for error cases */
+                    ++pSrc; /* continue after the lead byte */
+                    utf8_nextCharSafeBodyPointer(&pSrc, pSrcLimit, ch);
+                    ++numSubstitutions;
+                    if(subchar<=0xFFFF) {
+                        *(pDest++)=(UChar)subchar;
+                    } else {
+                        *(pDest++)=U16_LEAD(subchar);
+                        *(pDest++)=U16_TRAIL(subchar);
+                    }
+                }
+            }
+        } while(--count > 0);
+    }
+
+    while((pSrc<pSrcLimit) && (pDest<pDestLimit)) {
+        ch = *pSrc;
+        if(ch <= 0x7f){
+            *pDest++=(UChar)ch;
+            ++pSrc;
+        } else {
+            if(ch >= 0xe0) {
+                if( /* handle U+0000..U+FFFF inline */
+                    ch <= 0xef &&
+                    ((pSrcLimit - pSrc) >= 3) &&
+                    (t1 = (uint8_t)(pSrc[1] - 0x80)) <= 0x3f &&
+                    (t2 = (uint8_t)(pSrc[2] - 0x80)) <= 0x3f
+                ) {
+                    /* no need for (ch & 0xf) because the upper bits are truncated after <<12 in the cast to (UChar) */
+                    *pDest++ = (UChar)((ch << 12) | (t1 << 6) | t2);
+                    pSrc += 3;
+                    continue;
+                }
+            } else {
+                if( /* handle U+0000..U+07FF inline */
+                    ch >= 0xc0 &&
+                    ((pSrcLimit - pSrc) >= 2) &&
+                    (t1 = (uint8_t)(pSrc[1] - 0x80)) <= 0x3f
+                ) {
+                    *pDest++ = (UChar)(((ch & 0x1f) << 6) | t1);
+                    pSrc += 2;
+                    continue;
+                }
+            }
+
+            if(subchar < 0) {
+                *pErrorCode = U_INVALID_CHAR_FOUND;
+                return NULL;
+            } else {
+                /* function call for error cases */
+                ++pSrc; /* continue after the lead byte */
+                utf8_nextCharSafeBodyPointer(&pSrc, pSrcLimit, ch);
+                ++numSubstitutions;
+                if(subchar<=0xFFFF) {
+                    *(pDest++)=(UChar)subchar;
+                } else {
+                    *(pDest++)=U16_LEAD(subchar);
+                    if(pDest<pDestLimit) {
+                        *(pDest++)=U16_TRAIL(subchar);
+                    } else {
+                        reqLength++;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    /* do not fill the dest buffer just count the UChars needed */
+    while(pSrc < pSrcLimit){
+        ch = *pSrc;
+        if(ch <= 0x7f) {
+            reqLength++;
+            ++pSrc;
+        } else {
+            if(ch >= 0xe0) {
+                if( /* handle U+0000..U+FFFF inline */
+                    ch <= 0xef &&
+                    ((pSrcLimit - pSrc) >= 3) &&
+                    (uint8_t)(pSrc[1] - 0x80) <= 0x3f &&
+                    (uint8_t)(pSrc[2] - 0x80) <= 0x3f
+                ) {
+                    reqLength++;
+                    pSrc += 3;
+                    continue;
+                }
+            } else {
+                if( /* handle U+0000..U+07FF inline */
+                    ch >= 0xc0 &&
+                    ((pSrcLimit - pSrc) >= 2) &&
+                    (uint8_t)(pSrc[1] - 0x80) <= 0x3f
+                ) {
+                    reqLength++;
+                    pSrc += 2;
+                    continue;
+                }
+            }
+
+            if(subchar < 0) {
+                *pErrorCode = U_INVALID_CHAR_FOUND;
+                return NULL;
+            } else {
+                /* function call for error cases */
+                ++pSrc; /* continue after the lead byte */
+                utf8_nextCharSafeBodyPointer(&pSrc, pSrcLimit, ch);
+                ++numSubstitutions;
+                reqLength+=U16_LENGTH(ch);
+            }
+        }
+    }
+
+    if(pNumSubstitutions!=NULL) {
+        *pNumSubstitutions=numSubstitutions;
+    }
+
+    reqLength+=(int32_t)(pDest - dest);
+    if(pDestLength) {
+        *pDestLength = reqLength;
+    }
+
+    /* Terminate the buffer */
+    u_terminateUChars(dest, destCapacity, reqLength, pErrorCode);
+    return dest;
+}
+
+U_CAPI char* U_EXPORT2 
+u_strToJavaModifiedUTF8(
+        char *dest,
+        int32_t destCapacity,
+        int32_t *pDestLength,
+        const UChar *src, 
+        int32_t srcLength,
+        UErrorCode *pErrorCode) {
+    int32_t reqLength=0;
+    uint32_t ch=0;
+    uint8_t *pDest = (uint8_t *)dest;
+    uint8_t *pDestLimit = pDest + destCapacity;
+    const UChar *pSrcLimit;
+    int32_t count;
+
+    /* args check */
+    if(U_FAILURE(*pErrorCode)){
+        return NULL;
+    }
+    if( (src==NULL && srcLength!=0) || srcLength < -1 ||
+        (dest==NULL && destCapacity!=0) || destCapacity<0
+    ) {
+        *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    if(srcLength==-1) {
+        /* Convert NUL-terminated ASCII, then find the string length. */
+        while((ch=*src)<=0x7f && ch != 0 && pDest<pDestLimit) {
+            *pDest++ = (uint8_t)ch;
+            ++src;
+        }
+        if(ch == 0) {
+            reqLength=(int32_t)(pDest - (uint8_t *)dest);
+            if(pDestLength) {
+                *pDestLength = reqLength;
+            }
+
+            /* Terminate the buffer */
+            u_terminateChars(dest, destCapacity, reqLength, pErrorCode);
+            return dest;
+        }
+        srcLength = u_strlen(src);
+    }
+
+    /* Faster loop without ongoing checking for pSrcLimit and pDestLimit. */
+    pSrcLimit = src+srcLength;
+    for(;;) {
+        count = (int32_t)(pDestLimit - pDest);
+        srcLength = (int32_t)(pSrcLimit - src);
+        if(count >= srcLength && srcLength > 0 && *src <= 0x7f) {
+            /* fast ASCII loop */
+            const UChar *prevSrc = src;
+            int32_t delta;
+            while(src < pSrcLimit && (ch = *src) <= 0x7f && ch != 0) {
+                *pDest++=(uint8_t)ch;
+                ++src;
+            }
+            delta = (int32_t)(src - prevSrc);
+            count -= delta;
+            srcLength -= delta;
+        }
+        /*
+         * Each iteration of the inner loop progresses by at most 3 UTF-8
+         * bytes and one UChar.
+         */
+        count /= 3;
+        if(count > srcLength) {
+            count = srcLength; /* min(remaining dest/3, remaining src) */
+        }
+        if(count < 3) {
+            /*
+             * Too much overhead if we get near the end of the string,
+             * continue with the next loop.
+             */
+            break;
+        }
+        do {
+            ch=*src++;
+            if(ch <= 0x7f && ch != 0) {
+                *pDest++ = (uint8_t)ch;
+            } else if(ch <= 0x7ff) {
+                *pDest++=(uint8_t)((ch>>6)|0xc0);
+                *pDest++=(uint8_t)((ch&0x3f)|0x80);
+            } else {
+                *pDest++=(uint8_t)((ch>>12)|0xe0);
+                *pDest++=(uint8_t)(((ch>>6)&0x3f)|0x80);
+                *pDest++=(uint8_t)((ch&0x3f)|0x80);
+            }
+        } while(--count > 0);
+    }
+
+    while(src<pSrcLimit) {
+        ch=*src++;
+        if(ch <= 0x7f && ch != 0) {
+            if(pDest<pDestLimit) {
+                *pDest++ = (uint8_t)ch;
+            } else {
+                reqLength = 1;
+                break;
+            }
+        } else if(ch <= 0x7ff) {
+            if((pDestLimit - pDest) >= 2) {
+                *pDest++=(uint8_t)((ch>>6)|0xc0);
+                *pDest++=(uint8_t)((ch&0x3f)|0x80);
+            } else {
+                reqLength = 2;
+                break;
+            }
+        } else {
+            if((pDestLimit - pDest) >= 3) {
+                *pDest++=(uint8_t)((ch>>12)|0xe0);
+                *pDest++=(uint8_t)(((ch>>6)&0x3f)|0x80);
+                *pDest++=(uint8_t)((ch&0x3f)|0x80);
+            } else {
+                reqLength = 3;
+                break;
+            }
+        }
+    }
+    while(src<pSrcLimit) {
+        ch=*src++;
+        if(ch <= 0x7f && ch != 0) {
+            ++reqLength;
+        } else if(ch<=0x7ff) {
+            reqLength+=2;
+        } else {
+            reqLength+=3;
+        }
+    }
+
+    reqLength+=(int32_t)(pDest - (uint8_t *)dest);
+    if(pDestLength){
+        *pDestLength = reqLength;
+    }
+
+    /* Terminate the buffer */
+    u_terminateChars(dest, destCapacity, reqLength, pErrorCode);
+    return dest;
+}
diff --git a/source/common/utext.cpp b/source/common/utext.cpp
new file mode 100644
index 0000000..e0cc5b7
--- /dev/null
+++ b/source/common/utext.cpp
@@ -0,0 +1,3200 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2005-2011, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  utext.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2005apr12
+*   created by: Markus W. Scherer
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/ustring.h"
+#include "unicode/unistr.h"
+#include "unicode/chariter.h"
+#include "unicode/utext.h"
+#include "ustr_imp.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uassert.h"
+#include "putilimp.h"
+
+U_NAMESPACE_USE
+
+#define I32_FLAG(bitIndex) ((int32_t)1<<(bitIndex))
+
+
+static UBool
+utext_access(UText *ut, int64_t index, UBool forward) {
+    return ut->pFuncs->access(ut, index, forward);
+}
+
+
+
+U_CAPI UBool U_EXPORT2
+utext_moveIndex32(UText *ut, int32_t delta) {
+    UChar32  c;
+    if (delta > 0) {
+        do {
+            if(ut->chunkOffset>=ut->chunkLength && !utext_access(ut, ut->chunkNativeLimit, TRUE)) {
+                return FALSE;
+            }
+            c = ut->chunkContents[ut->chunkOffset];
+            if (U16_IS_SURROGATE(c)) {
+                c = utext_next32(ut);
+                if (c == U_SENTINEL) {
+                    return FALSE;
+                }
+            } else {
+                ut->chunkOffset++;
+            }
+        } while(--delta>0);
+
+    } else if (delta<0) {
+        do {
+            if(ut->chunkOffset<=0 && !utext_access(ut, ut->chunkNativeStart, FALSE)) {
+                return FALSE;
+            }
+            c = ut->chunkContents[ut->chunkOffset-1];
+            if (U16_IS_SURROGATE(c)) {
+                c = utext_previous32(ut);
+                if (c == U_SENTINEL) {
+                    return FALSE;
+                }
+            } else {
+                ut->chunkOffset--;
+            }
+        } while(++delta<0);
+    }
+
+    return TRUE;
+}
+
+
+U_CAPI int64_t U_EXPORT2
+utext_nativeLength(UText *ut) {
+    return ut->pFuncs->nativeLength(ut);
+}
+
+
+U_CAPI UBool U_EXPORT2
+utext_isLengthExpensive(const UText *ut) {
+    UBool r = (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE)) != 0;
+    return r;
+}
+
+
+U_CAPI int64_t U_EXPORT2
+utext_getNativeIndex(const UText *ut) {
+    if(ut->chunkOffset <= ut->nativeIndexingLimit) {
+        return ut->chunkNativeStart+ut->chunkOffset;
+    } else {
+        return ut->pFuncs->mapOffsetToNative(ut);
+    }
+}
+
+
+U_CAPI void U_EXPORT2
+utext_setNativeIndex(UText *ut, int64_t index) {
+    if(index<ut->chunkNativeStart || index>=ut->chunkNativeLimit) {
+        // The desired position is outside of the current chunk.
+        // Access the new position.  Assume a forward iteration from here,
+        // which will also be optimimum for a single random access.
+        // Reverse iterations may suffer slightly.
+        ut->pFuncs->access(ut, index, TRUE);
+    } else if((int32_t)(index - ut->chunkNativeStart) <= ut->nativeIndexingLimit) {
+        // utf-16 indexing.
+        ut->chunkOffset=(int32_t)(index-ut->chunkNativeStart);
+    } else {
+         ut->chunkOffset=ut->pFuncs->mapNativeIndexToUTF16(ut, index);
+    }
+    // The convention is that the index must always be on a code point boundary.
+    // Adjust the index position if it is in the middle of a surrogate pair.
+    if (ut->chunkOffset<ut->chunkLength) {
+        UChar c= ut->chunkContents[ut->chunkOffset];
+        if (UTF16_IS_TRAIL(c)) {
+            if (ut->chunkOffset==0) {
+                ut->pFuncs->access(ut, ut->chunkNativeStart, FALSE);
+            }
+            if (ut->chunkOffset>0) {
+                UChar lead = ut->chunkContents[ut->chunkOffset-1];
+                if (UTF16_IS_LEAD(lead)) {
+                    ut->chunkOffset--;
+                }
+            }
+        }
+    }
+}
+
+
+
+U_CAPI int64_t U_EXPORT2
+utext_getPreviousNativeIndex(UText *ut) {
+    //
+    //  Fast-path the common case.
+    //     Common means current position is not at the beginning of a chunk
+    //     and the preceding character is not supplementary.
+    //
+    int32_t i = ut->chunkOffset - 1;
+    int64_t result;
+    if (i >= 0) {
+        UChar c = ut->chunkContents[i];
+        if (U16_IS_TRAIL(c) == FALSE) {
+            if (i <= ut->nativeIndexingLimit) {
+                result = ut->chunkNativeStart + i;
+            } else {
+                ut->chunkOffset = i;
+                result = ut->pFuncs->mapOffsetToNative(ut);
+                ut->chunkOffset++;
+            }
+            return result;
+        }
+    }
+
+    // If at the start of text, simply return 0.
+    if (ut->chunkOffset==0 && ut->chunkNativeStart==0) {
+        return 0;
+    }
+
+    // Harder, less common cases.  We are at a chunk boundary, or on a surrogate.
+    //    Keep it simple, use other functions to handle the edges.
+    //
+    utext_previous32(ut);
+    result = UTEXT_GETNATIVEINDEX(ut);
+    utext_next32(ut);
+    return result;
+}
+
+
+//
+//  utext_current32.  Get the UChar32 at the current position.
+//                    UText iteration position is always on a code point boundary,
+//                    never on the trail half of a surrogate pair.
+//
+U_CAPI UChar32 U_EXPORT2
+utext_current32(UText *ut) {
+    UChar32  c;
+    if (ut->chunkOffset==ut->chunkLength) {
+        // Current position is just off the end of the chunk.
+        if (ut->pFuncs->access(ut, ut->chunkNativeLimit, TRUE) == FALSE) {
+            // Off the end of the text.
+            return U_SENTINEL;
+        }
+    }
+
+    c = ut->chunkContents[ut->chunkOffset];
+    if (U16_IS_LEAD(c) == FALSE) {
+        // Normal, non-supplementary case.
+        return c;
+    }
+
+    //
+    //  Possible supplementary char.
+    //
+    UChar32   trail = 0;
+    UChar32   supplementaryC = c;
+    if ((ut->chunkOffset+1) < ut->chunkLength) {
+        // The trail surrogate is in the same chunk.
+        trail = ut->chunkContents[ut->chunkOffset+1];
+    } else {
+        //  The trail surrogate is in a different chunk.
+        //     Because we must maintain the iteration position, we need to switch forward
+        //     into the new chunk, get the trail surrogate, then revert the chunk back to the
+        //     original one.
+        //     An edge case to be careful of:  the entire text may end with an unpaired
+        //        leading surrogate.  The attempt to access the trail will fail, but
+        //        the original position before the unpaired lead still needs to be restored.
+        int64_t  nativePosition = ut->chunkNativeLimit;
+        int32_t  originalOffset = ut->chunkOffset;
+        if (ut->pFuncs->access(ut, nativePosition, TRUE)) {
+            trail = ut->chunkContents[ut->chunkOffset];
+        }
+        UBool r = ut->pFuncs->access(ut, nativePosition, FALSE);  // reverse iteration flag loads preceding chunk
+        U_ASSERT(r==TRUE);
+        ut->chunkOffset = originalOffset;
+        if(!r) {
+            return U_SENTINEL;
+        }
+    }
+
+    if (U16_IS_TRAIL(trail)) {
+        supplementaryC = U16_GET_SUPPLEMENTARY(c, trail);
+    }
+    return supplementaryC;
+
+}
+
+
+U_CAPI UChar32 U_EXPORT2
+utext_char32At(UText *ut, int64_t nativeIndex) {
+    UChar32 c = U_SENTINEL;
+
+    // Fast path the common case.
+    if (nativeIndex>=ut->chunkNativeStart && nativeIndex < ut->chunkNativeStart + ut->nativeIndexingLimit) {
+        ut->chunkOffset = (int32_t)(nativeIndex - ut->chunkNativeStart);
+        c = ut->chunkContents[ut->chunkOffset];
+        if (U16_IS_SURROGATE(c) == FALSE) {
+            return c;
+        }
+    }
+
+
+    utext_setNativeIndex(ut, nativeIndex);
+    if (nativeIndex>=ut->chunkNativeStart && ut->chunkOffset<ut->chunkLength) {
+        c = ut->chunkContents[ut->chunkOffset];
+        if (U16_IS_SURROGATE(c)) {
+            // For surrogates, let current32() deal with the complications
+            //    of supplementaries that may span chunk boundaries.
+            c = utext_current32(ut);
+        }
+    }
+    return c;
+}
+
+
+U_CAPI UChar32 U_EXPORT2
+utext_next32(UText *ut) {
+    UChar32       c;
+
+    if (ut->chunkOffset >= ut->chunkLength) {
+        if (ut->pFuncs->access(ut, ut->chunkNativeLimit, TRUE) == FALSE) {
+            return U_SENTINEL;
+        }
+    }
+
+    c = ut->chunkContents[ut->chunkOffset++];
+    if (U16_IS_LEAD(c) == FALSE) {
+        // Normal case, not supplementary.
+        //   (A trail surrogate seen here is just returned as is, as a surrogate value.
+        //    It cannot be part of a pair.)
+        return c;
+    }
+
+    if (ut->chunkOffset >= ut->chunkLength) {
+        if (ut->pFuncs->access(ut, ut->chunkNativeLimit, TRUE) == FALSE) {
+            // c is an unpaired lead surrogate at the end of the text.
+            // return it as it is.
+            return c;
+        }
+    }
+    UChar32 trail = ut->chunkContents[ut->chunkOffset];
+    if (U16_IS_TRAIL(trail) == FALSE) {
+        // c was an unpaired lead surrogate, not at the end of the text.
+        // return it as it is (unpaired).  Iteration position is on the
+        // following character, possibly in the next chunk, where the
+        //  trail surrogate would have been if it had existed.
+        return c;
+    }
+
+    UChar32 supplementary = U16_GET_SUPPLEMENTARY(c, trail);
+    ut->chunkOffset++;   // move iteration position over the trail surrogate.
+    return supplementary;
+    }
+
+
+U_CAPI UChar32 U_EXPORT2
+utext_previous32(UText *ut) {
+    UChar32       c;
+
+    if (ut->chunkOffset <= 0) {
+        if (ut->pFuncs->access(ut, ut->chunkNativeStart, FALSE) == FALSE) {
+            return U_SENTINEL;
+        }
+    }
+    ut->chunkOffset--;
+    c = ut->chunkContents[ut->chunkOffset];
+    if (U16_IS_TRAIL(c) == FALSE) {
+        // Normal case, not supplementary.
+        //   (A lead surrogate seen here is just returned as is, as a surrogate value.
+        //    It cannot be part of a pair.)
+        return c;
+    }
+
+    if (ut->chunkOffset <= 0) {
+        if (ut->pFuncs->access(ut, ut->chunkNativeStart, FALSE) == FALSE) {
+            // c is an unpaired trail surrogate at the start of the text.
+            // return it as it is.
+            return c;
+        }
+    }
+
+    UChar32 lead = ut->chunkContents[ut->chunkOffset-1];
+    if (U16_IS_LEAD(lead) == FALSE) {
+        // c was an unpaired trail surrogate, not at the end of the text.
+        // return it as it is (unpaired).  Iteration position is at c
+        return c;
+    }
+
+    UChar32 supplementary = U16_GET_SUPPLEMENTARY(lead, c);
+    ut->chunkOffset--;   // move iteration position over the lead surrogate.
+    return supplementary;
+}
+
+
+
+U_CAPI UChar32 U_EXPORT2
+utext_next32From(UText *ut, int64_t index) {
+    UChar32       c      = U_SENTINEL;
+
+    if(index<ut->chunkNativeStart || index>=ut->chunkNativeLimit) {
+        // Desired position is outside of the current chunk.
+        if(!ut->pFuncs->access(ut, index, TRUE)) {
+            // no chunk available here
+            return U_SENTINEL;
+        }
+    } else if (index - ut->chunkNativeStart  <= (int64_t)ut->nativeIndexingLimit) {
+        // Desired position is in chunk, with direct 1:1 native to UTF16 indexing
+        ut->chunkOffset = (int32_t)(index - ut->chunkNativeStart);
+    } else {
+        // Desired position is in chunk, with non-UTF16 indexing.
+        ut->chunkOffset = ut->pFuncs->mapNativeIndexToUTF16(ut, index);
+    }
+
+    c = ut->chunkContents[ut->chunkOffset++];
+    if (U16_IS_SURROGATE(c)) {
+        // Surrogates.  Many edge cases.  Use other functions that already
+        //              deal with the problems.
+        utext_setNativeIndex(ut, index);
+        c = utext_next32(ut);
+    }
+    return c;
+}
+
+
+U_CAPI UChar32 U_EXPORT2
+utext_previous32From(UText *ut, int64_t index) {
+    //
+    //  Return the character preceding the specified index.
+    //  Leave the iteration position at the start of the character that was returned.
+    //
+    UChar32     cPrev;    // The character preceding cCurr, which is what we will return.
+
+    // Address the chunk containg the position preceding the incoming index
+    // A tricky edge case:
+    //   We try to test the requested native index against the chunkNativeStart to determine
+    //    whether the character preceding the one at the index is in the current chunk.
+    //    BUT, this test can fail with UTF-8 (or any other multibyte encoding), when the
+    //    requested index is on something other than the first position of the first char.
+    //
+    if(index<=ut->chunkNativeStart || index>ut->chunkNativeLimit) {
+        // Requested native index is outside of the current chunk.
+        if(!ut->pFuncs->access(ut, index, FALSE)) {
+            // no chunk available here
+            return U_SENTINEL;
+        }
+    } else if(index - ut->chunkNativeStart <= (int64_t)ut->nativeIndexingLimit) {
+        // Direct UTF-16 indexing.
+        ut->chunkOffset = (int32_t)(index - ut->chunkNativeStart);
+    } else {
+        ut->chunkOffset=ut->pFuncs->mapNativeIndexToUTF16(ut, index);
+        if (ut->chunkOffset==0 && !ut->pFuncs->access(ut, index, FALSE)) {
+            // no chunk available here
+            return U_SENTINEL;
+        }
+    }
+
+    //
+    // Simple case with no surrogates.
+    //
+    ut->chunkOffset--;
+    cPrev = ut->chunkContents[ut->chunkOffset];
+
+    if (U16_IS_SURROGATE(cPrev)) {
+        // Possible supplementary.  Many edge cases.
+        // Let other functions do the heavy lifting.
+        utext_setNativeIndex(ut, index);
+        cPrev = utext_previous32(ut);
+    }
+    return cPrev;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+utext_extract(UText *ut,
+             int64_t start, int64_t limit,
+             UChar *dest, int32_t destCapacity,
+             UErrorCode *status) {
+                 return ut->pFuncs->extract(ut, start, limit, dest, destCapacity, status);
+             }
+
+
+
+U_CAPI UBool U_EXPORT2
+utext_equals(const UText *a, const UText *b) {
+    if (a==NULL || b==NULL ||
+        a->magic != UTEXT_MAGIC ||
+        b->magic != UTEXT_MAGIC) {
+            // Null or invalid arguments don't compare equal to anything.
+            return FALSE;
+    }
+
+    if (a->pFuncs != b->pFuncs) {
+        // Different types of text providers.
+        return FALSE;
+    }
+
+    if (a->context != b->context) {
+        // Different sources (different strings)
+        return FALSE;
+    }
+    if (utext_getNativeIndex(a) != utext_getNativeIndex(b)) {
+        // Different current position in the string.
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+U_CAPI int32_t U_EXPORT2
+utext_compare(UText *s1, int32_t length1,
+              UText *s2, int32_t length2) {
+    UChar32 c1 = 0, c2 = 0;
+    
+    if(length1<0 && length2<0) {
+        /* strcmp style, go until end of string */
+        for(;;) {
+            c1 = UTEXT_NEXT32(s1);
+            c2 = UTEXT_NEXT32(s2);
+            if(c1 != c2) {
+                break;
+            } else if(c1 == U_SENTINEL) {
+                return 0;
+            }
+        }
+    } else {
+        if(length1 < 0) {
+            length1 = INT32_MIN;
+        } else if (length2 < 0) {
+            length2 = INT32_MIN;
+        }
+        
+        /* memcmp/UnicodeString style, both length-specified */        
+        while((length1 > 0 || length1 == INT32_MIN) && (length2 > 0 || length2 == INT32_MIN)) {
+            c1 = UTEXT_NEXT32(s1);
+            c2 = UTEXT_NEXT32(s2);
+                       
+            if(c1 != c2) {
+                break;
+            } else if(c1 == U_SENTINEL) {
+                return 0;
+            }
+            
+            if (length1 != INT32_MIN) {
+                length1 -= 1;
+            }
+            if (length2 != INT32_MIN) {
+                length2 -= 1;
+            }
+        }
+        
+        if(length1 <= 0 && length1 != INT32_MIN) {
+            if(length2 <= 0) {
+                return 0;
+            } else {
+                return -1;
+            }
+        } else if(length2 <= 0 && length2 != INT32_MIN) {
+            if (length1 <= 0) {
+                return 0;
+            } else {
+                return 1;
+            }
+        }
+    }
+    
+    return (int32_t)c1-(int32_t)c2;
+}
+
+U_CAPI int32_t U_EXPORT2
+utext_compareNativeLimit(UText *s1, int64_t limit1,
+                         UText *s2, int64_t limit2) {
+    UChar32 c1, c2;
+    
+    if(limit1<0 && limit2<0) {
+        /* strcmp style, go until end of string */
+        for(;;) {
+            c1 = UTEXT_NEXT32(s1);
+            c2 = UTEXT_NEXT32(s2);
+            if(c1 != c2) {
+                return (int32_t)c1-(int32_t)c2;
+            } else if(c1 == U_SENTINEL) {
+                return 0;
+            }
+        }
+    } else {
+        /* memcmp/UnicodeString style, both length-specified */   
+        int64_t index1 = (limit1 >= 0 ? UTEXT_GETNATIVEINDEX(s1) : 0);
+        int64_t index2 = (limit2 >= 0 ? UTEXT_GETNATIVEINDEX(s2) : 0);
+        
+        while((limit1 < 0 || index1 < limit1) && (limit2 < 0 || index2 < limit2)) {
+            c1 = UTEXT_NEXT32(s1);
+            c2 = UTEXT_NEXT32(s2);
+            
+            if(c1 != c2) {
+                return (int32_t)c1-(int32_t)c2;
+            } else if(c1 == U_SENTINEL) {
+                return 0;
+            }
+            
+            if (limit1 >= 0) {
+                index1 = UTEXT_GETNATIVEINDEX(s1);
+            }
+            if (limit2 >= 0) {
+                index2 = UTEXT_GETNATIVEINDEX(s2);
+            }
+        }
+        
+        if(limit1 >= 0 && index1 >= limit1) {
+            if(index2 >= limit2) {
+                return 0;
+            } else {
+                return -1;
+            }
+        } else {
+            if(index1 >= limit1) {
+                return 0;
+            } else {
+                return 1;
+            }
+        }
+    }
+}
+
+U_CAPI int32_t U_EXPORT2
+utext_caseCompare(UText *s1, int32_t length1,
+                     UText *s2, int32_t length2,
+                     uint32_t options, UErrorCode *pErrorCode) {
+    const UCaseProps *csp;
+    
+    /* case folding variables */
+    const UChar *p;
+    int32_t length;
+    
+    /* case folding buffers, only use current-level start/limit */
+    UChar fold1[UCASE_MAX_STRING_LENGTH+1], fold2[UCASE_MAX_STRING_LENGTH+1];
+    int32_t foldOffset1, foldOffset2, foldLength1, foldLength2;
+    
+    /* current code points */
+    UChar32 c1, c2;
+    uint8_t cLength1, cLength2;
+
+    /* argument checking */
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(s1==NULL || s2==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    csp=ucase_getSingleton();
+
+    /* for variable-length strings */
+    if(length1 < 0) {
+        length1 = INT32_MIN;
+    }
+    if (length2 < 0) {
+        length2 = INT32_MIN;
+    }
+    
+    /* initialize */
+    foldOffset1 = foldOffset2 = foldLength1 = foldLength2 = 0;
+    
+    /* comparison loop */
+    while((foldOffset1 < foldLength1 || length1 > 0 || length1 == INT32_MIN) &&
+          (foldOffset2 < foldLength2 || length2 > 0 || length2 == INT32_MIN)) {
+        if(foldOffset1 < foldLength1) {
+            U16_NEXT_UNSAFE(fold1, foldOffset1, c1);
+            cLength1 = 0;
+        } else {
+            c1 = UTEXT_NEXT32(s1);
+            if (c1 != U_SENTINEL) {
+                cLength1 = U16_LENGTH(c1);
+                
+                length = ucase_toFullFolding(csp, c1, &p, options);
+                if(length >= 0) {
+                    if(length <= UCASE_MAX_STRING_LENGTH) {   // !!!: Does not correctly handle 0-length folded-case strings
+                        u_memcpy(fold1, p, length);
+                        foldOffset1 = 0;
+                        foldLength1 = length;
+                        U16_NEXT_UNSAFE(fold1, foldOffset1, c1);
+                    } else {
+                        c1 = length;
+                    }
+                }
+            }
+            
+            if(length1 != INT32_MIN) {
+                length1 -= 1;
+            }
+        }
+        
+        if(foldOffset2 < foldLength2) {
+            U16_NEXT_UNSAFE(fold2, foldOffset2, c2);
+            cLength2 = 0;
+        } else {
+            c2 = UTEXT_NEXT32(s2);
+            if (c2 != U_SENTINEL) {
+                cLength2 = U16_LENGTH(c2);
+                
+                length = ucase_toFullFolding(csp, c2, &p, options);
+                if(length >= 0) {
+                    if(length <= UCASE_MAX_STRING_LENGTH) {   // !!!: Does not correctly handle 0-length folded-case strings
+                        u_memcpy(fold2, p, length);
+                        foldOffset2 = 0;
+                        foldLength2 = length;
+                        U16_NEXT_UNSAFE(fold2, foldOffset2, c2);
+                    } else {
+                        c2 = length;
+                    }
+                }
+            } else if(c1 == U_SENTINEL) {
+                return 0; // end of both strings at once
+            }
+            
+            if(length2 != INT32_MIN) {
+                length2 -= 1;
+            }
+        }
+        
+        if(c1 != c2) {
+            return (int32_t)c1-(int32_t)c2;
+        }
+    }
+    
+    /* By now at least one of the strings is out of characters */
+    length1 += foldLength1 - foldOffset1;
+    length2 += foldLength2 - foldOffset2;
+    
+    if(length1 <= 0 && length1 != INT32_MIN) {
+        if(length2 <= 0) {
+            return 0;
+        } else {
+            return -1;
+        }
+    } else {
+        if (length1 <= 0) {
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+}
+
+U_CAPI int32_t U_EXPORT2
+utext_caseCompareNativeLimit(UText *s1, int64_t limit1,
+                                UText *s2, int64_t limit2,
+                                uint32_t options, UErrorCode *pErrorCode) {
+    const UCaseProps *csp;
+    
+    /* case folding variables */
+    const UChar *p;
+    int32_t length;
+    
+    /* case folding buffers, only use current-level start/limit */
+    UChar fold1[UCASE_MAX_STRING_LENGTH+1], fold2[UCASE_MAX_STRING_LENGTH+1];
+    int32_t foldOffset1, foldOffset2, foldLength1, foldLength2;
+    
+    /* current code points */
+    UChar32 c1, c2;
+    
+    /* native indexes into s1 and s2 */
+    int64_t index1, index2;
+
+    /* argument checking */
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(s1==NULL || s2==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    csp=ucase_getSingleton();
+
+    /* initialize */
+    index1 = (limit1 >= 0 ? UTEXT_GETNATIVEINDEX(s1) : 0);
+    index2 = (limit2 >= 0 ? UTEXT_GETNATIVEINDEX(s2) : 0);
+
+    foldOffset1 = foldOffset2 = foldLength1 = foldLength2 = 0;
+    
+    /* comparison loop */
+    while((foldOffset1 < foldLength1 || limit1 < 0 || index1 < limit1) &&
+          (foldOffset2 < foldLength2 || limit2 < 0 || index2 < limit2)) {
+        if(foldOffset1 < foldLength1) {
+            U16_NEXT_UNSAFE(fold1, foldOffset1, c1);
+        } else {
+            c1 = UTEXT_NEXT32(s1);
+            if (c1 != U_SENTINEL) {
+                length = ucase_toFullFolding(csp, c1, &p, options);
+                if(length >= 0) {
+                    if(length <= UCASE_MAX_STRING_LENGTH) {   // !!!: Does not correctly handle 0-length folded-case strings
+                        u_memcpy(fold1, p, length);
+                        foldOffset1 = 0;
+                        foldLength1 = length;
+                        U16_NEXT_UNSAFE(fold1, foldOffset1, c1);
+                    } else {
+                        c1 = length;
+                    }
+                }
+            }
+            
+            if (limit1 >= 0) {
+                index1 = UTEXT_GETNATIVEINDEX(s1);
+            }
+        }
+        
+        if(foldOffset2 < foldLength2) {
+            U16_NEXT_UNSAFE(fold2, foldOffset2, c2);
+        } else {
+            c2 = UTEXT_NEXT32(s2);
+            if (c2 != U_SENTINEL) {
+                length = ucase_toFullFolding(csp, c2, &p, options);
+                if(length >= 0) {
+                    if(length <= UCASE_MAX_STRING_LENGTH) {   // !!!: Does not correctly handle 0-length folded-case strings
+                        u_memcpy(fold2, p, length);
+                        foldOffset2 = 0;
+                        foldLength2 = length;
+                        U16_NEXT_UNSAFE(fold2, foldOffset2, c2);
+                    } else {
+                        c2 = length;
+                    }
+                }
+            } else if(c1 == U_SENTINEL) {
+                return 0;
+            }
+            
+            if (limit2 >= 0) {
+                index2 = UTEXT_GETNATIVEINDEX(s2);
+            }
+        }
+        
+        if(c1 != c2) {
+            return (int32_t)c1-(int32_t)c2;
+        }
+    }
+    
+    /* By now at least one of the strings is out of characters */
+    index1 -= foldLength1 - foldOffset1;
+    index2 -= foldLength2 - foldOffset2;
+    
+    if(limit1 >= 0 && index1 >= limit1) {
+        if(index2 >= limit2) {
+            return 0;
+        } else {
+            return -1;
+        }
+    } else {
+        if(index1 >= limit1) {
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+}
+
+
+U_CAPI UBool U_EXPORT2
+utext_isWritable(const UText *ut)
+{
+    UBool b = (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_WRITABLE)) != 0;
+    return b;
+}
+
+
+U_CAPI void U_EXPORT2
+utext_freeze(UText *ut) {
+    // Zero out the WRITABLE flag.
+    ut->providerProperties &= ~(I32_FLAG(UTEXT_PROVIDER_WRITABLE));
+}
+
+
+U_CAPI UBool U_EXPORT2
+utext_hasMetaData(const UText *ut)
+{
+    UBool b = (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_HAS_META_DATA)) != 0;
+    return b;
+}
+
+
+
+U_CAPI int32_t U_EXPORT2
+utext_replace(UText *ut,
+             int64_t nativeStart, int64_t nativeLimit,
+             const UChar *replacementText, int32_t replacementLength,
+             UErrorCode *status)
+{
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+    if ((ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_WRITABLE)) == 0) {
+        *status = U_NO_WRITE_PERMISSION;
+        return 0;
+    }
+    int32_t i = ut->pFuncs->replace(ut, nativeStart, nativeLimit, replacementText, replacementLength, status);
+    return i;
+}
+
+U_CAPI void U_EXPORT2
+utext_copy(UText *ut,
+          int64_t nativeStart, int64_t nativeLimit,
+          int64_t destIndex,
+          UBool move,
+          UErrorCode *status)
+{
+    if (U_FAILURE(*status)) {
+        return;
+    }
+    if ((ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_WRITABLE)) == 0) {
+        *status = U_NO_WRITE_PERMISSION;
+        return;
+    }
+    ut->pFuncs->copy(ut, nativeStart, nativeLimit, destIndex, move, status);
+}
+
+
+
+U_CAPI UText * U_EXPORT2
+utext_clone(UText *dest, const UText *src, UBool deep, UBool readOnly, UErrorCode *status) {
+    UText *result;
+    result = src->pFuncs->clone(dest, src, deep, status);
+    if (readOnly) {
+        utext_freeze(result);
+    }
+    return result;
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+//   UText common functions implementation
+//
+//------------------------------------------------------------------------------
+
+//
+//  UText.flags bit definitions
+//
+enum {
+    UTEXT_HEAP_ALLOCATED  = 1,      //  1 if ICU has allocated this UText struct on the heap.
+                                    //  0 if caller provided storage for the UText.
+
+    UTEXT_EXTRA_HEAP_ALLOCATED = 2, //  1 if ICU has allocated extra storage as a separate
+                                    //     heap block.
+                                    //  0 if there is no separate allocation.  Either no extra
+                                    //     storage was requested, or it is appended to the end
+                                    //     of the main UText storage.
+
+    UTEXT_OPEN = 4                  //  1 if this UText is currently open
+                                    //  0 if this UText is not open.
+};
+
+
+//
+//  Extended form of a UText.  The purpose is to aid in computing the total size required
+//    when a provider asks for a UText to be allocated with extra storage.
+
+struct ExtendedUText {
+    UText          ut;
+    UAlignedMemory extension;
+};
+
+static const UText emptyText = UTEXT_INITIALIZER;
+
+U_CAPI UText * U_EXPORT2
+utext_setup(UText *ut, int32_t extraSpace, UErrorCode *status) {
+    if (U_FAILURE(*status)) {
+        return ut;
+    }
+
+    if (ut == NULL) {
+        // We need to heap-allocate storage for the new UText
+        int32_t spaceRequired = sizeof(UText);
+        if (extraSpace > 0) {
+            spaceRequired = sizeof(ExtendedUText) + extraSpace - sizeof(UAlignedMemory);
+        }
+        ut = (UText *)uprv_malloc(spaceRequired);
+        if (ut == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return NULL;
+        } else {
+            *ut = emptyText;
+            ut->flags |= UTEXT_HEAP_ALLOCATED;
+            if (spaceRequired>0) {
+                ut->extraSize = extraSpace;
+                ut->pExtra    = &((ExtendedUText *)ut)->extension;
+            }
+        }
+    } else {
+        // We have been supplied with an already existing UText.
+        // Verify that it really appears to be a UText.
+        if (ut->magic != UTEXT_MAGIC) {
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+            return ut;
+        }
+        // If the ut is already open and there's a provider supplied close
+        //   function, call it.
+        if ((ut->flags & UTEXT_OPEN) && ut->pFuncs->close != NULL)  {
+            ut->pFuncs->close(ut);
+        }
+        ut->flags &= ~UTEXT_OPEN;
+
+        // If extra space was requested by our caller, check whether
+        //   sufficient already exists, and allocate new if needed.
+        if (extraSpace > ut->extraSize) {
+            // Need more space.  If there is existing separately allocated space,
+            //   delete it first, then allocate new space.
+            if (ut->flags & UTEXT_EXTRA_HEAP_ALLOCATED) {
+                uprv_free(ut->pExtra);
+                ut->extraSize = 0;
+            }
+            ut->pExtra = uprv_malloc(extraSpace);
+            if (ut->pExtra == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+            } else {
+                ut->extraSize = extraSpace;
+                ut->flags |= UTEXT_EXTRA_HEAP_ALLOCATED;
+            }
+        }
+    }
+    if (U_SUCCESS(*status)) {
+        ut->flags |= UTEXT_OPEN;
+
+        // Initialize all remaining fields of the UText.
+        //
+        ut->context             = NULL;
+        ut->chunkContents       = NULL;
+        ut->p                   = NULL;
+        ut->q                   = NULL;
+        ut->r                   = NULL;
+        ut->a                   = 0;
+        ut->b                   = 0;
+        ut->c                   = 0;
+        ut->chunkOffset         = 0;
+        ut->chunkLength         = 0;
+        ut->chunkNativeStart    = 0;
+        ut->chunkNativeLimit    = 0;
+        ut->nativeIndexingLimit = 0;
+        ut->providerProperties  = 0;
+        ut->privA               = 0;
+        ut->privB               = 0;
+        ut->privC               = 0;
+        ut->privP               = NULL;
+        if (ut->pExtra!=NULL && ut->extraSize>0)
+            uprv_memset(ut->pExtra, 0, ut->extraSize);
+
+    }
+    return ut;
+}
+
+
+U_CAPI UText * U_EXPORT2
+utext_close(UText *ut) {
+    if (ut==NULL ||
+        ut->magic != UTEXT_MAGIC ||
+        (ut->flags & UTEXT_OPEN) == 0)
+    {
+        // The supplied ut is not an open UText.
+        // Do nothing.
+        return ut;
+    }
+
+    // If the provider gave us a close function, call it now.
+    // This will clean up anything allocated specifically by the provider.
+    if (ut->pFuncs->close != NULL) {
+        ut->pFuncs->close(ut);
+    }
+    ut->flags &= ~UTEXT_OPEN;
+
+    // If we (the framework) allocated the UText or subsidiary storage,
+    //   delete it.
+    if (ut->flags & UTEXT_EXTRA_HEAP_ALLOCATED) {
+        uprv_free(ut->pExtra);
+        ut->pExtra = NULL;
+        ut->flags &= ~UTEXT_EXTRA_HEAP_ALLOCATED;
+        ut->extraSize = 0;
+    }
+
+    // Zero out function table of the closed UText.  This is a defensive move,
+    //   inteded to cause applications that inadvertantly use a closed
+    //   utext to crash with null pointer errors.
+    ut->pFuncs        = NULL;
+
+    if (ut->flags & UTEXT_HEAP_ALLOCATED) {
+        // This UText was allocated by UText setup.  We need to free it.
+        // Clear magic, so we can detect if the user messes up and immediately
+        //  tries to reopen another UText using the deleted storage.
+        ut->magic = 0;
+        uprv_free(ut);
+        ut = NULL;
+    }
+    return ut;
+}
+
+
+
+
+//
+// invalidateChunk   Reset a chunk to have no contents, so that the next call
+//                   to access will cause new data to load.
+//                   This is needed when copy/move/replace operate directly on the
+//                   backing text, potentially putting it out of sync with the
+//                   contents in the chunk.
+//
+static void
+invalidateChunk(UText *ut) {
+    ut->chunkLength = 0;
+    ut->chunkNativeLimit = 0;
+    ut->chunkNativeStart = 0;
+    ut->chunkOffset = 0;
+    ut->nativeIndexingLimit = 0;
+}
+
+//
+// pinIndex        Do range pinning on a native index parameter.
+//                 64 bit pinning is done in place.
+//                 32 bit truncated result is returned as a convenience for
+//                        use in providers that don't need 64 bits.
+static int32_t
+pinIndex(int64_t &index, int64_t limit) {
+    if (index<0) {
+        index = 0;
+    } else if (index > limit) {
+        index = limit;
+    }
+    return (int32_t)index;
+}
+
+
+U_CDECL_BEGIN
+
+//
+// Pointer relocation function,
+//   a utility used by shallow clone.
+//   Adjust a pointer that refers to something within one UText (the source)
+//   to refer to the same relative offset within a another UText (the target)
+//
+static void adjustPointer(UText *dest, const void **destPtr, const UText *src) {
+    // convert all pointers to (char *) so that byte address arithmetic will work.
+    char  *dptr = (char *)*destPtr;
+    char  *dUText = (char *)dest;
+    char  *sUText = (char *)src;
+
+    if (dptr >= (char *)src->pExtra && dptr < ((char*)src->pExtra)+src->extraSize) {
+        // target ptr was to something within the src UText's pExtra storage.
+        //   relocate it into the target UText's pExtra region.
+        *destPtr = ((char *)dest->pExtra) + (dptr - (char *)src->pExtra);
+    } else if (dptr>=sUText && dptr < sUText+src->sizeOfStruct) {
+        // target ptr was pointing to somewhere within the source UText itself.
+        //   Move it to the same offset within the target UText.
+        *destPtr = dUText + (dptr-sUText);
+    }
+}
+
+
+//
+//  Clone.  This is a generic copy-the-utext-by-value clone function that can be
+//          used as-is with some utext types, and as a helper by other clones.
+//
+static UText * U_CALLCONV
+shallowTextClone(UText * dest, const UText * src, UErrorCode * status) {
+    if (U_FAILURE(*status)) {
+        return NULL;
+    }
+    int32_t  srcExtraSize = src->extraSize;
+
+    //
+    // Use the generic text_setup to allocate storage if required.
+    //
+    dest = utext_setup(dest, srcExtraSize, status);
+    if (U_FAILURE(*status)) {
+        return dest;
+    }
+
+    //
+    //  flags (how the UText was allocated) and the pointer to the
+    //   extra storage must retain the values in the cloned utext that
+    //   were set up by utext_setup.  Save them separately before
+    //   copying the whole struct.
+    //
+    void *destExtra = dest->pExtra;
+    int32_t flags   = dest->flags;
+
+
+    //
+    //  Copy the whole UText struct by value.
+    //  Any "Extra" storage is copied also.
+    //
+    int sizeToCopy = src->sizeOfStruct;
+    if (sizeToCopy > dest->sizeOfStruct) {
+        sizeToCopy = dest->sizeOfStruct;
+    }
+    uprv_memcpy(dest, src, sizeToCopy);
+    dest->pExtra = destExtra;
+    dest->flags  = flags;
+    if (srcExtraSize > 0) {
+        uprv_memcpy(dest->pExtra, src->pExtra, srcExtraSize);
+    }
+
+    //
+    // Relocate any pointers in the target that refer to the UText itself
+    //   to point to the cloned copy rather than the original source.
+    //
+    adjustPointer(dest, &dest->context, src);
+    adjustPointer(dest, &dest->p, src);
+    adjustPointer(dest, &dest->q, src);
+    adjustPointer(dest, &dest->r, src);
+    adjustPointer(dest, (const void **)&dest->chunkContents, src);
+
+    return dest;
+}
+
+
+U_CDECL_END
+
+
+
+//------------------------------------------------------------------------------
+//
+//     UText implementation for UTF-8 char * strings (read-only)
+//     Limitation:  string length must be <= 0x7fffffff in length.
+//                  (length must for in an int32_t variable)
+//
+//         Use of UText data members:
+//              context    pointer to UTF-8 string
+//              utext.b    is the input string length (bytes).
+//              utext.c    Length scanned so far in string
+//                           (for optimizing finding length of zero terminated strings.)
+//              utext.p    pointer to the current buffer
+//              utext.q    pointer to the other buffer.
+//
+//------------------------------------------------------------------------------
+
+// Chunk size.
+//     Must be less than 85, because of byte mapping from UChar indexes to native indexes.
+//     Worst case is three native bytes to one UChar.  (Supplemenaries are 4 native bytes
+//     to two UChars.)
+//
+enum { UTF8_TEXT_CHUNK_SIZE=32 };
+
+//
+// UTF8Buf  Two of these structs will be set up in the UText's extra allocated space.
+//          Each contains the UChar chunk buffer, the to and from native maps, and
+//          header info.
+//
+//     because backwards iteration fills the buffers starting at the end and
+//     working towards the front, the filled part of the buffers may not begin
+//     at the start of the available storage for the buffers.
+//
+//     Buffer size is one bigger than the specified UTF8_TEXT_CHUNK_SIZE to allow for
+//     the last character added being a supplementary, and thus requiring a surrogate
+//     pair.  Doing this is simpler than checking for the edge case.
+//
+
+struct UTF8Buf {
+    int32_t   bufNativeStart;                        // Native index of first char in UChar buf
+    int32_t   bufNativeLimit;                        // Native index following last char in buf.
+    int32_t   bufStartIdx;                           // First filled position in buf.
+    int32_t   bufLimitIdx;                           // Limit of filled range in buf.
+    int32_t   bufNILimit;                            // Limit of native indexing part of buf
+    int32_t   toUCharsMapStart;                      // Native index corresponding to
+                                                     //   mapToUChars[0].
+                                                     //   Set to bufNativeStart when filling forwards.
+                                                     //   Set to computed value when filling backwards.
+
+    UChar     buf[UTF8_TEXT_CHUNK_SIZE+4];           // The UChar buffer.  Requires one extra position beyond the
+                                                     //   the chunk size, to allow for surrogate at the end.
+                                                     //   Length must be identical to mapToNative array, below,
+                                                     //   because of the way indexing works when the array is
+                                                     //   filled backwards during a reverse iteration.  Thus,
+                                                     //   the additional extra size.
+    uint8_t   mapToNative[UTF8_TEXT_CHUNK_SIZE+4];   // map UChar index in buf to
+                                                     //  native offset from bufNativeStart.
+                                                     //  Requires two extra slots,
+                                                     //    one for a supplementary starting in the last normal position,
+                                                     //    and one for an entry for the buffer limit position.
+    uint8_t   mapToUChars[UTF8_TEXT_CHUNK_SIZE*3+6]; // Map native offset from bufNativeStart to
+                                                     //   correspoding offset in filled part of buf.
+    int32_t   align;
+};
+
+U_CDECL_BEGIN
+
+//
+//   utf8TextLength
+//
+//        Get the length of the string.  If we don't already know it,
+//              we'll need to scan for the trailing  nul.
+//
+static int64_t U_CALLCONV
+utf8TextLength(UText *ut) {
+    if (ut->b < 0) {
+        // Zero terminated string, and we haven't scanned to the end yet.
+        // Scan it now.
+        const char *r = (const char *)ut->context + ut->c;
+        while (*r != 0) {
+            r++;
+        }
+        if ((r - (const char *)ut->context) < 0x7fffffff) {
+            ut->b = (int32_t)(r - (const char *)ut->context);
+        } else {
+            // Actual string was bigger (more than 2 gig) than we
+            //   can handle.  Clip it to 2 GB.
+            ut->b = 0x7fffffff;
+        }
+        ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE);
+    }
+    return ut->b;
+}
+
+
+
+
+
+
+static UBool U_CALLCONV
+utf8TextAccess(UText *ut, int64_t index, UBool forward) {
+    //
+    //  Apologies to those who are allergic to goto statements.
+    //    Consider each goto to a labelled block to be the equivalent of
+    //         call the named block as if it were a function();
+    //         return;
+    //
+    const uint8_t *s8=(const uint8_t *)ut->context;
+    UTF8Buf *u8b = NULL;
+    int32_t  length = ut->b;         // Length of original utf-8
+    int32_t  ix= (int32_t)index;     // Requested index, trimmed to 32 bits.
+    int32_t  mapIndex = 0;
+    if (index<0) {
+        ix=0;
+    } else if (index > 0x7fffffff) {
+        // Strings with 64 bit lengths not supported by this UTF-8 provider.
+        ix = 0x7fffffff;
+    }
+
+    // Pin requested index to the string length.
+    if (ix>length) {
+        if (length>=0) {
+            ix=length;
+        } else if (ix>=ut->c) {
+            // Zero terminated string, and requested index is beyond
+            //   the region that has already been scanned.
+            //   Scan up to either the end of the string or to the
+            //   requested position, whichever comes first.
+            while (ut->c<ix && s8[ut->c]!=0) {
+                ut->c++;
+            }
+            //  TODO:  support for null terminated string length > 32 bits.
+            if (s8[ut->c] == 0) {
+                // We just found the actual length of the string.
+                //  Trim the requested index back to that.
+                ix     = ut->c;
+                ut->b  = ut->c;
+                length = ut->c;
+                ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE);
+            }
+        }
+    }
+
+    //
+    // Dispatch to the appropriate action for a forward iteration request.
+    //
+    if (forward) {
+        if (ix==ut->chunkNativeLimit) {
+            // Check for normal sequential iteration cases first.
+            if (ix==length) {
+                // Just reached end of string
+                // Don't swap buffers, but do set the
+                //   current buffer position.
+                ut->chunkOffset = ut->chunkLength;
+                return FALSE;
+            } else {
+                // End of current buffer.
+                //   check whether other buffer already has what we need.
+                UTF8Buf *altB = (UTF8Buf *)ut->q;
+                if (ix>=altB->bufNativeStart && ix<altB->bufNativeLimit) {
+                    goto swapBuffers;
+                }
+            }
+        }
+
+        // A random access.  Desired index could be in either or niether buf.
+        // For optimizing the order of testing, first check for the index
+        //    being in the other buffer.  This will be the case for uses that
+        //    move back and forth over a fairly limited range
+        {
+            u8b = (UTF8Buf *)ut->q;   // the alternate buffer
+            if (ix>=u8b->bufNativeStart && ix<u8b->bufNativeLimit) {
+                // Requested index is in the other buffer.
+                goto swapBuffers;
+            }
+            if (ix == length) {
+                // Requested index is end-of-string.
+                //   (this is the case of randomly seeking to the end.
+                //    The case of iterating off the end is handled earlier.)
+                if (ix == ut->chunkNativeLimit) {
+                    // Current buffer extends up to the end of the string.
+                    //   Leave it as the current buffer.
+                    ut->chunkOffset = ut->chunkLength;
+                    return FALSE;
+                }
+                if (ix == u8b->bufNativeLimit) {
+                    // Alternate buffer extends to the end of string.
+                    //   Swap it in as the current buffer.
+                    goto swapBuffersAndFail;
+                }
+
+                // Neither existing buffer extends to the end of the string.
+                goto makeStubBuffer;
+            }
+
+            if (ix<ut->chunkNativeStart || ix>=ut->chunkNativeLimit) {
+                // Requested index is in neither buffer.
+                goto fillForward;
+            }
+
+            // Requested index is in this buffer.
+            u8b = (UTF8Buf *)ut->p;   // the current buffer
+            mapIndex = ix - u8b->toUCharsMapStart;
+            ut->chunkOffset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx;
+            return TRUE;
+
+        }
+    }
+
+
+    //
+    // Dispatch to the appropriate action for a
+    //   Backwards Diretion iteration request.
+    //
+    if (ix==ut->chunkNativeStart) {
+        // Check for normal sequential iteration cases first.
+        if (ix==0) {
+            // Just reached the start of string
+            // Don't swap buffers, but do set the
+            //   current buffer position.
+            ut->chunkOffset = 0;
+            return FALSE;
+        } else {
+            // Start of current buffer.
+            //   check whether other buffer already has what we need.
+            UTF8Buf *altB = (UTF8Buf *)ut->q;
+            if (ix>altB->bufNativeStart && ix<=altB->bufNativeLimit) {
+                goto swapBuffers;
+            }
+        }
+    }
+
+    // A random access.  Desired index could be in either or niether buf.
+    // For optimizing the order of testing,
+    //    Most likely case:  in the other buffer.
+    //    Second most likely: in neither buffer.
+    //    Unlikely, but must work:  in the current buffer.
+    u8b = (UTF8Buf *)ut->q;   // the alternate buffer
+    if (ix>u8b->bufNativeStart && ix<=u8b->bufNativeLimit) {
+        // Requested index is in the other buffer.
+        goto swapBuffers;
+    }
+    // Requested index is start-of-string.
+    //   (this is the case of randomly seeking to the start.
+    //    The case of iterating off the start is handled earlier.)
+    if (ix==0) {
+        if (u8b->bufNativeStart==0) {
+            // Alternate buffer contains the data for the start string.
+            // Make it be the current buffer.
+            goto swapBuffersAndFail;
+        } else {
+            // Request for data before the start of string,
+            //   neither buffer is usable.
+            //   set up a zero-length buffer.
+            goto makeStubBuffer;
+        }
+    }
+
+    if (ix<=ut->chunkNativeStart || ix>ut->chunkNativeLimit) {
+        // Requested index is in neither buffer.
+        goto fillReverse;
+    }
+
+    // Requested index is in this buffer.
+    //   Set the utf16 buffer index.
+    u8b = (UTF8Buf *)ut->p;
+    mapIndex = ix - u8b->toUCharsMapStart;
+    ut->chunkOffset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx;
+    if (ut->chunkOffset==0) {
+        // This occurs when the first character in the text is
+        //   a multi-byte UTF-8 char, and the requested index is to
+        //   one of the trailing bytes.  Because there is no preceding ,
+        //   character, this access fails.  We can't pick up on the
+        //   situation sooner because the requested index is not zero.
+        return FALSE;
+    } else {
+        return TRUE;
+    }
+
+
+
+swapBuffers:
+    //  The alternate buffer (ut->q) has the string data that was requested.
+    //  Swap the primary and alternate buffers, and set the
+    //   chunk index into the new primary buffer.
+    {
+        u8b   = (UTF8Buf *)ut->q;
+        ut->q = ut->p;
+        ut->p = u8b;
+        ut->chunkContents       = &u8b->buf[u8b->bufStartIdx];
+        ut->chunkLength         = u8b->bufLimitIdx - u8b->bufStartIdx;
+        ut->chunkNativeStart    = u8b->bufNativeStart;
+        ut->chunkNativeLimit    = u8b->bufNativeLimit;
+        ut->nativeIndexingLimit = u8b->bufNILimit;
+
+        // Index into the (now current) chunk
+        // Use the map to set the chunk index.  It's more trouble than it's worth
+        //    to check whether native indexing can be used.
+        U_ASSERT(ix>=u8b->bufNativeStart);
+        U_ASSERT(ix<=u8b->bufNativeLimit);
+        mapIndex = ix - u8b->toUCharsMapStart;
+        U_ASSERT(mapIndex>=0);
+        U_ASSERT(mapIndex<(int32_t)sizeof(u8b->mapToUChars));
+        ut->chunkOffset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx;
+
+        return TRUE;
+    }
+
+
+ swapBuffersAndFail:
+    // We got a request for either the start or end of the string,
+    //  with iteration continuing in the out-of-bounds direction.
+    // The alternate buffer already contains the data up to the
+    //  start/end.
+    // Swap the buffers, then return failure, indicating that we couldn't
+    //  make things correct for continuing the iteration in the requested
+    //  direction.  The position & buffer are correct should the
+    //  user decide to iterate in the opposite direction.
+    u8b   = (UTF8Buf *)ut->q;
+    ut->q = ut->p;
+    ut->p = u8b;
+    ut->chunkContents       = &u8b->buf[u8b->bufStartIdx];
+    ut->chunkLength         = u8b->bufLimitIdx - u8b->bufStartIdx;
+    ut->chunkNativeStart    = u8b->bufNativeStart;
+    ut->chunkNativeLimit    = u8b->bufNativeLimit;
+    ut->nativeIndexingLimit = u8b->bufNILimit;
+
+    // Index into the (now current) chunk
+    //  For this function  (swapBuffersAndFail), the requested index
+    //    will always be at either the start or end of the chunk.
+    if (ix==u8b->bufNativeLimit) {
+        ut->chunkOffset = ut->chunkLength;
+    } else  {
+        ut->chunkOffset = 0;
+        U_ASSERT(ix == u8b->bufNativeStart);
+    }
+    return FALSE;
+
+makeStubBuffer:
+    //   The user has done a seek/access past the start or end
+    //   of the string.  Rather than loading data that is likely
+    //   to never be used, just set up a zero-length buffer at
+    //   the position.
+    u8b = (UTF8Buf *)ut->q;
+    u8b->bufNativeStart   = ix;
+    u8b->bufNativeLimit   = ix;
+    u8b->bufStartIdx      = 0;
+    u8b->bufLimitIdx      = 0;
+    u8b->bufNILimit       = 0;
+    u8b->toUCharsMapStart = ix;
+    u8b->mapToNative[0]   = 0;
+    u8b->mapToUChars[0]   = 0;
+    goto swapBuffersAndFail;
+
+
+
+fillForward:
+    {
+        // Move the incoming index to a code point boundary.
+        U8_SET_CP_START(s8, 0, ix);
+
+        // Swap the UText buffers.
+        //  We want to fill what was previously the alternate buffer,
+        //  and make what was the current buffer be the new alternate.
+        UTF8Buf *u8b = (UTF8Buf *)ut->q;
+        ut->q = ut->p;
+        ut->p = u8b;
+
+        int32_t strLen = ut->b;
+        UBool   nulTerminated = FALSE;
+        if (strLen < 0) {
+            strLen = 0x7fffffff;
+            nulTerminated = TRUE;
+        }
+
+        UChar   *buf = u8b->buf;
+        uint8_t *mapToNative  = u8b->mapToNative;
+        uint8_t *mapToUChars  = u8b->mapToUChars;
+        int32_t  destIx       = 0;
+        int32_t  srcIx        = ix;
+        UBool    seenNonAscii = FALSE;
+        UChar32  c = 0;
+
+        // Fill the chunk buffer and mapping arrays.
+        while (destIx<UTF8_TEXT_CHUNK_SIZE) {
+            c = s8[srcIx];
+            if (c>0 && c<0x80) {
+                // Special case ASCII range for speed.
+                //   zero is excluded to simplify bounds checking.
+                buf[destIx] = (UChar)c;
+                mapToNative[destIx]    = (uint8_t)(srcIx - ix);
+                mapToUChars[srcIx-ix]  = (uint8_t)destIx;
+                srcIx++;
+                destIx++;
+            } else {
+                // General case, handle everything.
+                if (seenNonAscii == FALSE) {
+                    seenNonAscii = TRUE;
+                    u8b->bufNILimit = destIx;
+                }
+
+                int32_t  cIx      = srcIx;
+                int32_t  dIx      = destIx;
+                int32_t  dIxSaved = destIx;
+                U8_NEXT(s8, srcIx, strLen, c);
+                if (c==0 && nulTerminated) {
+                    srcIx--;
+                    break;
+                }
+                if (c<0) {
+                    // Illegal UTF-8.  Replace with sub character.
+                    c = 0x0fffd;
+                }
+
+                U16_APPEND_UNSAFE(buf, destIx, c);
+                do {
+                    mapToNative[dIx++] = (uint8_t)(cIx - ix);
+                } while (dIx < destIx);
+
+                do {
+                    mapToUChars[cIx++ - ix] = (uint8_t)dIxSaved;
+                } while (cIx < srcIx);
+            }
+            if (srcIx>=strLen) {
+                break;
+            }
+
+        }
+
+        //  store Native <--> Chunk Map entries for the end of the buffer.
+        //    There is no actual character here, but the index position is valid.
+        mapToNative[destIx]     = (uint8_t)(srcIx - ix);
+        mapToUChars[srcIx - ix] = (uint8_t)destIx;
+
+        //  fill in Buffer descriptor
+        u8b->bufNativeStart     = ix;
+        u8b->bufNativeLimit     = srcIx;
+        u8b->bufStartIdx        = 0;
+        u8b->bufLimitIdx        = destIx;
+        if (seenNonAscii == FALSE) {
+            u8b->bufNILimit     = destIx;
+        }
+        u8b->toUCharsMapStart   = u8b->bufNativeStart;
+
+        // Set UText chunk to refer to this buffer.
+        ut->chunkContents       = buf;
+        ut->chunkOffset         = 0;
+        ut->chunkLength         = u8b->bufLimitIdx;
+        ut->chunkNativeStart    = u8b->bufNativeStart;
+        ut->chunkNativeLimit    = u8b->bufNativeLimit;
+        ut->nativeIndexingLimit = u8b->bufNILimit;
+
+        // For zero terminated strings, keep track of the maximum point
+        //   scanned so far.
+        if (nulTerminated && srcIx>ut->c) {
+            ut->c = srcIx;
+            if (c==0) {
+                // We scanned to the end.
+                //   Remember the actual length.
+                ut->b = srcIx;
+                ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE);
+            }
+        }
+        return TRUE;
+    }
+
+
+fillReverse:
+    {
+        // Move the incoming index to a code point boundary.
+        // Can only do this if the incoming index is somewhere in the interior of the string.
+        //   If index is at the end, there is no character there to look at.
+        if (ix != ut->b) {
+            U8_SET_CP_START(s8, 0, ix);
+        }
+
+        // Swap the UText buffers.
+        //  We want to fill what was previously the alternate buffer,
+        //  and make what was the current buffer be the new alternate.
+        UTF8Buf *u8b = (UTF8Buf *)ut->q;
+        ut->q = ut->p;
+        ut->p = u8b;
+
+        UChar   *buf = u8b->buf;
+        uint8_t *mapToNative = u8b->mapToNative;
+        uint8_t *mapToUChars = u8b->mapToUChars;
+        int32_t  toUCharsMapStart = ix - (UTF8_TEXT_CHUNK_SIZE*3 + 1);
+        int32_t  destIx = UTF8_TEXT_CHUNK_SIZE+2;   // Start in the overflow region
+                                                    //   at end of buffer to leave room
+                                                    //   for a surrogate pair at the
+                                                    //   buffer start.
+        int32_t  srcIx  = ix;
+        int32_t  bufNILimit = destIx;
+        UChar32   c;
+
+        // Map to/from Native Indexes, fill in for the position at the end of
+        //   the buffer.
+        //
+        mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart);
+        mapToUChars[srcIx - toUCharsMapStart] = (uint8_t)destIx;
+
+        // Fill the chunk buffer
+        // Work backwards, filling from the end of the buffer towards the front.
+        //
+        while (destIx>2 && (srcIx - toUCharsMapStart > 5) && (srcIx > 0)) {
+            srcIx--;
+            destIx--;
+
+            // Get last byte of the UTF-8 character
+            c = s8[srcIx];
+            if (c<0x80) {
+                // Special case ASCII range for speed.
+                buf[destIx] = (UChar)c;
+                mapToUChars[srcIx - toUCharsMapStart] = (uint8_t)destIx;
+                mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart);
+            } else {
+                // General case, handle everything non-ASCII.
+
+                int32_t  sIx      = srcIx;  // ix of last byte of multi-byte u8 char
+
+                // Get the full character from the UTF8 string.
+                //   use code derived from tbe macros in utf.8
+                //   Leaves srcIx pointing at the first byte of the UTF-8 char.
+                //
+                if (c<=0xbf) {
+                    c=utf8_prevCharSafeBody(s8, 0, &srcIx, c, -1);
+                    // leaves srcIx at first byte of the multi-byte char.
+                } else {
+                    c=0x0fffd;
+                }
+
+                // Store the character in UTF-16 buffer.
+                if (c<0x10000) {
+                    buf[destIx] = (UChar)c;
+                    mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart);
+                } else {
+                    buf[destIx]         = U16_TRAIL(c);
+                    mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart);
+                    buf[--destIx]       = U16_LEAD(c);
+                    mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart);
+                }
+
+                // Fill in the map from native indexes to UChars buf index.
+                do {
+                    mapToUChars[sIx-- - toUCharsMapStart] = (uint8_t)destIx;
+                } while (sIx >= srcIx);
+
+                // Set native indexing limit to be the current position.
+                //   We are processing a non-ascii, non-native-indexing char now;
+                //     the limit will be here if the rest of the chars to be
+                //     added to this buffer are ascii.
+                bufNILimit = destIx;
+            }
+        }
+        u8b->bufNativeStart     = srcIx;
+        u8b->bufNativeLimit     = ix;
+        u8b->bufStartIdx        = destIx;
+        u8b->bufLimitIdx        = UTF8_TEXT_CHUNK_SIZE+2;
+        u8b->bufNILimit         = bufNILimit - u8b->bufStartIdx;
+        u8b->toUCharsMapStart   = toUCharsMapStart;
+
+        ut->chunkContents       = &buf[u8b->bufStartIdx];
+        ut->chunkLength         = u8b->bufLimitIdx - u8b->bufStartIdx;
+        ut->chunkOffset         = ut->chunkLength;
+        ut->chunkNativeStart    = u8b->bufNativeStart;
+        ut->chunkNativeLimit    = u8b->bufNativeLimit;
+        ut->nativeIndexingLimit = u8b->bufNILimit;
+        return TRUE;
+    }
+
+}
+
+
+
+//
+//  This is a slightly modified copy of u_strFromUTF8,
+//     Inserts a Replacement Char rather than failing on invalid UTF-8
+//     Removes unnecessary features.
+//
+static UChar*
+utext_strFromUTF8(UChar *dest,
+              int32_t destCapacity,
+              int32_t *pDestLength,
+              const char* src,
+              int32_t srcLength,        // required.  NUL terminated not supported.
+              UErrorCode *pErrorCode
+              )
+{
+
+    UChar *pDest = dest;
+    UChar *pDestLimit = dest+destCapacity;
+    UChar32 ch=0;
+    int32_t index = 0;
+    int32_t reqLength = 0;
+    uint8_t* pSrc = (uint8_t*) src;
+
+
+    while((index < srcLength)&&(pDest<pDestLimit)){
+        ch = pSrc[index++];
+        if(ch <=0x7f){
+            *pDest++=(UChar)ch;
+        }else{
+            ch=utf8_nextCharSafeBody(pSrc, &index, srcLength, ch, -1);
+            if(ch<0){
+                ch = 0xfffd;
+            }
+            if(U_IS_BMP(ch)){
+                *(pDest++)=(UChar)ch;
+            }else{
+                *(pDest++)=UTF16_LEAD(ch);
+                if(pDest<pDestLimit){
+                    *(pDest++)=UTF16_TRAIL(ch);
+                }else{
+                    reqLength++;
+                    break;
+                }
+            }
+        }
+    }
+    /* donot fill the dest buffer just count the UChars needed */
+    while(index < srcLength){
+        ch = pSrc[index++];
+        if(ch <= 0x7f){
+            reqLength++;
+        }else{
+            ch=utf8_nextCharSafeBody(pSrc, &index, srcLength, ch, -1);
+            if(ch<0){
+                ch = 0xfffd;
+            }
+            reqLength+=U16_LENGTH(ch);
+        }
+    }
+
+    reqLength+=(int32_t)(pDest - dest);
+
+    if(pDestLength){
+        *pDestLength = reqLength;
+    }
+
+    /* Terminate the buffer */
+    u_terminateUChars(dest,destCapacity,reqLength,pErrorCode);
+
+    return dest;
+}
+
+
+
+static int32_t U_CALLCONV
+utf8TextExtract(UText *ut,
+                int64_t start, int64_t limit,
+                UChar *dest, int32_t destCapacity,
+                UErrorCode *pErrorCode) {
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(destCapacity<0 || (dest==NULL && destCapacity>0)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    int32_t  length  = ut->b;
+    int32_t  start32 = pinIndex(start, length);
+    int32_t  limit32 = pinIndex(limit, length);
+
+    if(start32>limit32) {
+        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0;
+    }
+
+
+    // adjust the incoming indexes to land on code point boundaries if needed.
+    //    adjust by no more than three, because that is the largest number of trail bytes
+    //    in a well formed UTF8 character.
+    const uint8_t *buf = (const uint8_t *)ut->context;
+    int i;
+    if (start32 < ut->chunkNativeLimit) {
+        for (i=0; i<3; i++) {
+            if (U8_IS_SINGLE(buf[start32]) || U8_IS_LEAD(buf[start32]) || start32==0) {
+                break;
+            }
+            start32--;
+        }
+    }
+
+    if (limit32 < ut->chunkNativeLimit) {
+        for (i=0; i<3; i++) {
+            if (U8_IS_SINGLE(buf[limit32]) || U8_IS_LEAD(buf[limit32]) || limit32==0) {
+                break;
+            }
+            limit32--;
+        }
+    }
+
+    // Do the actual extract.
+    int32_t destLength=0;
+    utext_strFromUTF8(dest, destCapacity, &destLength,
+                    (const char *)ut->context+start32, limit32-start32,
+                    pErrorCode);
+    utf8TextAccess(ut, limit32, TRUE);
+    return destLength;
+}
+
+//
+// utf8TextMapOffsetToNative
+//
+// Map a chunk (UTF-16) offset to a native index.
+static int64_t U_CALLCONV
+utf8TextMapOffsetToNative(const UText *ut) {
+    //
+    UTF8Buf *u8b = (UTF8Buf *)ut->p;
+    U_ASSERT(ut->chunkOffset>ut->nativeIndexingLimit && ut->chunkOffset<=ut->chunkLength);
+    int32_t nativeOffset = u8b->mapToNative[ut->chunkOffset + u8b->bufStartIdx] + u8b->toUCharsMapStart;
+    U_ASSERT(nativeOffset >= ut->chunkNativeStart && nativeOffset <= ut->chunkNativeLimit);
+    return nativeOffset;
+}
+
+//
+// Map a native index to the corrsponding chunk offset
+//
+static int32_t U_CALLCONV
+utf8TextMapIndexToUTF16(const UText *ut, int64_t index64) {
+    U_ASSERT(index64 <= 0x7fffffff);
+    int32_t index = (int32_t)index64;
+    UTF8Buf *u8b = (UTF8Buf *)ut->p;
+    U_ASSERT(index>=ut->chunkNativeStart+ut->nativeIndexingLimit);
+    U_ASSERT(index<=ut->chunkNativeLimit);
+    int32_t mapIndex = index - u8b->toUCharsMapStart;
+    int32_t offset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx;
+    U_ASSERT(offset>=0 && offset<=ut->chunkLength);
+    return offset;
+}
+
+static UText * U_CALLCONV
+utf8TextClone(UText *dest, const UText *src, UBool deep, UErrorCode *status)
+{
+    // First do a generic shallow clone.  Does everything needed for the UText struct itself.
+    dest = shallowTextClone(dest, src, status);
+
+    // For deep clones, make a copy of the string.
+    //  The copied storage is owned by the newly created clone.
+    //
+    // TODO:  There is an isssue with using utext_nativeLength().
+    //        That function is non-const in cases where the input was NUL terminated
+    //          and the length has not yet been determined.
+    //        This function (clone()) is const.
+    //        There potentially a thread safety issue lurking here.
+    //
+    if (deep && U_SUCCESS(*status)) {
+        int32_t  len = (int32_t)utext_nativeLength((UText *)src);
+        char *copyStr = (char *)uprv_malloc(len+1);
+        if (copyStr == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+        } else {
+            uprv_memcpy(copyStr, src->context, len+1);
+            dest->context = copyStr;
+            dest->providerProperties |= I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT);
+        }
+    }
+    return dest;
+}
+
+
+static void U_CALLCONV
+utf8TextClose(UText *ut) {
+    // Most of the work of close is done by the generic UText framework close.
+    // All that needs to be done here is to delete the UTF8 string if the UText
+    //  owns it.  This occurs if the UText was created by cloning.
+    if (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT)) {
+        char *s = (char *)ut->context;
+        uprv_free(s);
+        ut->context = NULL;
+    }
+}
+
+U_CDECL_END
+
+
+static const struct UTextFuncs utf8Funcs = 
+{
+    sizeof(UTextFuncs),
+    0, 0, 0,             // Reserved alignment padding
+    utf8TextClone,
+    utf8TextLength,
+    utf8TextAccess,
+    utf8TextExtract,
+    NULL,                /* replace*/
+    NULL,                /* copy   */
+    utf8TextMapOffsetToNative,
+    utf8TextMapIndexToUTF16,
+    utf8TextClose,
+    NULL,                // spare 1
+    NULL,                // spare 2
+    NULL                 // spare 3
+};
+
+
+static const char gEmptyString[] = {0};
+
+U_CAPI UText * U_EXPORT2
+utext_openUTF8(UText *ut, const char *s, int64_t length, UErrorCode *status) {
+    if(U_FAILURE(*status)) {
+        return NULL;
+    }
+    if(s==NULL && length==0) {
+        s = gEmptyString;
+    }
+
+    if(s==NULL || length<-1 || length>INT32_MAX) {
+        *status=U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    ut = utext_setup(ut, sizeof(UTF8Buf) * 2, status);
+    if (U_FAILURE(*status)) {
+        return ut;
+    }
+
+    ut->pFuncs  = &utf8Funcs;
+    ut->context = s;
+    ut->b       = (int32_t)length;
+    ut->c       = (int32_t)length;
+    if (ut->c < 0) {
+        ut->c = 0;
+        ut->providerProperties |= I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE);
+    }
+    ut->p = ut->pExtra;
+    ut->q = (char *)ut->pExtra + sizeof(UTF8Buf);
+    return ut;
+
+}
+
+
+
+
+
+
+
+
+//------------------------------------------------------------------------------
+//
+//     UText implementation wrapper for Replaceable (read/write)
+//
+//         Use of UText data members:
+//            context    pointer to Replaceable.
+//            p          pointer to Replaceable if it is owned by the UText.
+//
+//------------------------------------------------------------------------------
+
+
+
+// minimum chunk size for this implementation: 3
+// to allow for possible trimming for code point boundaries
+enum { REP_TEXT_CHUNK_SIZE=10 };
+
+struct ReplExtra {
+    /*
+     * Chunk UChars.
+     * +1 to simplify filling with surrogate pair at the end.
+     */
+    UChar s[REP_TEXT_CHUNK_SIZE+1];
+};
+
+
+U_CDECL_BEGIN
+
+static UText * U_CALLCONV
+repTextClone(UText *dest, const UText *src, UBool deep, UErrorCode *status) {
+    // First do a generic shallow clone.  Does everything needed for the UText struct itself.
+    dest = shallowTextClone(dest, src, status);
+
+    // For deep clones, make a copy of the Replaceable.
+    //  The copied Replaceable storage is owned by the newly created UText clone.
+    //  A non-NULL pointer in UText.p is the signal to the close() function to delete
+    //    it.
+    //
+    if (deep && U_SUCCESS(*status)) {
+        const Replaceable *replSrc = (const Replaceable *)src->context;
+        dest->context = replSrc->clone();
+        dest->providerProperties |= I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT);
+
+        // with deep clone, the copy is writable, even when the source is not.
+        dest->providerProperties |= I32_FLAG(UTEXT_PROVIDER_WRITABLE);
+    }
+    return dest;
+}
+
+
+static void U_CALLCONV
+repTextClose(UText *ut) {
+    // Most of the work of close is done by the generic UText framework close.
+    // All that needs to be done here is delete the Replaceable if the UText
+    //  owns it.  This occurs if the UText was created by cloning.
+    if (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT)) {
+        Replaceable *rep = (Replaceable *)ut->context;
+        delete rep;
+        ut->context = NULL;
+    }
+}
+
+
+static int64_t U_CALLCONV
+repTextLength(UText *ut) {
+    const Replaceable *replSrc = (const Replaceable *)ut->context;
+    int32_t  len = replSrc->length();
+    return len;
+}
+
+
+static UBool U_CALLCONV
+repTextAccess(UText *ut, int64_t index, UBool forward) {
+    const Replaceable *rep=(const Replaceable *)ut->context;
+    int32_t length=rep->length();   // Full length of the input text (bigger than a chunk)
+
+    // clip the requested index to the limits of the text.
+    int32_t index32 = pinIndex(index, length);
+    U_ASSERT(index<=INT32_MAX);
+
+
+    /*
+     * Compute start/limit boundaries around index, for a segment of text
+     * to be extracted.
+     * To allow for the possibility that our user gave an index to the trailing
+     * half of a surrogate pair, we must request one extra preceding UChar when
+     * going in the forward direction.  This will ensure that the buffer has the
+     * entire code point at the specified index.
+     */
+    if(forward) {
+
+        if (index32>=ut->chunkNativeStart && index32<ut->chunkNativeLimit) {
+            // Buffer already contains the requested position.
+            ut->chunkOffset = (int32_t)(index - ut->chunkNativeStart);
+            return TRUE;
+        }
+        if (index32>=length && ut->chunkNativeLimit==length) {
+            // Request for end of string, and buffer already extends up to it.
+            // Can't get the data, but don't change the buffer.
+            ut->chunkOffset = length - (int32_t)ut->chunkNativeStart;
+            return FALSE;
+        }
+
+        ut->chunkNativeLimit = index + REP_TEXT_CHUNK_SIZE - 1;
+        // Going forward, so we want to have the buffer with stuff at and beyond
+        //   the requested index.  The -1 gets us one code point before the
+        //   requested index also, to handle the case of the index being on
+        //   a trail surrogate of a surrogate pair.
+        if(ut->chunkNativeLimit > length) {
+            ut->chunkNativeLimit = length;
+        }
+        // unless buffer ran off end, start is index-1.
+        ut->chunkNativeStart = ut->chunkNativeLimit - REP_TEXT_CHUNK_SIZE;
+        if(ut->chunkNativeStart < 0) {
+            ut->chunkNativeStart = 0;
+        }
+    } else {
+        // Reverse iteration.  Fill buffer with data preceding the requested index.
+        if (index32>ut->chunkNativeStart && index32<=ut->chunkNativeLimit) {
+            // Requested position already in buffer.
+            ut->chunkOffset = index32 - (int32_t)ut->chunkNativeStart;
+            return TRUE;
+        }
+        if (index32==0 && ut->chunkNativeStart==0) {
+            // Request for start, buffer already begins at start.
+            //  No data, but keep the buffer as is.
+            ut->chunkOffset = 0;
+            return FALSE;
+        }
+
+        // Figure out the bounds of the chunk to extract for reverse iteration.
+        // Need to worry about chunk not splitting surrogate pairs, and while still
+        // containing the data we need.
+        // Fix by requesting a chunk that includes an extra UChar at the end.
+        // If this turns out to be a lead surrogate, we can lop it off and still have
+        //   the data we wanted.
+        ut->chunkNativeStart = index32 + 1 - REP_TEXT_CHUNK_SIZE;
+        if (ut->chunkNativeStart < 0) {
+            ut->chunkNativeStart = 0;
+        }
+
+        ut->chunkNativeLimit = index32 + 1;
+        if (ut->chunkNativeLimit > length) {
+            ut->chunkNativeLimit = length;
+        }
+    }
+
+    // Extract the new chunk of text from the Replaceable source.
+    ReplExtra *ex = (ReplExtra *)ut->pExtra;
+    // UnicodeString with its buffer a writable alias to the chunk buffer
+    UnicodeString buffer(ex->s, 0 /*buffer length*/, REP_TEXT_CHUNK_SIZE /*buffer capacity*/);
+    rep->extractBetween((int32_t)ut->chunkNativeStart, (int32_t)ut->chunkNativeLimit, buffer);
+
+    ut->chunkContents  = ex->s;
+    ut->chunkLength    = (int32_t)(ut->chunkNativeLimit - ut->chunkNativeStart);
+    ut->chunkOffset    = (int32_t)(index32 - ut->chunkNativeStart);
+
+    // Surrogate pairs from the input text must not span chunk boundaries.
+    // If end of chunk could be the start of a surrogate, trim it off.
+    if (ut->chunkNativeLimit < length &&
+        U16_IS_LEAD(ex->s[ut->chunkLength-1])) {
+            ut->chunkLength--;
+            ut->chunkNativeLimit--;
+            if (ut->chunkOffset > ut->chunkLength) {
+                ut->chunkOffset = ut->chunkLength;
+            }
+        }
+
+    // if the first UChar in the chunk could be the trailing half of a surrogate pair,
+    // trim it off.
+    if(ut->chunkNativeStart>0 && U16_IS_TRAIL(ex->s[0])) {
+        ++(ut->chunkContents);
+        ++(ut->chunkNativeStart);
+        --(ut->chunkLength);
+        --(ut->chunkOffset);
+    }
+
+    // adjust the index/chunkOffset to a code point boundary
+    U16_SET_CP_START(ut->chunkContents, 0, ut->chunkOffset);
+
+    // Use fast indexing for get/setNativeIndex()
+    ut->nativeIndexingLimit = ut->chunkLength;
+
+    return TRUE;
+}
+
+
+
+static int32_t U_CALLCONV
+repTextExtract(UText *ut,
+               int64_t start, int64_t limit,
+               UChar *dest, int32_t destCapacity,
+               UErrorCode *status) {
+    const Replaceable *rep=(const Replaceable *)ut->context;
+    int32_t  length=rep->length();
+
+    if(U_FAILURE(*status)) {
+        return 0;
+    }
+    if(destCapacity<0 || (dest==NULL && destCapacity>0)) {
+        *status=U_ILLEGAL_ARGUMENT_ERROR;
+    }
+    if(start>limit) {
+        *status=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0;
+    }
+
+    int32_t  start32 = pinIndex(start, length);
+    int32_t  limit32 = pinIndex(limit, length);
+
+    // adjust start, limit if they point to trail half of surrogates
+    if (start32<length && U16_IS_TRAIL(rep->charAt(start32)) &&
+        U_IS_SUPPLEMENTARY(rep->char32At(start32))){
+            start32--;
+    }
+    if (limit32<length && U16_IS_TRAIL(rep->charAt(limit32)) &&
+        U_IS_SUPPLEMENTARY(rep->char32At(limit32))){
+            limit32--;
+    }
+
+    length=limit32-start32;
+    if(length>destCapacity) {
+        limit32 = start32 + destCapacity;
+    }
+    UnicodeString buffer(dest, 0, destCapacity); // writable alias
+    rep->extractBetween(start32, limit32, buffer);
+    repTextAccess(ut, limit32, TRUE);
+    
+    return u_terminateUChars(dest, destCapacity, length, status);
+}
+
+static int32_t U_CALLCONV
+repTextReplace(UText *ut,
+               int64_t start, int64_t limit,
+               const UChar *src, int32_t length,
+               UErrorCode *status) {
+    Replaceable *rep=(Replaceable *)ut->context;
+    int32_t oldLength;
+
+    if(U_FAILURE(*status)) {
+        return 0;
+    }
+    if(src==NULL && length!=0) {
+        *status=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    oldLength=rep->length(); // will subtract from new length
+    if(start>limit ) {
+        *status=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0;
+    }
+
+    int32_t start32 = pinIndex(start, oldLength);
+    int32_t limit32 = pinIndex(limit, oldLength);
+
+    // Snap start & limit to code point boundaries.
+    if (start32<oldLength && U16_IS_TRAIL(rep->charAt(start32)) &&
+        start32>0 && U16_IS_LEAD(rep->charAt(start32-1)))
+    {
+            start32--;
+    }
+    if (limit32<oldLength && U16_IS_LEAD(rep->charAt(limit32-1)) &&
+        U16_IS_TRAIL(rep->charAt(limit32)))
+    {
+            limit32++;
+    }
+
+    // Do the actual replace operation using methods of the Replaceable class
+    UnicodeString replStr((UBool)(length<0), src, length); // read-only alias
+    rep->handleReplaceBetween(start32, limit32, replStr);
+    int32_t newLength = rep->length();
+    int32_t lengthDelta = newLength - oldLength;
+
+    // Is the UText chunk buffer OK?
+    if (ut->chunkNativeLimit > start32) {
+        // this replace operation may have impacted the current chunk.
+        // invalidate it, which will force a reload on the next access.
+        invalidateChunk(ut);
+    }
+
+    // set the iteration position to the end of the newly inserted replacement text.
+    int32_t newIndexPos = limit32 + lengthDelta;
+    repTextAccess(ut, newIndexPos, TRUE);
+
+    return lengthDelta;
+}
+
+
+static void U_CALLCONV
+repTextCopy(UText *ut,
+                int64_t start, int64_t limit,
+                int64_t destIndex,
+                UBool move,
+                UErrorCode *status)
+{
+    Replaceable *rep=(Replaceable *)ut->context;
+    int32_t length=rep->length();
+
+    if(U_FAILURE(*status)) {
+        return;
+    }
+    if (start>limit || (start<destIndex && destIndex<limit))
+    {
+        *status=U_INDEX_OUTOFBOUNDS_ERROR;
+        return;
+    }
+
+    int32_t start32     = pinIndex(start, length);
+    int32_t limit32     = pinIndex(limit, length);
+    int32_t destIndex32 = pinIndex(destIndex, length);
+
+    // TODO:  snap input parameters to code point boundaries.
+
+    if(move) {
+        // move: copy to destIndex, then replace original with nothing
+        int32_t segLength=limit32-start32;
+        rep->copy(start32, limit32, destIndex32);
+        if(destIndex32<start32) {
+            start32+=segLength;
+            limit32+=segLength;
+        }
+        rep->handleReplaceBetween(start32, limit32, UnicodeString());
+    } else {
+        // copy
+        rep->copy(start32, limit32, destIndex32);
+    }
+
+    // If the change to the text touched the region in the chunk buffer,
+    //  invalidate the buffer.
+    int32_t firstAffectedIndex = destIndex32;
+    if (move && start32<firstAffectedIndex) {
+        firstAffectedIndex = start32;
+    }
+    if (firstAffectedIndex < ut->chunkNativeLimit) {
+        // changes may have affected range covered by the chunk
+        invalidateChunk(ut);
+    }
+
+    // Put iteration position at the newly inserted (moved) block,
+    int32_t  nativeIterIndex = destIndex32 + limit32 - start32;
+    if (move && destIndex32>start32) {
+        // moved a block of text towards the end of the string.
+        nativeIterIndex = destIndex32;
+    }
+
+    // Set position, reload chunk if needed.
+    repTextAccess(ut, nativeIterIndex, TRUE);
+}
+
+static const struct UTextFuncs repFuncs = 
+{
+    sizeof(UTextFuncs),
+    0, 0, 0,           // Reserved alignment padding
+    repTextClone,
+    repTextLength,
+    repTextAccess,
+    repTextExtract,
+    repTextReplace,   
+    repTextCopy,   
+    NULL,              // MapOffsetToNative,
+    NULL,              // MapIndexToUTF16,
+    repTextClose,
+    NULL,              // spare 1
+    NULL,              // spare 2
+    NULL               // spare 3
+};
+
+
+U_CAPI UText * U_EXPORT2
+utext_openReplaceable(UText *ut, Replaceable *rep, UErrorCode *status)
+{
+    if(U_FAILURE(*status)) {
+        return NULL;
+    }
+    if(rep==NULL) {
+        *status=U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+    ut = utext_setup(ut, sizeof(ReplExtra), status);
+
+    ut->providerProperties = I32_FLAG(UTEXT_PROVIDER_WRITABLE);
+    if(rep->hasMetaData()) {
+        ut->providerProperties |=I32_FLAG(UTEXT_PROVIDER_HAS_META_DATA);
+    }
+
+    ut->pFuncs  = &repFuncs;
+    ut->context =  rep;
+    return ut;
+}
+
+U_CDECL_END
+
+
+
+
+
+
+
+
+//------------------------------------------------------------------------------
+//
+//     UText implementation for UnicodeString (read/write)  and
+//                    for const UnicodeString (read only)
+//             (same implementation, only the flags are different)
+//
+//         Use of UText data members:
+//            context    pointer to UnicodeString
+//            p          pointer to UnicodeString IF this UText owns the string
+//                       and it must be deleted on close().  NULL otherwise.
+//
+//------------------------------------------------------------------------------
+
+U_CDECL_BEGIN
+
+
+static UText * U_CALLCONV
+unistrTextClone(UText *dest, const UText *src, UBool deep, UErrorCode *status) {
+    // First do a generic shallow clone.  Does everything needed for the UText struct itself.
+    dest = shallowTextClone(dest, src, status);
+
+    // For deep clones, make a copy of the UnicodeSring.
+    //  The copied UnicodeString storage is owned by the newly created UText clone.
+    //  A non-NULL pointer in UText.p is the signal to the close() function to delete
+    //    the UText.
+    //
+    if (deep && U_SUCCESS(*status)) {
+        const UnicodeString *srcString = (const UnicodeString *)src->context;
+        dest->context = new UnicodeString(*srcString);
+        dest->providerProperties |= I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT);
+
+        // with deep clone, the copy is writable, even when the source is not.
+        dest->providerProperties |= I32_FLAG(UTEXT_PROVIDER_WRITABLE);
+    }
+    return dest;
+}
+
+static void U_CALLCONV
+unistrTextClose(UText *ut) {
+    // Most of the work of close is done by the generic UText framework close.
+    // All that needs to be done here is delete the UnicodeString if the UText
+    //  owns it.  This occurs if the UText was created by cloning.
+    if (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT)) {
+        UnicodeString *str = (UnicodeString *)ut->context;
+        delete str;
+        ut->context = NULL;
+    }
+}
+
+
+static int64_t U_CALLCONV
+unistrTextLength(UText *t) {
+    return ((const UnicodeString *)t->context)->length();
+}
+
+
+static UBool U_CALLCONV
+unistrTextAccess(UText *ut, int64_t index, UBool  forward) {
+    int32_t length  = ut->chunkLength;
+    ut->chunkOffset = pinIndex(index, length);
+
+    // Check whether request is at the start or end
+    UBool retVal = (forward && index<length) || (!forward && index>0);
+    return retVal;
+}
+
+
+
+static int32_t U_CALLCONV
+unistrTextExtract(UText *t,
+                  int64_t start, int64_t limit,
+                  UChar *dest, int32_t destCapacity,
+                  UErrorCode *pErrorCode) {
+    const UnicodeString *us=(const UnicodeString *)t->context;
+    int32_t length=us->length();
+
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(destCapacity<0 || (dest==NULL && destCapacity>0)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+    }
+    if(start<0 || start>limit) {
+        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0;
+    }
+
+    int32_t start32 = start<length ? us->getChar32Start((int32_t)start) : length;
+    int32_t limit32 = limit<length ? us->getChar32Start((int32_t)limit) : length;
+
+    length=limit32-start32;
+    if (destCapacity>0 && dest!=NULL) {
+        int32_t trimmedLength = length;
+        if(trimmedLength>destCapacity) {
+            trimmedLength=destCapacity;
+        }
+        us->extract(start32, trimmedLength, dest);
+        t->chunkOffset = start32+trimmedLength;
+    } else {
+        t->chunkOffset = start32;
+    }
+    u_terminateUChars(dest, destCapacity, length, pErrorCode);
+    return length;
+}
+
+static int32_t U_CALLCONV
+unistrTextReplace(UText *ut,
+                  int64_t start, int64_t limit,
+                  const UChar *src, int32_t length,
+                  UErrorCode *pErrorCode) {
+    UnicodeString *us=(UnicodeString *)ut->context;
+    int32_t oldLength;
+
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(src==NULL && length!=0) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+    }
+    if(start>limit) {
+        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0;
+    }
+    oldLength=us->length();
+    int32_t start32 = pinIndex(start, oldLength);
+    int32_t limit32 = pinIndex(limit, oldLength);
+    if (start32 < oldLength) {
+        start32 = us->getChar32Start(start32);
+    }
+    if (limit32 < oldLength) {
+        limit32 = us->getChar32Start(limit32);
+    }
+
+    // replace
+    us->replace(start32, limit32-start32, src, length);
+    int32_t newLength = us->length();
+
+    // Update the chunk description.
+    ut->chunkContents    = us->getBuffer();
+    ut->chunkLength      = newLength;
+    ut->chunkNativeLimit = newLength;
+    ut->nativeIndexingLimit = newLength;
+
+    // Set iteration position to the point just following the newly inserted text.
+    int32_t lengthDelta = newLength - oldLength;
+    ut->chunkOffset = limit32 + lengthDelta;
+
+    return lengthDelta;
+}
+
+static void U_CALLCONV
+unistrTextCopy(UText *ut,
+               int64_t start, int64_t limit,
+               int64_t destIndex,
+               UBool move,
+               UErrorCode *pErrorCode) {
+    UnicodeString *us=(UnicodeString *)ut->context;
+    int32_t length=us->length();
+
+    if(U_FAILURE(*pErrorCode)) {
+        return;
+    }
+    int32_t start32 = pinIndex(start, length);
+    int32_t limit32 = pinIndex(limit, length);
+    int32_t destIndex32 = pinIndex(destIndex, length);
+
+    if( start32>limit32 || (start32<destIndex32 && destIndex32<limit32)) {
+        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+        return;
+    }
+
+    if(move) {
+        // move: copy to destIndex, then replace original with nothing
+        int32_t segLength=limit32-start32;
+        us->copy(start32, limit32, destIndex32);
+        if(destIndex32<start32) {
+            start32+=segLength;
+        }
+        us->replace(start32, segLength, NULL, 0);
+    } else {
+        // copy
+        us->copy(start32, limit32, destIndex32);
+    }
+
+    // update chunk description, set iteration position.
+    ut->chunkContents = us->getBuffer();
+    if (move==FALSE) {
+        // copy operation, string length grows
+        ut->chunkLength += limit32-start32;
+        ut->chunkNativeLimit = ut->chunkLength;
+        ut->nativeIndexingLimit = ut->chunkLength;
+    }
+
+    // Iteration position to end of the newly inserted text.
+    ut->chunkOffset = destIndex32+limit32-start32;
+    if (move && destIndex32>start32) {
+        ut->chunkOffset = destIndex32;
+    }
+
+}
+
+static const struct UTextFuncs unistrFuncs = 
+{
+    sizeof(UTextFuncs),
+    0, 0, 0,             // Reserved alignment padding
+    unistrTextClone,
+    unistrTextLength,
+    unistrTextAccess,
+    unistrTextExtract,
+    unistrTextReplace,   
+    unistrTextCopy,   
+    NULL,                // MapOffsetToNative,
+    NULL,                // MapIndexToUTF16,
+    unistrTextClose,
+    NULL,                // spare 1
+    NULL,                // spare 2
+    NULL                 // spare 3
+};
+
+
+
+U_CDECL_END
+
+
+U_CAPI UText * U_EXPORT2
+utext_openUnicodeString(UText *ut, UnicodeString *s, UErrorCode *status) {
+    // TODO:  use openConstUnicodeString, then add in the differences.
+    //
+    ut = utext_setup(ut, 0, status);
+    if (U_SUCCESS(*status)) {
+        ut->pFuncs              = &unistrFuncs;
+        ut->context             = s;
+        ut->providerProperties  = I32_FLAG(UTEXT_PROVIDER_STABLE_CHUNKS)|
+                                  I32_FLAG(UTEXT_PROVIDER_WRITABLE);
+
+        ut->chunkContents       = s->getBuffer();
+        ut->chunkLength         = s->length();
+        ut->chunkNativeStart    = 0;
+        ut->chunkNativeLimit    = ut->chunkLength;
+        ut->nativeIndexingLimit = ut->chunkLength;
+    }
+    return ut;
+}
+
+
+
+U_CAPI UText * U_EXPORT2
+utext_openConstUnicodeString(UText *ut, const UnicodeString *s, UErrorCode *status) {
+    ut = utext_setup(ut, 0, status);
+    //    note:  use the standard (writable) function table for UnicodeString.
+    //           The flag settings disable writing, so having the functions in
+    //           the table is harmless.
+    if (U_SUCCESS(*status)) {
+        ut->pFuncs              = &unistrFuncs;
+        ut->context             = s;
+        ut->providerProperties  = I32_FLAG(UTEXT_PROVIDER_STABLE_CHUNKS);
+        ut->chunkContents       = s->getBuffer();
+        ut->chunkLength         = s->length();
+        ut->chunkNativeStart    = 0;
+        ut->chunkNativeLimit    = ut->chunkLength;
+        ut->nativeIndexingLimit = ut->chunkLength;
+    }
+    return ut;
+}
+
+//------------------------------------------------------------------------------
+//
+//     UText implementation for const UChar * strings
+//
+//         Use of UText data members:
+//            context    pointer to UnicodeString
+//            a          length.  -1 if not yet known.
+//
+//         TODO:  support 64 bit lengths.
+//
+//------------------------------------------------------------------------------
+
+U_CDECL_BEGIN
+
+
+static UText * U_CALLCONV
+ucstrTextClone(UText *dest, const UText * src, UBool deep, UErrorCode * status) {
+    // First do a generic shallow clone.
+    dest = shallowTextClone(dest, src, status);
+
+    // For deep clones, make a copy of the string.
+    //  The copied storage is owned by the newly created clone.
+    //  A non-NULL pointer in UText.p is the signal to the close() function to delete
+    //    it.
+    //
+    if (deep && U_SUCCESS(*status)) {
+        U_ASSERT(utext_nativeLength(dest) < INT32_MAX);
+        int32_t  len = (int32_t)utext_nativeLength(dest);
+
+        // The cloned string IS going to be NUL terminated, whether or not the original was.
+        const UChar *srcStr = (const UChar *)src->context;
+        UChar *copyStr = (UChar *)uprv_malloc((len+1) * sizeof(UChar));
+        if (copyStr == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+        } else {
+            int64_t i;
+            for (i=0; i<len; i++) {
+                copyStr[i] = srcStr[i];
+            }
+            copyStr[len] = 0;
+            dest->context = copyStr;
+            dest->providerProperties |= I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT);
+        }
+    }
+    return dest;
+}
+
+
+static void U_CALLCONV
+ucstrTextClose(UText *ut) {
+    // Most of the work of close is done by the generic UText framework close.
+    // All that needs to be done here is delete the string if the UText
+    //  owns it.  This occurs if the UText was created by cloning.
+    if (ut->providerProperties & I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT)) {
+        UChar *s = (UChar *)ut->context;
+        uprv_free(s);
+        ut->context = NULL;
+    }
+}
+
+
+
+static int64_t U_CALLCONV
+ucstrTextLength(UText *ut) {
+    if (ut->a < 0) {
+        // null terminated, we don't yet know the length.  Scan for it.
+        //    Access is not convenient for doing this
+        //    because the current interation postion can't be changed.
+        const UChar  *str = (const UChar *)ut->context;
+        for (;;) {
+            if (str[ut->chunkNativeLimit] == 0) {
+                break;
+            }
+            ut->chunkNativeLimit++;
+        }
+        ut->a = ut->chunkNativeLimit;
+        ut->chunkLength = (int32_t)ut->chunkNativeLimit;
+        ut->nativeIndexingLimit = ut->chunkLength;
+        ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE);
+    }
+    return ut->a;
+}
+
+
+static UBool U_CALLCONV
+ucstrTextAccess(UText *ut, int64_t index, UBool  forward) {
+    const UChar *str   = (const UChar *)ut->context;
+
+    // pin the requested index to the bounds of the string,
+    //  and set current iteration position.
+    if (index<0) {
+        index = 0;
+    } else if (index < ut->chunkNativeLimit) {
+        // The request data is within the chunk as it is known so far.
+        // Put index on a code point boundary.
+        U16_SET_CP_START(str, 0, index);
+    } else if (ut->a >= 0) {
+        // We know the length of this string, and the user is requesting something
+        // at or beyond the length.  Pin the requested index to the length.
+        index = ut->a;
+    } else {
+        // Null terminated string, length not yet known, and the requested index
+        //  is beyond where we have scanned so far.
+        //  Scan to 32 UChars beyond the requested index.  The strategy here is
+        //  to avoid fully scanning a long string when the caller only wants to
+        //  see a few characters at its beginning.
+        int32_t scanLimit = (int32_t)index + 32;
+        if ((index + 32)>INT32_MAX || (index + 32)<0 ) {   // note: int64 expression
+            scanLimit = INT32_MAX;
+        }
+
+        int32_t chunkLimit = (int32_t)ut->chunkNativeLimit;
+        for (; chunkLimit<scanLimit; chunkLimit++) {
+            if (str[chunkLimit] == 0) {
+                // We found the end of the string.  Remember it, pin the requested index to it,
+                //  and bail out of here.
+                ut->a = chunkLimit;
+                ut->chunkLength = chunkLimit;
+                ut->nativeIndexingLimit = chunkLimit;
+                if (index >= chunkLimit) {
+                    index = chunkLimit;
+                } else {
+                    U16_SET_CP_START(str, 0, index);
+                }
+
+                ut->chunkNativeLimit = chunkLimit;
+                ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE);
+                goto breakout;
+            }
+        }
+        // We scanned through the next batch of UChars without finding the end.
+        U16_SET_CP_START(str, 0, index);
+        if (chunkLimit == INT32_MAX) {
+            // Scanned to the limit of a 32 bit length.
+            // Forceably trim the overlength string back so length fits in int32
+            //  TODO:  add support for 64 bit strings.
+            ut->a = chunkLimit;
+            ut->chunkLength = chunkLimit;
+            ut->nativeIndexingLimit = chunkLimit;
+            if (index > chunkLimit) {
+                index = chunkLimit;
+            }
+            ut->chunkNativeLimit = chunkLimit;
+            ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE);
+        } else {
+            // The endpoint of a chunk must not be left in the middle of a surrogate pair.
+            // If the current end is on a lead surrogate, back the end up by one.
+            // It doesn't matter if the end char happens to be an unpaired surrogate,
+            //    and it's simpler not to worry about it.
+            if (U16_IS_LEAD(str[chunkLimit-1])) {
+                --chunkLimit;
+            }
+            // Null-terminated chunk with end still unknown.
+            // Update the chunk length to reflect what has been scanned thus far.
+            // That the full length is still unknown is (still) flagged by
+            //    ut->a being < 0.
+            ut->chunkNativeLimit = chunkLimit;
+            ut->nativeIndexingLimit = chunkLimit;
+            ut->chunkLength = chunkLimit;
+        }
+
+    }
+breakout:
+    U_ASSERT(index<=INT32_MAX);
+    ut->chunkOffset = (int32_t)index;
+
+    // Check whether request is at the start or end
+    UBool retVal = (forward && index<ut->chunkNativeLimit) || (!forward && index>0);
+    return retVal;
+}
+
+
+
+static int32_t U_CALLCONV
+ucstrTextExtract(UText *ut,
+                  int64_t start, int64_t limit,
+                  UChar *dest, int32_t destCapacity,
+                  UErrorCode *pErrorCode)
+{
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(destCapacity<0 || (dest==NULL && destCapacity>0) || start>limit) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    //const UChar *s=(const UChar *)ut->context;
+    int32_t si, di;
+
+    int32_t start32;
+    int32_t limit32;
+
+    // Access the start.  Does two things we need:
+    //   Pins 'start' to the length of the string, if it came in out-of-bounds.
+    //   Snaps 'start' to the beginning of a code point.
+    ucstrTextAccess(ut, start, TRUE);
+    const UChar *s=ut->chunkContents;
+    start32 = ut->chunkOffset;
+
+    int32_t strLength=(int32_t)ut->a;
+    if (strLength >= 0) {
+        limit32 = pinIndex(limit, strLength);
+    } else {
+        limit32 = pinIndex(limit, INT32_MAX);
+    }
+
+    di = 0;
+    for (si=start32; si<limit32; si++) {
+        if (strLength<0 && s[si]==0) {
+            // Just hit the end of a null-terminated string.
+            ut->a = si;               // set string length for this UText
+            ut->chunkNativeLimit    = si;
+            ut->chunkLength         = si;
+            ut->nativeIndexingLimit = si;
+            strLength               = si;
+            break;
+        }
+        if (di<destCapacity) {
+            // only store if there is space.
+            dest[di] = s[si];
+        } else {
+            if (strLength>=0) {
+                // We have filled the destination buffer, and the string length is known.
+                //  Cut the loop short.  There is no need to scan string termination.
+                di = limit32 - start32;
+                si = limit32;
+                break;
+            }
+        }
+        di++;
+    }
+
+    // If the limit index points to a lead surrogate of a pair,
+    //   add the corresponding trail surrogate to the destination.
+    if (si>0 && U16_IS_LEAD(s[si-1]) &&
+        ((si<strLength || strLength<0)  && U16_IS_TRAIL(s[si])))
+    {
+        if (di<destCapacity) {
+            // store only if there is space in the output buffer.
+            dest[di++] = s[si++];
+        }
+    }
+
+    // Put iteration position at the point just following the extracted text
+    ut->chunkOffset = uprv_min(strLength, start32 + destCapacity);
+
+    // Add a terminating NUL if space in the buffer permits,
+    // and set the error status as required.
+    u_terminateUChars(dest, destCapacity, di, pErrorCode);
+    return di;
+}
+
+static const struct UTextFuncs ucstrFuncs = 
+{
+    sizeof(UTextFuncs),
+    0, 0, 0,           // Reserved alignment padding
+    ucstrTextClone,
+    ucstrTextLength,
+    ucstrTextAccess,
+    ucstrTextExtract,
+    NULL,              // Replace
+    NULL,              // Copy
+    NULL,              // MapOffsetToNative,
+    NULL,              // MapIndexToUTF16,
+    ucstrTextClose,
+    NULL,              // spare 1
+    NULL,              // spare 2
+    NULL,              // spare 3
+};
+
+U_CDECL_END
+
+static const UChar gEmptyUString[] = {0};
+
+U_CAPI UText * U_EXPORT2
+utext_openUChars(UText *ut, const UChar *s, int64_t length, UErrorCode *status) {
+    if (U_FAILURE(*status)) {
+        return NULL;
+    }
+    if(s==NULL && length==0) {
+        s = gEmptyUString;
+    }
+    if (s==NULL || length < -1 || length>INT32_MAX) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+    ut = utext_setup(ut, 0, status);
+    if (U_SUCCESS(*status)) {
+        ut->pFuncs               = &ucstrFuncs;
+        ut->context              = s;
+        ut->providerProperties   = I32_FLAG(UTEXT_PROVIDER_STABLE_CHUNKS);
+        if (length==-1) {
+            ut->providerProperties |= I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE);
+        }
+        ut->a                    = length;
+        ut->chunkContents        = s;
+        ut->chunkNativeStart     = 0;
+        ut->chunkNativeLimit     = length>=0? length : 0;
+        ut->chunkLength          = (int32_t)ut->chunkNativeLimit;
+        ut->chunkOffset          = 0;
+        ut->nativeIndexingLimit  = ut->chunkLength;
+    }
+    return ut;
+}
+
+
+//------------------------------------------------------------------------------
+//
+//     UText implementation for text from ICU CharacterIterators
+//
+//         Use of UText data members:
+//            context    pointer to the CharacterIterator
+//            a          length of the full text.
+//            p          pointer to  buffer 1
+//            b          start index of local buffer 1 contents
+//            q          pointer to buffer 2
+//            c          start index of local buffer 2 contents
+//            r          pointer to the character iterator if the UText owns it.
+//                       Null otherwise.
+//
+//------------------------------------------------------------------------------
+#define CIBufSize 16
+
+U_CDECL_BEGIN
+static void U_CALLCONV
+charIterTextClose(UText *ut) {
+    // Most of the work of close is done by the generic UText framework close.
+    // All that needs to be done here is delete the CharacterIterator if the UText
+    //  owns it.  This occurs if the UText was created by cloning.
+    CharacterIterator *ci = (CharacterIterator *)ut->r;
+    delete ci;
+    ut->r = NULL;
+}
+
+static int64_t U_CALLCONV
+charIterTextLength(UText *ut) {
+    return (int32_t)ut->a;
+}
+
+static UBool U_CALLCONV
+charIterTextAccess(UText *ut, int64_t index, UBool  forward) {
+    CharacterIterator *ci   = (CharacterIterator *)ut->context;
+
+    int32_t clippedIndex = (int32_t)index;
+    if (clippedIndex<0) {
+        clippedIndex=0;
+    } else if (clippedIndex>=ut->a) {
+        clippedIndex=(int32_t)ut->a;
+    }
+    int32_t neededIndex = clippedIndex;
+    if (!forward && neededIndex>0) {
+        // reverse iteration, want the position just before what was asked for.
+        neededIndex--;
+    } else if (forward && neededIndex==ut->a && neededIndex>0) {
+        // Forward iteration, don't ask for something past the end of the text.
+        neededIndex--;
+    }
+
+    // Find the native index of the start of the buffer containing what we want.
+    neededIndex -= neededIndex % CIBufSize;
+
+    UChar *buf = NULL;
+    UBool  needChunkSetup = TRUE;
+    int    i;
+    if (ut->chunkNativeStart == neededIndex) {
+        // The buffer we want is already the current chunk.
+        needChunkSetup = FALSE;
+    } else if (ut->b == neededIndex) {
+        // The first buffer (buffer p) has what we need.
+        buf = (UChar *)ut->p;
+    } else if (ut->c == neededIndex) {
+        // The second buffer (buffer q) has what we need.
+        buf = (UChar *)ut->q;
+    } else {
+        // Neither buffer already has what we need.
+        // Load new data from the character iterator.
+        // Use the buf that is not the current buffer.
+        buf = (UChar *)ut->p;
+        if (ut->p == ut->chunkContents) {
+            buf = (UChar *)ut->q;
+        }
+        ci->setIndex(neededIndex);
+        for (i=0; i<CIBufSize; i++) {
+            buf[i] = ci->nextPostInc();
+            if (i+neededIndex > ut->a) {
+                break;
+            }
+        }
+    }
+
+    // We have a buffer with the data we need.
+    // Set it up as the current chunk, if it wasn't already.
+    if (needChunkSetup) {
+        ut->chunkContents = buf;
+        ut->chunkLength   = CIBufSize;
+        ut->chunkNativeStart = neededIndex;
+        ut->chunkNativeLimit = neededIndex + CIBufSize;
+        if (ut->chunkNativeLimit > ut->a) {
+            ut->chunkNativeLimit = ut->a;
+            ut->chunkLength  = (int32_t)(ut->chunkNativeLimit)-(int32_t)(ut->chunkNativeStart);
+        }
+        ut->nativeIndexingLimit = ut->chunkLength;
+        U_ASSERT(ut->chunkOffset>=0 && ut->chunkOffset<=CIBufSize);
+    }
+    ut->chunkOffset = clippedIndex - (int32_t)ut->chunkNativeStart;
+    UBool success = (forward? ut->chunkOffset<ut->chunkLength : ut->chunkOffset>0);
+    return success;
+}
+
+static UText * U_CALLCONV
+charIterTextClone(UText *dest, const UText *src, UBool deep, UErrorCode * status) {
+    if (U_FAILURE(*status)) {
+        return NULL;
+    }
+
+    if (deep) {
+        // There is no CharacterIterator API for cloning the underlying text storage.
+        *status = U_UNSUPPORTED_ERROR;
+        return NULL;
+    } else {
+        CharacterIterator *srcCI =(CharacterIterator *)src->context;
+        srcCI = srcCI->clone();
+        dest = utext_openCharacterIterator(dest, srcCI, status);
+        // cast off const on getNativeIndex.
+        //   For CharacterIterator based UTexts, this is safe, the operation is const.
+        int64_t  ix = utext_getNativeIndex((UText *)src);
+        utext_setNativeIndex(dest, ix);
+        dest->r = srcCI;    // flags that this UText owns the CharacterIterator
+    }
+    return dest;
+}
+
+static int32_t U_CALLCONV
+charIterTextExtract(UText *ut,
+                  int64_t start, int64_t limit,
+                  UChar *dest, int32_t destCapacity,
+                  UErrorCode *status)
+{
+    if(U_FAILURE(*status)) {
+        return 0;
+    }
+    if(destCapacity<0 || (dest==NULL && destCapacity>0) || start>limit) {
+        *status=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    int32_t  length  = (int32_t)ut->a;
+    int32_t  start32 = pinIndex(start, length);
+    int32_t  limit32 = pinIndex(limit, length);
+    int32_t  desti   = 0;
+    int32_t  srci;
+    int32_t  copyLimit;
+
+    CharacterIterator *ci = (CharacterIterator *)ut->context;
+    ci->setIndex32(start32);   // Moves ix to lead of surrogate pair, if needed.
+    srci = ci->getIndex();
+    copyLimit = srci;
+    while (srci<limit32) {
+        UChar32 c = ci->next32PostInc();
+        int32_t  len = U16_LENGTH(c);
+        if (desti+len <= destCapacity) {
+            U16_APPEND_UNSAFE(dest, desti, c);
+            copyLimit = srci+len;
+        } else {
+            desti += len;
+            *status = U_BUFFER_OVERFLOW_ERROR;
+        }
+        srci += len;
+    }
+    
+    charIterTextAccess(ut, copyLimit, TRUE);
+
+    u_terminateUChars(dest, destCapacity, desti, status);
+    return desti;
+}
+
+static const struct UTextFuncs charIterFuncs = 
+{
+    sizeof(UTextFuncs),
+    0, 0, 0,             // Reserved alignment padding
+    charIterTextClone,
+    charIterTextLength,
+    charIterTextAccess,
+    charIterTextExtract,
+    NULL,                // Replace
+    NULL,                // Copy
+    NULL,                // MapOffsetToNative,
+    NULL,                // MapIndexToUTF16,
+    charIterTextClose,
+    NULL,                // spare 1
+    NULL,                // spare 2
+    NULL                 // spare 3
+};
+U_CDECL_END
+
+
+U_CAPI UText * U_EXPORT2
+utext_openCharacterIterator(UText *ut, CharacterIterator *ci, UErrorCode *status) {
+    if (U_FAILURE(*status)) {
+        return NULL;
+    }
+
+    if (ci->startIndex() > 0) {
+        // No support for CharacterIterators that do not start indexing from zero.
+        *status = U_UNSUPPORTED_ERROR;
+        return NULL;
+    }
+
+    // Extra space in UText for 2 buffers of CIBufSize UChars each.
+    int32_t  extraSpace = 2 * CIBufSize * sizeof(UChar);
+    ut = utext_setup(ut, extraSpace, status);
+    if (U_SUCCESS(*status)) {
+        ut->pFuncs                = &charIterFuncs;
+        ut->context              = ci;
+        ut->providerProperties   = 0;
+        ut->a                    = ci->endIndex();        // Length of text
+        ut->p                    = ut->pExtra;            // First buffer
+        ut->b                    = -1;                    // Native index of first buffer contents
+        ut->q                    = (UChar*)ut->pExtra+CIBufSize;  // Second buffer
+        ut->c                    = -1;                    // Native index of second buffer contents
+
+        // Initialize current chunk contents to be empty.
+        //   First access will fault something in.
+        //   Note:  The initial nativeStart and chunkOffset must sum to zero
+        //          so that getNativeIndex() will correctly compute to zero
+        //          if no call to Access() has ever been made.  They can't be both
+        //          zero without Access() thinking that the chunk is valid.
+        ut->chunkContents        = (UChar *)ut->p;
+        ut->chunkNativeStart     = -1;
+        ut->chunkOffset          = 1;
+        ut->chunkNativeLimit     = 0;
+        ut->chunkLength          = 0;
+        ut->nativeIndexingLimit  = ut->chunkOffset;  // enables native indexing
+    }
+    return ut;
+}
+
+
+
diff --git a/source/common/utf_impl.c b/source/common/utf_impl.c
new file mode 100644
index 0000000..8f45546
--- /dev/null
+++ b/source/common/utf_impl.c
@@ -0,0 +1,364 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  utf_impl.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999sep13
+*   created by: Markus W. Scherer
+*
+*   This file provides implementation functions for macros in the utfXX.h
+*   that would otherwise be too long as macros.
+*/
+
+/* set import/export definitions */
+#ifndef U_UTF8_IMPL
+#   define U_UTF8_IMPL
+#endif
+
+#include "unicode/utypes.h"
+
+/*
+ * This table could be replaced on many machines by
+ * a few lines of assembler code using an
+ * "index of first 0-bit from msb" instruction and
+ * one or two more integer instructions.
+ *
+ * For example, on an i386, do something like
+ * - MOV AL, leadByte
+ * - NOT AL         (8-bit, leave b15..b8==0..0, reverse only b7..b0)
+ * - MOV AH, 0
+ * - BSR BX, AX     (16-bit)
+ * - MOV AX, 6      (result)
+ * - JZ finish      (ZF==1 if leadByte==0xff)
+ * - SUB AX, BX (result)
+ * -finish:
+ * (BSR: Bit Scan Reverse, scans for a 1-bit, starting from the MSB)
+ *
+ * In Unicode, all UTF-8 byte sequences with more than 4 bytes are illegal;
+ * lead bytes above 0xf4 are illegal.
+ * We keep them in this table for skipping long ISO 10646-UTF-8 sequences.
+ */
+U_EXPORT const uint8_t 
+utf8_countTrailBytes[256]={
+    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,
+    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,
+    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,
+    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,
+
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    3, 3, 3, 3, 3,
+    3, 3, 3,    /* illegal in Unicode */
+    4, 4, 4, 4, /* illegal in Unicode */
+    5, 5,       /* illegal in Unicode */
+    0, 0        /* illegal bytes 0xfe and 0xff */
+};
+
+static const UChar32
+utf8_minLegal[4]={ 0, 0x80, 0x800, 0x10000 };
+
+static const UChar32
+utf8_errorValue[6]={
+    UTF8_ERROR_VALUE_1, UTF8_ERROR_VALUE_2, UTF_ERROR_VALUE, 0x10ffff,
+    0x3ffffff, 0x7fffffff
+};
+
+/*
+ * Handle the non-inline part of the U8_NEXT() macro and its obsolete sibling
+ * UTF8_NEXT_CHAR_SAFE().
+ *
+ * The "strict" parameter controls the error behavior:
+ * <0  "Safe" behavior of U8_NEXT(): All illegal byte sequences yield a negative
+ *     code point result.
+ *  0  Obsolete "safe" behavior of UTF8_NEXT_CHAR_SAFE(..., FALSE):
+ *     All illegal byte sequences yield a positive code point such that this
+ *     result code point would be encoded with the same number of bytes as
+ *     the illegal sequence.
+ * >0  Obsolete "strict" behavior of UTF8_NEXT_CHAR_SAFE(..., TRUE):
+ *     Same as the obsolete "safe" behavior, but non-characters are also treated
+ *     like illegal sequences.
+ *
+ * The special negative (<0) value -2 is used for lenient treatment of surrogate
+ * code points as legal. Some implementations use this for roundtripping of
+ * Unicode 16-bit strings that are not well-formed UTF-16, that is, they
+ * contain unpaired surrogates.
+ *
+ * Note that a UBool is the same as an int8_t.
+ */
+U_CAPI UChar32 U_EXPORT2
+utf8_nextCharSafeBody(const uint8_t *s, int32_t *pi, int32_t length, UChar32 c, UBool strict) {
+    int32_t i=*pi;
+    uint8_t count=UTF8_COUNT_TRAIL_BYTES(c);
+    if((i)+count<=(length)) {
+        uint8_t trail, illegal=0;
+
+        UTF8_MASK_LEAD_BYTE((c), count);
+        /* count==0 for illegally leading trail bytes and the illegal bytes 0xfe and 0xff */
+        switch(count) {
+        /* each branch falls through to the next one */
+        case 5:
+        case 4:
+            /* count>=4 is always illegal: no more than 3 trail bytes in Unicode's UTF-8 */
+            illegal=1;
+            break;
+        case 3:
+            trail=s[(i)++];
+            (c)=((c)<<6)|(trail&0x3f);
+            if(c<0x110) {
+                illegal|=(trail&0xc0)^0x80;
+            } else {
+                /* code point>0x10ffff, outside Unicode */
+                illegal=1;
+                break;
+            }
+        case 2:
+            trail=s[(i)++];
+            (c)=((c)<<6)|(trail&0x3f);
+            illegal|=(trail&0xc0)^0x80;
+        case 1:
+            trail=s[(i)++];
+            (c)=((c)<<6)|(trail&0x3f);
+            illegal|=(trail&0xc0)^0x80;
+            break;
+        case 0:
+            if(strict>=0) {
+                return UTF8_ERROR_VALUE_1;
+            } else {
+                return U_SENTINEL;
+            }
+        /* no default branch to optimize switch()  - all values are covered */
+        }
+
+        /*
+         * All the error handling should return a value
+         * that needs count bytes so that UTF8_GET_CHAR_SAFE() works right.
+         *
+         * Starting with Unicode 3.0.1, non-shortest forms are illegal.
+         * Starting with Unicode 3.2, surrogate code points must not be
+         * encoded in UTF-8, and there are no irregular sequences any more.
+         *
+         * U8_ macros (new in ICU 2.4) return negative values for error conditions.
+         */
+
+        /* correct sequence - all trail bytes have (b7..b6)==(10)? */
+        /* illegal is also set if count>=4 */
+        if(illegal || (c)<utf8_minLegal[count] || (UTF_IS_SURROGATE(c) && strict!=-2)) {
+            /* error handling */
+            uint8_t errorCount=count;
+            /* don't go beyond this sequence */
+            i=*pi;
+            while(count>0 && UTF8_IS_TRAIL(s[i])) {
+                ++(i);
+                --count;
+            }
+            if(strict>=0) {
+                c=utf8_errorValue[errorCount-count];
+            } else {
+                c=U_SENTINEL;
+            }
+        } else if((strict)>0 && UTF_IS_UNICODE_NONCHAR(c)) {
+            /* strict: forbid non-characters like U+fffe */
+            c=utf8_errorValue[count];
+        }
+    } else /* too few bytes left */ {
+        /* error handling */
+        int32_t i0=i;
+        /* don't just set (i)=(length) in case there is an illegal sequence */
+        while((i)<(length) && UTF8_IS_TRAIL(s[i])) {
+            ++(i);
+        }
+        if(strict>=0) {
+            c=utf8_errorValue[i-i0];
+        } else {
+            c=U_SENTINEL;
+        }
+    }
+    *pi=i;
+    return c;
+}
+
+U_CAPI int32_t U_EXPORT2
+utf8_appendCharSafeBody(uint8_t *s, int32_t i, int32_t length, UChar32 c, UBool *pIsError) {
+    if((uint32_t)(c)<=0x7ff) {
+        if((i)+1<(length)) {
+            (s)[(i)++]=(uint8_t)(((c)>>6)|0xc0);
+            (s)[(i)++]=(uint8_t)(((c)&0x3f)|0x80);
+            return i;
+        }
+    } else if((uint32_t)(c)<=0xffff) {
+        /* Starting with Unicode 3.2, surrogate code points must not be encoded in UTF-8. */
+        if((i)+2<(length) && !U_IS_SURROGATE(c)) {
+            (s)[(i)++]=(uint8_t)(((c)>>12)|0xe0);
+            (s)[(i)++]=(uint8_t)((((c)>>6)&0x3f)|0x80);
+            (s)[(i)++]=(uint8_t)(((c)&0x3f)|0x80);
+            return i;
+        }
+    } else if((uint32_t)(c)<=0x10ffff) {
+        if((i)+3<(length)) {
+            (s)[(i)++]=(uint8_t)(((c)>>18)|0xf0);
+            (s)[(i)++]=(uint8_t)((((c)>>12)&0x3f)|0x80);
+            (s)[(i)++]=(uint8_t)((((c)>>6)&0x3f)|0x80);
+            (s)[(i)++]=(uint8_t)(((c)&0x3f)|0x80);
+            return i;
+        }
+    }
+    /* c>0x10ffff or not enough space, write an error value */
+    if(pIsError!=NULL) {
+        *pIsError=TRUE;
+    } else {
+        length-=i;
+        if(length>0) {
+            int32_t offset;
+            if(length>3) {
+                length=3;
+            }
+            s+=i;
+            offset=0;
+            c=utf8_errorValue[length-1];
+            UTF8_APPEND_CHAR_UNSAFE(s, offset, c);
+            i=i+offset;
+        }
+    }
+    return i;
+}
+
+U_CAPI UChar32 U_EXPORT2
+utf8_prevCharSafeBody(const uint8_t *s, int32_t start, int32_t *pi, UChar32 c, UBool strict) {
+    int32_t i=*pi;
+    uint8_t b, count=1, shift=6;
+
+    /* extract value bits from the last trail byte */
+    c&=0x3f;
+
+    for(;;) {
+        if(i<=start) {
+            /* no lead byte at all */
+            if(strict>=0) {
+                return UTF8_ERROR_VALUE_1;
+            } else {
+                return U_SENTINEL;
+            }
+            /*break;*/
+        }
+
+        /* read another previous byte */
+        b=s[--i];
+        if((uint8_t)(b-0x80)<0x7e) { /* 0x80<=b<0xfe */
+            if(b&0x40) {
+                /* lead byte, this will always end the loop */
+                uint8_t shouldCount=UTF8_COUNT_TRAIL_BYTES(b);
+
+                if(count==shouldCount) {
+                    /* set the new position */
+                    *pi=i;
+                    UTF8_MASK_LEAD_BYTE(b, count);
+                    c|=(UChar32)b<<shift;
+                    if(count>=4 || c>0x10ffff || c<utf8_minLegal[count] || (UTF_IS_SURROGATE(c) && strict!=-2) || (strict>0 && UTF_IS_UNICODE_NONCHAR(c))) {
+                        /* illegal sequence or (strict and non-character) */
+                        if(count>=4) {
+                            count=3;
+                        }
+                        if(strict>=0) {
+                            c=utf8_errorValue[count];
+                        } else {
+                            c=U_SENTINEL;
+                        }
+                    } else {
+                        /* exit with correct c */
+                    }
+                } else {
+                    /* the lead byte does not match the number of trail bytes */
+                    /* only set the position to the lead byte if it would
+                       include the trail byte that we started with */
+                    if(count<shouldCount) {
+                        *pi=i;
+                        if(strict>=0) {
+                            c=utf8_errorValue[count];
+                        } else {
+                            c=U_SENTINEL;
+                        }
+                    } else {
+                        if(strict>=0) {
+                            c=UTF8_ERROR_VALUE_1;
+                        } else {
+                            c=U_SENTINEL;
+                        }
+                    }
+                }
+                break;
+            } else if(count<5) {
+                /* trail byte */
+                c|=(UChar32)(b&0x3f)<<shift;
+                ++count;
+                shift+=6;
+            } else {
+                /* more than 5 trail bytes is illegal */
+                if(strict>=0) {
+                    c=UTF8_ERROR_VALUE_1;
+                } else {
+                    c=U_SENTINEL;
+                }
+                break;
+            }
+        } else {
+            /* single-byte character precedes trailing bytes */
+            if(strict>=0) {
+                c=UTF8_ERROR_VALUE_1;
+            } else {
+                c=U_SENTINEL;
+            }
+            break;
+        }
+    }
+    return c;
+}
+
+U_CAPI int32_t U_EXPORT2
+utf8_back1SafeBody(const uint8_t *s, int32_t start, int32_t i) {
+    /* i had been decremented once before the function call */
+    int32_t I=i, Z;
+    uint8_t b;
+
+    /* read at most the 6 bytes s[Z] to s[i], inclusively */
+    if(I-5>start) {
+        Z=I-5;
+    } else {
+        Z=start;
+    }
+
+    /* return I if the sequence starting there is long enough to include i */
+    do {
+        b=s[I];
+        if((uint8_t)(b-0x80)>=0x7e) { /* not 0x80<=b<0xfe */
+            break;
+        } else if(b>=0xc0) {
+            if(UTF8_COUNT_TRAIL_BYTES(b)>=(i-I)) {
+                return I;
+            } else {
+                break;
+            }
+        }
+    } while(Z<=--I);
+
+    /* return i itself to be consistent with the FWD_1 macro */
+    return i;
+}
diff --git a/source/common/util.cpp b/source/common/util.cpp
new file mode 100644
index 0000000..f084a29
--- /dev/null
+++ b/source/common/util.cpp
@@ -0,0 +1,445 @@
+/*
+**********************************************************************
+*   Copyright (c) 2001-2008, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   Date        Name        Description
+*   11/19/2001  aliu        Creation.
+**********************************************************************
+*/
+
+#include "util.h"
+#include "unicode/unimatch.h"
+#include "unicode/uniset.h"
+
+// Define UChar constants using hex for EBCDIC compatibility
+
+static const UChar BACKSLASH  = 0x005C; /*\*/
+static const UChar UPPER_U    = 0x0055; /*U*/
+static const UChar LOWER_U    = 0x0075; /*u*/
+static const UChar APOSTROPHE = 0x0027; // '\''
+static const UChar SPACE      = 0x0020; // ' '
+
+// "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+static const UChar DIGITS[] = {
+    48,49,50,51,52,53,54,55,56,57,
+    65,66,67,68,69,70,71,72,73,74,
+    75,76,77,78,79,80,81,82,83,84,
+    85,86,87,88,89,90
+};
+
+U_NAMESPACE_BEGIN
+
+UnicodeString& ICU_Utility::appendNumber(UnicodeString& result, int32_t n,
+                                     int32_t radix, int32_t minDigits) {
+    if (radix < 2 || radix > 36) {
+        // Bogus radix
+        return result.append((UChar)63/*?*/);
+    }
+    // Handle negatives
+    if (n < 0) {
+        n = -n;
+        result.append((UChar)45/*-*/);
+    }
+    // First determine the number of digits
+    int32_t nn = n;
+    int32_t r = 1;
+    while (nn >= radix) {
+        nn /= radix;
+        r *= radix;
+        --minDigits;
+    }
+    // Now generate the digits
+    while (--minDigits > 0) {
+        result.append(DIGITS[0]);
+    }
+    while (r > 0) {
+        int32_t digit = n / r;
+        result.append(DIGITS[digit]);
+        n -= digit * r;
+        r /= radix;
+    }
+    return result;
+}
+
+/**
+ * Return true if the character is NOT printable ASCII.
+ */
+UBool ICU_Utility::isUnprintable(UChar32 c) {
+    return !(c >= 0x20 && c <= 0x7E);
+}
+
+/**
+ * Escape unprintable characters using \uxxxx notation for U+0000 to
+ * U+FFFF and \Uxxxxxxxx for U+10000 and above.  If the character is
+ * printable ASCII, then do nothing and return FALSE.  Otherwise,
+ * append the escaped notation and return TRUE.
+ */
+UBool ICU_Utility::escapeUnprintable(UnicodeString& result, UChar32 c) {
+    if (isUnprintable(c)) {
+        result.append(BACKSLASH);
+        if (c & ~0xFFFF) {
+            result.append(UPPER_U);
+            result.append(DIGITS[0xF&(c>>28)]);
+            result.append(DIGITS[0xF&(c>>24)]);
+            result.append(DIGITS[0xF&(c>>20)]);
+            result.append(DIGITS[0xF&(c>>16)]);
+        } else {
+            result.append(LOWER_U);
+        }
+        result.append(DIGITS[0xF&(c>>12)]);
+        result.append(DIGITS[0xF&(c>>8)]);
+        result.append(DIGITS[0xF&(c>>4)]);
+        result.append(DIGITS[0xF&c]);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+/**
+ * Returns the index of a character, ignoring quoted text.
+ * For example, in the string "abc'hide'h", the 'h' in "hide" will not be
+ * found by a search for 'h'.
+ */
+// FOR FUTURE USE.  DISABLE FOR NOW for coverage reasons.
+/*
+int32_t ICU_Utility::quotedIndexOf(const UnicodeString& text,
+                               int32_t start, int32_t limit,
+                               UChar charToFind) {
+    for (int32_t i=start; i<limit; ++i) {
+        UChar c = text.charAt(i);
+        if (c == BACKSLASH) {
+            ++i;
+        } else if (c == APOSTROPHE) {
+            while (++i < limit
+                   && text.charAt(i) != APOSTROPHE) {}
+        } else if (c == charToFind) {
+            return i;
+        }
+    }
+    return -1;
+}
+*/
+
+/**
+ * Skip over a sequence of zero or more white space characters at pos.
+ * @param advance if true, advance pos to the first non-white-space
+ * character at or after pos, or str.length(), if there is none.
+ * Otherwise leave pos unchanged.
+ * @return the index of the first non-white-space character at or
+ * after pos, or str.length(), if there is none.
+ */
+int32_t ICU_Utility::skipWhitespace(const UnicodeString& str, int32_t& pos,
+                                    UBool advance) {
+    int32_t p = pos;
+    while (p < str.length()) {
+        UChar32 c = str.char32At(p);
+        if (!uprv_isRuleWhiteSpace(c)) {
+            break;
+        }
+        p += UTF_CHAR_LENGTH(c);
+    }
+    if (advance) {
+        pos = p;
+    }
+    return p;
+}
+
+/**
+ * Skip over whitespace in a Replaceable.  Whitespace is defined by
+ * uprv_isRuleWhiteSpace().  Skipping may be done in the forward or
+ * reverse direction.  In either case, the leftmost index will be
+ * inclusive, and the rightmost index will be exclusive.  That is,
+ * given a range defined as [start, limit), the call
+ * skipWhitespace(text, start, limit) will advance start past leading
+ * whitespace, whereas the call skipWhitespace(text, limit, start),
+ * will back up limit past trailing whitespace.
+ * @param text the text to be analyzed
+ * @param pos either the start or limit of a range of 'text', to skip
+ * leading or trailing whitespace, respectively
+ * @param stop either the limit or start of a range of 'text', to skip
+ * leading or trailing whitespace, respectively
+ * @return the new start or limit, depending on what was passed in to
+ * 'pos'
+ */
+//?FOR FUTURE USE.  DISABLE FOR NOW for coverage reasons.
+//?int32_t ICU_Utility::skipWhitespace(const Replaceable& text,
+//?                                    int32_t pos, int32_t stop) {
+//?    UChar32 c;
+//?    UBool isForward = (stop >= pos);
+//?
+//?    if (!isForward) {
+//?        --pos; // pos is a limit, so back up by one
+//?    }
+//?    
+//?    while (pos != stop &&
+//?           uprv_isRuleWhiteSpace(c = text.char32At(pos))) {
+//?        if (isForward) {
+//?            pos += UTF_CHAR_LENGTH(c);
+//?        } else {
+//?            pos -= UTF_CHAR_LENGTH(c);
+//?        }
+//?    }
+//?
+//?    if (!isForward) {
+//?        ++pos; // make pos back into a limit
+//?    }
+//?
+//?    return pos;
+//?}
+
+/**
+ * Parse a single non-whitespace character 'ch', optionally
+ * preceded by whitespace.
+ * @param id the string to be parsed
+ * @param pos INPUT-OUTPUT parameter.  On input, pos[0] is the
+ * offset of the first character to be parsed.  On output, pos[0]
+ * is the index after the last parsed character.  If the parse
+ * fails, pos[0] will be unchanged.
+ * @param ch the non-whitespace character to be parsed.
+ * @return true if 'ch' is seen preceded by zero or more
+ * whitespace characters.
+ */
+UBool ICU_Utility::parseChar(const UnicodeString& id, int32_t& pos, UChar ch) {
+    int32_t start = pos;
+    skipWhitespace(id, pos, TRUE);
+    if (pos == id.length() ||
+        id.charAt(pos) != ch) {
+        pos = start;
+        return FALSE;
+    }
+    ++pos;
+    return TRUE;
+}
+
+/**
+ * Parse a pattern string within the given Replaceable and a parsing
+ * pattern.  Characters are matched literally and case-sensitively
+ * except for the following special characters:
+ *
+ * ~  zero or more uprv_isRuleWhiteSpace chars
+ *
+ * If end of pattern is reached with all matches along the way,
+ * pos is advanced to the first unparsed index and returned.
+ * Otherwise -1 is returned.
+ * @param pat pattern that controls parsing
+ * @param text text to be parsed, starting at index
+ * @param index offset to first character to parse
+ * @param limit offset after last character to parse
+ * @return index after last parsed character, or -1 on parse failure.
+ */
+int32_t ICU_Utility::parsePattern(const UnicodeString& pat,
+                                  const Replaceable& text,
+                                  int32_t index,
+                                  int32_t limit) {
+    int32_t ipat = 0;
+
+    // empty pattern matches immediately
+    if (ipat == pat.length()) {
+        return index;
+    }
+
+    UChar32 cpat = pat.char32At(ipat);
+
+    while (index < limit) {
+        UChar32 c = text.char32At(index);
+
+        // parse \s*
+        if (cpat == 126 /*~*/) {
+            if (uprv_isRuleWhiteSpace(c)) {
+                index += UTF_CHAR_LENGTH(c);
+                continue;
+            } else {
+                if (++ipat == pat.length()) {
+                    return index; // success; c unparsed
+                }
+                // fall thru; process c again with next cpat
+            }
+        }
+
+        // parse literal
+        else if (c == cpat) {
+            index += UTF_CHAR_LENGTH(c);
+            ipat += UTF_CHAR_LENGTH(cpat);
+            if (ipat == pat.length()) {
+                return index; // success; c parsed
+            }
+            // fall thru; get next cpat
+        }
+
+        // match failure of literal
+        else {
+            return -1;
+        }
+
+        cpat = pat.char32At(ipat);
+    }
+
+    return -1; // text ended before end of pat
+}
+
+/**
+ * Append a character to a rule that is being built up.  To flush
+ * the quoteBuf to rule, make one final call with isLiteral == TRUE.
+ * If there is no final character, pass in (UChar32)-1 as c.
+ * @param rule the string to append the character to
+ * @param c the character to append, or (UChar32)-1 if none.
+ * @param isLiteral if true, then the given character should not be
+ * quoted or escaped.  Usually this means it is a syntactic element
+ * such as > or $
+ * @param escapeUnprintable if true, then unprintable characters
+ * should be escaped using \uxxxx or \Uxxxxxxxx.  These escapes will
+ * appear outside of quotes.
+ * @param quoteBuf a buffer which is used to build up quoted
+ * substrings.  The caller should initially supply an empty buffer,
+ * and thereafter should not modify the buffer.  The buffer should be
+ * cleared out by, at the end, calling this method with a literal
+ * character.
+ */
+void ICU_Utility::appendToRule(UnicodeString& rule,
+                               UChar32 c,
+                               UBool isLiteral,
+                               UBool escapeUnprintable,
+                               UnicodeString& quoteBuf) {
+    // If we are escaping unprintables, then escape them outside
+    // quotes.  \u and \U are not recognized within quotes.  The same
+    // logic applies to literals, but literals are never escaped.
+    if (isLiteral ||
+        (escapeUnprintable && ICU_Utility::isUnprintable(c))) {
+        if (quoteBuf.length() > 0) {
+            // We prefer backslash APOSTROPHE to double APOSTROPHE
+            // (more readable, less similar to ") so if there are
+            // double APOSTROPHEs at the ends, we pull them outside
+            // of the quote.
+
+            // If the first thing in the quoteBuf is APOSTROPHE
+            // (doubled) then pull it out.
+            while (quoteBuf.length() >= 2 &&
+                   quoteBuf.charAt(0) == APOSTROPHE &&
+                   quoteBuf.charAt(1) == APOSTROPHE) {
+                rule.append(BACKSLASH).append(APOSTROPHE);
+                quoteBuf.remove(0, 2);
+            }
+            // If the last thing in the quoteBuf is APOSTROPHE
+            // (doubled) then remove and count it and add it after.
+            int32_t trailingCount = 0;
+            while (quoteBuf.length() >= 2 &&
+                   quoteBuf.charAt(quoteBuf.length()-2) == APOSTROPHE &&
+                   quoteBuf.charAt(quoteBuf.length()-1) == APOSTROPHE) {
+                quoteBuf.truncate(quoteBuf.length()-2);
+                ++trailingCount;
+            }
+            if (quoteBuf.length() > 0) {
+                rule.append(APOSTROPHE);
+                rule.append(quoteBuf);
+                rule.append(APOSTROPHE);
+                quoteBuf.truncate(0);
+            }
+            while (trailingCount-- > 0) {
+                rule.append(BACKSLASH).append(APOSTROPHE);
+            }
+        }
+        if (c != (UChar32)-1) {
+            /* Since spaces are ignored during parsing, they are
+             * emitted only for readability.  We emit one here
+             * only if there isn't already one at the end of the
+             * rule.
+             */
+            if (c == SPACE) {
+                int32_t len = rule.length();
+                if (len > 0 && rule.charAt(len-1) != c) {
+                    rule.append(c);
+                }
+            } else if (!escapeUnprintable || !ICU_Utility::escapeUnprintable(rule, c)) {
+                rule.append(c);
+            }
+        }
+    }
+
+    // Escape ' and '\' and don't begin a quote just for them
+    else if (quoteBuf.length() == 0 &&
+             (c == APOSTROPHE || c == BACKSLASH)) {
+        rule.append(BACKSLASH);
+        rule.append(c);
+    }
+
+    // Specials (printable ascii that isn't [0-9a-zA-Z]) and
+    // whitespace need quoting.  Also append stuff to quotes if we are
+    // building up a quoted substring already.
+    else if (quoteBuf.length() > 0 ||
+             (c >= 0x0021 && c <= 0x007E &&
+              !((c >= 0x0030/*'0'*/ && c <= 0x0039/*'9'*/) ||
+                (c >= 0x0041/*'A'*/ && c <= 0x005A/*'Z'*/) ||
+                (c >= 0x0061/*'a'*/ && c <= 0x007A/*'z'*/))) ||
+             uprv_isRuleWhiteSpace(c)) {
+        quoteBuf.append(c);
+        // Double ' within a quote
+        if (c == APOSTROPHE) {
+            quoteBuf.append(c);
+        }
+    }
+    
+    // Otherwise just append
+    else {
+        rule.append(c);
+    }
+}
+
+void ICU_Utility::appendToRule(UnicodeString& rule,
+                               const UnicodeString& text,
+                               UBool isLiteral,
+                               UBool escapeUnprintable,
+                               UnicodeString& quoteBuf) {
+    for (int32_t i=0; i<text.length(); ++i) {
+        appendToRule(rule, text[i], isLiteral, escapeUnprintable, quoteBuf);
+    }
+}
+
+/**
+ * Given a matcher reference, which may be null, append its
+ * pattern as a literal to the given rule.
+ */
+void ICU_Utility::appendToRule(UnicodeString& rule,
+                               const UnicodeMatcher* matcher,
+                               UBool escapeUnprintable,
+                               UnicodeString& quoteBuf) {
+    if (matcher != NULL) {
+        UnicodeString pat;
+        appendToRule(rule, matcher->toPattern(pat, escapeUnprintable),
+                     TRUE, escapeUnprintable, quoteBuf);
+    }
+}
+
+U_NAMESPACE_END
+
+U_CAPI UBool U_EXPORT2
+uprv_isRuleWhiteSpace(UChar32 c) {
+    /* "white space" in the sense of ICU rule parsers
+       This is a FIXED LIST that is NOT DEPENDENT ON UNICODE PROPERTIES.
+       See UAX #31 Identifier and Pattern Syntax: http://www.unicode.org/reports/tr31/
+       U+0009..U+000D, U+0020, U+0085, U+200E..U+200F, and U+2028..U+2029
+       Equivalent to test for Pattern_White_Space Unicode property.
+    */
+    return (c >= 0x0009 && c <= 0x2029 &&
+            (c <= 0x000D || c == 0x0020 || c == 0x0085 ||
+             c == 0x200E || c == 0x200F || c >= 0x2028));
+}
+
+U_CAPI U_NAMESPACE_QUALIFIER UnicodeSet* U_EXPORT2
+uprv_openRuleWhiteSpaceSet(UErrorCode* ec) {
+    if(U_FAILURE(*ec)) {
+        return NULL;
+    }
+    // create a set with the Pattern_White_Space characters,
+    // without a pattern for fewer code dependencies
+    U_NAMESPACE_QUALIFIER UnicodeSet *set=new U_NAMESPACE_QUALIFIER UnicodeSet(9, 0xd);
+    // Check for new failure.
+    if (set == NULL) {
+        *ec = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    set->UnicodeSet::add(0x20).add(0x85).add(0x200e, 0x200f).add(0x2028, 0x2029);
+    return set;
+}
+
+//eof
diff --git a/source/common/util.h b/source/common/util.h
new file mode 100644
index 0000000..37fb568
--- /dev/null
+++ b/source/common/util.h
@@ -0,0 +1,261 @@
+/*
+ **********************************************************************
+ *   Copyright (c) 2001-2007, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ **********************************************************************
+ *   Date        Name        Description
+ *   11/19/2001  aliu        Creation.
+ **********************************************************************
+ */
+
+#ifndef ICU_UTIL_H
+#define ICU_UTIL_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+
+//--------------------------------------------------------------------
+// class ICU_Utility
+// i18n utility functions, scoped into the class ICU_Utility.
+//--------------------------------------------------------------------
+
+U_NAMESPACE_BEGIN
+
+class UnicodeMatcher;
+class UnicodeSet;
+
+class U_COMMON_API ICU_Utility /* not : public UObject because all methods are static */ {
+ public:
+
+    /**
+     * Append a number to the given UnicodeString in the given radix.
+     * Standard digits '0'-'9' are used and letters 'A'-'Z' for
+     * radices 11 through 36.
+     * @param result the digits of the number are appended here
+     * @param n the number to be converted to digits; may be negative.
+     * If negative, a '-' is prepended to the digits.
+     * @param radix a radix from 2 to 36 inclusive.
+     * @param minDigits the minimum number of digits, not including
+     * any '-', to produce.  Values less than 2 have no effect.  One
+     * digit is always emitted regardless of this parameter.
+     * @return a reference to result
+     */
+    static UnicodeString& appendNumber(UnicodeString& result, int32_t n,
+                                       int32_t radix = 10,
+                                       int32_t minDigits = 1);
+
+    /**
+     * Return true if the character is NOT printable ASCII.
+     *
+     * This method should really be in UnicodeString (or similar).  For
+     * now, we implement it here and share it with friend classes.
+     */
+    static UBool isUnprintable(UChar32 c);
+
+    /**
+     * Escape unprintable characters using \uxxxx notation for U+0000 to
+     * U+FFFF and \Uxxxxxxxx for U+10000 and above.  If the character is
+     * printable ASCII, then do nothing and return FALSE.  Otherwise,
+     * append the escaped notation and return TRUE.
+     */
+    static UBool escapeUnprintable(UnicodeString& result, UChar32 c);
+
+    /**
+     * Returns the index of a character, ignoring quoted text.
+     * For example, in the string "abc'hide'h", the 'h' in "hide" will not be
+     * found by a search for 'h'.
+     * @param text text to be searched
+     * @param start the beginning index, inclusive; <code>0 <= start
+     * <= limit</code>.
+     * @param limit the ending index, exclusive; <code>start <= limit
+     * <= text.length()</code>.
+     * @param c character to search for
+     * @return Offset of the first instance of c, or -1 if not found.
+     */
+//?FOR FUTURE USE.  DISABLE FOR NOW for coverage reasons.
+//    static int32_t quotedIndexOf(const UnicodeString& text,
+//                                 int32_t start, int32_t limit,
+//                                 UChar c);
+
+    /**
+     * Skip over a sequence of zero or more white space characters at pos.
+     * @param advance if true, advance pos to the first non-white-space
+     * character at or after pos, or str.length(), if there is none.
+     * Otherwise leave pos unchanged.
+     * @return the index of the first non-white-space character at or
+     * after pos, or str.length(), if there is none.
+     */
+    static int32_t skipWhitespace(const UnicodeString& str, int32_t& pos,
+                                  UBool advance = FALSE);
+
+    /**
+     * Skip over whitespace in a Replaceable.  Whitespace is defined by
+     * uprv_isRuleWhiteSpace().  Skipping may be done in the forward or
+     * reverse direction.  In either case, the leftmost index will be
+     * inclusive, and the rightmost index will be exclusive.  That is,
+     * given a range defined as [start, limit), the call
+     * skipWhitespace(text, start, limit) will advance start past leading
+     * whitespace, whereas the call skipWhitespace(text, limit, start),
+     * will back up limit past trailing whitespace.
+     * @param text the text to be analyzed
+     * @param pos either the start or limit of a range of 'text', to skip
+     * leading or trailing whitespace, respectively
+     * @param stop either the limit or start of a range of 'text', to skip
+     * leading or trailing whitespace, respectively
+     * @return the new start or limit, depending on what was passed in to
+     * 'pos'
+     */
+//?FOR FUTURE USE.  DISABLE FOR NOW for coverage reasons.
+//?    static int32_t skipWhitespace(const Replaceable& text,
+//?                                  int32_t pos, int32_t stop);
+
+    /**
+     * Parse a single non-whitespace character 'ch', optionally
+     * preceded by whitespace.
+     * @param id the string to be parsed
+     * @param pos INPUT-OUTPUT parameter.  On input, pos[0] is the
+     * offset of the first character to be parsed.  On output, pos[0]
+     * is the index after the last parsed character.  If the parse
+     * fails, pos[0] will be unchanged.
+     * @param ch the non-whitespace character to be parsed.
+     * @return true if 'ch' is seen preceded by zero or more
+     * whitespace characters.
+     */
+    static UBool parseChar(const UnicodeString& id, int32_t& pos, UChar ch);
+
+    /**
+     * Parse a pattern string starting at offset pos.  Keywords are
+     * matched case-insensitively.  Spaces may be skipped and may be
+     * optional or required.  Integer values may be parsed, and if
+     * they are, they will be returned in the given array.  If
+     * successful, the offset of the next non-space character is
+     * returned.  On failure, -1 is returned.
+     * @param pattern must only contain lowercase characters, which
+     * will match their uppercase equivalents as well.  A space
+     * character matches one or more required spaces.  A '~' character
+     * matches zero or more optional spaces.  A '#' character matches
+     * an integer and stores it in parsedInts, which the caller must
+     * ensure has enough capacity.
+     * @param parsedInts array to receive parsed integers.  Caller
+     * must ensure that parsedInts.length is >= the number of '#'
+     * signs in 'pattern'.
+     * @return the position after the last character parsed, or -1 if
+     * the parse failed
+     */
+    static int32_t parsePattern(const UnicodeString& rule, int32_t pos, int32_t limit,
+                                const UnicodeString& pattern, int32_t* parsedInts);
+        
+    /**
+     * Parse a pattern string within the given Replaceable and a parsing
+     * pattern.  Characters are matched literally and case-sensitively
+     * except for the following special characters:
+     *
+     * ~  zero or more uprv_isRuleWhiteSpace chars
+     *
+     * If end of pattern is reached with all matches along the way,
+     * pos is advanced to the first unparsed index and returned.
+     * Otherwise -1 is returned.
+     * @param pat pattern that controls parsing
+     * @param text text to be parsed, starting at index
+     * @param index offset to first character to parse
+     * @param limit offset after last character to parse
+     * @return index after last parsed character, or -1 on parse failure.
+     */
+    static int32_t parsePattern(const UnicodeString& pat,
+                                const Replaceable& text,
+                                int32_t index,
+                                int32_t limit);
+
+    /**
+     * Parse an integer at pos, either of the form \d+ or of the form
+     * 0x[0-9A-Fa-f]+ or 0[0-7]+, that is, in standard decimal, hex,
+     * or octal format.
+     * @param pos INPUT-OUTPUT parameter.  On input, the first
+     * character to parse.  On output, the character after the last
+     * parsed character.
+     */
+    static int32_t parseInteger(const UnicodeString& rule, int32_t& pos, int32_t limit);
+
+    /**
+     * Parse a Unicode identifier from the given string at the given
+     * position.  Return the identifier, or an empty string if there
+     * is no identifier.
+     * @param str the string to parse
+     * @param pos INPUT-OUPUT parameter.  On INPUT, pos is the
+     * first character to examine.  It must be less than str.length(),
+     * and it must not point to a whitespace character.  That is, must
+     * have pos < str.length() and
+     * !UCharacter::isWhitespace(str.char32At(pos)).  On
+     * OUTPUT, the position after the last parsed character.
+     * @return the Unicode identifier, or an empty string if there is
+     * no valid identifier at pos.
+     */
+    static UnicodeString parseUnicodeIdentifier(const UnicodeString& str, int32_t& pos);
+
+    /**
+     * Parse an unsigned 31-bit integer at the given offset.  Use
+     * UCharacter.digit() to parse individual characters into digits.
+     * @param text the text to be parsed
+     * @param pos INPUT-OUTPUT parameter.  On entry, pos is the
+     * offset within text at which to start parsing; it should point
+     * to a valid digit.  On exit, pos is the offset after the last
+     * parsed character.  If the parse failed, it will be unchanged on
+     * exit.  Must be >= 0 on entry.
+     * @param radix the radix in which to parse; must be >= 2 and <=
+     * 36.
+     * @return a non-negative parsed number, or -1 upon parse failure.
+     * Parse fails if there are no digits, that is, if pos does not
+     * point to a valid digit on entry, or if the number to be parsed
+     * does not fit into a 31-bit unsigned integer.
+     */
+    static int32_t parseNumber(const UnicodeString& text,
+                               int32_t& pos, int8_t radix);
+
+    static void appendToRule(UnicodeString& rule,
+                             UChar32 c,
+                             UBool isLiteral,
+                             UBool escapeUnprintable,
+                             UnicodeString& quoteBuf);
+    
+    static void appendToRule(UnicodeString& rule,
+                             const UnicodeString& text,
+                             UBool isLiteral,
+                             UBool escapeUnprintable,
+                             UnicodeString& quoteBuf);
+
+    static void appendToRule(UnicodeString& rule,
+                             const UnicodeMatcher* matcher,
+                             UBool escapeUnprintable,
+                             UnicodeString& quoteBuf);
+
+private:
+    // do not instantiate
+    ICU_Utility();
+};
+
+U_NAMESPACE_END
+
+/**
+ * Get the set of "white space" characters in the sense of ICU rule
+ * parsers.  Caller must close/delete result.
+ * Equivalent to the set of characters with the Pattern_White_Space Unicode property.
+ * Stable set of characters, won't change.
+ * See UAX #31 Identifier and Pattern Syntax: http://www.unicode.org/reports/tr31/
+ * @internal
+ */
+U_CAPI U_NAMESPACE_QUALIFIER UnicodeSet* U_EXPORT2
+uprv_openRuleWhiteSpaceSet(UErrorCode* ec);
+
+/**
+ * Is this character a "white space" in the sense of ICU rule parsers?
+ * Equivalent to test for Pattern_White_Space Unicode property.
+ * Stable set of characters, won't change.
+ * See UAX #31 Identifier and Pattern Syntax: http://www.unicode.org/reports/tr31/
+ * @internal
+ */
+U_CAPI UBool U_EXPORT2
+uprv_isRuleWhiteSpace(UChar32 c);
+
+#endif
+//eof
diff --git a/source/common/util_props.cpp b/source/common/util_props.cpp
new file mode 100644
index 0000000..f91666b
--- /dev/null
+++ b/source/common/util_props.cpp
@@ -0,0 +1,214 @@
+/*
+**********************************************************************
+*   Copyright (c) 2001-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   Date        Name        Description
+*   11/19/2001  aliu        Creation.
+**********************************************************************
+*/
+
+#include "util.h"
+#include "unicode/uchar.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Parse an integer at pos, either of the form \d+ or of the form
+ * 0x[0-9A-Fa-f]+ or 0[0-7]+, that is, in standard decimal, hex,
+ * or octal format.
+ * @param pos INPUT-OUTPUT parameter.  On input, the first
+ * character to parse.  On output, the character after the last
+ * parsed character.
+ */
+int32_t ICU_Utility::parseInteger(const UnicodeString& rule, int32_t& pos, int32_t limit) {
+    int32_t count = 0;
+    int32_t value = 0;
+    int32_t p = pos;
+    int8_t radix = 10;
+
+    if (p < limit && rule.charAt(p) == 48 /*0*/) {
+        if (p+1 < limit && (rule.charAt(p+1) == 0x78 /*x*/ || rule.charAt(p+1) == 0x58 /*X*/)) {
+            p += 2;
+            radix = 16;
+        }
+        else {
+            p++;
+            count = 1;
+            radix = 8;
+        }
+    }
+
+    while (p < limit) {
+        int32_t d = u_digit(rule.charAt(p++), radix);
+        if (d < 0) {
+            --p;
+            break;
+        }
+        ++count;
+        int32_t v = (value * radix) + d;
+        if (v <= value) {
+            // If there are too many input digits, at some point
+            // the value will go negative, e.g., if we have seen
+            // "0x8000000" already and there is another '0', when
+            // we parse the next 0 the value will go negative.
+            return 0;
+        }
+        value = v;
+    }
+    if (count > 0) {
+        pos = p;
+    }
+    return value;
+}
+
+/**
+ * Parse a pattern string starting at offset pos.  Keywords are
+ * matched case-insensitively.  Spaces may be skipped and may be
+ * optional or required.  Integer values may be parsed, and if
+ * they are, they will be returned in the given array.  If
+ * successful, the offset of the next non-space character is
+ * returned.  On failure, -1 is returned.
+ * @param pattern must only contain lowercase characters, which
+ * will match their uppercase equivalents as well.  A space
+ * character matches one or more required spaces.  A '~' character
+ * matches zero or more optional spaces.  A '#' character matches
+ * an integer and stores it in parsedInts, which the caller must
+ * ensure has enough capacity.
+ * @param parsedInts array to receive parsed integers.  Caller
+ * must ensure that parsedInts.length is >= the number of '#'
+ * signs in 'pattern'.
+ * @return the position after the last character parsed, or -1 if
+ * the parse failed
+ */
+int32_t ICU_Utility::parsePattern(const UnicodeString& rule, int32_t pos, int32_t limit,
+                              const UnicodeString& pattern, int32_t* parsedInts) {
+    // TODO Update this to handle surrogates
+    int32_t p;
+    int32_t intCount = 0; // number of integers parsed
+    for (int32_t i=0; i<pattern.length(); ++i) {
+        UChar cpat = pattern.charAt(i);
+        UChar c;
+        switch (cpat) {
+        case 32 /*' '*/:
+            if (pos >= limit) {
+                return -1;
+            }
+            c = rule.charAt(pos++);
+            if (!uprv_isRuleWhiteSpace(c)) {
+                return -1;
+            }
+            // FALL THROUGH to skipWhitespace
+        case 126 /*'~'*/:
+            pos = skipWhitespace(rule, pos);
+            break;
+        case 35 /*'#'*/:
+            p = pos;
+            parsedInts[intCount++] = parseInteger(rule, p, limit);
+            if (p == pos) {
+                // Syntax error; failed to parse integer
+                return -1;
+            }
+            pos = p;
+            break;
+        default:
+            if (pos >= limit) {
+                return -1;
+            }
+            c = (UChar) u_tolower(rule.charAt(pos++));
+            if (c != cpat) {
+                return -1;
+            }
+            break;
+        }
+    }
+    return pos;
+}
+
+/**
+ * Parse a Unicode identifier from the given string at the given
+ * position.  Return the identifier, or an empty string if there
+ * is no identifier.
+ * @param str the string to parse
+ * @param pos INPUT-OUPUT parameter.  On INPUT, pos is the
+ * first character to examine.  It must be less than str.length(),
+ * and it must not point to a whitespace character.  That is, must
+ * have pos < str.length() and
+ * !uprv_isRuleWhiteSpace(str.char32At(pos)).  On
+ * OUTPUT, the position after the last parsed character.
+ * @return the Unicode identifier, or an empty string if there is
+ * no valid identifier at pos.
+ */
+UnicodeString ICU_Utility::parseUnicodeIdentifier(const UnicodeString& str, int32_t& pos) {
+    // assert(pos < str.length());
+    // assert(!uprv_isRuleWhiteSpace(str.char32At(pos)));
+    UnicodeString buf;
+    int p = pos;
+    while (p < str.length()) {
+        UChar32 ch = str.char32At(p);
+        if (buf.length() == 0) {
+            if (u_isIDStart(ch)) {
+                buf.append(ch);
+            } else {
+                buf.truncate(0);
+                return buf;
+            }
+        } else {
+            if (u_isIDPart(ch)) {
+                buf.append(ch);
+            } else {
+                break;
+            }
+        }
+        p += UTF_CHAR_LENGTH(ch);
+    }
+    pos = p;
+    return buf;
+}
+
+/**
+ * Parse an unsigned 31-bit integer at the given offset.  Use
+ * UCharacter.digit() to parse individual characters into digits.
+ * @param text the text to be parsed
+ * @param pos INPUT-OUTPUT parameter.  On entry, pos[0] is the
+ * offset within text at which to start parsing; it should point
+ * to a valid digit.  On exit, pos[0] is the offset after the last
+ * parsed character.  If the parse failed, it will be unchanged on
+ * exit.  Must be >= 0 on entry.
+ * @param radix the radix in which to parse; must be >= 2 and <=
+ * 36.
+ * @return a non-negative parsed number, or -1 upon parse failure.
+ * Parse fails if there are no digits, that is, if pos[0] does not
+ * point to a valid digit on entry, or if the number to be parsed
+ * does not fit into a 31-bit unsigned integer.
+ */
+int32_t ICU_Utility::parseNumber(const UnicodeString& text,
+                                 int32_t& pos, int8_t radix) {
+    // assert(pos[0] >= 0);
+    // assert(radix >= 2);
+    // assert(radix <= 36);
+    int32_t n = 0;
+    int32_t p = pos;
+    while (p < text.length()) {
+        UChar32 ch = text.char32At(p);
+        int32_t d = u_digit(ch, radix);
+        if (d < 0) {
+            break;
+        }
+        n = radix*n + d;
+        // ASSUME that when a 32-bit integer overflows it becomes
+        // negative.  E.g., 214748364 * 10 + 8 => negative value.
+        if (n < 0) {
+            return -1;
+        }
+        ++p;
+    }
+    if (p == pos) {
+        return -1;
+    }
+    pos = p;
+    return n;
+}
+
+U_NAMESPACE_END
+
diff --git a/source/common/utrace.c b/source/common/utrace.c
new file mode 100644
index 0000000..803dfcf
--- /dev/null
+++ b/source/common/utrace.c
@@ -0,0 +1,486 @@
+/*
+*******************************************************************************
+*   Copyright (C) 2003-2008, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*******************************************************************************
+*   file name:  utrace.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*/
+
+#define   UTRACE_IMPL
+#include "unicode/utrace.h"
+#include "utracimp.h"
+#include "cstring.h"
+#include "uassert.h"
+#include "ucln_cmn.h"
+
+
+static UTraceEntry     *pTraceEntryFunc = NULL;
+static UTraceExit      *pTraceExitFunc  = NULL;
+static UTraceData      *pTraceDataFunc  = NULL;
+static const void      *gTraceContext   = NULL;
+
+U_EXPORT int32_t
+utrace_level = UTRACE_ERROR;
+
+U_CAPI void U_EXPORT2
+utrace_entry(int32_t fnNumber) {
+    if (pTraceEntryFunc != NULL) {
+        (*pTraceEntryFunc)(gTraceContext, fnNumber);
+    }
+}
+
+
+static const char gExitFmt[]             = "Returns.";
+static const char gExitFmtValue[]        = "Returns %d.";
+static const char gExitFmtStatus[]       = "Returns.  Status = %d.";
+static const char gExitFmtValueStatus[]  = "Returns %d.  Status = %d.";
+static const char gExitFmtPtrStatus[]    = "Returns %d.  Status = %p.";
+
+U_CAPI void U_EXPORT2
+utrace_exit(int32_t fnNumber, int32_t returnType, ...) {
+    if (pTraceExitFunc != NULL) {
+        va_list     args;
+        const char *fmt;
+
+        switch (returnType) {
+        case 0:
+            fmt = gExitFmt;
+            break;
+        case UTRACE_EXITV_I32:
+            fmt = gExitFmtValue;
+            break;
+        case UTRACE_EXITV_STATUS:
+            fmt = gExitFmtStatus;
+            break;
+        case UTRACE_EXITV_I32 | UTRACE_EXITV_STATUS:
+            fmt = gExitFmtValueStatus;
+            break;
+        case UTRACE_EXITV_PTR | UTRACE_EXITV_STATUS:
+            fmt = gExitFmtPtrStatus;
+            break;
+        default:
+            U_ASSERT(FALSE);
+            fmt = gExitFmt;
+        }
+
+        va_start(args, returnType);
+        (*pTraceExitFunc)(gTraceContext, fnNumber, fmt, args);
+        va_end(args);
+    }
+}
+ 
+
+ 
+U_CAPI void U_EXPORT2 
+utrace_data(int32_t fnNumber, int32_t level, const char *fmt, ...) {
+    if (pTraceDataFunc != NULL) {
+           va_list args;
+           va_start(args, fmt ); 
+           (*pTraceDataFunc)(gTraceContext, fnNumber, level, fmt, args);
+           va_end(args);
+    }
+}
+
+
+static void outputChar(char c, char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) {
+    int32_t i;
+    /* Check whether a start of line indenting is needed.  Three cases:
+     *   1.  At the start of the first line  (output index == 0).
+     *   2.  At the start of subsequent lines  (preceeding char in buffer == '\n')
+     *   3.  When preflighting buffer len (buffer capacity is exceeded), when
+     *       a \n is output.  Ideally we wouldn't do the indent until the following char
+     *       is received, but that won't work because there's no place to remember that
+     *       the preceding char was \n.  Meaning that we may overstimate the
+     *       buffer size needed.  No harm done.
+     */
+    if (*outIx==0 ||   /* case 1. */
+        (c!='\n' && c!=0 && *outIx < capacity && outBuf[(*outIx)-1]=='\n') ||  /* case 2. */
+        (c=='\n' && *outIx>=capacity))    /* case 3 */
+    {
+        /* At the start of a line.  Indent. */
+        for(i=0; i<indent; i++) {
+            if (*outIx < capacity) {
+                outBuf[*outIx] = ' ';
+            }
+            (*outIx)++;
+        }
+    }
+
+    if (*outIx < capacity) {
+        outBuf[*outIx] = c;
+    }
+    if (c != 0) {
+        /* Nulls only appear as end-of-string terminators.  Move them to the output
+         *  buffer, but do not update the length of the buffer, so that any
+         *  following output will overwrite the null. */
+        (*outIx)++;
+    }
+}
+
+static void outputHexBytes(int64_t val, int32_t charsToOutput,
+                           char *outBuf, int32_t *outIx, int32_t capacity) {
+    static const char gHexChars[] = "0123456789abcdef";
+    int32_t shiftCount;
+    for  (shiftCount=(charsToOutput-1)*4; shiftCount >= 0; shiftCount-=4) {
+        char c = gHexChars[(val >> shiftCount) & 0xf];
+        outputChar(c, outBuf, outIx, capacity, 0);
+    }
+}
+
+/* Output a pointer value in hex.  Work with any size of pointer   */
+static void outputPtrBytes(void *val, char *outBuf, int32_t *outIx, int32_t capacity) {
+    int32_t  i;
+    int32_t  incVal = 1;              /* +1 for big endian, -1 for little endian          */
+    char     *p     = (char *)&val;   /* point to current byte to output in the ptr val  */
+
+#if !U_IS_BIG_ENDIAN
+    /* Little Endian.  Move p to most significant end of the value      */
+    incVal = -1;
+    p += sizeof(void *) - 1;
+#endif
+
+    /* Loop through the bytes of the ptr as it sits in memory, from 
+     * most significant to least significant end                    */
+    for (i=0; i<sizeof(void *); i++) {
+        outputHexBytes(*p, 2, outBuf, outIx, capacity);
+        p += incVal;
+    }
+}
+
+static void outputString(const char *s, char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) {
+    int32_t i = 0;
+    char    c;
+    if (s==NULL) {
+        s = "*NULL*";
+    }
+    do {
+        c = s[i++];
+        outputChar(c, outBuf, outIx, capacity, indent);
+    } while (c != 0);
+}
+        
+
+
+static void outputUString(const UChar *s, int32_t len, 
+                          char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) {
+    int32_t i = 0;
+    UChar   c;
+    if (s==NULL) {
+        outputString(NULL, outBuf, outIx, capacity, indent);
+        return;
+    }
+
+    for (i=0; i<len || len==-1; i++) {
+        c = s[i];
+        outputHexBytes(c, 4, outBuf, outIx, capacity);
+        outputChar(' ', outBuf, outIx, capacity, indent);
+        if (len == -1 && c==0) {
+            break;
+        }
+    }
+}
+        
+U_CAPI int32_t U_EXPORT2
+utrace_vformat(char *outBuf, int32_t capacity, int32_t indent, const char *fmt, va_list args) {
+    int32_t   outIx  = 0;
+    int32_t   fmtIx  = 0;
+    char      fmtC;
+    char      c;
+    int32_t   intArg;
+    int64_t   longArg = 0;
+    char      *ptrArg;
+
+    /*   Loop runs once for each character in the format string.
+     */
+    for (;;) {
+        fmtC = fmt[fmtIx++];
+        if (fmtC != '%') {
+            /* Literal character, not part of a %sequence.  Just copy it to the output. */
+            outputChar(fmtC, outBuf, &outIx, capacity, indent);
+            if (fmtC == 0) {
+                /* We hit the null that terminates the format string.
+                 * This is the normal (and only) exit from the loop that
+                 * interprets the format
+                 */
+                break;
+            }
+            continue;
+        }
+
+        /* We encountered a '%'.  Pick up the following format char */
+        fmtC = fmt[fmtIx++];
+
+        switch (fmtC) {
+        case 'c':
+            /* single 8 bit char   */
+            c = (char)va_arg(args, int32_t);
+            outputChar(c, outBuf, &outIx, capacity, indent);
+            break;
+
+        case 's':
+            /* char * string, null terminated.  */
+            ptrArg = va_arg(args, char *);
+            outputString((const char *)ptrArg, outBuf, &outIx, capacity, indent);
+            break;
+
+        case 'S':
+            /* UChar * string, with length, len==-1 for null terminated. */
+            ptrArg = va_arg(args, void *);             /* Ptr    */
+            intArg =(int32_t)va_arg(args, int32_t);    /* Length */
+            outputUString((const UChar *)ptrArg, intArg, outBuf, &outIx, capacity, indent);
+            break;
+
+        case 'b':
+            /*  8 bit int  */
+            intArg = va_arg(args, int);
+            outputHexBytes(intArg, 2, outBuf, &outIx, capacity);
+            break;
+
+        case 'h':
+            /*  16 bit int  */
+            intArg = va_arg(args, int);
+            outputHexBytes(intArg, 4, outBuf, &outIx, capacity);
+            break;
+
+        case 'd':
+            /*  32 bit int  */
+            intArg = va_arg(args, int);
+            outputHexBytes(intArg, 8, outBuf, &outIx, capacity);
+            break;
+
+        case 'l':
+            /*  64 bit long  */
+            longArg = va_arg(args, int64_t);
+            outputHexBytes(longArg, 16, outBuf, &outIx, capacity);
+            break;
+            
+        case 'p':
+            /*  Pointers.   */
+            ptrArg = va_arg(args, void *);
+            outputPtrBytes(ptrArg, outBuf, &outIx, capacity);
+            break;
+
+        case 0:
+            /* Single '%' at end of fmt string.  Output as literal '%'.   
+             * Back up index into format string so that the terminating null will be
+             * re-fetched in the outer loop, causing it to terminate.
+             */
+            outputChar('%', outBuf, &outIx, capacity, indent);
+            fmtIx--;
+            break;
+
+        case 'v':
+            {
+                /* Vector of values, e.g. %vh */
+                char     vectorType;
+                int32_t  vectorLen;
+                const char   *i8Ptr;
+                int16_t  *i16Ptr;
+                int32_t  *i32Ptr;
+                int64_t  *i64Ptr;
+                void     **ptrPtr;
+                int32_t   charsToOutput = 0;
+                int32_t   i;
+                
+                vectorType = fmt[fmtIx];    /* b, h, d, l, p, etc. */
+                if (vectorType != 0) {
+                    fmtIx++;
+                }
+                i8Ptr = (const char *)va_arg(args, void*);
+                i16Ptr = (int16_t *)i8Ptr;
+                i32Ptr = (int32_t *)i8Ptr;
+                i64Ptr = (int64_t *)i8Ptr;
+                ptrPtr = (void **)i8Ptr;
+                vectorLen =(int32_t)va_arg(args, int32_t);
+                if (ptrPtr == NULL) {
+                    outputString("*NULL* ", outBuf, &outIx, capacity, indent);
+                } else {
+                    for (i=0; i<vectorLen || vectorLen==-1; i++) { 
+                        switch (vectorType) {
+                        case 'b':
+                            charsToOutput = 2;
+                            longArg = *i8Ptr++;
+                            break;
+                        case 'h':
+                            charsToOutput = 4;
+                            longArg = *i16Ptr++;
+                            break;
+                        case 'd':
+                            charsToOutput = 8;
+                            longArg = *i32Ptr++;
+                            break;
+                        case 'l':
+                            charsToOutput = 16;
+                            longArg = *i64Ptr++;
+                            break;
+                        case 'p':
+                            charsToOutput = 0;
+                            outputPtrBytes(*ptrPtr, outBuf, &outIx, capacity);
+                            longArg = *ptrPtr==NULL? 0: 1;    /* test for null terminated array. */
+                            ptrPtr++;
+                            break;
+                        case 'c':
+                            charsToOutput = 0;
+                            outputChar(*i8Ptr, outBuf, &outIx, capacity, indent);
+                            longArg = *i8Ptr;    /* for test for null terminated array. */
+                            i8Ptr++;
+                            break;
+                        case 's':
+                            charsToOutput = 0;
+                            outputString(*ptrPtr, outBuf, &outIx, capacity, indent);
+                            outputChar('\n', outBuf, &outIx, capacity, indent);
+                            longArg = *ptrPtr==NULL? 0: 1;   /* for test for null term. array. */
+                            ptrPtr++;
+                            break;
+
+                        case 'S':
+                            charsToOutput = 0;
+                            outputUString((const UChar *)*ptrPtr, -1, outBuf, &outIx, capacity, indent);
+                            outputChar('\n', outBuf, &outIx, capacity, indent);
+                            longArg = *ptrPtr==NULL? 0: 1;   /* for test for null term. array. */
+                            ptrPtr++;
+                            break;
+
+                            
+                        }
+                        if (charsToOutput > 0) {
+                            outputHexBytes(longArg, charsToOutput, outBuf, &outIx, capacity);
+                            outputChar(' ', outBuf, &outIx, capacity, indent);
+                        }
+                        if (vectorLen == -1 && longArg == 0) {
+                            break;
+                        }
+                    }
+                }
+                outputChar('[', outBuf, &outIx, capacity, indent);
+                outputHexBytes(vectorLen, 8, outBuf, &outIx, capacity);
+                outputChar(']', outBuf, &outIx, capacity, indent);
+            }
+            break;
+
+
+        default:
+            /* %. in format string, where . is some character not in the set
+             *    of recognized format chars.  Just output it as if % wasn't there.
+             *    (Covers "%%" outputing a single '%')
+             */
+             outputChar(fmtC, outBuf, &outIx, capacity, indent);
+        }
+    }
+    outputChar(0, outBuf, &outIx, capacity, indent);  /* Make sure that output is null terminated  */
+    return outIx + 1;     /* outIx + 1 because outIx does not increment when outputing final null. */
+}
+
+
+
+
+U_CAPI int32_t U_EXPORT2
+utrace_format(char *outBuf, int32_t capacity,
+                int32_t indent, const char *fmt,  ...) {
+    int32_t retVal;
+    va_list args;
+    va_start(args, fmt ); 
+    retVal = utrace_vformat(outBuf, capacity, indent, fmt, args);
+    va_end(args);
+    return retVal;
+}
+
+
+U_CAPI void U_EXPORT2
+utrace_setFunctions(const void *context,
+                    UTraceEntry *e, UTraceExit *x, UTraceData *d) {
+    pTraceEntryFunc = e;
+    pTraceExitFunc  = x;
+    pTraceDataFunc  = d;
+    gTraceContext   = context;
+}
+
+
+U_CAPI void U_EXPORT2
+utrace_getFunctions(const void **context,
+                    UTraceEntry **e, UTraceExit **x, UTraceData **d) {
+    *e = pTraceEntryFunc;
+    *x = pTraceExitFunc;
+    *d = pTraceDataFunc;
+    *context = gTraceContext;
+}
+
+U_CAPI void U_EXPORT2
+utrace_setLevel(int32_t level) {
+    if (level < UTRACE_OFF) {
+        level = UTRACE_OFF;
+    }
+    if (level > UTRACE_VERBOSE) {
+        level = UTRACE_VERBOSE;
+    }
+    utrace_level = level;
+}
+
+U_CAPI int32_t U_EXPORT2
+utrace_getLevel() {
+    return utrace_level;
+}
+
+
+U_CFUNC UBool 
+utrace_cleanup() {
+    pTraceEntryFunc = NULL;
+    pTraceExitFunc  = NULL;
+    pTraceDataFunc  = NULL;
+    utrace_level    = UTRACE_OFF;
+    gTraceContext   = NULL;
+    return TRUE;
+}
+
+
+static const char * const
+trFnName[] = {
+    "u_init",
+    "u_cleanup",
+    NULL
+};
+
+
+static const char * const
+trConvNames[] = {
+    "ucnv_open",
+    "ucnv_openPackage",
+    "ucnv_openAlgorithmic",
+    "ucnv_clone",
+    "ucnv_close",
+    "ucnv_flushCache",
+    "ucnv_load",
+    "ucnv_unload",
+    NULL
+};
+
+    
+static const char * const
+trCollNames[] = {
+    "ucol_open",
+    "ucol_close",
+    "ucol_strcoll",
+    "ucol_getSortKey",
+    "ucol_getLocale",
+    "ucol_nextSortKeyPart",
+    "ucol_strcollIter",
+    NULL
+};
+
+                
+U_CAPI const char * U_EXPORT2
+utrace_functionName(int32_t fnNumber) {
+    if(UTRACE_FUNCTION_START <= fnNumber && fnNumber < UTRACE_FUNCTION_LIMIT) {
+        return trFnName[fnNumber];
+    } else if(UTRACE_CONVERSION_START <= fnNumber && fnNumber < UTRACE_CONVERSION_LIMIT) {
+        return trConvNames[fnNumber - UTRACE_CONVERSION_START];
+    } else if(UTRACE_COLLATION_START <= fnNumber && fnNumber < UTRACE_COLLATION_LIMIT){
+        return trCollNames[fnNumber - UTRACE_COLLATION_START];
+    } else {
+        return "[BOGUS Trace Function Number]";
+    }
+}
+
diff --git a/source/common/utracimp.h b/source/common/utracimp.h
new file mode 100644
index 0000000..317fbe3
--- /dev/null
+++ b/source/common/utracimp.h
@@ -0,0 +1,384 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2003-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  utracimp.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2003aug06
+*   created by: Markus W. Scherer
+*
+*   Internal header for ICU tracing/logging.
+*
+*
+*   Various notes:
+*   - using a trace level variable to only call trace functions
+*     when the level is sufficient
+*   - using the same variable for tracing on/off to never make a function
+*     call when off
+*   - the function number is put into a local variable by the entry macro
+*     and used implicitly to avoid copy&paste/typing mistakes by the developer
+*   - the application must call utrace_setFunctions() and pass in
+*     implementations for the trace functions
+*   - ICU trace macros call ICU functions that route through the function
+*     pointers if they have been set;
+*     this avoids an indirection at the call site
+*     (which would cost more code for another check and for the indirection)
+*
+*   ### TODO Issues:
+*   - Verify that va_list is portable among compilers for the same platform.
+*     va_list should be portable because printf() would fail otherwise!
+*   - Should enum values like UTraceLevel be passed into int32_t-type arguments,
+*     or should enum types be used?
+*/
+
+#ifndef __UTRACIMP_H__
+#define __UTRACIMP_H__
+
+#include "unicode/utrace.h"
+#include <stdarg.h>
+
+U_CDECL_BEGIN
+
+/**
+ * \var utrace_level
+ * Trace level variable. Negative for "off".
+ * Use only via UTRACE_ macros.
+ * @internal
+ */
+#ifdef UTRACE_IMPL
+U_EXPORT int32_t
+#else
+U_CFUNC U_COMMON_API int32_t
+#endif
+utrace_level;
+
+
+/** 
+ *   Traced Function Exit return types.  
+ *   Flags indicating the number and types of varargs included in a call
+ *   to a UTraceExit function.
+ *   Bits 0-3:  The function return type.  First variable param.
+ *   Bit    4:  Flag for presence of U_ErrorCode status param.
+ *   @internal
+ */
+typedef enum UTraceExitVal {
+    /** The traced function returns no value  @internal */
+    UTRACE_EXITV_NONE   = 0,
+    /** The traced function returns an int32_t, or compatible, type.  @internal */
+    UTRACE_EXITV_I32    = 1,
+    /** The traced function returns a pointer  @internal */
+    UTRACE_EXITV_PTR    = 2,
+    /** The traced function returns a UBool  @internal */
+    UTRACE_EXITV_BOOL   = 3,
+    /** Mask to extract the return type values from a UTraceExitVal  @internal */
+    UTRACE_EXITV_MASK   = 0xf,
+    /** Bit indicating that the traced function includes a UErrorCode parameter  @internal */
+    UTRACE_EXITV_STATUS = 0x10
+} UTraceExitVal;
+
+/**
+ * Trace function for the entry point of a function.
+ * Do not use directly, use UTRACE_ENTRY instead.
+ * @param fnNumber The UTraceFunctionNumber for the current function.
+ * @internal
+ */
+U_CAPI void U_EXPORT2
+utrace_entry(int32_t fnNumber);
+
+/**
+ * Trace function for each exit point of a function.
+ * Do not use directly, use UTRACE_EXIT* instead.
+ * @param fnNumber The UTraceFunctionNumber for the current function.
+ * @param returnType The type of the value returned by the function.
+ * @param errorCode The UErrorCode value at function exit. See UTRACE_EXIT.
+ * @internal
+ */
+U_CAPI void U_EXPORT2
+utrace_exit(int32_t fnNumber, int32_t returnType, ...);
+
+
+/**
+ * Trace function used inside functions that have a UTRACE_ENTRY() statement.
+ * Do not use directly, use UTRACE_DATAX() macros instead.
+ *
+ * @param utraceFnNumber The number of the current function, from the local
+ *        variable of the same name.
+ * @param level The trace level for this message.
+ * @param fmt The trace format string.
+ *
+ * @internal
+ */
+U_CAPI void U_EXPORT2
+utrace_data(int32_t utraceFnNumber, int32_t level, const char *fmt, ...);
+
+U_CDECL_END
+
+#if U_ENABLE_TRACING
+
+/**
+ * Boolean expression to see if ICU tracing is turned on
+ * to at least the specified level.
+ * @internal
+ */
+#define UTRACE_LEVEL(level) (utrace_getLevel()>=(level))
+
+/**
+  *  Flag bit in utraceFnNumber, the local variable added to each function 
+  *  with tracing code to contains the function number.
+  *
+  *  Set the flag if the function's entry is traced, which will cause the
+  *  function's exit to also be traced.  utraceFnNumber is uncoditionally 
+  *  set at entry, whether or not the entry is traced, so that it will
+  *  always be available for error trace output.
+  *  @internal
+  */            
+#define UTRACE_TRACED_ENTRY 0x80000000
+
+/**
+ * Trace statement for the entry point of a function.
+ * Stores the function number in a local variable.
+ * In C code, must be placed immediately after the last variable declaration.
+ * Must be matched with UTRACE_EXIT() at all function exit points.
+ *
+ * Tracing should start with UTRACE_ENTRY after checking for
+ * U_FAILURE at function entry, so that if a function returns immediately
+ * because of a pre-existing error condition, it does not show up in the trace,
+ * consistent with ICU's error handling model.
+ *
+ * @param fnNumber The UTraceFunctionNumber for the current function.
+ * @internal
+ */
+#define UTRACE_ENTRY(fnNumber) \
+    int32_t utraceFnNumber=(fnNumber); \
+    if(utrace_getLevel()>=UTRACE_INFO) { \
+        utrace_entry(fnNumber); \
+        utraceFnNumber |= UTRACE_TRACED_ENTRY; \
+    }
+
+
+/**
+ * Trace statement for the entry point of open and close functions.
+ * Produces trace output at a less verbose setting than plain UTRACE_ENTRY
+ * Stores the function number in a local variable.
+ * In C code, must be placed immediately after the last variable declaration.
+ * Must be matched with UTRACE_EXIT() at all function exit points.
+ *
+ * @param fnNumber The UTraceFunctionNumber for the current function.
+ * @internal
+ */
+#define UTRACE_ENTRY_OC(fnNumber) \
+    int32_t utraceFnNumber=(fnNumber); \
+    if(utrace_getLevel()>=UTRACE_OPEN_CLOSE) { \
+        utrace_entry(fnNumber); \
+        utraceFnNumber |= UTRACE_TRACED_ENTRY; \
+    }
+
+/**
+ * Trace statement for each exit point of a function that has a UTRACE_ENTRY()
+ * statement.
+ *
+ * @param errorCode The function's ICU UErrorCode value at function exit,
+ *                  or U_ZERO_ERROR if the function does not use a UErrorCode.
+ *                  0==U_ZERO_ERROR indicates success,
+ *                  positive values an error (see u_errorName()),
+ *                  negative values an informational status.
+ *
+ * @internal
+ */
+#define UTRACE_EXIT() \
+    {if(utraceFnNumber & UTRACE_TRACED_ENTRY) { \
+        utrace_exit(utraceFnNumber & ~UTRACE_TRACED_ENTRY, UTRACE_EXITV_NONE); \
+    }}
+
+/**
+ * Trace statement for each exit point of a function that has a UTRACE_ENTRY()
+ * statement, and that returns a value.
+ *
+ * @param val       The function's return value, int32_t or comatible type.
+ *
+ * @internal 
+ */
+#define UTRACE_EXIT_VALUE(val) \
+    {if(utraceFnNumber & UTRACE_TRACED_ENTRY) { \
+        utrace_exit(utraceFnNumber & ~UTRACE_TRACED_ENTRY, UTRACE_EXITV_I32, val); \
+    }}
+
+#define UTRACE_EXIT_STATUS(status) \
+    {if(utraceFnNumber & UTRACE_TRACED_ENTRY) { \
+        utrace_exit(utraceFnNumber & ~UTRACE_TRACED_ENTRY, UTRACE_EXITV_STATUS, status); \
+    }}
+
+#define UTRACE_EXIT_VALUE_STATUS(val, status) \
+    {if(utraceFnNumber & UTRACE_TRACED_ENTRY) { \
+        utrace_exit(utraceFnNumber & ~UTRACE_TRACED_ENTRY, (UTRACE_EXITV_I32 | UTRACE_EXITV_STATUS), val, status); \
+    }}
+
+#define UTRACE_EXIT_PTR_STATUS(ptr, status) \
+    {if(utraceFnNumber & UTRACE_TRACED_ENTRY) { \
+        utrace_exit(utraceFnNumber & ~UTRACE_TRACED_ENTRY, (UTRACE_EXITV_PTR | UTRACE_EXITV_STATUS), ptr, status); \
+    }}
+
+/**
+ * Trace statement used inside functions that have a UTRACE_ENTRY() statement.
+ * Takes no data arguments.
+ * The number of arguments for this macro must match the number of inserts
+ * in the format string. Vector inserts count as two arguments.
+ * Calls utrace_data() if the level is high enough.
+ * @internal
+ */
+#define UTRACE_DATA0(level, fmt) \
+    if(UTRACE_LEVEL(level)) { \
+        utrace_data(utraceFnNumber & ~UTRACE_TRACED_ENTRY, (level), (fmt)); \
+    }
+
+/**
+ * Trace statement used inside functions that have a UTRACE_ENTRY() statement.
+ * Takes one data argument.
+ * The number of arguments for this macro must match the number of inserts
+ * in the format string. Vector inserts count as two arguments.
+ * Calls utrace_data() if the level is high enough.
+ * @internal
+ */
+#define UTRACE_DATA1(level, fmt, a) \
+    if(UTRACE_LEVEL(level)) { \
+        utrace_data(utraceFnNumber & ~UTRACE_TRACED_ENTRY , (level), (fmt), (a)); \
+    }
+
+/**
+ * Trace statement used inside functions that have a UTRACE_ENTRY() statement.
+ * Takes two data arguments.
+ * The number of arguments for this macro must match the number of inserts
+ * in the format string. Vector inserts count as two arguments.
+ * Calls utrace_data() if the level is high enough.
+ * @internal
+ */
+#define UTRACE_DATA2(level, fmt, a, b) \
+    if(UTRACE_LEVEL(level)) { \
+        utrace_data(utraceFnNumber & ~UTRACE_TRACED_ENTRY , (level), (fmt), (a), (b)); \
+    }
+
+/**
+ * Trace statement used inside functions that have a UTRACE_ENTRY() statement.
+ * Takes three data arguments.
+ * The number of arguments for this macro must match the number of inserts
+ * in the format string. Vector inserts count as two arguments.
+ * Calls utrace_data() if the level is high enough.
+ * @internal
+ */
+#define UTRACE_DATA3(level, fmt, a, b, c) \
+    if(UTRACE_LEVEL(level)) { \
+        utrace_data(utraceFnNumber & ~UTRACE_TRACED_ENTRY, (level), (fmt), (a), (b), (c)); \
+    }
+
+/**
+ * Trace statement used inside functions that have a UTRACE_ENTRY() statement.
+ * Takes four data arguments.
+ * The number of arguments for this macro must match the number of inserts
+ * in the format string. Vector inserts count as two arguments.
+ * Calls utrace_data() if the level is high enough.
+ * @internal
+ */
+#define UTRACE_DATA4(level, fmt, a, b, c, d) \
+    if(UTRACE_LEVEL(level)) { \
+        utrace_data(utraceFnNumber & ~UTRACE_TRACED_ENTRY, (level), (fmt), (a), (b), (c), (d)); \
+    }
+
+/**
+ * Trace statement used inside functions that have a UTRACE_ENTRY() statement.
+ * Takes five data arguments.
+ * The number of arguments for this macro must match the number of inserts
+ * in the format string. Vector inserts count as two arguments.
+ * Calls utrace_data() if the level is high enough.
+ * @internal
+ */
+#define UTRACE_DATA5(level, fmt, a, b, c, d, e) \
+    if(UTRACE_LEVEL(level)) { \
+        utrace_data(utraceFnNumber & ~UTRACE_TRACED_ENTRY, (level), (fmt), (a), (b), (c), (d), (e)); \
+    }
+
+/**
+ * Trace statement used inside functions that have a UTRACE_ENTRY() statement.
+ * Takes six data arguments.
+ * The number of arguments for this macro must match the number of inserts
+ * in the format string. Vector inserts count as two arguments.
+ * Calls utrace_data() if the level is high enough.
+ * @internal
+ */
+#define UTRACE_DATA6(level, fmt, a, b, c, d, e, f) \
+    if(UTRACE_LEVEL(level)) { \
+        utrace_data(utraceFnNumber & ~UTRACE_TRACED_ENTRY, (level), (fmt), (a), (b), (c), (d), (e), (f)); \
+    }
+
+/**
+ * Trace statement used inside functions that have a UTRACE_ENTRY() statement.
+ * Takes seven data arguments.
+ * The number of arguments for this macro must match the number of inserts
+ * in the format string. Vector inserts count as two arguments.
+ * Calls utrace_data() if the level is high enough.
+ * @internal
+ */
+#define UTRACE_DATA7(level, fmt, a, b, c, d, e, f, g) \
+    if(UTRACE_LEVEL(level)) { \
+        utrace_data(utraceFnNumber & ~UTRACE_TRACED_ENTRY, (level), (fmt), (a), (b), (c), (d), (e), (f), (g)); \
+    }
+
+/**
+ * Trace statement used inside functions that have a UTRACE_ENTRY() statement.
+ * Takes eight data arguments.
+ * The number of arguments for this macro must match the number of inserts
+ * in the format string. Vector inserts count as two arguments.
+ * Calls utrace_data() if the level is high enough.
+ * @internal
+ */
+#define UTRACE_DATA8(level, fmt, a, b, c, d, e, f, g, h) \
+    if(UTRACE_LEVEL(level)) { \
+        utrace_data(utraceFnNumber & ~UTRACE_TRACED_ENTRY, (level), (fmt), (a), (b), (c), (d), (e), (f), (g), (h)); \
+    }
+
+/**
+ * Trace statement used inside functions that have a UTRACE_ENTRY() statement.
+ * Takes nine data arguments.
+ * The number of arguments for this macro must match the number of inserts
+ * in the format string. Vector inserts count as two arguments.
+ * Calls utrace_data() if the level is high enough.
+ * @internal
+ */
+#define UTRACE_DATA9(level, fmt, a, b, c, d, e, f, g, h, i) \
+    if(UTRACE_LEVEL(level)) { \
+        utrace_data(utraceFnNumber & ~UTRACE_TRACED_ENTRY, (level), (fmt), (a), (b), (c), (d), (e), (f), (g), (h), (i)); \
+    }
+
+#else
+
+/*
+ * When tracing is disabled, the following macros become empty
+ */
+
+#define UTRACE_LEVEL(level) 0
+#define UTRACE_ENTRY(fnNumber)
+#define UTRACE_ENTRY_OC(fnNumber)
+#define UTRACE_EXIT()
+#define UTRACE_EXIT_VALUE(val)
+#define UTRACE_EXIT_STATUS(status)
+#define UTRACE_EXIT_VALUE_STATUS(val, status)
+#define UTRACE_EXIT_PTR_STATUS(ptr, status)
+#define UTRACE_DATA0(level, fmt)
+#define UTRACE_DATA1(level, fmt, a)
+#define UTRACE_DATA2(level, fmt, a, b)
+#define UTRACE_DATA3(level, fmt, a, b, c)
+#define UTRACE_DATA4(level, fmt, a, b, c, d)
+#define UTRACE_DATA5(level, fmt, a, b, c, d, e)
+#define UTRACE_DATA6(level, fmt, a, b, c, d, e, f)
+#define UTRACE_DATA7(level, fmt, a, b, c, d, e, f, g)
+#define UTRACE_DATA8(level, fmt, a, b, c, d, e, f, g, h)
+#define UTRACE_DATA9(level, fmt, a, b, c, d, e, f, g, h, i)
+
+#endif
+
+#endif
diff --git a/source/common/utrie.c b/source/common/utrie.c
new file mode 100644
index 0000000..ddb94bb
--- /dev/null
+++ b/source/common/utrie.c
@@ -0,0 +1,1232 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2001-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  utrie.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2001oct20
+*   created by: Markus W. Scherer
+*
+*   This is a common implementation of a "folded" trie.
+*   It is a kind of compressed, serializable table of 16- or 32-bit values associated with
+*   Unicode code points (0..0x10ffff).
+*/
+
+#ifdef UTRIE_DEBUG
+#   include <stdio.h>
+#endif
+
+#include "unicode/utypes.h"
+#include "cmemory.h"
+#include "utrie.h"
+
+/* miscellaneous ------------------------------------------------------------ */
+
+#undef ABS
+#define ABS(x) ((x)>=0 ? (x) : -(x))
+
+static U_INLINE UBool
+equal_uint32(const uint32_t *s, const uint32_t *t, int32_t length) {
+    while(length>0 && *s==*t) {
+        ++s;
+        ++t;
+        --length;
+    }
+    return (UBool)(length==0);
+}
+
+/* Building a trie ----------------------------------------------------------*/
+
+U_CAPI UNewTrie * U_EXPORT2
+utrie_open(UNewTrie *fillIn,
+           uint32_t *aliasData, int32_t maxDataLength,
+           uint32_t initialValue, uint32_t leadUnitValue,
+           UBool latin1Linear) {
+    UNewTrie *trie;
+    int32_t i, j;
+
+    if( maxDataLength<UTRIE_DATA_BLOCK_LENGTH ||
+        (latin1Linear && maxDataLength<1024)
+    ) {
+        return NULL;
+    }
+
+    if(fillIn!=NULL) {
+        trie=fillIn;
+    } else {
+        trie=(UNewTrie *)uprv_malloc(sizeof(UNewTrie));
+        if(trie==NULL) {
+            return NULL;
+        }
+    }
+    uprv_memset(trie, 0, sizeof(UNewTrie));
+    trie->isAllocated= (UBool)(fillIn==NULL);
+
+    if(aliasData!=NULL) {
+        trie->data=aliasData;
+        trie->isDataAllocated=FALSE;
+    } else {
+        trie->data=(uint32_t *)uprv_malloc(maxDataLength*4);
+        if(trie->data==NULL) {
+            uprv_free(trie);
+            return NULL;
+        }
+        trie->isDataAllocated=TRUE;
+    }
+
+    /* preallocate and reset the first data block (block index 0) */
+    j=UTRIE_DATA_BLOCK_LENGTH;
+
+    if(latin1Linear) {
+        /* preallocate and reset the first block (number 0) and Latin-1 (U+0000..U+00ff) after that */
+        /* made sure above that maxDataLength>=1024 */
+
+        /* set indexes to point to consecutive data blocks */
+        i=0;
+        do {
+            /* do this at least for trie->index[0] even if that block is only partly used for Latin-1 */
+            trie->index[i++]=j;
+            j+=UTRIE_DATA_BLOCK_LENGTH;
+        } while(i<(256>>UTRIE_SHIFT));
+    }
+
+    /* reset the initially allocated blocks to the initial value */
+    trie->dataLength=j;
+    while(j>0) {
+        trie->data[--j]=initialValue;
+    }
+
+    trie->leadUnitValue=leadUnitValue;
+    trie->indexLength=UTRIE_MAX_INDEX_LENGTH;
+    trie->dataCapacity=maxDataLength;
+    trie->isLatin1Linear=latin1Linear;
+    trie->isCompacted=FALSE;
+    return trie;
+}
+
+U_CAPI UNewTrie * U_EXPORT2
+utrie_clone(UNewTrie *fillIn, const UNewTrie *other, uint32_t *aliasData, int32_t aliasDataCapacity) {
+    UNewTrie *trie;
+    UBool isDataAllocated;
+
+    /* do not clone if other is not valid or already compacted */
+    if(other==NULL || other->data==NULL || other->isCompacted) {
+        return NULL;
+    }
+
+    /* clone data */
+    if(aliasData!=NULL && aliasDataCapacity>=other->dataCapacity) {
+        isDataAllocated=FALSE;
+    } else {
+        aliasDataCapacity=other->dataCapacity;
+        aliasData=(uint32_t *)uprv_malloc(other->dataCapacity*4);
+        if(aliasData==NULL) {
+            return NULL;
+        }
+        isDataAllocated=TRUE;
+    }
+
+    trie=utrie_open(fillIn, aliasData, aliasDataCapacity,
+                    other->data[0], other->leadUnitValue,
+                    other->isLatin1Linear);
+    if(trie==NULL) {
+        uprv_free(aliasData);
+    } else {
+        uprv_memcpy(trie->index, other->index, sizeof(trie->index));
+        uprv_memcpy(trie->data, other->data, other->dataLength*4);
+        trie->dataLength=other->dataLength;
+        trie->isDataAllocated=isDataAllocated;
+    }
+
+    return trie;
+}
+
+U_CAPI void U_EXPORT2
+utrie_close(UNewTrie *trie) {
+    if(trie!=NULL) {
+        if(trie->isDataAllocated) {
+            uprv_free(trie->data);
+            trie->data=NULL;
+        }
+        if(trie->isAllocated) {
+            uprv_free(trie);
+        }
+    }
+}
+
+U_CAPI uint32_t * U_EXPORT2
+utrie_getData(UNewTrie *trie, int32_t *pLength) {
+    if(trie==NULL || pLength==NULL) {
+        return NULL;
+    }
+
+    *pLength=trie->dataLength;
+    return trie->data;
+}
+
+static int32_t
+utrie_allocDataBlock(UNewTrie *trie) {
+    int32_t newBlock, newTop;
+
+    newBlock=trie->dataLength;
+    newTop=newBlock+UTRIE_DATA_BLOCK_LENGTH;
+    if(newTop>trie->dataCapacity) {
+        /* out of memory in the data array */
+        return -1;
+    }
+    trie->dataLength=newTop;
+    return newBlock;
+}
+
+/**
+ * No error checking for illegal arguments.
+ *
+ * @return -1 if no new data block available (out of memory in data array)
+ * @internal
+ */
+static int32_t
+utrie_getDataBlock(UNewTrie *trie, UChar32 c) {
+    int32_t indexValue, newBlock;
+
+    c>>=UTRIE_SHIFT;
+    indexValue=trie->index[c];
+    if(indexValue>0) {
+        return indexValue;
+    }
+
+    /* allocate a new data block */
+    newBlock=utrie_allocDataBlock(trie);
+    if(newBlock<0) {
+        /* out of memory in the data array */
+        return -1;
+    }
+    trie->index[c]=newBlock;
+
+    /* copy-on-write for a block from a setRange() */
+    uprv_memcpy(trie->data+newBlock, trie->data-indexValue, 4*UTRIE_DATA_BLOCK_LENGTH);
+    return newBlock;
+}
+
+/**
+ * @return TRUE if the value was successfully set
+ */
+U_CAPI UBool U_EXPORT2
+utrie_set32(UNewTrie *trie, UChar32 c, uint32_t value) {
+    int32_t block;
+
+    /* valid, uncompacted trie and valid c? */
+    if(trie==NULL || trie->isCompacted || (uint32_t)c>0x10ffff) {
+        return FALSE;
+    }
+
+    block=utrie_getDataBlock(trie, c);
+    if(block<0) {
+        return FALSE;
+    }
+
+    trie->data[block+(c&UTRIE_MASK)]=value;
+    return TRUE;
+}
+
+U_CAPI uint32_t U_EXPORT2
+utrie_get32(UNewTrie *trie, UChar32 c, UBool *pInBlockZero) {
+    int32_t block;
+
+    /* valid, uncompacted trie and valid c? */
+    if(trie==NULL || trie->isCompacted || (uint32_t)c>0x10ffff) {
+        if(pInBlockZero!=NULL) {
+            *pInBlockZero=TRUE;
+        }
+        return 0;
+    }
+
+    block=trie->index[c>>UTRIE_SHIFT];
+    if(pInBlockZero!=NULL) {
+        *pInBlockZero= (UBool)(block==0);
+    }
+
+    return trie->data[ABS(block)+(c&UTRIE_MASK)];
+}
+
+/**
+ * @internal
+ */
+static void
+utrie_fillBlock(uint32_t *block, UChar32 start, UChar32 limit,
+                uint32_t value, uint32_t initialValue, UBool overwrite) {
+    uint32_t *pLimit;
+
+    pLimit=block+limit;
+    block+=start;
+    if(overwrite) {
+        while(block<pLimit) {
+            *block++=value;
+        }
+    } else {
+        while(block<pLimit) {
+            if(*block==initialValue) {
+                *block=value;
+            }
+            ++block;
+        }
+    }
+}
+
+U_CAPI UBool U_EXPORT2
+utrie_setRange32(UNewTrie *trie, UChar32 start, UChar32 limit, uint32_t value, UBool overwrite) {
+    /*
+     * repeat value in [start..limit[
+     * mark index values for repeat-data blocks by setting bit 31 of the index values
+     * fill around existing values if any, if(overwrite)
+     */
+    uint32_t initialValue;
+    int32_t block, rest, repeatBlock;
+
+    /* valid, uncompacted trie and valid indexes? */
+    if( trie==NULL || trie->isCompacted ||
+        (uint32_t)start>0x10ffff || (uint32_t)limit>0x110000 || start>limit
+    ) {
+        return FALSE;
+    }
+    if(start==limit) {
+        return TRUE; /* nothing to do */
+    }
+
+    initialValue=trie->data[0];
+    if(start&UTRIE_MASK) {
+        UChar32 nextStart;
+
+        /* set partial block at [start..following block boundary[ */
+        block=utrie_getDataBlock(trie, start);
+        if(block<0) {
+            return FALSE;
+        }
+
+        nextStart=(start+UTRIE_DATA_BLOCK_LENGTH)&~UTRIE_MASK;
+        if(nextStart<=limit) {
+            utrie_fillBlock(trie->data+block, start&UTRIE_MASK, UTRIE_DATA_BLOCK_LENGTH,
+                            value, initialValue, overwrite);
+            start=nextStart;
+        } else {
+            utrie_fillBlock(trie->data+block, start&UTRIE_MASK, limit&UTRIE_MASK,
+                            value, initialValue, overwrite);
+            return TRUE;
+        }
+    }
+
+    /* number of positions in the last, partial block */
+    rest=limit&UTRIE_MASK;
+
+    /* round down limit to a block boundary */
+    limit&=~UTRIE_MASK;
+
+    /* iterate over all-value blocks */
+    if(value==initialValue) {
+        repeatBlock=0;
+    } else {
+        repeatBlock=-1;
+    }
+    while(start<limit) {
+        /* get index value */
+        block=trie->index[start>>UTRIE_SHIFT];
+        if(block>0) {
+            /* already allocated, fill in value */
+            utrie_fillBlock(trie->data+block, 0, UTRIE_DATA_BLOCK_LENGTH, value, initialValue, overwrite);
+        } else if(trie->data[-block]!=value && (block==0 || overwrite)) {
+            /* set the repeatBlock instead of the current block 0 or range block */
+            if(repeatBlock>=0) {
+                trie->index[start>>UTRIE_SHIFT]=-repeatBlock;
+            } else {
+                /* create and set and fill the repeatBlock */
+                repeatBlock=utrie_getDataBlock(trie, start);
+                if(repeatBlock<0) {
+                    return FALSE;
+                }
+
+                /* set the negative block number to indicate that it is a repeat block */
+                trie->index[start>>UTRIE_SHIFT]=-repeatBlock;
+                utrie_fillBlock(trie->data+repeatBlock, 0, UTRIE_DATA_BLOCK_LENGTH, value, initialValue, TRUE);
+            }
+        }
+
+        start+=UTRIE_DATA_BLOCK_LENGTH;
+    }
+
+    if(rest>0) {
+        /* set partial block at [last block boundary..limit[ */
+        block=utrie_getDataBlock(trie, start);
+        if(block<0) {
+            return FALSE;
+        }
+
+        utrie_fillBlock(trie->data+block, 0, rest, value, initialValue, overwrite);
+    }
+
+    return TRUE;
+}
+
+static int32_t
+_findSameIndexBlock(const int32_t *idx, int32_t indexLength,
+                    int32_t otherBlock) {
+    int32_t block, i;
+
+    for(block=UTRIE_BMP_INDEX_LENGTH; block<indexLength; block+=UTRIE_SURROGATE_BLOCK_COUNT) {
+        for(i=0; i<UTRIE_SURROGATE_BLOCK_COUNT; ++i) {
+            if(idx[block+i]!=idx[otherBlock+i]) {
+                break;
+            }
+        }
+        if(i==UTRIE_SURROGATE_BLOCK_COUNT) {
+            return block;
+        }
+    }
+    return indexLength;
+}
+
+/*
+ * Fold the normalization data for supplementary code points into
+ * a compact area on top of the BMP-part of the trie index,
+ * with the lead surrogates indexing this compact area.
+ *
+ * Duplicate the index values for lead surrogates:
+ * From inside the BMP area, where some may be overridden with folded values,
+ * to just after the BMP area, where they can be retrieved for
+ * code point lookups.
+ */
+static void
+utrie_fold(UNewTrie *trie, UNewTrieGetFoldedValue *getFoldedValue, UErrorCode *pErrorCode) {
+    int32_t leadIndexes[UTRIE_SURROGATE_BLOCK_COUNT];
+    int32_t *idx;
+    uint32_t value;
+    UChar32 c;
+    int32_t indexLength, block;
+#ifdef UTRIE_DEBUG
+    int countLeadCUWithData=0;
+#endif
+
+    idx=trie->index;
+
+    /* copy the lead surrogate indexes into a temporary array */
+    uprv_memcpy(leadIndexes, idx+(0xd800>>UTRIE_SHIFT), 4*UTRIE_SURROGATE_BLOCK_COUNT);
+
+    /*
+     * set all values for lead surrogate code *units* to leadUnitValue
+     * so that, by default, runtime lookups will find no data for associated
+     * supplementary code points, unless there is data for such code points
+     * which will result in a non-zero folding value below that is set for
+     * the respective lead units
+     *
+     * the above saved the indexes for surrogate code *points*
+     * fill the indexes with simplified code from utrie_setRange32()
+     */
+    if(trie->leadUnitValue==trie->data[0]) {
+        block=0; /* leadUnitValue==initialValue, use all-initial-value block */
+    } else {
+        /* create and fill the repeatBlock */
+        block=utrie_allocDataBlock(trie);
+        if(block<0) {
+            /* data table overflow */
+            *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+        utrie_fillBlock(trie->data+block, 0, UTRIE_DATA_BLOCK_LENGTH, trie->leadUnitValue, trie->data[0], TRUE);
+        block=-block; /* negative block number to indicate that it is a repeat block */
+    }
+    for(c=(0xd800>>UTRIE_SHIFT); c<(0xdc00>>UTRIE_SHIFT); ++c) {
+        trie->index[c]=block;
+    }
+
+    /*
+     * Fold significant index values into the area just after the BMP indexes.
+     * In case the first lead surrogate has significant data,
+     * its index block must be used first (in which case the folding is a no-op).
+     * Later all folded index blocks are moved up one to insert the copied
+     * lead surrogate indexes.
+     */
+    indexLength=UTRIE_BMP_INDEX_LENGTH;
+
+    /* search for any index (stage 1) entries for supplementary code points */
+    for(c=0x10000; c<0x110000;) {
+        if(idx[c>>UTRIE_SHIFT]!=0) {
+            /* there is data, treat the full block for a lead surrogate */
+            c&=~0x3ff;
+
+#ifdef UTRIE_DEBUG
+            ++countLeadCUWithData;
+            /* printf("supplementary data for lead surrogate U+%04lx\n", (long)(0xd7c0+(c>>10))); */
+#endif
+
+            /* is there an identical index block? */
+            block=_findSameIndexBlock(idx, indexLength, c>>UTRIE_SHIFT);
+
+            /*
+             * get a folded value for [c..c+0x400[ and,
+             * if different from the value for the lead surrogate code point,
+             * set it for the lead surrogate code unit
+             */
+            value=getFoldedValue(trie, c, block+UTRIE_SURROGATE_BLOCK_COUNT);
+            if(value!=utrie_get32(trie, U16_LEAD(c), NULL)) {
+                if(!utrie_set32(trie, U16_LEAD(c), value)) {
+                    /* data table overflow */
+                    *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+                    return;
+                }
+
+                /* if we did not find an identical index block... */
+                if(block==indexLength) {
+                    /* move the actual index (stage 1) entries from the supplementary position to the new one */
+                    uprv_memmove(idx+indexLength,
+                                 idx+(c>>UTRIE_SHIFT),
+                                 4*UTRIE_SURROGATE_BLOCK_COUNT);
+                    indexLength+=UTRIE_SURROGATE_BLOCK_COUNT;
+                }
+            }
+            c+=0x400;
+        } else {
+            c+=UTRIE_DATA_BLOCK_LENGTH;
+        }
+    }
+#ifdef UTRIE_DEBUG
+    if(countLeadCUWithData>0) {
+        printf("supplementary data for %d lead surrogates\n", countLeadCUWithData);
+    }
+#endif
+
+    /*
+     * index array overflow?
+     * This is to guarantee that a folding offset is of the form
+     * UTRIE_BMP_INDEX_LENGTH+n*UTRIE_SURROGATE_BLOCK_COUNT with n=0..1023.
+     * If the index is too large, then n>=1024 and more than 10 bits are necessary.
+     *
+     * In fact, it can only ever become n==1024 with completely unfoldable data and
+     * the additional block of duplicated values for lead surrogates.
+     */
+    if(indexLength>=UTRIE_MAX_INDEX_LENGTH) {
+        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+        return;
+    }
+
+    /*
+     * make space for the lead surrogate index block and
+     * insert it between the BMP indexes and the folded ones
+     */
+    uprv_memmove(idx+UTRIE_BMP_INDEX_LENGTH+UTRIE_SURROGATE_BLOCK_COUNT,
+                 idx+UTRIE_BMP_INDEX_LENGTH,
+                 4*(indexLength-UTRIE_BMP_INDEX_LENGTH));
+    uprv_memcpy(idx+UTRIE_BMP_INDEX_LENGTH,
+                leadIndexes,
+                4*UTRIE_SURROGATE_BLOCK_COUNT);
+    indexLength+=UTRIE_SURROGATE_BLOCK_COUNT;
+
+#ifdef UTRIE_DEBUG
+    printf("trie index count: BMP %ld  all Unicode %ld  folded %ld\n",
+           UTRIE_BMP_INDEX_LENGTH, (long)UTRIE_MAX_INDEX_LENGTH, indexLength);
+#endif
+
+    trie->indexLength=indexLength;
+}
+
+/*
+ * Set a value in the trie index map to indicate which data block
+ * is referenced and which one is not.
+ * utrie_compact() will remove data blocks that are not used at all.
+ * Set
+ * - 0 if it is used
+ * - -1 if it is not used
+ */
+static void
+_findUnusedBlocks(UNewTrie *trie) {
+    int32_t i;
+
+    /* fill the entire map with "not used" */
+    uprv_memset(trie->map, 0xff, (UTRIE_MAX_BUILD_TIME_DATA_LENGTH>>UTRIE_SHIFT)*4);
+
+    /* mark each block that _is_ used with 0 */
+    for(i=0; i<trie->indexLength; ++i) {
+        trie->map[ABS(trie->index[i])>>UTRIE_SHIFT]=0;
+    }
+
+    /* never move the all-initial-value block 0 */
+    trie->map[0]=0;
+}
+
+static int32_t
+_findSameDataBlock(const uint32_t *data, int32_t dataLength,
+                   int32_t otherBlock, int32_t step) {
+    int32_t block;
+
+    /* ensure that we do not even partially get past dataLength */
+    dataLength-=UTRIE_DATA_BLOCK_LENGTH;
+
+    for(block=0; block<=dataLength; block+=step) {
+        if(equal_uint32(data+block, data+otherBlock, UTRIE_DATA_BLOCK_LENGTH)) {
+            return block;
+        }
+    }
+    return -1;
+}
+
+/*
+ * Compact a folded build-time trie.
+ *
+ * The compaction
+ * - removes blocks that are identical with earlier ones
+ * - overlaps adjacent blocks as much as possible (if overlap==TRUE)
+ * - moves blocks in steps of the data granularity
+ * - moves and overlaps blocks that overlap with multiple values in the overlap region
+ *
+ * It does not
+ * - try to move and overlap blocks that are not already adjacent
+ */
+static void
+utrie_compact(UNewTrie *trie, UBool overlap, UErrorCode *pErrorCode) {
+    int32_t i, start, newStart, overlapStart;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return;
+    }
+
+    /* valid, uncompacted trie? */
+    if(trie==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    if(trie->isCompacted) {
+        return; /* nothing left to do */
+    }
+
+    /* compaction */
+
+    /* initialize the index map with "block is used/unused" flags */
+    _findUnusedBlocks(trie);
+
+    /* if Latin-1 is preallocated and linear, then do not compact Latin-1 data */
+    if(trie->isLatin1Linear && UTRIE_SHIFT<=8) {
+        overlapStart=UTRIE_DATA_BLOCK_LENGTH+256;
+    } else {
+        overlapStart=UTRIE_DATA_BLOCK_LENGTH;
+    }
+
+    newStart=UTRIE_DATA_BLOCK_LENGTH;
+    for(start=newStart; start<trie->dataLength;) {
+        /*
+         * start: index of first entry of current block
+         * newStart: index where the current block is to be moved
+         *           (right after current end of already-compacted data)
+         */
+
+        /* skip blocks that are not used */
+        if(trie->map[start>>UTRIE_SHIFT]<0) {
+            /* advance start to the next block */
+            start+=UTRIE_DATA_BLOCK_LENGTH;
+
+            /* leave newStart with the previous block! */
+            continue;
+        }
+
+        /* search for an identical block */
+        if( start>=overlapStart &&
+            (i=_findSameDataBlock(trie->data, newStart, start,
+                            overlap ? UTRIE_DATA_GRANULARITY : UTRIE_DATA_BLOCK_LENGTH))
+             >=0
+        ) {
+            /* found an identical block, set the other block's index value for the current block */
+            trie->map[start>>UTRIE_SHIFT]=i;
+
+            /* advance start to the next block */
+            start+=UTRIE_DATA_BLOCK_LENGTH;
+
+            /* leave newStart with the previous block! */
+            continue;
+        }
+
+        /* see if the beginning of this block can be overlapped with the end of the previous block */
+        if(overlap && start>=overlapStart) {
+            /* look for maximum overlap (modulo granularity) with the previous, adjacent block */
+            for(i=UTRIE_DATA_BLOCK_LENGTH-UTRIE_DATA_GRANULARITY;
+                i>0 && !equal_uint32(trie->data+(newStart-i), trie->data+start, i);
+                i-=UTRIE_DATA_GRANULARITY) {}
+        } else {
+            i=0;
+        }
+
+        if(i>0) {
+            /* some overlap */
+            trie->map[start>>UTRIE_SHIFT]=newStart-i;
+
+            /* move the non-overlapping indexes to their new positions */
+            start+=i;
+            for(i=UTRIE_DATA_BLOCK_LENGTH-i; i>0; --i) {
+                trie->data[newStart++]=trie->data[start++];
+            }
+        } else if(newStart<start) {
+            /* no overlap, just move the indexes to their new positions */
+            trie->map[start>>UTRIE_SHIFT]=newStart;
+            for(i=UTRIE_DATA_BLOCK_LENGTH; i>0; --i) {
+                trie->data[newStart++]=trie->data[start++];
+            }
+        } else /* no overlap && newStart==start */ {
+            trie->map[start>>UTRIE_SHIFT]=start;
+            newStart+=UTRIE_DATA_BLOCK_LENGTH;
+            start=newStart;
+        }
+    }
+
+    /* now adjust the index (stage 1) table */
+    for(i=0; i<trie->indexLength; ++i) {
+        trie->index[i]=trie->map[ABS(trie->index[i])>>UTRIE_SHIFT];
+    }
+
+#ifdef UTRIE_DEBUG
+    /* we saved some space */
+    printf("compacting trie: count of 32-bit words %lu->%lu\n",
+            (long)trie->dataLength, (long)newStart);
+#endif
+
+    trie->dataLength=newStart;
+}
+
+/* serialization ------------------------------------------------------------ */
+
+/*
+ * Default function for the folding value:
+ * Just store the offset (16 bits) if there is any non-initial-value entry.
+ *
+ * The offset parameter is never 0.
+ * Returning the offset itself is safe for UTRIE_SHIFT>=5 because
+ * for UTRIE_SHIFT==5 the maximum index length is UTRIE_MAX_INDEX_LENGTH==0x8800
+ * which fits into 16-bit trie values;
+ * for higher UTRIE_SHIFT, UTRIE_MAX_INDEX_LENGTH decreases.
+ *
+ * Theoretically, it would be safer for all possible UTRIE_SHIFT including
+ * those of 4 and lower to return offset>>UTRIE_SURROGATE_BLOCK_BITS
+ * which would always result in a value of 0x40..0x43f
+ * (start/end 1k blocks of supplementary Unicode code points).
+ * However, this would be uglier, and would not work for some existing
+ * binary data file formats.
+ *
+ * Also, we do not plan to change UTRIE_SHIFT because it would change binary
+ * data file formats, and we would probably not make it smaller because of
+ * the then even larger BMP index length even for empty tries.
+ */
+static uint32_t U_CALLCONV
+defaultGetFoldedValue(UNewTrie *trie, UChar32 start, int32_t offset) {
+    uint32_t value, initialValue;
+    UChar32 limit;
+    UBool inBlockZero;
+
+    initialValue=trie->data[0];
+    limit=start+0x400;
+    while(start<limit) {
+        value=utrie_get32(trie, start, &inBlockZero);
+        if(inBlockZero) {
+            start+=UTRIE_DATA_BLOCK_LENGTH;
+        } else if(value!=initialValue) {
+            return (uint32_t)offset;
+        } else {
+            ++start;
+        }
+    }
+    return 0;
+}
+
+U_CAPI int32_t U_EXPORT2
+utrie_serialize(UNewTrie *trie, void *dt, int32_t capacity,
+                UNewTrieGetFoldedValue *getFoldedValue,
+                UBool reduceTo16Bits,
+                UErrorCode *pErrorCode) {
+    UTrieHeader *header;
+    uint32_t *p;
+    uint16_t *dest16;
+    int32_t i, length;
+    uint8_t* data = NULL;
+
+    /* argument check */
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    if(trie==NULL || capacity<0 || (capacity>0 && dt==NULL)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    if(getFoldedValue==NULL) {
+        getFoldedValue=defaultGetFoldedValue;
+    }
+
+    data = (uint8_t*)dt;
+    /* fold and compact if necessary, also checks that indexLength is within limits */
+    if(!trie->isCompacted) {
+        /* compact once without overlap to improve folding */
+        utrie_compact(trie, FALSE, pErrorCode);
+
+        /* fold the supplementary part of the index array */
+        utrie_fold(trie, getFoldedValue, pErrorCode);
+
+        /* compact again with overlap for minimum data array length */
+        utrie_compact(trie, TRUE, pErrorCode);
+
+        trie->isCompacted=TRUE;
+        if(U_FAILURE(*pErrorCode)) {
+            return 0;
+        }
+    }
+
+    /* is dataLength within limits? */
+    if( (reduceTo16Bits ? (trie->dataLength+trie->indexLength) : trie->dataLength) >= UTRIE_MAX_DATA_LENGTH) {
+        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+    }
+
+    length=sizeof(UTrieHeader)+2*trie->indexLength;
+    if(reduceTo16Bits) {
+        length+=2*trie->dataLength;
+    } else {
+        length+=4*trie->dataLength;
+    }
+
+    if(length>capacity) {
+        return length; /* preflighting */
+    }
+
+#ifdef UTRIE_DEBUG
+    printf("**UTrieLengths(serialize)** index:%6ld  data:%6ld  serialized:%6ld\n",
+           (long)trie->indexLength, (long)trie->dataLength, (long)length);
+#endif
+
+    /* set the header fields */
+    header=(UTrieHeader *)data;
+    data+=sizeof(UTrieHeader);
+
+    header->signature=0x54726965; /* "Trie" */
+    header->options=UTRIE_SHIFT | (UTRIE_INDEX_SHIFT<<UTRIE_OPTIONS_INDEX_SHIFT);
+
+    if(!reduceTo16Bits) {
+        header->options|=UTRIE_OPTIONS_DATA_IS_32_BIT;
+    }
+    if(trie->isLatin1Linear) {
+        header->options|=UTRIE_OPTIONS_LATIN1_IS_LINEAR;
+    }
+
+    header->indexLength=trie->indexLength;
+    header->dataLength=trie->dataLength;
+
+    /* write the index (stage 1) array and the 16/32-bit data (stage 2) array */
+    if(reduceTo16Bits) {
+        /* write 16-bit index values shifted right by UTRIE_INDEX_SHIFT, after adding indexLength */
+        p=(uint32_t *)trie->index;
+        dest16=(uint16_t *)data;
+        for(i=trie->indexLength; i>0; --i) {
+            *dest16++=(uint16_t)((*p++ + trie->indexLength)>>UTRIE_INDEX_SHIFT);
+        }
+
+        /* write 16-bit data values */
+        p=trie->data;
+        for(i=trie->dataLength; i>0; --i) {
+            *dest16++=(uint16_t)*p++;
+        }
+    } else {
+        /* write 16-bit index values shifted right by UTRIE_INDEX_SHIFT */
+        p=(uint32_t *)trie->index;
+        dest16=(uint16_t *)data;
+        for(i=trie->indexLength; i>0; --i) {
+            *dest16++=(uint16_t)(*p++ >> UTRIE_INDEX_SHIFT);
+        }
+
+        /* write 32-bit data values */
+        uprv_memcpy(dest16, trie->data, 4*trie->dataLength);
+    }
+
+    return length;
+}
+
+/* inverse to defaultGetFoldedValue() */
+U_CAPI int32_t U_EXPORT2
+utrie_defaultGetFoldingOffset(uint32_t data) {
+    return (int32_t)data;
+}
+
+U_CAPI int32_t U_EXPORT2
+utrie_unserialize(UTrie *trie, const void *data, int32_t length, UErrorCode *pErrorCode) {
+    const UTrieHeader *header;
+    const uint16_t *p16;
+    uint32_t options;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return -1;
+    }
+
+    /* enough data for a trie header? */
+    if(length<sizeof(UTrieHeader)) {
+        *pErrorCode=U_INVALID_FORMAT_ERROR;
+        return -1;
+    }
+
+    /* check the signature */
+    header=(const UTrieHeader *)data;
+    if(header->signature!=0x54726965) {
+        *pErrorCode=U_INVALID_FORMAT_ERROR;
+        return -1;
+    }
+
+    /* get the options and check the shift values */
+    options=header->options;
+    if( (options&UTRIE_OPTIONS_SHIFT_MASK)!=UTRIE_SHIFT ||
+        ((options>>UTRIE_OPTIONS_INDEX_SHIFT)&UTRIE_OPTIONS_SHIFT_MASK)!=UTRIE_INDEX_SHIFT
+    ) {
+        *pErrorCode=U_INVALID_FORMAT_ERROR;
+        return -1;
+    }
+    trie->isLatin1Linear= (UBool)((options&UTRIE_OPTIONS_LATIN1_IS_LINEAR)!=0);
+
+    /* get the length values */
+    trie->indexLength=header->indexLength;
+    trie->dataLength=header->dataLength;
+
+    length-=(int32_t)sizeof(UTrieHeader);
+
+    /* enough data for the index? */
+    if(length<2*trie->indexLength) {
+        *pErrorCode=U_INVALID_FORMAT_ERROR;
+        return -1;
+    }
+    p16=(const uint16_t *)(header+1);
+    trie->index=p16;
+    p16+=trie->indexLength;
+    length-=2*trie->indexLength;
+
+    /* get the data */
+    if(options&UTRIE_OPTIONS_DATA_IS_32_BIT) {
+        if(length<4*trie->dataLength) {
+            *pErrorCode=U_INVALID_FORMAT_ERROR;
+            return -1;
+        }
+        trie->data32=(const uint32_t *)p16;
+        trie->initialValue=trie->data32[0];
+        length=(int32_t)sizeof(UTrieHeader)+2*trie->indexLength+4*trie->dataLength;
+    } else {
+        if(length<2*trie->dataLength) {
+            *pErrorCode=U_INVALID_FORMAT_ERROR;
+            return -1;
+        }
+
+        /* the "data16" data is used via the index pointer */
+        trie->data32=NULL;
+        trie->initialValue=trie->index[trie->indexLength];
+        length=(int32_t)sizeof(UTrieHeader)+2*trie->indexLength+2*trie->dataLength;
+    }
+
+    trie->getFoldingOffset=utrie_defaultGetFoldingOffset;
+
+    return length;
+}
+
+U_CAPI int32_t U_EXPORT2
+utrie_unserializeDummy(UTrie *trie,
+                       void *data, int32_t length,
+                       uint32_t initialValue, uint32_t leadUnitValue,
+                       UBool make16BitTrie,
+                       UErrorCode *pErrorCode) {
+    uint16_t *p16;
+    int32_t actualLength, latin1Length, i, limit;
+    uint16_t block;
+
+    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+        return -1;
+    }
+
+    /* calculate the actual size of the dummy trie data */
+
+    /* max(Latin-1, block 0) */
+    latin1Length= UTRIE_SHIFT<=8 ? 256 : UTRIE_DATA_BLOCK_LENGTH;
+
+    trie->indexLength=UTRIE_BMP_INDEX_LENGTH+UTRIE_SURROGATE_BLOCK_COUNT;
+    trie->dataLength=latin1Length;
+    if(leadUnitValue!=initialValue) {
+        trie->dataLength+=UTRIE_DATA_BLOCK_LENGTH;
+    }
+
+    actualLength=trie->indexLength*2;
+    if(make16BitTrie) {
+        actualLength+=trie->dataLength*2;
+    } else {
+        actualLength+=trie->dataLength*4;
+    }
+
+    /* enough space for the dummy trie? */
+    if(length<actualLength) {
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+        return actualLength;
+    }
+
+    trie->isLatin1Linear=TRUE;
+    trie->initialValue=initialValue;
+
+    /* fill the index and data arrays */
+    p16=(uint16_t *)data;
+    trie->index=p16;
+
+    if(make16BitTrie) {
+        /* indexes to block 0 */
+        block=(uint16_t)(trie->indexLength>>UTRIE_INDEX_SHIFT);
+        limit=trie->indexLength;
+        for(i=0; i<limit; ++i) {
+            p16[i]=block;
+        }
+
+        if(leadUnitValue!=initialValue) {
+            /* indexes for lead surrogate code units to the block after Latin-1 */
+            block+=(uint16_t)(latin1Length>>UTRIE_INDEX_SHIFT);
+            i=0xd800>>UTRIE_SHIFT;
+            limit=0xdc00>>UTRIE_SHIFT;
+            for(; i<limit; ++i) {
+                p16[i]=block;
+            }
+        }
+
+        trie->data32=NULL;
+
+        /* Latin-1 data */
+        p16+=trie->indexLength;
+        for(i=0; i<latin1Length; ++i) {
+            p16[i]=(uint16_t)initialValue;
+        }
+
+        /* data for lead surrogate code units */
+        if(leadUnitValue!=initialValue) {
+            limit=latin1Length+UTRIE_DATA_BLOCK_LENGTH;
+            for(/* i=latin1Length */; i<limit; ++i) {
+                p16[i]=(uint16_t)leadUnitValue;
+            }
+        }
+    } else {
+        uint32_t *p32;
+
+        /* indexes to block 0 */
+        uprv_memset(p16, 0, trie->indexLength*2);
+
+        if(leadUnitValue!=initialValue) {
+            /* indexes for lead surrogate code units to the block after Latin-1 */
+            block=(uint16_t)(latin1Length>>UTRIE_INDEX_SHIFT);
+            i=0xd800>>UTRIE_SHIFT;
+            limit=0xdc00>>UTRIE_SHIFT;
+            for(; i<limit; ++i) {
+                p16[i]=block;
+            }
+        }
+
+        trie->data32=p32=(uint32_t *)(p16+trie->indexLength);
+
+        /* Latin-1 data */
+        for(i=0; i<latin1Length; ++i) {
+            p32[i]=initialValue;
+        }
+
+        /* data for lead surrogate code units */
+        if(leadUnitValue!=initialValue) {
+            limit=latin1Length+UTRIE_DATA_BLOCK_LENGTH;
+            for(/* i=latin1Length */; i<limit; ++i) {
+                p32[i]=leadUnitValue;
+            }
+        }
+    }
+
+    trie->getFoldingOffset=utrie_defaultGetFoldingOffset;
+
+    return actualLength;
+}
+
+/* enumeration -------------------------------------------------------------- */
+
+/* default UTrieEnumValue() returns the input value itself */
+static uint32_t U_CALLCONV
+enumSameValue(const void *context, uint32_t value) {
+    return value;
+}
+
+/**
+ * Enumerate all ranges of code points with the same relevant values.
+ * The values are transformed from the raw trie entries by the enumValue function.
+ */
+U_CAPI void U_EXPORT2
+utrie_enum(const UTrie *trie,
+           UTrieEnumValue *enumValue, UTrieEnumRange *enumRange, const void *context) {
+    const uint32_t *data32;
+    const uint16_t *idx;
+
+    uint32_t value, prevValue, initialValue;
+    UChar32 c, prev;
+    int32_t l, i, j, block, prevBlock, nullBlock, offset;
+
+    /* check arguments */
+    if(trie==NULL || trie->index==NULL || enumRange==NULL) {
+        return;
+    }
+    if(enumValue==NULL) {
+        enumValue=enumSameValue;
+    }
+
+    idx=trie->index;
+    data32=trie->data32;
+
+    /* get the enumeration value that corresponds to an initial-value trie data entry */
+    initialValue=enumValue(context, trie->initialValue);
+
+    if(data32==NULL) {
+        nullBlock=trie->indexLength;
+    } else {
+        nullBlock=0;
+    }
+
+    /* set variables for previous range */
+    prevBlock=nullBlock;
+    prev=0;
+    prevValue=initialValue;
+
+    /* enumerate BMP - the main loop enumerates data blocks */
+    for(i=0, c=0; c<=0xffff; ++i) {
+        if(c==0xd800) {
+            /* skip lead surrogate code _units_, go to lead surr. code _points_ */
+            i=UTRIE_BMP_INDEX_LENGTH;
+        } else if(c==0xdc00) {
+            /* go back to regular BMP code points */
+            i=c>>UTRIE_SHIFT;
+        }
+
+        block=idx[i]<<UTRIE_INDEX_SHIFT;
+        if(block==prevBlock) {
+            /* the block is the same as the previous one, and filled with value */
+            c+=UTRIE_DATA_BLOCK_LENGTH;
+        } else if(block==nullBlock) {
+            /* this is the all-initial-value block */
+            if(prevValue!=initialValue) {
+                if(prev<c) {
+                    if(!enumRange(context, prev, c, prevValue)) {
+                        return;
+                    }
+                }
+                prevBlock=nullBlock;
+                prev=c;
+                prevValue=initialValue;
+            }
+            c+=UTRIE_DATA_BLOCK_LENGTH;
+        } else {
+            prevBlock=block;
+            for(j=0; j<UTRIE_DATA_BLOCK_LENGTH; ++j) {
+                value=enumValue(context, data32!=NULL ? data32[block+j] : idx[block+j]);
+                if(value!=prevValue) {
+                    if(prev<c) {
+                        if(!enumRange(context, prev, c, prevValue)) {
+                            return;
+                        }
+                    }
+                    if(j>0) {
+                        /* the block is not filled with all the same value */
+                        prevBlock=-1;
+                    }
+                    prev=c;
+                    prevValue=value;
+                }
+                ++c;
+            }
+        }
+    }
+
+    /* enumerate supplementary code points */
+    for(l=0xd800; l<0xdc00;) {
+        /* lead surrogate access */
+        offset=idx[l>>UTRIE_SHIFT]<<UTRIE_INDEX_SHIFT;
+        if(offset==nullBlock) {
+            /* no entries for a whole block of lead surrogates */
+            if(prevValue!=initialValue) {
+                if(prev<c) {
+                    if(!enumRange(context, prev, c, prevValue)) {
+                        return;
+                    }
+                }
+                prevBlock=nullBlock;
+                prev=c;
+                prevValue=initialValue;
+            }
+
+            l+=UTRIE_DATA_BLOCK_LENGTH;
+            c+=UTRIE_DATA_BLOCK_LENGTH<<10;
+            continue;
+        }
+
+        value= data32!=NULL ? data32[offset+(l&UTRIE_MASK)] : idx[offset+(l&UTRIE_MASK)];
+
+        /* enumerate trail surrogates for this lead surrogate */
+        offset=trie->getFoldingOffset(value);
+        if(offset<=0) {
+            /* no data for this lead surrogate */
+            if(prevValue!=initialValue) {
+                if(prev<c) {
+                    if(!enumRange(context, prev, c, prevValue)) {
+                        return;
+                    }
+                }
+                prevBlock=nullBlock;
+                prev=c;
+                prevValue=initialValue;
+            }
+
+            /* nothing else to do for the supplementary code points for this lead surrogate */
+            c+=0x400;
+        } else {
+            /* enumerate code points for this lead surrogate */
+            i=offset;
+            offset+=UTRIE_SURROGATE_BLOCK_COUNT;
+            do {
+                /* copy of most of the body of the BMP loop */
+                block=idx[i]<<UTRIE_INDEX_SHIFT;
+                if(block==prevBlock) {
+                    /* the block is the same as the previous one, and filled with value */
+                    c+=UTRIE_DATA_BLOCK_LENGTH;
+                } else if(block==nullBlock) {
+                    /* this is the all-initial-value block */
+                    if(prevValue!=initialValue) {
+                        if(prev<c) {
+                            if(!enumRange(context, prev, c, prevValue)) {
+                                return;
+                            }
+                        }
+                        prevBlock=nullBlock;
+                        prev=c;
+                        prevValue=initialValue;
+                    }
+                    c+=UTRIE_DATA_BLOCK_LENGTH;
+                } else {
+                    prevBlock=block;
+                    for(j=0; j<UTRIE_DATA_BLOCK_LENGTH; ++j) {
+                        value=enumValue(context, data32!=NULL ? data32[block+j] : idx[block+j]);
+                        if(value!=prevValue) {
+                            if(prev<c) {
+                                if(!enumRange(context, prev, c, prevValue)) {
+                                    return;
+                                }
+                            }
+                            if(j>0) {
+                                /* the block is not filled with all the same value */
+                                prevBlock=-1;
+                            }
+                            prev=c;
+                            prevValue=value;
+                        }
+                        ++c;
+                    }
+                }
+            } while(++i<offset);
+        }
+
+        ++l;
+    }
+
+    /* deliver last range */
+    enumRange(context, prev, c, prevValue);
+}
diff --git a/source/common/utrie.h b/source/common/utrie.h
new file mode 100644
index 0000000..2a9dc0d
--- /dev/null
+++ b/source/common/utrie.h
@@ -0,0 +1,794 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2001-2008, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  utrie.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2001nov08
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __UTRIE_H__
+#define __UTRIE_H__
+
+#include "unicode/utypes.h"
+#include "udataswp.h"
+
+U_CDECL_BEGIN
+
+/**
+ * \file
+ *
+ * This is a common implementation of a "folded" trie.
+ * It is a kind of compressed, serializable table of 16- or 32-bit values associated with
+ * Unicode code points (0..0x10ffff).
+ *
+ * This implementation is optimized for getting values while walking forward
+ * through a UTF-16 string.
+ * Therefore, the simplest and fastest access macros are the
+ * _FROM_LEAD() and _FROM_OFFSET_TRAIL() macros.
+ *
+ * The _FROM_BMP() macros are a little more complicated; they get values
+ * even for lead surrogate code _points_, while the _FROM_LEAD() macros
+ * get special "folded" values for lead surrogate code _units_ if
+ * there is relevant data associated with them.
+ * From such a folded value, an offset needs to be extracted to supply
+ * to the _FROM_OFFSET_TRAIL() macros.
+ *
+ * Most of the more complex (and more convenient) functions/macros call a callback function
+ * to get that offset from the folded value for a lead surrogate unit.
+ */
+
+/**
+ * Trie constants, defining shift widths, index array lengths, etc.
+ */
+enum {
+    /** Shift size for shifting right the input index. 1..9 */
+    UTRIE_SHIFT=5,
+
+    /** Number of data values in a stage 2 (data array) block. 2, 4, 8, .., 0x200 */
+    UTRIE_DATA_BLOCK_LENGTH=1<<UTRIE_SHIFT,
+
+    /** Mask for getting the lower bits from the input index. */
+    UTRIE_MASK=UTRIE_DATA_BLOCK_LENGTH-1,
+
+    /**
+     * Lead surrogate code points' index displacement in the index array.
+     * 0x10000-0xd800=0x2800
+     */
+    UTRIE_LEAD_INDEX_DISP=0x2800>>UTRIE_SHIFT,
+
+    /**
+     * Shift size for shifting left the index array values.
+     * Increases possible data size with 16-bit index values at the cost
+     * of compactability.
+     * This requires blocks of stage 2 data to be aligned by UTRIE_DATA_GRANULARITY.
+     * 0..UTRIE_SHIFT
+     */
+    UTRIE_INDEX_SHIFT=2,
+
+    /** The alignment size of a stage 2 data block. Also the granularity for compaction. */
+    UTRIE_DATA_GRANULARITY=1<<UTRIE_INDEX_SHIFT,
+
+    /** Number of bits of a trail surrogate that are used in index table lookups. */
+    UTRIE_SURROGATE_BLOCK_BITS=10-UTRIE_SHIFT,
+
+    /**
+     * Number of index (stage 1) entries per lead surrogate.
+     * Same as number of index entries for 1024 trail surrogates,
+     * ==0x400>>UTRIE_SHIFT
+     */
+    UTRIE_SURROGATE_BLOCK_COUNT=(1<<UTRIE_SURROGATE_BLOCK_BITS),
+
+    /** Length of the BMP portion of the index (stage 1) array. */
+    UTRIE_BMP_INDEX_LENGTH=0x10000>>UTRIE_SHIFT
+};
+
+/**
+ * Length of the index (stage 1) array before folding.
+ * Maximum number of Unicode code points (0x110000) shifted right by UTRIE_SHIFT.
+ */
+#define UTRIE_MAX_INDEX_LENGTH (0x110000>>UTRIE_SHIFT)
+
+/**
+ * Maximum length of the runtime data (stage 2) array.
+ * Limited by 16-bit index values that are left-shifted by UTRIE_INDEX_SHIFT.
+ */
+#define UTRIE_MAX_DATA_LENGTH (0x10000<<UTRIE_INDEX_SHIFT)
+
+/**
+ * Maximum length of the build-time data (stage 2) array.
+ * The maximum length is 0x110000+UTRIE_DATA_BLOCK_LENGTH+0x400.
+ * (Number of Unicode code points + one all-initial-value block +
+ *  possible duplicate entries for 1024 lead surrogates.)
+ */
+#define UTRIE_MAX_BUILD_TIME_DATA_LENGTH (0x110000+UTRIE_DATA_BLOCK_LENGTH+0x400)
+
+/**
+ * Number of bytes for a dummy trie.
+ * A dummy trie is an empty runtime trie, used when a real data trie cannot
+ * be loaded.
+ * The number of bytes works for Latin-1-linear tries with 32-bit data
+ * (worst case).
+ *
+ * Calculation:
+ *   BMP index + 1 index block for lead surrogate code points +
+ *   Latin-1-linear array + 1 data block for lead surrogate code points
+ *
+ * Latin-1: if(UTRIE_SHIFT<=8) { 256 } else { included in first data block }
+ *
+ * @see utrie_unserializeDummy
+ */
+#define UTRIE_DUMMY_SIZE ((UTRIE_BMP_INDEX_LENGTH+UTRIE_SURROGATE_BLOCK_COUNT)*2+(UTRIE_SHIFT<=8?256:UTRIE_DATA_BLOCK_LENGTH)*4+UTRIE_DATA_BLOCK_LENGTH*4)
+
+/**
+ * Runtime UTrie callback function.
+ * Extract from a lead surrogate's data the
+ * index array offset of the indexes for that lead surrogate.
+ *
+ * @param data data value for a surrogate from the trie, including the folding offset
+ * @return offset>=UTRIE_BMP_INDEX_LENGTH, or 0 if there is no data for the lead surrogate
+ */
+typedef int32_t U_CALLCONV
+UTrieGetFoldingOffset(uint32_t data);
+
+/**
+ * Run-time Trie structure.
+ *
+ * Either the data table is 16 bits wide and accessed via the index
+ * pointer, with each index item increased by indexLength;
+ * in this case, data32==NULL.
+ *
+ * Or the data table is 32 bits wide and accessed via the data32 pointer.
+ */
+struct UTrie {
+    const uint16_t *index;
+    const uint32_t *data32; /* NULL if 16b data is used via index */
+
+    /**
+     * This function is not used in _FROM_LEAD, _FROM_BMP, and _FROM_OFFSET_TRAIL macros.
+     * If convenience macros like _GET16 or _NEXT32 are used, this function must be set.
+     *
+     * utrie_unserialize() sets a default function which simply returns
+     * the lead surrogate's value itself - which is the inverse of the default
+     * folding function used by utrie_serialize().
+     *
+     * @see UTrieGetFoldingOffset
+     */
+    UTrieGetFoldingOffset *getFoldingOffset;
+
+    int32_t indexLength, dataLength;
+    uint32_t initialValue;
+    UBool isLatin1Linear;
+};
+
+#ifndef __UTRIE2_H__
+typedef struct UTrie UTrie;
+#endif
+
+/** Internal trie getter from an offset (0 if c16 is a BMP/lead units) and a 16-bit unit */
+#define _UTRIE_GET_RAW(trie, data, offset, c16) \
+    (trie)->data[ \
+        ((int32_t)((trie)->index[(offset)+((c16)>>UTRIE_SHIFT)])<<UTRIE_INDEX_SHIFT)+ \
+        ((c16)&UTRIE_MASK) \
+    ]
+
+/** Internal trie getter from a pair of surrogates */
+#define _UTRIE_GET_FROM_PAIR(trie, data, c, c2, result, resultType) { \
+    int32_t __offset; \
+\
+    /* get data for lead surrogate */ \
+    (result)=_UTRIE_GET_RAW((trie), data, 0, (c)); \
+    __offset=(trie)->getFoldingOffset(result); \
+\
+    /* get the real data from the folded lead/trail units */ \
+    if(__offset>0) { \
+        (result)=_UTRIE_GET_RAW((trie), data, __offset, (c2)&0x3ff); \
+    } else { \
+        (result)=(resultType)((trie)->initialValue); \
+    } \
+}
+
+/** Internal trie getter from a BMP code point, treating a lead surrogate as a normal code point */
+#define _UTRIE_GET_FROM_BMP(trie, data, c16) \
+    _UTRIE_GET_RAW(trie, data, 0xd800<=(c16) && (c16)<=0xdbff ? UTRIE_LEAD_INDEX_DISP : 0, c16);
+
+/**
+ * Internal trie getter from a code point.
+ * Could be faster(?) but longer with
+ *   if((c32)<=0xd7ff) { (result)=_UTRIE_GET_RAW(trie, data, 0, c32); }
+ */
+#define _UTRIE_GET(trie, data, c32, result, resultType) \
+    if((uint32_t)(c32)<=0xffff) { \
+        /* BMP code points */ \
+        (result)=_UTRIE_GET_FROM_BMP(trie, data, c32); \
+    } else if((uint32_t)(c32)<=0x10ffff) { \
+        /* supplementary code point */ \
+        UChar __lead16=UTF16_LEAD(c32); \
+        _UTRIE_GET_FROM_PAIR(trie, data, __lead16, c32, result, resultType); \
+    } else { \
+        /* out of range */ \
+        (result)=(resultType)((trie)->initialValue); \
+    }
+
+/** Internal next-post-increment: get the next code point (c, c2) and its data */
+#define _UTRIE_NEXT(trie, data, src, limit, c, c2, result, resultType) { \
+    (c)=*(src)++; \
+    if(!UTF_IS_LEAD(c)) { \
+        (c2)=0; \
+        (result)=_UTRIE_GET_RAW((trie), data, 0, (c)); \
+    } else if((src)!=(limit) && UTF_IS_TRAIL((c2)=*(src))) { \
+        ++(src); \
+        _UTRIE_GET_FROM_PAIR((trie), data, (c), (c2), (result), resultType); \
+    } else { \
+        /* unpaired lead surrogate code point */ \
+        (c2)=0; \
+        (result)=_UTRIE_GET_RAW((trie), data, UTRIE_LEAD_INDEX_DISP, (c)); \
+    } \
+}
+
+/** Internal previous: get the previous code point (c, c2) and its data */
+#define _UTRIE_PREVIOUS(trie, data, start, src, c, c2, result, resultType) { \
+    (c)=*--(src); \
+    if(!UTF_IS_SURROGATE(c)) { \
+        (c2)=0; \
+        (result)=_UTRIE_GET_RAW((trie), data, 0, (c)); \
+    } else if(!UTF_IS_SURROGATE_FIRST(c)) { \
+        /* trail surrogate */ \
+        if((start)!=(src) && UTF_IS_LEAD((c2)=*((src)-1))) { \
+            --(src); \
+            (result)=(c); (c)=(c2); (c2)=(UChar)(result); /* swap c, c2 */ \
+            _UTRIE_GET_FROM_PAIR((trie), data, (c), (c2), (result), resultType); \
+        } else { \
+            /* unpaired trail surrogate code point */ \
+            (c2)=0; \
+            (result)=_UTRIE_GET_RAW((trie), data, 0, (c)); \
+        } \
+    } else { \
+        /* unpaired lead surrogate code point */ \
+        (c2)=0; \
+        (result)=_UTRIE_GET_RAW((trie), data, UTRIE_LEAD_INDEX_DISP, (c)); \
+    } \
+}
+
+/* Public UTrie API ---------------------------------------------------------*/
+
+/**
+ * Get a pointer to the contiguous part of the data array
+ * for the Latin-1 range (U+0000..U+00ff).
+ * Must be used only if the Latin-1 range is in fact linear
+ * (trie->isLatin1Linear).
+ *
+ * @param trie (const UTrie *, in) a pointer to the runtime trie structure
+ * @return (const uint16_t *) pointer to values for Latin-1 code points
+ */
+#define UTRIE_GET16_LATIN1(trie) ((trie)->index+(trie)->indexLength+UTRIE_DATA_BLOCK_LENGTH)
+
+/**
+ * Get a pointer to the contiguous part of the data array
+ * for the Latin-1 range (U+0000..U+00ff).
+ * Must be used only if the Latin-1 range is in fact linear
+ * (trie->isLatin1Linear).
+ *
+ * @param trie (const UTrie *, in) a pointer to the runtime trie structure
+ * @return (const uint32_t *) pointer to values for Latin-1 code points
+ */
+#define UTRIE_GET32_LATIN1(trie) ((trie)->data32+UTRIE_DATA_BLOCK_LENGTH)
+
+/**
+ * Get a 16-bit trie value from a BMP code point (UChar, <=U+ffff).
+ * c16 may be a lead surrogate, which may have a value including a folding offset.
+ *
+ * @param trie (const UTrie *, in) a pointer to the runtime trie structure
+ * @param c16 (UChar, in) the input BMP code point
+ * @return (uint16_t) trie lookup result
+ */
+#define UTRIE_GET16_FROM_LEAD(trie, c16) _UTRIE_GET_RAW(trie, index, 0, c16)
+
+/**
+ * Get a 32-bit trie value from a BMP code point (UChar, <=U+ffff).
+ * c16 may be a lead surrogate, which may have a value including a folding offset.
+ *
+ * @param trie (const UTrie *, in) a pointer to the runtime trie structure
+ * @param c16 (UChar, in) the input BMP code point
+ * @return (uint32_t) trie lookup result
+ */
+#define UTRIE_GET32_FROM_LEAD(trie, c16) _UTRIE_GET_RAW(trie, data32, 0, c16)
+
+/**
+ * Get a 16-bit trie value from a BMP code point (UChar, <=U+ffff).
+ * Even lead surrogate code points are treated as normal code points,
+ * with unfolded values that may differ from _FROM_LEAD() macro results for them.
+ *
+ * @param trie (const UTrie *, in) a pointer to the runtime trie structure
+ * @param c16 (UChar, in) the input BMP code point
+ * @return (uint16_t) trie lookup result
+ */
+#define UTRIE_GET16_FROM_BMP(trie, c16) _UTRIE_GET_FROM_BMP(trie, index, c16)
+
+/**
+ * Get a 32-bit trie value from a BMP code point (UChar, <=U+ffff).
+ * Even lead surrogate code points are treated as normal code points,
+ * with unfolded values that may differ from _FROM_LEAD() macro results for them.
+ *
+ * @param trie (const UTrie *, in) a pointer to the runtime trie structure
+ * @param c16 (UChar, in) the input BMP code point
+ * @return (uint32_t) trie lookup result
+ */
+#define UTRIE_GET32_FROM_BMP(trie, c16) _UTRIE_GET_FROM_BMP(trie, data32, c16)
+
+/**
+ * Get a 16-bit trie value from a code point.
+ * Even lead surrogate code points are treated as normal code points,
+ * with unfolded values that may differ from _FROM_LEAD() macro results for them.
+ *
+ * @param trie (const UTrie *, in) a pointer to the runtime trie structure
+ * @param c32 (UChar32, in) the input code point
+ * @param result (uint16_t, out) uint16_t variable for the trie lookup result
+ */
+#define UTRIE_GET16(trie, c32, result) _UTRIE_GET(trie, index, c32, result, uint16_t)
+
+/**
+ * Get a 32-bit trie value from a code point.
+ * Even lead surrogate code points are treated as normal code points,
+ * with unfolded values that may differ from _FROM_LEAD() macro results for them.
+ *
+ * @param trie (const UTrie *, in) a pointer to the runtime trie structure
+ * @param c32 (UChar32, in) the input code point
+ * @param result (uint32_t, out) uint32_t variable for the trie lookup result
+ */
+#define UTRIE_GET32(trie, c32, result) _UTRIE_GET(trie, data32, c32, result, uint32_t)
+
+/**
+ * Get the next code point (c, c2), post-increment src,
+ * and get a 16-bit value from the trie.
+ *
+ * @param trie (const UTrie *, in) a pointer to the runtime trie structure
+ * @param src (const UChar *, in/out) the source text pointer
+ * @param limit (const UChar *, in) the limit pointer for the text, or NULL
+ * @param c (UChar, out) variable for the BMP or lead code unit
+ * @param c2 (UChar, out) variable for 0 or the trail code unit
+ * @param result (uint16_t, out) uint16_t variable for the trie lookup result
+ */
+#define UTRIE_NEXT16(trie, src, limit, c, c2, result) _UTRIE_NEXT(trie, index, src, limit, c, c2, result, uint16_t)
+
+/**
+ * Get the next code point (c, c2), post-increment src,
+ * and get a 32-bit value from the trie.
+ *
+ * @param trie (const UTrie *, in) a pointer to the runtime trie structure
+ * @param src (const UChar *, in/out) the source text pointer
+ * @param limit (const UChar *, in) the limit pointer for the text, or NULL
+ * @param c (UChar, out) variable for the BMP or lead code unit
+ * @param c2 (UChar, out) variable for 0 or the trail code unit
+ * @param result (uint32_t, out) uint32_t variable for the trie lookup result
+ */
+#define UTRIE_NEXT32(trie, src, limit, c, c2, result) _UTRIE_NEXT(trie, data32, src, limit, c, c2, result, uint32_t)
+
+/**
+ * Get the previous code point (c, c2), pre-decrement src,
+ * and get a 16-bit value from the trie.
+ *
+ * @param trie (const UTrie *, in) a pointer to the runtime trie structure
+ * @param start (const UChar *, in) the start pointer for the text, or NULL
+ * @param src (const UChar *, in/out) the source text pointer
+ * @param c (UChar, out) variable for the BMP or lead code unit
+ * @param c2 (UChar, out) variable for 0 or the trail code unit
+ * @param result (uint16_t, out) uint16_t variable for the trie lookup result
+ */
+#define UTRIE_PREVIOUS16(trie, start, src, c, c2, result) _UTRIE_PREVIOUS(trie, index, start, src, c, c2, result, uint16_t)
+
+/**
+ * Get the previous code point (c, c2), pre-decrement src,
+ * and get a 32-bit value from the trie.
+ *
+ * @param trie (const UTrie *, in) a pointer to the runtime trie structure
+ * @param start (const UChar *, in) the start pointer for the text, or NULL
+ * @param src (const UChar *, in/out) the source text pointer
+ * @param c (UChar, out) variable for the BMP or lead code unit
+ * @param c2 (UChar, out) variable for 0 or the trail code unit
+ * @param result (uint32_t, out) uint32_t variable for the trie lookup result
+ */
+#define UTRIE_PREVIOUS32(trie, start, src, c, c2, result) _UTRIE_PREVIOUS(trie, data32, start, src, c, c2, result, uint32_t)
+
+/**
+ * Get a 16-bit trie value from a pair of surrogates.
+ *
+ * @param trie (const UTrie *, in) a pointer to the runtime trie structure
+ * @param c (UChar, in) a lead surrogate
+ * @param c2 (UChar, in) a trail surrogate
+ * @param result (uint16_t, out) uint16_t variable for the trie lookup result
+ */
+#define UTRIE_GET16_FROM_PAIR(trie, c, c2, result) _UTRIE_GET_FROM_PAIR(trie, index, c, c2, result, uint16_t)
+
+/**
+ * Get a 32-bit trie value from a pair of surrogates.
+ *
+ * @param trie (const UTrie *, in) a pointer to the runtime trie structure
+ * @param c (UChar, in) a lead surrogate
+ * @param c2 (UChar, in) a trail surrogate
+ * @param result (uint32_t, out) uint32_t variable for the trie lookup result
+ */
+#define UTRIE_GET32_FROM_PAIR(trie, c, c2, result) _UTRIE_GET_FROM_PAIR(trie, data32, c, c2, result, uint32_t)
+
+/**
+ * Get a 16-bit trie value from a folding offset (from the value of a lead surrogate)
+ * and a trail surrogate.
+ *
+ * @param trie (const UTrie *, in) a pointer to the runtime trie structure
+ * @param offset (int32_t, in) the folding offset from the value of a lead surrogate
+ * @param c2 (UChar, in) a trail surrogate (only the 10 low bits are significant)
+ * @return (uint16_t) trie lookup result
+ */
+#define UTRIE_GET16_FROM_OFFSET_TRAIL(trie, offset, c2) _UTRIE_GET_RAW(trie, index, offset, (c2)&0x3ff)
+
+/**
+ * Get a 32-bit trie value from a folding offset (from the value of a lead surrogate)
+ * and a trail surrogate.
+ *
+ * @param trie (const UTrie *, in) a pointer to the runtime trie structure
+ * @param offset (int32_t, in) the folding offset from the value of a lead surrogate
+ * @param c2 (UChar, in) a trail surrogate (only the 10 low bits are significant)
+ * @return (uint32_t) trie lookup result
+ */
+#define UTRIE_GET32_FROM_OFFSET_TRAIL(trie, offset, c2) _UTRIE_GET_RAW(trie, data32, offset, (c2)&0x3ff)
+
+/* enumeration callback types */
+
+/**
+ * Callback from utrie_enum(), extracts a uint32_t value from a
+ * trie value. This value will be passed on to the UTrieEnumRange function.
+ *
+ * @param context an opaque pointer, as passed into utrie_enum()
+ * @param value a value from the trie
+ * @return the value that is to be passed on to the UTrieEnumRange function
+ */
+typedef uint32_t U_CALLCONV
+UTrieEnumValue(const void *context, uint32_t value);
+
+/**
+ * Callback from utrie_enum(), is called for each contiguous range
+ * of code points with the same value as retrieved from the trie and
+ * transformed by the UTrieEnumValue function.
+ *
+ * The callback function can stop the enumeration by returning FALSE.
+ *
+ * @param context an opaque pointer, as passed into utrie_enum()
+ * @param start the first code point in a contiguous range with value
+ * @param limit one past the last code point in a contiguous range with value
+ * @param value the value that is set for all code points in [start..limit[
+ * @return FALSE to stop the enumeration
+ */
+typedef UBool U_CALLCONV
+UTrieEnumRange(const void *context, UChar32 start, UChar32 limit, uint32_t value);
+
+/**
+ * Enumerate efficiently all values in a trie.
+ * For each entry in the trie, the value to be delivered is passed through
+ * the UTrieEnumValue function.
+ * The value is unchanged if that function pointer is NULL.
+ *
+ * For each contiguous range of code points with a given value,
+ * the UTrieEnumRange function is called.
+ *
+ * @param trie a pointer to the runtime trie structure
+ * @param enumValue a pointer to a function that may transform the trie entry value,
+ *                  or NULL if the values from the trie are to be used directly
+ * @param enumRange a pointer to a function that is called for each contiguous range
+ *                  of code points with the same value
+ * @param context an opaque pointer that is passed on to the callback functions
+ */
+U_CAPI void U_EXPORT2
+utrie_enum(const UTrie *trie,
+           UTrieEnumValue *enumValue, UTrieEnumRange *enumRange, const void *context);
+
+/**
+ * Unserialize a trie from 32-bit-aligned memory.
+ * Inverse of utrie_serialize().
+ * Fills the UTrie runtime trie structure with the settings for the trie data.
+ *
+ * @param trie a pointer to the runtime trie structure
+ * @param data a pointer to 32-bit-aligned memory containing trie data
+ * @param length the number of bytes available at data
+ * @param pErrorCode an in/out ICU UErrorCode
+ * @return the number of bytes at data taken up by the trie data
+ */
+U_CAPI int32_t U_EXPORT2
+utrie_unserialize(UTrie *trie, const void *data, int32_t length, UErrorCode *pErrorCode);
+
+/**
+ * "Unserialize" a dummy trie.
+ * A dummy trie is an empty runtime trie, used when a real data trie cannot
+ * be loaded.
+ *
+ * The input memory is filled so that the trie always returns the initialValue,
+ * or the leadUnitValue for lead surrogate code points.
+ * The Latin-1 part is always set up to be linear.
+ *
+ * @param trie a pointer to the runtime trie structure
+ * @param data a pointer to 32-bit-aligned memory to be filled with the dummy trie data
+ * @param length the number of bytes available at data (recommended to use UTRIE_DUMMY_SIZE)
+ * @param initialValue the initial value that is set for all code points
+ * @param leadUnitValue the value for lead surrogate code _units_ that do not
+ *                      have associated supplementary data
+ * @param pErrorCode an in/out ICU UErrorCode
+ *
+ * @see UTRIE_DUMMY_SIZE
+ * @see utrie_open
+ */
+U_CAPI int32_t U_EXPORT2
+utrie_unserializeDummy(UTrie *trie,
+                       void *data, int32_t length,
+                       uint32_t initialValue, uint32_t leadUnitValue,
+                       UBool make16BitTrie,
+                       UErrorCode *pErrorCode);
+
+/**
+ * Default implementation for UTrie.getFoldingOffset, set automatically by
+ * utrie_unserialize().
+ * Simply returns the lead surrogate's value itself - which is the inverse
+ * of the default folding function used by utrie_serialize().
+ * Exported for static const UTrie structures.
+ *
+ * @see UTrieGetFoldingOffset
+ */
+U_CAPI int32_t U_EXPORT2
+utrie_defaultGetFoldingOffset(uint32_t data);
+
+/* Building a trie ----------------------------------------------------------*/
+
+/**
+ * Build-time trie structure.
+ * Opaque definition, here only to make fillIn parameters possible
+ * for utrie_open() and utrie_clone().
+ */
+struct UNewTrie {
+    /**
+     * Index values at build-time are 32 bits wide for easier processing.
+     * Bit 31 is set if the data block is used by multiple index values (from utrie_setRange()).
+     */
+    int32_t index[UTRIE_MAX_INDEX_LENGTH];
+    uint32_t *data;
+
+    uint32_t leadUnitValue;
+    int32_t indexLength, dataCapacity, dataLength;
+    UBool isAllocated, isDataAllocated;
+    UBool isLatin1Linear, isCompacted;
+
+    /**
+     * Map of adjusted indexes, used in utrie_compact().
+     * Maps from original indexes to new ones.
+     */
+    int32_t map[UTRIE_MAX_BUILD_TIME_DATA_LENGTH>>UTRIE_SHIFT];
+};
+
+typedef struct UNewTrie UNewTrie;
+
+/**
+ * Build-time trie callback function, used with utrie_serialize().
+ * This function calculates a lead surrogate's value including a folding offset
+ * from the 1024 supplementary code points [start..start+1024[ .
+ * It is U+10000 <= start <= U+10fc00 and (start&0x3ff)==0.
+ *
+ * The folding offset is provided by the caller.
+ * It is offset=UTRIE_BMP_INDEX_LENGTH+n*UTRIE_SURROGATE_BLOCK_COUNT with n=0..1023.
+ * Instead of the offset itself, n can be stored in 10 bits -
+ * or fewer if it can be assumed that few lead surrogates have associated data.
+ *
+ * The returned value must be
+ * - not zero if and only if there is relevant data
+ *   for the corresponding 1024 supplementary code points
+ * - such that UTrie.getFoldingOffset(UNewTrieGetFoldedValue(..., offset))==offset
+ *
+ * @return a folded value, or 0 if there is no relevant data for the lead surrogate.
+ */
+typedef uint32_t U_CALLCONV
+UNewTrieGetFoldedValue(UNewTrie *trie, UChar32 start, int32_t offset);
+
+/**
+ * Open a build-time trie structure.
+ * The size of the build-time data array is specified to avoid allocating a large
+ * array in all cases. The array itself can also be passed in.
+ *
+ * Although the trie is never fully expanded to a linear array, especially when
+ * utrie_setRange32() is used, the data array could be large during build time.
+ * The maximum length is
+ * UTRIE_MAX_BUILD_TIME_DATA_LENGTH=0x110000+UTRIE_DATA_BLOCK_LENGTH+0x400.
+ * (Number of Unicode code points + one all-initial-value block +
+ *  possible duplicate entries for 1024 lead surrogates.)
+ * (UTRIE_DATA_BLOCK_LENGTH<=0x200 in all cases.)
+ *
+ * @param fillIn a pointer to a UNewTrie structure to be initialized (will not be released), or
+ *               NULL if one is to be allocated
+ * @param aliasData a pointer to a data array to be used (will not be released), or
+ *                  NULL if one is to be allocated
+ * @param maxDataLength the capacity of aliasData (if not NULL) or
+ *                      the length of the data array to be allocated
+ * @param initialValue the initial value that is set for all code points
+ * @param leadUnitValue the value for lead surrogate code _units_ that do not
+ *                      have associated supplementary data
+ * @param latin1Linear a flag indicating whether the Latin-1 range is to be allocated and
+ *                     kept in a linear, contiguous part of the data array
+ * @return a pointer to the initialized fillIn or the allocated and initialized new UNewTrie
+ */
+U_CAPI UNewTrie * U_EXPORT2
+utrie_open(UNewTrie *fillIn,
+           uint32_t *aliasData, int32_t maxDataLength,
+           uint32_t initialValue, uint32_t leadUnitValue,
+           UBool latin1Linear);
+
+/**
+ * Clone a build-time trie structure with all entries.
+ *
+ * @param fillIn like in utrie_open()
+ * @param other the build-time trie structure to clone
+ * @param aliasData like in utrie_open(),
+ *                  used if aliasDataLength>=(capacity of other's data array)
+ * @param aliasDataLength the length of aliasData
+ * @return a pointer to the initialized fillIn or the allocated and initialized new UNewTrie
+ */
+U_CAPI UNewTrie * U_EXPORT2
+utrie_clone(UNewTrie *fillIn, const UNewTrie *other, uint32_t *aliasData, int32_t aliasDataLength);
+
+/**
+ * Close a build-time trie structure, and release memory
+ * that was allocated by utrie_open() or utrie_clone().
+ *
+ * @param trie the build-time trie
+ */
+U_CAPI void U_EXPORT2
+utrie_close(UNewTrie *trie);
+
+/**
+ * Get the data array of a build-time trie.
+ * The data may be modified, but entries that are equal before
+ * must still be equal after modification.
+ *
+ * @param trie the build-time trie
+ * @param pLength (out) a pointer to a variable that receives the number
+ *                of entries in the data array
+ * @return the data array
+ */
+U_CAPI uint32_t * U_EXPORT2
+utrie_getData(UNewTrie *trie, int32_t *pLength);
+
+/**
+ * Set a value for a code point.
+ *
+ * @param trie the build-time trie
+ * @param c the code point
+ * @param value the value
+ * @return FALSE if a failure occurred (illegal argument or data array overrun)
+ */
+U_CAPI UBool U_EXPORT2
+utrie_set32(UNewTrie *trie, UChar32 c, uint32_t value);
+
+/**
+ * Get a value from a code point as stored in the build-time trie.
+ *
+ * @param trie the build-time trie
+ * @param c the code point
+ * @param pInBlockZero if not NULL, then *pInBlockZero is set to TRUE
+ *                     iff the value is retrieved from block 0;
+ *                     block 0 is the all-initial-value initial block
+ * @return the value
+ */
+U_CAPI uint32_t U_EXPORT2
+utrie_get32(UNewTrie *trie, UChar32 c, UBool *pInBlockZero);
+
+/**
+ * Set a value in a range of code points [start..limit[.
+ * All code points c with start<=c<limit will get the value if
+ * overwrite is TRUE or if the old value is 0.
+ *
+ * @param trie the build-time trie
+ * @param start the first code point to get the value
+ * @param limit one past the last code point to get the value
+ * @param value the value
+ * @param overwrite flag for whether old non-initial values are to be overwritten
+ * @return FALSE if a failure occurred (illegal argument or data array overrun)
+ */
+U_CAPI UBool U_EXPORT2
+utrie_setRange32(UNewTrie *trie, UChar32 start, UChar32 limit, uint32_t value, UBool overwrite);
+
+/**
+ * Compact the build-time trie after all values are set, and then
+ * serialize it into 32-bit aligned memory.
+ *
+ * After this, the trie can only be serizalized again and/or closed;
+ * no further values can be added.
+ *
+ * @see utrie_unserialize()
+ *
+ * @param trie the build-time trie
+ * @param data a pointer to 32-bit-aligned memory for the trie data
+ * @param capacity the number of bytes available at data
+ * @param getFoldedValue a callback function that calculates the value for
+ *                       a lead surrogate from all of its supplementary code points
+ *                       and the folding offset;
+ *                       if NULL, then a default function is used which returns just
+ *                       the input offset when there are any non-initial-value entries
+ * @param reduceTo16Bits flag for whether the values are to be reduced to a
+ *                       width of 16 bits for serialization and runtime
+ * @param pErrorCode a UErrorCode argument; among other possible error codes:
+ * - U_BUFFER_OVERFLOW_ERROR if the data storage block is too small for serialization
+ * - U_MEMORY_ALLOCATION_ERROR if the trie data array is too small
+ * - U_INDEX_OUTOFBOUNDS_ERROR if the index or data arrays are too long after compaction for serialization
+ *
+ * @return the number of bytes written for the trie
+ */
+U_CAPI int32_t U_EXPORT2
+utrie_serialize(UNewTrie *trie, void *data, int32_t capacity,
+                UNewTrieGetFoldedValue *getFoldedValue,
+                UBool reduceTo16Bits,
+                UErrorCode *pErrorCode);
+
+/**
+ * Swap a serialized UTrie.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+utrie_swap(const UDataSwapper *ds,
+           const void *inData, int32_t length, void *outData,
+           UErrorCode *pErrorCode);
+
+/* serialization ------------------------------------------------------------ */
+
+/**
+ * Trie data structure in serialized form:
+ *
+ * UTrieHeader header;
+ * uint16_t index[header.indexLength];
+ * uint16_t data[header.dataLength];
+ * @internal
+ */
+typedef struct UTrieHeader {
+    /** "Trie" in big-endian US-ASCII (0x54726965) */
+    uint32_t signature;
+
+    /**
+     * options bit field:
+     *     9    1=Latin-1 data is stored linearly at data+UTRIE_DATA_BLOCK_LENGTH
+     *     8    0=16-bit data, 1=32-bit data
+     *  7..4    UTRIE_INDEX_SHIFT   // 0..UTRIE_SHIFT
+     *  3..0    UTRIE_SHIFT         // 1..9
+     */
+    uint32_t options;
+
+    /** indexLength is a multiple of UTRIE_SURROGATE_BLOCK_COUNT */
+    int32_t indexLength;
+
+    /** dataLength>=UTRIE_DATA_BLOCK_LENGTH */
+    int32_t dataLength;
+} UTrieHeader;
+
+/**
+ * Constants for use with UTrieHeader.options.
+ * @internal
+ */
+enum {
+    /** Mask to get the UTRIE_SHIFT value from options. */
+    UTRIE_OPTIONS_SHIFT_MASK=0xf,
+
+    /** Shift options right this much to get the UTRIE_INDEX_SHIFT value. */
+    UTRIE_OPTIONS_INDEX_SHIFT=4,
+
+    /** If set, then the data (stage 2) array is 32 bits wide. */
+    UTRIE_OPTIONS_DATA_IS_32_BIT=0x100,
+
+    /**
+     * If set, then Latin-1 data (for U+0000..U+00ff) is stored in the data (stage 2) array
+     * as a simple, linear array at data+UTRIE_DATA_BLOCK_LENGTH.
+     */
+    UTRIE_OPTIONS_LATIN1_IS_LINEAR=0x200
+};
+
+U_CDECL_END
+
+#endif
diff --git a/source/common/utrie2.cpp b/source/common/utrie2.cpp
new file mode 100644
index 0000000..5567860
--- /dev/null
+++ b/source/common/utrie2.cpp
@@ -0,0 +1,738 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2001-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  utrie2.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2008aug16 (starting from a copy of utrie.c)
+*   created by: Markus W. Scherer
+*
+*   This is a common implementation of a Unicode trie.
+*   It is a kind of compressed, serializable table of 16- or 32-bit values associated with
+*   Unicode code points (0..0x10ffff).
+*   This is the second common version of a Unicode trie (hence the name UTrie2).
+*   See utrie2.h for a comparison.
+*
+*   This file contains only the runtime and enumeration code, for read-only access.
+*   See utrie2_builder.c for the builder code.
+*/
+#ifdef UTRIE2_DEBUG
+#   include <stdio.h>
+#endif
+
+#include "unicode/utypes.h"
+#include "cmemory.h"
+#include "utrie2.h"
+#include "utrie2_impl.h"
+
+/* Public UTrie2 API implementation ----------------------------------------- */
+
+static uint32_t
+get32(const UNewTrie2 *trie, UChar32 c, UBool fromLSCP) {
+    int32_t i2, block;
+
+    if(c>=trie->highStart && (!U_IS_LEAD(c) || fromLSCP)) {
+        return trie->data[trie->dataLength-UTRIE2_DATA_GRANULARITY];
+    }
+
+    if(U_IS_LEAD(c) && fromLSCP) {
+        i2=(UTRIE2_LSCP_INDEX_2_OFFSET-(0xd800>>UTRIE2_SHIFT_2))+
+            (c>>UTRIE2_SHIFT_2);
+    } else {
+        i2=trie->index1[c>>UTRIE2_SHIFT_1]+
+            ((c>>UTRIE2_SHIFT_2)&UTRIE2_INDEX_2_MASK);
+    }
+    block=trie->index2[i2];
+    return trie->data[block+(c&UTRIE2_DATA_MASK)];
+}
+
+U_CAPI uint32_t U_EXPORT2
+utrie2_get32(const UTrie2 *trie, UChar32 c) {
+    if(trie->data16!=NULL) {
+        return UTRIE2_GET16(trie, c);
+    } else if(trie->data32!=NULL) {
+        return UTRIE2_GET32(trie, c);
+    } else if((uint32_t)c>0x10ffff) {
+        return trie->errorValue;
+    } else {
+        return get32(trie->newTrie, c, TRUE);
+    }
+}
+
+U_CAPI uint32_t U_EXPORT2
+utrie2_get32FromLeadSurrogateCodeUnit(const UTrie2 *trie, UChar32 c) {
+    if(!U_IS_LEAD(c)) {
+        return trie->errorValue;
+    }
+    if(trie->data16!=NULL) {
+        return UTRIE2_GET16_FROM_U16_SINGLE_LEAD(trie, c);
+    } else if(trie->data32!=NULL) {
+        return UTRIE2_GET32_FROM_U16_SINGLE_LEAD(trie, c);
+    } else {
+        return get32(trie->newTrie, c, FALSE);
+    }
+}
+
+static U_INLINE int32_t
+u8Index(const UTrie2 *trie, UChar32 c, int32_t i) {
+    int32_t idx=
+        _UTRIE2_INDEX_FROM_CP(
+            trie,
+            trie->data32==NULL ? trie->indexLength : 0,
+            c);
+    return (idx<<3)|i;
+}
+
+U_CAPI int32_t U_EXPORT2
+utrie2_internalU8NextIndex(const UTrie2 *trie, UChar32 c,
+                           const uint8_t *src, const uint8_t *limit) {
+    int32_t i, length;
+    i=0;
+    /* support 64-bit pointers by avoiding cast of arbitrary difference */
+    if((limit-src)<=7) {
+        length=(int32_t)(limit-src);
+    } else {
+        length=7;
+    }
+    c=utf8_nextCharSafeBody(src, &i, length, c, -1);
+    return u8Index(trie, c, i);
+}
+
+U_CAPI int32_t U_EXPORT2
+utrie2_internalU8PrevIndex(const UTrie2 *trie, UChar32 c,
+                           const uint8_t *start, const uint8_t *src) {
+    int32_t i, length;
+    /* support 64-bit pointers by avoiding cast of arbitrary difference */
+    if((src-start)<=7) {
+        i=length=(int32_t)(src-start);
+    } else {
+        i=length=7;
+        start=src-7;
+    }
+    c=utf8_prevCharSafeBody(start, 0, &i, c, -1);
+    i=length-i;  /* number of bytes read backward from src */
+    return u8Index(trie, c, i);
+}
+
+U_CAPI UTrie2 * U_EXPORT2
+utrie2_openFromSerialized(UTrie2ValueBits valueBits,
+                          const void *data, int32_t length, int32_t *pActualLength,
+                          UErrorCode *pErrorCode) {
+    const UTrie2Header *header;
+    const uint16_t *p16;
+    int32_t actualLength;
+
+    UTrie2 tempTrie;
+    UTrie2 *trie;
+
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    if( length<=0 || (U_POINTER_MASK_LSB(data, 3)!=0) ||
+        valueBits<0 || UTRIE2_COUNT_VALUE_BITS<=valueBits
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* enough data for a trie header? */
+    if(length<(int32_t)sizeof(UTrie2Header)) {
+        *pErrorCode=U_INVALID_FORMAT_ERROR;
+        return 0;
+    }
+
+    /* check the signature */
+    header=(const UTrie2Header *)data;
+    if(header->signature!=UTRIE2_SIG) {
+        *pErrorCode=U_INVALID_FORMAT_ERROR;
+        return 0;
+    }
+
+    /* get the options */
+    if(valueBits!=(UTrie2ValueBits)(header->options&UTRIE2_OPTIONS_VALUE_BITS_MASK)) {
+        *pErrorCode=U_INVALID_FORMAT_ERROR;
+        return 0;
+    }
+
+    /* get the length values and offsets */
+    uprv_memset(&tempTrie, 0, sizeof(tempTrie));
+    tempTrie.indexLength=header->indexLength;
+    tempTrie.dataLength=header->shiftedDataLength<<UTRIE2_INDEX_SHIFT;
+    tempTrie.index2NullOffset=header->index2NullOffset;
+    tempTrie.dataNullOffset=header->dataNullOffset;
+
+    tempTrie.highStart=header->shiftedHighStart<<UTRIE2_SHIFT_1;
+    tempTrie.highValueIndex=tempTrie.dataLength-UTRIE2_DATA_GRANULARITY;
+    if(valueBits==UTRIE2_16_VALUE_BITS) {
+        tempTrie.highValueIndex+=tempTrie.indexLength;
+    }
+
+    /* calculate the actual length */
+    actualLength=(int32_t)sizeof(UTrie2Header)+tempTrie.indexLength*2;
+    if(valueBits==UTRIE2_16_VALUE_BITS) {
+        actualLength+=tempTrie.dataLength*2;
+    } else {
+        actualLength+=tempTrie.dataLength*4;
+    }
+    if(length<actualLength) {
+        *pErrorCode=U_INVALID_FORMAT_ERROR;  /* not enough bytes */
+        return 0;
+    }
+
+    /* allocate the trie */
+    trie=(UTrie2 *)uprv_malloc(sizeof(UTrie2));
+    if(trie==NULL) {
+        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
+    uprv_memcpy(trie, &tempTrie, sizeof(tempTrie));
+    trie->memory=(uint32_t *)data;
+    trie->length=actualLength;
+    trie->isMemoryOwned=FALSE;
+
+    /* set the pointers to its index and data arrays */
+    p16=(const uint16_t *)(header+1);
+    trie->index=p16;
+    p16+=trie->indexLength;
+
+    /* get the data */
+    switch(valueBits) {
+    case UTRIE2_16_VALUE_BITS:
+        trie->data16=p16;
+        trie->data32=NULL;
+        trie->initialValue=trie->index[trie->dataNullOffset];
+        trie->errorValue=trie->data16[UTRIE2_BAD_UTF8_DATA_OFFSET];
+        break;
+    case UTRIE2_32_VALUE_BITS:
+        trie->data16=NULL;
+        trie->data32=(const uint32_t *)p16;
+        trie->initialValue=trie->data32[trie->dataNullOffset];
+        trie->errorValue=trie->data32[UTRIE2_BAD_UTF8_DATA_OFFSET];
+        break;
+    default:
+        *pErrorCode=U_INVALID_FORMAT_ERROR;
+        return 0;
+    }
+
+    if(pActualLength!=NULL) {
+        *pActualLength=actualLength;
+    }
+    return trie;
+}
+
+U_CAPI UTrie2 * U_EXPORT2
+utrie2_openDummy(UTrie2ValueBits valueBits,
+                 uint32_t initialValue, uint32_t errorValue,
+                 UErrorCode *pErrorCode) {
+    UTrie2 *trie;
+    UTrie2Header *header;
+    uint32_t *p;
+    uint16_t *dest16;
+    int32_t indexLength, dataLength, length, i;
+    int32_t dataMove;  /* >0 if the data is moved to the end of the index array */
+
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    if(valueBits<0 || UTRIE2_COUNT_VALUE_BITS<=valueBits) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* calculate the total length of the dummy trie data */
+    indexLength=UTRIE2_INDEX_1_OFFSET;
+    dataLength=UTRIE2_DATA_START_OFFSET+UTRIE2_DATA_GRANULARITY;
+    length=(int32_t)sizeof(UTrie2Header)+indexLength*2;
+    if(valueBits==UTRIE2_16_VALUE_BITS) {
+        length+=dataLength*2;
+    } else {
+        length+=dataLength*4;
+    }
+
+    /* allocate the trie */
+    trie=(UTrie2 *)uprv_malloc(sizeof(UTrie2));
+    if(trie==NULL) {
+        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
+    uprv_memset(trie, 0, sizeof(UTrie2));
+    trie->memory=uprv_malloc(length);
+    if(trie->memory==NULL) {
+        uprv_free(trie);
+        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
+    trie->length=length;
+    trie->isMemoryOwned=TRUE;
+
+    /* set the UTrie2 fields */
+    if(valueBits==UTRIE2_16_VALUE_BITS) {
+        dataMove=indexLength;
+    } else {
+        dataMove=0;
+    }
+
+    trie->indexLength=indexLength;
+    trie->dataLength=dataLength;
+    trie->index2NullOffset=UTRIE2_INDEX_2_OFFSET;
+    trie->dataNullOffset=(uint16_t)dataMove;
+    trie->initialValue=initialValue;
+    trie->errorValue=errorValue;
+    trie->highStart=0;
+    trie->highValueIndex=dataMove+UTRIE2_DATA_START_OFFSET;
+
+    /* set the header fields */
+    header=(UTrie2Header *)trie->memory;
+
+    header->signature=UTRIE2_SIG; /* "Tri2" */
+    header->options=(uint16_t)valueBits;
+
+    header->indexLength=(uint16_t)indexLength;
+    header->shiftedDataLength=(uint16_t)(dataLength>>UTRIE2_INDEX_SHIFT);
+    header->index2NullOffset=(uint16_t)UTRIE2_INDEX_2_OFFSET;
+    header->dataNullOffset=(uint16_t)dataMove;
+    header->shiftedHighStart=0;
+
+    /* fill the index and data arrays */
+    dest16=(uint16_t *)(header+1);
+    trie->index=dest16;
+
+    /* write the index-2 array values shifted right by UTRIE2_INDEX_SHIFT */
+    for(i=0; i<UTRIE2_INDEX_2_BMP_LENGTH; ++i) {
+        *dest16++=(uint16_t)(dataMove>>UTRIE2_INDEX_SHIFT);  /* null data block */
+    }
+
+    /* write UTF-8 2-byte index-2 values, not right-shifted */
+    for(i=0; i<(0xc2-0xc0); ++i) {                                  /* C0..C1 */
+        *dest16++=(uint16_t)(dataMove+UTRIE2_BAD_UTF8_DATA_OFFSET);
+    }
+    for(; i<(0xe0-0xc0); ++i) {                                     /* C2..DF */
+        *dest16++=(uint16_t)dataMove;
+    }
+
+    /* write the 16/32-bit data array */
+    switch(valueBits) {
+    case UTRIE2_16_VALUE_BITS:
+        /* write 16-bit data values */
+        trie->data16=dest16;
+        trie->data32=NULL;
+        for(i=0; i<0x80; ++i) {
+            *dest16++=(uint16_t)initialValue;
+        }
+        for(; i<0xc0; ++i) {
+            *dest16++=(uint16_t)errorValue;
+        }
+        /* highValue and reserved values */
+        for(i=0; i<UTRIE2_DATA_GRANULARITY; ++i) {
+            *dest16++=(uint16_t)initialValue;
+        }
+        break;
+    case UTRIE2_32_VALUE_BITS:
+        /* write 32-bit data values */
+        p=(uint32_t *)dest16;
+        trie->data16=NULL;
+        trie->data32=p;
+        for(i=0; i<0x80; ++i) {
+            *p++=initialValue;
+        }
+        for(; i<0xc0; ++i) {
+            *p++=errorValue;
+        }
+        /* highValue and reserved values */
+        for(i=0; i<UTRIE2_DATA_GRANULARITY; ++i) {
+            *p++=initialValue;
+        }
+        break;
+    default:
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    return trie;
+}
+
+U_CAPI void U_EXPORT2
+utrie2_close(UTrie2 *trie) {
+    if(trie!=NULL) {
+        if(trie->isMemoryOwned) {
+            uprv_free(trie->memory);
+        }
+        if(trie->newTrie!=NULL) {
+            uprv_free(trie->newTrie->data);
+            uprv_free(trie->newTrie);
+        }
+        uprv_free(trie);
+    }
+}
+
+U_CAPI int32_t U_EXPORT2
+utrie2_getVersion(const void *data, int32_t length, UBool anyEndianOk) {
+    uint32_t signature;
+    if(length<16 || data==NULL || (U_POINTER_MASK_LSB(data, 3)!=0)) {
+        return 0;
+    }
+    signature=*(const uint32_t *)data;
+    if(signature==UTRIE2_SIG) {
+        return 2;
+    }
+    if(anyEndianOk && signature==UTRIE2_OE_SIG) {
+        return 2;
+    }
+    if(signature==UTRIE_SIG) {
+        return 1;
+    }
+    if(anyEndianOk && signature==UTRIE_OE_SIG) {
+        return 1;
+    }
+    return 0;
+}
+
+U_CAPI int32_t U_EXPORT2
+utrie2_swap(const UDataSwapper *ds,
+            const void *inData, int32_t length, void *outData,
+            UErrorCode *pErrorCode) {
+    const UTrie2Header *inTrie;
+    UTrie2Header trie;
+    int32_t dataLength, size;
+    UTrie2ValueBits valueBits;
+
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+    if(ds==NULL || inData==NULL || (length>=0 && outData==NULL)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    /* setup and swapping */
+    if(length>=0 && length<(int32_t)sizeof(UTrie2Header)) {
+        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0;
+    }
+
+    inTrie=(const UTrie2Header *)inData;
+    trie.signature=ds->readUInt32(inTrie->signature);
+    trie.options=ds->readUInt16(inTrie->options);
+    trie.indexLength=ds->readUInt16(inTrie->indexLength);
+    trie.shiftedDataLength=ds->readUInt16(inTrie->shiftedDataLength);
+
+    valueBits=(UTrie2ValueBits)(trie.options&UTRIE2_OPTIONS_VALUE_BITS_MASK);
+    dataLength=(int32_t)trie.shiftedDataLength<<UTRIE2_INDEX_SHIFT;
+
+    if( trie.signature!=UTRIE2_SIG ||
+        valueBits<0 || UTRIE2_COUNT_VALUE_BITS<=valueBits ||
+        trie.indexLength<UTRIE2_INDEX_1_OFFSET ||
+        dataLength<UTRIE2_DATA_START_OFFSET
+    ) {
+        *pErrorCode=U_INVALID_FORMAT_ERROR; /* not a UTrie */
+        return 0;
+    }
+
+    size=sizeof(UTrie2Header)+trie.indexLength*2;
+    switch(valueBits) {
+    case UTRIE2_16_VALUE_BITS:
+        size+=dataLength*2;
+        break;
+    case UTRIE2_32_VALUE_BITS:
+        size+=dataLength*4;
+        break;
+    default:
+        *pErrorCode=U_INVALID_FORMAT_ERROR;
+        return 0;
+    }
+
+    if(length>=0) {
+        UTrie2Header *outTrie;
+
+        if(length<size) {
+            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+            return 0;
+        }
+
+        outTrie=(UTrie2Header *)outData;
+
+        /* swap the header */
+        ds->swapArray32(ds, &inTrie->signature, 4, &outTrie->signature, pErrorCode);
+        ds->swapArray16(ds, &inTrie->options, 12, &outTrie->options, pErrorCode);
+
+        /* swap the index and the data */
+        switch(valueBits) {
+        case UTRIE2_16_VALUE_BITS:
+            ds->swapArray16(ds, inTrie+1, (trie.indexLength+dataLength)*2, outTrie+1, pErrorCode);
+            break;
+        case UTRIE2_32_VALUE_BITS:
+            ds->swapArray16(ds, inTrie+1, trie.indexLength*2, outTrie+1, pErrorCode);
+            ds->swapArray32(ds, (const uint16_t *)(inTrie+1)+trie.indexLength, dataLength*4,
+                                     (uint16_t *)(outTrie+1)+trie.indexLength, pErrorCode);
+            break;
+        default:
+            *pErrorCode=U_INVALID_FORMAT_ERROR;
+            return 0;
+        }
+    }
+
+    return size;
+}
+
+// utrie2_swapAnyVersion() should be defined here but lives in utrie2_builder.c
+// to avoid a dependency from utrie2.cpp on utrie.c.
+
+/* enumeration -------------------------------------------------------------- */
+
+#define MIN_VALUE(a, b) ((a)<(b) ? (a) : (b))
+
+/* default UTrie2EnumValue() returns the input value itself */
+static uint32_t U_CALLCONV
+enumSameValue(const void * /*context*/, uint32_t value) {
+    return value;
+}
+
+/**
+ * Enumerate all ranges of code points with the same relevant values.
+ * The values are transformed from the raw trie entries by the enumValue function.
+ *
+ * Currently requires start<limit and both start and limit must be multiples
+ * of UTRIE2_DATA_BLOCK_LENGTH.
+ *
+ * Optimizations:
+ * - Skip a whole block if we know that it is filled with a single value,
+ *   and it is the same as we visited just before.
+ * - Handle the null block specially because we know a priori that it is filled
+ *   with a single value.
+ */
+static void
+enumEitherTrie(const UTrie2 *trie,
+               UChar32 start, UChar32 limit,
+               UTrie2EnumValue *enumValue, UTrie2EnumRange *enumRange, const void *context) {
+    const uint32_t *data32;
+    const uint16_t *idx;
+
+    uint32_t value, prevValue, initialValue;
+    UChar32 c, prev, highStart;
+    int32_t j, i2Block, prevI2Block, index2NullOffset, block, prevBlock, nullBlock;
+
+    if(enumRange==NULL) {
+        return;
+    }
+    if(enumValue==NULL) {
+        enumValue=enumSameValue;
+    }
+
+    if(trie->newTrie==NULL) {
+        /* frozen trie */
+        idx=trie->index;
+        data32=trie->data32;
+
+        index2NullOffset=trie->index2NullOffset;
+        nullBlock=trie->dataNullOffset;
+    } else {
+        /* unfrozen, mutable trie */
+        idx=NULL;
+        data32=trie->newTrie->data;
+
+        index2NullOffset=trie->newTrie->index2NullOffset;
+        nullBlock=trie->newTrie->dataNullOffset;
+    }
+
+    highStart=trie->highStart;
+
+    /* get the enumeration value that corresponds to an initial-value trie data entry */
+    initialValue=enumValue(context, trie->initialValue);
+
+    /* set variables for previous range */
+    prevI2Block=-1;
+    prevBlock=-1;
+    prev=start;
+    prevValue=0;
+
+    /* enumerate index-2 blocks */
+    for(c=start; c<limit && c<highStart;) {
+        /* Code point limit for iterating inside this i2Block. */
+        UChar32 tempLimit=c+UTRIE2_CP_PER_INDEX_1_ENTRY;
+        if(limit<tempLimit) {
+            tempLimit=limit;
+        }
+        if(c<=0xffff) {
+            if(!U_IS_SURROGATE(c)) {
+                i2Block=c>>UTRIE2_SHIFT_2;
+            } else if(U_IS_SURROGATE_LEAD(c)) {
+                /*
+                 * Enumerate values for lead surrogate code points, not code units:
+                 * This special block has half the normal length.
+                 */
+                i2Block=UTRIE2_LSCP_INDEX_2_OFFSET;
+                tempLimit=MIN_VALUE(0xdc00, limit);
+            } else {
+                /*
+                 * Switch back to the normal part of the index-2 table.
+                 * Enumerate the second half of the surrogates block.
+                 */
+                i2Block=0xd800>>UTRIE2_SHIFT_2;
+                tempLimit=MIN_VALUE(0xe000, limit);
+            }
+        } else {
+            /* supplementary code points */
+            if(idx!=NULL) {
+                i2Block=idx[(UTRIE2_INDEX_1_OFFSET-UTRIE2_OMITTED_BMP_INDEX_1_LENGTH)+
+                              (c>>UTRIE2_SHIFT_1)];
+            } else {
+                i2Block=trie->newTrie->index1[c>>UTRIE2_SHIFT_1];
+            }
+            if(i2Block==prevI2Block && (c-prev)>=UTRIE2_CP_PER_INDEX_1_ENTRY) {
+                /*
+                 * The index-2 block is the same as the previous one, and filled with prevValue.
+                 * Only possible for supplementary code points because the linear-BMP index-2
+                 * table creates unique i2Block values.
+                 */
+                c+=UTRIE2_CP_PER_INDEX_1_ENTRY;
+                continue;
+            }
+        }
+        prevI2Block=i2Block;
+        if(i2Block==index2NullOffset) {
+            /* this is the null index-2 block */
+            if(prevValue!=initialValue) {
+                if(prev<c && !enumRange(context, prev, c-1, prevValue)) {
+                    return;
+                }
+                prevBlock=nullBlock;
+                prev=c;
+                prevValue=initialValue;
+            }
+            c+=UTRIE2_CP_PER_INDEX_1_ENTRY;
+        } else {
+            /* enumerate data blocks for one index-2 block */
+            int32_t i2, i2Limit;
+            i2=(c>>UTRIE2_SHIFT_2)&UTRIE2_INDEX_2_MASK;
+            if((c>>UTRIE2_SHIFT_1)==(tempLimit>>UTRIE2_SHIFT_1)) {
+                i2Limit=(tempLimit>>UTRIE2_SHIFT_2)&UTRIE2_INDEX_2_MASK;
+            } else {
+                i2Limit=UTRIE2_INDEX_2_BLOCK_LENGTH;
+            }
+            for(; i2<i2Limit; ++i2) {
+                if(idx!=NULL) {
+                    block=(int32_t)idx[i2Block+i2]<<UTRIE2_INDEX_SHIFT;
+                } else {
+                    block=trie->newTrie->index2[i2Block+i2];
+                }
+                if(block==prevBlock && (c-prev)>=UTRIE2_DATA_BLOCK_LENGTH) {
+                    /* the block is the same as the previous one, and filled with prevValue */
+                    c+=UTRIE2_DATA_BLOCK_LENGTH;
+                    continue;
+                }
+                prevBlock=block;
+                if(block==nullBlock) {
+                    /* this is the null data block */
+                    if(prevValue!=initialValue) {
+                        if(prev<c && !enumRange(context, prev, c-1, prevValue)) {
+                            return;
+                        }
+                        prev=c;
+                        prevValue=initialValue;
+                    }
+                    c+=UTRIE2_DATA_BLOCK_LENGTH;
+                } else {
+                    for(j=0; j<UTRIE2_DATA_BLOCK_LENGTH; ++j) {
+                        value=enumValue(context, data32!=NULL ? data32[block+j] : idx[block+j]);
+                        if(value!=prevValue) {
+                            if(prev<c && !enumRange(context, prev, c-1, prevValue)) {
+                                return;
+                            }
+                            prev=c;
+                            prevValue=value;
+                        }
+                        ++c;
+                    }
+                }
+            }
+        }
+    }
+
+    if(c>limit) {
+        c=limit;  /* could be higher if in the index2NullOffset */
+    } else if(c<limit) {
+        /* c==highStart<limit */
+        uint32_t highValue;
+        if(idx!=NULL) {
+            highValue=
+                data32!=NULL ?
+                    data32[trie->highValueIndex] :
+                    idx[trie->highValueIndex];
+        } else {
+            highValue=trie->newTrie->data[trie->newTrie->dataLength-UTRIE2_DATA_GRANULARITY];
+        }
+        value=enumValue(context, highValue);
+        if(value!=prevValue) {
+            if(prev<c && !enumRange(context, prev, c-1, prevValue)) {
+                return;
+            }
+            prev=c;
+            prevValue=value;
+        }
+        c=limit;
+    }
+
+    /* deliver last range */
+    enumRange(context, prev, c-1, prevValue);
+}
+
+U_CAPI void U_EXPORT2
+utrie2_enum(const UTrie2 *trie,
+            UTrie2EnumValue *enumValue, UTrie2EnumRange *enumRange, const void *context) {
+    enumEitherTrie(trie, 0, 0x110000, enumValue, enumRange, context);
+}
+
+U_CAPI void U_EXPORT2
+utrie2_enumForLeadSurrogate(const UTrie2 *trie, UChar32 lead,
+                            UTrie2EnumValue *enumValue, UTrie2EnumRange *enumRange,
+                            const void *context) {
+    if(!U16_IS_LEAD(lead)) {
+        return;
+    }
+    lead=(lead-0xd7c0)<<10;   /* start code point */
+    enumEitherTrie(trie, lead, lead+0x400, enumValue, enumRange, context);
+}
+
+/* C++ convenience wrappers ------------------------------------------------- */
+
+U_NAMESPACE_BEGIN
+
+uint16_t BackwardUTrie2StringIterator::previous16() {
+    codePointLimit=codePointStart;
+    if(start>=codePointStart) {
+        codePoint=U_SENTINEL;
+        return 0;
+    }
+    uint16_t result;
+    UTRIE2_U16_PREV16(trie, start, codePointStart, codePoint, result);
+    return result;
+}
+
+uint16_t ForwardUTrie2StringIterator::next16() {
+    codePointStart=codePointLimit;
+    if(codePointLimit==limit) {
+        codePoint=U_SENTINEL;
+        return 0;
+    }
+    uint16_t result;
+    UTRIE2_U16_NEXT16(trie, codePointLimit, limit, codePoint, result);
+    return result;
+}
+
+UTrie2 *UTrie2Singleton::getInstance(InstantiatorFn *instantiator, const void *context,
+                                     UErrorCode &errorCode) {
+    void *duplicate;
+    UTrie2 *instance=(UTrie2 *)singleton.getInstance(instantiator, context, duplicate, errorCode);
+    utrie2_close((UTrie2 *)duplicate);
+    return instance;
+}
+
+U_NAMESPACE_END
diff --git a/source/common/utrie2.h b/source/common/utrie2.h
new file mode 100644
index 0000000..4e7ead0
--- /dev/null
+++ b/source/common/utrie2.h
@@ -0,0 +1,999 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2001-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  utrie2.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2008aug16 (starting from a copy of utrie.h)
+*   created by: Markus W. Scherer
+*/
+
+#ifndef __UTRIE2_H__
+#define __UTRIE2_H__
+
+#include "unicode/utypes.h"
+#include "udataswp.h"
+
+U_CDECL_BEGIN
+
+struct UTrie;  /* forward declaration */
+#ifndef __UTRIE_H__
+typedef struct UTrie UTrie;
+#endif
+
+/**
+ * \file
+ *
+ * This is a common implementation of a Unicode trie.
+ * It is a kind of compressed, serializable table of 16- or 32-bit values associated with
+ * Unicode code points (0..0x10ffff). (A map from code points to integers.)
+ *
+ * This is the second common version of a Unicode trie (hence the name UTrie2).
+ * Compared with UTrie version 1:
+ * - Still splitting BMP code points 11:5 bits for index and data table lookups.
+ * - Still separate data for lead surrogate code _units_ vs. code _points_,
+ *   but the lead surrogate code unit values are not required any more
+ *   for data lookup for supplementary code points.
+ * - The "folding" mechanism is removed. In UTrie version 1, this somewhat
+ *   hard-to-explain mechanism was meant to be used for optimized UTF-16
+ *   processing, with application-specific encoding of indexing bits
+ *   in the lead surrogate data for the associated supplementary code points.
+ * - For the last single-value code point range (ending with U+10ffff),
+ *   the starting code point ("highStart") and the value are stored.
+ * - For supplementary code points U+10000..highStart-1 a three-table lookup
+ *   (two index tables and one data table) is used. The first index
+ *   is truncated, omitting both the BMP portion and the high range.
+ * - There is a special small index for 2-byte UTF-8, and the initial data
+ *   entries are designed for fast 1/2-byte UTF-8 lookup.
+ */
+
+/**
+ * Trie structure.
+ * Use only with public API macros and functions.
+ */
+struct UTrie2;
+typedef struct UTrie2 UTrie2;
+
+/* Public UTrie2 API functions: read-only access ---------------------------- */
+
+/**
+ * Selectors for the width of a UTrie2 data value.
+ */
+enum UTrie2ValueBits {
+    /** 16 bits per UTrie2 data value. */
+    UTRIE2_16_VALUE_BITS,
+    /** 32 bits per UTrie2 data value. */
+    UTRIE2_32_VALUE_BITS,
+    /** Number of selectors for the width of UTrie2 data values. */
+    UTRIE2_COUNT_VALUE_BITS
+};
+typedef enum UTrie2ValueBits UTrie2ValueBits;
+
+/**
+ * Open a frozen trie from its serialized from, stored in 32-bit-aligned memory.
+ * Inverse of utrie2_serialize().
+ * The memory must remain valid and unchanged as long as the trie is used.
+ * You must utrie2_close() the trie once you are done using it.
+ *
+ * @param valueBits selects the data entry size; results in an
+ *                  U_INVALID_FORMAT_ERROR if it does not match the serialized form
+ * @param data a pointer to 32-bit-aligned memory containing the serialized form of a UTrie2
+ * @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 trie data;
+ *                      can be NULL
+ * @param pErrorCode an in/out ICU UErrorCode
+ * @return the unserialized trie
+ *
+ * @see utrie2_open
+ * @see utrie2_serialize
+ */
+U_CAPI UTrie2 * U_EXPORT2
+utrie2_openFromSerialized(UTrie2ValueBits valueBits,
+                          const void *data, int32_t length, int32_t *pActualLength,
+                          UErrorCode *pErrorCode);
+
+/**
+ * Open a frozen, empty "dummy" trie.
+ * A dummy trie is an empty trie, used when a real data trie cannot
+ * be loaded. Equivalent to calling utrie2_open() and utrie2_freeze(),
+ * but without internally creating and compacting/serializing the
+ * builder data structure.
+ *
+ * The trie always returns the initialValue,
+ * or the errorValue for out-of-range code points and illegal UTF-8.
+ *
+ * You must utrie2_close() the trie once you are done using it.
+ *
+ * @param valueBits selects the data entry size
+ * @param initialValue the initial value that is set for all code points
+ * @param errorValue the value for out-of-range code points and illegal UTF-8
+ * @param pErrorCode an in/out ICU UErrorCode
+ * @return the dummy trie
+ *
+ * @see utrie2_openFromSerialized
+ * @see utrie2_open
+ */
+U_CAPI UTrie2 * U_EXPORT2
+utrie2_openDummy(UTrie2ValueBits valueBits,
+                 uint32_t initialValue, uint32_t errorValue,
+                 UErrorCode *pErrorCode);
+
+/**
+ * Get a value from a code point as stored in the trie.
+ * Easier to use than UTRIE2_GET16() and UTRIE2_GET32() but slower.
+ * Easier to use because, unlike the macros, this function works on all UTrie2
+ * objects, frozen or not, holding 16-bit or 32-bit data values.
+ *
+ * @param trie the trie
+ * @param c the code point
+ * @return the value
+ */
+U_CAPI uint32_t U_EXPORT2
+utrie2_get32(const UTrie2 *trie, UChar32 c);
+
+/* enumeration callback types */
+
+/**
+ * Callback from utrie2_enum(), extracts a uint32_t value from a
+ * trie value. This value will be passed on to the UTrie2EnumRange function.
+ *
+ * @param context an opaque pointer, as passed into utrie2_enum()
+ * @param value a value from the trie
+ * @return the value that is to be passed on to the UTrie2EnumRange function
+ */
+typedef uint32_t U_CALLCONV
+UTrie2EnumValue(const void *context, uint32_t value);
+
+/**
+ * Callback from utrie2_enum(), is called for each contiguous range
+ * of code points with the same value as retrieved from the trie and
+ * transformed by the UTrie2EnumValue function.
+ *
+ * The callback function can stop the enumeration by returning FALSE.
+ *
+ * @param context an opaque pointer, as passed into utrie2_enum()
+ * @param start the first code point in a contiguous range with value
+ * @param end the last code point in a contiguous range with value (inclusive)
+ * @param value the value that is set for all code points in [start..end]
+ * @return FALSE to stop the enumeration
+ */
+typedef UBool U_CALLCONV
+UTrie2EnumRange(const void *context, UChar32 start, UChar32 end, uint32_t value);
+
+/**
+ * Enumerate efficiently all values in a trie.
+ * Do not modify the trie during the enumeration.
+ *
+ * For each entry in the trie, the value to be delivered is passed through
+ * the UTrie2EnumValue function.
+ * The value is unchanged if that function pointer is NULL.
+ *
+ * For each contiguous range of code points with a given (transformed) value,
+ * the UTrie2EnumRange function is called.
+ *
+ * @param trie a pointer to the trie
+ * @param enumValue a pointer to a function that may transform the trie entry value,
+ *                  or NULL if the values from the trie are to be used directly
+ * @param enumRange a pointer to a function that is called for each contiguous range
+ *                  of code points with the same (transformed) value
+ * @param context an opaque pointer that is passed on to the callback functions
+ */
+U_CAPI void U_EXPORT2
+utrie2_enum(const UTrie2 *trie,
+            UTrie2EnumValue *enumValue, UTrie2EnumRange *enumRange, const void *context);
+
+/* Building a trie ---------------------------------------------------------- */
+
+/**
+ * Open an empty, writable trie. At build time, 32-bit data values are used.
+ * utrie2_freeze() takes a valueBits parameter
+ * which determines the data value width in the serialized and frozen forms.
+ * You must utrie2_close() the trie once you are done using it.
+ *
+ * @param initialValue the initial value that is set for all code points
+ * @param errorValue the value for out-of-range code points and illegal UTF-8
+ * @param pErrorCode an in/out ICU UErrorCode
+ * @return a pointer to the allocated and initialized new trie
+ */
+U_CAPI UTrie2 * U_EXPORT2
+utrie2_open(uint32_t initialValue, uint32_t errorValue, UErrorCode *pErrorCode);
+
+/**
+ * Clone a trie.
+ * You must utrie2_close() the clone once you are done using it.
+ *
+ * @param other the trie to clone
+ * @param pErrorCode an in/out ICU UErrorCode
+ * @return a pointer to the new trie clone
+ */
+U_CAPI UTrie2 * U_EXPORT2
+utrie2_clone(const UTrie2 *other, UErrorCode *pErrorCode);
+
+/**
+ * Clone a trie. The clone will be mutable/writable even if the other trie
+ * is frozen. (See utrie2_freeze().)
+ * You must utrie2_close() the clone once you are done using it.
+ *
+ * @param other the trie to clone
+ * @param pErrorCode an in/out ICU UErrorCode
+ * @return a pointer to the new trie clone
+ */
+U_CAPI UTrie2 * U_EXPORT2
+utrie2_cloneAsThawed(const UTrie2 *other, UErrorCode *pErrorCode);
+
+/**
+ * Close a trie and release associated memory.
+ *
+ * @param trie the trie
+ */
+U_CAPI void U_EXPORT2
+utrie2_close(UTrie2 *trie);
+
+/**
+ * Set a value for a code point.
+ *
+ * @param trie the unfrozen trie
+ * @param c the code point
+ * @param value the value
+ * @param pErrorCode an in/out ICU UErrorCode; among other possible error codes:
+ * - U_NO_WRITE_PERMISSION if the trie is frozen
+ */
+U_CAPI void U_EXPORT2
+utrie2_set32(UTrie2 *trie, UChar32 c, uint32_t value, UErrorCode *pErrorCode);
+
+/**
+ * Set a value in a range of code points [start..end].
+ * All code points c with start<=c<=end will get the value if
+ * overwrite is TRUE or if the old value is the initial value.
+ *
+ * @param trie the unfrozen trie
+ * @param start the first code point to get the value
+ * @param end the last code point to get the value (inclusive)
+ * @param value the value
+ * @param overwrite flag for whether old non-initial values are to be overwritten
+ * @param pErrorCode an in/out ICU UErrorCode; among other possible error codes:
+ * - U_NO_WRITE_PERMISSION if the trie is frozen
+ */
+U_CAPI void U_EXPORT2
+utrie2_setRange32(UTrie2 *trie,
+                  UChar32 start, UChar32 end,
+                  uint32_t value, UBool overwrite,
+                  UErrorCode *pErrorCode);
+
+/**
+ * Freeze a trie. Make it immutable (read-only) and compact it,
+ * ready for serialization and for use with fast macros.
+ * Functions to set values will fail after serializing.
+ *
+ * A trie can be frozen only once. If this function is called again with different
+ * valueBits then it will set a U_ILLEGAL_ARGUMENT_ERROR.
+ *
+ * @param trie the trie
+ * @param valueBits selects the data entry size; if smaller than 32 bits, then
+ *                  the values stored in the trie will be truncated
+ * @param pErrorCode an in/out ICU UErrorCode; among other possible error codes:
+ * - U_INDEX_OUTOFBOUNDS_ERROR if the compacted index or data arrays are too long
+ *                             for serialization
+ *                             (the trie will be immutable and usable,
+ *                             but not frozen and not usable with the fast macros)
+ *
+ * @see utrie2_cloneAsThawed
+ */
+U_CAPI void U_EXPORT2
+utrie2_freeze(UTrie2 *trie, UTrie2ValueBits valueBits, UErrorCode *pErrorCode);
+
+/**
+ * Test if the trie is frozen. (See utrie2_freeze().)
+ *
+ * @param trie the trie
+ * @return TRUE if the trie is frozen, that is, immutable, ready for serialization
+ *         and for use with fast macros
+ */
+U_CAPI UBool U_EXPORT2
+utrie2_isFrozen(const UTrie2 *trie);
+
+/**
+ * Serialize a frozen trie into 32-bit aligned memory.
+ * If the trie is not frozen, then the function returns with a U_ILLEGAL_ARGUMENT_ERROR.
+ * A trie can be serialized multiple times.
+ *
+ * @param trie the frozen trie
+ * @param data a pointer to 32-bit-aligned memory to be filled with the trie data,
+ *             can be NULL if capacity==0
+ * @param capacity the number of bytes available at data,
+ *                 or 0 for preflighting
+ * @param pErrorCode an in/out ICU UErrorCode; among other possible error codes:
+ * - U_BUFFER_OVERFLOW_ERROR if the data storage block is too small for serialization
+ * - U_ILLEGAL_ARGUMENT_ERROR if the trie is not frozen or the data and capacity
+ *                            parameters are bad
+ * @return the number of bytes written or needed for the trie
+ *
+ * @see utrie2_openFromSerialized()
+ */
+U_CAPI int32_t U_EXPORT2
+utrie2_serialize(UTrie2 *trie,
+                 void *data, int32_t capacity,
+                 UErrorCode *pErrorCode);
+
+/* Public UTrie2 API: miscellaneous functions ------------------------------- */
+
+/**
+ * Get the UTrie version from 32-bit-aligned memory containing the serialized form
+ * of either a UTrie (version 1) or a UTrie2 (version 2).
+ *
+ * @param data a pointer to 32-bit-aligned memory containing the serialized form
+ *             of a UTrie, version 1 or 2
+ * @param length the number of bytes available at data;
+ *               can be more than necessary (see return value)
+ * @param anyEndianOk If FALSE, only platform-endian serialized forms are recognized.
+ *                    If TRUE, opposite-endian serialized forms are recognized as well.
+ * @return the UTrie version of the serialized form, or 0 if it is not
+ *         recognized as a serialized UTrie
+ */
+U_CAPI int32_t U_EXPORT2
+utrie2_getVersion(const void *data, int32_t length, UBool anyEndianOk);
+
+/**
+ * Swap a serialized UTrie2.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+utrie2_swap(const UDataSwapper *ds,
+            const void *inData, int32_t length, void *outData,
+            UErrorCode *pErrorCode);
+
+/**
+ * Swap a serialized UTrie or UTrie2.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+utrie2_swapAnyVersion(const UDataSwapper *ds,
+                      const void *inData, int32_t length, void *outData,
+                      UErrorCode *pErrorCode);
+
+/**
+ * Build a UTrie2 (version 2) from a UTrie (version 1).
+ * Enumerates all values in the UTrie and builds a UTrie2 with the same values.
+ * The resulting UTrie2 will be frozen.
+ *
+ * @param trie1 the runtime UTrie structure to be enumerated
+ * @param errorValue the value for out-of-range code points and illegal UTF-8
+ * @param pErrorCode an in/out ICU UErrorCode
+ * @return The frozen UTrie2 with the same values as the UTrie.
+ */
+U_CAPI UTrie2 * U_EXPORT2
+utrie2_fromUTrie(const UTrie *trie1, uint32_t errorValue, UErrorCode *pErrorCode);
+
+/* Public UTrie2 API macros ------------------------------------------------- */
+
+/*
+ * These macros provide fast data lookup from a frozen trie.
+ * They will crash when used on an unfrozen trie.
+ */
+
+/**
+ * Return a 16-bit trie value from a code point, with range checking.
+ * Returns trie->errorValue if c is not in the range 0..U+10ffff.
+ *
+ * @param trie (const UTrie2 *, in) a frozen trie
+ * @param c (UChar32, in) the input code point
+ * @return (uint16_t) The code point's trie value.
+ */
+#define UTRIE2_GET16(trie, c) _UTRIE2_GET((trie), index, (trie)->indexLength, (c))
+
+/**
+ * Return a 32-bit trie value from a code point, with range checking.
+ * Returns trie->errorValue if c is not in the range 0..U+10ffff.
+ *
+ * @param trie (const UTrie2 *, in) a frozen trie
+ * @param c (UChar32, in) the input code point
+ * @return (uint32_t) The code point's trie value.
+ */
+#define UTRIE2_GET32(trie, c) _UTRIE2_GET((trie), data32, 0, (c))
+
+/**
+ * UTF-16: Get the next code point (UChar32 c, out), post-increment src,
+ * and get a 16-bit value from the trie.
+ *
+ * @param trie (const UTrie2 *, in) a frozen trie
+ * @param src (const UChar *, in/out) the source text pointer
+ * @param limit (const UChar *, in) the limit pointer for the text, or NULL if NUL-terminated
+ * @param c (UChar32, out) variable for the code point
+ * @param result (uint16_t, out) uint16_t variable for the trie lookup result
+ */
+#define UTRIE2_U16_NEXT16(trie, src, limit, c, result) _UTRIE2_U16_NEXT(trie, index, src, limit, c, result)
+
+/**
+ * UTF-16: Get the next code point (UChar32 c, out), post-increment src,
+ * and get a 32-bit value from the trie.
+ *
+ * @param trie (const UTrie2 *, in) a frozen trie
+ * @param src (const UChar *, in/out) the source text pointer
+ * @param limit (const UChar *, in) the limit pointer for the text, or NULL if NUL-terminated
+ * @param c (UChar32, out) variable for the code point
+ * @param result (uint32_t, out) uint32_t variable for the trie lookup result
+ */
+#define UTRIE2_U16_NEXT32(trie, src, limit, c, result) _UTRIE2_U16_NEXT(trie, data32, src, limit, c, result)
+
+/**
+ * UTF-16: Get the previous code point (UChar32 c, out), pre-decrement src,
+ * and get a 16-bit value from the trie.
+ *
+ * @param trie (const UTrie2 *, in) a frozen trie
+ * @param start (const UChar *, in) the start pointer for the text
+ * @param src (const UChar *, in/out) the source text pointer
+ * @param c (UChar32, out) variable for the code point
+ * @param result (uint16_t, out) uint16_t variable for the trie lookup result
+ */
+#define UTRIE2_U16_PREV16(trie, start, src, c, result) _UTRIE2_U16_PREV(trie, index, start, src, c, result)
+
+/**
+ * UTF-16: Get the previous code point (UChar32 c, out), pre-decrement src,
+ * and get a 32-bit value from the trie.
+ *
+ * @param trie (const UTrie2 *, in) a frozen trie
+ * @param start (const UChar *, in) the start pointer for the text
+ * @param src (const UChar *, in/out) the source text pointer
+ * @param c (UChar32, out) variable for the code point
+ * @param result (uint32_t, out) uint32_t variable for the trie lookup result
+ */
+#define UTRIE2_U16_PREV32(trie, start, src, c, result) _UTRIE2_U16_PREV(trie, data32, start, src, c, result)
+
+/**
+ * UTF-8: Post-increment src and get a 16-bit value from the trie.
+ *
+ * @param trie (const UTrie2 *, in) a frozen trie
+ * @param src (const char *, in/out) the source text pointer
+ * @param limit (const char *, in) the limit pointer for the text (must not be NULL)
+ * @param result (uint16_t, out) uint16_t variable for the trie lookup result
+ */
+#define UTRIE2_U8_NEXT16(trie, src, limit, result)\
+    _UTRIE2_U8_NEXT(trie, data16, index, src, limit, result)
+
+/**
+ * UTF-8: Post-increment src and get a 32-bit value from the trie.
+ *
+ * @param trie (const UTrie2 *, in) a frozen trie
+ * @param src (const char *, in/out) the source text pointer
+ * @param limit (const char *, in) the limit pointer for the text (must not be NULL)
+ * @param result (uint16_t, out) uint32_t variable for the trie lookup result
+ */
+#define UTRIE2_U8_NEXT32(trie, src, limit, result) \
+    _UTRIE2_U8_NEXT(trie, data32, data32, src, limit, result)
+
+/**
+ * UTF-8: Pre-decrement src and get a 16-bit value from the trie.
+ *
+ * @param trie (const UTrie2 *, in) a frozen trie
+ * @param start (const char *, in) the start pointer for the text
+ * @param src (const char *, in/out) the source text pointer
+ * @param result (uint16_t, out) uint16_t variable for the trie lookup result
+ */
+#define UTRIE2_U8_PREV16(trie, start, src, result) \
+    _UTRIE2_U8_PREV(trie, data16, index, start, src, result)
+
+/**
+ * UTF-8: Pre-decrement src and get a 32-bit value from the trie.
+ *
+ * @param trie (const UTrie2 *, in) a frozen trie
+ * @param start (const char *, in) the start pointer for the text
+ * @param src (const char *, in/out) the source text pointer
+ * @param result (uint16_t, out) uint32_t variable for the trie lookup result
+ */
+#define UTRIE2_U8_PREV32(trie, start, src, result) \
+    _UTRIE2_U8_PREV(trie, data32, data32, start, src, result)
+
+/* Public UTrie2 API: optimized UTF-16 access ------------------------------- */
+
+/*
+ * The following functions and macros are used for highly optimized UTF-16
+ * text processing. The UTRIE2_U16_NEXTxy() macros do not depend on these.
+ *
+ * A UTrie2 stores separate values for lead surrogate code _units_ vs. code _points_.
+ * UTF-16 text processing can be optimized by detecting surrogate pairs and
+ * assembling supplementary code points only when there is non-trivial data
+ * available.
+ *
+ * At build-time, use utrie2_enumForLeadSurrogate() to see if there
+ * is non-trivial (non-initialValue) data for any of the supplementary
+ * code points associated with a lead surrogate.
+ * If so, then set a special (application-specific) value for the
+ * lead surrogate code _unit_, with utrie2_set32ForLeadSurrogateCodeUnit().
+ *
+ * At runtime, use UTRIE2_GET16_FROM_U16_SINGLE_LEAD() or
+ * UTRIE2_GET32_FROM_U16_SINGLE_LEAD() per code unit. If there is non-trivial
+ * data and the code unit is a lead surrogate, then check if a trail surrogate
+ * follows. If so, assemble the supplementary code point with
+ * U16_GET_SUPPLEMENTARY() and look up its value with UTRIE2_GET16_FROM_SUPP()
+ * or UTRIE2_GET32_FROM_SUPP(); otherwise reset the lead
+ * surrogate's value or do a code point lookup for it.
+ *
+ * If there is only trivial data for lead and trail surrogates, then processing
+ * can often skip them. For example, in normalization or case mapping
+ * all characters that do not have any mappings are simply copied as is.
+ */
+
+/**
+ * Get a value from a lead surrogate code unit as stored in the trie.
+ *
+ * @param trie the trie
+ * @param c the code unit (U+D800..U+DBFF)
+ * @return the value
+ */
+U_CAPI uint32_t U_EXPORT2
+utrie2_get32FromLeadSurrogateCodeUnit(const UTrie2 *trie, UChar32 c);
+
+/**
+ * Enumerate the trie values for the 1024=0x400 code points
+ * corresponding to a given lead surrogate.
+ * For example, for the lead surrogate U+D87E it will enumerate the values
+ * for [U+2F800..U+2FC00[.
+ * Used by data builder code that sets special lead surrogate code unit values
+ * for optimized UTF-16 string processing.
+ *
+ * Do not modify the trie during the enumeration.
+ *
+ * Except for the limited code point range, this functions just like utrie2_enum():
+ * For each entry in the trie, the value to be delivered is passed through
+ * the UTrie2EnumValue function.
+ * The value is unchanged if that function pointer is NULL.
+ *
+ * For each contiguous range of code points with a given (transformed) value,
+ * the UTrie2EnumRange function is called.
+ *
+ * @param trie a pointer to the trie
+ * @param enumValue a pointer to a function that may transform the trie entry value,
+ *                  or NULL if the values from the trie are to be used directly
+ * @param enumRange a pointer to a function that is called for each contiguous range
+ *                  of code points with the same (transformed) value
+ * @param context an opaque pointer that is passed on to the callback functions
+ */
+U_CAPI void U_EXPORT2
+utrie2_enumForLeadSurrogate(const UTrie2 *trie, UChar32 lead,
+                            UTrie2EnumValue *enumValue, UTrie2EnumRange *enumRange,
+                            const void *context);
+
+/**
+ * Set a value for a lead surrogate code unit.
+ *
+ * @param trie the unfrozen trie
+ * @param lead the lead surrogate code unit (U+D800..U+DBFF)
+ * @param value the value
+ * @param pErrorCode an in/out ICU UErrorCode; among other possible error codes:
+ * - U_NO_WRITE_PERMISSION if the trie is frozen
+ */
+U_CAPI void U_EXPORT2
+utrie2_set32ForLeadSurrogateCodeUnit(UTrie2 *trie,
+                                     UChar32 lead, uint32_t value,
+                                     UErrorCode *pErrorCode);
+
+/**
+ * Return a 16-bit trie value from a UTF-16 single/lead code unit (<=U+ffff).
+ * Same as UTRIE2_GET16() if c is a BMP code point except for lead surrogates,
+ * but smaller and faster.
+ *
+ * @param trie (const UTrie2 *, in) a frozen trie
+ * @param c (UChar32, in) the input code unit, must be 0<=c<=U+ffff
+ * @return (uint16_t) The code unit's trie value.
+ */
+#define UTRIE2_GET16_FROM_U16_SINGLE_LEAD(trie, c) _UTRIE2_GET_FROM_U16_SINGLE_LEAD((trie), index, c)
+
+/**
+ * Return a 32-bit trie value from a UTF-16 single/lead code unit (<=U+ffff).
+ * Same as UTRIE2_GET32() if c is a BMP code point except for lead surrogates,
+ * but smaller and faster.
+ *
+ * @param trie (const UTrie2 *, in) a frozen trie
+ * @param c (UChar32, in) the input code unit, must be 0<=c<=U+ffff
+ * @return (uint32_t) The code unit's trie value.
+ */
+#define UTRIE2_GET32_FROM_U16_SINGLE_LEAD(trie, c) _UTRIE2_GET_FROM_U16_SINGLE_LEAD((trie), data32, c)
+
+/**
+ * Return a 16-bit trie value from a supplementary code point (U+10000..U+10ffff).
+ *
+ * @param trie (const UTrie2 *, in) a frozen trie
+ * @param c (UChar32, in) the input code point, must be U+10000<=c<=U+10ffff
+ * @return (uint16_t) The code point's trie value.
+ */
+#define UTRIE2_GET16_FROM_SUPP(trie, c) _UTRIE2_GET_FROM_SUPP((trie), index, c)
+
+/**
+ * Return a 32-bit trie value from a supplementary code point (U+10000..U+10ffff).
+ *
+ * @param trie (const UTrie2 *, in) a frozen trie
+ * @param c (UChar32, in) the input code point, must be U+10000<=c<=U+10ffff
+ * @return (uint32_t) The code point's trie value.
+ */
+#define UTRIE2_GET32_FROM_SUPP(trie, c) _UTRIE2_GET_FROM_SUPP((trie), data32, c)
+
+U_CDECL_END
+
+/* C++ convenience wrappers ------------------------------------------------- */
+
+#ifdef XP_CPLUSPLUS
+
+#include "mutex.h"
+
+U_NAMESPACE_BEGIN
+
+// Use the Forward/Backward subclasses below.
+class UTrie2StringIterator : public UMemory {
+public:
+    UTrie2StringIterator(const UTrie2 *t, const UChar *p) :
+        trie(t), codePointStart(p), codePointLimit(p), codePoint(U_SENTINEL) {}
+
+    const UTrie2 *trie;
+    const UChar *codePointStart, *codePointLimit;
+    UChar32 codePoint;
+};
+
+class BackwardUTrie2StringIterator : public UTrie2StringIterator {
+public:
+    BackwardUTrie2StringIterator(const UTrie2 *t, const UChar *s, const UChar *p) :
+        UTrie2StringIterator(t, p), start(s) {}
+
+    uint16_t previous16();
+
+    const UChar *start;
+};
+
+class ForwardUTrie2StringIterator : public UTrie2StringIterator {
+public:
+    // Iteration limit l can be NULL.
+    // In that case, the caller must detect c==0 and stop.
+    ForwardUTrie2StringIterator(const UTrie2 *t, const UChar *p, const UChar *l) :
+        UTrie2StringIterator(t, p), limit(l) {}
+
+    uint16_t next16();
+
+    const UChar *limit;
+};
+
+class UTrie2Singleton {
+public:
+    UTrie2Singleton(SimpleSingleton &s) : singleton(s) {}
+    void deleteInstance() {
+        utrie2_close((UTrie2 *)singleton.fInstance);
+        singleton.reset();
+    }
+    UTrie2 *getInstance(InstantiatorFn *instantiator, const void *context,
+                        UErrorCode &errorCode);
+private:
+    SimpleSingleton &singleton;
+};
+
+U_NAMESPACE_END
+
+#endif
+
+/* Internal definitions ----------------------------------------------------- */
+
+U_CDECL_BEGIN
+
+/** Build-time trie structure. */
+struct UNewTrie2;
+typedef struct UNewTrie2 UNewTrie2;
+
+/*
+ * Trie structure definition.
+ *
+ * Either the data table is 16 bits wide and accessed via the index
+ * pointer, with each index item increased by indexLength;
+ * in this case, data32==NULL, and data16 is used for direct ASCII access.
+ *
+ * Or the data table is 32 bits wide and accessed via the data32 pointer.
+ */
+struct UTrie2 {
+    /* protected: used by macros and functions for reading values */
+    const uint16_t *index;
+    const uint16_t *data16;     /* for fast UTF-8 ASCII access, if 16b data */
+    const uint32_t *data32;     /* NULL if 16b data is used via index */
+
+    int32_t indexLength, dataLength;
+    uint16_t index2NullOffset;  /* 0xffff if there is no dedicated index-2 null block */
+    uint16_t dataNullOffset;
+    uint32_t initialValue;
+    /** Value returned for out-of-range code points and illegal UTF-8. */
+    uint32_t errorValue;
+
+    /* Start of the last range which ends at U+10ffff, and its value. */
+    UChar32 highStart;
+    int32_t highValueIndex;
+
+    /* private: used by builder and unserialization functions */
+    void *memory;           /* serialized bytes; NULL if not frozen yet */
+    int32_t length;         /* number of serialized bytes at memory; 0 if not frozen yet */
+    UBool isMemoryOwned;    /* TRUE if the trie owns the memory */
+    UBool padding1;
+    int16_t padding2;
+    UNewTrie2 *newTrie;     /* builder object; NULL when frozen */
+};
+
+/**
+ * Trie constants, defining shift widths, index array lengths, etc.
+ *
+ * These are needed for the runtime macros but users can treat these as
+ * implementation details and skip to the actual public API further below.
+ */
+enum {
+    /** Shift size for getting the index-1 table offset. */
+    UTRIE2_SHIFT_1=6+5,
+
+    /** Shift size for getting the index-2 table offset. */
+    UTRIE2_SHIFT_2=5,
+
+    /**
+     * Difference between the two shift sizes,
+     * for getting an index-1 offset from an index-2 offset. 6=11-5
+     */
+    UTRIE2_SHIFT_1_2=UTRIE2_SHIFT_1-UTRIE2_SHIFT_2,
+
+    /**
+     * Number of index-1 entries for the BMP. 32=0x20
+     * This part of the index-1 table is omitted from the serialized form.
+     */
+    UTRIE2_OMITTED_BMP_INDEX_1_LENGTH=0x10000>>UTRIE2_SHIFT_1,
+
+    /** Number of code points per index-1 table entry. 2048=0x800 */
+    UTRIE2_CP_PER_INDEX_1_ENTRY=1<<UTRIE2_SHIFT_1,
+
+    /** Number of entries in an index-2 block. 64=0x40 */
+    UTRIE2_INDEX_2_BLOCK_LENGTH=1<<UTRIE2_SHIFT_1_2,
+
+    /** Mask for getting the lower bits for the in-index-2-block offset. */
+    UTRIE2_INDEX_2_MASK=UTRIE2_INDEX_2_BLOCK_LENGTH-1,
+
+    /** Number of entries in a data block. 32=0x20 */
+    UTRIE2_DATA_BLOCK_LENGTH=1<<UTRIE2_SHIFT_2,
+
+    /** Mask for getting the lower bits for the in-data-block offset. */
+    UTRIE2_DATA_MASK=UTRIE2_DATA_BLOCK_LENGTH-1,
+
+    /**
+     * Shift size for shifting left the index array values.
+     * Increases possible data size with 16-bit index values at the cost
+     * of compactability.
+     * This requires data blocks to be aligned by UTRIE2_DATA_GRANULARITY.
+     */
+    UTRIE2_INDEX_SHIFT=2,
+
+    /** The alignment size of a data block. Also the granularity for compaction. */
+    UTRIE2_DATA_GRANULARITY=1<<UTRIE2_INDEX_SHIFT,
+
+    /* Fixed layout of the first part of the index array. ------------------- */
+
+    /**
+     * The BMP part of the index-2 table is fixed and linear and starts at offset 0.
+     * Length=2048=0x800=0x10000>>UTRIE2_SHIFT_2.
+     */
+    UTRIE2_INDEX_2_OFFSET=0,
+
+    /**
+     * The part of the index-2 table for U+D800..U+DBFF stores values for
+     * lead surrogate code _units_ not code _points_.
+     * Values for lead surrogate code _points_ are indexed with this portion of the table.
+     * Length=32=0x20=0x400>>UTRIE2_SHIFT_2. (There are 1024=0x400 lead surrogates.)
+     */
+    UTRIE2_LSCP_INDEX_2_OFFSET=0x10000>>UTRIE2_SHIFT_2,
+    UTRIE2_LSCP_INDEX_2_LENGTH=0x400>>UTRIE2_SHIFT_2,
+
+    /** Count the lengths of both BMP pieces. 2080=0x820 */
+    UTRIE2_INDEX_2_BMP_LENGTH=UTRIE2_LSCP_INDEX_2_OFFSET+UTRIE2_LSCP_INDEX_2_LENGTH,
+
+    /**
+     * The 2-byte UTF-8 version of the index-2 table follows at offset 2080=0x820.
+     * Length 32=0x20 for lead bytes C0..DF, regardless of UTRIE2_SHIFT_2.
+     */
+    UTRIE2_UTF8_2B_INDEX_2_OFFSET=UTRIE2_INDEX_2_BMP_LENGTH,
+    UTRIE2_UTF8_2B_INDEX_2_LENGTH=0x800>>6,  /* U+0800 is the first code point after 2-byte UTF-8 */
+
+    /**
+     * The index-1 table, only used for supplementary code points, at offset 2112=0x840.
+     * Variable length, for code points up to highStart, where the last single-value range starts.
+     * Maximum length 512=0x200=0x100000>>UTRIE2_SHIFT_1.
+     * (For 0x100000 supplementary code points U+10000..U+10ffff.)
+     *
+     * The part of the index-2 table for supplementary code points starts
+     * after this index-1 table.
+     *
+     * Both the index-1 table and the following part of the index-2 table
+     * are omitted completely if there is only BMP data.
+     */
+    UTRIE2_INDEX_1_OFFSET=UTRIE2_UTF8_2B_INDEX_2_OFFSET+UTRIE2_UTF8_2B_INDEX_2_LENGTH,
+    UTRIE2_MAX_INDEX_1_LENGTH=0x100000>>UTRIE2_SHIFT_1,
+
+    /*
+     * Fixed layout of the first part of the data array. -----------------------
+     * Starts with 4 blocks (128=0x80 entries) for ASCII.
+     */
+
+    /**
+     * The illegal-UTF-8 data block follows the ASCII block, at offset 128=0x80.
+     * Used with linear access for single bytes 0..0xbf for simple error handling.
+     * Length 64=0x40, not UTRIE2_DATA_BLOCK_LENGTH.
+     */
+    UTRIE2_BAD_UTF8_DATA_OFFSET=0x80,
+
+    /** The start of non-linear-ASCII data blocks, at offset 192=0xc0. */
+    UTRIE2_DATA_START_OFFSET=0xc0
+};
+
+/* Internal functions and macros -------------------------------------------- */
+
+/**
+ * Internal function for part of the UTRIE2_U8_NEXTxx() macro implementations.
+ * Do not call directly.
+ * @internal
+ */
+U_INTERNAL int32_t U_EXPORT2
+utrie2_internalU8NextIndex(const UTrie2 *trie, UChar32 c,
+                           const uint8_t *src, const uint8_t *limit);
+
+/**
+ * Internal function for part of the UTRIE2_U8_PREVxx() macro implementations.
+ * Do not call directly.
+ * @internal
+ */
+U_INTERNAL int32_t U_EXPORT2
+utrie2_internalU8PrevIndex(const UTrie2 *trie, UChar32 c,
+                           const uint8_t *start, const uint8_t *src);
+
+
+/** Internal low-level trie getter. Returns a data index. */
+#define _UTRIE2_INDEX_RAW(offset, trieIndex, c) \
+    (((int32_t)((trieIndex)[(offset)+((c)>>UTRIE2_SHIFT_2)]) \
+    <<UTRIE2_INDEX_SHIFT)+ \
+    ((c)&UTRIE2_DATA_MASK))
+
+/** Internal trie getter from a UTF-16 single/lead code unit. Returns the data index. */
+#define _UTRIE2_INDEX_FROM_U16_SINGLE_LEAD(trieIndex, c) _UTRIE2_INDEX_RAW(0, trieIndex, c)
+
+/** Internal trie getter from a lead surrogate code point (D800..DBFF). Returns the data index. */
+#define _UTRIE2_INDEX_FROM_LSCP(trieIndex, c) \
+    _UTRIE2_INDEX_RAW(UTRIE2_LSCP_INDEX_2_OFFSET-(0xd800>>UTRIE2_SHIFT_2), trieIndex, c)
+
+/** Internal trie getter from a BMP code point. Returns the data index. */
+#define _UTRIE2_INDEX_FROM_BMP(trieIndex, c) \
+    _UTRIE2_INDEX_RAW(U_IS_LEAD(c) ? UTRIE2_LSCP_INDEX_2_OFFSET-(0xd800>>UTRIE2_SHIFT_2) : 0, \
+                      trieIndex, c)
+
+/** Internal trie getter from a supplementary code point below highStart. Returns the data index. */
+#define _UTRIE2_INDEX_FROM_SUPP(trieIndex, c) \
+    (((int32_t)((trieIndex)[ \
+        (trieIndex)[(UTRIE2_INDEX_1_OFFSET-UTRIE2_OMITTED_BMP_INDEX_1_LENGTH)+ \
+                      ((c)>>UTRIE2_SHIFT_1)]+ \
+        (((c)>>UTRIE2_SHIFT_2)&UTRIE2_INDEX_2_MASK)]) \
+    <<UTRIE2_INDEX_SHIFT)+ \
+    ((c)&UTRIE2_DATA_MASK))
+
+/**
+ * Internal trie getter from a code point, with checking that c is in 0..10FFFF.
+ * Returns the data index.
+ */
+#define _UTRIE2_INDEX_FROM_CP(trie, asciiOffset, c) \
+    ((uint32_t)(c)<0xd800 ? \
+        _UTRIE2_INDEX_RAW(0, (trie)->index, c) : \
+        (uint32_t)(c)<=0xffff ? \
+            _UTRIE2_INDEX_RAW( \
+                (c)<=0xdbff ? UTRIE2_LSCP_INDEX_2_OFFSET-(0xd800>>UTRIE2_SHIFT_2) : 0, \
+                (trie)->index, c) : \
+            (uint32_t)(c)>0x10ffff ? \
+                (asciiOffset)+UTRIE2_BAD_UTF8_DATA_OFFSET : \
+                (c)>=(trie)->highStart ? \
+                    (trie)->highValueIndex : \
+                    _UTRIE2_INDEX_FROM_SUPP((trie)->index, c))
+
+/** Internal trie getter from a UTF-16 single/lead code unit. Returns the data. */
+#define _UTRIE2_GET_FROM_U16_SINGLE_LEAD(trie, data, c) \
+    (trie)->data[_UTRIE2_INDEX_FROM_U16_SINGLE_LEAD((trie)->index, c)]
+
+/** Internal trie getter from a supplementary code point. Returns the data. */
+#define _UTRIE2_GET_FROM_SUPP(trie, data, c) \
+    (trie)->data[(c)>=(trie)->highStart ? (trie)->highValueIndex : \
+                 _UTRIE2_INDEX_FROM_SUPP((trie)->index, c)]
+
+/**
+ * Internal trie getter from a code point, with checking that c is in 0..10FFFF.
+ * Returns the data.
+ */
+#define _UTRIE2_GET(trie, data, asciiOffset, c) \
+    (trie)->data[_UTRIE2_INDEX_FROM_CP(trie, asciiOffset, c)]
+
+/** Internal next-post-increment: get the next code point (c) and its data. */
+#define _UTRIE2_U16_NEXT(trie, data, src, limit, c, result) { \
+    { \
+        uint16_t __c2; \
+        (c)=*(src)++; \
+        if(!U16_IS_LEAD(c)) { \
+            (result)=_UTRIE2_GET_FROM_U16_SINGLE_LEAD(trie, data, c); \
+        } else if((src)==(limit) || !U16_IS_TRAIL(__c2=*(src))) { \
+            (result)=(trie)->data[_UTRIE2_INDEX_FROM_LSCP((trie)->index, c)]; \
+        } else { \
+            ++(src); \
+            (c)=U16_GET_SUPPLEMENTARY((c), __c2); \
+            (result)=_UTRIE2_GET_FROM_SUPP((trie), data, (c)); \
+        } \
+    } \
+}
+
+/** Internal pre-decrement-previous: get the previous code point (c) and its data */
+#define _UTRIE2_U16_PREV(trie, data, start, src, c, result) { \
+    { \
+        uint16_t __c2; \
+        (c)=*--(src); \
+        if(!U16_IS_TRAIL(c) || (src)==(start) || !U16_IS_LEAD(__c2=*((src)-1))) { \
+            (result)=(trie)->data[_UTRIE2_INDEX_FROM_BMP((trie)->index, c)]; \
+        } else { \
+            --(src); \
+            (c)=U16_GET_SUPPLEMENTARY(__c2, (c)); \
+            (result)=_UTRIE2_GET_FROM_SUPP((trie), data, (c)); \
+        } \
+    } \
+}
+
+/** Internal UTF-8 next-post-increment: get the next code point's data. */
+#define _UTRIE2_U8_NEXT(trie, ascii, data, src, limit, result) { \
+    uint8_t __lead=(uint8_t)*(src)++; \
+    if(__lead<0xc0) { \
+        (result)=(trie)->ascii[__lead]; \
+    } else { \
+        uint8_t __t1, __t2; \
+        if( /* handle U+0000..U+07FF inline */ \
+            __lead<0xe0 && (src)<(limit) && \
+            (__t1=(uint8_t)(*(src)-0x80))<=0x3f \
+        ) { \
+            ++(src); \
+            (result)=(trie)->data[ \
+                (trie)->index[(UTRIE2_UTF8_2B_INDEX_2_OFFSET-0xc0)+__lead]+ \
+                __t1]; \
+        } else if( /* handle U+0000..U+CFFF inline */ \
+            __lead<0xed && ((src)+1)<(limit) && \
+            (__t1=(uint8_t)(*(src)-0x80))<=0x3f && (__lead>0xe0 || __t1>=0x20) && \
+            (__t2=(uint8_t)(*((src)+1)-0x80))<= 0x3f \
+        ) { \
+            (src)+=2; \
+            (result)=(trie)->data[ \
+                ((int32_t)((trie)->index[((__lead-0xe0)<<(12-UTRIE2_SHIFT_2))+ \
+                                         (__t1<<(6-UTRIE2_SHIFT_2))+(__t2>>UTRIE2_SHIFT_2)]) \
+                <<UTRIE2_INDEX_SHIFT)+ \
+                (__t2&UTRIE2_DATA_MASK)]; \
+        } else { \
+            int32_t __index=utrie2_internalU8NextIndex((trie), __lead, (const uint8_t *)(src), \
+                                                                       (const uint8_t *)(limit)); \
+            (src)+=__index&7; \
+            (result)=(trie)->data[__index>>3]; \
+        } \
+    } \
+}
+
+/** Internal UTF-8 pre-decrement-previous: get the previous code point's data. */
+#define _UTRIE2_U8_PREV(trie, ascii, data, start, src, result) { \
+    uint8_t __b=(uint8_t)*--(src); \
+    if(__b<0x80) { \
+        (result)=(trie)->ascii[__b]; \
+    } else { \
+        int32_t __index=utrie2_internalU8PrevIndex((trie), __b, (const uint8_t *)(start), \
+                                                                (const uint8_t *)(src)); \
+        (src)-=__index&7; \
+        (result)=(trie)->data[__index>>3]; \
+    } \
+}
+
+U_CDECL_END
+
+/**
+ * Work around MSVC 2003 optimization bugs.
+ */
+#if defined (U_HAVE_MSVC_2003_OR_EARLIER)
+#pragma optimize("", off)
+#endif
+
+#endif
diff --git a/source/common/utrie2_builder.c b/source/common/utrie2_builder.c
new file mode 100644
index 0000000..1f3c4c1
--- /dev/null
+++ b/source/common/utrie2_builder.c
@@ -0,0 +1,1470 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2001-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  utrie2_builder.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2008sep26 (split off from utrie2.c)
+*   created by: Markus W. Scherer
+*
+*   This is a common implementation of a Unicode trie.
+*   It is a kind of compressed, serializable table of 16- or 32-bit values associated with
+*   Unicode code points (0..0x10ffff).
+*   This is the second common version of a Unicode trie (hence the name UTrie2).
+*   See utrie2.h for a comparison.
+*
+*   This file contains only the builder code.
+*   See utrie2.c for the runtime and enumeration code.
+*/
+#ifdef UTRIE2_DEBUG
+#   include <stdio.h>
+#endif
+
+#include "unicode/utypes.h"
+#include "cmemory.h"
+#include "utrie2.h"
+#include "utrie2_impl.h"
+
+#include "utrie.h" /* for utrie2_fromUTrie() and utrie_swap() */
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+/* Implementation notes ----------------------------------------------------- */
+
+/*
+ * The UTRIE2_SHIFT_1, UTRIE2_SHIFT_2, UTRIE2_INDEX_SHIFT and other values
+ * have been chosen to minimize trie sizes overall.
+ * Most of the code is flexible enough to work with a range of values,
+ * within certain limits.
+ *
+ * Exception: Support for separate values for lead surrogate code _units_
+ * vs. code _points_ was added after the constants were fixed,
+ * and has not been tested nor particularly designed for different constant values.
+ * (Especially the utrie2_enum() code that jumps to the special LSCP index-2
+ * part and back.)
+ *
+ * Requires UTRIE2_SHIFT_2<=6. Otherwise 0xc0 which is the top of the ASCII-linear data
+ * including the bad-UTF-8-data block is not a multiple of UTRIE2_DATA_BLOCK_LENGTH
+ * and map[block>>UTRIE2_SHIFT_2] (used in reference counting and compaction
+ * remapping) stops working.
+ *
+ * Requires UTRIE2_SHIFT_1>=10 because utrie2_enumForLeadSurrogate()
+ * assumes that a single index-2 block is used for 0x400 code points
+ * corresponding to one lead surrogate.
+ *
+ * Requires UTRIE2_SHIFT_1<=16. Otherwise one single index-2 block contains
+ * more than one Unicode plane, and the split of the index-2 table into a BMP
+ * part and a supplementary part, with a gap in between, would not work.
+ *
+ * Requires UTRIE2_INDEX_SHIFT>=1 not because of the code but because
+ * there is data with more than 64k distinct values,
+ * for example for Unihan collation with a separate collation weight per
+ * Han character.
+ */
+
+/* Building a trie ----------------------------------------------------------*/
+
+enum {
+    /** The null index-2 block, following the gap in the index-2 table. */
+    UNEWTRIE2_INDEX_2_NULL_OFFSET=UNEWTRIE2_INDEX_GAP_OFFSET+UNEWTRIE2_INDEX_GAP_LENGTH,
+
+    /** The start of allocated index-2 blocks. */
+    UNEWTRIE2_INDEX_2_START_OFFSET=UNEWTRIE2_INDEX_2_NULL_OFFSET+UTRIE2_INDEX_2_BLOCK_LENGTH,
+
+    /**
+     * The null data block.
+     * Length 64=0x40 even if UTRIE2_DATA_BLOCK_LENGTH is smaller,
+     * to work with 6-bit trail bytes from 2-byte UTF-8.
+     */
+    UNEWTRIE2_DATA_NULL_OFFSET=UTRIE2_DATA_START_OFFSET,
+
+    /** The start of allocated data blocks. */
+    UNEWTRIE2_DATA_START_OFFSET=UNEWTRIE2_DATA_NULL_OFFSET+0x40,
+
+    /**
+     * The start of data blocks for U+0800 and above.
+     * Below, compaction uses a block length of 64 for 2-byte UTF-8.
+     * From here on, compaction uses UTRIE2_DATA_BLOCK_LENGTH.
+     * Data values for 0x780 code points beyond ASCII.
+     */
+    UNEWTRIE2_DATA_0800_OFFSET=UNEWTRIE2_DATA_START_OFFSET+0x780
+};
+
+/* Start with allocation of 16k data entries. */
+#define UNEWTRIE2_INITIAL_DATA_LENGTH ((int32_t)1<<14)
+
+/* Grow about 8x each time. */
+#define UNEWTRIE2_MEDIUM_DATA_LENGTH ((int32_t)1<<17)
+
+static int32_t
+allocIndex2Block(UNewTrie2 *trie);
+
+U_CAPI UTrie2 * U_EXPORT2
+utrie2_open(uint32_t initialValue, uint32_t errorValue, UErrorCode *pErrorCode) {
+    UTrie2 *trie;
+    UNewTrie2 *newTrie;
+    uint32_t *data;
+    int32_t i, j;
+
+    if(U_FAILURE(*pErrorCode)) {
+        return NULL;
+    }
+
+    trie=(UTrie2 *)uprv_malloc(sizeof(UTrie2));
+    newTrie=(UNewTrie2 *)uprv_malloc(sizeof(UNewTrie2));
+    data=(uint32_t *)uprv_malloc(UNEWTRIE2_INITIAL_DATA_LENGTH*4);
+    if(trie==NULL || newTrie==NULL || data==NULL) {
+        uprv_free(trie);
+        uprv_free(newTrie);
+        uprv_free(data);
+        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
+
+    uprv_memset(trie, 0, sizeof(UTrie2));
+    trie->initialValue=initialValue;
+    trie->errorValue=errorValue;
+    trie->highStart=0x110000;
+    trie->newTrie=newTrie;
+
+    newTrie->data=data;
+    newTrie->dataCapacity=UNEWTRIE2_INITIAL_DATA_LENGTH;
+    newTrie->initialValue=initialValue;
+    newTrie->errorValue=errorValue;
+    newTrie->highStart=0x110000;
+    newTrie->firstFreeBlock=0;  /* no free block in the list */
+    newTrie->isCompacted=FALSE;
+
+    /*
+     * preallocate and reset
+     * - ASCII
+     * - the bad-UTF-8-data block
+     * - the null data block
+     */
+    for(i=0; i<0x80; ++i) {
+        newTrie->data[i]=initialValue;
+    }
+    for(; i<0xc0; ++i) {
+        newTrie->data[i]=errorValue;
+    }
+    for(i=UNEWTRIE2_DATA_NULL_OFFSET; i<UNEWTRIE2_DATA_START_OFFSET; ++i) {
+        newTrie->data[i]=initialValue;
+    }
+    newTrie->dataNullOffset=UNEWTRIE2_DATA_NULL_OFFSET;
+    newTrie->dataLength=UNEWTRIE2_DATA_START_OFFSET;
+
+    /* set the index-2 indexes for the 2=0x80>>UTRIE2_SHIFT_2 ASCII data blocks */
+    for(i=0, j=0; j<0x80; ++i, j+=UTRIE2_DATA_BLOCK_LENGTH) {
+        newTrie->index2[i]=j;
+        newTrie->map[i]=1;
+    }
+    /* reference counts for the bad-UTF-8-data block */
+    for(; j<0xc0; ++i, j+=UTRIE2_DATA_BLOCK_LENGTH) {
+        newTrie->map[i]=0;
+    }
+    /*
+     * Reference counts for the null data block: all blocks except for the ASCII blocks.
+     * Plus 1 so that we don't drop this block during compaction.
+     * Plus as many as needed for lead surrogate code points.
+     */
+    /* i==newTrie->dataNullOffset */
+    newTrie->map[i++]=
+        (0x110000>>UTRIE2_SHIFT_2)-
+        (0x80>>UTRIE2_SHIFT_2)+
+        1+
+        UTRIE2_LSCP_INDEX_2_LENGTH;
+    j+=UTRIE2_DATA_BLOCK_LENGTH;
+    for(; j<UNEWTRIE2_DATA_START_OFFSET; ++i, j+=UTRIE2_DATA_BLOCK_LENGTH) {
+        newTrie->map[i]=0;
+    }
+
+    /*
+     * set the remaining indexes in the BMP index-2 block
+     * to the null data block
+     */
+    for(i=0x80>>UTRIE2_SHIFT_2; i<UTRIE2_INDEX_2_BMP_LENGTH; ++i) {
+        newTrie->index2[i]=UNEWTRIE2_DATA_NULL_OFFSET;
+    }
+
+    /*
+     * Fill the index gap with impossible values so that compaction
+     * does not overlap other index-2 blocks with the gap.
+     */
+    for(i=0; i<UNEWTRIE2_INDEX_GAP_LENGTH; ++i) {
+        newTrie->index2[UNEWTRIE2_INDEX_GAP_OFFSET+i]=-1;
+    }
+
+    /* set the indexes in the null index-2 block */
+    for(i=0; i<UTRIE2_INDEX_2_BLOCK_LENGTH; ++i) {
+        newTrie->index2[UNEWTRIE2_INDEX_2_NULL_OFFSET+i]=UNEWTRIE2_DATA_NULL_OFFSET;
+    }
+    newTrie->index2NullOffset=UNEWTRIE2_INDEX_2_NULL_OFFSET;
+    newTrie->index2Length=UNEWTRIE2_INDEX_2_START_OFFSET;
+
+    /* set the index-1 indexes for the linear index-2 block */
+    for(i=0, j=0;
+        i<UTRIE2_OMITTED_BMP_INDEX_1_LENGTH;
+        ++i, j+=UTRIE2_INDEX_2_BLOCK_LENGTH
+    ) {
+        newTrie->index1[i]=j;
+    }
+
+    /* set the remaining index-1 indexes to the null index-2 block */
+    for(; i<UNEWTRIE2_INDEX_1_LENGTH; ++i) {
+        newTrie->index1[i]=UNEWTRIE2_INDEX_2_NULL_OFFSET;
+    }
+
+    /*
+     * Preallocate and reset data for U+0080..U+07ff,
+     * for 2-byte UTF-8 which will be compacted in 64-blocks
+     * even if UTRIE2_DATA_BLOCK_LENGTH is smaller.
+     */
+    for(i=0x80; i<0x800; i+=UTRIE2_DATA_BLOCK_LENGTH) {
+        utrie2_set32(trie, i, initialValue, pErrorCode);
+    }
+
+    return trie;
+}
+
+static UNewTrie2 *
+cloneBuilder(const UNewTrie2 *other) {
+    UNewTrie2 *trie;
+
+    trie=(UNewTrie2 *)uprv_malloc(sizeof(UNewTrie2));
+    if(trie==NULL) {
+        return NULL;
+    }
+
+    trie->data=(uint32_t *)uprv_malloc(other->dataCapacity*4);
+    if(trie->data==NULL) {
+        uprv_free(trie);
+        return NULL;
+    }
+    trie->dataCapacity=other->dataCapacity;
+
+    /* clone data */
+    uprv_memcpy(trie->index1, other->index1, sizeof(trie->index1));
+    uprv_memcpy(trie->index2, other->index2, other->index2Length*4);
+    trie->index2NullOffset=other->index2NullOffset;
+    trie->index2Length=other->index2Length;
+
+    uprv_memcpy(trie->data, other->data, other->dataLength*4);
+    trie->dataNullOffset=other->dataNullOffset;
+    trie->dataLength=other->dataLength;
+
+    /* reference counters */
+    if(other->isCompacted) {
+        trie->firstFreeBlock=0;
+    } else {
+        uprv_memcpy(trie->map, other->map, (other->dataLength>>UTRIE2_SHIFT_2)*4);
+        trie->firstFreeBlock=other->firstFreeBlock;
+    }
+
+    trie->initialValue=other->initialValue;
+    trie->errorValue=other->errorValue;
+    trie->highStart=other->highStart;
+    trie->isCompacted=other->isCompacted;
+
+    return trie;
+}
+
+U_CAPI UTrie2 * U_EXPORT2
+utrie2_clone(const UTrie2 *other, UErrorCode *pErrorCode) {
+    UTrie2 *trie;
+
+    if(U_FAILURE(*pErrorCode)) {
+        return NULL;
+    }
+    if(other==NULL || (other->memory==NULL && other->newTrie==NULL)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    trie=(UTrie2 *)uprv_malloc(sizeof(UTrie2));
+    if(trie==NULL) {
+        return NULL;
+    }
+    uprv_memcpy(trie, other, sizeof(UTrie2));
+
+    if(other->memory!=NULL) {
+        trie->memory=uprv_malloc(other->length);
+        if(trie->memory!=NULL) {
+            trie->isMemoryOwned=TRUE;
+            uprv_memcpy(trie->memory, other->memory, other->length);
+
+            /* make the clone's pointers point to its own memory */
+            trie->index=(uint16_t *)trie->memory+(other->index-(uint16_t *)other->memory);
+            if(other->data16!=NULL) {
+                trie->data16=(uint16_t *)trie->memory+(other->data16-(uint16_t *)other->memory);
+            }
+            if(other->data32!=NULL) {
+                trie->data32=(uint32_t *)trie->memory+(other->data32-(uint32_t *)other->memory);
+            }
+        }
+    } else /* other->newTrie!=NULL */ {
+        trie->newTrie=cloneBuilder(other->newTrie);
+    }
+
+    if(trie->memory==NULL && trie->newTrie==NULL) {
+        uprv_free(trie);
+        trie=NULL;
+    }
+    return trie;
+}
+
+typedef struct NewTrieAndStatus {
+    UTrie2 *trie;
+    UErrorCode errorCode;
+    UBool exclusiveLimit;  /* rather than inclusive range end */
+} NewTrieAndStatus;
+
+static UBool U_CALLCONV
+copyEnumRange(const void *context, UChar32 start, UChar32 end, uint32_t value) {
+    NewTrieAndStatus *nt=(NewTrieAndStatus *)context;
+    if(value!=nt->trie->initialValue) {
+        if(nt->exclusiveLimit) {
+            --end;
+        }
+        if(start==end) {
+            utrie2_set32(nt->trie, start, value, &nt->errorCode);
+        } else {
+            utrie2_setRange32(nt->trie, start, end, value, TRUE, &nt->errorCode);
+        }
+        return U_SUCCESS(nt->errorCode);
+    } else {
+        return TRUE;
+    }
+}
+
+#ifdef UTRIE2_DEBUG
+static void
+utrie_printLengths(const UTrie *trie) {
+    long indexLength=trie->indexLength;
+    long dataLength=(long)trie->dataLength;
+    long totalLength=(long)sizeof(UTrieHeader)+indexLength*2+dataLength*(trie->data32!=NULL ? 4 : 2);
+    printf("**UTrieLengths** index:%6ld  data:%6ld  serialized:%6ld\n",
+           indexLength, dataLength, totalLength);
+}
+
+static void
+utrie2_printLengths(const UTrie2 *trie, const char *which) {
+    long indexLength=trie->indexLength;
+    long dataLength=(long)trie->dataLength;
+    long totalLength=(long)sizeof(UTrie2Header)+indexLength*2+dataLength*(trie->data32!=NULL ? 4 : 2);
+    printf("**UTrie2Lengths(%s)** index:%6ld  data:%6ld  serialized:%6ld\n",
+           which, indexLength, dataLength, totalLength);
+}
+#endif
+
+U_CAPI UTrie2 * U_EXPORT2
+utrie2_cloneAsThawed(const UTrie2 *other, UErrorCode *pErrorCode) {
+    NewTrieAndStatus context;
+    UChar lead;
+
+    if(U_FAILURE(*pErrorCode)) {
+        return NULL;
+    }
+    if(other==NULL || (other->memory==NULL && other->newTrie==NULL)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+    if(other->newTrie!=NULL && !other->newTrie->isCompacted) {
+        return utrie2_clone(other, pErrorCode);  /* clone an unfrozen trie */
+    }
+
+    /* Clone the frozen trie by enumerating it and building a new one. */
+    context.trie=utrie2_open(other->initialValue, other->errorValue, pErrorCode);
+    if(U_FAILURE(*pErrorCode)) {
+        return NULL;
+    }
+    context.exclusiveLimit=FALSE;
+    context.errorCode=*pErrorCode;
+    utrie2_enum(other, NULL, copyEnumRange, &context);
+    *pErrorCode=context.errorCode;
+    for(lead=0xd800; lead<0xdc00; ++lead) {
+        uint32_t value;
+        if(other->data32==NULL) {
+            value=UTRIE2_GET16_FROM_U16_SINGLE_LEAD(other, lead);
+        } else {
+            value=UTRIE2_GET32_FROM_U16_SINGLE_LEAD(other, lead);
+        }
+        if(value!=other->initialValue) {
+            utrie2_set32ForLeadSurrogateCodeUnit(context.trie, lead, value, pErrorCode);
+        }
+    }
+    if(U_FAILURE(*pErrorCode)) {
+        utrie2_close(context.trie);
+        context.trie=NULL;
+    }
+    return context.trie;
+}
+
+/* Almost the same as utrie2_cloneAsThawed() but copies a UTrie and freezes the clone. */
+U_CAPI UTrie2 * U_EXPORT2
+utrie2_fromUTrie(const UTrie *trie1, uint32_t errorValue, UErrorCode *pErrorCode) {
+    NewTrieAndStatus context;
+    UChar lead;
+
+    if(U_FAILURE(*pErrorCode)) {
+        return NULL;
+    }
+    if(trie1==NULL) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+    context.trie=utrie2_open(trie1->initialValue, errorValue, pErrorCode);
+    if(U_FAILURE(*pErrorCode)) {
+        return NULL;
+    }
+    context.exclusiveLimit=TRUE;
+    context.errorCode=*pErrorCode;
+    utrie_enum(trie1, NULL, copyEnumRange, &context);
+    *pErrorCode=context.errorCode;
+    for(lead=0xd800; lead<0xdc00; ++lead) {
+        uint32_t value;
+        if(trie1->data32==NULL) {
+            value=UTRIE_GET16_FROM_LEAD(trie1, lead);
+        } else {
+            value=UTRIE_GET32_FROM_LEAD(trie1, lead);
+        }
+        if(value!=trie1->initialValue) {
+            utrie2_set32ForLeadSurrogateCodeUnit(context.trie, lead, value, pErrorCode);
+        }
+    }
+    if(U_SUCCESS(*pErrorCode)) {
+        utrie2_freeze(context.trie,
+                      trie1->data32!=NULL ? UTRIE2_32_VALUE_BITS : UTRIE2_16_VALUE_BITS,
+                      pErrorCode);
+    }
+#ifdef UTRIE2_DEBUG
+    if(U_SUCCESS(*pErrorCode)) {
+        utrie_printLengths(trie1);
+        utrie2_printLengths(context.trie, "fromUTrie");
+    }
+#endif
+    if(U_FAILURE(*pErrorCode)) {
+        utrie2_close(context.trie);
+        context.trie=NULL;
+    }
+    return context.trie;
+}
+
+static U_INLINE UBool
+isInNullBlock(UNewTrie2 *trie, UChar32 c, UBool forLSCP) {
+    int32_t i2, block;
+
+    if(U_IS_LEAD(c) && forLSCP) {
+        i2=(UTRIE2_LSCP_INDEX_2_OFFSET-(0xd800>>UTRIE2_SHIFT_2))+
+            (c>>UTRIE2_SHIFT_2);
+    } else {
+        i2=trie->index1[c>>UTRIE2_SHIFT_1]+
+            ((c>>UTRIE2_SHIFT_2)&UTRIE2_INDEX_2_MASK);
+    }
+    block=trie->index2[i2];
+    return (UBool)(block==trie->dataNullOffset);
+}
+
+static int32_t
+allocIndex2Block(UNewTrie2 *trie) {
+    int32_t newBlock, newTop;
+
+    newBlock=trie->index2Length;
+    newTop=newBlock+UTRIE2_INDEX_2_BLOCK_LENGTH;
+    if(newTop>LENGTHOF(trie->index2)) {
+        /*
+         * Should never occur.
+         * Either UTRIE2_MAX_BUILD_TIME_INDEX_LENGTH is incorrect,
+         * or the code writes more values than should be possible.
+         */
+        return -1;
+    }
+    trie->index2Length=newTop;
+    uprv_memcpy(trie->index2+newBlock, trie->index2+trie->index2NullOffset, UTRIE2_INDEX_2_BLOCK_LENGTH*4);
+    return newBlock;
+}
+
+static int32_t
+getIndex2Block(UNewTrie2 *trie, UChar32 c, UBool forLSCP) {
+    int32_t i1, i2;
+
+    if(U_IS_LEAD(c) && forLSCP) {
+        return UTRIE2_LSCP_INDEX_2_OFFSET;
+    }
+
+    i1=c>>UTRIE2_SHIFT_1;
+    i2=trie->index1[i1];
+    if(i2==trie->index2NullOffset) {
+        i2=allocIndex2Block(trie);
+        if(i2<0) {
+            return -1;  /* program error */
+        }
+        trie->index1[i1]=i2;
+    }
+    return i2;
+}
+
+static int32_t
+allocDataBlock(UNewTrie2 *trie, int32_t copyBlock) {
+    int32_t newBlock, newTop;
+
+    if(trie->firstFreeBlock!=0) {
+        /* get the first free block */
+        newBlock=trie->firstFreeBlock;
+        trie->firstFreeBlock=-trie->map[newBlock>>UTRIE2_SHIFT_2];
+    } else {
+        /* get a new block from the high end */
+        newBlock=trie->dataLength;
+        newTop=newBlock+UTRIE2_DATA_BLOCK_LENGTH;
+        if(newTop>trie->dataCapacity) {
+            /* out of memory in the data array */
+            int32_t capacity;
+            uint32_t *data;
+
+            if(trie->dataCapacity<UNEWTRIE2_MEDIUM_DATA_LENGTH) {
+                capacity=UNEWTRIE2_MEDIUM_DATA_LENGTH;
+            } else if(trie->dataCapacity<UNEWTRIE2_MAX_DATA_LENGTH) {
+                capacity=UNEWTRIE2_MAX_DATA_LENGTH;
+            } else {
+                /*
+                 * Should never occur.
+                 * Either UNEWTRIE2_MAX_DATA_LENGTH is incorrect,
+                 * or the code writes more values than should be possible.
+                 */
+                return -1;
+            }
+            data=(uint32_t *)uprv_malloc(capacity*4);
+            if(data==NULL) {
+                return -1;
+            }
+            uprv_memcpy(data, trie->data, trie->dataLength*4);
+            uprv_free(trie->data);
+            trie->data=data;
+            trie->dataCapacity=capacity;
+        }
+        trie->dataLength=newTop;
+    }
+    uprv_memcpy(trie->data+newBlock, trie->data+copyBlock, UTRIE2_DATA_BLOCK_LENGTH*4);
+    trie->map[newBlock>>UTRIE2_SHIFT_2]=0;
+    return newBlock;
+}
+
+/* call when the block's reference counter reaches 0 */
+static void
+releaseDataBlock(UNewTrie2 *trie, int32_t block) {
+    /* put this block at the front of the free-block chain */
+    trie->map[block>>UTRIE2_SHIFT_2]=-trie->firstFreeBlock;
+    trie->firstFreeBlock=block;
+}
+
+static U_INLINE UBool
+isWritableBlock(UNewTrie2 *trie, int32_t block) {
+    return (UBool)(block!=trie->dataNullOffset && 1==trie->map[block>>UTRIE2_SHIFT_2]);
+}
+
+static U_INLINE void
+setIndex2Entry(UNewTrie2 *trie, int32_t i2, int32_t block) {
+    int32_t oldBlock;
+    ++trie->map[block>>UTRIE2_SHIFT_2];  /* increment first, in case block==oldBlock! */
+    oldBlock=trie->index2[i2];
+    if(0 == --trie->map[oldBlock>>UTRIE2_SHIFT_2]) {
+        releaseDataBlock(trie, oldBlock);
+    }
+    trie->index2[i2]=block;
+}
+
+/**
+ * No error checking for illegal arguments.
+ *
+ * @return -1 if no new data block available (out of memory in data array)
+ * @internal
+ */
+static int32_t
+getDataBlock(UNewTrie2 *trie, UChar32 c, UBool forLSCP) {
+    int32_t i2, oldBlock, newBlock;
+
+    i2=getIndex2Block(trie, c, forLSCP);
+    if(i2<0) {
+        return -1;  /* program error */
+    }
+
+    i2+=(c>>UTRIE2_SHIFT_2)&UTRIE2_INDEX_2_MASK;
+    oldBlock=trie->index2[i2];
+    if(isWritableBlock(trie, oldBlock)) {
+        return oldBlock;
+    }
+
+    /* allocate a new data block */
+    newBlock=allocDataBlock(trie, oldBlock);
+    if(newBlock<0) {
+        /* out of memory in the data array */
+        return -1;
+    }
+    setIndex2Entry(trie, i2, newBlock);
+    return newBlock;
+}
+
+/**
+ * @return TRUE if the value was successfully set
+ */
+static void
+set32(UNewTrie2 *trie,
+      UChar32 c, UBool forLSCP, uint32_t value,
+      UErrorCode *pErrorCode) {
+    int32_t block;
+
+    if(trie==NULL || trie->isCompacted) {
+        *pErrorCode=U_NO_WRITE_PERMISSION;
+        return;
+    }
+
+    block=getDataBlock(trie, c, forLSCP);
+    if(block<0) {
+        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+
+    trie->data[block+(c&UTRIE2_DATA_MASK)]=value;
+}
+
+U_CAPI void U_EXPORT2
+utrie2_set32(UTrie2 *trie, UChar32 c, uint32_t value, UErrorCode *pErrorCode) {
+    if(U_FAILURE(*pErrorCode)) {
+        return;
+    }
+    if((uint32_t)c>0x10ffff) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    set32(trie->newTrie, c, TRUE, value, pErrorCode);
+}
+
+U_CAPI void U_EXPORT2
+utrie2_set32ForLeadSurrogateCodeUnit(UTrie2 *trie,
+                                     UChar32 c, uint32_t value,
+                                     UErrorCode *pErrorCode) {
+    if(U_FAILURE(*pErrorCode)) {
+        return;
+    }
+    if(!U_IS_LEAD(c)) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    set32(trie->newTrie, c, FALSE, value, pErrorCode);
+}
+
+static void
+writeBlock(uint32_t *block, uint32_t value) {
+    uint32_t *limit=block+UTRIE2_DATA_BLOCK_LENGTH;
+    while(block<limit) {
+        *block++=value;
+    }
+}
+
+/**
+ * initialValue is ignored if overwrite=TRUE
+ * @internal
+ */
+static void
+fillBlock(uint32_t *block, UChar32 start, UChar32 limit,
+          uint32_t value, uint32_t initialValue, UBool overwrite) {
+    uint32_t *pLimit;
+
+    pLimit=block+limit;
+    block+=start;
+    if(overwrite) {
+        while(block<pLimit) {
+            *block++=value;
+        }
+    } else {
+        while(block<pLimit) {
+            if(*block==initialValue) {
+                *block=value;
+            }
+            ++block;
+        }
+    }
+}
+
+U_CAPI void U_EXPORT2
+utrie2_setRange32(UTrie2 *trie,
+                  UChar32 start, UChar32 end,
+                  uint32_t value, UBool overwrite,
+                  UErrorCode *pErrorCode) {
+    /*
+     * repeat value in [start..end]
+     * mark index values for repeat-data blocks by setting bit 31 of the index values
+     * fill around existing values if any, if(overwrite)
+     */
+    UNewTrie2 *newTrie;
+    int32_t block, rest, repeatBlock;
+    UChar32 limit;
+
+    if(U_FAILURE(*pErrorCode)) {
+        return;
+    }
+    if((uint32_t)start>0x10ffff || (uint32_t)end>0x10ffff || start>end) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    newTrie=trie->newTrie;
+    if(newTrie==NULL || newTrie->isCompacted) {
+        *pErrorCode=U_NO_WRITE_PERMISSION;
+        return;
+    }
+    if(!overwrite && value==newTrie->initialValue) {
+        return; /* nothing to do */
+    }
+
+    limit=end+1;
+    if(start&UTRIE2_DATA_MASK) {
+        UChar32 nextStart;
+
+        /* set partial block at [start..following block boundary[ */
+        block=getDataBlock(newTrie, start, TRUE);
+        if(block<0) {
+            *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+
+        nextStart=(start+UTRIE2_DATA_BLOCK_LENGTH)&~UTRIE2_DATA_MASK;
+        if(nextStart<=limit) {
+            fillBlock(newTrie->data+block, start&UTRIE2_DATA_MASK, UTRIE2_DATA_BLOCK_LENGTH,
+                      value, newTrie->initialValue, overwrite);
+            start=nextStart;
+        } else {
+            fillBlock(newTrie->data+block, start&UTRIE2_DATA_MASK, limit&UTRIE2_DATA_MASK,
+                      value, newTrie->initialValue, overwrite);
+            return;
+        }
+    }
+
+    /* number of positions in the last, partial block */
+    rest=limit&UTRIE2_DATA_MASK;
+
+    /* round down limit to a block boundary */
+    limit&=~UTRIE2_DATA_MASK;
+
+    /* iterate over all-value blocks */
+    if(value==newTrie->initialValue) {
+        repeatBlock=newTrie->dataNullOffset;
+    } else {
+        repeatBlock=-1;
+    }
+
+    while(start<limit) {
+        int32_t i2;
+        UBool setRepeatBlock=FALSE;
+
+        if(value==newTrie->initialValue && isInNullBlock(newTrie, start, TRUE)) {
+            start+=UTRIE2_DATA_BLOCK_LENGTH; /* nothing to do */
+            continue;
+        }
+
+        /* get index value */
+        i2=getIndex2Block(newTrie, start, TRUE);
+        if(i2<0) {
+            *pErrorCode=U_INTERNAL_PROGRAM_ERROR;
+            return;
+        }
+        i2+=(start>>UTRIE2_SHIFT_2)&UTRIE2_INDEX_2_MASK;
+        block=newTrie->index2[i2];
+        if(isWritableBlock(newTrie, block)) {
+            /* already allocated */
+            if(overwrite && block>=UNEWTRIE2_DATA_0800_OFFSET) {
+                /*
+                 * We overwrite all values, and it's not a
+                 * protected (ASCII-linear or 2-byte UTF-8) block:
+                 * replace with the repeatBlock.
+                 */
+                setRepeatBlock=TRUE;
+            } else {
+                /* !overwrite, or protected block: just write the values into this block */
+                fillBlock(newTrie->data+block,
+                          0, UTRIE2_DATA_BLOCK_LENGTH,
+                          value, newTrie->initialValue, overwrite);
+            }
+        } else if(newTrie->data[block]!=value && (overwrite || block==newTrie->dataNullOffset)) {
+            /*
+             * Set the repeatBlock instead of the null block or previous repeat block:
+             *
+             * If !isWritableBlock() then all entries in the block have the same value
+             * because it's the null block or a range block (the repeatBlock from a previous
+             * call to utrie2_setRange32()).
+             * No other blocks are used multiple times before compacting.
+             *
+             * The null block is the only non-writable block with the initialValue because
+             * of the repeatBlock initialization above. (If value==initialValue, then
+             * the repeatBlock will be the null data block.)
+             *
+             * We set our repeatBlock if the desired value differs from the block's value,
+             * and if we overwrite any data or if the data is all initial values
+             * (which is the same as the block being the null block, see above).
+             */
+            setRepeatBlock=TRUE;
+        }
+        if(setRepeatBlock) {
+            if(repeatBlock>=0) {
+                setIndex2Entry(newTrie, i2, repeatBlock);
+            } else {
+                /* create and set and fill the repeatBlock */
+                repeatBlock=getDataBlock(newTrie, start, TRUE);
+                if(repeatBlock<0) {
+                    *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+                    return;
+                }
+                writeBlock(newTrie->data+repeatBlock, value);
+            }
+        }
+
+        start+=UTRIE2_DATA_BLOCK_LENGTH;
+    }
+
+    if(rest>0) {
+        /* set partial block at [last block boundary..limit[ */
+        block=getDataBlock(newTrie, start, TRUE);
+        if(block<0) {
+            *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+
+        fillBlock(newTrie->data+block, 0, rest, value, newTrie->initialValue, overwrite);
+    }
+
+    return;
+}
+
+/* compaction --------------------------------------------------------------- */
+
+static U_INLINE UBool
+equal_int32(const int32_t *s, const int32_t *t, int32_t length) {
+    while(length>0 && *s==*t) {
+        ++s;
+        ++t;
+        --length;
+    }
+    return (UBool)(length==0);
+}
+
+static U_INLINE UBool
+equal_uint32(const uint32_t *s, const uint32_t *t, int32_t length) {
+    while(length>0 && *s==*t) {
+        ++s;
+        ++t;
+        --length;
+    }
+    return (UBool)(length==0);
+}
+
+static int32_t
+findSameIndex2Block(const int32_t *idx, int32_t index2Length, int32_t otherBlock) {
+    int32_t block;
+
+    /* ensure that we do not even partially get past index2Length */
+    index2Length-=UTRIE2_INDEX_2_BLOCK_LENGTH;
+
+    for(block=0; block<=index2Length; ++block) {
+        if(equal_int32(idx+block, idx+otherBlock, UTRIE2_INDEX_2_BLOCK_LENGTH)) {
+            return block;
+        }
+    }
+    return -1;
+}
+
+static int32_t
+findSameDataBlock(const uint32_t *data, int32_t dataLength, int32_t otherBlock, int32_t blockLength) {
+    int32_t block;
+
+    /* ensure that we do not even partially get past dataLength */
+    dataLength-=blockLength;
+
+    for(block=0; block<=dataLength; block+=UTRIE2_DATA_GRANULARITY) {
+        if(equal_uint32(data+block, data+otherBlock, blockLength)) {
+            return block;
+        }
+    }
+    return -1;
+}
+
+/*
+ * Find the start of the last range in the trie by enumerating backward.
+ * Indexes for supplementary code points higher than this will be omitted.
+ */
+static UChar32
+findHighStart(UNewTrie2 *trie, uint32_t highValue) {
+    const uint32_t *data32;
+
+    uint32_t value, initialValue;
+    UChar32 c, prev;
+    int32_t i1, i2, j, i2Block, prevI2Block, index2NullOffset, block, prevBlock, nullBlock;
+
+    data32=trie->data;
+    initialValue=trie->initialValue;
+
+    index2NullOffset=trie->index2NullOffset;
+    nullBlock=trie->dataNullOffset;
+
+    /* set variables for previous range */
+    if(highValue==initialValue) {
+        prevI2Block=index2NullOffset;
+        prevBlock=nullBlock;
+    } else {
+        prevI2Block=-1;
+        prevBlock=-1;
+    }
+    prev=0x110000;
+
+    /* enumerate index-2 blocks */
+    i1=UNEWTRIE2_INDEX_1_LENGTH;
+    c=prev;
+    while(c>0) {
+        i2Block=trie->index1[--i1];
+        if(i2Block==prevI2Block) {
+            /* the index-2 block is the same as the previous one, and filled with highValue */
+            c-=UTRIE2_CP_PER_INDEX_1_ENTRY;
+            continue;
+        }
+        prevI2Block=i2Block;
+        if(i2Block==index2NullOffset) {
+            /* this is the null index-2 block */
+            if(highValue!=initialValue) {
+                return c;
+            }
+            c-=UTRIE2_CP_PER_INDEX_1_ENTRY;
+        } else {
+            /* enumerate data blocks for one index-2 block */
+            for(i2=UTRIE2_INDEX_2_BLOCK_LENGTH; i2>0;) {
+                block=trie->index2[i2Block+ --i2];
+                if(block==prevBlock) {
+                    /* the block is the same as the previous one, and filled with highValue */
+                    c-=UTRIE2_DATA_BLOCK_LENGTH;
+                    continue;
+                }
+                prevBlock=block;
+                if(block==nullBlock) {
+                    /* this is the null data block */
+                    if(highValue!=initialValue) {
+                        return c;
+                    }
+                    c-=UTRIE2_DATA_BLOCK_LENGTH;
+                } else {
+                    for(j=UTRIE2_DATA_BLOCK_LENGTH; j>0;) {
+                        value=data32[block+ --j];
+                        if(value!=highValue) {
+                            return c;
+                        }
+                        --c;
+                    }
+                }
+            }
+        }
+    }
+
+    /* deliver last range */
+    return 0;
+}
+
+/*
+ * Compact a build-time trie.
+ *
+ * The compaction
+ * - removes blocks that are identical with earlier ones
+ * - overlaps adjacent blocks as much as possible (if overlap==TRUE)
+ * - moves blocks in steps of the data granularity
+ * - moves and overlaps blocks that overlap with multiple values in the overlap region
+ *
+ * It does not
+ * - try to move and overlap blocks that are not already adjacent
+ */
+static void
+compactData(UNewTrie2 *trie) {
+    int32_t start, newStart, movedStart;
+    int32_t blockLength, overlap;
+    int32_t i, mapIndex, blockCount;
+
+    /* do not compact linear-ASCII data */
+    newStart=UTRIE2_DATA_START_OFFSET;
+    for(start=0, i=0; start<newStart; start+=UTRIE2_DATA_BLOCK_LENGTH, ++i) {
+        trie->map[i]=start;
+    }
+
+    /*
+     * Start with a block length of 64 for 2-byte UTF-8,
+     * then switch to UTRIE2_DATA_BLOCK_LENGTH.
+     */
+    blockLength=64;
+    blockCount=blockLength>>UTRIE2_SHIFT_2;
+    for(start=newStart; start<trie->dataLength;) {
+        /*
+         * start: index of first entry of current block
+         * newStart: index where the current block is to be moved
+         *           (right after current end of already-compacted data)
+         */
+        if(start==UNEWTRIE2_DATA_0800_OFFSET) {
+            blockLength=UTRIE2_DATA_BLOCK_LENGTH;
+            blockCount=1;
+        }
+
+        /* skip blocks that are not used */
+        if(trie->map[start>>UTRIE2_SHIFT_2]<=0) {
+            /* advance start to the next block */
+            start+=blockLength;
+
+            /* leave newStart with the previous block! */
+            continue;
+        }
+
+        /* search for an identical block */
+        if( (movedStart=findSameDataBlock(trie->data, newStart, start, blockLength))
+             >=0
+        ) {
+            /* found an identical block, set the other block's index value for the current block */
+            for(i=blockCount, mapIndex=start>>UTRIE2_SHIFT_2; i>0; --i) {
+                trie->map[mapIndex++]=movedStart;
+                movedStart+=UTRIE2_DATA_BLOCK_LENGTH;
+            }
+
+            /* advance start to the next block */
+            start+=blockLength;
+
+            /* leave newStart with the previous block! */
+            continue;
+        }
+
+        /* see if the beginning of this block can be overlapped with the end of the previous block */
+        /* look for maximum overlap (modulo granularity) with the previous, adjacent block */
+        for(overlap=blockLength-UTRIE2_DATA_GRANULARITY;
+            overlap>0 && !equal_uint32(trie->data+(newStart-overlap), trie->data+start, overlap);
+            overlap-=UTRIE2_DATA_GRANULARITY) {}
+
+        if(overlap>0 || newStart<start) {
+            /* some overlap, or just move the whole block */
+            movedStart=newStart-overlap;
+            for(i=blockCount, mapIndex=start>>UTRIE2_SHIFT_2; i>0; --i) {
+                trie->map[mapIndex++]=movedStart;
+                movedStart+=UTRIE2_DATA_BLOCK_LENGTH;
+            }
+
+            /* move the non-overlapping indexes to their new positions */
+            start+=overlap;
+            for(i=blockLength-overlap; i>0; --i) {
+                trie->data[newStart++]=trie->data[start++];
+            }
+        } else /* no overlap && newStart==start */ {
+            for(i=blockCount, mapIndex=start>>UTRIE2_SHIFT_2; i>0; --i) {
+                trie->map[mapIndex++]=start;
+                start+=UTRIE2_DATA_BLOCK_LENGTH;
+            }
+            newStart=start;
+        }
+    }
+
+    /* now adjust the index-2 table */
+    for(i=0; i<trie->index2Length; ++i) {
+        if(i==UNEWTRIE2_INDEX_GAP_OFFSET) {
+            /* Gap indexes are invalid (-1). Skip over the gap. */
+            i+=UNEWTRIE2_INDEX_GAP_LENGTH;
+        }
+        trie->index2[i]=trie->map[trie->index2[i]>>UTRIE2_SHIFT_2];
+    }
+    trie->dataNullOffset=trie->map[trie->dataNullOffset>>UTRIE2_SHIFT_2];
+
+    /* ensure dataLength alignment */
+    while((newStart&(UTRIE2_DATA_GRANULARITY-1))!=0) {
+        trie->data[newStart++]=trie->initialValue;
+    }
+
+#ifdef UTRIE2_DEBUG
+    /* we saved some space */
+    printf("compacting UTrie2: count of 32-bit data words %lu->%lu\n",
+            (long)trie->dataLength, (long)newStart);
+#endif
+
+    trie->dataLength=newStart;
+}
+
+static void
+compactIndex2(UNewTrie2 *trie) {
+    int32_t i, start, newStart, movedStart, overlap;
+
+    /* do not compact linear-BMP index-2 blocks */
+    newStart=UTRIE2_INDEX_2_BMP_LENGTH;
+    for(start=0, i=0; start<newStart; start+=UTRIE2_INDEX_2_BLOCK_LENGTH, ++i) {
+        trie->map[i]=start;
+    }
+
+    /* Reduce the index table gap to what will be needed at runtime. */
+    newStart+=UTRIE2_UTF8_2B_INDEX_2_LENGTH+((trie->highStart-0x10000)>>UTRIE2_SHIFT_1);
+
+    for(start=UNEWTRIE2_INDEX_2_NULL_OFFSET; start<trie->index2Length;) {
+        /*
+         * start: index of first entry of current block
+         * newStart: index where the current block is to be moved
+         *           (right after current end of already-compacted data)
+         */
+
+        /* search for an identical block */
+        if( (movedStart=findSameIndex2Block(trie->index2, newStart, start))
+             >=0
+        ) {
+            /* found an identical block, set the other block's index value for the current block */
+            trie->map[start>>UTRIE2_SHIFT_1_2]=movedStart;
+
+            /* advance start to the next block */
+            start+=UTRIE2_INDEX_2_BLOCK_LENGTH;
+
+            /* leave newStart with the previous block! */
+            continue;
+        }
+
+        /* see if the beginning of this block can be overlapped with the end of the previous block */
+        /* look for maximum overlap with the previous, adjacent block */
+        for(overlap=UTRIE2_INDEX_2_BLOCK_LENGTH-1;
+            overlap>0 && !equal_int32(trie->index2+(newStart-overlap), trie->index2+start, overlap);
+            --overlap) {}
+
+        if(overlap>0 || newStart<start) {
+            /* some overlap, or just move the whole block */
+            trie->map[start>>UTRIE2_SHIFT_1_2]=newStart-overlap;
+
+            /* move the non-overlapping indexes to their new positions */
+            start+=overlap;
+            for(i=UTRIE2_INDEX_2_BLOCK_LENGTH-overlap; i>0; --i) {
+                trie->index2[newStart++]=trie->index2[start++];
+            }
+        } else /* no overlap && newStart==start */ {
+            trie->map[start>>UTRIE2_SHIFT_1_2]=start;
+            start+=UTRIE2_INDEX_2_BLOCK_LENGTH;
+            newStart=start;
+        }
+    }
+
+    /* now adjust the index-1 table */
+    for(i=0; i<UNEWTRIE2_INDEX_1_LENGTH; ++i) {
+        trie->index1[i]=trie->map[trie->index1[i]>>UTRIE2_SHIFT_1_2];
+    }
+    trie->index2NullOffset=trie->map[trie->index2NullOffset>>UTRIE2_SHIFT_1_2];
+
+    /*
+     * Ensure data table alignment:
+     * Needs to be granularity-aligned for 16-bit trie
+     * (so that dataMove will be down-shiftable),
+     * and 2-aligned for uint32_t data.
+     */
+    while((newStart&((UTRIE2_DATA_GRANULARITY-1)|1))!=0) {
+        /* Arbitrary value: 0x3fffc not possible for real data. */
+        trie->index2[newStart++]=(int32_t)0xffff<<UTRIE2_INDEX_SHIFT;
+    }
+
+#ifdef UTRIE2_DEBUG
+    /* we saved some space */
+    printf("compacting UTrie2: count of 16-bit index-2 words %lu->%lu\n",
+            (long)trie->index2Length, (long)newStart);
+#endif
+
+    trie->index2Length=newStart;
+}
+
+static void
+compactTrie(UTrie2 *trie, UErrorCode *pErrorCode) {
+    UNewTrie2 *newTrie;
+    UChar32 highStart, suppHighStart;
+    uint32_t highValue;
+
+    newTrie=trie->newTrie;
+
+    /* find highStart and round it up */
+    highValue=utrie2_get32(trie, 0x10ffff);
+    highStart=findHighStart(newTrie, highValue);
+    highStart=(highStart+(UTRIE2_CP_PER_INDEX_1_ENTRY-1))&~(UTRIE2_CP_PER_INDEX_1_ENTRY-1);
+    if(highStart==0x110000) {
+        highValue=trie->errorValue;
+    }
+
+    /*
+     * Set trie->highStart only after utrie2_get32(trie, highStart).
+     * Otherwise utrie2_get32(trie, highStart) would try to read the highValue.
+     */
+    trie->highStart=newTrie->highStart=highStart;
+
+#ifdef UTRIE2_DEBUG
+    printf("UTrie2: highStart U+%04lx  highValue 0x%lx  initialValue 0x%lx\n",
+            (long)highStart, (long)highValue, (long)trie->initialValue);
+#endif
+
+    if(highStart<0x110000) {
+        /* Blank out [highStart..10ffff] to release associated data blocks. */
+        suppHighStart= highStart<=0x10000 ? 0x10000 : highStart;
+        utrie2_setRange32(trie, suppHighStart, 0x10ffff, trie->initialValue, TRUE, pErrorCode);
+        if(U_FAILURE(*pErrorCode)) {
+            return;
+        }
+    }
+
+    compactData(newTrie);
+    if(highStart>0x10000) {
+        compactIndex2(newTrie);
+#ifdef UTRIE2_DEBUG
+    } else {
+        printf("UTrie2: highStart U+%04lx  count of 16-bit index-2 words %lu->%lu\n",
+                (long)highStart, (long)trie->newTrie->index2Length, (long)UTRIE2_INDEX_1_OFFSET);
+#endif
+    }
+
+    /*
+     * Store the highValue in the data array and round up the dataLength.
+     * Must be done after compactData() because that assumes that dataLength
+     * is a multiple of UTRIE2_DATA_BLOCK_LENGTH.
+     */
+    newTrie->data[newTrie->dataLength++]=highValue;
+    while((newTrie->dataLength&(UTRIE2_DATA_GRANULARITY-1))!=0) {
+        newTrie->data[newTrie->dataLength++]=trie->initialValue;
+    }
+
+    newTrie->isCompacted=TRUE;
+}
+
+/* serialization ------------------------------------------------------------ */
+
+/**
+ * Maximum length of the runtime index array.
+ * Limited by its own 16-bit index values, and by uint16_t UTrie2Header.indexLength.
+ * (The actual maximum length is lower,
+ * (0x110000>>UTRIE2_SHIFT_2)+UTRIE2_UTF8_2B_INDEX_2_LENGTH+UTRIE2_MAX_INDEX_1_LENGTH.)
+ */
+#define UTRIE2_MAX_INDEX_LENGTH 0xffff
+
+/**
+ * Maximum length of the runtime data array.
+ * Limited by 16-bit index values that are left-shifted by UTRIE2_INDEX_SHIFT,
+ * and by uint16_t UTrie2Header.shiftedDataLength.
+ */
+#define UTRIE2_MAX_DATA_LENGTH (0xffff<<UTRIE2_INDEX_SHIFT)
+
+/* Compact and internally serialize the trie. */
+U_CAPI void U_EXPORT2
+utrie2_freeze(UTrie2 *trie, UTrie2ValueBits valueBits, UErrorCode *pErrorCode) {
+    UNewTrie2 *newTrie;
+    UTrie2Header *header;
+    uint32_t *p;
+    uint16_t *dest16;
+    int32_t i, length;
+    int32_t allIndexesLength;
+    int32_t dataMove;  /* >0 if the data is moved to the end of the index array */
+    UChar32 highStart;
+
+    /* argument check */
+    if(U_FAILURE(*pErrorCode)) {
+        return;
+    }
+    if( trie==NULL ||
+        valueBits<0 || UTRIE2_COUNT_VALUE_BITS<=valueBits
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    newTrie=trie->newTrie;
+    if(newTrie==NULL) {
+        /* already frozen */
+        UTrie2ValueBits frozenValueBits=
+            trie->data16!=NULL ? UTRIE2_16_VALUE_BITS : UTRIE2_32_VALUE_BITS;
+        if(valueBits!=frozenValueBits) {
+            *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        }
+        return;
+    }
+
+    /* compact if necessary */
+    if(!newTrie->isCompacted) {
+        compactTrie(trie, pErrorCode);
+        if(U_FAILURE(*pErrorCode)) {
+            return;
+        }
+    }
+    highStart=trie->highStart;
+
+    if(highStart<=0x10000) {
+        allIndexesLength=UTRIE2_INDEX_1_OFFSET;
+    } else {
+        allIndexesLength=newTrie->index2Length;
+    }
+    if(valueBits==UTRIE2_16_VALUE_BITS) {
+        dataMove=allIndexesLength;
+    } else {
+        dataMove=0;
+    }
+
+    /* are indexLength and dataLength within limits? */
+    if( /* for unshifted indexLength */
+        allIndexesLength>UTRIE2_MAX_INDEX_LENGTH ||
+        /* for unshifted dataNullOffset */
+        (dataMove+newTrie->dataNullOffset)>0xffff ||
+        /* for unshifted 2-byte UTF-8 index-2 values */
+        (dataMove+UNEWTRIE2_DATA_0800_OFFSET)>0xffff ||
+        /* for shiftedDataLength */
+        (dataMove+newTrie->dataLength)>UTRIE2_MAX_DATA_LENGTH
+    ) {
+        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+        return;
+    }
+
+    /* calculate the total serialized length */
+    length=sizeof(UTrie2Header)+allIndexesLength*2;
+    if(valueBits==UTRIE2_16_VALUE_BITS) {
+        length+=newTrie->dataLength*2;
+    } else {
+        length+=newTrie->dataLength*4;
+    }
+
+    trie->memory=uprv_malloc(length);
+    if(trie->memory==NULL) {
+        *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    trie->length=length;
+    trie->isMemoryOwned=TRUE;
+
+    trie->indexLength=allIndexesLength;
+    trie->dataLength=newTrie->dataLength;
+    if(highStart<=0x10000) {
+        trie->index2NullOffset=0xffff;
+    } else {
+        trie->index2NullOffset=UTRIE2_INDEX_2_OFFSET+newTrie->index2NullOffset;
+    }
+    trie->dataNullOffset=(uint16_t)(dataMove+newTrie->dataNullOffset);
+    trie->highValueIndex=dataMove+trie->dataLength-UTRIE2_DATA_GRANULARITY;
+
+    /* set the header fields */
+    header=(UTrie2Header *)trie->memory;
+
+    header->signature=UTRIE2_SIG; /* "Tri2" */
+    header->options=(uint16_t)valueBits;
+
+    header->indexLength=(uint16_t)trie->indexLength;
+    header->shiftedDataLength=(uint16_t)(trie->dataLength>>UTRIE2_INDEX_SHIFT);
+    header->index2NullOffset=trie->index2NullOffset;
+    header->dataNullOffset=trie->dataNullOffset;
+    header->shiftedHighStart=(uint16_t)(highStart>>UTRIE2_SHIFT_1);
+
+    /* fill the index and data arrays */
+    dest16=(uint16_t *)(header+1);
+    trie->index=dest16;
+
+    /* write the index-2 array values shifted right by UTRIE2_INDEX_SHIFT, after adding dataMove */
+    p=(uint32_t *)newTrie->index2;
+    for(i=UTRIE2_INDEX_2_BMP_LENGTH; i>0; --i) {
+        *dest16++=(uint16_t)((dataMove + *p++)>>UTRIE2_INDEX_SHIFT);
+    }
+
+    /* write UTF-8 2-byte index-2 values, not right-shifted */
+    for(i=0; i<(0xc2-0xc0); ++i) {                                  /* C0..C1 */
+        *dest16++=(uint16_t)(dataMove+UTRIE2_BAD_UTF8_DATA_OFFSET);
+    }
+    for(; i<(0xe0-0xc0); ++i) {                                     /* C2..DF */
+        *dest16++=(uint16_t)(dataMove+newTrie->index2[i<<(6-UTRIE2_SHIFT_2)]);
+    }
+
+    if(highStart>0x10000) {
+        int32_t index1Length=(highStart-0x10000)>>UTRIE2_SHIFT_1;
+        int32_t index2Offset=UTRIE2_INDEX_2_BMP_LENGTH+UTRIE2_UTF8_2B_INDEX_2_LENGTH+index1Length;
+
+        /* write 16-bit index-1 values for supplementary code points */
+        p=(uint32_t *)newTrie->index1+UTRIE2_OMITTED_BMP_INDEX_1_LENGTH;
+        for(i=index1Length; i>0; --i) {
+            *dest16++=(uint16_t)(UTRIE2_INDEX_2_OFFSET + *p++);
+        }
+
+        /*
+         * write the index-2 array values for supplementary code points,
+         * shifted right by UTRIE2_INDEX_SHIFT, after adding dataMove
+         */
+        p=(uint32_t *)newTrie->index2+index2Offset;
+        for(i=newTrie->index2Length-index2Offset; i>0; --i) {
+            *dest16++=(uint16_t)((dataMove + *p++)>>UTRIE2_INDEX_SHIFT);
+        }
+    }
+
+    /* write the 16/32-bit data array */
+    switch(valueBits) {
+    case UTRIE2_16_VALUE_BITS:
+        /* write 16-bit data values */
+        trie->data16=dest16;
+        trie->data32=NULL;
+        p=newTrie->data;
+        for(i=newTrie->dataLength; i>0; --i) {
+            *dest16++=(uint16_t)*p++;
+        }
+        break;
+    case UTRIE2_32_VALUE_BITS:
+        /* write 32-bit data values */
+        trie->data16=NULL;
+        trie->data32=(uint32_t *)dest16;
+        uprv_memcpy(dest16, newTrie->data, newTrie->dataLength*4);
+        break;
+    default:
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    /* Delete the UNewTrie2. */
+    uprv_free(newTrie->data);
+    uprv_free(newTrie);
+    trie->newTrie=NULL;
+}
+
+U_CAPI UBool U_EXPORT2
+utrie2_isFrozen(const UTrie2 *trie) {
+    return (UBool)(trie->newTrie==NULL);
+}
+
+U_CAPI int32_t U_EXPORT2
+utrie2_serialize(UTrie2 *trie,
+                 void *data, int32_t capacity,
+                 UErrorCode *pErrorCode) {
+    /* argument check */
+    if(U_FAILURE(*pErrorCode)) {
+        return 0;
+    }
+
+    if( trie==NULL || trie->memory==NULL || trie->newTrie!=NULL ||
+        capacity<0 || (capacity>0 && (data==NULL || (U_POINTER_MASK_LSB(data, 3)!=0)))
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    if(capacity>=trie->length) {
+        uprv_memcpy(data, trie->memory, trie->length);
+    } else {
+        *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+    }
+    return trie->length;
+}
+
+/*
+ * This is here to avoid a dependency from utrie2.cpp on utrie.c.
+ * This file already depends on utrie.c.
+ * Otherwise, this should be in utrie2.cpp right after utrie2_swap().
+ */
+U_CAPI int32_t U_EXPORT2
+utrie2_swapAnyVersion(const UDataSwapper *ds,
+                      const void *inData, int32_t length, void *outData,
+                      UErrorCode *pErrorCode) {
+    if(U_SUCCESS(*pErrorCode)) {
+        switch(utrie2_getVersion(inData, length, TRUE)) {
+        case 1:
+            return utrie_swap(ds, inData, length, outData, pErrorCode);
+        case 2:
+            return utrie2_swap(ds, inData, length, outData, pErrorCode);
+        default:
+            *pErrorCode=U_INVALID_FORMAT_ERROR;
+            return 0;
+        }
+    }
+    return 0;
+}
diff --git a/source/common/utrie2_impl.h b/source/common/utrie2_impl.h
new file mode 100644
index 0000000..ecb3b6f
--- /dev/null
+++ b/source/common/utrie2_impl.h
@@ -0,0 +1,172 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2001-2008, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  utrie2_impl.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2008sep26 (split off from utrie2.c)
+*   created by: Markus W. Scherer
+*
+*   Definitions needed for both runtime and builder code for UTrie2,
+*   used by utrie2.c and utrie2_builder.c.
+*/
+
+#ifndef __UTRIE2_IMPL_H__
+#define __UTRIE2_IMPL_H__
+
+#include "utrie2.h"
+
+/* Public UTrie2 API implementation ----------------------------------------- */
+
+/*
+ * These definitions are mostly needed by utrie2.c,
+ * but also by utrie2_serialize() and utrie2_swap().
+ */
+
+/*
+ * UTrie and UTrie2 signature values,
+ * in platform endianness and opposite endianness.
+ */
+#define UTRIE_SIG       0x54726965
+#define UTRIE_OE_SIG    0x65697254
+
+#define UTRIE2_SIG      0x54726932
+#define UTRIE2_OE_SIG   0x32697254
+
+/**
+ * Trie data structure in serialized form:
+ *
+ * UTrie2Header header;
+ * uint16_t index[header.index2Length];
+ * uint16_t data[header.shiftedDataLength<<2];  -- or uint32_t data[...]
+ * @internal
+ */
+typedef struct UTrie2Header {
+    /** "Tri2" in big-endian US-ASCII (0x54726932) */
+    uint32_t signature;
+
+    /**
+     * options bit field:
+     * 15.. 4   reserved (0)
+     *  3.. 0   UTrie2ValueBits valueBits
+     */
+    uint16_t options;
+
+    /** UTRIE2_INDEX_1_OFFSET..UTRIE2_MAX_INDEX_LENGTH */
+    uint16_t indexLength;
+
+    /** (UTRIE2_DATA_START_OFFSET..UTRIE2_MAX_DATA_LENGTH)>>UTRIE2_INDEX_SHIFT */
+    uint16_t shiftedDataLength;
+
+    /** Null index and data blocks, not shifted. */
+    uint16_t index2NullOffset, dataNullOffset;
+
+    /**
+     * First code point of the single-value range ending with U+10ffff,
+     * rounded up and then shifted right by UTRIE2_SHIFT_1.
+     */
+    uint16_t shiftedHighStart;
+} UTrie2Header;
+
+/**
+ * Constants for use with UTrie2Header.options.
+ * @internal
+ */
+enum {
+    /** Mask to get the UTrie2ValueBits valueBits from options. */
+    UTRIE2_OPTIONS_VALUE_BITS_MASK=0xf
+};
+
+/* Building a trie ---------------------------------------------------------- */
+
+/*
+ * These definitions are mostly needed by utrie2_builder.c, but also by
+ * utrie2_get32() and utrie2_enum().
+ */
+
+enum {
+    /**
+     * At build time, leave a gap in the index-2 table,
+     * at least as long as the maximum lengths of the 2-byte UTF-8 index-2 table
+     * and the supplementary index-1 table.
+     * Round up to UTRIE2_INDEX_2_BLOCK_LENGTH for proper compacting.
+     */
+    UNEWTRIE2_INDEX_GAP_OFFSET=UTRIE2_INDEX_2_BMP_LENGTH,
+    UNEWTRIE2_INDEX_GAP_LENGTH=
+        ((UTRIE2_UTF8_2B_INDEX_2_LENGTH+UTRIE2_MAX_INDEX_1_LENGTH)+UTRIE2_INDEX_2_MASK)&
+        ~UTRIE2_INDEX_2_MASK,
+
+    /**
+     * Maximum length of the build-time index-2 array.
+     * Maximum number of Unicode code points (0x110000) shifted right by UTRIE2_SHIFT_2,
+     * plus the part of the index-2 table for lead surrogate code points,
+     * plus the build-time index gap,
+     * plus the null index-2 block.
+     */
+    UNEWTRIE2_MAX_INDEX_2_LENGTH=
+        (0x110000>>UTRIE2_SHIFT_2)+
+        UTRIE2_LSCP_INDEX_2_LENGTH+
+        UNEWTRIE2_INDEX_GAP_LENGTH+
+        UTRIE2_INDEX_2_BLOCK_LENGTH,
+
+    UNEWTRIE2_INDEX_1_LENGTH=0x110000>>UTRIE2_SHIFT_1
+};
+
+/**
+ * Maximum length of the build-time data array.
+ * One entry per 0x110000 code points, plus the illegal-UTF-8 block and the null block,
+ * plus values for the 0x400 surrogate code units.
+ */
+#define UNEWTRIE2_MAX_DATA_LENGTH (0x110000+0x40+0x40+0x400)
+
+/*
+ * Build-time trie structure.
+ *
+ * Just using a boolean flag for "repeat use" could lead to data array overflow
+ * because we would not be able to detect when a data block becomes unused.
+ * It also leads to orphan data blocks that are kept through serialization.
+ *
+ * Need to use reference counting for data blocks,
+ * and allocDataBlock() needs to look for a free block before increasing dataLength.
+ *
+ * This scheme seems like overkill for index-2 blocks since the whole index array is
+ * preallocated anyway (unlike the growable data array).
+ * Just allocating multiple index-2 blocks as needed.
+ */
+struct UNewTrie2 {
+    int32_t index1[UNEWTRIE2_INDEX_1_LENGTH];
+    int32_t index2[UNEWTRIE2_MAX_INDEX_2_LENGTH];
+    uint32_t *data;
+
+    uint32_t initialValue, errorValue;
+    int32_t index2Length, dataCapacity, dataLength;
+    int32_t firstFreeBlock;
+    int32_t index2NullOffset, dataNullOffset;
+    UChar32 highStart;
+    UBool isCompacted;
+
+    /**
+     * Multi-purpose per-data-block table.
+     *
+     * Before compacting:
+     *
+     * Per-data-block reference counters/free-block list.
+     *  0: unused
+     * >0: reference counter (number of index-2 entries pointing here)
+     * <0: next free data block in free-block list
+     *
+     * While compacting:
+     *
+     * Map of adjusted indexes, used in compactData() and compactIndex2().
+     * Maps from original indexes to new ones.
+     */
+    int32_t map[UNEWTRIE2_MAX_DATA_LENGTH>>UTRIE2_SHIFT_2];
+};
+
+#endif
diff --git a/source/common/uts46.cpp b/source/common/uts46.cpp
new file mode 100644
index 0000000..e08ee35
--- /dev/null
+++ b/source/common/uts46.cpp
@@ -0,0 +1,1346 @@
+/*
+*******************************************************************************
+*   Copyright (C) 2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*******************************************************************************
+*   file name:  uts46.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2010mar09
+*   created by: Markus W. Scherer
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_IDNA
+
+#include "unicode/idna.h"
+#include "unicode/normalizer2.h"
+#include "unicode/ustring.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "punycode.h"
+#include "ustr_imp.h"
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+// Note about tests for UIDNA_ERROR_DOMAIN_NAME_TOO_LONG:
+//
+// The domain name length limit is 255 octets in an internal DNS representation
+// where the last ("root") label is the empty label
+// represented by length byte 0 alone.
+// In a conventional string, this translates to 253 characters, or 254
+// if there is a trailing dot for the root label.
+
+U_NAMESPACE_BEGIN
+
+// Severe errors which usually result in a U+FFFD replacement character in the result string.
+const uint32_t severeErrors=
+    UIDNA_ERROR_LEADING_COMBINING_MARK|
+    UIDNA_ERROR_DISALLOWED|
+    UIDNA_ERROR_PUNYCODE|
+    UIDNA_ERROR_LABEL_HAS_DOT|
+    UIDNA_ERROR_INVALID_ACE_LABEL;
+
+static inline UBool
+isASCIIString(const UnicodeString &dest) {
+    const UChar *s=dest.getBuffer();
+    const UChar *limit=s+dest.length();
+    while(s<limit) {
+        if(*s++>0x7f) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+static UBool
+isASCIIOkBiDi(const UChar *s, int32_t length);
+
+static UBool
+isASCIIOkBiDi(const char *s, int32_t length);
+
+// IDNA class default implementations -------------------------------------- ***
+
+void
+IDNA::labelToASCII_UTF8(const StringPiece &label, ByteSink &dest,
+                        IDNAInfo &info, UErrorCode &errorCode) const {
+    if(U_SUCCESS(errorCode)) {
+        UnicodeString destString;
+        labelToASCII(UnicodeString::fromUTF8(label), destString,
+                     info, errorCode).toUTF8(dest);
+    }
+}
+
+void
+IDNA::labelToUnicodeUTF8(const StringPiece &label, ByteSink &dest,
+                         IDNAInfo &info, UErrorCode &errorCode) const {
+    if(U_SUCCESS(errorCode)) {
+        UnicodeString destString;
+        labelToUnicode(UnicodeString::fromUTF8(label), destString,
+                       info, errorCode).toUTF8(dest);
+    }
+}
+
+void
+IDNA::nameToASCII_UTF8(const StringPiece &name, ByteSink &dest,
+                       IDNAInfo &info, UErrorCode &errorCode) const {
+    if(U_SUCCESS(errorCode)) {
+        UnicodeString destString;
+        nameToASCII(UnicodeString::fromUTF8(name), destString,
+                    info, errorCode).toUTF8(dest);
+    }
+}
+
+void
+IDNA::nameToUnicodeUTF8(const StringPiece &name, ByteSink &dest,
+                        IDNAInfo &info, UErrorCode &errorCode) const {
+    if(U_SUCCESS(errorCode)) {
+        UnicodeString destString;
+        nameToUnicode(UnicodeString::fromUTF8(name), destString,
+                      info, errorCode).toUTF8(dest);
+    }
+}
+
+UOBJECT_DEFINE_NO_RTTI_IMPLEMENTATION(IDNA)
+
+// UTS46 class declaration ------------------------------------------------- ***
+
+class UTS46 : public IDNA {
+public:
+    UTS46(uint32_t options, UErrorCode &errorCode);
+    virtual ~UTS46();
+
+    virtual UnicodeString &
+    labelToASCII(const UnicodeString &label, UnicodeString &dest,
+                 IDNAInfo &info, UErrorCode &errorCode) const;
+
+    virtual UnicodeString &
+    labelToUnicode(const UnicodeString &label, UnicodeString &dest,
+                   IDNAInfo &info, UErrorCode &errorCode) const;
+
+    virtual UnicodeString &
+    nameToASCII(const UnicodeString &name, UnicodeString &dest,
+                IDNAInfo &info, UErrorCode &errorCode) const;
+
+    virtual UnicodeString &
+    nameToUnicode(const UnicodeString &name, UnicodeString &dest,
+                  IDNAInfo &info, UErrorCode &errorCode) const;
+
+    virtual void
+    labelToASCII_UTF8(const StringPiece &label, ByteSink &dest,
+                      IDNAInfo &info, UErrorCode &errorCode) const;
+
+    virtual void
+    labelToUnicodeUTF8(const StringPiece &label, ByteSink &dest,
+                       IDNAInfo &info, UErrorCode &errorCode) const;
+
+    virtual void
+    nameToASCII_UTF8(const StringPiece &name, ByteSink &dest,
+                     IDNAInfo &info, UErrorCode &errorCode) const;
+
+    virtual void
+    nameToUnicodeUTF8(const StringPiece &name, ByteSink &dest,
+                      IDNAInfo &info, UErrorCode &errorCode) const;
+
+private:
+    UnicodeString &
+    process(const UnicodeString &src,
+            UBool isLabel, UBool toASCII,
+            UnicodeString &dest,
+            IDNAInfo &info, UErrorCode &errorCode) const;
+
+    void
+    processUTF8(const StringPiece &src,
+                UBool isLabel, UBool toASCII,
+                ByteSink &dest,
+                IDNAInfo &info, UErrorCode &errorCode) const;
+
+    UnicodeString &
+    processUnicode(const UnicodeString &src,
+                   int32_t labelStart, int32_t mappingStart,
+                   UBool isLabel, UBool toASCII,
+                   UnicodeString &dest,
+                   IDNAInfo &info, UErrorCode &errorCode) const;
+
+    // returns the new dest.length()
+    int32_t
+    mapDevChars(UnicodeString &dest, int32_t labelStart, int32_t mappingStart,
+                UErrorCode &errorCode) const;
+
+    // returns the new label length
+    int32_t
+    processLabel(UnicodeString &dest,
+                 int32_t labelStart, int32_t labelLength,
+                 UBool toASCII,
+                 IDNAInfo &info, UErrorCode &errorCode) const;
+    int32_t
+    markBadACELabel(UnicodeString &dest,
+                    int32_t labelStart, int32_t labelLength,
+                    UBool toASCII, IDNAInfo &info) const;
+
+    void
+    checkLabelBiDi(const UChar *label, int32_t labelLength, IDNAInfo &info) const;
+
+    UBool
+    isLabelOkContextJ(const UChar *label, int32_t labelLength) const;
+
+    const Normalizer2 &uts46Norm2;  // uts46.nrm
+    uint32_t options;
+};
+
+IDNA *
+IDNA::createUTS46Instance(uint32_t options, UErrorCode &errorCode) {
+    if(U_SUCCESS(errorCode)) {
+        IDNA *idna=new UTS46(options, errorCode);
+        if(idna==NULL) {
+            errorCode=U_MEMORY_ALLOCATION_ERROR;
+        } else if(U_FAILURE(errorCode)) {
+            delete idna;
+            idna=NULL;
+        }
+        return idna;
+    } else {
+        return NULL;
+    }
+}
+
+// UTS46 implementation ---------------------------------------------------- ***
+
+UTS46::UTS46(uint32_t opt, UErrorCode &errorCode)
+        : uts46Norm2(*Normalizer2::getInstance(NULL, "uts46", UNORM2_COMPOSE, errorCode)),
+          options(opt) {}
+
+UTS46::~UTS46() {}
+
+UnicodeString &
+UTS46::labelToASCII(const UnicodeString &label, UnicodeString &dest,
+                    IDNAInfo &info, UErrorCode &errorCode) const {
+    return process(label, TRUE, TRUE, dest, info, errorCode);
+}
+
+UnicodeString &
+UTS46::labelToUnicode(const UnicodeString &label, UnicodeString &dest,
+                      IDNAInfo &info, UErrorCode &errorCode) const {
+    return process(label, TRUE, FALSE, dest, info, errorCode);
+}
+
+UnicodeString &
+UTS46::nameToASCII(const UnicodeString &name, UnicodeString &dest,
+                   IDNAInfo &info, UErrorCode &errorCode) const {
+    process(name, FALSE, TRUE, dest, info, errorCode);
+    if( dest.length()>=254 && (info.errors&UIDNA_ERROR_DOMAIN_NAME_TOO_LONG)==0 &&
+        isASCIIString(dest) &&
+        (dest.length()>254 || dest[253]!=0x2e)
+    ) {
+        info.errors|=UIDNA_ERROR_DOMAIN_NAME_TOO_LONG;
+    }
+    return dest;
+}
+
+UnicodeString &
+UTS46::nameToUnicode(const UnicodeString &name, UnicodeString &dest,
+                     IDNAInfo &info, UErrorCode &errorCode) const {
+    return process(name, FALSE, FALSE, dest, info, errorCode);
+}
+
+void
+UTS46::labelToASCII_UTF8(const StringPiece &label, ByteSink &dest,
+                         IDNAInfo &info, UErrorCode &errorCode) const {
+    processUTF8(label, TRUE, TRUE, dest, info, errorCode);
+}
+
+void
+UTS46::labelToUnicodeUTF8(const StringPiece &label, ByteSink &dest,
+                          IDNAInfo &info, UErrorCode &errorCode) const {
+    processUTF8(label, TRUE, FALSE, dest, info, errorCode);
+}
+
+void
+UTS46::nameToASCII_UTF8(const StringPiece &name, ByteSink &dest,
+                        IDNAInfo &info, UErrorCode &errorCode) const {
+    processUTF8(name, FALSE, TRUE, dest, info, errorCode);
+}
+
+void
+UTS46::nameToUnicodeUTF8(const StringPiece &name, ByteSink &dest,
+                         IDNAInfo &info, UErrorCode &errorCode) const {
+    processUTF8(name, FALSE, FALSE, dest, info, errorCode);
+}
+
+// UTS #46 data for ASCII characters.
+// The normalizer (using uts46.nrm) maps uppercase ASCII letters to lowercase
+// and passes through all other ASCII characters.
+// If UIDNA_USE_STD3_RULES is set, then non-LDH characters are disallowed
+// using this data.
+// The ASCII fastpath also uses this data.
+// Values: -1=disallowed  0==valid  1==mapped (lowercase)
+static const int8_t asciiData[128]={
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    // 002D..002E; valid  #  HYPHEN-MINUS..FULL STOP
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  0,  0, -1,
+    // 0030..0039; valid  #  DIGIT ZERO..DIGIT NINE
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0, -1, -1, -1, -1, -1, -1,
+    // 0041..005A; mapped  #  LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+    -1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, -1, -1, -1, -1, -1,
+    // 0061..007A; valid  #  LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+    -1,  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, -1, -1, -1, -1, -1
+};
+
+UnicodeString &
+UTS46::process(const UnicodeString &src,
+               UBool isLabel, UBool toASCII,
+               UnicodeString &dest,
+               IDNAInfo &info, UErrorCode &errorCode) const {
+    // uts46Norm2.normalize() would do all of this error checking and setup,
+    // but with the ASCII fastpath we do not always call it, and do not
+    // call it first.
+    if(U_FAILURE(errorCode)) {
+        dest.setToBogus();
+        return dest;
+    }
+    const UChar *srcArray=src.getBuffer();
+    if(&dest==&src || srcArray==NULL) {
+        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        dest.setToBogus();
+        return dest;
+    }
+    // Arguments are fine, reset output values.
+    dest.remove();
+    info.reset();
+    int32_t srcLength=src.length();
+    if(srcLength==0) {
+        if(toASCII) {
+            info.errors|=UIDNA_ERROR_EMPTY_LABEL;
+        }
+        return dest;
+    }
+    UChar *destArray=dest.getBuffer(srcLength);
+    if(destArray==NULL) {
+        errorCode=U_MEMORY_ALLOCATION_ERROR;
+        return dest;
+    }
+    // ASCII fastpath
+    UBool disallowNonLDHDot=(options&UIDNA_USE_STD3_RULES)!=0;
+    int32_t labelStart=0;
+    int32_t i;
+    for(i=0;; ++i) {
+        if(i==srcLength) {
+            if(toASCII) {
+                if((i-labelStart)>63) {
+                    info.labelErrors|=UIDNA_ERROR_LABEL_TOO_LONG;
+                }
+                // There is a trailing dot if labelStart==i.
+                if(!isLabel && i>=254 && (i>254 || labelStart<i)) {
+                    info.errors|=UIDNA_ERROR_DOMAIN_NAME_TOO_LONG;
+                }
+            }
+            info.errors|=info.labelErrors;
+            dest.releaseBuffer(i);
+            return dest;
+        }
+        UChar c=srcArray[i];
+        if(c>0x7f) {
+            break;
+        }
+        int cData=asciiData[c];
+        if(cData>0) {
+            destArray[i]=c+0x20;  // Lowercase an uppercase ASCII letter.
+        } else if(cData<0 && disallowNonLDHDot) {
+            break;  // Replacing with U+FFFD can be complicated for toASCII.
+        } else {
+            destArray[i]=c;
+            if(c==0x2d) {  // hyphen
+                if(i==(labelStart+3) && srcArray[i-1]==0x2d) {
+                    // "??--..." is Punycode or forbidden.
+                    ++i;  // '-' was copied to dest already
+                    break;
+                }
+                if(i==labelStart) {
+                    // label starts with "-"
+                    info.labelErrors|=UIDNA_ERROR_LEADING_HYPHEN;
+                }
+                if((i+1)==srcLength || srcArray[i+1]==0x2e) {
+                    // label ends with "-"
+                    info.labelErrors|=UIDNA_ERROR_TRAILING_HYPHEN;
+                }
+            } else if(c==0x2e) {  // dot
+                if(isLabel) {
+                    // Replacing with U+FFFD can be complicated for toASCII.
+                    ++i;  // '.' was copied to dest already
+                    break;
+                }
+                if(toASCII) {
+                    // Permit an empty label at the end but not elsewhere.
+                    if(i==labelStart && i<(srcLength-1)) {
+                        info.labelErrors|=UIDNA_ERROR_EMPTY_LABEL;
+                    } else if((i-labelStart)>63) {
+                        info.labelErrors|=UIDNA_ERROR_LABEL_TOO_LONG;
+                    }
+                }
+                info.errors|=info.labelErrors;
+                info.labelErrors=0;
+                labelStart=i+1;
+            }
+        }
+    }
+    info.errors|=info.labelErrors;
+    dest.releaseBuffer(i);
+    processUnicode(src, labelStart, i, isLabel, toASCII, dest, info, errorCode);
+    if( info.isBiDi && U_SUCCESS(errorCode) && (info.errors&severeErrors)==0 &&
+        (!info.isOkBiDi || (labelStart>0 && !isASCIIOkBiDi(dest.getBuffer(), labelStart)))
+    ) {
+        info.errors|=UIDNA_ERROR_BIDI;
+    }
+    return dest;
+}
+
+void
+UTS46::processUTF8(const StringPiece &src,
+                   UBool isLabel, UBool toASCII,
+                   ByteSink &dest,
+                   IDNAInfo &info, UErrorCode &errorCode) const {
+    if(U_FAILURE(errorCode)) {
+        return;
+    }
+    const char *srcArray=src.data();
+    int32_t srcLength=src.length();
+    if(srcArray==NULL && srcLength!=0) {
+        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    // Arguments are fine, reset output values.
+    info.reset();
+    if(srcLength==0) {
+        if(toASCII) {
+            info.errors|=UIDNA_ERROR_EMPTY_LABEL;
+        }
+        dest.Flush();
+        return;
+    }
+    UnicodeString destString;
+    int32_t labelStart=0;
+    if(srcLength<=256) {  // length of stackArray[]
+        // ASCII fastpath
+        char stackArray[256];
+        int32_t destCapacity;
+        char *destArray=dest.GetAppendBuffer(srcLength, srcLength+20,
+                                             stackArray, LENGTHOF(stackArray), &destCapacity);
+        UBool disallowNonLDHDot=(options&UIDNA_USE_STD3_RULES)!=0;
+        int32_t i;
+        for(i=0;; ++i) {
+            if(i==srcLength) {
+                if(toASCII) {
+                    if((i-labelStart)>63) {
+                        info.labelErrors|=UIDNA_ERROR_LABEL_TOO_LONG;
+                    }
+                    // There is a trailing dot if labelStart==i.
+                    if(!isLabel && i>=254 && (i>254 || labelStart<i)) {
+                        info.errors|=UIDNA_ERROR_DOMAIN_NAME_TOO_LONG;
+                    }
+                }
+                info.errors|=info.labelErrors;
+                dest.Append(destArray, i);
+                dest.Flush();
+                return;
+            }
+            char c=srcArray[i];
+            if((int8_t)c<0) {  // (uint8_t)c>0x7f
+                break;
+            }
+            int cData=asciiData[(int)c];  // Cast: gcc warns about indexing with a char.
+            if(cData>0) {
+                destArray[i]=c+0x20;  // Lowercase an uppercase ASCII letter.
+            } else if(cData<0 && disallowNonLDHDot) {
+                break;  // Replacing with U+FFFD can be complicated for toASCII.
+            } else {
+                destArray[i]=c;
+                if(c==0x2d) {  // hyphen
+                    if(i==(labelStart+3) && srcArray[i-1]==0x2d) {
+                        // "??--..." is Punycode or forbidden.
+                        break;
+                    }
+                    if(i==labelStart) {
+                        // label starts with "-"
+                        info.labelErrors|=UIDNA_ERROR_LEADING_HYPHEN;
+                    }
+                    if((i+1)==srcLength || srcArray[i+1]==0x2e) {
+                        // label ends with "-"
+                        info.labelErrors|=UIDNA_ERROR_TRAILING_HYPHEN;
+                    }
+                } else if(c==0x2e) {  // dot
+                    if(isLabel) {
+                        break;  // Replacing with U+FFFD can be complicated for toASCII.
+                    }
+                    if(toASCII) {
+                        // Permit an empty label at the end but not elsewhere.
+                        if(i==labelStart && i<(srcLength-1)) {
+                            info.labelErrors|=UIDNA_ERROR_EMPTY_LABEL;
+                        } else if((i-labelStart)>63) {
+                            info.labelErrors|=UIDNA_ERROR_LABEL_TOO_LONG;
+                        }
+                    }
+                    info.errors|=info.labelErrors;
+                    info.labelErrors=0;
+                    labelStart=i+1;
+                }
+            }
+        }
+        info.errors|=info.labelErrors;
+        // Convert the processed ASCII prefix of the current label to UTF-16.
+        int32_t mappingStart=i-labelStart;
+        destString=UnicodeString::fromUTF8(StringPiece(destArray+labelStart, mappingStart));
+        // Output the previous ASCII labels and process the rest of src in UTF-16.
+        dest.Append(destArray, labelStart);
+        processUnicode(UnicodeString::fromUTF8(StringPiece(src, labelStart)), 0, mappingStart,
+                       isLabel, toASCII,
+                       destString, info, errorCode);
+    } else {
+        // src is too long for the ASCII fastpath implementation.
+        processUnicode(UnicodeString::fromUTF8(src), 0, 0,
+                       isLabel, toASCII,
+                       destString, info, errorCode);
+    }
+    destString.toUTF8(dest);  // calls dest.Flush()
+    if(toASCII && !isLabel) {
+        // length==labelStart==254 means that there is a trailing dot (ok) and
+        // destString is empty (do not index at 253-labelStart).
+        int32_t length=labelStart+destString.length();
+        if( length>=254 && isASCIIString(destString) &&
+            (length>254 ||
+             (labelStart<254 && destString[253-labelStart]!=0x2e))
+        ) {
+            info.errors|=UIDNA_ERROR_DOMAIN_NAME_TOO_LONG;
+        }
+    }
+    if( info.isBiDi && U_SUCCESS(errorCode) && (info.errors&severeErrors)==0 &&
+        (!info.isOkBiDi || (labelStart>0 && !isASCIIOkBiDi(srcArray, labelStart)))
+    ) {
+        info.errors|=UIDNA_ERROR_BIDI;
+    }
+}
+
+UnicodeString &
+UTS46::processUnicode(const UnicodeString &src,
+                      int32_t labelStart, int32_t mappingStart,
+                      UBool isLabel, UBool toASCII,
+                      UnicodeString &dest,
+                      IDNAInfo &info, UErrorCode &errorCode) const {
+    if(mappingStart==0) {
+        uts46Norm2.normalize(src, dest, errorCode);
+    } else {
+        uts46Norm2.normalizeSecondAndAppend(dest, src.tempSubString(mappingStart), errorCode);
+    }
+    if(U_FAILURE(errorCode)) {
+        return dest;
+    }
+    UBool doMapDevChars=
+        toASCII ? (options&UIDNA_NONTRANSITIONAL_TO_ASCII)==0 :
+                  (options&UIDNA_NONTRANSITIONAL_TO_UNICODE)==0;
+    const UChar *destArray=dest.getBuffer();
+    int32_t destLength=dest.length();
+    int32_t labelLimit=labelStart;
+    while(labelLimit<destLength) {
+        UChar c=destArray[labelLimit];
+        if(c==0x2e && !isLabel) {
+            int32_t labelLength=labelLimit-labelStart;
+            int32_t newLength=processLabel(dest, labelStart, labelLength,
+                                            toASCII, info, errorCode);
+            info.errors|=info.labelErrors;
+            info.labelErrors=0;
+            if(U_FAILURE(errorCode)) {
+                return dest;
+            }
+            destArray=dest.getBuffer();
+            destLength+=newLength-labelLength;
+            labelLimit=labelStart+=newLength+1;
+        } else if(0xdf<=c && c<=0x200d && (c==0xdf || c==0x3c2 || c>=0x200c)) {
+            info.isTransDiff=TRUE;
+            if(doMapDevChars) {
+                destLength=mapDevChars(dest, labelStart, labelLimit, errorCode);
+                if(U_FAILURE(errorCode)) {
+                    return dest;
+                }
+                destArray=dest.getBuffer();
+                // Do not increment labelLimit in case c was removed.
+                // All deviation characters have been mapped, no need to check for them again.
+                doMapDevChars=FALSE;
+            } else {
+                ++labelLimit;
+            }
+        } else {
+            ++labelLimit;
+        }
+    }
+    // Permit an empty label at the end (0<labelStart==labelLimit==destLength is ok)
+    // but not an empty label elsewhere nor a completely empty domain name.
+    // processLabel() sets UIDNA_ERROR_EMPTY_LABEL when labelLength==0.
+    if(0==labelStart || labelStart<labelLimit) {
+        processLabel(dest, labelStart, labelLimit-labelStart,
+                      toASCII, info, errorCode);
+        info.errors|=info.labelErrors;
+    }
+    return dest;
+}
+
+int32_t
+UTS46::mapDevChars(UnicodeString &dest, int32_t labelStart, int32_t mappingStart,
+                   UErrorCode &errorCode) const {
+    int32_t length=dest.length();
+    UChar *s=dest.getBuffer(dest[mappingStart]==0xdf ? length+1 : length);
+    if(s==NULL) {
+        errorCode=U_MEMORY_ALLOCATION_ERROR;
+        return length;
+    }
+    int32_t capacity=dest.getCapacity();
+    UBool didMapDevChars=FALSE;
+    int32_t readIndex=mappingStart, writeIndex=mappingStart;
+    do {
+        UChar c=s[readIndex++];
+        switch(c) {
+        case 0xdf:
+            // Map sharp s to ss.
+            didMapDevChars=TRUE;
+            s[writeIndex++]=0x73;  // Replace sharp s with first s.
+            // Insert second s and account for possible buffer reallocation.
+            if(writeIndex==readIndex) {
+                if(length==capacity) {
+                    dest.releaseBuffer(length);
+                    s=dest.getBuffer(length+1);
+                    if(s==NULL) {
+                        errorCode=U_MEMORY_ALLOCATION_ERROR;
+                        return length;
+                    }
+                    capacity=dest.getCapacity();
+                }
+                u_memmove(s+writeIndex+1, s+writeIndex, length-writeIndex);
+                ++readIndex;
+            }
+            s[writeIndex++]=0x73;
+            ++length;
+            break;
+        case 0x3c2:  // Map final sigma to nonfinal sigma.
+            didMapDevChars=TRUE;
+            s[writeIndex++]=0x3c3;
+            break;
+        case 0x200c:  // Ignore/remove ZWNJ.
+        case 0x200d:  // Ignore/remove ZWJ.
+            didMapDevChars=TRUE;
+            --length;
+            break;
+        default:
+            // Only really necessary if writeIndex was different from readIndex.
+            s[writeIndex++]=c;
+            break;
+        }
+    } while(writeIndex<length);
+    dest.releaseBuffer(length);
+    if(didMapDevChars) {
+        // Mapping deviation characters might have resulted in an un-NFC string.
+        // We could use either the NFC or the UTS #46 normalizer.
+        // By using the UTS #46 normalizer again, we avoid having to load a second .nrm data file.
+        UnicodeString normalized;
+        uts46Norm2.normalize(dest.tempSubString(labelStart), normalized, errorCode);
+        if(U_SUCCESS(errorCode)) {
+            dest.replace(labelStart, 0x7fffffff, normalized);
+            return dest.length();
+        }
+    }
+    return length;
+}
+
+// Some non-ASCII characters are equivalent to sequences with
+// non-LDH ASCII characters. To find them:
+// grep disallowed_STD3_valid IdnaMappingTable.txt (or uts46.txt)
+static inline UBool
+isNonASCIIDisallowedSTD3Valid(UChar32 c) {
+    return c==0x2260 || c==0x226E || c==0x226F;
+}
+
+// Replace the label in dest with the label string, if the label was modified.
+// If &label==&dest then the label was modified in-place and labelLength
+// is the new label length, different from label.length().
+// If &label!=&dest then labelLength==label.length().
+// Returns labelLength (= the new label length).
+static int32_t
+replaceLabel(UnicodeString &dest, int32_t destLabelStart, int32_t destLabelLength,
+             const UnicodeString &label, int32_t labelLength) {
+    if(&label!=&dest) {
+        dest.replace(destLabelStart, destLabelLength, label);
+    }
+    return labelLength;
+}
+
+int32_t
+UTS46::processLabel(UnicodeString &dest,
+                    int32_t labelStart, int32_t labelLength,
+                    UBool toASCII,
+                    IDNAInfo &info, UErrorCode &errorCode) const {
+    UnicodeString fromPunycode;
+    UnicodeString *labelString;
+    const UChar *label=dest.getBuffer()+labelStart;
+    int32_t destLabelStart=labelStart;
+    int32_t destLabelLength=labelLength;
+    UBool wasPunycode;
+    if(labelLength>=4 && label[0]==0x78 && label[1]==0x6e && label[2]==0x2d && label[3]==0x2d) {
+        // Label starts with "xn--", try to un-Punycode it.
+        wasPunycode=TRUE;
+        UChar *unicodeBuffer=fromPunycode.getBuffer(-1);  // capacity==-1: most labels should fit
+        if(unicodeBuffer==NULL) {
+            // Should never occur if we used capacity==-1 which uses the internal buffer.
+            errorCode=U_MEMORY_ALLOCATION_ERROR;
+            return labelLength;
+        }
+        UErrorCode punycodeErrorCode=U_ZERO_ERROR;
+        int32_t unicodeLength=u_strFromPunycode(label+4, labelLength-4,
+                                                unicodeBuffer, fromPunycode.getCapacity(),
+                                                NULL, &punycodeErrorCode);
+        if(punycodeErrorCode==U_BUFFER_OVERFLOW_ERROR) {
+            fromPunycode.releaseBuffer(0);
+            unicodeBuffer=fromPunycode.getBuffer(unicodeLength);
+            if(unicodeBuffer==NULL) {
+                errorCode=U_MEMORY_ALLOCATION_ERROR;
+                return labelLength;
+            }
+            punycodeErrorCode=U_ZERO_ERROR;
+            unicodeLength=u_strFromPunycode(label+4, labelLength-4,
+                                            unicodeBuffer, fromPunycode.getCapacity(),
+                                            NULL, &punycodeErrorCode);
+        }
+        fromPunycode.releaseBuffer(unicodeLength);
+        if(U_FAILURE(punycodeErrorCode)) {
+            info.labelErrors|=UIDNA_ERROR_PUNYCODE;
+            return markBadACELabel(dest, labelStart, labelLength, toASCII, info);
+        }
+        // Check for NFC, and for characters that are not
+        // valid or deviation characters according to the normalizer.
+        // If there is something wrong, then the string will change.
+        // Note that the normalizer passes through non-LDH ASCII and deviation characters.
+        // Deviation characters are ok in Punycode even in transitional processing.
+        // In the code further below, if we find non-LDH ASCII and we have UIDNA_USE_STD3_RULES
+        // then we will set UIDNA_ERROR_INVALID_ACE_LABEL there too.
+        UBool isValid=uts46Norm2.isNormalized(fromPunycode, errorCode);
+        if(U_FAILURE(errorCode)) {
+            return labelLength;
+        }
+        if(!isValid) {
+            info.labelErrors|=UIDNA_ERROR_INVALID_ACE_LABEL;
+            return markBadACELabel(dest, labelStart, labelLength, toASCII, info);
+        }
+        labelString=&fromPunycode;
+        label=fromPunycode.getBuffer();
+        labelStart=0;
+        labelLength=fromPunycode.length();
+    } else {
+        wasPunycode=FALSE;
+        labelString=&dest;
+    }
+    // Validity check
+    if(labelLength==0) {
+        if(toASCII) {
+            info.labelErrors|=UIDNA_ERROR_EMPTY_LABEL;
+        }
+        return replaceLabel(dest, destLabelStart, destLabelLength, *labelString, labelLength);
+    }
+    // labelLength>0
+    if(labelLength>=4 && label[2]==0x2d && label[3]==0x2d) {
+        // label starts with "??--"
+        info.labelErrors|=UIDNA_ERROR_HYPHEN_3_4;
+    }
+    if(label[0]==0x2d) {
+        // label starts with "-"
+        info.labelErrors|=UIDNA_ERROR_LEADING_HYPHEN;
+    }
+    if(label[labelLength-1]==0x2d) {
+        // label ends with "-"
+        info.labelErrors|=UIDNA_ERROR_TRAILING_HYPHEN;
+    }
+    // If the label was not a Punycode label, then it was the result of
+    // mapping, normalization and label segmentation.
+    // If the label was in Punycode, then we mapped it again above
+    // and checked its validity.
+    // Now we handle the STD3 restriction to LDH characters (if set)
+    // and we look for U+FFFD which indicates disallowed characters
+    // in a non-Punycode label or U+FFFD itself in a Punycode label.
+    // We also check for dots which can come from the input to a single-label function.
+    // Ok to cast away const because we own the UnicodeString.
+    UChar *s=(UChar *)label;
+    const UChar *limit=label+labelLength;
+    UChar oredChars=0;
+    // If we enforce STD3 rules, then ASCII characters other than LDH and dot are disallowed.
+    UBool disallowNonLDHDot=(options&UIDNA_USE_STD3_RULES)!=0;
+    do {
+        UChar c=*s;
+        if(c<=0x7f) {
+            if(c==0x2e) {
+                info.labelErrors|=UIDNA_ERROR_LABEL_HAS_DOT;
+                *s=0xfffd;
+            } else if(disallowNonLDHDot && asciiData[c]<0) {
+                info.labelErrors|=UIDNA_ERROR_DISALLOWED;
+                *s=0xfffd;
+            }
+        } else {
+            oredChars|=c;
+            if(disallowNonLDHDot && isNonASCIIDisallowedSTD3Valid(c)) {
+                info.labelErrors|=UIDNA_ERROR_DISALLOWED;
+                *s=0xfffd;
+            } else if(c==0xfffd) {
+                info.labelErrors|=UIDNA_ERROR_DISALLOWED;
+            }
+        }
+        ++s;
+    } while(s<limit);
+    // Check for a leading combining mark after other validity checks
+    // so that we don't report UIDNA_ERROR_DISALLOWED for the U+FFFD from here.
+    UChar32 c;
+    int32_t cpLength=0;
+    // "Unsafe" is ok because unpaired surrogates were mapped to U+FFFD.
+    U16_NEXT_UNSAFE(label, cpLength, c);
+    if((U_GET_GC_MASK(c)&U_GC_M_MASK)!=0) {
+        info.labelErrors|=UIDNA_ERROR_LEADING_COMBINING_MARK;
+        labelString->replace(labelStart, cpLength, (UChar)0xfffd);
+        label=labelString->getBuffer()+labelStart;
+        labelLength+=1-cpLength;
+        if(labelString==&dest) {
+            destLabelLength=labelLength;
+        }
+    }
+    if((info.labelErrors&severeErrors)==0) {
+        // Do contextual checks only if we do not have U+FFFD from a severe error
+        // because U+FFFD can make these checks fail.
+        if((options&UIDNA_CHECK_BIDI)!=0 && (!info.isBiDi || info.isOkBiDi)) {
+            checkLabelBiDi(label, labelLength, info);
+        }
+        if( (options&UIDNA_CHECK_CONTEXTJ)!=0 && (oredChars&0x200c)==0x200c &&
+            !isLabelOkContextJ(label, labelLength)
+        ) {
+            info.labelErrors|=UIDNA_ERROR_CONTEXTJ;
+        }
+        if(toASCII) {
+            if(wasPunycode) {
+                // Leave a Punycode label unchanged if it has no severe errors.
+                if(destLabelLength>63) {
+                    info.labelErrors|=UIDNA_ERROR_LABEL_TOO_LONG;
+                }
+                return destLabelLength;
+            } else if(oredChars>=0x80) {
+                // Contains non-ASCII characters.
+                UnicodeString punycode;
+                UChar *buffer=punycode.getBuffer(63);  // 63==maximum DNS label length
+                if(buffer==NULL) {
+                    errorCode=U_MEMORY_ALLOCATION_ERROR;
+                    return destLabelLength;
+                }
+                buffer[0]=0x78;  // Write "xn--".
+                buffer[1]=0x6e;
+                buffer[2]=0x2d;
+                buffer[3]=0x2d;
+                int32_t punycodeLength=u_strToPunycode(label, labelLength,
+                                                      buffer+4, punycode.getCapacity()-4,
+                                                      NULL, &errorCode);
+                if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
+                    errorCode=U_ZERO_ERROR;
+                    punycode.releaseBuffer(4);
+                    buffer=punycode.getBuffer(4+punycodeLength);
+                    if(buffer==NULL) {
+                        errorCode=U_MEMORY_ALLOCATION_ERROR;
+                        return destLabelLength;
+                    }
+                    punycodeLength=u_strToPunycode(label, labelLength,
+                                                  buffer+4, punycode.getCapacity()-4,
+                                                  NULL, &errorCode);
+                }
+                punycodeLength+=4;
+                punycode.releaseBuffer(punycodeLength);
+                if(U_FAILURE(errorCode)) {
+                    return destLabelLength;
+                }
+                if(punycodeLength>63) {
+                    info.labelErrors|=UIDNA_ERROR_LABEL_TOO_LONG;
+                }
+                return replaceLabel(dest, destLabelStart, destLabelLength,
+                                    punycode, punycodeLength);
+            } else {
+                // all-ASCII label
+                if(labelLength>63) {
+                    info.labelErrors|=UIDNA_ERROR_LABEL_TOO_LONG;
+                }
+            }
+        }
+    } else {
+        // If a Punycode label has severe errors,
+        // then leave it but make sure it does not look valid.
+        if(wasPunycode) {
+            info.labelErrors|=UIDNA_ERROR_INVALID_ACE_LABEL;
+            return markBadACELabel(dest, destLabelStart, destLabelLength, toASCII, info);
+        }
+    }
+    return replaceLabel(dest, destLabelStart, destLabelLength, *labelString, labelLength);
+}
+
+// Make sure an ACE label does not look valid.
+// Append U+FFFD if the label has only LDH characters.
+// If UIDNA_USE_STD3_RULES, also replace disallowed ASCII characters with U+FFFD.
+int32_t
+UTS46::markBadACELabel(UnicodeString &dest,
+                       int32_t labelStart, int32_t labelLength,
+                       UBool toASCII, IDNAInfo &info) const {
+    UBool disallowNonLDHDot=(options&UIDNA_USE_STD3_RULES)!=0;
+    UBool isASCII=TRUE;
+    UBool onlyLDH=TRUE;
+    const UChar *label=dest.getBuffer()+labelStart;
+    // Ok to cast away const because we own the UnicodeString.
+    UChar *s=(UChar *)label+4;  // After the initial "xn--".
+    const UChar *limit=label+labelLength;
+    do {
+        UChar c=*s;
+        if(c<=0x7f) {
+            if(c==0x2e) {
+                info.labelErrors|=UIDNA_ERROR_LABEL_HAS_DOT;
+                *s=0xfffd;
+                isASCII=onlyLDH=FALSE;
+            } else if(asciiData[c]<0) {
+                onlyLDH=FALSE;
+                if(disallowNonLDHDot) {
+                    *s=0xfffd;
+                    isASCII=FALSE;
+                }
+            }
+        } else {
+            isASCII=onlyLDH=FALSE;
+        }
+    } while(++s<limit);
+    if(onlyLDH) {
+        dest.insert(labelStart+labelLength, (UChar)0xfffd);
+        ++labelLength;
+    } else {
+        if(toASCII && isASCII && labelLength>63) {
+            info.labelErrors|=UIDNA_ERROR_LABEL_TOO_LONG;
+        }
+    }
+    return labelLength;
+}
+
+const uint32_t L_MASK=U_MASK(U_LEFT_TO_RIGHT);
+const uint32_t R_AL_MASK=U_MASK(U_RIGHT_TO_LEFT)|U_MASK(U_RIGHT_TO_LEFT_ARABIC);
+const uint32_t L_R_AL_MASK=L_MASK|R_AL_MASK;
+
+const uint32_t R_AL_AN_MASK=R_AL_MASK|U_MASK(U_ARABIC_NUMBER);
+
+const uint32_t EN_AN_MASK=U_MASK(U_EUROPEAN_NUMBER)|U_MASK(U_ARABIC_NUMBER);
+const uint32_t R_AL_EN_AN_MASK=R_AL_MASK|EN_AN_MASK;
+const uint32_t L_EN_MASK=L_MASK|U_MASK(U_EUROPEAN_NUMBER);
+
+const uint32_t ES_CS_ET_ON_BN_NSM_MASK=
+    U_MASK(U_EUROPEAN_NUMBER_SEPARATOR)|
+    U_MASK(U_COMMON_NUMBER_SEPARATOR)|
+    U_MASK(U_EUROPEAN_NUMBER_TERMINATOR)|
+    U_MASK(U_OTHER_NEUTRAL)|
+    U_MASK(U_BOUNDARY_NEUTRAL)|
+    U_MASK(U_DIR_NON_SPACING_MARK);
+const uint32_t L_EN_ES_CS_ET_ON_BN_NSM_MASK=L_EN_MASK|ES_CS_ET_ON_BN_NSM_MASK;
+const uint32_t R_AL_AN_EN_ES_CS_ET_ON_BN_NSM_MASK=R_AL_MASK|EN_AN_MASK|ES_CS_ET_ON_BN_NSM_MASK;
+
+// We scan the whole label and check both for whether it contains RTL characters
+// and whether it passes the BiDi Rule.
+// In a BiDi domain name, all labels must pass the BiDi Rule, but we might find
+// that a domain name is a BiDi domain name (has an RTL label) only after
+// processing several earlier labels.
+void
+UTS46::checkLabelBiDi(const UChar *label, int32_t labelLength, IDNAInfo &info) const {
+    // IDNA2008 BiDi rule
+    // Get the directionality of the first character.
+    UChar32 c;
+    int32_t i=0;
+    U16_NEXT_UNSAFE(label, i, c);
+    uint32_t firstMask=U_MASK(u_charDirection(c));
+    // 1. The first character must be a character with BIDI property L, R
+    // or AL.  If it has the R or AL property, it is an RTL label; if it
+    // has the L property, it is an LTR label.
+    if((firstMask&~L_R_AL_MASK)!=0) {
+        info.isOkBiDi=FALSE;
+    }
+    // Get the directionality of the last non-NSM character.
+    uint32_t lastMask;
+    for(;;) {
+        if(i>=labelLength) {
+            lastMask=firstMask;
+            break;
+        }
+        U16_PREV_UNSAFE(label, labelLength, c);
+        UCharDirection dir=u_charDirection(c);
+        if(dir!=U_DIR_NON_SPACING_MARK) {
+            lastMask=U_MASK(dir);
+            break;
+        }
+    }
+    // 3. In an RTL label, the end of the label must be a character with
+    // BIDI property R, AL, EN or AN, followed by zero or more
+    // characters with BIDI property NSM.
+    // 6. In an LTR label, the end of the label must be a character with
+    // BIDI property L or EN, followed by zero or more characters with
+    // BIDI property NSM.
+    if( (firstMask&L_MASK)!=0 ?
+            (lastMask&~L_EN_MASK)!=0 :
+            (lastMask&~R_AL_EN_AN_MASK)!=0
+    ) {
+        info.isOkBiDi=FALSE;
+    }
+    // Get the directionalities of the intervening characters.
+    uint32_t mask=0;
+    while(i<labelLength) {
+        U16_NEXT_UNSAFE(label, i, c);
+        mask|=U_MASK(u_charDirection(c));
+    }
+    if(firstMask&L_MASK) {
+        // 5. In an LTR label, only characters with the BIDI properties L, EN,
+        // ES, CS, ET, ON, BN and NSM are allowed.
+        if((mask&~L_EN_ES_CS_ET_ON_BN_NSM_MASK)!=0) {
+            info.isOkBiDi=FALSE;
+        }
+    } else {
+        // 2. In an RTL label, only characters with the BIDI properties R, AL,
+        // AN, EN, ES, CS, ET, ON, BN and NSM are allowed.
+        if((mask&~R_AL_AN_EN_ES_CS_ET_ON_BN_NSM_MASK)!=0) {
+            info.isOkBiDi=FALSE;
+        }
+        // 4. In an RTL label, if an EN is present, no AN may be present, and
+        // vice versa.
+        if((mask&EN_AN_MASK)==EN_AN_MASK) {
+            info.isOkBiDi=FALSE;
+        }
+    }
+    // An RTL label is a label that contains at least one character of type
+    // R, AL or AN. [...]
+    // A "BIDI domain name" is a domain name that contains at least one RTL
+    // label. [...]
+    // The following rule, consisting of six conditions, applies to labels
+    // in BIDI domain names.
+    if(((firstMask|mask|lastMask)&R_AL_AN_MASK)!=0) {
+        info.isBiDi=TRUE;
+    }
+}
+
+// Special code for the ASCII prefix of a BiDi domain name.
+// The ASCII prefix is all-LTR.
+
+// IDNA2008 BiDi rule, parts relevant to ASCII labels:
+// 1. The first character must be a character with BIDI property L [...]
+// 5. In an LTR label, only characters with the BIDI properties L, EN,
+// ES, CS, ET, ON, BN and NSM are allowed.
+// 6. In an LTR label, the end of the label must be a character with
+// BIDI property L or EN [...]
+
+// UTF-16 version, called for mapped ASCII prefix.
+// Cannot contain uppercase A-Z.
+// s[length-1] must be the trailing dot.
+static UBool
+isASCIIOkBiDi(const UChar *s, int32_t length) {
+    int32_t labelStart=0;
+    for(int32_t i=0; i<length; ++i) {
+        UChar c=s[i];
+        if(c==0x2e) {  // dot
+            if(i>labelStart) {
+                c=s[i-1];
+                if(!(0x61<=c && c<=0x7a) && !(0x30<=c && c<=0x39)) {
+                    // Last character in the label is not an L or EN.
+                    return FALSE;
+                }
+            }
+            labelStart=i+1;
+        } else if(i==labelStart) {
+            if(!(0x61<=c && c<=0x7a)) {
+                // First character in the label is not an L.
+                return FALSE;
+            }
+        } else {
+            if(c<=0x20 && (c>=0x1c || (9<=c && c<=0xd))) {
+                // Intermediate character in the label is a B, S or WS.
+                return FALSE;
+            }
+        }
+    }
+    return TRUE;
+}
+
+// UTF-8 version, called for source ASCII prefix.
+// Can contain uppercase A-Z.
+// s[length-1] must be the trailing dot.
+static UBool
+isASCIIOkBiDi(const char *s, int32_t length) {
+    int32_t labelStart=0;
+    for(int32_t i=0; i<length; ++i) {
+        char c=s[i];
+        if(c==0x2e) {  // dot
+            if(i>labelStart) {
+                c=s[i-1];
+                if(!(0x61<=c && c<=0x7a) && !(0x41<=c && c<=0x5a) && !(0x30<=c && c<=0x39)) {
+                    // Last character in the label is not an L or EN.
+                    return FALSE;
+                }
+            }
+            labelStart=i+1;
+        } else if(i==labelStart) {
+            if(!(0x61<=c && c<=0x7a) && !(0x41<=c && c<=0x5a)) {
+                // First character in the label is not an L.
+                return FALSE;
+            }
+        } else {
+            if(c<=0x20 && (c>=0x1c || (9<=c && c<=0xd))) {
+                // Intermediate character in the label is a B, S or WS.
+                return FALSE;
+            }
+        }
+    }
+    return TRUE;
+}
+
+UBool
+UTS46::isLabelOkContextJ(const UChar *label, int32_t labelLength) const {
+    // [IDNA2008-Tables]
+    // 200C..200D  ; CONTEXTJ    # ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER
+    for(int32_t i=0; i<labelLength; ++i) {
+        if(label[i]==0x200c) {
+            // Appendix A.1. ZERO WIDTH NON-JOINER
+            // Rule Set:
+            //  False;
+            //  If Canonical_Combining_Class(Before(cp)) .eq.  Virama Then True;
+            //  If RegExpMatch((Joining_Type:{L,D})(Joining_Type:T)*\u200C
+            //     (Joining_Type:T)*(Joining_Type:{R,D})) Then True;
+            if(i==0) {
+                return FALSE;
+            }
+            UChar32 c;
+            int32_t j=i;
+            U16_PREV_UNSAFE(label, j, c);
+            if(u_getCombiningClass(c)==9) {
+                continue;
+            }
+            // check precontext (Joining_Type:{L,D})(Joining_Type:T)*
+            for(;;) {
+                UJoiningType type=(UJoiningType)u_getIntPropertyValue(c, UCHAR_JOINING_TYPE);
+                if(type==U_JT_TRANSPARENT) {
+                    if(j==0) {
+                        return FALSE;
+                    }
+                    U16_PREV_UNSAFE(label, j, c);
+                } else if(type==U_JT_LEFT_JOINING || type==U_JT_DUAL_JOINING) {
+                    break;  // precontext fulfilled
+                } else {
+                    return FALSE;
+                }
+            }
+            // check postcontext (Joining_Type:T)*(Joining_Type:{R,D})
+            for(j=i+1;;) {
+                if(j==labelLength) {
+                    return FALSE;
+                }
+                U16_NEXT_UNSAFE(label, j, c);
+                UJoiningType type=(UJoiningType)u_getIntPropertyValue(c, UCHAR_JOINING_TYPE);
+                if(type==U_JT_TRANSPARENT) {
+                    // just skip this character
+                } else if(type==U_JT_RIGHT_JOINING || type==U_JT_DUAL_JOINING) {
+                    break;  // postcontext fulfilled
+                } else {
+                    return FALSE;
+                }
+            }
+        } else if(label[i]==0x200d) {
+            // Appendix A.2. ZERO WIDTH JOINER (U+200D)
+            // Rule Set:
+            //  False;
+            //  If Canonical_Combining_Class(Before(cp)) .eq.  Virama Then True;
+            if(i==0) {
+                return FALSE;
+            }
+            UChar32 c;
+            int32_t j=i;
+            U16_PREV_UNSAFE(label, j, c);
+            if(u_getCombiningClass(c)!=9) {
+                return FALSE;
+            }
+        }
+    }
+    return TRUE;
+}
+
+U_NAMESPACE_END
+
+// C API ------------------------------------------------------------------- ***
+
+U_NAMESPACE_USE
+
+U_DRAFT UIDNA * U_EXPORT2
+uidna_openUTS46(uint32_t options, UErrorCode *pErrorCode) {
+    return reinterpret_cast<UIDNA *>(IDNA::createUTS46Instance(options, *pErrorCode));
+}
+
+U_DRAFT void U_EXPORT2
+uidna_close(UIDNA *idna) {
+    delete reinterpret_cast<IDNA *>(idna);
+}
+
+static UBool
+checkArgs(const void *label, int32_t length,
+          void *dest, int32_t capacity,
+          UIDNAInfo *pInfo, UErrorCode *pErrorCode) {
+    if(U_FAILURE(*pErrorCode)) {
+        return FALSE;
+    }
+    // sizeof(UIDNAInfo)=16 in the first API version.
+    if(pInfo==NULL || pInfo->size<16) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return FALSE;
+    }
+    if( (label==NULL ? length!=0 : length<-1) ||
+        (dest==NULL ? capacity!=0 : capacity<0) ||
+        (dest==label && label!=NULL)
+    ) {
+        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+        return FALSE;
+    }
+    // Set all *pInfo bytes to 0 except for the size field itself.
+    uprv_memset(&pInfo->size+1, 0, pInfo->size-sizeof(pInfo->size));
+    return TRUE;
+}
+
+static void
+idnaInfoToStruct(IDNAInfo &info, UIDNAInfo *pInfo) {
+    pInfo->isTransitionalDifferent=info.isTransitionalDifferent();
+    pInfo->errors=info.getErrors();
+}
+
+U_DRAFT int32_t U_EXPORT2
+uidna_labelToASCII(const UIDNA *idna,
+                   const UChar *label, int32_t length,
+                   UChar *dest, int32_t capacity,
+                   UIDNAInfo *pInfo, UErrorCode *pErrorCode) {
+    if(!checkArgs(label, length, dest, capacity, pInfo, pErrorCode)) {
+        return 0;
+    }
+    UnicodeString src((UBool)(length<0), label, length);
+    UnicodeString destString(dest, 0, capacity);
+    IDNAInfo info;
+    reinterpret_cast<const IDNA *>(idna)->labelToASCII(src, destString, info, *pErrorCode);
+    idnaInfoToStruct(info, pInfo);
+    return destString.extract(dest, capacity, *pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+uidna_labelToUnicode(const UIDNA *idna,
+                     const UChar *label, int32_t length,
+                     UChar *dest, int32_t capacity,
+                     UIDNAInfo *pInfo, UErrorCode *pErrorCode) {
+    if(!checkArgs(label, length, dest, capacity, pInfo, pErrorCode)) {
+        return 0;
+    }
+    UnicodeString src((UBool)(length<0), label, length);
+    UnicodeString destString(dest, 0, capacity);
+    IDNAInfo info;
+    reinterpret_cast<const IDNA *>(idna)->labelToUnicode(src, destString, info, *pErrorCode);
+    idnaInfoToStruct(info, pInfo);
+    return destString.extract(dest, capacity, *pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+uidna_nameToASCII(const UIDNA *idna,
+                  const UChar *name, int32_t length,
+                  UChar *dest, int32_t capacity,
+                  UIDNAInfo *pInfo, UErrorCode *pErrorCode) {
+    if(!checkArgs(name, length, dest, capacity, pInfo, pErrorCode)) {
+        return 0;
+    }
+    UnicodeString src((UBool)(length<0), name, length);
+    UnicodeString destString(dest, 0, capacity);
+    IDNAInfo info;
+    reinterpret_cast<const IDNA *>(idna)->nameToASCII(src, destString, info, *pErrorCode);
+    idnaInfoToStruct(info, pInfo);
+    return destString.extract(dest, capacity, *pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+uidna_nameToUnicode(const UIDNA *idna,
+                    const UChar *name, int32_t length,
+                    UChar *dest, int32_t capacity,
+                    UIDNAInfo *pInfo, UErrorCode *pErrorCode) {
+    if(!checkArgs(name, length, dest, capacity, pInfo, pErrorCode)) {
+        return 0;
+    }
+    UnicodeString src((UBool)(length<0), name, length);
+    UnicodeString destString(dest, 0, capacity);
+    IDNAInfo info;
+    reinterpret_cast<const IDNA *>(idna)->nameToUnicode(src, destString, info, *pErrorCode);
+    idnaInfoToStruct(info, pInfo);
+    return destString.extract(dest, capacity, *pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+uidna_labelToASCII_UTF8(const UIDNA *idna,
+                        const char *label, int32_t length,
+                        char *dest, int32_t capacity,
+                        UIDNAInfo *pInfo, UErrorCode *pErrorCode) {
+    if(!checkArgs(label, length, dest, capacity, pInfo, pErrorCode)) {
+        return 0;
+    }
+    StringPiece src(label, length<0 ? uprv_strlen(label) : length);
+    CheckedArrayByteSink sink(dest, capacity);
+    IDNAInfo info;
+    reinterpret_cast<const IDNA *>(idna)->labelToASCII_UTF8(src, sink, info, *pErrorCode);
+    idnaInfoToStruct(info, pInfo);
+    return u_terminateChars(dest, capacity, sink.NumberOfBytesAppended(), pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+uidna_labelToUnicodeUTF8(const UIDNA *idna,
+                         const char *label, int32_t length,
+                         char *dest, int32_t capacity,
+                         UIDNAInfo *pInfo, UErrorCode *pErrorCode) {
+    if(!checkArgs(label, length, dest, capacity, pInfo, pErrorCode)) {
+        return 0;
+    }
+    StringPiece src(label, length<0 ? uprv_strlen(label) : length);
+    CheckedArrayByteSink sink(dest, capacity);
+    IDNAInfo info;
+    reinterpret_cast<const IDNA *>(idna)->labelToUnicodeUTF8(src, sink, info, *pErrorCode);
+    idnaInfoToStruct(info, pInfo);
+    return u_terminateChars(dest, capacity, sink.NumberOfBytesAppended(), pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+uidna_nameToASCII_UTF8(const UIDNA *idna,
+                       const char *name, int32_t length,
+                       char *dest, int32_t capacity,
+                       UIDNAInfo *pInfo, UErrorCode *pErrorCode) {
+    if(!checkArgs(name, length, dest, capacity, pInfo, pErrorCode)) {
+        return 0;
+    }
+    StringPiece src(name, length<0 ? uprv_strlen(name) : length);
+    CheckedArrayByteSink sink(dest, capacity);
+    IDNAInfo info;
+    reinterpret_cast<const IDNA *>(idna)->nameToASCII_UTF8(src, sink, info, *pErrorCode);
+    idnaInfoToStruct(info, pInfo);
+    return u_terminateChars(dest, capacity, sink.NumberOfBytesAppended(), pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+uidna_nameToUnicodeUTF8(const UIDNA *idna,
+                        const char *name, int32_t length,
+                        char *dest, int32_t capacity,
+                        UIDNAInfo *pInfo, UErrorCode *pErrorCode) {
+    if(!checkArgs(name, length, dest, capacity, pInfo, pErrorCode)) {
+        return 0;
+    }
+    StringPiece src(name, length<0 ? uprv_strlen(name) : length);
+    CheckedArrayByteSink sink(dest, capacity);
+    IDNAInfo info;
+    reinterpret_cast<const IDNA *>(idna)->nameToUnicodeUTF8(src, sink, info, *pErrorCode);
+    idnaInfoToStruct(info, pInfo);
+    return u_terminateChars(dest, capacity, sink.NumberOfBytesAppended(), pErrorCode);
+}
+
+#endif  // UCONFIG_NO_IDNA
diff --git a/source/common/utypes.c b/source/common/utypes.c
new file mode 100644
index 0000000..b8041ac
--- /dev/null
+++ b/source/common/utypes.c
@@ -0,0 +1,219 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1997-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+*  FILE NAME : utypes.c (previously putil.c)
+*
+*   Date        Name        Description
+*   10/07/2004  grhoten     split from putil.c
+******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+/* u_errorName() ------------------------------------------------------------ */
+
+static const char * const
+_uErrorInfoName[U_ERROR_WARNING_LIMIT-U_ERROR_WARNING_START]={
+    "U_USING_FALLBACK_WARNING",
+    "U_USING_DEFAULT_WARNING",
+    "U_SAFECLONE_ALLOCATED_WARNING",
+    "U_STATE_OLD_WARNING",
+    "U_STRING_NOT_TERMINATED_WARNING",
+    "U_SORT_KEY_TOO_SHORT_WARNING",
+    "U_AMBIGUOUS_ALIAS_WARNING",
+    "U_DIFFERENT_UCA_VERSION",
+    "U_PLUGIN_CHANGED_LEVEL_WARNING",
+};
+
+static const char * const
+_uTransErrorName[U_PARSE_ERROR_LIMIT - U_PARSE_ERROR_START]={
+    "U_BAD_VARIABLE_DEFINITION",
+    "U_MALFORMED_RULE",
+    "U_MALFORMED_SET",
+    "U_MALFORMED_SYMBOL_REFERENCE",
+    "U_MALFORMED_UNICODE_ESCAPE",
+    "U_MALFORMED_VARIABLE_DEFINITION",
+    "U_MALFORMED_VARIABLE_REFERENCE",
+    "U_MISMATCHED_SEGMENT_DELIMITERS",
+    "U_MISPLACED_ANCHOR_START",
+    "U_MISPLACED_CURSOR_OFFSET",
+    "U_MISPLACED_QUANTIFIER",
+    "U_MISSING_OPERATOR",
+    "U_MISSING_SEGMENT_CLOSE",
+    "U_MULTIPLE_ANTE_CONTEXTS",
+    "U_MULTIPLE_CURSORS",
+    "U_MULTIPLE_POST_CONTEXTS",
+    "U_TRAILING_BACKSLASH",
+    "U_UNDEFINED_SEGMENT_REFERENCE",
+    "U_UNDEFINED_VARIABLE",
+    "U_UNQUOTED_SPECIAL",
+    "U_UNTERMINATED_QUOTE",
+    "U_RULE_MASK_ERROR",
+    "U_MISPLACED_COMPOUND_FILTER",
+    "U_MULTIPLE_COMPOUND_FILTERS",
+    "U_INVALID_RBT_SYNTAX",
+    "U_INVALID_PROPERTY_PATTERN",
+    "U_MALFORMED_PRAGMA",
+    "U_UNCLOSED_SEGMENT",
+    "U_ILLEGAL_CHAR_IN_SEGMENT",
+    "U_VARIABLE_RANGE_EXHAUSTED",
+    "U_VARIABLE_RANGE_OVERLAP",
+    "U_ILLEGAL_CHARACTER",
+    "U_INTERNAL_TRANSLITERATOR_ERROR",
+    "U_INVALID_ID",
+    "U_INVALID_FUNCTION"
+};
+
+static const char * const
+_uErrorName[U_STANDARD_ERROR_LIMIT]={
+    "U_ZERO_ERROR",
+
+    "U_ILLEGAL_ARGUMENT_ERROR",
+    "U_MISSING_RESOURCE_ERROR",
+    "U_INVALID_FORMAT_ERROR",
+    "U_FILE_ACCESS_ERROR",
+    "U_INTERNAL_PROGRAM_ERROR",
+    "U_MESSAGE_PARSE_ERROR",
+    "U_MEMORY_ALLOCATION_ERROR",
+    "U_INDEX_OUTOFBOUNDS_ERROR",
+    "U_PARSE_ERROR",
+    "U_INVALID_CHAR_FOUND",
+    "U_TRUNCATED_CHAR_FOUND",
+    "U_ILLEGAL_CHAR_FOUND",
+    "U_INVALID_TABLE_FORMAT",
+    "U_INVALID_TABLE_FILE",
+    "U_BUFFER_OVERFLOW_ERROR",
+    "U_UNSUPPORTED_ERROR",
+    "U_RESOURCE_TYPE_MISMATCH",
+    "U_ILLEGAL_ESCAPE_SEQUENCE",
+    "U_UNSUPPORTED_ESCAPE_SEQUENCE",
+    "U_NO_SPACE_AVAILABLE",
+    "U_CE_NOT_FOUND_ERROR",
+    "U_PRIMARY_TOO_LONG_ERROR",
+    "U_STATE_TOO_OLD_ERROR",
+    "U_TOO_MANY_ALIASES_ERROR",
+    "U_ENUM_OUT_OF_SYNC_ERROR",
+    "U_INVARIANT_CONVERSION_ERROR",
+    "U_INVALID_STATE_ERROR",
+    "U_COLLATOR_VERSION_MISMATCH",
+    "U_USELESS_COLLATOR_ERROR",
+    "U_NO_WRITE_PERMISSION"
+};
+static const char * const
+_uFmtErrorName[U_FMT_PARSE_ERROR_LIMIT - U_FMT_PARSE_ERROR_START] = {
+    "U_UNEXPECTED_TOKEN",
+    "U_MULTIPLE_DECIMAL_SEPARATORS",
+    "U_MULTIPLE_EXPONENTIAL_SYMBOLS",
+    "U_MALFORMED_EXPONENTIAL_PATTERN",
+    "U_MULTIPLE_PERCENT_SYMBOLS",
+    "U_MULTIPLE_PERMILL_SYMBOLS",
+    "U_MULTIPLE_PAD_SPECIFIERS",
+    "U_PATTERN_SYNTAX_ERROR",
+    "U_ILLEGAL_PAD_POSITION",
+    "U_UNMATCHED_BRACES",
+    "U_UNSUPPORTED_PROPERTY",
+    "U_UNSUPPORTED_ATTRIBUTE",
+    "U_ARGUMENT_TYPE_MISMATCH",
+    "U_DUPLICATE_KEYWORD",
+    "U_UNDEFINED_KEYWORD",
+    "U_DEFAULT_KEYWORD_MISSING",
+    "U_DECIMAL_NUMBER_SYNTAX_ERROR"
+};
+
+static const char * const
+_uBrkErrorName[U_BRK_ERROR_LIMIT - U_BRK_ERROR_START] = {
+    "U_BRK_INTERNAL_ERROR",
+    "U_BRK_HEX_DIGITS_EXPECTED",
+    "U_BRK_SEMICOLON_EXPECTED",
+    "U_BRK_RULE_SYNTAX",
+    "U_BRK_UNCLOSED_SET",
+    "U_BRK_ASSIGN_ERROR",
+    "U_BRK_VARIABLE_REDFINITION",
+    "U_BRK_MISMATCHED_PAREN",
+    "U_BRK_NEW_LINE_IN_QUOTED_STRING",
+    "U_BRK_UNDEFINED_VARIABLE",
+    "U_BRK_INIT_ERROR",
+    "U_BRK_RULE_EMPTY_SET",
+    "U_BRK_UNRECOGNIZED_OPTION",
+    "U_BRK_MALFORMED_RULE_TAG"
+};
+
+static const char * const
+_uRegexErrorName[U_REGEX_ERROR_LIMIT - U_REGEX_ERROR_START] = {
+    "U_REGEX_INTERNAL_ERROR",
+    "U_REGEX_RULE_SYNTAX",
+    "U_REGEX_INVALID_STATE",
+    "U_REGEX_BAD_ESCAPE_SEQUENCE",
+    "U_REGEX_PROPERTY_SYNTAX",
+    "U_REGEX_UNIMPLEMENTED",
+    "U_REGEX_MISMATCHED_PAREN",
+    "U_REGEX_NUMBER_TOO_BIG",
+    "U_REGEX_BAD_INTERVAL",
+    "U_REGEX_MAX_LT_MIN",
+    "U_REGEX_INVALID_BACK_REF",
+    "U_REGEX_INVALID_FLAG",
+    "U_REGEX_LOOK_BEHIND_LIMIT",
+    "U_REGEX_SET_CONTAINS_STRING",
+    "U_REGEX_OCTAL_TOO_BIG",
+    "U_REGEX_MISSING_CLOSE_BRACKET",
+    "U_REGEX_INVALID_RANGE",
+    "U_REGEX_STACK_OVERFLOW",
+    "U_REGEX_TIME_OUT",
+    "U_REGEX_STOPPED_BY_CALLER"
+};
+
+static const char * const
+_uIDNAErrorName[U_IDNA_ERROR_LIMIT - U_IDNA_ERROR_START] = {
+     "U_STRINGPREP_PROHIBITED_ERROR",
+     "U_STRINGPREP_UNASSIGNED_ERROR",
+     "U_STRINGPREP_CHECK_BIDI_ERROR",
+     "U_IDNA_STD3_ASCII_RULES_ERROR",
+     "U_IDNA_ACE_PREFIX_ERROR",
+     "U_IDNA_VERIFICATION_ERROR",
+     "U_IDNA_LABEL_TOO_LONG_ERROR",
+     "U_IDNA_ZERO_LENGTH_LABEL_ERROR",
+     "U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR"
+};
+
+static const char * const
+_uPluginErrorName[U_PLUGIN_ERROR_LIMIT - U_PLUGIN_ERROR_START] = {
+     "U_PLUGIN_TOO_HIGH",
+     "U_PLUGIN_DIDNT_SET_LEVEL",
+};
+
+U_CAPI const char * U_EXPORT2
+u_errorName(UErrorCode code) {
+    if(U_ZERO_ERROR <= code && code < U_STANDARD_ERROR_LIMIT) {
+        return _uErrorName[code];
+    } else if(U_ERROR_WARNING_START <= code && code < U_ERROR_WARNING_LIMIT) {
+        return _uErrorInfoName[code - U_ERROR_WARNING_START];
+    } else if(U_PARSE_ERROR_START <= code && code < U_PARSE_ERROR_LIMIT){
+        return _uTransErrorName[code - U_PARSE_ERROR_START];
+    } else if(U_FMT_PARSE_ERROR_START <= code && code < U_FMT_PARSE_ERROR_LIMIT){
+        return _uFmtErrorName[code - U_FMT_PARSE_ERROR_START];
+    } else if (U_BRK_ERROR_START <= code  && code < U_BRK_ERROR_LIMIT){
+        return _uBrkErrorName[code - U_BRK_ERROR_START];
+    } else if (U_REGEX_ERROR_START <= code && code < U_REGEX_ERROR_LIMIT) {
+        return _uRegexErrorName[code - U_REGEX_ERROR_START];
+    } else if(U_IDNA_ERROR_START <= code && code < U_IDNA_ERROR_LIMIT) {
+        return _uIDNAErrorName[code - U_IDNA_ERROR_START];
+    } else if(U_PLUGIN_ERROR_START <= code && code < U_PLUGIN_ERROR_LIMIT) {
+        return _uPluginErrorName[code - U_PLUGIN_ERROR_START];
+    } else {
+        return "[BOGUS UErrorCode]";
+    }
+}
+
+/*
+ * Hey, Emacs, please set the following:
+ *
+ * Local Variables:
+ * indent-tabs-mode: nil
+ * End:
+ *
+ */
diff --git a/source/common/uvector.cpp b/source/common/uvector.cpp
new file mode 100644
index 0000000..d0ecb44
--- /dev/null
+++ b/source/common/uvector.cpp
@@ -0,0 +1,553 @@
+/*
+******************************************************************************
+* Copyright (C) 1999-2010, International Business Machines Corporation and   *
+* others. All Rights Reserved.                                               *
+******************************************************************************
+*   Date        Name        Description
+*   10/22/99    alan        Creation.
+**********************************************************************
+*/
+
+#include "uvector.h"
+#include "cmemory.h"
+#include "uarrsort.h"
+
+U_NAMESPACE_BEGIN
+
+#define DEFAULT_CAPACITY 8
+
+/*
+ * Constants for hinting whether a key is an integer
+ * or a pointer.  If a hint bit is zero, then the associated
+ * token is assumed to be an integer. This is needed for iSeries
+ */
+#define HINT_KEY_POINTER   (1)
+#define HINT_KEY_INTEGER   (0)
+ 
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UVector)
+
+UVector::UVector(UErrorCode &status) :
+    count(0),
+    capacity(0),
+    elements(0),
+    deleter(0),
+    comparer(0)
+{
+    _init(DEFAULT_CAPACITY, status);
+}
+
+UVector::UVector(int32_t initialCapacity, UErrorCode &status) :
+    count(0),
+    capacity(0),
+    elements(0),
+    deleter(0),
+    comparer(0)
+{
+    _init(initialCapacity, status);
+}
+
+UVector::UVector(UObjectDeleter *d, UKeyComparator *c, UErrorCode &status) :
+    count(0),
+    capacity(0),
+    elements(0),
+    deleter(d),
+    comparer(c)
+{
+    _init(DEFAULT_CAPACITY, status);
+}
+
+UVector::UVector(UObjectDeleter *d, UKeyComparator *c, int32_t initialCapacity, UErrorCode &status) :
+    count(0),
+    capacity(0),
+    elements(0),
+    deleter(d),
+    comparer(c)
+{
+    _init(initialCapacity, status);
+}
+
+void UVector::_init(int32_t initialCapacity, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return;
+    }
+    // Fix bogus initialCapacity values; avoid malloc(0) and integer overflow
+    if ((initialCapacity < 1) || (initialCapacity > (int32_t)(INT32_MAX / sizeof(UHashTok)))) {
+        initialCapacity = DEFAULT_CAPACITY;
+    }
+    elements = (UHashTok *)uprv_malloc(sizeof(UHashTok)*initialCapacity);
+    if (elements == 0) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+    } else {
+        capacity = initialCapacity;
+    }
+}
+
+UVector::~UVector() {
+    removeAllElements();
+    uprv_free(elements);
+    elements = 0;
+}
+
+/**
+ * Assign this object to another (make this a copy of 'other').
+ * Use the 'assign' function to assign each element.
+ */
+void UVector::assign(const UVector& other, UTokenAssigner *assign, UErrorCode &ec) {
+    if (ensureCapacity(other.count, ec)) {
+        setSize(other.count, ec);
+        if (U_SUCCESS(ec)) {
+            for (int32_t i=0; i<other.count; ++i) {
+                if (elements[i].pointer != 0 && deleter != 0) {
+                    (*deleter)(elements[i].pointer);
+                }
+                (*assign)(&elements[i], &other.elements[i]);
+            }
+        }
+    }
+}
+
+// This only does something sensible if this object has a non-null comparer
+UBool UVector::operator==(const UVector& other) {
+    int32_t i;
+    if (count != other.count) return FALSE;
+    if (comparer != NULL) {
+        // Compare using this object's comparer
+        for (i=0; i<count; ++i) {
+            if (!(*comparer)(elements[i], other.elements[i])) {
+                return FALSE;
+            }
+        }
+    }
+    return TRUE;
+}
+
+void UVector::addElement(void* obj, UErrorCode &status) {
+    if (ensureCapacity(count + 1, status)) {
+        elements[count++].pointer = obj;
+    }
+}
+
+void UVector::addElement(int32_t elem, UErrorCode &status) {
+    if (ensureCapacity(count + 1, status)) {
+        elements[count].pointer = NULL;     // Pointers may be bigger than ints.
+        elements[count].integer = elem;
+        count++;
+    }
+}
+
+void UVector::setElementAt(void* obj, int32_t index) {
+    if (0 <= index && index < count) {
+        if (elements[index].pointer != 0 && deleter != 0) {
+            (*deleter)(elements[index].pointer);
+        }
+        elements[index].pointer = obj;
+    }
+    /* else index out of range */
+}
+
+void UVector::setElementAt(int32_t elem, int32_t index) {
+    if (0 <= index && index < count) {
+        if (elements[index].pointer != 0 && deleter != 0) {
+            // TODO:  this should be an error.  mixing up ints and pointers.
+            (*deleter)(elements[index].pointer);
+        }
+        elements[index].pointer = NULL;
+        elements[index].integer = elem;
+    }
+    /* else index out of range */
+}
+
+void UVector::insertElementAt(void* obj, int32_t index, UErrorCode &status) {
+    // must have 0 <= index <= count
+    if (0 <= index && index <= count && ensureCapacity(count + 1, status)) {
+        for (int32_t i=count; i>index; --i) {
+            elements[i] = elements[i-1];
+        }
+        elements[index].pointer = obj;
+        ++count;
+    }
+    /* else index out of range */
+}
+
+void UVector::insertElementAt(int32_t elem, int32_t index, UErrorCode &status) {
+    // must have 0 <= index <= count
+    if (0 <= index && index <= count && ensureCapacity(count + 1, status)) {
+        for (int32_t i=count; i>index; --i) {
+            elements[i] = elements[i-1];
+        }
+        elements[index].pointer = NULL;
+        elements[index].integer = elem;
+        ++count;
+    }
+    /* else index out of range */
+}
+
+void* UVector::elementAt(int32_t index) const {
+    return (0 <= index && index < count) ? elements[index].pointer : 0;
+}
+
+int32_t UVector::elementAti(int32_t index) const {
+    return (0 <= index && index < count) ? elements[index].integer : 0;
+}
+
+UBool UVector::containsAll(const UVector& other) const {
+    for (int32_t i=0; i<other.size(); ++i) {
+        if (indexOf(other.elements[i]) < 0) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+UBool UVector::containsNone(const UVector& other) const {
+    for (int32_t i=0; i<other.size(); ++i) {
+        if (indexOf(other.elements[i]) >= 0) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+UBool UVector::removeAll(const UVector& other) {
+    UBool changed = FALSE;
+    for (int32_t i=0; i<other.size(); ++i) {
+        int32_t j = indexOf(other.elements[i]);
+        if (j >= 0) {
+            removeElementAt(j);
+            changed = TRUE;
+        }
+    }
+    return changed;
+}
+
+UBool UVector::retainAll(const UVector& other) {
+    UBool changed = FALSE;
+    for (int32_t j=size()-1; j>=0; --j) {
+        int32_t i = other.indexOf(elements[j]);
+        if (i < 0) {
+            removeElementAt(j);
+            changed = TRUE;
+        }
+    }
+    return changed;
+}
+
+void UVector::removeElementAt(int32_t index) {
+    void* e = orphanElementAt(index);
+    if (e != 0 && deleter != 0) {
+        (*deleter)(e);
+    }
+}
+
+UBool UVector::removeElement(void* obj) {
+    int32_t i = indexOf(obj);
+    if (i >= 0) {
+        removeElementAt(i);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+void UVector::removeAllElements(void) {
+    if (deleter != 0) {
+        for (int32_t i=0; i<count; ++i) {
+            if (elements[i].pointer != 0) {
+                (*deleter)(elements[i].pointer);
+            }
+        }
+    }
+    count = 0;
+}
+
+UBool   UVector::equals(const UVector &other) const {
+    int      i;
+
+    if (this->count != other.count) {
+        return FALSE;
+    }
+    if (comparer == 0) {
+        for (i=0; i<count; i++) {
+            if (elements[i].pointer != other.elements[i].pointer) {
+                return FALSE;
+            }
+        }
+    } else {
+        UHashTok key;
+        for (i=0; i<count; i++) {
+            key.pointer = &other.elements[i];
+            if (!(*comparer)(key, elements[i])) {
+                return FALSE;
+            }
+        }
+    }
+    return TRUE;
+}
+
+
+
+int32_t UVector::indexOf(void* obj, int32_t startIndex) const {
+    UHashTok key;
+    key.pointer = obj;
+    return indexOf(key, startIndex, HINT_KEY_POINTER);
+}
+
+int32_t UVector::indexOf(int32_t obj, int32_t startIndex) const {
+    UHashTok key;
+    key.integer = obj;
+    return indexOf(key, startIndex, HINT_KEY_INTEGER);
+}
+
+// This only works if this object has a non-null comparer
+int32_t UVector::indexOf(UHashTok key, int32_t startIndex, int8_t hint) const {
+    int32_t i;
+    if (comparer != 0) {
+        for (i=startIndex; i<count; ++i) {
+            if ((*comparer)(key, elements[i])) {
+                return i;
+            }
+        }
+    } else {
+        for (i=startIndex; i<count; ++i) {
+            /* Pointers are not always the same size as ints so to perform
+             * a valid comparision we need to know whether we are being
+             * provided an int or a pointer. */
+            if (hint & HINT_KEY_POINTER) {
+                if (key.pointer == elements[i].pointer) {
+                    return i;
+                }
+            } else {
+                if (key.integer == elements[i].integer) {
+                    return i;
+                }
+            }
+        }
+    }
+    return -1;
+}
+
+UBool UVector::ensureCapacity(int32_t minimumCapacity, UErrorCode &status) {
+	if (minimumCapacity < 0) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return FALSE;
+	}
+    if (capacity < minimumCapacity) {
+        if (capacity > (INT32_MAX - 1) / 2) {        	// integer overflow check
+        	status = U_ILLEGAL_ARGUMENT_ERROR;
+        	return FALSE;
+        }
+        int32_t newCap = capacity * 2;
+        if (newCap < minimumCapacity) {
+            newCap = minimumCapacity;
+        }
+        if (newCap > (int32_t)(INT32_MAX / sizeof(UHashTok))) {	// integer overflow check
+        	// We keep the original memory contents on bad minimumCapacity.
+        	status = U_ILLEGAL_ARGUMENT_ERROR;
+        	return FALSE;
+        }
+        UHashTok* newElems = (UHashTok *)uprv_realloc(elements, sizeof(UHashTok)*newCap);
+        if (newElems == NULL) {
+            // We keep the original contents on the memory failure on realloc or bad minimumCapacity.
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return FALSE;
+        }
+        elements = newElems;
+        capacity = newCap;
+    }
+    return TRUE;
+}
+
+/**
+ * Change the size of this vector as follows: If newSize is smaller,
+ * then truncate the array, possibly deleting held elements for i >=
+ * newSize.  If newSize is larger, grow the array, filling in new
+ * slots with NULL.
+ */
+void UVector::setSize(int32_t newSize, UErrorCode &status) {
+    int32_t i;
+    if (newSize < 0) {
+        return;
+    }
+    if (newSize > count) {
+        if (!ensureCapacity(newSize, status)) {
+            return;
+        }
+        UHashTok empty;
+        empty.pointer = NULL;
+        empty.integer = 0;
+        for (i=count; i<newSize; ++i) {
+            elements[i] = empty;
+        }
+    } else {
+        /* Most efficient to count down */
+        for (i=count-1; i>=newSize; --i) {
+            removeElementAt(i);
+        }
+    }
+    count = newSize;
+}
+
+/**
+ * Fill in the given array with all elements of this vector.
+ */
+void** UVector::toArray(void** result) const {
+    void** a = result;
+    for (int i=0; i<count; ++i) {
+        *a++ = elements[i].pointer;
+    }
+    return result;
+}
+
+UObjectDeleter *UVector::setDeleter(UObjectDeleter *d) {
+    UObjectDeleter *old = deleter;
+    deleter = d;
+    return old;
+}
+
+UKeyComparator *UVector::setComparer(UKeyComparator *d) {
+    UKeyComparator *old = comparer;
+    comparer = d;
+    return old;
+}
+
+/**
+ * Removes the element at the given index from this vector and
+ * transfer ownership of it to the caller.  After this call, the
+ * caller owns the result and must delete it and the vector entry
+ * at 'index' is removed, shifting all subsequent entries back by
+ * one index and shortening the size of the vector by one.  If the
+ * index is out of range or if there is no item at the given index
+ * then 0 is returned and the vector is unchanged.
+ */
+void* UVector::orphanElementAt(int32_t index) {
+    void* e = 0;
+    if (0 <= index && index < count) {
+        e = elements[index].pointer;
+        for (int32_t i=index; i<count-1; ++i) {
+            elements[i] = elements[i+1];
+        }
+        --count;
+    }
+    /* else index out of range */
+    return e;
+}
+
+/**
+ * Insert the given object into this vector at its sorted position
+ * as defined by 'compare'.  The current elements are assumed to
+ * be sorted already.
+ */
+void UVector::sortedInsert(void* obj, USortComparator *compare, UErrorCode& ec) {
+    UHashTok tok;
+    tok.pointer = obj;
+    sortedInsert(tok, compare, ec);
+}
+
+/**
+ * Insert the given integer into this vector at its sorted position
+ * as defined by 'compare'.  The current elements are assumed to
+ * be sorted already.
+ */
+void UVector::sortedInsert(int32_t obj, USortComparator *compare, UErrorCode& ec) {
+    UHashTok tok;
+    tok.integer = obj;
+    sortedInsert(tok, compare, ec);
+}
+
+// ASSUME elements[] IS CURRENTLY SORTED
+void UVector::sortedInsert(UHashTok tok, USortComparator *compare, UErrorCode& ec) {
+    // Perform a binary search for the location to insert tok at.  Tok
+    // will be inserted between two elements a and b such that a <=
+    // tok && tok < b, where there is a 'virtual' elements[-1] always
+    // less than tok and a 'virtual' elements[count] always greater
+    // than tok.
+    int32_t min = 0, max = count;
+    while (min != max) {
+        int32_t probe = (min + max) / 2;
+        int8_t c = (*compare)(elements[probe], tok);
+        if (c > 0) {
+            max = probe;
+        } else {
+            // assert(c <= 0);
+            min = probe + 1;
+        }
+    }
+    if (ensureCapacity(count + 1, ec)) {
+        for (int32_t i=count; i>min; --i) {
+            elements[i] = elements[i-1];
+        }
+        elements[min] = tok;
+        ++count;
+    }
+}
+
+/**
+  *  Array sort comparator function.
+  *  Used from UVector::sort()
+  *  Conforms to function signature required for uprv_sortArray().
+  *  This function is essentially just a wrapper, to make a
+  *  UVector style comparator function usable with uprv_sortArray().
+  *
+  *  The context pointer to this function is a pointer back
+  *  (with some extra indirection) to the user supplied comparator.
+  *  
+  */
+static int32_t U_CALLCONV
+sortComparator(const void *context, const void *left, const void *right) {
+    USortComparator *compare = *static_cast<USortComparator * const *>(context);
+    UHashTok tok1 = *static_cast<const UHashTok *>(left);
+    UHashTok tok2 = *static_cast<const UHashTok *>(right);
+    int32_t result = (*compare)(tok1, tok2);
+    return result;
+}
+
+
+/**
+  *  Array sort comparison function for use from UVector::sorti()
+  *  Compares int32_t vector elements.
+  */
+static int32_t U_CALLCONV
+sortiComparator(const void * /*context */, const void *left, const void *right) {
+    const UHashTok *tok1 = static_cast<const UHashTok *>(left);
+    const UHashTok *tok2 = static_cast<const UHashTok *>(right);
+    int32_t result = tok1->integer < tok2->integer? -1 :
+                     tok1->integer == tok2->integer? 0 : 1;
+    return result;
+}
+
+/**
+  * Sort the vector, assuming it constains ints.
+  *     (A more general sort would take a comparison function, but it's
+  *     not clear whether UVector's USortComparator or
+  *     UComparator from uprv_sortAray would be more appropriate.)
+  */
+void UVector::sorti(UErrorCode &ec) {
+    if (U_SUCCESS(ec)) {
+        uprv_sortArray(elements, count, sizeof(UHashTok),
+                       sortiComparator, NULL,  FALSE, &ec);
+    }
+}
+
+
+/**
+ *  Sort with a user supplied comparator.
+ *
+ *    The comparator function handling is confusing because the function type
+ *    for UVector  (as defined for sortedInsert()) is different from the signature
+ *    required by uprv_sortArray().  This is handled by passing the
+ *    the UVector sort function pointer via the context pointer to a
+ *    sortArray() comparator function, which can then call back to
+ *    the original user functtion.
+ *
+ *    An additional twist is that it's not safe to pass a pointer-to-function
+ *    as  a (void *) data pointer, so instead we pass a (data) pointer to a
+ *    pointer-to-function variable.
+ */
+void UVector::sort(USortComparator *compare, UErrorCode &ec) {
+    if (U_SUCCESS(ec)) {
+        uprv_sortArray(elements, count, sizeof(UHashTok),
+                       sortComparator, &compare, FALSE, &ec);
+    }
+}
+
+U_NAMESPACE_END
+
diff --git a/source/common/uvector.h b/source/common/uvector.h
new file mode 100644
index 0000000..2724cb1
--- /dev/null
+++ b/source/common/uvector.h
@@ -0,0 +1,422 @@
+/*
+**********************************************************************
+*   Copyright (C) 1999-2009, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*   Date        Name        Description
+*   10/22/99    alan        Creation.  This is an internal header.
+*                           It should not be exported.
+**********************************************************************
+*/
+
+#ifndef UVECTOR_H
+#define UVECTOR_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "uhash.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A token comparison function.
+ * @param tok1 A token (object or integer)
+ * @param tok2 A token (object or integer)
+ * @return 0 if the two tokens are equal, -1 if tok1 is < tok2, or
+ * +1 if tok1 is > tok2.
+ */
+typedef int8_t U_CALLCONV USortComparator(UHashTok tok1,
+                                          UHashTok tok2);
+
+/**
+ * A token assignment function.  It may copy an integer, copy
+ * a pointer, or clone a pointer, as appropriate.
+ * @param dst The token to be assigned to
+ * @param src The token to assign from
+ */
+typedef void U_CALLCONV UTokenAssigner(UHashTok *dst,
+                                       UHashTok *src);
+
+/**
+ * <p>Ultralightweight C++ implementation of a <tt>void*</tt> vector
+ * that is (mostly) compatible with java.util.Vector.
+ *
+ * <p>This is a very simple implementation, written to satisfy an
+ * immediate porting need.  As such, it is not completely fleshed out,
+ * and it aims for simplicity and conformity.  Nonetheless, it serves
+ * its purpose (porting code from java that uses java.util.Vector)
+ * well, and it could be easily made into a more robust vector class.
+ *
+ * <p><b>Design notes</b>
+ *
+ * <p>There is index bounds checking, but little is done about it.  If
+ * indices are out of bounds, either nothing happens, or zero is
+ * returned.  We <em>do</em> avoid indexing off into the weeds.
+ *
+ * <p>There is detection of out of memory, but the handling is very
+ * coarse-grained -- similar to UnicodeString's protocol, but even
+ * coarser.  The class contains <em>one static flag</em> that is set
+ * when any call to <tt>new</tt> returns zero.  This allows the caller
+ * to use several vectors and make just one check at the end to see if
+ * a memory failure occurred.  This is more efficient than making a
+ * check after each call on each vector when doing many operations on
+ * multiple vectors.  The single static flag works best when memory
+ * failures are infrequent, and when recovery options are limited or
+ * nonexistent.
+ *
+ * <p>Since we don't have garbage collection, UVector was given the
+ * option to <em>own</em>its contents.  To employ this, set a deleter
+ * function.  The deleter is called on a void* pointer when that
+ * pointer is released by the vector, either when the vector itself is
+ * destructed, or when a call to setElementAt() overwrites an element,
+ * or when a call to remove() or one of its variants explicitly
+ * removes an element.  If no deleter is set, or the deleter is set to
+ * zero, then it is assumed that the caller will delete elements as
+ * needed.
+ *
+ * <p>In order to implement methods such as contains() and indexOf(),
+ * UVector needs a way to compare objects for equality.  To do so, it
+ * uses a comparison frunction, or "comparer."  If the comparer is not
+ * set, or is set to zero, then all such methods will act as if the
+ * vector contains no element.  That is, indexOf() will always return
+ * -1, contains() will always return FALSE, etc.
+ *
+ * <p><b>To do</b>
+ *
+ * <p>Improve the handling of index out of bounds errors.
+ *
+ * @author Alan Liu
+ */
+class U_COMMON_API UVector : public UObject {
+    // NOTE: UVector uses the UHashKey (union of void* and int32_t) as
+    // its basic storage type.  It uses UKeyComparator as its
+    // comparison function.  It uses UObjectDeleter as its deleter
+    // function.  These are named for hashtables, but used here as-is
+    // rather than duplicating the type.  This allows sharing of
+    // support functions.
+
+private:
+    int32_t count;
+
+    int32_t capacity;
+
+    UHashTok* elements;
+
+    UObjectDeleter *deleter;
+
+    UKeyComparator *comparer;
+
+public:
+    UVector(UErrorCode &status);
+
+    UVector(int32_t initialCapacity, UErrorCode &status);
+
+    UVector(UObjectDeleter *d, UKeyComparator *c, UErrorCode &status);
+
+    UVector(UObjectDeleter *d, UKeyComparator *c, int32_t initialCapacity, UErrorCode &status);
+
+    virtual ~UVector();
+
+    /**
+     * Assign this object to another (make this a copy of 'other').
+     * Use the 'assign' function to assign each element.
+     */
+    void assign(const UVector& other, UTokenAssigner *assign, UErrorCode &ec);
+
+    /**
+     * Compare this vector with another.  They will be considered
+     * equal if they are of the same size and all elements are equal,
+     * as compared using this object's comparer.
+     */
+    UBool operator==(const UVector& other);
+
+    /**
+     * Equivalent to !operator==()
+     */
+    inline UBool operator!=(const UVector& other);
+
+    //------------------------------------------------------------
+    // java.util.Vector API
+    //------------------------------------------------------------
+
+    void addElement(void* obj, UErrorCode &status);
+
+    void addElement(int32_t elem, UErrorCode &status);
+
+    void setElementAt(void* obj, int32_t index);
+
+    void setElementAt(int32_t elem, int32_t index);
+
+    void insertElementAt(void* obj, int32_t index, UErrorCode &status);
+
+    void insertElementAt(int32_t elem, int32_t index, UErrorCode &status);
+    
+    void* elementAt(int32_t index) const;
+
+    int32_t elementAti(int32_t index) const;
+
+    UBool equals(const UVector &other) const;
+
+    void* firstElement(void) const;
+
+    void* lastElement(void) const;
+
+    int32_t lastElementi(void) const;
+
+    int32_t indexOf(void* obj, int32_t startIndex = 0) const;
+
+    int32_t indexOf(int32_t obj, int32_t startIndex = 0) const;
+
+    UBool contains(void* obj) const;
+
+    UBool contains(int32_t obj) const;
+
+    UBool containsAll(const UVector& other) const;
+
+    UBool removeAll(const UVector& other);
+
+    UBool retainAll(const UVector& other);
+
+    void removeElementAt(int32_t index);
+
+    UBool removeElement(void* obj);
+
+    void removeAllElements();
+
+    int32_t size(void) const;
+
+    UBool isEmpty(void) const;
+
+    UBool ensureCapacity(int32_t minimumCapacity, UErrorCode &status);
+
+    /**
+     * Change the size of this vector as follows: If newSize is
+     * smaller, then truncate the array, possibly deleting held
+     * elements for i >= newSize.  If newSize is larger, grow the
+     * array, filling in new slots with NULL.
+     */
+    void setSize(int32_t newSize, UErrorCode &status);
+
+    /**
+     * Fill in the given array with all elements of this vector.
+     */
+    void** toArray(void** result) const;
+
+    //------------------------------------------------------------
+    // New API
+    //------------------------------------------------------------
+
+    UObjectDeleter *setDeleter(UObjectDeleter *d);
+
+    UKeyComparator *setComparer(UKeyComparator *c);
+
+    void* operator[](int32_t index) const;
+
+    /**
+     * Removes the element at the given index from this vector and
+     * transfer ownership of it to the caller.  After this call, the
+     * caller owns the result and must delete it and the vector entry
+     * at 'index' is removed, shifting all subsequent entries back by
+     * one index and shortening the size of the vector by one.  If the
+     * index is out of range or if there is no item at the given index
+     * then 0 is returned and the vector is unchanged.
+     */
+    void* orphanElementAt(int32_t index);
+
+    /**
+     * Returns true if this vector contains none of the elements
+     * of the given vector.
+     * @param other vector to be checked for containment
+     * @return true if the test condition is met
+     */
+    UBool containsNone(const UVector& other) const;
+
+    /**
+     * Insert the given object into this vector at its sorted position
+     * as defined by 'compare'.  The current elements are assumed to
+     * be sorted already.
+     */
+    void sortedInsert(void* obj, USortComparator *compare, UErrorCode& ec);
+
+    /**
+     * Insert the given integer into this vector at its sorted position
+     * as defined by 'compare'.  The current elements are assumed to
+     * be sorted already.
+     */
+    void sortedInsert(int32_t obj, USortComparator *compare, UErrorCode& ec);
+
+    /**
+     * Sort the contents of the vector, assuming that the contents of the
+     * vector are of type int32_t.
+     */
+    void sorti(UErrorCode &ec);
+
+    /**
+      * Sort the contents of this vector, using a caller-supplied function
+      * to do the comparisons.  (It's confusing that
+      *  UVector's USortComparator function is different from the
+      *  UComparator function type defined in uarrsort.h)
+      */
+    void sort(USortComparator *compare, UErrorCode &ec);
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     */
+    static UClassID U_EXPORT2 getStaticClassID();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     */
+    virtual UClassID getDynamicClassID() const;
+
+private:
+    void _init(int32_t initialCapacity, UErrorCode &status);
+
+    int32_t indexOf(UHashTok key, int32_t startIndex = 0, int8_t hint = 0) const;
+
+    void sortedInsert(UHashTok tok, USortComparator *compare, UErrorCode& ec);
+
+    // Disallow
+    UVector(const UVector&);
+
+    // Disallow
+    UVector& operator=(const UVector&);
+
+};
+
+
+/**
+ * <p>Ultralightweight C++ implementation of a <tt>void*</tt> stack
+ * that is (mostly) compatible with java.util.Stack.  As in java, this
+ * is merely a paper thin layer around UVector.  See the UVector
+ * documentation for further information.
+ *
+ * <p><b>Design notes</b>
+ *
+ * <p>The element at index <tt>n-1</tt> is (of course) the top of the
+ * stack.
+ *
+ * <p>The poorly named <tt>empty()</tt> method doesn't empty the
+ * stack; it determines if the stack is empty.
+ *
+ * @author Alan Liu
+ */
+class U_COMMON_API UStack : public UVector {
+public:
+    UStack(UErrorCode &status);
+
+    UStack(int32_t initialCapacity, UErrorCode &status);
+
+    UStack(UObjectDeleter *d, UKeyComparator *c, UErrorCode &status);
+
+    UStack(UObjectDeleter *d, UKeyComparator *c, int32_t initialCapacity, UErrorCode &status);
+
+    virtual ~UStack();
+
+    // It's okay not to have a virtual destructor (in UVector)
+    // because UStack has no special cleanup to do.
+
+    UBool empty(void) const;
+
+    void* peek(void) const;
+
+    int32_t peeki(void) const;
+    
+    void* pop(void);
+    
+    int32_t popi(void);
+    
+    void* push(void* obj, UErrorCode &status);
+
+    int32_t push(int32_t i, UErrorCode &status);
+
+    /*
+    If the object o occurs as an item in this stack,
+    this method returns the 1-based distance from the top of the stack.
+    */
+    int32_t search(void* obj) const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     */
+    static UClassID U_EXPORT2 getStaticClassID();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     */
+    virtual UClassID getDynamicClassID() const;
+
+private:
+    // Disallow
+    UStack(const UStack&);
+
+    // Disallow
+    UStack& operator=(const UStack&);
+};
+
+
+// UVector inlines
+
+inline int32_t UVector::size(void) const {
+    return count;
+}
+
+inline UBool UVector::isEmpty(void) const {
+    return count == 0;
+}
+
+inline UBool UVector::contains(void* obj) const {
+    return indexOf(obj) >= 0;
+}
+
+inline UBool UVector::contains(int32_t obj) const {
+    return indexOf(obj) >= 0;
+}
+
+inline void* UVector::firstElement(void) const {
+    return elementAt(0);
+}
+
+inline void* UVector::lastElement(void) const {
+    return elementAt(count-1);
+}
+
+inline int32_t UVector::lastElementi(void) const {
+    return elementAti(count-1);
+}
+
+inline void* UVector::operator[](int32_t index) const {
+    return elementAt(index);
+}
+
+inline UBool UVector::operator!=(const UVector& other) {
+    return !operator==(other);
+}
+
+// UStack inlines
+
+inline UBool UStack::empty(void) const {
+    return isEmpty();
+}
+
+inline void* UStack::peek(void) const {
+    return lastElement();
+}
+
+inline int32_t UStack::peeki(void) const {
+    return lastElementi();
+}
+
+inline void* UStack::push(void* obj, UErrorCode &status) {
+    addElement(obj, status);
+    return obj;
+}
+
+inline int32_t UStack::push(int32_t i, UErrorCode &status) {
+    addElement(i, status);
+    return i;
+}
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/uvectr32.cpp b/source/common/uvectr32.cpp
new file mode 100644
index 0000000..f0ffa10
--- /dev/null
+++ b/source/common/uvectr32.cpp
@@ -0,0 +1,330 @@
+/*
+******************************************************************************
+* Copyright (C) 1999-2010, International Business Machines Corporation and   *
+* others. All Rights Reserved.                                               *
+******************************************************************************
+*   Date        Name        Description
+*   10/22/99    alan        Creation.
+**********************************************************************
+*/
+
+#include "uvectr32.h"
+#include "cmemory.h"
+#include "putilimp.h"
+
+U_NAMESPACE_BEGIN
+
+#define DEFAULT_CAPACITY 8
+
+/*
+ * Constants for hinting whether a key is an integer
+ * or a pointer.  If a hint bit is zero, then the associated
+ * token is assumed to be an integer. This is needed for iSeries
+ */
+ 
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UVector32)
+
+UVector32::UVector32(UErrorCode &status) :
+    count(0),
+    capacity(0),
+    maxCapacity(0),
+    elements(NULL)
+{
+    _init(DEFAULT_CAPACITY, status);
+}
+
+UVector32::UVector32(int32_t initialCapacity, UErrorCode &status) :
+    count(0),
+    capacity(0),
+    maxCapacity(0),
+    elements(0)
+{
+    _init(initialCapacity, status);
+}
+
+
+
+void UVector32::_init(int32_t initialCapacity, UErrorCode &status) {
+    // Fix bogus initialCapacity values; avoid malloc(0)
+    if (initialCapacity < 1) {
+        initialCapacity = DEFAULT_CAPACITY;
+    }
+    if (maxCapacity>0 && maxCapacity<initialCapacity) {
+        initialCapacity = maxCapacity;
+    }
+    if (initialCapacity > (int32_t)(INT32_MAX / sizeof(int32_t))) {
+        initialCapacity = uprv_min(DEFAULT_CAPACITY, maxCapacity);
+    }
+    elements = (int32_t *)uprv_malloc(sizeof(int32_t)*initialCapacity);
+    if (elements == 0) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+    } else {
+        capacity = initialCapacity;
+    }
+}
+
+UVector32::~UVector32() {
+    uprv_free(elements);
+    elements = 0;
+}
+
+/**
+ * Assign this object to another (make this a copy of 'other').
+ */
+void UVector32::assign(const UVector32& other, UErrorCode &ec) {
+    if (ensureCapacity(other.count, ec)) {
+        setSize(other.count);
+        for (int32_t i=0; i<other.count; ++i) {
+            elements[i] = other.elements[i];
+        }
+    }
+}
+
+
+UBool UVector32::operator==(const UVector32& other) {
+    int32_t i;
+    if (count != other.count) return FALSE;
+    for (i=0; i<count; ++i) {
+        if (elements[i] != other.elements[i]) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+
+void UVector32::setElementAt(int32_t elem, int32_t index) {
+    if (0 <= index && index < count) {
+        elements[index] = elem;
+    }
+    /* else index out of range */
+}
+
+void UVector32::insertElementAt(int32_t elem, int32_t index, UErrorCode &status) {
+    // must have 0 <= index <= count
+    if (0 <= index && index <= count && ensureCapacity(count + 1, status)) {
+        for (int32_t i=count; i>index; --i) {
+            elements[i] = elements[i-1];
+        }
+        elements[index] = elem;
+        ++count;
+    }
+    /* else index out of range */
+}
+
+UBool UVector32::containsAll(const UVector32& other) const {
+    for (int32_t i=0; i<other.size(); ++i) {
+        if (indexOf(other.elements[i]) < 0) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+UBool UVector32::containsNone(const UVector32& other) const {
+    for (int32_t i=0; i<other.size(); ++i) {
+        if (indexOf(other.elements[i]) >= 0) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+UBool UVector32::removeAll(const UVector32& other) {
+    UBool changed = FALSE;
+    for (int32_t i=0; i<other.size(); ++i) {
+        int32_t j = indexOf(other.elements[i]);
+        if (j >= 0) {
+            removeElementAt(j);
+            changed = TRUE;
+        }
+    }
+    return changed;
+}
+
+UBool UVector32::retainAll(const UVector32& other) {
+    UBool changed = FALSE;
+    for (int32_t j=size()-1; j>=0; --j) {
+        int32_t i = other.indexOf(elements[j]);
+        if (i < 0) {
+            removeElementAt(j);
+            changed = TRUE;
+        }
+    }
+    return changed;
+}
+
+void UVector32::removeElementAt(int32_t index) {
+    if (index >= 0) {
+        for (int32_t i=index; i<count-1; ++i) {
+            elements[i] = elements[i+1];
+        }
+        --count;
+    }
+}
+
+void UVector32::removeAllElements(void) {
+    count = 0;
+}
+
+UBool   UVector32::equals(const UVector32 &other) const {
+    int      i;
+
+    if (this->count != other.count) {
+        return FALSE;
+    }
+    for (i=0; i<count; i++) {
+        if (elements[i] != other.elements[i]) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+
+
+
+int32_t UVector32::indexOf(int32_t key, int32_t startIndex) const {
+    int32_t i;
+    for (i=startIndex; i<count; ++i) {
+        if (key == elements[i]) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+
+UBool UVector32::expandCapacity(int32_t minimumCapacity, UErrorCode &status) {
+    if (minimumCapacity < 0) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return FALSE;
+    }
+    if (capacity >= minimumCapacity) {
+        return TRUE;
+    }
+    if (maxCapacity>0 && minimumCapacity>maxCapacity) {
+        status = U_BUFFER_OVERFLOW_ERROR;
+        return FALSE;
+    }
+    if (capacity > (INT32_MAX - 1) / 2) {  // integer overflow check
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return FALSE;
+    }
+    int32_t newCap = capacity * 2;
+    if (newCap < minimumCapacity) {
+        newCap = minimumCapacity;
+    }
+    if (maxCapacity > 0 && newCap > maxCapacity) {
+        newCap = maxCapacity;
+    }
+    if (newCap > (int32_t)(INT32_MAX / sizeof(int32_t))) {  // integer overflow check
+        // We keep the original memory contents on bad minimumCapacity/maxCapacity.
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return FALSE;
+    }
+    int32_t* newElems = (int32_t *)uprv_realloc(elements, sizeof(int32_t)*newCap);
+    if (newElems == NULL) {
+        // We keep the original contents on the memory failure on realloc.
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return FALSE;
+    }
+    elements = newElems;
+    capacity = newCap;
+    return TRUE;
+}
+
+void UVector32::setMaxCapacity(int32_t limit) {
+    U_ASSERT(limit >= 0);
+    if (limit < 0) {
+        limit = 0;
+    }
+    if (limit > (int32_t)(INT32_MAX / sizeof(int32_t))) {  // integer overflow check for realloc
+        //  Something is very wrong, don't realloc, leave capacity and maxCapacity unchanged
+        return;
+    }
+    maxCapacity = limit;
+    if (capacity <= maxCapacity || maxCapacity == 0) {
+        // Current capacity is within the new limit.
+        return;
+    }
+    
+    // New maximum capacity is smaller than the current size.
+    // Realloc the storage to the new, smaller size.
+    int32_t* newElems = (int32_t *)uprv_realloc(elements, sizeof(int32_t)*maxCapacity);
+    if (newElems == NULL) {
+        // Realloc to smaller failed.
+        //   Just keep what we had.  No need to call it a failure.
+        return;
+    }
+    elements = newElems;
+    capacity = maxCapacity;
+    if (count > capacity) {
+        count = capacity;
+    }
+}
+
+/**
+ * Change the size of this vector as follows: If newSize is smaller,
+ * then truncate the array, possibly deleting held elements for i >=
+ * newSize.  If newSize is larger, grow the array, filling in new
+ * slots with NULL.
+ */
+void UVector32::setSize(int32_t newSize) {
+    int32_t i;
+    if (newSize < 0) {
+        return;
+    }
+    if (newSize > count) {
+        UErrorCode ec = U_ZERO_ERROR;
+        if (!ensureCapacity(newSize, ec)) {
+            return;
+        }
+        for (i=count; i<newSize; ++i) {
+            elements[i] = 0;
+        }
+    } 
+    count = newSize;
+}
+
+
+
+
+/**
+ * Insert the given integer into this vector at its sorted position
+ * as defined by 'compare'.  The current elements are assumed to
+ * be sorted already.
+ */
+void UVector32::sortedInsert(int32_t tok, UErrorCode& ec) {
+    // Perform a binary search for the location to insert tok at.  Tok
+    // will be inserted between two elements a and b such that a <=
+    // tok && tok < b, where there is a 'virtual' elements[-1] always
+    // less than tok and a 'virtual' elements[count] always greater
+    // than tok.
+    int32_t min = 0, max = count;
+    while (min != max) {
+        int32_t probe = (min + max) / 2;
+        //int8_t c = (*compare)(elements[probe], tok);
+        //if (c > 0) {
+        if (elements[probe] > tok) {
+            max = probe;
+        } else {
+            // assert(c <= 0);
+            min = probe + 1;
+        }
+    }
+    if (ensureCapacity(count + 1, ec)) {
+        for (int32_t i=count; i>min; --i) {
+            elements[i] = elements[i-1];
+        }
+        elements[min] = tok;
+        ++count;
+    }
+}
+
+
+
+
+
+U_NAMESPACE_END
+
diff --git a/source/common/uvectr32.h b/source/common/uvectr32.h
new file mode 100644
index 0000000..ff49d49
--- /dev/null
+++ b/source/common/uvectr32.h
@@ -0,0 +1,304 @@
+/*
+**********************************************************************
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+
+//
+//  UVector32 is a class implementing a vector of 32 bit integers.
+//            It is similar to UVector, but holds int32_t values rather than pointers.
+//            Most of the code is unchanged from UVector.
+//
+
+#ifndef UVECTOR32_H
+#define UVECTOR32_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "uhash.h"
+#include "uassert.h"
+
+U_NAMESPACE_BEGIN
+
+
+
+/**
+ * <p>Ultralightweight C++ implementation of a <tt>void*</tt> vector
+ * that is (mostly) compatible with java.util.Vector.
+ *
+ * <p>This is a very simple implementation, written to satisfy an
+ * immediate porting need.  As such, it is not completely fleshed out,
+ * and it aims for simplicity and conformity.  Nonetheless, it serves
+ * its purpose (porting code from java that uses java.util.Vector)
+ * well, and it could be easily made into a more robust vector class.
+ *
+ * <p><b>Design notes</b>
+ *
+ * <p>There is index bounds checking, but little is done about it.  If
+ * indices are out of bounds, either nothing happens, or zero is
+ * returned.  We <em>do</em> avoid indexing off into the weeds.
+ *
+ * <p>There is detection of out of memory, but the handling is very
+ * coarse-grained -- similar to UnicodeString's protocol, but even
+ * coarser.  The class contains <em>one static flag</em> that is set
+ * when any call to <tt>new</tt> returns zero.  This allows the caller
+ * to use several vectors and make just one check at the end to see if
+ * a memory failure occurred.  This is more efficient than making a
+ * check after each call on each vector when doing many operations on
+ * multiple vectors.  The single static flag works best when memory
+ * failures are infrequent, and when recovery options are limited or
+ * nonexistent.
+ *
+ * <p><b>To do</b>
+ *
+ * <p>Improve the handling of index out of bounds errors.
+ *
+ * @author Alan Liu
+ */
+class U_COMMON_API UVector32 : public UObject {
+private:
+    int32_t   count;
+
+    int32_t   capacity;
+    
+    int32_t   maxCapacity;   // Limit beyond which capacity is not permitted to grow.
+
+    int32_t*  elements;
+
+public:
+    UVector32(UErrorCode &status);
+
+    UVector32(int32_t initialCapacity, UErrorCode &status);
+
+    virtual ~UVector32();
+
+    /**
+     * Assign this object to another (make this a copy of 'other').
+     * Use the 'assign' function to assign each element.
+     */
+    void assign(const UVector32& other, UErrorCode &ec);
+
+    /**
+     * Compare this vector with another.  They will be considered
+     * equal if they are of the same size and all elements are equal,
+     * as compared using this object's comparer.
+     */
+    UBool operator==(const UVector32& other);
+
+    /**
+     * Equivalent to !operator==()
+     */
+    inline UBool operator!=(const UVector32& other);
+
+    //------------------------------------------------------------
+    // java.util.Vector API
+    //------------------------------------------------------------
+
+    void addElement(int32_t elem, UErrorCode &status);
+
+    void setElementAt(int32_t elem, int32_t index);
+
+    void insertElementAt(int32_t elem, int32_t index, UErrorCode &status);
+    
+    int32_t elementAti(int32_t index) const;
+
+    UBool equals(const UVector32 &other) const;
+
+    int32_t lastElementi(void) const;
+
+    int32_t indexOf(int32_t elem, int32_t startIndex = 0) const;
+
+    UBool contains(int32_t elem) const;
+
+    UBool containsAll(const UVector32& other) const;
+
+    UBool removeAll(const UVector32& other);
+
+    UBool retainAll(const UVector32& other);
+
+    void removeElementAt(int32_t index);
+
+    void removeAllElements();
+
+    int32_t size(void) const;
+
+    UBool isEmpty(void) const;
+
+    // Inline.  Use this one for speedy size check.
+    inline UBool ensureCapacity(int32_t minimumCapacity, UErrorCode &status);
+
+    // Out-of-line, handles actual growth.  Called by ensureCapacity() when necessary.
+    UBool expandCapacity(int32_t minimumCapacity, UErrorCode &status);
+
+    /**
+     * Change the size of this vector as follows: If newSize is
+     * smaller, then truncate the array, possibly deleting held
+     * elements for i >= newSize.  If newSize is larger, grow the
+     * array, filling in new slows with zero.
+     */
+    void setSize(int32_t newSize);
+
+    //------------------------------------------------------------
+    // New API
+    //------------------------------------------------------------
+
+    /**
+     * Returns true if this vector contains none of the elements
+     * of the given vector.
+     * @param other vector to be checked for containment
+     * @return true if the test condition is met
+     */
+    UBool containsNone(const UVector32& other) const;
+
+
+    /**
+     * Insert the given integer into this vector at its sorted position.
+     * The current elements are assumed to be sorted already.
+     */
+    void sortedInsert(int32_t elem, UErrorCode& ec);
+
+    /**
+     * Returns a pointer to the internal array holding the vector.
+     */
+    int32_t *getBuffer() const;
+
+    /**
+     * Set the maximum allowed buffer capacity for this vector/stack.
+     * Default with no limit set is unlimited, go until malloc() fails.
+     * A Limit of zero means unlimited capacity.
+     * Units are vector elements (32 bits each), not bytes.
+     */
+    void setMaxCapacity(int32_t limit);
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     */
+    static UClassID U_EXPORT2 getStaticClassID();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     */
+    virtual UClassID getDynamicClassID() const;
+
+private:
+    void _init(int32_t initialCapacity, UErrorCode &status);
+
+    // Disallow
+    UVector32(const UVector32&);
+
+    // Disallow
+    UVector32& operator=(const UVector32&);
+
+
+    //  API Functions for Stack operations.
+    //  In the original UVector, these were in a separate derived class, UStack.
+    //  Here in UVector32, they are all together.
+public:
+    UBool empty(void) const;   // TODO:  redundant, same as empty().  Remove it?
+
+    int32_t peeki(void) const;
+    
+    int32_t popi(void);
+    
+    int32_t push(int32_t i, UErrorCode &status);
+
+    int32_t *reserveBlock(int32_t size, UErrorCode &status);
+    int32_t *popFrame(int32_t size);
+};
+
+
+// UVector32 inlines
+
+inline UBool UVector32::ensureCapacity(int32_t minimumCapacity, UErrorCode &status) {
+    if ((minimumCapacity >= 0) && (capacity >= minimumCapacity)) {
+        return TRUE;
+    } else {
+        return expandCapacity(minimumCapacity, status);
+    }
+}
+
+inline int32_t UVector32::elementAti(int32_t index) const {
+    return (0 <= index && index < count) ? elements[index] : 0;
+}
+
+
+inline void UVector32::addElement(int32_t elem, UErrorCode &status) {
+    if (ensureCapacity(count + 1, status)) {
+        elements[count] = elem;
+        count++;
+    }
+}
+
+inline int32_t *UVector32::reserveBlock(int32_t size, UErrorCode &status) {
+    if (ensureCapacity(count+size, status) == FALSE) {
+        return NULL;
+    }
+    int32_t  *rp = elements+count;
+    count += size;
+    return rp;
+}
+
+inline int32_t *UVector32::popFrame(int32_t size) {
+    U_ASSERT(count >= size);
+    count -= size;
+    if (count < 0) {
+        count = 0;
+    }
+    return elements+count-size;
+}
+
+
+
+inline int32_t UVector32::size(void) const {
+    return count;
+}
+
+inline UBool UVector32::isEmpty(void) const {
+    return count == 0;
+}
+
+inline UBool UVector32::contains(int32_t obj) const {
+    return indexOf(obj) >= 0;
+}
+
+inline int32_t UVector32::lastElementi(void) const {
+    return elementAti(count-1);
+}
+
+inline UBool UVector32::operator!=(const UVector32& other) {
+    return !operator==(other);
+}
+
+inline int32_t *UVector32::getBuffer() const {
+    return elements;
+}
+
+
+// UStack inlines
+
+inline UBool UVector32::empty(void) const {
+    return isEmpty();
+}
+
+inline int32_t UVector32::peeki(void) const {
+    return lastElementi();
+}
+
+inline int32_t UVector32::push(int32_t i, UErrorCode &status) {
+    addElement(i, status);
+    return i;
+}
+
+inline int32_t UVector32::popi(void) {
+    int32_t result = 0;
+    if (count > 0) {
+        count--;
+        result = elements[count];
+    }
+    return result;
+}
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/uvectr64.cpp b/source/common/uvectr64.cpp
new file mode 100644
index 0000000..c09ed51
--- /dev/null
+++ b/source/common/uvectr64.cpp
@@ -0,0 +1,209 @@
+/*
+******************************************************************************
+* Copyright (C) 1999-2010, International Business Machines Corporation and   *
+* others. All Rights Reserved.                                               *
+******************************************************************************
+*/
+
+#include "uvectr64.h"
+#include "cmemory.h"
+#include "putilimp.h"
+
+U_NAMESPACE_BEGIN
+
+#define DEFAULT_CAPACITY 8
+
+/*
+ * Constants for hinting whether a key is an integer
+ * or a pointer.  If a hint bit is zero, then the associated
+ * token is assumed to be an integer. This is needed for iSeries
+ */
+ 
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UVector64)
+
+UVector64::UVector64(UErrorCode &status) :
+    count(0),
+    capacity(0),
+    maxCapacity(0),
+    elements(NULL)
+{
+    _init(DEFAULT_CAPACITY, status);
+}
+
+UVector64::UVector64(int32_t initialCapacity, UErrorCode &status) :
+    count(0),
+    capacity(0),
+    maxCapacity(0),
+    elements(0)
+{
+    _init(initialCapacity, status);
+}
+
+
+
+void UVector64::_init(int32_t initialCapacity, UErrorCode &status) {
+    // Fix bogus initialCapacity values; avoid malloc(0)
+    if (initialCapacity < 1) {
+        initialCapacity = DEFAULT_CAPACITY;
+    }
+    if (maxCapacity>0 && maxCapacity<initialCapacity) {
+        initialCapacity = maxCapacity;
+    }
+    if (initialCapacity > (int32_t)(INT32_MAX / sizeof(int64_t))) {
+        initialCapacity = uprv_min(DEFAULT_CAPACITY, maxCapacity);
+    }
+    elements = (int64_t *)uprv_malloc(sizeof(int64_t)*initialCapacity);
+    if (elements == 0) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+    } else {
+        capacity = initialCapacity;
+    }
+}
+
+UVector64::~UVector64() {
+    uprv_free(elements);
+    elements = 0;
+}
+
+/**
+ * Assign this object to another (make this a copy of 'other').
+ */
+void UVector64::assign(const UVector64& other, UErrorCode &ec) {
+    if (ensureCapacity(other.count, ec)) {
+        setSize(other.count);
+        for (int32_t i=0; i<other.count; ++i) {
+            elements[i] = other.elements[i];
+        }
+    }
+}
+
+
+UBool UVector64::operator==(const UVector64& other) {
+    int32_t i;
+    if (count != other.count) return FALSE;
+    for (i=0; i<count; ++i) {
+        if (elements[i] != other.elements[i]) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+
+void UVector64::setElementAt(int64_t elem, int32_t index) {
+    if (0 <= index && index < count) {
+        elements[index] = elem;
+    }
+    /* else index out of range */
+}
+
+void UVector64::insertElementAt(int64_t elem, int32_t index, UErrorCode &status) {
+    // must have 0 <= index <= count
+    if (0 <= index && index <= count && ensureCapacity(count + 1, status)) {
+        for (int32_t i=count; i>index; --i) {
+            elements[i] = elements[i-1];
+        }
+        elements[index] = elem;
+        ++count;
+    }
+    /* else index out of range */
+}
+
+void UVector64::removeAllElements(void) {
+    count = 0;
+}
+
+UBool UVector64::expandCapacity(int32_t minimumCapacity, UErrorCode &status) {
+    if (minimumCapacity < 0) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return FALSE;
+    }
+    if (capacity >= minimumCapacity) {
+        return TRUE;
+    }
+    if (maxCapacity>0 && minimumCapacity>maxCapacity) {
+        status = U_BUFFER_OVERFLOW_ERROR;
+        return FALSE;
+    }
+    if (capacity > (INT32_MAX - 1) / 2) {  // integer overflow check
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return FALSE;
+    }
+    int32_t newCap = capacity * 2;
+    if (newCap < minimumCapacity) {
+        newCap = minimumCapacity;
+    }
+    if (maxCapacity > 0 && newCap > maxCapacity) {
+        newCap = maxCapacity;
+    }
+    if (newCap > (int32_t)(INT32_MAX / sizeof(int64_t))) {  // integer overflow check
+        // We keep the original memory contents on bad minimumCapacity/maxCapacity.
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return FALSE;
+    }
+    int64_t* newElems = (int64_t *)uprv_realloc(elements, sizeof(int64_t)*newCap);
+    if (newElems == NULL) {
+        // We keep the original contents on the memory failure on realloc.
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return FALSE;
+    }
+    elements = newElems;
+    capacity = newCap;
+    return TRUE;
+}
+
+void UVector64::setMaxCapacity(int32_t limit) {
+    U_ASSERT(limit >= 0);
+    if (limit < 0) {
+        limit = 0;
+    }
+    if (limit > (int32_t)(INT32_MAX / sizeof(int64_t))) {  // integer overflow check for realloc
+        //  Something is very wrong, don't realloc, leave capacity and maxCapacity unchanged
+        return;
+    }
+    maxCapacity = limit;
+    if (capacity <= maxCapacity || maxCapacity == 0) {
+        // Current capacity is within the new limit.
+        return;
+    }
+    
+    // New maximum capacity is smaller than the current size.
+    // Realloc the storage to the new, smaller size.
+    int64_t* newElems = (int64_t *)uprv_realloc(elements, sizeof(int64_t)*maxCapacity);
+    if (newElems == NULL) {
+        // Realloc to smaller failed.
+        //   Just keep what we had.  No need to call it a failure.
+        return;
+    }
+    elements = newElems;
+    capacity = maxCapacity;
+    if (count > capacity) {
+        count = capacity;
+    }
+}
+
+/**
+ * Change the size of this vector as follows: If newSize is smaller,
+ * then truncate the array, possibly deleting held elements for i >=
+ * newSize.  If newSize is larger, grow the array, filling in new
+ * slots with NULL.
+ */
+void UVector64::setSize(int32_t newSize) {
+    int32_t i;
+    if (newSize < 0) {
+        return;
+    }
+    if (newSize > count) {
+        UErrorCode ec = U_ZERO_ERROR;
+        if (!ensureCapacity(newSize, ec)) {
+            return;
+        }
+        for (i=count; i<newSize; ++i) {
+            elements[i] = 0;
+        }
+    } 
+    count = newSize;
+}
+
+U_NAMESPACE_END
+
diff --git a/source/common/uvectr64.h b/source/common/uvectr64.h
new file mode 100644
index 0000000..05cbc35
--- /dev/null
+++ b/source/common/uvectr64.h
@@ -0,0 +1,277 @@
+/*
+**********************************************************************
+*   Copyright (C) 1999-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+
+//
+//  UVector64 is a class implementing a vector of 64 bit integers.
+//            It is similar to UVector32, but holds int64_t values rather than int32_t.
+//            Most of the code is unchanged from UVector.
+//
+
+#ifndef UVECTOR64_H
+#define UVECTOR64_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "uhash.h"
+#include "uassert.h"
+
+U_NAMESPACE_BEGIN
+
+
+
+/**
+ * <p>Ultralightweight C++ implementation of an <tt>int64_t</tt> vector
+ * that has a subset of methods from UVector32
+ *
+ * <p>This is a very simple implementation, written to satisfy an
+ * immediate porting need.  As such, it is not completely fleshed out,
+ * and it aims for simplicity and conformity.  Nonetheless, it serves
+ * its purpose (porting code from java that uses java.util.Vector)
+ * well, and it could be easily made into a more robust vector class.
+ *
+ * <p><b>Design notes</b>
+ *
+ * <p>There is index bounds checking, but little is done about it.  If
+ * indices are out of bounds, either nothing happens, or zero is
+ * returned.  We <em>do</em> avoid indexing off into the weeds.
+ *
+ * <p>There is detection of out of memory, but the handling is very
+ * coarse-grained -- similar to UnicodeString's protocol, but even
+ * coarser.  The class contains <em>one static flag</em> that is set
+ * when any call to <tt>new</tt> returns zero.  This allows the caller
+ * to use several vectors and make just one check at the end to see if
+ * a memory failure occurred.  This is more efficient than making a
+ * check after each call on each vector when doing many operations on
+ * multiple vectors.  The single static flag works best when memory
+ * failures are infrequent, and when recovery options are limited or
+ * nonexistent.
+ *
+ * <p><b>To do</b>
+ *
+ * <p>Improve the handling of index out of bounds errors.
+ *
+ */
+class U_COMMON_API UVector64 : public UObject {
+private:
+    int32_t   count;
+
+    int32_t   capacity;
+    
+    int32_t   maxCapacity;   // Limit beyond which capacity is not permitted to grow.
+
+    int64_t*  elements;
+
+public:
+    UVector64(UErrorCode &status);
+
+    UVector64(int32_t initialCapacity, UErrorCode &status);
+
+    virtual ~UVector64();
+
+    /**
+     * Assign this object to another (make this a copy of 'other').
+     * Use the 'assign' function to assign each element.
+     */
+    void assign(const UVector64& other, UErrorCode &ec);
+
+    /**
+     * Compare this vector with another.  They will be considered
+     * equal if they are of the same size and all elements are equal,
+     * as compared using this object's comparer.
+     */
+    UBool operator==(const UVector64& other);
+
+    /**
+     * Equivalent to !operator==()
+     */
+    inline UBool operator!=(const UVector64& other);
+
+    //------------------------------------------------------------
+    // subset of java.util.Vector API
+    //------------------------------------------------------------
+
+    void addElement(int64_t elem, UErrorCode &status);
+
+    void setElementAt(int64_t elem, int32_t index);
+
+    void insertElementAt(int64_t elem, int32_t index, UErrorCode &status);
+    
+    int64_t elementAti(int32_t index) const;
+
+    //UBool equals(const UVector64 &other) const;
+
+    int64_t lastElementi(void) const;
+
+    //int32_t indexOf(int64_t elem, int32_t startIndex = 0) const;
+
+    //UBool contains(int64_t elem) const;
+
+    //UBool containsAll(const UVector64& other) const;
+
+    //UBool removeAll(const UVector64& other);
+
+    //UBool retainAll(const UVector64& other);
+
+    //void removeElementAt(int32_t index);
+
+    void removeAllElements();
+
+    int32_t size(void) const;
+
+    //UBool isEmpty(void) const;
+
+    // Inline.  Use this one for speedy size check.
+    inline UBool ensureCapacity(int32_t minimumCapacity, UErrorCode &status);
+
+    // Out-of-line, handles actual growth.  Called by ensureCapacity() when necessary.
+    UBool expandCapacity(int32_t minimumCapacity, UErrorCode &status);
+
+    /**
+     * Change the size of this vector as follows: If newSize is
+     * smaller, then truncate the array, possibly deleting held
+     * elements for i >= newSize.  If newSize is larger, grow the
+     * array, filling in new slows with zero.
+     */
+    void setSize(int32_t newSize);
+
+    //------------------------------------------------------------
+    // New API
+    //------------------------------------------------------------
+
+    //UBool containsNone(const UVector64& other) const;
+
+
+    //void sortedInsert(int64_t elem, UErrorCode& ec);
+
+    /**
+     * Returns a pointer to the internal array holding the vector.
+     */
+    int64_t *getBuffer() const;
+
+    /**
+     * Set the maximum allowed buffer capacity for this vector/stack.
+     * Default with no limit set is unlimited, go until malloc() fails.
+     * A Limit of zero means unlimited capacity.
+     * Units are vector elements (64 bits each), not bytes.
+     */
+    void setMaxCapacity(int32_t limit);
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     */
+    static UClassID U_EXPORT2 getStaticClassID();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     */
+    virtual UClassID getDynamicClassID() const;
+
+private:
+    void _init(int32_t initialCapacity, UErrorCode &status);
+
+    // Disallow
+    UVector64(const UVector64&);
+
+    // Disallow
+    UVector64& operator=(const UVector64&);
+
+
+    //  API Functions for Stack operations.
+    //  In the original UVector, these were in a separate derived class, UStack.
+    //  Here in UVector64, they are all together.
+public:
+    //UBool empty(void) const;   // TODO:  redundant, same as empty().  Remove it?
+
+    //int64_t peeki(void) const;
+    
+    int64_t popi(void);
+    
+    int64_t push(int64_t i, UErrorCode &status);
+
+    int64_t *reserveBlock(int32_t size, UErrorCode &status);
+    int64_t *popFrame(int32_t size);
+};
+
+
+// UVector64 inlines
+
+inline UBool UVector64::ensureCapacity(int32_t minimumCapacity, UErrorCode &status) {
+    if ((minimumCapacity >= 0) && (capacity >= minimumCapacity)) {
+        return TRUE;
+    } else {
+        return expandCapacity(minimumCapacity, status);
+    }
+}
+
+inline int64_t UVector64::elementAti(int32_t index) const {
+    return (0 <= index && index < count) ? elements[index] : 0;
+}
+
+
+inline void UVector64::addElement(int64_t elem, UErrorCode &status) {
+    if (ensureCapacity(count + 1, status)) {
+        elements[count] = elem;
+        count++;
+    }
+}
+
+inline int64_t *UVector64::reserveBlock(int32_t size, UErrorCode &status) {
+    if (ensureCapacity(count+size, status) == FALSE) {
+        return NULL;
+    }
+    int64_t  *rp = elements+count;
+    count += size;
+    return rp;
+}
+
+inline int64_t *UVector64::popFrame(int32_t size) {
+    U_ASSERT(count >= size);
+    count -= size;
+    if (count < 0) {
+        count = 0;
+    }
+    return elements+count-size;
+}
+
+
+
+inline int32_t UVector64::size(void) const {
+    return count;
+}
+
+inline int64_t UVector64::lastElementi(void) const {
+    return elementAti(count-1);
+}
+
+inline UBool UVector64::operator!=(const UVector64& other) {
+    return !operator==(other);
+}
+
+inline int64_t *UVector64::getBuffer() const {
+    return elements;
+}
+
+
+// UStack inlines
+
+inline int64_t UVector64::push(int64_t i, UErrorCode &status) {
+    addElement(i, status);
+    return i;
+}
+
+inline int64_t UVector64::popi(void) {
+    int64_t result = 0;
+    if (count > 0) {
+        count--;
+        result = elements[count];
+    }
+    return result;
+}
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/common/wintz.c b/source/common/wintz.c
new file mode 100644
index 0000000..bf204ea
--- /dev/null
+++ b/source/common/wintz.c
@@ -0,0 +1,290 @@
+/*
+********************************************************************************
+*   Copyright (C) 2005-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+********************************************************************************
+*
+* File WINTZ.CPP
+*
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#ifdef U_WINDOWS
+
+#include "wintz.h"
+
+#include "cmemory.h"
+#include "cstring.h"
+
+#include "unicode/ustring.h"
+#include "unicode/ures.h"
+
+#   define WIN32_LEAN_AND_MEAN
+#   define VC_EXTRALEAN
+#   define NOUSER
+#   define NOSERVICE
+#   define NOIME
+#   define NOMCX
+#include <windows.h>
+
+/* The layout of the Tzi value in the registry */
+typedef struct
+{
+    int32_t bias;
+    int32_t standardBias;
+    int32_t daylightBias;
+    SYSTEMTIME standardDate;
+    SYSTEMTIME daylightDate;
+} TZI;
+
+/**
+ * Various registry keys and key fragments.
+ */
+static const char CURRENT_ZONE_REGKEY[] = "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation\\";
+static const char STANDARD_NAME_REGKEY[] = "StandardName";
+static const char STANDARD_TIME_REGKEY[] = " Standard Time";
+static const char TZI_REGKEY[] = "TZI";
+static const char STD_REGKEY[] = "Std";
+
+/**
+ * HKLM subkeys used to probe for the flavor of Windows.  Note that we
+ * specifically check for the "GMT" zone subkey; this is present on
+ * NT, but on XP has become "GMT Standard Time".  We need to
+ * discriminate between these cases.
+ */
+static const char* const WIN_TYPE_PROBE_REGKEY[] = {
+    /* WIN_9X_ME_TYPE */
+    "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones",
+
+    /* WIN_NT_TYPE */
+    "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\GMT"
+
+    /* otherwise: WIN_2K_XP_TYPE */
+};
+
+/**
+ * The time zone root subkeys (under HKLM) for different flavors of
+ * Windows.
+ */
+static const char* const TZ_REGKEY[] = {
+    /* WIN_9X_ME_TYPE */
+    "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones\\",
+
+    /* WIN_NT_TYPE | WIN_2K_XP_TYPE */
+    "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\"
+};
+
+/**
+ * Flavor of Windows, from our perspective.  Not a real OS version,
+ * but rather the flavor of the layout of the time zone information in
+ * the registry.
+ */
+enum {
+    WIN_9X_ME_TYPE = 1,
+    WIN_NT_TYPE = 2,
+    WIN_2K_XP_TYPE = 3
+};
+
+static int32_t gWinType = 0;
+
+static int32_t detectWindowsType()
+{
+    int32_t winType;
+    LONG result;
+    HKEY hkey;
+
+    /* Detect the version of windows by trying to open a sequence of
+        probe keys.  We don't use the OS version API because what we
+        really want to know is how the registry is laid out.
+        Specifically, is it 9x/Me or not, and is it "GMT" or "GMT
+        Standard Time". */
+    for (winType = 0; winType < 2; winType++) {
+        result = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
+                              WIN_TYPE_PROBE_REGKEY[winType],
+                              0,
+                              KEY_QUERY_VALUE,
+                              &hkey);
+        RegCloseKey(hkey);
+
+        if (result == ERROR_SUCCESS) {
+            break;
+        }
+    }
+
+    return winType+1; // +1 to bring it inline with the enum
+}
+
+static LONG openTZRegKey(HKEY *hkey, const char *winid)
+{
+    char subKeyName[110]; /* TODO: why 96?? */
+    char *name;
+    LONG result;
+
+    /* This isn't thread safe, but it's good enough because the result should be constant per system. */
+    if (gWinType <= 0) {
+        gWinType = detectWindowsType();
+    }
+
+    uprv_strcpy(subKeyName, TZ_REGKEY[(gWinType != WIN_9X_ME_TYPE)]);
+    name = &subKeyName[strlen(subKeyName)];
+    uprv_strcat(subKeyName, winid);
+
+    if (gWinType == WIN_9X_ME_TYPE) {
+        /* Remove " Standard Time" */
+        char *pStd = uprv_strstr(subKeyName, STANDARD_TIME_REGKEY);
+        if (pStd) {
+            *pStd = 0;
+        }
+    }
+
+    result = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
+                            subKeyName,
+                            0,
+                            KEY_QUERY_VALUE,
+                            hkey);
+    return result;
+}
+
+static LONG getTZI(const char *winid, TZI *tzi)
+{
+    DWORD cbData = sizeof(TZI);
+    LONG result;
+    HKEY hkey;
+
+    result = openTZRegKey(&hkey, winid);
+
+    if (result == ERROR_SUCCESS) {
+        result = RegQueryValueExA(hkey,
+                                    TZI_REGKEY,
+                                    NULL,
+                                    NULL,
+                                    (LPBYTE)tzi,
+                                    &cbData);
+
+    }
+
+    RegCloseKey(hkey);
+
+    return result;
+}
+
+/*
+  This code attempts to detect the Windows time zone, as set in the
+  Windows Date and Time control panel.  It attempts to work on
+  multiple flavors of Windows (9x, Me, NT, 2000, XP) and on localized
+  installs.  It works by directly interrogating the registry and
+  comparing the data there with the data returned by the
+  GetTimeZoneInformation API, along with some other strategies.  The
+  registry contains time zone data under one of two keys (depending on
+  the flavor of Windows):
+
+    HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones\
+    HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\
+
+  Under this key are several subkeys, one for each time zone.  These
+  subkeys are named "Pacific" on Win9x/Me and "Pacific Standard Time"
+  on WinNT/2k/XP.  There are some other wrinkles; see the code for
+  details.  The subkey name is NOT LOCALIZED, allowing us to support
+  localized installs.
+
+  Under the subkey are data values.  We care about:
+
+    Std   Standard time display name, localized
+    TZI   Binary block of data
+
+  The TZI data is of particular interest.  It contains the offset, two
+  more offsets for standard and daylight time, and the start and end
+  rules.  This is the same data returned by the GetTimeZoneInformation
+  API.  The API may modify the data on the way out, so we have to be
+  careful, but essentially we do a binary comparison against the TZI
+  blocks of various registry keys.  When we find a match, we know what
+  time zone Windows is set to.  Since the registry key is not
+  localized, we can then translate the key through a simple table
+  lookup into the corresponding ICU time zone.
+
+  This strategy doesn't always work because there are zones which
+  share an offset and rules, so more than one TZI block will match.
+  For example, both Tokyo and Seoul are at GMT+9 with no DST rules;
+  their TZI blocks are identical.  For these cases, we fall back to a
+  name lookup.  We attempt to match the display name as stored in the
+  registry for the current zone to the display name stored in the
+  registry for various Windows zones.  By comparing the registry data
+  directly we avoid conversion complications.
+
+  Author: Alan Liu
+  Since: ICU 2.6
+  Based on original code by Carl Brown <cbrown@xnetinc.com>
+*/
+
+/**
+ * Main Windows time zone detection function.  Returns the Windows
+ * time zone, translated to an ICU time zone, or NULL upon failure.
+ */
+U_CFUNC const char* U_EXPORT2
+uprv_detectWindowsTimeZone() {
+    UErrorCode status = U_ZERO_ERROR;
+    UResourceBundle* bundle = NULL;
+    char* icuid = NULL;
+
+    LONG result;
+    TZI tziKey;
+    TZI tziReg;
+    TIME_ZONE_INFORMATION apiTZI;
+
+    /* Obtain TIME_ZONE_INFORMATION from the API, and then convert it
+       to TZI.  We could also interrogate the registry directly; we do
+       this below if needed. */
+    uprv_memset(&apiTZI, 0, sizeof(apiTZI));
+    uprv_memset(&tziKey, 0, sizeof(tziKey));
+    uprv_memset(&tziReg, 0, sizeof(tziReg));
+    GetTimeZoneInformation(&apiTZI);
+    tziKey.bias = apiTZI.Bias;
+    uprv_memcpy((char *)&tziKey.standardDate, (char*)&apiTZI.StandardDate,
+           sizeof(apiTZI.StandardDate));
+    uprv_memcpy((char *)&tziKey.daylightDate, (char*)&apiTZI.DaylightDate,
+           sizeof(apiTZI.DaylightDate));
+
+    bundle = ures_openDirect(NULL, "windowsZones", &status);
+    ures_getByKey(bundle, "mapTimezones", bundle, &status);
+
+    /* Note: We get the winid not from static tables but from resource bundle. */
+    while (U_SUCCESS(status) && ures_hasNext(bundle)) {
+        const char* winid;
+        int32_t len;
+        UResourceBundle* winTZ = ures_getNextResource(bundle, NULL, &status);
+        if (U_FAILURE(status)) {
+            break;
+        }
+        winid = ures_getKey(winTZ);
+        result = getTZI(winid, &tziReg);
+
+        if (result == ERROR_SUCCESS) {
+            /* Windows alters the DaylightBias in some situations.
+               Using the bias and the rules suffices, so overwrite
+               these unreliable fields. */
+            tziKey.standardBias = tziReg.standardBias;
+            tziKey.daylightBias = tziReg.daylightBias;
+
+            if (uprv_memcmp((char *)&tziKey, (char*)&tziReg, sizeof(tziKey)) == 0) {
+                const UChar* icuTZ = ures_getStringByKey(winTZ, "001", &len, &status);
+                if (U_SUCCESS(status)) {
+                    icuid = (char*)uprv_malloc(sizeof(char) * (len + 1));
+                    uprv_memset(icuid, 0, len + 1);
+                    u_austrncpy(icuid, icuTZ, len);
+                }
+            }
+        }
+        ures_close(winTZ);
+        if (icuid != NULL) {
+            break;
+        }
+    }
+
+    ures_close(bundle);
+
+    return icuid;
+}
+
+#endif /* #ifdef U_WINDOWS */
diff --git a/source/common/wintz.h b/source/common/wintz.h
new file mode 100644
index 0000000..3a06ceb
--- /dev/null
+++ b/source/common/wintz.h
@@ -0,0 +1,34 @@
+/*
+********************************************************************************
+*   Copyright (C) 2005-2008, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+********************************************************************************
+*
+* File WINTZ.H
+*
+********************************************************************************
+*/
+
+#ifndef __WINTZ
+#define __WINTZ
+
+#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
+
+U_CFUNC const char* U_EXPORT2
+uprv_detectWindowsTimeZone();
+
+#endif /* #ifdef U_WINDOWS */
+
+#endif /* __WINTZ */
diff --git a/source/config.guess b/source/config.guess
new file mode 100644
index 0000000..f0f0d36
--- /dev/null
+++ b/source/config.guess
@@ -0,0 +1,1529 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+#   Free Software Foundation, Inc.
+
+timestamp='2008-09-28'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep __ELF__ >/dev/null
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+	        os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+	        UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	exit ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+        echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm:riscos:*:*|arm:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+        exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+ 	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[456])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+              	{
+              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+              	case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+              	    switch (bits)
+              		{
+              		case 64: puts ("hppa2.0w"); break;
+              		case 32: puts ("hppa2.0n"); break;
+              		default: puts ("hppa2.0"); break;
+              		} break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+              	    puts ("hppa2.0"); break;
+              #endif
+              	default: puts ("hppa1.0"); break;
+              	}
+                  exit (0);
+              }
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep __LP64__ >/dev/null
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit ;;
+    5000:UNIX_System_V:4.*:*)
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	case ${UNAME_MACHINE} in
+	    pc98)
+		echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    i*:windows32*:*)
+    	# uname -m includes "-pc" on this system.
+    	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:[3456]*)
+    	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    EM64T | authenticamd | genuineintel)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-gnu
+	else
+	    echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    cris:Linux:*:*)
+	echo cris-axis-linux-gnu
+	exit ;;
+    crisv32:Linux:*:*)
+	echo crisv32-axis-linux-gnu
+	exit ;;
+    frv:Linux:*:*)
+    	echo frv-unknown-linux-gnu
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    mips:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips
+	#undef mipsel
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mipsel
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^CPU/{
+		s: ::g
+		p
+	    }'`"
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips64
+	#undef mips64el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mips64el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips64
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^CPU/{
+		s: ::g
+		p
+	    }'`"
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    or32:Linux:*:*)
+	echo or32-unknown-linux-gnu
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-gnu
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+	objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-gnu
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
+	esac
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux
+	exit ;;
+    sh64*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-gnu
+	exit ;;
+    x86_64:Linux:*:*)
+	echo x86_64-unknown-linux-gnu
+	exit ;;
+    xtensa*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    i*86:Linux:*:*)
+	# The BFD linker knows what the default object file format is, so
+	# first see if it will tell us. cd to the root directory to prevent
+	# problems with other programs or directories called `ld' in the path.
+	# Set LC_ALL=C to ensure ld outputs messages in English.
+	ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+			 | sed -ne '/supported targets:/!d
+				    s/[ 	][ 	]*/ /g
+				    s/.*supported targets: *//
+				    s/ .*//
+				    p'`
+        case "$ld_supported_targets" in
+	  elf32-i386)
+		TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+		;;
+	  a.out-i386-linux)
+		echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+		exit ;;
+	  "")
+		# Either a pre-BFD a.out linker (linux-gnuoldld) or
+		# one that does not give us useful --help.
+		echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+		exit ;;
+	esac
+	# Determine whether the default compiler is a.out or elf
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <features.h>
+	#ifdef __ELF__
+	# ifdef __GLIBC__
+	#  if __GLIBC__ >= 2
+	LIBC=gnu
+	#  else
+	LIBC=gnulibc1
+	#  endif
+	# else
+	LIBC=gnulibc1
+	# endif
+	#else
+	#if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+	LIBC=gnu
+	#else
+	LIBC=gnuaout
+	#endif
+	#endif
+	#ifdef __dietlibc__
+	LIBC=dietlibc
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^LIBC/{
+		s: ::g
+		p
+	    }'`"
+	test x"${LIBC}" != x && {
+		echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+		exit
+	}
+	test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+	;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+    	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+	echo i386-pc-msdosdjgpp
+        exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && { echo i486-ncr-sysv4; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes@openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf@swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+	        echo mips-nec-sysv${UNAME_RELEASE}
+	else
+	        echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+        exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	case $UNAME_PROCESSOR in
+	    unknown) UNAME_PROCESSOR=powerpc ;;
+	esac
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NSE-?:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+    	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+	  ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    c34*)
+	echo c34-convex-bsd
+	exit ;;
+    c38*)
+	echo c38-convex-bsd
+	exit ;;
+    c4*)
+	echo c4-convex-bsd
+	exit ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/source/config.sub b/source/config.sub
new file mode 100644
index 0000000..6759825
--- /dev/null
+++ b/source/config.sub
@@ -0,0 +1,1658 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+#   Free Software Foundation, Inc.
+
+timestamp='2008-01-16'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+  uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis | -knuth | -cray)
+		os=
+		basic_machine=$1
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+ 	-chorusrdb)
+ 		os=-chorusrdb
+		basic_machine=$1
+ 		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+	| bfin \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| fido | fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | mcore | mep \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64vr | mips64vrel \
+	| mips64orion | mips64orionel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| mt \
+	| msp430 \
+	| nios | nios2 \
+	| ns16k | ns32k \
+	| or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| pyramid \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu | strongarm \
+	| tahoe | thumb | tic4x | tic80 | tron \
+	| v850 | v850e \
+	| we32k \
+	| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+	| z8k)
+		basic_machine=$basic_machine-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12)
+		# Motorola 68HC11/12.
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+	| clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nios-* | nios2-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| pyramid-* \
+	| romp-* | rs6000-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+	| tahoe-* | thumb-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+	| tron-* \
+	| v850-* | v850e-* | vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+    	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16)
+		basic_machine=cr16-unknown
+		os=-elf
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc)	basic_machine=powerpc-unknown
+		;;
+	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tic54x | c54x*)
+		basic_machine=tic54x-unknown
+		os=-coff
+		;;
+	tic55x | c55x*)
+		basic_machine=tic55x-unknown
+		os=-coff
+		;;
+	tic6x | c6x*)
+		basic_machine=tic6x-unknown
+		os=-coff
+		;;
+	tile*)
+		basic_machine=tile-unknown
+		os=-linux-gnu
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -openbsd* | -solidbsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+        -os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+        -tpf*)
+		os=-tpf
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-kaos*)
+		os=-kaos
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+        score-*)
+		os=-elf
+		;;
+        spu-*)
+		os=-elf
+		;;
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+        c4x-* | tic4x-*)
+        	os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+        mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-haiku)
+		os=-haiku
+		;;
+	*-ibm)
+		os=-aix
+		;;
+    	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/source/config/Makefile.inc.in b/source/config/Makefile.inc.in
new file mode 100644
index 0000000..773a4bd
--- /dev/null
+++ b/source/config/Makefile.inc.in
@@ -0,0 +1,286 @@
+## -*-makefile-*-
+#******************************************************************************
+#   Copyright (C) 1999-2010, International Business Machines
+#   Corporation and others.  All Rights Reserved.
+#******************************************************************************
+# This Makefile.inc is designed to be included into projects which make use
+# of the ICU.
+
+# CONTENTS OF THIS FILE
+# 1). Base configuration information and linkage
+# 2). Variables giving access to ICU tools
+# 3). Host information
+# 4). Compiler flags and settings 
+# 5). Data Packaging directives
+# 6). Include of platform make fragment (mh-* file)
+
+##################################################################
+##################################################################
+#
+#       *1*  base configuration information and linkage
+#
+##################################################################
+# The PREFIX is the base of where ICU is installed.
+# Inside this directory you should find  bin, lib, include/unicode, 
+# etc.  If ICU is not installed in this directory, you must change the
+# following line.  There should exist $(prefix)/include/unicode/utypes.h
+# for example.
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+libdir = @libdir@
+libexecdir = @libexecdir@
+bindir = @bindir@
+datarootdir = @datarootdir@
+datadir = @datadir@
+sbindir = @sbindir@
+
+# about the ICU version
+VERSION = @VERSION@
+UNICODE_VERSION = @UNICODE_VERSION@
+
+# The prefix for ICU libraries, normally 'icu'
+ICUPREFIX = icu
+PACKAGE = @PACKAGE@
+LIBICU = lib$(ICUPREFIX)
+
+# Static library prefix and file extension
+STATIC_PREFIX = s
+LIBSICU = lib$(STATIC_PREFIX)$(ICUPREFIX)
+A = a
+
+# Suffix at the end of libraries. Usually empty.
+ICULIBSUFFIX = @ICULIBSUFFIX@
+# ICULIBSUFFIX_VERSION  is non-empty if it is to contain a library
+# version. For example, if it is 21, it means libraries are named
+# libicuuc21.so for example.
+
+# rpath links a library search path right into the binaries.
+## mh-files MUST NOT override RPATHLDFLAGS unless they provide
+## equivalent '#SH#' lines for icu-config fixup
+ENABLE_RPATH = @ENABLE_RPATH@
+ifeq ($(ENABLE_RPATH),YES)
+RPATHLDFLAGS = $(LD_RPATH)$(LD_RPATH_PRE)$(libdir)
+endif
+
+#SH## icu-config version of above 'if':
+#SH#case "$ENABLE_RPATH" in 
+#SH#     [yY]*)
+#SH# 	ENABLE_RPATH=YES
+#SH# 	RPATHLDFLAGS="${LD_RPATH}${LD_RPATH_PRE}${libdir}"
+#SH# 	;;
+#SH#
+#SH#     [nN]*)
+#SH# 	ENABLE_RPATH=NO
+#SH# 	RPATHLDFLAGS=""
+#SH# 	;;
+#SH#
+#SH#     *)
+#SH# 	echo $0: Unknown --enable-rpath value ${ENABLE_RPATH} 1>&2
+#SH# 	exit 3
+#SH# 	;;
+#SH#esac
+
+# Name flexibility for the library naming scheme.  Any modifications should
+# be made in the mh- file for the specific platform.
+DATA_STUBNAME = data
+COMMON_STUBNAME = uc
+I18N_STUBNAME = i18n
+LAYOUT_STUBNAME = le
+LAYOUTEX_STUBNAME = lx
+IO_STUBNAME = io
+TOOLUTIL_STUBNAME = tu
+CTESTFW_STUBNAME = test
+ 
+
+
+### To link your application with ICU:
+# 1. use LDFLAGS, CFLAGS, etc from above
+# 2. link with $(ICULIBS)
+# 3. optionally, add one or more of:
+#    - $(ICULIBS_I18N)    - i18n library, formatting, etc.
+#    - $(ICULIBS_LAYOUT)  - ICU layout library. 
+#    - $(ICULIBS_ICUIO)   - ICU stdio equivalent library
+
+ICULIBS_COMMON = -l$(ICUPREFIX)uc$(ICULIBSUFFIX)$(ICULIBSUFFIX_VERSION)
+ICULIBS_DATA   = -l$(ICUPREFIX)$(DATA_STUBNAME)$(ICULIBSUFFIX)$(ICULIBSUFFIX_VERSION)
+ICULIBS_I18N   = -l$(ICUPREFIX)$(I18N_STUBNAME)$(ICULIBSUFFIX)$(ICULIBSUFFIX_VERSION)
+ICULIBS_TOOLUTIL = -l$(ICUPREFIX)tu$(ICULIBSUFFIX)$(ICULIBSUFFIX_VERSION)
+ICULIBS_CTESTFW = -l$(ICUPREFIX)ctestfw$(ICULIBSUFFIX)$(ICULIBSUFFIX_VERSION)
+ICULIBS_ICUIO = -l$(ICUPREFIX)io$(ICULIBSUFFIX)$(ICULIBSUFFIX_VERSION)
+ICULIBS_OBSOLETE = -l$(ICUPREFIX)obsolete$(ICULIBSUFFIX)$(ICULIBSUFFIX_VERSION)
+ICULIBS_LAYOUT = -l$(ICUPREFIX)le$(ICULIBSUFFIX)$(ICULIBSUFFIX_VERSION)
+ICULIBS_LAYOUTEX = -l$(ICUPREFIX)lx$(ICULIBSUFFIX)$(ICULIBSUFFIX_VERSION)
+ICULIBS_BASE = $(LIBS) -L$(libdir)
+
+# for icu-config to test with
+ICULIBS_COMMON_LIB_NAME = ${LIBICU}${COMMON_STUBNAME}${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}.${SO}
+ICULIBS_COMMON_LIB_NAME_A = ${LIBICU}${COMMON_STUBNAME}${ICULIBSUFFIX}.${A}
+
+# ICULIBS is the set of libraries your application should link
+# with usually. Many applications will want to add $(ICULIBS_I18N) as well. 
+ICULIBS = $(ICULIBS_BASE) $(ICULIBS_I18N) $(ICULIBS_COMMON) $(ICULIBS_DATA) 
+
+# Proper echo newline handling is needed in icu-config
+ECHO_N=@ICU_ECHO_N@
+ECHO_C=@ICU_ECHO_C@
+# Not currently being used but good to have for proper tab handling
+ECHO_T=@ICU_ECHO_T@
+
+##################################################################
+##################################################################
+#
+#       *2*  access to ICU tools
+#
+##################################################################
+# Environment variable to set a runtime search path
+#   (Overridden when necessary in -mh files)
+LDLIBRARYPATH_ENVVAR = LD_LIBRARY_PATH
+
+# Versioned target for a shared library
+FINAL_SO_TARGET = $(SO_TARGET).$(SO_TARGET_VERSION)
+MIDDLE_SO_TARGET = $(SO_TARGET).$(SO_TARGET_VERSION_MAJOR)
+
+# Access to important ICU tools.
+# Use as follows:  $(INVOKE) $(GENRB) arguments .. 
+INVOKE = $(LDLIBRARYPATH_ENVVAR)=$(libdir):$$$(LDLIBRARYPATH_ENVVAR) $(LEAK_CHECKER)
+GENCCODE = $(sbindir)/genccode
+ICUPKG   = $(sbindir)/icupkg
+GENCMN   = $(sbindir)/gencmn
+GENRB    = $(bindir)/genrb
+PKGDATA  = $(bindir)/pkgdata
+
+# moved here because of dependencies
+pkgdatadir = $(datadir)/$(PACKAGE)$(ICULIBSUFFIX)/$(VERSION)
+pkglibdir = $(libdir)/$(PACKAGE)$(ICULIBSUFFIX)/$(VERSION)
+
+##################################################################
+##################################################################
+#
+#       *3*  Information about the host
+#
+##################################################################
+
+# Information about the host that 'configure' was run on.
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_vendor = @host_vendor@
+host_os = @host_os@
+# Our platform canonical name (as determined by configure)
+# this is a #define value (i.e. U_XXXX or XXXX)
+platform = @platform@
+
+##################################################################
+##################################################################
+#
+#       *4*  compiler flags and misc. options
+#
+##################################################################
+AR = @AR@
+# initial tab keeps it out of the shell version.
+	ARFLAGS := @ARFLAGS@ $(ARFLAGS)
+#SH#ARFLAGS="@ARFLAGS@ ${ARFLAGS}"
+CC = @CC@
+CFLAGS = @CFLAGS@ 
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@ $(LIBCPPFLAGS) -I$(prefix)/include
+CXX = @CXX@
+CXXFLAGS = @CXXFLAGS@ 
+DEFAULT_MODE = @DATA_PACKAGING_MODE@
+DEFS = @DEFS@ 
+FFLAGS = @FFLAGS@
+# use a consistent INSTALL 
+INSTALL  =  $(SHELL) $(pkgdatadir)/install-sh -c
+INSTALL_DATA  =  @INSTALL_DATA@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM  =  @INSTALL_PROGRAM@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+LDFLAGS = @LDFLAGS@ $(RPATHLDFLAGS)
+LIBS = @LIBS@ 
+LIB_M = @LIB_M@
+LIB_VERSION = @LIB_VERSION@
+LIB_VERSION_MAJOR = @LIB_VERSION_MAJOR@
+MKINSTALLDIRS = $(SHELL) $(pkgdatadir)/mkinstalldirs
+RANLIB = @RANLIB@
+RMV = rm -rf
+SHELL = @SHELL@
+SHLIB.c=      $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared
+SHLIB.cc=     $(CXX) $(DEFS) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -shared
+U_IS_BIG_ENDIAN = @U_IS_BIG_ENDIAN@
+includedir = @includedir@
+infodir = @infodir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+program_transform_name = @program_transform_name@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+INSTALL-L = ${INSTALL_DATA}
+
+
+##################################################################
+##################################################################
+#
+#       *5* packaging options and directories
+#
+##################################################################
+
+
+# The basename of the ICU data file (i.e. icudt21b )
+ICUDATA_CHAR = @ICUDATA_CHAR@
+ICUDATA_NAME = icudt@LIB_VERSION_MAJOR@@ICUDATA_CHAR@
+
+# Defaults for pkgdata's mode and directories
+# The default data dir changes depending on what packaging mode 
+# is being used
+ifeq ($(strip $(PKGDATA_MODE)),)
+#SH# if [ "x$PKGDATA_MODE" = "x" ];
+#SH# then
+PKGDATA_MODE=@DATA_PACKAGING_MODE@
+#SH# fi
+endif
+
+#SH# case "$PKGDATA_MODE" in
+ifeq ($(PKGDATA_MODE),common)
+#SH# common)
+ICUDATA_DIR = $(pkgdatadir)
+ICUPKGDATA_DIR = $(ICUDATA_DIR)
+#SH# ;;
+else
+ifeq ($(PKGDATA_MODE),dll)
+#SH# dll)
+ICUDATA_DIR = $(pkgdatadir)
+ICUPKGDATA_DIR = $(libdir)
+#SH# ;;
+else
+#SH# *)
+ICUDATA_DIR = $(pkgdatadir)
+ICUPKGDATA_DIR = $(ICUDATA_DIR)
+#SH# ;;
+endif
+endif
+
+#SH# esac
+
+GENCCODE_ASSEMBLY = @GENCCODE_ASSEMBLY@
+
+##################################################################
+##################################################################
+#
+#       *6* Inclusion of platform make fragment (mh-* file)
+#
+##################################################################
+# The mh- file ("make fragment") for the platform is included here. 
+# It may override the above settings.
+# It is put last so that the mh-file can override anything.
+# The selfcheck is just a sanity check that this makefile is
+# parseable. The mh fragment is only included if this does not occur.
+
+ifeq (selfcheck,$(MAKECMDGOALS)) #M#
+selfcheck: #M#
+	@echo passed #M#
+else #M#
+include $(pkgdatadir)/config/@platform_make_fragment_name@
+endif #M#
+
diff --git a/source/config/icu-config-bottom b/source/config/icu-config-bottom
new file mode 100644
index 0000000..53a9062
--- /dev/null
+++ b/source/config/icu-config-bottom
@@ -0,0 +1,404 @@
+## -*-sh-*-
+## BEGIN of icu-config-bottom.
+## Copyright (c) 2002-2010, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+ICUUC_FILE="${libdir}/${ICULIBS_COMMON_LIB_NAME}"
+ICUUC_FILE_A="${libdir}/${ICULIBS_COMMON_LIB_NAME_A}"
+    
+#  echo ENABLE RPATH $ENABLE_RPATH and RPATHLDFLAGS=${RPATH_LDFLAGS}
+if [ "x$PKGDATA_MODE" = "x" ]; then
+    PKGDATA_MODE=dll
+fi
+
+}
+
+## The actual code of icu-config goes here.
+
+ME=`basename "$0"`
+
+allflags()
+{
+    echo "  --noverify             Don't verify that ICU is actually installed."
+    echo "  --bindir               Print binary directory path (bin)"
+    echo "  --cc                   Print C compiler used [CC]"
+    echo "  --cflags               Print C compiler flags [CFLAGS]"
+    echo "  --cflags-dynamic       Print additional C flags for"
+    echo "                             building shared libraries."
+    echo "  --cppflags             Print C Preprocessor flags [CPPFLAGS]"
+    echo "  --cppflags-dynamic     Print additional C Preprocessor flags for"
+    echo "                             building shared libraries."
+    echo "  --cppflags-searchpath  Print only -I include directives  (-Iinclude)"
+    echo "  --cxx                  Print C++ compiler used [CXX]"
+    echo "  --cxxflags             Print C++ compiler flags [CXXFLAGS]"
+    echo "  --cxxflags-dynamic     Print additional C++ flags for"
+    echo "                             building shared libraries."
+    echo "  --detect-prefix        Attempt to detect prefix based on PATH"
+    echo "  --exec-prefix          Print prefix for executables (/bin)"
+    echo "  --exists               Return with 0 status if ICU exists else fail"
+    echo "  --help, -?, --usage    Print this message"
+    echo "  --icudata              Print shortname of ICU data file (icudt21l)"
+    echo "  --icudata-install-dir  Print path to install data to - use as --install option to pkgdata(1)"
+    echo "  --icudata-mode         Print default ICU pkgdata mode (dll) - use as --mode option to pkgdata(1)."
+    echo "  --icudatadir           Print path to packaged archive data. Can set as [ICU_DATA]"
+    echo "  --invoke               Print commands to invoke an ICU program"
+    echo "  --invoke=<prog>        Print commands to invoke an ICU program named <prog> (ex: genrb)" 
+    echo "  --ldflags              Print -L search path and -l libraries to link with ICU [LDFLAGS].  This is for the data, uc (common), and i18n libraries only.  "
+    echo "  --ldflags-layout       Print ICU layout engine link directive. Use in addition to --ldflags"
+    echo "  --ldflags-libsonly     Same as --ldflags, but only the -l directives"
+    echo "  --ldflags-searchpath   Print only -L (search path) directive"
+    echo "  --ldflags-system       Print only system libs ICU links with (-lpthread, -lm)"
+    echo "  --ldflags-icuio        Print ICU icuio link directive. Use in addition to --ldflags "
+    echo "  --ldflags-obsolete     Print ICU obsolete link directive. Use in addition to --ldflags. (requires icuapps/obsolete to be built and installed.) "
+    echo "  --mandir               Print manpage (man) path"
+    echo "  --prefix               Print PREFIX to icu install (/usr/local)"
+    echo "  --prefix=XXX           Set prefix to XXX for remainder of command"
+    echo "  --sbindir              Print system binary path (sbin) "
+    echo "  --shared-datadir       Print shared data (share) path. This is NOT the ICU data dir."
+    echo "  --shlib-c              Print the command to compile and build C shared libraries with ICU"
+    echo "  --shlib-cc             Print the command to compile and build C++ shared libraries with ICU"
+    echo "  --sysconfdir           Print system config (etc) path"
+    echo "  --unicode-version      Print version of Unicode data used in ICU ($UNICODE_VERSION)"
+    echo "  --version              Print ICU version ($VERSION)"
+    echo "  --incfile              Print path to Makefile.inc"
+    echo "  --incpkgdatafile       Print path to pkgdata.inc (for -O option of pkgdata)"
+    echo "  --install              Print path to install-sh"
+    echo "  --mkinstalldirs        Print path to mkinstalldirs"
+}
+
+## Print the normal usage message
+shortusage()
+{
+    echo "usage: ${ME} " `allflags | cut -c-25 | sed -e 's%.*%[ & ]%'`
+}
+
+
+usage()
+{
+    echo "${ME}: icu-config: ICU configuration helper script"
+    echo
+    echo "The most commonly used options will be --cflags, --cxxflags, --cppflags, and --ldflags."
+    echo 'Example (in make):   CPFLAGS=$(shell icu-config --cppflags)'
+    echo '                     LDFLAGS=$(shell icu-config --ldflags)'
+    echo "                     (etc).."
+    echo
+    echo "Usage:"
+    allflags
+
+    echo 
+    echo " [Brackets] show MAKE variable equivalents,  (parenthesis) show example output"
+    echo
+    echo "Copyright (c) 2002, International Business Machines Corporation and others. All Rights Reserved."
+}
+
+## Check the sanity of current variables
+sanity()
+{
+    if [ ! -f "${ICUUC_FILE}" -a ! -f "${ICUUC_FILE_A}" ] && [ ${IGNORE_ICUUC_FILE_CHECK} = "no" ] && [ ${SANITY} = "sane" ];
+    then
+	echo "### $ME: Can't find ${ICUUC_FILE} - ICU prefix is wrong."  1>&2
+	echo "###      Try the --prefix= option " 1>&2
+	echo "###      or --detect-prefix" 1>&2
+        echo "###      (If you want to disable this check, use  the --noverify option)" 1>&2
+	echo "### $ME: Exitting." 1>&2
+	exit 2
+    fi
+}
+
+## Main starts here.
+
+if [ $# -lt 1 ]; then
+    shortusage
+    exit 1
+fi
+
+# For certain options (e.g. --detect-prefix) don't check for icuuc library file.
+
+IGNORE_ICUUC_FILE_CHECK="no";
+
+SANITY="sane"
+
+case "$1" in
+--noverify)
+    SANITY="nosanity"
+    shift
+    ;;
+esac
+
+case "$1" in 
+*prefix*)
+    IGNORE_ICUUC_FILE_CHECK="yes"
+    ;;
+esac
+
+# Load our variables from autoconf
+# ALWAYS load twice because of dependencies
+loaddefs
+loaddefs
+
+if [ $# -gt 0 -a $1 = "--selfcheck" ];
+then
+	echo "passed"
+	exit 
+	# EXIT for self check
+fi
+
+sanity
+
+while [ $# -gt 0 ];
+do
+    arg="$1"
+    var=`echo $arg | sed -e 's/^[^=]*=//'`
+#    echo "### processing $arg" 1>&2
+    case "$arg" in
+
+        # undocumented.
+        --debug)
+	    set -x
+	    ;;
+        
+        --noverify)
+            echo "### $ME: Error: --noverify must be the first argument." 1>&2
+            exit 1
+            ;;
+            
+    --so)
+        echo $SO
+        ;;
+
+	--bindir)
+	    echo $bindir
+	    ;;
+
+	--libdir)
+	    echo $libdir
+	    ;;
+
+	--exists)
+	    sanity
+	    ;;
+
+	--sbindir)
+	    echo $sbindir
+	    ;;
+
+	--mkinstalldirs)
+	    echo ${MKINSTALLDIRS}
+	    ;;
+
+	--install)
+	    echo ${INSTALL}
+	    ;;
+
+	--invoke=*)
+	    QUOT="\""
+            CMD="${var}"
+
+            # If it's not a locally executable command (1st choice) then 
+            # search for it in the ICU directories. 
+            if [ ! -x ${CMD} ]; then
+                if [ -x ${bindir}/${var} ]; then
+                    CMD="${bindir}/${var}"
+                fi
+                if [ -x ${sbindir}/${var} ]; then
+                    CMD="${sbindir}/${var}"
+                fi
+            fi
+
+	    echo "env ${QUOT}${LDLIBRARYPATH_ENVVAR}=${libdir}:"'${'"${LDLIBRARYPATH_ENVVAR}"'}'${QUOT} ${CMD}
+	    ;;
+
+	--invoke)
+	    QUOT="\""
+	    echo "env ${QUOT}${LDLIBRARYPATH_ENVVAR}=${libdir}:"'${'"${LDLIBRARYPATH_ENVVAR}"'}'${QUOT}
+	    ;;
+
+	--cflags)
+	    echo $ECHO_N "${CFLAGS} ${ECHO_C}"
+	    ;;
+	    
+	--cc)
+	    echo $ECHO_N "${CC} ${ECHO_C}"
+	    ;;
+	    
+	--cxx)
+	    echo $ECHO_N "${CXX} ${ECHO_C}"
+	    ;;
+
+	--cxxflags)
+	    echo $ECHO_N "${CXXFLAGS} ${ECHO_C}"
+	    ;;
+
+	--cppflags)
+	    # Don't echo the -I. - it's unneeded.
+	    echo $ECHO_N "${CPPFLAGS} ${ECHO_C}" | sed -e 's/-I. //'
+	    ;;
+
+	--cppflags-searchpath)
+	    echo $ECHO_N "-I${prefix}/include ${ECHO_C}"
+	    ;;
+
+	--cppflags-dynamic)
+	    echo $ECHO_N "${SHAREDLIBCPPFLAGS} ${ECHO_C}"
+	    ;;
+
+	--cxxflags-dynamic)
+	    echo $ECHO_N "${SHAREDLIBCXXFLAGS} ${ECHO_C}"
+	    ;;
+
+	--cflags-dynamic)
+	    echo $ECHO_N "${SHAREDLIBCFLAGS} ${ECHO_C}"
+	    ;;
+
+	--ldflags-system)
+	    echo $ECHO_N "${LIBS} ${ECHO_C}"
+	    ;;
+
+	--ldflags)
+	    echo $ECHO_N "${LDFLAGS} ${ICULIBS} ${LIBS} ${ECHO_C}"
+# $RPATH_LDFLAGS
+	    ;;
+
+	--ldflags-libsonly)
+	    echo $ECHO_N "${ICULIBS_I18N} ${ICULIBS_COMMON} ${ICULIBS_DATA} ${ECHO_C}"
+	    ;;
+
+	--ldflags-icuio)
+	    echo $ECHO_N " ${ICULIBS_ICUIO} ${ECHO_C}"
+	    ;;
+
+	--ldflags-obsolete)
+	    echo $ECHO_N "${ICULIBS_OBSOLETE} ${ECHO_C}"
+	    ;;
+
+	--ldflags-toolutil)
+	    echo $ECHO_N " ${ICULIBS_TOOLUTIL} ${ECHO_C}"
+	    ;;
+
+	--ldflags-layout)
+	    echo $ECHO_N "${ICULIBS_LAYOUT} ${ICULIBS_LAYOUTEX} ${ECHO_C}"
+	    ;;
+
+	--ldflags-searchpath)
+	    echo $ECHO_N "-L${libdir} ${ECHO_C}"
+	    ;;
+
+	--detect-prefix)
+	    HERE=`echo $0 | sed -e "s/$ME//g"`
+	    if [ -f "${HERE}/../lib/${ICULIBS_COMMON_LIB_NAME}" -o -f  "${HERE}/../lib/${ICULIBS_COMMON_LIB_NAME_A}"  ]; then
+		prefix="${HERE}/.."
+		echo "## Using --prefix=${prefix}" 1>&2
+	    fi
+	    loaddefs
+	    loaddefs
+	    ;;
+
+	--exec-prefix)
+	    echo $exec_prefix
+	    ;;
+
+	--prefix)
+	    echo $prefix
+	    ;;
+
+	--prefix=*)
+	    prefix=$var
+	    loaddefs
+	    loaddefs
+	    ;;
+
+	--sysconfdir)
+	    echo $sysconfdir
+	    ;;
+
+	--mandir)
+	    echo $mandir
+	    ;;
+
+	--shared-datadir)
+	    echo $ECHO_N "${datadir} ${ECHO_C}"
+	    ;;
+
+        --incfile)
+	    echo $ECHO_N "${pkglibdir}/Makefile.inc ${ECHO_C}"
+	    ;;
+
+	--incpkgdatafile)
+	    echo $ECHO_N "${pkglibdir}/pkgdata.inc ${ECHO_C}"
+	    ;;
+
+	--icudata)
+	    echo $ECHO_N "${ICUDATA_NAME} ${ECHO_C}"
+	    ;;
+
+	--icudata-mode)
+	    echo $ECHO_N "${PKGDATA_MODE} ${ECHO_C}"
+	    ;;
+
+	--icudata-install-dir)
+        echo $ECHO_N "${ICUPKGDATA_DIR} ${ECHO_C}"
+	    ;;
+	    
+	--icudatadir)
+	    echo $ECHO_N "${ICUDATA_DIR} ${ECHO_C}"
+	    ;;
+
+	--shlib-c)
+	    echo $ECHO_N "${SHLIB_c} ${ECHO_C}"
+	    ;;
+
+	--shlib-cc)
+	    echo $ECHO_N "${SHLIB_cc} ${ECHO_C}"
+	    ;;
+
+	--version)
+        echo $ECHO_N $VERSION
+        ;;
+
+    --unicode-version)
+        echo $ECHO_N $UNICODE_VERSION
+        ;;
+
+	--help)
+	    usage
+	    exit 0
+	    ;;
+
+	--usage)
+	    usage
+	    exit 0
+	    ;;
+
+#	--enable-rpath=*)
+#	    ENABLE_RPATH=$var
+#	    loaddefs
+#	    ;;
+
+	-?)
+	    usage
+	    exit 0
+	    ;;
+
+        *)
+	    echo ${ME}: ERROR Unknown Option $arg 1>&2
+            echo 1>&2
+            shortusage 1>&2
+	    echo "### $ME: Exitting." 1>&2
+            exit 1;
+            ;;
+    esac
+    shift
+    
+    # Reset the ignore icuuc file check flag
+    if [ $IGNORE_ICUUC_FILE_CHECK = "yes" ]; then
+        IGNORE_ICUUC_FILE_CHECK="no"
+        sanity
+    fi
+done
+echo
+# Check once before we quit (will check last used prefix)
+sanity
+## END of icu-config-bottom
+
+exit 0
+
diff --git a/source/config/icu-config-top b/source/config/icu-config-top
new file mode 100644
index 0000000..874a3ab
--- /dev/null
+++ b/source/config/icu-config-top
@@ -0,0 +1,22 @@
+#!/bin/sh
+## -*-sh-*-
+#set -x
+# BEGIN of icu-config-top
+#******************************************************************************
+#   Copyright (C) 1999-2004, International Business Machines
+#   Corporation and others.  All Rights Reserved.
+#******************************************************************************
+# This script is designed to aid configuration of ICU.
+# rpath links a library search path right into the binaries.
+
+
+### END of icu-config-top
+
+## Zero out prefix.
+execprefix=
+prefix=
+
+
+loaddefs()
+{
+
diff --git a/source/config/icu-config.1.in b/source/config/icu-config.1.in
new file mode 100644
index 0000000..ad457b5
--- /dev/null
+++ b/source/config/icu-config.1.in
@@ -0,0 +1,288 @@
+.\" Hey, Emacs! This is -*-nroff-*- you know...
+.\"
+.\" icu-config.1: manual page for the icu-config utility
+.\"
+.\" Copyright (C) 2002-2008 IBM, Inc. and others.
+.\"
+.\" Based on  Yves Arrouye's pkgdata page <yves@arrouye.net>
+.\" Modified by Steven R. Loomis <srl@jtcsv.com>.
+.\" With help from http://www.igpm.rwth-aachen.de/~albrecht/manpage.html
+
+.TH ICU-CONFIG 1 "17 May 2004" "ICU MANPAGE" "ICU @VERSION@ Manual"
+.\".Dd "17 May 2004"
+.\".Dt ICU-CONFIG 1
+.\".Os 
+
+.SH NAME
+.B icu-config
+\- output ICU build options 
+.SH SYNOPSIS
+.B icu-config
+[
+.BI "\-\-bindir"
+]
+[
+.BI "\-\-cc"
+]
+[
+.BI "\-\-cflags"
+]
+[
+.BI "\-\-cppflags"
+]
+[
+.BI "\-\-cppflags\-searchpath"
+]
+[
+.BI "\-\-cxx"
+]
+[
+.BI "\-\-cxxflags"
+]
+[
+.BI "\-\-detect\-prefix"
+]
+[
+.BI "\-\-exec\-prefix"
+]
+[
+.BI "\-\-exists"
+]
+[
+.BI "\-\-help\fP, \fB\-?\fP,\fB"
+.BI "\-\-usage"
+]
+[
+.BI "\-\-icudata"
+]
+[
+.BI "\-\-icudata\-install\-dir"
+]
+[
+.BI "\-\-icudata\-mode"
+]
+[
+.BI "\-\-icudatadir"
+]
+[
+.BI "\-\-invoke"
+]
+[
+.BI "\-\-invoke=" "prog"
+]
+[
+.BI "\-\-ldflags"
+]
+[
+.BI "\-\-ldflags\-layout"
+]
+[
+.BI "\-\-ldflags\-libsonly"
+]
+[
+.BI "\-\-ldflags\-searchpath"
+]
+[
+.BI "\-\-ldflags\-system"
+]
+[
+.BI "\-\-ldflags\-icuio"
+]
+[
+.BI "\-\-mandir"
+]
+[
+.BI "\-\-prefix"
+]
+[
+.BI "\-\-prefix=" "prefix"
+]
+[
+.BI "\-\-sbindir"
+]
+[
+.BI "\-\-shared\-datadir"
+]
+[
+.BI "\-\-sysconfdir"
+]
+[
+.BI "\-\-unicode\-version"
+]
+[
+.BI "\-\-version"
+]
+[
+.BI "\-\-incfile"
+]
+
+
+
+.SH DESCRIPTION
+.B icu-config
+simplifies the task of building and linking against ICU as compared to
+manually configuring user makefiles or equivalent.  Because 
+.B icu-config
+is an executable script, it also solves the problem of locating the ICU
+libraries and headers, by allowing the system PATH to locate it. 
+.SH EXAMPLES
+.B icu-config
+can be used without a makefile. The command line below is sufficient for
+building a single-file c++ program against ICU. (For example, \fBicu/source/samples/props/props.cpp\fR)
+.PP
+.RS
+`icu-config --cxx --cxxflags --cppflags --ldflags` -o props props.cpp
+.RE
+.PP
+More commonly,
+.B icu-config
+will be called from within a makefile, and used to set up variables. The
+following example also builds the \fIprops\fR example.
+.PP
+.RS
+CC=$(shell icu-config --cc)
+
+CXX=$(shell icu-config --cxx)
+
+CPPFLAGS=$(shell icu-config --cppflags)
+
+CXXFLAGS=$(shell icu-config --cxxflags)
+
+LDFLAGS =$(shell icu-config --ldflags)
+
+all: props
+
+props.o: props.cpp
+.RE
+.PP
+make(1) will automatically use the above variables.
+.SH OPTIONS
+.TP
+.BI "\-\-bindir"
+Prints the binary (executable) directory path. Normally equivalent to 'bin'.
+ICU user-executable applications and scripts are found here.
+.TP
+.BI "\-\-cc"
+Print the C compiler used.  Equivalent to the $(CC) Makefile variable.
+.TP
+.BI "\-\-cflags"
+Print the C compiler flags. Equivalent to the $(CFLAGS) Makefile variable.
+Does NOT include preprocessor directives such as include path or defined symbols. Examples include debugging (\-g) and optimization flags
+.TP
+.BI "\-\-cppflags"
+Print the C preprocessor flags. Equivalent to the $(CPPFLAGS) Makefile variable. Examples are \-I include paths  and \-D define directives.
+.TP
+.BI "\-\-cppflags\-searchpath"
+Print the C preprocessor flags, as above but only \-I search paths.
+.TP
+.BI "\-\-cxx"
+Print the C++ compiler. Equivalent to the $(CXX) Makefile variable.
+.TP
+.BI "\-\-cxxflags"
+Print the C++ compiler flags. Equivalent to the $(CXXFLAGS) Makefile variable.
+.TP
+.BI "\-\-detect\-prefix"
+If ICU has been moved from its installed location, prepending this flag to
+other 
+.B icu-config
+calls will attempt to locate ICU relative to where the
+.B icu-config
+script has been located. Can be used as a last-chance effort if the ICU
+install has been damaged.
+.TP
+.BI "\-\-exec\-prefix"
+Print the prefix used for executable program directories (such as bin, sbin, etc). Normally the same as the prefix.
+.TP
+.BI "\-\-exists"
+Script will return with a successful (0) status if ICU seems to be installed
+and located correctly, otherwise an error message and nonzero status will
+be displayed.
+.TP
+.BI "\-\-help\fP, \fB\-?\fP,\fB\-\-usage"
+Print a help and usage message.
+.TP
+.BI "\-\-icudata"
+Print the \fIshortname\fP of the ICU data file. This does not include any suffix such as .dat, .dll, .so, .lib, .a, etc nor does it include prefixes such as 'lib'.  It may be in the form \fBicudt21b\fP
+.TP
+.BI "\-\-icudata\-install\-dir"
+Print the directory where ICU packaged data should 
+be installed.   Can use as pkgdata(1)'s --install option.
+.TP
+.BI "\-\-icudata\-mode"
+Print the default ICU pkgdata mode, such as dll or common.  Can use as pkgdata(1)'s --mode option.
+.TP
+.BI "\-\-icudatadir"
+Print the path to packaged archive data.  (should be where $ICU_DATA 
+or equivalent default path points.)  Will NOT point to the libdir.
+.TP
+.BI "\-\-invoke"
+If ICU is not installed in a location where the operating system will locate 
+its shared libraries, this option will print out commands so as to set the
+appropriate environment variables to load ICU's shared libraries. For example,
+on many systems a variable named LD_LIBRARY_PATH or equivalent must be set.
+.TP
+.BI "\-\-invoke=" "prog"
+Same as the \fB\-\-invoke\fP option, except includes options for invoking 
+a program named \fIprog\fP.  If \fIprog\fP is the name of an ICU tool, 
+such as genrb(1), then \fBicu-config\fP will also include the full path
+to that tool. 
+.TP
+.BI "\-\-ldflags"
+Print any flags which should be passed to the linker. These may include 
+-L for library search paths, and -l for including ICU libraries. By default, 
+this option will attempt to link in the "common" (libicuuc) and "i18n" 
+(libicui18n) libraries, as well as the data library. If additional libraries
+are required, any of the following two flags may be added in conjunction with this one,
+for example "\-\-ldflags \-\-ldflags-icuio" if the icuio library is required
+in addition to the standard ICU libraries.
+Equivalent to the $(LDFLAGS) Makefile variable.
+.TP
+.BI "\-\-ldflags\-layout"
+Prints the link option for the ICU layout library.
+.TP
+.BI "\-\-ldflags\-icuio"
+Prints the link option to add the ICU I/O package
+.TP
+.BI "\-\-ldflags\-libsonly"
+Similar to \fI\-\-ldflags\fP but only includes the \-l options.
+.TP
+.BI "\-\-ldflags\-searchpath"
+Similar to \fI\-\-ldflags\fP but only includes the \-L search path options.
+.TP
+.BI "\-\-ldflags\-system"
+Similar to \fI\-\-ldflags\fP but only includes system libraries (such as pthreads)
+.BI "\-\-mandir"
+Prints the location of the installed ICU man pages. Normally (man)
+.TP
+.BI "\-\-prefix"
+Prints the prefix (base directory) under which the installed ICU resides. 
+.TP
+.BI "\-\-prefix=" "prefix"
+Sets the ICU prefix to \fIprefix\fP for the remainder of this command line.  
+Does test whether the new prefix is valid.
+.TP
+.BI "\-\-sbindir"
+Prints the location of ICU system binaries, normally (sbin)
+.TP
+.BI "\-\-shared\-datadir"
+Prints the location of ICU shared data, normally (share)
+.TP
+.BI "\-\-sysconfdir"
+Prints the location of ICU system configuration data, normally (etc)
+.TP
+.BI "\-\-unicode\-version"
+Prints the Version of the Unicode Standard which the current ICU uses.
+.TP
+.BI "\-\-version"
+Prints the current version of ICU.
+.TP
+.BI "\-\-incfile"
+Prints the 'Makefile.inc' path, suitable for use with pkgdata(1)'s \-O option.
+.PP
+.SH AUTHORS
+Steven Loomis
+.SH VERSION
+@VERSION@
+.SH COPYRIGHT
+Copyright (C) 2002-2004 IBM, Inc. and others.
+
diff --git a/source/config/icu.pc.in b/source/config/icu.pc.in
new file mode 100644
index 0000000..406b196
--- /dev/null
+++ b/source/config/icu.pc.in
@@ -0,0 +1,31 @@
+# Copyright (C) 2010, International Business Machines Corporation. All Rights Reserved.
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+#bindir = @bindir@
+libdir = @libdir@
+includedir = @includedir@
+baselibs = @LIBS@
+#datarootdir = @datarootdir@
+#datadir = @datadir@
+#sbindir = @sbindir@
+#mandir = @mandir@
+#sysconfdir = @sysconfdir@
+CFLAGS = @CFLAGS@ 
+#CXXFLAGS = @CXXFLAGS@ 
+DEFS = @DEFS@ 
+UNICODE_VERSION=@UNICODE_VERSION@
+ICUPREFIX=icu
+ICULIBSUFFIX=@ICULIBSUFFIX@
+LIBICU=lib${ICUPREFIX}
+#SHAREDLIBCFLAGS=-fPIC
+pkglibdir=${libdir}/@PACKAGE@${ICULIBSUFFIX}/@VERSION@
+#pkgdatadir=${datadir}/@PACKAGE@${ICULIBSUFFIX}/@VERSION@
+ICUDATA_NAME = icudt@LIB_VERSION_MAJOR@@ICUDATA_CHAR@
+#ICUPKGDATA_DIR=@libdir@
+#ICUDATA_DIR=${pkgdatadir}
+ICUDESC=International Components for Unicode
+
+Version: @VERSION@
+Cflags: -I${includedir}
+# end of icu.pc.in
diff --git a/source/config/make2sh.sed b/source/config/make2sh.sed
new file mode 100644
index 0000000..8088af6
--- /dev/null
+++ b/source/config/make2sh.sed
@@ -0,0 +1,17 @@
+# Copyright (C) 1999-2010, International Business Machines  Corporation and others.  All Rights Reserved.
+s%^\([a-zA-Z0-9\._-]*\)[ 	]*+=%\1=$(\1) %
+s%^[A-Z]*_SO_TARG*%## &%
+s%^SHARED_OBJECT.*%## &%
+s%^LD_SONAME.*%## &%
+s%$(\([^\)]*\))%${\1}%g
+s%^	%#M#	%
+s@^[a-zA-Z%$.][^=]*$@#M#&@
+s@^\([a-zA-Z][-.a-zA-Z_0-9-]*\)[	 ]*=[ 	]*\(.*\)@\1="\2"@
+s@^\([a-zA-Z][-a-zA-Z_0-9-]*\)\.\([a-zA-Z_0-9-]*\)[	 ]*=[ 	]*\(.*\)@\1_\2=\3@
+s@^\([a-zA-Z][-a-zA-Z_0-9-]*\)\-\([a-zA-Z_0-9-]*\)[	 ]*=[ 	]*\(.*\)@\1_\2=\3@
+s@\${\([a-zA-Z][-a-zA-Z_0-9-]*\)\.\([a-zA-Z_0-9-]*\)}@${\1_\2}@g
+s@^\(prefix\)=\(.*\)@default_\1=\2\
+if [ "x${\1}" = "x" ]; then \1="$default_\1"; fi@
+s@^\(ENABLE_RPATH\)=\(.*\)@default_\1=\2\
+if [ "x${\1}" = "x" ]; then \1="$default_\1"; fi@
+s%^#SH#[ ]*%%
diff --git a/source/config/mh-aix-gcc b/source/config/mh-aix-gcc
new file mode 100644
index 0000000..40564ab
--- /dev/null
+++ b/source/config/mh-aix-gcc
@@ -0,0 +1,133 @@
+## -*-makefile-*-
+## Copyright (c) 2003-2009 IBM, Ken Foskey, and others. All rights reserved.
+##
+## Aix-specific setup (for gcc)
+##
+## Please note: AIX does NOT have library versioning per se (there is no 'SONAME' capability). 
+## So, we are using 'windows' style library names, that is, libicuuc20.1.so instead of libicuuc.so.20.1
+
+# Certain files don't compile in -ansi mode (e.g. umutex.c, toolutil.c, and cdatatst.c)
+CFLAGS += -D_ALL_SOURCE
+
+## Commands to generate dependency files
+GEN_DEPS.c=	$(CC) -E -MM $(DEFS) $(CPPFLAGS)
+GEN_DEPS.cc=	$(CXX) -E -MM $(DEFS) $(CPPFLAGS)
+
+## Commands to link
+## We need to use the C++ linker, even when linking C programs, since
+##  our libraries contain C++ code (C++ static init not called)
+LINK.c=		$(AIX_PREDELETE) $(CXX) $(CXXFLAGS) $(LDFLAGS) 
+LINK.cc=	$(AIX_PREDELETE) $(CXX) $(CXXFLAGS) $(LDFLAGS) 
+
+## Shared library options
+LD_SOOPTIONS= -Wl,-bsymbolic
+
+## Commands to make a shared library
+SHLIB.c=    $(AIX_PREDELETE) $(CC) $(CFLAGS) $(LDFLAGS) -shared -Wl,-bexpall $(LD_SOOPTIONS)
+SHLIB.cc=   $(AIX_PREDELETE) $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared -Wl,-bexpall $(LD_SOOPTIONS)
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=	-I
+LD_RPATH_PRE=	
+
+## enable the shared lib loader
+LDFLAGS += -Wl,-bbigtoc
+
+## These are the library specific LDFLAGS
+LDFLAGSICUDT=-nodefaultlibs -nostdlib
+
+## We need to delete things prior to linking, or else we'll get
+## SEVERE ERROR: output file in use ..  on AIX. 
+## But, shell script version should NOT delete target as we don't
+## have $@ in that context.  (SH = only shell script, icu-config)
+AIX_PREDELETE=rm -f $@ ; 
+#SH# AIX_PREDELETE=
+
+## Environment variable to set a runtime search path
+LDLIBRARYPATH_ENVVAR = LIBPATH
+
+## Override Versioned target for a shared library.
+FINAL_SO_TARGET=  $(basename $(SO_TARGET))$(SO_TARGET_VERSION).$(SO)
+MIDDLE_SO_TARGET= $(basename $(SO_TARGET))$(SO_TARGET_VERSION_MAJOR).$(SO)
+SHARED_OBJECT = $(notdir $(FINAL_SO_TARGET:.$(SO)=.$(SOBJ)))
+SHARED_OBJECT_NO_VERSION = $(basename $(SO_TARGET)).$(SOBJ)
+
+# The following is for Makefile.inc's use.
+ICULIBSUFFIX_VERSION = $(LIB_VERSION_MAJOR)
+
+# this one is for icudefs.mk's use
+ifeq ($(ENABLE_SHARED),YES)
+SO_TARGET_VERSION_SUFFIX = $(SO_TARGET_VERSION_MAJOR)
+endif
+
+## Compiler switch to embed a library name. Not present on AIX.
+LD_SONAME = 
+
+## The type of assembly needed when pkgdata is used for generating shared libraries.
+GENCCODE_ASSEMBLY=-a xlc
+
+## Shared object suffix
+SOBJ=   so
+# without the -brtl option, the library names use .a. AIX is funny that way.
+SO=	a
+A=	a
+
+## Non-shared intermediate object suffix
+STATIC_O = o
+
+## Special AIX rules
+
+## Build archive from shared object
+%.a : %.so
+	ln -f $< $(SHARED_OBJECT_NO_VERSION)
+	$(AR) $(ARFLAGS) $@ $(SHARED_OBJECT_NO_VERSION)
+	rm -f $(SHARED_OBJECT_NO_VERSION)
+$(LIBDIR)/%.a : %.so
+	ln -f $< $(SHARED_OBJECT_NO_VERSION)
+	$(AR) $(ARFLAGS) $@ $(SHARED_OBJECT_NO_VERSION)
+	rm -f $(SHARED_OBJECT_NO_VERSION)
+
+## Build import list from export list
+%.e : %.exp
+	@echo "Building an import list for $<"
+	@$(SHELL) -ec "echo '#! $*.a($*.so)' | cat - $< > $@"
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+%.d: $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.c) $< \
+		| sed '\''s%\($*\)\.o[ :]*%\1.o $@ : %g'\'' > $@; \
+		[ -s $@ ] || rm -f $@'
+
+%.d: $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.cc) $< \
+		| sed '\''s%\($*\)\.o[ :]*%\1.o $@ : %g'\'' > $@; \
+		[ -s $@ ] || rm -f $@'
+
+## Versioned libraries rules
+%$(SO_TARGET_VERSION_MAJOR).$(SO): %$(SO_TARGET_VERSION).$(SO)
+	$(RM) $@ && ln -s ${*F}$(SO_TARGET_VERSION).$(SO) $@
+%.$(SO): %$(SO_TARGET_VERSION).$(SO)
+	$(RM) $@ && ln -s ${*F}$(SO_TARGET_VERSION).$(SO) $@
+
+
+## BIR  - bind with internal references [so app data and icu data doesn't collide]
+# LDflags that pkgdata will use
+BIR_LDFLAGS= -Wl,-bE:$(NAME).map,-bnoexpall
+
+# Dependencies [i.e. map files] for the final library
+BIR_DEPS= $(NAME).map
+
diff --git a/source/config/mh-aix-va b/source/config/mh-aix-va
new file mode 100644
index 0000000..628e4f5
--- /dev/null
+++ b/source/config/mh-aix-va
@@ -0,0 +1,138 @@
+## -*-makefile-*-
+## Aix-specific setup (for Visual Age 5+)
+## Copyright (c) 1999-2010, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+## Commands to generate dependency files
+GEN_DEPS.c=	$(CC) -E -M $(DEFS) $(CPPFLAGS)
+GEN_DEPS.cc=	$(CXX) -E -M $(DEFS) $(CPPFLAGS)
+
+# -qroconst make the strings readonly, which is usually the default.
+#           This helps in the data library,
+# -qproto assumes all functions are prototyped (for optimization)
+# -qrtti turns on compiler RTTI, required beginning with ICU 4.6
+CFLAGS += -qproto -qroconst
+CXXFLAGS += -qproto -qroconst -qrtti
+
+# If you readd this line, you must change the SO value
+#LDFLAGS += -brtl
+
+ifeq ($(UCLN_NO_AUTO_CLEANUP),0)
+# set up init point.
+UCLN_FINI =  ucln_fini$(TARGET_STUBNAME)_$(SO_TARGET_VERSION_MAJOR)$(ICULIBSUFFIXCNAME)
+CPPFLAGS_FINI = -DUCLN_FINI=$(UCLN_FINI)
+LDFLAGS_FINI = -binitfini::$(UCLN_FINI)
+
+CPPFLAGSICUUC += $(CPPFLAGS_FINI)
+LDFLAGSICUUC += $(LDFLAGS_FINI)
+CPPFLAGSICUIO += $(CPPFLAGS_FINI)
+LDFLAGSICUIO += $(LDFLAGS_FINI)
+CPPFLAGSICUI18N += $(CPPFLAGS_FINI)
+LDFLAGSICUI18N += $(LDFLAGS_FINI)
+CPPFLAGSCTESTFW += $(CPPFLAGS_FINI)
+LDFLAGSCTESTFW += $(LDFLAGS_FINI)
+
+# ICUUC, ICUIO, ICUI18N, CTESTFW
+endif
+
+## We need to delete things prior to linking, or else we'll get
+## SEVERE ERROR: output file in use ..  on AIX. 
+## But, shell script version should NOT delete target as we don't
+## have $@ in that context.  (SH = only shell script, icu-config)
+AIX_PREDELETE=rm -f $@ ; 
+#SH# AIX_PREDELETE=
+
+## Commands to link
+## We need to use the C++ linker, even when linking C programs, since
+##  our libraries contain C++ code (C++ static init not called)
+LINK.c=		$(AIX_PREDELETE) $(CXX) $(CXXFLAGS) $(LDFLAGS)
+LINK.cc=	$(AIX_PREDELETE) $(CXX) $(CXXFLAGS) $(LDFLAGS)
+
+## Commands to make a shared library
+## -G means -berok -brtl -bnortllib -bnosymbolic -bnoautoexp
+## -bh:8 means halt on errors or worse.  We don't display warnings about
+##      duplicate inline symbols.
+SHLIB.c=	$(AIX_PREDELETE) $(CXX) -qmkshrobj -G $(LDFLAGS)
+SHLIB.cc=	$(AIX_PREDELETE) $(CXX) -qmkshrobj -G $(LDFLAGS)
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=	-I
+LD_RPATH_PRE=	
+
+## Environment variable to set a runtime search path
+LDLIBRARYPATH_ENVVAR = LIBPATH
+
+# The following is for Makefile.inc's use.
+ICULIBSUFFIX_VERSION = $(LIB_VERSION_MAJOR)
+
+# this one is for icudefs.mk's use
+ifeq ($(ENABLE_SHARED),YES)
+SO_TARGET_VERSION_SUFFIX = $(SO_TARGET_VERSION_MAJOR)
+endif
+
+LD_SONAME = 
+
+## The type of assembly needed when pkgdata is used for generating shared libraries.
+GENCCODE_ASSEMBLY=-a xlc
+
+## Shared object suffix
+SOBJ=	so
+# without the -brtl option, the library names use .a. AIX is funny that way.
+SO=	a
+## Non-shared intermediate object suffix
+STATIC_O = o
+
+## Override Versioned target for a shared library.
+FINAL_SO_TARGET=  $(basename $(SO_TARGET))$(SO_TARGET_VERSION).$(SO)
+MIDDLE_SO_TARGET= $(basename $(SO_TARGET))$(SO_TARGET_VERSION_MAJOR).$(SO)
+SHARED_OBJECT = $(notdir $(FINAL_SO_TARGET:.$(SO)=.$(SOBJ)))
+SHARED_OBJECT_NO_VERSION=  $(basename $(SO_TARGET)).$(SOBJ)
+
+## Build archive from shared object
+%.a : %.so
+	ln -f $< $(SHARED_OBJECT_NO_VERSION) 
+	$(AIX_PREDELETE) $(AR) $(ARFLAGS) $@ $(SHARED_OBJECT_NO_VERSION)
+	rm -f $(SHARED_OBJECT_NO_VERSION)
+$(LIBDIR)/%.a : %.so
+	ln -f $< $(SHARED_OBJECT_NO_VERSION) 
+	$(AIX_PREDELETE) $(AR) $(ARFLAGS) $@ $(SHARED_OBJECT_NO_VERSION)
+	rm -f $(SHARED_OBJECT_NO_VERSION)
+
+## Build import list from export list
+%.e : %.exp
+	@echo "Building an import list for $<"
+	@$(SHELL) -ec "echo '#! $*.a($*.so)' | cat - $< > $@"
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+%.d : %.u
+	@$(SHELL) -ec 'cat $<  \
+		| sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \
+		[ -s $@ ] || rm -f $@ ; rm -f $<'
+
+%.u : $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+	@$(GEN_DEPS.c) $< > /dev/null
+
+%.u : $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+	@$(GEN_DEPS.cc) $< > /dev/null
+
+## Versioned libraries rules
+%$(SO_TARGET_VERSION_MAJOR).$(SO): %$(SO_TARGET_VERSION).$(SO)
+	$(RM) $@ && ln -s ${*F}$(SO_TARGET_VERSION).$(SO) $@
+%.$(SO): %$(SO_TARGET_VERSION).$(SO)
+	$(RM) $@ && ln -s ${*F}$(SO_TARGET_VERSION).$(SO) $@
+
+## End Aix-specific setup
diff --git a/source/config/mh-alpha-linux-cc b/source/config/mh-alpha-linux-cc
new file mode 100644
index 0000000..f05632e
--- /dev/null
+++ b/source/config/mh-alpha-linux-cc
@@ -0,0 +1,85 @@
+## -*-makefile-*-
+## Alpha-Linux-specific setup
+## Copyright (c) 1999-2006, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+## Commands to generate dependency files
+#GEN_DEPS.c=	$(CC) $(DEFS) $(CPPFLAGS) -MD -c -msg_quiet
+#GEN_DEPS.cc=	$(CXX) $(DEFS) $(CPPFLAGS) -D__USE_STD_IOSTREAM -c -MD -msg_quiet
+
+## Flags for position independent code
+SHAREDLIBCFLAGS = -fPIC
+SHAREDLIBCXXFLAGS = -fPIC
+SHAREDLIBCPPFLAGS = -DPIC
+
+## Additional flags when building libraries and with threads
+THREADSCPPFLAGS = -D_REENTRANT
+LIBCPPFLAGS =
+
+# The tests need complete IEEE floating point support
+CFLAGS += -ieee
+CXXFLAGS += -ieee
+
+## Commands to compile
+COMPILE.c=	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS)  -c -signed -accept nogccinline
+COMPILE.cc=	$(CXX) $(DEFS) $(CPPFLAGS) $(CXXFLAGS) -c -signed -D__USE_STD_IOSTREAM -accept nogcc_inline
+
+
+## Commands to link
+LINK.c=		$(CC) -call_shared $(CFLAGS) $(LDFLAGS)
+LINK.cc=	$(CXX) -call_shared $(CXXFLAGS) $(LDFLAGS)
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=
+LD_RPATH_PRE=	-Wl,-rpath,
+
+## Compiler switch to embed a library name
+LD_SONAME = -Wl,-soname -Wl,$(notdir $(MIDDLE_SO_TARGET))
+
+## Shared object suffix
+SO = so
+## Non-shared intermediate object suffix
+STATIC_O = ao
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+#%.d: $(srcdir)/%.c
+#	@echo "generating dependency information for $<"
+#	@$(SHELL) -ec '$(GEN_DEPS.c) $< \
+#		| sed '\''s%\($*\)\.o[ :]*%\1.o $@ : %g'\'' > $@; \
+#		[ -s $@ ] || rm -f $@'
+
+#%.d: $(srcdir)/%.cpp
+#	@echo "generating dependency information for $<"
+#	@$(SHELL) -ec '$(GEN_DEPS.cc) $< \
+#		| sed '\''s%\($*\)\.o[ :]*%\1.o $@ : %g'\'' > $@; \
+#		[ -s $@ ] || rm -f $@'
+#
+## Versioned libraries rules
+
+%.$(SO).$(SO_TARGET_VERSION_MAJOR): %.$(SO).$(SO_TARGET_VERSION)
+	$(RM) $@ && ln -s ${<F} $@
+%.$(SO): %.$(SO).$(SO_TARGET_VERSION_MAJOR)
+	$(RM) $@ && ln -s ${*F}.$(SO).$(SO_TARGET_VERSION) $@
+
+##  Bind internal references
+
+# LDflags that pkgdata will use
+BIR_LDFLAGS= -Wl,-Bsymbolic
+
+# Dependencies [i.e. map files] for the final library
+BIR_DEPS=
+
+## End Linux-specific setup
+
diff --git a/source/config/mh-alpha-linux-gcc b/source/config/mh-alpha-linux-gcc
new file mode 100644
index 0000000..b4da43d
--- /dev/null
+++ b/source/config/mh-alpha-linux-gcc
@@ -0,0 +1,83 @@
+## -*-makefile-*-
+## Linux-specific setup
+## Copyright (c) 1999-2009, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+## Commands to generate dependency files
+GEN_DEPS.c=	$(CC) -E -MM $(DEFS) $(CPPFLAGS)
+GEN_DEPS.cc=	$(CXX) -E -MM $(DEFS) $(CPPFLAGS)
+
+## Flags for position independent code
+SHAREDLIBCFLAGS = -fPIC
+SHAREDLIBCXXFLAGS = -fPIC
+SHAREDLIBCPPFLAGS = -DPIC
+
+## Additional flags when building libraries and with threads
+THREADSCPPFLAGS = -D_REENTRANT
+LIBCPPFLAGS =
+
+# The tests need complete IEEE floating point support
+CFLAGS += -mieee
+CXXFLAGS += -mieee
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=	
+LD_RPATH_PRE=	-Wl,-rpath,
+
+## Compiler switch to embed a library name
+LD_SONAME = -Wl,-soname -Wl,$(notdir $(MIDDLE_SO_TARGET))
+
+
+## Shared library options
+LD_SOOPTIONS= -Wl,-Bsymbolic
+
+## Shared object suffix
+SO = so
+## Non-shared intermediate object suffix
+STATIC_O = ao
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+%.d: $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.c) $< \
+		| sed '\''s%\($*\)\.o[ :]*%\1.o $@ : %g'\'' > $@; \
+		[ -s $@ ] || rm -f $@'
+
+%.d: $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.cc) $< \
+		| sed '\''s%\($*\)\.o[ :]*%\1.o $@ : %g'\'' > $@; \
+		[ -s $@ ] || rm -f $@'
+
+## Versioned libraries rules
+
+%.$(SO).$(SO_TARGET_VERSION_MAJOR): %.$(SO).$(SO_TARGET_VERSION)
+	$(RM) $@ && ln -s ${<F} $@
+%.$(SO): %.$(SO).$(SO_TARGET_VERSION_MAJOR)
+	$(RM) $@ && ln -s ${*F}.$(SO).$(SO_TARGET_VERSION) $@
+
+# The type of assembly to write for generating an object file
+GENCCODE_ASSEMBLY=-a gcc
+
+##  Bind internal references
+
+# LDflags that pkgdata will use
+BIR_LDFLAGS= -Wl,-Bsymbolic
+
+# Dependencies [i.e. map files] for the final library
+BIR_DEPS=
+
+## End Linux-specific setup
+
diff --git a/source/config/mh-alpha-osf b/source/config/mh-alpha-osf
new file mode 100644
index 0000000..bf63259
--- /dev/null
+++ b/source/config/mh-alpha-osf
@@ -0,0 +1,85 @@
+## -*-makefile-*-
+## Alpha-OSF-specific setup
+## Copyright (c) 1999-2006, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+## Commands to generate dependency files
+#GEN_DEPS.c=	$(CC) $(DEFS) $(CPPFLAGS) -MD -c -msg_quiet
+#GEN_DEPS.cc=	$(CXX) $(DEFS) $(CPPFLAGS) -D__USE_STD_IOSTREAM -c -MD -msg_quiet 
+
+## Flags for position independent code
+SHAREDLIBCFLAGS = 
+SHAREDLIBCXXFLAGS = 
+SHAREDLIBCPPFLAGS = 
+
+## Additional flags when building libraries and with threads
+THREADSCPPFLAGS = -D_REENTRANT -pthread
+LIBCPPFLAGS =
+
+# The tests need complete IEEE floating point support
+CFLAGS += -ieee
+CXXFLAGS += -ieee
+
+## Commands to compile
+COMPILE.c=	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c
+COMPILE.cc=	$(CXX) $(DEFS) $(CPPFLAGS) $(CXXFLAGS) -c -D__USE_STD_IOSTREAM
+
+
+## Commands to link
+LINK.c=		$(CC) -call_shared $(CFLAGS) $(LDFLAGS) 
+LINK.cc=	$(CXX) -call_shared $(CXXFLAGS) $(LDFLAGS) 
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=	$(LD_RPATH)$(LD_RPATH_PRE)path1	
+LD_RPATH_PRE=	-Wl,-rpath,
+
+## Compiler switch to embed a library name
+LD_SONAME = -Wl,-soname -Wl,$(notdir $(MIDDLE_SO_TARGET))
+
+## Shared object suffix
+SO = so
+## Non-shared intermediate object suffix
+STATIC_O = ao
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+#%.d: $(srcdir)/%.c
+#	@echo "generating dependency information for $<"
+#	@$(SHELL) -ec '$(GEN_DEPS.c) $< \
+#		| sed '\''s%\($*\)\.o[ :]*%\1.o $@ : %g'\'' > $@; \
+#		[ -s $@ ] || rm -f $@'
+
+#%.d: $(srcdir)/%.cpp
+#	@echo "generating dependency information for $<"
+#	@$(SHELL) -ec '$(GEN_DEPS.cc) $< \
+#		| sed '\''s%\($*\)\.o[ :]*%\1.o $@ : %g'\'' > $@; \
+#		[ -s $@ ] || rm -f $@'
+#
+## Versioned libraries rules
+
+%.$(SO).$(SO_TARGET_VERSION_MAJOR): %.$(SO).$(SO_TARGET_VERSION)
+	$(RM) $@ && ln -s ${<F} $@
+%.$(SO): %.$(SO).$(SO_TARGET_VERSION_MAJOR)
+	$(RM) $@ && ln -s ${*F}.$(SO).$(SO_TARGET_VERSION) $@
+
+##  Bind internal references
+
+# LDflags that pkgdata will use
+BIR_LDFLAGS= -Wl,-Bsymbolic
+
+# Dependencies [i.e. map files] for the final library
+BIR_DEPS=
+
+## End Tru64 5.1 specific setup
+
diff --git a/source/config/mh-beos b/source/config/mh-beos
new file mode 100644
index 0000000..0e5691b
--- /dev/null
+++ b/source/config/mh-beos
@@ -0,0 +1,106 @@
+## -*-makefile-*-
+## BeOS-specific setup
+## Copyright (c) 2003-2006, International Business Machines Corporation and
+## others. All Rights Reserved.
+##
+## Original author: Andrew Bachmann
+
+## Commands to generate dependency files
+GEN_DEPS.c=  $(CC) -E -MM $(DEFS) $(CPPFLAGS)
+GEN_DEPS.cc= $(CXX) -E -MM $(DEFS) $(CPPFLAGS)
+
+# Safe optimizations
+#OPTIMIZATIONS= -fdefault-inline -fdefer-pop -fforce-mem -fforce-addr \
+#	  -finline -finline-functions \
+#	  -fkeep-inline-functions -fkeep-static-consts -fbranch-count-reg \
+#	  -ffunction-cse -fstrength-reduce -fthread-jumps -fcse-follow-jumps \
+#	  -fcse-skip-blocks -frerun-cse-after-loop -frerun-loop-opt \
+#	  -fexpensive-optimizations -foptimize-register-move -fregmove \
+#	  -fschedule-insns -fschedule-insns2 -ffloat-store -funroll-loops \
+#	  -fmove-all-movables -freduce-all-givs -fpeephole \
+#	  -funroll-all-loops -ffunction-sections -fdata-sections
+
+# BeOS gccs (geekgadgets + 2.95.3) have this old bug: 
+# after this:          const wchar_t x[] = L"foo";
+# x[2] is "optimized" into: (wchar_t)((char *)x)[2] (== 0)
+#
+# see also: http://gcc.gnu.org/ml/gcc-patches/2000-09/msg00454.html
+#
+# Unfortunately this behavior isn't controlled by a flag so we can't
+# use any O optimizations at all. (the behavior kicks in at -O1)
+
+# Optimizations aren't currently defined in the mh files.
+# So Don't override any flags set by the user or runConfigureICU.
+#CFLAGS += $(OPTIMIZATIONS)
+#CXXFLAGS += $(OPTIMIZATIONS)
+
+# Use -nostart instead of -shared
+SHLIB.c=      $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -nostart
+SHLIB.cc=     $(CXX) $(DEFS) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -nostart
+
+## Flags for position independent code
+SHAREDLIBCFLAGS = -fPIC
+SHAREDLIBCXXFLAGS = -fPIC
+SHAREDLIBCPPFLAGS = -DPIC
+
+## Additional flags when building libraries and with threads
+LIBCPPFLAGS = 
+THREADSCPPFLAGS = 
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=	
+LD_RPATH_PRE = -Wl,-rpath,
+
+## Compiler switch to embed a library name
+LD_SONAME = -Wl,-soname -Wl,$(notdir $(MIDDLE_SO_TARGET))
+
+## Shared object suffix
+SO = so
+## Non-shared intermediate object suffix
+STATIC_O = ao
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+%.d: $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.c) $< \
+		| sed '\''s%\($*\)\.o[ :]*%\1.o $@ : %g'\'' > $@; \
+		[ -s $@ ] || rm -f $@'
+
+%.d: $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.cc) $< \
+		| sed '\''s%\($*\)\.o[ :]*%\1.o $@ : %g'\'' > $@; \
+		[ -s $@ ] || rm -f $@'
+
+## Versioned libraries rules
+
+%.$(SO).$(SO_TARGET_VERSION_MAJOR): %.$(SO).$(SO_TARGET_VERSION)
+	$(RM) $@ && ln -s ${<F} $@
+%.$(SO): %.$(SO).$(SO_TARGET_VERSION_MAJOR)
+	$(RM) $@ && ln -s ${*F}.$(SO).$(SO_TARGET_VERSION) $@
+
+##  Bind internal references
+
+# LDflags that pkgdata will use
+BIR_LDFLAGS= -Wl,-Bsymbolic
+
+# Dependencies [i.e. map files] for the final library
+BIR_DEPS=
+
+# Use LIBRARY_PATH instead of LD_LIBRARY_PATH
+LDLIBRARYPATH_ENVVAR= LIBRARY_PATH
+
+## End BeOS-specific setup
+
diff --git a/source/config/mh-bsd-gcc b/source/config/mh-bsd-gcc
new file mode 100644
index 0000000..5f8a38d
--- /dev/null
+++ b/source/config/mh-bsd-gcc
@@ -0,0 +1,67 @@
+## -*-makefile-*-
+## BSD-specific setup (FreeBSD, OpenBSD, NetBSD, *BSD)
+## Copyright (c) 1999-2009, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+## Commands to generate dependency files
+GEN_DEPS.c=	$(CC) -E -MM $(DEFS) $(CPPFLAGS)
+GEN_DEPS.cc=	$(CXX) -E -MM $(DEFS) $(CPPFLAGS)
+
+## Flags for position independent code
+SHAREDLIBCFLAGS = -fPIC
+SHAREDLIBCXXFLAGS = -fPIC
+SHAREDLIBCPPFLAGS = -DPIC
+
+## Additional flags when building libraries and with threads
+THREADSCPPFLAGS = -D_REENTRANT
+LIBCPPFLAGS =
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=	
+LD_RPATH_PRE=	-Wl,-rpath,
+
+## Compiler switch to embed a library name
+LD_SONAME = -Wl,-soname -Wl,$(notdir $(MIDDLE_SO_TARGET))
+
+## Shared library options
+LD_SOOPTIONS= -Wl,-Bsymbolic
+
+## Shared object suffix
+SO = so
+## Non-shared intermediate object suffix
+STATIC_O = ao
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+%.d: $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.c) $< \
+		| sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \
+		[ -s $@ ] || rm -f $@'
+
+%.d: $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.cc) $< \
+		| sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \
+		[ -s $@ ] || rm -f $@'
+
+## Versioned libraries rules
+
+%.$(SO).$(SO_TARGET_VERSION_MAJOR): %.$(SO).$(SO_TARGET_VERSION)
+	$(RM) $@ && ln -s ${<F} $@
+%.$(SO): %.$(SO).$(SO_TARGET_VERSION_MAJOR)
+	$(RM) $@ && ln -s ${*F}.$(SO).$(SO_TARGET_VERSION) $@
+
+## End FreeBSD-specific setup
+
diff --git a/source/config/mh-cygwin b/source/config/mh-cygwin
new file mode 100644
index 0000000..fdbd0e7
--- /dev/null
+++ b/source/config/mh-cygwin
@@ -0,0 +1,141 @@
+## -*-makefile-*-
+## Cygwin-specific setup
+## Copyright (c) 2001-2010, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+## Commands to generate dependency files
+GEN_DEPS.c=	$(CC) -E -MM $(DEFS) $(CPPFLAGS)
+GEN_DEPS.cc=	$(CXX) -E -MM $(DEFS) $(CPPFLAGS)
+
+## Flags to create/use a static library
+ifneq ($(ENABLE_SHARED),YES)
+## Make sure that the static libraries can be built and used
+CPPFLAGS += -DU_STATIC_IMPLEMENTATION
+else
+## Make sure that the static libraries can be built
+STATICCPPFLAGS = -DU_STATIC_IMPLEMENTATION
+endif
+
+## Flags for position independent code
+SHAREDLIBCFLAGS = 
+SHAREDLIBCXXFLAGS = 
+SHAREDLIBCPPFLAGS = -DPIC
+
+## Additional flags when building libraries and with threads
+THREADSCPPFLAGS = -D_REENTRANT
+LIBCPPFLAGS =
+
+# Commands to link. Link with C++ in case static libraries are used.
+LINK.c=       $(CXX) $(CXXFLAGS) $(LDFLAGS)
+#LINK.cc=      $(CXX) $(CXXFLAGS) $(LDFLAGS)
+
+## Shared library options
+LD_SOOPTIONS= -Wl,-Bsymbolic
+
+## Commands to make a shared library
+# $(subst) won't work in shell script.  #M# at the end omits these
+# lines from the shell script (Make only)
+SHLIB.c=	$(CC) $(CFLAGS) $(LDFLAGS) -shared $(LD_SOOPTIONS) -Wl,--enable-auto-import -Wl,--out-implib=$(subst cyg,lib,$@).$(A)#M#
+SHLIB.cc=	$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(LD_SOOPTIONS) -Wl,--enable-auto-import -Wl,--out-implib=$(subst cyg,lib,$@).$(A)#M#
+# the #SH# lines don't go through further postprocessing. 
+# so, they must be valid shell script starting from column 4
+#SH#SHLIB_c="$(CC) $(CFLAGS) $(LDFLAGS) -shared "
+#SH#SHLIB_cc="$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared "
+
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=	
+LD_RPATH_PRE=	-Wl,-rpath,
+
+## Compiler switch to embed a library name
+LD_SONAME =
+
+## Shared object suffix
+SO = dll
+## Non-shared intermediate object suffix
+STATIC_O = ao
+LIBICU = cyg$(ICUPREFIX)
+## To have an import library is better on Cygwin
+IMPORT_LIB_EXT = .dll.a
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+%.d: $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+	@echo -n "$@ " > $@
+	@$(GEN_DEPS.c) $< >> $@ || (rm -f $@ && FALSE)
+
+%.d: $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+	@echo -n "$@ " > $@
+	@$(GEN_DEPS.cc) $< >> $@ || (rm -f $@ && FALSE)
+
+## Versioned target for a shared library.
+## Since symbolic links don't work the same way on Windows,
+## we only use the version major number.
+#FINAL_SO_TARGET=$(basename $(SO_TARGET))$(SO_TARGET_VERSION).$(SO)
+FINAL_SO_TARGET=$(basename $(SO_TARGET))$(SO_TARGET_VERSION_MAJOR).$(SO)
+MIDDLE_SO_TARGET=$(FINAL_SO_TARGET)
+
+IMPORT_LIB = $(subst cyg,lib,$(FINAL_SO_TARGET)).$(A)#M#
+MIDDLE_IMPORT_LIB = $(subst cyg,lib,$(basename $(SO_TARGET)))$(SO_TARGET_VERSION_MAJOR).$(SO).$(A)#M#
+FINAL_IMPORT_LIB = $(IMPORT_LIB)#M#
+
+# The following is for Makefile.inc's use.
+ICULIBSUFFIX_VERSION = $(LIB_VERSION_MAJOR)
+
+## Versioned libraries rules
+#%$(SO_TARGET_VERSION_MAJOR).$(SO): %$(SO_TARGET_VERSION).$(SO)
+#	$(RM) $@ && cp ${<F} $@
+%.$(SO): %$(SO_TARGET_VERSION_MAJOR).$(SO)
+	$(RM) $(subst cyg,lib,$@).$(A) && ln -s $(subst cyg,lib,${<F}).$(A) $(subst cyg,lib,$@).$(A)
+
+## Install libraries as executable
+INSTALL-L=$(INSTALL_PROGRAM)
+
+##  Bind internal references
+
+# LDflags that pkgdata will use
+BIR_LDFLAGS= -Wl,-Bsymbolic
+
+# Dependencies [i.e. map files] for the final library
+BIR_DEPS=
+
+# Environment variable to set a runtime search path
+LDLIBRARYPATH_ENVVAR = PATH
+
+# The type of assembly to write for generating an object file
+GENCCODE_ASSEMBLY=-a gcc-cygwin
+
+# put this here again so it gets cyguc...
+
+#SH#ICULIBS_COMMON_LIB_NAME="${LIBICU}uc${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}.${SO}"
+
+# for icu-config
+
+#SH### copied from Makefile.inc
+#SH#ICULIBS_COMMON="-l${LIBICU}uc${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}"
+#SH#ICULIBS_DATA="-l${LIBICU}${DATA_STUBNAME}${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}"
+#SH#ICULIBS_I18N="-l${LIBICU}${I18N_STUBNAME}${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}"
+#SH#ICULIBS_TOOLUTIL="-l${LIBICU}tu${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}"
+#SH#ICULIBS_CTESTFW="-l${LIBICU}ctestfw${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}"
+#SH#ICULIBS_ICUIO="-l${LIBICU}io${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}"
+#SH#ICULIBS_OBSOLETE="-l${LIBICU}obsolete${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}"
+#SH#ICULIBS_LAYOUT="-l${LIBICU}le${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}"
+#SH#ICULIBS_LAYOUTEX="-l${LIBICU}lx${ICULIBSUFFIX}${ICULIBSUFFIX_VERSION}"
+#SH#ICULIBS_BASE="${LIBS} -L${libdir}"
+#SH#ICULIBS="${ICULIBS_BASE} ${ICULIBS_I18N} ${ICULIBS_COMMON} ${ICULIBS_DATA}" 
+
+## End Cygwin-specific setup
+
diff --git a/source/config/mh-cygwin-msvc b/source/config/mh-cygwin-msvc
new file mode 100644
index 0000000..48deb43
--- /dev/null
+++ b/source/config/mh-cygwin-msvc
@@ -0,0 +1,230 @@
+## Cygwin with Microsoft Visual C++ compiler specific setup
+## Copyright (c) 2001-2010, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+# We install sbin tools into the same bin directory because
+# pkgdata needs some of the tools in sbin, and we can't always depend on
+# icu-config working on Windows.
+sbindir=$(bindir)
+
+## Commands to generate dependency files
+GEN_DEPS.c=	:
+GEN_DEPS.cc=	:
+#GEN_DEPS.c=	$(COMPILE.c) /E
+#GEN_DEPS.cc=	$(COMPILE.cc) /E
+
+## Flags to create/use a static library
+ifneq ($(ENABLE_SHARED),YES)
+## Make sure that the static libraries can be built and used
+CPPFLAGS += -DU_STATIC_IMPLEMENTATION#M#
+else
+## Make sure that the static libraries can be built
+STATICCPPFLAGS = -DU_STATIC_IMPLEMENTATION
+endif
+
+## Flags for position independent code
+SHAREDLIBCFLAGS = 
+SHAREDLIBCXXFLAGS = 
+SHAREDLIBCPPFLAGS =
+
+## Additional flags when building libraries and with threads
+LIBCPPFLAGS = 
+
+ifeq ($(ENABLE_RELEASE),1)
+# Make sure that assertions are disabled
+CPPFLAGS+=-DU_RELEASE=1#M#
+endif
+
+ifeq ($(ENABLE_DEBUG),1)
+# Pass debugging flag through
+CPPFLAGS+=-D_DEBUG=1#M#
+ICULIBSUFFIX:=$(ICULIBSUFFIX)d#M#
+endif
+
+# /GF pools strings and places them into read-only memory
+# /EHsc enables exception handling
+# /Zc:wchar_t makes wchar_t a native type. Required for C++ ABI compatibility.
+# -D_CRT_SECURE_NO_DEPRECATE is needed to quiet warnings about using standard C functions.
+CFLAGS+=/GF /nologo
+CXXFLAGS+=/GF /nologo /EHsc /Zc:wchar_t
+CPPFLAGS+=-D_CRT_SECURE_NO_DEPRECATE
+DEFS+=-DWIN32
+DEFS+=-DCYGWINMSVC
+LDFLAGS+=/nologo
+
+# Commands to compile
+COMPILE.c=	$(CC) $(CPPFLAGS) $(DEFS) $(CFLAGS) /c
+COMPILE.cc=	$(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) /c
+
+# Commands to link
+LINK.c=		LINK.EXE /subsystem:console $(LDFLAGS)
+LINK.cc=	LINK.EXE /subsystem:console $(LDFLAGS)
+
+## Commands to make a shared library
+SHLIB.c=	LINK.EXE /DLL $(LDFLAGS)
+SHLIB.cc=	LINK.EXE /DLL $(LDFLAGS)
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=	
+LD_RPATH_PRE=
+
+## Compiler switch to embed a library name
+LD_SONAME = /IMPLIB:$(SO_TARGET:.dll=.lib)
+
+## Shared object suffix
+SO = dll
+## Non-shared intermediate object suffix
+STATIC_O = ao
+# OUTOPT is for creating a specific output name
+OUTOPT = /out:
+
+# Static library prefix and file extension
+LIBSICU = $(STATIC_PREFIX)$(ICUPREFIX)
+A = lib
+
+# Cygwin's ar can't handle Win64 right now. So we use Microsoft's tool instead.
+AR = LIB.EXE#M#
+ARFLAGS := /nologo $(ARFLAGS:r=)#M#
+RANLIB = ls -s#M#
+AR_OUTOPT = /OUT:#M#
+
+## An import library is needed for z/OS, MSVC and Cygwin
+IMPORT_LIB_EXT = .lib
+
+LIBPREFIX=
+DEFAULT_LIBS = advapi32.lib
+
+# Change the stubnames so that poorly working FAT disks and installation programs can work.
+# This is also for backwards compatibility.
+DATA_STUBNAME = dt
+I18N_STUBNAME = in
+LIBICU = $(STATIC_PREFIX_WHEN_USED)$(ICUPREFIX)
+
+## Link commands to link to ICU libs
+ifeq ($(wildcard $(LIBDIR)/$(LIBICU)$(DATA_STUBNAME)$(ICULIBSUFFIX).lib),)
+LIBICUDT=	$(top_builddir)/stubdata/$(LIBICU)$(DATA_STUBNAME)$(ICULIBSUFFIX).lib
+else
+LIBICUDT=	$(LIBDIR)/$(LIBICU)$(DATA_STUBNAME)$(ICULIBSUFFIX).lib
+endif
+LIBICUUC=	$(LIBDIR)/$(LIBICU)$(COMMON_STUBNAME)$(ICULIBSUFFIX).lib $(LIBICUDT)
+LIBICUI18N=	$(LIBDIR)/$(LIBICU)$(I18N_STUBNAME)$(ICULIBSUFFIX).lib
+LIBICULE=	$(LIBDIR)/$(LIBICU)$(LAYOUT_STUBNAME)$(ICULIBSUFFIX).lib
+LIBICULX=	$(LIBDIR)/$(LIBICU)$(LAYOUTEX_STUBNAME)$(ICULIBSUFFIX).lib
+LIBICUIO=	$(LIBDIR)/$(LIBICU)$(IO_STUBNAME)$(ICULIBSUFFIX).lib
+LIBCTESTFW=	$(top_builddir)/tools/ctestfw/$(LIBICU)$(CTESTFW_STUBNAME)$(ICULIBSUFFIX).lib
+LIBICUTOOLUTIL=	$(LIBDIR)/$(LIBICU)$(TOOLUTIL_STUBNAME)$(ICULIBSUFFIX).lib
+
+## These are the library specific LDFLAGS
+LDFLAGSICUDT+=	/base:"0x4ad00000" /NOENTRY# The NOENTRY option is required for creating a resource-only DLL.
+LDFLAGSICUUC=	/base:"0x4a800000"# in-uc = 1MB
+LDFLAGSICUI18N=	/base:"0x4a900000"# io-in = 2MB
+LDFLAGSICUIO=	/base:"0x4ab00000"# le-io = 1MB
+LDFLAGSICULE=	/base:"0x4ac00000"# lx-le = 512KB
+LDFLAGSICULX=	/base:"0x4ac80000"
+LDFLAGSCTESTFW=# Unused for now.
+LDFLAGSICUTOOLUTIL=	/base:"0x4ac00000"# Same as layout. Layout and tools probably won't mix.
+
+# The #M# is used to delete lines for icu-config
+# Current full path directory.
+CURR_FULL_DIR=$(subst \,/,$(shell cygpath -da .))#M# -m isn't used because it doesn't work on Win98
+# Current full path directory for use in source code in a -D compiler option.
+CURR_SRCCODE_FULL_DIR=$(subst \,\\,$(shell cygpath -da .))#M#
+
+ifeq ($(srcdir),.)
+SOURCE_FILE=$<
+else
+SOURCE_FILE=$(shell cygpath -dma $<)#M#
+endif
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) /Fo$@ $(SOURCE_FILE)
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) /Fo$@ $(SOURCE_FILE)
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) /Fo$@ $(SOURCE_FILE)
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) /Fo$@ $(SOURCE_FILE)
+
+
+## Dependency rules
+## This is a start to how depdendencies could work
+# The commented out rules may not properly delete the file when ^C is pressed
+#   or the compiler fails.
+# make currently doesn't like rules with C:\\PROGRA~1\\.. in the depedency.
+#   So system headers are ignored by ignoring \\
+%.d : $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+	@$(GEN_DEPS.c) $< > $@
+#	@echo -n "generating dependency information for "
+#	@echo -n "$@ $(basename $<).o : " > $@
+#	@$(SHELL) -ec '$(GEN_DEPS.c) $< \
+#		| grep "#line 1 " | grep -v \\\\ | cut -d " " -f 3 \
+#		| /usr/bin/sort -u | sed s/\"$$/\\\\/ | sed s/^\"/\	/ >> $@ \
+#		|| (rm -f $@ && echo $@ && false)'
+
+%.d : $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+	@$(GEN_DEPS.cc) $< > $@
+#	@echo -n "generating dependency information for "
+#	@echo -n "$@ $(basename $<).o : " > $@
+#	@$(SHELL) -ec '$(GEN_DEPS.cc) $< \
+#		| grep "#line 1 " | grep -v \\\\ | cut -d " " -f 3 \
+#		| /usr/bin/sort -u | sed s/\"$$/\\\\/ | sed s/^\"/\	/ >> $@ \
+#		|| (rm -f $@ && echo $@ && false)'
+
+## Compile a Windows resource file
+%.res : $(srcdir)/%.rc
+	rc.exe /fo$@ $(CPPFLAGS) $(SOURCE_FILE)
+
+## Versioned target for a shared library.
+FINAL_SO_TARGET= $(basename $(SO_TARGET))$(SO_TARGET_VERSION_MAJOR).$(SO)
+MIDDLE_SO_TARGET=$(FINAL_SO_TARGET)
+
+## Starting in MSVC 2005, manifest files are required. This reduces the obnoxiousness of this feature.
+	POST_SO_BUILD_STEP = @([ -e $<.manifest ] && \
+	( echo Embedding manifest into $< && mt.exe -nologo -manifest $<.manifest -outputresource:"$<;2" && rm -rf $<.manifest )) \
+	|| true
+	POST_BUILD_STEP = @([ -e $@.manifest ] && \
+	( echo Embedding manifest into $@ && mt.exe -nologo -manifest $@.manifest -outputresource:"$@;1" && rm -rf $@.manifest )) \
+	|| true
+
+## Special pkgdata information that is needed
+PKGDATA_VERSIONING = -r $(SO_TARGET_VERSION_MAJOR)
+ICUPKGDATA_INSTALL_DIR = $(shell mkdir -p  $(DESTDIR)$(ICUPKGDATA_DIR) ;  cygpath -dma $(DESTDIR)$(ICUPKGDATA_DIR))#M#
+ICUPKGDATA_INSTALL_LIBDIR = $(shell mkdir -p  $(DESTDIR)$(libdir) ; cygpath -dma $(DESTDIR)$(libdir))#M#
+
+## Versioned import library names. The library names are versioned,
+## but the import libraries do not need versioning.
+IMPORT_LIB = $(basename $(SO_TARGET))$(IMPORT_LIB_EXT)#M#
+MIDDLE_IMPORT_LIB = $(IMPORT_LIB)#M#
+FINAL_IMPORT_LIB = $(MIDDLE_IMPORT_LIB)#M#
+
+# The following is for Makefile.inc's use.
+ICULIBSUFFIX_VERSION = $(LIB_VERSION_MAJOR)
+
+## Versioned libraries rules
+#%$(SO_TARGET_VERSION_MAJOR).$(SO): %$(SO_TARGET_VERSION).$(SO)
+#	$(RM) $@ && cp ${<F} $@
+
+# The following rule is sometimes a no op.
+# We only want to do a post-build step when a manifest file doesn't exist.
+%.$(SO): %$(SO_TARGET_VERSION_MAJOR).$(SO)
+	@echo -n
+	$(POST_SO_BUILD_STEP)
+
+## Install libraries as executable
+INSTALL-L=$(INSTALL_PROGRAM)
+
+# Environment variable to set a runtime search path
+LDLIBRARYPATH_ENVVAR = PATH
+
+# These are needed to allow the pkgdata nmake files to work
+PKGDATA_INVOKE_OPTS = MAKEFLAGS=
+
+# Include the version information in the shared library
+ENABLE_SO_VERSION_DATA=1
+
+## End Cygwin-specific setup
+
diff --git a/source/config/mh-darwin b/source/config/mh-darwin
new file mode 100644
index 0000000..c2dc398
--- /dev/null
+++ b/source/config/mh-darwin
@@ -0,0 +1,94 @@
+## -*-makefile-*-
+## Darwin-specific setup (Darwin is the Mac OS X developer preview, successor
+## to Rhapsody, aka Mac OS X Server)
+## Copyright (c) 1999-2009 International Business Machines Corporation and
+## others. All Rights Reserved.
+
+## Flags for position independent code
+SHAREDLIBCFLAGS = -dynamic
+SHAREDLIBCXXFLAGS = -dynamic
+SHAREDLIBCPPFLAGS =
+
+# Pad out the paths to the maximum possible length
+LD_FLAGS += -headerpad_max_install_names
+
+## Commands to generate dependency files
+GEN_DEPS.c=	$(CC) -E -MMD  $(DEFS) $(CPPFLAGS)
+GEN_DEPS.cc=	$(CXX) -E -MMD  $(DEFS) $(CPPFLAGS)
+
+## Commands to compile
+COMPILE.c=	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -fno-common -c
+COMPILE.cc=	$(CXX) $(DEFS) $(CPPFLAGS) $(CXXFLAGS) -fno-common -c
+
+## Commands to make a shared library
+SHLIB.c=	$(CC) -dynamiclib -dynamic $(CFLAGS) $(LDFLAGS) $(LD_SOOPTIONS)
+SHLIB.cc=	$(CXX) -dynamiclib -dynamic $(CXXFLAGS) $(LDFLAGS) $(LD_SOOPTIONS)
+
+## Compiler switches to embed a library name and version information
+LD_SONAME = -Wl,-compatibility_version -Wl,$(SO_TARGET_VERSION_MAJOR) -Wl,-current_version -Wl,$(SO_TARGET_VERSION) -install_name $(notdir $(MIDDLE_SO_TARGET))
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=
+LD_RPATH_PRE=	
+
+## Environment variable to set a runtime search path
+LDLIBRARYPATH_ENVVAR = DYLD_LIBRARY_PATH
+
+GENCCODE_ASSEMBLY=-a gcc-darwin
+
+## Shared object suffix
+SO=		dylib
+## Non-shared intermediate object suffix
+STATIC_O = ao
+
+## Override Versioned target for a shared library.
+FINAL_SO_TARGET=  $(basename $(SO_TARGET)).$(SO_TARGET_VERSION).$(SO)
+MIDDLE_SO_TARGET= $(basename $(SO_TARGET)).$(SO_TARGET_VERSION_MAJOR).$(SO)
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+%.d : $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+	@$(GEN_DEPS.c) $< > /dev/null
+	@mv $@ $@~
+	@printf "%s" "$@ " > $@
+	@cat < $@~ >> $@
+	@-rm $@~
+
+%.d : $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+	@$(GEN_DEPS.cc) $< >/dev/null
+	@mv $@ $@~
+	@printf "%s" "$@ " > $@
+	@cat < $@~ >> $@
+	@-rm $@~
+
+## Versioned libraries rules
+
+%.$(SO_TARGET_VERSION_MAJOR).$(SO): %.$(SO_TARGET_VERSION).$(SO)
+	$(RM) $@ && ln -s ${<F} $@
+%.$(SO): %.$(SO_TARGET_VERSION_MAJOR).$(SO)
+	$(RM) $@ && ln -s ${*F}.$(SO_TARGET_VERSION).$(SO) $@
+
+# tzcode option
+TZORIG_EXTRA_CFLAGS=-DSTD_INSPIRED
+
+# genren opts
+GENREN_PL_OPTS=-x Mach-O -n '-g' -p '| c++filt'
+
+## Remove shared library 's'
+STATIC_PREFIX_WHEN_USED = 
+STATIC_PREFIX = 
+
+## End Darwin-specific setup
diff --git a/source/config/mh-haiku b/source/config/mh-haiku
new file mode 100644
index 0000000..7f6ce61
--- /dev/null
+++ b/source/config/mh-haiku
@@ -0,0 +1,75 @@
+## -*-makefile-*-

+## haiku-specific setup

+## Copyright (c) 2010, International Business Machines Corporation and

+## others. All Rights Reserved.

+##

+

+## Commands to generate dependency files

+GEN_DEPS.c=  $(CC) -E -MM $(DEFS) $(CPPFLAGS)

+GEN_DEPS.cc= $(CXX) -E -MM $(DEFS) $(CPPFLAGS)

+

+## Flags for position independent code

+SHAREDLIBCFLAGS = -fPIC

+SHAREDLIBCXXFLAGS = -fPIC

+SHAREDLIBCPPFLAGS = -DPIC

+

+## Additional flags when building libraries and with threads

+LIBCPPFLAGS =

+THREADSCPPFLAGS =

+

+## Compiler switch to embed a runtime search path

+LD_RPATH=

+LD_RPATH_PRE = -Wl,-rpath,

+

+## Compiler switch to embed a library name

+LD_SONAME = -Wl,-soname -Wl,$(notdir $(MIDDLE_SO_TARGET))

+

+## Shared object suffix

+SO = so

+## Non-shared intermediate object suffix

+STATIC_O = ao

+

+## Compilation rules

+%.$(STATIC_O): $(srcdir)/%.c

+        $(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<

+%.o: $(srcdir)/%.c

+        $(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<

+

+%.$(STATIC_O): $(srcdir)/%.cpp

+        $(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<

+%.o: $(srcdir)/%.cpp

+        $(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<

+

+

+## Dependency rules

+%.d: $(srcdir)/%.c

+        @echo "generating dependency information for $<"

+        @$(SHELL) -ec '$(GEN_DEPS.c) $< \

+                | sed '\''s%\($*\)\.o[ :]*%\1.o $@ : %g'\'' > $@; \

+                [ -s $@ ] || rm -f $@'

+

+%.d: $(srcdir)/%.cpp

+        @echo "generating dependency information for $<"

+        @$(SHELL) -ec '$(GEN_DEPS.cc) $< \

+                | sed '\''s%\($*\)\.o[ :]*%\1.o $@ : %g'\'' > $@; \

+                [ -s $@ ] || rm -f $@'

+

+## Versioned libraries rules

+

+%.$(SO).$(SO_TARGET_VERSION_MAJOR): %.$(SO).$(SO_TARGET_VERSION)

+        $(RM) $@ && ln -s ${<F} $@

+%.$(SO): %.$(SO).$(SO_TARGET_VERSION_MAJOR)

+        $(RM) $@ && ln -s ${*F}.$(SO).$(SO_TARGET_VERSION) $@

+

+##  Bind internal references

+

+# LDflags that pkgdata will use

+BIR_LDFLAGS= -Wl,-Bsymbolic

+

+# Dependencies [i.e. map files] for the final library

+BIR_DEPS=

+

+# Use LIBRARY_PATH instead of LD_LIBRARY_PATH

+LDLIBRARYPATH_ENVVAR= LIBRARY_PATH

+

+## End haiku-specific setup

diff --git a/source/config/mh-hpux-acc b/source/config/mh-hpux-acc
new file mode 100644
index 0000000..ab93596
--- /dev/null
+++ b/source/config/mh-hpux-acc
@@ -0,0 +1,136 @@
+## -*-makefile-*-
+## HP/UX-specific setup using aCC
+## Copyright (c) 1999-2010, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+## Commands to generate dependency files
+GEN_DEPS.c=	:
+GEN_DEPS.cc= 	:
+
+## Flags for position independent code
+SHAREDLIBCFLAGS = +Z
+SHAREDLIBCXXFLAGS = +Z
+
+## Additional flags when building libraries with threads
+## We use this instead of -mt, which isn't available in all versions of aCC
+## Our tools won't compile with -D_POSIX_C_SOURCE=199506L
+THREADSCPPFLAGS = -D_REENTRANT -D_THREAD_SAFE
+
+# Use Extended ANSI mode, which is useful for 64-bit numbers
+# +W ignores some warnings
+#    740 Unsafe cast between pointers/references to incomplete classes...
+#    749 This operation is non-portable and potentially unsafe.
+#        (Ironically the solution to fix this warning is non-portable)
+#    823 Redundant preprocessing concatenation operation results in two valid
+#        preprocessing tokens. This comes from INT64_C in <inttypes.h>
+#   4232 conversion to a more strictly aligned type may cause misaligned access.
+CFLAGS += -Ae +Olit=all
+CXXFLAGS += -Wc,-ansi_for_scope,on +W740 +W749 +W823 +W4232
+
+ifeq ($(UCLN_NO_AUTO_CLEANUP),0)
+# set up init point.
+UCLN_FINI =  ucln_fini$(TARGET_STUBNAME)_$(SO_TARGET_VERSION_MAJOR)$(ICULIBSUFFIXCNAME)
+CPPFLAGS_FINI = -DUCLN_FINI=$(UCLN_FINI)
+LDFLAGS_FINI = -Wl,+fini,$(UCLN_FINI)
+
+CPPFLAGSICUUC += $(CPPFLAGS_FINI)
+LDFLAGSICUUC += $(LDFLAGS_FINI)
+CPPFLAGSICUIO += $(CPPFLAGS_FINI)
+LDFLAGSICUIO += $(LDFLAGS_FINI)
+CPPFLAGSICUI18N += $(CPPFLAGS_FINI)
+LDFLAGSICUI18N += $(LDFLAGS_FINI)
+CPPFLAGSCTESTFW += $(CPPFLAGS_FINI)
+LDFLAGSCTESTFW += $(LDFLAGS_FINI)
+
+# ICUUC, ICUIO, ICUI18N, CTESTFW
+endif
+
+# -Bhidden_def Hides all symbols defined in the module.
+#LIBCFLAGS = -Bhidden_def
+#LIBCXXFLAGS = -Bhidden_def
+
+## Commands to compile
+COMPILE.c=	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c
+COMPILE.cc=	$(CXX) $(DEFS) $(CPPFLAGS) $(CXXFLAGS) -c
+
+## Common 'default' path to ensure the sanity of users.  Search the current
+## directory, at least.
+LD_DEFAULTPATH= -Wl,+b,'$$'ORIGIN/
+
+# Use SHLIB_PATH and LD_LIBRARY_PATH to locate shared libraries
+LDFLAGS += -Wl,+s $(LD_DEFAULTPATH)
+
+## Commands to link
+## For aCC, use the C++ linker so that __shlinit gets defined
+LINK.c=		$(CXX) $(CXXFLAGS) $(LDFLAGS)
+LINK.cc=	$(CXX) $(CXXFLAGS) $(LDFLAGS)
+
+## Shared library options
+## HPUX PA-risc does not recognize -Bprotected_def aC++ option.
+## Use linker option -Wl,-B,symbolic instead.
+ifeq ($(shell uname -m),ia64)
+    LD_SOOPTIONS= -Bprotected_def
+else
+    LD_SOOPTIONS= -Wl,-B,symbolic
+endif
+
+## Commands to make a shared library
+#SHLIB.c=	$(LD) $(LDFLAGS) -b
+SHLIB.c=	$(CXX) $(CXXFLAGS) $(LDFLAGS) -b $(LD_SOOPTIONS)
+SHLIB.cc=	$(CXX) $(CXXFLAGS) $(LDFLAGS) -b $(LD_SOOPTIONS)
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=	-Wl,+b,
+LD_RPATH_PRE= 	
+
+## Environment variable to set a runtime search path
+LDLIBRARYPATH_ENVVAR = SHLIB_PATH
+
+## Compiler switch to embed a library name
+LD_SONAME = -Wl,+h,$(notdir $(MIDDLE_SO_TARGET))
+
+## The type of assembly needed when pkgdata is used for generating shared libraries.
+# Commented out for now because the hp1 test machine runs out of memory.
+#GENCCODE_ASSEMBLY=-a aCC-parisc
+
+## Shared object suffix
+SO=		sl
+## Non-shared intermediate object suffix
+STATIC_O = o
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+%.d : $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+	@$(GEN_DEPS.c) $< > $@
+
+%.d : $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+	@$(GEN_DEPS.cc) $< > $@
+
+## Versioned libraries rules
+
+%.$(SO).$(SO_TARGET_VERSION_MAJOR): %.$(SO).$(SO_TARGET_VERSION)
+	$(RM) $@ && ln -s ${<F} $@
+%.$(SO): %.$(SO).$(SO_TARGET_VERSION_MAJOR)
+	$(RM) $@ && ln -s ${*F}.$(SO).$(SO_TARGET_VERSION) $@
+
+## Install libraries as executable
+INSTALL-L=$(INSTALL_PROGRAM)
+
+## Remove shared library 's'
+STATIC_PREFIX_WHEN_USED = 
+STATIC_PREFIX = 
+
+## End HP/UX-specific setup
diff --git a/source/config/mh-hpux-gcc b/source/config/mh-hpux-gcc
new file mode 100644
index 0000000..72967f1
--- /dev/null
+++ b/source/config/mh-hpux-gcc
@@ -0,0 +1,86 @@
+## -*-makefile-*-
+## HPUX/gcc specific setup
+## Copyright (c) 1999-2009, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+## Commands to generate dependency files
+GEN_DEPS.c=	$(CC) -E -MM $(DEFS) $(CPPFLAGS)
+GEN_DEPS.cc=	$(CXX) -E -MM $(DEFS) $(CPPFLAGS)
+
+## Flags for position independent code
+SHAREDLIBCFLAGS = -fPIC
+SHAREDLIBCXXFLAGS = -fPIC
+SHAREDLIBCPPFLAGS = -DPIC
+
+## Common 'default' path to ensure the sanity of users.  Search the current
+## directory, at least.
+LD_DEFAULTPATH= -Wl,+b,.:'$$'ORIGIN/
+
+# Get some handy functions defined properly
+DEFS += -D_HPUX_SOURCE -D_POSIX_C_SOURCE=199506L
+
+## Commands to link
+## For aCC, use the C++ linker so that __shlinit gets defined
+LINK.c=     $(CXX) $(DEFS) $(LDFLAGS) -Wl,+s $(LD_DEFAULTPATH)
+LINK.cc=    $(CXX) $(DEFS) $(LDFLAGS) -Wl,+s $(LD_DEFAULTPATH)
+
+## Shared library options
+LD_SOOPTIONS= -Wl,-Bsymbolic
+
+## Commands to make a shared library
+SHLIB.c=  $(CC) $(DEFS) $(CFLAGS) $(LDFLAGS) $(SHAREDLIBCXXFLAGS) -shared -Wl,+s $(LD_DEFAULTPATH) $(LD_SOOPTIONS)
+SHLIB.cc= $(CXX) $(DEFS) $(CXXFLAGS) $(LDFLAGS) $(SHAREDLIBCXXFLAGS) -shared -Wl,+s $(LD_DEFAULTPATH) $(LD_SOOPTIONS)
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=   -Wl,+b,
+LD_RPATH_PRE=
+
+## Compiler switch to embed a library name
+LD_SONAME = -Wl,+h,$(notdir $(MIDDLE_SO_TARGET))
+
+## Environment variable to set a runtime search path
+LDLIBRARYPATH_ENVVAR = SHLIB_PATH
+
+## Shared object suffix
+SO=		sl
+## Non-shared intermediate object suffix
+STATIC_O = o
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+%.d : $(srcdir)/%.c
+	@echo "Generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.c) $< \
+		| sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \
+		[ -s $@ ] || rm -f $@'
+
+%.d : $(srcdir)/%.cpp
+	@echo "Generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.cc) $< \
+		| sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \
+		[ -s $@ ] || rm -f $@'
+
+## Versioned libraries rules
+
+%.$(SO).$(SO_TARGET_VERSION_MAJOR): %.$(SO).$(SO_TARGET_VERSION)
+	$(RM) $@ && ln -s ${<F} $@
+%.$(SO): %.$(SO).$(SO_TARGET_VERSION_MAJOR)
+	$(RM) $@ && ln -s ${*F}.$(SO).$(SO_TARGET_VERSION) $@
+
+## Remove shared library 's'
+STATIC_PREFIX_WHEN_USED = 
+STATIC_PREFIX = 
+
+## End HPUX/gcc specific setup
+
diff --git a/source/config/mh-irix b/source/config/mh-irix
new file mode 100644
index 0000000..59d4aaf
--- /dev/null
+++ b/source/config/mh-irix
@@ -0,0 +1,74 @@
+## -*-makefile-*-
+## IRIX-specific setup (for CC)
+## Copyright (c) 1999-2006, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+## Flags for position independent code
+SHAREDLIBCFLAGS = -shared
+SHAREDLIBCXXFLAGS = -shared
+SHAREDLIBCPPFLAGS =
+
+## Commands to generate dependency files
+GEN_DEPS.c=	$(CC) -E -M $(DEFS) $(CPPFLAGS)
+GEN_DEPS.cc=	$(CXX) -E -M $(DEFS) $(CPPFLAGS)
+
+## Commands to link
+## We need to use the C++ linker, even when linking C programs, since
+##  our libraries contain C++ code (C++ static init not called)
+#LINK.c=	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
+LINK.c=		$(CXX) $(DEFS) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS)
+LINK.cc=	$(CXX) $(DEFS) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS)
+
+## Commands to make a shared library
+SHLIB.c=    $(CC) -shared $(DEFS) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS)
+SHLIB.cc=   $(CXX) -shared $(DEFS) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS)
+
+## Additional flags when building libraries with thread safety
+THREADSCPPFLAGS = -D_REENTRANT -D_PTHREADS
+LIBCPPFLAGS =
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=
+LD_RPATH_PRE=  -Wl,-rpath,
+
+## Compiler switch to embed a library name
+LD_SONAME = -Wl,-soname -Wl,$(notdir $(MIDDLE_SO_TARGET))
+
+## Shared object suffix
+SO=		so
+## Non-shared intermediate object suffix
+STATIC_O = ao
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+%.d : $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.c) $< \
+		| sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \
+		[ -s $@ ] || rm -f $@'
+
+%.d : $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.cc) $< \
+		| sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \
+		[ -s $@ ] || rm -f $@'
+
+## Versioned libraries rules
+
+%.$(SO).$(SO_TARGET_VERSION_MAJOR): %.$(SO).$(SO_TARGET_VERSION)
+	$(RM) $@ && ln -s ${<F} $@
+%.$(SO): %.$(SO).$(SO_TARGET_VERSION_MAJOR)
+	$(RM) $@ && ln -s ${*F}.$(SO).$(SO_TARGET_VERSION) $@
+
+## End IRIX-specific setup
diff --git a/source/config/mh-linux b/source/config/mh-linux
new file mode 100644
index 0000000..6a8299f
--- /dev/null
+++ b/source/config/mh-linux
@@ -0,0 +1,85 @@
+## -*-makefile-*-
+## Linux-specific setup
+## Copyright (c) 1999-2010, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+## Commands to generate dependency files
+GEN_DEPS.c=  $(CC) -E -MM $(DEFS) $(CPPFLAGS)
+GEN_DEPS.cc= $(CXX) -E -MM $(DEFS) $(CPPFLAGS)
+
+## Flags for position independent code
+SHAREDLIBCFLAGS = -fPIC
+SHAREDLIBCXXFLAGS = -fPIC
+SHAREDLIBCPPFLAGS = -DPIC
+
+## Additional flags when building libraries and with threads
+THREADSCPPFLAGS = -D_REENTRANT
+LIBCPPFLAGS =
+
+## Compiler switch to embed a runtime search path
+LD_RPATH= -Wl,-zorigin,-rpath,'$$'ORIGIN 
+LD_RPATH_PRE = -Wl,-rpath,
+
+## These are the library specific LDFLAGS
+LDFLAGSICUDT=-nodefaultlibs -nostdlib
+
+## Compiler switch to embed a library name
+# The initial tab in the next line is to prevent icu-config from reading it.
+	LD_SONAME = -Wl,-soname -Wl,$(notdir $(MIDDLE_SO_TARGET))
+#SH# # We can't depend on MIDDLE_SO_TARGET being set.
+#SH# LD_SONAME=
+
+## Shared library options
+LD_SOOPTIONS= -Wl,-Bsymbolic
+
+## Shared object suffix
+SO = so
+## Non-shared intermediate object suffix
+STATIC_O = ao
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+%.d: $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.c) $< \
+		| sed '\''s%\($*\)\.o[ :]*%\1.o $@ : %g'\'' > $@; \
+		[ -s $@ ] || rm -f $@'
+
+%.d: $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.cc) $< \
+		| sed '\''s%\($*\)\.o[ :]*%\1.o $@ : %g'\'' > $@; \
+		[ -s $@ ] || rm -f $@'
+
+## Versioned libraries rules
+
+%.$(SO).$(SO_TARGET_VERSION_MAJOR): %.$(SO).$(SO_TARGET_VERSION)
+	$(RM) $@ && ln -s ${<F} $@
+%.$(SO): %.$(SO).$(SO_TARGET_VERSION_MAJOR)
+	$(RM) $@ && ln -s ${*F}.$(SO).$(SO_TARGET_VERSION) $@
+
+##  Bind internal references
+
+# LDflags that pkgdata will use
+BIR_LDFLAGS= -Wl,-Bsymbolic
+
+# Dependencies [i.e. map files] for the final library
+BIR_DEPS=
+
+## Remove shared library 's'
+STATIC_PREFIX_WHEN_USED = 
+STATIC_PREFIX = 
+
+## End Linux-specific setup
+
diff --git a/source/config/mh-linux-va b/source/config/mh-linux-va
new file mode 100644
index 0000000..7bee921
--- /dev/null
+++ b/source/config/mh-linux-va
@@ -0,0 +1,77 @@
+## -*-makefile-*-
+## Linux-specific setup for Visual Age
+## Copyright (c) 2003-2010, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+## Commands to generate dependency files
+GEN_DEPS.c=  $(CC) -E -MM $(DEFS) $(CPPFLAGS)
+GEN_DEPS.cc= $(CXX) -E -MM $(DEFS) $(CPPFLAGS)
+
+# -qroconst make the strings readonly, which is usually the default.
+#           This helps in the data library,
+# -qproto assumes all functions are prototyped (for optimization)
+CFLAGS += -qproto -qroconst
+CXXFLAGS += -qproto -qroconst
+
+GENCCODE_ASSEMBLY=-a gcc
+## Flags for position independent code
+SHAREDLIBCFLAGS = -qpic=large
+SHAREDLIBCXXFLAGS = -qpic=large
+SHAREDLIBCPPFLAGS = -DPIC
+
+## Additional flags when building libraries and with threads
+THREADSCPPFLAGS = -D_REENTRANT
+LIBCPPFLAGS =
+
+## Compiler switch to embed a runtime search path
+LD_RPATH= -Wl,-zorigin,-rpath,'$$'ORIGIN 
+#LD_RPATH_PRE = -Wl,-rpath,
+
+## Compiler switch to embed a library name
+# The initial tab in the next line is to prevent icu-config from reading it.
+	LD_SONAME = -Wl,-soname -Wl,$(notdir $(MIDDLE_SO_TARGET))
+#SH# # We can't depend on MIDDLE_SO_TARGET being set.
+#SH# LD_SONAME=
+
+## The type of assembly needed when pkgdata is used for generating shared libraries.
+GENCCODE_ASSEMBLY=-a gcc
+
+## Shared object suffix
+SO = so
+## Non-shared intermediate object suffix
+STATIC_O = ao
+
+## Override the default mechanism for building shared objects
+SHLIB.c=      $(CC)  $(CFLAGS)   -qmkshrobj -qpic=large -G $(LDFLAGS) 
+SHLIB.cc=     $(CXX) $(CXXFLAGS) -qmkshrobj -qpic=large -G $(LDFLAGS)
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+%.d: $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.c) $< > /dev/null'
+
+%.d: $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.cc) $< > /dev/null'
+
+## Versioned libraries rules
+
+%.$(SO).$(SO_TARGET_VERSION_MAJOR): %.$(SO).$(SO_TARGET_VERSION)
+	$(RM) $@ && ln -s ${<F} $@
+%.$(SO): %.$(SO).$(SO_TARGET_VERSION_MAJOR)
+	$(RM) $@ && ln -s ${*F}.$(SO).$(SO_TARGET_VERSION) $@
+
+## End Linux-specific setup
+
diff --git a/source/config/mh-mingw b/source/config/mh-mingw
new file mode 100644
index 0000000..a79e3d7
--- /dev/null
+++ b/source/config/mh-mingw
@@ -0,0 +1,131 @@
+## -*-makefile-*-
+## Cygwin/MinGW specific setup
+## Copyright (c) 2001-2009, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+# TODO: Finish the rest of this port. This platform port is incomplete.
+
+# We install sbin tools into the same bin directory because
+# pkgdata needs some of the tools in sbin, and we can't always depend on
+# icu-config working on Windows.
+sbindir=$(bindir)
+
+## Commands to generate dependency files
+GEN_DEPS.c=	$(CC) -E -MM $(DEFS) $(CPPFLAGS)
+GEN_DEPS.cc=	$(CXX) -E -MM $(DEFS) $(CPPFLAGS)
+
+## Flags to create/use a static library
+ifneq ($(ENABLE_SHARED),YES)
+## Make sure that the static libraries can be built and used
+CPPFLAGS += -DU_STATIC_IMPLEMENTATION
+else
+## Make sure that the static libraries can be built
+STATICCPPFLAGS = -DU_STATIC_IMPLEMENTATION
+endif
+
+## Flags for position independent code
+SHAREDLIBCFLAGS = 
+SHAREDLIBCXXFLAGS = 
+SHAREDLIBCPPFLAGS = -DPIC
+
+## Additional flags when building libraries and with threads
+THREADSCFLAGS = -mthreads
+THREADSCXXFLAGS = -mthreads
+LIBCPPFLAGS =
+
+# Commands to link. Link with C++ in case static libraries are used.
+LINK.c=       $(CXX) $(CXXFLAGS) $(LDFLAGS)
+#LINK.cc=      $(CXX) $(CXXFLAGS) $(LDFLAGS)
+
+## Commands to make a shared library
+SHLIB.c=	$(CC) $(CFLAGS) $(LDFLAGS) -shared
+SHLIB.cc=	$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=	
+LD_RPATH_PRE=	-Wl,-rpath,
+
+## Compiler switch to embed a library name
+LD_SONAME = 
+
+## Shared object suffix
+SO = dll
+## Non-shared intermediate object suffix
+STATIC_O = ao
+SO_TARGET_VERSION_SUFFIX = $(SO_TARGET_VERSION_MAJOR)
+
+# Static library prefix and file extension
+LIBSICU = $(STATIC_PREFIX)$(ICUPREFIX)
+A = lib
+
+## An import library is needed for z/OS and MSVC
+#IMPORT_LIB_EXT = .lib
+
+LIBPREFIX=
+
+# Change the stubnames so that poorly working FAT disks and installation programs can work.
+# This is also for backwards compatibility.
+DATA_STUBNAME = dt
+I18N_STUBNAME = in
+LIBICU = $(STATIC_PREFIX_WHEN_USED)$(ICUPREFIX)
+
+# The #M# is used to delete lines for icu-config
+# Current full path directory.
+#CURR_FULL_DIR=$(shell pwd -W)#M# for MSYS
+CURR_FULL_DIR=$(subst \,/,$(shell cmd /c cd))#M# for Cygwin shell
+# Current full path directory for use in source code in a -D compiler option.
+#CURR_SRCCODE_FULL_DIR=$(subst /,\\\\,$(shell pwd -W))#M# for MSYS
+CURR_SRCCODE_FULL_DIR=$(subst \,/,$(shell cmd /c cd))#M# for Cygwin shell
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+%.d: $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+	@echo -n "$@ " > $@
+	@$(GEN_DEPS.c) $< >> $@ || (rm -f $@ && FALSE)
+
+%.d: $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+	@echo -n "$@ " > $@
+	@$(GEN_DEPS.cc) $< >> $@ || (rm -f $@ && FALSE)
+
+## Versioned target for a shared library.
+## Since symbolic links don't work the same way on Windows,
+## we only use the version major number.
+#FINAL_SO_TARGET=$(basename $(SO_TARGET))$(SO_TARGET_VERSION).$(SO)
+FINAL_SO_TARGET=$(basename $(SO_TARGET))$(SO_TARGET_VERSION_MAJOR).$(SO)
+MIDDLE_SO_TARGET=$(FINAL_SO_TARGET)
+
+## Special pkgdata information that is needed
+PKGDATA_VERSIONING = -r $(SO_TARGET_VERSION_MAJOR)
+#ICUPKGDATA_INSTALL_DIR = $(shell cygpath -dma $(DESTDIR)$(ICUPKGDATA_DIR))#M#
+#ICUPKGDATA_INSTALL_LIBDIR = $(shell cygpath -dma $(DESTDIR)$(libdir))#M#
+
+## Versioned libraries rules
+#%$(SO_TARGET_VERSION_MAJOR).$(SO): %$(SO_TARGET_VERSION).$(SO)
+#	$(RM) $@ && cp ${<F} $@
+%.$(SO): %$(SO_TARGET_VERSION_MAJOR).$(SO)
+	@echo -n
+
+# Environment variable to set a runtime search path
+LDLIBRARYPATH_ENVVAR = PATH
+
+# The type of assembly to write for generating an object file
+GENCCODE_ASSEMBLY=-a gcc-cygwin
+
+# These are needed to allow the pkgdata GNU make files to work
+PKGDATA_DEFS = -DU_MAKE=\"$(MAKE)\"
+
+## End Cygwin/MinGW specific setup
+
diff --git a/source/config/mh-mpras b/source/config/mh-mpras
new file mode 100644
index 0000000..175aff3
--- /dev/null
+++ b/source/config/mh-mpras
@@ -0,0 +1,64 @@
+## -*-makefile-*-
+## MP-RAS specific setup
+## Copyright (c) 2003-2004, International Business Machines Corporation and
+## others. All Rights Reserved.
+##
+## Original contributer: Jason Gordon from NCR
+
+## Flags for position independent code
+SHAREDLIBCFLAGS = -K PIC
+SHAREDLIBCXXFLAGS = -K PIC
+SHAREDLIBCPPFLAGS = -DPIC
+
+## Commands to generate dependency files
+GEN_DEPS.c= $(CC) -Hnocopyr -I/usr/include -Hcpplvl=3 -Xa -Hmake $(DEFS) $(CPPFLAGS)
+GEN_DEPS.cc= $(CXX) -Hnocopyr -I/usr/include -Hcpplvl=3 -Xa -Hmake $(DEFS) $(CPPFLAGS)
+
+## Commands to link
+LINK.c=		$(CC) $(CXXFLAGS) $(LDFLAGS)
+LINK.cc=	$(CXX) $(CXXFLAGS) $(LDFLAGS)
+
+## Commands to make a shared library
+SHLIB.c=	$(CC) $(CFLAGS) $(LDFLAGS) -G
+SHLIB.cc=	$(CXX) $(CXXFLAGS) $(LDFLAGS) -G
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=     -YP,
+LD_RPATH_PRE=	
+
+## Compiler switch to embed a library name
+LD_SONAME = -h $(notdir $(MIDDLE_SO_TARGET))
+
+## Shared object suffix
+SO=		so
+## Non-shared intermediate object suffix
+STATIC_O = o
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+%.d : $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+	@$(GEN_DEPS.c) $< > $@
+
+%.d : $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+	@$(GEN_DEPS.cc) $< > $@
+
+## Versioned libraries rules
+
+%.$(SO).$(SO_TARGET_VERSION_MAJOR): %.$(SO).$(SO_TARGET_VERSION)
+	$(RM) $@ && ln -s ${<F} $@
+%.$(SO): %.$(SO).$(SO_TARGET_VERSION_MAJOR)
+	$(RM) $@ && ln -s ${*F}.$(SO).$(SO_TARGET_VERSION) $@
+
diff --git a/source/config/mh-os390 b/source/config/mh-os390
new file mode 100644
index 0000000..b327092
--- /dev/null
+++ b/source/config/mh-os390
@@ -0,0 +1,228 @@
+## -*-makefile-*-
+## os/390, z/OS specific setup 
+## Copyright (c) 1999-2007, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+###################################################################
+#                    IMPORTANT NOTE                               #
+###################################################################
+# Before you try to run the Makefile, make sure you have the      #
+# environment variables set.                                      #
+#                                                                 #
+# If you are going to do the OS390BATCH build, make sure you have #
+# the OS390BATCH environment variable set.                        #
+#                                                                 #
+#   export OS390BATCH=1                                           #
+#                                                                 #
+# To build a version of ICU that does not use IEEE Floating point #
+#                                                                 #
+#   export IEEE390=0                                              #
+#                                                                 #
+# To build a version of ICU which uses a two data libraries       #
+# where the smaller one is loaded first, use OS390_STUBDATA.      #
+# USAGE OF THIS OPTION IS DEPRECATED. You should look into using  #
+# Link Pack Area (LPA), library lookaside facility (LLA) or other #
+# z/OS options that enable page fault based loading of read-only  #
+# code/data instead of this option.                               #
+# This option will be removed in a future version of ICU.         #
+#                                                                 #
+#   export OS390_STUBDATA=1                                       #
+#                                                                 #
+# To build a version of ICU which exploits the C/C++ compiler     #
+# and runtime Extra Performance Linkage (XPLINK), specify         #
+#                                                                 #
+#   export OS390_XPLINK=1                                         #
+#                                                                 #
+###################################################################
+
+# TODO: Fix this configuration so that icu-config will work!
+#       If statements don't work well when icu-config is generated.
+ifeq (${IEEE390},)
+IEEE390=1#M#
+endif
+
+ifeq (${IEEE390}, 1)
+ICU_IEEE          = -Wc,'float(ieee)'
+else
+ICU_IEEE          = -DIEEE_754=0#M#
+endif
+
+## Additional flags when building libraries and with threads
+THREADSCPPFLAGS = -D_OPEN_THREADS
+
+# For a dynamically called DLL module to share access to the POSIX external
+# variables, with its caller, the DLL module must define these _SHR_* macros.
+SHAREDLIBCPPFLAGS	= -D_SHR_TZNAME -D_SHR_TIMEZONE
+
+# -Wc,expo is used to export all functions
+SHAREDLIBCFLAGS	= -Wc,expo
+SHAREDLIBCXXFLAGS	= -Wc,expo
+
+# TODO: Consider using  -Wc,roc,ros for making the data and strings readonly
+#       -Wc,"ros" seems to work, but not the "roc"
+# The RENT option makes the program reentrant. This may not really have the same
+#       meaning as normal reentrancy on other platforms. See the z/OS documentation
+#       for details. This is the default for C++, but not C.
+# The DLL option must be used by the callee and caller code when using shared libraries.
+# NOCSECT might be used as an optimization option.
+# -+ means accept any file extension as a C++ file. By default only .C is accepted.
+CFLAGS          += -Wc,'langlvl(extended),ros,rent,dll' $(ICU_IEEE)
+CXXFLAGS        += -Wc,'langlvl(extended),ros,dll' $(ICU_IEEE) -+
+ARFLAGS         = -cr
+
+# _MSE_PROTOS usually interacts with _XOPEN_SOURCE. It affects some standard
+# C functions that use wchar_t, and it selects behavior for
+# multibyte extension support (MSE) functions.
+#DEFS            += -D_MSE_PROTOS
+
+ifeq (${OS390_XPLINK}, 1)
+#SH# if [ "x$OS390_XPLINK" = "x1" ]; then
+# These lines must be the last options specified.
+# GOFF is is the strategic object module format for S/390. It is required for XPLINK.
+# NOTEMPINC could be used if ICU starts using templates.
+ICU_XPLINK_C      = -Wc,'xplink(backchain,storeargs),goff'
+ICU_XPLINK_CXX    = -Wc,'xplink(backchain,storeargs),goff'
+ICU_XPLINK_L      = -Wl,xplink
+#SH# fi
+endif
+
+## OS390BATCH
+ifeq (${OS390BATCH},1)
+DEFS            += -DOS390BATCH#M#
+endif
+
+## Commands to generate dependency files
+GEN_DEPS.c=	makedep                        
+GEN_DEPS.cc=	makedep
+
+## Commands to compile
+# _CXX_STEPS="-1" is a prelink step when compiling C and C++, and
+# it's only needed for long function names
+COMPILE.c       = $(COMPILE_LINK_ENVVAR) $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) $(ICU_XPLINK_C) -c
+COMPILE.cc      = $(COMPILE_LINK_ENVVAR) $(CXX) $(DEFS) $(CPPFLAGS) $(CXXFLAGS) $(ICU_XPLINK_CXX) -c
+
+# Commands to link
+LINK.c=		$(COMPILE_LINK_ENVVAR) $(CC) $(CFLAGS) -Wl,dll $(LDFLAGS) $(ICU_XPLINK_L)
+LINK.cc=	$(COMPILE_LINK_ENVVAR) $(CXX) $(CXXFLAGS) -Wl,dll $(LDFLAGS) $(ICU_XPLINK_L)
+
+## Commands for shared library (dll)
+SHLIB.c=	$(LINK.c)
+SHLIB.cc=	$(LINK.cc)
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=	-I
+
+## Environment variable to set a runtime search path
+LDLIBRARYPATH_ENVVAR = LIBPATH
+
+## An import library (a.k.a. sidedeck) is needed for z/OS and MSVC
+IMPORT_LIB_EXT = .x
+
+## Versioned target for a shared library.
+FINAL_SO_TARGET=  $(basename $(SO_TARGET))$(SO_TARGET_VERSION).$(SO)
+MIDDLE_SO_TARGET= $(basename $(SO_TARGET))$(SO_TARGET_VERSION_MAJOR).$(SO)
+
+## Versioned import library names.
+IMPORT_LIB = $(basename $(notdir $(SO_TARGET)))$(IMPORT_LIB_EXT)#M#
+MIDDLE_IMPORT_LIB = $(basename $(notdir $(MIDDLE_SO_TARGET)))$(IMPORT_LIB_EXT)#M#
+FINAL_IMPORT_LIB = $(basename $(notdir $(FINAL_SO_TARGET)))$(IMPORT_LIB_EXT)#M#
+
+## Non-shared intermediate object suffix
+STATIC_O = o
+
+ifeq ($(OS390_STUBDATA),1)
+## Suffix of the subset data library for dual common library support
+STUB_SUFFIX=_stub#M#
+DEFS      += -DOS390_STUBDATA -DU_LIBICUDATA_NAME=\"$(ICUPREFIX)$(DATA_STUBNAME)$(ICULIBSUFFIX)\"#M#
+endif
+
+ifeq ($(OS390BATCH),1)
+ifeq ($(OS390_STUBDATA),1)
+BATCH_STUB_TARGET=	"//'${LOADMOD}(IXMI${SO_TARGET_VERSION_MAJOR}D1)'"
+BATCH_LIBICUDT=		"//'${LOADEXP}(IXMI${SO_TARGET_VERSION_MAJOR}D1)'"
+else
+BATCH_STUB_TARGET=	"//'${LOADMOD}(IXMI${SO_TARGET_VERSION_MAJOR}DA)'"
+BATCH_LIBICUDT=		"//'${LOADEXP}(IXMI${SO_TARGET_VERSION_MAJOR}DA)'"
+PKGDATA_DEFS        += -DU_LIBICUDATA_NAME=\"$(ICUPREFIX)$(DATA_STUBNAME)$(ICULIBSUFFIX)\"
+endif
+
+BATCH_COMMON_TARGET="//'${LOADMOD}(IXMI${SO_TARGET_VERSION_MAJOR}UC)'"
+BATCH_I18N_TARGET="//'${LOADMOD}(IXMI${SO_TARGET_VERSION_MAJOR}IN)'"
+BATCH_IO_TARGET="//'${LOADMOD}(IXMI${SO_TARGET_VERSION_MAJOR}IO)'"
+BATCH_LAYOUT_TARGET="//'${LOADMOD}(IXMI${SO_TARGET_VERSION_MAJOR}LE)'"
+BATCH_LAYOUTEX_TARGET="//'${LOADMOD}(IXMI${SO_TARGET_VERSION_MAJOR}LX)'"
+
+BATCH_LIBICUUC=		"//'${LOADEXP}(IXMI${SO_TARGET_VERSION_MAJOR}UC)'"
+BATCH_LIBICUI18N=	"//'${LOADEXP}(IXMI${SO_TARGET_VERSION_MAJOR}IN)'"
+BATCH_LIBICUIO=		"//'${LOADEXP}(IXMI${SO_TARGET_VERSION_MAJOR}IO)'"
+BATCH_LIBICULE=		"//'${LOADEXP}(IXMI${SO_TARGET_VERSION_MAJOR}LE)'"
+BATCH_LIBICULX=		"//'${LOADEXP}(IXMI${SO_TARGET_VERSION_MAJOR}LX)'"
+endif
+
+## Link commands to link to ICU libs
+LIBICUDT=	$(top_builddir)/stubdata/$(LIBICU)data$(ICULIBSUFFIX)$(STUB_SUFFIX)$(SO_TARGET_VERSION).x
+LIBICUUC=	$(top_builddir)/common/$(LIBICU)uc$(ICULIBSUFFIX)$(SO_TARGET_VERSION).x
+LIBICUI18N=	$(top_builddir)/i18n/$(LIBICU)i18n$(ICULIBSUFFIX)$(SO_TARGET_VERSION).x
+LIBICULE=	$(top_builddir)/layout/$(LIBICU)le$(ICULIBSUFFIX)$(SO_TARGET_VERSION).x
+LIBICULX=	$(top_builddir)/layoutex/$(LIBICU)lx$(ICULIBSUFFIX)$(SO_TARGET_VERSION).x
+LIBICUIO=	$(top_builddir)/io/$(LIBICU)io$(ICULIBSUFFIX)$(SO_TARGET_VERSION).x
+LIBCTESTFW=	$(top_builddir)/tools/ctestfw/$(LIBICU)test$(ICULIBSUFFIX)$(SO_TARGET_VERSION).x
+LIBICUTOOLUTIL=	$(top_builddir)/tools/toolutil/$(LIBICU)tu$(ICULIBSUFFIX)$(SO_TARGET_VERSION).x
+
+ifneq (${ICUDATA_CHAR},e)
+#SH# if [ "$ICUDATA_CHAR" != "e" ]; then
+## We're in ASCII mode.
+CFLAGS		+= -Wc,'ascii'
+CXXFLAGS	+= -Wc,'ascii'
+SO = so
+else
+#SH# else
+## We're in EBCDIC mode.
+## Shared object suffix
+SO = dll
+endif
+#SH# fi
+
+## Special 390 rules
+
+## Build archive from object
+%.a : $(OBJECTS)
+	$(AR) $(ARFLAGS) $@ $(OBJECTS)
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+## Dependency rules
+%.d : %.u
+	@$(SHELL) -ec 'cat $<  \
+		| sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \
+		[ -s $@ ] || rm -f $@ ; rm -f $<'
+
+%.u : $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec 'touch            $*.u  > /dev/null 2>&1'
+	@$(SHELL) -ec '$(GEN_DEPS.c) -f $*.u $< > /dev/null 2>&1'
+
+%.u : $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec 'touch              $*.u  > /dev/null 2>&1'
+	@$(SHELL) -ec '$(GEN_DEPS.cc)  -f $*.u $< > /dev/null 2>&1'
+
+## Versioned libraries rules
+%$(SO_TARGET_VERSION_MAJOR).$(SO): %$(SO_TARGET_VERSION).$(SO)
+	$(RM) $@ && ln -s ${*F}$(SO_TARGET_VERSION).$(SO) $@
+%.$(SO): %$(SO_TARGET_VERSION).$(SO)
+	$(RM) $@ && ln -s ${*F}$(SO_TARGET_VERSION).$(SO) $@
+
+## Install libraries as executable
+INSTALL-L=$(INSTALL_PROGRAM)
+
+## End 390-specific setup
diff --git a/source/config/mh-os400 b/source/config/mh-os400
new file mode 100644
index 0000000..b4a8e09
--- /dev/null
+++ b/source/config/mh-os400
@@ -0,0 +1,129 @@
+## -*-makefile-*-
+## OS400-specific setup (for cross build)
+## Copyright (c) 1999-2005, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+GEN_DEPS.c=	$(CC1) -E -M $(DEFS) $(CPPFLAGS)
+GEN_DEPS.cc=	$(CXX1) -E -M $(DEFS) $(CPPFLAGS)
+
+THREADSCPPFLAGS = -D_MULTI_THREADED
+
+## Commands to compile
+# -qTERASPACE: large pointers
+# -qPFROPT=*STRDONLY: Strings are read-only
+COMPILE.c=	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -qTERASPACE=*YES -qSTGMDL=*INHERIT -qPFROPT=*STRDONLY
+COMPILE.cc=	$(CXX) $(DEFS) $(CPPFLAGS) $(CXXFLAGS) -c -qTERASPACE=*YES -qSTGMDL=*INHERIT -qPFROPT=*STRDONLY
+
+## Commands to link
+## We need to use the C++ linker, even when linking C programs, since
+##  our libraries contain C++ code (C++ static init not called)
+LINK.c=		$(CXX) $(CXXFLAGS) $(LDFLAGS) -qOPTION='*DUPPROC *DUPVAR'
+LINK.cc=	$(CXX) $(CXXFLAGS) $(LDFLAGS) -qOPTION='*DUPPROC *DUPVAR'
+
+## Commands to make a shared library
+# -qALWLIBUPD: It allows the compiled service program to have dependencies on
+#	service programs in a different library than that specified originally
+#	by CRTSRVPGM after having used the UPDSRVPGM command.
+#	Similar to -fPIC and -install_name on other compilers, but different.
+SHLIB.c=   ld -v -qOPTION='*DUPPROC *DUPVAR' -qALWLIBUPD=*YES
+SHLIB.cc=	 ld -v -qOPTION='*DUPPROC *DUPVAR' -qALWLIBUPD=*YES
+AR = qar
+ARFLAGS = -cuv
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=	-I
+LD_RPATH_PRE=	-I
+
+## Make target to rebind the common library
+## to the actual data versus the stub data
+POST_DATA_BUILD = os400-data-rebind
+
+# The stubdata directory is the same directory as the normal data library.
+STUBDATA_LIBDIR = $(LIBDIR)/
+
+## Versioned target for a shared library.
+FINAL_SO_TARGET = $(SO_TARGET)
+MIDDLE_SO_TARGET = 
+
+# this one is for icudefs.mk's use
+ifeq ($(ENABLE_SHARED),YES)
+SO_TARGET_VERSION_SUFFIX = $(SO_TARGET_VERSION_MAJOR)
+endif
+
+# this one is for the individual make files and linking
+ICULIBSUFFIX = $(SO_TARGET_VERSION_SUFFIX)
+
+##  object suffix
+TO=		o
+
+## Shared object suffix
+SO=	so
+## Non-shared intermediate object suffix
+STATIC_O = o
+
+## Platform command to remove or move executable target
+RMV = del
+## Platform commands to remove or move executable and library targets
+INSTALL-S =  cp -fph
+INSTALL-L = $(INSTALL-S)
+
+# Stub name overrides for iSeries
+DATA_STUBNAME = dt
+I18N_STUBNAME = in
+CTESTFW_STUBNAME = tf
+
+## Link commands to link to ICU service programs
+LIBICUDT = $(LIBDIR)/$(LIBICU)$(DATA_STUBNAME)$(ICULIBSUFFIX).$(SO)
+LIBICUUC = $(LIBDIR)/$(LIBICU)$(COMMON_STUBNAME)$(ICULIBSUFFIX).$(SO)
+LIBICUI18N = $(LIBDIR)/$(LIBICU)$(I18N_STUBNAME)$(ICULIBSUFFIX).$(SO)
+LIBICULE = $(LIBDIR)/$(LIBICU)$(LAYOUT_STUBNAME)$(ICULIBSUFFIX).$(SO)
+LIBICULX = $(LIBDIR)/$(LIBICU)$(LAYOUTEX_STUBNAME)$(ICULIBSUFFIX).$(SO)
+LIBCTESTFW = $(top_builddir)/tools/ctestfw/$(LIBICU)$(CTESTFW_STUBNAME)$(ICULIBSUFFIX).$(SO)
+LIBICUTOOLUTIL = $(LIBDIR)/$(LIBICU)$(TOOLUTIL_STUBNAME)$(ICULIBSUFFIX).$(SO)
+LIBICUIO= $(LIBDIR)/$(LIBICU)$(IO_STUBNAME)$(ICULIBSUFFIX).$(SO)
+
+## Special OS400 rules
+
+## Build archive from shared object
+%.a : %.o
+	$(AR) $(ARFLAGS) $@ $<
+
+## Build import list from export list
+%.e : %.exp
+	@echo "Building an import list for $<"
+	@$(SHELL) -ec "echo '#! $*.a($*.so)' | cat - $< > $@"
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+%.qwobj : $(srcdir)/%.c
+	$(COMPILE.c) -o $@ $<
+
+%.qwobj : $(srcdir)/%.cpp
+	$(COMPILE.cc) -o $@ $<
+
+## Dependency rules
+%.d : %.u
+#	@$(SHELL) -ec 'cat $<  \
+#		| sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \
+#		[ -s $@ ] || rm -f $@ ; rm -f $<'
+
+%.u : $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+#	@$(SHELL) -ec 'touch            $*.u  > /dev/null 2>&1'
+#	@$(SHELL) -ec '$(GEN_DEPS.c) -f $*.u $< > /dev/null 2>&1'
+
+%.u : $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+#	@$(SHELL) -ec 'touch              $*.u  > /dev/null 2>&1'
+#	@$(SHELL) -ec '$(GEN_DEPS.cc)  -f $*.u $< > /dev/null 2>&1'
+
+## End OS400-specific setup
diff --git a/source/config/mh-qnx b/source/config/mh-qnx
new file mode 100644
index 0000000..3d2b350
--- /dev/null
+++ b/source/config/mh-qnx
@@ -0,0 +1,92 @@
+## -*-makefile-*-
+## QNX-specific setup
+## Copyright (c) 1999-2006, International Business Machines Corporation and
+## others. All Rights Reserved.
+##
+## Provided By: Chris McKillop <cdm@qnx.com>
+
+
+#
+# Create shared libs that "work" properly.
+#
+
+## Commands to generate dependency files
+GEN_DEPS.c=  $(CC) -E -Wp,-MM $(DEFS) $(CPPFLAGS)
+GEN_DEPS.cc= $(CXX) -E -Wp,-MM $(DEFS) $(CPPFLAGS)
+
+## Flags for position independent code
+SHAREDLIBCFLAGS = -shared
+SHAREDLIBCXXFLAGS = -shared
+# SHAREDLIBCPPFLAGS = -shared
+
+#
+# Always generatate PIC code.
+#
+#CPPFLAGS+=-shared
+
+## Additional flags when building libraries and with threads
+LIBCPPFLAGS = 
+THREADSCPPFLAGS = 
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=	
+LD_RPATH_PRE = -Wl,-rpath,
+
+## Compiler switch to embed a library name
+LD_SONAME = -Wl,-soname -Wl,$(notdir $(MIDDLE_SO_TARGET))
+
+## Shared object suffix
+SO = so
+## Non-shared intermediate object suffix
+STATIC_O = ao
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+%.d: $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.c) $< \
+		| sed '\''s%\($*\)\.o[ :]*%\1.o $@ : %g'\'' > $@; \
+		[ -s $@ ] || rm -f $@'
+
+%.d: $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.cc) $< \
+		| sed '\''s%\($*\)\.o[ :]*%\1.o $@ : %g'\'' > $@; \
+		[ -s $@ ] || rm -f $@'
+
+## Versioned libraries rules
+##
+## QNX wants the SONAME in the shared lib to match the final "real" filename.
+## (to ease in packaging with QNX's native package format)
+##
+MIDDLE_SO_TARGET = $(SO_TARGET).$(SO_TARGET_VERSION_MAJOR)
+FINAL_SO_TARGET = $(MIDDLE_SO_TARGET)
+
+%.$(SO): %.$(SO).$(SO_TARGET_VERSION_MAJOR)
+	$(RM) $@ && ln -s ${*F}.$(SO).$(SO_TARGET_VERSION_MAJOR) $@
+#%.$(SO).$(SO_TARGET_VERSION_MAJOR): %.$(SO).$(SO_TARGET_VERSION)
+#	$(RM) $@ && ln -s ${<F} $@
+#%.$(SO): %.$(SO).$(SO_TARGET_VERSION_MAJOR)
+#	$(RM) $@ && ln -s ${*F}.$(SO).$(SO_TARGET_VERSION) $@
+
+##  Bind internal references
+
+# LDflags that pkgdata will use
+BIR_LDFLAGS= -Wl,-Bsymbolic
+
+# Dependencies [i.e. map files] for the final library
+BIR_DEPS=
+
+## End QNX-specific setup
+
diff --git a/source/config/mh-solaris b/source/config/mh-solaris
new file mode 100644
index 0000000..4b969b5
--- /dev/null
+++ b/source/config/mh-solaris
@@ -0,0 +1,98 @@
+## -*-makefile-*-
+## Solaris-specific setup using Sun's compilers
+## Copyright (c) 1999-2010, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+## Flags for position independent code
+SHAREDLIBCFLAGS = -KPIC
+SHAREDLIBCXXFLAGS = -KPIC
+SHAREDLIBCPPFLAGS = -DPIC
+
+## Commands to generate dependency files
+GEN_DEPS.c=  $(CC) -xM $(DEFS) $(CPPFLAGS)
+GEN_DEPS.cc= $(CXX) -xM $(DEFS) $(CPPFLAGS)
+
+ifeq ($(UCLN_NO_AUTO_CLEANUP),0)
+# set up init point.
+UCLN_FINI =  ucln_fini$(TARGET_STUBNAME)_$(SO_TARGET_VERSION_MAJOR)$(ICULIBSUFFIXCNAME)
+CPPFLAGS_FINI = -DUCLN_FINI=$(UCLN_FINI)
+LDFLAGS_FINI = -zfiniarray=$(UCLN_FINI)
+
+CPPFLAGSICUUC += $(CPPFLAGS_FINI)
+LDFLAGSICUUC += $(LDFLAGS_FINI)
+CPPFLAGSICUIO += $(CPPFLAGS_FINI)
+LDFLAGSICUIO += $(LDFLAGS_FINI)
+CPPFLAGSICUI18N += $(CPPFLAGS_FINI)
+LDFLAGSICUI18N += $(LDFLAGS_FINI)
+CPPFLAGSCTESTFW += $(CPPFLAGS_FINI)
+LDFLAGSCTESTFW += $(LDFLAGS_FINI)
+
+# ICUUC, ICUIO, ICUI18N, CTESTFW
+endif
+
+# -mt means 'compiles and links a multithreaded program'
+THREADSCFLAGS += -mt
+THREADSCXXFLAGS += -mt
+
+## Commands to link
+## For Sun Workshop, use CC to link to bring in C++ runtime
+LINK.c=		$(CXX) $(CXXFLAGS) $(LDFLAGS)
+LINK.cc=	$(CXX) $(CXXFLAGS) $(LDFLAGS)
+
+## Commands to make a shared library
+SHLIB.c=	$(CC) $(CFLAGS) $(LDFLAGS) -G
+SHLIB.cc=	$(CXX) $(CXXFLAGS) $(LDFLAGS) -G
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=       -R'$$'ORIGIN 
+LD_RPATH_PRE=   -R
+
+#LIBRARY_PATH_PREFIX=/usr/lib/lwp:
+
+## Compiler switch to embed a library name
+LD_SONAME = -h $(notdir $(MIDDLE_SO_TARGET))
+
+## Shared object suffix
+SO=		so
+## Non-shared intermediate object suffix
+STATIC_O = o
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+%.d : $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+	@$(GEN_DEPS.c) $< > $@
+
+%.d : $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+	@$(GEN_DEPS.cc) $< > $@
+
+## Versioned libraries rules
+
+%.$(SO).$(SO_TARGET_VERSION_MAJOR): %.$(SO).$(SO_TARGET_VERSION)
+	$(RM) $@ && ln -s ${<F} $@
+%.$(SO): %.$(SO).$(SO_TARGET_VERSION_MAJOR)
+	$(RM) $@ && ln -s ${*F}.$(SO).$(SO_TARGET_VERSION) $@
+
+# 
+ifeq (strip $(GENCCODE_ASSEMBLY),)
+BIR_LDFLAGS=  -Wl,-M,$(NAME).map -Wl,-B,symbolic -Wl,-B,eliminate
+BIR_DEPS=   $(NAME).map
+endif
+
+## Remove shared library 's'
+STATIC_PREFIX_WHEN_USED = 
+STATIC_PREFIX = 
+
+## End Solaris-specific setup
diff --git a/source/config/mh-solaris-gcc b/source/config/mh-solaris-gcc
new file mode 100644
index 0000000..ee9ba75
--- /dev/null
+++ b/source/config/mh-solaris-gcc
@@ -0,0 +1,78 @@
+## -*-makefile-*-
+## Solaris-specific setup using gcc
+## Copyright (c) 1999-2010, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+## Flags for position independent code
+SHAREDLIBCFLAGS = -fPIC
+SHAREDLIBCXXFLAGS = -fPIC
+SHAREDLIBCPPFLAGS = -DPIC
+
+## Commands to generate dependency files
+GEN_DEPS.c= 	$(CC) -E -MM $(DEFS) $(CPPFLAGS)
+GEN_DEPS.cc=	$(CXX) -E -MM $(DEFS) $(CPPFLAGS)
+
+## These are the library specific LDFLAGS
+LDFLAGSICUDT=-nodefaultlibs -nostdlib
+
+## Additional flags when building libraries and with threads
+THREADSCPPFLAGS = -D_REENTRANT
+
+## Compiler switch to embed a runtime search path
+LD_RPATH=       -R'$$'ORIGIN 
+LD_RPATH_PRE=   -R
+
+## Compiler switch to embed a library name
+LD_SONAME = -h $(notdir $(MIDDLE_SO_TARGET))
+
+## Shared library options
+LD_SOOPTIONS= -Wl,-Bsymbolic
+
+## The type of assembly needed when pkgdata is used for generating shared libraries.
+## Only use this when not on x86 Solaris.
+ifeq (strip $(GENCCODE_ASSEMBLY),)
+GENCCODE_ASSEMBLY=-a sun
+endif
+
+## Shared object suffix
+SO=		so
+## Non-shared intermediate object suffix
+STATIC_O = ao
+
+## Compilation rules
+%.$(STATIC_O): $(srcdir)/%.c
+	$(COMPILE.c) $(STATICCPPFLAGS) $(STATICCFLAGS) -o $@ $<
+%.o: $(srcdir)/%.c
+	$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCFLAGS) -o $@ $<
+
+%.$(STATIC_O): $(srcdir)/%.cpp
+	$(COMPILE.cc) $(STATICCPPFLAGS) $(STATICCXXFLAGS) -o $@ $<
+%.o: $(srcdir)/%.cpp
+	$(COMPILE.cc) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $<
+
+
+## Dependency rules
+%.d : $(srcdir)/%.c
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.c) $< \
+		| sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \
+		[ -s $@ ] || rm -f $@'
+
+%.d : $(srcdir)/%.cpp
+	@echo "generating dependency information for $<"
+	@$(SHELL) -ec '$(GEN_DEPS.cc) $< \
+		| sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \
+		[ -s $@ ] || rm -f $@'
+
+## Versioned libraries rules
+
+%.$(SO).$(SO_TARGET_VERSION_MAJOR): %.$(SO).$(SO_TARGET_VERSION)
+	$(RM) $@ && ln -s ${<F} $@
+%.$(SO): %.$(SO).$(SO_TARGET_VERSION_MAJOR)
+	$(RM) $@ && ln -s ${*F}.$(SO).$(SO_TARGET_VERSION) $@
+
+## Remove shared library 's'
+STATIC_PREFIX_WHEN_USED = 
+STATIC_PREFIX = 
+
+## End Solaris-specific setup
diff --git a/source/config/mh-unknown b/source/config/mh-unknown
new file mode 100644
index 0000000..e9219be
--- /dev/null
+++ b/source/config/mh-unknown
@@ -0,0 +1,27 @@
+## -*-makefile-*-
+## Copyright (c) 2003, International Business Machines Corporation and
+## others. All Rights Reserved.
+##
+
+# Note, this is not a real mh- file. You got here because configure
+# (specifically, aclocal.m4) could not determine a suitable mh- file.
+#
+# Perhaps your platform wasn't detected- try changing aclocal.m4 and
+# re-running autoconf. 
+#
+# If your platform is truly new/different:
+# As a start, try copying mh-linux (which is fairly generic) over this
+# file, and re-run config.status.
+
+%.$(STATIC_O) %.o %.$(STATIC_O) %.o ../data/%.o %.d %.d %.$(SO).$(SO_TARGET_VERSION_MAJOR) %.$(SO):
+	@echo 
+	@echo 
+	@echo "*** ERROR - configure could not detect your platform"
+	@echo "*** see the readme.html"
+	@echo "*** or, try copying icu/source/config/mh-linux to mh-unknown"
+	@echo "***   and editing it."
+	@echo 
+	@echo 
+	exit 1
+
+
diff --git a/source/config/pkgdataMakefile.in b/source/config/pkgdataMakefile.in
new file mode 100644
index 0000000..bb97a10
--- /dev/null
+++ b/source/config/pkgdataMakefile.in
@@ -0,0 +1,40 @@
+## pkgdataMakefile.in for ICU data
+## Copyright (c) 2008, International Business Machines Corporation and
+## others. All Rights Reserved.
+
+## Source directory information
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+
+# So that you have $(top_builddir)/config.status
+top_builddir = ..
+
+## All the flags and other definitions are included here.
+include $(top_builddir)/icudefs.mk
+
+OUTPUTFILE=pkgdata.inc
+MIDDLE_SO_TARGET=
+
+all : clean 
+	@echo GENCCODE_ASSEMBLY_TYPE=$(GENCCODE_ASSEMBLY) >> $(OUTPUTFILE)
+	@echo SO=$(SO) >> $(OUTPUTFILE)
+	@echo SOBJ=$(SOBJ) >> $(OUTPUTFILE)
+	@echo A=$(A) >> $(OUTPUTFILE)
+	@echo LIBPREFIX=$(LIBPREFIX) >> $(OUTPUTFILE)
+	@echo LIB_EXT_ORDER=$(FINAL_SO_TARGET) >> $(OUTPUTFILE)
+	@echo COMPILE="$(COMPILE.c)" >> $(OUTPUTFILE)
+	@echo LIBFLAGS="-I$(prefix)/include $(SHAREDLIBCPPFLAGS) $(SHAREDLIBCFLAGS)" >> $(OUTPUTFILE)
+	@echo GENLIB="$(SHLIB.c)" >> $(OUTPUTFILE)
+	@echo LDICUDTFLAGS=$(LDFLAGSICUDT) >> $(OUTPUTFILE)
+	@echo LD_SONAME=$(LD_SONAME) >> $(OUTPUTFILE)
+	@echo RPATH_FLAGS=$(RPATH_FLAGS) >> $(OUTPUTFILE)
+	@echo BIR_LDFLAGS=$(BIR_LDFLAGS) >> $(OUTPUTFILE)
+	@echo AR=$(AR) >> $(OUTPUTFILE)
+	@echo ARFLAGS=$(ARFLAGS) >> $(OUTPUTFILE)
+	@echo RANLIB=$(RANLIB) >> $(OUTPUTFILE)
+	@echo INSTALL_CMD=$(INSTALL-L) >> $(OUTPUTFILE)
+
+
+clean : 
+	$(RMV) $(OUTPUTFILE)
+
diff --git a/source/config/test-icu-config.sh b/source/config/test-icu-config.sh
new file mode 100755
index 0000000..20dfcc2
--- /dev/null
+++ b/source/config/test-icu-config.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+## -*-sh-*-
+## Copyright (c) 2002, International Business Machines Corporation and
+## others. All Rights Reserved.
+#
+# Just a script to test out icu-config.
+#
+
+set -x
+which icu-config
+icu-config
+icu-config -?
+icu-config --BAD ARGUMENT
+icu-config --bindir               
+icu-config --cflags               
+icu-config --cxx
+icu-config --cc
+icu-config --cxxflags               
+icu-config --cppflags               
+icu-config --cppflags-searchpath
+icu-config --incpath
+icu-config --invoke
+icu-config --invoke=genrb
+icu-config --invoke=./myapp
+icu-config --invoke=/path/to/myapp
+icu-config --ldflags                 
+icu-config --ldflags-layout          
+icu-config --ldflags-searchpath
+icu-config --ldflags-libsonly
+icu-config --ldflags-system          
+icu-config --ldflags-ustdio          
+icu-config --exec-prefix               
+icu-config --prefix               
+icu-config --sbindir              
+icu-config --sysconfdir
+icu-config --mandir
+icu-config --icudata
+icu-config --icudatadir
+icu-config --icudata-mode
+icu-config --icudata-install-dir
+icu-config --shared-datadir
+icu-config --unicode-version      
+icu-config --version              
+# should fail
+icu-config --prefix=/tmp --bindir
+# following needs to point to an alternate path that will work 
+icu-config --prefix=/Users/srl/II --cflags
+icu-config --detect-prefix --ldflags --ldflags-layout
+
diff --git a/source/config/windows-update.sed.in b/source/config/windows-update.sed.in
new file mode 100644
index 0000000..e586fda
--- /dev/null
+++ b/source/config/windows-update.sed.in
@@ -0,0 +1,6 @@
+# Copyright (C) 2010 IBM Corporation and Others. All Rights Reserved
+# sed script for updating windows .mak and .vcproj files
+s%^U_ICUDATA_NAME=.*%U_ICUDATA_NAME=icudt@LIB_VERSION_MAJOR@%
+s%^UNICODE_VERSION=.*%UNICODE_VERSION=@UNICODE_VERSION@%
+s%\(icu[a-zA-Z]*\)[0-9][0-9]\(d\.dll\)%\1@LIB_VERSION_MAJOR@\2%g
+s%\(icu[a-zA-Z]*\)[0-9][0-9]\(\.dll\)%\1@LIB_VERSION_MAJOR@\2%g
diff --git a/source/configure b/source/configure
new file mode 100755
index 0000000..89fddbe
--- /dev/null
+++ b/source/configure
@@ -0,0 +1,9124 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.67.
+#
+#  Copyright (c) 1999-2010, International Business Machines Corporation and others. All Rights Reserved.
+#
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
+# Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     # Try only shells that exist, to save several forks.
+	     as_shell=$as_dir/$as_base
+	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+	   done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  # We cannot yet assume a decent shell, so we have to provide a
+	# neutralization value for shells without unset; and this also
+	# works around shells that cannot unset nonexistent variables.
+	BASH_ENV=/dev/null
+	ENV=/dev/null
+	(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+	export CONFIG_SHELL
+	exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+	test -d "$1/.";
+      else
+	case $1 in #(
+	-*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="common/unicode/utypes.h"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+platform_make_fragment
+platform_make_fragment_name
+platform
+ICUDATA_CHAR
+SAMPLES_TRUE
+TESTS_TRUE
+ICULIBSUFFIXCNAME
+U_HAVE_LIB_SUFFIX
+ICULIBSUFFIX
+DATA_PACKAGING_MODE
+thepkgicudatadir
+pkgicudatadir
+LAYOUT_TRUE
+ICUIO_TRUE
+EXTRAS_TRUE
+U_CHECK_UTF16_STRING
+U_CHECK_GNUC_UTF16_STRING
+U_SIZEOF_WCHAR_T
+U_HAVE_WCSCPY
+U_HAVE_WCHAR_H
+HAVE_UINT64_T
+HAVE_INT64_T
+HAVE_UINT32_T
+HAVE_INT32_T
+HAVE_UINT16_T
+HAVE_INT16_T
+HAVE_UINT8_T
+HAVE_INT8_T
+U_TIMEZONE
+U_HAVE_TIMEZONE
+U_TZNAME
+U_HAVE_TZNAME
+U_TZSET
+U_HAVE_TZSET
+U_HAVE_POPEN
+U_HAVE_GCC_ATOMICS
+U_HAVE_PLACEMENT_NEW
+U_OVERRIDE_CXX_ALLOCATION
+U_HAVE_NAMESPACE
+U_NL_LANGINFO_CODESET
+U_HAVE_NL_LANGINFO_CODESET
+U_IS_BIG_ENDIAN
+U_IOSTREAM_SOURCE
+U_HAVE_DIRENT_H
+U_HAVE_INTTYPES_H
+GENCCODE_ASSEMBLY
+HAVE_MMAP
+LIB_THREAD
+ICU_USE_THREADS
+THREADS_TRUE
+U_HAVE_STD_STRING
+U_INLINE
+ENABLE_RPATH
+U_CHECK_DYLOAD
+U_ENABLE_DYLOAD
+U_ENABLE_TRACING
+U_DISABLE_RENAMING
+AR
+RANLIB
+LIBCXXFLAGS
+LIBCFLAGS
+U_USE_GCC_VISIBILITY_ATTRIBUTE
+U_DEFAULT_SHOW_DRAFT
+UCLN_NO_AUTO_CLEANUP
+ENABLE_STATIC
+ENABLE_SHARED
+LIB_M
+COMPILE_LINK_ENVVAR
+ARFLAGS
+EGREP
+GREP
+DOXYGEN
+cross_buildroot
+U_MAKE
+cross_compiling
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+CPP
+ac_ct_CXX
+CXXFLAGS
+CXX
+OBJEXT
+EXEEXT
+ac_ct_CC
+LDFLAGS
+CFLAGS
+CC
+ENABLE_RELEASE
+ENABLE_DEBUG
+CPPFLAGS
+target_os
+target_vendor
+target_cpu
+target
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+UNICODE_VERSION
+LIB_VERSION_MAJOR
+LIB_VERSION
+VERSION
+ICU_ECHO_T
+ICU_ECHO_C
+ICU_ECHO_N
+PACKAGE
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_debug
+enable_release
+with_cross_build
+enable_strict
+enable_64bit_libs
+with_library_bits
+enable_shared
+enable_static
+enable_auto_cleanup
+enable_draft
+enable_renaming
+enable_tracing
+enable_dyload
+enable_rpath
+enable_threads
+enable_weak_threads
+with_iostream
+enable_extras
+enable_icuio
+enable_layout
+with_data_packaging
+with_library_suffix
+enable_tests
+enable_samples
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CXX
+CXXFLAGS
+CCC
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used" >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_myself" : 'X\(//\)[^/]' \| \
+	 X"$as_myself" : 'X\(//\)$' \| \
+	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking ...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/PACKAGE]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+  --target=TARGET   configure for building compilers for TARGET [HOST]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-debug          build debug libraries default=no
+  --enable-release        build release libraries default=yes
+  --enable-strict         compile with strict compiler options default=yes
+  --enable-64bit-libs     (deprecated, use --with-library-bits) build 64-bit libraries default= platform default
+  --enable-shared         build shared libraries default=yes
+  --enable-static         build static libraries default=no
+  --enable-auto-cleanup   enable auto cleanup of libraries default=no
+  --enable-draft          enable draft APIs (and internal APIs) default=yes
+  --enable-renaming       add a version suffix to symbols default=yes
+  --enable-tracing        enable function and data tracing default=no
+  --disable-dyload        disable dynamic loading default=no
+  --enable-rpath          use rpath when linking default is only if necessary
+  --enable-threads        build ICU with thread safety default=yes
+  --enable-weak-threads   weakly reference the threading library default=no
+  --enable-extras         build ICU extras default=yes
+  --enable-icuio          build ICU's icuio library default=yes
+  --enable-layout         build ICU's layout library default=yes
+  --enable-tests          build ICU tests default=yes
+  --enable-samples        build ICU samples default=yes
+
+Additionally, the variable FORCE_LIBS may be set before calling configure.
+If set, it will REPLACE any automatic list of libraries.
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-cross-build=dir specify an absolute path to the build directory of an ICU built for the current platform default=no cross dir
+  --with-library-bits=bits specify how many bits to use for the library (32, 64, 64else32, nochange) default=nochange
+  --with-iostream=version specify the version of iostream to use (none, old, std, auto) default=auto
+  --with-data-packaging=type specify how to package ICU data (files, archive, library, static, auto) default=auto
+  --with-library-suffix=suffix    tag a suffix to the library names default=
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CXX         C++ compiler command
+  CXXFLAGS    C++ compiler flags
+  CPP         C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.67
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+
+ Copyright (c) 1999-2010, International Business Machines Corporation and others. All Rights Reserved.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_cxx_try_compile LINENO
+# ----------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_cxx_try_link LINENO
+# -------------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_link
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES
+# --------------------------------------------
+# Tries to find the compile-time value of EXPR in a program that includes
+# INCLUDES, setting VAR accordingly. Returns whether the value could be
+# computed
+ac_fn_c_compute_int ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if test "$cross_compiling" = yes; then
+    # Depending upon the size, compute the lo and hi bounds.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=$ac_mid; break
+else
+  as_fn_arith $ac_mid + 1 && ac_lo=$as_val
+			if test $ac_lo -le $ac_mid; then
+			  ac_lo= ac_hi=
+			  break
+			fi
+			as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_lo=$ac_mid; break
+else
+  as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val
+			if test $ac_mid -le $ac_hi; then
+			  ac_lo= ac_hi=
+			  break
+			fi
+			as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  ac_lo= ac_hi=
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=$ac_mid
+else
+  as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in #((
+?*) eval "$3=\$ac_lo"; ac_retval=0 ;;
+'') ac_retval=1 ;;
+esac
+  else
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+static long int longval () { return $2; }
+static unsigned long int ulongval () { return $2; }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (($2) < 0)
+    {
+      long int i = longval ();
+      if (i != ($2))
+	return 1;
+      fprintf (f, "%ld", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ($2))
+	return 1;
+      fprintf (f, "%lu", i);
+    }
+  /* Do not output a trailing newline, as this causes \r\n confusion
+     on some platforms.  */
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  echo >>conftest.val; read $3 <conftest.val; ac_retval=0
+else
+  ac_retval=1
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f conftest.val
+
+  fi
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_compute_int
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval "test \"\${$3+set}\"" = set; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_func
+
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=no"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+	 return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+	    return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_type
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.67.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	$as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	# differences in whitespace do not lead to failure.
+	ac_old_val_w=`echo x $ac_old_val`
+	ac_new_val_w=`echo x $ac_new_val`
+	if test "$ac_old_val_w" != "$ac_new_val_w"; then
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	  ac_cache_corrupted=:
+	else
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+	  eval $ac_var=\$ac_old_val
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+ac_config_headers="$ac_config_headers common/icucfg.h"
+
+PACKAGE="icu"
+
+
+# Use custom echo test for newline option
+# Current autoconf (2.65) gives incorrect echo newline option
+# for icu-config
+# This may be removed later - mow (June 17, 2010)
+ICU_ECHO_C= ICU_ECHO_N= ICU_ECHO_T=
+case `/bin/sh -c "echo -n x"` in
+-n*)
+  case `/bin/sh -c "echo 'x\c'"` in
+  *c*) ICU_ECHO_T=' ';;     # ECHO_T is single tab character.
+  *)   ICU_ECHO_C='\c';;
+  esac;;
+*)
+  ICU_ECHO_N='-n';;
+esac
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ICU version numbers" >&5
+$as_echo_n "checking for ICU version numbers... " >&6; }
+
+# Get the ICU version from uversion.h or other headers
+geticuversion() {
+    sed -n 's/^[ 	]*#[ 	]*define[ 	]*U_ICU_VERSION[ 	]*"\([^"]*\)".*/\1/p' "$@"
+}
+getuversion() {
+    sed -n 's/^[ 	]*#[ 	]*define[ 	]*U_UNICODE_VERSION[ 	]*"\([^"]*\)".*/\1/p' "$@"
+}
+VERSION=`geticuversion $srcdir/common/unicode/uvernum.h`
+if test x"$VERSION" = x; then
+    VERSION=`geticuversion $srcdir/common/unicode/*.h`
+    if test x"$VERSION" = x; then
+        as_fn_error $? "Cannot determine ICU version number from uvernum.h header file" "$LINENO" 5
+    fi
+fi
+
+UNICODE_VERSION=`getuversion $srcdir/common/unicode/uchar.h`
+if test x"$UNICODE_VERSION" = x; then
+    UNICODE_VERSION=`getuversion $srcdir/common/unicode/*.h`
+    if test x"$UNICODE_VERSION" = x; then
+        as_fn_error $? "Cannot determine Unicode version number from uchar.h header file" "$LINENO" 5
+    fi
+fi
+# Compute a reasonable library version from the release version. This is
+# very bad, but that's wanted... We want to make sure that the LIB_VERSION
+# has at least a dot in it, so we'll add a .0 if needed.
+LIB_VERSION=`echo $VERSION | sed -e 's/\.//' -e 's/^\([^.]*\)$/\1.0/'`
+LIB_VERSION_MAJOR=`echo $LIB_VERSION | sed 's/\..*//'`
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: release $VERSION, library $LIB_VERSION, unicode version $UNICODE_VERSION" >&5
+$as_echo "release $VERSION, library $LIB_VERSION, unicode version $UNICODE_VERSION" >&6; }
+
+
+
+# Determine the host system
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if test "${ac_cv_build+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if test "${ac_cv_host+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5
+$as_echo_n "checking target system type... " >&6; }
+if test "${ac_cv_target+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$target_alias" = x; then
+  ac_cv_target=$ac_cv_host
+else
+  ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5
+$as_echo "$ac_cv_target" >&6; }
+case $ac_cv_target in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;;
+esac
+target=$ac_cv_target
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_target
+shift
+target_cpu=$1
+target_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+target_os=$*
+IFS=$ac_save_IFS
+case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+  test "$program_prefix$program_suffix$program_transform_name" = \
+    NONENONEs,x,x, &&
+  program_prefix=${target_alias}-
+
+
+
+
+# This variable is needed on z/OS because the C++ compiler only recognizes .C
+_CXX_CXXSUFFIX=cpp
+export _CXX_CXXSUFFIX
+
+# Check whether to build debug libraries
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build debug libraries" >&5
+$as_echo_n "checking whether to build debug libraries... " >&6; }
+enabled=no
+ENABLE_DEBUG=0
+# Check whether --enable-debug was given.
+if test "${enable_debug+set}" = set; then :
+  enableval=$enable_debug;  case "${enableval}" in
+         yes|"") enabled=yes; ENABLE_DEBUG=1 ;;
+         *) ;;
+    esac
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enabled" >&5
+$as_echo "$enabled" >&6; }
+
+
+# Check whether to build release libraries
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build release libraries" >&5
+$as_echo_n "checking whether to build release libraries... " >&6; }
+enabled=yes
+ENABLE_RELEASE=1
+# Check whether --enable-release was given.
+if test "${enable_release+set}" = set; then :
+  enableval=$enable_release;  case "${enableval}" in
+         no) enabled=no; ENABLE_RELEASE=0 ;;
+         *) ;;
+    esac
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enabled" >&5
+$as_echo "$enabled" >&6; }
+
+
+# Don't use the default C/CXXFLags
+: ${CFLAGS=""}
+: ${CXXFLAGS=""}
+
+# Checks for programs
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+	if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+	then :; else
+	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	fi
+	# We set ac_cv_exeext here because the later test for it is not
+	# safe: cross compilers may not add the suffix if given an `-o'
+	# argument, so we may need to know it at that point already.
+	# Even if this section looks crufty: it has the advantage of
+	# actually working.
+	break;;
+    * )
+	break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if test "${ac_cv_objext+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -z "$CXX"; then
+  if test -n "$CCC"; then
+    CXX=$CCC
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CXX+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
+$as_echo "$CXX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CXX" && break
+  done
+fi
+if test -z "$CXX"; then
+  ac_ct_CXX=$CXX
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CXX"; then
+  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CXX="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
+$as_echo "$ac_ct_CXX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CXX" && break
+done
+
+  if test "x$ac_ct_CXX" = x; then
+    CXX="g++"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CXX=$ac_ct_CXX
+  fi
+fi
+
+  fi
+fi
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
+$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
+if test "${ac_cv_cxx_compiler_gnu+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
+$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GXX=yes
+else
+  GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
+$as_echo_n "checking whether $CXX accepts -g... " >&6; }
+if test "${ac_cv_prog_cxx_g+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+   ac_cxx_werror_flag=yes
+   ac_cv_prog_cxx_g=no
+   CXXFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_prog_cxx_g=yes
+else
+  CXXFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+else
+  ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+	 CXXFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_prog_cxx_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
+$as_echo "$ac_cv_prog_cxx_g" >&6; }
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Ensure that if CXXFLAGS/CFLAGS were not set when calling configure, set it correctly based on (enable/disable) debug or release option
+# The release mode use is the default one for autoconf
+if test "$GCC" = yes; then
+    if test "$CFLAGS" = ""; then
+        if test "$ENABLE_DEBUG" = 1; then
+            CFLAGS=-g
+        fi
+        if test "$ENABLE_RELEASE" = 1; then
+            CFLAGS="$CFLAGS -O2"
+        fi
+    fi
+    if test "$CXXFLAGS" = ""; then
+        if test "$ENABLE_DEBUG" = 1; then
+            CXXFLAGS=-g
+        fi
+        if test "$ENABLE_RELEASE" = 1; then
+            CXXFLAGS="$CXXFLAGS -O2"
+        fi
+    fi
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if test "${ac_cv_prog_CPP+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    rm -rf conftest.one conftest.two conftest.dir
+	    echo one > conftest.one
+	    echo two > conftest.two
+	    mkdir conftest.dir
+	    if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+	      test -s conftest.one && test -s conftest.two &&
+	      test -s conftest.dir/conftest.one &&
+	      test -s conftest.dir/conftest.two
+	    then
+	      ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	      break 3
+	    fi
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+
+  done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+
+
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# make sure install is relative to srcdir - if a script
+if test "$srcdir" = "."; then
+  # If srcdir isn't just ., then (srcdir) is already prepended.
+  if test "${ac_install_sh}" = "${INSTALL}"; then
+   INSTALL="\\\$(top_srcdir)/${ac_install_sh}"
+  fi
+fi
+
+#AC_CHECK_PROG(AUTOCONF, autoconf, autoconf, true)
+#AC_CHECK_PROG(STRIP, strip, strip, true)
+
+# Check for the platform make
+for ac_prog in gmake gnumake
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_path_U_MAKE+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $U_MAKE in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_U_MAKE="$U_MAKE" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_U_MAKE="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+U_MAKE=$ac_cv_path_U_MAKE
+if test -n "$U_MAKE"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $U_MAKE" >&5
+$as_echo "$U_MAKE" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$U_MAKE" && break
+done
+test -n "$U_MAKE" || U_MAKE="make"
+
+
+
+
+
+# Check whether --with-cross-build was given.
+if test "${with_cross_build+set}" = set; then :
+  withval=$with_cross_build; cross_buildroot="${withval}"
+else
+  cross_buildroot=""
+fi
+
+
+if test "X$cross_buildroot" = "X"; then
+    if test "$cross_compiling" = "yes"; then
+        as_fn_error $? "Error! Cross compiling but no --with-cross-build option specified - please supply the path to an executable ICU's build root" "$LINENO" 5
+	    fi
+else
+    if test -f "${cross_buildroot}/config/icucross.mk"; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using cross buildroot: $cross_buildroot" >&5
+$as_echo "Using cross buildroot: $cross_buildroot" >&6; }
+    else
+        if test -d "${cross_buildroot}"; then
+            as_fn_error $? "${cross_buildroot}/config/icucross.mk not found. Please build ICU in ${cross_buildroot} first." "$LINENO" 5
+        else
+            as_fn_error $? "No such directory ${cross_buildroot} supplied as the argument to --with-cross-build. Use an absolute path." "$LINENO" 5
+        fi
+    fi
+fi
+
+
+# Check for doxygen to generate documentation
+# Extract the first word of "doxygen", so it can be a program name with args.
+set dummy doxygen; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_path_DOXYGEN+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $DOXYGEN in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_DOXYGEN="$DOXYGEN" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_dummy="$PATH:/usr/local/bin:/usr/bin"
+for as_dir in $as_dummy
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_DOXYGEN="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+DOXYGEN=$ac_cv_path_DOXYGEN
+if test -n "$DOXYGEN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DOXYGEN" >&5
+$as_echo "$DOXYGEN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+# Check that the linker is usable
+
+case "${host}" in
+    *-*-cygwin*|*-*-mingw*)
+        if test "$GCC" != yes && test -n "`link --version 2>&1 | grep 'GNU coreutils'`"; then
+            as_fn_error $? "link.exe is not a valid linker. Your PATH is incorrect.
+                  Please follow the directions in ICU's readme." "$LINENO" 5
+        fi;;
+    *);;
+esac
+
+# Determine the executable suffix
+# We don't use AC_EXEEXT because some compilers output separate debugging
+# files, which confuses the AC_EXEEXT macro.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking checking for executable suffix" >&5
+$as_echo_n "checking checking for executable suffix... " >&6; }
+case "${host}" in
+    *-*-cygwin*|*-*-mingw*)  EXEEXT=.exe ;;
+    *)      EXEEXT="" ;;
+esac
+ac_exeext=$EXEEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $EXEEXT" >&5
+$as_echo "$EXEEXT" >&6; }
+
+
+# Determine how strict we want to be when compiling
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether strict compiling is on" >&5
+$as_echo_n "checking whether strict compiling is on... " >&6; }
+    # Check whether --enable-strict was given.
+if test "${enable_strict+set}" = set; then :
+  enableval=$enable_strict;
+        if test "$enableval" = no
+        then
+            ac_use_strict_options=no
+        else
+            ac_use_strict_options=yes
+        fi
+
+else
+  ac_use_strict_options=yes
+fi
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_use_strict_options" >&5
+$as_echo "$ac_use_strict_options" >&6; }
+
+    if test "$ac_use_strict_options" = yes
+    then
+        if test "$GCC" = yes
+        then
+            CFLAGS="$CFLAGS -Wall -ansi -pedantic -Wshadow -Wpointer-arith -Wmissing-prototypes -Wwrite-strings -Wno-long-long"
+            case "${host}" in
+            *-*-solaris*)
+                CFLAGS="$CFLAGS -D__STDC__=0";;
+            esac
+        else
+            case "${host}" in
+            *-*-cygwin)
+                if test "`$CC /help 2>&1 | head -c9`" = "Microsoft"
+                then
+                    CFLAGS="$CFLAGS /W4"
+                fi
+            esac
+        fi
+        if test "$GXX" = yes
+        then
+            CXXFLAGS="$CXXFLAGS -W -Wall -ansi -pedantic -Wpointer-arith -Wwrite-strings -Wno-long-long"
+            case "${host}" in
+            *-*-solaris*)
+                CXXFLAGS="$CXXFLAGS -D__STDC__=0";;
+            esac
+        else
+            case "${host}" in
+            *-*-cygwin)
+                if test "`$CXX /help 2>&1 | head -c9`" = "Microsoft"
+                then
+                    CXXFLAGS="$CXXFLAGS /W4"
+                fi
+            esac
+        fi
+    fi
+
+
+# Check if we can build and use 64-bit libraries
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+    BITS_REQ=nochange
+    ENABLE_64BIT_LIBS=unknown
+    ## revisit this for cross-compile.
+
+    # Check whether --enable-64bit-libs was given.
+if test "${enable_64bit_libs+set}" = set; then :
+  enableval=$enable_64bit_libs; echo "note, use --with-library-bits instead of --*-64bit-libs"
+         case "${enableval}" in
+            no|false|32) with_library_bits=32;  ;;
+            yes|true|64) with_library_bits=64else32 ;;
+            nochange) with_library_bits=nochange; ;;
+            *) as_fn_error $? "bad value ${enableval} for '--*-64bit-libs'" "$LINENO" 5 ;;
+            esac
+fi
+
+
+
+
+# Check whether --with-library-bits was given.
+if test "${with_library_bits+set}" = set; then :
+  withval=$with_library_bits; case "${withval}" in
+            ""|nochange) BITS_REQ=$withval ;;
+            32|64|64else32) BITS_REQ=$withval ;;
+            *) as_fn_error $? "bad value ${withval} for --with-library-bits" "$LINENO" 5 ;;
+            esac
+fi
+
+
+    # don't use these for cross compiling
+    if test "$cross_compiling" = "yes" -a "${BITS_REQ}" != "nochange"; then
+        as_fn_error $? "Don't specify bitness when cross compiling. See readme.html for help with cross compilation., and set compiler options manually." "$LINENO" 5
+    fi
+    # The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5
+$as_echo_n "checking size of void *... " >&6; }
+if test "${ac_cv_sizeof_void_p+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_void_p" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (void *)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_void_p=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5
+$as_echo "$ac_cv_sizeof_void_p" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_VOID_P $ac_cv_sizeof_void_p
+_ACEOF
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether runnable 64 bit binaries are built by default" >&5
+$as_echo_n "checking whether runnable 64 bit binaries are built by default... " >&6; }
+    case $ac_cv_sizeof_void_p in
+        8) DEFAULT_64BIT=yes ;;
+        4) DEFAULT_64BIT=no ;;
+        *) DEFAULT_64BIT=unknown
+    esac
+    BITS_GOT=unknown
+
+    # 'OK' here means, we can exit any further checking, everything's copa
+    BITS_OK=yes
+
+    # do we need to check for buildable/runnable 32 or 64 bit?
+    BITS_CHECK_32=no
+    BITS_CHECK_64=no
+
+    # later, can we run the 32/64 bit binaries so made?
+    BITS_RUN_32=no
+    BITS_RUN_64=no
+
+    if test "$DEFAULT_64BIT" = "yes"; then
+        # we get 64 bits by default.
+        BITS_GOT=64
+        case "$BITS_REQ" in
+            32)
+                # need to look for 32 bit support.
+                BITS_CHECK_32=yes
+                # not copa.
+                BITS_OK=no;;
+            # everyone else is happy.
+            nochange) ;;
+            *) ;;
+        esac
+    elif test "$DEFAULT_64BIT" = "no"; then
+        # not 64 bit by default.
+        BITS_GOT=32
+        case "$BITS_REQ" in
+            64|64else32)
+                BITS_CHECK_64=yes
+                #BITS_CHECK_32=yes
+                BITS_OK=no;;
+            nochange) ;;
+            *) ;;
+        esac
+    elif test "$DEFAULT_64BIT" = "unknown"; then
+        # cross compiling.
+        BITS_GOT=unknown
+        case "$BITS_REQ" in
+            64|64else32) BITS_OK=no
+            BITS_CHECK_32=yes
+            BITS_CHECK_64=yes ;;
+            32) BITS_OK=no;;
+            nochange) ;;
+            *) ;;
+        esac
+    fi
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEFAULT_64BIT" >&5
+$as_echo "$DEFAULT_64BIT" >&6; };
+
+    if test "$BITS_OK" != "yes"; then
+        # not copa. back these up.
+        CFLAGS_OLD="${CFLAGS}"
+        CXXFLAGS_OLD="${CXXFLAGS}"
+        LDFLAGS_OLD="${LDFLAGS}"
+        ARFLAGS_OLD="${ARFLAGS}"
+
+        CFLAGS_32="${CFLAGS}"
+        CXXFLAGS_32="${CXXFLAGS}"
+        LDFLAGS_32="${LDFLAGS}"
+        ARFLAGS_32="${ARFLAGS}"
+
+        CFLAGS_64="${CFLAGS}"
+        CXXFLAGS_64="${CXXFLAGS}"
+        LDFLAGS_64="${LDFLAGS}"
+        ARFLAGS_64="${ARFLAGS}"
+
+        CAN_BUILD_64=unknown
+        CAN_BUILD_32=unknown
+        # These results can't be cached because is sets compiler flags.
+        if test "$BITS_CHECK_64" = "yes"; then
+            { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to build 64-bit executables" >&5
+$as_echo_n "checking how to build 64-bit executables... " >&6; }
+            CAN_BUILD_64=no
+            ####
+            # Find out if we think we can *build* for 64 bit. Doesn't check whether we can run it.
+            #  Note, we don't have to actually check if the options work- we'll try them before using them.
+            #  So, only try actually testing the options, if you are trying to decide between multiple options.
+            # On exit from the following clauses:
+            # if CAN_BUILD_64=yes:
+            #    *FLAGS are assumed to contain the right settings for 64bit
+            # else if CAN_BUILD_64=no: (default)
+            #    *FLAGS are assumed to be trashed, and will be reset from *FLAGS_OLD
+
+            if test "$GCC" = yes; then
+                CFLAGS="${CFLAGS} -m64"
+                CXXFLAGS="${CXXFLAGS} -m64"
+                cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int main(void) {return (sizeof(void*)*8==64)?0:1;}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  CAN_BUILD_64=yes
+else
+  CAN_BUILD_64=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+            else
+                case "${host}" in
+                sparc*-*-solaris*)
+                    # 1. try -m64
+                    CFLAGS="${CFLAGS} -m64"
+                    CXXFLAGS="${CXXFLAGS} -m64"
+                    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int main(void) {return (sizeof(void*)*8==64)?0:1;}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  CAN_BUILD_64=yes
+else
+  CAN_BUILD_64=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+                    if test "$CAN_BUILD_64" != yes; then
+                        # Nope. back out changes.
+                        CFLAGS="${CFLAGS_OLD}"
+                        CXXFLAGS="${CFLAGS_OLD}"
+                        # 2. try xarch=v9 [deprecated]
+                        ## TODO: cross compile: the following won't work.
+                        SPARCV9=`isainfo -n 2>&1 | grep sparcv9`
+                        SOL64=`$CXX -xarch=v9 2>&1 && $CC -xarch=v9 2>&1 | grep -v usage:`
+                        # "Warning: -xarch=v9 is deprecated, use -m64 to create 64-bit programs"
+                        if test -z "$SOL64" && test -n "$SPARCV9"; then
+                            CFLAGS="${CFLAGS} -xtarget=ultra -xarch=v9"
+                            CXXFLAGS="${CXXFLAGS} -xtarget=ultra -xarch=v9"
+                            LDFLAGS="${LDFLAGS} -xtarget=ultra -xarch=v9"
+                            CAN_BUILD_64=yes
+                        fi
+                    fi
+                    ;;
+                i386-*-solaris*)
+                    # 1. try -m64
+                    CFLAGS="${CFLAGS} -m64"
+                    CXXFLAGS="${CXXFLAGS} -m64"
+                    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int main(void) {return (sizeof(void*)*8==64)?0:1;}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  CAN_BUILD_64=yes
+else
+  CAN_BUILD_64=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+                    if test "$CAN_BUILD_64" != yes; then
+                        # Nope. back out changes.
+                        CFLAGS="${CFLAGS_OLD}"
+                        CXXFLAGS="${CXXFLAGS_OLD}"
+                        # 2. try the older compiler option
+                        ## TODO: cross compile problem
+                        SOL64=`$CXX -xtarget=generic64 2>&1 && $CC -xtarget=generic64 2>&1 | grep -v usage:`
+                        if test -z "$SOL64" && test -n "$AMD64"; then
+                            CFLAGS="${CFLAGS} -xtarget=generic64"
+                            CXXFLAGS="${CXXFLAGS} -xtarget=generic64"
+                            CAN_BUILD_64=yes
+                        fi
+                    fi
+                    ;;
+                ia64-*-linux*)
+                    # check for ecc/ecpc compiler support
+                    ## TODO: cross compiler problem
+                    if test -n "`$CXX --help 2>&1 && $CC --help 2>&1 | grep -v Intel`"; then
+                        if test -n "`$CXX --help 2>&1 && $CC --help 2>&1 | grep -v Itanium`"; then
+                            CAN_BUILD_64=yes
+                        fi
+                    fi
+                    ;;
+                *-*-cygwin)
+                    # vcvarsamd64.bat should have been used to enable 64-bit builds.
+                    # We only do this check to display the correct answer.
+                    ## TODO: cross compiler problem
+                    if test -n "`$CXX -help 2>&1 | grep 'for x64'`"; then
+                        CAN_BUILD_64=yes
+                    fi
+                    ;;
+                *-*-aix*|powerpc64-*-linux*)
+                    CFLAGS="${CFLAGS} -q64"
+                    CXXFLAGS="${CXXFLAGS} -q64"
+                    LDFLAGS="${LDFLAGS} -q64"
+                    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int main(void) {return (sizeof(void*)*8==64)?0:1;}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  CAN_BUILD_64=yes
+else
+  CAN_BUILD_64=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+                    if test "$CAN_BUILD_64" = yes; then
+                        # worked- set other options.
+                        case "${host}" in
+                        *-*-aix*)
+                            # tell AIX what executable mode to use.
+                            ARFLAGS="${ARFLAGS} -X64"
+                        esac
+                    fi
+                    ;;
+                *-*-hpux*)
+                    # First we try the newer +DD64, if that doesn't work,
+                    # try other options.
+
+                    CFLAGS="${CFLAGS} +DD64"
+                    CXXFLAGS="${CXXFLAGS} +DD64"
+                    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int main(void) {return (sizeof(void*)*8==64)?0:1;}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  CAN_BUILD_64=yes
+else
+  CAN_BUILD_64=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+                    if test "$CAN_BUILD_64" != yes; then
+                        # reset
+                        CFLAGS="${CFLAGS_OLD}"
+                        CXXFLAGS="${CXXFLAGS_OLD}"
+                        # append
+                        CFLAGS="${CFLAGS} +DA2.0W"
+                        CXXFLAGS="${CXXFLAGS} +DA2.0W"
+                        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int main(void) {return (sizeof(void*)*8==64)?0:1;}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  CAN_BUILD_64=yes
+else
+  CAN_BUILD_64=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+                    fi
+                    ;;
+                *-*ibm-openedition*|*-*-os390*)
+                    CFLAGS="${CFLAGS} -Wc,lp64"
+                    CXXFLAGS="${CXXFLAGS} -Wc,lp64"
+                    LDFLAGS="${LDFLAGS} -Wl,lp64"
+                    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int main(void) {return (sizeof(void*)*8==64)?0:1;}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  CAN_BUILD_64=yes
+else
+  CAN_BUILD_64=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+                    ;;
+                *)
+                    # unknown platform.
+                    ;;
+                esac
+            fi
+            { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CAN_BUILD_64" >&5
+$as_echo "$CAN_BUILD_64" >&6; }
+            if test "$CAN_BUILD_64" = yes; then
+                { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether runnable 64-bit binaries are being built " >&5
+$as_echo_n "checking whether runnable 64-bit binaries are being built ... " >&6; }
+                if test "$cross_compiling" = yes; then :
+  BITS_RUN_64=unknown
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int main(void) {return (sizeof(void*)*8==64)?0:1;}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  BITS_RUN_64=yes
+else
+  BITS_RUN_64=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+                { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BITS_RUN_64" >&5
+$as_echo "$BITS_RUN_64" >&6; };
+
+                CFLAGS_64="${CFLAGS}"
+                CXXFLAGS_64="${CXXFLAGS}"
+                LDFLAGS_64="${LDFLAGS}"
+                ARFLAGS_64="${ARFLAGS}"
+            fi
+            # put it back.
+            CFLAGS="${CFLAGS_OLD}"
+            CXXFLAGS="${CXXFLAGS_OLD}"
+            LDFLAGS="${LDFLAGS_OLD}"
+            ARFLAGS="${ARFLAGS_OLD}"
+        fi
+        if test "$BITS_CHECK_32" = "yes"; then
+            # see comment under 'if BITS_CHECK_64', above.
+            { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to build 32-bit executables" >&5
+$as_echo_n "checking how to build 32-bit executables... " >&6; }
+            if test "$GCC" = yes; then
+                CFLAGS="${CFLAGS} -m32"
+                CXXFLAGS="${CXXFLAGS} -m32"
+                cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int main(void) {return (sizeof(void*)*8==32)?0:1;}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  CAN_BUILD_32=yes
+else
+  CAN_BUILD_32=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+            fi
+            { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CAN_BUILD_32" >&5
+$as_echo "$CAN_BUILD_32" >&6; }
+            if test "$CAN_BUILD_32" = yes; then
+                { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether runnable 32-bit binaries are being built " >&5
+$as_echo_n "checking whether runnable 32-bit binaries are being built ... " >&6; }
+                if test "$cross_compiling" = yes; then :
+  BITS_RUN_32=unknown
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int main(void) {return (sizeof(void*)*8==32)?0:1;}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  BITS_RUN_32=yes
+else
+  BITS_RUN_32=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+                { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BITS_RUN_32" >&5
+$as_echo "$BITS_RUN_32" >&6; };
+                CFLAGS_32="${CFLAGS}"
+                CXXFLAGS_32="${CXXFLAGS}"
+                LDFLAGS_32="${LDFLAGS}"
+                ARFLAGS_32="${ARFLAGS}"
+            fi
+            # put it back.
+            CFLAGS="${CFLAGS_OLD}"
+            CXXFLAGS="${CXXFLAGS_OLD}"
+            LDFLAGS="${LDFLAGS_OLD}"
+            ARFLAGS="${ARFLAGS_OLD}"
+        fi
+
+        ##
+        # OK. Now, we've tested for 32 and 64 bitness. Let's see what we'll do.
+        #
+
+        # First, implement 64else32
+        if test "$BITS_REQ" = "64else32"; then
+            if test "$BITS_RUN_64" = "yes"; then
+                BITS_REQ=64
+            else
+                # no changes.
+                BITS_OK=yes
+            fi
+        fi
+
+        # implement.
+        if test "$BITS_REQ" = "32" -a "$BITS_RUN_32" = "yes"; then
+            CFLAGS="${CFLAGS_32}"
+            CXXFLAGS="${CXXFLAGS_32}"
+            LDFLAGS="${LDFLAGS_32}"
+            ARFLAGS="${ARFLAGS_32}"
+            BITS_OK=yes
+        elif test "$BITS_REQ" = "64" -a "$BITS_RUN_64" = "yes"; then
+            CFLAGS="${CFLAGS_64}"
+            CXXFLAGS="${CXXFLAGS_64}"
+            LDFLAGS="${LDFLAGS_64}"
+            ARFLAGS="${ARFLAGS_64}"
+            BITS_OK=yes
+        elif test "$BITS_OK" != "yes"; then
+            as_fn_error $? "Requested $BITS_REQ bit binaries but could not compile and execute them. See readme.html for help with cross compilation., and set compiler options manually." "$LINENO" 5
+        fi
+     fi
+
+
+
+
+# Determine the Makefile fragment
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which Makefile fragment to use for ${host}" >&5
+$as_echo_n "checking which Makefile fragment to use for ${host}... " >&6; }
+if test "${icu_cv_host_frag+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+
+case "${host}" in
+*-*-solaris*)
+	if test "$GCC" = yes; then
+		icu_cv_host_frag=mh-solaris-gcc
+	else
+		icu_cv_host_frag=mh-solaris
+	fi ;;
+alpha*-*-linux-gnu)
+	if test "$GCC" = yes; then
+		icu_cv_host_frag=mh-alpha-linux-gcc
+	else
+		icu_cv_host_frag=mh-alpha-linux-cc
+	fi ;;
+powerpc*-*-linux*)
+	if test "$GCC" = yes; then
+		icu_cv_host_frag=mh-linux
+	else
+		icu_cv_host_frag=mh-linux-va
+	fi ;;
+*-*-linux*|*-*-gnu|*-*-k*bsd*-gnu|*-*-kopensolaris*-gnu) icu_cv_host_frag=mh-linux ;;
+*-*-cygwin|*-*-mingw32)
+	if test "$GCC" = yes; then
+		cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#ifndef __MINGW32__
+#error This is not MinGW
+#endif
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  icu_cv_host_frag=mh-mingw
+else
+  icu_cv_host_frag=mh-cygwin
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+	else
+		icu_cv_host_frag=mh-cygwin-msvc
+	fi ;;
+*-*-*bsd*|*-*-dragonfly*) 	icu_cv_host_frag=mh-bsd-gcc ;;
+*-*-aix*)
+	if test "$GCC" = yes; then
+		icu_cv_host_frag=mh-aix-gcc
+	else
+		icu_cv_host_frag=mh-aix-va
+	fi ;;
+*-*-hpux*)
+	if test "$GCC" = yes; then
+		icu_cv_host_frag=mh-hpux-gcc
+	else
+		case "$CXX" in
+		*aCC)    icu_cv_host_frag=mh-hpux-acc ;;
+		esac
+	fi ;;
+*-*ibm-openedition*|*-*-os390*)	icu_cv_host_frag=mh-os390 ;;
+*-*-os400*)	icu_cv_host_frag=mh-os400 ;;
+*-apple-rhapsody*)	icu_cv_host_frag=mh-darwin ;;
+*-apple-darwin*)	icu_cv_host_frag=mh-darwin ;;
+*-*-beos)       icu_cv_host_frag=mh-beos ;;
+*-*-haiku)      icu_cv_host_frag=mh-haiku ;;
+*-*-irix*)	icu_cv_host_frag=mh-irix ;;
+*-dec-osf*) icu_cv_host_frag=mh-alpha-osf ;;
+*-*-nto*)	icu_cv_host_frag=mh-qnx ;;
+*-ncr-*)	icu_cv_host_frag=mh-mpras ;;
+*) 		icu_cv_host_frag=mh-unknown ;;
+esac
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $icu_cv_host_frag" >&5
+$as_echo "$icu_cv_host_frag" >&6; }
+
+
+# Checks for libraries and other host specific stuff
+# On HP/UX, don't link to -lm from a shared lib because it isn't
+#  PIC (at least on 10.2)
+case "${host}" in
+	*-*-hpux*) 	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for floor in -lm" >&5
+$as_echo_n "checking for floor in -lm... " >&6; }
+if test "${ac_cv_lib_m_floor+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char floor ();
+int
+main ()
+{
+return floor ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_floor=yes
+else
+  ac_cv_lib_m_floor=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_floor" >&5
+$as_echo "$ac_cv_lib_m_floor" >&6; }
+if test "x$ac_cv_lib_m_floor" = x""yes; then :
+  LIB_M="-lm"
+fi
+ ;;
+
+	*) 		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for floor in -lm" >&5
+$as_echo_n "checking for floor in -lm... " >&6; }
+if test "${ac_cv_lib_m_floor+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char floor ();
+int
+main ()
+{
+return floor ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_floor=yes
+else
+  ac_cv_lib_m_floor=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_floor" >&5
+$as_echo "$ac_cv_lib_m_floor" >&6; }
+if test "x$ac_cv_lib_m_floor" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+  LIBS="-lm $LIBS"
+
+fi
+
+			LIB_M="" ;;
+esac
+
+
+# Check whether to build shared libraries
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+enabled=no
+# Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+  enableval=$enable_shared;  case "${enableval}" in
+	     yes|"") enabled=yes; ENABLE_SHARED=YES ;;
+	     no);;
+	     *) ;;
+    esac
+else
+  enabled=yes; ENABLE_SHARED=YES
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enabled" >&5
+$as_echo "$enabled" >&6; }
+
+
+# Check whether to build static libraries
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+enabled=no
+# Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+  enableval=$enable_static;  case "${enableval}" in
+	     yes|"") enabled=yes; ENABLE_STATIC=YES ;;
+	     no) ;;
+	     *) ;;
+    esac
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enabled" >&5
+$as_echo "$enabled" >&6; }
+
+
+# Check whether to enable auto cleanup of libraries
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable auto cleanup of libraries" >&5
+$as_echo_n "checking whether to enable auto cleanup of libraries... " >&6; }
+enabled=no
+UCLN_NO_AUTO_CLEANUP=1
+# Check whether --enable-auto-cleanup was given.
+if test "${enable_auto_cleanup+set}" = set; then :
+  enableval=$enable_auto_cleanup;  case "${enableval}" in
+         yes) enabled=yes; UCLN_NO_AUTO_CLEANUP=0 ;;
+         *) ;;
+    esac
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enabled" >&5
+$as_echo "$enabled" >&6; }
+
+
+# MSVC floating-point option
+MSVC_RELEASE_FLAG=""
+if test $enabled = yes
+then
+    if test $icu_cv_host_frag = mh-cygwin-msvc
+    then
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+    #if defined _MSC_VER && _MSC_VER >= 1400
+    #else
+    Microsoft Visual C++ < 2005
+    #endif
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  MSVC_RELEASE_FLAG="/fp:precise"
+else
+  MSVC_RELEASE_FLAG="/Op"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+        CFLAGS="${CFLAGS} ${MSVC_RELEASE_FLAG}"
+        CXXFLAGS="${CXXFLAGS} ${MSVC_RELEASE_FLAG}"
+    fi
+fi
+
+# Check whether to enabled draft APIs
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable draft APIs" >&5
+$as_echo_n "checking whether to enable draft APIs... " >&6; }
+enabled=yes
+U_DEFAULT_SHOW_DRAFT=1
+# Check whether --enable-draft was given.
+if test "${enable_draft+set}" = set; then :
+  enableval=$enable_draft;  case "${enableval}" in
+         no) enabled=no; U_DEFAULT_SHOW_DRAFT=0 ;;
+         *) ;;
+    esac
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enabled" >&5
+$as_echo "$enabled" >&6; }
+# Make sure that we can use draft API in ICU.
+if test "$U_DEFAULT_SHOW_DRAFT" = 0; then
+    CPPFLAGS="$CPPFLAGS -DU_SHOW_DRAFT_API"
+fi
+
+
+# Check if we can hide variables from
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library API export" >&5
+$as_echo_n "checking for library API export... " >&6; }
+SHAREDLIBEXPORT=no
+U_USE_GCC_VISIBILITY_ATTRIBUTE=0
+OLD_CFLAGS="${CFLAGS}"
+OLD_CXXFLAGS="${CXXFLAGS}"
+if test "$ac_cv_c_compiler_gnu" = yes; then
+    LIBCFLAGS="-fvisibility=hidden"
+    LIBCXXFLAGS="-fvisibility=hidden"
+    CFLAGS="${CFLAGS} ${LIBCFLAGS}"
+    CXXFLAGS="${CXXFLAGS} ${LIBCXXFLAGS}"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+__attribute__ ((visibility ("default"))) void f(void);
+#include <stdlib.h>
+int
+main ()
+{
+exit(0);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  SHAREDLIBEXPORT=yes
+else
+  SHAREDLIBEXPORT=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+    if test "$SHAREDLIBEXPORT" = no; then
+        LIBCFLAGS=
+        LIBCXXFLAGS=
+    else
+        U_USE_GCC_VISIBILITY_ATTRIBUTE=1
+    fi
+else
+    case "${host}" in
+    *-*-solaris*)
+        LIBCFLAGS="-xldscope=hidden"
+        LIBCXXFLAGS="-xldscope=hidden"
+        CFLAGS="${CFLAGS} ${LIBCFLAGS}"
+        CXXFLAGS="${CXXFLAGS} ${LIBCXXFLAGS}"
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+__global void f(void);
+#include <stdlib.h>
+int
+main ()
+{
+exit(0);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  SHAREDLIBEXPORT=yes
+else
+  SHAREDLIBEXPORT=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+        if test "$SHAREDLIBEXPORT" = no; then
+            LIBCFLAGS=
+            LIBCXXFLAGS=
+        fi
+        ;;
+    *-*-hpux*)
+        # ICU isn't set up to follow the HP syntax yet.
+        ;;
+    *)
+    esac
+fi
+# Restore to their original state because the Intel compiler chokes
+# on this option when checking for the wchar_t size, but the
+# option otherwise works.
+CFLAGS="${OLD_CFLAGS}"
+CXXFLAGS="${OLD_CXXFLAGS}"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $SHAREDLIBEXPORT" >&5
+$as_echo "$SHAREDLIBEXPORT" >&6; }
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_RANLIB+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_RANLIB" = x; then
+    RANLIB=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    RANLIB=$ac_ct_RANLIB
+  fi
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+
+# look for 'ar' the proper way
+#AC_PATH_PROG(AR,ar,[echo archiver ar not found re-run configure ; false],$PATH:/bin:/usr/bin:/usr/ccs/bin)
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_AR+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_AR="${ac_tool_prefix}ar"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+  ac_ct_AR=$AR
+  # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_AR"; then
+  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_AR="ar"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_AR" = x; then
+    AR=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    AR=$ac_ct_AR
+  fi
+else
+  AR="$ac_cv_prog_AR"
+fi
+
+if test "x$AR" = "x"; then
+  as_fn_error $? "Archiver ar not found. Set AR= or fix PATH" "$LINENO" 5
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable renaming of symbols" >&5
+$as_echo_n "checking whether to enable renaming of symbols... " >&6; }
+enabled=yes
+U_DISABLE_RENAMING=0
+# Check whether --enable-renaming was given.
+if test "${enable_renaming+set}" = set; then :
+  enableval=$enable_renaming;  case "${enableval}" in
+	     yes|"") enabled=yes ;;
+	     no) enabled=no; U_DISABLE_RENAMING=1 ;;
+	     *) ;;
+    esac
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enabled" >&5
+$as_echo "$enabled" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable function and data tracing" >&5
+$as_echo_n "checking whether to enable function and data tracing... " >&6; }
+enabled=no
+U_ENABLE_TRACING=0
+# Check whether --enable-tracing was given.
+if test "${enable_tracing+set}" = set; then :
+  enableval=$enable_tracing;  case "${enableval}" in
+	     yes|"") enabled=yes; U_ENABLE_TRACING=1 ;;
+	     no) enabled=no; U_ENABLE_TRACING=0 ;;
+	     *) ;;
+    esac
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enabled" >&5
+$as_echo "$enabled" >&6; }
+
+
+
+U_ENABLE_DYLOAD=1
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable dynamic loading of plugins" >&5
+$as_echo_n "checking whether to enable dynamic loading of plugins... " >&6; }
+enabled=check
+# Check whether --enable-dyload was given.
+if test "${enable_dyload+set}" = set; then :
+  enableval=$enable_dyload;  case "${enableval}" in
+	     yes|"")
+		     U_ENABLE_DYLOAD=1
+		     enabled=check ;;
+	     no)
+	     	 U_ENABLE_DYLOAD=0;
+	     	 enabled=disabled ;;
+	     *) ;;
+    esac
+fi
+
+
+
+# goes into icucfg.h
+for ac_header in dlfcn.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default"
+if test "x$ac_cv_header_dlfcn_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+U_CHECK_DYLOAD=0
+#AC_MSG_RESULT($enabled)
+if test "$enabled" = "check"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5
+$as_echo_n "checking for library containing dlopen... " >&6; }
+if test "${ac_cv_search_dlopen+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' dl; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_dlopen=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if test "${ac_cv_search_dlopen+set}" = set; then :
+  break
+fi
+done
+if test "${ac_cv_search_dlopen+set}" = set; then :
+
+else
+  ac_cv_search_dlopen=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5
+$as_echo "$ac_cv_search_dlopen" >&6; }
+ac_res=$ac_cv_search_dlopen
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+    for ac_func in dlopen
+do :
+  ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DLOPEN 1
+_ACEOF
+
+fi
+done
+
+    U_CHECK_DYLOAD=1
+fi
+
+
+# Check for miscellanous functions.
+# These only go into common/icucfg.h and are NOT exported with ICU builds.
+# So, use for putil / tools only.
+# Note that this will generate HAVE_GETTIMEOFDAY, not U_HAVE_GETTIMEOFDAY
+# rerun 'autoheader' to regenerate icucfg.h.in
+for ac_func in gettimeofday
+do :
+  ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday"
+if test "x$ac_cv_func_gettimeofday" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_GETTIMEOFDAY 1
+_ACEOF
+
+fi
+done
+
+
+# Check whether to use the evil rpath or not
+# Check whether --enable-rpath was given.
+if test "${enable_rpath+set}" = set; then :
+  enableval=$enable_rpath;  case "${enableval}" in
+	     yes|"") ENABLE_RPATH=YES ;;
+	     no) ;;
+	     *) ;;
+    esac
+else
+  ENABLE_RPATH=NO
+
+fi
+
+
+
+
+# set up U_INLINE.
+# Copy the definition of AC_C_INLINE, with slight mods.
+#
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for definition of U_INLINE for C" >&5
+$as_echo_n "checking for definition of U_INLINE for C... " >&6; }
+if test "${ac_cv_c_inline+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+return 0;} $ac_kw int foo() {
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_inline=$ac_kw; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
+$as_echo "$ac_cv_c_inline" >&6; }
+case "$ac_cv_c_inline" in
+      yes)       U_INLINE= "inline" ;;
+	  no )       U_INLINE= ;;
+	    *)       U_INLINE=$ac_cv_c_inline ;;
+esac
+
+
+# set up U_HAVE_STD_STRING.
+# Copy the definition of AC_C_INLINE, with slight mods.
+#
+U_HAVE_STD_STRING=0
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have a C++ compiler" >&5
+$as_echo_n "checking if we have a C++ compiler... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  cxx_okay=yes
+else
+  cxx_okay=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+if test $cxx_okay = yes
+then
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: congratulations" >&5
+$as_echo "congratulations" >&6; }
+else
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+	as_fn_error $? "C++ compiler $CXX does not work or no compiler found" "$LINENO" 5
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if #include <string> works" >&5
+$as_echo_n "checking if #include <string> works... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string>
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_header_stdstring=yes
+else
+  ac_cv_header_stdstring=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdstring" >&5
+$as_echo "$ac_cv_header_stdstring" >&6; }
+if test $ac_cv_header_stdstring = yes
+then
+	U_HAVE_STD_STRING=1
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+threads=true
+
+# Enable/disable threads
+# Check whether --enable-threads was given.
+if test "${enable_threads+set}" = set; then :
+  enableval=$enable_threads; case "${enableval}" in
+		yes) threads=true ;;
+		no)  threads=false ;;
+		*) as_fn_error $? "bad value ${enableval} for --enable-threads" "$LINENO" 5 ;;
+		esac
+else
+  threads=true
+fi
+
+
+if test "$threads" = true; then
+  THREADS_TRUE=
+else
+  THREADS_TRUE='#'
+fi
+
+ICU_USE_THREADS=0
+OLD_LIBS=${LIBS}
+
+if test $threads = true; then
+  # For Compaq Tru64 (OSF1), we must look for pthread_attr_init
+  # and must do this before seaching for pthread_mutex_destroy, or
+  # we will pick up libpthreads.so not libpthread.so
+  # If this fails, then we must test for HPUX specials, before
+  # moving on to a more generic test
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_attr_init in -lpthread" >&5
+$as_echo_n "checking for pthread_attr_init in -lpthread... " >&6; }
+if test "${ac_cv_lib_pthread_pthread_attr_init+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_attr_init ();
+int
+main ()
+{
+return pthread_attr_init ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_pthread_pthread_attr_init=yes
+else
+  ac_cv_lib_pthread_pthread_attr_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_attr_init" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_attr_init" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_attr_init" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+  LIBS="-lpthread $LIBS"
+
+fi
+
+  if test $ac_cv_lib_pthread_pthread_attr_init = yes; then
+    ICU_USE_THREADS=1
+  else
+    # Locate the right library for POSIX threads. We look for the
+    # symbols in the libraries first, because on Solaris libc provides
+    # pthread_create but libpthread has the real code :(
+    # AIX uses libpthreads instead of libpthread, and HP/UX uses libpthread
+    # FreeBSD users may need libpthread if they do not have libc_r.
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_mutex_destroy" >&5
+$as_echo_n "checking for library containing pthread_mutex_destroy... " >&6; }
+if test "${ac_cv_search_pthread_mutex_destroy+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS="$LIBS"
+ac_cv_search_pthread_mutex_destroy="no"
+for i in pthread pthreads c_r ; do
+LIBS="-l$i  $ac_func_search_save_LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_mutex_destroy ();
+int
+main ()
+{
+return pthread_mutex_destroy ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_pthread_mutex_destroy="-l$i"
+break
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+done
+if test "$ac_cv_search_pthread_mutex_destroy" = "no"; then
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_mutex_destroy ();
+int
+main ()
+{
+return pthread_mutex_destroy ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_pthread_mutex_destroy="none required"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+LIBS="$ac_func_search_save_LIBS"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_mutex_destroy" >&5
+$as_echo "$ac_cv_search_pthread_mutex_destroy" >&6; }
+if test "$ac_cv_search_pthread_mutex_destroy" != "no"; then
+  test "$ac_cv_search_pthread_mutex_destroy" = "none required" || LIBS="$ac_cv_search_pthread_mutex_destroy $LIBS"
+
+else :
+
+fi
+
+    if test "$ac_cv_search_pthread_mutex_destroy" != no; then
+      ICU_USE_THREADS=1
+    else
+      # For HP 11
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthread" >&5
+$as_echo_n "checking for pthread_mutex_init in -lpthread... " >&6; }
+if test "${ac_cv_lib_pthread_pthread_mutex_init+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_mutex_init ();
+int
+main ()
+{
+return pthread_mutex_init ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_pthread_pthread_mutex_init=yes
+else
+  ac_cv_lib_pthread_pthread_mutex_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_mutex_init" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_mutex_init" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_mutex_init" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+  LIBS="-lpthread $LIBS"
+
+fi
+
+      if test $ac_cv_lib_pthread_pthread_mutex_init = yes; then
+        ICU_USE_THREADS=1
+      fi
+    fi
+
+    ac_fn_c_check_func "$LINENO" "pthread_mutex_lock" "ac_cv_func_pthread_mutex_lock"
+if test "x$ac_cv_func_pthread_mutex_lock" = x""yes; then :
+
+fi
+
+
+    if test $ac_cv_func_pthread_mutex_lock = yes; then
+      ICU_USE_THREADS=1
+    fi
+  fi
+  # Check to see if we are using CygWin with MSVC
+  case "${host}" in
+  *-pc-cygwin*|*-pc-mingw*)
+    # For gcc, the thread options are set by mh-mingw/mh-cygwin
+    # For msvc, the thread options are set by runConfigureICU
+    ICU_USE_THREADS=1
+    ;;
+  *-*-hpux*)
+    # Add -mt because it does several nice things on newer compilers.
+    case "${icu_cv_host_frag}" in
+      mh-hpux-acc)
+        OLD_CXXFLAGS="${CXXFLAGS}"
+        CXXFLAGS="${CXXFLAGS} -mt"
+        if test x"`${CXX} ${CXXFLAGS} 2>&1`" != x""; then
+           CXXFLAGS="${OLD_CXXFLAGS}"
+       fi
+      ;;
+    esac
+    ;;
+  *-*-solaris*)
+    case "${icu_cv_host_frag}" in
+      mh-solaris)
+           LIBS="${LIBS} -mt"
+      ;;
+    esac
+    ;;
+  esac
+fi
+
+
+
+# Check whether --enable-weak-threads was given.
+if test "${enable_weak_threads+set}" = set; then :
+  enableval=$enable_weak_threads; case "${enableval}" in
+		yes)
+            LIB_THREAD="${LIBS%${OLD_LIBS}}"
+            LIBS=${OLD_LIBS}
+            ;;
+		no)  ;;
+		*) as_fn_error $? "bad value ${enableval} for --enable-weak-threads" "$LINENO" 5 ;;
+		esac
+fi
+
+
+
+# Check for mmap()
+
+# The AC_FUNC_MMAP macro doesn't work properly.  It seems to be too specific.
+# Do this check instead.
+HAVE_MMAP=0
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for mmap" >&5
+$as_echo_n "checking for mmap... " >&6; }
+if test "${ac_cv_func_mmap_ok+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+int
+main ()
+{
+mmap((void *)0, 0, PROT_READ, 0, 0, 0);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_func_mmap_ok=yes
+else
+  ac_cv_func_mmap_ok=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_ok" >&5
+$as_echo "$ac_cv_func_mmap_ok" >&6; }
+if test $ac_cv_func_mmap_ok = yes
+then
+    HAVE_MMAP=1
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for genccode assembly" >&5
+$as_echo_n "checking for genccode assembly... " >&6; }
+
+# Check to see if genccode can generate simple assembly.
+GENCCODE_ASSEMBLY=
+case "${host}" in
+*-linux*|i*86-*-*bsd*|i*86-pc-gnu)
+    if test "$GCC" = yes; then
+        # We're using gcc, and the simple -a gcc command line works for genccode
+        GENCCODE_ASSEMBLY="-a gcc"
+    fi ;;
+i*86-*-solaris*)
+    if test "$GCC" = yes; then
+        # When using gcc, look if we're also using GNU as.
+        # When using GNU as, the simple -a gcc command line works for genccode.
+        asv=`"${CC}" -print-prog-name=as 2>/dev/null`
+        asv=`"${asv}" --version 2>/dev/null`
+        case "X${asv}" in
+        X*GNU*) GENCCODE_ASSEMBLY="-a gcc" ;;
+        X*) GENCCODE_ASSEMBLY="-a sun-x86" ;;
+        esac
+        unset asv
+    else
+        GENCCODE_ASSEMBLY="-a sun-x86"
+    fi ;;
+sparc-*-solaris*)
+    GENCCODE_ASSEMBLY="-a sun"
+    ;;
+ia64-*-hpux*)
+    GENCCODE_ASSEMBLY="-a aCC-ia64"
+    ;;
+esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $GENCCODE_ASSEMBLY" >&5
+$as_echo "$GENCCODE_ASSEMBLY" >&6; }
+
+# Checks for header files
+for ac_header in inttypes.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "inttypes.h" "ac_cv_header_inttypes_h" "$ac_includes_default"
+if test "x$ac_cv_header_inttypes_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_INTTYPES_H 1
+_ACEOF
+
+fi
+
+done
+
+if test $ac_cv_header_inttypes_h = no; then
+ U_HAVE_INTTYPES_H=0
+else
+ U_HAVE_INTTYPES_H=1
+fi
+if test "$CC" = ccc; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"C compiler set to CCC ${CC}\" " >&5
+$as_echo "\"C compiler set to CCC ${CC}\" " >&6; }
+ case "${host}" in
+        alpha*-*-*) U_HAVE_INTTYPES_H=0;
+ esac
+fi
+
+
+
+for ac_header in dirent.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "dirent.h" "ac_cv_header_dirent_h" "$ac_includes_default"
+if test "x$ac_cv_header_dirent_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DIRENT_H 1
+_ACEOF
+
+fi
+
+done
+
+if test $ac_cv_header_dirent_h = no; then
+ U_HAVE_DIRENT_H=0
+else
+ U_HAVE_DIRENT_H=1
+fi
+
+
+
+
+
+# Check whether --with-iostream was given.
+if test "${with_iostream+set}" = set; then :
+  withval=$with_iostream; case "${withval}" in
+		none) streams=none ;;
+		old) streams=198506 ;;
+		std) streams=199711 ;;
+		auto) streams= ;;
+		*) as_fn_error $? "bad value ${withval} for --with-iostream" "$LINENO" 5 ;;
+		esac
+else
+  streams=
+fi
+
+
+U_IOSTREAM_SOURCE=0
+if test x$streams != xnone
+then
+    ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+    OLD_CXXFLAGS="${CXXFLAGS}"
+    case "${icu_cv_host_frag}" in
+        mh-hpux-acc)
+            CXXFLAGS="${CXXFLAGS} -AA"
+        ;;
+    esac
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iostream usability" >&5
+$as_echo_n "checking for iostream usability... " >&6; }
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <iostream>
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_header_iostream=yes
+else
+  ac_cv_header_iostream=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    if test $icu_cv_host_frag = mh-cygwin-msvc
+    then
+        # <iostream> is always there on Windows.
+        # We do this to prevent the C++ preprocessor from being used because
+        # autoconf can't deal with the Windows C++ preprocessor
+        ac_cv_header_iostream=yes
+    fi
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_iostream" >&5
+$as_echo "$ac_cv_header_iostream" >&6; }
+    if test $ac_cv_header_iostream = yes
+    then
+        U_IOSTREAM_SOURCE=199711
+    else
+        CXXFLAGS="${OLD_CXXFLAGS}"
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ostream in iostream.h is really defined" >&5
+$as_echo_n "checking whether ostream in iostream.h is really defined... " >&6; }
+        if test "${ac_cv_iostream_ok+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <iostream.h>
+int
+main ()
+{
+ostream &testout = cout; testout << "test" << endl;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_iostream_ok=yes
+else
+  ac_cv_iostream_ok=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_iostream_ok" >&5
+$as_echo "$ac_cv_iostream_ok" >&6; }
+        if test $ac_cv_iostream_ok = yes
+        then
+            U_IOSTREAM_SOURCE=198506
+        fi
+    fi
+    if test x$streams != x
+    then
+        if test $U_IOSTREAM_SOURCE -ge $streams
+        then
+            U_IOSTREAM_SOURCE=$streams
+            case "${icu_cv_host_frag}" in
+                mh-hpux-acc)
+                    if test $U_IOSTREAM_SOURCE -lt 199711; then
+                        CXXFLAGS=${OLD_CXXFLAGS}
+                    fi
+                ;;
+            esac
+        else
+            as_fn_error $? "${withval} iostream is not available" "$LINENO" 5
+        fi
+    fi
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Check for endianness
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
+if test "${ac_cv_c_bigendian+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_bigendian=unknown
+    # See if we're dealing with a universal compiler.
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifndef __APPLE_CC__
+	       not a universal capable compiler
+	     #endif
+	     typedef int dummy;
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+	# Check for potential -arch flags.  It is not universal unless
+	# there are at least two -arch flags with different values.
+	ac_arch=
+	ac_prev=
+	for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
+	 if test -n "$ac_prev"; then
+	   case $ac_word in
+	     i?86 | x86_64 | ppc | ppc64)
+	       if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
+		 ac_arch=$ac_word
+	       else
+		 ac_cv_c_bigendian=universal
+		 break
+	       fi
+	       ;;
+	   esac
+	   ac_prev=
+	 elif test "x$ac_word" = "x-arch"; then
+	   ac_prev=arch
+	 fi
+       done
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    if test $ac_cv_c_bigendian = unknown; then
+      # See if sys/param.h defines the BYTE_ORDER macro.
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+	     #include <sys/param.h>
+
+int
+main ()
+{
+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
+		     && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
+		     && LITTLE_ENDIAN)
+	      bogus endian macros
+	     #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+		#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+		 not big endian
+		#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_bigendian=yes
+else
+  ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    fi
+    if test $ac_cv_c_bigendian = unknown; then
+      # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+	      bogus endian macros
+	     #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  # It does; now see whether it defined to _BIG_ENDIAN or not.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#ifndef _BIG_ENDIAN
+		 not big endian
+		#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_bigendian=yes
+else
+  ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    fi
+    if test $ac_cv_c_bigendian = unknown; then
+      # Compile a test program.
+      if test "$cross_compiling" = yes; then :
+  # Try to guess by grepping values from an object file.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+short int ascii_mm[] =
+		  { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+		short int ascii_ii[] =
+		  { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+		int use_ascii (int i) {
+		  return ascii_mm[i] + ascii_ii[i];
+		}
+		short int ebcdic_ii[] =
+		  { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+		short int ebcdic_mm[] =
+		  { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+		int use_ebcdic (int i) {
+		  return ebcdic_mm[i] + ebcdic_ii[i];
+		}
+		extern int foo;
+
+int
+main ()
+{
+return use_ascii (foo) == use_ebcdic (foo);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
+	      ac_cv_c_bigendian=yes
+	    fi
+	    if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+	      if test "$ac_cv_c_bigendian" = unknown; then
+		ac_cv_c_bigendian=no
+	      else
+		# finding both strings is unlikely to happen, but who knows?
+		ac_cv_c_bigendian=unknown
+	      fi
+	    fi
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+
+	     /* Are we little or big endian?  From Harbison&Steele.  */
+	     union
+	     {
+	       long int l;
+	       char c[sizeof (long int)];
+	     } u;
+	     u.l = 1;
+	     return u.c[sizeof (long int) - 1] == 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_c_bigendian=no
+else
+  ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+    fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
+$as_echo "$ac_cv_c_bigendian" >&6; }
+ case $ac_cv_c_bigendian in #(
+   yes)
+     $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h
+;; #(
+   no)
+      ;; #(
+   universal)
+
+$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+
+     ;; #(
+   *)
+     as_fn_error $? "unknown endianness
+ presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
+ esac
+
+if test $ac_cv_c_bigendian = no; then
+U_IS_BIG_ENDIAN=0
+U_ENDIAN_CHAR="l"
+else
+U_IS_BIG_ENDIAN=1
+U_ENDIAN_CHAR="b"
+fi
+
+
+# Do various POSIX related checks
+U_HAVE_NL_LANGINFO_CODESET=0
+U_NL_LANGINFO_CODESET=-1
+ac_fn_c_check_func "$LINENO" "nl_langinfo" "ac_cv_func_nl_langinfo"
+if test "x$ac_cv_func_nl_langinfo" = x""yes; then :
+  U_HAVE_NL_LANGINFO=1
+else
+  U_HAVE_NL_LANGINFO=0
+fi
+
+if test $U_HAVE_NL_LANGINFO -eq 1; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_langinfo's argument to obtain the codeset" >&5
+$as_echo_n "checking for nl_langinfo's argument to obtain the codeset... " >&6; }
+if test "${ac_cv_nl_langinfo_codeset+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_nl_langinfo_codeset="unknown"
+  for a in CODESET _NL_CTYPE_CODESET_NAME; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <langinfo.h>
+int
+main ()
+{
+nl_langinfo($a);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_nl_langinfo_codeset="$a"; break
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_nl_langinfo_codeset" >&5
+$as_echo "$ac_cv_nl_langinfo_codeset" >&6; }
+  if test x$ac_cv_nl_langinfo_codeset != xunknown
+  then
+      U_HAVE_NL_LANGINFO_CODESET=1
+      U_NL_LANGINFO_CODESET=$ac_cv_nl_langinfo_codeset
+  fi
+fi
+
+
+
+# Namespace support checks
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for namespace support" >&5
+$as_echo_n "checking for namespace support... " >&6; }
+if test "${ac_cv_namespace_ok+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+namespace x_version {void f(){}}
+    namespace x = x_version;
+    using namespace x_version;
+
+int
+main ()
+{
+f();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_namespace_ok=yes
+else
+  ac_cv_namespace_ok=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_namespace_ok" >&5
+$as_echo "$ac_cv_namespace_ok" >&6; }
+U_HAVE_NAMESPACE=1
+if test $ac_cv_namespace_ok = no
+then
+    U_HAVE_NAMESPACE=0
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for properly overriding new and delete" >&5
+$as_echo_n "checking for properly overriding new and delete... " >&6; }
+U_OVERRIDE_CXX_ALLOCATION=0
+U_HAVE_PLACEMENT_NEW=0
+if test "${ac_cv_override_cxx_allocation_ok+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+    class UMemory {
+    public:
+    void *operator new(size_t size) {return malloc(size);}
+    void *operator new[](size_t size) {return malloc(size);}
+    void operator delete(void *p) {free(p);}
+    void operator delete[](void *p) {free(p);}
+    };
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_override_cxx_allocation_ok=yes
+else
+  ac_cv_override_cxx_allocation_ok=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_override_cxx_allocation_ok" >&5
+$as_echo "$ac_cv_override_cxx_allocation_ok" >&6; }
+if test $ac_cv_override_cxx_allocation_ok = yes
+then
+    U_OVERRIDE_CXX_ALLOCATION=1
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for placement new and delete" >&5
+$as_echo_n "checking for placement new and delete... " >&6; }
+    if test "${ac_cv_override_placement_new_ok+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+        class UMemory {
+        public:
+        void *operator new(size_t size) {return malloc(size);}
+        void *operator new[](size_t size) {return malloc(size);}
+        void operator delete(void *p) {free(p);}
+        void operator delete[](void *p) {free(p);}
+        void * operator new(size_t, void *ptr) { return ptr; }
+        void operator delete(void *, void *) {}
+        };
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_override_placement_new_ok=yes
+else
+  ac_cv_override_placement_new_ok=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_override_placement_new_ok" >&5
+$as_echo "$ac_cv_override_placement_new_ok" >&6; }
+    if test $ac_cv_override_placement_new_ok = yes
+    then
+        U_HAVE_PLACEMENT_NEW=1
+    fi
+fi
+
+
+
+# gcc atomic built-in functions check
+# AC_TRY_LINK([], [int foo, bar; bar = __sync_val_compare_and_swap(&foo, 0, 1);],,
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc atomic functions" >&5
+$as_echo_n "checking for gcc atomic functions... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+        void *p;
+        int   i;
+
+int
+main ()
+{
+
+        __sync_fetch_and_add(&i, 1);
+        __sync_fetch_and_sub(&i, 1);
+        __sync_val_compare_and_swap(&p, 0, 0);
+
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  U_HAVE_GCC_ATOMICS=1; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  U_HAVE_GCC_ATOMICS=0; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_fn_c_check_func "$LINENO" "popen" "ac_cv_func_popen"
+if test "x$ac_cv_func_popen" = x""yes; then :
+
+fi
+
+if test x$ac_cv_func_popen = xyes
+then
+     U_HAVE_POPEN=1
+else
+     U_HAVE_POPEN=0
+fi
+
+
+ac_fn_c_check_func "$LINENO" "tzset" "ac_cv_func_tzset"
+if test "x$ac_cv_func_tzset" = x""yes; then :
+
+fi
+
+U_HAVE_TZSET=0
+if test x$ac_cv_func_tzset = xyes
+then
+    U_TZSET=tzset
+    U_HAVE_TZSET=1
+else
+    ac_fn_c_check_func "$LINENO" "_tzset" "ac_cv_func__tzset"
+if test "x$ac_cv_func__tzset" = x""yes; then :
+
+fi
+
+    if test x$ac_cv_func__tzset = xyes
+    then
+        U_TZSET=_tzset
+        U_HAVE_TZSET=1
+    fi
+fi
+
+
+
+U_HAVE_TZNAME=0
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5
+$as_echo_n "checking for tzname... " >&6; }
+if test "${ac_cv_var_tzname+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifndef __USE_POSIX
+#define __USE_POSIX
+#endif
+#include <stdlib.h>
+#include <time.h>
+#ifndef tzname /* For SGI.  */
+extern char *tzname[]; /* RS6000 and others reject char **tzname.  */
+#endif
+int
+main ()
+{
+atoi(*tzname);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_var_tzname=yes
+else
+  ac_cv_var_tzname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_var_tzname" >&5
+$as_echo "$ac_cv_var_tzname" >&6; }
+if test $ac_cv_var_tzname = yes; then
+  U_TZNAME=tzname
+  U_HAVE_TZNAME=1
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _tzname" >&5
+$as_echo_n "checking for _tzname... " >&6; }
+if test "${ac_cv_var__tzname+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+  #include <time.h>
+  extern char *_tzname[];
+int
+main ()
+{
+atoi(*_tzname);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_var__tzname=yes
+else
+  ac_cv_var__tzname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_var__tzname" >&5
+$as_echo "$ac_cv_var__tzname" >&6; }
+    if test $ac_cv_var__tzname = yes; then
+      U_TZNAME=_tzname
+      U_HAVE_TZNAME=1
+    fi
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for timezone" >&5
+$as_echo_n "checking for timezone... " >&6; }
+if test "${ac_cv_var_timezone+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifndef __USE_POSIX
+#define __USE_POSIX
+#endif
+#ifndef __USE_XOPEN
+#define __USE_XOPEN
+#endif
+#include <time.h>
+
+int
+main ()
+{
+timezone = 1;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_var_timezone=yes
+else
+  ac_cv_var_timezone=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_var_timezone" >&5
+$as_echo "$ac_cv_var_timezone" >&6; }
+U_HAVE_TIMEZONE=0
+if test $ac_cv_var_timezone = yes; then
+  U_TIMEZONE=timezone
+  U_HAVE_TIMEZONE=1
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __timezone" >&5
+$as_echo_n "checking for __timezone... " >&6; }
+if test "${ac_cv_var___timezone+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <time.h>
+int
+main ()
+{
+__timezone = 1;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_var___timezone=yes
+else
+  ac_cv_var___timezone=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_var___timezone" >&5
+$as_echo "$ac_cv_var___timezone" >&6; }
+  if test $ac_cv_var___timezone = yes; then
+    U_TIMEZONE=__timezone
+    U_HAVE_TIMEZONE=1
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _timezone" >&5
+$as_echo_n "checking for _timezone... " >&6; }
+if test "${ac_cv_var__timezone+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <time.h>
+int
+main ()
+{
+_timezone = 1;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_var__timezone=yes
+else
+  ac_cv_var__timezone=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_var__timezone" >&5
+$as_echo "$ac_cv_var__timezone" >&6; }
+    if test $ac_cv_var__timezone = yes; then
+      U_TIMEZONE=_timezone
+      U_HAVE_TIMEZONE=1
+    fi
+  fi
+fi
+
+
+
+# Checks for typedefs
+ac_fn_c_check_type "$LINENO" "int8_t" "ac_cv_type_int8_t" "$ac_includes_default"
+if test "x$ac_cv_type_int8_t" = x""yes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define int8_t signed char
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "uint8_t" "ac_cv_type_uint8_t" "$ac_includes_default"
+if test "x$ac_cv_type_uint8_t" = x""yes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define uint8_t unsigned char
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "int16_t" "ac_cv_type_int16_t" "$ac_includes_default"
+if test "x$ac_cv_type_int16_t" = x""yes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define int16_t signed short
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "uint16_t" "ac_cv_type_uint16_t" "$ac_includes_default"
+if test "x$ac_cv_type_uint16_t" = x""yes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define uint16_t unsigned short
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "int32_t" "ac_cv_type_int32_t" "$ac_includes_default"
+if test "x$ac_cv_type_int32_t" = x""yes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define int32_t signed long
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "uint32_t" "ac_cv_type_uint32_t" "$ac_includes_default"
+if test "x$ac_cv_type_uint32_t" = x""yes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define uint32_t unsigned long
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "int64_t" "ac_cv_type_int64_t" "$ac_includes_default"
+if test "x$ac_cv_type_int64_t" = x""yes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define int64_t signed long long
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "uint64_t" "ac_cv_type_uint64_t" "$ac_includes_default"
+if test "x$ac_cv_type_uint64_t" = x""yes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define uint64_t unsigned long long
+_ACEOF
+
+fi
+
+
+if test $ac_cv_type_int8_t = no; then
+HAVE_INT8_T=0
+else
+HAVE_INT8_T=1
+fi
+
+
+if test $ac_cv_type_uint8_t = no; then
+HAVE_UINT8_T=0
+else
+HAVE_UINT8_T=1
+fi
+
+
+if test $ac_cv_type_int16_t = no; then
+HAVE_INT16_T=0
+else
+HAVE_INT16_T=1
+fi
+
+
+if test $ac_cv_type_uint16_t = no; then
+HAVE_UINT16_T=0
+else
+HAVE_UINT16_T=1
+fi
+
+
+if test $ac_cv_type_int32_t = no; then
+HAVE_INT32_T=0
+else
+HAVE_INT32_T=1
+fi
+
+
+if test $ac_cv_type_uint32_t = no; then
+HAVE_UINT32_T=0
+else
+HAVE_UINT32_T=1
+fi
+
+
+if test $ac_cv_type_int64_t = no; then
+HAVE_INT64_T=0
+else
+HAVE_INT64_T=1
+fi
+
+
+if test $ac_cv_type_uint64_t = no; then
+HAVE_UINT64_T=0
+else
+HAVE_UINT64_T=1
+fi
+
+
+# Do various wchar_t related checks
+ac_fn_c_check_header_mongrel "$LINENO" "wchar.h" "ac_cv_header_wchar_h" "$ac_includes_default"
+if test "x$ac_cv_header_wchar_h" = x""yes; then :
+
+fi
+
+
+if test "$ac_cv_header_wchar_h" = no
+then
+    U_HAVE_WCHAR_H=0
+    U_HAVE_WCSCPY=0
+else
+
+$as_echo "#define HAVE_WCHAR_H 1" >>confdefs.h
+
+    U_HAVE_WCHAR_H=1
+    # Some broken systems have wchar.h but not some of its functions...
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing wcscpy" >&5
+$as_echo_n "checking for library containing wcscpy... " >&6; }
+if test "${ac_cv_search_wcscpy+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char wcscpy ();
+int
+main ()
+{
+return wcscpy ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' wcs w; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_wcscpy=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if test "${ac_cv_search_wcscpy+set}" = set; then :
+  break
+fi
+done
+if test "${ac_cv_search_wcscpy+set}" = set; then :
+
+else
+  ac_cv_search_wcscpy=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_wcscpy" >&5
+$as_echo "$ac_cv_search_wcscpy" >&6; }
+ac_res=$ac_cv_search_wcscpy
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+    if test "$ac_cv_search_wcscpy" != no; then
+      U_HAVE_WCSCPY=1
+    else
+      U_HAVE_WCSCPY=0
+    fi
+fi
+
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of wchar_t" >&5
+$as_echo_n "checking size of wchar_t... " >&6; }
+if test "${ac_cv_sizeof_wchar_t+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (wchar_t))" "ac_cv_sizeof_wchar_t"        "
+#if STDC_HEADERS
+#include <stddef.h>
+#endif
+#include <stdlib.h>
+#if HAVE_WCHAR_H
+#include <string.h>
+#include <wchar.h>
+#endif
+"; then :
+
+else
+  if test "$ac_cv_type_wchar_t" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (wchar_t)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_wchar_t=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_wchar_t" >&5
+$as_echo "$ac_cv_sizeof_wchar_t" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_WCHAR_T $ac_cv_sizeof_wchar_t
+_ACEOF
+
+
+U_SIZEOF_WCHAR_T=$ac_cv_sizeof_wchar_t
+# We do this check to verify that everything is okay.
+if test $U_SIZEOF_WCHAR_T = 0; then
+    if test $U_HAVE_WCHAR_H=1; then
+       as_fn_error $? "There is wchar.h but the size of wchar_t is 0" "$LINENO" 5
+    fi
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for UTF-16 string literal support" >&5
+$as_echo_n "checking for UTF-16 string literal support... " >&6; }
+U_CHECK_UTF16_STRING=1
+CHECK_UTF16_STRING_RESULT="unknown"
+
+case "${host}" in
+*-*-aix*|powerpc64-*-linux*)
+    if test "$ac_cv_c_compiler_gnu" = no; then
+        OLD_CFLAGS="${CFLAGS}"
+        OLD_CXXFLAGS="${CXXFLAGS}"
+        CFLAGS="${CFLAGS} -qutf"
+        CXXFLAGS="${CXXFLAGS} -qutf"
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+const unsigned short hello[] = u"hello";
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  U_CHECK_UTF16_STRING=1
+else
+  U_CHECK_UTF16_STRING=0
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+        if test "$U_CHECK_UTF16_STRING" = 0; then
+            CFLAGS="${OLD_CFLAGS}"
+            CXXFLAGS="${OLD_CXXFLAGS}"
+        else
+            CHECK_UTF16_STRING_RESULT="-qutf"
+        fi
+    fi
+    ;;
+*-*-solaris*)
+    if test "$ac_cv_c_compiler_gnu" = no; then
+        OLD_CFLAGS="${CFLAGS}"
+        OLD_CXXFLAGS="${CXXFLAGS}"
+        CFLAGS="${CFLAGS} -xustr=ascii_utf16_ushort"
+        CXXFLAGS="${CXXFLAGS} -xustr=ascii_utf16_ushort"
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+const unsigned short hello[] = U"hello";
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  U_CHECK_UTF16_STRING=1
+else
+  U_CHECK_UTF16_STRING=0
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+        if test "$U_CHECK_UTF16_STRING" = 0; then
+            CFLAGS="${OLD_CFLAGS}"
+            CXXFLAGS="${OLD_CXXFLAGS}"
+        else
+            CHECK_UTF16_STRING_RESULT="-xustr=ascii_utf16_ushort"
+
+            # Since we can't detect the availability of this UTF-16 syntax at compile time,
+            # we depend on configure telling us that we can use it.
+            # Since we can't ensure ICU users use -xustr=ascii_utf16_ushort,
+            # we only use this macro within ICU.
+            # If an ICU user uses icu-config, this feature will be enabled.
+            CPPFLAGS="${CPPFLAGS} -DU_CHECK_UTF16_STRING=1"
+            U_CHECK_UTF16_STRING=0
+        fi
+    fi
+    ;;
+*-*-hpux*)
+    if test "$ac_cv_c_compiler_gnu" = no; then
+        # The option will be detected at compile time without additional compiler options.
+        CHECK_UTF16_STRING_RESULT="available"
+    fi
+    ;;
+*-*-cygwin)
+    # wchar_t can be used
+    CHECK_UTF16_STRING_RESULT="available"
+    ;;
+*)
+    ;;
+esac
+
+# GCC >= 4.4 supports UTF16 string literals. The CFLAGS and CXXFLAGS may change in the future.
+# Since we have to use a different standard, if strict is enable, don't enable UTF16 string literals.
+U_CHECK_GNUC_UTF16_STRING=0
+if test "$ac_use_strict_options" = no && test "$CHECK_UTF16_STRING_RESULT" = "unknown"; then
+    if test "$ac_cv_c_compiler_gnu" = yes; then
+        OLD_CFLAGS="${CFLAGS}"
+        OLD_CXXFLAGS="${CXXFLAGS}"
+        CFLAGS="${CFLAGS} -std=gnu99 -D_GCC_"
+        CXXFLAGS="${CXXFLAGS} -std=c++0x"
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
+#ifdef _GCC_
+typedef __CHAR16_TYPE__ char16_t;
+#endif
+char16_t test[] = u"This is a UTF16 literal string.";
+#else
+GCC IS TOO OLD!
+#endif
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  U_CHECK_UTF16_STRING=1
+else
+  U_CHECK_UTF16_STRING=0
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+        if test "$U_CHECK_UTF16_STRING" = 1; then
+            CHECK_UTF16_STRING_RESULT="available";
+            U_CHECK_GNUC_UTF16_STRING=1
+        else
+            CFLAGS="${OLD_CFLAGS}"
+            CXXFLAGS="${OLD_CXXFLAGS}"
+        fi
+    fi
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CHECK_UTF16_STRING_RESULT" >&5
+$as_echo "$CHECK_UTF16_STRING_RESULT" >&6; }
+
+
+# Enable/disable extras
+# Check whether --enable-extras was given.
+if test "${enable_extras+set}" = set; then :
+  enableval=$enable_extras; case "${enableval}" in
+		yes) extras=true ;;
+		no)  extras=false ;;
+		*) as_fn_error $? "bad value ${enableval} for --enable-extras" "$LINENO" 5 ;;
+		esac
+else
+  extras=true
+fi
+
+
+if test "$extras" = true; then
+  EXTRAS_TRUE=
+else
+  EXTRAS_TRUE='#'
+fi
+# Check whether --enable-icuio was given.
+if test "${enable_icuio+set}" = set; then :
+  enableval=$enable_icuio; case "${enableval}" in
+		yes) icuio=true ;;
+		no)  icuio=false ;;
+		*) as_fn_error $? "bad value ${enableval} for --enable-icuio" "$LINENO" 5 ;;
+		esac
+else
+  icuio=true
+fi
+
+
+if test "$icuio" = true; then
+  ICUIO_TRUE=
+else
+  ICUIO_TRUE='#'
+fi
+
+# Enable/disable layout
+# Check whether --enable-layout was given.
+if test "${enable_layout+set}" = set; then :
+  enableval=$enable_layout; case "${enableval}" in
+		yes) layout=true ;;
+		no)  layout=false ;;
+		*) as_fn_error $? "bad value ${enableval} for --enable-layout" "$LINENO" 5 ;;
+		esac
+else
+  layout=true
+fi
+
+
+if test "$layout" = true; then
+  LAYOUT_TRUE=
+else
+  LAYOUT_TRUE='#'
+fi
+
+
+# Check whether --with-data-packaging was given.
+if test "${with_data_packaging+set}" = set; then :
+  withval=$with_data_packaging; case "${withval}" in
+                files|archive|library) datapackaging=$withval ;;
+		auto) datapackaging=$withval ;;
+		common) datapackaging=archive ;;
+		dll) datapackaging=library ;;
+		static) datapackaging=static ;;
+		*) as_fn_error $? "bad value ${withval} for --with-data-packaging" "$LINENO" 5 ;;
+		esac
+else
+  datapackaging=
+fi
+
+
+# Note:  'thesysconfdir' is an evaluated version, for Man pages, so also for thedatadir, thelibdir, etc..
+# thesysconfdir=`eval echo $sysconfdir`
+thedatadir=`eval echo $datadir`
+# Always put raw data files in share/icu/{version}, etc.   Never use lib/icu/{version} for data files.. Actual shared libraries will go in {libdir}.
+pkgicudatadir=$datadir
+thepkgicudatadir=$thedatadir
+
+
+
+
+if test x"$datapackaging" = x -o x"$datapackaging" = xauto; then
+	# default to library
+	datapackaging=library
+	if test "$ENABLE_STATIC" = "YES"; then
+		if test "$ENABLE_SHARED" != "YES"; then
+			datapackaging=static
+		fi
+	fi
+fi
+
+datapackaging_dir=`eval echo $thedatadir`"/icu/${VERSION}"
+
+datapackaging_msg="(No explaination for mode $datapackaging.)"
+
+datapackaging_msg_path="ICU will look in $datapackaging_dir which is the installation location. Call u_setDataDirectory() or use the ICU_DATA environment variable to override."
+datapackaging_msg_set="ICU will use the linked data library. If linked with the stub library located in stubdata/, the application can use udata_setCommonData() or set a data path to override."
+datapackaging_howfound="(unknown)"
+
+case "$datapackaging" in
+    files)
+    DATA_PACKAGING_MODE=files
+    datapackaging_msg="ICU data will be stored in individual files."
+    datapackaging_howfound="$datapackaging_msg_path"
+    ;;
+    archive)
+    DATA_PACKAGING_MODE=common
+    datapackaging_msg="ICU data will be stored in a single .dat file."
+    datapackaging_howfound="$datapackaging_msg_path"
+    ;;
+    library)
+    DATA_PACKAGING_MODE=dll
+    datapackaging_msg="ICU data will be linked with ICU."
+    if test "$ENABLE_STATIC" = "YES"; then
+        datapackaging_msg="$datapackaging_msg A static data library will be built. "
+    fi
+    if test "$ENABLE_SHARED" = "YES"; then
+        datapackaging_msg="$datapackaging_msg A shared data library will be built. "
+    fi
+    datapackaging_howfound="$datapackaging_msg_set"
+    ;;
+    static)
+    DATA_PACKAGING_MODE=static
+    datapackaging_msg="ICU data will be stored in a static library."
+    datapackaging_howfound="$datapackaging_msg_set"
+    ;;
+esac
+
+
+# Sets a library suffix
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a library suffix to use" >&5
+$as_echo_n "checking for a library suffix to use... " >&6; }
+
+# Check whether --with-library-suffix was given.
+if test "${with_library_suffix+set}" = set; then :
+  withval=$with_library_suffix; ICULIBSUFFIX="${withval}"
+else
+  ICULIBSUFFIX=
+fi
+
+msg=$ICULIBSUFFIX
+if test "$msg" = ""; then
+    msg=none
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $msg" >&5
+$as_echo "$msg" >&6; }
+
+if test "$ICULIBSUFFIX" != ""
+then
+    U_HAVE_LIB_SUFFIX=1
+    ICULIBSUFFIXCNAME=`echo _$ICULIBSUFFIX | sed 's/^A-Za-z0-9_/_/g'`
+else
+    U_HAVE_LIB_SUFFIX=0
+fi
+
+
+
+# Enable/disable tests
+# Check whether --enable-tests was given.
+if test "${enable_tests+set}" = set; then :
+  enableval=$enable_tests; case "${enableval}" in
+		yes) tests=true ;;
+		no)  tests=false ;;
+		*) as_fn_error $? "bad value ${enableval} for --enable-tests" "$LINENO" 5 ;;
+		esac
+else
+  tests=true
+fi
+
+
+if test "$tests" = true; then
+  TESTS_TRUE=
+else
+  TESTS_TRUE='#'
+fi
+
+# Enable/disable samples
+# Check whether --enable-samples was given.
+if test "${enable_samples+set}" = set; then :
+  enableval=$enable_samples; case "${enableval}" in
+		yes) samples=true ;;
+		no)  samples=false ;;
+		*) as_fn_error $? "bad value ${enableval} for --enable-samples" "$LINENO" 5 ;;
+		esac
+else
+  samples=true
+fi
+
+
+if test "$samples" = true; then
+  SAMPLES_TRUE=
+else
+  SAMPLES_TRUE='#'
+fi
+
+ICUDATA_CHAR=$U_ENDIAN_CHAR
+
+# Platform-specific Makefile setup
+# set ICUDATA_CHAR to 'e' for any EBCDIC (which should be big endian) platform.
+case "${host}" in
+	*-*-solaris*) 	platform=U_SOLARIS ;;
+	*-*-linux*|*-*-gnu|*-*-k*bsd*-gnu|*-*-kopensolaris*-gnu)        platform=U_LINUX ;;
+	*-*-*bsd*|*-*-dragonfly*) 	platform=U_BSD ;;
+	*-*-aix*) 	platform=U_AIX ;;
+	*-*-hpux*) 	platform=U_HPUX ;;
+	*-apple-darwin*|*-apple-rhapsody*)	platform=U_DARWIN ;;
+	*-*-cygwin*|*-*-mingw*)	platform=U_CYGWIN ;;
+	*-*ibm-openedition*|*-*-os390*)	platform=OS390
+			if test "${ICU_ENABLE_ASCII_STRINGS}" != "1"; then
+				ICUDATA_CHAR="e"
+			fi ;;
+	*-*-os400*)	platform=OS400
+			if test "${ICU_ENABLE_ASCII_STRINGS}" != "1"; then
+				ICUDATA_CHAR="e"
+			fi ;;
+	*-*-nto*)	platform=U_QNX ;;
+	*-dec-osf*) 	platform=U_OSF ;;
+	*-*-beos)		platform=U_BEOS ;;
+	*-*-irix*)		platform=U_IRIX ;;
+	*-ncr-*)		platform=U_MPRAS ;;
+	*) 		platform=U_UNKNOWN_PLATFORM ;;
+esac
+
+
+platform_make_fragment_name="$icu_cv_host_frag"
+platform_make_fragment='$(top_srcdir)/config/'"$platform_make_fragment_name"
+
+
+
+if test "${FORCE_LIBS}" != ""; then
+   echo " *** Overriding automatically chosen LIBS=$LIBS, using instead FORCE_LIBS=${FORCE_LIBS}"  1>&6
+   LIBS=${FORCE_LIBS}
+fi
+
+
+# Now that we're done using CPPFLAGS etc. for tests, we can change it
+# for build.
+
+if test $ICU_USE_THREADS -ne 0
+then
+    CPPFLAGS="$CPPFLAGS \$(THREADSCPPFLAGS)"
+    CFLAGS="$CFLAGS \$(THREADSCFLAGS)"
+    CXXFLAGS="$CXXFLAGS \$(THREADSCXXFLAGS)"
+fi
+
+# output the Makefiles
+ac_config_files="$ac_config_files icudefs.mk Makefile data/pkgdataMakefile config/Makefile.inc config/icu.pc config/pkgdataMakefile data/Makefile stubdata/Makefile common/Makefile i18n/Makefile layout/Makefile layoutex/Makefile io/Makefile extra/Makefile extra/uconv/Makefile extra/uconv/pkgdataMakefile extra/scrptrun/Makefile tools/Makefile tools/ctestfw/Makefile tools/toolutil/Makefile tools/makeconv/Makefile tools/genrb/Makefile tools/genccode/Makefile tools/gencmn/Makefile tools/gencnval/Makefile tools/genctd/Makefile tools/gentest/Makefile tools/gennorm2/Makefile tools/genbrk/Makefile tools/gensprep/Makefile tools/icuinfo/Makefile tools/icupkg/Makefile tools/icuswap/Makefile tools/pkgdata/Makefile tools/tzcode/Makefile tools/gencfu/Makefile test/Makefile test/compat/Makefile test/testdata/Makefile test/testdata/pkgdataMakefile test/hdrtst/Makefile test/intltest/Makefile test/cintltst/Makefile test/iotest/Makefile test/letest/Makefile test/perf/Makefile test/perf/collationperf/Makefile test/perf/ubrkperf/Makefile test/perf/charperf/Makefile test/perf/convperf/Makefile test/perf/normperf/Makefile test/perf/DateFmtPerf/Makefile test/perf/strsrchperf/Makefile test/perf/unisetperf/Makefile test/perf/usetperf/Makefile test/perf/ustrperf/Makefile test/perf/utfperf/Makefile test/perf/utrie2perf/Makefile samples/Makefile samples/date/Makefile samples/cal/Makefile samples/layout/Makefile common/unicode/platform.h"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    test "x$cache_file" != "x/dev/null" &&
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+    cat confcache >$cache_file
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+	test -d "$1/.";
+      else
+	case $1 in #(
+	-*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.67.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+      --header=FILE[:TEMPLATE]
+                   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.67,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "common/icucfg.h") CONFIG_HEADERS="$CONFIG_HEADERS common/icucfg.h" ;;
+    "icudefs.mk") CONFIG_FILES="$CONFIG_FILES icudefs.mk" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "data/pkgdataMakefile") CONFIG_FILES="$CONFIG_FILES data/pkgdataMakefile" ;;
+    "config/Makefile.inc") CONFIG_FILES="$CONFIG_FILES config/Makefile.inc" ;;
+    "config/icu.pc") CONFIG_FILES="$CONFIG_FILES config/icu.pc" ;;
+    "config/pkgdataMakefile") CONFIG_FILES="$CONFIG_FILES config/pkgdataMakefile" ;;
+    "data/Makefile") CONFIG_FILES="$CONFIG_FILES data/Makefile" ;;
+    "stubdata/Makefile") CONFIG_FILES="$CONFIG_FILES stubdata/Makefile" ;;
+    "common/Makefile") CONFIG_FILES="$CONFIG_FILES common/Makefile" ;;
+    "i18n/Makefile") CONFIG_FILES="$CONFIG_FILES i18n/Makefile" ;;
+    "layout/Makefile") CONFIG_FILES="$CONFIG_FILES layout/Makefile" ;;
+    "layoutex/Makefile") CONFIG_FILES="$CONFIG_FILES layoutex/Makefile" ;;
+    "io/Makefile") CONFIG_FILES="$CONFIG_FILES io/Makefile" ;;
+    "extra/Makefile") CONFIG_FILES="$CONFIG_FILES extra/Makefile" ;;
+    "extra/uconv/Makefile") CONFIG_FILES="$CONFIG_FILES extra/uconv/Makefile" ;;
+    "extra/uconv/pkgdataMakefile") CONFIG_FILES="$CONFIG_FILES extra/uconv/pkgdataMakefile" ;;
+    "extra/scrptrun/Makefile") CONFIG_FILES="$CONFIG_FILES extra/scrptrun/Makefile" ;;
+    "tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
+    "tools/ctestfw/Makefile") CONFIG_FILES="$CONFIG_FILES tools/ctestfw/Makefile" ;;
+    "tools/toolutil/Makefile") CONFIG_FILES="$CONFIG_FILES tools/toolutil/Makefile" ;;
+    "tools/makeconv/Makefile") CONFIG_FILES="$CONFIG_FILES tools/makeconv/Makefile" ;;
+    "tools/genrb/Makefile") CONFIG_FILES="$CONFIG_FILES tools/genrb/Makefile" ;;
+    "tools/genccode/Makefile") CONFIG_FILES="$CONFIG_FILES tools/genccode/Makefile" ;;
+    "tools/gencmn/Makefile") CONFIG_FILES="$CONFIG_FILES tools/gencmn/Makefile" ;;
+    "tools/gencnval/Makefile") CONFIG_FILES="$CONFIG_FILES tools/gencnval/Makefile" ;;
+    "tools/genctd/Makefile") CONFIG_FILES="$CONFIG_FILES tools/genctd/Makefile" ;;
+    "tools/gentest/Makefile") CONFIG_FILES="$CONFIG_FILES tools/gentest/Makefile" ;;
+    "tools/gennorm2/Makefile") CONFIG_FILES="$CONFIG_FILES tools/gennorm2/Makefile" ;;
+    "tools/genbrk/Makefile") CONFIG_FILES="$CONFIG_FILES tools/genbrk/Makefile" ;;
+    "tools/gensprep/Makefile") CONFIG_FILES="$CONFIG_FILES tools/gensprep/Makefile" ;;
+    "tools/icuinfo/Makefile") CONFIG_FILES="$CONFIG_FILES tools/icuinfo/Makefile" ;;
+    "tools/icupkg/Makefile") CONFIG_FILES="$CONFIG_FILES tools/icupkg/Makefile" ;;
+    "tools/icuswap/Makefile") CONFIG_FILES="$CONFIG_FILES tools/icuswap/Makefile" ;;
+    "tools/pkgdata/Makefile") CONFIG_FILES="$CONFIG_FILES tools/pkgdata/Makefile" ;;
+    "tools/tzcode/Makefile") CONFIG_FILES="$CONFIG_FILES tools/tzcode/Makefile" ;;
+    "tools/gencfu/Makefile") CONFIG_FILES="$CONFIG_FILES tools/gencfu/Makefile" ;;
+    "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
+    "test/compat/Makefile") CONFIG_FILES="$CONFIG_FILES test/compat/Makefile" ;;
+    "test/testdata/Makefile") CONFIG_FILES="$CONFIG_FILES test/testdata/Makefile" ;;
+    "test/testdata/pkgdataMakefile") CONFIG_FILES="$CONFIG_FILES test/testdata/pkgdataMakefile" ;;
+    "test/hdrtst/Makefile") CONFIG_FILES="$CONFIG_FILES test/hdrtst/Makefile" ;;
+    "test/intltest/Makefile") CONFIG_FILES="$CONFIG_FILES test/intltest/Makefile" ;;
+    "test/cintltst/Makefile") CONFIG_FILES="$CONFIG_FILES test/cintltst/Makefile" ;;
+    "test/iotest/Makefile") CONFIG_FILES="$CONFIG_FILES test/iotest/Makefile" ;;
+    "test/letest/Makefile") CONFIG_FILES="$CONFIG_FILES test/letest/Makefile" ;;
+    "test/perf/Makefile") CONFIG_FILES="$CONFIG_FILES test/perf/Makefile" ;;
+    "test/perf/collationperf/Makefile") CONFIG_FILES="$CONFIG_FILES test/perf/collationperf/Makefile" ;;
+    "test/perf/ubrkperf/Makefile") CONFIG_FILES="$CONFIG_FILES test/perf/ubrkperf/Makefile" ;;
+    "test/perf/charperf/Makefile") CONFIG_FILES="$CONFIG_FILES test/perf/charperf/Makefile" ;;
+    "test/perf/convperf/Makefile") CONFIG_FILES="$CONFIG_FILES test/perf/convperf/Makefile" ;;
+    "test/perf/normperf/Makefile") CONFIG_FILES="$CONFIG_FILES test/perf/normperf/Makefile" ;;
+    "test/perf/DateFmtPerf/Makefile") CONFIG_FILES="$CONFIG_FILES test/perf/DateFmtPerf/Makefile" ;;
+    "test/perf/strsrchperf/Makefile") CONFIG_FILES="$CONFIG_FILES test/perf/strsrchperf/Makefile" ;;
+    "test/perf/unisetperf/Makefile") CONFIG_FILES="$CONFIG_FILES test/perf/unisetperf/Makefile" ;;
+    "test/perf/usetperf/Makefile") CONFIG_FILES="$CONFIG_FILES test/perf/usetperf/Makefile" ;;
+    "test/perf/ustrperf/Makefile") CONFIG_FILES="$CONFIG_FILES test/perf/ustrperf/Makefile" ;;
+    "test/perf/utfperf/Makefile") CONFIG_FILES="$CONFIG_FILES test/perf/utfperf/Makefile" ;;
+    "test/perf/utrie2perf/Makefile") CONFIG_FILES="$CONFIG_FILES test/perf/utrie2perf/Makefile" ;;
+    "samples/Makefile") CONFIG_FILES="$CONFIG_FILES samples/Makefile" ;;
+    "samples/date/Makefile") CONFIG_FILES="$CONFIG_FILES samples/date/Makefile" ;;
+    "samples/cal/Makefile") CONFIG_FILES="$CONFIG_FILES samples/cal/Makefile" ;;
+    "samples/layout/Makefile") CONFIG_FILES="$CONFIG_FILES samples/layout/Makefile" ;;
+    "common/unicode/platform.h") CONFIG_FILES="$CONFIG_FILES common/unicode/platform.h" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp=
+  trap 'exit_status=$?
+  { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = ""
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
+h
+s///
+s/^/:/
+s/[	 ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[	 ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_t=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_t"; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[	 ]*#[	 ]*define[	 ][	 ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #undef with comments.  This is necessary, for example,
+    # in the case of _POSIX_SOURCE, which is predefined and required
+    # on some systems where configure will not decide to define it.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    "
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+	`' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$tmp/stdin"
+  case $ac_file in
+  -) cat "$tmp/out" && rm -f "$tmp/out";;
+  *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs"
+    } >"$tmp/config.h" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$tmp/config.h" "$ac_file" \
+	|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \
+      || as_fn_error $? "could not create -" "$LINENO" 5
+  fi
+ ;;
+
+
+  esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+echo
+echo "ICU for C/C++ $VERSION is ready to be built."
+echo "=== Important Notes: ==="
+
+if test $ICU_USE_THREADS = 0; then
+  echo
+  echo  "** ICU was configured without mutex or thread support. Multithread-safe operation will not be tested. If this is unexpected, then run configure with --enable-threads=yes or check the messages above to see why thread support was not found." 1>&6
+  echo
+fi
+
+echo "Data Packaging: $datapackaging"
+echo " This means: $datapackaging_msg"
+echo " To locate data: $datapackaging_howfound"
+
+if test -n "`$U_MAKE -v 2>&1 | grep '^GNU Make'`"; then
+echo "Building ICU: Use a GNU make such as $U_MAKE to build ICU."
+else
+echo "** WARNING: $U_MAKE may not be GNU make."
+echo "This may cause ICU to fail to build. Please make sure that GNU make"
+echo "is in your PATH so that the configure script can detect its location."
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the version of \"$U_MAKE\"" >&5
+$as_echo_n "checking the version of \"$U_MAKE\"... " >&6; }
+if "$U_MAKE" -f "$srcdir/config/gmakever.mk" PLATFORM="$platform"; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+else
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: too old or test failed - try upgrading GNU Make" >&5
+$as_echo "too old or test failed - try upgrading GNU Make" >&6; }
+fi
+
+$as_unset _CXX_CXXSUFFIX
diff --git a/source/configure.in b/source/configure.in
new file mode 100644
index 0000000..107912b
--- /dev/null
+++ b/source/configure.in
@@ -0,0 +1,1402 @@
+# -*-autoconf-*-
+AC_COPYRIGHT([ Copyright (c) 1999-2010, International Business Machines Corporation and others. All Rights Reserved. ])
+# configure.in for ICU
+# Stephen F. Booth, heavily modified by Yves and others
+
+# Check for autoconf version
+AC_PREREQ(2.67)
+
+
+# Process this file with autoconf to produce a configure script
+AC_INIT
+AC_CONFIG_SRCDIR([common/unicode/utypes.h])
+
+AC_CONFIG_HEADERS(common/icucfg.h)
+PACKAGE="icu"
+AC_SUBST(PACKAGE)
+
+# Use custom echo test for newline option
+# Current autoconf (2.65) gives incorrect echo newline option
+# for icu-config
+# This may be removed later - mow (June 17, 2010)
+ICU_ECHO_C= ICU_ECHO_N= ICU_ECHO_T=
+case `/bin/sh -c "echo -n x"` in
+-n*)
+  case `/bin/sh -c "echo 'x\c'"` in
+  *c*) ICU_ECHO_T=' ';;     # ECHO_T is single tab character.
+  *)   ICU_ECHO_C='\c';;
+  esac;;
+*)
+  ICU_ECHO_N='-n';;
+esac
+AC_SUBST(ICU_ECHO_N)
+AC_SUBST(ICU_ECHO_C)
+AC_SUBST(ICU_ECHO_T)
+
+AC_MSG_CHECKING(for ICU version numbers)
+
+# Get the ICU version from uversion.h or other headers
+geticuversion() {
+    [sed -n 's/^[ 	]*#[ 	]*define[ 	]*U_ICU_VERSION[ 	]*"\([^"]*\)".*/\1/p' "$@"]
+}
+getuversion() {
+    [sed -n 's/^[ 	]*#[ 	]*define[ 	]*U_UNICODE_VERSION[ 	]*"\([^"]*\)".*/\1/p' "$@"]
+}
+VERSION=`geticuversion $srcdir/common/unicode/uvernum.h`
+if test x"$VERSION" = x; then
+    VERSION=`geticuversion $srcdir/common/unicode/*.h`
+    if test x"$VERSION" = x; then
+        AC_MSG_ERROR([Cannot determine ICU version number from uvernum.h header file])
+    fi
+fi
+
+UNICODE_VERSION=`getuversion $srcdir/common/unicode/uchar.h`
+if test x"$UNICODE_VERSION" = x; then
+    UNICODE_VERSION=`getuversion $srcdir/common/unicode/*.h`
+    if test x"$UNICODE_VERSION" = x; then
+        AC_MSG_ERROR([Cannot determine Unicode version number from uchar.h header file])
+    fi
+fi
+# Compute a reasonable library version from the release version. This is
+# very bad, but that's wanted... We want to make sure that the LIB_VERSION
+# has at least a dot in it, so we'll add a .0 if needed.
+[LIB_VERSION=`echo $VERSION | sed -e 's/\.//' -e 's/^\([^.]*\)$/\1.0/'`]
+LIB_VERSION_MAJOR=`echo $LIB_VERSION | sed 's/\..*//'`
+AC_SUBST(VERSION)
+AC_SUBST(LIB_VERSION)
+AC_SUBST(LIB_VERSION_MAJOR)
+AC_MSG_RESULT([release $VERSION, library $LIB_VERSION, unicode version $UNICODE_VERSION])
+
+AC_SUBST(UNICODE_VERSION)
+
+# Determine the host system
+AC_CANONICAL_SYSTEM
+
+AC_SUBST(CPPFLAGS)
+
+# This variable is needed on z/OS because the C++ compiler only recognizes .C
+_CXX_CXXSUFFIX=cpp
+export _CXX_CXXSUFFIX
+
+# Check whether to build debug libraries
+AC_MSG_CHECKING([whether to build debug libraries])
+enabled=no
+ENABLE_DEBUG=0
+AC_ARG_ENABLE(debug,
+    [  --enable-debug          build debug libraries [default=no]],
+    [ case "${enableval}" in
+         yes|"") enabled=yes; ENABLE_DEBUG=1 ;;
+         *) ;;   
+    esac],  
+)
+AC_MSG_RESULT($enabled)
+AC_SUBST(ENABLE_DEBUG)
+
+# Check whether to build release libraries
+AC_MSG_CHECKING([whether to build release libraries])
+enabled=yes
+ENABLE_RELEASE=1
+AC_ARG_ENABLE(release,
+    [  --enable-release        build release libraries [default=yes]],
+    [ case "${enableval}" in
+         no) enabled=no; ENABLE_RELEASE=0 ;;
+         *) ;;   
+    esac],  
+)
+AC_MSG_RESULT($enabled)
+AC_SUBST(ENABLE_RELEASE)
+
+# Don't use the default C/CXXFLags
+: ${CFLAGS=""}
+: ${CXXFLAGS=""}
+
+# Checks for programs
+AC_PROG_CC
+AC_PROG_CXX
+
+# Ensure that if CXXFLAGS/CFLAGS were not set when calling configure, set it correctly based on (enable/disable) debug or release option
+# The release mode use is the default one for autoconf
+if test "$GCC" = yes; then
+    if test "$CFLAGS" = ""; then
+        if test "$ENABLE_DEBUG" = 1; then
+            CFLAGS=-g
+        fi
+        if test "$ENABLE_RELEASE" = 1; then
+            CFLAGS="$CFLAGS -O2"
+        fi
+    fi
+    if test "$CXXFLAGS" = ""; then
+        if test "$ENABLE_DEBUG" = 1; then
+            CXXFLAGS=-g
+        fi
+        if test "$ENABLE_RELEASE" = 1; then
+            CXXFLAGS="$CXXFLAGS -O2"
+        fi
+    fi
+fi
+
+AC_PROG_CPP
+
+AC_PROG_INSTALL
+
+AC_SUBST(cross_compiling)
+
+dnl use the pld hack to get ac_fn_cxx_try_link defined globally and not local
+AC_LANG_PUSH([C++])
+AC_LINK_IFELSE([AC_LANG_PROGRAM()])
+AC_LANG_POP([C++])
+
+# make sure install is relative to srcdir - if a script
+if test "$srcdir" = "."; then
+  # If srcdir isn't just ., then (srcdir) is already prepended.
+  if test "${ac_install_sh}" = "${INSTALL}"; then
+   INSTALL="\\\$(top_srcdir)/${ac_install_sh}"
+  fi
+fi
+
+#AC_CHECK_PROG(AUTOCONF, autoconf, autoconf, true)
+#AC_CHECK_PROG(STRIP, strip, strip, true)
+
+# Check for the platform make
+AC_PATH_PROGS(U_MAKE, gmake gnumake, make)
+AC_SUBST(U_MAKE)
+
+
+AC_ARG_WITH(cross-build,
+	[  --with-cross-build=dir specify an absolute path to the build directory of an ICU built for the current platform [default=no cross dir]],
+	[cross_buildroot="${withval}"], 
+        [cross_buildroot=""])
+
+if test "X$cross_buildroot" = "X"; then
+    if test "$cross_compiling" = "yes"; then
+        AC_MSG_ERROR([Error! Cross compiling but no --with-cross-build option specified - please supply the path to an executable ICU's build root])
+	dnl '
+    fi
+else
+    if test -f "${cross_buildroot}/config/icucross.mk"; then
+        AC_MSG_RESULT([Using cross buildroot: $cross_buildroot])
+    else
+        if test -d "${cross_buildroot}"; then
+            AC_MSG_ERROR([${cross_buildroot}/config/icucross.mk not found. Please build ICU in ${cross_buildroot} first.])
+        else
+            AC_MSG_ERROR([No such directory ${cross_buildroot} supplied as the argument to --with-cross-build. Use an absolute path.])
+        fi
+    fi
+fi
+AC_SUBST(cross_buildroot)
+
+# Check for doxygen to generate documentation
+AC_PATH_PROG(DOXYGEN,doxygen,,$PATH:/usr/local/bin:/usr/bin)
+
+# Check that the linker is usable
+ICU_PROG_LINK
+
+# Determine the executable suffix
+# We don't use AC_EXEEXT because some compilers output separate debugging
+# files, which confuses the AC_EXEEXT macro.
+AC_MSG_CHECKING(checking for executable suffix)
+case "${host}" in
+    *-*-cygwin*|*-*-mingw*)  EXEEXT=.exe ;;
+    *)      EXEEXT="" ;;
+esac
+ac_exeext=$EXEEXT
+AC_MSG_RESULT($EXEEXT)
+AC_SUBST(EXEEXT)
+
+# Determine how strict we want to be when compiling
+AC_CHECK_STRICT_COMPILE
+
+# Check if we can build and use 64-bit libraries
+AC_CHECK_64BIT_LIBS
+AC_SUBST(ARFLAGS)
+AC_SUBST(COMPILE_LINK_ENVVAR)
+
+# Determine the Makefile fragment
+ICU_CHECK_MH_FRAG
+
+# Checks for libraries and other host specific stuff
+# On HP/UX, don't link to -lm from a shared lib because it isn't
+#  PIC (at least on 10.2)
+case "${host}" in
+	*-*-hpux*) 	AC_CHECK_LIB(m, floor, LIB_M="-lm") ;;
+	
+	*) 		AC_CHECK_LIB(m, floor) 
+			LIB_M="" ;;
+esac
+AC_SUBST(LIB_M)
+
+# Check whether to build shared libraries
+AC_MSG_CHECKING([whether to build shared libraries])
+enabled=no
+AC_ARG_ENABLE(shared,
+    [  --enable-shared         build shared libraries [default=yes]],
+    [ case "${enableval}" in
+	     yes|"") enabled=yes; ENABLE_SHARED=YES ;;
+	     no);;
+	     *) ;;
+    esac],
+    [enabled=yes; ENABLE_SHARED=YES]
+)
+AC_MSG_RESULT($enabled)
+AC_SUBST(ENABLE_SHARED)
+
+# Check whether to build static libraries
+AC_MSG_CHECKING([whether to build static libraries])
+enabled=no
+AC_ARG_ENABLE(static,
+    [  --enable-static         build static libraries [default=no]],
+    [ case "${enableval}" in
+	     yes|"") enabled=yes; ENABLE_STATIC=YES ;;
+	     no) ;;
+	     *) ;;
+    esac],
+)
+AC_MSG_RESULT($enabled)
+AC_SUBST(ENABLE_STATIC)
+
+# Check whether to enable auto cleanup of libraries
+AC_MSG_CHECKING([whether to enable auto cleanup of libraries])
+enabled=no
+UCLN_NO_AUTO_CLEANUP=1
+AC_ARG_ENABLE(auto-cleanup,
+    [  --enable-auto-cleanup   enable auto cleanup of libraries [default=no]],
+    [ case "${enableval}" in
+         yes) enabled=yes; UCLN_NO_AUTO_CLEANUP=0 ;;
+         *) ;;
+    esac],
+)
+AC_MSG_RESULT($enabled)
+AC_SUBST(UCLN_NO_AUTO_CLEANUP)
+
+# MSVC floating-point option
+MSVC_RELEASE_FLAG=""
+if test $enabled = yes
+then  
+    if test $icu_cv_host_frag = mh-cygwin-msvc
+    then
+        AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+    #if defined _MSC_VER && _MSC_VER >= 1400
+    #else
+    Microsoft Visual C++ < 2005
+    #endif
+        ]], [[]])],[MSVC_RELEASE_FLAG="/fp:precise"],[MSVC_RELEASE_FLAG="/Op"])
+        
+        CFLAGS="${CFLAGS} ${MSVC_RELEASE_FLAG}"
+        CXXFLAGS="${CXXFLAGS} ${MSVC_RELEASE_FLAG}"
+    fi
+fi
+
+# Check whether to enabled draft APIs
+AC_MSG_CHECKING([whether to enable draft APIs])
+enabled=yes
+U_DEFAULT_SHOW_DRAFT=1
+AC_ARG_ENABLE(draft,
+    [  --enable-draft          enable draft APIs (and internal APIs) [default=yes]],
+    [ case "${enableval}" in
+         no) enabled=no; U_DEFAULT_SHOW_DRAFT=0 ;;
+         *) ;;
+    esac],
+)
+AC_MSG_RESULT($enabled)
+# Make sure that we can use draft API in ICU.
+if test "$U_DEFAULT_SHOW_DRAFT" = 0; then
+    CPPFLAGS="$CPPFLAGS -DU_SHOW_DRAFT_API"
+fi
+AC_SUBST(U_DEFAULT_SHOW_DRAFT)
+
+# Check if we can hide variables from 
+AC_MSG_CHECKING([for library API export])
+SHAREDLIBEXPORT=no
+U_USE_GCC_VISIBILITY_ATTRIBUTE=0
+OLD_CFLAGS="${CFLAGS}"
+OLD_CXXFLAGS="${CXXFLAGS}"
+if test "$ac_cv_c_compiler_gnu" = yes; then
+    LIBCFLAGS="-fvisibility=hidden"
+    LIBCXXFLAGS="-fvisibility=hidden"
+    CFLAGS="${CFLAGS} ${LIBCFLAGS}"
+    CXXFLAGS="${CXXFLAGS} ${LIBCXXFLAGS}"
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([[__attribute__ ((visibility ("default"))) void f(void);
+#include <stdlib.h>]], [[exit(0);]])],[SHAREDLIBEXPORT=yes],[SHAREDLIBEXPORT=no])
+    if test "$SHAREDLIBEXPORT" = no; then
+        LIBCFLAGS=
+        LIBCXXFLAGS=
+    else
+        U_USE_GCC_VISIBILITY_ATTRIBUTE=1
+    fi
+else
+    case "${host}" in
+    *-*-solaris*)
+        LIBCFLAGS="-xldscope=hidden"
+        LIBCXXFLAGS="-xldscope=hidden"
+        CFLAGS="${CFLAGS} ${LIBCFLAGS}"
+        CXXFLAGS="${CXXFLAGS} ${LIBCXXFLAGS}"
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([[__global void f(void);
+#include <stdlib.h>]], [[exit(0);]])],[SHAREDLIBEXPORT=yes],[SHAREDLIBEXPORT=no])
+        if test "$SHAREDLIBEXPORT" = no; then
+            LIBCFLAGS=
+            LIBCXXFLAGS=
+        fi
+        ;;
+    *-*-hpux*)
+        # ICU isn't set up to follow the HP syntax yet.
+        ;;
+    *)
+    esac
+fi
+# Restore to their original state because the Intel compiler chokes
+# on this option when checking for the wchar_t size, but the
+# option otherwise works.
+CFLAGS="${OLD_CFLAGS}"
+CXXFLAGS="${OLD_CXXFLAGS}"
+AC_MSG_RESULT($SHAREDLIBEXPORT)
+AC_SUBST(U_USE_GCC_VISIBILITY_ATTRIBUTE)
+AC_SUBST(LIBCFLAGS)
+AC_SUBST(LIBCXXFLAGS)
+
+AC_PROG_RANLIB
+
+# look for 'ar' the proper way
+#AC_PATH_PROG(AR,ar,[echo archiver ar not found re-run configure ; false],$PATH:/bin:/usr/bin:/usr/ccs/bin)
+AC_CHECK_TOOL(AR, ar)
+if test "x$AR" = "x"; then
+  AC_MSG_ERROR(Archiver ar not found. Set AR= or fix PATH)
+fi
+
+
+AC_MSG_CHECKING([whether to enable renaming of symbols])
+enabled=yes
+U_DISABLE_RENAMING=0
+AC_ARG_ENABLE(renaming,
+    [  --enable-renaming       add a version suffix to symbols [default=yes]],
+    [ case "${enableval}" in
+	     yes|"") enabled=yes ;;
+	     no) enabled=no; U_DISABLE_RENAMING=1 ;;
+	     *) ;;
+    esac],
+)
+AC_MSG_RESULT($enabled)
+AC_SUBST(U_DISABLE_RENAMING)
+
+AC_MSG_CHECKING([whether to enable function and data tracing])
+enabled=no
+U_ENABLE_TRACING=0
+AC_ARG_ENABLE(tracing,
+    [  --enable-tracing        enable function and data tracing [default=no]],
+    [ case "${enableval}" in
+	     yes|"") enabled=yes; U_ENABLE_TRACING=1 ;;
+	     no) enabled=no; U_ENABLE_TRACING=0 ;;
+	     *) ;;
+    esac],
+)
+AC_MSG_RESULT($enabled)
+AC_SUBST(U_ENABLE_TRACING)
+
+
+U_ENABLE_DYLOAD=1
+AC_MSG_CHECKING([whether to enable dynamic loading of plugins])
+enabled=check
+AC_ARG_ENABLE(dyload,
+    [  --disable-dyload        disable dynamic loading [default=no]],
+    [ case "${enableval}" in
+	     yes|"") 
+		     U_ENABLE_DYLOAD=1
+		     enabled=check ;;
+	     no) 
+	     	 U_ENABLE_DYLOAD=0;
+	     	 enabled=disabled ;;
+	     *) ;;
+    esac],
+)
+AC_SUBST(U_ENABLE_DYLOAD)
+
+# goes into icucfg.h
+AC_CHECK_HEADERS([dlfcn.h])
+U_CHECK_DYLOAD=0
+#AC_MSG_RESULT($enabled)
+if test "$enabled" = "check"; then
+    AC_SEARCH_LIBS([dlopen], [dl])
+    AC_CHECK_FUNCS([dlopen])
+    U_CHECK_DYLOAD=1
+fi
+AC_SUBST(U_CHECK_DYLOAD)
+
+# Check for miscellanous functions.
+# These only go into common/icucfg.h and are NOT exported with ICU builds.
+# So, use for putil / tools only.
+# Note that this will generate HAVE_GETTIMEOFDAY, not U_HAVE_GETTIMEOFDAY
+# rerun 'autoheader' to regenerate icucfg.h.in
+AC_CHECK_FUNCS([gettimeofday])
+
+# Check whether to use the evil rpath or not
+AC_ARG_ENABLE(rpath,
+    [  --enable-rpath          use rpath when linking [default is only if necessary]],
+    [ case "${enableval}" in
+	     yes|"") ENABLE_RPATH=YES ;;
+	     no) ;;
+	     *) ;;
+    esac],
+    [ENABLE_RPATH=NO]
+)
+AC_SUBST(ENABLE_RPATH)
+
+
+# set up U_INLINE.  
+# Copy the definition of AC_C_INLINE, with slight mods.
+#
+AC_CACHE_CHECK([for definition of U_INLINE for C], ac_cv_c_inline,
+[ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[return 0;} $ac_kw int foo() {]])],[ac_cv_c_inline=$ac_kw; break],[])
+  done
+  ])
+case "$ac_cv_c_inline" in
+      yes)       U_INLINE= "inline" ;;
+	  no )       U_INLINE= ;;
+	    *)       U_INLINE=$ac_cv_c_inline ;;
+esac
+AC_SUBST(U_INLINE)
+
+# set up U_HAVE_STD_STRING.
+# Copy the definition of AC_C_INLINE, with slight mods.
+#
+U_HAVE_STD_STRING=0
+AC_LANG_PUSH([C++])
+AC_MSG_CHECKING([[if we have a C++ compiler]])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[cxx_okay=yes],[cxx_okay=no])
+if test $cxx_okay = yes
+then
+	AC_MSG_RESULT([[congratulations]])
+else
+	AC_MSG_RESULT([[no]])
+	AC_MSG_ERROR([[C++ compiler $CXX does not work or no compiler found]])
+fi
+
+AC_MSG_CHECKING([[if #include <string> works]])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <string>]], [[]])], [ac_cv_header_stdstring=yes], [ac_cv_header_stdstring=no])
+AC_MSG_RESULT($ac_cv_header_stdstring)
+if test $ac_cv_header_stdstring = yes
+then
+	U_HAVE_STD_STRING=1
+fi
+AC_SUBST(U_HAVE_STD_STRING)
+AC_LANG_POP([C++])
+
+threads=true
+
+# Enable/disable threads
+AC_ARG_ENABLE(threads,
+	[  --enable-threads        build ICU with thread safety [default=yes]],
+	[case "${enableval}" in
+		yes) threads=true ;;
+		no)  threads=false ;;
+		*) AC_MSG_ERROR(bad value ${enableval} for --enable-threads) ;;
+		esac], 
+	threads=true)
+ICU_CONDITIONAL(THREADS, test "$threads" = true)
+
+ICU_USE_THREADS=0
+OLD_LIBS=${LIBS}
+
+if test $threads = true; then
+  # For Compaq Tru64 (OSF1), we must look for pthread_attr_init
+  # and must do this before seaching for pthread_mutex_destroy, or
+  # we will pick up libpthreads.so not libpthread.so
+  # If this fails, then we must test for HPUX specials, before
+  # moving on to a more generic test
+ 
+  AC_CHECK_LIB(pthread, pthread_attr_init)
+  if test $ac_cv_lib_pthread_pthread_attr_init = yes; then
+    ICU_USE_THREADS=1
+  else
+    # Locate the right library for POSIX threads. We look for the
+    # symbols in the libraries first, because on Solaris libc provides
+    # pthread_create but libpthread has the real code :(
+    # AIX uses libpthreads instead of libpthread, and HP/UX uses libpthread
+    # FreeBSD users may need libpthread if they do not have libc_r.
+
+    AC_SEARCH_LIBS_FIRST(pthread_mutex_destroy, pthread pthreads c_r )
+
+    if test "$ac_cv_search_pthread_mutex_destroy" != no; then
+      ICU_USE_THREADS=1
+    else
+      # For HP 11
+      AC_CHECK_LIB(pthread, pthread_mutex_init)
+      if test $ac_cv_lib_pthread_pthread_mutex_init = yes; then
+        ICU_USE_THREADS=1
+      fi
+    fi
+
+    AC_CHECK_FUNC(pthread_mutex_lock)
+
+    if test $ac_cv_func_pthread_mutex_lock = yes; then
+      ICU_USE_THREADS=1
+    fi
+  fi
+  # Check to see if we are using CygWin with MSVC
+  case "${host}" in
+  *-pc-cygwin*|*-pc-mingw*)
+    # For gcc, the thread options are set by mh-mingw/mh-cygwin
+    # For msvc, the thread options are set by runConfigureICU
+    ICU_USE_THREADS=1
+    ;;
+  *-*-hpux*)
+    # Add -mt because it does several nice things on newer compilers.
+    case "${icu_cv_host_frag}" in
+      mh-hpux-acc)
+        OLD_CXXFLAGS="${CXXFLAGS}"
+        CXXFLAGS="${CXXFLAGS} -mt"
+        if test x"`${CXX} ${CXXFLAGS} 2>&1`" != x""; then
+           CXXFLAGS="${OLD_CXXFLAGS}"
+       fi
+      ;;
+    esac
+    ;;
+  *-*-solaris*)
+    case "${icu_cv_host_frag}" in
+      mh-solaris)
+           LIBS="${LIBS} -mt"
+      ;;
+    esac
+    ;;
+  esac
+fi
+
+AC_SUBST(ICU_USE_THREADS)
+
+AC_ARG_ENABLE(weak-threads,
+	[  --enable-weak-threads   weakly reference the threading library [default=no]],
+	[case "${enableval}" in
+		yes)
+            LIB_THREAD="${LIBS%${OLD_LIBS}}"
+            LIBS=${OLD_LIBS}
+            ;;
+		no)  ;;
+		*) AC_MSG_ERROR(bad value ${enableval} for --enable-weak-threads) ;;
+		esac])
+AC_SUBST(LIB_THREAD)
+
+# Check for mmap()
+
+# The AC_FUNC_MMAP macro doesn't work properly.  It seems to be too specific.
+# Do this check instead.
+HAVE_MMAP=0
+AC_MSG_CHECKING([for mmap])
+AC_CACHE_VAL(ac_cv_func_mmap_ok,
+    [AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>], [mmap((void *)0, 0, PROT_READ, 0, 0, 0);])],[ac_cv_func_mmap_ok=yes],[ac_cv_func_mmap_ok=no])] )
+AC_MSG_RESULT($ac_cv_func_mmap_ok)
+if test $ac_cv_func_mmap_ok = yes
+then
+    HAVE_MMAP=1
+fi
+AC_SUBST(HAVE_MMAP)
+
+AC_MSG_CHECKING([for genccode assembly])
+
+# Check to see if genccode can generate simple assembly.
+GENCCODE_ASSEMBLY=
+case "${host}" in
+*-linux*|i*86-*-*bsd*|i*86-pc-gnu)
+    if test "$GCC" = yes; then
+        # We're using gcc, and the simple -a gcc command line works for genccode
+        GENCCODE_ASSEMBLY="-a gcc"
+    fi ;;
+i*86-*-solaris*)
+    if test "$GCC" = yes; then
+        # When using gcc, look if we're also using GNU as.
+        # When using GNU as, the simple -a gcc command line works for genccode.
+        asv=`"${CC}" -print-prog-name=as 2>/dev/null`
+        asv=`"${asv}" --version 2>/dev/null`
+        case "X${asv}" in
+        X*GNU*) GENCCODE_ASSEMBLY="-a gcc" ;;
+        X*) GENCCODE_ASSEMBLY="-a sun-x86" ;;
+        esac
+        unset asv
+    else
+        GENCCODE_ASSEMBLY="-a sun-x86"
+    fi ;;
+sparc-*-solaris*)
+    GENCCODE_ASSEMBLY="-a sun"
+    ;;
+ia64-*-hpux*)
+    GENCCODE_ASSEMBLY="-a aCC-ia64"
+    ;;
+esac
+AC_SUBST(GENCCODE_ASSEMBLY)
+
+AC_MSG_RESULT($GENCCODE_ASSEMBLY)
+
+# Checks for header files
+AC_CHECK_HEADERS(inttypes.h)
+if test $ac_cv_header_inttypes_h = no; then
+ U_HAVE_INTTYPES_H=0
+else
+ U_HAVE_INTTYPES_H=1
+fi
+if test "$CC" = ccc; then
+ AC_MSG_RESULT("C compiler set to CCC ${CC}" )
+ case "${host}" in
+        alpha*-*-*) U_HAVE_INTTYPES_H=0;
+ esac
+fi
+
+AC_SUBST(U_HAVE_INTTYPES_H)
+
+AC_CHECK_HEADERS(dirent.h)
+if test $ac_cv_header_dirent_h = no; then
+ U_HAVE_DIRENT_H=0
+else
+ U_HAVE_DIRENT_H=1
+fi
+
+AC_SUBST(U_HAVE_DIRENT_H)
+
+
+AC_ARG_WITH(iostream,
+	[  --with-iostream=version specify the version of iostream to use (none, old, std, auto) [default=auto]],
+	[case "${withval}" in
+		none) streams=none ;;
+		old) streams=198506 ;;
+		std) streams=199711 ;;
+		auto) streams= ;;
+		*) AC_MSG_ERROR(bad value ${withval} for --with-iostream) ;;
+		esac], 
+        [streams=])
+
+U_IOSTREAM_SOURCE=0
+if test x$streams != xnone
+then
+    AC_LANG_PUSH(C++)
+    OLD_CXXFLAGS="${CXXFLAGS}"
+    case "${icu_cv_host_frag}" in
+        mh-hpux-acc)
+            CXXFLAGS="${CXXFLAGS} -AA"
+        ;;
+    esac
+    AC_MSG_CHECKING([for iostream usability])
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <iostream>]], [[]])],[ac_cv_header_iostream=yes],[ac_cv_header_iostream=no])
+    if test $icu_cv_host_frag = mh-cygwin-msvc
+    then
+        # <iostream> is always there on Windows.
+        # We do this to prevent the C++ preprocessor from being used because
+        # autoconf can't deal with the Windows C++ preprocessor 
+        ac_cv_header_iostream=yes
+    fi
+    AC_MSG_RESULT($ac_cv_header_iostream)
+    if test $ac_cv_header_iostream = yes
+    then
+        U_IOSTREAM_SOURCE=199711
+    else
+        CXXFLAGS="${OLD_CXXFLAGS}"
+        AC_MSG_CHECKING([whether ostream in iostream.h is really defined])
+        AC_CACHE_VAL(ac_cv_iostream_ok,
+            AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <iostream.h>]], [[ostream &testout = cout; testout << "test" << endl;]])],[ac_cv_iostream_ok=yes],[ac_cv_iostream_ok=no]))
+        AC_MSG_RESULT($ac_cv_iostream_ok)
+        if test $ac_cv_iostream_ok = yes
+        then
+            U_IOSTREAM_SOURCE=198506
+        fi
+    fi
+    if test x$streams != x
+    then
+        if test $U_IOSTREAM_SOURCE -ge $streams
+        then
+            U_IOSTREAM_SOURCE=$streams
+            case "${icu_cv_host_frag}" in
+                mh-hpux-acc)
+                    if test $U_IOSTREAM_SOURCE -lt 199711; then
+                        CXXFLAGS=${OLD_CXXFLAGS}
+                    fi
+                ;;
+            esac
+        else
+            AC_MSG_ERROR(${withval} iostream is not available)
+        fi
+    fi
+fi
+AC_SUBST(U_IOSTREAM_SOURCE)
+AC_LANG_POP
+
+# Check for endianness
+AC_C_BIGENDIAN()
+if test $ac_cv_c_bigendian = no; then
+U_IS_BIG_ENDIAN=0
+U_ENDIAN_CHAR="l"
+else
+U_IS_BIG_ENDIAN=1
+U_ENDIAN_CHAR="b"
+fi
+AC_SUBST(U_IS_BIG_ENDIAN)
+
+# Do various POSIX related checks
+U_HAVE_NL_LANGINFO_CODESET=0
+U_NL_LANGINFO_CODESET=-1
+AC_CHECK_FUNC(nl_langinfo,[U_HAVE_NL_LANGINFO=1],[U_HAVE_NL_LANGINFO=0])
+dnl AC_SUBST(U_HAVE_NL_LANGINFO)
+if test $U_HAVE_NL_LANGINFO -eq 1; then
+  AC_CACHE_CHECK([for nl_langinfo's argument to obtain the codeset],
+  ac_cv_nl_langinfo_codeset,
+  [ac_cv_nl_langinfo_codeset="unknown"
+  for a in CODESET _NL_CTYPE_CODESET_NAME; do
+  AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <langinfo.h>]], [[nl_langinfo($a);]])],[ac_cv_nl_langinfo_codeset="$a"; break],[])]
+  done)
+  if test x$ac_cv_nl_langinfo_codeset != xunknown
+  then
+      U_HAVE_NL_LANGINFO_CODESET=1
+      U_NL_LANGINFO_CODESET=$ac_cv_nl_langinfo_codeset
+  fi
+fi
+AC_SUBST(U_HAVE_NL_LANGINFO_CODESET)
+AC_SUBST(U_NL_LANGINFO_CODESET)
+
+# Namespace support checks
+AC_LANG(C++)
+AC_MSG_CHECKING([for namespace support])
+AC_CACHE_VAL(ac_cv_namespace_ok,
+    [AC_LINK_IFELSE([AC_LANG_PROGRAM([namespace x_version {void f(){}}
+    namespace x = x_version;
+    using namespace x_version;
+    ], [f();])],[ac_cv_namespace_ok=yes],[ac_cv_namespace_ok=no])] )
+AC_MSG_RESULT($ac_cv_namespace_ok)
+U_HAVE_NAMESPACE=1
+if test $ac_cv_namespace_ok = no
+then
+    U_HAVE_NAMESPACE=0
+fi
+AC_SUBST(U_HAVE_NAMESPACE)
+
+AC_MSG_CHECKING([for properly overriding new and delete])
+U_OVERRIDE_CXX_ALLOCATION=0
+U_HAVE_PLACEMENT_NEW=0
+AC_CACHE_VAL(ac_cv_override_cxx_allocation_ok,
+    [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stdlib.h>
+    class UMemory {
+    public:
+    void *operator new(size_t size) {return malloc(size);}
+    void *operator new[](size_t size) {return malloc(size);}
+    void operator delete(void *p) {free(p);}
+    void operator delete[](void *p) {free(p);}
+    };
+    ]], [])],[ac_cv_override_cxx_allocation_ok=yes],[ac_cv_override_cxx_allocation_ok=no])] )
+AC_MSG_RESULT($ac_cv_override_cxx_allocation_ok)
+if test $ac_cv_override_cxx_allocation_ok = yes
+then
+    U_OVERRIDE_CXX_ALLOCATION=1
+    AC_MSG_CHECKING([for placement new and delete])
+    AC_CACHE_VAL(ac_cv_override_placement_new_ok,
+        [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stdlib.h>
+        class UMemory {
+        public:
+        void *operator new(size_t size) {return malloc(size);}
+        void *operator new[](size_t size) {return malloc(size);}
+        void operator delete(void *p) {free(p);}
+        void operator delete[](void *p) {free(p);}
+        void * operator new(size_t, void *ptr) { return ptr; }
+        void operator delete(void *, void *) {}
+        };
+        ]], [])],[ac_cv_override_placement_new_ok=yes],[ac_cv_override_placement_new_ok=no])] )
+    AC_MSG_RESULT($ac_cv_override_placement_new_ok)
+    if test $ac_cv_override_placement_new_ok = yes
+    then
+        U_HAVE_PLACEMENT_NEW=1
+    fi
+fi
+AC_SUBST(U_OVERRIDE_CXX_ALLOCATION)
+AC_SUBST(U_HAVE_PLACEMENT_NEW)
+
+# gcc atomic built-in functions check
+# AC_TRY_LINK([], [int foo, bar; bar = __sync_val_compare_and_swap(&foo, 0, 1);],, 
+AC_LANG(C)
+AC_MSG_CHECKING([for gcc atomic functions])
+AC_LINK_IFELSE([AC_LANG_PROGRAM(
+    [[
+        void *p;
+        int   i;
+    ]],
+    [[
+        __sync_fetch_and_add(&i, 1);
+        __sync_fetch_and_sub(&i, 1);
+        __sync_val_compare_and_swap(&p, 0, 0);
+    ]]
+)],
+[U_HAVE_GCC_ATOMICS=1; AC_MSG_RESULT([yes])],
+[U_HAVE_GCC_ATOMICS=0; AC_MSG_RESULT([no])])
+AC_SUBST(U_HAVE_GCC_ATOMICS)
+
+AC_LANG(C)
+AC_CHECK_FUNC(popen)
+if test x$ac_cv_func_popen = xyes
+then
+     U_HAVE_POPEN=1
+else
+     U_HAVE_POPEN=0
+fi
+AC_SUBST(U_HAVE_POPEN)
+
+AC_CHECK_FUNC(tzset)
+U_HAVE_TZSET=0
+if test x$ac_cv_func_tzset = xyes
+then
+    U_TZSET=tzset
+    U_HAVE_TZSET=1
+else
+    AC_CHECK_FUNC(_tzset)
+    if test x$ac_cv_func__tzset = xyes
+    then
+        U_TZSET=_tzset
+        U_HAVE_TZSET=1
+    fi
+fi
+AC_SUBST(U_HAVE_TZSET)
+AC_SUBST(U_TZSET)
+
+U_HAVE_TZNAME=0
+AC_CACHE_CHECK(for tzname,ac_cv_var_tzname,
+[AC_LINK_IFELSE([AC_LANG_PROGRAM([[#ifndef __USE_POSIX
+#define __USE_POSIX
+#endif
+#include <stdlib.h>
+#include <time.h>
+#ifndef tzname /* For SGI.  */
+extern char *tzname[]; /* RS6000 and others reject char **tzname.  */
+#endif]], [atoi(*tzname);])],[ac_cv_var_tzname=yes],[ac_cv_var_tzname=no])])
+if test $ac_cv_var_tzname = yes; then
+  U_TZNAME=tzname
+  U_HAVE_TZNAME=1
+else
+  AC_CACHE_CHECK(for _tzname,ac_cv_var__tzname,
+  [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stdlib.h>
+  #include <time.h>
+  extern char *_tzname[];]], [atoi(*_tzname);])],[ac_cv_var__tzname=yes],[ac_cv_var__tzname=no])])
+    if test $ac_cv_var__tzname = yes; then
+      U_TZNAME=_tzname
+      U_HAVE_TZNAME=1
+    fi
+fi
+AC_SUBST(U_HAVE_TZNAME)
+AC_SUBST(U_TZNAME)
+
+AC_CACHE_CHECK(for timezone,ac_cv_var_timezone,
+[AC_LINK_IFELSE([AC_LANG_PROGRAM([#ifndef __USE_POSIX
+#define __USE_POSIX
+#endif
+#ifndef __USE_XOPEN
+#define __USE_XOPEN
+#endif
+#include <time.h>
+], [[timezone = 1;]])],[ac_cv_var_timezone=yes],[ac_cv_var_timezone=no])])
+U_HAVE_TIMEZONE=0
+if test $ac_cv_var_timezone = yes; then
+  U_TIMEZONE=timezone
+  U_HAVE_TIMEZONE=1
+else
+  AC_CACHE_CHECK(for __timezone,ac_cv_var___timezone,
+  [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <time.h>]], [[__timezone = 1;]])],[ac_cv_var___timezone=yes],[ac_cv_var___timezone=no])])
+  if test $ac_cv_var___timezone = yes; then
+    U_TIMEZONE=__timezone
+    U_HAVE_TIMEZONE=1
+  else
+    AC_CACHE_CHECK(for _timezone,ac_cv_var__timezone,
+    [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <time.h>]], [[_timezone = 1;]])],[ac_cv_var__timezone=yes],[ac_cv_var__timezone=no])])
+    if test $ac_cv_var__timezone = yes; then
+      U_TIMEZONE=_timezone
+      U_HAVE_TIMEZONE=1
+    fi
+  fi
+fi
+AC_SUBST(U_HAVE_TIMEZONE)
+AC_SUBST(U_TIMEZONE)
+
+# Checks for typedefs
+AC_CHECK_TYPE(int8_t,signed char)
+AC_CHECK_TYPE(uint8_t,unsigned char)
+AC_CHECK_TYPE(int16_t,signed short)
+AC_CHECK_TYPE(uint16_t,unsigned short)
+AC_CHECK_TYPE(int32_t,signed long)
+AC_CHECK_TYPE(uint32_t,unsigned long)
+AC_CHECK_TYPE(int64_t,signed long long)
+AC_CHECK_TYPE(uint64_t,unsigned long long)
+
+if test $ac_cv_type_int8_t = no; then
+HAVE_INT8_T=0
+else
+HAVE_INT8_T=1
+fi
+AC_SUBST(HAVE_INT8_T)
+
+if test $ac_cv_type_uint8_t = no; then
+HAVE_UINT8_T=0
+else
+HAVE_UINT8_T=1
+fi
+AC_SUBST(HAVE_UINT8_T)
+
+if test $ac_cv_type_int16_t = no; then
+HAVE_INT16_T=0
+else
+HAVE_INT16_T=1
+fi
+AC_SUBST(HAVE_INT16_T)
+
+if test $ac_cv_type_uint16_t = no; then
+HAVE_UINT16_T=0
+else
+HAVE_UINT16_T=1
+fi
+AC_SUBST(HAVE_UINT16_T)
+
+if test $ac_cv_type_int32_t = no; then
+HAVE_INT32_T=0
+else
+HAVE_INT32_T=1
+fi
+AC_SUBST(HAVE_INT32_T)
+
+if test $ac_cv_type_uint32_t = no; then
+HAVE_UINT32_T=0
+else
+HAVE_UINT32_T=1
+fi
+AC_SUBST(HAVE_UINT32_T)
+
+if test $ac_cv_type_int64_t = no; then
+HAVE_INT64_T=0
+else
+HAVE_INT64_T=1
+fi
+AC_SUBST(HAVE_INT64_T)
+
+if test $ac_cv_type_uint64_t = no; then
+HAVE_UINT64_T=0
+else
+HAVE_UINT64_T=1
+fi
+AC_SUBST(HAVE_UINT64_T)
+
+# Do various wchar_t related checks
+AC_CHECK_HEADER(wchar.h)
+if test "$ac_cv_header_wchar_h" = no
+then
+    U_HAVE_WCHAR_H=0
+    U_HAVE_WCSCPY=0
+else
+    AC_DEFINE([HAVE_WCHAR_H], [1], [wchar.h was found.])
+    U_HAVE_WCHAR_H=1
+    # Some broken systems have wchar.h but not some of its functions...
+    AC_SEARCH_LIBS(wcscpy, wcs w)
+    if test "$ac_cv_search_wcscpy" != no; then
+      U_HAVE_WCSCPY=1
+    else
+      U_HAVE_WCSCPY=0
+    fi
+fi
+AC_SUBST(U_HAVE_WCHAR_H)
+AC_SUBST(U_HAVE_WCSCPY)
+
+AC_CHECK_SIZEOF([wchar_t], 0, [
+#if STDC_HEADERS
+#include <stddef.h>
+#endif
+#include <stdlib.h>
+#if HAVE_WCHAR_H
+#include <string.h>
+#include <wchar.h>
+#endif])
+U_SIZEOF_WCHAR_T=$ac_cv_sizeof_wchar_t
+# We do this check to verify that everything is okay.
+if test $U_SIZEOF_WCHAR_T = 0; then
+    if test $U_HAVE_WCHAR_H=1; then
+       AC_MSG_ERROR(There is wchar.h but the size of wchar_t is 0)
+    fi
+fi
+AC_SUBST(U_SIZEOF_WCHAR_T)
+
+AC_MSG_CHECKING([for UTF-16 string literal support])
+U_CHECK_UTF16_STRING=1
+CHECK_UTF16_STRING_RESULT="unknown"
+
+case "${host}" in
+*-*-aix*|powerpc64-*-linux*)
+    if test "$ac_cv_c_compiler_gnu" = no; then
+        OLD_CFLAGS="${CFLAGS}"
+        OLD_CXXFLAGS="${CXXFLAGS}"
+        CFLAGS="${CFLAGS} -qutf"
+        CXXFLAGS="${CXXFLAGS} -qutf"
+        AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[const unsigned short hello[] = u"hello";]], [[]])],[U_CHECK_UTF16_STRING=1],[U_CHECK_UTF16_STRING=0])
+        if test "$U_CHECK_UTF16_STRING" = 0; then
+            CFLAGS="${OLD_CFLAGS}"
+            CXXFLAGS="${OLD_CXXFLAGS}"
+        else
+            CHECK_UTF16_STRING_RESULT="-qutf"
+        fi
+    fi
+    ;;
+*-*-solaris*)
+    if test "$ac_cv_c_compiler_gnu" = no; then
+        OLD_CFLAGS="${CFLAGS}"
+        OLD_CXXFLAGS="${CXXFLAGS}"
+        CFLAGS="${CFLAGS} -xustr=ascii_utf16_ushort"
+        CXXFLAGS="${CXXFLAGS} -xustr=ascii_utf16_ushort"
+        AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[const unsigned short hello[] = U"hello";]], [[]])],[U_CHECK_UTF16_STRING=1],[U_CHECK_UTF16_STRING=0])
+        if test "$U_CHECK_UTF16_STRING" = 0; then
+            CFLAGS="${OLD_CFLAGS}"
+            CXXFLAGS="${OLD_CXXFLAGS}"
+        else
+            CHECK_UTF16_STRING_RESULT="-xustr=ascii_utf16_ushort"
+
+            # Since we can't detect the availability of this UTF-16 syntax at compile time,
+            # we depend on configure telling us that we can use it.
+            # Since we can't ensure ICU users use -xustr=ascii_utf16_ushort,
+            # we only use this macro within ICU.
+            # If an ICU user uses icu-config, this feature will be enabled.
+            CPPFLAGS="${CPPFLAGS} -DU_CHECK_UTF16_STRING=1"
+            U_CHECK_UTF16_STRING=0
+        fi
+    fi
+    ;;
+*-*-hpux*)
+    if test "$ac_cv_c_compiler_gnu" = no; then
+        # The option will be detected at compile time without additional compiler options.
+        CHECK_UTF16_STRING_RESULT="available"
+    fi
+    ;;
+*-*-cygwin)
+    # wchar_t can be used
+    CHECK_UTF16_STRING_RESULT="available"
+    ;;
+*)
+    ;;
+esac
+
+# GCC >= 4.4 supports UTF16 string literals. The CFLAGS and CXXFLAGS may change in the future.
+# Since we have to use a different standard, if strict is enable, don't enable UTF16 string literals.
+U_CHECK_GNUC_UTF16_STRING=0
+if test "$ac_use_strict_options" = no && test "$CHECK_UTF16_STRING_RESULT" = "unknown"; then
+    if test "$ac_cv_c_compiler_gnu" = yes; then
+        OLD_CFLAGS="${CFLAGS}"
+        OLD_CXXFLAGS="${CXXFLAGS}"
+        CFLAGS="${CFLAGS} -std=gnu99 -D_GCC_"
+        CXXFLAGS="${CXXFLAGS} -std=c++0x"
+        AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
+#ifdef _GCC_
+typedef __CHAR16_TYPE__ char16_t;
+#endif
+char16_t test[] = u"This is a UTF16 literal string.";
+#else
+GCC IS TOO OLD!
+#endif
+        ]], [[]])],[U_CHECK_UTF16_STRING=1],[U_CHECK_UTF16_STRING=0])
+        if test "$U_CHECK_UTF16_STRING" = 1; then
+            CHECK_UTF16_STRING_RESULT="available";
+            U_CHECK_GNUC_UTF16_STRING=1
+        else
+            CFLAGS="${OLD_CFLAGS}"
+            CXXFLAGS="${OLD_CXXFLAGS}"
+        fi
+    fi
+fi
+AC_SUBST(U_CHECK_GNUC_UTF16_STRING)
+
+AC_MSG_RESULT($CHECK_UTF16_STRING_RESULT)
+AC_SUBST(U_CHECK_UTF16_STRING)
+
+# Enable/disable extras
+AC_ARG_ENABLE(extras,
+	[  --enable-extras         build ICU extras [default=yes]],
+	[case "${enableval}" in
+		yes) extras=true ;;
+		no)  extras=false ;;
+		*) AC_MSG_ERROR(bad value ${enableval} for --enable-extras) ;;
+		esac], 
+	extras=true)
+ICU_CONDITIONAL(EXTRAS, test "$extras" = true)
+AC_ARG_ENABLE(icuio,
+	[  --enable-icuio          build ICU's icuio library [default=yes]],
+	[case "${enableval}" in
+		yes) icuio=true ;;
+		no)  icuio=false ;;
+		*) AC_MSG_ERROR(bad value ${enableval} for --enable-icuio) ;;
+		esac], 
+	icuio=true)
+ICU_CONDITIONAL(ICUIO, test "$icuio" = true)
+
+# Enable/disable layout
+AC_ARG_ENABLE(layout,
+	[  --enable-layout         build ICU's layout library [default=yes]],
+	[case "${enableval}" in
+		yes) layout=true ;;
+		no)  layout=false ;;
+		*) AC_MSG_ERROR(bad value ${enableval} for --enable-layout) ;;
+		esac], 
+	layout=true)
+ICU_CONDITIONAL(LAYOUT, test "$layout" = true)
+
+AC_ARG_WITH(data-packaging,
+	[  --with-data-packaging=type specify how to package ICU data (files, archive, library, static, auto) [default=auto]],
+	[case "${withval}" in
+                files|archive|library) datapackaging=$withval ;;
+		auto) datapackaging=$withval ;;
+		common) datapackaging=archive ;;
+		dll) datapackaging=library ;;
+		static) datapackaging=static ;;
+		*) AC_MSG_ERROR(bad value ${withval} for --with-data-packaging) ;;
+		esac], 
+        [datapackaging=])
+
+# Note:  'thesysconfdir' is an evaluated version, for Man pages, so also for thedatadir, thelibdir, etc.. 
+# thesysconfdir=`eval echo $sysconfdir`
+dnl# AC_SUBST(thesysconfdir)
+dnl# thelibdir=`test "x$exec_prefix" = xNONE && exec_prefix="$prefix"; eval echo $libdir`
+dnl# AC_SUBST(thelibdir)
+thedatadir=`eval echo $datadir`
+dnl# AC_SUBST(thedatadir)
+# Always put raw data files in share/icu/{version}, etc.   Never use lib/icu/{version} for data files.. Actual shared libraries will go in {libdir}. 
+pkgicudatadir=$datadir
+thepkgicudatadir=$thedatadir
+AC_SUBST(pkgicudatadir)
+AC_SUBST(thepkgicudatadir)
+
+dnl# Shouldn't need the AC_SUBST
+
+if test x"$datapackaging" = x -o x"$datapackaging" = xauto; then
+	# default to library
+	datapackaging=library
+	if test "$ENABLE_STATIC" = "YES"; then
+		if test "$ENABLE_SHARED" != "YES"; then
+			datapackaging=static
+		fi
+	fi
+fi
+
+datapackaging_dir=`eval echo $thedatadir`"/icu/${VERSION}"
+
+datapackaging_msg="(No explaination for mode $datapackaging.)"
+
+datapackaging_msg_path="ICU will look in $datapackaging_dir which is the installation location. Call u_setDataDirectory() or use the ICU_DATA environment variable to override."
+datapackaging_msg_set="ICU will use the linked data library. If linked with the stub library located in stubdata/, the application can use udata_setCommonData() or set a data path to override." 
+datapackaging_howfound="(unknown)"
+
+case "$datapackaging" in
+    files)
+    DATA_PACKAGING_MODE=files
+    datapackaging_msg="ICU data will be stored in individual files."
+    datapackaging_howfound="$datapackaging_msg_path"
+    ;;
+    archive)
+    DATA_PACKAGING_MODE=common
+    datapackaging_msg="ICU data will be stored in a single .dat file."
+    datapackaging_howfound="$datapackaging_msg_path"
+    ;;
+    library)
+    DATA_PACKAGING_MODE=dll
+    datapackaging_msg="ICU data will be linked with ICU."
+    if test "$ENABLE_STATIC" = "YES"; then
+        datapackaging_msg="$datapackaging_msg A static data library will be built. "
+    fi
+    if test "$ENABLE_SHARED" = "YES"; then
+        datapackaging_msg="$datapackaging_msg A shared data library will be built. "
+    fi
+    datapackaging_howfound="$datapackaging_msg_set"
+    ;;
+    static)
+    DATA_PACKAGING_MODE=static
+    datapackaging_msg="ICU data will be stored in a static library."
+    datapackaging_howfound="$datapackaging_msg_set"
+    ;;
+esac
+AC_SUBST(DATA_PACKAGING_MODE)
+
+# Sets a library suffix
+AC_MSG_CHECKING([for a library suffix to use])
+AC_ARG_WITH(library-suffix,
+	[  --with-library-suffix=suffix    tag a suffix to the library names [default=]],
+	[ICULIBSUFFIX="${withval}"],
+	[ICULIBSUFFIX=])
+msg=$ICULIBSUFFIX
+if test "$msg" = ""; then
+    msg=none
+fi
+AC_MSG_RESULT($msg)
+AC_SUBST(ICULIBSUFFIX)
+if test "$ICULIBSUFFIX" != ""
+then
+    U_HAVE_LIB_SUFFIX=1
+    ICULIBSUFFIXCNAME=`echo _$ICULIBSUFFIX | sed 's/[^A-Za-z0-9_]/_/g'`
+else
+    U_HAVE_LIB_SUFFIX=0
+fi
+AC_SUBST(U_HAVE_LIB_SUFFIX)
+AC_SUBST(ICULIBSUFFIXCNAME)
+
+# Enable/disable tests
+AC_ARG_ENABLE(tests,
+	[  --enable-tests          build ICU tests [default=yes]],
+	[case "${enableval}" in
+		yes) tests=true ;;
+		no)  tests=false ;;
+		*) AC_MSG_ERROR(bad value ${enableval} for --enable-tests) ;;
+		esac], 
+	tests=true)
+ICU_CONDITIONAL(TESTS, test "$tests" = true)
+
+# Enable/disable samples
+AC_ARG_ENABLE(samples,
+	[  --enable-samples        build ICU samples [default=yes]  
+
+Additionally, the variable FORCE_LIBS may be set before calling configure.
+If set, it will REPLACE any automatic list of libraries.],
+	[case "${enableval}" in
+		yes) samples=true ;;
+		no)  samples=false ;;
+		*) AC_MSG_ERROR(bad value ${enableval} for --enable-samples) ;;
+		esac], 
+	samples=true)
+ICU_CONDITIONAL(SAMPLES, test "$samples" = true)
+
+ICUDATA_CHAR=$U_ENDIAN_CHAR
+
+# Platform-specific Makefile setup
+# set ICUDATA_CHAR to 'e' for any EBCDIC (which should be big endian) platform.
+case "${host}" in
+	*-*-solaris*) 	platform=U_SOLARIS ;;
+	*-*-linux*|*-*-gnu|*-*-k*bsd*-gnu|*-*-kopensolaris*-gnu)        platform=U_LINUX ;;
+	*-*-*bsd*|*-*-dragonfly*) 	platform=U_BSD ;;
+	*-*-aix*) 	platform=U_AIX ;;
+	*-*-hpux*) 	platform=U_HPUX ;;
+	*-apple-darwin*|*-apple-rhapsody*)	platform=U_DARWIN ;;
+	*-*-cygwin*|*-*-mingw*)	platform=U_CYGWIN ;;
+	*-*ibm-openedition*|*-*-os390*)	platform=OS390
+			if test "${ICU_ENABLE_ASCII_STRINGS}" != "1"; then
+				ICUDATA_CHAR="e"
+			fi ;;
+	*-*-os400*)	platform=OS400
+			if test "${ICU_ENABLE_ASCII_STRINGS}" != "1"; then
+				ICUDATA_CHAR="e"
+			fi ;;
+	*-*-nto*)	platform=U_QNX ;;
+	*-dec-osf*) 	platform=U_OSF ;;
+	*-*-beos)		platform=U_BEOS ;;
+	*-*-irix*)		platform=U_IRIX ;;
+	*-ncr-*)		platform=U_MPRAS ;;
+	*) 		platform=U_UNKNOWN_PLATFORM ;;
+esac
+AC_SUBST(ICUDATA_CHAR)
+AC_SUBST(platform)
+platform_make_fragment_name="$icu_cv_host_frag"
+platform_make_fragment='$(top_srcdir)/config/'"$platform_make_fragment_name"
+AC_SUBST(platform_make_fragment_name)
+AC_SUBST(platform_make_fragment)
+
+if test "${FORCE_LIBS}" != ""; then
+   echo " *** Overriding automatically chosen [LIBS=$LIBS], using instead [FORCE_LIBS=${FORCE_LIBS}]"  1>&6
+   LIBS=${FORCE_LIBS}
+fi
+
+
+# Now that we're done using CPPFLAGS etc. for tests, we can change it
+# for build.
+
+if test $ICU_USE_THREADS -ne 0
+then
+    CPPFLAGS="$CPPFLAGS \$(THREADSCPPFLAGS)"
+    CFLAGS="$CFLAGS \$(THREADSCFLAGS)"
+    CXXFLAGS="$CXXFLAGS \$(THREADSCXXFLAGS)"
+fi
+
+# output the Makefiles
+AC_CONFIG_FILES([icudefs.mk \
+		Makefile \
+		data/pkgdataMakefile \
+		config/Makefile.inc \
+		config/icu.pc \
+		config/pkgdataMakefile \
+		data/Makefile \
+		stubdata/Makefile \
+		common/Makefile \
+		i18n/Makefile \
+		layout/Makefile \
+		layoutex/Makefile \
+		io/Makefile \
+		extra/Makefile \
+		extra/uconv/Makefile \
+		extra/uconv/pkgdataMakefile \
+		extra/scrptrun/Makefile \
+		tools/Makefile \
+		tools/ctestfw/Makefile \
+		tools/toolutil/Makefile \
+		tools/makeconv/Makefile \
+		tools/genrb/Makefile \
+		tools/genccode/Makefile \
+		tools/gencmn/Makefile \
+		tools/gencnval/Makefile \
+		tools/genctd/Makefile \
+		tools/gentest/Makefile \
+		tools/gennorm2/Makefile \
+		tools/genbrk/Makefile \
+		tools/gensprep/Makefile \
+		tools/icuinfo/Makefile \
+		tools/icupkg/Makefile \
+		tools/icuswap/Makefile \
+		tools/pkgdata/Makefile \
+		tools/tzcode/Makefile \
+		tools/gencfu/Makefile \
+		test/Makefile \
+		test/compat/Makefile \
+		test/testdata/Makefile \
+		test/testdata/pkgdataMakefile \
+		test/hdrtst/Makefile \
+		test/intltest/Makefile \
+		test/cintltst/Makefile \
+		test/iotest/Makefile \
+		test/letest/Makefile \
+		test/perf/Makefile \
+		test/perf/collationperf/Makefile \
+		test/perf/ubrkperf/Makefile \
+		test/perf/charperf/Makefile \
+		test/perf/convperf/Makefile \
+		test/perf/normperf/Makefile \
+		test/perf/DateFmtPerf/Makefile \
+		test/perf/strsrchperf/Makefile \
+		test/perf/unisetperf/Makefile \
+		test/perf/usetperf/Makefile \
+		test/perf/ustrperf/Makefile \
+		test/perf/utfperf/Makefile \
+		test/perf/utrie2perf/Makefile \
+		samples/Makefile samples/date/Makefile \
+		samples/cal/Makefile samples/layout/Makefile \
+		common/unicode/platform.h])
+AC_OUTPUT
+
+echo 
+echo "ICU for C/C++ $VERSION is ready to be built."
+echo "=== Important Notes: ==="
+
+if test $ICU_USE_THREADS = 0; then
+  echo
+  echo  "** ICU was configured without mutex or thread support. Multithread-safe operation will not be tested. If this is unexpected, then run configure with --enable-threads=yes or check the messages [above] to see why thread support was not found." 1>&6
+  echo
+fi
+
+echo "Data Packaging: $datapackaging"
+echo " This means: $datapackaging_msg"
+echo " To locate data: $datapackaging_howfound"
+
+if test -n "`$U_MAKE -v 2>&1 | grep '^GNU Make'`"; then
+echo "Building ICU: Use a GNU make such as $U_MAKE to build ICU."
+else
+echo "** WARNING: $U_MAKE may not be GNU make."
+echo "This may cause ICU to fail to build. Please make sure that GNU make"
+echo "is in your PATH so that the configure script can detect its location."
+fi
+
+AC_MSG_CHECKING([the version of "$U_MAKE"])
+if "$U_MAKE" -f "$srcdir/config/gmakever.mk" PLATFORM="$platform"; then
+AC_MSG_RESULT([ok])
+else
+AC_MSG_RESULT([too old or test failed - try upgrading GNU Make])
+fi
+
+$as_unset _CXX_CXXSUFFIX
diff --git a/source/i18n/Makefile.in b/source/i18n/Makefile.in
new file mode 100644
index 0000000..a23e5d9
--- /dev/null
+++ b/source/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/source/i18n/anytrans.cpp b/source/i18n/anytrans.cpp
new file mode 100644
index 0000000..7ce9ca7
--- /dev/null
+++ b/source/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/source/i18n/anytrans.h b/source/i18n/anytrans.h
new file mode 100644
index 0000000..228ccbe
--- /dev/null
+++ b/source/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/source/i18n/astro.cpp b/source/i18n/astro.cpp
new file mode 100644
index 0000000..95ddfa3
--- /dev/null
+++ b/source/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/source/i18n/astro.h b/source/i18n/astro.h
new file mode 100644
index 0000000..cd20b6c
--- /dev/null
+++ b/source/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/source/i18n/basictz.cpp b/source/i18n/basictz.cpp
new file mode 100644
index 0000000..6b4889a
--- /dev/null
+++ b/source/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/source/i18n/bms.cpp b/source/i18n/bms.cpp
new file mode 100644
index 0000000..99a4589
--- /dev/null
+++ b/source/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/source/i18n/bmsearch.cpp b/source/i18n/bmsearch.cpp
new file mode 100644
index 0000000..d7aa5c8
--- /dev/null
+++ b/source/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/source/i18n/bocsu.c b/source/i18n/bocsu.c
new file mode 100644
index 0000000..d4c6ab8
--- /dev/null
+++ b/source/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/source/i18n/bocsu.h b/source/i18n/bocsu.h
new file mode 100644
index 0000000..26562b1
--- /dev/null
+++ b/source/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/source/i18n/brktrans.cpp b/source/i18n/brktrans.cpp
new file mode 100644
index 0000000..5207266
--- /dev/null
+++ b/source/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/source/i18n/brktrans.h b/source/i18n/brktrans.h
new file mode 100644
index 0000000..0070118
--- /dev/null
+++ b/source/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/source/i18n/buddhcal.cpp b/source/i18n/buddhcal.cpp
new file mode 100644
index 0000000..92f726c
--- /dev/null
+++ b/source/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/source/i18n/buddhcal.h b/source/i18n/buddhcal.h
new file mode 100644
index 0000000..735f618
--- /dev/null
+++ b/source/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/source/i18n/calendar.cpp b/source/i18n/calendar.cpp
new file mode 100644
index 0000000..af29367
--- /dev/null
+++ b/source/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/source/i18n/casetrn.cpp b/source/i18n/casetrn.cpp
new file mode 100644
index 0000000..5038c51
--- /dev/null
+++ b/source/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/source/i18n/casetrn.h b/source/i18n/casetrn.h
new file mode 100644
index 0000000..48233cc
--- /dev/null
+++ b/source/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/source/i18n/cecal.cpp b/source/i18n/cecal.cpp
new file mode 100644
index 0000000..ab4eca9
--- /dev/null
+++ b/source/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/source/i18n/cecal.h b/source/i18n/cecal.h
new file mode 100644
index 0000000..471d889
--- /dev/null
+++ b/source/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/source/i18n/chnsecal.cpp b/source/i18n/chnsecal.cpp
new file mode 100644
index 0000000..0f22812
--- /dev/null
+++ b/source/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/source/i18n/chnsecal.h b/source/i18n/chnsecal.h
new file mode 100644
index 0000000..d379770
--- /dev/null
+++ b/source/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/source/i18n/choicfmt.cpp b/source/i18n/choicfmt.cpp
new file mode 100644
index 0000000..ae53872
--- /dev/null
+++ b/source/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/source/i18n/coleitr.cpp b/source/i18n/coleitr.cpp
new file mode 100644
index 0000000..173166a
--- /dev/null
+++ b/source/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/source/i18n/coll.cpp b/source/i18n/coll.cpp
new file mode 100644
index 0000000..83c7565
--- /dev/null
+++ b/source/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/source/i18n/colldata.cpp b/source/i18n/colldata.cpp
new file mode 100644
index 0000000..c5349d2
--- /dev/null
+++ b/source/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/source/i18n/coptccal.cpp b/source/i18n/coptccal.cpp
new file mode 100644
index 0000000..84bbad7
--- /dev/null
+++ b/source/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/source/i18n/coptccal.h b/source/i18n/coptccal.h
new file mode 100644
index 0000000..f42230d
--- /dev/null
+++ b/source/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/source/i18n/cpdtrans.cpp b/source/i18n/cpdtrans.cpp
new file mode 100644
index 0000000..ebe5d44
--- /dev/null
+++ b/source/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/source/i18n/cpdtrans.h b/source/i18n/cpdtrans.h
new file mode 100644
index 0000000..e964d4c
--- /dev/null
+++ b/source/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/source/i18n/csdetect.cpp b/source/i18n/csdetect.cpp
new file mode 100644
index 0000000..26c0f6c
--- /dev/null
+++ b/source/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/source/i18n/csdetect.h b/source/i18n/csdetect.h
new file mode 100644
index 0000000..405e1f5
--- /dev/null
+++ b/source/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/source/i18n/csmatch.cpp b/source/i18n/csmatch.cpp
new file mode 100644
index 0000000..f1d25d2
--- /dev/null
+++ b/source/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/source/i18n/csmatch.h b/source/i18n/csmatch.h
new file mode 100644
index 0000000..50b78a3
--- /dev/null
+++ b/source/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/source/i18n/csr2022.cpp b/source/i18n/csr2022.cpp
new file mode 100644
index 0000000..84d9495
--- /dev/null
+++ b/source/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/source/i18n/csr2022.h b/source/i18n/csr2022.h
new file mode 100644
index 0000000..5d34711
--- /dev/null
+++ b/source/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/source/i18n/csrecog.cpp b/source/i18n/csrecog.cpp
new file mode 100644
index 0000000..ba70b15
--- /dev/null
+++ b/source/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/source/i18n/csrecog.h b/source/i18n/csrecog.h
new file mode 100644
index 0000000..75cf94f
--- /dev/null
+++ b/source/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/source/i18n/csrmbcs.cpp b/source/i18n/csrmbcs.cpp
new file mode 100644
index 0000000..d0c57de
--- /dev/null
+++ b/source/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/source/i18n/csrmbcs.h b/source/i18n/csrmbcs.h
new file mode 100644
index 0000000..371889a
--- /dev/null
+++ b/source/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/source/i18n/csrsbcs.cpp b/source/i18n/csrsbcs.cpp
new file mode 100644
index 0000000..5b55af6
--- /dev/null
+++ b/source/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/source/i18n/csrsbcs.h b/source/i18n/csrsbcs.h
new file mode 100644
index 0000000..21cbabe
--- /dev/null
+++ b/source/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/source/i18n/csrucode.cpp b/source/i18n/csrucode.cpp
new file mode 100644
index 0000000..99a76d8
--- /dev/null
+++ b/source/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/source/i18n/csrucode.h b/source/i18n/csrucode.h
new file mode 100644
index 0000000..315bad6
--- /dev/null
+++ b/source/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/source/i18n/csrutf8.cpp b/source/i18n/csrutf8.cpp
new file mode 100644
index 0000000..b87c277
--- /dev/null
+++ b/source/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/source/i18n/csrutf8.h b/source/i18n/csrutf8.h
new file mode 100644
index 0000000..10fe287
--- /dev/null
+++ b/source/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/source/i18n/curramt.cpp b/source/i18n/curramt.cpp
new file mode 100644
index 0000000..f4e1abb
--- /dev/null
+++ b/source/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/source/i18n/currfmt.cpp b/source/i18n/currfmt.cpp
new file mode 100644
index 0000000..1334971
--- /dev/null
+++ b/source/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/source/i18n/currfmt.h b/source/i18n/currfmt.h
new file mode 100644
index 0000000..82aae3e
--- /dev/null
+++ b/source/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/source/i18n/currpinf.cpp b/source/i18n/currpinf.cpp
new file mode 100644
index 0000000..3a2c850
--- /dev/null
+++ b/source/i18n/currpinf.cpp
@@ -0,0 +1,388 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2009-2011, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ *******************************************************************************
+ */
+
+#include "unicode/currpinf.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+//#define CURRENCY_PLURAL_INFO_DEBUG 1
+
+#ifdef CURRENCY_PLURAL_INFO_DEBUG
+#include <iostream>
+#endif
+
+
+#include "unicode/locid.h"
+#include "unicode/plurrule.h"
+#include "unicode/ures.h"
+#include "cstring.h"
+#include "hash.h"
+#include "uresimp.h"
+#include "ureslocs.h"
+
+U_NAMESPACE_BEGIN
+
+
+static const UChar gNumberPatternSeparator = 0x3B; // ;
+
+U_CDECL_BEGIN
+
+/**
+ * @internal ICU 4.2
+ */
+static UBool U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2);
+
+UBool
+U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2) {
+    const UnicodeString* affix_1 = (UnicodeString*)val1.pointer;
+    const UnicodeString* affix_2 = (UnicodeString*)val2.pointer;
+    return  *affix_1 == *affix_2;
+}
+
+U_CDECL_END
+
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CurrencyPluralInfo)
+
+static const UChar gDefaultCurrencyPluralPattern[] = {'0', '.', '#', '#', ' ', 0xA4, 0xA4, 0xA4, 0};
+static const UChar gTripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0};
+static const UChar gPluralCountOther[] = {0x6F, 0x74, 0x68, 0x65, 0x72, 0};
+static const UChar gPart0[] = {0x7B, 0x30, 0x7D, 0};
+static const UChar gPart1[] = {0x7B, 0x31, 0x7D, 0};
+
+static const char gNumberElementsTag[]="NumberElements";
+static const char gLatnTag[]="latn";
+static const char gPatternsTag[]="patterns";
+static const char gDecimalFormatTag[]="decimalFormat";
+static const char gCurrUnitPtnTag[]="CurrencyUnitPatterns";
+
+CurrencyPluralInfo::CurrencyPluralInfo(UErrorCode& status)
+:   fPluralCountToCurrencyUnitPattern(NULL),
+    fPluralRules(NULL),
+    fLocale(NULL) {
+    initialize(Locale::getDefault(), status);
+}
+
+CurrencyPluralInfo::CurrencyPluralInfo(const Locale& locale, UErrorCode& status)
+:   fPluralCountToCurrencyUnitPattern(NULL),
+    fPluralRules(NULL),
+    fLocale(NULL) {
+    initialize(locale, status);
+}
+
+CurrencyPluralInfo::CurrencyPluralInfo(const CurrencyPluralInfo& info) 
+:   UObject(info),
+    fPluralCountToCurrencyUnitPattern(NULL),
+    fPluralRules(NULL),
+    fLocale(NULL) {
+    *this = info;
+}
+
+
+CurrencyPluralInfo&
+CurrencyPluralInfo::operator=(const CurrencyPluralInfo& info) {
+    if (this == &info) {
+        return *this;
+    }
+
+    deleteHash(fPluralCountToCurrencyUnitPattern);
+    UErrorCode status = U_ZERO_ERROR;
+    fPluralCountToCurrencyUnitPattern = initHash(status);
+    copyHash(info.fPluralCountToCurrencyUnitPattern, 
+             fPluralCountToCurrencyUnitPattern, status);
+    if ( U_FAILURE(status) ) {
+        return *this;
+    }
+
+    delete fPluralRules;
+    delete fLocale;
+    if (info.fPluralRules) {
+        fPluralRules = info.fPluralRules->clone();
+    } else {
+        fPluralRules = NULL;
+    }
+    if (info.fLocale) {
+        fLocale = info.fLocale->clone();
+    } else {
+        fLocale = NULL;
+    }
+    return *this;
+}
+
+
+CurrencyPluralInfo::~CurrencyPluralInfo() {
+    deleteHash(fPluralCountToCurrencyUnitPattern);
+    fPluralCountToCurrencyUnitPattern = NULL;
+    delete fPluralRules;
+    delete fLocale;
+    fPluralRules = NULL;
+    fLocale = NULL;
+}
+
+UBool
+CurrencyPluralInfo::operator==(const CurrencyPluralInfo& info) const {
+#ifdef CURRENCY_PLURAL_INFO_DEBUG
+    if (*fPluralRules == *info.fPluralRules) {
+        std::cout << "same plural rules\n";
+    }
+    if (*fLocale == *info.fLocale) {
+        std::cout << "same locale\n";
+    }
+    if (fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern)) {
+        std::cout << "same pattern\n";
+    }
+#endif
+    return *fPluralRules == *info.fPluralRules &&
+           *fLocale == *info.fLocale &&
+           fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern);
+}
+
+
+CurrencyPluralInfo*
+CurrencyPluralInfo::clone() const {
+    return new CurrencyPluralInfo(*this);
+}
+
+const PluralRules* 
+CurrencyPluralInfo::getPluralRules() const {
+    return fPluralRules;
+}
+
+UnicodeString&
+CurrencyPluralInfo::getCurrencyPluralPattern(const UnicodeString&  pluralCount,
+                                             UnicodeString& result) const {
+    const UnicodeString* currencyPluralPattern = 
+        (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(pluralCount);
+    if (currencyPluralPattern == NULL) {
+        // fall back to "other"
+        if (pluralCount.compare(gPluralCountOther)) {
+            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;
+    }
+    if ( U_FAILURE(status) ) {
+        delete hTable; 
+        return NULL;
+    }
+    hTable->setValueComparator(ValueComparator);
+    return hTable;
+}
+
+
+void
+CurrencyPluralInfo::copyHash(const Hashtable* source,
+                           Hashtable* target,
+                           UErrorCode& status) {
+    if ( U_FAILURE(status) ) {
+        return;
+    }
+    int32_t pos = -1;
+    const UHashElement* element = NULL;
+    if ( source ) {
+        while ( (element = source->nextElement(pos)) != NULL ) {
+            const UHashTok keyTok = element->key;
+            const UnicodeString* key = (UnicodeString*)keyTok.pointer;
+            const UHashTok valueTok = element->value;
+            const UnicodeString* value = (UnicodeString*)valueTok.pointer;
+            UnicodeString* copy = new UnicodeString(*value);
+            target->put(UnicodeString(*key), copy, status);
+            if ( U_FAILURE(status) ) {
+                return;
+            }
+        }
+    }
+}
+
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/i18n/currunit.cpp b/source/i18n/currunit.cpp
new file mode 100644
index 0000000..47cba62
--- /dev/null
+++ b/source/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/source/i18n/datefmt.cpp b/source/i18n/datefmt.cpp
new file mode 100644
index 0000000..9280d20
--- /dev/null
+++ b/source/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/source/i18n/dcfmtsym.cpp b/source/i18n/dcfmtsym.cpp
new file mode 100644
index 0000000..eaab453
--- /dev/null
+++ b/source/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/source/i18n/decContext.c b/source/i18n/decContext.c
new file mode 100644
index 0000000..513e021
--- /dev/null
+++ b/source/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/source/i18n/decContext.h b/source/i18n/decContext.h
new file mode 100644
index 0000000..c25e495
--- /dev/null
+++ b/source/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/source/i18n/decNumber.c b/source/i18n/decNumber.c
new file mode 100644
index 0000000..ab69078
--- /dev/null
+++ b/source/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/source/i18n/decNumber.h b/source/i18n/decNumber.h
new file mode 100644
index 0000000..4fe0649
--- /dev/null
+++ b/source/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/source/i18n/decNumberLocal.h b/source/i18n/decNumberLocal.h
new file mode 100644
index 0000000..4a36723
--- /dev/null
+++ b/source/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/source/i18n/decimfmt.cpp b/source/i18n/decimfmt.cpp
new file mode 100644
index 0000000..b594a50
--- /dev/null
+++ b/source/i18n/decimfmt.cpp
@@ -0,0 +1,4623 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2011, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*
+* File DECIMFMT.CPP
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   02/19/97    aliu        Converted from java.
+*   03/20/97    clhuang     Implemented with new APIs.
+*   03/31/97    aliu        Moved isLONG_MIN to DigitList, and fixed it.
+*   04/3/97     aliu        Rewrote parsing and formatting completely, and
+*                           cleaned up and debugged.  Actually works now.
+*                           Implemented NAN and INF handling, for both parsing
+*                           and formatting.  Extensive testing & debugging.
+*   04/10/97    aliu        Modified to compile on AIX.
+*   04/16/97    aliu        Rewrote to use DigitList, which has been resurrected.
+*                           Changed DigitCount to int per code review.
+*   07/09/97    helena      Made ParsePosition into a class.
+*   08/26/97    aliu        Extensive changes to applyPattern; completely
+*                           rewritten from the Java.
+*   09/09/97    aliu        Ported over support for exponential formats.
+*   07/20/98    stephen     JDK 1.2 sync up.
+*                             Various instances of '0' replaced with 'NULL'
+*                             Check for grouping size in subFormat()
+*                             Brought subParse() in line with Java 1.2
+*                             Added method appendAffix()
+*   08/24/1998  srl         Removed Mutex calls. This is not a thread safe class!
+*   02/22/99    stephen     Removed character literals for EBCDIC safety
+*   06/24/99    helena      Integrated Alan's NF enhancements and Java2 bug fixes
+*   06/28/99    stephen     Fixed bugs in toPattern().
+*   06/29/99    stephen     Fixed operator= to copy fFormatWidth, fPad,
+*                             fPadPosition
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "fphdlimp.h"
+#include "unicode/decimfmt.h"
+#include "unicode/choicfmt.h"
+#include "unicode/ucurr.h"
+#include "unicode/ustring.h"
+#include "unicode/dcfmtsym.h"
+#include "unicode/ures.h"
+#include "unicode/uchar.h"
+#include "unicode/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;
+    }
+    if ( U_FAILURE(status) ) {
+        delete hTable; 
+        return NULL;
+    }
+    hTable->setValueComparator(decimfmtAffixValueComparator);
+    return hTable;
+}
+
+Hashtable*
+DecimalFormat::initHashForAffixPattern(UErrorCode& status) {
+    if ( U_FAILURE(status) ) {
+        return NULL;
+    }
+    Hashtable* hTable;
+    if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    if ( U_FAILURE(status) ) {
+        delete hTable; 
+        return NULL;
+    }
+    hTable->setValueComparator(decimfmtAffixPatternValueComparator);
+    return hTable;
+}
+
+void
+DecimalFormat::deleteHashForAffix(Hashtable*& table)
+{
+    if ( table == NULL ) {
+        return;
+    }
+    int32_t pos = -1;
+    const UHashElement* element = NULL;
+    while ( (element = table->nextElement(pos)) != NULL ) {
+        const UHashTok 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/source/i18n/digitlst.cpp b/source/i18n/digitlst.cpp
new file mode 100644
index 0000000..f3040d8
--- /dev/null
+++ b/source/i18n/digitlst.cpp
@@ -0,0 +1,865 @@
+/*
+**********************************************************************
+*   Copyright (C) 1997-2011, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*
+* File DIGITLST.CPP
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   03/21/97    clhuang     Converted from java.
+*   03/21/97    clhuang     Implemented with new APIs.
+*   03/27/97    helena      Updated to pass the simple test after code review.
+*   03/31/97    aliu        Moved isLONG_MIN to here, and fixed it.
+*   04/15/97    aliu        Changed MAX_COUNT to DBL_DIG.  Changed Digit to char.
+*                           Reworked representation by replacing fDecimalAt
+*                           with fExponent.
+*   04/16/97    aliu        Rewrote set() and getDouble() to use sprintf/atof
+*                           to do digit conversion.
+*   09/09/97    aliu        Modified for exponential notation support.
+*   08/02/98    stephen     Added nearest/even rounding
+*                            Fixed bug in fitsIntoLong
+******************************************************************************
+*/
+
+#include "digitlst.h"
+
+#if !UCONFIG_NO_FORMATTING
+#include "unicode/putil.h"
+#include "charstr.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "putilimp.h"
+#include "uassert.h"
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits>
+
+// ***************************************************************************
+// class DigitList
+//    A wrapper onto decNumber.
+//    Used to be standalone.
+// ***************************************************************************
+
+/**
+ * This is the zero digit.  The base for the digits returned by getDigit()
+ * Note that it is the platform invariant digit, and is not Unicode.
+ */
+#define kZero '0'
+
+static char gDecimal = 0;
+
+/* Only for 32 bit numbers. Ignore the negative sign. */
+static const char LONG_MIN_REP[] = "2147483648";
+static const char I64_MIN_REP[] = "9223372036854775808";
+
+
+U_NAMESPACE_BEGIN
+
+// -------------------------------------
+// default constructor
+
+DigitList::DigitList()
+{
+    uprv_decContextDefault(&fContext, DEC_INIT_BASE);
+    fContext.traps  = 0;
+    uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN);
+    fContext.digits = fStorage.getCapacity();
+
+    fDecNumber = fStorage.getAlias();
+    uprv_decNumberZero(fDecNumber);
+
+    fDouble = 0.0;
+    fHaveDouble = TRUE;
+}
+
+// -------------------------------------
+
+DigitList::~DigitList()
+{
+}
+
+// -------------------------------------
+// copy constructor
+
+DigitList::DigitList(const DigitList &other)
+{
+    fDecNumber = fStorage.getAlias();
+    *this = other;
+}
+
+
+// -------------------------------------
+// assignment operator
+
+DigitList&
+DigitList::operator=(const DigitList& other)
+{
+    if (this != &other)
+    {
+        uprv_memcpy(&fContext, &other.fContext, sizeof(decContext));
+
+        if (other.fStorage.getCapacity() > fStorage.getCapacity()) {
+            fDecNumber = fStorage.resize(other.fStorage.getCapacity());
+        }
+        // Always reset the fContext.digits, even if fDecNumber was not reallocated,
+        // because above we copied fContext from other.fContext.
+        fContext.digits = fStorage.getCapacity();
+        uprv_decNumberCopy(fDecNumber, other.fDecNumber);
+
+        fDouble = other.fDouble;
+        fHaveDouble = other.fHaveDouble;
+    }
+    return *this;
+}
+
+// -------------------------------------
+//    operator ==  (does not exactly match the old DigitList function)
+
+UBool
+DigitList::operator==(const DigitList& that) const
+{
+    if (this == &that) {
+        return TRUE;
+    }
+    decNumber n;  // Has space for only a none digit value.
+    decContext c;
+    uprv_decContextDefault(&c, DEC_INIT_BASE);
+    c.digits = 1;
+    c.traps = 0;
+
+    uprv_decNumberCompare(&n, this->fDecNumber, that.fDecNumber, &c);
+    UBool result = decNumberIsZero(&n);
+    return result;
+}
+
+// -------------------------------------
+//      comparison function.   Returns 
+//         Not Comparable :  -2
+//                      < :  -1
+//                     == :   0
+//                      > :  +1
+int32_t DigitList::compare(const DigitList &other) {
+    decNumber   result;
+    int32_t     savedDigits = fContext.digits;
+    fContext.digits = 1;
+    uprv_decNumberCompare(&result, this->fDecNumber, other.fDecNumber, &fContext);
+    fContext.digits = savedDigits;
+    if (decNumberIsZero(&result)) {
+        return 0;
+    } else if (decNumberIsSpecial(&result)) {
+        return -2;
+    } else if (result.bits & DECNEG) {
+        return -1;
+    } else {
+        return 1;
+    }
+}
+
+
+// -------------------------------------
+//  Reduce - remove trailing zero digits.
+void
+DigitList::reduce() {
+    uprv_decNumberReduce(fDecNumber, fDecNumber, &fContext);
+}
+
+
+// -------------------------------------
+//  trim - remove trailing fraction zero digits.
+void
+DigitList::trim() {
+    uprv_decNumberTrim(fDecNumber);
+}
+
+// -------------------------------------
+// Resets the digit list; sets all the digits to zero.
+
+void
+DigitList::clear()
+{
+    uprv_decNumberZero(fDecNumber);
+    uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN);
+    fDouble = 0.0;
+    fHaveDouble = TRUE;
+}
+
+
+/**
+ * Formats a int64_t number into a base 10 string representation, and NULL terminates it.
+ * @param number The number to format
+ * @param outputStr The string to output to.  Must be at least MAX_DIGITS+2 in length (21),
+ *                  to hold the longest int64_t value.
+ * @return the number of digits written, not including the sign.
+ */
+static int32_t
+formatBase10(int64_t number, char *outputStr) {
+    // The number is output backwards, starting with the LSD.
+    // Fill the buffer from the far end.  After the number is complete,
+    // slide the string contents to the front.
+
+    const int32_t MAX_IDX = MAX_DIGITS+2;
+    int32_t destIdx = MAX_IDX;
+    outputStr[--destIdx] = 0; 
+
+    int64_t  n = number;
+    if (number < 0) {   // Negative numbers are slightly larger than a postive
+        outputStr[--destIdx] = (char)(-(n % 10) + kZero);
+        n /= -10;
+    }
+    do { 
+        outputStr[--destIdx] = (char)(n % 10 + kZero);
+        n /= 10;
+    } while (n > 0);
+    
+    if (number < 0) {
+        outputStr[--destIdx] = '-';
+    }
+
+    // Slide the number to the start of the output str
+    U_ASSERT(destIdx >= 0);
+    int32_t length = MAX_IDX - destIdx;
+    uprv_memmove(outputStr, outputStr+MAX_IDX-length, length);
+
+    return length;
+}
+
+
+// -------------------------------------
+
+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.   Truncate if there is a fractional part.
+ *  Return zero if the number cannot be represented.
+ */
+int64_t DigitList::getInt64() /*const*/ {
+    // Truncate if non-integer.
+    // Return 0 if out of range.
+    // Range of in64_t is -9223372036854775808 to 9223372036854775807  (19 digits)
+    //
+    if (fDecNumber->digits + fDecNumber->exponent > 19) {
+        // Overflow, absolute value too big.
+        return 0;
+    }
+
+    // The number of integer digits may differ from the number of digits stored
+    //   in the decimal number.
+    //     for 12.345  numIntDigits = 2, number->digits = 5
+    //     for 12E4    numIntDigits = 6, number->digits = 2
+    // The conversion ignores the fraction digits in the first case,
+    // and fakes up extra zero digits in the second.
+    // TODO:  It would be faster to store a table of powers of ten to multiply by
+    //        instead of looping over zero digits, multiplying each time.
+
+    int32_t numIntDigits = fDecNumber->digits + fDecNumber->exponent;
+    uint64_t value = 0;
+    for (int32_t i = 0; i < numIntDigits; i++) {
+        // Loop is iterating over digits starting with the most significant.
+        // Numbers are stored with the least significant digit at index zero.
+        int32_t digitIndex = fDecNumber->digits - i - 1;
+        int32_t v = (digitIndex >= 0) ? fDecNumber->lsu[digitIndex] : 0;
+        value = value * (uint64_t)10 + (uint64_t)v;
+    }
+
+    if (decNumberIsNegative(fDecNumber)) {
+        value = ~value;
+        value += 1;
+    }
+    int64_t svalue = (int64_t)value;
+
+    // Check overflow.  It's convenient that the MSD is 9 only on overflow, the amount of
+    //                  overflow can't wrap too far.  The test will also fail -0, but
+    //                  that does no harm; the right answer is 0.
+    if (numIntDigits == 19) {
+        if (( decNumberIsNegative(fDecNumber) && svalue>0) ||
+            (!decNumberIsNegative(fDecNumber) && svalue<0)) {
+            svalue = 0;
+        }
+    }
+        
+    return svalue;
+}
+
+
+/**
+ *  Return a string form of this number.
+ *     Format is as defined by the decNumber library, for interchange of
+ *     decimal numbers.
+ */
+void DigitList::getDecimal(CharString &str, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return;
+    }
+
+    // A decimal number in string form can, worst case, be 14 characters longer
+    //  than the number of digits.  So says the decNumber library doc.
+    int32_t maxLength = fDecNumber->digits + 14;
+    int32_t capacity = 0;
+    char *buffer = str.clear().getAppendBuffer(maxLength, 0, capacity, status);
+    if (U_FAILURE(status)) {
+        return;    // Memory allocation error on growing the string.
+    }
+    U_ASSERT(capacity >= maxLength);
+    uprv_decNumberToString(this->fDecNumber, buffer);
+    U_ASSERT((int32_t)uprv_strlen(buffer) <= maxLength);
+    str.append(buffer, -1, status);
+}
+
+/**
+ * Return true if this is an integer value that can be held
+ * by an int32_t type.
+ */
+UBool
+DigitList::fitsIntoLong(UBool ignoreNegativeZero) /*const*/
+{
+    if (decNumberIsSpecial(this->fDecNumber)) {
+        // NaN or Infinity.  Does not fit in int32.
+        return FALSE;
+    }
+    uprv_decNumberTrim(this->fDecNumber);
+    if (fDecNumber->exponent < 0) {
+        // Number contains fraction digits.
+        return FALSE;
+    }
+    if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero &&
+        (fDecNumber->bits & DECNEG) != 0) {
+        // Negative Zero, not ingored.  Cannot represent as a long.
+        return FALSE;
+    }
+    if (fDecNumber->digits + fDecNumber->exponent < 10) {
+        // The number is 9 or fewer digits.
+        // The max and min int32 are 10 digts, so this number fits.
+        // This is the common case.
+        return TRUE;
+    }
+
+    // TODO:  Should cache these constants; construction is relatively costly.
+    //        But not of huge consequence; they're only needed for 10 digit ints.
+    UErrorCode status = U_ZERO_ERROR;
+    DigitList min32; min32.set("-2147483648", status);
+    if (this->compare(min32) < 0) {
+        return FALSE;
+    }
+    DigitList max32; max32.set("2147483647", status);
+    if (this->compare(max32) > 0) {
+        return FALSE;
+    }
+    if (U_FAILURE(status)) {
+        return FALSE;
+    }
+    return true;
+}
+
+
+
+/**
+ * Return true if the number represented by this object can fit into
+ * a long.
+ */
+UBool
+DigitList::fitsIntoInt64(UBool ignoreNegativeZero) /*const*/
+{
+    if (decNumberIsSpecial(this->fDecNumber)) {
+        // NaN or Infinity.  Does not fit in int32.
+        return FALSE;
+    }
+    uprv_decNumberTrim(this->fDecNumber);
+    if (fDecNumber->exponent < 0) {
+        // Number contains fraction digits.
+        return FALSE;
+    }
+    if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero &&
+        (fDecNumber->bits & DECNEG) != 0) {
+        // Negative Zero, not ingored.  Cannot represent as a long.
+        return FALSE;
+    }
+    if (fDecNumber->digits + fDecNumber->exponent < 19) {
+        // The number is 18 or fewer digits.
+        // The max and min int64 are 19 digts, so this number fits.
+        // This is the common case.
+        return TRUE;
+    }
+
+    // TODO:  Should cache these constants; construction is relatively costly.
+    //        But not of huge consequence; they're only needed for 19 digit ints.
+    UErrorCode status = U_ZERO_ERROR;
+    DigitList min64; min64.set("-9223372036854775808", status);
+    if (this->compare(min64) < 0) {
+        return FALSE;
+    }
+    DigitList max64; max64.set("9223372036854775807", status);
+    if (this->compare(max64) > 0) {
+        return FALSE;
+    }
+    if (U_FAILURE(status)) {
+        return FALSE;
+    }
+    return true;
+}
+
+
+// -------------------------------------
+
+void
+DigitList::set(int32_t source)
+{
+    set((int64_t)source);
+    fDouble = source;
+    fHaveDouble = TRUE;
+}
+
+// -------------------------------------
+/**
+ * @param maximumDigits The maximum digits to be generated.  If zero,
+ * there is no maximum -- generate all digits.
+ */
+void
+DigitList::set(int64_t source)
+{
+    char str[MAX_DIGITS+2];   // Leave room for sign and trailing nul.
+    formatBase10(source, str);
+    U_ASSERT(uprv_strlen(str) < sizeof(str));
+
+    uprv_decNumberFromString(fDecNumber, str, &fContext);
+    fDouble = (double)source;
+    fHaveDouble = TRUE;
+}
+
+
+// -------------------------------------
+/**
+ * Set the DigitList from a decimal number string.
+ *
+ * The incoming string _must_ be nul terminated, even though it is arriving
+ * as a StringPiece because that is what the decNumber library wants.
+ * We can get away with this for an internal function; it would not
+ * be acceptable for a public API.
+ */
+void
+DigitList::set(const StringPiece &source, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return;
+    }
+
+    // Figure out a max number of digits to use during the conversion, and
+    // resize the number up if necessary.
+    int32_t numDigits = source.length();
+    if (numDigits > fContext.digits) {
+        // fContext.digits == fStorage.getCapacity()
+        decNumber *t = fStorage.resize(numDigits, fStorage.getCapacity());
+        if (t == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+        fDecNumber = t;
+        fContext.digits = numDigits;
+    }
+
+    fContext.status = 0;
+    uprv_decNumberFromString(fDecNumber, source.data(), &fContext);
+    if ((fContext.status & DEC_Conversion_syntax) != 0) {
+        status = U_DECIMAL_NUMBER_SYNTAX_ERROR;
+    }
+    fHaveDouble = FALSE;
+}   
+
+/**
+ * Set the digit list to a representation of the given double value.
+ * This method supports both fixed-point and exponential notation.
+ * @param source Value to be converted.
+ */
+void
+DigitList::set(double source)
+{
+    // for now, simple implementation; later, do proper IEEE stuff
+    char rep[MAX_DIGITS + 8]; // Extra space for '+', '.', e+NNN, and '\0' (actually +8 is enough)
+
+    // Generate a representation of the form /[+-][0-9]+e[+-][0-9]+/
+    sprintf(rep, "%+1.*e", MAX_DBL_DIGITS - 1, source);
+    U_ASSERT(uprv_strlen(rep) < sizeof(rep));
+
+    // Create a decNumber from the string.
+    uprv_decNumberFromString(fDecNumber, rep, &fContext);
+    uprv_decNumberTrim(fDecNumber);
+    fDouble = source;
+    fHaveDouble = TRUE;
+}
+
+// -------------------------------------
+
+/*
+ * Multiply
+ *      The number will be expanded if need be to retain full precision.
+ *      In practice, for formatting, multiply is by 10, 100 or 1000, so more digits
+ *      will not be required for this use.
+ */
+void
+DigitList::mult(const DigitList &other, UErrorCode &status) {
+    fContext.status = 0;
+    int32_t requiredDigits = this->digits() + other.digits();
+    if (requiredDigits > fContext.digits) {
+        reduce();    // Remove any trailing zeros
+        int32_t requiredDigits = this->digits() + other.digits();
+        ensureCapacity(requiredDigits, status);
+    }
+    uprv_decNumberMultiply(fDecNumber, fDecNumber, other.fDecNumber, &fContext);
+    fHaveDouble = FALSE;
+}
+
+// -------------------------------------
+
+/*
+ * Divide
+ *      The number will _not_ be expanded for inexact results.
+ *      TODO:  probably should expand some, for rounding increments that
+ *             could add a few digits, e.g. .25, but not expand arbitrarily.
+ */
+void
+DigitList::div(const DigitList &other, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return;
+    }
+    uprv_decNumberDivide(fDecNumber, fDecNumber, other.fDecNumber, &fContext);
+    fHaveDouble = FALSE;
+}
+
+// -------------------------------------
+
+/*
+ * ensureCapacity.   Grow the digit storage for the number if it's less than the requested
+ *         amount.  Never reduce it.  Available size is kept in fContext.digits.
+ */
+void
+DigitList::ensureCapacity(int32_t requestedCapacity, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return;
+    }
+    if (requestedCapacity <= 0) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    if (requestedCapacity > DEC_MAX_DIGITS) {
+        // Don't report an error for requesting too much.
+        // Arithemetic Results will be rounded to what can be supported.
+        //   At 999,999,999 max digits, exceeding the limit is not too likely!
+        requestedCapacity = DEC_MAX_DIGITS;
+    }
+    if (requestedCapacity > fContext.digits) {
+        decNumber *newBuffer = fStorage.resize(requestedCapacity, fStorage.getCapacity());
+        if (newBuffer == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+        fContext.digits = requestedCapacity;
+        fDecNumber = newBuffer;
+    }
+}
+
+// -------------------------------------
+
+/**
+ * Round the representation to the given number of digits.
+ * @param maximumDigits The maximum number of digits to be shown.
+ * Upon return, count will be less than or equal to maximumDigits.
+ */
+void
+DigitList::round(int32_t maximumDigits)
+{
+    int32_t savedDigits  = fContext.digits;
+    fContext.digits = maximumDigits;
+    uprv_decNumberPlus(fDecNumber, fDecNumber, &fContext);
+    fContext.digits = savedDigits;
+    uprv_decNumberTrim(fDecNumber);
+    fHaveDouble = FALSE;
+}
+
+
+void
+DigitList::roundFixedPoint(int32_t maximumFractionDigits) {
+    trim();        // Remove trailing zeros.
+    if (fDecNumber->exponent >= -maximumFractionDigits) {
+        return;
+    }
+    decNumber scale;   // Dummy decimal number, but with the desired number of
+    uprv_decNumberZero(&scale);    //    fraction digits.
+    scale.exponent = -maximumFractionDigits;
+    scale.lsu[0] = 1;
+    
+    uprv_decNumberQuantize(fDecNumber, fDecNumber, &scale, &fContext);
+    trim();
+    fHaveDouble = FALSE;
+}
+
+// -------------------------------------
+
+void
+DigitList::toIntegralValue() {
+    uprv_decNumberToIntegralValue(fDecNumber, fDecNumber, &fContext);
+}
+
+
+// -------------------------------------
+UBool
+DigitList::isZero() const
+{
+    return decNumberIsZero(fDecNumber);
+}
+
+
+U_NAMESPACE_END
+#endif // #if !UCONFIG_NO_FORMATTING
+
+//eof
diff --git a/source/i18n/digitlst.h b/source/i18n/digitlst.h
new file mode 100644
index 0000000..c95fb5f
--- /dev/null
+++ b/source/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/source/i18n/dtfmtsym.cpp b/source/i18n/dtfmtsym.cpp
new file mode 100644
index 0000000..78f2069
--- /dev/null
+++ b/source/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/source/i18n/dtitv_impl.h b/source/i18n/dtitv_impl.h
new file mode 100644
index 0000000..009d9a8
--- /dev/null
+++ b/source/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/source/i18n/dtitvfmt.cpp b/source/i18n/dtitvfmt.cpp
new file mode 100644
index 0000000..8bb6c6e
--- /dev/null
+++ b/source/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/source/i18n/dtitvinf.cpp b/source/i18n/dtitvinf.cpp
new file mode 100644
index 0000000..2cdcd2f
--- /dev/null
+++ b/source/i18n/dtitvinf.cpp
@@ -0,0 +1,664 @@
+/*******************************************************************************
+* Copyright (C) 2008-2011, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File DTITVINF.CPP 
+*
+*******************************************************************************
+*/
+
+#include "unicode/dtitvinf.h"
+
+
+#if !UCONFIG_NO_FORMATTING
+
+//TODO: define it in compiler time
+//#define DTITVINF_DEBUG 1
+
+
+#ifdef DTITVINF_DEBUG 
+#include <iostream>
+#endif
+
+#include "cstring.h"
+#include "unicode/msgfmt.h"
+#include "unicode/uloc.h"
+#include "unicode/ures.h"
+#include "dtitv_impl.h"
+#include "hash.h"
+#include "gregoimp.h"
+#include "uresimp.h"
+#include "hash.h"
+#include "gregoimp.h"
+#include "uresimp.h"
+
+
+U_NAMESPACE_BEGIN
+
+
+#ifdef DTITVINF_DEBUG 
+#define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; }
+#endif
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalInfo)
+
+static const char gCalendarTag[]="calendar";
+static const char gGregorianTag[]="gregorian";
+static const char gIntervalDateTimePatternTag[]="intervalFormats";
+static const char gFallbackPatternTag[]="fallback";
+
+// {0}
+static const UChar gFirstPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET};
+// {1}
+static const UChar gSecondPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET};
+
+// default fall-back
+static const UChar gDefaultFallbackPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, EN_DASH, SPACE, LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET, 0};
+
+
+
+DateIntervalInfo::DateIntervalInfo(UErrorCode& status) 
+:   fFallbackIntervalPattern(gDefaultFallbackPattern),
+    fFirstDateInPtnIsLaterDate(false),
+    fIntervalPatterns(NULL)
+{
+    fIntervalPatterns = initHash(status);
+}
+
+
+
+DateIntervalInfo::DateIntervalInfo(const Locale& locale, UErrorCode& status)
+:   fFallbackIntervalPattern(gDefaultFallbackPattern),
+    fFirstDateInPtnIsLaterDate(false),
+    fIntervalPatterns(NULL)
+{
+    initializeData(locale, status);
+}
+
+
+
+void
+DateIntervalInfo::setIntervalPattern(const UnicodeString& skeleton,
+                                     UCalendarDateFields lrgDiffCalUnit,
+                                     const UnicodeString& intervalPattern,
+                                     UErrorCode& status) {
+    
+    if ( lrgDiffCalUnit == UCAL_HOUR_OF_DAY ) {
+        setIntervalPatternInternally(skeleton, UCAL_AM_PM, intervalPattern, status);
+        setIntervalPatternInternally(skeleton, UCAL_HOUR, intervalPattern, status);
+    } else if ( lrgDiffCalUnit == UCAL_DAY_OF_MONTH ||
+                lrgDiffCalUnit == UCAL_DAY_OF_WEEK ) {
+        setIntervalPatternInternally(skeleton, UCAL_DATE, intervalPattern, status);
+    } else {
+        setIntervalPatternInternally(skeleton, lrgDiffCalUnit, intervalPattern, status);
+    }
+}
+
+
+void
+DateIntervalInfo::setFallbackIntervalPattern(
+                                    const UnicodeString& fallbackPattern,
+                                    UErrorCode& status) {
+    if ( U_FAILURE(status) ) {
+        return;
+    }
+    int32_t firstPatternIndex = fallbackPattern.indexOf(gFirstPattern, 
+                        sizeof(gFirstPattern)/sizeof(gFirstPattern[0]), 0);
+    int32_t secondPatternIndex = fallbackPattern.indexOf(gSecondPattern, 
+                        sizeof(gSecondPattern)/sizeof(gSecondPattern[0]), 0);
+    if ( firstPatternIndex == -1 || secondPatternIndex == -1 ) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+    if ( firstPatternIndex > secondPatternIndex ) { 
+        fFirstDateInPtnIsLaterDate = true;
+    }
+    fFallbackIntervalPattern = fallbackPattern;
+}
+
+
+
+DateIntervalInfo::DateIntervalInfo(const DateIntervalInfo& dtitvinf)
+:   UObject(dtitvinf),
+    fIntervalPatterns(NULL)
+{
+    *this = dtitvinf;
+}
+    
+
+
+DateIntervalInfo&
+DateIntervalInfo::operator=(const DateIntervalInfo& dtitvinf) {
+    if ( this == &dtitvinf ) {
+        return *this;
+    }
+    
+    UErrorCode status = U_ZERO_ERROR;
+    deleteHash(fIntervalPatterns);
+    fIntervalPatterns = initHash(status);
+    copyHash(dtitvinf.fIntervalPatterns, fIntervalPatterns, status);
+    if ( U_FAILURE(status) ) {
+        return *this;
+    } 
+
+    fFallbackIntervalPattern = dtitvinf.fFallbackIntervalPattern;
+    fFirstDateInPtnIsLaterDate = dtitvinf.fFirstDateInPtnIsLaterDate;
+    return *this;
+}
+
+
+DateIntervalInfo*
+DateIntervalInfo::clone() const {
+    return new DateIntervalInfo(*this);
+}
+
+
+DateIntervalInfo::~DateIntervalInfo() {
+    deleteHash(fIntervalPatterns);
+    fIntervalPatterns = NULL;
+}
+
+
+UBool
+DateIntervalInfo::operator==(const DateIntervalInfo& other) const {
+    UBool equal = ( 
+      fFallbackIntervalPattern == other.fFallbackIntervalPattern &&
+      fFirstDateInPtnIsLaterDate == other.fFirstDateInPtnIsLaterDate );
+
+    if ( equal == TRUE ) {
+        equal = fIntervalPatterns->equals(*(other.fIntervalPatterns));
+    }
+
+    return equal;
+}
+
+
+UnicodeString&
+DateIntervalInfo::getIntervalPattern(const UnicodeString& skeleton,
+                                     UCalendarDateFields field,
+                                     UnicodeString& result,
+                                     UErrorCode& status) const {
+    if ( U_FAILURE(status) ) {
+        return result;
+    }
+   
+    const UnicodeString* patternsOfOneSkeleton = (UnicodeString*) fIntervalPatterns->get(skeleton);
+    if ( patternsOfOneSkeleton != NULL ) {
+        IntervalPatternIndex index = calendarFieldToIntervalIndex(field, status);
+        if ( U_FAILURE(status) ) {
+            return result;
+        }
+        const UnicodeString& intervalPattern =  patternsOfOneSkeleton[index];
+        if ( !intervalPattern.isEmpty() ) {
+            result = intervalPattern;
+        }
+    }
+    return result;
+}
+
+
+UBool
+DateIntervalInfo::getDefaultOrder() const {
+    return fFirstDateInPtnIsLaterDate;
+}
+
+
+UnicodeString&
+DateIntervalInfo::getFallbackIntervalPattern(UnicodeString& result) const {
+    result = fFallbackIntervalPattern;
+    return result;
+}
+
+#define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
+
+void 
+DateIntervalInfo::initializeData(const Locale& locale, UErrorCode& err)
+{
+  fIntervalPatterns = initHash(err);
+  if ( U_FAILURE(err) ) {
+      return;
+  }
+  const char *locName = locale.getName();
+  char parentLocale[ULOC_FULLNAME_CAPACITY];
+  int32_t locNameLen;
+  uprv_strcpy(parentLocale, locName);
+  UErrorCode status = U_ZERO_ERROR;
+  Hashtable skeletonSet(FALSE, status);
+  if ( U_FAILURE(status) ) {
+      return;
+  }
+
+  // determine calendar type
+  const char * calendarTypeToUse = gGregorianTag; // initial default
+  char         calendarType[ULOC_KEYWORDS_CAPACITY]; // to be filled in with the type to use, if all goes well
+  char         localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY];
+  // obtain a locale that always has the calendar key value that should be used
+  (void)ures_getFunctionalEquivalent(localeWithCalendarKey, ULOC_LOCALE_IDENTIFIER_CAPACITY, NULL,
+                                     "calendar", "calendar", locName, NULL, FALSE, &status);
+  localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination
+  // now get the calendar key value from that locale
+  int32_t calendarTypeLen = uloc_getKeywordValue(localeWithCalendarKey, "calendar", calendarType, ULOC_KEYWORDS_CAPACITY, &status);
+  if (U_SUCCESS(status) && calendarTypeLen < ULOC_KEYWORDS_CAPACITY) {
+    calendarTypeToUse = calendarType;
+  }
+  status = U_ZERO_ERROR;
+  
+  do {
+    UResourceBundle *rb, *calBundle, *calTypeBundle, *itvDtPtnResource;
+    rb = ures_open(NULL, parentLocale, &status);
+    calBundle = ures_getByKey(rb, gCalendarTag, NULL, &status); 
+    calTypeBundle = ures_getByKey(calBundle, calendarTypeToUse, NULL, &status);
+    itvDtPtnResource = ures_getByKeyWithFallback(calTypeBundle, 
+                         gIntervalDateTimePatternTag, NULL, &status);
+
+    if ( U_SUCCESS(status) ) {
+        // look for fallback first, since it establishes the default order
+        const UChar* resStr;
+        int32_t resStrLen = 0;
+        resStr = ures_getStringByKeyWithFallback(itvDtPtnResource, 
+                                             gFallbackPatternTag, 
+                                             &resStrLen, &status);
+        if ( U_SUCCESS(status) ) {
+            UnicodeString pattern = UnicodeString(TRUE, resStr, resStrLen);
+            setFallbackIntervalPattern(pattern, status);
+        }
+
+        int32_t size = ures_getSize(itvDtPtnResource);
+        int32_t index;
+        for ( index = 0; index < size; ++index ) {
+            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;
+    }
+    if ( U_FAILURE(status) ) {
+        delete hTable; 
+        return NULL;
+    }
+    hTable->setValueComparator(dtitvinfHashTableValueComparator);
+    return hTable;
+}
+
+
+void
+DateIntervalInfo::copyHash(const Hashtable* source,
+                           Hashtable* target,
+                           UErrorCode& status) {
+    if ( U_FAILURE(status) ) {
+        return;
+    }
+    int32_t pos = -1;
+    const UHashElement* element = NULL;
+    if ( source ) {
+        while ( (element = source->nextElement(pos)) != NULL ) {
+            const UHashTok keyTok = element->key;
+            const UnicodeString* key = (UnicodeString*)keyTok.pointer;
+            const UHashTok valueTok = element->value;
+            const UnicodeString* value = (UnicodeString*)valueTok.pointer;
+            UnicodeString* copy = new UnicodeString[kIPI_MAX_INDEX];
+            int8_t i;
+            for ( i = 0; i < kIPI_MAX_INDEX; ++i ) {
+                copy[i] = value[i];
+            }
+            target->put(UnicodeString(*key), copy, status);
+            if ( U_FAILURE(status) ) {
+                return;
+            }
+        }
+    }
+}
+
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/i18n/dtptngen.cpp b/source/i18n/dtptngen.cpp
new file mode 100644
index 0000000..bb4dd27
--- /dev/null
+++ b/source/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/source/i18n/dtptngen_impl.h b/source/i18n/dtptngen_impl.h
new file mode 100644
index 0000000..25afef8
--- /dev/null
+++ b/source/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/source/i18n/dtrule.cpp b/source/i18n/dtrule.cpp
new file mode 100644
index 0000000..c2eeb05
--- /dev/null
+++ b/source/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/source/i18n/esctrn.cpp b/source/i18n/esctrn.cpp
new file mode 100644
index 0000000..93f13f5
--- /dev/null
+++ b/source/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/source/i18n/esctrn.h b/source/i18n/esctrn.h
new file mode 100644
index 0000000..96872b9
--- /dev/null
+++ b/source/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/source/i18n/ethpccal.cpp b/source/i18n/ethpccal.cpp
new file mode 100644
index 0000000..9317dea
--- /dev/null
+++ b/source/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/source/i18n/ethpccal.h b/source/i18n/ethpccal.h
new file mode 100644
index 0000000..01db826
--- /dev/null
+++ b/source/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/source/i18n/fmtable.cpp b/source/i18n/fmtable.cpp
new file mode 100644
index 0000000..685fe21
--- /dev/null
+++ b/source/i18n/fmtable.cpp
@@ -0,0 +1,866 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2011, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*
+* File FMTABLE.CPP
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   03/25/97    clhuang     Initial Implementation.
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include <math.h>
+#include "unicode/fmtable.h"
+#include "unicode/ustring.h"
+#include "unicode/measure.h"
+#include "unicode/curramt.h"
+#include "charstr.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "decNumber.h"
+#include "digitlst.h"
+
+// *****************************************************************************
+// class Formattable
+// *****************************************************************************
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable)
+
+//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
+
+// NOTE: As of 3.0, there are limitations to the UObject API.  It does
+// not (yet) support cloning, operator=, nor operator==.  To
+// work around this, I implement some simple inlines here.  Later
+// these can be modified or removed.  [alan]
+
+// NOTE: These inlines assume that all fObjects are in fact instances
+// of the Measure class, which is true as of 3.0.  [alan]
+
+// Return TRUE if *a == *b.
+static inline UBool objectEquals(const UObject* a, const UObject* b) {
+    // LATER: return *a == *b;
+    return *((const Measure*) a) == *((const Measure*) b);
+}
+
+// Return a clone of *a.
+static inline UObject* objectClone(const UObject* a) {
+    // LATER: return a->clone();
+    return ((const Measure*) a)->clone();
+}
+
+// Return TRUE if *a is an instance of Measure.
+static inline UBool instanceOfMeasure(const UObject* a) {
+    return dynamic_cast<const Measure*>(a) != NULL;
+}
+
+/**
+ * Creates a new Formattable array and copies the values from the specified
+ * original.
+ * @param array the original array
+ * @param count the original array count
+ * @return the new Formattable array.
+ */
+static Formattable* createArrayCopy(const Formattable* array, int32_t count) {
+    Formattable *result = new Formattable[count];
+    if (result != NULL) {
+        for (int32_t i=0; i<count; ++i)
+            result[i] = array[i]; // Don't memcpy!
+    }
+    return result;
+}
+
+//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
+
+/**
+ * Set 'ec' to 'err' only if 'ec' is not already set to a failing UErrorCode.
+ */
+static void setError(UErrorCode& ec, UErrorCode err) {
+    if (U_SUCCESS(ec)) {
+        ec = err;
+    }
+}
+
+//
+//  Common initialization code, shared by constructors.
+//  Put everything into a known state.
+//
+void  Formattable::init() {
+    fValue.fInt64 = 0;
+    fType = kLong;
+    fDecimalStr = NULL;
+    fDecimalNum = NULL;
+    fBogus.setToBogus(); 
+}
+
+// -------------------------------------
+// default constructor.
+// Creates a formattable object with a long value 0.
+
+Formattable::Formattable() {
+    init();
+}
+
+// -------------------------------------
+// Creates a formattable object with a Date instance.
+
+Formattable::Formattable(UDate date, ISDATE /*isDate*/)
+{
+    init();
+    fType = kDate;
+    fValue.fDate = date;
+}
+
+// -------------------------------------
+// Creates a formattable object with a double value.
+
+Formattable::Formattable(double value)
+{
+    init();
+    fType = kDouble;
+    fValue.fDouble = value;
+}
+
+// -------------------------------------
+// Creates a formattable object with an int32_t value.
+
+Formattable::Formattable(int32_t value)
+{
+    init();
+    fValue.fInt64 = value;
+}
+
+// -------------------------------------
+// Creates a formattable object with an int64_t value.
+
+Formattable::Formattable(int64_t value)
+{
+    init();
+    fType = kInt64;
+    fValue.fInt64 = value;
+}
+
+// -------------------------------------
+// Creates a formattable object with a decimal number value from a string.
+
+Formattable::Formattable(const StringPiece &number, UErrorCode &status) {
+    init();
+    setDecimalNumber(number, status);
+}
+
+
+// -------------------------------------
+// Creates a formattable object with a UnicodeString instance.
+
+Formattable::Formattable(const UnicodeString& stringToCopy)
+{
+    init();
+    fType = kString;
+    fValue.fString = new UnicodeString(stringToCopy);
+}
+
+// -------------------------------------
+// Creates a formattable object with a UnicodeString* value.
+// (adopting symantics)
+
+Formattable::Formattable(UnicodeString* stringToAdopt)
+{
+    init();
+    fType = kString;
+    fValue.fString = stringToAdopt;
+}
+
+Formattable::Formattable(UObject* objectToAdopt)
+{
+    init();
+    fType = kObject;
+    fValue.fObject = objectToAdopt;
+}
+
+// -------------------------------------
+
+Formattable::Formattable(const Formattable* arrayToCopy, int32_t count)
+    :   UObject(), fType(kArray)
+{
+    init();
+    fType = kArray;
+    fValue.fArrayAndCount.fArray = createArrayCopy(arrayToCopy, count);
+    fValue.fArrayAndCount.fCount = count;
+}
+
+// -------------------------------------
+// copy constructor
+
+
+Formattable::Formattable(const Formattable &source)
+     :  UObject(*this)
+{
+    init();
+    *this = source;
+}
+
+// -------------------------------------
+// assignment operator
+
+Formattable&
+Formattable::operator=(const Formattable& source)
+{
+    if (this != &source)
+    {
+        // Disposes the current formattable value/setting.
+        dispose();
+
+        // Sets the correct data type for this value.
+        fType = source.fType;
+        switch (fType)
+        {
+        case kArray:
+            // Sets each element in the array one by one and records the array count.
+            fValue.fArrayAndCount.fCount = source.fValue.fArrayAndCount.fCount;
+            fValue.fArrayAndCount.fArray = createArrayCopy(source.fValue.fArrayAndCount.fArray,
+                                                           source.fValue.fArrayAndCount.fCount);
+            break;
+        case kString:
+            // Sets the string value.
+            fValue.fString = new UnicodeString(*source.fValue.fString);
+            break;
+        case kDouble:
+            // Sets the double value.
+            fValue.fDouble = source.fValue.fDouble;
+            break;
+        case kLong:
+        case kInt64:
+            // Sets the long value.
+            fValue.fInt64 = source.fValue.fInt64;
+            break;
+        case kDate:
+            // Sets the Date value.
+            fValue.fDate = source.fValue.fDate;
+            break;
+        case kObject:
+            fValue.fObject = objectClone(source.fValue.fObject);
+            break;
+        }
+
+        UErrorCode status = U_ZERO_ERROR;
+        if (source.fDecimalNum != NULL) {
+            fDecimalNum = new DigitList(*source.fDecimalNum);
+        }
+        if (source.fDecimalStr != NULL) {
+            fDecimalStr = new CharString(*source.fDecimalStr, status);
+            if (U_FAILURE(status)) {
+                delete fDecimalStr;
+                fDecimalStr = NULL;
+            }
+        }
+    }
+    return *this;
+}
+
+// -------------------------------------
+
+UBool
+Formattable::operator==(const Formattable& that) const
+{
+    int32_t i;
+
+    if (this == &that) return TRUE;
+
+    // Returns FALSE if the data types are different.
+    if (fType != that.fType) return FALSE;
+
+    // Compares the actual data values.
+    UBool equal = TRUE;
+    switch (fType) {
+    case kDate:
+        equal = (fValue.fDate == that.fValue.fDate);
+        break;
+    case kDouble:
+        equal = (fValue.fDouble == that.fValue.fDouble);
+        break;
+    case kLong:
+    case kInt64:
+        equal = (fValue.fInt64 == that.fValue.fInt64);
+        break;
+    case kString:
+        equal = (*(fValue.fString) == *(that.fValue.fString));
+        break;
+    case kArray:
+        if (fValue.fArrayAndCount.fCount != that.fValue.fArrayAndCount.fCount) {
+            equal = FALSE;
+            break;
+        }
+        // Checks each element for equality.
+        for (i=0; i<fValue.fArrayAndCount.fCount; ++i) {
+            if (fValue.fArrayAndCount.fArray[i] != that.fValue.fArrayAndCount.fArray[i]) {
+                equal = FALSE;
+                break;
+            }
+        }
+        break;
+    case kObject:
+        if (fValue.fObject == NULL || that.fValue.fObject == NULL) {
+            equal = FALSE;
+        } else {
+            equal = objectEquals(fValue.fObject, that.fValue.fObject);
+        }
+        break;
+    }
+
+    // TODO:  compare digit lists if numeric.
+    return equal;
+}
+
+// -------------------------------------
+
+Formattable::~Formattable()
+{
+    dispose();
+}
+
+// -------------------------------------
+
+void Formattable::dispose()
+{
+    // Deletes the data value if necessary.
+    switch (fType) {
+    case kString:
+        delete fValue.fString;
+        break;
+    case kArray:
+        delete[] fValue.fArrayAndCount.fArray;
+        break;
+    case kObject:
+        delete fValue.fObject;
+        break;
+    default:
+        break;
+    }
+
+    fType = kLong;
+    fValue.fInt64 = 0;
+    delete fDecimalStr;
+    fDecimalStr = NULL;
+    delete fDecimalNum;
+    fDecimalNum = NULL;
+}
+
+Formattable *
+Formattable::clone() const {
+    return new Formattable(*this);
+}
+
+// -------------------------------------
+// Gets the data type of this Formattable object. 
+Formattable::Type
+Formattable::getType() const
+{
+    return fType;
+}
+
+UBool
+Formattable::isNumeric() const {
+    switch (fType) {
+    case kDouble:
+    case kLong:
+    case kInt64:
+        return TRUE;
+    default:
+        return FALSE;
+    }
+}
+
+// -------------------------------------
+int32_t
+//Formattable::getLong(UErrorCode* status) const
+Formattable::getLong(UErrorCode& status) const
+{
+    if (U_FAILURE(status)) {
+        return 0;
+    }
+        
+    switch (fType) {
+    case Formattable::kLong: 
+        return (int32_t)fValue.fInt64;
+    case Formattable::kInt64: 
+        if (fValue.fInt64 > INT32_MAX) {
+            status = U_INVALID_FORMAT_ERROR;
+            return INT32_MAX;
+        } else if (fValue.fInt64 < INT32_MIN) {
+            status = U_INVALID_FORMAT_ERROR;
+            return INT32_MIN;
+        } else {
+            return (int32_t)fValue.fInt64;
+        }
+    case Formattable::kDouble:
+        if (fValue.fDouble > INT32_MAX) {
+            status = U_INVALID_FORMAT_ERROR;
+            return INT32_MAX;
+        } else if (fValue.fDouble < INT32_MIN) {
+            status = U_INVALID_FORMAT_ERROR;
+            return INT32_MIN;
+        } else {
+            return (int32_t)fValue.fDouble; // loses fraction
+        }
+    case Formattable::kObject:
+        if (fValue.fObject == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+        // TODO Later replace this with instanceof call
+        if (instanceOfMeasure(fValue.fObject)) {
+            return ((const Measure*) fValue.fObject)->
+                getNumber().getLong(status);
+        }
+    default: 
+        status = U_INVALID_FORMAT_ERROR;
+        return 0;
+    }
+}
+
+// -------------------------------------
+// Maximum int that can be represented exactly in a double.  (53 bits)
+//    Larger ints may be rounded to a near-by value as not all are representable.
+// TODO:  move this constant elsewhere, possibly configure it for different
+//        floating point formats, if any non-standard ones are still in use.
+static const int64_t U_DOUBLE_MAX_EXACT_INT = 9007199254740992LL;
+
+int64_t
+Formattable::getInt64(UErrorCode& status) const
+{
+    if (U_FAILURE(status)) {
+        return 0;
+    }
+        
+    switch (fType) {
+    case Formattable::kLong: 
+    case Formattable::kInt64: 
+        return fValue.fInt64;
+    case Formattable::kDouble:
+        if (fValue.fDouble > (double)U_INT64_MAX) {
+            status = U_INVALID_FORMAT_ERROR;
+            return U_INT64_MAX;
+        } else if (fValue.fDouble < (double)U_INT64_MIN) {
+            status = U_INVALID_FORMAT_ERROR;
+            return U_INT64_MIN;
+        } else if (fabs(fValue.fDouble) > U_DOUBLE_MAX_EXACT_INT && fDecimalNum != NULL) {
+            int64_t val = fDecimalNum->getInt64();
+            if (val != 0) {
+                return val;
+            } else {
+                status = U_INVALID_FORMAT_ERROR;
+                return fValue.fDouble > 0 ? U_INT64_MAX : U_INT64_MIN;
+            }
+        } else {
+            return (int64_t)fValue.fDouble;
+        } 
+    case Formattable::kObject:
+        if (fValue.fObject == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+        if (instanceOfMeasure(fValue.fObject)) {
+            return ((const Measure*) fValue.fObject)->
+                getNumber().getInt64(status);
+        }
+    default: 
+        status = U_INVALID_FORMAT_ERROR;
+        return 0;
+    }
+}
+
+// -------------------------------------
+double
+Formattable::getDouble(UErrorCode& status) const
+{
+    if (U_FAILURE(status)) {
+        return 0;
+    }
+        
+    switch (fType) {
+    case Formattable::kLong: 
+    case Formattable::kInt64: // loses precision
+        return (double)fValue.fInt64;
+    case Formattable::kDouble:
+        return fValue.fDouble;
+    case Formattable::kObject:
+        if (fValue.fObject == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+        // TODO Later replace this with instanceof call
+        if (instanceOfMeasure(fValue.fObject)) {
+            return ((const Measure*) fValue.fObject)->
+                getNumber().getDouble(status);
+        }
+    default: 
+        status = U_INVALID_FORMAT_ERROR;
+        return 0;
+    }
+}
+
+const UObject*
+Formattable::getObject() const {
+    return (fType == kObject) ? fValue.fObject : NULL;
+}
+
+// -------------------------------------
+// Sets the value to a double value d.
+
+void
+Formattable::setDouble(double d)
+{
+    dispose();
+    fType = kDouble;
+    fValue.fDouble = d;
+}
+
+// -------------------------------------
+// Sets the value to a long value l.
+
+void
+Formattable::setLong(int32_t l)
+{
+    dispose();
+    fType = kLong;
+    fValue.fInt64 = l;
+}
+
+// -------------------------------------
+// Sets the value to an int64 value ll.
+
+void
+Formattable::setInt64(int64_t ll)
+{
+    dispose();
+    fType = kInt64;
+    fValue.fInt64 = ll;
+}
+
+// -------------------------------------
+// Sets the value to a Date instance d.
+
+void
+Formattable::setDate(UDate d)
+{
+    dispose();
+    fType = kDate;
+    fValue.fDate = d;
+}
+
+// -------------------------------------
+// Sets the value to a string value stringToCopy.
+
+void
+Formattable::setString(const UnicodeString& stringToCopy)
+{
+    dispose();
+    fType = kString;
+    fValue.fString = new UnicodeString(stringToCopy);
+}
+
+// -------------------------------------
+// Sets the value to an array of Formattable objects.
+
+void
+Formattable::setArray(const Formattable* array, int32_t count)
+{
+    dispose();
+    fType = kArray;
+    fValue.fArrayAndCount.fArray = createArrayCopy(array, count);
+    fValue.fArrayAndCount.fCount = count;
+}
+
+// -------------------------------------
+// Adopts the stringToAdopt value.
+
+void
+Formattable::adoptString(UnicodeString* stringToAdopt)
+{
+    dispose();
+    fType = kString;
+    fValue.fString = stringToAdopt;
+}
+
+// -------------------------------------
+// Adopts the array value and its count.
+
+void
+Formattable::adoptArray(Formattable* array, int32_t count)
+{
+    dispose();
+    fType = kArray;
+    fValue.fArrayAndCount.fArray = array;
+    fValue.fArrayAndCount.fCount = count;
+}
+
+void
+Formattable::adoptObject(UObject* objectToAdopt) {
+    dispose();
+    fType = kObject;
+    fValue.fObject = objectToAdopt;
+}
+
+// -------------------------------------
+UnicodeString& 
+Formattable::getString(UnicodeString& result, UErrorCode& status) const 
+{
+    if (fType != kString) {
+        setError(status, U_INVALID_FORMAT_ERROR);
+        result.setToBogus();
+    } else {
+        if (fValue.fString == NULL) {
+            setError(status, U_MEMORY_ALLOCATION_ERROR);
+        } else {
+            result = *fValue.fString;
+        }
+    }
+    return result;
+}
+
+// -------------------------------------
+const UnicodeString& 
+Formattable::getString(UErrorCode& status) const 
+{
+    if (fType != kString) {
+        setError(status, U_INVALID_FORMAT_ERROR);
+        return *getBogus();
+    }
+    if (fValue.fString == NULL) {
+        setError(status, U_MEMORY_ALLOCATION_ERROR);
+        return *getBogus();
+    }
+    return *fValue.fString;
+}
+
+// -------------------------------------
+UnicodeString& 
+Formattable::getString(UErrorCode& status) 
+{
+    if (fType != kString) {
+        setError(status, U_INVALID_FORMAT_ERROR);
+        return *getBogus();
+    }
+    if (fValue.fString == NULL) {
+    	setError(status, U_MEMORY_ALLOCATION_ERROR);
+    	return *getBogus();
+    }
+    return *fValue.fString;
+}
+
+// -------------------------------------
+const Formattable* 
+Formattable::getArray(int32_t& count, UErrorCode& status) const 
+{
+    if (fType != kArray) {
+        setError(status, U_INVALID_FORMAT_ERROR);
+        count = 0;
+        return NULL;
+    }
+    count = fValue.fArrayAndCount.fCount; 
+    return fValue.fArrayAndCount.fArray;
+}
+
+// -------------------------------------
+// Gets the bogus string, ensures mondo bogosity.
+
+UnicodeString*
+Formattable::getBogus() const 
+{
+    return (UnicodeString*)&fBogus; /* cast away const :-( */
+}
+
+
+// --------------------------------------
+StringPiece Formattable::getDecimalNumber(UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return "";
+    }
+    if (fDecimalStr != NULL) {
+        return fDecimalStr->toStringPiece();
+    }
+
+    if (fDecimalNum == NULL) {
+        // No decimal number for the formattable yet.  Which means the value was
+        // set directly by the user as an int, int64 or double.  If the value came
+        // from parsing, or from the user setting a decimal number, fDecimalNum
+        // would already be set.
+        //
+        fDecimalNum = new DigitList;
+        if (fDecimalNum == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return "";
+        }
+
+        switch (fType) {
+        case kDouble:
+            fDecimalNum->set(this->getDouble());
+            break;
+        case kLong:
+            fDecimalNum->set(this->getLong());
+            break;
+        case kInt64:
+            fDecimalNum->set(this->getInt64());
+            break;
+        default:
+            // The formattable's value is not a numeric type.
+            status = U_INVALID_STATE_ERROR;
+            return "";
+        }
+    }
+
+    fDecimalStr = new CharString;
+    if (fDecimalStr == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return "";
+    }
+    fDecimalNum->getDecimal(*fDecimalStr, status);
+
+    return fDecimalStr->toStringPiece();
+}
+
+
+
+// ---------------------------------------
+void
+Formattable::adoptDigitList(DigitList *dl) {
+    dispose();
+
+    fDecimalNum = dl;
+
+    // Set the value into the Union of simple type values.
+    // Cannot use the set() functions because they would delete the fDecimalNum value,
+
+    if (fDecimalNum->fitsIntoLong(FALSE)) {
+        fType = kLong;
+        fValue.fInt64 = fDecimalNum->getLong();
+    } else if (fDecimalNum->fitsIntoInt64(FALSE)) {
+        fType = kInt64;
+        fValue.fInt64 = fDecimalNum->getInt64();
+    } else {
+        fType = kDouble;
+        fValue.fDouble = fDecimalNum->getDouble();
+    }
+}
+
+
+// ---------------------------------------
+void
+Formattable::setDecimalNumber(const StringPiece &numberString, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return;
+    }
+    dispose();
+
+    // Copy the input string and nul-terminate it.
+    //    The decNumber library requires nul-terminated input.  StringPiece input
+    //    is not guaranteed nul-terminated.  Too bad.
+    //    CharString automatically adds the nul.
+    DigitList *dnum = new DigitList();
+    if (dnum == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    dnum->set(CharString(numberString, status).toStringPiece(), status);
+    if (U_FAILURE(status)) {
+        delete dnum;
+        return;   // String didn't contain a decimal number.
+    }
+    adoptDigitList(dnum);
+
+    // Note that we do not hang on to the caller's input string.
+    // If we are asked for the string, we will regenerate one from fDecimalNum.
+}
+
+#if 0
+//----------------------------------------------------
+// console I/O
+//----------------------------------------------------
+#ifdef _DEBUG
+
+#if U_IOSTREAM_SOURCE >= 199711
+#include <iostream>
+using namespace std;
+#elif U_IOSTREAM_SOURCE >= 198506
+#include <iostream.h>
+#endif
+
+#include "unicode/datefmt.h"
+#include "unistrm.h"
+
+class FormattableStreamer /* not : public UObject because all methods are static */ {
+public:
+    static void streamOut(ostream& stream, const Formattable& obj);
+
+private:
+    FormattableStreamer() {} // private - forbid instantiation
+};
+
+// This is for debugging purposes only.  This will send a displayable
+// form of the Formattable object to the output stream.
+
+void
+FormattableStreamer::streamOut(ostream& stream, const Formattable& obj)
+{
+    static DateFormat *defDateFormat = 0;
+
+    UnicodeString buffer;
+    switch(obj.getType()) {
+        case Formattable::kDate : 
+            // Creates a DateFormat instance for formatting the
+            // Date instance.
+            if (defDateFormat == 0) {
+                defDateFormat = DateFormat::createInstance();
+            }
+            defDateFormat->format(obj.getDate(), buffer);
+            stream << buffer;
+            break;
+        case Formattable::kDouble :
+            // Output the double as is.
+            stream << obj.getDouble() << 'D';
+            break;
+        case Formattable::kLong :
+            // Output the double as is.
+            stream << obj.getLong() << 'L';
+            break;
+        case Formattable::kString:
+            // Output the double as is.  Please see UnicodeString console
+            // I/O routine for more details.
+            stream << '"' << obj.getString(buffer) << '"';
+            break;
+        case Formattable::kArray:
+            int32_t i, count;
+            const Formattable* array;
+            array = obj.getArray(count);
+            stream << '[';
+            // Recursively calling the console I/O routine for each element in the array.
+            for (i=0; i<count; ++i) {
+                FormattableStreamer::streamOut(stream, array[i]);
+                stream << ( (i==(count-1)) ? "" : ", " );
+            }
+            stream << ']';
+            break;
+        default:
+            // Not a recognizable Formattable object.
+            stream << "INVALID_Formattable";
+    }
+    stream.flush();
+}
+#endif
+
+#endif
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/source/i18n/fmtable_cnv.cpp b/source/i18n/fmtable_cnv.cpp
new file mode 100644
index 0000000..8e96454
--- /dev/null
+++ b/source/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/source/i18n/format.cpp b/source/i18n/format.cpp
new file mode 100644
index 0000000..701b489
--- /dev/null
+++ b/source/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/source/i18n/fphdlimp.cpp b/source/i18n/fphdlimp.cpp
new file mode 100644
index 0000000..9d94a41
--- /dev/null
+++ b/source/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/source/i18n/fphdlimp.h b/source/i18n/fphdlimp.h
new file mode 100644
index 0000000..cd5c314
--- /dev/null
+++ b/source/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/source/i18n/fpositer.cpp b/source/i18n/fpositer.cpp
new file mode 100644
index 0000000..6971264
--- /dev/null
+++ b/source/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/source/i18n/funcrepl.cpp b/source/i18n/funcrepl.cpp
new file mode 100644
index 0000000..03d7183
--- /dev/null
+++ b/source/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/source/i18n/funcrepl.h b/source/i18n/funcrepl.h
new file mode 100644
index 0000000..f58d613
--- /dev/null
+++ b/source/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/source/i18n/gregocal.cpp b/source/i18n/gregocal.cpp
new file mode 100644
index 0000000..3bc77cf
--- /dev/null
+++ b/source/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/source/i18n/gregoimp.cpp b/source/i18n/gregoimp.cpp
new file mode 100644
index 0000000..08a3fbc
--- /dev/null
+++ b/source/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/source/i18n/gregoimp.h b/source/i18n/gregoimp.h
new file mode 100644
index 0000000..f65d141
--- /dev/null
+++ b/source/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/source/i18n/hebrwcal.cpp b/source/i18n/hebrwcal.cpp
new file mode 100644
index 0000000..3a6ef43
--- /dev/null
+++ b/source/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/source/i18n/hebrwcal.h b/source/i18n/hebrwcal.h
new file mode 100644
index 0000000..76f100f
--- /dev/null
+++ b/source/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/source/i18n/i18n.rc b/source/i18n/i18n.rc
new file mode 100644
index 0000000..1b624ad
--- /dev/null
+++ b/source/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/source/i18n/i18n.vcxproj b/source/i18n/i18n.vcxproj
new file mode 100644
index 0000000..66ebda0
--- /dev/null
+++ b/source/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/source/i18n/i18n.vcxproj.filters b/source/i18n/i18n.vcxproj.filters
new file mode 100644
index 0000000..d1ea38b
--- /dev/null
+++ b/source/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/source/i18n/indiancal.cpp b/source/i18n/indiancal.cpp
new file mode 100644
index 0000000..526cfc4
--- /dev/null
+++ b/source/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/source/i18n/indiancal.h b/source/i18n/indiancal.h
new file mode 100644
index 0000000..ff841fb
--- /dev/null
+++ b/source/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/source/i18n/inputext.cpp b/source/i18n/inputext.cpp
new file mode 100644
index 0000000..e5a8ee1
--- /dev/null
+++ b/source/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/source/i18n/inputext.h b/source/i18n/inputext.h
new file mode 100644
index 0000000..0c5973d
--- /dev/null
+++ b/source/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/source/i18n/islamcal.cpp b/source/i18n/islamcal.cpp
new file mode 100644
index 0000000..5867091
--- /dev/null
+++ b/source/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/source/i18n/islamcal.h b/source/i18n/islamcal.h
new file mode 100644
index 0000000..e3647bc
--- /dev/null
+++ b/source/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/source/i18n/japancal.cpp b/source/i18n/japancal.cpp
new file mode 100644
index 0000000..ad95b7c
--- /dev/null
+++ b/source/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/source/i18n/japancal.h b/source/i18n/japancal.h
new file mode 100644
index 0000000..4219d6a
--- /dev/null
+++ b/source/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/source/i18n/locdspnm.cpp b/source/i18n/locdspnm.cpp
new file mode 100644
index 0000000..83ce4ec
--- /dev/null
+++ b/source/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/source/i18n/measfmt.cpp b/source/i18n/measfmt.cpp
new file mode 100644
index 0000000..eaa37a2
--- /dev/null
+++ b/source/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/source/i18n/measure.cpp b/source/i18n/measure.cpp
new file mode 100644
index 0000000..7b91677
--- /dev/null
+++ b/source/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/source/i18n/msgfmt.cpp b/source/i18n/msgfmt.cpp
new file mode 100644
index 0000000..b529246
--- /dev/null
+++ b/source/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/source/i18n/msgfmt_impl.h b/source/i18n/msgfmt_impl.h
new file mode 100644
index 0000000..699dc37
--- /dev/null
+++ b/source/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/source/i18n/name2uni.cpp b/source/i18n/name2uni.cpp
new file mode 100644
index 0000000..4c2e9d2
--- /dev/null
+++ b/source/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/source/i18n/name2uni.h b/source/i18n/name2uni.h
new file mode 100644
index 0000000..1324ec3
--- /dev/null
+++ b/source/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/source/i18n/nfrlist.h b/source/i18n/nfrlist.h
new file mode 100644
index 0000000..a33731d
--- /dev/null
+++ b/source/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/source/i18n/nfrs.cpp b/source/i18n/nfrs.cpp
new file mode 100644
index 0000000..ef72ce3
--- /dev/null
+++ b/source/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/source/i18n/nfrs.h b/source/i18n/nfrs.h
new file mode 100644
index 0000000..93a29b0
--- /dev/null
+++ b/source/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/source/i18n/nfrule.cpp b/source/i18n/nfrule.cpp
new file mode 100644
index 0000000..d73a570
--- /dev/null
+++ b/source/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/source/i18n/nfrule.h b/source/i18n/nfrule.h
new file mode 100644
index 0000000..8422a20
--- /dev/null
+++ b/source/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/source/i18n/nfsubs.cpp b/source/i18n/nfsubs.cpp
new file mode 100644
index 0000000..4348f5d
--- /dev/null
+++ b/source/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/source/i18n/nfsubs.h b/source/i18n/nfsubs.h
new file mode 100644
index 0000000..644b4b2
--- /dev/null
+++ b/source/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/source/i18n/nortrans.cpp b/source/i18n/nortrans.cpp
new file mode 100644
index 0000000..329fb91
--- /dev/null
+++ b/source/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/source/i18n/nortrans.h b/source/i18n/nortrans.h
new file mode 100644
index 0000000..634f534
--- /dev/null
+++ b/source/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/source/i18n/nultrans.cpp b/source/i18n/nultrans.cpp
new file mode 100644
index 0000000..820c43d
--- /dev/null
+++ b/source/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/source/i18n/nultrans.h b/source/i18n/nultrans.h
new file mode 100644
index 0000000..699c323
--- /dev/null
+++ b/source/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/source/i18n/numfmt.cpp b/source/i18n/numfmt.cpp
new file mode 100644
index 0000000..dcd24a7
--- /dev/null
+++ b/source/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/source/i18n/numsys.cpp b/source/i18n/numsys.cpp
new file mode 100644
index 0000000..534ed15
--- /dev/null
+++ b/source/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/source/i18n/olsontz.cpp b/source/i18n/olsontz.cpp
new file mode 100644
index 0000000..b9b2e05
--- /dev/null
+++ b/source/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/source/i18n/olsontz.h b/source/i18n/olsontz.h
new file mode 100644
index 0000000..d997e26
--- /dev/null
+++ b/source/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/source/i18n/persncal.cpp b/source/i18n/persncal.cpp
new file mode 100644
index 0000000..5130341
--- /dev/null
+++ b/source/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/source/i18n/persncal.h b/source/i18n/persncal.h
new file mode 100644
index 0000000..b926da5
--- /dev/null
+++ b/source/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/source/i18n/plurfmt.cpp b/source/i18n/plurfmt.cpp
new file mode 100644
index 0000000..0464cf5
--- /dev/null
+++ b/source/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/source/i18n/plurrule.cpp b/source/i18n/plurrule.cpp
new file mode 100644
index 0000000..987bb24
--- /dev/null
+++ b/source/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/source/i18n/plurrule_impl.h b/source/i18n/plurrule_impl.h
new file mode 100644
index 0000000..82f79ca
--- /dev/null
+++ b/source/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/source/i18n/quant.cpp b/source/i18n/quant.cpp
new file mode 100644
index 0000000..3b48290
--- /dev/null
+++ b/source/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/source/i18n/quant.h b/source/i18n/quant.h
new file mode 100644
index 0000000..7938895
--- /dev/null
+++ b/source/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/source/i18n/rbnf.cpp b/source/i18n/rbnf.cpp
new file mode 100644
index 0000000..b8d392a
--- /dev/null
+++ b/source/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/source/i18n/rbt.cpp b/source/i18n/rbt.cpp
new file mode 100644
index 0000000..6041a92
--- /dev/null
+++ b/source/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/source/i18n/rbt.h b/source/i18n/rbt.h
new file mode 100644
index 0000000..d061de6
--- /dev/null
+++ b/source/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/source/i18n/rbt_data.cpp b/source/i18n/rbt_data.cpp
new file mode 100644
index 0000000..beef992
--- /dev/null
+++ b/source/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/source/i18n/rbt_data.h b/source/i18n/rbt_data.h
new file mode 100644
index 0000000..ce833dc
--- /dev/null
+++ b/source/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/source/i18n/rbt_pars.cpp b/source/i18n/rbt_pars.cpp
new file mode 100644
index 0000000..483c054
--- /dev/null
+++ b/source/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/source/i18n/rbt_pars.h b/source/i18n/rbt_pars.h
new file mode 100644
index 0000000..96bdac0
--- /dev/null
+++ b/source/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/source/i18n/rbt_rule.cpp b/source/i18n/rbt_rule.cpp
new file mode 100644
index 0000000..69a2202
--- /dev/null
+++ b/source/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/source/i18n/rbt_rule.h b/source/i18n/rbt_rule.h
new file mode 100644
index 0000000..0816956
--- /dev/null
+++ b/source/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/source/i18n/rbt_set.cpp b/source/i18n/rbt_set.cpp
new file mode 100644
index 0000000..1553c4f
--- /dev/null
+++ b/source/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/source/i18n/rbt_set.h b/source/i18n/rbt_set.h
new file mode 100644
index 0000000..f92e130
--- /dev/null
+++ b/source/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/source/i18n/rbtz.cpp b/source/i18n/rbtz.cpp
new file mode 100644
index 0000000..961c8fb
--- /dev/null
+++ b/source/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/source/i18n/regexcmp.cpp b/source/i18n/regexcmp.cpp
new file mode 100644
index 0000000..bef729a
--- /dev/null
+++ b/source/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/source/i18n/regexcmp.h b/source/i18n/regexcmp.h
new file mode 100644
index 0000000..032fdb7
--- /dev/null
+++ b/source/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/source/i18n/regexcst.h b/source/i18n/regexcst.h
new file mode 100644
index 0000000..ab43137
--- /dev/null
+++ b/source/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/source/i18n/regexcst.pl b/source/i18n/regexcst.pl
new file mode 100755
index 0000000..f1dc06a
--- /dev/null
+++ b/source/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/source/i18n/regexcst.txt b/source/i18n/regexcst.txt
new file mode 100644
index 0000000..77ebd96
--- /dev/null
+++ b/source/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/source/i18n/regeximp.h b/source/i18n/regeximp.h
new file mode 100644
index 0000000..3ee9102
--- /dev/null
+++ b/source/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/source/i18n/regexst.cpp b/source/i18n/regexst.cpp
new file mode 100644
index 0000000..b8ad297
--- /dev/null
+++ b/source/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/source/i18n/regexst.h b/source/i18n/regexst.h
new file mode 100644
index 0000000..07034d4
--- /dev/null
+++ b/source/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/source/i18n/regextxt.cpp b/source/i18n/regextxt.cpp
new file mode 100644
index 0000000..6960dac
--- /dev/null
+++ b/source/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/source/i18n/regextxt.h b/source/i18n/regextxt.h
new file mode 100644
index 0000000..5b59838
--- /dev/null
+++ b/source/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/source/i18n/reldtfmt.cpp b/source/i18n/reldtfmt.cpp
new file mode 100644
index 0000000..c135c1d
--- /dev/null
+++ b/source/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/source/i18n/reldtfmt.h b/source/i18n/reldtfmt.h
new file mode 100644
index 0000000..692f9a9
--- /dev/null
+++ b/source/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/source/i18n/rematch.cpp b/source/i18n/rematch.cpp
new file mode 100644
index 0000000..dda8a1e
--- /dev/null
+++ b/source/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/source/i18n/remtrans.cpp b/source/i18n/remtrans.cpp
new file mode 100644
index 0000000..c21c79b
--- /dev/null
+++ b/source/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/source/i18n/remtrans.h b/source/i18n/remtrans.h
new file mode 100644
index 0000000..25a5609
--- /dev/null
+++ b/source/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/source/i18n/repattrn.cpp b/source/i18n/repattrn.cpp
new file mode 100644
index 0000000..4369eb8
--- /dev/null
+++ b/source/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/source/i18n/search.cpp b/source/i18n/search.cpp
new file mode 100644
index 0000000..5d2aa13
--- /dev/null
+++ b/source/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/source/i18n/selfmt.cpp b/source/i18n/selfmt.cpp
new file mode 100755
index 0000000..090b643
--- /dev/null
+++ b/source/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/source/i18n/selfmtimpl.h b/source/i18n/selfmtimpl.h
new file mode 100755
index 0000000..208a659
--- /dev/null
+++ b/source/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/source/i18n/simpletz.cpp b/source/i18n/simpletz.cpp
new file mode 100644
index 0000000..fb960bb
--- /dev/null
+++ b/source/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/source/i18n/smpdtfmt.cpp b/source/i18n/smpdtfmt.cpp
new file mode 100644
index 0000000..86e98cb
--- /dev/null
+++ b/source/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/source/i18n/sortkey.cpp b/source/i18n/sortkey.cpp
new file mode 100644
index 0000000..ceca9d1
--- /dev/null
+++ b/source/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/source/i18n/strmatch.cpp b/source/i18n/strmatch.cpp
new file mode 100644
index 0000000..8286c7e
--- /dev/null
+++ b/source/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/source/i18n/strmatch.h b/source/i18n/strmatch.h
new file mode 100644
index 0000000..90cba0c
--- /dev/null
+++ b/source/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/source/i18n/strrepl.cpp b/source/i18n/strrepl.cpp
new file mode 100644
index 0000000..4ae12b0
--- /dev/null
+++ b/source/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/source/i18n/strrepl.h b/source/i18n/strrepl.h
new file mode 100644
index 0000000..67a93e9
--- /dev/null
+++ b/source/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/source/i18n/stsearch.cpp b/source/i18n/stsearch.cpp
new file mode 100644
index 0000000..447f95f
--- /dev/null
+++ b/source/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/source/i18n/taiwncal.cpp b/source/i18n/taiwncal.cpp
new file mode 100644
index 0000000..4a89525
--- /dev/null
+++ b/source/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/source/i18n/taiwncal.h b/source/i18n/taiwncal.h
new file mode 100644
index 0000000..fe6f89b
--- /dev/null
+++ b/source/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/source/i18n/tblcoll.cpp b/source/i18n/tblcoll.cpp
new file mode 100644
index 0000000..15f5c49
--- /dev/null
+++ b/source/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/source/i18n/timezone.cpp b/source/i18n/timezone.cpp
new file mode 100644
index 0000000..777bee7
--- /dev/null
+++ b/source/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/source/i18n/titletrn.cpp b/source/i18n/titletrn.cpp
new file mode 100644
index 0000000..76c17d1
--- /dev/null
+++ b/source/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/source/i18n/titletrn.h b/source/i18n/titletrn.h
new file mode 100644
index 0000000..a093152
--- /dev/null
+++ b/source/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/source/i18n/tmunit.cpp b/source/i18n/tmunit.cpp
new file mode 100644
index 0000000..fb31e25
--- /dev/null
+++ b/source/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/source/i18n/tmutamt.cpp b/source/i18n/tmutamt.cpp
new file mode 100644
index 0000000..382c7ff
--- /dev/null
+++ b/source/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/source/i18n/tmutfmt.cpp b/source/i18n/tmutfmt.cpp
new file mode 100644
index 0000000..f8ad9a3
--- /dev/null
+++ b/source/i18n/tmutfmt.cpp
@@ -0,0 +1,878 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2008-2011, Google, International Business Machines Corporation
+ * and  others. All Rights Reserved.                                           
+ *******************************************************************************
+ */
+
+#include <typeinfo>  // for 'typeid' to work
+
+#include "unicode/tmutfmt.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "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;
+    }
+    if ( U_FAILURE(status) ) {
+        delete hTable; 
+        return NULL;
+    }
+    hTable->setValueComparator(tmutfmtHashTableValueComparator);
+    return hTable;
+}
+
+
+const char*
+TimeUnitFormat::getTimeUnitName(TimeUnit::UTimeUnitFields unitField, 
+                                UErrorCode& status) {
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+    switch (unitField) {
+      case TimeUnit::UTIMEUNIT_YEAR:
+        return gTimeUnitYear;
+      case TimeUnit::UTIMEUNIT_MONTH:
+        return gTimeUnitMonth;
+      case TimeUnit::UTIMEUNIT_DAY:
+        return gTimeUnitDay;
+      case TimeUnit::UTIMEUNIT_WEEK:
+        return gTimeUnitWeek;
+      case TimeUnit::UTIMEUNIT_HOUR:
+        return gTimeUnitHour;
+      case TimeUnit::UTIMEUNIT_MINUTE:
+        return gTimeUnitMinute;
+      case TimeUnit::UTIMEUNIT_SECOND:
+        return gTimeUnitSecond;
+      default:
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+}
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/i18n/tolowtrn.cpp b/source/i18n/tolowtrn.cpp
new file mode 100644
index 0000000..c93f4d0
--- /dev/null
+++ b/source/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/source/i18n/tolowtrn.h b/source/i18n/tolowtrn.h
new file mode 100644
index 0000000..564b215
--- /dev/null
+++ b/source/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/source/i18n/toupptrn.cpp b/source/i18n/toupptrn.cpp
new file mode 100644
index 0000000..4b7c7d0
--- /dev/null
+++ b/source/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/source/i18n/toupptrn.h b/source/i18n/toupptrn.h
new file mode 100644
index 0000000..77799ac
--- /dev/null
+++ b/source/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/source/i18n/translit.cpp b/source/i18n/translit.cpp
new file mode 100644
index 0000000..8436479
--- /dev/null
+++ b/source/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/source/i18n/transreg.cpp b/source/i18n/transreg.cpp
new file mode 100644
index 0000000..8e1d4f4
--- /dev/null
+++ b/source/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/source/i18n/transreg.h b/source/i18n/transreg.h
new file mode 100644
index 0000000..483e74f
--- /dev/null
+++ b/source/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/source/i18n/tridpars.cpp b/source/i18n/tridpars.cpp
new file mode 100644
index 0000000..cf9fd3f
--- /dev/null
+++ b/source/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/source/i18n/tridpars.h b/source/i18n/tridpars.h
new file mode 100644
index 0000000..1f2268f
--- /dev/null
+++ b/source/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/source/i18n/tzrule.cpp b/source/i18n/tzrule.cpp
new file mode 100644
index 0000000..e54b9b8
--- /dev/null
+++ b/source/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/source/i18n/tztrans.cpp b/source/i18n/tztrans.cpp
new file mode 100644
index 0000000..f795e40
--- /dev/null
+++ b/source/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/source/i18n/ucal.cpp b/source/i18n/ucal.cpp
new file mode 100644
index 0000000..5a659e5
--- /dev/null
+++ b/source/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/source/i18n/ucln_in.c b/source/i18n/ucln_in.c
new file mode 100644
index 0000000..cce5890
--- /dev/null
+++ b/source/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/source/i18n/ucln_in.h b/source/i18n/ucln_in.h
new file mode 100644
index 0000000..82de838
--- /dev/null
+++ b/source/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/source/i18n/ucol.cpp b/source/i18n/ucol.cpp
new file mode 100644
index 0000000..65b157c
--- /dev/null
+++ b/source/i18n/ucol.cpp
@@ -0,0 +1,8612 @@
+/*
+*******************************************************************************
+*   Copyright (C) 1996-2011, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*******************************************************************************
+*   file name:  ucol.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+* Modification history
+* Date        Name      Comments
+* 1996-1999   various members of ICU team maintained C API for collation framework
+* 02/16/2001  synwee    Added internal method getPrevSpecialCE
+* 03/01/2001  synwee    Added maxexpansion functionality.
+* 03/16/2001  weiv      Collation framework is rewritten in C and made UCA compliant
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/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;
+
+    do {
+        for (;;)                           /* Loop handles case when incremental normalize switches   */
+        {                                  /*   to or from the side buffer / original string, and we  */
+            /*   need to start again to get the next character.        */
+
+            if ((collationSource->flags & (UCOL_ITER_HASLEN | UCOL_ITER_INNORMBUF | UCOL_ITER_NORM | UCOL_HIRAGANA_Q | UCOL_USE_ITERATOR)) == 0)
+            {
+                // The source string is null terminated and we're not working from the side buffer,
+                //   and we're not normalizing.  This is the fast path.
+                //   (We can be in the side buffer for Thai pre-vowel reordering even when not normalizing.)
+                ch = *collationSource->pos++;
+                if (ch != 0) {
+                    break;
+                }
+                else {
+                    return UCOL_NO_MORE_CES;
+                }
+            }
+
+            if (collationSource->flags & UCOL_ITER_HASLEN) {
+                // Normal path for strings when length is specified.
+                //   (We can't be in side buffer because it is always null terminated.)
+                if (collationSource->pos >= collationSource->endp) {
+                    // Ran off of the end of the main source string.  We're done.
+                    return UCOL_NO_MORE_CES;
+                }
+                ch = *collationSource->pos++;
+            }
+            else if(collationSource->flags & UCOL_USE_ITERATOR) {
+                UChar32 iterCh = collationSource->iterator->next(collationSource->iterator);
+                if(iterCh == U_SENTINEL) {
+                    return UCOL_NO_MORE_CES;
+                }
+                ch = (UChar)iterCh;
+            }
+            else
+            {
+                // Null terminated string.
+                ch = *collationSource->pos++;
+                if (ch == 0) {
+                    // Ran off end of buffer.
+                    if ((collationSource->flags & UCOL_ITER_INNORMBUF) == 0) {
+                        // Ran off end of main string. backing up one character.
+                        collationSource->pos--;
+                        return UCOL_NO_MORE_CES;
+                    }
+                    else
+                    {
+                        // Hit null in the normalize side buffer.
+                        // Usually this means the end of the normalized data,
+                        // except for one odd case: a null followed by combining chars,
+                        //   which is the case if we are at the start of the buffer.
+                        if (collationSource->pos == collationSource->writableBuffer.getBuffer()+1) {
+                            break;
+                        }
+
+                        //  Null marked end of side buffer.
+                        //   Revert to the main string and
+                        //   loop back to top to try again to get a character.
+                        collationSource->pos   = collationSource->fcdPosition;
+                        collationSource->flags = collationSource->origFlags;
+                        continue;
+                    }
+                }
+            }
+
+            if(collationSource->flags&UCOL_HIRAGANA_Q) {
+                /* Codepoints \u3099-\u309C are both Hiragana and Katakana. Set the flag
+                 * based on whether the previous codepoint was Hiragana or Katakana.
+                 */
+                if(((ch>=0x3040 && ch<=0x3096) || (ch >= 0x309d && ch <= 0x309f)) ||
+                        ((collationSource->flags & UCOL_WAS_HIRAGANA) && (ch >= 0x3099 && ch <= 0x309C))) {
+                    collationSource->flags |= UCOL_WAS_HIRAGANA;
+                } else {
+                    collationSource->flags &= ~UCOL_WAS_HIRAGANA;
+                }
+            }
+
+            // We've got a character.  See if there's any fcd and/or normalization stuff to do.
+            //    Note that UCOL_ITER_NORM flag is always zero when we are in the side buffer.
+            if ((collationSource->flags & UCOL_ITER_NORM) == 0) {
+                break;
+            }
+
+            if (collationSource->fcdPosition >= collationSource->pos) {
+                // An earlier FCD check has already covered the current character.
+                // We can go ahead and process this char.
+                break;
+            }
+
+            if (ch < ZERO_CC_LIMIT_ ) {
+                // Fast fcd safe path.  Trailing combining class == 0.  This char is OK.
+                break;
+            }
+
+            if (ch < NFC_ZERO_CC_BLOCK_LIMIT_) {
+                // We need to peek at the next character in order to tell if we are FCD
+                if ((collationSource->flags & UCOL_ITER_HASLEN) && collationSource->pos >= collationSource->endp) {
+                    // We are at the last char of source string.
+                    //  It is always OK for FCD check.
+                    break;
+                }
+
+                // Not at last char of source string (or we'll check against terminating null).  Do the FCD fast test
+                if (*collationSource->pos < NFC_ZERO_CC_BLOCK_LIMIT_) {
+                    break;
+                }
+            }
+
+
+            // Need a more complete FCD check and possible normalization.
+            if (collIterFCD(collationSource)) {
+                collIterNormalize(collationSource);
+            }
+            if ((collationSource->flags & UCOL_ITER_INNORMBUF) == 0) {
+                //  No normalization was needed.  Go ahead and process the char we already had.
+                break;
+            }
+
+            // Some normalization happened.  Next loop iteration will pick up a char
+            //   from the normalization buffer.
+
+        }   // end for (;;)
+
+
+        if (ch <= 0xFF) {
+            /*  For latin-1 characters we never need to fall back to the UCA table        */
+            /*    because all of the UCA data is replicated in the latinOneMapping array  */
+            order = coll->latinOneMapping[ch];
+            if (order > UCOL_NOT_FOUND) {
+                order = ucol_prv_getSpecialCE(coll, ch, order, collationSource, status);
+            }
+        }
+        else
+        {
+            // Always use UCA for Han, Hangul
+            // (Han extension A is before main Han block)
+            // **** Han compatibility chars ?? ****
+            if ((collationSource->flags & UCOL_FORCE_HAN_IMPLICIT) != 0 &&
+                (ch >= UCOL_FIRST_HAN_A && ch <= UCOL_LAST_HANGUL)) {
+                if (ch > UCOL_LAST_HAN && ch < UCOL_FIRST_HANGUL) {
+                    // between the two target ranges; do normal lookup
+                    // **** this range is YI, Modifier tone letters, ****
+                    // **** Latin-D, Syloti Nagari, Phagas-pa.       ****
+                    // **** Latin-D might be tailored, so we need to ****
+                    // **** do the normal lookup for these guys.     ****
+                    order = UTRIE_GET32_FROM_LEAD(&coll->mapping, ch);
+                } else {
+                    // in one of the target ranges; use UCA
+                    order = UCOL_NOT_FOUND;
+                }
+            } else {
+                order = UTRIE_GET32_FROM_LEAD(&coll->mapping, ch);
+            }
+
+            if(order > UCOL_NOT_FOUND) {                                       /* if a CE is special                */
+                order = ucol_prv_getSpecialCE(coll, ch, order, collationSource, status);    /* and try to get the special CE     */
+            }
+
+            if(order == UCOL_NOT_FOUND && coll->UCA) {   /* We couldn't find a good CE in the tailoring */
+                /* if we got here, the codepoint MUST be over 0xFF - so we look directly in the trie */
+                order = UTRIE_GET32_FROM_LEAD(&coll->UCA->mapping, ch);
+
+                if(order > UCOL_NOT_FOUND) { /* UCA also gives us a special CE */
+                    order = ucol_prv_getSpecialCE(coll->UCA, ch, order, collationSource, status);
+                }
+            }
+        }
+    } while ( order == UCOL_IGNORABLE && ch >= UCOL_FIRST_HANGUL && ch <= UCOL_LAST_HANGUL );
+
+    if(order == UCOL_NOT_FOUND) {
+        order = getImplicit(ch, collationSource);
+    }
+    return order; /* return the CE */
+}
+
+/* ucol_getNextCE, out-of-line version for use from other files.   */
+U_CAPI uint32_t  U_EXPORT2
+ucol_getNextCE(const UCollator *coll, collIterate *collationSource, UErrorCode *status) {
+    return ucol_IGetNextCE(coll, collationSource, status);
+}
+
+
+/**
+* Incremental previous normalization happens here. Pick up the range of chars
+* identifed by FCD, normalize it into the collIterate's writable buffer,
+* switch the collIterate's state to use the writable buffer.
+* @param data collation iterator data
+*/
+static
+void collPrevIterNormalize(collIterate *data)
+{
+    UErrorCode status  = U_ZERO_ERROR;
+    const UChar *pEnd   = data->pos;  /* End normalize + 1 */
+    const UChar *pStart;
+
+    /* Start normalize */
+    if (data->fcdPosition == NULL) {
+        pStart = data->string;
+    }
+    else {
+        pStart = data->fcdPosition + 1;
+    }
+
+    int32_t normLen =
+        data->nfd->normalize(UnicodeString(FALSE, pStart, (int32_t)((pEnd - pStart) + 1)),
+                             data->writableBuffer,
+                             status).
+        length();
+    if(U_FAILURE(status)) {
+        return;
+    }
+    /*
+    this puts the null termination infront of the normalized string instead
+    of the end
+    */
+    data->writableBuffer.insert(0, (UChar)0);
+
+    /*
+     * The usual case at this point is that we've got a base
+     * character followed by marks that were normalized. If
+     * fcdPosition is NULL, that means that we backed up to
+     * the beginning of the string and there's no base character.
+     *
+     * Forward processing will usually normalize when it sees
+     * the first mark, so that mark will get it's natural offset
+     * and the rest will get the offset of the character following
+     * the marks. The base character will also get its natural offset.
+     *
+     * We write the offset of the base character, if there is one,
+     * followed by the offset of the first mark and then the offsets
+     * of the rest of the marks.
+     */
+    int32_t firstMarkOffset = 0;
+    int32_t trailOffset     = (int32_t)(data->pos - data->string + 1);
+    int32_t trailCount      = normLen - 1;
+
+    if (data->fcdPosition != NULL) {
+        int32_t baseOffset = (int32_t)(data->fcdPosition - data->string);
+        UChar   baseChar   = *data->fcdPosition;
+
+        firstMarkOffset = baseOffset + 1;
+
+        /*
+         * If the base character is the start of a contraction, forward processing
+         * will normalize the marks while checking for the contraction, which means
+         * that the offset of the first mark will the same as the other marks.
+         *
+         * **** THIS IS PROBABLY NOT A COMPLETE TEST ****
+         */
+        if (baseChar >= 0x100) {
+            uint32_t baseOrder = UTRIE_GET32_FROM_LEAD(&data->coll->mapping, baseChar);
+
+            if (baseOrder == UCOL_NOT_FOUND && data->coll->UCA) {
+                baseOrder = UTRIE_GET32_FROM_LEAD(&data->coll->UCA->mapping, baseChar);
+            }
+
+            if (baseOrder > UCOL_NOT_FOUND && getCETag(baseOrder) == CONTRACTION_TAG) {
+                firstMarkOffset = trailOffset;
+            }
+        }
+
+        data->appendOffset(baseOffset, status);
+    }
+
+    data->appendOffset(firstMarkOffset, status);
+
+    for (int32_t i = 0; i < trailCount; i += 1) {
+        data->appendOffset(trailOffset, status);
+    }
+
+    data->offsetRepeatValue = trailOffset;
+
+    data->offsetReturn = data->offsetStore - 1;
+    if (data->offsetReturn == data->offsetBuffer) {
+        data->offsetStore = data->offsetBuffer;
+    }
+
+    data->pos        = data->writableBuffer.getTerminatedBuffer() + 1 + normLen;
+    data->origFlags  = data->flags;
+    data->flags     |= UCOL_ITER_INNORMBUF;
+    data->flags     &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN);
+}
+
+
+/**
+* Incremental FCD check for previous iteration and normalize. Called from
+* getPrevCE when normalization state is suspect.
+* When entering, the state is known to be this:
+* o  We are working in the main buffer of the collIterate, not the side
+*    writable buffer. When in the side buffer, normalization mode is always
+*    off, so we won't get here.
+* o  The leading combining class from the current character is 0 or the
+*    trailing combining class of the previous char was zero.
+*    True because the previous call to this function will have always exited
+*    that way, and we get called for every char where cc might be non-zero.
+* @param data collation iterate struct
+* @return normalization status, TRUE for normalization to be done, FALSE
+*         otherwise
+*/
+static
+inline UBool collPrevIterFCD(collIterate *data)
+{
+    const UChar *src, *start;
+    uint8_t     leadingCC;
+    uint8_t     trailingCC = 0;
+    uint16_t    fcd;
+    UBool       result = FALSE;
+
+    start = data->string;
+    src = data->pos + 1;
+
+    /* Get the trailing combining class of the current character. */
+    fcd = unorm_prevFCD16(fcdTrieIndex, fcdHighStart, start, src);
+
+    leadingCC = (uint8_t)(fcd >> SECOND_LAST_BYTE_SHIFT_);
+
+    if (leadingCC != 0) {
+        /*
+        The current char has a non-zero leading combining class.
+        Scan backward until we find a char with a trailing cc of zero.
+        */
+        for (;;)
+        {
+            if (start == src) {
+                data->fcdPosition = NULL;
+                return result;
+            }
+
+            fcd = unorm_prevFCD16(fcdTrieIndex, fcdHighStart, start, src);
+
+            trailingCC = (uint8_t)(fcd & LAST_BYTE_MASK_);
+
+            if (trailingCC == 0) {
+                break;
+            }
+
+            if (leadingCC < trailingCC) {
+                result = TRUE;
+            }
+
+            leadingCC = (uint8_t)(fcd >> SECOND_LAST_BYTE_SHIFT_);
+        }
+    }
+
+    data->fcdPosition = (UChar *)src;
+
+    return result;
+}
+
+/** gets a code unit from the string at a given offset
+ *  Handles both normal and iterative cases.
+ *  No error checking - caller beware!
+ */
+static inline
+UChar peekCodeUnit(collIterate *source, int32_t offset) {
+    if(source->pos != NULL) {
+        return *(source->pos + offset);
+    } else if(source->iterator != NULL) {
+        UChar32 c;
+        if(offset != 0) {
+            source->iterator->move(source->iterator, offset, UITER_CURRENT);
+            c = source->iterator->next(source->iterator);
+            source->iterator->move(source->iterator, -offset-1, UITER_CURRENT);
+        } else {
+            c = source->iterator->current(source->iterator);
+        }
+        return c >= 0 ? (UChar)c : 0xfffd;  // If the caller works properly, we should never see c<0.
+    } else {
+        return 0xfffd;
+    }
+}
+
+// Code point version. Treats the offset as a _code point_ delta.
+// We cannot use U16_FWD_1_UNSAFE and similar because we might not have well-formed UTF-16.
+// We cannot use U16_FWD_1 and similar because we do not know the start and limit of the buffer.
+static inline
+UChar32 peekCodePoint(collIterate *source, int32_t offset) {
+    UChar32 c;
+    if(source->pos != NULL) {
+        const UChar *p = source->pos;
+        if(offset >= 0) {
+            // Skip forward over (offset-1) code points.
+            while(--offset >= 0) {
+                if(U16_IS_LEAD(*p++) && U16_IS_TRAIL(*p)) {
+                    ++p;
+                }
+            }
+            // Read the code point there.
+            c = *p++;
+            UChar trail;
+            if(U16_IS_LEAD(c) && U16_IS_TRAIL(trail = *p)) {
+                c = U16_GET_SUPPLEMENTARY(c, trail);
+            }
+        } else /* offset<0 */ {
+            // Skip backward over (offset-1) code points.
+            while(++offset < 0) {
+                if(U16_IS_TRAIL(*--p) && U16_IS_LEAD(*(p - 1))) {
+                    --p;
+                }
+            }
+            // Read the code point before that.
+            c = *--p;
+            UChar lead;
+            if(U16_IS_TRAIL(c) && U16_IS_LEAD(lead = *(p - 1))) {
+                c = U16_GET_SUPPLEMENTARY(lead, c);
+            }
+        }
+    } else if(source->iterator != NULL) {
+        if(offset >= 0) {
+            // Skip forward over (offset-1) code points.
+            int32_t fwd = offset;
+            while(fwd-- > 0) {
+                uiter_next32(source->iterator);
+            }
+            // Read the code point there.
+            c = uiter_current32(source->iterator);
+            // Return to the starting point, skipping backward over (offset-1) code points.
+            while(offset-- > 0) {
+                uiter_previous32(source->iterator);
+            }
+        } else /* offset<0 */ {
+            // Read backward, reading offset code points, remember only the last-read one.
+            int32_t back = offset;
+            do {
+                c = uiter_previous32(source->iterator);
+            } while(++back < 0);
+            // Return to the starting position, skipping forward over offset code points.
+            do {
+                uiter_next32(source->iterator);
+            } while(++offset < 0);
+        }
+    } else {
+        c = U_SENTINEL;
+    }
+    return c;
+}
+
+/**
+* Determines if we are at the start of the data string in the backwards
+* collation iterator
+* @param data collation iterator
+* @return TRUE if we are at the start
+*/
+static
+inline UBool isAtStartPrevIterate(collIterate *data) {
+    if(data->pos == NULL && data->iterator != NULL) {
+        return !data->iterator->hasPrevious(data->iterator);
+    }
+    //return (collIter_bos(data)) ||
+    return (data->pos == data->string) ||
+              ((data->flags & UCOL_ITER_INNORMBUF) &&
+              *(data->pos - 1) == 0 && data->fcdPosition == NULL);
+}
+
+static
+inline void goBackOne(collIterate *data) {
+# if 0
+    // somehow, it looks like we need to keep iterator synced up
+    // at all times, as above.
+    if(data->pos) {
+        data->pos--;
+    }
+    if(data->iterator) {
+        data->iterator->previous(data->iterator);
+    }
+#endif
+    if(data->iterator && (data->flags & UCOL_USE_ITERATOR)) {
+        data->iterator->previous(data->iterator);
+    }
+    if(data->pos) {
+        data->pos --;
+    }
+}
+
+/**
+* Inline function that gets a simple CE.
+* So what it does is that it will first check the expansion buffer. If the
+* expansion buffer is not empty, ie the end pointer to the expansion buffer
+* is different from the string pointer, we return the collation element at the
+* return pointer and decrement it.
+* For more complicated CEs it resorts to getComplicatedCE.
+* @param coll collator data
+* @param data collation iterator struct
+* @param status error status
+*/
+static
+inline uint32_t ucol_IGetPrevCE(const UCollator *coll, collIterate *data,
+                               UErrorCode *status)
+{
+    uint32_t result = (uint32_t)UCOL_NULLORDER;
+
+    if (data->offsetReturn != NULL) {
+        if (data->offsetRepeatCount > 0) {
+                data->offsetRepeatCount -= 1;
+        } else {
+            if (data->offsetReturn == data->offsetBuffer) {
+                data->offsetReturn = NULL;
+                data->offsetStore  = data->offsetBuffer;
+            } else {
+                data->offsetReturn -= 1;
+            }
+        }
+    }
+
+    if ((data->extendCEs && data->toReturn > data->extendCEs) ||
+            (!data->extendCEs && data->toReturn > data->CEs))
+    {
+        data->toReturn -= 1;
+        result = *(data->toReturn);
+        if (data->CEs == data->toReturn || data->extendCEs == data->toReturn) {
+            data->CEpos = data->toReturn;
+        }
+    }
+    else {
+        UChar ch = 0;
+
+        do {
+            /*
+            Loop handles case when incremental normalize switches to or from the
+            side buffer / original string, and we need to start again to get the
+            next character.
+            */
+            for (;;) {
+                if (data->flags & UCOL_ITER_HASLEN) {
+                    /*
+                    Normal path for strings when length is specified.
+                    Not in side buffer because it is always null terminated.
+                    */
+                    if (data->pos <= data->string) {
+                        /* End of the main source string */
+                        return UCOL_NO_MORE_CES;
+                    }
+                    data->pos --;
+                    ch = *data->pos;
+                }
+                // we are using an iterator to go back. Pray for us!
+                else if (data->flags & UCOL_USE_ITERATOR) {
+                  UChar32 iterCh = data->iterator->previous(data->iterator);
+                  if(iterCh == U_SENTINEL) {
+                    return UCOL_NO_MORE_CES;
+                  } else {
+                    ch = (UChar)iterCh;
+                  }
+                }
+                else {
+                    data->pos --;
+                    ch = *data->pos;
+                    /* we are in the side buffer. */
+                    if (ch == 0) {
+                        /*
+                        At the start of the normalize side buffer.
+                        Go back to string.
+                        Because pointer points to the last accessed character,
+                        hence we have to increment it by one here.
+                        */
+                        data->flags = data->origFlags;
+                        data->offsetRepeatValue = 0;
+
+                         if (data->fcdPosition == NULL) {
+                            data->pos = data->string;
+                            return UCOL_NO_MORE_CES;
+                        }
+                        else {
+                            data->pos   = data->fcdPosition + 1;
+                        }
+
+                       continue;
+                    }
+                }
+
+                if(data->flags&UCOL_HIRAGANA_Q) {
+                  if(ch>=0x3040 && ch<=0x309f) {
+                    data->flags |= UCOL_WAS_HIRAGANA;
+                  } else {
+                    data->flags &= ~UCOL_WAS_HIRAGANA;
+                  }
+                }
+
+                /*
+                * got a character to determine if there's fcd and/or normalization
+                * stuff to do.
+                * if the current character is not fcd.
+                * if current character is at the start of the string
+                * Trailing combining class == 0.
+                * Note if pos is in the writablebuffer, norm is always 0
+                */
+                if (ch < ZERO_CC_LIMIT_ ||
+                  // this should propel us out of the loop in the iterator case
+                    (data->flags & UCOL_ITER_NORM) == 0 ||
+                    (data->fcdPosition != NULL && data->fcdPosition <= data->pos)
+                    || data->string == data->pos) {
+                    break;
+                }
+
+                if (ch < NFC_ZERO_CC_BLOCK_LIMIT_) {
+                    /* if next character is FCD */
+                    if (data->pos == data->string) {
+                        /* First char of string is always OK for FCD check */
+                        break;
+                    }
+
+                    /* Not first char of string, do the FCD fast test */
+                    if (*(data->pos - 1) < NFC_ZERO_CC_BLOCK_LIMIT_) {
+                        break;
+                    }
+                }
+
+                /* Need a more complete FCD check and possible normalization. */
+                if (collPrevIterFCD(data)) {
+                    collPrevIterNormalize(data);
+                }
+
+                if ((data->flags & UCOL_ITER_INNORMBUF) == 0) {
+                    /*  No normalization. Go ahead and process the char. */
+                    break;
+                }
+
+                /*
+                Some normalization happened.
+                Next loop picks up a char from the normalization buffer.
+                */
+            }
+
+            /* attempt to handle contractions, after removal of the backwards
+            contraction
+            */
+            if (ucol_contractionEndCP(ch, coll) && !isAtStartPrevIterate(data)) {
+                result = ucol_prv_getSpecialPrevCE(coll, ch, UCOL_CONTRACTION, data, status);
+            } else {
+                if (ch <= 0xFF) {
+                    result = coll->latinOneMapping[ch];
+                }
+                else {
+                    // Always use UCA for [3400..9FFF], [AC00..D7AF]
+                    // **** [FA0E..FA2F] ?? ****
+                    if ((data->flags & UCOL_FORCE_HAN_IMPLICIT) != 0 &&
+                        (ch >= 0x3400 && ch <= 0xD7AF)) {
+                        if (ch > 0x9FFF && ch < 0xAC00) {
+                            // between the two target ranges; do normal lookup
+                            // **** this range is YI, Modifier tone letters, ****
+                            // **** Latin-D, Syloti Nagari, Phagas-pa.       ****
+                            // **** Latin-D might be tailored, so we need to ****
+                            // **** do the normal lookup for these guys.     ****
+                             result = UTRIE_GET32_FROM_LEAD(&coll->mapping, ch);
+                        } else {
+                            result = UCOL_NOT_FOUND;
+                        }
+                    } else {
+                        result = UTRIE_GET32_FROM_LEAD(&coll->mapping, ch);
+                    }
+                }
+                if (result > UCOL_NOT_FOUND) {
+                    result = ucol_prv_getSpecialPrevCE(coll, ch, result, data, status);
+                }
+                if (result == UCOL_NOT_FOUND) { // Not found in master list
+                    if (!isAtStartPrevIterate(data) &&
+                        ucol_contractionEndCP(ch, data->coll))
+                    {
+                        result = UCOL_CONTRACTION;
+                    } else {
+                        if(coll->UCA) {
+                            result = UTRIE_GET32_FROM_LEAD(&coll->UCA->mapping, ch);
+                        }
+                    }
+
+                    if (result > UCOL_NOT_FOUND) {
+                        if(coll->UCA) {
+                            result = ucol_prv_getSpecialPrevCE(coll->UCA, ch, result, data, status);
+                        }
+                    }
+                }
+            }
+        } while ( result == UCOL_IGNORABLE && ch >= UCOL_FIRST_HANGUL && ch <= UCOL_LAST_HANGUL );
+
+        if(result == UCOL_NOT_FOUND) {
+            result = getPrevImplicit(ch, data);
+        }
+    }
+
+    return result;
+}
+
+
+/*   ucol_getPrevCE, out-of-line version for use from other files.  */
+U_CFUNC uint32_t  U_EXPORT2
+ucol_getPrevCE(const UCollator *coll, collIterate *data,
+                        UErrorCode *status) {
+    return ucol_IGetPrevCE(coll, data, status);
+}
+
+
+/* this should be connected to special Jamo handling */
+U_CFUNC uint32_t  U_EXPORT2
+ucol_getFirstCE(const UCollator *coll, UChar u, UErrorCode *status) {
+    collIterate colIt;
+    IInit_collIterate(coll, &u, 1, &colIt, status);
+    if(U_FAILURE(*status)) {
+        return 0;
+    }
+    return ucol_IGetNextCE(coll, &colIt, status);
+}
+
+/**
+* Inserts the argument character into the end of the buffer pushing back the
+* null terminator.
+* @param data collIterate struct data
+* @param ch character to be appended
+* @return the position of the new addition
+*/
+static
+inline const UChar * insertBufferEnd(collIterate *data, UChar ch)
+{
+    int32_t oldLength = data->writableBuffer.length();
+    return data->writableBuffer.append(ch).getTerminatedBuffer() + oldLength;
+}
+
+/**
+* Inserts the argument string into the end of the buffer pushing back the
+* null terminator.
+* @param data collIterate struct data
+* @param string to be appended
+* @param length of the string to be appended
+* @return the position of the new addition
+*/
+static
+inline const UChar * insertBufferEnd(collIterate *data, const UChar *str, int32_t length)
+{
+    int32_t oldLength = data->writableBuffer.length();
+    return data->writableBuffer.append(str, length).getTerminatedBuffer() + oldLength;
+}
+
+/**
+* Special normalization function for contraction in the forwards iterator.
+* This normalization sequence will place the current character at source->pos
+* and its following normalized sequence into the buffer.
+* The fcd position, pos will be changed.
+* pos will now point to positions in the buffer.
+* Flags will be changed accordingly.
+* @param data collation iterator data
+*/
+static
+inline void normalizeNextContraction(collIterate *data)
+{
+    int32_t     strsize;
+    UErrorCode  status     = U_ZERO_ERROR;
+    /* because the pointer points to the next character */
+    const UChar *pStart    = data->pos - 1;
+    const UChar *pEnd;
+
+    if ((data->flags & UCOL_ITER_INNORMBUF) == 0) {
+        data->writableBuffer.setTo(*(pStart - 1));
+        strsize               = 1;
+    }
+    else {
+        strsize = data->writableBuffer.length();
+    }
+
+    pEnd = data->fcdPosition;
+
+    data->writableBuffer.append(
+        data->nfd->normalize(UnicodeString(FALSE, pStart, (int32_t)(pEnd - pStart)), status));
+    if(U_FAILURE(status)) {
+        return;
+    }
+
+    data->pos        = data->writableBuffer.getTerminatedBuffer() + strsize;
+    data->origFlags  = data->flags;
+    data->flags     |= UCOL_ITER_INNORMBUF;
+    data->flags     &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN);
+}
+
+/**
+* Contraction character management function that returns the next character
+* for the forwards iterator.
+* Does nothing if the next character is in buffer and not the first character
+* in it.
+* Else it checks next character in data string to see if it is normalizable.
+* If it is not, the character is simply copied into the buffer, else
+* the whole normalized substring is copied into the buffer, including the
+* current character.
+* @param data collation element iterator data
+* @return next character
+*/
+static
+inline UChar getNextNormalizedChar(collIterate *data)
+{
+    UChar  nextch;
+    UChar  ch;
+    // Here we need to add the iterator code. One problem is the way
+    // end of string is handled. If we just return next char, it could
+    // be the sentinel. Most of the cases already check for this, but we
+    // need to be sure.
+    if ((data->flags & (UCOL_ITER_NORM | UCOL_ITER_INNORMBUF)) == 0 ) {
+         /* if no normalization and not in buffer. */
+      if(data->flags & UCOL_USE_ITERATOR) {
+         return (UChar)data->iterator->next(data->iterator);
+      } else {
+         return *(data->pos ++);
+      }
+    }
+
+    //if (data->flags & UCOL_ITER_NORM && data->flags & UCOL_USE_ITERATOR) {
+      //normalizeIterator(data);
+    //}
+
+    UBool  innormbuf = (UBool)(data->flags & UCOL_ITER_INNORMBUF);
+    if ((innormbuf && *data->pos != 0) ||
+        (data->fcdPosition != NULL && !innormbuf &&
+        data->pos < data->fcdPosition)) {
+        /*
+        if next character is in normalized buffer, no further normalization
+        is required
+        */
+        return *(data->pos ++);
+    }
+
+    if (data->flags & UCOL_ITER_HASLEN) {
+        /* in data string */
+        if (data->pos + 1 == data->endp) {
+            return *(data->pos ++);
+        }
+    }
+    else {
+        if (innormbuf) {
+          // inside the normalization buffer, but at the end
+          // (since we encountered zero). This means, in the
+          // case we're using char iterator, that we need to
+          // do another round of normalization.
+          //if(data->origFlags & UCOL_USE_ITERATOR) {
+            // we need to restore original flags,
+            // otherwise, we'll lose them
+            //data->flags = data->origFlags;
+            //normalizeIterator(data);
+            //return *(data->pos++);
+          //} else {
+            /*
+            in writable buffer, at this point fcdPosition can not be
+            pointing to the end of the data string. see contracting tag.
+            */
+          if(data->fcdPosition) {
+            if (*(data->fcdPosition + 1) == 0 ||
+                data->fcdPosition + 1 == data->endp) {
+                /* at the end of the string, dump it into the normalizer */
+                data->pos = insertBufferEnd(data, *(data->fcdPosition)) + 1;
+                // Check if data->pos received a null pointer
+                if (data->pos == NULL) {
+                    return (UChar)-1; // Return to indicate error.
+                }
+                return *(data->fcdPosition ++);
+            }
+            data->pos = data->fcdPosition;
+          } else if(data->origFlags & UCOL_USE_ITERATOR) {
+            // if we are here, we're using a normalizing iterator.
+            // we should just continue further.
+            data->flags = data->origFlags;
+            data->pos = NULL;
+            return (UChar)data->iterator->next(data->iterator);
+          }
+          //}
+        }
+        else {
+            if (*(data->pos + 1) == 0) {
+                return *(data->pos ++);
+            }
+        }
+    }
+
+    ch = *data->pos ++;
+    nextch = *data->pos;
+
+    /*
+    * if the current character is not fcd.
+    * Trailing combining class == 0.
+    */
+    if ((data->fcdPosition == NULL || data->fcdPosition < data->pos) &&
+        (nextch >= NFC_ZERO_CC_BLOCK_LIMIT_ ||
+         ch >= NFC_ZERO_CC_BLOCK_LIMIT_)) {
+            /*
+            Need a more complete FCD check and possible normalization.
+            normalize substring will be appended to buffer
+            */
+        if (collIterFCD(data)) {
+            normalizeNextContraction(data);
+            return *(data->pos ++);
+        }
+        else if (innormbuf) {
+            /* fcdposition shifted even when there's no normalization, if we
+            don't input the rest into this, we'll get the wrong position when
+            we reach the end of the writableBuffer */
+            int32_t length = (int32_t)(data->fcdPosition - data->pos + 1);
+            data->pos = insertBufferEnd(data, data->pos - 1, length);
+            // Check if data->pos received a null pointer
+            if (data->pos == NULL) {
+                return (UChar)-1; // Return to indicate error.
+            }
+            return *(data->pos ++);
+        }
+    }
+
+    if (innormbuf) {
+        /*
+        no normalization is to be done hence only one character will be
+        appended to the buffer.
+        */
+        data->pos = insertBufferEnd(data, ch) + 1;
+        // Check if data->pos received a null pointer
+        if (data->pos == NULL) {
+            return (UChar)-1; // Return to indicate error.
+        }
+    }
+
+    /* points back to the pos in string */
+    return ch;
+}
+
+
+
+/**
+* Function to copy the buffer into writableBuffer and sets the fcd position to
+* the correct position
+* @param source data string source
+* @param buffer character buffer
+*/
+static
+inline void setDiscontiguosAttribute(collIterate *source, const UnicodeString &buffer)
+{
+    /* okay confusing part here. to ensure that the skipped characters are
+    considered later, we need to place it in the appropriate position in the
+    normalization buffer and reassign the pos pointer. simple case if pos
+    reside in string, simply copy to normalization buffer and
+    fcdposition = pos, pos = start of normalization buffer. if pos in
+    normalization buffer, we'll insert the copy infront of pos and point pos
+    to the start of the normalization buffer. why am i doing these copies?
+    well, so that the whole chunk of codes in the getNextCE, ucol_prv_getSpecialCE does
+    not require any changes, which be really painful. */
+    if (source->flags & UCOL_ITER_INNORMBUF) {
+        int32_t replaceLength = source->pos - source->writableBuffer.getBuffer();
+        source->writableBuffer.replace(0, replaceLength, buffer);
+    }
+    else {
+        source->fcdPosition  = source->pos;
+        source->origFlags    = source->flags;
+        source->flags       |= UCOL_ITER_INNORMBUF;
+        source->flags       &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN | UCOL_USE_ITERATOR);
+        source->writableBuffer = buffer;
+    }
+
+    source->pos = source->writableBuffer.getTerminatedBuffer();
+}
+
+/**
+* Function to get the discontiguos collation element within the source.
+* Note this function will set the position to the appropriate places.
+* @param coll current collator used
+* @param source data string source
+* @param constart index to the start character in the contraction table
+* @return discontiguos collation element offset
+*/
+static
+uint32_t getDiscontiguous(const UCollator *coll, collIterate *source,
+                                const UChar *constart)
+{
+    /* source->pos currently points to the second combining character after
+       the start character */
+          const UChar *temppos      = source->pos;
+          UnicodeString buffer;
+    const UChar   *tempconstart = constart;
+          uint8_t  tempflags    = source->flags;
+          UBool    multicontraction = FALSE;
+          collIterateState discState;
+
+          backupState(source, &discState);
+
+    buffer.setTo(peekCodePoint(source, -1));
+    for (;;) {
+        UChar    *UCharOffset;
+        UChar     schar,
+                  tchar;
+        uint32_t  result;
+
+        if (((source->flags & UCOL_ITER_HASLEN) && source->pos >= source->endp)
+            || (peekCodeUnit(source, 0) == 0  &&
+            //|| (*source->pos == 0  &&
+                ((source->flags & UCOL_ITER_INNORMBUF) == 0 ||
+                 source->fcdPosition == NULL ||
+                 source->fcdPosition == source->endp ||
+                 *(source->fcdPosition) == 0 ||
+                 u_getCombiningClass(*(source->fcdPosition)) == 0)) ||
+                 /* end of string in null terminated string or stopped by a
+                 null character, note fcd does not always point to a base
+                 character after the discontiguos change */
+                 u_getCombiningClass(peekCodePoint(source, 0)) == 0) {
+                 //u_getCombiningClass(*(source->pos)) == 0) {
+            //constart = (UChar *)coll->image + getContractOffset(CE);
+            if (multicontraction) {
+                source->pos    = temppos - 1;
+                setDiscontiguosAttribute(source, buffer);
+                return *(coll->contractionCEs +
+                                    (tempconstart - coll->contractionIndex));
+            }
+            constart = tempconstart;
+            break;
+        }
+
+        UCharOffset = (UChar *)(tempconstart + 1); /* skip the backward offset*/
+        schar = getNextNormalizedChar(source);
+
+        while (schar > (tchar = *UCharOffset)) {
+            UCharOffset++;
+        }
+
+        if (schar != tchar) {
+            /* not the correct codepoint. we stuff the current codepoint into
+            the discontiguos buffer and try the next character */
+            buffer.append(schar);
+            continue;
+        }
+        else {
+            if (u_getCombiningClass(schar) ==
+                u_getCombiningClass(peekCodePoint(source, -2))) {
+                buffer.append(schar);
+                continue;
+            }
+            result = *(coll->contractionCEs +
+                                      (UCharOffset - coll->contractionIndex));
+        }
+
+        if (result == UCOL_NOT_FOUND) {
+          break;
+        } else if (isContraction(result)) {
+            /* this is a multi-contraction*/
+            tempconstart = (UChar *)coll->image + getContractOffset(result);
+            if (*(coll->contractionCEs + (constart - coll->contractionIndex))
+                != UCOL_NOT_FOUND) {
+                multicontraction = TRUE;
+                temppos       = source->pos + 1;
+            }
+        } else {
+            setDiscontiguosAttribute(source, buffer);
+            return result;
+        }
+    }
+
+    /* no problems simply reverting just like that,
+    if we are in string before getting into this function, points back to
+    string hence no problem.
+    if we are in normalization buffer before getting into this function,
+    since we'll never use another normalization within this function, we
+    know that fcdposition points to a base character. the normalization buffer
+    never change, hence this revert works. */
+    loadState(source, &discState, TRUE);
+    goBackOne(source);
+
+    //source->pos   = temppos - 1;
+    source->flags = tempflags;
+    return *(coll->contractionCEs + (constart - coll->contractionIndex));
+}
+
+/* now uses Mark's getImplicitPrimary code */
+static
+inline uint32_t getImplicit(UChar32 cp, collIterate *collationSource) {
+    uint32_t r = uprv_uca_getImplicitPrimary(cp);
+    *(collationSource->CEpos++) = ((r & 0x0000FFFF)<<16) | 0x000000C0;
+    collationSource->offsetRepeatCount += 1;
+    return (r & UCOL_PRIMARYMASK) | 0x00000505; // This was 'order'
+}
+
+/**
+* Inserts the argument character into the front of the buffer replacing the
+* front null terminator.
+* @param data collation element iterator data
+* @param ch character to be appended
+*/
+static
+inline void insertBufferFront(collIterate *data, UChar ch)
+{
+    data->pos = data->writableBuffer.setCharAt(0, ch).insert(0, (UChar)0).getTerminatedBuffer() + 2;
+}
+
+/**
+* Special normalization function for contraction in the previous iterator.
+* This normalization sequence will place the current character at source->pos
+* and its following normalized sequence into the buffer.
+* The fcd position, pos will be changed.
+* pos will now point to positions in the buffer.
+* Flags will be changed accordingly.
+* @param data collation iterator data
+*/
+static
+inline void normalizePrevContraction(collIterate *data, UErrorCode *status)
+{
+    const UChar *pEnd = data->pos + 1;         /* End normalize + 1 */
+    const UChar *pStart;
+
+    UnicodeString endOfBuffer;
+    if (data->flags & UCOL_ITER_HASLEN) {
+        /*
+        normalization buffer not used yet, we'll pull down the next
+        character into the end of the buffer
+        */
+        endOfBuffer.setTo(*pEnd);
+    }
+    else {
+        endOfBuffer.setTo(data->writableBuffer, 1);  // after the leading NUL
+    }
+
+    if (data->fcdPosition == NULL) {
+        pStart = data->string;
+    }
+    else {
+        pStart = data->fcdPosition + 1;
+    }
+    int32_t normLen =
+        data->nfd->normalize(UnicodeString(FALSE, pStart, (int32_t)(pEnd - pStart)),
+                             data->writableBuffer,
+                             *status).
+        length();
+    if(U_FAILURE(*status)) {
+        return;
+    }
+    /*
+    this puts the null termination infront of the normalized string instead
+    of the end
+    */
+    data->pos =
+        data->writableBuffer.insert(0, (UChar)0).append(endOfBuffer).getTerminatedBuffer() +
+        1 + normLen;
+    data->origFlags  = data->flags;
+    data->flags     |= UCOL_ITER_INNORMBUF;
+    data->flags     &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN);
+}
+
+/**
+* Contraction character management function that returns the previous character
+* for the backwards iterator.
+* Does nothing if the previous character is in buffer and not the first
+* character in it.
+* Else it checks previous character in data string to see if it is
+* normalizable.
+* If it is not, the character is simply copied into the buffer, else
+* the whole normalized substring is copied into the buffer, including the
+* current character.
+* @param data collation element iterator data
+* @return previous character
+*/
+static
+inline UChar getPrevNormalizedChar(collIterate *data, UErrorCode *status)
+{
+    UChar  prevch;
+    UChar  ch;
+    const UChar *start;
+    UBool  innormbuf = (UBool)(data->flags & UCOL_ITER_INNORMBUF);
+    if ((data->flags & (UCOL_ITER_NORM | UCOL_ITER_INNORMBUF)) == 0 ||
+        (innormbuf && *(data->pos - 1) != 0)) {
+        /*
+        if no normalization.
+        if previous character is in normalized buffer, no further normalization
+        is required
+        */
+      if(data->flags & UCOL_USE_ITERATOR) {
+        data->iterator->move(data->iterator, -1, UITER_CURRENT);
+        return (UChar)data->iterator->next(data->iterator);
+      } else {
+        return *(data->pos - 1);
+      }
+    }
+
+    start = data->pos;
+    if ((data->fcdPosition==NULL)||(data->flags & UCOL_ITER_HASLEN)) {
+        /* in data string */
+        if ((start - 1) == data->string) {
+            return *(start - 1);
+        }
+        start --;
+        ch     = *start;
+        prevch = *(start - 1);
+    }
+    else {
+        /*
+        in writable buffer, at this point fcdPosition can not be NULL.
+        see contracting tag.
+        */
+        if (data->fcdPosition == data->string) {
+            /* at the start of the string, just dump it into the normalizer */
+            insertBufferFront(data, *(data->fcdPosition));
+            data->fcdPosition = NULL;
+            return *(data->pos - 1);
+        }
+        start  = data->fcdPosition;
+        ch     = *start;
+        prevch = *(start - 1);
+    }
+    /*
+    * if the current character is not fcd.
+    * Trailing combining class == 0.
+    */
+    if (data->fcdPosition > start &&
+       (ch >= NFC_ZERO_CC_BLOCK_LIMIT_ || prevch >= NFC_ZERO_CC_BLOCK_LIMIT_))
+    {
+        /*
+        Need a more complete FCD check and possible normalization.
+        normalize substring will be appended to buffer
+        */
+        const UChar *backuppos = data->pos;
+        data->pos = start;
+        if (collPrevIterFCD(data)) {
+            normalizePrevContraction(data, status);
+            return *(data->pos - 1);
+        }
+        data->pos = backuppos;
+        data->fcdPosition ++;
+    }
+
+    if (innormbuf) {
+    /*
+    no normalization is to be done hence only one character will be
+    appended to the buffer.
+    */
+        insertBufferFront(data, ch);
+        data->fcdPosition --;
+    }
+
+    return ch;
+}
+
+/* This function handles the special CEs like contractions, expansions, surrogates, Thai */
+/* It is called by getNextCE */
+
+/* The following should be even */
+#define UCOL_MAX_DIGITS_FOR_NUMBER 254
+
+uint32_t ucol_prv_getSpecialCE(const UCollator *coll, UChar ch, uint32_t CE, collIterate *source, UErrorCode *status) {
+    collIterateState entryState;
+    backupState(source, &entryState);
+    UChar32 cp = ch;
+
+    for (;;) {
+        // This loop will repeat only in the case of contractions, and only when a contraction
+        //   is found and the first CE resulting from that contraction is itself a special
+        //   (an expansion, for example.)  All other special CE types are fully handled the
+        //   first time through, and the loop exits.
+
+        const uint32_t *CEOffset = NULL;
+        switch(getCETag(CE)) {
+        case NOT_FOUND_TAG:
+            /* This one is not found, and we'll let somebody else bother about it... no more games */
+            return CE;
+        case SPEC_PROC_TAG:
+            {
+                // Special processing is getting a CE that is preceded by a certain prefix
+                // Currently this is only needed for optimizing Japanese length and iteration marks.
+                // When we encouter a special processing tag, we go backwards and try to see if
+                // we have a match.
+                // Contraction tables are used - so the whole process is not unlike contraction.
+                // prefix data is stored backwards in the table.
+                const UChar *UCharOffset;
+                UChar schar, tchar;
+                collIterateState prefixState;
+                backupState(source, &prefixState);
+                loadState(source, &entryState, TRUE);
+                goBackOne(source); // We want to look at the point where we entered - actually one
+                // before that...
+
+                for(;;) {
+                    // This loop will run once per source string character, for as long as we
+                    //  are matching a potential contraction sequence
+
+                    // First we position ourselves at the begining of contraction sequence
+                    const UChar *ContractionStart = UCharOffset = (UChar *)coll->image+getContractOffset(CE);
+                    if (collIter_bos(source)) {
+                        CE = *(coll->contractionCEs + (UCharOffset - coll->contractionIndex));
+                        break;
+                    }
+                    schar = getPrevNormalizedChar(source, status);
+                    goBackOne(source);
+
+                    while(schar > (tchar = *UCharOffset)) { /* since the contraction codepoints should be ordered, we skip all that are smaller */
+                        UCharOffset++;
+                    }
+
+                    if (schar == tchar) {
+                        // Found the source string char in the table.
+                        //  Pick up the corresponding CE from the table.
+                        CE = *(coll->contractionCEs +
+                            (UCharOffset - coll->contractionIndex));
+                    }
+                    else
+                    {
+                        // Source string char was not in the table.
+                        //   We have not found the prefix.
+                        CE = *(coll->contractionCEs +
+                            (ContractionStart - coll->contractionIndex));
+                    }
+
+                    if(!isPrefix(CE)) {
+                        // The source string char was in the contraction table, and the corresponding
+                        //   CE is not a prefix CE.  We found the prefix, break
+                        //   out of loop, this CE will end up being returned.  This is the normal
+                        //   way out of prefix handling when the source actually contained
+                        //   the prefix.
+                        break;
+                    }
+                }
+                if(CE != UCOL_NOT_FOUND) { // we found something and we can merilly continue
+                    loadState(source, &prefixState, TRUE);
+                    if(source->origFlags & UCOL_USE_ITERATOR) {
+                        source->flags = source->origFlags;
+                    }
+                } else { // prefix search was a failure, we have to backup all the way to the start
+                    loadState(source, &entryState, TRUE);
+                }
+                break;
+            }
+        case CONTRACTION_TAG:
+            {
+                /* This should handle contractions */
+                collIterateState state;
+                backupState(source, &state);
+                uint32_t firstCE = *(coll->contractionCEs + ((UChar *)coll->image+getContractOffset(CE) - coll->contractionIndex)); //UCOL_NOT_FOUND;
+                const UChar *UCharOffset;
+                UChar schar, tchar;
+
+                for (;;) {
+                    /* This loop will run once per source string character, for as long as we     */
+                    /*  are matching a potential contraction sequence                  */
+
+                    /* First we position ourselves at the begining of contraction sequence */
+                    const UChar *ContractionStart = UCharOffset = (UChar *)coll->image+getContractOffset(CE);
+
+                    if (collIter_eos(source)) {
+                        // Ran off the end of the source string.
+                        CE = *(coll->contractionCEs + (UCharOffset - coll->contractionIndex));
+                        // So we'll pick whatever we have at the point...
+                        if (CE == UCOL_NOT_FOUND) {
+                            // back up the source over all the chars we scanned going into this contraction.
+                            CE = firstCE;
+                            loadState(source, &state, TRUE);
+                            if(source->origFlags & UCOL_USE_ITERATOR) {
+                                source->flags = source->origFlags;
+                            }
+                        }
+                        break;
+                    }
+
+                    uint8_t maxCC = (uint8_t)(*(UCharOffset)&0xFF); /*get the discontiguos stuff */ /* skip the backward offset, see above */
+                    uint8_t allSame = (uint8_t)(*(UCharOffset++)>>8);
+
+                    schar = getNextNormalizedChar(source);
+                    while(schar > (tchar = *UCharOffset)) { /* since the contraction codepoints should be ordered, we skip all that are smaller */
+                        UCharOffset++;
+                    }
+
+                    if (schar == tchar) {
+                        // Found the source string char in the contraction table.
+                        //  Pick up the corresponding CE from the table.
+                        CE = *(coll->contractionCEs +
+                            (UCharOffset - coll->contractionIndex));
+                    }
+                    else
+                    {
+                        // Source string char was not in contraction table.
+                        //   Unless we have a discontiguous contraction, we have finished
+                        //   with this contraction.
+                        // in order to do the proper detection, we
+                        // need to see if we're dealing with a supplementary
+                        /* We test whether the next two char are surrogate pairs.
+                        * This test is done if the iterator is not NULL.
+                        * If there is no surrogate pair, the iterator
+                        * goes back one if needed. */
+                        UChar32 miss = schar;
+                        if (source->iterator) {
+                            UChar32 surrNextChar; /* the next char in the iteration to test */
+                            int32_t prevPos; /* holds the previous position before move forward of the source iterator */
+                            if(U16_IS_LEAD(schar) && source->iterator->hasNext(source->iterator)) {
+                                prevPos = source->iterator->index;
+                                surrNextChar = getNextNormalizedChar(source);
+                                if (U16_IS_TRAIL(surrNextChar)) {
+                                    miss = U16_GET_SUPPLEMENTARY(schar, surrNextChar);
+                                } else if (prevPos < source->iterator->index){
+                                    goBackOne(source);
+                                }
+                            }
+                        } else if (U16_IS_LEAD(schar)) {
+                            miss = U16_GET_SUPPLEMENTARY(schar, getNextNormalizedChar(source));
+                        }
+
+                        uint8_t sCC;
+                        if (miss < 0x300 ||
+                            maxCC == 0 ||
+                            (sCC = i_getCombiningClass(miss, coll)) == 0 ||
+                            sCC>maxCC ||
+                            (allSame != 0 && sCC == maxCC) ||
+                            collIter_eos(source))
+                        {
+                            //  Contraction can not be discontiguous.
+                            goBackOne(source);  // back up the source string by one,
+                            //  because  the character we just looked at was
+                            //  not part of the contraction.   */
+                            if(U_IS_SUPPLEMENTARY(miss)) {
+                                goBackOne(source);
+                            }
+                            CE = *(coll->contractionCEs +
+                                (ContractionStart - coll->contractionIndex));
+                        } else {
+                            //
+                            // Contraction is possibly discontiguous.
+                            //   Scan more of source string looking for a match
+                            //
+                            UChar tempchar;
+                            /* find the next character if schar is not a base character
+                            and we are not yet at the end of the string */
+                            tempchar = getNextNormalizedChar(source);
+                            // probably need another supplementary thingie here
+                            goBackOne(source);
+                            if (i_getCombiningClass(tempchar, coll) == 0) {
+                                goBackOne(source);
+                                if(U_IS_SUPPLEMENTARY(miss)) {
+                                    goBackOne(source);
+                                }
+                                /* Spit out the last char of the string, wasn't tasty enough */
+                                CE = *(coll->contractionCEs +
+                                    (ContractionStart - coll->contractionIndex));
+                            } else {
+                                CE = getDiscontiguous(coll, source, ContractionStart);
+                            }
+                        }
+                    } // else after if(schar == tchar)
+
+                    if(CE == UCOL_NOT_FOUND) {
+                        /* The Source string did not match the contraction that we were checking.  */
+                        /*  Back up the source position to undo the effects of having partially    */
+                        /*   scanned through what ultimately proved to not be a contraction.       */
+                        loadState(source, &state, TRUE);
+                        CE = firstCE;
+                        break;
+                    }
+
+                    if(!isContraction(CE)) {
+                        // The source string char was in the contraction table, and the corresponding
+                        //   CE is not a contraction CE.  We completed the contraction, break
+                        //   out of loop, this CE will end up being returned.  This is the normal
+                        //   way out of contraction handling when the source actually contained
+                        //   the contraction.
+                        break;
+                    }
+
+
+                    // The source string char was in the contraction table, and the corresponding
+                    //   CE is IS  a contraction CE.  We will continue looping to check the source
+                    //   string for the remaining chars in the contraction.
+                    uint32_t tempCE = *(coll->contractionCEs + (ContractionStart - coll->contractionIndex));
+                    if(tempCE != UCOL_NOT_FOUND) {
+                        // We have scanned a a section of source string for which there is a
+                        //  CE from the contraction table.  Remember the CE and scan position, so
+                        //  that we can return to this point if further scanning fails to
+                        //  match a longer contraction sequence.
+                        firstCE = tempCE;
+
+                        goBackOne(source);
+                        backupState(source, &state);
+                        getNextNormalizedChar(source);
+
+                        // Another way to do this is:
+                        //collIterateState tempState;
+                        //backupState(source, &tempState);
+                        //goBackOne(source);
+                        //backupState(source, &state);
+                        //loadState(source, &tempState, TRUE);
+
+                        // The problem is that for incomplete contractions we have to remember the previous
+                        // position. Before, the only thing I needed to do was state.pos--;
+                        // After iterator introduction and especially after introduction of normalizing
+                        // iterators, it became much more difficult to decrease the saved state.
+                        // I'm not yet sure which of the two methods above is faster.
+                    }
+                } // for(;;)
+                break;
+            } // case CONTRACTION_TAG:
+        case LONG_PRIMARY_TAG:
+            {
+                *(source->CEpos++) = ((CE & 0xFF)<<24)|UCOL_CONTINUATION_MARKER;
+                CE = ((CE & 0xFFFF00) << 8) | (UCOL_BYTE_COMMON << 8) | UCOL_BYTE_COMMON;
+                source->offsetRepeatCount += 1;
+                return CE;
+            }
+        case EXPANSION_TAG:
+            {
+                /* This should handle expansion. */
+                /* NOTE: we can encounter both continuations and expansions in an expansion! */
+                /* I have to decide where continuations are going to be dealt with */
+                uint32_t size;
+                uint32_t i;    /* general counter */
+
+                CEOffset = (uint32_t *)coll->image+getExpansionOffset(CE); /* find the offset to expansion table */
+                size = getExpansionCount(CE);
+                CE = *CEOffset++;
+              //source->offsetRepeatCount = -1;
+
+                if(size != 0) { /* if there are less than 16 elements in expansion, we don't terminate */
+                    for(i = 1; i<size; i++) {
+                        *(source->CEpos++) = *CEOffset++;
+                        source->offsetRepeatCount += 1;
+                    }
+                } else { /* else, we do */
+                    while(*CEOffset != 0) {
+                        *(source->CEpos++) = *CEOffset++;
+                        source->offsetRepeatCount += 1;
+                    }
+                }
+
+                return CE;
+            }
+        case DIGIT_TAG:
+            {
+                /*
+                We do a check to see if we want to collate digits as numbers; if so we generate
+                a custom collation key. Otherwise we pull out the value stored in the expansion table.
+                */
+                //uint32_t size;
+                uint32_t i;    /* general counter */
+
+                if (source->coll->numericCollation == UCOL_ON){
+                    collIterateState digitState = {0,0,0,0,0,0,0,0,0};
+                    UChar32 char32 = 0;
+                    int32_t digVal = 0;
+
+                    uint32_t digIndx = 0;
+                    uint32_t endIndex = 0;
+                    uint32_t trailingZeroIndex = 0;
+
+                    uint8_t collateVal = 0;
+
+                    UBool nonZeroValReached = FALSE;
+
+                    uint8_t numTempBuf[UCOL_MAX_DIGITS_FOR_NUMBER/2 + 3]; // I just need a temporary place to store my generated CEs.
+                    /*
+                         We parse the source string until we hit a char that's NOT a digit.
+                        Use this u_charDigitValue. This might be slow because we have to
+                        handle surrogates...
+                    */
+            /*
+                    if (U16_IS_LEAD(ch)){
+                      if (!collIter_eos(source)) {
+                        backupState(source, &digitState);
+                        UChar trail = getNextNormalizedChar(source);
+                        if(U16_IS_TRAIL(trail)) {
+                          char32 = U16_GET_SUPPLEMENTARY(ch, trail);
+                        } else {
+                          loadState(source, &digitState, TRUE);
+                          char32 = ch;
+                        }
+                      } else {
+                        char32 = ch;
+                      }
+                    } else {
+                      char32 = ch;
+                    }
+                    digVal = u_charDigitValue(char32);
+            */
+                    digVal = u_charDigitValue(cp); // if we have arrived here, we have
+                    // already processed possible supplementaries that trigered the digit tag -
+                    // all supplementaries are marked in the UCA.
+                    /*
+                        We  pad a zero in front of the first element anyways. This takes
+                        care of the (probably) most common case where people are sorting things followed
+                        by a single digit
+                    */
+                    digIndx++;
+                    for(;;){
+                        // Make sure we have enough space. No longer needed;
+                        // at this point digIndx now has a max value of UCOL_MAX_DIGITS_FOR_NUMBER
+                        // (it has been pre-incremented) so we just ensure that numTempBuf is big enough
+                        // (UCOL_MAX_DIGITS_FOR_NUMBER/2 + 3).
+
+                        // Skipping over leading zeroes.
+                        if (digVal != 0) {
+                            nonZeroValReached = TRUE;
+                        }
+                        if (nonZeroValReached) {
+                            /*
+                            We parse the digit string into base 100 numbers (this fits into a byte).
+                            We only add to the buffer in twos, thus if we are parsing an odd character,
+                            that serves as the 'tens' digit while the if we are parsing an even one, that
+                            is the 'ones' digit. We dumped the parsed base 100 value (collateVal) into
+                            a buffer. We multiply each collateVal by 2 (to give us room) and add 5 (to avoid
+                            overlapping magic CE byte values). The last byte we subtract 1 to ensure it is less
+                            than all the other bytes.
+                            */
+
+                            if (digIndx % 2 == 1){
+                                collateVal += (uint8_t)digVal;
+
+                                // We don't enter the low-order-digit case unless we've already seen
+                                // the high order, or for the first digit, which is always non-zero.
+                                if (collateVal != 0)
+                                    trailingZeroIndex = 0;
+
+                                numTempBuf[(digIndx/2) + 2] = collateVal*2 + 6;
+                                collateVal = 0;
+                            }
+                            else{
+                                // We drop the collation value into the buffer so if we need to do
+                                // a "front patch" we don't have to check to see if we're hitting the
+                                // last element.
+                                collateVal = (uint8_t)(digVal * 10);
+
+                                // Check for trailing zeroes.
+                                if (collateVal == 0)
+                                {
+                                    if (!trailingZeroIndex)
+                                        trailingZeroIndex = (digIndx/2) + 2;
+                                }
+                                else
+                                    trailingZeroIndex = 0;
+
+                                numTempBuf[(digIndx/2) + 2] = collateVal*2 + 6;
+                            }
+                            digIndx++;
+                        }
+
+                        // Get next character.
+                        if (!collIter_eos(source)){
+                            ch = getNextNormalizedChar(source);
+                            if (U16_IS_LEAD(ch)){
+                                if (!collIter_eos(source)) {
+                                    backupState(source, &digitState);
+                                    UChar trail = getNextNormalizedChar(source);
+                                    if(U16_IS_TRAIL(trail)) {
+                                        char32 = U16_GET_SUPPLEMENTARY(ch, trail);
+                                    } else {
+                                        loadState(source, &digitState, TRUE);
+                                        char32 = ch;
+                                    }
+                                }
+                            } else {
+                                char32 = ch;
+                            }
+
+                            if ((digVal = u_charDigitValue(char32)) == -1 || digIndx > UCOL_MAX_DIGITS_FOR_NUMBER){
+                                // Resetting position to point to the next unprocessed char. We
+                                // overshot it when doing our test/set for numbers.
+                                if (char32 > 0xFFFF) { // For surrogates.
+                                    loadState(source, &digitState, TRUE);
+                                    //goBackOne(source);
+                                }
+                                goBackOne(source);
+                                break;
+                            }
+                        } else {
+                            break;
+                        }
+                    }
+
+                    if (nonZeroValReached == FALSE){
+                        digIndx = 2;
+                        numTempBuf[2] = 6;
+                    }
+
+                    endIndex = trailingZeroIndex ? trailingZeroIndex : ((digIndx/2) + 2) ;
+                    if (digIndx % 2 != 0){
+                        /*
+                        We missed a value. Since digIndx isn't even, stuck too many values into the buffer (this is what
+                        we get for padding the first byte with a zero). "Front-patch" now by pushing all nybbles forward.
+                        Doing it this way ensures that at least 50% of the time (statistically speaking) we'll only be doing a
+                        single pass and optimizes for strings with single digits. I'm just assuming that's the more common case.
+                        */
+
+                        for(i = 2; i < endIndex; i++){
+                            numTempBuf[i] =     (((((numTempBuf[i] - 6)/2) % 10) * 10) +
+                                (((numTempBuf[i+1])-6)/2) / 10) * 2 + 6;
+                        }
+                        --digIndx;
+                    }
+
+                    // Subtract one off of the last byte.
+                    numTempBuf[endIndex-1] -= 1;
+
+                    /*
+                    We want to skip over the first two slots in the buffer. The first slot
+                    is reserved for the header byte UCOL_CODAN_PLACEHOLDER. The second slot is for the
+                    sign/exponent byte: 0x80 + (decimalPos/2) & 7f.
+                    */
+                    numTempBuf[0] = UCOL_CODAN_PLACEHOLDER;
+                    numTempBuf[1] = (uint8_t)(0x80 + ((digIndx/2) & 0x7F));
+
+                    // Now transfer the collation key to our collIterate struct.
+                    // The total size for our collation key is endIndx bumped up to the next largest even value divided by two.
+                    //size = ((endIndex+1) & ~1)/2;
+                    CE = (((numTempBuf[0] << 8) | numTempBuf[1]) << UCOL_PRIMARYORDERSHIFT) | //Primary weight
+                        (UCOL_BYTE_COMMON << UCOL_SECONDARYORDERSHIFT) | // Secondary weight
+                        UCOL_BYTE_COMMON; // Tertiary weight.
+                    i = 2; // Reset the index into the buffer.
+                    while(i < endIndex)
+                    {
+                        uint32_t primWeight = numTempBuf[i++] << 8;
+                        if ( i < endIndex)
+                            primWeight |= numTempBuf[i++];
+                        *(source->CEpos++) = (primWeight << UCOL_PRIMARYORDERSHIFT) | UCOL_CONTINUATION_MARKER;
+                    }
+
+                } else {
+                    // no numeric mode, we'll just switch to whatever we stashed and continue
+                    CEOffset = (uint32_t *)coll->image+getExpansionOffset(CE); /* find the offset to expansion table */
+                    CE = *CEOffset++;
+                    break;
+                }
+                return CE;
+            }
+            /* various implicits optimization */
+        case IMPLICIT_TAG:        /* everything that is not defined otherwise */
+            /* UCA is filled with these. Tailorings are NOT_FOUND */
+            return getImplicit(cp, source);
+        case CJK_IMPLICIT_TAG:    /* 0x3400-0x4DB5, 0x4E00-0x9FA5, 0xF900-0xFA2D*/
+            // TODO: remove CJK_IMPLICIT_TAG completely - handled by the getImplicit
+            return getImplicit(cp, source);
+        case HANGUL_SYLLABLE_TAG: /* AC00-D7AF*/
+            {
+                static const uint32_t
+                    SBase = 0xAC00, LBase = 0x1100, VBase = 0x1161, TBase = 0x11A7;
+                //const uint32_t LCount = 19;
+                static const uint32_t VCount = 21;
+                static const uint32_t TCount = 28;
+                //const uint32_t NCount = VCount * TCount;   // 588
+                //const uint32_t SCount = LCount * NCount;   // 11172
+                uint32_t L = ch - SBase;
+
+                // divide into pieces
+
+                uint32_t T = L % TCount; // we do it in this order since some compilers can do % and / in one operation
+                L /= TCount;
+                uint32_t V = L % VCount;
+                L /= VCount;
+
+                // offset them
+
+                L += LBase;
+                V += VBase;
+                T += TBase;
+
+                // return the first CE, but first put the rest into the expansion buffer
+                if (!source->coll->image->jamoSpecial) { // FAST PATH
+
+                    *(source->CEpos++) = UTRIE_GET32_FROM_LEAD(&coll->mapping, V);
+                    if (T != TBase) {
+                        *(source->CEpos++) = UTRIE_GET32_FROM_LEAD(&coll->mapping, T);
+                    }
+
+                    return UTRIE_GET32_FROM_LEAD(&coll->mapping, L);
+
+                } else { // Jamo is Special
+                    // Since Hanguls pass the FCD check, it is
+                    // guaranteed that we won't be in
+                    // the normalization buffer if something like this happens
+
+                    // However, if we are using a uchar iterator and normalization
+                    // is ON, the Hangul that lead us here is going to be in that
+                    // normalization buffer. Here we want to restore the uchar
+                    // iterator state and pull out of the normalization buffer
+                    if(source->iterator != NULL && source->flags & UCOL_ITER_INNORMBUF) {
+                        source->flags = source->origFlags; // restore the iterator
+                        source->pos = NULL;
+                    }
+
+                    // Move Jamos into normalization buffer
+                    UChar *buffer = source->writableBuffer.getBuffer(4);
+                    int32_t bufferLength;
+                    buffer[0] = (UChar)L;
+                    buffer[1] = (UChar)V;
+                    if (T != TBase) {
+                        buffer[2] = (UChar)T;
+                        bufferLength = 3;
+                    } else {
+                        bufferLength = 2;
+                    }
+                    source->writableBuffer.releaseBuffer(bufferLength);
+
+                    // Indicate where to continue in main input string after exhausting the writableBuffer
+                    source->fcdPosition       = source->pos;
+
+                    source->pos   = source->writableBuffer.getTerminatedBuffer();
+                    source->origFlags   = source->flags;
+                    source->flags       |= UCOL_ITER_INNORMBUF;
+                    source->flags       &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN);
+
+                    return(UCOL_IGNORABLE);
+                }
+            }
+        case SURROGATE_TAG:
+            /* we encountered a leading surrogate. We shall get the CE by using the following code unit */
+            /* two things can happen here: next code point can be a trailing surrogate - we will use it */
+            /* to retrieve the CE, or it is not a trailing surrogate (or the string is done). In that case */
+            /* we treat it like an unassigned code point. */
+            {
+                UChar trail;
+                collIterateState state;
+                backupState(source, &state);
+                if (collIter_eos(source) || !(U16_IS_TRAIL((trail = getNextNormalizedChar(source))))) {
+                    // we chould have stepped one char forward and it might have turned that it
+                    // was not a trail surrogate. In that case, we have to backup.
+                    loadState(source, &state, TRUE);
+                    return UCOL_NOT_FOUND;
+                } else {
+                    /* TODO: CE contain the data from the previous CE + the mask. It should at least be unmasked */
+                    CE = UTRIE_GET32_FROM_OFFSET_TRAIL(&coll->mapping, CE&0xFFFFFF, trail);
+                    if(CE == UCOL_NOT_FOUND) { // there are tailored surrogates in this block, but not this one.
+                        // We need to backup
+                        loadState(source, &state, TRUE);
+                        return CE;
+                    }
+                    // calculate the supplementary code point value, if surrogate was not tailored
+                    cp = ((((uint32_t)ch)<<10UL)+(trail)-(((uint32_t)0xd800<<10UL)+0xdc00-0x10000));
+                }
+            }
+            break;
+        case LEAD_SURROGATE_TAG:  /* D800-DBFF*/
+            UChar nextChar;
+            if( source->flags & UCOL_USE_ITERATOR) {
+                if(U_IS_TRAIL(nextChar = (UChar)source->iterator->current(source->iterator))) {
+                    cp = U16_GET_SUPPLEMENTARY(ch, nextChar);
+                    source->iterator->next(source->iterator);
+                    return getImplicit(cp, source);
+                }
+            } else if((((source->flags & UCOL_ITER_HASLEN) == 0 ) || (source->pos<source->endp)) &&
+                      U_IS_TRAIL((nextChar=*source->pos))) {
+                cp = U16_GET_SUPPLEMENTARY(ch, nextChar);
+                source->pos++;
+                return getImplicit(cp, source);
+            }
+            return UCOL_NOT_FOUND;
+        case TRAIL_SURROGATE_TAG: /* DC00-DFFF*/
+            return UCOL_NOT_FOUND; /* broken surrogate sequence */
+        case CHARSET_TAG:
+            /* not yet implemented */
+            /* probably after 1.8 */
+            return UCOL_NOT_FOUND;
+        default:
+            *status = U_INTERNAL_PROGRAM_ERROR;
+            CE=0;
+            break;
+    }
+    if (CE <= UCOL_NOT_FOUND) break;
+  }
+  return CE;
+}
+
+
+/* now uses Mark's getImplicitPrimary code */
+static
+inline uint32_t getPrevImplicit(UChar32 cp, collIterate *collationSource) {
+    uint32_t r = uprv_uca_getImplicitPrimary(cp);
+
+    *(collationSource->CEpos++) = (r & UCOL_PRIMARYMASK) | 0x00000505;
+    collationSource->toReturn = collationSource->CEpos;
+
+    // **** doesn't work if using iterator ****
+    if (collationSource->flags & UCOL_ITER_INNORMBUF) {
+        collationSource->offsetRepeatCount = 1;
+    } else {
+        int32_t firstOffset = (int32_t)(collationSource->pos - collationSource->string);
+
+        UErrorCode errorCode = U_ZERO_ERROR;
+        collationSource->appendOffset(firstOffset, errorCode);
+        collationSource->appendOffset(firstOffset + 1, errorCode);
+
+        collationSource->offsetReturn = collationSource->offsetStore - 1;
+        *(collationSource->offsetBuffer) = firstOffset;
+        if (collationSource->offsetReturn == collationSource->offsetBuffer) {
+            collationSource->offsetStore = collationSource->offsetBuffer;
+        }
+    }
+
+    return ((r & 0x0000FFFF)<<16) | 0x000000C0;
+}
+
+/**
+ * This function handles the special CEs like contractions, expansions,
+ * surrogates, Thai.
+ * It is called by both getPrevCE
+ */
+uint32_t ucol_prv_getSpecialPrevCE(const UCollator *coll, UChar ch, uint32_t CE,
+                          collIterate *source,
+                          UErrorCode *status)
+{
+    const uint32_t *CEOffset    = NULL;
+          UChar    *UCharOffset = NULL;
+          UChar    schar;
+    const UChar    *constart    = NULL;
+          uint32_t size;
+          UChar    buffer[UCOL_MAX_BUFFER];
+          uint32_t *endCEBuffer;
+          UChar   *strbuffer;
+          int32_t noChars = 0;
+          int32_t CECount = 0;
+
+    for(;;)
+    {
+        /* the only ces that loops are thai and contractions */
+        switch (getCETag(CE))
+        {
+        case NOT_FOUND_TAG:  /* this tag always returns */
+            return CE;
+
+        case SPEC_PROC_TAG:
+            {
+                // Special processing is getting a CE that is preceded by a certain prefix
+                // Currently this is only needed for optimizing Japanese length and iteration marks.
+                // When we encouter a special processing tag, we go backwards and try to see if
+                // we have a match.
+                // Contraction tables are used - so the whole process is not unlike contraction.
+                // prefix data is stored backwards in the table.
+                const UChar *UCharOffset;
+                UChar schar, tchar;
+                collIterateState prefixState;
+                backupState(source, &prefixState);
+                for(;;) {
+                    // This loop will run once per source string character, for as long as we
+                    //  are matching a potential contraction sequence
+
+                    // First we position ourselves at the begining of contraction sequence
+                    const UChar *ContractionStart = UCharOffset = (UChar *)coll->image+getContractOffset(CE);
+
+                    if (collIter_bos(source)) {
+                        CE = *(coll->contractionCEs + (UCharOffset - coll->contractionIndex));
+                        break;
+                    }
+                    schar = getPrevNormalizedChar(source, status);
+                    goBackOne(source);
+
+                    while(schar > (tchar = *UCharOffset)) { /* since the contraction codepoints should be ordered, we skip all that are smaller */
+                        UCharOffset++;
+                    }
+
+                    if (schar == tchar) {
+                        // Found the source string char in the table.
+                        //  Pick up the corresponding CE from the table.
+                        CE = *(coll->contractionCEs +
+                            (UCharOffset - coll->contractionIndex));
+                    }
+                    else
+                    {
+                        // if there is a completely ignorable code point in the middle of
+                        // a prefix, we need to act as if it's not there
+                        // assumption: 'real' noncharacters (*fffe, *ffff, fdd0-fdef are set to zero)
+                        // lone surrogates cannot be set to zero as it would break other processing
+                        uint32_t isZeroCE = UTRIE_GET32_FROM_LEAD(&coll->mapping, schar);
+                        // it's easy for BMP code points
+                        if(isZeroCE == 0) {
+                            continue;
+                        } else if(U16_IS_SURROGATE(schar)) {
+                            // for supplementary code points, we have to check the next one
+                            // situations where we are going to ignore
+                            // 1. beginning of the string: schar is a lone surrogate
+                            // 2. schar is a lone surrogate
+                            // 3. schar is a trail surrogate in a valid surrogate sequence
+                            //    that is explicitly set to zero.
+                            if (!collIter_bos(source)) {
+                                UChar lead;
+                                if(!U16_IS_SURROGATE_LEAD(schar) && U16_IS_LEAD(lead = getPrevNormalizedChar(source, status))) {
+                                    isZeroCE = UTRIE_GET32_FROM_LEAD(&coll->mapping, lead);
+                                    if(isSpecial(isZeroCE) && getCETag(isZeroCE) == SURROGATE_TAG) {
+                                        uint32_t finalCE = UTRIE_GET32_FROM_OFFSET_TRAIL(&coll->mapping, isZeroCE&0xFFFFFF, schar);
+                                        if(finalCE == 0) {
+                                            // this is a real, assigned completely ignorable code point
+                                            goBackOne(source);
+                                            continue;
+                                        }
+                                    }
+                                } else {
+                                    // lone surrogate, treat like unassigned
+                                    return UCOL_NOT_FOUND;
+                                }
+                            } else {
+                                // lone surrogate at the beggining, treat like unassigned
+                                return UCOL_NOT_FOUND;
+                            }
+                        }
+                        // Source string char was not in the table.
+                        //   We have not found the prefix.
+                        CE = *(coll->contractionCEs +
+                            (ContractionStart - coll->contractionIndex));
+                    }
+
+                    if(!isPrefix(CE)) {
+                        // The source string char was in the contraction table, and the corresponding
+                        //   CE is not a prefix CE.  We found the prefix, break
+                        //   out of loop, this CE will end up being returned.  This is the normal
+                        //   way out of prefix handling when the source actually contained
+                        //   the prefix.
+                        break;
+                    }
+                }
+                loadState(source, &prefixState, TRUE);
+                break;
+            }
+
+        case CONTRACTION_TAG: {
+            /* to ensure that the backwards and forwards iteration matches, we
+            take the current region of most possible match and pass it through
+            the forward iteration. this will ensure that the obstinate problem of
+            overlapping contractions will not occur.
+            */
+            schar = peekCodeUnit(source, 0);
+            constart = (UChar *)coll->image + getContractOffset(CE);
+            if (isAtStartPrevIterate(source)
+                /* commented away contraction end checks after adding the checks
+                in getPrevCE  */) {
+                    /* start of string or this is not the end of any contraction */
+                    CE = *(coll->contractionCEs +
+                        (constart - coll->contractionIndex));
+                    break;
+            }
+            strbuffer = buffer;
+            UCharOffset = strbuffer + (UCOL_MAX_BUFFER - 1);
+            *(UCharOffset --) = 0;
+            noChars = 0;
+            // have to swap thai characters
+            while (ucol_unsafeCP(schar, coll)) {
+                *(UCharOffset) = schar;
+                noChars++;
+                UCharOffset --;
+                schar = getPrevNormalizedChar(source, status);
+                goBackOne(source);
+                // TODO: when we exhaust the contraction buffer,
+                // it needs to get reallocated. The problem is
+                // that the size depends on the string which is
+                // not iterated over. However, since we're travelling
+                // backwards, we already had to set the iterator at
+                // the end - so we might as well know where we are?
+                if (UCharOffset + 1 == buffer) {
+                    /* we have exhausted the buffer */
+                    int32_t newsize = 0;
+                    if(source->pos) { // actually dealing with a position
+                        newsize = (int32_t)(source->pos - source->string + 1);
+                    } else { // iterator
+                        newsize = 4 * UCOL_MAX_BUFFER;
+                    }
+                    strbuffer = (UChar *)uprv_malloc(sizeof(UChar) *
+                        (newsize + UCOL_MAX_BUFFER));
+                    /* test for NULL */
+                    if (strbuffer == NULL) {
+                        *status = U_MEMORY_ALLOCATION_ERROR;
+                        return UCOL_NO_MORE_CES;
+                    }
+                    UCharOffset = strbuffer + newsize;
+                    uprv_memcpy(UCharOffset, buffer,
+                        UCOL_MAX_BUFFER * sizeof(UChar));
+                    UCharOffset --;
+                }
+                if ((source->pos && (source->pos == source->string ||
+                    ((source->flags & UCOL_ITER_INNORMBUF) &&
+                    *(source->pos - 1) == 0 && source->fcdPosition == NULL)))
+                    || (source->iterator && !source->iterator->hasPrevious(source->iterator))) {
+                        break;
+                }
+            }
+            /* adds the initial base character to the string */
+            *(UCharOffset) = schar;
+            noChars++;
+
+            int32_t offsetBias;
+
+            // **** doesn't work if using iterator ****
+            if (source->flags & UCOL_ITER_INNORMBUF) {
+                offsetBias = -1;
+            } else {
+                offsetBias = (int32_t)(source->pos - source->string);
+            }
+
+            /* a new collIterate is used to simplify things, since using the current
+            collIterate will mean that the forward and backwards iteration will
+            share and change the same buffers. we don't want to get into that. */
+            collIterate temp;
+            int32_t rawOffset;
+
+            IInit_collIterate(coll, UCharOffset, noChars, &temp, status);
+            if(U_FAILURE(*status)) {
+                return UCOL_NULLORDER;
+            }
+            temp.flags &= ~UCOL_ITER_NORM;
+            temp.flags |= source->flags & UCOL_FORCE_HAN_IMPLICIT;
+
+            rawOffset = (int32_t)(temp.pos - temp.string); // should always be zero?
+            CE = ucol_IGetNextCE(coll, &temp, status);
+
+            if (source->extendCEs) {
+                endCEBuffer = source->extendCEs + source->extendCEsSize;
+                CECount = (int32_t)((source->CEpos - source->extendCEs)/sizeof(uint32_t));
+            } else {
+                endCEBuffer = source->CEs + UCOL_EXPAND_CE_BUFFER_SIZE;
+                CECount = (int32_t)((source->CEpos - source->CEs)/sizeof(uint32_t));
+            }
+
+            while (CE != UCOL_NO_MORE_CES) {
+                *(source->CEpos ++) = CE;
+
+                if (offsetBias >= 0) {
+                    source->appendOffset(rawOffset + offsetBias, *status);
+                }
+
+                CECount++;
+                if (source->CEpos == endCEBuffer) {
+                    /* ran out of CE space, reallocate to new buffer.
+                    If reallocation fails, reset pointers and bail out,
+                    there's no guarantee of the right character position after
+                    this bail*/
+                    if (!increaseCEsCapacity(source)) {
+                        *status = U_MEMORY_ALLOCATION_ERROR;
+                        break;
+                    }
+
+                    endCEBuffer = source->extendCEs + source->extendCEsSize;
+                }
+
+                if ((temp.flags & UCOL_ITER_INNORMBUF) != 0) {
+                    rawOffset = (int32_t)(temp.fcdPosition - temp.string);
+                } else {
+                    rawOffset = (int32_t)(temp.pos - temp.string);
+                }
+
+                CE = ucol_IGetNextCE(coll, &temp, status);
+            }
+
+            if (strbuffer != buffer) {
+                uprv_free(strbuffer);
+            }
+            if (U_FAILURE(*status)) {
+                return (uint32_t)UCOL_NULLORDER;
+            }
+
+            if (source->offsetRepeatValue != 0) {
+                if (CECount > noChars) {
+                    source->offsetRepeatCount += temp.offsetRepeatCount;
+                } else {
+                    // **** does this really skip the right offsets? ****
+                    source->offsetReturn -= (noChars - CECount);
+                }
+            }
+
+            if (offsetBias >= 0) {
+                source->offsetReturn = source->offsetStore - 1;
+                if (source->offsetReturn == source->offsetBuffer) {
+                    source->offsetStore = source->offsetBuffer;
+                }
+            }
+
+            source->toReturn = source->CEpos - 1;
+            if (source->toReturn == source->CEs) {
+                source->CEpos = source->CEs;
+            }
+
+            return *(source->toReturn);
+        }
+        case LONG_PRIMARY_TAG:
+            {
+                *(source->CEpos++) = ((CE & 0xFFFF00) << 8) | (UCOL_BYTE_COMMON << 8) | UCOL_BYTE_COMMON;
+                *(source->CEpos++) = ((CE & 0xFF)<<24)|UCOL_CONTINUATION_MARKER;
+                source->toReturn = source->CEpos - 1;
+
+                if (source->flags & UCOL_ITER_INNORMBUF) {
+                    source->offsetRepeatCount = 1;
+                } else {
+                    int32_t firstOffset = (int32_t)(source->pos - source->string);
+
+                    source->appendOffset(firstOffset, *status);
+                    source->appendOffset(firstOffset + 1, *status);
+
+                    source->offsetReturn = source->offsetStore - 1;
+                    *(source->offsetBuffer) = firstOffset;
+                    if (source->offsetReturn == source->offsetBuffer) {
+                        source->offsetStore = source->offsetBuffer;
+                    }
+                }
+
+
+                return *(source->toReturn);
+            }
+
+        case EXPANSION_TAG: /* this tag always returns */
+            {
+            /*
+            This should handle expansion.
+            NOTE: we can encounter both continuations and expansions in an expansion!
+            I have to decide where continuations are going to be dealt with
+            */
+            int32_t firstOffset = (int32_t)(source->pos - source->string);
+
+            // **** doesn't work if using iterator ****
+            if (source->offsetReturn != NULL) {
+                if (! (source->flags & UCOL_ITER_INNORMBUF) && source->offsetReturn == source->offsetBuffer) {
+                    source->offsetStore = source->offsetBuffer;
+                }else {
+                  firstOffset = -1;
+                }
+            }
+
+            /* find the offset to expansion table */
+            CEOffset = (uint32_t *)coll->image + getExpansionOffset(CE);
+            size     = getExpansionCount(CE);
+            if (size != 0) {
+                /*
+                if there are less than 16 elements in expansion, we don't terminate
+                */
+                uint32_t count;
+
+                for (count = 0; count < size; count++) {
+                    *(source->CEpos ++) = *CEOffset++;
+
+                    if (firstOffset >= 0) {
+                        source->appendOffset(firstOffset + 1, *status);
+                    }
+                }
+            } else {
+                /* else, we do */
+                while (*CEOffset != 0) {
+                    *(source->CEpos ++) = *CEOffset ++;
+
+                    if (firstOffset >= 0) {
+                        source->appendOffset(firstOffset + 1, *status);
+                    }
+                }
+            }
+
+            if (firstOffset >= 0) {
+                source->offsetReturn = source->offsetStore - 1;
+                *(source->offsetBuffer) = firstOffset;
+                if (source->offsetReturn == source->offsetBuffer) {
+                    source->offsetStore = source->offsetBuffer;
+                }
+            } else {
+                source->offsetRepeatCount += size - 1;
+            }
+
+            source->toReturn = source->CEpos - 1;
+            // in case of one element expansion, we
+            // want to immediately return CEpos
+            if(source->toReturn == source->CEs) {
+                source->CEpos = source->CEs;
+            }
+
+            return *(source->toReturn);
+            }
+
+        case DIGIT_TAG:
+            {
+                /*
+                We do a check to see if we want to collate digits as numbers; if so we generate
+                a custom collation key. Otherwise we pull out the value stored in the expansion table.
+                */
+                uint32_t i;    /* general counter */
+
+                if (source->coll->numericCollation == UCOL_ON){
+                    uint32_t digIndx = 0;
+                    uint32_t endIndex = 0;
+                    uint32_t leadingZeroIndex = 0;
+                    uint32_t trailingZeroCount = 0;
+
+                    uint8_t collateVal = 0;
+
+                    UBool nonZeroValReached = FALSE;
+
+                    uint8_t numTempBuf[UCOL_MAX_DIGITS_FOR_NUMBER/2 + 2]; // I just need a temporary place to store my generated CEs.
+                    /*
+                    We parse the source string until we hit a char that's NOT a digit.
+                    Use this u_charDigitValue. This might be slow because we have to
+                    handle surrogates...
+                    */
+                    /*
+                    We need to break up the digit string into collection elements of UCOL_MAX_DIGITS_FOR_NUMBER or less,
+                    with any chunks smaller than that being on the right end of the digit string - i.e. the first collation
+                    element we process when going backward. To determine how long that chunk might be, we may need to make
+                    two passes through the loop that collects digits - one to see how long the string is (and how much is
+                    leading zeros) to determine the length of that right-hand chunk, and a second (if the whole string has
+                    more than UCOL_MAX_DIGITS_FOR_NUMBER non-leading-zero digits) to actually process that collation
+                    element chunk after resetting the state to the initialState at the right side of the digit string.
+                    */
+                    uint32_t ceLimit = 0;
+                    UChar initial_ch = ch;
+                    collIterateState initialState = {0,0,0,0,0,0,0,0,0};
+                    backupState(source, &initialState);
+
+                    for(;;) {
+                        collIterateState state = {0,0,0,0,0,0,0,0,0};
+                        UChar32 char32 = 0;
+                        int32_t digVal = 0;
+
+                        if (U16_IS_TRAIL (ch)) {
+                            if (!collIter_bos(source)){
+                                UChar lead = getPrevNormalizedChar(source, status);
+                                if(U16_IS_LEAD(lead)) {
+                                    char32 = U16_GET_SUPPLEMENTARY(lead,ch);
+                                    goBackOne(source);
+                                } else {
+                                    char32 = ch;
+                                }
+                            } else {
+                                char32 = ch;
+                            }
+                        } else {
+                            char32 = ch;
+                        }
+                        digVal = u_charDigitValue(char32);
+
+                        for(;;) {
+                            // Make sure we have enough space. No longer needed;
+                            // at this point the largest value of digIndx when we need to save data in numTempBuf
+                            // is UCOL_MAX_DIGITS_FOR_NUMBER-1 (digIndx is post-incremented) so we just ensure
+                            // that numTempBuf is big enough (UCOL_MAX_DIGITS_FOR_NUMBER/2 + 2).
+
+                            // Skip over trailing zeroes, and keep a count of them.
+                            if (digVal != 0)
+                                nonZeroValReached = TRUE;
+
+                            if (nonZeroValReached) {
+                                /*
+                                We parse the digit string into base 100 numbers (this fits into a byte).
+                                We only add to the buffer in twos, thus if we are parsing an odd character,
+                                that serves as the 'tens' digit while the if we are parsing an even one, that
+                                is the 'ones' digit. We dumped the parsed base 100 value (collateVal) into
+                                a buffer. We multiply each collateVal by 2 (to give us room) and add 5 (to avoid
+                                overlapping magic CE byte values). The last byte we subtract 1 to ensure it is less
+                                than all the other bytes.
+
+                                Since we're doing in this reverse we want to put the first digit encountered into the
+                                ones place and the second digit encountered into the tens place.
+                                */
+
+                                if ((digIndx + trailingZeroCount) % 2 == 1) {
+                                    // High-order digit case (tens place)
+                                    collateVal += (uint8_t)(digVal * 10);
+
+                                    // We cannot set leadingZeroIndex unless it has been set for the
+                                    // low-order digit. Therefore, all we can do for the high-order
+                                    // digit is turn it off, never on.
+                                    // The only time we will have a high digit without a low is for
+                                    // the very first non-zero digit, so no zero check is necessary.
+                                    if (collateVal != 0)
+                                        leadingZeroIndex = 0;
+
+                                    // The first pass through, digIndx may exceed the limit, but in that case
+                                    // we no longer care about numTempBuf contents since they will be discarded
+                                    if ( digIndx < UCOL_MAX_DIGITS_FOR_NUMBER ) {
+                                        numTempBuf[(digIndx/2) + 2] = collateVal*2 + 6;
+                                    }
+                                    collateVal = 0;
+                                } else {
+                                    // Low-order digit case (ones place)
+                                    collateVal = (uint8_t)digVal;
+
+                                    // Check for leading zeroes.
+                                    if (collateVal == 0) {
+                                        if (!leadingZeroIndex)
+                                            leadingZeroIndex = (digIndx/2) + 2;
+                                    } else
+                                        leadingZeroIndex = 0;
+
+                                    // No need to write to buffer; the case of a last odd digit
+                                    // is handled below.
+                                }
+                                ++digIndx;
+                            } else
+                                ++trailingZeroCount;
+
+                            if (!collIter_bos(source)) {
+                                ch = getPrevNormalizedChar(source, status);
+                                //goBackOne(source);
+                                if (U16_IS_TRAIL(ch)) {
+                                    backupState(source, &state);
+                                    if (!collIter_bos(source)) {
+                                        goBackOne(source);
+                                        UChar lead = getPrevNormalizedChar(source, status);
+
+                                        if(U16_IS_LEAD(lead)) {
+                                            char32 = U16_GET_SUPPLEMENTARY(lead,ch);
+                                        } else {
+                                            loadState(source, &state, FALSE);
+                                            char32 = ch;
+                                        }
+                                    }
+                                } else
+                                    char32 = ch;
+
+                                if ((digVal = u_charDigitValue(char32)) == -1 || (ceLimit > 0 && (digIndx + trailingZeroCount) >= ceLimit)) {
+                                    if (char32 > 0xFFFF) {// For surrogates.
+                                        loadState(source, &state, FALSE);
+                                    }
+                                    // Don't need to "reverse" the goBackOne call,
+                                    // as this points to the next position to process..
+                                    //if (char32 > 0xFFFF) // For surrogates.
+                                    //getNextNormalizedChar(source);
+                                    break;
+                                }
+
+                                goBackOne(source);
+                            }else
+                                break;
+                        }
+
+                        if (digIndx + trailingZeroCount <= UCOL_MAX_DIGITS_FOR_NUMBER) {
+                            // our collation element is not too big, go ahead and finish with it
+                            break;
+                        }
+                        // our digit string is too long for a collation element;
+                        // set the limit for it, reset the state and begin again
+                        ceLimit = (digIndx + trailingZeroCount) % UCOL_MAX_DIGITS_FOR_NUMBER;
+                        if ( ceLimit == 0 ) {
+                            ceLimit = UCOL_MAX_DIGITS_FOR_NUMBER;
+                        }
+                        ch = initial_ch;
+                        loadState(source, &initialState, FALSE);
+                        digIndx = endIndex = leadingZeroIndex = trailingZeroCount = 0;
+                        collateVal = 0;
+                        nonZeroValReached = FALSE;
+                    }
+
+                    if (! nonZeroValReached) {
+                        digIndx = 2;
+                        trailingZeroCount = 0;
+                        numTempBuf[2] = 6;
+                    }
+
+                    if ((digIndx + trailingZeroCount) % 2 != 0) {
+                        numTempBuf[((digIndx)/2) + 2] = collateVal*2 + 6;
+                        digIndx += 1;       // The implicit leading zero
+                    }
+                    if (trailingZeroCount % 2 != 0) {
+                        // We had to consume one trailing zero for the low digit
+                        // of the least significant byte
+                        digIndx += 1;       // The trailing zero not in the exponent
+                        trailingZeroCount -= 1;
+                    }
+
+                    endIndex = leadingZeroIndex ? leadingZeroIndex : ((digIndx/2) + 2) ;
+
+                    // Subtract one off of the last byte. Really the first byte here, but it's reversed...
+                    numTempBuf[2] -= 1;
+
+                    /*
+                    We want to skip over the first two slots in the buffer. The first slot
+                    is reserved for the header byte UCOL_CODAN_PLACEHOLDER. The second slot is for the
+                    sign/exponent byte: 0x80 + (decimalPos/2) & 7f.
+                    The exponent must be adjusted by the number of leading zeroes, and the number of
+                    trailing zeroes.
+                    */
+                    numTempBuf[0] = UCOL_CODAN_PLACEHOLDER;
+                    uint32_t exponent = (digIndx+trailingZeroCount)/2;
+                    if (leadingZeroIndex)
+                        exponent -= ((digIndx/2) + 2 - leadingZeroIndex);
+                    numTempBuf[1] = (uint8_t)(0x80 + (exponent & 0x7F));
+
+                    // Now transfer the collation key to our collIterate struct.
+                    // The total size for our collation key is half of endIndex, rounded up.
+                    int32_t size = (endIndex+1)/2;
+                    if(!ensureCEsCapacity(source, size)) {
+                        return UCOL_NULLORDER;
+                    }
+                    *(source->CEpos++) = (((numTempBuf[0] << 8) | numTempBuf[1]) << UCOL_PRIMARYORDERSHIFT) | //Primary weight
+                        (UCOL_BYTE_COMMON << UCOL_SECONDARYORDERSHIFT) | // Secondary weight
+                        UCOL_BYTE_COMMON; // Tertiary weight.
+                    i = endIndex - 1; // Reset the index into the buffer.
+                    while(i >= 2) {
+                        uint32_t primWeight = numTempBuf[i--] << 8;
+                        if ( i >= 2)
+                            primWeight |= numTempBuf[i--];
+                        *(source->CEpos++) = (primWeight << UCOL_PRIMARYORDERSHIFT) | UCOL_CONTINUATION_MARKER;
+                    }
+
+                    source->toReturn = source->CEpos -1;
+                    return *(source->toReturn);
+                } else {
+                    CEOffset = (uint32_t *)coll->image + getExpansionOffset(CE);
+                    CE = *(CEOffset++);
+                    break;
+                }
+            }
+
+        case HANGUL_SYLLABLE_TAG: /* AC00-D7AF*/
+            {
+                static const uint32_t
+                    SBase = 0xAC00, LBase = 0x1100, VBase = 0x1161, TBase = 0x11A7;
+                //const uint32_t LCount = 19;
+                static const uint32_t VCount = 21;
+                static const uint32_t TCount = 28;
+                //const uint32_t NCount = VCount * TCount;   /* 588 */
+                //const uint32_t SCount = LCount * NCount;   /* 11172 */
+
+                uint32_t L = ch - SBase;
+                /*
+                divide into pieces.
+                we do it in this order since some compilers can do % and / in one
+                operation
+                */
+                uint32_t T = L % TCount;
+                L /= TCount;
+                uint32_t V = L % VCount;
+                L /= VCount;
+
+                /* offset them */
+                L += LBase;
+                V += VBase;
+                T += TBase;
+
+                int32_t firstOffset = (int32_t)(source->pos - source->string);
+                source->appendOffset(firstOffset, *status);
+
+                /*
+                 * return the first CE, but first put the rest into the expansion buffer
+                 */
+                if (!source->coll->image->jamoSpecial) {
+                    *(source->CEpos++) = UTRIE_GET32_FROM_LEAD(&coll->mapping, L);
+                    *(source->CEpos++) = UTRIE_GET32_FROM_LEAD(&coll->mapping, V);
+                    source->appendOffset(firstOffset + 1, *status);
+
+                    if (T != TBase) {
+                        *(source->CEpos++) = UTRIE_GET32_FROM_LEAD(&coll->mapping, T);
+                        source->appendOffset(firstOffset + 1, *status);
+                    }
+
+                    source->toReturn = source->CEpos - 1;
+
+                    source->offsetReturn = source->offsetStore - 1;
+                    if (source->offsetReturn == source->offsetBuffer) {
+                        source->offsetStore = source->offsetBuffer;
+                    }
+
+                    return *(source->toReturn);
+                } else {
+                    // Since Hanguls pass the FCD check, it is
+                    // guaranteed that we won't be in
+                    // the normalization buffer if something like this happens
+
+                    // Move Jamos into normalization buffer
+                    UChar *tempbuffer = source->writableBuffer.getBuffer(5);
+                    int32_t tempbufferLength, jamoOffset;
+                    tempbuffer[0] = 0;
+                    tempbuffer[1] = (UChar)L;
+                    tempbuffer[2] = (UChar)V;
+                    if (T != TBase) {
+                        tempbuffer[3] = (UChar)T;
+                        tempbufferLength = 4;
+                    } else {
+                        tempbufferLength = 3;
+                    }
+                    source->writableBuffer.releaseBuffer(tempbufferLength);
+
+                    // Indicate where to continue in main input string after exhausting the writableBuffer
+                    if (source->pos  == source->string) {
+                        jamoOffset = 0;
+                        source->fcdPosition = NULL;
+                    } else {
+                        jamoOffset = source->pos - source->string;
+                        source->fcdPosition       = source->pos-1;
+                    }
+                    
+                    // Append offsets for the additional chars
+                    // (not the 0, and not the L whose offsets match the original Hangul)
+                    int32_t jamoRemaining = tempbufferLength - 2;
+                    jamoOffset++; // appended offsets should match end of original Hangul
+                    while (jamoRemaining-- > 0) {
+                        source->appendOffset(jamoOffset, *status);
+                    }
+
+                    source->offsetRepeatValue = jamoOffset;
+
+                    source->offsetReturn = source->offsetStore - 1;
+                    if (source->offsetReturn == source->offsetBuffer) {
+                        source->offsetStore = source->offsetBuffer;
+                    }
+
+                    source->pos               = source->writableBuffer.getTerminatedBuffer() + tempbufferLength;
+                    source->origFlags         = source->flags;
+                    source->flags            |= UCOL_ITER_INNORMBUF;
+                    source->flags            &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN);
+
+                    return(UCOL_IGNORABLE);
+                }
+            }
+
+        case IMPLICIT_TAG:        /* everything that is not defined otherwise */
+            return getPrevImplicit(ch, source);
+
+            // TODO: Remove CJK implicits as they are handled by the getImplicitPrimary function
+        case CJK_IMPLICIT_TAG:    /* 0x3400-0x4DB5, 0x4E00-0x9FA5, 0xF900-0xFA2D*/
+            return getPrevImplicit(ch, source);
+
+        case SURROGATE_TAG:  /* This is a surrogate pair */
+            /* essentially an engaged lead surrogate. */
+            /* if you have encountered it here, it means that a */
+            /* broken sequence was encountered and this is an error */
+            return UCOL_NOT_FOUND;
+
+        case LEAD_SURROGATE_TAG:  /* D800-DBFF*/
+            return UCOL_NOT_FOUND; /* broken surrogate sequence */
+
+        case TRAIL_SURROGATE_TAG: /* DC00-DFFF*/
+            {
+                UChar32 cp = 0;
+                UChar  prevChar;
+                const UChar *prev;
+                if (isAtStartPrevIterate(source)) {
+                    /* we are at the start of the string, wrong place to be at */
+                    return UCOL_NOT_FOUND;
+                }
+                if (source->pos != source->writableBuffer.getBuffer()) {
+                    prev     = source->pos - 1;
+                } else {
+                    prev     = source->fcdPosition;
+                }
+                prevChar = *prev;
+
+                /* Handles Han and Supplementary characters here.*/
+                if (U16_IS_LEAD(prevChar)) {
+                    cp = ((((uint32_t)prevChar)<<10UL)+(ch)-(((uint32_t)0xd800<<10UL)+0xdc00-0x10000));
+                    source->pos = prev;
+                } else {
+                    return UCOL_NOT_FOUND; /* like unassigned */
+                }
+
+                return getPrevImplicit(cp, source);
+            }
+
+            /* UCA is filled with these. Tailorings are NOT_FOUND */
+            /* not yet implemented */
+        case CHARSET_TAG:  /* this tag always returns */
+            /* probably after 1.8 */
+            return UCOL_NOT_FOUND;
+
+        default:           /* this tag always returns */
+            *status = U_INTERNAL_PROGRAM_ERROR;
+            CE=0;
+            break;
+        }
+
+        if (CE <= UCOL_NOT_FOUND) {
+            break;
+        }
+    }
+
+    return CE;
+}
+
+/* This should really be a macro        */
+/* 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/source/i18n/ucol_bld.cpp b/source/i18n/ucol_bld.cpp
new file mode 100644
index 0000000..e6c5048
--- /dev/null
+++ b/source/i18n/ucol_bld.cpp
@@ -0,0 +1,1417 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 2001-2011, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  ucol_bld.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created 02/22/2001
+*   created by: Vladimir Weinstein
+*
+* This module builds a collator based on the rule set.
+*
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/ucoleitr.h"
+#include "unicode/udata.h"
+#include "unicode/uchar.h"
+#include "unicode/uniset.h"
+#include "unicode/uscript.h"
+#include "unicode/ustring.h"
+#include "normalizer2impl.h"
+#include "ucol_bld.h"
+#include "ucol_elm.h"
+#include "ucol_cnt.h"
+#include "ucln_in.h"
+#include "umutex.h"
+#include "cmemory.h"
+#include "cstring.h"
+
+static const InverseUCATableHeader* _staticInvUCA = NULL;
+static UDataMemory* invUCA_DATA_MEM = NULL;
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+isAcceptableInvUCA(void * /*context*/,
+                   const char * /*type*/, const char * /*name*/,
+                   const UDataInfo *pInfo)
+{
+    /* context, type & name are intentionally not used */
+    if( pInfo->size>=20 &&
+        pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
+        pInfo->charsetFamily==U_CHARSET_FAMILY &&
+        pInfo->dataFormat[0]==INVUCA_DATA_FORMAT_0 &&   /* dataFormat="InvC" */
+        pInfo->dataFormat[1]==INVUCA_DATA_FORMAT_1 &&
+        pInfo->dataFormat[2]==INVUCA_DATA_FORMAT_2 &&
+        pInfo->dataFormat[3]==INVUCA_DATA_FORMAT_3 &&
+        pInfo->formatVersion[0]==INVUCA_FORMAT_VERSION_0 &&
+        pInfo->formatVersion[1]>=INVUCA_FORMAT_VERSION_1 //&&
+        //pInfo->formatVersion[1]==INVUCA_FORMAT_VERSION_1 &&
+        //pInfo->formatVersion[2]==INVUCA_FORMAT_VERSION_2 &&
+        //pInfo->formatVersion[3]==INVUCA_FORMAT_VERSION_3 &&
+        )
+    {
+        UVersionInfo UCDVersion;
+        u_getUnicodeVersion(UCDVersion);
+        return (pInfo->dataVersion[0]==UCDVersion[0] &&
+            pInfo->dataVersion[1]==UCDVersion[1]);
+            //pInfo->dataVersion[1]==invUcaDataInfo.dataVersion[1] &&
+            //pInfo->dataVersion[2]==invUcaDataInfo.dataVersion[2] &&
+            //pInfo->dataVersion[3]==invUcaDataInfo.dataVersion[3]) {
+    } else {
+        return FALSE;
+    }
+}
+U_CDECL_END
+
+/*
+* Takes two CEs (lead and continuation) and
+* compares them as CEs should be compared:
+* primary vs. primary, secondary vs. secondary
+* tertiary vs. tertiary
+*/
+static int32_t compareCEs(uint32_t source0, uint32_t source1, uint32_t target0, uint32_t target1) {
+    uint32_t s1 = source0, s2, t1 = target0, t2;
+    if(isContinuation(source1)) {
+        s2 = source1;
+    } else {
+        s2 = 0;
+    }
+    if(isContinuation(target1)) {
+        t2 = target1;
+    } else {
+        t2 = 0;
+    }
+
+    uint32_t s = 0, t = 0;
+    if(s1 == t1 && s2 == t2) {
+        return 0;
+    }
+    s = (s1 & 0xFFFF0000)|((s2 & 0xFFFF0000)>>16);
+    t = (t1 & 0xFFFF0000)|((t2 & 0xFFFF0000)>>16);
+    if(s < t) {
+        return -1;
+    } else if(s > t) {
+        return 1;
+    } else {
+        s = (s1 & 0x0000FF00) | (s2 & 0x0000FF00)>>8;
+        t = (t1 & 0x0000FF00) | (t2 & 0x0000FF00)>>8;
+        if(s < t) {
+            return -1;
+        } else if(s > t) {
+            return 1;
+        } else {
+            s = (s1 & 0x000000FF)<<8 | (s2 & 0x000000FF);
+            t = (t1 & 0x000000FF)<<8 | (t2 & 0x000000FF);
+            if(s < t) {
+                return -1;
+            } else {
+                return 1;
+            }
+        }
+    }
+}
+
+static
+int32_t ucol_inv_findCE(const UColTokenParser *src, uint32_t CE, uint32_t SecondCE) {
+    uint32_t bottom = 0, top = src->invUCA->tableSize;
+    uint32_t i = 0;
+    uint32_t first = 0, second = 0;
+    uint32_t *CETable = (uint32_t *)((uint8_t *)src->invUCA+src->invUCA->table);
+    int32_t res = 0;
+
+    while(bottom < top-1) {
+        i = (top+bottom)/2;
+        first = *(CETable+3*i);
+        second = *(CETable+3*i+1);
+        res = compareCEs(first, second, CE, SecondCE);
+        if(res > 0) {
+            top = i;
+        } else if(res < 0) {
+            bottom = i;
+        } else {
+            break;
+        }
+    }
+
+    /* weiv:                                                  */
+    /* in searching for elements, I have removed the failure  */
+    /* The reason for this is that the builder does not rely  */
+    /* on search mechanism telling it that it didn't find an  */
+    /* element. However, indirect positioning relies on being */
+    /* able to find the elements around any CE, even if it is */
+    /* not defined in the UCA. */
+    return i;
+    /*
+    if((first == CE && second == SecondCE)) {
+    return i;
+    } else {
+    return -1;
+    }
+    */
+}
+
+static const uint32_t strengthMask[UCOL_CE_STRENGTH_LIMIT] = {
+    0xFFFF0000,
+    0xFFFFFF00,
+    0xFFFFFFFF
+};
+
+U_CAPI int32_t U_EXPORT2 ucol_inv_getNextCE(const UColTokenParser *src,
+                                            uint32_t CE, uint32_t contCE,
+                                            uint32_t *nextCE, uint32_t *nextContCE,
+                                            uint32_t strength)
+{
+    uint32_t *CETable = (uint32_t *)((uint8_t *)src->invUCA+src->invUCA->table);
+    int32_t iCE;
+
+    iCE = ucol_inv_findCE(src, CE, contCE);
+
+    if(iCE<0) {
+        *nextCE = UCOL_NOT_FOUND;
+        return -1;
+    }
+
+    CE &= strengthMask[strength];
+    contCE &= strengthMask[strength];
+
+    *nextCE = CE;
+    *nextContCE = contCE;
+
+    while((*nextCE  & strengthMask[strength]) == CE
+        && (*nextContCE  & strengthMask[strength]) == contCE)
+    {
+        *nextCE = (*(CETable+3*(++iCE)));
+        *nextContCE = (*(CETable+3*(iCE)+1));
+    }
+
+    return iCE;
+}
+
+U_CFUNC int32_t U_EXPORT2 ucol_inv_getPrevCE(const UColTokenParser *src,
+                                            uint32_t CE, uint32_t contCE,
+                                            uint32_t *prevCE, uint32_t *prevContCE,
+                                            uint32_t strength)
+{
+    uint32_t *CETable = (uint32_t *)((uint8_t *)src->invUCA+src->invUCA->table);
+    int32_t iCE;
+
+    iCE = ucol_inv_findCE(src, CE, contCE);
+
+    if(iCE<0) {
+        *prevCE = UCOL_NOT_FOUND;
+        return -1;
+    }
+
+    CE &= strengthMask[strength];
+    contCE &= strengthMask[strength];
+
+    *prevCE = CE;
+    *prevContCE = contCE;
+
+    while((*prevCE  & strengthMask[strength]) == CE
+        && (*prevContCE  & strengthMask[strength])== contCE
+        && iCE > 0) /* this condition should prevent falling off the edge of the world */
+    {
+        /* here, we end up in a singularity - zero */
+        *prevCE = (*(CETable+3*(--iCE)));
+        *prevContCE = (*(CETable+3*(iCE)+1));
+    }
+
+    return iCE;
+}
+
+U_CFUNC uint32_t U_EXPORT2 ucol_getCEStrengthDifference(uint32_t CE, uint32_t contCE,
+                                                       uint32_t prevCE, uint32_t prevContCE)
+{
+    if(prevCE == CE && prevContCE == contCE) {
+        return UCOL_IDENTICAL;
+    }
+    if((prevCE & strengthMask[UCOL_PRIMARY]) != (CE & strengthMask[UCOL_PRIMARY])
+        || (prevContCE & strengthMask[UCOL_PRIMARY]) != (contCE & strengthMask[UCOL_PRIMARY]))
+    {
+        return UCOL_PRIMARY;
+    }
+    if((prevCE & strengthMask[UCOL_SECONDARY]) != (CE & strengthMask[UCOL_SECONDARY])
+        || (prevContCE & strengthMask[UCOL_SECONDARY]) != (contCE & strengthMask[UCOL_SECONDARY]))
+    {
+        return UCOL_SECONDARY;
+    }
+    return UCOL_TERTIARY;
+}
+
+
+/*static
+inline int32_t ucol_inv_getPrevious(UColTokenParser *src, UColTokListHeader *lh, uint32_t strength) {
+
+    uint32_t CE = lh->baseCE;
+    uint32_t SecondCE = lh->baseContCE;
+
+    uint32_t *CETable = (uint32_t *)((uint8_t *)src->invUCA+src->invUCA->table);
+    uint32_t previousCE, previousContCE;
+    int32_t iCE;
+
+    iCE = ucol_inv_findCE(src, CE, SecondCE);
+
+    if(iCE<0) {
+        return -1;
+    }
+
+    CE &= strengthMask[strength];
+    SecondCE &= strengthMask[strength];
+
+    previousCE = CE;
+    previousContCE = SecondCE;
+
+    while((previousCE  & strengthMask[strength]) == CE && (previousContCE  & strengthMask[strength])== SecondCE) {
+        previousCE = (*(CETable+3*(--iCE)));
+        previousContCE = (*(CETable+3*(iCE)+1));
+    }
+    lh->previousCE = previousCE;
+    lh->previousContCE = previousContCE;
+
+    return iCE;
+}*/
+
+static
+inline int32_t ucol_inv_getNext(UColTokenParser *src, UColTokListHeader *lh, uint32_t strength) {
+    uint32_t CE = lh->baseCE;
+    uint32_t SecondCE = lh->baseContCE;
+
+    uint32_t *CETable = (uint32_t *)((uint8_t *)src->invUCA+src->invUCA->table);
+    uint32_t nextCE, nextContCE;
+    int32_t iCE;
+
+    iCE = ucol_inv_findCE(src, CE, SecondCE);
+
+    if(iCE<0) {
+        return -1;
+    }
+
+    CE &= strengthMask[strength];
+    SecondCE &= strengthMask[strength];
+
+    nextCE = CE;
+    nextContCE = SecondCE;
+
+    while((nextCE  & strengthMask[strength]) == CE
+        && (nextContCE  & strengthMask[strength]) == SecondCE)
+    {
+        nextCE = (*(CETable+3*(++iCE)));
+        nextContCE = (*(CETable+3*(iCE)+1));
+    }
+
+    lh->nextCE = nextCE;
+    lh->nextContCE = nextContCE;
+
+    return iCE;
+}
+
+static void ucol_inv_getGapPositions(UColTokenParser *src, UColTokListHeader *lh, UErrorCode *status) {
+    /* reset all the gaps */
+    int32_t i = 0;
+    uint32_t *CETable = (uint32_t *)((uint8_t *)src->invUCA+src->invUCA->table);
+    uint32_t st = 0;
+    uint32_t t1, t2;
+    int32_t pos;
+
+    UColToken *tok = lh->first;
+    uint32_t tokStrength = tok->strength;
+
+    for(i = 0; i<3; i++) {
+        lh->gapsHi[3*i] = 0;
+        lh->gapsHi[3*i+1] = 0;
+        lh->gapsHi[3*i+2] = 0;
+        lh->gapsLo[3*i] = 0;
+        lh->gapsLo[3*i+1] = 0;
+        lh->gapsLo[3*i+2] = 0;
+        lh->numStr[i] = 0;
+        lh->fStrToken[i] = NULL;
+        lh->lStrToken[i] = NULL;
+        lh->pos[i] = -1;
+    }
+
+    UCAConstants *consts = (UCAConstants *)((uint8_t *)src->UCA->image + src->UCA->image->UCAConsts);
+
+    if((lh->baseCE & 0xFF000000)>= (consts->UCA_PRIMARY_IMPLICIT_MIN<<24) && (lh->baseCE & 0xFF000000) <= (consts->UCA_PRIMARY_IMPLICIT_MAX<<24) ) { /* implicits - */
+        //if(lh->baseCE >= PRIMARY_IMPLICIT_MIN && lh->baseCE < PRIMARY_IMPLICIT_MAX ) { /* implicits - */
+        lh->pos[0] = 0;
+        t1 = lh->baseCE;
+        t2 = lh->baseContCE & UCOL_REMOVE_CONTINUATION;
+        lh->gapsLo[0] = (t1 & UCOL_PRIMARYMASK) | (t2 & UCOL_PRIMARYMASK) >> 16;
+        lh->gapsLo[1] = (t1 & UCOL_SECONDARYMASK) << 16 | (t2 & UCOL_SECONDARYMASK) << 8;
+        lh->gapsLo[2] = (UCOL_TERTIARYORDER(t1)) << 24 | (UCOL_TERTIARYORDER(t2)) << 16;
+        uint32_t primaryCE = (t1 & UCOL_PRIMARYMASK) | ((t2 & UCOL_PRIMARYMASK) >> 16);
+        primaryCE = uprv_uca_getImplicitFromRaw(uprv_uca_getRawFromImplicit(primaryCE)+1);
+
+        t1 = (primaryCE & UCOL_PRIMARYMASK) | 0x0505;
+        t2 = (primaryCE << 16) & UCOL_PRIMARYMASK; // | UCOL_CONTINUATION_MARKER;
+
+        lh->gapsHi[0] = (t1 & UCOL_PRIMARYMASK) | (t2 & UCOL_PRIMARYMASK) >> 16;
+        lh->gapsHi[1] = (t1 & UCOL_SECONDARYMASK) << 16 | (t2 & UCOL_SECONDARYMASK) << 8;
+        lh->gapsHi[2] = (UCOL_TERTIARYORDER(t1)) << 24 | (UCOL_TERTIARYORDER(t2)) << 16;
+    } else if(lh->indirect == TRUE && lh->nextCE != 0) {
+        //} else if(lh->baseCE == UCOL_RESET_TOP_VALUE && lh->baseContCE == 0) {
+        lh->pos[0] = 0;
+        t1 = lh->baseCE;
+        t2 = lh->baseContCE&UCOL_REMOVE_CONTINUATION;
+        lh->gapsLo[0] = (t1 & UCOL_PRIMARYMASK) | (t2 & UCOL_PRIMARYMASK) >> 16;
+        lh->gapsLo[1] = (t1 & UCOL_SECONDARYMASK) << 16 | (t2 & UCOL_SECONDARYMASK) << 8;
+        lh->gapsLo[2] = (UCOL_TERTIARYORDER(t1)) << 24 | (UCOL_TERTIARYORDER(t2)) << 16;
+        t1 = lh->nextCE;
+        t2 = lh->nextContCE&UCOL_REMOVE_CONTINUATION;
+        lh->gapsHi[0] = (t1 & UCOL_PRIMARYMASK) | (t2 & UCOL_PRIMARYMASK) >> 16;
+        lh->gapsHi[1] = (t1 & UCOL_SECONDARYMASK) << 16 | (t2 & UCOL_SECONDARYMASK) << 8;
+        lh->gapsHi[2] = (UCOL_TERTIARYORDER(t1)) << 24 | (UCOL_TERTIARYORDER(t2)) << 16;
+    } else {
+        for(;;) {
+            if(tokStrength < UCOL_CE_STRENGTH_LIMIT) {
+                if((lh->pos[tokStrength] = ucol_inv_getNext(src, lh, tokStrength)) >= 0) {
+                    lh->fStrToken[tokStrength] = tok;
+                } else { /* The CE must be implicit, since it's not in the table */
+                    /* Error */
+                    *status = U_INTERNAL_PROGRAM_ERROR;
+                }
+            }
+
+            while(tok != NULL && tok->strength >= tokStrength) {
+                if(tokStrength < UCOL_CE_STRENGTH_LIMIT) {
+                    lh->lStrToken[tokStrength] = tok;
+                }
+                tok = tok->next;
+            }
+            if(tokStrength < UCOL_CE_STRENGTH_LIMIT-1) {
+                /* check if previous interval is the same and merge the intervals if it is so */
+                if(lh->pos[tokStrength] == lh->pos[tokStrength+1]) {
+                    lh->fStrToken[tokStrength] = lh->fStrToken[tokStrength+1];
+                    lh->fStrToken[tokStrength+1] = NULL;
+                    lh->lStrToken[tokStrength+1] = NULL;
+                    lh->pos[tokStrength+1] = -1;
+                }
+            }
+            if(tok != NULL) {
+                tokStrength = tok->strength;
+            } else {
+                break;
+            }
+        }
+        for(st = 0; st < 3; st++) {
+            if((pos = lh->pos[st]) >= 0) {
+                t1 = *(CETable+3*(pos));
+                t2 = *(CETable+3*(pos)+1);
+                lh->gapsHi[3*st] = (t1 & UCOL_PRIMARYMASK) | (t2 & UCOL_PRIMARYMASK) >> 16;
+                lh->gapsHi[3*st+1] = (t1 & UCOL_SECONDARYMASK) << 16 | (t2 & UCOL_SECONDARYMASK) << 8;
+                //lh->gapsHi[3*st+2] = (UCOL_TERTIARYORDER(t1)) << 24 | (UCOL_TERTIARYORDER(t2)) << 16;
+                lh->gapsHi[3*st+2] = (t1&0x3f) << 24 | (t2&0x3f) << 16;
+                //pos--;
+                //t1 = *(CETable+3*(pos));
+                //t2 = *(CETable+3*(pos)+1);
+                t1 = lh->baseCE;
+                t2 = lh->baseContCE;
+                lh->gapsLo[3*st] = (t1 & UCOL_PRIMARYMASK) | (t2 & UCOL_PRIMARYMASK) >> 16;
+                lh->gapsLo[3*st+1] = (t1 & UCOL_SECONDARYMASK) << 16 | (t2 & UCOL_SECONDARYMASK) << 8;
+                lh->gapsLo[3*st+2] = (t1&0x3f) << 24 | (t2&0x3f) << 16;
+            }
+        }
+    }
+}
+
+
+#define ucol_countBytes(value, noOfBytes)   \
+{                               \
+    uint32_t mask = 0xFFFFFFFF;   \
+    (noOfBytes) = 0;              \
+    while(mask != 0) {            \
+    if(((value) & mask) != 0) { \
+    (noOfBytes)++;            \
+    }                           \
+    mask >>= 8;                 \
+    }                             \
+}
+
+static uint32_t ucol_getNextGenerated(ucolCEGenerator *g, UErrorCode *status) {
+    if(U_SUCCESS(*status)) {
+        g->current = ucol_nextWeight(g->ranges, &g->noOfRanges);
+    }
+    return g->current;
+}
+
+static uint32_t ucol_getSimpleCEGenerator(ucolCEGenerator *g, UColToken *tok, uint32_t strength, UErrorCode *status) {
+    /* TODO: rename to enum names */
+    uint32_t high, low, count=1;
+    uint32_t maxByte = (strength == UCOL_TERTIARY)?0x3F:0xFF;
+
+    if(strength == UCOL_SECONDARY) {
+        low = UCOL_COMMON_TOP2<<24;
+        high = 0xFFFFFFFF;
+        count = 0xFF - UCOL_COMMON_TOP2;
+    } else {
+        low = UCOL_BYTE_COMMON << 24; //0x05000000;
+        high = 0x40000000;
+        count = 0x40 - UCOL_BYTE_COMMON;
+    }
+
+    if(tok->next != NULL && tok->next->strength == strength) {
+        count = tok->next->toInsert;
+    }
+
+    g->noOfRanges = ucol_allocWeights(low, high, count, maxByte, g->ranges);
+    g->current = UCOL_BYTE_COMMON<<24;
+
+    if(g->noOfRanges == 0) {
+        *status = U_INTERNAL_PROGRAM_ERROR;
+    }
+    return g->current;
+}
+
+static uint32_t ucol_getCEGenerator(ucolCEGenerator *g, uint32_t* lows, uint32_t* highs, UColToken *tok, uint32_t fStrength, UErrorCode *status) {
+    uint32_t strength = tok->strength;
+    uint32_t low = lows[fStrength*3+strength];
+    uint32_t high = highs[fStrength*3+strength];
+    uint32_t maxByte = 0;
+    if(strength == UCOL_TERTIARY) {
+        maxByte = 0x3F;
+    } else if(strength == UCOL_PRIMARY) {
+        maxByte = 0xFE;
+    } else {
+        maxByte = 0xFF;
+    }
+
+    uint32_t count = tok->toInsert;
+
+    if(low >= high && strength > UCOL_PRIMARY) {
+        int32_t s = strength;
+        for(;;) {
+            s--;
+            if(lows[fStrength*3+s] != highs[fStrength*3+s]) {
+                if(strength == UCOL_SECONDARY) {
+                    if (low < UCOL_COMMON_TOP2<<24 ) {
+                       // Override if low range is less than UCOL_COMMON_TOP2.
+		        low = UCOL_COMMON_TOP2<<24;
+                    }
+                    high = 0xFFFFFFFF;
+                } else {
+                    // Override if low range is less than UCOL_COMMON_BOT3.
+		    if ( low < UCOL_COMMON_BOT3<<24 ) {
+                        low = UCOL_COMMON_BOT3<<24;
+		    }
+                    high = 0x40000000;
+                }
+                break;
+            }
+            if(s<0) {
+                *status = U_INTERNAL_PROGRAM_ERROR;
+                return 0;
+            }
+        }
+    }
+
+    if(low < 0x02000000) {
+        // We must not use CE weight byte 02, so we set it as the minimum lower bound.
+        // See http://site.icu-project.org/design/collation/bytes
+        low = 0x02000000;
+    }
+
+    if(strength == UCOL_SECONDARY) { /* similar as simple */
+        if(low >= (UCOL_COMMON_BOT2<<24) && low < (uint32_t)(UCOL_COMMON_TOP2<<24)) {
+            low = UCOL_COMMON_TOP2<<24;
+        }
+        if(high > (UCOL_COMMON_BOT2<<24) && high < (uint32_t)(UCOL_COMMON_TOP2<<24)) {
+            high = UCOL_COMMON_TOP2<<24;
+        }
+        if(low < (UCOL_COMMON_BOT2<<24)) {
+            g->noOfRanges = ucol_allocWeights(UCOL_BYTE_UNSHIFTED_MIN<<24, high, count, maxByte, g->ranges);
+            g->current = ucol_nextWeight(g->ranges, &g->noOfRanges);
+            //g->current = UCOL_COMMON_BOT2<<24;
+            return g->current;
+        }
+    }
+
+    g->noOfRanges = ucol_allocWeights(low, high, count, maxByte, g->ranges);
+    if(g->noOfRanges == 0) {
+        *status = U_INTERNAL_PROGRAM_ERROR;
+    }
+    g->current = ucol_nextWeight(g->ranges, &g->noOfRanges);
+    return g->current;
+}
+
+static
+uint32_t u_toLargeKana(const UChar *source, const uint32_t sourceLen, UChar *resBuf, const uint32_t resLen, UErrorCode *status) {
+    uint32_t i = 0;
+    UChar c;
+
+    if(U_FAILURE(*status)) {
+        return 0;
+    }
+
+    if(sourceLen > resLen) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
+
+    for(i = 0; i < sourceLen; i++) {
+        c = source[i];
+        if(0x3041 <= c && c <= 0x30FA) { /* Kana range */
+            switch(c - 0x3000) {
+            case 0x41: case 0x43: case 0x45: case 0x47: case 0x49: case 0x63: case 0x83: case 0x85: case 0x8E:
+            case 0xA1: case 0xA3: case 0xA5: case 0xA7: case 0xA9: case 0xC3: case 0xE3: case 0xE5: case 0xEE:
+                c++;
+                break;
+            case 0xF5:
+                c = 0x30AB;
+                break;
+            case 0xF6:
+                c = 0x30B1;
+                break;
+            }
+        }
+        resBuf[i] = c;
+    }
+    return sourceLen;
+}
+
+static
+uint32_t u_toSmallKana(const UChar *source, const uint32_t sourceLen, UChar *resBuf, const uint32_t resLen, UErrorCode *status) {
+    uint32_t i = 0;
+    UChar c;
+
+    if(U_FAILURE(*status)) {
+        return 0;
+    }
+
+    if(sourceLen > resLen) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
+
+    for(i = 0; i < sourceLen; i++) {
+        c = source[i];
+        if(0x3041 <= c && c <= 0x30FA) { /* Kana range */
+            switch(c - 0x3000) {
+            case 0x42: case 0x44: case 0x46: case 0x48: case 0x4A: case 0x64: case 0x84: case 0x86: case 0x8F:
+            case 0xA2: case 0xA4: case 0xA6: case 0xA8: case 0xAA: case 0xC4: case 0xE4: case 0xE6: case 0xEF:
+                c--;
+                break;
+            case 0xAB:
+                c = 0x30F5;
+                break;
+            case 0xB1:
+                c = 0x30F6;
+                break;
+            }
+        }
+        resBuf[i] = c;
+    }
+    return sourceLen;
+}
+
+U_NAMESPACE_BEGIN
+
+static
+uint8_t ucol_uprv_getCaseBits(const UCollator *UCA, const UChar *src, uint32_t len, UErrorCode *status) {
+    uint32_t i = 0;
+    UChar n[128];
+    uint32_t nLen = 0;
+    uint32_t uCount = 0, lCount = 0;
+
+    collIterate s;
+    uint32_t order = 0;
+
+    if(U_FAILURE(*status)) {
+        return UCOL_LOWER_CASE;
+    }
+
+    nLen = unorm_normalize(src, len, UNORM_NFKD, 0, n, 128, status);
+    if(U_SUCCESS(*status)) {
+        for(i = 0; i < nLen; i++) {
+            uprv_init_collIterate(UCA, &n[i], 1, &s, status);
+            order = ucol_getNextCE(UCA, &s, status);
+            if(isContinuation(order)) {
+                *status = U_INTERNAL_PROGRAM_ERROR;
+                return UCOL_LOWER_CASE;
+            }
+            if((order&UCOL_CASE_BIT_MASK)== UCOL_UPPER_CASE) {
+                uCount++;
+            } else {
+                if(u_islower(n[i])) {
+                    lCount++;
+                } else if(U_SUCCESS(*status)) {
+                    UChar sk[1], lk[1];
+                    u_toSmallKana(&n[i], 1, sk, 1, status);
+                    u_toLargeKana(&n[i], 1, lk, 1, status);
+                    if(sk[0] == n[i] && lk[0] != n[i]) {
+                        lCount++;
+                    }
+                }
+            }
+        }
+    }
+
+    if(uCount != 0 && lCount != 0) {
+        return UCOL_MIXED_CASE;
+    } else if(uCount != 0) {
+        return UCOL_UPPER_CASE;
+    } else {
+        return UCOL_LOWER_CASE;
+    }
+}
+
+
+U_CFUNC void ucol_doCE(UColTokenParser *src, uint32_t *CEparts, UColToken *tok, UErrorCode *status) {
+    /* this one makes the table and stuff */
+    uint32_t noOfBytes[3];
+    uint32_t i;
+
+    for(i = 0; i<3; i++) {
+        ucol_countBytes(CEparts[i], noOfBytes[i]);
+    }
+
+    /* Here we have to pack CEs from parts */
+
+    uint32_t CEi = 0;
+    uint32_t value = 0;
+
+    while(2*CEi<noOfBytes[0] || CEi<noOfBytes[1] || CEi<noOfBytes[2]) {
+        if(CEi > 0) {
+            value = UCOL_CONTINUATION_MARKER; /* Continuation marker */
+        } else {
+            value = 0;
+        }
+
+        if(2*CEi<noOfBytes[0]) {
+            value |= ((CEparts[0]>>(32-16*(CEi+1))) & 0xFFFF) << 16;
+        }
+        if(CEi<noOfBytes[1]) {
+            value |= ((CEparts[1]>>(32-8*(CEi+1))) & 0xFF) << 8;
+        }
+        if(CEi<noOfBytes[2]) {
+            value |= ((CEparts[2]>>(32-8*(CEi+1))) & 0x3F);
+        }
+        tok->CEs[CEi] = value;
+        CEi++;
+    }
+    if(CEi == 0) { /* totally ignorable */
+        tok->noOfCEs = 1;
+        tok->CEs[0] = 0;
+    } else { /* there is at least something */
+        tok->noOfCEs = CEi;
+    }
+
+
+    // we want to set case bits here and now, not later.
+    // Case bits handling
+    if(tok->CEs[0] != 0) { // case bits should be set only for non-ignorables
+        tok->CEs[0] &= 0xFFFFFF3F; // Clean the case bits field
+        int32_t cSize = (tok->source & 0xFF000000) >> 24;
+        UChar *cPoints = (tok->source & 0x00FFFFFF) + src->source;
+
+        if(cSize > 1) {
+            // Do it manually
+            tok->CEs[0] |= ucol_uprv_getCaseBits(src->UCA, cPoints, cSize, status);
+        } else {
+            // Copy it from the UCA
+            uint32_t caseCE = ucol_getFirstCE(src->UCA, cPoints[0], status);
+            tok->CEs[0] |= (caseCE & 0xC0);
+        }
+    }
+
+#if UCOL_DEBUG==2
+    fprintf(stderr, "%04X str: %i, [%08X, %08X, %08X]: tok: ", tok->debugSource, tok->strength, CEparts[0] >> (32-8*noOfBytes[0]), CEparts[1] >> (32-8*noOfBytes[1]), CEparts[2]>> (32-8*noOfBytes[2]));
+    for(i = 0; i<tok->noOfCEs; i++) {
+        fprintf(stderr, "%08X ", tok->CEs[i]);
+    }
+    fprintf(stderr, "\n");
+#endif
+}
+
+U_CFUNC void ucol_initBuffers(UColTokenParser *src, UColTokListHeader *lh, UErrorCode *status) {
+    ucolCEGenerator Gens[UCOL_CE_STRENGTH_LIMIT];
+    uint32_t CEparts[UCOL_CE_STRENGTH_LIMIT];
+
+    UColToken *tok = lh->last;
+    uint32_t t[UCOL_STRENGTH_LIMIT];
+
+    uprv_memset(t, 0, UCOL_STRENGTH_LIMIT*sizeof(uint32_t));
+
+    tok->toInsert = 1;
+    t[tok->strength] = 1;
+
+    while(tok->previous != NULL) {
+        if(tok->previous->strength < tok->strength) { /* going up */
+            t[tok->strength] = 0;
+            t[tok->previous->strength]++;
+        } else if(tok->previous->strength > tok->strength) { /* going down */
+            t[tok->previous->strength] = 1;
+        } else {
+            t[tok->strength]++;
+        }
+        tok=tok->previous;
+        tok->toInsert = t[tok->strength];
+    }
+
+    tok->toInsert = t[tok->strength];
+    ucol_inv_getGapPositions(src, lh, status);
+
+#if UCOL_DEBUG
+    fprintf(stderr, "BaseCE: %08X %08X\n", lh->baseCE, lh->baseContCE);
+    int32_t j = 2;
+    for(j = 2; j >= 0; j--) {
+        fprintf(stderr, "gapsLo[%i] [%08X %08X %08X]\n", j, lh->gapsLo[j*3], lh->gapsLo[j*3+1], lh->gapsLo[j*3+2]);
+        fprintf(stderr, "gapsHi[%i] [%08X %08X %08X]\n", j, lh->gapsHi[j*3], lh->gapsHi[j*3+1], lh->gapsHi[j*3+2]);
+    }
+    tok=&lh->first[UCOL_TOK_POLARITY_POSITIVE];
+
+    do {
+        fprintf(stderr,"%i", tok->strength);
+        tok = tok->next;
+    } while(tok != NULL);
+    fprintf(stderr, "\n");
+
+    tok=&lh->first[UCOL_TOK_POLARITY_POSITIVE];
+
+    do {
+        fprintf(stderr,"%i", tok->toInsert);
+        tok = tok->next;
+    } while(tok != NULL);
+#endif
+
+    tok = lh->first;
+    uint32_t fStrength = UCOL_IDENTICAL;
+    uint32_t initStrength = UCOL_IDENTICAL;
+
+
+    CEparts[UCOL_PRIMARY] = (lh->baseCE & UCOL_PRIMARYMASK) | (lh->baseContCE & UCOL_PRIMARYMASK) >> 16;
+    CEparts[UCOL_SECONDARY] = (lh->baseCE & UCOL_SECONDARYMASK) << 16 | (lh->baseContCE & UCOL_SECONDARYMASK) << 8;
+    CEparts[UCOL_TERTIARY] = (UCOL_TERTIARYORDER(lh->baseCE)) << 24 | (UCOL_TERTIARYORDER(lh->baseContCE)) << 16;
+
+    while (tok != NULL && U_SUCCESS(*status)) {
+        fStrength = tok->strength;
+        if(fStrength < initStrength) {
+            initStrength = fStrength;
+            if(lh->pos[fStrength] == -1) {
+                while(lh->pos[fStrength] == -1 && fStrength > 0) {
+                    fStrength--;
+                }
+                if(lh->pos[fStrength] == -1) {
+                    *status = U_INTERNAL_PROGRAM_ERROR;
+                    return;
+                }
+            }
+            if(initStrength == UCOL_TERTIARY) { /* starting with tertiary */
+                CEparts[UCOL_PRIMARY] = lh->gapsLo[fStrength*3];
+                CEparts[UCOL_SECONDARY] = lh->gapsLo[fStrength*3+1];
+                /*CEparts[UCOL_TERTIARY] = ucol_getCEGenerator(&Gens[2], lh->gapsLo[fStrength*3+2], lh->gapsHi[fStrength*3+2], tok, UCOL_TERTIARY); */
+                CEparts[UCOL_TERTIARY] = ucol_getCEGenerator(&Gens[UCOL_TERTIARY], lh->gapsLo, lh->gapsHi, tok, fStrength, status);
+            } else if(initStrength == UCOL_SECONDARY) { /* secondaries */
+                CEparts[UCOL_PRIMARY] = lh->gapsLo[fStrength*3];
+                /*CEparts[1] = ucol_getCEGenerator(&Gens[1], lh->gapsLo[fStrength*3+1], lh->gapsHi[fStrength*3+1], tok, 1);*/
+                CEparts[UCOL_SECONDARY] = ucol_getCEGenerator(&Gens[UCOL_SECONDARY], lh->gapsLo, lh->gapsHi, tok, fStrength,  status);
+                CEparts[UCOL_TERTIARY] = ucol_getSimpleCEGenerator(&Gens[UCOL_TERTIARY], tok, UCOL_TERTIARY, status);
+            } else { /* primaries */
+                /*CEparts[UCOL_PRIMARY] = ucol_getCEGenerator(&Gens[0], lh->gapsLo[0], lh->gapsHi[0], tok, UCOL_PRIMARY);*/
+                CEparts[UCOL_PRIMARY] = ucol_getCEGenerator(&Gens[UCOL_PRIMARY], lh->gapsLo, lh->gapsHi, tok, fStrength,  status);
+                CEparts[UCOL_SECONDARY] = ucol_getSimpleCEGenerator(&Gens[UCOL_SECONDARY], tok, UCOL_SECONDARY, status);
+                CEparts[UCOL_TERTIARY] = ucol_getSimpleCEGenerator(&Gens[UCOL_TERTIARY], tok, UCOL_TERTIARY, status);
+            }
+        } else {
+            if(tok->strength == UCOL_TERTIARY) {
+                CEparts[UCOL_TERTIARY] = ucol_getNextGenerated(&Gens[UCOL_TERTIARY], status);
+            } else if(tok->strength == UCOL_SECONDARY) {
+                CEparts[UCOL_SECONDARY] = ucol_getNextGenerated(&Gens[UCOL_SECONDARY], status);
+                CEparts[UCOL_TERTIARY] = ucol_getSimpleCEGenerator(&Gens[UCOL_TERTIARY], tok, UCOL_TERTIARY, status);
+            } else if(tok->strength == UCOL_PRIMARY) {
+                CEparts[UCOL_PRIMARY] = ucol_getNextGenerated(&Gens[UCOL_PRIMARY], status);
+                CEparts[UCOL_SECONDARY] = ucol_getSimpleCEGenerator(&Gens[UCOL_SECONDARY], tok, UCOL_SECONDARY, status);
+                CEparts[UCOL_TERTIARY] = ucol_getSimpleCEGenerator(&Gens[UCOL_TERTIARY], tok, UCOL_TERTIARY, status);
+            }
+        }
+        ucol_doCE(src, CEparts, tok, status);
+        tok = tok->next;
+    }
+}
+
+U_CFUNC void ucol_createElements(UColTokenParser *src, tempUCATable *t, UColTokListHeader *lh, UErrorCode *status) {
+    UCAElements el;
+    UColToken *tok = lh->first;
+    UColToken *expt = NULL;
+    uint32_t i = 0, j = 0;
+    UChar32 fcdHighStart;
+    const uint16_t *fcdTrieIndex = unorm_getFCDTrieIndex(fcdHighStart, status);
+
+    while(tok != NULL && U_SUCCESS(*status)) {
+        /* first, check if there are any expansions */
+        /* if there are expansions, we need to do a little bit more processing */
+        /* since parts of expansion can be tailored, while others are not */
+        if(tok->expansion != 0) {
+            uint32_t len = tok->expansion >> 24;
+            uint32_t currentSequenceLen = len;
+            uint32_t expOffset = tok->expansion & 0x00FFFFFF;
+            //uint32_t exp = currentSequenceLen | expOffset;
+            UColToken exp;
+            exp.source = currentSequenceLen | expOffset;
+            exp.rulesToParseHdl = &(src->source);
+
+            while(len > 0) {
+                currentSequenceLen = len;
+                while(currentSequenceLen > 0) {
+                    exp.source = (currentSequenceLen << 24) | expOffset;
+                    if((expt = (UColToken *)uhash_get(src->tailored, &exp)) != NULL && expt->strength != UCOL_TOK_RESET) { /* expansion is tailored */
+                        uint32_t noOfCEsToCopy = expt->noOfCEs;
+                        for(j = 0; j<noOfCEsToCopy; j++) {
+                            tok->expCEs[tok->noOfExpCEs + j] = expt->CEs[j];
+                        }
+                        tok->noOfExpCEs += noOfCEsToCopy;
+                        // Smart people never try to add codepoints and CEs.
+                        // For some odd reason, it won't work.
+                        expOffset += currentSequenceLen; //noOfCEsToCopy;
+                        len -= currentSequenceLen; //noOfCEsToCopy;
+                        break;
+                    } else {
+                        currentSequenceLen--;
+                    }
+                }
+                if(currentSequenceLen == 0) { /* couldn't find any tailored subsequence */
+                    /* will have to get one from UCA */
+                    /* first, get the UChars from the rules */
+                    /* then pick CEs out until there is no more and stuff them into expansion */
+                    collIterate s;
+                    uint32_t order = 0;
+                    uprv_init_collIterate(src->UCA, expOffset + src->source, 1, &s, status);
+
+                    for(;;) {
+                        order = ucol_getNextCE(src->UCA, &s, status);
+                        if(order == UCOL_NO_MORE_CES) {
+                            break;
+                        }
+                        tok->expCEs[tok->noOfExpCEs++] = order;
+                    }
+                    expOffset++;
+                    len--;
+                }
+            }
+        } else {
+            tok->noOfExpCEs = 0;
+        }
+
+        /* set the ucaelement with obtained values */
+        el.noOfCEs = tok->noOfCEs + tok->noOfExpCEs;
+        /* copy CEs */
+        for(i = 0; i<tok->noOfCEs; i++) {
+            el.CEs[i] = tok->CEs[i];
+        }
+        for(i = 0; i<tok->noOfExpCEs; i++) {
+            el.CEs[i+tok->noOfCEs] = tok->expCEs[i];
+        }
+
+        /* copy UChars */
+        // We kept prefix and source kind of together, as it is a kind of a contraction.
+        // However, now we have to slice the prefix off the main thing -
+        el.prefix = el.prefixChars;
+        el.cPoints = el.uchars;
+        if(tok->prefix != 0) { // we will just copy the prefix here, and adjust accordingly in the
+            // addPrefix function in ucol_elm. The reason is that we need to add both composed AND
+            // decomposed elements to the unsaf table.
+            el.prefixSize = tok->prefix>>24;
+            uprv_memcpy(el.prefix, src->source + (tok->prefix & 0x00FFFFFF), el.prefixSize*sizeof(UChar));
+
+            el.cSize = (tok->source >> 24)-(tok->prefix>>24);
+            uprv_memcpy(el.uchars, (tok->source & 0x00FFFFFF)+(tok->prefix>>24) + src->source, el.cSize*sizeof(UChar));
+        } else {
+            el.prefixSize = 0;
+            *el.prefix = 0;
+
+            el.cSize = (tok->source >> 24);
+            uprv_memcpy(el.uchars, (tok->source & 0x00FFFFFF) + src->source, el.cSize*sizeof(UChar));
+        }
+        if(src->UCA != NULL) {
+            for(i = 0; i<el.cSize; i++) {
+                if(UCOL_ISJAMO(el.cPoints[i])) {
+                    t->image->jamoSpecial = TRUE;
+                }
+            }
+            if (!src->buildCCTabFlag && el.cSize > 0) {
+                // Check the trailing canonical combining class (tccc) of the last character.
+                const UChar *s = el.cPoints + el.cSize;
+                uint16_t fcd = unorm_prevFCD16(fcdTrieIndex, fcdHighStart, el.cPoints, s);
+                if ((fcd & 0xff) != 0) {
+                    src->buildCCTabFlag = TRUE;
+                }
+            }
+        }
+
+        /* and then, add it */
+#if UCOL_DEBUG==2
+        fprintf(stderr, "Adding: %04X with %08X\n", el.cPoints[0], el.CEs[0]);
+#endif
+        uprv_uca_addAnElement(t, &el, status);
+
+#if UCOL_DEBUG_DUPLICATES
+        if(*status != U_ZERO_ERROR) {
+            fprintf(stderr, "replaced CE for %04X with CE for %04X\n", el.cPoints[0], tok->debugSource);
+            *status = U_ZERO_ERROR;
+        }
+#endif
+
+        tok = tok->next;
+    }
+}
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+_processUCACompleteIgnorables(const void *context, UChar32 start, UChar32 limit, uint32_t value) {
+    UErrorCode status = U_ZERO_ERROR;
+    tempUCATable *t = (tempUCATable *)context;
+    if(value == 0) {
+        while(start < limit) {
+            uint32_t CE = utrie_get32(t->mapping, start, NULL);
+            if(CE == UCOL_NOT_FOUND) {
+                UCAElements el;
+                el.isThai = FALSE;
+                el.prefixSize = 0;
+                el.prefixChars[0] = 0;
+                el.prefix = el.prefixChars;
+                el.cPoints = el.uchars;
+
+                el.cSize = 0;
+                UTF_APPEND_CHAR(el.uchars, el.cSize, 1024, start);
+
+                el.noOfCEs = 1;
+                el.CEs[0] = 0;
+                uprv_uca_addAnElement(t, &el, &status);
+
+            }
+            start++;
+        }
+    }
+    if(U_FAILURE(status)) {
+        return FALSE;
+    } else {
+        return TRUE;
+    }
+}
+U_CDECL_END
+
+static void
+ucol_uprv_bld_copyRangeFromUCA(UColTokenParser *src, tempUCATable *t,
+                               UChar32 start, UChar32 end,
+                               UErrorCode *status)
+{
+    //UChar decomp[256];
+    uint32_t CE = UCOL_NOT_FOUND;
+    UChar32 u = 0;
+    UCAElements el;
+    el.isThai = FALSE;
+    el.prefixSize = 0;
+    el.prefixChars[0] = 0;
+    collIterate colIt;
+
+    if(U_SUCCESS(*status)) {
+        for(u = start; u<=end; u++) {
+            if((CE = utrie_get32(t->mapping, u, NULL)) == UCOL_NOT_FOUND
+                /* this test is for contractions that are missing the starting element. */
+                || ((isCntTableElement(CE)) &&
+                (uprv_cnttab_getCE(t->contractions, CE, 0, status) == UCOL_NOT_FOUND))
+                )
+            {
+                el.cSize = 0;
+                U16_APPEND_UNSAFE(el.uchars, el.cSize, u);
+                //decomp[0] = (UChar)u;
+                //el.uchars[0] = (UChar)u;
+                el.cPoints = el.uchars;
+                //el.cSize = 1;
+                el.noOfCEs = 0;
+                el.prefix = el.prefixChars;
+                el.prefixSize = 0;
+                //uprv_init_collIterate(src->UCA, decomp, 1, &colIt);
+                // We actually want to check whether this element is a special
+                // If it is an implicit element (hangul, CJK - we want to copy the
+                // special, not the resolved CEs) - for hangul, copying resolved
+                // would just make things the same (there is an expansion and it
+                // takes approximately the same amount of time to resolve as
+                // falling back to the UCA).
+                /*
+                UTRIE_GET32(src->UCA->mapping, u, CE);
+                tag = getCETag(CE);
+                if(tag == HANGUL_SYLLABLE_TAG || tag == CJK_IMPLICIT_TAG
+                || tag == IMPLICIT_TAG || tag == TRAIL_SURROGATE_TAG
+                || tag == LEAD_SURROGATE_TAG) {
+                el.CEs[el.noOfCEs++] = CE;
+                } else {
+                */
+                // It turns out that it does not make sense to keep implicits
+                // unresolved. The cost of resolving them is big enough so that
+                // it doesn't make any difference whether we have to go to the UCA
+                // or not.
+                {
+                    uprv_init_collIterate(src->UCA, el.uchars, el.cSize, &colIt, status);
+                    while(CE != UCOL_NO_MORE_CES) {
+                        CE = ucol_getNextCE(src->UCA, &colIt, status);
+                        if(CE != UCOL_NO_MORE_CES) {
+                            el.CEs[el.noOfCEs++] = CE;
+                        }
+                    }
+                }
+                uprv_uca_addAnElement(t, &el, status);
+            }
+        }
+    }
+}
+
+U_NAMESPACE_END
+
+U_CFUNC UCATableHeader *
+ucol_assembleTailoringTable(UColTokenParser *src, UErrorCode *status) {
+    U_NAMESPACE_USE
+
+    uint32_t i = 0;
+    if(U_FAILURE(*status)) {
+        return NULL;
+    }
+    /*
+    2.  Eliminate the negative lists by doing the following for each non-null negative list:
+    o   if previousCE(baseCE, strongestN) != some ListHeader X's baseCE,
+    create new ListHeader X
+    o   reverse the list, add to the end of X's positive list. Reset the strength of the
+    first item you add, based on the stronger strength levels of the two lists.
+    */
+    /*
+    3.  For each ListHeader with a non-null positive list:
+    */
+    /*
+    o   Find all character strings with CEs between the baseCE and the
+    next/previous CE, at the strength of the first token. Add these to the
+    tailoring.
+    ? That is, if UCA has ...  x <<< X << x' <<< X' < y ..., and the
+    tailoring has & x < z...
+    ? Then we change the tailoring to & x  <<< X << x' <<< X' < z ...
+    */
+    /* It is possible that this part should be done even while constructing list */
+    /* The problem is that it is unknown what is going to be the strongest weight */
+    /* So we might as well do it here */
+
+    /*
+    o   Allocate CEs for each token in the list, based on the total number N of the
+    largest level difference, and the gap G between baseCE and nextCE at that
+    level. The relation * between the last item and nextCE is the same as the
+    strongest strength.
+    o   Example: baseCE < a << b <<< q << c < d < e * nextCE(X,1)
+    ? There are 3 primary items: a, d, e. Fit them into the primary gap.
+    Then fit b and c into the secondary gap between a and d, then fit q
+    into the tertiary gap between b and c.
+
+    o   Example: baseCE << b <<< q << c * nextCE(X,2)
+    ? There are 2 secondary items: b, c. Fit them into the secondary gap.
+    Then fit q into the tertiary gap between b and c.
+    o   When incrementing primary values, we will not cross high byte
+    boundaries except where there is only a single-byte primary. That is to
+    ensure that the script reordering will continue to work.
+    */
+    UCATableHeader *image = (UCATableHeader *)uprv_malloc(sizeof(UCATableHeader));
+    /* test for NULL */
+    if (image == NULL) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    uprv_memcpy(image, src->UCA->image, sizeof(UCATableHeader));
+
+    for(i = 0; i<src->resultLen; i++) {
+        /* now we need to generate the CEs */
+        /* We stuff the initial value in the buffers, and increase the appropriate buffer */
+        /* According to strength                                                          */
+        if(U_SUCCESS(*status)) {
+            if(src->lh[i].first) { // if there are any elements
+                // due to the way parser works, subsequent tailorings
+                // may remove all the elements from a sequence, therefore
+                // leaving an empty tailoring sequence.
+                ucol_initBuffers(src, &src->lh[i], status);
+            }
+        }
+        if(U_FAILURE(*status)) {
+            uprv_free(image);
+            return NULL;
+        }
+    }
+
+    if(src->varTop != NULL) { /* stuff the variable top value */
+        src->opts->variableTopValue = (*(src->varTop->CEs))>>16;
+        /* remove it from the list */
+        if(src->varTop->listHeader->first == src->varTop) { /* first in list */
+            src->varTop->listHeader->first = src->varTop->next;
+        }
+        if(src->varTop->listHeader->last == src->varTop) { /* first in list */
+            src->varTop->listHeader->last = src->varTop->previous;
+        }
+        if(src->varTop->next != NULL) {
+            src->varTop->next->previous = src->varTop->previous;
+        }
+        if(src->varTop->previous != NULL) {
+            src->varTop->previous->next = src->varTop->next;
+        }
+    }
+
+
+    tempUCATable *t = uprv_uca_initTempTable(image, src->opts, src->UCA, NOT_FOUND_TAG, NOT_FOUND_TAG, status);
+    if(U_FAILURE(*status)) {
+        uprv_free(image);
+        return NULL;
+    }
+
+
+    /* After this, we have assigned CE values to all regular CEs      */
+    /* now we will go through list once more and resolve expansions,  */
+    /* make UCAElements structs and add them to table                 */
+    for(i = 0; i<src->resultLen; i++) {
+        /* now we need to generate the CEs */
+        /* We stuff the initial value in the buffers, and increase the appropriate buffer */
+        /* According to strength                                                          */
+        if(U_SUCCESS(*status)) {
+            ucol_createElements(src, t, &src->lh[i], status);
+        }
+    }
+
+    UCAElements el;
+    el.isThai = FALSE;
+    el.prefixSize = 0;
+    el.prefixChars[0] = 0;
+
+    /* add latin-1 stuff */
+    ucol_uprv_bld_copyRangeFromUCA(src, t, 0, 0xFF, status);
+
+    /* add stuff for copying */
+    if(src->copySet != NULL) {
+        int32_t i = 0;
+        UnicodeSet *set = (UnicodeSet *)src->copySet;
+        for(i = 0; i < set->getRangeCount(); i++) {
+            ucol_uprv_bld_copyRangeFromUCA(src, t, set->getRangeStart(i), set->getRangeEnd(i), status);
+        }
+    }
+
+    if(U_SUCCESS(*status)) {
+        /* copy contractions from the UCA - this is felt mostly for cyrillic*/
+
+        uint32_t tailoredCE = UCOL_NOT_FOUND;
+        //UChar *conts = (UChar *)((uint8_t *)src->UCA->image + src->UCA->image->UCAConsts+sizeof(UCAConstants));
+        UChar *conts = (UChar *)((uint8_t *)src->UCA->image + src->UCA->image->contractionUCACombos);
+        UCollationElements *ucaEl = ucol_openElements(src->UCA, NULL, 0, status);
+        // Check for null pointer
+        if (ucaEl == NULL) {
+        	*status = U_MEMORY_ALLOCATION_ERROR;
+        	return NULL;
+        }
+        while(*conts != 0) {
+            /*tailoredCE = ucmpe32_get(t->mapping, *conts);*/
+            tailoredCE = utrie_get32(t->mapping, *conts, NULL);
+            if(tailoredCE != UCOL_NOT_FOUND) {
+                UBool needToAdd = TRUE;
+                if(isCntTableElement(tailoredCE)) {
+                    if(uprv_cnttab_isTailored(t->contractions, tailoredCE, conts+1, status) == TRUE) {
+                        needToAdd = FALSE;
+                    }
+                }
+                if (!needToAdd && isPrefix(tailoredCE) && *(conts+1)==0) {
+                    UCAElements elm;
+                    elm.cPoints = el.uchars;
+                    elm.noOfCEs = 0;
+                    elm.uchars[0] = *conts;
+                    elm.uchars[1] = 0;
+                    elm.cSize = 1;
+                    elm.prefixChars[0] = *(conts+2);
+                    elm.isThai = FALSE;
+                    elm.prefix = elm.prefixChars;
+                    elm.prefixSize = 1;
+                    UCAElements *prefixEnt=(UCAElements *)uhash_get(t->prefixLookup, &elm);
+                    if ((prefixEnt==NULL) || *(prefixEnt->prefix)!=*(conts+2)) {
+                        needToAdd = TRUE;
+                    }
+                }
+                if(src->removeSet != NULL && uset_contains(src->removeSet, *conts)) {
+                    needToAdd = FALSE;
+                }
+
+                if(needToAdd == TRUE) { // we need to add if this contraction is not tailored.
+                    if (*(conts+1) != 0) {  // contractions
+                        el.prefix = el.prefixChars;
+                        el.prefixSize = 0;
+                        el.cPoints = el.uchars;
+                        el.noOfCEs = 0;
+                        el.uchars[0] = *conts;
+                        el.uchars[1] = *(conts+1);
+                        if(*(conts+2)!=0) {
+                            el.uchars[2] = *(conts+2);
+                            el.cSize = 3;
+                        } else {
+                            el.cSize = 2;
+                        }
+                        ucol_setText(ucaEl, el.uchars, el.cSize, status);
+                    }
+                    else { // pre-context character
+                        UChar str[4] = { 0 };
+                        int32_t len=0;
+                        int32_t preKeyLen=0;
+                        
+                        el.cPoints = el.uchars;
+                        el.noOfCEs = 0;
+                        el.uchars[0] = *conts;
+                        el.uchars[1] = 0;
+                        el.cSize = 1;
+                        el.prefixChars[0] = *(conts+2);
+                        el.prefix = el.prefixChars;
+                        el.prefixSize = 1;
+                        if (el.prefixChars[0]!=0) {
+                            // get CE of prefix character first
+                            str[0]=el.prefixChars[0];
+                            str[1]=0;
+                            ucol_setText(ucaEl, str, 1, status);
+                            while ((int32_t)(el.CEs[el.noOfCEs] = ucol_next(ucaEl, status))
+                                    != UCOL_NULLORDER) {
+                                preKeyLen++;  // count number of keys for prefix character
+                            }
+                            str[len++] = el.prefixChars[0];
+                        }
+
+                        str[len++] = el.uchars[0];
+                        str[len]=0;
+                        ucol_setText(ucaEl, str, len, status);
+                        // Skip the keys for prefix character, then copy the rest to el.
+                        while ((preKeyLen-->0) && 
+                               (int32_t)(el.CEs[el.noOfCEs] = ucol_next(ucaEl, status)) != UCOL_NULLORDER) {
+                            continue;
+                        }
+                           
+                    }
+                    while ((int32_t)(el.CEs[el.noOfCEs] = ucol_next(ucaEl, status)) != UCOL_NULLORDER) {
+                        el.noOfCEs++;
+                    }
+                    uprv_uca_addAnElement(t, &el, status);
+                }
+
+            } else if(src->removeSet != NULL && uset_contains(src->removeSet, *conts)) {
+                ucol_uprv_bld_copyRangeFromUCA(src, t, *conts, *conts, status);
+            }
+            conts+=3;
+        }
+        ucol_closeElements(ucaEl);
+    }
+
+    // Add completely ignorable elements
+    utrie_enum(&t->UCA->mapping, NULL, _processUCACompleteIgnorables, t);
+
+    // add tailoring characters related canonical closures
+    uprv_uca_canonicalClosure(t, src, NULL, status);
+
+    /* still need to produce compatibility closure */
+
+    UCATableHeader *myData = uprv_uca_assembleTable(t, status);
+
+    uprv_uca_closeTempTable(t);
+    uprv_free(image);
+
+    return myData;
+}
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+ucol_bld_cleanup(void)
+{
+    udata_close(invUCA_DATA_MEM);
+    invUCA_DATA_MEM = NULL;
+    _staticInvUCA = NULL;
+    return TRUE;
+}
+U_CDECL_END
+
+U_CAPI const InverseUCATableHeader * U_EXPORT2
+ucol_initInverseUCA(UErrorCode *status)
+{
+    if(U_FAILURE(*status)) return NULL;
+
+    UBool needsInit;
+    UMTX_CHECK(NULL, (_staticInvUCA == NULL), needsInit);
+
+    if(needsInit) {
+        InverseUCATableHeader *newInvUCA = NULL;
+        UDataMemory *result = udata_openChoice(U_ICUDATA_COLL, INVC_DATA_TYPE, INVC_DATA_NAME, isAcceptableInvUCA, NULL, status);
+
+        if(U_FAILURE(*status)) {
+            if (result) {
+                udata_close(result);
+            }
+            // This is not needed, as we are talking about
+            // memory we got from UData
+            //uprv_free(newInvUCA);
+        }
+
+        if(result != NULL) { /* It looks like sometimes we can fail to find the data file */
+            newInvUCA = (InverseUCATableHeader *)udata_getMemory(result);
+            UCollator *UCA = ucol_initUCA(status);
+            // UCA versions of UCA and inverse UCA should match
+            if(uprv_memcmp(newInvUCA->UCAVersion, UCA->image->UCAVersion, sizeof(UVersionInfo)) != 0) {
+                *status = U_INVALID_FORMAT_ERROR;
+                udata_close(result);
+                return NULL;
+            }
+
+            umtx_lock(NULL);
+            if(_staticInvUCA == NULL) {
+                invUCA_DATA_MEM = result;
+                _staticInvUCA = newInvUCA;
+                result = NULL;
+                newInvUCA = NULL;
+            }
+            umtx_unlock(NULL);
+
+            if(newInvUCA != NULL) {
+                udata_close(result);
+                // This is not needed, as we are talking about
+                // memory we got from UData
+                //uprv_free(newInvUCA);
+            }
+            else {
+                ucln_i18n_registerCleanup(UCLN_I18N_UCOL_BLD, ucol_bld_cleanup);
+            }
+        }
+    }
+    return _staticInvUCA;
+}
+
+/* This is the data that is used for non-script reordering codes. These _must_ be kept
+ * in order that they are to be applied as defaults and in synch with the UColReorderCode enum.
+ */
+static const char* ReorderingTokenNames[] = {
+    "SPACE",
+    "PUNCT",
+    "SYMBOL",
+    "CURRENCY",
+    "DIGIT",
+    NULL
+};
+
+static void toUpper(const char* src, char* dst, uint32_t length) {
+   for (uint32_t i = 0; *src != '\0' && i < length - 1; ++src, ++dst, ++i) {
+       *dst = toupper(*src);
+   }
+   *dst = '\0';
+}
+
+U_INTERNAL int32_t U_EXPORT2 
+ucol_findReorderingEntry(const char* name) {
+    char buffer[32];
+    toUpper(name, buffer, 32);
+    for (uint32_t entry = 0; ReorderingTokenNames[entry] != NULL; entry++) {
+        if (uprv_strcmp(buffer, ReorderingTokenNames[entry]) == 0) {
+            return entry + UCOL_REORDER_CODE_FIRST;
+        }
+    }
+    return USCRIPT_INVALID_CODE;
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/source/i18n/ucol_bld.h b/source/i18n/ucol_bld.h
new file mode 100644
index 0000000..e722c6c
--- /dev/null
+++ b/source/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/source/i18n/ucol_cnt.cpp b/source/i18n/ucol_cnt.cpp
new file mode 100644
index 0000000..7c274b7
--- /dev/null
+++ b/source/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/source/i18n/ucol_cnt.h b/source/i18n/ucol_cnt.h
new file mode 100644
index 0000000..f6dfcd7
--- /dev/null
+++ b/source/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/source/i18n/ucol_elm.cpp b/source/i18n/ucol_elm.cpp
new file mode 100644
index 0000000..bb686ee
--- /dev/null
+++ b/source/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/source/i18n/ucol_elm.h b/source/i18n/ucol_elm.h
new file mode 100644
index 0000000..9c85b19
--- /dev/null
+++ b/source/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/source/i18n/ucol_imp.h b/source/i18n/ucol_imp.h
new file mode 100644
index 0000000..6604bab
--- /dev/null
+++ b/source/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/source/i18n/ucol_res.cpp b/source/i18n/ucol_res.cpp
new file mode 100644
index 0000000..a1a1e13
--- /dev/null
+++ b/source/i18n/ucol_res.cpp
@@ -0,0 +1,1298 @@
+/*
+*******************************************************************************
+*   Copyright (C) 1996-2011, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*******************************************************************************
+*   file name:  ucol_res.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+* Description:
+* This file contains dependencies that the collation run-time doesn't normally
+* need. This mainly contains resource bundle usage and collation meta information
+*
+* Modification history
+* Date        Name      Comments
+* 1996-1999   various members of ICU team maintained C API for collation framework
+* 02/16/2001  synwee    Added internal method getPrevSpecialCE
+* 03/01/2001  synwee    Added maxexpansion functionality.
+* 03/16/2001  weiv      Collation framework is rewritten in C and made UCA compliant
+* 12/08/2004  grhoten   Split part of ucol.cpp into ucol_res.cpp
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+#include "unicode/uloc.h"
+#include "unicode/coll.h"
+#include "unicode/tblcoll.h"
+#include "unicode/caniter.h"
+#include "unicode/uscript.h"
+#include "unicode/ustring.h"
+
+#include "ucol_bld.h"
+#include "ucol_imp.h"
+#include "ucol_tok.h"
+#include "ucol_elm.h"
+#include "uresimp.h"
+#include "ustr_imp.h"
+#include "cstring.h"
+#include "umutex.h"
+#include "ucln_in.h"
+#include "ustrenum.h"
+#include "putilimp.h"
+#include "utracimp.h"
+#include "cmemory.h"
+#include "uenumimp.h"
+#include "ulist.h"
+
+U_NAMESPACE_USE
+
+static void ucol_setReorderCodesFromParser(UCollator *coll, UColTokenParser *parser, UErrorCode *status);
+
+// static UCA. There is only one. Collators don't use it.
+// It is referenced only in ucol_initUCA and ucol_cleanup
+static UCollator* _staticUCA = NULL;
+// static pointer to udata memory. Inited in ucol_initUCA
+// used for cleanup in ucol_cleanup
+static UDataMemory* UCA_DATA_MEM = NULL;
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+ucol_res_cleanup(void)
+{
+    if (UCA_DATA_MEM) {
+        udata_close(UCA_DATA_MEM);
+        UCA_DATA_MEM = NULL;
+    }
+    if (_staticUCA) {
+        ucol_close(_staticUCA);
+        _staticUCA = NULL;
+    }
+    return TRUE;
+}
+
+static UBool U_CALLCONV
+isAcceptableUCA(void * /*context*/,
+             const char * /*type*/, const char * /*name*/,
+             const UDataInfo *pInfo){
+  /* context, type & name are intentionally not used */
+    if( pInfo->size>=20 &&
+        pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
+        pInfo->charsetFamily==U_CHARSET_FAMILY &&
+        pInfo->dataFormat[0]==UCA_DATA_FORMAT_0 &&   /* dataFormat="UCol" */
+        pInfo->dataFormat[1]==UCA_DATA_FORMAT_1 &&
+        pInfo->dataFormat[2]==UCA_DATA_FORMAT_2 &&
+        pInfo->dataFormat[3]==UCA_DATA_FORMAT_3 &&
+        pInfo->formatVersion[0]==UCA_FORMAT_VERSION_0 &&
+        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;
+    int32_t reorderCodesIndex = -1;
+    
+    // lead bytes that have alread been assigned to the permutation table
+    bool newLeadByteUsed[256];
+    // permutation table slots that have already been filled
+    bool permutationSlotFilled[256];
+
+    // nothing to do
+    if(U_FAILURE(*status) || coll == NULL || 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 reorderCodesCount = 0; reorderCodesCount < internalReorderCodesLength; reorderCodesCount++) {
+        reorderCodesIndex += fromTheBottom ? 1 : -1;
+        int32_t next = internalReorderCodes[reorderCodesIndex];
+        if (next == UCOL_REORDER_CODE_IGNORE) {
+            continue;
+        }
+        if (next == USCRIPT_UNKNOWN) {
+            if (fromTheBottom == false) {
+                // double turnaround
+                *status = U_ILLEGAL_ARGUMENT_ERROR;
+                if (coll->leadBytePermutationTable != NULL) {
+                    uprv_free(coll->leadBytePermutationTable);
+                    coll->leadBytePermutationTable = NULL;
+                }
+                coll->reorderCodesLength = 0;
+                if (internalReorderCodes != NULL) {
+                    uprv_free(internalReorderCodes);
+                }
+                return;
+            }
+            fromTheBottom = false;
+            reorderCodesIndex = internalReorderCodesLength;
+            continue;
+        }
+        
+        uint16_t leadByteCount = ucol_getLeadBytesForReorderCode(coll, 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/source/i18n/ucol_sit.cpp b/source/i18n/ucol_sit.cpp
new file mode 100644
index 0000000..45f24ea
--- /dev/null
+++ b/source/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/source/i18n/ucol_tok.cpp b/source/i18n/ucol_tok.cpp
new file mode 100644
index 0000000..811d552
--- /dev/null
+++ b/source/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/source/i18n/ucol_tok.h b/source/i18n/ucol_tok.h
new file mode 100644
index 0000000..838ecd0
--- /dev/null
+++ b/source/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/source/i18n/ucol_wgt.cpp b/source/i18n/ucol_wgt.cpp
new file mode 100644
index 0000000..5833ea3
--- /dev/null
+++ b/source/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/source/i18n/ucol_wgt.h b/source/i18n/ucol_wgt.h
new file mode 100644
index 0000000..b3cb4c9
--- /dev/null
+++ b/source/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/source/i18n/ucoleitr.cpp b/source/i18n/ucoleitr.cpp
new file mode 100644
index 0000000..00dfea8
--- /dev/null
+++ b/source/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/source/i18n/ucsdet.cpp b/source/i18n/ucsdet.cpp
new file mode 100644
index 0000000..d06dd33
--- /dev/null
+++ b/source/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/source/i18n/ucurr.cpp b/source/i18n/ucurr.cpp
new file mode 100644
index 0000000..1fb24b1
--- /dev/null
+++ b/source/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/source/i18n/ucurrimp.h b/source/i18n/ucurrimp.h
new file mode 100644
index 0000000..98871ce
--- /dev/null
+++ b/source/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/source/i18n/udat.cpp b/source/i18n/udat.cpp
new file mode 100644
index 0000000..758a6a7
--- /dev/null
+++ b/source/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/source/i18n/udatpg.cpp b/source/i18n/udatpg.cpp
new file mode 100644
index 0000000..006384f
--- /dev/null
+++ b/source/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/source/i18n/ulocdata.c b/source/i18n/ulocdata.c
new file mode 100644
index 0000000..20d0246
--- /dev/null
+++ b/source/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/source/i18n/umsg.cpp b/source/i18n/umsg.cpp
new file mode 100644
index 0000000..8a58ee0
--- /dev/null
+++ b/source/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/source/i18n/umsg_imp.h b/source/i18n/umsg_imp.h
new file mode 100644
index 0000000..78bbf96
--- /dev/null
+++ b/source/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/source/i18n/unesctrn.cpp b/source/i18n/unesctrn.cpp
new file mode 100644
index 0000000..c3d848d
--- /dev/null
+++ b/source/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/source/i18n/unesctrn.h b/source/i18n/unesctrn.h
new file mode 100644
index 0000000..bfde6fc
--- /dev/null
+++ b/source/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/source/i18n/uni2name.cpp b/source/i18n/uni2name.cpp
new file mode 100644
index 0000000..5eba79d
--- /dev/null
+++ b/source/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/source/i18n/uni2name.h b/source/i18n/uni2name.h
new file mode 100644
index 0000000..aede864
--- /dev/null
+++ b/source/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/source/i18n/unicode/basictz.h b/source/i18n/unicode/basictz.h
new file mode 100644
index 0000000..f3d34a6
--- /dev/null
+++ b/source/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/source/i18n/unicode/bms.h b/source/i18n/unicode/bms.h
new file mode 100644
index 0000000..516e6aa
--- /dev/null
+++ b/source/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/source/i18n/unicode/bmsearch.h b/source/i18n/unicode/bmsearch.h
new file mode 100644
index 0000000..b5973e5
--- /dev/null
+++ b/source/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/source/i18n/unicode/calendar.h b/source/i18n/unicode/calendar.h
new file mode 100644
index 0000000..5aa5ff9
--- /dev/null
+++ b/source/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/source/i18n/unicode/choicfmt.h b/source/i18n/unicode/choicfmt.h
new file mode 100644
index 0000000..921b0a9
--- /dev/null
+++ b/source/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/source/i18n/unicode/coleitr.h b/source/i18n/unicode/coleitr.h
new file mode 100644
index 0000000..4025a41
--- /dev/null
+++ b/source/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/source/i18n/unicode/coll.h b/source/i18n/unicode/coll.h
new file mode 100644
index 0000000..357af13
--- /dev/null
+++ b/source/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/source/i18n/unicode/colldata.h b/source/i18n/unicode/colldata.h
new file mode 100644
index 0000000..af465f5
--- /dev/null
+++ b/source/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/source/i18n/unicode/curramt.h b/source/i18n/unicode/curramt.h
new file mode 100644
index 0000000..c33e6f1
--- /dev/null
+++ b/source/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/source/i18n/unicode/currpinf.h b/source/i18n/unicode/currpinf.h
new file mode 100644
index 0000000..fd9e5da
--- /dev/null
+++ b/source/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/source/i18n/unicode/currunit.h b/source/i18n/unicode/currunit.h
new file mode 100644
index 0000000..ecd9411
--- /dev/null
+++ b/source/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/source/i18n/unicode/datefmt.h b/source/i18n/unicode/datefmt.h
new file mode 100644
index 0000000..d21133a
--- /dev/null
+++ b/source/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/source/i18n/unicode/dcfmtsym.h b/source/i18n/unicode/dcfmtsym.h
new file mode 100644
index 0000000..dd554c5
--- /dev/null
+++ b/source/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/source/i18n/unicode/decimfmt.h b/source/i18n/unicode/decimfmt.h
new file mode 100644
index 0000000..778bf22
--- /dev/null
+++ b/source/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/source/i18n/unicode/dtfmtsym.h b/source/i18n/unicode/dtfmtsym.h
new file mode 100644
index 0000000..d858ba9
--- /dev/null
+++ b/source/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/source/i18n/unicode/dtitvfmt.h b/source/i18n/unicode/dtitvfmt.h
new file mode 100644
index 0000000..750454f
--- /dev/null
+++ b/source/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/source/i18n/unicode/dtitvinf.h b/source/i18n/unicode/dtitvinf.h
new file mode 100644
index 0000000..f6513a2
--- /dev/null
+++ b/source/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/source/i18n/unicode/dtptngen.h b/source/i18n/unicode/dtptngen.h
new file mode 100644
index 0000000..1a0f70b
--- /dev/null
+++ b/source/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/source/i18n/unicode/dtrule.h b/source/i18n/unicode/dtrule.h
new file mode 100644
index 0000000..cb526a1
--- /dev/null
+++ b/source/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/source/i18n/unicode/fieldpos.h b/source/i18n/unicode/fieldpos.h
new file mode 100644
index 0000000..38a9576
--- /dev/null
+++ b/source/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/source/i18n/unicode/fmtable.h b/source/i18n/unicode/fmtable.h
new file mode 100644
index 0000000..0834037
--- /dev/null
+++ b/source/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/source/i18n/unicode/format.h b/source/i18n/unicode/format.h
new file mode 100644
index 0000000..5651c9e
--- /dev/null
+++ b/source/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/source/i18n/unicode/fpositer.h b/source/i18n/unicode/fpositer.h
new file mode 100644
index 0000000..ecaa777
--- /dev/null
+++ b/source/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/source/i18n/unicode/gregocal.h b/source/i18n/unicode/gregocal.h
new file mode 100644
index 0000000..c17b6fe
--- /dev/null
+++ b/source/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/source/i18n/unicode/locdspnm.h b/source/i18n/unicode/locdspnm.h
new file mode 100644
index 0000000..647b062
--- /dev/null
+++ b/source/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/source/i18n/unicode/measfmt.h b/source/i18n/unicode/measfmt.h
new file mode 100644
index 0000000..a5af55e
--- /dev/null
+++ b/source/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/source/i18n/unicode/measunit.h b/source/i18n/unicode/measunit.h
new file mode 100644
index 0000000..9a210e6
--- /dev/null
+++ b/source/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/source/i18n/unicode/measure.h b/source/i18n/unicode/measure.h
new file mode 100644
index 0000000..6b7a049
--- /dev/null
+++ b/source/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/source/i18n/unicode/msgfmt.h b/source/i18n/unicode/msgfmt.h
new file mode 100644
index 0000000..58c74f1
--- /dev/null
+++ b/source/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/source/i18n/unicode/numfmt.h b/source/i18n/unicode/numfmt.h
new file mode 100644
index 0000000..63914ca
--- /dev/null
+++ b/source/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/source/i18n/unicode/numsys.h b/source/i18n/unicode/numsys.h
new file mode 100644
index 0000000..4fed002
--- /dev/null
+++ b/source/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/source/i18n/unicode/plurfmt.h b/source/i18n/unicode/plurfmt.h
new file mode 100644
index 0000000..35a6172
--- /dev/null
+++ b/source/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/source/i18n/unicode/plurrule.h b/source/i18n/unicode/plurrule.h
new file mode 100644
index 0000000..7c05fec
--- /dev/null
+++ b/source/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/source/i18n/unicode/rbnf.h b/source/i18n/unicode/rbnf.h
new file mode 100644
index 0000000..59835d3
--- /dev/null
+++ b/source/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/source/i18n/unicode/rbtz.h b/source/i18n/unicode/rbtz.h
new file mode 100644
index 0000000..2be2967
--- /dev/null
+++ b/source/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/source/i18n/unicode/regex.h b/source/i18n/unicode/regex.h
new file mode 100644
index 0000000..d8d7bc0
--- /dev/null
+++ b/source/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/source/i18n/unicode/search.h b/source/i18n/unicode/search.h
new file mode 100644
index 0000000..8b82906
--- /dev/null
+++ b/source/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/source/i18n/unicode/selfmt.h b/source/i18n/unicode/selfmt.h
new file mode 100755
index 0000000..e53f4ce
--- /dev/null
+++ b/source/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/source/i18n/unicode/simpletz.h b/source/i18n/unicode/simpletz.h
new file mode 100644
index 0000000..871c960
--- /dev/null
+++ b/source/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/source/i18n/unicode/smpdtfmt.h b/source/i18n/unicode/smpdtfmt.h
new file mode 100644
index 0000000..14c91d4
--- /dev/null
+++ b/source/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/source/i18n/unicode/sortkey.h b/source/i18n/unicode/sortkey.h
new file mode 100644
index 0000000..ef202dd
--- /dev/null
+++ b/source/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/source/i18n/unicode/stsearch.h b/source/i18n/unicode/stsearch.h
new file mode 100644
index 0000000..8499752
--- /dev/null
+++ b/source/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/source/i18n/unicode/tblcoll.h b/source/i18n/unicode/tblcoll.h
new file mode 100644
index 0000000..8e22251
--- /dev/null
+++ b/source/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/source/i18n/unicode/timezone.h b/source/i18n/unicode/timezone.h
new file mode 100644
index 0000000..a06d33d
--- /dev/null
+++ b/source/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/source/i18n/unicode/tmunit.h b/source/i18n/unicode/tmunit.h
new file mode 100644
index 0000000..6eda105
--- /dev/null
+++ b/source/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/source/i18n/unicode/tmutamt.h b/source/i18n/unicode/tmutamt.h
new file mode 100644
index 0000000..bd2b8a4
--- /dev/null
+++ b/source/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/source/i18n/unicode/tmutfmt.h b/source/i18n/unicode/tmutfmt.h
new file mode 100644
index 0000000..540be3f
--- /dev/null
+++ b/source/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/source/i18n/unicode/translit.h b/source/i18n/unicode/translit.h
new file mode 100644
index 0000000..b77eef5
--- /dev/null
+++ b/source/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/source/i18n/unicode/tzrule.h b/source/i18n/unicode/tzrule.h
new file mode 100644
index 0000000..afa4014
--- /dev/null
+++ b/source/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/source/i18n/unicode/tztrans.h b/source/i18n/unicode/tztrans.h
new file mode 100644
index 0000000..94b8e91
--- /dev/null
+++ b/source/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/source/i18n/unicode/ucal.h b/source/i18n/unicode/ucal.h
new file mode 100644
index 0000000..997af15
--- /dev/null
+++ b/source/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/source/i18n/unicode/ucol.h b/source/i18n/unicode/ucol.h
new file mode 100644
index 0000000..4a4cd60
--- /dev/null
+++ b/source/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/source/i18n/unicode/ucoleitr.h b/source/i18n/unicode/ucoleitr.h
new file mode 100644
index 0000000..419cb9f
--- /dev/null
+++ b/source/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/source/i18n/unicode/ucsdet.h b/source/i18n/unicode/ucsdet.h
new file mode 100644
index 0000000..dc492ee
--- /dev/null
+++ b/source/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/source/i18n/unicode/ucurr.h b/source/i18n/unicode/ucurr.h
new file mode 100644
index 0000000..cee8e21
--- /dev/null
+++ b/source/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/source/i18n/unicode/udat.h b/source/i18n/unicode/udat.h
new file mode 100644
index 0000000..d480c7d
--- /dev/null
+++ b/source/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/source/i18n/unicode/udatpg.h b/source/i18n/unicode/udatpg.h
new file mode 100644
index 0000000..3dc7e89
--- /dev/null
+++ b/source/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/source/i18n/unicode/uldnames.h b/source/i18n/unicode/uldnames.h
new file mode 100644
index 0000000..4a119ea
--- /dev/null
+++ b/source/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/source/i18n/unicode/ulocdata.h b/source/i18n/unicode/ulocdata.h
new file mode 100644
index 0000000..3431f25
--- /dev/null
+++ b/source/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/source/i18n/unicode/umsg.h b/source/i18n/unicode/umsg.h
new file mode 100644
index 0000000..7d08fd3
--- /dev/null
+++ b/source/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/source/i18n/unicode/unirepl.h b/source/i18n/unicode/unirepl.h
new file mode 100644
index 0000000..6b7746b
--- /dev/null
+++ b/source/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/source/i18n/unicode/unum.h b/source/i18n/unicode/unum.h
new file mode 100644
index 0000000..1102bab
--- /dev/null
+++ b/source/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/source/i18n/unicode/uregex.h b/source/i18n/unicode/uregex.h
new file mode 100644
index 0000000..0663e7e
--- /dev/null
+++ b/source/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/source/i18n/unicode/usearch.h b/source/i18n/unicode/usearch.h
new file mode 100644
index 0000000..2f3d563
--- /dev/null
+++ b/source/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/source/i18n/unicode/uspoof.h b/source/i18n/unicode/uspoof.h
new file mode 100644
index 0000000..7a218ca
--- /dev/null
+++ b/source/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/source/i18n/unicode/utmscale.h b/source/i18n/unicode/utmscale.h
new file mode 100644
index 0000000..472d776
--- /dev/null
+++ b/source/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/source/i18n/unicode/utrans.h b/source/i18n/unicode/utrans.h
new file mode 100644
index 0000000..5ef035f
--- /dev/null
+++ b/source/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/source/i18n/unicode/vtzone.h b/source/i18n/unicode/vtzone.h
new file mode 100644
index 0000000..724da7e
--- /dev/null
+++ b/source/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/source/i18n/unum.cpp b/source/i18n/unum.cpp
new file mode 100644
index 0000000..4e01677
--- /dev/null
+++ b/source/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/source/i18n/uregex.cpp b/source/i18n/uregex.cpp
new file mode 100644
index 0000000..c2249eb
--- /dev/null
+++ b/source/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/source/i18n/uregexc.cpp b/source/i18n/uregexc.cpp
new file mode 100644
index 0000000..6590020
--- /dev/null
+++ b/source/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/source/i18n/usearch.cpp b/source/i18n/usearch.cpp
new file mode 100644
index 0000000..e568b0c
--- /dev/null
+++ b/source/i18n/usearch.cpp
@@ -0,0 +1,4749 @@
+/*
+**********************************************************************
+*   Copyright (C) 2001-2011 IBM and others. All rights reserved.
+**********************************************************************
+*   Date        Name        Description
+*  07/02/2001   synwee      Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION && !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/usearch.h"
+#include "unicode/ustring.h"
+#include "unicode/uchar.h"
+#include "normalizer2impl.h"
+#include "ucol_imp.h"
+#include "usrchimp.h"
+#include "cmemory.h"
+#include "ucln_in.h"
+#include "uassert.h"
+#include "ustr_imp.h"
+
+U_NAMESPACE_USE
+
+// don't use Boyer-Moore
+// (and if we decide to turn this on again there are several new TODOs that will need to be addressed)
+#define BOYER_MOORE 0
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+// internal definition ---------------------------------------------------
+
+#define LAST_BYTE_MASK_          0xFF
+#define SECOND_LAST_BYTE_SHIFT_  8
+#define SUPPLEMENTARY_MIN_VALUE_ 0x10000
+
+static const uint16_t *fcdTrieIndex = NULL;
+static UChar32 fcdHighStart = 0;
+
+// internal methods -------------------------------------------------
+
+/**
+* Fast collation element iterator setOffset.
+* This function does not check for bounds.
+* @param coleiter collation element iterator
+* @param offset to set
+*/
+static
+inline void setColEIterOffset(UCollationElements *elems,
+                      int32_t             offset)
+{
+    collIterate *ci = &(elems->iteratordata_);
+    ci->pos         = ci->string + offset;
+    ci->CEpos       = ci->toReturn = ci->extendCEs ? ci->extendCEs : ci->CEs;
+    if (ci->flags & UCOL_ITER_INNORMBUF) {
+        ci->flags = ci->origFlags;
+    }
+    ci->fcdPosition = NULL;
+
+	ci->offsetReturn = NULL;
+    ci->offsetStore  = ci->offsetBuffer;
+	ci->offsetRepeatCount = ci->offsetRepeatValue = 0;
+}
+
+/**
+* Getting the mask for collation strength
+* @param strength collation strength
+* @return collation element mask
+*/
+static
+inline uint32_t getMask(UCollationStrength strength)
+{
+    switch (strength)
+    {
+    case UCOL_PRIMARY:
+        return UCOL_PRIMARYORDERMASK;
+    case UCOL_SECONDARY:
+        return UCOL_SECONDARYORDERMASK | UCOL_PRIMARYORDERMASK;
+    default:
+        return UCOL_TERTIARYORDERMASK | UCOL_SECONDARYORDERMASK |
+               UCOL_PRIMARYORDERMASK;
+    }
+}
+
+/**
+* This is to squeeze the 21bit ces into a 256 table
+* @param ce collation element
+* @return collapsed version of the collation element
+*/
+static
+inline int hash(uint32_t ce)
+{
+    // the old value UCOL_PRIMARYORDER(ce) % MAX_TABLE_SIZE_ does not work
+    // well with the new collation where most of the latin 1 characters
+    // are of the value xx000xxx. their hashes will most of the time be 0
+    // to be discussed on the hash algo.
+    return UCOL_PRIMARYORDER(ce) % MAX_TABLE_SIZE_;
+}
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+usearch_cleanup(void) {
+    fcdTrieIndex = NULL;
+    return TRUE;
+}
+U_CDECL_END
+
+/**
+* Initializing the fcd tables.
+* Internal method, status assumed to be a success.
+* @param status output error if any, caller to check status before calling
+*               method, status assumed to be success when passed in.
+*/
+static
+inline void initializeFCD(UErrorCode *status)
+{
+    if (fcdTrieIndex == NULL) {
+        fcdTrieIndex = unorm_getFCDTrieIndex(fcdHighStart, status);
+        ucln_i18n_registerCleanup(UCLN_I18N_USEARCH, usearch_cleanup);
+    }
+}
+
+/**
+* Gets the fcd value for a character at the argument index.
+* This method takes into accounts of the supplementary characters.
+* @param str UTF16 string where character for fcd retrieval resides
+* @param offset position of the character whose fcd is to be retrieved, to be
+*               overwritten with the next character position, taking
+*               surrogate characters into consideration.
+* @param strlength length of the argument string
+* @return fcd value
+*/
+static
+uint16_t getFCD(const UChar   *str, int32_t *offset,
+                             int32_t  strlength)
+{
+    const UChar *temp = str + *offset;
+    uint16_t    result = unorm_nextFCD16(fcdTrieIndex, fcdHighStart, temp, str + strlength);
+    *offset = (int32_t)(temp - str);
+    return result;
+}
+
+/**
+* Getting the modified collation elements taking into account the collation
+* attributes
+* @param strsrch string search data
+* @param sourcece
+* @return the modified collation element
+*/
+static
+inline int32_t getCE(const UStringSearch *strsrch, uint32_t sourcece)
+{
+    // note for tertiary we can't use the collator->tertiaryMask, that
+    // is a preprocessed mask that takes into account case options. since
+    // we are only concerned with exact matches, we don't need that.
+    sourcece &= strsrch->ceMask;
+
+    if (strsrch->toShift) {
+        // alternate handling here, since only the 16 most significant digits
+        // is only used, we can safely do a compare without masking
+        // if the ce is a variable, we mask and get only the primary values
+        // no shifting to quartenary is required since all primary values
+        // less than variabletop will need to be masked off anyway.
+        if (strsrch->variableTop > sourcece) {
+            if (strsrch->strength >= UCOL_QUATERNARY) {
+                sourcece &= UCOL_PRIMARYORDERMASK;
+            }
+            else {
+                sourcece = UCOL_IGNORABLE;
+            }
+        }
+    } else if (strsrch->strength >= UCOL_QUATERNARY && sourcece == UCOL_IGNORABLE) {
+        sourcece = 0xFFFF;
+    }
+
+    return sourcece;
+}
+
+/**
+* Allocate a memory and returns NULL if it failed.
+* Internal method, status assumed to be a success.
+* @param size to allocate
+* @param status output error if any, caller to check status before calling
+*               method, status assumed to be success when passed in.
+* @return newly allocated array, NULL otherwise
+*/
+static
+inline void * allocateMemory(uint32_t size, UErrorCode *status)
+{
+    uint32_t *result = (uint32_t *)uprv_malloc(size);
+    if (result == NULL) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+    }
+    return result;
+}
+
+/**
+* Adds a uint32_t value to a destination array.
+* Creates a new array if we run out of space. The caller will have to
+* manually deallocate the newly allocated array.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method. destination not to be NULL and has at least
+* size destinationlength.
+* @param destination target array
+* @param offset destination offset to add value
+* @param destinationlength target array size, return value for the new size
+* @param value to be added
+* @param increments incremental size expected
+* @param status output error if any, caller to check status before calling
+*               method, status assumed to be success when passed in.
+* @return new destination array, destination if there was no new allocation
+*/
+static
+inline int32_t * addTouint32_tArray(int32_t    *destination,
+                                    uint32_t    offset,
+                                    uint32_t   *destinationlength,
+                                    uint32_t    value,
+                                    uint32_t    increments,
+                                    UErrorCode *status)
+{
+    uint32_t newlength = *destinationlength;
+    if (offset + 1 == newlength) {
+        newlength += increments;
+        int32_t *temp = (int32_t *)allocateMemory(
+                                         sizeof(int32_t) * newlength, status);
+        if (U_FAILURE(*status)) {
+            return NULL;
+        }
+        uprv_memcpy(temp, destination, sizeof(int32_t) * offset);
+        *destinationlength = newlength;
+        destination        = temp;
+    }
+    destination[offset] = value;
+    return destination;
+}
+
+/**
+* Adds a uint64_t value to a destination array.
+* Creates a new array if we run out of space. The caller will have to
+* manually deallocate the newly allocated array.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method. destination not to be NULL and has at least
+* size destinationlength.
+* @param destination target array
+* @param offset destination offset to add value
+* @param destinationlength target array size, return value for the new size
+* @param value to be added
+* @param increments incremental size expected
+* @param status output error if any, caller to check status before calling
+*               method, status assumed to be success when passed in.
+* @return new destination array, destination if there was no new allocation
+*/
+static
+inline int64_t * addTouint64_tArray(int64_t    *destination,
+                                    uint32_t    offset,
+                                    uint32_t   *destinationlength,
+                                    uint64_t    value,
+                                    uint32_t    increments,
+                                    UErrorCode *status)
+{
+    uint32_t newlength = *destinationlength;
+    if (offset + 1 == newlength) {
+        newlength += increments;
+        int64_t *temp = (int64_t *)allocateMemory(
+                                         sizeof(int64_t) * newlength, status);
+
+        if (U_FAILURE(*status)) {
+            return NULL;
+        }
+
+        uprv_memcpy(temp, destination, sizeof(int64_t) * offset);
+        *destinationlength = newlength;
+        destination        = temp;
+    }
+
+    destination[offset] = value;
+
+    return destination;
+}
+
+/**
+* Initializing the ce table for a pattern.
+* Stores non-ignorable collation keys.
+* Table size will be estimated by the size of the pattern text. Table
+* expansion will be perform as we go along. Adding 1 to ensure that the table
+* size definitely increases.
+* Internal method, status assumed to be a success.
+* @param strsrch string search data
+* @param status output error if any, caller to check status before calling
+*               method, status assumed to be success when passed in.
+* @return total number of expansions
+*/
+static
+inline uint16_t initializePatternCETable(UStringSearch *strsrch,
+                                         UErrorCode    *status)
+{
+    UPattern *pattern            = &(strsrch->pattern);
+    uint32_t  cetablesize        = INITIAL_ARRAY_SIZE_;
+    int32_t  *cetable            = pattern->CEBuffer;
+    uint32_t  patternlength      = pattern->textLength;
+    UCollationElements *coleiter = strsrch->utilIter;
+
+    if (coleiter == NULL) {
+        coleiter = ucol_openElements(strsrch->collator, pattern->text,
+                                     patternlength, status);
+        // status will be checked in ucol_next(..) later and if it is an
+        // error UCOL_NULLORDER the result of ucol_next(..) and 0 will be
+        // returned.
+        strsrch->utilIter = coleiter;
+    }
+    else {
+        uprv_init_collIterate(strsrch->collator, pattern->text,
+                         pattern->textLength,
+                         &coleiter->iteratordata_,
+                         status);
+    }
+    if(U_FAILURE(*status)) {
+        return 0;
+    }
+
+    if (pattern->CE != cetable && pattern->CE) {
+        uprv_free(pattern->CE);
+    }
+
+    uint16_t  offset      = 0;
+    uint16_t  result      = 0;
+    int32_t   ce;
+
+    while ((ce = ucol_next(coleiter, status)) != UCOL_NULLORDER &&
+           U_SUCCESS(*status)) {
+        uint32_t newce = getCE(strsrch, ce);
+        if (newce) {
+            int32_t *temp = addTouint32_tArray(cetable, offset, &cetablesize,
+                                  newce,
+                                  patternlength - ucol_getOffset(coleiter) + 1,
+                                  status);
+            if (U_FAILURE(*status)) {
+                return 0;
+            }
+            offset ++;
+            if (cetable != temp && cetable != pattern->CEBuffer) {
+                uprv_free(cetable);
+            }
+            cetable = temp;
+        }
+        result += (uint16_t)(ucol_getMaxExpansion(coleiter, ce) - 1);
+    }
+
+    cetable[offset]   = 0;
+    pattern->CE       = cetable;
+    pattern->CELength = offset;
+
+    return result;
+}
+
+/**
+* Initializing the pce table for a pattern.
+* Stores non-ignorable collation keys.
+* Table size will be estimated by the size of the pattern text. Table
+* expansion will be perform as we go along. Adding 1 to ensure that the table
+* size definitely increases.
+* Internal method, status assumed to be a success.
+* @param strsrch string search data
+* @param status output error if any, caller to check status before calling
+*               method, status assumed to be success when passed in.
+* @return total number of expansions
+*/
+static
+inline uint16_t initializePatternPCETable(UStringSearch *strsrch,
+                                          UErrorCode    *status)
+{
+    UPattern *pattern            = &(strsrch->pattern);
+    uint32_t  pcetablesize       = INITIAL_ARRAY_SIZE_;
+    int64_t  *pcetable           = pattern->PCEBuffer;
+    uint32_t  patternlength      = pattern->textLength;
+    UCollationElements *coleiter = strsrch->utilIter;
+
+    if (coleiter == NULL) {
+        coleiter = ucol_openElements(strsrch->collator, pattern->text,
+                                     patternlength, status);
+        // status will be checked in ucol_next(..) later and if it is an
+        // error UCOL_NULLORDER the result of ucol_next(..) and 0 will be
+        // returned.
+        strsrch->utilIter = coleiter;
+    } else {
+        uprv_init_collIterate(strsrch->collator, pattern->text,
+                              pattern->textLength,
+                              &coleiter->iteratordata_,
+                              status);
+    }
+    if(U_FAILURE(*status)) {
+        return 0;
+    }
+
+    if (pattern->PCE != pcetable && pattern->PCE != NULL) {
+        uprv_free(pattern->PCE);
+    }
+
+    uint16_t  offset = 0;
+    uint16_t  result = 0;
+    int64_t   pce;
+
+    uprv_init_pce(coleiter);
+
+    // ** Should processed CEs be signed or unsigned?
+    // ** (the rest of the code in this file seems to play fast-and-loose with
+    // **  whether a CE is signed or unsigned. For example, look at routine above this one.)
+    while ((pce = ucol_nextProcessed(coleiter, NULL, NULL, status)) != UCOL_PROCESSED_NULLORDER &&
+           U_SUCCESS(*status)) {
+        int64_t *temp = addTouint64_tArray(pcetable, offset, &pcetablesize,
+                              pce,
+                              patternlength - ucol_getOffset(coleiter) + 1,
+                              status);
+
+        if (U_FAILURE(*status)) {
+            return 0;
+        }
+
+        offset += 1;
+
+        if (pcetable != temp && pcetable != pattern->PCEBuffer) {
+            uprv_free(pcetable);
+        }
+
+        pcetable = temp;
+        //result += (uint16_t)(ucol_getMaxExpansion(coleiter, ce) - 1);
+    }
+
+    pcetable[offset]   = 0;
+    pattern->PCE       = pcetable;
+    pattern->PCELength = offset;
+
+    return result;
+}
+
+/**
+* Initializes the pattern struct.
+* Internal method, status assumed to be success.
+* @param strsrch UStringSearch data storage
+* @param status output error if any, caller to check status before calling
+*               method, status assumed to be success when passed in.
+* @return expansionsize the total expansion size of the pattern
+*/
+static
+inline int16_t initializePattern(UStringSearch *strsrch, UErrorCode *status)
+{
+          UPattern   *pattern     = &(strsrch->pattern);
+    const UChar      *patterntext = pattern->text;
+          int32_t     length      = pattern->textLength;
+          int32_t index       = 0;
+
+    // Since the strength is primary, accents are ignored in the pattern.
+    if (strsrch->strength == UCOL_PRIMARY) {
+    	pattern->hasPrefixAccents = 0;
+    	pattern->hasSuffixAccents = 0;
+    } else {
+	    pattern->hasPrefixAccents = getFCD(patterntext, &index, length) >>
+	                                                     SECOND_LAST_BYTE_SHIFT_;
+	    index = length;
+	    UTF_BACK_1(patterntext, 0, index);
+	    pattern->hasSuffixAccents = getFCD(patterntext, &index, length) &
+	                                                             LAST_BYTE_MASK_;
+    }
+
+    // ** HACK **
+    if (strsrch->pattern.PCE != NULL) {
+        if (strsrch->pattern.PCE != strsrch->pattern.PCEBuffer) {
+            uprv_free(strsrch->pattern.PCE);
+        }
+
+        strsrch->pattern.PCE = NULL;
+    }
+
+    // since intializePattern is an internal method status is a success.
+    return initializePatternCETable(strsrch, status);
+}
+
+/**
+* Initializing shift tables, with the default values.
+* If a corresponding default value is 0, the shift table is not set.
+* @param shift table for forwards shift
+* @param backshift table for backwards shift
+* @param cetable table containing pattern ce
+* @param cesize size of the pattern ces
+* @param expansionsize total size of the expansions
+* @param defaultforward the default forward value
+* @param defaultbackward the default backward value
+*/
+static
+inline void setShiftTable(int16_t   shift[], int16_t backshift[],
+                          int32_t  *cetable, int32_t cesize,
+                          int16_t   expansionsize,
+                          int16_t   defaultforward,
+                          int16_t   defaultbackward)
+{
+    // estimate the value to shift. to do that we estimate the smallest
+    // number of characters to give the relevant ces, ie approximately
+    // the number of ces minus their expansion, since expansions can come
+    // from a character.
+    int32_t count;
+    for (count = 0; count < MAX_TABLE_SIZE_; count ++) {
+        shift[count] = defaultforward;
+    }
+    cesize --; // down to the last index
+    for (count = 0; count < cesize; count ++) {
+        // number of ces from right of array to the count
+        int temp = defaultforward - count - 1;
+        shift[hash(cetable[count])] = temp > 1 ? temp : 1;
+    }
+    shift[hash(cetable[cesize])] = 1;
+    // for ignorables we just shift by one. see test examples.
+    shift[hash(0)] = 1;
+
+    for (count = 0; count < MAX_TABLE_SIZE_; count ++) {
+        backshift[count] = defaultbackward;
+    }
+    for (count = cesize; count > 0; count --) {
+        // the original value count does not seem to work
+        backshift[hash(cetable[count])] = count > expansionsize ?
+                                          (int16_t)(count - expansionsize) : 1;
+    }
+    backshift[hash(cetable[0])] = 1;
+    backshift[hash(0)] = 1;
+}
+
+/**
+* Building of the pattern collation element list and the boyer moore strsrch
+* table.
+* The canonical match will only be performed after the default match fails.
+* For both cases we need to remember the size of the composed and decomposed
+* versions of the string. Since the Boyer-Moore shift calculations shifts by
+* a number of characters in the text and tries to match the pattern from that
+* offset, the shift value can not be too large in case we miss some
+* characters. To choose a right shift size, we estimate the NFC form of the
+* and use its size as a shift guide. The NFC form should be the small
+* possible representation of the pattern. Anyways, we'll err on the smaller
+* shift size. Hence the calculation for minlength.
+* Canonical match will be performed slightly differently. We'll split the
+* pattern into 3 parts, the prefix accents (PA), the middle string bounded by
+* the first and last base character (MS), the ending accents (EA). Matches
+* will be done on MS first, and only when we match MS then some processing
+* will be required for the prefix and end accents in order to determine if
+* they match PA and EA. Hence the default shift values
+* for the canonical match will take the size of either end's accent into
+* consideration. Forwards search will take the end accents into consideration
+* for the default shift values and the backwards search will take the prefix
+* accents into consideration.
+* If pattern has no non-ignorable ce, we return a illegal argument error.
+* Internal method, status assumed to be success.
+* @param strsrch UStringSearch data storage
+* @param status  for output errors if it occurs, status is assumed to be a
+*                success when it is passed in.
+*/
+static
+inline void initialize(UStringSearch *strsrch, UErrorCode *status)
+{
+    int16_t expandlength  = initializePattern(strsrch, status);
+    if (U_SUCCESS(*status) && strsrch->pattern.CELength > 0) {
+        UPattern *pattern = &strsrch->pattern;
+        int32_t   cesize  = pattern->CELength;
+
+        int16_t minlength = cesize > expandlength
+                            ? (int16_t)cesize - expandlength : 1;
+        pattern->defaultShiftSize    = minlength;
+        setShiftTable(pattern->shift, pattern->backShift, pattern->CE,
+                      cesize, expandlength, minlength, minlength);
+        return;
+    }
+    strsrch->pattern.defaultShiftSize = 0;
+}
+
+#if BOYER_MOORE
+/**
+* Check to make sure that the match length is at the end of the character by
+* using the breakiterator.
+* @param strsrch string search data
+* @param start target text start offset
+* @param end target text end offset
+*/
+static
+void checkBreakBoundary(const UStringSearch *strsrch, int32_t * /*start*/,
+                               int32_t *end)
+{
+#if !UCONFIG_NO_BREAK_ITERATION
+    UBreakIterator *breakiterator = strsrch->search->internalBreakIter;
+    if (breakiterator) {
+	    int32_t matchend = *end;
+	    //int32_t matchstart = *start;
+
+	    if (!ubrk_isBoundary(breakiterator, matchend)) {
+	    	*end = ubrk_following(breakiterator, matchend);
+        }
+
+	    /* Check the start of the matched text to make sure it doesn't have any accents
+	     * before it.  This code may not be necessary and so it is commented out */
+	    /*if (!ubrk_isBoundary(breakiterator, matchstart) && !ubrk_isBoundary(breakiterator, matchstart-1)) {
+	    	*start = ubrk_preceding(breakiterator, matchstart);
+	    }*/
+    }
+#endif
+}
+
+/**
+* Determine whether the target text in UStringSearch bounded by the offset
+* start and end is one or more whole units of text as
+* determined by the breakiterator in UStringSearch.
+* @param strsrch string search data
+* @param start target text start offset
+* @param end target text end offset
+*/
+static
+UBool isBreakUnit(const UStringSearch *strsrch, int32_t start,
+                               int32_t    end)
+{
+#if !UCONFIG_NO_BREAK_ITERATION
+    UBreakIterator *breakiterator = strsrch->search->breakIter;
+    //TODO: Add here.
+    if (breakiterator) {
+        int32_t startindex = ubrk_first(breakiterator);
+        int32_t endindex   = ubrk_last(breakiterator);
+
+        // out-of-range indexes are never boundary positions
+        if (start < startindex || start > endindex ||
+            end < startindex || end > endindex) {
+            return FALSE;
+        }
+        // otherwise, we can use following() on the position before the
+        // specified one and return true of the position we get back is the
+        // one the user specified
+        UBool result = (start == startindex ||
+                ubrk_following(breakiterator, start - 1) == start) &&
+               (end == endindex ||
+                ubrk_following(breakiterator, end - 1) == end);
+        if (result) {
+            // iterates the individual ces
+                  UCollationElements *coleiter  = strsrch->utilIter;
+            const UChar              *text      = strsrch->search->text +
+                                                                      start;
+                  UErrorCode          status    = U_ZERO_ERROR;
+            ucol_setText(coleiter, text, end - start, &status);
+            for (int32_t count = 0; count < strsrch->pattern.CELength;
+                 count ++) {
+                int32_t ce = getCE(strsrch, ucol_next(coleiter, &status));
+                if (ce == UCOL_IGNORABLE) {
+                    count --;
+                    continue;
+                }
+                if (U_FAILURE(status) || ce != strsrch->pattern.CE[count]) {
+                    return FALSE;
+                }
+            }
+            int32_t nextce = ucol_next(coleiter, &status);
+            while (ucol_getOffset(coleiter) == (end - start)
+                   && getCE(strsrch, nextce) == UCOL_IGNORABLE) {
+                nextce = ucol_next(coleiter, &status);
+            }
+            if (ucol_getOffset(coleiter) == (end - start)
+                && nextce != UCOL_NULLORDER) {
+                // extra collation elements at the end of the match
+                return FALSE;
+            }
+        }
+        return result;
+    }
+#endif
+    return TRUE;
+}
+
+/**
+* Getting the next base character offset if current offset is an accent,
+* or the current offset if the current character contains a base character.
+* accents the following base character will be returned
+* @param text string
+* @param textoffset current offset
+* @param textlength length of text string
+* @return the next base character or the current offset
+*         if the current character is contains a base character.
+*/
+static
+inline int32_t getNextBaseOffset(const UChar       *text,
+                                           int32_t  textoffset,
+                                           int32_t      textlength)
+{
+    if (textoffset < textlength) {
+        int32_t temp = textoffset;
+        if (getFCD(text, &temp, textlength) >> SECOND_LAST_BYTE_SHIFT_) {
+            while (temp < textlength) {
+                int32_t result = temp;
+                if ((getFCD(text, &temp, textlength) >>
+                     SECOND_LAST_BYTE_SHIFT_) == 0) {
+                    return result;
+                }
+            }
+            return textlength;
+        }
+    }
+    return textoffset;
+}
+
+/**
+* Gets the next base character offset depending on the string search pattern
+* data
+* @param strsrch string search data
+* @param textoffset current offset, one offset away from the last character
+*                   to search for.
+* @return start index of the next base character or the current offset
+*         if the current character is contains a base character.
+*/
+static
+inline int32_t getNextUStringSearchBaseOffset(UStringSearch *strsrch,
+                                                  int32_t    textoffset)
+{
+    int32_t textlength = strsrch->search->textLength;
+    if (strsrch->pattern.hasSuffixAccents &&
+        textoffset < textlength) {
+              int32_t  temp       = textoffset;
+        const UChar       *text       = strsrch->search->text;
+        UTF_BACK_1(text, 0, temp);
+        if (getFCD(text, &temp, textlength) & LAST_BYTE_MASK_) {
+            return getNextBaseOffset(text, textoffset, textlength);
+        }
+    }
+    return textoffset;
+}
+
+/**
+* Shifting the collation element iterator position forward to prepare for
+* a following match. If the last character is a unsafe character, we'll only
+* shift by 1 to capture contractions, normalization etc.
+* Internal method, status assumed to be success.
+* @param text strsrch string search data
+* @param textoffset start text position to do search
+* @param ce the text ce which failed the match.
+* @param patternceindex index of the ce within the pattern ce buffer which
+*        failed the match
+* @return final offset
+*/
+static
+inline int32_t shiftForward(UStringSearch *strsrch,
+                                int32_t    textoffset,
+                                int32_t       ce,
+                                int32_t        patternceindex)
+{
+    UPattern *pattern = &(strsrch->pattern);
+    if (ce != UCOL_NULLORDER) {
+        int32_t shift = pattern->shift[hash(ce)];
+        // this is to adjust for characters in the middle of the
+        // substring for matching that failed.
+        int32_t adjust = pattern->CELength - patternceindex;
+        if (adjust > 1 && shift >= adjust) {
+            shift -= adjust - 1;
+        }
+        textoffset += shift;
+    }
+    else {
+        textoffset += pattern->defaultShiftSize;
+    }
+
+    textoffset = getNextUStringSearchBaseOffset(strsrch, textoffset);
+    // check for unsafe characters
+    // * if it is the start or middle of a contraction: to be done after
+    //   a initial match is found
+    // * thai or lao base consonant character: similar to contraction
+    // * high surrogate character: similar to contraction
+    // * next character is a accent: shift to the next base character
+    return textoffset;
+}
+#endif // #if BOYER_MOORE
+
+/**
+* sets match not found
+* @param strsrch string search data
+*/
+static
+inline void setMatchNotFound(UStringSearch *strsrch)
+{
+    // this method resets the match result regardless of the error status.
+    strsrch->search->matchedIndex = USEARCH_DONE;
+    strsrch->search->matchedLength = 0;
+    if (strsrch->search->isForwardSearching) {
+        setColEIterOffset(strsrch->textIter, strsrch->search->textLength);
+    }
+    else {
+        setColEIterOffset(strsrch->textIter, 0);
+    }
+}
+
+#if BOYER_MOORE
+/**
+* Gets the offset to the next safe point in text.
+* ie. not the middle of a contraction, swappable characters or supplementary
+* characters.
+* @param collator collation sata
+* @param text string to work with
+* @param textoffset offset in string
+* @param textlength length of text string
+* @return offset to the next safe character
+*/
+static
+inline int32_t getNextSafeOffset(const UCollator   *collator,
+                                     const UChar       *text,
+                                           int32_t  textoffset,
+                                           int32_t      textlength)
+{
+    int32_t result = textoffset; // first contraction character
+    while (result != textlength && ucol_unsafeCP(text[result], collator)) {
+        result ++;
+    }
+    return result;
+}
+
+/**
+* This checks for accents in the potential match started with a .
+* composite character.
+* This is really painful... we have to check that composite character do not
+* have any extra accents. We have to normalize the potential match and find
+* the immediate decomposed character before the match.
+* The first composite character would have been taken care of by the fcd
+* checks in checkForwardExactMatch.
+* This is the slow path after the fcd of the first character and
+* the last character has been checked by checkForwardExactMatch and we
+* determine that the potential match has extra non-ignorable preceding
+* ces.
+* E.g. looking for \u0301 acute in \u01FA A ring above and acute,
+* checkExtraMatchAccent should fail since there is a middle ring in \u01FA
+* Note here that accents checking are slow and cautioned in the API docs.
+* Internal method, status assumed to be a success, caller should check status
+* before calling this method
+* @param strsrch string search data
+* @param start index of the potential unfriendly composite character
+* @param end index of the potential unfriendly composite character
+* @param status output error status if any.
+* @return TRUE if there is non-ignorable accents before at the beginning
+*              of the match, FALSE otherwise.
+*/
+
+static
+UBool checkExtraMatchAccents(const UStringSearch *strsrch, int32_t start,
+                                   int32_t    end,
+                                   UErrorCode    *status)
+{
+    UBool result = FALSE;
+    if (strsrch->pattern.hasPrefixAccents) {
+              int32_t  length = end - start;
+              int32_t  offset = 0;
+        const UChar       *text   = strsrch->search->text + start;
+
+        UTF_FWD_1(text, offset, length);
+        // we are only concerned with the first composite character
+        if (unorm_quickCheck(text, offset, UNORM_NFD, status) == UNORM_NO) {
+            int32_t safeoffset = getNextSafeOffset(strsrch->collator,
+                                                       text, 0, length);
+            if (safeoffset != length) {
+                safeoffset ++;
+            }
+            UChar   *norm = NULL;
+            UChar    buffer[INITIAL_ARRAY_SIZE_];
+            int32_t  size = unorm_normalize(text, safeoffset, UNORM_NFD, 0,
+                                            buffer, INITIAL_ARRAY_SIZE_,
+                                            status);
+            if (U_FAILURE(*status)) {
+                return FALSE;
+            }
+            if (size >= INITIAL_ARRAY_SIZE_) {
+                norm = (UChar *)allocateMemory((size + 1) * sizeof(UChar),
+                                               status);
+                // if allocation failed, status will be set to
+                // U_MEMORY_ALLOCATION_ERROR and unorm_normalize internally
+                // checks for it.
+                size = unorm_normalize(text, safeoffset, UNORM_NFD, 0, norm,
+                                       size, status);
+                if (U_FAILURE(*status) && norm != NULL) {
+                    uprv_free(norm);
+                    return FALSE;
+                }
+            }
+            else {
+                norm = buffer;
+            }
+
+            UCollationElements *coleiter  = strsrch->utilIter;
+            ucol_setText(coleiter, norm, size, status);
+            uint32_t            firstce   = strsrch->pattern.CE[0];
+            UBool               ignorable = TRUE;
+            uint32_t            ce        = UCOL_IGNORABLE;
+            while (U_SUCCESS(*status) && ce != firstce && ce != (uint32_t)UCOL_NULLORDER) {
+                offset = ucol_getOffset(coleiter);
+                if (ce != firstce && ce != UCOL_IGNORABLE) {
+                    ignorable = FALSE;
+                }
+                ce = ucol_next(coleiter, status);
+            }
+            UChar32 codepoint;
+            UTF_PREV_CHAR(norm, 0, offset, codepoint);
+            result = !ignorable && (u_getCombiningClass(codepoint) != 0);
+
+            if (norm != buffer) {
+                uprv_free(norm);
+            }
+        }
+    }
+
+    return result;
+}
+
+/**
+* Used by exact matches, checks if there are accents before the match.
+* This is really painful... we have to check that composite characters at
+* the start of the matches have to not have any extra accents.
+* We check the FCD of the character first, if it starts with an accent and
+* the first pattern ce does not match the first ce of the character, we bail.
+* Otherwise we try normalizing the first composite
+* character and find the immediate decomposed character before the match to
+* see if it is an non-ignorable accent.
+* Now normalizing the first composite character is enough because we ensure
+* that when the match is passed in here with extra beginning ces, the
+* first or last ce that match has to occur within the first character.
+* E.g. looking for \u0301 acute in \u01FA A ring above and acute,
+* checkExtraMatchAccent should fail since there is a middle ring in \u01FA
+* Note here that accents checking are slow and cautioned in the API docs.
+* @param strsrch string search data
+* @param start offset
+* @param end offset
+* @return TRUE if there are accents on either side of the match,
+*         FALSE otherwise
+*/
+static
+UBool hasAccentsBeforeMatch(const UStringSearch *strsrch, int32_t start,
+                                  int32_t    end)
+{
+    if (strsrch->pattern.hasPrefixAccents) {
+        UCollationElements *coleiter  = strsrch->textIter;
+        UErrorCode          status    = U_ZERO_ERROR;
+        // we have been iterating forwards previously
+        uint32_t            ignorable = TRUE;
+        int32_t             firstce   = strsrch->pattern.CE[0];
+
+        setColEIterOffset(coleiter, start);
+        int32_t ce  = getCE(strsrch, ucol_next(coleiter, &status));
+        if (U_FAILURE(status)) {
+            return TRUE;
+        }
+        while (ce != firstce) {
+            if (ce != UCOL_IGNORABLE) {
+                ignorable = FALSE;
+            }
+            ce = getCE(strsrch, ucol_next(coleiter, &status));
+            if (U_FAILURE(status) || ce == UCOL_NULLORDER) {
+                return TRUE;
+            }
+        }
+        if (!ignorable && inNormBuf(coleiter)) {
+            // within normalization buffer, discontiguous handled here
+            return TRUE;
+        }
+
+        // within text
+        int32_t temp = start;
+        // original code
+        // accent = (getFCD(strsrch->search->text, &temp,
+        //                  strsrch->search->textLength)
+        //            >> SECOND_LAST_BYTE_SHIFT_);
+        // however this code does not work well with VC7 .net in release mode.
+        // maybe the inlines for getFCD combined with shifting has bugs in
+        // VC7. anyways this is a work around.
+        UBool accent = getFCD(strsrch->search->text, &temp,
+                              strsrch->search->textLength) > 0xFF;
+        if (!accent) {
+            return checkExtraMatchAccents(strsrch, start, end, &status);
+        }
+        if (!ignorable) {
+            return TRUE;
+        }
+        if (start > 0) {
+            temp = start;
+            UTF_BACK_1(strsrch->search->text, 0, temp);
+            if (getFCD(strsrch->search->text, &temp,
+                       strsrch->search->textLength) & LAST_BYTE_MASK_) {
+                setColEIterOffset(coleiter, start);
+                ce = ucol_previous(coleiter, &status);
+                if (U_FAILURE(status) ||
+                    (ce != UCOL_NULLORDER && ce != UCOL_IGNORABLE)) {
+                    return TRUE;
+                }
+            }
+        }
+    }
+
+    return FALSE;
+}
+
+/**
+* Used by exact matches, checks if there are accents bounding the match.
+* Note this is the initial boundary check. If the potential match
+* starts or ends with composite characters, the accents in those
+* characters will be determined later.
+* Not doing backwards iteration here, since discontiguos contraction for
+* backwards collation element iterator, use up too many characters.
+* E.g. looking for \u030A ring in \u01FA A ring above and acute,
+* should fail since there is a acute at the end of \u01FA
+* Note here that accents checking are slow and cautioned in the API docs.
+* @param strsrch string search data
+* @param start offset of match
+* @param end end offset of the match
+* @return TRUE if there are accents on either side of the match,
+*         FALSE otherwise
+*/
+static
+UBool hasAccentsAfterMatch(const UStringSearch *strsrch, int32_t start,
+                                 int32_t    end)
+{
+    if (strsrch->pattern.hasSuffixAccents) {
+        const UChar       *text       = strsrch->search->text;
+              int32_t  temp       = end;
+              int32_t      textlength = strsrch->search->textLength;
+        UTF_BACK_1(text, 0, temp);
+        if (getFCD(text, &temp, textlength) & LAST_BYTE_MASK_) {
+            int32_t             firstce  = strsrch->pattern.CE[0];
+            UCollationElements *coleiter = strsrch->textIter;
+            UErrorCode          status   = U_ZERO_ERROR;
+			int32_t ce;
+            setColEIterOffset(coleiter, start);
+            while ((ce = getCE(strsrch, ucol_next(coleiter, &status))) != firstce) {
+                if (U_FAILURE(status) || ce == UCOL_NULLORDER) {
+                    return TRUE;
+                }
+            }
+            int32_t count = 1;
+            while (count < strsrch->pattern.CELength) {
+                if (getCE(strsrch, ucol_next(coleiter, &status))
+                    == UCOL_IGNORABLE) {
+                    // Thai can give an ignorable here.
+                    count --;
+                }
+                if (U_FAILURE(status)) {
+                    return TRUE;
+                }
+                count ++;
+            }
+
+			ce = ucol_next(coleiter, &status);
+            if (U_FAILURE(status)) {
+                return TRUE;
+            }
+            if (ce != UCOL_NULLORDER && ce != UCOL_IGNORABLE) {
+            	ce = getCE(strsrch, ce);
+            }
+            if (ce != UCOL_NULLORDER && ce != UCOL_IGNORABLE) {
+                if (ucol_getOffset(coleiter) <= end) {
+                    return TRUE;
+                }
+                if (getFCD(text, &end, textlength) >> SECOND_LAST_BYTE_SHIFT_) {
+                    return TRUE;
+                }
+            }
+        }
+    }
+    return FALSE;
+}
+#endif // #if BOYER_MOORE
+
+/**
+* Checks if the offset runs out of the text string
+* @param offset
+* @param textlength of the text string
+* @return TRUE if offset is out of bounds, FALSE otherwise
+*/
+static
+inline UBool isOutOfBounds(int32_t textlength, int32_t offset)
+{
+    return offset < 0 || offset > textlength;
+}
+
+/**
+* Checks for identical match
+* @param strsrch string search data
+* @param start offset of possible match
+* @param end offset of possible match
+* @return TRUE if identical match is found
+*/
+static
+inline UBool checkIdentical(const UStringSearch *strsrch, int32_t start,
+                                  int32_t    end)
+{
+    if (strsrch->strength != UCOL_IDENTICAL) {
+        return TRUE;
+    }
+
+    // Note: We could use Normalizer::compare() or similar, but for short strings
+    // which may not be in FCD it might be faster to just NFD them.
+    UErrorCode status = U_ZERO_ERROR;
+    UnicodeString t2, p2;
+    strsrch->nfd->normalize(
+        UnicodeString(FALSE, strsrch->search->text + start, end - start), t2, status);
+    strsrch->nfd->normalize(
+        UnicodeString(FALSE, strsrch->pattern.text, strsrch->pattern.textLength), p2, status);
+    // return FALSE if NFD failed
+    return U_SUCCESS(status) && t2 == p2;
+}
+
+#if BOYER_MOORE
+/**
+* Checks to see if the match is repeated
+* @param strsrch string search data
+* @param start new match start index
+* @param end new match end index
+* @return TRUE if the the match is repeated, FALSE otherwise
+*/
+static
+inline UBool checkRepeatedMatch(UStringSearch *strsrch,
+                                int32_t    start,
+                                int32_t    end)
+{
+    int32_t lastmatchindex = strsrch->search->matchedIndex;
+    UBool       result;
+    if (lastmatchindex == USEARCH_DONE) {
+        return FALSE;
+    }
+    if (strsrch->search->isForwardSearching) {
+        result = start <= lastmatchindex;
+    }
+    else {
+        result = start >= lastmatchindex;
+    }
+    if (!result && !strsrch->search->isOverlap) {
+        if (strsrch->search->isForwardSearching) {
+            result = start < lastmatchindex + strsrch->search->matchedLength;
+        }
+        else {
+            result = end > lastmatchindex;
+        }
+    }
+    return result;
+}
+
+/**
+* Gets the collation element iterator's current offset.
+* @param coleiter collation element iterator
+* @param forwards flag TRUE if we are moving in th forwards direction
+* @return current offset
+*/
+static
+inline int32_t getColElemIterOffset(const UCollationElements *coleiter,
+                                              UBool               forwards)
+{
+    int32_t result = ucol_getOffset(coleiter);
+    // intricacies of the the backwards collation element iterator
+    if (FALSE && !forwards && inNormBuf(coleiter) && !isFCDPointerNull(coleiter)) {
+        result ++;
+    }
+    return result;
+}
+
+/**
+* Checks match for contraction.
+* If the match ends with a partial contraction we fail.
+* If the match starts too far off (because of backwards iteration) we try to
+* chip off the extra characters depending on whether a breakiterator has
+* been used.
+* Internal method, error assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param start offset of potential match, to be modified if necessary
+* @param end offset of potential match, to be modified if necessary
+* @param status output error status if any
+* @return TRUE if match passes the contraction test, FALSE otherwise
+*/
+
+static
+UBool checkNextExactContractionMatch(UStringSearch *strsrch,
+                                     int32_t   *start,
+                                     int32_t   *end, UErrorCode  *status)
+{
+          UCollationElements *coleiter   = strsrch->textIter;
+          int32_t             textlength = strsrch->search->textLength;
+          int32_t             temp       = *start;
+    const UCollator          *collator   = strsrch->collator;
+    const UChar              *text       = strsrch->search->text;
+    // This part checks if either ends of the match contains potential
+    // contraction. If so we'll have to iterate through them
+    // The start contraction needs to be checked since ucol_previous dumps
+    // all characters till the first safe character into the buffer.
+    // *start + 1 is used to test for the unsafe characters instead of *start
+    // because ucol_prev takes all unsafe characters till the first safe
+    // character ie *start. so by testing *start + 1, we can estimate if
+    // excess prefix characters has been included in the potential search
+    // results.
+    if ((*end < textlength && ucol_unsafeCP(text[*end], collator)) ||
+        (*start + 1 < textlength
+         && ucol_unsafeCP(text[*start + 1], collator))) {
+        int32_t expansion  = getExpansionPrefix(coleiter);
+        UBool   expandflag = expansion > 0;
+        setColEIterOffset(coleiter, *start);
+        while (expansion > 0) {
+            // getting rid of the redundant ce, caused by setOffset.
+            // since backward contraction/expansion may have extra ces if we
+            // are in the normalization buffer, hasAccentsBeforeMatch would
+            // have taken care of it.
+            // E.g. the character \u01FA will have an expansion of 3, but if
+            // we are only looking for acute and ring \u030A and \u0301, we'll
+            // have to skip the first ce in the expansion buffer.
+            ucol_next(coleiter, status);
+            if (U_FAILURE(*status)) {
+                return FALSE;
+            }
+            if (ucol_getOffset(coleiter) != temp) {
+                *start = temp;
+                temp  = ucol_getOffset(coleiter);
+            }
+            expansion --;
+        }
+
+        int32_t  *patternce       = strsrch->pattern.CE;
+        int32_t   patterncelength = strsrch->pattern.CELength;
+        int32_t   count           = 0;
+        while (count < patterncelength) {
+            int32_t ce = getCE(strsrch, ucol_next(coleiter, status));
+            if (ce == UCOL_IGNORABLE) {
+                continue;
+            }
+            if (expandflag && count == 0 && ucol_getOffset(coleiter) != temp) {
+                *start = temp;
+                temp   = ucol_getOffset(coleiter);
+            }
+            if (U_FAILURE(*status) || ce != patternce[count]) {
+                (*end) ++;
+                *end = getNextUStringSearchBaseOffset(strsrch, *end);
+                return FALSE;
+            }
+            count ++;
+        }
+    }
+    return TRUE;
+}
+
+/**
+* Checks and sets the match information if found.
+* Checks
+* <ul>
+* <li> the potential match does not repeat the previous match
+* <li> boundaries are correct
+* <li> exact matches has no extra accents
+* <li> identical matchesb
+* <li> potential match does not end in the middle of a contraction
+* <\ul>
+* Otherwise the offset will be shifted to the next character.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param textoffset offset in the collation element text. the returned value
+*        will be the truncated end offset of the match or the new start
+*        search offset.
+* @param status output error status if any
+* @return TRUE if the match is valid, FALSE otherwise
+*/
+static
+inline UBool checkNextExactMatch(UStringSearch *strsrch,
+                                 int32_t   *textoffset, UErrorCode *status)
+{
+    UCollationElements *coleiter = strsrch->textIter;
+    int32_t         start    = getColElemIterOffset(coleiter, FALSE);
+
+    if (!checkNextExactContractionMatch(strsrch, &start, textoffset, status)) {
+        return FALSE;
+    }
+
+    // this totally matches, however we need to check if it is repeating
+    if (!isBreakUnit(strsrch, start, *textoffset) ||
+        checkRepeatedMatch(strsrch, start, *textoffset) ||
+        hasAccentsBeforeMatch(strsrch, start, *textoffset) ||
+        !checkIdentical(strsrch, start, *textoffset) ||
+        hasAccentsAfterMatch(strsrch, start, *textoffset)) {
+
+        (*textoffset) ++;
+        *textoffset = getNextUStringSearchBaseOffset(strsrch, *textoffset);
+        return FALSE;
+    }
+
+    //Add breakiterator boundary check for primary strength search.
+    if (!strsrch->search->breakIter && strsrch->strength == UCOL_PRIMARY) {
+    	checkBreakBoundary(strsrch, &start, textoffset);
+    }
+
+    // totally match, we will get rid of the ending ignorables.
+    strsrch->search->matchedIndex  = start;
+    strsrch->search->matchedLength = *textoffset - start;
+    return TRUE;
+}
+
+/**
+* Getting the previous base character offset, or the current offset if the
+* current character is a base character
+* @param text string
+* @param textoffset one offset after the current character
+* @return the offset of the next character after the base character or the first
+*         composed character with accents
+*/
+static
+inline int32_t getPreviousBaseOffset(const UChar       *text,
+                                               int32_t  textoffset)
+{
+    if (textoffset > 0) {
+        for (;;) {
+            int32_t result = textoffset;
+            UTF_BACK_1(text, 0, textoffset);
+            int32_t temp = textoffset;
+            uint16_t fcd = getFCD(text, &temp, result);
+            if ((fcd >> SECOND_LAST_BYTE_SHIFT_) == 0) {
+                if (fcd & LAST_BYTE_MASK_) {
+                    return textoffset;
+                }
+                return result;
+            }
+            if (textoffset == 0) {
+                return 0;
+            }
+        }
+    }
+    return textoffset;
+}
+
+/**
+* Getting the indexes of the accents that are not blocked in the argument
+* accent array
+* @param accents array of accents in nfd terminated by a 0.
+* @param accentsindex array of indexes of the accents that are not blocked
+*/
+static
+inline int getUnblockedAccentIndex(UChar *accents, int32_t *accentsindex)
+{
+    int32_t index     = 0;
+    int32_t     length    = u_strlen(accents);
+    UChar32     codepoint = 0;
+    int         cclass    = 0;
+    int         result    = 0;
+    int32_t temp;
+    while (index < length) {
+        temp = index;
+        UTF_NEXT_CHAR(accents, index, length, codepoint);
+        if (u_getCombiningClass(codepoint) != cclass) {
+            cclass        = u_getCombiningClass(codepoint);
+            accentsindex[result] = temp;
+            result ++;
+        }
+    }
+    accentsindex[result] = length;
+    return result;
+}
+
+/**
+* Appends 3 UChar arrays to a destination array.
+* Creates a new array if we run out of space. The caller will have to
+* manually deallocate the newly allocated array.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method. destination not to be NULL and has at least
+* size destinationlength.
+* @param destination target array
+* @param destinationlength target array size, returning the appended length
+* @param source1 null-terminated first array
+* @param source2 second array
+* @param source2length length of seond array
+* @param source3 null-terminated third array
+* @param status error status if any
+* @return new destination array, destination if there was no new allocation
+*/
+static
+inline UChar * addToUCharArray(      UChar      *destination,
+                                     int32_t    *destinationlength,
+                               const UChar      *source1,
+                               const UChar      *source2,
+                                     int32_t     source2length,
+                               const UChar      *source3,
+                                     UErrorCode *status)
+{
+    int32_t source1length = source1 ? u_strlen(source1) : 0;
+    int32_t source3length = source3 ? u_strlen(source3) : 0;
+    if (*destinationlength < source1length + source2length + source3length +
+                                                                           1)
+    {
+        destination = (UChar *)allocateMemory(
+          (source1length + source2length + source3length + 1) * sizeof(UChar),
+          status);
+        // if error allocating memory, status will be
+        // U_MEMORY_ALLOCATION_ERROR
+        if (U_FAILURE(*status)) {
+            *destinationlength = 0;
+            return NULL;
+        }
+    }
+    if (source1length != 0) {
+        uprv_memcpy(destination, source1, sizeof(UChar) * source1length);
+    }
+    if (source2length != 0) {
+        uprv_memcpy(destination + source1length, source2,
+                    sizeof(UChar) * source2length);
+    }
+    if (source3length != 0) {
+        uprv_memcpy(destination + source1length + source2length, source3,
+                    sizeof(UChar) * source3length);
+    }
+    *destinationlength = source1length + source2length + source3length;
+    return destination;
+}
+
+/**
+* Running through a collation element iterator to see if the contents matches
+* pattern in string search data
+* @param strsrch string search data
+* @param coleiter collation element iterator
+* @return TRUE if a match if found, FALSE otherwise
+*/
+static
+inline UBool checkCollationMatch(const UStringSearch      *strsrch,
+                                       UCollationElements *coleiter)
+{
+    int         patternceindex = strsrch->pattern.CELength;
+    int32_t    *patternce      = strsrch->pattern.CE;
+    UErrorCode  status = U_ZERO_ERROR;
+    while (patternceindex > 0) {
+        int32_t ce = getCE(strsrch, ucol_next(coleiter, &status));
+        if (ce == UCOL_IGNORABLE) {
+            continue;
+        }
+        if (U_FAILURE(status) || ce != *patternce) {
+            return FALSE;
+        }
+        patternce ++;
+        patternceindex --;
+    }
+    return TRUE;
+}
+
+/**
+* Rearranges the front accents to try matching.
+* Prefix accents in the text will be grouped according to their combining
+* class and the groups will be mixed and matched to try find the perfect
+* match with the pattern.
+* So for instance looking for "\u0301" in "\u030A\u0301\u0325"
+* step 1: split "\u030A\u0301" into 6 other type of potential accent substrings
+*         "\u030A", "\u0301", "\u0325", "\u030A\u0301", "\u030A\u0325",
+*         "\u0301\u0325".
+* step 2: check if any of the generated substrings matches the pattern.
+* Internal method, status is assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search match
+* @param start first offset of the accents to start searching
+* @param end start of the last accent set
+* @param status output error status if any
+* @return USEARCH_DONE if a match is not found, otherwise return the starting
+*         offset of the match. Note this start includes all preceding accents.
+*/
+static
+int32_t doNextCanonicalPrefixMatch(UStringSearch *strsrch,
+                                       int32_t    start,
+                                       int32_t    end,
+                                       UErrorCode    *status)
+{
+    const UChar       *text       = strsrch->search->text;
+          int32_t      textlength = strsrch->search->textLength;
+          int32_t  tempstart  = start;
+
+    if ((getFCD(text, &tempstart, textlength) & LAST_BYTE_MASK_) == 0) {
+        // die... failed at a base character
+        return USEARCH_DONE;
+    }
+
+    int32_t offset = getNextBaseOffset(text, tempstart, textlength);
+    start = getPreviousBaseOffset(text, tempstart);
+
+    UChar       accents[INITIAL_ARRAY_SIZE_];
+    // normalizing the offensive string
+    unorm_normalize(text + start, offset - start, UNORM_NFD, 0, accents,
+                    INITIAL_ARRAY_SIZE_, status);
+    if (U_FAILURE(*status)) {
+        return USEARCH_DONE;
+    }
+
+    int32_t         accentsindex[INITIAL_ARRAY_SIZE_];
+    int32_t         accentsize = getUnblockedAccentIndex(accents,
+                                                                 accentsindex);
+    int32_t         count      = (2 << (accentsize - 1)) - 1;
+    UChar               buffer[INITIAL_ARRAY_SIZE_];
+    UCollationElements *coleiter   = strsrch->utilIter;
+    while (U_SUCCESS(*status) && count > 0) {
+        UChar *rearrange = strsrch->canonicalPrefixAccents;
+        // copy the base characters
+        for (int k = 0; k < accentsindex[0]; k ++) {
+            *rearrange ++ = accents[k];
+        }
+        // forming all possible canonical rearrangement by dropping
+        // sets of accents
+        for (int i = 0; i <= accentsize - 1; i ++) {
+            int32_t mask = 1 << (accentsize - i - 1);
+            if (count & mask) {
+                for (int j = accentsindex[i]; j < accentsindex[i + 1]; j ++) {
+                    *rearrange ++ = accents[j];
+                }
+            }
+        }
+        *rearrange = 0;
+        int32_t  matchsize = INITIAL_ARRAY_SIZE_;
+        UChar   *match     = addToUCharArray(buffer, &matchsize,
+                                           strsrch->canonicalPrefixAccents,
+                                           strsrch->search->text + offset,
+                                           end - offset,
+                                           strsrch->canonicalSuffixAccents,
+                                           status);
+
+        // if status is a failure, ucol_setText does nothing.
+        // run the collator iterator through this match
+        ucol_setText(coleiter, match, matchsize, status);
+        if (U_SUCCESS(*status)) {
+            if (checkCollationMatch(strsrch, coleiter)) {
+                if (match != buffer) {
+                    uprv_free(match);
+                }
+                return start;
+            }
+        }
+        count --;
+    }
+    return USEARCH_DONE;
+}
+
+/**
+* Gets the offset to the safe point in text before textoffset.
+* ie. not the middle of a contraction, swappable characters or supplementary
+* characters.
+* @param collator collation sata
+* @param text string to work with
+* @param textoffset offset in string
+* @param textlength length of text string
+* @return offset to the previous safe character
+*/
+static
+inline uint32_t getPreviousSafeOffset(const UCollator   *collator,
+                                      const UChar       *text,
+                                            int32_t  textoffset)
+{
+    int32_t result = textoffset; // first contraction character
+    while (result != 0 && ucol_unsafeCP(text[result - 1], collator)) {
+        result --;
+    }
+    if (result != 0) {
+        // the first contraction character is consider unsafe here
+        result --;
+    }
+    return result;
+}
+
+/**
+* Cleaning up after we passed the safe zone
+* @param strsrch string search data
+* @param safetext safe text array
+* @param safebuffer safe text buffer
+* @param coleiter collation element iterator for safe text
+*/
+static
+inline void cleanUpSafeText(const UStringSearch *strsrch, UChar *safetext,
+                                  UChar         *safebuffer)
+{
+    if (safetext != safebuffer && safetext != strsrch->canonicalSuffixAccents)
+    {
+       uprv_free(safetext);
+    }
+}
+
+/**
+* Take the rearranged end accents and tries matching. If match failed at
+* a seperate preceding set of accents (seperated from the rearranged on by
+* at least a base character) then we rearrange the preceding accents and
+* tries matching again.
+* We allow skipping of the ends of the accent set if the ces do not match.
+* However if the failure is found before the accent set, it fails.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param textoffset of the start of the rearranged accent
+* @param status output error status if any
+* @return USEARCH_DONE if a match is not found, otherwise return the starting
+*         offset of the match. Note this start includes all preceding accents.
+*/
+static
+int32_t doNextCanonicalSuffixMatch(UStringSearch *strsrch,
+                                       int32_t    textoffset,
+                                       UErrorCode    *status)
+{
+    const UChar              *text           = strsrch->search->text;
+    const UCollator          *collator       = strsrch->collator;
+          int32_t             safelength     = 0;
+          UChar              *safetext;
+          int32_t             safetextlength;
+          UChar               safebuffer[INITIAL_ARRAY_SIZE_];
+          UCollationElements *coleiter       = strsrch->utilIter;
+          int32_t         safeoffset     = textoffset;
+
+    if (textoffset != 0 && ucol_unsafeCP(strsrch->canonicalSuffixAccents[0],
+                                         collator)) {
+        safeoffset     = getPreviousSafeOffset(collator, text, textoffset);
+        safelength     = textoffset - safeoffset;
+        safetextlength = INITIAL_ARRAY_SIZE_;
+        safetext       = addToUCharArray(safebuffer, &safetextlength, NULL,
+                                         text + safeoffset, safelength,
+                                         strsrch->canonicalSuffixAccents,
+                                         status);
+    }
+    else {
+        safetextlength = u_strlen(strsrch->canonicalSuffixAccents);
+        safetext       = strsrch->canonicalSuffixAccents;
+    }
+
+    // if status is a failure, ucol_setText does nothing
+    ucol_setText(coleiter, safetext, safetextlength, status);
+    // status checked in loop below
+
+    int32_t  *ce        = strsrch->pattern.CE;
+    int32_t   celength  = strsrch->pattern.CELength;
+    int       ceindex   = celength - 1;
+    UBool     isSafe    = TRUE; // indication flag for position in safe zone
+
+    while (ceindex >= 0) {
+        int32_t textce = ucol_previous(coleiter, status);
+        if (U_FAILURE(*status)) {
+            if (isSafe) {
+                cleanUpSafeText(strsrch, safetext, safebuffer);
+            }
+            return USEARCH_DONE;
+        }
+        if (textce == UCOL_NULLORDER) {
+            // check if we have passed the safe buffer
+            if (coleiter == strsrch->textIter) {
+                cleanUpSafeText(strsrch, safetext, safebuffer);
+                return USEARCH_DONE;
+            }
+            cleanUpSafeText(strsrch, safetext, safebuffer);
+            safetext = safebuffer;
+            coleiter = strsrch->textIter;
+            setColEIterOffset(coleiter, safeoffset);
+            // status checked at the start of the loop
+            isSafe = FALSE;
+            continue;
+        }
+        textce = getCE(strsrch, textce);
+        if (textce != UCOL_IGNORABLE && textce != ce[ceindex]) {
+            // do the beginning stuff
+            int32_t failedoffset = getColElemIterOffset(coleiter, FALSE);
+            if (isSafe && failedoffset >= safelength) {
+                // alas... no hope. failed at rearranged accent set
+                cleanUpSafeText(strsrch, safetext, safebuffer);
+                return USEARCH_DONE;
+            }
+            else {
+                if (isSafe) {
+                    failedoffset += safeoffset;
+                    cleanUpSafeText(strsrch, safetext, safebuffer);
+                }
+
+                // try rearranging the front accents
+                int32_t result = doNextCanonicalPrefixMatch(strsrch,
+                                        failedoffset, textoffset, status);
+                if (result != USEARCH_DONE) {
+                    // if status is a failure, ucol_setOffset does nothing
+                    setColEIterOffset(strsrch->textIter, result);
+                }
+                if (U_FAILURE(*status)) {
+                    return USEARCH_DONE;
+                }
+                return result;
+            }
+        }
+        if (textce == ce[ceindex]) {
+            ceindex --;
+        }
+    }
+    // set offset here
+    if (isSafe) {
+        int32_t result     = getColElemIterOffset(coleiter, FALSE);
+        // sets the text iterator here with the correct expansion and offset
+        int32_t    leftoverces = getExpansionPrefix(coleiter);
+        cleanUpSafeText(strsrch, safetext, safebuffer);
+        if (result >= safelength) {
+            result = textoffset;
+        }
+        else {
+            result += safeoffset;
+        }
+        setColEIterOffset(strsrch->textIter, result);
+        strsrch->textIter->iteratordata_.toReturn =
+                       setExpansionPrefix(strsrch->textIter, leftoverces);
+        return result;
+    }
+
+    return ucol_getOffset(coleiter);
+}
+
+/**
+* Trying out the substring and sees if it can be a canonical match.
+* This will try normalizing the end accents and arranging them into canonical
+* equivalents and check their corresponding ces with the pattern ce.
+* Suffix accents in the text will be grouped according to their combining
+* class and the groups will be mixed and matched to try find the perfect
+* match with the pattern.
+* So for instance looking for "\u0301" in "\u030A\u0301\u0325"
+* step 1: split "\u030A\u0301" into 6 other type of potential accent substrings
+*         "\u030A", "\u0301", "\u0325", "\u030A\u0301", "\u030A\u0325",
+*         "\u0301\u0325".
+* step 2: check if any of the generated substrings matches the pattern.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param textoffset end offset in the collation element text that ends with
+*                   the accents to be rearranged
+* @param status error status if any
+* @return TRUE if the match is valid, FALSE otherwise
+*/
+static
+UBool doNextCanonicalMatch(UStringSearch *strsrch,
+                           int32_t    textoffset,
+                           UErrorCode    *status)
+{
+    const UChar       *text = strsrch->search->text;
+          int32_t  temp = textoffset;
+    UTF_BACK_1(text, 0, temp);
+    if ((getFCD(text, &temp, textoffset) & LAST_BYTE_MASK_) == 0) {
+        UCollationElements *coleiter = strsrch->textIter;
+        int32_t         offset   = getColElemIterOffset(coleiter, FALSE);
+        if (strsrch->pattern.hasPrefixAccents) {
+            offset = doNextCanonicalPrefixMatch(strsrch, offset, textoffset,
+                                                status);
+            if (U_SUCCESS(*status) && offset != USEARCH_DONE) {
+                setColEIterOffset(coleiter, offset);
+                return TRUE;
+            }
+        }
+        return FALSE;
+    }
+
+    if (!strsrch->pattern.hasSuffixAccents) {
+        return FALSE;
+    }
+
+    UChar       accents[INITIAL_ARRAY_SIZE_];
+    // offset to the last base character in substring to search
+    int32_t baseoffset = getPreviousBaseOffset(text, textoffset);
+    // normalizing the offensive string
+    unorm_normalize(text + baseoffset, textoffset - baseoffset, UNORM_NFD,
+                               0, accents, INITIAL_ARRAY_SIZE_, status);
+    // status checked in loop below
+
+    int32_t accentsindex[INITIAL_ARRAY_SIZE_];
+    int32_t size = getUnblockedAccentIndex(accents, accentsindex);
+
+    // 2 power n - 1 plus the full set of accents
+    int32_t  count = (2 << (size - 1)) - 1;
+    while (U_SUCCESS(*status) && count > 0) {
+        UChar *rearrange = strsrch->canonicalSuffixAccents;
+        // copy the base characters
+        for (int k = 0; k < accentsindex[0]; k ++) {
+            *rearrange ++ = accents[k];
+        }
+        // forming all possible canonical rearrangement by dropping
+        // sets of accents
+        for (int i = 0; i <= size - 1; i ++) {
+            int32_t mask = 1 << (size - i - 1);
+            if (count & mask) {
+                for (int j = accentsindex[i]; j < accentsindex[i + 1]; j ++) {
+                    *rearrange ++ = accents[j];
+                }
+            }
+        }
+        *rearrange = 0;
+        int32_t offset = doNextCanonicalSuffixMatch(strsrch, baseoffset,
+                                                        status);
+        if (offset != USEARCH_DONE) {
+            return TRUE; // match found
+        }
+        count --;
+    }
+    return FALSE;
+}
+
+/**
+* Gets the previous base character offset depending on the string search
+* pattern data
+* @param strsrch string search data
+* @param textoffset current offset, current character
+* @return the offset of the next character after this base character or itself
+*         if it is a composed character with accents
+*/
+static
+inline int32_t getPreviousUStringSearchBaseOffset(UStringSearch *strsrch,
+                                                      int32_t textoffset)
+{
+    if (strsrch->pattern.hasPrefixAccents && textoffset > 0) {
+        const UChar       *text = strsrch->search->text;
+              int32_t  offset = textoffset;
+        if (getFCD(text, &offset, strsrch->search->textLength) >>
+                                                   SECOND_LAST_BYTE_SHIFT_) {
+            return getPreviousBaseOffset(text, textoffset);
+        }
+    }
+    return textoffset;
+}
+
+/**
+* Checks match for contraction.
+* If the match ends with a partial contraction we fail.
+* If the match starts too far off (because of backwards iteration) we try to
+* chip off the extra characters
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param start offset of potential match, to be modified if necessary
+* @param end offset of potential match, to be modified if necessary
+* @param status output error status if any
+* @return TRUE if match passes the contraction test, FALSE otherwise
+*/
+static
+UBool checkNextCanonicalContractionMatch(UStringSearch *strsrch,
+                                         int32_t   *start,
+                                         int32_t   *end,
+                                         UErrorCode    *status)
+{
+          UCollationElements *coleiter   = strsrch->textIter;
+          int32_t             textlength = strsrch->search->textLength;
+          int32_t         temp       = *start;
+    const UCollator          *collator   = strsrch->collator;
+    const UChar              *text       = strsrch->search->text;
+    // This part checks if either ends of the match contains potential
+    // contraction. If so we'll have to iterate through them
+    if ((*end < textlength && ucol_unsafeCP(text[*end], collator)) ||
+        (*start + 1 < textlength
+         && ucol_unsafeCP(text[*start + 1], collator))) {
+        int32_t expansion  = getExpansionPrefix(coleiter);
+        UBool   expandflag = expansion > 0;
+        setColEIterOffset(coleiter, *start);
+        while (expansion > 0) {
+            // getting rid of the redundant ce, caused by setOffset.
+            // since backward contraction/expansion may have extra ces if we
+            // are in the normalization buffer, hasAccentsBeforeMatch would
+            // have taken care of it.
+            // E.g. the character \u01FA will have an expansion of 3, but if
+            // we are only looking for acute and ring \u030A and \u0301, we'll
+            // have to skip the first ce in the expansion buffer.
+            ucol_next(coleiter, status);
+            if (U_FAILURE(*status)) {
+                return FALSE;
+            }
+            if (ucol_getOffset(coleiter) != temp) {
+                *start = temp;
+                temp  = ucol_getOffset(coleiter);
+            }
+            expansion --;
+        }
+
+        int32_t  *patternce       = strsrch->pattern.CE;
+        int32_t   patterncelength = strsrch->pattern.CELength;
+        int32_t   count           = 0;
+        int32_t   textlength      = strsrch->search->textLength;
+        while (count < patterncelength) {
+            int32_t ce = getCE(strsrch, ucol_next(coleiter, status));
+            // status checked below, note that if status is a failure
+            // ucol_next returns UCOL_NULLORDER
+            if (ce == UCOL_IGNORABLE) {
+                continue;
+            }
+            if (expandflag && count == 0 && ucol_getOffset(coleiter) != temp) {
+                *start = temp;
+                temp   = ucol_getOffset(coleiter);
+            }
+
+            if (count == 0 && ce != patternce[0]) {
+                // accents may have extra starting ces, this occurs when a
+                // pure accent pattern is matched without rearrangement
+                // text \u0325\u0300 and looking for \u0300
+                int32_t expected = patternce[0];
+                if (getFCD(text, start, textlength) & LAST_BYTE_MASK_) {
+                    ce = getCE(strsrch, ucol_next(coleiter, status));
+                    while (U_SUCCESS(*status) && ce != expected &&
+                           ce != UCOL_NULLORDER &&
+                           ucol_getOffset(coleiter) <= *end) {
+                        ce = getCE(strsrch, ucol_next(coleiter, status));
+                    }
+                }
+            }
+            if (U_FAILURE(*status) || ce != patternce[count]) {
+                (*end) ++;
+                *end = getNextUStringSearchBaseOffset(strsrch, *end);
+                return FALSE;
+            }
+            count ++;
+        }
+    }
+    return TRUE;
+}
+
+/**
+* Checks and sets the match information if found.
+* Checks
+* <ul>
+* <li> the potential match does not repeat the previous match
+* <li> boundaries are correct
+* <li> potential match does not end in the middle of a contraction
+* <li> identical matches
+* <\ul>
+* Otherwise the offset will be shifted to the next character.
+* Internal method, status assumed to be success, caller has to check the
+* status before calling this method.
+* @param strsrch string search data
+* @param textoffset offset in the collation element text. the returned value
+*        will be the truncated end offset of the match or the new start
+*        search offset.
+* @param status output error status if any
+* @return TRUE if the match is valid, FALSE otherwise
+*/
+static
+inline UBool checkNextCanonicalMatch(UStringSearch *strsrch,
+                                     int32_t   *textoffset,
+                                     UErrorCode    *status)
+{
+    // to ensure that the start and ends are not composite characters
+    UCollationElements *coleiter = strsrch->textIter;
+    // if we have a canonical accent match
+    if ((strsrch->pattern.hasSuffixAccents &&
+        strsrch->canonicalSuffixAccents[0]) ||
+        (strsrch->pattern.hasPrefixAccents &&
+        strsrch->canonicalPrefixAccents[0])) {
+        strsrch->search->matchedIndex  = getPreviousUStringSearchBaseOffset(
+                                                    strsrch,
+                                                    ucol_getOffset(coleiter));
+        strsrch->search->matchedLength = *textoffset -
+                                                strsrch->search->matchedIndex;
+        return TRUE;
+    }
+
+    int32_t start = getColElemIterOffset(coleiter, FALSE);
+    if (!checkNextCanonicalContractionMatch(strsrch, &start, textoffset,
+                                            status) || U_FAILURE(*status)) {
+        return FALSE;
+    }
+
+    start = getPreviousUStringSearchBaseOffset(strsrch, start);
+    // this totally matches, however we need to check if it is repeating
+    if (checkRepeatedMatch(strsrch, start, *textoffset) ||
+        !isBreakUnit(strsrch, start, *textoffset) ||
+        !checkIdentical(strsrch, start, *textoffset)) {
+        (*textoffset) ++;
+        *textoffset = getNextBaseOffset(strsrch->search->text, *textoffset,
+                                        strsrch->search->textLength);
+        return FALSE;
+    }
+
+    strsrch->search->matchedIndex  = start;
+    strsrch->search->matchedLength = *textoffset - start;
+    return TRUE;
+}
+
+/**
+* Shifting the collation element iterator position forward to prepare for
+* a preceding match. If the first character is a unsafe character, we'll only
+* shift by 1 to capture contractions, normalization etc.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param text strsrch string search data
+* @param textoffset start text position to do search
+* @param ce the text ce which failed the match.
+* @param patternceindex index of the ce within the pattern ce buffer which
+*        failed the match
+* @return final offset
+*/
+static
+inline int32_t reverseShift(UStringSearch *strsrch,
+                                int32_t    textoffset,
+                                int32_t       ce,
+                                int32_t        patternceindex)
+{
+    if (strsrch->search->isOverlap) {
+        if (textoffset != strsrch->search->textLength) {
+            textoffset --;
+        }
+        else {
+            textoffset -= strsrch->pattern.defaultShiftSize;
+        }
+    }
+    else {
+        if (ce != UCOL_NULLORDER) {
+            int32_t shift = strsrch->pattern.backShift[hash(ce)];
+
+            // this is to adjust for characters in the middle of the substring
+            // for matching that failed.
+            int32_t adjust = patternceindex;
+            if (adjust > 1 && shift > adjust) {
+                shift -= adjust - 1;
+            }
+            textoffset -= shift;
+        }
+        else {
+            textoffset -= strsrch->pattern.defaultShiftSize;
+        }
+    }
+    textoffset = getPreviousUStringSearchBaseOffset(strsrch, textoffset);
+    return textoffset;
+}
+
+/**
+* Checks match for contraction.
+* If the match starts with a partial contraction we fail.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param start offset of potential match, to be modified if necessary
+* @param end offset of potential match, to be modified if necessary
+* @param status output error status if any
+* @return TRUE if match passes the contraction test, FALSE otherwise
+*/
+static
+UBool checkPreviousExactContractionMatch(UStringSearch *strsrch,
+                                     int32_t   *start,
+                                     int32_t   *end, UErrorCode  *status)
+{
+          UCollationElements *coleiter   = strsrch->textIter;
+          int32_t             textlength = strsrch->search->textLength;
+          int32_t             temp       = *end;
+    const UCollator          *collator   = strsrch->collator;
+    const UChar              *text       = strsrch->search->text;
+    // This part checks if either if the start of the match contains potential
+    // contraction. If so we'll have to iterate through them
+    // Since we used ucol_next while previously looking for the potential
+    // match, this guarantees that our end will not be a partial contraction,
+    // or a partial supplementary character.
+    if (*start < textlength && ucol_unsafeCP(text[*start], collator)) {
+        int32_t expansion  = getExpansionSuffix(coleiter);
+        UBool   expandflag = expansion > 0;
+        setColEIterOffset(coleiter, *end);
+        while (U_SUCCESS(*status) && expansion > 0) {
+            // getting rid of the redundant ce
+            // since forward contraction/expansion may have extra ces
+            // if we are in the normalization buffer, hasAccentsBeforeMatch
+            // would have taken care of it.
+            // E.g. the character \u01FA will have an expansion of 3, but if
+            // we are only looking for A ring A\u030A, we'll have to skip the
+            // last ce in the expansion buffer
+            ucol_previous(coleiter, status);
+            if (U_FAILURE(*status)) {
+                return FALSE;
+            }
+            if (ucol_getOffset(coleiter) != temp) {
+                *end = temp;
+                temp  = ucol_getOffset(coleiter);
+            }
+            expansion --;
+        }
+
+        int32_t  *patternce       = strsrch->pattern.CE;
+        int32_t   patterncelength = strsrch->pattern.CELength;
+        int32_t   count           = patterncelength;
+        while (count > 0) {
+            int32_t ce = getCE(strsrch, ucol_previous(coleiter, status));
+            // status checked below, note that if status is a failure
+            // ucol_previous returns UCOL_NULLORDER
+            if (ce == UCOL_IGNORABLE) {
+                continue;
+            }
+            if (expandflag && count == 0 &&
+                getColElemIterOffset(coleiter, FALSE) != temp) {
+                *end = temp;
+                temp  = ucol_getOffset(coleiter);
+            }
+            if (U_FAILURE(*status) || ce != patternce[count - 1]) {
+                (*start) --;
+                *start = getPreviousBaseOffset(text, *start);
+                return FALSE;
+            }
+            count --;
+        }
+    }
+    return TRUE;
+}
+
+/**
+* Checks and sets the match information if found.
+* Checks
+* <ul>
+* <li> the current match does not repeat the last match
+* <li> boundaries are correct
+* <li> exact matches has no extra accents
+* <li> identical matches
+* <\ul>
+* Otherwise the offset will be shifted to the preceding character.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param collator
+* @param coleiter collation element iterator
+* @param text string
+* @param textoffset offset in the collation element text. the returned value
+*        will be the truncated start offset of the match or the new start
+*        search offset.
+* @param status output error status if any
+* @return TRUE if the match is valid, FALSE otherwise
+*/
+static
+inline UBool checkPreviousExactMatch(UStringSearch *strsrch,
+                                     int32_t   *textoffset,
+                                     UErrorCode    *status)
+{
+    // to ensure that the start and ends are not composite characters
+    int32_t end = ucol_getOffset(strsrch->textIter);
+    if (!checkPreviousExactContractionMatch(strsrch, textoffset, &end, status)
+        || U_FAILURE(*status)) {
+            return FALSE;
+    }
+
+    // this totally matches, however we need to check if it is repeating
+    // the old match
+    if (checkRepeatedMatch(strsrch, *textoffset, end) ||
+        !isBreakUnit(strsrch, *textoffset, end) ||
+        hasAccentsBeforeMatch(strsrch, *textoffset, end) ||
+        !checkIdentical(strsrch, *textoffset, end) ||
+        hasAccentsAfterMatch(strsrch, *textoffset, end)) {
+        (*textoffset) --;
+        *textoffset = getPreviousBaseOffset(strsrch->search->text,
+                                            *textoffset);
+        return FALSE;
+    }
+
+    //Add breakiterator boundary check for primary strength search.
+    if (!strsrch->search->breakIter && strsrch->strength == UCOL_PRIMARY) {
+    	checkBreakBoundary(strsrch, textoffset, &end);
+    }
+
+    strsrch->search->matchedIndex = *textoffset;
+    strsrch->search->matchedLength = end - *textoffset;
+    return TRUE;
+}
+
+/**
+* Rearranges the end accents to try matching.
+* Suffix accents in the text will be grouped according to their combining
+* class and the groups will be mixed and matched to try find the perfect
+* match with the pattern.
+* So for instance looking for "\u0301" in "\u030A\u0301\u0325"
+* step 1: split "\u030A\u0301" into 6 other type of potential accent substrings
+*         "\u030A", "\u0301", "\u0325", "\u030A\u0301", "\u030A\u0325",
+*         "\u0301\u0325".
+* step 2: check if any of the generated substrings matches the pattern.
+* Internal method, status assumed to be success, user has to check status
+* before calling this method.
+* @param strsrch string search match
+* @param start offset of the first base character
+* @param end start of the last accent set
+* @param status only error status if any
+* @return USEARCH_DONE if a match is not found, otherwise return the ending
+*         offset of the match. Note this start includes all following accents.
+*/
+static
+int32_t doPreviousCanonicalSuffixMatch(UStringSearch *strsrch,
+                                           int32_t    start,
+                                           int32_t    end,
+                                           UErrorCode    *status)
+{
+    const UChar       *text       = strsrch->search->text;
+          int32_t  tempend    = end;
+
+    UTF_BACK_1(text, 0, tempend);
+    if (!(getFCD(text, &tempend, strsrch->search->textLength) &
+                                                           LAST_BYTE_MASK_)) {
+        // die... failed at a base character
+        return USEARCH_DONE;
+    }
+    end = getNextBaseOffset(text, end, strsrch->search->textLength);
+
+    if (U_SUCCESS(*status)) {
+        UChar       accents[INITIAL_ARRAY_SIZE_];
+        int32_t offset = getPreviousBaseOffset(text, end);
+        // normalizing the offensive string
+        unorm_normalize(text + offset, end - offset, UNORM_NFD, 0, accents,
+                        INITIAL_ARRAY_SIZE_, status);
+
+        int32_t         accentsindex[INITIAL_ARRAY_SIZE_];
+        int32_t         accentsize = getUnblockedAccentIndex(accents,
+                                                         accentsindex);
+        int32_t         count      = (2 << (accentsize - 1)) - 1;
+        UChar               buffer[INITIAL_ARRAY_SIZE_];
+        UCollationElements *coleiter = strsrch->utilIter;
+        while (U_SUCCESS(*status) && count > 0) {
+            UChar *rearrange = strsrch->canonicalSuffixAccents;
+            // copy the base characters
+            for (int k = 0; k < accentsindex[0]; k ++) {
+                *rearrange ++ = accents[k];
+            }
+            // forming all possible canonical rearrangement by dropping
+            // sets of accents
+            for (int i = 0; i <= accentsize - 1; i ++) {
+                int32_t mask = 1 << (accentsize - i - 1);
+                if (count & mask) {
+                    for (int j = accentsindex[i]; j < accentsindex[i + 1]; j ++) {
+                        *rearrange ++ = accents[j];
+                    }
+                }
+            }
+            *rearrange = 0;
+            int32_t  matchsize = INITIAL_ARRAY_SIZE_;
+            UChar   *match     = addToUCharArray(buffer, &matchsize,
+                                           strsrch->canonicalPrefixAccents,
+                                           strsrch->search->text + start,
+                                           offset - start,
+                                           strsrch->canonicalSuffixAccents,
+                                           status);
+
+            // run the collator iterator through this match
+            // if status is a failure ucol_setText does nothing
+            ucol_setText(coleiter, match, matchsize, status);
+            if (U_SUCCESS(*status)) {
+                if (checkCollationMatch(strsrch, coleiter)) {
+                    if (match != buffer) {
+                        uprv_free(match);
+                    }
+                    return end;
+                }
+            }
+            count --;
+        }
+    }
+    return USEARCH_DONE;
+}
+
+/**
+* Take the rearranged start accents and tries matching. If match failed at
+* a seperate following set of accents (seperated from the rearranged on by
+* at least a base character) then we rearrange the preceding accents and
+* tries matching again.
+* We allow skipping of the ends of the accent set if the ces do not match.
+* However if the failure is found before the accent set, it fails.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param textoffset of the ends of the rearranged accent
+* @param status output error status if any
+* @return USEARCH_DONE if a match is not found, otherwise return the ending
+*         offset of the match. Note this start includes all following accents.
+*/
+static
+int32_t doPreviousCanonicalPrefixMatch(UStringSearch *strsrch,
+                                           int32_t    textoffset,
+                                           UErrorCode    *status)
+{
+    const UChar       *text       = strsrch->search->text;
+    const UCollator   *collator   = strsrch->collator;
+          int32_t      safelength = 0;
+          UChar       *safetext;
+          int32_t      safetextlength;
+          UChar        safebuffer[INITIAL_ARRAY_SIZE_];
+          int32_t  safeoffset = textoffset;
+
+    if (textoffset &&
+        ucol_unsafeCP(strsrch->canonicalPrefixAccents[
+                                 u_strlen(strsrch->canonicalPrefixAccents) - 1
+                                         ], collator)) {
+        safeoffset     = getNextSafeOffset(collator, text, textoffset,
+                                           strsrch->search->textLength);
+        safelength     = safeoffset - textoffset;
+        safetextlength = INITIAL_ARRAY_SIZE_;
+        safetext       = addToUCharArray(safebuffer, &safetextlength,
+                                         strsrch->canonicalPrefixAccents,
+                                         text + textoffset, safelength,
+                                         NULL, status);
+    }
+    else {
+        safetextlength = u_strlen(strsrch->canonicalPrefixAccents);
+        safetext       = strsrch->canonicalPrefixAccents;
+    }
+
+    UCollationElements *coleiter = strsrch->utilIter;
+     // if status is a failure, ucol_setText does nothing
+    ucol_setText(coleiter, safetext, safetextlength, status);
+    // status checked in loop below
+
+    int32_t  *ce           = strsrch->pattern.CE;
+    int32_t   celength     = strsrch->pattern.CELength;
+    int       ceindex      = 0;
+    UBool     isSafe       = TRUE; // safe zone indication flag for position
+    int32_t   prefixlength = u_strlen(strsrch->canonicalPrefixAccents);
+
+    while (ceindex < celength) {
+        int32_t textce = ucol_next(coleiter, status);
+        if (U_FAILURE(*status)) {
+            if (isSafe) {
+                cleanUpSafeText(strsrch, safetext, safebuffer);
+            }
+            return USEARCH_DONE;
+        }
+        if (textce == UCOL_NULLORDER) {
+            // check if we have passed the safe buffer
+            if (coleiter == strsrch->textIter) {
+                cleanUpSafeText(strsrch, safetext, safebuffer);
+                return USEARCH_DONE;
+            }
+            cleanUpSafeText(strsrch, safetext, safebuffer);
+            safetext = safebuffer;
+            coleiter = strsrch->textIter;
+            setColEIterOffset(coleiter, safeoffset);
+            // status checked at the start of the loop
+            isSafe = FALSE;
+            continue;
+        }
+        textce = getCE(strsrch, textce);
+        if (textce != UCOL_IGNORABLE && textce != ce[ceindex]) {
+            // do the beginning stuff
+            int32_t failedoffset = ucol_getOffset(coleiter);
+            if (isSafe && failedoffset <= prefixlength) {
+                // alas... no hope. failed at rearranged accent set
+                cleanUpSafeText(strsrch, safetext, safebuffer);
+                return USEARCH_DONE;
+            }
+            else {
+                if (isSafe) {
+                    failedoffset = safeoffset - failedoffset;
+                    cleanUpSafeText(strsrch, safetext, safebuffer);
+                }
+
+                // try rearranging the end accents
+                int32_t result = doPreviousCanonicalSuffixMatch(strsrch,
+                                        textoffset, failedoffset, status);
+                if (result != USEARCH_DONE) {
+                    // if status is a failure, ucol_setOffset does nothing
+                    setColEIterOffset(strsrch->textIter, result);
+                }
+                if (U_FAILURE(*status)) {
+                    return USEARCH_DONE;
+                }
+                return result;
+            }
+        }
+        if (textce == ce[ceindex]) {
+            ceindex ++;
+        }
+    }
+    // set offset here
+    if (isSafe) {
+        int32_t result      = ucol_getOffset(coleiter);
+        // sets the text iterator here with the correct expansion and offset
+        int32_t     leftoverces = getExpansionSuffix(coleiter);
+        cleanUpSafeText(strsrch, safetext, safebuffer);
+        if (result <= prefixlength) {
+            result = textoffset;
+        }
+        else {
+            result = textoffset + (safeoffset - result);
+        }
+        setColEIterOffset(strsrch->textIter, result);
+        setExpansionSuffix(strsrch->textIter, leftoverces);
+        return result;
+    }
+
+    return ucol_getOffset(coleiter);
+}
+
+/**
+* Trying out the substring and sees if it can be a canonical match.
+* This will try normalizing the starting accents and arranging them into
+* canonical equivalents and check their corresponding ces with the pattern ce.
+* Prefix accents in the text will be grouped according to their combining
+* class and the groups will be mixed and matched to try find the perfect
+* match with the pattern.
+* So for instance looking for "\u0301" in "\u030A\u0301\u0325"
+* step 1: split "\u030A\u0301" into 6 other type of potential accent substrings
+*         "\u030A", "\u0301", "\u0325", "\u030A\u0301", "\u030A\u0325",
+*         "\u0301\u0325".
+* step 2: check if any of the generated substrings matches the pattern.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param textoffset start offset in the collation element text that starts
+*                   with the accents to be rearranged
+* @param status output error status if any
+* @return TRUE if the match is valid, FALSE otherwise
+*/
+static
+UBool doPreviousCanonicalMatch(UStringSearch *strsrch,
+                               int32_t    textoffset,
+                               UErrorCode    *status)
+{
+    const UChar       *text       = strsrch->search->text;
+          int32_t  temp       = textoffset;
+          int32_t      textlength = strsrch->search->textLength;
+    if ((getFCD(text, &temp, textlength) >> SECOND_LAST_BYTE_SHIFT_) == 0) {
+        UCollationElements *coleiter = strsrch->textIter;
+        int32_t         offset   = ucol_getOffset(coleiter);
+        if (strsrch->pattern.hasSuffixAccents) {
+            offset = doPreviousCanonicalSuffixMatch(strsrch, textoffset,
+                                                    offset, status);
+            if (U_SUCCESS(*status) && offset != USEARCH_DONE) {
+                setColEIterOffset(coleiter, offset);
+                return TRUE;
+            }
+        }
+        return FALSE;
+    }
+
+    if (!strsrch->pattern.hasPrefixAccents) {
+        return FALSE;
+    }
+
+    UChar       accents[INITIAL_ARRAY_SIZE_];
+    // offset to the last base character in substring to search
+    int32_t baseoffset = getNextBaseOffset(text, textoffset, textlength);
+    // normalizing the offensive string
+    unorm_normalize(text + textoffset, baseoffset - textoffset, UNORM_NFD,
+                               0, accents, INITIAL_ARRAY_SIZE_, status);
+    // status checked in loop
+
+    int32_t accentsindex[INITIAL_ARRAY_SIZE_];
+    int32_t size = getUnblockedAccentIndex(accents, accentsindex);
+
+    // 2 power n - 1 plus the full set of accents
+    int32_t  count = (2 << (size - 1)) - 1;
+    while (U_SUCCESS(*status) && count > 0) {
+        UChar *rearrange = strsrch->canonicalPrefixAccents;
+        // copy the base characters
+        for (int k = 0; k < accentsindex[0]; k ++) {
+            *rearrange ++ = accents[k];
+        }
+        // forming all possible canonical rearrangement by dropping
+        // sets of accents
+        for (int i = 0; i <= size - 1; i ++) {
+            int32_t mask = 1 << (size - i - 1);
+            if (count & mask) {
+                for (int j = accentsindex[i]; j < accentsindex[i + 1]; j ++) {
+                    *rearrange ++ = accents[j];
+                }
+            }
+        }
+        *rearrange = 0;
+        int32_t offset = doPreviousCanonicalPrefixMatch(strsrch,
+                                                          baseoffset, status);
+        if (offset != USEARCH_DONE) {
+            return TRUE; // match found
+        }
+        count --;
+    }
+    return FALSE;
+}
+
+/**
+* Checks match for contraction.
+* If the match starts with a partial contraction we fail.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param start offset of potential match, to be modified if necessary
+* @param end offset of potential match, to be modified if necessary
+* @param status only error status if any
+* @return TRUE if match passes the contraction test, FALSE otherwise
+*/
+static
+UBool checkPreviousCanonicalContractionMatch(UStringSearch *strsrch,
+                                     int32_t   *start,
+                                     int32_t   *end, UErrorCode  *status)
+{
+          UCollationElements *coleiter   = strsrch->textIter;
+          int32_t             textlength = strsrch->search->textLength;
+          int32_t         temp       = *end;
+    const UCollator          *collator   = strsrch->collator;
+    const UChar              *text       = strsrch->search->text;
+    // This part checks if either if the start of the match contains potential
+    // contraction. If so we'll have to iterate through them
+    // Since we used ucol_next while previously looking for the potential
+    // match, this guarantees that our end will not be a partial contraction,
+    // or a partial supplementary character.
+    if (*start < textlength && ucol_unsafeCP(text[*start], collator)) {
+        int32_t expansion  = getExpansionSuffix(coleiter);
+        UBool   expandflag = expansion > 0;
+        setColEIterOffset(coleiter, *end);
+        while (expansion > 0) {
+            // getting rid of the redundant ce
+            // since forward contraction/expansion may have extra ces
+            // if we are in the normalization buffer, hasAccentsBeforeMatch
+            // would have taken care of it.
+            // E.g. the character \u01FA will have an expansion of 3, but if
+            // we are only looking for A ring A\u030A, we'll have to skip the
+            // last ce in the expansion buffer
+            ucol_previous(coleiter, status);
+            if (U_FAILURE(*status)) {
+                return FALSE;
+            }
+            if (ucol_getOffset(coleiter) != temp) {
+                *end = temp;
+                temp  = ucol_getOffset(coleiter);
+            }
+            expansion --;
+        }
+
+        int32_t  *patternce       = strsrch->pattern.CE;
+        int32_t   patterncelength = strsrch->pattern.CELength;
+        int32_t   count           = patterncelength;
+        while (count > 0) {
+            int32_t ce = getCE(strsrch, ucol_previous(coleiter, status));
+            // status checked below, note that if status is a failure
+            // ucol_previous returns UCOL_NULLORDER
+            if (ce == UCOL_IGNORABLE) {
+                continue;
+            }
+            if (expandflag && count == 0 &&
+                getColElemIterOffset(coleiter, FALSE) != temp) {
+                *end = temp;
+                temp  = ucol_getOffset(coleiter);
+            }
+            if (count == patterncelength &&
+                ce != patternce[patterncelength - 1]) {
+                // accents may have extra starting ces, this occurs when a
+                // pure accent pattern is matched without rearrangement
+                int32_t    expected = patternce[patterncelength - 1];
+                UTF_BACK_1(text, 0, *end);
+                if (getFCD(text, end, textlength) & LAST_BYTE_MASK_) {
+                    ce = getCE(strsrch, ucol_previous(coleiter, status));
+                    while (U_SUCCESS(*status) && ce != expected &&
+                           ce != UCOL_NULLORDER &&
+                           ucol_getOffset(coleiter) <= *start) {
+                        ce = getCE(strsrch, ucol_previous(coleiter, status));
+                    }
+                }
+            }
+            if (U_FAILURE(*status) || ce != patternce[count - 1]) {
+                (*start) --;
+                *start = getPreviousBaseOffset(text, *start);
+                return FALSE;
+            }
+            count --;
+        }
+    }
+    return TRUE;
+}
+
+/**
+* Checks and sets the match information if found.
+* Checks
+* <ul>
+* <li> the potential match does not repeat the previous match
+* <li> boundaries are correct
+* <li> potential match does not end in the middle of a contraction
+* <li> identical matches
+* <\ul>
+* Otherwise the offset will be shifted to the next character.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param textoffset offset in the collation element text. the returned value
+*        will be the truncated start offset of the match or the new start
+*        search offset.
+* @param status only error status if any
+* @return TRUE if the match is valid, FALSE otherwise
+*/
+static
+inline UBool checkPreviousCanonicalMatch(UStringSearch *strsrch,
+                                         int32_t   *textoffset,
+                                         UErrorCode    *status)
+{
+    // to ensure that the start and ends are not composite characters
+    UCollationElements *coleiter = strsrch->textIter;
+    // if we have a canonical accent match
+    if ((strsrch->pattern.hasSuffixAccents &&
+        strsrch->canonicalSuffixAccents[0]) ||
+        (strsrch->pattern.hasPrefixAccents &&
+        strsrch->canonicalPrefixAccents[0])) {
+        strsrch->search->matchedIndex  = *textoffset;
+        strsrch->search->matchedLength =
+            getNextUStringSearchBaseOffset(strsrch,
+                                      getColElemIterOffset(coleiter, FALSE))
+            - *textoffset;
+        return TRUE;
+    }
+
+    int32_t end = ucol_getOffset(coleiter);
+    if (!checkPreviousCanonicalContractionMatch(strsrch, textoffset, &end,
+                                                status) ||
+         U_FAILURE(*status)) {
+        return FALSE;
+    }
+
+    end = getNextUStringSearchBaseOffset(strsrch, end);
+    // this totally matches, however we need to check if it is repeating
+    if (checkRepeatedMatch(strsrch, *textoffset, end) ||
+        !isBreakUnit(strsrch, *textoffset, end) ||
+        !checkIdentical(strsrch, *textoffset, end)) {
+        (*textoffset) --;
+        *textoffset = getPreviousBaseOffset(strsrch->search->text,
+                                            *textoffset);
+        return FALSE;
+    }
+
+    strsrch->search->matchedIndex  = *textoffset;
+    strsrch->search->matchedLength = end - *textoffset;
+    return TRUE;
+}
+#endif // #if BOYER_MOORE
+
+// constructors and destructor -------------------------------------------
+
+U_CAPI UStringSearch * U_EXPORT2 usearch_open(const UChar *pattern,
+                                          int32_t         patternlength,
+                                    const UChar          *text,
+                                          int32_t         textlength,
+                                    const char           *locale,
+                                          UBreakIterator *breakiter,
+                                          UErrorCode     *status)
+{
+    if (U_FAILURE(*status)) {
+        return NULL;
+    }
+#if UCONFIG_NO_BREAK_ITERATION
+    if (breakiter != NULL) {
+        *status = U_UNSUPPORTED_ERROR;
+        return NULL;
+    }
+#endif
+    if (locale) {
+        // ucol_open internally checks for status
+        UCollator     *collator = ucol_open(locale, status);
+        // pattern, text checks are done in usearch_openFromCollator
+        UStringSearch *result   = usearch_openFromCollator(pattern,
+                                              patternlength, text, textlength,
+                                              collator, breakiter, status);
+
+        if (result == NULL || U_FAILURE(*status)) {
+            if (collator) {
+                ucol_close(collator);
+            }
+            return NULL;
+        }
+        else {
+            result->ownCollator = TRUE;
+        }
+        return result;
+    }
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+    return NULL;
+}
+
+U_CAPI UStringSearch * U_EXPORT2 usearch_openFromCollator(
+                                  const UChar          *pattern,
+                                        int32_t         patternlength,
+                                  const UChar          *text,
+                                        int32_t         textlength,
+                                  const UCollator      *collator,
+                                        UBreakIterator *breakiter,
+                                        UErrorCode     *status)
+{
+    if (U_FAILURE(*status)) {
+        return NULL;
+    }
+#if UCONFIG_NO_BREAK_ITERATION
+    if (breakiter != NULL) {
+        *status = U_UNSUPPORTED_ERROR;
+        return NULL;
+    }
+#endif
+    if (pattern == NULL || text == NULL || collator == NULL) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    // string search does not really work when numeric collation is turned on
+    if(ucol_getAttribute(collator, UCOL_NUMERIC_COLLATION, status) == UCOL_ON) {
+        *status = U_UNSUPPORTED_ERROR;
+        return NULL;
+    }
+
+    if (U_SUCCESS(*status)) {
+        initializeFCD(status);
+        if (U_FAILURE(*status)) {
+            return NULL;
+        }
+
+        UStringSearch *result;
+        if (textlength == -1) {
+            textlength = u_strlen(text);
+        }
+        if (patternlength == -1) {
+            patternlength = u_strlen(pattern);
+        }
+        if (textlength <= 0 || patternlength <= 0) {
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+            return NULL;
+        }
+
+        result = (UStringSearch *)uprv_malloc(sizeof(UStringSearch));
+        if (result == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return NULL;
+        }
+
+        result->collator    = collator;
+        result->strength    = ucol_getStrength(collator);
+        result->ceMask      = getMask(result->strength);
+        result->toShift     =
+             ucol_getAttribute(collator, UCOL_ALTERNATE_HANDLING, status) ==
+                                                            UCOL_SHIFTED;
+        result->variableTop = ucol_getVariableTop(collator, status);
+
+        result->nfd         = Normalizer2Factory::getNFDInstance(*status);
+
+        if (U_FAILURE(*status)) {
+            uprv_free(result);
+            return NULL;
+        }
+
+        result->search             = (USearch *)uprv_malloc(sizeof(USearch));
+        if (result->search == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            uprv_free(result);
+            return NULL;
+        }
+
+        result->search->text       = text;
+        result->search->textLength = textlength;
+
+        result->pattern.text       = pattern;
+        result->pattern.textLength = patternlength;
+        result->pattern.CE         = NULL;
+        result->pattern.PCE        = NULL;
+
+        result->search->breakIter  = breakiter;
+#if !UCONFIG_NO_BREAK_ITERATION
+        result->search->internalBreakIter = ubrk_open(UBRK_CHARACTER, ucol_getLocaleByType(result->collator, ULOC_VALID_LOCALE, status), text, textlength, status);
+        if (breakiter) {
+        	ubrk_setText(breakiter, text, textlength, status);
+        }
+#endif
+
+        result->ownCollator           = FALSE;
+        result->search->matchedLength = 0;
+        result->search->matchedIndex  = USEARCH_DONE;
+        result->utilIter              = NULL;
+        result->textIter              = ucol_openElements(collator, text,
+                                                          textlength, status);
+        if (U_FAILURE(*status)) {
+            usearch_close(result);
+            return NULL;
+        }
+
+        result->search->isOverlap          = FALSE;
+        result->search->isCanonicalMatch   = FALSE;
+        result->search->elementComparisonType = 0;
+        result->search->isForwardSearching = TRUE;
+        result->search->reset              = TRUE;
+
+        initialize(result, status);
+
+        if (U_FAILURE(*status)) {
+            usearch_close(result);
+            return NULL;
+        }
+
+        return result;
+    }
+    return NULL;
+}
+
+U_CAPI void U_EXPORT2 usearch_close(UStringSearch *strsrch)
+{
+    if (strsrch) {
+        if (strsrch->pattern.CE != strsrch->pattern.CEBuffer &&
+            strsrch->pattern.CE) {
+            uprv_free(strsrch->pattern.CE);
+        }
+
+        if (strsrch->pattern.PCE != NULL &&
+            strsrch->pattern.PCE != strsrch->pattern.PCEBuffer) {
+            uprv_free(strsrch->pattern.PCE);
+        }
+
+        ucol_closeElements(strsrch->textIter);
+        ucol_closeElements(strsrch->utilIter);
+
+        if (strsrch->ownCollator && strsrch->collator) {
+            ucol_close((UCollator *)strsrch->collator);
+        }
+
+#if !UCONFIG_NO_BREAK_ITERATION
+        if (strsrch->search->internalBreakIter) {
+        	ubrk_close(strsrch->search->internalBreakIter);
+        }
+#endif
+
+        uprv_free(strsrch->search);
+        uprv_free(strsrch);
+    }
+}
+
+// set and get methods --------------------------------------------------
+
+U_CAPI void U_EXPORT2 usearch_setOffset(UStringSearch *strsrch,
+                                        int32_t    position,
+                                        UErrorCode    *status)
+{
+    if (U_SUCCESS(*status) && strsrch) {
+        if (isOutOfBounds(strsrch->search->textLength, position)) {
+            *status = U_INDEX_OUTOFBOUNDS_ERROR;
+        }
+        else {
+            setColEIterOffset(strsrch->textIter, position);
+        }
+        strsrch->search->matchedIndex  = USEARCH_DONE;
+        strsrch->search->matchedLength = 0;
+        strsrch->search->reset         = FALSE;
+    }
+}
+
+U_CAPI int32_t U_EXPORT2 usearch_getOffset(const UStringSearch *strsrch)
+{
+    if (strsrch) {
+        int32_t result = ucol_getOffset(strsrch->textIter);
+        if (isOutOfBounds(strsrch->search->textLength, result)) {
+            return USEARCH_DONE;
+        }
+        return result;
+    }
+    return USEARCH_DONE;
+}
+
+U_CAPI void U_EXPORT2 usearch_setAttribute(UStringSearch *strsrch,
+                                 USearchAttribute attribute,
+                                 USearchAttributeValue value,
+                                 UErrorCode *status)
+{
+    if (U_SUCCESS(*status) && strsrch) {
+        switch (attribute)
+        {
+        case USEARCH_OVERLAP :
+            strsrch->search->isOverlap = (value == USEARCH_ON ? TRUE : FALSE);
+            break;
+        case USEARCH_CANONICAL_MATCH :
+            strsrch->search->isCanonicalMatch = (value == USEARCH_ON ? TRUE :
+                                                                      FALSE);
+            break;
+        case USEARCH_ELEMENT_COMPARISON :
+            if (value == USEARCH_PATTERN_BASE_WEIGHT_IS_WILDCARD || value == USEARCH_ANY_BASE_WEIGHT_IS_WILDCARD) {
+                strsrch->search->elementComparisonType = (int16_t)value;
+            } else {
+                strsrch->search->elementComparisonType = 0;
+            }
+            break;
+        case USEARCH_ATTRIBUTE_COUNT :
+        default:
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+    }
+    if (value == USEARCH_ATTRIBUTE_VALUE_COUNT) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+    }
+}
+
+U_CAPI USearchAttributeValue U_EXPORT2 usearch_getAttribute(
+                                                const UStringSearch *strsrch,
+                                                USearchAttribute attribute)
+{
+    if (strsrch) {
+        switch (attribute) {
+        case USEARCH_OVERLAP :
+            return (strsrch->search->isOverlap == TRUE ? USEARCH_ON :
+                                                        USEARCH_OFF);
+        case USEARCH_CANONICAL_MATCH :
+            return (strsrch->search->isCanonicalMatch == TRUE ? USEARCH_ON :
+                                                               USEARCH_OFF);
+        case USEARCH_ELEMENT_COMPARISON :
+            {
+                int16_t value = strsrch->search->elementComparisonType;
+                if (value == USEARCH_PATTERN_BASE_WEIGHT_IS_WILDCARD || value == USEARCH_ANY_BASE_WEIGHT_IS_WILDCARD) {
+                    return (USearchAttributeValue)value;
+                } else {
+                    return USEARCH_STANDARD_ELEMENT_COMPARISON;
+                }
+            }
+        case USEARCH_ATTRIBUTE_COUNT :
+            return USEARCH_DEFAULT;
+        }
+    }
+    return USEARCH_DEFAULT;
+}
+
+U_CAPI int32_t U_EXPORT2 usearch_getMatchedStart(
+                                                const UStringSearch *strsrch)
+{
+    if (strsrch == NULL) {
+        return USEARCH_DONE;
+    }
+    return strsrch->search->matchedIndex;
+}
+
+
+U_CAPI int32_t U_EXPORT2 usearch_getMatchedText(const UStringSearch *strsrch,
+                                            UChar         *result,
+                                            int32_t        resultCapacity,
+                                            UErrorCode    *status)
+{
+    if (U_FAILURE(*status)) {
+        return USEARCH_DONE;
+    }
+    if (strsrch == NULL || resultCapacity < 0 || (resultCapacity > 0 &&
+        result == NULL)) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return USEARCH_DONE;
+    }
+
+    int32_t     copylength = strsrch->search->matchedLength;
+    int32_t copyindex  = strsrch->search->matchedIndex;
+    if (copyindex == USEARCH_DONE) {
+        u_terminateUChars(result, resultCapacity, 0, status);
+        return USEARCH_DONE;
+    }
+
+    if (resultCapacity < copylength) {
+        copylength = resultCapacity;
+    }
+    if (copylength > 0) {
+        uprv_memcpy(result, strsrch->search->text + copyindex,
+                    copylength * sizeof(UChar));
+    }
+    return u_terminateUChars(result, resultCapacity,
+                             strsrch->search->matchedLength, status);
+}
+
+U_CAPI int32_t U_EXPORT2 usearch_getMatchedLength(
+                                              const UStringSearch *strsrch)
+{
+    if (strsrch) {
+        return strsrch->search->matchedLength;
+    }
+    return USEARCH_DONE;
+}
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+U_CAPI void U_EXPORT2 usearch_setBreakIterator(UStringSearch  *strsrch,
+                                               UBreakIterator *breakiter,
+                                               UErrorCode     *status)
+{
+    if (U_SUCCESS(*status) && strsrch) {
+    	strsrch->search->breakIter = breakiter;
+        if (breakiter) {
+            ubrk_setText(breakiter, strsrch->search->text,
+                         strsrch->search->textLength, status);
+        }
+    }
+}
+
+U_CAPI const UBreakIterator* U_EXPORT2
+usearch_getBreakIterator(const UStringSearch *strsrch)
+{
+    if (strsrch) {
+        return strsrch->search->breakIter;
+    }
+    return NULL;
+}
+
+#endif
+
+U_CAPI void U_EXPORT2 usearch_setText(      UStringSearch *strsrch,
+                                      const UChar         *text,
+                                            int32_t        textlength,
+                                            UErrorCode    *status)
+{
+    if (U_SUCCESS(*status)) {
+        if (strsrch == NULL || text == NULL || textlength < -1 ||
+            textlength == 0) {
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+        else {
+            if (textlength == -1) {
+                textlength = u_strlen(text);
+            }
+            strsrch->search->text       = text;
+            strsrch->search->textLength = textlength;
+            ucol_setText(strsrch->textIter, text, textlength, status);
+            strsrch->search->matchedIndex  = USEARCH_DONE;
+            strsrch->search->matchedLength = 0;
+            strsrch->search->reset         = TRUE;
+#if !UCONFIG_NO_BREAK_ITERATION
+            if (strsrch->search->breakIter != NULL) {
+                ubrk_setText(strsrch->search->breakIter, text,
+                             textlength, status);
+            }
+            ubrk_setText(strsrch->search->internalBreakIter, text, textlength, status);
+#endif
+        }
+    }
+}
+
+U_CAPI const UChar * U_EXPORT2 usearch_getText(const UStringSearch *strsrch,
+                                                     int32_t       *length)
+{
+    if (strsrch) {
+        *length = strsrch->search->textLength;
+        return strsrch->search->text;
+    }
+    return NULL;
+}
+
+U_CAPI void U_EXPORT2 usearch_setCollator(      UStringSearch *strsrch,
+                                          const UCollator     *collator,
+                                                UErrorCode    *status)
+{
+    if (U_SUCCESS(*status)) {
+        if (collator == NULL) {
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+            return;
+        }
+
+        if (strsrch) {
+            if (strsrch->ownCollator && (strsrch->collator != collator)) {
+                ucol_close((UCollator *)strsrch->collator);
+                strsrch->ownCollator = FALSE;
+            }
+            strsrch->collator    = collator;
+            strsrch->strength    = ucol_getStrength(collator);
+            strsrch->ceMask      = getMask(strsrch->strength);
+#if !UCONFIG_NO_BREAK_ITERATION
+        	ubrk_close(strsrch->search->internalBreakIter);
+        	strsrch->search->internalBreakIter = ubrk_open(UBRK_CHARACTER, ucol_getLocaleByType(collator, ULOC_VALID_LOCALE, status),
+        											 strsrch->search->text, strsrch->search->textLength, status);
+#endif
+            // if status is a failure, ucol_getAttribute returns UCOL_DEFAULT
+            strsrch->toShift     =
+               ucol_getAttribute(collator, UCOL_ALTERNATE_HANDLING, status) ==
+                                                                UCOL_SHIFTED;
+            // if status is a failure, ucol_getVariableTop returns 0
+            strsrch->variableTop = ucol_getVariableTop(collator, status);
+            if (U_SUCCESS(*status)) {
+                initialize(strsrch, status);
+                if (U_SUCCESS(*status)) {
+                    /* free offset buffer to avoid memory leak before initializing. */
+                    ucol_freeOffsetBuffer(&(strsrch->textIter->iteratordata_));
+                    uprv_init_collIterate(collator, strsrch->search->text,
+                                          strsrch->search->textLength,
+                                          &(strsrch->textIter->iteratordata_),
+                                          status);
+                    strsrch->utilIter->iteratordata_.coll = collator;
+                }
+            }
+        }
+
+        // **** are these calls needed?
+        // **** we call uprv_init_pce in initializePatternPCETable
+        // **** and the CEBuffer constructor...
+#if 0
+        uprv_init_pce(strsrch->textIter);
+        uprv_init_pce(strsrch->utilIter);
+#endif
+    }
+}
+
+U_CAPI UCollator * U_EXPORT2 usearch_getCollator(const UStringSearch *strsrch)
+{
+    if (strsrch) {
+        return (UCollator *)strsrch->collator;
+    }
+    return NULL;
+}
+
+U_CAPI void U_EXPORT2 usearch_setPattern(      UStringSearch *strsrch,
+                                         const UChar         *pattern,
+                                               int32_t        patternlength,
+                                               UErrorCode    *status)
+{
+    if (U_SUCCESS(*status)) {
+        if (strsrch == NULL || pattern == NULL) {
+            *status = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+        else {
+            if (patternlength == -1) {
+                patternlength = u_strlen(pattern);
+            }
+            if (patternlength == 0) {
+                *status = U_ILLEGAL_ARGUMENT_ERROR;
+                return;
+            }
+            strsrch->pattern.text       = pattern;
+            strsrch->pattern.textLength = patternlength;
+            initialize(strsrch, status);
+        }
+    }
+}
+
+U_CAPI const UChar* U_EXPORT2
+usearch_getPattern(const UStringSearch *strsrch,
+                   int32_t       *length)
+{
+    if (strsrch) {
+        *length = strsrch->pattern.textLength;
+        return strsrch->pattern.text;
+    }
+    return NULL;
+}
+
+// miscellanous methods --------------------------------------------------
+
+U_CAPI int32_t U_EXPORT2 usearch_first(UStringSearch *strsrch,
+                                           UErrorCode    *status)
+{
+    if (strsrch && U_SUCCESS(*status)) {
+        strsrch->search->isForwardSearching = TRUE;
+        usearch_setOffset(strsrch, 0, status);
+        if (U_SUCCESS(*status)) {
+            return usearch_next(strsrch, status);
+        }
+    }
+    return USEARCH_DONE;
+}
+
+U_CAPI int32_t U_EXPORT2 usearch_following(UStringSearch *strsrch,
+                                               int32_t    position,
+                                               UErrorCode    *status)
+{
+    if (strsrch && U_SUCCESS(*status)) {
+        strsrch->search->isForwardSearching = TRUE;
+        // position checked in usearch_setOffset
+        usearch_setOffset(strsrch, position, status);
+        if (U_SUCCESS(*status)) {
+            return usearch_next(strsrch, status);
+        }
+    }
+    return USEARCH_DONE;
+}
+
+U_CAPI int32_t U_EXPORT2 usearch_last(UStringSearch *strsrch,
+                                          UErrorCode    *status)
+{
+    if (strsrch && U_SUCCESS(*status)) {
+        strsrch->search->isForwardSearching = FALSE;
+        usearch_setOffset(strsrch, strsrch->search->textLength, status);
+        if (U_SUCCESS(*status)) {
+            return usearch_previous(strsrch, status);
+        }
+    }
+    return USEARCH_DONE;
+}
+
+U_CAPI int32_t U_EXPORT2 usearch_preceding(UStringSearch *strsrch,
+                                               int32_t    position,
+                                               UErrorCode    *status)
+{
+    if (strsrch && U_SUCCESS(*status)) {
+        strsrch->search->isForwardSearching = FALSE;
+        // position checked in usearch_setOffset
+        usearch_setOffset(strsrch, position, status);
+        if (U_SUCCESS(*status)) {
+            return usearch_previous(strsrch, status);
+        }
+    }
+    return USEARCH_DONE;
+}
+
+/**
+* If a direction switch is required, we'll count the number of ces till the
+* beginning of the collation element iterator and iterate forwards that
+* number of times. This is so that we get to the correct point within the
+* string to continue the search in. Imagine when we are in the middle of the
+* normalization buffer when the change in direction is request. arrrgghh....
+* After searching the offset within the collation element iterator will be
+* shifted to the start of the match. If a match is not found, the offset would
+* have been set to the end of the text string in the collation element
+* iterator.
+* Okay, here's my take on normalization buffer. The only time when there can
+* be 2 matches within the same normalization is when the pattern is consists
+* of all accents. But since the offset returned is from the text string, we
+* should not confuse the caller by returning the second match within the
+* same normalization buffer. If we do, the 2 results will have the same match
+* offsets, and that'll be confusing. I'll return the next match that doesn't
+* fall within the same normalization buffer. Note this does not affect the
+* results of matches spanning the text and the normalization buffer.
+* The position to start searching is taken from the collation element
+* iterator. Callers of this API would have to set the offset in the collation
+* element iterator before using this method.
+*/
+U_CAPI int32_t U_EXPORT2 usearch_next(UStringSearch *strsrch,
+                                          UErrorCode    *status)
+{
+    if (U_SUCCESS(*status) && strsrch) {
+        // note offset is either equivalent to the start of the previous match
+        // or is set by the user
+        int32_t      offset       = usearch_getOffset(strsrch);
+        USearch     *search       = strsrch->search;
+        search->reset             = FALSE;
+        int32_t      textlength   = search->textLength;
+        if (search->isForwardSearching) {
+#if BOYER_MOORE
+            if (offset == textlength
+                || (!search->isOverlap &&
+                    (offset + strsrch->pattern.defaultShiftSize > textlength ||
+                    (search->matchedIndex != USEARCH_DONE &&
+                     offset + search->matchedLength >= textlength)))) {
+                // not enough characters to match
+                setMatchNotFound(strsrch);
+                return USEARCH_DONE;
+            }
+#else
+            if (offset == textlength ||
+                (! search->isOverlap &&
+                (search->matchedIndex != USEARCH_DONE &&
+                offset + search->matchedLength > textlength))) {
+                    // not enough characters to match
+                    setMatchNotFound(strsrch);
+                    return USEARCH_DONE;
+            }
+#endif
+        }
+        else {
+            // switching direction.
+            // if matchedIndex == USEARCH_DONE, it means that either a
+            // setOffset has been called or that previous ran off the text
+            // string. the iterator would have been set to offset 0 if a
+            // match is not found.
+            search->isForwardSearching = TRUE;
+            if (search->matchedIndex != USEARCH_DONE) {
+                // there's no need to set the collation element iterator
+                // the next call to next will set the offset.
+                return search->matchedIndex;
+            }
+        }
+
+        if (U_SUCCESS(*status)) {
+            if (strsrch->pattern.CELength == 0) {
+                if (search->matchedIndex == USEARCH_DONE) {
+                    search->matchedIndex = offset;
+                }
+                else { // moves by codepoints
+                    UTF_FWD_1(search->text, search->matchedIndex, textlength);
+                }
+
+                search->matchedLength = 0;
+                setColEIterOffset(strsrch->textIter, search->matchedIndex);
+                // status checked below
+                if (search->matchedIndex == textlength) {
+                    search->matchedIndex = USEARCH_DONE;
+                }
+            }
+            else {
+                if (search->matchedLength > 0) {
+                    // if matchlength is 0 we are at the start of the iteration
+                    if (search->isOverlap) {
+                        ucol_setOffset(strsrch->textIter, offset + 1, status);
+                    }
+                    else {
+                        ucol_setOffset(strsrch->textIter,
+                                       offset + search->matchedLength, status);
+                    }
+                }
+                else {
+                    // for boundary check purposes. this will ensure that the
+                    // next match will not preceed the current offset
+                    // note search->matchedIndex will always be set to something
+                    // in the code
+                    search->matchedIndex = offset - 1;
+                }
+
+                if (search->isCanonicalMatch) {
+                    // can't use exact here since extra accents are allowed.
+                    usearch_handleNextCanonical(strsrch, status);
+                }
+                else {
+                    usearch_handleNextExact(strsrch, status);
+                }
+            }
+
+            if (U_FAILURE(*status)) {
+                return USEARCH_DONE;
+            }
+
+#if !BOYER_MOORE
+            if (search->matchedIndex == USEARCH_DONE) {
+                ucol_setOffset(strsrch->textIter, search->textLength, status);
+            } else {
+                ucol_setOffset(strsrch->textIter, search->matchedIndex, status);
+            }
+#endif
+
+            return search->matchedIndex;
+        }
+    }
+    return USEARCH_DONE;
+}
+
+U_CAPI int32_t U_EXPORT2 usearch_previous(UStringSearch *strsrch,
+                                              UErrorCode *status)
+{
+    if (U_SUCCESS(*status) && strsrch) {
+        int32_t offset;
+        USearch *search = strsrch->search;
+        if (search->reset) {
+            offset                     = search->textLength;
+            search->isForwardSearching = FALSE;
+            search->reset              = FALSE;
+            setColEIterOffset(strsrch->textIter, offset);
+        }
+        else {
+            offset = usearch_getOffset(strsrch);
+        }
+
+        int32_t matchedindex = search->matchedIndex;
+        if (search->isForwardSearching == TRUE) {
+            // switching direction.
+            // if matchedIndex == USEARCH_DONE, it means that either a
+            // setOffset has been called or that next ran off the text
+            // string. the iterator would have been set to offset textLength if
+            // a match is not found.
+            search->isForwardSearching = FALSE;
+            if (matchedindex != USEARCH_DONE) {
+                return matchedindex;
+            }
+        }
+        else {
+#if BOYER_MOORE
+            if (offset == 0 || matchedindex == 0 ||
+                (!search->isOverlap &&
+                    (offset < strsrch->pattern.defaultShiftSize ||
+                    (matchedindex != USEARCH_DONE &&
+                    matchedindex < strsrch->pattern.defaultShiftSize)))) {
+                // not enough characters to match
+                setMatchNotFound(strsrch);
+                return USEARCH_DONE;
+            }
+#else
+            // Could check pattern length, but the
+            // linear search will do the right thing
+            if (offset == 0 || matchedindex == 0) {
+                setMatchNotFound(strsrch);
+                return USEARCH_DONE;
+            }
+#endif
+        }
+
+        if (U_SUCCESS(*status)) {
+            if (strsrch->pattern.CELength == 0) {
+                search->matchedIndex =
+                      (matchedindex == USEARCH_DONE ? offset : matchedindex);
+                if (search->matchedIndex == 0) {
+                    setMatchNotFound(strsrch);
+                    // status checked below
+                }
+                else { // move by codepoints
+                    UTF_BACK_1(search->text, 0, search->matchedIndex);
+                    setColEIterOffset(strsrch->textIter, search->matchedIndex);
+                    // status checked below
+                    search->matchedLength = 0;
+                }
+            }
+            else {
+#if !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.PCELength+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/source/i18n/uspoof.cpp b/source/i18n/uspoof.cpp
new file mode 100644
index 0000000..48e3e45
--- /dev/null
+++ b/source/i18n/uspoof.cpp
@@ -0,0 +1,827 @@
+/*
+***************************************************************************
+* Copyright (C) 2008-2011, International Business Machines Corporation
+* and others. All Rights Reserved.
+***************************************************************************
+*   file name:  uspoof.cpp
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2008Feb13
+*   created by: Andy Heninger
+*
+*   Unicode Spoof Detection
+*/
+#include "unicode/utypes.h"
+#include "unicode/uspoof.h"
+#include "unicode/unorm.h"
+#include "unicode/ustring.h"
+#include "cmemory.h"
+#include "uspoof_impl.h"
+#include "uassert.h"
+
+
+#if !UCONFIG_NO_NORMALIZATION
+
+
+#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 NFD input
+        NFDBuffer   normalizedInput(text, length, *status);
+        const UChar  *nfdText = normalizedInput.getBuffer();
+        int32_t      nfdLength = normalizedInput.getLength();
+
+        if (This->fChecks & USPOOF_INVISIBLE) {
+           
+            // scan for more than one occurence of the same non-spacing mark
+            // in a sequence of non-spacing marks.
+            int32_t     i;
+            UChar32     c;
+            UChar32     firstNonspacingMark = 0;
+            UBool       haveMultipleMarks = FALSE;  
+            UnicodeSet  marksSeenSoFar;   // Set of combining marks in a single combining sequence.
+            
+            for (i=0; i<length ;) {
+                U16_NEXT(nfdText, i, nfdLength, c);
+                if (u_charType(c) != U_NON_SPACING_MARK) {
+                    firstNonspacingMark = 0;
+                    if (haveMultipleMarks) {
+                        marksSeenSoFar.clear();
+                        haveMultipleMarks = FALSE;
+                    }
+                    continue;
+                }
+                if (firstNonspacingMark == 0) {
+                    firstNonspacingMark = c;
+                    continue;
+                }
+                if (!haveMultipleMarks) {
+                    marksSeenSoFar.add(firstNonspacingMark);
+                    haveMultipleMarks = TRUE;
+                }
+                if (marksSeenSoFar.contains(c)) {
+                    // report the error, and stop scanning.
+                    // No need to find more than the first failure.
+                    result |= USPOOF_INVISIBLE;
+                    failPos = i;
+                    break;
+                }
+                marksSeenSoFar.add(c);
+            }
+        }
+       
+        
+        if (This->fChecks & (USPOOF_WHOLE_SCRIPT_CONFUSABLE | USPOOF_MIXED_SCRIPT_CONFUSABLE)) {
+            // The basic test is the same for both whole and mixed script confusables.
+            // Compute the set of scripts that every input character has a confusable in.
+            // For this computation an input character is always considered to be
+            //    confusable with itself in its own script.
+            // If the number of such scripts is two or more, and the input consisted of
+            //   characters all from a single script, we have a whole script confusable.
+            //   (The two scripts will be the original script and the one that is confusable)
+            // If the number of such scripts >= one, and the original input contained characters from
+            //   more than one script, we have a mixed script confusable.  (We can transform
+            //   some of the characters, and end up with a visually similar string all in
+            //   one script.)
+
+            if (scriptCount == -1) {
+                int32_t t;
+                scriptCount = This->scriptScan(text, length, t, *status);
+            }
+            
+            ScriptSet scripts;
+            This->wholeScriptCheck(nfdText, nfdLength, &scripts, *status);
+            int32_t confusableScriptCount = scripts.countMembers();
+            //printf("confusableScriptCount = %d\n", confusableScriptCount);
+            
+            if ((This->fChecks & USPOOF_WHOLE_SCRIPT_CONFUSABLE) &&
+                confusableScriptCount >= 2 &&
+                scriptCount == 1) {
+                result |= USPOOF_WHOLE_SCRIPT_CONFUSABLE;
+            }
+        
+            if ((This->fChecks & USPOOF_MIXED_SCRIPT_CONFUSABLE) &&
+                confusableScriptCount >= 1 &&
+                scriptCount > 1) {
+                result |= USPOOF_MIXED_SCRIPT_CONFUSABLE;
+            }
+        }
+    }
+    if (position != NULL && failPos != 0x7fffffff) {
+        *position = failPos;
+    }
+    return result;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_checkUTF8(const USpoofChecker *sc,
+                 const char *text, int32_t length,
+                 int32_t *position,
+                 UErrorCode *status) {
+
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+    UChar stackBuf[USPOOF_STACK_BUFFER_SIZE];
+    UChar* text16 = stackBuf;
+    int32_t len16;
+    
+    u_strFromUTF8(text16, USPOOF_STACK_BUFFER_SIZE, &len16, text, length, status);
+    if (U_FAILURE(*status) && *status != U_BUFFER_OVERFLOW_ERROR) {
+        return 0;
+    }
+    if (*status == U_BUFFER_OVERFLOW_ERROR) {
+        text16 = static_cast<UChar *>(uprv_malloc(len16 * sizeof(UChar) + 2));
+        if (text16 == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+        *status = U_ZERO_ERROR;
+        u_strFromUTF8(text16, len16+1, NULL, text, length, status);
+    }
+
+    int32_t position16 = -1;
+    int32_t result = uspoof_check(sc, text16, len16, &position16, status);
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+
+    if (position16 > 0) {
+        // Translate a UTF-16 based error position back to a UTF-8 offset.
+        // u_strToUTF8() in preflight mode is an easy way to do it.
+        U_ASSERT(position16 <= len16);
+        u_strToUTF8(NULL, 0, position, text16, position16, status);
+        if (position > 0) {
+            // position is the required buffer length from u_strToUTF8, which includes
+            // space for a terminating NULL, which we don't want, hence the -1.
+            *position -= 1;
+        }
+        *status = U_ZERO_ERROR;   // u_strToUTF8, above sets BUFFER_OVERFLOW_ERROR.
+    }
+
+    if (text16 != stackBuf) {
+        uprv_free(text16);
+    }
+    return result;
+    
+}
+
+/*  A convenience wrapper around the public uspoof_getSkeleton that handles
+ *  allocating a larger buffer than provided if the original is too small.
+ */
+static UChar *getSkeleton(const USpoofChecker *sc, uint32_t type, const UChar *s, int32_t inputLength,
+                         UChar *dest, int32_t destCapacity, int32_t *outputLength, UErrorCode *status) {
+    int32_t requiredCapacity = 0;
+    UChar *buf = dest;
+
+    if (U_FAILURE(*status)) {
+        return NULL;
+    }
+    requiredCapacity = uspoof_getSkeleton(sc, type, s, inputLength, dest, destCapacity, status);
+    if (*status == U_BUFFER_OVERFLOW_ERROR) {
+        buf = static_cast<UChar *>(uprv_malloc(requiredCapacity * sizeof(UChar)));
+        if (buf == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return NULL;
+        }
+        *status = U_ZERO_ERROR;
+        uspoof_getSkeleton(sc, type, s, inputLength, buf, requiredCapacity, status);
+    }
+    *outputLength = requiredCapacity;
+    return buf;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_areConfusable(const USpoofChecker *sc,
+                     const UChar *s1, int32_t length1,
+                     const UChar *s2, int32_t length2,
+                     UErrorCode *status) {
+    const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+    // 
+    // See section 4 of UAX 39 for the algorithm for checking whether two strings are confusable,
+    //   and for definitions of the types (single, whole, mixed-script) of confusables.
+    
+    // We only care about a few of the check flags.  Ignore the others.
+    // If no tests relavant to this function have been specified, return an error.
+    // TODO:  is this really the right thing to do?  It's probably an error on the caller's part,
+    //        but logically we would just return 0 (no error).
+    if ((This->fChecks & (USPOOF_SINGLE_SCRIPT_CONFUSABLE | USPOOF_MIXED_SCRIPT_CONFUSABLE | 
+                          USPOOF_WHOLE_SCRIPT_CONFUSABLE)) == 0) {
+        *status = U_INVALID_STATE_ERROR;
+        return 0;
+    }
+    int32_t  flagsForSkeleton = This->fChecks & USPOOF_ANY_CASE;
+    UChar    s1SkeletonBuf[USPOOF_STACK_BUFFER_SIZE];
+    UChar   *s1Skeleton;
+    int32_t  s1SkeletonLength = 0;
+
+    UChar    s2SkeletonBuf[USPOOF_STACK_BUFFER_SIZE];
+    UChar   *s2Skeleton;
+    int32_t  s2SkeletonLength = 0;
+
+    int32_t  result = 0;
+    int32_t  t;
+    int32_t  s1ScriptCount = This->scriptScan(s1, length1, t, *status);
+    int32_t  s2ScriptCount = This->scriptScan(s2, length2, t, *status);
+
+    if (This->fChecks & USPOOF_SINGLE_SCRIPT_CONFUSABLE) {
+        // Do the Single Script compare.
+        if (s1ScriptCount <= 1 && s2ScriptCount <= 1) {
+            flagsForSkeleton |= USPOOF_SINGLE_SCRIPT_CONFUSABLE;
+            s1Skeleton = getSkeleton(sc, flagsForSkeleton, s1, length1, s1SkeletonBuf, 
+                                     sizeof(s1SkeletonBuf)/sizeof(UChar), &s1SkeletonLength, status);
+            s2Skeleton = getSkeleton(sc, flagsForSkeleton, s2, length2, s2SkeletonBuf, 
+                                     sizeof(s2SkeletonBuf)/sizeof(UChar), &s2SkeletonLength, status);
+            if (s1SkeletonLength == s2SkeletonLength && u_strncmp(s1Skeleton, s2Skeleton, s1SkeletonLength) == 0) {
+                result |= USPOOF_SINGLE_SCRIPT_CONFUSABLE;
+            }
+            if (s1Skeleton != s1SkeletonBuf) {
+                uprv_free(s1Skeleton);
+            }
+            if (s2Skeleton != s2SkeletonBuf) {
+                uprv_free(s2Skeleton);
+            }
+        }
+    }
+
+    if (result & USPOOF_SINGLE_SCRIPT_CONFUSABLE) {
+         // If the two inputs are single script confusable they cannot also be
+         // mixed or whole script confusable, according to the UAX39 definitions.
+         // So we can skip those tests.
+         return result;
+    }
+
+    // Optimization for whole script confusables test:  two identifiers are whole script confusable if
+    // each is of a single script and they are mixed script confusable.
+    UBool possiblyWholeScriptConfusables = 
+        s1ScriptCount <= 1 && s2ScriptCount <= 1 && (This->fChecks & USPOOF_WHOLE_SCRIPT_CONFUSABLE);
+
+    //
+    // Mixed Script Check
+    //
+    if ((This->fChecks & USPOOF_MIXED_SCRIPT_CONFUSABLE) || possiblyWholeScriptConfusables ) {
+        // For getSkeleton(), resetting the USPOOF_SINGLE_SCRIPT_CONFUSABLE flag will get us
+        // the mixed script table skeleton, which is what we want.
+        // The Any Case / Lower Case bit in the skelton flags was set at the top of the function.
+        flagsForSkeleton &= ~USPOOF_SINGLE_SCRIPT_CONFUSABLE;
+        s1Skeleton = getSkeleton(sc, flagsForSkeleton, s1, length1, s1SkeletonBuf, 
+                                 sizeof(s1SkeletonBuf)/sizeof(UChar), &s1SkeletonLength, status);
+        s2Skeleton = getSkeleton(sc, flagsForSkeleton, s2, length2, s2SkeletonBuf, 
+                                 sizeof(s2SkeletonBuf)/sizeof(UChar), &s2SkeletonLength, status);
+        if (s1SkeletonLength == s2SkeletonLength && u_strncmp(s1Skeleton, s2Skeleton, s1SkeletonLength) == 0) {
+            result |= USPOOF_MIXED_SCRIPT_CONFUSABLE;
+            if (possiblyWholeScriptConfusables) {
+                result |= USPOOF_WHOLE_SCRIPT_CONFUSABLE;
+            }
+        }
+        if (s1Skeleton != s1SkeletonBuf) {
+            uprv_free(s1Skeleton);
+        }
+        if (s2Skeleton != s2SkeletonBuf) {
+            uprv_free(s2Skeleton);
+        }
+    }
+
+    return result;
+}
+
+
+// Convenience function for converting a UTF-8 input to a UChar * string, including
+//          reallocating a buffer when required.  Parameters and their interpretation mostly
+//          match u_strFromUTF8.
+
+static UChar * convertFromUTF8(UChar *outBuf, int32_t outBufCapacity, int32_t *outputLength,
+                               const char *in, int32_t inLength, UErrorCode *status) {
+    if (U_FAILURE(*status)) {
+        return NULL;
+    }
+    UChar *dest = outBuf;
+    u_strFromUTF8(dest, outBufCapacity, outputLength, in, inLength, status);
+    if (*status == U_BUFFER_OVERFLOW_ERROR) {
+        dest = static_cast<UChar *>(uprv_malloc(*outputLength * sizeof(UChar)));
+        if (dest == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return NULL;
+        }
+        *status = U_ZERO_ERROR;
+        u_strFromUTF8(dest, *outputLength, NULL, in, inLength, status);
+    }
+    return dest;
+}
+
+    
+
+U_CAPI int32_t U_EXPORT2
+uspoof_areConfusableUTF8(const USpoofChecker *sc,
+                         const char *s1, int32_t length1,
+                         const char *s2, int32_t length2,
+                         UErrorCode *status) {
+
+    SpoofImpl::validateThis(sc, *status);
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+
+    UChar    s1Buf[USPOOF_STACK_BUFFER_SIZE];
+    int32_t  lengthS1U;
+    UChar   *s1U = convertFromUTF8(s1Buf, USPOOF_STACK_BUFFER_SIZE, &lengthS1U, s1, length1, status);
+
+    UChar    s2Buf[USPOOF_STACK_BUFFER_SIZE];
+    int32_t  lengthS2U;
+    UChar   *s2U = convertFromUTF8(s2Buf, USPOOF_STACK_BUFFER_SIZE, &lengthS2U, s2, length2, status);
+
+    int32_t results = uspoof_areConfusable(sc, s1U, lengthS1U, s2U, lengthS2U, status);
+    
+    if (s1U != s1Buf) {
+        uprv_free(s1U);
+    }
+    if (s2U != s2Buf) {
+        uprv_free(s2U);
+    }
+    return results;
+}
+ 
+
+U_CAPI int32_t U_EXPORT2
+uspoof_areConfusableUnicodeString(const USpoofChecker *sc,
+                                  const U_NAMESPACE_QUALIFIER UnicodeString &s1,
+                                  const U_NAMESPACE_QUALIFIER UnicodeString &s2,
+                                  UErrorCode *status) {
+
+    const UChar *u1  = s1.getBuffer();
+    int32_t  length1 = s1.length();
+    const UChar *u2  = s2.getBuffer();
+    int32_t  length2 = s2.length();
+
+    int32_t results  = uspoof_areConfusable(sc, u1, length1, u2, length2, status);
+    return results;
+}
+
+
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_checkUnicodeString(const USpoofChecker *sc,
+                          const U_NAMESPACE_QUALIFIER UnicodeString &text, 
+                          int32_t *position,
+                          UErrorCode *status) {
+    int32_t result = uspoof_check(sc, text.getBuffer(), text.length(), position, status);
+    return result;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_getSkeleton(const USpoofChecker *sc,
+                   uint32_t type,
+                   const UChar *s,  int32_t length,
+                   UChar *dest, int32_t destCapacity,
+                   UErrorCode *status) {
+
+    // TODO:  this function could be sped up a bit
+    //        Skip the input normalization when not needed, work from callers data.
+    //        Put the initial skeleton straight into the caller's destination buffer.
+    //        It probably won't need normalization.
+    //        But these would make the structure more complicated.  
+
+    const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+    if (length<-1 || destCapacity<0 || (destCapacity==0 && dest!=NULL) ||
+        (type & ~(USPOOF_SINGLE_SCRIPT_CONFUSABLE | USPOOF_ANY_CASE)) != 0) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+   int32_t tableMask = 0;
+   switch (type) {
+      case 0:
+        tableMask = USPOOF_ML_TABLE_FLAG;
+        break;
+      case USPOOF_SINGLE_SCRIPT_CONFUSABLE:
+        tableMask = USPOOF_SL_TABLE_FLAG;
+        break;
+      case USPOOF_ANY_CASE:
+        tableMask = USPOOF_MA_TABLE_FLAG;
+        break;
+      case USPOOF_SINGLE_SCRIPT_CONFUSABLE | USPOOF_ANY_CASE:
+        tableMask = USPOOF_SA_TABLE_FLAG;
+        break;
+      default:
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    // NFD transform of the user supplied input
+    
+    UChar nfdStackBuf[USPOOF_STACK_BUFFER_SIZE];
+    UChar *nfdInput = nfdStackBuf;
+    int32_t normalizedLen = unorm_normalize(
+        s, length, UNORM_NFD, 0, nfdInput, USPOOF_STACK_BUFFER_SIZE, status);
+    if (*status == U_BUFFER_OVERFLOW_ERROR) {
+        nfdInput = (UChar *)uprv_malloc((normalizedLen+1)*sizeof(UChar));
+        if (nfdInput == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+        *status = U_ZERO_ERROR;
+        normalizedLen = unorm_normalize(s, length, UNORM_NFD, 0,
+                                        nfdInput, normalizedLen+1, status);
+    }
+    if (U_FAILURE(*status)) {
+        if (nfdInput != nfdStackBuf) {
+            uprv_free(nfdInput);
+        }
+        return 0;
+    }
+
+    // buffer to hold the Unicode defined skeleton mappings for a single code point
+    UChar buf[USPOOF_MAX_SKELETON_EXPANSION];
+
+    // Apply the skeleton mapping to the NFD normalized input string
+    // Accumulate the skeleton, possibly unnormalized, in a UnicodeString.
+    int32_t inputIndex = 0;
+    UnicodeString skelStr;
+    while (inputIndex < normalizedLen) {
+        UChar32 c;
+        U16_NEXT(nfdInput, inputIndex, normalizedLen, c);
+        int32_t replaceLen = This->confusableLookup(c, tableMask, buf);
+        skelStr.append(buf, replaceLen);
+    }
+
+    if (nfdInput != nfdStackBuf) {
+        uprv_free(nfdInput);
+    }
+    
+    const UChar *result = skelStr.getBuffer();
+    int32_t  resultLen  = skelStr.length();
+    UChar   *normedResult = NULL;
+
+    // Check the skeleton for NFD, normalize it if needed.
+    // Unnormalized results should be very rare.
+    if (!unorm_isNormalized(result, resultLen, UNORM_NFD, status)) {
+        normalizedLen = unorm_normalize(result, resultLen, UNORM_NFD, 0, NULL, 0, status);
+        normedResult = static_cast<UChar *>(uprv_malloc((normalizedLen+1)*sizeof(UChar)));
+        if (normedResult == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+        *status = U_ZERO_ERROR;
+        unorm_normalize(result, resultLen, UNORM_NFD, 0, normedResult, normalizedLen+1, status);
+        result = normedResult;
+        resultLen = normalizedLen;
+    }
+
+    // Copy the skeleton to the caller's buffer
+    if (U_SUCCESS(*status)) {
+        if (destCapacity == 0 || resultLen > destCapacity) {
+            *status = resultLen>destCapacity ? U_BUFFER_OVERFLOW_ERROR : U_STRING_NOT_TERMINATED_WARNING;
+        } else {
+            u_memcpy(dest, result, resultLen);
+            if (destCapacity > resultLen) {
+                dest[resultLen] = 0;
+            } else {
+                *status = U_STRING_NOT_TERMINATED_WARNING;
+            }
+        }
+     }       
+     uprv_free(normedResult);
+     return resultLen;
+}
+
+
+
+U_CAPI UnicodeString &  U_EXPORT2
+uspoof_getSkeletonUnicodeString(const USpoofChecker *sc,
+                                uint32_t type,
+                                const UnicodeString &s,
+                                UnicodeString &dest,
+                                UErrorCode *status) {
+    if (U_FAILURE(*status)) {
+        return dest;
+    }
+    dest.remove();
+    
+    const UChar *str = s.getBuffer();
+    int32_t      strLen = s.length();
+    UChar        smallBuf[USPOOF_STACK_BUFFER_SIZE];
+    UChar       *buf = smallBuf;
+    int32_t outputSize = uspoof_getSkeleton(sc, type, str, strLen, smallBuf, USPOOF_STACK_BUFFER_SIZE, status);
+    if (*status == U_BUFFER_OVERFLOW_ERROR) {
+        buf = static_cast<UChar *>(uprv_malloc((outputSize+1)*sizeof(UChar)));
+        if (buf == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            return dest;
+        }
+        *status = U_ZERO_ERROR;
+        uspoof_getSkeleton(sc, type, str, strLen, buf, outputSize+1, status);
+    }
+    if (U_SUCCESS(*status)) {
+        dest.setTo(buf, outputSize);
+    }
+
+    if (buf != smallBuf) {
+        uprv_free(buf);
+    }
+    return dest;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_getSkeletonUTF8(const USpoofChecker *sc,
+                       uint32_t type,
+                       const char *s,  int32_t length,
+                       char *dest, int32_t destCapacity,
+                       UErrorCode *status) {
+    // Lacking a UTF-8 normalization API, just converting the input to
+    // UTF-16 seems as good an approach as any.  In typical use, input will
+    // be an identifier, which is to say not too long for stack buffers.
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+    // Buffers for the UChar form of the input and skeleton strings.
+    UChar    smallInBuf[USPOOF_STACK_BUFFER_SIZE];
+    UChar   *inBuf = smallInBuf;
+    UChar    smallOutBuf[USPOOF_STACK_BUFFER_SIZE];
+    UChar   *outBuf = smallOutBuf;
+
+    int32_t  lengthInUChars = 0;
+    int32_t  skelLengthInUChars = 0;
+    int32_t  skelLengthInUTF8 = 0;
+    
+    u_strFromUTF8(inBuf, USPOOF_STACK_BUFFER_SIZE, &lengthInUChars,
+                  s, length, status);
+    if (*status == U_BUFFER_OVERFLOW_ERROR) {
+        inBuf = static_cast<UChar *>(uprv_malloc((lengthInUChars+1)*sizeof(UChar)));
+        if (inBuf == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            goto cleanup;
+        }
+        *status = U_ZERO_ERROR;
+        u_strFromUTF8(inBuf, lengthInUChars+1, &lengthInUChars,
+                      s, length, status);
+    }
+    
+    skelLengthInUChars = uspoof_getSkeleton(sc, type, inBuf, lengthInUChars,
+                                         outBuf, USPOOF_STACK_BUFFER_SIZE, status);
+    if (*status == U_BUFFER_OVERFLOW_ERROR) {
+        outBuf = static_cast<UChar *>(uprv_malloc((skelLengthInUChars+1)*sizeof(UChar)));
+        if (outBuf == NULL) {
+            *status = U_MEMORY_ALLOCATION_ERROR;
+            goto cleanup;
+        }
+        *status = U_ZERO_ERROR;
+        skelLengthInUChars = uspoof_getSkeleton(sc, type, inBuf, lengthInUChars,
+                                         outBuf, skelLengthInUChars+1, status);
+    }
+
+    u_strToUTF8(dest, destCapacity, &skelLengthInUTF8,
+                outBuf, skelLengthInUChars, status);
+
+  cleanup:
+    if (inBuf != smallInBuf) {
+        uprv_free(inBuf);
+    }
+    if (outBuf != smallOutBuf) {
+        uprv_free(outBuf);
+    }
+    return skelLengthInUTF8;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_serialize(USpoofChecker *sc,void *buf, int32_t capacity, UErrorCode *status) {
+    SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+    if (This == NULL) {
+        U_ASSERT(U_FAILURE(*status));
+        return 0;
+    }
+    int32_t dataSize = This->fSpoofData->fRawData->fLength;
+    if (capacity < dataSize) {
+        *status = U_BUFFER_OVERFLOW_ERROR;
+        return dataSize;
+    }
+    uprv_memcpy(buf, This->fSpoofData->fRawData, dataSize);
+    return dataSize;
+}
+
+#endif
diff --git a/source/i18n/uspoof_build.cpp b/source/i18n/uspoof_build.cpp
new file mode 100644
index 0000000..681282e
--- /dev/null
+++ b/source/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/source/i18n/uspoof_conf.cpp b/source/i18n/uspoof_conf.cpp
new file mode 100644
index 0000000..7a8f207
--- /dev/null
+++ b/source/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/source/i18n/uspoof_conf.h b/source/i18n/uspoof_conf.h
new file mode 100644
index 0000000..d23e6d5
--- /dev/null
+++ b/source/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/source/i18n/uspoof_impl.cpp b/source/i18n/uspoof_impl.cpp
new file mode 100644
index 0000000..790c8c8
--- /dev/null
+++ b/source/i18n/uspoof_impl.cpp
@@ -0,0 +1,964 @@
+/*
+**********************************************************************
+*   Copyright (C) 2008-2011, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uspoof.h"
+#include "unicode/unorm.h"
+#include "unicode/uchar.h"
+#include "unicode/uniset.h"
+#include "utrie2.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "udatamem.h"
+#include "umutex.h"
+#include "udataswp.h"
+#include "uassert.h"
+#include "uspoof_impl.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SpoofImpl)
+
+SpoofImpl::SpoofImpl(SpoofData *data, UErrorCode &status) :
+    fMagic(0), fSpoofData(NULL), fAllowedCharsSet(NULL) , fAllowedLocales(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 NFD
+//      Return the set of scripts, each of which can represent something that is
+//             confusable with the input text.  The script of the input text
+//             is included; input consisting of characters from a single script will
+//             always produce a result consisting of a set containing that script.
+//
+//---------------------------------------------------------------------------------------
+void SpoofImpl::wholeScriptCheck(
+    const UChar *text, int32_t length, ScriptSet *result, UErrorCode &status) const {
+
+    int32_t       inputIdx = 0;
+    UChar32       c;
+
+    UTrie2 *table =
+        (fChecks & USPOOF_ANY_CASE) ? fSpoofData->fAnyCaseTrie : fSpoofData->fLowerCaseTrie;
+    result->setAll();
+    while (inputIdx < length) {
+        U16_NEXT(text, inputIdx, length, c);
+        uint32_t index = utrie2_get32(table, c);
+        if (index == 0) {
+            // No confusables in another script for this char.
+            // TODO:  we should change the data to have sets with just the single script
+            //        bit for the script of this char.  Gets rid of this special case.
+            //        Until then, grab the script from the char and intersect it with the set.
+            UScriptCode cpScript = uscript_getScript(c, &status);
+            U_ASSERT(cpScript > USCRIPT_INHERITED);
+            result->intersect(cpScript);
+        } else if (index == 1) {
+            // Script == Common or Inherited.  Nothing to do.
+        } else {
+            result->intersect(fSpoofData->fScriptSets[index]);
+        }
+    }
+}
+
+
+void SpoofImpl::setAllowedLocales(const char *localesList, UErrorCode &status) {
+    UnicodeSet    allowedChars;
+    UnicodeSet    *tmpSet = NULL;
+    const char    *locStart = localesList;
+    const char    *locEnd = NULL;
+    const char    *localesListEnd = localesList + uprv_strlen(localesList);
+    int32_t        localeListCount = 0;   // Number of locales provided by caller.
+
+    // Loop runs once per locale from the localesList, a comma separated list of locales.
+    do {
+        locEnd = uprv_strchr(locStart, ',');
+        if (locEnd == NULL) {
+            locEnd = localesListEnd;
+        }
+        while (*locStart == ' ') {
+            locStart++;
+        }
+        const char *trimmedEnd = locEnd-1;
+        while (trimmedEnd > locStart && *trimmedEnd == ' ') {
+            trimmedEnd--;
+        }
+        if (trimmedEnd <= locStart) {
+            break;
+        }
+        const char *locale = uprv_strndup(locStart, (int32_t)(trimmedEnd + 1 - locStart));
+        localeListCount++;
+
+        // We have one locale from the locales list.
+        // Add the script chars for this locale to the accumulating set of allowed chars.
+        // If the locale is no good, we will be notified back via status.
+        addScriptChars(locale, &allowedChars, status);
+        uprv_free((void *)locale);
+        if (U_FAILURE(status)) {
+            break;
+        }
+        locStart = locEnd + 1;
+    } while (locStart < localesListEnd);
+
+    // If our caller provided an empty list of locales, we disable the allowed characters checking
+    if (localeListCount == 0) {
+        uprv_free((void *)fAllowedLocales);
+        fAllowedLocales = uprv_strdup("");
+        tmpSet = new UnicodeSet(0, 0x10ffff);
+        if (fAllowedLocales == NULL || tmpSet == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return;
+        } 
+        tmpSet->freeze();
+        delete fAllowedCharsSet;
+        fAllowedCharsSet = tmpSet;
+        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;
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+//  NFDBuffer Implementation.
+//
+//-----------------------------------------------------------------------------
+
+NFDBuffer::NFDBuffer(const UChar *text, int32_t length, UErrorCode &status) {
+    fNormalizedText = NULL;
+    fNormalizedTextLength = 0;
+    fOriginalText = text;
+    if (U_FAILURE(status)) {
+        return;
+    }
+    fNormalizedText = fSmallBuf;
+    fNormalizedTextLength = unorm_normalize(
+        text, length, UNORM_NFD, 0, fNormalizedText, USPOOF_STACK_BUFFER_SIZE, &status);
+    if (status == U_BUFFER_OVERFLOW_ERROR) {
+        status = U_ZERO_ERROR;
+        fNormalizedText = (UChar *)uprv_malloc((fNormalizedTextLength+1)*sizeof(UChar));
+        if (fNormalizedText == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+        } else {
+            fNormalizedTextLength = unorm_normalize(text, length, UNORM_NFD, 0,
+                                        fNormalizedText, fNormalizedTextLength+1, &status);
+        }
+    }
+}
+
+
+NFDBuffer::~NFDBuffer() {
+    if (fNormalizedText != fSmallBuf) {
+        uprv_free(fNormalizedText);
+    }
+    fNormalizedText = 0;
+}
+
+const UChar *NFDBuffer::getBuffer() {
+    return fNormalizedText;
+}
+
+int32_t NFDBuffer::getLength() {
+    return fNormalizedTextLength;
+}
+
+
+
+
+
+U_NAMESPACE_END
+
+U_NAMESPACE_USE
+
+//-----------------------------------------------------------------------------
+//
+//  uspoof_swap   -  byte swap and char encoding swap of spoof data
+//
+//-----------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uspoof_swap(const UDataSwapper *ds, const void *inData, int32_t length, void *outData,
+           UErrorCode *status) {
+
+    if (status == NULL || U_FAILURE(*status)) {
+        return 0;
+    }
+    if(ds==NULL || inData==NULL || length<-1 || (length>0 && outData==NULL)) {
+        *status=U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    //
+    //  Check that the data header is for spoof data.
+    //    (Header contents are defined in gencfu.cpp)
+    //
+    const UDataInfo *pInfo = (const UDataInfo *)((const char *)inData+4);
+    if(!(  pInfo->dataFormat[0]==0x43 &&   /* dataFormat="Cfu " */
+           pInfo->dataFormat[1]==0x66 &&
+           pInfo->dataFormat[2]==0x75 &&
+           pInfo->dataFormat[3]==0x20 &&
+           pInfo->formatVersion[0]==1  )) {
+        udata_printError(ds, "uspoof_swap(): data format %02x.%02x.%02x.%02x "
+                             "(format version %02x %02x %02x %02x) is not recognized\n",
+                         pInfo->dataFormat[0], pInfo->dataFormat[1],
+                         pInfo->dataFormat[2], pInfo->dataFormat[3],
+                         pInfo->formatVersion[0], pInfo->formatVersion[1],
+                         pInfo->formatVersion[2], pInfo->formatVersion[3]);
+        *status=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    //
+    // Swap the data header.  (This is the generic ICU Data Header, not the uspoof Specific
+    //                         header).  This swap also conveniently gets us
+    //                         the size of the ICU d.h., which lets us locate the start
+    //                         of the uspoof specific data.
+    //
+    int32_t headerSize=udata_swapDataHeader(ds, inData, length, outData, status);
+
+
+    //
+    // Get the Spoof Data Header, and check that it appears to be OK.
+    //
+    //
+    const uint8_t   *inBytes =(const uint8_t *)inData+headerSize;
+    SpoofDataHeader *spoofDH = (SpoofDataHeader *)inBytes;
+    if (ds->readUInt32(spoofDH->fMagic)   != USPOOF_MAGIC ||
+        ds->readUInt32(spoofDH->fLength)  <  sizeof(SpoofDataHeader)) 
+    {
+        udata_printError(ds, "uspoof_swap(): Spoof Data header is invalid.\n");
+        *status=U_UNSUPPORTED_ERROR;
+        return 0;
+    }
+
+    //
+    // Prefight operation?  Just return the size
+    //
+    int32_t spoofDataLength = ds->readUInt32(spoofDH->fLength);
+    int32_t totalSize = headerSize + spoofDataLength;
+    if (length < 0) {
+        return totalSize;
+    }
+
+    //
+    // Check that length passed in is consistent with length from Spoof data header.
+    //
+    if (length < totalSize) {
+        udata_printError(ds, "uspoof_swap(): too few bytes (%d after ICU Data header) for spoof data.\n",
+                            spoofDataLength);
+        *status=U_INDEX_OUTOFBOUNDS_ERROR;
+        return 0;
+        }
+
+
+    //
+    // Swap the Data.  Do the data itself first, then the Spoof Data Header, because
+    //                 we need to reference the header to locate the data, and an
+    //                 inplace swap of the header leaves it unusable.
+    //
+    uint8_t          *outBytes = (uint8_t *)outData + headerSize;
+    SpoofDataHeader  *outputDH = (SpoofDataHeader *)outBytes;
+
+    int32_t   sectionStart;
+    int32_t   sectionLength;
+
+    //
+    // If not swapping in place, zero out the output buffer before starting.
+    //    Gaps may exist between the individual sections, and these must be zeroed in
+    //    the output buffer.  The simplest way to do that is to just zero the whole thing.
+    //
+    if (inBytes != outBytes) {
+        uprv_memset(outBytes, 0, spoofDataLength);
+    }
+
+    // Confusables Keys Section   (fCFUKeys)
+    sectionStart  = ds->readUInt32(spoofDH->fCFUKeys);
+    sectionLength = ds->readUInt32(spoofDH->fCFUKeysSize) * 4;
+    ds->swapArray32(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+    // String Index Section
+    sectionStart  = ds->readUInt32(spoofDH->fCFUStringIndex);
+    sectionLength = ds->readUInt32(spoofDH->fCFUStringIndexSize) * 2;
+    ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+    // String Table Section
+    sectionStart  = ds->readUInt32(spoofDH->fCFUStringTable);
+    sectionLength = ds->readUInt32(spoofDH->fCFUStringTableLen) * 2;
+    ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+    // String Lengths Section
+    sectionStart  = ds->readUInt32(spoofDH->fCFUStringLengths);
+    sectionLength = ds->readUInt32(spoofDH->fCFUStringLengthsSize) * 4;
+    ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+    // Any Case Trie
+    sectionStart  = ds->readUInt32(spoofDH->fAnyCaseTrie);
+    sectionLength = ds->readUInt32(spoofDH->fAnyCaseTrieLength);
+    utrie2_swap(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+    // Lower Case Trie
+    sectionStart  = ds->readUInt32(spoofDH->fLowerCaseTrie);
+    sectionLength = ds->readUInt32(spoofDH->fLowerCaseTrieLength);
+    utrie2_swap(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+    // Script Sets.  The data is an array of int32_t
+    sectionStart  = ds->readUInt32(spoofDH->fScriptSets);
+    sectionLength = ds->readUInt32(spoofDH->fScriptSetsLength) * sizeof(ScriptSet);
+    ds->swapArray32(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+    // And, last, swap the header itself.
+    //   int32_t   fMagic             // swap this
+    //   uint8_t   fFormatVersion[4]  // Do not swap this, just copy
+    //   int32_t   fLength and all the rest       // Swap the rest, all is 32 bit stuff.
+    //
+    uint32_t magic = ds->readUInt32(spoofDH->fMagic);
+    ds->writeUInt32((uint32_t *)&outputDH->fMagic, magic);
+    uprv_memcpy(outputDH->fFormatVersion, spoofDH->fFormatVersion, sizeof(spoofDH->fFormatVersion));
+    // swap starting at fLength
+    ds->swapArray32(ds, &spoofDH->fLength, sizeof(SpoofDataHeader)-8 /* minus magic and fFormatVersion[4] */, &outputDH->fLength, status);
+
+    return totalSize;
+}
+
+#endif
+
+
diff --git a/source/i18n/uspoof_impl.h b/source/i18n/uspoof_impl.h
new file mode 100644
index 0000000..d4471ed
--- /dev/null
+++ b/source/i18n/uspoof_impl.h
@@ -0,0 +1,414 @@
+/*
+***************************************************************************
+* Copyright (C) 2008-2011, International Business Machines Corporation
+* and others. All Rights Reserved.
+***************************************************************************
+*
+*  uspoof_impl.h
+*
+*    Implemenation header for spoof detection
+*
+*/
+
+#ifndef USPOOFIM_H
+#define USPOOFIM_H
+
+#include "unicode/utypes.h"
+#include "unicode/uspoof.h"
+#include "utrie2.h"
+#include "unicode/uscript.h"
+#include "unicode/udata.h"
+
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#ifdef XP_CPLUSPLUS
+
+U_NAMESPACE_BEGIN
+
+// The maximium length (in UTF-16 UChars) of the skeleton replacement string resulting from
+//   a single input code point.  This is function of the unicode.org data.
+#define USPOOF_MAX_SKELETON_EXPANSION 20
+
+// The default stack buffer size for copies or conversions or normalizations
+// of input strings being checked.  (Used in multiple places.)
+#define USPOOF_STACK_BUFFER_SIZE 100
+
+// Magic number for sanity checking spoof data.
+#define USPOOF_MAGIC 0x3845fdef
+
+class SpoofData;
+struct SpoofDataHeader;
+struct SpoofStringLengthsElement;
+class ScriptSet;
+
+/**
+  *  Class SpoofImpl corresponds directly to the plain C API opaque type
+  *  USpoofChecker.  One can be cast to the other.
+  */
+class SpoofImpl : public UObject  {
+public:
+	SpoofImpl(SpoofData *data, UErrorCode &status);
+	SpoofImpl();
+	virtual ~SpoofImpl();
+
+    /** Copy constructor, used by the user level uspoof_clone() function.
+     */
+    SpoofImpl(const SpoofImpl &src, UErrorCode &status);
+    
+    static SpoofImpl *validateThis(USpoofChecker *sc, UErrorCode &status);
+    static const SpoofImpl *validateThis(const USpoofChecker *sc, UErrorCode &status);
+
+    /** Get the confusable skeleton transform for a single code point.
+     *  The result is a string with a length between 1 and 18.
+     *  @param    tableMask  bit flag specifying which confusable table to use.
+     *                       One of USPOOF_SL_TABLE_FLAG, USPOOF_MA_TABLE_FLAG, etc.
+     *  @return   The length in UTF-16 code units of the substition string.
+     */  
+    int32_t confusableLookup(UChar32 inChar, int32_t tableMask, UChar *destBuf) const;
+
+    /** Set and Get AllowedLocales, implementations of the corresponding API */
+    void setAllowedLocales(const char *localesList, UErrorCode &status);
+    const char * getAllowedLocales(UErrorCode &status);
+
+    // Add (union) to the UnicodeSet all of the characters for the scripts used for
+    // the specified locale.  Part of the implementation of setAllowedLocales.
+    void addScriptChars(const char *locale, UnicodeSet *allowedChars, UErrorCode &status);
+
+
+    /** parse a hex number.  Untility used by the builders.   */
+    static UChar32 ScanHex(const UChar *s, int32_t start, int32_t limit, UErrorCode &status);
+
+    // Implementation for Whole Script tests.
+    // Return the test bit flag to be ORed into the eventual user return value
+    //    if a Spoof opportunity is detected.
+    void wholeScriptCheck(
+        const UChar *text, int32_t length, ScriptSet *result, UErrorCode &status) const;
+	    
+    /** Scan a string to determine how many scripts it includes.
+     * Ignore characters with script=Common and scirpt=Inherited.
+     * @param    text     The UChar text to be scanned
+     * @param    length   The length of the input text, -1 for nul termintated.
+     * @param    pos      An out parameter, set to the first input postion at which
+     *                    a second script was encountered, ignoring Common and Inherited.
+     * @param    status   For errors.
+     * @return            the number of (non-common,inherited) scripts encountered,
+     *                    clipped to a max of two.
+     */
+    int32_t scriptScan(const UChar *text, int32_t length, int32_t &pos, UErrorCode &status) const;
+
+
+    // 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];
+};
+
+
+
+
+//-------------------------------------------------------------------------------
+//
+//  NFDBuffer   A little class to handle the NFD normalization that is
+//               needed on incoming identifiers to be checked.
+//               Takes care of buffer handling and normalization
+//
+//               Instances of this class are intended to be stack-allocated.
+//
+//               TODO:  how to map position offsets back to user values?
+//
+//--------------------------------------------------------------------------------
+class NFDBuffer: public UMemory {
+public:
+    NFDBuffer(const UChar *text, int32_t length, UErrorCode &status);
+    ~NFDBuffer();
+    const UChar *getBuffer();
+    int32_t getLength();
+
+  private:
+    const UChar *fOriginalText;
+    UChar       *fNormalizedText;
+    int32_t      fNormalizedTextLength;
+    UChar        fSmallBuf[USPOOF_STACK_BUFFER_SIZE];
+};
+
+
+
+
+
+//-------------------------------------------------------------------------------------
+//
+//  SpoofData
+//
+//    A small class that wraps the raw (usually memory mapped) spoof data.
+//    Serves two primary functions:
+//      1.  Convenience.  Contains real pointers to the data, to avoid dealing with
+//          the offsets in the raw data.
+//      2.  Reference counting.  When a spoof checker is cloned, the raw data is shared
+//          and must be retained until all checkers using the data are closed.
+//    Nothing in this struct includes state that is specific to any particular
+//    USpoofDetector object.
+//
+//---------------------------------------------------------------------------------------
+class SpoofData: public UMemory {
+  public:
+    static SpoofData *getDefault(UErrorCode &status);   // Load standard ICU spoof data.
+    SpoofData(UErrorCode &status);   // Create new spoof data wrapper.
+                                     // Only used when building new data from rules.
+    
+    // Constructor for use when creating from prebuilt default data.
+    //   A UDataMemory is what the ICU internal data loading functions provide.
+    //   The udm is adopted by the SpoofData.
+    SpoofData(UDataMemory *udm, UErrorCode &status);
+
+    // Constructor for use when creating from serialized data.
+    //
+    SpoofData(const void *serializedData, int32_t length, UErrorCode &status);
+
+    //  Check raw Spoof Data Version compatibility.
+    //  Return TRUE it looks good.
+    static UBool validateDataVersion(const SpoofDataHeader *rawData, UErrorCode &status);
+    ~SpoofData();                    // Destructor not normally used.
+                                     // Use removeReference() instead.
+    // Reference Counting functions.
+    //    Clone of a user-level spoof detector increments the ref count on the data.
+    //    Close of a user-level spoof detector decrements the ref count.
+    //    If the data is owned by us, it will be deleted when count goes to zero.
+    SpoofData *addReference(); 
+    void removeReference();
+
+    // Reserve space in the raw data.  For use by builder when putting together a
+    //   new set of data.  Init the new storage to zero, to prevent inconsistent
+    //   results if it is not all otherwise set by the requester.
+    //  Return:
+    //    pointer to the new space that was added by this function.
+    void *reserveSpace(int32_t numBytes, UErrorCode &status);
+
+    // initialize the pointers from this object to the raw data.
+    void initPtrs(UErrorCode &status);
+
+    // Reset all fields to an initial state.
+    // Called from the top of all constructors.
+    void reset();
+    
+    SpoofDataHeader             *fRawData;          // Ptr to the raw memory-mapped data
+    UBool                       fDataOwned;         // True if the raw data is owned, and needs
+                                                    //  to be deleted when refcount goes to zero.
+    UDataMemory                 *fUDM;              // If not NULL, our data came from a
+                                                    //   UDataMemory, which we must close when
+                                                    //   we'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;                // (0x3845fdef)
+    uint8_t       fFormatVersion[4];     // Data Format. Same as the value in struct UDataInfo
+                                         //   if there is one associated with this data.
+    int32_t       fLength;               // Total lenght in bytes of this spoof data,
+                                         //   including all sections, not just the header.
+
+    // The following four sections refer to data representing the confusable data
+    //   from the Unicode.org data from "confusables.txt"
+
+    int32_t       fCFUKeys;               // byte offset to Keys table (from SpoofDataHeader *)
+    int32_t       fCFUKeysSize;           // number of entries in keys table  (32 bits each)
+
+    // TODO: change name to fCFUValues, for consistency.
+    int32_t       fCFUStringIndex;        // byte offset to String Indexes table
+    int32_t       fCFUStringIndexSize;    // number of entries in String Indexes table (16 bits each)
+                                          //     (number of entries must be same as in Keys table
+
+    int32_t       fCFUStringTable;        // byte offset of String table
+    int32_t       fCFUStringTableLen;     // length of string table (in 16 bit UChars)
+
+    int32_t       fCFUStringLengths;      // byte offset to String Lengths table
+    int32_t       fCFUStringLengthsSize;  // number of entries in lengths table. (2 x 16 bits each)
+
+
+    // The following sections are for data from confusablesWholeScript.txt
+    
+    int32_t       fAnyCaseTrie;           // byte offset to the serialized Any Case Trie
+    int32_t       fAnyCaseTrieLength;     // Length (bytes) of the serialized Any Case Trie
+    
+    int32_t       fLowerCaseTrie;         // byte offset to the serialized Lower Case Trie
+    int32_t       fLowerCaseTrieLength;   // Length (bytes) of the serialized Lower Case Trie
+
+    int32_t       fScriptSets;            // byte offset to array of ScriptSets
+    int32_t       fScriptSetsLength;      // Number of ScriptSets (24 bytes each)
+    
+
+    // The following sections are for data from xidmodifications.txt
+    
+    
+    int32_t       unused[15];              // Padding, Room for Expansion
+    
+ }; 
+
+
+
+    
+//
+//  Structure for the Whole Script Confusable Data
+//    See Unicode UAX-39, Unicode Security Mechanisms, for a description of the
+//    Whole Script confusable data
+//
+//  The data provides mappings from code points to a set of scripts
+//    that contain characters that might be confused with the code point.
+//  There are two mappings, one for lower case only, and one for characters
+//    of any case.
+//
+//  The actual data consists of a utrie2 to map from a code point to an offset,
+//  and an array of UScriptSets (essentially bit maps) that is indexed
+//  by the offsets obtained from the Trie.
+//
+//
+
+
+U_NAMESPACE_END
+#endif /* XP_CPLUSPLUS */
+
+/**
+  * Endianness swap function for binary spoof data.
+  * @internal
+  */
+U_CAPI int32_t U_EXPORT2
+uspoof_swap(const UDataSwapper *ds, const void *inData, int32_t length, void *outData,
+            UErrorCode *status);
+
+
+#endif
+
+#endif  /* USPOOFIM_H */
+
diff --git a/source/i18n/uspoof_wsconf.cpp b/source/i18n/uspoof_wsconf.cpp
new file mode 100644
index 0000000..3723244
--- /dev/null
+++ b/source/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/source/i18n/uspoof_wsconf.h b/source/i18n/uspoof_wsconf.h
new file mode 100644
index 0000000..2b63315
--- /dev/null
+++ b/source/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/source/i18n/usrchimp.h b/source/i18n/usrchimp.h
new file mode 100644
index 0000000..986db33
--- /dev/null
+++ b/source/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/source/i18n/utmscale.c b/source/i18n/utmscale.c
new file mode 100644
index 0000000..33f5d92
--- /dev/null
+++ b/source/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/source/i18n/utrans.cpp b/source/i18n/utrans.cpp
new file mode 100644
index 0000000..16a09bd
--- /dev/null
+++ b/source/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/source/i18n/vtzone.cpp b/source/i18n/vtzone.cpp
new file mode 100644
index 0000000..51a6a81
--- /dev/null
+++ b/source/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/source/i18n/vzone.cpp b/source/i18n/vzone.cpp
new file mode 100644
index 0000000..3aa2dbb
--- /dev/null
+++ b/source/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/source/i18n/vzone.h b/source/i18n/vzone.h
new file mode 100644
index 0000000..c81413c
--- /dev/null
+++ b/source/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/source/i18n/windtfmt.cpp b/source/i18n/windtfmt.cpp
new file mode 100644
index 0000000..8fedabd
--- /dev/null
+++ b/source/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/source/i18n/windtfmt.h b/source/i18n/windtfmt.h
new file mode 100644
index 0000000..5f6e2da
--- /dev/null
+++ b/source/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/source/i18n/winnmfmt.cpp b/source/i18n/winnmfmt.cpp
new file mode 100644
index 0000000..4207c52
--- /dev/null
+++ b/source/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/source/i18n/winnmfmt.h b/source/i18n/winnmfmt.h
new file mode 100644
index 0000000..9b737f8
--- /dev/null
+++ b/source/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/source/i18n/wintzimpl.cpp b/source/i18n/wintzimpl.cpp
new file mode 100644
index 0000000..fb7de50
--- /dev/null
+++ b/source/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/source/i18n/wintzimpl.h b/source/i18n/wintzimpl.h
new file mode 100644
index 0000000..e7083e9
--- /dev/null
+++ b/source/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/source/i18n/zonemeta.cpp b/source/i18n/zonemeta.cpp
new file mode 100644
index 0000000..65291e6
--- /dev/null
+++ b/source/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/source/i18n/zonemeta.h b/source/i18n/zonemeta.h
new file mode 100644
index 0000000..ead9f35
--- /dev/null
+++ b/source/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/source/i18n/zrule.cpp b/source/i18n/zrule.cpp
new file mode 100644
index 0000000..82c3116
--- /dev/null
+++ b/source/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/source/i18n/zrule.h b/source/i18n/zrule.h
new file mode 100644
index 0000000..04f7abf
--- /dev/null
+++ b/source/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/source/i18n/zstrfmt.cpp b/source/i18n/zstrfmt.cpp
new file mode 100644
index 0000000..acd3546
--- /dev/null
+++ b/source/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/source/i18n/zstrfmt.h b/source/i18n/zstrfmt.h
new file mode 100644
index 0000000..814b0f8
--- /dev/null
+++ b/source/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/source/i18n/ztrans.cpp b/source/i18n/ztrans.cpp
new file mode 100644
index 0000000..58f2e12
--- /dev/null
+++ b/source/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/source/i18n/ztrans.h b/source/i18n/ztrans.h
new file mode 100644
index 0000000..d96198e
--- /dev/null
+++ b/source/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
diff --git a/source/icudefs.mk.in b/source/icudefs.mk.in
new file mode 100644
index 0000000..a6923e3
--- /dev/null
+++ b/source/icudefs.mk.in
@@ -0,0 +1,286 @@
+# Make definitions that are shared by the different subprojects of ICU.
+#
+# Yves Arrouye.
+#
+# Copyright (C) 2000-2010, International Business Machines Corporation and others.
+# All Rights Reserved.
+
+#
+# Some of these variables are overridden in the config/mh-* files.
+# 
+# Please be sure to update config/Makefile.inc.in  if you add something here.
+#
+
+# Shell to use
+
+SHELL = @SHELL@
+
+# Standard directories
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+datarootdir = @datarootdir@
+datadir = @datadir@
+libdir = @libdir@
+includedir = @includedir@
+mandir = @mandir@
+sysconfdir = @sysconfdir@
+# controls the include of $(top_builddir)/icucross.mk at bottom of file
+cross_compiling = @cross_compiling@
+cross_buildroot = @cross_buildroot@
+
+# Package information
+
+PACKAGE_ICU_DESCRIPTION = "International Components for Unicode"
+PACKAGE_ICU_URL = "http://icu-project.org"
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+UNICODE_VERSION = @UNICODE_VERSION@
+SO_TARGET_VERSION = @LIB_VERSION@
+SO_TARGET_VERSION_MAJOR = @LIB_VERSION_MAJOR@
+
+# The ICU data external name is usually icudata; the entry point name is
+# the version-dependent name (for no particular reason except it was easier
+# to change the build this way). When building in common mode, the data
+# name is the versioned platform-dependent one. 
+
+ICUDATA_DIR = @pkgicudatadir@/$(PACKAGE)$(ICULIBSUFFIX)/$(VERSION)
+
+ICUDATA_BASENAME_VERSION = $(ICUPREFIX)dt@LIB_VERSION_MAJOR@
+# the entry point is almost like the basename, but has the lib suffix.  
+ICUDATA_ENTRY_POINT = $(ICUPREFIX)dt@ICULIBSUFFIXCNAME@@LIB_VERSION_MAJOR@ 
+ICUDATA_CHAR = @ICUDATA_CHAR@
+ICUDATA_PLATFORM_NAME = $(ICUDATA_BASENAME_VERSION)$(ICUDATA_CHAR)
+PKGDATA_LIBSTATICNAME = -L $(STATIC_PREFIX)$(ICUPREFIX)$(DATA_STUBNAME)$(ICULIBSUFFIX)
+ifeq ($(strip $(PKGDATA_MODE)),)
+PKGDATA_MODE=@DATA_PACKAGING_MODE@
+endif
+ifeq ($(PKGDATA_MODE),common)
+ICUDATA_NAME = $(ICUDATA_PLATFORM_NAME)
+ICUPKGDATA_DIR = $(ICUDATA_DIR)
+else
+ifeq ($(PKGDATA_MODE),dll)
+ICUDATA_NAME = $(ICUDATA_PLATFORM_NAME)
+PKGDATA_LIBNAME = -L $(ICUPREFIX)$(DATA_STUBNAME)$(ICULIBSUFFIX)
+ICUPKGDATA_DIR = $(libdir)
+else
+ifeq ($(PKGDATA_MODE),static)
+ICUDATA_NAME = $(ICUDATA_PLATFORM_NAME)
+PKGDATA_LIBNAME = -L $(ICUPREFIX)$(DATA_STUBNAME)$(ICULIBSUFFIX)
+ICUPKGDATA_DIR = $(libdir)
+else
+ICUDATA_NAME = $(ICUDATA_PLATFORM_NAME)
+ICUPKGDATA_DIR = $(ICUDATA_DIR)
+endif
+endif
+endif
+# This is needed so that make -j2 doesn't complain when invoking pkgdata's make
+PKGDATA_INVOKE_OPTS = MAKEFLAGS=
+
+# These are defined here because mh-cygwin-msvc needs to override these values.
+ICUPKGDATA_INSTALL_DIR = $(DESTDIR)$(ICUPKGDATA_DIR)
+ICUPKGDATA_INSTALL_LIBDIR = $(DESTDIR)$(libdir)
+
+# If defined to a valid value, pkgdata will generate a data library more quickly
+GENCCODE_ASSEMBLY = @GENCCODE_ASSEMBLY@
+
+# ICU specific directories
+
+pkgdatadir = $(datadir)/$(PACKAGE)$(ICULIBSUFFIX)/$(VERSION)
+pkglibdir = $(libdir)/$(PACKAGE)$(ICULIBSUFFIX)/$(VERSION)
+pkgsysconfdir = $(sysconfdir)/$(PACKAGE)$(ICULIBSUFFIX)
+
+# Installation programs
+
+MKINSTALLDIRS = $(SHELL) $(top_srcdir)/mkinstalldirs
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+
+# Library suffix (to support different C++ compilers)
+
+ICULIBSUFFIX=@ICULIBSUFFIX@
+
+# Compiler and tools
+
+ENABLE_DEBUG = @ENABLE_DEBUG@
+ENABLE_RELEASE = @ENABLE_RELEASE@
+EXEEXT = @EXEEXT@
+CC = @CC@
+CXX = @CXX@
+AR = @AR@
+ARFLAGS = @ARFLAGS@ r
+RANLIB = @RANLIB@
+COMPILE_LINK_ENVVAR = @COMPILE_LINK_ENVVAR@
+UCLN_NO_AUTO_CLEANUP = @UCLN_NO_AUTO_CLEANUP@
+
+# Various flags for the tools
+
+# DEFS is for common macro definitions.
+# configure prevents user defined DEFS, and configure's DEFS is not needed
+# So we ignore the DEFS that comes from configure
+DEFS =
+# CFLAGS is for C only flags
+CFLAGS = @CFLAGS@
+# CXXFLAGS is for C++ only flags
+CXXFLAGS = @CXXFLAGS@
+# CPPFLAGS is for C Pre-Processor flags
+CPPFLAGS = @CPPFLAGS@
+# LIBCFLAGS are the flags for static and shared libraries.
+LIBCFLAGS = @LIBCFLAGS@
+# LIBCXXFLAGS are the flags for static and shared libraries.
+LIBCXXFLAGS = @LIBCXXFLAGS@
+# DEFAULT_LIBS are the default libraries to link against
+DEFAULT_LIBS = @LIBS@
+# LIB_M is for linking against the math library
+LIB_M = @LIB_M@
+# LIB_THREAD is for linking against the threading library
+LIB_THREAD = @LIB_THREAD@
+# OUTOPT is for creating a specific output name
+OUTOPT = -o # The extra space after the argument is needed.
+# AR_OUTOPT is for creating a specific output name for static libraries.
+AR_OUTOPT =
+
+ENABLE_RPATH = @ENABLE_RPATH@
+ifeq ($(ENABLE_RPATH),YES)
+RPATHLDFLAGS = $(LD_RPATH)$(LD_RPATH_PRE)$(libdir)
+endif
+LDFLAGS = @LDFLAGS@ $(RPATHLDFLAGS)
+
+# What kind of libraries are we building and linking against?
+ENABLE_STATIC = @ENABLE_STATIC@
+ENABLE_SHARED = @ENABLE_SHARED@
+
+# Echo w/o newline
+
+#ECHO_N = @ICU_ECHO_N@
+#ECHO_C = @ICU_ECHO_C@
+
+# Commands to compile
+COMPILE.c=    $(CC) $(CPPFLAGS) $(DEFS) $(CFLAGS) -c
+COMPILE.cc=   $(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) -c
+
+# Commands to link
+LINK.c=       $(CC) $(CFLAGS) $(LDFLAGS)
+LINK.cc=      $(CXX) $(CXXFLAGS) $(LDFLAGS)
+
+# Commands to make a shared library
+SHLIB.c=      $(CC) $(CFLAGS) $(LDFLAGS) -shared $(LD_SOOPTIONS)
+SHLIB.cc=     $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(LD_SOOPTIONS)
+
+# Environment variable to set a runtime search path
+LDLIBRARYPATH_ENVVAR = LD_LIBRARY_PATH
+
+# Versioned target for a shared library.
+FINAL_SO_TARGET = $(SO_TARGET).$(SO_TARGET_VERSION)
+MIDDLE_SO_TARGET = $(SO_TARGET).$(SO_TARGET_VERSION_MAJOR)
+SHARED_OBJECT = $(FINAL_SO_TARGET)
+
+##  How ICU libraries are named...  ex. $(LIBICU)uc$(SO)
+# Prefix for the ICU library names
+ICUPREFIX = icu
+LIBPREFIX = lib
+LIBICU = $(LIBPREFIX)$(ICUPREFIX)
+
+## If we can't use the shared libraries, use the static libraries
+ifneq ($(ENABLE_SHARED),YES)
+STATIC_PREFIX_WHEN_USED = s
+else
+STATIC_PREFIX_WHEN_USED = 
+endif
+
+# Static library prefix and file extension
+STATIC_PREFIX = s
+LIBSICU = $(LIBPREFIX)$(STATIC_PREFIX)$(ICUPREFIX)
+A = a
+SOBJ = $(SO)
+
+# Force removal [for make clean]
+RMV = rm -rf
+
+# Platform commands to remove or move executable and library targets
+# INSTALL-L installs libraries. Override in mh-* file to INSTALL_PROGRAM
+#           when the library needs to have executable permissions
+INSTALL-S = $(INSTALL_PROGRAM)
+INSTALL-L = $(INSTALL_PROGRAM)
+#INSTALL-L = $(INSTALL_DATA)
+
+# Location of the libraries before "make install" is used
+LIBDIR=$(top_builddir)/lib
+
+# Location of the executables before "make install" is used
+BINDIR=$(top_builddir)/bin
+
+# overridden by icucross.mk
+TOOLBINDIR=$(BINDIR)
+TOOLLIBDIR=$(LIBDIR)
+
+# Current full path directory.
+CURR_FULL_DIR=$(shell pwd | sed 's/ /\\ /g')
+# Current full path directory for use in source code in a -D compiler option.
+CURR_SRCCODE_FULL_DIR=$(shell pwd | sed 's/ /\\ /')
+
+# Name flexibility for the library naming scheme.  Any modifications should
+# be made in the mh- file for the specific platform.
+DATA_STUBNAME = data
+COMMON_STUBNAME = uc
+I18N_STUBNAME = i18n
+LAYOUT_STUBNAME = le
+LAYOUTEX_STUBNAME = lx
+IO_STUBNAME = io
+TOOLUTIL_STUBNAME = tu
+CTESTFW_STUBNAME = test
+
+# Just the libs.
+ICULIBS_DT	= -l$(STATIC_PREFIX_WHEN_USED)$(ICUPREFIX)$(DATA_STUBNAME)$(ICULIBSUFFIX)$(SO_TARGET_VERSION_SUFFIX)
+ICULIBS_UC	= -l$(STATIC_PREFIX_WHEN_USED)$(ICUPREFIX)$(COMMON_STUBNAME)$(ICULIBSUFFIX)$(SO_TARGET_VERSION_SUFFIX)
+ICULIBS_I18N	= -l$(STATIC_PREFIX_WHEN_USED)$(ICUPREFIX)$(I18N_STUBNAME)$(ICULIBSUFFIX)$(SO_TARGET_VERSION_SUFFIX)
+ICULIBS_LE	= -l$(STATIC_PREFIX_WHEN_USED)$(ICUPREFIX)$(LAYOUT_STUBNAME)$(ICULIBSUFFIX)$(SO_TARGET_VERSION_SUFFIX)
+ICULIBS_LX	= -l$(STATIC_PREFIX_WHEN_USED)$(ICUPREFIX)$(LAYOUTEX_STUBNAME)$(ICULIBSUFFIX)$(SO_TARGET_VERSION_SUFFIX)
+ICULIBS_IO	= -l$(STATIC_PREFIX_WHEN_USED)$(ICUPREFIX)$(IO_STUBNAME)$(ICULIBSUFFIX)$(SO_TARGET_VERSION_SUFFIX)
+ICULIBS_CTESTFW	= -l$(STATIC_PREFIX_WHEN_USED)$(ICUPREFIX)$(CTESTFW_STUBNAME)$(ICULIBSUFFIX)$(SO_TARGET_VERSION_SUFFIX)
+ICULIBS_TOOLUTIL = -l$(STATIC_PREFIX_WHEN_USED)$(ICUPREFIX)$(TOOLUTIL_STUBNAME)$(ICULIBSUFFIX)$(SO_TARGET_VERSION_SUFFIX)
+# Link commands to link to ICU libs
+LLIBDIR		= -L$(LIBDIR)
+LSTUBDIR	= -L$(top_builddir)/stubdata
+LCTESTFW	= -L$(top_builddir)/tools/ctestfw
+
+LIBICUDT	= $(LLIBDIR) $(LSTUBDIR) $(ICULIBS_DT)
+LIBICUUC	= $(LLIBDIR) $(ICULIBS_UC) $(LSTUBDIR) $(ICULIBS_DT)
+LIBICUI18N	= $(LLIBDIR) $(ICULIBS_I18N)
+LIBICULE	= $(LLIBDIR) $(ICULIBS_LE)
+LIBICULX	= $(LLIBDIR) $(ICULIBS_LX)
+LIBCTESTFW	= $(LCTESTFW) $(ICULIBS_CTESTFW)
+LIBICUTOOLUTIL	= $(LLIBDIR) $(ICULIBS_TOOLUTIL)
+LIBICUIO	= $(LLIBDIR) $(ICULIBS_IO)
+
+# Invoke, set library path for all ICU libraries.
+# overridden by icucross.mk
+INVOKE = $(LDLIBRARYPATH_ENVVAR)=$(LIBRARY_PATH_PREFIX)$(LIBDIR):$(top_builddir)/stubdata:$(top_builddir)/tools/ctestfw:$$$(LDLIBRARYPATH_ENVVAR) $(LEAK_CHECKER)
+# prefer stubdata
+PKGDATA_INVOKE = $(LDLIBRARYPATH_ENVVAR)=$(top_builddir)/stubdata:$(top_builddir)/tools/ctestfw:$(LIBRARY_PATH_PREFIX)$(LIBDIR):$$$(LDLIBRARYPATH_ENVVAR) $(LEAK_CHECKER) $(PKGDATA_INVOKE_OPTS)
+
+# Platform-specific setup
+include @platform_make_fragment@
+
+# When shared libraries are disabled and static libraries are enabled,
+# the C++ compiler must be used to link in the libraries for the tools.
+ifneq ($(ENABLE_SHARED),YES)
+LINK.c = $(LINK.cc)
+endif
+
+# some imported things from the cross env
+TOOLEXEEXT = $(EXEEXT)
+ifneq ($(strip $(cross_buildroot)),)
+include $(cross_buildroot)/config/icucross.mk
+else
+cross_buildroot = $(top_builddir)
+endif
+
+# optional include at top
+-include $(top_builddir)/icudefs.local
diff --git a/source/install-sh b/source/install-sh
new file mode 100755
index 0000000..e9de238
--- /dev/null
+++ b/source/install-sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+		chmodcmd=""
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename | 
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
diff --git a/source/io/Makefile.in b/source/io/Makefile.in
new file mode 100644
index 0000000..a40f7fd
--- /dev/null
+++ b/source/io/Makefile.in
@@ -0,0 +1,166 @@
+#******************************************************************************
+#
+#   Copyright (C) 1999-2009, International Business Machines
+#   Corporation and others.  All Rights Reserved.
+#
+#******************************************************************************
+## Makefile.in for ICU - icuio.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 = io
+
+## Extra files to remove for 'make clean'
+CLEANFILES = *~ $(DEPS) $(IMPORT_LIB) $(MIDDLE_IMPORT_LIB) $(FINAL_IMPORT_LIB)
+
+## Target information
+
+TARGET_STUBNAME=$(IO_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 = io.res
+endif
+
+ifeq ($(OS390BATCH),1)
+BATCH_TARGET = $(BATCH_IO_TARGET)
+BATCH_LIBS = $(BATCH_LIBICUUC) $(BATCH_LIBICUI18N) -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$(top_srcdir)/common -I$(top_srcdir)/i18n $(LIBCPPFLAGS) $(CPPFLAGSICUIO)
+DEFS += -DU_IO_IMPLEMENTATION
+LDFLAGS += $(LDFLAGSICUIO)
+LIBS = $(LIBICUUC) $(LIBICUI18N) $(DEFAULT_LIBS)
+
+OBJECTS = locbund.o ufile.o ufmt_cmn.o uprintf.o uprntf_p.o \
+uscanf.o uscanf_p.o ustdio.o sprintf.o sscanf.o \
+ustream.o ucln_io.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/source/io/io.rc b/source/io/io.rc
new file mode 100644
index 0000000..4494132
--- /dev/null
+++ b/source/io/io.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 " I/O 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", "icuio" U_ICU_VERSION_SHORT "d.dll\0"
+#else
+            VALUE "OriginalFilename", "icuio" 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/source/io/io.vcxproj b/source/io/io.vcxproj
new file mode 100644
index 0000000..b03f98e
--- /dev/null
+++ b/source/io/io.vcxproj
@@ -0,0 +1,322 @@
+<?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>{C2B04507-2521-4801-BF0D-5FD79D6D518C}</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\icuio.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <AdditionalIncludeDirectories>..\..\include;..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;U_IO_IMPLEMENTATION;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <StringPooling>true</StringPooling>

+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x86\Release/icuio.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\icuio46.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <ProgramDatabaseFile>.\..\..\lib\icuio.pdb</ProgramDatabaseFile>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <BaseAddress>0x4ab00000</BaseAddress>

+      <RandomizedBaseAddress>false</RandomizedBaseAddress>

+      <DataExecutionPrevention>

+      </DataExecutionPrevention>

+      <ImportLibrary>..\..\lib\icuio.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\icuio.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>..\..\include;..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;U_IO_IMPLEMENTATION;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>

+      <BufferSecurityCheck>true</BufferSecurityCheck>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x86\Debug/icuio.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\icuio46d.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <ProgramDatabaseFile>.\..\..\lib\icuiod.pdb</ProgramDatabaseFile>

+      <BaseAddress>0x4ab00000</BaseAddress>

+      <RandomizedBaseAddress>false</RandomizedBaseAddress>

+      <DataExecutionPrevention>

+      </DataExecutionPrevention>

+      <ImportLibrary>..\..\lib\icuiod.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\icuio.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <AdditionalIncludeDirectories>..\..\include;..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN64;WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;U_IO_IMPLEMENTATION;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <StringPooling>true</StringPooling>

+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x64\Release/icuio.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\icuio46.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <ProgramDatabaseFile>.\..\..\lib64\icuio.pdb</ProgramDatabaseFile>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <BaseAddress>0x4ab00000</BaseAddress>

+      <ImportLibrary>..\..\lib64\icuio.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\icuio.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>..\..\include;..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN64;WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;U_IO_IMPLEMENTATION;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>

+      <BufferSecurityCheck>true</BufferSecurityCheck>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x64\Debug/icuio.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\icuio46d.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <ProgramDatabaseFile>.\..\..\lib64\icuiod.pdb</ProgramDatabaseFile>

+      <BaseAddress>0x4ab00000</BaseAddress>

+      <ImportLibrary>..\..\lib64\icuiod.lib</ImportLibrary>

+      <TargetMachine>MachineX64</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="locbund.c" />

+    <ClCompile Include="sprintf.c" />

+    <ClCompile Include="sscanf.c" />

+    <ClCompile Include="ucln_io.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="ufile.c" />

+    <ClCompile Include="ufmt_cmn.c" />

+    <ClCompile Include="uprintf.c" />

+    <ClCompile Include="uprntf_p.c" />

+    <ClCompile Include="uscanf.c" />

+    <ClCompile Include="uscanf_p.c" />

+    <ClCompile Include="ustdio.c" />

+    <ClCompile Include="ustream.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>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="locbund.h" />

+    <ClInclude Include="ucln_io.h" />

+    <ClInclude Include="ufile.h" />

+    <ClInclude Include="ufmt_cmn.h" />

+    <ClInclude Include="uprintf.h" />

+    <ClInclude Include="uscanf.h" />

+    <CustomBuild Include="unicode\ustdio.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\ustream.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>

+  </ItemGroup>

+  <ItemGroup>

+    <ResourceCompile Include="io.rc" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\common\common.vcxproj">

+      <Project>{73c0a65b-d1f2-4de1-b3a6-15dad2c23f3d}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\i18n\i18n.vcxproj">

+      <Project>{0178b127-6269-407d-b112-93877bb62776}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
diff --git a/source/io/io.vcxproj.filters b/source/io/io.vcxproj.filters
new file mode 100644
index 0000000..83e23d6
--- /dev/null
+++ b/source/io/io.vcxproj.filters
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{851db102-16a0-4e9d-b6bc-aa5cce5119d6}</UniqueIdentifier>

+      <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>

+    </Filter>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{051f18b2-608f-486c-9b00-308b7a429167}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl</Extensions>

+    </Filter>

+    <Filter Include="Resource Files">

+      <UniqueIdentifier>{9fd3bb57-16c4-405d-a045-2be622895424}</UniqueIdentifier>

+      <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="locbund.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="sprintf.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="sscanf.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ucln_io.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ufile.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ufmt_cmn.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="uprintf.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="uprntf_p.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="uscanf.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="uscanf_p.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ustdio.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ustream.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="locbund.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ucln_io.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ufile.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ufmt_cmn.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="uprintf.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="uscanf.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+  <ItemGroup>

+    <ResourceCompile Include="io.rc">

+      <Filter>Resource Files</Filter>

+    </ResourceCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <CustomBuild Include="unicode\ustdio.h">

+      <Filter>Header Files</Filter>

+    </CustomBuild>

+    <CustomBuild Include="unicode\ustream.h">

+      <Filter>Header Files</Filter>

+    </CustomBuild>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/source/io/locbund.c b/source/io/locbund.c
new file mode 100644
index 0000000..1859999
--- /dev/null
+++ b/source/io/locbund.c
@@ -0,0 +1,187 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1998-2007, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*
+* File locbund.c
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   11/18/98    stephen        Creation.
+*   12/10/1999  bobbyr(at)optiosoftware.com       Fix for memory leak + string allocation bugs
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "locbund.h"
+
+#include "cmemory.h"
+#include "cstring.h"
+#include "ucln_io.h"
+#include "umutex.h"
+#include "unicode/ustring.h"
+#include "unicode/uloc.h"
+
+static UBool isFormatsInitialized = FALSE;
+static UNumberFormat *gPosixNumberFormat[ULOCALEBUNDLE_NUMBERFORMAT_COUNT];
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV locbund_cleanup(void) {
+    int32_t style;
+    for (style = 0; style < ULOCALEBUNDLE_NUMBERFORMAT_COUNT; style++) {
+        unum_close(gPosixNumberFormat[style]);
+        gPosixNumberFormat[style] = NULL;
+    }
+    isFormatsInitialized = FALSE;
+    return TRUE;
+}
+U_CDECL_END
+
+
+static U_INLINE UNumberFormat * copyInvariantFormatter(ULocaleBundle *result, UNumberFormatStyle style) {
+    if (result->fNumberFormat[style-1] == NULL) {
+        UErrorCode status = U_ZERO_ERROR;
+        UBool needsInit;
+
+        UMTX_CHECK(NULL, gPosixNumberFormat[style-1] == NULL, needsInit);
+        if (needsInit) {
+            UNumberFormat *formatAlias = unum_open(style, NULL, 0, "en_US_POSIX", NULL, &status);
+
+            /* Cache upon first request. */
+            if (U_SUCCESS(status)) {
+                umtx_lock(NULL);
+                gPosixNumberFormat[style-1] = formatAlias;
+                ucln_io_registerCleanup(UCLN_IO_LOCBUND, locbund_cleanup);
+                umtx_unlock(NULL);
+            }
+        }
+
+        /* Copy the needed formatter. */
+        result->fNumberFormat[style-1] = unum_clone(gPosixNumberFormat[style-1], &status);
+    }
+    return result->fNumberFormat[style-1];
+}
+
+ULocaleBundle*        
+u_locbund_init(ULocaleBundle *result, const char *loc)
+{
+    int32_t len;
+
+    if(result == 0)
+        return 0;
+
+    if (loc == NULL) {
+        loc = uloc_getDefault();
+    }
+
+    uprv_memset(result, 0, sizeof(ULocaleBundle));
+
+    len = (int32_t)strlen(loc);
+    result->fLocale = (char*) uprv_malloc(len + 1);
+    if(result->fLocale == 0) {
+        return 0;
+    }
+
+    uprv_strcpy(result->fLocale, loc);
+
+    result->isInvariantLocale = uprv_strcmp(result->fLocale, "en_US_POSIX") == 0;
+
+    return result;
+}
+
+/*ULocaleBundle*        
+u_locbund_new(const char *loc)
+{
+    ULocaleBundle *result = (ULocaleBundle*) uprv_malloc(sizeof(ULocaleBundle));
+    return u_locbund_init(result, loc);
+}
+
+ULocaleBundle*
+u_locbund_clone(const ULocaleBundle *bundle)
+{
+    ULocaleBundle *result = (ULocaleBundle*)uprv_malloc(sizeof(ULocaleBundle));
+    UErrorCode status = U_ZERO_ERROR;
+    int32_t styleIdx;
+    
+    if(result == 0)
+        return 0;
+    
+    result->fLocale = (char*) uprv_malloc(strlen(bundle->fLocale) + 1);
+    if(result->fLocale == 0) {
+        uprv_free(result);
+        return 0;
+    }
+    
+    strcpy(result->fLocale, bundle->fLocale );
+    
+    for (styleIdx = 0; styleIdx < ULOCALEBUNDLE_NUMBERFORMAT_COUNT; styleIdx++) {
+        status = U_ZERO_ERROR;
+        if (result->fNumberFormat[styleIdx]) {
+            result->fNumberFormat[styleIdx] = unum_clone(bundle->fNumberFormat[styleIdx], &status);
+            if (U_FAILURE(status)) {
+                result->fNumberFormat[styleIdx] = NULL;
+            }
+        }
+        else {
+            result->fNumberFormat[styleIdx] = NULL;
+        }
+    }
+    result->fDateFormat         = (bundle->fDateFormat == 0 ? 0 :
+        udat_clone(bundle->fDateFormat, &status));
+    result->fTimeFormat         = (bundle->fTimeFormat == 0 ? 0 :
+        udat_clone(bundle->fTimeFormat, &status));
+    
+    return result;
+}*/
+
+void
+u_locbund_close(ULocaleBundle *bundle)
+{
+    int32_t styleIdx;
+
+    uprv_free(bundle->fLocale);
+    
+    for (styleIdx = 0; styleIdx < ULOCALEBUNDLE_NUMBERFORMAT_COUNT; styleIdx++) {
+        if (bundle->fNumberFormat[styleIdx]) {
+            unum_close(bundle->fNumberFormat[styleIdx]);
+        }
+    }
+    
+    uprv_memset(bundle, 0, sizeof(ULocaleBundle));
+/*    uprv_free(bundle);*/
+}
+
+UNumberFormat*
+u_locbund_getNumberFormat(ULocaleBundle *bundle, UNumberFormatStyle style)
+{
+    UNumberFormat *formatAlias = NULL;
+    if (style > UNUM_IGNORE) {
+        formatAlias = bundle->fNumberFormat[style-1];
+        if (formatAlias == NULL) {
+            if (bundle->isInvariantLocale) {
+                formatAlias = copyInvariantFormatter(bundle, style);
+            }
+            else {
+                UErrorCode status = U_ZERO_ERROR;
+                formatAlias = unum_open(style, NULL, 0, bundle->fLocale, NULL, &status);
+                if (U_FAILURE(status)) {
+                    unum_close(formatAlias);
+                    formatAlias = NULL;
+                }
+                else {
+                    bundle->fNumberFormat[style-1] = formatAlias;
+                }
+            }
+        }
+    }
+    return formatAlias;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/source/io/locbund.h b/source/io/locbund.h
new file mode 100644
index 0000000..f4ff449
--- /dev/null
+++ b/source/io/locbund.h
@@ -0,0 +1,80 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1998-2006s, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*
+* File locbund.h
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   10/16/98    stephen     Creation.
+*   02/25/99    stephen     Modified for new C API.
+*******************************************************************************
+*/
+
+#ifndef LOCBUND_H
+#define LOCBUND_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unum.h"
+
+#define ULOCALEBUNDLE_NUMBERFORMAT_COUNT ((int32_t)UNUM_SPELLOUT)
+
+typedef struct ULocaleBundle {
+    char            *fLocale;
+
+    UNumberFormat   *fNumberFormat[ULOCALEBUNDLE_NUMBERFORMAT_COUNT];
+    UBool           isInvariantLocale;
+} ULocaleBundle;
+
+
+/**
+ * Initialize a ULocaleBundle, initializing all formatters to 0.
+ * @param result A ULocaleBundle to initialize.
+ * @param loc The locale of the ULocaleBundle.
+ * @return A pointer to a ULocaleBundle, or 0 if <TT>loc</TT> was invalid.
+ */
+ULocaleBundle* 
+u_locbund_init(ULocaleBundle *result, const char *loc);
+
+/**
+ * Create a new ULocaleBundle, initializing all formatters to 0.
+ * @param loc The locale of the ULocaleBundle.
+ * @return A pointer to a ULocaleBundle, or 0 if <TT>loc</TT> was invalid.
+ */
+/*ULocaleBundle*
+u_locbund_new(const char *loc);*/
+
+/**
+ * Create a deep copy of this ULocaleBundle;
+ * @param bundle The ULocaleBundle to clone.
+ * @return A new ULocaleBundle.
+ */
+/*ULocaleBundle*
+u_locbund_clone(const ULocaleBundle *bundle);*/
+
+/**
+ * Delete the specified ULocaleBundle, freeing all associated memory.
+ * @param bundle The ULocaleBundle to delete
+ */
+void
+u_locbund_close(ULocaleBundle *bundle);
+
+/**
+ * Get the NumberFormat used to format and parse numbers in a ULocaleBundle.
+ * @param bundle The ULocaleBundle to use
+ * @return A pointer to the NumberFormat used for number formatting and parsing.
+ */
+UNumberFormat*        
+u_locbund_getNumberFormat(ULocaleBundle *bundle, UNumberFormatStyle style);
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/source/io/sprintf.c b/source/io/sprintf.c
new file mode 100644
index 0000000..91d29c5
--- /dev/null
+++ b/source/io/sprintf.c
@@ -0,0 +1,260 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2001-2008, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File sprintf.c
+*
+* Modification History:
+*
+*   Date        Name            Description
+*   02/08/2001  george          Creation. Copied from uprintf.c
+*   03/27/2002  Mark Schneckloth Many fixes regarding alignment, null termination
+*       (mschneckloth@atomz.com) and other various problems.
+*   08/07/2003  george          Reunify printf implementations
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ustdio.h"
+#include "unicode/ustring.h"
+#include "unicode/putil.h"
+
+#include "uprintf.h"
+#include "locbund.h"
+
+#include "cmemory.h"
+#include <ctype.h>
+
+/* u_minstrncpy copies the minimum number of code units of (count or output->available) */
+static int32_t
+u_sprintf_write(void        *context,
+                const UChar *str,
+                int32_t     count)
+{
+    u_localized_print_string *output = (u_localized_print_string *)context;
+    int32_t size = ufmt_min(count, output->available);
+
+    u_strncpy(output->str + (output->len - output->available), str, size);
+    output->available -= size;
+    return size;
+}
+
+static int32_t
+u_sprintf_pad_and_justify(void                        *context,
+                          const u_printf_spec_info    *info,
+                          const UChar                 *result,
+                          int32_t                     resultLen)
+{
+    u_localized_print_string *output = (u_localized_print_string *)context;
+    int32_t written = 0;
+    int32_t lengthOfResult = resultLen;
+
+    resultLen = ufmt_min(resultLen, output->available);
+
+    /* pad and justify, if needed */
+    if(info->fWidth != -1 && resultLen < info->fWidth) {
+        int32_t paddingLeft = info->fWidth - resultLen;
+        int32_t outputPos = output->len - output->available;
+  
+        if (paddingLeft + resultLen > output->available) {
+            paddingLeft = output->available - resultLen;
+            if (paddingLeft < 0) {
+                paddingLeft = 0;
+            }
+            /* paddingLeft = output->available - resultLen;*/
+        }
+        written += paddingLeft;
+
+        /* left justify */
+        if(info->fLeft) {
+            written += u_sprintf_write(output, result, resultLen);
+            u_memset(&output->str[outputPos + resultLen], info->fPadChar, paddingLeft);
+            output->available -= paddingLeft;
+        }
+        /* right justify */
+        else {
+            u_memset(&output->str[outputPos], info->fPadChar, paddingLeft);
+            output->available -= paddingLeft;
+            written += u_sprintf_write(output, result, resultLen);
+        }
+    }
+    /* just write the formatted output */
+    else {
+        written = u_sprintf_write(output, result, resultLen);
+    }
+    
+    if (written >= 0 && lengthOfResult > written) {
+    	return lengthOfResult;
+    }
+
+    return written;
+}
+
+U_CAPI int32_t U_EXPORT2
+u_sprintf(UChar       *buffer,
+          const char    *patternSpecification,
+          ... )
+{
+    va_list ap;
+    int32_t written;
+
+    va_start(ap, patternSpecification);
+    written = u_vsnprintf(buffer, INT32_MAX, patternSpecification, ap);
+    va_end(ap);
+
+    return written;
+}
+
+U_CAPI int32_t U_EXPORT2
+u_sprintf_u(UChar     *buffer,
+            const UChar    *patternSpecification,
+            ... )
+{
+    va_list ap;
+    int32_t written;
+
+    va_start(ap, patternSpecification);
+    written = u_vsnprintf_u(buffer, INT32_MAX, patternSpecification, ap);
+    va_end(ap);
+
+    return written;
+}
+
+U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_vsprintf(UChar       *buffer,
+           const char     *patternSpecification,
+           va_list         ap)
+{
+    return u_vsnprintf(buffer, INT32_MAX, patternSpecification, ap);
+}
+
+U_CAPI int32_t U_EXPORT2
+u_snprintf(UChar       *buffer,
+           int32_t         count,
+           const char    *patternSpecification,
+           ... )
+{
+    va_list ap;
+    int32_t written;
+
+    va_start(ap, patternSpecification);
+    written = u_vsnprintf(buffer, count, patternSpecification, ap);
+    va_end(ap);
+
+    return written;
+}
+
+U_CAPI int32_t U_EXPORT2
+u_snprintf_u(UChar     *buffer,
+             int32_t        count,
+             const UChar    *patternSpecification,
+             ... )
+{
+    va_list ap;
+    int32_t written;
+
+    va_start(ap, patternSpecification);
+    written = u_vsnprintf_u(buffer, count, patternSpecification, ap);
+    va_end(ap);
+
+    return written;
+}
+
+U_CAPI int32_t  U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_vsnprintf(UChar       *buffer,
+            int32_t         count,
+            const char     *patternSpecification,
+            va_list         ap)
+{
+    int32_t written;
+    UChar *pattern;
+    UChar patBuffer[UFMT_DEFAULT_BUFFER_SIZE];
+    int32_t size = (int32_t)strlen(patternSpecification) + 1;
+
+    /* convert from the default codepage to Unicode */
+    if (size >= MAX_UCHAR_BUFFER_SIZE(patBuffer)) {
+        pattern = (UChar *)uprv_malloc(size * sizeof(UChar));
+        if(pattern == 0) {
+            return 0;
+        }
+    }
+    else {
+        pattern = patBuffer;
+    }
+    u_charsToUChars(patternSpecification, pattern, size);
+
+    /* do the work */
+    written = u_vsnprintf_u(buffer, count, pattern, ap);
+
+    /* clean up */
+    if (pattern != patBuffer) {
+        uprv_free(pattern);
+    }
+
+    return written;
+}
+
+U_CAPI int32_t U_EXPORT2 
+u_vsprintf_u(UChar       *buffer, 
+             const UChar *patternSpecification, 
+             va_list     ap) 
+{ 
+    return u_vsnprintf_u(buffer, INT32_MAX, patternSpecification, ap); 
+} 
+
+static const u_printf_stream_handler g_sprintf_stream_handler = {
+    u_sprintf_write,
+    u_sprintf_pad_and_justify
+};
+
+U_CAPI int32_t  U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_vsnprintf_u(UChar    *buffer,
+              int32_t        count,
+              const UChar    *patternSpecification,
+              va_list        ap)
+{
+    int32_t          written = 0;   /* haven't written anything yet */
+    int32_t			 result = 0; /* test the return value of u_printf_parse */
+
+    u_localized_print_string outStr;
+
+    if (count < 0) {
+        count = INT32_MAX;
+    }
+
+    outStr.str = buffer;
+    outStr.len = count;
+    outStr.available = count;
+
+    if(u_locbund_init(&outStr.fBundle, "en_US_POSIX") == 0) {
+        return 0;
+    }
+
+    /* parse and print the whole format string */
+    result = u_printf_parse(&g_sprintf_stream_handler, patternSpecification, &outStr, &outStr, &outStr.fBundle, &written, ap);
+    
+    /* Terminate the buffer, if there's room. */
+    if (outStr.available > 0) {
+        buffer[outStr.len - outStr.available] = 0x0000;
+    }
+
+    /* Release the cloned bundle, if we cloned it. */
+    u_locbund_close(&outStr.fBundle);
+
+    /* parsing error */ 
+    if (result < 0) {
+    	return result;
+    }
+    /* return # of UChars written */
+    return written;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
diff --git a/source/io/sscanf.c b/source/io/sscanf.c
new file mode 100644
index 0000000..eb0bedf
--- /dev/null
+++ b/source/io/sscanf.c
@@ -0,0 +1,128 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 2000-2004, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File sscanf.c
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   02/08/00    george      Creation. Copied from uscanf.c
+******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/putil.h"
+#include "unicode/ustdio.h"
+#include "unicode/ustring.h"
+#include "uscanf.h"
+#include "ufile.h"
+#include "ufmt_cmn.h"
+
+#include "cmemory.h"
+#include "cstring.h"
+
+
+U_CAPI int32_t U_EXPORT2
+u_sscanf(const UChar   *buffer,
+         const char    *patternSpecification,
+         ... )
+{
+    va_list ap;
+    int32_t converted;
+
+    va_start(ap, patternSpecification);
+    converted = u_vsscanf(buffer, patternSpecification, ap);
+    va_end(ap);
+
+    return converted;
+}
+
+U_CAPI int32_t U_EXPORT2
+u_sscanf_u(const UChar    *buffer,
+           const UChar    *patternSpecification,
+           ... )
+{
+    va_list ap;
+    int32_t converted;
+
+    va_start(ap, patternSpecification);
+    converted = u_vsscanf_u(buffer, patternSpecification, ap);
+    va_end(ap);
+
+    return converted;
+}
+
+U_CAPI int32_t  U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_vsscanf(const UChar   *buffer,
+          const char    *patternSpecification,
+          va_list        ap)
+{
+    int32_t converted;
+    UChar *pattern;
+    UChar patBuffer[UFMT_DEFAULT_BUFFER_SIZE];
+    int32_t size = (int32_t)uprv_strlen(patternSpecification) + 1;
+
+    /* convert from the default codepage to Unicode */
+    if (size >= MAX_UCHAR_BUFFER_SIZE(patBuffer)) {
+        pattern = (UChar *)uprv_malloc(size * sizeof(UChar));
+        if(pattern == 0) {
+            return 0;
+        }
+    }
+    else {
+        pattern = patBuffer;
+    }
+    u_charsToUChars(patternSpecification, pattern, size);
+
+    /* do the work */
+    converted = u_vsscanf_u(buffer, pattern, ap);
+
+    /* clean up */
+    if (pattern != patBuffer) {
+        uprv_free(pattern);
+    }
+
+    return converted;
+}
+
+U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_vsscanf_u(const UChar *buffer,
+            const UChar *patternSpecification,
+            va_list     ap)
+{
+    int32_t         converted;
+    UFILE           inStr;
+
+    inStr.fConverter = NULL;
+    inStr.fFile = NULL;
+    inStr.fOwnFile = FALSE;
+#if !UCONFIG_NO_TRANSLITERATION
+    inStr.fTranslit = NULL;
+#endif
+    inStr.fUCBuffer[0] = 0;
+    inStr.str.fBuffer = (UChar *)buffer;
+    inStr.str.fPos = (UChar *)buffer;
+    inStr.str.fLimit = buffer + u_strlen(buffer);
+
+    if(u_locbund_init(&inStr.str.fBundle, "en_US_POSIX") == 0) {
+        return 0;
+    }
+
+    converted = u_scanf_parse(&inStr, patternSpecification, ap);
+
+    u_locbund_close(&inStr.str.fBundle);
+
+    /* return # of items converted */
+    return converted;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
diff --git a/source/io/ucln_io.c b/source/io/ucln_io.c
new file mode 100644
index 0000000..05c00b9
--- /dev/null
+++ b/source/io/ucln_io.c
@@ -0,0 +1,62 @@
+/*
+******************************************************************************
+*                                                                            *
+* Copyright (C) 2001-2009, International Business Machines                   *
+*                Corporation and others. All Rights Reserved.                *
+*                                                                            *
+******************************************************************************
+*   file name:  ucln_io.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2006August11
+*   created by: George Rhoten
+*/
+
+#include "ucln.h"
+#include "ucln_io.h"
+#include "umutex.h"
+#include "uassert.h"
+
+/**  Auto-client */
+#define UCLN_TYPE UCLN_IO
+#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_IO_COUNT];
+
+static UBool io_cleanup(void)
+{
+    ECleanupIOType libType = UCLN_IO_START;
+
+    while (++libType<UCLN_IO_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_io_registerCleanup(ECleanupIOType type,
+                               cleanupFunc *func)
+{
+    U_ASSERT(UCLN_IO_START < type && type < UCLN_IO_COUNT);
+    ucln_registerCleanup(UCLN_IO, io_cleanup);
+    if (UCLN_IO_START < type && type < UCLN_IO_COUNT)
+    {
+        gCleanupFunctions[type] = func;
+    }
+
+#if !UCLN_NO_AUTO_CLEANUP && (defined(UCLN_AUTO_ATEXIT) || defined(UCLN_AUTO_LOCAL))
+    ucln_registerAutomaticCleanup();
+#endif
+}
+
diff --git a/source/io/ucln_io.h b/source/io/ucln_io.h
new file mode 100644
index 0000000..e26c1b6
--- /dev/null
+++ b/source/io/ucln_io.h
@@ -0,0 +1,37 @@
+/*
+******************************************************************************
+*                                                                            *
+* Copyright (C) 2001-2006, International Business Machines                   *
+*                Corporation and others. All Rights Reserved.                *
+*                                                                            *
+******************************************************************************
+*   file name:  ucln_io.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 2006August11
+*   created by: George Rhoten
+*/
+
+#ifndef __UCLN_IO_H__
+#define __UCLN_IO_H__
+
+#include "unicode/utypes.h"
+#include "ucln.h"
+
+/*
+Please keep the order of enums declared in same order
+as the functions are suppose to be called. */
+typedef enum ECleanupIOType {
+    UCLN_IO_START = -1,
+    UCLN_IO_LOCBUND,
+    UCLN_IO_COUNT /* This must be last */
+} ECleanupIOType;
+
+/* Main library cleanup registration function. */
+/* See common/ucln.h for details on adding a cleanup function. */
+U_CFUNC void U_EXPORT2 ucln_io_registerCleanup(ECleanupIOType type,
+                                                 cleanupFunc *func);
+
+#endif
diff --git a/source/io/ufile.c b/source/io/ufile.c
new file mode 100644
index 0000000..2f0739f
--- /dev/null
+++ b/source/io/ufile.c
@@ -0,0 +1,311 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1998-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File ufile.c
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   11/19/98    stephen     Creation.
+*   03/12/99    stephen     Modified for new C API.
+*   06/16/99    stephen     Changed T_LocaleBundle to u_locbund
+*   07/19/99    stephen     Fixed to use ucnv's default codepage.
+******************************************************************************
+*/
+
+/* define for fileno.  */
+#ifndef _XOPEN_SOURCE
+#if __STDC_VERSION__ >= 199901L
+/* It is invalid to compile an XPG3, XPG4, XPG4v2 or XPG5 application using c99 */
+#define _XOPEN_SOURCE 600
+#else
+#define _XOPEN_SOURCE 4
+#endif
+#endif
+
+#include "locmap.h"
+#include "unicode/ustdio.h"
+#include "ufile.h"
+#include "unicode/uloc.h"
+#include "unicode/ures.h"
+#include "unicode/ucnv.h"
+#include "cstring.h"
+#include "cmemory.h"
+
+#if defined(U_WINDOWS) && !defined(fileno)
+/* Windows likes to rename Unix-like functions */
+#define fileno _fileno
+#endif
+
+static UFILE*
+finit_owner(FILE         *f,
+              const char *locale,
+              const char *codepage,
+              UBool       takeOwnership
+              )
+{
+    UErrorCode status = U_ZERO_ERROR;
+    UFILE     *result;
+    if(f == NULL) {
+        return 0;
+    }
+    result = (UFILE*) uprv_malloc(sizeof(UFILE));
+    if(result == NULL) {
+        return 0;
+    }
+
+    uprv_memset(result, 0, sizeof(UFILE));
+    result->fFileno = fileno(f);
+
+#ifdef U_WINDOWS
+    if (0 <= result->fFileno && result->fFileno <= 2) {
+        /* stdin, stdout and stderr need to be special cased for Windows 98 */
+#if _MSC_VER >= 1400
+        result->fFile = &__iob_func()[_fileno(f)];
+#else
+        result->fFile = &_iob[_fileno(f)];
+#endif
+    }
+    else
+#endif
+    {
+        result->fFile = f;
+    }
+
+    result->str.fBuffer = result->fUCBuffer;
+    result->str.fPos    = result->fUCBuffer;
+    result->str.fLimit  = result->fUCBuffer;
+
+#if !UCONFIG_NO_FORMATTING
+        /* if locale is 0, use the default */
+        if(u_locbund_init(&result->str.fBundle, locale) == 0) {
+            /* DO NOT FCLOSE HERE! */
+            uprv_free(result);
+            return 0;
+        }
+#endif
+
+    /* If the codepage is not "" use the ucnv_open default behavior */
+    if(codepage == NULL || *codepage != '\0') {
+        result->fConverter = ucnv_open(codepage, &status);
+    }
+    /* else result->fConverter is already memset'd to NULL. */
+
+    if(U_SUCCESS(status)) {
+        result->fOwnFile = takeOwnership;
+    }
+    else {
+#if !UCONFIG_NO_FORMATTING
+        u_locbund_close(&result->str.fBundle);
+#endif
+        /* DO NOT fclose here!!!!!! */
+        uprv_free(result);
+        result = NULL;
+    }
+
+    return result;
+}
+
+U_CAPI UFILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_finit(FILE          *f,
+        const char    *locale,
+        const char    *codepage)
+{
+    return finit_owner(f, locale, codepage, FALSE);
+}
+
+U_CAPI UFILE* U_EXPORT2
+u_fadopt(FILE         *f,
+        const char    *locale,
+        const char    *codepage)
+{
+    return finit_owner(f, locale, codepage, TRUE);
+}
+
+U_CAPI UFILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_fopen(const char    *filename,
+        const char    *perm,
+        const char    *locale,
+        const char    *codepage)
+{
+    UFILE     *result;
+    FILE     *systemFile = fopen(filename, perm);
+    if(systemFile == 0) {
+        return 0;
+    }
+
+    result = finit_owner(systemFile, locale, codepage, TRUE);
+
+    if (!result) {
+        /* Something bad happened.
+           Maybe the converter couldn't be opened. */
+        fclose(systemFile);
+    }
+
+    return result;
+}
+
+U_CAPI UFILE* U_EXPORT2
+u_fstropen(UChar *stringBuf,
+           int32_t      capacity,
+           const char  *locale)
+{
+    UFILE *result;
+
+    if (capacity < 0) {
+        return NULL;
+    }
+
+    result = (UFILE*) uprv_malloc(sizeof(UFILE));
+    /* Null pointer test */
+    if (result == NULL) {
+    	return NULL; /* Just get out. */
+    }
+    uprv_memset(result, 0, sizeof(UFILE));
+    result->str.fBuffer = stringBuf;
+    result->str.fPos    = stringBuf;
+    result->str.fLimit  = stringBuf+capacity;
+
+#if !UCONFIG_NO_FORMATTING
+    /* if locale is 0, use the default */
+    if(u_locbund_init(&result->str.fBundle, locale) == 0) {
+        /* DO NOT FCLOSE HERE! */
+        uprv_free(result);
+        return 0;
+    }
+#endif
+
+    return result;
+}
+
+U_CAPI UBool U_EXPORT2
+u_feof(UFILE  *f)
+{
+    UBool endOfBuffer;
+    if (f == NULL) {
+        return TRUE;
+    }
+    endOfBuffer = (UBool)(f->str.fPos >= f->str.fLimit);
+    if (f->fFile != NULL) {
+        return endOfBuffer && feof(f->fFile);
+    }
+    return endOfBuffer;
+}
+
+U_CAPI void U_EXPORT2
+u_fflush(UFILE *file)
+{
+    ufile_flush_translit(file);
+    ufile_flush_io(file);
+    if (file->fFile) {
+        fflush(file->fFile);
+    }
+    else if (file->str.fPos < file->str.fLimit) {
+        *(file->str.fPos++) = 0;
+    }
+    /* TODO: flush input */
+}
+
+U_CAPI void
+u_frewind(UFILE *file)
+{
+    u_fflush(file);
+    ucnv_reset(file->fConverter);
+    if (file->fFile) {
+        rewind(file->fFile);
+        file->str.fLimit = file->fUCBuffer;
+        file->str.fPos   = file->fUCBuffer;
+    }
+    else {
+        file->str.fPos = file->str.fBuffer;
+    }
+}
+
+U_CAPI void U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_fclose(UFILE *file)
+{
+    if (file) {
+        u_fflush(file);
+        ufile_close_translit(file);
+
+        if(file->fOwnFile)
+            fclose(file->fFile);
+
+#if !UCONFIG_NO_FORMATTING
+        u_locbund_close(&file->str.fBundle);
+#endif
+
+        ucnv_close(file->fConverter);
+        uprv_free(file);
+    }
+}
+
+U_CAPI FILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_fgetfile(    UFILE         *f)
+{
+    return f->fFile;
+}
+
+#if !UCONFIG_NO_FORMATTING
+
+U_CAPI const char*  U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_fgetlocale(    UFILE        *file)
+{
+    return file->str.fBundle.fLocale;
+}
+
+U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_fsetlocale(UFILE      *file,
+             const char *locale)
+{
+    u_locbund_close(&file->str.fBundle);
+
+    return u_locbund_init(&file->str.fBundle, locale) == 0 ? -1 : 0;
+}
+
+#endif
+
+U_CAPI const char* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_fgetcodepage(UFILE        *file)
+{
+    UErrorCode     status = U_ZERO_ERROR;
+    const char     *codepage = NULL;
+
+    if (file->fConverter) {
+        codepage = ucnv_getName(file->fConverter, &status);
+        if(U_FAILURE(status))
+            return 0;
+    }
+    return codepage;
+}
+
+U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_fsetcodepage(    const char    *codepage,
+               UFILE        *file)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    int32_t retVal = -1;
+
+    /* We use the normal default codepage for this system, and not the one for the locale. */
+    if ((file->str.fPos == file->str.fBuffer) && (file->str.fLimit == file->str.fBuffer)) {
+        ucnv_close(file->fConverter);
+        file->fConverter = ucnv_open(codepage, &status);
+        if(U_SUCCESS(status)) {
+            retVal = 0;
+        }
+    }
+    return retVal;
+}
+
+
+U_CAPI UConverter * U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_fgetConverter(UFILE *file)
+{
+    return file->fConverter;
+}
+
diff --git a/source/io/ufile.h b/source/io/ufile.h
new file mode 100644
index 0000000..3305642
--- /dev/null
+++ b/source/io/ufile.h
@@ -0,0 +1,132 @@
+/*
+ *******************************************************************************
+ *
+ *   Copyright (C) 1998-2010, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ *
+ *******************************************************************************
+ *
+ * File ufile.h
+ *
+ * Modification History:
+ *
+ *   Date        Name        Description
+ *   12/01/98    stephen        Creation.
+ *   03/12/99    stephen     Modified for new C API.
+ *******************************************************************************
+ */
+
+#ifndef UFILE_H
+#define UFILE_H
+
+#include "unicode/utypes.h"
+#include "unicode/ucnv.h"
+#include "unicode/utrans.h"
+#include "locbund.h"
+
+/* The buffer size for fromUnicode calls */
+#define UFILE_CHARBUFFER_SIZE 1024
+
+/* The buffer size for toUnicode calls */
+#define UFILE_UCHARBUFFER_SIZE 1024
+
+/* A UFILE */
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+typedef struct {
+    UChar  *buffer;             /* Beginning of buffer */
+    int32_t capacity;           /* Capacity of buffer */
+    int32_t pos;                /* Beginning of untranslitted data */
+    int32_t length;             /* Length *from beginning of buffer* of untranslitted data */
+    UTransliterator *translit;
+} UFILETranslitBuffer;
+
+#endif
+
+typedef struct u_localized_string {
+    UChar       *fPos;          /* current pos in fUCBuffer */
+    const UChar *fLimit;        /* data limit in fUCBuffer */
+    UChar       *fBuffer;       /* Place to write the string */
+
+#if !UCONFIG_NO_FORMATTING
+    ULocaleBundle  fBundle; /* formatters */
+#endif
+} u_localized_string;
+
+struct UFILE {
+#if !UCONFIG_NO_TRANSLITERATION
+    UFILETranslitBuffer *fTranslit;
+#endif
+
+    FILE        *fFile;         /* the actual filesystem interface */
+
+    UConverter  *fConverter;    /* for codeset conversion */
+
+    u_localized_string str;     /* struct to handle strings for number formatting */
+
+    UChar       fUCBuffer[UFILE_UCHARBUFFER_SIZE];/* buffer used for toUnicode */
+
+    UBool       fOwnFile;       /* TRUE if fFile should be closed */
+
+    int32_t     fFileno;        /* File number. Useful to determine if it's stdin. */
+};
+
+/**
+ * Like u_file_write but takes a flush parameter
+ */
+U_CFUNC int32_t U_EXPORT2
+u_file_write_flush( const UChar     *chars, 
+        int32_t     count, 
+        UFILE       *f,
+        UBool       flushIO,
+        UBool       flushTranslit);
+
+/**
+ * Fill a UFILE's buffer with converted codepage data.
+ * @param f The UFILE containing the buffer to fill.
+ */
+void
+ufile_fill_uchar_buffer(UFILE *f);
+
+/**
+ * Get one code unit and detect whether the end of file has been reached.
+ * @param f The UFILE containing the characters.
+ * @param ch The read in character
+ * @return TRUE if the character is valid, or FALSE when EOF has been detected
+ */
+U_CFUNC UBool U_EXPORT2
+ufile_getch(UFILE *f, UChar *ch);
+
+/**
+ * Get one character and detect whether the end of file has been reached.
+ * @param f The UFILE containing the characters.
+ * @param ch The read in character
+ * @return TRUE if the character is valid, or FALSE when EOF has been detected
+ */
+U_CFUNC UBool U_EXPORT2
+ufile_getch32(UFILE *f, UChar32 *ch);
+
+/**
+ * Close out the transliterator and flush any data therein.
+ * @param f flu
+ */
+void 
+ufile_close_translit(UFILE *f);
+
+/**
+ * Flush the buffer in the transliterator 
+ * @param f UFile to flush
+ */
+void 
+ufile_flush_translit(UFILE *f);
+
+/**
+ * Flush the IO buffer
+ * @param f UFile to flush
+ */
+void 
+ufile_flush_io(UFILE *f);
+
+
+#endif
diff --git a/source/io/ufmt_cmn.c b/source/io/ufmt_cmn.c
new file mode 100644
index 0000000..e4e0903
--- /dev/null
+++ b/source/io/ufmt_cmn.c
@@ -0,0 +1,253 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1998-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File ufmt_cmn.c
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   12/02/98    stephen     Creation.
+*   03/12/99    stephen     Modified for new C API.
+*   03/15/99    stephen     Added defaultCPToUnicode, unicodeToDefaultCP
+*   07/19/99    stephen     Fixed bug in defaultCPToUnicode
+******************************************************************************
+*/
+
+#include "cstring.h"
+#include "cmemory.h"
+#include "ufmt_cmn.h"
+#include "unicode/uchar.h"
+#include "unicode/ucnv.h"
+#include "ustr_cnv.h"
+
+#define DIGIT_0     0x0030
+#define DIGIT_9     0x0039
+#define LOWERCASE_A 0x0061
+#define UPPERCASE_A 0x0041
+#define LOWERCASE_Z 0x007A
+#define UPPERCASE_Z 0x005A
+
+int
+ufmt_digitvalue(UChar c)
+{
+    if( ((c>=DIGIT_0)&&(c<=DIGIT_9)) ||
+        ((c>=LOWERCASE_A)&&(c<=LOWERCASE_Z)) ||
+        ((c>=UPPERCASE_A)&&(c<=UPPERCASE_Z))  )
+    {
+      return c - DIGIT_0 - (c >= 0x0041 ? (c >= 0x0061 ? 39 : 7) : 0);
+    }
+    else
+    {
+      return -1;
+    }
+}
+
+UBool
+ufmt_isdigit(UChar     c,
+             int32_t     radix)
+{
+    int digitVal = ufmt_digitvalue(c);
+
+    return (UBool)(digitVal < radix && digitVal >= 0);
+}
+
+#define TO_UC_DIGIT(a) a <= 9 ? (DIGIT_0 + a) : (0x0037 + a)
+#define TO_LC_DIGIT(a) a <= 9 ? (DIGIT_0 + a) : (0x0057 + a)
+
+void 
+ufmt_64tou(UChar     *buffer, 
+          int32_t   *len,
+          uint64_t  value, 
+          uint8_t  radix,
+          UBool     uselower,
+          int32_t   minDigits)
+{
+    int32_t  length = 0;
+    uint32_t digit;
+    UChar    *left, *right, temp;
+    
+    do {
+        digit = (uint32_t)(value % radix);
+        value = value / radix;
+        buffer[length++] = (UChar)(uselower ? TO_LC_DIGIT(digit) 
+            : TO_UC_DIGIT(digit));
+    } while(value);
+
+    /* pad with zeroes to make it minDigits long */
+    if(minDigits != -1 && length < minDigits) {
+        while(length < minDigits && length < *len)
+            buffer[length++] = DIGIT_0;  /*zero padding */
+    }
+
+    /* reverse the buffer */
+    left     = buffer;
+    right = buffer + length;
+    while(left < --right) {
+        temp     = *left;
+        *left++     = *right;
+        *right     = temp;
+    }
+    
+    *len = length;
+}
+
+void 
+ufmt_ptou(UChar    *buffer, 
+          int32_t   *len,
+          void      *value, 
+          UBool     uselower)
+{
+    int32_t i;
+    int32_t length = 0;
+    uint8_t *ptrIdx = (uint8_t *)&value;
+
+#if U_IS_BIG_ENDIAN
+    for (i = 0; i < (int32_t)sizeof(void *); i++)
+#else
+    for (i = (int32_t)sizeof(void *)-1; i >= 0 ; i--)
+#endif
+    {
+        uint8_t byteVal = ptrIdx[i];
+        uint16_t firstNibble = (uint16_t)(byteVal>>4);
+        uint16_t secondNibble = (uint16_t)(byteVal&0xF);
+        if (uselower) {
+            buffer[length++]=TO_LC_DIGIT(firstNibble);
+            buffer[length++]=TO_LC_DIGIT(secondNibble);
+        }
+        else {
+            buffer[length++]=TO_UC_DIGIT(firstNibble);
+            buffer[length++]=TO_UC_DIGIT(secondNibble);
+        }
+    }
+
+    *len = length;
+}
+
+int64_t
+ufmt_uto64(const UChar     *buffer, 
+          int32_t     *len,
+          int8_t     radix)
+{
+    const UChar     *limit;
+    int32_t         count;
+    int64_t        result;
+    
+    
+    /* intialize parameters */
+    limit     = buffer + *len;
+    count     = 0;
+    result    = 0;
+    
+    /* iterate through buffer */
+    while(ufmt_isdigit(*buffer, radix) && buffer < limit) {
+        
+        /* read the next digit */
+        result *= radix;
+        result += ufmt_digitvalue(*buffer++);
+        
+        /* increment our count */
+        ++count;
+    }
+    
+    *len = count;
+    return result;
+}
+
+#define NIBBLE_PER_BYTE 2
+void *
+ufmt_utop(const UChar     *buffer,
+          int32_t     *len)
+{
+    int32_t count, resultIdx, incVal, offset;
+    /* This union allows the pointer to be written as an array. */
+    union {
+        void *ptr;
+        uint8_t bytes[sizeof(void*)];
+    } result;
+    
+    /* intialize variables */
+    count      = 0;
+    offset     = 0;
+    result.ptr = NULL;
+
+    /* Skip the leading zeros */
+    while(buffer[count] == DIGIT_0 || u_isspace(buffer[count])) {
+        count++;
+        offset++;
+    }
+
+    /* iterate through buffer, stop when you hit the end */
+    while(ufmt_isdigit(buffer[count], 16) && count < *len) {
+        /* increment the count consumed */
+        ++count;
+    }
+
+    /* detect overflow */
+    if (count - offset > (int32_t)(sizeof(void*)*NIBBLE_PER_BYTE)) {
+        offset = count - (int32_t)(sizeof(void*)*NIBBLE_PER_BYTE);
+    }
+    
+    /* Initialize the direction of the input */
+#if U_IS_BIG_ENDIAN
+    incVal = -1;
+    resultIdx = (int32_t)(sizeof(void*) - 1);
+#else
+    incVal = 1;
+    resultIdx = 0;
+#endif
+    /* Write how much was consumed. */
+    *len = count;
+    while(--count >= offset) {
+        /* Get the first nibble of the byte */
+        uint8_t byte = (uint8_t)ufmt_digitvalue(buffer[count]);
+
+        if (count > offset) {
+            /* Get the second nibble of the byte when available */
+            byte = (uint8_t)(byte + (ufmt_digitvalue(buffer[--count]) << 4));
+        }
+        /* Write the byte into the array */
+        result.bytes[resultIdx] = byte;
+        resultIdx += incVal;
+    }
+
+    return result.ptr;
+}
+
+UChar*
+ufmt_defaultCPToUnicode(const char *s, int32_t sSize,
+                        UChar *target, int32_t tSize)
+{
+    UChar *alias;
+    UErrorCode status = U_ZERO_ERROR;
+    UConverter *defConverter = u_getDefaultConverter(&status);
+    
+    if(U_FAILURE(status) || defConverter == 0)
+        return 0;
+
+    if(sSize <= 0) {
+        sSize = uprv_strlen(s) + 1;
+    }
+    
+    /* perform the conversion in one swoop */
+    if(target != 0) {
+        
+        alias = target;
+        ucnv_toUnicode(defConverter, &alias, alias + tSize, &s, s + sSize - 1, 
+            NULL, TRUE, &status);
+        
+        
+        /* add the null terminator */
+        *alias = 0x0000;
+    }
+    
+    u_releaseDefaultConverter(defConverter);
+    
+    return target;
+}
+
+
diff --git a/source/io/ufmt_cmn.h b/source/io/ufmt_cmn.h
new file mode 100644
index 0000000..29a4a07
--- /dev/null
+++ b/source/io/ufmt_cmn.h
@@ -0,0 +1,159 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1998-2004, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File ufmt_cmn.h
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   12/02/98    stephen        Creation.
+*   03/12/99    stephen     Modified for new C API.
+*   03/15/99    stephen     Added defaultCPToUnicode, unicodeToDefaultCP
+******************************************************************************
+*/
+
+#ifndef UFMT_CMN_H
+#define UFMT_CMN_H
+
+#include "unicode/utypes.h"
+
+#define UFMT_DEFAULT_BUFFER_SIZE 128
+#define MAX_UCHAR_BUFFER_SIZE(buffer) (sizeof(buffer)/(UTF_MAX_CHAR_LENGTH*sizeof(UChar)))
+#define MAX_UCHAR_BUFFER_NEEDED(strLen) ((strLen+1)*UTF_MAX_CHAR_LENGTH*sizeof(UChar))
+
+/** 
+ * Enum representing the possible argument types for uprintf/uscanf
+ */
+typedef enum ufmt_type_info {
+    ufmt_empty = 0,
+    ufmt_simple_percent, /* %% do nothing */
+    ufmt_count,      /* special flag for count */
+    ufmt_int,        /* int */
+    ufmt_char,       /* int, cast to char */
+    ufmt_string,     /* char* */
+    ufmt_pointer,    /* void* */
+    ufmt_float,      /* float */
+    ufmt_double,     /* double */
+    ufmt_uchar,      /* int, cast to UChar */
+    ufmt_ustring     /* UChar* */
+    /*ufmt_wchar,*/      /* wchar_t */
+    /*ufmt_wstring,*/    /* wchar_t* */
+    /*ufmt_date,*/       /* Date */
+    /*ufmt_last*/
+} ufmt_type_info;
+
+/**
+ * Union representing a uprintf/uscanf argument
+ */
+typedef union ufmt_args {
+    int64_t int64Value;    /* int, UChar */
+    float   floatValue;    /* float */
+    double  doubleValue;   /* double */
+    void    *ptrValue;     /* any pointer - void*, char*, wchar_t*, UChar* */
+    /*wchar_t wcharValue;*/    /* wchar_t */    /* TODO: Should wchar_t be used? */
+    /*UDate dateValue;*/     /* Date */
+} ufmt_args;
+
+/**
+ * Macro for determining the minimum of two numbers.
+ * @param a An integer
+ * @param b An integer
+ * @return <TT>a</TT> if </TT>a < b</TT>, <TT>b</TT> otherwise
+ */
+#define ufmt_min(a,b) ((a) < (b) ? (a) : (b))
+
+/**
+ * Convert a UChar in hex radix to an integer value.
+ * @param c The UChar to convert.
+ * @return The integer value of <TT>c</TT>.
+ */
+int
+ufmt_digitvalue(UChar c);
+
+/**
+ * Determine if a UChar is a digit for a specified radix.
+ * @param c The UChar to check.
+ * @param radix The desired radix.
+ * @return TRUE if <TT>c</TT> is a digit in <TT>radix</TT>, FALSE otherwise.
+ */
+UBool
+ufmt_isdigit(UChar     c,
+         int32_t     radix);
+
+/**
+ * Convert an int64_t to a UChar* in a specified radix
+ * @param buffer The target buffer
+ * @param len On input, the size of <TT>buffer</TT>.  On output,
+ * the number of UChars written to <TT>buffer</TT>.
+ * @param value The value to be converted
+ * @param radix The desired radix
+ * @param uselower TRUE means lower case will be used, FALSE means upper case
+ * @param minDigits The minimum number of digits for for the formatted number,
+ * which will be padded with zeroes. -1 means do not pad.
+ */
+void 
+ufmt_64tou(UChar     *buffer, 
+      int32_t     *len,
+      uint64_t     value, 
+      uint8_t     radix,
+      UBool    uselower,
+      int32_t    minDigits);
+
+/**
+ * It's like ufmt_64tou, but with a pointer.
+ * This functions avoids size constraints of 64-bit types.
+ * Pointers can be at 32-128 bits in size.
+ */
+void 
+ufmt_ptou(UChar    *buffer, 
+          int32_t   *len,
+          void      *value, 
+          UBool     uselower);
+
+/**
+ * Convert a UChar* in a specified radix to an int64_t.
+ * @param buffer The target buffer
+ * @param len On input, the size of <TT>buffer</TT>.  On output,
+ * the number of UChars read from <TT>buffer</TT>.
+ * @param radix The desired radix
+ * @return The numeric value.
+ */
+int64_t
+ufmt_uto64(const UChar     *buffer, 
+      int32_t     *len,
+      int8_t     radix);
+
+/**
+ * Convert a UChar* in a specified radix to a pointer,
+ * @param buffer The target buffer
+ * @param len On input, the size of <TT>buffer</TT>.  On output,
+ * the number of UChars read from <TT>buffer</TT>.
+ * @param radix The desired radix
+ * @return The pointer value.
+ */
+void *
+ufmt_utop(const UChar     *buffer,
+      int32_t     *len);
+
+/**
+ * Convert a string from the default codepage to Unicode.
+ * @param s The string to convert, in the default codepage.
+ * @param sSize The size of s to convert.
+ * @param target The buffer to convert to.
+ * @param tSize The size of target
+ * @return A pointer to a newly allocated converted version of s, or 0 
+ * on error.
+ */
+UChar*
+ufmt_defaultCPToUnicode(const char *s, int32_t sSize,
+                        UChar *target, int32_t tSize);
+
+
+
+#endif
+
diff --git a/source/io/unicode/ustdio.h b/source/io/unicode/ustdio.h
new file mode 100644
index 0000000..9bcc797
--- /dev/null
+++ b/source/io/unicode/ustdio.h
@@ -0,0 +1,951 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1998-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File ustdio.h
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   10/16/98    stephen     Creation.
+*   11/06/98    stephen     Modified per code review.
+*   03/12/99    stephen     Modified for new C API.
+*   07/19/99    stephen     Minor doc update.
+*   02/01/01    george      Added sprintf & sscanf with all of its variants
+******************************************************************************
+*/
+
+#ifndef USTDIO_H
+#define USTDIO_H
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "unicode/utypes.h"
+#include "unicode/ucnv.h"
+#include "unicode/utrans.h"
+#include "unicode/localpointer.h"
+
+/*
+    TODO
+ The following is a small list as to what is currently wrong/suggestions for
+ ustdio.
+
+ * Make sure that * in the scanf format specification works for all formats.
+ * Each UFILE takes up at least 2KB.
+    Look into adding setvbuf() for configurable buffers.
+ * This library does buffering. The OS should do this for us already. Check on
+    this, and remove it from this library, if this is the case. Double buffering
+    wastes a lot of time and space.
+ * Test stdin and stdout with the u_f* functions
+ * Testing should be done for reading and writing multi-byte encodings,
+    and make sure that a character that is contained across buffer boundries
+    works even for incomplete characters.
+ * Make sure that the last character is flushed when the file/string is closed.
+ * snprintf should follow the C99 standard for the return value, which is
+    return the number of characters (excluding the trailing '\0')
+    which would have been written to the destination string regardless
+    of available space. This is like pre-flighting.
+ * Everything that uses %s should do what operator>> does for UnicodeString.
+    It should convert one byte at a time, and once a character is
+    converted then check to see if it's whitespace or in the scanset.
+    If it's whitespace or in the scanset, put all the bytes back (do nothing
+    for sprintf/sscanf).
+ * If bad string data is encountered, make sure that the function fails
+    without memory leaks and the unconvertable characters are valid
+    substitution or are escaped characters.
+ * u_fungetc() can't unget a character when it's at the beginning of the
+    internal conversion buffer. For example, read the buffer size # of
+    characters, and then ungetc to get the previous character that was
+    at the end of the last buffer.
+ * u_fflush() and u_fclose should return an int32_t like C99 functions.
+    0 is returned if the operation was successful and EOF otherwise.
+ * u_fsettransliterator does not support U_READ side of transliteration.
+ * The format specifier should limit the size of a format or honor it in
+    order to prevent buffer overruns.  (e.g. %256.256d).
+ * u_fread and u_fwrite don't exist. They're needed for reading and writing
+    data structures without any conversion.
+ * u_file_read and u_file_write are used for writing strings. u_fgets and
+    u_fputs or u_fread and u_fwrite should be used to do this.
+ * The width parameter for all scanf formats, including scanset, needs
+    better testing. This prevents buffer overflows.
+ * Figure out what is suppose to happen when a codepage is changed midstream.
+    Maybe a flush or a rewind are good enough.
+ * Make sure that a UFile opened with "rw" can be used after using
+    u_fflush with a u_frewind.
+ * scanf(%i) should detect what type of number to use.
+ * Add more testing of the alternate format, %#
+ * Look at newline handling of fputs/puts
+ * Think more about codeunit/codepoint error handling/support in %S,%s,%C,%c,%[]
+ * Complete the file documentation with proper doxygen formatting.
+    See http://oss.software.ibm.com/pipermail/icu/2003-July/005647.html
+*/
+
+/**
+ * \file
+ * \brief C API: Unicode stdio-like API
+ *
+ * <h2>Unicode stdio-like C API</h2>
+ *
+ * <p>This API provides an stdio-like API wrapper around ICU's other
+ * formatting and parsing APIs. It is meant to ease the transition of adding
+ * Unicode support to a preexisting applications using stdio. The following
+ * is a small list of noticable differences between stdio and ICU I/O's
+ * ustdio implementation.</p>
+ *
+ * <ul>
+ * <li>Locale specific formatting and parsing is only done with file IO.</li>
+ * <li>u_fstropen can be used to simulate file IO with strings.
+ * This is similar to the iostream API, and it allows locale specific
+ * formatting and parsing to be used.</li>
+ * <li>This API provides uniform formatting and parsing behavior between
+ * platforms (unlike the standard stdio implementations found on various
+ * platforms).</li>
+ * <li>This API is better suited for text data handling than binary data
+ * handling when compared to the typical stdio implementation.</li>
+ * <li>You can specify a Transliterator while using the file IO.</li>
+ * <li>You can specify a file's codepage separately from the default
+ * system codepage.</li>
+ * </ul>
+ *
+ * <h2>Formatting and Parsing Specification</h2>
+ *
+ * General printf format:<br>
+ * %[format modifier][width][.precision][type modifier][format]
+ * 
+ * General scanf format:<br>
+ * %[*][format modifier][width][type modifier][format]
+ * 
+<table cellspacing="3">
+<tr><td>format</td><td>default<br>printf<br>type</td><td>default<br>scanf<br>type</td><td>description</td></tr>
+<tr><td>%E</td><td>double</td><td>float</td><td>Scientific with an uppercase exponent</td></tr>
+<tr><td>%e</td><td>double</td><td>float</td><td>Scientific with a lowercase exponent</td></tr>
+<tr><td>%G</td><td>double</td><td>float</td><td>Use %E or %f for best format</td></tr>
+<tr><td>%g</td><td>double</td><td>float</td><td>Use %e or %f for best format</td></tr>
+<tr><td>%f</td><td>double</td><td>float</td><td>Simple floating point without the exponent</td></tr>
+<tr><td>%X</td><td>int32_t</td><td>int32_t</td><td>ustdio special uppercase hex radix formatting</td></tr>
+<tr><td>%x</td><td>int32_t</td><td>int32_t</td><td>ustdio special lowercase hex radix formatting</td></tr>
+<tr><td>%d</td><td>int32_t</td><td>int32_t</td><td>Decimal format</td></tr>
+<tr><td>%i</td><td>int32_t</td><td>int32_t</td><td>Same as %d</td></tr>
+<tr><td>%n</td><td>int32_t</td><td>int32_t</td><td>count (write the number of UTF-16 codeunits read/written)</td></tr>
+<tr><td>%o</td><td>int32_t</td><td>int32_t</td><td>ustdio special octal radix formatting</td></tr>
+<tr><td>%u</td><td>uint32_t</td><td>uint32_t</td><td>Decimal format</td></tr>
+<tr><td>%p</td><td>void *</td><td>void *</td><td>Prints the pointer value</td></tr>
+<tr><td>%s</td><td>char *</td><td>char *</td><td>Use default converter or specified converter from fopen</td></tr>
+<tr><td>%c</td><td>char</td><td>char</td><td>Use default converter or specified converter from fopen<br>
+When width is specified for scanf, this acts like a non-NULL-terminated char * string.<br>
+By default, only one char is written.</td></tr>
+<tr><td>%S</td><td>UChar *</td><td>UChar *</td><td>Null terminated UTF-16 string</td></tr>
+<tr><td>%C</td><td>UChar</td><td>UChar</td><td>16-bit Unicode code unit<br>
+When width is specified for scanf, this acts like a non-NULL-terminated UChar * string<br>
+By default, only one codepoint is written.</td></tr>
+<tr><td>%[]</td><td>&nbsp;</td><td>UChar *</td><td>Null terminated UTF-16 string which contains the filtered set of characters specified by the UnicodeSet</td></tr>
+<tr><td>%%</td><td>&nbsp;</td><td>&nbsp;</td><td>Show a percent sign</td></tr>
+</table>
+
+Format modifiers
+<table>
+<tr><td>modifier</td><td>formats</td><td>type</td><td>comments</td></tr>
+<tr><td>%h</td><td>%d, %i, %o, %x</td><td>int16_t</td><td>short format</td></tr>
+<tr><td>%h</td><td>%u</td><td>uint16_t</td><td>short format</td></tr>
+<tr><td>%h</td><td>c</td><td>char</td><td><b>(Unimplemented)</b> Use invariant converter</td></tr>
+<tr><td>%h</td><td>s</td><td>char *</td><td><b>(Unimplemented)</b> Use invariant converter</td></tr>
+<tr><td>%h</td><td>C</td><td>char</td><td><b>(Unimplemented)</b> 8-bit Unicode code unit</td></tr>
+<tr><td>%h</td><td>S</td><td>char *</td><td><b>(Unimplemented)</b> Null terminated UTF-8 string</td></tr>
+<tr><td>%l</td><td>%d, %i, %o, %x</td><td>int32_t</td><td>long format (no effect)</td></tr>
+<tr><td>%l</td><td>%u</td><td>uint32_t</td><td>long format (no effect)</td></tr>
+<tr><td>%l</td><td>c</td><td>N/A</td><td><b>(Unimplemented)</b> Reserved for future implementation</td></tr>
+<tr><td>%l</td><td>s</td><td>N/A</td><td><b>(Unimplemented)</b> Reserved for future implementation</td></tr>
+<tr><td>%l</td><td>C</td><td>UChar32</td><td><b>(Unimplemented)</b> 32-bit Unicode code unit</td></tr>
+<tr><td>%l</td><td>S</td><td>UChar32 *</td><td><b>(Unimplemented)</b> Null terminated UTF-32 string</td></tr>
+<tr><td>%ll</td><td>%d, %i, %o, %x</td><td>int64_t</td><td>long long format</td></tr>
+<tr><td>%ll</td><td>%u</td><td>uint64_t</td><td><b>(Unimplemented)</b> long long format</td></tr>
+<tr><td>%-</td><td><i>all</i></td><td>N/A</td><td>Left justify</td></tr>
+<tr><td>%+</td><td>%d, %i, %o, %x, %e, %f, %g, %E, %G</td><td>N/A</td><td>Always show the plus or minus sign. Needs data for plus sign.</td></tr>
+<tr><td>% </td><td>%d, %i, %o, %x, %e, %f, %g, %E, %G</td><td>N/A</td><td>Instead of a "+" output a blank character for positive numbers.</td></tr>
+<tr><td>%#</td><td>%d, %i, %o, %x, %e, %f, %g, %E, %G</td><td>N/A</td><td>Precede octal value with 0, hex with 0x and show the 
+                decimal point for floats.</td></tr>
+<tr><td>%<i>n</i></td><td><i>all</i></td><td>N/A</td><td>Width of input/output. num is an actual number from 0 to 
+                some large number.</td></tr>
+<tr><td>%.<i>n</i></td><td>%e, %f, %g, %E, %F, %G</td><td>N/A</td><td>Significant digits precision. num is an actual number from
+                0 to some large number.<br>If * is used in printf, then the precision is passed in as an argument before the number to be formatted.</td></tr>
+</table>
+
+printf modifier
+%*  int32_t     Next argument after this one specifies the width
+
+scanf modifier
+%*  N/A         This field is scanned, but not stored
+
+<p>If you are using this C API instead of the ustream.h API for C++,
+you can use one of the following u_fprintf examples to display a UnicodeString.</p>
+
+<pre><code>
+    UFILE *out = u_finit(stdout, NULL, NULL);
+    UnicodeString string1("string 1");
+    UnicodeString string2("string 2");
+    u_fprintf(out, "%S\n", string1.getTerminatedBuffer());
+    u_fprintf(out, "%.*S\n", string2.length(), string2.getBuffer());
+    u_fclose(out);
+</code></pre>
+
+ */
+
+
+/**
+ * When an end of file is encountered, this value can be returned.
+ * @see u_fgetc
+ * @stable 3.0
+ */
+#define U_EOF 0xFFFF
+
+/** Forward declaration of a Unicode-aware file @stable 3.0 */
+typedef struct UFILE UFILE;
+
+/**
+ * Enum for which direction of stream a transliterator applies to.
+ * @see u_fsettransliterator
+ * @stable ICU 3.0
+ */
+typedef enum { 
+   U_READ = 1,
+   U_WRITE = 2, 
+   U_READWRITE =3  /* == (U_READ | U_WRITE) */ 
+} UFileDirection;
+
+/**
+ * Open a UFILE.
+ * A UFILE is a wrapper around a FILE* that is locale and codepage aware.
+ * That is, data written to a UFILE will be formatted using the conventions
+ * specified by that UFILE's Locale; this data will be in the character set
+ * specified by that UFILE's codepage.
+ * @param filename The name of the file to open.
+ * @param perm The read/write permission for the UFILE; one of "r", "w", "rw"
+ * @param locale The locale whose conventions will be used to format 
+ * and parse output. If this parameter is NULL, the default locale will 
+ * be used.
+ * @param codepage The codepage in which data will be written to and
+ * read from the file. If this paramter is NULL the system default codepage
+ * will be used.
+ * @return A new UFILE, or NULL if an error occurred.
+ * @stable ICU 3.0
+ */
+U_STABLE UFILE* U_EXPORT2
+u_fopen(const char    *filename,
+    const char    *perm,
+    const char    *locale,
+    const char    *codepage);
+
+/**
+ * Open a UFILE on top of an existing FILE* stream. The FILE* stream
+ * ownership remains with the caller. To have the UFILE take over
+ * ownership and responsibility for the FILE* stream, use the
+ * function u_fadopt.
+ * @param f The FILE* to which this UFILE will attach and use.
+ * @param locale The locale whose conventions will be used to format 
+ * and parse output. If this parameter is NULL, the default locale will 
+ * be used.
+ * @param codepage The codepage in which data will be written to and
+ * read from the file. If this paramter is NULL, data will be written and
+ * read using the default codepage for <TT>locale</TT>, unless <TT>locale</TT>
+ * is NULL, in which case the system default codepage will be used.
+ * @return A new UFILE, or NULL if an error occurred.
+ * @stable ICU 3.0
+ */
+U_STABLE UFILE* U_EXPORT2
+u_finit(FILE        *f,
+    const char    *locale,
+    const char    *codepage);
+
+/**
+ * Open a UFILE on top of an existing FILE* stream. The FILE* stream
+ * ownership is transferred to the new UFILE. It will be closed when the
+ * UFILE is closed.
+ * @param f The FILE* which this UFILE will take ownership of.
+ * @param locale The locale whose conventions will be used to format
+ * and parse output. If this parameter is NULL, the default locale will
+ * be used.
+ * @param codepage The codepage in which data will be written to and
+ * read from the file. If this paramter is NULL, data will be written and
+ * read using the default codepage for <TT>locale</TT>, unless <TT>locale</TT>
+ * is NULL, in which case the system default codepage will be used.
+ * @return A new UFILE, or NULL if an error occurred. If an error occurs
+ * the ownership of the FILE* stream remains with the caller.
+ * @stable ICU 4.4
+ */
+U_STABLE UFILE* U_EXPORT2
+u_fadopt(FILE     *f,
+    const char    *locale,
+    const char    *codepage);
+
+/**
+ * Create a UFILE that can be used for localized formatting or parsing.
+ * The u_sprintf and u_sscanf functions do not read or write numbers for a
+ * specific locale. The ustdio.h file functions can be used on this UFILE.
+ * The string is usable once u_fclose or u_fflush has been called on the
+ * returned UFILE.
+ * @param stringBuf The string used for reading or writing.
+ * @param capacity The number of code units available for use in stringBuf
+ * @param locale The locale whose conventions will be used to format 
+ * and parse output. If this parameter is NULL, the default locale will 
+ * be used.
+ * @return A new UFILE, or NULL if an error occurred.
+ * @stable ICU 3.0
+ */
+U_STABLE UFILE* U_EXPORT2
+u_fstropen(UChar      *stringBuf,
+           int32_t     capacity,
+           const char *locale);
+
+/**
+ * Close a UFILE. Implies u_fflush first.
+ * @param file The UFILE to close.
+ * @stable ICU 3.0
+ * @see u_fflush
+ */
+U_STABLE void U_EXPORT2
+u_fclose(UFILE *file);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUFILEPointer
+ * "Smart pointer" class, closes a UFILE via u_fclose().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUFILEPointer, UFILE, u_fclose);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Tests if the UFILE is at the end of the file stream.
+ * @param f The UFILE from which to read.
+ * @return Returns TRUE after the first read operation that attempts to
+ * read past the end of the file. It returns FALSE if the current position is
+ * not end of file.
+ * @stable ICU 3.0
+*/
+U_STABLE UBool U_EXPORT2
+u_feof(UFILE  *f);
+
+/**
+ * Flush output of a UFILE. Implies a flush of
+ * converter/transliterator state. (That is, a logical break is
+ * made in the output stream - for example if a different type of
+ * output is desired.)  The underlying OS level file is also flushed.
+ * Note that for a stateful encoding, the converter may write additional
+ * bytes to return the stream to default state.
+ * @param file The UFILE to flush.
+ * @stable ICU 3.0
+ */
+U_STABLE void U_EXPORT2
+u_fflush(UFILE *file);
+
+/**
+ * Rewind the file pointer to the beginning of the file.
+ * @param file The UFILE to rewind.
+ * @stable ICU 3.0
+ */
+U_STABLE void
+u_frewind(UFILE *file);
+
+/**
+ * Get the FILE* associated with a UFILE.
+ * @param f The UFILE
+ * @return A FILE*, owned by the UFILE.  The FILE <EM>must not</EM> be closed.
+ * @stable ICU 3.0
+ */
+U_STABLE FILE* U_EXPORT2
+u_fgetfile(UFILE *f);
+
+#if !UCONFIG_NO_FORMATTING
+
+/**
+ * Get the locale whose conventions are used to format and parse output.
+ * This is the same locale passed in the preceding call to<TT>u_fsetlocale</TT>
+ * or <TT>u_fopen</TT>.
+ * @param file The UFILE to set.
+ * @return The locale whose conventions are used to format and parse output.
+ * @stable ICU 3.0
+ */
+U_STABLE const char* U_EXPORT2
+u_fgetlocale(UFILE *file);
+
+/**
+ * Set the locale whose conventions will be used to format and parse output.
+ * @param locale The locale whose conventions will be used to format 
+ * and parse output.
+ * @param file The UFILE to query.
+ * @return NULL if successful, otherwise a negative number.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_fsetlocale(UFILE      *file,
+             const char *locale);
+
+#endif
+
+/**
+ * Get the codepage in which data is written to and read from the UFILE.
+ * This is the same codepage passed in the preceding call to 
+ * <TT>u_fsetcodepage</TT> or <TT>u_fopen</TT>.
+ * @param file The UFILE to query.
+ * @return The codepage in which data is written to and read from the UFILE,
+ * or NULL if an error occurred.
+ * @stable ICU 3.0
+ */
+U_STABLE const char* U_EXPORT2
+u_fgetcodepage(UFILE *file);
+
+/**
+ * Set the codepage in which data will be written to and read from the UFILE.
+ * All Unicode data written to the UFILE will be converted to this codepage
+ * before it is written to the underlying FILE*. It it generally a bad idea to
+ * mix codepages within a file. This should only be called right
+ * after opening the <TT>UFile</TT>, or after calling <TT>u_frewind</TT>.
+ * @param codepage The codepage in which data will be written to 
+ * and read from the file. For example <TT>"latin-1"</TT> or <TT>"ibm-943"</TT>.
+ * A value of NULL means the default codepage for the UFILE's current 
+ * locale will be used.
+ * @param file The UFILE to set.
+ * @return 0 if successful, otherwise a negative number.
+ * @see u_frewind
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_fsetcodepage(const char   *codepage,
+               UFILE        *file);
+
+
+/**
+ * Returns an alias to the converter being used for this file.
+ * @param f The UFILE to get the value from
+ * @return alias to the converter
+ * @stable ICU 3.0
+ */
+U_STABLE UConverter* U_EXPORT2 u_fgetConverter(UFILE *f);
+
+#if !UCONFIG_NO_FORMATTING
+
+/* Output functions */
+
+/**
+ * Write formatted data to a UFILE.
+ * @param f The UFILE to which to write.
+ * @param patternSpecification A pattern specifying how <TT>u_fprintf</TT> will
+ * interpret the variable arguments received and format the data.
+ * @return The number of Unicode characters written to <TT>f</TT>.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_fprintf(UFILE         *f,
+          const char    *patternSpecification,
+          ... );
+
+/**
+ * Write formatted data to a UFILE.
+ * This is identical to <TT>u_fprintf</TT>, except that it will
+ * <EM>not</EM> call <TT>va_start</TT> and <TT>va_end</TT>.
+ * @param f The UFILE to which to write.
+ * @param patternSpecification A pattern specifying how <TT>u_fprintf</TT> will
+ * interpret the variable arguments received and format the data.
+ * @param ap The argument list to use.
+ * @return The number of Unicode characters written to <TT>f</TT>.
+ * @see u_fprintf
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_vfprintf(UFILE        *f,
+           const char   *patternSpecification,
+           va_list      ap);
+
+/**
+ * Write formatted data to a UFILE.
+ * @param f The UFILE to which to write.
+ * @param patternSpecification A pattern specifying how <TT>u_fprintf</TT> will
+ * interpret the variable arguments received and format the data.
+ * @return The number of Unicode characters written to <TT>f</TT>.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_fprintf_u(UFILE       *f,
+            const UChar *patternSpecification,
+            ... );
+
+/**
+ * Write formatted data to a UFILE.
+ * This is identical to <TT>u_fprintf_u</TT>, except that it will
+ * <EM>not</EM> call <TT>va_start</TT> and <TT>va_end</TT>.
+ * @param f The UFILE to which to write.
+ * @param patternSpecification A pattern specifying how <TT>u_fprintf</TT> will
+ * interpret the variable arguments received and format the data.
+ * @param ap The argument list to use.
+ * @return The number of Unicode characters written to <TT>f</TT>.
+ * @see u_fprintf_u
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_vfprintf_u(UFILE      *f,
+            const UChar *patternSpecification,
+            va_list     ap);
+#endif
+/**
+ * Write a Unicode to a UFILE.  The null (U+0000) terminated UChar*
+ * <TT>s</TT> will be written to <TT>f</TT>, excluding the NULL terminator.
+ * A newline will be added to <TT>f</TT>.
+ * @param s The UChar* to write.
+ * @param f The UFILE to which to write.
+ * @return A non-negative number if successful, EOF otherwise.
+ * @see u_file_write
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_fputs(const UChar *s,
+        UFILE       *f);
+
+/**
+ * Write a UChar to a UFILE.
+ * @param uc The UChar to write.
+ * @param f The UFILE to which to write.
+ * @return The character written if successful, EOF otherwise.
+ * @stable ICU 3.0
+ */
+U_STABLE UChar32 U_EXPORT2
+u_fputc(UChar32  uc,
+        UFILE  *f);
+
+/**
+ * Write Unicode to a UFILE.
+ * The ustring passed in will be converted to the UFILE's underlying
+ * codepage before it is written.
+ * @param ustring A pointer to the Unicode data to write.
+ * @param count The number of Unicode characters to write
+ * @param f The UFILE to which to write.
+ * @return The number of Unicode characters written.
+ * @see u_fputs
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_file_write(const UChar    *ustring, 
+             int32_t        count, 
+             UFILE          *f);
+
+
+/* Input functions */
+#if !UCONFIG_NO_FORMATTING
+
+/**
+ * Read formatted data from a UFILE.
+ * @param f The UFILE from which to read.
+ * @param patternSpecification A pattern specifying how <TT>u_fscanf</TT> will
+ * interpret the variable arguments received and parse the data.
+ * @return The number of items successfully converted and assigned, or EOF
+ * if an error occurred.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_fscanf(UFILE      *f,
+         const char *patternSpecification,
+         ... );
+
+/**
+ * Read formatted data from a UFILE.
+ * This is identical to <TT>u_fscanf</TT>, except that it will
+ * <EM>not</EM> call <TT>va_start</TT> and <TT>va_end</TT>.
+ * @param f The UFILE from which to read.
+ * @param patternSpecification A pattern specifying how <TT>u_fscanf</TT> will
+ * interpret the variable arguments received and parse the data.
+ * @param ap The argument list to use.
+ * @return The number of items successfully converted and assigned, or EOF
+ * if an error occurred.
+ * @see u_fscanf
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_vfscanf(UFILE         *f,
+          const char    *patternSpecification,
+          va_list        ap);
+
+/**
+ * Read formatted data from a UFILE.
+ * @param f The UFILE from which to read.
+ * @param patternSpecification A pattern specifying how <TT>u_fscanf</TT> will
+ * interpret the variable arguments received and parse the data.
+ * @return The number of items successfully converted and assigned, or EOF
+ * if an error occurred.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_fscanf_u(UFILE        *f,
+           const UChar  *patternSpecification,
+           ... );
+
+/**
+ * Read formatted data from a UFILE.
+ * This is identical to <TT>u_fscanf_u</TT>, except that it will
+ * <EM>not</EM> call <TT>va_start</TT> and <TT>va_end</TT>.
+ * @param f The UFILE from which to read.
+ * @param patternSpecification A pattern specifying how <TT>u_fscanf</TT> will
+ * interpret the variable arguments received and parse the data.
+ * @param ap The argument list to use.
+ * @return The number of items successfully converted and assigned, or EOF
+ * if an error occurred.
+ * @see u_fscanf_u
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_vfscanf_u(UFILE       *f,
+            const UChar *patternSpecification,
+            va_list      ap);
+#endif
+
+/**
+ * Read one line of text into a UChar* string from a UFILE. The newline
+ * at the end of the line is read into the string. The string is always
+ * null terminated
+ * @param f The UFILE from which to read.
+ * @param n The maximum number of characters - 1 to read.
+ * @param s The UChar* to receive the read data.  Characters will be
+ * stored successively in <TT>s</TT> until a newline or EOF is
+ * reached. A null character (U+0000) will be appended to <TT>s</TT>.
+ * @return A pointer to <TT>s</TT>, or NULL if no characters were available.
+ * @stable ICU 3.0
+ */
+U_STABLE UChar* U_EXPORT2
+u_fgets(UChar  *s,
+        int32_t n,
+        UFILE  *f);
+
+/**
+ * Read a UChar from a UFILE. It is recommended that <TT>u_fgetcx</TT>
+ * used instead for proper parsing functions, but sometimes reading
+ * code units is needed instead of codepoints.
+ *
+ * @param f The UFILE from which to read.
+ * @return The UChar value read, or U+FFFF if no character was available.
+ * @stable ICU 3.0
+ */
+U_STABLE UChar U_EXPORT2
+u_fgetc(UFILE   *f);
+
+/**
+ * Read a UChar32 from a UFILE.
+ *
+ * @param f The UFILE from which to read.
+ * @return The UChar32 value read, or U_EOF if no character was
+ * available, or U+FFFFFFFF if an ill-formed character was
+ * encountered.
+ * @see u_unescape()
+ * @stable ICU 3.0
+ */
+U_STABLE UChar32 U_EXPORT2
+u_fgetcx(UFILE  *f);
+
+/**
+ * Unget a UChar from a UFILE.
+ * If this function is not the first to operate on <TT>f</TT> after a call
+ * to <TT>u_fgetc</TT>, the results are undefined.
+ * If this function is passed a character that was not recieved from the
+ * previous <TT>u_fgetc</TT> or <TT>u_fgetcx</TT> call, the results are undefined.
+ * @param c The UChar to put back on the stream.
+ * @param f The UFILE to receive <TT>c</TT>.
+ * @return The UChar32 value put back if successful, U_EOF otherwise.
+ * @stable ICU 3.0
+ */
+U_STABLE UChar32 U_EXPORT2
+u_fungetc(UChar32   c,
+      UFILE        *f);
+
+/**
+ * Read Unicode from a UFILE.
+ * Bytes will be converted from the UFILE's underlying codepage, with
+ * subsequent conversion to Unicode. The data will not be NULL terminated.
+ * @param chars A pointer to receive the Unicode data.
+ * @param count The number of Unicode characters to read.
+ * @param f The UFILE from which to read.
+ * @return The number of Unicode characters read.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_file_read(UChar        *chars, 
+        int32_t        count, 
+        UFILE         *f);
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+/**
+ * Set a transliterator on the UFILE. The transliterator will be owned by the
+ * UFILE. 
+ * @param file The UFILE to set transliteration on
+ * @param adopt The UTransliterator to set. Can be NULL, which will
+ * mean that no transliteration is used.
+ * @param direction either U_READ, U_WRITE, or U_READWRITE - sets
+ *  which direction the transliterator is to be applied to. If
+ * U_READWRITE, the "Read" transliteration will be in the inverse
+ * direction.
+ * @param status ICU error code.
+ * @return The previously set transliterator, owned by the
+ * caller. If U_READWRITE is specified, only the WRITE transliterator
+ * is returned. In most cases, the caller should call utrans_close()
+ * on the result of this function.
+ * @stable ICU 3.0
+ */
+U_STABLE UTransliterator* U_EXPORT2
+u_fsettransliterator(UFILE *file, UFileDirection direction,
+                     UTransliterator *adopt, UErrorCode *status);
+
+#endif
+
+
+/* Output string functions */
+#if !UCONFIG_NO_FORMATTING
+
+
+/**
+ * Write formatted data to a Unicode string.
+ *
+ * @param buffer The Unicode String to which to write.
+ * @param patternSpecification A pattern specifying how <TT>u_sprintf</TT> will
+ * interpret the variable arguments received and format the data.
+ * @return The number of Unicode code units written to <TT>buffer</TT>. This
+ * does not include the terminating null character.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_sprintf(UChar       *buffer,
+        const char    *patternSpecification,
+        ... );
+
+/**
+ * Write formatted data to a Unicode string. When the number of code units
+ * required to store the data exceeds <TT>count</TT>, then <TT>count</TT> code
+ * units of data are stored in <TT>buffer</TT> and a negative value is
+ * returned. When the number of code units required to store the data equals
+ * <TT>count</TT>, the string is not null terminated and <TT>count</TT> is
+ * returned.
+ *
+ * @param buffer The Unicode String to which to write.
+ * @param count The number of code units to read.
+ * @param patternSpecification A pattern specifying how <TT>u_sprintf</TT> will
+ * interpret the variable arguments received and format the data.
+ * @return The number of Unicode characters that would have been written to
+ * <TT>buffer</TT> had count been sufficiently large. This does not include
+ * the terminating null character.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_snprintf(UChar      *buffer,
+        int32_t       count,
+        const char    *patternSpecification,
+        ... );
+
+/**
+ * Write formatted data to a Unicode string.
+ * This is identical to <TT>u_sprintf</TT>, except that it will
+ * <EM>not</EM> call <TT>va_start</TT> and <TT>va_end</TT>.
+ *
+ * @param buffer The Unicode string to which to write.
+ * @param patternSpecification A pattern specifying how <TT>u_sprintf</TT> will
+ * interpret the variable arguments received and format the data.
+ * @param ap The argument list to use.
+ * @return The number of Unicode characters written to <TT>buffer</TT>.
+ * @see u_sprintf
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_vsprintf(UChar      *buffer,
+        const char    *patternSpecification,
+        va_list        ap);
+
+/**
+ * Write formatted data to a Unicode string.
+ * This is identical to <TT>u_snprintf</TT>, except that it will
+ * <EM>not</EM> call <TT>va_start</TT> and <TT>va_end</TT>.<br><br>
+ * When the number of code units required to store the data exceeds
+ * <TT>count</TT>, then <TT>count</TT> code units of data are stored in
+ * <TT>buffer</TT> and a negative value is returned. When the number of code
+ * units required to store the data equals <TT>count</TT>, the string is not
+ * null terminated and <TT>count</TT> is returned.
+ *
+ * @param buffer The Unicode string to which to write.
+ * @param count The number of code units to read.
+ * @param patternSpecification A pattern specifying how <TT>u_sprintf</TT> will
+ * interpret the variable arguments received and format the data.
+ * @param ap The argument list to use.
+ * @return The number of Unicode characters that would have been written to
+ * <TT>buffer</TT> had count been sufficiently large.
+ * @see u_sprintf
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_vsnprintf(UChar     *buffer,
+        int32_t       count,
+        const char    *patternSpecification,
+        va_list        ap);
+
+/**
+ * Write formatted data to a Unicode string.
+ *
+ * @param buffer The Unicode string to which to write.
+ * @param patternSpecification A pattern specifying how <TT>u_sprintf</TT> will
+ * interpret the variable arguments received and format the data.
+ * @return The number of Unicode characters written to <TT>buffer</TT>.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_sprintf_u(UChar      *buffer,
+        const UChar    *patternSpecification,
+        ... );
+
+/**
+ * Write formatted data to a Unicode string. When the number of code units
+ * required to store the data exceeds <TT>count</TT>, then <TT>count</TT> code
+ * units of data are stored in <TT>buffer</TT> and a negative value is
+ * returned. When the number of code units required to store the data equals
+ * <TT>count</TT>, the string is not null terminated and <TT>count</TT> is
+ * returned.
+ *
+ * @param buffer The Unicode string to which to write.
+ * @param count The number of code units to read.
+ * @param patternSpecification A pattern specifying how <TT>u_sprintf</TT> will
+ * interpret the variable arguments received and format the data.
+ * @return The number of Unicode characters that would have been written to
+ * <TT>buffer</TT> had count been sufficiently large.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_snprintf_u(UChar     *buffer,
+        int32_t        count,
+        const UChar    *patternSpecification,
+        ... );
+
+/**
+ * Write formatted data to a Unicode string.
+ * This is identical to <TT>u_sprintf_u</TT>, except that it will
+ * <EM>not</EM> call <TT>va_start</TT> and <TT>va_end</TT>.
+ *
+ * @param buffer The Unicode string to which to write.
+ * @param patternSpecification A pattern specifying how <TT>u_sprintf</TT> will
+ * interpret the variable arguments received and format the data.
+ * @param ap The argument list to use.
+ * @return The number of Unicode characters written to <TT>f</TT>.
+ * @see u_sprintf_u
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_vsprintf_u(UChar     *buffer,
+        const UChar    *patternSpecification,
+        va_list        ap);
+
+/**
+ * Write formatted data to a Unicode string.
+ * This is identical to <TT>u_snprintf_u</TT>, except that it will
+ * <EM>not</EM> call <TT>va_start</TT> and <TT>va_end</TT>.
+ * When the number of code units required to store the data exceeds
+ * <TT>count</TT>, then <TT>count</TT> code units of data are stored in
+ * <TT>buffer</TT> and a negative value is returned. When the number of code
+ * units required to store the data equals <TT>count</TT>, the string is not
+ * null terminated and <TT>count</TT> is returned.
+ *
+ * @param buffer The Unicode string to which to write.
+ * @param count The number of code units to read.
+ * @param patternSpecification A pattern specifying how <TT>u_sprintf</TT> will
+ * interpret the variable arguments received and format the data.
+ * @param ap The argument list to use.
+ * @return The number of Unicode characters that would have been written to
+ * <TT>f</TT> had count been sufficiently large.
+ * @see u_sprintf_u
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_vsnprintf_u(UChar *buffer,
+        int32_t         count,
+        const UChar     *patternSpecification,
+        va_list         ap);
+
+/* Input string functions */
+
+/**
+ * Read formatted data from a Unicode string.
+ *
+ * @param buffer The Unicode string from which to read.
+ * @param patternSpecification A pattern specifying how <TT>u_sscanf</TT> will
+ * interpret the variable arguments received and parse the data.
+ * @return The number of items successfully converted and assigned, or EOF
+ * if an error occurred.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_sscanf(const UChar   *buffer,
+        const char     *patternSpecification,
+        ... );
+
+/**
+ * Read formatted data from a Unicode string.
+ * This is identical to <TT>u_sscanf</TT>, except that it will
+ * <EM>not</EM> call <TT>va_start</TT> and <TT>va_end</TT>.
+ *
+ * @param buffer The Unicode string from which to read.
+ * @param patternSpecification A pattern specifying how <TT>u_sscanf</TT> will
+ * interpret the variable arguments received and parse the data.
+ * @param ap The argument list to use.
+ * @return The number of items successfully converted and assigned, or EOF
+ * if an error occurred.
+ * @see u_sscanf
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_vsscanf(const UChar  *buffer,
+        const char     *patternSpecification,
+        va_list        ap);
+
+/**
+ * Read formatted data from a Unicode string.
+ *
+ * @param buffer The Unicode string from which to read.
+ * @param patternSpecification A pattern specifying how <TT>u_sscanf</TT> will
+ * interpret the variable arguments received and parse the data.
+ * @return The number of items successfully converted and assigned, or EOF
+ * if an error occurred.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_sscanf_u(const UChar  *buffer,
+        const UChar     *patternSpecification,
+        ... );
+
+/**
+ * Read formatted data from a Unicode string.
+ * This is identical to <TT>u_sscanf_u</TT>, except that it will
+ * <EM>not</EM> call <TT>va_start</TT> and <TT>va_end</TT>.
+ *
+ * @param buffer The Unicode string from which to read.
+ * @param patternSpecification A pattern specifying how <TT>u_sscanf</TT> will
+ * interpret the variable arguments received and parse the data.
+ * @param ap The argument list to use.
+ * @return The number of items successfully converted and assigned, or EOF
+ * if an error occurred.
+ * @see u_sscanf_u
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_vsscanf_u(const UChar *buffer,
+        const UChar     *patternSpecification,
+        va_list         ap);
+
+#endif
+#endif
+
+
diff --git a/source/io/unicode/ustream.h b/source/io/unicode/ustream.h
new file mode 100644
index 0000000..43509ff
--- /dev/null
+++ b/source/io/unicode/ustream.h
@@ -0,0 +1,71 @@
+/*
+**********************************************************************
+*   Copyright (C) 2001-2010 International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*  FILE NAME : ustream.h
+*
+*   Modification History:
+*
+*   Date        Name        Description
+*   06/25/2001  grhoten     Move iostream from unistr.h
+******************************************************************************
+*/
+
+#ifndef USTREAM_H
+#define USTREAM_H
+
+#include "unicode/unistr.h"
+
+/**
+ * \file
+ * \brief C++ API: Unicode iostream like API
+ *
+ * At this time, this API is very limited. It contains
+ * operator<< and operator>> for UnicodeString manipulation with the
+ * C++ I/O stream API.
+ */
+
+#if U_IOSTREAM_SOURCE >= 199711
+#if (__GNUC__ == 2)
+#include <iostream>
+#else
+#include <istream>
+#include <ostream>
+#endif
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Write the contents of a UnicodeString to a C++ ostream. This functions writes
+ * the characters in a UnicodeString to an ostream. The UChars in the
+ * UnicodeString are converted to the char based ostream with the default
+ * converter.
+ * @stable 3.0
+ */
+U_IO_API std::ostream & U_EXPORT2 operator<<(std::ostream& stream, const UnicodeString& s);
+
+/**
+ * Write the contents from a C++ istream to a UnicodeString. The UChars in the
+ * UnicodeString are converted from the char based istream with the default
+ * converter.
+ * @stable 3.0
+ */
+U_IO_API std::istream & U_EXPORT2 operator>>(std::istream& stream, UnicodeString& s);
+U_NAMESPACE_END
+
+#elif U_IOSTREAM_SOURCE >= 198506
+/* <istream.h> and <ostream.h> don't exist. */
+#include <iostream.h>
+
+U_NAMESPACE_BEGIN
+U_IO_API ostream & U_EXPORT2 operator<<(ostream& stream, const UnicodeString& s);
+
+U_IO_API istream & U_EXPORT2 operator>>(istream& stream, UnicodeString& s);
+U_NAMESPACE_END
+
+#endif
+
+/* No operator for UChar because it can conflict with wchar_t  */
+
+#endif
diff --git a/source/io/uprintf.c b/source/io/uprintf.c
new file mode 100644
index 0000000..d95c02c
--- /dev/null
+++ b/source/io/uprintf.c
@@ -0,0 +1,163 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1998-2004, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File uprintf.c
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   11/19/98    stephen     Creation.
+*   03/12/99    stephen     Modified for new C API.
+*                           Added conversion from default codepage.
+*   08/07/2003  george      Reunify printf implementations
+******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ustdio.h"
+#include "unicode/ustring.h"
+#include "unicode/unum.h"
+#include "unicode/udat.h"
+#include "unicode/putil.h"
+
+#include "uprintf.h"
+#include "ufile.h"
+#include "locbund.h"
+
+#include "cmemory.h"
+
+static int32_t U_EXPORT2
+u_printf_write(void          *context,
+               const UChar   *str,
+               int32_t       count)
+{
+    return u_file_write(str, count, (UFILE *)context);
+}
+
+static int32_t
+u_printf_pad_and_justify(void                        *context,
+                         const u_printf_spec_info    *info,
+                         const UChar                 *result,
+                         int32_t                     resultLen)
+{
+    UFILE   *output = (UFILE *)context;
+    int32_t written, i;
+
+    /* pad and justify, if needed */
+    if(info->fWidth != -1 && resultLen < info->fWidth) {
+        /* left justify */
+        if(info->fLeft) {
+            written = u_file_write(result, resultLen, output);
+            for(i = 0; i < info->fWidth - resultLen; ++i) {
+                written += u_file_write(&info->fPadChar, 1, output);
+            }
+        }
+        /* right justify */
+        else {
+            written = 0;
+            for(i = 0; i < info->fWidth - resultLen; ++i) {
+                written += u_file_write(&info->fPadChar, 1, output);
+            }
+            written += u_file_write(result, resultLen, output);
+        }
+    }
+    /* just write the formatted output */
+    else {
+        written = u_file_write(result, resultLen, output);
+    }
+
+    return written;
+}
+
+U_CAPI int32_t U_EXPORT2 
+u_fprintf(    UFILE        *f,
+          const char    *patternSpecification,
+          ... )
+{
+    va_list ap;
+    int32_t count;
+
+    va_start(ap, patternSpecification);
+    count = u_vfprintf(f, patternSpecification, ap);
+    va_end(ap);
+
+    return count;
+}
+
+U_CAPI int32_t U_EXPORT2 
+u_fprintf_u(    UFILE        *f,
+            const UChar    *patternSpecification,
+            ... )
+{
+    va_list ap;
+    int32_t count;
+
+    va_start(ap, patternSpecification);
+    count = u_vfprintf_u(f, patternSpecification, ap);
+    va_end(ap);
+
+    return count;
+}
+
+U_CAPI int32_t  U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_vfprintf(    UFILE        *f,
+           const char    *patternSpecification,
+           va_list        ap)
+{
+    int32_t count;
+    UChar *pattern;
+    UChar buffer[UFMT_DEFAULT_BUFFER_SIZE];
+    int32_t size = (int32_t)strlen(patternSpecification) + 1;
+
+    /* convert from the default codepage to Unicode */
+    if (size >= MAX_UCHAR_BUFFER_SIZE(buffer)) {
+        pattern = (UChar *)uprv_malloc(size * sizeof(UChar));
+        if(pattern == 0) {
+            return 0;
+        }
+    }
+    else {
+        pattern = buffer;
+    }
+    u_charsToUChars(patternSpecification, pattern, size);
+
+    /* do the work */
+    count = u_vfprintf_u(f, pattern, ap);
+
+    /* clean up */
+    if (pattern != buffer) {
+        uprv_free(pattern);
+    }
+
+    return count;
+}
+
+static const u_printf_stream_handler g_stream_handler = {
+    u_printf_write,
+    u_printf_pad_and_justify
+};
+
+U_CAPI int32_t  U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_vfprintf_u(    UFILE        *f,
+             const UChar    *patternSpecification,
+             va_list        ap)
+{
+    int32_t          written = 0;   /* haven't written anything yet */
+
+    /* parse and print the whole format string */
+    u_printf_parse(&g_stream_handler, patternSpecification, f, NULL, &f->str.fBundle, &written, ap);
+
+    /* return # of UChars written */
+    return written;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
diff --git a/source/io/uprintf.h b/source/io/uprintf.h
new file mode 100644
index 0000000..4b53845
--- /dev/null
+++ b/source/io/uprintf.h
@@ -0,0 +1,101 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1998-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File uprintf.h
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   11/19/98    stephen        Creation.
+*   03/12/99    stephen     Modified for new C API.
+******************************************************************************
+*/
+
+#ifndef UPRINTF_H
+#define UPRINTF_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ustdio.h"
+#include "ufmt_cmn.h"
+#include "locbund.h"
+
+/**
+ * Struct encapsulating a single uprintf format specification.
+ */
+typedef struct u_printf_spec_info {
+  int32_t    fPrecision;    /* Precision  */
+  int32_t    fWidth;        /* Width  */
+
+  UChar     fOrigSpec;      /* Conversion specification */
+  UChar     fSpec;          /* Conversion specification */
+  UChar     fPadChar;       /* Padding character  */
+
+  UBool     fAlt;           /* # flag  */
+  UBool     fSpace;         /* Space flag  */
+  UBool     fLeft;          /* - flag  */
+  UBool     fShowSign;      /* + flag  */
+  UBool     fZero;          /* 0 flag  */
+
+  UBool     fIsLongDouble;  /* L flag  */
+  UBool     fIsShort;       /* h flag  */
+  UBool     fIsLong;        /* l flag  */
+  UBool     fIsLongLong;    /* ll flag  */
+} u_printf_spec_info;
+
+typedef int32_t U_EXPORT2
+u_printf_write_stream(void          *context,
+                      const UChar   *str,
+                      int32_t       count);
+
+typedef int32_t U_EXPORT2
+u_printf_pad_and_justify_stream(void                        *context,
+                                const u_printf_spec_info    *info,
+                                const UChar                 *result,
+                                int32_t                     resultLen);
+
+typedef struct u_printf_stream_handler {
+    u_printf_write_stream *write;
+    u_printf_pad_and_justify_stream *pad_and_justify;
+} u_printf_stream_handler;
+
+/* Used by sprintf */
+typedef struct u_localized_print_string {
+    UChar     *str;     /* Place to write the string */
+    int32_t   available;/* Number of codeunits available to write to */
+    int32_t   len;      /* Maximum number of code units that can be written to output */
+
+    ULocaleBundle  fBundle;     /* formatters */
+} u_localized_print_string;
+
+#define UP_PERCENT 0x0025
+
+/**
+ * Parse a single u_printf format string.
+ * @param fmt A pointer to a '%' character in a u_printf format specification.
+ * @param spec A pointer to a <TT>u_printf_spec</TT> to receive the parsed
+ * format specifier.
+ * @param locStringContext If present, will make sure that it will only write
+ *          to the buffer when space is available. It's done this way because
+ *          va_list sometimes can't be passed by pointer.
+ * @return The number of characters contained in this specifier.
+ */
+U_CFUNC int32_t
+u_printf_parse(const u_printf_stream_handler *streamHandler,
+               const UChar     *fmt,
+               void            *context,
+               u_localized_print_string *locStringContext,
+               ULocaleBundle   *formatBundle,
+               int32_t         *written,
+               va_list         ap);
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/source/io/uprntf_p.c b/source/io/uprntf_p.c
new file mode 100644
index 0000000..f303c0c
--- /dev/null
+++ b/source/io/uprntf_p.c
@@ -0,0 +1,1589 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1998-2008, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File uprntf_p.c
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   11/23/98    stephen     Creation.
+*   03/12/99    stephen     Modified for new C API.
+*   08/07/2003  george      Reunify printf implementations
+******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ustring.h"
+
+#include "uprintf.h"
+#include "ufmt_cmn.h"
+#include "cmemory.h"
+#include "putilimp.h"
+
+/* ANSI style formatting */
+/* Use US-ASCII characters only for formatting */
+
+/* % */
+#define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_printf_simple_percent_handler}
+/* s */
+#define UFMT_STRING         {ufmt_string, u_printf_string_handler}
+/* c */
+#define UFMT_CHAR           {ufmt_char, u_printf_char_handler}
+/* d, i */
+#define UFMT_INT            {ufmt_int, u_printf_integer_handler}
+/* u */
+#define UFMT_UINT           {ufmt_int, u_printf_uinteger_handler}
+/* o */
+#define UFMT_OCTAL          {ufmt_int, u_printf_octal_handler}
+/* x, X */
+#define UFMT_HEX            {ufmt_int, u_printf_hex_handler}
+/* f */
+#define UFMT_DOUBLE         {ufmt_double, u_printf_double_handler}
+/* e, E */
+#define UFMT_SCIENTIFIC     {ufmt_double, u_printf_scientific_handler}
+/* g, G */
+#define UFMT_SCIDBL         {ufmt_double, u_printf_scidbl_handler}
+/* n */
+#define UFMT_COUNT          {ufmt_count, u_printf_count_handler}
+
+/* non-ANSI extensions */
+/* Use US-ASCII characters only for formatting */
+
+/* p */
+#define UFMT_POINTER        {ufmt_pointer, u_printf_pointer_handler}
+/* V */
+#define UFMT_SPELLOUT       {ufmt_double, u_printf_spellout_handler}
+/* P */
+#define UFMT_PERCENT        {ufmt_double, u_printf_percent_handler}
+/* C  K is old format */
+#define UFMT_UCHAR          {ufmt_uchar, u_printf_uchar_handler}
+/* S  U is old format */
+#define UFMT_USTRING        {ufmt_ustring, u_printf_ustring_handler}
+
+
+#define UFMT_EMPTY {ufmt_empty, NULL}
+
+/**
+ * A u_printf handler function.  
+ * A u_printf handler is responsible for handling a single u_printf 
+ * format specification, for example 'd' or 's'.
+ * @param stream The UFILE to which to write output.
+ * @param info A pointer to a <TT>u_printf_spec_info</TT> struct containing
+ * information on the format specification.
+ * @param args A pointer to the argument data
+ * @return The number of Unicode characters written to <TT>stream</TT>.
+ */
+typedef int32_t U_EXPORT2
+u_printf_handler(const u_printf_stream_handler  *handler,
+
+                 void                           *context,
+                 ULocaleBundle                  *formatBundle,
+                 const u_printf_spec_info       *info,
+                 const ufmt_args                *args);
+
+typedef struct u_printf_info {
+    ufmt_type_info info;
+    u_printf_handler *handler;
+} u_printf_info;
+
+/**
+ * Struct encapsulating a single uprintf format specification.
+ */
+typedef struct u_printf_spec {
+  u_printf_spec_info    fInfo;        /* Information on this spec */
+  int32_t        fWidthPos;     /* Position of width in arg list */
+  int32_t        fPrecisionPos;    /* Position of precision in arg list */
+  int32_t        fArgPos;    /* Position of data in arg list */
+} u_printf_spec;
+
+#define UPRINTF_NUM_FMT_HANDLERS 108
+
+/* We do not use handlers for 0-0x1f */
+#define UPRINTF_BASE_FMT_HANDLERS 0x20
+
+/* buffer size for formatting */
+#define UPRINTF_BUFFER_SIZE 1024
+#define UPRINTF_SYMBOL_BUFFER_SIZE 8
+
+static const UChar gNullStr[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */
+static const UChar gSpaceStr[] = {0x20, 0}; /* " " */
+
+/* Sets the sign of a format based on u_printf_spec_info */
+/* TODO: Is setting the prefix symbol to a positive sign a good idea in all locales? */
+static void
+u_printf_set_sign(UNumberFormat        *format,
+                   const u_printf_spec_info     *info,
+                   UChar *prefixBuffer,
+                   int32_t *prefixBufLen,
+                   UErrorCode *status)
+{
+    if(info->fShowSign) {
+        *prefixBufLen = unum_getTextAttribute(format,
+                                              UNUM_POSITIVE_PREFIX,
+                                              prefixBuffer,
+                                              *prefixBufLen,
+                                              status);
+        if (info->fSpace) {
+            /* Setting UNUM_PLUS_SIGN_SYMBOL affects the exponent too. */
+            /* unum_setSymbol(format, UNUM_PLUS_SIGN_SYMBOL, gSpaceStr, 1, &status); */
+            unum_setTextAttribute(format, UNUM_POSITIVE_PREFIX, gSpaceStr, 1, status);
+        }
+        else {
+            UChar plusSymbol[UPRINTF_SYMBOL_BUFFER_SIZE];
+            int32_t symbolLen;
+
+            symbolLen = unum_getSymbol(format,
+                UNUM_PLUS_SIGN_SYMBOL,
+                plusSymbol,
+                sizeof(plusSymbol)/sizeof(*plusSymbol),
+                status);
+            unum_setTextAttribute(format,
+                UNUM_POSITIVE_PREFIX,
+                plusSymbol,
+                symbolLen,
+                status);
+        }
+    }
+    else {
+        *prefixBufLen = 0;
+    }
+}
+
+static void
+u_printf_reset_sign(UNumberFormat        *format,
+                   const u_printf_spec_info     *info,
+                   UChar *prefixBuffer,
+                   int32_t *prefixBufLen,
+                   UErrorCode *status)
+{
+    if(info->fShowSign) {
+        unum_setTextAttribute(format,
+                              UNUM_POSITIVE_PREFIX,
+                              prefixBuffer,
+                              *prefixBufLen,
+                              status);
+    }
+}
+
+
+/* handle a '%' */
+static int32_t
+u_printf_simple_percent_handler(const u_printf_stream_handler  *handler,
+                                void                           *context,
+                                ULocaleBundle                  *formatBundle,
+                                const u_printf_spec_info       *info,
+                                const ufmt_args                *args)
+{
+    static const UChar PERCENT[] = { UP_PERCENT };
+
+    /* put a single '%' onto the output */
+    return handler->write(context, PERCENT, 1);
+}
+
+/* handle 's' */
+static int32_t
+u_printf_string_handler(const u_printf_stream_handler  *handler,
+                        void                           *context,
+                        ULocaleBundle                  *formatBundle,
+                        const u_printf_spec_info       *info,
+                        const ufmt_args                *args)
+{
+    UChar *s;
+    UChar buffer[UFMT_DEFAULT_BUFFER_SIZE];
+    int32_t len, written;
+    int32_t argSize;
+    const char *arg = (const char*)(args[0].ptrValue);
+
+    /* convert from the default codepage to Unicode */
+    if (arg) {
+        argSize = (int32_t)strlen(arg) + 1;
+        if (argSize >= MAX_UCHAR_BUFFER_SIZE(buffer)) {
+            s = ufmt_defaultCPToUnicode(arg, argSize,
+                    (UChar *)uprv_malloc(MAX_UCHAR_BUFFER_NEEDED(argSize)),
+                    MAX_UCHAR_BUFFER_NEEDED(argSize));
+            if(s == NULL) {
+                return 0;
+            }
+        }
+        else {
+            s = ufmt_defaultCPToUnicode(arg, argSize, buffer,
+                    sizeof(buffer)/sizeof(UChar));
+        }
+    }
+    else {
+        s = (UChar *)gNullStr;
+    }
+    len = u_strlen(s);
+
+    /* width = minimum # of characters to write */
+    /* precision = maximum # of characters to write */
+    if (info->fPrecision != -1 && info->fPrecision < len) {
+        len = info->fPrecision;
+    }
+
+    written = handler->pad_and_justify(context, info, s, len);
+
+    /* clean up */
+    if (gNullStr != s && buffer != s) {
+        uprv_free(s);
+    }
+
+    return written;
+}
+
+static int32_t
+u_printf_char_handler(const u_printf_stream_handler  *handler,
+                      void                           *context,
+                      ULocaleBundle                  *formatBundle,
+                      const u_printf_spec_info       *info,
+                      const ufmt_args                *args)
+{
+    UChar s[UTF_MAX_CHAR_LENGTH+1];
+    int32_t len = 1, written;
+    unsigned char arg = (unsigned char)(args[0].int64Value);
+
+    /* convert from default codepage to Unicode */
+    ufmt_defaultCPToUnicode((const char *)&arg, 2, s, sizeof(s)/sizeof(UChar));
+
+    /* Remember that this may be an MBCS character */
+    if (arg != 0) {
+        len = u_strlen(s);
+    }
+
+    /* width = minimum # of characters to write */
+    /* precision = maximum # of characters to write */
+    /* precision is ignored when handling a char */
+
+    written = handler->pad_and_justify(context, info, s, len);
+
+    return written;
+}
+
+static int32_t
+u_printf_double_handler(const u_printf_stream_handler  *handler,
+                        void                           *context,
+                        ULocaleBundle                  *formatBundle,
+                        const u_printf_spec_info       *info,
+                        const ufmt_args                *args)
+{
+    double        num         = (double) (args[0].doubleValue);
+    UNumberFormat  *format;
+    UChar          result[UPRINTF_BUFFER_SIZE];
+    UChar          prefixBuffer[UPRINTF_BUFFER_SIZE];
+    int32_t        prefixBufferLen = sizeof(prefixBuffer);
+    int32_t        minDecimalDigits;
+    int32_t        maxDecimalDigits;
+    int32_t        resultLen;
+    UErrorCode     status        = U_ZERO_ERROR;
+
+    prefixBuffer[0] = 0;
+
+    /* mask off any necessary bits */
+    /*  if(! info->fIsLongDouble)
+    num &= DBL_MAX;*/
+
+    /* get the formatter */
+    format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
+
+    /* handle error */
+    if(format == 0)
+        return 0;
+
+    /* save the formatter's state */
+    minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
+    maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
+
+    /* set the appropriate flags and number of decimal digits on the formatter */
+    if(info->fPrecision != -1) {
+        /* set the # of decimal digits */
+        unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
+    }
+    else if(info->fAlt) {
+        /* '#' means always show decimal point */
+        /* copy of printf behavior on Solaris - '#' shows 6 digits */
+        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
+    }
+    else {
+        /* # of decimal digits is 6 if precision not specified regardless of locale */
+        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
+    }
+
+    /* set whether to show the sign */
+    if (info->fShowSign) {
+        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
+    }
+
+    /* format the number */
+    resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
+
+    if (U_FAILURE(status)) {
+        resultLen = 0;
+    }
+
+    /* restore the number format */
+    /* TODO: Is this needed? */
+    unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
+    unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
+
+    if (info->fShowSign) {
+        /* Reset back to original value regardless of what the error was */
+        UErrorCode localStatus = U_ZERO_ERROR;
+        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
+    }
+
+    return handler->pad_and_justify(context, info, result, resultLen);
+}
+
+/* HSYS */
+static int32_t
+u_printf_integer_handler(const u_printf_stream_handler  *handler,
+                         void                           *context,
+                         ULocaleBundle                  *formatBundle,
+                         const u_printf_spec_info       *info,
+                         const ufmt_args                *args)
+{
+    int64_t         num        = args[0].int64Value;
+    UNumberFormat   *format;
+    UChar           result[UPRINTF_BUFFER_SIZE];
+    UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
+    int32_t         prefixBufferLen = sizeof(prefixBuffer);
+    int32_t         minDigits     = -1;
+    int32_t         resultLen;
+    UErrorCode      status        = U_ZERO_ERROR;
+
+    prefixBuffer[0] = 0;
+
+    /* mask off any necessary bits */
+    if (info->fIsShort)
+        num = (int16_t)num;
+    else if (!info->fIsLongLong)
+        num = (int32_t)num;
+
+    /* get the formatter */
+    format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
+
+    /* handle error */
+    if(format == 0)
+        return 0;
+
+    /* set the appropriate flags on the formatter */
+
+    /* set the minimum integer digits */
+    if(info->fPrecision != -1) {
+        /* set the minimum # of digits */
+        minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
+        unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
+    }
+
+    /* set whether to show the sign */
+    if(info->fShowSign) {
+        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
+    }
+
+    /* format the number */
+    resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
+
+    if (U_FAILURE(status)) {
+        resultLen = 0;
+    }
+
+    /* restore the number format */
+    if (minDigits != -1) {
+        unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
+    }
+
+    if (info->fShowSign) {
+        /* Reset back to original value regardless of what the error was */
+        UErrorCode localStatus = U_ZERO_ERROR;
+        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
+    }
+
+    return handler->pad_and_justify(context, info, result, resultLen);
+}
+
+static int32_t
+u_printf_hex_handler(const u_printf_stream_handler  *handler,
+                     void                           *context,
+                     ULocaleBundle                  *formatBundle,
+                     const u_printf_spec_info       *info,
+                     const ufmt_args                *args)
+{
+    int64_t         num        = args[0].int64Value;
+    UChar           result[UPRINTF_BUFFER_SIZE];
+    int32_t         len        = UPRINTF_BUFFER_SIZE;
+
+
+    /* mask off any necessary bits */
+    if (info->fIsShort)
+        num &= UINT16_MAX;
+    else if (!info->fIsLongLong)
+        num &= UINT32_MAX;
+
+    /* format the number, preserving the minimum # of digits */
+    ufmt_64tou(result, &len, num, 16,
+        (UBool)(info->fSpec == 0x0078),
+        (info->fPrecision == -1 && info->fZero) ? info->fWidth : info->fPrecision);
+
+    /* convert to alt form, if desired */
+    if(num != 0 && info->fAlt && len < UPRINTF_BUFFER_SIZE - 2) {
+        /* shift the formatted string right by 2 chars */
+        memmove(result + 2, result, len * sizeof(UChar));
+        result[0] = 0x0030;
+        result[1] = info->fSpec;
+        len += 2;
+    }
+
+    return handler->pad_and_justify(context, info, result, len);
+}
+
+static int32_t
+u_printf_octal_handler(const u_printf_stream_handler  *handler,
+                       void                           *context,
+                       ULocaleBundle                  *formatBundle,
+                       const u_printf_spec_info       *info,
+                       const ufmt_args                *args)
+{
+    int64_t         num        = args[0].int64Value;
+    UChar           result[UPRINTF_BUFFER_SIZE];
+    int32_t         len        = UPRINTF_BUFFER_SIZE;
+
+
+    /* mask off any necessary bits */
+    if (info->fIsShort)
+        num &= UINT16_MAX;
+    else if (!info->fIsLongLong)
+        num &= UINT32_MAX;
+
+    /* format the number, preserving the minimum # of digits */
+    ufmt_64tou(result, &len, num, 8,
+        FALSE, /* doesn't matter for octal */
+        info->fPrecision == -1 && info->fZero ? info->fWidth : info->fPrecision);
+
+    /* convert to alt form, if desired */
+    if(info->fAlt && result[0] != 0x0030 && len < UPRINTF_BUFFER_SIZE - 1) {
+        /* shift the formatted string right by 1 char */
+        memmove(result + 1, result, len * sizeof(UChar));
+        result[0] = 0x0030;
+        len += 1;
+    }
+
+    return handler->pad_and_justify(context, info, result, len);
+}
+
+static int32_t
+u_printf_uinteger_handler(const u_printf_stream_handler *handler,
+                          void                          *context,
+                          ULocaleBundle                 *formatBundle,
+                          const u_printf_spec_info      *info,
+                          const ufmt_args               *args)
+{
+    int64_t         num        = args[0].int64Value;
+    UNumberFormat   *format;
+    UChar           result[UPRINTF_BUFFER_SIZE];
+    int32_t         minDigits     = -1;
+    int32_t         resultLen;
+    UErrorCode      status        = U_ZERO_ERROR;
+
+    /* TODO: Fix this once uint64_t can be formatted. */
+    if (info->fIsShort)
+        num &= UINT16_MAX;
+    else if (!info->fIsLongLong)
+        num &= UINT32_MAX;
+
+    /* get the formatter */
+    format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
+
+    /* handle error */
+    if(format == 0)
+        return 0;
+
+    /* set the appropriate flags on the formatter */
+
+    /* set the minimum integer digits */
+    if(info->fPrecision != -1) {
+        /* set the minimum # of digits */
+        minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
+        unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
+    }
+
+    /* To mirror other stdio implementations, we ignore the sign argument */
+
+    /* format the number */
+    resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
+
+    if (U_FAILURE(status)) {
+        resultLen = 0;
+    }
+
+    /* restore the number format */
+    if (minDigits != -1) {
+        unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
+    }
+
+    return handler->pad_and_justify(context, info, result, resultLen);
+}
+
+static int32_t
+u_printf_pointer_handler(const u_printf_stream_handler  *handler,
+                         void                           *context,
+                         ULocaleBundle                  *formatBundle,
+                         const u_printf_spec_info       *info,
+                         const ufmt_args                *args)
+{
+    UChar           result[UPRINTF_BUFFER_SIZE];
+    int32_t         len  = UPRINTF_BUFFER_SIZE;
+
+    /* format the pointer in hex */
+    ufmt_ptou(result, &len, args[0].ptrValue, TRUE/*, info->fPrecision*/);
+
+    return handler->pad_and_justify(context, info, result, len);
+}
+
+static int32_t
+u_printf_scientific_handler(const u_printf_stream_handler  *handler,
+                            void                           *context,
+                            ULocaleBundle                  *formatBundle,
+                            const u_printf_spec_info       *info,
+                            const ufmt_args                *args)
+{
+    double          num         = (double) (args[0].doubleValue);
+    UNumberFormat   *format;
+    UChar           result[UPRINTF_BUFFER_SIZE];
+    UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
+    int32_t         prefixBufferLen = sizeof(prefixBuffer);
+    int32_t         minDecimalDigits;
+    int32_t         maxDecimalDigits;
+    UErrorCode      status        = U_ZERO_ERROR;
+    UChar srcExpBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
+    int32_t srcLen, expLen;
+    int32_t resultLen;
+    UChar expBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
+
+    prefixBuffer[0] = 0;
+
+    /* mask off any necessary bits */
+    /*  if(! info->fIsLongDouble)
+    num &= DBL_MAX;*/
+
+    /* get the formatter */
+    format = u_locbund_getNumberFormat(formatBundle, UNUM_SCIENTIFIC);
+
+    /* handle error */
+    if(format == 0)
+        return 0;
+
+    /* set the appropriate flags on the formatter */
+
+    srcLen = unum_getSymbol(format,
+        UNUM_EXPONENTIAL_SYMBOL,
+        srcExpBuf,
+        sizeof(srcExpBuf),
+        &status);
+
+    /* Upper/lower case the e */
+    if (info->fSpec == (UChar)0x65 /* e */) {
+        expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf),
+            srcExpBuf, srcLen,
+            formatBundle->fLocale,
+            &status);
+    }
+    else {
+        expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf),
+            srcExpBuf, srcLen,
+            formatBundle->fLocale,
+            &status);
+    }
+
+    unum_setSymbol(format,
+        UNUM_EXPONENTIAL_SYMBOL,
+        expBuf,
+        expLen,
+        &status);
+
+    /* save the formatter's state */
+    minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
+    maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
+
+    /* set the appropriate flags and number of decimal digits on the formatter */
+    if(info->fPrecision != -1) {
+        /* set the # of decimal digits */
+        if (info->fOrigSpec == (UChar)0x65 /* e */ || info->fOrigSpec == (UChar)0x45 /* E */) {
+            unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
+        }
+        else {
+            unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, 1);
+            unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, info->fPrecision);
+        }
+    }
+    else if(info->fAlt) {
+        /* '#' means always show decimal point */
+        /* copy of printf behavior on Solaris - '#' shows 6 digits */
+        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
+    }
+    else {
+        /* # of decimal digits is 6 if precision not specified */
+        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
+    }
+
+    /* set whether to show the sign */
+    if (info->fShowSign) {
+        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
+    }
+
+    /* format the number */
+    resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
+
+    if (U_FAILURE(status)) {
+        resultLen = 0;
+    }
+
+    /* restore the number format */
+    /* TODO: Is this needed? */
+    unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
+    unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
+
+    /* Since we're the only one using the scientific
+       format, we don't need to save the old exponent value. */
+    /*unum_setSymbol(format,
+        UNUM_EXPONENTIAL_SYMBOL,
+        srcExpBuf,
+        srcLen,
+        &status);*/
+
+    if (info->fShowSign) {
+        /* Reset back to original value regardless of what the error was */
+        UErrorCode localStatus = U_ZERO_ERROR;
+        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
+    }
+
+    return handler->pad_and_justify(context, info, result, resultLen);
+}
+
+static int32_t
+u_printf_percent_handler(const u_printf_stream_handler  *handler,
+                         void                           *context,
+                         ULocaleBundle                  *formatBundle,
+                         const u_printf_spec_info       *info,
+                         const ufmt_args                *args)
+{
+    double          num         = (double) (args[0].doubleValue);
+    UNumberFormat   *format;
+    UChar           result[UPRINTF_BUFFER_SIZE];
+    UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
+    int32_t         prefixBufferLen = sizeof(prefixBuffer);
+    int32_t         minDecimalDigits;
+    int32_t         maxDecimalDigits;
+    int32_t         resultLen;
+    UErrorCode      status        = U_ZERO_ERROR;
+
+    prefixBuffer[0] = 0;
+
+    /* mask off any necessary bits */
+    /*  if(! info->fIsLongDouble)
+    num &= DBL_MAX;*/
+
+    /* get the formatter */
+    format = u_locbund_getNumberFormat(formatBundle, UNUM_PERCENT);
+
+    /* handle error */
+    if(format == 0)
+        return 0;
+
+    /* save the formatter's state */
+    minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
+    maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
+
+    /* set the appropriate flags and number of decimal digits on the formatter */
+    if(info->fPrecision != -1) {
+        /* set the # of decimal digits */
+        unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
+    }
+    else if(info->fAlt) {
+        /* '#' means always show decimal point */
+        /* copy of printf behavior on Solaris - '#' shows 6 digits */
+        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
+    }
+    else {
+        /* # of decimal digits is 6 if precision not specified */
+        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
+    }
+
+    /* set whether to show the sign */
+    if (info->fShowSign) {
+        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
+    }
+
+    /* format the number */
+    resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
+
+    if (U_FAILURE(status)) {
+        resultLen = 0;
+    }
+
+    /* restore the number format */
+    /* TODO: Is this needed? */
+    unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
+    unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
+
+    if (info->fShowSign) {
+        /* Reset back to original value regardless of what the error was */
+        UErrorCode localStatus = U_ZERO_ERROR;
+        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
+    }
+
+    return handler->pad_and_justify(context, info, result, resultLen);
+}
+
+static int32_t
+u_printf_ustring_handler(const u_printf_stream_handler  *handler,
+                         void                           *context,
+                         ULocaleBundle                  *formatBundle,
+                         const u_printf_spec_info       *info,
+                         const ufmt_args                *args)
+{
+    int32_t len, written;
+    const UChar *arg = (const UChar*)(args[0].ptrValue);
+
+    /* allocate enough space for the buffer */
+    if (arg == NULL) {
+        arg = gNullStr;
+    }
+    len = u_strlen(arg);
+
+    /* width = minimum # of characters to write */
+    /* precision = maximum # of characters to write */
+    if (info->fPrecision != -1 && info->fPrecision < len) {
+        len = info->fPrecision;
+    }
+
+    /* determine if the string should be padded */
+    written = handler->pad_and_justify(context, info, arg, len);
+
+    return written;
+}
+
+static int32_t
+u_printf_uchar_handler(const u_printf_stream_handler  *handler,
+                       void                           *context,
+                       ULocaleBundle                  *formatBundle,
+                       const u_printf_spec_info       *info,
+                       const ufmt_args                *args)
+{
+    int32_t written = 0;
+    UChar arg = (UChar)(args[0].int64Value);
+
+    /* width = minimum # of characters to write */
+    /* precision = maximum # of characters to write */
+    /* precision is ignored when handling a uchar */
+
+    /* determine if the string should be padded */
+    written = handler->pad_and_justify(context, info, &arg, 1);
+
+    return written;
+}
+
+static int32_t
+u_printf_scidbl_handler(const u_printf_stream_handler  *handler,
+                        void                           *context,
+                        ULocaleBundle                  *formatBundle,
+                        const u_printf_spec_info       *info,
+                        const ufmt_args                *args)
+{
+    u_printf_spec_info scidbl_info;
+    double      num = args[0].doubleValue;
+    int32_t     retVal;
+    UNumberFormat *format;
+    int32_t maxSigDecimalDigits, significantDigits;
+
+    memcpy(&scidbl_info, info, sizeof(u_printf_spec_info));
+
+    /* determine whether to use 'd', 'e' or 'f' notation */
+    if (scidbl_info.fPrecision == -1 && num == uprv_trunc(num))
+    {
+        /* use 'f' notation */
+        scidbl_info.fSpec = 0x0066;
+        scidbl_info.fPrecision = 0;
+        /* call the double handler */
+        retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args);
+    }
+    else if(num < 0.0001 || (scidbl_info.fPrecision < 1 && 1000000.0 <= num)
+        || (scidbl_info.fPrecision != -1 && num > uprv_pow10(scidbl_info.fPrecision)))
+    {
+        /* use 'e' or 'E' notation */
+        scidbl_info.fSpec = scidbl_info.fSpec - 2;
+        if (scidbl_info.fPrecision == -1) {
+            scidbl_info.fPrecision = 5;
+        }
+        /* call the scientific handler */
+        retVal = u_printf_scientific_handler(handler, context, formatBundle, &scidbl_info, args);
+    }
+    else {
+        format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
+        /* Check for null pointer */
+        if (format == NULL) {
+            return 0;
+        }
+        maxSigDecimalDigits = unum_getAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS);
+        significantDigits = scidbl_info.fPrecision;
+
+        /* use 'f' notation */
+        scidbl_info.fSpec = 0x0066;
+        if (significantDigits == -1) {
+            significantDigits = 6;
+        }
+        unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, TRUE);
+        unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, significantDigits);
+        /* call the double handler */
+        retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args);
+        unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, maxSigDecimalDigits);
+        unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, FALSE);
+    }
+    return retVal;
+}
+
+static int32_t
+u_printf_count_handler(const u_printf_stream_handler  *handler,
+                       void                           *context,
+                       ULocaleBundle                  *formatBundle,
+                       const u_printf_spec_info       *info,
+                       const ufmt_args                *args)
+{
+    int32_t *count = (int32_t*)(args[0].ptrValue);
+
+    /* in the special case of count, the u_printf_spec_info's width */
+    /* will contain the # of chars written thus far */
+    *count = info->fWidth;
+
+    return 0;
+}
+
+static int32_t
+u_printf_spellout_handler(const u_printf_stream_handler *handler,
+                          void                          *context,
+                          ULocaleBundle                 *formatBundle,
+                          const u_printf_spec_info      *info,
+                          const ufmt_args               *args)
+{
+    double          num         = (double) (args[0].doubleValue);
+    UNumberFormat   *format;
+    UChar           result[UPRINTF_BUFFER_SIZE];
+    UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
+    int32_t         prefixBufferLen = sizeof(prefixBuffer);
+    int32_t         minDecimalDigits;
+    int32_t         maxDecimalDigits;
+    int32_t         resultLen;
+    UErrorCode      status        = U_ZERO_ERROR;
+
+    prefixBuffer[0] = 0;
+
+    /* mask off any necessary bits */
+    /*  if(! info->fIsLongDouble)
+    num &= DBL_MAX;*/
+
+    /* get the formatter */
+    format = u_locbund_getNumberFormat(formatBundle, UNUM_SPELLOUT);
+
+    /* handle error */
+    if(format == 0)
+        return 0;
+
+    /* save the formatter's state */
+    minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
+    maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
+
+    /* set the appropriate flags and number of decimal digits on the formatter */
+    if(info->fPrecision != -1) {
+        /* set the # of decimal digits */
+        unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
+    }
+    else if(info->fAlt) {
+        /* '#' means always show decimal point */
+        /* copy of printf behavior on Solaris - '#' shows 6 digits */
+        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
+    }
+    else {
+        /* # of decimal digits is 6 if precision not specified */
+        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
+    }
+
+    /* set whether to show the sign */
+    if (info->fShowSign) {
+        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
+    }
+
+    /* format the number */
+    resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
+
+    if (U_FAILURE(status)) {
+        resultLen = 0;
+    }
+
+    /* restore the number format */
+    /* TODO: Is this needed? */
+    unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
+    unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
+
+    if (info->fShowSign) {
+        /* Reset back to original value regardless of what the error was */
+        UErrorCode localStatus = U_ZERO_ERROR;
+        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
+    }
+
+    return handler->pad_and_justify(context, info, result, resultLen);
+}
+
+/* Use US-ASCII characters only for formatting. Most codepages have
+ characters 20-7F from Unicode. Using any other codepage specific
+ characters will make it very difficult to format the string on
+ non-Unicode machines */
+static const u_printf_info g_u_printf_infos[UPRINTF_NUM_FMT_HANDLERS] = {
+/* 0x20 */
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_EMPTY,         UFMT_SIMPLE_PERCENT,UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+
+/* 0x30 */
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+
+/* 0x40 */
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_UCHAR,
+    UFMT_EMPTY,         UFMT_SCIENTIFIC,    UFMT_EMPTY,         UFMT_SCIDBL,
+#ifdef U_USE_OBSOLETE_IO_FORMATTING
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_UCHAR/*deprecated*/,
+#else
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+#endif
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+
+/* 0x50 */
+    UFMT_PERCENT,       UFMT_EMPTY,         UFMT_EMPTY,         UFMT_USTRING,
+#ifdef U_USE_OBSOLETE_IO_FORMATTING
+    UFMT_EMPTY,         UFMT_USTRING/*deprecated*/,UFMT_SPELLOUT,      UFMT_EMPTY,
+#else
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_SPELLOUT,      UFMT_EMPTY,
+#endif
+    UFMT_HEX,           UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+
+/* 0x60 */
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_CHAR,
+    UFMT_INT,           UFMT_SCIENTIFIC,    UFMT_DOUBLE,        UFMT_SCIDBL,
+    UFMT_EMPTY,         UFMT_INT,           UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_COUNT,         UFMT_OCTAL,
+
+/* 0x70 */
+    UFMT_POINTER,       UFMT_EMPTY,         UFMT_EMPTY,         UFMT_STRING,
+    UFMT_EMPTY,         UFMT_UINT,          UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_HEX,           UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+};
+
+/* flag characters for uprintf */
+#define FLAG_MINUS 0x002D
+#define FLAG_PLUS 0x002B
+#define FLAG_SPACE 0x0020
+#define FLAG_POUND 0x0023
+#define FLAG_ZERO  0x0030
+#define FLAG_PAREN 0x0028
+
+#define ISFLAG(s)    (s) == FLAG_MINUS || \
+            (s) == FLAG_PLUS || \
+            (s) == FLAG_SPACE || \
+            (s) == FLAG_POUND || \
+            (s) == FLAG_ZERO || \
+            (s) == FLAG_PAREN
+
+/* special characters for uprintf */
+#define SPEC_ASTERISK 0x002A
+#define SPEC_DOLLARSIGN 0x0024
+#define SPEC_PERIOD 0x002E
+#define SPEC_PERCENT 0x0025
+
+/* unicode digits */
+#define DIGIT_ZERO 0x0030
+#define DIGIT_ONE 0x0031
+#define DIGIT_TWO 0x0032
+#define DIGIT_THREE 0x0033
+#define DIGIT_FOUR 0x0034
+#define DIGIT_FIVE 0x0035
+#define DIGIT_SIX 0x0036
+#define DIGIT_SEVEN 0x0037
+#define DIGIT_EIGHT 0x0038
+#define DIGIT_NINE 0x0039
+
+#define ISDIGIT(s)    (s) == DIGIT_ZERO || \
+            (s) == DIGIT_ONE || \
+            (s) == DIGIT_TWO || \
+            (s) == DIGIT_THREE || \
+            (s) == DIGIT_FOUR || \
+            (s) == DIGIT_FIVE || \
+            (s) == DIGIT_SIX || \
+            (s) == DIGIT_SEVEN || \
+            (s) == DIGIT_EIGHT || \
+            (s) == DIGIT_NINE
+
+/* u_printf modifiers */
+#define MOD_H 0x0068
+#define MOD_LOWERL 0x006C
+#define MOD_L 0x004C
+
+#define ISMOD(s)    (s) == MOD_H || \
+            (s) == MOD_LOWERL || \
+            (s) == MOD_L
+/* Returns an array of the parsed argument type given in the format string. */
+static ufmt_args* parseArguments(const UChar *alias, va_list ap, UErrorCode *status) {
+    ufmt_args *arglist = NULL;
+    ufmt_type_info *typelist = NULL;
+    UBool *islonglong = NULL;
+    int32_t size = 0;
+    int32_t pos = 0;
+    UChar type;
+    uint16_t handlerNum;
+    const UChar *aliasStart = alias;
+
+    /* get maximum number of arguments */
+    for(;;) {
+        /* find % */
+        while(*alias != UP_PERCENT && *alias != 0x0000) {
+            alias++;
+        }
+
+        if(*alias == 0x0000) {
+            break;
+        }
+
+        alias++;
+
+        /* handle the pos number */
+        if(ISDIGIT(*alias)) {
+
+            /* handle positional parameters */
+            if(ISDIGIT(*alias)) {
+                pos = (int) (*alias++ - DIGIT_ZERO);
+
+                while(ISDIGIT(*alias)) {
+                    pos *= 10;
+                    pos += (int) (*alias++ - DIGIT_ZERO);
+                }
+            }
+
+            /* if there is no '$', don't read anything */
+            if(*alias != SPEC_DOLLARSIGN) {
+                return NULL;
+            }
+        } else {
+            return NULL;
+        }
+
+        if (pos > size) {
+            size = pos;
+        }
+    }
+
+    /* create the parsed argument list */
+    typelist = (ufmt_type_info*)uprv_malloc(sizeof(ufmt_type_info) * size);
+    islonglong = (UBool*)uprv_malloc(sizeof(UBool) * size);
+    arglist = (ufmt_args*)uprv_malloc(sizeof(ufmt_args) * size);
+
+    /* If malloc failed, return NULL */
+    if (!typelist || !islonglong || !arglist) {
+        if (typelist) {
+            uprv_free(typelist);
+        }
+
+        if (islonglong) {
+            uprv_free(islonglong);
+        }
+
+        if (arglist) {
+            uprv_free(arglist);
+        }
+
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+
+    /* reset alias back to the beginning */
+    alias = aliasStart;
+
+    for(;;) {
+        /* find % */
+        while(*alias != UP_PERCENT && *alias != 0x0000) {
+            alias++;
+        }
+
+        if(*alias == 0x0000) {
+            break;
+        }
+
+        alias++;
+
+        /* handle positional parameters */
+        if(ISDIGIT(*alias)) {
+            pos = (int) (*alias++ - DIGIT_ZERO);
+
+            while(ISDIGIT(*alias)) {
+                pos *= 10;
+                pos += (int) (*alias++ - DIGIT_ZERO);
+            }
+        }
+        /* offset position by 1 */
+        pos--;
+
+        /* skip over everything except for the type */
+        while (ISMOD(*alias) || ISFLAG(*alias) || ISDIGIT(*alias) || 
+            *alias == SPEC_ASTERISK || *alias == SPEC_PERIOD || *alias == SPEC_DOLLARSIGN) {
+                islonglong[pos] = FALSE;
+                if (ISMOD(*alias)) {
+                    alias++;
+                    if (*alias == MOD_LOWERL) {
+                        islonglong[pos] = TRUE;
+                    } 
+                } 
+                alias++;
+        }
+        type = *alias;
+
+        /* store the argument type in the correct position of the parsed argument list */
+        handlerNum = (uint16_t)(type - UPRINTF_BASE_FMT_HANDLERS);
+        if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) {
+            typelist[pos] = g_u_printf_infos[ handlerNum ].info;
+        } else {
+            typelist[pos] = ufmt_empty;
+        }
+    }
+
+    /* store argument in arglist */
+    for (pos = 0; pos < size; pos++) {
+        switch (typelist[pos]) {
+        case ufmt_string:
+        case ufmt_ustring:
+        case ufmt_pointer:
+            arglist[pos].ptrValue = va_arg(ap, void*);
+            break;
+        case ufmt_char:
+        case ufmt_uchar:
+        case ufmt_int:
+            if (islonglong[pos]) {
+                arglist[pos].int64Value = va_arg(ap, int64_t);
+            }
+            else {
+                arglist[pos].int64Value = va_arg(ap, int32_t);
+            }
+            break;
+        case ufmt_float:
+            arglist[pos].floatValue = (float) va_arg(ap, double);
+            break;
+        case ufmt_double:
+            arglist[pos].doubleValue = va_arg(ap, double);
+            break;
+        default:
+            /* else args is ignored */
+            arglist[pos].ptrValue = NULL;
+            break;
+        }
+    }
+
+    uprv_free(typelist);
+    uprv_free(islonglong);
+
+    return arglist;
+}
+
+/* We parse the argument list in Unicode */
+U_CFUNC int32_t
+u_printf_parse(const u_printf_stream_handler *streamHandler,
+               const UChar     *fmt,
+               void            *context,
+               u_localized_print_string *locStringContext,
+               ULocaleBundle   *formatBundle,
+               int32_t         *written,
+               va_list         ap)
+{
+    uint16_t         handlerNum;
+    ufmt_args        args;
+    ufmt_type_info   argType;
+    u_printf_handler *handler;
+    u_printf_spec    spec;
+    u_printf_spec_info *info = &(spec.fInfo);
+
+    const UChar *alias = fmt;
+    const UChar *backup;
+    const UChar *lastAlias;
+    const UChar *orgAlias = fmt;
+    /* parsed argument list */
+    ufmt_args *arglist = NULL; /* initialized it to avoid compiler warnings */
+    UErrorCode status = U_ZERO_ERROR;
+    if (!locStringContext || locStringContext->available >= 0) {
+        /* get the parsed list of argument types */
+        arglist = parseArguments(orgAlias, ap, &status);
+
+        /* Return error if parsing failed. */
+        if (U_FAILURE(status)) {
+            return -1;
+        }
+    }
+    
+    /* iterate through the pattern */
+    while(!locStringContext || locStringContext->available >= 0) {
+
+        /* find the next '%' */
+        lastAlias = alias;
+        while(*alias != UP_PERCENT && *alias != 0x0000) {
+            alias++;
+        }
+
+        /* write any characters before the '%' */
+        if(alias > lastAlias) {
+            *written += (streamHandler->write)(context, lastAlias, (int32_t)(alias - lastAlias));
+        }
+
+        /* break if at end of string */
+        if(*alias == 0x0000) {
+            break;
+        }
+
+        /* initialize spec to default values */
+        spec.fWidthPos     = -1;
+        spec.fPrecisionPos = -1;
+        spec.fArgPos       = -1;
+
+        uprv_memset(info, 0, sizeof(*info));
+        info->fPrecision    = -1;
+        info->fWidth        = -1;
+        info->fPadChar      = 0x0020;
+
+        /* skip over the initial '%' */
+        alias++;
+
+        /* Check for positional argument */
+        if(ISDIGIT(*alias)) {
+
+            /* Save the current position */
+            backup = alias;
+
+            /* handle positional parameters */
+            if(ISDIGIT(*alias)) {
+                spec.fArgPos = (int) (*alias++ - DIGIT_ZERO);
+
+                while(ISDIGIT(*alias)) {
+                    spec.fArgPos *= 10;
+                    spec.fArgPos += (int) (*alias++ - DIGIT_ZERO);
+                }
+            }
+
+            /* if there is no '$', don't read anything */
+            if(*alias != SPEC_DOLLARSIGN) {
+                spec.fArgPos = -1;
+                alias = backup;
+            }
+            /* munge the '$' */
+            else
+                alias++;
+        }
+
+        /* Get any format flags */
+        while(ISFLAG(*alias)) {
+            switch(*alias++) {
+
+                /* left justify */
+            case FLAG_MINUS:
+                info->fLeft = TRUE;
+                break;
+
+                /* always show sign */
+            case FLAG_PLUS:
+                info->fShowSign = TRUE;
+                break;
+
+                /* use space if no sign present */
+            case FLAG_SPACE:
+                info->fShowSign = TRUE;
+                info->fSpace = TRUE;
+                break;
+
+                /* use alternate form */
+            case FLAG_POUND:
+                info->fAlt = TRUE;
+                break;
+
+                /* pad with leading zeroes */
+            case FLAG_ZERO:
+                info->fZero = TRUE;
+                info->fPadChar = 0x0030;
+                break;
+
+                /* pad character specified */
+            case FLAG_PAREN:
+
+                /* TODO test that all four are numbers */
+                /* first four characters are hex values for pad char */
+                info->fPadChar = (UChar)ufmt_digitvalue(*alias++);
+                info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
+                info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
+                info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
+
+                /* final character is ignored */
+                alias++;
+
+                break;
+            }
+        }
+
+        /* Get the width */
+
+        /* width is specified out of line */
+        if(*alias == SPEC_ASTERISK) {
+
+            info->fWidth = -2;
+
+            /* Skip the '*' */
+            alias++;
+
+            /* Save the current position */
+            backup = alias;
+
+            /* handle positional parameters */
+            if(ISDIGIT(*alias)) {
+                spec.fWidthPos = (int) (*alias++ - DIGIT_ZERO);
+
+                while(ISDIGIT(*alias)) {
+                    spec.fWidthPos *= 10;
+                    spec.fWidthPos += (int) (*alias++ - DIGIT_ZERO);
+                }
+            }
+
+            /* if there is no '$', don't read anything */
+            if(*alias != SPEC_DOLLARSIGN) {
+                spec.fWidthPos = -1;
+                alias = backup;
+            }
+            /* munge the '$' */
+            else
+                alias++;
+        }
+        /* read the width, if present */
+        else if(ISDIGIT(*alias)){
+            info->fWidth = (int) (*alias++ - DIGIT_ZERO);
+
+            while(ISDIGIT(*alias)) {
+                info->fWidth *= 10;
+                info->fWidth += (int) (*alias++ - DIGIT_ZERO);
+            }
+        }
+
+        /* Get the precision */
+
+        if(*alias == SPEC_PERIOD) {
+
+            /* eat up the '.' */
+            alias++;
+
+            /* precision is specified out of line */
+            if(*alias == SPEC_ASTERISK) {
+
+                info->fPrecision = -2;
+
+                /* Skip the '*' */
+                alias++;
+
+                /* save the current position */
+                backup = alias;
+
+                /* handle positional parameters */
+                if(ISDIGIT(*alias)) {
+                    spec.fPrecisionPos = (int) (*alias++ - DIGIT_ZERO);
+
+                    while(ISDIGIT(*alias)) {
+                        spec.fPrecisionPos *= 10;
+                        spec.fPrecisionPos += (int) (*alias++ - DIGIT_ZERO);
+                    }
+
+                    /* if there is no '$', don't read anything */
+                    if(*alias != SPEC_DOLLARSIGN) {
+                        spec.fPrecisionPos = -1;
+                        alias = backup;
+                    }
+                    else {
+                        /* munge the '$' */
+                        alias++;
+                    }
+                }
+            }
+            /* read the precision */
+            else if(ISDIGIT(*alias)){
+                info->fPrecision = (int) (*alias++ - DIGIT_ZERO);
+
+                while(ISDIGIT(*alias)) {
+                    info->fPrecision *= 10;
+                    info->fPrecision += (int) (*alias++ - DIGIT_ZERO);
+                }
+            }
+        }
+
+        /* Get any modifiers */
+        if(ISMOD(*alias)) {
+            switch(*alias++) {
+
+                /* short */
+            case MOD_H:
+                info->fIsShort = TRUE;
+                break;
+
+                /* long or long long */
+            case MOD_LOWERL:
+                if(*alias == MOD_LOWERL) {
+                    info->fIsLongLong = TRUE;
+                    /* skip over the next 'l' */
+                    alias++;
+                }
+                else
+                    info->fIsLong = TRUE;
+                break;
+
+                /* long double */
+            case MOD_L:
+                info->fIsLongDouble = TRUE;
+                break;
+            }
+        }
+
+        /* finally, get the specifier letter */
+        info->fSpec = *alias++;
+        info->fOrigSpec = info->fSpec;
+
+        /* fill in the precision and width, if specified out of line */
+
+        /* width specified out of line */
+        if(spec.fInfo.fWidth == -2) {
+            if(spec.fWidthPos == -1) {
+                /* read the width from the argument list */
+                info->fWidth = va_arg(ap, int32_t);
+            }
+            /* else handle positional parameter */
+
+            /* if it's negative, take the absolute value and set left alignment */
+            if(info->fWidth < 0) {
+                info->fWidth *= -1; /* Make positive */
+                info->fLeft = TRUE;
+            }
+        }
+
+        /* precision specified out of line */
+        if(info->fPrecision == -2) {
+            if(spec.fPrecisionPos == -1) {
+                /* read the precision from the argument list */
+                info->fPrecision = va_arg(ap, int32_t);
+            }
+            /* else handle positional parameter */
+
+            /* if it's negative, set it to zero */
+            if(info->fPrecision < 0)
+                info->fPrecision = 0;
+        }
+
+        handlerNum = (uint16_t)(info->fSpec - UPRINTF_BASE_FMT_HANDLERS);
+        if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) {
+            /* query the info function for argument information */
+            argType = g_u_printf_infos[ handlerNum ].info;
+
+            /* goto the correct argument on arg_list if position is specified */
+            if (spec.fArgPos > 0) {
+                /* offset position by 1 */
+                spec.fArgPos--;
+                switch(argType) {
+                case ufmt_count:
+                    /* set the spec's width to the # of chars written */
+                    info->fWidth = *written;
+                    /* fall through to set the pointer */
+                case ufmt_string:
+                case ufmt_ustring:
+                case ufmt_pointer:
+                    args.ptrValue = arglist[spec.fArgPos].ptrValue;
+                    break;
+                case ufmt_char:
+                case ufmt_uchar:
+                case ufmt_int:
+                    args.int64Value = arglist[spec.fArgPos].int64Value;
+                    break;
+                case ufmt_float:
+                    args.floatValue = arglist[spec.fArgPos].floatValue;
+                    break;
+                case ufmt_double:
+                    args.doubleValue = arglist[spec.fArgPos].doubleValue;
+                    break;
+                default:
+                    /* else args is ignored */
+                    args.ptrValue = NULL;
+                    break;
+                }
+            } else { /* no positional argument specified */
+                switch(argType) {
+                case ufmt_count:
+                    /* set the spec's width to the # of chars written */
+                    info->fWidth = *written;
+                    /* fall through to set the pointer */
+                case ufmt_string:
+                case ufmt_ustring:
+                case ufmt_pointer:
+                    args.ptrValue = va_arg(ap, void*);
+                    break;
+                case ufmt_char:
+                case ufmt_uchar:
+                case ufmt_int:
+                    if (info->fIsLongLong) {
+                        args.int64Value = va_arg(ap, int64_t);
+                    }
+                    else {
+                        args.int64Value = va_arg(ap, int32_t);
+                    }
+                    break;
+                case ufmt_float:
+                    args.floatValue = (float) va_arg(ap, double);
+                    break;
+                case ufmt_double:
+                    args.doubleValue = va_arg(ap, double);
+                    break;
+                default:
+                    /* else args is ignored */
+                    args.ptrValue = NULL;
+                    break;
+                }
+            }
+
+            /* call the handler function */
+            handler = g_u_printf_infos[ handlerNum ].handler;
+            if(handler != 0) {
+                *written += (*handler)(streamHandler, context, formatBundle, info, &args);
+            }
+            else {
+                /* just echo unknown tags */
+                *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
+            }
+        }
+        else {
+            /* just echo unknown tags */
+            *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
+        }
+    }
+    /* delete parsed argument list */
+    if (arglist != NULL) {
+        uprv_free(arglist);
+    }
+    /* return # of characters in this format that have been parsed. */
+    return (int32_t)(alias - fmt);
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/source/io/uscanf.c b/source/io/uscanf.c
new file mode 100644
index 0000000..5743f65
--- /dev/null
+++ b/source/io/uscanf.c
@@ -0,0 +1,106 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1998-2004, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File uscanf.c
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   12/02/98    stephen        Creation.
+*   03/13/99    stephen     Modified for new C API.
+******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/putil.h"
+#include "unicode/ustdio.h"
+#include "unicode/ustring.h"
+#include "uscanf.h"
+#include "ufile.h"
+#include "ufmt_cmn.h"
+
+#include "cmemory.h"
+#include "cstring.h"
+
+
+U_CAPI int32_t U_EXPORT2
+u_fscanf(UFILE        *f,
+         const char    *patternSpecification,
+         ... )
+{
+    va_list ap;
+    int32_t converted;
+
+    va_start(ap, patternSpecification);
+    converted = u_vfscanf(f, patternSpecification, ap);
+    va_end(ap);
+
+    return converted;
+}
+
+U_CAPI int32_t U_EXPORT2
+u_fscanf_u(UFILE        *f,
+           const UChar    *patternSpecification,
+           ... )
+{
+    va_list ap;
+    int32_t converted;
+
+    va_start(ap, patternSpecification);
+    converted = u_vfscanf_u(f, patternSpecification, ap);
+    va_end(ap);
+
+    return converted;
+}
+
+U_CAPI int32_t  U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_vfscanf(UFILE        *f,
+          const char    *patternSpecification,
+          va_list        ap)
+{
+    int32_t converted;
+    UChar *pattern;
+    UChar patBuffer[UFMT_DEFAULT_BUFFER_SIZE];
+    int32_t size = (int32_t)uprv_strlen(patternSpecification) + 1;
+
+    /* convert from the default codepage to Unicode */
+    if (size >= MAX_UCHAR_BUFFER_SIZE(patBuffer)) {
+        pattern = (UChar *)uprv_malloc(size * sizeof(UChar));
+        if(pattern == 0) {
+            return 0;
+        }
+    }
+    else {
+        pattern = patBuffer;
+    }
+    u_charsToUChars(patternSpecification, pattern, size);
+
+    /* do the work */
+    converted = u_vfscanf_u(f, pattern, ap);
+
+    /* clean up */
+    if (pattern != patBuffer) {
+        uprv_free(pattern);
+    }
+
+    return converted;
+}
+
+U_CAPI int32_t  U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_vfscanf_u(UFILE       *f,
+            const UChar *patternSpecification,
+            va_list     ap)
+{
+    return u_scanf_parse(f, patternSpecification, ap);
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
diff --git a/source/io/uscanf.h b/source/io/uscanf.h
new file mode 100644
index 0000000..dd8b854
--- /dev/null
+++ b/source/io/uscanf.h
@@ -0,0 +1,36 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1998-2004, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*
+* File uscanf.h
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   12/02/98    stephen        Creation.
+*   03/13/99    stephen     Modified for new C API.
+******************************************************************************
+*/
+
+#ifndef USCANF_H
+#define USCANF_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ustdio.h"
+
+U_CFUNC int32_t
+u_scanf_parse(UFILE     *f,
+            const UChar *patternSpecification,
+            va_list     ap);
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
+
diff --git a/source/io/uscanf_p.c b/source/io/uscanf_p.c
new file mode 100644
index 0000000..ec6d97e
--- /dev/null
+++ b/source/io/uscanf_p.c
@@ -0,0 +1,1407 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1998-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*
+* File uscnnf_p.c
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   12/02/98    stephen        Creation.
+*   03/13/99    stephen     Modified for new C API.
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uchar.h"
+#include "unicode/ustring.h"
+#include "unicode/unum.h"
+#include "unicode/udat.h"
+#include "unicode/uset.h"
+#include "uscanf.h"
+#include "ufmt_cmn.h"
+#include "ufile.h"
+#include "locbund.h"
+
+#include "cmemory.h"
+#include "ustr_cnv.h"
+
+/* flag characters for u_scanf */
+#define FLAG_ASTERISK 0x002A
+#define FLAG_PAREN 0x0028
+
+#define ISFLAG(s)    (s) == FLAG_ASTERISK || \
+            (s) == FLAG_PAREN
+
+/* special characters for u_scanf */
+#define SPEC_DOLLARSIGN 0x0024
+
+/* unicode digits */
+#define DIGIT_ZERO 0x0030
+#define DIGIT_ONE 0x0031
+#define DIGIT_TWO 0x0032
+#define DIGIT_THREE 0x0033
+#define DIGIT_FOUR 0x0034
+#define DIGIT_FIVE 0x0035
+#define DIGIT_SIX 0x0036
+#define DIGIT_SEVEN 0x0037
+#define DIGIT_EIGHT 0x0038
+#define DIGIT_NINE 0x0039
+
+#define ISDIGIT(s)    (s) == DIGIT_ZERO || \
+            (s) == DIGIT_ONE || \
+            (s) == DIGIT_TWO || \
+            (s) == DIGIT_THREE || \
+            (s) == DIGIT_FOUR || \
+            (s) == DIGIT_FIVE || \
+            (s) == DIGIT_SIX || \
+            (s) == DIGIT_SEVEN || \
+            (s) == DIGIT_EIGHT || \
+            (s) == DIGIT_NINE
+
+/* u_scanf modifiers */
+#define MOD_H 0x0068
+#define MOD_LOWERL 0x006C
+#define MOD_L 0x004C
+
+#define ISMOD(s)    (s) == MOD_H || \
+            (s) == MOD_LOWERL || \
+            (s) == MOD_L
+
+/**
+ * Struct encapsulating a single uscanf format specification.
+ */
+typedef struct u_scanf_spec_info {
+    int32_t fWidth;         /* Width  */
+
+    UChar   fSpec;          /* Format specification  */
+
+    UChar   fPadChar;       /* Padding character  */
+
+    UBool   fSkipArg;       /* TRUE if arg should be skipped */
+    UBool   fIsLongDouble;  /* L flag  */
+    UBool   fIsShort;       /* h flag  */
+    UBool   fIsLong;        /* l flag  */
+    UBool   fIsLongLong;    /* ll flag  */
+    UBool   fIsString;      /* TRUE if this is a NULL-terminated string. */
+} u_scanf_spec_info;
+
+
+/**
+ * Struct encapsulating a single u_scanf format specification.
+ */
+typedef struct u_scanf_spec {
+    u_scanf_spec_info    fInfo;        /* Information on this spec */
+    int32_t        fArgPos;    /* Position of data in arg list */
+} u_scanf_spec;
+
+/**
+ * Parse a single u_scanf format specifier in Unicode.
+ * @param fmt A pointer to a '%' character in a u_scanf format specification.
+ * @param spec A pointer to a <TT>u_scanf_spec</TT> to receive the parsed
+ * format specifier.
+ * @return The number of characters contained in this specifier.
+ */
+static int32_t
+u_scanf_parse_spec (const UChar     *fmt,
+            u_scanf_spec    *spec)
+{
+    const UChar *s = fmt;
+    const UChar *backup;
+    u_scanf_spec_info *info = &(spec->fInfo);
+
+    /* initialize spec to default values */
+    spec->fArgPos             = -1;
+
+    info->fWidth        = -1;
+    info->fSpec         = 0x0000;
+    info->fPadChar      = 0x0020;
+    info->fSkipArg      = FALSE;
+    info->fIsLongDouble = FALSE;
+    info->fIsShort      = FALSE;
+    info->fIsLong       = FALSE;
+    info->fIsLongLong   = FALSE;
+    info->fIsString     = TRUE;
+
+
+    /* skip over the initial '%' */
+    s++;
+
+    /* Check for positional argument */
+    if(ISDIGIT(*s)) {
+
+        /* Save the current position */
+        backup = s;
+
+        /* handle positional parameters */
+        if(ISDIGIT(*s)) {
+            spec->fArgPos = (int) (*s++ - DIGIT_ZERO);
+
+            while(ISDIGIT(*s)) {
+                spec->fArgPos *= 10;
+                spec->fArgPos += (int) (*s++ - DIGIT_ZERO);
+            }
+        }
+
+        /* if there is no '$', don't read anything */
+        if(*s != SPEC_DOLLARSIGN) {
+            spec->fArgPos = -1;
+            s = backup;
+        }
+        /* munge the '$' */
+        else
+            s++;
+    }
+
+    /* Get any format flags */
+    while(ISFLAG(*s)) {
+        switch(*s++) {
+
+            /* skip argument */
+        case FLAG_ASTERISK:
+            info->fSkipArg = TRUE;
+            break;
+
+            /* pad character specified */
+        case FLAG_PAREN:
+
+            /* first four characters are hex values for pad char */
+            info->fPadChar = (UChar)ufmt_digitvalue(*s++);
+            info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*s++));
+            info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*s++));
+            info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*s++));
+
+            /* final character is ignored */
+            s++;
+
+            break;
+        }
+    }
+
+    /* Get the width */
+    if(ISDIGIT(*s)){
+        info->fWidth = (int) (*s++ - DIGIT_ZERO);
+
+        while(ISDIGIT(*s)) {
+            info->fWidth *= 10;
+            info->fWidth += (int) (*s++ - DIGIT_ZERO);
+        }
+    }
+
+    /* Get any modifiers */
+    if(ISMOD(*s)) {
+        switch(*s++) {
+
+            /* short */
+        case MOD_H:
+            info->fIsShort = TRUE;
+            break;
+
+            /* long or long long */
+        case MOD_LOWERL:
+            if(*s == MOD_LOWERL) {
+                info->fIsLongLong = TRUE;
+                /* skip over the next 'l' */
+                s++;
+            }
+            else
+                info->fIsLong = TRUE;
+            break;
+
+            /* long double */
+        case MOD_L:
+            info->fIsLongDouble = TRUE;
+            break;
+        }
+    }
+
+    /* finally, get the specifier letter */
+    info->fSpec = *s++;
+
+    /* return # of characters in this specifier */
+    return (int32_t)(s - fmt);
+}
+
+#define UP_PERCENT 0x0025
+
+
+/* ANSI style formatting */
+/* Use US-ASCII characters only for formatting */
+
+/* % */
+#define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_scanf_simple_percent_handler}
+/* s */
+#define UFMT_STRING         {ufmt_string, u_scanf_string_handler}
+/* c */
+#define UFMT_CHAR           {ufmt_string, u_scanf_char_handler}
+/* d, i */
+#define UFMT_INT            {ufmt_int, u_scanf_integer_handler}
+/* u */
+#define UFMT_UINT           {ufmt_int, u_scanf_uinteger_handler}
+/* o */
+#define UFMT_OCTAL          {ufmt_int, u_scanf_octal_handler}
+/* x, X */
+#define UFMT_HEX            {ufmt_int, u_scanf_hex_handler}
+/* f */
+#define UFMT_DOUBLE         {ufmt_double, u_scanf_double_handler}
+/* e, E */
+#define UFMT_SCIENTIFIC     {ufmt_double, u_scanf_scientific_handler}
+/* g, G */
+#define UFMT_SCIDBL         {ufmt_double, u_scanf_scidbl_handler}
+/* n */
+#define UFMT_COUNT          {ufmt_count, u_scanf_count_handler}
+/* [ */
+#define UFMT_SCANSET        {ufmt_string, u_scanf_scanset_handler}
+
+/* non-ANSI extensions */
+/* Use US-ASCII characters only for formatting */
+
+/* p */
+#define UFMT_POINTER        {ufmt_pointer, u_scanf_pointer_handler}
+/* V */
+#define UFMT_SPELLOUT       {ufmt_double, u_scanf_spellout_handler}
+/* P */
+#define UFMT_PERCENT        {ufmt_double, u_scanf_percent_handler}
+/* C  K is old format */
+#define UFMT_UCHAR          {ufmt_uchar, u_scanf_uchar_handler}
+/* S  U is old format */
+#define UFMT_USTRING        {ufmt_ustring, u_scanf_ustring_handler}
+
+
+#define UFMT_EMPTY {ufmt_empty, NULL}
+
+/**
+ * A u_scanf handler function.  
+ * A u_scanf handler is responsible for handling a single u_scanf 
+ * format specification, for example 'd' or 's'.
+ * @param stream The UFILE to which to write output.
+ * @param info A pointer to a <TT>u_scanf_spec_info</TT> struct containing
+ * information on the format specification.
+ * @param args A pointer to the argument data
+ * @param fmt A pointer to the first character in the format string
+ * following the spec.
+ * @param fmtConsumed On output, set to the number of characters consumed
+ * in <TT>fmt</TT>. Do nothing, if the argument isn't variable width.
+ * @param argConverted The number of arguments converted and assigned, or -1 if an
+ * error occurred.
+ * @return The number of code points consumed during reading.
+ */
+typedef int32_t (*u_scanf_handler) (UFILE   *stream,
+                   u_scanf_spec_info  *info,
+                   ufmt_args                *args,
+                   const UChar              *fmt,
+                   int32_t                  *fmtConsumed,
+                   int32_t                  *argConverted);
+
+typedef struct u_scanf_info {
+    ufmt_type_info info;
+    u_scanf_handler handler;
+} u_scanf_info;
+
+#define USCANF_NUM_FMT_HANDLERS 108
+#define USCANF_SYMBOL_BUFFER_SIZE 8
+
+/* We do not use handlers for 0-0x1f */
+#define USCANF_BASE_FMT_HANDLERS 0x20
+
+
+static int32_t
+u_scanf_skip_leading_ws(UFILE   *input,
+                        UChar   pad)
+{
+    UChar   c;
+    int32_t count = 0;
+    UBool isNotEOF;
+
+    /* skip all leading ws in the input */
+    while( (isNotEOF = ufile_getch(input, &c)) && (c == pad || u_isWhitespace(c)) )
+    {
+        count++;
+    }
+
+    /* put the final character back on the input */
+    if(isNotEOF)
+        u_fungetc(c, input);
+
+    return count;
+}
+
+/* TODO: Is always skipping the prefix symbol as a positive sign a good idea in all locales? */
+static int32_t
+u_scanf_skip_leading_positive_sign(UFILE   *input,
+                                   UNumberFormat *format,
+                                   UErrorCode *status)
+{
+    UChar   c;
+    int32_t count = 0;
+    UBool isNotEOF;
+    UChar plusSymbol[USCANF_SYMBOL_BUFFER_SIZE];
+    int32_t symbolLen;
+    UErrorCode localStatus = U_ZERO_ERROR;
+
+    if (U_SUCCESS(*status)) {
+        symbolLen = unum_getSymbol(format,
+            UNUM_PLUS_SIGN_SYMBOL,
+            plusSymbol,
+            sizeof(plusSymbol)/sizeof(*plusSymbol),
+            &localStatus);
+
+        if (U_SUCCESS(localStatus)) {
+            /* skip all leading ws in the input */
+            while( (isNotEOF = ufile_getch(input, &c)) && (count < symbolLen && c == plusSymbol[count]) )
+            {
+                count++;
+            }
+
+            /* put the final character back on the input */
+            if(isNotEOF) {
+                u_fungetc(c, input);
+            }
+        }
+    }
+
+    return count;
+}
+
+static int32_t 
+u_scanf_simple_percent_handler(UFILE        *input,
+                               u_scanf_spec_info *info,
+                               ufmt_args    *args,
+                               const UChar  *fmt,
+                               int32_t      *fmtConsumed,
+                               int32_t      *argConverted)
+{
+    /* make sure the next character in the input is a percent */
+    *argConverted = 0;
+    if(u_fgetc(input) != 0x0025) {
+        *argConverted = -1;
+    }
+    return 1;
+}
+
+static int32_t
+u_scanf_count_handler(UFILE         *input,
+                      u_scanf_spec_info *info,
+                      ufmt_args     *args,
+                      const UChar   *fmt,
+                      int32_t       *fmtConsumed,
+                      int32_t       *argConverted)
+{
+    /* in the special case of count, the u_scanf_spec_info's width */
+    /* will contain the # of items converted thus far */
+    if (!info->fSkipArg) {
+        if (info->fIsShort)
+            *(int16_t*)(args[0].ptrValue) = (int16_t)(UINT16_MAX & info->fWidth);
+        else if (info->fIsLongLong)
+            *(int64_t*)(args[0].ptrValue) = info->fWidth;
+        else
+            *(int32_t*)(args[0].ptrValue) = (int32_t)(UINT32_MAX & info->fWidth);
+    }
+    *argConverted = 0;
+
+    /* we converted 0 args */
+    return 0;
+}
+
+static int32_t
+u_scanf_double_handler(UFILE        *input,
+                       u_scanf_spec_info *info,
+                       ufmt_args    *args,
+                       const UChar  *fmt,
+                       int32_t      *fmtConsumed,
+                       int32_t      *argConverted)
+{
+    int32_t         len;
+    double          num;
+    UNumberFormat   *format;
+    int32_t         parsePos    = 0;
+    int32_t         skipped;
+    UErrorCode      status      = U_ZERO_ERROR;
+
+
+    /* skip all ws in the input */
+    skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
+
+    /* fill the input's internal buffer */
+    ufile_fill_uchar_buffer(input);
+
+    /* determine the size of the input's buffer */
+    len = (int32_t)(input->str.fLimit - input->str.fPos);
+
+    /* truncate to the width, if specified */
+    if(info->fWidth != -1)
+        len = ufmt_min(len, info->fWidth);
+
+    /* get the formatter */
+    format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_DECIMAL);
+
+    /* handle error */
+    if(format == 0)
+        return 0;
+
+    /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
+    skipped += u_scanf_skip_leading_positive_sign(input, format, &status);
+
+    /* parse the number */
+    num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
+
+    if (!info->fSkipArg) {
+        if (info->fIsLong)
+            *(double*)(args[0].ptrValue) = num;
+        else if (info->fIsLongDouble)
+            *(long double*)(args[0].ptrValue) = num;
+        else
+            *(float*)(args[0].ptrValue) = (float)num;
+    }
+
+    /* mask off any necessary bits */
+    /*  if(! info->fIsLong_double)
+    num &= DBL_MAX;*/
+
+    /* update the input's position to reflect consumed data */
+    input->str.fPos += parsePos;
+
+    /* we converted 1 arg */
+    *argConverted = !info->fSkipArg;
+    return parsePos + skipped;
+}
+
+#define UPRINTF_SYMBOL_BUFFER_SIZE 8
+
+static int32_t
+u_scanf_scientific_handler(UFILE        *input,
+                           u_scanf_spec_info *info,
+                           ufmt_args    *args,
+                           const UChar  *fmt,
+                           int32_t      *fmtConsumed,
+                           int32_t      *argConverted)
+{
+    int32_t         len;
+    double          num;
+    UNumberFormat   *format;
+    int32_t         parsePos    = 0;
+    int32_t         skipped;
+    UErrorCode      status      = U_ZERO_ERROR;
+    UChar srcExpBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
+    int32_t srcLen, expLen;
+    UChar expBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
+
+
+    /* skip all ws in the input */
+    skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
+
+    /* fill the input's internal buffer */
+    ufile_fill_uchar_buffer(input);
+
+    /* determine the size of the input's buffer */
+    len = (int32_t)(input->str.fLimit - input->str.fPos);
+
+    /* truncate to the width, if specified */
+    if(info->fWidth != -1)
+        len = ufmt_min(len, info->fWidth);
+
+    /* get the formatter */
+    format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SCIENTIFIC);
+
+    /* handle error */
+    if(format == 0)
+        return 0;
+
+    /* set the appropriate flags on the formatter */
+
+    srcLen = unum_getSymbol(format,
+        UNUM_EXPONENTIAL_SYMBOL,
+        srcExpBuf,
+        sizeof(srcExpBuf),
+        &status);
+
+    /* Upper/lower case the e */
+    if (info->fSpec == (UChar)0x65 /* e */) {
+        expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf),
+            srcExpBuf, srcLen,
+            input->str.fBundle.fLocale,
+            &status);
+    }
+    else {
+        expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf),
+            srcExpBuf, srcLen,
+            input->str.fBundle.fLocale,
+            &status);
+    }
+
+    unum_setSymbol(format,
+        UNUM_EXPONENTIAL_SYMBOL,
+        expBuf,
+        expLen,
+        &status);
+
+
+
+
+    /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
+    skipped += u_scanf_skip_leading_positive_sign(input, format, &status);
+
+    /* parse the number */
+    num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
+
+    if (!info->fSkipArg) {
+        if (info->fIsLong)
+            *(double*)(args[0].ptrValue) = num;
+        else if (info->fIsLongDouble)
+            *(long double*)(args[0].ptrValue) = num;
+        else
+            *(float*)(args[0].ptrValue) = (float)num;
+    }
+
+    /* mask off any necessary bits */
+    /*  if(! info->fIsLong_double)
+    num &= DBL_MAX;*/
+
+    /* update the input's position to reflect consumed data */
+    input->str.fPos += parsePos;
+
+    /* we converted 1 arg */
+    *argConverted = !info->fSkipArg;
+    return parsePos + skipped;
+}
+
+static int32_t
+u_scanf_scidbl_handler(UFILE        *input,
+                       u_scanf_spec_info *info,
+                       ufmt_args    *args,
+                       const UChar  *fmt,
+                       int32_t      *fmtConsumed,
+                       int32_t      *argConverted)
+{
+    int32_t       len;
+    double        num;
+    UNumberFormat *scientificFormat, *genericFormat;
+    /*int32_t       scientificResult, genericResult;*/
+    double        scientificResult, genericResult;
+    int32_t       scientificParsePos = 0, genericParsePos = 0, parsePos = 0;
+    int32_t       skipped;
+    UErrorCode    scientificStatus = U_ZERO_ERROR;
+    UErrorCode    genericStatus = U_ZERO_ERROR;
+
+
+    /* since we can't determine by scanning the characters whether */
+    /* a number was formatted in the 'f' or 'g' styles, parse the */
+    /* string with both formatters, and assume whichever one */
+    /* parsed the most is the correct formatter to use */
+
+
+    /* skip all ws in the input */
+    skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
+
+    /* fill the input's internal buffer */
+    ufile_fill_uchar_buffer(input);
+
+    /* determine the size of the input's buffer */
+    len = (int32_t)(input->str.fLimit - input->str.fPos);
+
+    /* truncate to the width, if specified */
+    if(info->fWidth != -1)
+        len = ufmt_min(len, info->fWidth);
+
+    /* get the formatters */
+    scientificFormat = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SCIENTIFIC);
+    genericFormat = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_DECIMAL);
+
+    /* handle error */
+    if(scientificFormat == 0 || genericFormat == 0)
+        return 0;
+
+    /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
+    skipped += u_scanf_skip_leading_positive_sign(input, genericFormat, &genericStatus);
+
+    /* parse the number using each format*/
+
+    scientificResult = unum_parseDouble(scientificFormat, input->str.fPos, len,
+        &scientificParsePos, &scientificStatus);
+
+    genericResult = unum_parseDouble(genericFormat, input->str.fPos, len,
+        &genericParsePos, &genericStatus);
+
+    /* determine which parse made it farther */
+    if(scientificParsePos > genericParsePos) {
+        /* stash the result in num */
+        num = scientificResult;
+        /* update the input's position to reflect consumed data */
+        parsePos += scientificParsePos;
+    }
+    else {
+        /* stash the result in num */
+        num = genericResult;
+        /* update the input's position to reflect consumed data */
+        parsePos += genericParsePos;
+    }
+    input->str.fPos += parsePos;
+
+    if (!info->fSkipArg) {
+        if (info->fIsLong)
+            *(double*)(args[0].ptrValue) = num;
+        else if (info->fIsLongDouble)
+            *(long double*)(args[0].ptrValue) = num;
+        else
+            *(float*)(args[0].ptrValue) = (float)num;
+    }
+
+    /* mask off any necessary bits */
+    /*  if(! info->fIsLong_double)
+    num &= DBL_MAX;*/
+
+    /* we converted 1 arg */
+    *argConverted = !info->fSkipArg;
+    return parsePos + skipped;
+}
+
+static int32_t
+u_scanf_integer_handler(UFILE       *input,
+                        u_scanf_spec_info *info,
+                        ufmt_args   *args,
+                        const UChar *fmt,
+                        int32_t     *fmtConsumed,
+                        int32_t     *argConverted)
+{
+    int32_t         len;
+    void            *num        = (void*) (args[0].ptrValue);
+    UNumberFormat   *format;
+    int32_t         parsePos    = 0;
+    int32_t         skipped;
+    UErrorCode      status      = U_ZERO_ERROR;
+    int64_t         result;
+
+
+    /* skip all ws in the input */
+    skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
+
+    /* fill the input's internal buffer */
+    ufile_fill_uchar_buffer(input);
+
+    /* determine the size of the input's buffer */
+    len = (int32_t)(input->str.fLimit - input->str.fPos);
+
+    /* truncate to the width, if specified */
+    if(info->fWidth != -1)
+        len = ufmt_min(len, info->fWidth);
+
+    /* get the formatter */
+    format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_DECIMAL);
+
+    /* handle error */
+    if(format == 0)
+        return 0;
+
+    /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
+    skipped += u_scanf_skip_leading_positive_sign(input, format, &status);
+
+    /* parse the number */
+    result = unum_parseInt64(format, input->str.fPos, len, &parsePos, &status);
+
+    /* mask off any necessary bits */
+    if (!info->fSkipArg) {
+        if (info->fIsShort)
+            *(int16_t*)num = (int16_t)(UINT16_MAX & result);
+        else if (info->fIsLongLong)
+            *(int64_t*)num = result;
+        else
+            *(int32_t*)num = (int32_t)(UINT32_MAX & result);
+    }
+
+    /* update the input's position to reflect consumed data */
+    input->str.fPos += parsePos;
+
+    /* we converted 1 arg */
+    *argConverted = !info->fSkipArg;
+    return parsePos + skipped;
+}
+
+static int32_t
+u_scanf_uinteger_handler(UFILE          *input,
+                         u_scanf_spec_info *info,
+                         ufmt_args      *args,
+                         const UChar    *fmt,
+                         int32_t        *fmtConsumed,
+                         int32_t        *argConverted)
+{
+    /* TODO Fix this when Numberformat handles uint64_t */
+    return u_scanf_integer_handler(input, info, args, fmt, fmtConsumed, argConverted);
+}
+
+static int32_t
+u_scanf_percent_handler(UFILE       *input,
+                        u_scanf_spec_info *info,
+                        ufmt_args   *args,
+                        const UChar *fmt,
+                        int32_t     *fmtConsumed,
+                        int32_t     *argConverted)
+{
+    int32_t         len;
+    double          num;
+    UNumberFormat   *format;
+    int32_t         parsePos    = 0;
+    int32_t         skipped;
+    UErrorCode      status      = U_ZERO_ERROR;
+
+
+    /* skip all ws in the input */
+    skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
+
+    /* fill the input's internal buffer */
+    ufile_fill_uchar_buffer(input);
+
+    /* determine the size of the input's buffer */
+    len = (int32_t)(input->str.fLimit - input->str.fPos);
+
+    /* truncate to the width, if specified */
+    if(info->fWidth != -1)
+        len = ufmt_min(len, info->fWidth);
+
+    /* get the formatter */
+    format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_PERCENT);
+
+    /* handle error */
+    if(format == 0)
+        return 0;
+
+    /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
+    skipped += u_scanf_skip_leading_positive_sign(input, format, &status);
+
+    /* parse the number */
+    num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
+
+    if (!info->fSkipArg) {
+        *(double*)(args[0].ptrValue) = num;
+    }
+
+    /* mask off any necessary bits */
+    /*  if(! info->fIsLong_double)
+    num &= DBL_MAX;*/
+
+    /* update the input's position to reflect consumed data */
+    input->str.fPos += parsePos;
+
+    /* we converted 1 arg */
+    *argConverted = !info->fSkipArg;
+    return parsePos;
+}
+
+static int32_t
+u_scanf_string_handler(UFILE        *input,
+                       u_scanf_spec_info *info,
+                       ufmt_args    *args,
+                       const UChar  *fmt,
+                       int32_t      *fmtConsumed,
+                       int32_t      *argConverted)
+{
+    const UChar *source;
+    UConverter  *conv;
+    char        *arg    = (char*)(args[0].ptrValue);
+    char        *alias  = arg;
+    char        *limit;
+    UErrorCode  status  = U_ZERO_ERROR;
+    int32_t     count;
+    int32_t     skipped = 0;
+    UChar       c;
+    UBool       isNotEOF = FALSE;
+
+    /* skip all ws in the input */
+    if (info->fIsString) {
+        skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
+    }
+
+    /* get the string one character at a time, truncating to the width */
+    count = 0;
+
+    /* open the default converter */
+    conv = u_getDefaultConverter(&status);
+
+    if(U_FAILURE(status))
+        return -1;
+
+    while( (info->fWidth == -1 || count < info->fWidth) 
+        && (isNotEOF = ufile_getch(input, &c))
+        && (!info->fIsString || (c != info->fPadChar && !u_isWhitespace(c))))
+    {
+
+        if (!info->fSkipArg) {
+            /* put the character from the input onto the target */
+            source = &c;
+            /* Since we do this one character at a time, do it this way. */
+            if (info->fWidth > 0) {
+                limit = alias + info->fWidth - count;
+            }
+            else {
+                limit = alias + ucnv_getMaxCharSize(conv);
+            }
+
+            /* convert the character to the default codepage */
+            ucnv_fromUnicode(conv, &alias, limit, &source, source + 1,
+                NULL, TRUE, &status);
+
+            if(U_FAILURE(status)) {
+                /* clean up */
+                u_releaseDefaultConverter(conv);
+                return -1;
+            }
+        }
+
+        /* increment the count */
+        ++count;
+    }
+
+    /* put the final character we read back on the input */
+    if (!info->fSkipArg) {
+        if ((info->fWidth == -1 || count < info->fWidth) && isNotEOF)
+            u_fungetc(c, input);
+
+        /* add the terminator */
+        if (info->fIsString) {
+            *alias = 0x00;
+        }
+    }
+
+    /* clean up */
+    u_releaseDefaultConverter(conv);
+
+    /* we converted 1 arg */
+    *argConverted = !info->fSkipArg;
+    return count + skipped;
+}
+
+static int32_t
+u_scanf_char_handler(UFILE          *input,
+                     u_scanf_spec_info *info,
+                     ufmt_args      *args,
+                     const UChar    *fmt,
+                     int32_t        *fmtConsumed,
+                     int32_t        *argConverted)
+{
+    if (info->fWidth < 0) {
+        info->fWidth = 1;
+    }
+    info->fIsString = FALSE;
+    return u_scanf_string_handler(input, info, args, fmt, fmtConsumed, argConverted);
+}
+
+static int32_t
+u_scanf_ustring_handler(UFILE       *input,
+                        u_scanf_spec_info *info,
+                        ufmt_args   *args,
+                        const UChar *fmt,
+                        int32_t     *fmtConsumed,
+                        int32_t     *argConverted)
+{
+    UChar   *arg     = (UChar*)(args[0].ptrValue);
+    UChar   *alias     = arg;
+    int32_t count;
+    int32_t skipped = 0;
+    UChar   c;
+    UBool   isNotEOF = FALSE;
+
+    /* skip all ws in the input */
+    if (info->fIsString) {
+        skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
+    }
+
+    /* get the string one character at a time, truncating to the width */
+    count = 0;
+
+    while( (info->fWidth == -1 || count < info->fWidth)
+        && (isNotEOF = ufile_getch(input, &c))
+        && (!info->fIsString || (c != info->fPadChar && !u_isWhitespace(c))))
+    {
+
+        /* put the character from the input onto the target */
+        if (!info->fSkipArg) {
+            *alias++ = c;
+        }
+
+        /* increment the count */
+        ++count;
+    }
+
+    /* put the final character we read back on the input */
+    if (!info->fSkipArg) {
+        if((info->fWidth == -1 || count < info->fWidth) && isNotEOF) {
+            u_fungetc(c, input);
+        }
+
+        /* add the terminator */
+        if (info->fIsString) {
+            *alias = 0x0000;
+        }
+    }
+
+    /* we converted 1 arg */
+    *argConverted = !info->fSkipArg;
+    return count + skipped;
+}
+
+static int32_t
+u_scanf_uchar_handler(UFILE         *input,
+                      u_scanf_spec_info *info,
+                      ufmt_args     *args,
+                      const UChar   *fmt,
+                      int32_t       *fmtConsumed,
+                      int32_t       *argConverted)
+{
+    if (info->fWidth < 0) {
+        info->fWidth = 1;
+    }
+    info->fIsString = FALSE;
+    return u_scanf_ustring_handler(input, info, args, fmt, fmtConsumed, argConverted);
+}
+
+static int32_t
+u_scanf_spellout_handler(UFILE          *input,
+                         u_scanf_spec_info *info,
+                         ufmt_args      *args,
+                         const UChar    *fmt,
+                         int32_t        *fmtConsumed,
+                         int32_t        *argConverted)
+{
+    int32_t         len;
+    double          num;
+    UNumberFormat   *format;
+    int32_t         parsePos    = 0;
+    int32_t         skipped;
+    UErrorCode      status      = U_ZERO_ERROR;
+
+
+    /* skip all ws in the input */
+    skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
+
+    /* fill the input's internal buffer */
+    ufile_fill_uchar_buffer(input);
+
+    /* determine the size of the input's buffer */
+    len = (int32_t)(input->str.fLimit - input->str.fPos);
+
+    /* truncate to the width, if specified */
+    if(info->fWidth != -1)
+        len = ufmt_min(len, info->fWidth);
+
+    /* get the formatter */
+    format = u_locbund_getNumberFormat(&input->str.fBundle, UNUM_SPELLOUT);
+
+    /* handle error */
+    if(format == 0)
+        return 0;
+
+    /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
+    /* This is not applicable to RBNF. */
+    /*skipped += u_scanf_skip_leading_positive_sign(input, format, &status);*/
+
+    /* parse the number */
+    num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
+
+    if (!info->fSkipArg) {
+        *(double*)(args[0].ptrValue) = num;
+    }
+
+    /* mask off any necessary bits */
+    /*  if(! info->fIsLong_double)
+    num &= DBL_MAX;*/
+
+    /* update the input's position to reflect consumed data */
+    input->str.fPos += parsePos;
+
+    /* we converted 1 arg */
+    *argConverted = !info->fSkipArg;
+    return parsePos + skipped;
+}
+
+static int32_t
+u_scanf_hex_handler(UFILE       *input,
+                    u_scanf_spec_info *info,
+                    ufmt_args   *args,
+                    const UChar *fmt,
+                    int32_t     *fmtConsumed,
+                    int32_t     *argConverted)
+{
+    int32_t     len;
+    int32_t     skipped;
+    void        *num    = (void*) (args[0].ptrValue);
+    int64_t     result;
+
+    /* skip all ws in the input */
+    skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
+
+    /* fill the input's internal buffer */
+    ufile_fill_uchar_buffer(input);
+
+    /* determine the size of the input's buffer */
+    len = (int32_t)(input->str.fLimit - input->str.fPos);
+
+    /* truncate to the width, if specified */
+    if(info->fWidth != -1)
+        len = ufmt_min(len, info->fWidth);
+
+    /* check for alternate form */
+    if( *(input->str.fPos) == 0x0030 &&
+        (*(input->str.fPos + 1) == 0x0078 || *(input->str.fPos + 1) == 0x0058) ) {
+
+        /* skip the '0' and 'x' or 'X' if present */
+        input->str.fPos += 2;
+        len -= 2;
+    }
+
+    /* parse the number */
+    result = ufmt_uto64(input->str.fPos, &len, 16);
+
+    /* update the input's position to reflect consumed data */
+    input->str.fPos += len;
+
+    /* mask off any necessary bits */
+    if (!info->fSkipArg) {
+        if (info->fIsShort)
+            *(int16_t*)num = (int16_t)(UINT16_MAX & result);
+        else if (info->fIsLongLong)
+            *(int64_t*)num = result;
+        else
+            *(int32_t*)num = (int32_t)(UINT32_MAX & result);
+    }
+
+    /* we converted 1 arg */
+    *argConverted = !info->fSkipArg;
+    return len + skipped;
+}
+
+static int32_t
+u_scanf_octal_handler(UFILE         *input,
+                      u_scanf_spec_info *info,
+                      ufmt_args     *args,
+                      const UChar   *fmt,
+                      int32_t       *fmtConsumed,
+                      int32_t       *argConverted)
+{
+    int32_t     len;
+    int32_t     skipped;
+    void        *num         = (void*) (args[0].ptrValue);
+    int64_t     result;
+
+    /* skip all ws in the input */
+    skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
+
+    /* fill the input's internal buffer */
+    ufile_fill_uchar_buffer(input);
+
+    /* determine the size of the input's buffer */
+    len = (int32_t)(input->str.fLimit - input->str.fPos);
+
+    /* truncate to the width, if specified */
+    if(info->fWidth != -1)
+        len = ufmt_min(len, info->fWidth);
+
+    /* parse the number */
+    result = ufmt_uto64(input->str.fPos, &len, 8);
+
+    /* update the input's position to reflect consumed data */
+    input->str.fPos += len;
+
+    /* mask off any necessary bits */
+    if (!info->fSkipArg) {
+        if (info->fIsShort)
+            *(int16_t*)num = (int16_t)(UINT16_MAX & result);
+        else if (info->fIsLongLong)
+            *(int64_t*)num = result;
+        else
+            *(int32_t*)num = (int32_t)(UINT32_MAX & result);
+    }
+
+    /* we converted 1 arg */
+    *argConverted = !info->fSkipArg;
+    return len + skipped;
+}
+
+static int32_t
+u_scanf_pointer_handler(UFILE       *input,
+                        u_scanf_spec_info *info,
+                        ufmt_args   *args,
+                        const UChar *fmt,
+                        int32_t     *fmtConsumed,
+                        int32_t     *argConverted)
+{
+    int32_t len;
+    int32_t skipped;
+    void    *result;
+    void    **p     = (void**)(args[0].ptrValue);
+
+
+    /* skip all ws in the input */
+    skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
+
+    /* fill the input's internal buffer */
+    ufile_fill_uchar_buffer(input);
+
+    /* determine the size of the input's buffer */
+    len = (int32_t)(input->str.fLimit - input->str.fPos);
+
+    /* truncate to the width, if specified */
+    if(info->fWidth != -1) {
+        len = ufmt_min(len, info->fWidth);
+    }
+
+    /* Make sure that we don't consume too much */
+    if (len > (int32_t)(sizeof(void*)*2)) {
+        len = (int32_t)(sizeof(void*)*2);
+    }
+
+    /* parse the pointer - assign to temporary value */
+    result = ufmt_utop(input->str.fPos, &len);
+
+    if (!info->fSkipArg) {
+        *p = result;
+    }
+
+    /* update the input's position to reflect consumed data */
+    input->str.fPos += len;
+
+    /* we converted 1 arg */
+    *argConverted = !info->fSkipArg;
+    return len + skipped;
+}
+
+static int32_t
+u_scanf_scanset_handler(UFILE       *input,
+                        u_scanf_spec_info *info,
+                        ufmt_args   *args,
+                        const UChar *fmt,
+                        int32_t     *fmtConsumed,
+                        int32_t     *argConverted)
+{
+    USet        *scanset;
+    UErrorCode  status = U_ZERO_ERROR;
+    int32_t     chLeft = INT32_MAX;
+    UChar32     c;
+    UChar       *alias = (UChar*) (args[0].ptrValue);
+    UBool       isNotEOF = FALSE;
+    UBool       readCharacter = FALSE;
+
+    /* Create an empty set */
+    scanset = uset_open(0, -1);
+
+    /* Back up one to get the [ */
+    fmt--;
+
+    /* truncate to the width, if specified and alias the target */
+    if(info->fWidth >= 0) {
+        chLeft = info->fWidth;
+    }
+
+    /* parse the scanset from the fmt string */
+    *fmtConsumed = uset_applyPattern(scanset, fmt, -1, 0, &status);
+
+    /* verify that the parse was successful */
+    if (U_SUCCESS(status)) {
+        c=0;
+
+        /* grab characters one at a time and make sure they are in the scanset */
+        while(chLeft > 0) {
+            if ((isNotEOF = ufile_getch32(input, &c)) && uset_contains(scanset, c)) {
+                readCharacter = TRUE;
+                if (!info->fSkipArg) {
+                    int32_t idx = 0;
+                    UBool isError = FALSE;
+
+                    U16_APPEND(alias, idx, chLeft, c, isError);
+                    if (isError) {
+                        break;
+                    }
+                    alias += idx;
+                }
+                chLeft -= (1 + U_IS_SUPPLEMENTARY(c));
+            }
+            else {
+                /* if the character's not in the scanset, break out */
+                break;
+            }
+        }
+
+        /* put the final character we read back on the input */
+        if(isNotEOF && chLeft > 0) {
+            u_fungetc(c, input);
+        }
+    }
+
+    uset_close(scanset);
+
+    /* if we didn't match at least 1 character, fail */
+    if(!readCharacter)
+        return -1;
+    /* otherwise, add the terminator */
+    else if (!info->fSkipArg) {
+        *alias = 0x00;
+    }
+
+    /* we converted 1 arg */
+    *argConverted = !info->fSkipArg;
+    return (info->fWidth >= 0 ? info->fWidth : INT32_MAX) - chLeft;
+}
+
+/* Use US-ASCII characters only for formatting. Most codepages have
+ characters 20-7F from Unicode. Using any other codepage specific
+ characters will make it very difficult to format the string on
+ non-Unicode machines */
+static const u_scanf_info g_u_scanf_infos[USCANF_NUM_FMT_HANDLERS] = {
+/* 0x20 */
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_EMPTY,         UFMT_SIMPLE_PERCENT,UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+
+/* 0x30 */
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+
+/* 0x40 */
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_UCHAR,
+    UFMT_EMPTY,         UFMT_SCIENTIFIC,    UFMT_EMPTY,         UFMT_SCIDBL,
+#ifdef U_USE_OBSOLETE_IO_FORMATTING
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_UCHAR/*deprecated*/,
+#else
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+#endif
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+
+/* 0x50 */
+    UFMT_PERCENT,       UFMT_EMPTY,         UFMT_EMPTY,         UFMT_USTRING,
+#ifdef U_USE_OBSOLETE_IO_FORMATTING
+    UFMT_EMPTY,         UFMT_USTRING/*deprecated*/,UFMT_SPELLOUT,      UFMT_EMPTY,
+#else
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_SPELLOUT,      UFMT_EMPTY,
+#endif
+    UFMT_HEX,           UFMT_EMPTY,         UFMT_EMPTY,         UFMT_SCANSET,
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+
+/* 0x60 */
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_CHAR,
+    UFMT_INT,           UFMT_SCIENTIFIC,    UFMT_DOUBLE,        UFMT_SCIDBL,
+    UFMT_EMPTY,         UFMT_INT,           UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_COUNT,         UFMT_OCTAL,
+
+/* 0x70 */
+    UFMT_POINTER,       UFMT_EMPTY,         UFMT_EMPTY,         UFMT_STRING,
+    UFMT_EMPTY,         UFMT_UINT,          UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_HEX,           UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
+};
+
+U_CFUNC int32_t
+u_scanf_parse(UFILE     *f,
+            const UChar *patternSpecification,
+            va_list     ap)
+{
+    const UChar     *alias;
+    int32_t         count, converted, argConsumed, cpConsumed;
+    uint16_t        handlerNum;
+
+    ufmt_args       args;
+    u_scanf_spec    spec;
+    ufmt_type_info  info;
+    u_scanf_handler handler;
+
+    /* alias the pattern */
+    alias = patternSpecification;
+
+    /* haven't converted anything yet */
+    argConsumed = 0;
+    converted = 0;
+    cpConsumed = 0;
+
+    /* iterate through the pattern */
+    for(;;) {
+
+        /* match any characters up to the next '%' */
+        while(*alias != UP_PERCENT && *alias != 0x0000 && u_fgetc(f) == *alias) {
+            alias++;
+        }
+
+        /* if we aren't at a '%', or if we're at end of string, break*/
+        if(*alias != UP_PERCENT || *alias == 0x0000)
+            break;
+
+        /* parse the specifier */
+        count = u_scanf_parse_spec(alias, &spec);
+
+        /* update the pointer in pattern */
+        alias += count;
+
+        handlerNum = (uint16_t)(spec.fInfo.fSpec - USCANF_BASE_FMT_HANDLERS);
+        if (handlerNum < USCANF_NUM_FMT_HANDLERS) {
+            /* skip the argument, if necessary */
+            /* query the info function for argument information */
+            info = g_u_scanf_infos[ handlerNum ].info;
+            if (info != ufmt_count && u_feof(f)) {
+                break;
+            }
+            else if(spec.fInfo.fSkipArg) {
+                args.ptrValue = NULL;
+            }
+            else {
+                switch(info) {
+                case ufmt_count:
+                    /* set the spec's width to the # of items converted */
+                    spec.fInfo.fWidth = cpConsumed;
+                    /* fall through to next case */
+                case ufmt_char:
+                case ufmt_uchar:
+                case ufmt_int:
+                case ufmt_string:
+                case ufmt_ustring:
+                case ufmt_pointer:
+                case ufmt_float:
+                case ufmt_double:
+                    args.ptrValue = va_arg(ap, void*);
+                    break;
+
+                default:
+                    /* else args is ignored */
+                    args.ptrValue = NULL;
+                    break;
+                }
+            }
+
+            /* call the handler function */
+            handler = g_u_scanf_infos[ handlerNum ].handler;
+            if(handler != 0) {
+
+                /* reset count to 1 so that += for alias works. */
+                count = 1;
+
+                cpConsumed += (*handler)(f, &spec.fInfo, &args, alias, &count, &argConsumed);
+
+                /* if the handler encountered an error condition, break */
+                if(argConsumed < 0) {
+                    converted = -1;
+                    break;
+                }
+
+                /* add to the # of items converted */
+                converted += argConsumed;
+
+                /* update the pointer in pattern */
+                alias += count-1;
+            }
+            /* else do nothing */
+        }
+        /* else do nothing */
+
+        /* just ignore unknown tags */
+    }
+
+    /* return # of items converted */
+    return converted;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/source/io/ustdio.c b/source/io/ustdio.c
new file mode 100644
index 0000000..0ec153a
--- /dev/null
+++ b/source/io/ustdio.c
@@ -0,0 +1,726 @@
+/*
+ ******************************************************************************
+ *
+ *   Copyright (C) 1998-2010, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ *
+ ******************************************************************************
+ *
+ * File ustdio.c
+ *
+ * Modification History:
+ *
+ *   Date        Name        Description
+ *   11/18/98    stephen     Creation.
+ *   03/12/99    stephen     Modified for new C API.
+ *   07/19/99    stephen     Fixed read() and gets()
+ ******************************************************************************
+ */
+
+#include "unicode/ustdio.h"
+#include "unicode/putil.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "ufile.h"
+#include "ufmt_cmn.h"
+#include "unicode/ucnv.h"
+#include "unicode/ustring.h"
+
+#include <string.h>
+
+#define DELIM_LF 0x000A
+#define DELIM_VT 0x000B
+#define DELIM_FF 0x000C
+#define DELIM_CR 0x000D
+#define DELIM_NEL 0x0085
+#define DELIM_LS 0x2028
+#define DELIM_PS 0x2029
+
+/* TODO: is this correct for all codepages? Should we just use \n and let the converter handle it? */
+#ifdef U_WINDOWS
+static const UChar DELIMITERS [] = { DELIM_CR, DELIM_LF, 0x0000 };
+static const uint32_t DELIMITERS_LEN = 2;
+/* TODO: Default newline writing should be detected based upon the converter being used. */
+#else
+static const UChar DELIMITERS [] = { DELIM_LF, 0x0000 };
+static const uint32_t DELIMITERS_LEN = 1;
+#endif
+
+#define IS_FIRST_STRING_DELIMITER(c1) \
+ (UBool)((DELIM_LF <= (c1) && (c1) <= DELIM_CR) \
+        || (c1) == DELIM_NEL \
+        || (c1) == DELIM_LS \
+        || (c1) == DELIM_PS)
+#define CAN_HAVE_COMBINED_STRING_DELIMITER(c1) (UBool)((c1) == DELIM_CR)
+#define IS_COMBINED_STRING_DELIMITER(c1, c2) \
+ (UBool)((c1) == DELIM_CR && (c2) == DELIM_LF)
+
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+U_CAPI UTransliterator* U_EXPORT2
+u_fsettransliterator(UFILE *file, UFileDirection direction,
+                     UTransliterator *adopt, UErrorCode *status)
+{
+    UTransliterator *old = NULL;
+
+    if(U_FAILURE(*status))
+    {
+        return adopt;
+    }
+
+    if(!file)
+    {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return adopt;
+    }
+
+    if(direction & U_READ)
+    {
+        /** TODO: implement */
+        *status = U_UNSUPPORTED_ERROR;
+        return adopt;
+    }
+
+    if(adopt == NULL) /* they are clearing it */
+    {
+        if(file->fTranslit != NULL)
+        {
+            /* TODO: Check side */
+            old = file->fTranslit->translit;
+            uprv_free(file->fTranslit->buffer);
+            file->fTranslit->buffer=NULL;
+            uprv_free(file->fTranslit);
+            file->fTranslit=NULL;
+        }
+    }
+    else
+    {
+        if(file->fTranslit == NULL)
+        {
+            file->fTranslit = (UFILETranslitBuffer*) uprv_malloc(sizeof(UFILETranslitBuffer));
+            if(!file->fTranslit)
+            {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                return adopt;
+            }
+            file->fTranslit->capacity = 0;
+            file->fTranslit->length = 0;
+            file->fTranslit->pos = 0;
+            file->fTranslit->buffer = NULL;
+        }
+        else
+        {
+            old = file->fTranslit->translit;
+            ufile_flush_translit(file);
+        }
+
+        file->fTranslit->translit = adopt;
+    }
+
+    return old;
+}
+
+static const UChar * u_file_translit(UFILE *f, const UChar *src, int32_t *count, UBool flush)
+{
+    int32_t newlen;
+    int32_t junkCount = 0;
+    int32_t textLength;
+    int32_t textLimit;
+    UTransPosition pos;
+    UErrorCode status = U_ZERO_ERROR;
+
+    if(count == NULL)
+    {
+        count = &junkCount;
+    }
+
+    if ((!f)||(!f->fTranslit)||(!f->fTranslit->translit))
+    {
+        /* fast path */
+        return src;
+    }
+
+    /* First: slide over everything */
+    if(f->fTranslit->length > f->fTranslit->pos)
+    {
+        memmove(f->fTranslit->buffer, f->fTranslit->buffer + f->fTranslit->pos,
+            (f->fTranslit->length - f->fTranslit->pos)*sizeof(UChar));
+    }
+    f->fTranslit->length -= f->fTranslit->pos; /* always */
+    f->fTranslit->pos = 0;
+
+    /* Calculate new buffer size needed */
+    newlen = (*count + f->fTranslit->length) * 4;
+
+    if(newlen > f->fTranslit->capacity)
+    {
+        if(f->fTranslit->buffer == NULL)
+        {
+            f->fTranslit->buffer = (UChar*)uprv_malloc(newlen * sizeof(UChar));
+        }
+        else
+        {
+            f->fTranslit->buffer = (UChar*)uprv_realloc(f->fTranslit->buffer, newlen * sizeof(UChar));
+        }
+        /* Check for malloc/realloc failure. */
+        if (f->fTranslit->buffer == NULL) {
+        	return NULL;
+        }
+        f->fTranslit->capacity = newlen;
+    }
+
+    /* Now, copy any data over */
+    u_strncpy(f->fTranslit->buffer + f->fTranslit->length,
+        src,
+        *count);
+    f->fTranslit->length += *count;
+
+    /* Now, translit in place as much as we can  */
+    if(flush == FALSE)
+    {
+        textLength = f->fTranslit->length;
+        pos.contextStart = 0;
+        pos.contextLimit = textLength;
+        pos.start        = 0;
+        pos.limit        = textLength;
+
+        utrans_transIncrementalUChars(f->fTranslit->translit,
+            f->fTranslit->buffer, /* because we shifted */
+            &textLength,
+            f->fTranslit->capacity,
+            &pos,
+            &status);
+
+        /* now: start/limit point to the transliterated text */
+        /* Transliterated is [buffer..pos.start) */
+        *count            = pos.start;
+        f->fTranslit->pos = pos.start;
+        f->fTranslit->length = pos.limit;
+
+        return f->fTranslit->buffer;
+    }
+    else
+    {
+        textLength = f->fTranslit->length;
+        textLimit = f->fTranslit->length;
+
+        utrans_transUChars(f->fTranslit->translit,
+            f->fTranslit->buffer,
+            &textLength,
+            f->fTranslit->capacity,
+            0,
+            &textLimit,
+            &status);
+
+        /* out: converted len */
+        *count = textLimit;
+
+        /* Set pointers to 0 */
+        f->fTranslit->pos = 0;
+        f->fTranslit->length = 0;
+
+        return f->fTranslit->buffer;
+    }
+}
+
+#endif
+
+void
+ufile_flush_translit(UFILE *f)
+{
+#if !UCONFIG_NO_TRANSLITERATION
+    if((!f)||(!f->fTranslit))
+        return;
+#endif
+
+    u_file_write_flush(NULL, 0, f, FALSE, TRUE);
+}
+
+
+void
+ufile_flush_io(UFILE *f)
+{
+  if((!f) || (!f->fFile)) {
+    return; /* skip if no file */
+  }
+
+  u_file_write_flush(NULL, 0, f, TRUE, FALSE);
+}
+
+
+void
+ufile_close_translit(UFILE *f)
+{
+#if !UCONFIG_NO_TRANSLITERATION
+    if((!f)||(!f->fTranslit))
+        return;
+#endif
+
+    ufile_flush_translit(f);
+
+#if !UCONFIG_NO_TRANSLITERATION
+    if(f->fTranslit->translit)
+        utrans_close(f->fTranslit->translit);
+
+    if(f->fTranslit->buffer)
+    {
+        uprv_free(f->fTranslit->buffer);
+    }
+
+    uprv_free(f->fTranslit);
+    f->fTranslit = NULL;
+#endif
+}
+
+
+/* Input/output */
+
+U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_fputs(const UChar    *s,
+        UFILE        *f)
+{
+    int32_t count = u_file_write(s, u_strlen(s), f);
+    count += u_file_write(DELIMITERS, DELIMITERS_LEN, f);
+    return count;
+}
+
+U_CAPI UChar32 U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_fputc(UChar32      uc,
+        UFILE        *f)
+{
+    UChar buf[2];
+    int32_t idx = 0;
+    UBool isError = FALSE;
+
+    U16_APPEND(buf, idx, sizeof(buf)/sizeof(*buf), uc, isError);
+    if (isError) {
+        return U_EOF;
+    }
+    return u_file_write(buf, idx, f) == idx ? uc : U_EOF;
+}
+
+
+U_CFUNC int32_t U_EXPORT2
+u_file_write_flush(const UChar *chars,
+                   int32_t     count,
+                   UFILE       *f,
+                   UBool       flushIO,
+                   UBool       flushTranslit)
+{
+    /* Set up conversion parameters */
+    UErrorCode  status       = U_ZERO_ERROR;
+    const UChar *mySource    = chars;
+    const UChar *mySourceBegin; 
+    const UChar *mySourceEnd;
+    char        charBuffer[UFILE_CHARBUFFER_SIZE];
+    char        *myTarget   = charBuffer;
+    int32_t     written      = 0;
+    int32_t     numConverted = 0;
+
+    if (count < 0) {
+        count = u_strlen(chars);
+    }
+
+#if !UCONFIG_NO_TRANSLITERATION
+    if((f->fTranslit) && (f->fTranslit->translit))
+    {
+        /* Do the transliteration */
+        mySource = u_file_translit(f, chars, &count, flushTranslit);
+    }
+#endif
+
+    /* Write to a string. */
+    if (!f->fFile) {
+        int32_t charsLeft = (int32_t)(f->str.fLimit - f->str.fPos);
+        if (flushIO && charsLeft > count) {
+            count++;
+        }
+        written = ufmt_min(count, charsLeft);
+        u_strncpy(f->str.fPos, mySource, written);
+        f->str.fPos += written;
+        return written;
+    }
+
+    mySourceEnd = mySource + count;
+
+    /* Perform the conversion in a loop */
+    do {
+        mySourceBegin = mySource; /* beginning location for this loop */
+        status     = U_ZERO_ERROR;
+        if(f->fConverter != NULL) { /* We have a valid converter */
+            ucnv_fromUnicode(f->fConverter,
+                &myTarget,
+                charBuffer + UFILE_CHARBUFFER_SIZE,
+                &mySource,
+                mySourceEnd,
+                NULL,
+                flushIO,
+                &status);
+        } else { /*weiv: do the invariant conversion */
+            int32_t convertChars = (int32_t) (mySourceEnd - mySource); 
+            if (convertChars > UFILE_CHARBUFFER_SIZE) { 
+                convertChars = UFILE_CHARBUFFER_SIZE; 
+                status = U_BUFFER_OVERFLOW_ERROR; 
+            } 
+            u_UCharsToChars(mySource, myTarget, convertChars); 
+            mySource += convertChars; 
+            myTarget += convertChars; 
+        }
+        numConverted = (int32_t)(myTarget - charBuffer);
+
+        if (numConverted > 0) {
+            /* write the converted bytes */
+            fwrite(charBuffer,
+                sizeof(char),
+                numConverted,
+                f->fFile);
+
+            written     += (int32_t) (mySource - mySourceBegin);
+        }
+        myTarget     = charBuffer;
+    }
+    while(status == U_BUFFER_OVERFLOW_ERROR);
+
+    /* return # of chars written */
+    return written;
+}
+
+U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_file_write(    const UChar     *chars,
+             int32_t        count,
+             UFILE         *f)
+{
+    return u_file_write_flush(chars,count,f,FALSE,FALSE);
+}
+
+
+/* private function used for buffering input */
+void
+ufile_fill_uchar_buffer(UFILE *f)
+{
+    UErrorCode  status;
+    const char  *mySource;
+    const char  *mySourceEnd;
+    UChar       *myTarget;
+    int32_t     bufferSize;
+    int32_t     maxCPBytes;
+    int32_t     bytesRead;
+    int32_t     availLength;
+    int32_t     dataSize;
+    char        charBuffer[UFILE_CHARBUFFER_SIZE];
+    u_localized_string *str;
+
+    if (f->fFile == NULL) {
+        /* There is nothing to do. It's a string. */
+        return;
+    }
+
+    str = &f->str;
+    dataSize = (int32_t)(str->fLimit - str->fPos);
+    if (f->fFileno == 0 && dataSize > 0) {
+        /* Don't read from stdin too many times. There is still some data. */
+        return;
+    }
+
+    /* shift the buffer if it isn't empty */
+    if(dataSize != 0) {
+        uprv_memmove(f->fUCBuffer, str->fPos, dataSize * sizeof(UChar));
+    }
+
+
+    /* record how much buffer space is available */
+    availLength = UFILE_UCHARBUFFER_SIZE - dataSize;
+
+    /* Determine the # of codepage bytes needed to fill our UChar buffer */
+    /* weiv: if converter is NULL, we use invariant converter with charwidth = 1)*/
+    maxCPBytes = availLength / (f->fConverter!=NULL?(2*ucnv_getMinCharSize(f->fConverter)):1);
+
+    /* Read in the data to convert */
+    if (f->fFileno == 0) {
+        /* Special case. Read from stdin one line at a time. */
+        char *retStr = fgets(charBuffer, ufmt_min(maxCPBytes, UFILE_CHARBUFFER_SIZE), f->fFile);
+        bytesRead = (int32_t)(retStr ? uprv_strlen(charBuffer) : 0);
+    }
+    else {
+        /* A normal file */
+        bytesRead = (int32_t)fread(charBuffer,
+            sizeof(char),
+            ufmt_min(maxCPBytes, UFILE_CHARBUFFER_SIZE),
+            f->fFile);
+    }
+
+    /* Set up conversion parameters */
+    status      = U_ZERO_ERROR;
+    mySource    = charBuffer;
+    mySourceEnd = charBuffer + bytesRead;
+    myTarget    = f->fUCBuffer + dataSize;
+    bufferSize  = UFILE_UCHARBUFFER_SIZE;
+
+    if(f->fConverter != NULL) { /* We have a valid converter */
+        /* Perform the conversion */
+        ucnv_toUnicode(f->fConverter,
+            &myTarget,
+            f->fUCBuffer + bufferSize,
+            &mySource,
+            mySourceEnd,
+            NULL,
+            (UBool)(feof(f->fFile) != 0),
+            &status);
+
+    } else { /*weiv: do the invariant conversion */
+        u_charsToUChars(mySource, myTarget, bytesRead);
+        myTarget += bytesRead;
+    }
+
+    /* update the pointers into our array */
+    str->fPos    = str->fBuffer;
+    str->fLimit  = myTarget;
+}
+
+U_CAPI UChar* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_fgets(UChar        *s,
+        int32_t       n,
+        UFILE        *f)
+{
+    int32_t dataSize;
+    int32_t count;
+    UChar *alias;
+    const UChar *limit;
+    UChar *sItr;
+    UChar currDelim = 0;
+    u_localized_string *str;
+
+    if (n <= 0) {
+        /* Caller screwed up. We need to write the null terminatior. */
+        return NULL;
+    }
+
+    /* fill the buffer if needed */
+    str = &f->str;
+    if (str->fPos >= str->fLimit) {
+        ufile_fill_uchar_buffer(f);
+    }
+
+    /* subtract 1 from n to compensate for the terminator */
+    --n;
+
+    /* determine the amount of data in the buffer */
+    dataSize = (int32_t)(str->fLimit - str->fPos);
+
+    /* if 0 characters were left, return 0 */
+    if (dataSize == 0)
+        return NULL;
+
+    /* otherwise, iteratively fill the buffer and copy */
+    count = 0;
+    sItr = s;
+    currDelim = 0;
+    while (dataSize > 0 && count < n) {
+        alias = str->fPos;
+
+        /* Find how much to copy */
+        if (dataSize < (n - count)) {
+            limit = str->fLimit;
+        }
+        else {
+            limit = alias + (n - count);
+        }
+
+        if (!currDelim) {
+            /* Copy UChars until we find the first occurrence of a delimiter character */
+            while (alias < limit && !IS_FIRST_STRING_DELIMITER(*alias)) {
+                count++;
+                *(sItr++) = *(alias++);
+            }
+            /* Preserve the newline */
+            if (alias < limit && IS_FIRST_STRING_DELIMITER(*alias)) {
+                if (CAN_HAVE_COMBINED_STRING_DELIMITER(*alias)) {
+                    currDelim = *alias;
+                }
+                else {
+                    currDelim = 1;  /* This isn't a newline, but it's used to say
+                                    that we should break later. We've checked all
+                                    possible newline combinations even across buffer
+                                    boundaries. */
+                }
+                count++;
+                *(sItr++) = *(alias++);
+            }
+        }
+        /* If we have a CRLF combination, preserve that too. */
+        if (alias < limit) {
+            if (currDelim && IS_COMBINED_STRING_DELIMITER(currDelim, *alias)) {
+                count++;
+                *(sItr++) = *(alias++);
+            }
+            currDelim = 1;  /* This isn't a newline, but it's used to say
+                            that we should break later. We've checked all
+                            possible newline combinations even across buffer
+                            boundaries. */
+        }
+
+        /* update the current buffer position */
+        str->fPos = alias;
+
+        /* if we found a delimiter */
+        if (currDelim == 1) {
+            /* break out */
+            break;
+        }
+
+        /* refill the buffer */
+        ufile_fill_uchar_buffer(f);
+
+        /* determine the amount of data in the buffer */
+        dataSize = (int32_t)(str->fLimit - str->fPos);
+    }
+
+    /* add the terminator and return s */
+    *sItr = 0x0000;
+    return s;
+}
+
+U_CFUNC UBool U_EXPORT2
+ufile_getch(UFILE *f, UChar *ch)
+{
+    UBool isValidChar = FALSE;
+
+    *ch = U_EOF;
+    /* if we have an available character in the buffer, return it */
+    if(f->str.fPos < f->str.fLimit){
+        *ch = *(f->str.fPos)++;
+        isValidChar = TRUE;
+    }
+    else {
+        /* otherwise, fill the buffer and return the next character */
+        if(f->str.fPos >= f->str.fLimit) {
+            ufile_fill_uchar_buffer(f);
+        }
+        if(f->str.fPos < f->str.fLimit) {
+            *ch = *(f->str.fPos)++;
+            isValidChar = TRUE;
+        }
+    }
+    return isValidChar;
+}
+
+U_CAPI UChar U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_fgetc(UFILE        *f)
+{
+    UChar ch;
+    ufile_getch(f, &ch);
+    return ch;
+}
+
+U_CFUNC UBool U_EXPORT2
+ufile_getch32(UFILE *f, UChar32 *c32)
+{
+    UBool isValidChar = FALSE;
+    u_localized_string *str;
+
+    *c32 = U_EOF;
+
+    /* Fill the buffer if it is empty */
+    str = &f->str;
+    if (f && str->fPos + 1 >= str->fLimit) {
+        ufile_fill_uchar_buffer(f);
+    }
+
+    /* Get the next character in the buffer */
+    if (str->fPos < str->fLimit) {
+        *c32 = *(str->fPos)++;
+        if (U_IS_LEAD(*c32)) {
+            if (str->fPos < str->fLimit) {
+                UChar c16 = *(str->fPos)++;
+                *c32 = U16_GET_SUPPLEMENTARY(*c32, c16);
+                isValidChar = TRUE;
+            }
+            else {
+                *c32 = U_EOF;
+            }
+        }
+        else {
+            isValidChar = TRUE;
+        }
+    }
+
+    return isValidChar;
+}
+
+U_CAPI UChar32 U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_fgetcx(UFILE        *f)
+{
+    UChar32 ch;
+    ufile_getch32(f, &ch);
+    return ch;
+}
+
+U_CAPI UChar32 U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_fungetc(UChar32        ch,
+    UFILE        *f)
+{
+    u_localized_string *str;
+
+    str = &f->str;
+
+    /* if we're at the beginning of the buffer, sorry! */
+    if (str->fPos == str->fBuffer
+        || (U_IS_LEAD(ch) && (str->fPos - 1) == str->fBuffer))
+    {
+        ch = U_EOF;
+    }
+    else {
+        /* otherwise, put the character back */
+        /* Remember, read them back on in the reverse order. */
+        if (U_IS_LEAD(ch)) {
+            if (*--(str->fPos) != U16_TRAIL(ch)
+                || *--(str->fPos) != U16_LEAD(ch))
+            {
+                ch = U_EOF;
+            }
+        }
+        else if (*--(str->fPos) != ch) {
+            ch = U_EOF;
+        }
+    }
+    return ch;
+}
+
+U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
+u_file_read(    UChar        *chars,
+    int32_t        count,
+    UFILE         *f)
+{
+    int32_t dataSize;
+    int32_t read = 0;
+    u_localized_string *str = &f->str;
+
+    do {
+
+        /* determine the amount of data in the buffer */
+        dataSize = (int32_t)(str->fLimit - str->fPos);
+        if (dataSize <= 0) {
+            /* fill the buffer */
+            ufile_fill_uchar_buffer(f);
+            dataSize = (int32_t)(str->fLimit - str->fPos);
+        }
+
+        /* Make sure that we don't read too much */
+        if (dataSize > (count - read)) {
+            dataSize = count - read;
+        }
+
+        /* copy the current data in the buffer */
+        memcpy(chars + read, str->fPos, dataSize * sizeof(UChar));
+
+        /* update number of items read */
+        read += dataSize;
+
+        /* update the current buffer position */
+        str->fPos += dataSize;
+    }
+    while (dataSize != 0 && read < count);
+
+    return read;
+}
diff --git a/source/io/ustream.cpp b/source/io/ustream.cpp
new file mode 100644
index 0000000..3fd6237
--- /dev/null
+++ b/source/io/ustream.cpp
@@ -0,0 +1,172 @@
+/*
+**********************************************************************
+*   Copyright (C) 2001-2010, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*  FILE NAME : ustream.cpp
+*
+*   Modification History:
+*
+*   Date        Name        Description
+*   06/25/2001  grhoten     Move iostream from unistr.h to here
+******************************************************************************
+*/
+
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/ustream.h"
+#include "unicode/ucnv.h"
+#include "unicode/uchar.h"
+#include "ustr_cnv.h"
+#include "cmemory.h"
+#include <string.h>
+
+// console IO
+
+#if U_IOSTREAM_SOURCE >= 198506
+
+#if U_IOSTREAM_SOURCE >= 199711
+#define STD_NAMESPACE std::
+#else
+#define STD_NAMESPACE
+#endif
+
+#define STD_OSTREAM STD_NAMESPACE ostream
+#define STD_ISTREAM STD_NAMESPACE istream
+
+U_NAMESPACE_BEGIN
+
+U_IO_API STD_OSTREAM & U_EXPORT2
+operator<<(STD_OSTREAM& stream, const UnicodeString& str)
+{
+    if(str.length() > 0) {
+        char buffer[200];
+        UConverter *converter;
+        UErrorCode errorCode = U_ZERO_ERROR;
+
+        // use the default converter to convert chunks of text
+        converter = u_getDefaultConverter(&errorCode);
+        if(U_SUCCESS(errorCode)) {
+            const UChar *us = str.getBuffer();
+            const UChar *uLimit = us + str.length();
+            char *s, *sLimit = buffer + (sizeof(buffer) - 1);
+            do {
+                errorCode = U_ZERO_ERROR;
+                s = buffer;
+                ucnv_fromUnicode(converter, &s, sLimit, &us, uLimit, 0, FALSE, &errorCode);
+                *s = 0;
+
+                // write this chunk
+                if(s > buffer) {
+                    stream << buffer;
+                }
+            } while(errorCode == U_BUFFER_OVERFLOW_ERROR);
+            u_releaseDefaultConverter(converter);
+        }
+    }
+
+/*    stream.flush();*/
+    return stream;
+}
+
+U_IO_API STD_ISTREAM & U_EXPORT2
+operator>>(STD_ISTREAM& stream, UnicodeString& str)
+{
+    // This is like ICU status checking.
+    if (stream.fail()) {
+        return stream;
+    }
+
+    /* ipfx should eat whitespace when ios::skipws is set */
+    UChar uBuffer[16];
+    char buffer[16];
+    int32_t idx = 0;
+    UConverter *converter;
+    UErrorCode errorCode = U_ZERO_ERROR;
+
+    // use the default converter to convert chunks of text
+    converter = u_getDefaultConverter(&errorCode);
+    if(U_SUCCESS(errorCode)) {
+        UChar *us = uBuffer;
+        const UChar *uLimit = uBuffer + sizeof(uBuffer)/sizeof(*uBuffer);
+        const char *s, *sLimit;
+        char ch;
+        UChar ch32;
+        UBool initialWhitespace = TRUE;
+        UBool continueReading = TRUE;
+
+        /* We need to consume one byte at a time to see what is considered whitespace. */
+        while (continueReading) {
+            ch = stream.get();
+            if (stream.eof()) {
+                // The EOF is only set after the get() of an unavailable byte.
+                if (!initialWhitespace) {
+                    stream.clear(stream.eofbit);
+                }
+                continueReading = FALSE;
+            }
+            sLimit = &ch + (int)continueReading;
+            us = uBuffer;
+            s = &ch;
+            errorCode = U_ZERO_ERROR;
+            /*
+            Since we aren't guaranteed to see the state before this call,
+            this code won't work on stateful encodings like ISO-2022 or an EBCDIC stateful encoding.
+            We flush on the last byte to ensure that we output truncated multibyte characters.
+            */
+            ucnv_toUnicode(converter, &us, uLimit, &s, sLimit, 0, !continueReading, &errorCode);
+            if(U_FAILURE(errorCode)) {
+                /* Something really bad happened. setstate() isn't always an available API */
+                stream.clear(stream.failbit);
+                goto STOP_READING;
+            }
+            /* Was the character consumed? */
+            if (us != uBuffer) {
+                /* Reminder: ibm-1390 & JISX0213 can output 2 Unicode code points */
+                int32_t uBuffSize = us-uBuffer;
+                int32_t uBuffIdx = 0;
+                while (uBuffIdx < uBuffSize) {
+                    U16_NEXT(uBuffer, uBuffIdx, uBuffSize, ch32);
+                    if (u_isWhitespace(ch32)) {
+                        if (!initialWhitespace) {
+                            buffer[idx++] = ch;
+                            while (idx > 0) {
+                                stream.putback(buffer[--idx]);
+                            }
+                            goto STOP_READING;
+                        }
+                        /* else skip intialWhitespace */
+                    }
+                    else {
+                        if (initialWhitespace) {
+                            /*
+                            When initialWhitespace is TRUE, we haven't appended any
+                            character yet.  This is where we truncate the string,
+                            to avoid modifying the string before we know if we can
+                            actually read from the stream.
+                            */
+                            str.truncate(0);
+                            initialWhitespace = FALSE;
+                        }
+                        str.append(ch32);
+                    }
+                }
+                idx = 0;
+            }
+            else {
+                buffer[idx++] = ch;
+            }
+        }
+STOP_READING:
+        u_releaseDefaultConverter(converter);
+    }
+
+/*    stream.flush();*/
+    return stream;
+}
+
+U_NAMESPACE_END
+
+#endif
+
diff --git a/source/layout/AlternateSubstSubtables.cpp b/source/layout/AlternateSubstSubtables.cpp
new file mode 100644
index 0000000..81989cd
--- /dev/null
+++ b/source/layout/AlternateSubstSubtables.cpp
@@ -0,0 +1,45 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEGlyphFilter.h"
+#include "OpenTypeTables.h"
+#include "GlyphSubstitutionTables.h"
+#include "AlternateSubstSubtables.h"
+#include "GlyphIterator.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+le_uint32 AlternateSubstitutionSubtable::process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter) const
+{
+    // NOTE: For now, we'll just pick the first alternative...
+    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
+    le_int32 coverageIndex = getGlyphCoverage(glyph);
+
+    if (coverageIndex >= 0) {
+        le_uint16 altSetCount = SWAPW(alternateSetCount);
+
+        if (coverageIndex < altSetCount) {
+            Offset alternateSetTableOffset = SWAPW(alternateSetTableOffsetArray[coverageIndex]);
+            const AlternateSetTable *alternateSetTable =
+                (const AlternateSetTable *) ((char *) this + alternateSetTableOffset);
+            TTGlyphID alternate = SWAPW(alternateSetTable->alternateArray[0]);
+
+            if (filter == NULL || filter->accept(LE_SET_GLYPH(glyph, alternate))) {
+                glyphIterator->setCurrGlyphID(SWAPW(alternateSetTable->alternateArray[0]));
+            }
+            
+            return 1;
+        }
+
+        // XXXX If we get here, the table's mal-formed...
+    }
+
+    return 0;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/AlternateSubstSubtables.h b/source/layout/AlternateSubstSubtables.h
new file mode 100644
index 0000000..41e3bc9
--- /dev/null
+++ b/source/layout/AlternateSubstSubtables.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __ALTERNATESUBSTITUTIONSUBTABLES_H
+#define __ALTERNATESUBSTITUTIONSUBTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEGlyphFilter.h"
+#include "OpenTypeTables.h"
+#include "GlyphSubstitutionTables.h"
+#include "GlyphIterator.h"
+
+U_NAMESPACE_BEGIN
+
+struct AlternateSetTable
+{
+    le_uint16 glyphCount;
+    TTGlyphID alternateArray[ANY_NUMBER];
+};
+
+struct AlternateSubstitutionSubtable : GlyphSubstitutionSubtable
+{
+    le_uint16 alternateSetCount;
+    Offset    alternateSetTableOffsetArray[ANY_NUMBER];
+
+    le_uint32 process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter = NULL) const;
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/AnchorTables.cpp b/source/layout/AnchorTables.cpp
new file mode 100644
index 0000000..24f3cf3
--- /dev/null
+++ b/source/layout/AnchorTables.cpp
@@ -0,0 +1,106 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "DeviceTables.h"
+#include "AnchorTables.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+void AnchorTable::getAnchor(LEGlyphID glyphID, const LEFontInstance *fontInstance,
+                            LEPoint &anchor) const
+{
+    switch(SWAPW(anchorFormat)) {
+    case 1:
+    {
+        const Format1AnchorTable *f1 = (const Format1AnchorTable *) this;
+
+        f1->getAnchor(fontInstance, anchor);
+        break;
+    }
+
+    case 2:
+    {
+        const Format2AnchorTable *f2 = (const Format2AnchorTable *) this;
+
+        f2->getAnchor(glyphID, fontInstance, anchor);
+        break;
+    }
+
+    case 3:
+    {
+        const Format3AnchorTable *f3 = (const Format3AnchorTable *) this;
+
+        f3->getAnchor(fontInstance, anchor);
+        break;
+    }
+
+    default:
+        // unknown format: just use x, y coordinate, like format 1...
+        const Format1AnchorTable *f1 = (const Format1AnchorTable *) this;
+
+        f1->getAnchor(fontInstance, anchor);
+        break;
+    }
+}
+
+void Format1AnchorTable::getAnchor(const LEFontInstance *fontInstance, LEPoint &anchor) const
+{
+    le_int16 x = SWAPW(xCoordinate);
+    le_int16 y = SWAPW(yCoordinate);
+    LEPoint pixels;
+
+    fontInstance->transformFunits(x, y, pixels);
+
+    fontInstance->pixelsToUnits(pixels, anchor);
+}
+
+void Format2AnchorTable::getAnchor(LEGlyphID glyphID, const LEFontInstance *fontInstance, LEPoint &anchor) const
+{
+    LEPoint point;
+
+    if (! fontInstance->getGlyphPoint(glyphID, SWAPW(anchorPoint), point)) {
+        le_int16 x = SWAPW(xCoordinate);
+        le_int16 y = SWAPW(yCoordinate);
+
+        fontInstance->transformFunits(x, y, point);
+    }
+
+
+    fontInstance->pixelsToUnits(point, anchor);
+}
+
+void Format3AnchorTable::getAnchor(const LEFontInstance *fontInstance, LEPoint &anchor) const
+{
+    le_int16 x = SWAPW(xCoordinate);
+    le_int16 y = SWAPW(yCoordinate);
+    LEPoint pixels;
+    Offset dtxOffset = SWAPW(xDeviceTableOffset);
+    Offset dtyOffset = SWAPW(yDeviceTableOffset);
+
+    fontInstance->transformFunits(x, y, pixels);
+
+    if (dtxOffset != 0) {
+        const DeviceTable *dtx = (const DeviceTable *) ((char *) this + dtxOffset);
+        le_int16 adjx = dtx->getAdjustment((le_int16) fontInstance->getXPixelsPerEm());
+
+        pixels.fX += adjx;
+    }
+
+    if (dtyOffset != 0) {
+        const DeviceTable *dty = (const DeviceTable *) ((char *) this + dtyOffset);
+        le_int16 adjy = dty->getAdjustment((le_int16) fontInstance->getYPixelsPerEm());
+
+        pixels.fY += adjy;
+    }
+
+    fontInstance->pixelsToUnits(pixels, anchor);
+}
+
+U_NAMESPACE_END
+
diff --git a/source/layout/AnchorTables.h b/source/layout/AnchorTables.h
new file mode 100644
index 0000000..71825c5
--- /dev/null
+++ b/source/layout/AnchorTables.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __ANCHORTABLES_H
+#define __ANCHORTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+
+U_NAMESPACE_BEGIN
+
+struct AnchorTable
+{
+    le_uint16  anchorFormat;
+    le_int16   xCoordinate;
+    le_int16   yCoordinate;
+
+    void    getAnchor(LEGlyphID glyphID, const LEFontInstance *fontInstance,
+                      LEPoint &anchor) const;
+};
+
+struct Format1AnchorTable : AnchorTable
+{
+    void getAnchor(const LEFontInstance *fontInstance, LEPoint &anchor) const;
+};
+
+struct Format2AnchorTable : AnchorTable
+{
+    le_uint16  anchorPoint;
+
+    void getAnchor(LEGlyphID glyphID, const LEFontInstance *fontInstance, LEPoint &anchor) const;
+};
+
+struct Format3AnchorTable : AnchorTable
+{
+    Offset  xDeviceTableOffset;
+    Offset  yDeviceTableOffset;
+
+    void getAnchor(const LEFontInstance *fontInstance, LEPoint &anchor) const;
+};
+
+U_NAMESPACE_END
+#endif
+
+
diff --git a/source/layout/ArabicLayoutEngine.cpp b/source/layout/ArabicLayoutEngine.cpp
new file mode 100644
index 0000000..c0f780e
--- /dev/null
+++ b/source/layout/ArabicLayoutEngine.cpp
@@ -0,0 +1,217 @@
+
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEScripts.h"
+#include "LEGlyphFilter.h"
+#include "LEGlyphStorage.h"
+#include "LayoutEngine.h"
+#include "OpenTypeLayoutEngine.h"
+#include "ArabicLayoutEngine.h"
+#include "ScriptAndLanguageTags.h"
+#include "CharSubstitutionFilter.h"
+
+#include "GlyphSubstitutionTables.h"
+#include "GlyphDefinitionTables.h"
+#include "GlyphPositioningTables.h"
+
+#include "GDEFMarkFilter.h"
+
+#include "ArabicShaping.h"
+#include "CanonShaping.h"
+
+U_NAMESPACE_BEGIN
+
+le_bool CharSubstitutionFilter::accept(LEGlyphID glyph) const
+{
+    return fFontInstance->canDisplay((LEUnicode) glyph);
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ArabicOpenTypeLayoutEngine)
+
+ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+                        le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success)
+    : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success)
+{
+    fFeatureMap = ArabicShaping::getFeatureMap(fFeatureMapCount);
+    fFeatureOrder = TRUE;
+}
+
+ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+						       le_int32 typoFlags, LEErrorCode &success)
+    : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success)
+{
+    fFeatureMap = ArabicShaping::getFeatureMap(fFeatureMapCount);
+
+    // NOTE: We don't need to set fFeatureOrder to TRUE here
+    // because this constructor is only called by the constructor
+    // for UnicodeArabicOpenTypeLayoutEngine, which uses a pre-built
+    // GSUB table that has the features in the correct order.
+
+    //fFeatureOrder = TRUE;
+}
+
+ArabicOpenTypeLayoutEngine::~ArabicOpenTypeLayoutEngine()
+{
+    // nothing to do
+}
+
+// Input: characters
+// Output: characters, char indices, tags
+// Returns: output character count
+le_int32 ArabicOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+        LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    outChars = LE_NEW_ARRAY(LEUnicode, count);
+
+    if (outChars == NULL) {
+        success = LE_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
+
+    glyphStorage.allocateGlyphArray(count, rightToLeft, success);
+    glyphStorage.allocateAuxData(success);
+
+    if (LE_FAILURE(success)) {
+        LE_DELETE_ARRAY(outChars);
+        return 0;
+    }
+
+    CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, outChars, glyphStorage);
+
+    // Note: This processes the *original* character array so we can get context
+    // for the first and last characters. This is OK because only the marks
+    // will have been reordered, and they don't contribute to shaping.
+    ArabicShaping::shape(chars, offset, count, max, rightToLeft, glyphStorage);
+
+    return count;
+}
+
+void ArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
+                                                      LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    if (fGPOSTable != NULL) {
+        OpenTypeLayoutEngine::adjustGlyphPositions(chars, offset, count, reverse, glyphStorage, success);
+    } else if (fGDEFTable != NULL) {
+        GDEFMarkFilter filter(fGDEFTable);
+
+        adjustMarkGlyphs(glyphStorage, &filter, success);
+    } else {
+        GlyphDefinitionTableHeader *gdefTable = (GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable;
+        GDEFMarkFilter filter(gdefTable);
+
+        adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
+    }
+}
+
+UnicodeArabicOpenTypeLayoutEngine::UnicodeArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success)
+    : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success)
+{
+    fGSUBTable = (const GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable;
+    fGDEFTable = (const GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable;
+
+    fSubstitutionFilter = new CharSubstitutionFilter(fontInstance);
+}
+
+UnicodeArabicOpenTypeLayoutEngine::~UnicodeArabicOpenTypeLayoutEngine()
+{
+    delete fSubstitutionFilter;
+}
+
+// "glyphs", "indices" -> glyphs, indices
+le_int32 UnicodeArabicOpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    // FIXME: we could avoid the memory allocation and copy if we
+    // made a clone of mapCharsToGlyphs which took the fake glyphs
+    // directly.
+    le_int32 tempGlyphCount = tempGlyphStorage.getGlyphCount();
+    LEUnicode *tempChars = LE_NEW_ARRAY(LEUnicode, tempGlyphCount);
+
+    if (tempChars == NULL) {
+        success = LE_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
+
+    for (le_int32 i = 0; i < tempGlyphCount; i += 1) {
+        tempChars[i] = (LEUnicode) LE_GET_GLYPH(tempGlyphStorage[i]);
+    }
+
+    glyphStorage.adoptCharIndicesArray(tempGlyphStorage);
+
+    ArabicOpenTypeLayoutEngine::mapCharsToGlyphs(tempChars, 0, tempGlyphCount, FALSE, TRUE, glyphStorage, success);
+
+    LE_DELETE_ARRAY(tempChars);
+
+    return tempGlyphCount;
+}
+
+void UnicodeArabicOpenTypeLayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool /*mirror*/, LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    le_int32 i, dir = 1, out = 0;
+
+    if (reverse) {
+        out = count - 1;
+        dir = -1;
+    }
+
+    glyphStorage.allocateGlyphArray(count, reverse, success);
+
+    for (i = 0; i < count; i += 1, out += dir) {
+        glyphStorage[out] = (LEGlyphID) chars[offset + i];
+    }
+}
+
+void UnicodeArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
+                                                      LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    GDEFMarkFilter filter(fGDEFTable);
+
+    adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
+}
+
+U_NAMESPACE_END
+
diff --git a/source/layout/ArabicLayoutEngine.h b/source/layout/ArabicLayoutEngine.h
new file mode 100644
index 0000000..a449701
--- /dev/null
+++ b/source/layout/ArabicLayoutEngine.h
@@ -0,0 +1,241 @@
+
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#ifndef __ARABICLAYOUTENGINE_H
+#define __ARABICLAYOUTENGINE_H
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "LEGlyphFilter.h"
+#include "LayoutEngine.h"
+#include "OpenTypeLayoutEngine.h"
+
+#include "GlyphSubstitutionTables.h"
+#include "GlyphDefinitionTables.h"
+#include "GlyphPositioningTables.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * This class implements OpenType layout for Arabic fonts. It overrides
+ * the characerProcessing method to assign the correct OpenType feature
+ * tags for the Arabic contextual forms. It also overrides the adjustGlyphPositions
+ * method to guarantee that all vowel and accent glyphs have zero advance width.
+ *
+ * @internal
+ */
+class ArabicOpenTypeLayoutEngine : public OpenTypeLayoutEngine
+{
+public:
+    /**
+     * This is the main constructor. It constructs an instance of ArabicOpenTypeLayoutEngine for
+     * a particular font, script and language. It takes the GSUB table as a parameter since
+     * LayoutEngine::layoutEngineFactory has to read the GSUB table to know that it has an
+     * Indic OpenType font.
+     *
+     * @param fontInstance - the font
+     * @param scriptCode - the script
+     * @param langaugeCode - the language
+     * @param gsubTable - the GSUB table
+     * @param success - set to an error code if the operation fails
+     *
+     * @see LayoutEngine::layoutEngineFactory
+     * @see OpenTypeLayoutEngine
+     * @see ScriptAndLanguageTags.h for script and language codes
+     *
+     * @internal
+     */
+    ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+                            le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success);
+
+    /**
+     * This constructor is used when the font requires a "canned" GSUB table which can't be known
+     * until after this constructor has been invoked.
+     *
+     * @param fontInstance - the font
+     * @param scriptCode - the script
+     * @param langaugeCode - the language
+     * @param success - set to an error code if the operation fails
+     *
+     * @see OpenTypeLayoutEngine
+     * @see ScriptAndLanguageTags.h for script and language codes
+     *
+     * @internal
+     */
+    ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+			       le_int32 typoFlags, LEErrorCode &success);
+
+    /**
+     * The destructor, virtual for correct polymorphic invocation.
+     *
+     * @internal
+     */
+    virtual ~ArabicOpenTypeLayoutEngine();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.8
+     */
+    static UClassID getStaticClassID();
+
+protected:
+
+    /**
+     * This method does Arabic OpenType character processing. It assigns the OpenType feature
+     * tags to the characters to generate the correct contextual forms and ligatures.
+     *
+     * Input parameters:
+     * @param chars - the input character context
+     * @param offset - the index of the first character to process
+     * @param count - the number of characters to process
+     * @param max - the number of characters in the input context
+     * @param rightToLeft - <code>TRUE</code> if the characters are in a right to left directional run
+     *
+     * Output parameters:
+     * @param outChars - the output character arrayt
+     * @param charIndices - the output character index array
+     * @param featureTags - the output feature tag array
+     * @param success - set to an error code if the operation fails
+     *
+     * @return the output character count
+     *
+     * @internal
+     */
+    virtual le_int32 characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+            LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+    /**
+     * This method applies the GPOS table if it is present, otherwise it ensures that all vowel
+     * and accent glyphs have a zero advance width by calling the adjustMarkGlyphs method.
+     * If the font contains a GDEF table, that is used to identify voewls and accents. Otherwise
+     * the character codes are used.
+     *
+     * @param chars - the input character context
+     * @param offset - the offset of the first character to process
+     * @param count - the number of characters to process
+     * @param reverse - <code>TRUE</code> if the glyphs in the glyph array have been reordered
+     * @param glyphs - the input glyph array
+     * @param glyphCount - the number of glyphs
+     * @param positions - the position array, will be updated as needed
+     * @param success - output parameter set to an error code if the operation fails
+     *
+     * @internal
+     */
+    virtual void adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+    // static void adjustMarkGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool rightToLeft, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+};
+
+/**
+ * The class implements OpenType layout for Arabic fonts which don't
+ * contain a GSUB table, using a canned GSUB table based on Unicode
+ * Arabic Presentation Forms. It overrides the mapCharsToGlyphs method
+ * to use the Presentation Forms as logical glyph indices. It overrides the
+ * glyphPostProcessing method to convert the Presentation Forms to actual
+ * glyph indices.
+ *
+ * @see ArabicOpenTypeLayoutEngine
+ *
+ * @internal
+ */
+class UnicodeArabicOpenTypeLayoutEngine : public ArabicOpenTypeLayoutEngine
+{
+public:
+    /**
+     * This constructs an instance of UnicodeArabicOpenTypeLayoutEngine for a specific font,
+     * script and language.
+     *
+     * @param fontInstance - the font
+     * @param scriptCode - the script
+     * @param languageCode - the language
+     * @param success - set to an error code if the operation fails
+     *
+     * @see LEFontInstance
+     * @see ScriptAndLanguageTags.h for script and language codes
+     *
+     * @internal
+     */
+    UnicodeArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+		le_int32 typoFlags, LEErrorCode &success);
+
+    /**
+     * The destructor, virtual for correct polymorphic invocation.
+     *
+     * @internal
+     */
+    virtual ~UnicodeArabicOpenTypeLayoutEngine();
+
+protected:
+
+    /**
+     * This method converts the Arabic Presentation Forms in the temp glyph array
+     * into actual glyph indices using ArabicOpenTypeLayoutEngine::mapCharsToGlyps.
+     *
+     * Input paramters:
+     * @param tempGlyphs - the input presentation forms
+     * @param tempCharIndices - the input character index array
+     * @param tempGlyphCount - the number of Presentation Froms
+     *
+     * Output parameters:
+     * @param glyphs - the output glyph index array
+     * @param charIndices - the output character index array
+     * @param success - set to an error code if the operation fails
+     *
+     * @return the number of glyph indices in the output glyph index array
+     *
+     * @internal
+     */
+    virtual le_int32 glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+    /**
+     * This method copies the input characters into the output glyph index array,
+     * for use by the canned GSUB table. It also generates the character index array.
+     *
+     * Input parameters:
+     * @param chars - the input character context
+     * @param offset - the offset of the first character to be mapped
+     * @param count - the number of characters to be mapped
+     * @param reverse - if <code>TRUE</code>, the output will be in reverse order
+     * @param mirror - if <code>TRUE</code>, do character mirroring
+     * @param glyphStorage - the glyph storage object. Glyph and char index arrays will be updated.
+     *
+     * @param success - set to an error code if the operation fails
+     *
+     * @internal
+     */
+    virtual void mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror,
+        LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+    /**
+     * This method ensures that all vowel and accent glyphs have a zero advance width by calling
+     * the adjustMarkGlyphs method. The character codes are used to identify the vowel and mark
+     * glyphs.
+     *
+     * @param chars - the input character context
+     * @param offset - the offset of the first character to process
+     * @param count - the number of characters to process
+     * @param reverse - <code>TRUE</code> if the glyphs in the glyph array have been reordered
+     * @param glyphStorage - the glyph storage object. The glyph positions will be updated as needed.
+     * @param success - output parameter set to an error code if the operation fails
+     *
+     * @internal
+     */
+    virtual void adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/ArabicShaping.cpp b/source/layout/ArabicShaping.cpp
new file mode 100644
index 0000000..d2859b4
--- /dev/null
+++ b/source/layout/ArabicShaping.cpp
@@ -0,0 +1,210 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "ArabicShaping.h"
+#include "LEGlyphStorage.h"
+#include "ClassDefinitionTables.h"
+
+U_NAMESPACE_BEGIN
+
+// This table maps Unicode joining types to
+// ShapeTypes.
+const ArabicShaping::ShapeType ArabicShaping::shapeTypes[] =
+{
+    ArabicShaping::ST_NOSHAPE_NONE, // [U]
+    ArabicShaping::ST_NOSHAPE_DUAL, // [C]
+    ArabicShaping::ST_DUAL,         // [D]
+    ArabicShaping::ST_LEFT,         // [L]
+    ArabicShaping::ST_RIGHT,        // [R]
+    ArabicShaping::ST_TRANSPARENT   // [T]
+};
+
+/*
+    shaping array holds types for Arabic chars between 0610 and 0700
+    other values are either unshaped, or transparent if a mark or format
+    code, except for format codes 200c (zero-width non-joiner) and 200d 
+    (dual-width joiner) which are both unshaped and non_joining or
+    dual-joining, respectively.
+*/
+ArabicShaping::ShapeType ArabicShaping::getShapeType(LEUnicode c)
+{
+    const ClassDefinitionTable *joiningTypes = (const ClassDefinitionTable *) ArabicShaping::shapingTypeTable;
+    le_int32 joiningType = joiningTypes->getGlyphClass(c);
+
+    if (joiningType >= 0 && joiningType < ArabicShaping::JT_COUNT) {
+        return ArabicShaping::shapeTypes[joiningType];
+    }
+
+    return ArabicShaping::ST_NOSHAPE_NONE;
+}
+
+#define isolFeatureTag LE_ISOL_FEATURE_TAG
+#define initFeatureTag LE_INIT_FEATURE_TAG
+#define mediFeatureTag LE_MEDI_FEATURE_TAG
+#define finaFeatureTag LE_FINA_FEATURE_TAG
+#define ligaFeatureTag LE_LIGA_FEATURE_TAG
+#define msetFeatureTag LE_MSET_FEATURE_TAG
+#define markFeatureTag LE_MARK_FEATURE_TAG
+#define ccmpFeatureTag LE_CCMP_FEATURE_TAG
+#define rligFeatureTag LE_RLIG_FEATURE_TAG
+#define caltFeatureTag LE_CALT_FEATURE_TAG
+#define dligFeatureTag LE_DLIG_FEATURE_TAG
+#define cswhFeatureTag LE_CSWH_FEATURE_TAG
+#define cursFeatureTag LE_CURS_FEATURE_TAG
+#define kernFeatureTag LE_KERN_FEATURE_TAG
+#define mkmkFeatureTag LE_MKMK_FEATURE_TAG
+
+// NOTE:
+// The isol, fina, init and medi features must be
+// defined in the above order, and have masks that
+// are all in the same nibble.
+#define isolFeatureMask 0x80000000UL
+#define finaFeatureMask 0x40000000UL
+#define initFeatureMask 0x20000000UL
+#define mediFeatureMask 0x10000000UL
+#define ccmpFeatureMask 0x08000000UL
+#define rligFeatureMask 0x04000000UL
+#define caltFeatureMask 0x02000000UL
+#define ligaFeatureMask 0x01000000UL
+#define dligFeatureMask 0x00800000UL
+#define cswhFeatureMask 0x00400000UL
+#define msetFeatureMask 0x00200000UL
+#define cursFeatureMask 0x00100000UL
+#define kernFeatureMask 0x00080000UL
+#define markFeatureMask 0x00040000UL
+#define mkmkFeatureMask 0x00020000UL
+
+#define NO_FEATURES   0
+#define ISOL_FEATURES (isolFeatureMask | ligaFeatureMask | msetFeatureMask | markFeatureMask | ccmpFeatureMask | rligFeatureMask | caltFeatureMask | dligFeatureMask | cswhFeatureMask | cursFeatureMask | kernFeatureMask | mkmkFeatureMask)
+
+#define SHAPE_MASK 0xF0000000UL
+
+static const FeatureMap featureMap[] = {
+    {ccmpFeatureTag, ccmpFeatureMask},
+    {isolFeatureTag, isolFeatureMask},
+    {finaFeatureTag, finaFeatureMask},
+    {mediFeatureTag, mediFeatureMask},
+    {initFeatureTag, initFeatureMask},
+    {rligFeatureTag, rligFeatureMask},
+    {caltFeatureTag, caltFeatureMask},
+    {ligaFeatureTag, ligaFeatureMask},
+    {dligFeatureTag, dligFeatureMask},
+    {cswhFeatureTag, cswhFeatureMask},
+    {msetFeatureTag, msetFeatureMask},
+    {cursFeatureTag, cursFeatureMask},
+    {kernFeatureTag, kernFeatureMask},
+    {markFeatureTag, markFeatureMask},
+    {mkmkFeatureTag, mkmkFeatureMask}
+};
+
+const FeatureMap *ArabicShaping::getFeatureMap(le_int32 &count)
+{
+    count = LE_ARRAY_SIZE(featureMap);
+
+    return featureMap;
+}
+
+void ArabicShaping::adjustTags(le_int32 outIndex, le_int32 shapeOffset, LEGlyphStorage &glyphStorage)
+{
+    LEErrorCode success = LE_NO_ERROR;
+    FeatureMask featureMask = (FeatureMask) glyphStorage.getAuxData(outIndex, success);
+    FeatureMask shape = featureMask & SHAPE_MASK;
+
+    shape >>= shapeOffset;
+
+    glyphStorage.setAuxData(outIndex, ((featureMask & ~SHAPE_MASK) | shape), success);
+}
+
+void ArabicShaping::shape(const LEUnicode *chars, le_int32 offset, le_int32 charCount, le_int32 charMax,
+                          le_bool rightToLeft, LEGlyphStorage &glyphStorage)
+{
+    // iterate in logical order, store tags in visible order
+    // 
+    // the effective right char is the most recently encountered 
+    // non-transparent char
+    //
+    // four boolean states:
+    //   the effective right char shapes
+    //   the effective right char causes left shaping
+    //   the current char shapes
+    //   the current char causes right shaping
+    // 
+    // if both cause shaping, then
+    //   shaper.shape(errout, 2) (isolate to initial, or final to medial)
+    //   shaper.shape(out, 1) (isolate to final)
+
+    ShapeType rightType = ST_NOSHAPE_NONE, leftType = ST_NOSHAPE_NONE;
+    LEErrorCode success = LE_NO_ERROR;
+    le_int32 i;
+
+    for (i = offset - 1; i >= 0; i -= 1) {
+        rightType = getShapeType(chars[i]);
+        
+        if (rightType != ST_TRANSPARENT) {
+            break;
+        }
+    }
+
+    for (i = offset + charCount; i < charMax; i += 1) {
+        leftType = getShapeType(chars[i]);
+
+        if (leftType != ST_TRANSPARENT) {
+            break;
+        }
+    }
+
+    // erout is effective right logical index
+    le_int32 erout = -1;
+    le_bool rightShapes = FALSE;
+    le_bool rightCauses = (rightType & MASK_SHAPE_LEFT) != 0;
+    le_int32 in, e, out = 0, dir = 1;
+
+    if (rightToLeft) {
+        out = charCount - 1;
+        erout = charCount;
+        dir = -1;
+    }
+
+    for (in = offset, e = offset + charCount; in < e; in += 1, out += dir) {
+        LEUnicode c = chars[in];
+        ShapeType t = getShapeType(c);
+
+        if (t == ST_NOSHAPE_NONE) {
+            glyphStorage.setAuxData(out, NO_FEATURES, success);
+        } else {
+            glyphStorage.setAuxData(out, ISOL_FEATURES, success);
+        }
+
+        if ((t & MASK_TRANSPARENT) != 0) {
+            continue;
+        }
+
+        le_bool curShapes = (t & MASK_NOSHAPE) == 0;
+        le_bool curCauses = (t & MASK_SHAPE_RIGHT) != 0;
+
+        if (rightCauses && curCauses) {
+            if (rightShapes) {
+                adjustTags(erout, 2, glyphStorage);
+            }
+
+            if (curShapes) {
+                adjustTags(out, 1, glyphStorage);
+            }
+        }
+
+        rightShapes = curShapes;
+        rightCauses = (t & MASK_SHAPE_LEFT) != 0;
+        erout = out;
+    }
+
+    if (rightShapes && rightCauses && (leftType & MASK_SHAPE_RIGHT) != 0) {
+        adjustTags(erout, 2, glyphStorage);
+    }
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/ArabicShaping.h b/source/layout/ArabicShaping.h
new file mode 100644
index 0000000..9bf5aca
--- /dev/null
+++ b/source/layout/ArabicShaping.h
@@ -0,0 +1,77 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
+ *
+ */
+
+#ifndef __ARABICSHAPING_H
+#define __ARABICSHAPING_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+class ArabicShaping /* not : public UObject because all methods are static */ {
+public:
+    // Joining types
+    enum JoiningTypes
+    {
+        JT_NON_JOINING   = 0,
+        JT_JOIN_CAUSING  = 1,
+        JT_DUAL_JOINING  = 2,
+        JT_LEFT_JOINING  = 3,
+        JT_RIGHT_JOINING = 4,
+        JT_TRANSPARENT   = 5,
+        JT_COUNT         = 6
+    };
+
+    // shaping bit masks
+    enum ShapingBitMasks
+    {
+        MASK_SHAPE_RIGHT    = 1, // if this bit set, shapes to right
+        MASK_SHAPE_LEFT     = 2, // if this bit set, shapes to left
+        MASK_TRANSPARENT    = 4, // if this bit set, is transparent (ignore other bits)
+        MASK_NOSHAPE        = 8  // if this bit set, don't shape this char, i.e. tatweel
+    };
+
+    // shaping values
+    enum ShapeTypeValues
+    {
+        ST_NONE         = 0,
+        ST_RIGHT        = MASK_SHAPE_RIGHT,
+        ST_LEFT         = MASK_SHAPE_LEFT,
+        ST_DUAL         = MASK_SHAPE_RIGHT | MASK_SHAPE_LEFT,
+        ST_TRANSPARENT  = MASK_TRANSPARENT,
+        ST_NOSHAPE_DUAL = MASK_NOSHAPE | ST_DUAL,
+        ST_NOSHAPE_NONE = MASK_NOSHAPE
+    };
+
+    typedef le_int32 ShapeType;
+
+    static void shape(const LEUnicode *chars, le_int32 offset, le_int32 charCount, le_int32 charMax,
+                      le_bool rightToLeft, LEGlyphStorage &glyphStorage);
+
+    static const FeatureMap *getFeatureMap(le_int32 &count);
+
+private:
+    // forbid instantiation
+    ArabicShaping();
+
+    static ShapeType getShapeType(LEUnicode c);
+
+    static const le_uint8 shapingTypeTable[];
+    static const ShapeType shapeTypes[];
+
+    static void adjustTags(le_int32 outIndex, le_int32 shapeOffset, LEGlyphStorage &glyphStorage); 
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/AttachmentPosnSubtables.h b/source/layout/AttachmentPosnSubtables.h
new file mode 100644
index 0000000..7f8406d
--- /dev/null
+++ b/source/layout/AttachmentPosnSubtables.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
+ *
+ */
+
+#ifndef __ATTACHMENTPOSITIONINGSUBTABLES_H
+#define __ATTACHMENTPOSITIONINGSUBTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "GlyphPositioningTables.h"
+#include "ValueRecords.h"
+#include "GlyphIterator.h"
+
+U_NAMESPACE_BEGIN
+
+struct AttachmentPositioningSubtable : GlyphPositioningSubtable
+{
+    Offset    baseCoverageTableOffset;
+    le_uint16 classCount;
+    Offset    markArrayOffset;
+    Offset    baseArrayOffset;
+
+    inline le_int32  getBaseCoverage(LEGlyphID baseGlyphId) const;
+
+    le_uint32 process(GlyphIterator *glyphIterator) const;
+};
+
+inline le_int32 AttachmentPositioningSubtable::getBaseCoverage(LEGlyphID baseGlyphID) const
+{
+    return getGlyphCoverage(baseCoverageTableOffset, baseGlyphID);
+}
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/CanonData.cpp b/source/layout/CanonData.cpp
new file mode 100644
index 0000000..f4fe33b
--- /dev/null
+++ b/source/layout/CanonData.cpp
@@ -0,0 +1,3619 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008. All Rights Reserved.
+ *
+ * WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT UNLESS
+ * YOU REALLY KNOW WHAT YOU'RE DOING.
+ *
+ * Generated on: 03/12/2008 03:14:34 PM HST
+ */
+
+#include "LETypes.h"
+#include "CanonShaping.h"
+
+U_NAMESPACE_BEGIN
+
+const le_uint8 CanonShaping::glyphSubstitutionTable[] = {
+    0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x34, 0x02, 0x46, 0x00, 0x10, 0x61, 0x72, 0x61, 0x62, 
+    0x00, 0x62, 0x62, 0x61, 0x6C, 0x69, 0x00, 0x76, 0x62, 0x65, 0x6E, 0x67, 0x00, 0x82, 0x63, 0x79, 
+    0x72, 0x6C, 0x00, 0x8E, 0x64, 0x65, 0x76, 0x61, 0x00, 0x9A, 0x67, 0x72, 0x65, 0x6B, 0x00, 0xA6, 
+    0x68, 0x69, 0x72, 0x61, 0x00, 0xB2, 0x6B, 0x61, 0x6E, 0x61, 0x00, 0xBE, 0x6B, 0x6E, 0x64, 0x61, 
+    0x00, 0xCA, 0x6C, 0x61, 0x74, 0x6E, 0x00, 0xD6, 0x6D, 0x6C, 0x79, 0x6D, 0x00, 0xE2, 0x6D, 0x79, 
+    0x6D, 0x72, 0x00, 0xEE, 0x6F, 0x72, 0x79, 0x61, 0x00, 0xFA, 0x73, 0x69, 0x6E, 0x68, 0x01, 0x06, 
+    0x74, 0x61, 0x6D, 0x6C, 0x01, 0x12, 0x74, 0x65, 0x6C, 0x75, 0x01, 0x1E, 0x00, 0x04, 0x00, 0x00, 
+    0x00, 0x00, 0xFF, 0xFF, 0x00, 0x05, 0x00, 0x00, 0x00, 0x11, 0x00, 0x13, 0x00, 0x10, 0x00, 0x12, 
+    0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x0F, 0x00, 0x04, 0x00, 0x00, 
+    0x00, 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 
+    0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x03, 
+    0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 
+    0x00, 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 
+    0x00, 0x01, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x06, 
+    0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 
+    0x00, 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 
+    0x00, 0x01, 0x00, 0x0A, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x0B, 
+    0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x00, 
+    0x00, 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x0D, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 
+    0x00, 0x01, 0x00, 0x0E, 0x00, 0x14, 0x63, 0x63, 0x6D, 0x70, 0x00, 0x7A, 0x63, 0x63, 0x6D, 0x70, 
+    0x00, 0x82, 0x63, 0x63, 0x6D, 0x70, 0x00, 0x8A, 0x63, 0x63, 0x6D, 0x70, 0x00, 0x92, 0x63, 0x63, 
+    0x6D, 0x70, 0x00, 0x9A, 0x63, 0x63, 0x6D, 0x70, 0x00, 0xA2, 0x63, 0x63, 0x6D, 0x70, 0x00, 0xAA, 
+    0x63, 0x63, 0x6D, 0x70, 0x00, 0xB2, 0x63, 0x63, 0x6D, 0x70, 0x00, 0xBA, 0x63, 0x63, 0x6D, 0x70, 
+    0x00, 0xC2, 0x63, 0x63, 0x6D, 0x70, 0x00, 0xCA, 0x63, 0x63, 0x6D, 0x70, 0x00, 0xD2, 0x63, 0x63, 
+    0x6D, 0x70, 0x00, 0xDA, 0x63, 0x63, 0x6D, 0x70, 0x00, 0xE2, 0x63, 0x63, 0x6D, 0x70, 0x00, 0xEA, 
+    0x63, 0x63, 0x6D, 0x70, 0x00, 0xF2, 0x66, 0x69, 0x6E, 0x61, 0x00, 0xFA, 0x69, 0x6E, 0x69, 0x74, 
+    0x01, 0x00, 0x6C, 0x69, 0x67, 0x61, 0x01, 0x06, 0x6D, 0x65, 0x64, 0x69, 0x01, 0x0C, 0x00, 0x00, 
+    0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x07, 0x00, 0x00, 
+    0x00, 0x02, 0x00, 0x08, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x0B, 0x00, 0x00, 
+    0x00, 0x02, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x02, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x00, 
+    0x00, 0x02, 0x00, 0x10, 0x00, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x12, 0x00, 0x13, 0x00, 0x00, 
+    0x00, 0x02, 0x00, 0x14, 0x00, 0x15, 0x00, 0x00, 0x00, 0x02, 0x00, 0x16, 0x00, 0x17, 0x00, 0x00, 
+    0x00, 0x02, 0x00, 0x18, 0x00, 0x19, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1A, 0x00, 0x1B, 0x00, 0x00, 
+    0x00, 0x02, 0x00, 0x1C, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1E, 0x00, 0x1F, 0x00, 0x00, 
+    0x00, 0x02, 0x00, 0x20, 0x00, 0x21, 0x00, 0x00, 0x00, 0x02, 0x00, 0x22, 0x00, 0x23, 0x00, 0x00, 
+    0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x24, 0x00, 0x4A, 0x00, 0xC0, 0x01, 0x22, 0x01, 0xEC, 
+    0x02, 0xB6, 0x03, 0xF0, 0x14, 0xFE, 0x15, 0x26, 0x15, 0x4C, 0x17, 0xFE, 0x1A, 0x74, 0x1A, 0xB0, 
+    0x1A, 0xE0, 0x4E, 0xDA, 0x8B, 0xBC, 0x8D, 0x2A, 0x8E, 0x4A, 0x8E, 0xA0, 0x8E, 0xFC, 0x90, 0xA2, 
+    0x91, 0xEA, 0xB1, 0xA2, 0xD5, 0x1E, 0xD5, 0x54, 0xD5, 0x84, 0xD5, 0xA4, 0xD5, 0xC0, 0xD5, 0xF0, 
+    0xD6, 0x20, 0xD6, 0x68, 0xD6, 0xBA, 0xD6, 0xFE, 0xD7, 0x38, 0xD7, 0x58, 0xD7, 0x74, 0xD8, 0x20, 
+    0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x5E, 0x00, 0x06, 0x00, 0x12, 
+    0x00, 0x2C, 0x00, 0x36, 0x00, 0x40, 0x00, 0x4A, 0x00, 0x54, 0x00, 0x03, 0x00, 0x08, 0x00, 0x0E, 
+    0x00, 0x14, 0x06, 0x22, 0x00, 0x02, 0x06, 0x53, 0x06, 0x23, 0x00, 0x02, 0x06, 0x54, 0x06, 0x25, 
+    0x00, 0x02, 0x06, 0x55, 0x00, 0x01, 0x00, 0x04, 0x06, 0x24, 0x00, 0x02, 0x06, 0x54, 0x00, 0x01, 
+    0x00, 0x04, 0x06, 0x26, 0x00, 0x02, 0x06, 0x54, 0x00, 0x01, 0x00, 0x04, 0x06, 0xC2, 0x00, 0x02, 
+    0x06, 0x54, 0x00, 0x01, 0x00, 0x04, 0x06, 0xD3, 0x00, 0x02, 0x06, 0x54, 0x00, 0x01, 0x00, 0x04, 
+    0x06, 0xC0, 0x00, 0x02, 0x06, 0x54, 0x00, 0x01, 0x00, 0x06, 0x06, 0x27, 0x06, 0x48, 0x06, 0x4A, 
+    0x06, 0xC1, 0x06, 0xD2, 0x06, 0xD5, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 
+    0x00, 0x46, 0x00, 0x08, 0x00, 0x16, 0x00, 0x1C, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 
+    0x00, 0x3A, 0x00, 0x40, 0x00, 0x02, 0x06, 0x27, 0x06, 0x53, 0x00, 0x02, 0x06, 0x27, 0x06, 0x54, 
+    0x00, 0x02, 0x06, 0x48, 0x06, 0x54, 0x00, 0x02, 0x06, 0x27, 0x06, 0x55, 0x00, 0x02, 0x06, 0x4A, 
+    0x06, 0x54, 0x00, 0x02, 0x06, 0xD5, 0x06, 0x54, 0x00, 0x02, 0x06, 0xC1, 0x06, 0x54, 0x00, 0x02, 
+    0x06, 0xD2, 0x06, 0x54, 0x00, 0x01, 0x00, 0x08, 0x06, 0x22, 0x06, 0x23, 0x06, 0x24, 0x06, 0x25, 
+    0x06, 0x26, 0x06, 0xC0, 0x06, 0xC2, 0x06, 0xD3, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 
+    0x00, 0x02, 0x00, 0x62, 0x00, 0x2E, 0xFE, 0x8B, 0xFE, 0x91, 0xFE, 0x97, 0xFE, 0x9B, 0xFE, 0x9F, 
+    0xFE, 0xA3, 0xFE, 0xA7, 0xFE, 0xB3, 0xFE, 0xB7, 0xFE, 0xBB, 0xFE, 0xBF, 0xFE, 0xC3, 0xFE, 0xC7, 
+    0xFE, 0xCB, 0xFE, 0xCF, 0xFE, 0xD3, 0xFE, 0xD7, 0xFE, 0xDB, 0xFE, 0xDF, 0xFE, 0xE3, 0xFE, 0xE7, 
+    0xFE, 0xEB, 0xFB, 0xE8, 0xFE, 0xF3, 0xFB, 0x68, 0xFB, 0x60, 0xFB, 0x54, 0xFB, 0x58, 0xFB, 0x64, 
+    0xFB, 0x5C, 0xFB, 0x78, 0xFB, 0x74, 0xFB, 0x7C, 0xFB, 0x80, 0xFB, 0x6C, 0xFB, 0x70, 0xFB, 0x90, 
+    0xFB, 0xD5, 0xFB, 0x94, 0xFB, 0x9C, 0xFB, 0x98, 0xFB, 0xA2, 0xFB, 0xAC, 0xFB, 0xA8, 0xFB, 0xFE, 
+    0xFB, 0xE6, 0x00, 0x01, 0x00, 0x2E, 0x06, 0x26, 0x06, 0x28, 0x06, 0x2A, 0x06, 0x2B, 0x06, 0x2C, 
+    0x06, 0x2D, 0x06, 0x2E, 0x06, 0x33, 0x06, 0x34, 0x06, 0x35, 0x06, 0x36, 0x06, 0x37, 0x06, 0x38, 
+    0x06, 0x39, 0x06, 0x3A, 0x06, 0x41, 0x06, 0x42, 0x06, 0x43, 0x06, 0x44, 0x06, 0x45, 0x06, 0x46, 
+    0x06, 0x47, 0x06, 0x49, 0x06, 0x4A, 0x06, 0x79, 0x06, 0x7A, 0x06, 0x7B, 0x06, 0x7E, 0x06, 0x7F, 
+    0x06, 0x80, 0x06, 0x83, 0x06, 0x84, 0x06, 0x86, 0x06, 0x87, 0x06, 0xA4, 0x06, 0xA6, 0x06, 0xA9, 
+    0x06, 0xAD, 0x06, 0xAF, 0x06, 0xB1, 0x06, 0xB3, 0x06, 0xBB, 0x06, 0xBE, 0x06, 0xC1, 0x06, 0xCC, 
+    0x06, 0xD0, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x00, 0x62, 0x00, 0x2E, 
+    0xFE, 0x8C, 0xFE, 0x92, 0xFE, 0x98, 0xFE, 0x9C, 0xFE, 0xA0, 0xFE, 0xA4, 0xFE, 0xA8, 0xFE, 0xB4, 
+    0xFE, 0xB8, 0xFE, 0xBC, 0xFE, 0xC0, 0xFE, 0xC4, 0xFE, 0xC8, 0xFE, 0xCC, 0xFE, 0xD0, 0xFE, 0xD4, 
+    0xFE, 0xD8, 0xFE, 0xDC, 0xFE, 0xE0, 0xFE, 0xE4, 0xFE, 0xE8, 0xFE, 0xEC, 0xFB, 0xE9, 0xFE, 0xF4, 
+    0xFB, 0x69, 0xFB, 0x61, 0xFB, 0x55, 0xFB, 0x59, 0xFB, 0x65, 0xFB, 0x5D, 0xFB, 0x79, 0xFB, 0x75, 
+    0xFB, 0x7D, 0xFB, 0x81, 0xFB, 0x6D, 0xFB, 0x71, 0xFB, 0x91, 0xFB, 0xD6, 0xFB, 0x95, 0xFB, 0x9D, 
+    0xFB, 0x99, 0xFB, 0xA3, 0xFB, 0xAD, 0xFB, 0xA9, 0xFB, 0xFF, 0xFB, 0xE7, 0x00, 0x01, 0x00, 0x2E, 
+    0x06, 0x26, 0x06, 0x28, 0x06, 0x2A, 0x06, 0x2B, 0x06, 0x2C, 0x06, 0x2D, 0x06, 0x2E, 0x06, 0x33, 
+    0x06, 0x34, 0x06, 0x35, 0x06, 0x36, 0x06, 0x37, 0x06, 0x38, 0x06, 0x39, 0x06, 0x3A, 0x06, 0x41, 
+    0x06, 0x42, 0x06, 0x43, 0x06, 0x44, 0x06, 0x45, 0x06, 0x46, 0x06, 0x47, 0x06, 0x49, 0x06, 0x4A, 
+    0x06, 0x79, 0x06, 0x7A, 0x06, 0x7B, 0x06, 0x7E, 0x06, 0x7F, 0x06, 0x80, 0x06, 0x83, 0x06, 0x84, 
+    0x06, 0x86, 0x06, 0x87, 0x06, 0xA4, 0x06, 0xA6, 0x06, 0xA9, 0x06, 0xAD, 0x06, 0xAF, 0x06, 0xB1, 
+    0x06, 0xB3, 0x06, 0xBB, 0x06, 0xBE, 0x06, 0xC1, 0x06, 0xCC, 0x06, 0xD0, 0x00, 0x01, 0x00, 0x00, 
+    0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x00, 0x9A, 0x00, 0x4A, 0xFE, 0x82, 0xFE, 0x84, 0xFE, 0x86, 
+    0xFE, 0x88, 0xFE, 0x8A, 0xFE, 0x8E, 0xFE, 0x90, 0xFE, 0x94, 0xFE, 0x96, 0xFE, 0x9A, 0xFE, 0x9E, 
+    0xFE, 0xA2, 0xFE, 0xA6, 0xFE, 0xAA, 0xFE, 0xAC, 0xFE, 0xAE, 0xFE, 0xB0, 0xFE, 0xB2, 0xFE, 0xB6, 
+    0xFE, 0xBA, 0xFE, 0xBE, 0xFE, 0xC2, 0xFE, 0xC6, 0xFE, 0xCA, 0xFE, 0xCE, 0xFE, 0xD2, 0xFE, 0xD6, 
+    0xFE, 0xDA, 0xFE, 0xDE, 0xFE, 0xE2, 0xFE, 0xE6, 0xFE, 0xEA, 0xFE, 0xEE, 0xFE, 0xF0, 0xFE, 0xF2, 
+    0xFB, 0x51, 0xFB, 0x67, 0xFB, 0x5F, 0xFB, 0x53, 0xFB, 0x57, 0xFB, 0x63, 0xFB, 0x5B, 0xFB, 0x77, 
+    0xFB, 0x73, 0xFB, 0x7B, 0xFB, 0x7F, 0xFB, 0x89, 0xFB, 0x85, 0xFB, 0x83, 0xFB, 0x87, 0xFB, 0x8D, 
+    0xFB, 0x8B, 0xFB, 0x6B, 0xFB, 0x6F, 0xFB, 0x8F, 0xFB, 0xD4, 0xFB, 0x93, 0xFB, 0x9B, 0xFB, 0x97, 
+    0xFB, 0x9F, 0xFB, 0xA1, 0xFB, 0xAB, 0xFB, 0xA5, 0xFB, 0xA7, 0xFB, 0xE1, 0xFB, 0xDA, 0xFB, 0xD8, 
+    0xFB, 0xDC, 0xFB, 0xE3, 0xFB, 0xDF, 0xFB, 0xFD, 0xFB, 0xE5, 0xFB, 0xAF, 0xFB, 0xB1, 0x00, 0x01, 
+    0x00, 0x4A, 0x06, 0x22, 0x06, 0x23, 0x06, 0x24, 0x06, 0x25, 0x06, 0x26, 0x06, 0x27, 0x06, 0x28, 
+    0x06, 0x29, 0x06, 0x2A, 0x06, 0x2B, 0x06, 0x2C, 0x06, 0x2D, 0x06, 0x2E, 0x06, 0x2F, 0x06, 0x30, 
+    0x06, 0x31, 0x06, 0x32, 0x06, 0x33, 0x06, 0x34, 0x06, 0x35, 0x06, 0x36, 0x06, 0x37, 0x06, 0x38, 
+    0x06, 0x39, 0x06, 0x3A, 0x06, 0x41, 0x06, 0x42, 0x06, 0x43, 0x06, 0x44, 0x06, 0x45, 0x06, 0x46, 
+    0x06, 0x47, 0x06, 0x48, 0x06, 0x49, 0x06, 0x4A, 0x06, 0x71, 0x06, 0x79, 0x06, 0x7A, 0x06, 0x7B, 
+    0x06, 0x7E, 0x06, 0x7F, 0x06, 0x80, 0x06, 0x83, 0x06, 0x84, 0x06, 0x86, 0x06, 0x87, 0x06, 0x88, 
+    0x06, 0x8C, 0x06, 0x8D, 0x06, 0x8E, 0x06, 0x91, 0x06, 0x98, 0x06, 0xA4, 0x06, 0xA6, 0x06, 0xA9, 
+    0x06, 0xAD, 0x06, 0xAF, 0x06, 0xB1, 0x06, 0xB3, 0x06, 0xBA, 0x06, 0xBB, 0x06, 0xBE, 0x06, 0xC0, 
+    0x06, 0xC1, 0x06, 0xC5, 0x06, 0xC6, 0x06, 0xC7, 0x06, 0xC8, 0x06, 0xC9, 0x06, 0xCB, 0x06, 0xCC, 
+    0x06, 0xD0, 0x06, 0xD2, 0x06, 0xD3, 0x00, 0x04, 0x00, 0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 
+    0x10, 0x98, 0x00, 0x35, 0x00, 0x70, 0x00, 0x7A, 0x01, 0x0C, 0x01, 0x86, 0x01, 0xA8, 0x01, 0xB2, 
+    0x02, 0x0C, 0x02, 0x62, 0x03, 0x02, 0x03, 0x8A, 0x03, 0xB4, 0x03, 0xF6, 0x04, 0x46, 0x04, 0x8A, 
+    0x04, 0xBC, 0x04, 0xEC, 0x05, 0x26, 0x05, 0x38, 0x05, 0x42, 0x05, 0x64, 0x05, 0xF8, 0x06, 0x6C, 
+    0x06, 0xEC, 0x07, 0x80, 0x08, 0x1E, 0x08, 0x56, 0x08, 0xBA, 0x08, 0xF2, 0x09, 0x38, 0x09, 0x66, 
+    0x09, 0x78, 0x09, 0x82, 0x09, 0xD4, 0x0A, 0x0E, 0x0A, 0x40, 0x0A, 0x70, 0x0A, 0xCC, 0x0A, 0xF2, 
+    0x0B, 0x38, 0x0B, 0x68, 0x0B, 0xDC, 0x0C, 0x2A, 0x0C, 0xD6, 0x0D, 0x72, 0x0E, 0x16, 0x0E, 0x50, 
+    0x0E, 0xC8, 0x0F, 0x5A, 0x0F, 0xA8, 0x0F, 0xB6, 0x0F, 0xC0, 0x0F, 0xCA, 0x10, 0x2E, 0x00, 0x01, 
+    0x00, 0x04, 0xFB, 0xDD, 0x00, 0x02, 0x06, 0x74, 0x00, 0x12, 0x00, 0x26, 0x00, 0x2C, 0x00, 0x32, 
+    0x00, 0x38, 0x00, 0x3E, 0x00, 0x44, 0x00, 0x4A, 0x00, 0x50, 0x00, 0x56, 0x00, 0x5C, 0x00, 0x62, 
+    0x00, 0x68, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x7A, 0x00, 0x80, 0x00, 0x86, 0x00, 0x8C, 0xFB, 0xEC, 
+    0x00, 0x02, 0x00, 0x01, 0xFB, 0xF0, 0x00, 0x02, 0xFB, 0xD8, 0xFB, 0xF2, 0x00, 0x02, 0xFB, 0xDA, 
+    0xFB, 0xF4, 0x00, 0x02, 0xFB, 0xDC, 0xFB, 0xF6, 0x00, 0x02, 0xFB, 0xE5, 0xFB, 0xF8, 0x00, 0x02, 
+    0xFB, 0xE7, 0xFB, 0xEA, 0x00, 0x02, 0xFE, 0x8E, 0xFC, 0x00, 0x00, 0x02, 0xFE, 0x9E, 0xFC, 0x97, 
+    0x00, 0x02, 0xFE, 0xA0, 0xFC, 0x01, 0x00, 0x02, 0xFE, 0xA2, 0xFC, 0x98, 0x00, 0x02, 0xFE, 0xA4, 
+    0xFC, 0x99, 0x00, 0x02, 0xFE, 0xA8, 0xFC, 0x02, 0x00, 0x02, 0xFE, 0xE2, 0xFC, 0x9A, 0x00, 0x02, 
+    0xFE, 0xE4, 0xFC, 0x9B, 0x00, 0x02, 0xFE, 0xEC, 0xFB, 0xEE, 0x00, 0x02, 0xFE, 0xEE, 0xFB, 0xF9, 
+    0x00, 0x02, 0xFE, 0xF0, 0xFB, 0xFB, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x0F, 0x00, 0x20, 0x00, 0x26, 
+    0x00, 0x2C, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x44, 0x00, 0x4A, 0x00, 0x50, 0x00, 0x56, 
+    0x00, 0x5C, 0x00, 0x62, 0x00, 0x68, 0x00, 0x6E, 0x00, 0x74, 0xFB, 0xED, 0x00, 0x02, 0x00, 0x01, 
+    0xFB, 0xF1, 0x00, 0x02, 0xFB, 0xD8, 0xFB, 0xF3, 0x00, 0x02, 0xFB, 0xDA, 0xFB, 0xF5, 0x00, 0x02, 
+    0xFB, 0xDC, 0xFB, 0xF7, 0x00, 0x02, 0xFB, 0xE5, 0xFB, 0xEB, 0x00, 0x02, 0xFE, 0x8E, 0xFC, 0x64, 
+    0x00, 0x02, 0xFE, 0xAE, 0xFC, 0x65, 0x00, 0x02, 0xFE, 0xB0, 0xFC, 0x66, 0x00, 0x02, 0xFE, 0xE2, 
+    0xFC, 0xDF, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0x67, 0x00, 0x02, 0xFE, 0xE6, 0xFC, 0xE0, 0x00, 0x02, 
+    0xFE, 0xEC, 0xFB, 0xEF, 0x00, 0x02, 0xFE, 0xEE, 0xFB, 0xFA, 0x00, 0x02, 0xFE, 0xF0, 0xFC, 0x69, 
+    0x00, 0x02, 0xFE, 0xF2, 0x00, 0x03, 0x00, 0x08, 0x00, 0x0E, 0x00, 0x18, 0xFD, 0x3D, 0x00, 0x02, 
+    0x06, 0x4B, 0xFD, 0xF3, 0x00, 0x04, 0xFE, 0xDB, 0xFE, 0x92, 0xFE, 0xAE, 0xFD, 0xF2, 0x00, 0x04, 
+    0xFE, 0xDF, 0xFE, 0xE0, 0xFE, 0xEA, 0x00, 0x01, 0x00, 0x04, 0xFD, 0x3C, 0x00, 0x02, 0x06, 0x4B, 
+    0x00, 0x0B, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x36, 0x00, 0x3C, 
+    0x00, 0x42, 0x00, 0x48, 0x00, 0x4E, 0x00, 0x54, 0xFC, 0x05, 0x00, 0x02, 0xFE, 0x9E, 0xFC, 0x9C, 
+    0x00, 0x02, 0xFE, 0xA0, 0xFC, 0x06, 0x00, 0x02, 0xFE, 0xA2, 0xFC, 0x9D, 0x00, 0x02, 0xFE, 0xA4, 
+    0xFC, 0x07, 0x00, 0x02, 0xFE, 0xA6, 0xFC, 0x9E, 0x00, 0x02, 0xFE, 0xA8, 0xFC, 0x08, 0x00, 0x02, 
+    0xFE, 0xE2, 0xFC, 0x9F, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0xA0, 0x00, 0x02, 0xFE, 0xEC, 0xFC, 0x09, 
+    0x00, 0x02, 0xFE, 0xF0, 0xFC, 0x0A, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x0A, 0x00, 0x16, 0x00, 0x1E, 
+    0x00, 0x26, 0x00, 0x2C, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x44, 0x00, 0x4A, 0x00, 0x50, 
+    0xFD, 0xC2, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xF2, 0xFD, 0x9E, 0x00, 0x03, 0xFE, 0xA8, 0xFE, 0xF2, 
+    0xFC, 0x6A, 0x00, 0x02, 0xFE, 0xAE, 0xFC, 0x6B, 0x00, 0x02, 0xFE, 0xB0, 0xFC, 0x6C, 0x00, 0x02, 
+    0xFE, 0xE2, 0xFC, 0xE1, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0x6D, 0x00, 0x02, 0xFE, 0xE6, 0xFC, 0xE2, 
+    0x00, 0x02, 0xFE, 0xEC, 0xFC, 0x6E, 0x00, 0x02, 0xFE, 0xF0, 0xFC, 0x6F, 0x00, 0x02, 0xFE, 0xF2, 
+    0x00, 0x12, 0x00, 0x26, 0x00, 0x2C, 0x00, 0x34, 0x00, 0x3A, 0x00, 0x40, 0x00, 0x48, 0x00, 0x50, 
+    0x00, 0x56, 0x00, 0x5C, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 
+    0x00, 0x8E, 0x00, 0x94, 0x00, 0x9A, 0xFC, 0x0B, 0x00, 0x02, 0xFE, 0x9E, 0xFD, 0x50, 0x00, 0x03, 
+    0xFE, 0xA0, 0xFE, 0xE4, 0xFC, 0xA1, 0x00, 0x02, 0xFE, 0xA0, 0xFC, 0x0C, 0x00, 0x02, 0xFE, 0xA2, 
+    0xFD, 0x52, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xA0, 0xFD, 0x53, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xE4, 
+    0xFC, 0xA2, 0x00, 0x02, 0xFE, 0xA4, 0xFC, 0x0D, 0x00, 0x02, 0xFE, 0xA6, 0xFD, 0x54, 0x00, 0x03, 
+    0xFE, 0xA8, 0xFE, 0xE4, 0xFC, 0xA3, 0x00, 0x02, 0xFE, 0xA8, 0xFC, 0x0E, 0x00, 0x02, 0xFE, 0xE2, 
+    0xFD, 0x55, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xA0, 0xFD, 0x56, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xA4, 
+    0xFD, 0x57, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xA8, 0xFC, 0xA4, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0xA5, 
+    0x00, 0x02, 0xFE, 0xEC, 0xFC, 0x0F, 0x00, 0x02, 0xFE, 0xF0, 0xFC, 0x10, 0x00, 0x02, 0xFE, 0xF2, 
+    0x00, 0x0F, 0x00, 0x20, 0x00, 0x28, 0x00, 0x30, 0x00, 0x38, 0x00, 0x40, 0x00, 0x48, 0x00, 0x4E, 
+    0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 0x00, 0x6A, 0x00, 0x70, 0x00, 0x76, 0x00, 0x7C, 0x00, 0x82, 
+    0xFD, 0xA0, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0xF0, 0xFD, 0x9F, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0xF2, 
+    0xFD, 0x51, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0x9E, 0xFD, 0xA2, 0x00, 0x03, 0xFE, 0xA8, 0xFE, 0xF0, 
+    0xFD, 0xA1, 0x00, 0x03, 0xFE, 0xA8, 0xFE, 0xF2, 0xFC, 0x70, 0x00, 0x02, 0xFE, 0xAE, 0xFC, 0x71, 
+    0x00, 0x02, 0xFE, 0xB0, 0xFC, 0x72, 0x00, 0x02, 0xFE, 0xE2, 0xFD, 0xA4, 0x00, 0x03, 0xFE, 0xE4, 
+    0xFE, 0xF0, 0xFD, 0xA3, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xF2, 0xFC, 0xE3, 0x00, 0x02, 0xFE, 0xE4, 
+    0xFC, 0x73, 0x00, 0x02, 0xFE, 0xE6, 0xFC, 0xE4, 0x00, 0x02, 0xFE, 0xEC, 0xFC, 0x74, 0x00, 0x02, 
+    0xFE, 0xF0, 0xFC, 0x75, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 
+    0x00, 0x1E, 0x00, 0x24, 0xFC, 0x11, 0x00, 0x02, 0xFE, 0x9E, 0xFC, 0x12, 0x00, 0x02, 0xFE, 0xE2, 
+    0xFC, 0xA6, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0x13, 0x00, 0x02, 0xFE, 0xF0, 0xFC, 0x14, 0x00, 0x02, 
+    0xFE, 0xF2, 0x00, 0x08, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x00, 0x2A, 0x00, 0x30, 
+    0x00, 0x36, 0x00, 0x3C, 0xFC, 0x76, 0x00, 0x02, 0xFE, 0xAE, 0xFC, 0x77, 0x00, 0x02, 0xFE, 0xB0, 
+    0xFC, 0x78, 0x00, 0x02, 0xFE, 0xE2, 0xFC, 0xE5, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0x79, 0x00, 0x02, 
+    0xFE, 0xE6, 0xFC, 0xE6, 0x00, 0x02, 0xFE, 0xEC, 0xFC, 0x7A, 0x00, 0x02, 0xFE, 0xF0, 0xFC, 0x7B, 
+    0x00, 0x02, 0xFE, 0xF2, 0x00, 0x08, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x30, 0x00, 0x36, 
+    0x00, 0x3E, 0x00, 0x44, 0x00, 0x4A, 0xFC, 0x15, 0x00, 0x02, 0xFE, 0xA2, 0xFC, 0xA7, 0x00, 0x02, 
+    0xFE, 0xA4, 0xFD, 0xFB, 0x00, 0x08, 0xFE, 0xDE, 0x00, 0x20, 0xFE, 0x9F, 0xFE, 0xE0, 0xFE, 0x8E, 
+    0xFE, 0xDF, 0xFE, 0xEA, 0xFC, 0x16, 0x00, 0x02, 0xFE, 0xE2, 0xFD, 0x59, 0x00, 0x03, 0xFE, 0xE4, 
+    0xFE, 0xA4, 0xFC, 0xA8, 0x00, 0x02, 0xFE, 0xE4, 0xFD, 0x01, 0x00, 0x02, 0xFE, 0xF0, 0xFD, 0x02, 
+    0x00, 0x02, 0xFE, 0xF2, 0x00, 0x07, 0x00, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x28, 0x00, 0x30, 
+    0x00, 0x38, 0x00, 0x3E, 0xFD, 0xA6, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xF0, 0xFD, 0xBE, 0x00, 0x03, 
+    0xFE, 0xA4, 0xFE, 0xF2, 0xFD, 0x58, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xA2, 0xFD, 0xA7, 0x00, 0x03, 
+    0xFE, 0xE4, 0xFE, 0xF0, 0xFD, 0xA5, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xF2, 0xFD, 0x1D, 0x00, 0x02, 
+    0xFE, 0xF0, 0xFD, 0x1E, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x1A, 
+    0x00, 0x20, 0x00, 0x26, 0x00, 0x2C, 0xFC, 0x17, 0x00, 0x02, 0xFE, 0x9E, 0xFC, 0xA9, 0x00, 0x02, 
+    0xFE, 0xA0, 0xFC, 0x18, 0x00, 0x02, 0xFE, 0xE2, 0xFC, 0xAA, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0xFF, 
+    0x00, 0x02, 0xFE, 0xF0, 0xFD, 0x00, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x14, 
+    0x00, 0x1C, 0x00, 0x24, 0x00, 0x2A, 0xFD, 0xBF, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0xF2, 0xFD, 0x5B, 
+    0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xF0, 0xFD, 0x5A, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xF2, 0xFD, 0x1B, 
+    0x00, 0x02, 0xFE, 0xF0, 0xFD, 0x1C, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x07, 0x00, 0x10, 0x00, 0x16, 
+    0x00, 0x1C, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0xFC, 0x19, 0x00, 0x02, 0xFE, 0x9E, 
+    0xFC, 0xAB, 0x00, 0x02, 0xFE, 0xA0, 0xFC, 0x1A, 0x00, 0x02, 0xFE, 0xA2, 0xFC, 0x1B, 0x00, 0x02, 
+    0xFE, 0xE2, 0xFC, 0xAC, 0x00, 0x02, 0xFE, 0xE4, 0xFD, 0x03, 0x00, 0x02, 0xFE, 0xF0, 0xFD, 0x04, 
+    0x00, 0x02, 0xFE, 0xF2, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0xFD, 0x1F, 0x00, 0x02, 0xFE, 0xF0, 
+    0xFD, 0x20, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x01, 0x00, 0x04, 0xFC, 0x5B, 0x00, 0x02, 0x06, 0x70, 
+    0x00, 0x03, 0x00, 0x08, 0x00, 0x0E, 0x00, 0x18, 0xFC, 0x5C, 0x00, 0x02, 0x06, 0x70, 0xFD, 0xFC, 
+    0x00, 0x04, 0xFB, 0xFE, 0xFE, 0x8E, 0xFE, 0xDD, 0xFD, 0xF6, 0x00, 0x04, 0xFE, 0xB3, 0xFE, 0xEE, 
+    0xFE, 0xDD, 0x00, 0x11, 0x00, 0x24, 0x00, 0x2A, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x46, 
+    0x00, 0x4C, 0x00, 0x52, 0x00, 0x58, 0x00, 0x5E, 0x00, 0x64, 0x00, 0x6C, 0x00, 0x74, 0x00, 0x7C, 
+    0x00, 0x82, 0x00, 0x88, 0x00, 0x8E, 0xFC, 0x1C, 0x00, 0x02, 0xFE, 0x9E, 0xFD, 0x5D, 0x00, 0x03, 
+    0xFE, 0xA0, 0xFE, 0xA4, 0xFC, 0xAD, 0x00, 0x02, 0xFE, 0xA0, 0xFC, 0x1D, 0x00, 0x02, 0xFE, 0xA2, 
+    0xFD, 0x5C, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xA0, 0xFC, 0xAE, 0x00, 0x02, 0xFE, 0xA4, 0xFC, 0x1E, 
+    0x00, 0x02, 0xFE, 0xA6, 0xFC, 0xAF, 0x00, 0x02, 0xFE, 0xA8, 0xFD, 0x0E, 0x00, 0x02, 0xFE, 0xAE, 
+    0xFC, 0x1F, 0x00, 0x02, 0xFE, 0xE2, 0xFD, 0x61, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xA0, 0xFD, 0x60, 
+    0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xA4, 0xFD, 0x63, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xE4, 0xFC, 0xB0, 
+    0x00, 0x02, 0xFE, 0xE4, 0xFD, 0x31, 0x00, 0x02, 0xFE, 0xEC, 0xFC, 0xFB, 0x00, 0x02, 0xFE, 0xF0, 
+    0xFC, 0xFC, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x0D, 0x00, 0x1C, 0x00, 0x24, 0x00, 0x2A, 0x00, 0x30, 
+    0x00, 0x38, 0x00, 0x40, 0x00, 0x46, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x5C, 0x00, 0x62, 0x00, 0x68, 
+    0x00, 0x6E, 0xFD, 0x5E, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0xF0, 0xFD, 0x34, 0x00, 0x02, 0xFE, 0xA0, 
+    0xFD, 0x35, 0x00, 0x02, 0xFE, 0xA4, 0xFD, 0xA8, 0x00, 0x03, 0xFE, 0xA8, 0xFE, 0xF0, 0xFD, 0xC6, 
+    0x00, 0x03, 0xFE, 0xA8, 0xFE, 0xF2, 0xFD, 0x36, 0x00, 0x02, 0xFE, 0xA8, 0xFD, 0x2A, 0x00, 0x02, 
+    0xFE, 0xAE, 0xFD, 0x5F, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xA2, 0xFD, 0x62, 0x00, 0x03, 0xFE, 0xE4, 
+    0xFE, 0xE2, 0xFC, 0xE7, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0xE8, 0x00, 0x02, 0xFE, 0xEC, 0xFD, 0x17, 
+    0x00, 0x02, 0xFE, 0xF0, 0xFD, 0x18, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x0F, 0x00, 0x20, 0x00, 0x26, 
+    0x00, 0x2C, 0x00, 0x32, 0x00, 0x3A, 0x00, 0x40, 0x00, 0x46, 0x00, 0x4C, 0x00, 0x52, 0x00, 0x58, 
+    0x00, 0x60, 0x00, 0x68, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x7A, 0xFD, 0x09, 0x00, 0x02, 0xFE, 0x9E, 
+    0xFD, 0x2D, 0x00, 0x02, 0xFE, 0xA0, 0xFD, 0x0A, 0x00, 0x02, 0xFE, 0xA2, 0xFD, 0x68, 0x00, 0x03, 
+    0xFE, 0xA4, 0xFE, 0xE4, 0xFD, 0x2E, 0x00, 0x02, 0xFE, 0xA4, 0xFD, 0x0B, 0x00, 0x02, 0xFE, 0xA6, 
+    0xFD, 0x2F, 0x00, 0x02, 0xFE, 0xA8, 0xFD, 0x0D, 0x00, 0x02, 0xFE, 0xAE, 0xFD, 0x0C, 0x00, 0x02, 
+    0xFE, 0xE2, 0xFD, 0x6B, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xA8, 0xFD, 0x6D, 0x00, 0x03, 0xFE, 0xE4, 
+    0xFE, 0xE4, 0xFD, 0x30, 0x00, 0x02, 0xFE, 0xE4, 0xFD, 0x32, 0x00, 0x02, 0xFE, 0xEC, 0xFC, 0xFD, 
+    0x00, 0x02, 0xFE, 0xF0, 0xFC, 0xFE, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x11, 0x00, 0x24, 0x00, 0x2A, 
+    0x00, 0x32, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x46, 0x00, 0x4E, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x60, 
+    0x00, 0x66, 0x00, 0x6C, 0x00, 0x74, 0x00, 0x7C, 0x00, 0x82, 0x00, 0x88, 0x00, 0x8E, 0xFD, 0x25, 
+    0x00, 0x02, 0xFE, 0x9E, 0xFD, 0x69, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0xF2, 0xFD, 0x37, 0x00, 0x02, 
+    0xFE, 0xA0, 0xFD, 0x26, 0x00, 0x02, 0xFE, 0xA2, 0xFD, 0x67, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xE2, 
+    0xFD, 0xAA, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xF2, 0xFD, 0x38, 0x00, 0x02, 0xFE, 0xA4, 0xFD, 0x27, 
+    0x00, 0x02, 0xFE, 0xA6, 0xFD, 0x39, 0x00, 0x02, 0xFE, 0xA8, 0xFD, 0x29, 0x00, 0x02, 0xFE, 0xAE, 
+    0xFD, 0x28, 0x00, 0x02, 0xFE, 0xE2, 0xFD, 0x6A, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xA6, 0xFD, 0x6C, 
+    0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xE2, 0xFC, 0xE9, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0xEA, 0x00, 0x02, 
+    0xFE, 0xEC, 0xFD, 0x19, 0x00, 0x02, 0xFE, 0xF0, 0xFD, 0x1A, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x0E, 
+    0x00, 0x1E, 0x00, 0x24, 0x00, 0x2C, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x46, 0x00, 0x50, 
+    0x00, 0x76, 0x00, 0x7E, 0x00, 0x84, 0x00, 0x8C, 0x00, 0x92, 0x00, 0x98, 0xFC, 0x20, 0x00, 0x02, 
+    0xFE, 0xA2, 0xFD, 0x65, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xA4, 0xFC, 0xB1, 0x00, 0x02, 0xFE, 0xA4, 
+    0xFC, 0xB2, 0x00, 0x02, 0xFE, 0xA8, 0xFD, 0x0F, 0x00, 0x02, 0xFE, 0xAE, 0xFD, 0xF0, 0x00, 0x03, 
+    0xFE, 0xE0, 0xFB, 0xAF, 0xFD, 0xF5, 0x00, 0x04, 0xFE, 0xE0, 0xFE, 0xCC, 0xFE, 0xE2, 0xFD, 0xFA, 
+    0x00, 0x12, 0xFE, 0xE0, 0xFE, 0xF0, 0x00, 0x20, 0xFE, 0x8D, 0xFE, 0xDF, 0xFE, 0xE0, 0xFE, 0xEA, 
+    0x00, 0x20, 0xFE, 0xCB, 0xFE, 0xE0, 0xFE, 0xF4, 0xFE, 0xEA, 0x00, 0x20, 0xFE, 0xED, 0xFE, 0xB3, 
+    0xFE, 0xE0, 0xFE, 0xE2, 0xFD, 0xF9, 0x00, 0x03, 0xFE, 0xE0, 0xFE, 0xF0, 0xFC, 0x21, 0x00, 0x02, 
+    0xFE, 0xE2, 0xFD, 0xC5, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xE4, 0xFC, 0xB3, 0x00, 0x02, 0xFE, 0xE4, 
+    0xFD, 0x05, 0x00, 0x02, 0xFE, 0xF0, 0xFD, 0x06, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x06, 0x00, 0x0E, 
+    0x00, 0x16, 0x00, 0x1E, 0x00, 0x24, 0x00, 0x2C, 0x00, 0x32, 0xFD, 0x64, 0x00, 0x03, 0xFE, 0xA4, 
+    0xFE, 0xA2, 0xFD, 0xA9, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xF2, 0xFD, 0x2B, 0x00, 0x02, 0xFE, 0xAE, 
+    0xFD, 0x66, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xE2, 0xFD, 0x21, 0x00, 0x02, 0xFE, 0xF0, 0xFD, 0x22, 
+    0x00, 0x02, 0xFE, 0xF2, 0x00, 0x0C, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00, 0x2C, 0x00, 0x32, 
+    0x00, 0x38, 0x00, 0x40, 0x00, 0x46, 0x00, 0x4C, 0x00, 0x52, 0x00, 0x58, 0x00, 0x5E, 0xFC, 0x22, 
+    0x00, 0x02, 0xFE, 0x9E, 0xFC, 0xB4, 0x00, 0x02, 0xFE, 0xA0, 0xFC, 0x23, 0x00, 0x02, 0xFE, 0xA2, 
+    0xFC, 0xB5, 0x00, 0x02, 0xFE, 0xA4, 0xFC, 0x24, 0x00, 0x02, 0xFE, 0xA6, 0xFD, 0x70, 0x00, 0x03, 
+    0xFE, 0xA8, 0xFE, 0xE4, 0xFC, 0xB6, 0x00, 0x02, 0xFE, 0xA8, 0xFD, 0x10, 0x00, 0x02, 0xFE, 0xAE, 
+    0xFC, 0x25, 0x00, 0x02, 0xFE, 0xE2, 0xFC, 0xB7, 0x00, 0x02, 0xFE, 0xE4, 0xFD, 0x07, 0x00, 0x02, 
+    0xFE, 0xF0, 0xFD, 0x08, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x16, 0x00, 0x1E, 
+    0x00, 0x26, 0x00, 0x2C, 0x00, 0x32, 0xFD, 0x6E, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xF0, 0xFD, 0xAB, 
+    0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xF2, 0xFD, 0x6F, 0x00, 0x03, 0xFE, 0xA8, 0xFE, 0xE2, 0xFD, 0x2C, 
+    0x00, 0x02, 0xFE, 0xAE, 0xFD, 0x23, 0x00, 0x02, 0xFE, 0xF0, 0xFD, 0x24, 0x00, 0x02, 0xFE, 0xF2, 
+    0x00, 0x08, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x00, 0x2C, 0x00, 0x34, 0x00, 0x3A, 
+    0x00, 0x40, 0xFC, 0x26, 0x00, 0x02, 0xFE, 0xA2, 0xFC, 0xB8, 0x00, 0x02, 0xFE, 0xA4, 0xFC, 0x27, 
+    0x00, 0x02, 0xFE, 0xE2, 0xFD, 0x72, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xA4, 0xFD, 0x73, 0x00, 0x03, 
+    0xFE, 0xE4, 0xFE, 0xE4, 0xFD, 0x33, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0xF5, 0x00, 0x02, 0xFE, 0xF0, 
+    0xFC, 0xF6, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x14, 0x00, 0x1C, 0x00, 0x22, 
+    0x00, 0x28, 0xFD, 0x71, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xA2, 0xFD, 0x74, 0x00, 0x03, 0xFE, 0xE4, 
+    0xFE, 0xF2, 0xFD, 0x3A, 0x00, 0x02, 0xFE, 0xE4, 0xFD, 0x11, 0x00, 0x02, 0xFE, 0xF0, 0xFD, 0x12, 
+    0x00, 0x02, 0xFE, 0xF2, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0xFC, 0x28, 0x00, 0x02, 0xFE, 0xE2, 
+    0xFC, 0xB9, 0x00, 0x02, 0xFE, 0xE4, 0x00, 0x01, 0x00, 0x04, 0xFD, 0x3B, 0x00, 0x02, 0xFE, 0xE4, 
+    0x00, 0x09, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x22, 0x00, 0x28, 0x00, 0x32, 0x00, 0x38, 0x00, 0x40, 
+    0x00, 0x46, 0x00, 0x4C, 0xFC, 0x29, 0x00, 0x02, 0xFE, 0x9E, 0xFD, 0xC4, 0x00, 0x03, 0xFE, 0xA0, 
+    0xFE, 0xE4, 0xFC, 0xBA, 0x00, 0x02, 0xFE, 0xA0, 0xFD, 0xF7, 0x00, 0x04, 0xFE, 0xE0, 0xFE, 0xF4, 
+    0xFE, 0xEA, 0xFC, 0x2A, 0x00, 0x02, 0xFE, 0xE2, 0xFD, 0x77, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xE4, 
+    0xFC, 0xBB, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0xF7, 0x00, 0x02, 0xFE, 0xF0, 0xFC, 0xF8, 0x00, 0x02, 
+    0xFE, 0xF2, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x26, 0x00, 0x2E, 0x00, 0x34, 
+    0xFD, 0x75, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0xE2, 0xFD, 0x76, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xE2, 
+    0xFD, 0x78, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xF0, 0xFD, 0xB6, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xF2, 
+    0xFD, 0x13, 0x00, 0x02, 0xFE, 0xF0, 0xFD, 0x14, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x06, 0x00, 0x0E, 
+    0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00, 0x2C, 0xFC, 0x2B, 0x00, 0x02, 0xFE, 0x9E, 
+    0xFC, 0xBC, 0x00, 0x02, 0xFE, 0xA0, 0xFC, 0x2C, 0x00, 0x02, 0xFE, 0xE2, 0xFC, 0xBD, 0x00, 0x02, 
+    0xFE, 0xE4, 0xFC, 0xF9, 0x00, 0x02, 0xFE, 0xF0, 0xFC, 0xFA, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x05, 
+    0x00, 0x0C, 0x00, 0x14, 0x00, 0x1C, 0x00, 0x24, 0x00, 0x2A, 0xFD, 0x79, 0x00, 0x03, 0xFE, 0xE4, 
+    0xFE, 0xE2, 0xFD, 0x7B, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xF0, 0xFD, 0x7A, 0x00, 0x03, 0xFE, 0xE4, 
+    0xFE, 0xF2, 0xFD, 0x15, 0x00, 0x02, 0xFE, 0xF0, 0xFD, 0x16, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x0B, 
+    0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x36, 0x00, 0x3E, 0x00, 0x44, 
+    0x00, 0x4A, 0x00, 0x50, 0x00, 0x56, 0xFC, 0x2D, 0x00, 0x02, 0xFE, 0x9E, 0xFC, 0xBE, 0x00, 0x02, 
+    0xFE, 0xA0, 0xFC, 0x2E, 0x00, 0x02, 0xFE, 0xA2, 0xFC, 0xBF, 0x00, 0x02, 0xFE, 0xA4, 0xFC, 0x2F, 
+    0x00, 0x02, 0xFE, 0xA6, 0xFD, 0x7D, 0x00, 0x03, 0xFE, 0xA8, 0xFE, 0xE4, 0xFC, 0xC0, 0x00, 0x02, 
+    0xFE, 0xA8, 0xFC, 0x30, 0x00, 0x02, 0xFE, 0xE2, 0xFC, 0xC1, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0x31, 
+    0x00, 0x02, 0xFE, 0xF0, 0xFC, 0x32, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x12, 
+    0x00, 0x1A, 0x00, 0x20, 0xFD, 0x7C, 0x00, 0x03, 0xFE, 0xA8, 0xFE, 0xE2, 0xFD, 0xC1, 0x00, 0x03, 
+    0xFE, 0xE4, 0xFE, 0xF2, 0xFC, 0x7C, 0x00, 0x02, 0xFE, 0xF0, 0xFC, 0x7D, 0x00, 0x02, 0xFE, 0xF2, 
+    0x00, 0x08, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x26, 0x00, 0x2C, 0x00, 0x34, 0x00, 0x3A, 
+    0x00, 0x40, 0xFC, 0x33, 0x00, 0x02, 0xFE, 0xA2, 0xFC, 0xC2, 0x00, 0x02, 0xFE, 0xA4, 0xFD, 0xF1, 
+    0x00, 0x03, 0xFE, 0xE0, 0xFB, 0xAF, 0xFC, 0x34, 0x00, 0x02, 0xFE, 0xE2, 0xFD, 0xB4, 0x00, 0x03, 
+    0xFE, 0xE4, 0xFE, 0xA4, 0xFC, 0xC3, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0x35, 0x00, 0x02, 0xFE, 0xF0, 
+    0xFC, 0x36, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x14, 0x00, 0x1C, 0x00, 0x24, 
+    0x00, 0x2A, 0xFD, 0x7E, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xA2, 0xFD, 0x7F, 0x00, 0x03, 0xFE, 0xE4, 
+    0xFE, 0xE2, 0xFD, 0xB2, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xF2, 0xFC, 0x7E, 0x00, 0x02, 0xFE, 0xF0, 
+    0xFC, 0x7F, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x0E, 0x00, 0x1E, 0x00, 0x24, 0x00, 0x2A, 0x00, 0x30, 
+    0x00, 0x36, 0x00, 0x3C, 0x00, 0x42, 0x00, 0x48, 0x00, 0x4E, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 
+    0x00, 0x68, 0x00, 0x6E, 0xFC, 0x37, 0x00, 0x02, 0xFE, 0x8E, 0xFC, 0x38, 0x00, 0x02, 0xFE, 0x9E, 
+    0xFC, 0xC4, 0x00, 0x02, 0xFE, 0xA0, 0xFC, 0x39, 0x00, 0x02, 0xFE, 0xA2, 0xFC, 0xC5, 0x00, 0x02, 
+    0xFE, 0xA4, 0xFC, 0x3A, 0x00, 0x02, 0xFE, 0xA6, 0xFC, 0xC6, 0x00, 0x02, 0xFE, 0xA8, 0xFC, 0x3B, 
+    0x00, 0x02, 0xFE, 0xDE, 0xFC, 0xC7, 0x00, 0x02, 0xFE, 0xE0, 0xFC, 0x3C, 0x00, 0x02, 0xFE, 0xE2, 
+    0xFD, 0xC3, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xE4, 0xFC, 0xC8, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0x3D, 
+    0x00, 0x02, 0xFE, 0xF0, 0xFC, 0x3E, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x09, 0x00, 0x14, 0x00, 0x1A, 
+    0x00, 0x20, 0x00, 0x26, 0x00, 0x2C, 0x00, 0x34, 0x00, 0x3C, 0x00, 0x42, 0x00, 0x48, 0xFC, 0x80, 
+    0x00, 0x02, 0xFE, 0x8E, 0xFC, 0x81, 0x00, 0x02, 0xFE, 0xDE, 0xFC, 0xEB, 0x00, 0x02, 0xFE, 0xE0, 
+    0xFC, 0x82, 0x00, 0x02, 0xFE, 0xE2, 0xFD, 0xBB, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xE2, 0xFD, 0xB7, 
+    0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xF2, 0xFC, 0xEC, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0x83, 0x00, 0x02, 
+    0xFE, 0xF0, 0xFC, 0x84, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x14, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x36, 
+    0x00, 0x3C, 0x00, 0x42, 0x00, 0x48, 0x00, 0x50, 0x00, 0x58, 0x00, 0x5E, 0x00, 0x64, 0x00, 0x6C, 
+    0x00, 0x72, 0x00, 0x78, 0x00, 0x80, 0x00, 0x86, 0x00, 0x8C, 0x00, 0x94, 0x00, 0x9A, 0x00, 0xA0, 
+    0x00, 0xA6, 0xFE, 0xF5, 0x00, 0x02, 0xFE, 0x82, 0xFE, 0xF7, 0x00, 0x02, 0xFE, 0x84, 0xFE, 0xF9, 
+    0x00, 0x02, 0xFE, 0x88, 0xFE, 0xFB, 0x00, 0x02, 0xFE, 0x8E, 0xFC, 0x3F, 0x00, 0x02, 0xFE, 0x9E, 
+    0xFD, 0x83, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0xA0, 0xFD, 0xBA, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0xE4, 
+    0xFC, 0xC9, 0x00, 0x02, 0xFE, 0xA0, 0xFC, 0x40, 0x00, 0x02, 0xFE, 0xA2, 0xFD, 0xB5, 0x00, 0x03, 
+    0xFE, 0xA4, 0xFE, 0xE4, 0xFC, 0xCA, 0x00, 0x02, 0xFE, 0xA4, 0xFC, 0x41, 0x00, 0x02, 0xFE, 0xA6, 
+    0xFD, 0x86, 0x00, 0x03, 0xFE, 0xA8, 0xFE, 0xE4, 0xFC, 0xCB, 0x00, 0x02, 0xFE, 0xA8, 0xFC, 0x42, 
+    0x00, 0x02, 0xFE, 0xE2, 0xFD, 0x88, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xA4, 0xFC, 0xCC, 0x00, 0x02, 
+    0xFE, 0xE4, 0xFC, 0xCD, 0x00, 0x02, 0xFE, 0xEC, 0xFC, 0x43, 0x00, 0x02, 0xFE, 0xF0, 0xFC, 0x44, 
+    0x00, 0x02, 0xFE, 0xF2, 0x00, 0x11, 0x00, 0x24, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x36, 0x00, 0x3C, 
+    0x00, 0x44, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x5C, 0x00, 0x64, 0x00, 0x6C, 0x00, 0x74, 0x00, 0x7A, 
+    0x00, 0x82, 0x00, 0x8A, 0x00, 0x90, 0x00, 0x96, 0xFE, 0xF6, 0x00, 0x02, 0xFE, 0x82, 0xFE, 0xF8, 
+    0x00, 0x02, 0xFE, 0x84, 0xFE, 0xFA, 0x00, 0x02, 0xFE, 0x88, 0xFE, 0xFC, 0x00, 0x02, 0xFE, 0x8E, 
+    0xFD, 0x84, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0x9E, 0xFD, 0xBC, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0xE2, 
+    0xFD, 0xAC, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0xF2, 0xFD, 0x80, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xE2, 
+    0xFD, 0x82, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xF0, 0xFD, 0x81, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xF2, 
+    0xFD, 0x85, 0x00, 0x03, 0xFE, 0xA8, 0xFE, 0xE2, 0xFC, 0x85, 0x00, 0x02, 0xFE, 0xE2, 0xFD, 0x87, 
+    0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xA2, 0xFD, 0xAD, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xF2, 0xFC, 0xED, 
+    0x00, 0x02, 0xFE, 0xE4, 0xFC, 0x86, 0x00, 0x02, 0xFE, 0xF0, 0xFC, 0x87, 0x00, 0x02, 0xFE, 0xF2, 
+    0x00, 0x12, 0x00, 0x26, 0x00, 0x2C, 0x00, 0x34, 0x00, 0x3C, 0x00, 0x44, 0x00, 0x4A, 0x00, 0x50, 
+    0x00, 0x58, 0x00, 0x62, 0x00, 0x6A, 0x00, 0x70, 0x00, 0x76, 0x00, 0x7E, 0x00, 0x86, 0x00, 0x8C, 
+    0x00, 0x92, 0x00, 0x98, 0x00, 0x9E, 0xFC, 0x45, 0x00, 0x02, 0xFE, 0x9E, 0xFD, 0x8C, 0x00, 0x03, 
+    0xFE, 0xA0, 0xFE, 0xA4, 0xFD, 0x92, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0xA8, 0xFD, 0x8D, 0x00, 0x03, 
+    0xFE, 0xA0, 0xFE, 0xE4, 0xFC, 0xCE, 0x00, 0x02, 0xFE, 0xA0, 0xFC, 0x46, 0x00, 0x02, 0xFE, 0xA2, 
+    0xFD, 0x89, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xA0, 0xFD, 0xF4, 0x00, 0x04, 0xFE, 0xA4, 0xFE, 0xE4, 
+    0xFE, 0xAA, 0xFD, 0x8A, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xE4, 0xFC, 0xCF, 0x00, 0x02, 0xFE, 0xA4, 
+    0xFC, 0x47, 0x00, 0x02, 0xFE, 0xA6, 0xFD, 0x8E, 0x00, 0x03, 0xFE, 0xA8, 0xFE, 0xA0, 0xFD, 0x8F, 
+    0x00, 0x03, 0xFE, 0xA8, 0xFE, 0xE4, 0xFC, 0xD0, 0x00, 0x02, 0xFE, 0xA8, 0xFC, 0x48, 0x00, 0x02, 
+    0xFE, 0xE2, 0xFC, 0xD1, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0x49, 0x00, 0x02, 0xFE, 0xF0, 0xFC, 0x4A, 
+    0x00, 0x02, 0xFE, 0xF2, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x1C, 0x00, 0x24, 0x00, 0x2C, 
+    0x00, 0x32, 0xFC, 0x88, 0x00, 0x02, 0xFE, 0x8E, 0xFD, 0xC0, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0xF2, 
+    0xFD, 0x8B, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xF2, 0xFD, 0xB9, 0x00, 0x03, 0xFE, 0xA8, 0xFE, 0xF2, 
+    0xFC, 0x89, 0x00, 0x02, 0xFE, 0xE2, 0xFD, 0xB1, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xF2, 0x00, 0x0E, 
+    0x00, 0x1E, 0x00, 0x24, 0x00, 0x2C, 0x00, 0x34, 0x00, 0x3A, 0x00, 0x40, 0x00, 0x48, 0x00, 0x4E, 
+    0x00, 0x54, 0x00, 0x5A, 0x00, 0x60, 0x00, 0x66, 0x00, 0x6C, 0x00, 0x72, 0xFC, 0x4B, 0x00, 0x02, 
+    0xFE, 0x9E, 0xFD, 0xB8, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0xA4, 0xFD, 0x98, 0x00, 0x03, 0xFE, 0xA0, 
+    0xFE, 0xE4, 0xFC, 0xD2, 0x00, 0x02, 0xFE, 0xA0, 0xFC, 0x4C, 0x00, 0x02, 0xFE, 0xA2, 0xFD, 0x95, 
+    0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xE4, 0xFC, 0xD3, 0x00, 0x02, 0xFE, 0xA4, 0xFC, 0x4D, 0x00, 0x02, 
+    0xFE, 0xA6, 0xFC, 0xD4, 0x00, 0x02, 0xFE, 0xA8, 0xFC, 0x4E, 0x00, 0x02, 0xFE, 0xE2, 0xFC, 0xD5, 
+    0x00, 0x02, 0xFE, 0xE4, 0xFC, 0xD6, 0x00, 0x02, 0xFE, 0xEC, 0xFC, 0x4F, 0x00, 0x02, 0xFE, 0xF0, 
+    0xFC, 0x50, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x10, 0x00, 0x22, 0x00, 0x2A, 0x00, 0x32, 0x00, 0x3A, 
+    0x00, 0x42, 0x00, 0x4A, 0x00, 0x52, 0x00, 0x58, 0x00, 0x5E, 0x00, 0x64, 0x00, 0x6C, 0x00, 0x74, 
+    0x00, 0x7A, 0x00, 0x80, 0x00, 0x86, 0x00, 0x8C, 0xFD, 0xBD, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0xA2, 
+    0xFD, 0x97, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0xE2, 0xFD, 0x99, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0xF0, 
+    0xFD, 0xC7, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0xF2, 0xFD, 0x96, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xF0, 
+    0xFD, 0xB3, 0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xF2, 0xFC, 0x8A, 0x00, 0x02, 0xFE, 0xAE, 0xFC, 0x8B, 
+    0x00, 0x02, 0xFE, 0xB0, 0xFC, 0x8C, 0x00, 0x02, 0xFE, 0xE2, 0xFD, 0x9B, 0x00, 0x03, 0xFE, 0xE4, 
+    0xFE, 0xF0, 0xFD, 0x9A, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xF2, 0xFC, 0xEE, 0x00, 0x02, 0xFE, 0xE4, 
+    0xFC, 0x8D, 0x00, 0x02, 0xFE, 0xE6, 0xFC, 0xEF, 0x00, 0x02, 0xFE, 0xEC, 0xFC, 0x8E, 0x00, 0x02, 
+    0xFE, 0xF0, 0xFC, 0x8F, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x09, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 
+    0x00, 0x26, 0x00, 0x2C, 0x00, 0x34, 0x00, 0x3C, 0x00, 0x42, 0x00, 0x48, 0xFC, 0xD9, 0x00, 0x02, 
+    0x06, 0x70, 0xFC, 0x51, 0x00, 0x02, 0xFE, 0x9E, 0xFC, 0xD7, 0x00, 0x02, 0xFE, 0xA0, 0xFC, 0x52, 
+    0x00, 0x02, 0xFE, 0xE2, 0xFD, 0x93, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xA0, 0xFD, 0x94, 0x00, 0x03, 
+    0xFE, 0xE4, 0xFE, 0xE4, 0xFC, 0xD8, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0x53, 0x00, 0x02, 0xFE, 0xF0, 
+    0xFC, 0x54, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x01, 0x00, 0x04, 0xFD, 0xF8, 0x00, 0x04, 0xFE, 0xB3, 
+    0xFE, 0xE0, 0xFE, 0xE2, 0x00, 0x01, 0x00, 0x04, 0xFC, 0x5D, 0x00, 0x02, 0x06, 0x70, 0x00, 0x01, 
+    0x00, 0x04, 0xFC, 0x90, 0x00, 0x02, 0x06, 0x70, 0x00, 0x0C, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 
+    0x00, 0x2C, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x44, 0x00, 0x4C, 0x00, 0x52, 0x00, 0x58, 
+    0x00, 0x5E, 0xFC, 0x55, 0x00, 0x02, 0xFE, 0x9E, 0xFC, 0xDA, 0x00, 0x02, 0xFE, 0xA0, 0xFC, 0x56, 
+    0x00, 0x02, 0xFE, 0xA2, 0xFC, 0xDB, 0x00, 0x02, 0xFE, 0xA4, 0xFC, 0x57, 0x00, 0x02, 0xFE, 0xA6, 
+    0xFC, 0xDC, 0x00, 0x02, 0xFE, 0xA8, 0xFC, 0x58, 0x00, 0x02, 0xFE, 0xE2, 0xFD, 0x9D, 0x00, 0x03, 
+    0xFE, 0xE4, 0xFE, 0xE4, 0xFC, 0xDD, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0xDE, 0x00, 0x02, 0xFE, 0xEC, 
+    0xFC, 0x59, 0x00, 0x02, 0xFE, 0xF0, 0xFC, 0x5A, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x0C, 0x00, 0x1A, 
+    0x00, 0x22, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x36, 0x00, 0x3C, 0x00, 0x44, 0x00, 0x4C, 0x00, 0x52, 
+    0x00, 0x58, 0x00, 0x5E, 0x00, 0x64, 0xFD, 0xAF, 0x00, 0x03, 0xFE, 0xA0, 0xFE, 0xF2, 0xFD, 0xAE, 
+    0x00, 0x03, 0xFE, 0xA4, 0xFE, 0xF2, 0xFC, 0x91, 0x00, 0x02, 0xFE, 0xAE, 0xFC, 0x92, 0x00, 0x02, 
+    0xFE, 0xB0, 0xFC, 0x93, 0x00, 0x02, 0xFE, 0xE2, 0xFD, 0x9C, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xE2, 
+    0xFD, 0xB0, 0x00, 0x03, 0xFE, 0xE4, 0xFE, 0xF2, 0xFC, 0xF0, 0x00, 0x02, 0xFE, 0xE4, 0xFC, 0x94, 
+    0x00, 0x02, 0xFE, 0xE6, 0xFC, 0xF1, 0x00, 0x02, 0xFE, 0xEC, 0xFC, 0x95, 0x00, 0x02, 0xFE, 0xF0, 
+    0xFC, 0x96, 0x00, 0x02, 0xFE, 0xF2, 0x00, 0x01, 0x00, 0x35, 0xFB, 0xD7, 0xFE, 0x8B, 0xFE, 0x8C, 
+    0xFE, 0x8D, 0xFE, 0x8E, 0xFE, 0x91, 0xFE, 0x92, 0xFE, 0x97, 0xFE, 0x98, 0xFE, 0x9B, 0xFE, 0x9C, 
+    0xFE, 0x9F, 0xFE, 0xA0, 0xFE, 0xA3, 0xFE, 0xA4, 0xFE, 0xA7, 0xFE, 0xA8, 0xFE, 0xAB, 0xFE, 0xAD, 
+    0xFE, 0xB3, 0xFE, 0xB4, 0xFE, 0xB7, 0xFE, 0xB8, 0xFE, 0xBB, 0xFE, 0xBC, 0xFE, 0xBF, 0xFE, 0xC0, 
+    0xFE, 0xC3, 0xFE, 0xC4, 0xFE, 0xC7, 0xFE, 0xC8, 0xFE, 0xCB, 0xFE, 0xCC, 0xFE, 0xCF, 0xFE, 0xD0, 
+    0xFE, 0xD3, 0xFE, 0xD4, 0xFE, 0xD7, 0xFE, 0xD8, 0xFE, 0xDB, 0xFE, 0xDC, 0xFE, 0xDF, 0xFE, 0xE0, 
+    0xFE, 0xE3, 0xFE, 0xE4, 0xFE, 0xE7, 0xFE, 0xE8, 0xFE, 0xEB, 0xFE, 0xED, 0xFE, 0xEF, 0xFE, 0xF0, 
+    0xFE, 0xF3, 0xFE, 0xF4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x1A, 
+    0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x09, 0xCB, 0x00, 0x02, 0x09, 0xBE, 
+    0x09, 0xCC, 0x00, 0x02, 0x09, 0xD7, 0x00, 0x01, 0x00, 0x01, 0x09, 0xC7, 0x00, 0x02, 0x00, 0x00, 
+    0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x16, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x02, 
+    0x09, 0xC7, 0x09, 0xBE, 0x00, 0x02, 0x09, 0xC7, 0x09, 0xD7, 0x00, 0x01, 0x00, 0x02, 0x09, 0xCB, 
+    0x09, 0xCC, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x02, 0x66, 0x00, 0x20, 
+    0x00, 0x46, 0x00, 0x50, 0x00, 0x62, 0x00, 0x74, 0x00, 0x96, 0x00, 0xA8, 0x00, 0xB2, 0x00, 0xDC, 
+    0x00, 0xEE, 0x00, 0xF8, 0x01, 0x1A, 0x01, 0x24, 0x01, 0x2E, 0x01, 0x38, 0x01, 0x4A, 0x01, 0x5C, 
+    0x01, 0x7E, 0x01, 0x90, 0x01, 0x9A, 0x01, 0xC4, 0x01, 0xD6, 0x01, 0xE0, 0x02, 0x02, 0x02, 0x0C, 
+    0x02, 0x16, 0x02, 0x20, 0x02, 0x2A, 0x02, 0x34, 0x02, 0x3E, 0x02, 0x48, 0x02, 0x52, 0x02, 0x5C, 
+    0x00, 0x01, 0x00, 0x04, 0x04, 0x07, 0x00, 0x02, 0x03, 0x08, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 
+    0x04, 0xD0, 0x00, 0x02, 0x03, 0x06, 0x04, 0xD2, 0x00, 0x02, 0x03, 0x08, 0x00, 0x02, 0x00, 0x06, 
+    0x00, 0x0C, 0x04, 0x03, 0x00, 0x02, 0x03, 0x01, 0x04, 0x03, 0x00, 0x02, 0x03, 0x41, 0x00, 0x04, 
+    0x00, 0x0A, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x04, 0xD6, 
+    0x00, 0x02, 0x03, 0x06, 0x04, 0x01, 0x00, 0x02, 0x03, 0x08, 0x04, 0x00, 0x00, 0x02, 0x03, 0x40, 
+    0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x04, 0xC1, 0x00, 0x02, 0x03, 0x06, 0x04, 0xDC, 0x00, 0x02, 
+    0x03, 0x08, 0x00, 0x01, 0x00, 0x04, 0x04, 0xDE, 0x00, 0x02, 0x03, 0x08, 0x00, 0x05, 0x00, 0x0C, 
+    0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x04, 0x0D, 0x00, 0x02, 0x03, 0x00, 0x04, 0xE2, 
+    0x00, 0x02, 0x03, 0x04, 0x04, 0x19, 0x00, 0x02, 0x03, 0x06, 0x04, 0xE4, 0x00, 0x02, 0x03, 0x08, 
+    0x04, 0x0D, 0x00, 0x02, 0x03, 0x40, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x04, 0x0C, 0x00, 0x02, 
+    0x03, 0x01, 0x04, 0x0C, 0x00, 0x02, 0x03, 0x41, 0x00, 0x01, 0x00, 0x04, 0x04, 0xE6, 0x00, 0x02, 
+    0x03, 0x08, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 0x04, 0xEE, 0x00, 0x02, 
+    0x03, 0x04, 0x04, 0x0E, 0x00, 0x02, 0x03, 0x06, 0x04, 0xF0, 0x00, 0x02, 0x03, 0x08, 0x04, 0xF2, 
+    0x00, 0x02, 0x03, 0x0B, 0x00, 0x01, 0x00, 0x04, 0x04, 0xF4, 0x00, 0x02, 0x03, 0x08, 0x00, 0x01, 
+    0x00, 0x04, 0x04, 0xF8, 0x00, 0x02, 0x03, 0x08, 0x00, 0x01, 0x00, 0x04, 0x04, 0xEC, 0x00, 0x02, 
+    0x03, 0x08, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x04, 0xD1, 0x00, 0x02, 0x03, 0x06, 0x04, 0xD3, 
+    0x00, 0x02, 0x03, 0x08, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x04, 0x53, 0x00, 0x02, 0x03, 0x01, 
+    0x04, 0x53, 0x00, 0x02, 0x03, 0x41, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 
+    0x04, 0x50, 0x00, 0x02, 0x03, 0x00, 0x04, 0xD7, 0x00, 0x02, 0x03, 0x06, 0x04, 0x51, 0x00, 0x02, 
+    0x03, 0x08, 0x04, 0x50, 0x00, 0x02, 0x03, 0x40, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x04, 0xC2, 
+    0x00, 0x02, 0x03, 0x06, 0x04, 0xDD, 0x00, 0x02, 0x03, 0x08, 0x00, 0x01, 0x00, 0x04, 0x04, 0xDF, 
+    0x00, 0x02, 0x03, 0x08, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 
+    0x04, 0x5D, 0x00, 0x02, 0x03, 0x00, 0x04, 0xE3, 0x00, 0x02, 0x03, 0x04, 0x04, 0x39, 0x00, 0x02, 
+    0x03, 0x06, 0x04, 0xE5, 0x00, 0x02, 0x03, 0x08, 0x04, 0x5D, 0x00, 0x02, 0x03, 0x40, 0x00, 0x02, 
+    0x00, 0x06, 0x00, 0x0C, 0x04, 0x5C, 0x00, 0x02, 0x03, 0x01, 0x04, 0x5C, 0x00, 0x02, 0x03, 0x41, 
+    0x00, 0x01, 0x00, 0x04, 0x04, 0xE7, 0x00, 0x02, 0x03, 0x08, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x10, 
+    0x00, 0x16, 0x00, 0x1C, 0x04, 0xEF, 0x00, 0x02, 0x03, 0x04, 0x04, 0x5E, 0x00, 0x02, 0x03, 0x06, 
+    0x04, 0xF1, 0x00, 0x02, 0x03, 0x08, 0x04, 0xF3, 0x00, 0x02, 0x03, 0x0B, 0x00, 0x01, 0x00, 0x04, 
+    0x04, 0xF5, 0x00, 0x02, 0x03, 0x08, 0x00, 0x01, 0x00, 0x04, 0x04, 0xF9, 0x00, 0x02, 0x03, 0x08, 
+    0x00, 0x01, 0x00, 0x04, 0x04, 0xED, 0x00, 0x02, 0x03, 0x08, 0x00, 0x01, 0x00, 0x04, 0x04, 0x57, 
+    0x00, 0x02, 0x03, 0x08, 0x00, 0x01, 0x00, 0x04, 0x04, 0x76, 0x00, 0x02, 0x03, 0x0F, 0x00, 0x01, 
+    0x00, 0x04, 0x04, 0x77, 0x00, 0x02, 0x03, 0x0F, 0x00, 0x01, 0x00, 0x04, 0x04, 0xDA, 0x00, 0x02, 
+    0x03, 0x08, 0x00, 0x01, 0x00, 0x04, 0x04, 0xDB, 0x00, 0x02, 0x03, 0x08, 0x00, 0x01, 0x00, 0x04, 
+    0x04, 0xEA, 0x00, 0x02, 0x03, 0x08, 0x00, 0x01, 0x00, 0x04, 0x04, 0xEB, 0x00, 0x02, 0x03, 0x08, 
+    0x00, 0x01, 0x00, 0x20, 0x04, 0x06, 0x04, 0x10, 0x04, 0x13, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 
+    0x04, 0x18, 0x04, 0x1A, 0x04, 0x1E, 0x04, 0x23, 0x04, 0x27, 0x04, 0x2B, 0x04, 0x2D, 0x04, 0x30, 
+    0x04, 0x33, 0x04, 0x35, 0x04, 0x36, 0x04, 0x37, 0x04, 0x38, 0x04, 0x3A, 0x04, 0x3E, 0x04, 0x43, 
+    0x04, 0x47, 0x04, 0x4B, 0x04, 0x4D, 0x04, 0x56, 0x04, 0x74, 0x04, 0x75, 0x04, 0xD8, 0x04, 0xD9, 
+    0x04, 0xE8, 0x04, 0xE9, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x0A, 0x02, 0x1C, 0x00, 0x01, 
+    0x01, 0xA6, 0x00, 0x34, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x7A, 0x00, 0x80, 0x00, 0x86, 0x00, 0x8C, 
+    0x00, 0x92, 0x00, 0x98, 0x00, 0x9E, 0x00, 0xA4, 0x00, 0xAA, 0x00, 0xB0, 0x00, 0xB6, 0x00, 0xBC, 
+    0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00, 0xD4, 0x00, 0xDA, 0x00, 0xE0, 0x00, 0xE6, 0x00, 0xEC, 
+    0x00, 0xF2, 0x00, 0xF8, 0x00, 0xFE, 0x01, 0x04, 0x01, 0x0A, 0x01, 0x10, 0x01, 0x16, 0x01, 0x1C, 
+    0x01, 0x22, 0x01, 0x28, 0x01, 0x2E, 0x01, 0x34, 0x01, 0x3A, 0x01, 0x40, 0x01, 0x46, 0x01, 0x4C, 
+    0x01, 0x52, 0x01, 0x58, 0x01, 0x5E, 0x01, 0x64, 0x01, 0x6A, 0x01, 0x70, 0x01, 0x76, 0x01, 0x7C, 
+    0x01, 0x82, 0x01, 0x88, 0x01, 0x8E, 0x01, 0x94, 0x01, 0x9A, 0x01, 0xA0, 0x00, 0x02, 0x04, 0x15, 
+    0x03, 0x00, 0x00, 0x02, 0x04, 0x15, 0x03, 0x08, 0x00, 0x02, 0x04, 0x13, 0x03, 0x01, 0x00, 0x02, 
+    0x04, 0x06, 0x03, 0x08, 0x00, 0x02, 0x04, 0x1A, 0x03, 0x01, 0x00, 0x02, 0x04, 0x18, 0x03, 0x00, 
+    0x00, 0x02, 0x04, 0x23, 0x03, 0x06, 0x00, 0x02, 0x04, 0x18, 0x03, 0x06, 0x00, 0x02, 0x04, 0x38, 
+    0x03, 0x06, 0x00, 0x02, 0x04, 0x35, 0x03, 0x00, 0x00, 0x02, 0x04, 0x35, 0x03, 0x08, 0x00, 0x02, 
+    0x04, 0x33, 0x03, 0x01, 0x00, 0x02, 0x04, 0x56, 0x03, 0x08, 0x00, 0x02, 0x04, 0x3A, 0x03, 0x01, 
+    0x00, 0x02, 0x04, 0x38, 0x03, 0x00, 0x00, 0x02, 0x04, 0x43, 0x03, 0x06, 0x00, 0x02, 0x04, 0x74, 
+    0x03, 0x0F, 0x00, 0x02, 0x04, 0x75, 0x03, 0x0F, 0x00, 0x02, 0x04, 0x16, 0x03, 0x06, 0x00, 0x02, 
+    0x04, 0x36, 0x03, 0x06, 0x00, 0x02, 0x04, 0x10, 0x03, 0x06, 0x00, 0x02, 0x04, 0x30, 0x03, 0x06, 
+    0x00, 0x02, 0x04, 0x10, 0x03, 0x08, 0x00, 0x02, 0x04, 0x30, 0x03, 0x08, 0x00, 0x02, 0x04, 0x15, 
+    0x03, 0x06, 0x00, 0x02, 0x04, 0x35, 0x03, 0x06, 0x00, 0x02, 0x04, 0xD8, 0x03, 0x08, 0x00, 0x02, 
+    0x04, 0xD9, 0x03, 0x08, 0x00, 0x02, 0x04, 0x16, 0x03, 0x08, 0x00, 0x02, 0x04, 0x36, 0x03, 0x08, 
+    0x00, 0x02, 0x04, 0x17, 0x03, 0x08, 0x00, 0x02, 0x04, 0x37, 0x03, 0x08, 0x00, 0x02, 0x04, 0x18, 
+    0x03, 0x04, 0x00, 0x02, 0x04, 0x38, 0x03, 0x04, 0x00, 0x02, 0x04, 0x18, 0x03, 0x08, 0x00, 0x02, 
+    0x04, 0x38, 0x03, 0x08, 0x00, 0x02, 0x04, 0x1E, 0x03, 0x08, 0x00, 0x02, 0x04, 0x3E, 0x03, 0x08, 
+    0x00, 0x02, 0x04, 0xE8, 0x03, 0x08, 0x00, 0x02, 0x04, 0xE9, 0x03, 0x08, 0x00, 0x02, 0x04, 0x2D, 
+    0x03, 0x08, 0x00, 0x02, 0x04, 0x4D, 0x03, 0x08, 0x00, 0x02, 0x04, 0x23, 0x03, 0x04, 0x00, 0x02, 
+    0x04, 0x43, 0x03, 0x04, 0x00, 0x02, 0x04, 0x23, 0x03, 0x08, 0x00, 0x02, 0x04, 0x43, 0x03, 0x08, 
+    0x00, 0x02, 0x04, 0x23, 0x03, 0x0B, 0x00, 0x02, 0x04, 0x43, 0x03, 0x0B, 0x00, 0x02, 0x04, 0x27, 
+    0x03, 0x08, 0x00, 0x02, 0x04, 0x47, 0x03, 0x08, 0x00, 0x02, 0x04, 0x2B, 0x03, 0x08, 0x00, 0x02, 
+    0x04, 0x4B, 0x03, 0x08, 0x00, 0x01, 0x00, 0x34, 0x04, 0x00, 0x04, 0x01, 0x04, 0x03, 0x04, 0x07, 
+    0x04, 0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x19, 0x04, 0x39, 0x04, 0x50, 0x04, 0x51, 0x04, 0x53, 
+    0x04, 0x57, 0x04, 0x5C, 0x04, 0x5D, 0x04, 0x5E, 0x04, 0x76, 0x04, 0x77, 0x04, 0xC1, 0x04, 0xC2, 
+    0x04, 0xD0, 0x04, 0xD1, 0x04, 0xD2, 0x04, 0xD3, 0x04, 0xD6, 0x04, 0xD7, 0x04, 0xDA, 0x04, 0xDB, 
+    0x04, 0xDC, 0x04, 0xDD, 0x04, 0xDE, 0x04, 0xDF, 0x04, 0xE2, 0x04, 0xE3, 0x04, 0xE4, 0x04, 0xE5, 
+    0x04, 0xE6, 0x04, 0xE7, 0x04, 0xEA, 0x04, 0xEB, 0x04, 0xEC, 0x04, 0xED, 0x04, 0xEE, 0x04, 0xEF, 
+    0x04, 0xF0, 0x04, 0xF1, 0x04, 0xF2, 0x04, 0xF3, 0x04, 0xF4, 0x04, 0xF5, 0x04, 0xF8, 0x04, 0xF9, 
+    0x00, 0x01, 0x00, 0x46, 0x00, 0x08, 0x00, 0x16, 0x00, 0x1C, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2E, 
+    0x00, 0x34, 0x00, 0x3A, 0x00, 0x40, 0x00, 0x02, 0x04, 0x15, 0x03, 0x40, 0x00, 0x02, 0x04, 0x13, 
+    0x03, 0x41, 0x00, 0x02, 0x04, 0x1A, 0x03, 0x41, 0x00, 0x02, 0x04, 0x18, 0x03, 0x40, 0x00, 0x02, 
+    0x04, 0x35, 0x03, 0x40, 0x00, 0x02, 0x04, 0x33, 0x03, 0x41, 0x00, 0x02, 0x04, 0x3A, 0x03, 0x41, 
+    0x00, 0x02, 0x04, 0x38, 0x03, 0x40, 0x00, 0x01, 0x00, 0x08, 0x04, 0x00, 0x04, 0x03, 0x04, 0x0C, 
+    0x04, 0x0D, 0x04, 0x50, 0x04, 0x53, 0x04, 0x5C, 0x04, 0x5D, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 
+    0x00, 0x08, 0x00, 0x01, 0x00, 0x2A, 0x00, 0x03, 0x00, 0x0C, 0x00, 0x16, 0x00, 0x20, 0x00, 0x01, 
+    0x00, 0x04, 0x09, 0x29, 0x00, 0x02, 0x09, 0x3C, 0x00, 0x01, 0x00, 0x04, 0x09, 0x31, 0x00, 0x02, 
+    0x09, 0x3C, 0x00, 0x01, 0x00, 0x04, 0x09, 0x34, 0x00, 0x02, 0x09, 0x3C, 0x00, 0x01, 0x00, 0x03, 
+    0x09, 0x28, 0x09, 0x30, 0x09, 0x33, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 
+    0x00, 0x1E, 0x00, 0x03, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x02, 0x09, 0x28, 0x09, 0x3C, 
+    0x00, 0x02, 0x09, 0x30, 0x09, 0x3C, 0x00, 0x02, 0x09, 0x33, 0x09, 0x3C, 0x00, 0x01, 0x00, 0x03, 
+    0x09, 0x29, 0x09, 0x31, 0x09, 0x34, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 
+    0x33, 0x04, 0x00, 0x75, 0x00, 0xF0, 0x01, 0x1A, 0x04, 0x5A, 0x05, 0x0C, 0x08, 0x3C, 0x09, 0x24, 
+    0x09, 0xD6, 0x09, 0xE0, 0x0A, 0x54, 0x0D, 0x84, 0x0D, 0x8E, 0x0D, 0x98, 0x11, 0x44, 0x11, 0xF6, 
+    0x15, 0x92, 0x16, 0xBC, 0x17, 0x6E, 0x17, 0x88, 0x18, 0xB2, 0x1C, 0x4E, 0x1C, 0x78, 0x1C, 0xA2, 
+    0x1C, 0xAC, 0x1C, 0xC6, 0x1D, 0x5C, 0x1D, 0xF2, 0x1D, 0xFC, 0x1E, 0x06, 0x1E, 0x10, 0x1E, 0x1A, 
+    0x1E, 0x24, 0x1E, 0x2E, 0x1E, 0xC4, 0x1F, 0x5A, 0x1F, 0x64, 0x1F, 0x6E, 0x1F, 0x78, 0x1F, 0x82, 
+    0x1F, 0x8C, 0x1F, 0x96, 0x1F, 0xB8, 0x1F, 0xDA, 0x1F, 0xFC, 0x20, 0x1E, 0x20, 0xB4, 0x21, 0x4A, 
+    0x21, 0x54, 0x21, 0x5E, 0x21, 0x68, 0x21, 0x72, 0x21, 0x7C, 0x21, 0x86, 0x22, 0x1C, 0x22, 0xB2, 
+    0x22, 0xBC, 0x22, 0xC6, 0x22, 0xD0, 0x22, 0xDA, 0x22, 0xE4, 0x22, 0xEE, 0x23, 0x18, 0x23, 0x42, 
+    0x23, 0x6C, 0x23, 0x96, 0x23, 0xB8, 0x23, 0xDA, 0x23, 0xFC, 0x24, 0x1E, 0x24, 0x48, 0x24, 0x72, 
+    0x24, 0x9C, 0x25, 0x32, 0x25, 0xC8, 0x25, 0xD2, 0x25, 0xDC, 0x25, 0xE6, 0x25, 0xF0, 0x25, 0xFA, 
+    0x26, 0x04, 0x26, 0x9A, 0x27, 0x30, 0x27, 0x3A, 0x27, 0x44, 0x27, 0x4E, 0x27, 0x58, 0x27, 0x62, 
+    0x27, 0x6C, 0x27, 0x76, 0x27, 0x80, 0x27, 0x8A, 0x27, 0x94, 0x27, 0x9E, 0x27, 0xA8, 0x27, 0xD2, 
+    0x27, 0xFC, 0x28, 0x26, 0x28, 0x50, 0x28, 0x7A, 0x28, 0xA4, 0x28, 0xCE, 0x28, 0xF8, 0x29, 0x22, 
+    0x29, 0x4C, 0x29, 0x76, 0x29, 0xA0, 0x2A, 0x78, 0x2A, 0x82, 0x2B, 0x32, 0x2C, 0x5C, 0x2C, 0x86, 
+    0x2D, 0x5E, 0x2D, 0x68, 0x2E, 0x18, 0x2E, 0xF0, 0x2E, 0xFA, 0x2F, 0xAA, 0x2F, 0xD4, 0x00, 0x05, 
+    0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x1F, 0xED, 0x00, 0x02, 0x03, 0x00, 
+    0x03, 0x85, 0x00, 0x02, 0x03, 0x01, 0x1F, 0xED, 0x00, 0x02, 0x03, 0x40, 0x03, 0x85, 0x00, 0x02, 
+    0x03, 0x41, 0x1F, 0xC1, 0x00, 0x02, 0x03, 0x42, 0x00, 0x4C, 0x00, 0x9A, 0x00, 0xA0, 0x00, 0xA6, 
+    0x00, 0xAC, 0x00, 0xB2, 0x00, 0xBC, 0x00, 0xC4, 0x00, 0xCE, 0x00, 0xD6, 0x00, 0xE0, 0x00, 0xE8, 
+    0x00, 0xF2, 0x00, 0xFA, 0x01, 0x04, 0x01, 0x0C, 0x01, 0x16, 0x01, 0x20, 0x01, 0x2A, 0x01, 0x34, 
+    0x01, 0x3E, 0x01, 0x46, 0x01, 0x4C, 0x01, 0x56, 0x01, 0x5E, 0x01, 0x68, 0x01, 0x70, 0x01, 0x7A, 
+    0x01, 0x82, 0x01, 0x8C, 0x01, 0x94, 0x01, 0x9E, 0x01, 0xA6, 0x01, 0xB0, 0x01, 0xBA, 0x01, 0xC4, 
+    0x01, 0xCE, 0x01, 0xD8, 0x01, 0xE0, 0x01, 0xE6, 0x01, 0xEC, 0x01, 0xF2, 0x01, 0xFC, 0x02, 0x04, 
+    0x02, 0x0E, 0x02, 0x16, 0x02, 0x20, 0x02, 0x28, 0x02, 0x32, 0x02, 0x3A, 0x02, 0x44, 0x02, 0x4C, 
+    0x02, 0x56, 0x02, 0x60, 0x02, 0x6A, 0x02, 0x74, 0x02, 0x7E, 0x02, 0x86, 0x02, 0x8C, 0x02, 0x96, 
+    0x02, 0xA0, 0x02, 0xAA, 0x02, 0xB4, 0x02, 0xBE, 0x02, 0xC6, 0x02, 0xD0, 0x02, 0xDA, 0x02, 0xE4, 
+    0x02, 0xEE, 0x02, 0xF8, 0x03, 0x00, 0x03, 0x0A, 0x03, 0x14, 0x03, 0x1E, 0x03, 0x28, 0x03, 0x32, 
+    0x03, 0x3A, 0x1F, 0xBA, 0x00, 0x02, 0x03, 0x00, 0x03, 0x86, 0x00, 0x02, 0x03, 0x01, 0x1F, 0xB9, 
+    0x00, 0x02, 0x03, 0x04, 0x1F, 0xB8, 0x00, 0x02, 0x03, 0x06, 0x1F, 0x8A, 0x00, 0x04, 0x03, 0x13, 
+    0x03, 0x00, 0x03, 0x45, 0x1F, 0x0A, 0x00, 0x03, 0x03, 0x13, 0x03, 0x00, 0x1F, 0x8C, 0x00, 0x04, 
+    0x03, 0x13, 0x03, 0x01, 0x03, 0x45, 0x1F, 0x0C, 0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 0x1F, 0x8A, 
+    0x00, 0x04, 0x03, 0x13, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x0A, 0x00, 0x03, 0x03, 0x13, 0x03, 0x40, 
+    0x1F, 0x8C, 0x00, 0x04, 0x03, 0x13, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x0C, 0x00, 0x03, 0x03, 0x13, 
+    0x03, 0x41, 0x1F, 0x8E, 0x00, 0x04, 0x03, 0x13, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x0E, 0x00, 0x03, 
+    0x03, 0x13, 0x03, 0x42, 0x1F, 0x8A, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x00, 0x1F, 0x8C, 
+    0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x01, 0x1F, 0x8A, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 
+    0x03, 0x40, 0x1F, 0x8C, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x41, 0x1F, 0x8E, 0x00, 0x04, 
+    0x03, 0x13, 0x03, 0x45, 0x03, 0x42, 0x1F, 0x88, 0x00, 0x03, 0x03, 0x13, 0x03, 0x45, 0x1F, 0x08, 
+    0x00, 0x02, 0x03, 0x13, 0x1F, 0x8B, 0x00, 0x04, 0x03, 0x14, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x0B, 
+    0x00, 0x03, 0x03, 0x14, 0x03, 0x00, 0x1F, 0x8D, 0x00, 0x04, 0x03, 0x14, 0x03, 0x01, 0x03, 0x45, 
+    0x1F, 0x0D, 0x00, 0x03, 0x03, 0x14, 0x03, 0x01, 0x1F, 0x8B, 0x00, 0x04, 0x03, 0x14, 0x03, 0x40, 
+    0x03, 0x45, 0x1F, 0x0B, 0x00, 0x03, 0x03, 0x14, 0x03, 0x40, 0x1F, 0x8D, 0x00, 0x04, 0x03, 0x14, 
+    0x03, 0x41, 0x03, 0x45, 0x1F, 0x0D, 0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 0x1F, 0x8F, 0x00, 0x04, 
+    0x03, 0x14, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x0F, 0x00, 0x03, 0x03, 0x14, 0x03, 0x42, 0x1F, 0x8B, 
+    0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x00, 0x1F, 0x8D, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 
+    0x03, 0x01, 0x1F, 0x8B, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x40, 0x1F, 0x8D, 0x00, 0x04, 
+    0x03, 0x14, 0x03, 0x45, 0x03, 0x41, 0x1F, 0x8F, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x42, 
+    0x1F, 0x89, 0x00, 0x03, 0x03, 0x14, 0x03, 0x45, 0x1F, 0x09, 0x00, 0x02, 0x03, 0x14, 0x1F, 0xBA, 
+    0x00, 0x02, 0x03, 0x40, 0x03, 0x86, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x8A, 0x00, 0x04, 0x03, 0x43, 
+    0x03, 0x00, 0x03, 0x45, 0x1F, 0x0A, 0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 0x1F, 0x8C, 0x00, 0x04, 
+    0x03, 0x43, 0x03, 0x01, 0x03, 0x45, 0x1F, 0x0C, 0x00, 0x03, 0x03, 0x43, 0x03, 0x01, 0x1F, 0x8A, 
+    0x00, 0x04, 0x03, 0x43, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x0A, 0x00, 0x03, 0x03, 0x43, 0x03, 0x40, 
+    0x1F, 0x8C, 0x00, 0x04, 0x03, 0x43, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x0C, 0x00, 0x03, 0x03, 0x43, 
+    0x03, 0x41, 0x1F, 0x8E, 0x00, 0x04, 0x03, 0x43, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x0E, 0x00, 0x03, 
+    0x03, 0x43, 0x03, 0x42, 0x1F, 0x8A, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x00, 0x1F, 0x8C, 
+    0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x01, 0x1F, 0x8A, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 
+    0x03, 0x40, 0x1F, 0x8C, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x41, 0x1F, 0x8E, 0x00, 0x04, 
+    0x03, 0x43, 0x03, 0x45, 0x03, 0x42, 0x1F, 0x88, 0x00, 0x03, 0x03, 0x43, 0x03, 0x45, 0x1F, 0x08, 
+    0x00, 0x02, 0x03, 0x43, 0x1F, 0x8A, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x00, 0x1F, 0x8C, 
+    0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x01, 0x1F, 0x8A, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 
+    0x03, 0x40, 0x1F, 0x8C, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x41, 0x1F, 0x8E, 0x00, 0x04, 
+    0x03, 0x45, 0x03, 0x13, 0x03, 0x42, 0x1F, 0x88, 0x00, 0x03, 0x03, 0x45, 0x03, 0x13, 0x1F, 0x8B, 
+    0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x00, 0x1F, 0x8D, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 
+    0x03, 0x01, 0x1F, 0x8B, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x40, 0x1F, 0x8D, 0x00, 0x04, 
+    0x03, 0x45, 0x03, 0x14, 0x03, 0x41, 0x1F, 0x8F, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x42, 
+    0x1F, 0x89, 0x00, 0x03, 0x03, 0x45, 0x03, 0x14, 0x1F, 0x8A, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 
+    0x03, 0x00, 0x1F, 0x8C, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x01, 0x1F, 0x8A, 0x00, 0x04, 
+    0x03, 0x45, 0x03, 0x43, 0x03, 0x40, 0x1F, 0x8C, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x41, 
+    0x1F, 0x8E, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x42, 0x1F, 0x88, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x43, 0x1F, 0xBC, 0x00, 0x02, 0x03, 0x45, 0x00, 0x13, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 
+    0x00, 0x3C, 0x00, 0x44, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 0x00, 0x6A, 0x00, 0x72, 
+    0x00, 0x7A, 0x00, 0x80, 0x00, 0x86, 0x00, 0x8C, 0x00, 0x94, 0x00, 0x9C, 0x00, 0xA4, 0x00, 0xAC, 
+    0x1F, 0xC8, 0x00, 0x02, 0x03, 0x00, 0x03, 0x88, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x1A, 0x00, 0x03, 
+    0x03, 0x13, 0x03, 0x00, 0x1F, 0x1C, 0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 0x1F, 0x1A, 0x00, 0x03, 
+    0x03, 0x13, 0x03, 0x40, 0x1F, 0x1C, 0x00, 0x03, 0x03, 0x13, 0x03, 0x41, 0x1F, 0x18, 0x00, 0x02, 
+    0x03, 0x13, 0x1F, 0x1B, 0x00, 0x03, 0x03, 0x14, 0x03, 0x00, 0x1F, 0x1D, 0x00, 0x03, 0x03, 0x14, 
+    0x03, 0x01, 0x1F, 0x1B, 0x00, 0x03, 0x03, 0x14, 0x03, 0x40, 0x1F, 0x1D, 0x00, 0x03, 0x03, 0x14, 
+    0x03, 0x41, 0x1F, 0x19, 0x00, 0x02, 0x03, 0x14, 0x1F, 0xC8, 0x00, 0x02, 0x03, 0x40, 0x03, 0x88, 
+    0x00, 0x02, 0x03, 0x41, 0x1F, 0x1A, 0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 0x1F, 0x1C, 0x00, 0x03, 
+    0x03, 0x43, 0x03, 0x01, 0x1F, 0x1A, 0x00, 0x03, 0x03, 0x43, 0x03, 0x40, 0x1F, 0x1C, 0x00, 0x03, 
+    0x03, 0x43, 0x03, 0x41, 0x1F, 0x18, 0x00, 0x02, 0x03, 0x43, 0x00, 0x4A, 0x00, 0x96, 0x00, 0x9C, 
+    0x00, 0xA2, 0x00, 0xAC, 0x00, 0xB4, 0x00, 0xBE, 0x00, 0xC6, 0x00, 0xD0, 0x00, 0xD8, 0x00, 0xE2, 
+    0x00, 0xEA, 0x00, 0xF4, 0x00, 0xFC, 0x01, 0x06, 0x01, 0x10, 0x01, 0x1A, 0x01, 0x24, 0x01, 0x2E, 
+    0x01, 0x36, 0x01, 0x3C, 0x01, 0x46, 0x01, 0x4E, 0x01, 0x58, 0x01, 0x60, 0x01, 0x6A, 0x01, 0x72, 
+    0x01, 0x7C, 0x01, 0x84, 0x01, 0x8E, 0x01, 0x96, 0x01, 0xA0, 0x01, 0xAA, 0x01, 0xB4, 0x01, 0xBE, 
+    0x01, 0xC8, 0x01, 0xD0, 0x01, 0xD6, 0x01, 0xDC, 0x01, 0xE2, 0x01, 0xEC, 0x01, 0xF4, 0x01, 0xFE, 
+    0x02, 0x06, 0x02, 0x10, 0x02, 0x18, 0x02, 0x22, 0x02, 0x2A, 0x02, 0x34, 0x02, 0x3C, 0x02, 0x46, 
+    0x02, 0x50, 0x02, 0x5A, 0x02, 0x64, 0x02, 0x6E, 0x02, 0x76, 0x02, 0x7C, 0x02, 0x86, 0x02, 0x90, 
+    0x02, 0x9A, 0x02, 0xA4, 0x02, 0xAE, 0x02, 0xB6, 0x02, 0xC0, 0x02, 0xCA, 0x02, 0xD4, 0x02, 0xDE, 
+    0x02, 0xE8, 0x02, 0xF0, 0x02, 0xFA, 0x03, 0x04, 0x03, 0x0E, 0x03, 0x18, 0x03, 0x22, 0x03, 0x2A, 
+    0x1F, 0xCA, 0x00, 0x02, 0x03, 0x00, 0x03, 0x89, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x9A, 0x00, 0x04, 
+    0x03, 0x13, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x2A, 0x00, 0x03, 0x03, 0x13, 0x03, 0x00, 0x1F, 0x9C, 
+    0x00, 0x04, 0x03, 0x13, 0x03, 0x01, 0x03, 0x45, 0x1F, 0x2C, 0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 
+    0x1F, 0x9A, 0x00, 0x04, 0x03, 0x13, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x2A, 0x00, 0x03, 0x03, 0x13, 
+    0x03, 0x40, 0x1F, 0x9C, 0x00, 0x04, 0x03, 0x13, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x2C, 0x00, 0x03, 
+    0x03, 0x13, 0x03, 0x41, 0x1F, 0x9E, 0x00, 0x04, 0x03, 0x13, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x2E, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x42, 0x1F, 0x9A, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x00, 
+    0x1F, 0x9C, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x01, 0x1F, 0x9A, 0x00, 0x04, 0x03, 0x13, 
+    0x03, 0x45, 0x03, 0x40, 0x1F, 0x9C, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x41, 0x1F, 0x9E, 
+    0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x42, 0x1F, 0x98, 0x00, 0x03, 0x03, 0x13, 0x03, 0x45, 
+    0x1F, 0x28, 0x00, 0x02, 0x03, 0x13, 0x1F, 0x9B, 0x00, 0x04, 0x03, 0x14, 0x03, 0x00, 0x03, 0x45, 
+    0x1F, 0x2B, 0x00, 0x03, 0x03, 0x14, 0x03, 0x00, 0x1F, 0x9D, 0x00, 0x04, 0x03, 0x14, 0x03, 0x01, 
+    0x03, 0x45, 0x1F, 0x2D, 0x00, 0x03, 0x03, 0x14, 0x03, 0x01, 0x1F, 0x9B, 0x00, 0x04, 0x03, 0x14, 
+    0x03, 0x40, 0x03, 0x45, 0x1F, 0x2B, 0x00, 0x03, 0x03, 0x14, 0x03, 0x40, 0x1F, 0x9D, 0x00, 0x04, 
+    0x03, 0x14, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x2D, 0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 0x1F, 0x9F, 
+    0x00, 0x04, 0x03, 0x14, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x2F, 0x00, 0x03, 0x03, 0x14, 0x03, 0x42, 
+    0x1F, 0x9B, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x00, 0x1F, 0x9D, 0x00, 0x04, 0x03, 0x14, 
+    0x03, 0x45, 0x03, 0x01, 0x1F, 0x9B, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x40, 0x1F, 0x9D, 
+    0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x41, 0x1F, 0x9F, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 
+    0x03, 0x42, 0x1F, 0x99, 0x00, 0x03, 0x03, 0x14, 0x03, 0x45, 0x1F, 0x29, 0x00, 0x02, 0x03, 0x14, 
+    0x1F, 0xCA, 0x00, 0x02, 0x03, 0x40, 0x03, 0x89, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x9A, 0x00, 0x04, 
+    0x03, 0x43, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x2A, 0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 0x1F, 0x9C, 
+    0x00, 0x04, 0x03, 0x43, 0x03, 0x01, 0x03, 0x45, 0x1F, 0x2C, 0x00, 0x03, 0x03, 0x43, 0x03, 0x01, 
+    0x1F, 0x9A, 0x00, 0x04, 0x03, 0x43, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x2A, 0x00, 0x03, 0x03, 0x43, 
+    0x03, 0x40, 0x1F, 0x9C, 0x00, 0x04, 0x03, 0x43, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x2C, 0x00, 0x03, 
+    0x03, 0x43, 0x03, 0x41, 0x1F, 0x9E, 0x00, 0x04, 0x03, 0x43, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x2E, 
+    0x00, 0x03, 0x03, 0x43, 0x03, 0x42, 0x1F, 0x9A, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x00, 
+    0x1F, 0x9C, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x01, 0x1F, 0x9A, 0x00, 0x04, 0x03, 0x43, 
+    0x03, 0x45, 0x03, 0x40, 0x1F, 0x9C, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x41, 0x1F, 0x9E, 
+    0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x42, 0x1F, 0x98, 0x00, 0x03, 0x03, 0x43, 0x03, 0x45, 
+    0x1F, 0x28, 0x00, 0x02, 0x03, 0x43, 0x1F, 0x9A, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x00, 
+    0x1F, 0x9C, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x01, 0x1F, 0x9A, 0x00, 0x04, 0x03, 0x45, 
+    0x03, 0x13, 0x03, 0x40, 0x1F, 0x9C, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x41, 0x1F, 0x9E, 
+    0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x42, 0x1F, 0x98, 0x00, 0x03, 0x03, 0x45, 0x03, 0x13, 
+    0x1F, 0x9B, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x00, 0x1F, 0x9D, 0x00, 0x04, 0x03, 0x45, 
+    0x03, 0x14, 0x03, 0x01, 0x1F, 0x9B, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x40, 0x1F, 0x9D, 
+    0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x41, 0x1F, 0x9F, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 
+    0x03, 0x42, 0x1F, 0x99, 0x00, 0x03, 0x03, 0x45, 0x03, 0x14, 0x1F, 0x9A, 0x00, 0x04, 0x03, 0x45, 
+    0x03, 0x43, 0x03, 0x00, 0x1F, 0x9C, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x01, 0x1F, 0x9A, 
+    0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x40, 0x1F, 0x9C, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 
+    0x03, 0x41, 0x1F, 0x9E, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x42, 0x1F, 0x98, 0x00, 0x03, 
+    0x03, 0x45, 0x03, 0x43, 0x1F, 0xCC, 0x00, 0x02, 0x03, 0x45, 0x00, 0x19, 0x00, 0x34, 0x00, 0x3A, 
+    0x00, 0x40, 0x00, 0x46, 0x00, 0x4C, 0x00, 0x52, 0x00, 0x5A, 0x00, 0x62, 0x00, 0x6A, 0x00, 0x72, 
+    0x00, 0x7A, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 0x00, 0x98, 0x00, 0xA0, 0x00, 0xA8, 0x00, 0xAE, 
+    0x00, 0xB4, 0x00, 0xBA, 0x00, 0xC2, 0x00, 0xCA, 0x00, 0xD2, 0x00, 0xDA, 0x00, 0xE2, 0x1F, 0xDA, 
+    0x00, 0x02, 0x03, 0x00, 0x03, 0x8A, 0x00, 0x02, 0x03, 0x01, 0x1F, 0xD9, 0x00, 0x02, 0x03, 0x04, 
+    0x1F, 0xD8, 0x00, 0x02, 0x03, 0x06, 0x03, 0xAA, 0x00, 0x02, 0x03, 0x08, 0x1F, 0x3A, 0x00, 0x03, 
+    0x03, 0x13, 0x03, 0x00, 0x1F, 0x3C, 0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 0x1F, 0x3A, 0x00, 0x03, 
+    0x03, 0x13, 0x03, 0x40, 0x1F, 0x3C, 0x00, 0x03, 0x03, 0x13, 0x03, 0x41, 0x1F, 0x3E, 0x00, 0x03, 
+    0x03, 0x13, 0x03, 0x42, 0x1F, 0x38, 0x00, 0x02, 0x03, 0x13, 0x1F, 0x3B, 0x00, 0x03, 0x03, 0x14, 
+    0x03, 0x00, 0x1F, 0x3D, 0x00, 0x03, 0x03, 0x14, 0x03, 0x01, 0x1F, 0x3B, 0x00, 0x03, 0x03, 0x14, 
+    0x03, 0x40, 0x1F, 0x3D, 0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 0x1F, 0x3F, 0x00, 0x03, 0x03, 0x14, 
+    0x03, 0x42, 0x1F, 0x39, 0x00, 0x02, 0x03, 0x14, 0x1F, 0xDA, 0x00, 0x02, 0x03, 0x40, 0x03, 0x8A, 
+    0x00, 0x02, 0x03, 0x41, 0x1F, 0x3A, 0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 0x1F, 0x3C, 0x00, 0x03, 
+    0x03, 0x43, 0x03, 0x01, 0x1F, 0x3A, 0x00, 0x03, 0x03, 0x43, 0x03, 0x40, 0x1F, 0x3C, 0x00, 0x03, 
+    0x03, 0x43, 0x03, 0x41, 0x1F, 0x3E, 0x00, 0x03, 0x03, 0x43, 0x03, 0x42, 0x1F, 0x38, 0x00, 0x02, 
+    0x03, 0x43, 0x00, 0x13, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0x00, 0x3C, 0x00, 0x44, 0x00, 0x4C, 
+    0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 0x00, 0x6A, 0x00, 0x72, 0x00, 0x7A, 0x00, 0x80, 0x00, 0x86, 
+    0x00, 0x8C, 0x00, 0x94, 0x00, 0x9C, 0x00, 0xA4, 0x00, 0xAC, 0x1F, 0xF8, 0x00, 0x02, 0x03, 0x00, 
+    0x03, 0x8C, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x4A, 0x00, 0x03, 0x03, 0x13, 0x03, 0x00, 0x1F, 0x4C, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 0x1F, 0x4A, 0x00, 0x03, 0x03, 0x13, 0x03, 0x40, 0x1F, 0x4C, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x41, 0x1F, 0x48, 0x00, 0x02, 0x03, 0x13, 0x1F, 0x4B, 0x00, 0x03, 
+    0x03, 0x14, 0x03, 0x00, 0x1F, 0x4D, 0x00, 0x03, 0x03, 0x14, 0x03, 0x01, 0x1F, 0x4B, 0x00, 0x03, 
+    0x03, 0x14, 0x03, 0x40, 0x1F, 0x4D, 0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 0x1F, 0x49, 0x00, 0x02, 
+    0x03, 0x14, 0x1F, 0xF8, 0x00, 0x02, 0x03, 0x40, 0x03, 0x8C, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x4A, 
+    0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 0x1F, 0x4C, 0x00, 0x03, 0x03, 0x43, 0x03, 0x01, 0x1F, 0x4A, 
+    0x00, 0x03, 0x03, 0x43, 0x03, 0x40, 0x1F, 0x4C, 0x00, 0x03, 0x03, 0x43, 0x03, 0x41, 0x1F, 0x48, 
+    0x00, 0x02, 0x03, 0x43, 0x00, 0x01, 0x00, 0x04, 0x1F, 0xEC, 0x00, 0x02, 0x03, 0x14, 0x00, 0x0D, 
+    0x00, 0x1C, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0x00, 0x3A, 0x00, 0x42, 0x00, 0x4A, 
+    0x00, 0x52, 0x00, 0x5A, 0x00, 0x62, 0x00, 0x68, 0x00, 0x6E, 0x1F, 0xEA, 0x00, 0x02, 0x03, 0x00, 
+    0x03, 0x8E, 0x00, 0x02, 0x03, 0x01, 0x1F, 0xE9, 0x00, 0x02, 0x03, 0x04, 0x1F, 0xE8, 0x00, 0x02, 
+    0x03, 0x06, 0x03, 0xAB, 0x00, 0x02, 0x03, 0x08, 0x1F, 0x5B, 0x00, 0x03, 0x03, 0x14, 0x03, 0x00, 
+    0x1F, 0x5D, 0x00, 0x03, 0x03, 0x14, 0x03, 0x01, 0x1F, 0x5B, 0x00, 0x03, 0x03, 0x14, 0x03, 0x40, 
+    0x1F, 0x5D, 0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 0x1F, 0x5F, 0x00, 0x03, 0x03, 0x14, 0x03, 0x42, 
+    0x1F, 0x59, 0x00, 0x02, 0x03, 0x14, 0x1F, 0xEA, 0x00, 0x02, 0x03, 0x40, 0x03, 0x8E, 0x00, 0x02, 
+    0x03, 0x41, 0x00, 0x4A, 0x00, 0x96, 0x00, 0x9C, 0x00, 0xA2, 0x00, 0xAC, 0x00, 0xB4, 0x00, 0xBE, 
+    0x00, 0xC6, 0x00, 0xD0, 0x00, 0xD8, 0x00, 0xE2, 0x00, 0xEA, 0x00, 0xF4, 0x00, 0xFC, 0x01, 0x06, 
+    0x01, 0x10, 0x01, 0x1A, 0x01, 0x24, 0x01, 0x2E, 0x01, 0x36, 0x01, 0x3C, 0x01, 0x46, 0x01, 0x4E, 
+    0x01, 0x58, 0x01, 0x60, 0x01, 0x6A, 0x01, 0x72, 0x01, 0x7C, 0x01, 0x84, 0x01, 0x8E, 0x01, 0x96, 
+    0x01, 0xA0, 0x01, 0xAA, 0x01, 0xB4, 0x01, 0xBE, 0x01, 0xC8, 0x01, 0xD0, 0x01, 0xD6, 0x01, 0xDC, 
+    0x01, 0xE2, 0x01, 0xEC, 0x01, 0xF4, 0x01, 0xFE, 0x02, 0x06, 0x02, 0x10, 0x02, 0x18, 0x02, 0x22, 
+    0x02, 0x2A, 0x02, 0x34, 0x02, 0x3C, 0x02, 0x46, 0x02, 0x50, 0x02, 0x5A, 0x02, 0x64, 0x02, 0x6E, 
+    0x02, 0x76, 0x02, 0x7C, 0x02, 0x86, 0x02, 0x90, 0x02, 0x9A, 0x02, 0xA4, 0x02, 0xAE, 0x02, 0xB6, 
+    0x02, 0xC0, 0x02, 0xCA, 0x02, 0xD4, 0x02, 0xDE, 0x02, 0xE8, 0x02, 0xF0, 0x02, 0xFA, 0x03, 0x04, 
+    0x03, 0x0E, 0x03, 0x18, 0x03, 0x22, 0x03, 0x2A, 0x1F, 0xFA, 0x00, 0x02, 0x03, 0x00, 0x03, 0x8F, 
+    0x00, 0x02, 0x03, 0x01, 0x1F, 0xAA, 0x00, 0x04, 0x03, 0x13, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x6A, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x00, 0x1F, 0xAC, 0x00, 0x04, 0x03, 0x13, 0x03, 0x01, 0x03, 0x45, 
+    0x1F, 0x6C, 0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 0x1F, 0xAA, 0x00, 0x04, 0x03, 0x13, 0x03, 0x40, 
+    0x03, 0x45, 0x1F, 0x6A, 0x00, 0x03, 0x03, 0x13, 0x03, 0x40, 0x1F, 0xAC, 0x00, 0x04, 0x03, 0x13, 
+    0x03, 0x41, 0x03, 0x45, 0x1F, 0x6C, 0x00, 0x03, 0x03, 0x13, 0x03, 0x41, 0x1F, 0xAE, 0x00, 0x04, 
+    0x03, 0x13, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x6E, 0x00, 0x03, 0x03, 0x13, 0x03, 0x42, 0x1F, 0xAA, 
+    0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x00, 0x1F, 0xAC, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 
+    0x03, 0x01, 0x1F, 0xAA, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x40, 0x1F, 0xAC, 0x00, 0x04, 
+    0x03, 0x13, 0x03, 0x45, 0x03, 0x41, 0x1F, 0xAE, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x42, 
+    0x1F, 0xA8, 0x00, 0x03, 0x03, 0x13, 0x03, 0x45, 0x1F, 0x68, 0x00, 0x02, 0x03, 0x13, 0x1F, 0xAB, 
+    0x00, 0x04, 0x03, 0x14, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x6B, 0x00, 0x03, 0x03, 0x14, 0x03, 0x00, 
+    0x1F, 0xAD, 0x00, 0x04, 0x03, 0x14, 0x03, 0x01, 0x03, 0x45, 0x1F, 0x6D, 0x00, 0x03, 0x03, 0x14, 
+    0x03, 0x01, 0x1F, 0xAB, 0x00, 0x04, 0x03, 0x14, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x6B, 0x00, 0x03, 
+    0x03, 0x14, 0x03, 0x40, 0x1F, 0xAD, 0x00, 0x04, 0x03, 0x14, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x6D, 
+    0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 0x1F, 0xAF, 0x00, 0x04, 0x03, 0x14, 0x03, 0x42, 0x03, 0x45, 
+    0x1F, 0x6F, 0x00, 0x03, 0x03, 0x14, 0x03, 0x42, 0x1F, 0xAB, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 
+    0x03, 0x00, 0x1F, 0xAD, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x01, 0x1F, 0xAB, 0x00, 0x04, 
+    0x03, 0x14, 0x03, 0x45, 0x03, 0x40, 0x1F, 0xAD, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x41, 
+    0x1F, 0xAF, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x42, 0x1F, 0xA9, 0x00, 0x03, 0x03, 0x14, 
+    0x03, 0x45, 0x1F, 0x69, 0x00, 0x02, 0x03, 0x14, 0x1F, 0xFA, 0x00, 0x02, 0x03, 0x40, 0x03, 0x8F, 
+    0x00, 0x02, 0x03, 0x41, 0x1F, 0xAA, 0x00, 0x04, 0x03, 0x43, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x6A, 
+    0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 0x1F, 0xAC, 0x00, 0x04, 0x03, 0x43, 0x03, 0x01, 0x03, 0x45, 
+    0x1F, 0x6C, 0x00, 0x03, 0x03, 0x43, 0x03, 0x01, 0x1F, 0xAA, 0x00, 0x04, 0x03, 0x43, 0x03, 0x40, 
+    0x03, 0x45, 0x1F, 0x6A, 0x00, 0x03, 0x03, 0x43, 0x03, 0x40, 0x1F, 0xAC, 0x00, 0x04, 0x03, 0x43, 
+    0x03, 0x41, 0x03, 0x45, 0x1F, 0x6C, 0x00, 0x03, 0x03, 0x43, 0x03, 0x41, 0x1F, 0xAE, 0x00, 0x04, 
+    0x03, 0x43, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x6E, 0x00, 0x03, 0x03, 0x43, 0x03, 0x42, 0x1F, 0xAA, 
+    0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x00, 0x1F, 0xAC, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 
+    0x03, 0x01, 0x1F, 0xAA, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x40, 0x1F, 0xAC, 0x00, 0x04, 
+    0x03, 0x43, 0x03, 0x45, 0x03, 0x41, 0x1F, 0xAE, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x42, 
+    0x1F, 0xA8, 0x00, 0x03, 0x03, 0x43, 0x03, 0x45, 0x1F, 0x68, 0x00, 0x02, 0x03, 0x43, 0x1F, 0xAA, 
+    0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x00, 0x1F, 0xAC, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 
+    0x03, 0x01, 0x1F, 0xAA, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x40, 0x1F, 0xAC, 0x00, 0x04, 
+    0x03, 0x45, 0x03, 0x13, 0x03, 0x41, 0x1F, 0xAE, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x42, 
+    0x1F, 0xA8, 0x00, 0x03, 0x03, 0x45, 0x03, 0x13, 0x1F, 0xAB, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 
+    0x03, 0x00, 0x1F, 0xAD, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x01, 0x1F, 0xAB, 0x00, 0x04, 
+    0x03, 0x45, 0x03, 0x14, 0x03, 0x40, 0x1F, 0xAD, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x41, 
+    0x1F, 0xAF, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x42, 0x1F, 0xA9, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x14, 0x1F, 0xAA, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x00, 0x1F, 0xAC, 0x00, 0x04, 
+    0x03, 0x45, 0x03, 0x43, 0x03, 0x01, 0x1F, 0xAA, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x40, 
+    0x1F, 0xAC, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x41, 0x1F, 0xAE, 0x00, 0x04, 0x03, 0x45, 
+    0x03, 0x43, 0x03, 0x42, 0x1F, 0xA8, 0x00, 0x03, 0x03, 0x45, 0x03, 0x43, 0x1F, 0xFC, 0x00, 0x02, 
+    0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0xB4, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 
+    0x1F, 0xC4, 0x00, 0x02, 0x03, 0x45, 0x00, 0x57, 0x00, 0xB0, 0x00, 0xB8, 0x00, 0xBE, 0x00, 0xC6, 
+    0x00, 0xCC, 0x00, 0xD2, 0x00, 0xD8, 0x00, 0xE2, 0x00, 0xEA, 0x00, 0xF4, 0x00, 0xFC, 0x01, 0x06, 
+    0x01, 0x0E, 0x01, 0x18, 0x01, 0x20, 0x01, 0x2A, 0x01, 0x32, 0x01, 0x3C, 0x01, 0x46, 0x01, 0x50, 
+    0x01, 0x5A, 0x01, 0x64, 0x01, 0x6C, 0x01, 0x72, 0x01, 0x7C, 0x01, 0x84, 0x01, 0x8E, 0x01, 0x96, 
+    0x01, 0xA0, 0x01, 0xA8, 0x01, 0xB2, 0x01, 0xBA, 0x01, 0xC4, 0x01, 0xCC, 0x01, 0xD6, 0x01, 0xE0, 
+    0x01, 0xEA, 0x01, 0xF4, 0x01, 0xFE, 0x02, 0x06, 0x02, 0x0C, 0x02, 0x14, 0x02, 0x1A, 0x02, 0x22, 
+    0x02, 0x28, 0x02, 0x30, 0x02, 0x36, 0x02, 0x40, 0x02, 0x48, 0x02, 0x52, 0x02, 0x5A, 0x02, 0x64, 
+    0x02, 0x6C, 0x02, 0x76, 0x02, 0x7E, 0x02, 0x88, 0x02, 0x90, 0x02, 0x9A, 0x02, 0xA4, 0x02, 0xAE, 
+    0x02, 0xB8, 0x02, 0xC2, 0x02, 0xCA, 0x02, 0xD0, 0x02, 0xD8, 0x02, 0xE0, 0x02, 0xEA, 0x02, 0xF4, 
+    0x02, 0xFE, 0x03, 0x08, 0x03, 0x12, 0x03, 0x1A, 0x03, 0x24, 0x03, 0x2E, 0x03, 0x38, 0x03, 0x42, 
+    0x03, 0x4C, 0x03, 0x54, 0x03, 0x5C, 0x03, 0x64, 0x03, 0x6C, 0x03, 0x76, 0x03, 0x80, 0x03, 0x8A, 
+    0x03, 0x94, 0x03, 0x9E, 0x03, 0xA6, 0x1F, 0xB2, 0x00, 0x03, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x70, 
+    0x00, 0x02, 0x03, 0x00, 0x1F, 0xB4, 0x00, 0x03, 0x03, 0x01, 0x03, 0x45, 0x03, 0xAC, 0x00, 0x02, 
+    0x03, 0x01, 0x1F, 0xB1, 0x00, 0x02, 0x03, 0x04, 0x1F, 0xB0, 0x00, 0x02, 0x03, 0x06, 0x1F, 0x82, 
+    0x00, 0x04, 0x03, 0x13, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x02, 0x00, 0x03, 0x03, 0x13, 0x03, 0x00, 
+    0x1F, 0x84, 0x00, 0x04, 0x03, 0x13, 0x03, 0x01, 0x03, 0x45, 0x1F, 0x04, 0x00, 0x03, 0x03, 0x13, 
+    0x03, 0x01, 0x1F, 0x82, 0x00, 0x04, 0x03, 0x13, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x02, 0x00, 0x03, 
+    0x03, 0x13, 0x03, 0x40, 0x1F, 0x84, 0x00, 0x04, 0x03, 0x13, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x04, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x41, 0x1F, 0x86, 0x00, 0x04, 0x03, 0x13, 0x03, 0x42, 0x03, 0x45, 
+    0x1F, 0x06, 0x00, 0x03, 0x03, 0x13, 0x03, 0x42, 0x1F, 0x82, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 
+    0x03, 0x00, 0x1F, 0x84, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x01, 0x1F, 0x82, 0x00, 0x04, 
+    0x03, 0x13, 0x03, 0x45, 0x03, 0x40, 0x1F, 0x84, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x41, 
+    0x1F, 0x86, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x42, 0x1F, 0x80, 0x00, 0x03, 0x03, 0x13, 
+    0x03, 0x45, 0x1F, 0x00, 0x00, 0x02, 0x03, 0x13, 0x1F, 0x83, 0x00, 0x04, 0x03, 0x14, 0x03, 0x00, 
+    0x03, 0x45, 0x1F, 0x03, 0x00, 0x03, 0x03, 0x14, 0x03, 0x00, 0x1F, 0x85, 0x00, 0x04, 0x03, 0x14, 
+    0x03, 0x01, 0x03, 0x45, 0x1F, 0x05, 0x00, 0x03, 0x03, 0x14, 0x03, 0x01, 0x1F, 0x83, 0x00, 0x04, 
+    0x03, 0x14, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x03, 0x00, 0x03, 0x03, 0x14, 0x03, 0x40, 0x1F, 0x85, 
+    0x00, 0x04, 0x03, 0x14, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x05, 0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 
+    0x1F, 0x87, 0x00, 0x04, 0x03, 0x14, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x07, 0x00, 0x03, 0x03, 0x14, 
+    0x03, 0x42, 0x1F, 0x83, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x00, 0x1F, 0x85, 0x00, 0x04, 
+    0x03, 0x14, 0x03, 0x45, 0x03, 0x01, 0x1F, 0x83, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x40, 
+    0x1F, 0x85, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x41, 0x1F, 0x87, 0x00, 0x04, 0x03, 0x14, 
+    0x03, 0x45, 0x03, 0x42, 0x1F, 0x81, 0x00, 0x03, 0x03, 0x14, 0x03, 0x45, 0x1F, 0x01, 0x00, 0x02, 
+    0x03, 0x14, 0x1F, 0xB2, 0x00, 0x03, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x70, 0x00, 0x02, 0x03, 0x40, 
+    0x1F, 0xB4, 0x00, 0x03, 0x03, 0x41, 0x03, 0x45, 0x03, 0xAC, 0x00, 0x02, 0x03, 0x41, 0x1F, 0xB7, 
+    0x00, 0x03, 0x03, 0x42, 0x03, 0x45, 0x1F, 0xB6, 0x00, 0x02, 0x03, 0x42, 0x1F, 0x82, 0x00, 0x04, 
+    0x03, 0x43, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x02, 0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 0x1F, 0x84, 
+    0x00, 0x04, 0x03, 0x43, 0x03, 0x01, 0x03, 0x45, 0x1F, 0x04, 0x00, 0x03, 0x03, 0x43, 0x03, 0x01, 
+    0x1F, 0x82, 0x00, 0x04, 0x03, 0x43, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x02, 0x00, 0x03, 0x03, 0x43, 
+    0x03, 0x40, 0x1F, 0x84, 0x00, 0x04, 0x03, 0x43, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x04, 0x00, 0x03, 
+    0x03, 0x43, 0x03, 0x41, 0x1F, 0x86, 0x00, 0x04, 0x03, 0x43, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x06, 
+    0x00, 0x03, 0x03, 0x43, 0x03, 0x42, 0x1F, 0x82, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x00, 
+    0x1F, 0x84, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x01, 0x1F, 0x82, 0x00, 0x04, 0x03, 0x43, 
+    0x03, 0x45, 0x03, 0x40, 0x1F, 0x84, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x41, 0x1F, 0x86, 
+    0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x42, 0x1F, 0x80, 0x00, 0x03, 0x03, 0x43, 0x03, 0x45, 
+    0x1F, 0x00, 0x00, 0x02, 0x03, 0x43, 0x1F, 0xB2, 0x00, 0x03, 0x03, 0x45, 0x03, 0x00, 0x1F, 0xB4, 
+    0x00, 0x03, 0x03, 0x45, 0x03, 0x01, 0x1F, 0x82, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x00, 
+    0x1F, 0x84, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x01, 0x1F, 0x82, 0x00, 0x04, 0x03, 0x45, 
+    0x03, 0x13, 0x03, 0x40, 0x1F, 0x84, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x41, 0x1F, 0x86, 
+    0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x42, 0x1F, 0x80, 0x00, 0x03, 0x03, 0x45, 0x03, 0x13, 
+    0x1F, 0x83, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x00, 0x1F, 0x85, 0x00, 0x04, 0x03, 0x45, 
+    0x03, 0x14, 0x03, 0x01, 0x1F, 0x83, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x40, 0x1F, 0x85, 
+    0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x41, 0x1F, 0x87, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 
+    0x03, 0x42, 0x1F, 0x81, 0x00, 0x03, 0x03, 0x45, 0x03, 0x14, 0x1F, 0xB2, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x40, 0x1F, 0xB4, 0x00, 0x03, 0x03, 0x45, 0x03, 0x41, 0x1F, 0xB7, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x42, 0x1F, 0x82, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x00, 0x1F, 0x84, 0x00, 0x04, 
+    0x03, 0x45, 0x03, 0x43, 0x03, 0x01, 0x1F, 0x82, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x40, 
+    0x1F, 0x84, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x41, 0x1F, 0x86, 0x00, 0x04, 0x03, 0x45, 
+    0x03, 0x43, 0x03, 0x42, 0x1F, 0x80, 0x00, 0x03, 0x03, 0x45, 0x03, 0x43, 0x1F, 0xB3, 0x00, 0x02, 
+    0x03, 0x45, 0x00, 0x13, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0x00, 0x3C, 0x00, 0x44, 0x00, 0x4C, 
+    0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 0x00, 0x6A, 0x00, 0x72, 0x00, 0x7A, 0x00, 0x80, 0x00, 0x86, 
+    0x00, 0x8C, 0x00, 0x94, 0x00, 0x9C, 0x00, 0xA4, 0x00, 0xAC, 0x1F, 0x72, 0x00, 0x02, 0x03, 0x00, 
+    0x03, 0xAD, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x12, 0x00, 0x03, 0x03, 0x13, 0x03, 0x00, 0x1F, 0x14, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 0x1F, 0x12, 0x00, 0x03, 0x03, 0x13, 0x03, 0x40, 0x1F, 0x14, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x41, 0x1F, 0x10, 0x00, 0x02, 0x03, 0x13, 0x1F, 0x13, 0x00, 0x03, 
+    0x03, 0x14, 0x03, 0x00, 0x1F, 0x15, 0x00, 0x03, 0x03, 0x14, 0x03, 0x01, 0x1F, 0x13, 0x00, 0x03, 
+    0x03, 0x14, 0x03, 0x40, 0x1F, 0x15, 0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 0x1F, 0x11, 0x00, 0x02, 
+    0x03, 0x14, 0x1F, 0x72, 0x00, 0x02, 0x03, 0x40, 0x03, 0xAD, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x12, 
+    0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 0x1F, 0x14, 0x00, 0x03, 0x03, 0x43, 0x03, 0x01, 0x1F, 0x12, 
+    0x00, 0x03, 0x03, 0x43, 0x03, 0x40, 0x1F, 0x14, 0x00, 0x03, 0x03, 0x43, 0x03, 0x41, 0x1F, 0x10, 
+    0x00, 0x02, 0x03, 0x43, 0x00, 0x55, 0x00, 0xAC, 0x00, 0xB4, 0x00, 0xBA, 0x00, 0xC2, 0x00, 0xC8, 
+    0x00, 0xD2, 0x00, 0xDA, 0x00, 0xE4, 0x00, 0xEC, 0x00, 0xF6, 0x00, 0xFE, 0x01, 0x08, 0x01, 0x10, 
+    0x01, 0x1A, 0x01, 0x22, 0x01, 0x2C, 0x01, 0x36, 0x01, 0x40, 0x01, 0x4A, 0x01, 0x54, 0x01, 0x5C, 
+    0x01, 0x62, 0x01, 0x6C, 0x01, 0x74, 0x01, 0x7E, 0x01, 0x86, 0x01, 0x90, 0x01, 0x98, 0x01, 0xA2, 
+    0x01, 0xAA, 0x01, 0xB4, 0x01, 0xBC, 0x01, 0xC6, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xE4, 0x01, 0xEE, 
+    0x01, 0xF6, 0x01, 0xFC, 0x02, 0x04, 0x02, 0x0A, 0x02, 0x12, 0x02, 0x18, 0x02, 0x20, 0x02, 0x26, 
+    0x02, 0x30, 0x02, 0x38, 0x02, 0x42, 0x02, 0x4A, 0x02, 0x54, 0x02, 0x5C, 0x02, 0x66, 0x02, 0x6E, 
+    0x02, 0x78, 0x02, 0x80, 0x02, 0x8A, 0x02, 0x94, 0x02, 0x9E, 0x02, 0xA8, 0x02, 0xB2, 0x02, 0xBA, 
+    0x02, 0xC0, 0x02, 0xC8, 0x02, 0xD0, 0x02, 0xDA, 0x02, 0xE4, 0x02, 0xEE, 0x02, 0xF8, 0x03, 0x02, 
+    0x03, 0x0A, 0x03, 0x14, 0x03, 0x1E, 0x03, 0x28, 0x03, 0x32, 0x03, 0x3C, 0x03, 0x44, 0x03, 0x4C, 
+    0x03, 0x54, 0x03, 0x5C, 0x03, 0x66, 0x03, 0x70, 0x03, 0x7A, 0x03, 0x84, 0x03, 0x8E, 0x03, 0x96, 
+    0x1F, 0xC2, 0x00, 0x03, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x74, 0x00, 0x02, 0x03, 0x00, 0x1F, 0xC4, 
+    0x00, 0x03, 0x03, 0x01, 0x03, 0x45, 0x03, 0xAE, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x92, 0x00, 0x04, 
+    0x03, 0x13, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x22, 0x00, 0x03, 0x03, 0x13, 0x03, 0x00, 0x1F, 0x94, 
+    0x00, 0x04, 0x03, 0x13, 0x03, 0x01, 0x03, 0x45, 0x1F, 0x24, 0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 
+    0x1F, 0x92, 0x00, 0x04, 0x03, 0x13, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x22, 0x00, 0x03, 0x03, 0x13, 
+    0x03, 0x40, 0x1F, 0x94, 0x00, 0x04, 0x03, 0x13, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x24, 0x00, 0x03, 
+    0x03, 0x13, 0x03, 0x41, 0x1F, 0x96, 0x00, 0x04, 0x03, 0x13, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x26, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x42, 0x1F, 0x92, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x00, 
+    0x1F, 0x94, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x01, 0x1F, 0x92, 0x00, 0x04, 0x03, 0x13, 
+    0x03, 0x45, 0x03, 0x40, 0x1F, 0x94, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x41, 0x1F, 0x96, 
+    0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x42, 0x1F, 0x90, 0x00, 0x03, 0x03, 0x13, 0x03, 0x45, 
+    0x1F, 0x20, 0x00, 0x02, 0x03, 0x13, 0x1F, 0x93, 0x00, 0x04, 0x03, 0x14, 0x03, 0x00, 0x03, 0x45, 
+    0x1F, 0x23, 0x00, 0x03, 0x03, 0x14, 0x03, 0x00, 0x1F, 0x95, 0x00, 0x04, 0x03, 0x14, 0x03, 0x01, 
+    0x03, 0x45, 0x1F, 0x25, 0x00, 0x03, 0x03, 0x14, 0x03, 0x01, 0x1F, 0x93, 0x00, 0x04, 0x03, 0x14, 
+    0x03, 0x40, 0x03, 0x45, 0x1F, 0x23, 0x00, 0x03, 0x03, 0x14, 0x03, 0x40, 0x1F, 0x95, 0x00, 0x04, 
+    0x03, 0x14, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x25, 0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 0x1F, 0x97, 
+    0x00, 0x04, 0x03, 0x14, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x27, 0x00, 0x03, 0x03, 0x14, 0x03, 0x42, 
+    0x1F, 0x93, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x00, 0x1F, 0x95, 0x00, 0x04, 0x03, 0x14, 
+    0x03, 0x45, 0x03, 0x01, 0x1F, 0x93, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x40, 0x1F, 0x95, 
+    0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x41, 0x1F, 0x97, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 
+    0x03, 0x42, 0x1F, 0x91, 0x00, 0x03, 0x03, 0x14, 0x03, 0x45, 0x1F, 0x21, 0x00, 0x02, 0x03, 0x14, 
+    0x1F, 0xC2, 0x00, 0x03, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x74, 0x00, 0x02, 0x03, 0x40, 0x1F, 0xC4, 
+    0x00, 0x03, 0x03, 0x41, 0x03, 0x45, 0x03, 0xAE, 0x00, 0x02, 0x03, 0x41, 0x1F, 0xC7, 0x00, 0x03, 
+    0x03, 0x42, 0x03, 0x45, 0x1F, 0xC6, 0x00, 0x02, 0x03, 0x42, 0x1F, 0x92, 0x00, 0x04, 0x03, 0x43, 
+    0x03, 0x00, 0x03, 0x45, 0x1F, 0x22, 0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 0x1F, 0x94, 0x00, 0x04, 
+    0x03, 0x43, 0x03, 0x01, 0x03, 0x45, 0x1F, 0x24, 0x00, 0x03, 0x03, 0x43, 0x03, 0x01, 0x1F, 0x92, 
+    0x00, 0x04, 0x03, 0x43, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x22, 0x00, 0x03, 0x03, 0x43, 0x03, 0x40, 
+    0x1F, 0x94, 0x00, 0x04, 0x03, 0x43, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x24, 0x00, 0x03, 0x03, 0x43, 
+    0x03, 0x41, 0x1F, 0x96, 0x00, 0x04, 0x03, 0x43, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x26, 0x00, 0x03, 
+    0x03, 0x43, 0x03, 0x42, 0x1F, 0x92, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x00, 0x1F, 0x94, 
+    0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x01, 0x1F, 0x92, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 
+    0x03, 0x40, 0x1F, 0x94, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x41, 0x1F, 0x96, 0x00, 0x04, 
+    0x03, 0x43, 0x03, 0x45, 0x03, 0x42, 0x1F, 0x90, 0x00, 0x03, 0x03, 0x43, 0x03, 0x45, 0x1F, 0x20, 
+    0x00, 0x02, 0x03, 0x43, 0x1F, 0xC2, 0x00, 0x03, 0x03, 0x45, 0x03, 0x00, 0x1F, 0xC4, 0x00, 0x03, 
+    0x03, 0x45, 0x03, 0x01, 0x1F, 0x92, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x00, 0x1F, 0x94, 
+    0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x01, 0x1F, 0x92, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 
+    0x03, 0x40, 0x1F, 0x94, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x41, 0x1F, 0x96, 0x00, 0x04, 
+    0x03, 0x45, 0x03, 0x13, 0x03, 0x42, 0x1F, 0x90, 0x00, 0x03, 0x03, 0x45, 0x03, 0x13, 0x1F, 0x93, 
+    0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x00, 0x1F, 0x95, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 
+    0x03, 0x01, 0x1F, 0x93, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x40, 0x1F, 0x95, 0x00, 0x04, 
+    0x03, 0x45, 0x03, 0x14, 0x03, 0x41, 0x1F, 0x97, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x42, 
+    0x1F, 0x91, 0x00, 0x03, 0x03, 0x45, 0x03, 0x14, 0x1F, 0xC2, 0x00, 0x03, 0x03, 0x45, 0x03, 0x40, 
+    0x1F, 0xC4, 0x00, 0x03, 0x03, 0x45, 0x03, 0x41, 0x1F, 0xC7, 0x00, 0x03, 0x03, 0x45, 0x03, 0x42, 
+    0x1F, 0x92, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x00, 0x1F, 0x94, 0x00, 0x04, 0x03, 0x45, 
+    0x03, 0x43, 0x03, 0x01, 0x1F, 0x92, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x40, 0x1F, 0x94, 
+    0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x41, 0x1F, 0x96, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 
+    0x03, 0x42, 0x1F, 0x90, 0x00, 0x03, 0x03, 0x45, 0x03, 0x43, 0x1F, 0xC3, 0x00, 0x02, 0x03, 0x45, 
+    0x00, 0x20, 0x00, 0x42, 0x00, 0x48, 0x00, 0x4E, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 0x00, 0x6A, 
+    0x00, 0x72, 0x00, 0x7A, 0x00, 0x82, 0x00, 0x88, 0x00, 0x90, 0x00, 0x98, 0x00, 0xA0, 0x00, 0xA8, 
+    0x00, 0xB0, 0x00, 0xB6, 0x00, 0xBE, 0x00, 0xC6, 0x00, 0xCE, 0x00, 0xD6, 0x00, 0xDE, 0x00, 0xE4, 
+    0x00, 0xEA, 0x00, 0xF0, 0x00, 0xF6, 0x00, 0xFE, 0x01, 0x06, 0x01, 0x0E, 0x01, 0x16, 0x01, 0x1E, 
+    0x01, 0x24, 0x1F, 0x76, 0x00, 0x02, 0x03, 0x00, 0x03, 0xAF, 0x00, 0x02, 0x03, 0x01, 0x1F, 0xD1, 
+    0x00, 0x02, 0x03, 0x04, 0x1F, 0xD0, 0x00, 0x02, 0x03, 0x06, 0x1F, 0xD2, 0x00, 0x03, 0x03, 0x08, 
+    0x03, 0x00, 0x03, 0x90, 0x00, 0x03, 0x03, 0x08, 0x03, 0x01, 0x1F, 0xD2, 0x00, 0x03, 0x03, 0x08, 
+    0x03, 0x40, 0x03, 0x90, 0x00, 0x03, 0x03, 0x08, 0x03, 0x41, 0x1F, 0xD7, 0x00, 0x03, 0x03, 0x08, 
+    0x03, 0x42, 0x03, 0xCA, 0x00, 0x02, 0x03, 0x08, 0x1F, 0x32, 0x00, 0x03, 0x03, 0x13, 0x03, 0x00, 
+    0x1F, 0x34, 0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 0x1F, 0x32, 0x00, 0x03, 0x03, 0x13, 0x03, 0x40, 
+    0x1F, 0x34, 0x00, 0x03, 0x03, 0x13, 0x03, 0x41, 0x1F, 0x36, 0x00, 0x03, 0x03, 0x13, 0x03, 0x42, 
+    0x1F, 0x30, 0x00, 0x02, 0x03, 0x13, 0x1F, 0x33, 0x00, 0x03, 0x03, 0x14, 0x03, 0x00, 0x1F, 0x35, 
+    0x00, 0x03, 0x03, 0x14, 0x03, 0x01, 0x1F, 0x33, 0x00, 0x03, 0x03, 0x14, 0x03, 0x40, 0x1F, 0x35, 
+    0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 0x1F, 0x37, 0x00, 0x03, 0x03, 0x14, 0x03, 0x42, 0x1F, 0x31, 
+    0x00, 0x02, 0x03, 0x14, 0x1F, 0x76, 0x00, 0x02, 0x03, 0x40, 0x03, 0xAF, 0x00, 0x02, 0x03, 0x41, 
+    0x1F, 0xD6, 0x00, 0x02, 0x03, 0x42, 0x1F, 0x32, 0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 0x1F, 0x34, 
+    0x00, 0x03, 0x03, 0x43, 0x03, 0x01, 0x1F, 0x32, 0x00, 0x03, 0x03, 0x43, 0x03, 0x40, 0x1F, 0x34, 
+    0x00, 0x03, 0x03, 0x43, 0x03, 0x41, 0x1F, 0x36, 0x00, 0x03, 0x03, 0x43, 0x03, 0x42, 0x1F, 0x30, 
+    0x00, 0x02, 0x03, 0x43, 0x03, 0x90, 0x00, 0x02, 0x03, 0x44, 0x00, 0x13, 0x00, 0x28, 0x00, 0x2E, 
+    0x00, 0x34, 0x00, 0x3C, 0x00, 0x44, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 0x00, 0x6A, 
+    0x00, 0x72, 0x00, 0x7A, 0x00, 0x80, 0x00, 0x86, 0x00, 0x8C, 0x00, 0x94, 0x00, 0x9C, 0x00, 0xA4, 
+    0x00, 0xAC, 0x1F, 0x78, 0x00, 0x02, 0x03, 0x00, 0x03, 0xCC, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x42, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x00, 0x1F, 0x44, 0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 0x1F, 0x42, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x40, 0x1F, 0x44, 0x00, 0x03, 0x03, 0x13, 0x03, 0x41, 0x1F, 0x40, 
+    0x00, 0x02, 0x03, 0x13, 0x1F, 0x43, 0x00, 0x03, 0x03, 0x14, 0x03, 0x00, 0x1F, 0x45, 0x00, 0x03, 
+    0x03, 0x14, 0x03, 0x01, 0x1F, 0x43, 0x00, 0x03, 0x03, 0x14, 0x03, 0x40, 0x1F, 0x45, 0x00, 0x03, 
+    0x03, 0x14, 0x03, 0x41, 0x1F, 0x41, 0x00, 0x02, 0x03, 0x14, 0x1F, 0x78, 0x00, 0x02, 0x03, 0x40, 
+    0x03, 0xCC, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x42, 0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 0x1F, 0x44, 
+    0x00, 0x03, 0x03, 0x43, 0x03, 0x01, 0x1F, 0x42, 0x00, 0x03, 0x03, 0x43, 0x03, 0x40, 0x1F, 0x44, 
+    0x00, 0x03, 0x03, 0x43, 0x03, 0x41, 0x1F, 0x40, 0x00, 0x02, 0x03, 0x43, 0x00, 0x03, 0x00, 0x08, 
+    0x00, 0x0E, 0x00, 0x14, 0x1F, 0xE4, 0x00, 0x02, 0x03, 0x13, 0x1F, 0xE5, 0x00, 0x02, 0x03, 0x14, 
+    0x1F, 0xE4, 0x00, 0x02, 0x03, 0x43, 0x00, 0x20, 0x00, 0x42, 0x00, 0x48, 0x00, 0x4E, 0x00, 0x54, 
+    0x00, 0x5A, 0x00, 0x62, 0x00, 0x6A, 0x00, 0x72, 0x00, 0x7A, 0x00, 0x82, 0x00, 0x88, 0x00, 0x90, 
+    0x00, 0x98, 0x00, 0xA0, 0x00, 0xA8, 0x00, 0xB0, 0x00, 0xB6, 0x00, 0xBE, 0x00, 0xC6, 0x00, 0xCE, 
+    0x00, 0xD6, 0x00, 0xDE, 0x00, 0xE4, 0x00, 0xEA, 0x00, 0xF0, 0x00, 0xF6, 0x00, 0xFE, 0x01, 0x06, 
+    0x01, 0x0E, 0x01, 0x16, 0x01, 0x1E, 0x01, 0x24, 0x1F, 0x7A, 0x00, 0x02, 0x03, 0x00, 0x03, 0xCD, 
+    0x00, 0x02, 0x03, 0x01, 0x1F, 0xE1, 0x00, 0x02, 0x03, 0x04, 0x1F, 0xE0, 0x00, 0x02, 0x03, 0x06, 
+    0x1F, 0xE2, 0x00, 0x03, 0x03, 0x08, 0x03, 0x00, 0x03, 0xB0, 0x00, 0x03, 0x03, 0x08, 0x03, 0x01, 
+    0x1F, 0xE2, 0x00, 0x03, 0x03, 0x08, 0x03, 0x40, 0x03, 0xB0, 0x00, 0x03, 0x03, 0x08, 0x03, 0x41, 
+    0x1F, 0xE7, 0x00, 0x03, 0x03, 0x08, 0x03, 0x42, 0x03, 0xCB, 0x00, 0x02, 0x03, 0x08, 0x1F, 0x52, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x00, 0x1F, 0x54, 0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 0x1F, 0x52, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x40, 0x1F, 0x54, 0x00, 0x03, 0x03, 0x13, 0x03, 0x41, 0x1F, 0x56, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x42, 0x1F, 0x50, 0x00, 0x02, 0x03, 0x13, 0x1F, 0x53, 0x00, 0x03, 
+    0x03, 0x14, 0x03, 0x00, 0x1F, 0x55, 0x00, 0x03, 0x03, 0x14, 0x03, 0x01, 0x1F, 0x53, 0x00, 0x03, 
+    0x03, 0x14, 0x03, 0x40, 0x1F, 0x55, 0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 0x1F, 0x57, 0x00, 0x03, 
+    0x03, 0x14, 0x03, 0x42, 0x1F, 0x51, 0x00, 0x02, 0x03, 0x14, 0x1F, 0x7A, 0x00, 0x02, 0x03, 0x40, 
+    0x03, 0xCD, 0x00, 0x02, 0x03, 0x41, 0x1F, 0xE6, 0x00, 0x02, 0x03, 0x42, 0x1F, 0x52, 0x00, 0x03, 
+    0x03, 0x43, 0x03, 0x00, 0x1F, 0x54, 0x00, 0x03, 0x03, 0x43, 0x03, 0x01, 0x1F, 0x52, 0x00, 0x03, 
+    0x03, 0x43, 0x03, 0x40, 0x1F, 0x54, 0x00, 0x03, 0x03, 0x43, 0x03, 0x41, 0x1F, 0x56, 0x00, 0x03, 
+    0x03, 0x43, 0x03, 0x42, 0x1F, 0x50, 0x00, 0x02, 0x03, 0x43, 0x03, 0xB0, 0x00, 0x02, 0x03, 0x44, 
+    0x00, 0x55, 0x00, 0xAC, 0x00, 0xB4, 0x00, 0xBA, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xD2, 0x00, 0xDA, 
+    0x00, 0xE4, 0x00, 0xEC, 0x00, 0xF6, 0x00, 0xFE, 0x01, 0x08, 0x01, 0x10, 0x01, 0x1A, 0x01, 0x22, 
+    0x01, 0x2C, 0x01, 0x36, 0x01, 0x40, 0x01, 0x4A, 0x01, 0x54, 0x01, 0x5C, 0x01, 0x62, 0x01, 0x6C, 
+    0x01, 0x74, 0x01, 0x7E, 0x01, 0x86, 0x01, 0x90, 0x01, 0x98, 0x01, 0xA2, 0x01, 0xAA, 0x01, 0xB4, 
+    0x01, 0xBC, 0x01, 0xC6, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xE4, 0x01, 0xEE, 0x01, 0xF6, 0x01, 0xFC, 
+    0x02, 0x04, 0x02, 0x0A, 0x02, 0x12, 0x02, 0x18, 0x02, 0x20, 0x02, 0x26, 0x02, 0x30, 0x02, 0x38, 
+    0x02, 0x42, 0x02, 0x4A, 0x02, 0x54, 0x02, 0x5C, 0x02, 0x66, 0x02, 0x6E, 0x02, 0x78, 0x02, 0x80, 
+    0x02, 0x8A, 0x02, 0x94, 0x02, 0x9E, 0x02, 0xA8, 0x02, 0xB2, 0x02, 0xBA, 0x02, 0xC0, 0x02, 0xC8, 
+    0x02, 0xD0, 0x02, 0xDA, 0x02, 0xE4, 0x02, 0xEE, 0x02, 0xF8, 0x03, 0x02, 0x03, 0x0A, 0x03, 0x14, 
+    0x03, 0x1E, 0x03, 0x28, 0x03, 0x32, 0x03, 0x3C, 0x03, 0x44, 0x03, 0x4C, 0x03, 0x54, 0x03, 0x5C, 
+    0x03, 0x66, 0x03, 0x70, 0x03, 0x7A, 0x03, 0x84, 0x03, 0x8E, 0x03, 0x96, 0x1F, 0xF2, 0x00, 0x03, 
+    0x03, 0x00, 0x03, 0x45, 0x1F, 0x7C, 0x00, 0x02, 0x03, 0x00, 0x1F, 0xF4, 0x00, 0x03, 0x03, 0x01, 
+    0x03, 0x45, 0x03, 0xCE, 0x00, 0x02, 0x03, 0x01, 0x1F, 0xA2, 0x00, 0x04, 0x03, 0x13, 0x03, 0x00, 
+    0x03, 0x45, 0x1F, 0x62, 0x00, 0x03, 0x03, 0x13, 0x03, 0x00, 0x1F, 0xA4, 0x00, 0x04, 0x03, 0x13, 
+    0x03, 0x01, 0x03, 0x45, 0x1F, 0x64, 0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 0x1F, 0xA2, 0x00, 0x04, 
+    0x03, 0x13, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x62, 0x00, 0x03, 0x03, 0x13, 0x03, 0x40, 0x1F, 0xA4, 
+    0x00, 0x04, 0x03, 0x13, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x64, 0x00, 0x03, 0x03, 0x13, 0x03, 0x41, 
+    0x1F, 0xA6, 0x00, 0x04, 0x03, 0x13, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x66, 0x00, 0x03, 0x03, 0x13, 
+    0x03, 0x42, 0x1F, 0xA2, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x00, 0x1F, 0xA4, 0x00, 0x04, 
+    0x03, 0x13, 0x03, 0x45, 0x03, 0x01, 0x1F, 0xA2, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x40, 
+    0x1F, 0xA4, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x41, 0x1F, 0xA6, 0x00, 0x04, 0x03, 0x13, 
+    0x03, 0x45, 0x03, 0x42, 0x1F, 0xA0, 0x00, 0x03, 0x03, 0x13, 0x03, 0x45, 0x1F, 0x60, 0x00, 0x02, 
+    0x03, 0x13, 0x1F, 0xA3, 0x00, 0x04, 0x03, 0x14, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x63, 0x00, 0x03, 
+    0x03, 0x14, 0x03, 0x00, 0x1F, 0xA5, 0x00, 0x04, 0x03, 0x14, 0x03, 0x01, 0x03, 0x45, 0x1F, 0x65, 
+    0x00, 0x03, 0x03, 0x14, 0x03, 0x01, 0x1F, 0xA3, 0x00, 0x04, 0x03, 0x14, 0x03, 0x40, 0x03, 0x45, 
+    0x1F, 0x63, 0x00, 0x03, 0x03, 0x14, 0x03, 0x40, 0x1F, 0xA5, 0x00, 0x04, 0x03, 0x14, 0x03, 0x41, 
+    0x03, 0x45, 0x1F, 0x65, 0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 0x1F, 0xA7, 0x00, 0x04, 0x03, 0x14, 
+    0x03, 0x42, 0x03, 0x45, 0x1F, 0x67, 0x00, 0x03, 0x03, 0x14, 0x03, 0x42, 0x1F, 0xA3, 0x00, 0x04, 
+    0x03, 0x14, 0x03, 0x45, 0x03, 0x00, 0x1F, 0xA5, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x01, 
+    0x1F, 0xA3, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x40, 0x1F, 0xA5, 0x00, 0x04, 0x03, 0x14, 
+    0x03, 0x45, 0x03, 0x41, 0x1F, 0xA7, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x42, 0x1F, 0xA1, 
+    0x00, 0x03, 0x03, 0x14, 0x03, 0x45, 0x1F, 0x61, 0x00, 0x02, 0x03, 0x14, 0x1F, 0xF2, 0x00, 0x03, 
+    0x03, 0x40, 0x03, 0x45, 0x1F, 0x7C, 0x00, 0x02, 0x03, 0x40, 0x1F, 0xF4, 0x00, 0x03, 0x03, 0x41, 
+    0x03, 0x45, 0x03, 0xCE, 0x00, 0x02, 0x03, 0x41, 0x1F, 0xF7, 0x00, 0x03, 0x03, 0x42, 0x03, 0x45, 
+    0x1F, 0xF6, 0x00, 0x02, 0x03, 0x42, 0x1F, 0xA2, 0x00, 0x04, 0x03, 0x43, 0x03, 0x00, 0x03, 0x45, 
+    0x1F, 0x62, 0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 0x1F, 0xA4, 0x00, 0x04, 0x03, 0x43, 0x03, 0x01, 
+    0x03, 0x45, 0x1F, 0x64, 0x00, 0x03, 0x03, 0x43, 0x03, 0x01, 0x1F, 0xA2, 0x00, 0x04, 0x03, 0x43, 
+    0x03, 0x40, 0x03, 0x45, 0x1F, 0x62, 0x00, 0x03, 0x03, 0x43, 0x03, 0x40, 0x1F, 0xA4, 0x00, 0x04, 
+    0x03, 0x43, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x64, 0x00, 0x03, 0x03, 0x43, 0x03, 0x41, 0x1F, 0xA6, 
+    0x00, 0x04, 0x03, 0x43, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x66, 0x00, 0x03, 0x03, 0x43, 0x03, 0x42, 
+    0x1F, 0xA2, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x00, 0x1F, 0xA4, 0x00, 0x04, 0x03, 0x43, 
+    0x03, 0x45, 0x03, 0x01, 0x1F, 0xA2, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x40, 0x1F, 0xA4, 
+    0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x41, 0x1F, 0xA6, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 
+    0x03, 0x42, 0x1F, 0xA0, 0x00, 0x03, 0x03, 0x43, 0x03, 0x45, 0x1F, 0x60, 0x00, 0x02, 0x03, 0x43, 
+    0x1F, 0xF2, 0x00, 0x03, 0x03, 0x45, 0x03, 0x00, 0x1F, 0xF4, 0x00, 0x03, 0x03, 0x45, 0x03, 0x01, 
+    0x1F, 0xA2, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x00, 0x1F, 0xA4, 0x00, 0x04, 0x03, 0x45, 
+    0x03, 0x13, 0x03, 0x01, 0x1F, 0xA2, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x40, 0x1F, 0xA4, 
+    0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x41, 0x1F, 0xA6, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 
+    0x03, 0x42, 0x1F, 0xA0, 0x00, 0x03, 0x03, 0x45, 0x03, 0x13, 0x1F, 0xA3, 0x00, 0x04, 0x03, 0x45, 
+    0x03, 0x14, 0x03, 0x00, 0x1F, 0xA5, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x01, 0x1F, 0xA3, 
+    0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x40, 0x1F, 0xA5, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 
+    0x03, 0x41, 0x1F, 0xA7, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x42, 0x1F, 0xA1, 0x00, 0x03, 
+    0x03, 0x45, 0x03, 0x14, 0x1F, 0xF2, 0x00, 0x03, 0x03, 0x45, 0x03, 0x40, 0x1F, 0xF4, 0x00, 0x03, 
+    0x03, 0x45, 0x03, 0x41, 0x1F, 0xF7, 0x00, 0x03, 0x03, 0x45, 0x03, 0x42, 0x1F, 0xA2, 0x00, 0x04, 
+    0x03, 0x45, 0x03, 0x43, 0x03, 0x00, 0x1F, 0xA4, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x01, 
+    0x1F, 0xA2, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x40, 0x1F, 0xA4, 0x00, 0x04, 0x03, 0x45, 
+    0x03, 0x43, 0x03, 0x41, 0x1F, 0xA6, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x42, 0x1F, 0xA0, 
+    0x00, 0x03, 0x03, 0x45, 0x03, 0x43, 0x1F, 0xF3, 0x00, 0x02, 0x03, 0x45, 0x00, 0x05, 0x00, 0x0C, 
+    0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x1F, 0xD2, 0x00, 0x02, 0x03, 0x00, 0x03, 0x90, 
+    0x00, 0x02, 0x03, 0x01, 0x1F, 0xD2, 0x00, 0x02, 0x03, 0x40, 0x03, 0x90, 0x00, 0x02, 0x03, 0x41, 
+    0x1F, 0xD7, 0x00, 0x02, 0x03, 0x42, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 
+    0x00, 0x24, 0x1F, 0xE2, 0x00, 0x02, 0x03, 0x00, 0x03, 0xB0, 0x00, 0x02, 0x03, 0x01, 0x1F, 0xE2, 
+    0x00, 0x02, 0x03, 0x40, 0x03, 0xB0, 0x00, 0x02, 0x03, 0x41, 0x1F, 0xE7, 0x00, 0x02, 0x03, 0x42, 
+    0x00, 0x01, 0x00, 0x04, 0x1F, 0xF4, 0x00, 0x02, 0x03, 0x45, 0x00, 0x03, 0x00, 0x08, 0x00, 0x0E, 
+    0x00, 0x14, 0x03, 0xD3, 0x00, 0x02, 0x03, 0x01, 0x03, 0xD4, 0x00, 0x02, 0x03, 0x08, 0x03, 0xD3, 
+    0x00, 0x02, 0x03, 0x41, 0x00, 0x10, 0x00, 0x22, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x38, 0x00, 0x3E, 
+    0x00, 0x46, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 
+    0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 0x1F, 0x82, 0x00, 0x03, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x02, 
+    0x00, 0x02, 0x03, 0x00, 0x1F, 0x84, 0x00, 0x03, 0x03, 0x01, 0x03, 0x45, 0x1F, 0x04, 0x00, 0x02, 
+    0x03, 0x01, 0x1F, 0x82, 0x00, 0x03, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x02, 0x00, 0x02, 0x03, 0x40, 
+    0x1F, 0x84, 0x00, 0x03, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x04, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x86, 
+    0x00, 0x03, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x06, 0x00, 0x02, 0x03, 0x42, 0x1F, 0x82, 0x00, 0x03, 
+    0x03, 0x45, 0x03, 0x00, 0x1F, 0x84, 0x00, 0x03, 0x03, 0x45, 0x03, 0x01, 0x1F, 0x82, 0x00, 0x03, 
+    0x03, 0x45, 0x03, 0x40, 0x1F, 0x84, 0x00, 0x03, 0x03, 0x45, 0x03, 0x41, 0x1F, 0x86, 0x00, 0x03, 
+    0x03, 0x45, 0x03, 0x42, 0x1F, 0x80, 0x00, 0x02, 0x03, 0x45, 0x00, 0x10, 0x00, 0x22, 0x00, 0x2A, 
+    0x00, 0x30, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x46, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 
+    0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 0x1F, 0x83, 0x00, 0x03, 
+    0x03, 0x00, 0x03, 0x45, 0x1F, 0x03, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x85, 0x00, 0x03, 0x03, 0x01, 
+    0x03, 0x45, 0x1F, 0x05, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x83, 0x00, 0x03, 0x03, 0x40, 0x03, 0x45, 
+    0x1F, 0x03, 0x00, 0x02, 0x03, 0x40, 0x1F, 0x85, 0x00, 0x03, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x05, 
+    0x00, 0x02, 0x03, 0x41, 0x1F, 0x87, 0x00, 0x03, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x07, 0x00, 0x02, 
+    0x03, 0x42, 0x1F, 0x83, 0x00, 0x03, 0x03, 0x45, 0x03, 0x00, 0x1F, 0x85, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x01, 0x1F, 0x83, 0x00, 0x03, 0x03, 0x45, 0x03, 0x40, 0x1F, 0x85, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x41, 0x1F, 0x87, 0x00, 0x03, 0x03, 0x45, 0x03, 0x42, 0x1F, 0x81, 0x00, 0x02, 0x03, 0x45, 
+    0x00, 0x01, 0x00, 0x04, 0x1F, 0x82, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0x83, 
+    0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0x84, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 
+    0x00, 0x04, 0x1F, 0x85, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0x86, 0x00, 0x02, 
+    0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0x87, 0x00, 0x02, 0x03, 0x45, 0x00, 0x10, 0x00, 0x22, 
+    0x00, 0x2A, 0x00, 0x30, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x46, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x5A, 
+    0x00, 0x62, 0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 0x1F, 0x8A, 
+    0x00, 0x03, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x0A, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x8C, 0x00, 0x03, 
+    0x03, 0x01, 0x03, 0x45, 0x1F, 0x0C, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x8A, 0x00, 0x03, 0x03, 0x40, 
+    0x03, 0x45, 0x1F, 0x0A, 0x00, 0x02, 0x03, 0x40, 0x1F, 0x8C, 0x00, 0x03, 0x03, 0x41, 0x03, 0x45, 
+    0x1F, 0x0C, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x8E, 0x00, 0x03, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x0E, 
+    0x00, 0x02, 0x03, 0x42, 0x1F, 0x8A, 0x00, 0x03, 0x03, 0x45, 0x03, 0x00, 0x1F, 0x8C, 0x00, 0x03, 
+    0x03, 0x45, 0x03, 0x01, 0x1F, 0x8A, 0x00, 0x03, 0x03, 0x45, 0x03, 0x40, 0x1F, 0x8C, 0x00, 0x03, 
+    0x03, 0x45, 0x03, 0x41, 0x1F, 0x8E, 0x00, 0x03, 0x03, 0x45, 0x03, 0x42, 0x1F, 0x88, 0x00, 0x02, 
+    0x03, 0x45, 0x00, 0x10, 0x00, 0x22, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x46, 
+    0x00, 0x4C, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 
+    0x00, 0x88, 0x00, 0x90, 0x1F, 0x8B, 0x00, 0x03, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x0B, 0x00, 0x02, 
+    0x03, 0x00, 0x1F, 0x8D, 0x00, 0x03, 0x03, 0x01, 0x03, 0x45, 0x1F, 0x0D, 0x00, 0x02, 0x03, 0x01, 
+    0x1F, 0x8B, 0x00, 0x03, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x0B, 0x00, 0x02, 0x03, 0x40, 0x1F, 0x8D, 
+    0x00, 0x03, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x0D, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x8F, 0x00, 0x03, 
+    0x03, 0x42, 0x03, 0x45, 0x1F, 0x0F, 0x00, 0x02, 0x03, 0x42, 0x1F, 0x8B, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x00, 0x1F, 0x8D, 0x00, 0x03, 0x03, 0x45, 0x03, 0x01, 0x1F, 0x8B, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x40, 0x1F, 0x8D, 0x00, 0x03, 0x03, 0x45, 0x03, 0x41, 0x1F, 0x8F, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x42, 0x1F, 0x89, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0x8A, 0x00, 0x02, 
+    0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0x8B, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 
+    0x1F, 0x8C, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0x8D, 0x00, 0x02, 0x03, 0x45, 
+    0x00, 0x01, 0x00, 0x04, 0x1F, 0x8E, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0x8F, 
+    0x00, 0x02, 0x03, 0x45, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 0x1F, 0x12, 
+    0x00, 0x02, 0x03, 0x00, 0x1F, 0x14, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x12, 0x00, 0x02, 0x03, 0x40, 
+    0x1F, 0x14, 0x00, 0x02, 0x03, 0x41, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 
+    0x1F, 0x13, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x15, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x13, 0x00, 0x02, 
+    0x03, 0x40, 0x1F, 0x15, 0x00, 0x02, 0x03, 0x41, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x16, 
+    0x00, 0x1C, 0x1F, 0x1A, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x1C, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x1A, 
+    0x00, 0x02, 0x03, 0x40, 0x1F, 0x1C, 0x00, 0x02, 0x03, 0x41, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x10, 
+    0x00, 0x16, 0x00, 0x1C, 0x1F, 0x1B, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x1D, 0x00, 0x02, 0x03, 0x01, 
+    0x1F, 0x1B, 0x00, 0x02, 0x03, 0x40, 0x1F, 0x1D, 0x00, 0x02, 0x03, 0x41, 0x00, 0x10, 0x00, 0x22, 
+    0x00, 0x2A, 0x00, 0x30, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x46, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x5A, 
+    0x00, 0x62, 0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 0x1F, 0x92, 
+    0x00, 0x03, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x22, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x94, 0x00, 0x03, 
+    0x03, 0x01, 0x03, 0x45, 0x1F, 0x24, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x92, 0x00, 0x03, 0x03, 0x40, 
+    0x03, 0x45, 0x1F, 0x22, 0x00, 0x02, 0x03, 0x40, 0x1F, 0x94, 0x00, 0x03, 0x03, 0x41, 0x03, 0x45, 
+    0x1F, 0x24, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x96, 0x00, 0x03, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x26, 
+    0x00, 0x02, 0x03, 0x42, 0x1F, 0x92, 0x00, 0x03, 0x03, 0x45, 0x03, 0x00, 0x1F, 0x94, 0x00, 0x03, 
+    0x03, 0x45, 0x03, 0x01, 0x1F, 0x92, 0x00, 0x03, 0x03, 0x45, 0x03, 0x40, 0x1F, 0x94, 0x00, 0x03, 
+    0x03, 0x45, 0x03, 0x41, 0x1F, 0x96, 0x00, 0x03, 0x03, 0x45, 0x03, 0x42, 0x1F, 0x90, 0x00, 0x02, 
+    0x03, 0x45, 0x00, 0x10, 0x00, 0x22, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x46, 
+    0x00, 0x4C, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 
+    0x00, 0x88, 0x00, 0x90, 0x1F, 0x93, 0x00, 0x03, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x23, 0x00, 0x02, 
+    0x03, 0x00, 0x1F, 0x95, 0x00, 0x03, 0x03, 0x01, 0x03, 0x45, 0x1F, 0x25, 0x00, 0x02, 0x03, 0x01, 
+    0x1F, 0x93, 0x00, 0x03, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x23, 0x00, 0x02, 0x03, 0x40, 0x1F, 0x95, 
+    0x00, 0x03, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x25, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x97, 0x00, 0x03, 
+    0x03, 0x42, 0x03, 0x45, 0x1F, 0x27, 0x00, 0x02, 0x03, 0x42, 0x1F, 0x93, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x00, 0x1F, 0x95, 0x00, 0x03, 0x03, 0x45, 0x03, 0x01, 0x1F, 0x93, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x40, 0x1F, 0x95, 0x00, 0x03, 0x03, 0x45, 0x03, 0x41, 0x1F, 0x97, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x42, 0x1F, 0x91, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0x92, 0x00, 0x02, 
+    0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0x93, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 
+    0x1F, 0x94, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0x95, 0x00, 0x02, 0x03, 0x45, 
+    0x00, 0x01, 0x00, 0x04, 0x1F, 0x96, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0x97, 
+    0x00, 0x02, 0x03, 0x45, 0x00, 0x10, 0x00, 0x22, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x38, 0x00, 0x3E, 
+    0x00, 0x46, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 
+    0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 0x1F, 0x9A, 0x00, 0x03, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x2A, 
+    0x00, 0x02, 0x03, 0x00, 0x1F, 0x9C, 0x00, 0x03, 0x03, 0x01, 0x03, 0x45, 0x1F, 0x2C, 0x00, 0x02, 
+    0x03, 0x01, 0x1F, 0x9A, 0x00, 0x03, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x2A, 0x00, 0x02, 0x03, 0x40, 
+    0x1F, 0x9C, 0x00, 0x03, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x2C, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x9E, 
+    0x00, 0x03, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x2E, 0x00, 0x02, 0x03, 0x42, 0x1F, 0x9A, 0x00, 0x03, 
+    0x03, 0x45, 0x03, 0x00, 0x1F, 0x9C, 0x00, 0x03, 0x03, 0x45, 0x03, 0x01, 0x1F, 0x9A, 0x00, 0x03, 
+    0x03, 0x45, 0x03, 0x40, 0x1F, 0x9C, 0x00, 0x03, 0x03, 0x45, 0x03, 0x41, 0x1F, 0x9E, 0x00, 0x03, 
+    0x03, 0x45, 0x03, 0x42, 0x1F, 0x98, 0x00, 0x02, 0x03, 0x45, 0x00, 0x10, 0x00, 0x22, 0x00, 0x2A, 
+    0x00, 0x30, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x46, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 
+    0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 0x1F, 0x9B, 0x00, 0x03, 
+    0x03, 0x00, 0x03, 0x45, 0x1F, 0x2B, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x9D, 0x00, 0x03, 0x03, 0x01, 
+    0x03, 0x45, 0x1F, 0x2D, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x9B, 0x00, 0x03, 0x03, 0x40, 0x03, 0x45, 
+    0x1F, 0x2B, 0x00, 0x02, 0x03, 0x40, 0x1F, 0x9D, 0x00, 0x03, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x2D, 
+    0x00, 0x02, 0x03, 0x41, 0x1F, 0x9F, 0x00, 0x03, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x2F, 0x00, 0x02, 
+    0x03, 0x42, 0x1F, 0x9B, 0x00, 0x03, 0x03, 0x45, 0x03, 0x00, 0x1F, 0x9D, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x01, 0x1F, 0x9B, 0x00, 0x03, 0x03, 0x45, 0x03, 0x40, 0x1F, 0x9D, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x41, 0x1F, 0x9F, 0x00, 0x03, 0x03, 0x45, 0x03, 0x42, 0x1F, 0x99, 0x00, 0x02, 0x03, 0x45, 
+    0x00, 0x01, 0x00, 0x04, 0x1F, 0x9A, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0x9B, 
+    0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0x9C, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 
+    0x00, 0x04, 0x1F, 0x9D, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0x9E, 0x00, 0x02, 
+    0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0x9F, 0x00, 0x02, 0x03, 0x45, 0x00, 0x05, 0x00, 0x0C, 
+    0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x1F, 0x32, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x34, 
+    0x00, 0x02, 0x03, 0x01, 0x1F, 0x32, 0x00, 0x02, 0x03, 0x40, 0x1F, 0x34, 0x00, 0x02, 0x03, 0x41, 
+    0x1F, 0x36, 0x00, 0x02, 0x03, 0x42, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 
+    0x00, 0x24, 0x1F, 0x33, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x35, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x33, 
+    0x00, 0x02, 0x03, 0x40, 0x1F, 0x35, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x37, 0x00, 0x02, 0x03, 0x42, 
+    0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x1F, 0x3A, 0x00, 0x02, 
+    0x03, 0x00, 0x1F, 0x3C, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x3A, 0x00, 0x02, 0x03, 0x40, 0x1F, 0x3C, 
+    0x00, 0x02, 0x03, 0x41, 0x1F, 0x3E, 0x00, 0x02, 0x03, 0x42, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 
+    0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x1F, 0x3B, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x3D, 0x00, 0x02, 
+    0x03, 0x01, 0x1F, 0x3B, 0x00, 0x02, 0x03, 0x40, 0x1F, 0x3D, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x3F, 
+    0x00, 0x02, 0x03, 0x42, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 0x1F, 0x42, 
+    0x00, 0x02, 0x03, 0x00, 0x1F, 0x44, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x42, 0x00, 0x02, 0x03, 0x40, 
+    0x1F, 0x44, 0x00, 0x02, 0x03, 0x41, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 
+    0x1F, 0x43, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x45, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x43, 0x00, 0x02, 
+    0x03, 0x40, 0x1F, 0x45, 0x00, 0x02, 0x03, 0x41, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x16, 
+    0x00, 0x1C, 0x1F, 0x4A, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x4C, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x4A, 
+    0x00, 0x02, 0x03, 0x40, 0x1F, 0x4C, 0x00, 0x02, 0x03, 0x41, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x10, 
+    0x00, 0x16, 0x00, 0x1C, 0x1F, 0x4B, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x4D, 0x00, 0x02, 0x03, 0x01, 
+    0x1F, 0x4B, 0x00, 0x02, 0x03, 0x40, 0x1F, 0x4D, 0x00, 0x02, 0x03, 0x41, 0x00, 0x05, 0x00, 0x0C, 
+    0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x1F, 0x52, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x54, 
+    0x00, 0x02, 0x03, 0x01, 0x1F, 0x52, 0x00, 0x02, 0x03, 0x40, 0x1F, 0x54, 0x00, 0x02, 0x03, 0x41, 
+    0x1F, 0x56, 0x00, 0x02, 0x03, 0x42, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 
+    0x00, 0x24, 0x1F, 0x53, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x55, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x53, 
+    0x00, 0x02, 0x03, 0x40, 0x1F, 0x55, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x57, 0x00, 0x02, 0x03, 0x42, 
+    0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x1F, 0x5B, 0x00, 0x02, 
+    0x03, 0x00, 0x1F, 0x5D, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x5B, 0x00, 0x02, 0x03, 0x40, 0x1F, 0x5D, 
+    0x00, 0x02, 0x03, 0x41, 0x1F, 0x5F, 0x00, 0x02, 0x03, 0x42, 0x00, 0x10, 0x00, 0x22, 0x00, 0x2A, 
+    0x00, 0x30, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x46, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 
+    0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 0x1F, 0xA2, 0x00, 0x03, 
+    0x03, 0x00, 0x03, 0x45, 0x1F, 0x62, 0x00, 0x02, 0x03, 0x00, 0x1F, 0xA4, 0x00, 0x03, 0x03, 0x01, 
+    0x03, 0x45, 0x1F, 0x64, 0x00, 0x02, 0x03, 0x01, 0x1F, 0xA2, 0x00, 0x03, 0x03, 0x40, 0x03, 0x45, 
+    0x1F, 0x62, 0x00, 0x02, 0x03, 0x40, 0x1F, 0xA4, 0x00, 0x03, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x64, 
+    0x00, 0x02, 0x03, 0x41, 0x1F, 0xA6, 0x00, 0x03, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x66, 0x00, 0x02, 
+    0x03, 0x42, 0x1F, 0xA2, 0x00, 0x03, 0x03, 0x45, 0x03, 0x00, 0x1F, 0xA4, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x01, 0x1F, 0xA2, 0x00, 0x03, 0x03, 0x45, 0x03, 0x40, 0x1F, 0xA4, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x41, 0x1F, 0xA6, 0x00, 0x03, 0x03, 0x45, 0x03, 0x42, 0x1F, 0xA0, 0x00, 0x02, 0x03, 0x45, 
+    0x00, 0x10, 0x00, 0x22, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x46, 0x00, 0x4C, 
+    0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 
+    0x00, 0x90, 0x1F, 0xA3, 0x00, 0x03, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x63, 0x00, 0x02, 0x03, 0x00, 
+    0x1F, 0xA5, 0x00, 0x03, 0x03, 0x01, 0x03, 0x45, 0x1F, 0x65, 0x00, 0x02, 0x03, 0x01, 0x1F, 0xA3, 
+    0x00, 0x03, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x63, 0x00, 0x02, 0x03, 0x40, 0x1F, 0xA5, 0x00, 0x03, 
+    0x03, 0x41, 0x03, 0x45, 0x1F, 0x65, 0x00, 0x02, 0x03, 0x41, 0x1F, 0xA7, 0x00, 0x03, 0x03, 0x42, 
+    0x03, 0x45, 0x1F, 0x67, 0x00, 0x02, 0x03, 0x42, 0x1F, 0xA3, 0x00, 0x03, 0x03, 0x45, 0x03, 0x00, 
+    0x1F, 0xA5, 0x00, 0x03, 0x03, 0x45, 0x03, 0x01, 0x1F, 0xA3, 0x00, 0x03, 0x03, 0x45, 0x03, 0x40, 
+    0x1F, 0xA5, 0x00, 0x03, 0x03, 0x45, 0x03, 0x41, 0x1F, 0xA7, 0x00, 0x03, 0x03, 0x45, 0x03, 0x42, 
+    0x1F, 0xA1, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0xA2, 0x00, 0x02, 0x03, 0x45, 
+    0x00, 0x01, 0x00, 0x04, 0x1F, 0xA3, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0xA4, 
+    0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0xA5, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 
+    0x00, 0x04, 0x1F, 0xA6, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0xA7, 0x00, 0x02, 
+    0x03, 0x45, 0x00, 0x10, 0x00, 0x22, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x46, 
+    0x00, 0x4C, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 
+    0x00, 0x88, 0x00, 0x90, 0x1F, 0xAA, 0x00, 0x03, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x6A, 0x00, 0x02, 
+    0x03, 0x00, 0x1F, 0xAC, 0x00, 0x03, 0x03, 0x01, 0x03, 0x45, 0x1F, 0x6C, 0x00, 0x02, 0x03, 0x01, 
+    0x1F, 0xAA, 0x00, 0x03, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x6A, 0x00, 0x02, 0x03, 0x40, 0x1F, 0xAC, 
+    0x00, 0x03, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x6C, 0x00, 0x02, 0x03, 0x41, 0x1F, 0xAE, 0x00, 0x03, 
+    0x03, 0x42, 0x03, 0x45, 0x1F, 0x6E, 0x00, 0x02, 0x03, 0x42, 0x1F, 0xAA, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x00, 0x1F, 0xAC, 0x00, 0x03, 0x03, 0x45, 0x03, 0x01, 0x1F, 0xAA, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x40, 0x1F, 0xAC, 0x00, 0x03, 0x03, 0x45, 0x03, 0x41, 0x1F, 0xAE, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x42, 0x1F, 0xA8, 0x00, 0x02, 0x03, 0x45, 0x00, 0x10, 0x00, 0x22, 0x00, 0x2A, 0x00, 0x30, 
+    0x00, 0x38, 0x00, 0x3E, 0x00, 0x46, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 0x00, 0x68, 
+    0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 0x1F, 0xAB, 0x00, 0x03, 0x03, 0x00, 
+    0x03, 0x45, 0x1F, 0x6B, 0x00, 0x02, 0x03, 0x00, 0x1F, 0xAD, 0x00, 0x03, 0x03, 0x01, 0x03, 0x45, 
+    0x1F, 0x6D, 0x00, 0x02, 0x03, 0x01, 0x1F, 0xAB, 0x00, 0x03, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x6B, 
+    0x00, 0x02, 0x03, 0x40, 0x1F, 0xAD, 0x00, 0x03, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x6D, 0x00, 0x02, 
+    0x03, 0x41, 0x1F, 0xAF, 0x00, 0x03, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x6F, 0x00, 0x02, 0x03, 0x42, 
+    0x1F, 0xAB, 0x00, 0x03, 0x03, 0x45, 0x03, 0x00, 0x1F, 0xAD, 0x00, 0x03, 0x03, 0x45, 0x03, 0x01, 
+    0x1F, 0xAB, 0x00, 0x03, 0x03, 0x45, 0x03, 0x40, 0x1F, 0xAD, 0x00, 0x03, 0x03, 0x45, 0x03, 0x41, 
+    0x1F, 0xAF, 0x00, 0x03, 0x03, 0x45, 0x03, 0x42, 0x1F, 0xA9, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 
+    0x00, 0x04, 0x1F, 0xAA, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0xAB, 0x00, 0x02, 
+    0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0xAC, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 
+    0x1F, 0xAD, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0xAE, 0x00, 0x02, 0x03, 0x45, 
+    0x00, 0x01, 0x00, 0x04, 0x1F, 0xAF, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0xB2, 
+    0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0xB4, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 
+    0x00, 0x04, 0x1F, 0xC2, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0xC4, 0x00, 0x02, 
+    0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 0x1F, 0xF2, 0x00, 0x02, 0x03, 0x45, 0x00, 0x01, 0x00, 0x04, 
+    0x1F, 0xF4, 0x00, 0x02, 0x03, 0x45, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 
+    0x00, 0x24, 0x1F, 0x82, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x84, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x82, 
+    0x00, 0x02, 0x03, 0x40, 0x1F, 0x84, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x86, 0x00, 0x02, 0x03, 0x42, 
+    0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x1F, 0x83, 0x00, 0x02, 
+    0x03, 0x00, 0x1F, 0x85, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x83, 0x00, 0x02, 0x03, 0x40, 0x1F, 0x85, 
+    0x00, 0x02, 0x03, 0x41, 0x1F, 0x87, 0x00, 0x02, 0x03, 0x42, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 
+    0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x1F, 0x8A, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x8C, 0x00, 0x02, 
+    0x03, 0x01, 0x1F, 0x8A, 0x00, 0x02, 0x03, 0x40, 0x1F, 0x8C, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x8E, 
+    0x00, 0x02, 0x03, 0x42, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 
+    0x1F, 0x8B, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x8D, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x8B, 0x00, 0x02, 
+    0x03, 0x40, 0x1F, 0x8D, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x8F, 0x00, 0x02, 0x03, 0x42, 0x00, 0x05, 
+    0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x1F, 0x92, 0x00, 0x02, 0x03, 0x00, 
+    0x1F, 0x94, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x92, 0x00, 0x02, 0x03, 0x40, 0x1F, 0x94, 0x00, 0x02, 
+    0x03, 0x41, 0x1F, 0x96, 0x00, 0x02, 0x03, 0x42, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 
+    0x00, 0x1E, 0x00, 0x24, 0x1F, 0x93, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x95, 0x00, 0x02, 0x03, 0x01, 
+    0x1F, 0x93, 0x00, 0x02, 0x03, 0x40, 0x1F, 0x95, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x97, 0x00, 0x02, 
+    0x03, 0x42, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x1F, 0x9A, 
+    0x00, 0x02, 0x03, 0x00, 0x1F, 0x9C, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x9A, 0x00, 0x02, 0x03, 0x40, 
+    0x1F, 0x9C, 0x00, 0x02, 0x03, 0x41, 0x1F, 0x9E, 0x00, 0x02, 0x03, 0x42, 0x00, 0x05, 0x00, 0x0C, 
+    0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x1F, 0x9B, 0x00, 0x02, 0x03, 0x00, 0x1F, 0x9D, 
+    0x00, 0x02, 0x03, 0x01, 0x1F, 0x9B, 0x00, 0x02, 0x03, 0x40, 0x1F, 0x9D, 0x00, 0x02, 0x03, 0x41, 
+    0x1F, 0x9F, 0x00, 0x02, 0x03, 0x42, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 
+    0x00, 0x24, 0x1F, 0xA2, 0x00, 0x02, 0x03, 0x00, 0x1F, 0xA4, 0x00, 0x02, 0x03, 0x01, 0x1F, 0xA2, 
+    0x00, 0x02, 0x03, 0x40, 0x1F, 0xA4, 0x00, 0x02, 0x03, 0x41, 0x1F, 0xA6, 0x00, 0x02, 0x03, 0x42, 
+    0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x1F, 0xA3, 0x00, 0x02, 
+    0x03, 0x00, 0x1F, 0xA5, 0x00, 0x02, 0x03, 0x01, 0x1F, 0xA3, 0x00, 0x02, 0x03, 0x40, 0x1F, 0xA5, 
+    0x00, 0x02, 0x03, 0x41, 0x1F, 0xA7, 0x00, 0x02, 0x03, 0x42, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 
+    0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x1F, 0xAA, 0x00, 0x02, 0x03, 0x00, 0x1F, 0xAC, 0x00, 0x02, 
+    0x03, 0x01, 0x1F, 0xAA, 0x00, 0x02, 0x03, 0x40, 0x1F, 0xAC, 0x00, 0x02, 0x03, 0x41, 0x1F, 0xAE, 
+    0x00, 0x02, 0x03, 0x42, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 
+    0x1F, 0xAB, 0x00, 0x02, 0x03, 0x00, 0x1F, 0xAD, 0x00, 0x02, 0x03, 0x01, 0x1F, 0xAB, 0x00, 0x02, 
+    0x03, 0x40, 0x1F, 0xAD, 0x00, 0x02, 0x03, 0x41, 0x1F, 0xAF, 0x00, 0x02, 0x03, 0x42, 0x00, 0x17, 
+    0x00, 0x30, 0x00, 0x36, 0x00, 0x3C, 0x00, 0x44, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x5C, 0x00, 0x64, 
+    0x00, 0x6A, 0x00, 0x72, 0x00, 0x7A, 0x00, 0x82, 0x00, 0x8A, 0x00, 0x92, 0x00, 0x98, 0x00, 0x9E, 
+    0x00, 0xA4, 0x00, 0xAA, 0x00, 0xB2, 0x00, 0xBA, 0x00, 0xC2, 0x00, 0xCA, 0x00, 0xD2, 0x1F, 0xB2, 
+    0x00, 0x02, 0x03, 0x00, 0x1F, 0xB4, 0x00, 0x02, 0x03, 0x01, 0x1F, 0x82, 0x00, 0x03, 0x03, 0x13, 
+    0x03, 0x00, 0x1F, 0x84, 0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 0x1F, 0x82, 0x00, 0x03, 0x03, 0x13, 
+    0x03, 0x40, 0x1F, 0x84, 0x00, 0x03, 0x03, 0x13, 0x03, 0x41, 0x1F, 0x86, 0x00, 0x03, 0x03, 0x13, 
+    0x03, 0x42, 0x1F, 0x80, 0x00, 0x02, 0x03, 0x13, 0x1F, 0x83, 0x00, 0x03, 0x03, 0x14, 0x03, 0x00, 
+    0x1F, 0x85, 0x00, 0x03, 0x03, 0x14, 0x03, 0x01, 0x1F, 0x83, 0x00, 0x03, 0x03, 0x14, 0x03, 0x40, 
+    0x1F, 0x85, 0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 0x1F, 0x87, 0x00, 0x03, 0x03, 0x14, 0x03, 0x42, 
+    0x1F, 0x81, 0x00, 0x02, 0x03, 0x14, 0x1F, 0xB2, 0x00, 0x02, 0x03, 0x40, 0x1F, 0xB4, 0x00, 0x02, 
+    0x03, 0x41, 0x1F, 0xB7, 0x00, 0x02, 0x03, 0x42, 0x1F, 0x82, 0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 
+    0x1F, 0x84, 0x00, 0x03, 0x03, 0x43, 0x03, 0x01, 0x1F, 0x82, 0x00, 0x03, 0x03, 0x43, 0x03, 0x40, 
+    0x1F, 0x84, 0x00, 0x03, 0x03, 0x43, 0x03, 0x41, 0x1F, 0x86, 0x00, 0x03, 0x03, 0x43, 0x03, 0x42, 
+    0x1F, 0x80, 0x00, 0x02, 0x03, 0x43, 0x00, 0x01, 0x00, 0x04, 0x1F, 0xB7, 0x00, 0x02, 0x03, 0x45, 
+    0x00, 0x12, 0x00, 0x26, 0x00, 0x2E, 0x00, 0x36, 0x00, 0x3E, 0x00, 0x46, 0x00, 0x4E, 0x00, 0x54, 
+    0x00, 0x5C, 0x00, 0x64, 0x00, 0x6C, 0x00, 0x74, 0x00, 0x7C, 0x00, 0x82, 0x00, 0x8A, 0x00, 0x92, 
+    0x00, 0x9A, 0x00, 0xA2, 0x00, 0xAA, 0x1F, 0x8A, 0x00, 0x03, 0x03, 0x13, 0x03, 0x00, 0x1F, 0x8C, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 0x1F, 0x8A, 0x00, 0x03, 0x03, 0x13, 0x03, 0x40, 0x1F, 0x8C, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x41, 0x1F, 0x8E, 0x00, 0x03, 0x03, 0x13, 0x03, 0x42, 0x1F, 0x88, 
+    0x00, 0x02, 0x03, 0x13, 0x1F, 0x8B, 0x00, 0x03, 0x03, 0x14, 0x03, 0x00, 0x1F, 0x8D, 0x00, 0x03, 
+    0x03, 0x14, 0x03, 0x01, 0x1F, 0x8B, 0x00, 0x03, 0x03, 0x14, 0x03, 0x40, 0x1F, 0x8D, 0x00, 0x03, 
+    0x03, 0x14, 0x03, 0x41, 0x1F, 0x8F, 0x00, 0x03, 0x03, 0x14, 0x03, 0x42, 0x1F, 0x89, 0x00, 0x02, 
+    0x03, 0x14, 0x1F, 0x8A, 0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 0x1F, 0x8C, 0x00, 0x03, 0x03, 0x43, 
+    0x03, 0x01, 0x1F, 0x8A, 0x00, 0x03, 0x03, 0x43, 0x03, 0x40, 0x1F, 0x8C, 0x00, 0x03, 0x03, 0x43, 
+    0x03, 0x41, 0x1F, 0x8E, 0x00, 0x03, 0x03, 0x43, 0x03, 0x42, 0x1F, 0x88, 0x00, 0x02, 0x03, 0x43, 
+    0x00, 0x20, 0x00, 0x42, 0x00, 0x48, 0x00, 0x4E, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 0x00, 0x6A, 
+    0x00, 0x72, 0x00, 0x7A, 0x00, 0x82, 0x00, 0x88, 0x00, 0x90, 0x00, 0x98, 0x00, 0xA0, 0x00, 0xA8, 
+    0x00, 0xB0, 0x00, 0xB6, 0x00, 0xBE, 0x00, 0xC6, 0x00, 0xCE, 0x00, 0xD6, 0x00, 0xDE, 0x00, 0xE4, 
+    0x00, 0xEA, 0x00, 0xF0, 0x00, 0xF6, 0x00, 0xFE, 0x01, 0x06, 0x01, 0x0E, 0x01, 0x16, 0x01, 0x1E, 
+    0x01, 0x24, 0x1F, 0x76, 0x00, 0x02, 0x03, 0x00, 0x03, 0xAF, 0x00, 0x02, 0x03, 0x01, 0x1F, 0xD1, 
+    0x00, 0x02, 0x03, 0x04, 0x1F, 0xD0, 0x00, 0x02, 0x03, 0x06, 0x1F, 0xD2, 0x00, 0x03, 0x03, 0x08, 
+    0x03, 0x00, 0x03, 0x90, 0x00, 0x03, 0x03, 0x08, 0x03, 0x01, 0x1F, 0xD2, 0x00, 0x03, 0x03, 0x08, 
+    0x03, 0x40, 0x03, 0x90, 0x00, 0x03, 0x03, 0x08, 0x03, 0x41, 0x1F, 0xD7, 0x00, 0x03, 0x03, 0x08, 
+    0x03, 0x42, 0x03, 0xCA, 0x00, 0x02, 0x03, 0x08, 0x1F, 0x32, 0x00, 0x03, 0x03, 0x13, 0x03, 0x00, 
+    0x1F, 0x34, 0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 0x1F, 0x32, 0x00, 0x03, 0x03, 0x13, 0x03, 0x40, 
+    0x1F, 0x34, 0x00, 0x03, 0x03, 0x13, 0x03, 0x41, 0x1F, 0x36, 0x00, 0x03, 0x03, 0x13, 0x03, 0x42, 
+    0x1F, 0x30, 0x00, 0x02, 0x03, 0x13, 0x1F, 0x33, 0x00, 0x03, 0x03, 0x14, 0x03, 0x00, 0x1F, 0x35, 
+    0x00, 0x03, 0x03, 0x14, 0x03, 0x01, 0x1F, 0x33, 0x00, 0x03, 0x03, 0x14, 0x03, 0x40, 0x1F, 0x35, 
+    0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 0x1F, 0x37, 0x00, 0x03, 0x03, 0x14, 0x03, 0x42, 0x1F, 0x31, 
+    0x00, 0x02, 0x03, 0x14, 0x1F, 0x76, 0x00, 0x02, 0x03, 0x40, 0x03, 0xAF, 0x00, 0x02, 0x03, 0x41, 
+    0x1F, 0xD6, 0x00, 0x02, 0x03, 0x42, 0x1F, 0x32, 0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 0x1F, 0x34, 
+    0x00, 0x03, 0x03, 0x43, 0x03, 0x01, 0x1F, 0x32, 0x00, 0x03, 0x03, 0x43, 0x03, 0x40, 0x1F, 0x34, 
+    0x00, 0x03, 0x03, 0x43, 0x03, 0x41, 0x1F, 0x36, 0x00, 0x03, 0x03, 0x43, 0x03, 0x42, 0x1F, 0x30, 
+    0x00, 0x02, 0x03, 0x43, 0x03, 0x90, 0x00, 0x02, 0x03, 0x44, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 
+    0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x1F, 0xCD, 0x00, 0x02, 0x03, 0x00, 0x1F, 0xCE, 0x00, 0x02, 
+    0x03, 0x01, 0x1F, 0xCD, 0x00, 0x02, 0x03, 0x40, 0x1F, 0xCE, 0x00, 0x02, 0x03, 0x41, 0x1F, 0xCF, 
+    0x00, 0x02, 0x03, 0x42, 0x00, 0x17, 0x00, 0x30, 0x00, 0x36, 0x00, 0x3C, 0x00, 0x44, 0x00, 0x4C, 
+    0x00, 0x54, 0x00, 0x5C, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x72, 0x00, 0x7A, 0x00, 0x82, 0x00, 0x8A, 
+    0x00, 0x92, 0x00, 0x98, 0x00, 0x9E, 0x00, 0xA4, 0x00, 0xAA, 0x00, 0xB2, 0x00, 0xBA, 0x00, 0xC2, 
+    0x00, 0xCA, 0x00, 0xD2, 0x1F, 0xC2, 0x00, 0x02, 0x03, 0x00, 0x1F, 0xC4, 0x00, 0x02, 0x03, 0x01, 
+    0x1F, 0x92, 0x00, 0x03, 0x03, 0x13, 0x03, 0x00, 0x1F, 0x94, 0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 
+    0x1F, 0x92, 0x00, 0x03, 0x03, 0x13, 0x03, 0x40, 0x1F, 0x94, 0x00, 0x03, 0x03, 0x13, 0x03, 0x41, 
+    0x1F, 0x96, 0x00, 0x03, 0x03, 0x13, 0x03, 0x42, 0x1F, 0x90, 0x00, 0x02, 0x03, 0x13, 0x1F, 0x93, 
+    0x00, 0x03, 0x03, 0x14, 0x03, 0x00, 0x1F, 0x95, 0x00, 0x03, 0x03, 0x14, 0x03, 0x01, 0x1F, 0x93, 
+    0x00, 0x03, 0x03, 0x14, 0x03, 0x40, 0x1F, 0x95, 0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 0x1F, 0x97, 
+    0x00, 0x03, 0x03, 0x14, 0x03, 0x42, 0x1F, 0x91, 0x00, 0x02, 0x03, 0x14, 0x1F, 0xC2, 0x00, 0x02, 
+    0x03, 0x40, 0x1F, 0xC4, 0x00, 0x02, 0x03, 0x41, 0x1F, 0xC7, 0x00, 0x02, 0x03, 0x42, 0x1F, 0x92, 
+    0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 0x1F, 0x94, 0x00, 0x03, 0x03, 0x43, 0x03, 0x01, 0x1F, 0x92, 
+    0x00, 0x03, 0x03, 0x43, 0x03, 0x40, 0x1F, 0x94, 0x00, 0x03, 0x03, 0x43, 0x03, 0x41, 0x1F, 0x96, 
+    0x00, 0x03, 0x03, 0x43, 0x03, 0x42, 0x1F, 0x90, 0x00, 0x02, 0x03, 0x43, 0x00, 0x01, 0x00, 0x04, 
+    0x1F, 0xC7, 0x00, 0x02, 0x03, 0x45, 0x00, 0x12, 0x00, 0x26, 0x00, 0x2E, 0x00, 0x36, 0x00, 0x3E, 
+    0x00, 0x46, 0x00, 0x4E, 0x00, 0x54, 0x00, 0x5C, 0x00, 0x64, 0x00, 0x6C, 0x00, 0x74, 0x00, 0x7C, 
+    0x00, 0x82, 0x00, 0x8A, 0x00, 0x92, 0x00, 0x9A, 0x00, 0xA2, 0x00, 0xAA, 0x1F, 0x9A, 0x00, 0x03, 
+    0x03, 0x13, 0x03, 0x00, 0x1F, 0x9C, 0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 0x1F, 0x9A, 0x00, 0x03, 
+    0x03, 0x13, 0x03, 0x40, 0x1F, 0x9C, 0x00, 0x03, 0x03, 0x13, 0x03, 0x41, 0x1F, 0x9E, 0x00, 0x03, 
+    0x03, 0x13, 0x03, 0x42, 0x1F, 0x98, 0x00, 0x02, 0x03, 0x13, 0x1F, 0x9B, 0x00, 0x03, 0x03, 0x14, 
+    0x03, 0x00, 0x1F, 0x9D, 0x00, 0x03, 0x03, 0x14, 0x03, 0x01, 0x1F, 0x9B, 0x00, 0x03, 0x03, 0x14, 
+    0x03, 0x40, 0x1F, 0x9D, 0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 0x1F, 0x9F, 0x00, 0x03, 0x03, 0x14, 
+    0x03, 0x42, 0x1F, 0x99, 0x00, 0x02, 0x03, 0x14, 0x1F, 0x9A, 0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 
+    0x1F, 0x9C, 0x00, 0x03, 0x03, 0x43, 0x03, 0x01, 0x1F, 0x9A, 0x00, 0x03, 0x03, 0x43, 0x03, 0x40, 
+    0x1F, 0x9C, 0x00, 0x03, 0x03, 0x43, 0x03, 0x41, 0x1F, 0x9E, 0x00, 0x03, 0x03, 0x43, 0x03, 0x42, 
+    0x1F, 0x98, 0x00, 0x02, 0x03, 0x43, 0x00, 0x17, 0x00, 0x30, 0x00, 0x36, 0x00, 0x3C, 0x00, 0x44, 
+    0x00, 0x4C, 0x00, 0x54, 0x00, 0x5C, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x72, 0x00, 0x7A, 0x00, 0x82, 
+    0x00, 0x8A, 0x00, 0x92, 0x00, 0x98, 0x00, 0x9E, 0x00, 0xA4, 0x00, 0xAA, 0x00, 0xB2, 0x00, 0xBA, 
+    0x00, 0xC2, 0x00, 0xCA, 0x00, 0xD2, 0x1F, 0xF2, 0x00, 0x02, 0x03, 0x00, 0x1F, 0xF4, 0x00, 0x02, 
+    0x03, 0x01, 0x1F, 0xA2, 0x00, 0x03, 0x03, 0x13, 0x03, 0x00, 0x1F, 0xA4, 0x00, 0x03, 0x03, 0x13, 
+    0x03, 0x01, 0x1F, 0xA2, 0x00, 0x03, 0x03, 0x13, 0x03, 0x40, 0x1F, 0xA4, 0x00, 0x03, 0x03, 0x13, 
+    0x03, 0x41, 0x1F, 0xA6, 0x00, 0x03, 0x03, 0x13, 0x03, 0x42, 0x1F, 0xA0, 0x00, 0x02, 0x03, 0x13, 
+    0x1F, 0xA3, 0x00, 0x03, 0x03, 0x14, 0x03, 0x00, 0x1F, 0xA5, 0x00, 0x03, 0x03, 0x14, 0x03, 0x01, 
+    0x1F, 0xA3, 0x00, 0x03, 0x03, 0x14, 0x03, 0x40, 0x1F, 0xA5, 0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 
+    0x1F, 0xA7, 0x00, 0x03, 0x03, 0x14, 0x03, 0x42, 0x1F, 0xA1, 0x00, 0x02, 0x03, 0x14, 0x1F, 0xF2, 
+    0x00, 0x02, 0x03, 0x40, 0x1F, 0xF4, 0x00, 0x02, 0x03, 0x41, 0x1F, 0xF7, 0x00, 0x02, 0x03, 0x42, 
+    0x1F, 0xA2, 0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 0x1F, 0xA4, 0x00, 0x03, 0x03, 0x43, 0x03, 0x01, 
+    0x1F, 0xA2, 0x00, 0x03, 0x03, 0x43, 0x03, 0x40, 0x1F, 0xA4, 0x00, 0x03, 0x03, 0x43, 0x03, 0x41, 
+    0x1F, 0xA6, 0x00, 0x03, 0x03, 0x43, 0x03, 0x42, 0x1F, 0xA0, 0x00, 0x02, 0x03, 0x43, 0x00, 0x01, 
+    0x00, 0x04, 0x1F, 0xF7, 0x00, 0x02, 0x03, 0x45, 0x00, 0x12, 0x00, 0x26, 0x00, 0x2E, 0x00, 0x36, 
+    0x00, 0x3E, 0x00, 0x46, 0x00, 0x4E, 0x00, 0x54, 0x00, 0x5C, 0x00, 0x64, 0x00, 0x6C, 0x00, 0x74, 
+    0x00, 0x7C, 0x00, 0x82, 0x00, 0x8A, 0x00, 0x92, 0x00, 0x9A, 0x00, 0xA2, 0x00, 0xAA, 0x1F, 0xAA, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x00, 0x1F, 0xAC, 0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 0x1F, 0xAA, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x40, 0x1F, 0xAC, 0x00, 0x03, 0x03, 0x13, 0x03, 0x41, 0x1F, 0xAE, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x42, 0x1F, 0xA8, 0x00, 0x02, 0x03, 0x13, 0x1F, 0xAB, 0x00, 0x03, 
+    0x03, 0x14, 0x03, 0x00, 0x1F, 0xAD, 0x00, 0x03, 0x03, 0x14, 0x03, 0x01, 0x1F, 0xAB, 0x00, 0x03, 
+    0x03, 0x14, 0x03, 0x40, 0x1F, 0xAD, 0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 0x1F, 0xAF, 0x00, 0x03, 
+    0x03, 0x14, 0x03, 0x42, 0x1F, 0xA9, 0x00, 0x02, 0x03, 0x14, 0x1F, 0xAA, 0x00, 0x03, 0x03, 0x43, 
+    0x03, 0x00, 0x1F, 0xAC, 0x00, 0x03, 0x03, 0x43, 0x03, 0x01, 0x1F, 0xAA, 0x00, 0x03, 0x03, 0x43, 
+    0x03, 0x40, 0x1F, 0xAC, 0x00, 0x03, 0x03, 0x43, 0x03, 0x41, 0x1F, 0xAE, 0x00, 0x03, 0x03, 0x43, 
+    0x03, 0x42, 0x1F, 0xA8, 0x00, 0x02, 0x03, 0x43, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 
+    0x00, 0x1E, 0x00, 0x24, 0x1F, 0xDD, 0x00, 0x02, 0x03, 0x00, 0x1F, 0xDE, 0x00, 0x02, 0x03, 0x01, 
+    0x1F, 0xDD, 0x00, 0x02, 0x03, 0x40, 0x1F, 0xDE, 0x00, 0x02, 0x03, 0x41, 0x1F, 0xDF, 0x00, 0x02, 
+    0x03, 0x42, 0x00, 0x4A, 0x00, 0x96, 0x00, 0x9C, 0x00, 0xA2, 0x00, 0xAC, 0x00, 0xB4, 0x00, 0xBE, 
+    0x00, 0xC6, 0x00, 0xD0, 0x00, 0xD8, 0x00, 0xE2, 0x00, 0xEA, 0x00, 0xF4, 0x00, 0xFC, 0x01, 0x06, 
+    0x01, 0x10, 0x01, 0x1A, 0x01, 0x24, 0x01, 0x2E, 0x01, 0x36, 0x01, 0x3C, 0x01, 0x46, 0x01, 0x4E, 
+    0x01, 0x58, 0x01, 0x60, 0x01, 0x6A, 0x01, 0x72, 0x01, 0x7C, 0x01, 0x84, 0x01, 0x8E, 0x01, 0x96, 
+    0x01, 0xA0, 0x01, 0xAA, 0x01, 0xB4, 0x01, 0xBE, 0x01, 0xC8, 0x01, 0xD0, 0x01, 0xD6, 0x01, 0xDC, 
+    0x01, 0xE2, 0x01, 0xEC, 0x01, 0xF4, 0x01, 0xFE, 0x02, 0x06, 0x02, 0x10, 0x02, 0x18, 0x02, 0x22, 
+    0x02, 0x2A, 0x02, 0x34, 0x02, 0x3C, 0x02, 0x46, 0x02, 0x50, 0x02, 0x5A, 0x02, 0x64, 0x02, 0x6E, 
+    0x02, 0x76, 0x02, 0x7C, 0x02, 0x86, 0x02, 0x90, 0x02, 0x9A, 0x02, 0xA4, 0x02, 0xAE, 0x02, 0xB6, 
+    0x02, 0xC0, 0x02, 0xCA, 0x02, 0xD4, 0x02, 0xDE, 0x02, 0xE8, 0x02, 0xF0, 0x02, 0xFA, 0x03, 0x04, 
+    0x03, 0x0E, 0x03, 0x18, 0x03, 0x22, 0x03, 0x2A, 0x1F, 0xFA, 0x00, 0x02, 0x03, 0x00, 0x03, 0x8F, 
+    0x00, 0x02, 0x03, 0x01, 0x1F, 0xAA, 0x00, 0x04, 0x03, 0x13, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x6A, 
+    0x00, 0x03, 0x03, 0x13, 0x03, 0x00, 0x1F, 0xAC, 0x00, 0x04, 0x03, 0x13, 0x03, 0x01, 0x03, 0x45, 
+    0x1F, 0x6C, 0x00, 0x03, 0x03, 0x13, 0x03, 0x01, 0x1F, 0xAA, 0x00, 0x04, 0x03, 0x13, 0x03, 0x40, 
+    0x03, 0x45, 0x1F, 0x6A, 0x00, 0x03, 0x03, 0x13, 0x03, 0x40, 0x1F, 0xAC, 0x00, 0x04, 0x03, 0x13, 
+    0x03, 0x41, 0x03, 0x45, 0x1F, 0x6C, 0x00, 0x03, 0x03, 0x13, 0x03, 0x41, 0x1F, 0xAE, 0x00, 0x04, 
+    0x03, 0x13, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x6E, 0x00, 0x03, 0x03, 0x13, 0x03, 0x42, 0x1F, 0xAA, 
+    0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x00, 0x1F, 0xAC, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 
+    0x03, 0x01, 0x1F, 0xAA, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x40, 0x1F, 0xAC, 0x00, 0x04, 
+    0x03, 0x13, 0x03, 0x45, 0x03, 0x41, 0x1F, 0xAE, 0x00, 0x04, 0x03, 0x13, 0x03, 0x45, 0x03, 0x42, 
+    0x1F, 0xA8, 0x00, 0x03, 0x03, 0x13, 0x03, 0x45, 0x1F, 0x68, 0x00, 0x02, 0x03, 0x13, 0x1F, 0xAB, 
+    0x00, 0x04, 0x03, 0x14, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x6B, 0x00, 0x03, 0x03, 0x14, 0x03, 0x00, 
+    0x1F, 0xAD, 0x00, 0x04, 0x03, 0x14, 0x03, 0x01, 0x03, 0x45, 0x1F, 0x6D, 0x00, 0x03, 0x03, 0x14, 
+    0x03, 0x01, 0x1F, 0xAB, 0x00, 0x04, 0x03, 0x14, 0x03, 0x40, 0x03, 0x45, 0x1F, 0x6B, 0x00, 0x03, 
+    0x03, 0x14, 0x03, 0x40, 0x1F, 0xAD, 0x00, 0x04, 0x03, 0x14, 0x03, 0x41, 0x03, 0x45, 0x1F, 0x6D, 
+    0x00, 0x03, 0x03, 0x14, 0x03, 0x41, 0x1F, 0xAF, 0x00, 0x04, 0x03, 0x14, 0x03, 0x42, 0x03, 0x45, 
+    0x1F, 0x6F, 0x00, 0x03, 0x03, 0x14, 0x03, 0x42, 0x1F, 0xAB, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 
+    0x03, 0x00, 0x1F, 0xAD, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x01, 0x1F, 0xAB, 0x00, 0x04, 
+    0x03, 0x14, 0x03, 0x45, 0x03, 0x40, 0x1F, 0xAD, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x41, 
+    0x1F, 0xAF, 0x00, 0x04, 0x03, 0x14, 0x03, 0x45, 0x03, 0x42, 0x1F, 0xA9, 0x00, 0x03, 0x03, 0x14, 
+    0x03, 0x45, 0x1F, 0x69, 0x00, 0x02, 0x03, 0x14, 0x1F, 0xFA, 0x00, 0x02, 0x03, 0x40, 0x03, 0x8F, 
+    0x00, 0x02, 0x03, 0x41, 0x1F, 0xAA, 0x00, 0x04, 0x03, 0x43, 0x03, 0x00, 0x03, 0x45, 0x1F, 0x6A, 
+    0x00, 0x03, 0x03, 0x43, 0x03, 0x00, 0x1F, 0xAC, 0x00, 0x04, 0x03, 0x43, 0x03, 0x01, 0x03, 0x45, 
+    0x1F, 0x6C, 0x00, 0x03, 0x03, 0x43, 0x03, 0x01, 0x1F, 0xAA, 0x00, 0x04, 0x03, 0x43, 0x03, 0x40, 
+    0x03, 0x45, 0x1F, 0x6A, 0x00, 0x03, 0x03, 0x43, 0x03, 0x40, 0x1F, 0xAC, 0x00, 0x04, 0x03, 0x43, 
+    0x03, 0x41, 0x03, 0x45, 0x1F, 0x6C, 0x00, 0x03, 0x03, 0x43, 0x03, 0x41, 0x1F, 0xAE, 0x00, 0x04, 
+    0x03, 0x43, 0x03, 0x42, 0x03, 0x45, 0x1F, 0x6E, 0x00, 0x03, 0x03, 0x43, 0x03, 0x42, 0x1F, 0xAA, 
+    0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x00, 0x1F, 0xAC, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 
+    0x03, 0x01, 0x1F, 0xAA, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x40, 0x1F, 0xAC, 0x00, 0x04, 
+    0x03, 0x43, 0x03, 0x45, 0x03, 0x41, 0x1F, 0xAE, 0x00, 0x04, 0x03, 0x43, 0x03, 0x45, 0x03, 0x42, 
+    0x1F, 0xA8, 0x00, 0x03, 0x03, 0x43, 0x03, 0x45, 0x1F, 0x68, 0x00, 0x02, 0x03, 0x43, 0x1F, 0xAA, 
+    0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x00, 0x1F, 0xAC, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 
+    0x03, 0x01, 0x1F, 0xAA, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x40, 0x1F, 0xAC, 0x00, 0x04, 
+    0x03, 0x45, 0x03, 0x13, 0x03, 0x41, 0x1F, 0xAE, 0x00, 0x04, 0x03, 0x45, 0x03, 0x13, 0x03, 0x42, 
+    0x1F, 0xA8, 0x00, 0x03, 0x03, 0x45, 0x03, 0x13, 0x1F, 0xAB, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 
+    0x03, 0x00, 0x1F, 0xAD, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x01, 0x1F, 0xAB, 0x00, 0x04, 
+    0x03, 0x45, 0x03, 0x14, 0x03, 0x40, 0x1F, 0xAD, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x41, 
+    0x1F, 0xAF, 0x00, 0x04, 0x03, 0x45, 0x03, 0x14, 0x03, 0x42, 0x1F, 0xA9, 0x00, 0x03, 0x03, 0x45, 
+    0x03, 0x14, 0x1F, 0xAA, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x00, 0x1F, 0xAC, 0x00, 0x04, 
+    0x03, 0x45, 0x03, 0x43, 0x03, 0x01, 0x1F, 0xAA, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x40, 
+    0x1F, 0xAC, 0x00, 0x04, 0x03, 0x45, 0x03, 0x43, 0x03, 0x41, 0x1F, 0xAE, 0x00, 0x04, 0x03, 0x45, 
+    0x03, 0x43, 0x03, 0x42, 0x1F, 0xA8, 0x00, 0x03, 0x03, 0x45, 0x03, 0x43, 0x1F, 0xFC, 0x00, 0x02, 
+    0x03, 0x45, 0x00, 0x01, 0x00, 0x75, 0x00, 0xA8, 0x03, 0x91, 0x03, 0x95, 0x03, 0x97, 0x03, 0x99, 
+    0x03, 0x9F, 0x03, 0xA1, 0x03, 0xA5, 0x03, 0xA9, 0x03, 0xAC, 0x03, 0xAE, 0x03, 0xB1, 0x03, 0xB5, 
+    0x03, 0xB7, 0x03, 0xB9, 0x03, 0xBF, 0x03, 0xC1, 0x03, 0xC5, 0x03, 0xC9, 0x03, 0xCA, 0x03, 0xCB, 
+    0x03, 0xCE, 0x03, 0xD2, 0x1F, 0x00, 0x1F, 0x01, 0x1F, 0x02, 0x1F, 0x03, 0x1F, 0x04, 0x1F, 0x05, 
+    0x1F, 0x06, 0x1F, 0x07, 0x1F, 0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F, 0x0C, 0x1F, 0x0D, 
+    0x1F, 0x0E, 0x1F, 0x0F, 0x1F, 0x10, 0x1F, 0x11, 0x1F, 0x18, 0x1F, 0x19, 0x1F, 0x20, 0x1F, 0x21, 
+    0x1F, 0x22, 0x1F, 0x23, 0x1F, 0x24, 0x1F, 0x25, 0x1F, 0x26, 0x1F, 0x27, 0x1F, 0x28, 0x1F, 0x29, 
+    0x1F, 0x2A, 0x1F, 0x2B, 0x1F, 0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F, 0x30, 0x1F, 0x31, 
+    0x1F, 0x38, 0x1F, 0x39, 0x1F, 0x40, 0x1F, 0x41, 0x1F, 0x48, 0x1F, 0x49, 0x1F, 0x50, 0x1F, 0x51, 
+    0x1F, 0x59, 0x1F, 0x60, 0x1F, 0x61, 0x1F, 0x62, 0x1F, 0x63, 0x1F, 0x64, 0x1F, 0x65, 0x1F, 0x66, 
+    0x1F, 0x67, 0x1F, 0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F, 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 
+    0x1F, 0x6F, 0x1F, 0x70, 0x1F, 0x71, 0x1F, 0x74, 0x1F, 0x75, 0x1F, 0x7C, 0x1F, 0x7D, 0x1F, 0x80, 
+    0x1F, 0x81, 0x1F, 0x88, 0x1F, 0x89, 0x1F, 0x90, 0x1F, 0x91, 0x1F, 0x98, 0x1F, 0x99, 0x1F, 0xA0, 
+    0x1F, 0xA1, 0x1F, 0xA8, 0x1F, 0xA9, 0x1F, 0xB3, 0x1F, 0xB6, 0x1F, 0xBC, 0x1F, 0xBE, 0x1F, 0xBF, 
+    0x1F, 0xC3, 0x1F, 0xC6, 0x1F, 0xCC, 0x1F, 0xF3, 0x1F, 0xF6, 0x1F, 0xFC, 0x1F, 0xFE, 0x21, 0x26, 
+    0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x4C, 0x09, 0x66, 0x11, 0x1A, 0x17, 0x08, 0x1C, 0xC2, 
+    0x20, 0xBC, 0x24, 0x9E, 0x27, 0x3C, 0x29, 0x7A, 0x2B, 0x42, 0x2D, 0x22, 0x2E, 0xD2, 0x30, 0x80, 
+    0x31, 0xE8, 0x33, 0x50, 0x34, 0xB8, 0x35, 0x94, 0x36, 0x70, 0x37, 0x4C, 0x38, 0x1A, 0x38, 0xE8, 
+    0x39, 0xB6, 0x3A, 0x68, 0x3B, 0x1A, 0x3B, 0x40, 0x3B, 0x66, 0x3B, 0x8C, 0x3B, 0xB2, 0x3B, 0xD8, 
+    0x3B, 0xFE, 0x3C, 0x24, 0x3C, 0x4A, 0x3C, 0x70, 0x3C, 0x96, 0x3C, 0xBC, 0x00, 0x01, 0x07, 0x46, 
+    0x00, 0xE8, 0x01, 0xD6, 0x01, 0xDC, 0x01, 0xE2, 0x01, 0xE8, 0x01, 0xEE, 0x01, 0xF4, 0x01, 0xFA, 
+    0x02, 0x00, 0x02, 0x06, 0x02, 0x0C, 0x02, 0x12, 0x02, 0x18, 0x02, 0x1E, 0x02, 0x24, 0x02, 0x2A, 
+    0x02, 0x30, 0x02, 0x36, 0x02, 0x3C, 0x02, 0x42, 0x02, 0x48, 0x02, 0x4E, 0x02, 0x54, 0x02, 0x5A, 
+    0x02, 0x60, 0x02, 0x66, 0x02, 0x6C, 0x02, 0x72, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02, 0x8A, 
+    0x02, 0x90, 0x02, 0x96, 0x02, 0x9C, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02, 0xB4, 0x02, 0xBA, 
+    0x02, 0xC0, 0x02, 0xC6, 0x02, 0xCC, 0x02, 0xD2, 0x02, 0xD8, 0x02, 0xDE, 0x02, 0xE4, 0x02, 0xEA, 
+    0x02, 0xF0, 0x02, 0xF6, 0x02, 0xFC, 0x03, 0x02, 0x03, 0x08, 0x03, 0x0E, 0x03, 0x14, 0x03, 0x1A, 
+    0x03, 0x20, 0x03, 0x26, 0x03, 0x2C, 0x03, 0x32, 0x03, 0x38, 0x03, 0x3E, 0x03, 0x44, 0x03, 0x4A, 
+    0x03, 0x50, 0x03, 0x56, 0x03, 0x5C, 0x03, 0x62, 0x03, 0x68, 0x03, 0x6E, 0x03, 0x74, 0x03, 0x7A, 
+    0x03, 0x80, 0x03, 0x86, 0x03, 0x8C, 0x03, 0x92, 0x03, 0x98, 0x03, 0x9E, 0x03, 0xA4, 0x03, 0xAA, 
+    0x03, 0xB0, 0x03, 0xB6, 0x03, 0xBC, 0x03, 0xC2, 0x03, 0xC8, 0x03, 0xCE, 0x03, 0xD4, 0x03, 0xDA, 
+    0x03, 0xE0, 0x03, 0xE6, 0x03, 0xEC, 0x03, 0xF2, 0x03, 0xF8, 0x03, 0xFE, 0x04, 0x04, 0x04, 0x0A, 
+    0x04, 0x10, 0x04, 0x16, 0x04, 0x1C, 0x04, 0x22, 0x04, 0x28, 0x04, 0x2E, 0x04, 0x34, 0x04, 0x3A, 
+    0x04, 0x40, 0x04, 0x46, 0x04, 0x4C, 0x04, 0x52, 0x04, 0x58, 0x04, 0x5E, 0x04, 0x64, 0x04, 0x6A, 
+    0x04, 0x70, 0x04, 0x76, 0x04, 0x7C, 0x04, 0x82, 0x04, 0x88, 0x04, 0x8E, 0x04, 0x94, 0x04, 0x9A, 
+    0x04, 0xA0, 0x04, 0xA6, 0x04, 0xAC, 0x04, 0xB2, 0x04, 0xB8, 0x04, 0xBE, 0x04, 0xC4, 0x04, 0xCA, 
+    0x04, 0xD0, 0x04, 0xD6, 0x04, 0xDC, 0x04, 0xE2, 0x04, 0xE8, 0x04, 0xEE, 0x04, 0xF4, 0x04, 0xFA, 
+    0x05, 0x00, 0x05, 0x06, 0x05, 0x0C, 0x05, 0x12, 0x05, 0x18, 0x05, 0x1E, 0x05, 0x24, 0x05, 0x2A, 
+    0x05, 0x30, 0x05, 0x36, 0x05, 0x3C, 0x05, 0x42, 0x05, 0x48, 0x05, 0x4E, 0x05, 0x54, 0x05, 0x5A, 
+    0x05, 0x60, 0x05, 0x66, 0x05, 0x6C, 0x05, 0x72, 0x05, 0x78, 0x05, 0x7E, 0x05, 0x84, 0x05, 0x8A, 
+    0x05, 0x90, 0x05, 0x96, 0x05, 0x9C, 0x05, 0xA2, 0x05, 0xA8, 0x05, 0xAE, 0x05, 0xB4, 0x05, 0xBA, 
+    0x05, 0xC0, 0x05, 0xC6, 0x05, 0xCC, 0x05, 0xD2, 0x05, 0xD8, 0x05, 0xDE, 0x05, 0xE4, 0x05, 0xEA, 
+    0x05, 0xF0, 0x05, 0xF6, 0x05, 0xFC, 0x06, 0x02, 0x06, 0x08, 0x06, 0x0E, 0x06, 0x14, 0x06, 0x1A, 
+    0x06, 0x20, 0x06, 0x26, 0x06, 0x2C, 0x06, 0x32, 0x06, 0x38, 0x06, 0x3E, 0x06, 0x44, 0x06, 0x4A, 
+    0x06, 0x50, 0x06, 0x56, 0x06, 0x5C, 0x06, 0x62, 0x06, 0x68, 0x06, 0x6E, 0x06, 0x74, 0x06, 0x7A, 
+    0x06, 0x80, 0x06, 0x86, 0x06, 0x8C, 0x06, 0x92, 0x06, 0x98, 0x06, 0x9E, 0x06, 0xA4, 0x06, 0xAA, 
+    0x06, 0xB0, 0x06, 0xB6, 0x06, 0xBC, 0x06, 0xC2, 0x06, 0xC8, 0x06, 0xCE, 0x06, 0xD4, 0x06, 0xDA, 
+    0x06, 0xE0, 0x06, 0xE6, 0x06, 0xEC, 0x06, 0xF2, 0x06, 0xF8, 0x06, 0xFE, 0x07, 0x04, 0x07, 0x0A, 
+    0x07, 0x10, 0x07, 0x16, 0x07, 0x1C, 0x07, 0x22, 0x07, 0x28, 0x07, 0x2E, 0x07, 0x34, 0x07, 0x3A, 
+    0x07, 0x40, 0x00, 0x02, 0x00, 0xA8, 0x03, 0x01, 0x00, 0x02, 0x03, 0x91, 0x03, 0x01, 0x00, 0x02, 
+    0x03, 0x95, 0x03, 0x01, 0x00, 0x02, 0x03, 0x97, 0x03, 0x01, 0x00, 0x02, 0x03, 0x99, 0x03, 0x01, 
+    0x00, 0x02, 0x03, 0x9F, 0x03, 0x01, 0x00, 0x02, 0x03, 0xA5, 0x03, 0x01, 0x00, 0x02, 0x03, 0xA9, 
+    0x03, 0x01, 0x00, 0x02, 0x03, 0xB9, 0x03, 0x44, 0x00, 0x02, 0x03, 0x99, 0x03, 0x08, 0x00, 0x02, 
+    0x03, 0xA5, 0x03, 0x08, 0x00, 0x02, 0x03, 0xB1, 0x03, 0x01, 0x00, 0x02, 0x03, 0xB5, 0x03, 0x01, 
+    0x00, 0x02, 0x03, 0xB7, 0x03, 0x01, 0x00, 0x02, 0x03, 0xB9, 0x03, 0x01, 0x00, 0x02, 0x03, 0xC5, 
+    0x03, 0x44, 0x00, 0x02, 0x03, 0xB9, 0x03, 0x08, 0x00, 0x02, 0x03, 0xC5, 0x03, 0x08, 0x00, 0x02, 
+    0x03, 0xBF, 0x03, 0x01, 0x00, 0x02, 0x03, 0xC5, 0x03, 0x01, 0x00, 0x02, 0x03, 0xC9, 0x03, 0x01, 
+    0x00, 0x02, 0x03, 0xD2, 0x03, 0x01, 0x00, 0x02, 0x03, 0xD2, 0x03, 0x08, 0x00, 0x02, 0x03, 0xB1, 
+    0x03, 0x13, 0x00, 0x02, 0x03, 0xB1, 0x03, 0x14, 0x00, 0x02, 0x1F, 0x00, 0x03, 0x00, 0x00, 0x02, 
+    0x1F, 0x01, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x00, 0x03, 0x01, 0x00, 0x02, 0x1F, 0x01, 0x03, 0x01, 
+    0x00, 0x02, 0x1F, 0x00, 0x03, 0x42, 0x00, 0x02, 0x1F, 0x01, 0x03, 0x42, 0x00, 0x02, 0x03, 0x91, 
+    0x03, 0x13, 0x00, 0x02, 0x03, 0x91, 0x03, 0x14, 0x00, 0x02, 0x1F, 0x08, 0x03, 0x00, 0x00, 0x02, 
+    0x1F, 0x09, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x08, 0x03, 0x01, 0x00, 0x02, 0x1F, 0x09, 0x03, 0x01, 
+    0x00, 0x02, 0x1F, 0x08, 0x03, 0x42, 0x00, 0x02, 0x1F, 0x09, 0x03, 0x42, 0x00, 0x02, 0x03, 0xB5, 
+    0x03, 0x13, 0x00, 0x02, 0x03, 0xB5, 0x03, 0x14, 0x00, 0x02, 0x1F, 0x10, 0x03, 0x00, 0x00, 0x02, 
+    0x1F, 0x11, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x10, 0x03, 0x01, 0x00, 0x02, 0x1F, 0x11, 0x03, 0x01, 
+    0x00, 0x02, 0x03, 0x95, 0x03, 0x13, 0x00, 0x02, 0x03, 0x95, 0x03, 0x14, 0x00, 0x02, 0x1F, 0x18, 
+    0x03, 0x00, 0x00, 0x02, 0x1F, 0x19, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x18, 0x03, 0x01, 0x00, 0x02, 
+    0x1F, 0x19, 0x03, 0x01, 0x00, 0x02, 0x03, 0xB7, 0x03, 0x13, 0x00, 0x02, 0x03, 0xB7, 0x03, 0x14, 
+    0x00, 0x02, 0x1F, 0x20, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x21, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x20, 
+    0x03, 0x01, 0x00, 0x02, 0x1F, 0x21, 0x03, 0x01, 0x00, 0x02, 0x1F, 0x20, 0x03, 0x42, 0x00, 0x02, 
+    0x1F, 0x21, 0x03, 0x42, 0x00, 0x02, 0x03, 0x97, 0x03, 0x13, 0x00, 0x02, 0x03, 0x97, 0x03, 0x14, 
+    0x00, 0x02, 0x1F, 0x28, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x29, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x28, 
+    0x03, 0x01, 0x00, 0x02, 0x1F, 0x29, 0x03, 0x01, 0x00, 0x02, 0x1F, 0x28, 0x03, 0x42, 0x00, 0x02, 
+    0x1F, 0x29, 0x03, 0x42, 0x00, 0x02, 0x03, 0xB9, 0x03, 0x13, 0x00, 0x02, 0x03, 0xB9, 0x03, 0x14, 
+    0x00, 0x02, 0x1F, 0x30, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x31, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x30, 
+    0x03, 0x01, 0x00, 0x02, 0x1F, 0x31, 0x03, 0x01, 0x00, 0x02, 0x1F, 0x30, 0x03, 0x42, 0x00, 0x02, 
+    0x1F, 0x31, 0x03, 0x42, 0x00, 0x02, 0x03, 0x99, 0x03, 0x13, 0x00, 0x02, 0x03, 0x99, 0x03, 0x14, 
+    0x00, 0x02, 0x1F, 0x38, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x39, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x38, 
+    0x03, 0x01, 0x00, 0x02, 0x1F, 0x39, 0x03, 0x01, 0x00, 0x02, 0x1F, 0x38, 0x03, 0x42, 0x00, 0x02, 
+    0x1F, 0x39, 0x03, 0x42, 0x00, 0x02, 0x03, 0xBF, 0x03, 0x13, 0x00, 0x02, 0x03, 0xBF, 0x03, 0x14, 
+    0x00, 0x02, 0x1F, 0x40, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x41, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x40, 
+    0x03, 0x01, 0x00, 0x02, 0x1F, 0x41, 0x03, 0x01, 0x00, 0x02, 0x03, 0x9F, 0x03, 0x13, 0x00, 0x02, 
+    0x03, 0x9F, 0x03, 0x14, 0x00, 0x02, 0x1F, 0x48, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x49, 0x03, 0x00, 
+    0x00, 0x02, 0x1F, 0x48, 0x03, 0x01, 0x00, 0x02, 0x1F, 0x49, 0x03, 0x01, 0x00, 0x02, 0x03, 0xC5, 
+    0x03, 0x13, 0x00, 0x02, 0x03, 0xC5, 0x03, 0x14, 0x00, 0x02, 0x1F, 0x50, 0x03, 0x00, 0x00, 0x02, 
+    0x1F, 0x51, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x50, 0x03, 0x01, 0x00, 0x02, 0x1F, 0x51, 0x03, 0x01, 
+    0x00, 0x02, 0x1F, 0x50, 0x03, 0x42, 0x00, 0x02, 0x1F, 0x51, 0x03, 0x42, 0x00, 0x02, 0x03, 0xA5, 
+    0x03, 0x14, 0x00, 0x02, 0x1F, 0x59, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x59, 0x03, 0x01, 0x00, 0x02, 
+    0x1F, 0x59, 0x03, 0x42, 0x00, 0x02, 0x03, 0xC9, 0x03, 0x13, 0x00, 0x02, 0x03, 0xC9, 0x03, 0x14, 
+    0x00, 0x02, 0x1F, 0x60, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x61, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x60, 
+    0x03, 0x01, 0x00, 0x02, 0x1F, 0x61, 0x03, 0x01, 0x00, 0x02, 0x1F, 0x60, 0x03, 0x42, 0x00, 0x02, 
+    0x1F, 0x61, 0x03, 0x42, 0x00, 0x02, 0x03, 0xA9, 0x03, 0x13, 0x00, 0x02, 0x03, 0xA9, 0x03, 0x14, 
+    0x00, 0x02, 0x1F, 0x68, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x69, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x68, 
+    0x03, 0x01, 0x00, 0x02, 0x1F, 0x69, 0x03, 0x01, 0x00, 0x02, 0x1F, 0x68, 0x03, 0x42, 0x00, 0x02, 
+    0x1F, 0x69, 0x03, 0x42, 0x00, 0x02, 0x03, 0xB1, 0x03, 0x00, 0x00, 0x02, 0x03, 0xB5, 0x03, 0x00, 
+    0x00, 0x02, 0x03, 0xB7, 0x03, 0x00, 0x00, 0x02, 0x03, 0xB9, 0x03, 0x00, 0x00, 0x02, 0x03, 0xBF, 
+    0x03, 0x00, 0x00, 0x02, 0x03, 0xC5, 0x03, 0x00, 0x00, 0x02, 0x03, 0xC9, 0x03, 0x00, 0x00, 0x02, 
+    0x1F, 0x00, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x01, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x02, 0x03, 0x45, 
+    0x00, 0x02, 0x1F, 0x03, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x04, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x05, 
+    0x03, 0x45, 0x00, 0x02, 0x1F, 0x06, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x07, 0x03, 0x45, 0x00, 0x02, 
+    0x1F, 0x08, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x09, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x0A, 0x03, 0x45, 
+    0x00, 0x02, 0x1F, 0x0B, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x0C, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x0D, 
+    0x03, 0x45, 0x00, 0x02, 0x1F, 0x0E, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x0F, 0x03, 0x45, 0x00, 0x02, 
+    0x1F, 0x20, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x21, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x22, 0x03, 0x45, 
+    0x00, 0x02, 0x1F, 0x23, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x24, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x25, 
+    0x03, 0x45, 0x00, 0x02, 0x1F, 0x26, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x27, 0x03, 0x45, 0x00, 0x02, 
+    0x1F, 0x28, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x29, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x2A, 0x03, 0x45, 
+    0x00, 0x02, 0x1F, 0x2B, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x2C, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x2D, 
+    0x03, 0x45, 0x00, 0x02, 0x1F, 0x2E, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x2F, 0x03, 0x45, 0x00, 0x02, 
+    0x1F, 0x60, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x61, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x62, 0x03, 0x45, 
+    0x00, 0x02, 0x1F, 0x63, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x64, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x65, 
+    0x03, 0x45, 0x00, 0x02, 0x1F, 0x66, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x67, 0x03, 0x45, 0x00, 0x02, 
+    0x1F, 0x68, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x69, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x6A, 0x03, 0x45, 
+    0x00, 0x02, 0x1F, 0x6B, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x6C, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x6D, 
+    0x03, 0x45, 0x00, 0x02, 0x1F, 0x6E, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x6F, 0x03, 0x45, 0x00, 0x02, 
+    0x03, 0xB1, 0x03, 0x06, 0x00, 0x02, 0x03, 0xB1, 0x03, 0x04, 0x00, 0x02, 0x1F, 0x70, 0x03, 0x45, 
+    0x00, 0x02, 0x03, 0xB1, 0x03, 0x45, 0x00, 0x02, 0x03, 0xAC, 0x03, 0x45, 0x00, 0x02, 0x03, 0xB1, 
+    0x03, 0x42, 0x00, 0x02, 0x1F, 0xB3, 0x03, 0x42, 0x00, 0x02, 0x03, 0x91, 0x03, 0x06, 0x00, 0x02, 
+    0x03, 0x91, 0x03, 0x04, 0x00, 0x02, 0x03, 0x91, 0x03, 0x00, 0x00, 0x02, 0x03, 0x91, 0x03, 0x45, 
+    0x00, 0x02, 0x00, 0xA8, 0x03, 0x42, 0x00, 0x02, 0x1F, 0x74, 0x03, 0x45, 0x00, 0x02, 0x03, 0xB7, 
+    0x03, 0x45, 0x00, 0x02, 0x03, 0xAE, 0x03, 0x45, 0x00, 0x02, 0x03, 0xB7, 0x03, 0x42, 0x00, 0x02, 
+    0x1F, 0xC3, 0x03, 0x42, 0x00, 0x02, 0x03, 0x95, 0x03, 0x00, 0x00, 0x02, 0x03, 0x97, 0x03, 0x00, 
+    0x00, 0x02, 0x03, 0x97, 0x03, 0x45, 0x00, 0x02, 0x1F, 0xBF, 0x03, 0x00, 0x00, 0x02, 0x1F, 0xBF, 
+    0x03, 0x01, 0x00, 0x02, 0x1F, 0xBF, 0x03, 0x42, 0x00, 0x02, 0x03, 0xB9, 0x03, 0x06, 0x00, 0x02, 
+    0x03, 0xB9, 0x03, 0x04, 0x00, 0x02, 0x03, 0xCA, 0x03, 0x00, 0x00, 0x02, 0x03, 0xB9, 0x03, 0x42, 
+    0x00, 0x02, 0x03, 0xCA, 0x03, 0x42, 0x00, 0x02, 0x03, 0x99, 0x03, 0x06, 0x00, 0x02, 0x03, 0x99, 
+    0x03, 0x04, 0x00, 0x02, 0x03, 0x99, 0x03, 0x00, 0x00, 0x02, 0x1F, 0xFE, 0x03, 0x00, 0x00, 0x02, 
+    0x1F, 0xFE, 0x03, 0x01, 0x00, 0x02, 0x1F, 0xFE, 0x03, 0x42, 0x00, 0x02, 0x03, 0xC5, 0x03, 0x06, 
+    0x00, 0x02, 0x03, 0xC5, 0x03, 0x04, 0x00, 0x02, 0x03, 0xCB, 0x03, 0x00, 0x00, 0x02, 0x03, 0xC1, 
+    0x03, 0x13, 0x00, 0x02, 0x03, 0xC1, 0x03, 0x14, 0x00, 0x02, 0x03, 0xC5, 0x03, 0x42, 0x00, 0x02, 
+    0x03, 0xCB, 0x03, 0x42, 0x00, 0x02, 0x03, 0xA5, 0x03, 0x06, 0x00, 0x02, 0x03, 0xA5, 0x03, 0x04, 
+    0x00, 0x02, 0x03, 0xA5, 0x03, 0x00, 0x00, 0x02, 0x03, 0xA1, 0x03, 0x14, 0x00, 0x02, 0x00, 0xA8, 
+    0x03, 0x00, 0x00, 0x02, 0x1F, 0x7C, 0x03, 0x45, 0x00, 0x02, 0x03, 0xC9, 0x03, 0x45, 0x00, 0x02, 
+    0x03, 0xCE, 0x03, 0x45, 0x00, 0x02, 0x03, 0xC9, 0x03, 0x42, 0x00, 0x02, 0x1F, 0xF3, 0x03, 0x42, 
+    0x00, 0x02, 0x03, 0x9F, 0x03, 0x00, 0x00, 0x02, 0x03, 0xA9, 0x03, 0x00, 0x00, 0x02, 0x03, 0xA9, 
+    0x03, 0x45, 0x00, 0x01, 0x00, 0xE8, 0x03, 0x85, 0x03, 0x86, 0x03, 0x88, 0x03, 0x89, 0x03, 0x8A, 
+    0x03, 0x8C, 0x03, 0x8E, 0x03, 0x8F, 0x03, 0x90, 0x03, 0xAA, 0x03, 0xAB, 0x03, 0xAC, 0x03, 0xAD, 
+    0x03, 0xAE, 0x03, 0xAF, 0x03, 0xB0, 0x03, 0xCA, 0x03, 0xCB, 0x03, 0xCC, 0x03, 0xCD, 0x03, 0xCE, 
+    0x03, 0xD3, 0x03, 0xD4, 0x1F, 0x00, 0x1F, 0x01, 0x1F, 0x02, 0x1F, 0x03, 0x1F, 0x04, 0x1F, 0x05, 
+    0x1F, 0x06, 0x1F, 0x07, 0x1F, 0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F, 0x0C, 0x1F, 0x0D, 
+    0x1F, 0x0E, 0x1F, 0x0F, 0x1F, 0x10, 0x1F, 0x11, 0x1F, 0x12, 0x1F, 0x13, 0x1F, 0x14, 0x1F, 0x15, 
+    0x1F, 0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F, 0x1C, 0x1F, 0x1D, 0x1F, 0x20, 0x1F, 0x21, 
+    0x1F, 0x22, 0x1F, 0x23, 0x1F, 0x24, 0x1F, 0x25, 0x1F, 0x26, 0x1F, 0x27, 0x1F, 0x28, 0x1F, 0x29, 
+    0x1F, 0x2A, 0x1F, 0x2B, 0x1F, 0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F, 0x30, 0x1F, 0x31, 
+    0x1F, 0x32, 0x1F, 0x33, 0x1F, 0x34, 0x1F, 0x35, 0x1F, 0x36, 0x1F, 0x37, 0x1F, 0x38, 0x1F, 0x39, 
+    0x1F, 0x3A, 0x1F, 0x3B, 0x1F, 0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F, 0x40, 0x1F, 0x41, 
+    0x1F, 0x42, 0x1F, 0x43, 0x1F, 0x44, 0x1F, 0x45, 0x1F, 0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 
+    0x1F, 0x4C, 0x1F, 0x4D, 0x1F, 0x50, 0x1F, 0x51, 0x1F, 0x52, 0x1F, 0x53, 0x1F, 0x54, 0x1F, 0x55, 
+    0x1F, 0x56, 0x1F, 0x57, 0x1F, 0x59, 0x1F, 0x5B, 0x1F, 0x5D, 0x1F, 0x5F, 0x1F, 0x60, 0x1F, 0x61, 
+    0x1F, 0x62, 0x1F, 0x63, 0x1F, 0x64, 0x1F, 0x65, 0x1F, 0x66, 0x1F, 0x67, 0x1F, 0x68, 0x1F, 0x69, 
+    0x1F, 0x6A, 0x1F, 0x6B, 0x1F, 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F, 0x70, 0x1F, 0x72, 
+    0x1F, 0x74, 0x1F, 0x76, 0x1F, 0x78, 0x1F, 0x7A, 0x1F, 0x7C, 0x1F, 0x80, 0x1F, 0x81, 0x1F, 0x82, 
+    0x1F, 0x83, 0x1F, 0x84, 0x1F, 0x85, 0x1F, 0x86, 0x1F, 0x87, 0x1F, 0x88, 0x1F, 0x89, 0x1F, 0x8A, 
+    0x1F, 0x8B, 0x1F, 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, 0x90, 0x1F, 0x91, 0x1F, 0x92, 
+    0x1F, 0x93, 0x1F, 0x94, 0x1F, 0x95, 0x1F, 0x96, 0x1F, 0x97, 0x1F, 0x98, 0x1F, 0x99, 0x1F, 0x9A, 
+    0x1F, 0x9B, 0x1F, 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, 0xA0, 0x1F, 0xA1, 0x1F, 0xA2, 
+    0x1F, 0xA3, 0x1F, 0xA4, 0x1F, 0xA5, 0x1F, 0xA6, 0x1F, 0xA7, 0x1F, 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 
+    0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, 0xB0, 0x1F, 0xB1, 0x1F, 0xB2, 
+    0x1F, 0xB3, 0x1F, 0xB4, 0x1F, 0xB6, 0x1F, 0xB7, 0x1F, 0xB8, 0x1F, 0xB9, 0x1F, 0xBA, 0x1F, 0xBC, 
+    0x1F, 0xC1, 0x1F, 0xC2, 0x1F, 0xC3, 0x1F, 0xC4, 0x1F, 0xC6, 0x1F, 0xC7, 0x1F, 0xC8, 0x1F, 0xCA, 
+    0x1F, 0xCC, 0x1F, 0xCD, 0x1F, 0xCE, 0x1F, 0xCF, 0x1F, 0xD0, 0x1F, 0xD1, 0x1F, 0xD2, 0x1F, 0xD6, 
+    0x1F, 0xD7, 0x1F, 0xD8, 0x1F, 0xD9, 0x1F, 0xDA, 0x1F, 0xDD, 0x1F, 0xDE, 0x1F, 0xDF, 0x1F, 0xE0, 
+    0x1F, 0xE1, 0x1F, 0xE2, 0x1F, 0xE4, 0x1F, 0xE5, 0x1F, 0xE6, 0x1F, 0xE7, 0x1F, 0xE8, 0x1F, 0xE9, 
+    0x1F, 0xEA, 0x1F, 0xEC, 0x1F, 0xED, 0x1F, 0xF2, 0x1F, 0xF3, 0x1F, 0xF4, 0x1F, 0xF6, 0x1F, 0xF7, 
+    0x1F, 0xF8, 0x1F, 0xFA, 0x1F, 0xFC, 0x00, 0x01, 0x06, 0x30, 0x00, 0xC0, 0x01, 0x86, 0x01, 0x8C, 
+    0x01, 0x92, 0x01, 0x98, 0x01, 0x9E, 0x01, 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB6, 0x01, 0xBC, 
+    0x01, 0xC2, 0x01, 0xC8, 0x01, 0xCE, 0x01, 0xD4, 0x01, 0xDA, 0x01, 0xE0, 0x01, 0xE6, 0x01, 0xEC, 
+    0x01, 0xF2, 0x01, 0xF8, 0x01, 0xFE, 0x02, 0x04, 0x02, 0x0A, 0x02, 0x10, 0x02, 0x16, 0x02, 0x1E, 
+    0x02, 0x26, 0x02, 0x2C, 0x02, 0x32, 0x02, 0x38, 0x02, 0x3E, 0x02, 0x44, 0x02, 0x4C, 0x02, 0x54, 
+    0x02, 0x5A, 0x02, 0x60, 0x02, 0x66, 0x02, 0x6C, 0x02, 0x72, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 
+    0x02, 0x8A, 0x02, 0x90, 0x02, 0x96, 0x02, 0x9C, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02, 0xB6, 
+    0x02, 0xBE, 0x02, 0xC4, 0x02, 0xCA, 0x02, 0xD0, 0x02, 0xD6, 0x02, 0xDC, 0x02, 0xE4, 0x02, 0xEC, 
+    0x02, 0xF2, 0x02, 0xF8, 0x02, 0xFE, 0x03, 0x04, 0x03, 0x0A, 0x03, 0x10, 0x03, 0x18, 0x03, 0x20, 
+    0x03, 0x26, 0x03, 0x2C, 0x03, 0x32, 0x03, 0x38, 0x03, 0x3E, 0x03, 0x46, 0x03, 0x4E, 0x03, 0x54, 
+    0x03, 0x5A, 0x03, 0x60, 0x03, 0x66, 0x03, 0x6C, 0x03, 0x72, 0x03, 0x78, 0x03, 0x7E, 0x03, 0x84, 
+    0x03, 0x8A, 0x03, 0x90, 0x03, 0x96, 0x03, 0x9C, 0x03, 0xA2, 0x03, 0xA8, 0x03, 0xB0, 0x03, 0xB8, 
+    0x03, 0xBE, 0x03, 0xC4, 0x03, 0xCC, 0x03, 0xD2, 0x03, 0xD8, 0x03, 0xDE, 0x03, 0xE4, 0x03, 0xEA, 
+    0x03, 0xF2, 0x03, 0xFA, 0x04, 0x00, 0x04, 0x06, 0x04, 0x0C, 0x04, 0x12, 0x04, 0x18, 0x04, 0x1E, 
+    0x04, 0x26, 0x04, 0x2E, 0x04, 0x34, 0x04, 0x3A, 0x04, 0x40, 0x04, 0x46, 0x04, 0x4C, 0x04, 0x52, 
+    0x04, 0x58, 0x04, 0x5E, 0x04, 0x64, 0x04, 0x6A, 0x04, 0x70, 0x04, 0x76, 0x04, 0x7C, 0x04, 0x82, 
+    0x04, 0x88, 0x04, 0x8E, 0x04, 0x94, 0x04, 0x9A, 0x04, 0xA0, 0x04, 0xA6, 0x04, 0xAC, 0x04, 0xB2, 
+    0x04, 0xB8, 0x04, 0xBE, 0x04, 0xC4, 0x04, 0xCA, 0x04, 0xD0, 0x04, 0xD6, 0x04, 0xDC, 0x04, 0xE2, 
+    0x04, 0xE8, 0x04, 0xEE, 0x04, 0xF4, 0x04, 0xFA, 0x05, 0x00, 0x05, 0x06, 0x05, 0x0C, 0x05, 0x12, 
+    0x05, 0x18, 0x05, 0x1E, 0x05, 0x24, 0x05, 0x2A, 0x05, 0x30, 0x05, 0x36, 0x05, 0x3C, 0x05, 0x42, 
+    0x05, 0x48, 0x05, 0x4E, 0x05, 0x54, 0x05, 0x5A, 0x05, 0x60, 0x05, 0x66, 0x05, 0x6C, 0x05, 0x72, 
+    0x05, 0x78, 0x05, 0x7E, 0x05, 0x84, 0x05, 0x8A, 0x05, 0x90, 0x05, 0x96, 0x05, 0x9C, 0x05, 0xA2, 
+    0x05, 0xA8, 0x05, 0xAE, 0x05, 0xB4, 0x05, 0xBA, 0x05, 0xC0, 0x05, 0xC6, 0x05, 0xCC, 0x05, 0xD2, 
+    0x05, 0xDA, 0x05, 0xE0, 0x05, 0xE6, 0x05, 0xEC, 0x05, 0xF2, 0x05, 0xF8, 0x06, 0x00, 0x06, 0x06, 
+    0x06, 0x0C, 0x06, 0x12, 0x06, 0x18, 0x06, 0x1E, 0x06, 0x24, 0x06, 0x2A, 0x00, 0x02, 0x00, 0xA8, 
+    0x03, 0x41, 0x00, 0x02, 0x03, 0x91, 0x03, 0x41, 0x00, 0x02, 0x03, 0x95, 0x03, 0x41, 0x00, 0x02, 
+    0x03, 0x97, 0x03, 0x41, 0x00, 0x02, 0x03, 0x99, 0x03, 0x41, 0x00, 0x02, 0x03, 0x9F, 0x03, 0x41, 
+    0x00, 0x02, 0x03, 0xA5, 0x03, 0x41, 0x00, 0x02, 0x03, 0xA9, 0x03, 0x41, 0x00, 0x02, 0x03, 0xCA, 
+    0x03, 0x01, 0x00, 0x02, 0x03, 0xB1, 0x03, 0x41, 0x00, 0x02, 0x03, 0xB5, 0x03, 0x41, 0x00, 0x02, 
+    0x03, 0xB7, 0x03, 0x41, 0x00, 0x02, 0x03, 0xB9, 0x03, 0x41, 0x00, 0x02, 0x03, 0xCB, 0x03, 0x01, 
+    0x00, 0x02, 0x1F, 0xBE, 0x03, 0x08, 0x00, 0x02, 0x03, 0xBF, 0x03, 0x41, 0x00, 0x02, 0x03, 0xC5, 
+    0x03, 0x41, 0x00, 0x02, 0x03, 0xC9, 0x03, 0x41, 0x00, 0x02, 0x03, 0xD2, 0x03, 0x41, 0x00, 0x02, 
+    0x03, 0xB1, 0x03, 0x43, 0x00, 0x02, 0x1F, 0x00, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x01, 0x03, 0x40, 
+    0x00, 0x02, 0x1F, 0x00, 0x03, 0x41, 0x00, 0x02, 0x1F, 0x01, 0x03, 0x41, 0x00, 0x03, 0x03, 0xB1, 
+    0x03, 0x13, 0x03, 0x42, 0x00, 0x03, 0x03, 0xB1, 0x03, 0x14, 0x03, 0x42, 0x00, 0x02, 0x03, 0x91, 
+    0x03, 0x43, 0x00, 0x02, 0x1F, 0x08, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x09, 0x03, 0x40, 0x00, 0x02, 
+    0x1F, 0x08, 0x03, 0x41, 0x00, 0x02, 0x1F, 0x09, 0x03, 0x41, 0x00, 0x03, 0x03, 0x91, 0x03, 0x13, 
+    0x03, 0x42, 0x00, 0x03, 0x03, 0x91, 0x03, 0x14, 0x03, 0x42, 0x00, 0x02, 0x03, 0xB5, 0x03, 0x43, 
+    0x00, 0x02, 0x1F, 0x10, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x11, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x10, 
+    0x03, 0x41, 0x00, 0x02, 0x1F, 0x11, 0x03, 0x41, 0x00, 0x02, 0x03, 0x95, 0x03, 0x43, 0x00, 0x02, 
+    0x1F, 0x18, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x19, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x18, 0x03, 0x41, 
+    0x00, 0x02, 0x1F, 0x19, 0x03, 0x41, 0x00, 0x02, 0x03, 0xB7, 0x03, 0x43, 0x00, 0x02, 0x1F, 0x20, 
+    0x03, 0x40, 0x00, 0x02, 0x1F, 0x21, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x20, 0x03, 0x41, 0x00, 0x02, 
+    0x1F, 0x21, 0x03, 0x41, 0x00, 0x03, 0x03, 0xB7, 0x03, 0x13, 0x03, 0x42, 0x00, 0x03, 0x03, 0xB7, 
+    0x03, 0x14, 0x03, 0x42, 0x00, 0x02, 0x03, 0x97, 0x03, 0x43, 0x00, 0x02, 0x1F, 0x28, 0x03, 0x40, 
+    0x00, 0x02, 0x1F, 0x29, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x28, 0x03, 0x41, 0x00, 0x02, 0x1F, 0x29, 
+    0x03, 0x41, 0x00, 0x03, 0x03, 0x97, 0x03, 0x13, 0x03, 0x42, 0x00, 0x03, 0x03, 0x97, 0x03, 0x14, 
+    0x03, 0x42, 0x00, 0x02, 0x03, 0xB9, 0x03, 0x43, 0x00, 0x02, 0x1F, 0xBE, 0x03, 0x14, 0x00, 0x02, 
+    0x1F, 0x30, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x31, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x30, 0x03, 0x41, 
+    0x00, 0x02, 0x1F, 0x31, 0x03, 0x41, 0x00, 0x03, 0x03, 0xB9, 0x03, 0x13, 0x03, 0x42, 0x00, 0x03, 
+    0x03, 0xB9, 0x03, 0x14, 0x03, 0x42, 0x00, 0x02, 0x03, 0x99, 0x03, 0x43, 0x00, 0x02, 0x1F, 0x38, 
+    0x03, 0x40, 0x00, 0x02, 0x1F, 0x39, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x38, 0x03, 0x41, 0x00, 0x02, 
+    0x1F, 0x39, 0x03, 0x41, 0x00, 0x03, 0x03, 0x99, 0x03, 0x13, 0x03, 0x42, 0x00, 0x03, 0x03, 0x99, 
+    0x03, 0x14, 0x03, 0x42, 0x00, 0x02, 0x03, 0xBF, 0x03, 0x43, 0x00, 0x02, 0x1F, 0x40, 0x03, 0x40, 
+    0x00, 0x02, 0x1F, 0x41, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x40, 0x03, 0x41, 0x00, 0x02, 0x1F, 0x41, 
+    0x03, 0x41, 0x00, 0x02, 0x03, 0x9F, 0x03, 0x43, 0x00, 0x02, 0x1F, 0x48, 0x03, 0x40, 0x00, 0x02, 
+    0x1F, 0x49, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x48, 0x03, 0x41, 0x00, 0x02, 0x1F, 0x49, 0x03, 0x41, 
+    0x00, 0x02, 0x03, 0xC5, 0x03, 0x43, 0x00, 0x02, 0x1F, 0x50, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x51, 
+    0x03, 0x40, 0x00, 0x02, 0x1F, 0x50, 0x03, 0x41, 0x00, 0x02, 0x1F, 0x51, 0x03, 0x41, 0x00, 0x03, 
+    0x03, 0xC5, 0x03, 0x13, 0x03, 0x42, 0x00, 0x03, 0x03, 0xC5, 0x03, 0x14, 0x03, 0x42, 0x00, 0x02, 
+    0x1F, 0x59, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x59, 0x03, 0x41, 0x00, 0x03, 0x03, 0xA5, 0x03, 0x14, 
+    0x03, 0x42, 0x00, 0x02, 0x03, 0xC9, 0x03, 0x43, 0x00, 0x02, 0x1F, 0x60, 0x03, 0x40, 0x00, 0x02, 
+    0x1F, 0x61, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x60, 0x03, 0x41, 0x00, 0x02, 0x1F, 0x61, 0x03, 0x41, 
+    0x00, 0x03, 0x03, 0xC9, 0x03, 0x13, 0x03, 0x42, 0x00, 0x03, 0x03, 0xC9, 0x03, 0x14, 0x03, 0x42, 
+    0x00, 0x02, 0x03, 0xA9, 0x03, 0x43, 0x00, 0x02, 0x21, 0x26, 0x03, 0x14, 0x00, 0x02, 0x1F, 0x68, 
+    0x03, 0x40, 0x00, 0x02, 0x1F, 0x69, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x68, 0x03, 0x41, 0x00, 0x02, 
+    0x1F, 0x69, 0x03, 0x41, 0x00, 0x03, 0x03, 0xA9, 0x03, 0x13, 0x03, 0x42, 0x00, 0x03, 0x03, 0xA9, 
+    0x03, 0x14, 0x03, 0x42, 0x00, 0x02, 0x03, 0xB1, 0x03, 0x40, 0x00, 0x02, 0x03, 0xB5, 0x03, 0x40, 
+    0x00, 0x02, 0x03, 0xB7, 0x03, 0x40, 0x00, 0x02, 0x03, 0xB9, 0x03, 0x40, 0x00, 0x02, 0x03, 0xBF, 
+    0x03, 0x40, 0x00, 0x02, 0x03, 0xC5, 0x03, 0x40, 0x00, 0x02, 0x03, 0xC9, 0x03, 0x40, 0x00, 0x02, 
+    0x1F, 0xB3, 0x03, 0x13, 0x00, 0x02, 0x1F, 0xB3, 0x03, 0x14, 0x00, 0x02, 0x1F, 0x80, 0x03, 0x00, 
+    0x00, 0x02, 0x1F, 0x81, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x80, 0x03, 0x01, 0x00, 0x02, 0x1F, 0x81, 
+    0x03, 0x01, 0x00, 0x02, 0x1F, 0x80, 0x03, 0x42, 0x00, 0x02, 0x1F, 0x81, 0x03, 0x42, 0x00, 0x02, 
+    0x1F, 0xBC, 0x03, 0x13, 0x00, 0x02, 0x1F, 0xBC, 0x03, 0x14, 0x00, 0x02, 0x1F, 0x88, 0x03, 0x00, 
+    0x00, 0x02, 0x1F, 0x89, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x88, 0x03, 0x01, 0x00, 0x02, 0x1F, 0x89, 
+    0x03, 0x01, 0x00, 0x02, 0x1F, 0x88, 0x03, 0x42, 0x00, 0x02, 0x1F, 0x89, 0x03, 0x42, 0x00, 0x02, 
+    0x1F, 0xC3, 0x03, 0x13, 0x00, 0x02, 0x1F, 0xC3, 0x03, 0x14, 0x00, 0x02, 0x1F, 0x90, 0x03, 0x00, 
+    0x00, 0x02, 0x1F, 0x91, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x90, 0x03, 0x01, 0x00, 0x02, 0x1F, 0x91, 
+    0x03, 0x01, 0x00, 0x02, 0x1F, 0x90, 0x03, 0x42, 0x00, 0x02, 0x1F, 0x91, 0x03, 0x42, 0x00, 0x02, 
+    0x1F, 0xCC, 0x03, 0x13, 0x00, 0x02, 0x1F, 0xCC, 0x03, 0x14, 0x00, 0x02, 0x1F, 0x98, 0x03, 0x00, 
+    0x00, 0x02, 0x1F, 0x99, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x98, 0x03, 0x01, 0x00, 0x02, 0x1F, 0x99, 
+    0x03, 0x01, 0x00, 0x02, 0x1F, 0x98, 0x03, 0x42, 0x00, 0x02, 0x1F, 0x99, 0x03, 0x42, 0x00, 0x02, 
+    0x1F, 0xF3, 0x03, 0x13, 0x00, 0x02, 0x1F, 0xF3, 0x03, 0x14, 0x00, 0x02, 0x1F, 0xA0, 0x03, 0x00, 
+    0x00, 0x02, 0x1F, 0xA1, 0x03, 0x00, 0x00, 0x02, 0x1F, 0xA0, 0x03, 0x01, 0x00, 0x02, 0x1F, 0xA1, 
+    0x03, 0x01, 0x00, 0x02, 0x1F, 0xA0, 0x03, 0x42, 0x00, 0x02, 0x1F, 0xA1, 0x03, 0x42, 0x00, 0x02, 
+    0x1F, 0xFC, 0x03, 0x13, 0x00, 0x02, 0x1F, 0xFC, 0x03, 0x14, 0x00, 0x02, 0x1F, 0xA8, 0x03, 0x00, 
+    0x00, 0x02, 0x1F, 0xA9, 0x03, 0x00, 0x00, 0x02, 0x1F, 0xA8, 0x03, 0x01, 0x00, 0x02, 0x1F, 0xA9, 
+    0x03, 0x01, 0x00, 0x02, 0x1F, 0xA8, 0x03, 0x42, 0x00, 0x02, 0x1F, 0xA9, 0x03, 0x42, 0x00, 0x02, 
+    0x1F, 0xB3, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x71, 0x03, 0x45, 0x00, 0x02, 0x1F, 0xB6, 0x03, 0x45, 
+    0x00, 0x02, 0x03, 0x91, 0x03, 0x40, 0x00, 0x02, 0x1F, 0xC3, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x75, 
+    0x03, 0x45, 0x00, 0x02, 0x1F, 0xC6, 0x03, 0x45, 0x00, 0x02, 0x03, 0x95, 0x03, 0x40, 0x00, 0x02, 
+    0x03, 0x97, 0x03, 0x40, 0x00, 0x02, 0x1F, 0xBF, 0x03, 0x40, 0x00, 0x02, 0x1F, 0xBF, 0x03, 0x41, 
+    0x00, 0x02, 0x1F, 0xBE, 0x03, 0x06, 0x00, 0x02, 0x1F, 0xBE, 0x03, 0x04, 0x00, 0x02, 0x03, 0xCA, 
+    0x03, 0x40, 0x00, 0x02, 0x1F, 0xBE, 0x03, 0x42, 0x00, 0x03, 0x03, 0xB9, 0x03, 0x08, 0x03, 0x42, 
+    0x00, 0x02, 0x03, 0x99, 0x03, 0x40, 0x00, 0x02, 0x1F, 0xFE, 0x03, 0x40, 0x00, 0x02, 0x1F, 0xFE, 
+    0x03, 0x41, 0x00, 0x02, 0x03, 0xCB, 0x03, 0x40, 0x00, 0x02, 0x03, 0xC1, 0x03, 0x43, 0x00, 0x03, 
+    0x03, 0xC5, 0x03, 0x08, 0x03, 0x42, 0x00, 0x02, 0x03, 0xA5, 0x03, 0x40, 0x00, 0x02, 0x00, 0xA8, 
+    0x03, 0x40, 0x00, 0x02, 0x1F, 0xF3, 0x03, 0x00, 0x00, 0x02, 0x1F, 0x7D, 0x03, 0x45, 0x00, 0x02, 
+    0x1F, 0xF6, 0x03, 0x45, 0x00, 0x02, 0x03, 0x9F, 0x03, 0x40, 0x00, 0x02, 0x03, 0xA9, 0x03, 0x40, 
+    0x00, 0x02, 0x21, 0x26, 0x03, 0x45, 0x00, 0x01, 0x00, 0xC0, 0x03, 0x85, 0x03, 0x86, 0x03, 0x88, 
+    0x03, 0x89, 0x03, 0x8A, 0x03, 0x8C, 0x03, 0x8E, 0x03, 0x8F, 0x03, 0x90, 0x03, 0xAC, 0x03, 0xAD, 
+    0x03, 0xAE, 0x03, 0xAF, 0x03, 0xB0, 0x03, 0xCA, 0x03, 0xCC, 0x03, 0xCD, 0x03, 0xCE, 0x03, 0xD3, 
+    0x1F, 0x00, 0x1F, 0x02, 0x1F, 0x03, 0x1F, 0x04, 0x1F, 0x05, 0x1F, 0x06, 0x1F, 0x07, 0x1F, 0x08, 
+    0x1F, 0x0A, 0x1F, 0x0B, 0x1F, 0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F, 0x10, 0x1F, 0x12, 
+    0x1F, 0x13, 0x1F, 0x14, 0x1F, 0x15, 0x1F, 0x18, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F, 0x1C, 0x1F, 0x1D, 
+    0x1F, 0x20, 0x1F, 0x22, 0x1F, 0x23, 0x1F, 0x24, 0x1F, 0x25, 0x1F, 0x26, 0x1F, 0x27, 0x1F, 0x28, 
+    0x1F, 0x2A, 0x1F, 0x2B, 0x1F, 0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F, 0x30, 0x1F, 0x31, 
+    0x1F, 0x32, 0x1F, 0x33, 0x1F, 0x34, 0x1F, 0x35, 0x1F, 0x36, 0x1F, 0x37, 0x1F, 0x38, 0x1F, 0x3A, 
+    0x1F, 0x3B, 0x1F, 0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F, 0x40, 0x1F, 0x42, 0x1F, 0x43, 
+    0x1F, 0x44, 0x1F, 0x45, 0x1F, 0x48, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F, 0x4C, 0x1F, 0x4D, 0x1F, 0x50, 
+    0x1F, 0x52, 0x1F, 0x53, 0x1F, 0x54, 0x1F, 0x55, 0x1F, 0x56, 0x1F, 0x57, 0x1F, 0x5B, 0x1F, 0x5D, 
+    0x1F, 0x5F, 0x1F, 0x60, 0x1F, 0x62, 0x1F, 0x63, 0x1F, 0x64, 0x1F, 0x65, 0x1F, 0x66, 0x1F, 0x67, 
+    0x1F, 0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F, 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 
+    0x1F, 0x70, 0x1F, 0x72, 0x1F, 0x74, 0x1F, 0x76, 0x1F, 0x78, 0x1F, 0x7A, 0x1F, 0x7C, 0x1F, 0x80, 
+    0x1F, 0x81, 0x1F, 0x82, 0x1F, 0x83, 0x1F, 0x84, 0x1F, 0x85, 0x1F, 0x86, 0x1F, 0x87, 0x1F, 0x88, 
+    0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, 0x90, 
+    0x1F, 0x91, 0x1F, 0x92, 0x1F, 0x93, 0x1F, 0x94, 0x1F, 0x95, 0x1F, 0x96, 0x1F, 0x97, 0x1F, 0x98, 
+    0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, 0xA0, 
+    0x1F, 0xA1, 0x1F, 0xA2, 0x1F, 0xA3, 0x1F, 0xA4, 0x1F, 0xA5, 0x1F, 0xA6, 0x1F, 0xA7, 0x1F, 0xA8, 
+    0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, 0xB2, 
+    0x1F, 0xB4, 0x1F, 0xB7, 0x1F, 0xBA, 0x1F, 0xC2, 0x1F, 0xC4, 0x1F, 0xC7, 0x1F, 0xC8, 0x1F, 0xCA, 
+    0x1F, 0xCD, 0x1F, 0xCE, 0x1F, 0xD0, 0x1F, 0xD1, 0x1F, 0xD2, 0x1F, 0xD6, 0x1F, 0xD7, 0x1F, 0xDA, 
+    0x1F, 0xDD, 0x1F, 0xDE, 0x1F, 0xE2, 0x1F, 0xE4, 0x1F, 0xE7, 0x1F, 0xEA, 0x1F, 0xED, 0x1F, 0xF2, 
+    0x1F, 0xF4, 0x1F, 0xF7, 0x1F, 0xF8, 0x1F, 0xFA, 0x1F, 0xFC, 0x00, 0x01, 0x04, 0xE0, 0x00, 0x85, 
+    0x01, 0x10, 0x01, 0x16, 0x01, 0x1C, 0x01, 0x22, 0x01, 0x28, 0x01, 0x30, 0x01, 0x38, 0x01, 0x40, 
+    0x01, 0x48, 0x01, 0x50, 0x01, 0x58, 0x01, 0x60, 0x01, 0x68, 0x01, 0x70, 0x01, 0x78, 0x01, 0x80, 
+    0x01, 0x88, 0x01, 0x90, 0x01, 0x98, 0x01, 0xA0, 0x01, 0xA8, 0x01, 0xB0, 0x01, 0xB8, 0x01, 0xC0, 
+    0x01, 0xC8, 0x01, 0xD0, 0x01, 0xD8, 0x01, 0xE0, 0x01, 0xE8, 0x01, 0xF0, 0x01, 0xF8, 0x02, 0x00, 
+    0x02, 0x08, 0x02, 0x0E, 0x02, 0x16, 0x02, 0x1E, 0x02, 0x26, 0x02, 0x2E, 0x02, 0x36, 0x02, 0x3E, 
+    0x02, 0x46, 0x02, 0x4E, 0x02, 0x56, 0x02, 0x5E, 0x02, 0x66, 0x02, 0x6E, 0x02, 0x76, 0x02, 0x7E, 
+    0x02, 0x86, 0x02, 0x8E, 0x02, 0x96, 0x02, 0x9E, 0x02, 0xA6, 0x02, 0xAE, 0x02, 0xB6, 0x02, 0xBE, 
+    0x02, 0xC6, 0x02, 0xCE, 0x02, 0xD6, 0x02, 0xDE, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF6, 0x02, 0xFE, 
+    0x03, 0x06, 0x03, 0x0C, 0x03, 0x14, 0x03, 0x1C, 0x03, 0x24, 0x03, 0x2C, 0x03, 0x34, 0x03, 0x3C, 
+    0x03, 0x42, 0x03, 0x48, 0x03, 0x50, 0x03, 0x56, 0x03, 0x5C, 0x03, 0x62, 0x03, 0x68, 0x03, 0x70, 
+    0x03, 0x78, 0x03, 0x7E, 0x03, 0x86, 0x03, 0x8C, 0x03, 0x92, 0x03, 0x98, 0x03, 0x9E, 0x03, 0xA6, 
+    0x03, 0xAE, 0x03, 0xB4, 0x03, 0xBC, 0x03, 0xC2, 0x03, 0xC8, 0x03, 0xCE, 0x03, 0xD4, 0x03, 0xDC, 
+    0x03, 0xE4, 0x03, 0xEA, 0x03, 0xF2, 0x03, 0xF8, 0x03, 0xFE, 0x04, 0x04, 0x04, 0x0A, 0x04, 0x12, 
+    0x04, 0x1A, 0x04, 0x20, 0x04, 0x28, 0x04, 0x2E, 0x04, 0x34, 0x04, 0x3A, 0x04, 0x40, 0x04, 0x48, 
+    0x04, 0x50, 0x04, 0x56, 0x04, 0x5E, 0x04, 0x64, 0x04, 0x6A, 0x04, 0x70, 0x04, 0x76, 0x04, 0x7E, 
+    0x04, 0x86, 0x04, 0x8C, 0x04, 0x92, 0x04, 0x9A, 0x04, 0xA0, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB6, 
+    0x04, 0xBE, 0x04, 0xC6, 0x04, 0xCC, 0x04, 0xD2, 0x04, 0xDA, 0x00, 0x02, 0x21, 0x26, 0x03, 0x01, 
+    0x00, 0x02, 0x03, 0xCA, 0x03, 0x41, 0x00, 0x02, 0x1F, 0xBE, 0x03, 0x01, 0x00, 0x02, 0x03, 0xCB, 
+    0x03, 0x41, 0x00, 0x03, 0x03, 0xB1, 0x03, 0x13, 0x03, 0x00, 0x00, 0x03, 0x03, 0xB1, 0x03, 0x14, 
+    0x03, 0x00, 0x00, 0x03, 0x03, 0xB1, 0x03, 0x13, 0x03, 0x01, 0x00, 0x03, 0x03, 0xB1, 0x03, 0x14, 
+    0x03, 0x01, 0x00, 0x03, 0x03, 0xB1, 0x03, 0x43, 0x03, 0x42, 0x00, 0x03, 0x03, 0x91, 0x03, 0x13, 
+    0x03, 0x00, 0x00, 0x03, 0x03, 0x91, 0x03, 0x14, 0x03, 0x00, 0x00, 0x03, 0x03, 0x91, 0x03, 0x13, 
+    0x03, 0x01, 0x00, 0x03, 0x03, 0x91, 0x03, 0x14, 0x03, 0x01, 0x00, 0x03, 0x03, 0x91, 0x03, 0x43, 
+    0x03, 0x42, 0x00, 0x03, 0x03, 0xB5, 0x03, 0x13, 0x03, 0x00, 0x00, 0x03, 0x03, 0xB5, 0x03, 0x14, 
+    0x03, 0x00, 0x00, 0x03, 0x03, 0xB5, 0x03, 0x13, 0x03, 0x01, 0x00, 0x03, 0x03, 0xB5, 0x03, 0x14, 
+    0x03, 0x01, 0x00, 0x03, 0x03, 0x95, 0x03, 0x13, 0x03, 0x00, 0x00, 0x03, 0x03, 0x95, 0x03, 0x14, 
+    0x03, 0x00, 0x00, 0x03, 0x03, 0x95, 0x03, 0x13, 0x03, 0x01, 0x00, 0x03, 0x03, 0x95, 0x03, 0x14, 
+    0x03, 0x01, 0x00, 0x03, 0x03, 0xB7, 0x03, 0x13, 0x03, 0x00, 0x00, 0x03, 0x03, 0xB7, 0x03, 0x14, 
+    0x03, 0x00, 0x00, 0x03, 0x03, 0xB7, 0x03, 0x13, 0x03, 0x01, 0x00, 0x03, 0x03, 0xB7, 0x03, 0x14, 
+    0x03, 0x01, 0x00, 0x03, 0x03, 0xB7, 0x03, 0x43, 0x03, 0x42, 0x00, 0x03, 0x03, 0x97, 0x03, 0x13, 
+    0x03, 0x00, 0x00, 0x03, 0x03, 0x97, 0x03, 0x14, 0x03, 0x00, 0x00, 0x03, 0x03, 0x97, 0x03, 0x13, 
+    0x03, 0x01, 0x00, 0x03, 0x03, 0x97, 0x03, 0x14, 0x03, 0x01, 0x00, 0x03, 0x03, 0x97, 0x03, 0x43, 
+    0x03, 0x42, 0x00, 0x02, 0x1F, 0xBE, 0x03, 0x13, 0x00, 0x03, 0x03, 0xB9, 0x03, 0x13, 0x03, 0x00, 
+    0x00, 0x03, 0x03, 0xB9, 0x03, 0x14, 0x03, 0x00, 0x00, 0x03, 0x03, 0xB9, 0x03, 0x13, 0x03, 0x01, 
+    0x00, 0x03, 0x03, 0xB9, 0x03, 0x14, 0x03, 0x01, 0x00, 0x03, 0x03, 0xB9, 0x03, 0x43, 0x03, 0x42, 
+    0x00, 0x03, 0x1F, 0xBE, 0x03, 0x14, 0x03, 0x42, 0x00, 0x03, 0x03, 0x99, 0x03, 0x13, 0x03, 0x00, 
+    0x00, 0x03, 0x03, 0x99, 0x03, 0x14, 0x03, 0x00, 0x00, 0x03, 0x03, 0x99, 0x03, 0x13, 0x03, 0x01, 
+    0x00, 0x03, 0x03, 0x99, 0x03, 0x14, 0x03, 0x01, 0x00, 0x03, 0x03, 0x99, 0x03, 0x43, 0x03, 0x42, 
+    0x00, 0x03, 0x03, 0xBF, 0x03, 0x13, 0x03, 0x00, 0x00, 0x03, 0x03, 0xBF, 0x03, 0x14, 0x03, 0x00, 
+    0x00, 0x03, 0x03, 0xBF, 0x03, 0x13, 0x03, 0x01, 0x00, 0x03, 0x03, 0xBF, 0x03, 0x14, 0x03, 0x01, 
+    0x00, 0x03, 0x03, 0x9F, 0x03, 0x13, 0x03, 0x00, 0x00, 0x03, 0x03, 0x9F, 0x03, 0x14, 0x03, 0x00, 
+    0x00, 0x03, 0x03, 0x9F, 0x03, 0x13, 0x03, 0x01, 0x00, 0x03, 0x03, 0x9F, 0x03, 0x14, 0x03, 0x01, 
+    0x00, 0x03, 0x03, 0xC5, 0x03, 0x13, 0x03, 0x00, 0x00, 0x03, 0x03, 0xC5, 0x03, 0x14, 0x03, 0x00, 
+    0x00, 0x03, 0x03, 0xC5, 0x03, 0x13, 0x03, 0x01, 0x00, 0x03, 0x03, 0xC5, 0x03, 0x14, 0x03, 0x01, 
+    0x00, 0x03, 0x03, 0xC5, 0x03, 0x43, 0x03, 0x42, 0x00, 0x03, 0x03, 0xA5, 0x03, 0x14, 0x03, 0x00, 
+    0x00, 0x03, 0x03, 0xA5, 0x03, 0x14, 0x03, 0x01, 0x00, 0x03, 0x03, 0xC9, 0x03, 0x13, 0x03, 0x00, 
+    0x00, 0x03, 0x03, 0xC9, 0x03, 0x14, 0x03, 0x00, 0x00, 0x03, 0x03, 0xC9, 0x03, 0x13, 0x03, 0x01, 
+    0x00, 0x03, 0x03, 0xC9, 0x03, 0x14, 0x03, 0x01, 0x00, 0x03, 0x03, 0xC9, 0x03, 0x43, 0x03, 0x42, 
+    0x00, 0x02, 0x21, 0x26, 0x03, 0x13, 0x00, 0x03, 0x03, 0xA9, 0x03, 0x13, 0x03, 0x00, 0x00, 0x03, 
+    0x03, 0xA9, 0x03, 0x14, 0x03, 0x00, 0x00, 0x03, 0x03, 0xA9, 0x03, 0x13, 0x03, 0x01, 0x00, 0x03, 
+    0x03, 0xA9, 0x03, 0x14, 0x03, 0x01, 0x00, 0x03, 0x03, 0xA9, 0x03, 0x43, 0x03, 0x42, 0x00, 0x03, 
+    0x21, 0x26, 0x03, 0x14, 0x03, 0x42, 0x00, 0x02, 0x1F, 0xBE, 0x03, 0x00, 0x00, 0x02, 0x1F, 0xB3, 
+    0x03, 0x43, 0x00, 0x03, 0x03, 0xB1, 0x03, 0x14, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x80, 0x03, 0x40, 
+    0x00, 0x02, 0x1F, 0x81, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x80, 0x03, 0x41, 0x00, 0x02, 0x1F, 0x81, 
+    0x03, 0x41, 0x00, 0x03, 0x1F, 0x00, 0x03, 0x42, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x01, 0x03, 0x42, 
+    0x03, 0x45, 0x00, 0x02, 0x1F, 0xBC, 0x03, 0x43, 0x00, 0x03, 0x03, 0x91, 0x03, 0x14, 0x03, 0x45, 
+    0x00, 0x02, 0x1F, 0x88, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x89, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x88, 
+    0x03, 0x41, 0x00, 0x02, 0x1F, 0x89, 0x03, 0x41, 0x00, 0x03, 0x1F, 0x08, 0x03, 0x42, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x09, 0x03, 0x42, 0x03, 0x45, 0x00, 0x02, 0x1F, 0xC3, 0x03, 0x43, 0x00, 0x03, 
+    0x03, 0xB7, 0x03, 0x14, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x90, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x91, 
+    0x03, 0x40, 0x00, 0x02, 0x1F, 0x90, 0x03, 0x41, 0x00, 0x02, 0x1F, 0x91, 0x03, 0x41, 0x00, 0x03, 
+    0x1F, 0x20, 0x03, 0x42, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x21, 0x03, 0x42, 0x03, 0x45, 0x00, 0x02, 
+    0x1F, 0xCC, 0x03, 0x43, 0x00, 0x03, 0x03, 0x97, 0x03, 0x14, 0x03, 0x45, 0x00, 0x02, 0x1F, 0x98, 
+    0x03, 0x40, 0x00, 0x02, 0x1F, 0x99, 0x03, 0x40, 0x00, 0x02, 0x1F, 0x98, 0x03, 0x41, 0x00, 0x02, 
+    0x1F, 0x99, 0x03, 0x41, 0x00, 0x03, 0x1F, 0x28, 0x03, 0x42, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x29, 
+    0x03, 0x42, 0x03, 0x45, 0x00, 0x02, 0x1F, 0xF3, 0x03, 0x43, 0x00, 0x03, 0x03, 0xC9, 0x03, 0x14, 
+    0x03, 0x45, 0x00, 0x02, 0x1F, 0xA0, 0x03, 0x40, 0x00, 0x02, 0x1F, 0xA1, 0x03, 0x40, 0x00, 0x02, 
+    0x1F, 0xA0, 0x03, 0x41, 0x00, 0x02, 0x1F, 0xA1, 0x03, 0x41, 0x00, 0x03, 0x1F, 0x60, 0x03, 0x42, 
+    0x03, 0x45, 0x00, 0x03, 0x1F, 0x61, 0x03, 0x42, 0x03, 0x45, 0x00, 0x02, 0x1F, 0xFC, 0x03, 0x43, 
+    0x00, 0x03, 0x03, 0xA9, 0x03, 0x14, 0x03, 0x45, 0x00, 0x02, 0x1F, 0xA8, 0x03, 0x40, 0x00, 0x02, 
+    0x1F, 0xA9, 0x03, 0x40, 0x00, 0x02, 0x1F, 0xA8, 0x03, 0x41, 0x00, 0x02, 0x1F, 0xA9, 0x03, 0x41, 
+    0x00, 0x03, 0x1F, 0x68, 0x03, 0x42, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x69, 0x03, 0x42, 0x03, 0x45, 
+    0x00, 0x02, 0x1F, 0xB3, 0x03, 0x40, 0x00, 0x02, 0x1F, 0xB3, 0x03, 0x01, 0x00, 0x03, 0x03, 0xB1, 
+    0x03, 0x42, 0x03, 0x45, 0x00, 0x02, 0x1F, 0xC3, 0x03, 0x40, 0x00, 0x02, 0x1F, 0xC3, 0x03, 0x01, 
+    0x00, 0x03, 0x03, 0xB7, 0x03, 0x42, 0x03, 0x45, 0x00, 0x03, 0x03, 0xB9, 0x03, 0x08, 0x03, 0x00, 
+    0x00, 0x03, 0x1F, 0xBE, 0x03, 0x08, 0x03, 0x42, 0x00, 0x03, 0x03, 0xC5, 0x03, 0x08, 0x03, 0x00, 
+    0x00, 0x02, 0x1F, 0xF3, 0x03, 0x40, 0x00, 0x02, 0x1F, 0xF3, 0x03, 0x01, 0x00, 0x03, 0x03, 0xC9, 
+    0x03, 0x42, 0x03, 0x45, 0x00, 0x02, 0x21, 0x26, 0x03, 0x00, 0x00, 0x01, 0x00, 0x85, 0x03, 0x8F, 
+    0x03, 0x90, 0x03, 0xAF, 0x03, 0xB0, 0x1F, 0x02, 0x1F, 0x03, 0x1F, 0x04, 0x1F, 0x05, 0x1F, 0x06, 
+    0x1F, 0x0A, 0x1F, 0x0B, 0x1F, 0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x12, 0x1F, 0x13, 0x1F, 0x14, 
+    0x1F, 0x15, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F, 0x1C, 0x1F, 0x1D, 0x1F, 0x22, 0x1F, 0x23, 0x1F, 0x24, 
+    0x1F, 0x25, 0x1F, 0x26, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F, 0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x30, 
+    0x1F, 0x32, 0x1F, 0x33, 0x1F, 0x34, 0x1F, 0x35, 0x1F, 0x36, 0x1F, 0x37, 0x1F, 0x3A, 0x1F, 0x3B, 
+    0x1F, 0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x42, 0x1F, 0x43, 0x1F, 0x44, 0x1F, 0x45, 0x1F, 0x4A, 
+    0x1F, 0x4B, 0x1F, 0x4C, 0x1F, 0x4D, 0x1F, 0x52, 0x1F, 0x53, 0x1F, 0x54, 0x1F, 0x55, 0x1F, 0x56, 
+    0x1F, 0x5B, 0x1F, 0x5D, 0x1F, 0x62, 0x1F, 0x63, 0x1F, 0x64, 0x1F, 0x65, 0x1F, 0x66, 0x1F, 0x68, 
+    0x1F, 0x6A, 0x1F, 0x6B, 0x1F, 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F, 0x76, 0x1F, 0x80, 
+    0x1F, 0x81, 0x1F, 0x82, 0x1F, 0x83, 0x1F, 0x84, 0x1F, 0x85, 0x1F, 0x86, 0x1F, 0x87, 0x1F, 0x88, 
+    0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, 0x90, 
+    0x1F, 0x91, 0x1F, 0x92, 0x1F, 0x93, 0x1F, 0x94, 0x1F, 0x95, 0x1F, 0x96, 0x1F, 0x97, 0x1F, 0x98, 
+    0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, 0xA0, 
+    0x1F, 0xA1, 0x1F, 0xA2, 0x1F, 0xA3, 0x1F, 0xA4, 0x1F, 0xA5, 0x1F, 0xA6, 0x1F, 0xA7, 0x1F, 0xA8, 
+    0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, 0xB2, 
+    0x1F, 0xB4, 0x1F, 0xB7, 0x1F, 0xC2, 0x1F, 0xC4, 0x1F, 0xC7, 0x1F, 0xD2, 0x1F, 0xD7, 0x1F, 0xE2, 
+    0x1F, 0xF2, 0x1F, 0xF4, 0x1F, 0xF7, 0x1F, 0xFA, 0x00, 0x01, 0x04, 0xC0, 0x00, 0x7B, 0x00, 0xFC, 
+    0x01, 0x02, 0x01, 0x08, 0x01, 0x0E, 0x01, 0x16, 0x01, 0x1E, 0x01, 0x26, 0x01, 0x2E, 0x01, 0x36, 
+    0x01, 0x3E, 0x01, 0x46, 0x01, 0x4E, 0x01, 0x56, 0x01, 0x5E, 0x01, 0x66, 0x01, 0x6E, 0x01, 0x76, 
+    0x01, 0x7E, 0x01, 0x86, 0x01, 0x8E, 0x01, 0x96, 0x01, 0x9E, 0x01, 0xA6, 0x01, 0xAE, 0x01, 0xB6, 
+    0x01, 0xBE, 0x01, 0xC6, 0x01, 0xCE, 0x01, 0xD6, 0x01, 0xDC, 0x01, 0xE4, 0x01, 0xEC, 0x01, 0xF4, 
+    0x01, 0xFC, 0x02, 0x04, 0x02, 0x0C, 0x02, 0x14, 0x02, 0x1C, 0x02, 0x24, 0x02, 0x2C, 0x02, 0x34, 
+    0x02, 0x3C, 0x02, 0x44, 0x02, 0x4C, 0x02, 0x54, 0x02, 0x5C, 0x02, 0x64, 0x02, 0x6C, 0x02, 0x74, 
+    0x02, 0x7C, 0x02, 0x84, 0x02, 0x8C, 0x02, 0x94, 0x02, 0x9C, 0x02, 0xA4, 0x02, 0xAC, 0x02, 0xB4, 
+    0x02, 0xBA, 0x02, 0xC2, 0x02, 0xCA, 0x02, 0xD2, 0x02, 0xDA, 0x02, 0xE2, 0x02, 0xE8, 0x02, 0xF0, 
+    0x02, 0xF8, 0x03, 0x00, 0x03, 0x08, 0x03, 0x10, 0x03, 0x18, 0x03, 0x20, 0x03, 0x28, 0x03, 0x30, 
+    0x03, 0x38, 0x03, 0x40, 0x03, 0x48, 0x03, 0x50, 0x03, 0x58, 0x03, 0x60, 0x03, 0x68, 0x03, 0x70, 
+    0x03, 0x78, 0x03, 0x80, 0x03, 0x88, 0x03, 0x90, 0x03, 0x98, 0x03, 0xA0, 0x03, 0xA8, 0x03, 0xB0, 
+    0x03, 0xB8, 0x03, 0xC0, 0x03, 0xC8, 0x03, 0xD0, 0x03, 0xD8, 0x03, 0xE0, 0x03, 0xE8, 0x03, 0xF0, 
+    0x03, 0xF8, 0x04, 0x00, 0x04, 0x08, 0x04, 0x10, 0x04, 0x18, 0x04, 0x20, 0x04, 0x28, 0x04, 0x30, 
+    0x04, 0x38, 0x04, 0x40, 0x04, 0x48, 0x04, 0x50, 0x04, 0x58, 0x04, 0x60, 0x04, 0x68, 0x04, 0x70, 
+    0x04, 0x76, 0x04, 0x7E, 0x04, 0x86, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9C, 0x04, 0xA4, 0x04, 0xAC, 
+    0x04, 0xB2, 0x04, 0xBA, 0x00, 0x02, 0x21, 0x26, 0x03, 0x41, 0x00, 0x02, 0x1F, 0xBE, 0x03, 0x44, 
+    0x00, 0x02, 0x1F, 0xBE, 0x03, 0x41, 0x00, 0x03, 0x03, 0xC5, 0x03, 0x08, 0x03, 0x01, 0x00, 0x03, 
+    0x03, 0xB1, 0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x03, 0xB1, 0x03, 0x14, 0x03, 0x40, 0x00, 0x03, 
+    0x03, 0xB1, 0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x03, 0xB1, 0x03, 0x14, 0x03, 0x41, 0x00, 0x03, 
+    0x03, 0x91, 0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x03, 0x91, 0x03, 0x14, 0x03, 0x40, 0x00, 0x03, 
+    0x03, 0x91, 0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x03, 0x91, 0x03, 0x14, 0x03, 0x41, 0x00, 0x03, 
+    0x03, 0xB5, 0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x03, 0xB5, 0x03, 0x14, 0x03, 0x40, 0x00, 0x03, 
+    0x03, 0xB5, 0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x03, 0xB5, 0x03, 0x14, 0x03, 0x41, 0x00, 0x03, 
+    0x03, 0x95, 0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x03, 0x95, 0x03, 0x14, 0x03, 0x40, 0x00, 0x03, 
+    0x03, 0x95, 0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x03, 0x95, 0x03, 0x14, 0x03, 0x41, 0x00, 0x03, 
+    0x03, 0xB7, 0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x03, 0xB7, 0x03, 0x14, 0x03, 0x40, 0x00, 0x03, 
+    0x03, 0xB7, 0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x03, 0xB7, 0x03, 0x14, 0x03, 0x41, 0x00, 0x03, 
+    0x03, 0x97, 0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x03, 0x97, 0x03, 0x14, 0x03, 0x40, 0x00, 0x03, 
+    0x03, 0x97, 0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x03, 0x97, 0x03, 0x14, 0x03, 0x41, 0x00, 0x02, 
+    0x1F, 0xBE, 0x03, 0x43, 0x00, 0x03, 0x03, 0xB9, 0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x03, 0xB9, 
+    0x03, 0x14, 0x03, 0x40, 0x00, 0x03, 0x03, 0xB9, 0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x03, 0xB9, 
+    0x03, 0x14, 0x03, 0x41, 0x00, 0x03, 0x1F, 0xBE, 0x03, 0x13, 0x03, 0x42, 0x00, 0x03, 0x03, 0x99, 
+    0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x03, 0x99, 0x03, 0x14, 0x03, 0x40, 0x00, 0x03, 0x03, 0x99, 
+    0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x03, 0x99, 0x03, 0x14, 0x03, 0x41, 0x00, 0x03, 0x03, 0xBF, 
+    0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x03, 0xBF, 0x03, 0x14, 0x03, 0x40, 0x00, 0x03, 0x03, 0xBF, 
+    0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x03, 0xBF, 0x03, 0x14, 0x03, 0x41, 0x00, 0x03, 0x03, 0x9F, 
+    0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x03, 0x9F, 0x03, 0x14, 0x03, 0x40, 0x00, 0x03, 0x03, 0x9F, 
+    0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x03, 0x9F, 0x03, 0x14, 0x03, 0x41, 0x00, 0x03, 0x03, 0xC5, 
+    0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x03, 0xC5, 0x03, 0x14, 0x03, 0x40, 0x00, 0x03, 0x03, 0xC5, 
+    0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x03, 0xC5, 0x03, 0x14, 0x03, 0x41, 0x00, 0x03, 0x03, 0xA5, 
+    0x03, 0x14, 0x03, 0x40, 0x00, 0x03, 0x03, 0xA5, 0x03, 0x14, 0x03, 0x41, 0x00, 0x03, 0x03, 0xC9, 
+    0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x03, 0xC9, 0x03, 0x14, 0x03, 0x40, 0x00, 0x03, 0x03, 0xC9, 
+    0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x03, 0xC9, 0x03, 0x14, 0x03, 0x41, 0x00, 0x02, 0x21, 0x26, 
+    0x03, 0x43, 0x00, 0x03, 0x03, 0xA9, 0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x03, 0xA9, 0x03, 0x14, 
+    0x03, 0x40, 0x00, 0x03, 0x03, 0xA9, 0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x03, 0xA9, 0x03, 0x14, 
+    0x03, 0x41, 0x00, 0x03, 0x21, 0x26, 0x03, 0x13, 0x03, 0x42, 0x00, 0x02, 0x1F, 0xBE, 0x03, 0x40, 
+    0x00, 0x03, 0x03, 0xB1, 0x03, 0x13, 0x03, 0x45, 0x00, 0x03, 0x03, 0xB1, 0x03, 0x45, 0x03, 0x14, 
+    0x00, 0x03, 0x1F, 0x00, 0x03, 0x00, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x01, 0x03, 0x00, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x00, 0x03, 0x01, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x01, 0x03, 0x01, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x00, 0x03, 0x45, 0x03, 0x42, 0x00, 0x03, 0x1F, 0x01, 0x03, 0x45, 0x03, 0x42, 
+    0x00, 0x03, 0x03, 0x91, 0x03, 0x13, 0x03, 0x45, 0x00, 0x03, 0x03, 0x91, 0x03, 0x45, 0x03, 0x14, 
+    0x00, 0x03, 0x1F, 0x08, 0x03, 0x00, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x09, 0x03, 0x00, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x08, 0x03, 0x01, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x09, 0x03, 0x01, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x08, 0x03, 0x45, 0x03, 0x42, 0x00, 0x03, 0x1F, 0x09, 0x03, 0x45, 0x03, 0x42, 
+    0x00, 0x03, 0x03, 0xB7, 0x03, 0x13, 0x03, 0x45, 0x00, 0x03, 0x03, 0xB7, 0x03, 0x45, 0x03, 0x14, 
+    0x00, 0x03, 0x1F, 0x20, 0x03, 0x00, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x21, 0x03, 0x00, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x20, 0x03, 0x01, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x21, 0x03, 0x01, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x20, 0x03, 0x45, 0x03, 0x42, 0x00, 0x03, 0x1F, 0x21, 0x03, 0x45, 0x03, 0x42, 
+    0x00, 0x03, 0x03, 0x97, 0x03, 0x13, 0x03, 0x45, 0x00, 0x03, 0x03, 0x97, 0x03, 0x45, 0x03, 0x14, 
+    0x00, 0x03, 0x1F, 0x28, 0x03, 0x00, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x29, 0x03, 0x00, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x28, 0x03, 0x01, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x29, 0x03, 0x01, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x28, 0x03, 0x45, 0x03, 0x42, 0x00, 0x03, 0x1F, 0x29, 0x03, 0x45, 0x03, 0x42, 
+    0x00, 0x03, 0x03, 0xC9, 0x03, 0x13, 0x03, 0x45, 0x00, 0x03, 0x03, 0xC9, 0x03, 0x45, 0x03, 0x14, 
+    0x00, 0x03, 0x1F, 0x60, 0x03, 0x00, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x61, 0x03, 0x00, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x60, 0x03, 0x01, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x61, 0x03, 0x01, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x60, 0x03, 0x45, 0x03, 0x42, 0x00, 0x03, 0x1F, 0x61, 0x03, 0x45, 0x03, 0x42, 
+    0x00, 0x03, 0x03, 0xA9, 0x03, 0x13, 0x03, 0x45, 0x00, 0x03, 0x03, 0xA9, 0x03, 0x45, 0x03, 0x14, 
+    0x00, 0x03, 0x1F, 0x68, 0x03, 0x00, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x69, 0x03, 0x00, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x68, 0x03, 0x01, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x69, 0x03, 0x01, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x68, 0x03, 0x45, 0x03, 0x42, 0x00, 0x03, 0x1F, 0x69, 0x03, 0x45, 0x03, 0x42, 
+    0x00, 0x03, 0x03, 0xB1, 0x03, 0x00, 0x03, 0x45, 0x00, 0x02, 0x1F, 0xB3, 0x03, 0x41, 0x00, 0x03, 
+    0x03, 0xB1, 0x03, 0x45, 0x03, 0x42, 0x00, 0x03, 0x03, 0xB7, 0x03, 0x00, 0x03, 0x45, 0x00, 0x02, 
+    0x1F, 0xC3, 0x03, 0x41, 0x00, 0x03, 0x03, 0xB7, 0x03, 0x45, 0x03, 0x42, 0x00, 0x03, 0x03, 0xB9, 
+    0x03, 0x08, 0x03, 0x40, 0x00, 0x03, 0x03, 0xC5, 0x03, 0x08, 0x03, 0x40, 0x00, 0x03, 0x03, 0xC9, 
+    0x03, 0x00, 0x03, 0x45, 0x00, 0x02, 0x1F, 0xF3, 0x03, 0x41, 0x00, 0x03, 0x03, 0xC9, 0x03, 0x45, 
+    0x03, 0x42, 0x00, 0x02, 0x21, 0x26, 0x03, 0x40, 0x00, 0x01, 0x00, 0x7B, 0x03, 0x8F, 0x03, 0x90, 
+    0x03, 0xAF, 0x03, 0xB0, 0x1F, 0x02, 0x1F, 0x03, 0x1F, 0x04, 0x1F, 0x05, 0x1F, 0x0A, 0x1F, 0x0B, 
+    0x1F, 0x0C, 0x1F, 0x0D, 0x1F, 0x12, 0x1F, 0x13, 0x1F, 0x14, 0x1F, 0x15, 0x1F, 0x1A, 0x1F, 0x1B, 
+    0x1F, 0x1C, 0x1F, 0x1D, 0x1F, 0x22, 0x1F, 0x23, 0x1F, 0x24, 0x1F, 0x25, 0x1F, 0x2A, 0x1F, 0x2B, 
+    0x1F, 0x2C, 0x1F, 0x2D, 0x1F, 0x30, 0x1F, 0x32, 0x1F, 0x33, 0x1F, 0x34, 0x1F, 0x35, 0x1F, 0x36, 
+    0x1F, 0x3A, 0x1F, 0x3B, 0x1F, 0x3C, 0x1F, 0x3D, 0x1F, 0x42, 0x1F, 0x43, 0x1F, 0x44, 0x1F, 0x45, 
+    0x1F, 0x4A, 0x1F, 0x4B, 0x1F, 0x4C, 0x1F, 0x4D, 0x1F, 0x52, 0x1F, 0x53, 0x1F, 0x54, 0x1F, 0x55, 
+    0x1F, 0x5B, 0x1F, 0x5D, 0x1F, 0x62, 0x1F, 0x63, 0x1F, 0x64, 0x1F, 0x65, 0x1F, 0x68, 0x1F, 0x6A, 
+    0x1F, 0x6B, 0x1F, 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x76, 0x1F, 0x80, 0x1F, 0x81, 0x1F, 0x82, 
+    0x1F, 0x83, 0x1F, 0x84, 0x1F, 0x85, 0x1F, 0x86, 0x1F, 0x87, 0x1F, 0x88, 0x1F, 0x89, 0x1F, 0x8A, 
+    0x1F, 0x8B, 0x1F, 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, 0x90, 0x1F, 0x91, 0x1F, 0x92, 
+    0x1F, 0x93, 0x1F, 0x94, 0x1F, 0x95, 0x1F, 0x96, 0x1F, 0x97, 0x1F, 0x98, 0x1F, 0x99, 0x1F, 0x9A, 
+    0x1F, 0x9B, 0x1F, 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, 0xA0, 0x1F, 0xA1, 0x1F, 0xA2, 
+    0x1F, 0xA3, 0x1F, 0xA4, 0x1F, 0xA5, 0x1F, 0xA6, 0x1F, 0xA7, 0x1F, 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 
+    0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, 0xB2, 0x1F, 0xB4, 0x1F, 0xB7, 
+    0x1F, 0xC2, 0x1F, 0xC4, 0x1F, 0xC7, 0x1F, 0xD2, 0x1F, 0xE2, 0x1F, 0xF2, 0x1F, 0xF4, 0x1F, 0xF7, 
+    0x1F, 0xFA, 0x00, 0x01, 0x03, 0x4E, 0x00, 0x54, 0x00, 0xAE, 0x00, 0xB6, 0x00, 0xBE, 0x00, 0xC6, 
+    0x00, 0xCE, 0x00, 0xD6, 0x00, 0xDE, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xF6, 0x00, 0xFE, 0x01, 0x06, 
+    0x01, 0x0E, 0x01, 0x16, 0x01, 0x1E, 0x01, 0x26, 0x01, 0x2E, 0x01, 0x36, 0x01, 0x3E, 0x01, 0x46, 
+    0x01, 0x4E, 0x01, 0x56, 0x01, 0x5E, 0x01, 0x66, 0x01, 0x6E, 0x01, 0x76, 0x01, 0x7E, 0x01, 0x86, 
+    0x01, 0x8E, 0x01, 0x96, 0x01, 0x9E, 0x01, 0xA6, 0x01, 0xAE, 0x01, 0xB6, 0x01, 0xBE, 0x01, 0xC6, 
+    0x01, 0xCE, 0x01, 0xD6, 0x01, 0xDE, 0x01, 0xE6, 0x01, 0xEE, 0x01, 0xF6, 0x01, 0xFE, 0x02, 0x06, 
+    0x02, 0x0E, 0x02, 0x16, 0x02, 0x1E, 0x02, 0x26, 0x02, 0x2E, 0x02, 0x36, 0x02, 0x3E, 0x02, 0x46, 
+    0x02, 0x4E, 0x02, 0x56, 0x02, 0x5E, 0x02, 0x66, 0x02, 0x6E, 0x02, 0x76, 0x02, 0x7E, 0x02, 0x86, 
+    0x02, 0x8E, 0x02, 0x96, 0x02, 0x9E, 0x02, 0xA6, 0x02, 0xAE, 0x02, 0xB6, 0x02, 0xBE, 0x02, 0xC6, 
+    0x02, 0xCE, 0x02, 0xD6, 0x02, 0xDE, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF6, 0x02, 0xFE, 0x03, 0x06, 
+    0x03, 0x0E, 0x03, 0x16, 0x03, 0x1E, 0x03, 0x26, 0x03, 0x2E, 0x03, 0x36, 0x03, 0x3E, 0x03, 0x46, 
+    0x00, 0x03, 0x03, 0xB9, 0x03, 0x08, 0x03, 0x01, 0x00, 0x03, 0x03, 0xC5, 0x03, 0x08, 0x03, 0x41, 
+    0x00, 0x03, 0x03, 0xB1, 0x03, 0x43, 0x03, 0x00, 0x00, 0x03, 0x03, 0xB1, 0x03, 0x43, 0x03, 0x01, 
+    0x00, 0x03, 0x03, 0x91, 0x03, 0x43, 0x03, 0x00, 0x00, 0x03, 0x03, 0x91, 0x03, 0x43, 0x03, 0x01, 
+    0x00, 0x03, 0x03, 0xB5, 0x03, 0x43, 0x03, 0x00, 0x00, 0x03, 0x03, 0xB5, 0x03, 0x43, 0x03, 0x01, 
+    0x00, 0x03, 0x03, 0x95, 0x03, 0x43, 0x03, 0x00, 0x00, 0x03, 0x03, 0x95, 0x03, 0x43, 0x03, 0x01, 
+    0x00, 0x03, 0x03, 0xB7, 0x03, 0x43, 0x03, 0x00, 0x00, 0x03, 0x03, 0xB7, 0x03, 0x43, 0x03, 0x01, 
+    0x00, 0x03, 0x03, 0x97, 0x03, 0x43, 0x03, 0x00, 0x00, 0x03, 0x03, 0x97, 0x03, 0x43, 0x03, 0x01, 
+    0x00, 0x03, 0x03, 0xB9, 0x03, 0x43, 0x03, 0x00, 0x00, 0x03, 0x1F, 0xBE, 0x03, 0x14, 0x03, 0x00, 
+    0x00, 0x03, 0x03, 0xB9, 0x03, 0x43, 0x03, 0x01, 0x00, 0x03, 0x1F, 0xBE, 0x03, 0x14, 0x03, 0x01, 
+    0x00, 0x03, 0x1F, 0xBE, 0x03, 0x43, 0x03, 0x42, 0x00, 0x03, 0x03, 0x99, 0x03, 0x43, 0x03, 0x00, 
+    0x00, 0x03, 0x03, 0x99, 0x03, 0x43, 0x03, 0x01, 0x00, 0x03, 0x03, 0xBF, 0x03, 0x43, 0x03, 0x00, 
+    0x00, 0x03, 0x03, 0xBF, 0x03, 0x43, 0x03, 0x01, 0x00, 0x03, 0x03, 0x9F, 0x03, 0x43, 0x03, 0x00, 
+    0x00, 0x03, 0x03, 0x9F, 0x03, 0x43, 0x03, 0x01, 0x00, 0x03, 0x03, 0xC5, 0x03, 0x43, 0x03, 0x00, 
+    0x00, 0x03, 0x03, 0xC5, 0x03, 0x43, 0x03, 0x01, 0x00, 0x03, 0x03, 0xC9, 0x03, 0x43, 0x03, 0x00, 
+    0x00, 0x03, 0x03, 0xC9, 0x03, 0x43, 0x03, 0x01, 0x00, 0x03, 0x03, 0xA9, 0x03, 0x43, 0x03, 0x00, 
+    0x00, 0x03, 0x21, 0x26, 0x03, 0x14, 0x03, 0x00, 0x00, 0x03, 0x03, 0xA9, 0x03, 0x43, 0x03, 0x01, 
+    0x00, 0x03, 0x21, 0x26, 0x03, 0x14, 0x03, 0x01, 0x00, 0x03, 0x21, 0x26, 0x03, 0x43, 0x03, 0x42, 
+    0x00, 0x03, 0x03, 0xB1, 0x03, 0x43, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x00, 0x03, 0x40, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x01, 0x03, 0x40, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x00, 0x03, 0x41, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x01, 0x03, 0x41, 0x03, 0x45, 0x00, 0x03, 0x1F, 0xB3, 0x03, 0x13, 0x03, 0x42, 
+    0x00, 0x03, 0x1F, 0xB3, 0x03, 0x14, 0x03, 0x42, 0x00, 0x03, 0x03, 0x91, 0x03, 0x43, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x08, 0x03, 0x40, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x09, 0x03, 0x40, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x08, 0x03, 0x41, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x09, 0x03, 0x41, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0xBC, 0x03, 0x13, 0x03, 0x42, 0x00, 0x03, 0x1F, 0xBC, 0x03, 0x14, 0x03, 0x42, 
+    0x00, 0x03, 0x03, 0xB7, 0x03, 0x43, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x20, 0x03, 0x40, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x21, 0x03, 0x40, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x20, 0x03, 0x41, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x21, 0x03, 0x41, 0x03, 0x45, 0x00, 0x03, 0x1F, 0xC3, 0x03, 0x13, 0x03, 0x42, 
+    0x00, 0x03, 0x1F, 0xC3, 0x03, 0x14, 0x03, 0x42, 0x00, 0x03, 0x03, 0x97, 0x03, 0x43, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x28, 0x03, 0x40, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x29, 0x03, 0x40, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x28, 0x03, 0x41, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x29, 0x03, 0x41, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0xCC, 0x03, 0x13, 0x03, 0x42, 0x00, 0x03, 0x1F, 0xCC, 0x03, 0x14, 0x03, 0x42, 
+    0x00, 0x03, 0x03, 0xC9, 0x03, 0x43, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x60, 0x03, 0x40, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x61, 0x03, 0x40, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x60, 0x03, 0x41, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x61, 0x03, 0x41, 0x03, 0x45, 0x00, 0x03, 0x1F, 0xF3, 0x03, 0x13, 0x03, 0x42, 
+    0x00, 0x03, 0x1F, 0xF3, 0x03, 0x14, 0x03, 0x42, 0x00, 0x03, 0x03, 0xA9, 0x03, 0x43, 0x03, 0x45, 
+    0x00, 0x03, 0x21, 0x26, 0x03, 0x14, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x68, 0x03, 0x40, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x69, 0x03, 0x40, 0x03, 0x45, 0x00, 0x03, 0x1F, 0x68, 0x03, 0x41, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0x69, 0x03, 0x41, 0x03, 0x45, 0x00, 0x03, 0x1F, 0xFC, 0x03, 0x13, 0x03, 0x42, 
+    0x00, 0x03, 0x1F, 0xFC, 0x03, 0x14, 0x03, 0x42, 0x00, 0x03, 0x03, 0xB1, 0x03, 0x40, 0x03, 0x45, 
+    0x00, 0x03, 0x03, 0xB1, 0x03, 0x01, 0x03, 0x45, 0x00, 0x03, 0x03, 0xB7, 0x03, 0x40, 0x03, 0x45, 
+    0x00, 0x03, 0x03, 0xB7, 0x03, 0x01, 0x03, 0x45, 0x00, 0x03, 0x1F, 0xBE, 0x03, 0x08, 0x03, 0x00, 
+    0x00, 0x03, 0x03, 0xC9, 0x03, 0x40, 0x03, 0x45, 0x00, 0x03, 0x03, 0xC9, 0x03, 0x01, 0x03, 0x45, 
+    0x00, 0x01, 0x00, 0x54, 0x03, 0x90, 0x03, 0xB0, 0x1F, 0x02, 0x1F, 0x04, 0x1F, 0x0A, 0x1F, 0x0C, 
+    0x1F, 0x12, 0x1F, 0x14, 0x1F, 0x1A, 0x1F, 0x1C, 0x1F, 0x22, 0x1F, 0x24, 0x1F, 0x2A, 0x1F, 0x2C, 
+    0x1F, 0x32, 0x1F, 0x33, 0x1F, 0x34, 0x1F, 0x35, 0x1F, 0x36, 0x1F, 0x3A, 0x1F, 0x3C, 0x1F, 0x42, 
+    0x1F, 0x44, 0x1F, 0x4A, 0x1F, 0x4C, 0x1F, 0x52, 0x1F, 0x54, 0x1F, 0x62, 0x1F, 0x64, 0x1F, 0x6A, 
+    0x1F, 0x6B, 0x1F, 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x80, 0x1F, 0x82, 0x1F, 0x83, 0x1F, 0x84, 
+    0x1F, 0x85, 0x1F, 0x86, 0x1F, 0x87, 0x1F, 0x88, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, 0x8C, 0x1F, 0x8D, 
+    0x1F, 0x8E, 0x1F, 0x8F, 0x1F, 0x90, 0x1F, 0x92, 0x1F, 0x93, 0x1F, 0x94, 0x1F, 0x95, 0x1F, 0x96, 
+    0x1F, 0x97, 0x1F, 0x98, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 
+    0x1F, 0xA0, 0x1F, 0xA2, 0x1F, 0xA3, 0x1F, 0xA4, 0x1F, 0xA5, 0x1F, 0xA6, 0x1F, 0xA7, 0x1F, 0xA8, 
+    0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, 0xB2, 
+    0x1F, 0xB4, 0x1F, 0xC2, 0x1F, 0xC4, 0x1F, 0xD2, 0x1F, 0xF2, 0x1F, 0xF4, 0x00, 0x01, 0x03, 0x3C, 
+    0x00, 0x51, 0x00, 0xA8, 0x00, 0xB0, 0x00, 0xB8, 0x00, 0xC0, 0x00, 0xC8, 0x00, 0xD0, 0x00, 0xD8, 
+    0x00, 0xE0, 0x00, 0xE8, 0x00, 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x08, 0x01, 0x10, 0x01, 0x18, 
+    0x01, 0x20, 0x01, 0x28, 0x01, 0x30, 0x01, 0x38, 0x01, 0x40, 0x01, 0x48, 0x01, 0x50, 0x01, 0x58, 
+    0x01, 0x60, 0x01, 0x68, 0x01, 0x70, 0x01, 0x78, 0x01, 0x80, 0x01, 0x88, 0x01, 0x90, 0x01, 0x98, 
+    0x01, 0xA0, 0x01, 0xA8, 0x01, 0xB0, 0x01, 0xB8, 0x01, 0xC0, 0x01, 0xC8, 0x01, 0xD0, 0x01, 0xDA, 
+    0x01, 0xE2, 0x01, 0xEA, 0x01, 0xF2, 0x01, 0xFA, 0x02, 0x02, 0x02, 0x0A, 0x02, 0x14, 0x02, 0x1C, 
+    0x02, 0x24, 0x02, 0x2C, 0x02, 0x34, 0x02, 0x3C, 0x02, 0x44, 0x02, 0x4E, 0x02, 0x56, 0x02, 0x5E, 
+    0x02, 0x66, 0x02, 0x6E, 0x02, 0x76, 0x02, 0x7E, 0x02, 0x88, 0x02, 0x90, 0x02, 0x98, 0x02, 0xA0, 
+    0x02, 0xA8, 0x02, 0xB0, 0x02, 0xB8, 0x02, 0xC2, 0x02, 0xCA, 0x02, 0xD2, 0x02, 0xDA, 0x02, 0xE2, 
+    0x02, 0xEA, 0x02, 0xF2, 0x02, 0xFA, 0x03, 0x04, 0x03, 0x0C, 0x03, 0x14, 0x03, 0x1C, 0x03, 0x24, 
+    0x03, 0x2C, 0x03, 0x34, 0x00, 0x03, 0x03, 0xB9, 0x03, 0x08, 0x03, 0x41, 0x00, 0x03, 0x03, 0xB1, 
+    0x03, 0x43, 0x03, 0x40, 0x00, 0x03, 0x03, 0xB1, 0x03, 0x43, 0x03, 0x41, 0x00, 0x03, 0x03, 0x91, 
+    0x03, 0x43, 0x03, 0x40, 0x00, 0x03, 0x03, 0x91, 0x03, 0x43, 0x03, 0x41, 0x00, 0x03, 0x03, 0xB5, 
+    0x03, 0x43, 0x03, 0x40, 0x00, 0x03, 0x03, 0xB5, 0x03, 0x43, 0x03, 0x41, 0x00, 0x03, 0x03, 0x95, 
+    0x03, 0x43, 0x03, 0x40, 0x00, 0x03, 0x03, 0x95, 0x03, 0x43, 0x03, 0x41, 0x00, 0x03, 0x03, 0xB7, 
+    0x03, 0x43, 0x03, 0x40, 0x00, 0x03, 0x03, 0xB7, 0x03, 0x43, 0x03, 0x41, 0x00, 0x03, 0x03, 0x97, 
+    0x03, 0x43, 0x03, 0x40, 0x00, 0x03, 0x03, 0x97, 0x03, 0x43, 0x03, 0x41, 0x00, 0x03, 0x03, 0xB9, 
+    0x03, 0x43, 0x03, 0x40, 0x00, 0x03, 0x1F, 0xBE, 0x03, 0x14, 0x03, 0x40, 0x00, 0x03, 0x03, 0xB9, 
+    0x03, 0x43, 0x03, 0x41, 0x00, 0x03, 0x1F, 0xBE, 0x03, 0x14, 0x03, 0x41, 0x00, 0x03, 0x03, 0x99, 
+    0x03, 0x43, 0x03, 0x40, 0x00, 0x03, 0x03, 0x99, 0x03, 0x43, 0x03, 0x41, 0x00, 0x03, 0x03, 0xBF, 
+    0x03, 0x43, 0x03, 0x40, 0x00, 0x03, 0x03, 0xBF, 0x03, 0x43, 0x03, 0x41, 0x00, 0x03, 0x03, 0x9F, 
+    0x03, 0x43, 0x03, 0x40, 0x00, 0x03, 0x03, 0x9F, 0x03, 0x43, 0x03, 0x41, 0x00, 0x03, 0x03, 0xC5, 
+    0x03, 0x43, 0x03, 0x40, 0x00, 0x03, 0x03, 0xC5, 0x03, 0x43, 0x03, 0x41, 0x00, 0x03, 0x03, 0xC9, 
+    0x03, 0x43, 0x03, 0x40, 0x00, 0x03, 0x03, 0xC9, 0x03, 0x43, 0x03, 0x41, 0x00, 0x03, 0x03, 0xA9, 
+    0x03, 0x43, 0x03, 0x40, 0x00, 0x03, 0x21, 0x26, 0x03, 0x14, 0x03, 0x40, 0x00, 0x03, 0x03, 0xA9, 
+    0x03, 0x43, 0x03, 0x41, 0x00, 0x03, 0x21, 0x26, 0x03, 0x14, 0x03, 0x41, 0x00, 0x03, 0x03, 0xB1, 
+    0x03, 0x45, 0x03, 0x13, 0x00, 0x03, 0x1F, 0x00, 0x03, 0x45, 0x03, 0x00, 0x00, 0x03, 0x1F, 0x01, 
+    0x03, 0x45, 0x03, 0x00, 0x00, 0x03, 0x1F, 0x00, 0x03, 0x45, 0x03, 0x01, 0x00, 0x03, 0x1F, 0x01, 
+    0x03, 0x45, 0x03, 0x01, 0x00, 0x03, 0x1F, 0xB3, 0x03, 0x43, 0x03, 0x42, 0x00, 0x04, 0x03, 0xB1, 
+    0x03, 0x14, 0x03, 0x42, 0x03, 0x45, 0x00, 0x03, 0x03, 0x91, 0x03, 0x45, 0x03, 0x13, 0x00, 0x03, 
+    0x1F, 0x08, 0x03, 0x45, 0x03, 0x00, 0x00, 0x03, 0x1F, 0x09, 0x03, 0x45, 0x03, 0x00, 0x00, 0x03, 
+    0x1F, 0x08, 0x03, 0x45, 0x03, 0x01, 0x00, 0x03, 0x1F, 0x09, 0x03, 0x45, 0x03, 0x01, 0x00, 0x03, 
+    0x1F, 0xBC, 0x03, 0x43, 0x03, 0x42, 0x00, 0x04, 0x03, 0x91, 0x03, 0x14, 0x03, 0x42, 0x03, 0x45, 
+    0x00, 0x03, 0x03, 0xB7, 0x03, 0x45, 0x03, 0x13, 0x00, 0x03, 0x1F, 0x20, 0x03, 0x45, 0x03, 0x00, 
+    0x00, 0x03, 0x1F, 0x21, 0x03, 0x45, 0x03, 0x00, 0x00, 0x03, 0x1F, 0x20, 0x03, 0x45, 0x03, 0x01, 
+    0x00, 0x03, 0x1F, 0x21, 0x03, 0x45, 0x03, 0x01, 0x00, 0x03, 0x1F, 0xC3, 0x03, 0x43, 0x03, 0x42, 
+    0x00, 0x04, 0x03, 0xB7, 0x03, 0x14, 0x03, 0x42, 0x03, 0x45, 0x00, 0x03, 0x03, 0x97, 0x03, 0x45, 
+    0x03, 0x13, 0x00, 0x03, 0x1F, 0x28, 0x03, 0x45, 0x03, 0x00, 0x00, 0x03, 0x1F, 0x29, 0x03, 0x45, 
+    0x03, 0x00, 0x00, 0x03, 0x1F, 0x28, 0x03, 0x45, 0x03, 0x01, 0x00, 0x03, 0x1F, 0x29, 0x03, 0x45, 
+    0x03, 0x01, 0x00, 0x03, 0x1F, 0xCC, 0x03, 0x43, 0x03, 0x42, 0x00, 0x04, 0x03, 0x97, 0x03, 0x14, 
+    0x03, 0x42, 0x03, 0x45, 0x00, 0x03, 0x03, 0xC9, 0x03, 0x45, 0x03, 0x13, 0x00, 0x03, 0x1F, 0x60, 
+    0x03, 0x45, 0x03, 0x00, 0x00, 0x03, 0x1F, 0x61, 0x03, 0x45, 0x03, 0x00, 0x00, 0x03, 0x1F, 0x60, 
+    0x03, 0x45, 0x03, 0x01, 0x00, 0x03, 0x1F, 0x61, 0x03, 0x45, 0x03, 0x01, 0x00, 0x03, 0x1F, 0xF3, 
+    0x03, 0x43, 0x03, 0x42, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x14, 0x03, 0x42, 0x03, 0x45, 0x00, 0x03, 
+    0x03, 0xA9, 0x03, 0x45, 0x03, 0x13, 0x00, 0x03, 0x21, 0x26, 0x03, 0x45, 0x03, 0x14, 0x00, 0x03, 
+    0x1F, 0x68, 0x03, 0x45, 0x03, 0x00, 0x00, 0x03, 0x1F, 0x69, 0x03, 0x45, 0x03, 0x00, 0x00, 0x03, 
+    0x1F, 0x68, 0x03, 0x45, 0x03, 0x01, 0x00, 0x03, 0x1F, 0x69, 0x03, 0x45, 0x03, 0x01, 0x00, 0x03, 
+    0x1F, 0xFC, 0x03, 0x43, 0x03, 0x42, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x14, 0x03, 0x42, 0x03, 0x45, 
+    0x00, 0x03, 0x03, 0xB1, 0x03, 0x45, 0x03, 0x00, 0x00, 0x03, 0x03, 0xB1, 0x03, 0x41, 0x03, 0x45, 
+    0x00, 0x03, 0x03, 0xB7, 0x03, 0x45, 0x03, 0x00, 0x00, 0x03, 0x03, 0xB7, 0x03, 0x41, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0xBE, 0x03, 0x08, 0x03, 0x40, 0x00, 0x03, 0x03, 0xC9, 0x03, 0x45, 0x03, 0x00, 
+    0x00, 0x03, 0x03, 0xC9, 0x03, 0x41, 0x03, 0x45, 0x00, 0x01, 0x00, 0x51, 0x03, 0x90, 0x1F, 0x02, 
+    0x1F, 0x04, 0x1F, 0x0A, 0x1F, 0x0C, 0x1F, 0x12, 0x1F, 0x14, 0x1F, 0x1A, 0x1F, 0x1C, 0x1F, 0x22, 
+    0x1F, 0x24, 0x1F, 0x2A, 0x1F, 0x2C, 0x1F, 0x32, 0x1F, 0x33, 0x1F, 0x34, 0x1F, 0x35, 0x1F, 0x3A, 
+    0x1F, 0x3C, 0x1F, 0x42, 0x1F, 0x44, 0x1F, 0x4A, 0x1F, 0x4C, 0x1F, 0x52, 0x1F, 0x54, 0x1F, 0x62, 
+    0x1F, 0x64, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F, 0x6C, 0x1F, 0x6D, 0x1F, 0x80, 0x1F, 0x82, 0x1F, 0x83, 
+    0x1F, 0x84, 0x1F, 0x85, 0x1F, 0x86, 0x1F, 0x87, 0x1F, 0x88, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, 0x8C, 
+    0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, 0x90, 0x1F, 0x92, 0x1F, 0x93, 0x1F, 0x94, 0x1F, 0x95, 
+    0x1F, 0x96, 0x1F, 0x97, 0x1F, 0x98, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 
+    0x1F, 0x9F, 0x1F, 0xA0, 0x1F, 0xA2, 0x1F, 0xA3, 0x1F, 0xA4, 0x1F, 0xA5, 0x1F, 0xA6, 0x1F, 0xA7, 
+    0x1F, 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 
+    0x1F, 0xB2, 0x1F, 0xB4, 0x1F, 0xC2, 0x1F, 0xC4, 0x1F, 0xD2, 0x1F, 0xF2, 0x1F, 0xF4, 0x00, 0x01, 
+    0x02, 0x30, 0x00, 0x35, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 0x00, 0x98, 
+    0x00, 0xA0, 0x00, 0xA8, 0x00, 0xB0, 0x00, 0xB8, 0x00, 0xC0, 0x00, 0xCA, 0x00, 0xD4, 0x00, 0xDC, 
+    0x00, 0xE4, 0x00, 0xEC, 0x00, 0xF4, 0x00, 0xFC, 0x01, 0x06, 0x01, 0x10, 0x01, 0x18, 0x01, 0x20, 
+    0x01, 0x28, 0x01, 0x30, 0x01, 0x38, 0x01, 0x42, 0x01, 0x4C, 0x01, 0x54, 0x01, 0x5C, 0x01, 0x64, 
+    0x01, 0x6C, 0x01, 0x74, 0x01, 0x7E, 0x01, 0x88, 0x01, 0x90, 0x01, 0x98, 0x01, 0xA0, 0x01, 0xA8, 
+    0x01, 0xB0, 0x01, 0xBA, 0x01, 0xC4, 0x01, 0xCC, 0x01, 0xD4, 0x01, 0xDC, 0x01, 0xE4, 0x01, 0xEC, 
+    0x01, 0xF6, 0x02, 0x00, 0x02, 0x08, 0x02, 0x10, 0x02, 0x18, 0x02, 0x20, 0x02, 0x28, 0x00, 0x03, 
+    0x1F, 0xBE, 0x03, 0x08, 0x03, 0x01, 0x00, 0x03, 0x1F, 0xBE, 0x03, 0x13, 0x03, 0x00, 0x00, 0x03, 
+    0x1F, 0xBE, 0x03, 0x13, 0x03, 0x01, 0x00, 0x03, 0x21, 0x26, 0x03, 0x13, 0x03, 0x00, 0x00, 0x03, 
+    0x21, 0x26, 0x03, 0x13, 0x03, 0x01, 0x00, 0x03, 0x03, 0xB1, 0x03, 0x45, 0x03, 0x43, 0x00, 0x03, 
+    0x1F, 0x00, 0x03, 0x45, 0x03, 0x40, 0x00, 0x03, 0x1F, 0x01, 0x03, 0x45, 0x03, 0x40, 0x00, 0x03, 
+    0x1F, 0x00, 0x03, 0x45, 0x03, 0x41, 0x00, 0x03, 0x1F, 0x01, 0x03, 0x45, 0x03, 0x41, 0x00, 0x04, 
+    0x03, 0xB1, 0x03, 0x13, 0x03, 0x42, 0x03, 0x45, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x14, 0x03, 0x45, 
+    0x03, 0x42, 0x00, 0x03, 0x03, 0x91, 0x03, 0x45, 0x03, 0x43, 0x00, 0x03, 0x1F, 0x08, 0x03, 0x45, 
+    0x03, 0x40, 0x00, 0x03, 0x1F, 0x09, 0x03, 0x45, 0x03, 0x40, 0x00, 0x03, 0x1F, 0x08, 0x03, 0x45, 
+    0x03, 0x41, 0x00, 0x03, 0x1F, 0x09, 0x03, 0x45, 0x03, 0x41, 0x00, 0x04, 0x03, 0x91, 0x03, 0x13, 
+    0x03, 0x42, 0x03, 0x45, 0x00, 0x04, 0x03, 0x91, 0x03, 0x14, 0x03, 0x45, 0x03, 0x42, 0x00, 0x03, 
+    0x03, 0xB7, 0x03, 0x45, 0x03, 0x43, 0x00, 0x03, 0x1F, 0x20, 0x03, 0x45, 0x03, 0x40, 0x00, 0x03, 
+    0x1F, 0x21, 0x03, 0x45, 0x03, 0x40, 0x00, 0x03, 0x1F, 0x20, 0x03, 0x45, 0x03, 0x41, 0x00, 0x03, 
+    0x1F, 0x21, 0x03, 0x45, 0x03, 0x41, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x13, 0x03, 0x42, 0x03, 0x45, 
+    0x00, 0x04, 0x03, 0xB7, 0x03, 0x14, 0x03, 0x45, 0x03, 0x42, 0x00, 0x03, 0x03, 0x97, 0x03, 0x45, 
+    0x03, 0x43, 0x00, 0x03, 0x1F, 0x28, 0x03, 0x45, 0x03, 0x40, 0x00, 0x03, 0x1F, 0x29, 0x03, 0x45, 
+    0x03, 0x40, 0x00, 0x03, 0x1F, 0x28, 0x03, 0x45, 0x03, 0x41, 0x00, 0x03, 0x1F, 0x29, 0x03, 0x45, 
+    0x03, 0x41, 0x00, 0x04, 0x03, 0x97, 0x03, 0x13, 0x03, 0x42, 0x03, 0x45, 0x00, 0x04, 0x03, 0x97, 
+    0x03, 0x14, 0x03, 0x45, 0x03, 0x42, 0x00, 0x03, 0x03, 0xC9, 0x03, 0x45, 0x03, 0x43, 0x00, 0x03, 
+    0x1F, 0x60, 0x03, 0x45, 0x03, 0x40, 0x00, 0x03, 0x1F, 0x61, 0x03, 0x45, 0x03, 0x40, 0x00, 0x03, 
+    0x1F, 0x60, 0x03, 0x45, 0x03, 0x41, 0x00, 0x03, 0x1F, 0x61, 0x03, 0x45, 0x03, 0x41, 0x00, 0x04, 
+    0x03, 0xC9, 0x03, 0x13, 0x03, 0x42, 0x03, 0x45, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x14, 0x03, 0x45, 
+    0x03, 0x42, 0x00, 0x03, 0x03, 0xA9, 0x03, 0x45, 0x03, 0x43, 0x00, 0x03, 0x1F, 0x68, 0x03, 0x45, 
+    0x03, 0x40, 0x00, 0x03, 0x1F, 0x69, 0x03, 0x45, 0x03, 0x40, 0x00, 0x03, 0x1F, 0x68, 0x03, 0x45, 
+    0x03, 0x41, 0x00, 0x03, 0x1F, 0x69, 0x03, 0x45, 0x03, 0x41, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x13, 
+    0x03, 0x42, 0x03, 0x45, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x14, 0x03, 0x45, 0x03, 0x42, 0x00, 0x03, 
+    0x03, 0xB1, 0x03, 0x45, 0x03, 0x40, 0x00, 0x03, 0x03, 0xB1, 0x03, 0x45, 0x03, 0x01, 0x00, 0x03, 
+    0x03, 0xB7, 0x03, 0x45, 0x03, 0x40, 0x00, 0x03, 0x03, 0xB7, 0x03, 0x45, 0x03, 0x01, 0x00, 0x03, 
+    0x03, 0xC9, 0x03, 0x45, 0x03, 0x40, 0x00, 0x03, 0x03, 0xC9, 0x03, 0x45, 0x03, 0x01, 0x00, 0x01, 
+    0x00, 0x35, 0x03, 0x90, 0x1F, 0x32, 0x1F, 0x34, 0x1F, 0x6A, 0x1F, 0x6C, 0x1F, 0x80, 0x1F, 0x82, 
+    0x1F, 0x83, 0x1F, 0x84, 0x1F, 0x85, 0x1F, 0x86, 0x1F, 0x87, 0x1F, 0x88, 0x1F, 0x8A, 0x1F, 0x8B, 
+    0x1F, 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, 0x90, 0x1F, 0x92, 0x1F, 0x93, 0x1F, 0x94, 
+    0x1F, 0x95, 0x1F, 0x96, 0x1F, 0x97, 0x1F, 0x98, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, 0x9C, 0x1F, 0x9D, 
+    0x1F, 0x9E, 0x1F, 0x9F, 0x1F, 0xA0, 0x1F, 0xA2, 0x1F, 0xA3, 0x1F, 0xA4, 0x1F, 0xA5, 0x1F, 0xA6, 
+    0x1F, 0xA7, 0x1F, 0xA8, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 
+    0x1F, 0xB2, 0x1F, 0xB4, 0x1F, 0xC2, 0x1F, 0xC4, 0x1F, 0xF2, 0x1F, 0xF4, 0x00, 0x01, 0x01, 0xE0, 
+    0x00, 0x2D, 0x00, 0x60, 0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 
+    0x00, 0x98, 0x00, 0xA0, 0x00, 0xA8, 0x00, 0xB2, 0x00, 0xBC, 0x00, 0xC4, 0x00, 0xCC, 0x00, 0xD4, 
+    0x00, 0xDC, 0x00, 0xE6, 0x00, 0xF0, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x08, 0x01, 0x10, 0x01, 0x1A, 
+    0x01, 0x24, 0x01, 0x2C, 0x01, 0x34, 0x01, 0x3C, 0x01, 0x44, 0x01, 0x4E, 0x01, 0x58, 0x01, 0x60, 
+    0x01, 0x68, 0x01, 0x70, 0x01, 0x78, 0x01, 0x82, 0x01, 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA4, 
+    0x01, 0xAC, 0x01, 0xB4, 0x01, 0xBE, 0x01, 0xC8, 0x01, 0xD0, 0x01, 0xD8, 0x00, 0x03, 0x1F, 0xBE, 
+    0x03, 0x08, 0x03, 0x41, 0x00, 0x03, 0x1F, 0xBE, 0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x1F, 0xBE, 
+    0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x21, 0x26, 0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x21, 0x26, 
+    0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x1F, 0xB3, 0x03, 0x13, 0x03, 0x00, 0x00, 0x03, 0x1F, 0xB3, 
+    0x03, 0x14, 0x03, 0x00, 0x00, 0x03, 0x1F, 0xB3, 0x03, 0x13, 0x03, 0x01, 0x00, 0x03, 0x1F, 0xB3, 
+    0x03, 0x14, 0x03, 0x01, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x13, 0x03, 0x45, 0x03, 0x42, 0x00, 0x04, 
+    0x03, 0xB1, 0x03, 0x45, 0x03, 0x14, 0x03, 0x42, 0x00, 0x03, 0x1F, 0xBC, 0x03, 0x13, 0x03, 0x00, 
+    0x00, 0x03, 0x1F, 0xBC, 0x03, 0x14, 0x03, 0x00, 0x00, 0x03, 0x1F, 0xBC, 0x03, 0x13, 0x03, 0x01, 
+    0x00, 0x03, 0x1F, 0xBC, 0x03, 0x14, 0x03, 0x01, 0x00, 0x04, 0x03, 0x91, 0x03, 0x13, 0x03, 0x45, 
+    0x03, 0x42, 0x00, 0x04, 0x03, 0x91, 0x03, 0x45, 0x03, 0x14, 0x03, 0x42, 0x00, 0x03, 0x1F, 0xC3, 
+    0x03, 0x13, 0x03, 0x00, 0x00, 0x03, 0x1F, 0xC3, 0x03, 0x14, 0x03, 0x00, 0x00, 0x03, 0x1F, 0xC3, 
+    0x03, 0x13, 0x03, 0x01, 0x00, 0x03, 0x1F, 0xC3, 0x03, 0x14, 0x03, 0x01, 0x00, 0x04, 0x03, 0xB7, 
+    0x03, 0x13, 0x03, 0x45, 0x03, 0x42, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x45, 0x03, 0x14, 0x03, 0x42, 
+    0x00, 0x03, 0x1F, 0xCC, 0x03, 0x13, 0x03, 0x00, 0x00, 0x03, 0x1F, 0xCC, 0x03, 0x14, 0x03, 0x00, 
+    0x00, 0x03, 0x1F, 0xCC, 0x03, 0x13, 0x03, 0x01, 0x00, 0x03, 0x1F, 0xCC, 0x03, 0x14, 0x03, 0x01, 
+    0x00, 0x04, 0x03, 0x97, 0x03, 0x13, 0x03, 0x45, 0x03, 0x42, 0x00, 0x04, 0x03, 0x97, 0x03, 0x45, 
+    0x03, 0x14, 0x03, 0x42, 0x00, 0x03, 0x1F, 0xF3, 0x03, 0x13, 0x03, 0x00, 0x00, 0x03, 0x1F, 0xF3, 
+    0x03, 0x14, 0x03, 0x00, 0x00, 0x03, 0x1F, 0xF3, 0x03, 0x13, 0x03, 0x01, 0x00, 0x03, 0x1F, 0xF3, 
+    0x03, 0x14, 0x03, 0x01, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x13, 0x03, 0x45, 0x03, 0x42, 0x00, 0x04, 
+    0x03, 0xC9, 0x03, 0x45, 0x03, 0x14, 0x03, 0x42, 0x00, 0x03, 0x21, 0x26, 0x03, 0x13, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0xFC, 0x03, 0x13, 0x03, 0x00, 0x00, 0x03, 0x1F, 0xFC, 0x03, 0x14, 0x03, 0x00, 
+    0x00, 0x03, 0x1F, 0xFC, 0x03, 0x13, 0x03, 0x01, 0x00, 0x03, 0x1F, 0xFC, 0x03, 0x14, 0x03, 0x01, 
+    0x00, 0x04, 0x03, 0xA9, 0x03, 0x13, 0x03, 0x45, 0x03, 0x42, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x45, 
+    0x03, 0x14, 0x03, 0x42, 0x00, 0x03, 0x03, 0xB1, 0x03, 0x45, 0x03, 0x41, 0x00, 0x03, 0x03, 0xB7, 
+    0x03, 0x45, 0x03, 0x41, 0x00, 0x03, 0x03, 0xC9, 0x03, 0x45, 0x03, 0x41, 0x00, 0x01, 0x00, 0x2D, 
+    0x03, 0x90, 0x1F, 0x32, 0x1F, 0x34, 0x1F, 0x6A, 0x1F, 0x6C, 0x1F, 0x82, 0x1F, 0x83, 0x1F, 0x84, 
+    0x1F, 0x85, 0x1F, 0x86, 0x1F, 0x87, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 
+    0x1F, 0x8F, 0x1F, 0x92, 0x1F, 0x93, 0x1F, 0x94, 0x1F, 0x95, 0x1F, 0x96, 0x1F, 0x97, 0x1F, 0x9A, 
+    0x1F, 0x9B, 0x1F, 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, 0xA2, 0x1F, 0xA3, 0x1F, 0xA4, 
+    0x1F, 0xA5, 0x1F, 0xA6, 0x1F, 0xA7, 0x1F, 0xA8, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 
+    0x1F, 0xAE, 0x1F, 0xAF, 0x1F, 0xB4, 0x1F, 0xC4, 0x1F, 0xF4, 0x00, 0x01, 0x01, 0x7C, 0x00, 0x24, 
+    0x00, 0x4E, 0x00, 0x56, 0x00, 0x5E, 0x00, 0x66, 0x00, 0x6E, 0x00, 0x76, 0x00, 0x7E, 0x00, 0x86, 
+    0x00, 0x8E, 0x00, 0x98, 0x00, 0xA0, 0x00, 0xA8, 0x00, 0xB0, 0x00, 0xB8, 0x00, 0xC2, 0x00, 0xCA, 
+    0x00, 0xD2, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xEC, 0x00, 0xF4, 0x00, 0xFC, 0x01, 0x04, 0x01, 0x0C, 
+    0x01, 0x16, 0x01, 0x1E, 0x01, 0x26, 0x01, 0x2E, 0x01, 0x36, 0x01, 0x40, 0x01, 0x48, 0x01, 0x50, 
+    0x01, 0x58, 0x01, 0x60, 0x01, 0x68, 0x01, 0x72, 0x00, 0x03, 0x1F, 0xBE, 0x03, 0x43, 0x03, 0x00, 
+    0x00, 0x03, 0x1F, 0xBE, 0x03, 0x43, 0x03, 0x01, 0x00, 0x03, 0x21, 0x26, 0x03, 0x43, 0x03, 0x00, 
+    0x00, 0x03, 0x21, 0x26, 0x03, 0x43, 0x03, 0x01, 0x00, 0x03, 0x1F, 0xB3, 0x03, 0x13, 0x03, 0x40, 
+    0x00, 0x03, 0x1F, 0xB3, 0x03, 0x14, 0x03, 0x40, 0x00, 0x03, 0x1F, 0xB3, 0x03, 0x13, 0x03, 0x41, 
+    0x00, 0x03, 0x1F, 0xB3, 0x03, 0x14, 0x03, 0x41, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x43, 0x03, 0x42, 
+    0x03, 0x45, 0x00, 0x03, 0x1F, 0xBC, 0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x1F, 0xBC, 0x03, 0x14, 
+    0x03, 0x40, 0x00, 0x03, 0x1F, 0xBC, 0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x1F, 0xBC, 0x03, 0x14, 
+    0x03, 0x41, 0x00, 0x04, 0x03, 0x91, 0x03, 0x43, 0x03, 0x42, 0x03, 0x45, 0x00, 0x03, 0x1F, 0xC3, 
+    0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x1F, 0xC3, 0x03, 0x14, 0x03, 0x40, 0x00, 0x03, 0x1F, 0xC3, 
+    0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x1F, 0xC3, 0x03, 0x14, 0x03, 0x41, 0x00, 0x04, 0x03, 0xB7, 
+    0x03, 0x43, 0x03, 0x42, 0x03, 0x45, 0x00, 0x03, 0x1F, 0xCC, 0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 
+    0x1F, 0xCC, 0x03, 0x14, 0x03, 0x40, 0x00, 0x03, 0x1F, 0xCC, 0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 
+    0x1F, 0xCC, 0x03, 0x14, 0x03, 0x41, 0x00, 0x04, 0x03, 0x97, 0x03, 0x43, 0x03, 0x42, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0xF3, 0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x1F, 0xF3, 0x03, 0x14, 0x03, 0x40, 
+    0x00, 0x03, 0x1F, 0xF3, 0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x1F, 0xF3, 0x03, 0x14, 0x03, 0x41, 
+    0x00, 0x04, 0x03, 0xC9, 0x03, 0x43, 0x03, 0x42, 0x03, 0x45, 0x00, 0x03, 0x21, 0x26, 0x03, 0x43, 
+    0x03, 0x45, 0x00, 0x03, 0x1F, 0xFC, 0x03, 0x13, 0x03, 0x40, 0x00, 0x03, 0x1F, 0xFC, 0x03, 0x14, 
+    0x03, 0x40, 0x00, 0x03, 0x1F, 0xFC, 0x03, 0x13, 0x03, 0x41, 0x00, 0x03, 0x1F, 0xFC, 0x03, 0x14, 
+    0x03, 0x41, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x43, 0x03, 0x42, 0x03, 0x45, 0x00, 0x04, 0x21, 0x26, 
+    0x03, 0x14, 0x03, 0x42, 0x03, 0x45, 0x00, 0x01, 0x00, 0x24, 0x1F, 0x32, 0x1F, 0x34, 0x1F, 0x6A, 
+    0x1F, 0x6C, 0x1F, 0x82, 0x1F, 0x83, 0x1F, 0x84, 0x1F, 0x85, 0x1F, 0x86, 0x1F, 0x8A, 0x1F, 0x8B, 
+    0x1F, 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x92, 0x1F, 0x93, 0x1F, 0x94, 0x1F, 0x95, 0x1F, 0x96, 
+    0x1F, 0x9A, 0x1F, 0x9B, 0x1F, 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0xA2, 0x1F, 0xA3, 0x1F, 0xA4, 
+    0x1F, 0xA5, 0x1F, 0xA6, 0x1F, 0xA8, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 
+    0x1F, 0xAF, 0x00, 0x01, 0x01, 0x94, 0x00, 0x24, 0x00, 0x4E, 0x00, 0x56, 0x00, 0x5E, 0x00, 0x66, 
+    0x00, 0x6E, 0x00, 0x76, 0x00, 0x80, 0x00, 0x88, 0x00, 0x92, 0x00, 0x9C, 0x00, 0xA4, 0x00, 0xAE, 
+    0x00, 0xB6, 0x00, 0xC0, 0x00, 0xCA, 0x00, 0xD2, 0x00, 0xDC, 0x00, 0xE4, 0x00, 0xEE, 0x00, 0xF8, 
+    0x01, 0x00, 0x01, 0x0A, 0x01, 0x12, 0x01, 0x1C, 0x01, 0x26, 0x01, 0x2E, 0x01, 0x38, 0x01, 0x40, 
+    0x01, 0x4A, 0x01, 0x54, 0x01, 0x5C, 0x01, 0x64, 0x01, 0x6E, 0x01, 0x76, 0x01, 0x80, 0x01, 0x8A, 
+    0x00, 0x03, 0x1F, 0xBE, 0x03, 0x43, 0x03, 0x40, 0x00, 0x03, 0x1F, 0xBE, 0x03, 0x43, 0x03, 0x41, 
+    0x00, 0x03, 0x21, 0x26, 0x03, 0x43, 0x03, 0x40, 0x00, 0x03, 0x21, 0x26, 0x03, 0x43, 0x03, 0x41, 
+    0x00, 0x03, 0x1F, 0xB3, 0x03, 0x43, 0x03, 0x00, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x14, 0x03, 0x00, 
+    0x03, 0x45, 0x00, 0x03, 0x1F, 0xB3, 0x03, 0x43, 0x03, 0x01, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x14, 
+    0x03, 0x01, 0x03, 0x45, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x43, 0x03, 0x45, 0x03, 0x42, 0x00, 0x03, 
+    0x1F, 0xBC, 0x03, 0x43, 0x03, 0x00, 0x00, 0x04, 0x03, 0x91, 0x03, 0x14, 0x03, 0x00, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0xBC, 0x03, 0x43, 0x03, 0x01, 0x00, 0x04, 0x03, 0x91, 0x03, 0x14, 0x03, 0x01, 
+    0x03, 0x45, 0x00, 0x04, 0x03, 0x91, 0x03, 0x43, 0x03, 0x45, 0x03, 0x42, 0x00, 0x03, 0x1F, 0xC3, 
+    0x03, 0x43, 0x03, 0x00, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x14, 0x03, 0x00, 0x03, 0x45, 0x00, 0x03, 
+    0x1F, 0xC3, 0x03, 0x43, 0x03, 0x01, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x14, 0x03, 0x01, 0x03, 0x45, 
+    0x00, 0x04, 0x03, 0xB7, 0x03, 0x43, 0x03, 0x45, 0x03, 0x42, 0x00, 0x03, 0x1F, 0xCC, 0x03, 0x43, 
+    0x03, 0x00, 0x00, 0x04, 0x03, 0x97, 0x03, 0x14, 0x03, 0x00, 0x03, 0x45, 0x00, 0x03, 0x1F, 0xCC, 
+    0x03, 0x43, 0x03, 0x01, 0x00, 0x04, 0x03, 0x97, 0x03, 0x14, 0x03, 0x01, 0x03, 0x45, 0x00, 0x04, 
+    0x03, 0x97, 0x03, 0x43, 0x03, 0x45, 0x03, 0x42, 0x00, 0x03, 0x1F, 0xF3, 0x03, 0x43, 0x03, 0x00, 
+    0x00, 0x04, 0x03, 0xC9, 0x03, 0x14, 0x03, 0x00, 0x03, 0x45, 0x00, 0x03, 0x1F, 0xF3, 0x03, 0x43, 
+    0x03, 0x01, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x14, 0x03, 0x01, 0x03, 0x45, 0x00, 0x04, 0x03, 0xC9, 
+    0x03, 0x43, 0x03, 0x45, 0x03, 0x42, 0x00, 0x03, 0x21, 0x26, 0x03, 0x45, 0x03, 0x13, 0x00, 0x03, 
+    0x1F, 0xFC, 0x03, 0x43, 0x03, 0x00, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x14, 0x03, 0x00, 0x03, 0x45, 
+    0x00, 0x03, 0x1F, 0xFC, 0x03, 0x43, 0x03, 0x01, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x14, 0x03, 0x01, 
+    0x03, 0x45, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x43, 0x03, 0x45, 0x03, 0x42, 0x00, 0x04, 0x21, 0x26, 
+    0x03, 0x14, 0x03, 0x45, 0x03, 0x42, 0x00, 0x01, 0x00, 0x24, 0x1F, 0x32, 0x1F, 0x34, 0x1F, 0x6A, 
+    0x1F, 0x6C, 0x1F, 0x82, 0x1F, 0x83, 0x1F, 0x84, 0x1F, 0x85, 0x1F, 0x86, 0x1F, 0x8A, 0x1F, 0x8B, 
+    0x1F, 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x92, 0x1F, 0x93, 0x1F, 0x94, 0x1F, 0x95, 0x1F, 0x96, 
+    0x1F, 0x9A, 0x1F, 0x9B, 0x1F, 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0xA2, 0x1F, 0xA3, 0x1F, 0xA4, 
+    0x1F, 0xA5, 0x1F, 0xA6, 0x1F, 0xA8, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 
+    0x1F, 0xAF, 0x00, 0x01, 0x01, 0x6C, 0x00, 0x20, 0x00, 0x46, 0x00, 0x4E, 0x00, 0x58, 0x00, 0x60, 
+    0x00, 0x6A, 0x00, 0x74, 0x00, 0x7C, 0x00, 0x86, 0x00, 0x8E, 0x00, 0x98, 0x00, 0xA2, 0x00, 0xAA, 
+    0x00, 0xB4, 0x00, 0xBC, 0x00, 0xC6, 0x00, 0xD0, 0x00, 0xD8, 0x00, 0xE2, 0x00, 0xEA, 0x00, 0xF4, 
+    0x00, 0xFE, 0x01, 0x06, 0x01, 0x10, 0x01, 0x18, 0x01, 0x22, 0x01, 0x2C, 0x01, 0x34, 0x01, 0x3C, 
+    0x01, 0x46, 0x01, 0x4E, 0x01, 0x58, 0x01, 0x62, 0x00, 0x03, 0x1F, 0xB3, 0x03, 0x43, 0x03, 0x40, 
+    0x00, 0x04, 0x03, 0xB1, 0x03, 0x14, 0x03, 0x40, 0x03, 0x45, 0x00, 0x03, 0x1F, 0xB3, 0x03, 0x43, 
+    0x03, 0x41, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x14, 0x03, 0x41, 0x03, 0x45, 0x00, 0x04, 0x03, 0xB1, 
+    0x03, 0x45, 0x03, 0x13, 0x03, 0x42, 0x00, 0x03, 0x1F, 0xBC, 0x03, 0x43, 0x03, 0x40, 0x00, 0x04, 
+    0x03, 0x91, 0x03, 0x14, 0x03, 0x40, 0x03, 0x45, 0x00, 0x03, 0x1F, 0xBC, 0x03, 0x43, 0x03, 0x41, 
+    0x00, 0x04, 0x03, 0x91, 0x03, 0x14, 0x03, 0x41, 0x03, 0x45, 0x00, 0x04, 0x03, 0x91, 0x03, 0x45, 
+    0x03, 0x13, 0x03, 0x42, 0x00, 0x03, 0x1F, 0xC3, 0x03, 0x43, 0x03, 0x40, 0x00, 0x04, 0x03, 0xB7, 
+    0x03, 0x14, 0x03, 0x40, 0x03, 0x45, 0x00, 0x03, 0x1F, 0xC3, 0x03, 0x43, 0x03, 0x41, 0x00, 0x04, 
+    0x03, 0xB7, 0x03, 0x14, 0x03, 0x41, 0x03, 0x45, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x45, 0x03, 0x13, 
+    0x03, 0x42, 0x00, 0x03, 0x1F, 0xCC, 0x03, 0x43, 0x03, 0x40, 0x00, 0x04, 0x03, 0x97, 0x03, 0x14, 
+    0x03, 0x40, 0x03, 0x45, 0x00, 0x03, 0x1F, 0xCC, 0x03, 0x43, 0x03, 0x41, 0x00, 0x04, 0x03, 0x97, 
+    0x03, 0x14, 0x03, 0x41, 0x03, 0x45, 0x00, 0x04, 0x03, 0x97, 0x03, 0x45, 0x03, 0x13, 0x03, 0x42, 
+    0x00, 0x03, 0x1F, 0xF3, 0x03, 0x43, 0x03, 0x40, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x14, 0x03, 0x40, 
+    0x03, 0x45, 0x00, 0x03, 0x1F, 0xF3, 0x03, 0x43, 0x03, 0x41, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x14, 
+    0x03, 0x41, 0x03, 0x45, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x45, 0x03, 0x13, 0x03, 0x42, 0x00, 0x03, 
+    0x21, 0x26, 0x03, 0x45, 0x03, 0x43, 0x00, 0x03, 0x1F, 0xFC, 0x03, 0x43, 0x03, 0x40, 0x00, 0x04, 
+    0x03, 0xA9, 0x03, 0x14, 0x03, 0x40, 0x03, 0x45, 0x00, 0x03, 0x1F, 0xFC, 0x03, 0x43, 0x03, 0x41, 
+    0x00, 0x04, 0x03, 0xA9, 0x03, 0x14, 0x03, 0x41, 0x03, 0x45, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x45, 
+    0x03, 0x13, 0x03, 0x42, 0x00, 0x04, 0x21, 0x26, 0x03, 0x45, 0x03, 0x14, 0x03, 0x42, 0x00, 0x01, 
+    0x00, 0x20, 0x1F, 0x82, 0x1F, 0x83, 0x1F, 0x84, 0x1F, 0x85, 0x1F, 0x86, 0x1F, 0x8A, 0x1F, 0x8B, 
+    0x1F, 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x92, 0x1F, 0x93, 0x1F, 0x94, 0x1F, 0x95, 0x1F, 0x96, 
+    0x1F, 0x9A, 0x1F, 0x9B, 0x1F, 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0xA2, 0x1F, 0xA3, 0x1F, 0xA4, 
+    0x1F, 0xA5, 0x1F, 0xA6, 0x1F, 0xA8, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 
+    0x1F, 0xAF, 0x00, 0x01, 0x01, 0x6E, 0x00, 0x1E, 0x00, 0x42, 0x00, 0x4C, 0x00, 0x56, 0x00, 0x60, 
+    0x00, 0x6A, 0x00, 0x74, 0x00, 0x7E, 0x00, 0x88, 0x00, 0x92, 0x00, 0x9C, 0x00, 0xA6, 0x00, 0xB0, 
+    0x00, 0xBA, 0x00, 0xC4, 0x00, 0xCE, 0x00, 0xD8, 0x00, 0xE2, 0x00, 0xEC, 0x00, 0xF6, 0x01, 0x00, 
+    0x01, 0x0A, 0x01, 0x14, 0x01, 0x1E, 0x01, 0x28, 0x01, 0x32, 0x01, 0x3C, 0x01, 0x46, 0x01, 0x50, 
+    0x01, 0x5A, 0x01, 0x64, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x13, 0x03, 0x00, 0x03, 0x45, 0x00, 0x04, 
+    0x03, 0xB1, 0x03, 0x14, 0x03, 0x45, 0x03, 0x00, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x13, 0x03, 0x01, 
+    0x03, 0x45, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x14, 0x03, 0x45, 0x03, 0x01, 0x00, 0x04, 0x03, 0xB1, 
+    0x03, 0x45, 0x03, 0x43, 0x03, 0x42, 0x00, 0x04, 0x03, 0x91, 0x03, 0x13, 0x03, 0x00, 0x03, 0x45, 
+    0x00, 0x04, 0x03, 0x91, 0x03, 0x14, 0x03, 0x45, 0x03, 0x00, 0x00, 0x04, 0x03, 0x91, 0x03, 0x13, 
+    0x03, 0x01, 0x03, 0x45, 0x00, 0x04, 0x03, 0x91, 0x03, 0x14, 0x03, 0x45, 0x03, 0x01, 0x00, 0x04, 
+    0x03, 0x91, 0x03, 0x45, 0x03, 0x43, 0x03, 0x42, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x13, 0x03, 0x00, 
+    0x03, 0x45, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x14, 0x03, 0x45, 0x03, 0x00, 0x00, 0x04, 0x03, 0xB7, 
+    0x03, 0x13, 0x03, 0x01, 0x03, 0x45, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x14, 0x03, 0x45, 0x03, 0x01, 
+    0x00, 0x04, 0x03, 0xB7, 0x03, 0x45, 0x03, 0x43, 0x03, 0x42, 0x00, 0x04, 0x03, 0x97, 0x03, 0x13, 
+    0x03, 0x00, 0x03, 0x45, 0x00, 0x04, 0x03, 0x97, 0x03, 0x14, 0x03, 0x45, 0x03, 0x00, 0x00, 0x04, 
+    0x03, 0x97, 0x03, 0x13, 0x03, 0x01, 0x03, 0x45, 0x00, 0x04, 0x03, 0x97, 0x03, 0x14, 0x03, 0x45, 
+    0x03, 0x01, 0x00, 0x04, 0x03, 0x97, 0x03, 0x45, 0x03, 0x43, 0x03, 0x42, 0x00, 0x04, 0x03, 0xC9, 
+    0x03, 0x13, 0x03, 0x00, 0x03, 0x45, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x14, 0x03, 0x45, 0x03, 0x00, 
+    0x00, 0x04, 0x03, 0xC9, 0x03, 0x13, 0x03, 0x01, 0x03, 0x45, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x14, 
+    0x03, 0x45, 0x03, 0x01, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x45, 0x03, 0x43, 0x03, 0x42, 0x00, 0x04, 
+    0x03, 0xA9, 0x03, 0x13, 0x03, 0x00, 0x03, 0x45, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x14, 0x03, 0x45, 
+    0x03, 0x00, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x13, 0x03, 0x01, 0x03, 0x45, 0x00, 0x04, 0x03, 0xA9, 
+    0x03, 0x14, 0x03, 0x45, 0x03, 0x01, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x45, 0x03, 0x43, 0x03, 0x42, 
+    0x00, 0x01, 0x00, 0x1E, 0x1F, 0x82, 0x1F, 0x83, 0x1F, 0x84, 0x1F, 0x85, 0x1F, 0x86, 0x1F, 0x8A, 
+    0x1F, 0x8B, 0x1F, 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x92, 0x1F, 0x93, 0x1F, 0x94, 0x1F, 0x95, 
+    0x1F, 0x96, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0xA2, 0x1F, 0xA3, 
+    0x1F, 0xA4, 0x1F, 0xA5, 0x1F, 0xA6, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 
+    0x00, 0x01, 0x01, 0x32, 0x00, 0x19, 0x00, 0x38, 0x00, 0x42, 0x00, 0x4C, 0x00, 0x56, 0x00, 0x60, 
+    0x00, 0x6A, 0x00, 0x74, 0x00, 0x7E, 0x00, 0x88, 0x00, 0x92, 0x00, 0x9C, 0x00, 0xA6, 0x00, 0xB0, 
+    0x00, 0xBA, 0x00, 0xC4, 0x00, 0xCE, 0x00, 0xD8, 0x00, 0xE2, 0x00, 0xEC, 0x00, 0xF6, 0x01, 0x00, 
+    0x01, 0x0A, 0x01, 0x14, 0x01, 0x1E, 0x01, 0x28, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x13, 0x03, 0x40, 
+    0x03, 0x45, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x14, 0x03, 0x45, 0x03, 0x40, 0x00, 0x04, 0x03, 0xB1, 
+    0x03, 0x13, 0x03, 0x41, 0x03, 0x45, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x14, 0x03, 0x45, 0x03, 0x41, 
+    0x00, 0x04, 0x03, 0x91, 0x03, 0x13, 0x03, 0x40, 0x03, 0x45, 0x00, 0x04, 0x03, 0x91, 0x03, 0x14, 
+    0x03, 0x45, 0x03, 0x40, 0x00, 0x04, 0x03, 0x91, 0x03, 0x13, 0x03, 0x41, 0x03, 0x45, 0x00, 0x04, 
+    0x03, 0x91, 0x03, 0x14, 0x03, 0x45, 0x03, 0x41, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x13, 0x03, 0x40, 
+    0x03, 0x45, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x14, 0x03, 0x45, 0x03, 0x40, 0x00, 0x04, 0x03, 0xB7, 
+    0x03, 0x13, 0x03, 0x41, 0x03, 0x45, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x14, 0x03, 0x45, 0x03, 0x41, 
+    0x00, 0x04, 0x03, 0x97, 0x03, 0x13, 0x03, 0x40, 0x03, 0x45, 0x00, 0x04, 0x03, 0x97, 0x03, 0x14, 
+    0x03, 0x45, 0x03, 0x40, 0x00, 0x04, 0x03, 0x97, 0x03, 0x13, 0x03, 0x41, 0x03, 0x45, 0x00, 0x04, 
+    0x03, 0x97, 0x03, 0x14, 0x03, 0x45, 0x03, 0x41, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x13, 0x03, 0x40, 
+    0x03, 0x45, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x14, 0x03, 0x45, 0x03, 0x40, 0x00, 0x04, 0x03, 0xC9, 
+    0x03, 0x13, 0x03, 0x41, 0x03, 0x45, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x14, 0x03, 0x45, 0x03, 0x41, 
+    0x00, 0x04, 0x03, 0xA9, 0x03, 0x13, 0x03, 0x40, 0x03, 0x45, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x14, 
+    0x03, 0x45, 0x03, 0x40, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x13, 0x03, 0x41, 0x03, 0x45, 0x00, 0x04, 
+    0x03, 0xA9, 0x03, 0x14, 0x03, 0x45, 0x03, 0x41, 0x00, 0x04, 0x21, 0x26, 0x03, 0x13, 0x03, 0x42, 
+    0x03, 0x45, 0x00, 0x01, 0x00, 0x19, 0x1F, 0x82, 0x1F, 0x83, 0x1F, 0x84, 0x1F, 0x85, 0x1F, 0x8A, 
+    0x1F, 0x8B, 0x1F, 0x8C, 0x1F, 0x8D, 0x1F, 0x92, 0x1F, 0x93, 0x1F, 0x94, 0x1F, 0x95, 0x1F, 0x9A, 
+    0x1F, 0x9B, 0x1F, 0x9C, 0x1F, 0x9D, 0x1F, 0xA2, 0x1F, 0xA3, 0x1F, 0xA4, 0x1F, 0xA5, 0x1F, 0xAA, 
+    0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x00, 0x01, 0x01, 0x32, 0x00, 0x19, 0x00, 0x38, 
+    0x00, 0x42, 0x00, 0x4C, 0x00, 0x56, 0x00, 0x60, 0x00, 0x6A, 0x00, 0x74, 0x00, 0x7E, 0x00, 0x88, 
+    0x00, 0x92, 0x00, 0x9C, 0x00, 0xA6, 0x00, 0xB0, 0x00, 0xBA, 0x00, 0xC4, 0x00, 0xCE, 0x00, 0xD8, 
+    0x00, 0xE2, 0x00, 0xEC, 0x00, 0xF6, 0x01, 0x00, 0x01, 0x0A, 0x01, 0x14, 0x01, 0x1E, 0x01, 0x28, 
+    0x00, 0x04, 0x03, 0xB1, 0x03, 0x13, 0x03, 0x45, 0x03, 0x00, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x45, 
+    0x03, 0x14, 0x03, 0x00, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x13, 0x03, 0x45, 0x03, 0x01, 0x00, 0x04, 
+    0x03, 0xB1, 0x03, 0x45, 0x03, 0x14, 0x03, 0x01, 0x00, 0x04, 0x03, 0x91, 0x03, 0x13, 0x03, 0x45, 
+    0x03, 0x00, 0x00, 0x04, 0x03, 0x91, 0x03, 0x45, 0x03, 0x14, 0x03, 0x00, 0x00, 0x04, 0x03, 0x91, 
+    0x03, 0x13, 0x03, 0x45, 0x03, 0x01, 0x00, 0x04, 0x03, 0x91, 0x03, 0x45, 0x03, 0x14, 0x03, 0x01, 
+    0x00, 0x04, 0x03, 0xB7, 0x03, 0x13, 0x03, 0x45, 0x03, 0x00, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x45, 
+    0x03, 0x14, 0x03, 0x00, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x13, 0x03, 0x45, 0x03, 0x01, 0x00, 0x04, 
+    0x03, 0xB7, 0x03, 0x45, 0x03, 0x14, 0x03, 0x01, 0x00, 0x04, 0x03, 0x97, 0x03, 0x13, 0x03, 0x45, 
+    0x03, 0x00, 0x00, 0x04, 0x03, 0x97, 0x03, 0x45, 0x03, 0x14, 0x03, 0x00, 0x00, 0x04, 0x03, 0x97, 
+    0x03, 0x13, 0x03, 0x45, 0x03, 0x01, 0x00, 0x04, 0x03, 0x97, 0x03, 0x45, 0x03, 0x14, 0x03, 0x01, 
+    0x00, 0x04, 0x03, 0xC9, 0x03, 0x13, 0x03, 0x45, 0x03, 0x00, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x45, 
+    0x03, 0x14, 0x03, 0x00, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x13, 0x03, 0x45, 0x03, 0x01, 0x00, 0x04, 
+    0x03, 0xC9, 0x03, 0x45, 0x03, 0x14, 0x03, 0x01, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x13, 0x03, 0x45, 
+    0x03, 0x00, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x45, 0x03, 0x14, 0x03, 0x00, 0x00, 0x04, 0x03, 0xA9, 
+    0x03, 0x13, 0x03, 0x45, 0x03, 0x01, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x45, 0x03, 0x14, 0x03, 0x01, 
+    0x00, 0x04, 0x21, 0x26, 0x03, 0x13, 0x03, 0x45, 0x03, 0x42, 0x00, 0x01, 0x00, 0x19, 0x1F, 0x82, 
+    0x1F, 0x83, 0x1F, 0x84, 0x1F, 0x85, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, 0x8C, 0x1F, 0x8D, 0x1F, 0x92, 
+    0x1F, 0x93, 0x1F, 0x94, 0x1F, 0x95, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, 0x9C, 0x1F, 0x9D, 0x1F, 0xA2, 
+    0x1F, 0xA3, 0x1F, 0xA4, 0x1F, 0xA5, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 
+    0x00, 0x01, 0x01, 0x32, 0x00, 0x19, 0x00, 0x38, 0x00, 0x42, 0x00, 0x4C, 0x00, 0x56, 0x00, 0x60, 
+    0x00, 0x6A, 0x00, 0x74, 0x00, 0x7E, 0x00, 0x88, 0x00, 0x92, 0x00, 0x9C, 0x00, 0xA6, 0x00, 0xB0, 
+    0x00, 0xBA, 0x00, 0xC4, 0x00, 0xCE, 0x00, 0xD8, 0x00, 0xE2, 0x00, 0xEC, 0x00, 0xF6, 0x01, 0x00, 
+    0x01, 0x0A, 0x01, 0x14, 0x01, 0x1E, 0x01, 0x28, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x13, 0x03, 0x45, 
+    0x03, 0x40, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x45, 0x03, 0x14, 0x03, 0x40, 0x00, 0x04, 0x03, 0xB1, 
+    0x03, 0x13, 0x03, 0x45, 0x03, 0x41, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x45, 0x03, 0x14, 0x03, 0x41, 
+    0x00, 0x04, 0x03, 0x91, 0x03, 0x13, 0x03, 0x45, 0x03, 0x40, 0x00, 0x04, 0x03, 0x91, 0x03, 0x45, 
+    0x03, 0x14, 0x03, 0x40, 0x00, 0x04, 0x03, 0x91, 0x03, 0x13, 0x03, 0x45, 0x03, 0x41, 0x00, 0x04, 
+    0x03, 0x91, 0x03, 0x45, 0x03, 0x14, 0x03, 0x41, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x13, 0x03, 0x45, 
+    0x03, 0x40, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x45, 0x03, 0x14, 0x03, 0x40, 0x00, 0x04, 0x03, 0xB7, 
+    0x03, 0x13, 0x03, 0x45, 0x03, 0x41, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x45, 0x03, 0x14, 0x03, 0x41, 
+    0x00, 0x04, 0x03, 0x97, 0x03, 0x13, 0x03, 0x45, 0x03, 0x40, 0x00, 0x04, 0x03, 0x97, 0x03, 0x45, 
+    0x03, 0x14, 0x03, 0x40, 0x00, 0x04, 0x03, 0x97, 0x03, 0x13, 0x03, 0x45, 0x03, 0x41, 0x00, 0x04, 
+    0x03, 0x97, 0x03, 0x45, 0x03, 0x14, 0x03, 0x41, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x13, 0x03, 0x45, 
+    0x03, 0x40, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x45, 0x03, 0x14, 0x03, 0x40, 0x00, 0x04, 0x03, 0xC9, 
+    0x03, 0x13, 0x03, 0x45, 0x03, 0x41, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x45, 0x03, 0x14, 0x03, 0x41, 
+    0x00, 0x04, 0x03, 0xA9, 0x03, 0x13, 0x03, 0x45, 0x03, 0x40, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x45, 
+    0x03, 0x14, 0x03, 0x40, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x13, 0x03, 0x45, 0x03, 0x41, 0x00, 0x04, 
+    0x03, 0xA9, 0x03, 0x45, 0x03, 0x14, 0x03, 0x41, 0x00, 0x04, 0x21, 0x26, 0x03, 0x43, 0x03, 0x42, 
+    0x03, 0x45, 0x00, 0x01, 0x00, 0x19, 0x1F, 0x82, 0x1F, 0x83, 0x1F, 0x84, 0x1F, 0x85, 0x1F, 0x8A, 
+    0x1F, 0x8B, 0x1F, 0x8C, 0x1F, 0x8D, 0x1F, 0x92, 0x1F, 0x93, 0x1F, 0x94, 0x1F, 0x95, 0x1F, 0x9A, 
+    0x1F, 0x9B, 0x1F, 0x9C, 0x1F, 0x9D, 0x1F, 0xA2, 0x1F, 0xA3, 0x1F, 0xA4, 0x1F, 0xA5, 0x1F, 0xAA, 
+    0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x00, 0x01, 0x00, 0xBA, 0x00, 0x0F, 0x00, 0x24, 
+    0x00, 0x2E, 0x00, 0x38, 0x00, 0x42, 0x00, 0x4C, 0x00, 0x56, 0x00, 0x60, 0x00, 0x6A, 0x00, 0x74, 
+    0x00, 0x7E, 0x00, 0x88, 0x00, 0x92, 0x00, 0x9C, 0x00, 0xA6, 0x00, 0xB0, 0x00, 0x04, 0x03, 0xB1, 
+    0x03, 0x43, 0x03, 0x00, 0x03, 0x45, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x43, 0x03, 0x01, 0x03, 0x45, 
+    0x00, 0x04, 0x03, 0x91, 0x03, 0x43, 0x03, 0x00, 0x03, 0x45, 0x00, 0x04, 0x03, 0x91, 0x03, 0x43, 
+    0x03, 0x01, 0x03, 0x45, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x43, 0x03, 0x00, 0x03, 0x45, 0x00, 0x04, 
+    0x03, 0xB7, 0x03, 0x43, 0x03, 0x01, 0x03, 0x45, 0x00, 0x04, 0x03, 0x97, 0x03, 0x43, 0x03, 0x00, 
+    0x03, 0x45, 0x00, 0x04, 0x03, 0x97, 0x03, 0x43, 0x03, 0x01, 0x03, 0x45, 0x00, 0x04, 0x03, 0xC9, 
+    0x03, 0x43, 0x03, 0x00, 0x03, 0x45, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x43, 0x03, 0x01, 0x03, 0x45, 
+    0x00, 0x04, 0x03, 0xA9, 0x03, 0x43, 0x03, 0x00, 0x03, 0x45, 0x00, 0x04, 0x21, 0x26, 0x03, 0x14, 
+    0x03, 0x00, 0x03, 0x45, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x43, 0x03, 0x01, 0x03, 0x45, 0x00, 0x04, 
+    0x21, 0x26, 0x03, 0x14, 0x03, 0x01, 0x03, 0x45, 0x00, 0x04, 0x21, 0x26, 0x03, 0x43, 0x03, 0x45, 
+    0x03, 0x42, 0x00, 0x01, 0x00, 0x0F, 0x1F, 0x82, 0x1F, 0x84, 0x1F, 0x8A, 0x1F, 0x8C, 0x1F, 0x92, 
+    0x1F, 0x94, 0x1F, 0x9A, 0x1F, 0x9C, 0x1F, 0xA2, 0x1F, 0xA4, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, 0xAC, 
+    0x1F, 0xAD, 0x1F, 0xAE, 0x00, 0x01, 0x00, 0xBA, 0x00, 0x0F, 0x00, 0x24, 0x00, 0x2E, 0x00, 0x38, 
+    0x00, 0x42, 0x00, 0x4C, 0x00, 0x56, 0x00, 0x60, 0x00, 0x6A, 0x00, 0x74, 0x00, 0x7E, 0x00, 0x88, 
+    0x00, 0x92, 0x00, 0x9C, 0x00, 0xA6, 0x00, 0xB0, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x43, 0x03, 0x40, 
+    0x03, 0x45, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x43, 0x03, 0x41, 0x03, 0x45, 0x00, 0x04, 0x03, 0x91, 
+    0x03, 0x43, 0x03, 0x40, 0x03, 0x45, 0x00, 0x04, 0x03, 0x91, 0x03, 0x43, 0x03, 0x41, 0x03, 0x45, 
+    0x00, 0x04, 0x03, 0xB7, 0x03, 0x43, 0x03, 0x40, 0x03, 0x45, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x43, 
+    0x03, 0x41, 0x03, 0x45, 0x00, 0x04, 0x03, 0x97, 0x03, 0x43, 0x03, 0x40, 0x03, 0x45, 0x00, 0x04, 
+    0x03, 0x97, 0x03, 0x43, 0x03, 0x41, 0x03, 0x45, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x43, 0x03, 0x40, 
+    0x03, 0x45, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x43, 0x03, 0x41, 0x03, 0x45, 0x00, 0x04, 0x03, 0xA9, 
+    0x03, 0x43, 0x03, 0x40, 0x03, 0x45, 0x00, 0x04, 0x21, 0x26, 0x03, 0x14, 0x03, 0x40, 0x03, 0x45, 
+    0x00, 0x04, 0x03, 0xA9, 0x03, 0x43, 0x03, 0x41, 0x03, 0x45, 0x00, 0x04, 0x21, 0x26, 0x03, 0x14, 
+    0x03, 0x41, 0x03, 0x45, 0x00, 0x04, 0x21, 0x26, 0x03, 0x45, 0x03, 0x13, 0x03, 0x42, 0x00, 0x01, 
+    0x00, 0x0F, 0x1F, 0x82, 0x1F, 0x84, 0x1F, 0x8A, 0x1F, 0x8C, 0x1F, 0x92, 0x1F, 0x94, 0x1F, 0x9A, 
+    0x1F, 0x9C, 0x1F, 0xA2, 0x1F, 0xA4, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 
+    0x00, 0x01, 0x00, 0xBA, 0x00, 0x0F, 0x00, 0x24, 0x00, 0x2E, 0x00, 0x38, 0x00, 0x42, 0x00, 0x4C, 
+    0x00, 0x56, 0x00, 0x60, 0x00, 0x6A, 0x00, 0x74, 0x00, 0x7E, 0x00, 0x88, 0x00, 0x92, 0x00, 0x9C, 
+    0x00, 0xA6, 0x00, 0xB0, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x43, 0x03, 0x45, 0x03, 0x00, 0x00, 0x04, 
+    0x03, 0xB1, 0x03, 0x43, 0x03, 0x45, 0x03, 0x01, 0x00, 0x04, 0x03, 0x91, 0x03, 0x43, 0x03, 0x45, 
+    0x03, 0x00, 0x00, 0x04, 0x03, 0x91, 0x03, 0x43, 0x03, 0x45, 0x03, 0x01, 0x00, 0x04, 0x03, 0xB7, 
+    0x03, 0x43, 0x03, 0x45, 0x03, 0x00, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x43, 0x03, 0x45, 0x03, 0x01, 
+    0x00, 0x04, 0x03, 0x97, 0x03, 0x43, 0x03, 0x45, 0x03, 0x00, 0x00, 0x04, 0x03, 0x97, 0x03, 0x43, 
+    0x03, 0x45, 0x03, 0x01, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x43, 0x03, 0x45, 0x03, 0x00, 0x00, 0x04, 
+    0x03, 0xC9, 0x03, 0x43, 0x03, 0x45, 0x03, 0x01, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x43, 0x03, 0x45, 
+    0x03, 0x00, 0x00, 0x04, 0x21, 0x26, 0x03, 0x14, 0x03, 0x45, 0x03, 0x00, 0x00, 0x04, 0x03, 0xA9, 
+    0x03, 0x43, 0x03, 0x45, 0x03, 0x01, 0x00, 0x04, 0x21, 0x26, 0x03, 0x14, 0x03, 0x45, 0x03, 0x01, 
+    0x00, 0x04, 0x21, 0x26, 0x03, 0x45, 0x03, 0x43, 0x03, 0x42, 0x00, 0x01, 0x00, 0x0F, 0x1F, 0x82, 
+    0x1F, 0x84, 0x1F, 0x8A, 0x1F, 0x8C, 0x1F, 0x92, 0x1F, 0x94, 0x1F, 0x9A, 0x1F, 0x9C, 0x1F, 0xA2, 
+    0x1F, 0xA4, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x00, 0x01, 0x00, 0xAE, 
+    0x00, 0x0E, 0x00, 0x22, 0x00, 0x2C, 0x00, 0x36, 0x00, 0x40, 0x00, 0x4A, 0x00, 0x54, 0x00, 0x5E, 
+    0x00, 0x68, 0x00, 0x72, 0x00, 0x7C, 0x00, 0x86, 0x00, 0x90, 0x00, 0x9A, 0x00, 0xA4, 0x00, 0x04, 
+    0x03, 0xB1, 0x03, 0x43, 0x03, 0x45, 0x03, 0x40, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x43, 0x03, 0x45, 
+    0x03, 0x41, 0x00, 0x04, 0x03, 0x91, 0x03, 0x43, 0x03, 0x45, 0x03, 0x40, 0x00, 0x04, 0x03, 0x91, 
+    0x03, 0x43, 0x03, 0x45, 0x03, 0x41, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x43, 0x03, 0x45, 0x03, 0x40, 
+    0x00, 0x04, 0x03, 0xB7, 0x03, 0x43, 0x03, 0x45, 0x03, 0x41, 0x00, 0x04, 0x03, 0x97, 0x03, 0x43, 
+    0x03, 0x45, 0x03, 0x40, 0x00, 0x04, 0x03, 0x97, 0x03, 0x43, 0x03, 0x45, 0x03, 0x41, 0x00, 0x04, 
+    0x03, 0xC9, 0x03, 0x43, 0x03, 0x45, 0x03, 0x40, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x43, 0x03, 0x45, 
+    0x03, 0x41, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x43, 0x03, 0x45, 0x03, 0x40, 0x00, 0x04, 0x21, 0x26, 
+    0x03, 0x14, 0x03, 0x45, 0x03, 0x40, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x43, 0x03, 0x45, 0x03, 0x41, 
+    0x00, 0x04, 0x21, 0x26, 0x03, 0x14, 0x03, 0x45, 0x03, 0x41, 0x00, 0x01, 0x00, 0x0E, 0x1F, 0x82, 
+    0x1F, 0x84, 0x1F, 0x8A, 0x1F, 0x8C, 0x1F, 0x92, 0x1F, 0x94, 0x1F, 0x9A, 0x1F, 0x9C, 0x1F, 0xA2, 
+    0x1F, 0xA4, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x00, 0x01, 0x00, 0xAE, 0x00, 0x0E, 
+    0x00, 0x22, 0x00, 0x2C, 0x00, 0x36, 0x00, 0x40, 0x00, 0x4A, 0x00, 0x54, 0x00, 0x5E, 0x00, 0x68, 
+    0x00, 0x72, 0x00, 0x7C, 0x00, 0x86, 0x00, 0x90, 0x00, 0x9A, 0x00, 0xA4, 0x00, 0x04, 0x03, 0xB1, 
+    0x03, 0x45, 0x03, 0x13, 0x03, 0x00, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x45, 0x03, 0x13, 0x03, 0x01, 
+    0x00, 0x04, 0x03, 0x91, 0x03, 0x45, 0x03, 0x13, 0x03, 0x00, 0x00, 0x04, 0x03, 0x91, 0x03, 0x45, 
+    0x03, 0x13, 0x03, 0x01, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x45, 0x03, 0x13, 0x03, 0x00, 0x00, 0x04, 
+    0x03, 0xB7, 0x03, 0x45, 0x03, 0x13, 0x03, 0x01, 0x00, 0x04, 0x03, 0x97, 0x03, 0x45, 0x03, 0x13, 
+    0x03, 0x00, 0x00, 0x04, 0x03, 0x97, 0x03, 0x45, 0x03, 0x13, 0x03, 0x01, 0x00, 0x04, 0x03, 0xC9, 
+    0x03, 0x45, 0x03, 0x13, 0x03, 0x00, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x45, 0x03, 0x13, 0x03, 0x01, 
+    0x00, 0x04, 0x03, 0xA9, 0x03, 0x45, 0x03, 0x13, 0x03, 0x00, 0x00, 0x04, 0x21, 0x26, 0x03, 0x45, 
+    0x03, 0x14, 0x03, 0x00, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x45, 0x03, 0x13, 0x03, 0x01, 0x00, 0x04, 
+    0x21, 0x26, 0x03, 0x45, 0x03, 0x14, 0x03, 0x01, 0x00, 0x01, 0x00, 0x0E, 0x1F, 0x82, 0x1F, 0x84, 
+    0x1F, 0x8A, 0x1F, 0x8C, 0x1F, 0x92, 0x1F, 0x94, 0x1F, 0x9A, 0x1F, 0x9C, 0x1F, 0xA2, 0x1F, 0xA4, 
+    0x1F, 0xAA, 0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x00, 0x01, 0x00, 0xAE, 0x00, 0x0E, 0x00, 0x22, 
+    0x00, 0x2C, 0x00, 0x36, 0x00, 0x40, 0x00, 0x4A, 0x00, 0x54, 0x00, 0x5E, 0x00, 0x68, 0x00, 0x72, 
+    0x00, 0x7C, 0x00, 0x86, 0x00, 0x90, 0x00, 0x9A, 0x00, 0xA4, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x45, 
+    0x03, 0x13, 0x03, 0x40, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x45, 0x03, 0x13, 0x03, 0x41, 0x00, 0x04, 
+    0x03, 0x91, 0x03, 0x45, 0x03, 0x13, 0x03, 0x40, 0x00, 0x04, 0x03, 0x91, 0x03, 0x45, 0x03, 0x13, 
+    0x03, 0x41, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x45, 0x03, 0x13, 0x03, 0x40, 0x00, 0x04, 0x03, 0xB7, 
+    0x03, 0x45, 0x03, 0x13, 0x03, 0x41, 0x00, 0x04, 0x03, 0x97, 0x03, 0x45, 0x03, 0x13, 0x03, 0x40, 
+    0x00, 0x04, 0x03, 0x97, 0x03, 0x45, 0x03, 0x13, 0x03, 0x41, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x45, 
+    0x03, 0x13, 0x03, 0x40, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x45, 0x03, 0x13, 0x03, 0x41, 0x00, 0x04, 
+    0x03, 0xA9, 0x03, 0x45, 0x03, 0x13, 0x03, 0x40, 0x00, 0x04, 0x21, 0x26, 0x03, 0x45, 0x03, 0x14, 
+    0x03, 0x40, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x45, 0x03, 0x13, 0x03, 0x41, 0x00, 0x04, 0x21, 0x26, 
+    0x03, 0x45, 0x03, 0x14, 0x03, 0x41, 0x00, 0x01, 0x00, 0x0E, 0x1F, 0x82, 0x1F, 0x84, 0x1F, 0x8A, 
+    0x1F, 0x8C, 0x1F, 0x92, 0x1F, 0x94, 0x1F, 0x9A, 0x1F, 0x9C, 0x1F, 0xA2, 0x1F, 0xA4, 0x1F, 0xAA, 
+    0x1F, 0xAB, 0x1F, 0xAC, 0x1F, 0xAD, 0x00, 0x01, 0x00, 0x96, 0x00, 0x0C, 0x00, 0x1E, 0x00, 0x28, 
+    0x00, 0x32, 0x00, 0x3C, 0x00, 0x46, 0x00, 0x50, 0x00, 0x5A, 0x00, 0x64, 0x00, 0x6E, 0x00, 0x78, 
+    0x00, 0x82, 0x00, 0x8C, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x45, 0x03, 0x43, 0x03, 0x00, 0x00, 0x04, 
+    0x03, 0xB1, 0x03, 0x45, 0x03, 0x43, 0x03, 0x01, 0x00, 0x04, 0x03, 0x91, 0x03, 0x45, 0x03, 0x43, 
+    0x03, 0x00, 0x00, 0x04, 0x03, 0x91, 0x03, 0x45, 0x03, 0x43, 0x03, 0x01, 0x00, 0x04, 0x03, 0xB7, 
+    0x03, 0x45, 0x03, 0x43, 0x03, 0x00, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x45, 0x03, 0x43, 0x03, 0x01, 
+    0x00, 0x04, 0x03, 0x97, 0x03, 0x45, 0x03, 0x43, 0x03, 0x00, 0x00, 0x04, 0x03, 0x97, 0x03, 0x45, 
+    0x03, 0x43, 0x03, 0x01, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x45, 0x03, 0x43, 0x03, 0x00, 0x00, 0x04, 
+    0x03, 0xC9, 0x03, 0x45, 0x03, 0x43, 0x03, 0x01, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x45, 0x03, 0x43, 
+    0x03, 0x00, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x45, 0x03, 0x43, 0x03, 0x01, 0x00, 0x01, 0x00, 0x0C, 
+    0x1F, 0x82, 0x1F, 0x84, 0x1F, 0x8A, 0x1F, 0x8C, 0x1F, 0x92, 0x1F, 0x94, 0x1F, 0x9A, 0x1F, 0x9C, 
+    0x1F, 0xA2, 0x1F, 0xA4, 0x1F, 0xAA, 0x1F, 0xAC, 0x00, 0x01, 0x00, 0x96, 0x00, 0x0C, 0x00, 0x1E, 
+    0x00, 0x28, 0x00, 0x32, 0x00, 0x3C, 0x00, 0x46, 0x00, 0x50, 0x00, 0x5A, 0x00, 0x64, 0x00, 0x6E, 
+    0x00, 0x78, 0x00, 0x82, 0x00, 0x8C, 0x00, 0x04, 0x03, 0xB1, 0x03, 0x45, 0x03, 0x43, 0x03, 0x40, 
+    0x00, 0x04, 0x03, 0xB1, 0x03, 0x45, 0x03, 0x43, 0x03, 0x41, 0x00, 0x04, 0x03, 0x91, 0x03, 0x45, 
+    0x03, 0x43, 0x03, 0x40, 0x00, 0x04, 0x03, 0x91, 0x03, 0x45, 0x03, 0x43, 0x03, 0x41, 0x00, 0x04, 
+    0x03, 0xB7, 0x03, 0x45, 0x03, 0x43, 0x03, 0x40, 0x00, 0x04, 0x03, 0xB7, 0x03, 0x45, 0x03, 0x43, 
+    0x03, 0x41, 0x00, 0x04, 0x03, 0x97, 0x03, 0x45, 0x03, 0x43, 0x03, 0x40, 0x00, 0x04, 0x03, 0x97, 
+    0x03, 0x45, 0x03, 0x43, 0x03, 0x41, 0x00, 0x04, 0x03, 0xC9, 0x03, 0x45, 0x03, 0x43, 0x03, 0x40, 
+    0x00, 0x04, 0x03, 0xC9, 0x03, 0x45, 0x03, 0x43, 0x03, 0x41, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x45, 
+    0x03, 0x43, 0x03, 0x40, 0x00, 0x04, 0x03, 0xA9, 0x03, 0x45, 0x03, 0x43, 0x03, 0x41, 0x00, 0x01, 
+    0x00, 0x0C, 0x1F, 0x82, 0x1F, 0x84, 0x1F, 0x8A, 0x1F, 0x8C, 0x1F, 0x92, 0x1F, 0x94, 0x1F, 0x9A, 
+    0x1F, 0x9C, 0x1F, 0xA2, 0x1F, 0xA4, 0x1F, 0xAA, 0x1F, 0xAC, 0x00, 0x01, 0x00, 0x1E, 0x00, 0x02, 
+    0x00, 0x0A, 0x00, 0x14, 0x00, 0x04, 0x21, 0x26, 0x03, 0x13, 0x03, 0x00, 0x03, 0x45, 0x00, 0x04, 
+    0x21, 0x26, 0x03, 0x13, 0x03, 0x01, 0x03, 0x45, 0x00, 0x01, 0x00, 0x02, 0x1F, 0xAA, 0x1F, 0xAC, 
+    0x00, 0x01, 0x00, 0x1E, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x14, 0x00, 0x04, 0x21, 0x26, 0x03, 0x13, 
+    0x03, 0x40, 0x03, 0x45, 0x00, 0x04, 0x21, 0x26, 0x03, 0x13, 0x03, 0x41, 0x03, 0x45, 0x00, 0x01, 
+    0x00, 0x02, 0x1F, 0xAA, 0x1F, 0xAC, 0x00, 0x01, 0x00, 0x1E, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x14, 
+    0x00, 0x04, 0x21, 0x26, 0x03, 0x13, 0x03, 0x45, 0x03, 0x00, 0x00, 0x04, 0x21, 0x26, 0x03, 0x13, 
+    0x03, 0x45, 0x03, 0x01, 0x00, 0x01, 0x00, 0x02, 0x1F, 0xAA, 0x1F, 0xAC, 0x00, 0x01, 0x00, 0x1E, 
+    0x00, 0x02, 0x00, 0x0A, 0x00, 0x14, 0x00, 0x04, 0x21, 0x26, 0x03, 0x13, 0x03, 0x45, 0x03, 0x40, 
+    0x00, 0x04, 0x21, 0x26, 0x03, 0x13, 0x03, 0x45, 0x03, 0x41, 0x00, 0x01, 0x00, 0x02, 0x1F, 0xAA, 
+    0x1F, 0xAC, 0x00, 0x01, 0x00, 0x1E, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x14, 0x00, 0x04, 0x21, 0x26, 
+    0x03, 0x43, 0x03, 0x00, 0x03, 0x45, 0x00, 0x04, 0x21, 0x26, 0x03, 0x43, 0x03, 0x01, 0x03, 0x45, 
+    0x00, 0x01, 0x00, 0x02, 0x1F, 0xAA, 0x1F, 0xAC, 0x00, 0x01, 0x00, 0x1E, 0x00, 0x02, 0x00, 0x0A, 
+    0x00, 0x14, 0x00, 0x04, 0x21, 0x26, 0x03, 0x43, 0x03, 0x40, 0x03, 0x45, 0x00, 0x04, 0x21, 0x26, 
+    0x03, 0x43, 0x03, 0x41, 0x03, 0x45, 0x00, 0x01, 0x00, 0x02, 0x1F, 0xAA, 0x1F, 0xAC, 0x00, 0x01, 
+    0x00, 0x1E, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x14, 0x00, 0x04, 0x21, 0x26, 0x03, 0x43, 0x03, 0x45, 
+    0x03, 0x00, 0x00, 0x04, 0x21, 0x26, 0x03, 0x43, 0x03, 0x45, 0x03, 0x01, 0x00, 0x01, 0x00, 0x02, 
+    0x1F, 0xAA, 0x1F, 0xAC, 0x00, 0x01, 0x00, 0x1E, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x14, 0x00, 0x04, 
+    0x21, 0x26, 0x03, 0x43, 0x03, 0x45, 0x03, 0x40, 0x00, 0x04, 0x21, 0x26, 0x03, 0x43, 0x03, 0x45, 
+    0x03, 0x41, 0x00, 0x01, 0x00, 0x02, 0x1F, 0xAA, 0x1F, 0xAC, 0x00, 0x01, 0x00, 0x1E, 0x00, 0x02, 
+    0x00, 0x0A, 0x00, 0x14, 0x00, 0x04, 0x21, 0x26, 0x03, 0x45, 0x03, 0x13, 0x03, 0x00, 0x00, 0x04, 
+    0x21, 0x26, 0x03, 0x45, 0x03, 0x13, 0x03, 0x01, 0x00, 0x01, 0x00, 0x02, 0x1F, 0xAA, 0x1F, 0xAC, 
+    0x00, 0x01, 0x00, 0x1E, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x14, 0x00, 0x04, 0x21, 0x26, 0x03, 0x45, 
+    0x03, 0x13, 0x03, 0x40, 0x00, 0x04, 0x21, 0x26, 0x03, 0x45, 0x03, 0x13, 0x03, 0x41, 0x00, 0x01, 
+    0x00, 0x02, 0x1F, 0xAA, 0x1F, 0xAC, 0x00, 0x01, 0x00, 0x1E, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x14, 
+    0x00, 0x04, 0x21, 0x26, 0x03, 0x45, 0x03, 0x43, 0x03, 0x00, 0x00, 0x04, 0x21, 0x26, 0x03, 0x45, 
+    0x03, 0x43, 0x03, 0x01, 0x00, 0x01, 0x00, 0x02, 0x1F, 0xAA, 0x1F, 0xAC, 0x00, 0x01, 0x00, 0x1E, 
+    0x00, 0x02, 0x00, 0x0A, 0x00, 0x14, 0x00, 0x04, 0x21, 0x26, 0x03, 0x45, 0x03, 0x43, 0x03, 0x40, 
+    0x00, 0x04, 0x21, 0x26, 0x03, 0x45, 0x03, 0x43, 0x03, 0x41, 0x00, 0x01, 0x00, 0x02, 0x1F, 0xAA, 
+    0x1F, 0xAC, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x01, 0x36, 0x00, 0x16, 
+    0x00, 0x32, 0x00, 0x3C, 0x00, 0x46, 0x00, 0x50, 0x00, 0x5A, 0x00, 0x64, 0x00, 0x6E, 0x00, 0x78, 
+    0x00, 0x82, 0x00, 0x8C, 0x00, 0x96, 0x00, 0xA0, 0x00, 0xAA, 0x00, 0xB4, 0x00, 0xBE, 0x00, 0xC8, 
+    0x00, 0xD2, 0x00, 0xE4, 0x00, 0xF6, 0x01, 0x08, 0x01, 0x1A, 0x01, 0x2C, 0x00, 0x01, 0x00, 0x04, 
+    0x30, 0x94, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0x4C, 0x00, 0x02, 0x30, 0x99, 
+    0x00, 0x01, 0x00, 0x04, 0x30, 0x4E, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0x50, 
+    0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0x52, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 
+    0x00, 0x04, 0x30, 0x54, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0x56, 0x00, 0x02, 
+    0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0x58, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 
+    0x30, 0x5A, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0x5C, 0x00, 0x02, 0x30, 0x99, 
+    0x00, 0x01, 0x00, 0x04, 0x30, 0x5E, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0x60, 
+    0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0x62, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 
+    0x00, 0x04, 0x30, 0x65, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0x67, 0x00, 0x02, 
+    0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0x69, 0x00, 0x02, 0x30, 0x99, 0x00, 0x02, 0x00, 0x06, 
+    0x00, 0x0C, 0x30, 0x70, 0x00, 0x02, 0x30, 0x99, 0x30, 0x71, 0x00, 0x02, 0x30, 0x9A, 0x00, 0x02, 
+    0x00, 0x06, 0x00, 0x0C, 0x30, 0x73, 0x00, 0x02, 0x30, 0x99, 0x30, 0x74, 0x00, 0x02, 0x30, 0x9A, 
+    0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x30, 0x76, 0x00, 0x02, 0x30, 0x99, 0x30, 0x77, 0x00, 0x02, 
+    0x30, 0x9A, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x30, 0x79, 0x00, 0x02, 0x30, 0x99, 0x30, 0x7A, 
+    0x00, 0x02, 0x30, 0x9A, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x30, 0x7C, 0x00, 0x02, 0x30, 0x99, 
+    0x30, 0x7D, 0x00, 0x02, 0x30, 0x9A, 0x00, 0x01, 0x00, 0x04, 0x30, 0x9E, 0x00, 0x02, 0x30, 0x99, 
+    0x00, 0x01, 0x00, 0x16, 0x30, 0x46, 0x30, 0x4B, 0x30, 0x4D, 0x30, 0x4F, 0x30, 0x51, 0x30, 0x53, 
+    0x30, 0x55, 0x30, 0x57, 0x30, 0x59, 0x30, 0x5B, 0x30, 0x5D, 0x30, 0x5F, 0x30, 0x61, 0x30, 0x64, 
+    0x30, 0x66, 0x30, 0x68, 0x30, 0x6F, 0x30, 0x72, 0x30, 0x75, 0x30, 0x78, 0x30, 0x7B, 0x30, 0x9D, 
+    0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0xDE, 0x00, 0x1B, 0x00, 0x3C, 
+    0x00, 0x42, 0x00, 0x48, 0x00, 0x4E, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x60, 0x00, 0x66, 0x00, 0x6C, 
+    0x00, 0x72, 0x00, 0x78, 0x00, 0x7E, 0x00, 0x84, 0x00, 0x8A, 0x00, 0x90, 0x00, 0x96, 0x00, 0x9C, 
+    0x00, 0xA2, 0x00, 0xA8, 0x00, 0xAE, 0x00, 0xB4, 0x00, 0xBA, 0x00, 0xC0, 0x00, 0xC6, 0x00, 0xCC, 
+    0x00, 0xD2, 0x00, 0xD8, 0x00, 0x02, 0x30, 0x4B, 0x30, 0x99, 0x00, 0x02, 0x30, 0x4D, 0x30, 0x99, 
+    0x00, 0x02, 0x30, 0x4F, 0x30, 0x99, 0x00, 0x02, 0x30, 0x51, 0x30, 0x99, 0x00, 0x02, 0x30, 0x53, 
+    0x30, 0x99, 0x00, 0x02, 0x30, 0x55, 0x30, 0x99, 0x00, 0x02, 0x30, 0x57, 0x30, 0x99, 0x00, 0x02, 
+    0x30, 0x59, 0x30, 0x99, 0x00, 0x02, 0x30, 0x5B, 0x30, 0x99, 0x00, 0x02, 0x30, 0x5D, 0x30, 0x99, 
+    0x00, 0x02, 0x30, 0x5F, 0x30, 0x99, 0x00, 0x02, 0x30, 0x61, 0x30, 0x99, 0x00, 0x02, 0x30, 0x64, 
+    0x30, 0x99, 0x00, 0x02, 0x30, 0x66, 0x30, 0x99, 0x00, 0x02, 0x30, 0x68, 0x30, 0x99, 0x00, 0x02, 
+    0x30, 0x6F, 0x30, 0x99, 0x00, 0x02, 0x30, 0x6F, 0x30, 0x9A, 0x00, 0x02, 0x30, 0x72, 0x30, 0x99, 
+    0x00, 0x02, 0x30, 0x72, 0x30, 0x9A, 0x00, 0x02, 0x30, 0x75, 0x30, 0x99, 0x00, 0x02, 0x30, 0x75, 
+    0x30, 0x9A, 0x00, 0x02, 0x30, 0x78, 0x30, 0x99, 0x00, 0x02, 0x30, 0x78, 0x30, 0x9A, 0x00, 0x02, 
+    0x30, 0x7B, 0x30, 0x99, 0x00, 0x02, 0x30, 0x7B, 0x30, 0x9A, 0x00, 0x02, 0x30, 0x46, 0x30, 0x99, 
+    0x00, 0x02, 0x30, 0x9D, 0x30, 0x99, 0x00, 0x01, 0x00, 0x1B, 0x30, 0x4C, 0x30, 0x4E, 0x30, 0x50, 
+    0x30, 0x52, 0x30, 0x54, 0x30, 0x56, 0x30, 0x58, 0x30, 0x5A, 0x30, 0x5C, 0x30, 0x5E, 0x30, 0x60, 
+    0x30, 0x62, 0x30, 0x65, 0x30, 0x67, 0x30, 0x69, 0x30, 0x70, 0x30, 0x71, 0x30, 0x73, 0x30, 0x74, 
+    0x30, 0x76, 0x30, 0x77, 0x30, 0x79, 0x30, 0x7A, 0x30, 0x7C, 0x30, 0x7D, 0x30, 0x94, 0x30, 0x9E, 
+    0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x44, 0x00, 0x03, 0x00, 0x0C, 
+    0x00, 0x16, 0x00, 0x3A, 0x00, 0x01, 0x00, 0x04, 0x0C, 0xC0, 0x00, 0x02, 0x0C, 0xD5, 0x00, 0x04, 
+    0x00, 0x0A, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x0C, 0xCB, 0x00, 0x03, 0x0C, 0xC2, 0x0C, 0xD5, 
+    0x0C, 0xCA, 0x00, 0x02, 0x0C, 0xC2, 0x0C, 0xC7, 0x00, 0x02, 0x0C, 0xD5, 0x0C, 0xC8, 0x00, 0x02, 
+    0x0C, 0xD6, 0x00, 0x01, 0x00, 0x04, 0x0C, 0xCB, 0x00, 0x02, 0x0C, 0xD5, 0x00, 0x01, 0x00, 0x03, 
+    0x0C, 0xBF, 0x0C, 0xC6, 0x0C, 0xCA, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x46, 
+    0x00, 0x01, 0x00, 0x2E, 0x00, 0x05, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 0x00, 0x22, 0x00, 0x28, 
+    0x00, 0x02, 0x0C, 0xBF, 0x0C, 0xD5, 0x00, 0x02, 0x0C, 0xC6, 0x0C, 0xD5, 0x00, 0x02, 0x0C, 0xC6, 
+    0x0C, 0xD6, 0x00, 0x02, 0x0C, 0xC6, 0x0C, 0xC2, 0x00, 0x02, 0x0C, 0xCA, 0x0C, 0xD5, 0x00, 0x01, 
+    0x00, 0x05, 0x0C, 0xC0, 0x0C, 0xC7, 0x0C, 0xC8, 0x0C, 0xCA, 0x0C, 0xCB, 0x00, 0x01, 0x00, 0x10, 
+    0x00, 0x01, 0x00, 0x08, 0x00, 0x03, 0x0C, 0xC6, 0x0C, 0xC2, 0x0C, 0xD5, 0x00, 0x01, 0x00, 0x01, 
+    0x0C, 0xCB, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x01, 0x66, 0x00, 0x1A, 
+    0x00, 0x3A, 0x00, 0x44, 0x00, 0x4E, 0x00, 0x58, 0x00, 0x62, 0x00, 0x6C, 0x00, 0x76, 0x00, 0x80, 
+    0x00, 0x8A, 0x00, 0x94, 0x00, 0x9E, 0x00, 0xA8, 0x00, 0xB2, 0x00, 0xBC, 0x00, 0xC6, 0x00, 0xD0, 
+    0x00, 0xDA, 0x00, 0xEC, 0x00, 0xFE, 0x01, 0x10, 0x01, 0x22, 0x01, 0x34, 0x01, 0x3E, 0x01, 0x48, 
+    0x01, 0x52, 0x01, 0x5C, 0x00, 0x01, 0x00, 0x04, 0x30, 0xF4, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 
+    0x00, 0x04, 0x30, 0xAC, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0xAE, 0x00, 0x02, 
+    0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0xB0, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 
+    0x30, 0xB2, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0xB4, 0x00, 0x02, 0x30, 0x99, 
+    0x00, 0x01, 0x00, 0x04, 0x30, 0xB6, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0xB8, 
+    0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0xBA, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 
+    0x00, 0x04, 0x30, 0xBC, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0xBE, 0x00, 0x02, 
+    0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0xC0, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 
+    0x30, 0xC2, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0xC5, 0x00, 0x02, 0x30, 0x99, 
+    0x00, 0x01, 0x00, 0x04, 0x30, 0xC7, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0xC9, 
+    0x00, 0x02, 0x30, 0x99, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x30, 0xD0, 0x00, 0x02, 0x30, 0x99, 
+    0x30, 0xD1, 0x00, 0x02, 0x30, 0x9A, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x30, 0xD3, 0x00, 0x02, 
+    0x30, 0x99, 0x30, 0xD4, 0x00, 0x02, 0x30, 0x9A, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x30, 0xD6, 
+    0x00, 0x02, 0x30, 0x99, 0x30, 0xD7, 0x00, 0x02, 0x30, 0x9A, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 
+    0x30, 0xD9, 0x00, 0x02, 0x30, 0x99, 0x30, 0xDA, 0x00, 0x02, 0x30, 0x9A, 0x00, 0x02, 0x00, 0x06, 
+    0x00, 0x0C, 0x30, 0xDC, 0x00, 0x02, 0x30, 0x99, 0x30, 0xDD, 0x00, 0x02, 0x30, 0x9A, 0x00, 0x01, 
+    0x00, 0x04, 0x30, 0xF7, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0xF8, 0x00, 0x02, 
+    0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0xF9, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 
+    0x30, 0xFA, 0x00, 0x02, 0x30, 0x99, 0x00, 0x01, 0x00, 0x04, 0x30, 0xFE, 0x00, 0x02, 0x30, 0x99, 
+    0x00, 0x01, 0x00, 0x1A, 0x30, 0xA6, 0x30, 0xAB, 0x30, 0xAD, 0x30, 0xAF, 0x30, 0xB1, 0x30, 0xB3, 
+    0x30, 0xB5, 0x30, 0xB7, 0x30, 0xB9, 0x30, 0xBB, 0x30, 0xBD, 0x30, 0xBF, 0x30, 0xC1, 0x30, 0xC4, 
+    0x30, 0xC6, 0x30, 0xC8, 0x30, 0xCF, 0x30, 0xD2, 0x30, 0xD5, 0x30, 0xD8, 0x30, 0xDB, 0x30, 0xEF, 
+    0x30, 0xF0, 0x30, 0xF1, 0x30, 0xF2, 0x30, 0xFD, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 
+    0x00, 0x01, 0x00, 0xFE, 0x00, 0x1F, 0x00, 0x44, 0x00, 0x4A, 0x00, 0x50, 0x00, 0x56, 0x00, 0x5C, 
+    0x00, 0x62, 0x00, 0x68, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x7A, 0x00, 0x80, 0x00, 0x86, 0x00, 0x8C, 
+    0x00, 0x92, 0x00, 0x98, 0x00, 0x9E, 0x00, 0xA4, 0x00, 0xAA, 0x00, 0xB0, 0x00, 0xB6, 0x00, 0xBC, 
+    0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00, 0xD4, 0x00, 0xDA, 0x00, 0xE0, 0x00, 0xE6, 0x00, 0xEC, 
+    0x00, 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x30, 0xAB, 0x30, 0x99, 0x00, 0x02, 0x30, 0xAD, 0x30, 0x99, 
+    0x00, 0x02, 0x30, 0xAF, 0x30, 0x99, 0x00, 0x02, 0x30, 0xB1, 0x30, 0x99, 0x00, 0x02, 0x30, 0xB3, 
+    0x30, 0x99, 0x00, 0x02, 0x30, 0xB5, 0x30, 0x99, 0x00, 0x02, 0x30, 0xB7, 0x30, 0x99, 0x00, 0x02, 
+    0x30, 0xB9, 0x30, 0x99, 0x00, 0x02, 0x30, 0xBB, 0x30, 0x99, 0x00, 0x02, 0x30, 0xBD, 0x30, 0x99, 
+    0x00, 0x02, 0x30, 0xBF, 0x30, 0x99, 0x00, 0x02, 0x30, 0xC1, 0x30, 0x99, 0x00, 0x02, 0x30, 0xC4, 
+    0x30, 0x99, 0x00, 0x02, 0x30, 0xC6, 0x30, 0x99, 0x00, 0x02, 0x30, 0xC8, 0x30, 0x99, 0x00, 0x02, 
+    0x30, 0xCF, 0x30, 0x99, 0x00, 0x02, 0x30, 0xCF, 0x30, 0x9A, 0x00, 0x02, 0x30, 0xD2, 0x30, 0x99, 
+    0x00, 0x02, 0x30, 0xD2, 0x30, 0x9A, 0x00, 0x02, 0x30, 0xD5, 0x30, 0x99, 0x00, 0x02, 0x30, 0xD5, 
+    0x30, 0x9A, 0x00, 0x02, 0x30, 0xD8, 0x30, 0x99, 0x00, 0x02, 0x30, 0xD8, 0x30, 0x9A, 0x00, 0x02, 
+    0x30, 0xDB, 0x30, 0x99, 0x00, 0x02, 0x30, 0xDB, 0x30, 0x9A, 0x00, 0x02, 0x30, 0xA6, 0x30, 0x99, 
+    0x00, 0x02, 0x30, 0xEF, 0x30, 0x99, 0x00, 0x02, 0x30, 0xF0, 0x30, 0x99, 0x00, 0x02, 0x30, 0xF1, 
+    0x30, 0x99, 0x00, 0x02, 0x30, 0xF2, 0x30, 0x99, 0x00, 0x02, 0x30, 0xFD, 0x30, 0x99, 0x00, 0x01, 
+    0x00, 0x1F, 0x30, 0xAC, 0x30, 0xAE, 0x30, 0xB0, 0x30, 0xB2, 0x30, 0xB4, 0x30, 0xB6, 0x30, 0xB8, 
+    0x30, 0xBA, 0x30, 0xBC, 0x30, 0xBE, 0x30, 0xC0, 0x30, 0xC2, 0x30, 0xC5, 0x30, 0xC7, 0x30, 0xC9, 
+    0x30, 0xD0, 0x30, 0xD1, 0x30, 0xD3, 0x30, 0xD4, 0x30, 0xD6, 0x30, 0xD7, 0x30, 0xD9, 0x30, 0xDA, 
+    0x30, 0xDC, 0x30, 0xDD, 0x30, 0xF4, 0x30, 0xF7, 0x30, 0xF8, 0x30, 0xF9, 0x30, 0xFA, 0x30, 0xFE, 
+    0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x1E, 0x9A, 0x00, 0x89, 0x01, 0x18, 
+    0x02, 0x72, 0x02, 0x8C, 0x02, 0xE6, 0x03, 0x18, 0x04, 0x3E, 0x04, 0x48, 0x04, 0x8A, 0x04, 0xC4, 
+    0x05, 0x6A, 0x05, 0x74, 0x05, 0xA6, 0x05, 0xF4, 0x06, 0x16, 0x06, 0x70, 0x08, 0x56, 0x08, 0x70, 
+    0x08, 0xCE, 0x09, 0x42, 0x09, 0x7C, 0x0B, 0x14, 0x0B, 0x26, 0x0B, 0x68, 0x0B, 0x7A, 0x0B, 0xD4, 
+    0x0C, 0x0E, 0x0D, 0x68, 0x0D, 0x82, 0x0D, 0xDC, 0x0E, 0x0E, 0x0F, 0x34, 0x0F, 0x3E, 0x0F, 0x80, 
+    0x0F, 0xC2, 0x10, 0x60, 0x10, 0x72, 0x10, 0xA4, 0x10, 0xF2, 0x11, 0x14, 0x11, 0x6E, 0x13, 0x54, 
+    0x13, 0x6E, 0x13, 0xCC, 0x14, 0x40, 0x14, 0x82, 0x16, 0x1A, 0x16, 0x2C, 0x16, 0x76, 0x16, 0x88, 
+    0x16, 0xEA, 0x17, 0x24, 0x17, 0x5E, 0x17, 0x68, 0x17, 0x7A, 0x17, 0x94, 0x17, 0xA6, 0x17, 0xE0, 
+    0x17, 0xF2, 0x17, 0xFC, 0x18, 0x06, 0x18, 0x40, 0x18, 0x6A, 0x18, 0x74, 0x18, 0x86, 0x18, 0x90, 
+    0x18, 0x9A, 0x18, 0xCC, 0x19, 0x06, 0x19, 0x10, 0x19, 0x22, 0x19, 0x3C, 0x19, 0x4E, 0x19, 0x88, 
+    0x19, 0x9A, 0x19, 0xA4, 0x19, 0xAE, 0x19, 0xE8, 0x1A, 0x12, 0x1A, 0x1C, 0x1A, 0x2E, 0x1A, 0x38, 
+    0x1A, 0x42, 0x1A, 0x74, 0x1A, 0xAE, 0x1A, 0xE8, 0x1A, 0xF2, 0x1A, 0xFC, 0x1B, 0x1E, 0x1B, 0x40, 
+    0x1B, 0x4A, 0x1B, 0x54, 0x1B, 0x7E, 0x1B, 0xA8, 0x1B, 0xB2, 0x1B, 0xBC, 0x1B, 0xC6, 0x1B, 0xD0, 
+    0x1B, 0xEA, 0x1C, 0x04, 0x1C, 0x0E, 0x1C, 0x18, 0x1C, 0x22, 0x1C, 0x5C, 0x1C, 0x96, 0x1C, 0xD0, 
+    0x1D, 0x0A, 0x1D, 0x14, 0x1D, 0x1E, 0x1D, 0x28, 0x1D, 0x32, 0x1D, 0x3C, 0x1D, 0x46, 0x1D, 0x50, 
+    0x1D, 0x5A, 0x1D, 0x64, 0x1D, 0x6E, 0x1D, 0x78, 0x1D, 0x82, 0x1D, 0x8C, 0x1D, 0x96, 0x1D, 0xA0, 
+    0x1D, 0xAA, 0x1D, 0xB4, 0x1D, 0xBE, 0x1D, 0xD0, 0x1D, 0xE2, 0x1D, 0xEC, 0x1D, 0xF6, 0x1E, 0x08, 
+    0x1E, 0x1A, 0x1E, 0x24, 0x1E, 0x2E, 0x1E, 0x38, 0x1E, 0x42, 0x1E, 0x4C, 0x1E, 0x56, 0x1E, 0x88, 
+    0x00, 0x26, 0x00, 0x4E, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 0x00, 0x6A, 0x00, 0x72, 0x00, 0x7A, 
+    0x00, 0x82, 0x00, 0x8A, 0x00, 0x92, 0x00, 0x98, 0x00, 0x9E, 0x00, 0xA4, 0x00, 0xAC, 0x00, 0xB4, 
+    0x00, 0xBC, 0x00, 0xC4, 0x00, 0xCC, 0x00, 0xD4, 0x00, 0xDC, 0x00, 0xE2, 0x00, 0xEA, 0x00, 0xF0, 
+    0x00, 0xF8, 0x00, 0xFE, 0x01, 0x04, 0x01, 0x0C, 0x01, 0x14, 0x01, 0x1A, 0x01, 0x20, 0x01, 0x26, 
+    0x01, 0x2C, 0x01, 0x34, 0x01, 0x3C, 0x01, 0x42, 0x01, 0x48, 0x01, 0x4E, 0x01, 0x54, 0x00, 0xC0, 
+    0x00, 0x02, 0x03, 0x00, 0x00, 0xC1, 0x00, 0x02, 0x03, 0x01, 0x1E, 0xA6, 0x00, 0x03, 0x03, 0x02, 
+    0x03, 0x00, 0x1E, 0xA4, 0x00, 0x03, 0x03, 0x02, 0x03, 0x01, 0x1E, 0xAA, 0x00, 0x03, 0x03, 0x02, 
+    0x03, 0x03, 0x1E, 0xA8, 0x00, 0x03, 0x03, 0x02, 0x03, 0x09, 0x1E, 0xAC, 0x00, 0x03, 0x03, 0x02, 
+    0x03, 0x23, 0x1E, 0xA6, 0x00, 0x03, 0x03, 0x02, 0x03, 0x40, 0x1E, 0xA4, 0x00, 0x03, 0x03, 0x02, 
+    0x03, 0x41, 0x00, 0xC2, 0x00, 0x02, 0x03, 0x02, 0x00, 0xC3, 0x00, 0x02, 0x03, 0x03, 0x01, 0x00, 
+    0x00, 0x02, 0x03, 0x04, 0x1E, 0xB0, 0x00, 0x03, 0x03, 0x06, 0x03, 0x00, 0x1E, 0xAE, 0x00, 0x03, 
+    0x03, 0x06, 0x03, 0x01, 0x1E, 0xB4, 0x00, 0x03, 0x03, 0x06, 0x03, 0x03, 0x1E, 0xB2, 0x00, 0x03, 
+    0x03, 0x06, 0x03, 0x09, 0x1E, 0xB6, 0x00, 0x03, 0x03, 0x06, 0x03, 0x23, 0x1E, 0xB0, 0x00, 0x03, 
+    0x03, 0x06, 0x03, 0x40, 0x1E, 0xAE, 0x00, 0x03, 0x03, 0x06, 0x03, 0x41, 0x01, 0x02, 0x00, 0x02, 
+    0x03, 0x06, 0x01, 0xE0, 0x00, 0x03, 0x03, 0x07, 0x03, 0x04, 0x02, 0x26, 0x00, 0x02, 0x03, 0x07, 
+    0x01, 0xDE, 0x00, 0x03, 0x03, 0x08, 0x03, 0x04, 0x00, 0xC4, 0x00, 0x02, 0x03, 0x08, 0x1E, 0xA2, 
+    0x00, 0x02, 0x03, 0x09, 0x01, 0xFA, 0x00, 0x03, 0x03, 0x0A, 0x03, 0x01, 0x01, 0xFA, 0x00, 0x03, 
+    0x03, 0x0A, 0x03, 0x41, 0x00, 0xC5, 0x00, 0x02, 0x03, 0x0A, 0x01, 0xCD, 0x00, 0x02, 0x03, 0x0C, 
+    0x02, 0x00, 0x00, 0x02, 0x03, 0x0F, 0x02, 0x02, 0x00, 0x02, 0x03, 0x11, 0x1E, 0xAC, 0x00, 0x03, 
+    0x03, 0x23, 0x03, 0x02, 0x1E, 0xB6, 0x00, 0x03, 0x03, 0x23, 0x03, 0x06, 0x1E, 0xA0, 0x00, 0x02, 
+    0x03, 0x23, 0x1E, 0x00, 0x00, 0x02, 0x03, 0x25, 0x01, 0x04, 0x00, 0x02, 0x03, 0x28, 0x00, 0xC0, 
+    0x00, 0x02, 0x03, 0x40, 0x00, 0xC1, 0x00, 0x02, 0x03, 0x41, 0x00, 0x03, 0x00, 0x08, 0x00, 0x0E, 
+    0x00, 0x14, 0x1E, 0x02, 0x00, 0x02, 0x03, 0x07, 0x1E, 0x04, 0x00, 0x02, 0x03, 0x23, 0x1E, 0x06, 
+    0x00, 0x02, 0x03, 0x31, 0x00, 0x0A, 0x00, 0x16, 0x00, 0x1E, 0x00, 0x24, 0x00, 0x2A, 0x00, 0x30, 
+    0x00, 0x36, 0x00, 0x3E, 0x00, 0x46, 0x00, 0x4C, 0x00, 0x54, 0x1E, 0x08, 0x00, 0x03, 0x03, 0x01, 
+    0x03, 0x27, 0x01, 0x06, 0x00, 0x02, 0x03, 0x01, 0x01, 0x08, 0x00, 0x02, 0x03, 0x02, 0x01, 0x0A, 
+    0x00, 0x02, 0x03, 0x07, 0x01, 0x0C, 0x00, 0x02, 0x03, 0x0C, 0x1E, 0x08, 0x00, 0x03, 0x03, 0x27, 
+    0x03, 0x01, 0x1E, 0x08, 0x00, 0x03, 0x03, 0x27, 0x03, 0x41, 0x00, 0xC7, 0x00, 0x02, 0x03, 0x27, 
+    0x1E, 0x08, 0x00, 0x03, 0x03, 0x41, 0x03, 0x27, 0x01, 0x06, 0x00, 0x02, 0x03, 0x41, 0x00, 0x06, 
+    0x00, 0x0E, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00, 0x2C, 0x1E, 0x0A, 0x00, 0x02, 
+    0x03, 0x07, 0x01, 0x0E, 0x00, 0x02, 0x03, 0x0C, 0x1E, 0x0C, 0x00, 0x02, 0x03, 0x23, 0x1E, 0x10, 
+    0x00, 0x02, 0x03, 0x27, 0x1E, 0x12, 0x00, 0x02, 0x03, 0x2D, 0x1E, 0x0E, 0x00, 0x02, 0x03, 0x31, 
+    0x00, 0x21, 0x00, 0x44, 0x00, 0x4A, 0x00, 0x50, 0x00, 0x58, 0x00, 0x60, 0x00, 0x68, 0x00, 0x70, 
+    0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 0x00, 0x8E, 0x00, 0x94, 0x00, 0x9C, 0x00, 0xA4, 0x00, 0xAC, 
+    0x00, 0xB4, 0x00, 0xBA, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00, 0xD4, 0x00, 0xDA, 0x00, 0xE0, 
+    0x00, 0xE6, 0x00, 0xEC, 0x00, 0xF4, 0x00, 0xFA, 0x01, 0x02, 0x01, 0x08, 0x01, 0x0E, 0x01, 0x14, 
+    0x01, 0x1A, 0x01, 0x20, 0x00, 0xC8, 0x00, 0x02, 0x03, 0x00, 0x00, 0xC9, 0x00, 0x02, 0x03, 0x01, 
+    0x1E, 0xC0, 0x00, 0x03, 0x03, 0x02, 0x03, 0x00, 0x1E, 0xBE, 0x00, 0x03, 0x03, 0x02, 0x03, 0x01, 
+    0x1E, 0xC4, 0x00, 0x03, 0x03, 0x02, 0x03, 0x03, 0x1E, 0xC2, 0x00, 0x03, 0x03, 0x02, 0x03, 0x09, 
+    0x1E, 0xC6, 0x00, 0x03, 0x03, 0x02, 0x03, 0x23, 0x1E, 0xC0, 0x00, 0x03, 0x03, 0x02, 0x03, 0x40, 
+    0x1E, 0xBE, 0x00, 0x03, 0x03, 0x02, 0x03, 0x41, 0x00, 0xCA, 0x00, 0x02, 0x03, 0x02, 0x1E, 0xBC, 
+    0x00, 0x02, 0x03, 0x03, 0x1E, 0x14, 0x00, 0x03, 0x03, 0x04, 0x03, 0x00, 0x1E, 0x16, 0x00, 0x03, 
+    0x03, 0x04, 0x03, 0x01, 0x1E, 0x14, 0x00, 0x03, 0x03, 0x04, 0x03, 0x40, 0x1E, 0x16, 0x00, 0x03, 
+    0x03, 0x04, 0x03, 0x41, 0x01, 0x12, 0x00, 0x02, 0x03, 0x04, 0x1E, 0x1C, 0x00, 0x03, 0x03, 0x06, 
+    0x03, 0x27, 0x01, 0x14, 0x00, 0x02, 0x03, 0x06, 0x01, 0x16, 0x00, 0x02, 0x03, 0x07, 0x00, 0xCB, 
+    0x00, 0x02, 0x03, 0x08, 0x1E, 0xBA, 0x00, 0x02, 0x03, 0x09, 0x01, 0x1A, 0x00, 0x02, 0x03, 0x0C, 
+    0x02, 0x04, 0x00, 0x02, 0x03, 0x0F, 0x02, 0x06, 0x00, 0x02, 0x03, 0x11, 0x1E, 0xC6, 0x00, 0x03, 
+    0x03, 0x23, 0x03, 0x02, 0x1E, 0xB8, 0x00, 0x02, 0x03, 0x23, 0x1E, 0x1C, 0x00, 0x03, 0x03, 0x27, 
+    0x03, 0x06, 0x02, 0x28, 0x00, 0x02, 0x03, 0x27, 0x01, 0x18, 0x00, 0x02, 0x03, 0x28, 0x1E, 0x18, 
+    0x00, 0x02, 0x03, 0x2D, 0x1E, 0x1A, 0x00, 0x02, 0x03, 0x30, 0x00, 0xC8, 0x00, 0x02, 0x03, 0x40, 
+    0x00, 0xC9, 0x00, 0x02, 0x03, 0x41, 0x00, 0x01, 0x00, 0x04, 0x1E, 0x1E, 0x00, 0x02, 0x03, 0x07, 
+    0x00, 0x08, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x36, 
+    0x00, 0x3C, 0x01, 0xF4, 0x00, 0x02, 0x03, 0x01, 0x01, 0x1C, 0x00, 0x02, 0x03, 0x02, 0x1E, 0x20, 
+    0x00, 0x02, 0x03, 0x04, 0x01, 0x1E, 0x00, 0x02, 0x03, 0x06, 0x01, 0x20, 0x00, 0x02, 0x03, 0x07, 
+    0x01, 0xE6, 0x00, 0x02, 0x03, 0x0C, 0x01, 0x22, 0x00, 0x02, 0x03, 0x27, 0x01, 0xF4, 0x00, 0x02, 
+    0x03, 0x41, 0x00, 0x07, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2E, 
+    0x00, 0x34, 0x01, 0x24, 0x00, 0x02, 0x03, 0x02, 0x1E, 0x22, 0x00, 0x02, 0x03, 0x07, 0x1E, 0x26, 
+    0x00, 0x02, 0x03, 0x08, 0x02, 0x1E, 0x00, 0x02, 0x03, 0x0C, 0x1E, 0x24, 0x00, 0x02, 0x03, 0x23, 
+    0x1E, 0x28, 0x00, 0x02, 0x03, 0x27, 0x1E, 0x2A, 0x00, 0x02, 0x03, 0x2E, 0x00, 0x14, 0x00, 0x2A, 
+    0x00, 0x30, 0x00, 0x36, 0x00, 0x3C, 0x00, 0x42, 0x00, 0x48, 0x00, 0x4E, 0x00, 0x54, 0x00, 0x5C, 
+    0x00, 0x64, 0x00, 0x6A, 0x00, 0x70, 0x00, 0x76, 0x00, 0x7C, 0x00, 0x82, 0x00, 0x88, 0x00, 0x8E, 
+    0x00, 0x94, 0x00, 0x9A, 0x00, 0xA0, 0x00, 0xCC, 0x00, 0x02, 0x03, 0x00, 0x00, 0xCD, 0x00, 0x02, 
+    0x03, 0x01, 0x00, 0xCE, 0x00, 0x02, 0x03, 0x02, 0x01, 0x28, 0x00, 0x02, 0x03, 0x03, 0x01, 0x2A, 
+    0x00, 0x02, 0x03, 0x04, 0x01, 0x2C, 0x00, 0x02, 0x03, 0x06, 0x01, 0x30, 0x00, 0x02, 0x03, 0x07, 
+    0x1E, 0x2E, 0x00, 0x03, 0x03, 0x08, 0x03, 0x01, 0x1E, 0x2E, 0x00, 0x03, 0x03, 0x08, 0x03, 0x41, 
+    0x00, 0xCF, 0x00, 0x02, 0x03, 0x08, 0x1E, 0xC8, 0x00, 0x02, 0x03, 0x09, 0x01, 0xCF, 0x00, 0x02, 
+    0x03, 0x0C, 0x02, 0x08, 0x00, 0x02, 0x03, 0x0F, 0x02, 0x0A, 0x00, 0x02, 0x03, 0x11, 0x1E, 0xCA, 
+    0x00, 0x02, 0x03, 0x23, 0x01, 0x2E, 0x00, 0x02, 0x03, 0x28, 0x1E, 0x2C, 0x00, 0x02, 0x03, 0x30, 
+    0x00, 0xCC, 0x00, 0x02, 0x03, 0x40, 0x00, 0xCD, 0x00, 0x02, 0x03, 0x41, 0x1E, 0x2E, 0x00, 0x02, 
+    0x03, 0x44, 0x00, 0x01, 0x00, 0x04, 0x01, 0x34, 0x00, 0x02, 0x03, 0x02, 0x00, 0x06, 0x00, 0x0E, 
+    0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00, 0x2C, 0x1E, 0x30, 0x00, 0x02, 0x03, 0x01, 
+    0x01, 0xE8, 0x00, 0x02, 0x03, 0x0C, 0x1E, 0x32, 0x00, 0x02, 0x03, 0x23, 0x01, 0x36, 0x00, 0x02, 
+    0x03, 0x27, 0x1E, 0x34, 0x00, 0x02, 0x03, 0x31, 0x1E, 0x30, 0x00, 0x02, 0x03, 0x41, 0x00, 0x09, 
+    0x00, 0x14, 0x00, 0x1A, 0x00, 0x22, 0x00, 0x28, 0x00, 0x30, 0x00, 0x36, 0x00, 0x3C, 0x00, 0x42, 
+    0x00, 0x48, 0x01, 0x39, 0x00, 0x02, 0x03, 0x01, 0x1E, 0x38, 0x00, 0x03, 0x03, 0x04, 0x03, 0x23, 
+    0x01, 0x3D, 0x00, 0x02, 0x03, 0x0C, 0x1E, 0x38, 0x00, 0x03, 0x03, 0x23, 0x03, 0x04, 0x1E, 0x36, 
+    0x00, 0x02, 0x03, 0x23, 0x01, 0x3B, 0x00, 0x02, 0x03, 0x27, 0x1E, 0x3C, 0x00, 0x02, 0x03, 0x2D, 
+    0x1E, 0x3A, 0x00, 0x02, 0x03, 0x31, 0x01, 0x39, 0x00, 0x02, 0x03, 0x41, 0x00, 0x04, 0x00, 0x0A, 
+    0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 0x1E, 0x3E, 0x00, 0x02, 0x03, 0x01, 0x1E, 0x40, 0x00, 0x02, 
+    0x03, 0x07, 0x1E, 0x42, 0x00, 0x02, 0x03, 0x23, 0x1E, 0x3E, 0x00, 0x02, 0x03, 0x41, 0x00, 0x0B, 
+    0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x36, 0x00, 0x3C, 0x00, 0x42, 
+    0x00, 0x48, 0x00, 0x4E, 0x00, 0x54, 0x01, 0xF8, 0x00, 0x02, 0x03, 0x00, 0x01, 0x43, 0x00, 0x02, 
+    0x03, 0x01, 0x00, 0xD1, 0x00, 0x02, 0x03, 0x03, 0x1E, 0x44, 0x00, 0x02, 0x03, 0x07, 0x01, 0x47, 
+    0x00, 0x02, 0x03, 0x0C, 0x1E, 0x46, 0x00, 0x02, 0x03, 0x23, 0x01, 0x45, 0x00, 0x02, 0x03, 0x27, 
+    0x1E, 0x4A, 0x00, 0x02, 0x03, 0x2D, 0x1E, 0x48, 0x00, 0x02, 0x03, 0x31, 0x01, 0xF8, 0x00, 0x02, 
+    0x03, 0x40, 0x01, 0x43, 0x00, 0x02, 0x03, 0x41, 0x00, 0x34, 0x00, 0x6A, 0x00, 0x72, 0x00, 0x78, 
+    0x00, 0x80, 0x00, 0x86, 0x00, 0x8E, 0x00, 0x96, 0x00, 0x9E, 0x00, 0xA6, 0x00, 0xAE, 0x00, 0xB6, 
+    0x00, 0xBE, 0x00, 0xC4, 0x00, 0xCC, 0x00, 0xD4, 0x00, 0xDC, 0x00, 0xE4, 0x00, 0xEC, 0x00, 0xF2, 
+    0x00, 0xFA, 0x01, 0x02, 0x01, 0x0A, 0x01, 0x12, 0x01, 0x1A, 0x01, 0x20, 0x01, 0x26, 0x01, 0x2E, 
+    0x01, 0x34, 0x01, 0x3C, 0x01, 0x42, 0x01, 0x4A, 0x01, 0x50, 0x01, 0x56, 0x01, 0x5C, 0x01, 0x62, 
+    0x01, 0x68, 0x01, 0x70, 0x01, 0x78, 0x01, 0x80, 0x01, 0x88, 0x01, 0x90, 0x01, 0x98, 0x01, 0xA0, 
+    0x01, 0xA6, 0x01, 0xAE, 0x01, 0xB6, 0x01, 0xBC, 0x01, 0xC4, 0x01, 0xCA, 0x01, 0xD2, 0x01, 0xD8, 
+    0x01, 0xE0, 0x1E, 0xDC, 0x00, 0x03, 0x03, 0x00, 0x03, 0x1B, 0x00, 0xD2, 0x00, 0x02, 0x03, 0x00, 
+    0x1E, 0xDA, 0x00, 0x03, 0x03, 0x01, 0x03, 0x1B, 0x00, 0xD3, 0x00, 0x02, 0x03, 0x01, 0x1E, 0xD2, 
+    0x00, 0x03, 0x03, 0x02, 0x03, 0x00, 0x1E, 0xD0, 0x00, 0x03, 0x03, 0x02, 0x03, 0x01, 0x1E, 0xD6, 
+    0x00, 0x03, 0x03, 0x02, 0x03, 0x03, 0x1E, 0xD4, 0x00, 0x03, 0x03, 0x02, 0x03, 0x09, 0x1E, 0xD8, 
+    0x00, 0x03, 0x03, 0x02, 0x03, 0x23, 0x1E, 0xD2, 0x00, 0x03, 0x03, 0x02, 0x03, 0x40, 0x1E, 0xD0, 
+    0x00, 0x03, 0x03, 0x02, 0x03, 0x41, 0x00, 0xD4, 0x00, 0x02, 0x03, 0x02, 0x1E, 0x4C, 0x00, 0x03, 
+    0x03, 0x03, 0x03, 0x01, 0x02, 0x2C, 0x00, 0x03, 0x03, 0x03, 0x03, 0x04, 0x1E, 0x4E, 0x00, 0x03, 
+    0x03, 0x03, 0x03, 0x08, 0x1E, 0xE0, 0x00, 0x03, 0x03, 0x03, 0x03, 0x1B, 0x1E, 0x4C, 0x00, 0x03, 
+    0x03, 0x03, 0x03, 0x41, 0x00, 0xD5, 0x00, 0x02, 0x03, 0x03, 0x1E, 0x50, 0x00, 0x03, 0x03, 0x04, 
+    0x03, 0x00, 0x1E, 0x52, 0x00, 0x03, 0x03, 0x04, 0x03, 0x01, 0x01, 0xEC, 0x00, 0x03, 0x03, 0x04, 
+    0x03, 0x28, 0x1E, 0x50, 0x00, 0x03, 0x03, 0x04, 0x03, 0x40, 0x1E, 0x52, 0x00, 0x03, 0x03, 0x04, 
+    0x03, 0x41, 0x01, 0x4C, 0x00, 0x02, 0x03, 0x04, 0x01, 0x4E, 0x00, 0x02, 0x03, 0x06, 0x02, 0x30, 
+    0x00, 0x03, 0x03, 0x07, 0x03, 0x04, 0x02, 0x2E, 0x00, 0x02, 0x03, 0x07, 0x02, 0x2A, 0x00, 0x03, 
+    0x03, 0x08, 0x03, 0x04, 0x00, 0xD6, 0x00, 0x02, 0x03, 0x08, 0x1E, 0xDE, 0x00, 0x03, 0x03, 0x09, 
+    0x03, 0x1B, 0x1E, 0xCE, 0x00, 0x02, 0x03, 0x09, 0x01, 0x50, 0x00, 0x02, 0x03, 0x0B, 0x01, 0xD1, 
+    0x00, 0x02, 0x03, 0x0C, 0x02, 0x0C, 0x00, 0x02, 0x03, 0x0F, 0x02, 0x0E, 0x00, 0x02, 0x03, 0x11, 
+    0x1E, 0xDC, 0x00, 0x03, 0x03, 0x1B, 0x03, 0x00, 0x1E, 0xDA, 0x00, 0x03, 0x03, 0x1B, 0x03, 0x01, 
+    0x1E, 0xE0, 0x00, 0x03, 0x03, 0x1B, 0x03, 0x03, 0x1E, 0xDE, 0x00, 0x03, 0x03, 0x1B, 0x03, 0x09, 
+    0x1E, 0xE2, 0x00, 0x03, 0x03, 0x1B, 0x03, 0x23, 0x1E, 0xDC, 0x00, 0x03, 0x03, 0x1B, 0x03, 0x40, 
+    0x1E, 0xDA, 0x00, 0x03, 0x03, 0x1B, 0x03, 0x41, 0x01, 0xA0, 0x00, 0x02, 0x03, 0x1B, 0x1E, 0xD8, 
+    0x00, 0x03, 0x03, 0x23, 0x03, 0x02, 0x1E, 0xE2, 0x00, 0x03, 0x03, 0x23, 0x03, 0x1B, 0x1E, 0xCC, 
+    0x00, 0x02, 0x03, 0x23, 0x01, 0xEC, 0x00, 0x03, 0x03, 0x28, 0x03, 0x04, 0x01, 0xEA, 0x00, 0x02, 
+    0x03, 0x28, 0x1E, 0xDC, 0x00, 0x03, 0x03, 0x40, 0x03, 0x1B, 0x00, 0xD2, 0x00, 0x02, 0x03, 0x40, 
+    0x1E, 0xDA, 0x00, 0x03, 0x03, 0x41, 0x03, 0x1B, 0x00, 0xD3, 0x00, 0x02, 0x03, 0x41, 0x00, 0x03, 
+    0x00, 0x08, 0x00, 0x0E, 0x00, 0x14, 0x1E, 0x54, 0x00, 0x02, 0x03, 0x01, 0x1E, 0x56, 0x00, 0x02, 
+    0x03, 0x07, 0x1E, 0x54, 0x00, 0x02, 0x03, 0x41, 0x00, 0x0B, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x26, 
+    0x00, 0x2C, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x46, 0x00, 0x4C, 0x00, 0x52, 0x00, 0x58, 
+    0x01, 0x54, 0x00, 0x02, 0x03, 0x01, 0x1E, 0x5C, 0x00, 0x03, 0x03, 0x04, 0x03, 0x23, 0x1E, 0x58, 
+    0x00, 0x02, 0x03, 0x07, 0x01, 0x58, 0x00, 0x02, 0x03, 0x0C, 0x02, 0x10, 0x00, 0x02, 0x03, 0x0F, 
+    0x02, 0x12, 0x00, 0x02, 0x03, 0x11, 0x1E, 0x5C, 0x00, 0x03, 0x03, 0x23, 0x03, 0x04, 0x1E, 0x5A, 
+    0x00, 0x02, 0x03, 0x23, 0x01, 0x56, 0x00, 0x02, 0x03, 0x27, 0x1E, 0x5E, 0x00, 0x02, 0x03, 0x31, 
+    0x01, 0x54, 0x00, 0x02, 0x03, 0x41, 0x00, 0x0D, 0x00, 0x1C, 0x00, 0x24, 0x00, 0x2A, 0x00, 0x30, 
+    0x00, 0x38, 0x00, 0x3E, 0x00, 0x46, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x60, 0x00, 0x66, 
+    0x00, 0x6E, 0x1E, 0x64, 0x00, 0x03, 0x03, 0x01, 0x03, 0x07, 0x01, 0x5A, 0x00, 0x02, 0x03, 0x01, 
+    0x01, 0x5C, 0x00, 0x02, 0x03, 0x02, 0x1E, 0x68, 0x00, 0x03, 0x03, 0x07, 0x03, 0x23, 0x1E, 0x60, 
+    0x00, 0x02, 0x03, 0x07, 0x1E, 0x66, 0x00, 0x03, 0x03, 0x0C, 0x03, 0x07, 0x01, 0x60, 0x00, 0x02, 
+    0x03, 0x0C, 0x1E, 0x68, 0x00, 0x03, 0x03, 0x23, 0x03, 0x07, 0x1E, 0x62, 0x00, 0x02, 0x03, 0x23, 
+    0x02, 0x18, 0x00, 0x02, 0x03, 0x26, 0x01, 0x5E, 0x00, 0x02, 0x03, 0x27, 0x1E, 0x64, 0x00, 0x03, 
+    0x03, 0x41, 0x03, 0x07, 0x01, 0x5A, 0x00, 0x02, 0x03, 0x41, 0x00, 0x07, 0x00, 0x10, 0x00, 0x16, 
+    0x00, 0x1C, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0x1E, 0x6A, 0x00, 0x02, 0x03, 0x07, 
+    0x01, 0x64, 0x00, 0x02, 0x03, 0x0C, 0x1E, 0x6C, 0x00, 0x02, 0x03, 0x23, 0x02, 0x1A, 0x00, 0x02, 
+    0x03, 0x26, 0x01, 0x62, 0x00, 0x02, 0x03, 0x27, 0x1E, 0x70, 0x00, 0x02, 0x03, 0x2D, 0x1E, 0x6E, 
+    0x00, 0x02, 0x03, 0x31, 0x00, 0x2D, 0x00, 0x5C, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x72, 0x00, 0x78, 
+    0x00, 0x7E, 0x00, 0x86, 0x00, 0x8E, 0x00, 0x96, 0x00, 0x9C, 0x00, 0xA4, 0x00, 0xAA, 0x00, 0xB0, 
+    0x00, 0xB8, 0x00, 0xC0, 0x00, 0xC8, 0x00, 0xD0, 0x00, 0xD8, 0x00, 0xE0, 0x00, 0xE6, 0x00, 0xEE, 
+    0x00, 0xF4, 0x00, 0xFA, 0x01, 0x00, 0x01, 0x06, 0x01, 0x0C, 0x01, 0x12, 0x01, 0x1A, 0x01, 0x22, 
+    0x01, 0x2A, 0x01, 0x32, 0x01, 0x3A, 0x01, 0x42, 0x01, 0x4A, 0x01, 0x50, 0x01, 0x58, 0x01, 0x5E, 
+    0x01, 0x64, 0x01, 0x6A, 0x01, 0x70, 0x01, 0x76, 0x01, 0x7E, 0x01, 0x84, 0x01, 0x8C, 0x01, 0x92, 
+    0x1E, 0xEA, 0x00, 0x03, 0x03, 0x00, 0x03, 0x1B, 0x00, 0xD9, 0x00, 0x02, 0x03, 0x00, 0x1E, 0xE8, 
+    0x00, 0x03, 0x03, 0x01, 0x03, 0x1B, 0x00, 0xDA, 0x00, 0x02, 0x03, 0x01, 0x00, 0xDB, 0x00, 0x02, 
+    0x03, 0x02, 0x1E, 0x78, 0x00, 0x03, 0x03, 0x03, 0x03, 0x01, 0x1E, 0xEE, 0x00, 0x03, 0x03, 0x03, 
+    0x03, 0x1B, 0x1E, 0x78, 0x00, 0x03, 0x03, 0x03, 0x03, 0x41, 0x01, 0x68, 0x00, 0x02, 0x03, 0x03, 
+    0x1E, 0x7A, 0x00, 0x03, 0x03, 0x04, 0x03, 0x08, 0x01, 0x6A, 0x00, 0x02, 0x03, 0x04, 0x01, 0x6C, 
+    0x00, 0x02, 0x03, 0x06, 0x01, 0xDB, 0x00, 0x03, 0x03, 0x08, 0x03, 0x00, 0x01, 0xD7, 0x00, 0x03, 
+    0x03, 0x08, 0x03, 0x01, 0x01, 0xD5, 0x00, 0x03, 0x03, 0x08, 0x03, 0x04, 0x01, 0xD9, 0x00, 0x03, 
+    0x03, 0x08, 0x03, 0x0C, 0x01, 0xDB, 0x00, 0x03, 0x03, 0x08, 0x03, 0x40, 0x01, 0xD7, 0x00, 0x03, 
+    0x03, 0x08, 0x03, 0x41, 0x00, 0xDC, 0x00, 0x02, 0x03, 0x08, 0x1E, 0xEC, 0x00, 0x03, 0x03, 0x09, 
+    0x03, 0x1B, 0x1E, 0xE6, 0x00, 0x02, 0x03, 0x09, 0x01, 0x6E, 0x00, 0x02, 0x03, 0x0A, 0x01, 0x70, 
+    0x00, 0x02, 0x03, 0x0B, 0x01, 0xD3, 0x00, 0x02, 0x03, 0x0C, 0x02, 0x14, 0x00, 0x02, 0x03, 0x0F, 
+    0x02, 0x16, 0x00, 0x02, 0x03, 0x11, 0x1E, 0xEA, 0x00, 0x03, 0x03, 0x1B, 0x03, 0x00, 0x1E, 0xE8, 
+    0x00, 0x03, 0x03, 0x1B, 0x03, 0x01, 0x1E, 0xEE, 0x00, 0x03, 0x03, 0x1B, 0x03, 0x03, 0x1E, 0xEC, 
+    0x00, 0x03, 0x03, 0x1B, 0x03, 0x09, 0x1E, 0xF0, 0x00, 0x03, 0x03, 0x1B, 0x03, 0x23, 0x1E, 0xEA, 
+    0x00, 0x03, 0x03, 0x1B, 0x03, 0x40, 0x1E, 0xE8, 0x00, 0x03, 0x03, 0x1B, 0x03, 0x41, 0x01, 0xAF, 
+    0x00, 0x02, 0x03, 0x1B, 0x1E, 0xF0, 0x00, 0x03, 0x03, 0x23, 0x03, 0x1B, 0x1E, 0xE4, 0x00, 0x02, 
+    0x03, 0x23, 0x1E, 0x72, 0x00, 0x02, 0x03, 0x24, 0x01, 0x72, 0x00, 0x02, 0x03, 0x28, 0x1E, 0x76, 
+    0x00, 0x02, 0x03, 0x2D, 0x1E, 0x74, 0x00, 0x02, 0x03, 0x30, 0x1E, 0xEA, 0x00, 0x03, 0x03, 0x40, 
+    0x03, 0x1B, 0x00, 0xD9, 0x00, 0x02, 0x03, 0x40, 0x1E, 0xE8, 0x00, 0x03, 0x03, 0x41, 0x03, 0x1B, 
+    0x00, 0xDA, 0x00, 0x02, 0x03, 0x41, 0x01, 0xD7, 0x00, 0x02, 0x03, 0x44, 0x00, 0x02, 0x00, 0x06, 
+    0x00, 0x0C, 0x1E, 0x7C, 0x00, 0x02, 0x03, 0x03, 0x1E, 0x7E, 0x00, 0x02, 0x03, 0x23, 0x00, 0x08, 
+    0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x36, 0x00, 0x3C, 
+    0x1E, 0x80, 0x00, 0x02, 0x03, 0x00, 0x1E, 0x82, 0x00, 0x02, 0x03, 0x01, 0x01, 0x74, 0x00, 0x02, 
+    0x03, 0x02, 0x1E, 0x86, 0x00, 0x02, 0x03, 0x07, 0x1E, 0x84, 0x00, 0x02, 0x03, 0x08, 0x1E, 0x88, 
+    0x00, 0x02, 0x03, 0x23, 0x1E, 0x80, 0x00, 0x02, 0x03, 0x40, 0x1E, 0x82, 0x00, 0x02, 0x03, 0x41, 
+    0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x1E, 0x8A, 0x00, 0x02, 0x03, 0x07, 0x1E, 0x8C, 0x00, 0x02, 
+    0x03, 0x08, 0x00, 0x0B, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x36, 
+    0x00, 0x3C, 0x00, 0x42, 0x00, 0x48, 0x00, 0x4E, 0x00, 0x54, 0x1E, 0xF2, 0x00, 0x02, 0x03, 0x00, 
+    0x00, 0xDD, 0x00, 0x02, 0x03, 0x01, 0x01, 0x76, 0x00, 0x02, 0x03, 0x02, 0x1E, 0xF8, 0x00, 0x02, 
+    0x03, 0x03, 0x02, 0x32, 0x00, 0x02, 0x03, 0x04, 0x1E, 0x8E, 0x00, 0x02, 0x03, 0x07, 0x01, 0x78, 
+    0x00, 0x02, 0x03, 0x08, 0x1E, 0xF6, 0x00, 0x02, 0x03, 0x09, 0x1E, 0xF4, 0x00, 0x02, 0x03, 0x23, 
+    0x1E, 0xF2, 0x00, 0x02, 0x03, 0x40, 0x00, 0xDD, 0x00, 0x02, 0x03, 0x41, 0x00, 0x07, 0x00, 0x10, 
+    0x00, 0x16, 0x00, 0x1C, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0x01, 0x79, 0x00, 0x02, 
+    0x03, 0x01, 0x1E, 0x90, 0x00, 0x02, 0x03, 0x02, 0x01, 0x7B, 0x00, 0x02, 0x03, 0x07, 0x01, 0x7D, 
+    0x00, 0x02, 0x03, 0x0C, 0x1E, 0x92, 0x00, 0x02, 0x03, 0x23, 0x1E, 0x94, 0x00, 0x02, 0x03, 0x31, 
+    0x01, 0x79, 0x00, 0x02, 0x03, 0x41, 0x00, 0x26, 0x00, 0x4E, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x62, 
+    0x00, 0x6A, 0x00, 0x72, 0x00, 0x7A, 0x00, 0x82, 0x00, 0x8A, 0x00, 0x92, 0x00, 0x98, 0x00, 0x9E, 
+    0x00, 0xA4, 0x00, 0xAC, 0x00, 0xB4, 0x00, 0xBC, 0x00, 0xC4, 0x00, 0xCC, 0x00, 0xD4, 0x00, 0xDC, 
+    0x00, 0xE2, 0x00, 0xEA, 0x00, 0xF0, 0x00, 0xF8, 0x00, 0xFE, 0x01, 0x04, 0x01, 0x0C, 0x01, 0x14, 
+    0x01, 0x1A, 0x01, 0x20, 0x01, 0x26, 0x01, 0x2C, 0x01, 0x34, 0x01, 0x3C, 0x01, 0x42, 0x01, 0x48, 
+    0x01, 0x4E, 0x01, 0x54, 0x00, 0xE0, 0x00, 0x02, 0x03, 0x00, 0x00, 0xE1, 0x00, 0x02, 0x03, 0x01, 
+    0x1E, 0xA7, 0x00, 0x03, 0x03, 0x02, 0x03, 0x00, 0x1E, 0xA5, 0x00, 0x03, 0x03, 0x02, 0x03, 0x01, 
+    0x1E, 0xAB, 0x00, 0x03, 0x03, 0x02, 0x03, 0x03, 0x1E, 0xA9, 0x00, 0x03, 0x03, 0x02, 0x03, 0x09, 
+    0x1E, 0xAD, 0x00, 0x03, 0x03, 0x02, 0x03, 0x23, 0x1E, 0xA7, 0x00, 0x03, 0x03, 0x02, 0x03, 0x40, 
+    0x1E, 0xA5, 0x00, 0x03, 0x03, 0x02, 0x03, 0x41, 0x00, 0xE2, 0x00, 0x02, 0x03, 0x02, 0x00, 0xE3, 
+    0x00, 0x02, 0x03, 0x03, 0x01, 0x01, 0x00, 0x02, 0x03, 0x04, 0x1E, 0xB1, 0x00, 0x03, 0x03, 0x06, 
+    0x03, 0x00, 0x1E, 0xAF, 0x00, 0x03, 0x03, 0x06, 0x03, 0x01, 0x1E, 0xB5, 0x00, 0x03, 0x03, 0x06, 
+    0x03, 0x03, 0x1E, 0xB3, 0x00, 0x03, 0x03, 0x06, 0x03, 0x09, 0x1E, 0xB7, 0x00, 0x03, 0x03, 0x06, 
+    0x03, 0x23, 0x1E, 0xB1, 0x00, 0x03, 0x03, 0x06, 0x03, 0x40, 0x1E, 0xAF, 0x00, 0x03, 0x03, 0x06, 
+    0x03, 0x41, 0x01, 0x03, 0x00, 0x02, 0x03, 0x06, 0x01, 0xE1, 0x00, 0x03, 0x03, 0x07, 0x03, 0x04, 
+    0x02, 0x27, 0x00, 0x02, 0x03, 0x07, 0x01, 0xDF, 0x00, 0x03, 0x03, 0x08, 0x03, 0x04, 0x00, 0xE4, 
+    0x00, 0x02, 0x03, 0x08, 0x1E, 0xA3, 0x00, 0x02, 0x03, 0x09, 0x01, 0xFB, 0x00, 0x03, 0x03, 0x0A, 
+    0x03, 0x01, 0x01, 0xFB, 0x00, 0x03, 0x03, 0x0A, 0x03, 0x41, 0x00, 0xE5, 0x00, 0x02, 0x03, 0x0A, 
+    0x01, 0xCE, 0x00, 0x02, 0x03, 0x0C, 0x02, 0x01, 0x00, 0x02, 0x03, 0x0F, 0x02, 0x03, 0x00, 0x02, 
+    0x03, 0x11, 0x1E, 0xAD, 0x00, 0x03, 0x03, 0x23, 0x03, 0x02, 0x1E, 0xB7, 0x00, 0x03, 0x03, 0x23, 
+    0x03, 0x06, 0x1E, 0xA1, 0x00, 0x02, 0x03, 0x23, 0x1E, 0x01, 0x00, 0x02, 0x03, 0x25, 0x01, 0x05, 
+    0x00, 0x02, 0x03, 0x28, 0x00, 0xE0, 0x00, 0x02, 0x03, 0x40, 0x00, 0xE1, 0x00, 0x02, 0x03, 0x41, 
+    0x00, 0x03, 0x00, 0x08, 0x00, 0x0E, 0x00, 0x14, 0x1E, 0x03, 0x00, 0x02, 0x03, 0x07, 0x1E, 0x05, 
+    0x00, 0x02, 0x03, 0x23, 0x1E, 0x07, 0x00, 0x02, 0x03, 0x31, 0x00, 0x0A, 0x00, 0x16, 0x00, 0x1E, 
+    0x00, 0x24, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x36, 0x00, 0x3E, 0x00, 0x46, 0x00, 0x4C, 0x00, 0x54, 
+    0x1E, 0x09, 0x00, 0x03, 0x03, 0x01, 0x03, 0x27, 0x01, 0x07, 0x00, 0x02, 0x03, 0x01, 0x01, 0x09, 
+    0x00, 0x02, 0x03, 0x02, 0x01, 0x0B, 0x00, 0x02, 0x03, 0x07, 0x01, 0x0D, 0x00, 0x02, 0x03, 0x0C, 
+    0x1E, 0x09, 0x00, 0x03, 0x03, 0x27, 0x03, 0x01, 0x1E, 0x09, 0x00, 0x03, 0x03, 0x27, 0x03, 0x41, 
+    0x00, 0xE7, 0x00, 0x02, 0x03, 0x27, 0x1E, 0x09, 0x00, 0x03, 0x03, 0x41, 0x03, 0x27, 0x01, 0x07, 
+    0x00, 0x02, 0x03, 0x41, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 
+    0x00, 0x2C, 0x1E, 0x0B, 0x00, 0x02, 0x03, 0x07, 0x01, 0x0F, 0x00, 0x02, 0x03, 0x0C, 0x1E, 0x0D, 
+    0x00, 0x02, 0x03, 0x23, 0x1E, 0x11, 0x00, 0x02, 0x03, 0x27, 0x1E, 0x13, 0x00, 0x02, 0x03, 0x2D, 
+    0x1E, 0x0F, 0x00, 0x02, 0x03, 0x31, 0x00, 0x21, 0x00, 0x44, 0x00, 0x4A, 0x00, 0x50, 0x00, 0x58, 
+    0x00, 0x60, 0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 0x00, 0x8E, 0x00, 0x94, 
+    0x00, 0x9C, 0x00, 0xA4, 0x00, 0xAC, 0x00, 0xB4, 0x00, 0xBA, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 
+    0x00, 0xD4, 0x00, 0xDA, 0x00, 0xE0, 0x00, 0xE6, 0x00, 0xEC, 0x00, 0xF4, 0x00, 0xFA, 0x01, 0x02, 
+    0x01, 0x08, 0x01, 0x0E, 0x01, 0x14, 0x01, 0x1A, 0x01, 0x20, 0x00, 0xE8, 0x00, 0x02, 0x03, 0x00, 
+    0x00, 0xE9, 0x00, 0x02, 0x03, 0x01, 0x1E, 0xC1, 0x00, 0x03, 0x03, 0x02, 0x03, 0x00, 0x1E, 0xBF, 
+    0x00, 0x03, 0x03, 0x02, 0x03, 0x01, 0x1E, 0xC5, 0x00, 0x03, 0x03, 0x02, 0x03, 0x03, 0x1E, 0xC3, 
+    0x00, 0x03, 0x03, 0x02, 0x03, 0x09, 0x1E, 0xC7, 0x00, 0x03, 0x03, 0x02, 0x03, 0x23, 0x1E, 0xC1, 
+    0x00, 0x03, 0x03, 0x02, 0x03, 0x40, 0x1E, 0xBF, 0x00, 0x03, 0x03, 0x02, 0x03, 0x41, 0x00, 0xEA, 
+    0x00, 0x02, 0x03, 0x02, 0x1E, 0xBD, 0x00, 0x02, 0x03, 0x03, 0x1E, 0x15, 0x00, 0x03, 0x03, 0x04, 
+    0x03, 0x00, 0x1E, 0x17, 0x00, 0x03, 0x03, 0x04, 0x03, 0x01, 0x1E, 0x15, 0x00, 0x03, 0x03, 0x04, 
+    0x03, 0x40, 0x1E, 0x17, 0x00, 0x03, 0x03, 0x04, 0x03, 0x41, 0x01, 0x13, 0x00, 0x02, 0x03, 0x04, 
+    0x1E, 0x1D, 0x00, 0x03, 0x03, 0x06, 0x03, 0x27, 0x01, 0x15, 0x00, 0x02, 0x03, 0x06, 0x01, 0x17, 
+    0x00, 0x02, 0x03, 0x07, 0x00, 0xEB, 0x00, 0x02, 0x03, 0x08, 0x1E, 0xBB, 0x00, 0x02, 0x03, 0x09, 
+    0x01, 0x1B, 0x00, 0x02, 0x03, 0x0C, 0x02, 0x05, 0x00, 0x02, 0x03, 0x0F, 0x02, 0x07, 0x00, 0x02, 
+    0x03, 0x11, 0x1E, 0xC7, 0x00, 0x03, 0x03, 0x23, 0x03, 0x02, 0x1E, 0xB9, 0x00, 0x02, 0x03, 0x23, 
+    0x1E, 0x1D, 0x00, 0x03, 0x03, 0x27, 0x03, 0x06, 0x02, 0x29, 0x00, 0x02, 0x03, 0x27, 0x01, 0x19, 
+    0x00, 0x02, 0x03, 0x28, 0x1E, 0x19, 0x00, 0x02, 0x03, 0x2D, 0x1E, 0x1B, 0x00, 0x02, 0x03, 0x30, 
+    0x00, 0xE8, 0x00, 0x02, 0x03, 0x40, 0x00, 0xE9, 0x00, 0x02, 0x03, 0x41, 0x00, 0x01, 0x00, 0x04, 
+    0x1E, 0x1F, 0x00, 0x02, 0x03, 0x07, 0x00, 0x08, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 
+    0x00, 0x2A, 0x00, 0x30, 0x00, 0x36, 0x00, 0x3C, 0x01, 0xF5, 0x00, 0x02, 0x03, 0x01, 0x01, 0x1D, 
+    0x00, 0x02, 0x03, 0x02, 0x1E, 0x21, 0x00, 0x02, 0x03, 0x04, 0x01, 0x1F, 0x00, 0x02, 0x03, 0x06, 
+    0x01, 0x21, 0x00, 0x02, 0x03, 0x07, 0x01, 0xE7, 0x00, 0x02, 0x03, 0x0C, 0x01, 0x23, 0x00, 0x02, 
+    0x03, 0x27, 0x01, 0xF5, 0x00, 0x02, 0x03, 0x41, 0x00, 0x08, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 
+    0x00, 0x24, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x36, 0x00, 0x3C, 0x01, 0x25, 0x00, 0x02, 0x03, 0x02, 
+    0x1E, 0x23, 0x00, 0x02, 0x03, 0x07, 0x1E, 0x27, 0x00, 0x02, 0x03, 0x08, 0x02, 0x1F, 0x00, 0x02, 
+    0x03, 0x0C, 0x1E, 0x25, 0x00, 0x02, 0x03, 0x23, 0x1E, 0x29, 0x00, 0x02, 0x03, 0x27, 0x1E, 0x2B, 
+    0x00, 0x02, 0x03, 0x2E, 0x1E, 0x96, 0x00, 0x02, 0x03, 0x31, 0x00, 0x13, 0x00, 0x28, 0x00, 0x2E, 
+    0x00, 0x34, 0x00, 0x3A, 0x00, 0x40, 0x00, 0x46, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x5C, 0x00, 0x62, 
+    0x00, 0x68, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x7A, 0x00, 0x80, 0x00, 0x86, 0x00, 0x8C, 0x00, 0x92, 
+    0x00, 0x98, 0x00, 0xEC, 0x00, 0x02, 0x03, 0x00, 0x00, 0xED, 0x00, 0x02, 0x03, 0x01, 0x00, 0xEE, 
+    0x00, 0x02, 0x03, 0x02, 0x01, 0x29, 0x00, 0x02, 0x03, 0x03, 0x01, 0x2B, 0x00, 0x02, 0x03, 0x04, 
+    0x01, 0x2D, 0x00, 0x02, 0x03, 0x06, 0x1E, 0x2F, 0x00, 0x03, 0x03, 0x08, 0x03, 0x01, 0x1E, 0x2F, 
+    0x00, 0x03, 0x03, 0x08, 0x03, 0x41, 0x00, 0xEF, 0x00, 0x02, 0x03, 0x08, 0x1E, 0xC9, 0x00, 0x02, 
+    0x03, 0x09, 0x01, 0xD0, 0x00, 0x02, 0x03, 0x0C, 0x02, 0x09, 0x00, 0x02, 0x03, 0x0F, 0x02, 0x0B, 
+    0x00, 0x02, 0x03, 0x11, 0x1E, 0xCB, 0x00, 0x02, 0x03, 0x23, 0x01, 0x2F, 0x00, 0x02, 0x03, 0x28, 
+    0x1E, 0x2D, 0x00, 0x02, 0x03, 0x30, 0x00, 0xEC, 0x00, 0x02, 0x03, 0x40, 0x00, 0xED, 0x00, 0x02, 
+    0x03, 0x41, 0x1E, 0x2F, 0x00, 0x02, 0x03, 0x44, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x01, 0x35, 
+    0x00, 0x02, 0x03, 0x02, 0x01, 0xF0, 0x00, 0x02, 0x03, 0x0C, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x14, 
+    0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00, 0x2C, 0x1E, 0x31, 0x00, 0x02, 0x03, 0x01, 0x01, 0xE9, 
+    0x00, 0x02, 0x03, 0x0C, 0x1E, 0x33, 0x00, 0x02, 0x03, 0x23, 0x01, 0x37, 0x00, 0x02, 0x03, 0x27, 
+    0x1E, 0x35, 0x00, 0x02, 0x03, 0x31, 0x1E, 0x31, 0x00, 0x02, 0x03, 0x41, 0x00, 0x09, 0x00, 0x14, 
+    0x00, 0x1A, 0x00, 0x22, 0x00, 0x28, 0x00, 0x30, 0x00, 0x36, 0x00, 0x3C, 0x00, 0x42, 0x00, 0x48, 
+    0x01, 0x3A, 0x00, 0x02, 0x03, 0x01, 0x1E, 0x39, 0x00, 0x03, 0x03, 0x04, 0x03, 0x23, 0x01, 0x3E, 
+    0x00, 0x02, 0x03, 0x0C, 0x1E, 0x39, 0x00, 0x03, 0x03, 0x23, 0x03, 0x04, 0x1E, 0x37, 0x00, 0x02, 
+    0x03, 0x23, 0x01, 0x3C, 0x00, 0x02, 0x03, 0x27, 0x1E, 0x3D, 0x00, 0x02, 0x03, 0x2D, 0x1E, 0x3B, 
+    0x00, 0x02, 0x03, 0x31, 0x01, 0x3A, 0x00, 0x02, 0x03, 0x41, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x10, 
+    0x00, 0x16, 0x00, 0x1C, 0x1E, 0x3F, 0x00, 0x02, 0x03, 0x01, 0x1E, 0x41, 0x00, 0x02, 0x03, 0x07, 
+    0x1E, 0x43, 0x00, 0x02, 0x03, 0x23, 0x1E, 0x3F, 0x00, 0x02, 0x03, 0x41, 0x00, 0x0B, 0x00, 0x18, 
+    0x00, 0x1E, 0x00, 0x24, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x36, 0x00, 0x3C, 0x00, 0x42, 0x00, 0x48, 
+    0x00, 0x4E, 0x00, 0x54, 0x01, 0xF9, 0x00, 0x02, 0x03, 0x00, 0x01, 0x44, 0x00, 0x02, 0x03, 0x01, 
+    0x00, 0xF1, 0x00, 0x02, 0x03, 0x03, 0x1E, 0x45, 0x00, 0x02, 0x03, 0x07, 0x01, 0x48, 0x00, 0x02, 
+    0x03, 0x0C, 0x1E, 0x47, 0x00, 0x02, 0x03, 0x23, 0x01, 0x46, 0x00, 0x02, 0x03, 0x27, 0x1E, 0x4B, 
+    0x00, 0x02, 0x03, 0x2D, 0x1E, 0x49, 0x00, 0x02, 0x03, 0x31, 0x01, 0xF9, 0x00, 0x02, 0x03, 0x40, 
+    0x01, 0x44, 0x00, 0x02, 0x03, 0x41, 0x00, 0x34, 0x00, 0x6A, 0x00, 0x72, 0x00, 0x78, 0x00, 0x80, 
+    0x00, 0x86, 0x00, 0x8E, 0x00, 0x96, 0x00, 0x9E, 0x00, 0xA6, 0x00, 0xAE, 0x00, 0xB6, 0x00, 0xBE, 
+    0x00, 0xC4, 0x00, 0xCC, 0x00, 0xD4, 0x00, 0xDC, 0x00, 0xE4, 0x00, 0xEC, 0x00, 0xF2, 0x00, 0xFA, 
+    0x01, 0x02, 0x01, 0x0A, 0x01, 0x12, 0x01, 0x1A, 0x01, 0x20, 0x01, 0x26, 0x01, 0x2E, 0x01, 0x34, 
+    0x01, 0x3C, 0x01, 0x42, 0x01, 0x4A, 0x01, 0x50, 0x01, 0x56, 0x01, 0x5C, 0x01, 0x62, 0x01, 0x68, 
+    0x01, 0x70, 0x01, 0x78, 0x01, 0x80, 0x01, 0x88, 0x01, 0x90, 0x01, 0x98, 0x01, 0xA0, 0x01, 0xA6, 
+    0x01, 0xAE, 0x01, 0xB6, 0x01, 0xBC, 0x01, 0xC4, 0x01, 0xCA, 0x01, 0xD2, 0x01, 0xD8, 0x01, 0xE0, 
+    0x1E, 0xDD, 0x00, 0x03, 0x03, 0x00, 0x03, 0x1B, 0x00, 0xF2, 0x00, 0x02, 0x03, 0x00, 0x1E, 0xDB, 
+    0x00, 0x03, 0x03, 0x01, 0x03, 0x1B, 0x00, 0xF3, 0x00, 0x02, 0x03, 0x01, 0x1E, 0xD3, 0x00, 0x03, 
+    0x03, 0x02, 0x03, 0x00, 0x1E, 0xD1, 0x00, 0x03, 0x03, 0x02, 0x03, 0x01, 0x1E, 0xD7, 0x00, 0x03, 
+    0x03, 0x02, 0x03, 0x03, 0x1E, 0xD5, 0x00, 0x03, 0x03, 0x02, 0x03, 0x09, 0x1E, 0xD9, 0x00, 0x03, 
+    0x03, 0x02, 0x03, 0x23, 0x1E, 0xD3, 0x00, 0x03, 0x03, 0x02, 0x03, 0x40, 0x1E, 0xD1, 0x00, 0x03, 
+    0x03, 0x02, 0x03, 0x41, 0x00, 0xF4, 0x00, 0x02, 0x03, 0x02, 0x1E, 0x4D, 0x00, 0x03, 0x03, 0x03, 
+    0x03, 0x01, 0x02, 0x2D, 0x00, 0x03, 0x03, 0x03, 0x03, 0x04, 0x1E, 0x4F, 0x00, 0x03, 0x03, 0x03, 
+    0x03, 0x08, 0x1E, 0xE1, 0x00, 0x03, 0x03, 0x03, 0x03, 0x1B, 0x1E, 0x4D, 0x00, 0x03, 0x03, 0x03, 
+    0x03, 0x41, 0x00, 0xF5, 0x00, 0x02, 0x03, 0x03, 0x1E, 0x51, 0x00, 0x03, 0x03, 0x04, 0x03, 0x00, 
+    0x1E, 0x53, 0x00, 0x03, 0x03, 0x04, 0x03, 0x01, 0x01, 0xED, 0x00, 0x03, 0x03, 0x04, 0x03, 0x28, 
+    0x1E, 0x51, 0x00, 0x03, 0x03, 0x04, 0x03, 0x40, 0x1E, 0x53, 0x00, 0x03, 0x03, 0x04, 0x03, 0x41, 
+    0x01, 0x4D, 0x00, 0x02, 0x03, 0x04, 0x01, 0x4F, 0x00, 0x02, 0x03, 0x06, 0x02, 0x31, 0x00, 0x03, 
+    0x03, 0x07, 0x03, 0x04, 0x02, 0x2F, 0x00, 0x02, 0x03, 0x07, 0x02, 0x2B, 0x00, 0x03, 0x03, 0x08, 
+    0x03, 0x04, 0x00, 0xF6, 0x00, 0x02, 0x03, 0x08, 0x1E, 0xDF, 0x00, 0x03, 0x03, 0x09, 0x03, 0x1B, 
+    0x1E, 0xCF, 0x00, 0x02, 0x03, 0x09, 0x01, 0x51, 0x00, 0x02, 0x03, 0x0B, 0x01, 0xD2, 0x00, 0x02, 
+    0x03, 0x0C, 0x02, 0x0D, 0x00, 0x02, 0x03, 0x0F, 0x02, 0x0F, 0x00, 0x02, 0x03, 0x11, 0x1E, 0xDD, 
+    0x00, 0x03, 0x03, 0x1B, 0x03, 0x00, 0x1E, 0xDB, 0x00, 0x03, 0x03, 0x1B, 0x03, 0x01, 0x1E, 0xE1, 
+    0x00, 0x03, 0x03, 0x1B, 0x03, 0x03, 0x1E, 0xDF, 0x00, 0x03, 0x03, 0x1B, 0x03, 0x09, 0x1E, 0xE3, 
+    0x00, 0x03, 0x03, 0x1B, 0x03, 0x23, 0x1E, 0xDD, 0x00, 0x03, 0x03, 0x1B, 0x03, 0x40, 0x1E, 0xDB, 
+    0x00, 0x03, 0x03, 0x1B, 0x03, 0x41, 0x01, 0xA1, 0x00, 0x02, 0x03, 0x1B, 0x1E, 0xD9, 0x00, 0x03, 
+    0x03, 0x23, 0x03, 0x02, 0x1E, 0xE3, 0x00, 0x03, 0x03, 0x23, 0x03, 0x1B, 0x1E, 0xCD, 0x00, 0x02, 
+    0x03, 0x23, 0x01, 0xED, 0x00, 0x03, 0x03, 0x28, 0x03, 0x04, 0x01, 0xEB, 0x00, 0x02, 0x03, 0x28, 
+    0x1E, 0xDD, 0x00, 0x03, 0x03, 0x40, 0x03, 0x1B, 0x00, 0xF2, 0x00, 0x02, 0x03, 0x40, 0x1E, 0xDB, 
+    0x00, 0x03, 0x03, 0x41, 0x03, 0x1B, 0x00, 0xF3, 0x00, 0x02, 0x03, 0x41, 0x00, 0x03, 0x00, 0x08, 
+    0x00, 0x0E, 0x00, 0x14, 0x1E, 0x55, 0x00, 0x02, 0x03, 0x01, 0x1E, 0x57, 0x00, 0x02, 0x03, 0x07, 
+    0x1E, 0x55, 0x00, 0x02, 0x03, 0x41, 0x00, 0x0B, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x26, 0x00, 0x2C, 
+    0x00, 0x32, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x46, 0x00, 0x4C, 0x00, 0x52, 0x00, 0x58, 0x01, 0x55, 
+    0x00, 0x02, 0x03, 0x01, 0x1E, 0x5D, 0x00, 0x03, 0x03, 0x04, 0x03, 0x23, 0x1E, 0x59, 0x00, 0x02, 
+    0x03, 0x07, 0x01, 0x59, 0x00, 0x02, 0x03, 0x0C, 0x02, 0x11, 0x00, 0x02, 0x03, 0x0F, 0x02, 0x13, 
+    0x00, 0x02, 0x03, 0x11, 0x1E, 0x5D, 0x00, 0x03, 0x03, 0x23, 0x03, 0x04, 0x1E, 0x5B, 0x00, 0x02, 
+    0x03, 0x23, 0x01, 0x57, 0x00, 0x02, 0x03, 0x27, 0x1E, 0x5F, 0x00, 0x02, 0x03, 0x31, 0x01, 0x55, 
+    0x00, 0x02, 0x03, 0x41, 0x00, 0x0D, 0x00, 0x1C, 0x00, 0x24, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x38, 
+    0x00, 0x3E, 0x00, 0x46, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x5A, 0x00, 0x60, 0x00, 0x66, 0x00, 0x6E, 
+    0x1E, 0x65, 0x00, 0x03, 0x03, 0x01, 0x03, 0x07, 0x01, 0x5B, 0x00, 0x02, 0x03, 0x01, 0x01, 0x5D, 
+    0x00, 0x02, 0x03, 0x02, 0x1E, 0x69, 0x00, 0x03, 0x03, 0x07, 0x03, 0x23, 0x1E, 0x61, 0x00, 0x02, 
+    0x03, 0x07, 0x1E, 0x67, 0x00, 0x03, 0x03, 0x0C, 0x03, 0x07, 0x01, 0x61, 0x00, 0x02, 0x03, 0x0C, 
+    0x1E, 0x69, 0x00, 0x03, 0x03, 0x23, 0x03, 0x07, 0x1E, 0x63, 0x00, 0x02, 0x03, 0x23, 0x02, 0x19, 
+    0x00, 0x02, 0x03, 0x26, 0x01, 0x5F, 0x00, 0x02, 0x03, 0x27, 0x1E, 0x65, 0x00, 0x03, 0x03, 0x41, 
+    0x03, 0x07, 0x01, 0x5B, 0x00, 0x02, 0x03, 0x41, 0x00, 0x08, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 
+    0x00, 0x24, 0x00, 0x2A, 0x00, 0x30, 0x00, 0x36, 0x00, 0x3C, 0x1E, 0x6B, 0x00, 0x02, 0x03, 0x07, 
+    0x1E, 0x97, 0x00, 0x02, 0x03, 0x08, 0x01, 0x65, 0x00, 0x02, 0x03, 0x0C, 0x1E, 0x6D, 0x00, 0x02, 
+    0x03, 0x23, 0x02, 0x1B, 0x00, 0x02, 0x03, 0x26, 0x01, 0x63, 0x00, 0x02, 0x03, 0x27, 0x1E, 0x71, 
+    0x00, 0x02, 0x03, 0x2D, 0x1E, 0x6F, 0x00, 0x02, 0x03, 0x31, 0x00, 0x2D, 0x00, 0x5C, 0x00, 0x64, 
+    0x00, 0x6A, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7E, 0x00, 0x86, 0x00, 0x8E, 0x00, 0x96, 0x00, 0x9C, 
+    0x00, 0xA4, 0x00, 0xAA, 0x00, 0xB0, 0x00, 0xB8, 0x00, 0xC0, 0x00, 0xC8, 0x00, 0xD0, 0x00, 0xD8, 
+    0x00, 0xE0, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xF4, 0x00, 0xFA, 0x01, 0x00, 0x01, 0x06, 0x01, 0x0C, 
+    0x01, 0x12, 0x01, 0x1A, 0x01, 0x22, 0x01, 0x2A, 0x01, 0x32, 0x01, 0x3A, 0x01, 0x42, 0x01, 0x4A, 
+    0x01, 0x50, 0x01, 0x58, 0x01, 0x5E, 0x01, 0x64, 0x01, 0x6A, 0x01, 0x70, 0x01, 0x76, 0x01, 0x7E, 
+    0x01, 0x84, 0x01, 0x8C, 0x01, 0x92, 0x1E, 0xEB, 0x00, 0x03, 0x03, 0x00, 0x03, 0x1B, 0x00, 0xF9, 
+    0x00, 0x02, 0x03, 0x00, 0x1E, 0xE9, 0x00, 0x03, 0x03, 0x01, 0x03, 0x1B, 0x00, 0xFA, 0x00, 0x02, 
+    0x03, 0x01, 0x00, 0xFB, 0x00, 0x02, 0x03, 0x02, 0x1E, 0x79, 0x00, 0x03, 0x03, 0x03, 0x03, 0x01, 
+    0x1E, 0xEF, 0x00, 0x03, 0x03, 0x03, 0x03, 0x1B, 0x1E, 0x79, 0x00, 0x03, 0x03, 0x03, 0x03, 0x41, 
+    0x01, 0x69, 0x00, 0x02, 0x03, 0x03, 0x1E, 0x7B, 0x00, 0x03, 0x03, 0x04, 0x03, 0x08, 0x01, 0x6B, 
+    0x00, 0x02, 0x03, 0x04, 0x01, 0x6D, 0x00, 0x02, 0x03, 0x06, 0x01, 0xDC, 0x00, 0x03, 0x03, 0x08, 
+    0x03, 0x00, 0x01, 0xD8, 0x00, 0x03, 0x03, 0x08, 0x03, 0x01, 0x01, 0xD6, 0x00, 0x03, 0x03, 0x08, 
+    0x03, 0x04, 0x01, 0xDA, 0x00, 0x03, 0x03, 0x08, 0x03, 0x0C, 0x01, 0xDC, 0x00, 0x03, 0x03, 0x08, 
+    0x03, 0x40, 0x01, 0xD8, 0x00, 0x03, 0x03, 0x08, 0x03, 0x41, 0x00, 0xFC, 0x00, 0x02, 0x03, 0x08, 
+    0x1E, 0xED, 0x00, 0x03, 0x03, 0x09, 0x03, 0x1B, 0x1E, 0xE7, 0x00, 0x02, 0x03, 0x09, 0x01, 0x6F, 
+    0x00, 0x02, 0x03, 0x0A, 0x01, 0x71, 0x00, 0x02, 0x03, 0x0B, 0x01, 0xD4, 0x00, 0x02, 0x03, 0x0C, 
+    0x02, 0x15, 0x00, 0x02, 0x03, 0x0F, 0x02, 0x17, 0x00, 0x02, 0x03, 0x11, 0x1E, 0xEB, 0x00, 0x03, 
+    0x03, 0x1B, 0x03, 0x00, 0x1E, 0xE9, 0x00, 0x03, 0x03, 0x1B, 0x03, 0x01, 0x1E, 0xEF, 0x00, 0x03, 
+    0x03, 0x1B, 0x03, 0x03, 0x1E, 0xED, 0x00, 0x03, 0x03, 0x1B, 0x03, 0x09, 0x1E, 0xF1, 0x00, 0x03, 
+    0x03, 0x1B, 0x03, 0x23, 0x1E, 0xEB, 0x00, 0x03, 0x03, 0x1B, 0x03, 0x40, 0x1E, 0xE9, 0x00, 0x03, 
+    0x03, 0x1B, 0x03, 0x41, 0x01, 0xB0, 0x00, 0x02, 0x03, 0x1B, 0x1E, 0xF1, 0x00, 0x03, 0x03, 0x23, 
+    0x03, 0x1B, 0x1E, 0xE5, 0x00, 0x02, 0x03, 0x23, 0x1E, 0x73, 0x00, 0x02, 0x03, 0x24, 0x01, 0x73, 
+    0x00, 0x02, 0x03, 0x28, 0x1E, 0x77, 0x00, 0x02, 0x03, 0x2D, 0x1E, 0x75, 0x00, 0x02, 0x03, 0x30, 
+    0x1E, 0xEB, 0x00, 0x03, 0x03, 0x40, 0x03, 0x1B, 0x00, 0xF9, 0x00, 0x02, 0x03, 0x40, 0x1E, 0xE9, 
+    0x00, 0x03, 0x03, 0x41, 0x03, 0x1B, 0x00, 0xFA, 0x00, 0x02, 0x03, 0x41, 0x01, 0xD8, 0x00, 0x02, 
+    0x03, 0x44, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x1E, 0x7D, 0x00, 0x02, 0x03, 0x03, 0x1E, 0x7F, 
+    0x00, 0x02, 0x03, 0x23, 0x00, 0x09, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00, 0x2C, 
+    0x00, 0x32, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x44, 0x1E, 0x81, 0x00, 0x02, 0x03, 0x00, 0x1E, 0x83, 
+    0x00, 0x02, 0x03, 0x01, 0x01, 0x75, 0x00, 0x02, 0x03, 0x02, 0x1E, 0x87, 0x00, 0x02, 0x03, 0x07, 
+    0x1E, 0x85, 0x00, 0x02, 0x03, 0x08, 0x1E, 0x98, 0x00, 0x02, 0x03, 0x0A, 0x1E, 0x89, 0x00, 0x02, 
+    0x03, 0x23, 0x1E, 0x81, 0x00, 0x02, 0x03, 0x40, 0x1E, 0x83, 0x00, 0x02, 0x03, 0x41, 0x00, 0x02, 
+    0x00, 0x06, 0x00, 0x0C, 0x1E, 0x8B, 0x00, 0x02, 0x03, 0x07, 0x1E, 0x8D, 0x00, 0x02, 0x03, 0x08, 
+    0x00, 0x0C, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00, 0x2C, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3E, 
+    0x00, 0x44, 0x00, 0x4A, 0x00, 0x50, 0x00, 0x56, 0x00, 0x5C, 0x1E, 0xF3, 0x00, 0x02, 0x03, 0x00, 
+    0x00, 0xFD, 0x00, 0x02, 0x03, 0x01, 0x01, 0x77, 0x00, 0x02, 0x03, 0x02, 0x1E, 0xF9, 0x00, 0x02, 
+    0x03, 0x03, 0x02, 0x33, 0x00, 0x02, 0x03, 0x04, 0x1E, 0x8F, 0x00, 0x02, 0x03, 0x07, 0x00, 0xFF, 
+    0x00, 0x02, 0x03, 0x08, 0x1E, 0xF7, 0x00, 0x02, 0x03, 0x09, 0x1E, 0x99, 0x00, 0x02, 0x03, 0x0A, 
+    0x1E, 0xF5, 0x00, 0x02, 0x03, 0x23, 0x1E, 0xF3, 0x00, 0x02, 0x03, 0x40, 0x00, 0xFD, 0x00, 0x02, 
+    0x03, 0x41, 0x00, 0x07, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2E, 
+    0x00, 0x34, 0x01, 0x7A, 0x00, 0x02, 0x03, 0x01, 0x1E, 0x91, 0x00, 0x02, 0x03, 0x02, 0x01, 0x7C, 
+    0x00, 0x02, 0x03, 0x07, 0x01, 0x7E, 0x00, 0x02, 0x03, 0x0C, 0x1E, 0x93, 0x00, 0x02, 0x03, 0x23, 
+    0x1E, 0x95, 0x00, 0x02, 0x03, 0x31, 0x01, 0x7A, 0x00, 0x02, 0x03, 0x41, 0x00, 0x07, 0x00, 0x10, 
+    0x00, 0x16, 0x00, 0x1C, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0x1E, 0xA6, 0x00, 0x02, 
+    0x03, 0x00, 0x1E, 0xA4, 0x00, 0x02, 0x03, 0x01, 0x1E, 0xAA, 0x00, 0x02, 0x03, 0x03, 0x1E, 0xA8, 
+    0x00, 0x02, 0x03, 0x09, 0x1E, 0xAC, 0x00, 0x02, 0x03, 0x23, 0x1E, 0xA6, 0x00, 0x02, 0x03, 0x40, 
+    0x1E, 0xA4, 0x00, 0x02, 0x03, 0x41, 0x00, 0x01, 0x00, 0x04, 0x01, 0xDE, 0x00, 0x02, 0x03, 0x04, 
+    0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x01, 0xFA, 0x00, 0x02, 0x03, 0x01, 0x01, 0xFA, 0x00, 0x02, 
+    0x03, 0x41, 0x00, 0x03, 0x00, 0x08, 0x00, 0x0E, 0x00, 0x14, 0x01, 0xFC, 0x00, 0x02, 0x03, 0x01, 
+    0x01, 0xE2, 0x00, 0x02, 0x03, 0x04, 0x01, 0xFC, 0x00, 0x02, 0x03, 0x41, 0x00, 0x02, 0x00, 0x06, 
+    0x00, 0x0C, 0x1E, 0x08, 0x00, 0x02, 0x03, 0x01, 0x1E, 0x08, 0x00, 0x02, 0x03, 0x41, 0x00, 0x07, 
+    0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0x1E, 0xC0, 
+    0x00, 0x02, 0x03, 0x00, 0x1E, 0xBE, 0x00, 0x02, 0x03, 0x01, 0x1E, 0xC4, 0x00, 0x02, 0x03, 0x03, 
+    0x1E, 0xC2, 0x00, 0x02, 0x03, 0x09, 0x1E, 0xC6, 0x00, 0x02, 0x03, 0x23, 0x1E, 0xC0, 0x00, 0x02, 
+    0x03, 0x40, 0x1E, 0xBE, 0x00, 0x02, 0x03, 0x41, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x1E, 0x2E, 
+    0x00, 0x02, 0x03, 0x01, 0x1E, 0x2E, 0x00, 0x02, 0x03, 0x41, 0x00, 0x01, 0x00, 0x04, 0x1E, 0xDC, 
+    0x00, 0x02, 0x03, 0x1B, 0x00, 0x01, 0x00, 0x04, 0x1E, 0xDA, 0x00, 0x02, 0x03, 0x1B, 0x00, 0x07, 
+    0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0x1E, 0xD2, 
+    0x00, 0x02, 0x03, 0x00, 0x1E, 0xD0, 0x00, 0x02, 0x03, 0x01, 0x1E, 0xD6, 0x00, 0x02, 0x03, 0x03, 
+    0x1E, 0xD4, 0x00, 0x02, 0x03, 0x09, 0x1E, 0xD8, 0x00, 0x02, 0x03, 0x23, 0x1E, 0xD2, 0x00, 0x02, 
+    0x03, 0x40, 0x1E, 0xD0, 0x00, 0x02, 0x03, 0x41, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 
+    0x00, 0x1E, 0x00, 0x24, 0x1E, 0x4C, 0x00, 0x02, 0x03, 0x01, 0x02, 0x2C, 0x00, 0x02, 0x03, 0x04, 
+    0x1E, 0x4E, 0x00, 0x02, 0x03, 0x08, 0x1E, 0xE0, 0x00, 0x02, 0x03, 0x1B, 0x1E, 0x4C, 0x00, 0x02, 
+    0x03, 0x41, 0x00, 0x01, 0x00, 0x04, 0x02, 0x2A, 0x00, 0x02, 0x03, 0x04, 0x00, 0x02, 0x00, 0x06, 
+    0x00, 0x0C, 0x01, 0xFE, 0x00, 0x02, 0x03, 0x01, 0x01, 0xFE, 0x00, 0x02, 0x03, 0x41, 0x00, 0x01, 
+    0x00, 0x04, 0x1E, 0xEA, 0x00, 0x02, 0x03, 0x1B, 0x00, 0x01, 0x00, 0x04, 0x1E, 0xE8, 0x00, 0x02, 
+    0x03, 0x1B, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00, 0x2C, 
+    0x01, 0xDB, 0x00, 0x02, 0x03, 0x00, 0x01, 0xD7, 0x00, 0x02, 0x03, 0x01, 0x01, 0xD5, 0x00, 0x02, 
+    0x03, 0x04, 0x01, 0xD9, 0x00, 0x02, 0x03, 0x0C, 0x01, 0xDB, 0x00, 0x02, 0x03, 0x40, 0x01, 0xD7, 
+    0x00, 0x02, 0x03, 0x41, 0x00, 0x07, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 0x00, 0x22, 0x00, 0x28, 
+    0x00, 0x2E, 0x00, 0x34, 0x1E, 0xA7, 0x00, 0x02, 0x03, 0x00, 0x1E, 0xA5, 0x00, 0x02, 0x03, 0x01, 
+    0x1E, 0xAB, 0x00, 0x02, 0x03, 0x03, 0x1E, 0xA9, 0x00, 0x02, 0x03, 0x09, 0x1E, 0xAD, 0x00, 0x02, 
+    0x03, 0x23, 0x1E, 0xA7, 0x00, 0x02, 0x03, 0x40, 0x1E, 0xA5, 0x00, 0x02, 0x03, 0x41, 0x00, 0x01, 
+    0x00, 0x04, 0x01, 0xDF, 0x00, 0x02, 0x03, 0x04, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x01, 0xFB, 
+    0x00, 0x02, 0x03, 0x01, 0x01, 0xFB, 0x00, 0x02, 0x03, 0x41, 0x00, 0x03, 0x00, 0x08, 0x00, 0x0E, 
+    0x00, 0x14, 0x01, 0xFD, 0x00, 0x02, 0x03, 0x01, 0x01, 0xE3, 0x00, 0x02, 0x03, 0x04, 0x01, 0xFD, 
+    0x00, 0x02, 0x03, 0x41, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x1E, 0x09, 0x00, 0x02, 0x03, 0x01, 
+    0x1E, 0x09, 0x00, 0x02, 0x03, 0x41, 0x00, 0x07, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 0x00, 0x22, 
+    0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0x1E, 0xC1, 0x00, 0x02, 0x03, 0x00, 0x1E, 0xBF, 0x00, 0x02, 
+    0x03, 0x01, 0x1E, 0xC5, 0x00, 0x02, 0x03, 0x03, 0x1E, 0xC3, 0x00, 0x02, 0x03, 0x09, 0x1E, 0xC7, 
+    0x00, 0x02, 0x03, 0x23, 0x1E, 0xC1, 0x00, 0x02, 0x03, 0x40, 0x1E, 0xBF, 0x00, 0x02, 0x03, 0x41, 
+    0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x1E, 0x2F, 0x00, 0x02, 0x03, 0x01, 0x1E, 0x2F, 0x00, 0x02, 
+    0x03, 0x41, 0x00, 0x01, 0x00, 0x04, 0x1E, 0xDD, 0x00, 0x02, 0x03, 0x1B, 0x00, 0x01, 0x00, 0x04, 
+    0x1E, 0xDB, 0x00, 0x02, 0x03, 0x1B, 0x00, 0x07, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 0x00, 0x22, 
+    0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0x1E, 0xD3, 0x00, 0x02, 0x03, 0x00, 0x1E, 0xD1, 0x00, 0x02, 
+    0x03, 0x01, 0x1E, 0xD7, 0x00, 0x02, 0x03, 0x03, 0x1E, 0xD5, 0x00, 0x02, 0x03, 0x09, 0x1E, 0xD9, 
+    0x00, 0x02, 0x03, 0x23, 0x1E, 0xD3, 0x00, 0x02, 0x03, 0x40, 0x1E, 0xD1, 0x00, 0x02, 0x03, 0x41, 
+    0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x1E, 0x4D, 0x00, 0x02, 
+    0x03, 0x01, 0x02, 0x2D, 0x00, 0x02, 0x03, 0x04, 0x1E, 0x4F, 0x00, 0x02, 0x03, 0x08, 0x1E, 0xE1, 
+    0x00, 0x02, 0x03, 0x1B, 0x1E, 0x4D, 0x00, 0x02, 0x03, 0x41, 0x00, 0x01, 0x00, 0x04, 0x02, 0x2B, 
+    0x00, 0x02, 0x03, 0x04, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x01, 0xFF, 0x00, 0x02, 0x03, 0x01, 
+    0x01, 0xFF, 0x00, 0x02, 0x03, 0x41, 0x00, 0x01, 0x00, 0x04, 0x1E, 0xEB, 0x00, 0x02, 0x03, 0x1B, 
+    0x00, 0x01, 0x00, 0x04, 0x1E, 0xE9, 0x00, 0x02, 0x03, 0x1B, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x14, 
+    0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00, 0x2C, 0x01, 0xDC, 0x00, 0x02, 0x03, 0x00, 0x01, 0xD8, 
+    0x00, 0x02, 0x03, 0x01, 0x01, 0xD6, 0x00, 0x02, 0x03, 0x04, 0x01, 0xDA, 0x00, 0x02, 0x03, 0x0C, 
+    0x01, 0xDC, 0x00, 0x02, 0x03, 0x40, 0x01, 0xD8, 0x00, 0x02, 0x03, 0x41, 0x00, 0x07, 0x00, 0x10, 
+    0x00, 0x16, 0x00, 0x1C, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0x1E, 0xB0, 0x00, 0x02, 
+    0x03, 0x00, 0x1E, 0xAE, 0x00, 0x02, 0x03, 0x01, 0x1E, 0xB4, 0x00, 0x02, 0x03, 0x03, 0x1E, 0xB2, 
+    0x00, 0x02, 0x03, 0x09, 0x1E, 0xB6, 0x00, 0x02, 0x03, 0x23, 0x1E, 0xB0, 0x00, 0x02, 0x03, 0x40, 
+    0x1E, 0xAE, 0x00, 0x02, 0x03, 0x41, 0x00, 0x07, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 0x00, 0x22, 
+    0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0x1E, 0xB1, 0x00, 0x02, 0x03, 0x00, 0x1E, 0xAF, 0x00, 0x02, 
+    0x03, 0x01, 0x1E, 0xB5, 0x00, 0x02, 0x03, 0x03, 0x1E, 0xB3, 0x00, 0x02, 0x03, 0x09, 0x1E, 0xB7, 
+    0x00, 0x02, 0x03, 0x23, 0x1E, 0xB1, 0x00, 0x02, 0x03, 0x40, 0x1E, 0xAF, 0x00, 0x02, 0x03, 0x41, 
+    0x00, 0x01, 0x00, 0x04, 0x1E, 0x08, 0x00, 0x02, 0x03, 0x27, 0x00, 0x01, 0x00, 0x04, 0x1E, 0x09, 
+    0x00, 0x02, 0x03, 0x27, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 0x1E, 0x14, 
+    0x00, 0x02, 0x03, 0x00, 0x1E, 0x16, 0x00, 0x02, 0x03, 0x01, 0x1E, 0x14, 0x00, 0x02, 0x03, 0x40, 
+    0x1E, 0x16, 0x00, 0x02, 0x03, 0x41, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 
+    0x1E, 0x15, 0x00, 0x02, 0x03, 0x00, 0x1E, 0x17, 0x00, 0x02, 0x03, 0x01, 0x1E, 0x15, 0x00, 0x02, 
+    0x03, 0x40, 0x1E, 0x17, 0x00, 0x02, 0x03, 0x41, 0x00, 0x01, 0x00, 0x04, 0x1E, 0x1C, 0x00, 0x02, 
+    0x03, 0x27, 0x00, 0x01, 0x00, 0x04, 0x1E, 0x1D, 0x00, 0x02, 0x03, 0x27, 0x00, 0x05, 0x00, 0x0C, 
+    0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 0x00, 0x24, 0x1E, 0x50, 0x00, 0x02, 0x03, 0x00, 0x1E, 0x52, 
+    0x00, 0x02, 0x03, 0x01, 0x01, 0xEC, 0x00, 0x02, 0x03, 0x28, 0x1E, 0x50, 0x00, 0x02, 0x03, 0x40, 
+    0x1E, 0x52, 0x00, 0x02, 0x03, 0x41, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x1E, 
+    0x00, 0x24, 0x1E, 0x51, 0x00, 0x02, 0x03, 0x00, 0x1E, 0x53, 0x00, 0x02, 0x03, 0x01, 0x01, 0xED, 
+    0x00, 0x02, 0x03, 0x28, 0x1E, 0x51, 0x00, 0x02, 0x03, 0x40, 0x1E, 0x53, 0x00, 0x02, 0x03, 0x41, 
+    0x00, 0x01, 0x00, 0x04, 0x1E, 0x64, 0x00, 0x02, 0x03, 0x07, 0x00, 0x01, 0x00, 0x04, 0x1E, 0x65, 
+    0x00, 0x02, 0x03, 0x07, 0x00, 0x01, 0x00, 0x04, 0x1E, 0x66, 0x00, 0x02, 0x03, 0x07, 0x00, 0x01, 
+    0x00, 0x04, 0x1E, 0x67, 0x00, 0x02, 0x03, 0x07, 0x00, 0x03, 0x00, 0x08, 0x00, 0x0E, 0x00, 0x14, 
+    0x1E, 0x78, 0x00, 0x02, 0x03, 0x01, 0x1E, 0xEE, 0x00, 0x02, 0x03, 0x1B, 0x1E, 0x78, 0x00, 0x02, 
+    0x03, 0x41, 0x00, 0x03, 0x00, 0x08, 0x00, 0x0E, 0x00, 0x14, 0x1E, 0x79, 0x00, 0x02, 0x03, 0x01, 
+    0x1E, 0xEF, 0x00, 0x02, 0x03, 0x1B, 0x1E, 0x79, 0x00, 0x02, 0x03, 0x41, 0x00, 0x01, 0x00, 0x04, 
+    0x1E, 0x7A, 0x00, 0x02, 0x03, 0x08, 0x00, 0x01, 0x00, 0x04, 0x1E, 0x7B, 0x00, 0x02, 0x03, 0x08, 
+    0x00, 0x01, 0x00, 0x04, 0x1E, 0x9B, 0x00, 0x02, 0x03, 0x07, 0x00, 0x07, 0x00, 0x10, 0x00, 0x16, 
+    0x00, 0x1C, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0x1E, 0xDC, 0x00, 0x02, 0x03, 0x00, 
+    0x1E, 0xDA, 0x00, 0x02, 0x03, 0x01, 0x1E, 0xE0, 0x00, 0x02, 0x03, 0x03, 0x1E, 0xDE, 0x00, 0x02, 
+    0x03, 0x09, 0x1E, 0xE2, 0x00, 0x02, 0x03, 0x23, 0x1E, 0xDC, 0x00, 0x02, 0x03, 0x40, 0x1E, 0xDA, 
+    0x00, 0x02, 0x03, 0x41, 0x00, 0x07, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 0x00, 0x22, 0x00, 0x28, 
+    0x00, 0x2E, 0x00, 0x34, 0x1E, 0xDD, 0x00, 0x02, 0x03, 0x00, 0x1E, 0xDB, 0x00, 0x02, 0x03, 0x01, 
+    0x1E, 0xE1, 0x00, 0x02, 0x03, 0x03, 0x1E, 0xDF, 0x00, 0x02, 0x03, 0x09, 0x1E, 0xE3, 0x00, 0x02, 
+    0x03, 0x23, 0x1E, 0xDD, 0x00, 0x02, 0x03, 0x40, 0x1E, 0xDB, 0x00, 0x02, 0x03, 0x41, 0x00, 0x07, 
+    0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0x1E, 0xEA, 
+    0x00, 0x02, 0x03, 0x00, 0x1E, 0xE8, 0x00, 0x02, 0x03, 0x01, 0x1E, 0xEE, 0x00, 0x02, 0x03, 0x03, 
+    0x1E, 0xEC, 0x00, 0x02, 0x03, 0x09, 0x1E, 0xF0, 0x00, 0x02, 0x03, 0x23, 0x1E, 0xEA, 0x00, 0x02, 
+    0x03, 0x40, 0x1E, 0xE8, 0x00, 0x02, 0x03, 0x41, 0x00, 0x07, 0x00, 0x10, 0x00, 0x16, 0x00, 0x1C, 
+    0x00, 0x22, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0x1E, 0xEB, 0x00, 0x02, 0x03, 0x00, 0x1E, 0xE9, 
+    0x00, 0x02, 0x03, 0x01, 0x1E, 0xEF, 0x00, 0x02, 0x03, 0x03, 0x1E, 0xED, 0x00, 0x02, 0x03, 0x09, 
+    0x1E, 0xF1, 0x00, 0x02, 0x03, 0x23, 0x1E, 0xEB, 0x00, 0x02, 0x03, 0x40, 0x1E, 0xE9, 0x00, 0x02, 
+    0x03, 0x41, 0x00, 0x01, 0x00, 0x04, 0x01, 0xEE, 0x00, 0x02, 0x03, 0x0C, 0x00, 0x01, 0x00, 0x04, 
+    0x01, 0xEC, 0x00, 0x02, 0x03, 0x04, 0x00, 0x01, 0x00, 0x04, 0x01, 0xED, 0x00, 0x02, 0x03, 0x04, 
+    0x00, 0x01, 0x00, 0x04, 0x01, 0xE0, 0x00, 0x02, 0x03, 0x04, 0x00, 0x01, 0x00, 0x04, 0x01, 0xE1, 
+    0x00, 0x02, 0x03, 0x04, 0x00, 0x01, 0x00, 0x04, 0x1E, 0x1C, 0x00, 0x02, 0x03, 0x06, 0x00, 0x01, 
+    0x00, 0x04, 0x1E, 0x1D, 0x00, 0x02, 0x03, 0x06, 0x00, 0x01, 0x00, 0x04, 0x02, 0x30, 0x00, 0x02, 
+    0x03, 0x04, 0x00, 0x01, 0x00, 0x04, 0x02, 0x31, 0x00, 0x02, 0x03, 0x04, 0x00, 0x01, 0x00, 0x04, 
+    0x01, 0xEF, 0x00, 0x02, 0x03, 0x0C, 0x00, 0x01, 0x00, 0x04, 0x1E, 0x38, 0x00, 0x02, 0x03, 0x04, 
+    0x00, 0x01, 0x00, 0x04, 0x1E, 0x39, 0x00, 0x02, 0x03, 0x04, 0x00, 0x01, 0x00, 0x04, 0x1E, 0x5C, 
+    0x00, 0x02, 0x03, 0x04, 0x00, 0x01, 0x00, 0x04, 0x1E, 0x5D, 0x00, 0x02, 0x03, 0x04, 0x00, 0x01, 
+    0x00, 0x04, 0x1E, 0x68, 0x00, 0x02, 0x03, 0x23, 0x00, 0x01, 0x00, 0x04, 0x1E, 0x69, 0x00, 0x02, 
+    0x03, 0x23, 0x00, 0x01, 0x00, 0x04, 0x1E, 0x68, 0x00, 0x02, 0x03, 0x07, 0x00, 0x01, 0x00, 0x04, 
+    0x1E, 0x69, 0x00, 0x02, 0x03, 0x07, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x1E, 0xAC, 0x00, 0x02, 
+    0x03, 0x02, 0x1E, 0xB6, 0x00, 0x02, 0x03, 0x06, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x1E, 0xAD, 
+    0x00, 0x02, 0x03, 0x02, 0x1E, 0xB7, 0x00, 0x02, 0x03, 0x06, 0x00, 0x01, 0x00, 0x04, 0x1E, 0xC6, 
+    0x00, 0x02, 0x03, 0x02, 0x00, 0x01, 0x00, 0x04, 0x1E, 0xC7, 0x00, 0x02, 0x03, 0x02, 0x00, 0x02, 
+    0x00, 0x06, 0x00, 0x0C, 0x1E, 0xD8, 0x00, 0x02, 0x03, 0x02, 0x1E, 0xE2, 0x00, 0x02, 0x03, 0x1B, 
+    0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x1E, 0xD9, 0x00, 0x02, 0x03, 0x02, 0x1E, 0xE3, 0x00, 0x02, 
+    0x03, 0x1B, 0x00, 0x01, 0x00, 0x04, 0x1E, 0xDE, 0x00, 0x02, 0x03, 0x1B, 0x00, 0x01, 0x00, 0x04, 
+    0x1E, 0xDF, 0x00, 0x02, 0x03, 0x1B, 0x00, 0x01, 0x00, 0x04, 0x1E, 0xF0, 0x00, 0x02, 0x03, 0x1B, 
+    0x00, 0x01, 0x00, 0x04, 0x1E, 0xF1, 0x00, 0x02, 0x03, 0x1B, 0x00, 0x01, 0x00, 0x04, 0x1E, 0xEC, 
+    0x00, 0x02, 0x03, 0x1B, 0x00, 0x01, 0x00, 0x04, 0x1E, 0xED, 0x00, 0x02, 0x03, 0x1B, 0x00, 0x06, 
+    0x00, 0x0E, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00, 0x2C, 0x1E, 0x30, 0x00, 0x02, 
+    0x03, 0x01, 0x01, 0xE8, 0x00, 0x02, 0x03, 0x0C, 0x1E, 0x32, 0x00, 0x02, 0x03, 0x23, 0x01, 0x36, 
+    0x00, 0x02, 0x03, 0x27, 0x1E, 0x34, 0x00, 0x02, 0x03, 0x31, 0x1E, 0x30, 0x00, 0x02, 0x03, 0x41, 
+    0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x01, 0xFA, 0x00, 0x02, 0x03, 0x01, 0x01, 0xFA, 0x00, 0x02, 
+    0x03, 0x41, 0x00, 0x01, 0x00, 0x89, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 
+    0x00, 0x46, 0x00, 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00, 0x4C, 0x00, 0x4D, 
+    0x00, 0x4E, 0x00, 0x4F, 0x00, 0x50, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 
+    0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 
+    0x00, 0x65, 0x00, 0x66, 0x00, 0x67, 0x00, 0x68, 0x00, 0x69, 0x00, 0x6A, 0x00, 0x6B, 0x00, 0x6C, 
+    0x00, 0x6D, 0x00, 0x6E, 0x00, 0x6F, 0x00, 0x70, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 
+    0x00, 0x76, 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7A, 0x00, 0xC2, 0x00, 0xC4, 0x00, 0xC5, 
+    0x00, 0xC6, 0x00, 0xC7, 0x00, 0xCA, 0x00, 0xCF, 0x00, 0xD2, 0x00, 0xD3, 0x00, 0xD4, 0x00, 0xD5, 
+    0x00, 0xD6, 0x00, 0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDC, 0x00, 0xE2, 0x00, 0xE4, 0x00, 0xE5, 
+    0x00, 0xE6, 0x00, 0xE7, 0x00, 0xEA, 0x00, 0xEF, 0x00, 0xF2, 0x00, 0xF3, 0x00, 0xF4, 0x00, 0xF5, 
+    0x00, 0xF6, 0x00, 0xF8, 0x00, 0xF9, 0x00, 0xFA, 0x00, 0xFC, 0x01, 0x02, 0x01, 0x03, 0x01, 0x06, 
+    0x01, 0x07, 0x01, 0x12, 0x01, 0x13, 0x01, 0x14, 0x01, 0x15, 0x01, 0x4C, 0x01, 0x4D, 0x01, 0x5A, 
+    0x01, 0x5B, 0x01, 0x60, 0x01, 0x61, 0x01, 0x68, 0x01, 0x69, 0x01, 0x6A, 0x01, 0x6B, 0x01, 0x7F, 
+    0x01, 0xA0, 0x01, 0xA1, 0x01, 0xAF, 0x01, 0xB0, 0x01, 0xB7, 0x01, 0xEA, 0x01, 0xEB, 0x02, 0x26, 
+    0x02, 0x27, 0x02, 0x28, 0x02, 0x29, 0x02, 0x2E, 0x02, 0x2F, 0x02, 0x92, 0x1E, 0x36, 0x1E, 0x37, 
+    0x1E, 0x5A, 0x1E, 0x5B, 0x1E, 0x60, 0x1E, 0x61, 0x1E, 0x62, 0x1E, 0x63, 0x1E, 0xA0, 0x1E, 0xA1, 
+    0x1E, 0xB8, 0x1E, 0xB9, 0x1E, 0xCC, 0x1E, 0xCD, 0x1E, 0xCE, 0x1E, 0xCF, 0x1E, 0xE4, 0x1E, 0xE5, 
+    0x1E, 0xE6, 0x1E, 0xE7, 0x21, 0x2A, 0x21, 0x2B, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x14, 
+    0x13, 0x88, 0x1A, 0x9E, 0x1E, 0x3C, 0x21, 0xAE, 0x22, 0x6C, 0x22, 0xFA, 0x00, 0x01, 0x0F, 0x8E, 
+    0x01, 0xF1, 0x03, 0xE8, 0x03, 0xEE, 0x03, 0xF4, 0x03, 0xFA, 0x04, 0x00, 0x04, 0x06, 0x04, 0x0C, 
+    0x04, 0x12, 0x04, 0x18, 0x04, 0x1E, 0x04, 0x24, 0x04, 0x2A, 0x04, 0x30, 0x04, 0x36, 0x04, 0x3C, 
+    0x04, 0x42, 0x04, 0x48, 0x04, 0x4E, 0x04, 0x54, 0x04, 0x5A, 0x04, 0x60, 0x04, 0x66, 0x04, 0x6C, 
+    0x04, 0x72, 0x04, 0x78, 0x04, 0x7E, 0x04, 0x84, 0x04, 0x8A, 0x04, 0x90, 0x04, 0x96, 0x04, 0x9C, 
+    0x04, 0xA2, 0x04, 0xA8, 0x04, 0xAE, 0x04, 0xB4, 0x04, 0xBA, 0x04, 0xC0, 0x04, 0xC6, 0x04, 0xCC, 
+    0x04, 0xD2, 0x04, 0xD8, 0x04, 0xDE, 0x04, 0xE4, 0x04, 0xEA, 0x04, 0xF0, 0x04, 0xF6, 0x04, 0xFC, 
+    0x05, 0x02, 0x05, 0x08, 0x05, 0x0E, 0x05, 0x14, 0x05, 0x1A, 0x05, 0x20, 0x05, 0x26, 0x05, 0x2C, 
+    0x05, 0x32, 0x05, 0x38, 0x05, 0x3E, 0x05, 0x44, 0x05, 0x4A, 0x05, 0x50, 0x05, 0x56, 0x05, 0x5C, 
+    0x05, 0x62, 0x05, 0x68, 0x05, 0x6E, 0x05, 0x74, 0x05, 0x7A, 0x05, 0x80, 0x05, 0x86, 0x05, 0x8C, 
+    0x05, 0x92, 0x05, 0x98, 0x05, 0x9E, 0x05, 0xA4, 0x05, 0xAA, 0x05, 0xB0, 0x05, 0xB6, 0x05, 0xBC, 
+    0x05, 0xC2, 0x05, 0xC8, 0x05, 0xCE, 0x05, 0xD4, 0x05, 0xDA, 0x05, 0xE0, 0x05, 0xE6, 0x05, 0xEC, 
+    0x05, 0xF2, 0x05, 0xF8, 0x05, 0xFE, 0x06, 0x04, 0x06, 0x0A, 0x06, 0x10, 0x06, 0x16, 0x06, 0x1C, 
+    0x06, 0x22, 0x06, 0x28, 0x06, 0x2E, 0x06, 0x34, 0x06, 0x3A, 0x06, 0x40, 0x06, 0x46, 0x06, 0x4C, 
+    0x06, 0x52, 0x06, 0x58, 0x06, 0x5E, 0x06, 0x64, 0x06, 0x6A, 0x06, 0x70, 0x06, 0x76, 0x06, 0x7C, 
+    0x06, 0x82, 0x06, 0x88, 0x06, 0x8E, 0x06, 0x94, 0x06, 0x9A, 0x06, 0xA0, 0x06, 0xA6, 0x06, 0xAC, 
+    0x06, 0xB2, 0x06, 0xB8, 0x06, 0xBE, 0x06, 0xC4, 0x06, 0xCA, 0x06, 0xD0, 0x06, 0xD6, 0x06, 0xDC, 
+    0x06, 0xE2, 0x06, 0xE8, 0x06, 0xEE, 0x06, 0xF4, 0x06, 0xFA, 0x07, 0x00, 0x07, 0x06, 0x07, 0x0C, 
+    0x07, 0x12, 0x07, 0x18, 0x07, 0x1E, 0x07, 0x24, 0x07, 0x2A, 0x07, 0x30, 0x07, 0x36, 0x07, 0x3C, 
+    0x07, 0x42, 0x07, 0x48, 0x07, 0x4E, 0x07, 0x54, 0x07, 0x5A, 0x07, 0x60, 0x07, 0x66, 0x07, 0x6C, 
+    0x07, 0x72, 0x07, 0x78, 0x07, 0x7E, 0x07, 0x84, 0x07, 0x8A, 0x07, 0x90, 0x07, 0x96, 0x07, 0x9C, 
+    0x07, 0xA2, 0x07, 0xA8, 0x07, 0xAE, 0x07, 0xB4, 0x07, 0xBA, 0x07, 0xC0, 0x07, 0xC6, 0x07, 0xCC, 
+    0x07, 0xD2, 0x07, 0xD8, 0x07, 0xDE, 0x07, 0xE4, 0x07, 0xEA, 0x07, 0xF0, 0x07, 0xF6, 0x07, 0xFC, 
+    0x08, 0x02, 0x08, 0x08, 0x08, 0x0E, 0x08, 0x14, 0x08, 0x1A, 0x08, 0x20, 0x08, 0x26, 0x08, 0x2C, 
+    0x08, 0x32, 0x08, 0x38, 0x08, 0x3E, 0x08, 0x44, 0x08, 0x4A, 0x08, 0x50, 0x08, 0x56, 0x08, 0x5C, 
+    0x08, 0x62, 0x08, 0x68, 0x08, 0x6E, 0x08, 0x74, 0x08, 0x7A, 0x08, 0x80, 0x08, 0x86, 0x08, 0x8C, 
+    0x08, 0x92, 0x08, 0x98, 0x08, 0x9E, 0x08, 0xA4, 0x08, 0xAA, 0x08, 0xB0, 0x08, 0xB6, 0x08, 0xBC, 
+    0x08, 0xC2, 0x08, 0xC8, 0x08, 0xCE, 0x08, 0xD4, 0x08, 0xDA, 0x08, 0xE0, 0x08, 0xE6, 0x08, 0xEC, 
+    0x08, 0xF2, 0x08, 0xF8, 0x08, 0xFE, 0x09, 0x04, 0x09, 0x0A, 0x09, 0x10, 0x09, 0x16, 0x09, 0x1C, 
+    0x09, 0x22, 0x09, 0x28, 0x09, 0x2E, 0x09, 0x34, 0x09, 0x3A, 0x09, 0x40, 0x09, 0x46, 0x09, 0x4C, 
+    0x09, 0x52, 0x09, 0x58, 0x09, 0x5E, 0x09, 0x64, 0x09, 0x6A, 0x09, 0x70, 0x09, 0x76, 0x09, 0x7C, 
+    0x09, 0x82, 0x09, 0x88, 0x09, 0x8E, 0x09, 0x94, 0x09, 0x9A, 0x09, 0xA0, 0x09, 0xA6, 0x09, 0xAC, 
+    0x09, 0xB2, 0x09, 0xB8, 0x09, 0xBE, 0x09, 0xC4, 0x09, 0xCA, 0x09, 0xD0, 0x09, 0xD6, 0x09, 0xDC, 
+    0x09, 0xE2, 0x09, 0xE8, 0x09, 0xEE, 0x09, 0xF4, 0x09, 0xFA, 0x0A, 0x00, 0x0A, 0x06, 0x0A, 0x0C, 
+    0x0A, 0x12, 0x0A, 0x18, 0x0A, 0x1E, 0x0A, 0x24, 0x0A, 0x2A, 0x0A, 0x30, 0x0A, 0x36, 0x0A, 0x3C, 
+    0x0A, 0x42, 0x0A, 0x48, 0x0A, 0x4E, 0x0A, 0x54, 0x0A, 0x5A, 0x0A, 0x60, 0x0A, 0x66, 0x0A, 0x6C, 
+    0x0A, 0x72, 0x0A, 0x78, 0x0A, 0x7E, 0x0A, 0x84, 0x0A, 0x8A, 0x0A, 0x90, 0x0A, 0x96, 0x0A, 0x9C, 
+    0x0A, 0xA2, 0x0A, 0xA8, 0x0A, 0xAE, 0x0A, 0xB4, 0x0A, 0xBA, 0x0A, 0xC0, 0x0A, 0xC6, 0x0A, 0xCC, 
+    0x0A, 0xD2, 0x0A, 0xD8, 0x0A, 0xDE, 0x0A, 0xE4, 0x0A, 0xEA, 0x0A, 0xF0, 0x0A, 0xF6, 0x0A, 0xFC, 
+    0x0B, 0x02, 0x0B, 0x08, 0x0B, 0x0E, 0x0B, 0x14, 0x0B, 0x1A, 0x0B, 0x20, 0x0B, 0x26, 0x0B, 0x2C, 
+    0x0B, 0x32, 0x0B, 0x38, 0x0B, 0x3E, 0x0B, 0x44, 0x0B, 0x4A, 0x0B, 0x50, 0x0B, 0x56, 0x0B, 0x5C, 
+    0x0B, 0x62, 0x0B, 0x68, 0x0B, 0x6E, 0x0B, 0x74, 0x0B, 0x7A, 0x0B, 0x80, 0x0B, 0x86, 0x0B, 0x8C, 
+    0x0B, 0x92, 0x0B, 0x98, 0x0B, 0x9E, 0x0B, 0xA4, 0x0B, 0xAA, 0x0B, 0xB0, 0x0B, 0xB6, 0x0B, 0xBC, 
+    0x0B, 0xC2, 0x0B, 0xC8, 0x0B, 0xCE, 0x0B, 0xD4, 0x0B, 0xDA, 0x0B, 0xE0, 0x0B, 0xE6, 0x0B, 0xEC, 
+    0x0B, 0xF2, 0x0B, 0xF8, 0x0B, 0xFE, 0x0C, 0x04, 0x0C, 0x0A, 0x0C, 0x10, 0x0C, 0x16, 0x0C, 0x1C, 
+    0x0C, 0x22, 0x0C, 0x28, 0x0C, 0x2E, 0x0C, 0x34, 0x0C, 0x3A, 0x0C, 0x40, 0x0C, 0x46, 0x0C, 0x4C, 
+    0x0C, 0x52, 0x0C, 0x58, 0x0C, 0x5E, 0x0C, 0x64, 0x0C, 0x6A, 0x0C, 0x70, 0x0C, 0x76, 0x0C, 0x7C, 
+    0x0C, 0x82, 0x0C, 0x88, 0x0C, 0x8E, 0x0C, 0x94, 0x0C, 0x9A, 0x0C, 0xA0, 0x0C, 0xA6, 0x0C, 0xAC, 
+    0x0C, 0xB2, 0x0C, 0xB8, 0x0C, 0xBE, 0x0C, 0xC4, 0x0C, 0xCA, 0x0C, 0xD0, 0x0C, 0xD6, 0x0C, 0xDC, 
+    0x0C, 0xE2, 0x0C, 0xE8, 0x0C, 0xEE, 0x0C, 0xF4, 0x0C, 0xFA, 0x0D, 0x00, 0x0D, 0x06, 0x0D, 0x0C, 
+    0x0D, 0x12, 0x0D, 0x18, 0x0D, 0x1E, 0x0D, 0x24, 0x0D, 0x2A, 0x0D, 0x30, 0x0D, 0x36, 0x0D, 0x3C, 
+    0x0D, 0x42, 0x0D, 0x48, 0x0D, 0x4E, 0x0D, 0x54, 0x0D, 0x5A, 0x0D, 0x60, 0x0D, 0x66, 0x0D, 0x6C, 
+    0x0D, 0x72, 0x0D, 0x78, 0x0D, 0x7E, 0x0D, 0x84, 0x0D, 0x8A, 0x0D, 0x90, 0x0D, 0x96, 0x0D, 0x9C, 
+    0x0D, 0xA2, 0x0D, 0xA8, 0x0D, 0xAE, 0x0D, 0xB4, 0x0D, 0xBA, 0x0D, 0xC0, 0x0D, 0xC6, 0x0D, 0xCC, 
+    0x0D, 0xD2, 0x0D, 0xD8, 0x0D, 0xDE, 0x0D, 0xE4, 0x0D, 0xEA, 0x0D, 0xF0, 0x0D, 0xF6, 0x0D, 0xFC, 
+    0x0E, 0x02, 0x0E, 0x08, 0x0E, 0x0E, 0x0E, 0x14, 0x0E, 0x1A, 0x0E, 0x20, 0x0E, 0x26, 0x0E, 0x2C, 
+    0x0E, 0x32, 0x0E, 0x38, 0x0E, 0x3E, 0x0E, 0x44, 0x0E, 0x4A, 0x0E, 0x50, 0x0E, 0x56, 0x0E, 0x5C, 
+    0x0E, 0x62, 0x0E, 0x68, 0x0E, 0x6E, 0x0E, 0x74, 0x0E, 0x7A, 0x0E, 0x80, 0x0E, 0x86, 0x0E, 0x8C, 
+    0x0E, 0x92, 0x0E, 0x98, 0x0E, 0x9E, 0x0E, 0xA4, 0x0E, 0xAA, 0x0E, 0xB0, 0x0E, 0xB6, 0x0E, 0xBC, 
+    0x0E, 0xC2, 0x0E, 0xC8, 0x0E, 0xCE, 0x0E, 0xD4, 0x0E, 0xDA, 0x0E, 0xE0, 0x0E, 0xE6, 0x0E, 0xEC, 
+    0x0E, 0xF2, 0x0E, 0xF8, 0x0E, 0xFE, 0x0F, 0x04, 0x0F, 0x0A, 0x0F, 0x10, 0x0F, 0x16, 0x0F, 0x1C, 
+    0x0F, 0x22, 0x0F, 0x28, 0x0F, 0x2E, 0x0F, 0x34, 0x0F, 0x3A, 0x0F, 0x40, 0x0F, 0x46, 0x0F, 0x4C, 
+    0x0F, 0x52, 0x0F, 0x58, 0x0F, 0x5E, 0x0F, 0x64, 0x0F, 0x6A, 0x0F, 0x70, 0x0F, 0x76, 0x0F, 0x7C, 
+    0x0F, 0x82, 0x0F, 0x88, 0x00, 0x02, 0x00, 0x41, 0x03, 0x00, 0x00, 0x02, 0x00, 0x41, 0x03, 0x01, 
+    0x00, 0x02, 0x00, 0x41, 0x03, 0x02, 0x00, 0x02, 0x00, 0x41, 0x03, 0x03, 0x00, 0x02, 0x00, 0x41, 
+    0x03, 0x08, 0x00, 0x02, 0x00, 0x41, 0x03, 0x0A, 0x00, 0x02, 0x00, 0x43, 0x03, 0x27, 0x00, 0x02, 
+    0x00, 0x45, 0x03, 0x00, 0x00, 0x02, 0x00, 0x45, 0x03, 0x01, 0x00, 0x02, 0x00, 0x45, 0x03, 0x02, 
+    0x00, 0x02, 0x00, 0x45, 0x03, 0x08, 0x00, 0x02, 0x00, 0x49, 0x03, 0x00, 0x00, 0x02, 0x00, 0x49, 
+    0x03, 0x01, 0x00, 0x02, 0x00, 0x49, 0x03, 0x02, 0x00, 0x02, 0x00, 0x49, 0x03, 0x08, 0x00, 0x02, 
+    0x00, 0x4E, 0x03, 0x03, 0x00, 0x02, 0x00, 0x4F, 0x03, 0x00, 0x00, 0x02, 0x00, 0x4F, 0x03, 0x01, 
+    0x00, 0x02, 0x00, 0x4F, 0x03, 0x02, 0x00, 0x02, 0x00, 0x4F, 0x03, 0x03, 0x00, 0x02, 0x00, 0x4F, 
+    0x03, 0x08, 0x00, 0x02, 0x00, 0x55, 0x03, 0x00, 0x00, 0x02, 0x00, 0x55, 0x03, 0x01, 0x00, 0x02, 
+    0x00, 0x55, 0x03, 0x02, 0x00, 0x02, 0x00, 0x55, 0x03, 0x08, 0x00, 0x02, 0x00, 0x59, 0x03, 0x01, 
+    0x00, 0x02, 0x00, 0x61, 0x03, 0x00, 0x00, 0x02, 0x00, 0x61, 0x03, 0x01, 0x00, 0x02, 0x00, 0x61, 
+    0x03, 0x02, 0x00, 0x02, 0x00, 0x61, 0x03, 0x03, 0x00, 0x02, 0x00, 0x61, 0x03, 0x08, 0x00, 0x02, 
+    0x00, 0x61, 0x03, 0x0A, 0x00, 0x02, 0x00, 0x63, 0x03, 0x27, 0x00, 0x02, 0x00, 0x65, 0x03, 0x00, 
+    0x00, 0x02, 0x00, 0x65, 0x03, 0x01, 0x00, 0x02, 0x00, 0x65, 0x03, 0x02, 0x00, 0x02, 0x00, 0x65, 
+    0x03, 0x08, 0x00, 0x02, 0x00, 0x69, 0x03, 0x00, 0x00, 0x02, 0x00, 0x69, 0x03, 0x01, 0x00, 0x02, 
+    0x00, 0x69, 0x03, 0x02, 0x00, 0x02, 0x00, 0x69, 0x03, 0x08, 0x00, 0x02, 0x00, 0x6E, 0x03, 0x03, 
+    0x00, 0x02, 0x00, 0x6F, 0x03, 0x00, 0x00, 0x02, 0x00, 0x6F, 0x03, 0x01, 0x00, 0x02, 0x00, 0x6F, 
+    0x03, 0x02, 0x00, 0x02, 0x00, 0x6F, 0x03, 0x03, 0x00, 0x02, 0x00, 0x6F, 0x03, 0x08, 0x00, 0x02, 
+    0x00, 0x75, 0x03, 0x00, 0x00, 0x02, 0x00, 0x75, 0x03, 0x01, 0x00, 0x02, 0x00, 0x75, 0x03, 0x02, 
+    0x00, 0x02, 0x00, 0x75, 0x03, 0x08, 0x00, 0x02, 0x00, 0x79, 0x03, 0x01, 0x00, 0x02, 0x00, 0x79, 
+    0x03, 0x08, 0x00, 0x02, 0x00, 0x41, 0x03, 0x04, 0x00, 0x02, 0x00, 0x61, 0x03, 0x04, 0x00, 0x02, 
+    0x00, 0x41, 0x03, 0x06, 0x00, 0x02, 0x00, 0x61, 0x03, 0x06, 0x00, 0x02, 0x00, 0x41, 0x03, 0x28, 
+    0x00, 0x02, 0x00, 0x61, 0x03, 0x28, 0x00, 0x02, 0x00, 0x43, 0x03, 0x01, 0x00, 0x02, 0x00, 0x63, 
+    0x03, 0x01, 0x00, 0x02, 0x00, 0x43, 0x03, 0x02, 0x00, 0x02, 0x00, 0x63, 0x03, 0x02, 0x00, 0x02, 
+    0x00, 0x43, 0x03, 0x07, 0x00, 0x02, 0x00, 0x63, 0x03, 0x07, 0x00, 0x02, 0x00, 0x43, 0x03, 0x0C, 
+    0x00, 0x02, 0x00, 0x63, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x44, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x64, 
+    0x03, 0x0C, 0x00, 0x02, 0x00, 0x45, 0x03, 0x04, 0x00, 0x02, 0x00, 0x65, 0x03, 0x04, 0x00, 0x02, 
+    0x00, 0x45, 0x03, 0x06, 0x00, 0x02, 0x00, 0x65, 0x03, 0x06, 0x00, 0x02, 0x00, 0x45, 0x03, 0x07, 
+    0x00, 0x02, 0x00, 0x65, 0x03, 0x07, 0x00, 0x02, 0x00, 0x45, 0x03, 0x28, 0x00, 0x02, 0x00, 0x65, 
+    0x03, 0x28, 0x00, 0x02, 0x00, 0x45, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x65, 0x03, 0x0C, 0x00, 0x02, 
+    0x00, 0x47, 0x03, 0x02, 0x00, 0x02, 0x00, 0x67, 0x03, 0x02, 0x00, 0x02, 0x00, 0x47, 0x03, 0x06, 
+    0x00, 0x02, 0x00, 0x67, 0x03, 0x06, 0x00, 0x02, 0x00, 0x47, 0x03, 0x07, 0x00, 0x02, 0x00, 0x67, 
+    0x03, 0x07, 0x00, 0x02, 0x00, 0x47, 0x03, 0x27, 0x00, 0x02, 0x00, 0x67, 0x03, 0x27, 0x00, 0x02, 
+    0x00, 0x48, 0x03, 0x02, 0x00, 0x02, 0x00, 0x68, 0x03, 0x02, 0x00, 0x02, 0x00, 0x49, 0x03, 0x03, 
+    0x00, 0x02, 0x00, 0x69, 0x03, 0x03, 0x00, 0x02, 0x00, 0x49, 0x03, 0x04, 0x00, 0x02, 0x00, 0x69, 
+    0x03, 0x04, 0x00, 0x02, 0x00, 0x49, 0x03, 0x06, 0x00, 0x02, 0x00, 0x69, 0x03, 0x06, 0x00, 0x02, 
+    0x00, 0x49, 0x03, 0x28, 0x00, 0x02, 0x00, 0x69, 0x03, 0x28, 0x00, 0x02, 0x00, 0x49, 0x03, 0x07, 
+    0x00, 0x02, 0x00, 0x4A, 0x03, 0x02, 0x00, 0x02, 0x00, 0x6A, 0x03, 0x02, 0x00, 0x02, 0x00, 0x4B, 
+    0x03, 0x27, 0x00, 0x02, 0x00, 0x6B, 0x03, 0x27, 0x00, 0x02, 0x00, 0x4C, 0x03, 0x01, 0x00, 0x02, 
+    0x00, 0x6C, 0x03, 0x01, 0x00, 0x02, 0x00, 0x4C, 0x03, 0x27, 0x00, 0x02, 0x00, 0x6C, 0x03, 0x27, 
+    0x00, 0x02, 0x00, 0x4C, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x6C, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x4E, 
+    0x03, 0x01, 0x00, 0x02, 0x00, 0x6E, 0x03, 0x01, 0x00, 0x02, 0x00, 0x4E, 0x03, 0x27, 0x00, 0x02, 
+    0x00, 0x6E, 0x03, 0x27, 0x00, 0x02, 0x00, 0x4E, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x6E, 0x03, 0x0C, 
+    0x00, 0x02, 0x00, 0x4F, 0x03, 0x04, 0x00, 0x02, 0x00, 0x6F, 0x03, 0x04, 0x00, 0x02, 0x00, 0x4F, 
+    0x03, 0x06, 0x00, 0x02, 0x00, 0x6F, 0x03, 0x06, 0x00, 0x02, 0x00, 0x4F, 0x03, 0x0B, 0x00, 0x02, 
+    0x00, 0x6F, 0x03, 0x0B, 0x00, 0x02, 0x00, 0x52, 0x03, 0x01, 0x00, 0x02, 0x00, 0x72, 0x03, 0x01, 
+    0x00, 0x02, 0x00, 0x52, 0x03, 0x27, 0x00, 0x02, 0x00, 0x72, 0x03, 0x27, 0x00, 0x02, 0x00, 0x52, 
+    0x03, 0x0C, 0x00, 0x02, 0x00, 0x72, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x53, 0x03, 0x01, 0x00, 0x02, 
+    0x00, 0x73, 0x03, 0x01, 0x00, 0x02, 0x00, 0x53, 0x03, 0x02, 0x00, 0x02, 0x00, 0x73, 0x03, 0x02, 
+    0x00, 0x02, 0x00, 0x53, 0x03, 0x27, 0x00, 0x02, 0x00, 0x73, 0x03, 0x27, 0x00, 0x02, 0x00, 0x53, 
+    0x03, 0x0C, 0x00, 0x02, 0x00, 0x73, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x54, 0x03, 0x27, 0x00, 0x02, 
+    0x00, 0x74, 0x03, 0x27, 0x00, 0x02, 0x00, 0x54, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x74, 0x03, 0x0C, 
+    0x00, 0x02, 0x00, 0x55, 0x03, 0x03, 0x00, 0x02, 0x00, 0x75, 0x03, 0x03, 0x00, 0x02, 0x00, 0x55, 
+    0x03, 0x04, 0x00, 0x02, 0x00, 0x75, 0x03, 0x04, 0x00, 0x02, 0x00, 0x55, 0x03, 0x06, 0x00, 0x02, 
+    0x00, 0x75, 0x03, 0x06, 0x00, 0x02, 0x00, 0x55, 0x03, 0x0A, 0x00, 0x02, 0x00, 0x75, 0x03, 0x0A, 
+    0x00, 0x02, 0x00, 0x55, 0x03, 0x0B, 0x00, 0x02, 0x00, 0x75, 0x03, 0x0B, 0x00, 0x02, 0x00, 0x55, 
+    0x03, 0x28, 0x00, 0x02, 0x00, 0x75, 0x03, 0x28, 0x00, 0x02, 0x00, 0x57, 0x03, 0x02, 0x00, 0x02, 
+    0x00, 0x77, 0x03, 0x02, 0x00, 0x02, 0x00, 0x59, 0x03, 0x02, 0x00, 0x02, 0x00, 0x79, 0x03, 0x02, 
+    0x00, 0x02, 0x00, 0x59, 0x03, 0x08, 0x00, 0x02, 0x00, 0x5A, 0x03, 0x01, 0x00, 0x02, 0x00, 0x7A, 
+    0x03, 0x01, 0x00, 0x02, 0x00, 0x5A, 0x03, 0x07, 0x00, 0x02, 0x00, 0x7A, 0x03, 0x07, 0x00, 0x02, 
+    0x00, 0x5A, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x7A, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x4F, 0x03, 0x1B, 
+    0x00, 0x02, 0x00, 0x6F, 0x03, 0x1B, 0x00, 0x02, 0x00, 0x55, 0x03, 0x1B, 0x00, 0x02, 0x00, 0x75, 
+    0x03, 0x1B, 0x00, 0x02, 0x00, 0x41, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x61, 0x03, 0x0C, 0x00, 0x02, 
+    0x00, 0x49, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x69, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x4F, 0x03, 0x0C, 
+    0x00, 0x02, 0x00, 0x6F, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x55, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x75, 
+    0x03, 0x0C, 0x00, 0x02, 0x00, 0xDC, 0x03, 0x04, 0x00, 0x02, 0x00, 0xFC, 0x03, 0x04, 0x00, 0x02, 
+    0x00, 0x55, 0x03, 0x44, 0x00, 0x02, 0x00, 0x75, 0x03, 0x44, 0x00, 0x02, 0x00, 0xDC, 0x03, 0x0C, 
+    0x00, 0x02, 0x00, 0xFC, 0x03, 0x0C, 0x00, 0x02, 0x00, 0xDC, 0x03, 0x00, 0x00, 0x02, 0x00, 0xFC, 
+    0x03, 0x00, 0x00, 0x02, 0x00, 0xC4, 0x03, 0x04, 0x00, 0x02, 0x00, 0xE4, 0x03, 0x04, 0x00, 0x02, 
+    0x02, 0x26, 0x03, 0x04, 0x00, 0x02, 0x02, 0x27, 0x03, 0x04, 0x00, 0x02, 0x00, 0xC6, 0x03, 0x04, 
+    0x00, 0x02, 0x00, 0xE6, 0x03, 0x04, 0x00, 0x02, 0x00, 0x47, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x67, 
+    0x03, 0x0C, 0x00, 0x02, 0x00, 0x4B, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x6B, 0x03, 0x0C, 0x00, 0x02, 
+    0x00, 0x4F, 0x03, 0x28, 0x00, 0x02, 0x00, 0x6F, 0x03, 0x28, 0x00, 0x02, 0x01, 0x4C, 0x03, 0x28, 
+    0x00, 0x02, 0x01, 0x4D, 0x03, 0x28, 0x00, 0x02, 0x01, 0xB7, 0x03, 0x0C, 0x00, 0x02, 0x02, 0x92, 
+    0x03, 0x0C, 0x00, 0x02, 0x00, 0x6A, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x47, 0x03, 0x01, 0x00, 0x02, 
+    0x00, 0x67, 0x03, 0x01, 0x00, 0x02, 0x00, 0x4E, 0x03, 0x00, 0x00, 0x02, 0x00, 0x6E, 0x03, 0x00, 
+    0x00, 0x02, 0x00, 0xC5, 0x03, 0x01, 0x00, 0x02, 0x00, 0xE5, 0x03, 0x01, 0x00, 0x02, 0x00, 0xC6, 
+    0x03, 0x01, 0x00, 0x02, 0x00, 0xE6, 0x03, 0x01, 0x00, 0x02, 0x00, 0xD8, 0x03, 0x01, 0x00, 0x02, 
+    0x00, 0xF8, 0x03, 0x01, 0x00, 0x02, 0x00, 0x41, 0x03, 0x0F, 0x00, 0x02, 0x00, 0x61, 0x03, 0x0F, 
+    0x00, 0x02, 0x00, 0x41, 0x03, 0x11, 0x00, 0x02, 0x00, 0x61, 0x03, 0x11, 0x00, 0x02, 0x00, 0x45, 
+    0x03, 0x0F, 0x00, 0x02, 0x00, 0x65, 0x03, 0x0F, 0x00, 0x02, 0x00, 0x45, 0x03, 0x11, 0x00, 0x02, 
+    0x00, 0x65, 0x03, 0x11, 0x00, 0x02, 0x00, 0x49, 0x03, 0x0F, 0x00, 0x02, 0x00, 0x69, 0x03, 0x0F, 
+    0x00, 0x02, 0x00, 0x49, 0x03, 0x11, 0x00, 0x02, 0x00, 0x69, 0x03, 0x11, 0x00, 0x02, 0x00, 0x4F, 
+    0x03, 0x0F, 0x00, 0x02, 0x00, 0x6F, 0x03, 0x0F, 0x00, 0x02, 0x00, 0x4F, 0x03, 0x11, 0x00, 0x02, 
+    0x00, 0x6F, 0x03, 0x11, 0x00, 0x02, 0x00, 0x52, 0x03, 0x0F, 0x00, 0x02, 0x00, 0x72, 0x03, 0x0F, 
+    0x00, 0x02, 0x00, 0x52, 0x03, 0x11, 0x00, 0x02, 0x00, 0x72, 0x03, 0x11, 0x00, 0x02, 0x00, 0x55, 
+    0x03, 0x0F, 0x00, 0x02, 0x00, 0x75, 0x03, 0x0F, 0x00, 0x02, 0x00, 0x55, 0x03, 0x11, 0x00, 0x02, 
+    0x00, 0x75, 0x03, 0x11, 0x00, 0x02, 0x00, 0x53, 0x03, 0x26, 0x00, 0x02, 0x00, 0x73, 0x03, 0x26, 
+    0x00, 0x02, 0x00, 0x54, 0x03, 0x26, 0x00, 0x02, 0x00, 0x74, 0x03, 0x26, 0x00, 0x02, 0x00, 0x48, 
+    0x03, 0x0C, 0x00, 0x02, 0x00, 0x68, 0x03, 0x0C, 0x00, 0x02, 0x00, 0x41, 0x03, 0x07, 0x00, 0x02, 
+    0x00, 0x61, 0x03, 0x07, 0x00, 0x02, 0x00, 0x45, 0x03, 0x27, 0x00, 0x02, 0x00, 0x65, 0x03, 0x27, 
+    0x00, 0x02, 0x00, 0xD6, 0x03, 0x04, 0x00, 0x02, 0x00, 0xF6, 0x03, 0x04, 0x00, 0x02, 0x00, 0xD5, 
+    0x03, 0x04, 0x00, 0x02, 0x00, 0xF5, 0x03, 0x04, 0x00, 0x02, 0x00, 0x4F, 0x03, 0x07, 0x00, 0x02, 
+    0x00, 0x6F, 0x03, 0x07, 0x00, 0x02, 0x02, 0x2E, 0x03, 0x04, 0x00, 0x02, 0x02, 0x2F, 0x03, 0x04, 
+    0x00, 0x02, 0x00, 0x59, 0x03, 0x04, 0x00, 0x02, 0x00, 0x79, 0x03, 0x04, 0x00, 0x02, 0x00, 0x41, 
+    0x03, 0x25, 0x00, 0x02, 0x00, 0x61, 0x03, 0x25, 0x00, 0x02, 0x00, 0x42, 0x03, 0x07, 0x00, 0x02, 
+    0x00, 0x62, 0x03, 0x07, 0x00, 0x02, 0x00, 0x42, 0x03, 0x23, 0x00, 0x02, 0x00, 0x62, 0x03, 0x23, 
+    0x00, 0x02, 0x00, 0x42, 0x03, 0x31, 0x00, 0x02, 0x00, 0x62, 0x03, 0x31, 0x00, 0x02, 0x00, 0xC7, 
+    0x03, 0x01, 0x00, 0x02, 0x00, 0xE7, 0x03, 0x01, 0x00, 0x02, 0x00, 0x44, 0x03, 0x07, 0x00, 0x02, 
+    0x00, 0x64, 0x03, 0x07, 0x00, 0x02, 0x00, 0x44, 0x03, 0x23, 0x00, 0x02, 0x00, 0x64, 0x03, 0x23, 
+    0x00, 0x02, 0x00, 0x44, 0x03, 0x31, 0x00, 0x02, 0x00, 0x64, 0x03, 0x31, 0x00, 0x02, 0x00, 0x44, 
+    0x03, 0x27, 0x00, 0x02, 0x00, 0x64, 0x03, 0x27, 0x00, 0x02, 0x00, 0x44, 0x03, 0x2D, 0x00, 0x02, 
+    0x00, 0x64, 0x03, 0x2D, 0x00, 0x02, 0x01, 0x12, 0x03, 0x00, 0x00, 0x02, 0x01, 0x13, 0x03, 0x00, 
+    0x00, 0x02, 0x01, 0x12, 0x03, 0x01, 0x00, 0x02, 0x01, 0x13, 0x03, 0x01, 0x00, 0x02, 0x00, 0x45, 
+    0x03, 0x2D, 0x00, 0x02, 0x00, 0x65, 0x03, 0x2D, 0x00, 0x02, 0x00, 0x45, 0x03, 0x30, 0x00, 0x02, 
+    0x00, 0x65, 0x03, 0x30, 0x00, 0x02, 0x01, 0x14, 0x03, 0x27, 0x00, 0x02, 0x01, 0x15, 0x03, 0x27, 
+    0x00, 0x02, 0x00, 0x46, 0x03, 0x07, 0x00, 0x02, 0x00, 0x66, 0x03, 0x07, 0x00, 0x02, 0x00, 0x47, 
+    0x03, 0x04, 0x00, 0x02, 0x00, 0x67, 0x03, 0x04, 0x00, 0x02, 0x00, 0x48, 0x03, 0x07, 0x00, 0x02, 
+    0x00, 0x68, 0x03, 0x07, 0x00, 0x02, 0x00, 0x48, 0x03, 0x23, 0x00, 0x02, 0x00, 0x68, 0x03, 0x23, 
+    0x00, 0x02, 0x00, 0x48, 0x03, 0x08, 0x00, 0x02, 0x00, 0x68, 0x03, 0x08, 0x00, 0x02, 0x00, 0x48, 
+    0x03, 0x27, 0x00, 0x02, 0x00, 0x68, 0x03, 0x27, 0x00, 0x02, 0x00, 0x48, 0x03, 0x2E, 0x00, 0x02, 
+    0x00, 0x68, 0x03, 0x2E, 0x00, 0x02, 0x00, 0x49, 0x03, 0x30, 0x00, 0x02, 0x00, 0x69, 0x03, 0x30, 
+    0x00, 0x02, 0x00, 0x49, 0x03, 0x44, 0x00, 0x02, 0x00, 0x69, 0x03, 0x44, 0x00, 0x02, 0x00, 0x4B, 
+    0x03, 0x01, 0x00, 0x02, 0x00, 0x6B, 0x03, 0x01, 0x00, 0x02, 0x00, 0x4B, 0x03, 0x23, 0x00, 0x02, 
+    0x00, 0x6B, 0x03, 0x23, 0x00, 0x02, 0x00, 0x4B, 0x03, 0x31, 0x00, 0x02, 0x00, 0x6B, 0x03, 0x31, 
+    0x00, 0x02, 0x00, 0x4C, 0x03, 0x23, 0x00, 0x02, 0x00, 0x6C, 0x03, 0x23, 0x00, 0x02, 0x1E, 0x36, 
+    0x03, 0x04, 0x00, 0x02, 0x1E, 0x37, 0x03, 0x04, 0x00, 0x02, 0x00, 0x4C, 0x03, 0x31, 0x00, 0x02, 
+    0x00, 0x6C, 0x03, 0x31, 0x00, 0x02, 0x00, 0x4C, 0x03, 0x2D, 0x00, 0x02, 0x00, 0x6C, 0x03, 0x2D, 
+    0x00, 0x02, 0x00, 0x4D, 0x03, 0x01, 0x00, 0x02, 0x00, 0x6D, 0x03, 0x01, 0x00, 0x02, 0x00, 0x4D, 
+    0x03, 0x07, 0x00, 0x02, 0x00, 0x6D, 0x03, 0x07, 0x00, 0x02, 0x00, 0x4D, 0x03, 0x23, 0x00, 0x02, 
+    0x00, 0x6D, 0x03, 0x23, 0x00, 0x02, 0x00, 0x4E, 0x03, 0x07, 0x00, 0x02, 0x00, 0x6E, 0x03, 0x07, 
+    0x00, 0x02, 0x00, 0x4E, 0x03, 0x23, 0x00, 0x02, 0x00, 0x6E, 0x03, 0x23, 0x00, 0x02, 0x00, 0x4E, 
+    0x03, 0x31, 0x00, 0x02, 0x00, 0x6E, 0x03, 0x31, 0x00, 0x02, 0x00, 0x4E, 0x03, 0x2D, 0x00, 0x02, 
+    0x00, 0x6E, 0x03, 0x2D, 0x00, 0x02, 0x00, 0xD5, 0x03, 0x01, 0x00, 0x02, 0x00, 0xF5, 0x03, 0x01, 
+    0x00, 0x02, 0x00, 0xD5, 0x03, 0x08, 0x00, 0x02, 0x00, 0xF5, 0x03, 0x08, 0x00, 0x02, 0x01, 0x4C, 
+    0x03, 0x00, 0x00, 0x02, 0x01, 0x4D, 0x03, 0x00, 0x00, 0x02, 0x01, 0x4C, 0x03, 0x01, 0x00, 0x02, 
+    0x01, 0x4D, 0x03, 0x01, 0x00, 0x02, 0x00, 0x50, 0x03, 0x01, 0x00, 0x02, 0x00, 0x70, 0x03, 0x01, 
+    0x00, 0x02, 0x00, 0x50, 0x03, 0x07, 0x00, 0x02, 0x00, 0x70, 0x03, 0x07, 0x00, 0x02, 0x00, 0x52, 
+    0x03, 0x07, 0x00, 0x02, 0x00, 0x72, 0x03, 0x07, 0x00, 0x02, 0x00, 0x52, 0x03, 0x23, 0x00, 0x02, 
+    0x00, 0x72, 0x03, 0x23, 0x00, 0x02, 0x1E, 0x5A, 0x03, 0x04, 0x00, 0x02, 0x1E, 0x5B, 0x03, 0x04, 
+    0x00, 0x02, 0x00, 0x52, 0x03, 0x31, 0x00, 0x02, 0x00, 0x72, 0x03, 0x31, 0x00, 0x02, 0x00, 0x53, 
+    0x03, 0x07, 0x00, 0x02, 0x00, 0x73, 0x03, 0x07, 0x00, 0x02, 0x00, 0x53, 0x03, 0x23, 0x00, 0x02, 
+    0x00, 0x73, 0x03, 0x23, 0x00, 0x02, 0x01, 0x5A, 0x03, 0x07, 0x00, 0x02, 0x01, 0x5B, 0x03, 0x07, 
+    0x00, 0x02, 0x01, 0x60, 0x03, 0x07, 0x00, 0x02, 0x01, 0x61, 0x03, 0x07, 0x00, 0x02, 0x1E, 0x60, 
+    0x03, 0x23, 0x00, 0x02, 0x1E, 0x61, 0x03, 0x23, 0x00, 0x02, 0x00, 0x54, 0x03, 0x07, 0x00, 0x02, 
+    0x00, 0x74, 0x03, 0x07, 0x00, 0x02, 0x00, 0x54, 0x03, 0x23, 0x00, 0x02, 0x00, 0x74, 0x03, 0x23, 
+    0x00, 0x02, 0x00, 0x54, 0x03, 0x31, 0x00, 0x02, 0x00, 0x74, 0x03, 0x31, 0x00, 0x02, 0x00, 0x54, 
+    0x03, 0x2D, 0x00, 0x02, 0x00, 0x74, 0x03, 0x2D, 0x00, 0x02, 0x00, 0x55, 0x03, 0x24, 0x00, 0x02, 
+    0x00, 0x75, 0x03, 0x24, 0x00, 0x02, 0x00, 0x55, 0x03, 0x30, 0x00, 0x02, 0x00, 0x75, 0x03, 0x30, 
+    0x00, 0x02, 0x00, 0x55, 0x03, 0x2D, 0x00, 0x02, 0x00, 0x75, 0x03, 0x2D, 0x00, 0x02, 0x01, 0x68, 
+    0x03, 0x01, 0x00, 0x02, 0x01, 0x69, 0x03, 0x01, 0x00, 0x02, 0x01, 0x6A, 0x03, 0x08, 0x00, 0x02, 
+    0x01, 0x6B, 0x03, 0x08, 0x00, 0x02, 0x00, 0x56, 0x03, 0x03, 0x00, 0x02, 0x00, 0x76, 0x03, 0x03, 
+    0x00, 0x02, 0x00, 0x56, 0x03, 0x23, 0x00, 0x02, 0x00, 0x76, 0x03, 0x23, 0x00, 0x02, 0x00, 0x57, 
+    0x03, 0x00, 0x00, 0x02, 0x00, 0x77, 0x03, 0x00, 0x00, 0x02, 0x00, 0x57, 0x03, 0x01, 0x00, 0x02, 
+    0x00, 0x77, 0x03, 0x01, 0x00, 0x02, 0x00, 0x57, 0x03, 0x08, 0x00, 0x02, 0x00, 0x77, 0x03, 0x08, 
+    0x00, 0x02, 0x00, 0x57, 0x03, 0x07, 0x00, 0x02, 0x00, 0x77, 0x03, 0x07, 0x00, 0x02, 0x00, 0x57, 
+    0x03, 0x23, 0x00, 0x02, 0x00, 0x77, 0x03, 0x23, 0x00, 0x02, 0x00, 0x58, 0x03, 0x07, 0x00, 0x02, 
+    0x00, 0x78, 0x03, 0x07, 0x00, 0x02, 0x00, 0x58, 0x03, 0x08, 0x00, 0x02, 0x00, 0x78, 0x03, 0x08, 
+    0x00, 0x02, 0x00, 0x59, 0x03, 0x07, 0x00, 0x02, 0x00, 0x79, 0x03, 0x07, 0x00, 0x02, 0x00, 0x5A, 
+    0x03, 0x02, 0x00, 0x02, 0x00, 0x7A, 0x03, 0x02, 0x00, 0x02, 0x00, 0x5A, 0x03, 0x23, 0x00, 0x02, 
+    0x00, 0x7A, 0x03, 0x23, 0x00, 0x02, 0x00, 0x5A, 0x03, 0x31, 0x00, 0x02, 0x00, 0x7A, 0x03, 0x31, 
+    0x00, 0x02, 0x00, 0x68, 0x03, 0x31, 0x00, 0x02, 0x00, 0x74, 0x03, 0x08, 0x00, 0x02, 0x00, 0x77, 
+    0x03, 0x0A, 0x00, 0x02, 0x00, 0x79, 0x03, 0x0A, 0x00, 0x02, 0x01, 0x7F, 0x03, 0x07, 0x00, 0x02, 
+    0x00, 0x41, 0x03, 0x23, 0x00, 0x02, 0x00, 0x61, 0x03, 0x23, 0x00, 0x02, 0x00, 0x41, 0x03, 0x09, 
+    0x00, 0x02, 0x00, 0x61, 0x03, 0x09, 0x00, 0x02, 0x00, 0xC2, 0x03, 0x01, 0x00, 0x02, 0x00, 0xE2, 
+    0x03, 0x01, 0x00, 0x02, 0x00, 0xC2, 0x03, 0x00, 0x00, 0x02, 0x00, 0xE2, 0x03, 0x00, 0x00, 0x02, 
+    0x00, 0xC2, 0x03, 0x09, 0x00, 0x02, 0x00, 0xE2, 0x03, 0x09, 0x00, 0x02, 0x00, 0xC2, 0x03, 0x03, 
+    0x00, 0x02, 0x00, 0xE2, 0x03, 0x03, 0x00, 0x02, 0x00, 0xC2, 0x03, 0x23, 0x00, 0x02, 0x00, 0xE2, 
+    0x03, 0x23, 0x00, 0x02, 0x01, 0x02, 0x03, 0x01, 0x00, 0x02, 0x01, 0x03, 0x03, 0x01, 0x00, 0x02, 
+    0x01, 0x02, 0x03, 0x00, 0x00, 0x02, 0x01, 0x03, 0x03, 0x00, 0x00, 0x02, 0x01, 0x02, 0x03, 0x09, 
+    0x00, 0x02, 0x01, 0x03, 0x03, 0x09, 0x00, 0x02, 0x01, 0x02, 0x03, 0x03, 0x00, 0x02, 0x01, 0x03, 
+    0x03, 0x03, 0x00, 0x02, 0x01, 0x02, 0x03, 0x23, 0x00, 0x02, 0x01, 0x03, 0x03, 0x23, 0x00, 0x02, 
+    0x00, 0x45, 0x03, 0x23, 0x00, 0x02, 0x00, 0x65, 0x03, 0x23, 0x00, 0x02, 0x00, 0x45, 0x03, 0x09, 
+    0x00, 0x02, 0x00, 0x65, 0x03, 0x09, 0x00, 0x02, 0x00, 0x45, 0x03, 0x03, 0x00, 0x02, 0x00, 0x65, 
+    0x03, 0x03, 0x00, 0x02, 0x00, 0xCA, 0x03, 0x01, 0x00, 0x02, 0x00, 0xEA, 0x03, 0x01, 0x00, 0x02, 
+    0x00, 0xCA, 0x03, 0x00, 0x00, 0x02, 0x00, 0xEA, 0x03, 0x00, 0x00, 0x02, 0x00, 0xCA, 0x03, 0x09, 
+    0x00, 0x02, 0x00, 0xEA, 0x03, 0x09, 0x00, 0x02, 0x00, 0xCA, 0x03, 0x03, 0x00, 0x02, 0x00, 0xEA, 
+    0x03, 0x03, 0x00, 0x02, 0x00, 0xCA, 0x03, 0x23, 0x00, 0x02, 0x00, 0xEA, 0x03, 0x23, 0x00, 0x02, 
+    0x00, 0x49, 0x03, 0x09, 0x00, 0x02, 0x00, 0x69, 0x03, 0x09, 0x00, 0x02, 0x00, 0x49, 0x03, 0x23, 
+    0x00, 0x02, 0x00, 0x69, 0x03, 0x23, 0x00, 0x02, 0x00, 0x4F, 0x03, 0x23, 0x00, 0x02, 0x00, 0x6F, 
+    0x03, 0x23, 0x00, 0x02, 0x00, 0x4F, 0x03, 0x09, 0x00, 0x02, 0x00, 0x6F, 0x03, 0x09, 0x00, 0x02, 
+    0x00, 0xD4, 0x03, 0x01, 0x00, 0x02, 0x00, 0xF4, 0x03, 0x01, 0x00, 0x02, 0x00, 0xD4, 0x03, 0x00, 
+    0x00, 0x02, 0x00, 0xF4, 0x03, 0x00, 0x00, 0x02, 0x00, 0xD4, 0x03, 0x09, 0x00, 0x02, 0x00, 0xF4, 
+    0x03, 0x09, 0x00, 0x02, 0x00, 0xD4, 0x03, 0x03, 0x00, 0x02, 0x00, 0xF4, 0x03, 0x03, 0x00, 0x02, 
+    0x00, 0xD4, 0x03, 0x23, 0x00, 0x02, 0x00, 0xF4, 0x03, 0x23, 0x00, 0x02, 0x00, 0xD3, 0x03, 0x1B, 
+    0x00, 0x02, 0x00, 0xF3, 0x03, 0x1B, 0x00, 0x02, 0x00, 0xD2, 0x03, 0x1B, 0x00, 0x02, 0x00, 0xF2, 
+    0x03, 0x1B, 0x00, 0x02, 0x01, 0xA0, 0x03, 0x09, 0x00, 0x02, 0x01, 0xA1, 0x03, 0x09, 0x00, 0x02, 
+    0x00, 0xD5, 0x03, 0x1B, 0x00, 0x02, 0x00, 0xF5, 0x03, 0x1B, 0x00, 0x02, 0x01, 0xA0, 0x03, 0x23, 
+    0x00, 0x02, 0x01, 0xA1, 0x03, 0x23, 0x00, 0x02, 0x00, 0x55, 0x03, 0x23, 0x00, 0x02, 0x00, 0x75, 
+    0x03, 0x23, 0x00, 0x02, 0x00, 0x55, 0x03, 0x09, 0x00, 0x02, 0x00, 0x75, 0x03, 0x09, 0x00, 0x02, 
+    0x00, 0xDA, 0x03, 0x1B, 0x00, 0x02, 0x00, 0xFA, 0x03, 0x1B, 0x00, 0x02, 0x00, 0xD9, 0x03, 0x1B, 
+    0x00, 0x02, 0x00, 0xF9, 0x03, 0x1B, 0x00, 0x02, 0x01, 0xAF, 0x03, 0x09, 0x00, 0x02, 0x01, 0xB0, 
+    0x03, 0x09, 0x00, 0x02, 0x01, 0x68, 0x03, 0x1B, 0x00, 0x02, 0x01, 0x69, 0x03, 0x1B, 0x00, 0x02, 
+    0x01, 0xAF, 0x03, 0x23, 0x00, 0x02, 0x01, 0xB0, 0x03, 0x23, 0x00, 0x02, 0x00, 0x59, 0x03, 0x00, 
+    0x00, 0x02, 0x00, 0x79, 0x03, 0x00, 0x00, 0x02, 0x00, 0x59, 0x03, 0x23, 0x00, 0x02, 0x00, 0x79, 
+    0x03, 0x23, 0x00, 0x02, 0x00, 0x59, 0x03, 0x09, 0x00, 0x02, 0x00, 0x79, 0x03, 0x09, 0x00, 0x02, 
+    0x00, 0x59, 0x03, 0x03, 0x00, 0x02, 0x00, 0x79, 0x03, 0x03, 0x00, 0x01, 0x01, 0xF1, 0x00, 0xC0, 
+    0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00, 0xC4, 0x00, 0xC5, 0x00, 0xC7, 0x00, 0xC8, 0x00, 0xC9, 
+    0x00, 0xCA, 0x00, 0xCB, 0x00, 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00, 0xD1, 0x00, 0xD2, 
+    0x00, 0xD3, 0x00, 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00, 0xDC, 
+    0x00, 0xDD, 0x00, 0xE0, 0x00, 0xE1, 0x00, 0xE2, 0x00, 0xE3, 0x00, 0xE4, 0x00, 0xE5, 0x00, 0xE7, 
+    0x00, 0xE8, 0x00, 0xE9, 0x00, 0xEA, 0x00, 0xEB, 0x00, 0xEC, 0x00, 0xED, 0x00, 0xEE, 0x00, 0xEF, 
+    0x00, 0xF1, 0x00, 0xF2, 0x00, 0xF3, 0x00, 0xF4, 0x00, 0xF5, 0x00, 0xF6, 0x00, 0xF9, 0x00, 0xFA, 
+    0x00, 0xFB, 0x00, 0xFC, 0x00, 0xFD, 0x00, 0xFF, 0x01, 0x00, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03, 
+    0x01, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x07, 0x01, 0x08, 0x01, 0x09, 0x01, 0x0A, 0x01, 0x0B, 
+    0x01, 0x0C, 0x01, 0x0D, 0x01, 0x0E, 0x01, 0x0F, 0x01, 0x12, 0x01, 0x13, 0x01, 0x14, 0x01, 0x15, 
+    0x01, 0x16, 0x01, 0x17, 0x01, 0x18, 0x01, 0x19, 0x01, 0x1A, 0x01, 0x1B, 0x01, 0x1C, 0x01, 0x1D, 
+    0x01, 0x1E, 0x01, 0x1F, 0x01, 0x20, 0x01, 0x21, 0x01, 0x22, 0x01, 0x23, 0x01, 0x24, 0x01, 0x25, 
+    0x01, 0x28, 0x01, 0x29, 0x01, 0x2A, 0x01, 0x2B, 0x01, 0x2C, 0x01, 0x2D, 0x01, 0x2E, 0x01, 0x2F, 
+    0x01, 0x30, 0x01, 0x34, 0x01, 0x35, 0x01, 0x36, 0x01, 0x37, 0x01, 0x39, 0x01, 0x3A, 0x01, 0x3B, 
+    0x01, 0x3C, 0x01, 0x3D, 0x01, 0x3E, 0x01, 0x43, 0x01, 0x44, 0x01, 0x45, 0x01, 0x46, 0x01, 0x47, 
+    0x01, 0x48, 0x01, 0x4C, 0x01, 0x4D, 0x01, 0x4E, 0x01, 0x4F, 0x01, 0x50, 0x01, 0x51, 0x01, 0x54, 
+    0x01, 0x55, 0x01, 0x56, 0x01, 0x57, 0x01, 0x58, 0x01, 0x59, 0x01, 0x5A, 0x01, 0x5B, 0x01, 0x5C, 
+    0x01, 0x5D, 0x01, 0x5E, 0x01, 0x5F, 0x01, 0x60, 0x01, 0x61, 0x01, 0x62, 0x01, 0x63, 0x01, 0x64, 
+    0x01, 0x65, 0x01, 0x68, 0x01, 0x69, 0x01, 0x6A, 0x01, 0x6B, 0x01, 0x6C, 0x01, 0x6D, 0x01, 0x6E, 
+    0x01, 0x6F, 0x01, 0x70, 0x01, 0x71, 0x01, 0x72, 0x01, 0x73, 0x01, 0x74, 0x01, 0x75, 0x01, 0x76, 
+    0x01, 0x77, 0x01, 0x78, 0x01, 0x79, 0x01, 0x7A, 0x01, 0x7B, 0x01, 0x7C, 0x01, 0x7D, 0x01, 0x7E, 
+    0x01, 0xA0, 0x01, 0xA1, 0x01, 0xAF, 0x01, 0xB0, 0x01, 0xCD, 0x01, 0xCE, 0x01, 0xCF, 0x01, 0xD0, 
+    0x01, 0xD1, 0x01, 0xD2, 0x01, 0xD3, 0x01, 0xD4, 0x01, 0xD5, 0x01, 0xD6, 0x01, 0xD7, 0x01, 0xD8, 
+    0x01, 0xD9, 0x01, 0xDA, 0x01, 0xDB, 0x01, 0xDC, 0x01, 0xDE, 0x01, 0xDF, 0x01, 0xE0, 0x01, 0xE1, 
+    0x01, 0xE2, 0x01, 0xE3, 0x01, 0xE6, 0x01, 0xE7, 0x01, 0xE8, 0x01, 0xE9, 0x01, 0xEA, 0x01, 0xEB, 
+    0x01, 0xEC, 0x01, 0xED, 0x01, 0xEE, 0x01, 0xEF, 0x01, 0xF0, 0x01, 0xF4, 0x01, 0xF5, 0x01, 0xF8, 
+    0x01, 0xF9, 0x01, 0xFA, 0x01, 0xFB, 0x01, 0xFC, 0x01, 0xFD, 0x01, 0xFE, 0x01, 0xFF, 0x02, 0x00, 
+    0x02, 0x01, 0x02, 0x02, 0x02, 0x03, 0x02, 0x04, 0x02, 0x05, 0x02, 0x06, 0x02, 0x07, 0x02, 0x08, 
+    0x02, 0x09, 0x02, 0x0A, 0x02, 0x0B, 0x02, 0x0C, 0x02, 0x0D, 0x02, 0x0E, 0x02, 0x0F, 0x02, 0x10, 
+    0x02, 0x11, 0x02, 0x12, 0x02, 0x13, 0x02, 0x14, 0x02, 0x15, 0x02, 0x16, 0x02, 0x17, 0x02, 0x18, 
+    0x02, 0x19, 0x02, 0x1A, 0x02, 0x1B, 0x02, 0x1E, 0x02, 0x1F, 0x02, 0x26, 0x02, 0x27, 0x02, 0x28, 
+    0x02, 0x29, 0x02, 0x2A, 0x02, 0x2B, 0x02, 0x2C, 0x02, 0x2D, 0x02, 0x2E, 0x02, 0x2F, 0x02, 0x30, 
+    0x02, 0x31, 0x02, 0x32, 0x02, 0x33, 0x1E, 0x00, 0x1E, 0x01, 0x1E, 0x02, 0x1E, 0x03, 0x1E, 0x04, 
+    0x1E, 0x05, 0x1E, 0x06, 0x1E, 0x07, 0x1E, 0x08, 0x1E, 0x09, 0x1E, 0x0A, 0x1E, 0x0B, 0x1E, 0x0C, 
+    0x1E, 0x0D, 0x1E, 0x0E, 0x1E, 0x0F, 0x1E, 0x10, 0x1E, 0x11, 0x1E, 0x12, 0x1E, 0x13, 0x1E, 0x14, 
+    0x1E, 0x15, 0x1E, 0x16, 0x1E, 0x17, 0x1E, 0x18, 0x1E, 0x19, 0x1E, 0x1A, 0x1E, 0x1B, 0x1E, 0x1C, 
+    0x1E, 0x1D, 0x1E, 0x1E, 0x1E, 0x1F, 0x1E, 0x20, 0x1E, 0x21, 0x1E, 0x22, 0x1E, 0x23, 0x1E, 0x24, 
+    0x1E, 0x25, 0x1E, 0x26, 0x1E, 0x27, 0x1E, 0x28, 0x1E, 0x29, 0x1E, 0x2A, 0x1E, 0x2B, 0x1E, 0x2C, 
+    0x1E, 0x2D, 0x1E, 0x2E, 0x1E, 0x2F, 0x1E, 0x30, 0x1E, 0x31, 0x1E, 0x32, 0x1E, 0x33, 0x1E, 0x34, 
+    0x1E, 0x35, 0x1E, 0x36, 0x1E, 0x37, 0x1E, 0x38, 0x1E, 0x39, 0x1E, 0x3A, 0x1E, 0x3B, 0x1E, 0x3C, 
+    0x1E, 0x3D, 0x1E, 0x3E, 0x1E, 0x3F, 0x1E, 0x40, 0x1E, 0x41, 0x1E, 0x42, 0x1E, 0x43, 0x1E, 0x44, 
+    0x1E, 0x45, 0x1E, 0x46, 0x1E, 0x47, 0x1E, 0x48, 0x1E, 0x49, 0x1E, 0x4A, 0x1E, 0x4B, 0x1E, 0x4C, 
+    0x1E, 0x4D, 0x1E, 0x4E, 0x1E, 0x4F, 0x1E, 0x50, 0x1E, 0x51, 0x1E, 0x52, 0x1E, 0x53, 0x1E, 0x54, 
+    0x1E, 0x55, 0x1E, 0x56, 0x1E, 0x57, 0x1E, 0x58, 0x1E, 0x59, 0x1E, 0x5A, 0x1E, 0x5B, 0x1E, 0x5C, 
+    0x1E, 0x5D, 0x1E, 0x5E, 0x1E, 0x5F, 0x1E, 0x60, 0x1E, 0x61, 0x1E, 0x62, 0x1E, 0x63, 0x1E, 0x64, 
+    0x1E, 0x65, 0x1E, 0x66, 0x1E, 0x67, 0x1E, 0x68, 0x1E, 0x69, 0x1E, 0x6A, 0x1E, 0x6B, 0x1E, 0x6C, 
+    0x1E, 0x6D, 0x1E, 0x6E, 0x1E, 0x6F, 0x1E, 0x70, 0x1E, 0x71, 0x1E, 0x72, 0x1E, 0x73, 0x1E, 0x74, 
+    0x1E, 0x75, 0x1E, 0x76, 0x1E, 0x77, 0x1E, 0x78, 0x1E, 0x79, 0x1E, 0x7A, 0x1E, 0x7B, 0x1E, 0x7C, 
+    0x1E, 0x7D, 0x1E, 0x7E, 0x1E, 0x7F, 0x1E, 0x80, 0x1E, 0x81, 0x1E, 0x82, 0x1E, 0x83, 0x1E, 0x84, 
+    0x1E, 0x85, 0x1E, 0x86, 0x1E, 0x87, 0x1E, 0x88, 0x1E, 0x89, 0x1E, 0x8A, 0x1E, 0x8B, 0x1E, 0x8C, 
+    0x1E, 0x8D, 0x1E, 0x8E, 0x1E, 0x8F, 0x1E, 0x90, 0x1E, 0x91, 0x1E, 0x92, 0x1E, 0x93, 0x1E, 0x94, 
+    0x1E, 0x95, 0x1E, 0x96, 0x1E, 0x97, 0x1E, 0x98, 0x1E, 0x99, 0x1E, 0x9B, 0x1E, 0xA0, 0x1E, 0xA1, 
+    0x1E, 0xA2, 0x1E, 0xA3, 0x1E, 0xA4, 0x1E, 0xA5, 0x1E, 0xA6, 0x1E, 0xA7, 0x1E, 0xA8, 0x1E, 0xA9, 
+    0x1E, 0xAA, 0x1E, 0xAB, 0x1E, 0xAC, 0x1E, 0xAD, 0x1E, 0xAE, 0x1E, 0xAF, 0x1E, 0xB0, 0x1E, 0xB1, 
+    0x1E, 0xB2, 0x1E, 0xB3, 0x1E, 0xB4, 0x1E, 0xB5, 0x1E, 0xB6, 0x1E, 0xB7, 0x1E, 0xB8, 0x1E, 0xB9, 
+    0x1E, 0xBA, 0x1E, 0xBB, 0x1E, 0xBC, 0x1E, 0xBD, 0x1E, 0xBE, 0x1E, 0xBF, 0x1E, 0xC0, 0x1E, 0xC1, 
+    0x1E, 0xC2, 0x1E, 0xC3, 0x1E, 0xC4, 0x1E, 0xC5, 0x1E, 0xC6, 0x1E, 0xC7, 0x1E, 0xC8, 0x1E, 0xC9, 
+    0x1E, 0xCA, 0x1E, 0xCB, 0x1E, 0xCC, 0x1E, 0xCD, 0x1E, 0xCE, 0x1E, 0xCF, 0x1E, 0xD0, 0x1E, 0xD1, 
+    0x1E, 0xD2, 0x1E, 0xD3, 0x1E, 0xD4, 0x1E, 0xD5, 0x1E, 0xD6, 0x1E, 0xD7, 0x1E, 0xD8, 0x1E, 0xD9, 
+    0x1E, 0xDA, 0x1E, 0xDB, 0x1E, 0xDC, 0x1E, 0xDD, 0x1E, 0xDE, 0x1E, 0xDF, 0x1E, 0xE0, 0x1E, 0xE1, 
+    0x1E, 0xE2, 0x1E, 0xE3, 0x1E, 0xE4, 0x1E, 0xE5, 0x1E, 0xE6, 0x1E, 0xE7, 0x1E, 0xE8, 0x1E, 0xE9, 
+    0x1E, 0xEA, 0x1E, 0xEB, 0x1E, 0xEC, 0x1E, 0xED, 0x1E, 0xEE, 0x1E, 0xEF, 0x1E, 0xF0, 0x1E, 0xF1, 
+    0x1E, 0xF2, 0x1E, 0xF3, 0x1E, 0xF4, 0x1E, 0xF5, 0x1E, 0xF6, 0x1E, 0xF7, 0x1E, 0xF8, 0x1E, 0xF9, 
+    0x00, 0x01, 0x05, 0xBA, 0x00, 0xAC, 0x01, 0x5E, 0x01, 0x64, 0x01, 0x6A, 0x01, 0x70, 0x01, 0x76, 
+    0x01, 0x7C, 0x01, 0x82, 0x01, 0x88, 0x01, 0x8E, 0x01, 0x94, 0x01, 0x9A, 0x01, 0xA0, 0x01, 0xA6, 
+    0x01, 0xAC, 0x01, 0xB2, 0x01, 0xB8, 0x01, 0xBE, 0x01, 0xC4, 0x01, 0xCA, 0x01, 0xD0, 0x01, 0xD6, 
+    0x01, 0xDC, 0x01, 0xE2, 0x01, 0xE8, 0x01, 0xEE, 0x01, 0xF4, 0x01, 0xFA, 0x02, 0x00, 0x02, 0x06, 
+    0x02, 0x0C, 0x02, 0x12, 0x02, 0x18, 0x02, 0x1E, 0x02, 0x24, 0x02, 0x2A, 0x02, 0x30, 0x02, 0x38, 
+    0x02, 0x40, 0x02, 0x46, 0x02, 0x4C, 0x02, 0x54, 0x02, 0x5C, 0x02, 0x62, 0x02, 0x68, 0x02, 0x70, 
+    0x02, 0x78, 0x02, 0x80, 0x02, 0x88, 0x02, 0x8E, 0x02, 0x94, 0x02, 0x9A, 0x02, 0xA0, 0x02, 0xA6, 
+    0x02, 0xAC, 0x02, 0xB2, 0x02, 0xB8, 0x02, 0xBE, 0x02, 0xC4, 0x02, 0xCA, 0x02, 0xD0, 0x02, 0xD6, 
+    0x02, 0xDE, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF6, 0x02, 0xFE, 0x03, 0x06, 0x03, 0x0C, 0x03, 0x12, 
+    0x03, 0x18, 0x03, 0x1E, 0x03, 0x24, 0x03, 0x2A, 0x03, 0x30, 0x03, 0x36, 0x03, 0x3C, 0x03, 0x42, 
+    0x03, 0x48, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x5A, 0x03, 0x62, 0x03, 0x6A, 0x03, 0x70, 0x03, 0x76, 
+    0x03, 0x7C, 0x03, 0x82, 0x03, 0x8A, 0x03, 0x92, 0x03, 0x98, 0x03, 0x9E, 0x03, 0xA4, 0x03, 0xAA, 
+    0x03, 0xB0, 0x03, 0xB6, 0x03, 0xBE, 0x03, 0xC6, 0x03, 0xCE, 0x03, 0xD6, 0x03, 0xDE, 0x03, 0xE6, 
+    0x03, 0xEC, 0x03, 0xF2, 0x03, 0xF8, 0x03, 0xFE, 0x04, 0x06, 0x04, 0x0E, 0x04, 0x14, 0x04, 0x1A, 
+    0x04, 0x20, 0x04, 0x26, 0x04, 0x2C, 0x04, 0x32, 0x04, 0x38, 0x04, 0x3E, 0x04, 0x46, 0x04, 0x4E, 
+    0x04, 0x56, 0x04, 0x5E, 0x04, 0x64, 0x04, 0x6A, 0x04, 0x70, 0x04, 0x76, 0x04, 0x7C, 0x04, 0x82, 
+    0x04, 0x8A, 0x04, 0x92, 0x04, 0x9A, 0x04, 0xA2, 0x04, 0xA8, 0x04, 0xAE, 0x04, 0xB4, 0x04, 0xBA, 
+    0x04, 0xC0, 0x04, 0xC6, 0x04, 0xCE, 0x04, 0xD6, 0x04, 0xDE, 0x04, 0xE6, 0x04, 0xEC, 0x04, 0xF2, 
+    0x04, 0xF8, 0x04, 0xFE, 0x05, 0x04, 0x05, 0x0A, 0x05, 0x12, 0x05, 0x1A, 0x05, 0x22, 0x05, 0x2A, 
+    0x05, 0x30, 0x05, 0x36, 0x05, 0x3C, 0x05, 0x42, 0x05, 0x48, 0x05, 0x4E, 0x05, 0x54, 0x05, 0x5A, 
+    0x05, 0x60, 0x05, 0x66, 0x05, 0x6C, 0x05, 0x72, 0x05, 0x78, 0x05, 0x7E, 0x05, 0x84, 0x05, 0x8A, 
+    0x05, 0x90, 0x05, 0x96, 0x05, 0x9C, 0x05, 0xA2, 0x05, 0xA8, 0x05, 0xAE, 0x05, 0xB4, 0x00, 0x02, 
+    0x00, 0x41, 0x03, 0x40, 0x00, 0x02, 0x00, 0x41, 0x03, 0x41, 0x00, 0x02, 0x00, 0x45, 0x03, 0x40, 
+    0x00, 0x02, 0x00, 0x45, 0x03, 0x41, 0x00, 0x02, 0x00, 0x49, 0x03, 0x40, 0x00, 0x02, 0x00, 0x49, 
+    0x03, 0x41, 0x00, 0x02, 0x00, 0x4F, 0x03, 0x40, 0x00, 0x02, 0x00, 0x4F, 0x03, 0x41, 0x00, 0x02, 
+    0x00, 0x55, 0x03, 0x40, 0x00, 0x02, 0x00, 0x55, 0x03, 0x41, 0x00, 0x02, 0x00, 0x59, 0x03, 0x41, 
+    0x00, 0x02, 0x00, 0x61, 0x03, 0x40, 0x00, 0x02, 0x00, 0x61, 0x03, 0x41, 0x00, 0x02, 0x00, 0x65, 
+    0x03, 0x40, 0x00, 0x02, 0x00, 0x65, 0x03, 0x41, 0x00, 0x02, 0x00, 0x69, 0x03, 0x40, 0x00, 0x02, 
+    0x00, 0x69, 0x03, 0x41, 0x00, 0x02, 0x00, 0x6F, 0x03, 0x40, 0x00, 0x02, 0x00, 0x6F, 0x03, 0x41, 
+    0x00, 0x02, 0x00, 0x75, 0x03, 0x40, 0x00, 0x02, 0x00, 0x75, 0x03, 0x41, 0x00, 0x02, 0x00, 0x79, 
+    0x03, 0x41, 0x00, 0x02, 0x00, 0x43, 0x03, 0x41, 0x00, 0x02, 0x00, 0x63, 0x03, 0x41, 0x00, 0x02, 
+    0x21, 0x2A, 0x03, 0x27, 0x00, 0x02, 0x00, 0x4C, 0x03, 0x41, 0x00, 0x02, 0x00, 0x6C, 0x03, 0x41, 
+    0x00, 0x02, 0x00, 0x4E, 0x03, 0x41, 0x00, 0x02, 0x00, 0x6E, 0x03, 0x41, 0x00, 0x02, 0x00, 0x52, 
+    0x03, 0x41, 0x00, 0x02, 0x00, 0x72, 0x03, 0x41, 0x00, 0x02, 0x00, 0x53, 0x03, 0x41, 0x00, 0x02, 
+    0x00, 0x73, 0x03, 0x41, 0x00, 0x02, 0x00, 0x5A, 0x03, 0x41, 0x00, 0x02, 0x00, 0x7A, 0x03, 0x41, 
+    0x00, 0x03, 0x00, 0x55, 0x03, 0x08, 0x03, 0x04, 0x00, 0x03, 0x00, 0x75, 0x03, 0x08, 0x03, 0x04, 
+    0x00, 0x02, 0x00, 0xDC, 0x03, 0x01, 0x00, 0x02, 0x00, 0xFC, 0x03, 0x01, 0x00, 0x03, 0x00, 0x55, 
+    0x03, 0x08, 0x03, 0x0C, 0x00, 0x03, 0x00, 0x75, 0x03, 0x08, 0x03, 0x0C, 0x00, 0x02, 0x00, 0xDC, 
+    0x03, 0x40, 0x00, 0x02, 0x00, 0xFC, 0x03, 0x40, 0x00, 0x03, 0x00, 0x41, 0x03, 0x08, 0x03, 0x04, 
+    0x00, 0x03, 0x00, 0x61, 0x03, 0x08, 0x03, 0x04, 0x00, 0x03, 0x00, 0x41, 0x03, 0x07, 0x03, 0x04, 
+    0x00, 0x03, 0x00, 0x61, 0x03, 0x07, 0x03, 0x04, 0x00, 0x02, 0x21, 0x2A, 0x03, 0x0C, 0x00, 0x02, 
+    0x01, 0xEA, 0x03, 0x04, 0x00, 0x02, 0x01, 0xEB, 0x03, 0x04, 0x00, 0x02, 0x00, 0x47, 0x03, 0x41, 
+    0x00, 0x02, 0x00, 0x67, 0x03, 0x41, 0x00, 0x02, 0x00, 0x4E, 0x03, 0x40, 0x00, 0x02, 0x00, 0x6E, 
+    0x03, 0x40, 0x00, 0x02, 0x00, 0xC5, 0x03, 0x41, 0x00, 0x02, 0x00, 0xE5, 0x03, 0x41, 0x00, 0x02, 
+    0x00, 0xC6, 0x03, 0x41, 0x00, 0x02, 0x00, 0xE6, 0x03, 0x41, 0x00, 0x02, 0x00, 0xD8, 0x03, 0x41, 
+    0x00, 0x02, 0x00, 0xF8, 0x03, 0x41, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x08, 0x03, 0x04, 0x00, 0x03, 
+    0x00, 0x6F, 0x03, 0x08, 0x03, 0x04, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x03, 0x03, 0x04, 0x00, 0x03, 
+    0x00, 0x6F, 0x03, 0x03, 0x03, 0x04, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x07, 0x03, 0x04, 0x00, 0x03, 
+    0x00, 0x6F, 0x03, 0x07, 0x03, 0x04, 0x00, 0x02, 0x00, 0xC7, 0x03, 0x41, 0x00, 0x02, 0x00, 0xE7, 
+    0x03, 0x41, 0x00, 0x02, 0x01, 0x12, 0x03, 0x40, 0x00, 0x02, 0x01, 0x13, 0x03, 0x40, 0x00, 0x02, 
+    0x01, 0x12, 0x03, 0x41, 0x00, 0x02, 0x01, 0x13, 0x03, 0x41, 0x00, 0x02, 0x02, 0x28, 0x03, 0x06, 
+    0x00, 0x02, 0x02, 0x29, 0x03, 0x06, 0x00, 0x02, 0x00, 0xCF, 0x03, 0x01, 0x00, 0x02, 0x00, 0xEF, 
+    0x03, 0x01, 0x00, 0x02, 0x00, 0x4B, 0x03, 0x41, 0x00, 0x02, 0x00, 0x6B, 0x03, 0x41, 0x00, 0x02, 
+    0x21, 0x2A, 0x03, 0x23, 0x00, 0x02, 0x21, 0x2A, 0x03, 0x31, 0x00, 0x03, 0x00, 0x4C, 0x03, 0x04, 
+    0x03, 0x23, 0x00, 0x03, 0x00, 0x6C, 0x03, 0x04, 0x03, 0x23, 0x00, 0x02, 0x00, 0x4D, 0x03, 0x41, 
+    0x00, 0x02, 0x00, 0x6D, 0x03, 0x41, 0x00, 0x02, 0x00, 0xD5, 0x03, 0x41, 0x00, 0x02, 0x00, 0xF5, 
+    0x03, 0x41, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x03, 0x03, 0x08, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x03, 
+    0x03, 0x08, 0x00, 0x02, 0x01, 0x4C, 0x03, 0x40, 0x00, 0x02, 0x01, 0x4D, 0x03, 0x40, 0x00, 0x02, 
+    0x01, 0x4C, 0x03, 0x41, 0x00, 0x02, 0x01, 0x4D, 0x03, 0x41, 0x00, 0x02, 0x00, 0x50, 0x03, 0x41, 
+    0x00, 0x02, 0x00, 0x70, 0x03, 0x41, 0x00, 0x03, 0x00, 0x52, 0x03, 0x04, 0x03, 0x23, 0x00, 0x03, 
+    0x00, 0x72, 0x03, 0x04, 0x03, 0x23, 0x00, 0x03, 0x00, 0x53, 0x03, 0x01, 0x03, 0x07, 0x00, 0x03, 
+    0x00, 0x73, 0x03, 0x01, 0x03, 0x07, 0x00, 0x03, 0x00, 0x53, 0x03, 0x0C, 0x03, 0x07, 0x00, 0x03, 
+    0x00, 0x73, 0x03, 0x0C, 0x03, 0x07, 0x00, 0x02, 0x1E, 0x62, 0x03, 0x07, 0x00, 0x02, 0x1E, 0x63, 
+    0x03, 0x07, 0x00, 0x02, 0x01, 0x68, 0x03, 0x41, 0x00, 0x02, 0x01, 0x69, 0x03, 0x41, 0x00, 0x03, 
+    0x00, 0x55, 0x03, 0x04, 0x03, 0x08, 0x00, 0x03, 0x00, 0x75, 0x03, 0x04, 0x03, 0x08, 0x00, 0x02, 
+    0x00, 0x57, 0x03, 0x40, 0x00, 0x02, 0x00, 0x77, 0x03, 0x40, 0x00, 0x02, 0x00, 0x57, 0x03, 0x41, 
+    0x00, 0x02, 0x00, 0x77, 0x03, 0x41, 0x00, 0x02, 0x00, 0xC2, 0x03, 0x41, 0x00, 0x02, 0x00, 0xE2, 
+    0x03, 0x41, 0x00, 0x02, 0x00, 0xC2, 0x03, 0x40, 0x00, 0x02, 0x00, 0xE2, 0x03, 0x40, 0x00, 0x03, 
+    0x00, 0x41, 0x03, 0x02, 0x03, 0x09, 0x00, 0x03, 0x00, 0x61, 0x03, 0x02, 0x03, 0x09, 0x00, 0x03, 
+    0x00, 0x41, 0x03, 0x02, 0x03, 0x03, 0x00, 0x03, 0x00, 0x61, 0x03, 0x02, 0x03, 0x03, 0x00, 0x02, 
+    0x1E, 0xA0, 0x03, 0x02, 0x00, 0x02, 0x1E, 0xA1, 0x03, 0x02, 0x00, 0x02, 0x01, 0x02, 0x03, 0x41, 
+    0x00, 0x02, 0x01, 0x03, 0x03, 0x41, 0x00, 0x02, 0x01, 0x02, 0x03, 0x40, 0x00, 0x02, 0x01, 0x03, 
+    0x03, 0x40, 0x00, 0x03, 0x00, 0x41, 0x03, 0x06, 0x03, 0x09, 0x00, 0x03, 0x00, 0x61, 0x03, 0x06, 
+    0x03, 0x09, 0x00, 0x03, 0x00, 0x41, 0x03, 0x06, 0x03, 0x03, 0x00, 0x03, 0x00, 0x61, 0x03, 0x06, 
+    0x03, 0x03, 0x00, 0x02, 0x1E, 0xA0, 0x03, 0x06, 0x00, 0x02, 0x1E, 0xA1, 0x03, 0x06, 0x00, 0x02, 
+    0x00, 0xCA, 0x03, 0x41, 0x00, 0x02, 0x00, 0xEA, 0x03, 0x41, 0x00, 0x02, 0x00, 0xCA, 0x03, 0x40, 
+    0x00, 0x02, 0x00, 0xEA, 0x03, 0x40, 0x00, 0x03, 0x00, 0x45, 0x03, 0x02, 0x03, 0x09, 0x00, 0x03, 
+    0x00, 0x65, 0x03, 0x02, 0x03, 0x09, 0x00, 0x03, 0x00, 0x45, 0x03, 0x02, 0x03, 0x03, 0x00, 0x03, 
+    0x00, 0x65, 0x03, 0x02, 0x03, 0x03, 0x00, 0x02, 0x1E, 0xB8, 0x03, 0x02, 0x00, 0x02, 0x1E, 0xB9, 
+    0x03, 0x02, 0x00, 0x02, 0x00, 0xD4, 0x03, 0x41, 0x00, 0x02, 0x00, 0xF4, 0x03, 0x41, 0x00, 0x02, 
+    0x00, 0xD4, 0x03, 0x40, 0x00, 0x02, 0x00, 0xF4, 0x03, 0x40, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x02, 
+    0x03, 0x09, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x02, 0x03, 0x09, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x02, 
+    0x03, 0x03, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x02, 0x03, 0x03, 0x00, 0x02, 0x1E, 0xCC, 0x03, 0x02, 
+    0x00, 0x02, 0x1E, 0xCD, 0x03, 0x02, 0x00, 0x02, 0x01, 0xA0, 0x03, 0x01, 0x00, 0x02, 0x01, 0xA1, 
+    0x03, 0x01, 0x00, 0x02, 0x01, 0xA0, 0x03, 0x00, 0x00, 0x02, 0x01, 0xA1, 0x03, 0x00, 0x00, 0x02, 
+    0x1E, 0xCE, 0x03, 0x1B, 0x00, 0x02, 0x1E, 0xCF, 0x03, 0x1B, 0x00, 0x02, 0x01, 0xA0, 0x03, 0x03, 
+    0x00, 0x02, 0x01, 0xA1, 0x03, 0x03, 0x00, 0x02, 0x1E, 0xCC, 0x03, 0x1B, 0x00, 0x02, 0x1E, 0xCD, 
+    0x03, 0x1B, 0x00, 0x02, 0x01, 0xAF, 0x03, 0x01, 0x00, 0x02, 0x01, 0xB0, 0x03, 0x01, 0x00, 0x02, 
+    0x01, 0xAF, 0x03, 0x00, 0x00, 0x02, 0x01, 0xB0, 0x03, 0x00, 0x00, 0x02, 0x1E, 0xE6, 0x03, 0x1B, 
+    0x00, 0x02, 0x1E, 0xE7, 0x03, 0x1B, 0x00, 0x02, 0x01, 0xAF, 0x03, 0x03, 0x00, 0x02, 0x01, 0xB0, 
+    0x03, 0x03, 0x00, 0x02, 0x1E, 0xE4, 0x03, 0x1B, 0x00, 0x02, 0x1E, 0xE5, 0x03, 0x1B, 0x00, 0x02, 
+    0x00, 0x59, 0x03, 0x40, 0x00, 0x02, 0x00, 0x79, 0x03, 0x40, 0x00, 0x01, 0x00, 0xAC, 0x00, 0xC0, 
+    0x00, 0xC1, 0x00, 0xC8, 0x00, 0xC9, 0x00, 0xCC, 0x00, 0xCD, 0x00, 0xD2, 0x00, 0xD3, 0x00, 0xD9, 
+    0x00, 0xDA, 0x00, 0xDD, 0x00, 0xE0, 0x00, 0xE1, 0x00, 0xE8, 0x00, 0xE9, 0x00, 0xEC, 0x00, 0xED, 
+    0x00, 0xF2, 0x00, 0xF3, 0x00, 0xF9, 0x00, 0xFA, 0x00, 0xFD, 0x01, 0x06, 0x01, 0x07, 0x01, 0x36, 
+    0x01, 0x39, 0x01, 0x3A, 0x01, 0x43, 0x01, 0x44, 0x01, 0x54, 0x01, 0x55, 0x01, 0x5A, 0x01, 0x5B, 
+    0x01, 0x79, 0x01, 0x7A, 0x01, 0xD5, 0x01, 0xD6, 0x01, 0xD7, 0x01, 0xD8, 0x01, 0xD9, 0x01, 0xDA, 
+    0x01, 0xDB, 0x01, 0xDC, 0x01, 0xDE, 0x01, 0xDF, 0x01, 0xE0, 0x01, 0xE1, 0x01, 0xE8, 0x01, 0xEC, 
+    0x01, 0xED, 0x01, 0xF4, 0x01, 0xF5, 0x01, 0xF8, 0x01, 0xF9, 0x01, 0xFA, 0x01, 0xFB, 0x01, 0xFC, 
+    0x01, 0xFD, 0x01, 0xFE, 0x01, 0xFF, 0x02, 0x2A, 0x02, 0x2B, 0x02, 0x2C, 0x02, 0x2D, 0x02, 0x30, 
+    0x02, 0x31, 0x1E, 0x08, 0x1E, 0x09, 0x1E, 0x14, 0x1E, 0x15, 0x1E, 0x16, 0x1E, 0x17, 0x1E, 0x1C, 
+    0x1E, 0x1D, 0x1E, 0x2E, 0x1E, 0x2F, 0x1E, 0x30, 0x1E, 0x31, 0x1E, 0x32, 0x1E, 0x34, 0x1E, 0x38, 
+    0x1E, 0x39, 0x1E, 0x3E, 0x1E, 0x3F, 0x1E, 0x4C, 0x1E, 0x4D, 0x1E, 0x4E, 0x1E, 0x4F, 0x1E, 0x50, 
+    0x1E, 0x51, 0x1E, 0x52, 0x1E, 0x53, 0x1E, 0x54, 0x1E, 0x55, 0x1E, 0x5C, 0x1E, 0x5D, 0x1E, 0x64, 
+    0x1E, 0x65, 0x1E, 0x66, 0x1E, 0x67, 0x1E, 0x68, 0x1E, 0x69, 0x1E, 0x78, 0x1E, 0x79, 0x1E, 0x7A, 
+    0x1E, 0x7B, 0x1E, 0x80, 0x1E, 0x81, 0x1E, 0x82, 0x1E, 0x83, 0x1E, 0xA4, 0x1E, 0xA5, 0x1E, 0xA6, 
+    0x1E, 0xA7, 0x1E, 0xA8, 0x1E, 0xA9, 0x1E, 0xAA, 0x1E, 0xAB, 0x1E, 0xAC, 0x1E, 0xAD, 0x1E, 0xAE, 
+    0x1E, 0xAF, 0x1E, 0xB0, 0x1E, 0xB1, 0x1E, 0xB2, 0x1E, 0xB3, 0x1E, 0xB4, 0x1E, 0xB5, 0x1E, 0xB6, 
+    0x1E, 0xB7, 0x1E, 0xBE, 0x1E, 0xBF, 0x1E, 0xC0, 0x1E, 0xC1, 0x1E, 0xC2, 0x1E, 0xC3, 0x1E, 0xC4, 
+    0x1E, 0xC5, 0x1E, 0xC6, 0x1E, 0xC7, 0x1E, 0xD0, 0x1E, 0xD1, 0x1E, 0xD2, 0x1E, 0xD3, 0x1E, 0xD4, 
+    0x1E, 0xD5, 0x1E, 0xD6, 0x1E, 0xD7, 0x1E, 0xD8, 0x1E, 0xD9, 0x1E, 0xDA, 0x1E, 0xDB, 0x1E, 0xDC, 
+    0x1E, 0xDD, 0x1E, 0xDE, 0x1E, 0xDF, 0x1E, 0xE0, 0x1E, 0xE1, 0x1E, 0xE2, 0x1E, 0xE3, 0x1E, 0xE8, 
+    0x1E, 0xE9, 0x1E, 0xEA, 0x1E, 0xEB, 0x1E, 0xEC, 0x1E, 0xED, 0x1E, 0xEE, 0x1E, 0xEF, 0x1E, 0xF0, 
+    0x1E, 0xF1, 0x1E, 0xF2, 0x1E, 0xF3, 0x00, 0x01, 0x02, 0xFC, 0x00, 0x4F, 0x00, 0xA4, 0x00, 0xAA, 
+    0x00, 0xB0, 0x00, 0xB8, 0x00, 0xC0, 0x00, 0xC8, 0x00, 0xD0, 0x00, 0xD6, 0x00, 0xDE, 0x00, 0xE4, 
+    0x00, 0xEA, 0x00, 0xF2, 0x00, 0xFA, 0x01, 0x02, 0x01, 0x0A, 0x01, 0x12, 0x01, 0x1A, 0x01, 0x20, 
+    0x01, 0x26, 0x01, 0x2C, 0x01, 0x34, 0x01, 0x3C, 0x01, 0x44, 0x01, 0x4C, 0x01, 0x54, 0x01, 0x5C, 
+    0x01, 0x64, 0x01, 0x6C, 0x01, 0x74, 0x01, 0x7C, 0x01, 0x84, 0x01, 0x8C, 0x01, 0x94, 0x01, 0x9C, 
+    0x01, 0xA4, 0x01, 0xAC, 0x01, 0xB4, 0x01, 0xBC, 0x01, 0xC4, 0x01, 0xCC, 0x01, 0xD4, 0x01, 0xDC, 
+    0x01, 0xE4, 0x01, 0xEC, 0x01, 0xF4, 0x01, 0xFC, 0x02, 0x04, 0x02, 0x0C, 0x02, 0x14, 0x02, 0x1C, 
+    0x02, 0x24, 0x02, 0x2C, 0x02, 0x34, 0x02, 0x3C, 0x02, 0x44, 0x02, 0x4C, 0x02, 0x54, 0x02, 0x5C, 
+    0x02, 0x64, 0x02, 0x6C, 0x02, 0x72, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02, 0x8C, 0x02, 0x94, 
+    0x02, 0x9C, 0x02, 0xA4, 0x02, 0xAC, 0x02, 0xB4, 0x02, 0xBA, 0x02, 0xC0, 0x02, 0xC6, 0x02, 0xCC, 
+    0x02, 0xD4, 0x02, 0xDC, 0x02, 0xE4, 0x02, 0xEC, 0x02, 0xF4, 0x00, 0x02, 0x00, 0xDC, 0x03, 0x41, 
+    0x00, 0x02, 0x00, 0xFC, 0x03, 0x41, 0x00, 0x03, 0x00, 0x55, 0x03, 0x08, 0x03, 0x00, 0x00, 0x03, 
+    0x00, 0x75, 0x03, 0x08, 0x03, 0x00, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x04, 0x03, 0x28, 0x00, 0x03, 
+    0x00, 0x6F, 0x03, 0x04, 0x03, 0x28, 0x00, 0x02, 0x21, 0x2B, 0x03, 0x01, 0x00, 0x03, 0x00, 0x61, 
+    0x03, 0x0A, 0x03, 0x01, 0x00, 0x02, 0x01, 0x06, 0x03, 0x27, 0x00, 0x02, 0x01, 0x07, 0x03, 0x27, 
+    0x00, 0x03, 0x00, 0x45, 0x03, 0x04, 0x03, 0x00, 0x00, 0x03, 0x00, 0x65, 0x03, 0x04, 0x03, 0x00, 
+    0x00, 0x03, 0x00, 0x45, 0x03, 0x04, 0x03, 0x01, 0x00, 0x03, 0x00, 0x65, 0x03, 0x04, 0x03, 0x01, 
+    0x00, 0x03, 0x00, 0x45, 0x03, 0x06, 0x03, 0x27, 0x00, 0x03, 0x00, 0x65, 0x03, 0x06, 0x03, 0x27, 
+    0x00, 0x02, 0x00, 0xCF, 0x03, 0x41, 0x00, 0x02, 0x00, 0xEF, 0x03, 0x41, 0x00, 0x02, 0x21, 0x2A, 
+    0x03, 0x01, 0x00, 0x03, 0x00, 0x4C, 0x03, 0x23, 0x03, 0x04, 0x00, 0x03, 0x00, 0x6C, 0x03, 0x23, 
+    0x03, 0x04, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x03, 0x03, 0x01, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x03, 
+    0x03, 0x01, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x04, 0x03, 0x00, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x04, 
+    0x03, 0x00, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x04, 0x03, 0x01, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x04, 
+    0x03, 0x01, 0x00, 0x03, 0x00, 0x52, 0x03, 0x23, 0x03, 0x04, 0x00, 0x03, 0x00, 0x72, 0x03, 0x23, 
+    0x03, 0x04, 0x00, 0x03, 0x00, 0x53, 0x03, 0x41, 0x03, 0x07, 0x00, 0x03, 0x00, 0x73, 0x03, 0x41, 
+    0x03, 0x07, 0x00, 0x03, 0x00, 0x53, 0x03, 0x07, 0x03, 0x23, 0x00, 0x03, 0x00, 0x73, 0x03, 0x07, 
+    0x03, 0x23, 0x00, 0x03, 0x00, 0x55, 0x03, 0x03, 0x03, 0x01, 0x00, 0x03, 0x00, 0x75, 0x03, 0x03, 
+    0x03, 0x01, 0x00, 0x03, 0x00, 0x41, 0x03, 0x02, 0x03, 0x01, 0x00, 0x03, 0x00, 0x61, 0x03, 0x02, 
+    0x03, 0x01, 0x00, 0x03, 0x00, 0x41, 0x03, 0x02, 0x03, 0x00, 0x00, 0x03, 0x00, 0x61, 0x03, 0x02, 
+    0x03, 0x00, 0x00, 0x03, 0x00, 0x41, 0x03, 0x02, 0x03, 0x23, 0x00, 0x03, 0x00, 0x61, 0x03, 0x02, 
+    0x03, 0x23, 0x00, 0x03, 0x00, 0x41, 0x03, 0x06, 0x03, 0x01, 0x00, 0x03, 0x00, 0x61, 0x03, 0x06, 
+    0x03, 0x01, 0x00, 0x03, 0x00, 0x41, 0x03, 0x06, 0x03, 0x00, 0x00, 0x03, 0x00, 0x61, 0x03, 0x06, 
+    0x03, 0x00, 0x00, 0x03, 0x00, 0x41, 0x03, 0x06, 0x03, 0x23, 0x00, 0x03, 0x00, 0x61, 0x03, 0x06, 
+    0x03, 0x23, 0x00, 0x03, 0x00, 0x45, 0x03, 0x02, 0x03, 0x01, 0x00, 0x03, 0x00, 0x65, 0x03, 0x02, 
+    0x03, 0x01, 0x00, 0x03, 0x00, 0x45, 0x03, 0x02, 0x03, 0x00, 0x00, 0x03, 0x00, 0x65, 0x03, 0x02, 
+    0x03, 0x00, 0x00, 0x03, 0x00, 0x45, 0x03, 0x02, 0x03, 0x23, 0x00, 0x03, 0x00, 0x65, 0x03, 0x02, 
+    0x03, 0x23, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x02, 0x03, 0x01, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x02, 
+    0x03, 0x01, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x02, 0x03, 0x00, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x02, 
+    0x03, 0x00, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x02, 0x03, 0x23, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x02, 
+    0x03, 0x23, 0x00, 0x02, 0x01, 0xA0, 0x03, 0x41, 0x00, 0x02, 0x01, 0xA1, 0x03, 0x41, 0x00, 0x02, 
+    0x01, 0xA0, 0x03, 0x40, 0x00, 0x02, 0x01, 0xA1, 0x03, 0x40, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x09, 
+    0x03, 0x1B, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x09, 0x03, 0x1B, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x03, 
+    0x03, 0x1B, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x03, 0x03, 0x1B, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x1B, 
+    0x03, 0x23, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x1B, 0x03, 0x23, 0x00, 0x02, 0x01, 0xAF, 0x03, 0x41, 
+    0x00, 0x02, 0x01, 0xB0, 0x03, 0x41, 0x00, 0x02, 0x01, 0xAF, 0x03, 0x40, 0x00, 0x02, 0x01, 0xB0, 
+    0x03, 0x40, 0x00, 0x03, 0x00, 0x55, 0x03, 0x09, 0x03, 0x1B, 0x00, 0x03, 0x00, 0x75, 0x03, 0x09, 
+    0x03, 0x1B, 0x00, 0x03, 0x00, 0x55, 0x03, 0x03, 0x03, 0x1B, 0x00, 0x03, 0x00, 0x75, 0x03, 0x03, 
+    0x03, 0x1B, 0x00, 0x03, 0x00, 0x55, 0x03, 0x1B, 0x03, 0x23, 0x00, 0x03, 0x00, 0x75, 0x03, 0x1B, 
+    0x03, 0x23, 0x00, 0x01, 0x00, 0x4F, 0x01, 0xD7, 0x01, 0xD8, 0x01, 0xDB, 0x01, 0xDC, 0x01, 0xEC, 
+    0x01, 0xED, 0x01, 0xFA, 0x01, 0xFB, 0x1E, 0x08, 0x1E, 0x09, 0x1E, 0x14, 0x1E, 0x15, 0x1E, 0x16, 
+    0x1E, 0x17, 0x1E, 0x1C, 0x1E, 0x1D, 0x1E, 0x2E, 0x1E, 0x2F, 0x1E, 0x30, 0x1E, 0x38, 0x1E, 0x39, 
+    0x1E, 0x4C, 0x1E, 0x4D, 0x1E, 0x50, 0x1E, 0x51, 0x1E, 0x52, 0x1E, 0x53, 0x1E, 0x5C, 0x1E, 0x5D, 
+    0x1E, 0x64, 0x1E, 0x65, 0x1E, 0x68, 0x1E, 0x69, 0x1E, 0x78, 0x1E, 0x79, 0x1E, 0xA4, 0x1E, 0xA5, 
+    0x1E, 0xA6, 0x1E, 0xA7, 0x1E, 0xAC, 0x1E, 0xAD, 0x1E, 0xAE, 0x1E, 0xAF, 0x1E, 0xB0, 0x1E, 0xB1, 
+    0x1E, 0xB6, 0x1E, 0xB7, 0x1E, 0xBE, 0x1E, 0xBF, 0x1E, 0xC0, 0x1E, 0xC1, 0x1E, 0xC6, 0x1E, 0xC7, 
+    0x1E, 0xD0, 0x1E, 0xD1, 0x1E, 0xD2, 0x1E, 0xD3, 0x1E, 0xD8, 0x1E, 0xD9, 0x1E, 0xDA, 0x1E, 0xDB, 
+    0x1E, 0xDC, 0x1E, 0xDD, 0x1E, 0xDE, 0x1E, 0xDF, 0x1E, 0xE0, 0x1E, 0xE1, 0x1E, 0xE2, 0x1E, 0xE3, 
+    0x1E, 0xE8, 0x1E, 0xE9, 0x1E, 0xEA, 0x1E, 0xEB, 0x1E, 0xEC, 0x1E, 0xED, 0x1E, 0xEE, 0x1E, 0xEF, 
+    0x1E, 0xF0, 0x1E, 0xF1, 0x00, 0x01, 0x02, 0xDC, 0x00, 0x49, 0x00, 0x98, 0x00, 0xA0, 0x00, 0xA8, 
+    0x00, 0xB0, 0x00, 0xB8, 0x00, 0xC0, 0x00, 0xC8, 0x00, 0xCE, 0x00, 0xD6, 0x00, 0xDE, 0x00, 0xE6, 
+    0x00, 0xEE, 0x00, 0xF6, 0x00, 0xFE, 0x01, 0x06, 0x01, 0x0E, 0x01, 0x16, 0x01, 0x1E, 0x01, 0x26, 
+    0x01, 0x2C, 0x01, 0x34, 0x01, 0x3C, 0x01, 0x44, 0x01, 0x4C, 0x01, 0x54, 0x01, 0x5C, 0x01, 0x64, 
+    0x01, 0x6C, 0x01, 0x74, 0x01, 0x7C, 0x01, 0x84, 0x01, 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA4, 
+    0x01, 0xAC, 0x01, 0xB4, 0x01, 0xBC, 0x01, 0xC4, 0x01, 0xCC, 0x01, 0xD4, 0x01, 0xDC, 0x01, 0xE4, 
+    0x01, 0xEC, 0x01, 0xF4, 0x01, 0xFC, 0x02, 0x04, 0x02, 0x0C, 0x02, 0x14, 0x02, 0x1C, 0x02, 0x24, 
+    0x02, 0x2C, 0x02, 0x34, 0x02, 0x3C, 0x02, 0x44, 0x02, 0x4C, 0x02, 0x54, 0x02, 0x5C, 0x02, 0x64, 
+    0x02, 0x6C, 0x02, 0x74, 0x02, 0x7C, 0x02, 0x84, 0x02, 0x8C, 0x02, 0x94, 0x02, 0x9C, 0x02, 0xA4, 
+    0x02, 0xAC, 0x02, 0xB4, 0x02, 0xBC, 0x02, 0xC4, 0x02, 0xCC, 0x02, 0xD4, 0x00, 0x03, 0x00, 0x55, 
+    0x03, 0x08, 0x03, 0x01, 0x00, 0x03, 0x00, 0x75, 0x03, 0x08, 0x03, 0x01, 0x00, 0x03, 0x00, 0x55, 
+    0x03, 0x08, 0x03, 0x40, 0x00, 0x03, 0x00, 0x75, 0x03, 0x08, 0x03, 0x40, 0x00, 0x03, 0x00, 0x4F, 
+    0x03, 0x28, 0x03, 0x04, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x28, 0x03, 0x04, 0x00, 0x02, 0x21, 0x2B, 
+    0x03, 0x41, 0x00, 0x03, 0x00, 0x61, 0x03, 0x0A, 0x03, 0x41, 0x00, 0x03, 0x00, 0x43, 0x03, 0x01, 
+    0x03, 0x27, 0x00, 0x03, 0x00, 0x63, 0x03, 0x01, 0x03, 0x27, 0x00, 0x03, 0x00, 0x45, 0x03, 0x04, 
+    0x03, 0x40, 0x00, 0x03, 0x00, 0x65, 0x03, 0x04, 0x03, 0x40, 0x00, 0x03, 0x00, 0x45, 0x03, 0x04, 
+    0x03, 0x41, 0x00, 0x03, 0x00, 0x65, 0x03, 0x04, 0x03, 0x41, 0x00, 0x03, 0x00, 0x45, 0x03, 0x27, 
+    0x03, 0x06, 0x00, 0x03, 0x00, 0x65, 0x03, 0x27, 0x03, 0x06, 0x00, 0x03, 0x00, 0x49, 0x03, 0x08, 
+    0x03, 0x01, 0x00, 0x03, 0x00, 0x69, 0x03, 0x08, 0x03, 0x01, 0x00, 0x02, 0x21, 0x2A, 0x03, 0x41, 
+    0x00, 0x03, 0x00, 0x4F, 0x03, 0x03, 0x03, 0x41, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x03, 0x03, 0x41, 
+    0x00, 0x03, 0x00, 0x4F, 0x03, 0x04, 0x03, 0x40, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x04, 0x03, 0x40, 
+    0x00, 0x03, 0x00, 0x4F, 0x03, 0x04, 0x03, 0x41, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x04, 0x03, 0x41, 
+    0x00, 0x03, 0x00, 0x53, 0x03, 0x23, 0x03, 0x07, 0x00, 0x03, 0x00, 0x73, 0x03, 0x23, 0x03, 0x07, 
+    0x00, 0x03, 0x00, 0x55, 0x03, 0x03, 0x03, 0x41, 0x00, 0x03, 0x00, 0x75, 0x03, 0x03, 0x03, 0x41, 
+    0x00, 0x03, 0x00, 0x41, 0x03, 0x02, 0x03, 0x41, 0x00, 0x03, 0x00, 0x61, 0x03, 0x02, 0x03, 0x41, 
+    0x00, 0x03, 0x00, 0x41, 0x03, 0x02, 0x03, 0x40, 0x00, 0x03, 0x00, 0x61, 0x03, 0x02, 0x03, 0x40, 
+    0x00, 0x03, 0x00, 0x41, 0x03, 0x23, 0x03, 0x02, 0x00, 0x03, 0x00, 0x61, 0x03, 0x23, 0x03, 0x02, 
+    0x00, 0x03, 0x00, 0x41, 0x03, 0x06, 0x03, 0x41, 0x00, 0x03, 0x00, 0x61, 0x03, 0x06, 0x03, 0x41, 
+    0x00, 0x03, 0x00, 0x41, 0x03, 0x06, 0x03, 0x40, 0x00, 0x03, 0x00, 0x61, 0x03, 0x06, 0x03, 0x40, 
+    0x00, 0x03, 0x00, 0x41, 0x03, 0x23, 0x03, 0x06, 0x00, 0x03, 0x00, 0x61, 0x03, 0x23, 0x03, 0x06, 
+    0x00, 0x03, 0x00, 0x45, 0x03, 0x02, 0x03, 0x41, 0x00, 0x03, 0x00, 0x65, 0x03, 0x02, 0x03, 0x41, 
+    0x00, 0x03, 0x00, 0x45, 0x03, 0x02, 0x03, 0x40, 0x00, 0x03, 0x00, 0x65, 0x03, 0x02, 0x03, 0x40, 
+    0x00, 0x03, 0x00, 0x45, 0x03, 0x23, 0x03, 0x02, 0x00, 0x03, 0x00, 0x65, 0x03, 0x23, 0x03, 0x02, 
+    0x00, 0x03, 0x00, 0x4F, 0x03, 0x02, 0x03, 0x41, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x02, 0x03, 0x41, 
+    0x00, 0x03, 0x00, 0x4F, 0x03, 0x02, 0x03, 0x40, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x02, 0x03, 0x40, 
+    0x00, 0x03, 0x00, 0x4F, 0x03, 0x23, 0x03, 0x02, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x23, 0x03, 0x02, 
+    0x00, 0x03, 0x00, 0x4F, 0x03, 0x01, 0x03, 0x1B, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x01, 0x03, 0x1B, 
+    0x00, 0x03, 0x00, 0x4F, 0x03, 0x00, 0x03, 0x1B, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x00, 0x03, 0x1B, 
+    0x00, 0x03, 0x00, 0x4F, 0x03, 0x1B, 0x03, 0x09, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x1B, 0x03, 0x09, 
+    0x00, 0x03, 0x00, 0x4F, 0x03, 0x1B, 0x03, 0x03, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x1B, 0x03, 0x03, 
+    0x00, 0x03, 0x00, 0x4F, 0x03, 0x23, 0x03, 0x1B, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x23, 0x03, 0x1B, 
+    0x00, 0x03, 0x00, 0x55, 0x03, 0x01, 0x03, 0x1B, 0x00, 0x03, 0x00, 0x75, 0x03, 0x01, 0x03, 0x1B, 
+    0x00, 0x03, 0x00, 0x55, 0x03, 0x00, 0x03, 0x1B, 0x00, 0x03, 0x00, 0x75, 0x03, 0x00, 0x03, 0x1B, 
+    0x00, 0x03, 0x00, 0x55, 0x03, 0x1B, 0x03, 0x09, 0x00, 0x03, 0x00, 0x75, 0x03, 0x1B, 0x03, 0x09, 
+    0x00, 0x03, 0x00, 0x55, 0x03, 0x1B, 0x03, 0x03, 0x00, 0x03, 0x00, 0x75, 0x03, 0x1B, 0x03, 0x03, 
+    0x00, 0x03, 0x00, 0x55, 0x03, 0x23, 0x03, 0x1B, 0x00, 0x03, 0x00, 0x75, 0x03, 0x23, 0x03, 0x1B, 
+    0x00, 0x01, 0x00, 0x49, 0x01, 0xD7, 0x01, 0xD8, 0x01, 0xDB, 0x01, 0xDC, 0x01, 0xEC, 0x01, 0xED, 
+    0x01, 0xFA, 0x01, 0xFB, 0x1E, 0x08, 0x1E, 0x09, 0x1E, 0x14, 0x1E, 0x15, 0x1E, 0x16, 0x1E, 0x17, 
+    0x1E, 0x1C, 0x1E, 0x1D, 0x1E, 0x2E, 0x1E, 0x2F, 0x1E, 0x30, 0x1E, 0x4C, 0x1E, 0x4D, 0x1E, 0x50, 
+    0x1E, 0x51, 0x1E, 0x52, 0x1E, 0x53, 0x1E, 0x68, 0x1E, 0x69, 0x1E, 0x78, 0x1E, 0x79, 0x1E, 0xA4, 
+    0x1E, 0xA5, 0x1E, 0xA6, 0x1E, 0xA7, 0x1E, 0xAC, 0x1E, 0xAD, 0x1E, 0xAE, 0x1E, 0xAF, 0x1E, 0xB0, 
+    0x1E, 0xB1, 0x1E, 0xB6, 0x1E, 0xB7, 0x1E, 0xBE, 0x1E, 0xBF, 0x1E, 0xC0, 0x1E, 0xC1, 0x1E, 0xC6, 
+    0x1E, 0xC7, 0x1E, 0xD0, 0x1E, 0xD1, 0x1E, 0xD2, 0x1E, 0xD3, 0x1E, 0xD8, 0x1E, 0xD9, 0x1E, 0xDA, 
+    0x1E, 0xDB, 0x1E, 0xDC, 0x1E, 0xDD, 0x1E, 0xDE, 0x1E, 0xDF, 0x1E, 0xE0, 0x1E, 0xE1, 0x1E, 0xE2, 
+    0x1E, 0xE3, 0x1E, 0xE8, 0x1E, 0xE9, 0x1E, 0xEA, 0x1E, 0xEB, 0x1E, 0xEC, 0x1E, 0xED, 0x1E, 0xEE, 
+    0x1E, 0xEF, 0x1E, 0xF0, 0x1E, 0xF1, 0x00, 0x01, 0x00, 0x9C, 0x00, 0x0F, 0x00, 0x24, 0x00, 0x2C, 
+    0x00, 0x34, 0x00, 0x3C, 0x00, 0x44, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x5C, 0x00, 0x64, 0x00, 0x6C, 
+    0x00, 0x74, 0x00, 0x7C, 0x00, 0x84, 0x00, 0x8C, 0x00, 0x94, 0x00, 0x03, 0x00, 0x55, 0x03, 0x08, 
+    0x03, 0x41, 0x00, 0x03, 0x00, 0x75, 0x03, 0x08, 0x03, 0x41, 0x00, 0x03, 0x00, 0x41, 0x03, 0x0A, 
+    0x03, 0x01, 0x00, 0x03, 0x00, 0x43, 0x03, 0x27, 0x03, 0x01, 0x00, 0x03, 0x00, 0x63, 0x03, 0x27, 
+    0x03, 0x01, 0x00, 0x03, 0x00, 0x49, 0x03, 0x08, 0x03, 0x41, 0x00, 0x03, 0x00, 0x69, 0x03, 0x08, 
+    0x03, 0x41, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x1B, 0x03, 0x01, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x1B, 
+    0x03, 0x01, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x1B, 0x03, 0x00, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x1B, 
+    0x03, 0x00, 0x00, 0x03, 0x00, 0x55, 0x03, 0x1B, 0x03, 0x01, 0x00, 0x03, 0x00, 0x75, 0x03, 0x1B, 
+    0x03, 0x01, 0x00, 0x03, 0x00, 0x55, 0x03, 0x1B, 0x03, 0x00, 0x00, 0x03, 0x00, 0x75, 0x03, 0x1B, 
+    0x03, 0x00, 0x00, 0x01, 0x00, 0x0F, 0x01, 0xD7, 0x01, 0xD8, 0x01, 0xFA, 0x1E, 0x08, 0x1E, 0x09, 
+    0x1E, 0x2E, 0x1E, 0x2F, 0x1E, 0xDA, 0x1E, 0xDB, 0x1E, 0xDC, 0x1E, 0xDD, 0x1E, 0xE8, 0x1E, 0xE9, 
+    0x1E, 0xEA, 0x1E, 0xEB, 0x00, 0x01, 0x00, 0x74, 0x00, 0x0B, 0x00, 0x1C, 0x00, 0x24, 0x00, 0x2C, 
+    0x00, 0x34, 0x00, 0x3C, 0x00, 0x44, 0x00, 0x4C, 0x00, 0x54, 0x00, 0x5C, 0x00, 0x64, 0x00, 0x6C, 
+    0x00, 0x03, 0x00, 0x41, 0x03, 0x0A, 0x03, 0x41, 0x00, 0x03, 0x00, 0x43, 0x03, 0x27, 0x03, 0x41, 
+    0x00, 0x03, 0x00, 0x63, 0x03, 0x27, 0x03, 0x41, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x1B, 0x03, 0x41, 
+    0x00, 0x03, 0x00, 0x6F, 0x03, 0x1B, 0x03, 0x41, 0x00, 0x03, 0x00, 0x4F, 0x03, 0x1B, 0x03, 0x40, 
+    0x00, 0x03, 0x00, 0x6F, 0x03, 0x1B, 0x03, 0x40, 0x00, 0x03, 0x00, 0x55, 0x03, 0x1B, 0x03, 0x41, 
+    0x00, 0x03, 0x00, 0x75, 0x03, 0x1B, 0x03, 0x41, 0x00, 0x03, 0x00, 0x55, 0x03, 0x1B, 0x03, 0x40, 
+    0x00, 0x03, 0x00, 0x75, 0x03, 0x1B, 0x03, 0x40, 0x00, 0x01, 0x00, 0x0B, 0x01, 0xFA, 0x1E, 0x08, 
+    0x1E, 0x09, 0x1E, 0xDA, 0x1E, 0xDB, 0x1E, 0xDC, 0x1E, 0xDD, 0x1E, 0xE8, 0x1E, 0xE9, 0x1E, 0xEA, 
+    0x1E, 0xEB, 0x00, 0x01, 0x00, 0x6A, 0x00, 0x0A, 0x00, 0x1A, 0x00, 0x22, 0x00, 0x2A, 0x00, 0x32, 
+    0x00, 0x3A, 0x00, 0x42, 0x00, 0x4A, 0x00, 0x52, 0x00, 0x5A, 0x00, 0x62, 0x00, 0x03, 0x00, 0x43, 
+    0x03, 0x41, 0x03, 0x27, 0x00, 0x03, 0x00, 0x63, 0x03, 0x41, 0x03, 0x27, 0x00, 0x03, 0x00, 0x4F, 
+    0x03, 0x41, 0x03, 0x1B, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x41, 0x03, 0x1B, 0x00, 0x03, 0x00, 0x4F, 
+    0x03, 0x40, 0x03, 0x1B, 0x00, 0x03, 0x00, 0x6F, 0x03, 0x40, 0x03, 0x1B, 0x00, 0x03, 0x00, 0x55, 
+    0x03, 0x41, 0x03, 0x1B, 0x00, 0x03, 0x00, 0x75, 0x03, 0x41, 0x03, 0x1B, 0x00, 0x03, 0x00, 0x55, 
+    0x03, 0x40, 0x03, 0x1B, 0x00, 0x03, 0x00, 0x75, 0x03, 0x40, 0x03, 0x1B, 0x00, 0x01, 0x00, 0x0A, 
+    0x1E, 0x08, 0x1E, 0x09, 0x1E, 0xDA, 0x1E, 0xDB, 0x1E, 0xDC, 0x1E, 0xDD, 0x1E, 0xE8, 0x1E, 0xE9, 
+    0x1E, 0xEA, 0x1E, 0xEB, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x26, 
+    0x00, 0x02, 0x00, 0x0A, 0x00, 0x1C, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0C, 0x0D, 0x4A, 0x00, 0x02, 
+    0x0D, 0x3E, 0x0D, 0x4C, 0x00, 0x02, 0x0D, 0x57, 0x00, 0x01, 0x00, 0x04, 0x0D, 0x4B, 0x00, 0x02, 
+    0x0D, 0x3E, 0x00, 0x01, 0x00, 0x02, 0x0D, 0x46, 0x0D, 0x47, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 
+    0x00, 0x08, 0x00, 0x01, 0x00, 0x1E, 0x00, 0x03, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x02, 
+    0x0D, 0x46, 0x0D, 0x3E, 0x00, 0x02, 0x0D, 0x47, 0x0D, 0x3E, 0x00, 0x02, 0x0D, 0x46, 0x0D, 0x57, 
+    0x00, 0x01, 0x00, 0x03, 0x0D, 0x4A, 0x0D, 0x4B, 0x0D, 0x4C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 
+    0x00, 0x08, 0x00, 0x01, 0x00, 0x12, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x04, 0x10, 0x26, 
+    0x00, 0x02, 0x10, 0x2E, 0x00, 0x01, 0x00, 0x01, 0x10, 0x25, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 
+    0x00, 0x08, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x10, 0x25, 0x10, 0x2E, 
+    0x00, 0x01, 0x00, 0x01, 0x10, 0x26, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 
+    0x00, 0x22, 0x00, 0x01, 0x00, 0x08, 0x00, 0x03, 0x00, 0x08, 0x00, 0x0E, 0x00, 0x14, 0x0B, 0x4B, 
+    0x00, 0x02, 0x0B, 0x3E, 0x0B, 0x48, 0x00, 0x02, 0x0B, 0x56, 0x0B, 0x4C, 0x00, 0x02, 0x0B, 0x57, 
+    0x00, 0x01, 0x00, 0x01, 0x0B, 0x47, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 
+    0x00, 0x1E, 0x00, 0x03, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x02, 0x0B, 0x47, 0x0B, 0x56, 
+    0x00, 0x02, 0x0B, 0x47, 0x0B, 0x3E, 0x00, 0x02, 0x0B, 0x47, 0x0B, 0x57, 0x00, 0x01, 0x00, 0x03, 
+    0x0B, 0x48, 0x0B, 0x4B, 0x0B, 0x4C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 
+    0x00, 0x38, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x2E, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x18, 
+    0x00, 0x1E, 0x0D, 0xDA, 0x00, 0x02, 0x0D, 0xCA, 0x0D, 0xDD, 0x00, 0x03, 0x0D, 0xCF, 0x0D, 0xCA, 
+    0x0D, 0xDC, 0x00, 0x02, 0x0D, 0xCF, 0x0D, 0xDE, 0x00, 0x02, 0x0D, 0xDF, 0x00, 0x01, 0x00, 0x04, 
+    0x0D, 0xDD, 0x00, 0x02, 0x0D, 0xCA, 0x00, 0x01, 0x00, 0x02, 0x0D, 0xD9, 0x0D, 0xDC, 0x00, 0x02, 
+    0x00, 0x00, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x3C, 0x00, 0x01, 0x00, 0x26, 0x00, 0x04, 0x00, 0x0E, 
+    0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x02, 0x0D, 0xD9, 0x0D, 0xCA, 0x00, 0x02, 0x0D, 0xD9, 
+    0x0D, 0xCF, 0x00, 0x02, 0x0D, 0xDC, 0x0D, 0xCA, 0x00, 0x02, 0x0D, 0xD9, 0x0D, 0xDF, 0x00, 0x01, 
+    0x00, 0x04, 0x0D, 0xDA, 0x0D, 0xDC, 0x0D, 0xDD, 0x0D, 0xDE, 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 
+    0x00, 0x08, 0x00, 0x03, 0x0D, 0xD9, 0x0D, 0xCF, 0x0D, 0xCA, 0x00, 0x01, 0x00, 0x01, 0x0D, 0xDD, 
+    0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x32, 0x00, 0x03, 0x00, 0x0C, 
+    0x00, 0x16, 0x00, 0x28, 0x00, 0x01, 0x00, 0x04, 0x0B, 0x94, 0x00, 0x02, 0x0B, 0xD7, 0x00, 0x02, 
+    0x00, 0x06, 0x00, 0x0C, 0x0B, 0xCA, 0x00, 0x02, 0x0B, 0xBE, 0x0B, 0xCC, 0x00, 0x02, 0x0B, 0xD7, 
+    0x00, 0x01, 0x00, 0x04, 0x0B, 0xCB, 0x00, 0x02, 0x0B, 0xBE, 0x00, 0x01, 0x00, 0x03, 0x0B, 0x92, 
+    0x0B, 0xC6, 0x0B, 0xC7, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x26, 
+    0x00, 0x04, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x02, 0x0B, 0x92, 0x0B, 0xD7, 
+    0x00, 0x02, 0x0B, 0xC6, 0x0B, 0xBE, 0x00, 0x02, 0x0B, 0xC7, 0x0B, 0xBE, 0x00, 0x02, 0x0B, 0xC6, 
+    0x0B, 0xD7, 0x00, 0x01, 0x00, 0x04, 0x0B, 0x94, 0x0B, 0xCA, 0x0B, 0xCB, 0x0B, 0xCC, 0x00, 0x04, 
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x12, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 
+    0x00, 0x04, 0x0C, 0x48, 0x00, 0x02, 0x0C, 0x56, 0x00, 0x01, 0x00, 0x01, 0x0C, 0x46, 0x00, 0x02, 
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 
+    0x0C, 0x46, 0x0C, 0x56, 0x00, 0x01, 0x00, 0x01, 0x0C, 0x48, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 
+    0x00, 0x08, 0x00, 0x01, 0x00, 0x8A, 0x00, 0x0B, 0x00, 0x1C, 0x00, 0x26, 0x00, 0x30, 0x00, 0x3A, 
+    0x00, 0x44, 0x00, 0x4E, 0x00, 0x58, 0x00, 0x62, 0x00, 0x6C, 0x00, 0x76, 0x00, 0x80, 0x00, 0x01, 
+    0x00, 0x04, 0x1B, 0x06, 0x00, 0x02, 0x1B, 0x35, 0x00, 0x01, 0x00, 0x04, 0x1B, 0x08, 0x00, 0x02, 
+    0x1B, 0x35, 0x00, 0x01, 0x00, 0x04, 0x1B, 0x0A, 0x00, 0x02, 0x1B, 0x35, 0x00, 0x01, 0x00, 0x04, 
+    0x1B, 0x0C, 0x00, 0x02, 0x1B, 0x35, 0x00, 0x01, 0x00, 0x04, 0x1B, 0x0E, 0x00, 0x02, 0x1B, 0x35, 
+    0x00, 0x01, 0x00, 0x04, 0x1B, 0x12, 0x00, 0x02, 0x1B, 0x35, 0x00, 0x01, 0x00, 0x04, 0x1B, 0x3B, 
+    0x00, 0x02, 0x1B, 0x35, 0x00, 0x01, 0x00, 0x04, 0x1B, 0x3D, 0x00, 0x02, 0x1B, 0x35, 0x00, 0x01, 
+    0x00, 0x04, 0x1B, 0x40, 0x00, 0x02, 0x1B, 0x35, 0x00, 0x01, 0x00, 0x04, 0x1B, 0x41, 0x00, 0x02, 
+    0x1B, 0x35, 0x00, 0x01, 0x00, 0x04, 0x1B, 0x43, 0x00, 0x02, 0x1B, 0x35, 0x00, 0x01, 0x00, 0x0B, 
+    0x1B, 0x05, 0x1B, 0x07, 0x1B, 0x09, 0x1B, 0x0B, 0x1B, 0x0D, 0x1B, 0x11, 0x1B, 0x3A, 0x1B, 0x3C, 
+    0x1B, 0x3E, 0x1B, 0x3F, 0x1B, 0x42, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 
+    0x00, 0x5E, 0x00, 0x0B, 0x00, 0x1C, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2E, 0x00, 0x34, 0x00, 0x3A, 
+    0x00, 0x40, 0x00, 0x46, 0x00, 0x4C, 0x00, 0x52, 0x00, 0x58, 0x00, 0x02, 0x1B, 0x05, 0x1B, 0x35, 
+    0x00, 0x02, 0x1B, 0x07, 0x1B, 0x35, 0x00, 0x02, 0x1B, 0x09, 0x1B, 0x35, 0x00, 0x02, 0x1B, 0x0B, 
+    0x1B, 0x35, 0x00, 0x02, 0x1B, 0x0D, 0x1B, 0x35, 0x00, 0x02, 0x1B, 0x11, 0x1B, 0x35, 0x00, 0x02, 
+    0x1B, 0x3A, 0x1B, 0x35, 0x00, 0x02, 0x1B, 0x3C, 0x1B, 0x35, 0x00, 0x02, 0x1B, 0x3E, 0x1B, 0x35, 
+    0x00, 0x02, 0x1B, 0x3F, 0x1B, 0x35, 0x00, 0x02, 0x1B, 0x42, 0x1B, 0x35, 0x00, 0x01, 0x00, 0x0B, 
+    0x1B, 0x06, 0x1B, 0x08, 0x1B, 0x0A, 0x1B, 0x0C, 0x1B, 0x0E, 0x1B, 0x12, 0x1B, 0x3B, 0x1B, 0x3D, 
+    0x1B, 0x40, 0x1B, 0x41, 0x1B, 0x43
+};
+
+const le_uint8 CanonShaping::glyphDefinitionTable[] = {
+    0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x28, 
+    0x06, 0x0B, 0x06, 0x0F, 0x00, 0x01, 0x06, 0x10, 0x06, 0x15, 0x00, 0x03, 0x06, 0x1B, 0x06, 0x1B, 
+    0x00, 0x01, 0x06, 0x1E, 0x06, 0x1F, 0x00, 0x01, 0x06, 0x21, 0x06, 0x21, 0x00, 0x01, 0x06, 0x22, 
+    0x06, 0x26, 0x00, 0x02, 0x06, 0x27, 0x06, 0x3A, 0x00, 0x01, 0x06, 0x40, 0x06, 0x4A, 0x00, 0x01, 
+    0x06, 0x4B, 0x06, 0x5E, 0x00, 0x03, 0x06, 0x60, 0x06, 0x6F, 0x00, 0x01, 0x06, 0x70, 0x06, 0x70, 
+    0x00, 0x03, 0x06, 0x71, 0x06, 0xBF, 0x00, 0x01, 0x06, 0xC0, 0x06, 0xC0, 0x00, 0x02, 0x06, 0xC1, 
+    0x06, 0xC1, 0x00, 0x01, 0x06, 0xC2, 0x06, 0xC2, 0x00, 0x02, 0x06, 0xC3, 0x06, 0xD2, 0x00, 0x01, 
+    0x06, 0xD3, 0x06, 0xD3, 0x00, 0x02, 0x06, 0xD4, 0x06, 0xD5, 0x00, 0x01, 0x06, 0xD6, 0x06, 0xDC, 
+    0x00, 0x03, 0x06, 0xDE, 0x06, 0xE4, 0x00, 0x03, 0x06, 0xE5, 0x06, 0xE6, 0x00, 0x01, 0x06, 0xE7, 
+    0x06, 0xE8, 0x00, 0x03, 0x06, 0xE9, 0x06, 0xE9, 0x00, 0x01, 0x06, 0xEA, 0x06, 0xED, 0x00, 0x03, 
+    0x06, 0xEE, 0x06, 0xFF, 0x00, 0x01, 0x07, 0x50, 0x07, 0x6D, 0x00, 0x01, 0xFB, 0x50, 0xFB, 0xB1, 
+    0x00, 0x01, 0xFB, 0xD3, 0xFB, 0xDC, 0x00, 0x01, 0xFB, 0xDD, 0xFB, 0xDD, 0x00, 0x02, 0xFB, 0xDE, 
+    0xFB, 0xE9, 0x00, 0x01, 0xFB, 0xEA, 0xFB, 0xFB, 0x00, 0x02, 0xFB, 0xFC, 0xFB, 0xFF, 0x00, 0x01, 
+    0xFC, 0x00, 0xFC, 0x5D, 0x00, 0x02, 0xFC, 0x64, 0xFC, 0xF1, 0x00, 0x02, 0xFC, 0xF5, 0xFD, 0x3D, 
+    0x00, 0x02, 0xFD, 0x50, 0xFD, 0x8F, 0x00, 0x02, 0xFD, 0x92, 0xFD, 0xC7, 0x00, 0x02, 0xFD, 0xF0, 
+    0xFD, 0xFC, 0x00, 0x02, 0xFE, 0x80, 0xFE, 0xF4, 0x00, 0x01, 0xFE, 0xF5, 0xFE, 0xFC, 0x00, 0x02, 
+    0x00, 0x02, 0x00, 0xCE, 0x03, 0x00, 0x03, 0x14, 0x00, 0xE6, 0x03, 0x15, 0x03, 0x15, 0x00, 0xE8, 
+    0x03, 0x16, 0x03, 0x19, 0x00, 0xDC, 0x03, 0x1A, 0x03, 0x1A, 0x00, 0xE8, 0x03, 0x1B, 0x03, 0x1B, 
+    0x00, 0xD8, 0x03, 0x1C, 0x03, 0x20, 0x00, 0xDC, 0x03, 0x21, 0x03, 0x22, 0x00, 0xCA, 0x03, 0x23, 
+    0x03, 0x26, 0x00, 0xDC, 0x03, 0x27, 0x03, 0x28, 0x00, 0xCA, 0x03, 0x29, 0x03, 0x33, 0x00, 0xDC, 
+    0x03, 0x34, 0x03, 0x38, 0x00, 0x01, 0x03, 0x39, 0x03, 0x3C, 0x00, 0xDC, 0x03, 0x3D, 0x03, 0x44, 
+    0x00, 0xE6, 0x03, 0x45, 0x03, 0x45, 0x00, 0xF0, 0x03, 0x46, 0x03, 0x46, 0x00, 0xE6, 0x03, 0x47, 
+    0x03, 0x49, 0x00, 0xDC, 0x03, 0x4A, 0x03, 0x4C, 0x00, 0xE6, 0x03, 0x4D, 0x03, 0x4E, 0x00, 0xDC, 
+    0x03, 0x50, 0x03, 0x52, 0x00, 0xE6, 0x03, 0x53, 0x03, 0x56, 0x00, 0xDC, 0x03, 0x57, 0x03, 0x57, 
+    0x00, 0xE6, 0x03, 0x58, 0x03, 0x58, 0x00, 0xE8, 0x03, 0x59, 0x03, 0x5A, 0x00, 0xDC, 0x03, 0x5B, 
+    0x03, 0x5B, 0x00, 0xE6, 0x03, 0x5C, 0x03, 0x5C, 0x00, 0xE9, 0x03, 0x5D, 0x03, 0x5E, 0x00, 0xEA, 
+    0x03, 0x5F, 0x03, 0x5F, 0x00, 0xE9, 0x03, 0x60, 0x03, 0x61, 0x00, 0xEA, 0x03, 0x62, 0x03, 0x62, 
+    0x00, 0xE9, 0x03, 0x63, 0x03, 0x6F, 0x00, 0xE6, 0x04, 0x83, 0x04, 0x86, 0x00, 0xE6, 0x05, 0x91, 
+    0x05, 0x91, 0x00, 0xDC, 0x05, 0x92, 0x05, 0x95, 0x00, 0xE6, 0x05, 0x96, 0x05, 0x96, 0x00, 0xDC, 
+    0x05, 0x97, 0x05, 0x98, 0x00, 0xE6, 0x05, 0x99, 0x05, 0x99, 0x00, 0xE8, 0x05, 0x9A, 0x05, 0x9A, 
+    0x00, 0xDE, 0x05, 0x9B, 0x05, 0x9B, 0x00, 0xDC, 0x05, 0x9C, 0x05, 0xA1, 0x00, 0xE6, 0x05, 0xA2, 
+    0x05, 0xA7, 0x00, 0xDC, 0x05, 0xA8, 0x05, 0xA8, 0x00, 0xE6, 0x05, 0xA9, 0x05, 0xA9, 0x00, 0xE8, 
+    0x05, 0xAA, 0x05, 0xAA, 0x00, 0xDC, 0x05, 0xAB, 0x05, 0xAC, 0x00, 0xE6, 0x05, 0xAD, 0x05, 0xAD, 
+    0x00, 0xDE, 0x05, 0xAE, 0x05, 0xAE, 0x00, 0xE8, 0x05, 0xAF, 0x05, 0xAF, 0x00, 0xE6, 0x05, 0xB0, 
+    0x05, 0xB8, 0x00, 0xDC, 0x05, 0xB9, 0x05, 0xB9, 0x00, 0x1B, 0x05, 0xBA, 0x05, 0xBA, 0x00, 0x13, 
+    0x05, 0xBB, 0x05, 0xBB, 0x00, 0xDC, 0x05, 0xBC, 0x05, 0xBC, 0x00, 0x15, 0x05, 0xBD, 0x05, 0xBD, 
+    0x00, 0xDC, 0x05, 0xBF, 0x05, 0xBF, 0x00, 0x17, 0x05, 0xC1, 0x05, 0xC1, 0x00, 0x0A, 0x05, 0xC2, 
+    0x05, 0xC2, 0x00, 0x0B, 0x05, 0xC4, 0x05, 0xC4, 0x00, 0xE6, 0x05, 0xC5, 0x05, 0xC5, 0x00, 0xDC, 
+    0x05, 0xC7, 0x05, 0xC7, 0x00, 0x12, 0x06, 0x10, 0x06, 0x15, 0x00, 0xE6, 0x06, 0x4B, 0x06, 0x4C, 
+    0x00, 0x1F, 0x06, 0x4D, 0x06, 0x4D, 0x00, 0x1E, 0x06, 0x4E, 0x06, 0x4F, 0x00, 0x1F, 0x06, 0x50, 
+    0x06, 0x50, 0x00, 0x1E, 0x06, 0x51, 0x06, 0x51, 0x00, 0x1C, 0x06, 0x52, 0x06, 0x52, 0x00, 0x1F, 
+    0x06, 0x53, 0x06, 0x53, 0x00, 0x20, 0x06, 0x54, 0x06, 0x55, 0x00, 0x1B, 0x06, 0x56, 0x06, 0x56, 
+    0x00, 0x1D, 0x06, 0x57, 0x06, 0x58, 0x00, 0x1F, 0x06, 0x59, 0x06, 0x5B, 0x00, 0xE6, 0x06, 0x5C, 
+    0x06, 0x5C, 0x00, 0xDC, 0x06, 0x5D, 0x06, 0x5E, 0x00, 0xE6, 0x06, 0x70, 0x06, 0x70, 0x00, 0x1D, 
+    0x06, 0xD6, 0x06, 0xDC, 0x00, 0xE6, 0x06, 0xDF, 0x06, 0xE0, 0x00, 0xE6, 0x06, 0xE1, 0x06, 0xE1, 
+    0x00, 0x1F, 0x06, 0xE2, 0x06, 0xE2, 0x00, 0xE6, 0x06, 0xE3, 0x06, 0xE3, 0x00, 0xDC, 0x06, 0xE4, 
+    0x06, 0xE4, 0x00, 0xE6, 0x06, 0xE7, 0x06, 0xE8, 0x00, 0xE6, 0x06, 0xEA, 0x06, 0xEA, 0x00, 0xDC, 
+    0x06, 0xEB, 0x06, 0xEC, 0x00, 0xE6, 0x06, 0xED, 0x06, 0xED, 0x00, 0xDC, 0x07, 0x11, 0x07, 0x11, 
+    0x00, 0x24, 0x07, 0x30, 0x07, 0x30, 0x00, 0xE6, 0x07, 0x31, 0x07, 0x31, 0x00, 0xDC, 0x07, 0x32, 
+    0x07, 0x33, 0x00, 0xE6, 0x07, 0x34, 0x07, 0x34, 0x00, 0xDC, 0x07, 0x35, 0x07, 0x36, 0x00, 0xE6, 
+    0x07, 0x37, 0x07, 0x39, 0x00, 0xDC, 0x07, 0x3A, 0x07, 0x3A, 0x00, 0xE6, 0x07, 0x3B, 0x07, 0x3C, 
+    0x00, 0xDC, 0x07, 0x3D, 0x07, 0x3D, 0x00, 0xE6, 0x07, 0x3E, 0x07, 0x3E, 0x00, 0xDC, 0x07, 0x3F, 
+    0x07, 0x41, 0x00, 0xE6, 0x07, 0x42, 0x07, 0x42, 0x00, 0xDC, 0x07, 0x43, 0x07, 0x43, 0x00, 0xE6, 
+    0x07, 0x44, 0x07, 0x44, 0x00, 0xDC, 0x07, 0x45, 0x07, 0x45, 0x00, 0xE6, 0x07, 0x46, 0x07, 0x46, 
+    0x00, 0xDC, 0x07, 0x47, 0x07, 0x47, 0x00, 0xE6, 0x07, 0x48, 0x07, 0x48, 0x00, 0xDC, 0x07, 0x49, 
+    0x07, 0x4A, 0x00, 0xE6, 0x07, 0xEB, 0x07, 0xF1, 0x00, 0xE6, 0x07, 0xF2, 0x07, 0xF2, 0x00, 0xDC, 
+    0x07, 0xF3, 0x07, 0xF3, 0x00, 0xE6, 0x09, 0x3C, 0x09, 0x3C, 0x00, 0x07, 0x09, 0x4D, 0x09, 0x4D, 
+    0x00, 0x09, 0x09, 0x51, 0x09, 0x51, 0x00, 0xE6, 0x09, 0x52, 0x09, 0x52, 0x00, 0xDC, 0x09, 0x53, 
+    0x09, 0x54, 0x00, 0xE6, 0x09, 0xBC, 0x09, 0xBC, 0x00, 0x07, 0x09, 0xCD, 0x09, 0xCD, 0x00, 0x09, 
+    0x0A, 0x3C, 0x0A, 0x3C, 0x00, 0x07, 0x0A, 0x4D, 0x0A, 0x4D, 0x00, 0x09, 0x0A, 0xBC, 0x0A, 0xBC, 
+    0x00, 0x07, 0x0A, 0xCD, 0x0A, 0xCD, 0x00, 0x09, 0x0B, 0x3C, 0x0B, 0x3C, 0x00, 0x07, 0x0B, 0x4D, 
+    0x0B, 0x4D, 0x00, 0x09, 0x0B, 0xCD, 0x0B, 0xCD, 0x00, 0x09, 0x0C, 0x4D, 0x0C, 0x4D, 0x00, 0x09, 
+    0x0C, 0x55, 0x0C, 0x55, 0x00, 0x54, 0x0C, 0x56, 0x0C, 0x56, 0x00, 0x5B, 0x0C, 0xBC, 0x0C, 0xBC, 
+    0x00, 0x07, 0x0C, 0xCD, 0x0C, 0xCD, 0x00, 0x09, 0x0D, 0x4D, 0x0D, 0x4D, 0x00, 0x09, 0x0D, 0xCA, 
+    0x0D, 0xCA, 0x00, 0x09, 0x0E, 0x38, 0x0E, 0x39, 0x00, 0x67, 0x0E, 0x3A, 0x0E, 0x3A, 0x00, 0x09, 
+    0x0E, 0x48, 0x0E, 0x4B, 0x00, 0x6B, 0x0E, 0xB8, 0x0E, 0xB9, 0x00, 0x76, 0x0E, 0xC8, 0x0E, 0xCB, 
+    0x00, 0x7A, 0x0F, 0x18, 0x0F, 0x19, 0x00, 0xDC, 0x0F, 0x35, 0x0F, 0x35, 0x00, 0xDC, 0x0F, 0x37, 
+    0x0F, 0x37, 0x00, 0xDC, 0x0F, 0x39, 0x0F, 0x39, 0x00, 0xD8, 0x0F, 0x71, 0x0F, 0x71, 0x00, 0x81, 
+    0x0F, 0x72, 0x0F, 0x72, 0x00, 0x82, 0x0F, 0x74, 0x0F, 0x74, 0x00, 0x84, 0x0F, 0x7A, 0x0F, 0x7D, 
+    0x00, 0x82, 0x0F, 0x80, 0x0F, 0x80, 0x00, 0x82, 0x0F, 0x82, 0x0F, 0x83, 0x00, 0xE6, 0x0F, 0x84, 
+    0x0F, 0x84, 0x00, 0x09, 0x0F, 0x86, 0x0F, 0x87, 0x00, 0xE6, 0x0F, 0xC6, 0x0F, 0xC6, 0x00, 0xDC, 
+    0x10, 0x37, 0x10, 0x37, 0x00, 0x07, 0x10, 0x39, 0x10, 0x39, 0x00, 0x09, 0x13, 0x5F, 0x13, 0x5F, 
+    0x00, 0xE6, 0x17, 0x14, 0x17, 0x14, 0x00, 0x09, 0x17, 0x34, 0x17, 0x34, 0x00, 0x09, 0x17, 0xD2, 
+    0x17, 0xD2, 0x00, 0x09, 0x17, 0xDD, 0x17, 0xDD, 0x00, 0xE6, 0x18, 0xA9, 0x18, 0xA9, 0x00, 0xE4, 
+    0x19, 0x39, 0x19, 0x39, 0x00, 0xDE, 0x19, 0x3A, 0x19, 0x3A, 0x00, 0xE6, 0x19, 0x3B, 0x19, 0x3B, 
+    0x00, 0xDC, 0x1A, 0x17, 0x1A, 0x17, 0x00, 0xE6, 0x1A, 0x18, 0x1A, 0x18, 0x00, 0xDC, 0x1B, 0x34, 
+    0x1B, 0x34, 0x00, 0x07, 0x1B, 0x44, 0x1B, 0x44, 0x00, 0x09, 0x1B, 0x6B, 0x1B, 0x6B, 0x00, 0xE6, 
+    0x1B, 0x6C, 0x1B, 0x6C, 0x00, 0xDC, 0x1B, 0x6D, 0x1B, 0x73, 0x00, 0xE6, 0x1D, 0xC0, 0x1D, 0xC1, 
+    0x00, 0xE6, 0x1D, 0xC2, 0x1D, 0xC2, 0x00, 0xDC, 0x1D, 0xC3, 0x1D, 0xC9, 0x00, 0xE6, 0x1D, 0xCA, 
+    0x1D, 0xCA, 0x00, 0xDC, 0x1D, 0xFE, 0x1D, 0xFE, 0x00, 0xE6, 0x1D, 0xFF, 0x1D, 0xFF, 0x00, 0xDC, 
+    0x20, 0xD0, 0x20, 0xD1, 0x00, 0xE6, 0x20, 0xD2, 0x20, 0xD3, 0x00, 0x01, 0x20, 0xD4, 0x20, 0xD7, 
+    0x00, 0xE6, 0x20, 0xD8, 0x20, 0xDA, 0x00, 0x01, 0x20, 0xDB, 0x20, 0xDC, 0x00, 0xE6, 0x20, 0xE1, 
+    0x20, 0xE1, 0x00, 0xE6, 0x20, 0xE5, 0x20, 0xE6, 0x00, 0x01, 0x20, 0xE7, 0x20, 0xE7, 0x00, 0xE6, 
+    0x20, 0xE8, 0x20, 0xE8, 0x00, 0xDC, 0x20, 0xE9, 0x20, 0xE9, 0x00, 0xE6, 0x20, 0xEA, 0x20, 0xEB, 
+    0x00, 0x01, 0x20, 0xEC, 0x20, 0xEF, 0x00, 0xDC, 0x30, 0x2A, 0x30, 0x2A, 0x00, 0xDA, 0x30, 0x2B, 
+    0x30, 0x2B, 0x00, 0xE4, 0x30, 0x2C, 0x30, 0x2C, 0x00, 0xE8, 0x30, 0x2D, 0x30, 0x2D, 0x00, 0xDE, 
+    0x30, 0x2E, 0x30, 0x2F, 0x00, 0xE0, 0x30, 0x99, 0x30, 0x9A, 0x00, 0x08, 0xA8, 0x06, 0xA8, 0x06, 
+    0x00, 0x09, 0xFB, 0x1E, 0xFB, 0x1E, 0x00, 0x1A, 0xFE, 0x20, 0xFE, 0x23, 0x00, 0xE6, 0x0A, 0x0D, 
+    0x0A, 0x0D, 0x00, 0xDC, 0x0A, 0x0F, 0x0A, 0x0F, 0x00, 0xE6, 0x0A, 0x38, 0x0A, 0x38, 0x00, 0xE6, 
+    0x0A, 0x39, 0x0A, 0x39, 0x00, 0x01, 0x0A, 0x3A, 0x0A, 0x3A, 0x00, 0xDC, 0x0A, 0x3F, 0x0A, 0x3F, 
+    0x00, 0x09, 0xD1, 0x65, 0xD1, 0x66, 0x00, 0xD8, 0xD1, 0x67, 0xD1, 0x69, 0x00, 0x01, 0xD1, 0x6D, 
+    0xD1, 0x6D, 0x00, 0xE2, 0xD1, 0x6E, 0xD1, 0x72, 0x00, 0xD8, 0xD1, 0x7B, 0xD1, 0x82, 0x00, 0xDC, 
+    0xD1, 0x85, 0xD1, 0x89, 0x00, 0xE6, 0xD1, 0x8A, 0xD1, 0x8B, 0x00, 0xDC, 0xD1, 0xAA, 0xD1, 0xAD, 
+    0x00, 0xE6, 0xD2, 0x42, 0xD2, 0x44, 0x00, 0xE6
+};
+
+U_NAMESPACE_END
diff --git a/source/layout/CanonShaping.cpp b/source/layout/CanonShaping.cpp
new file mode 100644
index 0000000..ea109a7
--- /dev/null
+++ b/source/layout/CanonShaping.cpp
@@ -0,0 +1,81 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEGlyphStorage.h"
+#include "CanonShaping.h"
+#include "GlyphDefinitionTables.h"
+#include "ClassDefinitionTables.h"
+
+U_NAMESPACE_BEGIN
+
+void CanonShaping::sortMarks(le_int32 *indices, const le_int32 *combiningClasses, le_int32 index, le_int32 limit)
+{
+    for (le_int32 j = index + 1; j < limit; j += 1) {
+        le_int32 i;
+        le_int32 v = indices[j];
+        le_int32 c = combiningClasses[v];
+
+        for (i = j - 1; i >= index; i -= 1) {
+            if (c >= combiningClasses[indices[i]]) {
+                break;
+            }
+
+            indices[i + 1] = indices[i];
+        }
+
+        indices[i + 1] = v;
+    }
+}
+
+void CanonShaping::reorderMarks(const LEUnicode *inChars, le_int32 charCount, le_bool rightToLeft,
+                                LEUnicode *outChars, LEGlyphStorage &glyphStorage)
+{
+    const GlyphDefinitionTableHeader *gdefTable = (const GlyphDefinitionTableHeader *) glyphDefinitionTable;
+    const ClassDefinitionTable *classTable = gdefTable->getMarkAttachClassDefinitionTable();
+    le_int32 *combiningClasses = LE_NEW_ARRAY(le_int32, charCount);
+    le_int32 *indices = LE_NEW_ARRAY(le_int32, charCount);
+    LEErrorCode status = LE_NO_ERROR;
+    le_int32 i;
+
+    for (i = 0; i < charCount; i += 1) {
+        combiningClasses[i] = classTable->getGlyphClass((LEGlyphID) inChars[i]);
+        indices[i] = i;
+    }
+
+    for (i = 0; i < charCount; i += 1) {
+        if (combiningClasses[i] != 0) {
+            le_int32 mark;
+
+            for (mark = i; mark < charCount; mark += 1) {
+                if (combiningClasses[mark] == 0) {
+                    break;
+                }
+            }
+
+            sortMarks(indices, combiningClasses, i, mark);
+        }
+    }
+
+    le_int32 out = 0, dir = 1;
+
+    if (rightToLeft) {
+        out = charCount - 1;
+        dir = -1;
+    }
+
+    for (i = 0; i < charCount; i += 1, out += dir) {
+        le_int32 index = indices[i];
+
+        outChars[i] = inChars[index];
+        glyphStorage.setCharIndex(out, index, status);
+    }
+
+    LE_DELETE_ARRAY(indices);
+    LE_DELETE_ARRAY(combiningClasses);
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/CanonShaping.h b/source/layout/CanonShaping.h
new file mode 100644
index 0000000..cdf1959
--- /dev/null
+++ b/source/layout/CanonShaping.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2006 - All Rights Reserved
+ *
+ */
+
+#ifndef __CANONSHAPING_H
+#define __CANONSHAPING_H
+
+#include "LETypes.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+class U_LAYOUT_API CanonShaping /* not : public UObject because all members are static */
+{
+public:
+    static const le_uint8 glyphSubstitutionTable[];
+    static const le_uint8 glyphDefinitionTable[];
+
+    static void reorderMarks(const LEUnicode *inChars, le_int32 charCount, le_bool rightToLeft,
+                                   LEUnicode *outChars, LEGlyphStorage &glyphStorage);
+
+private:
+    static void sortMarks(le_int32 *indices, const le_int32 *combiningClasses, le_int32 index, le_int32 limit);
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/CharSubstitutionFilter.h b/source/layout/CharSubstitutionFilter.h
new file mode 100644
index 0000000..780e8ad
--- /dev/null
+++ b/source/layout/CharSubstitutionFilter.h
@@ -0,0 +1,81 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __CHARSUBSTITUTIONFILTER_H
+#define __CHARSUBSTITUTIONFILTER_H
+
+#include "LETypes.h"
+#include "LEGlyphFilter.h"
+
+U_NAMESPACE_BEGIN
+
+class LEFontInstance;
+
+/**
+ * This filter is used by character-based GSUB processors. It
+ * accepts only those characters which the given font can display.
+ *
+ * @internal
+ */
+class CharSubstitutionFilter : public UMemory, public LEGlyphFilter
+{
+private:
+    /**
+     * Holds the font which is used to test the characters.
+     *
+     * @internal
+     */
+    const LEFontInstance *fFontInstance;
+
+    /**
+     * The copy constructor. Not allowed!
+     *
+     * @internal
+     */
+    CharSubstitutionFilter(const CharSubstitutionFilter &other); // forbid copying of this class
+
+    /**
+     * The replacement operator. Not allowed!
+     *
+     * @internal
+     */
+    CharSubstitutionFilter &operator=(const CharSubstitutionFilter &other); // forbid copying of this class
+
+public:
+    /**
+     * The constructor.
+     *
+     * @param fontInstance - the font to use to test the characters.
+     *
+     * @internal
+     */
+    CharSubstitutionFilter(const LEFontInstance *fontInstance);
+
+    /**
+     * The destructor.
+     *
+     * @internal
+     */
+    ~CharSubstitutionFilter();
+
+    /**
+     * This method is used to test if a particular
+     * character can be displayed by the filter's
+     * font.
+     *
+     * @param glyph - the Unicode character code to be tested
+     *
+     * @return TRUE if the filter's font can display this character.
+     *
+     * @internal
+     */
+    le_bool accept(LEGlyphID glyph) const;
+};
+
+U_NAMESPACE_END
+#endif
+
+
diff --git a/source/layout/ClassDefinitionTables.cpp b/source/layout/ClassDefinitionTables.cpp
new file mode 100644
index 0000000..471a2b3
--- /dev/null
+++ b/source/layout/ClassDefinitionTables.cpp
@@ -0,0 +1,120 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "OpenTypeUtilities.h"
+#include "ClassDefinitionTables.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+le_int32 ClassDefinitionTable::getGlyphClass(LEGlyphID glyphID) const
+{
+    switch(SWAPW(classFormat)) {
+    case 0:
+        return 0;
+
+    case 1:
+    {
+        const ClassDefFormat1Table *f1Table = (const ClassDefFormat1Table *) this;
+
+        return f1Table->getGlyphClass(glyphID);
+    }
+
+    case 2:
+    {
+        const ClassDefFormat2Table *f2Table = (const ClassDefFormat2Table *) this;
+
+        return f2Table->getGlyphClass(glyphID);
+    }
+
+    default:
+        return 0;
+    }
+}
+
+le_bool ClassDefinitionTable::hasGlyphClass(le_int32 glyphClass) const
+{
+    switch(SWAPW(classFormat)) {
+    case 0:
+        return 0;
+
+    case 1:
+    {
+        const ClassDefFormat1Table *f1Table = (const ClassDefFormat1Table *) this;
+
+        return f1Table->hasGlyphClass(glyphClass);
+    }
+
+    case 2:
+    {
+        const ClassDefFormat2Table *f2Table = (const ClassDefFormat2Table *) this;
+
+        return f2Table->hasGlyphClass(glyphClass);
+    }
+
+    default:
+        return 0;
+    }
+}
+
+le_int32 ClassDefFormat1Table::getGlyphClass(LEGlyphID glyphID) const
+{
+    TTGlyphID ttGlyphID  = (TTGlyphID) LE_GET_GLYPH(glyphID);
+    TTGlyphID firstGlyph = SWAPW(startGlyph);
+    TTGlyphID lastGlyph  = firstGlyph + SWAPW(glyphCount);
+
+    if (ttGlyphID >= firstGlyph && ttGlyphID < lastGlyph) {
+        return SWAPW(classValueArray[ttGlyphID - firstGlyph]);
+    }
+
+    return 0;
+}
+
+le_bool ClassDefFormat1Table::hasGlyphClass(le_int32 glyphClass) const
+{
+    le_uint16 count  = SWAPW(glyphCount);
+    int i;
+
+    for (i = 0; i < count; i += 1) {
+        if (SWAPW(classValueArray[i]) == glyphClass) {
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+le_int32 ClassDefFormat2Table::getGlyphClass(LEGlyphID glyphID) const
+{
+    TTGlyphID ttGlyph    = (TTGlyphID) LE_GET_GLYPH(glyphID);
+    le_uint16 rangeCount = SWAPW(classRangeCount);
+    le_int32  rangeIndex =
+        OpenTypeUtilities::getGlyphRangeIndex(ttGlyph, classRangeRecordArray, rangeCount);
+
+    if (rangeIndex < 0) {
+        return 0;
+    }
+
+    return SWAPW(classRangeRecordArray[rangeIndex].rangeValue);
+}
+
+le_bool ClassDefFormat2Table::hasGlyphClass(le_int32 glyphClass) const
+{
+    le_uint16 rangeCount = SWAPW(classRangeCount);
+    int i;
+
+    for (i = 0; i < rangeCount; i += 1) {
+        if (SWAPW(classRangeRecordArray[i].rangeValue) == glyphClass) {
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/ClassDefinitionTables.h b/source/layout/ClassDefinitionTables.h
new file mode 100644
index 0000000..3dfe86e
--- /dev/null
+++ b/source/layout/ClassDefinitionTables.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __CLASSDEFINITIONTABLES_H
+#define __CLASSDEFINITIONTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+
+U_NAMESPACE_BEGIN
+
+struct ClassDefinitionTable
+{
+    le_uint16 classFormat;
+
+    le_int32  getGlyphClass(LEGlyphID glyphID) const;
+    le_bool   hasGlyphClass(le_int32 glyphClass) const;
+};
+
+struct ClassDefFormat1Table : ClassDefinitionTable
+{
+    TTGlyphID  startGlyph;
+    le_uint16  glyphCount;
+    le_uint16  classValueArray[ANY_NUMBER];
+
+    le_int32 getGlyphClass(LEGlyphID glyphID) const;
+    le_bool  hasGlyphClass(le_int32 glyphClass) const;
+};
+
+struct ClassRangeRecord
+{
+    TTGlyphID start;
+    TTGlyphID end;
+    le_uint16 classValue;
+};
+
+struct ClassDefFormat2Table : ClassDefinitionTable
+{
+    le_uint16        classRangeCount;
+    GlyphRangeRecord classRangeRecordArray[ANY_NUMBER];
+
+    le_int32 getGlyphClass(LEGlyphID glyphID) const;
+    le_bool hasGlyphClass(le_int32 glyphClass) const;
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/ContextualGlyphInsertion.h b/source/layout/ContextualGlyphInsertion.h
new file mode 100644
index 0000000..ead8842
--- /dev/null
+++ b/source/layout/ContextualGlyphInsertion.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __CONTEXTUALGLYPHINSERTION_H
+#define __CONTEXTUALGLYPHINSERTION_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LayoutTables.h"
+#include "StateTables.h"
+#include "MorphTables.h"
+#include "MorphStateTables.h"
+
+U_NAMESPACE_BEGIN
+
+struct ContextualGlyphInsertionHeader : MorphStateTableHeader
+{
+};
+
+enum ContextualGlyphInsertionFlags
+{
+    cgiSetMark                  = 0x8000,
+    cgiDontAdvance              = 0x4000,
+    cgiCurrentIsKashidaLike     = 0x2000,
+    cgiMarkedIsKashidaLike      = 0x1000,
+    cgiCurrentInsertBefore      = 0x0800,
+    cgiMarkInsertBefore         = 0x0400,
+    cgiCurrentInsertCountMask   = 0x03E0,
+    cgiMarkedInsertCountMask    = 0x001F
+};
+
+struct LigatureSubstitutionStateEntry : StateEntry
+{
+    ByteOffset currentInsertionListOffset;
+    ByteOffset markedInsertionListOffset;
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/ContextualGlyphSubstProc.cpp b/source/layout/ContextualGlyphSubstProc.cpp
new file mode 100644
index 0000000..94c4a60
--- /dev/null
+++ b/source/layout/ContextualGlyphSubstProc.cpp
@@ -0,0 +1,79 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "StateTables.h"
+#include "MorphStateTables.h"
+#include "SubtableProcessor.h"
+#include "StateTableProcessor.h"
+#include "ContextualGlyphSubstProc.h"
+#include "LEGlyphStorage.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ContextualGlyphSubstitutionProcessor)
+
+ContextualGlyphSubstitutionProcessor::ContextualGlyphSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader)
+  : StateTableProcessor(morphSubtableHeader)
+{
+    contextualGlyphSubstitutionHeader = (const ContextualGlyphSubstitutionHeader *) morphSubtableHeader;
+    substitutionTableOffset = SWAPW(contextualGlyphSubstitutionHeader->substitutionTableOffset);
+
+    entryTable = (const ContextualGlyphSubstitutionStateEntry *) ((char *) &stateTableHeader->stHeader + entryTableOffset);
+}
+
+ContextualGlyphSubstitutionProcessor::~ContextualGlyphSubstitutionProcessor()
+{
+}
+
+void ContextualGlyphSubstitutionProcessor::beginStateTable()
+{
+    markGlyph = 0;
+}
+
+ByteOffset ContextualGlyphSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex index)
+{
+    const ContextualGlyphSubstitutionStateEntry *entry = &entryTable[index];
+    ByteOffset newState = SWAPW(entry->newStateOffset);
+    le_int16 flags = SWAPW(entry->flags);
+    WordOffset markOffset = SWAPW(entry->markOffset);
+    WordOffset currOffset = SWAPW(entry->currOffset);
+
+    if (markOffset != 0) {
+        const le_int16 *table = (const le_int16 *) ((char *) &stateTableHeader->stHeader + markOffset * 2);
+        LEGlyphID mGlyph = glyphStorage[markGlyph];
+        TTGlyphID newGlyph = SWAPW(table[LE_GET_GLYPH(mGlyph)]);
+
+         glyphStorage[markGlyph] = LE_SET_GLYPH(mGlyph, newGlyph);
+    }
+
+    if (currOffset != 0) {
+        const le_int16 *table = (const le_int16 *) ((char *) &stateTableHeader->stHeader + currOffset * 2);
+        LEGlyphID thisGlyph = glyphStorage[currGlyph];
+        TTGlyphID newGlyph = SWAPW(table[LE_GET_GLYPH(thisGlyph)]);
+
+        glyphStorage[currGlyph] = LE_SET_GLYPH(thisGlyph, newGlyph);
+    }
+
+    if (flags & cgsSetMark) {
+        markGlyph = currGlyph;
+    }
+
+    if (!(flags & cgsDontAdvance)) {
+        // should handle reverse too!
+        currGlyph += 1;
+    }
+
+    return newState;
+}
+
+void ContextualGlyphSubstitutionProcessor::endStateTable()
+{
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/ContextualGlyphSubstProc.h b/source/layout/ContextualGlyphSubstProc.h
new file mode 100644
index 0000000..b0c5a6b
--- /dev/null
+++ b/source/layout/ContextualGlyphSubstProc.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __CONTEXTUALGLYPHSUBSTITUTIONPROCESSOR_H
+#define __CONTEXTUALGLYPHSUBSTITUTIONPROCESSOR_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "SubtableProcessor.h"
+#include "StateTableProcessor.h"
+#include "ContextualGlyphSubstitution.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+class ContextualGlyphSubstitutionProcessor : public StateTableProcessor
+{
+public:
+    virtual void beginStateTable();
+
+    virtual ByteOffset processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex index);
+
+    virtual void endStateTable();
+
+    ContextualGlyphSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader);
+    virtual ~ContextualGlyphSubstitutionProcessor();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.8
+     */
+    static UClassID getStaticClassID();
+
+private:
+    ContextualGlyphSubstitutionProcessor();
+
+protected:
+    ByteOffset substitutionTableOffset;
+    const ContextualGlyphSubstitutionStateEntry *entryTable;
+
+    le_int32 markGlyph;
+
+    const ContextualGlyphSubstitutionHeader *contextualGlyphSubstitutionHeader;
+
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/ContextualGlyphSubstitution.h b/source/layout/ContextualGlyphSubstitution.h
new file mode 100644
index 0000000..72c2355
--- /dev/null
+++ b/source/layout/ContextualGlyphSubstitution.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __CONTEXTUALGLYPHSUBSTITUTION_H
+#define __CONTEXTUALGLYPHSUBSTITUTION_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LayoutTables.h"
+#include "StateTables.h"
+#include "MorphTables.h"
+
+U_NAMESPACE_BEGIN
+
+struct ContextualGlyphSubstitutionHeader : MorphStateTableHeader
+{
+    ByteOffset  substitutionTableOffset;
+};
+
+enum ContextualGlyphSubstitutionFlags
+{
+    cgsSetMark      = 0x8000,
+    cgsDontAdvance  = 0x4000,
+    cgsReserved     = 0x3FFF
+};
+
+struct ContextualGlyphSubstitutionStateEntry : StateEntry
+{
+    WordOffset markOffset;
+    WordOffset currOffset;
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/ContextualSubstSubtables.cpp b/source/layout/ContextualSubstSubtables.cpp
new file mode 100644
index 0000000..b75e388
--- /dev/null
+++ b/source/layout/ContextualSubstSubtables.cpp
@@ -0,0 +1,569 @@
+/*
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "GlyphSubstitutionTables.h"
+#include "ContextualSubstSubtables.h"
+#include "GlyphIterator.h"
+#include "LookupProcessor.h"
+#include "CoverageTables.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+/*
+    NOTE: This could be optimized somewhat by keeping track
+    of the previous sequenceIndex in the loop and doing next()
+    or prev() of the delta between that and the current
+    sequenceIndex instead of always resetting to the front.
+*/
+void ContextualSubstitutionBase::applySubstitutionLookups(
+        const LookupProcessor *lookupProcessor,
+        const SubstitutionLookupRecord *substLookupRecordArray,
+        le_uint16 substCount,
+        GlyphIterator *glyphIterator,
+        const LEFontInstance *fontInstance,
+        le_int32 position,
+        LEErrorCode& success)
+{
+    if (LE_FAILURE(success)) { 
+        return;
+    }
+
+    GlyphIterator tempIterator(*glyphIterator);
+
+    for (le_int16 subst = 0; subst < substCount && LE_SUCCESS(success); subst += 1) {
+        le_uint16 sequenceIndex = SWAPW(substLookupRecordArray[subst].sequenceIndex);
+        le_uint16 lookupListIndex = SWAPW(substLookupRecordArray[subst].lookupListIndex);
+
+        tempIterator.setCurrStreamPosition(position);
+        tempIterator.next(sequenceIndex);
+
+        lookupProcessor->applySingleLookup(lookupListIndex, &tempIterator, fontInstance, success);
+    }
+}
+
+le_bool ContextualSubstitutionBase::matchGlyphIDs(const TTGlyphID *glyphArray, le_uint16 glyphCount,
+                                               GlyphIterator *glyphIterator, le_bool backtrack)
+{
+    le_int32 direction = 1;
+    le_int32 match = 0;
+
+    if (backtrack) {
+        match = glyphCount -1;
+        direction = -1;
+    }
+
+    while (glyphCount > 0) {
+        if (! glyphIterator->next()) {
+            return FALSE;
+        }
+
+        TTGlyphID glyph = (TTGlyphID) glyphIterator->getCurrGlyphID();
+
+        if (glyph != SWAPW(glyphArray[match])) {
+            return FALSE;
+        }
+
+        glyphCount -= 1;
+        match += direction;
+    }
+
+    return TRUE;
+}
+
+le_bool ContextualSubstitutionBase::matchGlyphClasses(const le_uint16 *classArray, le_uint16 glyphCount,
+                                               GlyphIterator *glyphIterator,
+                                               const ClassDefinitionTable *classDefinitionTable,
+                                               le_bool backtrack)
+{
+    le_int32 direction = 1;
+    le_int32 match = 0;
+
+    if (backtrack) {
+        match = glyphCount - 1;
+        direction = -1;
+    }
+
+    while (glyphCount > 0) {
+        if (! glyphIterator->next()) {
+            return FALSE;
+        }
+
+        LEGlyphID glyph = glyphIterator->getCurrGlyphID();
+        le_int32 glyphClass = classDefinitionTable->getGlyphClass(glyph);
+        le_int32 matchClass = SWAPW(classArray[match]);
+
+        if (glyphClass != matchClass) {
+            // Some fonts, e.g. Traditional Arabic, have classes
+            // in the class array which aren't in the class definition
+            // table. If we're looking for such a class, pretend that
+            // we found it.
+            if (classDefinitionTable->hasGlyphClass(matchClass)) {
+                return FALSE;
+            }
+        }
+
+        glyphCount -= 1;
+        match += direction;
+    }
+
+    return TRUE;
+}
+
+le_bool ContextualSubstitutionBase::matchGlyphCoverages(const Offset *coverageTableOffsetArray, le_uint16 glyphCount,
+                                                     GlyphIterator *glyphIterator, const char *offsetBase, le_bool backtrack)
+{
+    le_int32 direction = 1;
+    le_int32 glyph = 0;
+
+    if (backtrack) {
+        glyph = glyphCount - 1;
+        direction = -1;
+    }
+
+    while (glyphCount > 0) {
+        Offset coverageTableOffset = SWAPW(coverageTableOffsetArray[glyph]);
+        const CoverageTable *coverageTable = (const CoverageTable *) (offsetBase + coverageTableOffset);
+
+        if (! glyphIterator->next()) {
+            return FALSE;
+        }
+
+        if (coverageTable->getGlyphCoverage((LEGlyphID) glyphIterator->getCurrGlyphID()) < 0) {
+            return FALSE;
+        }
+
+        glyphCount -= 1;
+        glyph += direction;
+    }
+
+    return TRUE;
+}
+
+le_uint32 ContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor, 
+                                                  GlyphIterator *glyphIterator,
+                                                  const LEFontInstance *fontInstance,
+                                                  LEErrorCode& success) const
+{
+    if (LE_FAILURE(success)) { 
+        return 0;
+    }
+
+    switch(SWAPW(subtableFormat))
+    {
+    case 0:
+        return 0;
+
+    case 1:
+    {
+        const ContextualSubstitutionFormat1Subtable *subtable = (const ContextualSubstitutionFormat1Subtable *) this;
+        return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
+    }
+
+    case 2:
+    {
+        const ContextualSubstitutionFormat2Subtable *subtable = (const ContextualSubstitutionFormat2Subtable *) this;
+        return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
+    }
+
+    case 3:
+    {
+        const ContextualSubstitutionFormat3Subtable *subtable = (const ContextualSubstitutionFormat3Subtable *) this;
+        return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
+    }
+
+    default:
+        return 0;
+    }
+}
+
+le_uint32 ContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor, 
+                                                         GlyphIterator *glyphIterator,
+                                                         const LEFontInstance *fontInstance,
+                                                         LEErrorCode& success) const
+{
+    if (LE_FAILURE(success)) { 
+        return 0;
+    }
+
+    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
+    le_int32 coverageIndex = getGlyphCoverage(glyph);
+
+    if (coverageIndex >= 0) {
+        le_uint16 srSetCount = SWAPW(subRuleSetCount);
+
+        if (coverageIndex < srSetCount) {
+            Offset subRuleSetTableOffset = SWAPW(subRuleSetTableOffsetArray[coverageIndex]);
+            const SubRuleSetTable *subRuleSetTable =
+                (const SubRuleSetTable *) ((char *) this + subRuleSetTableOffset);
+            le_uint16 subRuleCount = SWAPW(subRuleSetTable->subRuleCount);
+            le_int32 position = glyphIterator->getCurrStreamPosition();
+
+            for (le_uint16 subRule = 0; subRule < subRuleCount; subRule += 1) {
+                Offset subRuleTableOffset =
+                    SWAPW(subRuleSetTable->subRuleTableOffsetArray[subRule]);
+                const SubRuleTable *subRuleTable =
+                    (const SubRuleTable *) ((char *) subRuleSetTable + subRuleTableOffset);
+                le_uint16 matchCount = SWAPW(subRuleTable->glyphCount) - 1;
+                le_uint16 substCount = SWAPW(subRuleTable->substCount);
+
+                if (matchGlyphIDs(subRuleTable->inputGlyphArray, matchCount, glyphIterator)) {
+                    const SubstitutionLookupRecord *substLookupRecordArray = 
+                        (const SubstitutionLookupRecord *) &subRuleTable->inputGlyphArray[matchCount];
+
+                    applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
+
+                    return matchCount + 1;
+                }
+
+                glyphIterator->setCurrStreamPosition(position);
+            }
+        }
+
+        // XXX If we get here, the table is mal-formed...
+    }
+    
+    return 0;
+}
+
+le_uint32 ContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor, 
+                                                         GlyphIterator *glyphIterator,
+                                                         const LEFontInstance *fontInstance,
+                                                         LEErrorCode& success) const
+{
+    if (LE_FAILURE(success)) { 
+        return 0;
+    }
+
+    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
+    le_int32 coverageIndex = getGlyphCoverage(glyph);
+
+    if (coverageIndex >= 0) {
+        const ClassDefinitionTable *classDefinitionTable =
+            (const ClassDefinitionTable *) ((char *) this + SWAPW(classDefTableOffset));
+        le_uint16 scSetCount = SWAPW(subClassSetCount);
+        le_int32 setClass = classDefinitionTable->getGlyphClass(glyphIterator->getCurrGlyphID());
+
+        if (setClass < scSetCount && subClassSetTableOffsetArray[setClass] != 0) {
+            Offset subClassSetTableOffset = SWAPW(subClassSetTableOffsetArray[setClass]);
+            const SubClassSetTable *subClassSetTable =
+                (const SubClassSetTable *) ((char *) this + subClassSetTableOffset);
+            le_uint16 subClassRuleCount = SWAPW(subClassSetTable->subClassRuleCount);
+            le_int32 position = glyphIterator->getCurrStreamPosition();
+
+            for (le_uint16 scRule = 0; scRule < subClassRuleCount; scRule += 1) {
+                Offset subClassRuleTableOffset =
+                    SWAPW(subClassSetTable->subClassRuleTableOffsetArray[scRule]);
+                const SubClassRuleTable *subClassRuleTable =
+                    (const SubClassRuleTable *) ((char *) subClassSetTable + subClassRuleTableOffset);
+                le_uint16 matchCount = SWAPW(subClassRuleTable->glyphCount) - 1;
+                le_uint16 substCount = SWAPW(subClassRuleTable->substCount);
+
+                if (matchGlyphClasses(subClassRuleTable->classArray, matchCount, glyphIterator, classDefinitionTable)) {
+                    const SubstitutionLookupRecord *substLookupRecordArray = 
+                        (const SubstitutionLookupRecord *) &subClassRuleTable->classArray[matchCount];
+
+                    applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
+
+                    return matchCount + 1;
+                }
+
+                glyphIterator->setCurrStreamPosition(position);
+            }
+        }
+
+        // XXX If we get here, the table is mal-formed...
+    }
+    
+    return 0;
+}
+
+le_uint32 ContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor, 
+                                                         GlyphIterator *glyphIterator,
+                                                         const LEFontInstance *fontInstance,
+                                                         LEErrorCode& success)const 
+{
+    if (LE_FAILURE(success)) { 
+        return 0;
+    }
+
+    le_uint16 gCount = SWAPW(glyphCount);
+    le_uint16 subCount = SWAPW(substCount);
+    le_int32 position = glyphIterator->getCurrStreamPosition();
+
+    // Back up the glyph iterator so that we
+    // can call next() before the check, which
+    // will leave it pointing at the last glyph
+    // that matched when we're done.
+    glyphIterator->prev();
+
+    if (ContextualSubstitutionBase::matchGlyphCoverages(coverageTableOffsetArray, gCount, glyphIterator, (const char *) this)) {
+        const SubstitutionLookupRecord *substLookupRecordArray = 
+            (const SubstitutionLookupRecord *) &coverageTableOffsetArray[gCount];
+
+        ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, subCount, glyphIterator, fontInstance, position, success);
+
+        return gCount + 1;
+    }
+
+    glyphIterator->setCurrStreamPosition(position);
+
+    return 0;
+}
+
+le_uint32 ChainingContextualSubstitutionSubtable::process(const LookupProcessor *lookupProcessor, 
+                                                          GlyphIterator *glyphIterator,
+                                                          const LEFontInstance *fontInstance,
+                                                          LEErrorCode& success) const
+{
+    if (LE_FAILURE(success)) { 
+        return 0;
+    }
+
+    switch(SWAPW(subtableFormat))
+    {
+    case 0:
+        return 0;
+
+    case 1:
+    {
+        const ChainingContextualSubstitutionFormat1Subtable *subtable = (const ChainingContextualSubstitutionFormat1Subtable *) this;
+        return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
+    }
+
+    case 2:
+    {
+        const ChainingContextualSubstitutionFormat2Subtable *subtable = (const ChainingContextualSubstitutionFormat2Subtable *) this;
+        return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
+    }
+
+    case 3:
+    {
+        const ChainingContextualSubstitutionFormat3Subtable *subtable = (const ChainingContextualSubstitutionFormat3Subtable *) this;
+        return subtable->process(lookupProcessor, glyphIterator, fontInstance, success);
+    }
+
+    default:
+        return 0;
+    }
+}
+
+// NOTE: This could be a #define, but that seems to confuse
+// the Visual Studio .NET 2003 compiler on the calls to the
+// GlyphIterator constructor. It somehow can't decide if
+// emptyFeatureList matches an le_uint32 or an le_uint16...
+static const FeatureMask emptyFeatureList = 0x00000000UL;
+
+le_uint32 ChainingContextualSubstitutionFormat1Subtable::process(const LookupProcessor *lookupProcessor, 
+                                                                 GlyphIterator *glyphIterator,
+                                                                 const LEFontInstance *fontInstance,
+                                                                 LEErrorCode& success) const
+{
+    if (LE_FAILURE(success)) { 
+        return 0;
+    }
+
+    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
+    le_int32 coverageIndex = getGlyphCoverage(glyph);
+
+    if (coverageIndex >= 0) {
+        le_uint16 srSetCount = SWAPW(chainSubRuleSetCount);
+
+        if (coverageIndex < srSetCount) {
+            Offset chainSubRuleSetTableOffset = SWAPW(chainSubRuleSetTableOffsetArray[coverageIndex]);
+            const ChainSubRuleSetTable *chainSubRuleSetTable =
+                (const ChainSubRuleSetTable *) ((char *) this + chainSubRuleSetTableOffset);
+            le_uint16 chainSubRuleCount = SWAPW(chainSubRuleSetTable->chainSubRuleCount);
+            le_int32 position = glyphIterator->getCurrStreamPosition();
+            GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);
+
+            for (le_uint16 subRule = 0; subRule < chainSubRuleCount; subRule += 1) {
+                Offset chainSubRuleTableOffset =
+                    SWAPW(chainSubRuleSetTable->chainSubRuleTableOffsetArray[subRule]);
+                const ChainSubRuleTable *chainSubRuleTable =
+                    (const ChainSubRuleTable *) ((char *) chainSubRuleSetTable + chainSubRuleTableOffset);
+                le_uint16 backtrackGlyphCount = SWAPW(chainSubRuleTable->backtrackGlyphCount);
+                le_uint16 inputGlyphCount = (le_uint16) SWAPW(chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount]) - 1;
+                const TTGlyphID *inputGlyphArray = &chainSubRuleTable->backtrackGlyphArray[backtrackGlyphCount + 1];
+                le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputGlyphArray[inputGlyphCount]);
+                const TTGlyphID *lookaheadGlyphArray = &inputGlyphArray[inputGlyphCount + 1];
+                le_uint16 substCount = (le_uint16) SWAPW(lookaheadGlyphArray[lookaheadGlyphCount]);
+
+                tempIterator.setCurrStreamPosition(position);
+
+                if (! tempIterator.prev(backtrackGlyphCount)) {
+                    continue;
+                }
+
+                tempIterator.prev();
+                if (! matchGlyphIDs(chainSubRuleTable->backtrackGlyphArray, backtrackGlyphCount, &tempIterator, TRUE)) {
+                    continue;
+                }
+
+                tempIterator.setCurrStreamPosition(position);
+                tempIterator.next(inputGlyphCount);
+                if (!matchGlyphIDs(lookaheadGlyphArray, lookaheadGlyphCount, &tempIterator)) {
+                    continue;
+                }
+
+                if (matchGlyphIDs(inputGlyphArray, inputGlyphCount, glyphIterator)) {
+                    const SubstitutionLookupRecord *substLookupRecordArray = 
+                        (const SubstitutionLookupRecord *) &lookaheadGlyphArray[lookaheadGlyphCount + 1];
+
+                    applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
+
+                    return inputGlyphCount + 1;
+                }
+
+                glyphIterator->setCurrStreamPosition(position);
+            }
+        }
+
+        // XXX If we get here, the table is mal-formed...
+    }
+    
+    return 0;
+}
+
+le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LookupProcessor *lookupProcessor, 
+                                                                 GlyphIterator *glyphIterator,
+                                                                 const LEFontInstance *fontInstance,
+                                                                 LEErrorCode& success) const
+{
+    if (LE_FAILURE(success)) { 
+        return 0;
+    }
+
+    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
+    le_int32 coverageIndex = getGlyphCoverage(glyph);
+
+    if (coverageIndex >= 0) {
+        const ClassDefinitionTable *backtrackClassDefinitionTable =
+            (const ClassDefinitionTable *) ((char *) this + SWAPW(backtrackClassDefTableOffset));
+        const ClassDefinitionTable *inputClassDefinitionTable =
+            (const ClassDefinitionTable *) ((char *) this + SWAPW(inputClassDefTableOffset));
+        const ClassDefinitionTable *lookaheadClassDefinitionTable =
+            (const ClassDefinitionTable *) ((char *) this + SWAPW(lookaheadClassDefTableOffset));
+        le_uint16 scSetCount = SWAPW(chainSubClassSetCount);
+        le_int32 setClass = inputClassDefinitionTable->getGlyphClass(glyphIterator->getCurrGlyphID());
+
+        if (setClass < scSetCount && chainSubClassSetTableOffsetArray[setClass] != 0) {
+            Offset chainSubClassSetTableOffset = SWAPW(chainSubClassSetTableOffsetArray[setClass]);
+            const ChainSubClassSetTable *chainSubClassSetTable =
+                (const ChainSubClassSetTable *) ((char *) this + chainSubClassSetTableOffset);
+            le_uint16 chainSubClassRuleCount = SWAPW(chainSubClassSetTable->chainSubClassRuleCount);
+            le_int32 position = glyphIterator->getCurrStreamPosition();
+            GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);
+
+            for (le_uint16 scRule = 0; scRule < chainSubClassRuleCount; scRule += 1) {
+                Offset chainSubClassRuleTableOffset =
+                    SWAPW(chainSubClassSetTable->chainSubClassRuleTableOffsetArray[scRule]);
+                const ChainSubClassRuleTable *chainSubClassRuleTable =
+                    (const ChainSubClassRuleTable *) ((char *) chainSubClassSetTable + chainSubClassRuleTableOffset);
+                le_uint16 backtrackGlyphCount = SWAPW(chainSubClassRuleTable->backtrackGlyphCount);
+                le_uint16 inputGlyphCount = SWAPW(chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount]) - 1;
+                const le_uint16 *inputClassArray = &chainSubClassRuleTable->backtrackClassArray[backtrackGlyphCount + 1];
+                le_uint16 lookaheadGlyphCount = SWAPW(inputClassArray[inputGlyphCount]);
+                const le_uint16 *lookaheadClassArray = &inputClassArray[inputGlyphCount + 1];
+                le_uint16 substCount = SWAPW(lookaheadClassArray[lookaheadGlyphCount]);
+                
+
+                tempIterator.setCurrStreamPosition(position);
+
+                if (! tempIterator.prev(backtrackGlyphCount)) {
+                    continue;
+                }
+
+                tempIterator.prev();
+                if (! matchGlyphClasses(chainSubClassRuleTable->backtrackClassArray, backtrackGlyphCount,
+                    &tempIterator, backtrackClassDefinitionTable, TRUE)) {
+                    continue;
+                }
+
+                tempIterator.setCurrStreamPosition(position);
+                tempIterator.next(inputGlyphCount);
+                if (! matchGlyphClasses(lookaheadClassArray, lookaheadGlyphCount, &tempIterator, lookaheadClassDefinitionTable)) {
+                    continue;
+                }
+
+                if (matchGlyphClasses(inputClassArray, inputGlyphCount, glyphIterator, inputClassDefinitionTable)) {
+                    const SubstitutionLookupRecord *substLookupRecordArray = 
+                        (const SubstitutionLookupRecord *) &lookaheadClassArray[lookaheadGlyphCount + 1];
+
+                    applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
+
+                    return inputGlyphCount + 1;
+                }
+
+                glyphIterator->setCurrStreamPosition(position);
+            }
+        }
+
+        // XXX If we get here, the table is mal-formed...
+    }
+    
+    return 0;
+}
+
+le_uint32 ChainingContextualSubstitutionFormat3Subtable::process(const LookupProcessor *lookupProcessor, 
+                                                                 GlyphIterator *glyphIterator,
+                                                                 const LEFontInstance *fontInstance,
+                                                                 LEErrorCode & success) const
+{
+    if (LE_FAILURE(success)) { 
+        return 0;
+    }
+
+    le_uint16 backtrkGlyphCount = SWAPW(backtrackGlyphCount);
+    le_uint16 inputGlyphCount = (le_uint16) SWAPW(backtrackCoverageTableOffsetArray[backtrkGlyphCount]);
+    const Offset *inputCoverageTableOffsetArray = &backtrackCoverageTableOffsetArray[backtrkGlyphCount + 1];
+    const le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputCoverageTableOffsetArray[inputGlyphCount]);
+    const Offset *lookaheadCoverageTableOffsetArray = &inputCoverageTableOffsetArray[inputGlyphCount + 1];
+    le_uint16 substCount = (le_uint16) SWAPW(lookaheadCoverageTableOffsetArray[lookaheadGlyphCount]);
+    le_int32 position = glyphIterator->getCurrStreamPosition();
+    GlyphIterator tempIterator(*glyphIterator, emptyFeatureList);
+
+    if (! tempIterator.prev(backtrkGlyphCount)) {
+        return 0;
+    }
+
+    tempIterator.prev();
+    if (! ContextualSubstitutionBase::matchGlyphCoverages(backtrackCoverageTableOffsetArray,
+        backtrkGlyphCount, &tempIterator, (const char *) this, TRUE)) {
+        return 0;
+    }
+
+    tempIterator.setCurrStreamPosition(position);
+    tempIterator.next(inputGlyphCount - 1);
+    if (! ContextualSubstitutionBase::matchGlyphCoverages(lookaheadCoverageTableOffsetArray,
+        lookaheadGlyphCount, &tempIterator, (const char *) this)) {
+        return 0;
+    }
+
+    // Back up the glyph iterator so that we
+    // can call next() before the check, which
+    // will leave it pointing at the last glyph
+    // that matched when we're done.
+    glyphIterator->prev();
+
+    if (ContextualSubstitutionBase::matchGlyphCoverages(inputCoverageTableOffsetArray,
+        inputGlyphCount, glyphIterator, (const char *) this)) {
+        const SubstitutionLookupRecord *substLookupRecordArray = 
+            (const SubstitutionLookupRecord *) &lookaheadCoverageTableOffsetArray[lookaheadGlyphCount + 1];
+
+        ContextualSubstitutionBase::applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success);
+
+        return inputGlyphCount;
+    }
+
+    glyphIterator->setCurrStreamPosition(position);
+
+    return 0;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/ContextualSubstSubtables.h b/source/layout/ContextualSubstSubtables.h
new file mode 100644
index 0000000..2ca1c1a
--- /dev/null
+++ b/source/layout/ContextualSubstSubtables.h
@@ -0,0 +1,205 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#ifndef __CONTEXTUALSUBSTITUTIONSUBTABLES_H
+#define __CONTEXTUALSUBSTITUTIONSUBTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "GlyphSubstitutionTables.h"
+#include "GlyphIterator.h"
+#include "LookupProcessor.h"
+
+U_NAMESPACE_BEGIN
+
+struct SubstitutionLookupRecord
+{
+    le_uint16  sequenceIndex;
+    le_uint16  lookupListIndex;
+};
+
+struct ContextualSubstitutionBase : GlyphSubstitutionSubtable
+{
+    static le_bool matchGlyphIDs(
+        const TTGlyphID *glyphArray, le_uint16 glyphCount, GlyphIterator *glyphIterator,
+        le_bool backtrack = FALSE);
+
+    static le_bool matchGlyphClasses(
+        const le_uint16 *classArray, le_uint16 glyphCount, GlyphIterator *glyphIterator,
+        const ClassDefinitionTable *classDefinitionTable, le_bool backtrack = FALSE);
+
+    static le_bool matchGlyphCoverages(
+        const Offset *coverageTableOffsetArray, le_uint16 glyphCount,
+        GlyphIterator *glyphIterator, const char *offsetBase, le_bool backtrack = FALSE);
+
+    static void applySubstitutionLookups(
+        const LookupProcessor *lookupProcessor, 
+        const SubstitutionLookupRecord *substLookupRecordArray,
+        le_uint16 substCount,
+        GlyphIterator *glyphIterator,
+        const LEFontInstance *fontInstance,
+        le_int32 position,
+        LEErrorCode& success);
+};
+
+struct ContextualSubstitutionSubtable : ContextualSubstitutionBase
+{
+    le_uint32  process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const;
+};
+
+struct ContextualSubstitutionFormat1Subtable : ContextualSubstitutionSubtable
+{
+    le_uint16  subRuleSetCount;
+    Offset  subRuleSetTableOffsetArray[ANY_NUMBER];
+
+    le_uint32  process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const;
+};
+
+struct SubRuleSetTable
+{
+    le_uint16  subRuleCount;
+    Offset  subRuleTableOffsetArray[ANY_NUMBER];
+
+};
+
+// NOTE: Multiple variable size arrays!!
+struct SubRuleTable
+{
+    le_uint16  glyphCount;
+    le_uint16  substCount;
+    TTGlyphID inputGlyphArray[ANY_NUMBER];
+  //SubstitutionLookupRecord substLookupRecordArray[ANY_NUMBER];
+};
+
+struct ContextualSubstitutionFormat2Subtable : ContextualSubstitutionSubtable
+{
+    Offset  classDefTableOffset;
+    le_uint16  subClassSetCount;
+    Offset  subClassSetTableOffsetArray[ANY_NUMBER];
+
+    le_uint32  process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const;
+};
+
+struct SubClassSetTable
+{
+    le_uint16  subClassRuleCount;
+    Offset  subClassRuleTableOffsetArray[ANY_NUMBER];
+};
+
+// NOTE: Multiple variable size arrays!!
+struct SubClassRuleTable
+{
+    le_uint16  glyphCount;
+    le_uint16  substCount;
+    le_uint16  classArray[ANY_NUMBER];
+  //SubstitutionLookupRecord substLookupRecordArray[ANY_NUMBER];
+};
+
+// NOTE: This isn't a subclass of GlyphSubstitutionSubtable 'cause
+// it has an array of coverage tables instead of a single coverage table...
+//
+// NOTE: Multiple variable size arrays!!
+struct ContextualSubstitutionFormat3Subtable
+{
+    le_uint16  substFormat;
+    le_uint16  glyphCount;
+    le_uint16  substCount;
+    Offset  coverageTableOffsetArray[ANY_NUMBER];
+  //SubstitutionLookupRecord substLookupRecord[ANY_NUMBER];
+
+    le_uint32  process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const;
+};
+
+struct ChainingContextualSubstitutionSubtable : ContextualSubstitutionBase
+{
+    le_uint32  process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const;
+};
+
+struct ChainingContextualSubstitutionFormat1Subtable : ChainingContextualSubstitutionSubtable
+{
+    le_uint16  chainSubRuleSetCount;
+    Offset  chainSubRuleSetTableOffsetArray[ANY_NUMBER];
+
+    le_uint32  process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const;
+};
+
+struct ChainSubRuleSetTable
+{
+    le_uint16  chainSubRuleCount;
+    Offset  chainSubRuleTableOffsetArray[ANY_NUMBER];
+
+};
+
+// NOTE: Multiple variable size arrays!!
+struct ChainSubRuleTable
+{
+    le_uint16  backtrackGlyphCount;
+    TTGlyphID backtrackGlyphArray[ANY_NUMBER];
+  //le_uint16  inputGlyphCount;
+  //TTGlyphID inputGlyphArray[ANY_NUMBER];
+  //le_uint16  lookaheadGlyphCount;
+  //TTGlyphID lookaheadGlyphArray[ANY_NUMBER];
+  //le_uint16  substCount;
+  //SubstitutionLookupRecord substLookupRecordArray[ANY_NUMBER];
+};
+
+struct ChainingContextualSubstitutionFormat2Subtable : ChainingContextualSubstitutionSubtable
+{
+    Offset  backtrackClassDefTableOffset;
+    Offset  inputClassDefTableOffset;
+    Offset  lookaheadClassDefTableOffset;
+    le_uint16  chainSubClassSetCount;
+    Offset  chainSubClassSetTableOffsetArray[ANY_NUMBER];
+
+    le_uint32  process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const;
+};
+
+struct ChainSubClassSetTable
+{
+    le_uint16  chainSubClassRuleCount;
+    Offset  chainSubClassRuleTableOffsetArray[ANY_NUMBER];
+};
+
+// NOTE: Multiple variable size arrays!!
+struct ChainSubClassRuleTable
+{
+    le_uint16  backtrackGlyphCount;
+    le_uint16  backtrackClassArray[ANY_NUMBER];
+  //le_uint16  inputGlyphCount;
+  //le_uint16  inputClassArray[ANY_NUMBER];
+  //le_uint16  lookaheadGlyphCount;
+  //le_uint16  lookaheadClassArray[ANY_NUMBER];
+  //le_uint16  substCount;
+  //SubstitutionLookupRecord substLookupRecordArray[ANY_NUMBER];
+};
+
+// NOTE: This isn't a subclass of GlyphSubstitutionSubtable 'cause
+// it has arrays of coverage tables instead of a single coverage table...
+//
+// NOTE: Multiple variable size arrays!!
+struct ChainingContextualSubstitutionFormat3Subtable
+{
+    le_uint16  substFormat;
+    le_uint16  backtrackGlyphCount;
+    Offset  backtrackCoverageTableOffsetArray[ANY_NUMBER];
+  //le_uint16  inputGlyphCount;
+  //Offset  inputCoverageTableOffsetArray[ANY_NUMBER];
+  //le_uint16  lookaheadGlyphCount;
+  //le_uint16  lookaheadCoverageTableOffsetArray[ANY_NUMBER];
+  //le_uint16  substCount;
+  //SubstitutionLookupRecord substLookupRecord[ANY_NUMBER];
+
+    le_uint32  process(const LookupProcessor *lookupProcessor, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const;
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/CoverageTables.cpp b/source/layout/CoverageTables.cpp
new file mode 100644
index 0000000..e5f1597
--- /dev/null
+++ b/source/layout/CoverageTables.cpp
@@ -0,0 +1,91 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2006 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "OpenTypeUtilities.h"
+#include "CoverageTables.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+le_int32 CoverageTable::getGlyphCoverage(LEGlyphID glyphID) const
+{
+    switch(SWAPW(coverageFormat))
+    {
+    case 0:
+        return -1;
+
+    case 1:
+    {
+        const CoverageFormat1Table *f1Table = (const CoverageFormat1Table *) this;
+
+        return f1Table->getGlyphCoverage(glyphID);
+    }
+
+    case 2:
+    {
+        const CoverageFormat2Table *f2Table = (const CoverageFormat2Table *) this;
+
+        return f2Table->getGlyphCoverage(glyphID);
+    }
+
+    default:
+        return -1;
+    }
+}
+
+le_int32 CoverageFormat1Table::getGlyphCoverage(LEGlyphID glyphID) const
+{
+    TTGlyphID ttGlyphID = (TTGlyphID) LE_GET_GLYPH(glyphID);
+    le_uint16 count = SWAPW(glyphCount);
+    le_uint8 bit = OpenTypeUtilities::highBit(count);
+    le_uint16 power = 1 << bit;
+    le_uint16 extra = count - power;
+    le_uint16 probe = power;
+    le_uint16 index = 0;
+
+	if (count == 0) {
+		return -1;
+	}
+
+    if (SWAPW(glyphArray[extra]) <= ttGlyphID) {
+        index = extra;
+    }
+
+    while (probe > (1 << 0)) {
+        probe >>= 1;
+
+        if (SWAPW(glyphArray[index + probe]) <= ttGlyphID) {
+            index += probe;
+        }
+    }
+
+    if (SWAPW(glyphArray[index]) == ttGlyphID) {
+        return index;
+    }
+
+    return -1;
+}
+
+le_int32 CoverageFormat2Table::getGlyphCoverage(LEGlyphID glyphID) const
+{
+    TTGlyphID ttGlyphID = (TTGlyphID) LE_GET_GLYPH(glyphID);
+    le_uint16 count = SWAPW(rangeCount);
+    le_int32 rangeIndex =
+        OpenTypeUtilities::getGlyphRangeIndex(ttGlyphID, rangeRecordArray, count);
+
+    if (rangeIndex < 0) {
+        return -1;
+    }
+
+    TTGlyphID firstInRange = SWAPW(rangeRecordArray[rangeIndex].firstGlyph);
+    le_uint16  startCoverageIndex = SWAPW(rangeRecordArray[rangeIndex].rangeValue);
+
+    return startCoverageIndex + (ttGlyphID - firstInRange);
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/CoverageTables.h b/source/layout/CoverageTables.h
new file mode 100644
index 0000000..5e9dbaa
--- /dev/null
+++ b/source/layout/CoverageTables.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __COVERAGETABLES_H
+#define __COVERAGETABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+
+U_NAMESPACE_BEGIN
+
+struct CoverageTable
+{
+    le_uint16 coverageFormat;
+
+    le_int32 getGlyphCoverage(LEGlyphID glyphID) const;
+};
+
+struct CoverageFormat1Table : CoverageTable
+{
+    le_uint16  glyphCount;
+    TTGlyphID glyphArray[ANY_NUMBER];
+
+    le_int32 getGlyphCoverage(LEGlyphID glyphID) const;
+};
+
+struct CoverageFormat2Table : CoverageTable
+{
+    le_uint16        rangeCount;
+    GlyphRangeRecord rangeRecordArray[ANY_NUMBER];
+
+    le_int32 getGlyphCoverage(LEGlyphID glyphID) const;
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/CursiveAttachmentSubtables.cpp b/source/layout/CursiveAttachmentSubtables.cpp
new file mode 100644
index 0000000..9d2144f
--- /dev/null
+++ b/source/layout/CursiveAttachmentSubtables.cpp
@@ -0,0 +1,53 @@
+/*
+ * (C) Copyright IBM Corp. 1998 - 2007 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "GlyphPositioningTables.h"
+#include "CursiveAttachmentSubtables.h"
+#include "AnchorTables.h"
+#include "GlyphIterator.h"
+#include "OpenTypeUtilities.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+le_uint32 CursiveAttachmentSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const
+{
+    LEGlyphID glyphID       = glyphIterator->getCurrGlyphID();
+    le_int32  coverageIndex = getGlyphCoverage(glyphID);
+    le_uint16 eeCount       = SWAPW(entryExitCount);
+
+    if (coverageIndex < 0 || coverageIndex >= eeCount) {
+        glyphIterator->setCursiveGlyph();
+        return 0;
+    }
+
+    LEPoint entryAnchor, exitAnchor;
+    Offset entryOffset = SWAPW(entryExitRecords[coverageIndex].entryAnchor);
+    Offset exitOffset  = SWAPW(entryExitRecords[coverageIndex].exitAnchor);
+
+    if (entryOffset != 0) {
+        const AnchorTable *entryAnchorTable = (const AnchorTable *) ((char *) this + entryOffset);
+
+        entryAnchorTable->getAnchor(glyphID, fontInstance, entryAnchor);
+        glyphIterator->setCursiveEntryPoint(entryAnchor);
+    } else {
+        //glyphIterator->clearCursiveEntryPoint();
+    }
+
+    if (exitOffset != 0) {
+        const AnchorTable *exitAnchorTable = (const AnchorTable *) ((char *) this + exitOffset);
+
+        exitAnchorTable->getAnchor(glyphID, fontInstance, exitAnchor);
+        glyphIterator->setCursiveExitPoint(exitAnchor);
+    } else {
+        //glyphIterator->clearCursiveExitPoint();
+    }
+
+    return 1;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/CursiveAttachmentSubtables.h b/source/layout/CursiveAttachmentSubtables.h
new file mode 100644
index 0000000..5eefb2f
--- /dev/null
+++ b/source/layout/CursiveAttachmentSubtables.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
+ *
+ */
+
+#ifndef __CURSIVEATTACHMENTSUBTABLES_H
+#define __CURSIVEATTACHMENTSUBTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "GlyphPositioningTables.h"
+
+U_NAMESPACE_BEGIN
+
+class LEFontInstance;
+class GlyphIterator;
+
+struct EntryExitRecord
+{
+    Offset entryAnchor;
+    Offset exitAnchor;
+};
+
+struct CursiveAttachmentSubtable : GlyphPositioningSubtable
+{
+    le_uint16 entryExitCount;
+    EntryExitRecord entryExitRecords[ANY_NUMBER];
+
+    le_uint32  process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const;
+};
+
+U_NAMESPACE_END
+#endif
+
+
diff --git a/source/layout/DefaultCharMapper.h b/source/layout/DefaultCharMapper.h
new file mode 100644
index 0000000..c0e1bc1
--- /dev/null
+++ b/source/layout/DefaultCharMapper.h
@@ -0,0 +1,57 @@
+/*
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#ifndef __DEFAULTCHARMAPPER_H
+#define __DEFAULTCHARMAPPER_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * This class is an instance of LECharMapper which
+ * implements control character filtering and bidi
+ * mirroring.
+ *
+ * @see LECharMapper
+ */
+class DefaultCharMapper : public UMemory, public LECharMapper
+{
+private:
+    le_bool fFilterControls;
+    le_bool fMirror;
+
+    static const LEUnicode32 controlChars[];
+
+    static const le_int32 controlCharsCount;
+
+    static const LEUnicode32 mirroredChars[];
+    static const LEUnicode32 srahCderorrim[];
+
+    static const le_int32 mirroredCharsCount;
+
+public:
+    DefaultCharMapper(le_bool filterControls, le_bool mirror)
+        : fFilterControls(filterControls), fMirror(mirror)
+    {
+        // nothing
+    };
+
+    ~DefaultCharMapper()
+    {
+        // nada
+    };
+
+    LEUnicode32 mapChar(LEUnicode32 ch) const;
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/DeviceTables.cpp b/source/layout/DeviceTables.cpp
new file mode 100644
index 0000000..0bbbf18
--- /dev/null
+++ b/source/layout/DeviceTables.cpp
@@ -0,0 +1,46 @@
+/*
+ * @(#)DeviceTables.cpp 1.5 00/03/15
+ *
+ * (C) Copyright IBM Corp. 1998 - 2006 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "DeviceTables.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+const le_uint16 DeviceTable::fieldMasks[]    = {0x0003, 0x000F, 0x00FF};
+const le_uint16 DeviceTable::fieldSignBits[] = {0x0002, 0x0008, 0x0080};
+const le_uint16 DeviceTable::fieldBits[]     = {     2,      4,      8};
+
+#define FORMAT_COUNT LE_ARRAY_SIZE(fieldBits)
+
+le_int16 DeviceTable::getAdjustment(le_uint16 ppem) const
+{
+    le_uint16 start = SWAPW(startSize);
+    le_uint16 format = SWAPW(deltaFormat) - 1;
+    le_int16 result = 0;
+    
+    if (ppem >= start && ppem <= SWAPW(endSize) && format < FORMAT_COUNT) {
+        le_uint16 sizeIndex = ppem - start;
+        le_uint16 bits = fieldBits[format];
+        le_uint16 count = 16 / bits;
+        le_uint16 word = SWAPW(deltaValues[sizeIndex / count]);
+        le_uint16 fieldIndex = sizeIndex % count;
+        le_uint16 shift = 16 - (bits * (fieldIndex + 1));
+        le_uint16 field = (word >> shift) & fieldMasks[format];
+
+        result = field;
+
+        if ((field & fieldSignBits[format]) != 0) {
+            result |= ~ fieldMasks[format];
+        }
+    }
+
+    return result;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/DeviceTables.h b/source/layout/DeviceTables.h
new file mode 100644
index 0000000..864bba1
--- /dev/null
+++ b/source/layout/DeviceTables.h
@@ -0,0 +1,39 @@
+/*
+ * @(#)DeviceTables.h   1.5 00/03/15
+ *
+ * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
+ *
+ */
+
+#ifndef __DEVICETABLES_H
+#define __DEVICETABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+
+U_NAMESPACE_BEGIN
+
+struct DeviceTable
+{
+    le_uint16  startSize;
+    le_uint16  endSize;
+    le_uint16  deltaFormat;
+    le_uint16  deltaValues[ANY_NUMBER];
+
+    le_int16   getAdjustment(le_uint16 ppem) const;
+
+private:
+    static const le_uint16 fieldMasks[];
+    static const le_uint16 fieldSignBits[];
+    static const le_uint16 fieldBits[];
+};
+
+U_NAMESPACE_END
+#endif
+
+
diff --git a/source/layout/ExtensionSubtables.cpp b/source/layout/ExtensionSubtables.cpp
new file mode 100644
index 0000000..6011154
--- /dev/null
+++ b/source/layout/ExtensionSubtables.cpp
@@ -0,0 +1,41 @@
+/*
+ * %W% %E%
+ *
+ * (C) Copyright IBM Corp. 2008-2010 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "GlyphSubstitutionTables.h"
+#include "LookupProcessor.h"
+#include "ExtensionSubtables.h"
+#include "GlyphIterator.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+// read a 32-bit value that might only be 16-bit-aligned in memory
+#define READ_LONG(code) (le_uint32)((SWAPW(*(le_uint16*)&code) << 16) + SWAPW(*(((le_uint16*)&code) + 1)))
+
+// FIXME: should look at the format too... maybe have a sub-class for it?
+le_uint32 ExtensionSubtable::process(const LookupProcessor *lookupProcessor, le_uint16 lookupType,
+                                      GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    le_uint16 elt = SWAPW(extensionLookupType);
+
+    if (elt != lookupType) {
+        le_uint32 extOffset = READ_LONG(extensionOffset);
+        LookupSubtable *subtable = (LookupSubtable *) ((char *) this + extOffset);
+
+        return lookupProcessor->applySubtable(subtable, elt, glyphIterator, fontInstance, success);
+    }
+
+    return 0;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/ExtensionSubtables.h b/source/layout/ExtensionSubtables.h
new file mode 100644
index 0000000..7d214af
--- /dev/null
+++ b/source/layout/ExtensionSubtables.h
@@ -0,0 +1,35 @@
+/*
+ * %W% %E%
+ *
+ * (C) Copyright IBM Corp. 2002-2008 - All Rights Reserved
+ *
+ */
+
+#ifndef __EXTENSIONSUBTABLES_H
+#define __EXTENSIONSUBTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "GlyphSubstitutionTables.h"
+#include "LookupProcessor.h"
+#include "GlyphIterator.h"
+
+U_NAMESPACE_BEGIN
+
+struct ExtensionSubtable //: GlyphSubstitutionSubtable
+{
+    le_uint16 substFormat;
+    le_uint16 extensionLookupType;
+    le_uint32 extensionOffset;
+
+    le_uint32 process(const LookupProcessor *lookupProcessor, le_uint16 lookupType,
+                      GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const;
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/Features.cpp b/source/layout/Features.cpp
new file mode 100644
index 0000000..01419ec
--- /dev/null
+++ b/source/layout/Features.cpp
@@ -0,0 +1,61 @@
+/*
+ * @(#)Features.cpp 1.4 00/03/15
+ *
+ * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "OpenTypeUtilities.h"
+#include "OpenTypeTables.h"
+#include "ICUFeatures.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+const FeatureTable *FeatureListTable::getFeatureTable(le_uint16 featureIndex, LETag *featureTag) const
+{
+    if (featureIndex >= SWAPW(featureCount)) {
+        return 0;
+    }
+
+    Offset featureTableOffset = featureRecordArray[featureIndex].featureTableOffset;
+
+    *featureTag = SWAPT(featureRecordArray[featureIndex].featureTag);
+
+    return (const FeatureTable *) ((char *) this + SWAPW(featureTableOffset));
+}
+
+/*
+ * Note: according to the OpenType Spec. v 1.4, the entries in the Feature
+ * List Table are sorted alphabetically by feature tag; however, there seem
+ * to be some fonts which have an unsorted list; that's why the binary search
+ * is #if 0'd out and replaced by a linear search.
+ *
+ * Also note: as of ICU 2.6, this method isn't called anyhow...
+ */
+const FeatureTable *FeatureListTable::getFeatureTable(LETag featureTag) const
+{
+#if 0
+    Offset featureTableOffset =
+        OpenTypeUtilities::getTagOffset(featureTag, (TagAndOffsetRecord *) featureRecordArray, SWAPW(featureCount));
+
+    if (featureTableOffset == 0) {
+        return 0;
+    }
+
+    return (const FeatureTable *) ((char *) this + SWAPW(featureTableOffset));
+#else
+    int count = SWAPW(featureCount);
+    
+    for (int i = 0; i < count; i += 1) {
+        if (SWAPT(featureRecordArray[i].featureTag) == featureTag) {
+            return (const FeatureTable *) ((char *) this + SWAPW(featureRecordArray[i].featureTableOffset));
+        }
+    }
+
+    return 0;
+#endif
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/GDEFMarkFilter.cpp b/source/layout/GDEFMarkFilter.cpp
new file mode 100644
index 0000000..344e07a
--- /dev/null
+++ b/source/layout/GDEFMarkFilter.cpp
@@ -0,0 +1,31 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998 - 2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEGlyphFilter.h"
+#include "GDEFMarkFilter.h"
+#include "GlyphDefinitionTables.h"
+
+U_NAMESPACE_BEGIN
+
+GDEFMarkFilter::GDEFMarkFilter(const GlyphDefinitionTableHeader *gdefTable)
+{
+    classDefTable = gdefTable->getGlyphClassDefinitionTable();
+}
+
+GDEFMarkFilter::~GDEFMarkFilter()
+{
+    // nothing to do?
+}
+
+le_bool GDEFMarkFilter::accept(LEGlyphID glyph) const
+{
+    le_int32 glyphClass = classDefTable->getGlyphClass(glyph);
+
+    return glyphClass == gcdMarkGlyph;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/GDEFMarkFilter.h b/source/layout/GDEFMarkFilter.h
new file mode 100644
index 0000000..5ae5b45
--- /dev/null
+++ b/source/layout/GDEFMarkFilter.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __GDEFMARKFILTER__H
+#define __GDEFMARKFILTER__H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEGlyphFilter.h"
+#include "GlyphDefinitionTables.h"
+
+U_NAMESPACE_BEGIN
+
+class GDEFMarkFilter : public UMemory, public LEGlyphFilter
+{
+private:
+    const GlyphClassDefinitionTable *classDefTable;
+
+    GDEFMarkFilter(const GDEFMarkFilter &other); // forbid copying of this class
+    GDEFMarkFilter &operator=(const GDEFMarkFilter &other); // forbid copying of this class
+
+public:
+    GDEFMarkFilter(const GlyphDefinitionTableHeader *gdefTable);
+    virtual ~GDEFMarkFilter();
+
+    virtual le_bool accept(LEGlyphID glyph) const;
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/GXLayoutEngine.cpp b/source/layout/GXLayoutEngine.cpp
new file mode 100644
index 0000000..78f0162
--- /dev/null
+++ b/source/layout/GXLayoutEngine.cpp
@@ -0,0 +1,69 @@
+
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LayoutEngine.h"
+#include "GXLayoutEngine.h"
+#include "LEGlyphStorage.h"
+
+#include "MorphTables.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(GXLayoutEngine)
+
+GXLayoutEngine::GXLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const MorphTableHeader *morphTable, LEErrorCode &success) 
+    : LayoutEngine(fontInstance, scriptCode, languageCode, 0, success), fMorphTable(morphTable)
+{
+    // nothing else to do?
+}
+
+GXLayoutEngine::~GXLayoutEngine()
+{
+    reset();
+}
+
+// apply 'mort' table
+le_int32 GXLayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    mapCharsToGlyphs(chars, offset, count, FALSE, rightToLeft, glyphStorage, success);
+
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    fMorphTable->process(glyphStorage);
+
+    return count;
+}
+
+// apply positional tables
+void GXLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool /*reverse*/,
+                                          LEGlyphStorage &/*glyphStorage*/, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    // FIXME: no positional processing yet...
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/GXLayoutEngine.h b/source/layout/GXLayoutEngine.h
new file mode 100644
index 0000000..8d48a4e
--- /dev/null
+++ b/source/layout/GXLayoutEngine.h
@@ -0,0 +1,126 @@
+
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#ifndef __GXLAYOUTENGINE_H
+#define __GXLAYOUTENGINE_H
+
+#include "LETypes.h"
+#include "LayoutEngine.h"
+
+#include "MorphTables.h"
+
+U_NAMESPACE_BEGIN
+
+class LEFontInstance;
+class LEGlyphStorage;
+
+/**
+ * This class implements layout for QuickDraw GX or Apple Advanced Typograyph (AAT)
+ * fonts. A font is a GX or AAT font if it contains a 'mort' table. See Apple's
+ * TrueType Reference Manual (http://fonts.apple.com/TTRefMan/index.html) for details.
+ * Information about 'mort' tables is in the chapter titled "Font Files."
+ *
+ * @internal
+ */
+class GXLayoutEngine : public LayoutEngine
+{
+public:
+    /**
+     * This is the main constructor. It constructs an instance of GXLayoutEngine for
+     * a particular font, script and language. It takes the 'mort' table as a parameter since
+     * LayoutEngine::layoutEngineFactory has to read the 'mort' table to know that it has a
+     * GX font.
+     *
+     * Note: GX and AAT fonts don't contain any script and language specific tables, so
+     * the script and language are ignored.
+     *
+     * @param fontInstance - the font
+     * @param scriptCode - the script
+     * @param langaugeCode - the language
+     * @param morphTable - the 'mort' table
+     * @param success - set to an error code if the operation fails
+     *
+     * @see LayoutEngine::layoutEngineFactory
+     * @see ScriptAndLangaugeTags.h for script and language codes
+     *
+     * @internal
+     */
+    GXLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, const MorphTableHeader *morphTable, LEErrorCode &success);
+
+    /**
+     * The destructor, virtual for correct polymorphic invocation.
+     *
+     * @internal
+     */
+    virtual ~GXLayoutEngine();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.8
+     */
+    static UClassID getStaticClassID();
+
+protected:
+
+    /**
+     * The address of the 'mort' table
+     *
+     * @internal
+     */
+    const MorphTableHeader *fMorphTable;
+
+    /**
+     * This method does GX layout using the font's 'mort' table. It converts the
+     * input character codes to glyph indices using mapCharsToGlyphs, and then
+     * applies the 'mort' table.
+     *
+     * Input parameters:
+     * @param chars - the input character context
+     * @param offset - the index of the first character to process
+     * @param count - the number of characters to process
+     * @param max - the number of characters in the input context
+     * @param rightToLeft - <code>TRUE</code> if the text is in a right to left directional run
+     * @param glyphStorage - the glyph storage object. The glyph and char index arrays will be set.
+     *
+     * Output parameters:
+     * @param success - set to an error code if the operation fails
+     *
+     * @return the number of glyphs in the glyph index array
+     *
+     * @internal
+     */
+    virtual le_int32 computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+        LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+    /**
+     * This method adjusts the glyph positions using the font's
+     * 'kern', 'trak', 'bsln', 'opbd' and 'just' tables.
+     *
+     * Input parameters:
+     * @param glyphStorage - the object holding the glyph storage. The positions will be updated as needed.
+     *
+     * Output parameters:
+     * @param success - set to an error code if the operation fails
+     *
+     * @internal
+     */
+    virtual void adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
+                                      LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/GlyphDefinitionTables.cpp b/source/layout/GlyphDefinitionTables.cpp
new file mode 100644
index 0000000..a51e6ba
--- /dev/null
+++ b/source/layout/GlyphDefinitionTables.cpp
@@ -0,0 +1,34 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998 - 2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "GlyphDefinitionTables.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+const GlyphClassDefinitionTable *GlyphDefinitionTableHeader::getGlyphClassDefinitionTable() const
+{
+    return (const GlyphClassDefinitionTable *) ((char *) this + SWAPW(glyphClassDefOffset));
+}
+
+const AttachmentListTable *GlyphDefinitionTableHeader::getAttachmentListTable() const
+{
+    return (const AttachmentListTable *) ((char *) this + SWAPW(attachListOffset));
+}
+
+const LigatureCaretListTable *GlyphDefinitionTableHeader::getLigatureCaretListTable() const
+{
+    return (const LigatureCaretListTable *) ((char *) this + SWAPW(ligCaretListOffset));
+}
+
+const MarkAttachClassDefinitionTable *GlyphDefinitionTableHeader::getMarkAttachClassDefinitionTable() const
+{
+    return (const MarkAttachClassDefinitionTable *) ((char *) this + SWAPW(MarkAttachClassDefOffset));
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/GlyphDefinitionTables.h b/source/layout/GlyphDefinitionTables.h
new file mode 100644
index 0000000..e4cbbb6
--- /dev/null
+++ b/source/layout/GlyphDefinitionTables.h
@@ -0,0 +1,96 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __GLYPHDEFINITIONTABLES_H
+#define __GLYPHDEFINITIONTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "ClassDefinitionTables.h"
+
+U_NAMESPACE_BEGIN
+
+typedef ClassDefinitionTable GlyphClassDefinitionTable;
+
+enum GlyphClassDefinitions
+{
+    gcdNoGlyphClass     = 0,
+    gcdSimpleGlyph      = 1,
+    gcdLigatureGlyph    = 2,
+    gcdMarkGlyph        = 3,
+    gcdComponentGlyph   = 4
+};
+
+struct AttachmentListTable
+{
+    Offset  coverageTableOffset;
+    le_uint16  glyphCount;
+    Offset  attachPointTableOffsetArray[ANY_NUMBER];
+};
+
+struct AttachPointTable
+{
+    le_uint16  pointCount;
+    le_uint16  pointIndexArray[ANY_NUMBER];
+};
+
+struct LigatureCaretListTable
+{
+    Offset  coverageTableOffset;
+    le_uint16  ligGlyphCount;
+    Offset  ligGlyphTableOffsetArray[ANY_NUMBER];
+};
+
+struct LigatureGlyphTable
+{
+    le_uint16  caretCount;
+    Offset  caretValueTableOffsetArray[ANY_NUMBER];
+};
+
+struct CaretValueTable
+{
+    le_uint16  caretValueFormat;
+};
+
+struct CaretValueFormat1Table : CaretValueTable
+{
+    le_int16   coordinate;
+};
+
+struct CaretValueFormat2Table : CaretValueTable
+{
+    le_uint16  caretValuePoint;
+};
+
+struct CaretValueFormat3Table : CaretValueTable
+{
+    le_int16   coordinate;
+    Offset  deviceTableOffset;
+};
+
+typedef ClassDefinitionTable MarkAttachClassDefinitionTable;
+
+struct GlyphDefinitionTableHeader
+{
+    fixed32 version;
+    Offset  glyphClassDefOffset;
+    Offset  attachListOffset;
+    Offset  ligCaretListOffset;
+    Offset  MarkAttachClassDefOffset;
+
+    const GlyphClassDefinitionTable *getGlyphClassDefinitionTable() const;
+    const AttachmentListTable *getAttachmentListTable()const ;
+    const LigatureCaretListTable *getLigatureCaretListTable() const;
+    const MarkAttachClassDefinitionTable *getMarkAttachClassDefinitionTable() const;
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/GlyphIterator.cpp b/source/layout/GlyphIterator.cpp
new file mode 100644
index 0000000..2317434
--- /dev/null
+++ b/source/layout/GlyphIterator.cpp
@@ -0,0 +1,506 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "GlyphDefinitionTables.h"
+#include "GlyphPositionAdjustments.h"
+#include "GlyphIterator.h"
+#include "LEGlyphStorage.h"
+#include "Lookups.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+GlyphIterator::GlyphIterator(LEGlyphStorage &theGlyphStorage, GlyphPositionAdjustments *theGlyphPositionAdjustments, le_bool rightToLeft, le_uint16 theLookupFlags,
+                             FeatureMask theFeatureMask, const GlyphDefinitionTableHeader *theGlyphDefinitionTableHeader)
+  : direction(1), position(-1), nextLimit(-1), prevLimit(-1),
+    glyphStorage(theGlyphStorage), glyphPositionAdjustments(theGlyphPositionAdjustments),
+    srcIndex(-1), destIndex(-1), lookupFlags(theLookupFlags), featureMask(theFeatureMask), glyphGroup(0),
+    glyphClassDefinitionTable(NULL), markAttachClassDefinitionTable(NULL)
+
+{
+    le_int32 glyphCount = glyphStorage.getGlyphCount();
+
+    if (theGlyphDefinitionTableHeader != NULL) {
+        glyphClassDefinitionTable = theGlyphDefinitionTableHeader->getGlyphClassDefinitionTable();
+        markAttachClassDefinitionTable = theGlyphDefinitionTableHeader->getMarkAttachClassDefinitionTable();
+    }
+
+    nextLimit = glyphCount;
+
+    if (rightToLeft) {
+        direction = -1;
+        position = glyphCount;
+        nextLimit = -1;
+        prevLimit = glyphCount;
+    }
+}
+
+GlyphIterator::GlyphIterator(GlyphIterator &that)
+  : glyphStorage(that.glyphStorage)
+{
+    direction    = that.direction;
+    position     = that.position;
+    nextLimit    = that.nextLimit;
+    prevLimit    = that.prevLimit;
+
+    glyphPositionAdjustments = that.glyphPositionAdjustments;
+    srcIndex = that.srcIndex;
+    destIndex = that.destIndex;
+    lookupFlags = that.lookupFlags;
+    featureMask = that.featureMask;
+    glyphGroup  = that.glyphGroup;
+    glyphClassDefinitionTable = that.glyphClassDefinitionTable;
+    markAttachClassDefinitionTable = that.markAttachClassDefinitionTable;
+}
+
+GlyphIterator::GlyphIterator(GlyphIterator &that, FeatureMask newFeatureMask)
+  : glyphStorage(that.glyphStorage)
+{
+    direction    = that.direction;
+    position     = that.position;
+    nextLimit    = that.nextLimit;
+    prevLimit    = that.prevLimit;
+
+    glyphPositionAdjustments = that.glyphPositionAdjustments;
+    srcIndex = that.srcIndex;
+    destIndex = that.destIndex;
+    lookupFlags = that.lookupFlags;
+    featureMask = newFeatureMask;
+    glyphGroup  = 0;
+    glyphClassDefinitionTable = that.glyphClassDefinitionTable;
+    markAttachClassDefinitionTable = that.markAttachClassDefinitionTable;
+}
+
+GlyphIterator::GlyphIterator(GlyphIterator &that, le_uint16 newLookupFlags)
+  : glyphStorage(that.glyphStorage)
+{
+    direction    = that.direction;
+    position     = that.position;
+    nextLimit    = that.nextLimit;
+    prevLimit    = that.prevLimit;
+
+    glyphPositionAdjustments = that.glyphPositionAdjustments;
+    srcIndex = that.srcIndex;
+    destIndex = that.destIndex;
+    lookupFlags = newLookupFlags;
+    featureMask = that.featureMask;
+    glyphGroup  = that.glyphGroup;
+    glyphClassDefinitionTable = that.glyphClassDefinitionTable;
+    markAttachClassDefinitionTable = that.markAttachClassDefinitionTable;
+}
+
+GlyphIterator::~GlyphIterator()
+{
+    // nothing to do, right?
+}
+
+void GlyphIterator::reset(le_uint16 newLookupFlags, FeatureMask newFeatureMask)
+{
+    position     = prevLimit;
+    featureMask  = newFeatureMask;
+    glyphGroup   = 0;
+    lookupFlags  = newLookupFlags;
+}
+
+LEGlyphID *GlyphIterator::insertGlyphs(le_int32 count, LEErrorCode& success)
+{
+    return glyphStorage.insertGlyphs(position, count, success);
+}
+
+le_int32 GlyphIterator::applyInsertions()
+{
+    le_int32 newGlyphCount = glyphStorage.applyInsertions();
+
+    if (direction < 0) {
+        prevLimit = newGlyphCount;
+    } else {
+        nextLimit = newGlyphCount;
+    }
+
+    return newGlyphCount;
+}
+
+le_int32 GlyphIterator::getCurrStreamPosition() const
+{
+    return position;
+}
+
+le_bool GlyphIterator::isRightToLeft() const
+{
+    return direction < 0;
+}
+
+le_bool GlyphIterator::ignoresMarks() const
+{
+    return (lookupFlags & lfIgnoreMarks) != 0;
+}
+
+le_bool GlyphIterator::baselineIsLogicalEnd() const
+{
+    return (lookupFlags & lfBaselineIsLogicalEnd) != 0;
+}
+
+LEGlyphID GlyphIterator::getCurrGlyphID() const
+{
+    if (direction < 0) {
+        if (position <= nextLimit || position >= prevLimit) {
+            return 0xFFFF;
+        }
+    } else {
+        if (position <= prevLimit || position >= nextLimit) {
+            return 0xFFFF;
+        }
+    }
+
+    return glyphStorage[position];
+}
+
+void GlyphIterator::getCursiveEntryPoint(LEPoint &entryPoint) const
+{
+    if (direction < 0) {
+        if (position <= nextLimit || position >= prevLimit) {
+            return;
+        }
+    } else {
+        if (position <= prevLimit || position >= nextLimit) {
+            return;
+        }
+    }
+
+    glyphPositionAdjustments->getEntryPoint(position, entryPoint);
+}
+
+void GlyphIterator::getCursiveExitPoint(LEPoint &exitPoint) const
+{
+    if (direction < 0) {
+        if (position <= nextLimit || position >= prevLimit) {
+            return;
+        }
+    } else {
+        if (position <= prevLimit || position >= nextLimit) {
+            return;
+        }
+    }
+
+    glyphPositionAdjustments->getExitPoint(position, exitPoint);
+}
+
+void GlyphIterator::setCurrGlyphID(TTGlyphID glyphID)
+{
+    LEGlyphID glyph = glyphStorage[position];
+
+    glyphStorage[position] = LE_SET_GLYPH(glyph, glyphID);
+}
+
+void GlyphIterator::setCurrStreamPosition(le_int32 newPosition)
+{
+    if (direction < 0) {
+        if (newPosition >= prevLimit) {
+            position = prevLimit;
+            return;
+        }
+
+        if (newPosition <= nextLimit) {
+            position = nextLimit;
+            return;
+        }
+    } else {
+        if (newPosition <= prevLimit) {
+            position = prevLimit;
+            return;
+        }
+
+        if (newPosition >= nextLimit) {
+            position = nextLimit;
+            return;
+        }
+    }
+
+    position = newPosition - direction;
+    next();
+}
+
+void GlyphIterator::setCurrGlyphBaseOffset(le_int32 baseOffset)
+{
+    if (direction < 0) {
+        if (position <= nextLimit || position >= prevLimit) {
+            return;
+        }
+    } else {
+        if (position <= prevLimit || position >= nextLimit) {
+            return;
+        }
+    }
+
+    glyphPositionAdjustments->setBaseOffset(position, baseOffset);
+}
+
+void GlyphIterator::adjustCurrGlyphPositionAdjustment(float xPlacementAdjust, float yPlacementAdjust,
+                                                      float xAdvanceAdjust, float yAdvanceAdjust)
+{
+    if (direction < 0) {
+        if (position <= nextLimit || position >= prevLimit) {
+            return;
+        }
+    } else {
+        if (position <= prevLimit || position >= nextLimit) {
+            return;
+        }
+    }
+
+    glyphPositionAdjustments->adjustXPlacement(position, xPlacementAdjust);
+    glyphPositionAdjustments->adjustYPlacement(position, yPlacementAdjust);
+    glyphPositionAdjustments->adjustXAdvance(position, xAdvanceAdjust);
+    glyphPositionAdjustments->adjustYAdvance(position, yAdvanceAdjust);
+}
+
+void GlyphIterator::setCurrGlyphPositionAdjustment(float xPlacementAdjust, float yPlacementAdjust,
+                                                      float xAdvanceAdjust, float yAdvanceAdjust)
+{
+    if (direction < 0) {
+        if (position <= nextLimit || position >= prevLimit) {
+            return;
+        }
+    } else {
+        if (position <= prevLimit || position >= nextLimit) {
+            return;
+        }
+    }
+
+    glyphPositionAdjustments->setXPlacement(position, xPlacementAdjust);
+    glyphPositionAdjustments->setYPlacement(position, yPlacementAdjust);
+    glyphPositionAdjustments->setXAdvance(position, xAdvanceAdjust);
+    glyphPositionAdjustments->setYAdvance(position, yAdvanceAdjust);
+}
+
+void GlyphIterator::clearCursiveEntryPoint()
+{
+    if (direction < 0) {
+        if (position <= nextLimit || position >= prevLimit) {
+            return;
+        }
+    } else {
+        if (position <= prevLimit || position >= nextLimit) {
+            return;
+        }
+    }
+
+    glyphPositionAdjustments->clearEntryPoint(position);
+}
+
+void GlyphIterator::clearCursiveExitPoint()
+{
+    if (direction < 0) {
+        if (position <= nextLimit || position >= prevLimit) {
+            return;
+        }
+    } else {
+        if (position <= prevLimit || position >= nextLimit) {
+            return;
+        }
+    }
+
+    glyphPositionAdjustments->clearExitPoint(position);
+}
+
+void GlyphIterator::setCursiveEntryPoint(LEPoint &entryPoint)
+{
+    if (direction < 0) {
+        if (position <= nextLimit || position >= prevLimit) {
+            return;
+        }
+    } else {
+        if (position <= prevLimit || position >= nextLimit) {
+            return;
+        }
+    }
+
+    glyphPositionAdjustments->setEntryPoint(position, entryPoint, baselineIsLogicalEnd());
+}
+
+void GlyphIterator::setCursiveExitPoint(LEPoint &exitPoint)
+{
+    if (direction < 0) {
+        if (position <= nextLimit || position >= prevLimit) {
+            return;
+        }
+    } else {
+        if (position <= prevLimit || position >= nextLimit) {
+            return;
+        }
+    }
+
+    glyphPositionAdjustments->setExitPoint(position, exitPoint, baselineIsLogicalEnd());
+}
+
+void GlyphIterator::setCursiveGlyph()
+{
+    if (direction < 0) {
+        if (position <= nextLimit || position >= prevLimit) {
+            return;
+        }
+    } else {
+        if (position <= prevLimit || position >= nextLimit) {
+            return;
+        }
+    }
+
+    glyphPositionAdjustments->setCursiveGlyph(position, baselineIsLogicalEnd());
+}
+
+le_bool GlyphIterator::filterGlyph(le_uint32 index) const
+{
+    LEGlyphID glyphID = glyphStorage[index];
+    le_int32 glyphClass = gcdNoGlyphClass;
+
+    if (LE_GET_GLYPH(glyphID) >= 0xFFFE) {
+        return TRUE;
+    }
+
+    if (glyphClassDefinitionTable != NULL) {
+        glyphClass = glyphClassDefinitionTable->getGlyphClass(glyphID);
+    }
+
+    switch (glyphClass)
+    {
+    case gcdNoGlyphClass:
+        return FALSE;
+
+    case gcdSimpleGlyph:
+        return (lookupFlags & lfIgnoreBaseGlyphs) != 0;
+
+    case gcdLigatureGlyph:
+        return (lookupFlags & lfIgnoreLigatures) != 0;
+
+    case gcdMarkGlyph:
+    {
+        if ((lookupFlags & lfIgnoreMarks) != 0) {
+            return TRUE;
+        }
+
+        le_uint16 markAttachType = (lookupFlags & lfMarkAttachTypeMask) >> lfMarkAttachTypeShift;
+
+        if ((markAttachType != 0) && (markAttachClassDefinitionTable != NULL)) {
+            return markAttachClassDefinitionTable->getGlyphClass(glyphID) != markAttachType;
+        }
+
+        return FALSE;
+    }
+
+    case gcdComponentGlyph:
+        return (lookupFlags & lfIgnoreBaseGlyphs) != 0;
+
+    default:
+        return FALSE;
+    }
+}
+
+le_bool GlyphIterator::hasFeatureTag(le_bool matchGroup) const
+{
+    if (featureMask == 0) {
+        return TRUE;
+    }
+
+    LEErrorCode success = LE_NO_ERROR;
+    FeatureMask fm = glyphStorage.getAuxData(position, success);
+
+    return ((fm & featureMask) == featureMask) && (!matchGroup || (le_int32)(fm & LE_GLYPH_GROUP_MASK) == glyphGroup);
+}
+
+le_bool GlyphIterator::findFeatureTag()
+{
+  //glyphGroup = 0;
+
+    while (nextInternal()) {
+        if (hasFeatureTag(FALSE)) {
+            LEErrorCode success = LE_NO_ERROR;
+
+            glyphGroup = (glyphStorage.getAuxData(position, success) & LE_GLYPH_GROUP_MASK);
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+
+le_bool GlyphIterator::nextInternal(le_uint32 delta)
+{
+    le_int32 newPosition = position;
+
+    while (newPosition != nextLimit && delta > 0) {
+        do {
+            newPosition += direction;
+        } while (newPosition != nextLimit && filterGlyph(newPosition));
+
+        delta -= 1;
+    }
+
+    position = newPosition;
+
+    return position != nextLimit;
+}
+
+le_bool GlyphIterator::next(le_uint32 delta)
+{
+    return nextInternal(delta) && hasFeatureTag(TRUE);
+}
+
+le_bool GlyphIterator::prevInternal(le_uint32 delta)
+{
+    le_int32 newPosition = position;
+
+    while (newPosition != prevLimit && delta > 0) {
+        do {
+            newPosition -= direction;
+        } while (newPosition != prevLimit && filterGlyph(newPosition));
+
+        delta -= 1;
+    }
+
+    position = newPosition;
+
+    return position != prevLimit;
+}
+
+le_bool GlyphIterator::prev(le_uint32 delta)
+{
+    return prevInternal(delta) && hasFeatureTag(TRUE);
+}
+
+le_int32 GlyphIterator::getMarkComponent(le_int32 markPosition) const
+{
+    le_int32 component = 0;
+    le_int32 posn;
+
+    for (posn = position; posn != markPosition; posn += direction) {
+        if (glyphStorage[posn] == 0xFFFE) {
+            component += 1;
+        }
+    }
+
+    return component;
+}
+
+// This is basically prevInternal except that it
+// doesn't take a delta argument, and it doesn't
+// filter out 0xFFFE glyphs.
+le_bool GlyphIterator::findMark2Glyph()
+{
+    le_int32 newPosition = position;
+
+    do {
+        newPosition -= direction;
+    } while (newPosition != prevLimit && glyphStorage[newPosition] != 0xFFFE && filterGlyph(newPosition));
+
+    position = newPosition;
+
+    return position != prevLimit;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/GlyphIterator.h b/source/layout/GlyphIterator.h
new file mode 100644
index 0000000..2aef815
--- /dev/null
+++ b/source/layout/GlyphIterator.h
@@ -0,0 +1,102 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#ifndef __GLYPHITERATOR_H
+#define __GLYPHITERATOR_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "GlyphDefinitionTables.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+class GlyphPositionAdjustments;
+
+class GlyphIterator : public UMemory {
+public:
+    GlyphIterator(LEGlyphStorage &theGlyphStorage, GlyphPositionAdjustments *theGlyphPositionAdjustments, le_bool rightToLeft, le_uint16 theLookupFlags,
+        FeatureMask theFeatureMask, const GlyphDefinitionTableHeader *theGlyphDefinitionTableHeader);
+
+    GlyphIterator(GlyphIterator &that);
+
+    GlyphIterator(GlyphIterator &that, FeatureMask newFeatureMask);
+
+    GlyphIterator(GlyphIterator &that, le_uint16 newLookupFlags);
+
+    virtual ~GlyphIterator();
+
+    void reset(le_uint16 newLookupFlags, LETag newFeatureTag);
+
+    le_bool next(le_uint32 delta = 1);
+    le_bool prev(le_uint32 delta = 1);
+    le_bool findFeatureTag();
+
+    le_bool isRightToLeft() const;
+    le_bool ignoresMarks() const;
+
+    le_bool baselineIsLogicalEnd() const;
+
+    LEGlyphID getCurrGlyphID() const;
+    le_int32  getCurrStreamPosition() const;
+
+    le_int32  getMarkComponent(le_int32 markPosition) const;
+    le_bool   findMark2Glyph();
+
+    void getCursiveEntryPoint(LEPoint &entryPoint) const;
+    void getCursiveExitPoint(LEPoint &exitPoint) const;
+
+    void setCurrGlyphID(TTGlyphID glyphID);
+    void setCurrStreamPosition(le_int32 position);
+    void setCurrGlyphBaseOffset(le_int32 baseOffset);
+    void adjustCurrGlyphPositionAdjustment(float xPlacementAdjust, float yPlacementAdjust,
+                                           float xAdvanceAdjust,   float yAdvanceAdjust);
+
+    void setCurrGlyphPositionAdjustment(float xPlacementAdjust, float yPlacementAdjust,
+                                        float xAdvanceAdjust,   float yAdvanceAdjust);
+
+    void clearCursiveEntryPoint();
+    void clearCursiveExitPoint();
+    void setCursiveEntryPoint(LEPoint &entryPoint);
+    void setCursiveExitPoint(LEPoint &exitPoint);
+    void setCursiveGlyph();
+
+    LEGlyphID *insertGlyphs(le_int32 count, LEErrorCode& success);
+    le_int32 applyInsertions();
+
+private:
+    le_bool filterGlyph(le_uint32 index) const;
+    le_bool hasFeatureTag(le_bool matchGroup) const;
+    le_bool nextInternal(le_uint32 delta = 1);
+    le_bool prevInternal(le_uint32 delta = 1);
+
+    le_int32  direction;
+    le_int32  position;
+    le_int32  nextLimit;
+    le_int32  prevLimit;
+
+    LEGlyphStorage &glyphStorage;
+    GlyphPositionAdjustments *glyphPositionAdjustments;
+
+    le_int32    srcIndex;
+    le_int32    destIndex;
+    le_uint16   lookupFlags;
+    FeatureMask featureMask;
+    le_int32    glyphGroup;
+
+    const GlyphClassDefinitionTable *glyphClassDefinitionTable;
+    const MarkAttachClassDefinitionTable *markAttachClassDefinitionTable;
+
+    GlyphIterator &operator=(const GlyphIterator &other); // forbid copying of this class
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/GlyphLookupTables.cpp b/source/layout/GlyphLookupTables.cpp
new file mode 100644
index 0000000..fdc646f
--- /dev/null
+++ b/source/layout/GlyphLookupTables.cpp
@@ -0,0 +1,32 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "ScriptAndLanguage.h"
+#include "GlyphLookupTables.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+le_bool GlyphLookupTableHeader::coversScript(LETag scriptTag) const
+{
+    const ScriptListTable *scriptListTable = (const ScriptListTable *) ((char *)this + SWAPW(scriptListOffset));
+
+    return scriptListOffset != 0 && scriptListTable->findScript(scriptTag) != NULL;
+}
+
+le_bool GlyphLookupTableHeader::coversScriptAndLanguage(LETag scriptTag, LETag languageTag, le_bool exactMatch) const
+{
+    const ScriptListTable *scriptListTable = (const ScriptListTable *) ((char *)this + SWAPW(scriptListOffset));
+    const LangSysTable    *langSysTable    = scriptListTable->findLanguage(scriptTag, languageTag, exactMatch);
+
+    // FIXME: could check featureListOffset, lookupListOffset, and lookup count...
+    // Note: don't have to SWAPW langSysTable->featureCount to check for non-zero.
+    return langSysTable != NULL && langSysTable->featureCount != 0;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/GlyphLookupTables.h b/source/layout/GlyphLookupTables.h
new file mode 100644
index 0000000..65642d0
--- /dev/null
+++ b/source/layout/GlyphLookupTables.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __GLYPHLOOKUPTABLES_H
+#define __GLYPHLOOKUPTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+
+U_NAMESPACE_BEGIN
+
+struct GlyphLookupTableHeader
+{
+    fixed32 version;
+    Offset  scriptListOffset;
+    Offset  featureListOffset;
+    Offset  lookupListOffset;
+
+    le_bool coversScript(LETag scriptTag) const;
+    le_bool coversScriptAndLanguage(LETag scriptTag, LETag languageTag, le_bool exactMatch = FALSE) const;
+};
+
+U_NAMESPACE_END
+
+#endif
+
diff --git a/source/layout/GlyphPositionAdjustments.cpp b/source/layout/GlyphPositionAdjustments.cpp
new file mode 100644
index 0000000..900e1ae
--- /dev/null
+++ b/source/layout/GlyphPositionAdjustments.cpp
@@ -0,0 +1,185 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "GlyphPositionAdjustments.h"
+#include "LEGlyphStorage.h"
+#include "LEFontInstance.h"
+
+U_NAMESPACE_BEGIN
+
+#define CHECK_ALLOCATE_ARRAY(array, type, size) \
+    if (array == NULL) { \
+        array = (type *) new type[size]; \
+    }
+
+GlyphPositionAdjustments::GlyphPositionAdjustments(le_int32 glyphCount)
+    : fGlyphCount(glyphCount), fEntryExitPoints(NULL), fAdjustments(NULL)
+{
+    fAdjustments = (Adjustment *) new Adjustment[glyphCount];
+}
+
+GlyphPositionAdjustments::~GlyphPositionAdjustments()
+{
+    delete[] fEntryExitPoints;
+    delete[] fAdjustments;
+}
+
+const LEPoint *GlyphPositionAdjustments::getEntryPoint(le_int32 index, LEPoint &entryPoint) const
+{
+    if (fEntryExitPoints == NULL) {
+        return NULL;
+    }
+
+    return fEntryExitPoints[index].getEntryPoint(entryPoint);
+}
+
+const LEPoint *GlyphPositionAdjustments::getExitPoint(le_int32 index, LEPoint &exitPoint)const
+{
+    if (fEntryExitPoints == NULL) {
+        return NULL;
+    }
+
+    return fEntryExitPoints[index].getExitPoint(exitPoint);
+}
+
+void GlyphPositionAdjustments::clearEntryPoint(le_int32 index)
+{
+    CHECK_ALLOCATE_ARRAY(fEntryExitPoints, EntryExitPoint, fGlyphCount);
+
+    fEntryExitPoints[index].clearEntryPoint();
+}
+
+void GlyphPositionAdjustments::clearExitPoint(le_int32 index)
+{
+    CHECK_ALLOCATE_ARRAY(fEntryExitPoints, EntryExitPoint, fGlyphCount);
+
+    fEntryExitPoints[index].clearExitPoint();
+}
+
+void GlyphPositionAdjustments::setEntryPoint(le_int32 index, LEPoint &newEntryPoint, le_bool baselineIsLogicalEnd)
+{
+    CHECK_ALLOCATE_ARRAY(fEntryExitPoints, EntryExitPoint, fGlyphCount);
+
+    fEntryExitPoints[index].setEntryPoint(newEntryPoint, baselineIsLogicalEnd);
+}
+
+void GlyphPositionAdjustments::setExitPoint(le_int32 index, LEPoint &newExitPoint, le_bool baselineIsLogicalEnd)
+{
+    CHECK_ALLOCATE_ARRAY(fEntryExitPoints, EntryExitPoint, fGlyphCount);
+
+    fEntryExitPoints[index].setExitPoint(newExitPoint, baselineIsLogicalEnd);
+}
+
+void GlyphPositionAdjustments::setCursiveGlyph(le_int32 index, le_bool baselineIsLogicalEnd)
+{
+    CHECK_ALLOCATE_ARRAY(fEntryExitPoints, EntryExitPoint, fGlyphCount);
+
+    fEntryExitPoints[index].setCursiveGlyph(baselineIsLogicalEnd);
+}
+
+void GlyphPositionAdjustments::applyCursiveAdjustments(LEGlyphStorage &glyphStorage, le_bool rightToLeft, const LEFontInstance *fontInstance)
+{
+    if (! hasCursiveGlyphs()) {
+        return;
+    }
+
+    le_int32 start = 0, end = fGlyphCount, dir = 1;
+    le_int32 firstExitPoint = -1, lastExitPoint = -1;
+    LEPoint entryAnchor, exitAnchor, pixels;
+    LEGlyphID lastExitGlyphID = 0;
+    float baselineAdjustment = 0;
+
+    // This removes a possible warning about
+    // using exitAnchor before it's been initialized.
+    exitAnchor.fX = exitAnchor.fY = 0;
+
+    if (rightToLeft) {
+        start = fGlyphCount - 1;
+        end = -1;
+        dir = -1;
+    }
+
+    for (le_int32 i = start; i != end; i += dir) {
+        LEGlyphID glyphID = glyphStorage[i];
+
+        if (isCursiveGlyph(i)) {
+            if (lastExitPoint >= 0 && getEntryPoint(i, entryAnchor) != NULL) {
+                float anchorDiffX = exitAnchor.fX - entryAnchor.fX;
+                float anchorDiffY = exitAnchor.fY - entryAnchor.fY;
+
+                baselineAdjustment += anchorDiffY;
+                adjustYPlacement(i, baselineAdjustment);
+
+                if (rightToLeft) {
+                    LEPoint secondAdvance;
+
+                    fontInstance->getGlyphAdvance(glyphID, pixels);
+                    fontInstance->pixelsToUnits(pixels, secondAdvance);
+
+                    adjustXAdvance(i, -(anchorDiffX + secondAdvance.fX));
+                } else {
+                    LEPoint firstAdvance;
+
+                    fontInstance->getGlyphAdvance(lastExitGlyphID, pixels);
+                    fontInstance->pixelsToUnits(pixels, firstAdvance);
+
+                    adjustXAdvance(lastExitPoint, anchorDiffX - firstAdvance.fX);
+                }
+            }
+
+            lastExitPoint = i;
+
+            if (getExitPoint(i, exitAnchor) != NULL) {
+                if (firstExitPoint < 0) {
+                    firstExitPoint = i;
+                }
+
+                lastExitGlyphID = glyphID;
+            } else {
+                if (baselineIsLogicalEnd(i) && firstExitPoint >= 0 && lastExitPoint >= 0) {
+                    le_int32 limit = lastExitPoint /*+ dir*/;
+                    LEPoint dummyAnchor;
+
+                    if (getEntryPoint(i, dummyAnchor) != NULL) {
+                        limit += dir;
+                    }
+
+                    for (le_int32 j = firstExitPoint; j != limit; j += dir) {
+                        if (isCursiveGlyph(j)) {
+                            adjustYPlacement(j, -baselineAdjustment);
+                        }
+                    }
+                }
+
+                firstExitPoint = lastExitPoint = -1;
+                baselineAdjustment = 0;
+            }
+        }
+    }
+}
+
+LEPoint *GlyphPositionAdjustments::EntryExitPoint::getEntryPoint(LEPoint &entryPoint) const
+{
+    if (fFlags & EEF_HAS_ENTRY_POINT) {
+        entryPoint = fEntryPoint;
+        return &entryPoint;
+    }
+
+    return NULL;
+}
+
+LEPoint *GlyphPositionAdjustments::EntryExitPoint::getExitPoint(LEPoint &exitPoint) const
+{
+    if (fFlags & EEF_HAS_EXIT_POINT) {
+        exitPoint = fExitPoint;
+        return &exitPoint;
+    }
+
+    return NULL;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/GlyphPositionAdjustments.h b/source/layout/GlyphPositionAdjustments.h
new file mode 100644
index 0000000..9c9e39b
--- /dev/null
+++ b/source/layout/GlyphPositionAdjustments.h
@@ -0,0 +1,376 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#ifndef __GLYPHPOSITIONADJUSTMENTS_H
+#define __GLYPHPOSITIONADJUSTMENTS_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+class LEFontInstance;
+
+class GlyphPositionAdjustments : public UMemory
+{
+private:
+    class Adjustment : public UMemory {
+    public:
+
+        inline Adjustment();
+        inline Adjustment(float xPlace, float yPlace, float xAdv, float yAdv, le_int32 baseOff = -1);
+        inline ~Adjustment();
+
+        inline float    getXPlacement() const;
+        inline float    getYPlacement() const;
+        inline float    getXAdvance() const;
+        inline float    getYAdvance() const;
+
+        inline le_int32 getBaseOffset() const;
+
+        inline void     setXPlacement(float newXPlacement);
+        inline void     setYPlacement(float newYPlacement);
+        inline void     setXAdvance(float newXAdvance);
+        inline void     setYAdvance(float newYAdvance);
+
+        inline void     setBaseOffset(le_int32 newBaseOffset);
+
+        inline void    adjustXPlacement(float xAdjustment);
+        inline void    adjustYPlacement(float yAdjustment);
+        inline void    adjustXAdvance(float xAdjustment);
+        inline void    adjustYAdvance(float yAdjustment);
+
+    private:
+        float xPlacement;
+        float yPlacement;
+        float xAdvance;
+        float yAdvance;
+
+        le_int32 baseOffset;
+
+        // allow copying of this class because all of its fields are simple types
+    };
+
+    class EntryExitPoint : public UMemory
+    {
+    public:
+        inline EntryExitPoint();
+        inline ~EntryExitPoint();
+
+        inline le_bool isCursiveGlyph() const;
+        inline le_bool baselineIsLogicalEnd() const;
+
+        LEPoint *getEntryPoint(LEPoint &entryPoint) const;
+        LEPoint *getExitPoint(LEPoint &exitPoint) const;
+
+        inline void clearEntryPoint();
+        inline void clearExitPoint();
+        inline void setEntryPoint(LEPoint &newEntryPoint, le_bool baselineIsLogicalEnd);
+        inline void setExitPoint(LEPoint &newExitPoint, le_bool baselineIsLogicalEnd);
+        inline void setCursiveGlyph(le_bool baselineIsLogicalEnd);
+
+    private:
+        enum EntryExitFlags
+        {
+            EEF_HAS_ENTRY_POINT         = 0x80000000L,
+            EEF_HAS_EXIT_POINT          = 0x40000000L,
+            EEF_IS_CURSIVE_GLYPH        = 0x20000000L,
+            EEF_BASELINE_IS_LOGICAL_END = 0x10000000L
+        };
+
+        le_uint32 fFlags;
+        LEPoint fEntryPoint;
+        LEPoint fExitPoint;
+    };
+
+    le_int32 fGlyphCount;
+    EntryExitPoint *fEntryExitPoints;
+    Adjustment *fAdjustments;
+
+    GlyphPositionAdjustments();
+
+public:
+    GlyphPositionAdjustments(le_int32 glyphCount);
+    ~GlyphPositionAdjustments();
+
+    inline le_bool hasCursiveGlyphs() const;
+    inline le_bool isCursiveGlyph(le_int32 index) const;
+    inline le_bool baselineIsLogicalEnd(le_int32 index) const;
+
+    const LEPoint *getEntryPoint(le_int32 index, LEPoint &entryPoint) const;
+    const LEPoint *getExitPoint(le_int32 index, LEPoint &exitPoint) const;
+
+    inline float getXPlacement(le_int32 index) const;
+    inline float getYPlacement(le_int32 index) const;
+    inline float getXAdvance(le_int32 index) const;
+    inline float getYAdvance(le_int32 index) const;
+
+    inline le_int32 getBaseOffset(le_int32 index) const;
+
+    inline void setXPlacement(le_int32 index, float newXPlacement);
+    inline void setYPlacement(le_int32 index, float newYPlacement);
+    inline void setXAdvance(le_int32 index, float newXAdvance);
+    inline void setYAdvance(le_int32 index, float newYAdvance);
+
+    inline void setBaseOffset(le_int32 index, le_int32 newBaseOffset);
+
+    inline void adjustXPlacement(le_int32 index, float xAdjustment);
+    inline void adjustYPlacement(le_int32 index, float yAdjustment);
+    inline void adjustXAdvance(le_int32 index, float xAdjustment);
+    inline void adjustYAdvance(le_int32 index, float yAdjustment);
+   
+    void clearEntryPoint(le_int32 index);
+    void clearExitPoint(le_int32 index);
+    void setEntryPoint(le_int32 index, LEPoint &newEntryPoint, le_bool baselineIsLogicalEnd);
+    void setExitPoint(le_int32 index, LEPoint &newExitPoint, le_bool baselineIsLogicalEnd);
+    void setCursiveGlyph(le_int32 index, le_bool baselineIsLogicalEnd);
+
+    void applyCursiveAdjustments(LEGlyphStorage &glyphStorage, le_bool rightToLeft, const LEFontInstance *fontInstance);
+};
+
+inline GlyphPositionAdjustments::Adjustment::Adjustment()
+  : xPlacement(0), yPlacement(0), xAdvance(0), yAdvance(0), baseOffset(-1)
+{
+    // nothing else to do!
+}
+
+inline GlyphPositionAdjustments::Adjustment::Adjustment(float xPlace, float yPlace, float xAdv, float yAdv, le_int32 baseOff)
+  : xPlacement(xPlace), yPlacement(yPlace), xAdvance(xAdv), yAdvance(yAdv), baseOffset(baseOff)
+{
+    // nothing else to do!
+}
+
+inline GlyphPositionAdjustments::Adjustment::~Adjustment()
+{
+    // nothing to do!
+}
+
+inline float GlyphPositionAdjustments::Adjustment::getXPlacement() const
+{
+    return xPlacement;
+}
+
+inline float GlyphPositionAdjustments::Adjustment::getYPlacement() const
+{
+    return yPlacement;
+}
+
+inline float GlyphPositionAdjustments::Adjustment::getXAdvance() const
+{
+    return xAdvance;
+}
+
+inline float GlyphPositionAdjustments::Adjustment::getYAdvance() const
+{
+    return yAdvance;
+}
+
+inline le_int32 GlyphPositionAdjustments::Adjustment::getBaseOffset() const
+{
+    return baseOffset;
+}
+
+inline void GlyphPositionAdjustments::Adjustment::setXPlacement(float newXPlacement)
+{
+    xPlacement = newXPlacement;
+}
+
+inline void GlyphPositionAdjustments::Adjustment::setYPlacement(float newYPlacement)
+{
+    yPlacement = newYPlacement;
+}
+
+inline void GlyphPositionAdjustments::Adjustment::setXAdvance(float newXAdvance)
+{
+    xAdvance = newXAdvance;
+}
+
+inline void GlyphPositionAdjustments::Adjustment::setYAdvance(float newYAdvance)
+{
+    yAdvance = newYAdvance;
+}
+
+inline void GlyphPositionAdjustments::Adjustment::setBaseOffset(le_int32 newBaseOffset)
+{
+    baseOffset = newBaseOffset;
+}
+
+inline void GlyphPositionAdjustments::Adjustment::adjustXPlacement(float xAdjustment)
+{
+    xPlacement += xAdjustment;
+}
+
+inline void GlyphPositionAdjustments::Adjustment::adjustYPlacement(float yAdjustment)
+{
+    yPlacement += yAdjustment;
+}
+
+inline void GlyphPositionAdjustments::Adjustment::adjustXAdvance(float xAdjustment)
+{
+    xAdvance += xAdjustment;
+}
+
+inline void GlyphPositionAdjustments::Adjustment::adjustYAdvance(float yAdjustment)
+{
+    yAdvance += yAdjustment;
+}
+
+inline GlyphPositionAdjustments::EntryExitPoint::EntryExitPoint()
+    : fFlags(0)
+{
+    fEntryPoint.fX = fEntryPoint.fY = fExitPoint.fX = fExitPoint.fY = 0;
+}
+
+inline GlyphPositionAdjustments::EntryExitPoint::~EntryExitPoint()
+{
+    // nothing special to do
+}
+
+inline le_bool GlyphPositionAdjustments::EntryExitPoint::isCursiveGlyph() const
+{
+    return (fFlags & EEF_IS_CURSIVE_GLYPH) != 0;
+}
+
+inline le_bool GlyphPositionAdjustments::EntryExitPoint::baselineIsLogicalEnd() const
+{
+    return (fFlags & EEF_BASELINE_IS_LOGICAL_END) != 0;
+}
+
+inline void GlyphPositionAdjustments::EntryExitPoint::clearEntryPoint()
+{
+    fFlags &= ~EEF_HAS_ENTRY_POINT;
+}
+
+inline void GlyphPositionAdjustments::EntryExitPoint::clearExitPoint()
+{
+    fFlags &= ~EEF_HAS_EXIT_POINT;
+}
+
+inline void GlyphPositionAdjustments::EntryExitPoint::setEntryPoint(LEPoint &newEntryPoint, le_bool baselineIsLogicalEnd)
+{
+    if (baselineIsLogicalEnd) {
+        fFlags |= (EEF_HAS_ENTRY_POINT | EEF_IS_CURSIVE_GLYPH | EEF_BASELINE_IS_LOGICAL_END);
+    } else {
+        fFlags |= (EEF_HAS_ENTRY_POINT | EEF_IS_CURSIVE_GLYPH);
+    }
+
+    fEntryPoint = newEntryPoint;
+}
+
+inline void GlyphPositionAdjustments::EntryExitPoint::setExitPoint(LEPoint &newExitPoint, le_bool baselineIsLogicalEnd)
+{
+    if (baselineIsLogicalEnd) {
+        fFlags |= (EEF_HAS_EXIT_POINT | EEF_IS_CURSIVE_GLYPH | EEF_BASELINE_IS_LOGICAL_END);
+    } else {
+        fFlags |= (EEF_HAS_EXIT_POINT | EEF_IS_CURSIVE_GLYPH);
+    }
+
+    fExitPoint  = newExitPoint;
+}
+
+inline void GlyphPositionAdjustments::EntryExitPoint::setCursiveGlyph(le_bool baselineIsLogicalEnd)
+{
+    if (baselineIsLogicalEnd) {
+        fFlags |= (EEF_IS_CURSIVE_GLYPH | EEF_BASELINE_IS_LOGICAL_END);
+    } else {
+        fFlags |= EEF_IS_CURSIVE_GLYPH;
+    }
+}
+
+inline le_bool GlyphPositionAdjustments::isCursiveGlyph(le_int32 index) const
+{
+    return fEntryExitPoints != NULL && fEntryExitPoints[index].isCursiveGlyph();
+}
+
+inline le_bool GlyphPositionAdjustments::baselineIsLogicalEnd(le_int32 index) const
+{
+    return fEntryExitPoints != NULL && fEntryExitPoints[index].baselineIsLogicalEnd();
+}
+
+inline float GlyphPositionAdjustments::getXPlacement(le_int32 index) const
+{
+    return fAdjustments[index].getXPlacement();
+}
+
+inline float GlyphPositionAdjustments::getYPlacement(le_int32 index) const
+{
+    return fAdjustments[index].getYPlacement();
+}
+
+inline float GlyphPositionAdjustments::getXAdvance(le_int32 index) const
+{
+    return fAdjustments[index].getXAdvance();
+}
+
+inline float GlyphPositionAdjustments::getYAdvance(le_int32 index) const
+{
+    return fAdjustments[index].getYAdvance();
+}
+
+
+inline le_int32 GlyphPositionAdjustments::getBaseOffset(le_int32 index) const
+{
+    return fAdjustments[index].getBaseOffset();
+}
+
+inline void GlyphPositionAdjustments::setXPlacement(le_int32 index, float newXPlacement)
+{
+    fAdjustments[index].setXPlacement(newXPlacement);
+}
+
+inline void GlyphPositionAdjustments::setYPlacement(le_int32 index, float newYPlacement)
+{
+    fAdjustments[index].setYPlacement(newYPlacement);
+}
+
+inline void GlyphPositionAdjustments::setXAdvance(le_int32 index, float newXAdvance)
+{
+    fAdjustments[index].setXAdvance(newXAdvance);
+}
+
+inline void GlyphPositionAdjustments::setYAdvance(le_int32 index, float newYAdvance)
+{
+    fAdjustments[index].setYAdvance(newYAdvance);
+}
+
+inline void GlyphPositionAdjustments::setBaseOffset(le_int32 index, le_int32 newBaseOffset)
+{
+    fAdjustments[index].setBaseOffset(newBaseOffset);
+}
+
+inline void GlyphPositionAdjustments::adjustXPlacement(le_int32 index, float xAdjustment)
+{
+    fAdjustments[index].adjustXPlacement(xAdjustment);
+}
+
+inline void GlyphPositionAdjustments::adjustYPlacement(le_int32 index, float yAdjustment)
+{
+    fAdjustments[index].adjustYPlacement(yAdjustment);
+}
+
+inline void GlyphPositionAdjustments::adjustXAdvance(le_int32 index, float xAdjustment)
+{
+    fAdjustments[index].adjustXAdvance(xAdjustment);
+}
+
+inline void GlyphPositionAdjustments::adjustYAdvance(le_int32 index, float yAdjustment)
+{
+    fAdjustments[index].adjustYAdvance(yAdjustment);
+}
+
+inline le_bool GlyphPositionAdjustments::hasCursiveGlyphs() const
+{
+    return fEntryExitPoints != NULL;
+}
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/GlyphPositioningTables.cpp b/source/layout/GlyphPositioningTables.cpp
new file mode 100644
index 0000000..b973fb7
--- /dev/null
+++ b/source/layout/GlyphPositioningTables.cpp
@@ -0,0 +1,38 @@
+/*
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "Lookups.h"
+#include "GlyphDefinitionTables.h"
+#include "GlyphPositioningTables.h"
+#include "GlyphPosnLookupProc.h"
+#include "CursiveAttachmentSubtables.h"
+#include "LEGlyphStorage.h"
+#include "GlyphPositionAdjustments.h"
+
+U_NAMESPACE_BEGIN
+
+void GlyphPositioningTableHeader::process(LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments, le_bool rightToLeft,
+                                          LETag scriptTag, LETag languageTag,
+                                          const GlyphDefinitionTableHeader *glyphDefinitionTableHeader, LEErrorCode &success,
+                                          const LEFontInstance *fontInstance, const FeatureMap *featureMap, le_int32 featureMapCount, le_bool featureOrder) const
+{
+    if (LE_FAILURE(success)) {
+        return;
+    } 
+
+    GlyphPositioningLookupProcessor processor(this, scriptTag, languageTag, featureMap, featureMapCount, featureOrder, success);
+    if (LE_FAILURE(success)) {
+        return;
+    } 
+
+    processor.process(glyphStorage, glyphPositionAdjustments, rightToLeft, glyphDefinitionTableHeader, fontInstance, success);
+
+    glyphPositionAdjustments->applyCursiveAdjustments(glyphStorage, rightToLeft, fontInstance);
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/GlyphPositioningTables.h b/source/layout/GlyphPositioningTables.h
new file mode 100644
index 0000000..590488c
--- /dev/null
+++ b/source/layout/GlyphPositioningTables.h
@@ -0,0 +1,51 @@
+/*
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#ifndef __GLYPHPOSITIONINGTABLES_H
+#define __GLYPHPOSITIONINGTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "Lookups.h"
+#include "GlyphLookupTables.h"
+
+U_NAMESPACE_BEGIN
+
+class  LEFontInstance;
+class  LEGlyphStorage;
+class  LEGlyphFilter;
+class  GlyphPositionAdjustments;
+struct GlyphDefinitionTableHeader;
+
+struct GlyphPositioningTableHeader : public GlyphLookupTableHeader
+{
+    void    process(LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments,
+                le_bool rightToLeft, LETag scriptTag, LETag languageTag,
+                const GlyphDefinitionTableHeader *glyphDefinitionTableHeader, LEErrorCode &success,
+                const LEFontInstance *fontInstance, const FeatureMap *featureMap, le_int32 featureMapCount, le_bool featureOrder) const;
+};
+
+enum GlyphPositioningSubtableTypes
+{
+    gpstSingle          = 1,
+    gpstPair            = 2,
+    gpstCursive         = 3,
+    gpstMarkToBase      = 4,
+    gpstMarkToLigature  = 5,
+    gpstMarkToMark      = 6,
+    gpstContext         = 7,
+    gpstChainedContext  = 8,
+    gpstExtension       = 9
+};
+
+typedef LookupSubtable GlyphPositioningSubtable;
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/GlyphPosnLookupProc.cpp b/source/layout/GlyphPosnLookupProc.cpp
new file mode 100644
index 0000000..de32514
--- /dev/null
+++ b/source/layout/GlyphPosnLookupProc.cpp
@@ -0,0 +1,161 @@
+/*
+ * (C) Copyright IBM Corp. 1998 - 2010 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "ICUFeatures.h"
+#include "Lookups.h"
+#include "ScriptAndLanguage.h"
+#include "GlyphDefinitionTables.h"
+#include "GlyphPositioningTables.h"
+#include "SinglePositioningSubtables.h"
+#include "PairPositioningSubtables.h"
+#include "CursiveAttachmentSubtables.h"
+#include "MarkToBasePosnSubtables.h"
+#include "MarkToLigaturePosnSubtables.h"
+#include "MarkToMarkPosnSubtables.h"
+//#include "ContextualPositioningSubtables.h"
+#include "ContextualSubstSubtables.h"
+#include "ExtensionSubtables.h"
+#include "LookupProcessor.h"
+#include "GlyphPosnLookupProc.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+// Aside from the names, the contextual positioning subtables are
+// the same as the contextual substitution subtables.
+typedef ContextualSubstitutionSubtable ContextualPositioningSubtable;
+typedef ChainingContextualSubstitutionSubtable ChainingContextualPositioningSubtable;
+
+GlyphPositioningLookupProcessor::GlyphPositioningLookupProcessor(
+        const GlyphPositioningTableHeader *glyphPositioningTableHeader,
+        LETag scriptTag, 
+        LETag languageTag, 
+        const FeatureMap *featureMap, 
+        le_int32 featureMapCount, 
+        le_bool featureOrder,
+        LEErrorCode& success)
+    : LookupProcessor(
+                      (char *) glyphPositioningTableHeader,
+                      SWAPW(glyphPositioningTableHeader->scriptListOffset),
+                      SWAPW(glyphPositioningTableHeader->featureListOffset),
+                      SWAPW(glyphPositioningTableHeader->lookupListOffset),
+                      scriptTag, 
+                      languageTag, 
+                      featureMap, 
+                      featureMapCount, 
+                      featureOrder,
+                      success
+                      )
+{
+    // anything?
+}
+
+GlyphPositioningLookupProcessor::GlyphPositioningLookupProcessor()
+{
+}
+
+le_uint32 GlyphPositioningLookupProcessor::applySubtable(const LookupSubtable *lookupSubtable, le_uint16 lookupType,
+                                                       GlyphIterator *glyphIterator,
+                                                       const LEFontInstance *fontInstance,
+                                                       LEErrorCode& success) const
+{
+    if (LE_FAILURE(success)) { 
+        return 0;
+    } 
+
+    le_uint32 delta = 0;
+
+    switch(lookupType)
+    {
+    case 0:
+        break;
+
+    case gpstSingle:
+    {
+        const SinglePositioningSubtable *subtable = (const SinglePositioningSubtable *) lookupSubtable;
+
+        delta = subtable->process(glyphIterator, fontInstance);
+        break;
+    }
+
+    case gpstPair:
+    {
+        const PairPositioningSubtable *subtable = (const PairPositioningSubtable *) lookupSubtable;
+
+        delta = subtable->process(glyphIterator, fontInstance);
+        break;
+    }
+
+    case gpstCursive:
+    {
+        const CursiveAttachmentSubtable *subtable = (const CursiveAttachmentSubtable *) lookupSubtable;
+
+        delta = subtable->process(glyphIterator, fontInstance);
+        break;
+    }
+
+    case gpstMarkToBase:
+    {
+        const MarkToBasePositioningSubtable *subtable = (const MarkToBasePositioningSubtable *) lookupSubtable;
+
+        delta = subtable->process(glyphIterator, fontInstance);
+        break;
+    }
+
+     case gpstMarkToLigature:
+    {
+        const MarkToLigaturePositioningSubtable *subtable = (const MarkToLigaturePositioningSubtable *) lookupSubtable;
+
+        delta = subtable->process(glyphIterator, fontInstance);
+        break;
+    }
+
+    case gpstMarkToMark:
+    {
+        const MarkToMarkPositioningSubtable *subtable = (const MarkToMarkPositioningSubtable *) lookupSubtable;
+
+        delta = subtable->process(glyphIterator, fontInstance);
+        break;
+    }
+
+   case gpstContext:
+    {
+        const ContextualPositioningSubtable *subtable = (const ContextualPositioningSubtable *) lookupSubtable;
+
+        delta = subtable->process(this, glyphIterator, fontInstance, success);
+        break;
+    }
+
+    case gpstChainedContext:
+    {
+        const ChainingContextualPositioningSubtable *subtable = (const ChainingContextualPositioningSubtable *) lookupSubtable;
+
+        delta = subtable->process(this, glyphIterator, fontInstance, success);
+        break;
+    }
+
+    case gpstExtension:
+    {
+        const ExtensionSubtable *subtable = (const ExtensionSubtable *) lookupSubtable;
+
+        delta = subtable->process(this, lookupType, glyphIterator, fontInstance, success);
+        break;
+    }
+
+    default:
+        break;
+    }
+
+    return delta;
+}
+
+GlyphPositioningLookupProcessor::~GlyphPositioningLookupProcessor()
+{
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/GlyphPosnLookupProc.h b/source/layout/GlyphPosnLookupProc.h
new file mode 100644
index 0000000..b251137
--- /dev/null
+++ b/source/layout/GlyphPosnLookupProc.h
@@ -0,0 +1,52 @@
+/*
+ * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved
+ *
+ */
+
+#ifndef __GLYPHPOSITIONINGLOOKUPPROCESSOR_H
+#define __GLYPHPOSITIONINGLOOKUPPROCESSOR_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "Lookups.h"
+#include "ICUFeatures.h"
+#include "GlyphDefinitionTables.h"
+#include "GlyphPositioningTables.h"
+#include "GlyphIterator.h"
+#include "LookupProcessor.h"
+
+U_NAMESPACE_BEGIN
+
+class GlyphPositioningLookupProcessor : public LookupProcessor
+{
+public:
+    GlyphPositioningLookupProcessor(const GlyphPositioningTableHeader *glyphPositioningTableHeader,
+        LETag scriptTag, 
+        LETag languageTag, 
+        const FeatureMap *featureMap, 
+        le_int32 featureMapCount, 
+        le_bool featureOrder,
+        LEErrorCode& success);
+
+    virtual ~GlyphPositioningLookupProcessor();
+
+    virtual le_uint32 applySubtable(const LookupSubtable *lookupSubtable, le_uint16 lookupType, GlyphIterator *glyphIterator,
+        const LEFontInstance *fontInstance, LEErrorCode& success) const;
+
+protected:
+    GlyphPositioningLookupProcessor();
+
+private:
+
+    GlyphPositioningLookupProcessor(const GlyphPositioningLookupProcessor &other); // forbid copying of this class
+    GlyphPositioningLookupProcessor &operator=(const GlyphPositioningLookupProcessor &other); // forbid copying of this class
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/GlyphSubstLookupProc.cpp b/source/layout/GlyphSubstLookupProc.cpp
new file mode 100644
index 0000000..195de9d
--- /dev/null
+++ b/source/layout/GlyphSubstLookupProc.cpp
@@ -0,0 +1,132 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEGlyphFilter.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "ICUFeatures.h"
+#include "Lookups.h"
+#include "ScriptAndLanguage.h"
+#include "GlyphDefinitionTables.h"
+#include "GlyphSubstitutionTables.h"
+#include "SingleSubstitutionSubtables.h"
+#include "MultipleSubstSubtables.h"
+#include "AlternateSubstSubtables.h"
+#include "LigatureSubstSubtables.h"
+#include "ContextualSubstSubtables.h"
+#include "ExtensionSubtables.h"
+#include "LookupProcessor.h"
+#include "GlyphSubstLookupProc.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+GlyphSubstitutionLookupProcessor::GlyphSubstitutionLookupProcessor(
+        const GlyphSubstitutionTableHeader *glyphSubstitutionTableHeader,
+        LETag scriptTag, 
+        LETag languageTag, 
+        const LEGlyphFilter *filter, 
+        const FeatureMap *featureMap, 
+        le_int32 featureMapCount, 
+        le_bool featureOrder,
+        LEErrorCode& success)
+    : LookupProcessor(
+                      (char *) glyphSubstitutionTableHeader,
+                      SWAPW(glyphSubstitutionTableHeader->scriptListOffset),
+                      SWAPW(glyphSubstitutionTableHeader->featureListOffset),
+                      SWAPW(glyphSubstitutionTableHeader->lookupListOffset),
+                      scriptTag, languageTag, featureMap, featureMapCount, featureOrder, success), fFilter(filter)
+{
+    // anything?
+}
+
+GlyphSubstitutionLookupProcessor::GlyphSubstitutionLookupProcessor()
+{
+}
+
+le_uint32 GlyphSubstitutionLookupProcessor::applySubtable(const LookupSubtable *lookupSubtable, le_uint16 lookupType,
+                                                       GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    le_uint32 delta = 0;
+
+    switch(lookupType)
+    {
+    case 0:
+        break;
+
+    case gsstSingle:
+    {
+        const SingleSubstitutionSubtable *subtable = (const SingleSubstitutionSubtable *) lookupSubtable;
+
+        delta = subtable->process(glyphIterator, fFilter);
+        break;
+    }
+
+    case gsstMultiple:
+    {
+        const MultipleSubstitutionSubtable *subtable = (const MultipleSubstitutionSubtable *) lookupSubtable;
+
+        delta = subtable->process(glyphIterator, success, fFilter);
+        break;
+    }
+
+    case gsstAlternate:
+    {
+        const AlternateSubstitutionSubtable *subtable = (const AlternateSubstitutionSubtable *) lookupSubtable;
+
+        delta = subtable->process(glyphIterator, fFilter);
+        break;
+    }
+
+    case gsstLigature:
+    {
+        const LigatureSubstitutionSubtable *subtable = (const LigatureSubstitutionSubtable *) lookupSubtable;
+
+        delta = subtable->process(glyphIterator, fFilter);
+        break;
+    }
+
+    case gsstContext:
+    {
+        const ContextualSubstitutionSubtable *subtable = (const ContextualSubstitutionSubtable *) lookupSubtable;
+
+        delta = subtable->process(this, glyphIterator, fontInstance, success);
+        break;
+    }
+
+    case gsstChainingContext:
+    {
+        const ChainingContextualSubstitutionSubtable *subtable = (const ChainingContextualSubstitutionSubtable *) lookupSubtable;
+
+        delta = subtable->process(this, glyphIterator, fontInstance, success);
+        break;
+    }
+
+    case gsstExtension:
+    {
+        const ExtensionSubtable *subtable = (const ExtensionSubtable *) lookupSubtable;
+
+        delta = subtable->process(this, lookupType, glyphIterator, fontInstance, success);
+        break;
+    }
+
+    default:
+        break;
+    }
+
+    return delta;
+}
+
+GlyphSubstitutionLookupProcessor::~GlyphSubstitutionLookupProcessor()
+{
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/GlyphSubstLookupProc.h b/source/layout/GlyphSubstLookupProc.h
new file mode 100644
index 0000000..ef04db2
--- /dev/null
+++ b/source/layout/GlyphSubstLookupProc.h
@@ -0,0 +1,55 @@
+/*
+ * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved
+ *
+ */
+
+#ifndef __GLYPHSUBSTITUTIONLOOKUPPROCESSOR_H
+#define __GLYPHSUBSTITUTIONLOOKUPPROCESSOR_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEGlyphFilter.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "Lookups.h"
+#include "ICUFeatures.h"
+#include "GlyphDefinitionTables.h"
+#include "GlyphSubstitutionTables.h"
+#include "GlyphIterator.h"
+#include "LookupProcessor.h"
+
+U_NAMESPACE_BEGIN
+
+class GlyphSubstitutionLookupProcessor : public LookupProcessor
+{
+public:
+    GlyphSubstitutionLookupProcessor(const GlyphSubstitutionTableHeader *glyphSubstitutionTableHeader,
+        LETag scriptTag, 
+        LETag languageTag, 
+        const LEGlyphFilter *filter, 
+        const FeatureMap *featureMap, 
+        le_int32 featureMapCount, 
+        le_bool featureOrder,
+        LEErrorCode& success);
+
+    virtual ~GlyphSubstitutionLookupProcessor();
+
+    virtual le_uint32 applySubtable(const LookupSubtable *lookupSubtable, le_uint16 lookupType, GlyphIterator *glyphIterator,
+        const LEFontInstance *fontInstance, LEErrorCode& success) const;
+
+protected:
+    GlyphSubstitutionLookupProcessor();
+
+private:
+    const LEGlyphFilter *fFilter;
+
+    GlyphSubstitutionLookupProcessor(const GlyphSubstitutionLookupProcessor &other); // forbid copying of this class
+    GlyphSubstitutionLookupProcessor &operator=(const GlyphSubstitutionLookupProcessor &other); // forbid copying of this class
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/GlyphSubstitutionTables.cpp b/source/layout/GlyphSubstitutionTables.cpp
new file mode 100644
index 0000000..bdd8127
--- /dev/null
+++ b/source/layout/GlyphSubstitutionTables.cpp
@@ -0,0 +1,39 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEGlyphFilter.h"
+#include "OpenTypeTables.h"
+#include "Lookups.h"
+#include "GlyphDefinitionTables.h"
+#include "GlyphSubstitutionTables.h"
+#include "GlyphSubstLookupProc.h"
+#include "ScriptAndLanguage.h"
+#include "LEGlyphStorage.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+le_int32 GlyphSubstitutionTableHeader::process(LEGlyphStorage &glyphStorage,
+                                               le_bool rightToLeft, 
+                                               LETag scriptTag, 
+                                               LETag languageTag,
+                                               const GlyphDefinitionTableHeader *glyphDefinitionTableHeader, 
+                                               const LEGlyphFilter *filter, 
+                                               const FeatureMap *featureMap, 
+                                               le_int32 featureMapCount, 
+                                               le_bool featureOrder,
+                                               LEErrorCode &success) const
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    } 
+
+    GlyphSubstitutionLookupProcessor processor(this, scriptTag, languageTag, filter, featureMap, featureMapCount, featureOrder, success);
+    return processor.process(glyphStorage, NULL, rightToLeft, glyphDefinitionTableHeader, NULL, success);
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/GlyphSubstitutionTables.h b/source/layout/GlyphSubstitutionTables.h
new file mode 100644
index 0000000..b899bee
--- /dev/null
+++ b/source/layout/GlyphSubstitutionTables.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#ifndef __GLYPHSUBSTITUTIONTABLES_H
+#define __GLYPHSUBSTITUTIONTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "Lookups.h"
+#include "GlyphLookupTables.h"
+
+U_NAMESPACE_BEGIN
+
+class  LEGlyphStorage;
+class  LEGlyphFilter;
+struct GlyphDefinitionTableHeader;
+
+struct GlyphSubstitutionTableHeader : public GlyphLookupTableHeader
+{
+    le_int32    process(LEGlyphStorage &glyphStorage, 
+                        le_bool rightToLeft, 
+                        LETag scriptTag, 
+                        LETag languageTag,
+                        const GlyphDefinitionTableHeader *glyphDefinitionTableHeader, 
+                        const LEGlyphFilter *filter,
+                        const FeatureMap *featureMap, 
+                        le_int32 featureMapCount, 
+                        le_bool featureOrder,
+                        LEErrorCode &success) const;
+};
+
+enum GlyphSubstitutionSubtableTypes
+{
+    gsstSingle          = 1,
+    gsstMultiple        = 2,
+    gsstAlternate       = 3,
+    gsstLigature        = 4,
+    gsstContext         = 5,
+    gsstChainingContext = 6,
+    gsstExtension       = 7,
+    gsstReverseChaining = 8
+};
+
+typedef LookupSubtable GlyphSubstitutionSubtable;
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/HanLayoutEngine.cpp b/source/layout/HanLayoutEngine.cpp
new file mode 100644
index 0000000..31dc818
--- /dev/null
+++ b/source/layout/HanLayoutEngine.cpp
@@ -0,0 +1,84 @@
+/*
+ * HanLayoutEngine.cpp: OpenType processing for Han fonts.
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved.
+ */
+
+#include "LETypes.h"
+#include "LEScripts.h"
+#include "LELanguages.h"
+
+#include "LayoutEngine.h"
+#include "OpenTypeLayoutEngine.h"
+#include "HanLayoutEngine.h"
+#include "ScriptAndLanguageTags.h"
+#include "LEGlyphStorage.h"
+#include "OpenTypeTables.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(HanOpenTypeLayoutEngine)
+
+#define loclFeatureTag LE_LOCL_FEATURE_TAG
+#define smplFeatureTag LE_SMPL_FEATURE_TAG
+#define tradFeatureTag LE_TRAD_FEATURE_TAG
+
+#define loclFeatureMask 0x80000000UL
+#define smplFeatureMask 0x40000000UL
+#define tradFeatureMask 0x20000000UL
+
+static const FeatureMap featureMap[] =
+{
+    {loclFeatureTag, loclFeatureMask},
+    {smplFeatureTag, smplFeatureMask},
+    {tradFeatureTag, tradFeatureMask}
+};
+
+static const le_int32 featureMapCount = LE_ARRAY_SIZE(featureMap);
+
+#define features (loclFeatureMask)
+
+HanOpenTypeLayoutEngine::HanOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+                        le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success)
+    : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success)
+{
+    fFeatureMap      = featureMap;
+    fFeatureMapCount = featureMapCount;
+}
+
+HanOpenTypeLayoutEngine::~HanOpenTypeLayoutEngine()
+{
+    // nothing to do
+}
+
+le_int32 HanOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool /*rightToLeft*/,
+        LEUnicode *&/*outChars*/, LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    glyphStorage.allocateGlyphArray(count, FALSE, success);
+    glyphStorage.allocateAuxData(success);
+
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    // FIXME: do we want to add the 'trad' feature for 'ZHT' and the
+    // 'smpl' feature for 'ZHS'? If we do this, we can remove the exact
+    // flag from the language tag lookups, so we can use these features
+    // with the default LangSys...
+    for (le_int32 i = 0; i < count; i += 1) {
+        glyphStorage.setAuxData(i, features, success);
+    }
+
+    return count;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/HanLayoutEngine.h b/source/layout/HanLayoutEngine.h
new file mode 100644
index 0000000..f02153b
--- /dev/null
+++ b/source/layout/HanLayoutEngine.h
@@ -0,0 +1,105 @@
+
+/*
+ * HanLayoutEngine.h: OpenType processing for Han fonts.
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved.
+ */
+
+#ifndef __HANLAYOUTENGINE_H
+#define __HANLAYOUTENGINE_H
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "LayoutEngine.h"
+#include "OpenTypeLayoutEngine.h"
+
+#include "GlyphSubstitutionTables.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+/**
+ * This class implements OpenType layout for Han fonts. It overrides
+ * the characerProcessing method to assign the correct OpenType feature
+ * tags for the CJK language-specific forms.
+ *
+ * @internal
+ */
+class HanOpenTypeLayoutEngine : public OpenTypeLayoutEngine
+{
+public:
+    /**
+     * This is the main constructor. It constructs an instance of HanOpenTypeLayoutEngine for
+     * a particular font, script and language. It takes the GSUB table as a parameter since
+     * LayoutEngine::layoutEngineFactory has to read the GSUB table to know that it has a
+     * Han OpenType font.
+     *
+     * @param fontInstance - the font
+     * @param scriptCode - the script
+     * @param langaugeCode - the language
+     * @param gsubTable - the GSUB table
+     * @param success - set to an error code if the operation fails
+     *
+     * @see LayoutEngine::layoutEngineFactory
+     * @see OpenTypeLayoutEngine
+     * @see ScriptAndLangaugeTags.h for script and language codes
+     *
+     * @internal
+     */
+    HanOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+                            le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTablem, LEErrorCode &success);
+
+
+    /**
+     * The destructor, virtual for correct polymorphic invocation.
+     *
+     * @internal
+     */
+    virtual ~HanOpenTypeLayoutEngine();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.8
+     */
+    static UClassID getStaticClassID();
+
+protected:
+
+    /**
+     * This method does Han OpenType character processing. It assigns the OpenType feature
+     * tags to the characters to generate the correct language-specific variants.
+     *
+     * Input parameters:
+     * @param chars - the input character context
+     * @param offset - the index of the first character to process
+     * @param count - the number of characters to process
+     * @param max - the number of characters in the input context
+     * @param rightToLeft - <code>TRUE</code> if the characters are in a right to left directional run
+     * @param glyphStorage - the object holding the glyph storage. The char index and auxillary data arrays will be set.
+     *
+     * Output parameters:
+     * @param outChars - the output character arrayt
+     * @param charIndices - the output character index array
+     * @param featureTags - the output feature tag array
+     * @param success - set to an error code if the operation fails
+     *
+     * @return the output character count
+     *
+     * @internal
+     */
+    virtual le_int32 characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+            LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/HangulLayoutEngine.cpp b/source/layout/HangulLayoutEngine.cpp
new file mode 100644
index 0000000..ad4731e
--- /dev/null
+++ b/source/layout/HangulLayoutEngine.cpp
@@ -0,0 +1,338 @@
+/*
+ * HangulLayoutEngine.cpp: OpenType processing for Han fonts.
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved.
+ */
+
+#include "LETypes.h"
+#include "LEScripts.h"
+#include "LELanguages.h"
+
+#include "LayoutEngine.h"
+#include "OpenTypeLayoutEngine.h"
+#include "HangulLayoutEngine.h"
+#include "ScriptAndLanguageTags.h"
+#include "LEGlyphStorage.h"
+#include "OpenTypeTables.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(HangulOpenTypeLayoutEngine)
+
+
+#define FEATURE_MAP(name) {name ## FeatureTag, name ## FeatureMask}
+
+#define LJMO_FIRST 0x1100
+#define LJMO_LAST  0x1159
+#define LJMO_FILL  0x115F
+#define LJMO_COUNT 19
+
+#define VJMO_FIRST 0x1161
+#define VJMO_LAST  0x11A2
+#define VJMO_FILL  0x1160
+#define VJMO_COUNT 21
+
+#define TJMO_FIRST 0x11A7
+#define TJMO_LAST  0x11F9
+#define TJMO_COUNT 28
+
+#define HSYL_FIRST 0xAC00
+#define HSYL_COUNT 11172
+#define HSYL_LVCNT (VJMO_COUNT * TJMO_COUNT)
+
+// Character classes
+enum
+{
+    CC_L = 0,
+    CC_V,
+    CC_T,
+    CC_LV,
+    CC_LVT,
+    CC_X,
+    CC_COUNT
+};
+
+// Action flags
+#define AF_L 1
+#define AF_V 2
+#define AF_T 4
+
+// Actions
+#define a_N   0
+#define a_L   (AF_L)
+#define a_V   (AF_V)
+#define a_T   (AF_T)
+#define a_VT  (AF_V | AF_T)
+#define a_LV  (AF_L | AF_V)
+#define a_LVT (AF_L | AF_V | AF_T)
+
+typedef struct
+{
+    int32_t newState;
+    int32_t actionFlags;
+} StateTransition;
+
+static const StateTransition stateTable[][CC_COUNT] =
+{
+//       L          V          T          LV         LVT           X
+    { {1, a_L},  {2, a_LV}, {3, a_LVT}, {2, a_LV}, {3, a_LVT},  {4, a_T}}, // 0 - start
+    { {1, a_L},  {2, a_V},  {3, a_VT},  {2, a_LV}, {3, a_LVT}, {-1, a_V}}, // 1 - L+
+    {{-1, a_N},  {2, a_V},  {3, a_T},  {-1, a_N}, {-1, a_N},   {-1, a_N}}, // 2 - L+V+
+    {{-1, a_N}, {-1, a_N},  {3, a_T},  {-1, a_N}, {-1, a_N},   {-1, a_N}}, // 3 - L+V+T*
+    {{-1, a_N}, {-1, a_N}, {-1, a_N},  {-1, a_N}, {-1, a_N},    {4, a_T}}  // 4 - X+
+};
+
+
+#define ccmpFeatureTag LE_CCMP_FEATURE_TAG
+#define ljmoFeatureTag LE_LJMO_FEATURE_TAG
+#define vjmoFeatureTag LE_VJMO_FEATURE_TAG
+#define tjmoFeatureTag LE_TJMO_FEATURE_TAG
+
+#define ccmpFeatureMask 0x80000000UL
+#define ljmoFeatureMask 0x40000000UL
+#define vjmoFeatureMask 0x20000000UL
+#define tjmoFeatureMask 0x10000000UL
+
+static const FeatureMap featureMap[] =
+{
+    {ccmpFeatureTag, ccmpFeatureMask},
+    {ljmoFeatureTag, ljmoFeatureMask},
+    {vjmoFeatureTag, vjmoFeatureMask},
+    {tjmoFeatureTag, tjmoFeatureMask}
+};
+
+static const le_int32 featureMapCount = LE_ARRAY_SIZE(featureMap);
+
+#define nullFeatures 0
+#define ljmoFeatures (ccmpFeatureMask | ljmoFeatureMask)
+#define vjmoFeatures (ccmpFeatureMask | vjmoFeatureMask | ljmoFeatureMask | tjmoFeatureMask)
+#define tjmoFeatures (ccmpFeatureMask | tjmoFeatureMask | ljmoFeatureMask | vjmoFeatureMask)
+
+static le_int32 compose(LEUnicode lead, LEUnicode vowel, LEUnicode trail, LEUnicode &syllable)
+{
+    le_int32 lIndex = lead  - LJMO_FIRST;
+    le_int32 vIndex = vowel - VJMO_FIRST;
+    le_int32 tIndex = trail - TJMO_FIRST;
+    le_int32 result = 3;
+
+    if ((lIndex < 0 || lIndex >= LJMO_COUNT ) || (vIndex < 0 || vIndex >= VJMO_COUNT)) {
+        return 0;
+    }
+
+    if (tIndex <= 0 || tIndex >= TJMO_COUNT) {
+        tIndex = 0;
+        result = 2;
+    }
+
+    syllable = (LEUnicode) ((lIndex * VJMO_COUNT + vIndex) * TJMO_COUNT + tIndex + HSYL_FIRST);
+
+    return result;
+}
+
+static le_int32 decompose(LEUnicode syllable, LEUnicode &lead, LEUnicode &vowel, LEUnicode &trail)
+{
+    le_int32 sIndex = syllable - HSYL_FIRST;
+
+    if (sIndex < 0 || sIndex >= HSYL_COUNT) {
+        return 0;
+    }
+
+    lead  = LJMO_FIRST + (sIndex / HSYL_LVCNT);
+    vowel = VJMO_FIRST + (sIndex % HSYL_LVCNT) / TJMO_COUNT;
+    trail = TJMO_FIRST + (sIndex % TJMO_COUNT);
+
+    if (trail == TJMO_FIRST) {
+        return 2;
+    }
+
+    return 3;
+}
+
+static le_int32 getCharClass(LEUnicode ch, LEUnicode &lead, LEUnicode &vowel, LEUnicode &trail)
+{
+    lead  = LJMO_FILL;
+    vowel = VJMO_FILL;
+    trail = TJMO_FIRST;
+
+    if (ch >= LJMO_FIRST && ch <= LJMO_LAST) {
+        lead  = ch;
+        return CC_L;
+    }
+
+    if (ch >= VJMO_FIRST && ch <= VJMO_LAST) {
+        vowel = ch;
+        return CC_V;
+    }
+
+    if (ch > TJMO_FIRST && ch <= TJMO_LAST) {
+        trail = ch;
+        return CC_T;
+    }
+
+    le_int32 c = decompose(ch, lead, vowel, trail);
+
+    if (c == 2) {
+        return CC_LV;
+    }
+
+    if (c == 3) {
+        return CC_LVT;
+    }
+
+    trail = ch;
+    return CC_X;
+}
+
+HangulOpenTypeLayoutEngine::HangulOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 /*languageCode*/,
+                                       le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success)
+    : OpenTypeLayoutEngine(fontInstance, scriptCode, korLanguageCode, typoFlags, gsubTable, success)
+{
+    fFeatureMap = featureMap;
+    fFeatureMapCount = featureMapCount;
+    fFeatureOrder = TRUE;
+}
+
+HangulOpenTypeLayoutEngine::HangulOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 /*languageCode*/,
+			                                   le_int32 typoFlags, LEErrorCode &success)
+    : OpenTypeLayoutEngine(fontInstance, scriptCode, korLanguageCode, typoFlags, success)
+{
+    fFeatureMap = featureMap;
+    fFeatureMapCount = featureMapCount;
+    fFeatureOrder = TRUE;
+}
+
+HangulOpenTypeLayoutEngine::~HangulOpenTypeLayoutEngine()
+{
+    // nothing to do
+}
+
+le_int32 HangulOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+        LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    le_int32 worstCase = count * 3;
+
+    outChars = LE_NEW_ARRAY(LEUnicode, worstCase);
+
+    if (outChars == NULL) {
+        success = LE_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
+
+    glyphStorage.allocateGlyphArray(worstCase, rightToLeft, success);
+    glyphStorage.allocateAuxData(success);
+
+    if (LE_FAILURE(success)) {
+        LE_DELETE_ARRAY(outChars);
+        return 0;
+    }
+
+    le_int32 outCharCount = 0;
+    le_int32 limit = offset + count;
+    le_int32 i = offset;
+
+    while (i < limit) {
+        le_int32 state    = 0;
+        le_int32 inStart  = i;
+        le_int32 outStart = outCharCount;
+
+        while( i < limit) {
+            LEUnicode lead  = 0;
+            LEUnicode vowel = 0;
+            LEUnicode trail = 0;
+            int32_t chClass = getCharClass(chars[i], lead, vowel, trail);
+            const StateTransition transition = stateTable[state][chClass];
+
+            if (chClass == CC_X) {
+                /* Any character of type X will be stored as a trail jamo */
+                if ((transition.actionFlags & AF_T) != 0) {
+                    outChars[outCharCount] = trail;
+                    glyphStorage.setCharIndex(outCharCount, i-offset, success);
+                    glyphStorage.setAuxData(outCharCount++, nullFeatures, success);
+                }
+            } else {
+                /* Any Hangul will be fully decomposed. Output the decomposed characters. */
+                if ((transition.actionFlags & AF_L) != 0) {
+                    outChars[outCharCount] = lead;
+                    glyphStorage.setCharIndex(outCharCount, i-offset, success);
+                    glyphStorage.setAuxData(outCharCount++, ljmoFeatures, success);
+                }
+
+                if ((transition.actionFlags & AF_V) != 0) {
+                    outChars[outCharCount] = vowel;
+                    glyphStorage.setCharIndex(outCharCount, i-offset, success);
+                    glyphStorage.setAuxData(outCharCount++, vjmoFeatures, success);
+                }
+
+                if ((transition.actionFlags & AF_T) != 0) {
+                    outChars[outCharCount] = trail;
+                    glyphStorage.setCharIndex(outCharCount, i-offset, success);
+                    glyphStorage.setAuxData(outCharCount++, tjmoFeatures, success);
+                }
+            }
+
+            state = transition.newState;
+
+            /* Negative next state means stop. */
+            if (state < 0) {
+                break;
+            }
+
+            i += 1;
+        }
+
+        le_int32 inLength  = i - inStart;
+        le_int32 outLength = outCharCount - outStart;
+
+        /*
+         * See if the syllable can be composed into a single character. There are 5
+         * possible cases:
+         *
+         *   Input     Decomposed to    Compose to
+         *   LV        L, V             LV
+         *   LVT       L, V, T          LVT
+         *   L, V      L, V             LV, DEL
+         *   LV, T     L, V, T          LVT, DEL
+         *   L, V, T   L, V, T          LVT, DEL, DEL
+         */
+        if ((inLength >= 1 && inLength <= 3) && (outLength == 2 || outLength == 3)) {
+            LEUnicode syllable = 0x0000;
+            LEUnicode lead  = outChars[outStart];
+            LEUnicode vowel = outChars[outStart + 1];
+            LEUnicode trail = outLength == 3? outChars[outStart + 2] : TJMO_FIRST;
+
+            /*
+             * If the composition consumes the whole decomposed syllable,
+             * we can use it.
+             */
+            if (compose(lead, vowel, trail, syllable) == outLength) {
+                outCharCount = outStart;
+                outChars[outCharCount] = syllable;
+                glyphStorage.setCharIndex(outCharCount, inStart-offset, success);
+                glyphStorage.setAuxData(outCharCount++, nullFeatures, success);
+
+                /*
+                 * Replace the rest of the input characters with DEL.
+                 */
+                for(le_int32 d = inStart + 1; d < i; d += 1) {
+                    outChars[outCharCount] = 0xFFFF;
+                    glyphStorage.setCharIndex(outCharCount, d - offset, success);
+                    glyphStorage.setAuxData(outCharCount++, nullFeatures, success);
+                }
+            }
+        }
+    }
+
+    glyphStorage.adoptGlyphCount(outCharCount);
+    return outCharCount;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/HangulLayoutEngine.h b/source/layout/HangulLayoutEngine.h
new file mode 100644
index 0000000..70a46c4
--- /dev/null
+++ b/source/layout/HangulLayoutEngine.h
@@ -0,0 +1,127 @@
+
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#ifndef __HANGULAYOUTENGINE_H
+#define __HANGULAYOUTENGINE_H
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "LEGlyphFilter.h"
+#include "LayoutEngine.h"
+#include "OpenTypeLayoutEngine.h"
+
+#include "GlyphSubstitutionTables.h"
+#include "GlyphDefinitionTables.h"
+#include "GlyphPositioningTables.h"
+
+U_NAMESPACE_BEGIN
+
+class MPreFixups;
+class LEGlyphStorage;
+
+/**
+ * This class implements OpenType layout for Old Hangul OpenType fonts, as
+ * specified by Microsoft in "Creating and Supporting OpenType Fonts for
+ * The Korean Hangul Script" (http://www.microsoft.com/typography/otfntdev/hangulot/default.htm)
+ *
+ * This class overrides the characterProcessing method to do Hangul character processing.
+ * (See the MS spec. for more details)
+ *
+ * @internal
+ */
+class HangulOpenTypeLayoutEngine : public OpenTypeLayoutEngine
+{
+public:
+    /**
+     * This is the main constructor. It constructs an instance of HangulOpenTypeLayoutEngine for
+     * a particular font, script and language. It takes the GSUB table as a parameter since
+     * LayoutEngine::layoutEngineFactory has to read the GSUB table to know that it has an
+     * Hangul OpenType font.
+     *
+     * @param fontInstance - the font
+     * @param scriptCode - the script
+     * @param langaugeCode - the language
+     * @param gsubTable - the GSUB table
+     * @param success - set to an error code if the operation fails
+     *
+     * @see LayoutEngine::layoutEngineFactory
+     * @see OpenTypeLayoutEngine
+     * @see ScriptAndLangaugeTags.h for script and language codes
+     *
+     * @internal
+     */
+    HangulOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+                            le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success);
+
+    /**
+     * This constructor is used when the font requires a "canned" GSUB table which can't be known
+     * until after this constructor has been invoked.
+     *
+     * @param fontInstance - the font
+     * @param scriptCode - the script
+     * @param langaugeCode - the language
+     * @param success - set to an error code if the operation fails
+     *
+     * @see OpenTypeLayoutEngine
+     * @see ScriptAndLangaugeTags.h for script and language codes
+     *
+     * @internal
+     */
+    HangulOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+			      le_int32 typoFlags, LEErrorCode &success);
+
+    /**
+     * The destructor, virtual for correct polymorphic invocation.
+     *
+     * @internal
+     */
+   virtual ~HangulOpenTypeLayoutEngine();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.8
+     */
+    static UClassID getStaticClassID();
+
+protected:
+
+    /**
+     * This method does Hangul OpenType character processing. It assigns the OpenType feature
+     * tags to the characters, and may compose a character sequence into a modern Hangul syllable,
+     * or decompose a modern Hangul syllable if it forms part of an old Hangul syllable.
+     *
+     * Input parameters:
+     * @param chars - the input character context
+     * @param offset - the index of the first character to process
+     * @param count - the number of characters to process
+     * @param max - the number of characters in the input context
+     * @param rightToLeft - <code>TRUE</code> if the characters are in a right to left directional run
+     * @param glyphStorage - the glyph storage object. The glyph and character index arrays will be set.
+     *                       the auxillary data array will be set to the feature tags.
+     *
+     * Output parameters:
+     * @param success - set to an error code if the operation fails
+     *
+     * @return the output character count
+     *
+     * @internal
+     */
+    virtual le_int32 characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+            LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/ICUFeatures.h b/source/layout/ICUFeatures.h
new file mode 100644
index 0000000..4d93866
--- /dev/null
+++ b/source/layout/ICUFeatures.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved
+ *
+ */
+
+#ifndef __ICUFEATURES_H
+#define __ICUFEATURES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+
+U_NAMESPACE_BEGIN
+
+struct FeatureRecord
+{
+    ATag        featureTag;
+    Offset      featureTableOffset;
+};
+
+struct FeatureTable
+{
+    Offset      featureParamsOffset;
+    le_uint16   lookupCount;
+    le_uint16   lookupListIndexArray[ANY_NUMBER];
+};
+
+struct FeatureListTable
+{
+    le_uint16           featureCount;
+    FeatureRecord       featureRecordArray[ANY_NUMBER];
+
+    const FeatureTable  *getFeatureTable(le_uint16 featureIndex, LETag *featureTag) const;
+
+    const FeatureTable *getFeatureTable(LETag featureTag) const;
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/IndicClassTables.cpp b/source/layout/IndicClassTables.cpp
new file mode 100644
index 0000000..217d08f
--- /dev/null
+++ b/source/layout/IndicClassTables.cpp
@@ -0,0 +1,468 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2011 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEScripts.h"
+#include "OpenTypeTables.h"
+#include "OpenTypeUtilities.h"
+#include "IndicReordering.h"
+
+U_NAMESPACE_BEGIN
+
+// Split matra table indices
+#define _x1  (1 << CF_INDEX_SHIFT)
+#define _x2  (2 << CF_INDEX_SHIFT)
+#define _x3  (3 << CF_INDEX_SHIFT)
+#define _x4  (4 << CF_INDEX_SHIFT)
+#define _x5  (5 << CF_INDEX_SHIFT)
+#define _x6  (6 << CF_INDEX_SHIFT)
+#define _x7  (7 << CF_INDEX_SHIFT)
+#define _x8  (8 << CF_INDEX_SHIFT)
+#define _x9  (9 << CF_INDEX_SHIFT)
+
+// simple classes
+#define _xx  (CC_RESERVED)
+#define _ma  (CC_VOWEL_MODIFIER | CF_POS_ABOVE)
+#define _mp  (CC_VOWEL_MODIFIER | CF_POS_AFTER)
+#define _sa  (CC_STRESS_MARK | CF_POS_ABOVE)
+#define _sb  (CC_STRESS_MARK | CF_POS_BELOW)
+#define _iv  (CC_INDEPENDENT_VOWEL)
+#define _i2  (CC_INDEPENDENT_VOWEL_2)
+#define _i3  (CC_INDEPENDENT_VOWEL_3)
+#define _ct  (CC_CONSONANT | CF_CONSONANT)
+#define _cn  (CC_CONSONANT_WITH_NUKTA | CF_CONSONANT)
+#define _nu  (CC_NUKTA)
+#define _dv  (CC_DEPENDENT_VOWEL)
+#define _dl  (_dv | CF_POS_BEFORE)
+#define _db  (_dv | CF_POS_BELOW)
+#define _da  (_dv | CF_POS_ABOVE)
+#define _dr  (_dv | CF_POS_AFTER)
+#define _lm  (_dv | CF_LENGTH_MARK)
+#define _l1  (CC_SPLIT_VOWEL_PIECE_1 | CF_POS_BEFORE)
+#define _a1  (CC_SPLIT_VOWEL_PIECE_1 | CF_POS_ABOVE)
+#define _b2  (CC_SPLIT_VOWEL_PIECE_2 | CF_POS_BELOW)
+#define _r2  (CC_SPLIT_VOWEL_PIECE_2 | CF_POS_AFTER)
+#define _m2  (CC_SPLIT_VOWEL_PIECE_2 | CF_LENGTH_MARK)
+#define _m3  (CC_SPLIT_VOWEL_PIECE_3 | CF_LENGTH_MARK)
+#define _vr  (CC_VIRAMA)
+#define _al  (CC_AL_LAKUNA)
+
+// split matras
+#define _s1  (_dv | _x1)
+#define _s2  (_dv | _x2)
+#define _s3  (_dv | _x3)
+#define _s4  (_dv | _x4)
+#define _s5  (_dv | _x5)
+#define _s6  (_dv | _x6)
+#define _s7  (_dv | _x7)
+#define _s8  (_dv | _x8)
+#define _s9  (_dv | _x9)
+
+// consonants with special forms
+// NOTE: this assumes that no consonants with nukta have
+// special forms... (Bengali RA?)
+#define _bb  (_ct | CF_BELOW_BASE)
+#define _pb  (_ct | CF_POST_BASE)
+#define _fb  (_ct | CF_PRE_BASE)
+#define _vt  (_bb | CF_VATTU)
+#define _rv  (_vt | CF_REPH)
+#define _rp  (_pb | CF_REPH)
+#define _rb  (_bb | CF_REPH)
+
+//
+// Character class tables
+//
+static const IndicClassTable::CharClass devaCharClasses[] =
+{
+    _xx, _ma, _ma, _mp, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _iv, // 0900 - 090F
+    _iv, _iv, _iv, _iv, _iv, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, // 0910 - 091F
+    _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _cn, _ct, _ct, _ct, _ct, _ct, _ct, // 0920 - 092F
+    _rv, _cn, _ct, _ct, _cn, _ct, _ct, _ct, _ct, _ct, _xx, _xx, _nu, _xx, _dr, _dl, // 0930 - 093F
+    _dr, _db, _db, _db, _db, _da, _da, _da, _da, _dr, _dr, _dr, _dr, _vr, _xx, _xx, // 0940 - 094F
+    _xx, _sa, _sb, _sa, _sa, _xx, _xx, _xx, _cn, _cn, _cn, _cn, _cn, _cn, _cn, _cn, // 0950 - 095F
+    _iv, _iv, _db, _db, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, // 0960 - 096F
+    _xx                                                                             // 0970
+};
+
+static const IndicClassTable::CharClass bengCharClasses[] =
+{
+    _xx, _ma, _mp, _mp, _xx, _i2, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _xx, _xx, _i2, // 0980 - 098F
+    _iv, _xx, _xx, _iv, _iv, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, // 0990 - 099F
+    _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _xx, _ct, _ct, _bb, _ct, _ct, _pb, // 09A0 - 09AF
+    _rv, _xx, _ct, _xx, _xx, _xx, _ct, _ct, _ct, _ct, _xx, _xx, _nu, _xx, _r2, _dl, // 09B0 - 09BF
+    _dr, _db, _db, _db, _db, _xx, _xx, _l1, _dl, _xx, _xx, _s1, _s2, _vr, _xx, _xx, // 09C0 - 09CF
+    _xx, _xx, _xx, _xx, _xx, _xx, _xx, _m2, _xx, _xx, _xx, _xx, _cn, _cn, _xx, _cn, // 09D0 - 09DF
+    _iv, _iv, _dv, _dv, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, // 09E0 - 09EF
+    _rv, _ct, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx                           // 09F0 - 09FA
+};
+
+static const IndicClassTable::CharClass punjCharClasses[] =
+{
+    _xx, _ma, _ma, _mp, _xx, _iv, _iv, _iv, _iv, _iv, _iv, _xx, _xx, _xx, _xx, _iv, // 0A00 - 0A0F
+    _iv, _xx, _xx, _i3, _iv, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, // 0A10 - 0A1F
+    _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _xx, _ct, _ct, _ct, _ct, _ct, _bb, // 0A20 - 0A2F
+    _vt, _xx, _ct, _cn, _xx, _bb, _cn, _xx, _ct, _bb, _xx, _xx, _nu, _xx, _dr, _dl, // 0A30 - 0A3F
+    _dr, _b2, _db, _xx, _xx, _xx, _xx, _da, _da, _xx, _xx, _a1, _da, _vr, _xx, _xx, // 0A40 - 0A4F
+    _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _cn, _cn, _cn, _ct, _xx, _cn, _xx, // 0A50 - 0A5F
+    _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, // 0A60 - 0A6F
+    _ma, _ma, _xx, _xx, _xx                                                         // 0A70 - 0A74
+};
+
+static const IndicClassTable::CharClass gujrCharClasses[] =
+{
+    _xx, _ma, _ma, _mp, _xx, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _xx, _iv, _xx, _iv, // 0A80 - 0A8F
+    _iv, _iv, _xx, _iv, _iv, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, // 0A90 - 0A9F
+    _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _xx, _ct, _ct, _ct, _ct, _ct, _ct, // 0AA0 - 0AAF
+    _rv, _xx, _ct, _ct, _xx, _ct, _ct, _ct, _ct, _ct, _xx, _xx, _nu, _xx, _dr, _dl, // 0AB0 - 0ABF
+    _dr, _db, _db, _db, _db, _da, _xx, _da, _da, _dr, _xx, _dr, _dr, _vr, _xx, _xx, // 0AC0 - 0ACF
+    _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, // 0AD0 - 0ADF
+    _iv, _iv, _db, _db, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx  // 0AE0 - 0AEF
+};
+
+#if 1
+static const IndicClassTable::CharClass oryaCharClasses[] =
+{
+    _xx, _ma, _mp, _mp, _xx, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _xx, _xx, _iv, /* 0B00 - 0B0F */
+    _iv, _xx, _xx, _iv, _iv, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _ct, _bb, /* 0B10 - 0B1F */
+    _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _xx, _bb, _bb, _bb, _bb, _bb, _pb, /* 0B20 - 0B2F */
+    _rb, _xx, _bb, _bb, _xx, _bb, _bb, _bb, _bb, _bb, _xx, _xx, _nu, _xx, _dr, _da, /* 0B30 - 0B3F */
+    _dr, _db, _db, _db, _xx, _xx, _xx, _dl, _s1, _xx, _xx, _s2, _s3, _vr, _xx, _xx, /* 0B40 - 0B4F */
+    _xx, _xx, _xx, _xx, _xx, _xx, _da, _dr, _xx, _xx, _xx, _xx, _cn, _cn, _xx, _pb, /* 0B50 - 0B5F */
+    _iv, _iv, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, /* 0B60 - 0B6F */
+    _xx, _bb                                                                        /* 0B70 - 0B71 */
+};
+#else
+static const IndicClassTable::CharClass oryaCharClasses[] =
+{
+    _xx, _ma, _mp, _mp, _xx, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _xx, _xx, _iv, // 0B00 - 0B0F
+    _iv, _xx, _xx, _iv, _iv, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, // 0B10 - 0B1F
+    _ct, _ct, _ct, _ct, _bb, _ct, _ct, _ct, _bb, _xx, _ct, _ct, _bb, _bb, _bb, _pb, // 0B20 - 0B2F
+    _rb, _xx, _bb, _bb, _xx, _ct, _ct, _ct, _ct, _ct, _xx, _xx, _nu, _xx, _r2, _da, // 0B30 - 0B3F
+    _dr, _db, _db, _db, _xx, _xx, _xx, _l1, _s1, _xx, _xx, _s2, _s3, _vr, _xx, _xx, // 0B40 - 0B4F
+    _xx, _xx, _xx, _xx, _xx, _xx, _m2, _m2, _xx, _xx, _xx, _xx, _cn, _cn, _xx, _cn, // 0B50 - 0B5F
+    _iv, _iv, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, // 0B60 - 0B6F
+    _xx, _ct                                                                        // 0B70 - 0B71
+};
+#endif
+
+static const IndicClassTable::CharClass tamlCharClasses[] =
+{
+    _xx, _xx, _ma, _xx, _xx, _iv, _iv, _iv, _iv, _iv, _iv, _xx, _xx, _xx, _iv, _iv, // 0B80 - 0B8F
+    _iv, _xx, _iv, _iv, _iv, _ct, _xx, _xx, _xx, _ct, _ct, _xx, _ct, _xx, _ct, _ct, // 0B90 - 0B9F
+    _xx, _xx, _xx, _ct, _ct, _xx, _xx, _xx, _ct, _ct, _ct, _xx, _xx, _xx, _ct, _ct, // 0BA0 - 0BAF
+    _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _xx, _xx, _xx, _xx, _r2, _dr, // 0BB0 - 0BBF
+    _da, _dr, _dr, _xx, _xx, _xx, _l1, _l1, _dl, _xx, _s1, _s2, _s3, _vr, _xx, _xx, // 0BC0 - 0BCF
+    _xx, _xx, _xx, _xx, _xx, _xx, _xx, _m2, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, // 0BD0 - 0BDF
+    _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, // 0BE0 - 0BEF
+    _xx, _xx, _xx                                                                   // 0BF0 - 0BF2
+};
+
+// FIXME: Should some of the bb's be pb's? (KA, NA, MA, YA, VA, etc. (approx 13))
+// U+C43 and U+C44 are _lm here not _dr.  Similar to the situation with U+CC3 and
+// U+CC4 in Kannada below.
+static const IndicClassTable::CharClass teluCharClasses[] =
+{
+    _xx, _mp, _mp, _mp, _xx, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _xx, _iv, _iv, // 0C00 - 0C0F
+    _iv, _xx, _iv, _iv, _iv, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, // 0C10 - 0C1F
+    _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _xx, _bb, _bb, _bb, _bb, _bb, _bb, // 0C20 - 0C2F
+    _bb, _bb, _bb, _bb, _xx, _bb, _bb, _bb, _bb, _bb, _xx, _xx, _xx, _xx, _da, _da, // 0C30 - 0C3F
+    _da, _dr, _dr, _lm, _lm, _xx, _a1, _da, _s1, _xx, _da, _da, _da, _vr, _xx, _xx, // 0C40 - 0C4F
+    _xx, _xx, _xx, _xx, _xx, _da, _m2, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, // 0C50 - 0C5F
+    _iv, _iv, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx  // 0C60 - 0C6F
+};
+
+// U+CC3 and U+CC4 are _lm here not _dr since the Kannada rendering
+// rules want them below and to the right of the entire cluster
+//
+// There's some information about this in:
+//
+//  http://brahmi.sourceforge.net/docs/KannadaComputing.html
+static const IndicClassTable::CharClass kndaCharClasses[] =
+{
+    _xx, _xx, _mp, _mp, _xx, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _xx, _iv, _iv, // 0C80 - 0C8F
+    _iv, _xx, _iv, _iv, _iv, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, // 0C90 - 0C9F
+    _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _bb, _xx, _bb, _bb, _bb, _bb, _bb, _bb, // 0CA0 - 0CAF
+    _rb, _ct, _bb, _bb, _xx, _bb, _bb, _bb, _bb, _bb, _xx, _xx, _xx, _xx, _dr, _da, // 0CB0 - 0CBF
+    _s1, _dr, _r2, _lm, _lm, _xx, _a1, _s2, _s3, _xx, _s4, _s5, _da, _vr, _xx, _xx, // 0CC0 - 0CCF
+    _xx, _xx, _xx, _xx, _xx, _m3, _m2, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _ct, _xx, // 0CD0 - 0CDF
+    _iv, _iv, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx  // 0CE0 - 0CEF
+};
+
+// FIXME: this is correct for old-style Malayalam (MAL) but not for reformed Malayalam (MLR)
+// FIXME: should there be a REPH for old-style Malayalam?
+static const IndicClassTable::CharClass mlymCharClasses[] =
+{
+    _xx, _xx, _mp, _mp, _xx, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _xx, _iv, _iv, // 0D00 - 0D0F
+    _iv, _xx, _iv, _iv, _iv, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, // 0D10 - 0D1F
+    _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _xx, _ct, _ct, _ct, _ct, _ct, _pb, // 0D20 - 0D2F
+    _fb, _fb, _bb, _ct, _ct, _pb, _ct, _ct, _ct, _ct, _xx, _xx, _xx, _xx, _r2, _dr, // 0D30 - 0D3F
+    _dr, _dr, _dr, _dr, _xx, _xx, _l1, _l1, _dl, _xx, _s1, _s2, _s3, _vr, _xx, _xx, // 0D40 - 0D4F
+    _xx, _xx, _xx, _xx, _xx, _xx, _xx, _m2, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, // 0D50 - 0D5F
+    _iv, _iv, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx  // 0D60 - 0D6F
+};
+ 
+static const IndicClassTable::CharClass sinhCharClasses[] =
+{
+    _xx, _xx, _mp, _mp, _xx, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _iv, _iv, // 0D80 - 0D8F
+    _iv, _iv, _iv, _iv, _iv, _iv, _iv, _xx, _xx, _xx, _ct, _ct, _ct, _ct, _ct, _ct, // 0D90 - 0D9F
+    _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, // 0DA0 - 0DAF
+    _ct, _ct, _xx, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _ct, _xx, _ct, _xx, _xx, // 0DB0 - 0DBF
+    _ct, _ct, _ct, _ct, _ct, _ct, _ct, _xx, _xx, _xx, _al, _xx, _xx, _xx, _xx, _dr, // 0DC0 - 0DCF
+    _dr, _dr, _da, _da, _db, _xx, _db, _xx, _dr, _dl, _s1, _dl, _s2, _s3, _s4, _dr, // 0DD0 - 0DDF
+    _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, // 0DE0 - 0DEF
+    _xx, _xx, _dr, _dr, _xx                                                         // 0DF0 - 0DF4
+};
+
+//
+// Split matra tables
+//
+static const SplitMatra bengSplitTable[] = {{0x09C7, 0x09BE}, {0x09C7, 0x09D7}};
+
+static const SplitMatra oryaSplitTable[] = {{0x0B47, 0x0B56}, {0x0B47, 0x0B3E}, {0x0B47, 0x0B57}};
+
+static const SplitMatra tamlSplitTable[] = {{0x0BC6, 0x0BBE}, {0x0BC7, 0x0BBE}, {0x0BC6, 0x0BD7}};
+
+static const SplitMatra teluSplitTable[] = {{0x0C46, 0x0C56}};
+
+static const SplitMatra kndaSplitTable[] = {{0x0CBF, 0x0CD5}, {0x0CC6, 0x0CD5}, {0x0CC6, 0x0CD6}, {0x0CC6, 0x0CC2},
+                                            {0x0CC6, 0x0CC2, 0x0CD5}};
+
+static const SplitMatra mlymSplitTable[] = {{0x0D46, 0x0D3E}, {0x0D47, 0x0D3E}, {0x0D46, 0x0D57}};
+
+ 
+static const SplitMatra sinhSplitTable[] = {{0x0DD9, 0x0DCA}, {0x0DD9, 0x0DCF}, {0x0DD9, 0x0DCF, 0x0DCA},
+                                            {0x0DD9, 0x0DDF}};
+//
+// Script Flags
+//
+
+// FIXME: post 'GSUB' reordering of MATRA_PRE's for Malayalam and Tamil
+// FIXME: reformed Malayalam needs to reorder VATTU to before base glyph...
+// FIXME: not sure passing ZWJ/ZWNJ is best way to render Malayalam Cillu...
+// FIXME: eyelash RA only for Devanagari??
+#define DEVA_SCRIPT_FLAGS (SF_EYELASH_RA | SF_NO_POST_BASE_LIMIT | SF_FILTER_ZERO_WIDTH)
+#define BENG_SCRIPT_FLAGS (SF_REPH_AFTER_BELOW | SF_NO_POST_BASE_LIMIT | SF_FILTER_ZERO_WIDTH)
+#define PUNJ_SCRIPT_FLAGS (SF_NO_POST_BASE_LIMIT | SF_FILTER_ZERO_WIDTH)
+#define GUJR_SCRIPT_FLAGS (SF_NO_POST_BASE_LIMIT | SF_FILTER_ZERO_WIDTH)
+#define ORYA_SCRIPT_FLAGS (SF_REPH_AFTER_BELOW | SF_NO_POST_BASE_LIMIT | SF_FILTER_ZERO_WIDTH)
+#define TAML_SCRIPT_FLAGS (SF_MPRE_FIXUP | SF_NO_POST_BASE_LIMIT | SF_FILTER_ZERO_WIDTH)
+#define TELU_SCRIPT_FLAGS (SF_MATRAS_AFTER_BASE | SF_FILTER_ZERO_WIDTH | 3)
+#define KNDA_SCRIPT_FLAGS (SF_MATRAS_AFTER_BASE | SF_FILTER_ZERO_WIDTH | 3)
+#define MLYM_SCRIPT_FLAGS (SF_MPRE_FIXUP | SF_NO_POST_BASE_LIMIT /*| SF_FILTER_ZERO_WIDTH*/)
+#define SINH_SCRIPT_FLAGS (SF_NO_POST_BASE_LIMIT)
+
+//
+// Indic Class Tables
+//
+static const IndicClassTable devaClassTable = {0x0900, 0x0970, 2, DEVA_SCRIPT_FLAGS, devaCharClasses, NULL};
+
+static const IndicClassTable bengClassTable = {0x0980, 0x09FA, 3, BENG_SCRIPT_FLAGS, bengCharClasses, bengSplitTable};
+
+static const IndicClassTable punjClassTable = {0x0A00, 0x0A74, 2, PUNJ_SCRIPT_FLAGS, punjCharClasses, NULL};
+
+static const IndicClassTable gujrClassTable = {0x0A80, 0x0AEF, 2, GUJR_SCRIPT_FLAGS, gujrCharClasses, NULL};
+
+static const IndicClassTable oryaClassTable = {0x0B00, 0x0B71, 3, ORYA_SCRIPT_FLAGS, oryaCharClasses, oryaSplitTable};
+
+static const IndicClassTable tamlClassTable = {0x0B80, 0x0BF2, 3, TAML_SCRIPT_FLAGS, tamlCharClasses, tamlSplitTable};
+
+static const IndicClassTable teluClassTable = {0x0C00, 0x0C6F, 3, TELU_SCRIPT_FLAGS, teluCharClasses, teluSplitTable};
+
+static const IndicClassTable kndaClassTable = {0x0C80, 0x0CEF, 4, KNDA_SCRIPT_FLAGS, kndaCharClasses, kndaSplitTable};
+
+static const IndicClassTable mlymClassTable = {0x0D00, 0x0D6F, 3, MLYM_SCRIPT_FLAGS, mlymCharClasses, mlymSplitTable};
+
+static const IndicClassTable sinhClassTable = {0x0D80, 0x0DF4, 4, SINH_SCRIPT_FLAGS, sinhCharClasses, sinhSplitTable};
+
+//
+// IndicClassTable addresses
+//
+static const IndicClassTable * const indicClassTables[scriptCodeCount] = {
+    NULL,            /* 'zyyy' (COMMON) */
+    NULL,            /* 'qaai' (INHERITED) */
+    NULL,            /* 'arab' (ARABIC) */
+    NULL,            /* 'armn' (ARMENIAN) */
+    &bengClassTable, /* 'beng' (BENGALI) */
+    NULL,            /* 'bopo' (BOPOMOFO) */
+    NULL,            /* 'cher' (CHEROKEE) */
+    NULL,            /* 'copt' (COPTIC) */
+    NULL,            /* 'cyrl' (CYRILLIC) */
+    NULL,            /* 'dsrt' (DESERET) */
+    &devaClassTable, /* 'deva' (DEVANAGARI) */
+    NULL,            /* 'ethi' (ETHIOPIC) */
+    NULL,            /* 'geor' (GEORGIAN) */
+    NULL,            /* 'goth' (GOTHIC) */
+    NULL,            /* 'grek' (GREEK) */
+    &gujrClassTable, /* 'gujr' (GUJARATI) */
+    &punjClassTable, /* 'guru' (GURMUKHI) */
+    NULL,            /* 'hani' (HAN) */
+    NULL,            /* 'hang' (HANGUL) */
+    NULL,            /* 'hebr' (HEBREW) */
+    NULL,            /* 'hira' (HIRAGANA) */
+    &kndaClassTable, /* 'knda' (KANNADA) */
+    NULL,            /* 'kata' (KATAKANA) */
+    NULL,            /* 'khmr' (KHMER) */
+    NULL,            /* 'laoo' (LAO) */
+    NULL,            /* 'latn' (LATIN) */
+    &mlymClassTable, /* 'mlym' (MALAYALAM) */
+    NULL,            /* 'mong' (MONGOLIAN) */
+    NULL,            /* 'mymr' (MYANMAR) */
+    NULL,            /* 'ogam' (OGHAM) */
+    NULL,            /* 'ital' (OLD-ITALIC) */
+    &oryaClassTable, /* 'orya' (ORIYA) */
+    NULL,            /* 'runr' (RUNIC) */
+    &sinhClassTable, /* 'sinh' (SINHALA) */
+    NULL,            /* 'syrc' (SYRIAC) */
+    &tamlClassTable, /* 'taml' (TAMIL) */
+    &teluClassTable, /* 'telu' (TELUGU) */
+    NULL,            /* 'thaa' (THAANA) */
+    NULL,            /* 'thai' (THAI) */
+    NULL,            /* 'tibt' (TIBETAN) */
+    NULL,            /* 'cans' (CANADIAN-ABORIGINAL) */
+    NULL,            /* 'yiii' (YI) */
+    NULL,            /* 'tglg' (TAGALOG) */
+    NULL,            /* 'hano' (HANUNOO) */
+    NULL,            /* 'buhd' (BUHID) */
+    NULL,            /* 'tagb' (TAGBANWA) */
+    NULL,            /* 'brai' (BRAILLE) */
+    NULL,            /* 'cprt' (CYPRIOT) */
+    NULL,            /* 'limb' (LIMBU) */
+    NULL,            /* 'linb' (LINEAR_B) */
+    NULL,            /* 'osma' (OSMANYA) */
+    NULL,            /* 'shaw' (SHAVIAN) */
+    NULL,            /* 'tale' (TAI_LE) */
+    NULL,            /* 'ugar' (UGARITIC) */
+    NULL,            /* 'hrkt' (KATAKANA_OR_HIRAGANA) */
+    NULL,            /* 'bugi' (BUGINESE) */
+    NULL,            /* 'glag' (GLAGOLITIC) */
+    NULL,            /* 'khar' (KHAROSHTHI) */
+    NULL,            /* 'sylo' (SYLOTI_NAGRI) */
+    NULL,            /* 'talu' (NEW_TAI_LUE) */
+    NULL,            /* 'tfng' (TIFINAGH) */
+    NULL,            /* 'xpeo' (OLD_PERSIAN) */
+    NULL,            /* 'bali' (BALINESE) */
+    NULL,            /* 'batk' (BATK) */
+    NULL,            /* 'blis' (BLIS) */
+    NULL,            /* 'brah' (BRAH) */
+    NULL,            /* 'cham' (CHAM) */
+    NULL,            /* 'cirt' (CIRT) */
+    NULL,            /* 'cyrs' (CYRS) */
+    NULL,            /* 'egyd' (EGYD) */
+    NULL,            /* 'egyh' (EGYH) */
+    NULL,            /* 'egyp' (EGYP) */
+    NULL,            /* 'geok' (GEOK) */
+    NULL,            /* 'hans' (HANS) */
+    NULL,            /* 'hant' (HANT) */
+    NULL,            /* 'hmng' (HMNG) */
+    NULL,            /* 'hung' (HUNG) */
+    NULL,            /* 'inds' (INDS) */
+    NULL,            /* 'java' (JAVA) */
+    NULL,            /* 'kali' (KALI) */
+    NULL,            /* 'latf' (LATF) */
+    NULL,            /* 'latg' (LATG) */
+    NULL,            /* 'lepc' (LEPC) */
+    NULL,            /* 'lina' (LINA) */
+    NULL,            /* 'mand' (MAND) */
+    NULL,            /* 'maya' (MAYA) */
+    NULL,            /* 'mero' (MERO) */
+    NULL,            /* 'nko ' (NKO) */
+    NULL,            /* 'orkh' (ORKH) */
+    NULL,            /* 'perm' (PERM) */
+    NULL,            /* 'phag' (PHAGS_PA) */
+    NULL,            /* 'phnx' (PHOENICIAN) */
+    NULL,            /* 'plrd' (PLRD) */
+    NULL,            /* 'roro' (RORO) */
+    NULL,            /* 'sara' (SARA) */
+    NULL,            /* 'syre' (SYRE) */
+    NULL,            /* 'syrj' (SYRJ) */
+    NULL,            /* 'syrn' (SYRN) */
+    NULL,            /* 'teng' (TENG) */
+    NULL,            /* 'vai ' (VAII) */
+    NULL,            /* 'visp' (VISP) */
+    NULL,            /* 'xsux' (CUNEIFORM) */
+    NULL,            /* 'zxxx' (ZXXX) */
+    NULL,            /* 'zzzz' (UNKNOWN) */
+    NULL,            /* 'cari' (CARI) */
+    NULL,            /* 'jpan' (JPAN) */
+    NULL,            /* 'lana' (LANA) */
+    NULL,            /* 'lyci' (LYCI) */
+    NULL,            /* 'lydi' (LYDI) */
+    NULL,            /* 'olck' (OLCK) */
+    NULL,            /* 'rjng' (RJNG) */
+    NULL,            /* 'saur' (SAUR) */
+    NULL,            /* 'sgnw' (SGNW) */
+    NULL,            /* 'sund' (SUND) */
+    NULL,            /* 'moon' (MOON) */
+    NULL,            /* 'mtei' (MTEI) */
+    NULL,            /* 'armi' (ARMI) */
+    NULL,            /* 'avst' (AVST) */
+    NULL,            /* 'cakm' (CAKM) */
+    NULL,            /* 'kore' (KORE) */
+    NULL,            /* 'kthi' (KTHI) */
+    NULL,            /* 'mani' (MANI) */
+    NULL,            /* 'phli' (PHLI) */
+    NULL,            /* 'phlp' (PHLP) */
+    NULL,            /* 'phlv' (PHLV) */
+    NULL,            /* 'prti' (PRTI) */
+    NULL,            /* 'samr' (SAMR) */
+    NULL,            /* 'tavt' (TAVT) */
+    NULL,            /* 'zmth' (ZMTH) */
+    NULL,            /* 'zsym' (ZSYM) */
+    NULL,            /* 'bamu' (BAMUM) */
+    NULL,            /* 'lisu' (LISU) */
+    NULL,            /* 'nkgb' (NKGB) */
+    NULL             /* 'sarb' (OLD_SOUTH_ARABIAN) */
+};
+
+IndicClassTable::CharClass IndicClassTable::getCharClass(LEUnicode ch) const
+{
+    if (ch == C_SIGN_ZWJ) {
+        return CF_CONSONANT | CC_ZERO_WIDTH_MARK;
+    }
+
+    if (ch == C_SIGN_ZWNJ) {
+        return CC_ZERO_WIDTH_MARK;
+    }
+
+    if (ch < firstChar || ch > lastChar) {
+        return CC_RESERVED;
+    }
+
+    return classTable[ch - firstChar];
+}
+
+const IndicClassTable *IndicClassTable::getScriptClassTable(le_int32 scriptCode)
+{
+    if (scriptCode < 0 || scriptCode >= scriptCodeCount) {
+        return NULL;
+    }
+
+    return indicClassTables[scriptCode];
+}
+
+le_int32 IndicReordering::getWorstCaseExpansion(le_int32 scriptCode)
+{
+    const IndicClassTable *classTable = IndicClassTable::getScriptClassTable(scriptCode);
+
+    if (classTable == NULL) {
+        return 1;
+    }
+
+    return classTable->getWorstCaseExpansion();
+}
+
+le_bool IndicReordering::getFilterZeroWidth(le_int32 scriptCode)
+{
+    const IndicClassTable *classTable = IndicClassTable::getScriptClassTable(scriptCode);
+
+    if (classTable == NULL) {
+        return TRUE;
+    }
+
+    return classTable->getFilterZeroWidth();
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/IndicLayoutEngine.cpp b/source/layout/IndicLayoutEngine.cpp
new file mode 100644
index 0000000..5bc0435
--- /dev/null
+++ b/source/layout/IndicLayoutEngine.cpp
@@ -0,0 +1,135 @@
+
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2009 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LayoutEngine.h"
+#include "OpenTypeLayoutEngine.h"
+#include "IndicLayoutEngine.h"
+#include "ScriptAndLanguageTags.h"
+
+#include "GlyphSubstitutionTables.h"
+#include "GlyphDefinitionTables.h"
+#include "GlyphPositioningTables.h"
+
+#include "GDEFMarkFilter.h"
+#include "LEGlyphStorage.h"
+
+#include "IndicReordering.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IndicOpenTypeLayoutEngine)
+
+IndicOpenTypeLayoutEngine::IndicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+                    le_int32 typoFlags, le_bool version2, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success)
+    : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success), fMPreFixups(NULL)
+{
+	if ( version2 ) {
+		fFeatureMap = IndicReordering::getv2FeatureMap(fFeatureMapCount);
+	} else {
+        fFeatureMap = IndicReordering::getFeatureMap(fFeatureMapCount);
+	}
+	fFeatureOrder = TRUE;
+    fVersion2 = version2;
+    fFilterZeroWidth = IndicReordering::getFilterZeroWidth(fScriptCode);
+}
+
+IndicOpenTypeLayoutEngine::IndicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success)
+    : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fMPreFixups(NULL)
+{
+    fFeatureMap = IndicReordering::getFeatureMap(fFeatureMapCount);
+    fFeatureOrder = TRUE;
+	fVersion2 =  FALSE;
+}
+
+IndicOpenTypeLayoutEngine::~IndicOpenTypeLayoutEngine()
+{
+    // nothing to do
+}
+
+// Input: characters, tags
+// Output: glyphs, char indices
+le_int32 IndicOpenTypeLayoutEngine::glyphProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+                    LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    le_int32 retCount = OpenTypeLayoutEngine::glyphProcessing(chars, offset, count, max, rightToLeft, glyphStorage, success);
+
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if (fVersion2) {
+        IndicReordering::finalReordering(glyphStorage,retCount);
+        IndicReordering::applyPresentationForms(glyphStorage,retCount);
+        OpenTypeLayoutEngine::glyphSubstitution(count,max, rightToLeft, glyphStorage, success);
+    } else {
+        IndicReordering::adjustMPres(fMPreFixups, glyphStorage, success);
+    }
+    return retCount;
+}
+
+// Input: characters
+// Output: characters, char indices, tags
+// Returns: output character count
+le_int32 IndicOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+        LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    le_int32 worstCase = count * IndicReordering::getWorstCaseExpansion(fScriptCode);
+
+    outChars = LE_NEW_ARRAY(LEUnicode, worstCase);
+
+    if (outChars == NULL) {
+        success = LE_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
+
+    glyphStorage.allocateGlyphArray(worstCase, rightToLeft, success);
+    glyphStorage.allocateAuxData(success);
+
+    if (LE_FAILURE(success)) {
+        LE_DELETE_ARRAY(outChars);
+        return 0;
+    }
+
+    // NOTE: assumes this allocates featureTags...
+    // (probably better than doing the worst case stuff here...)
+
+    le_int32 outCharCount;
+    if (fVersion2) {
+        outCharCount = IndicReordering::v2process(&chars[offset], count, fScriptCode, outChars, glyphStorage);
+    } else {
+        outCharCount = IndicReordering::reorder(&chars[offset], count, fScriptCode, outChars, glyphStorage, &fMPreFixups, success);
+    }
+
+    if (LE_FAILURE(success)) {
+        LE_DELETE_ARRAY(outChars);
+        return 0;
+    }
+
+    glyphStorage.adoptGlyphCount(outCharCount);
+    return outCharCount;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/IndicLayoutEngine.h b/source/layout/IndicLayoutEngine.h
new file mode 100644
index 0000000..ff0b83c
--- /dev/null
+++ b/source/layout/IndicLayoutEngine.h
@@ -0,0 +1,167 @@
+
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2009 - All Rights Reserved
+ *
+ */
+
+#ifndef __INDICLAYOUTENGINE_H
+#define __INDICLAYOUTENGINE_H
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "LEGlyphFilter.h"
+#include "LayoutEngine.h"
+#include "OpenTypeLayoutEngine.h"
+
+#include "GlyphSubstitutionTables.h"
+#include "GlyphDefinitionTables.h"
+#include "GlyphPositioningTables.h"
+
+U_NAMESPACE_BEGIN
+
+class MPreFixups;
+class LEGlyphStorage;
+
+/**
+ * This class implements OpenType layout for Indic OpenType fonts, as
+ * specified by Microsoft in "Creating and Supporting OpenType Fonts for
+ * Indic Scripts" (http://www.microsoft.com/typography/otspec/indicot/default.htm)
+ *
+ * This class overrides the characterProcessing method to do Indic character processing
+ * and reordering, and the glyphProcessing method to implement post-GSUB processing for
+ * left matras. (See the MS spec. for more details)
+ *
+ * @internal
+ */
+class IndicOpenTypeLayoutEngine : public OpenTypeLayoutEngine
+{
+public:
+    /**
+     * This is the main constructor. It constructs an instance of IndicOpenTypeLayoutEngine for
+     * a particular font, script and language. It takes the GSUB table as a parameter since
+     * LayoutEngine::layoutEngineFactory has to read the GSUB table to know that it has an
+     * Indic OpenType font.
+     *
+     * @param fontInstance - the font
+     * @param scriptCode - the script
+     * @param langaugeCode - the language
+     * @param gsubTable - the GSUB table
+     * @param success - set to an error code if the operation fails
+     *
+     * @see LayoutEngine::layoutEngineFactory
+     * @see OpenTypeLayoutEngine
+     * @see ScriptAndLangaugeTags.h for script and language codes
+     *
+     * @internal
+     */
+    IndicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+                            le_int32 typoFlags, le_bool version2, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success);
+
+    /**
+     * This constructor is used when the font requires a "canned" GSUB table which can't be known
+     * until after this constructor has been invoked.
+     *
+     * @param fontInstance - the font
+     * @param scriptCode - the script
+     * @param langaugeCode - the language
+     * @param success - set to an error code if the operation fails
+     *
+     * @see OpenTypeLayoutEngine
+     * @see ScriptAndLangaugeTags.h for script and language codes
+     *
+     * @internal
+     */
+    IndicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+			      le_int32 typoFlags, LEErrorCode &success);
+
+    /**
+     * The destructor, virtual for correct polymorphic invocation.
+     *
+     * @internal
+     */
+   virtual ~IndicOpenTypeLayoutEngine();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.8
+     */
+    static UClassID getStaticClassID();
+
+protected:
+
+    /**
+     * This method does Indic OpenType character processing. It assigns the OpenType feature
+     * tags to the characters, and may generate output characters which have been reordered. For
+     * some Indic scripts, it may also split some vowels, resulting in more output characters
+     * than input characters.
+     *
+     * Input parameters:
+     * @param chars - the input character context
+     * @param offset - the index of the first character to process
+     * @param count - the number of characters to process
+     * @param max - the number of characters in the input context
+     * @param rightToLeft - <code>TRUE</code> if the characters are in a right to left directional run
+     * @param glyphStorage - the glyph storage object. The glyph and character index arrays will be set.
+     *                       the auxillary data array will be set to the feature tags.
+     *
+     * Output parameters:
+     * @param success - set to an error code if the operation fails
+     *
+     * @return the output character count
+     *
+     * @internal
+     */
+    virtual le_int32 characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+            LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+    /**
+     * This method does character to glyph mapping, applies the GSUB table and applies
+     * any post GSUB fixups for left matras. It calls OpenTypeLayoutEngine::glyphProcessing
+     * to do the character to glyph mapping, and apply the GSUB table.
+     *
+     * Note that in the case of "canned" GSUB tables, the output glyph indices may be
+     * "fake" glyph indices that need to be converted to "real" glyph indices by the
+     * glyphPostProcessing method.
+     *
+     * Input parameters:
+     * @param chars - the input character context
+     * @param offset - the index of the first character to process
+     * @param count - the number of characters to process
+     * @param max - the number of characters in the input context
+     * @param rightToLeft - <code>TRUE</code> if the characters are in a right to left directional run
+     * @param featureTags - the feature tag array
+     * @param glyphStorage - the glyph storage object. The glyph and char index arrays will be set.
+     *
+     * Output parameters:
+     * @param success - set to an error code if the operation fails
+     *
+     * @return the number of glyphs in the output glyph index array
+     *
+     * Note: if the character index array was already set by the characterProcessing
+     * method, this method won't change it.
+     *
+     * @internal
+     */
+    virtual le_int32 glyphProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+            LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+    le_bool fVersion2;
+
+private:
+
+    MPreFixups *fMPreFixups;
+
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/IndicRearrangement.h b/source/layout/IndicRearrangement.h
new file mode 100644
index 0000000..48b1d08
--- /dev/null
+++ b/source/layout/IndicRearrangement.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __INDICREARRANGEMENT_H
+#define __INDICREARRANGEMENT_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LayoutTables.h"
+#include "StateTables.h"
+#include "MorphTables.h"
+#include "MorphStateTables.h"
+
+U_NAMESPACE_BEGIN
+
+struct IndicRearrangementSubtableHeader : MorphStateTableHeader
+{
+};
+
+enum IndicRearrangementFlags
+{
+    irfMarkFirst    = 0x8000,
+    irfDontAdvance  = 0x4000,
+    irfMarkLast     = 0x2000,
+    irfReserved     = 0x1FF0,
+    irfVerbMask     = 0x000F
+};
+
+enum IndicRearrangementVerb
+{
+    irvNoAction = 0x0000,               /*   no action    */
+    irvxA       = 0x0001,               /*    Ax => xA    */
+    irvDx       = 0x0002,               /*    xD => Dx    */
+    irvDxA      = 0x0003,               /*   AxD => DxA   */
+        
+    irvxAB      = 0x0004,               /*   ABx => xAB   */
+    irvxBA      = 0x0005,               /*   ABx => xBA   */
+    irvCDx      = 0x0006,               /*   xCD => CDx   */
+    irvDCx      = 0x0007,               /*   xCD => DCx   */
+
+    irvCDxA     = 0x0008,               /*  AxCD => CDxA  */
+    irvDCxA     = 0x0009,               /*  AxCD => DCxA  */
+    irvDxAB     = 0x000A,               /*  ABxD => DxAB  */
+    irvDxBA     = 0x000B,               /*  ABxD => DxBA  */
+
+    irvCDxAB    = 0x000C,               /* ABxCD => CDxAB */
+    irvCDxBA    = 0x000D,               /* ABxCD => CDxBA */
+    irvDCxAB    = 0x000E,               /* ABxCD => DCxAB */
+    irvDCxBA    = 0x000F                /* ABxCD => DCxBA */
+};
+
+struct IndicRearrangementStateEntry : StateEntry
+{
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/IndicRearrangementProcessor.cpp b/source/layout/IndicRearrangementProcessor.cpp
new file mode 100644
index 0000000..9220245
--- /dev/null
+++ b/source/layout/IndicRearrangementProcessor.cpp
@@ -0,0 +1,398 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "StateTables.h"
+#include "MorphStateTables.h"
+#include "SubtableProcessor.h"
+#include "StateTableProcessor.h"
+#include "IndicRearrangementProcessor.h"
+#include "LEGlyphStorage.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IndicRearrangementProcessor)
+
+IndicRearrangementProcessor::IndicRearrangementProcessor(const MorphSubtableHeader *morphSubtableHeader)
+  : StateTableProcessor(morphSubtableHeader)
+{
+    indicRearrangementSubtableHeader = (const IndicRearrangementSubtableHeader *) morphSubtableHeader;
+    entryTable = (const IndicRearrangementStateEntry *) ((char *) &stateTableHeader->stHeader + entryTableOffset);
+}
+
+IndicRearrangementProcessor::~IndicRearrangementProcessor()
+{
+}
+
+void IndicRearrangementProcessor::beginStateTable()
+{
+    firstGlyph = 0;
+    lastGlyph = 0;
+}
+
+ByteOffset IndicRearrangementProcessor::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex index)
+{
+    const IndicRearrangementStateEntry *entry = &entryTable[index];
+    ByteOffset newState = SWAPW(entry->newStateOffset);
+    IndicRearrangementFlags flags = (IndicRearrangementFlags) SWAPW(entry->flags);
+
+    if (flags & irfMarkFirst) {
+        firstGlyph = currGlyph;
+    }
+
+    if (flags & irfMarkLast) {
+        lastGlyph = currGlyph;
+    }
+
+    doRearrangementAction(glyphStorage, (IndicRearrangementVerb) (flags & irfVerbMask));
+
+    if (!(flags & irfDontAdvance)) {
+        // XXX: Should handle reverse too...
+        currGlyph += 1;
+    }
+
+    return newState;
+}
+
+void IndicRearrangementProcessor::endStateTable()
+{
+}
+
+void IndicRearrangementProcessor::doRearrangementAction(LEGlyphStorage &glyphStorage, IndicRearrangementVerb verb) const
+{
+    LEGlyphID a, b, c, d;
+    le_int32 ia, ib, ic, id, ix, x;
+    LEErrorCode success = LE_NO_ERROR;
+
+    switch(verb)
+    {
+    case irvNoAction:
+        break;
+
+    case irvxA:
+        a = glyphStorage[firstGlyph];
+        ia = glyphStorage.getCharIndex(firstGlyph, success);
+        x = firstGlyph + 1;
+
+        while (x <= lastGlyph) {
+            glyphStorage[x - 1] = glyphStorage[x];
+            ix = glyphStorage.getCharIndex(x, success);
+            glyphStorage.setCharIndex(x - 1, ix, success);
+            x += 1;
+        }
+
+        glyphStorage[lastGlyph] = a;
+        glyphStorage.setCharIndex(lastGlyph, ia, success);
+        break;
+
+    case irvDx:
+        d = glyphStorage[lastGlyph];
+        id = glyphStorage.getCharIndex(lastGlyph, success);
+        x = lastGlyph - 1;
+
+        while (x >= firstGlyph) {
+            glyphStorage[x + 1] = glyphStorage[x];
+            ix = glyphStorage.getCharIndex(x, success);
+            glyphStorage.setCharIndex(x + 1, ix, success);
+            x -= 1;
+        }
+
+        glyphStorage[firstGlyph] = d;
+        glyphStorage.setCharIndex(firstGlyph, id, success);
+        break;
+
+    case irvDxA:
+        a = glyphStorage[firstGlyph];
+        ia = glyphStorage.getCharIndex(firstGlyph, success);
+        id = glyphStorage.getCharIndex(lastGlyph,  success);
+
+        glyphStorage[firstGlyph] = glyphStorage[lastGlyph];
+        glyphStorage[lastGlyph] = a;
+
+        glyphStorage.setCharIndex(firstGlyph, id, success);
+        glyphStorage.setCharIndex(lastGlyph,  ia, success);
+        break;
+        
+    case irvxAB:
+        a = glyphStorage[firstGlyph];
+        b = glyphStorage[firstGlyph + 1];
+        ia = glyphStorage.getCharIndex(firstGlyph, success);
+        ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
+        x = firstGlyph + 2;
+
+        while (x <= lastGlyph) {
+            glyphStorage[x - 2] = glyphStorage[x];
+            ix = glyphStorage.getCharIndex(x, success);
+            glyphStorage.setCharIndex(x - 2, ix, success);
+            x += 1;
+        }
+
+        glyphStorage[lastGlyph - 1] = a;
+        glyphStorage[lastGlyph] = b;
+
+        glyphStorage.setCharIndex(lastGlyph - 1, ia, success);
+        glyphStorage.setCharIndex(lastGlyph, ib, success);
+        break;
+
+    case irvxBA:
+        a = glyphStorage[firstGlyph];
+        b = glyphStorage[firstGlyph + 1];
+        ia = glyphStorage.getCharIndex(firstGlyph, success);
+        ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
+        x = firstGlyph + 2;
+
+        while (x <= lastGlyph) {
+            glyphStorage[x - 2] = glyphStorage[x];
+            ix = glyphStorage.getCharIndex(x, success);
+            glyphStorage.setCharIndex(x - 2, ix, success);
+            x += 1;
+        }
+
+        glyphStorage[lastGlyph - 1] = b;
+        glyphStorage[lastGlyph] = a;
+
+        glyphStorage.setCharIndex(lastGlyph - 1, ib, success);
+        glyphStorage.setCharIndex(lastGlyph, ia, success);
+        break;
+
+    case irvCDx:
+        c = glyphStorage[lastGlyph - 1];
+        d = glyphStorage[lastGlyph];
+        ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
+        id = glyphStorage.getCharIndex(lastGlyph, success);
+        x = lastGlyph - 2;
+
+        while (x >= firstGlyph) {
+            glyphStorage[x + 2] = glyphStorage[x];
+            ix = glyphStorage.getCharIndex(x, success);
+            glyphStorage.setCharIndex(x + 2, ix, success);
+            x -= 1;
+        }
+        
+        glyphStorage[firstGlyph] = c;
+        glyphStorage[firstGlyph + 1] = d;
+
+        glyphStorage.setCharIndex(firstGlyph, ic, success);
+        glyphStorage.setCharIndex(firstGlyph + 1, id, success);
+        break; 
+
+    case irvDCx:
+        c = glyphStorage[lastGlyph - 1];
+        d = glyphStorage[lastGlyph];
+        ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
+        id = glyphStorage.getCharIndex(lastGlyph, success);
+        x = lastGlyph - 2;
+
+        while (x >= firstGlyph) {
+            glyphStorage[x + 2] = glyphStorage[x];
+            ix = glyphStorage.getCharIndex(x, success);
+            glyphStorage.setCharIndex(x + 2, ix, success);
+            x -= 1;
+        }
+        
+        glyphStorage[firstGlyph] = d;
+        glyphStorage[firstGlyph + 1] = c;
+
+        glyphStorage.setCharIndex(firstGlyph, id, success);
+        glyphStorage.setCharIndex(firstGlyph + 1, ic, success);
+        break; 
+
+    case irvCDxA:
+        a = glyphStorage[firstGlyph];
+        c = glyphStorage[lastGlyph - 1];
+        d = glyphStorage[lastGlyph];
+        ia = glyphStorage.getCharIndex(firstGlyph, success);
+        ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
+        id = glyphStorage.getCharIndex(lastGlyph, success);
+        x = lastGlyph - 2;
+
+        while (x > firstGlyph) {
+            glyphStorage[x + 1] = glyphStorage[x];
+            ix = glyphStorage.getCharIndex(x, success);
+            glyphStorage.setCharIndex(x + 1, ix, success);
+            x -= 1;
+        }
+        
+        glyphStorage[firstGlyph] = c;
+        glyphStorage[firstGlyph + 1] = d;
+        glyphStorage[lastGlyph] = a;
+
+        glyphStorage.setCharIndex(firstGlyph, ic, success);
+        glyphStorage.setCharIndex(firstGlyph + 1, id, success);
+        glyphStorage.setCharIndex(lastGlyph, ia, success);
+        break; 
+
+    case irvDCxA:
+        a = glyphStorage[firstGlyph];
+        c = glyphStorage[lastGlyph - 1];
+        d = glyphStorage[lastGlyph];
+        ia = glyphStorage.getCharIndex(firstGlyph, success);
+        ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
+        id = glyphStorage.getCharIndex(lastGlyph, success);
+        x = lastGlyph - 2;
+
+        while (x > firstGlyph) {
+            glyphStorage[x + 1] = glyphStorage[x];
+            ix = glyphStorage.getCharIndex(x, success);
+            glyphStorage.setCharIndex(x + 1, ix, success);
+            x -= 1;
+        }
+        
+        glyphStorage[firstGlyph] = d;
+        glyphStorage[firstGlyph + 1] = c;
+        glyphStorage[lastGlyph] = a;
+
+        glyphStorage.setCharIndex(firstGlyph, id, success);
+        glyphStorage.setCharIndex(firstGlyph + 1, ic, success);
+        glyphStorage.setCharIndex(lastGlyph, ia, success);
+        break; 
+
+    case irvDxAB:
+        a = glyphStorage[firstGlyph];
+        b = glyphStorage[firstGlyph + 1];
+        d = glyphStorage[lastGlyph];
+        ia = glyphStorage.getCharIndex(firstGlyph, success);
+        ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
+        id = glyphStorage.getCharIndex(lastGlyph, success);
+        x = firstGlyph + 2;
+
+        while (x < lastGlyph) {
+            glyphStorage[x - 2] = glyphStorage[x];
+            ix = glyphStorage.getCharIndex(x, success);
+            glyphStorage.setCharIndex(x - 2, ix, success);
+            x += 1;
+        }
+
+        glyphStorage[firstGlyph] = d;
+        glyphStorage[lastGlyph - 1] = a;
+        glyphStorage[lastGlyph] = b;
+
+        glyphStorage.setCharIndex(firstGlyph, id, success);
+        glyphStorage.setCharIndex(lastGlyph - 1, ia, success);
+        glyphStorage.setCharIndex(lastGlyph, ib, success);
+        break;
+
+    case irvDxBA:
+        a = glyphStorage[firstGlyph];
+        b = glyphStorage[firstGlyph + 1];
+        d = glyphStorage[lastGlyph];
+        ia = glyphStorage.getCharIndex(firstGlyph, success);
+        ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
+        id = glyphStorage.getCharIndex(lastGlyph, success);
+        x = firstGlyph + 2;
+
+        while (x < lastGlyph) {
+            glyphStorage[x - 2] = glyphStorage[x];
+            ix = glyphStorage.getCharIndex(x, success);
+            glyphStorage.setCharIndex(x - 2, ix, success);
+            x += 1;
+        }
+
+        glyphStorage[firstGlyph] = d;
+        glyphStorage[lastGlyph - 1] = b;
+        glyphStorage[lastGlyph] = a;
+
+        glyphStorage.setCharIndex(firstGlyph, id, success);
+        glyphStorage.setCharIndex(lastGlyph - 1, ib, success);
+        glyphStorage.setCharIndex(lastGlyph, ia, success);
+        break;
+
+    case irvCDxAB:
+        a = glyphStorage[firstGlyph];
+        b = glyphStorage[firstGlyph + 1];
+
+        glyphStorage[firstGlyph] = glyphStorage[lastGlyph - 1];
+        glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph];
+
+        glyphStorage[lastGlyph - 1] = a;
+        glyphStorage[lastGlyph] = b;
+
+        ia = glyphStorage.getCharIndex(firstGlyph, success);
+        ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
+        ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
+        id = glyphStorage.getCharIndex(lastGlyph, success);
+
+        glyphStorage.setCharIndex(firstGlyph, ic, success);
+        glyphStorage.setCharIndex(firstGlyph + 1, id, success);
+
+        glyphStorage.setCharIndex(lastGlyph - 1, ia, success);
+        glyphStorage.setCharIndex(lastGlyph, ib, success);
+        break;
+
+    case irvCDxBA:
+        a = glyphStorage[firstGlyph];
+        b = glyphStorage[firstGlyph + 1];
+
+        glyphStorage[firstGlyph] = glyphStorage[lastGlyph - 1];
+        glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph];
+
+        glyphStorage[lastGlyph - 1] = b;
+        glyphStorage[lastGlyph] = a;
+
+        ia = glyphStorage.getCharIndex(firstGlyph, success);
+        ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
+        ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
+        id = glyphStorage.getCharIndex(lastGlyph, success);
+
+        glyphStorage.setCharIndex(firstGlyph, ic, success);
+        glyphStorage.setCharIndex(firstGlyph + 1, id, success);
+
+        glyphStorage.setCharIndex(lastGlyph - 1, ib, success);
+        glyphStorage.setCharIndex(lastGlyph, ia, success);
+        break;
+
+    case irvDCxAB:
+        a = glyphStorage[firstGlyph];
+        b = glyphStorage[firstGlyph + 1];
+
+        glyphStorage[firstGlyph] = glyphStorage[lastGlyph];
+        glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph - 1];
+
+        glyphStorage[lastGlyph - 1] = a;
+        glyphStorage[lastGlyph] = b;
+
+        ia = glyphStorage.getCharIndex(firstGlyph, success);
+        ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
+        ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
+        id = glyphStorage.getCharIndex(lastGlyph, success);
+
+        glyphStorage.setCharIndex(firstGlyph, id, success);
+        glyphStorage.setCharIndex(firstGlyph + 1, ic, success);
+
+        glyphStorage.setCharIndex(lastGlyph - 1, ia, success);
+        glyphStorage.setCharIndex(lastGlyph, ib, success);
+        break;
+
+    case irvDCxBA:
+        a = glyphStorage[firstGlyph];
+        b = glyphStorage[firstGlyph + 1];
+
+        glyphStorage[firstGlyph] = glyphStorage[lastGlyph];
+        glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph - 1];
+
+        glyphStorage[lastGlyph - 1] = b;
+        glyphStorage[lastGlyph] = a;
+
+        ia = glyphStorage.getCharIndex(firstGlyph, success);
+        ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
+        ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
+        id = glyphStorage.getCharIndex(lastGlyph, success);
+
+        glyphStorage.setCharIndex(firstGlyph, id, success);
+        glyphStorage.setCharIndex(firstGlyph + 1, ic, success);
+
+        glyphStorage.setCharIndex(lastGlyph - 1, ib, success);
+        glyphStorage.setCharIndex(lastGlyph, ia, success);
+        break;
+    
+    default:
+        break;
+    }
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/IndicRearrangementProcessor.h b/source/layout/IndicRearrangementProcessor.h
new file mode 100644
index 0000000..0cb46dd
--- /dev/null
+++ b/source/layout/IndicRearrangementProcessor.h
@@ -0,0 +1,63 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __INDICREARRANGEMENTPROCESSOR_H
+#define __INDICREARRANGEMENTPROCESSOR_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "SubtableProcessor.h"
+#include "StateTableProcessor.h"
+#include "IndicRearrangement.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+class IndicRearrangementProcessor : public StateTableProcessor
+{
+public:
+    virtual void beginStateTable();
+
+    virtual ByteOffset processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex index);
+
+    virtual void endStateTable();
+
+    void doRearrangementAction(LEGlyphStorage &glyphStorage, IndicRearrangementVerb verb) const;
+
+    IndicRearrangementProcessor(const MorphSubtableHeader *morphSubtableHeader);
+    virtual ~IndicRearrangementProcessor();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.8
+     */
+    static UClassID getStaticClassID();
+
+protected:
+    le_int32 firstGlyph;
+    le_int32 lastGlyph;
+
+    const IndicRearrangementStateEntry *entryTable;
+    const IndicRearrangementSubtableHeader *indicRearrangementSubtableHeader;
+
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/IndicReordering.cpp b/source/layout/IndicReordering.cpp
new file mode 100644
index 0000000..8f24768
--- /dev/null
+++ b/source/layout/IndicReordering.cpp
@@ -0,0 +1,1228 @@
+/*
+/ *
+ * (C) Copyright IBM Corp. 1998-2009 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "OpenTypeUtilities.h"
+#include "IndicReordering.h"
+#include "LEGlyphStorage.h"
+#include "MPreFixups.h"
+
+U_NAMESPACE_BEGIN
+
+#define loclFeatureTag LE_LOCL_FEATURE_TAG
+#define initFeatureTag LE_INIT_FEATURE_TAG
+#define nuktFeatureTag LE_NUKT_FEATURE_TAG
+#define akhnFeatureTag LE_AKHN_FEATURE_TAG
+#define rphfFeatureTag LE_RPHF_FEATURE_TAG
+#define rkrfFeatureTag LE_RKRF_FEATURE_TAG
+#define blwfFeatureTag LE_BLWF_FEATURE_TAG
+#define halfFeatureTag LE_HALF_FEATURE_TAG
+#define pstfFeatureTag LE_PSTF_FEATURE_TAG
+#define vatuFeatureTag LE_VATU_FEATURE_TAG
+#define presFeatureTag LE_PRES_FEATURE_TAG
+#define blwsFeatureTag LE_BLWS_FEATURE_TAG
+#define abvsFeatureTag LE_ABVS_FEATURE_TAG
+#define pstsFeatureTag LE_PSTS_FEATURE_TAG
+#define halnFeatureTag LE_HALN_FEATURE_TAG
+#define cjctFeatureTag LE_CJCT_FEATURE_TAG
+#define blwmFeatureTag LE_BLWM_FEATURE_TAG
+#define abvmFeatureTag LE_ABVM_FEATURE_TAG
+#define distFeatureTag LE_DIST_FEATURE_TAG
+#define caltFeatureTag LE_CALT_FEATURE_TAG
+#define kernFeatureTag LE_KERN_FEATURE_TAG
+
+#define loclFeatureMask 0x80000000UL
+#define rphfFeatureMask 0x40000000UL
+#define blwfFeatureMask 0x20000000UL
+#define halfFeatureMask 0x10000000UL
+#define pstfFeatureMask 0x08000000UL
+#define nuktFeatureMask 0x04000000UL
+#define akhnFeatureMask 0x02000000UL
+#define vatuFeatureMask 0x01000000UL
+#define presFeatureMask 0x00800000UL
+#define blwsFeatureMask 0x00400000UL
+#define abvsFeatureMask 0x00200000UL
+#define pstsFeatureMask 0x00100000UL 
+#define halnFeatureMask 0x00080000UL
+#define blwmFeatureMask 0x00040000UL
+#define abvmFeatureMask 0x00020000UL
+#define distFeatureMask 0x00010000UL
+#define initFeatureMask 0x00008000UL
+#define cjctFeatureMask 0x00004000UL
+#define rkrfFeatureMask 0x00002000UL
+#define caltFeatureMask 0x00001000UL
+#define kernFeatureMask 0x00000800UL
+
+// Syllable structure bits 
+#define baseConsonantMask       0x00000400UL
+#define consonantMask           0x00000200UL
+#define halfConsonantMask       0x00000100UL
+#define rephConsonantMask       0x00000080UL
+#define matraMask               0x00000040UL
+#define vowelModifierMask       0x00000020UL
+#define markPositionMask        0x00000018UL
+
+#define postBasePosition        0x00000000UL
+#define preBasePosition         0x00000008UL
+#define aboveBasePosition       0x00000010UL
+#define belowBasePosition       0x00000018UL
+
+#define repositionedGlyphMask   0x00000002UL
+
+#define basicShapingFormsMask ( loclFeatureMask | nuktFeatureMask | akhnFeatureMask | rkrfFeatureMask | blwfFeatureMask | halfFeatureMask | vatuFeatureMask | cjctFeatureMask )
+#define positioningFormsMask ( kernFeatureMask | distFeatureMask | abvmFeatureMask | blwmFeatureMask )
+#define presentationFormsMask ( presFeatureMask | abvsFeatureMask | blwsFeatureMask | pstsFeatureMask | halnFeatureMask | caltFeatureMask )
+
+
+#define C_MALAYALAM_VOWEL_SIGN_U 0x0D41
+#define	C_DOTTED_CIRCLE 0x25CC
+#define NO_GLYPH 0xFFFF
+
+// Some level of debate as to the proper value for MAX_CONSONANTS_PER_SYLLABLE.  Ticket 5588 states that 4
+// is the magic number according to ISCII, but 5 seems to be the more consistent with XP.
+#define MAX_CONSONANTS_PER_SYLLABLE 5
+
+#define INDIC_BLOCK_SIZE 0x7F
+
+class IndicReorderingOutput : public UMemory {
+private:
+    le_int32   fSyllableCount;
+    le_int32   fOutIndex;
+    LEUnicode *fOutChars;
+
+    LEGlyphStorage &fGlyphStorage;
+
+    LEUnicode   fMpre;
+    le_int32    fMpreIndex;
+
+    LEUnicode   fMbelow;
+    le_int32    fMbelowIndex;
+
+    LEUnicode   fMabove;
+    le_int32    fMaboveIndex;
+
+    LEUnicode   fMpost;
+    le_int32    fMpostIndex;
+
+    LEUnicode   fLengthMark;
+    le_int32    fLengthMarkIndex;
+
+    LEUnicode   fAlLakuna;
+    le_int32    fAlLakunaIndex;
+
+    FeatureMask fMatraFeatures;
+    
+    le_int32    fMPreOutIndex;
+    MPreFixups *fMPreFixups;
+    
+    LEUnicode   fVMabove;
+    LEUnicode   fVMpost;
+    le_int32    fVMIndex;
+    FeatureMask fVMFeatures;
+    
+    LEUnicode   fSMabove;
+    LEUnicode   fSMbelow;
+    le_int32    fSMIndex;
+    FeatureMask fSMFeatures;
+
+    LEUnicode   fPreBaseConsonant;
+    LEUnicode   fPreBaseVirama;
+    le_int32    fPBCIndex;
+    FeatureMask fPBCFeatures;
+
+    void saveMatra(LEUnicode matra, le_int32 matraIndex, IndicClassTable::CharClass matraClass)
+    {
+        // FIXME: check if already set, or if not a matra...
+        if (IndicClassTable::isLengthMark(matraClass)) {
+            fLengthMark = matra;
+            fLengthMarkIndex = matraIndex;
+        } else if (IndicClassTable::isAlLakuna(matraClass)) {
+            fAlLakuna = matra;
+            fAlLakunaIndex = matraIndex;
+        } else {
+            switch (matraClass & CF_POS_MASK) {
+            case CF_POS_BEFORE:
+                fMpre = matra;
+                fMpreIndex = matraIndex;
+                break;
+               
+            case CF_POS_BELOW:
+                fMbelow = matra;
+                fMbelowIndex = matraIndex;
+                break;
+               
+            case CF_POS_ABOVE:
+                fMabove = matra;
+                fMaboveIndex = matraIndex;
+                break;
+               
+            case CF_POS_AFTER:
+                fMpost = matra;
+                fMpostIndex = matraIndex;
+                break;
+               
+            default:
+                // can't get here...
+                break;
+           }
+        }
+    }
+
+public:
+    IndicReorderingOutput(LEUnicode *outChars, LEGlyphStorage &glyphStorage, MPreFixups *mpreFixups)
+        : fSyllableCount(0), fOutIndex(0), fOutChars(outChars), fGlyphStorage(glyphStorage),
+          fMpre(0), fMpreIndex(0), fMbelow(0), fMbelowIndex(0), fMabove(0), fMaboveIndex(0),
+          fMpost(0), fMpostIndex(0), fLengthMark(0), fLengthMarkIndex(0), fAlLakuna(0), fAlLakunaIndex(0),
+          fMatraFeatures(0), fMPreOutIndex(-1), fMPreFixups(mpreFixups),
+          fVMabove(0), fVMpost(0), fVMIndex(0), fVMFeatures(0),
+          fSMabove(0), fSMbelow(0), fSMIndex(0), fSMFeatures(0),
+          fPreBaseConsonant(0), fPreBaseVirama(0), fPBCIndex(0), fPBCFeatures(0)
+    {
+        // nothing else to do...
+    }
+
+    ~IndicReorderingOutput()
+    {
+        // nothing to do here...
+    }
+
+    void reset()
+    {
+        fSyllableCount += 1;
+
+        fMpre = fMbelow = fMabove = fMpost = fLengthMark = fAlLakuna = 0;
+        fMPreOutIndex = -1;
+        
+        fVMabove = fVMpost  = 0;
+        fSMabove = fSMbelow = 0;
+
+        fPreBaseConsonant = fPreBaseVirama = 0;
+    }
+
+    void writeChar(LEUnicode ch, le_uint32 charIndex, FeatureMask charFeatures)
+    {
+        LEErrorCode success = LE_NO_ERROR;
+
+        fOutChars[fOutIndex] = ch;
+
+        fGlyphStorage.setCharIndex(fOutIndex, charIndex, success);
+        fGlyphStorage.setAuxData(fOutIndex, charFeatures | (fSyllableCount & LE_GLYPH_GROUP_MASK), success);
+
+        fOutIndex += 1;
+    }
+
+    void setFeatures ( le_uint32 charIndex, FeatureMask charFeatures)
+    {
+        LEErrorCode success = LE_NO_ERROR;
+
+        fGlyphStorage.setAuxData( charIndex, charFeatures, success );
+
+    }
+
+    FeatureMask getFeatures ( le_uint32 charIndex )
+    {
+        LEErrorCode success = LE_NO_ERROR;
+        return fGlyphStorage.getAuxData(charIndex,success);
+    }
+
+	void decomposeReorderMatras ( const IndicClassTable *classTable, le_int32 beginSyllable, le_int32 nextSyllable, le_int32 inv_count ) {
+		le_int32 i;
+        LEErrorCode success = LE_NO_ERROR;
+
+		for ( i = beginSyllable ; i < nextSyllable ; i++ ) {
+			if ( classTable->isMatra(fOutChars[i+inv_count])) {
+				IndicClassTable::CharClass matraClass = classTable->getCharClass(fOutChars[i+inv_count]);	
+				if ( classTable->isSplitMatra(matraClass)) {
+					le_int32 saveIndex = fGlyphStorage.getCharIndex(i+inv_count,success);
+					le_uint32 saveAuxData = fGlyphStorage.getAuxData(i+inv_count,success);
+                    const SplitMatra *splitMatra = classTable->getSplitMatra(matraClass);
+                    int j;
+                    for (j = 0 ; *(splitMatra)[j] != 0 ; j++) {
+                        LEUnicode piece = (*splitMatra)[j];
+						if ( j == 0 ) {
+							fOutChars[i+inv_count] = piece;
+							matraClass = classTable->getCharClass(piece);
+						} else {
+							insertCharacter(piece,i+1+inv_count,saveIndex,saveAuxData);
+							nextSyllable++;
+						}
+ 				    }
+				}
+				
+				if ((matraClass & CF_POS_MASK) == CF_POS_BEFORE) {
+                    moveCharacter(i+inv_count,beginSyllable+inv_count);
+				}
+			}
+		}
+	}
+
+	void moveCharacter( le_int32 fromPosition, le_int32 toPosition ) {
+		le_int32 i,saveIndex;
+		le_uint32 saveAuxData;
+		LEUnicode saveChar = fOutChars[fromPosition];
+	    LEErrorCode success = LE_NO_ERROR;
+		LEErrorCode success2 = LE_NO_ERROR;
+		saveIndex = fGlyphStorage.getCharIndex(fromPosition,success);
+        saveAuxData = fGlyphStorage.getAuxData(fromPosition,success);
+
+		if ( fromPosition > toPosition ) {
+			for ( i = fromPosition ; i > toPosition ; i-- ) {
+				fOutChars[i] = fOutChars[i-1];
+				fGlyphStorage.setCharIndex(i,fGlyphStorage.getCharIndex(i-1,success2),success);
+				fGlyphStorage.setAuxData(i,fGlyphStorage.getAuxData(i-1,success2), success);
+
+			}
+		} else {
+			for ( i = fromPosition ; i < toPosition ; i++ ) {
+				fOutChars[i] = fOutChars[i+1];
+				fGlyphStorage.setCharIndex(i,fGlyphStorage.getCharIndex(i+1,success2),success);
+				fGlyphStorage.setAuxData(i,fGlyphStorage.getAuxData(i+1,success2), success);
+			}
+
+		}
+		fOutChars[toPosition] = saveChar;
+		fGlyphStorage.setCharIndex(toPosition,saveIndex,success);
+		fGlyphStorage.setAuxData(toPosition,saveAuxData,success);
+
+	}
+	void insertCharacter( LEUnicode ch, le_int32 toPosition, le_int32 charIndex, le_uint32 auxData ) {
+	    LEErrorCode success = LE_NO_ERROR;
+        le_int32 i;
+		fOutIndex += 1;
+
+		for ( i = fOutIndex ; i > toPosition ; i--) {
+				fOutChars[i] = fOutChars[i-1];
+				fGlyphStorage.setCharIndex(i,fGlyphStorage.getCharIndex(i-1,success),success);
+				fGlyphStorage.setAuxData(i,fGlyphStorage.getAuxData(i-1,success), success);
+		}
+
+		fOutChars[toPosition] = ch;
+		fGlyphStorage.setCharIndex(toPosition,charIndex,success);
+		fGlyphStorage.setAuxData(toPosition,auxData,success);
+
+	}
+	void removeCharacter( le_int32 fromPosition ) {
+	    LEErrorCode success = LE_NO_ERROR;
+        le_int32 i;
+		fOutIndex -= 1;
+
+		for ( i = fromPosition ; i < fOutIndex ; i--) {
+				fOutChars[i] = fOutChars[i+1];
+				fGlyphStorage.setCharIndex(i,fGlyphStorage.getCharIndex(i+1,success),success);
+				fGlyphStorage.setAuxData(i,fGlyphStorage.getAuxData(i+1,success), success);
+		}
+	}
+
+    le_bool noteMatra(const IndicClassTable *classTable, LEUnicode matra, le_uint32 matraIndex, FeatureMask matraFeatures, le_bool wordStart)
+    {
+        IndicClassTable::CharClass matraClass = classTable->getCharClass(matra);
+
+        fMatraFeatures  = matraFeatures;
+
+        if (wordStart) {
+            fMatraFeatures |= initFeatureMask;
+        }
+
+        if (IndicClassTable::isMatra(matraClass)) {
+            if (IndicClassTable::isSplitMatra(matraClass)) {
+                const SplitMatra *splitMatra = classTable->getSplitMatra(matraClass);
+                int i;
+
+                for (i = 0; i < 3 && (*splitMatra)[i] != 0; i += 1) {
+                    LEUnicode piece = (*splitMatra)[i];
+                    IndicClassTable::CharClass pieceClass = classTable->getCharClass(piece);
+
+                    saveMatra(piece, matraIndex, pieceClass);
+                }
+            } else {
+                saveMatra(matra, matraIndex, matraClass);
+            }
+
+            return TRUE;
+        }
+
+        return FALSE;
+    }
+    
+    void noteVowelModifier(const IndicClassTable *classTable, LEUnicode vowelModifier, le_uint32 vowelModifierIndex, FeatureMask vowelModifierFeatures)
+    {
+        IndicClassTable::CharClass vmClass = classTable->getCharClass(vowelModifier);
+        
+        fVMIndex = vowelModifierIndex;
+        fVMFeatures  = vowelModifierFeatures;
+        
+        if (IndicClassTable::isVowelModifier(vmClass)) {
+           switch (vmClass & CF_POS_MASK) {
+           case CF_POS_ABOVE:
+               fVMabove = vowelModifier;
+               break;
+            
+           case CF_POS_AFTER:
+               fVMpost = vowelModifier;
+               break;
+           
+           default:
+               // FIXME: this is an error...
+               break;
+           }
+        }
+    }
+    
+    void noteStressMark(const IndicClassTable *classTable, LEUnicode stressMark, le_uint32 stressMarkIndex, FeatureMask stressMarkFeatures)
+    {
+       IndicClassTable::CharClass smClass = classTable->getCharClass(stressMark);
+        
+        fSMIndex = stressMarkIndex;
+        fSMFeatures  = stressMarkFeatures;
+        
+        if (IndicClassTable::isStressMark(smClass)) {
+            switch (smClass & CF_POS_MASK) {
+            case CF_POS_ABOVE:
+                fSMabove = stressMark;
+                break;
+            
+            case CF_POS_BELOW:
+                fSMbelow = stressMark;
+                break;
+           
+            default:
+                // FIXME: this is an error...
+                break;
+           }
+        }
+    }
+
+    void notePreBaseConsonant(le_uint32 index,LEUnicode PBConsonant, LEUnicode PBVirama, FeatureMask features)
+    {
+        fPBCIndex = index;
+        fPreBaseConsonant = PBConsonant;
+        fPreBaseVirama = PBVirama;
+        fPBCFeatures = features;
+    }
+
+    void noteBaseConsonant()
+    {
+        if (fMPreFixups != NULL && fMPreOutIndex >= 0) {
+            fMPreFixups->add(fOutIndex, fMPreOutIndex);
+        }
+    }
+
+    // Handles Al-Lakuna in Sinhala split vowels.
+    void writeAlLakuna()
+    {
+        if (fAlLakuna != 0) {
+            writeChar(fAlLakuna, fAlLakunaIndex, fMatraFeatures);
+        }
+    }
+
+    void writeMpre()
+    {
+        if (fMpre != 0) {
+            fMPreOutIndex = fOutIndex;
+            writeChar(fMpre, fMpreIndex, fMatraFeatures);
+        }
+    }
+
+    void writeMbelow()
+    {
+        if (fMbelow != 0) {
+            writeChar(fMbelow, fMbelowIndex, fMatraFeatures);
+        }
+    }
+
+    void writeMabove()
+    {
+        if (fMabove != 0) {
+            writeChar(fMabove, fMaboveIndex, fMatraFeatures);
+        }
+    }
+
+    void writeMpost()
+    {
+        if (fMpost != 0) {
+            writeChar(fMpost, fMpostIndex, fMatraFeatures);
+        }
+    }
+
+    void writeLengthMark()
+    {
+        if (fLengthMark != 0) {
+            writeChar(fLengthMark, fLengthMarkIndex, fMatraFeatures);
+        }
+    }
+    
+    void writeVMabove()
+    {
+        if (fVMabove != 0) {
+            writeChar(fVMabove, fVMIndex, fVMFeatures);
+        }
+    }
+        
+    void writeVMpost()
+    {
+        if (fVMpost != 0) {
+            writeChar(fVMpost, fVMIndex, fVMFeatures);
+        }
+    }
+    
+    void writeSMabove()
+    {
+        if (fSMabove != 0) {
+            writeChar(fSMabove, fSMIndex, fSMFeatures);
+        }
+    }
+    
+    void writeSMbelow()
+    {
+        if (fSMbelow != 0) {
+            writeChar(fSMbelow, fSMIndex, fSMFeatures);
+        }
+    }
+    
+    void writePreBaseConsonant()
+    {
+        // The TDIL spec says that consonant + virama + RRA should produce a rakar in Malayalam.  However,
+        // it seems that almost none of the fonts for Malayalam are set up to handle this.
+        // So, we're going to force the issue here by using the rakar as defined with RA in most fonts.
+
+        if (fPreBaseConsonant == 0x0d31) { // RRA
+            fPreBaseConsonant = 0x0d30; // RA
+        }
+        
+        if (fPreBaseConsonant != 0) {
+            writeChar(fPreBaseConsonant, fPBCIndex, fPBCFeatures);
+            writeChar(fPreBaseVirama,fPBCIndex-1,fPBCFeatures);
+        }
+    }
+
+    le_int32 getOutputIndex()
+    {
+        return fOutIndex;
+    }
+};
+
+
+
+// TODO: Find better names for these!
+#define tagArray4 (loclFeatureMask | nuktFeatureMask | akhnFeatureMask | vatuFeatureMask | presFeatureMask | blwsFeatureMask | abvsFeatureMask | pstsFeatureMask | halnFeatureMask | blwmFeatureMask | abvmFeatureMask | distFeatureMask)
+#define tagArray3 (pstfFeatureMask | tagArray4)
+#define tagArray2 (halfFeatureMask | tagArray3)
+#define tagArray1 (blwfFeatureMask | tagArray2)
+#define tagArray0 (rphfFeatureMask | tagArray1)
+
+static const FeatureMap featureMap[] = {
+    {loclFeatureTag, loclFeatureMask},
+    {initFeatureTag, initFeatureMask},
+    {nuktFeatureTag, nuktFeatureMask},
+    {akhnFeatureTag, akhnFeatureMask},
+    {rphfFeatureTag, rphfFeatureMask},
+    {blwfFeatureTag, blwfFeatureMask},
+    {halfFeatureTag, halfFeatureMask},
+    {pstfFeatureTag, pstfFeatureMask},
+    {vatuFeatureTag, vatuFeatureMask},
+    {presFeatureTag, presFeatureMask},
+    {blwsFeatureTag, blwsFeatureMask},
+    {abvsFeatureTag, abvsFeatureMask},
+    {pstsFeatureTag, pstsFeatureMask},
+    {halnFeatureTag, halnFeatureMask},
+    {blwmFeatureTag, blwmFeatureMask},
+    {abvmFeatureTag, abvmFeatureMask},
+    {distFeatureTag, distFeatureMask}
+};
+
+static const le_int32 featureCount = LE_ARRAY_SIZE(featureMap);
+
+static const FeatureMap v2FeatureMap[] = {
+	{loclFeatureTag, loclFeatureMask},
+    {nuktFeatureTag, nuktFeatureMask},
+    {akhnFeatureTag, akhnFeatureMask},
+    {rphfFeatureTag, rphfFeatureMask},
+	{rkrfFeatureTag, rkrfFeatureMask}, 
+	{blwfFeatureTag, blwfFeatureMask},
+    {halfFeatureTag, halfFeatureMask},
+    {vatuFeatureTag, vatuFeatureMask},
+    {cjctFeatureTag, cjctFeatureMask},
+    {presFeatureTag, presFeatureMask},
+    {abvsFeatureTag, abvsFeatureMask},
+    {blwsFeatureTag, blwsFeatureMask},
+    {pstsFeatureTag, pstsFeatureMask},
+	{halnFeatureTag, halnFeatureMask}, 
+	{caltFeatureTag, caltFeatureMask},
+    {kernFeatureTag, kernFeatureMask},
+    {distFeatureTag, distFeatureMask},
+    {abvmFeatureTag, abvmFeatureMask},
+    {blwmFeatureTag, blwmFeatureMask}
+};
+
+static const le_int32 v2FeatureMapCount = LE_ARRAY_SIZE(v2FeatureMap);
+
+static const le_int8 stateTable[][CC_COUNT] =
+{
+//   xx  vm  sm  iv  i2  i3  ct  cn  nu  dv  s1  s2  s3  vr  zw  al
+    { 1,  6,  1,  5,  8, 11,  3,  2,  1,  5,  9,  5,  5,  1,  1,  1}, //  0 - ground state
+    {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, //  1 - exit state
+    {-1,  6,  1, -1, -1, -1, -1, -1, -1,  5,  9,  5,  5,  4, 12, -1}, //  2 - consonant with nukta
+    {-1,  6,  1, -1, -1, -1, -1, -1,  2,  5,  9,  5,  5,  4, 12, 13}, //  3 - consonant
+    {-1, -1, -1, -1, -1, -1,  3,  2, -1, -1, -1, -1, -1, -1,  7, -1}, //  4 - consonant virama
+    {-1,  6,  1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, //  5 - dependent vowels
+    {-1, -1,  1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, //  6 - vowel mark
+    {-1, -1, -1, -1, -1, -1,  3,  2, -1, -1, -1, -1, -1, -1, -1, -1}, //  7 - consonant virama ZWJ, consonant ZWJ virama
+    {-1,  6,  1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  4, -1, -1}, //  8 - independent vowels that can take a virama
+    {-1,  6,  1, -1, -1, -1, -1, -1, -1, -1, -1, 10,  5, -1, -1, -1}, //  9 - first part of split vowel
+    {-1,  6,  1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  5, -1, -1, -1}, // 10 - second part of split vowel
+    {-1,  6,  1, -1, -1, -1, -1, -1, -1,  5,  9,  5,  5,  4, -1, -1}, // 11 - independent vowels that can take an iv
+    {-1, -1,  1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  7, -1,  7}, // 12 - consonant ZWJ (TODO: Take everything else that can be after a consonant?)
+    {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  7, -1}  // 13 - consonant al-lakuna ZWJ consonant
+};
+
+
+const FeatureMap *IndicReordering::getFeatureMap(le_int32 &count)
+{
+    count = featureCount;
+
+    return featureMap;
+}
+
+const FeatureMap *IndicReordering::getv2FeatureMap(le_int32 &count)
+{
+    count = v2FeatureMapCount;
+
+    return v2FeatureMap;
+}
+
+le_int32 IndicReordering::findSyllable(const IndicClassTable *classTable, const LEUnicode *chars, le_int32 prev, le_int32 charCount)
+{
+    le_int32 cursor = prev;
+    le_int8 state = 0;
+    le_int8 consonant_count = 0;
+
+    while (cursor < charCount) {
+        IndicClassTable::CharClass charClass = classTable->getCharClass(chars[cursor]);
+        
+        if ( IndicClassTable::isConsonant(charClass) ) {
+            consonant_count++;
+            if ( consonant_count > MAX_CONSONANTS_PER_SYLLABLE ) {
+                break;
+            }
+        }
+
+        state = stateTable[state][charClass & CF_CLASS_MASK];
+
+        if (state < 0) {
+            break;
+        }
+
+        cursor += 1;
+    }
+
+    return cursor;
+}
+
+le_int32 IndicReordering::reorder(const LEUnicode *chars, le_int32 charCount, le_int32 scriptCode,
+                                  LEUnicode *outChars, LEGlyphStorage &glyphStorage,
+                                  MPreFixups **outMPreFixups, LEErrorCode& success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    MPreFixups *mpreFixups = NULL;
+    const IndicClassTable *classTable = IndicClassTable::getScriptClassTable(scriptCode);
+
+    if (classTable->scriptFlags & SF_MPRE_FIXUP) {
+        mpreFixups = new MPreFixups(charCount);
+        if (mpreFixups == NULL) { 
+            success = LE_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+    }
+
+    IndicReorderingOutput output(outChars, glyphStorage, mpreFixups);
+    le_int32 i, prev = 0;
+    le_bool lastInWord = FALSE;
+
+    while (prev < charCount) {
+        le_int32 syllable = findSyllable(classTable, chars, prev, charCount);
+        le_int32 matra, markStart = syllable;
+
+        output.reset();
+        
+        if (classTable->isStressMark(chars[markStart - 1])) {
+            markStart -= 1;
+            output.noteStressMark(classTable, chars[markStart], markStart, tagArray1);
+        }
+        
+        if (markStart != prev && classTable->isVowelModifier(chars[markStart - 1])) {
+            markStart -= 1;
+            output.noteVowelModifier(classTable, chars[markStart], markStart, tagArray1);
+        }
+
+        matra = markStart - 1;
+
+        while (output.noteMatra(classTable, chars[matra], matra, tagArray1, !lastInWord) && matra != prev) {
+            matra -= 1;
+        }
+
+        lastInWord = TRUE;
+
+        switch (classTable->getCharClass(chars[prev]) & CF_CLASS_MASK) {
+        case CC_RESERVED:
+            lastInWord = FALSE;
+            /* fall through */
+
+        case CC_INDEPENDENT_VOWEL:
+        case CC_ZERO_WIDTH_MARK:
+            for (i = prev; i < syllable; i += 1) {
+                output.writeChar(chars[i], i, tagArray1);
+            }
+
+            break;
+
+        case CC_AL_LAKUNA:
+        case CC_NUKTA:
+            output.writeChar(C_DOTTED_CIRCLE, prev, tagArray1);
+            output.writeChar(chars[prev], prev, tagArray1);
+            break;
+
+        case CC_VIRAMA:
+            // A lone virama is illegal unless it follows a
+            // MALAYALAM_VOWEL_SIGN_U. Such a usage is called
+            // "samvruthokaram".
+            if (chars[prev - 1] != C_MALAYALAM_VOWEL_SIGN_U) {
+                output.writeChar(C_DOTTED_CIRCLE, prev, tagArray1);
+            }
+
+            output.writeChar(chars[prev], prev, tagArray1);
+            break;
+
+        case CC_DEPENDENT_VOWEL:
+        case CC_SPLIT_VOWEL_PIECE_1:
+        case CC_SPLIT_VOWEL_PIECE_2:
+        case CC_SPLIT_VOWEL_PIECE_3:
+        case CC_VOWEL_MODIFIER:
+        case CC_STRESS_MARK:
+            output.writeMpre();
+
+            output.writeChar(C_DOTTED_CIRCLE, prev, tagArray1);
+
+            output.writeMbelow();
+            output.writeSMbelow();
+            output.writeMabove();
+
+            if ((classTable->scriptFlags & SF_MATRAS_AFTER_BASE) != 0) {
+                output.writeMpost();
+            }
+
+            if ((classTable->scriptFlags & SF_REPH_AFTER_BELOW) != 0) {
+                output.writeVMabove();
+                output.writeSMabove(); // FIXME: there are no SM's in these scripts...
+            }
+
+            if ((classTable->scriptFlags & SF_MATRAS_AFTER_BASE) == 0) {
+                output.writeMpost();
+            }
+
+            output.writeLengthMark();
+            output.writeAlLakuna();
+
+            if ((classTable->scriptFlags & SF_REPH_AFTER_BELOW) == 0) {
+                output.writeVMabove();
+                output.writeSMabove();
+            }
+
+            output.writeVMpost();
+            break;
+
+        case CC_INDEPENDENT_VOWEL_2:
+        case CC_INDEPENDENT_VOWEL_3:
+        case CC_CONSONANT:
+        case CC_CONSONANT_WITH_NUKTA:
+        {
+            le_uint32 length = markStart - prev;
+            le_int32  lastConsonant = markStart - 1;
+            le_int32  baseLimit = prev;
+
+            // Check for REPH at front of syllable
+            if (length > 2 && classTable->isReph(chars[prev]) && classTable->isVirama(chars[prev + 1]) && chars[prev + 2] != C_SIGN_ZWNJ) {
+                baseLimit += 2;
+
+                // Check for eyelash RA, if the script supports it
+                if ((classTable->scriptFlags & SF_EYELASH_RA) != 0 &&
+                    chars[baseLimit] == C_SIGN_ZWJ) {
+                    if (length > 3) {
+                        baseLimit += 1;
+                    } else {
+                        baseLimit -= 2;
+                    }
+                }
+            }
+
+            while (lastConsonant > baseLimit && !classTable->isConsonant(chars[lastConsonant])) {
+                lastConsonant -= 1;
+            }
+
+            
+            IndicClassTable::CharClass charClass = CC_RESERVED;
+            IndicClassTable::CharClass nextClass = CC_RESERVED;
+            le_int32 baseConsonant = lastConsonant;
+            le_int32 postBase = lastConsonant + 1;
+            le_int32 postBaseLimit = classTable->scriptFlags & SF_POST_BASE_LIMIT_MASK;
+            le_bool  seenVattu = FALSE;
+            le_bool  seenBelowBaseForm = FALSE;
+            le_bool  seenPreBaseForm = FALSE;
+            le_bool  hasNukta = FALSE;
+            le_bool  hasBelowBaseForm = FALSE;
+            le_bool  hasPostBaseForm = FALSE;
+            le_bool  hasPreBaseForm = FALSE;
+
+            if (postBase < markStart && classTable->isNukta(chars[postBase])) {
+                charClass = CC_NUKTA;
+                postBase += 1;
+            }
+
+            while (baseConsonant > baseLimit) {
+                nextClass = charClass;
+                hasNukta  = IndicClassTable::isNukta(nextClass);
+                charClass = classTable->getCharClass(chars[baseConsonant]);
+
+                hasBelowBaseForm = IndicClassTable::hasBelowBaseForm(charClass) && !hasNukta;
+                hasPostBaseForm  = IndicClassTable::hasPostBaseForm(charClass)  && !hasNukta;
+                hasPreBaseForm = IndicClassTable::hasPreBaseForm(charClass) && !hasNukta;
+
+                if (IndicClassTable::isConsonant(charClass)) {
+                    if (postBaseLimit == 0 || seenVattu ||
+                        (baseConsonant > baseLimit && !classTable->isVirama(chars[baseConsonant - 1])) ||
+                        !(hasBelowBaseForm || hasPostBaseForm || hasPreBaseForm)) {
+                        break;
+                    }
+
+                    // Note any pre-base consonants
+                    if ( baseConsonant == lastConsonant && lastConsonant > 0 && 
+                         hasPreBaseForm && classTable->isVirama(chars[baseConsonant - 1])) {
+                        output.notePreBaseConsonant(lastConsonant,chars[lastConsonant],chars[lastConsonant-1],tagArray2);
+                        seenPreBaseForm = TRUE;
+   
+                    }
+                    // consonants with nuktas are never vattus
+                    seenVattu = IndicClassTable::isVattu(charClass) && !hasNukta;
+
+                    // consonants with nuktas never have below- or post-base forms
+                    if (hasPostBaseForm) {
+                        if (seenBelowBaseForm) {
+                            break;
+                        }
+
+                        postBase = baseConsonant;
+                    } else if (hasBelowBaseForm) {
+                        seenBelowBaseForm = TRUE;
+                    }
+
+                    postBaseLimit -= 1;
+                }
+
+                baseConsonant -= 1;
+            }
+
+            // Write Mpre
+            output.writeMpre();
+
+            // Write eyelash RA
+            // NOTE: baseLimit == prev + 3 iff eyelash RA present...
+            if (baseLimit == prev + 3) {
+                output.writeChar(chars[prev], prev, tagArray2);
+                output.writeChar(chars[prev + 1], prev + 1, tagArray2);
+                output.writeChar(chars[prev + 2], prev + 2, tagArray2);
+            }
+
+            // write any pre-base consonants
+            output.writePreBaseConsonant();
+
+            le_bool supressVattu = TRUE;
+
+            for (i = baseLimit; i < baseConsonant; i += 1) {
+                LEUnicode ch = chars[i];
+                // Don't put 'pstf' or 'blwf' on anything before the base consonant.
+                FeatureMask features = tagArray1 & ~( pstfFeatureMask | blwfFeatureMask );
+
+                charClass = classTable->getCharClass(ch);
+                nextClass = classTable->getCharClass(chars[i + 1]);
+                hasNukta  = IndicClassTable::isNukta(nextClass);
+
+                if (IndicClassTable::isConsonant(charClass)) {
+                    if (IndicClassTable::isVattu(charClass) && !hasNukta && supressVattu) {
+                        features = tagArray4;
+                    }
+
+                    supressVattu = IndicClassTable::isVattu(charClass) && !hasNukta;
+                } else if (IndicClassTable::isVirama(charClass) && chars[i + 1] == C_SIGN_ZWNJ)
+                {
+                    features = tagArray4;
+                }
+
+                output.writeChar(ch, i, features);
+            }
+
+            le_int32 bcSpan = baseConsonant + 1;
+
+            if (bcSpan < markStart && classTable->isNukta(chars[bcSpan])) {
+                bcSpan += 1;
+            }
+
+            if (baseConsonant == lastConsonant && bcSpan < markStart &&
+                 (classTable->isVirama(chars[bcSpan]) || classTable->isAlLakuna(chars[bcSpan]))) {
+                bcSpan += 1;
+
+                if (bcSpan < markStart && chars[bcSpan] == C_SIGN_ZWNJ) {
+                    bcSpan += 1;
+                }
+            }
+
+            // note the base consonant for post-GSUB fixups
+            output.noteBaseConsonant();
+
+            // write base consonant
+            for (i = baseConsonant; i < bcSpan; i += 1) {
+                output.writeChar(chars[i], i, tagArray4);
+            }
+
+            if ((classTable->scriptFlags & SF_MATRAS_AFTER_BASE) != 0) {
+                output.writeMbelow();
+                output.writeSMbelow(); // FIXME: there are no SMs in these scripts...
+                output.writeMabove();
+                output.writeMpost();
+            }
+
+            // write below-base consonants
+            if (baseConsonant != lastConsonant && !seenPreBaseForm) {
+                for (i = bcSpan + 1; i < postBase; i += 1) {
+                    output.writeChar(chars[i], i, tagArray1);
+                }
+
+                if (postBase > lastConsonant) {
+                    // write halant that was after base consonant
+                    output.writeChar(chars[bcSpan], bcSpan, tagArray1);
+                }
+            }
+
+            // write Mbelow, SMbelow, Mabove
+            if ((classTable->scriptFlags & SF_MATRAS_AFTER_BASE) == 0) {
+                output.writeMbelow();
+                output.writeSMbelow();
+                output.writeMabove();
+            }
+
+            if ((classTable->scriptFlags & SF_REPH_AFTER_BELOW) != 0) {
+                if (baseLimit == prev + 2) {
+                    output.writeChar(chars[prev], prev, tagArray0);
+                    output.writeChar(chars[prev + 1], prev + 1, tagArray0);
+                }
+
+                output.writeVMabove();
+                output.writeSMabove(); // FIXME: there are no SM's in these scripts...
+            }
+
+            // write post-base consonants
+            // FIXME: does this put the right tags on post-base consonants?
+            if (baseConsonant != lastConsonant && !seenPreBaseForm) {
+                if (postBase <= lastConsonant) {
+                    for (i = postBase; i <= lastConsonant; i += 1) {
+                        output.writeChar(chars[i], i, tagArray3);
+                    }
+
+                    // write halant that was after base consonant
+                    output.writeChar(chars[bcSpan], bcSpan, tagArray1);
+                }
+
+                // write the training halant, if there is one
+                if (lastConsonant < matra && classTable->isVirama(chars[matra])) {
+                    output.writeChar(chars[matra], matra, tagArray4);
+                }
+            }
+
+            // write Mpost
+            if ((classTable->scriptFlags & SF_MATRAS_AFTER_BASE) == 0) {
+                output.writeMpost();
+            }
+
+            output.writeLengthMark();
+            output.writeAlLakuna();
+
+            // write reph
+            if ((classTable->scriptFlags & SF_REPH_AFTER_BELOW) == 0) {
+                if (baseLimit == prev + 2) {
+                    output.writeChar(chars[prev], prev, tagArray0);
+                    output.writeChar(chars[prev + 1], prev + 1, tagArray0);
+                }
+
+                output.writeVMabove();
+                output.writeSMabove();
+            }
+
+            output.writeVMpost();
+
+            break;
+        }
+
+        default:
+            break;
+        }
+
+        prev = syllable;
+    }
+
+    *outMPreFixups = mpreFixups;
+
+    return output.getOutputIndex();
+}
+
+void IndicReordering::adjustMPres(MPreFixups *mpreFixups, LEGlyphStorage &glyphStorage, LEErrorCode& success)
+{
+    if (mpreFixups != NULL) {
+        mpreFixups->apply(glyphStorage, success);
+        
+        delete mpreFixups;
+    }
+}
+
+void IndicReordering::applyPresentationForms(LEGlyphStorage &glyphStorage, le_int32 count)
+{
+    LEErrorCode success = LE_NO_ERROR;
+
+//  This sets us up for 2nd pass of glyph substitution as well as setting the feature masks for the
+//  GPOS table lookups
+
+    for ( le_int32 i = 0 ; i < count ; i++ ) {
+        glyphStorage.setAuxData(i, ( presentationFormsMask | positioningFormsMask ), success);
+    }
+
+}
+void IndicReordering::finalReordering(LEGlyphStorage &glyphStorage, le_int32 count)
+{
+    LEErrorCode success = LE_NO_ERROR;
+
+    // Reposition REPH as appropriate
+
+    for ( le_int32 i = 0 ; i < count ; i++ ) {
+
+        le_int32 tmpAuxData = glyphStorage.getAuxData(i,success);
+        LEGlyphID tmpGlyph = glyphStorage.getGlyphID(i,success);
+
+        if ( ( tmpGlyph != NO_GLYPH ) && (tmpAuxData & rephConsonantMask) && !(tmpAuxData & repositionedGlyphMask))  {
+
+            le_bool targetPositionFound = false;
+            le_int32 targetPosition = i+1;
+            le_int32 baseConsonantData;
+
+            while (!targetPositionFound) {
+                tmpGlyph = glyphStorage.getGlyphID(targetPosition,success);
+                tmpAuxData = glyphStorage.getAuxData(targetPosition,success);
+
+                if ( tmpAuxData & baseConsonantMask ) {
+                    baseConsonantData = tmpAuxData;
+                    targetPositionFound = true;
+                } else {
+                    targetPosition++;
+                }
+            }
+
+            // Make sure we are not putting the reph into an empty hole
+
+            le_bool targetPositionHasGlyph = false;
+            while (!targetPositionHasGlyph) {
+                tmpGlyph = glyphStorage.getGlyphID(targetPosition,success);
+                if ( tmpGlyph != NO_GLYPH ) {
+                    targetPositionHasGlyph = true;
+                } else {
+                    targetPosition--;
+                }
+            }
+
+            // Make sure that REPH is positioned after any above base or post base matras
+            //
+            le_bool checkMatraDone = false;
+            le_int32 checkMatraPosition = targetPosition+1;
+            while ( !checkMatraDone ) {
+               tmpAuxData = glyphStorage.getAuxData(checkMatraPosition,success);
+               if ( checkMatraPosition >= count || ( (tmpAuxData ^ baseConsonantData) & LE_GLYPH_GROUP_MASK)) {
+                   checkMatraDone = true;
+                   continue;
+               }
+               if ( (tmpAuxData & matraMask) && 
+                    (((tmpAuxData & markPositionMask) == aboveBasePosition) || 
+                      ((tmpAuxData & markPositionMask) == postBasePosition))) {
+                   targetPosition = checkMatraPosition;                   
+               }
+               checkMatraPosition++;
+            }
+            
+            glyphStorage.moveGlyph(i,targetPosition,repositionedGlyphMask);
+        }
+    }
+}
+
+
+le_int32 IndicReordering::v2process(const LEUnicode *chars, le_int32 charCount, le_int32 scriptCode,
+                                  LEUnicode *outChars, LEGlyphStorage &glyphStorage)
+{
+    const IndicClassTable *classTable = IndicClassTable::getScriptClassTable(scriptCode);
+
+    DynamicProperties dynProps[INDIC_BLOCK_SIZE];
+    IndicReordering::getDynamicProperties(dynProps,classTable);
+
+    IndicReorderingOutput output(outChars, glyphStorage, NULL);
+    le_int32 i, firstConsonant, baseConsonant, secondConsonant, inv_count = 0, beginSyllable = 0;
+    //le_bool lastInWord = FALSE;
+
+    while (beginSyllable < charCount) {
+        le_int32 nextSyllable = findSyllable(classTable, chars, beginSyllable, charCount);
+
+        output.reset();
+
+		// Find the First Consonant
+		for ( firstConsonant = beginSyllable ; firstConsonant < nextSyllable ; firstConsonant++ ) {
+			 if ( classTable->isConsonant(chars[firstConsonant]) ) {
+					break;
+				}
+		}
+
+        // Find the base consonant
+
+        baseConsonant = nextSyllable - 1;
+        secondConsonant = firstConsonant;
+
+        // TODO: Use Dynamic Properties for hasBelowBaseForm and hasPostBaseForm()
+
+        while ( baseConsonant > firstConsonant ) {
+            if ( classTable->isConsonant(chars[baseConsonant]) && 
+                 !classTable->hasBelowBaseForm(chars[baseConsonant]) && 
+                 !classTable->hasPostBaseForm(chars[baseConsonant]) ) {
+                break;
+            }
+            else {
+                if ( classTable->isConsonant(chars[baseConsonant]) ) {
+                    secondConsonant = baseConsonant;
+                }
+                baseConsonant--;
+            }
+        }
+
+        // If the syllable starts with Ra + Halant ( in a script that has Reph ) and has more than one
+        // consonant, Ra is excluced from candidates for base consonants
+
+        if ( classTable->isReph(chars[beginSyllable]) &&
+             beginSyllable+1 < nextSyllable && classTable->isVirama(chars[beginSyllable+1]) &&
+             secondConsonant != firstConsonant) {
+            baseConsonant = secondConsonant;                     
+        }
+
+	    // Populate the output 
+		for ( i = beginSyllable ; i < nextSyllable ; i++ ) {
+
+            // Handle invalid combinartions
+
+            if ( classTable->isVirama(chars[beginSyllable]) || 
+			     classTable->isMatra(chars[beginSyllable]) ||
+			     classTable->isVowelModifier(chars[beginSyllable]) ||
+			     classTable->isNukta(chars[beginSyllable]) ) {
+                     output.writeChar(C_DOTTED_CIRCLE,beginSyllable,basicShapingFormsMask);
+                     inv_count++;
+            }
+             output.writeChar(chars[i],i, basicShapingFormsMask);
+
+        }
+
+        // Adjust features and set syllable structure bits
+
+        for ( i = beginSyllable ; i < nextSyllable ; i++ ) {
+
+            FeatureMask outMask = output.getFeatures(i+inv_count);
+            FeatureMask saveMask = outMask;
+
+            // Since reph can only validly occur at the beginning of a syllable
+            // We only apply it to the first 2 characters in the syllable, to keep it from
+            // conflicting with other features ( i.e. rkrf )
+
+            // TODO : Use the dynamic property for determining isREPH
+            if ( i == beginSyllable && i < baseConsonant && classTable->isReph(chars[i]) &&
+                 i+1 < nextSyllable && classTable->isVirama(chars[i+1])) {
+                outMask |= rphfFeatureMask;
+                outMask |= rephConsonantMask;
+                output.setFeatures(i+1+inv_count,outMask);
+
+            }
+
+            if ( i == baseConsonant ) {
+                outMask |= baseConsonantMask;
+            }
+
+            if ( classTable->isMatra(chars[i])) {
+                    outMask |= matraMask;
+                    if ( classTable->hasAboveBaseForm(chars[i])) {
+                        outMask |= aboveBasePosition;
+                    } else if ( classTable->hasBelowBaseForm(chars[i])) {
+                        outMask |= belowBasePosition;
+                    }
+            }
+
+            // Don't apply half form to virama that stands alone at the end of a syllable
+            // to prevent half forms from forming when syllable ends with virama
+
+            if ( classTable->isVirama(chars[i]) && (i+1 == nextSyllable) ) {
+                outMask ^= halfFeatureMask;
+                if ( classTable->isConsonant(chars[i-1]) ) {
+                    FeatureMask tmp = output.getFeatures(i-1+inv_count);
+                    tmp ^= halfFeatureMask;
+                    output.setFeatures(i-1+inv_count,tmp);
+                }
+            }
+
+            if ( outMask != saveMask ) {
+                output.setFeatures(i+inv_count,outMask);
+            }
+		}
+
+	    output.decomposeReorderMatras(classTable,beginSyllable,nextSyllable,inv_count);
+
+        beginSyllable = nextSyllable;   
+	}
+
+
+    return output.getOutputIndex();
+}
+
+
+void IndicReordering::getDynamicProperties( DynamicProperties *, const IndicClassTable *classTable ) {
+
+
+    LEUnicode currentChar;
+    LEUnicode virama;
+    LEUnicode workChars[2];
+    LEGlyphStorage workGlyphs;
+
+    IndicReorderingOutput workOutput(workChars, workGlyphs, NULL);
+
+    //le_int32 offset = 0;
+
+    // First find the relevant virama for the script we are dealing with
+
+    for ( currentChar = classTable->firstChar ; currentChar <= classTable->lastChar ; currentChar++ ) {
+        if ( classTable->isVirama(currentChar)) {
+            virama = currentChar;
+            break;
+        }
+    }
+
+    for ( currentChar = classTable->firstChar ; currentChar <= classTable->lastChar ; currentChar++ ) {
+        if ( classTable->isConsonant(currentChar)) {
+            workOutput.reset();
+        }
+    }
+
+
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/IndicReordering.h b/source/layout/IndicReordering.h
new file mode 100644
index 0000000..c3452fa
--- /dev/null
+++ b/source/layout/IndicReordering.h
@@ -0,0 +1,356 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2009 - All Rights Reserved
+ *
+ */
+
+#ifndef __INDICREORDERING_H
+#define __INDICREORDERING_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+
+U_NAMESPACE_BEGIN
+
+// Characters that get refered to by name...
+#define C_SIGN_ZWNJ           0x200C
+#define C_SIGN_ZWJ            0x200D
+
+// Character class values
+#define CC_RESERVED               0U
+#define CC_VOWEL_MODIFIER         1U
+#define CC_STRESS_MARK            2U
+#define CC_INDEPENDENT_VOWEL      3U
+#define CC_INDEPENDENT_VOWEL_2    4U
+#define CC_INDEPENDENT_VOWEL_3    5U
+#define CC_CONSONANT              6U
+#define CC_CONSONANT_WITH_NUKTA   7U
+#define CC_NUKTA                  8U
+#define CC_DEPENDENT_VOWEL        9U
+#define CC_SPLIT_VOWEL_PIECE_1   10U
+#define CC_SPLIT_VOWEL_PIECE_2   11U
+#define CC_SPLIT_VOWEL_PIECE_3   12U
+#define CC_VIRAMA                13U
+#define CC_ZERO_WIDTH_MARK       14U
+#define CC_AL_LAKUNA             15U
+#define CC_COUNT                 16U
+
+// Character class flags
+#define CF_CLASS_MASK    0x0000FFFFU
+
+#define CF_CONSONANT     0x80000000U
+
+#define CF_REPH          0x40000000U
+#define CF_VATTU         0x20000000U
+#define CF_BELOW_BASE    0x10000000U
+#define CF_POST_BASE     0x08000000U
+#define CF_LENGTH_MARK   0x04000000U
+#define CF_PRE_BASE      0x02000000U
+
+#define CF_POS_BEFORE    0x00300000U
+#define CF_POS_BELOW     0x00200000U
+#define CF_POS_ABOVE     0x00100000U
+#define CF_POS_AFTER     0x00000000U
+#define CF_POS_MASK      0x00300000U
+
+#define CF_INDEX_MASK    0x000F0000U
+#define CF_INDEX_SHIFT   16
+
+// Script flag bits
+#define SF_MATRAS_AFTER_BASE     0x80000000U
+#define SF_REPH_AFTER_BELOW      0x40000000U
+#define SF_EYELASH_RA            0x20000000U
+#define SF_MPRE_FIXUP            0x10000000U
+#define SF_FILTER_ZERO_WIDTH     0x08000000U
+
+#define SF_POST_BASE_LIMIT_MASK  0x0000FFFFU
+#define SF_NO_POST_BASE_LIMIT    0x00007FFFU
+
+typedef LEUnicode SplitMatra[3];
+
+class MPreFixups;
+class LEGlyphStorage;
+
+// Dynamic Properties ( v2 fonts only )
+typedef le_uint32 DynamicProperties;
+
+#define DP_REPH               0x80000000U
+#define DP_HALF               0x40000000U
+#define DP_PREF               0x20000000U
+#define DP_BLWF               0x10000000U
+#define DP_PSTF               0x08000000U
+
+struct IndicClassTable
+{
+    typedef le_uint32 CharClass;
+    typedef le_uint32 ScriptFlags;
+    
+    LEUnicode firstChar;
+    LEUnicode lastChar;
+    le_int32 worstCaseExpansion;
+    ScriptFlags scriptFlags;
+    const CharClass *classTable;
+    const SplitMatra *splitMatraTable;
+
+    inline le_int32 getWorstCaseExpansion() const;
+    inline le_bool getFilterZeroWidth() const;
+
+    CharClass getCharClass(LEUnicode ch) const;
+
+    inline const SplitMatra *getSplitMatra(CharClass charClass) const;
+
+    inline le_bool isVowelModifier(LEUnicode ch) const;
+    inline le_bool isStressMark(LEUnicode ch) const;
+    inline le_bool isConsonant(LEUnicode ch) const;
+    inline le_bool isReph(LEUnicode ch) const;
+    inline le_bool isVirama(LEUnicode ch) const;
+    inline le_bool isAlLakuna(LEUnicode ch) const;
+    inline le_bool isNukta(LEUnicode ch) const;
+    inline le_bool isVattu(LEUnicode ch) const;
+    inline le_bool isMatra(LEUnicode ch) const;
+    inline le_bool isSplitMatra(LEUnicode ch) const;
+    inline le_bool isLengthMark(LEUnicode ch) const;
+    inline le_bool hasPostOrBelowBaseForm(LEUnicode ch) const;
+    inline le_bool hasPostBaseForm(LEUnicode ch) const;
+    inline le_bool hasBelowBaseForm(LEUnicode ch) const;
+    inline le_bool hasAboveBaseForm(LEUnicode ch) const;
+    inline le_bool hasPreBaseForm(LEUnicode ch) const;
+
+    inline static le_bool isVowelModifier(CharClass charClass);
+    inline static le_bool isStressMark(CharClass charClass);
+    inline static le_bool isConsonant(CharClass charClass);
+    inline static le_bool isReph(CharClass charClass);
+    inline static le_bool isVirama(CharClass charClass);
+    inline static le_bool isAlLakuna(CharClass charClass);
+    inline static le_bool isNukta(CharClass charClass);
+    inline static le_bool isVattu(CharClass charClass);
+    inline static le_bool isMatra(CharClass charClass);
+    inline static le_bool isSplitMatra(CharClass charClass);
+    inline static le_bool isLengthMark(CharClass charClass);
+    inline static le_bool hasPostOrBelowBaseForm(CharClass charClass);
+    inline static le_bool hasPostBaseForm(CharClass charClass);
+    inline static le_bool hasBelowBaseForm(CharClass charClass);
+    inline static le_bool hasAboveBaseForm(CharClass charClass);
+    inline static le_bool hasPreBaseForm(CharClass charClass);
+
+    static const IndicClassTable *getScriptClassTable(le_int32 scriptCode);
+};
+
+class IndicReordering /* not : public UObject because all methods are static */ {
+public:
+    static le_int32 getWorstCaseExpansion(le_int32 scriptCode);
+
+    static le_bool getFilterZeroWidth(le_int32 scriptCode);
+
+    static le_int32 reorder(const LEUnicode *theChars, le_int32 charCount, le_int32 scriptCode,
+        LEUnicode *outChars, LEGlyphStorage &glyphStorage,
+        MPreFixups **outMPreFixups, LEErrorCode& success);
+
+    static void adjustMPres(MPreFixups *mpreFixups, LEGlyphStorage &glyphStorage, LEErrorCode& success);
+
+    static le_int32 v2process(const LEUnicode *theChars, le_int32 charCount, le_int32 scriptCode,
+        LEUnicode *outChars, LEGlyphStorage &glyphStorage);
+
+    static const FeatureMap *getFeatureMap(le_int32 &count);
+
+	static const FeatureMap *getv2FeatureMap(le_int32 &count);
+
+    static void applyPresentationForms(LEGlyphStorage &glyphStorage, le_int32 count);
+
+    static void finalReordering(LEGlyphStorage &glyphStorage, le_int32 count);
+
+    static void getDynamicProperties(DynamicProperties *dProps, const IndicClassTable *classTable);
+
+private:
+    // do not instantiate
+    IndicReordering();
+
+    static le_int32 findSyllable(const IndicClassTable *classTable, const LEUnicode *chars, le_int32 prev, le_int32 charCount);
+
+};
+
+inline le_int32 IndicClassTable::getWorstCaseExpansion() const
+{
+    return worstCaseExpansion;
+}
+
+inline le_bool IndicClassTable::getFilterZeroWidth() const
+{
+    return (scriptFlags & SF_FILTER_ZERO_WIDTH) != 0;
+}
+
+inline const SplitMatra *IndicClassTable::getSplitMatra(CharClass charClass) const
+{
+    le_int32 index = (charClass & CF_INDEX_MASK) >> CF_INDEX_SHIFT;
+
+    return &splitMatraTable[index - 1];
+}
+
+inline le_bool IndicClassTable::isVowelModifier(CharClass charClass)
+{
+    return (charClass & CF_CLASS_MASK) == CC_VOWEL_MODIFIER;
+}
+
+inline le_bool IndicClassTable::isStressMark(CharClass charClass)
+{
+    return (charClass & CF_CLASS_MASK) == CC_STRESS_MARK;
+}
+
+inline le_bool IndicClassTable::isConsonant(CharClass charClass)
+{
+    return (charClass & CF_CONSONANT) != 0;
+}
+
+inline le_bool IndicClassTable::isReph(CharClass charClass)
+{
+    return (charClass & CF_REPH) != 0;
+}
+
+inline le_bool IndicClassTable::isNukta(CharClass charClass)
+{
+    return (charClass & CF_CLASS_MASK) == CC_NUKTA;
+}
+
+inline le_bool IndicClassTable::isVirama(CharClass charClass)
+{
+    return (charClass & CF_CLASS_MASK) == CC_VIRAMA;
+}
+
+inline le_bool IndicClassTable::isAlLakuna(CharClass charClass)
+{
+    return (charClass & CF_CLASS_MASK) == CC_AL_LAKUNA;
+}
+
+inline le_bool IndicClassTable::isVattu(CharClass charClass)
+{
+    return (charClass & CF_VATTU) != 0;
+}
+
+inline le_bool IndicClassTable::isMatra(CharClass charClass)
+{
+    charClass &= CF_CLASS_MASK;
+
+    return charClass >= CC_DEPENDENT_VOWEL && charClass <= CC_SPLIT_VOWEL_PIECE_3;
+}
+
+inline le_bool IndicClassTable::isSplitMatra(CharClass charClass)
+{
+    return (charClass & CF_INDEX_MASK) != 0;
+}
+
+inline le_bool IndicClassTable::isLengthMark(CharClass charClass)
+{
+    return (charClass & CF_LENGTH_MARK) != 0;
+}
+
+inline le_bool IndicClassTable::hasPostOrBelowBaseForm(CharClass charClass)
+{
+    return (charClass & (CF_POST_BASE | CF_BELOW_BASE)) != 0;
+}
+
+inline le_bool IndicClassTable::hasPostBaseForm(CharClass charClass)
+{
+    return (charClass & CF_POST_BASE) != 0;
+}
+
+inline le_bool IndicClassTable::hasPreBaseForm(CharClass charClass)
+{
+    return (charClass & CF_PRE_BASE) != 0;
+}
+
+inline le_bool IndicClassTable::hasBelowBaseForm(CharClass charClass)
+{
+    return (charClass & CF_BELOW_BASE) != 0;
+}
+
+inline le_bool IndicClassTable::hasAboveBaseForm(CharClass charClass)
+{
+    return ((charClass & CF_POS_MASK) == CF_POS_ABOVE);
+}
+
+inline le_bool IndicClassTable::isVowelModifier(LEUnicode ch) const
+{
+    return isVowelModifier(getCharClass(ch));
+}
+
+inline le_bool IndicClassTable::isStressMark(LEUnicode ch) const
+{
+    return isStressMark(getCharClass(ch));
+}
+
+inline le_bool IndicClassTable::isConsonant(LEUnicode ch) const
+{
+    return isConsonant(getCharClass(ch));
+}
+
+inline le_bool IndicClassTable::isReph(LEUnicode ch) const
+{
+    return isReph(getCharClass(ch));
+}
+
+inline le_bool IndicClassTable::isVirama(LEUnicode ch) const
+{
+    return isVirama(getCharClass(ch));
+}
+
+inline le_bool IndicClassTable::isAlLakuna(LEUnicode ch) const
+{
+    return isAlLakuna(getCharClass(ch));
+}
+
+inline le_bool IndicClassTable::isNukta(LEUnicode ch) const
+{
+    return isNukta(getCharClass(ch));
+}
+
+inline le_bool IndicClassTable::isVattu(LEUnicode ch) const
+{
+    return isVattu(getCharClass(ch));
+}
+
+inline le_bool IndicClassTable::isMatra(LEUnicode ch) const
+{
+    return isMatra(getCharClass(ch));
+}
+
+inline le_bool IndicClassTable::isSplitMatra(LEUnicode ch) const
+{
+    return isSplitMatra(getCharClass(ch));
+}
+
+inline le_bool IndicClassTable::isLengthMark(LEUnicode ch) const
+{
+    return isLengthMark(getCharClass(ch));
+}
+
+inline le_bool IndicClassTable::hasPostOrBelowBaseForm(LEUnicode ch) const
+{
+    return hasPostOrBelowBaseForm(getCharClass(ch));
+}
+
+inline le_bool IndicClassTable::hasPostBaseForm(LEUnicode ch) const
+{
+    return hasPostBaseForm(getCharClass(ch));
+}
+
+inline le_bool IndicClassTable::hasBelowBaseForm(LEUnicode ch) const
+{
+    return hasBelowBaseForm(getCharClass(ch));
+}
+
+inline le_bool IndicClassTable::hasPreBaseForm(LEUnicode ch) const
+{
+    return hasPreBaseForm(getCharClass(ch));
+}
+
+inline le_bool IndicClassTable::hasAboveBaseForm(LEUnicode ch) const
+{
+    return hasAboveBaseForm(getCharClass(ch));
+}
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/KernTable.cpp b/source/layout/KernTable.cpp
new file mode 100644
index 0000000..45ce091
--- /dev/null
+++ b/source/layout/KernTable.cpp
@@ -0,0 +1,231 @@
+/*
+ * @(#)KernTable.cpp	1.1 04/10/13
+ *
+ * (C) Copyright IBM Corp. 2004-2007 - All Rights Reserved
+ *
+ */
+
+#include "KernTable.h"
+#include "LEFontInstance.h"
+#include "LEGlyphStorage.h"
+
+#include "LESwaps.h"
+#include "OpenTypeUtilities.h"
+
+#include <stdio.h>
+
+#define DEBUG 0
+
+U_NAMESPACE_BEGIN
+
+struct PairInfo {
+  le_uint16 left;  // left glyph of kern pair
+  le_uint16 right; // right glyph of kern pair
+  le_int16  value; // fword, kern value in funits
+};
+#define KERN_PAIRINFO_SIZE 6
+
+#define SWAP_KEY(p) (((le_uint32) SWAPW((p)->left) << 16) | SWAPW((p)->right))
+
+struct Subtable_0 {
+  le_uint16 nPairs;
+  le_uint16 searchRange;
+  le_uint16 entrySelector;
+  le_uint16 rangeShift;
+};
+#define KERN_SUBTABLE_0_HEADER_SIZE 8
+
+// Kern table version 0 only
+struct SubtableHeader {
+  le_uint16 version;
+  le_uint16 length;
+  le_uint16 coverage;
+};
+#define KERN_SUBTABLE_HEADER_SIZE 6
+
+// Version 0 only, version 1 has different layout
+struct KernTableHeader {
+  le_uint16 version;
+  le_uint16 nTables;
+};
+#define KERN_TABLE_HEADER_SIZE 4
+
+#define COVERAGE_HORIZONTAL 0x1
+#define COVERAGE_MINIMUM 0x2
+#define COVERAGE_CROSS 0x4
+#define COVERAGE_OVERRIDE 0x8
+
+/*
+ * This implementation has support for only one subtable, so if the font has
+ * multiple subtables, only the first will be used.  If this turns out to
+ * be a problem in practice we should add it.
+ *
+ * This also supports only version 0 of the kern table header, only
+ * Apple supports the latter.
+ *
+ * This implementation isn't careful about the kern table flags, and
+ * might invoke kerning when it is not supposed to.  That too I'm
+ * leaving for a bug fix.
+ *
+ * TODO: support multiple subtables
+ * TODO: respect header flags
+ */
+KernTable::KernTable(const LEFontInstance* font, const void* tableData) 
+  : pairs(0), font(font)
+{
+  const KernTableHeader* header = (const KernTableHeader*)tableData;
+  if (header == 0) {
+#if DEBUG
+    fprintf(stderr, "no kern data\n");
+#endif
+    return;
+  }
+
+#if DEBUG
+  // dump first 32 bytes of header
+  for (int i = 0; i < 64; ++i) {
+    fprintf(stderr, "%0.2x ", ((const char*)tableData)[i]&0xff);
+    if (((i+1)&0xf) == 0) {
+      fprintf(stderr, "\n");
+    } else if (((i+1)&0x7) == 0) {
+      fprintf(stderr, "  ");
+    }
+  }
+#endif
+
+  if (header->version == 0 && SWAPW(header->nTables) > 0) {
+    const SubtableHeader* subhead = (const SubtableHeader*)((char*)tableData + KERN_TABLE_HEADER_SIZE);
+
+    if (subhead->version == 0) {
+      coverage = SWAPW(subhead->coverage);
+
+      if (coverage & COVERAGE_HORIZONTAL) { // only handle horizontal kerning
+        const Subtable_0* table = (const Subtable_0*)((char*)subhead + KERN_SUBTABLE_HEADER_SIZE);
+
+        nPairs        = SWAPW(table->nPairs);
+
+#if 0   // some old fonts have bad values here...
+        searchRange   = SWAPW(table->searchRange);
+        entrySelector = SWAPW(table->entrySelector);
+        rangeShift    = SWAPW(table->rangeShift);
+#else
+        entrySelector = OpenTypeUtilities::highBit(nPairs);
+        searchRange   = (1 << entrySelector) * KERN_PAIRINFO_SIZE;
+        rangeShift    = (nPairs * KERN_PAIRINFO_SIZE) - searchRange;
+#endif
+
+        pairs         = (const PairInfo*)((char*)table + KERN_SUBTABLE_0_HEADER_SIZE);
+
+#if DEBUG
+        fprintf(stderr, "coverage: %0.4x nPairs: %d pairs 0x%x\n", coverage, nPairs, pairs);
+        fprintf(stderr, "  searchRange: %d entrySelector: %d rangeShift: %d\n", searchRange, entrySelector, rangeShift);
+
+        {
+          // dump part of the pair list
+          char ids[256];
+
+          for (int i = 256; --i >= 0;) {
+            LEGlyphID id = font->mapCharToGlyph(i);
+
+            if (id < 256) {
+              ids[id] = (char)i;
+            }
+          }
+
+          const PairInfo* p = pairs;
+
+          for (i = 0; i < nPairs; ++i, p = (const PairInfo*)((char*)p+KERN_PAIRINFO_SIZE)) {
+            le_uint16 left = p->left;
+            le_uint16 right = p->right;
+
+            if (left < 256 && right < 256) {
+              char c = ids[left];
+
+              if (c > 0x20 && c < 0x7f) {
+                fprintf(stderr, "%c/", c & 0xff);
+              } else {
+                printf(stderr, "%0.2x/", c & 0xff);
+              }
+
+              c = ids[right];
+              if (c > 0x20 && c < 0x7f) {
+                fprintf(stderr, "%c ", c & 0xff);
+              } else {
+                fprintf(stderr, "%0.2x ", c & 0xff);
+              }
+            }
+          }
+        }
+#endif
+      }
+    }
+  }
+}
+  
+
+/*
+ * Process the glyph positions.  The positions array has two floats for each
+ * glyph, plus a trailing pair to mark the end of the last glyph.
+ */
+void KernTable::process(LEGlyphStorage& storage) 
+{
+  if (pairs) {
+    LEErrorCode success = LE_NO_ERROR;
+
+    le_uint32 key = storage[0]; // no need to mask off high bits
+    float adjust = 0;
+
+    for (int i = 1, e = storage.getGlyphCount(); i < e; ++i) {
+      key = key << 16 | (storage[i] & 0xffff);
+
+      // argh, to do a binary search, we need to have the pair list in sorted order
+      // but it is not in sorted order on win32 platforms because of the endianness difference
+      // so either I have to swap the element each time I examine it, or I have to swap
+      // all the elements ahead of time and store them in the font
+
+      const PairInfo* p = pairs;
+      const PairInfo* tp = (const PairInfo*)((char*)p + rangeShift);
+
+      if (key > SWAP_KEY(tp)) {
+        p = tp;
+      }
+
+#if DEBUG
+      fprintf(stderr, "binary search for %0.8x\n", key);
+#endif
+
+      le_uint32 probe = searchRange;
+
+      while (probe > KERN_PAIRINFO_SIZE) {
+        probe >>= 1;
+        tp = (const PairInfo*)((char*)p + probe);
+
+        le_uint32 tkey = SWAP_KEY(tp);
+#if DEBUG
+        fprintf(stdout, "   %.3d (%0.8x)\n", ((char*)tp - (char*)pairs)/KERN_PAIRINFO_SIZE, tkey);
+#endif
+        if (tkey <= key) {
+          if (tkey == key) {
+            le_int16 value = SWAPW(tp->value);
+#if DEBUG
+            fprintf(stdout, "binary found kerning pair %x:%x at %d, value: 0x%x (%g)\n", 
+              storage[i-1], storage[i], i, value & 0xffff, font->xUnitsToPoints(value));
+            fflush(stdout);
+#endif
+            adjust += font->xUnitsToPoints(value);
+            break;
+          }
+
+          p = tp;
+        }
+      }
+
+      storage.adjustPosition(i, adjust, 0, success);
+    }
+
+    storage.adjustPosition(storage.getGlyphCount(), adjust, 0, success);
+  }
+}
+
+U_NAMESPACE_END
+
diff --git a/source/layout/KernTable.h b/source/layout/KernTable.h
new file mode 100644
index 0000000..b8322cf
--- /dev/null
+++ b/source/layout/KernTable.h
@@ -0,0 +1,51 @@
+/*
+ * @(#)KernTable.h	1.1 04/10/13
+ *
+ * (C) Copyright IBM Corp. 2004-2005 - All Rights Reserved
+ *
+ */
+
+#ifndef __KERNTABLE_H
+#define __KERNTABLE_H
+
+#ifndef __LETYPES_H
+#include "LETypes.h"
+#endif
+
+#include "LETypes.h"
+//#include "LEFontInstance.h"
+//#include "LEGlyphStorage.h"
+
+#include <stdio.h>
+
+U_NAMESPACE_BEGIN
+struct PairInfo;
+class  LEFontInstance;
+class  LEGlyphStorage;
+
+/**
+ * Windows type 0 kerning table support only for now.
+ */
+class U_LAYOUT_API KernTable
+{
+ private:
+  le_uint16 coverage;
+  le_uint16 nPairs;
+  const PairInfo* pairs;
+  const LEFontInstance* font;
+  le_uint16 searchRange;
+  le_uint16 entrySelector;
+  le_uint16 rangeShift;
+
+ public:
+  KernTable(const LEFontInstance* font, const void* tableData);
+
+  /*
+   * Process the glyph positions.
+   */
+  void process(LEGlyphStorage& storage);
+};
+
+U_NAMESPACE_END
+
+#endif
diff --git a/source/layout/KhmerLayoutEngine.cpp b/source/layout/KhmerLayoutEngine.cpp
new file mode 100644
index 0000000..f4bbb60
--- /dev/null
+++ b/source/layout/KhmerLayoutEngine.cpp
@@ -0,0 +1,81 @@
+
+/*
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved 
+ *
+ * This file is a modification of the ICU file IndicLayoutEngine.cpp
+ * by Jens Herden and Javier Sola for Khmer language 
+ *
+ */
+
+
+#include "OpenTypeLayoutEngine.h"
+#include "KhmerLayoutEngine.h"
+#include "LEGlyphStorage.h"
+#include "KhmerReordering.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(KhmerOpenTypeLayoutEngine)
+
+KhmerOpenTypeLayoutEngine::KhmerOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+                    le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success)
+    : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success)
+{
+    fFeatureMap   = KhmerReordering::getFeatureMap(fFeatureMapCount);
+    fFeatureOrder = TRUE;
+}
+
+KhmerOpenTypeLayoutEngine::KhmerOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+						     le_int32 typoFlags, LEErrorCode &success)
+    : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success)
+{
+    fFeatureMap   = KhmerReordering::getFeatureMap(fFeatureMapCount);
+    fFeatureOrder = TRUE;
+}
+
+KhmerOpenTypeLayoutEngine::~KhmerOpenTypeLayoutEngine()
+{
+    // nothing to do
+}
+
+// Input: characters
+// Output: characters, char indices, tags
+// Returns: output character count
+le_int32 KhmerOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+        LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    le_int32 worstCase = count * 3;  // worst case is 3 for Khmer  TODO check if 2 is enough
+
+    outChars = LE_NEW_ARRAY(LEUnicode, worstCase);
+
+    if (outChars == NULL) {
+        success = LE_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
+
+    glyphStorage.allocateGlyphArray(worstCase, rightToLeft, success);
+    glyphStorage.allocateAuxData(success);
+
+    if (LE_FAILURE(success)) {
+        LE_DELETE_ARRAY(outChars);
+        return 0;
+    }
+
+    // NOTE: assumes this allocates featureTags...
+    // (probably better than doing the worst case stuff here...)
+    le_int32 outCharCount = KhmerReordering::reorder(&chars[offset], count, fScriptCode, outChars, glyphStorage);
+
+    glyphStorage.adoptGlyphCount(outCharCount);
+    return outCharCount;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/KhmerLayoutEngine.h b/source/layout/KhmerLayoutEngine.h
new file mode 100644
index 0000000..60a34f6
--- /dev/null
+++ b/source/layout/KhmerLayoutEngine.h
@@ -0,0 +1,131 @@
+
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved 
+ *
+ * This file is a modification of the ICU file IndicLayoutEngine.h
+ * by Jens Herden and Javier Sola for Khmer language 
+ *
+ */
+
+#ifndef __KHMERLAYOUTENGINE_H
+#define __KHMERLAYOUTENGINE_H
+
+// #include "LETypes.h"
+// #include "LEFontInstance.h"
+// #include "LEGlyphFilter.h"
+// #include "LayoutEngine.h"
+// #include "OpenTypeLayoutEngine.h"
+
+// #include "GlyphSubstitutionTables.h"
+// #include "GlyphDefinitionTables.h"
+// #include "GlyphPositioningTables.h"
+
+U_NAMESPACE_BEGIN
+
+// class MPreFixups;
+// class LEGlyphStorage;
+
+/**
+ * This class implements OpenType layout for Khmer OpenType fonts, as
+ * specified by Microsoft in "Creating and Supporting OpenType Fonts for
+ * Khmer Scripts" (http://www.microsoft.com/typography/otspec/indicot/default.htm) TODO: change url
+ *
+ * This class overrides the characterProcessing method to do Khmer character processing
+ * and reordering (See the MS spec. for more details)
+ *
+ * @internal
+ */
+class KhmerOpenTypeLayoutEngine : public OpenTypeLayoutEngine
+{
+public:
+    /**
+     * This is the main constructor. It constructs an instance of KhmerOpenTypeLayoutEngine for
+     * a particular font, script and language. It takes the GSUB table as a parameter since
+     * LayoutEngine::layoutEngineFactory has to read the GSUB table to know that it has an
+     * Khmer OpenType font.
+     *
+     * @param fontInstance - the font
+     * @param scriptCode - the script
+     * @param langaugeCode - the language
+     * @param gsubTable - the GSUB table
+     * @param success - set to an error code if the operation fails
+     *
+     * @see LayoutEngine::layoutEngineFactory
+     * @see OpenTypeLayoutEngine
+     * @see ScriptAndLangaugeTags.h for script and language codes
+     *
+     * @internal
+     */
+    KhmerOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+                            le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success);
+
+    /**
+     * This constructor is used when the font requires a "canned" GSUB table which can't be known
+     * until after this constructor has been invoked.
+     *
+     * @param fontInstance - the font
+     * @param scriptCode - the script
+     * @param langaugeCode - the language
+     * @param success - set to an error code if the operation fails
+     *
+     * @see OpenTypeLayoutEngine
+     * @see ScriptAndLangaugeTags.h for script and language codes
+     *
+     * @internal
+     */
+    KhmerOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+			      le_int32 typoFlags, LEErrorCode &success);
+
+    /**
+     * The destructor, virtual for correct polymorphic invocation.
+     *
+     * @internal
+     */
+   virtual ~KhmerOpenTypeLayoutEngine();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.8
+     */
+    static UClassID getStaticClassID();
+
+protected:
+
+    /**
+     * This method does Khmer OpenType character processing. It assigns the OpenType feature
+     * tags to the characters, and may generate output characters which have been reordered. 
+     * It may also split some vowels, resulting in more output characters than input characters.
+     *
+     * Input parameters:
+     * @param chars - the input character context
+     * @param offset - the index of the first character to process
+     * @param count - the number of characters to process
+     * @param max - the number of characters in the input context
+     * @param rightToLeft - <code>TRUE</code> if the characters are in a right to left directional run
+     * @param glyphStorage - the glyph storage object. The glyph and character index arrays will be set.
+     *                       the auxillary data array will be set to the feature tags.
+     *
+     * Output parameters:
+     * @param success - set to an error code if the operation fails
+     *
+     * @return the output character count
+     *
+     * @internal
+     */
+    virtual le_int32 characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+            LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/KhmerReordering.cpp b/source/layout/KhmerReordering.cpp
new file mode 100644
index 0000000..20c2ed4
--- /dev/null
+++ b/source/layout/KhmerReordering.cpp
@@ -0,0 +1,499 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved 
+ *
+ * This file is a modification of the ICU file IndicReordering.cpp
+ * by Jens Herden and Javier Sola for Khmer language 
+ *
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "KhmerReordering.h"
+#include "LEGlyphStorage.h"
+
+
+U_NAMESPACE_BEGIN
+
+// Characters that get refered to by name...
+enum
+{
+    C_SIGN_ZWNJ     = 0x200C,
+    C_SIGN_ZWJ      = 0x200D,
+    C_DOTTED_CIRCLE = 0x25CC,
+    C_RO            = 0x179A,
+    C_VOWEL_AA      = 0x17B6,
+    C_SIGN_NIKAHIT  = 0x17C6,
+    C_VOWEL_E       = 0x17C1,
+    C_COENG         = 0x17D2
+};
+
+
+enum
+{
+    // simple classes, they are used in the statetable (in this file) to control the length of a syllable
+    // they are also used to know where a character should be placed (location in reference to the base character)
+    // and also to know if a character, when independtly displayed, should be displayed with a dotted-circle to
+    // indicate error in syllable construction 
+    _xx = KhmerClassTable::CC_RESERVED,
+    _sa = KhmerClassTable::CC_SIGN_ABOVE | KhmerClassTable::CF_DOTTED_CIRCLE | KhmerClassTable::CF_POS_ABOVE,
+    _sp = KhmerClassTable::CC_SIGN_AFTER | KhmerClassTable::CF_DOTTED_CIRCLE| KhmerClassTable::CF_POS_AFTER,
+    _c1 = KhmerClassTable::CC_CONSONANT | KhmerClassTable::CF_CONSONANT,
+    _c2 = KhmerClassTable::CC_CONSONANT2 | KhmerClassTable::CF_CONSONANT,
+    _c3 = KhmerClassTable::CC_CONSONANT3 | KhmerClassTable::CF_CONSONANT,
+    _rb = KhmerClassTable::CC_ROBAT | KhmerClassTable::CF_POS_ABOVE | KhmerClassTable::CF_DOTTED_CIRCLE,
+    _cs = KhmerClassTable::CC_CONSONANT_SHIFTER | KhmerClassTable::CF_DOTTED_CIRCLE | KhmerClassTable::CF_SHIFTER,
+    _dl = KhmerClassTable::CC_DEPENDENT_VOWEL | KhmerClassTable::CF_POS_BEFORE | KhmerClassTable::CF_DOTTED_CIRCLE, 
+    _db = KhmerClassTable::CC_DEPENDENT_VOWEL | KhmerClassTable::CF_POS_BELOW | KhmerClassTable::CF_DOTTED_CIRCLE,
+    _da = KhmerClassTable::CC_DEPENDENT_VOWEL | KhmerClassTable::CF_POS_ABOVE | KhmerClassTable::CF_DOTTED_CIRCLE | KhmerClassTable::CF_ABOVE_VOWEL,
+    _dr = KhmerClassTable::CC_DEPENDENT_VOWEL | KhmerClassTable::CF_POS_AFTER | KhmerClassTable::CF_DOTTED_CIRCLE,
+    _co = KhmerClassTable::CC_COENG | KhmerClassTable::CF_COENG | KhmerClassTable::CF_DOTTED_CIRCLE,
+    
+    // split vowel
+    _va = _da | KhmerClassTable::CF_SPLIT_VOWEL,
+    _vr = _dr | KhmerClassTable::CF_SPLIT_VOWEL
+};
+
+
+// Character class tables 
+// _xx character does not combine into syllable, such as numbers, puntuation marks, non-Khmer signs... 
+// _sa Sign placed above the base
+// _sp Sign placed after the base
+// _c1 Consonant of type 1 or independent vowel (independent vowels behave as type 1 consonants)
+// _c2 Consonant of type 2 (only RO)
+// _c3 Consonant of type 3 
+// _rb Khmer sign robat u17CC. combining mark for subscript consonants
+// _cd Consonant-shifter
+// _dl Dependent vowel placed before the base (left of the base)
+// _db Dependent vowel placed below the base 
+// _da Dependent vowel placed above the base
+// _dr Dependent vowel placed behind the base (right of the base)    
+// _co Khmer combining mark COENG u17D2, combines with the consonant or independent vowel following 
+//     it to create a subscript consonant or independent vowel   
+// _va Khmer split vowel in wich the first part is before the base and the second one above the base
+// _vr Khmer split vowel in wich the first part is before the base and the second one behind (right of) the base
+
+static const KhmerClassTable::CharClass khmerCharClasses[] =
+{
+    _c1, _c1, _c1, _c3, _c1, _c1, _c1, _c1, _c3, _c1, _c1, _c1, _c1, _c3, _c1, _c1, // 1780 - 178F
+    _c1, _c1, _c1, _c1, _c3, _c1, _c1, _c1, _c1, _c3, _c2, _c1, _c1, _c1, _c3, _c3, // 1790 - 179F
+    _c1, _c3, _c1, _c1, _c1, _c1, _c1, _c1, _c1, _c1, _c1, _c1, _c1, _c1, _c1, _c1, // 17A0 - 17AF
+    _c1, _c1, _c1, _c1, _dr, _dr, _dr, _da, _da, _da, _da, _db, _db, _db, _va, _vr, // 17B0 - 17BF
+    _vr, _dl, _dl, _dl, _vr, _vr, _sa, _sp, _sp, _cs, _cs, _sa, _rb, _sa, _sa, _sa, // 17C0 - 17CF
+    _sa, _sa, _co, _sa, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _sa, _xx, _xx, // 17D0 - 17DF
+};                                                                                  
+
+
+//
+// Khmer Class Tables
+//                   
+
+//
+// The range of characters defined in the above table is defined here. FOr Khmer 1780 to 17DF
+// Even if the Khmer range is bigger, all other characters are not combinable, and therefore treated
+// as _xx
+static const KhmerClassTable khmerClassTable = {0x1780, 0x17df, khmerCharClasses};
+
+
+// Below we define how a character in the input string is either in the khmerCharClasses table
+// (in which case we get its type back), a ZWJ or ZWNJ (two characters that may appear 
+// within the syllable, but are not in the table) we also get their type back, or an unknown object
+// in which case we get _xx (CC_RESERVED) back
+KhmerClassTable::CharClass KhmerClassTable::getCharClass(LEUnicode ch) const
+{
+
+    if (ch == C_SIGN_ZWJ) {
+        return CC_ZERO_WIDTH_J_MARK;
+    }
+
+    if (ch == C_SIGN_ZWNJ) {
+        return CC_ZERO_WIDTH_NJ_MARK;
+    }
+
+    if (ch < firstChar || ch > lastChar) {
+        return CC_RESERVED;
+    }
+    
+    return classTable[ch - firstChar];
+}
+
+const KhmerClassTable *KhmerClassTable::getKhmerClassTable()
+{
+    return &khmerClassTable;
+}
+
+
+
+class KhmerReorderingOutput : public UMemory {
+private:
+    le_int32 fSyllableCount;
+    le_int32 fOutIndex;
+    LEUnicode *fOutChars;
+
+    LEGlyphStorage &fGlyphStorage;
+
+
+public:
+    KhmerReorderingOutput(LEUnicode *outChars, LEGlyphStorage &glyphStorage)
+        : fSyllableCount(0), fOutIndex(0), fOutChars(outChars), fGlyphStorage(glyphStorage)
+    {
+        // nothing else to do...
+    }
+
+    ~KhmerReorderingOutput()
+    {
+        // nothing to do here...
+    }
+
+    void reset()
+    {
+        fSyllableCount += 1;
+    }
+
+    void writeChar(LEUnicode ch, le_uint32 charIndex, FeatureMask charFeatures)
+    {
+        LEErrorCode success = LE_NO_ERROR;
+
+        fOutChars[fOutIndex] = ch;
+
+        fGlyphStorage.setCharIndex(fOutIndex, charIndex, success);
+        fGlyphStorage.setAuxData(fOutIndex, charFeatures | (fSyllableCount & LE_GLYPH_GROUP_MASK), success);
+
+        fOutIndex += 1;
+    }
+
+    le_int32 getOutputIndex()
+    {
+        return fOutIndex;
+    }
+};
+
+
+#define blwfFeatureTag LE_BLWF_FEATURE_TAG
+#define pstfFeatureTag LE_PSTF_FEATURE_TAG
+#define presFeatureTag LE_PRES_FEATURE_TAG
+#define blwsFeatureTag LE_BLWS_FEATURE_TAG
+#define abvsFeatureTag LE_ABVS_FEATURE_TAG
+#define pstsFeatureTag LE_PSTS_FEATURE_TAG
+
+#define blwmFeatureTag LE_BLWM_FEATURE_TAG
+#define abvmFeatureTag LE_ABVM_FEATURE_TAG
+#define distFeatureTag LE_DIST_FEATURE_TAG
+
+#define prefFeatureTag LE_PREF_FEATURE_TAG
+#define abvfFeatureTag LE_ABVF_FEATURE_TAG
+#define cligFeatureTag LE_CLIG_FEATURE_TAG
+#define mkmkFeatureTag LE_MKMK_FEATURE_TAG
+
+#define prefFeatureMask 0x80000000UL
+#define blwfFeatureMask 0x40000000UL
+#define abvfFeatureMask 0x20000000UL
+#define pstfFeatureMask 0x10000000UL 
+#define presFeatureMask 0x08000000UL
+#define blwsFeatureMask 0x04000000UL
+#define abvsFeatureMask 0x02000000UL
+#define pstsFeatureMask 0x01000000UL
+#define cligFeatureMask 0x00800000UL
+#define distFeatureMask 0x00400000UL
+#define blwmFeatureMask 0x00200000UL
+#define abvmFeatureMask 0x00100000UL
+#define mkmkFeatureMask 0x00080000UL
+
+#define tagPref    (prefFeatureMask | presFeatureMask | cligFeatureMask | distFeatureMask)
+#define tagAbvf    (abvfFeatureMask | abvsFeatureMask | cligFeatureMask | distFeatureMask | abvmFeatureMask | mkmkFeatureMask)
+#define tagPstf    (blwfFeatureMask | blwsFeatureMask | prefFeatureMask | presFeatureMask | pstfFeatureMask | pstsFeatureMask | cligFeatureMask | distFeatureMask | blwmFeatureMask)
+#define tagBlwf    (blwfFeatureMask | blwsFeatureMask | cligFeatureMask | distFeatureMask | blwmFeatureMask | mkmkFeatureMask)
+#define tagDefault (prefFeatureMask | blwfFeatureMask | presFeatureMask | blwsFeatureMask | cligFeatureMask | distFeatureMask | abvmFeatureMask | blwmFeatureMask | mkmkFeatureMask)
+
+
+
+// These are in the order in which the features need to be applied
+// for correct processing
+static const FeatureMap featureMap[] =
+{
+    // Shaping features
+    {prefFeatureTag, prefFeatureMask},
+    {blwfFeatureTag, blwfFeatureMask},
+    {abvfFeatureTag, abvfFeatureMask},
+    {pstfFeatureTag, pstfFeatureMask}, 
+    {presFeatureTag, presFeatureMask},
+    {blwsFeatureTag, blwsFeatureMask},
+    {abvsFeatureTag, abvsFeatureMask},
+    {pstsFeatureTag, pstsFeatureMask},
+    {cligFeatureTag, cligFeatureMask},
+    
+    // Positioning features
+    {distFeatureTag, distFeatureMask},
+    {blwmFeatureTag, blwmFeatureMask},
+    {abvmFeatureTag, abvmFeatureMask},
+    {mkmkFeatureTag, mkmkFeatureMask},
+};
+
+static const le_int32 featureMapCount = LE_ARRAY_SIZE(featureMap);
+
+// The stateTable is used to calculate the end (the length) of a well
+// formed Khmer Syllable. 
+//
+// Each horizontal line is ordered exactly the same way as the values in KhmerClassTable
+// CharClassValues in KhmerReordering.h This coincidence of values allows the
+// follow up of the table.
+//
+// Each line corresponds to a state, which does not necessarily need to be a type
+// of component... for example, state 2 is a base, with is always a first character
+// in the syllable, but the state could be produced a consonant of any type when
+// it is the first character that is analysed (in ground state).
+//
+// Differentiating 3 types of consonants is necessary in order to 
+// forbid the use of certain combinations, such as having a second
+// coeng after a coeng RO, 
+// The inexistent possibility of having a type 3 after another type 3 is permitted,
+// eliminating it would very much complicate the table, and it does not create typing
+// problems, as the case above.
+//
+// The table is quite complex, in order to limit the number of coeng consonants
+// to 2 (by means of the table).
+//
+// There a peculiarity, as far as Unicode is concerned:
+// - The consonant-shifter is considered in two possible different 
+//   locations, the one considered in Unicode 3.0 and the one considered in
+//   Unicode 4.0. (there is a backwards compatibility problem in this standard).
+
+
+// xx    independent character, such as a number, punctuation sign or non-khmer char
+//
+// c1    Khmer consonant of type 1 or an independent vowel
+//       that is, a letter in which the subscript for is only under the
+//       base, not taking any space to the right or to the left
+//
+// c2    Khmer consonant of type 2, the coeng form takes space under
+//       and to the left of the base (only RO is of this type)
+//
+// c3    Khmer consonant of type 3. Its subscript form takes space under
+//       and to the right of the base. 
+//
+// cs    Khmer consonant shifter         
+//
+// rb    Khmer robat
+//
+// co    coeng character (u17D2)
+//
+// dv    dependent vowel (including split vowels, they are treated in the same way).
+//       even if dv is not defined above, the component that is really tested for is
+//       KhmerClassTable::CC_DEPENDENT_VOWEL, which is common to all dependent vowels
+//
+// zwj   Zero Width joiner
+//
+// zwnj  Zero width non joiner  
+//
+// sa    above sign
+//
+// sp    post sign    
+// 
+// there are lines with equal content but for an easier understanding 
+// (and maybe change in the future) we did not join them
+//
+static const le_int8 khmerStateTable[][KhmerClassTable::CC_COUNT] =
+{
+
+//   xx  c1  c2  c3 zwnj cs  rb  co  dv  sa  sp zwj  
+    { 1,  2,  2,  2,  1,  1,  1,  6,  1,  1,  1,  2}, //  0 - ground state
+    {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, //  1 - exit state (or sign to the right of the syllable)
+    {-1, -1, -1, -1,  3,  4,  5,  6, 16, 17,  1, -1}, //  2 - Base consonant    
+    {-1, -1, -1, -1, -1,  4, -1, -1, 16, -1, -1, -1}, //  3 - First ZWNJ before a register shifter
+                                                      //      It can only be followed by a shifter or a vowel
+    {-1, -1, -1, -1, 15, -1, -1,  6, 16, 17,  1, 14}, //  4 - First register shifter             
+    {-1, -1, -1, -1, -1, -1, -1, -1, 20, -1,  1, -1}, //  5 - Robat
+    {-1,  7,  8,  9, -1, -1, -1, -1, -1, -1, -1, -1}, //  6 - First Coeng
+    {-1, -1, -1, -1, 12, 13, -1, 10, 16, 17,  1, 14}, //  7 - First consonant of type 1 after coeng 
+    {-1, -1, -1, -1, 12, 13, -1, -1, 16, 17,  1, 14}, //  8 - First consonant of type 2 after coeng
+    {-1, -1, -1, -1, 12, 13, -1, 10, 16, 17,  1, 14}, //  9 - First consonant or type 3 after ceong
+    {-1, 11, 11, 11, -1, -1, -1, -1, -1, -1, -1, -1}, // 10 - Second Coeng (no register shifter before)
+    {-1, -1, -1, -1, 15, -1, -1, -1, 16, 17,  1, 14}, // 11 - Second coeng consonant (or ind. vowel) no register shifter before 
+    {-1, -1, -1, -1, -1, 13, -1, -1, 16, -1, -1, -1}, // 12 - Second ZWNJ before a register shifter
+    {-1, -1, -1, -1, 15, -1, -1, -1, 16, 17,  1, 14}, // 13 - Second register shifter 
+    {-1, -1, -1, -1, -1, -1, -1, -1, 16, -1, -1, -1}, // 14 - ZWJ before vowel    
+    {-1, -1, -1, -1, -1, -1, -1, -1, 16, -1, -1, -1}, // 15 - ZWNJ before vowel
+    {-1, -1, -1, -1, -1, -1, -1, -1, -1, 17,  1, 18}, // 16 - dependent vowel 
+    {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  1, 18}, // 17 - sign above
+    {-1, -1, -1, -1, -1, -1, -1, 19, -1, -1, -1, -1}, // 18 - ZWJ after vowel    
+    {-1,  1, -1,  1, -1, -1, -1, -1, -1, -1, -1, -1}, // 19 - Third coeng 
+    {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  1, -1}, // 20 - dependent vowel after a Robat
+
+};         
+
+
+const FeatureMap *KhmerReordering::getFeatureMap(le_int32 &count)
+{
+    count = featureMapCount;
+
+    return featureMap;
+}
+
+
+// Given an input string of characters and a location in which to start looking
+// calculate, using the state table, which one is the last character of the syllable
+// that starts in the starting position.
+le_int32 KhmerReordering::findSyllable(const KhmerClassTable *classTable, const LEUnicode *chars, le_int32 prev, le_int32 charCount)
+{
+    le_int32 cursor = prev;
+    le_int8 state = 0;
+
+    while (cursor < charCount) {
+        KhmerClassTable::CharClass charClass = (classTable->getCharClass(chars[cursor]) & KhmerClassTable::CF_CLASS_MASK);
+
+        state = khmerStateTable[state][charClass];
+
+        if (state < 0) {
+            break;
+        }
+
+        cursor += 1;
+    }
+
+    return cursor;
+}
+
+
+// This is the real reordering function as applied to the Khmer language
+
+le_int32 KhmerReordering::reorder(const LEUnicode *chars, le_int32 charCount, le_int32 /*scriptCode*/,
+                                  LEUnicode *outChars, LEGlyphStorage &glyphStorage)
+{
+    const KhmerClassTable *classTable = KhmerClassTable::getKhmerClassTable();
+
+    KhmerReorderingOutput output(outChars, glyphStorage);
+    KhmerClassTable::CharClass charClass;
+    le_int32 i, prev = 0, coengRo;
+
+    
+    // This loop only exits when we reach the end of a run, which may contain 
+    // several syllables.
+    while (prev < charCount) {
+        le_int32 syllable = findSyllable(classTable, chars, prev, charCount);
+
+        output.reset();
+   
+        // write a pre vowel or the pre part of a split vowel first
+        // and look out for coeng + ro. RO is the only vowel of type 2, and
+        // therefore the only one that requires saving space before the base.
+        coengRo = -1;  // There is no Coeng Ro, if found this value will change
+        for (i = prev; i < syllable; i += 1) {
+            charClass = classTable->getCharClass(chars[i]);
+            
+            // if a split vowel, write the pre part. In Khmer the pre part
+            // is the same for all split vowels, same glyph as pre vowel C_VOWEL_E
+            if (charClass & KhmerClassTable::CF_SPLIT_VOWEL) {
+                output.writeChar(C_VOWEL_E, i, tagPref);
+                break; // there can be only one vowel
+            }
+            
+            // if a vowel with pos before write it out
+            if (charClass & KhmerClassTable::CF_POS_BEFORE) {
+                output.writeChar(chars[i], i, tagPref);
+                break; // there can be only one vowel 
+            }
+            
+            // look for coeng + ro and remember position
+            // works because coeng + ro is always in front of a vowel (if there is a vowel) 
+            // and because CC_CONSONANT2 is enough to identify it, as it is the only consonant
+            // with this flag
+            if ( (charClass & KhmerClassTable::CF_COENG) && (i + 1 < syllable) &&
+                 ( (classTable->getCharClass(chars[i + 1]) & KhmerClassTable::CF_CLASS_MASK) == KhmerClassTable::CC_CONSONANT2) )
+            {
+                    coengRo = i;
+            }
+        }
+        
+        // write coeng + ro if found
+        if (coengRo > -1) {
+            output.writeChar(C_COENG, coengRo, tagPref);
+            output.writeChar(C_RO, coengRo + 1, tagPref);
+        }
+        
+        // shall we add a dotted circle?
+        // If in the position in which the base should be (first char in the string) there is
+        // a character that has the Dotted circle flag (a character that cannot be a base)
+        // then write a dotted circle
+        if (classTable->getCharClass(chars[prev]) & KhmerClassTable::CF_DOTTED_CIRCLE) {
+            output.writeChar(C_DOTTED_CIRCLE, prev, tagDefault);        
+        }        
+
+        // copy what is left to the output, skipping before vowels and coeng Ro if they are present
+        for (i = prev; i < syllable; i += 1) {
+            charClass = classTable->getCharClass(chars[i]);
+            
+            // skip a before vowel, it was already processed
+            if (charClass & KhmerClassTable::CF_POS_BEFORE) {
+                continue;
+            }
+            
+            // skip coeng + ro, it was already processed
+            if (i == coengRo) {
+                i += 1;
+                continue;
+            }
+            
+            switch (charClass & KhmerClassTable::CF_POS_MASK) {
+                case KhmerClassTable::CF_POS_ABOVE :
+                    output.writeChar(chars[i], i, tagAbvf);
+                    break;
+                
+                case KhmerClassTable::CF_POS_AFTER :
+                    output.writeChar(chars[i], i, tagPstf);
+                    break;
+                
+                case KhmerClassTable::CF_POS_BELOW :
+                    output.writeChar(chars[i], i, tagBlwf);
+                    break;
+                
+                default:
+                    // assign the correct flags to a coeng consonant
+                    // Consonants of type 3 are taged as Post forms and those type 1 as below forms
+                    if ( (charClass & KhmerClassTable::CF_COENG) && i + 1 < syllable ) {
+                        if ( (classTable->getCharClass(chars[i + 1]) & KhmerClassTable::CF_CLASS_MASK) 
+                              == KhmerClassTable::CC_CONSONANT3) {
+                            output.writeChar(chars[i], i, tagPstf);
+                            i += 1;
+                            output.writeChar(chars[i], i, tagPstf);
+                        }
+                        else {
+                            output.writeChar(chars[i], i, tagBlwf);
+                            i += 1;
+                            output.writeChar(chars[i], i, tagBlwf);
+                        }
+                        break;
+                    }
+                    // if a shifter is followed by an above vowel change the shifter to below form,
+                    // an above vowel can have two possible positions i + 1 or i + 3 
+                    // (position i+1 corresponds to unicode 3, position i+3 to Unicode 4)
+                    // and there is an extra rule for C_VOWEL_AA + C_SIGN_NIKAHIT also for two
+                    // different positions, right after the shifter or after a vowel (Unicode 4)
+                    if ( (charClass & KhmerClassTable::CF_SHIFTER) && (i + 1 < syllable) ) {
+                        if ((classTable->getCharClass(chars[i + 1]) & KhmerClassTable::CF_ABOVE_VOWEL)
+                            || (i + 2 < syllable
+                                && ( (classTable->getCharClass(chars[i + 1]) & KhmerClassTable::CF_CLASS_MASK) == C_VOWEL_AA)
+                                && ( (classTable->getCharClass(chars[i + 2]) & KhmerClassTable::CF_CLASS_MASK) == C_SIGN_NIKAHIT))
+                            || (i + 3 < syllable && (classTable->getCharClass(chars[i + 3]) & KhmerClassTable::CF_ABOVE_VOWEL))
+                            || (i + 4 < syllable
+                                && ( (classTable->getCharClass(chars[i + 3]) & KhmerClassTable::CF_CLASS_MASK) == C_VOWEL_AA)
+                                && ( (classTable->getCharClass(chars[i + 4]) & KhmerClassTable::CF_CLASS_MASK) == C_SIGN_NIKAHIT) ) ) 
+                        {
+                            output.writeChar(chars[i], i, tagBlwf);
+                            break;
+                        }
+                        
+                    }
+                    // default - any other characters
+                    output.writeChar(chars[i], i, tagDefault);
+                    break;
+            } // switch
+        } // for
+
+        prev = syllable; // move the pointer to the start of next syllable
+    }
+
+    return output.getOutputIndex();
+}
+
+
+U_NAMESPACE_END
diff --git a/source/layout/KhmerReordering.h b/source/layout/KhmerReordering.h
new file mode 100644
index 0000000..eecd12d
--- /dev/null
+++ b/source/layout/KhmerReordering.h
@@ -0,0 +1,132 @@
+/*
+ * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved 
+ *
+ * This file is a modification of the ICU file IndicReordering.h
+ * by Jens Herden and Javier Sola for Khmer language 
+ *
+ */
+
+#ifndef __KHMERREORDERING_H
+#define __KHMERREORDERING_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+// Vocabulary 
+//     Base ->         A consonant or an independent vowel in its full (not subscript) form. It is the 
+//                     center of the syllable, it can be souranded by coeng (subscript) consonants, vowels,
+//                     split vowels, signs... but there is only one base in a syllable, it has to be coded as
+//                     the first character of the syllable.
+//     split vowel --> vowel that has two parts placed separately (e.g. Before and after the consonant).  
+//                     Khmer language has five of them. Khmer split vowels either have one part before the
+//                     base and one after the base or they have a part before the base and a part above the base.
+//                     The first part of all Khmer split vowels is the same character, identical to 
+//                     the glyph of Khmer dependent vowel SRA EI   
+//     coeng -->  modifier used in Khmer to construct coeng (subscript) consonants 
+//                Differently than indian languages, the coeng modifies the consonant that follows it,
+//                not the one preceding it  Each consonant has two forms, the base form and the subscript form
+//                the base form is the normal one (using the consonants code-point), the subscript form is
+//                displayed when the combination coeng + consonant is encountered.
+//     Consonant of type 1 -> A consonant which has subscript for that only occupies space under a base consonant
+//     Consonant of type 2.-> Its subscript form occupies space under and before the base (only one, RO)
+//     Consonant of Type 3 -> Its subscript form occupies space under and after the base (KHO, CHHO, THHO, BA, YO, SA)
+//     Consonant shifter -> Khmer has to series of consonants. The same dependent vowel has different sounds
+//                          if it is attached to a consonant of the first series or a consonant of the second series
+//                          Most consonants have an equivalent in the other series, but some of theme exist only in
+//                          one series (for example SA). If we want to use the consonant SA with a vowel sound that
+//                          can only be done with a vowel sound that corresponds to a vowel accompanying a consonant
+//                          of the other series, then we need to use a consonant shifter: TRIISAP or MUSIKATOAN
+//                          x17C9 y x17CA. TRIISAP changes a first series consonant to second series sound and 
+//                          MUSIKATOAN a second series consonant to have a first series vowel sound.
+//                          Consonant shifter are both normally supercript marks, but, when they are followed by a
+//                          superscript, they change shape and take the form of subscript dependent vowel SRA U.
+//                          If they are in the same syllable as a coeng consonant, Unicode 3.0 says that they
+//                          should be typed before the coeng. Unicode 4.0 breaks the standard and says that it should
+//                          be placed after the coeng consonant.
+//     Dependent vowel ->   In khmer dependent vowels can be placed above, below, before or after the base                             
+//                          Each vowel has its own position. Only one vowel per syllable is allowed.
+//     Signs            ->  Khmer has above signs and post signs. Only one above sign and/or one post sign are
+//                          Allowed in a syllable.
+//
+//     
+
+struct KhmerClassTable    // This list must include all types of components that can be used inside a syllable
+{
+    enum CharClassValues  // order is important here! This order must be the same that is found in each horizontal 
+                          // line in the statetable for Khmer (file KhmerReordering.cpp).
+    {
+        CC_RESERVED             =  0,
+        CC_CONSONANT            =  1, // consonant of type 1 or independent vowel
+        CC_CONSONANT2           =  2, // Consonant of type 2
+        CC_CONSONANT3           =  3, // Consonant of type 3 
+        CC_ZERO_WIDTH_NJ_MARK   =  4, // Zero Width non joiner character (0x200C)
+        CC_CONSONANT_SHIFTER    =  5, 
+        CC_ROBAT                =  6, // Khmer special diacritic accent -treated differently in state table
+        CC_COENG                =  7, // Subscript consonant combining character
+        CC_DEPENDENT_VOWEL      =  8, 
+        CC_SIGN_ABOVE           =  9,
+        CC_SIGN_AFTER           = 10,
+        CC_ZERO_WIDTH_J_MARK    = 11, // Zero width joiner character
+        CC_COUNT                = 12  // This is the number of character classes
+    };
+
+    enum CharClassFlags
+    {
+        CF_CLASS_MASK    = 0x0000FFFF,
+
+        CF_CONSONANT     = 0x01000000,  // flag to speed up comparing
+        CF_SPLIT_VOWEL   = 0x02000000,  // flag for a split vowel -> the first part is added in front of the syllable
+        CF_DOTTED_CIRCLE = 0x04000000,  // add a dotted circle if a character with this flag is the first in a syllable
+        CF_COENG         = 0x08000000,  // flag to speed up comparing
+        CF_SHIFTER       = 0x10000000,  // flag to speed up comparing
+        CF_ABOVE_VOWEL   = 0x20000000,  // flag to speed up comparing
+
+        // position flags
+        CF_POS_BEFORE    = 0x00080000,
+        CF_POS_BELOW     = 0x00040000,
+        CF_POS_ABOVE     = 0x00020000,
+        CF_POS_AFTER     = 0x00010000,
+        CF_POS_MASK      = 0x000f0000
+    };
+
+    typedef le_uint32 CharClass;
+
+    typedef le_int32 ScriptFlags;
+
+    LEUnicode firstChar;   // for Khmer this will become x1780
+    LEUnicode lastChar;    //  and this x17DF
+    const CharClass *classTable;
+
+    CharClass getCharClass(LEUnicode ch) const;
+
+    static const KhmerClassTable *getKhmerClassTable();
+};
+
+
+class KhmerReordering /* not : public UObject because all methods are static */ {
+public:
+    static le_int32 reorder(const LEUnicode *theChars, le_int32 charCount, le_int32 scriptCode,
+        LEUnicode *outChars, LEGlyphStorage &glyphStorage);
+
+    static const FeatureMap *getFeatureMap(le_int32 &count);
+
+private:
+    // do not instantiate
+    KhmerReordering();
+
+    static le_int32 findSyllable(const KhmerClassTable *classTable, const LEUnicode *chars, le_int32 prev, le_int32 charCount);
+
+};
+
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/LEFontInstance.cpp b/source/layout/LEFontInstance.cpp
new file mode 100644
index 0000000..e5595f2
--- /dev/null
+++ b/source/layout/LEFontInstance.cpp
@@ -0,0 +1,149 @@
+/*
+ *******************************************************************************
+ *
+ *   Copyright (C) 1999-2007, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ *
+ *******************************************************************************
+ *   file name:  LEFontInstance.cpp
+ *
+ *   created on: 02/06/2003
+ *   created by: Eric R. Mader
+ */
+
+#include "LETypes.h"
+#include "LEScripts.h"
+#include "LEFontInstance.h"
+#include "LEGlyphStorage.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LEFontInstance)
+
+LECharMapper::~LECharMapper()
+{
+    // nothing to do.
+}
+
+LEFontInstance::~LEFontInstance()
+{
+    // nothing to do
+}
+
+const LEFontInstance *LEFontInstance::getSubFont(const LEUnicode chars[], le_int32 *offset, le_int32 limit,
+                                                       le_int32 script, LEErrorCode &success) const
+{
+    if (LE_FAILURE(success)) {
+        return NULL;
+    }
+
+    if (chars == NULL || *offset < 0 || limit < 0 || *offset >= limit || script < 0 || script >= scriptCodeCount) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
+
+    *offset = limit;
+    return this;
+}
+
+void LEFontInstance::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count,
+                                      le_bool reverse, const LECharMapper *mapper, le_bool filterZeroWidth, LEGlyphStorage &glyphStorage) const
+{
+    le_int32 i, out = 0, dir = 1;
+
+    if (reverse) {
+        out = count - 1;
+        dir = -1;
+    }
+
+    for (i = offset; i < offset + count; i += 1, out += dir) {
+        LEUnicode16 high = chars[i];
+        LEUnicode32 code = high;
+
+        if (i < offset + count - 1 && high >= 0xD800 && high <= 0xDBFF) {
+            LEUnicode16 low = chars[i + 1];
+
+            if (low >= 0xDC00 && low <= 0xDFFF) {
+                code = (high - 0xD800) * 0x400 + low - 0xDC00 + 0x10000;
+            }
+        }
+
+        glyphStorage[out] = mapCharToGlyph(code, mapper, filterZeroWidth);
+
+        if (code >= 0x10000) {
+            i += 1;
+            glyphStorage[out += dir] = 0xFFFF;
+        }
+    }
+}
+
+LEGlyphID LEFontInstance::mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper) const
+{
+    return mapCharToGlyph(ch, mapper, TRUE);
+}
+
+LEGlyphID LEFontInstance::mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper, le_bool filterZeroWidth) const
+{
+    LEUnicode32 mappedChar = mapper->mapChar(ch);
+
+    if (mappedChar == 0xFFFE || mappedChar == 0xFFFF) {
+        return 0xFFFF;
+    }
+
+    if (filterZeroWidth && (mappedChar == 0x200C || mappedChar == 0x200D)) {
+        return canDisplay(mappedChar)? 0x0001 : 0xFFFF;
+    }
+
+    return mapCharToGlyph(mappedChar);
+}
+
+le_bool LEFontInstance::canDisplay(LEUnicode32 ch) const
+{
+    return LE_GET_GLYPH(mapCharToGlyph(ch)) != 0;
+}
+
+float LEFontInstance::xUnitsToPoints(float xUnits) const
+{
+    return (xUnits * getXPixelsPerEm()) / (float) getUnitsPerEM();
+}
+
+float LEFontInstance::yUnitsToPoints(float yUnits) const
+{
+    return (yUnits * getYPixelsPerEm()) / (float) getUnitsPerEM();
+}
+
+void LEFontInstance::unitsToPoints(LEPoint &units, LEPoint &points) const
+{
+    points.fX = xUnitsToPoints(units.fX);
+    points.fY = yUnitsToPoints(units.fY);
+}
+
+float LEFontInstance::xPixelsToUnits(float xPixels) const
+{
+    return (xPixels * getUnitsPerEM()) / (float) getXPixelsPerEm();
+}
+
+float LEFontInstance::yPixelsToUnits(float yPixels) const
+{
+    return (yPixels * getUnitsPerEM()) / (float) getYPixelsPerEm();
+}
+
+void LEFontInstance::pixelsToUnits(LEPoint &pixels, LEPoint &units) const
+{
+    units.fX = xPixelsToUnits(pixels.fX);
+    units.fY = yPixelsToUnits(pixels.fY);
+}
+
+void LEFontInstance::transformFunits(float xFunits, float yFunits, LEPoint &pixels) const
+{
+    pixels.fX = xUnitsToPoints(xFunits) * getScaleFactorX();
+    pixels.fY = yUnitsToPoints(yFunits) * getScaleFactorY();
+}
+
+le_int32 LEFontInstance::getLineHeight() const
+{
+    return getAscent() + getDescent() + getLeading();
+}
+
+U_NAMESPACE_END
+
diff --git a/source/layout/LEFontInstance.h b/source/layout/LEFontInstance.h
new file mode 100644
index 0000000..6747acb
--- /dev/null
+++ b/source/layout/LEFontInstance.h
@@ -0,0 +1,527 @@
+
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#ifndef __LEFONTINSTANCE_H
+#define __LEFONTINSTANCE_H
+
+#include "LETypes.h"
+/**
+ * \file 
+ * \brief C++ API: Layout Engine Font Instance object
+ */
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Instances of this class are used by <code>LEFontInstance::mapCharsToGlyphs</code> and
+ * <code>LEFontInstance::mapCharToGlyph</code> to adjust character codes before the character
+ * to glyph mapping process. Examples of this are filtering out control characters
+ * and character mirroring - replacing a character which has both a left and a right
+ * hand form with the opposite form.
+ *
+ * @stable ICU 3.2
+ */
+class LECharMapper /* not : public UObject because this is an interface/mixin class */
+{
+public:
+    /**
+     * Destructor.
+     * @stable ICU 3.2
+     */
+    virtual ~LECharMapper();
+
+    /**
+     * This method does the adjustments.
+     *
+     * @param ch - the input character
+     *
+     * @return the adjusted character
+     *
+     * @stable ICU 2.8
+     */
+    virtual LEUnicode32 mapChar(LEUnicode32 ch) const = 0;
+};
+
+/**
+ * This is a forward reference to the class which holds the per-glyph
+ * storage.
+ *
+ * @stable ICU 3.0
+ */
+class LEGlyphStorage;
+
+/**
+ * This is a virtual base class that serves as the interface between a LayoutEngine
+ * and the platform font environment. It allows a LayoutEngine to access font tables, do
+ * character to glyph mapping, and obtain metrics information without knowing any platform
+ * specific details. There are also a few utility methods for converting between points,
+ * pixels and funits. (font design units)
+ *
+ * An instance of an <code>LEFontInstance</code> represents a font at a particular point
+ * size. Each instance can represent either a single physical font, or a composite font.
+ * A composite font is a collection of physical fonts, each of which contains a subset of
+ * the characters contained in the composite font.
+ *
+ * Note: with the exception of <code>getSubFont</code>, the methods in this class only
+ * make sense for a physical font. If you have an <code>LEFontInstance</code> which
+ * represents a composite font you should only call the methods below which have
+ * an <code>LEGlyphID</code>, an <code>LEUnicode</code> or an <code>LEUnicode32</code>
+ * as one of the arguments because these can be used to select a particular subfont.
+ *
+ * Subclasses which implement composite fonts should supply an implementation of these
+ * methods with some default behavior such as returning constant values, or using the
+ * values from the first subfont.
+ *
+ * @stable ICU 3.0
+ */
+class U_LAYOUT_API LEFontInstance : public UObject
+{
+public:
+
+    /**
+     * This virtual destructor is here so that the subclass
+     * destructors can be invoked through the base class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual ~LEFontInstance();
+
+    /**
+     * Get a physical font which can render the given text. For composite fonts,
+     * if there is no single physical font which can render all of the text,
+     * return a physical font which can render an initial substring of the text,
+     * and set the <code>offset</code> parameter to the end of that substring.
+     *
+     * Internally, the LayoutEngine works with runs of text all in the same
+     * font and script, so it is best to call this method with text which is
+     * in a single script, passing the script code in as a hint. If you don't
+     * know the script of the text, you can use zero, which is the script code
+     * for characters used in more than one script.
+     *
+     * The default implementation of this method is intended for instances of
+     * <code>LEFontInstance</code> which represent a physical font. It returns
+     * <code>this</code> and indicates that the entire string can be rendered.
+     *
+     * This method will return a valid <code>LEFontInstance</code> unless you
+     * have passed illegal parameters, or an internal error has been encountered. 
+     * For composite fonts, it may return the warning <code>LE_NO_SUBFONT_WARNING</code>
+     * to indicate that the returned font may not be able to render all of
+     * the text. Whenever a valid font is returned, the <code>offset</code> parameter
+     * will be advanced by at least one.
+     *
+     * Subclasses which implement composite fonts must override this method.
+     * Where it makes sense, they should use the script code as a hint to render
+     * characters from the COMMON script in the font which is used for the given
+     * script. For example, if the input text is a series of Arabic words separated
+     * by spaces, and the script code passed in is <code>arabScriptCode</code> you
+     * should return the font used for Arabic characters for all of the input text,
+     * including the spaces. If, on the other hand, the input text contains characters
+     * which cannot be rendered by the font used for Arabic characters, but which can
+     * be rendered by another font, you should return that font for those characters.
+     *
+     * @param chars   - the array of Unicode characters.
+     * @param offset  - a pointer to the starting offset in the text. On exit this
+     *                  will be set the the limit offset of the text which can be
+     *                  rendered using the returned font.
+     * @param limit   - the limit offset for the input text.
+     * @param script  - the script hint.
+     * @param success - set to an error code if the arguments are illegal, or no font
+     *                  can be returned for some reason. May also be set to
+     *                  <code>LE_NO_SUBFONT_WARNING</code> if the subfont which
+     *                  was returned cannot render all of the text.
+     *
+     * @return an <code>LEFontInstance</code> for the sub font which can render the characters, or
+     *         <code>NULL</code> if there is an error.
+     *
+     * @see LEScripts.h
+     *
+     * @stable ICU 3.2
+     */
+    virtual const LEFontInstance *getSubFont(const LEUnicode chars[], le_int32 *offset, le_int32 limit, le_int32 script, LEErrorCode &success) const;
+
+    //
+    // Font file access
+    //
+
+    /**
+     * This method reads a table from the font. Note that in general,
+     * it only makes sense to call this method on an <code>LEFontInstance</code>
+     * which represents a physical font - i.e. one which has been returned by
+     * <code>getSubFont()</code>. This is because each subfont in a composite font
+     * will have different tables, and there's no way to know which subfont to access.
+     *
+     * Subclasses which represent composite fonts should always return <code>NULL</code>.
+     *
+     * @param tableTag - the four byte table tag. (e.g. 'cmap') 
+     *
+     * @return the address of the table in memory, or <code>NULL</code>
+     *         if the table doesn't exist.
+     *
+     * @stable ICU 2.8
+     */
+    virtual const void *getFontTable(LETag tableTag) const = 0;
+
+    /**
+     * This method is used to determine if the font can
+     * render the given character. This can usually be done
+     * by looking the character up in the font's character
+     * to glyph mapping.
+     *
+     * The default implementation of this method will return
+     * <code>TRUE</code> if <code>mapCharToGlyph(ch)</code>
+     * returns a non-zero value.
+     *
+     * @param ch - the character to be tested
+     *
+     * @return <code>TRUE</code> if the font can render ch.
+     *
+     * @stable ICU 3.2
+     */
+    virtual le_bool canDisplay(LEUnicode32 ch) const;
+
+    /**
+     * This method returns the number of design units in
+     * the font's EM square.
+     *
+     * @return the number of design units pre EM.
+     *
+     * @stable ICU 2.8
+     */
+    virtual le_int32 getUnitsPerEM() const = 0;
+
+    /**
+     * This method maps an array of character codes to an array of glyph
+     * indices, using the font's character to glyph map.
+     *
+     * The default implementation iterates over all of the characters and calls
+     * <code>mapCharToGlyph(ch, mapper)</code> on each one. It also handles surrogate
+     * characters, storing the glyph ID for the high surrogate, and a deleted glyph (0xFFFF)
+     * for the low surrogate.
+     *
+     * Most sublcasses will not need to implement this method.
+     *
+     * @param chars - the character array
+     * @param offset - the index of the first character
+     * @param count - the number of characters
+     * @param reverse - if <code>TRUE</code>, store the glyph indices in reverse order.
+     * @param mapper - the character mapper.
+     * @param filterZeroWidth - <code>TRUE</code> if ZWJ / ZWNJ characters should map to a glyph w/ no contours.
+     * @param glyphStorage - the object which contains the output glyph array
+     *
+     * @see LECharMapper
+     *
+     * @stable ICU 3.6
+     */
+    virtual void mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, const LECharMapper *mapper, le_bool filterZeroWidth, LEGlyphStorage &glyphStorage) const;
+
+    /**
+     * This method maps a single character to a glyph index, using the
+     * font's character to glyph map. The default implementation of this
+     * method calls the mapper, and then calls <code>mapCharToGlyph(mappedCh)</code>.
+     *
+     * @param ch - the character
+     * @param mapper - the character mapper
+     * @param filterZeroWidth - <code>TRUE</code> if ZWJ / ZWNJ characters should map to a glyph w/ no contours.
+     *
+     * @return the glyph index
+     *
+     * @see LECharMapper
+     *
+     * @stable ICU 3.6
+     */
+    virtual LEGlyphID mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper, le_bool filterZeroWidth) const;
+
+    /**
+     * This method maps a single character to a glyph index, using the
+     * font's character to glyph map. The default implementation of this
+     * method calls the mapper, and then calls <code>mapCharToGlyph(mappedCh)</code>.
+     *
+     * @param ch - the character
+     * @param mapper - the character mapper
+     *
+     * @return the glyph index
+     *
+     * @see LECharMapper
+     *
+     * @stable ICU 3.2
+     */
+    virtual LEGlyphID mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper) const;
+
+    /**
+     * This method maps a single character to a glyph index, using the
+     * font's character to glyph map. There is no default implementation
+     * of this method because it requires information about the platform
+     * font implementation.
+     *
+     * @param ch - the character
+     *
+     * @return the glyph index
+     *
+     * @stable ICU 3.2
+     */
+    virtual LEGlyphID mapCharToGlyph(LEUnicode32 ch) const = 0;
+
+    //
+    // Metrics
+    //
+
+    /**
+     * This method gets the X and Y advance of a particular glyph, in pixels.
+     *
+     * @param glyph - the glyph index
+     * @param advance - the X and Y pixel values will be stored here
+     *
+     * @stable ICU 3.2
+     */
+    virtual void getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const = 0;
+
+    /**
+     * This method gets the hinted X and Y pixel coordinates of a particular
+     * point in the outline of the given glyph.
+     *
+     * @param glyph - the glyph index
+     * @param pointNumber - the number of the point
+     * @param point - the point's X and Y pixel values will be stored here
+     *
+     * @return <code>TRUE</code> if the point coordinates could be stored.
+     *
+     * @stable ICU 2.8
+     */
+    virtual le_bool getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const = 0;
+
+    /**
+     * This method returns the width of the font's EM square
+     * in pixels.
+     *
+     * @return the pixel width of the EM square
+     *
+     * @stable ICU 2.8
+     */
+    virtual float getXPixelsPerEm() const = 0;
+
+    /**
+     * This method returns the height of the font's EM square
+     * in pixels.
+     *
+     * @return the pixel height of the EM square
+     *
+     * @stable ICU 2.8
+     */
+    virtual float getYPixelsPerEm() const = 0;
+
+    /**
+     * This method converts font design units in the
+     * X direction to points.
+     *
+     * @param xUnits - design units in the X direction
+     *
+     * @return points in the X direction
+     *
+     * @stable ICU 3.2
+     */
+    virtual float xUnitsToPoints(float xUnits) const;
+
+    /**
+     * This method converts font design units in the
+     * Y direction to points.
+     *
+     * @param yUnits - design units in the Y direction
+     *
+     * @return points in the Y direction
+     *
+     * @stable ICU 3.2
+     */
+    virtual float yUnitsToPoints(float yUnits) const;
+
+    /**
+     * This method converts font design units to points.
+     *
+     * @param units - X and Y design units
+     * @param points - set to X and Y points
+     *
+     * @stable ICU 3.2
+     */
+    virtual void unitsToPoints(LEPoint &units, LEPoint &points) const;
+
+    /**
+     * This method converts pixels in the
+     * X direction to font design units.
+     *
+     * @param xPixels - pixels in the X direction
+     *
+     * @return font design units in the X direction
+     *
+     * @stable ICU 3.2
+     */
+    virtual float xPixelsToUnits(float xPixels) const;
+
+    /**
+     * This method converts pixels in the
+     * Y direction to font design units.
+     *
+     * @param yPixels - pixels in the Y direction
+     *
+     * @return font design units in the Y direction
+     *
+     * @stable ICU 3.2
+     */
+    virtual float yPixelsToUnits(float yPixels) const;
+
+    /**
+     * This method converts pixels to font design units.
+     *
+     * @param pixels - X and Y pixel
+     * @param units - set to X and Y font design units
+     *
+     * @stable ICU 3.2
+     */
+    virtual void pixelsToUnits(LEPoint &pixels, LEPoint &units) const;
+
+    /**
+     * Get the X scale factor from the font's transform. The default
+     * implementation of <code>transformFunits()</code> will call this method.
+     *
+     * @return the X scale factor.
+     *
+     *
+     * @see transformFunits
+     *
+     * @stable ICU 3.2
+     */
+    virtual float getScaleFactorX() const = 0;
+
+    /**
+     * Get the Y scale factor from the font's transform. The default
+     * implementation of <code>transformFunits()</code> will call this method.
+     *
+     * @return the Yscale factor.
+     *
+     * @see transformFunits
+     *
+     * @stable ICU 3.2
+     */
+    virtual float getScaleFactorY() const = 0;
+
+    /**
+     * This method transforms an X, Y point in font design units to a
+     * pixel coordinate, applying the font's transform. The default
+     * implementation of this method calls <code>getScaleFactorX()</code>
+     * and <code>getScaleFactorY()</code>.
+     *
+     * @param xFunits - the X coordinate in font design units
+     * @param yFunits - the Y coordinate in font design units
+     * @param pixels - the tranformed co-ordinate in pixels
+     *
+     * @see getScaleFactorX
+     * @see getScaleFactorY
+     *
+     * @stable ICU 3.2
+     */
+    virtual void transformFunits(float xFunits, float yFunits, LEPoint &pixels) const;
+
+    /**
+     * This is a convenience method used to convert
+     * values in a 16.16 fixed point format to floating point.
+     *
+     * @param fixed - the fixed point value
+     *
+     * @return the floating point value
+     *
+     * @stable ICU 2.8
+     */
+    static inline float fixedToFloat(le_int32 fixed);
+
+    /**
+     * This is a convenience method used to convert
+     * floating point values to 16.16 fixed point format.
+     *
+     * @param theFloat - the floating point value
+     *
+     * @return the fixed point value
+     *
+     * @stable ICU 2.8
+     */
+    static inline le_int32 floatToFixed(float theFloat);
+
+    //
+    // These methods won't ever be called by the LayoutEngine,
+    // but are useful for clients of <code>LEFontInstance</code> who
+    // need to render text.
+    //
+
+    /**
+     * Get the font's ascent.
+     *
+     * @return the font's ascent, in points. This value
+     * will always be positive.
+     *
+     * @stable ICU 3.2
+     */
+    virtual le_int32 getAscent() const = 0;
+
+    /**
+     * Get the font's descent.
+     *
+     * @return the font's descent, in points. This value
+     * will always be positive.
+     *
+     * @stable ICU 3.2
+     */
+    virtual le_int32 getDescent() const = 0;
+
+    /**
+     * Get the font's leading.
+     *
+     * @return the font's leading, in points. This value
+     * will always be positive.
+     *
+     * @stable ICU 3.2
+     */
+    virtual le_int32 getLeading() const = 0;
+
+    /**
+     * Get the line height required to display text in
+     * this font. The default implementation of this method
+     * returns the sum of the ascent, descent, and leading.
+     *
+     * @return the line height, in points. This vaule will
+     * always be positive.
+     *
+     * @stable ICU 3.2
+     */
+    virtual le_int32 getLineHeight() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 3.2
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 3.2
+     */
+    static UClassID getStaticClassID();
+
+};
+
+inline float LEFontInstance::fixedToFloat(le_int32 fixed)
+{
+    return (float) (fixed / 65536.0);
+}
+
+inline le_int32 LEFontInstance::floatToFixed(float theFloat)
+{
+    return (le_int32) (theFloat * 65536.0);
+}
+
+U_NAMESPACE_END
+#endif
+
+
diff --git a/source/layout/LEGlyphFilter.h b/source/layout/LEGlyphFilter.h
new file mode 100644
index 0000000..f8fa173
--- /dev/null
+++ b/source/layout/LEGlyphFilter.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __LEGLYPHFILTER__H
+#define __LEGLYPHFILTER__H
+
+#include "LETypes.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * This is a helper class that is used to
+ * recognize a set of glyph indices.
+ *
+ * @internal
+ */
+class LEGlyphFilter /* not : public UObject because this is an interface/mixin class */ {
+public:
+    /**
+     * Destructor.
+     * @internal
+     */
+    virtual ~LEGlyphFilter();
+
+    /**
+     * This method is used to test a particular
+     * glyph index to see if it is in the set
+     * recognized by the filter.
+     *
+     * @param glyph - the glyph index to be tested
+     *
+     * @return TRUE if the glyph index is in the set.
+     *
+     * @internal
+     */
+    virtual le_bool accept(LEGlyphID glyph) const = 0;
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/LEGlyphStorage.cpp b/source/layout/LEGlyphStorage.cpp
new file mode 100644
index 0000000..bac403a
--- /dev/null
+++ b/source/layout/LEGlyphStorage.cpp
@@ -0,0 +1,666 @@
+/*
+ **********************************************************************
+ *   Copyright (C) 1998-2009, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ **********************************************************************
+ */
+
+#include "LETypes.h"
+#include "LEInsertionList.h"
+#include "LEGlyphStorage.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LEGlyphStorage)
+
+LEInsertionCallback::~LEInsertionCallback()
+{
+	// nothing to do...
+}
+
+LEGlyphStorage::LEGlyphStorage()
+    : fGlyphCount(0), fGlyphs(NULL), fCharIndices(NULL), fPositions(NULL),
+      fAuxData(NULL), fInsertionList(NULL), fSrcIndex(0), fDestIndex(0)
+{
+    // nothing else to do!
+}
+
+LEGlyphStorage::~LEGlyphStorage()
+{
+    reset();
+}
+
+void LEGlyphStorage::reset()
+{
+    fGlyphCount = 0;
+
+    if (fPositions != NULL) {
+        LE_DELETE_ARRAY(fPositions);
+        fPositions = NULL;
+    }
+
+    if (fAuxData != NULL) {
+        LE_DELETE_ARRAY(fAuxData);
+        fAuxData = NULL;
+    }
+
+    if (fInsertionList != NULL) {
+        delete fInsertionList;
+        fInsertionList = NULL;
+    }
+
+    if (fCharIndices != NULL) {
+        LE_DELETE_ARRAY(fCharIndices);
+        fCharIndices = NULL;
+    }
+
+    if (fGlyphs != NULL) {
+        LE_DELETE_ARRAY(fGlyphs);
+        fGlyphs = NULL;
+    }
+}
+
+// FIXME: This might get called more than once, for various reasons. Is
+// testing for pre-existing glyph and charIndices arrays good enough?
+void LEGlyphStorage::allocateGlyphArray(le_int32 initialGlyphCount, le_bool rightToLeft, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return;
+    }
+
+    if (initialGlyphCount <= 0) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    if (fGlyphs == NULL) {
+        fGlyphCount = initialGlyphCount;
+        fGlyphs = LE_NEW_ARRAY(LEGlyphID, fGlyphCount);
+
+        if (fGlyphs == NULL) {
+            success = LE_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+    }
+
+    if (fCharIndices == NULL) {
+        fCharIndices = LE_NEW_ARRAY(le_int32, fGlyphCount);
+
+        if (fCharIndices == NULL) {
+            LE_DELETE_ARRAY(fGlyphs);
+            fGlyphs = NULL;
+            success = LE_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+
+        // Initialize the charIndices array
+        le_int32 i, count = fGlyphCount, dir = 1, out = 0;
+
+        if (rightToLeft) {
+            out = fGlyphCount - 1;
+            dir = -1;
+        }
+
+        for (i = 0; i < count; i += 1, out += dir) {
+            fCharIndices[out] = i;
+        }
+    }
+
+    if (fInsertionList == NULL) {
+        // FIXME: check this for failure?
+        fInsertionList = new LEInsertionList(rightToLeft);
+        if (fInsertionList == NULL) { 
+            LE_DELETE_ARRAY(fCharIndices);
+            fCharIndices = NULL;
+
+            LE_DELETE_ARRAY(fGlyphs);
+            fGlyphs = NULL;
+
+            success = LE_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+    }
+}
+
+// FIXME: do we want to initialize the positions to [0, 0]?
+le_int32 LEGlyphStorage::allocatePositions(LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return -1;
+    }
+
+    if (fPositions != NULL) {
+        success = LE_INTERNAL_ERROR;
+        return -1;
+    }
+
+    fPositions = LE_NEW_ARRAY(float, 2 * (fGlyphCount + 1));
+
+    if (fPositions == NULL) {
+        success = LE_MEMORY_ALLOCATION_ERROR;
+        return -1;
+    }
+
+    return fGlyphCount;
+}
+
+// FIXME: do we want to initialize the aux data to NULL?
+le_int32 LEGlyphStorage::allocateAuxData(LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return -1;
+    }
+
+    if (fAuxData != NULL) {
+        success = LE_INTERNAL_ERROR;
+        return -1;
+    }
+
+    fAuxData = LE_NEW_ARRAY(le_uint32, fGlyphCount);
+
+    if (fAuxData == NULL) {
+        success = LE_MEMORY_ALLOCATION_ERROR;
+        return -1;
+    }
+
+    return fGlyphCount;
+}
+
+void LEGlyphStorage::getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const
+{
+    le_int32 i;
+
+    if (LE_FAILURE(success)) {
+        return;
+    }
+
+    if (charIndices == NULL) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    if (fCharIndices == NULL) {
+        success = LE_NO_LAYOUT_ERROR;
+        return;
+    }
+
+    for (i = 0; i < fGlyphCount; i += 1) {
+        charIndices[i] = fCharIndices[i] + indexBase;
+    }
+}
+
+void LEGlyphStorage::getCharIndices(le_int32 charIndices[], LEErrorCode &success) const
+{
+    if (LE_FAILURE(success)) {
+      return;
+    }
+    
+    if (charIndices == NULL) {
+      success = LE_ILLEGAL_ARGUMENT_ERROR;
+      return;
+    }
+    
+    if (fCharIndices == NULL) {
+      success = LE_NO_LAYOUT_ERROR;
+      return;
+    }
+    
+    LE_ARRAY_COPY(charIndices, fCharIndices, fGlyphCount);
+}
+
+// Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits
+void LEGlyphStorage::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const
+{
+    le_int32 i;
+
+    if (LE_FAILURE(success)) {
+        return;
+    }
+
+    if (glyphs == NULL) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    if (fGlyphs == NULL) {
+        success = LE_NO_LAYOUT_ERROR;
+        return;
+    }
+
+    for (i = 0; i < fGlyphCount; i += 1) {
+        glyphs[i] = fGlyphs[i] | extraBits;
+    }
+}
+
+void LEGlyphStorage::getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const
+{
+    if (LE_FAILURE(success)) {
+      return;
+    }
+    
+    if (glyphs == NULL) {
+      success = LE_ILLEGAL_ARGUMENT_ERROR;
+      return;
+    }
+    
+    if (fGlyphs == NULL) {
+      success = LE_NO_LAYOUT_ERROR;
+      return;
+    }
+    
+    LE_ARRAY_COPY(glyphs, fGlyphs, fGlyphCount);
+}
+
+LEGlyphID LEGlyphStorage::getGlyphID(le_int32 glyphIndex, LEErrorCode &success) const
+{
+    if (LE_FAILURE(success)) {
+        return 0xFFFF;
+    }
+
+    if (fGlyphs == NULL) {
+        success = LE_NO_LAYOUT_ERROR;
+        return 0xFFFF;
+    }
+
+    if (glyphIndex < 0 || glyphIndex >= fGlyphCount) {
+        success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
+        return 0xFFFF;
+    }
+
+    return fGlyphs[glyphIndex];
+}
+
+void LEGlyphStorage::setGlyphID(le_int32 glyphIndex, LEGlyphID glyphID, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return;
+    }
+
+    if (fGlyphs == NULL) {
+        success = LE_NO_LAYOUT_ERROR;
+        return;
+    }
+
+    if (glyphIndex < 0 || glyphIndex >= fGlyphCount) {
+        success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
+        return;
+    }
+
+    fGlyphs[glyphIndex] = glyphID;
+}
+
+le_int32 LEGlyphStorage::getCharIndex(le_int32 glyphIndex, LEErrorCode &success) const
+{
+    if (LE_FAILURE(success)) {
+        return -1;
+    }
+
+    if (fCharIndices == NULL) {
+        success = LE_NO_LAYOUT_ERROR;
+        return -1;
+    }
+
+    if (glyphIndex < 0 || glyphIndex >= fGlyphCount) {
+        success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
+        return -1;
+    }
+
+    return fCharIndices[glyphIndex];
+}
+
+void LEGlyphStorage::setCharIndex(le_int32 glyphIndex, le_int32 charIndex, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return;
+    }
+
+    if (fCharIndices == NULL) {
+        success = LE_NO_LAYOUT_ERROR;
+        return;
+    }
+
+    if (glyphIndex < 0 || glyphIndex >= fGlyphCount) {
+        success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
+        return;
+    }
+
+    fCharIndices[glyphIndex] = charIndex;
+}
+
+void LEGlyphStorage::getAuxData(le_uint32 auxData[], LEErrorCode &success) const
+{
+    if (LE_FAILURE(success)) {
+      return;
+    }
+    
+    if (auxData == NULL) {
+      success = LE_ILLEGAL_ARGUMENT_ERROR;
+      return;
+    }
+    
+    if (fAuxData == NULL) {
+      success = LE_NO_LAYOUT_ERROR;
+      return;
+    }
+    
+    LE_ARRAY_COPY(auxData, fAuxData, fGlyphCount);
+}
+
+le_uint32 LEGlyphStorage::getAuxData(le_int32 glyphIndex, LEErrorCode &success) const
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if (fAuxData == NULL) {
+        success = LE_NO_LAYOUT_ERROR;
+        return 0;
+    }
+    
+    if (glyphIndex < 0 || glyphIndex >= fGlyphCount) {
+        success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
+        return 0;
+    }
+
+    return fAuxData[glyphIndex];
+}
+
+void LEGlyphStorage::setAuxData(le_int32 glyphIndex, le_uint32 auxData, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return;
+    }
+
+    if (fAuxData == NULL) {
+        success = LE_NO_LAYOUT_ERROR;
+        return;
+    }
+
+    if (glyphIndex < 0 || glyphIndex >= fGlyphCount) {
+        success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
+        return;
+    }
+
+    fAuxData[glyphIndex] = auxData;
+}
+
+void LEGlyphStorage::getGlyphPositions(float positions[], LEErrorCode &success) const
+{
+    if (LE_FAILURE(success)) {
+      return;
+    }
+  
+    if (positions == NULL) {
+      success = LE_ILLEGAL_ARGUMENT_ERROR;
+      return;
+    }
+    
+    if (fPositions == NULL) {
+      success = LE_NO_LAYOUT_ERROR;
+      return;
+    }
+    
+    LE_ARRAY_COPY(positions, fPositions, fGlyphCount * 2 + 2);
+}
+
+void LEGlyphStorage::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const
+{
+    if (LE_FAILURE(success)) {
+      return;
+    }
+    
+    if (glyphIndex < 0 || glyphIndex > fGlyphCount) {
+      success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
+      return;
+    }
+    
+    if (fPositions == NULL) {
+      success = LE_NO_LAYOUT_ERROR;
+      return;
+    }
+    
+    x = fPositions[glyphIndex * 2];
+    y = fPositions[glyphIndex * 2 + 1];
+}
+
+void LEGlyphStorage::setPosition(le_int32 glyphIndex, float x, float y, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return;
+    }
+    
+    if (glyphIndex < 0 || glyphIndex > fGlyphCount) {
+      success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
+      return;
+    }
+    
+    fPositions[glyphIndex * 2]     = x;
+    fPositions[glyphIndex * 2 + 1] = y;
+}
+
+void LEGlyphStorage::adjustPosition(le_int32 glyphIndex, float xAdjust, float yAdjust, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return;
+    }
+    
+    if (glyphIndex < 0 || glyphIndex > fGlyphCount) {
+      success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
+      return;
+    }
+    
+    fPositions[glyphIndex * 2]     += xAdjust;
+    fPositions[glyphIndex * 2 + 1] += yAdjust;
+}
+
+void LEGlyphStorage::adoptGlyphArray(LEGlyphStorage &from)
+{
+    if (fGlyphs != NULL) {
+        LE_DELETE_ARRAY(fGlyphs);
+    }
+
+    fGlyphs = from.fGlyphs;
+    from.fGlyphs = NULL;
+
+    if (fInsertionList != NULL) {
+        delete fInsertionList;
+    }
+
+    fInsertionList = from.fInsertionList;
+    from.fInsertionList = NULL;
+}
+
+void LEGlyphStorage::adoptCharIndicesArray(LEGlyphStorage &from)
+{
+    if (fCharIndices != NULL) {
+        LE_DELETE_ARRAY(fCharIndices);
+    }
+
+    fCharIndices = from.fCharIndices;
+    from.fCharIndices = NULL;
+}
+
+void LEGlyphStorage::adoptPositionArray(LEGlyphStorage &from)
+{
+    if (fPositions != NULL) {
+        LE_DELETE_ARRAY(fPositions);
+    }
+
+    fPositions = from.fPositions;
+    from.fPositions = NULL;
+}
+
+void LEGlyphStorage::adoptAuxDataArray(LEGlyphStorage &from)
+{
+    if (fAuxData != NULL) {
+        LE_DELETE_ARRAY(fAuxData);
+    }
+
+    fAuxData = from.fAuxData;
+    from.fAuxData = NULL;
+}
+
+void LEGlyphStorage::adoptGlyphCount(LEGlyphStorage &from)
+{
+    fGlyphCount = from.fGlyphCount;
+}
+
+void LEGlyphStorage::adoptGlyphCount(le_int32 newGlyphCount)
+{
+    fGlyphCount = newGlyphCount;
+}
+
+// Move a glyph to a different position in the LEGlyphStorage ( used for Indic v2 processing )
+
+void LEGlyphStorage::moveGlyph(le_int32 fromPosition, le_int32 toPosition, le_uint32 marker )
+{
+
+    LEErrorCode success = LE_NO_ERROR;
+
+    LEGlyphID holdGlyph = getGlyphID(fromPosition,success);
+    le_int32 holdCharIndex = getCharIndex(fromPosition,success);
+    le_uint32 holdAuxData = getAuxData(fromPosition,success);
+
+    if ( fromPosition < toPosition ) {
+        for ( le_int32 i = fromPosition ; i < toPosition ; i++ ) {
+            setGlyphID(i,getGlyphID(i+1,success),success);
+            setCharIndex(i,getCharIndex(i+1,success),success);
+            setAuxData(i,getAuxData(i+1,success),success);
+        }
+    } else {
+        for ( le_int32 i = toPosition ; i > fromPosition ; i-- ) {
+            setGlyphID(i,getGlyphID(i-1,success),success);
+            setCharIndex(i,getCharIndex(i-1,success),success);
+            setAuxData(i,getAuxData(i-1,success),success);
+
+        }
+    }
+
+    setGlyphID(toPosition,holdGlyph,success);
+    setCharIndex(toPosition,holdCharIndex,success);
+    setAuxData(toPosition,holdAuxData | marker,success);
+
+}
+
+// Glue code for existing stable API
+LEGlyphID *LEGlyphStorage::insertGlyphs(le_int32  atIndex, le_int32 insertCount)
+{
+    LEErrorCode ignored = LE_NO_LAYOUT_ERROR;
+    return insertGlyphs(atIndex, insertCount, ignored);
+}
+
+// FIXME: add error checking?
+LEGlyphID *LEGlyphStorage::insertGlyphs(le_int32  atIndex, le_int32 insertCount, LEErrorCode& success)
+{
+    return fInsertionList->insert(atIndex, insertCount, success);
+}
+
+le_int32 LEGlyphStorage::applyInsertions()
+{
+    le_int32 growAmount = fInsertionList->getGrowAmount();
+
+    if (growAmount == 0) {
+        return fGlyphCount;
+    }
+
+    le_int32 newGlyphCount = fGlyphCount + growAmount;
+
+    LEGlyphID *newGlyphs = (LEGlyphID *) LE_GROW_ARRAY(fGlyphs, newGlyphCount); 
+    if (newGlyphs == NULL) { 
+        // Could not grow the glyph array 
+        return fGlyphCount; 
+    } 
+    fGlyphs = newGlyphs; 
+
+    le_int32 *newCharIndices = (le_int32 *) LE_GROW_ARRAY(fCharIndices, newGlyphCount);
+    if (newCharIndices == NULL) { 
+        // Could not grow the glyph array 
+        return fGlyphCount; 
+    } 
+    fCharIndices = newCharIndices;
+
+    if (fAuxData != NULL) {	
+        le_uint32 *newAuxData = (le_uint32 *) LE_GROW_ARRAY(fAuxData, newGlyphCount); 
+        if (newAuxData == NULL) { 
+            // could not grow the aux data array 
+            return fGlyphCount; 
+        } 
+        fAuxData = (le_uint32 *)newAuxData;
+    }
+
+    fSrcIndex  = fGlyphCount - 1;
+    fDestIndex = newGlyphCount - 1;
+
+#if 0
+    // If the current position is at the end of the array
+    // update it to point to the end of the new array. The
+    // insertion callback will handle all other cases.
+    // FIXME: this is left over from GlyphIterator, but there's no easy
+    // way to implement this here... it seems that GlyphIterator doesn't
+    // really need it 'cause the insertions don't get  applied until after a
+    // complete pass over the glyphs, after which the iterator gets reset anyhow...
+    // probably better to just document that for LEGlyphStorage and GlyphIterator...
+    if (position == glyphCount) {
+        position = newGlyphCount;
+    }
+#endif
+
+    fInsertionList->applyInsertions(this);
+
+    fInsertionList->reset();
+
+    return fGlyphCount = newGlyphCount;
+}
+
+le_bool LEGlyphStorage::applyInsertion(le_int32 atPosition, le_int32 count, LEGlyphID newGlyphs[])
+{
+#if 0
+    // if the current position is within the block we're shifting
+    // it needs to be updated to the current glyph's
+    // new location.
+    // FIXME: this is left over from GlyphIterator, but there's no easy
+    // way to implement this here... it seems that GlyphIterator doesn't
+    // really need it 'cause the insertions don't get  applied until after a
+    // complete pass over the glyphs, after which the iterator gets reset anyhow...
+    // probably better to just document that for LEGlyphStorage and GlyphIterator...
+    if (position >= atPosition && position <= fSrcIndex) {
+        position += fDestIndex - fSrcIndex;
+    }
+#endif
+
+    if (fAuxData != NULL) {
+        le_int32 src = fSrcIndex, dest = fDestIndex;
+
+        while (src > atPosition) {
+            fAuxData[dest--] = fAuxData[src--];
+        }
+
+        for (le_int32 i = count - 1; i >= 0; i -= 1) {
+            fAuxData[dest--] = fAuxData[atPosition];
+        }
+    }
+
+    while (fSrcIndex > atPosition) {
+        fGlyphs[fDestIndex]      = fGlyphs[fSrcIndex];
+        fCharIndices[fDestIndex] = fCharIndices[fSrcIndex];
+
+        fDestIndex -= 1;
+        fSrcIndex  -= 1;
+    }
+
+    for (le_int32 i = count - 1; i >= 0; i -= 1) {
+        fGlyphs[fDestIndex]      = newGlyphs[i];
+        fCharIndices[fDestIndex] = fCharIndices[atPosition];
+
+        fDestIndex -= 1;
+    }
+
+    // the source glyph we're pointing at
+    // just got replaced by the insertion
+    fSrcIndex -= 1;
+
+    return FALSE;
+}
+
+U_NAMESPACE_END
+
diff --git a/source/layout/LEGlyphStorage.h b/source/layout/LEGlyphStorage.h
new file mode 100644
index 0000000..8828b3f
--- /dev/null
+++ b/source/layout/LEGlyphStorage.h
@@ -0,0 +1,546 @@
+/*
+ **********************************************************************
+ *   Copyright (C) 1998-2010, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ **********************************************************************
+ */
+
+#ifndef __LEGLYPHSTORAGE_H
+#define __LEGLYPHSTORAGE_H
+
+#include "LETypes.h"
+#include "LEInsertionList.h"
+
+/**
+ * \file 
+ * \brief C++ API: This class encapsulates the per-glyph storage used by the ICU LayoutEngine.
+ */
+
+U_NAMESPACE_BEGIN
+
+/**
+ * This class encapsulates the per-glyph storage used by the ICU LayoutEngine.
+ * For each glyph it holds the glyph ID, the index of the backing store character
+ * which produced the glyph, the X and Y position of the glyph and an auxillary data
+ * pointer.
+ *
+ * The storage is growable using the <code>LEInsertionList</code> class.
+ *
+ *
+ * @see LEInsertionList.h
+ *
+ * @stable ICU 3.6
+ */
+class U_LAYOUT_API LEGlyphStorage : public UObject, protected LEInsertionCallback
+{
+private:
+    /**
+     * The number of entries in the per-glyph arrays.
+     *
+     * @internal
+     */
+    le_int32   fGlyphCount;
+
+    /**
+     * The glyph ID array.
+     *
+     * @internal
+     */
+    LEGlyphID *fGlyphs;
+ 
+    /**
+     * The char indices array.
+     *
+     * @internal
+     */
+    le_int32  *fCharIndices;
+
+    /**
+     * The glyph positions array.
+     *
+     * @internal
+     */
+    float     *fPositions;
+
+    /**
+     * The auxillary data array.
+     *
+     * @internal
+     */
+    le_uint32 *fAuxData;
+
+
+    /**
+     * The insertion list, used to grow the above arrays.
+     *
+     * @internal
+     */
+    LEInsertionList *fInsertionList;
+
+    /**
+     * The source index while growing the data arrays.
+     *
+     * @internal
+     */
+    le_int32 fSrcIndex;
+
+    /**
+     * The destination index used while growing the data arrays.
+     *
+     * @internal
+     */
+    le_int32 fDestIndex;
+
+protected:
+    /**
+     * This implements <code>LEInsertionCallback</code>. The <code>LEInsertionList</code>
+     * will call this method once for each insertion.
+     *
+     * @param atPosition the position of the insertion
+     * @param count the number of glyphs being inserted
+     * @param newGlyphs the address of the new glyph IDs
+     *
+     * @return <code>true</code> if <code>LEInsertionList</code> should stop
+     *         processing the insertion list after this insertion.
+     *
+     * @see LEInsertionList.h
+     *
+     * @stable ICU 3.0
+     */
+    virtual le_bool applyInsertion(le_int32 atPosition, le_int32 count, LEGlyphID newGlyphs[]);
+
+public:
+
+    /**
+     * Allocates an empty <code>LEGlyphStorage</code> object. You must call
+     * <code>allocateGlyphArray, allocatePositions and allocateAuxData</code>
+     * to allocate the data.
+     *
+     * @stable ICU 3.0
+     */
+    LEGlyphStorage();
+
+    /**
+     * The destructor. This will deallocate all of the arrays.
+     *
+     * @stable ICU 3.0
+     */
+    ~LEGlyphStorage();
+
+    /**
+     * This method returns the number of glyphs in the glyph array.
+     *
+     * @return the number of glyphs in the glyph array
+     *
+     * @stable ICU 3.0
+     */
+    inline le_int32 getGlyphCount() const;
+
+    /**
+     * This method copies the glyph array into a caller supplied array.
+     * The caller must ensure that the array is large enough to hold all
+     * the glyphs.
+     *
+     * @param glyphs - the destiniation glyph array
+     * @param success - set to an error code if the operation fails
+     *
+     * @stable ICU 3.0
+     */
+    void getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const;
+
+    /**
+     * This method copies the glyph array into a caller supplied array,
+     * ORing in extra bits. (This functionality is needed by the JDK,
+     * which uses 32 bits pre glyph idex, with the high 16 bits encoding
+     * the composite font slot number)
+     *
+     * @param glyphs - the destination (32 bit) glyph array
+     * @param extraBits - this value will be ORed with each glyph index
+     * @param success - set to an error code if the operation fails
+     *
+     * @stable ICU 3.0
+     */
+    void getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const;
+
+    /**
+     * This method copies the character index array into a caller supplied array.
+     * The caller must ensure that the array is large enough to hold a
+     * character index for each glyph.
+     *
+     * @param charIndices - the destiniation character index array
+     * @param success - set to an error code if the operation fails
+     *
+     * @stable ICU 3.0
+     */
+    void getCharIndices(le_int32 charIndices[], LEErrorCode &success) const;
+
+    /**
+     * This method copies the character index array into a caller supplied array.
+     * The caller must ensure that the array is large enough to hold a
+     * character index for each glyph.
+     *
+     * @param charIndices - the destiniation character index array
+     * @param indexBase - an offset which will be added to each index
+     * @param success - set to an error code if the operation fails
+     *
+     * @stable ICU 3.0
+     */
+    void getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const;
+
+    /**
+     * This method copies the position array into a caller supplied array.
+     * The caller must ensure that the array is large enough to hold an
+     * X and Y position for each glyph, plus an extra X and Y for the
+     * advance of the last glyph.
+     *
+     * @param positions - the destiniation position array
+     * @param success - set to an error code if the operation fails
+     *
+     * @stable ICU 3.0
+     */
+    void getGlyphPositions(float positions[], LEErrorCode &success) const;
+
+    /**
+     * This method returns the X and Y position of the glyph at
+     * the given index.
+     *
+     * Input parameters:
+     * @param glyphIndex - the index of the glyph
+     *
+     * Output parameters:
+     * @param x - the glyph's X position
+     * @param y - the glyph's Y position
+     * @param success - set to an error code if the operation fails
+     *
+     * @stable ICU 3.0
+     */
+    void getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const;
+
+    /**
+     * This method allocates the glyph array, the char indices array and the insertion list. You
+     * must call this method before using the object. This method also initializes the char indices
+     * array.
+     *
+     * @param initialGlyphCount the initial size of the glyph and char indices arrays.
+     * @param rightToLeft <code>true</code> if the original input text is right to left.
+     * @param success set to an error code if the storage cannot be allocated of if the initial
+     *        glyph count is not positive.
+     *
+     * @stable ICU 3.0
+     */
+    void allocateGlyphArray(le_int32 initialGlyphCount, le_bool rightToLeft, LEErrorCode &success);
+
+    /**
+     * This method allocates the storage for the glyph positions. It allocates one extra X, Y
+     * position pair for the position just after the last glyph.
+     *
+     * @param success set to an error code if the positions array cannot be allocated.
+     *
+     * @return the number of X, Y position pairs allocated.
+     *
+     * @stable ICU 3.0
+     */
+    le_int32 allocatePositions(LEErrorCode &success);
+
+    /**
+     * This method allocates the storage for the auxillary glyph data.
+     *
+     * @param success set to an error code if the aulillary data array cannot be allocated.
+     *
+     * @return the size of the auxillary data array.
+     *
+     * @stable ICU 3.6
+     */
+    le_int32 allocateAuxData(LEErrorCode &success);
+
+    /**
+     * Copy the entire auxillary data array.
+     *
+     * @param auxData the auxillary data array will be copied to this address
+     * @param success set to an error code if the data cannot be copied
+     *
+     * @stable ICU 3.6
+     */
+    void getAuxData(le_uint32 auxData[], LEErrorCode &success) const;
+
+    /**
+     * Get the glyph ID for a particular glyph.
+     *
+     * @param glyphIndex the index into the glyph array
+     * @param success set to an error code if the glyph ID cannot be retrieved.
+     *
+     * @return the glyph ID
+     *
+     * @stable ICU 3.0
+     */
+    LEGlyphID getGlyphID(le_int32 glyphIndex, LEErrorCode &success) const;
+
+    /**
+     * Get the char index for a particular glyph.
+     *
+     * @param glyphIndex the index into the glyph array
+     * @param success set to an error code if the char index cannot be retrieved.
+     *
+     * @return the character index
+     *
+     * @stable ICU 3.0
+     */
+    le_int32  getCharIndex(le_int32 glyphIndex, LEErrorCode &success) const;
+
+
+    /**
+     * Get the auxillary data for a particular glyph.
+     *
+     * @param glyphIndex the index into the glyph array
+     * @param success set to an error code if the auxillary data cannot be retrieved.
+     *
+     * @return the auxillary data
+     *
+     * @stable ICU 3.6
+     */
+    le_uint32 getAuxData(le_int32 glyphIndex, LEErrorCode &success) const;
+
+    /**
+     * This operator allows direct access to the glyph array
+     * using the index operator.
+     *
+     * @param glyphIndex the index into the glyph array
+     *
+     * @return a reference to the given location in the glyph array
+     *
+     * @stable ICU 3.0
+     */
+    inline LEGlyphID &operator[](le_int32 glyphIndex) const;
+
+    /**
+     * Call this method to replace a single glyph in the glyph array
+     * with multiple glyphs. This method uses the <code>LEInsertionList</code>
+     * to do the insertion. It returns the address of storage where the new
+     * glyph IDs can be stored. They will not actually be inserted into the
+     * glyph array until <code>applyInsertions</code> is called.
+     *
+     * @param atIndex the index of the glyph to be replaced
+     * @param insertCount the number of glyphs to replace it with
+     * @param success set to an error code if the auxillary data cannot be retrieved.
+     *
+     * @return the address at which to store the replacement glyphs.
+     *
+     * @see LEInsertionList.h
+     *
+     * @stable ICU 4.2
+     */
+    LEGlyphID *insertGlyphs(le_int32 atIndex, le_int32 insertCount, LEErrorCode& success);
+
+    /**
+     * Call this method to replace a single glyph in the glyph array
+     * with multiple glyphs. This method uses the <code>LEInsertionList</code>
+     * to do the insertion. It returns the address of storage where the new
+     * glyph IDs can be stored. They will not actually be inserted into the
+     * glyph array until <code>applyInsertions</code> is called.
+     *
+     * Note: Don't use this version, use the other version of this function which has an error code.
+     *
+     * @param atIndex the index of the glyph to be replaced
+     * @param insertCount the number of glyphs to replace it with
+     *
+     * @return the address at which to store the replacement glyphs.
+     *
+     * @see LEInsertionList.h
+     *
+     * @stable ICU 3.0
+     */
+    LEGlyphID *insertGlyphs(le_int32 atIndex, le_int32 insertCount);
+
+    /**
+     * This method is used to reposition glyphs during Indic v2 processing.  It moves 
+     * all of the relevant glyph information ( glyph, indices, positions, and auxData ), 
+     * from the source position to the target position, and also allows for a marker bit
+     * to be set in the target glyph's auxData so that it won't be reprocessed later in the
+     * cycle.
+     *
+     * @param fromPosition - position of the glyph to be moved
+     * @param toPosition - target position of the glyph
+     * @param marker marker bit
+     *
+     * @stable ICU 4.2
+     */
+    void moveGlyph(le_int32 fromPosition, le_int32 toPosition, le_uint32 marker);
+
+    /**
+     * This method causes all of the glyph insertions recorded by
+     * <code>insertGlyphs</code> to be applied to the glyph array. The
+     * new slots in the char indices and the auxillary data arrays
+     * will be filled in with the values for the glyph being replaced.
+     *
+     * @return the new size of the glyph array
+     *
+     * @see LEInsertionList.h
+     *
+     * @stable ICU 3.0
+     */
+    le_int32 applyInsertions();
+
+    /**
+     * Set the glyph ID for a particular glyph.
+     *
+     * @param glyphIndex the index of the glyph
+     * @param glyphID the new glyph ID
+     * @param success will be set to an error code if the glyph ID cannot be set.
+     *
+     * @stable ICU 3.0
+     */
+    void setGlyphID(le_int32 glyphIndex, LEGlyphID glyphID, LEErrorCode &success);
+
+    /**
+     * Set the char index for a particular glyph.
+     *
+     * @param glyphIndex the index of the glyph
+     * @param charIndex the new char index
+     * @param success will be set to an error code if the char index cannot be set.
+     *
+     * @stable ICU 3.0
+     */
+    void setCharIndex(le_int32 glyphIndex, le_int32 charIndex, LEErrorCode &success);
+
+    /**
+     * Set the X, Y position for a particular glyph.
+     *
+     * @param glyphIndex the index of the glyph
+     * @param x the new X position
+     * @param y the new Y position
+     * @param success will be set to an error code if the position cannot be set.
+     *
+     * @stable ICU 3.0
+     */
+    void setPosition(le_int32 glyphIndex, float x, float y, LEErrorCode &success);
+
+    /**
+     * Adjust the X, Y position for a particular glyph.
+     *
+     * @param glyphIndex the index of the glyph
+     * @param xAdjust the adjustment to the glyph's X position
+     * @param yAdjust the adjustment to the glyph's Y position
+     * @param success will be set to an error code if the glyph's position cannot be adjusted.
+     *
+     * @stable ICU 3.0
+     */
+    void adjustPosition(le_int32 glyphIndex, float xAdjust, float yAdjust, LEErrorCode &success);
+
+    /**
+     * Set the auxillary data for a particular glyph.
+     *
+     * @param glyphIndex the index of the glyph
+     * @param auxData the new auxillary data
+     * @param success will be set to an error code if the auxillary data cannot be set.
+     *
+     * @stable ICU 3.6
+     */
+    void setAuxData(le_int32 glyphIndex, le_uint32 auxData, LEErrorCode &success);
+
+    /**
+     * Delete the glyph array and replace it with the one
+     * in <code>from</code>. Set the glyph array pointer
+     * in <code>from</code> to <code>NULL</code>.
+     *
+     * @param from the <code>LEGlyphStorage</code> object from which
+     *             to get the new glyph array.
+     *
+     * @stable ICU 3.0
+     */
+    void adoptGlyphArray(LEGlyphStorage &from);
+
+    /**
+     * Delete the char indices array and replace it with the one
+     * in <code>from</code>. Set the char indices array pointer
+     * in <code>from</code> to <code>NULL</code>.
+     *
+     * @param from the <code>LEGlyphStorage</code> object from which
+     *             to get the new char indices array.
+     *
+     * @stable ICU 3.0
+     */
+    void adoptCharIndicesArray(LEGlyphStorage &from);
+
+    /**
+     * Delete the position array and replace it with the one
+     * in <code>from</code>. Set the position array pointer
+     * in <code>from</code> to <code>NULL</code>.
+     *
+     * @param from the <code>LEGlyphStorage</code> object from which
+     *             to get the new position array.
+     *
+     * @stable ICU 3.0
+     */
+    void adoptPositionArray(LEGlyphStorage &from);
+
+    /**
+     * Delete the auxillary data array and replace it with the one
+     * in <code>from</code>. Set the auxillary data array pointer
+     * in <code>from</code> to <code>NULL</code>.
+     *
+     * @param from the <code>LEGlyphStorage</code> object from which
+     *             to get the new auxillary data array.
+     *
+     * @stable ICU 3.0
+     */
+    void adoptAuxDataArray(LEGlyphStorage &from);
+
+    /**
+     * Change the glyph count of this object to be the same
+     * as the one in <code>from</code>.
+     *
+     * @param from the <code>LEGlyphStorage</code> object from which
+     *             to get the new glyph count.
+     *
+     * @stable ICU 3.0
+     */
+    void adoptGlyphCount(LEGlyphStorage &from);
+
+    /**
+     * Change the glyph count of this object to the given value.
+     *
+     * @param newGlyphCount the new glyph count.
+     *
+     * @stable ICU 3.0
+     */
+    void adoptGlyphCount(le_int32 newGlyphCount);
+
+    /**
+     * This method frees the glyph, character index, position  and
+     * auxillary data arrays so that the LayoutEngine can be reused
+     * to layout a different characer array. (This method is also called
+     * by the destructor)
+     *
+     * @stable ICU 3.0
+     */
+    void reset();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 3.0
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 3.0
+     */
+    static UClassID getStaticClassID();
+};
+
+inline le_int32 LEGlyphStorage::getGlyphCount() const
+{
+    return fGlyphCount;
+}
+
+inline LEGlyphID &LEGlyphStorage::operator[](le_int32 glyphIndex) const
+{
+    return fGlyphs[glyphIndex];
+}
+
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/LEInsertionList.cpp b/source/layout/LEInsertionList.cpp
new file mode 100644
index 0000000..c64b8a1
--- /dev/null
+++ b/source/layout/LEInsertionList.cpp
@@ -0,0 +1,96 @@
+/*
+ **********************************************************************
+ *   Copyright (C) 1998-2008, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ **********************************************************************
+ */
+
+#include "LETypes.h"
+#include "LEInsertionList.h"
+
+U_NAMESPACE_BEGIN
+
+#define ANY_NUMBER 1
+
+struct InsertionRecord
+{
+    InsertionRecord *next;
+    le_int32 position;
+    le_int32 count;
+    LEGlyphID glyphs[ANY_NUMBER];
+};
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LEInsertionList)
+
+LEInsertionList::LEInsertionList(le_bool rightToLeft)
+: head(NULL), tail(NULL), growAmount(0), append(rightToLeft)
+{
+    tail = (InsertionRecord *) &head;
+}
+
+LEInsertionList::~LEInsertionList()
+{
+    reset();
+}
+
+void LEInsertionList::reset()
+{
+    while (head != NULL) {
+        InsertionRecord *record = head;
+
+        head = head->next;
+        LE_DELETE_ARRAY(record);
+    }
+
+    tail = (InsertionRecord *) &head;
+    growAmount = 0;
+}
+
+le_int32 LEInsertionList::getGrowAmount()
+{
+    return growAmount;
+}
+
+LEGlyphID *LEInsertionList::insert(le_int32 position, le_int32 count, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    InsertionRecord *insertion = (InsertionRecord *) LE_NEW_ARRAY(char, sizeof(InsertionRecord) + (count - ANY_NUMBER) * sizeof (LEGlyphID));
+    if (insertion == NULL) { 
+        success = LE_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
+
+    insertion->position = position;
+    insertion->count = count;
+
+    growAmount += count - 1;
+
+    if (append) {
+        // insert on end of list...
+        insertion->next = NULL;
+        tail->next = insertion;
+        tail = insertion;
+    } else {
+        // insert on front of list...
+        insertion->next = head;
+        head = insertion;
+    }
+
+    return insertion->glyphs;
+}
+
+le_bool LEInsertionList::applyInsertions(LEInsertionCallback *callback)
+{
+    for (InsertionRecord *rec = head; rec != NULL; rec = rec->next) {
+        if (callback->applyInsertion(rec->position, rec->count, rec->glyphs)) {
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/LEInsertionList.h b/source/layout/LEInsertionList.h
new file mode 100644
index 0000000..68148b5
--- /dev/null
+++ b/source/layout/LEInsertionList.h
@@ -0,0 +1,175 @@
+/*
+ **********************************************************************
+ *   Copyright (C) 1998-2008, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ **********************************************************************
+ */
+
+#ifndef __LEINSERTIONLIST_H
+#define __LEINSERTIONLIST_H
+
+#include "LETypes.h"
+
+U_NAMESPACE_BEGIN
+
+struct InsertionRecord;
+
+/**
+ * This class encapsulates the callback used by <code>LEInsertionList</code>
+ * to apply an insertion from the insertion list.
+ *
+ * @internal
+ */
+class U_LAYOUT_API LEInsertionCallback
+{
+public:
+    /**
+     * This method will be called by <code>LEInsertionList::applyInsertions</code> for each
+     * entry on the insertion list.
+     *
+     * @param atPosition the position of the insertion
+     * @param count the number of glyphs to insert
+     * @param newGlyphs the address of the glyphs to insert
+     *
+     * @return <code>TRUE</code> if <code>LEInsertions::applyInsertions</code> should
+     *         stop after applying this insertion.
+     *
+     * @internal
+     */
+    virtual le_bool applyInsertion(le_int32 atPosition, le_int32 count, LEGlyphID newGlyphs[]) = 0;
+    
+    /**
+     * The destructor
+     */
+     virtual ~LEInsertionCallback();
+};
+
+/**
+ * This class is used to keep track of insertions to an array of
+ * <code>LEGlyphIDs</code>. The insertions are kept on a linked
+ * list of <code>InsertionRecords</code> so that the glyph array
+ * doesn't have to be grown for each insertion. The insertions are
+ * stored on the list from leftmost to rightmost to make it easier
+ * to do the insertions.
+ *
+ * The insertions are applied to the array by calling the
+ * <code>applyInsertions</code> method, which calls a client
+ * supplied <code>LEInsertionCallback</code> object to actually
+ * apply the individual insertions.
+ *
+ * @internal
+ */
+class LEInsertionList : public UObject
+{
+public:
+    /**
+     * Construct an empty insertion list.
+     *
+     * @param rightToLeft <code>TRUE</code> if the glyphs are stored
+     *                    in the array in right to left order.
+     *
+     * @internal
+     */
+    LEInsertionList(le_bool rightToLeft);
+
+    /**
+     * The destructor.
+     */
+    ~LEInsertionList();
+
+    /**
+     * Add an entry to the insertion list.
+     *
+     * @param position the glyph at this position in the array will be
+     *                 replaced by the new glyphs.
+     * @param count the number of new glyphs
+     * @param success set to an error code if the auxillary data cannot be retrieved.
+     *
+     * @return the address of an array in which to store the new glyphs. This will
+     *         <em>not</em> be in the glyph array.
+     *
+     * @internal
+     */
+    LEGlyphID *insert(le_int32 position, le_int32 count, LEErrorCode &success);
+
+    /**
+     * Return the number of new glyphs that have been inserted.
+     *
+     * @return the number of new glyphs which have been inserted
+     *
+     * @internal
+     */
+    le_int32 getGrowAmount();
+
+    /**
+     * Call the <code>LEInsertionCallback</code> once for each
+     * entry on the insertion list.
+     *
+     * @param callback the <code>LEInsertionCallback</code> to call for each insertion.
+     *
+     * @return <code>TRUE</code> if <code>callback</code> returned <code>TRUE</code> to
+     *         terminate the insertion list processing.
+     *
+     * @internal
+     */
+    le_bool applyInsertions(LEInsertionCallback *callback);
+
+    /**
+     * Empty the insertion list and free all associated
+     * storage.
+     *
+     * @internal
+     */
+    void reset();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.8
+     */
+    static UClassID getStaticClassID();
+
+private:
+
+    /**
+     * The head of the insertion list.
+     *
+     * @internal
+     */
+    InsertionRecord *head;
+
+    /**
+     * The tail of the insertion list.
+     *
+     * @internal
+     */
+    InsertionRecord *tail;
+
+    /**
+     * The total number of new glyphs on the insertion list.
+     *
+     * @internal
+     */
+    le_int32 growAmount;
+
+    /**
+     * Set to <code>TRUE</code> if the glyphs are in right
+     * to left order. Since we want the rightmost insertion
+     * to be first on the list, we need to append the
+     * insertions in this case. Otherwise they're prepended.
+     *
+     * @internal
+     */
+    le_bool  append;
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/LELanguages.h b/source/layout/LELanguages.h
new file mode 100644
index 0000000..6ec166b
--- /dev/null
+++ b/source/layout/LELanguages.h
@@ -0,0 +1,111 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2010. All Rights Reserved.
+ *
+ * WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT UNLESS
+ * YOU REALLY KNOW WHAT YOU'RE DOING.
+ *
+ * Generated on: 10/26/2010 02:53:33 PM PDT
+ */
+
+#ifndef __LELANGUAGES_H
+#define __LELANGUAGES_H
+
+#include "LETypes.h"
+
+/**
+ * \file
+ * \brief C++ API: List of language codes for LayoutEngine
+ */
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A provisional list of language codes. For now,
+ * this is just a list of languages which the LayoutEngine
+ * supports.
+ *
+ * @stable ICU 2.6
+ */
+
+enum LanguageCodes {
+    nullLanguageCode =  0,
+    araLanguageCode =  1,
+    asmLanguageCode =  2,
+    benLanguageCode =  3,
+    farLanguageCode =  4,
+    gujLanguageCode =  5,
+    hinLanguageCode =  6,
+    iwrLanguageCode =  7,
+    jiiLanguageCode =  8,
+    janLanguageCode =  9,
+    kanLanguageCode = 10,
+    kokLanguageCode = 11,
+    korLanguageCode = 12,
+    kshLanguageCode = 13,
+    malLanguageCode = 14,
+    marLanguageCode = 15,
+    mlrLanguageCode = 16,
+    mniLanguageCode = 17,
+    oriLanguageCode = 18,
+    sanLanguageCode = 19,
+    sndLanguageCode = 20,
+    snhLanguageCode = 21,
+    syrLanguageCode = 22,
+    tamLanguageCode = 23,
+    telLanguageCode = 24,
+    thaLanguageCode = 25,
+    urdLanguageCode = 26,
+    zhpLanguageCode = 27,
+    zhsLanguageCode = 28,
+    zhtLanguageCode = 29,
+
+    /** New language codes added 03/13/2008 @stable ICU 4.0 */
+    afkLanguageCode = 30,
+    belLanguageCode = 31,
+    bgrLanguageCode = 32,
+    catLanguageCode = 33,
+    cheLanguageCode = 34,
+    copLanguageCode = 35,
+    csyLanguageCode = 36,
+    danLanguageCode = 37,
+    deuLanguageCode = 38,
+    dznLanguageCode = 39,
+    ellLanguageCode = 40,
+    engLanguageCode = 41,
+    espLanguageCode = 42,
+    etiLanguageCode = 43,
+    euqLanguageCode = 44,
+    finLanguageCode = 45,
+    fraLanguageCode = 46,
+    gaeLanguageCode = 47,
+    hauLanguageCode = 48,
+    hrvLanguageCode = 49,
+    hunLanguageCode = 50,
+    hyeLanguageCode = 51,
+    indLanguageCode = 52,
+    itaLanguageCode = 53,
+    khmLanguageCode = 54,
+    mngLanguageCode = 55,
+    mtsLanguageCode = 56,
+    nepLanguageCode = 57,
+    nldLanguageCode = 58,
+    pasLanguageCode = 59,
+    plkLanguageCode = 60,
+    ptgLanguageCode = 61,
+    romLanguageCode = 62,
+    rusLanguageCode = 63,
+    skyLanguageCode = 64,
+    slvLanguageCode = 65,
+    sqiLanguageCode = 66,
+    srbLanguageCode = 67,
+    sveLanguageCode = 68,
+    tibLanguageCode = 69,
+    trkLanguageCode = 70,
+    welLanguageCode = 71,
+
+    languageCodeCount = 72
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/LEScripts.h b/source/layout/LEScripts.h
new file mode 100644
index 0000000..fca9226
--- /dev/null
+++ b/source/layout/LEScripts.h
@@ -0,0 +1,224 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2010. All Rights Reserved.
+ *
+ * WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT UNLESS
+ * YOU REALLY KNOW WHAT YOU'RE DOING.
+ *
+ * Generated on: 10/26/2010 02:53:33 PM PDT
+ */
+
+#ifndef __LESCRIPTS_H
+#define __LESCRIPTS_H
+
+#include "LETypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Constants for Unicode script values
+ */
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Constants for Unicode script values, generated using
+ * ICU4J's <code>UScript</code> class.
+ *
+ * @stable ICU 2.2
+ */
+
+enum ScriptCodes {
+    zyyyScriptCode =  0,
+    zinhScriptCode =  1,
+    qaaiScriptCode = zinhScriptCode,  /* manually added alias, for API stability */
+    arabScriptCode =  2,
+    armnScriptCode =  3,
+    bengScriptCode =  4,
+    bopoScriptCode =  5,
+    cherScriptCode =  6,
+    coptScriptCode =  7,
+    cyrlScriptCode =  8,
+    dsrtScriptCode =  9,
+    devaScriptCode = 10,
+    ethiScriptCode = 11,
+    georScriptCode = 12,
+    gothScriptCode = 13,
+    grekScriptCode = 14,
+    gujrScriptCode = 15,
+    guruScriptCode = 16,
+    haniScriptCode = 17,
+    hangScriptCode = 18,
+    hebrScriptCode = 19,
+    hiraScriptCode = 20,
+    kndaScriptCode = 21,
+    kanaScriptCode = 22,
+    khmrScriptCode = 23,
+    laooScriptCode = 24,
+    latnScriptCode = 25,
+    mlymScriptCode = 26,
+    mongScriptCode = 27,
+    mymrScriptCode = 28,
+    ogamScriptCode = 29,
+    italScriptCode = 30,
+    oryaScriptCode = 31,
+    runrScriptCode = 32,
+    sinhScriptCode = 33,
+    syrcScriptCode = 34,
+    tamlScriptCode = 35,
+    teluScriptCode = 36,
+    thaaScriptCode = 37,
+    thaiScriptCode = 38,
+    tibtScriptCode = 39,
+/**
+ * @stable ICU 2.6
+ */
+
+    cansScriptCode = 40,
+/**
+ * @stable ICU 2.2
+ */
+
+    yiiiScriptCode = 41,
+    tglgScriptCode = 42,
+    hanoScriptCode = 43,
+    buhdScriptCode = 44,
+    tagbScriptCode = 45,
+/**
+ * @stable ICU 2.6
+ */
+
+    braiScriptCode = 46,
+    cprtScriptCode = 47,
+    limbScriptCode = 48,
+    linbScriptCode = 49,
+    osmaScriptCode = 50,
+    shawScriptCode = 51,
+    taleScriptCode = 52,
+    ugarScriptCode = 53,
+/**
+ * @stable ICU 3.0
+ */
+
+    hrktScriptCode = 54,
+/**
+ * @stable ICU 3.4
+ */
+
+    bugiScriptCode = 55,
+    glagScriptCode = 56,
+    kharScriptCode = 57,
+    syloScriptCode = 58,
+    taluScriptCode = 59,
+    tfngScriptCode = 60,
+    xpeoScriptCode = 61,
+/**
+ * @stable ICU 3.6
+ */
+
+    baliScriptCode = 62,
+    batkScriptCode = 63,
+    blisScriptCode = 64,
+    brahScriptCode = 65,
+    chamScriptCode = 66,
+    cirtScriptCode = 67,
+    cyrsScriptCode = 68,
+    egydScriptCode = 69,
+    egyhScriptCode = 70,
+    egypScriptCode = 71,
+    geokScriptCode = 72,
+    hansScriptCode = 73,
+    hantScriptCode = 74,
+    hmngScriptCode = 75,
+    hungScriptCode = 76,
+    indsScriptCode = 77,
+    javaScriptCode = 78,
+    kaliScriptCode = 79,
+    latfScriptCode = 80,
+    latgScriptCode = 81,
+    lepcScriptCode = 82,
+    linaScriptCode = 83,
+    mandScriptCode = 84,
+    mayaScriptCode = 85,
+    meroScriptCode = 86,
+    nkooScriptCode = 87,
+    orkhScriptCode = 88,
+    permScriptCode = 89,
+    phagScriptCode = 90,
+    phnxScriptCode = 91,
+    plrdScriptCode = 92,
+    roroScriptCode = 93,
+    saraScriptCode = 94,
+    syreScriptCode = 95,
+    syrjScriptCode = 96,
+    syrnScriptCode = 97,
+    tengScriptCode = 98,
+    vaiiScriptCode = 99,
+    vispScriptCode = 100,
+    xsuxScriptCode = 101,
+    zxxxScriptCode = 102,
+    zzzzScriptCode = 103,
+/**
+ * @stable ICU 3.8
+ */
+
+    cariScriptCode = 104,
+    jpanScriptCode = 105,
+    lanaScriptCode = 106,
+    lyciScriptCode = 107,
+    lydiScriptCode = 108,
+    olckScriptCode = 109,
+    rjngScriptCode = 110,
+    saurScriptCode = 111,
+    sgnwScriptCode = 112,
+    sundScriptCode = 113,
+    moonScriptCode = 114,
+    mteiScriptCode = 115,
+/**
+ * @stable ICU 4.0
+ */
+
+    armiScriptCode = 116,
+    avstScriptCode = 117,
+    cakmScriptCode = 118,
+    koreScriptCode = 119,
+    kthiScriptCode = 120,
+    maniScriptCode = 121,
+    phliScriptCode = 122,
+    phlpScriptCode = 123,
+    phlvScriptCode = 124,
+    prtiScriptCode = 125,
+    samrScriptCode = 126,
+    tavtScriptCode = 127,
+    zmthScriptCode = 128,
+    zsymScriptCode = 129,
+/**
+ * @stable ICU 4.4
+ */
+
+    bamuScriptCode = 130,
+    lisuScriptCode = 131,
+    nkgbScriptCode = 132,
+    sarbScriptCode = 133,
+/**
+ * @stable ICU 4.6
+ */
+
+    bassScriptCode = 134,
+    duplScriptCode = 135,
+    elbaScriptCode = 136,
+    granScriptCode = 137,
+    kpelScriptCode = 138,
+    lomaScriptCode = 139,
+    mendScriptCode = 140,
+    mercScriptCode = 141,
+    narbScriptCode = 142,
+    nbatScriptCode = 143,
+    palmScriptCode = 144,
+    sindScriptCode = 145,
+    waraScriptCode = 146,
+
+    scriptCodeCount = 147
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/LESwaps.h b/source/layout/LESwaps.h
new file mode 100644
index 0000000..489a9ae
--- /dev/null
+++ b/source/layout/LESwaps.h
@@ -0,0 +1,86 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved
+ *
+ */
+
+#ifndef __LESWAPS_H
+#define __LESWAPS_H
+
+#include "LETypes.h"
+
+/**
+ * \file 
+ * \brief C++ API: Endian independent access to data for LayoutEngine
+ */
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A convenience macro which invokes the swapWord member function
+ * from a concise call.
+ *
+ * @stable ICU 2.8
+ */
+#define SWAPW(value) LESwaps::swapWord((le_uint16)(value))
+
+/**
+ * A convenience macro which invokes the swapLong member function
+ * from a concise call.
+ *
+ * @stable ICU 2.8
+ */
+#define SWAPL(value) LESwaps::swapLong((le_uint32)(value))
+
+/**
+ * This class is used to access data which stored in big endian order
+ * regardless of the conventions of the platform.
+ *
+ * All methods are static and inline in an attempt to induce the compiler
+ * to do most of the calculations at compile time.
+ *
+ * @stable ICU 2.8
+ */
+class U_LAYOUT_API LESwaps /* not : public UObject because all methods are static */ {
+public:
+
+    /**
+     * This method does the byte swap required on little endian platforms
+     * to correctly access a (16-bit) word.
+     *
+     * @param value - the word to be byte swapped
+     *
+     * @return the byte swapped word
+     *
+     * @stable ICU 2.8
+     */
+    static le_uint16 swapWord(le_uint16 value)
+    {
+        return (le_uint16)((value << 8) | (value >> 8));
+    };
+
+    /**
+     * This method does the byte swapping required on little endian platforms
+     * to correctly access a (32-bit) long.
+     *
+     * @param value - the long to be byte swapped
+     *
+     * @return the byte swapped long
+     *
+     * @stable ICU 2.8
+     */
+    static le_uint32 swapLong(le_uint32 value)
+    {
+        return (le_uint32)(
+            (value << 24) |
+            ((value << 8) & 0xff0000) |
+            ((value >> 8) & 0xff00) |
+            (value >> 24));
+    };
+
+private:
+    LESwaps() {} // private - forbid instantiation
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/LETypes.h b/source/layout/LETypes.h
new file mode 100644
index 0000000..400d016
--- /dev/null
+++ b/source/layout/LETypes.h
@@ -0,0 +1,568 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2009 - All Rights Reserved
+ *
+ */
+
+#ifndef __LETYPES_H
+#define __LETYPES_H
+
+#if !defined(LE_USE_CMEMORY) && (defined(U_LAYOUT_IMPLEMENTATION) || defined(U_LAYOUTEX_IMPLEMENTATION) || defined(U_STATIC_IMPLEMENTATION) || defined(U_COMBINED_IMPLEMENTATION))
+#define LE_USE_CMEMORY
+#endif
+
+#include "unicode/utypes.h"
+
+#ifdef XP_CPLUSPLUS
+#include "unicode/uobject.h"
+#endif
+
+#ifdef LE_USE_CMEMORY
+#include "cmemory.h"
+#endif
+
+/*!
+ * \file
+ * \brief C API: Basic definitions for the ICU LayoutEngine
+ */
+
+/**
+ * A type used for signed, 32-bit integers.
+ *
+ * @stable ICU 2.4
+ */
+typedef int32_t le_int32;
+
+/**
+ * A type used for unsigned, 32-bit integers.
+ *
+ * @stable ICU 2.4
+ */
+typedef uint32_t le_uint32;
+
+/**
+ * A type used for signed, 16-bit integers.
+ *
+ * @stable ICU 2.4
+ */
+typedef int16_t le_int16;
+
+/**
+ * A type used for unsigned, 16-bit integers.
+ *
+ * @stable ICU 2.4
+ */
+typedef uint16_t le_uint16;
+
+/**
+ * A type used for signed, 8-bit integers.
+ *
+ * @stable ICU 2.4
+ */
+typedef int8_t le_int8;
+
+/**
+ * A type used for unsigned, 8-bit integers.
+ *
+ * @stable ICU 2.4
+ */
+typedef uint8_t le_uint8;
+
+
+/**
+ * A type used for boolean values.
+ *
+ * @stable ICU 2.4
+ */
+typedef UBool le_bool;
+
+#ifndef NULL
+/**
+ * Used to represent empty pointers.
+ *
+ * @stable ICU 2.4
+ */
+#define NULL 0
+#endif
+
+/**
+ * Used for four character tags.
+ *
+ * @stable ICU 2.4
+ */
+typedef le_uint32 LETag;
+
+/**
+ * Used for 16-bit glyph indices as they're represented
+ * in TrueType font tables.
+ *
+ * @stable ICU 3.2
+ */
+typedef le_uint16 TTGlyphID;
+
+/**
+ * Used for glyph indices. The low-order 16 bits are
+ * the glyph ID within the font. The next 8 bits are
+ * the sub-font ID within a compound font. The high-
+ * order 8 bits are client defined. The LayoutEngine
+ * will never change or look at the client defined bits.
+ *
+ * @stable ICU 3.2
+ */
+typedef le_uint32 LEGlyphID;
+
+/**
+ * Used to mask off the glyph ID part of an LEGlyphID.
+ *
+ * @see LEGlyphID
+ * @stable ICU 3.2
+ */
+#define LE_GLYPH_MASK     0x0000FFFF
+
+/**
+ * Used to shift the glyph ID part of an LEGlyphID
+ * into the low-order bits.
+ *
+ * @see LEGlyphID
+ * @stable ICU 3.2
+ */
+#define LE_GLYPH_SHIFT    0
+
+
+/**
+ * Used to mask off the sub-font ID part of an LEGlyphID.
+ *
+ * @see LEGlyphID
+ * @stable ICU 3.2
+ */
+#define LE_SUB_FONT_MASK  0x00FF0000
+
+/**
+ * Used to shift the sub-font ID part of an LEGlyphID
+ * into the low-order bits.
+ *
+ * @see LEGlyphID
+ * @stable ICU 3.2
+ */
+#define LE_SUB_FONT_SHIFT 16
+
+
+/**
+ * Used to mask off the client-defined part of an LEGlyphID.
+ *
+ * @see LEGlyphID
+ * @stable ICU 3.2
+ */
+#define LE_CLIENT_MASK    0xFF000000
+
+/**
+ * Used to shift the sub-font ID part of an LEGlyphID
+ * into the low-order bits.
+ *
+ * @see LEGlyphID
+ * @stable ICU 3.2
+ */
+#define LE_CLIENT_SHIFT   24
+
+
+/**
+ * A convenience macro to get the Glyph ID part of an LEGlyphID.
+ *
+ * @see LEGlyphID
+ * @stable ICU 3.2
+ */
+#define LE_GET_GLYPH(gid) ((gid & LE_GLYPH_MASK) >> LE_GLYPH_SHIFT)
+
+/**
+ * A convenience macro to get the sub-font ID part of an LEGlyphID.
+ *
+ * @see LEGlyphID
+ * @stable ICU 3.2
+ */
+#define LE_GET_SUB_FONT(gid) ((gid & LE_SUB_FONT_MASK) >> LE_SUB_FONT_SHIFT)
+
+/**
+ * A convenience macro to get the client-defined part of an LEGlyphID.
+ *
+ * @see LEGlyphID
+ * @stable ICU 3.2
+ */
+#define LE_GET_CLIENT(gid) ((gid & LE_CLIENT_MASK) >> LE_CLIENT_SHIFT)
+
+
+/**
+ * A convenience macro to set the Glyph ID part of an LEGlyphID.
+ *
+ * @see LEGlyphID
+ * @stable ICU 3.2
+ */
+#define LE_SET_GLYPH(gid, glyph) ((gid & ~LE_GLYPH_MASK) | ((glyph << LE_GLYPH_SHIFT) & LE_GLYPH_MASK))
+
+/**
+ * A convenience macro to set the sub-font ID part of an LEGlyphID.
+ *
+ * @see LEGlyphID
+ * @stable ICU 3.2
+ */
+#define LE_SET_SUB_FONT(gid, font) ((gid & ~LE_SUB_FONT_MASK) | ((font << LE_SUB_FONT_SHIFT) & LE_SUB_FONT_MASK))
+
+/**
+ * A convenience macro to set the client-defined part of an LEGlyphID.
+ *
+ * @see LEGlyphID
+ * @stable ICU 3.2
+ */
+#define LE_SET_CLIENT(gid, client) ((gid & ~LE_CLIENT_MASK) | ((client << LE_CLIENT_SHIFT) & LE_CLIENT_MASK))
+
+
+/**
+ * Used to represent 16-bit Unicode code points.
+ *
+ * @stable ICU 2.4
+ */
+typedef UChar LEUnicode16;
+
+/**
+ * Used to represent 32-bit Unicode code points.
+ *
+ * @stable ICU 2.4
+ */
+typedef UChar32 LEUnicode32;
+
+/**
+ * Used to represent 16-bit Unicode code points.
+ *
+ * @deprecated since ICU 2.4. Use LEUnicode16 instead
+ */
+typedef UChar LEUnicode;
+
+/**
+ * Used to hold a pair of (x, y) values which represent a point.
+ *
+ * @stable ICU 2.4
+ */
+struct LEPoint
+{
+    /**
+     * The x coordinate of the point.
+     *
+     * @stable ICU 2.4
+     */
+    float fX;
+
+    /**
+     * The y coordinate of the point.
+     *
+     * @stable ICU 2.4
+     */
+    float fY;
+};
+
+#ifndef XP_CPLUSPLUS
+/**
+ * Used to hold a pair of (x, y) values which represent a point.
+ *
+ * @stable ICU 2.4
+ */
+typedef struct LEPoint LEPoint;
+#endif
+
+
+/**
+ * A convenience macro to get the length of an array.
+ *
+ * @internal
+ */
+#define LE_ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+
+#ifdef LE_USE_CMEMORY
+/**
+ * A convenience macro for copying an array.
+ *
+ * @internal
+ */
+#define LE_ARRAY_COPY(dst, src, count) uprv_memcpy((void *) (dst), (void *) (src), (count) * sizeof (src)[0])
+
+/**
+ * Allocate an array of basic types. This is used to isolate the rest of
+ * the LayoutEngine code from cmemory.h.
+ *
+ * @internal
+ */
+#define LE_NEW_ARRAY(type, count) (type *) uprv_malloc((count) * sizeof(type))
+
+/**
+ * Re-allocate an array of basic types. This is used to isolate the rest of
+ * the LayoutEngine code from cmemory.h.
+ *
+ * @internal
+ */
+#define LE_GROW_ARRAY(array, newSize) uprv_realloc((void *) (array), (newSize) * sizeof (array)[0])
+
+ /**
+ * Free an array of basic types. This is used to isolate the rest of
+ * the LayoutEngine code from cmemory.h.
+ *
+ * @internal
+ */
+#define LE_DELETE_ARRAY(array) uprv_free((void *) (array))
+#endif
+
+/**
+ * A macro to construct the four-letter tags used to
+ * label TrueType tables, and for script, language and
+ * feature tags in OpenType tables.
+ *
+ * WARNING: THIS MACRO WILL ONLY WORK CORRECTLY IF
+ * THE ARGUMENT CHARACTERS ARE ASCII.
+ *
+ * @stable ICU 3.2
+ */
+#define LE_MAKE_TAG(a, b, c, d) \
+    (((le_uint32)(a) << 24) |   \
+     ((le_uint32)(b) << 16) |   \
+     ((le_uint32)(c) << 8)  |   \
+      (le_uint32)(d))
+
+/**
+ * This enumeration defines constants for the standard
+ * TrueType, OpenType and AAT table tags.
+ *
+ * @stable ICU 3.2
+ */
+enum LETableTags {
+    LE_ACNT_TABLE_TAG = 0x61636E74UL, /**< 'acnt' */
+    LE_AVAR_TABLE_TAG = 0x61766172UL, /**< 'avar' */
+    LE_BASE_TABLE_TAG = 0x42415345UL, /**< 'BASE' */
+    LE_BDAT_TABLE_TAG = 0x62646174UL, /**< 'bdat' */
+    LE_BHED_TABLE_TAG = 0x62686564UL, /**< 'bhed' */
+    LE_BLOC_TABLE_TAG = 0x626C6F63UL, /**< 'bloc' */
+    LE_BSLN_TABLE_TAG = 0x62736C6EUL, /**< 'bsln' */
+    LE_CFF__TABLE_TAG = 0x43464620UL, /**< 'CFF ' */
+    LE_CMAP_TABLE_TAG = 0x636D6170UL, /**< 'cmap' */
+    LE_CVAR_TABLE_TAG = 0x63766172UL, /**< 'cvar' */
+    LE_CVT__TABLE_TAG = 0x63767420UL, /**< 'cvt ' */
+    LE_DSIG_TABLE_TAG = 0x44534947UL, /**< 'DSIG' */
+    LE_EBDT_TABLE_TAG = 0x45424454UL, /**< 'EBDT' */
+    LE_EBLC_TABLE_TAG = 0x45424C43UL, /**< 'EBLC' */
+    LE_EBSC_TABLE_TAG = 0x45425343UL, /**< 'EBSC' */
+    LE_FDSC_TABLE_TAG = 0x66647363UL, /**< 'fdsc' */
+    LE_FEAT_TABLE_TAG = 0x66656174UL, /**< 'feat' */
+    LE_FMTX_TABLE_TAG = 0x666D7478UL, /**< 'fmtx' */
+    LE_FPGM_TABLE_TAG = 0x6670676DUL, /**< 'fpgm' */
+    LE_FVAR_TABLE_TAG = 0x66766172UL, /**< 'fvar' */
+    LE_GASP_TABLE_TAG = 0x67617370UL, /**< 'gasp' */
+    LE_GDEF_TABLE_TAG = 0x47444546UL, /**< 'GDEF' */
+    LE_GLYF_TABLE_TAG = 0x676C7966UL, /**< 'glyf' */
+    LE_GPOS_TABLE_TAG = 0x47504F53UL, /**< 'GPOS' */
+    LE_GSUB_TABLE_TAG = 0x47535542UL, /**< 'GSUB' */
+    LE_GVAR_TABLE_TAG = 0x67766172UL, /**< 'gvar' */
+    LE_HDMX_TABLE_TAG = 0x68646D78UL, /**< 'hdmx' */
+    LE_HEAD_TABLE_TAG = 0x68656164UL, /**< 'head' */
+    LE_HHEA_TABLE_TAG = 0x68686561UL, /**< 'hhea' */
+    LE_HMTX_TABLE_TAG = 0x686D7478UL, /**< 'hmtx' */
+    LE_HSTY_TABLE_TAG = 0x68737479UL, /**< 'hsty' */
+    LE_JUST_TABLE_TAG = 0x6A757374UL, /**< 'just' */
+    LE_JSTF_TABLE_TAG = 0x4A535446UL, /**< 'JSTF' */
+    LE_KERN_TABLE_TAG = 0x6B65726EUL, /**< 'kern' */
+    LE_LCAR_TABLE_TAG = 0x6C636172UL, /**< 'lcar' */
+    LE_LOCA_TABLE_TAG = 0x6C6F6361UL, /**< 'loca' */
+    LE_LTSH_TABLE_TAG = 0x4C545348UL, /**< 'LTSH' */
+    LE_MAXP_TABLE_TAG = 0x6D617870UL, /**< 'maxp' */
+    LE_MORT_TABLE_TAG = 0x6D6F7274UL, /**< 'mort' */
+    LE_MORX_TABLE_TAG = 0x6D6F7278UL, /**< 'morx' */
+    LE_NAME_TABLE_TAG = 0x6E616D65UL, /**< 'name' */
+    LE_OPBD_TABLE_TAG = 0x6F706264UL, /**< 'opbd' */
+    LE_OS_2_TABLE_TAG = 0x4F532F32UL, /**< 'OS/2' */
+    LE_PCLT_TABLE_TAG = 0x50434C54UL, /**< 'PCLT' */
+    LE_POST_TABLE_TAG = 0x706F7374UL, /**< 'post' */
+    LE_PREP_TABLE_TAG = 0x70726570UL, /**< 'prep' */
+    LE_PROP_TABLE_TAG = 0x70726F70UL, /**< 'prop' */
+    LE_TRAK_TABLE_TAG = 0x7472616BUL, /**< 'trak' */
+    LE_VDMX_TABLE_TAG = 0x56444D58UL, /**< 'VDMX' */
+    LE_VHEA_TABLE_TAG = 0x76686561UL, /**< 'vhea' */
+    LE_VMTX_TABLE_TAG = 0x766D7478UL, /**< 'vmtx' */
+    LE_VORG_TABLE_TAG = 0x564F5247UL, /**< 'VORG' */
+    LE_ZAPF_TABLE_TAG = 0x5A617066UL  /**< 'Zapf' */
+};
+
+/**
+ * This enumeration defines constants for all
+ * the common OpenType feature tags.
+ *
+ * @stable ICU 3.2
+ */
+enum LEFeatureTags {
+    LE_AALT_FEATURE_TAG = 0x61616C74UL, /**< 'aalt' */
+    LE_ABVF_FEATURE_TAG = 0x61627666UL, /**< 'abvf' */
+    LE_ABVM_FEATURE_TAG = 0x6162766DUL, /**< 'abvm' */
+    LE_ABVS_FEATURE_TAG = 0x61627673UL, /**< 'abvs' */
+    LE_AFRC_FEATURE_TAG = 0x61667263UL, /**< 'afrc' */
+    LE_AKHN_FEATURE_TAG = 0x616B686EUL, /**< 'akhn' */
+    LE_BLWF_FEATURE_TAG = 0x626C7766UL, /**< 'blwf' */
+    LE_BLWM_FEATURE_TAG = 0x626C776DUL, /**< 'blwm' */
+    LE_BLWS_FEATURE_TAG = 0x626C7773UL, /**< 'blws' */
+    LE_CALT_FEATURE_TAG = 0x63616C74UL, /**< 'calt' */
+    LE_CASE_FEATURE_TAG = 0x63617365UL, /**< 'case' */
+    LE_CCMP_FEATURE_TAG = 0x63636D70UL, /**< 'ccmp' */
+	LE_CJCT_FEATURE_TAG = 0x636A6374UL, /**< 'cjct' */
+    LE_CLIG_FEATURE_TAG = 0x636C6967UL, /**< 'clig' */
+    LE_CPSP_FEATURE_TAG = 0x63707370UL, /**< 'cpsp' */
+    LE_CSWH_FEATURE_TAG = 0x63737768UL, /**< 'cswh' */
+    LE_CURS_FEATURE_TAG = 0x63757273UL, /**< 'curs' */
+    LE_C2SC_FEATURE_TAG = 0x63327363UL, /**< 'c2sc' */
+    LE_C2PC_FEATURE_TAG = 0x63327063UL, /**< 'c2pc' */
+    LE_DIST_FEATURE_TAG = 0x64697374UL, /**< 'dist' */
+    LE_DLIG_FEATURE_TAG = 0x646C6967UL, /**< 'dlig' */
+    LE_DNOM_FEATURE_TAG = 0x646E6F6DUL, /**< 'dnom' */
+    LE_EXPT_FEATURE_TAG = 0x65787074UL, /**< 'expt' */
+    LE_FALT_FEATURE_TAG = 0x66616C74UL, /**< 'falt' */
+    LE_FIN2_FEATURE_TAG = 0x66696E32UL, /**< 'fin2' */
+    LE_FIN3_FEATURE_TAG = 0x66696E33UL, /**< 'fin3' */
+    LE_FINA_FEATURE_TAG = 0x66696E61UL, /**< 'fina' */
+    LE_FRAC_FEATURE_TAG = 0x66726163UL, /**< 'frac' */
+    LE_FWID_FEATURE_TAG = 0x66776964UL, /**< 'fwid' */
+    LE_HALF_FEATURE_TAG = 0x68616C66UL, /**< 'half' */
+    LE_HALN_FEATURE_TAG = 0x68616C6EUL, /**< 'haln' */
+    LE_HALT_FEATURE_TAG = 0x68616C74UL, /**< 'halt' */
+    LE_HIST_FEATURE_TAG = 0x68697374UL, /**< 'hist' */
+    LE_HKNA_FEATURE_TAG = 0x686B6E61UL, /**< 'hkna' */
+    LE_HLIG_FEATURE_TAG = 0x686C6967UL, /**< 'hlig' */
+    LE_HNGL_FEATURE_TAG = 0x686E676CUL, /**< 'hngl' */
+    LE_HWID_FEATURE_TAG = 0x68776964UL, /**< 'hwid' */
+    LE_INIT_FEATURE_TAG = 0x696E6974UL, /**< 'init' */
+    LE_ISOL_FEATURE_TAG = 0x69736F6CUL, /**< 'isol' */
+    LE_ITAL_FEATURE_TAG = 0x6974616CUL, /**< 'ital' */
+    LE_JALT_FEATURE_TAG = 0x6A616C74UL, /**< 'jalt' */
+    LE_JP78_FEATURE_TAG = 0x6A703738UL, /**< 'jp78' */
+    LE_JP83_FEATURE_TAG = 0x6A703833UL, /**< 'jp83' */
+    LE_JP90_FEATURE_TAG = 0x6A703930UL, /**< 'jp90' */
+    LE_KERN_FEATURE_TAG = 0x6B65726EUL, /**< 'kern' */
+    LE_LFBD_FEATURE_TAG = 0x6C666264UL, /**< 'lfbd' */
+    LE_LIGA_FEATURE_TAG = 0x6C696761UL, /**< 'liga' */
+    LE_LJMO_FEATURE_TAG = 0x6C6A6D6FUL, /**< 'ljmo' */
+    LE_LNUM_FEATURE_TAG = 0x6C6E756DUL, /**< 'lnum' */
+    LE_LOCL_FEATURE_TAG = 0x6C6F636CUL, /**< 'locl' */
+    LE_MARK_FEATURE_TAG = 0x6D61726BUL, /**< 'mark' */
+    LE_MED2_FEATURE_TAG = 0x6D656432UL, /**< 'med2' */
+    LE_MEDI_FEATURE_TAG = 0x6D656469UL, /**< 'medi' */
+    LE_MGRK_FEATURE_TAG = 0x6D67726BUL, /**< 'mgrk' */
+    LE_MKMK_FEATURE_TAG = 0x6D6B6D6BUL, /**< 'mkmk' */
+    LE_MSET_FEATURE_TAG = 0x6D736574UL, /**< 'mset' */
+    LE_NALT_FEATURE_TAG = 0x6E616C74UL, /**< 'nalt' */
+    LE_NLCK_FEATURE_TAG = 0x6E6C636BUL, /**< 'nlck' */
+    LE_NUKT_FEATURE_TAG = 0x6E756B74UL, /**< 'nukt' */
+    LE_NUMR_FEATURE_TAG = 0x6E756D72UL, /**< 'numr' */
+    LE_ONUM_FEATURE_TAG = 0x6F6E756DUL, /**< 'onum' */
+    LE_OPBD_FEATURE_TAG = 0x6F706264UL, /**< 'opbd' */
+    LE_ORDN_FEATURE_TAG = 0x6F72646EUL, /**< 'ordn' */
+    LE_ORNM_FEATURE_TAG = 0x6F726E6DUL, /**< 'ornm' */
+    LE_PALT_FEATURE_TAG = 0x70616C74UL, /**< 'palt' */
+    LE_PCAP_FEATURE_TAG = 0x70636170UL, /**< 'pcap' */
+    LE_PNUM_FEATURE_TAG = 0x706E756DUL, /**< 'pnum' */
+    LE_PREF_FEATURE_TAG = 0x70726566UL, /**< 'pref' */
+    LE_PRES_FEATURE_TAG = 0x70726573UL, /**< 'pres' */
+    LE_PSTF_FEATURE_TAG = 0x70737466UL, /**< 'pstf' */
+    LE_PSTS_FEATURE_TAG = 0x70737473UL, /**< 'psts' */
+    LE_PWID_FEATURE_TAG = 0x70776964UL, /**< 'pwid' */
+    LE_QWID_FEATURE_TAG = 0x71776964UL, /**< 'qwid' */
+    LE_RAND_FEATURE_TAG = 0x72616E64UL, /**< 'rand' */
+    LE_RLIG_FEATURE_TAG = 0x726C6967UL, /**< 'rlig' */
+    LE_RPHF_FEATURE_TAG = 0x72706866UL, /**< 'rphf' */
+	LE_RKRF_FEATURE_TAG = 0x726B7266UL, /**< 'rkrf' */
+    LE_RTBD_FEATURE_TAG = 0x72746264UL, /**< 'rtbd' */
+    LE_RTLA_FEATURE_TAG = 0x72746C61UL, /**< 'rtla' */
+    LE_RUBY_FEATURE_TAG = 0x72756279UL, /**< 'ruby' */
+    LE_SALT_FEATURE_TAG = 0x73616C74UL, /**< 'salt' */
+    LE_SINF_FEATURE_TAG = 0x73696E66UL, /**< 'sinf' */
+    LE_SIZE_FEATURE_TAG = 0x73697A65UL, /**< 'size' */
+    LE_SMCP_FEATURE_TAG = 0x736D6370UL, /**< 'smcp' */
+    LE_SMPL_FEATURE_TAG = 0x736D706CUL, /**< 'smpl' */
+    LE_SS01_FEATURE_TAG = 0x73733031UL, /**< 'ss01' */
+    LE_SS02_FEATURE_TAG = 0x73733032UL, /**< 'ss02' */
+    LE_SS03_FEATURE_TAG = 0x73733033UL, /**< 'ss03' */
+    LE_SS04_FEATURE_TAG = 0x73733034UL, /**< 'ss04' */
+    LE_SS05_FEATURE_TAG = 0x73733035UL, /**< 'ss05' */
+    LE_SS06_FEATURE_TAG = 0x73733036UL, /**< 'ss06' */
+    LE_SS07_FEATURE_TAG = 0x73733037UL, /**< 'ss07' */
+    LE_SS08_FEATURE_TAG = 0x73733038UL, /**< 'ss08' */
+    LE_SS09_FEATURE_TAG = 0x73733039UL, /**< 'ss09' */
+    LE_SS10_FEATURE_TAG = 0x73733130UL, /**< 'ss10' */
+    LE_SS11_FEATURE_TAG = 0x73733131UL, /**< 'ss11' */
+    LE_SS12_FEATURE_TAG = 0x73733132UL, /**< 'ss12' */
+    LE_SS13_FEATURE_TAG = 0x73733133UL, /**< 'ss13' */
+    LE_SS14_FEATURE_TAG = 0x73733134UL, /**< 'ss14' */
+    LE_SS15_FEATURE_TAG = 0x73733135UL, /**< 'ss15' */
+    LE_SS16_FEATURE_TAG = 0x73733136UL, /**< 'ss16' */
+    LE_SS17_FEATURE_TAG = 0x73733137UL, /**< 'ss17' */
+    LE_SS18_FEATURE_TAG = 0x73733138UL, /**< 'ss18' */
+    LE_SS19_FEATURE_TAG = 0x73733139UL, /**< 'ss19' */
+    LE_SS20_FEATURE_TAG = 0x73733230UL, /**< 'ss20' */
+    LE_SUBS_FEATURE_TAG = 0x73756273UL, /**< 'subs' */
+    LE_SUPS_FEATURE_TAG = 0x73757073UL, /**< 'sups' */
+    LE_SWSH_FEATURE_TAG = 0x73777368UL, /**< 'swsh' */
+    LE_TITL_FEATURE_TAG = 0x7469746CUL, /**< 'titl' */
+    LE_TJMO_FEATURE_TAG = 0x746A6D6FUL, /**< 'tjmo' */
+    LE_TNAM_FEATURE_TAG = 0x746E616DUL, /**< 'tnam' */
+    LE_TNUM_FEATURE_TAG = 0x746E756DUL, /**< 'tnum' */
+    LE_TRAD_FEATURE_TAG = 0x74726164UL, /**< 'trad' */
+    LE_TWID_FEATURE_TAG = 0x74776964UL, /**< 'twid' */
+    LE_UNIC_FEATURE_TAG = 0x756E6963UL, /**< 'unic' */
+    LE_VALT_FEATURE_TAG = 0x76616C74UL, /**< 'valt' */
+    LE_VATU_FEATURE_TAG = 0x76617475UL, /**< 'vatu' */
+    LE_VERT_FEATURE_TAG = 0x76657274UL, /**< 'vert' */
+    LE_VHAL_FEATURE_TAG = 0x7668616CUL, /**< 'vhal' */
+    LE_VJMO_FEATURE_TAG = 0x766A6D6FUL, /**< 'vjmo' */
+    LE_VKNA_FEATURE_TAG = 0x766B6E61UL, /**< 'vkna' */
+    LE_VKRN_FEATURE_TAG = 0x766B726EUL, /**< 'vkrn' */
+    LE_VPAL_FEATURE_TAG = 0x7670616CUL, /**< 'vpal' */
+    LE_VRT2_FEATURE_TAG = 0x76727432UL, /**< 'vrt2' */
+    LE_ZERO_FEATURE_TAG = 0x7A65726FUL  /**< 'zero' */
+};
+
+/**
+ * Error codes returned by the LayoutEngine.
+ *
+ * @stable ICU 2.4
+ */
+enum LEErrorCode {
+    /* informational */
+    LE_NO_SUBFONT_WARNING          = U_USING_DEFAULT_WARNING, /**< The font does not contain subfonts. */
+
+    /* success */
+    LE_NO_ERROR                     = U_ZERO_ERROR, /**< No error, no warning. */
+
+    /* failures */
+    LE_ILLEGAL_ARGUMENT_ERROR       = U_ILLEGAL_ARGUMENT_ERROR,  /**< An illegal argument was detected. */
+    LE_MEMORY_ALLOCATION_ERROR      = U_MEMORY_ALLOCATION_ERROR, /**< Memory allocation error. */
+    LE_INDEX_OUT_OF_BOUNDS_ERROR    = U_INDEX_OUTOFBOUNDS_ERROR, /**< Trying to access an index that is out of bounds. */
+    LE_NO_LAYOUT_ERROR              = U_UNSUPPORTED_ERROR,       /**< You must call layoutChars() first. */
+    LE_INTERNAL_ERROR               = U_INTERNAL_PROGRAM_ERROR,  /**< An internal error was encountered. */
+    LE_FONT_FILE_NOT_FOUND_ERROR    = U_FILE_ACCESS_ERROR,       /**< The requested font file cannot be opened. */
+    LE_MISSING_FONT_TABLE_ERROR     = U_MISSING_RESOURCE_ERROR   /**< The requested font table does not exist. */
+};
+
+#ifndef XP_CPLUSPLUS
+/**
+ * Error codes returned by the LayoutEngine.
+ *
+ * @stable ICU 2.4
+ */
+typedef enum LEErrorCode LEErrorCode;
+#endif
+
+/**
+ * A convenience macro to test for the success of a LayoutEngine call.
+ *
+ * @stable ICU 2.4
+ */
+#define LE_SUCCESS(code) (U_SUCCESS((UErrorCode)code))
+
+/**
+ * A convenience macro to test for the failure of a LayoutEngine call.
+ *
+ * @stable ICU 2.4
+ */
+#define LE_FAILURE(code) (U_FAILURE((UErrorCode)code))
+
+#endif
diff --git a/source/layout/LayoutEngine.cpp b/source/layout/LayoutEngine.cpp
new file mode 100644
index 0000000..c13a08e
--- /dev/null
+++ b/source/layout/LayoutEngine.cpp
@@ -0,0 +1,655 @@
+
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2009 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEScripts.h"
+#include "LELanguages.h"
+
+#include "LayoutEngine.h"
+#include "ArabicLayoutEngine.h"
+#include "CanonShaping.h"
+#include "HanLayoutEngine.h"
+#include "HangulLayoutEngine.h"
+#include "IndicLayoutEngine.h"
+#include "KhmerLayoutEngine.h"
+#include "ThaiLayoutEngine.h"
+#include "TibetanLayoutEngine.h"
+#include "GXLayoutEngine.h"
+#include "ScriptAndLanguageTags.h"
+#include "CharSubstitutionFilter.h"
+
+#include "LEGlyphStorage.h"
+
+#include "OpenTypeUtilities.h"
+#include "GlyphSubstitutionTables.h"
+#include "GlyphDefinitionTables.h"
+#include "MorphTables.h"
+
+#include "DefaultCharMapper.h"
+
+#include "KernTable.h"
+
+U_NAMESPACE_BEGIN
+
+/* Leave this copyright notice here! It needs to go somewhere in this library. */
+static const char copyright[] = U_COPYRIGHT_STRING;
+
+const LEUnicode32 DefaultCharMapper::controlChars[] = {
+    0x0009, 0x000A, 0x000D,
+    /*0x200C, 0x200D,*/ 0x200E, 0x200F,
+    0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E,
+    0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F
+};
+
+const le_int32 DefaultCharMapper::controlCharsCount = LE_ARRAY_SIZE(controlChars);
+
+LEUnicode32 DefaultCharMapper::mapChar(LEUnicode32 ch) const
+{
+    if (fFilterControls) {
+        le_int32 index = OpenTypeUtilities::search((le_uint32)ch, (le_uint32 *)controlChars, controlCharsCount);
+
+        if (controlChars[index] == ch) {
+            return 0xFFFF;
+        }
+    }
+
+    if (fMirror) {
+        le_int32 index = OpenTypeUtilities::search((le_uint32) ch, (le_uint32 *)DefaultCharMapper::mirroredChars, DefaultCharMapper::mirroredCharsCount);
+
+        if (mirroredChars[index] == ch) {
+            return DefaultCharMapper::srahCderorrim[index];
+        }
+    }
+
+    return ch;
+}
+
+// This is here to get it out of LEGlyphFilter.h.
+// No particular reason to put it here, other than
+// this is a good central location...
+LEGlyphFilter::~LEGlyphFilter()
+{
+    // nothing to do
+}
+
+CharSubstitutionFilter::CharSubstitutionFilter(const LEFontInstance *fontInstance)
+  : fFontInstance(fontInstance)
+{
+    // nothing to do
+}
+
+CharSubstitutionFilter::~CharSubstitutionFilter()
+{
+    // nothing to do
+}
+
+class CanonMarkFilter : public UMemory, public LEGlyphFilter
+{
+private:
+    const GlyphClassDefinitionTable *classDefTable;
+
+    CanonMarkFilter(const CanonMarkFilter &other); // forbid copying of this class
+    CanonMarkFilter &operator=(const CanonMarkFilter &other); // forbid copying of this class
+
+public:
+    CanonMarkFilter(const GlyphDefinitionTableHeader *gdefTable);
+    virtual ~CanonMarkFilter();
+
+    virtual le_bool accept(LEGlyphID glyph) const;
+};
+
+CanonMarkFilter::CanonMarkFilter(const GlyphDefinitionTableHeader *gdefTable)
+{
+    classDefTable = gdefTable->getMarkAttachClassDefinitionTable();
+}
+
+CanonMarkFilter::~CanonMarkFilter()
+{
+    // nothing to do?
+}
+
+le_bool CanonMarkFilter::accept(LEGlyphID glyph) const
+{
+    le_int32 glyphClass = classDefTable->getGlyphClass(glyph);
+
+    return glyphClass != 0;
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine)
+
+#define ccmpFeatureTag  LE_CCMP_FEATURE_TAG
+
+#define ccmpFeatureMask 0x80000000UL
+
+#define canonFeatures (ccmpFeatureMask)
+
+static const FeatureMap canonFeatureMap[] =
+{
+    {ccmpFeatureTag, ccmpFeatureMask}
+};
+
+static const le_int32 canonFeatureMapCount = LE_ARRAY_SIZE(canonFeatureMap);
+
+LayoutEngine::LayoutEngine(const LEFontInstance *fontInstance, 
+                           le_int32 scriptCode, 
+                           le_int32 languageCode, 
+                           le_int32 typoFlags,
+                           LEErrorCode &success)
+  : fGlyphStorage(NULL), fFontInstance(fontInstance), fScriptCode(scriptCode), fLanguageCode(languageCode),
+    fTypoFlags(typoFlags), fFilterZeroWidth(TRUE)
+{
+    if (LE_FAILURE(success)) {
+        return;
+    } 
+
+    fGlyphStorage = new LEGlyphStorage();
+    if (fGlyphStorage == NULL) {
+        success = LE_MEMORY_ALLOCATION_ERROR;
+    }
+}
+
+le_int32 LayoutEngine::getGlyphCount() const
+{
+    return fGlyphStorage->getGlyphCount();
+}
+
+void LayoutEngine::getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const
+{
+    fGlyphStorage->getCharIndices(charIndices, indexBase, success);
+}
+
+void LayoutEngine::getCharIndices(le_int32 charIndices[], LEErrorCode &success) const
+{
+    fGlyphStorage->getCharIndices(charIndices, success);
+}
+
+// Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits
+void LayoutEngine::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const
+{
+    fGlyphStorage->getGlyphs(glyphs, extraBits, success);
+}
+
+void LayoutEngine::getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const
+{
+    fGlyphStorage->getGlyphs(glyphs, success);
+}
+
+
+void LayoutEngine::getGlyphPositions(float positions[], LEErrorCode &success) const
+{
+    fGlyphStorage->getGlyphPositions(positions, success);
+}
+
+void LayoutEngine::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const
+{
+    fGlyphStorage->getGlyphPosition(glyphIndex, x, y, success);
+}
+
+le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+                LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    const GlyphSubstitutionTableHeader *canonGSUBTable = (GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable;
+    LETag scriptTag  = OpenTypeLayoutEngine::getScriptTag(fScriptCode);
+    LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode);
+    le_int32 i, dir = 1, out = 0, outCharCount = count;
+
+    if (canonGSUBTable->coversScript(scriptTag)) {
+        CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance);
+        if (substitutionFilter == NULL) { 
+            success = LE_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+
+		const LEUnicode *inChars = &chars[offset];
+		LEUnicode *reordered = NULL;
+        LEGlyphStorage fakeGlyphStorage;
+
+        fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success);
+
+        if (LE_FAILURE(success)) {
+            delete substitutionFilter;
+            return 0;
+        }
+
+		// This is the cheapest way to get mark reordering only for Hebrew.
+		// We could just do the mark reordering for all scripts, but most
+		// of them probably don't need it...
+		if (fScriptCode == hebrScriptCode) {
+			reordered = LE_NEW_ARRAY(LEUnicode, count);
+
+			if (reordered == NULL) {
+                delete substitutionFilter;
+				success = LE_MEMORY_ALLOCATION_ERROR;
+				return 0;
+			}
+
+			CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage);
+			inChars = reordered;
+        }
+
+        fakeGlyphStorage.allocateAuxData(success);
+
+        if (LE_FAILURE(success)) {
+            delete substitutionFilter;
+            return 0;
+        }
+
+        if (rightToLeft) {
+            out = count - 1;
+            dir = -1;
+        }
+
+        for (i = 0; i < count; i += 1, out += dir) {
+            fakeGlyphStorage[out] = (LEGlyphID) inChars[i];
+            fakeGlyphStorage.setAuxData(out, canonFeatures, success);
+        }
+
+		if (reordered != NULL) {
+			LE_DELETE_ARRAY(reordered);
+		}
+
+        outCharCount = canonGSUBTable->process(fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, NULL, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE, success);
+
+        if (LE_FAILURE(success)) {
+            delete substitutionFilter;
+            return 0;
+        }
+
+        out = (rightToLeft? outCharCount - 1 : 0);
+
+        /*
+         * The char indices array in fakeGlyphStorage has the correct mapping
+         * back to the original input characters. Save it in glyphStorage. The
+         * subsequent call to glyphStoratge.allocateGlyphArray will keep this
+         * array rather than allocating and initializing a new one.
+         */
+        glyphStorage.adoptCharIndicesArray(fakeGlyphStorage);
+
+        outChars = LE_NEW_ARRAY(LEUnicode, outCharCount);
+
+        if (outChars == NULL) {
+            delete substitutionFilter;
+            success = LE_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+
+        for (i = 0; i < outCharCount; i += 1, out += dir) {
+            outChars[out] = (LEUnicode) LE_GET_GLYPH(fakeGlyphStorage[i]);
+        }
+
+        delete substitutionFilter;
+    }
+
+    return outCharCount;
+}
+
+le_int32 LayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+                                            LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    LEUnicode *outChars = NULL;
+    le_int32 outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success);
+
+    if (outChars != NULL) {
+        mapCharsToGlyphs(outChars, 0, outCharCount, rightToLeft, rightToLeft, glyphStorage, success);
+        LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work...
+    } else {
+        mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success);
+    }
+
+    return glyphStorage.getGlyphCount();
+}
+
+// Input: glyphs
+// Output: positions
+void LayoutEngine::positionGlyphs(LEGlyphStorage &glyphStorage, float x, float y, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return;
+    }
+
+    glyphStorage.allocatePositions(success);
+
+    if (LE_FAILURE(success)) {
+        return;
+    }
+
+    le_int32 i, glyphCount = glyphStorage.getGlyphCount();
+
+    for (i = 0; i < glyphCount; i += 1) {
+        LEPoint advance;
+
+        glyphStorage.setPosition(i, x, y, success);
+
+        fFontInstance->getGlyphAdvance(glyphStorage[i], advance);
+        x += advance.fX;
+        y += advance.fY;
+    }
+
+    glyphStorage.setPosition(glyphCount, x, y, success);
+}
+
+void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool  reverse,
+                                        LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    GlyphDefinitionTableHeader *gdefTable = (GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable;
+    CanonMarkFilter filter(gdefTable);
+
+    adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
+
+    if (fTypoFlags & 0x1) { /* kerning enabled */
+      static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG;
+
+      KernTable kt(fFontInstance, getFontTable(kernTableTag));
+      kt.process(glyphStorage);
+    }
+
+    // default is no adjustments
+    return;
+}
+
+void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success)
+{
+    float xAdjust = 0;
+    le_int32 p, glyphCount = glyphStorage.getGlyphCount();
+
+    if (LE_FAILURE(success)) {
+        return;
+    }
+
+    if (markFilter == NULL) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    float ignore, prev;
+
+    glyphStorage.getGlyphPosition(0, prev, ignore, success);
+
+    for (p = 0; p < glyphCount; p += 1) {
+        float next, xAdvance;
+        
+        glyphStorage.getGlyphPosition(p + 1, next, ignore, success);
+
+        xAdvance = next - prev;
+        glyphStorage.adjustPosition(p, xAdjust, 0, success);
+
+        if (markFilter->accept(glyphStorage[p])) {
+            xAdjust -= xAdvance;
+        }
+
+        prev = next;
+    }
+
+    glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success);
+}
+
+void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, le_bool reverse, LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success)
+{
+    float xAdjust = 0;
+    le_int32 c = 0, direction = 1, p;
+    le_int32 glyphCount = glyphStorage.getGlyphCount();
+
+    if (LE_FAILURE(success)) {
+        return;
+    }
+
+    if (markFilter == NULL) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    if (reverse) {
+        c = glyphCount - 1;
+        direction = -1;
+    }
+
+    float ignore, prev;
+
+    glyphStorage.getGlyphPosition(0, prev, ignore, success);
+
+    for (p = 0; p < charCount; p += 1, c += direction) {
+        float next, xAdvance;
+        
+        glyphStorage.getGlyphPosition(p + 1, next, ignore, success);
+
+        xAdvance = next - prev;
+        glyphStorage.adjustPosition(p, xAdjust, 0, success);
+
+        if (markFilter->accept(chars[c])) {
+            xAdjust -= xAdvance;
+        }
+
+        prev = next;
+    }
+
+    glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success);
+}
+
+const void *LayoutEngine::getFontTable(LETag tableTag) const
+{
+    return fFontInstance->getFontTable(tableTag);
+}
+
+void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror,
+                                    LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return;
+    }
+
+    glyphStorage.allocateGlyphArray(count, reverse, success);
+
+    DefaultCharMapper charMapper(TRUE, mirror);
+
+    fFontInstance->mapCharsToGlyphs(chars, offset, count, reverse, &charMapper, fFilterZeroWidth, glyphStorage);
+}
+
+// Input: characters, font?
+// Output: glyphs, positions, char indices
+// Returns: number of glyphs
+le_int32 LayoutEngine::layoutChars(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+                              float x, float y, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    le_int32 glyphCount;
+
+    if (fGlyphStorage->getGlyphCount() > 0) {
+        fGlyphStorage->reset();
+    }
+    
+    glyphCount = computeGlyphs(chars, offset, count, max, rightToLeft, *fGlyphStorage, success);
+    positionGlyphs(*fGlyphStorage, x, y, success);
+    adjustGlyphPositions(chars, offset, count, rightToLeft, *fGlyphStorage, success);
+
+    return glyphCount;
+}
+
+void LayoutEngine::reset()
+{
+    fGlyphStorage->reset();
+}
+    
+LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success)
+{
+  // 3 -> kerning and ligatures
+  return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, 3, success);
+}
+    
+LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success)
+{
+    static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG;
+    static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG;
+
+    if (LE_FAILURE(success)) {
+        return NULL;
+    }
+
+    const GlyphSubstitutionTableHeader *gsubTable = (const GlyphSubstitutionTableHeader *) fontInstance->getFontTable(gsubTableTag);
+    LayoutEngine *result = NULL;
+    LETag scriptTag   = 0x00000000;
+    LETag languageTag = 0x00000000;
+	LETag v2ScriptTag = OpenTypeLayoutEngine::getV2ScriptTag(scriptCode);
+
+    // Right now, only invoke V2 processing for Devanagari.  TODO: Allow more V2 scripts as they are
+    // properly tested.
+
+	if ( v2ScriptTag == dev2ScriptTag && gsubTable != NULL && gsubTable->coversScript( v2ScriptTag )) {
+		result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, TRUE, gsubTable, success);
+	}
+    else if (gsubTable != NULL && gsubTable->coversScript(scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode))) {
+        switch (scriptCode) {
+        case bengScriptCode:
+        case devaScriptCode:
+        case gujrScriptCode:
+        case kndaScriptCode:
+        case mlymScriptCode:
+        case oryaScriptCode:
+        case guruScriptCode:
+        case tamlScriptCode:
+        case teluScriptCode:
+        case sinhScriptCode:
+            result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, FALSE, gsubTable, success);
+            break;
+
+        case arabScriptCode:
+            result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
+            break;
+
+        case hangScriptCode:
+            result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
+            break;
+
+        case haniScriptCode:
+            languageTag = OpenTypeLayoutEngine::getLangSysTag(languageCode);
+
+            switch (languageCode) {
+            case korLanguageCode:
+            case janLanguageCode:
+            case zhtLanguageCode:
+            case zhsLanguageCode:
+                if (gsubTable->coversScriptAndLanguage(scriptTag, languageTag, TRUE)) {
+                    result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
+                    break;
+                }
+
+                // note: falling through to default case.
+            default:
+                result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
+                break;
+            }
+
+            break;
+
+        case tibtScriptCode:
+            result = new TibetanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
+            break;
+
+        case khmrScriptCode:
+            result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
+            break;
+
+        default:
+            result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
+            break;
+        }
+    } else {
+        const MorphTableHeader *morphTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag);
+
+        if (morphTable != NULL) {
+            result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, morphTable, success);
+        } else {
+            switch (scriptCode) {
+            case bengScriptCode:
+            case devaScriptCode:
+            case gujrScriptCode:
+            case kndaScriptCode:
+            case mlymScriptCode:
+            case oryaScriptCode:
+            case guruScriptCode:
+            case tamlScriptCode:
+            case teluScriptCode:
+            case sinhScriptCode:
+            {
+                result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
+                break;
+            }
+
+            case arabScriptCode:
+            //case hebrScriptCode:
+                result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
+                break;
+
+            //case hebrScriptCode:
+            //    return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
+
+            case thaiScriptCode:
+                result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
+                break;
+
+            case hangScriptCode:
+                result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
+                break;
+
+            default:
+                result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
+                break;
+            }
+        }
+    }
+
+    if (result && LE_FAILURE(success)) {
+		delete result;
+		result = NULL;
+	}
+
+    if (result == NULL) {
+        success = LE_MEMORY_ALLOCATION_ERROR;
+    }
+
+    return result;
+}
+
+LayoutEngine::~LayoutEngine() {
+    delete fGlyphStorage;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/LayoutEngine.h b/source/layout/LayoutEngine.h
new file mode 100644
index 0000000..b109e64
--- /dev/null
+++ b/source/layout/LayoutEngine.h
@@ -0,0 +1,496 @@
+
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#ifndef __LAYOUTENGINE_H
+#define __LAYOUTENGINE_H
+
+#include "LETypes.h"
+
+/**
+ * \file 
+ * \brief C++ API: Virtual base class for complex text layout.
+ */
+
+U_NAMESPACE_BEGIN
+
+class LEFontInstance;
+class LEGlyphFilter;
+class LEGlyphStorage;
+
+/**
+ * This is a virtual base class used to do complex text layout. The text must all
+ * be in a single font, script, and language. An instance of a LayoutEngine can be
+ * created by calling the layoutEngineFactory method. Fonts are identified by
+ * instances of the LEFontInstance class. Script and language codes are identified
+ * by integer codes, which are defined in ScriptAndLanuageTags.h.
+ *
+ * Note that this class is not public API. It is declared public so that it can be
+ * exported from the library that it is a part of.
+ *
+ * The input to the layout process is an array of characters in logical order,
+ * and a starting X, Y position for the text. The output is an array of glyph indices,
+ * an array of character indices for the glyphs, and an array of glyph positions.
+ * These arrays are protected members of LayoutEngine which can be retreived by a
+ * public method. The reset method can be called to free these arrays so that the
+ * LayoutEngine can be reused.
+ *
+ * The layout process is done in three steps. There is a protected virtual method
+ * for each step. These methods have a default implementation which only does
+ * character to glyph mapping and default positioning using the glyph's advance
+ * widths. Subclasses can override these methods for more advanced layout.
+ * There is a public method which invokes the steps in the correct order.
+ * 
+ * The steps are:
+ *
+ * 1) Glyph processing - character to glyph mapping and any other glyph processing
+ *    such as ligature substitution and contextual forms.
+ *
+ * 2) Glyph positioning - position the glyphs based on their advance widths.
+ *
+ * 3) Glyph position adjustments - adjustment of glyph positions for kerning,
+ *    accent placement, etc.
+ *
+ * NOTE: in all methods below, output parameters are references to pointers so
+ * the method can allocate and free the storage as needed. All storage allocated
+ * in this way is owned by the object which created it, and will be freed when it
+ * is no longer needed, or when the object's destructor is invoked.
+ *
+ * @see LEFontInstance
+ * @see ScriptAndLanguageTags.h
+ *
+ * @stable ICU 2.8
+ */
+class U_LAYOUT_API LayoutEngine : public UObject {
+protected:
+    /**
+     * The object which holds the glyph storage
+     *
+     * @internal
+     */
+    LEGlyphStorage *fGlyphStorage;
+
+    /**
+     * The font instance for the text font.
+     *
+     * @see LEFontInstance
+     *
+     * @internal
+     */
+    const LEFontInstance *fFontInstance;
+
+    /**
+     * The script code for the text
+     *
+     * @see ScriptAndLanguageTags.h for script codes.
+     *
+     * @internal
+     */
+    le_int32 fScriptCode;
+
+    /**
+     * The langauge code for the text
+     *
+     * @see ScriptAndLanguageTags.h for language codes.
+     *
+     * @internal
+     */
+    le_int32 fLanguageCode;
+
+    /**
+     * The typographic control flags
+     *
+     * @internal
+     */
+    le_int32 fTypoFlags;
+
+    /**
+     * <code>TRUE</code> if <code>mapCharsToGlyphs</code> should replace ZWJ / ZWNJ with a glyph
+     * with no contours.
+     *
+     * @internal
+     */
+    le_bool fFilterZeroWidth;
+
+    /**
+     * This constructs an instance for a given font, script and language. Subclass constructors
+     * must call this constructor.
+     *
+     * @param fontInstance - the font for the text
+     * @param scriptCode - the script for the text
+     * @param languageCode - the language for the text
+     * @param typoFlags - the typographic control flags for the text.  Set bit 1 if kerning
+     * is desired, set bit 2 if ligature formation is desired.  Others are reserved.
+     * @param success - set to an error code if the operation fails
+     *
+     * @see LEFontInstance
+     * @see ScriptAndLanguageTags.h
+     *
+     * @internal
+     */
+    LayoutEngine(const LEFontInstance *fontInstance, 
+                 le_int32 scriptCode, 
+                 le_int32 languageCode, 
+                 le_int32 typoFlags,
+                 LEErrorCode &success);
+
+    /**
+     * This overrides the default no argument constructor to make it
+     * difficult for clients to call it. Clients are expected to call
+     * layoutEngineFactory.
+     *
+     * @internal
+     */
+    LayoutEngine();
+
+    /**
+     * This method does any required pre-processing to the input characters. It
+     * may generate output characters that differ from the input charcters due to
+     * insertions, deletions, or reorderings. In such cases, it will also generate an
+     * output character index array reflecting these changes.
+     *
+     * Subclasses must override this method.
+     *
+     * Input parameters:
+     * @param chars - the input character context
+     * @param offset - the index of the first character to process
+     * @param count - the number of characters to process
+     * @param max - the number of characters in the input context
+     * @param rightToLeft - TRUE if the characters are in a right to left directional run
+     * @param outChars - the output character array, if different from the input
+     * @param glyphStorage - the object that holds the per-glyph storage. The character index array may be set.
+     * @param success - set to an error code if the operation fails
+     *
+     * @return the output character count (input character count if no change)
+     *
+     * @internal
+     */
+    virtual le_int32 characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+            LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+    /**
+     * This method does the glyph processing. It converts an array of characters
+     * into an array of glyph indices and character indices. The characters to be
+     * processed are passed in a surrounding context. The context is specified as
+     * a starting address and a maximum character count. An offset and a count are
+     * used to specify the characters to be processed.
+     *
+     * The default implementation of this method only does character to glyph mapping.
+     * Subclasses needing more elaborate glyph processing must override this method.
+     *
+     * Input parameters:
+     * @param chars - the character context
+     * @param offset - the offset of the first character to process
+     * @param count - the number of characters to process
+     * @param max - the number of characters in the context.
+     * @param rightToLeft - TRUE if the text is in a right to left directional run
+     * @param glyphStorage - the object which holds the per-glyph storage. The glyph and char indices arrays
+     *                       will be set.
+     *
+     * Output parameters:
+     * @param success - set to an error code if the operation fails
+     *
+     * @return the number of glyphs in the glyph index array
+     *
+     * @internal
+     */
+    virtual le_int32 computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+    /**
+     * This method does basic glyph positioning. The default implementation positions
+     * the glyphs based on their advance widths. This is sufficient for most uses. It
+     * is not expected that many subclasses will override this method.
+     *
+     * Input parameters:
+     * @param glyphStorage - the object which holds the per-glyph storage. The glyph position array will be set.
+     * @param x - the starting X position
+     * @param y - the starting Y position
+     * @param success - set to an error code if the operation fails
+     *
+     * @internal
+     */
+    virtual void positionGlyphs(LEGlyphStorage &glyphStorage, float x, float y, LEErrorCode &success);
+
+    /**
+     * This method does positioning adjustments like accent positioning and
+     * kerning. The default implementation does nothing. Subclasses needing
+     * position adjustments must override this method.
+     *
+     * Note that this method has both characters and glyphs as input so that
+     * it can use the character codes to determine glyph types if that information
+     * isn't directly available. (e.g. Some Arabic OpenType fonts don't have a GDEF
+     * table)
+     *
+     * @param chars - the input character context
+     * @param offset - the offset of the first character to process
+     * @param count - the number of characters to process
+     * @param reverse - <code>TRUE</code> if the glyphs in the glyph array have been reordered
+     * @param glyphStorage - the object which holds the per-glyph storage. The glyph positions will be
+     *                       adjusted as needed.
+     * @param success - output parameter set to an error code if the operation fails
+     *
+     * @internal
+     */
+    virtual void adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+    /**
+     * This method gets a table from the font associated with
+     * the text. The default implementation gets the table from
+     * the font instance. Subclasses which need to get the tables
+     * some other way must override this method.
+     * 
+     * @param tableTag - the four byte table tag.
+     *
+     * @return the address of the table.
+     *
+     * @internal
+     */
+    virtual const void *getFontTable(LETag tableTag) const;
+
+    /**
+     * This method does character to glyph mapping. The default implementation
+     * uses the font instance to do the mapping. It will allocate the glyph and
+     * character index arrays if they're not already allocated. If it allocates the
+     * character index array, it will fill it it.
+     *
+     * This method supports right to left
+     * text with the ability to store the glyphs in reverse order, and by supporting
+     * character mirroring, which will replace a character which has a left and right
+     * form, such as parens, with the opposite form before mapping it to a glyph index.
+     *
+     * Input parameters:
+     * @param chars - the input character context
+     * @param offset - the offset of the first character to be mapped
+     * @param count - the number of characters to be mapped
+     * @param reverse - if <code>TRUE</code>, the output will be in reverse order
+     * @param mirror - if <code>TRUE</code>, do character mirroring
+     * @param glyphStorage - the object which holds the per-glyph storage. The glyph and char
+     *                       indices arrays will be filled in.
+     * @param success - set to an error code if the operation fails
+     *
+     * @see LEFontInstance
+     *
+     * @internal
+     */
+    virtual void mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+    /**
+     * This is a convenience method that forces the advance width of mark
+     * glyphs to be zero, which is required for proper selection and highlighting.
+     * 
+     * @param glyphStorage - the object containing the per-glyph storage. The positions array will be modified.
+     * @param markFilter - used to identify mark glyphs
+     * @param success - output parameter set to an error code if the operation fails
+     *
+     * @see LEGlyphFilter
+     *
+     * @internal
+     */
+    static void adjustMarkGlyphs(LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success);
+
+
+    /**
+     * This is a convenience method that forces the advance width of mark
+     * glyphs to be zero, which is required for proper selection and highlighting.
+     * This method uses the input characters to identify marks. This is required in
+     * cases where the font does not contain enough information to identify them based
+     * on the glyph IDs.
+     * 
+     * @param chars - the array of input characters
+     * @param charCount - the number of input characers
+     * @param glyphStorage - the object containing the per-glyph storage. The positions array will be modified.
+     * @param reverse - <code>TRUE</code> if the glyph array has been reordered
+     * @param markFilter - used to identify mark glyphs
+     * @param success - output parameter set to an error code if the operation fails
+     *
+     * @see LEGlyphFilter
+     *
+     * @internal
+     */
+    static void adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, le_bool reverse, LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success);
+
+
+public:
+    /**
+     * The destructor. It will free any storage allocated for the
+     * glyph, character index and position arrays by calling the reset
+     * method. It is declared virtual so that it will be invoked by the
+     * subclass destructors.
+     *
+     * @stable ICU 2.8
+     */
+    virtual ~LayoutEngine();
+
+    /**
+     * This method will invoke the layout steps in their correct order by calling
+     * the computeGlyphs, positionGlyphs and adjustGlyphPosition methods. It will
+     * compute the glyph, character index and position arrays.
+     *
+     * @param chars - the input character context
+     * @param offset - the offset of the first character to process
+     * @param count - the number of characters to process
+     * @param max - the number of characters in the input context
+     * @param rightToLeft - TRUE if the characers are in a right to left directional run
+     * @param x - the initial X position
+     * @param y - the initial Y position
+     * @param success - output parameter set to an error code if the operation fails
+     *
+     * @return the number of glyphs in the glyph array
+     *
+     * Note: The glyph, character index and position array can be accessed
+     * using the getter methods below.
+     *
+     * Note: If you call this method more than once, you must call the reset()
+     * method first to free the glyph, character index and position arrays
+     * allocated by the previous call.
+     *
+     * @stable ICU 2.8
+     */
+    virtual le_int32 layoutChars(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, float x, float y, LEErrorCode &success);
+
+    /**
+     * This method returns the number of glyphs in the glyph array. Note
+     * that the number of glyphs will be greater than or equal to the number
+     * of characters used to create the LayoutEngine.
+     *
+     * @return the number of glyphs in the glyph array
+     *
+     * @stable ICU 2.8
+     */
+    le_int32 getGlyphCount() const;
+
+    /**
+     * This method copies the glyph array into a caller supplied array.
+     * The caller must ensure that the array is large enough to hold all
+     * the glyphs.
+     *
+     * @param glyphs - the destiniation glyph array
+     * @param success - set to an error code if the operation fails
+     *
+     * @stable ICU 2.8
+     */
+    void getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const;
+
+    /**
+     * This method copies the glyph array into a caller supplied array,
+     * ORing in extra bits. (This functionality is needed by the JDK,
+     * which uses 32 bits pre glyph idex, with the high 16 bits encoding
+     * the composite font slot number)
+     *
+     * @param glyphs - the destination (32 bit) glyph array
+     * @param extraBits - this value will be ORed with each glyph index
+     * @param success - set to an error code if the operation fails
+     *
+     * @stable ICU 2.8
+     */
+    virtual void getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const;
+
+    /**
+     * This method copies the character index array into a caller supplied array.
+     * The caller must ensure that the array is large enough to hold a
+     * character index for each glyph.
+     *
+     * @param charIndices - the destiniation character index array
+     * @param success - set to an error code if the operation fails
+     *
+     * @stable ICU 2.8
+     */
+    void getCharIndices(le_int32 charIndices[], LEErrorCode &success) const;
+
+    /**
+     * This method copies the character index array into a caller supplied array.
+     * The caller must ensure that the array is large enough to hold a
+     * character index for each glyph.
+     *
+     * @param charIndices - the destiniation character index array
+     * @param indexBase - an offset which will be added to each index
+     * @param success - set to an error code if the operation fails
+     *
+     * @stable ICU 2.8
+     */
+    void getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const;
+
+    /**
+     * This method copies the position array into a caller supplied array.
+     * The caller must ensure that the array is large enough to hold an
+     * X and Y position for each glyph, plus an extra X and Y for the
+     * advance of the last glyph.
+     *
+     * @param positions - the destiniation position array
+     * @param success - set to an error code if the operation fails
+     *
+     * @stable ICU 2.8
+     */
+    void getGlyphPositions(float positions[], LEErrorCode &success) const;
+
+    /**
+     * This method returns the X and Y position of the glyph at
+     * the given index.
+     *
+     * Input parameters:
+     * @param glyphIndex - the index of the glyph
+     *
+     * Output parameters:
+     * @param x - the glyph's X position
+     * @param y - the glyph's Y position
+     * @param success - set to an error code if the operation fails
+     *
+     * @stable ICU 2.8
+     */
+    void getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const;
+
+    /**
+     * This method frees the glyph, character index and position arrays
+     * so that the LayoutEngine can be reused to layout a different
+     * characer array. (This method is also called by the destructor)
+     *
+     * @stable ICU 2.8
+     */
+    virtual void reset();
+
+    /**
+     * This method returns a LayoutEngine capable of laying out text
+     * in the given font, script and langauge. Note that the LayoutEngine
+     * returned may be a subclass of LayoutEngine.
+     *
+     * @param fontInstance - the font of the text
+     * @param scriptCode - the script of the text
+     * @param languageCode - the language of the text
+     * @param success - output parameter set to an error code if the operation fails
+     *
+     * @return a LayoutEngine which can layout text in the given font.
+     *
+     * @see LEFontInstance
+     *
+     * @stable ICU 2.8
+     */
+    static LayoutEngine *layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success);
+
+    /**
+     * Override of existing call that provides flags to control typography.
+     * @stable ICU 3.4
+     */
+    static LayoutEngine *layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typo_flags, LEErrorCode &success);
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.8
+     */
+    static UClassID getStaticClassID();
+
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/LayoutTables.h b/source/layout/LayoutTables.h
new file mode 100644
index 0000000..fda5081
--- /dev/null
+++ b/source/layout/LayoutTables.h
@@ -0,0 +1,26 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __LAYOUTTABLES_H
+#define __LAYOUTTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+
+U_NAMESPACE_BEGIN
+
+#define ANY_NUMBER 1
+
+typedef le_int16 ByteOffset;
+typedef le_int16 WordOffset;
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/LigatureSubstProc.cpp b/source/layout/LigatureSubstProc.cpp
new file mode 100644
index 0000000..8df9a78
--- /dev/null
+++ b/source/layout/LigatureSubstProc.cpp
@@ -0,0 +1,117 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "StateTables.h"
+#include "MorphStateTables.h"
+#include "SubtableProcessor.h"
+#include "StateTableProcessor.h"
+#include "LigatureSubstProc.h"
+#include "LEGlyphStorage.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+#define ExtendedComplement(m) ((le_int32) (~((le_uint32) (m))))
+#define SignBit(m) ((ExtendedComplement(m) >> 1) & (le_int32)(m))
+#define SignExtend(v,m) (((v) & SignBit(m))? ((v) | ExtendedComplement(m)): (v))
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LigatureSubstitutionProcessor)
+
+LigatureSubstitutionProcessor::LigatureSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader)
+  : StateTableProcessor(morphSubtableHeader)
+{
+    ligatureSubstitutionHeader = (const LigatureSubstitutionHeader *) morphSubtableHeader;
+    ligatureActionTableOffset = SWAPW(ligatureSubstitutionHeader->ligatureActionTableOffset);
+    componentTableOffset = SWAPW(ligatureSubstitutionHeader->componentTableOffset);
+    ligatureTableOffset = SWAPW(ligatureSubstitutionHeader->ligatureTableOffset);
+
+    entryTable = (const LigatureSubstitutionStateEntry *) ((char *) &stateTableHeader->stHeader + entryTableOffset);
+}
+
+LigatureSubstitutionProcessor::~LigatureSubstitutionProcessor()
+{
+}
+
+void LigatureSubstitutionProcessor::beginStateTable()
+{
+    m = -1;
+}
+
+ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex index)
+{
+    const LigatureSubstitutionStateEntry *entry = &entryTable[index];
+    ByteOffset newState = SWAPW(entry->newStateOffset);
+    le_int16 flags = SWAPW(entry->flags);
+
+    if (flags & lsfSetComponent) {
+        if (++m >= nComponents) {
+            m = 0;
+        }
+
+        componentStack[m] = currGlyph;
+    }
+
+    ByteOffset actionOffset = flags & lsfActionOffsetMask;
+
+    if (actionOffset != 0) {
+        const LigatureActionEntry *ap = (const LigatureActionEntry *) ((char *) &ligatureSubstitutionHeader->stHeader + actionOffset);
+        LigatureActionEntry action;
+        le_int32 offset, i = 0;
+        le_int32 stack[nComponents];
+        le_int16 mm = -1;
+
+        do {
+            le_uint32 componentGlyph = componentStack[m--];
+
+            action = SWAPL(*ap++);
+
+            if (m < 0) {
+                m = nComponents - 1;
+            }
+
+            offset = action & lafComponentOffsetMask;
+            if (offset != 0) {
+                const le_int16 *offsetTable = (const le_int16 *)((char *) &ligatureSubstitutionHeader->stHeader + 2 * SignExtend(offset, lafComponentOffsetMask));
+
+                i += SWAPW(offsetTable[LE_GET_GLYPH(glyphStorage[componentGlyph])]);
+
+                if (action & (lafLast | lafStore))  {
+                    const TTGlyphID *ligatureOffset = (const TTGlyphID *) ((char *) &ligatureSubstitutionHeader->stHeader + i);
+                    TTGlyphID ligatureGlyph = SWAPW(*ligatureOffset);
+
+                    glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], ligatureGlyph);
+                    stack[++mm] = componentGlyph;
+                    i = 0;
+                } else {
+                    glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], 0xFFFF);
+                }
+            }
+        } while (!(action & lafLast));
+
+        while (mm >= 0) {
+            if (++m >= nComponents) {
+                m = 0;
+            }
+
+            componentStack[m] = stack[mm--];
+        }
+    }
+
+    if (!(flags & lsfDontAdvance)) {
+        // should handle reverse too!
+        currGlyph += 1;
+    }
+
+    return newState;
+}
+
+void LigatureSubstitutionProcessor::endStateTable()
+{
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/LigatureSubstProc.h b/source/layout/LigatureSubstProc.h
new file mode 100644
index 0000000..ef5b1ed
--- /dev/null
+++ b/source/layout/LigatureSubstProc.h
@@ -0,0 +1,71 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __LIGATURESUBSTITUTIONPROCESSOR_H
+#define __LIGATURESUBSTITUTIONPROCESSOR_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "SubtableProcessor.h"
+#include "StateTableProcessor.h"
+#include "LigatureSubstitution.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+#define nComponents 16
+
+class LigatureSubstitutionProcessor : public StateTableProcessor
+{
+public:
+    virtual void beginStateTable();
+
+    virtual ByteOffset processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex index);
+
+    virtual void endStateTable();
+
+    LigatureSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader);
+    virtual ~LigatureSubstitutionProcessor();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.8
+     */
+    static UClassID getStaticClassID();
+
+private:
+    LigatureSubstitutionProcessor();
+
+protected:
+    ByteOffset ligatureActionTableOffset;
+    ByteOffset componentTableOffset;
+    ByteOffset ligatureTableOffset;
+
+    const LigatureSubstitutionStateEntry *entryTable;
+
+    le_int32 componentStack[nComponents];
+    le_int16 m;
+
+    const LigatureSubstitutionHeader *ligatureSubstitutionHeader;
+
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/LigatureSubstSubtables.cpp b/source/layout/LigatureSubstSubtables.cpp
new file mode 100644
index 0000000..391ffe6
--- /dev/null
+++ b/source/layout/LigatureSubstSubtables.cpp
@@ -0,0 +1,68 @@
+/*
+ * (C) Copyright IBM Corp. 1998-2006 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEGlyphFilter.h"
+#include "OpenTypeTables.h"
+#include "GlyphSubstitutionTables.h"
+#include "LigatureSubstSubtables.h"
+#include "GlyphIterator.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+le_uint32 LigatureSubstitutionSubtable::process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter) const
+{
+    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
+    le_int32 coverageIndex = getGlyphCoverage(glyph);
+
+    if (coverageIndex >= 0) {
+        Offset ligSetTableOffset = SWAPW(ligSetTableOffsetArray[coverageIndex]);
+        const LigatureSetTable *ligSetTable = (const LigatureSetTable *) ((char *) this + ligSetTableOffset);
+        le_uint16 ligCount = SWAPW(ligSetTable->ligatureCount);
+
+        for (le_uint16 lig = 0; lig < ligCount; lig += 1) {
+            Offset ligTableOffset = SWAPW(ligSetTable->ligatureTableOffsetArray[lig]);
+            const LigatureTable *ligTable = (const LigatureTable *) ((char *)ligSetTable + ligTableOffset);
+            le_uint16 compCount = SWAPW(ligTable->compCount) - 1;
+            le_int32 startPosition = glyphIterator->getCurrStreamPosition();
+            TTGlyphID ligGlyph = SWAPW(ligTable->ligGlyph);
+            le_uint16 comp;
+
+            for (comp = 0; comp < compCount; comp += 1) {
+                if (! glyphIterator->next()) {
+                    break;
+                }
+
+                if (LE_GET_GLYPH(glyphIterator->getCurrGlyphID()) != SWAPW(ligTable->componentArray[comp])) {
+                    break;
+                }
+            }
+
+            if (comp == compCount && (filter == NULL || filter->accept(LE_SET_GLYPH(glyph, ligGlyph)))) {
+                GlyphIterator tempIterator(*glyphIterator);
+                TTGlyphID deletedGlyph = tempIterator.ignoresMarks()? 0xFFFE : 0xFFFF;
+
+                while (comp > 0) {
+                    tempIterator.setCurrGlyphID(deletedGlyph);
+                    tempIterator.prev();
+
+                    comp -= 1;
+                }
+
+                tempIterator.setCurrGlyphID(ligGlyph);
+
+                return compCount + 1;
+            }
+
+            glyphIterator->setCurrStreamPosition(startPosition);
+        }
+
+    }
+
+    return 0;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/LigatureSubstSubtables.h b/source/layout/LigatureSubstSubtables.h
new file mode 100644
index 0000000..423c95a
--- /dev/null
+++ b/source/layout/LigatureSubstSubtables.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __LIGATURESUBSTITUTIONSUBTABLES_H
+#define __LIGATURESUBSTITUTIONSUBTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEGlyphFilter.h"
+#include "OpenTypeTables.h"
+#include "GlyphSubstitutionTables.h"
+#include "GlyphIterator.h"
+
+U_NAMESPACE_BEGIN
+
+struct LigatureSetTable
+{
+    le_uint16 ligatureCount;
+    Offset    ligatureTableOffsetArray[ANY_NUMBER];
+};
+
+struct LigatureTable
+{
+    TTGlyphID ligGlyph;
+    le_uint16 compCount;
+    TTGlyphID componentArray[ANY_NUMBER];
+};
+
+struct LigatureSubstitutionSubtable : GlyphSubstitutionSubtable
+{
+    le_uint16 ligSetCount;
+    Offset    ligSetTableOffsetArray[ANY_NUMBER];
+
+    le_uint32  process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter = NULL) const;
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/LigatureSubstitution.h b/source/layout/LigatureSubstitution.h
new file mode 100644
index 0000000..2963b7c
--- /dev/null
+++ b/source/layout/LigatureSubstitution.h
@@ -0,0 +1,51 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __LIGATURESUBSTITUTION_H
+#define __LIGATURESUBSTITUTION_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LayoutTables.h"
+#include "StateTables.h"
+#include "MorphTables.h"
+#include "MorphStateTables.h"
+
+U_NAMESPACE_BEGIN
+
+struct LigatureSubstitutionHeader : MorphStateTableHeader
+{
+    ByteOffset ligatureActionTableOffset;
+    ByteOffset componentTableOffset;
+    ByteOffset ligatureTableOffset;
+};
+
+enum LigatureSubstitutionFlags
+{
+    lsfSetComponent     = 0x8000,
+    lsfDontAdvance      = 0x4000,
+    lsfActionOffsetMask = 0x3FFF
+};
+
+struct LigatureSubstitutionStateEntry : StateEntry
+{
+};
+
+typedef le_uint32 LigatureActionEntry;
+
+enum LigatureActionFlags
+{
+    lafLast                 = 0x80000000,
+    lafStore                = 0x40000000,
+    lafComponentOffsetMask  = 0x3FFFFFFF
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/LookupProcessor.cpp b/source/layout/LookupProcessor.cpp
new file mode 100644
index 0000000..4d4347c
--- /dev/null
+++ b/source/layout/LookupProcessor.cpp
@@ -0,0 +1,301 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "OpenTypeUtilities.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "ICUFeatures.h"
+#include "Lookups.h"
+#include "ScriptAndLanguage.h"
+#include "GlyphDefinitionTables.h"
+#include "GlyphIterator.h"
+#include "LookupProcessor.h"
+#include "LEGlyphStorage.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+le_uint32 LookupProcessor::applyLookupTable(const LookupTable *lookupTable, GlyphIterator *glyphIterator,
+                                         const LEFontInstance *fontInstance, LEErrorCode& success) const
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    le_uint16 lookupType = SWAPW(lookupTable->lookupType);
+    le_uint16 subtableCount = SWAPW(lookupTable->subTableCount);
+    le_int32 startPosition = glyphIterator->getCurrStreamPosition();
+    le_uint32 delta;
+
+    for (le_uint16 subtable = 0; subtable < subtableCount; subtable += 1) {
+        const LookupSubtable *lookupSubtable = lookupTable->getLookupSubtable(subtable);
+
+        delta = applySubtable(lookupSubtable, lookupType, glyphIterator, fontInstance, success);
+
+        if (delta > 0 && LE_FAILURE(success)) {
+            return 1;
+        }
+
+        glyphIterator->setCurrStreamPosition(startPosition);
+    }
+
+    return 1;
+}
+
+le_int32 LookupProcessor::process(LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments,
+                              le_bool rightToLeft, const GlyphDefinitionTableHeader *glyphDefinitionTableHeader,
+                              const LEFontInstance *fontInstance, LEErrorCode& success) const
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }    
+	
+    le_int32 glyphCount = glyphStorage.getGlyphCount();
+
+    if (lookupSelectArray == NULL) {
+        return glyphCount;
+    }
+
+    GlyphIterator glyphIterator(glyphStorage, glyphPositionAdjustments,
+                                rightToLeft, 0, 0, glyphDefinitionTableHeader);
+    le_int32 newGlyphCount = glyphCount;
+
+    for (le_uint16 order = 0; order < lookupOrderCount; order += 1) {
+        le_uint16 lookup = lookupOrderArray[order];
+        FeatureMask selectMask = lookupSelectArray[lookup];
+
+        if (selectMask != 0) {
+            const LookupTable *lookupTable = lookupListTable->getLookupTable(lookup);
+            le_uint16 lookupFlags = SWAPW(lookupTable->lookupFlags);
+            
+            glyphIterator.reset(lookupFlags, selectMask);
+
+            while (glyphIterator.findFeatureTag()) {
+                applyLookupTable(lookupTable, &glyphIterator, fontInstance, success);
+                if (LE_FAILURE(success)) { 
+                    return 0;
+                }
+            }
+
+            newGlyphCount = glyphIterator.applyInsertions();
+        }
+    }
+
+    return newGlyphCount;
+}
+
+le_uint32 LookupProcessor::applySingleLookup(le_uint16 lookupTableIndex, GlyphIterator *glyphIterator,
+                                          const LEFontInstance *fontInstance, LEErrorCode& success) const
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }    
+
+    const LookupTable *lookupTable = lookupListTable->getLookupTable(lookupTableIndex);
+    le_uint16 lookupFlags = SWAPW(lookupTable->lookupFlags);
+    GlyphIterator tempIterator(*glyphIterator, lookupFlags);
+    le_uint32 delta = applyLookupTable(lookupTable, &tempIterator, fontInstance, success);
+
+    return delta;
+}
+
+le_int32 LookupProcessor::selectLookups(const FeatureTable *featureTable, FeatureMask featureMask, le_int32 order)
+{
+    le_uint16 lookupCount = featureTable? SWAPW(featureTable->lookupCount) : 0;
+    le_int32  store = order;
+
+    for (le_uint16 lookup = 0; lookup < lookupCount; lookup += 1) {
+        le_uint16 lookupListIndex = SWAPW(featureTable->lookupListIndexArray[lookup]);
+
+        lookupSelectArray[lookupListIndex] |= featureMask;
+        lookupOrderArray[store++] = lookupListIndex;
+    }
+
+    return store - order;
+}
+
+LookupProcessor::LookupProcessor(const char *baseAddress,
+        Offset scriptListOffset, Offset featureListOffset, Offset lookupListOffset,
+        LETag scriptTag, LETag languageTag, const FeatureMap *featureMap, le_int32 featureMapCount, le_bool orderFeatures, 
+        LEErrorCode& success)
+    : lookupListTable(NULL), featureListTable(NULL), lookupSelectArray(NULL),
+      lookupOrderArray(NULL), lookupOrderCount(0)
+{
+    const ScriptListTable *scriptListTable = NULL;
+    const LangSysTable *langSysTable = NULL;
+    le_uint16 featureCount = 0;
+    le_uint16 lookupListCount = 0;
+    le_uint16 requiredFeatureIndex;
+
+    if (LE_FAILURE(success)) {
+        return;
+    } 
+
+    if (scriptListOffset != 0) {
+        scriptListTable = (const ScriptListTable *) (baseAddress + scriptListOffset);
+        langSysTable = scriptListTable->findLanguage(scriptTag, languageTag);
+
+        if (langSysTable != 0) {
+            featureCount = SWAPW(langSysTable->featureCount);
+        }
+    }
+
+    if (featureListOffset != 0) {
+        featureListTable = (const FeatureListTable *) (baseAddress + featureListOffset);
+    }
+
+    if (lookupListOffset != 0) {
+        lookupListTable = (const LookupListTable *) (baseAddress + lookupListOffset);
+        lookupListCount = SWAPW(lookupListTable->lookupCount);
+    }
+    
+    if (langSysTable == NULL || featureListTable == NULL || lookupListTable == NULL ||
+        featureCount == 0 || lookupListCount == 0) {
+        return;
+    }
+ 
+    requiredFeatureIndex = SWAPW(langSysTable->reqFeatureIndex);
+
+    lookupSelectArray = LE_NEW_ARRAY(FeatureMask, lookupListCount);
+    if (lookupSelectArray == NULL) {
+        success = LE_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+
+    for (int i = 0; i < lookupListCount; i += 1) {
+        lookupSelectArray[i] = 0;
+    }
+
+    le_int32 count, order = 0;
+    le_int32 featureReferences = 0;
+    const FeatureTable *featureTable = NULL;
+    LETag featureTag;
+
+    const FeatureTable *requiredFeatureTable = NULL;
+    LETag requiredFeatureTag = 0x00000000U;
+
+    // Count the total number of lookups referenced by all features. This will
+    // be the maximum number of entries in the lookupOrderArray. We can't use
+    // lookupListCount because some lookups might be referenced by more than
+    // one feature.
+    for (le_int32 feature = 0; feature < featureCount; feature += 1) {
+        le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]);
+
+        featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag);
+        featureReferences += SWAPW(featureTable->lookupCount);
+    }
+
+    if (requiredFeatureIndex != 0xFFFF) {
+        requiredFeatureTable = featureListTable->getFeatureTable(requiredFeatureIndex, &requiredFeatureTag);
+        featureReferences += SWAPW(featureTable->lookupCount);
+    }
+
+    lookupOrderArray = LE_NEW_ARRAY(le_uint16, featureReferences);
+    if (lookupOrderArray == NULL) {
+        success = LE_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+
+    for (le_int32 f = 0; f < featureMapCount; f += 1) {
+        FeatureMap fm = featureMap[f];
+        count = 0;
+
+        // If this is the required feature, add its lookups
+        if (requiredFeatureTag == fm.tag) {
+            count += selectLookups(requiredFeatureTable, fm.mask, order);
+        }
+
+        if (orderFeatures) {
+            // If we added lookups from the required feature, sort them
+            if (count > 1) {
+                OpenTypeUtilities::sort(lookupOrderArray, order);
+            }
+
+            for (le_uint16 feature = 0; feature < featureCount; feature += 1) {
+                le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]);
+ 
+                // don't add the required feature to the list more than once...
+                // TODO: Do we need this check? (Spec. says required feature won't be in feature list...)
+                if (featureIndex == requiredFeatureIndex) {
+                    continue;
+                }
+
+                featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag);
+
+                if (featureTag == fm.tag) {
+                    count += selectLookups(featureTable, fm.mask, order + count);
+                }
+            }
+
+            if (count > 1) {
+                OpenTypeUtilities::sort(&lookupOrderArray[order], count);
+            }
+
+            order += count;
+        } else {
+            for (le_uint16 feature = 0; feature < featureCount; feature += 1) {
+                le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]);
+ 
+                // don't add the required feature to the list more than once...
+                // NOTE: This check is commented out because the spec. says that
+                // the required feature won't be in the feature list, and because
+                // any duplicate entries will be removed below.
+#if 0
+                if (featureIndex == requiredFeatureIndex) {
+                    continue;
+                }
+#endif
+
+                featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag);
+
+                if (featureTag == fm.tag) {
+                    order += selectLookups(featureTable, fm.mask, order);
+                }
+            }
+        }
+    }
+
+    if (!orderFeatures && (order > 1)) {
+        OpenTypeUtilities::sort(lookupOrderArray, order);
+
+        // If there's no specified feature order,
+        // we will apply the lookups in the order
+        // that they're in the font. If a particular
+        // lookup may be referenced by more than one feature,
+        // it will apprear in the lookupOrderArray more than
+        // once, so remove any duplicate entries in the sorted array.
+        le_int32 out = 1;
+
+        for (le_int32 in = 1; in < order; in += 1) {
+            if (lookupOrderArray[out - 1] != lookupOrderArray[in]) {
+                if (out != in) {
+                    lookupOrderArray[out] = lookupOrderArray[in];
+                }
+
+                out += 1;
+            }
+        }
+
+        order = out;
+    }
+
+    lookupOrderCount = order;
+}
+
+LookupProcessor::LookupProcessor()
+{
+	lookupOrderArray = NULL;
+	lookupSelectArray = NULL;
+}
+
+LookupProcessor::~LookupProcessor()
+{
+    LE_DELETE_ARRAY(lookupOrderArray);
+    LE_DELETE_ARRAY(lookupSelectArray);
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/LookupProcessor.h b/source/layout/LookupProcessor.h
new file mode 100644
index 0000000..080034c
--- /dev/null
+++ b/source/layout/LookupProcessor.h
@@ -0,0 +1,79 @@
+/*
+ * %W% %E%
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#ifndef __LOOKUPPROCESSOR_H
+#define __LOOKUPPROCESSOR_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+//#include "Lookups.h"
+//#include "Features.h"
+
+U_NAMESPACE_BEGIN
+
+class  LEFontInstance;
+class  LEGlyphStorage;
+class  GlyphIterator;
+class  GlyphPositionAdjustments;
+struct FeatureTable;
+struct FeatureListTable;
+struct GlyphDefinitionTableHeader;
+struct LookupSubtable;
+struct LookupTable;
+
+class LookupProcessor : public UMemory {
+public:
+    le_int32 process(LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments,
+                 le_bool rightToLeft, const GlyphDefinitionTableHeader *glyphDefinitionTableHeader, const LEFontInstance *fontInstance, LEErrorCode& success) const;
+
+    le_uint32 applyLookupTable(const LookupTable *lookupTable, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const;
+
+    le_uint32 applySingleLookup(le_uint16 lookupTableIndex, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const;
+
+    virtual le_uint32 applySubtable(const LookupSubtable *lookupSubtable, le_uint16 subtableType,
+        GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const = 0;
+
+    virtual ~LookupProcessor();
+
+protected:
+    LookupProcessor(const char *baseAddress,
+        Offset scriptListOffset, 
+        Offset featureListOffset, 
+        Offset lookupListOffset,
+        LETag scriptTag, 
+        LETag languageTag, 
+        const FeatureMap *featureMap, 
+        le_int32 featureMapCount, 
+        le_bool orderFeatures, 
+        LEErrorCode& success);
+
+    LookupProcessor();
+
+    le_int32 selectLookups(const FeatureTable *featureTable, FeatureMask featureMask, le_int32 order);
+
+    const LookupListTable   *lookupListTable;
+    const FeatureListTable  *featureListTable;
+
+    FeatureMask            *lookupSelectArray;
+
+    le_uint16               *lookupOrderArray;
+    le_uint32               lookupOrderCount;
+
+private:
+
+    LookupProcessor(const LookupProcessor &other); // forbid copying of this class
+    LookupProcessor &operator=(const LookupProcessor &other); // forbid copying of this class
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/LookupTables.cpp b/source/layout/LookupTables.cpp
new file mode 100644
index 0000000..9766a81
--- /dev/null
+++ b/source/layout/LookupTables.cpp
@@ -0,0 +1,85 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LayoutTables.h"
+#include "LookupTables.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+/*
+    These are the rolled-up versions of the uniform binary search.
+    Someday, if we need more performance, we can un-roll them.
+    
+    Note: I put these in the base class, so they only have to
+    be written once. Since the base class doesn't define the
+    segment table, these routines assume that it's right after
+    the binary search header.
+
+    Another way to do this is to put each of these routines in one
+    of the derived classes, and implement it in the others by casting
+    the "this" pointer to the type that has the implementation.
+*/ 
+const LookupSegment *BinarySearchLookupTable::lookupSegment(const LookupSegment *segments, LEGlyphID glyph) const
+{
+    le_int16  unity = SWAPW(unitSize);
+    le_int16  probe = SWAPW(searchRange);
+    le_int16  extra = SWAPW(rangeShift);
+    TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(glyph);
+    const LookupSegment *entry = segments;
+    const LookupSegment *trial = (const LookupSegment *) ((char *) entry + extra);
+
+    if (SWAPW(trial->lastGlyph) <= ttGlyph) {
+        entry = trial;
+    }
+
+    while (probe > unity) {
+        probe >>= 1;
+        trial = (const LookupSegment *) ((char *) entry + probe);
+
+        if (SWAPW(trial->lastGlyph) <= ttGlyph) {
+            entry = trial;
+        }
+    }
+
+    if (SWAPW(entry->firstGlyph) <= ttGlyph) {
+        return entry;
+    }
+
+    return NULL;
+}
+
+const LookupSingle *BinarySearchLookupTable::lookupSingle(const LookupSingle *entries, LEGlyphID glyph) const
+{
+    le_int16  unity = SWAPW(unitSize);
+    le_int16  probe = SWAPW(searchRange);
+    le_int16  extra = SWAPW(rangeShift);
+    TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(glyph);
+    const LookupSingle *entry = entries;
+    const LookupSingle *trial = (const LookupSingle *) ((char *) entry + extra);
+
+    if (SWAPW(trial->glyph) <= ttGlyph) {
+        entry = trial;
+    }
+
+    while (probe > unity) {
+        probe >>= 1;
+        trial = (const LookupSingle *) ((char *) entry + probe);
+
+        if (SWAPW(trial->glyph) <= ttGlyph) {
+            entry = trial;
+        }
+    }
+
+    if (SWAPW(entry->glyph) == ttGlyph) {
+        return entry;
+    }
+
+    return NULL;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/LookupTables.h b/source/layout/LookupTables.h
new file mode 100644
index 0000000..5fa8499
--- /dev/null
+++ b/source/layout/LookupTables.h
@@ -0,0 +1,90 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __LOOKUPTABLES_H
+#define __LOOKUPTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LayoutTables.h"
+
+U_NAMESPACE_BEGIN
+
+enum LookupTableFormat
+{
+    ltfSimpleArray      = 0,
+    ltfSegmentSingle    = 2,
+    ltfSegmentArray     = 4,
+    ltfSingleTable      = 6,
+    ltfTrimmedArray     = 8
+};
+
+typedef le_int16 LookupValue;
+
+struct LookupTable
+{
+    le_int16 format;
+};
+
+struct LookupSegment
+{
+    TTGlyphID   lastGlyph;
+    TTGlyphID   firstGlyph;
+    LookupValue value;
+};
+
+struct LookupSingle
+{
+    TTGlyphID   glyph;
+    LookupValue value;
+};
+
+struct BinarySearchLookupTable : LookupTable
+{
+    le_int16 unitSize;
+    le_int16 nUnits;
+    le_int16 searchRange;
+    le_int16 entrySelector;
+    le_int16 rangeShift;
+
+    const LookupSegment *lookupSegment(const LookupSegment *segments, LEGlyphID glyph) const;
+
+    const LookupSingle *lookupSingle(const LookupSingle *entries, LEGlyphID glyph) const;
+};
+
+struct SimpleArrayLookupTable : LookupTable
+{
+    LookupValue valueArray[ANY_NUMBER];
+};
+
+struct SegmentSingleLookupTable : BinarySearchLookupTable
+{
+    LookupSegment segments[ANY_NUMBER];
+};
+
+struct SegmentArrayLookupTable : BinarySearchLookupTable
+{
+    LookupSegment segments[ANY_NUMBER];
+};
+
+struct SingleTableLookupTable : BinarySearchLookupTable
+{
+    LookupSingle entries[ANY_NUMBER];
+};
+
+struct TrimmedArrayLookupTable : LookupTable
+{
+    TTGlyphID   firstGlyph;
+    TTGlyphID   glyphCount;
+    LookupValue valueArray[ANY_NUMBER];
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/Lookups.cpp b/source/layout/Lookups.cpp
new file mode 100644
index 0000000..67f6295
--- /dev/null
+++ b/source/layout/Lookups.cpp
@@ -0,0 +1,44 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "Lookups.h"
+#include "CoverageTables.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+const LookupTable *LookupListTable::getLookupTable(le_uint16 lookupTableIndex) const
+{
+    if (lookupTableIndex >= SWAPW(lookupCount)) {
+        return 0;
+    }
+
+    Offset lookupTableOffset = lookupTableOffsetArray[lookupTableIndex];
+
+    return (const LookupTable *) ((char *) this + SWAPW(lookupTableOffset));
+}
+
+const LookupSubtable *LookupTable::getLookupSubtable(le_uint16 subtableIndex) const
+{
+    if (subtableIndex >= SWAPW(subTableCount)) {
+        return 0;
+    }
+
+    Offset subtableOffset = subTableOffsetArray[subtableIndex];
+
+    return (const LookupSubtable *) ((char *) this + SWAPW(subtableOffset));
+}
+
+le_int32 LookupSubtable::getGlyphCoverage(Offset tableOffset, LEGlyphID glyphID) const
+{
+    const CoverageTable *coverageTable = (const CoverageTable *) ((char *) this + SWAPW(tableOffset));
+
+    return coverageTable->getGlyphCoverage(glyphID);
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/Lookups.h b/source/layout/Lookups.h
new file mode 100644
index 0000000..2316b57
--- /dev/null
+++ b/source/layout/Lookups.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
+ *
+ */
+
+#ifndef __LOOKUPS_H
+#define __LOOKUPS_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+
+U_NAMESPACE_BEGIN
+
+enum LookupFlags
+{
+    lfBaselineIsLogicalEnd  = 0x0001,  // The MS spec. calls this flag "RightToLeft" but this name is more accurate 
+    lfIgnoreBaseGlyphs      = 0x0002,
+    lfIgnoreLigatures       = 0x0004,
+    lfIgnoreMarks           = 0x0008,
+    lfReservedMask          = 0x00F0,
+    lfMarkAttachTypeMask    = 0xFF00,
+    lfMarkAttachTypeShift   = 8
+};
+
+struct LookupSubtable
+{
+    le_uint16 subtableFormat;
+    Offset    coverageTableOffset;
+
+    inline le_int32  getGlyphCoverage(LEGlyphID glyphID) const;
+
+    le_int32  getGlyphCoverage(Offset tableOffset, LEGlyphID glyphID) const;
+};
+
+struct LookupTable
+{
+    le_uint16       lookupType;
+    le_uint16       lookupFlags;
+    le_uint16       subTableCount;
+    Offset          subTableOffsetArray[ANY_NUMBER];
+
+    const LookupSubtable  *getLookupSubtable(le_uint16 subtableIndex) const;
+};
+
+struct LookupListTable
+{
+    le_uint16   lookupCount;
+    Offset      lookupTableOffsetArray[ANY_NUMBER];
+
+    const LookupTable *getLookupTable(le_uint16 lookupTableIndex) const;
+};
+
+inline le_int32 LookupSubtable::getGlyphCoverage(LEGlyphID glyphID) const
+{
+    return getGlyphCoverage(coverageTableOffset, glyphID);
+}
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/MPreFixups.cpp b/source/layout/MPreFixups.cpp
new file mode 100644
index 0000000..08ad7a7
--- /dev/null
+++ b/source/layout/MPreFixups.cpp
@@ -0,0 +1,105 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 2002-2008 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEGlyphStorage.h"
+#include "MPreFixups.h"
+
+U_NAMESPACE_BEGIN
+
+struct FixupData
+{
+    le_int32 fBaseIndex;
+    le_int32 fMPreIndex;
+};
+
+MPreFixups::MPreFixups(le_int32 charCount)
+    : fFixupData(NULL), fFixupCount(0)
+{
+    fFixupData = LE_NEW_ARRAY(FixupData, charCount);
+}
+
+MPreFixups::~MPreFixups()
+{
+    LE_DELETE_ARRAY(fFixupData);
+    fFixupData = NULL;
+}
+
+void MPreFixups::add(le_int32 baseIndex, le_int32 mpreIndex)
+{
+    // NOTE: don't add the fixup data if the mpre is right
+    // before the base consonant glyph.
+    if (baseIndex - mpreIndex > 1) {
+        fFixupData[fFixupCount].fBaseIndex = baseIndex;
+        fFixupData[fFixupCount].fMPreIndex = mpreIndex;
+
+        fFixupCount += 1;
+    }
+}
+
+void MPreFixups::apply(LEGlyphStorage &glyphStorage, LEErrorCode& success)
+{
+    if (LE_FAILURE(success)) { 
+        return;
+    }
+
+    for (le_int32 fixup = 0; fixup < fFixupCount; fixup += 1) {
+        le_int32 baseIndex = fFixupData[fixup].fBaseIndex;
+        le_int32 mpreIndex = fFixupData[fixup].fMPreIndex;
+        le_int32 mpreLimit = mpreIndex + 1;
+
+        while (glyphStorage[baseIndex] == 0xFFFF || glyphStorage[baseIndex] == 0xFFFE) {
+            baseIndex -= 1;
+        }
+
+        while (glyphStorage[mpreLimit] == 0xFFFF || glyphStorage[mpreLimit] == 0xFFFE) {
+            mpreLimit += 1;
+        }
+
+        if (mpreLimit == baseIndex) {
+            continue;
+        }
+
+        LEErrorCode success = LE_NO_ERROR;
+        le_int32   mpreCount = mpreLimit - mpreIndex;
+        le_int32   moveCount = baseIndex - mpreLimit;
+        le_int32   mpreDest  = baseIndex - mpreCount;
+        LEGlyphID *mpreSave  = LE_NEW_ARRAY(LEGlyphID, mpreCount);
+        le_int32  *indexSave = LE_NEW_ARRAY(le_int32, mpreCount);
+
+        if (mpreSave == NULL || indexSave == NULL) {
+            LE_DELETE_ARRAY(mpreSave);
+            LE_DELETE_ARRAY(indexSave);
+            success = LE_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+
+        le_int32   i;
+
+        for (i = 0; i < mpreCount; i += 1) {
+            mpreSave[i]  = glyphStorage[mpreIndex + i];
+            indexSave[i] = glyphStorage.getCharIndex(mpreIndex + i, success); //charIndices[mpreIndex + i];
+        }
+
+        for (i = 0; i < moveCount; i += 1) {
+            LEGlyphID glyph = glyphStorage[mpreLimit + i];
+            le_int32 charIndex = glyphStorage.getCharIndex(mpreLimit + i, success);
+
+            glyphStorage[mpreIndex + i] = glyph;
+            glyphStorage.setCharIndex(mpreIndex + i, charIndex, success);
+        }
+
+        for (i = 0; i < mpreCount; i += 1) {
+            glyphStorage[mpreDest + i] = mpreSave[i];
+            glyphStorage.setCharIndex(mpreDest, indexSave[i], success);
+        }
+        
+        LE_DELETE_ARRAY(indexSave);
+        LE_DELETE_ARRAY(mpreSave);
+    }
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/MPreFixups.h b/source/layout/MPreFixups.h
new file mode 100644
index 0000000..18fefe0
--- /dev/null
+++ b/source/layout/MPreFixups.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 2002-2008 - All Rights Reserved
+ *
+ */
+
+#ifndef __MPREFIXUPS_H
+#define __MPREFIXUPS_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+// Might want to make this a private member...
+struct FixupData;
+
+class MPreFixups : public UMemory
+{
+public:
+    MPreFixups(le_int32 charCount);
+   ~MPreFixups();
+
+    void add(le_int32 baseIndex, le_int32 mpreIndex);
+    
+    void apply(LEGlyphStorage &glyphStorage, LEErrorCode& success);
+
+private:
+    FixupData *fFixupData;
+    le_int32   fFixupCount;
+};
+
+U_NAMESPACE_END
+#endif
+
+
diff --git a/source/layout/Makefile.in b/source/layout/Makefile.in
new file mode 100644
index 0000000..5e9ec49
--- /dev/null
+++ b/source/layout/Makefile.in
@@ -0,0 +1,236 @@
+#******************************************************************************
+#
+#   Copyright (C) 1999-2007, International Business Machines
+#   Corporation and others.  All Rights Reserved.
+#
+#******************************************************************************
+## Makefile.in for ICU - layout
+
+## 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 = layout
+
+## Extra files to remove for 'make clean'
+CLEANFILES = *~ $(DEPS) $(IMPORT_LIB) $(MIDDLE_IMPORT_LIB) $(FINAL_IMPORT_LIB)
+
+## Target information
+
+TARGET_STUBNAME=$(LAYOUT_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 = layout.res
+endif
+
+ifeq ($(OS390BATCH),1)
+BATCH_TARGET = $(BATCH_LAYOUT_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$(srcdir)/.. -I$(top_srcdir)/common -I$(srcdir)/unicode $(LIBCPPFLAGS)
+DEFS += -DU_LAYOUT_IMPLEMENTATION
+LDFLAGS += $(LDFLAGSICULE)
+LIBS = $(LIBICUUC) $(DEFAULT_LIBS)
+
+OBJECTS =  LEFontInstance.o \
+OpenTypeLayoutEngine.o \
+ThaiLayoutEngine.o \
+ThaiShaping.o \
+ThaiStateTables.o \
+ArabicLayoutEngine.o \
+GXLayoutEngine.o \
+HanLayoutEngine.o \
+IndicLayoutEngine.o \
+LayoutEngine.o \
+ContextualGlyphSubstProc.o \
+IndicRearrangementProcessor.o \
+LigatureSubstProc.o \
+LookupTables.o \
+MorphTables.o \
+NonContextualGlyphSubstProc.o \
+SegmentArrayProcessor.o \
+SegmentSingleProcessor.o \
+SimpleArrayProcessor.o \
+SingleTableProcessor.o \
+StateTableProcessor.o \
+SubtableProcessor.o \
+TrimmedArrayProcessor.o \
+AlternateSubstSubtables.o \
+AnchorTables.o \
+ArabicShaping.o \
+CanonData.o \
+CanonShaping.o \
+ClassDefinitionTables.o \
+ContextualSubstSubtables.o \
+CoverageTables.o \
+CursiveAttachmentSubtables.o \
+DeviceTables.o \
+ExtensionSubtables.o \
+Features.o \
+GDEFMarkFilter.o \
+GlyphDefinitionTables.o \
+GlyphIterator.o \
+GlyphLookupTables.o \
+GlyphPosnLookupProc.o \
+GlyphPositionAdjustments.o \
+GlyphPositioningTables.o \
+GlyphSubstLookupProc.o \
+GlyphSubstitutionTables.o \
+IndicClassTables.o \
+IndicReordering.o \
+LEInsertionList.o \
+LEGlyphStorage.o \
+LigatureSubstSubtables.o \
+LookupProcessor.o \
+Lookups.o \
+MarkArrays.o \
+MarkToBasePosnSubtables.o \
+MarkToLigaturePosnSubtables.o \
+MarkToMarkPosnSubtables.o \
+MirroredCharData.o \
+MPreFixups.o \
+MultipleSubstSubtables.o \
+OpenTypeUtilities.o \
+PairPositioningSubtables.o \
+ScriptAndLanguage.o \
+ScriptAndLanguageTags.o \
+ShapingTypeData.o \
+SinglePositioningSubtables.o \
+SingleSubstitutionSubtables.o \
+SubstitutionLookups.o \
+ValueRecords.o \
+KhmerLayoutEngine.o \
+KhmerReordering.o \
+TibetanLayoutEngine.o \
+TibetanReordering.o \
+HangulLayoutEngine.o \
+KernTable.o \
+loengine.o
+
+## Header files to install
+HEADERS= $(srcdir)/LayoutEngine.h $(srcdir)/LE*.h $(srcdir)/loengine.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)/layout
+	@for file in $(HEADERS); do \
+	 echo "$(INSTALL_DATA) $$file $(DESTDIR)$(includedir)/layout"; \
+	 $(INSTALL_DATA) $$file $(DESTDIR)$(includedir)/layout || 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/source/layout/MarkArrays.cpp b/source/layout/MarkArrays.cpp
new file mode 100644
index 0000000..47a0625
--- /dev/null
+++ b/source/layout/MarkArrays.cpp
@@ -0,0 +1,39 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "AnchorTables.h"
+#include "MarkArrays.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+le_int32 MarkArray::getMarkClass(LEGlyphID glyphID, le_int32 coverageIndex, const LEFontInstance *fontInstance,
+                              LEPoint &anchor) const
+{
+    le_int32 markClass = -1;
+
+    if (coverageIndex >= 0) {
+        le_uint16 mCount = SWAPW(markCount);
+
+        if (coverageIndex < mCount) {
+            const MarkRecord *markRecord = &markRecordArray[coverageIndex];
+            Offset anchorTableOffset = SWAPW(markRecord->markAnchorTableOffset);
+            const AnchorTable *anchorTable = (AnchorTable *) ((char *) this + anchorTableOffset);
+
+            anchorTable->getAnchor(glyphID, fontInstance, anchor);
+            markClass = SWAPW(markRecord->markClass);
+        }
+
+        // XXXX If we get here, the table is mal-formed
+    }
+
+    return markClass;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/MarkArrays.h b/source/layout/MarkArrays.h
new file mode 100644
index 0000000..66dca2a
--- /dev/null
+++ b/source/layout/MarkArrays.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __MARKARRAYS_H
+#define __MARKARRAYS_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+
+U_NAMESPACE_BEGIN
+
+struct MarkRecord
+{
+    le_uint16   markClass;
+    Offset      markAnchorTableOffset;
+};
+
+struct MarkArray
+{
+    le_uint16   markCount;
+    MarkRecord  markRecordArray[ANY_NUMBER];
+
+    le_int32 getMarkClass(LEGlyphID glyphID, le_int32 coverageIndex, const LEFontInstance *fontInstance,
+        LEPoint &anchor) const;
+};
+
+U_NAMESPACE_END
+#endif
+
+
diff --git a/source/layout/MarkToBasePosnSubtables.cpp b/source/layout/MarkToBasePosnSubtables.cpp
new file mode 100644
index 0000000..7711988
--- /dev/null
+++ b/source/layout/MarkToBasePosnSubtables.cpp
@@ -0,0 +1,115 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "AnchorTables.h"
+#include "MarkArrays.h"
+#include "GlyphPositioningTables.h"
+#include "AttachmentPosnSubtables.h"
+#include "MarkToBasePosnSubtables.h"
+#include "GlyphIterator.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+LEGlyphID MarkToBasePositioningSubtable::findBaseGlyph(GlyphIterator *glyphIterator) const
+{
+    if (glyphIterator->prev()) {
+        return glyphIterator->getCurrGlyphID();
+    }
+
+    return 0xFFFF;
+}
+
+le_int32 MarkToBasePositioningSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const
+{
+    LEGlyphID markGlyph = glyphIterator->getCurrGlyphID();
+    le_int32 markCoverage = getGlyphCoverage((LEGlyphID) markGlyph);
+
+    if (markCoverage < 0) {
+        // markGlyph isn't a covered mark glyph
+        return 0;
+    }
+
+    LEPoint markAnchor;
+    const MarkArray *markArray = (const MarkArray *) ((char *) this + SWAPW(markArrayOffset));
+    le_int32 markClass = markArray->getMarkClass(markGlyph, markCoverage, fontInstance, markAnchor);
+    le_uint16 mcCount = SWAPW(classCount);
+
+    if (markClass < 0 || markClass >= mcCount) {
+        // markGlyph isn't in the mark array or its
+        // mark class is too big. The table is mal-formed!
+        return 0;
+    }
+
+    // FIXME: We probably don't want to find a base glyph before a previous ligature... 
+    GlyphIterator baseIterator(*glyphIterator, (le_uint16) (lfIgnoreMarks /*| lfIgnoreLigatures*/));
+    LEGlyphID baseGlyph = findBaseGlyph(&baseIterator);
+    le_int32 baseCoverage = getBaseCoverage((LEGlyphID) baseGlyph);
+    const BaseArray *baseArray = (const BaseArray *) ((char *) this + SWAPW(baseArrayOffset));
+    le_uint16 baseCount = SWAPW(baseArray->baseRecordCount);
+
+    if (baseCoverage < 0 || baseCoverage >= baseCount) {
+        // The base glyph isn't covered, or the coverage
+        // index is too big. The latter means that the
+        // table is mal-formed...
+        return 0;
+    }
+
+    const BaseRecord *baseRecord = &baseArray->baseRecordArray[baseCoverage * mcCount];
+    Offset anchorTableOffset = SWAPW(baseRecord->baseAnchorTableOffsetArray[markClass]);
+    const AnchorTable *anchorTable = (const AnchorTable *) ((char *) baseArray + anchorTableOffset);
+    LEPoint baseAnchor, markAdvance, pixels;
+
+    if (anchorTableOffset == 0) {
+        // this means the table is mal-formed...
+        glyphIterator->setCurrGlyphBaseOffset(baseIterator.getCurrStreamPosition());
+        return 0;
+    }
+
+    anchorTable->getAnchor(baseGlyph, fontInstance, baseAnchor);
+
+    fontInstance->getGlyphAdvance(markGlyph, pixels);
+    fontInstance->pixelsToUnits(pixels, markAdvance);
+
+    float anchorDiffX = baseAnchor.fX - markAnchor.fX;
+    float anchorDiffY = baseAnchor.fY - markAnchor.fY;
+
+    glyphIterator->setCurrGlyphBaseOffset(baseIterator.getCurrStreamPosition());
+
+    if (glyphIterator->isRightToLeft()) {
+        // FIXME: need similar patch to below; also in MarkToLigature and MarkToMark
+        // (is there a better way to approach this for all the cases?)
+        glyphIterator->setCurrGlyphPositionAdjustment(anchorDiffX, anchorDiffY, -markAdvance.fX, -markAdvance.fY);
+    } else {
+        LEPoint baseAdvance;
+
+        fontInstance->getGlyphAdvance(baseGlyph, pixels);
+        
+        //JK: adjustment needs to account for non-zero advance of any marks between base glyph and current mark
+        GlyphIterator gi(baseIterator, (le_uint16)0); // copy of baseIterator that won't ignore marks
+        gi.next(); // point beyond the base glyph
+        while (gi.getCurrStreamPosition() < glyphIterator->getCurrStreamPosition()) { // for all intervening glyphs (marks)...
+            LEGlyphID otherMark = gi.getCurrGlyphID();
+            LEPoint px;
+            fontInstance->getGlyphAdvance(otherMark, px); // get advance, in case it's non-zero
+            pixels.fX += px.fX; // and add that to the base glyph's advance
+            pixels.fY += px.fY;
+            gi.next();
+        }
+        // end of JK patch
+   
+        fontInstance->pixelsToUnits(pixels, baseAdvance);
+
+        glyphIterator->setCurrGlyphPositionAdjustment(anchorDiffX - baseAdvance.fX, anchorDiffY - baseAdvance.fY, -markAdvance.fX, -markAdvance.fY);
+    }
+
+    return 1;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/MarkToBasePosnSubtables.h b/source/layout/MarkToBasePosnSubtables.h
new file mode 100644
index 0000000..aa7a0a1
--- /dev/null
+++ b/source/layout/MarkToBasePosnSubtables.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __MARKTOBASEPOSITIONINGSUBTABLES_H
+#define __MARKTOBASEPOSITIONINGSUBTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "GlyphPositioningTables.h"
+#include "AttachmentPosnSubtables.h"
+#include "GlyphIterator.h"
+
+U_NAMESPACE_BEGIN
+
+struct MarkToBasePositioningSubtable : AttachmentPositioningSubtable
+{
+    le_int32   process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const;
+    LEGlyphID  findBaseGlyph(GlyphIterator *glyphIterator) const;
+};
+
+struct BaseRecord
+{
+    Offset baseAnchorTableOffsetArray[ANY_NUMBER];
+};
+
+struct BaseArray
+{
+    le_int16 baseRecordCount;
+    BaseRecord baseRecordArray[ANY_NUMBER];
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/MarkToLigaturePosnSubtables.cpp b/source/layout/MarkToLigaturePosnSubtables.cpp
new file mode 100644
index 0000000..e247e4e
--- /dev/null
+++ b/source/layout/MarkToLigaturePosnSubtables.cpp
@@ -0,0 +1,103 @@
+/*
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "AnchorTables.h"
+#include "MarkArrays.h"
+#include "GlyphPositioningTables.h"
+#include "AttachmentPosnSubtables.h"
+#include "MarkToLigaturePosnSubtables.h"
+#include "GlyphIterator.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+LEGlyphID MarkToLigaturePositioningSubtable::findLigatureGlyph(GlyphIterator *glyphIterator) const
+{
+    if (glyphIterator->prev()) {
+        return glyphIterator->getCurrGlyphID();
+    }
+
+    return 0xFFFF;
+}
+
+le_int32 MarkToLigaturePositioningSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const
+{
+    LEGlyphID markGlyph = glyphIterator->getCurrGlyphID();
+    le_int32 markCoverage = getGlyphCoverage((LEGlyphID) markGlyph);
+
+    if (markCoverage < 0) {
+        // markGlyph isn't a covered mark glyph
+        return 0;
+    }
+
+    LEPoint markAnchor;
+    const MarkArray *markArray = (const MarkArray *) ((char *) this + SWAPW(markArrayOffset));
+    le_int32 markClass = markArray->getMarkClass(markGlyph, markCoverage, fontInstance, markAnchor);
+    le_uint16 mcCount = SWAPW(classCount);
+
+    if (markClass < 0 || markClass >= mcCount) {
+        // markGlyph isn't in the mark array or its
+        // mark class is too big. The table is mal-formed!
+        return 0;
+    }
+
+    // FIXME: we probably don't want to find a ligature before a previous base glyph...
+    GlyphIterator ligatureIterator(*glyphIterator, (le_uint16) (lfIgnoreMarks /*| lfIgnoreBaseGlyphs*/));
+    LEGlyphID ligatureGlyph = findLigatureGlyph(&ligatureIterator);
+    le_int32 ligatureCoverage = getBaseCoverage((LEGlyphID) ligatureGlyph);
+    const LigatureArray *ligatureArray = (const LigatureArray *) ((char *) this + SWAPW(baseArrayOffset));
+    le_uint16 ligatureCount = SWAPW(ligatureArray->ligatureCount);
+
+    if (ligatureCoverage < 0 || ligatureCoverage >= ligatureCount) {
+        // The ligature glyph isn't covered, or the coverage
+        // index is too big. The latter means that the
+        // table is mal-formed...
+        return 0;
+    }
+
+    le_int32 markPosition = glyphIterator->getCurrStreamPosition();
+    Offset ligatureAttachOffset = SWAPW(ligatureArray->ligatureAttachTableOffsetArray[ligatureCoverage]);
+    const LigatureAttachTable *ligatureAttachTable = (const LigatureAttachTable *) ((char *) ligatureArray + ligatureAttachOffset);
+    le_int32 componentCount = SWAPW(ligatureAttachTable->componentCount);
+    le_int32 component = ligatureIterator.getMarkComponent(markPosition);
+
+    if (component >= componentCount) {
+        // should really just bail at this point...
+        component = componentCount - 1;
+    }
+
+    const ComponentRecord *componentRecord = &ligatureAttachTable->componentRecordArray[component * mcCount];
+    Offset anchorTableOffset = SWAPW(componentRecord->ligatureAnchorTableOffsetArray[markClass]);
+    const AnchorTable *anchorTable = (const AnchorTable *) ((char *) ligatureAttachTable + anchorTableOffset);
+    LEPoint ligatureAnchor, markAdvance, pixels;
+
+    anchorTable->getAnchor(ligatureGlyph, fontInstance, ligatureAnchor);
+
+    fontInstance->getGlyphAdvance(markGlyph, pixels);
+    fontInstance->pixelsToUnits(pixels, markAdvance);
+
+    float anchorDiffX = ligatureAnchor.fX - markAnchor.fX;
+    float anchorDiffY = ligatureAnchor.fY - markAnchor.fY;
+
+    glyphIterator->setCurrGlyphBaseOffset(ligatureIterator.getCurrStreamPosition());
+
+    if (glyphIterator->isRightToLeft()) {
+        glyphIterator->setCurrGlyphPositionAdjustment(anchorDiffX, anchorDiffY, -markAdvance.fX, -markAdvance.fY);
+    } else {
+        LEPoint ligatureAdvance;
+
+        fontInstance->getGlyphAdvance(ligatureGlyph, pixels);
+        fontInstance->pixelsToUnits(pixels, ligatureAdvance);
+
+        glyphIterator->setCurrGlyphPositionAdjustment(anchorDiffX - ligatureAdvance.fX, anchorDiffY - ligatureAdvance.fY, -markAdvance.fX, -markAdvance.fY);
+    }
+
+    return 1;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/MarkToLigaturePosnSubtables.h b/source/layout/MarkToLigaturePosnSubtables.h
new file mode 100644
index 0000000..b8e34d1
--- /dev/null
+++ b/source/layout/MarkToLigaturePosnSubtables.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __MARKTOLIGATUREPOSITIONINGSUBTABLES_H
+#define __MARKTOLIGATUREPOSITIONINGSUBTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "GlyphPositioningTables.h"
+#include "AttachmentPosnSubtables.h"
+#include "GlyphIterator.h"
+
+U_NAMESPACE_BEGIN
+
+struct MarkToLigaturePositioningSubtable : AttachmentPositioningSubtable
+{
+    le_int32   process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const;
+    LEGlyphID  findLigatureGlyph(GlyphIterator *glyphIterator) const;
+};
+
+struct ComponentRecord
+{
+    Offset ligatureAnchorTableOffsetArray[ANY_NUMBER];
+};
+
+struct LigatureAttachTable
+{
+    le_uint16 componentCount;
+    ComponentRecord componentRecordArray[ANY_NUMBER];
+};
+
+struct LigatureArray
+{
+    le_uint16 ligatureCount;
+    Offset ligatureAttachTableOffsetArray[ANY_NUMBER];
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/MarkToMarkPosnSubtables.cpp b/source/layout/MarkToMarkPosnSubtables.cpp
new file mode 100644
index 0000000..3f571f5
--- /dev/null
+++ b/source/layout/MarkToMarkPosnSubtables.cpp
@@ -0,0 +1,97 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "AnchorTables.h"
+#include "MarkArrays.h"
+#include "GlyphPositioningTables.h"
+#include "AttachmentPosnSubtables.h"
+#include "MarkToMarkPosnSubtables.h"
+#include "GlyphIterator.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+LEGlyphID MarkToMarkPositioningSubtable::findMark2Glyph(GlyphIterator *glyphIterator) const
+{
+    if (glyphIterator->findMark2Glyph()) {
+        return glyphIterator->getCurrGlyphID();
+    }
+
+    return 0xFFFF;
+}
+
+le_int32 MarkToMarkPositioningSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const
+{
+    LEGlyphID markGlyph = glyphIterator->getCurrGlyphID();
+    le_int32 markCoverage = getGlyphCoverage((LEGlyphID) markGlyph);
+
+    if (markCoverage < 0) {
+        // markGlyph isn't a covered mark glyph
+        return 0;
+    }
+
+    LEPoint markAnchor;
+    const MarkArray *markArray = (const MarkArray *) ((char *) this + SWAPW(markArrayOffset));
+    le_int32 markClass = markArray->getMarkClass(markGlyph, markCoverage, fontInstance, markAnchor);
+    le_uint16 mcCount = SWAPW(classCount);
+
+    if (markClass < 0 || markClass >= mcCount) {
+        // markGlyph isn't in the mark array or its
+        // mark class is too big. The table is mal-formed!
+        return 0;
+    }
+
+    GlyphIterator mark2Iterator(*glyphIterator);
+    LEGlyphID mark2Glyph = findMark2Glyph(&mark2Iterator);
+    le_int32 mark2Coverage = getBaseCoverage((LEGlyphID) mark2Glyph);
+    const Mark2Array *mark2Array = (const Mark2Array *) ((char *) this + SWAPW(baseArrayOffset));
+    le_uint16 mark2Count = SWAPW(mark2Array->mark2RecordCount);
+
+    if (mark2Coverage < 0 || mark2Coverage >= mark2Count) {
+        // The mark2 glyph isn't covered, or the coverage
+        // index is too big. The latter means that the
+        // table is mal-formed...
+        return 0;
+    }
+
+    const Mark2Record *mark2Record = &mark2Array->mark2RecordArray[mark2Coverage * mcCount];
+    Offset anchorTableOffset = SWAPW(mark2Record->mark2AnchorTableOffsetArray[markClass]);
+    const AnchorTable *anchorTable = (const AnchorTable *) ((char *) mark2Array + anchorTableOffset);
+    LEPoint mark2Anchor, markAdvance, pixels;
+
+    if (anchorTableOffset == 0) {
+        // this seems to mean that the marks don't attach...
+        return 0;
+    }
+
+    anchorTable->getAnchor(mark2Glyph, fontInstance, mark2Anchor);
+
+    fontInstance->getGlyphAdvance(markGlyph, pixels);
+    fontInstance->pixelsToUnits(pixels, markAdvance);
+
+    float anchorDiffX = mark2Anchor.fX - markAnchor.fX;
+    float anchorDiffY = mark2Anchor.fY - markAnchor.fY;
+
+    glyphIterator->setCurrGlyphBaseOffset(mark2Iterator.getCurrStreamPosition());
+
+    if (glyphIterator->isRightToLeft()) {
+        glyphIterator->setCurrGlyphPositionAdjustment(anchorDiffX, anchorDiffY, -markAdvance.fX, -markAdvance.fY);
+    } else {
+        LEPoint mark2Advance;
+
+        fontInstance->getGlyphAdvance(mark2Glyph, pixels);
+        fontInstance->pixelsToUnits(pixels, mark2Advance);
+
+        glyphIterator->setCurrGlyphPositionAdjustment(anchorDiffX - mark2Advance.fX, anchorDiffY - mark2Advance.fY, -markAdvance.fX, -markAdvance.fY);
+    }
+
+    return 1;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/MarkToMarkPosnSubtables.h b/source/layout/MarkToMarkPosnSubtables.h
new file mode 100644
index 0000000..746ace2
--- /dev/null
+++ b/source/layout/MarkToMarkPosnSubtables.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __MARKTOMARKPOSITIONINGSUBTABLES_H
+#define __MARKTOMARKPOSITIONINGSUBTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "GlyphPositioningTables.h"
+#include "AttachmentPosnSubtables.h"
+#include "GlyphIterator.h"
+
+U_NAMESPACE_BEGIN
+
+struct MarkToMarkPositioningSubtable : AttachmentPositioningSubtable
+{
+    le_int32   process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const;
+    LEGlyphID  findMark2Glyph(GlyphIterator *glyphIterator) const;
+};
+
+struct Mark2Record
+{
+    Offset mark2AnchorTableOffsetArray[ANY_NUMBER];
+};
+
+struct Mark2Array
+{
+    le_uint16 mark2RecordCount;
+    Mark2Record mark2RecordArray[ANY_NUMBER];
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/MirroredCharData.cpp b/source/layout/MirroredCharData.cpp
new file mode 100644
index 0000000..b813371
--- /dev/null
+++ b/source/layout/MirroredCharData.cpp
@@ -0,0 +1,108 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2005. All Rights Reserved.
+ *
+ * WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT UNLESS
+ * YOU REALLY KNOW WHAT YOU'RE DOING.
+ *
+ * Generated on: 07/20/2005 10:43:59 AM PDT
+ */
+
+#include "LETypes.h"
+#include "DefaultCharMapper.h"
+
+U_NAMESPACE_BEGIN
+
+const LEUnicode32 DefaultCharMapper::mirroredChars[] = {
+    0x0028, 0x0029, 0x003C, 0x003E, 0x005B, 0x005D, 0x007B, 0x007D, 
+    0x00AB, 0x00BB, 0x2039, 0x203A, 0x2045, 0x2046, 0x207D, 0x207E, 
+    0x208D, 0x208E, 0x2208, 0x2209, 0x220A, 0x220B, 0x220C, 0x220D, 
+    0x2215, 0x223C, 0x223D, 0x2243, 0x2252, 0x2253, 0x2254, 0x2255, 
+    0x2264, 0x2265, 0x2266, 0x2267, 0x2268, 0x2269, 0x226A, 0x226B, 
+    0x226E, 0x226F, 0x2270, 0x2271, 0x2272, 0x2273, 0x2274, 0x2275, 
+    0x2276, 0x2277, 0x2278, 0x2279, 0x227A, 0x227B, 0x227C, 0x227D, 
+    0x227E, 0x227F, 0x2280, 0x2281, 0x2282, 0x2283, 0x2284, 0x2285, 
+    0x2286, 0x2287, 0x2288, 0x2289, 0x228A, 0x228B, 0x228F, 0x2290, 
+    0x2291, 0x2292, 0x2298, 0x22A2, 0x22A3, 0x22A6, 0x22A8, 0x22A9, 
+    0x22AB, 0x22B0, 0x22B1, 0x22B2, 0x22B3, 0x22B4, 0x22B5, 0x22B6, 
+    0x22B7, 0x22C9, 0x22CA, 0x22CB, 0x22CC, 0x22CD, 0x22D0, 0x22D1, 
+    0x22D6, 0x22D7, 0x22D8, 0x22D9, 0x22DA, 0x22DB, 0x22DC, 0x22DD, 
+    0x22DE, 0x22DF, 0x22E0, 0x22E1, 0x22E2, 0x22E3, 0x22E4, 0x22E5, 
+    0x22E6, 0x22E7, 0x22E8, 0x22E9, 0x22EA, 0x22EB, 0x22EC, 0x22ED, 
+    0x22F0, 0x22F1, 0x22F2, 0x22F3, 0x22F4, 0x22F6, 0x22F7, 0x22FA, 
+    0x22FB, 0x22FC, 0x22FD, 0x22FE, 0x2308, 0x2309, 0x230A, 0x230B, 
+    0x2329, 0x232A, 0x2768, 0x2769, 0x276A, 0x276B, 0x276C, 0x276D, 
+    0x276E, 0x276F, 0x2770, 0x2771, 0x2772, 0x2773, 0x2774, 0x2775, 
+    0x27C3, 0x27C4, 0x27C5, 0x27C6, 0x27D5, 0x27D6, 0x27DD, 0x27DE, 
+    0x27E2, 0x27E3, 0x27E4, 0x27E5, 0x27E6, 0x27E7, 0x27E8, 0x27E9, 
+    0x27EA, 0x27EB, 0x2983, 0x2984, 0x2985, 0x2986, 0x2987, 0x2988, 
+    0x2989, 0x298A, 0x298B, 0x298C, 0x298D, 0x298E, 0x298F, 0x2990, 
+    0x2991, 0x2992, 0x2993, 0x2994, 0x2995, 0x2996, 0x2997, 0x2998, 
+    0x29B8, 0x29C0, 0x29C1, 0x29C4, 0x29C5, 0x29CF, 0x29D0, 0x29D1, 
+    0x29D2, 0x29D4, 0x29D5, 0x29D8, 0x29D9, 0x29DA, 0x29DB, 0x29F5, 
+    0x29F8, 0x29F9, 0x29FC, 0x29FD, 0x2A2B, 0x2A2C, 0x2A2D, 0x2A2E, 
+    0x2A34, 0x2A35, 0x2A3C, 0x2A3D, 0x2A64, 0x2A65, 0x2A79, 0x2A7A, 
+    0x2A7D, 0x2A7E, 0x2A7F, 0x2A80, 0x2A81, 0x2A82, 0x2A83, 0x2A84, 
+    0x2A8B, 0x2A8C, 0x2A91, 0x2A92, 0x2A93, 0x2A94, 0x2A95, 0x2A96, 
+    0x2A97, 0x2A98, 0x2A99, 0x2A9A, 0x2A9B, 0x2A9C, 0x2AA1, 0x2AA2, 
+    0x2AA6, 0x2AA7, 0x2AA8, 0x2AA9, 0x2AAA, 0x2AAB, 0x2AAC, 0x2AAD, 
+    0x2AAF, 0x2AB0, 0x2AB3, 0x2AB4, 0x2ABB, 0x2ABC, 0x2ABD, 0x2ABE, 
+    0x2ABF, 0x2AC0, 0x2AC1, 0x2AC2, 0x2AC3, 0x2AC4, 0x2AC5, 0x2AC6, 
+    0x2ACD, 0x2ACE, 0x2ACF, 0x2AD0, 0x2AD1, 0x2AD2, 0x2AD3, 0x2AD4, 
+    0x2AD5, 0x2AD6, 0x2ADE, 0x2AE3, 0x2AE4, 0x2AE5, 0x2AEC, 0x2AED, 
+    0x2AF7, 0x2AF8, 0x2AF9, 0x2AFA, 0x2E02, 0x2E03, 0x2E04, 0x2E05, 
+    0x2E09, 0x2E0A, 0x2E0C, 0x2E0D, 0x2E1C, 0x2E1D, 0x3008, 0x3009, 
+    0x300A, 0x300B, 0x300C, 0x300D, 0x300E, 0x300F, 0x3010, 0x3011, 
+    0x3014, 0x3015, 0x3016, 0x3017, 0x3018, 0x3019, 0x301A, 0x301B, 
+    0xFF08, 0xFF09, 0xFF1C, 0xFF1E, 0xFF3B, 0xFF3D, 0xFF5B, 0xFF5D, 
+    0xFF5F, 0xFF60, 0xFF62, 0xFF63
+};
+
+const LEUnicode32 DefaultCharMapper::srahCderorrim[] = {
+    0x0029, 0x0028, 0x003E, 0x003C, 0x005D, 0x005B, 0x007D, 0x007B, 
+    0x00BB, 0x00AB, 0x203A, 0x2039, 0x2046, 0x2045, 0x207E, 0x207D, 
+    0x208E, 0x208D, 0x220B, 0x220C, 0x220D, 0x2208, 0x2209, 0x220A, 
+    0x29F5, 0x223D, 0x223C, 0x22CD, 0x2253, 0x2252, 0x2255, 0x2254, 
+    0x2265, 0x2264, 0x2267, 0x2266, 0x2269, 0x2268, 0x226B, 0x226A, 
+    0x226F, 0x226E, 0x2271, 0x2270, 0x2273, 0x2272, 0x2275, 0x2274, 
+    0x2277, 0x2276, 0x2279, 0x2278, 0x227B, 0x227A, 0x227D, 0x227C, 
+    0x227F, 0x227E, 0x2281, 0x2280, 0x2283, 0x2282, 0x2285, 0x2284, 
+    0x2287, 0x2286, 0x2289, 0x2288, 0x228B, 0x228A, 0x2290, 0x228F, 
+    0x2292, 0x2291, 0x29B8, 0x22A3, 0x22A2, 0x2ADE, 0x2AE4, 0x2AE3, 
+    0x2AE5, 0x22B1, 0x22B0, 0x22B3, 0x22B2, 0x22B5, 0x22B4, 0x22B7, 
+    0x22B6, 0x22CA, 0x22C9, 0x22CC, 0x22CB, 0x2243, 0x22D1, 0x22D0, 
+    0x22D7, 0x22D6, 0x22D9, 0x22D8, 0x22DB, 0x22DA, 0x22DD, 0x22DC, 
+    0x22DF, 0x22DE, 0x22E1, 0x22E0, 0x22E3, 0x22E2, 0x22E5, 0x22E4, 
+    0x22E7, 0x22E6, 0x22E9, 0x22E8, 0x22EB, 0x22EA, 0x22ED, 0x22EC, 
+    0x22F1, 0x22F0, 0x22FA, 0x22FB, 0x22FC, 0x22FD, 0x22FE, 0x22F2, 
+    0x22F3, 0x22F4, 0x22F6, 0x22F7, 0x2309, 0x2308, 0x230B, 0x230A, 
+    0x232A, 0x2329, 0x2769, 0x2768, 0x276B, 0x276A, 0x276D, 0x276C, 
+    0x276F, 0x276E, 0x2771, 0x2770, 0x2773, 0x2772, 0x2775, 0x2774, 
+    0x27C4, 0x27C3, 0x27C6, 0x27C5, 0x27D6, 0x27D5, 0x27DE, 0x27DD, 
+    0x27E3, 0x27E2, 0x27E5, 0x27E4, 0x27E7, 0x27E6, 0x27E9, 0x27E8, 
+    0x27EB, 0x27EA, 0x2984, 0x2983, 0x2986, 0x2985, 0x2988, 0x2987, 
+    0x298A, 0x2989, 0x298C, 0x298B, 0x2990, 0x298F, 0x298E, 0x298D, 
+    0x2992, 0x2991, 0x2994, 0x2993, 0x2996, 0x2995, 0x2998, 0x2997, 
+    0x2298, 0x29C1, 0x29C0, 0x29C5, 0x29C4, 0x29D0, 0x29CF, 0x29D2, 
+    0x29D1, 0x29D5, 0x29D4, 0x29D9, 0x29D8, 0x29DB, 0x29DA, 0x2215, 
+    0x29F9, 0x29F8, 0x29FD, 0x29FC, 0x2A2C, 0x2A2B, 0x2A2E, 0x2A2D, 
+    0x2A35, 0x2A34, 0x2A3D, 0x2A3C, 0x2A65, 0x2A64, 0x2A7A, 0x2A79, 
+    0x2A7E, 0x2A7D, 0x2A80, 0x2A7F, 0x2A82, 0x2A81, 0x2A84, 0x2A83, 
+    0x2A8C, 0x2A8B, 0x2A92, 0x2A91, 0x2A94, 0x2A93, 0x2A96, 0x2A95, 
+    0x2A98, 0x2A97, 0x2A9A, 0x2A99, 0x2A9C, 0x2A9B, 0x2AA2, 0x2AA1, 
+    0x2AA7, 0x2AA6, 0x2AA9, 0x2AA8, 0x2AAB, 0x2AAA, 0x2AAD, 0x2AAC, 
+    0x2AB0, 0x2AAF, 0x2AB4, 0x2AB3, 0x2ABC, 0x2ABB, 0x2ABE, 0x2ABD, 
+    0x2AC0, 0x2ABF, 0x2AC2, 0x2AC1, 0x2AC4, 0x2AC3, 0x2AC6, 0x2AC5, 
+    0x2ACE, 0x2ACD, 0x2AD0, 0x2ACF, 0x2AD2, 0x2AD1, 0x2AD4, 0x2AD3, 
+    0x2AD6, 0x2AD5, 0x22A6, 0x22A9, 0x22A8, 0x22AB, 0x2AED, 0x2AEC, 
+    0x2AF8, 0x2AF7, 0x2AFA, 0x2AF9, 0x2E03, 0x2E02, 0x2E05, 0x2E04, 
+    0x2E0A, 0x2E09, 0x2E0D, 0x2E0C, 0x2E1D, 0x2E1C, 0x3009, 0x3008, 
+    0x300B, 0x300A, 0x300D, 0x300C, 0x300F, 0x300E, 0x3011, 0x3010, 
+    0x3015, 0x3014, 0x3017, 0x3016, 0x3019, 0x3018, 0x301B, 0x301A, 
+    0xFF09, 0xFF08, 0xFF1E, 0xFF1C, 0xFF3D, 0xFF3B, 0xFF5D, 0xFF5B, 
+    0xFF60, 0xFF5F, 0xFF63, 0xFF62
+};
+
+const le_int32 DefaultCharMapper::mirroredCharsCount = 332;
+
+U_NAMESPACE_END
diff --git a/source/layout/MorphStateTables.h b/source/layout/MorphStateTables.h
new file mode 100644
index 0000000..a2e0b00
--- /dev/null
+++ b/source/layout/MorphStateTables.h
@@ -0,0 +1,28 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __MORPHSTATETABLES_H
+#define __MORPHSTATETABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LayoutTables.h"
+#include "MorphTables.h"
+#include "StateTables.h"
+
+U_NAMESPACE_BEGIN
+
+struct MorphStateTableHeader : MorphSubtableHeader
+{
+    StateTableHeader stHeader;
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/MorphTables.cpp b/source/layout/MorphTables.cpp
new file mode 100644
index 0000000..9272cc3
--- /dev/null
+++ b/source/layout/MorphTables.cpp
@@ -0,0 +1,96 @@
+/*
+ * %W% %W%
+ *
+ * (C) Copyright IBM Corp. 1998 - 2004 - All Rights Reserved
+ *
+ */
+
+
+#include "LETypes.h"
+#include "LayoutTables.h"
+#include "MorphTables.h"
+#include "SubtableProcessor.h"
+#include "IndicRearrangementProcessor.h"
+#include "ContextualGlyphSubstProc.h"
+#include "LigatureSubstProc.h"
+#include "NonContextualGlyphSubstProc.h"
+//#include "ContextualGlyphInsertionProcessor.h"
+#include "LEGlyphStorage.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+void MorphTableHeader::process(LEGlyphStorage &glyphStorage) const
+{
+    const ChainHeader *chainHeader = chains;
+    le_uint32 chainCount = SWAPL(this->nChains);
+    le_uint32 chain;
+
+    for (chain = 0; chain < chainCount; chain += 1) {
+        FeatureFlags defaultFlags = SWAPL(chainHeader->defaultFlags);
+        le_uint32 chainLength = SWAPL(chainHeader->chainLength);
+        le_int16 nFeatureEntries = SWAPW(chainHeader->nFeatureEntries);
+        le_int16 nSubtables = SWAPW(chainHeader->nSubtables);
+        const MorphSubtableHeader *subtableHeader =
+            (const MorphSubtableHeader *)&chainHeader->featureTable[nFeatureEntries];
+        le_int16 subtable;
+
+        for (subtable = 0; subtable < nSubtables; subtable += 1) {
+            le_int16 length = SWAPW(subtableHeader->length);
+            SubtableCoverage coverage = SWAPW(subtableHeader->coverage);
+            FeatureFlags subtableFeatures = SWAPL(subtableHeader->subtableFeatures);
+
+            // should check coverage more carefully...
+            if ((coverage & scfVertical) == 0 && (subtableFeatures & defaultFlags) != 0) {
+                subtableHeader->process(glyphStorage);
+            }
+
+            subtableHeader = (const MorphSubtableHeader *) ((char *)subtableHeader + length);
+        }
+
+        chainHeader = (const ChainHeader *)((char *)chainHeader + chainLength);
+    }
+}
+
+void MorphSubtableHeader::process(LEGlyphStorage &glyphStorage) const
+{
+    SubtableProcessor *processor = NULL;
+
+    switch (SWAPW(coverage) & scfTypeMask)
+    {
+    case mstIndicRearrangement:
+        processor = new IndicRearrangementProcessor(this);
+        break;
+
+    case mstContextualGlyphSubstitution:
+        processor = new ContextualGlyphSubstitutionProcessor(this);
+        break;
+
+    case mstLigatureSubstitution:
+        processor = new LigatureSubstitutionProcessor(this);
+        break;
+
+    case mstReservedUnused:
+        break;
+
+    case mstNonContextualGlyphSubstitution:
+        processor = NonContextualGlyphSubstitutionProcessor::createInstance(this);
+        break;
+
+    /*
+    case mstContextualGlyphInsertion:
+        processor = new ContextualGlyphInsertionProcessor(this);
+        break;
+    */
+
+    default:
+        break;
+    }
+
+    if (processor != NULL) {
+        processor->process(glyphStorage);
+        delete processor;
+    }
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/MorphTables.h b/source/layout/MorphTables.h
new file mode 100644
index 0000000..8d198cf
--- /dev/null
+++ b/source/layout/MorphTables.h
@@ -0,0 +1,85 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __MORPHTABLES_H
+#define __MORPHTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LayoutTables.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+typedef le_uint32 FeatureFlags;
+
+typedef le_int16 FeatureType;
+typedef le_int16 FeatureSetting;
+
+struct FeatureTableEntry
+{
+    FeatureType     featureType;
+    FeatureSetting  featureSetting;
+    FeatureFlags    enableFlags;
+    FeatureFlags    disableFlags;
+};
+
+struct ChainHeader
+{
+    FeatureFlags        defaultFlags;
+    le_uint32           chainLength;
+    le_int16           nFeatureEntries;
+    le_int16           nSubtables;
+    FeatureTableEntry   featureTable[ANY_NUMBER];
+};
+
+struct MorphTableHeader
+{
+    le_int32    version;
+    le_uint32   nChains;
+    ChainHeader chains[ANY_NUMBER];
+
+    void process(LEGlyphStorage &glyphStorage) const;
+};
+
+typedef le_int16 SubtableCoverage;
+
+enum SubtableCoverageFlags
+{
+    scfVertical = 0x8000,
+    scfReverse  = 0x4000,
+    scfIgnoreVt = 0x2000,
+    scfReserved = 0x1FF8,
+    scfTypeMask = 0x0007
+};
+
+enum MorphSubtableType
+{
+    mstIndicRearrangement               = 0,
+    mstContextualGlyphSubstitution      = 1,
+    mstLigatureSubstitution             = 2,
+    mstReservedUnused                   = 3,
+    mstNonContextualGlyphSubstitution   = 4,
+    mstContextualGlyphInsertion         = 5
+};
+
+struct MorphSubtableHeader
+{
+    le_int16           length;
+    SubtableCoverage    coverage;
+    FeatureFlags        subtableFeatures;
+
+    void process(LEGlyphStorage &glyphStorage) const;
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/MultipleSubstSubtables.cpp b/source/layout/MultipleSubstSubtables.cpp
new file mode 100644
index 0000000..f017722
--- /dev/null
+++ b/source/layout/MultipleSubstSubtables.cpp
@@ -0,0 +1,95 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEGlyphFilter.h"
+#include "OpenTypeTables.h"
+#include "GlyphSubstitutionTables.h"
+#include "MultipleSubstSubtables.h"
+#include "GlyphIterator.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+le_uint32 MultipleSubstitutionSubtable::process(GlyphIterator *glyphIterator, LEErrorCode& success, const LEGlyphFilter *filter) const
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
+
+    // If there's a filter, we only want to do the
+    // substitution if the *input* glyphs doesn't
+    // exist.
+    //
+    // FIXME: is this always the right thing to do?
+    // FIXME: should this only be done for a non-zero
+    //        glyphCount?
+    if (filter != NULL && filter->accept(glyph)) {
+        return 0;
+    }
+
+    le_int32 coverageIndex = getGlyphCoverage(glyph);
+    le_uint16 seqCount = SWAPW(sequenceCount);
+
+    if (coverageIndex >= 0 && coverageIndex < seqCount) {
+        Offset sequenceTableOffset = SWAPW(sequenceTableOffsetArray[coverageIndex]);
+        const SequenceTable *sequenceTable = (const SequenceTable *) ((char *) this + sequenceTableOffset);
+        le_uint16 glyphCount = SWAPW(sequenceTable->glyphCount);
+
+        if (glyphCount == 0) {
+            glyphIterator->setCurrGlyphID(0xFFFF);
+            return 1;
+        } else if (glyphCount == 1) {
+            TTGlyphID substitute = SWAPW(sequenceTable->substituteArray[0]);
+
+            if (filter != NULL && ! filter->accept(LE_SET_GLYPH(glyph, substitute))) {
+                return 0;
+            }
+
+            glyphIterator->setCurrGlyphID(substitute);
+            return 1;
+        } else {
+            // If there's a filter, make sure all of the output glyphs
+            // exist.
+            if (filter != NULL) {
+                for (le_int32 i = 0; i < glyphCount; i += 1) {
+                    TTGlyphID substitute = SWAPW(sequenceTable->substituteArray[i]);
+
+                    if (! filter->accept(substitute)) {
+                        return 0;
+                    }
+                }
+            }
+
+            LEGlyphID *newGlyphs = glyphIterator->insertGlyphs(glyphCount, success);
+            if (LE_FAILURE(success)) { 
+                return 0;
+            }
+
+            le_int32 insert = 0, direction = 1;
+
+            if (glyphIterator->isRightToLeft()) {
+                insert = glyphCount - 1;
+                direction = -1;
+            }
+
+            for (le_int32 i = 0; i < glyphCount; i += 1) {
+                TTGlyphID substitute = SWAPW(sequenceTable->substituteArray[i]);
+
+                newGlyphs[insert] = LE_SET_GLYPH(glyph, substitute);
+                insert += direction;
+            }
+
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/MultipleSubstSubtables.h b/source/layout/MultipleSubstSubtables.h
new file mode 100644
index 0000000..1d6c978
--- /dev/null
+++ b/source/layout/MultipleSubstSubtables.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#ifndef __MULTIPLESUBSTITUTIONSUBTABLES_H
+#define __MULTIPLESUBSTITUTIONSUBTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEGlyphFilter.h"
+#include "OpenTypeTables.h"
+#include "GlyphSubstitutionTables.h"
+#include "GlyphIterator.h"
+
+U_NAMESPACE_BEGIN
+
+struct SequenceTable
+{
+    le_uint16 glyphCount;
+    TTGlyphID substituteArray[ANY_NUMBER];
+};
+
+struct MultipleSubstitutionSubtable : GlyphSubstitutionSubtable
+{
+    le_uint16 sequenceCount;
+    Offset    sequenceTableOffsetArray[ANY_NUMBER];
+
+    le_uint32 process(GlyphIterator *glyphIterator, LEErrorCode& success, const LEGlyphFilter *filter = NULL) const;
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/NonContextualGlyphSubst.h b/source/layout/NonContextualGlyphSubst.h
new file mode 100644
index 0000000..ef2543a
--- /dev/null
+++ b/source/layout/NonContextualGlyphSubst.h
@@ -0,0 +1,30 @@
+/*
+ * %W% %E%
+ *
+ * (C) Copyright IBM Corp. 1998-2003 - All Rights Reserved
+ *
+ */
+
+#ifndef __NONCONTEXTUALGLYPHSUBSTITUTION_H
+#define __NONCONTEXTUALGLYPHSUBSTITUTION_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LayoutTables.h"
+#include "LookupTables.h"
+#include "MorphTables.h"
+
+U_NAMESPACE_BEGIN
+
+struct NonContextualGlyphSubstitutionHeader : MorphSubtableHeader
+{
+    LookupTable table;
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/NonContextualGlyphSubstProc.cpp b/source/layout/NonContextualGlyphSubstProc.cpp
new file mode 100644
index 0000000..69c065b
--- /dev/null
+++ b/source/layout/NonContextualGlyphSubstProc.cpp
@@ -0,0 +1,60 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "SubtableProcessor.h"
+#include "NonContextualGlyphSubst.h"
+#include "NonContextualGlyphSubstProc.h"
+#include "SimpleArrayProcessor.h"
+#include "SegmentSingleProcessor.h"
+#include "SegmentArrayProcessor.h"
+#include "SingleTableProcessor.h"
+#include "TrimmedArrayProcessor.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+NonContextualGlyphSubstitutionProcessor::NonContextualGlyphSubstitutionProcessor()
+{
+}
+
+NonContextualGlyphSubstitutionProcessor::NonContextualGlyphSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader)
+    : SubtableProcessor(morphSubtableHeader)
+{
+}
+
+NonContextualGlyphSubstitutionProcessor::~NonContextualGlyphSubstitutionProcessor()
+{
+}
+
+SubtableProcessor *NonContextualGlyphSubstitutionProcessor::createInstance(const MorphSubtableHeader *morphSubtableHeader)
+{
+    const NonContextualGlyphSubstitutionHeader *header = (const NonContextualGlyphSubstitutionHeader *) morphSubtableHeader;
+
+    switch (SWAPW(header->table.format))
+    {
+    case ltfSimpleArray:
+        return new SimpleArrayProcessor(morphSubtableHeader);
+
+    case ltfSegmentSingle:
+        return new SegmentSingleProcessor(morphSubtableHeader);
+
+    case ltfSegmentArray:
+        return new SegmentArrayProcessor(morphSubtableHeader);
+
+    case ltfSingleTable:
+        return new SingleTableProcessor(morphSubtableHeader);
+
+    case ltfTrimmedArray:
+        return new TrimmedArrayProcessor(morphSubtableHeader);
+
+    default:
+        return NULL;
+    }
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/NonContextualGlyphSubstProc.h b/source/layout/NonContextualGlyphSubstProc.h
new file mode 100644
index 0000000..4ce96cf
--- /dev/null
+++ b/source/layout/NonContextualGlyphSubstProc.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __NONCONTEXTUALGLYPHSUBSTITUTIONPROCESSOR_H
+#define __NONCONTEXTUALGLYPHSUBSTITUTIONPROCESSOR_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "SubtableProcessor.h"
+#include "NonContextualGlyphSubst.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+class NonContextualGlyphSubstitutionProcessor : public SubtableProcessor
+{
+public:
+    virtual void process(LEGlyphStorage &glyphStorage) = 0;
+
+    static SubtableProcessor *createInstance(const MorphSubtableHeader *morphSubtableHeader);
+
+protected:
+    NonContextualGlyphSubstitutionProcessor();
+    NonContextualGlyphSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader);
+
+    virtual ~NonContextualGlyphSubstitutionProcessor();
+
+private:
+    NonContextualGlyphSubstitutionProcessor(const NonContextualGlyphSubstitutionProcessor &other); // forbid copying of this class
+    NonContextualGlyphSubstitutionProcessor &operator=(const NonContextualGlyphSubstitutionProcessor &other); // forbid copying of this class
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/OpenTypeLayoutEngine.cpp b/source/layout/OpenTypeLayoutEngine.cpp
new file mode 100644
index 0000000..13479b4
--- /dev/null
+++ b/source/layout/OpenTypeLayoutEngine.cpp
@@ -0,0 +1,450 @@
+
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEScripts.h"
+#include "LELanguages.h"
+
+#include "LayoutEngine.h"
+#include "CanonShaping.h"
+#include "OpenTypeLayoutEngine.h"
+#include "ScriptAndLanguageTags.h"
+#include "CharSubstitutionFilter.h"
+
+#include "GlyphSubstitutionTables.h"
+#include "GlyphDefinitionTables.h"
+#include "GlyphPositioningTables.h"
+
+#include "LEGlyphStorage.h"
+#include "GlyphPositionAdjustments.h"
+
+#include "GDEFMarkFilter.h"
+
+#include "KernTable.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OpenTypeLayoutEngine)
+
+#define ccmpFeatureTag LE_CCMP_FEATURE_TAG
+#define ligaFeatureTag LE_LIGA_FEATURE_TAG
+#define cligFeatureTag LE_CLIG_FEATURE_TAG
+#define kernFeatureTag LE_KERN_FEATURE_TAG
+#define markFeatureTag LE_MARK_FEATURE_TAG
+#define mkmkFeatureTag LE_MKMK_FEATURE_TAG
+#define loclFeatureTag LE_LOCL_FEATURE_TAG
+#define caltFeatureTag LE_CALT_FEATURE_TAG
+
+// 'dlig' not used at the moment
+#define dligFeatureTag 0x646C6967
+
+// 'palt'
+#define paltFeatureTag 0x70616C74
+
+#define ccmpFeatureMask 0x80000000UL
+#define ligaFeatureMask 0x40000000UL
+#define cligFeatureMask 0x20000000UL
+#define kernFeatureMask 0x10000000UL
+#define paltFeatureMask 0x08000000UL
+#define markFeatureMask 0x04000000UL
+#define mkmkFeatureMask 0x02000000UL
+#define loclFeatureMask 0x01000000UL
+#define caltFeatureMask 0x00800000UL
+
+#define minimalFeatures     (ccmpFeatureMask | markFeatureMask | mkmkFeatureMask | loclFeatureMask | caltFeatureMask)
+#define ligaFeatures        (ligaFeatureMask | cligFeatureMask | minimalFeatures)
+#define kernFeatures        (kernFeatureMask | paltFeatureMask | minimalFeatures)
+#define kernAndLigaFeatures (ligaFeatures    | kernFeatures)
+ 
+static const FeatureMap featureMap[] =
+{
+    {ccmpFeatureTag, ccmpFeatureMask},
+    {ligaFeatureTag, ligaFeatureMask},
+    {cligFeatureTag, cligFeatureMask}, 
+    {kernFeatureTag, kernFeatureMask},
+    {paltFeatureTag, paltFeatureMask},
+    {markFeatureTag, markFeatureMask},
+    {mkmkFeatureTag, mkmkFeatureMask},
+    {loclFeatureTag, loclFeatureMask},
+    {caltFeatureTag, caltFeatureMask}
+};
+
+static const le_int32 featureMapCount = LE_ARRAY_SIZE(featureMap);
+
+OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+                        le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success)
+    : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fFeatureMask(minimalFeatures),
+      fFeatureMap(featureMap), fFeatureMapCount(featureMapCount), fFeatureOrder(FALSE),
+      fGSUBTable(gsubTable), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL)
+{
+    static const le_uint32 gdefTableTag = LE_GDEF_TABLE_TAG;
+    static const le_uint32 gposTableTag = LE_GPOS_TABLE_TAG;
+    const GlyphPositioningTableHeader *gposTable = (const GlyphPositioningTableHeader *) getFontTable(gposTableTag);
+
+    // todo: switch to more flags and bitfield rather than list of feature tags?
+    switch (typoFlags & ~0x80000000L) {
+    case 0: break; // default
+    case 1: fFeatureMask = kernFeatures; break;
+    case 2: fFeatureMask = ligaFeatures; break;
+    case 3: fFeatureMask = kernAndLigaFeatures; break;
+    default: break;
+    }
+
+    if (typoFlags & 0x80000000L) {
+        fSubstitutionFilter = new CharSubstitutionFilter(fontInstance);
+    }
+
+    setScriptAndLanguageTags();
+
+    fGDEFTable = (const GlyphDefinitionTableHeader *) getFontTable(gdefTableTag);
+    
+// JK patch, 2008-05-30 - see Sinhala bug report and LKLUG font
+//    if (gposTable != NULL && gposTable->coversScriptAndLanguage(fScriptTag, fLangSysTag)) {
+    if (gposTable != NULL && gposTable->coversScript(fScriptTag)) {
+        fGPOSTable = gposTable;
+    }
+}
+
+void OpenTypeLayoutEngine::reset()
+{
+    // NOTE: if we're called from
+    // the destructor, LayoutEngine;:reset()
+    // will have been called already by
+    // LayoutEngine::~LayoutEngine()
+    LayoutEngine::reset();
+}
+
+OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+                       le_int32 typoFlags, LEErrorCode &success)
+    : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fFeatureOrder(FALSE),
+      fGSUBTable(NULL), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL)
+{
+    setScriptAndLanguageTags();
+}
+
+OpenTypeLayoutEngine::~OpenTypeLayoutEngine()
+{
+    if (fTypoFlags & 0x80000000L) {
+        delete fSubstitutionFilter;
+    }
+
+    reset();
+}
+
+LETag OpenTypeLayoutEngine::getScriptTag(le_int32 scriptCode)
+{
+    if (scriptCode < 0 || scriptCode >= scriptCodeCount) {
+        return 0xFFFFFFFF;
+    }
+    return scriptTags[scriptCode];
+}
+
+LETag OpenTypeLayoutEngine::getV2ScriptTag(le_int32 scriptCode)
+{
+	switch (scriptCode) { 
+		case bengScriptCode :    return bng2ScriptTag;
+		case devaScriptCode :    return dev2ScriptTag;
+		case gujrScriptCode :    return gjr2ScriptTag;
+		case guruScriptCode :    return gur2ScriptTag;
+		case kndaScriptCode :    return knd2ScriptTag;
+		case mlymScriptCode :    return mlm2ScriptTag;
+		case oryaScriptCode :    return ory2ScriptTag;
+		case tamlScriptCode :    return tml2ScriptTag;
+		case teluScriptCode :    return tel2ScriptTag;
+		default:                 return nullScriptTag;
+	}
+}
+
+LETag OpenTypeLayoutEngine::getLangSysTag(le_int32 languageCode)
+{
+    if (languageCode < 0 || languageCode >= languageCodeCount) {
+        return 0xFFFFFFFF;
+    }
+
+    return languageTags[languageCode];
+}
+
+void OpenTypeLayoutEngine::setScriptAndLanguageTags()
+{
+    fScriptTag  = getScriptTag(fScriptCode);
+    fScriptTagV2 = getV2ScriptTag(fScriptCode);
+    fLangSysTag = getLangSysTag(fLanguageCode);
+}
+
+le_int32 OpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+                LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    // This is the cheapest way to get mark reordering only for Hebrew.
+    // We could just do the mark reordering for all scripts, but most
+    // of them probably don't need it... Another option would be to
+    // add a HebrewOpenTypeLayoutEngine subclass, but the only thing it
+    // would need to do is mark reordering, so that seems like overkill.
+    if (fScriptCode == hebrScriptCode) {
+        outChars = LE_NEW_ARRAY(LEUnicode, count);
+
+        if (outChars == NULL) {
+            success = LE_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+
+        if (LE_FAILURE(success)) {
+            LE_DELETE_ARRAY(outChars);
+            return 0;
+        }
+
+        CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, outChars, glyphStorage);
+    }
+
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    glyphStorage.allocateGlyphArray(count, rightToLeft, success);
+    glyphStorage.allocateAuxData(success);
+
+    for (le_int32 i = 0; i < count; i += 1) {
+        glyphStorage.setAuxData(i, fFeatureMask, success);
+    }
+
+    return count;
+}
+
+// Input: characters, tags
+// Output: glyphs, char indices
+le_int32 OpenTypeLayoutEngine::glyphProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+                                               LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success);
+
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+    
+    if (fGSUBTable != NULL) {
+        if (fScriptTagV2 != nullScriptTag && fGSUBTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) { 
+            count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTagV2, fLangSysTag, fGDEFTable, fSubstitutionFilter,
+                                    fFeatureMap, fFeatureMapCount, fFeatureOrder, success);
+
+        } else {
+        count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter,
+                                    fFeatureMap, fFeatureMapCount, fFeatureOrder, success);
+        }
+    }
+
+    return count;
+}
+// Input: characters, tags
+// Output: glyphs, char indices
+le_int32 OpenTypeLayoutEngine::glyphSubstitution(le_int32 count, le_int32 max, le_bool rightToLeft,
+                                               LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if ( count < 0 || max < 0 ) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+   
+    if (fGSUBTable != NULL) {
+        if (fScriptTagV2 != nullScriptTag && fGSUBTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) { 
+            count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTagV2, fLangSysTag, fGDEFTable, fSubstitutionFilter,
+                                    fFeatureMap, fFeatureMapCount, fFeatureOrder, success);
+
+        } else {
+        count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter,
+                                    fFeatureMap, fFeatureMapCount, fFeatureOrder, success);
+        }
+    }
+
+    return count;
+}
+le_int32 OpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    glyphStorage.adoptGlyphArray(tempGlyphStorage);
+    glyphStorage.adoptCharIndicesArray(tempGlyphStorage);
+    glyphStorage.adoptAuxDataArray(tempGlyphStorage);
+    glyphStorage.adoptGlyphCount(tempGlyphStorage);
+
+    return glyphStorage.getGlyphCount();
+}
+
+le_int32 OpenTypeLayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    LEUnicode *outChars = NULL;
+    LEGlyphStorage fakeGlyphStorage;
+    le_int32 outCharCount, outGlyphCount, fakeGlyphCount;
+
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, fakeGlyphStorage, success);
+
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if (outChars != NULL) {
+        fakeGlyphCount = glyphProcessing(outChars, 0, outCharCount, outCharCount, rightToLeft, fakeGlyphStorage, success);
+        LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work...
+        //adjustGlyphs(outChars, 0, outCharCount, rightToLeft, fakeGlyphs, fakeGlyphCount);
+    } else {
+        fakeGlyphCount = glyphProcessing(chars, offset, count, max, rightToLeft, fakeGlyphStorage, success);
+        //adjustGlyphs(chars, offset, count, rightToLeft, fakeGlyphs, fakeGlyphCount);
+    }
+
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    outGlyphCount = glyphPostProcessing(fakeGlyphStorage, glyphStorage, success);
+
+    return outGlyphCount;
+}
+
+// apply GPOS table, if any
+void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
+                                                LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    le_int32 glyphCount = glyphStorage.getGlyphCount();
+    if (glyphCount == 0) {
+        return;
+    }
+
+    if (fGPOSTable != NULL) {
+        GlyphPositionAdjustments *adjustments = new GlyphPositionAdjustments(glyphCount);
+        le_int32 i;
+
+        if (adjustments == NULL) {
+            success = LE_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+
+#if 0
+        // Don't need to do this if we allocate
+        // the adjustments array w/ new...
+        for (i = 0; i < glyphCount; i += 1) {
+            adjustments->setXPlacement(i, 0);
+            adjustments->setYPlacement(i, 0);
+
+            adjustments->setXAdvance(i, 0);
+            adjustments->setYAdvance(i, 0);
+
+            adjustments->setBaseOffset(i, -1);
+        }
+#endif
+
+        if (fGPOSTable != NULL) {
+            if (fScriptTagV2 != nullScriptTag && fGPOSTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) { 
+                fGPOSTable->process(glyphStorage, adjustments, reverse, fScriptTagV2, fLangSysTag, fGDEFTable, success, fFontInstance,
+                                fFeatureMap, fFeatureMapCount, fFeatureOrder);
+ 
+            } else {
+                fGPOSTable->process(glyphStorage, adjustments, reverse, fScriptTag, fLangSysTag, fGDEFTable, success, fFontInstance,
+                                fFeatureMap, fFeatureMapCount, fFeatureOrder);
+            }
+        } else if ( fTypoFlags & 0x1 ) {
+            static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG;
+            KernTable kt(fFontInstance, getFontTable(kernTableTag));
+            kt.process(glyphStorage);
+        }
+
+        float xAdjust = 0, yAdjust = 0;
+
+        for (i = 0; i < glyphCount; i += 1) {
+            float xAdvance   = adjustments->getXAdvance(i);
+            float yAdvance   = adjustments->getYAdvance(i);
+            float xPlacement = 0;
+            float yPlacement = 0;
+
+
+#if 0
+            // This is where separate kerning adjustments
+            // should get applied.
+            xAdjust += xKerning;
+            yAdjust += yKerning;
+#endif
+
+            for (le_int32 base = i; base >= 0; base = adjustments->getBaseOffset(base)) {
+                xPlacement += adjustments->getXPlacement(base);
+                yPlacement += adjustments->getYPlacement(base);
+            }
+
+            xPlacement = fFontInstance->xUnitsToPoints(xPlacement);
+            yPlacement = fFontInstance->yUnitsToPoints(yPlacement);
+            glyphStorage.adjustPosition(i, xAdjust + xPlacement, -(yAdjust + yPlacement), success);
+
+            xAdjust += fFontInstance->xUnitsToPoints(xAdvance);
+            yAdjust += fFontInstance->yUnitsToPoints(yAdvance);
+        }
+
+        glyphStorage.adjustPosition(glyphCount, xAdjust, -yAdjust, success);
+
+        delete adjustments;
+    } else {
+        // if there was no GPOS table, maybe there's non-OpenType kerning we can use
+        LayoutEngine::adjustGlyphPositions(chars, offset, count, reverse, glyphStorage, success);        
+    }
+
+    LEGlyphID zwnj  = fFontInstance->mapCharToGlyph(0x200C);
+
+    if (zwnj != 0x0000) {
+        for (le_int32 g = 0; g < glyphCount; g += 1) {
+            LEGlyphID glyph = glyphStorage[g];
+
+            if (glyph == zwnj) {
+                glyphStorage[g] = LE_SET_GLYPH(glyph, 0xFFFF);
+            }
+        }
+    }
+
+#if 0
+    // Don't know why this is here...
+    LE_DELETE_ARRAY(fFeatureTags);
+    fFeatureTags = NULL;
+#endif
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/OpenTypeLayoutEngine.h b/source/layout/OpenTypeLayoutEngine.h
new file mode 100644
index 0000000..4de8056
--- /dev/null
+++ b/source/layout/OpenTypeLayoutEngine.h
@@ -0,0 +1,390 @@
+/*
+ * (C) Copyright IBM Corp. 1998-2009 - All Rights Reserved
+ *
+ */
+
+#ifndef __OPENTYPELAYOUTENGINE_H
+#define __OPENTYPELAYOUTENGINE_H
+
+#include "LETypes.h"
+#include "LEGlyphFilter.h"
+#include "LEFontInstance.h"
+#include "LayoutEngine.h"
+
+#include "GlyphSubstitutionTables.h"
+#include "GlyphDefinitionTables.h"
+#include "GlyphPositioningTables.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * OpenTypeLayoutEngine implements complex text layout for OpenType fonts - that is
+ * fonts which have GSUB and GPOS tables associated with them. In order to do this,
+ * the glyph processsing step described for LayoutEngine is further broken into three
+ * steps:
+ *
+ * 1) Character processing - this step analyses the characters and assigns a list of OpenType
+ *    feature tags to each one. It may also change, remove or add characters, and change
+ *    their order.
+ *
+ * 2) Glyph processing - This step performs character to glyph mapping,and uses the GSUB
+ *    table associated with the font to perform glyph substitutions, such as ligature substitution.
+ *
+ * 3) Glyph post processing - in cases where the font doesn't directly contain a GSUB table,
+ *    the previous two steps may have generated "fake" glyph indices to use with a "canned" GSUB
+ *    table. This step turns those glyph indices into actual font-specific glyph indices, and may
+ *    perform any other adjustments requried by the previous steps.
+ *
+ * OpenTypeLayoutEngine will also use the font's GPOS table to apply position adjustments
+ * such as kerning and accent positioning.
+ *
+ * @see LayoutEngine
+ *
+ * @internal
+ */
+class U_LAYOUT_API OpenTypeLayoutEngine : public LayoutEngine
+{
+public:
+    /**
+     * This is the main constructor. It constructs an instance of OpenTypeLayoutEngine for
+     * a particular font, script and language. It takes the GSUB table as a parameter since
+     * LayoutEngine::layoutEngineFactory has to read the GSUB table to know that it has an
+     * OpenType font.
+     *
+     * @param fontInstance - the font
+     * @param scriptCode - the script
+     * @param langaugeCode - the language
+     * @param gsubTable - the GSUB table
+     * @param success - set to an error code if the operation fails
+     *
+     * @see LayoutEngine::layoutEngineFactory
+     * @see ScriptAndLangaugeTags.h for script and language codes
+     *
+     * @internal
+     */
+    OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+                            le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success);
+
+    /**
+     * This constructor is used when the font requires a "canned" GSUB table which can't be known
+     * until after this constructor has been invoked.
+     *
+     * @param fontInstance - the font
+     * @param scriptCode - the script
+     * @param langaugeCode - the language
+     * @param success - set to an error code if the operation fails
+     *
+     * @internal
+     */
+    OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+			 le_int32 typoFlags, LEErrorCode &success);
+
+    /**
+     * The destructor, virtual for correct polymorphic invocation.
+     *
+     * @internal
+     */
+    virtual ~OpenTypeLayoutEngine();
+
+    /**
+     * A convenience method used to convert the script code into
+     * the four byte script tag required by OpenType.
+	 * For Indic languages where multiple script tags exist,
+	 * the version 1 (old style) tag is returned.
+     *
+     * @param scriptCode - the script code
+     *
+     * @return the four byte script tag
+     *
+     * @internal
+     */
+    static LETag getScriptTag(le_int32 scriptCode);
+    /**
+     * A convenience method used to convert the script code into
+     * the four byte script tag required by OpenType.
+	 * For Indic languages where multiple script tags exist,
+	 * the version 2 tag is returned.
+     *
+     * @param scriptCode - the script code
+     *
+     * @return the four byte script tag
+     *
+     * @internal
+     */
+    static LETag getV2ScriptTag(le_int32 scriptCode);
+
+    /**
+     * A convenience method used to convert the langauge code into
+     * the four byte langauge tag required by OpenType.
+     *
+     * @param languageCode - the language code
+     *
+     * @return the four byte language tag
+     *
+     * @internal
+     */
+    static LETag getLangSysTag(le_int32 languageCode);
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.8
+     */
+    static UClassID getStaticClassID();
+
+    /**
+     * The array of language tags, indexed by language code.
+     *
+     * @internal
+     */
+    static const LETag languageTags[];
+
+private:
+
+    /**
+     * This method is used by the constructors to convert the script
+     * and language codes to four byte tags and save them.
+     */
+    void setScriptAndLanguageTags();
+
+    /**
+     * The array of script tags, indexed by script code.
+     */
+    static const LETag scriptTags[];
+
+protected:
+    /**
+     * A set of "default" features. The default characterProcessing method
+     * will apply all of these features to every glyph.
+     *
+     * @internal
+     */
+    FeatureMask fFeatureMask;
+
+    /**
+     * A set of mappings from feature tags to feature masks. These may
+     * be in the order in which the featues should be applied, but they
+     * don't need to be.
+     *
+     * @internal
+     */
+    const FeatureMap *fFeatureMap;
+
+    /**
+     * The length of the feature map.
+     *
+     * @internal
+     */
+    le_int32 fFeatureMapCount;
+
+    /**
+     * <code>TRUE</code> if the features in the
+     * feature map are in the order in which they
+     * must be applied.
+     *
+     * @internal
+     */
+    le_bool fFeatureOrder;
+
+    /**
+     * The address of the GSUB table.
+     *
+     * @internal
+     */
+    const GlyphSubstitutionTableHeader *fGSUBTable;
+
+    /**
+     * The address of the GDEF table.
+     *
+     * @internal
+     */
+    const GlyphDefinitionTableHeader   *fGDEFTable;
+
+    /**
+     * The address of the GPOS table.
+     *
+     * @internal
+     */
+    const GlyphPositioningTableHeader  *fGPOSTable;
+
+    /**
+     * An optional filter used to inhibit substitutions
+     * preformed by the GSUB table. This is used for some
+     * "canned" GSUB tables to restrict substitutions to
+     * glyphs that are in the font.
+     *
+     * @internal
+     */
+    LEGlyphFilter *fSubstitutionFilter;
+
+    /**
+     * The four byte script tag.
+     *
+     * @internal
+     */
+    LETag fScriptTag;
+  
+    /**
+     * The four byte script tag for V2 fonts.
+     *
+     * @internal
+     */
+    LETag fScriptTagV2;
+
+    /**
+     * The four byte language tag
+     *
+     * @internal
+     */
+    LETag fLangSysTag;
+
+    /**
+     * This method does the OpenType character processing. It assigns the OpenType feature
+     * tags to the characters, and may generate output characters that differ from the input
+     * charcters due to insertions, deletions, or reorderings. In such cases, it will also
+     * generate an output character index array reflecting these changes.
+     *
+     * Subclasses must override this method.
+     *
+     * Input parameters:
+     * @param chars - the input character context
+     * @param offset - the index of the first character to process
+     * @param count - the number of characters to process
+     * @param max - the number of characters in the input context
+     * @param rightToLeft - TRUE if the characters are in a right to left directional run
+     *
+     * Output parameters:
+     * @param outChars - the output character array, if different from the input
+     * @param charIndices - the output character index array
+     * @param featureTags - the output feature tag array
+     * @param success - set to an error code if the operation fails
+     *
+     * @return the output character count (input character count if no change)
+     *
+     * @internal
+     */
+    virtual le_int32 characterProcessing(const LEUnicode /*chars*/[], le_int32 offset, le_int32 count, le_int32 max, le_bool /*rightToLeft*/,
+            LEUnicode *&/*outChars*/, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+    /**
+     * This method does character to glyph mapping, and applies the GSUB table. The
+     * default implementation calls mapCharsToGlyphs and then applies the GSUB table,
+     * if there is one.
+     *
+     * Note that in the case of "canned" GSUB tables, the output glyph indices may be
+     * "fake" glyph indices that need to be converted to "real" glyph indices by the
+     * glyphPostProcessing method.
+     *
+     * Input parameters:
+     * @param chars - the input character context
+     * @param offset - the index of the first character to process
+     * @param count - the number of characters to process
+     * @param max - the number of characters in the input context
+     * @param rightToLeft - TRUE if the characters are in a right to left directional run
+     * @param featureTags - the feature tag array
+     *
+     * Output parameters:
+     * @param glyphs - the output glyph index array
+     * @param charIndices - the output character index array
+     * @param success - set to an error code if the operation fails
+     *
+     * @return the number of glyphs in the output glyph index array
+     *
+     * Note: if the character index array was already set by the characterProcessing
+     * method, this method won't change it.
+     *
+     * @internal
+     */
+    virtual le_int32 glyphProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+            LEGlyphStorage &glyphStorage, LEErrorCode &success);
+ 
+    virtual le_int32 glyphSubstitution(le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+    /**
+     * This method does any processing necessary to convert "fake"
+     * glyph indices used by the glyphProcessing method into "real" glyph
+     * indices which can be used to render the text. Note that in some
+     * cases, such as CDAC Indic fonts, several "real" glyphs may be needed
+     * to render one "fake" glyph.
+     *
+     * The default implementation of this method just returns the input glyph
+     * index and character index arrays, assuming that no "fake" glyph indices
+     * were needed to do GSUB processing.
+     *
+     * Input paramters:
+     * @param tempGlyphs - the input "fake" glyph index array
+     * @param tempCharIndices - the input "fake" character index array
+     * @param tempGlyphCount - the number of "fake" glyph indices
+     *
+     * Output parameters:
+     * @param glyphs - the output glyph index array
+     * @param charIndices - the output character index array
+     * @param success - set to an error code if the operation fails
+     *
+     * @return the number of glyph indices in the output glyph index array
+     *
+     * @internal
+     */
+    virtual le_int32 glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+    /**
+     * This method applies the characterProcessing, glyphProcessing and glyphPostProcessing
+     * methods. Most subclasses will not need to override this method.
+     *
+     * Input parameters:
+     * @param chars - the input character context
+     * @param offset - the index of the first character to process
+     * @param count - the number of characters to process
+     * @param max - the number of characters in the input context
+     * @param rightToLeft - TRUE if the text is in a right to left directional run
+     *
+     * Output parameters:
+     * @param glyphs - the glyph index array
+     * @param charIndices - the character index array
+     * @param success - set to an error code if the operation fails
+     *
+     * @return the number of glyphs in the glyph index array
+     *
+     * @see LayoutEngine::computeGlyphs
+     *
+     * @internal
+     */
+    virtual le_int32 computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+    /**
+     * This method uses the GPOS table, if there is one, to adjust the glyph positions.
+     *
+     * Input parameters:
+     * @param glyphs - the input glyph array
+     * @param glyphCount - the number of glyphs in the glyph array
+     * @param x - the starting X position
+     * @param y - the starting Y position
+     *
+     * Output parameters:
+     * @param positions - the output X and Y positions (two entries per glyph)
+     * @param success - set to an error code if the operation fails
+     *
+     * @internal
+     */
+    virtual void adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+    /**
+     * This method frees the feature tag array so that the
+     * OpenTypeLayoutEngine can be reused for different text.
+     * It is also called from our destructor.
+     *
+     * @internal
+     */
+    virtual void reset();
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/OpenTypeTables.h b/source/layout/OpenTypeTables.h
new file mode 100644
index 0000000..5398d17
--- /dev/null
+++ b/source/layout/OpenTypeTables.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#ifndef __OPENTYPETABLES_H
+#define __OPENTYPETABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+
+U_NAMESPACE_BEGIN
+
+#define ANY_NUMBER 1
+
+typedef le_uint16 Offset;
+typedef le_uint8  ATag[4];
+typedef le_uint32 fixed32;
+
+#define LE_GLYPH_GROUP_MASK 0x00000001UL
+typedef le_uint32 FeatureMask;
+
+#define SWAPT(atag) ((LETag) ((atag[0] << 24) + (atag[1] << 16) + (atag[2] << 8) + atag[3]))
+
+struct TagAndOffsetRecord
+{
+    ATag   tag;
+    Offset offset;
+};
+
+struct GlyphRangeRecord
+{
+    TTGlyphID firstGlyph;
+    TTGlyphID lastGlyph;
+    le_int16  rangeValue;
+};
+
+struct FeatureMap
+{
+    LETag       tag;
+    FeatureMask mask;
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/OpenTypeUtilities.cpp b/source/layout/OpenTypeUtilities.cpp
new file mode 100644
index 0000000..29c38dd
--- /dev/null
+++ b/source/layout/OpenTypeUtilities.cpp
@@ -0,0 +1,179 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2006 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "OpenTypeUtilities.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+//
+// Finds the high bit by binary searching
+// through the bits in n.
+//
+le_int8 OpenTypeUtilities::highBit(le_int32 value)
+{
+    if (value <= 0) {
+        return -32;
+    }
+
+    le_uint8 bit = 0;
+
+    if (value >= 1 << 16) {
+        value >>= 16;
+        bit += 16;
+    }
+
+    if (value >= 1 << 8) {
+        value >>= 8;
+        bit += 8;
+    }
+
+    if (value >= 1 << 4) {
+        value >>= 4;
+        bit += 4;
+    }
+
+    if (value >= 1 << 2) {
+        value >>= 2;
+        bit += 2;
+    }
+
+    if (value >= 1 << 1) {
+        value >>= 1;
+        bit += 1;
+    }
+
+    return bit;
+}
+
+Offset OpenTypeUtilities::getTagOffset(LETag tag, const TagAndOffsetRecord *records, le_int32 recordCount)
+{
+    le_uint8 bit = highBit(recordCount);
+    le_int32 power = 1 << bit;
+    le_int32 extra = recordCount - power;
+    le_int32 probe = power;
+    le_int32 index = 0;
+
+    if (SWAPT(records[extra].tag) <= tag) {
+        index = extra;
+    }
+
+    while (probe > (1 << 0)) {
+        probe >>= 1;
+
+        if (SWAPT(records[index + probe].tag) <= tag) {
+            index += probe;
+        }
+    }
+
+    if (SWAPT(records[index].tag) == tag) {
+        return SWAPW(records[index].offset);
+    }
+
+    return 0;
+}
+
+le_int32 OpenTypeUtilities::getGlyphRangeIndex(TTGlyphID glyphID, const GlyphRangeRecord *records, le_int32 recordCount)
+{
+    le_uint8 bit = highBit(recordCount);
+    le_int32 power = 1 << bit;
+    le_int32 extra = recordCount - power;
+    le_int32 probe = power;
+    le_int32 range = 0;
+
+	if (recordCount == 0) {
+		return -1;
+	}
+
+    if (SWAPW(records[extra].firstGlyph) <= glyphID) {
+        range = extra;
+    }
+
+    while (probe > (1 << 0)) {
+        probe >>= 1;
+
+        if (SWAPW(records[range + probe].firstGlyph) <= glyphID) {
+            range += probe;
+        }
+    }
+
+    if (SWAPW(records[range].firstGlyph) <= glyphID && SWAPW(records[range].lastGlyph) >= glyphID) {
+        return range;
+    }
+
+    return -1;
+}
+
+le_int32 OpenTypeUtilities::search(le_uint32 value, const le_uint32 array[], le_int32 count)
+{
+    le_int32 power = 1 << highBit(count);
+    le_int32 extra = count - power;
+    le_int32 probe = power;
+    le_int32 index = 0;
+
+    if (value >= array[extra]) {
+        index = extra;
+    }
+
+    while (probe > (1 << 0)) {
+        probe >>= 1;
+
+        if (value >= array[index + probe]) {
+            index += probe;
+        }
+    }
+
+    return index;
+}
+
+le_int32 OpenTypeUtilities::search(le_uint16 value, const le_uint16 array[], le_int32 count)
+{
+    le_int32 power = 1 << highBit(count);
+    le_int32 extra = count - power;
+    le_int32 probe = power;
+    le_int32 index = 0;
+
+    if (value >= array[extra]) {
+        index = extra;
+    }
+
+    while (probe > (1 << 0)) {
+        probe >>= 1;
+
+        if (value >= array[index + probe]) {
+            index += probe;
+        }
+    }
+
+    return index;
+}
+
+//
+// Straight insertion sort from Knuth vol. III, pg. 81
+//
+void OpenTypeUtilities::sort(le_uint16 *array, le_int32 count)
+{
+    for (le_int32 j = 1; j < count; j += 1) {
+        le_int32 i;
+        le_uint16 v = array[j];
+
+        for (i = j - 1; i >= 0; i -= 1) {
+            if (v >= array[i]) {
+                break;
+            }
+
+            array[i + 1] = array[i];
+        }
+
+        array[i + 1] = v;
+    }
+}
+
+ 
+
+U_NAMESPACE_END
diff --git a/source/layout/OpenTypeUtilities.h b/source/layout/OpenTypeUtilities.h
new file mode 100644
index 0000000..67a07c3
--- /dev/null
+++ b/source/layout/OpenTypeUtilities.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __OPENTYPEUTILITIES_H
+#define __OPENTYPEUTILITIES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+
+U_NAMESPACE_BEGIN
+
+class OpenTypeUtilities /* not : public UObject because all methods are static */ {
+public:
+    static le_int8 highBit(le_int32 value);
+    static Offset getTagOffset(LETag tag, const TagAndOffsetRecord *records, le_int32 recordCount);
+    static le_int32 getGlyphRangeIndex(TTGlyphID glyphID, const GlyphRangeRecord *records, le_int32 recordCount);
+    static le_int32 search(le_uint16 value, const le_uint16 array[], le_int32 count);
+    static le_int32 search(le_uint32 value, const le_uint32 array[], le_int32 count);
+    static void sort(le_uint16 *array, le_int32 count);
+
+private:
+    OpenTypeUtilities() {} // private - forbid instantiation
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/PairPositioningSubtables.cpp b/source/layout/PairPositioningSubtables.cpp
new file mode 100644
index 0000000..fce69f8
--- /dev/null
+++ b/source/layout/PairPositioningSubtables.cpp
@@ -0,0 +1,171 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2006 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "GlyphPositioningTables.h"
+#include "PairPositioningSubtables.h"
+#include "ValueRecords.h"
+#include "GlyphIterator.h"
+#include "OpenTypeUtilities.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+le_uint32 PairPositioningSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const
+{
+    switch(SWAPW(subtableFormat))
+    {
+    case 0:
+        return 0;
+
+    case 1:
+    {
+        const PairPositioningFormat1Subtable *subtable = (const PairPositioningFormat1Subtable *) this;
+
+        return subtable->process(glyphIterator, fontInstance);
+    }
+
+    case 2:
+    {
+        const PairPositioningFormat2Subtable *subtable = (const PairPositioningFormat2Subtable *) this;
+
+        return subtable->process(glyphIterator, fontInstance);
+    }
+
+    default:
+        return 0;
+    }
+}
+
+le_uint32 PairPositioningFormat1Subtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const
+{
+    LEGlyphID firstGlyph = glyphIterator->getCurrGlyphID();
+    le_int32 coverageIndex = getGlyphCoverage(firstGlyph);
+    GlyphIterator tempIterator(*glyphIterator);
+
+    if (coverageIndex >= 0 && glyphIterator->next()) {
+        Offset pairSetTableOffset = SWAPW(pairSetTableOffsetArray[coverageIndex]);
+        PairSetTable *pairSetTable = (PairSetTable *) ((char *) this + pairSetTableOffset);
+        le_uint16 pairValueCount = SWAPW(pairSetTable->pairValueCount);
+        le_int16 valueRecord1Size = ValueRecord::getSize(SWAPW(valueFormat1));
+        le_int16 valueRecord2Size = ValueRecord::getSize(SWAPW(valueFormat2));
+        le_int16 recordSize = sizeof(PairValueRecord) - sizeof(ValueRecord) + valueRecord1Size + valueRecord2Size;
+        LEGlyphID secondGlyph = glyphIterator->getCurrGlyphID();
+        const PairValueRecord *pairValueRecord = NULL;
+
+        if (pairValueCount != 0) {
+            pairValueRecord = findPairValueRecord((TTGlyphID) LE_GET_GLYPH(secondGlyph), pairSetTable->pairValueRecordArray, pairValueCount, recordSize);
+        }
+
+        if (pairValueRecord == NULL) {
+            return 0;
+        }
+
+        if (valueFormat1 != 0) {
+            pairValueRecord->valueRecord1.adjustPosition(SWAPW(valueFormat1), (char *) this, tempIterator, fontInstance);
+        }
+
+        if (valueFormat2 != 0) {
+            const ValueRecord *valueRecord2 = (const ValueRecord *) ((char *) &pairValueRecord->valueRecord1 + valueRecord1Size);
+
+            valueRecord2->adjustPosition(SWAPW(valueFormat2), (char *) this, *glyphIterator, fontInstance);
+        }
+
+        // back up glyphIterator so second glyph can be
+        // first glyph in the next pair
+        glyphIterator->prev();
+        return 1;
+    }
+
+    return 0;
+}
+
+le_uint32 PairPositioningFormat2Subtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const
+{
+    LEGlyphID firstGlyph = glyphIterator->getCurrGlyphID();
+    le_int32 coverageIndex = getGlyphCoverage(firstGlyph);
+    GlyphIterator tempIterator(*glyphIterator);
+
+    if (coverageIndex >= 0 && glyphIterator->next()) {
+        LEGlyphID secondGlyph = glyphIterator->getCurrGlyphID();
+        const ClassDefinitionTable *classDef1 = (const ClassDefinitionTable *) ((char *) this + SWAPW(classDef1Offset));
+        const ClassDefinitionTable *classDef2 = (const ClassDefinitionTable *) ((char *) this + SWAPW(classDef2Offset));
+        le_int32 class1 = classDef1->getGlyphClass(firstGlyph);
+        le_int32 class2 = classDef2->getGlyphClass(secondGlyph);
+        le_int16 valueRecord1Size = ValueRecord::getSize(SWAPW(valueFormat1));
+        le_int16 valueRecord2Size = ValueRecord::getSize(SWAPW(valueFormat2));
+        le_int16 class2RecordSize = valueRecord1Size + valueRecord2Size;
+        le_int16 class1RecordSize = class2RecordSize * SWAPW(class2Count);
+        const Class1Record *class1Record = (const Class1Record *) ((char *) class1RecordArray + (class1RecordSize * class1));
+        const Class2Record *class2Record = (const Class2Record *) ((char *) class1Record->class2RecordArray + (class2RecordSize * class2));
+
+
+        if (valueFormat1 != 0) {
+            class2Record->valueRecord1.adjustPosition(SWAPW(valueFormat1), (char *) this, tempIterator, fontInstance);
+        }
+
+        if (valueFormat2 != 0) {
+            const ValueRecord *valueRecord2 = (const ValueRecord *) ((char *) &class2Record->valueRecord1 + valueRecord1Size);
+
+            valueRecord2->adjustPosition(SWAPW(valueFormat2), (const char *) this, *glyphIterator, fontInstance);
+        }
+
+        // back up glyphIterator so second glyph can be
+        // first glyph in the next pair
+        glyphIterator->prev();
+        return 1;
+    }
+
+    return 0;
+}
+
+const PairValueRecord *PairPositioningFormat1Subtable::findPairValueRecord(TTGlyphID glyphID, const PairValueRecord *records, le_uint16 recordCount, le_uint16 recordSize) const
+{
+#if 1
+	// The OpenType spec. says that the ValueRecord table is
+	// sorted by secondGlyph. Unfortunately, there are fonts
+	// around that have an unsorted ValueRecord table.
+	const PairValueRecord *record = records;
+
+	for(le_int32 r = 0; r < recordCount; r += 1) {
+		if (SWAPW(record->secondGlyph) == glyphID) {
+			return record;
+		}
+
+		record = (const PairValueRecord *) ((char *) record + recordSize);
+	}
+#else
+    le_uint8 bit = OpenTypeUtilities::highBit(recordCount);
+    le_uint16 power = 1 << bit;
+    le_uint16 extra = (recordCount - power) * recordSize;
+    le_uint16 probe = power * recordSize;
+    const PairValueRecord *record = records;
+    const PairValueRecord *trial = (const PairValueRecord *) ((char *) record + extra);
+
+    if (SWAPW(trial->secondGlyph) <= glyphID) {
+        record = trial;
+    }
+
+    while (probe > recordSize) {
+        probe >>= 1;
+        trial = (const PairValueRecord *) ((char *) record + probe);
+
+        if (SWAPW(trial->secondGlyph) <= glyphID) {
+            record = trial;
+        }
+    }
+
+    if (SWAPW(record->secondGlyph) == glyphID) {
+        return record;
+    }
+#endif
+
+    return NULL;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/PairPositioningSubtables.h b/source/layout/PairPositioningSubtables.h
new file mode 100644
index 0000000..f017c33
--- /dev/null
+++ b/source/layout/PairPositioningSubtables.h
@@ -0,0 +1,84 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __PAIRPOSITIONINGSUBTABLES_H
+#define __PAIRPOSITIONINGSUBTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "GlyphPositioningTables.h"
+#include "ValueRecords.h"
+#include "GlyphIterator.h"
+
+U_NAMESPACE_BEGIN
+
+// NOTE: ValueRecord has a variable size
+struct PairValueRecord
+{
+    TTGlyphID     secondGlyph;
+    ValueRecord valueRecord1;
+//  ValueRecord valueRecord2;
+};
+
+struct PairSetTable
+{
+    le_uint16       pairValueCount;
+    PairValueRecord pairValueRecordArray[ANY_NUMBER];
+};
+
+struct PairPositioningSubtable : GlyphPositioningSubtable
+{
+    ValueFormat valueFormat1;
+    ValueFormat valueFormat2;
+
+    le_uint32  process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const;
+};
+
+struct PairPositioningFormat1Subtable : PairPositioningSubtable
+{
+    le_uint16   pairSetCount;
+    Offset      pairSetTableOffsetArray[ANY_NUMBER];
+
+    le_uint32  process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const;
+
+private:
+    const PairValueRecord *findPairValueRecord(TTGlyphID glyphID, const PairValueRecord *records,
+        le_uint16 recordCount, le_uint16 recordSize) const;
+};
+
+// NOTE: ValueRecord has a variable size
+struct Class2Record
+{
+    ValueRecord valueRecord1;
+//  ValueRecord valurRecord2;
+};
+
+struct Class1Record
+{
+    Class2Record class2RecordArray[ANY_NUMBER];
+};
+
+struct PairPositioningFormat2Subtable : PairPositioningSubtable
+{
+    Offset       classDef1Offset;
+    Offset       classDef2Offset;
+    le_uint16    class1Count;
+    le_uint16    class2Count;
+    Class1Record class1RecordArray[ANY_NUMBER];
+
+    le_uint32  process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const;
+};
+
+U_NAMESPACE_END
+#endif
+
+
diff --git a/source/layout/ScriptAndLanguage.cpp b/source/layout/ScriptAndLanguage.cpp
new file mode 100644
index 0000000..126f5f2
--- /dev/null
+++ b/source/layout/ScriptAndLanguage.cpp
@@ -0,0 +1,84 @@
+/*
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "OpenTypeUtilities.h"
+#include "ScriptAndLanguage.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+const LangSysTable *ScriptTable::findLanguage(LETag languageTag, le_bool exactMatch) const
+{
+    le_uint16 count = SWAPW(langSysCount);
+    Offset langSysTableOffset = exactMatch? 0 : SWAPW(defaultLangSysTableOffset);
+
+    if (count > 0) {
+        Offset foundOffset =
+            OpenTypeUtilities::getTagOffset(languageTag, langSysRecordArray, count);
+
+        if (foundOffset != 0) {
+            langSysTableOffset = foundOffset;
+        }
+    }
+
+    if (langSysTableOffset != 0) {
+        return (const LangSysTable *) ((char *)this + langSysTableOffset);
+    }
+
+    return NULL;
+}
+
+const ScriptTable *ScriptListTable::findScript(LETag scriptTag) const
+{
+    /*
+     * There are some fonts that have a large, bogus value for scriptCount. To try
+     * and protect against this, we use the offset in the first scriptRecord,
+     * which we know has to be past the end of the scriptRecordArray, to compute
+     * a value which is greater than or equal to the actual script count.
+     *
+     * Note: normally, the first offset will point to just after the scriptRecordArray,
+     * but there's no guarantee of this, only that it's *after* the scriptRecordArray.
+     * Because of this, a binary serach isn't safe, because the new count may include
+     * data that's not actually in the scriptRecordArray and hence the array will appear
+     * to be unsorted.
+     */
+    le_uint16 count = SWAPW(scriptCount);
+    le_uint16 limit = ((SWAPW(scriptRecordArray[0].offset) - sizeof(ScriptListTable)) / sizeof(scriptRecordArray)) + ANY_NUMBER;
+    Offset scriptTableOffset = 0;
+
+    if (count > limit) {
+        // the scriptCount value is bogus; do a linear search
+        // because limit may still be too large.
+        for(le_int32 s = 0; s < limit; s += 1) {
+            if (SWAPT(scriptRecordArray[s].tag) == scriptTag) {
+                scriptTableOffset = SWAPW(scriptRecordArray[s].offset);
+                break;
+            }
+        }
+    } else {
+        scriptTableOffset = OpenTypeUtilities::getTagOffset(scriptTag, scriptRecordArray, count);
+    }
+
+    if (scriptTableOffset != 0) {
+        return (const ScriptTable *) ((char *)this + scriptTableOffset);
+    }
+
+    return NULL;
+}
+
+const LangSysTable *ScriptListTable::findLanguage(LETag scriptTag, LETag languageTag, le_bool exactMatch) const
+{
+    const ScriptTable *scriptTable = findScript(scriptTag);
+
+    if (scriptTable == 0) {
+        return NULL;
+    }
+
+    return scriptTable->findLanguage(languageTag, exactMatch);
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/ScriptAndLanguage.h b/source/layout/ScriptAndLanguage.h
new file mode 100644
index 0000000..804dae9
--- /dev/null
+++ b/source/layout/ScriptAndLanguage.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __SCRIPTANDLANGUAGE_H
+#define __SCRIPTANDLANGUAGE_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+
+U_NAMESPACE_BEGIN
+
+typedef TagAndOffsetRecord LangSysRecord;
+
+struct LangSysTable
+{
+    Offset    lookupOrderOffset;
+    le_uint16 reqFeatureIndex;
+    le_uint16 featureCount;
+    le_uint16 featureIndexArray[ANY_NUMBER];
+};
+
+struct ScriptTable
+{
+    Offset              defaultLangSysTableOffset;
+    le_uint16           langSysCount;
+    LangSysRecord       langSysRecordArray[ANY_NUMBER];
+
+    const LangSysTable  *findLanguage(LETag languageTag, le_bool exactMatch = FALSE) const;
+};
+
+typedef TagAndOffsetRecord ScriptRecord;
+
+struct ScriptListTable
+{
+    le_uint16           scriptCount;
+    ScriptRecord        scriptRecordArray[ANY_NUMBER];
+
+    const ScriptTable   *findScript(LETag scriptTag) const;
+    const LangSysTable  *findLanguage(LETag scriptTag, LETag languageTag, le_bool exactMatch = FALSE) const;
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/ScriptAndLanguageTags.cpp b/source/layout/ScriptAndLanguageTags.cpp
new file mode 100644
index 0000000..077f05e
--- /dev/null
+++ b/source/layout/ScriptAndLanguageTags.cpp
@@ -0,0 +1,242 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2010. All Rights Reserved.
+ *
+ * WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT UNLESS
+ * YOU REALLY KNOW WHAT YOU'RE DOING.
+ *
+ * Generated on: 10/26/2010 02:53:33 PM PDT
+ */
+
+#include "LETypes.h"
+#include "ScriptAndLanguageTags.h"
+#include "OpenTypeLayoutEngine.h"
+
+U_NAMESPACE_BEGIN
+
+const LETag OpenTypeLayoutEngine::scriptTags[] = {
+    zyyyScriptTag, /* 'zyyy' (COMMON) */
+    zinhScriptTag, /* 'zinh' (INHERITED) */
+    arabScriptTag, /* 'arab' (ARABIC) */
+    armnScriptTag, /* 'armn' (ARMENIAN) */
+    bengScriptTag, /* 'beng' (BENGALI) */
+    bopoScriptTag, /* 'bopo' (BOPOMOFO) */
+    cherScriptTag, /* 'cher' (CHEROKEE) */
+    coptScriptTag, /* 'copt' (COPTIC) */
+    cyrlScriptTag, /* 'cyrl' (CYRILLIC) */
+    dsrtScriptTag, /* 'dsrt' (DESERET) */
+    devaScriptTag, /* 'deva' (DEVANAGARI) */
+    ethiScriptTag, /* 'ethi' (ETHIOPIC) */
+    georScriptTag, /* 'geor' (GEORGIAN) */
+    gothScriptTag, /* 'goth' (GOTHIC) */
+    grekScriptTag, /* 'grek' (GREEK) */
+    gujrScriptTag, /* 'gujr' (GUJARATI) */
+    guruScriptTag, /* 'guru' (GURMUKHI) */
+    haniScriptTag, /* 'hani' (HAN) */
+    hangScriptTag, /* 'hang' (HANGUL) */
+    hebrScriptTag, /* 'hebr' (HEBREW) */
+    hiraScriptTag, /* 'hira' (HIRAGANA) */
+    kndaScriptTag, /* 'knda' (KANNADA) */
+    kanaScriptTag, /* 'kana' (KATAKANA) */
+    khmrScriptTag, /* 'khmr' (KHMER) */
+    laooScriptTag, /* 'lao ' (LAO) */
+    latnScriptTag, /* 'latn' (LATIN) */
+    mlymScriptTag, /* 'mlym' (MALAYALAM) */
+    mongScriptTag, /* 'mong' (MONGOLIAN) */
+    mymrScriptTag, /* 'mymr' (MYANMAR) */
+    ogamScriptTag, /* 'ogam' (OGHAM) */
+    italScriptTag, /* 'ital' (OLD_ITALIC) */
+    oryaScriptTag, /* 'orya' (ORIYA) */
+    runrScriptTag, /* 'runr' (RUNIC) */
+    sinhScriptTag, /* 'sinh' (SINHALA) */
+    syrcScriptTag, /* 'syrc' (SYRIAC) */
+    tamlScriptTag, /* 'taml' (TAMIL) */
+    teluScriptTag, /* 'telu' (TELUGU) */
+    thaaScriptTag, /* 'thaa' (THAANA) */
+    thaiScriptTag, /* 'thai' (THAI) */
+    tibtScriptTag, /* 'tibt' (TIBETAN) */
+    cansScriptTag, /* 'cans' (CANADIAN_ABORIGINAL) */
+    yiiiScriptTag, /* 'yi  ' (YI) */
+    tglgScriptTag, /* 'tglg' (TAGALOG) */
+    hanoScriptTag, /* 'hano' (HANUNOO) */
+    buhdScriptTag, /* 'buhd' (BUHID) */
+    tagbScriptTag, /* 'tagb' (TAGBANWA) */
+    braiScriptTag, /* 'brai' (BRAILLE) */
+    cprtScriptTag, /* 'cprt' (CYPRIOT) */
+    limbScriptTag, /* 'limb' (LIMBU) */
+    linbScriptTag, /* 'linb' (LINEAR_B) */
+    osmaScriptTag, /* 'osma' (OSMANYA) */
+    shawScriptTag, /* 'shaw' (SHAVIAN) */
+    taleScriptTag, /* 'tale' (TAI_LE) */
+    ugarScriptTag, /* 'ugar' (UGARITIC) */
+    hrktScriptTag, /* 'hrkt' (KATAKANA_OR_HIRAGANA) */
+    bugiScriptTag, /* 'bugi' (BUGINESE) */
+    glagScriptTag, /* 'glag' (GLAGOLITIC) */
+    kharScriptTag, /* 'khar' (KHAROSHTHI) */
+    syloScriptTag, /* 'sylo' (SYLOTI_NAGRI) */
+    taluScriptTag, /* 'talu' (NEW_TAI_LUE) */
+    tfngScriptTag, /* 'tfng' (TIFINAGH) */
+    xpeoScriptTag, /* 'xpeo' (OLD_PERSIAN) */
+    baliScriptTag, /* 'bali' (BALINESE) */
+    batkScriptTag, /* 'batk' (BATAK) */
+    blisScriptTag, /* 'blis' (BLIS) */
+    brahScriptTag, /* 'brah' (BRAHMI) */
+    chamScriptTag, /* 'cham' (CHAM) */
+    cirtScriptTag, /* 'cirt' (CIRT) */
+    cyrsScriptTag, /* 'cyrs' (CYRS) */
+    egydScriptTag, /* 'egyd' (EGYD) */
+    egyhScriptTag, /* 'egyh' (EGYH) */
+    egypScriptTag, /* 'egyp' (EGYPTIAN_HIEROGLYPHS) */
+    geokScriptTag, /* 'geok' (GEOK) */
+    hansScriptTag, /* 'hans' (HANS) */
+    hantScriptTag, /* 'hant' (HANT) */
+    hmngScriptTag, /* 'hmng' (HMNG) */
+    hungScriptTag, /* 'hung' (HUNG) */
+    indsScriptTag, /* 'inds' (INDS) */
+    javaScriptTag, /* 'java' (JAVANESE) */
+    kaliScriptTag, /* 'kali' (KAYAH_LI) */
+    latfScriptTag, /* 'latf' (LATF) */
+    latgScriptTag, /* 'latg' (LATG) */
+    lepcScriptTag, /* 'lepc' (LEPCHA) */
+    linaScriptTag, /* 'lina' (LINA) */
+    mandScriptTag, /* 'mand' (MANDAIC) */
+    mayaScriptTag, /* 'maya' (MAYA) */
+    meroScriptTag, /* 'mero' (MERO) */
+    nkooScriptTag, /* 'nko ' (NKO) */
+    orkhScriptTag, /* 'orkh' (OLD_TURKIC) */
+    permScriptTag, /* 'perm' (PERM) */
+    phagScriptTag, /* 'phag' (PHAGS_PA) */
+    phnxScriptTag, /* 'phnx' (PHOENICIAN) */
+    plrdScriptTag, /* 'plrd' (PLRD) */
+    roroScriptTag, /* 'roro' (RORO) */
+    saraScriptTag, /* 'sara' (SARA) */
+    syreScriptTag, /* 'syre' (SYRE) */
+    syrjScriptTag, /* 'syrj' (SYRJ) */
+    syrnScriptTag, /* 'syrn' (SYRN) */
+    tengScriptTag, /* 'teng' (TENG) */
+    vaiiScriptTag, /* 'vai ' (VAI) */
+    vispScriptTag, /* 'visp' (VISP) */
+    xsuxScriptTag, /* 'xsux' (CUNEIFORM) */
+    zxxxScriptTag, /* 'zxxx' (ZXXX) */
+    zzzzScriptTag, /* 'zzzz' (UNKNOWN) */
+    cariScriptTag, /* 'cari' (CARIAN) */
+    jpanScriptTag, /* 'jpan' (JPAN) */
+    lanaScriptTag, /* 'lana' (TAI_THAM) */
+    lyciScriptTag, /* 'lyci' (LYCIAN) */
+    lydiScriptTag, /* 'lydi' (LYDIAN) */
+    olckScriptTag, /* 'olck' (OL_CHIKI) */
+    rjngScriptTag, /* 'rjng' (REJANG) */
+    saurScriptTag, /* 'saur' (SAURASHTRA) */
+    sgnwScriptTag, /* 'sgnw' (SGNW) */
+    sundScriptTag, /* 'sund' (SUNDANESE) */
+    moonScriptTag, /* 'moon' (MOON) */
+    mteiScriptTag, /* 'mtei' (MEETEI_MAYEK) */
+    armiScriptTag, /* 'armi' (IMPERIAL_ARAMAIC) */
+    avstScriptTag, /* 'avst' (AVESTAN) */
+    cakmScriptTag, /* 'cakm' (CAKM) */
+    koreScriptTag, /* 'kore' (KORE) */
+    kthiScriptTag, /* 'kthi' (KAITHI) */
+    maniScriptTag, /* 'mani' (MANI) */
+    phliScriptTag, /* 'phli' (INSCRIPTIONAL_PAHLAVI) */
+    phlpScriptTag, /* 'phlp' (PHLP) */
+    phlvScriptTag, /* 'phlv' (PHLV) */
+    prtiScriptTag, /* 'prti' (INSCRIPTIONAL_PARTHIAN) */
+    samrScriptTag, /* 'samr' (SAMARITAN) */
+    tavtScriptTag, /* 'tavt' (TAI_VIET) */
+    zmthScriptTag, /* 'zmth' (ZMTH) */
+    zsymScriptTag, /* 'zsym' (ZSYM) */
+    bamuScriptTag, /* 'bamu' (BAMUM) */
+    lisuScriptTag, /* 'lisu' (LISU) */
+    nkgbScriptTag, /* 'nkgb' (NKGB) */
+    sarbScriptTag, /* 'sarb' (OLD_SOUTH_ARABIAN) */
+    bassScriptTag, /* 'bass' (BASS) */
+    duplScriptTag, /* 'dupl' (DUPL) */
+    elbaScriptTag, /* 'elba' (ELBA) */
+    granScriptTag, /* 'gran' (GRAN) */
+    kpelScriptTag, /* 'kpel' (KPEL) */
+    lomaScriptTag, /* 'loma' (LOMA) */
+    mendScriptTag, /* 'mend' (MEND) */
+    mercScriptTag, /* 'merc' (MERC) */
+    narbScriptTag, /* 'narb' (NARB) */
+    nbatScriptTag, /* 'nbat' (NBAT) */
+    palmScriptTag, /* 'palm' (PALM) */
+    sindScriptTag, /* 'sind' (SIND) */
+    waraScriptTag  /* 'wara' (WARA) */
+};
+
+const LETag OpenTypeLayoutEngine::languageTags[] = {
+    nullLanguageTag, /* '' (null) */
+    araLanguageTag, /* 'ARA' (Arabic) */
+    asmLanguageTag, /* 'ASM' (Assamese) */
+    benLanguageTag, /* 'BEN' (Bengali) */
+    farLanguageTag, /* 'FAR' (Farsi) */
+    gujLanguageTag, /* 'GUJ' (Gujarati) */
+    hinLanguageTag, /* 'HIN' (Hindi) */
+    iwrLanguageTag, /* 'IWR' (Hebrew) */
+    jiiLanguageTag, /* 'JII' (Yiddish) */
+    janLanguageTag, /* 'JAN' (Japanese) */
+    kanLanguageTag, /* 'KAN' (Kannada) */
+    kokLanguageTag, /* 'KOK' (Konkani) */
+    korLanguageTag, /* 'KOR' (Korean) */
+    kshLanguageTag, /* 'KSH' (Kashmiri) */
+    malLanguageTag, /* 'MAL' (Malayalam (Traditional)) */
+    marLanguageTag, /* 'MAR' (Marathi) */
+    mlrLanguageTag, /* 'MLR' (Malayalam (Reformed)) */
+    mniLanguageTag, /* 'MNI' (Manipuri) */
+    oriLanguageTag, /* 'ORI' (Oriya) */
+    sanLanguageTag, /* 'SAN' (Sanscrit) */
+    sndLanguageTag, /* 'SND' (Sindhi) */
+    snhLanguageTag, /* 'SNH' (Sinhalese) */
+    syrLanguageTag, /* 'SYR' (Syriac) */
+    tamLanguageTag, /* 'TAM' (Tamil) */
+    telLanguageTag, /* 'TEL' (Telugu) */
+    thaLanguageTag, /* 'THA' (Thai) */
+    urdLanguageTag, /* 'URD' (Urdu) */
+    zhpLanguageTag, /* 'ZHP' (Chinese (Phonetic)) */
+    zhsLanguageTag, /* 'ZHS' (Chinese (Simplified)) */
+    zhtLanguageTag, /* 'ZHT' (Chinese (Traditional)) */
+    afkLanguageTag, /* 'AFK' (Afrikaans) */
+    belLanguageTag, /* 'BEL' (Belarussian) */
+    bgrLanguageTag, /* 'BGR' (Bulgarian) */
+    catLanguageTag, /* 'CAT' (Catalan) */
+    cheLanguageTag, /* 'CHE' (Chechen) */
+    copLanguageTag, /* 'COP' (Coptic) */
+    csyLanguageTag, /* 'CSY' (Czech) */
+    danLanguageTag, /* 'DAN' (Danish) */
+    deuLanguageTag, /* 'DEU' (German) */
+    dznLanguageTag, /* 'DZN' (Dzongkha) */
+    ellLanguageTag, /* 'ELL' (Greek) */
+    engLanguageTag, /* 'ENG' (English) */
+    espLanguageTag, /* 'ESP' (Spanish) */
+    etiLanguageTag, /* 'ETI' (Estonian) */
+    euqLanguageTag, /* 'EUQ' (Basque) */
+    finLanguageTag, /* 'FIN' (Finnish) */
+    fraLanguageTag, /* 'FRA' (French) */
+    gaeLanguageTag, /* 'GAE' (Gaelic) */
+    hauLanguageTag, /* 'HAU' (Hausa) */
+    hrvLanguageTag, /* 'HRV' (Croation) */
+    hunLanguageTag, /* 'HUN' (Hungarian) */
+    hyeLanguageTag, /* 'HYE' (Armenian) */
+    indLanguageTag, /* 'IND' (Indonesian) */
+    itaLanguageTag, /* 'ITA' (Italian) */
+    khmLanguageTag, /* 'KHM' (Khmer) */
+    mngLanguageTag, /* 'MNG' (Mongolian) */
+    mtsLanguageTag, /* 'MTS' (Maltese) */
+    nepLanguageTag, /* 'NEP' (Nepali) */
+    nldLanguageTag, /* 'NLD' (Dutch) */
+    pasLanguageTag, /* 'PAS' (Pashto) */
+    plkLanguageTag, /* 'PLK' (Polish) */
+    ptgLanguageTag, /* 'PTG' (Portuguese) */
+    romLanguageTag, /* 'ROM' (Romanian) */
+    rusLanguageTag, /* 'RUS' (Russian) */
+    skyLanguageTag, /* 'SKY' (Slovak) */
+    slvLanguageTag, /* 'SLV' (Slovenian) */
+    sqiLanguageTag, /* 'SQI' (Albanian) */
+    srbLanguageTag, /* 'SRB' (Serbian) */
+    sveLanguageTag, /* 'SVE' (Swedish) */
+    tibLanguageTag, /* 'TIB' (Tibetan) */
+    trkLanguageTag, /* 'TRK' (Turkish) */
+    welLanguageTag  /* 'WEL' (Welsh) */
+};
+
+U_NAMESPACE_END
diff --git a/source/layout/ScriptAndLanguageTags.h b/source/layout/ScriptAndLanguageTags.h
new file mode 100644
index 0000000..3f188b8
--- /dev/null
+++ b/source/layout/ScriptAndLanguageTags.h
@@ -0,0 +1,258 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2010. All Rights Reserved.
+ *
+ * WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT UNLESS
+ * YOU REALLY KNOW WHAT YOU'RE DOING.
+ *
+ * Generated on: 10/26/2010 02:53:33 PM PDT
+ */
+
+#ifndef __SCRIPTANDLANGUAGES_H
+#define __SCRIPTANDLANGUAGES_H
+
+#include "LETypes.h"
+
+/**
+ * \file
+ * \internal
+ */
+
+U_NAMESPACE_BEGIN
+
+const LETag zyyyScriptTag = 0x7A797979; /* 'zyyy' (COMMON) */
+const LETag zinhScriptTag = 0x7A696E68; /* 'zinh' (INHERITED) */
+const LETag arabScriptTag = 0x61726162; /* 'arab' (ARABIC) */
+const LETag armnScriptTag = 0x61726D6E; /* 'armn' (ARMENIAN) */
+const LETag bengScriptTag = 0x62656E67; /* 'beng' (BENGALI) */
+const LETag bng2ScriptTag = 0x626E6732; /* 'bng2' (BENGALI v.2) (manually added) */
+const LETag bopoScriptTag = 0x626F706F; /* 'bopo' (BOPOMOFO) */
+const LETag cherScriptTag = 0x63686572; /* 'cher' (CHEROKEE) */
+const LETag coptScriptTag = 0x636F7074; /* 'copt' (COPTIC) */
+const LETag cyrlScriptTag = 0x6379726C; /* 'cyrl' (CYRILLIC) */
+const LETag dsrtScriptTag = 0x64737274; /* 'dsrt' (DESERET) */
+const LETag devaScriptTag = 0x64657661; /* 'deva' (DEVANAGARI) */
+const LETag dev2ScriptTag = 0x64657632; /* 'dev2' (DEVANAGARI v.2) (manually added) */
+const LETag ethiScriptTag = 0x65746869; /* 'ethi' (ETHIOPIC) */
+const LETag georScriptTag = 0x67656F72; /* 'geor' (GEORGIAN) */
+const LETag gothScriptTag = 0x676F7468; /* 'goth' (GOTHIC) */
+const LETag grekScriptTag = 0x6772656B; /* 'grek' (GREEK) */
+const LETag gujrScriptTag = 0x67756A72; /* 'gujr' (GUJARATI) */
+const LETag gjr2ScriptTag = 0x676A7232; /* 'gjr2' (GUJARATI v.2) (manually added) */
+const LETag guruScriptTag = 0x67757275; /* 'guru' (GURMUKHI) */
+const LETag gur2ScriptTag = 0x67757232; /* 'gur2' (GURMUKHI v.2) (manually added) */
+const LETag haniScriptTag = 0x68616E69; /* 'hani' (HAN) */
+const LETag hangScriptTag = 0x68616E67; /* 'hang' (HANGUL) */
+const LETag hebrScriptTag = 0x68656272; /* 'hebr' (HEBREW) */
+const LETag hiraScriptTag = 0x68697261; /* 'hira' (HIRAGANA) */
+const LETag kndaScriptTag = 0x6B6E6461; /* 'knda' (KANNADA) */
+const LETag knd2ScriptTag = 0x6B6E6432; /* 'knd2' (KANNADA v.2) (manually added) */
+const LETag kanaScriptTag = 0x6B616E61; /* 'kana' (KATAKANA) */
+const LETag khmrScriptTag = 0x6B686D72; /* 'khmr' (KHMER) */
+const LETag laooScriptTag = 0x6C616F20; /* 'lao ' (LAO) */
+const LETag latnScriptTag = 0x6C61746E; /* 'latn' (LATIN) */
+const LETag mlymScriptTag = 0x6D6C796D; /* 'mlym' (MALAYALAM) */
+const LETag mlm2ScriptTag = 0x6D6C6D32; /* 'mlm2' (MALAYALAM v.2) (manually added) */
+const LETag mongScriptTag = 0x6D6F6E67; /* 'mong' (MONGOLIAN) */
+const LETag mymrScriptTag = 0x6D796D72; /* 'mymr' (MYANMAR) */
+const LETag ogamScriptTag = 0x6F67616D; /* 'ogam' (OGHAM) */
+const LETag italScriptTag = 0x6974616C; /* 'ital' (OLD_ITALIC) */
+const LETag oryaScriptTag = 0x6F727961; /* 'orya' (ORIYA) */
+const LETag ory2ScriptTag = 0x6F727932; /* 'ory2' (ORIYA v.2) (manually added) */
+const LETag runrScriptTag = 0x72756E72; /* 'runr' (RUNIC) */
+const LETag sinhScriptTag = 0x73696E68; /* 'sinh' (SINHALA) */
+const LETag syrcScriptTag = 0x73797263; /* 'syrc' (SYRIAC) */
+const LETag tamlScriptTag = 0x74616D6C; /* 'taml' (TAMIL) */
+const LETag tml2ScriptTag = 0x746D6C32; /* 'tml2' (TAMIL v.2) (manually added) */
+const LETag teluScriptTag = 0x74656C75; /* 'telu' (TELUGU) */
+const LETag tel2ScriptTag = 0x74656C32; /* 'tel2' (TELUGU v.2) (manually added) */
+const LETag thaaScriptTag = 0x74686161; /* 'thaa' (THAANA) */
+const LETag thaiScriptTag = 0x74686169; /* 'thai' (THAI) */
+const LETag tibtScriptTag = 0x74696274; /* 'tibt' (TIBETAN) */
+const LETag cansScriptTag = 0x63616E73; /* 'cans' (CANADIAN_ABORIGINAL) */
+const LETag yiiiScriptTag = 0x79692020; /* 'yi  ' (YI) */
+const LETag tglgScriptTag = 0x74676C67; /* 'tglg' (TAGALOG) */
+const LETag hanoScriptTag = 0x68616E6F; /* 'hano' (HANUNOO) */
+const LETag buhdScriptTag = 0x62756864; /* 'buhd' (BUHID) */
+const LETag tagbScriptTag = 0x74616762; /* 'tagb' (TAGBANWA) */
+const LETag braiScriptTag = 0x62726169; /* 'brai' (BRAILLE) */
+const LETag cprtScriptTag = 0x63707274; /* 'cprt' (CYPRIOT) */
+const LETag limbScriptTag = 0x6C696D62; /* 'limb' (LIMBU) */
+const LETag linbScriptTag = 0x6C696E62; /* 'linb' (LINEAR_B) */
+const LETag osmaScriptTag = 0x6F736D61; /* 'osma' (OSMANYA) */
+const LETag shawScriptTag = 0x73686177; /* 'shaw' (SHAVIAN) */
+const LETag taleScriptTag = 0x74616C65; /* 'tale' (TAI_LE) */
+const LETag ugarScriptTag = 0x75676172; /* 'ugar' (UGARITIC) */
+const LETag hrktScriptTag = 0x68726B74; /* 'hrkt' (KATAKANA_OR_HIRAGANA) */
+const LETag bugiScriptTag = 0x62756769; /* 'bugi' (BUGINESE) */
+const LETag glagScriptTag = 0x676C6167; /* 'glag' (GLAGOLITIC) */
+const LETag kharScriptTag = 0x6B686172; /* 'khar' (KHAROSHTHI) */
+const LETag syloScriptTag = 0x73796C6F; /* 'sylo' (SYLOTI_NAGRI) */
+const LETag taluScriptTag = 0x74616C75; /* 'talu' (NEW_TAI_LUE) */
+const LETag tfngScriptTag = 0x74666E67; /* 'tfng' (TIFINAGH) */
+const LETag xpeoScriptTag = 0x7870656F; /* 'xpeo' (OLD_PERSIAN) */
+const LETag baliScriptTag = 0x62616C69; /* 'bali' (BALINESE) */
+const LETag batkScriptTag = 0x6261746B; /* 'batk' (BATAK) */
+const LETag blisScriptTag = 0x626C6973; /* 'blis' (BLIS) */
+const LETag brahScriptTag = 0x62726168; /* 'brah' (BRAHMI) */
+const LETag chamScriptTag = 0x6368616D; /* 'cham' (CHAM) */
+const LETag cirtScriptTag = 0x63697274; /* 'cirt' (CIRT) */
+const LETag cyrsScriptTag = 0x63797273; /* 'cyrs' (CYRS) */
+const LETag egydScriptTag = 0x65677964; /* 'egyd' (EGYD) */
+const LETag egyhScriptTag = 0x65677968; /* 'egyh' (EGYH) */
+const LETag egypScriptTag = 0x65677970; /* 'egyp' (EGYPTIAN_HIEROGLYPHS) */
+const LETag geokScriptTag = 0x67656F6B; /* 'geok' (GEOK) */
+const LETag hansScriptTag = 0x68616E73; /* 'hans' (HANS) */
+const LETag hantScriptTag = 0x68616E74; /* 'hant' (HANT) */
+const LETag hmngScriptTag = 0x686D6E67; /* 'hmng' (HMNG) */
+const LETag hungScriptTag = 0x68756E67; /* 'hung' (HUNG) */
+const LETag indsScriptTag = 0x696E6473; /* 'inds' (INDS) */
+const LETag javaScriptTag = 0x6A617661; /* 'java' (JAVANESE) */
+const LETag kaliScriptTag = 0x6B616C69; /* 'kali' (KAYAH_LI) */
+const LETag latfScriptTag = 0x6C617466; /* 'latf' (LATF) */
+const LETag latgScriptTag = 0x6C617467; /* 'latg' (LATG) */
+const LETag lepcScriptTag = 0x6C657063; /* 'lepc' (LEPCHA) */
+const LETag linaScriptTag = 0x6C696E61; /* 'lina' (LINA) */
+const LETag mandScriptTag = 0x6D616E64; /* 'mand' (MANDAIC) */
+const LETag mayaScriptTag = 0x6D617961; /* 'maya' (MAYA) */
+const LETag meroScriptTag = 0x6D65726F; /* 'mero' (MERO) */
+const LETag nkooScriptTag = 0x6E6B6F20; /* 'nko ' (NKO) */
+const LETag orkhScriptTag = 0x6F726B68; /* 'orkh' (OLD_TURKIC) */
+const LETag permScriptTag = 0x7065726D; /* 'perm' (PERM) */
+const LETag phagScriptTag = 0x70686167; /* 'phag' (PHAGS_PA) */
+const LETag phnxScriptTag = 0x70686E78; /* 'phnx' (PHOENICIAN) */
+const LETag plrdScriptTag = 0x706C7264; /* 'plrd' (PLRD) */
+const LETag roroScriptTag = 0x726F726F; /* 'roro' (RORO) */
+const LETag saraScriptTag = 0x73617261; /* 'sara' (SARA) */
+const LETag syreScriptTag = 0x73797265; /* 'syre' (SYRE) */
+const LETag syrjScriptTag = 0x7379726A; /* 'syrj' (SYRJ) */
+const LETag syrnScriptTag = 0x7379726E; /* 'syrn' (SYRN) */
+const LETag tengScriptTag = 0x74656E67; /* 'teng' (TENG) */
+const LETag vaiiScriptTag = 0x76616920; /* 'vai ' (VAI) */
+const LETag vispScriptTag = 0x76697370; /* 'visp' (VISP) */
+const LETag xsuxScriptTag = 0x78737578; /* 'xsux' (CUNEIFORM) */
+const LETag zxxxScriptTag = 0x7A787878; /* 'zxxx' (ZXXX) */
+const LETag zzzzScriptTag = 0x7A7A7A7A; /* 'zzzz' (UNKNOWN) */
+const LETag cariScriptTag = 0x63617269; /* 'cari' (CARIAN) */
+const LETag jpanScriptTag = 0x6A70616E; /* 'jpan' (JPAN) */
+const LETag lanaScriptTag = 0x6C616E61; /* 'lana' (TAI_THAM) */
+const LETag lyciScriptTag = 0x6C796369; /* 'lyci' (LYCIAN) */
+const LETag lydiScriptTag = 0x6C796469; /* 'lydi' (LYDIAN) */
+const LETag olckScriptTag = 0x6F6C636B; /* 'olck' (OL_CHIKI) */
+const LETag rjngScriptTag = 0x726A6E67; /* 'rjng' (REJANG) */
+const LETag saurScriptTag = 0x73617572; /* 'saur' (SAURASHTRA) */
+const LETag sgnwScriptTag = 0x73676E77; /* 'sgnw' (SGNW) */
+const LETag sundScriptTag = 0x73756E64; /* 'sund' (SUNDANESE) */
+const LETag moonScriptTag = 0x6D6F6F6E; /* 'moon' (MOON) */
+const LETag mteiScriptTag = 0x6D746569; /* 'mtei' (MEETEI_MAYEK) */
+const LETag armiScriptTag = 0x61726D69; /* 'armi' (IMPERIAL_ARAMAIC) */
+const LETag avstScriptTag = 0x61767374; /* 'avst' (AVESTAN) */
+const LETag cakmScriptTag = 0x63616B6D; /* 'cakm' (CAKM) */
+const LETag koreScriptTag = 0x6B6F7265; /* 'kore' (KORE) */
+const LETag kthiScriptTag = 0x6B746869; /* 'kthi' (KAITHI) */
+const LETag maniScriptTag = 0x6D616E69; /* 'mani' (MANI) */
+const LETag phliScriptTag = 0x70686C69; /* 'phli' (INSCRIPTIONAL_PAHLAVI) */
+const LETag phlpScriptTag = 0x70686C70; /* 'phlp' (PHLP) */
+const LETag phlvScriptTag = 0x70686C76; /* 'phlv' (PHLV) */
+const LETag prtiScriptTag = 0x70727469; /* 'prti' (INSCRIPTIONAL_PARTHIAN) */
+const LETag samrScriptTag = 0x73616D72; /* 'samr' (SAMARITAN) */
+const LETag tavtScriptTag = 0x74617674; /* 'tavt' (TAI_VIET) */
+const LETag zmthScriptTag = 0x7A6D7468; /* 'zmth' (ZMTH) */
+const LETag zsymScriptTag = 0x7A73796D; /* 'zsym' (ZSYM) */
+const LETag bamuScriptTag = 0x62616D75; /* 'bamu' (BAMUM) */
+const LETag lisuScriptTag = 0x6C697375; /* 'lisu' (LISU) */
+const LETag nkgbScriptTag = 0x6E6B6762; /* 'nkgb' (NKGB) */
+const LETag sarbScriptTag = 0x73617262; /* 'sarb' (OLD_SOUTH_ARABIAN) */
+const LETag bassScriptTag = 0x62617373; /* 'bass' (BASS) */
+const LETag duplScriptTag = 0x6475706C; /* 'dupl' (DUPL) */
+const LETag elbaScriptTag = 0x656C6261; /* 'elba' (ELBA) */
+const LETag granScriptTag = 0x6772616E; /* 'gran' (GRAN) */
+const LETag kpelScriptTag = 0x6B70656C; /* 'kpel' (KPEL) */
+const LETag lomaScriptTag = 0x6C6F6D61; /* 'loma' (LOMA) */
+const LETag mendScriptTag = 0x6D656E64; /* 'mend' (MEND) */
+const LETag mercScriptTag = 0x6D657263; /* 'merc' (MERC) */
+const LETag narbScriptTag = 0x6E617262; /* 'narb' (NARB) */
+const LETag nbatScriptTag = 0x6E626174; /* 'nbat' (NBAT) */
+const LETag palmScriptTag = 0x70616C6D; /* 'palm' (PALM) */
+const LETag sindScriptTag = 0x73696E64; /* 'sind' (SIND) */
+const LETag waraScriptTag = 0x77617261; /* 'wara' (WARA) */
+
+const LETag nullScriptTag = 0x00000000; /* ''     (NULL) */
+
+
+const LETag nullLanguageTag = 0x00000000; /* '' (null) */
+const LETag araLanguageTag = 0x41524120; /* 'ARA' (Arabic) */
+const LETag asmLanguageTag = 0x41534D20; /* 'ASM' (Assamese) */
+const LETag benLanguageTag = 0x42454E20; /* 'BEN' (Bengali) */
+const LETag farLanguageTag = 0x46415220; /* 'FAR' (Farsi) */
+const LETag gujLanguageTag = 0x47554A20; /* 'GUJ' (Gujarati) */
+const LETag hinLanguageTag = 0x48494E20; /* 'HIN' (Hindi) */
+const LETag iwrLanguageTag = 0x49575220; /* 'IWR' (Hebrew) */
+const LETag jiiLanguageTag = 0x4A494920; /* 'JII' (Yiddish) */
+const LETag janLanguageTag = 0x4A414E20; /* 'JAN' (Japanese) */
+const LETag kanLanguageTag = 0x4B414E20; /* 'KAN' (Kannada) */
+const LETag kokLanguageTag = 0x4B4F4B20; /* 'KOK' (Konkani) */
+const LETag korLanguageTag = 0x4B4F5220; /* 'KOR' (Korean) */
+const LETag kshLanguageTag = 0x4B534820; /* 'KSH' (Kashmiri) */
+const LETag malLanguageTag = 0x4D414C20; /* 'MAL' (Malayalam (Traditional)) */
+const LETag marLanguageTag = 0x4D415220; /* 'MAR' (Marathi) */
+const LETag mlrLanguageTag = 0x4D4C5220; /* 'MLR' (Malayalam (Reformed)) */
+const LETag mniLanguageTag = 0x4D4E4920; /* 'MNI' (Manipuri) */
+const LETag oriLanguageTag = 0x4F524920; /* 'ORI' (Oriya) */
+const LETag sanLanguageTag = 0x53414E20; /* 'SAN' (Sanscrit) */
+const LETag sndLanguageTag = 0x534E4420; /* 'SND' (Sindhi) */
+const LETag snhLanguageTag = 0x534E4820; /* 'SNH' (Sinhalese) */
+const LETag syrLanguageTag = 0x53595220; /* 'SYR' (Syriac) */
+const LETag tamLanguageTag = 0x54414D20; /* 'TAM' (Tamil) */
+const LETag telLanguageTag = 0x54454C20; /* 'TEL' (Telugu) */
+const LETag thaLanguageTag = 0x54484120; /* 'THA' (Thai) */
+const LETag urdLanguageTag = 0x55524420; /* 'URD' (Urdu) */
+const LETag zhpLanguageTag = 0x5A485020; /* 'ZHP' (Chinese (Phonetic)) */
+const LETag zhsLanguageTag = 0x5A485320; /* 'ZHS' (Chinese (Simplified)) */
+const LETag zhtLanguageTag = 0x5A485420; /* 'ZHT' (Chinese (Traditional)) */
+const LETag afkLanguageTag = 0x41464B20; /* 'AFK' (Afrikaans) */
+const LETag belLanguageTag = 0x42454C20; /* 'BEL' (Belarussian) */
+const LETag bgrLanguageTag = 0x42475220; /* 'BGR' (Bulgarian) */
+const LETag catLanguageTag = 0x43415420; /* 'CAT' (Catalan) */
+const LETag cheLanguageTag = 0x43484520; /* 'CHE' (Chechen) */
+const LETag copLanguageTag = 0x434F5020; /* 'COP' (Coptic) */
+const LETag csyLanguageTag = 0x43535920; /* 'CSY' (Czech) */
+const LETag danLanguageTag = 0x44414E20; /* 'DAN' (Danish) */
+const LETag deuLanguageTag = 0x44455520; /* 'DEU' (German) */
+const LETag dznLanguageTag = 0x445A4E20; /* 'DZN' (Dzongkha) */
+const LETag ellLanguageTag = 0x454C4C20; /* 'ELL' (Greek) */
+const LETag engLanguageTag = 0x454E4720; /* 'ENG' (English) */
+const LETag espLanguageTag = 0x45535020; /* 'ESP' (Spanish) */
+const LETag etiLanguageTag = 0x45544920; /* 'ETI' (Estonian) */
+const LETag euqLanguageTag = 0x45555120; /* 'EUQ' (Basque) */
+const LETag finLanguageTag = 0x46494E20; /* 'FIN' (Finnish) */
+const LETag fraLanguageTag = 0x46524120; /* 'FRA' (French) */
+const LETag gaeLanguageTag = 0x47414520; /* 'GAE' (Gaelic) */
+const LETag hauLanguageTag = 0x48415520; /* 'HAU' (Hausa) */
+const LETag hrvLanguageTag = 0x48525620; /* 'HRV' (Croation) */
+const LETag hunLanguageTag = 0x48554E20; /* 'HUN' (Hungarian) */
+const LETag hyeLanguageTag = 0x48594520; /* 'HYE' (Armenian) */
+const LETag indLanguageTag = 0x494E4420; /* 'IND' (Indonesian) */
+const LETag itaLanguageTag = 0x49544120; /* 'ITA' (Italian) */
+const LETag khmLanguageTag = 0x4B484D20; /* 'KHM' (Khmer) */
+const LETag mngLanguageTag = 0x4D4E4720; /* 'MNG' (Mongolian) */
+const LETag mtsLanguageTag = 0x4D545320; /* 'MTS' (Maltese) */
+const LETag nepLanguageTag = 0x4E455020; /* 'NEP' (Nepali) */
+const LETag nldLanguageTag = 0x4E4C4420; /* 'NLD' (Dutch) */
+const LETag pasLanguageTag = 0x50415320; /* 'PAS' (Pashto) */
+const LETag plkLanguageTag = 0x504C4B20; /* 'PLK' (Polish) */
+const LETag ptgLanguageTag = 0x50544720; /* 'PTG' (Portuguese) */
+const LETag romLanguageTag = 0x524F4D20; /* 'ROM' (Romanian) */
+const LETag rusLanguageTag = 0x52555320; /* 'RUS' (Russian) */
+const LETag skyLanguageTag = 0x534B5920; /* 'SKY' (Slovak) */
+const LETag slvLanguageTag = 0x534C5620; /* 'SLV' (Slovenian) */
+const LETag sqiLanguageTag = 0x53514920; /* 'SQI' (Albanian) */
+const LETag srbLanguageTag = 0x53524220; /* 'SRB' (Serbian) */
+const LETag sveLanguageTag = 0x53564520; /* 'SVE' (Swedish) */
+const LETag tibLanguageTag = 0x54494220; /* 'TIB' (Tibetan) */
+const LETag trkLanguageTag = 0x54524B20; /* 'TRK' (Turkish) */
+const LETag welLanguageTag = 0x57454C20; /* 'WEL' (Welsh) */
+
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/SegmentArrayProcessor.cpp b/source/layout/SegmentArrayProcessor.cpp
new file mode 100644
index 0000000..b915cb9
--- /dev/null
+++ b/source/layout/SegmentArrayProcessor.cpp
@@ -0,0 +1,60 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "SubtableProcessor.h"
+#include "NonContextualGlyphSubst.h"
+#include "NonContextualGlyphSubstProc.h"
+#include "SegmentArrayProcessor.h"
+#include "LEGlyphStorage.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SegmentArrayProcessor)
+
+SegmentArrayProcessor::SegmentArrayProcessor()
+{
+}
+
+SegmentArrayProcessor::SegmentArrayProcessor(const MorphSubtableHeader *morphSubtableHeader)
+  : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader)
+{
+    const NonContextualGlyphSubstitutionHeader *header = (const NonContextualGlyphSubstitutionHeader *) morphSubtableHeader;
+
+    segmentArrayLookupTable = (const SegmentArrayLookupTable *) &header->table;
+}
+
+SegmentArrayProcessor::~SegmentArrayProcessor()
+{
+}
+
+void SegmentArrayProcessor::process(LEGlyphStorage &glyphStorage)
+{
+    const LookupSegment *segments = segmentArrayLookupTable->segments;
+    le_int32 glyphCount = glyphStorage.getGlyphCount();
+    le_int32 glyph;
+
+    for (glyph = 0; glyph < glyphCount; glyph += 1) {
+        LEGlyphID thisGlyph = glyphStorage[glyph];
+        const LookupSegment *lookupSegment = segmentArrayLookupTable->lookupSegment(segments, thisGlyph);
+
+        if (lookupSegment != NULL)  {
+            TTGlyphID firstGlyph = SWAPW(lookupSegment->firstGlyph);
+            le_int16  offset = SWAPW(lookupSegment->value);
+
+            if (offset != 0) {
+                TTGlyphID  *glyphArray = (TTGlyphID *) ((char *) subtableHeader + offset);
+                TTGlyphID   newGlyph   = SWAPW(glyphArray[LE_GET_GLYPH(thisGlyph) - firstGlyph]);
+                
+                glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph);
+            } 
+        }
+    }
+}
+ 
+U_NAMESPACE_END
diff --git a/source/layout/SegmentArrayProcessor.h b/source/layout/SegmentArrayProcessor.h
new file mode 100644
index 0000000..7e2028c
--- /dev/null
+++ b/source/layout/SegmentArrayProcessor.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __SEGMENTARRAYPROCESSOR_H
+#define __SEGMENTARRAYPROCESSOR_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "SubtableProcessor.h"
+#include "NonContextualGlyphSubst.h"
+#include "NonContextualGlyphSubstProc.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+class SegmentArrayProcessor : public NonContextualGlyphSubstitutionProcessor
+{
+public:
+    virtual void process(LEGlyphStorage &glyphStorage);
+
+    SegmentArrayProcessor(const MorphSubtableHeader *morphSubtableHeader);
+
+    virtual ~SegmentArrayProcessor();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.8
+     */
+    static UClassID getStaticClassID();
+
+private:
+    SegmentArrayProcessor();
+
+protected:
+    const SegmentArrayLookupTable *segmentArrayLookupTable;
+
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/SegmentSingleProcessor.cpp b/source/layout/SegmentSingleProcessor.cpp
new file mode 100644
index 0000000..75e33eb
--- /dev/null
+++ b/source/layout/SegmentSingleProcessor.cpp
@@ -0,0 +1,54 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "SubtableProcessor.h"
+#include "NonContextualGlyphSubst.h"
+#include "NonContextualGlyphSubstProc.h"
+#include "SegmentSingleProcessor.h"
+#include "LEGlyphStorage.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SegmentSingleProcessor)
+
+SegmentSingleProcessor::SegmentSingleProcessor()
+{
+}
+
+SegmentSingleProcessor::SegmentSingleProcessor(const MorphSubtableHeader *morphSubtableHeader)
+  : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader)
+{
+    const NonContextualGlyphSubstitutionHeader *header = (const NonContextualGlyphSubstitutionHeader *) morphSubtableHeader;
+
+    segmentSingleLookupTable = (const SegmentSingleLookupTable *) &header->table;
+}
+
+SegmentSingleProcessor::~SegmentSingleProcessor()
+{
+}
+
+void SegmentSingleProcessor::process(LEGlyphStorage &glyphStorage)
+{
+    const LookupSegment *segments = segmentSingleLookupTable->segments;
+    le_int32 glyphCount = glyphStorage.getGlyphCount();
+    le_int32 glyph;
+
+    for (glyph = 0; glyph < glyphCount; glyph += 1) {
+        LEGlyphID thisGlyph = glyphStorage[glyph];
+        const LookupSegment *lookupSegment = segmentSingleLookupTable->lookupSegment(segments, thisGlyph);
+
+        if (lookupSegment != NULL) {
+            TTGlyphID   newGlyph  = (TTGlyphID) LE_GET_GLYPH(thisGlyph) + SWAPW(lookupSegment->value);
+
+            glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph);
+        }
+    }
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/SegmentSingleProcessor.h b/source/layout/SegmentSingleProcessor.h
new file mode 100644
index 0000000..64b2b72
--- /dev/null
+++ b/source/layout/SegmentSingleProcessor.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __SEGMENTSINGLEPROCESSOR_H
+#define __SEGMENTSINGLEPROCESSOR_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "SubtableProcessor.h"
+#include "NonContextualGlyphSubst.h"
+#include "NonContextualGlyphSubstProc.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+class SegmentSingleProcessor : public NonContextualGlyphSubstitutionProcessor
+{
+public:
+    virtual void process(LEGlyphStorage &glyphStorage);
+
+    SegmentSingleProcessor(const MorphSubtableHeader *morphSubtableHeader);
+
+    virtual ~SegmentSingleProcessor();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.8
+     */
+    static UClassID getStaticClassID();
+
+private:
+    SegmentSingleProcessor();
+
+protected:
+    const SegmentSingleLookupTable *segmentSingleLookupTable;
+
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/ShapingTypeData.cpp b/source/layout/ShapingTypeData.cpp
new file mode 100644
index 0000000..75cf552
--- /dev/null
+++ b/source/layout/ShapingTypeData.cpp
@@ -0,0 +1,100 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008. All Rights Reserved.
+ *
+ * WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT UNLESS
+ * YOU REALLY KNOW WHAT YOU'RE DOING.
+ *
+ * Generated on: 05/29/2008 03:39:26 PM HST
+ */
+
+#include "LETypes.h"
+#include "ArabicShaping.h"
+
+U_NAMESPACE_BEGIN
+
+const le_uint8 ArabicShaping::shapingTypeTable[] = {
+    0x00, 0x02, 0x00, 0xD7, 0x00, 0xAD, 0x00, 0xAD, 0x00, 0x05, 0x03, 0x00, 0x03, 0x6F, 0x00, 0x05, 
+    0x04, 0x83, 0x04, 0x89, 0x00, 0x05, 0x05, 0x91, 0x05, 0xBD, 0x00, 0x05, 0x05, 0xBF, 0x05, 0xBF, 
+    0x00, 0x05, 0x05, 0xC1, 0x05, 0xC2, 0x00, 0x05, 0x05, 0xC4, 0x05, 0xC5, 0x00, 0x05, 0x05, 0xC7, 
+    0x05, 0xC7, 0x00, 0x05, 0x06, 0x10, 0x06, 0x1A, 0x00, 0x05, 0x06, 0x22, 0x06, 0x25, 0x00, 0x04, 
+    0x06, 0x26, 0x06, 0x26, 0x00, 0x02, 0x06, 0x27, 0x06, 0x27, 0x00, 0x04, 0x06, 0x28, 0x06, 0x28, 
+    0x00, 0x02, 0x06, 0x29, 0x06, 0x29, 0x00, 0x04, 0x06, 0x2A, 0x06, 0x2E, 0x00, 0x02, 0x06, 0x2F, 
+    0x06, 0x32, 0x00, 0x04, 0x06, 0x33, 0x06, 0x3F, 0x00, 0x02, 0x06, 0x40, 0x06, 0x40, 0x00, 0x01, 
+    0x06, 0x41, 0x06, 0x47, 0x00, 0x02, 0x06, 0x48, 0x06, 0x48, 0x00, 0x04, 0x06, 0x49, 0x06, 0x4A, 
+    0x00, 0x02, 0x06, 0x4B, 0x06, 0x5E, 0x00, 0x05, 0x06, 0x6E, 0x06, 0x6F, 0x00, 0x02, 0x06, 0x70, 
+    0x06, 0x70, 0x00, 0x05, 0x06, 0x71, 0x06, 0x73, 0x00, 0x04, 0x06, 0x75, 0x06, 0x77, 0x00, 0x04, 
+    0x06, 0x78, 0x06, 0x87, 0x00, 0x02, 0x06, 0x88, 0x06, 0x99, 0x00, 0x04, 0x06, 0x9A, 0x06, 0xBF, 
+    0x00, 0x02, 0x06, 0xC0, 0x06, 0xC0, 0x00, 0x04, 0x06, 0xC1, 0x06, 0xC2, 0x00, 0x02, 0x06, 0xC3, 
+    0x06, 0xCB, 0x00, 0x04, 0x06, 0xCC, 0x06, 0xCC, 0x00, 0x02, 0x06, 0xCD, 0x06, 0xCD, 0x00, 0x04, 
+    0x06, 0xCE, 0x06, 0xCE, 0x00, 0x02, 0x06, 0xCF, 0x06, 0xCF, 0x00, 0x04, 0x06, 0xD0, 0x06, 0xD1, 
+    0x00, 0x02, 0x06, 0xD2, 0x06, 0xD3, 0x00, 0x04, 0x06, 0xD5, 0x06, 0xD5, 0x00, 0x04, 0x06, 0xD6, 
+    0x06, 0xDC, 0x00, 0x05, 0x06, 0xDE, 0x06, 0xE4, 0x00, 0x05, 0x06, 0xE7, 0x06, 0xE8, 0x00, 0x05, 
+    0x06, 0xEA, 0x06, 0xED, 0x00, 0x05, 0x06, 0xEE, 0x06, 0xEF, 0x00, 0x04, 0x06, 0xFA, 0x06, 0xFC, 
+    0x00, 0x02, 0x06, 0xFF, 0x06, 0xFF, 0x00, 0x02, 0x07, 0x0F, 0x07, 0x0F, 0x00, 0x05, 0x07, 0x10, 
+    0x07, 0x10, 0x00, 0x04, 0x07, 0x11, 0x07, 0x11, 0x00, 0x05, 0x07, 0x12, 0x07, 0x14, 0x00, 0x02, 
+    0x07, 0x15, 0x07, 0x19, 0x00, 0x04, 0x07, 0x1A, 0x07, 0x1D, 0x00, 0x02, 0x07, 0x1E, 0x07, 0x1E, 
+    0x00, 0x04, 0x07, 0x1F, 0x07, 0x27, 0x00, 0x02, 0x07, 0x28, 0x07, 0x28, 0x00, 0x04, 0x07, 0x29, 
+    0x07, 0x29, 0x00, 0x02, 0x07, 0x2A, 0x07, 0x2A, 0x00, 0x04, 0x07, 0x2B, 0x07, 0x2B, 0x00, 0x02, 
+    0x07, 0x2C, 0x07, 0x2C, 0x00, 0x04, 0x07, 0x2D, 0x07, 0x2E, 0x00, 0x02, 0x07, 0x2F, 0x07, 0x2F, 
+    0x00, 0x04, 0x07, 0x30, 0x07, 0x4A, 0x00, 0x05, 0x07, 0x4D, 0x07, 0x4D, 0x00, 0x04, 0x07, 0x4E, 
+    0x07, 0x58, 0x00, 0x02, 0x07, 0x59, 0x07, 0x5B, 0x00, 0x04, 0x07, 0x5C, 0x07, 0x6A, 0x00, 0x02, 
+    0x07, 0x6B, 0x07, 0x6C, 0x00, 0x04, 0x07, 0x6D, 0x07, 0x70, 0x00, 0x02, 0x07, 0x71, 0x07, 0x71, 
+    0x00, 0x04, 0x07, 0x72, 0x07, 0x72, 0x00, 0x02, 0x07, 0x73, 0x07, 0x74, 0x00, 0x04, 0x07, 0x75, 
+    0x07, 0x77, 0x00, 0x02, 0x07, 0x78, 0x07, 0x79, 0x00, 0x04, 0x07, 0x7A, 0x07, 0x7F, 0x00, 0x02, 
+    0x07, 0xA6, 0x07, 0xB0, 0x00, 0x05, 0x07, 0xCA, 0x07, 0xEA, 0x00, 0x02, 0x07, 0xEB, 0x07, 0xF3, 
+    0x00, 0x05, 0x07, 0xFA, 0x07, 0xFA, 0x00, 0x01, 0x09, 0x01, 0x09, 0x02, 0x00, 0x05, 0x09, 0x3C, 
+    0x09, 0x3C, 0x00, 0x05, 0x09, 0x41, 0x09, 0x48, 0x00, 0x05, 0x09, 0x4D, 0x09, 0x4D, 0x00, 0x05, 
+    0x09, 0x51, 0x09, 0x54, 0x00, 0x05, 0x09, 0x62, 0x09, 0x63, 0x00, 0x05, 0x09, 0x81, 0x09, 0x81, 
+    0x00, 0x05, 0x09, 0xBC, 0x09, 0xBC, 0x00, 0x05, 0x09, 0xC1, 0x09, 0xC4, 0x00, 0x05, 0x09, 0xCD, 
+    0x09, 0xCD, 0x00, 0x05, 0x09, 0xE2, 0x09, 0xE3, 0x00, 0x05, 0x0A, 0x01, 0x0A, 0x02, 0x00, 0x05, 
+    0x0A, 0x3C, 0x0A, 0x3C, 0x00, 0x05, 0x0A, 0x41, 0x0A, 0x42, 0x00, 0x05, 0x0A, 0x47, 0x0A, 0x48, 
+    0x00, 0x05, 0x0A, 0x4B, 0x0A, 0x4D, 0x00, 0x05, 0x0A, 0x51, 0x0A, 0x51, 0x00, 0x05, 0x0A, 0x70, 
+    0x0A, 0x71, 0x00, 0x05, 0x0A, 0x75, 0x0A, 0x75, 0x00, 0x05, 0x0A, 0x81, 0x0A, 0x82, 0x00, 0x05, 
+    0x0A, 0xBC, 0x0A, 0xBC, 0x00, 0x05, 0x0A, 0xC1, 0x0A, 0xC5, 0x00, 0x05, 0x0A, 0xC7, 0x0A, 0xC8, 
+    0x00, 0x05, 0x0A, 0xCD, 0x0A, 0xCD, 0x00, 0x05, 0x0A, 0xE2, 0x0A, 0xE3, 0x00, 0x05, 0x0B, 0x01, 
+    0x0B, 0x01, 0x00, 0x05, 0x0B, 0x3C, 0x0B, 0x3C, 0x00, 0x05, 0x0B, 0x3F, 0x0B, 0x3F, 0x00, 0x05, 
+    0x0B, 0x41, 0x0B, 0x44, 0x00, 0x05, 0x0B, 0x4D, 0x0B, 0x4D, 0x00, 0x05, 0x0B, 0x56, 0x0B, 0x56, 
+    0x00, 0x05, 0x0B, 0x62, 0x0B, 0x63, 0x00, 0x05, 0x0B, 0x82, 0x0B, 0x82, 0x00, 0x05, 0x0B, 0xC0, 
+    0x0B, 0xC0, 0x00, 0x05, 0x0B, 0xCD, 0x0B, 0xCD, 0x00, 0x05, 0x0C, 0x3E, 0x0C, 0x40, 0x00, 0x05, 
+    0x0C, 0x46, 0x0C, 0x48, 0x00, 0x05, 0x0C, 0x4A, 0x0C, 0x4D, 0x00, 0x05, 0x0C, 0x55, 0x0C, 0x56, 
+    0x00, 0x05, 0x0C, 0x62, 0x0C, 0x63, 0x00, 0x05, 0x0C, 0xBC, 0x0C, 0xBC, 0x00, 0x05, 0x0C, 0xBF, 
+    0x0C, 0xBF, 0x00, 0x05, 0x0C, 0xC6, 0x0C, 0xC6, 0x00, 0x05, 0x0C, 0xCC, 0x0C, 0xCD, 0x00, 0x05, 
+    0x0C, 0xE2, 0x0C, 0xE3, 0x00, 0x05, 0x0D, 0x41, 0x0D, 0x44, 0x00, 0x05, 0x0D, 0x4D, 0x0D, 0x4D, 
+    0x00, 0x05, 0x0D, 0x62, 0x0D, 0x63, 0x00, 0x05, 0x0D, 0xCA, 0x0D, 0xCA, 0x00, 0x05, 0x0D, 0xD2, 
+    0x0D, 0xD4, 0x00, 0x05, 0x0D, 0xD6, 0x0D, 0xD6, 0x00, 0x05, 0x0E, 0x31, 0x0E, 0x31, 0x00, 0x05, 
+    0x0E, 0x34, 0x0E, 0x3A, 0x00, 0x05, 0x0E, 0x47, 0x0E, 0x4E, 0x00, 0x05, 0x0E, 0xB1, 0x0E, 0xB1, 
+    0x00, 0x05, 0x0E, 0xB4, 0x0E, 0xB9, 0x00, 0x05, 0x0E, 0xBB, 0x0E, 0xBC, 0x00, 0x05, 0x0E, 0xC8, 
+    0x0E, 0xCD, 0x00, 0x05, 0x0F, 0x18, 0x0F, 0x19, 0x00, 0x05, 0x0F, 0x35, 0x0F, 0x35, 0x00, 0x05, 
+    0x0F, 0x37, 0x0F, 0x37, 0x00, 0x05, 0x0F, 0x39, 0x0F, 0x39, 0x00, 0x05, 0x0F, 0x71, 0x0F, 0x7E, 
+    0x00, 0x05, 0x0F, 0x80, 0x0F, 0x84, 0x00, 0x05, 0x0F, 0x86, 0x0F, 0x87, 0x00, 0x05, 0x0F, 0x90, 
+    0x0F, 0x97, 0x00, 0x05, 0x0F, 0x99, 0x0F, 0xBC, 0x00, 0x05, 0x0F, 0xC6, 0x0F, 0xC6, 0x00, 0x05, 
+    0x10, 0x2D, 0x10, 0x30, 0x00, 0x05, 0x10, 0x32, 0x10, 0x37, 0x00, 0x05, 0x10, 0x39, 0x10, 0x3A, 
+    0x00, 0x05, 0x10, 0x3D, 0x10, 0x3E, 0x00, 0x05, 0x10, 0x58, 0x10, 0x59, 0x00, 0x05, 0x10, 0x5E, 
+    0x10, 0x60, 0x00, 0x05, 0x10, 0x71, 0x10, 0x74, 0x00, 0x05, 0x10, 0x82, 0x10, 0x82, 0x00, 0x05, 
+    0x10, 0x85, 0x10, 0x86, 0x00, 0x05, 0x10, 0x8D, 0x10, 0x8D, 0x00, 0x05, 0x13, 0x5F, 0x13, 0x5F, 
+    0x00, 0x05, 0x17, 0x12, 0x17, 0x14, 0x00, 0x05, 0x17, 0x32, 0x17, 0x34, 0x00, 0x05, 0x17, 0x52, 
+    0x17, 0x53, 0x00, 0x05, 0x17, 0x72, 0x17, 0x73, 0x00, 0x05, 0x17, 0xB4, 0x17, 0xB5, 0x00, 0x05, 
+    0x17, 0xB7, 0x17, 0xBD, 0x00, 0x05, 0x17, 0xC6, 0x17, 0xC6, 0x00, 0x05, 0x17, 0xC9, 0x17, 0xD3, 
+    0x00, 0x05, 0x17, 0xDD, 0x17, 0xDD, 0x00, 0x05, 0x18, 0x0B, 0x18, 0x0D, 0x00, 0x05, 0x18, 0xA9, 
+    0x18, 0xA9, 0x00, 0x05, 0x19, 0x20, 0x19, 0x22, 0x00, 0x05, 0x19, 0x27, 0x19, 0x28, 0x00, 0x05, 
+    0x19, 0x32, 0x19, 0x32, 0x00, 0x05, 0x19, 0x39, 0x19, 0x3B, 0x00, 0x05, 0x1A, 0x17, 0x1A, 0x18, 
+    0x00, 0x05, 0x1B, 0x00, 0x1B, 0x03, 0x00, 0x05, 0x1B, 0x34, 0x1B, 0x34, 0x00, 0x05, 0x1B, 0x36, 
+    0x1B, 0x3A, 0x00, 0x05, 0x1B, 0x3C, 0x1B, 0x3C, 0x00, 0x05, 0x1B, 0x42, 0x1B, 0x42, 0x00, 0x05, 
+    0x1B, 0x6B, 0x1B, 0x73, 0x00, 0x05, 0x1B, 0x80, 0x1B, 0x81, 0x00, 0x05, 0x1B, 0xA2, 0x1B, 0xA5, 
+    0x00, 0x05, 0x1B, 0xA8, 0x1B, 0xA9, 0x00, 0x05, 0x1C, 0x2C, 0x1C, 0x33, 0x00, 0x05, 0x1C, 0x36, 
+    0x1C, 0x37, 0x00, 0x05, 0x1D, 0xC0, 0x1D, 0xE6, 0x00, 0x05, 0x1D, 0xFE, 0x1D, 0xFF, 0x00, 0x05, 
+    0x20, 0x0B, 0x20, 0x0B, 0x00, 0x05, 0x20, 0x0D, 0x20, 0x0D, 0x00, 0x01, 0x20, 0x0E, 0x20, 0x0F, 
+    0x00, 0x05, 0x20, 0x2A, 0x20, 0x2E, 0x00, 0x05, 0x20, 0x60, 0x20, 0x64, 0x00, 0x05, 0x20, 0x6A, 
+    0x20, 0x6F, 0x00, 0x05, 0x20, 0xD0, 0x20, 0xF0, 0x00, 0x05, 0x2D, 0xE0, 0x2D, 0xFF, 0x00, 0x05, 
+    0x30, 0x2A, 0x30, 0x2F, 0x00, 0x05, 0x30, 0x99, 0x30, 0x9A, 0x00, 0x05, 0xA6, 0x6F, 0xA6, 0x72, 
+    0x00, 0x05, 0xA6, 0x7C, 0xA6, 0x7D, 0x00, 0x05, 0xA8, 0x02, 0xA8, 0x02, 0x00, 0x05, 0xA8, 0x06, 
+    0xA8, 0x06, 0x00, 0x05, 0xA8, 0x0B, 0xA8, 0x0B, 0x00, 0x05, 0xA8, 0x25, 0xA8, 0x26, 0x00, 0x05, 
+    0xA8, 0xC4, 0xA8, 0xC4, 0x00, 0x05, 0xA9, 0x26, 0xA9, 0x2D, 0x00, 0x05, 0xA9, 0x47, 0xA9, 0x51, 
+    0x00, 0x05, 0xAA, 0x29, 0xAA, 0x2E, 0x00, 0x05, 0xAA, 0x31, 0xAA, 0x32, 0x00, 0x05, 0xAA, 0x35, 
+    0xAA, 0x36, 0x00, 0x05, 0xAA, 0x43, 0xAA, 0x43, 0x00, 0x05, 0xAA, 0x4C, 0xAA, 0x4C, 0x00, 0x05, 
+    0xFB, 0x1E, 0xFB, 0x1E, 0x00, 0x05, 0xFE, 0x00, 0xFE, 0x0F, 0x00, 0x05, 0xFE, 0x20, 0xFE, 0x26, 
+    0x00, 0x05, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x05, 0xFF, 0xF9, 0xFF, 0xFB, 0x00, 0x05
+};
+
+U_NAMESPACE_END
diff --git a/source/layout/SimpleArrayProcessor.cpp b/source/layout/SimpleArrayProcessor.cpp
new file mode 100644
index 0000000..d677f54
--- /dev/null
+++ b/source/layout/SimpleArrayProcessor.cpp
@@ -0,0 +1,51 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "SubtableProcessor.h"
+#include "NonContextualGlyphSubst.h"
+#include "NonContextualGlyphSubstProc.h"
+#include "SimpleArrayProcessor.h"
+#include "LEGlyphStorage.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleArrayProcessor)
+
+SimpleArrayProcessor::SimpleArrayProcessor()
+{
+}
+
+SimpleArrayProcessor::SimpleArrayProcessor(const MorphSubtableHeader *morphSubtableHeader)
+  : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader)
+{
+    const NonContextualGlyphSubstitutionHeader *header = (const NonContextualGlyphSubstitutionHeader *) morphSubtableHeader;
+
+    simpleArrayLookupTable = (const SimpleArrayLookupTable *) &header->table;
+}
+
+SimpleArrayProcessor::~SimpleArrayProcessor()
+{
+}
+
+void SimpleArrayProcessor::process(LEGlyphStorage &glyphStorage)
+{
+    le_int32 glyphCount = glyphStorage.getGlyphCount();
+    le_int32 glyph;
+
+    for (glyph = 0; glyph < glyphCount; glyph += 1) {
+        LEGlyphID thisGlyph = glyphStorage[glyph];
+        if (LE_GET_GLYPH(thisGlyph) < 0xFFFF) {
+            TTGlyphID newGlyph = SWAPW(simpleArrayLookupTable->valueArray[LE_GET_GLYPH(thisGlyph)]);
+
+            glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph);
+        }
+    }
+}
+ 
+U_NAMESPACE_END
diff --git a/source/layout/SimpleArrayProcessor.h b/source/layout/SimpleArrayProcessor.h
new file mode 100644
index 0000000..afee79c
--- /dev/null
+++ b/source/layout/SimpleArrayProcessor.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __SIMPLEARRAYPROCESSOR_H
+#define __SIMPLEARRAYPROCESSOR_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "SubtableProcessor.h"
+#include "NonContextualGlyphSubst.h"
+#include "NonContextualGlyphSubstProc.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+class SimpleArrayProcessor : public NonContextualGlyphSubstitutionProcessor
+{
+public:
+    virtual void process(LEGlyphStorage &glyphStorage);
+
+    SimpleArrayProcessor(const MorphSubtableHeader *morphSubtableHeader);
+
+    virtual ~SimpleArrayProcessor();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.8
+     */
+    static UClassID getStaticClassID();
+
+private:
+    SimpleArrayProcessor();
+
+protected:
+    const SimpleArrayLookupTable *simpleArrayLookupTable;
+
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/SinglePositioningSubtables.cpp b/source/layout/SinglePositioningSubtables.cpp
new file mode 100644
index 0000000..e8759d2
--- /dev/null
+++ b/source/layout/SinglePositioningSubtables.cpp
@@ -0,0 +1,72 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "GlyphPositioningTables.h"
+#include "SinglePositioningSubtables.h"
+#include "ValueRecords.h"
+#include "GlyphIterator.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+le_uint32 SinglePositioningSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const
+{
+    switch(SWAPW(subtableFormat))
+    {
+    case 0:
+        return 0;
+
+    case 1:
+    {
+        const SinglePositioningFormat1Subtable *subtable = (const SinglePositioningFormat1Subtable *) this;
+
+        return subtable->process(glyphIterator, fontInstance);
+    }
+
+    case 2:
+    {
+        const SinglePositioningFormat2Subtable *subtable = (const SinglePositioningFormat2Subtable *) this;
+
+        return subtable->process(glyphIterator, fontInstance);
+    }
+
+    default:
+        return 0;
+    }
+}
+
+le_uint32 SinglePositioningFormat1Subtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const
+{
+    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
+    le_int32 coverageIndex = getGlyphCoverage(glyph);
+
+    if (coverageIndex >= 0) {
+        valueRecord.adjustPosition(SWAPW(valueFormat), (const char *) this, *glyphIterator, fontInstance);
+
+        return 1;
+    }
+
+    return 0;
+}
+
+le_uint32 SinglePositioningFormat2Subtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const
+{
+    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
+    le_int16 coverageIndex = (le_int16) getGlyphCoverage(glyph);
+
+    if (coverageIndex >= 0) {
+        valueRecordArray[0].adjustPosition(coverageIndex, SWAPW(valueFormat), (const char *) this, *glyphIterator, fontInstance);
+
+        return 1;
+    }
+
+    return 0;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/SinglePositioningSubtables.h b/source/layout/SinglePositioningSubtables.h
new file mode 100644
index 0000000..ec2ffcc
--- /dev/null
+++ b/source/layout/SinglePositioningSubtables.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __SINGLEPOSITIONINGSUBTABLES_H
+#define __SINGLEPOSITIONINGSUBTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "GlyphPositioningTables.h"
+#include "ValueRecords.h"
+#include "GlyphIterator.h"
+
+U_NAMESPACE_BEGIN
+
+struct SinglePositioningSubtable : GlyphPositioningSubtable
+{
+    le_uint32  process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const;
+};
+
+struct SinglePositioningFormat1Subtable : SinglePositioningSubtable
+{
+    ValueFormat valueFormat;
+    ValueRecord valueRecord;
+
+    le_uint32  process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const;
+};
+
+struct SinglePositioningFormat2Subtable : SinglePositioningSubtable
+{
+    ValueFormat valueFormat;
+    le_uint16   valueCount;
+    ValueRecord valueRecordArray[ANY_NUMBER];
+
+    le_uint32  process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const;
+};
+
+U_NAMESPACE_END
+#endif
+
+
diff --git a/source/layout/SingleSubstitutionSubtables.cpp b/source/layout/SingleSubstitutionSubtables.cpp
new file mode 100644
index 0000000..ae72ddf
--- /dev/null
+++ b/source/layout/SingleSubstitutionSubtables.cpp
@@ -0,0 +1,79 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEGlyphFilter.h"
+#include "OpenTypeTables.h"
+#include "GlyphSubstitutionTables.h"
+#include "SingleSubstitutionSubtables.h"
+#include "GlyphIterator.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+le_uint32 SingleSubstitutionSubtable::process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter) const
+{
+    switch(SWAPW(subtableFormat))
+    {
+    case 0:
+        return 0;
+
+    case 1:
+    {
+        const SingleSubstitutionFormat1Subtable *subtable = (const SingleSubstitutionFormat1Subtable *) this;
+
+        return subtable->process(glyphIterator, filter);
+    }
+
+    case 2:
+    {
+        const SingleSubstitutionFormat2Subtable *subtable = (const SingleSubstitutionFormat2Subtable *) this;
+
+        return subtable->process(glyphIterator, filter);
+    }
+
+    default:
+        return 0;
+    }
+}
+
+le_uint32 SingleSubstitutionFormat1Subtable::process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter) const
+{
+    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
+    le_int32 coverageIndex = getGlyphCoverage(glyph);
+
+    if (coverageIndex >= 0) {
+        TTGlyphID substitute = ((TTGlyphID) LE_GET_GLYPH(glyph)) + SWAPW(deltaGlyphID);
+
+        if (filter == NULL || filter->accept(LE_SET_GLYPH(glyph, substitute))) {
+            glyphIterator->setCurrGlyphID(substitute);
+        }
+
+        return 1;
+    }
+
+    return 0;
+}
+
+le_uint32 SingleSubstitutionFormat2Subtable::process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter) const
+{
+    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
+    le_int32 coverageIndex = getGlyphCoverage(glyph);
+
+    if (coverageIndex >= 0) {
+        TTGlyphID substitute = SWAPW(substituteArray[coverageIndex]);
+
+        if (filter == NULL || filter->accept(LE_SET_GLYPH(glyph, substitute))) {
+            glyphIterator->setCurrGlyphID(substitute);
+        }
+
+        return 1;
+    }
+
+    return 0;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/SingleSubstitutionSubtables.h b/source/layout/SingleSubstitutionSubtables.h
new file mode 100644
index 0000000..dfd2dad
--- /dev/null
+++ b/source/layout/SingleSubstitutionSubtables.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __SINGLESUBSTITUTIONSUBTABLES_H
+#define __SINGLESUBSTITUTIONSUBTABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEGlyphFilter.h"
+#include "OpenTypeTables.h"
+#include "GlyphSubstitutionTables.h"
+#include "GlyphIterator.h"
+
+U_NAMESPACE_BEGIN
+
+struct SingleSubstitutionSubtable : GlyphSubstitutionSubtable
+{
+    le_uint32  process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter = NULL) const;
+};
+
+struct SingleSubstitutionFormat1Subtable : SingleSubstitutionSubtable
+{
+    le_int16   deltaGlyphID;
+
+    le_uint32  process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter = NULL) const;
+};
+
+struct SingleSubstitutionFormat2Subtable : SingleSubstitutionSubtable
+{
+    le_uint16  glyphCount;
+    TTGlyphID  substituteArray[ANY_NUMBER];
+
+    le_uint32  process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter = NULL) const;
+};
+
+U_NAMESPACE_END
+#endif
+
+
diff --git a/source/layout/SingleTableProcessor.cpp b/source/layout/SingleTableProcessor.cpp
new file mode 100644
index 0000000..94a4edd
--- /dev/null
+++ b/source/layout/SingleTableProcessor.cpp
@@ -0,0 +1,51 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "SubtableProcessor.h"
+#include "NonContextualGlyphSubst.h"
+#include "NonContextualGlyphSubstProc.h"
+#include "SingleTableProcessor.h"
+#include "LEGlyphStorage.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SingleTableProcessor)
+
+SingleTableProcessor::SingleTableProcessor()
+{
+}
+
+SingleTableProcessor::SingleTableProcessor(const MorphSubtableHeader *moprhSubtableHeader)
+  : NonContextualGlyphSubstitutionProcessor(moprhSubtableHeader)
+{
+    const NonContextualGlyphSubstitutionHeader *header = (const NonContextualGlyphSubstitutionHeader *) moprhSubtableHeader;
+
+    singleTableLookupTable = (const SingleTableLookupTable *) &header->table;
+}
+
+SingleTableProcessor::~SingleTableProcessor()
+{
+}
+
+void SingleTableProcessor::process(LEGlyphStorage &glyphStorage)
+{
+    const LookupSingle *entries = singleTableLookupTable->entries;
+    le_int32 glyph;
+    le_int32 glyphCount = glyphStorage.getGlyphCount();
+
+    for (glyph = 0; glyph < glyphCount; glyph += 1) {
+        const LookupSingle *lookupSingle = singleTableLookupTable->lookupSingle(entries, glyphStorage[glyph]);
+
+        if (lookupSingle != NULL) {
+            glyphStorage[glyph] = SWAPW(lookupSingle->value);
+        }
+    }
+} 
+
+U_NAMESPACE_END
diff --git a/source/layout/SingleTableProcessor.h b/source/layout/SingleTableProcessor.h
new file mode 100644
index 0000000..d6ca048
--- /dev/null
+++ b/source/layout/SingleTableProcessor.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __SINGLETABLEPROCESSOR_H
+#define __SINGLETABLEPROCESSOR_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "SubtableProcessor.h"
+#include "NonContextualGlyphSubst.h"
+#include "NonContextualGlyphSubstProc.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+class SingleTableProcessor : public NonContextualGlyphSubstitutionProcessor
+{
+public:
+    virtual void process(LEGlyphStorage &glyphStorage);
+
+    SingleTableProcessor(const MorphSubtableHeader *morphSubtableHeader);
+
+    virtual ~SingleTableProcessor();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.8
+     */
+    static UClassID getStaticClassID();
+
+private:
+    SingleTableProcessor();
+
+protected:
+    const SingleTableLookupTable *singleTableLookupTable;
+
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/StateTableProcessor.cpp b/source/layout/StateTableProcessor.cpp
new file mode 100644
index 0000000..223959b
--- /dev/null
+++ b/source/layout/StateTableProcessor.cpp
@@ -0,0 +1,77 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "StateTables.h"
+#include "MorphStateTables.h"
+#include "SubtableProcessor.h"
+#include "StateTableProcessor.h"
+#include "LEGlyphStorage.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+StateTableProcessor::StateTableProcessor()
+{
+}
+
+StateTableProcessor::StateTableProcessor(const MorphSubtableHeader *morphSubtableHeader)
+  : SubtableProcessor(morphSubtableHeader)
+{
+    stateTableHeader = (const MorphStateTableHeader *) morphSubtableHeader;
+
+    stateSize = SWAPW(stateTableHeader->stHeader.stateSize);
+    classTableOffset = SWAPW(stateTableHeader->stHeader.classTableOffset);
+    stateArrayOffset = SWAPW(stateTableHeader->stHeader.stateArrayOffset);
+    entryTableOffset = SWAPW(stateTableHeader->stHeader.entryTableOffset);
+
+    classTable = (const ClassTable *) ((char *) &stateTableHeader->stHeader + classTableOffset);
+    firstGlyph = SWAPW(classTable->firstGlyph);
+    lastGlyph  = firstGlyph + SWAPW(classTable->nGlyphs);
+}
+
+StateTableProcessor::~StateTableProcessor()
+{
+}
+
+void StateTableProcessor::process(LEGlyphStorage &glyphStorage)
+{
+    // Start at state 0
+    // XXX: How do we know when to start at state 1?
+    ByteOffset currentState = stateArrayOffset;
+
+    // XXX: reverse? 
+    le_int32 currGlyph = 0;
+    le_int32 glyphCount = glyphStorage.getGlyphCount();
+
+    beginStateTable();
+
+    while (currGlyph <= glyphCount) {
+        ClassCode classCode = classCodeOOB;
+        if (currGlyph == glyphCount) {
+            // XXX: How do we handle EOT vs. EOL?
+            classCode = classCodeEOT;
+        } else {
+            TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(glyphStorage[currGlyph]);
+
+            if (glyphCode == 0xFFFF) {
+                classCode = classCodeDEL;
+            } else if ((glyphCode >= firstGlyph) && (glyphCode < lastGlyph)) {
+                classCode = classTable->classArray[glyphCode - firstGlyph];
+            }
+        }
+
+        const EntryTableIndex *stateArray = (const EntryTableIndex *) ((char *) &stateTableHeader->stHeader + currentState);
+        EntryTableIndex entryTableIndex = stateArray[(le_uint8)classCode];
+
+        currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex);
+    }
+
+    endStateTable();
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/StateTableProcessor.h b/source/layout/StateTableProcessor.h
new file mode 100644
index 0000000..41c50de
--- /dev/null
+++ b/source/layout/StateTableProcessor.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __STATETABLEPROCESSOR_H
+#define __STATETABLEPROCESSOR_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "MorphStateTables.h"
+#include "SubtableProcessor.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+class StateTableProcessor : public SubtableProcessor
+{
+public:
+    void process(LEGlyphStorage &glyphStorage);
+
+    virtual void beginStateTable() = 0;
+
+    virtual ByteOffset processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex index) = 0;
+
+    virtual void endStateTable() = 0;
+
+protected:
+    StateTableProcessor(const MorphSubtableHeader *morphSubtableHeader);
+    virtual ~StateTableProcessor();
+
+    StateTableProcessor();
+
+    le_int16 stateSize;
+    ByteOffset classTableOffset;
+    ByteOffset stateArrayOffset;
+    ByteOffset entryTableOffset;
+
+    const ClassTable *classTable;
+    TTGlyphID firstGlyph;
+    TTGlyphID lastGlyph;
+
+    const MorphStateTableHeader *stateTableHeader;
+
+private:
+    StateTableProcessor(const StateTableProcessor &other); // forbid copying of this class
+    StateTableProcessor &operator=(const StateTableProcessor &other); // forbid copying of this class
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/StateTables.h b/source/layout/StateTables.h
new file mode 100644
index 0000000..8b5f867
--- /dev/null
+++ b/source/layout/StateTables.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __STATETABLES_H
+#define __STATETABLES_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LayoutTables.h"
+
+U_NAMESPACE_BEGIN
+
+struct StateTableHeader
+{
+    le_int16 stateSize;
+    ByteOffset classTableOffset;
+    ByteOffset stateArrayOffset;
+    ByteOffset entryTableOffset;
+};
+
+enum ClassCodes
+{
+    classCodeEOT = 0,
+    classCodeOOB = 1,
+    classCodeDEL = 2,
+    classCodeEOL = 3,
+    classCodeFirstFree = 4,
+    classCodeMAX = 0xFF
+};
+
+typedef le_uint8 ClassCode;
+
+struct ClassTable
+{
+    TTGlyphID firstGlyph;
+    le_uint16 nGlyphs;
+    ClassCode classArray[ANY_NUMBER];
+};
+
+enum StateNumber
+{
+    stateSOT        = 0,
+    stateSOL        = 1,
+    stateFirstFree  = 2,
+    stateMAX        = 0xFF
+};
+
+typedef le_uint8 EntryTableIndex;
+
+struct StateEntry
+{
+    ByteOffset  newStateOffset;
+    le_int16    flags;
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/SubstitutionLookups.cpp b/source/layout/SubstitutionLookups.cpp
new file mode 100644
index 0000000..1fb2813
--- /dev/null
+++ b/source/layout/SubstitutionLookups.cpp
@@ -0,0 +1,51 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "GlyphSubstitutionTables.h"
+#include "GlyphIterator.h"
+#include "LookupProcessor.h"
+#include "SubstitutionLookups.h"
+#include "CoverageTables.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+/*
+    NOTE: This could be optimized somewhat by keeping track
+    of the previous sequenceIndex in the loop and doing next()
+    or prev() of the delta between that and the current
+    sequenceIndex instead of always resetting to the front.
+*/
+void SubstitutionLookup::applySubstitutionLookups(
+        LookupProcessor *lookupProcessor,
+        SubstitutionLookupRecord *substLookupRecordArray,
+        le_uint16 substCount,
+        GlyphIterator *glyphIterator,
+        const LEFontInstance *fontInstance,
+        le_int32 position,
+        LEErrorCode& success)
+{
+    if (LE_FAILURE(success)) { 
+        return;
+    }
+
+    GlyphIterator tempIterator(*glyphIterator);
+
+    for (le_uint16 subst = 0; subst < substCount && LE_SUCCESS(success); subst += 1) {
+        le_uint16 sequenceIndex = SWAPW(substLookupRecordArray[subst].sequenceIndex);
+        le_uint16 lookupListIndex = SWAPW(substLookupRecordArray[subst].lookupListIndex);
+
+        tempIterator.setCurrStreamPosition(position);
+        tempIterator.next(sequenceIndex);
+
+        lookupProcessor->applySingleLookup(lookupListIndex, &tempIterator, fontInstance, success);
+    }
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/SubstitutionLookups.h b/source/layout/SubstitutionLookups.h
new file mode 100644
index 0000000..582b6f6
--- /dev/null
+++ b/source/layout/SubstitutionLookups.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#ifndef __SUBSTITUTIONLOOKUPS_H
+#define __SUBSTITUTIONLOOKUPS_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "GlyphSubstitutionTables.h"
+#include "GlyphIterator.h"
+#include "LookupProcessor.h"
+
+U_NAMESPACE_BEGIN
+
+struct SubstitutionLookupRecord
+{
+    le_uint16  sequenceIndex;
+    le_uint16  lookupListIndex;
+};
+
+struct SubstitutionLookup
+{
+    static void applySubstitutionLookups(
+        LookupProcessor *lookupProcessor, 
+        SubstitutionLookupRecord *substLookupRecordArray,
+        le_uint16 substCount,
+        GlyphIterator *glyphIterator,
+        const LEFontInstance *fontInstance,
+        le_int32 position,
+		LEErrorCode& success);
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/SubtableProcessor.cpp b/source/layout/SubtableProcessor.cpp
new file mode 100644
index 0000000..dd5ce18
--- /dev/null
+++ b/source/layout/SubtableProcessor.cpp
@@ -0,0 +1,31 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "SubtableProcessor.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+SubtableProcessor::SubtableProcessor()
+{
+}
+
+SubtableProcessor::SubtableProcessor(const MorphSubtableHeader *morphSubtableHeader)
+{
+    subtableHeader = morphSubtableHeader;
+
+    length = SWAPW(subtableHeader->length);
+    coverage = SWAPW(subtableHeader->coverage);
+    subtableFeatures = SWAPL(subtableHeader->subtableFeatures);
+}
+
+SubtableProcessor::~SubtableProcessor()
+{
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/SubtableProcessor.h b/source/layout/SubtableProcessor.h
new file mode 100644
index 0000000..f304cb9
--- /dev/null
+++ b/source/layout/SubtableProcessor.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __SUBTABLEPROCESSOR_H
+#define __SUBTABLEPROCESSOR_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+class SubtableProcessor : public UMemory {
+public:
+    virtual void process(LEGlyphStorage &glyphStorage) = 0;
+    virtual ~SubtableProcessor();
+
+protected:
+    SubtableProcessor(const MorphSubtableHeader *morphSubtableHeader);
+
+    SubtableProcessor();
+
+    le_int16 length;
+    SubtableCoverage coverage;
+    FeatureFlags subtableFeatures;
+
+    const MorphSubtableHeader *subtableHeader;
+
+private:
+
+    SubtableProcessor(const SubtableProcessor &other); // forbid copying of this class
+    SubtableProcessor &operator=(const SubtableProcessor &other); // forbid copying of this class
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/ThaiLayoutEngine.cpp b/source/layout/ThaiLayoutEngine.cpp
new file mode 100644
index 0000000..f9d77a7
--- /dev/null
+++ b/source/layout/ThaiLayoutEngine.cpp
@@ -0,0 +1,123 @@
+
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LayoutEngine.h"
+#include "ThaiLayoutEngine.h"
+#include "ScriptAndLanguageTags.h"
+#include "LEGlyphStorage.h"
+
+#include "KernTable.h"
+
+#include "ThaiShaping.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ThaiLayoutEngine)
+
+ThaiLayoutEngine::ThaiLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success)
+    : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success)
+{
+    fErrorChar = 0x25CC;
+
+    // Figure out which presentation forms the font uses
+    if (! fontInstance->canDisplay(0x0E01)) {
+        // No Thai in font; don't use presentation forms.
+        fGlyphSet = 3;
+    } else if (fontInstance->canDisplay(0x0E64)) {
+        // WorldType uses reserved space in Thai block
+        fGlyphSet = 0;
+    } else if (fontInstance->canDisplay(0xF701)) {
+        // Microsoft corporate zone
+        fGlyphSet = 1;
+
+        if (!fontInstance->canDisplay(fErrorChar)) {
+            fErrorChar = 0xF71B;
+        }
+    } else if (fontInstance->canDisplay(0xF885)) {
+        // Apple corporate zone
+        fGlyphSet = 2;
+    } else {
+        // no presentation forms in the font
+        fGlyphSet = 3;
+    }
+}
+
+ThaiLayoutEngine::~ThaiLayoutEngine()
+{
+    // nothing to do
+}
+
+// Input: characters (0..max provided for context)
+// Output: glyphs, char indices
+// Returns: the glyph count
+// NOTE: this assumes that ThaiShaping::compose will allocate the outChars array...
+le_int32 ThaiLayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool /*rightToLeft*/, LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    LEUnicode *outChars;
+    le_int32 glyphCount;
+    
+    // This is enough room for the worst-case expansion
+    // (it says here...)
+    outChars = LE_NEW_ARRAY(LEUnicode, count * 2);
+
+    if (outChars == NULL) {
+        success = LE_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
+
+    glyphStorage.allocateGlyphArray(count * 2, FALSE, success);
+
+    if (LE_FAILURE(success)) {
+        LE_DELETE_ARRAY(outChars);
+        success = LE_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
+
+    glyphCount = ThaiShaping::compose(chars, offset, count, fGlyphSet, fErrorChar, outChars, glyphStorage);
+    mapCharsToGlyphs(outChars, 0, glyphCount, FALSE, FALSE, glyphStorage, success);
+
+    LE_DELETE_ARRAY(outChars);
+
+    glyphStorage.adoptGlyphCount(glyphCount);
+    return glyphCount;
+}
+
+// This is the same as LayoutEngline::adjustGlyphPositions() except that it doesn't call adjustMarkGlyphs
+void ThaiLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool  /*reverse*/,
+                                        LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    if (fTypoFlags & 0x1) { /* kerning enabled */
+      static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG;
+
+      KernTable kt(fFontInstance, getFontTable(kernTableTag));
+      kt.process(glyphStorage);
+    }
+
+    // default is no adjustments
+    return;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/ThaiLayoutEngine.h b/source/layout/ThaiLayoutEngine.h
new file mode 100644
index 0000000..08a154d
--- /dev/null
+++ b/source/layout/ThaiLayoutEngine.h
@@ -0,0 +1,144 @@
+
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#ifndef __THAILAYOUTENGINE_H
+#define __THAILAYOUTENGINE_H
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "LayoutEngine.h"
+
+#include "ThaiShaping.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+/**
+ * This class implements layout for the Thai script, using the ThaiShapingClass.
+ * All existing Thai fonts use an encoding which assigns character codes to all
+ * the variant forms needed to display accents and tone marks correctly in context.
+ * This class can deal with fonts using the Microsoft, Macintosh, and WorldType encodings.
+ *
+ * @internal
+ */
+class ThaiLayoutEngine : public LayoutEngine
+{
+public:
+    /**
+     * This constructs an instance of ThaiLayoutEngine for the given font, script and
+     * language. It examines the font, using LEFontInstance::canDisplay, to set fGlyphSet
+     * and fErrorChar. (see below)
+     *
+     * @param fontInstance - the font
+     * @param scriptCode - the script
+     * @param languageCode - the language
+     * @param success - set to an error code if the operation fails
+     *
+     * @see LEFontInstance
+     * @see ScriptAndLanguageTags.h for script and language codes
+     *
+     * @internal
+     */
+    ThaiLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success);
+
+    /**
+     * The destructor, virtual for correct polymorphic invocation.
+     *
+     * @internal
+     */
+    virtual ~ThaiLayoutEngine();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.8
+     */
+    static UClassID getStaticClassID();
+
+protected:
+    /**
+     * A small integer indicating which Thai encoding
+     * the font uses.
+     *
+     * @see ThaiShaping
+     *
+     * @internal
+     */
+    le_uint8 fGlyphSet;
+
+    /**
+     * The character used as a base for vowels and
+     * tone marks that are out of sequence. Usually
+     * this will be Unicode 0x25CC, if the font can
+     * display it.
+     *
+     * @see ThaiShaping
+     *
+     * @internal
+     */
+    LEUnicode fErrorChar;
+
+    /**
+     * This method performs Thai layout. It calls ThaiShaping::compose to
+     * generate the correct contextual character codes, and then calls
+     * mapCharsToGlyphs to generate the glyph indices.
+     *
+     * Input parameters:
+     * @param chars - the input character context
+     * @param offset - the index of the first character to process
+     * @param count - the number of characters to process
+     * @param max - the number of characters in the input context
+     * @param rightToLeft - <code>TRUE</code> if the text is in a right to left directional run
+     * @param glyphStorage - the glyph storage object. The glyph and char index arrays will be set.
+     *
+     * Output parameters:
+     * @param success - set to an error code if the operation fails
+     *
+     * @return the number of glyphs in the glyph index array
+     *
+     * @see ThaiShaping
+     *
+     * @internal
+     */
+    virtual le_int32 computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+        LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+    /**
+     * This method does positioning adjustments like accent positioning and
+     * kerning. The default implementation does nothing. Subclasses needing
+     * position adjustments must override this method.
+     *
+     * Note that this method has both characters and glyphs as input so that
+     * it can use the character codes to determine glyph types if that information
+     * isn't directly available. (e.g. Some Arabic OpenType fonts don't have a GDEF
+     * table)
+     *
+     * @param chars - the input character context
+     * @param offset - the offset of the first character to process
+     * @param count - the number of characters to process
+     * @param reverse - <code>TRUE</code> if the glyphs in the glyph array have been reordered
+     * @param glyphStorage - the object which holds the per-glyph storage. The glyph positions will be
+     *                       adjusted as needed.
+     * @param success - output parameter set to an error code if the operation fails
+     *
+     * @internal
+     */
+    virtual void adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/ThaiShaping.cpp b/source/layout/ThaiShaping.cpp
new file mode 100644
index 0000000..1680f0f
--- /dev/null
+++ b/source/layout/ThaiShaping.cpp
@@ -0,0 +1,307 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEGlyphFilter.h"
+#include "OpenTypeTables.h"
+#include "LEGlyphStorage.h"
+#include "ThaiShaping.h"
+
+U_NAMESPACE_BEGIN
+
+enum {
+    CH_SPACE        = 0x0020,
+    CH_YAMAKKAN     = 0x0E4E,
+    CH_MAI_HANAKAT  = 0x0E31,
+    CH_SARA_AA      = 0x0E32,
+    CH_SARA_AM      = 0x0E33,
+    CH_SARA_UEE     = 0x0E37,
+    CH_MAITAIKHU    = 0x0E47,
+    CH_NIKHAHIT     = 0x0E4D,
+    CH_SARA_U       = 0x0E38,
+    CH_PHINTHU      = 0x0E3A,
+    CH_YO_YING      = 0x0E0D,
+    CH_THO_THAN     = 0x0E10,
+    CH_DOTTED_CIRCLE = 0x25CC
+};
+
+    le_uint8 ThaiShaping::getCharClass(LEUnicode ch)
+{
+    le_uint8 charClass = NON;
+    
+    if (ch >= 0x0E00 && ch <= 0x0E5B) {
+        charClass = classTable[ch - 0x0E00];
+    }
+    
+    return charClass;
+}
+
+
+LEUnicode ThaiShaping::leftAboveVowel(LEUnicode vowel, le_uint8 glyphSet)
+{
+    static const LEUnicode leftAboveVowels[][7] = {
+        {0x0E61, 0x0E32, 0x0E33, 0x0E64, 0x0E65, 0x0E66, 0x0E67},
+        {0xF710, 0x0E32, 0x0E33, 0xF701, 0xF702, 0xF703, 0xF704},
+        {0xF884, 0x0E32, 0x0E33, 0xF885, 0xF886, 0xF887, 0xF788},
+        {0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37}
+    };
+   
+    if (vowel >= CH_MAI_HANAKAT && vowel <= CH_SARA_UEE) {
+        return leftAboveVowels[glyphSet][vowel - CH_MAI_HANAKAT];
+    }
+    
+    if (vowel == CH_YAMAKKAN && glyphSet == 0) {
+        return 0x0E7E;
+    }
+    
+    return vowel;
+}
+
+LEUnicode ThaiShaping::lowerRightTone(LEUnicode tone, le_uint8 glyphSet)
+{
+    static const LEUnicode lowerRightTones[][7] = {
+        {0x0E68, 0x0E69, 0x0E6A, 0x0E6B, 0x0E6C, 0x0E6D, 0x0E6E},
+        {0x0E47, 0xF70A, 0xF70B, 0xF70C, 0xF70D, 0xF70E, 0x0E4D},
+        {0x0E47, 0xF88B, 0xF88E, 0xF891, 0xF894, 0xF897, 0x0E4D},
+        {0x0E47, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D}
+    };
+
+    if (tone >= CH_MAITAIKHU && tone <= CH_NIKHAHIT) {
+        return lowerRightTones[glyphSet][tone - CH_MAITAIKHU];
+    }
+    
+    return tone;
+}
+
+LEUnicode ThaiShaping::lowerLeftTone(LEUnicode tone, le_uint8 glyphSet)
+{
+    static const LEUnicode lowerLeftTones[][7] = {
+        {0x0E76, 0x0E77, 0x0E78, 0x0E79, 0x0E7A, 0x0E7B, 0x0E7C},
+        {0xF712, 0xF705, 0xF706, 0xF707, 0xF708, 0xF709, 0xF711},
+        {0xF889, 0xF88C, 0xF88F, 0xF892, 0xF895, 0xF898, 0xF899},
+        {0x0E47, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D}
+    };
+
+    if (tone >= CH_MAITAIKHU && tone <= CH_NIKHAHIT) {
+        return lowerLeftTones[glyphSet][tone - CH_MAITAIKHU];
+    }
+    
+    return tone;
+}
+
+LEUnicode ThaiShaping::upperLeftTone(LEUnicode tone, le_uint8 glyphSet)
+{
+    static const LEUnicode upperLeftTones[][7] = {
+        {0x0E6F, 0x0E70, 0x0E71, 0x0E72, 0x0E73, 0x0E74, 0x0E75},
+        {0xF712, 0xF713, 0xF714, 0xF715, 0xF716, 0xF717, 0xF711},
+        {0xF889, 0xF88A, 0xF88D, 0xF890, 0xF893, 0xF896, 0xF899},
+        {0x0E47, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D}
+    };
+
+    if (tone >= CH_MAITAIKHU && tone <= CH_NIKHAHIT) {
+        return upperLeftTones[glyphSet][tone - CH_MAITAIKHU];
+    }
+    
+    return tone;
+}
+
+LEUnicode ThaiShaping::lowerBelowVowel(LEUnicode vowel, le_uint8 glyphSet)
+{
+    static const LEUnicode lowerBelowVowels[][3] = {
+        {0x0E3C, 0x0E3D, 0x0E3E},
+        {0xF718, 0xF719, 0xF71A},
+        {0x0E38, 0x0E39, 0x0E3A},
+        {0x0E38, 0x0E39, 0x0E3A}
+
+    };
+
+    if (vowel >= CH_SARA_U && vowel <= CH_PHINTHU) {
+        return lowerBelowVowels[glyphSet][vowel - CH_SARA_U];
+    }
+    
+    return vowel;
+}
+
+LEUnicode ThaiShaping::noDescenderCOD(LEUnicode cod, le_uint8 glyphSet)
+{
+    static const LEUnicode noDescenderCODs[][4] = {
+        {0x0E60, 0x0E0E, 0x0E0F, 0x0E63},
+        {0xF70F, 0x0E0E, 0x0E0F, 0xF700},
+        {0x0E0D, 0x0E0E, 0x0E0F, 0x0E10},
+        {0x0E0D, 0x0E0E, 0x0E0F, 0x0E10}
+
+    };
+
+    if (cod >= CH_YO_YING && cod <= CH_THO_THAN) {
+        return noDescenderCODs[glyphSet][cod - CH_YO_YING];
+    }
+    
+    return cod;
+}
+
+le_uint8 ThaiShaping::doTransition (StateTransition transition, LEUnicode currChar, le_int32 inputIndex, le_uint8 glyphSet,
+        LEUnicode errorChar, LEUnicode *outputBuffer, LEGlyphStorage &glyphStorage, le_int32 &outputIndex)
+{
+    LEErrorCode success = LE_NO_ERROR;
+
+    switch (transition.action) {
+    case tA:
+        glyphStorage.setCharIndex(outputIndex, inputIndex, success);
+        outputBuffer[outputIndex++] = currChar;
+        break;
+        
+    case tC:
+        glyphStorage.setCharIndex(outputIndex, inputIndex, success);
+        outputBuffer[outputIndex++] = currChar;
+        break;
+        
+    case tD:
+        glyphStorage.setCharIndex(outputIndex, inputIndex, success);
+        outputBuffer[outputIndex++] = leftAboveVowel(currChar, glyphSet);
+        break;
+        
+    case tE:
+        glyphStorage.setCharIndex(outputIndex, inputIndex, success);
+        outputBuffer[outputIndex++] = lowerRightTone(currChar, glyphSet);
+        break;
+        
+    case tF:
+        glyphStorage.setCharIndex(outputIndex, inputIndex, success);
+        outputBuffer[outputIndex++] = lowerLeftTone(currChar, glyphSet);
+        break;
+    
+    case tG:
+        glyphStorage.setCharIndex(outputIndex, inputIndex, success);
+        outputBuffer[outputIndex++] = upperLeftTone(currChar, glyphSet);
+        break;
+        
+    case tH:
+    {
+        LEUnicode cod = outputBuffer[outputIndex - 1];
+        LEUnicode coa = noDescenderCOD(cod, glyphSet);
+
+        if (cod != coa) {
+            outputBuffer[outputIndex - 1] = coa;
+            
+            glyphStorage.setCharIndex(outputIndex, inputIndex, success);
+            outputBuffer[outputIndex++] = currChar;
+            break;
+        }
+
+        glyphStorage.setCharIndex(outputIndex, inputIndex, success);
+        outputBuffer[outputIndex++] = lowerBelowVowel(currChar, glyphSet);
+        break;
+    }
+        
+    case tR:
+        glyphStorage.setCharIndex(outputIndex, inputIndex, success);
+        outputBuffer[outputIndex++] = errorChar;
+
+        glyphStorage.setCharIndex(outputIndex, inputIndex, success);
+        outputBuffer[outputIndex++] = currChar;
+        break;
+        
+    case tS:
+        if (currChar == CH_SARA_AM) {
+            glyphStorage.setCharIndex(outputIndex, inputIndex, success);
+            outputBuffer[outputIndex++] = errorChar;
+        }
+
+        glyphStorage.setCharIndex(outputIndex, inputIndex, success);
+        outputBuffer[outputIndex++] = currChar;
+        break;
+        
+    default:
+        // FIXME: if we get here, there's an error
+        // in the state table!
+        glyphStorage.setCharIndex(outputIndex, inputIndex, success);
+        outputBuffer[outputIndex++] = currChar;
+        break;
+     }
+     
+     return transition.nextState;
+}
+
+le_uint8 ThaiShaping::getNextState(LEUnicode ch, le_uint8 prevState, le_int32 inputIndex, le_uint8 glyphSet, LEUnicode errorChar,
+                              le_uint8 &charClass, LEUnicode *output, LEGlyphStorage &glyphStorage, le_int32 &outputIndex)
+{
+    StateTransition transition;
+
+    charClass = getCharClass(ch);
+    transition = getTransition(prevState, charClass);
+    
+    return doTransition(transition, ch, inputIndex, glyphSet, errorChar, output, glyphStorage, outputIndex);
+}
+
+le_bool ThaiShaping::isLegalHere(LEUnicode ch, le_uint8 prevState)
+{
+    le_uint8 charClass = getCharClass(ch);
+    StateTransition transition = getTransition(prevState, charClass);
+
+    switch (transition.action) {
+    case tA:
+    case tC:
+    case tD:
+    case tE:
+    case tF:
+    case tG:
+    case tH:
+        return TRUE;
+            
+    case tR:
+    case tS:
+        return FALSE;
+            
+    default:
+        // FIXME: if we get here, there's an error
+        // in the state table!
+        return FALSE;
+    }
+}
+    
+le_int32 ThaiShaping::compose(const LEUnicode *input, le_int32 offset, le_int32 charCount, le_uint8 glyphSet,
+                          LEUnicode errorChar, LEUnicode *output, LEGlyphStorage &glyphStorage)
+{
+    le_uint8 state = 0;
+    le_int32 inputIndex;
+    le_int32 outputIndex = 0;
+    le_uint8 conState = 0xFF;
+    le_int32 conInput = -1;
+    le_int32 conOutput = -1;
+    
+    for (inputIndex = 0; inputIndex < charCount; inputIndex += 1) {
+        LEUnicode ch = input[inputIndex + offset];
+        le_uint8 charClass;
+        
+        // Decompose SARA AM into NIKHAHIT + SARA AA
+        if (ch == CH_SARA_AM && isLegalHere(ch, state)) {
+            outputIndex = conOutput;
+            state = getNextState(CH_NIKHAHIT, conState, inputIndex, glyphSet, errorChar, charClass,
+                output, glyphStorage, outputIndex);
+            
+            for (int j = conInput + 1; j < inputIndex; j += 1) {
+                ch = input[j + offset];
+                state = getNextState(ch, state, j, glyphSet, errorChar, charClass,
+                    output, glyphStorage, outputIndex);
+            }
+            
+            ch = CH_SARA_AA;
+        }
+        
+        state = getNextState(ch, state, inputIndex, glyphSet, errorChar, charClass,
+            output, glyphStorage, outputIndex);
+        
+        if (charClass >= CON && charClass <= COD) {
+            conState = state;
+            conInput = inputIndex;
+            conOutput = outputIndex;
+        }
+    }
+    
+    return outputIndex;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/ThaiShaping.h b/source/layout/ThaiShaping.h
new file mode 100644
index 0000000..4c6d6a5
--- /dev/null
+++ b/source/layout/ThaiShaping.h
@@ -0,0 +1,108 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
+ *
+ */
+
+#ifndef __THAISHAPING_H
+#define __THAISHAPING_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEGlyphFilter.h"
+#include "OpenTypeTables.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+class ThaiShaping /* not : public UObject because all methods are static */ {
+public:
+
+    enum {
+        // Character classes
+        NON =  0,
+        CON =  1,
+        COA =  2,
+        COD =  3,
+        LVO =  4,
+        FV1 =  5,
+        FV2 =  6,
+        FV3 =  7,
+        BV1 =  8,
+        BV2 =  9,
+        BDI = 10,
+        TON = 11,
+        AD1 = 12,
+        AD2 = 13,
+        AD3 = 14,
+        NIK = 15,
+        AV1 = 16,
+        AV2 = 17,
+        AV3 = 18,
+        classCount = 19,
+
+        // State Transition actions
+        tA  =  0,
+        tC  =  1,
+        tD  =  2,
+        tE  =  3,
+        tF  =  4,
+        tG  =  5,
+        tH  =  6,
+        tR  =  7,
+        tS  =  8
+    };
+
+    struct StateTransition
+    {
+        le_uint8 nextState;
+        le_uint8 action;
+
+        le_uint8 getNextState() { return nextState; };
+        le_uint8 getAction() { return action; };
+    };
+
+    static le_int32 compose(const LEUnicode *input, le_int32 offset, le_int32 charCount, le_uint8 glyphSet,
+        LEUnicode errorChar, LEUnicode *output, LEGlyphStorage &glyphStorage);
+
+private:
+    // forbid instantiation
+    ThaiShaping();
+
+    static const le_uint8 classTable[];
+    static const StateTransition thaiStateTable[][classCount];
+
+    inline static StateTransition getTransition(le_uint8 state, le_uint8 currClass);
+
+    static le_uint8 doTransition(StateTransition transition, LEUnicode currChar, le_int32 inputIndex, le_uint8 glyphSet,
+        LEUnicode errorChar, LEUnicode *outputBuffer, LEGlyphStorage &glyphStorage, le_int32 &outputIndex);
+
+    static le_uint8 getNextState(LEUnicode ch, le_uint8 state, le_int32 inputIndex, le_uint8 glyphSet, LEUnicode errorChar,
+        le_uint8 &charClass, LEUnicode *output, LEGlyphStorage &glyphStorage, le_int32 &outputIndex);
+
+    static le_bool isLegalHere(LEUnicode ch, le_uint8 prevState);
+    static le_uint8 getCharClass(LEUnicode ch);
+
+    static LEUnicode noDescenderCOD(LEUnicode cod, le_uint8 glyphSet);
+    static LEUnicode leftAboveVowel(LEUnicode vowel, le_uint8 glyphSet);
+    static LEUnicode lowerBelowVowel(LEUnicode vowel, le_uint8 glyphSet);
+    static LEUnicode lowerRightTone(LEUnicode tone, le_uint8 glyphSet);
+    static LEUnicode lowerLeftTone(LEUnicode tone, le_uint8 glyphSet);
+    static LEUnicode upperLeftTone(LEUnicode tone, le_uint8 glyphSet);
+
+};
+
+inline ThaiShaping::StateTransition ThaiShaping::getTransition(le_uint8 state, le_uint8 currClass)
+{
+    return thaiStateTable[state][currClass];
+}
+
+U_NAMESPACE_END
+#endif
+
+
diff --git a/source/layout/ThaiStateTables.cpp b/source/layout/ThaiStateTables.cpp
new file mode 100644
index 0000000..b1f8b18
--- /dev/null
+++ b/source/layout/ThaiStateTables.cpp
@@ -0,0 +1,87 @@
+/*
+ * %W% %E%
+ *
+ * (C) Copyright IBM Corp. 1999-2003 - All Rights Reserved
+ *
+ * WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT UNLESS
+ * YOU REALLY KNOW WHAT YOU'RE DOING.
+ *
+ */
+
+#include "LETypes.h"
+#include "ThaiShaping.h"
+
+U_NAMESPACE_BEGIN
+
+const le_uint8 ThaiShaping::classTable[] = {
+    //       0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
+    //       -------------------------------------------------------------------------------
+    /*0E00*/ NON, CON, CON, CON, CON, CON, CON, CON, CON, CON, CON, CON, CON, COD, COD, COD, 
+    /*0E10*/ COD, CON, CON, CON, CON, CON, CON, CON, CON, CON, CON, COA, CON, COA, CON, COA, 
+    /*0E20*/ CON, CON, CON, CON, FV3, CON, FV3, CON, CON, CON, CON, CON, CON, CON, CON, NON, 
+    /*0E30*/ FV1, AV2, FV1, FV1, AV1, AV3, AV2, AV3, BV1, BV2, BDI, NON, NON, NON, NON, NON, 
+    /*0E40*/ LVO, LVO, LVO, LVO, LVO, FV2, NON, AD2, TON, TON, TON, TON, AD1, NIK, AD3, NON, 
+    /*0E50*/ NON, NON, NON, NON, NON, NON, NON, NON, NON, NON, NON, NON
+};
+
+const ThaiShaping::StateTransition ThaiShaping::thaiStateTable[][ThaiShaping::classCount] = {
+    //+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+    //|         N         C         C         C         L         F         F         F         B         B         B         T         A         A         A         N         A         A         A    |
+    //|         O         O         O         O         V         V         V         V         V         V         D         O         D         D         D         I         V         V         V    |
+    //|         N         N         A         D         O         1         2         3         1         2         I         N         1         2         3         K         1         2         3    |
+    //+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+    /*00*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*01*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 2, tC}, { 6, tC}, { 0, tC}, { 8, tE}, { 0, tE}, { 0, tE}, { 0, tC}, { 9, tE}, {11, tC}, {14, tC}, {16, tC}},
+    /*02*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 3, tE}, { 0, tE}, { 0, tR}, { 0, tR}, { 4, tE}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*03*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*04*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 5, tC}, { 0, tC}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*05*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*06*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 7, tE}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*07*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*08*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tA}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*09*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, {10, tC}, { 0, tC}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*10*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*11*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, {12, tC}, { 0, tC}, { 0, tR}, { 0, tR}, {13, tC}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*12*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*13*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*14*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, {15, tC}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*15*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*16*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, {17, tC}, { 0, tR}, { 0, tC}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*17*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*18*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tA}, { 0, tS}, { 0, tA}, {19, tC}, {23, tC}, { 0, tC}, {25, tF}, { 0, tF}, { 0, tF}, { 0, tD}, {26, tF}, {28, tD}, {31, tD}, {33, tD}},
+    /*19*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, {20, tF}, { 0, tF}, { 0, tR}, { 0, tR}, {21, tF}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*20*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*21*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, {22, tC}, { 0, tC}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*22*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*23*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, {24, tF}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*24*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*25*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tA}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*26*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, {27, tG}, { 0, tG}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*27*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*28*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, {29, tG}, { 0, tG}, { 0, tR}, { 0, tR}, {30, tG}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*29*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*30*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*31*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, {32, tG}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*32*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*33*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, {34, tG}, { 0, tR}, { 0, tG}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*34*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*35*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tA}, { 0, tS}, { 0, tA}, {36, tH}, {40, tH}, { 0, tH}, {42, tE}, { 0, tE}, { 0, tE}, { 0, tC}, {43, tE}, {45, tC}, {48, tC}, {50, tC}},
+    /*36*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, {37, tE}, { 0, tE}, { 0, tR}, { 0, tR}, {38, tE}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*37*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*38*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, {39, tC}, { 0, tC}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*39*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*40*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, {41, tE}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*41*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*42*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tA}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*43*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, {44, tC}, { 0, tC}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*44*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*45*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, {46, tC}, { 0, tC}, { 0, tR}, { 0, tR}, {47, tC}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*46*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*47*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*48*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, {49, tC}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*49*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*50*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tS}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, {51, tC}, { 0, tR}, { 0, tC}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}},
+    /*51*/ {{ 0, tA}, { 1, tA}, {18, tA}, {35, tA}, { 0, tA}, { 0, tS}, { 0, tA}, { 0, tA}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}, { 0, tR}}
+};
+
+U_NAMESPACE_END
diff --git a/source/layout/TibetanLayoutEngine.cpp b/source/layout/TibetanLayoutEngine.cpp
new file mode 100644
index 0000000..d89879f
--- /dev/null
+++ b/source/layout/TibetanLayoutEngine.cpp
@@ -0,0 +1,87 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved 
+ *
+ * Developed at DIT - Government of Bhutan
+ *
+ * Contact person: Pema Geyleg - <pema_geyleg@druknet.bt> 
+ *
+ * This file is a modification of the ICU file KhmerReordering.cpp
+ * by Jens Herden and Javier Sola who have given all their possible rights to IBM and the Governement of Bhutan
+ * A first module for Dzongkha was developed by Karunakar under Panlocalisation funding.
+ * Assistance for this module has been received from Namgay Thinley, Christopher Fynn and Javier Sola
+ *
+ */
+
+
+#include "OpenTypeLayoutEngine.h"
+#include "TibetanLayoutEngine.h"
+#include "LEGlyphStorage.h"
+#include "TibetanReordering.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TibetanOpenTypeLayoutEngine)
+
+TibetanOpenTypeLayoutEngine::TibetanOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+                    le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success)
+    : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success)
+{
+    fFeatureMap   = TibetanReordering::getFeatureMap(fFeatureMapCount);
+    fFeatureOrder = TRUE;
+}
+
+TibetanOpenTypeLayoutEngine::TibetanOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+						     le_int32 typoFlags, LEErrorCode &success)
+    : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success)
+{
+    fFeatureMap   = TibetanReordering::getFeatureMap(fFeatureMapCount);
+    fFeatureOrder = TRUE;
+}
+
+TibetanOpenTypeLayoutEngine::~TibetanOpenTypeLayoutEngine()
+{
+    // nothing to do
+}
+
+// Input: characters
+// Output: characters, char indices, tags
+// Returns: output character count
+le_int32 TibetanOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+        LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
+{
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
+    if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
+        success = LE_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+
+    le_int32 worstCase = count * 3;  // worst case is 3 for Khmer  TODO check if 2 is enough
+
+    outChars = LE_NEW_ARRAY(LEUnicode, worstCase);
+
+    if (outChars == NULL) {
+        success = LE_MEMORY_ALLOCATION_ERROR;
+        return 0;
+    }
+
+    glyphStorage.allocateGlyphArray(worstCase, rightToLeft, success);
+    glyphStorage.allocateAuxData(success);
+
+    if (LE_FAILURE(success)) {
+        LE_DELETE_ARRAY(outChars);
+        return 0;
+    }
+
+    // NOTE: assumes this allocates featureTags...
+    // (probably better than doing the worst case stuff here...)
+    le_int32 outCharCount = TibetanReordering::reorder(&chars[offset], count, fScriptCode, outChars, glyphStorage);
+
+    glyphStorage.adoptGlyphCount(outCharCount);
+    return outCharCount;
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/TibetanLayoutEngine.h b/source/layout/TibetanLayoutEngine.h
new file mode 100644
index 0000000..6ad38cb
--- /dev/null
+++ b/source/layout/TibetanLayoutEngine.h
@@ -0,0 +1,131 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved 
+ *
+ * Developed at DIT - Government of Bhutan
+ *
+ * Contact person: Pema Geyleg - <pema_geyleg@druknet.bt> 
+ *
+ * This file is a modification of the ICU file KhmerReordering.cpp
+ * by Jens Herden and Javier Sola who have given all their possible rights to IBM and the Governement of Bhutan
+ * A first module for Dzongkha was developed by Karunakar under Panlocalisation funding.
+ * Assistance for this module has been received from Namgay Thinley, Christopher Fynn and Javier Sola
+ *
+ */
+
+#ifndef __TIBETANLAYOUTENGINE_H
+#define __TIBETANLAYOUTENGINE_H
+
+// #include "LETypes.h"
+// #include "LEFontInstance.h"
+// #include "LEGlyphFilter.h"
+// #include "LayoutEngine.h"
+// #include "OpenTypeLayoutEngine.h"
+
+// #include "GlyphSubstitutionTables.h"
+// #include "GlyphDefinitionTables.h"
+// #include "GlyphPositioningTables.h"
+
+U_NAMESPACE_BEGIN
+
+// class MPreFixups;
+// class LEGlyphStorage;
+
+/**
+ * This class implements OpenType layout for Dzongkha and Tibetan OpenType fonts
+ *
+ * @internal
+ */
+class TibetanOpenTypeLayoutEngine : public OpenTypeLayoutEngine
+{
+public:
+    /**
+     * This is the main constructor. It constructs an instance of TibetanOpenTypeLayoutEngine for
+     * a particular font, script and language. It takes the GSUB table as a parameter since
+     * LayoutEngine::layoutEngineFactory has to read the GSUB table to know that it has an
+     * Tibetan OpenType font.
+     *
+     * @param fontInstance - the font
+     * @param scriptCode - the script
+     * @param langaugeCode - the language
+     * @param gsubTable - the GSUB table
+     * @param success - set to an error code if the operation fails
+     *
+     * @see LayoutEngine::layoutEngineFactory
+     * @see OpenTypeLayoutEngine
+     * @see ScriptAndLangaugeTags.h for script and language codes
+     *
+     * @internal
+     */
+    TibetanOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+                            le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success);
+
+    /**
+     * This constructor is used when the font requires a "canned" GSUB table which can't be known
+     * until after this constructor has been invoked.
+     *
+     * @param fontInstance - the font
+     * @param scriptCode - the script
+     * @param langaugeCode - the language
+     * @param success - set to an error code if the operation fails
+     *
+     * @see OpenTypeLayoutEngine
+     * @see ScriptAndLangaugeTags.h for script and language codes
+     *
+     * @internal
+     */
+    TibetanOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+                                le_int32 typoFlags, LEErrorCode &success);
+
+    /**
+     * The destructor, virtual for correct polymorphic invocation.
+     *
+     * @internal
+     */
+   virtual ~TibetanOpenTypeLayoutEngine();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @internal ICU 3.6
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @internal ICU 3.6
+     */
+    static UClassID getStaticClassID();
+
+protected:
+
+    /**
+     * This method does Tibetan OpenType character processing. It assigns the OpenType feature
+     * tags to the characters, and may generate output characters which have been reordered. 
+     * It may also split some vowels, resulting in more output characters than input characters.
+     *
+     * Input parameters:
+     * @param chars - the input character context
+     * @param offset - the index of the first character to process
+     * @param count - the number of characters to process
+     * @param max - the number of characters in the input context
+     * @param rightToLeft - <code>TRUE</code> if the characters are in a right to left directional run
+     * @param glyphStorage - the glyph storage object. The glyph and character index arrays will be set.
+     *                       the auxillary data array will be set to the feature tags.
+     *
+     * Output parameters:
+     * @param success - set to an error code if the operation fails
+     *
+     * @return the output character count
+     *
+     * @internal
+     */
+    virtual le_int32 characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
+            LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success);
+
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/TibetanReordering.cpp b/source/layout/TibetanReordering.cpp
new file mode 100644
index 0000000..4296d63
--- /dev/null
+++ b/source/layout/TibetanReordering.cpp
@@ -0,0 +1,389 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved 
+ *
+ * Developed at DIT - Government of Bhutan
+ *
+ * Contact person: Pema Geyleg - <pema_geyleg@druknet.bt> 
+ *
+ * This file is a modification of the ICU file KhmerReordering.cpp
+ * by Jens Herden and Javier Sola who have given all their possible rights to IBM and the Governement of Bhutan
+ * A first module for Dzongkha was developed by Karunakar under Panlocalisation funding.
+ * Assistance for this module has been received from Namgay Thinley, Christopher Fynn and Javier Sola
+ *
+ */
+
+//#include <stdio.h>
+#include "LETypes.h"
+#include "OpenTypeTables.h"
+#include "TibetanReordering.h"
+#include "LEGlyphStorage.h"
+
+
+U_NAMESPACE_BEGIN
+
+// Characters that get refered to by name...
+enum
+{
+    C_DOTTED_CIRCLE = 0x25CC,
+    C_PRE_NUMBER_MARK = 0x0F3F
+ };
+
+
+enum
+{
+    // simple classes, they are used in the statetable (in this file) to control the length of a syllable
+    // they are also used to know where a character should be placed (location in reference to the base character)
+    // and also to know if a character, when independtly displayed, should be displayed with a dotted-circle to
+    // indicate error in syllable construction 
+    _xx = TibetanClassTable::CC_RESERVED,
+    _ba = TibetanClassTable::CC_BASE,
+    _sj = TibetanClassTable::CC_SUBJOINED | TibetanClassTable::CF_DOTTED_CIRCLE | TibetanClassTable::CF_POS_BELOW, 
+    _tp = TibetanClassTable::CC_TSA_PHRU  | TibetanClassTable::CF_DOTTED_CIRCLE | TibetanClassTable::CF_POS_ABOVE,
+    _ac = TibetanClassTable::CC_A_CHUNG |  TibetanClassTable::CF_DOTTED_CIRCLE | TibetanClassTable::CF_POS_BELOW,
+    _cs = TibetanClassTable::CC_COMP_SANSKRIT | TibetanClassTable::CF_DOTTED_CIRCLE | TibetanClassTable::CF_POS_BELOW,
+    _ha = TibetanClassTable::CC_HALANTA | TibetanClassTable::CF_DOTTED_CIRCLE | TibetanClassTable::CF_POS_BELOW, 
+    _bv = TibetanClassTable::CC_BELOW_VOWEL | TibetanClassTable::CF_DOTTED_CIRCLE | TibetanClassTable::CF_POS_BELOW,
+    _av = TibetanClassTable::CC_ABOVE_VOWEL | TibetanClassTable::CF_DOTTED_CIRCLE | TibetanClassTable::CF_POS_ABOVE,
+    _an = TibetanClassTable::CC_ANUSVARA | TibetanClassTable::CF_DOTTED_CIRCLE | TibetanClassTable::CF_POS_ABOVE,
+    _cb = TibetanClassTable::CC_CANDRABINDU | TibetanClassTable::CF_DOTTED_CIRCLE | TibetanClassTable::CF_POS_ABOVE,
+    _vs = TibetanClassTable::CC_VISARGA | TibetanClassTable::CF_DOTTED_CIRCLE| TibetanClassTable::CF_POS_AFTER,
+    _as = TibetanClassTable::CC_ABOVE_S_MARK | TibetanClassTable::CF_DOTTED_CIRCLE | TibetanClassTable::CF_POS_ABOVE,
+    _bs = TibetanClassTable::CC_BELOW_S_MARK | TibetanClassTable::CF_DOTTED_CIRCLE | TibetanClassTable::CF_POS_BELOW,
+    _di = TibetanClassTable::CC_DIGIT | TibetanClassTable::CF_DIGIT,
+    _pd = TibetanClassTable::CC_PRE_DIGIT_MARK | TibetanClassTable::CF_DOTTED_CIRCLE | TibetanClassTable::CF_PREDIGIT | TibetanClassTable::CF_POS_BEFORE ,
+    _bd = TibetanClassTable::CC_POST_BELOW_DIGIT_M | TibetanClassTable::CF_DOTTED_CIRCLE | TibetanClassTable::CF_POS_AFTER
+};
+
+
+// Character class tables 
+//_xx Non Combining characters
+//_ba Base Consonants
+//_sj Subjoined consonants
+//_tp Tsa - phru
+//_ac A-chung, Vowel Lengthening mark
+//_cs Precomposed Sanskrit vowel + subjoined consonants
+//_ha Halanta/Virama
+//_bv Below vowel
+//_av above vowel
+//_an Anusvara
+//_cb Candrabindu
+//_vs Visaraga/Post mark
+//_as Upper Stress marks
+//_bs Lower Stress marks
+//_di Digit
+//_pd Number pre combining, Needs reordering
+//_bd Other number combining marks
+
+static const TibetanClassTable::CharClass tibetanCharClasses[] =
+{
+   // 0    1    2    3    4    5    6    7    8    9   a     b   c    d     e   f
+    _xx, _ba, _xx, _xx, _ba, _ba, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, // 0F00 - 0F0F 0
+    _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _bd, _bd, _xx, _xx, _xx, _xx, _xx, _xx, // 0F10 - 0F1F 1
+    _di, _di, _di, _di, _di, _di, _di, _di, _di, _di, _xx, _xx, _xx, _xx, _xx, _xx, // 0F20 - 0F2F 2 
+    _xx, _xx, _xx, _xx, _xx, _bs, _xx, _bs, _xx, _tp, _xx, _xx, _xx, _xx, _bd, _pd, // 0F30 - 0F3F 3 
+    _ba, _ba, _ba, _ba, _ba, _ba, _ba, _ba, _xx, _ba, _ba, _ba, _ba, _ba, _ba, _ba, // 0F40 - 0F4F 4
+    _ba, _ba, _ba, _ba, _ba, _ba, _ba, _ba, _ba, _ba, _ba, _ba, _ba, _ba, _ba, _ba, // 0F50 - 0F5F 5
+    _ba, _ba, _ba, _ba, _ba, _ba, _ba, _ba, _ba, _ba, _ba, _xx, _xx, _xx, _xx, _xx, // 0F60 - 0F6F 6
+    _xx, _ac, _av, _cs, _bv, _bv, _cs, _cs, _cs, _cs, _av, _av, _av, _av, _an, _vs, // 0F70 - 0F7F 7
+    _av, _cs, _cb, _cb, _ha, _xx, _as, _as, _ba, _ba, _ba, _ba, _xx, _xx, _xx, _xx, // 0F80 - 0F8F 8
+    _sj, _sj, _sj, _sj, _sj, _sj, _sj, _sj, _xx, _sj, _sj, _sj, _sj, _sj, _sj, _sj, // 0F90 - 0F9F 9
+    _sj, _sj, _sj, _sj, _sj, _sj, _sj, _sj, _sj, _sj, _sj, _sj, _sj, _sj, _sj, _sj, // 0FA0 - 0FAF a
+    _sj, _sj, _sj, _sj, _sj, _sj, _sj, _sj, _sj, _sj, _sj, _sj, _sj, _xx, _sj, _sj, // 0FB0 - 0FBF b
+    _xx, _xx, _xx, _xx, _xx, _xx, _bs, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, // 0FC0 - 0FCF c
+    _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx,// 0FD0 - 0FDF  d
+    _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, // 0FE0 - 0FEF e
+    _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, // 0FF0 - 0FFF f 
+};                                                                                  
+
+
+//
+// Tibetan Class Tables
+//                   
+
+//
+// The range of characters defined in the above table is defined here. For Tibetan 0F00 to 0FFF
+// Even if the Tibetan range is bigger, most of the characters are not combinable, and therefore treated
+// as _xx
+static const TibetanClassTable tibetanClassTable = {0x0F00, 0x0FFF, tibetanCharClasses};
+
+
+// Below we define how a character in the input string is either in the tibetanCharClasses table
+// (in which case we get its type back), or an unknown object in which case we get _xx (CC_RESERVED) back
+TibetanClassTable::CharClass TibetanClassTable::getCharClass(LEUnicode ch) const
+{
+    if (ch < firstChar || ch > lastChar) {
+        return CC_RESERVED;
+    }
+    
+    return classTable[ch - firstChar];
+}
+
+const TibetanClassTable *TibetanClassTable::getTibetanClassTable()
+{
+    return &tibetanClassTable;
+}
+
+
+
+class TibetanReorderingOutput : public UMemory {
+private:
+    le_int32 fSyllableCount;
+    le_int32 fOutIndex;
+    LEUnicode *fOutChars;
+
+    LEGlyphStorage &fGlyphStorage;
+
+
+public:
+    TibetanReorderingOutput(LEUnicode *outChars, LEGlyphStorage &glyphStorage)
+        : fSyllableCount(0), fOutIndex(0), fOutChars(outChars), fGlyphStorage(glyphStorage)
+    {
+        // nothing else to do...
+    }
+
+    ~TibetanReorderingOutput()
+    {
+        // nothing to do here...
+    }
+
+    void reset()
+    {
+        fSyllableCount += 1;
+    }
+
+    void writeChar(LEUnicode ch, le_uint32 charIndex, FeatureMask featureMask)
+    {
+        LEErrorCode success = LE_NO_ERROR;
+
+        fOutChars[fOutIndex] = ch;
+
+        fGlyphStorage.setCharIndex(fOutIndex, charIndex, success);
+        fGlyphStorage.setAuxData(fOutIndex, featureMask, success);
+
+        fOutIndex += 1;
+    }
+
+    le_int32 getOutputIndex()
+    {
+        return fOutIndex;
+    }
+};
+
+
+//TODO remove unused flags
+#define ccmpFeatureTag LE_CCMP_FEATURE_TAG
+#define blwfFeatureTag LE_BLWF_FEATURE_TAG
+#define pstfFeatureTag LE_PSTF_FEATURE_TAG
+#define presFeatureTag LE_PRES_FEATURE_TAG
+#define blwsFeatureTag LE_BLWS_FEATURE_TAG
+#define abvsFeatureTag LE_ABVS_FEATURE_TAG
+#define pstsFeatureTag LE_PSTS_FEATURE_TAG
+
+#define blwmFeatureTag LE_BLWM_FEATURE_TAG
+#define abvmFeatureTag LE_ABVM_FEATURE_TAG
+#define distFeatureTag LE_DIST_FEATURE_TAG
+
+#define prefFeatureTag LE_PREF_FEATURE_TAG
+#define abvfFeatureTag LE_ABVF_FEATURE_TAG
+#define cligFeatureTag LE_CLIG_FEATURE_TAG
+#define mkmkFeatureTag LE_MKMK_FEATURE_TAG
+
+// Shaping features
+#define prefFeatureMask 0x80000000UL
+#define blwfFeatureMask 0x40000000UL
+#define abvfFeatureMask 0x20000000UL
+#define pstfFeatureMask 0x10000000UL 
+#define presFeatureMask 0x08000000UL
+#define blwsFeatureMask 0x04000000UL
+#define abvsFeatureMask 0x02000000UL
+#define pstsFeatureMask 0x01000000UL
+#define cligFeatureMask 0x00800000UL 
+#define ccmpFeatureMask 0x00040000UL
+
+// Positioning features
+#define distFeatureMask 0x00400000UL
+#define blwmFeatureMask 0x00200000UL
+#define abvmFeatureMask 0x00100000UL
+#define mkmkFeatureMask 0x00080000UL
+
+#define tagPref    (ccmpFeatureMask | prefFeatureMask | presFeatureMask | cligFeatureMask | distFeatureMask)
+#define tagAbvf    (ccmpFeatureMask | abvfFeatureMask | abvsFeatureMask | cligFeatureMask | distFeatureMask | abvmFeatureMask | mkmkFeatureMask)
+#define tagPstf    (ccmpFeatureMask | blwfFeatureMask | blwsFeatureMask | prefFeatureMask | presFeatureMask | pstfFeatureMask | pstsFeatureMask | cligFeatureMask | distFeatureMask | blwmFeatureMask)
+#define tagBlwf    (ccmpFeatureMask | blwfFeatureMask | blwsFeatureMask | cligFeatureMask | distFeatureMask | blwmFeatureMask | mkmkFeatureMask)
+#define tagDefault (ccmpFeatureMask | prefFeatureMask | blwfFeatureMask | presFeatureMask | blwsFeatureMask | cligFeatureMask | distFeatureMask | abvmFeatureMask | blwmFeatureMask | mkmkFeatureMask)
+
+
+
+// These are in the order in which the features need to be applied
+// for correct processing
+static const FeatureMap featureMap[] =
+{
+    // Shaping features
+    {ccmpFeatureTag, ccmpFeatureMask},
+    {prefFeatureTag, prefFeatureMask},
+    {blwfFeatureTag, blwfFeatureMask},
+    {abvfFeatureTag, abvfFeatureMask},
+    {pstfFeatureTag, pstfFeatureMask}, 
+    {presFeatureTag, presFeatureMask},
+    {blwsFeatureTag, blwsFeatureMask},
+    {abvsFeatureTag, abvsFeatureMask},
+    {pstsFeatureTag, pstsFeatureMask},
+    {cligFeatureTag, cligFeatureMask},
+    
+    // Positioning features
+    {distFeatureTag, distFeatureMask},
+    {blwmFeatureTag, blwmFeatureMask},
+    {abvmFeatureTag, abvmFeatureMask},
+    {mkmkFeatureTag, mkmkFeatureMask},
+};
+
+static const le_int32 featureMapCount = LE_ARRAY_SIZE(featureMap);
+
+// The stateTable is used to calculate the end (the length) of a well
+// formed Tibetan Syllable. 
+//
+// Each horizontal line is ordered exactly the same way as the values in TibetanClassTable
+// CharClassValues in TibetanReordering.h This coincidence of values allows the
+// follow up of the table.
+//
+// Each line corresponds to a state, which does not necessarily need to be a type
+// of component... for example, state 2 is a base, with is always a first character
+// in the syllable, but the state could be produced a consonant of any type when
+// it is the first character that is analysed (in ground state).
+//
+static const le_int8 tibetanStateTable[][TibetanClassTable::CC_COUNT] =
+{
+
+     
+    //Dzongkha state table
+    //xx  ba  sj  tp  ac  cs  ha  bv  av  an  cb  vs  as  bs  di  pd  bd
+    { 1,  2,  4,  3,  8,  7,  9, 10, 14, 13, 17, 18, 19, 19, 20, 21, 21,}, //  0 - ground state
+    {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,}, //  1 - exit state (or sign to the right of the syllable)
+    {-1, -1,  4,  3,  8,  7,  9, 10, 14, 13, 17, 18, 19, 19, -1, -1, -1,}, //  2 - Base consonant    
+    {-1, -1,  5, -1,  8,  7, -1, 10, 14, 13, 17, 18, 19, 19, -1, -1, -1,}, //  3 - Tsa phru after base
+    {-1, -1,  4,  6,  8,  7,  9, 10, 14, 13, 17, 18, 19, 19, -1, -1, -1,}, //  4 - Subjoined consonant after base             
+    {-1, -1,  5, -1,  8,  7, -1, 10, 14, 13, 17, 18, 19, 19, -1, -1, -1,}, //  5 - Subjoined consonant after tsa phru
+    {-1, -1, -1, -1,  8,  7, -1, 10, 14, 13, 17, 18, 19, 19, -1, -1, -1,}, //  6 - Tsa phru after subjoined consonant
+    {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, 19, -1, -1, -1,}, //  7 - Pre Composed Sanskrit
+    {-1, -1, -1, -1, -1, -1, -1, 10, 14, 13, 17, 18, 19, 19, -1, -1, -1,}, //  8 - A-chung
+    {-1, -1, -1, -1, -1, -1, -1, -1, 14, 13, 17, -1, 19, 19, -1, -1, -1,}, //  9 - Halanta
+    {-1, -1, -1, -1, -1, -1, -1, 11, 14, 13, 17, 18, 19, 19, -1, -1, -1,}, // 10 - below vowel 1
+    {-1, -1, -1, -1, -1, -1, -1, 12, 14, 13, 17, 18, 19, 19, -1, -1, -1,}, // 11 - below vowel 2
+    {-1, -1, -1, -1, -1, -1, -1, -1, 14, 13, 17, 18, 19, 19, -1, -1, -1,}, // 12 - below vowel 3   
+    {-1, -1, -1, -1, -1, -1, -1, -1, 14, 17, 17, 18, 19, 19, -1, -1, -1,}, // 13 - Anusvara before vowel
+    {-1, -1, -1, -1, -1, -1, -1, -1, 15, 17, 17, 18, 19, 19, -1, -1, -1,}, // 14 - above vowel 1
+    {-1, -1, -1, -1, -1, -1, -1, -1, 16, 17, 17, 18, 19, 19, -1, -1, -1,}, // 15 - above vowel 2
+    {-1, -1, -1, -1, -1, -1, -1, -1, -1, 17, 17, 18, 19, 19, -1, -1, -1,}, // 16 - above vowel 3
+    {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 18, 19, 19, -1, -1, -1,}, // 17 - Anusvara or Candrabindu after vowel 
+    {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, 19, -1, -1, -1,}, // 18 - Visarga    
+    {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,}, // 19 - strss mark
+    {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 21, 21,}, // 20 - digit 
+    {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,}, // 21 - digit mark
+    
+
+};         
+
+
+const FeatureMap *TibetanReordering::getFeatureMap(le_int32 &count)
+{
+    count = featureMapCount;
+
+    return featureMap;
+}
+
+
+// Given an input string of characters and a location in which to start looking
+// calculate, using the state table, which one is the last character of the syllable
+// that starts in the starting position.
+le_int32 TibetanReordering::findSyllable(const TibetanClassTable *classTable, const LEUnicode *chars, le_int32 prev, le_int32 charCount)
+{
+    le_int32 cursor = prev;
+    le_int8 state = 0;
+
+    while (cursor < charCount) {
+        TibetanClassTable::CharClass charClass = (classTable->getCharClass(chars[cursor]) & TibetanClassTable::CF_CLASS_MASK);
+
+        state = tibetanStateTable[state][charClass];
+
+        if (state < 0) {
+            break;
+        }
+
+        cursor += 1;
+    }
+
+    return cursor;
+}
+
+
+// This is the real reordering function as applied to the Tibetan language
+
+le_int32 TibetanReordering::reorder(const LEUnicode *chars, le_int32 charCount, le_int32,
+                                  LEUnicode *outChars, LEGlyphStorage &glyphStorage)
+{
+    const TibetanClassTable *classTable = TibetanClassTable::getTibetanClassTable();
+
+    TibetanReorderingOutput output(outChars, glyphStorage);
+    TibetanClassTable::CharClass charClass;
+    le_int32 i, prev = 0;
+
+    // This loop only exits when we reach the end of a run, which may contain 
+    // several syllables.
+    while (prev < charCount) {
+        le_int32 syllable = findSyllable(classTable, chars, prev, charCount);  
+
+        output.reset();
+       
+        // shall we add a dotted circle?
+        // If in the position in which the base should be (first char in the string) there is
+        // a character that has the Dotted circle flag (a character that cannot be a base)
+        // then write a dotted circle
+        if (classTable->getCharClass(chars[prev]) & TibetanClassTable::CF_DOTTED_CIRCLE) {
+            output.writeChar(C_DOTTED_CIRCLE, prev, tagDefault);        
+        }        
+
+        // copy the rest to output, inverting the pre-number mark if present after a digit.
+        for (i = prev; i < syllable; i += 1) {
+            charClass = classTable->getCharClass(chars[i]);
+           
+           if ((TibetanClassTable::CF_DIGIT & charClass) 
+              && ( classTable->getCharClass(chars[i+1]) & TibetanClassTable::CF_PREDIGIT))
+           {
+         		 output.writeChar(C_PRE_NUMBER_MARK, i, tagPref);
+                         output.writeChar(chars[i], i+1 , tagPref);
+			i += 1;
+          } else {
+            switch (charClass & TibetanClassTable::CF_POS_MASK) {
+            	
+            	// If the present character is a number, and the next character is a pre-number combining mark
+            // then the two characters are reordered
+          	           	
+                case TibetanClassTable::CF_POS_ABOVE :
+                    output.writeChar(chars[i], i, tagAbvf);
+                    break;
+                
+                case TibetanClassTable::CF_POS_AFTER :
+                    output.writeChar(chars[i], i, tagPstf);
+                    break;
+                
+                case TibetanClassTable::CF_POS_BELOW :
+                    output.writeChar(chars[i], i, tagBlwf);
+                    break;
+                
+                default:                                       
+                    // default - any other characters
+                   output.writeChar(chars[i], i, tagDefault);
+                    break;
+            } // switch
+          } // if
+        } // for
+
+        prev = syllable; // move the pointer to the start of next syllable
+    }
+
+    return output.getOutputIndex();
+}
+
+
+U_NAMESPACE_END
diff --git a/source/layout/TibetanReordering.h b/source/layout/TibetanReordering.h
new file mode 100644
index 0000000..cafcf56
--- /dev/null
+++ b/source/layout/TibetanReordering.h
@@ -0,0 +1,151 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved 
+ *
+ * Developed at DIT - Government of Bhutan
+ *
+ * Contact person: Pema Geyleg - <pema_geyleg@druknet.bt> 
+ *
+ * This file is a modification of the ICU file KhmerReordering.h
+ * by Jens Herden and Javier Sola who have given all their possible rights to IBM and the Governement of Bhutan
+ * A first module for Dzongkha was developed by Karunakar under Panlocalisation funding.
+ * Assistance for this module has been received from Namgay Thinley, Christopher Fynn and Javier Sola
+ *
+ */
+
+#ifndef __TIBETANREORDERING_H
+#define __TIBETANORDERING_H
+
+/**
+ * \file
+ * \internal
+ */
+
+// #include "LETypes.h"
+// #include "OpenTypeTables.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+// Vocabulary 
+//     Base ->         A consonant in its full (not subscript) form. It is the 
+//                     center of the syllable, it can be souranded by subjoined consonants, vowels,
+//                     signs... but there is only one base in a stack, it has to be coded as
+//                     the first character of the syllable.Included here are also groups of base + subjoined 
+//										 which are represented by one single code point in unicode (e.g. 0F43) Also other characters that might take 
+//                     subjoined consonants or other combining characters.											
+//     Subjoined ->    Subjoined consonants and groups of subjoined consonants which have a single code-point 
+//                     to repersent the group (even if each subjoined consonant is represented independently
+//                     by anothe code-point
+//     Tsa Phru -->    Tsa Phru character, Bhutanese people will always place it right after the base, but sometimes, due to 
+// 										"normalization"							
+//										 is placed after all the subjoined consonants, and it is also permitted there.
+//     A Chung  Vowel lengthening mark --> . 0F71 It is placed after the base and any subjoined consonants but before any vowels
+//     Precomposed Sanskrit vowels --> The are combinations of subjoined consonants + vowels that have been assigned
+//                     a given code-point (in spite of each single part of them having also a code-point
+//                     They are avoided, and users are encouraged to use the combination of code-points that
+//                     represents the same sound instead of using this combined characters. This is included here
+//                     for compatibility with possible texts that use them (they are not in the Dzongkha keyboard).
+//     Halanta ->      The Halanta or Virama character 0F84 indicates that a consonant should not use its inheernt vowel, 
+//                     in spite of not having other vowels present. It is usually placed immediatly after a base consonant,
+//                     but in some special cases it can also be placed after a subjoined consonant, so this is also
+//                     permitted in this algorithm. (Halanta is always displayed in Tibetan not used as a connecting char)
+//
+//     Subjoined vowels -> Dependent vowels (matras) placed below the base and below all subjoined consonants. There
+//                     might be as much as three subjoined vowels in a given stack (only one in general text, but up 
+//                     to three for abreviations, they have to be permitted).
+//     Superscript vowels -> There are three superscript vowels, and they can be repeated or combined (up to three
+//                     times. They can combine with subjoined vowels, and are always coded after these.
+//     Anusvara -->    Nasalisation sign. Traditioinally placed in absence of vowels, but also after vowels. In some
+//                     special cases it can be placed before a vowel, so this is also permitted
+//     Candrabindu ->  Forms of the Anusvara with different glyphs (and different in identity) which can be placed
+//                     without vowel or after the vowel, but never before. Cannot combine with Anusvara.
+//     Stress marks -> Marks placed above or below a syllable, affecting the whole syllable. They are combining
+//                     marks, so they have to be attached to a specific stack. The are using to emphasise a syllable.
+//
+//     Digits ->       Digits are not considered as non-combining characters because there are a few characters which
+//                     combine with them, so they have to be considered independently.
+//     Digit combining marks -> dependent marks that combine with digits.
+//     
+//     TODO
+//     There are a number of characters in the CJK block that are used in Tibetan script, two of these are symbols
+//     are used as bases for combining glyphs, and have not been encoded in Tibetan. As these characters are outside
+//     of the tibetan block, they have not been treated in this program.
+    
+
+struct TibetanClassTable    // This list must include all types of components that can be used inside a syllable
+{
+    enum CharClassValues  // order is important here! This order must be the same that is found in each horizontal 
+                          // line in the statetable for Tibetan (file TibetanReordering.cpp). It assigns one number
+                          // to each type of character that has to be considered when analysing the order in which
+                          // characters can be placed
+    {
+        CC_RESERVED             =  0, //Non Combining Characters
+        CC_BASE                 =  1, // Base Consonants, Base Consonants with Subjoined attached in code point, Sanskrit base marks
+        CC_SUBJOINED            =  2, // Subjoined Consonats, combination of more than Subjoined Consonants in the code point
+        CC_TSA_PHRU             =  3, // Tsa-Phru character 0F39 
+        CC_A_CHUNG              =  4, // Vowel Lenthening a-chung mark 0F71
+        CC_COMP_SANSKRIT        =  5, // Precomposed Sanskrit vowels including Subjoined characters and vowels
+        CC_HALANTA              =  6, // Halanta Character 0F84
+        CC_BELOW_VOWEL          =  7, // Subjoined vowels
+        CC_ABOVE_VOWEL          =  8, // Superscript vowels
+        CC_ANUSVARA             =  9, // Tibetan sign Rjes Su Nga Ro 0F7E
+        CC_CANDRABINDU          = 10, // Tibetan sign Sna Ldan and Nyi Zla Naa Da 0F82, 0F83
+        CC_VISARGA              = 11, // Tibetan sign Rnam Bcad (0F7F)
+        CC_ABOVE_S_MARK         = 12, // Stress Marks placed above the text
+        CC_BELOW_S_MARK         = 13, // Stress Marks placed below the text
+        CC_DIGIT                = 14, // Dzongkha Digits
+        CC_PRE_DIGIT_MARK       = 15, // Mark placed before the digit
+        CC_POST_BELOW_DIGIT_M   = 16, // Mark placed below or after the digit
+        CC_COUNT                = 17  // This is the number of character classes
+    };
+
+    enum CharClassFlags
+    {
+        CF_CLASS_MASK    = 0x0000FFFF,
+
+        CF_DOTTED_CIRCLE = 0x04000000,  // add a dotted circle if a character with this flag is the first in a syllable
+        CF_DIGIT         = 0x01000000,  // flag to speed up comparaisson
+        CF_PREDIGIT      = 0x02000000,  // flag to detect pre-digit marks for reordering
+
+        // position flags
+        CF_POS_BEFORE    = 0x00080000,
+        CF_POS_BELOW     = 0x00040000,
+        CF_POS_ABOVE     = 0x00020000,
+        CF_POS_AFTER     = 0x00010000,
+        CF_POS_MASK      = 0x000f0000
+    };
+
+    typedef le_uint32 CharClass;
+
+    typedef le_int32 ScriptFlags;
+
+    LEUnicode firstChar;   // for Tibetan this will become xOF00
+    LEUnicode lastChar;    //  and this x0FFF
+    const CharClass *classTable;
+
+    CharClass getCharClass(LEUnicode ch) const;
+
+    static const TibetanClassTable *getTibetanClassTable();
+};
+
+
+class TibetanReordering /* not : public UObject because all methods are static */ {
+public:
+    static le_int32 reorder(const LEUnicode *theChars, le_int32 charCount, le_int32 scriptCode,
+        LEUnicode *outChars, LEGlyphStorage &glyphStorage);
+
+    static const FeatureMap *getFeatureMap(le_int32 &count);
+
+private:
+    // do not instantiate
+    TibetanReordering();
+
+    static le_int32 findSyllable(const TibetanClassTable *classTable, const LEUnicode *chars, le_int32 prev, le_int32 charCount);
+
+};
+
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layout/TrimmedArrayProcessor.cpp b/source/layout/TrimmedArrayProcessor.cpp
new file mode 100644
index 0000000..a68c056
--- /dev/null
+++ b/source/layout/TrimmedArrayProcessor.cpp
@@ -0,0 +1,55 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "SubtableProcessor.h"
+#include "NonContextualGlyphSubst.h"
+#include "NonContextualGlyphSubstProc.h"
+#include "TrimmedArrayProcessor.h"
+#include "LEGlyphStorage.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TrimmedArrayProcessor)
+
+TrimmedArrayProcessor::TrimmedArrayProcessor()
+{
+}
+
+TrimmedArrayProcessor::TrimmedArrayProcessor(const MorphSubtableHeader *morphSubtableHeader)
+  : NonContextualGlyphSubstitutionProcessor(morphSubtableHeader)
+{
+    const NonContextualGlyphSubstitutionHeader *header = (const NonContextualGlyphSubstitutionHeader *) morphSubtableHeader;
+
+    trimmedArrayLookupTable = (const TrimmedArrayLookupTable *) &header->table;
+    firstGlyph = SWAPW(trimmedArrayLookupTable->firstGlyph);
+    lastGlyph = firstGlyph + SWAPW(trimmedArrayLookupTable->glyphCount);
+}
+
+TrimmedArrayProcessor::~TrimmedArrayProcessor()
+{
+}
+
+void TrimmedArrayProcessor::process(LEGlyphStorage &glyphStorage)
+{
+    le_int32 glyphCount = glyphStorage.getGlyphCount();
+    le_int32 glyph;
+
+    for (glyph = 0; glyph < glyphCount; glyph += 1) {
+        LEGlyphID thisGlyph = glyphStorage[glyph];
+        TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(thisGlyph);
+
+        if ((ttGlyph > firstGlyph) && (ttGlyph < lastGlyph)) {
+            TTGlyphID newGlyph = SWAPW(trimmedArrayLookupTable->valueArray[ttGlyph - firstGlyph]);
+
+            glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph);
+        }
+    }
+} 
+
+U_NAMESPACE_END
diff --git a/source/layout/TrimmedArrayProcessor.h b/source/layout/TrimmedArrayProcessor.h
new file mode 100644
index 0000000..9d86980
--- /dev/null
+++ b/source/layout/TrimmedArrayProcessor.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ *
+ */
+
+#ifndef __TRIMMEDARRAYPROCESSOR_H
+#define __TRIMMEDARRAYPROCESSOR_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "SubtableProcessor.h"
+#include "NonContextualGlyphSubst.h"
+#include "NonContextualGlyphSubstProc.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+class TrimmedArrayProcessor : public NonContextualGlyphSubstitutionProcessor
+{
+public:
+    virtual void process(LEGlyphStorage &glyphStorage);
+
+    TrimmedArrayProcessor(const MorphSubtableHeader *morphSubtableHeader);
+
+    virtual ~TrimmedArrayProcessor();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 2.8
+     */
+    virtual UClassID getDynamicClassID() const;
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 2.8
+     */
+    static UClassID getStaticClassID();
+
+private:
+    TrimmedArrayProcessor();
+
+protected:
+    TTGlyphID firstGlyph;
+    TTGlyphID lastGlyph;
+    const TrimmedArrayLookupTable *trimmedArrayLookupTable;
+
+};
+
+U_NAMESPACE_END
+#endif
+
diff --git a/source/layout/ValueRecords.cpp b/source/layout/ValueRecords.cpp
new file mode 100644
index 0000000..6731ea4
--- /dev/null
+++ b/source/layout/ValueRecords.cpp
@@ -0,0 +1,304 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "ValueRecords.h"
+#include "DeviceTables.h"
+#include "GlyphIterator.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+#define Nibble(value, nibble) ((value >> (nibble * 4)) & 0xF)
+#define NibbleBits(value, nibble) (bitsInNibble[Nibble(value, nibble)])
+
+le_int16 ValueRecord::getFieldValue(ValueFormat valueFormat, ValueRecordField field) const
+{
+    le_int16 valueIndex = getFieldIndex(valueFormat, field);
+    le_int16 value = values[valueIndex];
+
+    return SWAPW(value);
+}
+
+le_int16 ValueRecord::getFieldValue(le_int16 index, ValueFormat valueFormat, ValueRecordField field) const
+{
+    le_int16 baseIndex = getFieldCount(valueFormat) * index;
+    le_int16 valueIndex = getFieldIndex(valueFormat, field);
+    le_int16 value = values[baseIndex + valueIndex];
+
+    return SWAPW(value);
+}
+
+void ValueRecord::adjustPosition(ValueFormat valueFormat, const char *base, GlyphIterator &glyphIterator,
+                                 const LEFontInstance *fontInstance) const
+{
+    float xPlacementAdjustment = 0;
+    float yPlacementAdjustment = 0;
+    float xAdvanceAdjustment   = 0;
+    float yAdvanceAdjustment   = 0;
+
+    if ((valueFormat & vfbXPlacement) != 0) {
+        le_int16 value = getFieldValue(valueFormat, vrfXPlacement);
+        LEPoint pixels;
+
+        fontInstance->transformFunits(value, 0, pixels);
+
+        xPlacementAdjustment += fontInstance->xPixelsToUnits(pixels.fX);
+        yPlacementAdjustment += fontInstance->yPixelsToUnits(pixels.fY);
+    }
+
+    if ((valueFormat & vfbYPlacement) != 0) {
+        le_int16 value = getFieldValue(valueFormat, vrfYPlacement);
+        LEPoint pixels;
+
+        fontInstance->transformFunits(0, value, pixels);
+
+        xPlacementAdjustment += fontInstance->xPixelsToUnits(pixels.fX);
+        yPlacementAdjustment += fontInstance->yPixelsToUnits(pixels.fY);
+    }
+
+    if ((valueFormat & vfbXAdvance) != 0) {
+        le_int16 value = getFieldValue(valueFormat, vrfXAdvance);
+        LEPoint pixels;
+
+        fontInstance->transformFunits(value, 0, pixels);
+
+        xAdvanceAdjustment += fontInstance->xPixelsToUnits(pixels.fX);
+        yAdvanceAdjustment += fontInstance->yPixelsToUnits(pixels.fY);
+    }
+
+    if ((valueFormat & vfbYAdvance) != 0) {
+        le_int16 value = getFieldValue(valueFormat, vrfYAdvance);
+        LEPoint pixels;
+
+        fontInstance->transformFunits(0, value, pixels);
+
+        xAdvanceAdjustment += fontInstance->xPixelsToUnits(pixels.fX);
+        yAdvanceAdjustment += fontInstance->yPixelsToUnits(pixels.fY);
+    }
+
+    // FIXME: The device adjustments should really be transformed, but
+    // the only way I know how to do that is to convert them to le_int16 units,
+    // transform them, and then convert them back to pixels. Sigh...
+    if ((valueFormat & vfbAnyDevice) != 0) {
+        le_int16 xppem = (le_int16) fontInstance->getXPixelsPerEm();
+        le_int16 yppem = (le_int16) fontInstance->getYPixelsPerEm();
+
+        if ((valueFormat & vfbXPlaDevice) != 0) {
+            Offset dtOffset = getFieldValue(valueFormat, vrfXPlaDevice);
+
+            if (dtOffset != 0) {
+                const DeviceTable *dt = (const DeviceTable *) (base + dtOffset);
+                le_int16 xAdj = dt->getAdjustment(xppem);
+
+                xPlacementAdjustment += fontInstance->xPixelsToUnits(xAdj);
+            }
+        }
+
+        if ((valueFormat & vfbYPlaDevice) != 0) {
+            Offset dtOffset = getFieldValue(valueFormat, vrfYPlaDevice);
+
+            if (dtOffset != 0) {
+                const DeviceTable *dt = (const DeviceTable *) (base + dtOffset);
+                le_int16 yAdj = dt->getAdjustment(yppem);
+
+                yPlacementAdjustment += fontInstance->yPixelsToUnits(yAdj);
+            }
+        }
+
+        if ((valueFormat & vfbXAdvDevice) != 0) {
+            Offset dtOffset = getFieldValue(valueFormat, vrfXAdvDevice);
+
+            if (dtOffset != 0) {
+                const DeviceTable *dt = (const DeviceTable *) (base + dtOffset);
+                le_int16 xAdj = dt->getAdjustment(xppem);
+
+                xAdvanceAdjustment += fontInstance->xPixelsToUnits(xAdj);
+            }
+        }
+
+        if ((valueFormat & vfbYAdvDevice) != 0) {
+            Offset dtOffset = getFieldValue(valueFormat, vrfYAdvDevice);
+
+            if (dtOffset != 0) {
+                const DeviceTable *dt = (const DeviceTable *) (base + dtOffset);
+                le_int16 yAdj = dt->getAdjustment(yppem);
+
+                yAdvanceAdjustment += fontInstance->yPixelsToUnits(yAdj);
+            }
+        }
+    }
+
+    glyphIterator.adjustCurrGlyphPositionAdjustment(
+        xPlacementAdjustment, yPlacementAdjustment, xAdvanceAdjustment, yAdvanceAdjustment);
+}
+
+void ValueRecord::adjustPosition(le_int16 index, ValueFormat valueFormat, const char *base, GlyphIterator &glyphIterator,
+                                 const LEFontInstance *fontInstance) const
+{
+    float xPlacementAdjustment = 0;
+    float yPlacementAdjustment = 0;
+    float xAdvanceAdjustment   = 0;
+    float yAdvanceAdjustment   = 0;
+
+    if ((valueFormat & vfbXPlacement) != 0) {
+        le_int16 value = getFieldValue(index, valueFormat, vrfXPlacement);
+        LEPoint pixels;
+
+        fontInstance->transformFunits(value, 0, pixels);
+
+        xPlacementAdjustment += fontInstance->xPixelsToUnits(pixels.fX);
+        yPlacementAdjustment += fontInstance->yPixelsToUnits(pixels.fY);
+    }
+
+    if ((valueFormat & vfbYPlacement) != 0) {
+        le_int16 value = getFieldValue(index, valueFormat, vrfYPlacement);
+        LEPoint pixels;
+
+        fontInstance->transformFunits(0, value, pixels);
+
+        xPlacementAdjustment += fontInstance->xPixelsToUnits(pixels.fX);
+        yPlacementAdjustment += fontInstance->yPixelsToUnits(pixels.fY);
+    }
+
+    if ((valueFormat & vfbXAdvance) != 0) {
+        le_int16 value = getFieldValue(index, valueFormat, vrfXAdvance);
+        LEPoint pixels;
+
+        fontInstance->transformFunits(value, 0, pixels);
+
+        xAdvanceAdjustment += fontInstance->xPixelsToUnits(pixels.fX);
+        yAdvanceAdjustment += fontInstance->yPixelsToUnits(pixels.fY);
+    }
+
+    if ((valueFormat & vfbYAdvance) != 0) {
+        le_int16 value = getFieldValue(index, valueFormat, vrfYAdvance);
+        LEPoint pixels;
+
+        fontInstance->transformFunits(0, value, pixels);
+
+        xAdvanceAdjustment += fontInstance->xPixelsToUnits(pixels.fX);
+        yAdvanceAdjustment += fontInstance->yPixelsToUnits(pixels.fY);
+    }
+
+    // FIXME: The device adjustments should really be transformed, but
+    // the only way I know how to do that is to convert them to le_int16 units,
+    // transform them, and then convert them back to pixels. Sigh...
+    if ((valueFormat & vfbAnyDevice) != 0) {
+        le_int16 xppem = (le_int16) fontInstance->getXPixelsPerEm();
+        le_int16 yppem = (le_int16) fontInstance->getYPixelsPerEm();
+
+        if ((valueFormat & vfbXPlaDevice) != 0) {
+            Offset dtOffset = getFieldValue(index, valueFormat, vrfXPlaDevice);
+
+            if (dtOffset != 0) {
+                const DeviceTable *dt = (const DeviceTable *) (base + dtOffset);
+                le_int16 xAdj = dt->getAdjustment(xppem);
+
+                xPlacementAdjustment += fontInstance->xPixelsToUnits(xAdj);
+            }
+        }
+
+        if ((valueFormat & vfbYPlaDevice) != 0) {
+            Offset dtOffset = getFieldValue(index, valueFormat, vrfYPlaDevice);
+
+            if (dtOffset != 0) {
+                const DeviceTable *dt = (const DeviceTable *) (base + dtOffset);
+                le_int16 yAdj = dt->getAdjustment(yppem);
+
+                yPlacementAdjustment += fontInstance->yPixelsToUnits(yAdj);
+            }
+        }
+
+        if ((valueFormat & vfbXAdvDevice) != 0) {
+            Offset dtOffset = getFieldValue(index, valueFormat, vrfXAdvDevice);
+
+            if (dtOffset != 0) {
+                const DeviceTable *dt = (const DeviceTable *) (base + dtOffset);
+                le_int16 xAdj = dt->getAdjustment(xppem);
+
+                xAdvanceAdjustment += fontInstance->xPixelsToUnits(xAdj);
+            }
+        }
+
+        if ((valueFormat & vfbYAdvDevice) != 0) {
+            Offset dtOffset = getFieldValue(index, valueFormat, vrfYAdvDevice);
+
+            if (dtOffset != 0) {
+                const DeviceTable *dt = (const DeviceTable *) (base + dtOffset);
+                le_int16 yAdj = dt->getAdjustment(yppem);
+
+                yAdvanceAdjustment += fontInstance->yPixelsToUnits(yAdj);
+            }
+        }
+    }
+
+    glyphIterator.adjustCurrGlyphPositionAdjustment(
+        xPlacementAdjustment, yPlacementAdjustment, xAdvanceAdjustment, yAdvanceAdjustment);
+}
+
+le_int16 ValueRecord::getSize(ValueFormat valueFormat)
+{
+    return getFieldCount(valueFormat) * sizeof(le_int16);
+}
+
+le_int16 ValueRecord::getFieldCount(ValueFormat valueFormat)
+{
+    static const le_int16 bitsInNibble[] =
+    {
+        0 + 0 + 0 + 0,
+        0 + 0 + 0 + 1,
+        0 + 0 + 1 + 0,
+        0 + 0 + 1 + 1,
+        0 + 1 + 0 + 0,
+        0 + 1 + 0 + 1,
+        0 + 1 + 1 + 0,
+        0 + 1 + 1 + 1,
+        1 + 0 + 0 + 0,
+        1 + 0 + 0 + 1,
+        1 + 0 + 1 + 0,
+        1 + 0 + 1 + 1,
+        1 + 1 + 0 + 0,
+        1 + 1 + 0 + 1,
+        1 + 1 + 1 + 0,
+        1 + 1 + 1 + 1
+    };
+
+    valueFormat &= ~vfbReserved;
+
+    return NibbleBits(valueFormat, 0) + NibbleBits(valueFormat, 1) +
+           NibbleBits(valueFormat, 2) + NibbleBits(valueFormat, 3);
+}
+
+le_int16 ValueRecord::getFieldIndex(ValueFormat valueFormat, ValueRecordField field)
+{
+    static const le_uint16 beforeMasks[] = 
+    {
+        0x0000,
+        0x0001,
+        0x0003,
+        0x0007,
+        0x000F,
+        0x001F,
+        0x003F,
+        0x007F,
+        0x00FF,
+        0x01FF,
+        0x03FF,
+        0x07FF,
+        0x0FFF,
+        0x1FFF,
+        0x3FFF,
+        0x7FFF,
+        0xFFFF
+    };
+
+    return getFieldCount(valueFormat & beforeMasks[field]);
+}
+
+U_NAMESPACE_END
diff --git a/source/layout/ValueRecords.h b/source/layout/ValueRecords.h
new file mode 100644
index 0000000..83db7b3
--- /dev/null
+++ b/source/layout/ValueRecords.h
@@ -0,0 +1,72 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
+ *
+ */
+
+#ifndef __VALUERECORDS_H
+#define __VALUERECORDS_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "OpenTypeTables.h"
+#include "GlyphIterator.h"
+
+U_NAMESPACE_BEGIN
+
+typedef le_uint16 ValueFormat;
+typedef le_int16 ValueRecordField;
+
+struct ValueRecord
+{
+    le_int16   values[ANY_NUMBER];
+
+    le_int16   getFieldValue(ValueFormat valueFormat, ValueRecordField field) const;
+    le_int16   getFieldValue(le_int16 index, ValueFormat valueFormat, ValueRecordField field) const;
+    void    adjustPosition(ValueFormat valueFormat, const char *base, GlyphIterator &glyphIterator,
+                const LEFontInstance *fontInstance) const;
+    void    adjustPosition(le_int16 index, ValueFormat valueFormat, const char *base, GlyphIterator &glyphIterator,
+                const LEFontInstance *fontInstance) const;
+
+    static le_int16    getSize(ValueFormat valueFormat);
+
+private:
+    static le_int16    getFieldCount(ValueFormat valueFormat);
+    static le_int16    getFieldIndex(ValueFormat valueFormat, ValueRecordField field);
+};
+
+enum ValueRecordFields
+{
+    vrfXPlacement   = 0,
+    vrfYPlacement   = 1,
+    vrfXAdvance     = 2,
+    vrfYAdvance     = 3,
+    vrfXPlaDevice   = 4,
+    vrfYPlaDevice   = 5,
+    vrfXAdvDevice   = 6,
+    vrfYAdvDevice   = 7
+};
+
+enum ValueFormatBits
+{
+    vfbXPlacement   = 0x0001,
+    vfbYPlacement   = 0x0002,
+    vfbXAdvance     = 0x0004,
+    vfbYAdvance     = 0x0008,
+    vfbXPlaDevice   = 0x0010,
+    vfbYPlaDevice   = 0x0020,
+    vfbXAdvDevice   = 0x0040,
+    vfbYAdvDevice   = 0x0080,
+    vfbReserved     = 0xFF00,
+    vfbAnyDevice    = vfbXPlaDevice + vfbYPlaDevice + vfbXAdvDevice + vfbYAdvDevice
+};
+
+U_NAMESPACE_END
+#endif
+
+
diff --git a/source/layout/layout.rc b/source/layout/layout.rc
new file mode 100644
index 0000000..b8c512d
--- /dev/null
+++ b/source/layout/layout.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 " Layout 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", "icule" U_ICU_VERSION_SHORT "d.dll\0"
+#else
+            VALUE "OriginalFilename", "icule" 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/source/layout/layout.vcxproj b/source/layout/layout.vcxproj
new file mode 100644
index 0000000..5328979
--- /dev/null
+++ b/source/layout/layout.vcxproj
@@ -0,0 +1,552 @@
+<?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>{C920062A-0647-4553-A3B2-37C58065664B}</ProjectGuid>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>DynamicLibrary</ConfigurationType>

+    <UseOfMfc>false</UseOfMfc>

+    <CharacterSet>MultiByte</CharacterSet>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" 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>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|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)'=='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|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|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)'=='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>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup>

+    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>

+    <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|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|x64'">.\x64\Debug\</OutDir>

+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\x64\Debug\</IntDir>

+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">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>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <Midl>

+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MkTypLibCompatible>true</MkTypLibCompatible>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <TargetEnvironment>Win32</TargetEnvironment>

+      <TypeLibraryName>.\..\..\lib\iculed.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>..\..\include;..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;U_LAYOUT_IMPLEMENTATION;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>

+      <BufferSecurityCheck>true</BufferSecurityCheck>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x86\Debug/layout.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\icule46d.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <ProgramDatabaseFile>.\..\..\lib\iculed.pdb</ProgramDatabaseFile>

+      <BaseAddress>0x4ac00000</BaseAddress>

+      <RandomizedBaseAddress>false</RandomizedBaseAddress>

+      <DataExecutionPrevention>

+      </DataExecutionPrevention>

+      <ImportLibrary>..\..\lib\iculed.lib</ImportLibrary>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <Midl>

+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MkTypLibCompatible>true</MkTypLibCompatible>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <TargetEnvironment>Win32</TargetEnvironment>

+      <TypeLibraryName>.\..\..\lib\icule.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <AdditionalIncludeDirectories>..\..\include;..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;U_LAYOUT_IMPLEMENTATION;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <StringPooling>true</StringPooling>

+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x86\Release/layout.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\icule46.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <ProgramDatabaseFile>.\..\..\lib\icule.pdb</ProgramDatabaseFile>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <BaseAddress>0x4ac00000</BaseAddress>

+      <RandomizedBaseAddress>false</RandomizedBaseAddress>

+      <DataExecutionPrevention>

+      </DataExecutionPrevention>

+      <ImportLibrary>..\..\lib\icule.lib</ImportLibrary>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <Midl>

+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MkTypLibCompatible>true</MkTypLibCompatible>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <TargetEnvironment>X64</TargetEnvironment>

+      <TypeLibraryName>.\..\..\lib64\iculed.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>..\..\include;..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN64;WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;U_LAYOUT_IMPLEMENTATION;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>

+      <BufferSecurityCheck>true</BufferSecurityCheck>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x64\Debug/layout.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\icule46d.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <ProgramDatabaseFile>.\..\..\lib64\iculed.pdb</ProgramDatabaseFile>

+      <BaseAddress>0x4ac00000</BaseAddress>

+      <ImportLibrary>..\..\lib64\iculed.lib</ImportLibrary>

+      <TargetMachine>MachineX64</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <Midl>

+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MkTypLibCompatible>true</MkTypLibCompatible>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <TargetEnvironment>X64</TargetEnvironment>

+      <TypeLibraryName>.\..\..\lib64\icule.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <AdditionalIncludeDirectories>..\..\include;..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN64;WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;U_LAYOUT_IMPLEMENTATION;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <StringPooling>true</StringPooling>

+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x64\Release/layout.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\icule46.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <ProgramDatabaseFile>.\..\..\lib64\icule.pdb</ProgramDatabaseFile>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <BaseAddress>0x4ac00000</BaseAddress>

+      <ImportLibrary>..\..\lib64\icule.lib</ImportLibrary>

+      <TargetMachine>MachineX64</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="AlternateSubstSubtables.cpp" />

+    <ClCompile Include="AnchorTables.cpp" />

+    <ClCompile Include="ArabicLayoutEngine.cpp" />

+    <ClCompile Include="ArabicShaping.cpp" />

+    <ClCompile Include="CanonData.cpp" />

+    <ClCompile Include="CanonShaping.cpp" />

+    <ClCompile Include="ClassDefinitionTables.cpp" />

+    <ClCompile Include="ContextualGlyphSubstProc.cpp" />

+    <ClCompile Include="ContextualSubstSubtables.cpp" />

+    <ClCompile Include="CoverageTables.cpp" />

+    <ClCompile Include="CursiveAttachmentSubtables.cpp" />

+    <ClCompile Include="DeviceTables.cpp" />

+    <ClCompile Include="ExtensionSubtables.cpp" />

+    <ClCompile Include="Features.cpp" />

+    <ClCompile Include="GDEFMarkFilter.cpp" />

+    <ClCompile Include="GlyphDefinitionTables.cpp" />

+    <ClCompile Include="GlyphIterator.cpp" />

+    <ClCompile Include="GlyphLookupTables.cpp" />

+    <ClCompile Include="GlyphPositionAdjustments.cpp" />

+    <ClCompile Include="GlyphPositioningTables.cpp" />

+    <ClCompile Include="GlyphPosnLookupProc.cpp" />

+    <ClCompile Include="GlyphSubstitutionTables.cpp" />

+    <ClCompile Include="GlyphSubstLookupProc.cpp" />

+    <ClCompile Include="GXLayoutEngine.cpp" />

+    <ClCompile Include="HangulLayoutEngine.cpp" />

+    <ClCompile Include="HanLayoutEngine.cpp" />

+    <ClCompile Include="IndicClassTables.cpp" />

+    <ClCompile Include="IndicLayoutEngine.cpp" />

+    <ClCompile Include="IndicRearrangementProcessor.cpp" />

+    <ClCompile Include="IndicReordering.cpp" />

+    <ClCompile Include="KernTable.cpp" />

+    <ClCompile Include="KhmerLayoutEngine.cpp" />

+    <ClCompile Include="KhmerReordering.cpp" />

+    <ClCompile Include="LayoutEngine.cpp" />

+    <ClCompile Include="LEFontInstance.cpp" />

+    <ClCompile Include="LEGlyphStorage.cpp" />

+    <ClCompile Include="LEInsertionList.cpp" />

+    <ClCompile Include="LigatureSubstProc.cpp" />

+    <ClCompile Include="LigatureSubstSubtables.cpp" />

+    <ClCompile Include="loengine.cpp" />

+    <ClCompile Include="LookupProcessor.cpp" />

+    <ClCompile Include="Lookups.cpp" />

+    <ClCompile Include="LookupTables.cpp" />

+    <ClCompile Include="MarkArrays.cpp" />

+    <ClCompile Include="MarkToBasePosnSubtables.cpp" />

+    <ClCompile Include="MarkToLigaturePosnSubtables.cpp" />

+    <ClCompile Include="MarkToMarkPosnSubtables.cpp" />

+    <ClCompile Include="MirroredCharData.cpp" />

+    <ClCompile Include="MorphTables.cpp" />

+    <ClCompile Include="MPreFixups.cpp" />

+    <ClCompile Include="MultipleSubstSubtables.cpp" />

+    <ClCompile Include="NonContextualGlyphSubstProc.cpp" />

+    <ClCompile Include="OpenTypeLayoutEngine.cpp" />

+    <ClCompile Include="OpenTypeUtilities.cpp" />

+    <ClCompile Include="PairPositioningSubtables.cpp" />

+    <ClCompile Include="ScriptAndLanguage.cpp" />

+    <ClCompile Include="ScriptAndLanguageTags.cpp" />

+    <ClCompile Include="SegmentArrayProcessor.cpp" />

+    <ClCompile Include="SegmentSingleProcessor.cpp" />

+    <ClCompile Include="ShapingTypeData.cpp" />

+    <ClCompile Include="SimpleArrayProcessor.cpp" />

+    <ClCompile Include="SinglePositioningSubtables.cpp" />

+    <ClCompile Include="SingleSubstitutionSubtables.cpp" />

+    <ClCompile Include="SingleTableProcessor.cpp" />

+    <ClCompile Include="StateTableProcessor.cpp" />

+    <ClCompile Include="SubstitutionLookups.cpp" />

+    <ClCompile Include="SubtableProcessor.cpp" />

+    <ClCompile Include="ThaiLayoutEngine.cpp" />

+    <ClCompile Include="ThaiShaping.cpp" />

+    <ClCompile Include="ThaiStateTables.cpp" />

+    <ClCompile Include="TibetanLayoutEngine.cpp" />

+    <ClCompile Include="TibetanReordering.cpp" />

+    <ClCompile Include="TrimmedArrayProcessor.cpp" />

+    <ClCompile Include="ValueRecords.cpp" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="AlternateSubstSubtables.h" />

+    <ClInclude Include="AnchorTables.h" />

+    <ClInclude Include="ArabicLayoutEngine.h" />

+    <ClInclude Include="ArabicShaping.h" />

+    <ClInclude Include="AttachmentPosnSubtables.h" />

+    <ClInclude Include="CanonShaping.h" />

+    <ClInclude Include="CharSubstitutionFilter.h" />

+    <ClInclude Include="ClassDefinitionTables.h" />

+    <ClInclude Include="ContextualGlyphInsertion.h" />

+    <ClInclude Include="ContextualGlyphSubstitution.h" />

+    <ClInclude Include="ContextualGlyphSubstProc.h" />

+    <ClInclude Include="ContextualSubstSubtables.h" />

+    <ClInclude Include="CoverageTables.h" />

+    <ClInclude Include="CursiveAttachmentSubtables.h" />

+    <ClInclude Include="DefaultCharMapper.h" />

+    <ClInclude Include="DeviceTables.h" />

+    <ClInclude Include="ExtensionSubtables.h" />

+    <ClInclude Include="GDEFMarkFilter.h" />

+    <ClInclude Include="GlyphDefinitionTables.h" />

+    <ClInclude Include="GlyphIterator.h" />

+    <ClInclude Include="GlyphLookupTables.h" />

+    <ClInclude Include="GlyphPositionAdjustments.h" />

+    <ClInclude Include="GlyphPositioningTables.h" />

+    <ClInclude Include="GlyphPosnLookupProc.h" />

+    <ClInclude Include="GlyphSubstitutionTables.h" />

+    <ClInclude Include="GlyphSubstLookupProc.h" />

+    <ClInclude Include="GXLayoutEngine.h" />

+    <ClInclude Include="HangulLayoutEngine.h" />

+    <ClInclude Include="HanLayoutEngine.h" />

+    <ClInclude Include="ICUFeatures.h" />

+    <ClInclude Include="IndicLayoutEngine.h" />

+    <ClInclude Include="IndicRearrangement.h" />

+    <ClInclude Include="IndicRearrangementProcessor.h" />

+    <ClInclude Include="IndicReordering.h" />

+    <ClInclude Include="KernTable.h" />

+    <ClInclude Include="KhmerLayoutEngine.h" />

+    <ClInclude Include="KhmerReordering.h" />

+    <CustomBuild Include="LayoutEngine.h">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+    </CustomBuild>

+    <ClInclude Include="LayoutTables.h" />

+    <CustomBuild Include="LEFontInstance.h">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+    </CustomBuild>

+    <CustomBuild Include="LEGlyphFilter.h">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+    </CustomBuild>

+    <CustomBuild Include="LEGlyphStorage.h">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+    </CustomBuild>

+    <CustomBuild Include="LEInsertionList.h">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+    </CustomBuild>

+    <CustomBuild Include="LELanguages.h">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+    </CustomBuild>

+    <CustomBuild Include="LEScripts.h">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+    </CustomBuild>

+    <CustomBuild Include="LESwaps.h">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+    </CustomBuild>

+    <CustomBuild Include="LETypes.h">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+    </CustomBuild>

+    <ClInclude Include="LigatureSubstitution.h" />

+    <ClInclude Include="LigatureSubstProc.h" />

+    <ClInclude Include="LigatureSubstSubtables.h" />

+    <CustomBuild Include="loengine.h">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+    </CustomBuild>

+    <ClInclude Include="LookupProcessor.h" />

+    <ClInclude Include="Lookups.h" />

+    <ClInclude Include="LookupTables.h" />

+    <ClInclude Include="MarkArrays.h" />

+    <ClInclude Include="MarkToBasePosnSubtables.h" />

+    <ClInclude Include="MarkToLigaturePosnSubtables.h" />

+    <ClInclude Include="MarkToMarkPosnSubtables.h" />

+    <ClInclude Include="MorphStateTables.h" />

+    <ClInclude Include="MorphTables.h" />

+    <ClInclude Include="MPreFixups.h" />

+    <ClInclude Include="MultipleSubstSubtables.h" />

+    <ClInclude Include="NonContextualGlyphSubst.h" />

+    <ClInclude Include="NonContextualGlyphSubstProc.h" />

+    <ClInclude Include="OpenTypeLayoutEngine.h" />

+    <ClInclude Include="OpenTypeTables.h" />

+    <ClInclude Include="OpenTypeUtilities.h" />

+    <ClInclude Include="PairPositioningSubtables.h" />

+    <ClInclude Include="ScriptAndLanguage.h" />

+    <ClInclude Include="ScriptAndLanguageTags.h" />

+    <ClInclude Include="SegmentArrayProcessor.h" />

+    <ClInclude Include="SegmentSingleProcessor.h" />

+    <ClInclude Include="SimpleArrayProcessor.h" />

+    <ClInclude Include="SinglePositioningSubtables.h" />

+    <ClInclude Include="SingleSubstitutionSubtables.h" />

+    <ClInclude Include="SingleTableProcessor.h" />

+    <ClInclude Include="StateTableProcessor.h" />

+    <ClInclude Include="StateTables.h" />

+    <ClInclude Include="SubstitutionLookups.h" />

+    <ClInclude Include="SubtableProcessor.h" />

+    <ClInclude Include="ThaiLayoutEngine.h" />

+    <ClInclude Include="ThaiShaping.h" />

+    <ClInclude Include="TibetanLayoutEngine.h" />

+    <ClInclude Include="TibetanReordering.h" />

+    <ClInclude Include="TrimmedArrayProcessor.h" />

+    <ClInclude Include="ValueRecords.h" />

+  </ItemGroup>

+  <ItemGroup>

+    <ResourceCompile Include="layout.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/source/layout/layout.vcxproj.filters b/source/layout/layout.vcxproj.filters
new file mode 100644
index 0000000..65c30ab
--- /dev/null
+++ b/source/layout/layout.vcxproj.filters
@@ -0,0 +1,508 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{612bee68-b22e-47ed-8cb2-2c5ca5ea6350}</UniqueIdentifier>

+      <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>

+    </Filter>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{6ccc0372-c74a-4a85-b31a-da1c0c72b56d}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl</Extensions>

+    </Filter>

+    <Filter Include="Resource Files">

+      <UniqueIdentifier>{ea7162f2-e3c7-47a7-98aa-e19c06f9e195}</UniqueIdentifier>

+      <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="AlternateSubstSubtables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="AnchorTables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ArabicLayoutEngine.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ArabicShaping.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="CanonData.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="CanonShaping.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ClassDefinitionTables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ContextualGlyphSubstProc.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ContextualSubstSubtables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="CoverageTables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="CursiveAttachmentSubtables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="DeviceTables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ExtensionSubtables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="Features.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="GDEFMarkFilter.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="GlyphDefinitionTables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="GlyphIterator.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="GlyphLookupTables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="GlyphPositionAdjustments.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="GlyphPositioningTables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="GlyphPosnLookupProc.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="GlyphSubstitutionTables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="GlyphSubstLookupProc.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="GXLayoutEngine.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="HangulLayoutEngine.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="HanLayoutEngine.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="IndicClassTables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="IndicLayoutEngine.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="IndicRearrangementProcessor.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="IndicReordering.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="KernTable.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="KhmerLayoutEngine.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="KhmerReordering.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="LayoutEngine.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="LEFontInstance.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="LEGlyphStorage.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="LEInsertionList.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="LigatureSubstProc.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="LigatureSubstSubtables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="loengine.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="LookupProcessor.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="Lookups.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="LookupTables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="MarkArrays.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="MarkToBasePosnSubtables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="MarkToLigaturePosnSubtables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="MarkToMarkPosnSubtables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="MirroredCharData.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="MorphTables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="MPreFixups.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="MultipleSubstSubtables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="NonContextualGlyphSubstProc.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="OpenTypeLayoutEngine.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="OpenTypeUtilities.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="PairPositioningSubtables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ScriptAndLanguage.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ScriptAndLanguageTags.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="SegmentArrayProcessor.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="SegmentSingleProcessor.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ShapingTypeData.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="SimpleArrayProcessor.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="SinglePositioningSubtables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="SingleSubstitutionSubtables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="SingleTableProcessor.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="StateTableProcessor.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="SubstitutionLookups.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="SubtableProcessor.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ThaiLayoutEngine.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ThaiShaping.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ThaiStateTables.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="TibetanLayoutEngine.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="TibetanReordering.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="TrimmedArrayProcessor.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ValueRecords.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="AlternateSubstSubtables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="AnchorTables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ArabicLayoutEngine.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ArabicShaping.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="AttachmentPosnSubtables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="CanonShaping.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="CharSubstitutionFilter.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ClassDefinitionTables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ContextualGlyphInsertion.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ContextualGlyphSubstitution.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ContextualGlyphSubstProc.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ContextualSubstSubtables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="CoverageTables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="CursiveAttachmentSubtables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="DefaultCharMapper.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="DeviceTables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ExtensionSubtables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="GDEFMarkFilter.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="GlyphDefinitionTables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="GlyphIterator.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="GlyphLookupTables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="GlyphPositionAdjustments.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="GlyphPositioningTables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="GlyphPosnLookupProc.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="GlyphSubstitutionTables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="GlyphSubstLookupProc.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="GXLayoutEngine.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="HangulLayoutEngine.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="HanLayoutEngine.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ICUFeatures.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="IndicLayoutEngine.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="IndicRearrangement.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="IndicRearrangementProcessor.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="IndicReordering.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="KernTable.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="KhmerLayoutEngine.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="KhmerReordering.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="LayoutTables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="LigatureSubstitution.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="LigatureSubstProc.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="LigatureSubstSubtables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="LookupProcessor.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="Lookups.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="LookupTables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="MarkArrays.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="MarkToBasePosnSubtables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="MarkToLigaturePosnSubtables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="MarkToMarkPosnSubtables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="MorphStateTables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="MorphTables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="MPreFixups.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="MultipleSubstSubtables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="NonContextualGlyphSubst.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="NonContextualGlyphSubstProc.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="OpenTypeLayoutEngine.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="OpenTypeTables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="OpenTypeUtilities.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="PairPositioningSubtables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ScriptAndLanguage.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ScriptAndLanguageTags.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="SegmentArrayProcessor.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="SegmentSingleProcessor.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="SimpleArrayProcessor.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="SinglePositioningSubtables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="SingleSubstitutionSubtables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="SingleTableProcessor.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="StateTableProcessor.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="StateTables.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="SubstitutionLookups.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="SubtableProcessor.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ThaiLayoutEngine.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ThaiShaping.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="TibetanLayoutEngine.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="TibetanReordering.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="TrimmedArrayProcessor.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+    <ClInclude Include="ValueRecords.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+  <ItemGroup>

+    <ResourceCompile Include="layout.rc">

+      <Filter>Resource Files</Filter>

+    </ResourceCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <CustomBuild Include="LayoutEngine.h">

+      <Filter>Header Files</Filter>

+    </CustomBuild>

+    <CustomBuild Include="LEFontInstance.h">

+      <Filter>Header Files</Filter>

+    </CustomBuild>

+    <CustomBuild Include="LEGlyphFilter.h">

+      <Filter>Header Files</Filter>

+    </CustomBuild>

+    <CustomBuild Include="LEGlyphStorage.h">

+      <Filter>Header Files</Filter>

+    </CustomBuild>

+    <CustomBuild Include="LEInsertionList.h">

+      <Filter>Header Files</Filter>

+    </CustomBuild>

+    <CustomBuild Include="LELanguages.h">

+      <Filter>Header Files</Filter>

+    </CustomBuild>

+    <CustomBuild Include="LEScripts.h">

+      <Filter>Header Files</Filter>

+    </CustomBuild>

+    <CustomBuild Include="LESwaps.h">

+      <Filter>Header Files</Filter>

+    </CustomBuild>

+    <CustomBuild Include="LETypes.h">

+      <Filter>Header Files</Filter>

+    </CustomBuild>

+    <CustomBuild Include="loengine.h">

+      <Filter>Header Files</Filter>

+    </CustomBuild>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/source/layout/loengine.cpp b/source/layout/loengine.cpp
new file mode 100644
index 0000000..3718b9f
--- /dev/null
+++ b/source/layout/loengine.cpp
@@ -0,0 +1,163 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "loengine.h"
+#include "LayoutEngine.h"
+
+/**
+ * \file 
+ * \brief C API for complex text layout.
+ */
+
+U_NAMESPACE_USE
+
+U_CAPI le_engine * U_EXPORT2
+le_create(const le_font *font,
+		  le_int32 scriptCode,
+		  le_int32 languageCode,
+		  le_int32 typo_flags,
+		  LEErrorCode *success)
+{
+	LEFontInstance *fontInstance = (LEFontInstance *) font;
+
+	return (le_engine *) LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, typo_flags, *success);
+}
+
+U_CAPI void U_EXPORT2
+le_close(le_engine *engine)
+{
+	LayoutEngine *le = (LayoutEngine *) engine;
+
+	delete le;
+}
+
+U_CAPI le_int32 U_EXPORT2
+le_layoutChars(le_engine *engine,
+			   const LEUnicode chars[],
+			   le_int32 offset,
+			   le_int32 count,
+			   le_int32 max,
+			   le_bool rightToLeft,
+			   float x,
+			   float y,
+			   LEErrorCode *success)
+{
+	LayoutEngine *le = (LayoutEngine *) engine;
+
+	if (le == NULL) {
+		*success = LE_ILLEGAL_ARGUMENT_ERROR;
+		return -1;
+	}
+
+	return le->layoutChars(chars, offset, count, max, rightToLeft, x, y, *success);
+}
+
+U_CAPI le_int32 U_EXPORT2
+le_getGlyphCount(le_engine *engine,
+				 LEErrorCode *success)
+{
+	LayoutEngine *le = (LayoutEngine *) engine;
+
+	if (le == NULL) {
+		*success = LE_ILLEGAL_ARGUMENT_ERROR;
+		return -1;
+	}
+
+	return le->getGlyphCount();
+}
+
+U_CAPI void U_EXPORT2
+le_getGlyphs(le_engine *engine,
+			 LEGlyphID glyphs[],
+			 LEErrorCode *success)
+{
+	LayoutEngine *le = (LayoutEngine *) engine;
+
+	if (le == NULL) {
+		*success = LE_ILLEGAL_ARGUMENT_ERROR;
+		return;
+	}
+
+	le->getGlyphs(glyphs, *success);
+}
+
+U_CAPI void U_EXPORT2
+le_getCharIndices(le_engine *engine,
+				  le_int32 charIndices[],
+				  LEErrorCode *success)
+{
+	LayoutEngine *le = (LayoutEngine *) engine;
+
+	if (le == NULL) {
+		*success = LE_ILLEGAL_ARGUMENT_ERROR;
+		return;
+	}
+
+	le->getCharIndices(charIndices, *success);
+}
+
+U_CAPI void U_EXPORT2
+le_getCharIndicesWithBase(le_engine *engine,
+				          le_int32 charIndices[],
+				          le_int32 indexBase,
+				          LEErrorCode *success)
+{
+	LayoutEngine *le = (LayoutEngine *) engine;
+
+	if (le == NULL) {
+		*success = LE_ILLEGAL_ARGUMENT_ERROR;
+		return;
+	}
+
+	le->getCharIndices(charIndices, indexBase, *success);
+}
+
+U_CAPI void U_EXPORT2
+le_getGlyphPositions(le_engine *engine,
+					 float positions[],
+					 LEErrorCode *success)
+{
+	LayoutEngine *le = (LayoutEngine *) engine;
+
+	if (le == NULL) {
+		*success = LE_ILLEGAL_ARGUMENT_ERROR;
+		return;
+	}
+
+	le->getGlyphPositions(positions, *success);
+}
+
+U_CAPI void U_EXPORT2
+le_getGlyphPosition(le_engine *engine,
+					le_int32 glyphIndex,
+					float *x,
+					float *y,
+					LEErrorCode *success)
+{
+	LayoutEngine *le = (LayoutEngine *) engine;
+
+	if (le == NULL) {
+		*success = LE_ILLEGAL_ARGUMENT_ERROR;
+		return;
+	}
+
+	le->getGlyphPosition(glyphIndex, *x, *y, *success);
+}
+
+U_CAPI void U_EXPORT2
+le_reset(le_engine *engine,
+		 LEErrorCode *success)
+{
+	LayoutEngine *le = (LayoutEngine *) engine;
+
+	if (le == NULL) {
+		*success = LE_ILLEGAL_ARGUMENT_ERROR;
+		return;
+	}
+
+	le->reset();
+}
diff --git a/source/layout/loengine.h b/source/layout/loengine.h
new file mode 100644
index 0000000..722dd32
--- /dev/null
+++ b/source/layout/loengine.h
@@ -0,0 +1,223 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#ifndef __LOENGINE_H
+#define __LOENGINE_H
+
+#include "LETypes.h"
+
+/**
+ * \file 
+ * \brief C API for complex text layout.
+ * \internal
+ *
+ * This is a technology preview. The API may
+ * change significantly.
+ *
+ */
+
+/**
+ * The opaque type for a LayoutEngine.
+ *
+ * @internal
+ */
+typedef void le_engine;
+
+/**
+ * The opaque type for a font instance.
+ *
+ * @internal
+ */
+typedef void le_font;
+
+/**
+ * This function returns an le_engine capable of laying out text
+ * in the given font, script and langauge. Note that the LayoutEngine
+ * returned may be a subclass of LayoutEngine.
+ *
+ * @param font - the font of the text
+ * @param scriptCode - the script of the text
+ * @param languageCode - the language of the text
+ * @param typo_flags - flags that control layout features like kerning and ligatures.
+ * @param success - output parameter set to an error code if the operation fails
+ *
+ * @return an le_engine which can layout text in the given font.
+ *
+ * @internal
+ */
+U_INTERNAL le_engine * U_EXPORT2
+le_create(const le_font *font,
+          le_int32 scriptCode,
+          le_int32 languageCode,
+          le_int32 typo_flags,
+          LEErrorCode *success);
+
+/**
+ * This function closes the given LayoutEngine. After
+ * it returns, the le_engine is no longer valid.
+ *
+ * @param engine - the LayoutEngine to close.
+ *
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2
+le_close(le_engine *engine);
+
+/**
+ * This routine will compute the glyph, character index and position arrays.
+ *
+ * @param engine - the LayoutEngine
+ * @param chars - the input character context
+ * @param offset - the offset of the first character to process
+ * @param count - the number of characters to process
+ * @param max - the number of characters in the input context
+ * @param rightToLeft - TRUE if the characers are in a right to left directional run
+ * @param x - the initial X position
+ * @param y - the initial Y position
+ * @param success - output parameter set to an error code if the operation fails
+ *
+ * @return the number of glyphs in the glyph array
+ *
+ * Note: The glyph, character index and position array can be accessed
+ * using the getter routines below.
+ *
+ * Note: If you call this function more than once, you must call the reset()
+ * function first to free the glyph, character index and position arrays
+ * allocated by the previous call.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+le_layoutChars(le_engine *engine,
+               const LEUnicode chars[],
+               le_int32 offset,
+               le_int32 count,
+               le_int32 max,
+               le_bool rightToLeft,
+               float x,
+               float y,
+               LEErrorCode *success);
+
+/**
+ * This function returns the number of glyphs in the glyph array. Note
+ * that the number of glyphs will be greater than or equal to the number
+ * of characters used to create the LayoutEngine.
+ *
+ * @param engine - the LayoutEngine
+ * @param success - output parameter set to an error code if the operation fails.
+ *
+ * @return the number of glyphs in the glyph array
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+le_getGlyphCount(le_engine *engine,
+                 LEErrorCode *success);
+
+/**
+ * This function copies the glyph array into a caller supplied array.
+ * The caller must ensure that the array is large enough to hold all
+ * the glyphs.
+ *
+ * @param engine - the LayoutEngine
+ * @param glyphs - the destiniation glyph array
+ * @param success - set to an error code if the operation fails
+ *
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2
+le_getGlyphs(le_engine *engine,
+             LEGlyphID glyphs[],
+             LEErrorCode *success);
+
+/**
+ * This function copies the character index array into a caller supplied array.
+ * The caller must ensure that the array is large enough to hold a
+ * character index for each glyph.
+ *
+ * @param engine - the LayoutEngine
+ * @param charIndices - the destiniation character index array
+ * @param success - set to an error code if the operation fails
+ *
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2
+le_getCharIndices(le_engine *engine,
+                  le_int32 charIndices[],
+                  LEErrorCode *success);
+
+/**
+ * This function copies the character index array into a caller supplied array.
+ * The caller must ensure that the array is large enough to hold a
+ * character index for each glyph.
+ *
+ * @param engine - the LayoutEngine
+ * @param charIndices - the destiniation character index array
+ * @param indexBase - an offset that will be added to each index.
+ * @param success - set to an error code if the operation fails
+ *
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2
+le_getCharIndicesWithBase(le_engine *engine,
+                  le_int32 charIndices[],
+                  le_int32 indexBase,
+                  LEErrorCode *success);
+
+/**
+ * This function copies the position array into a caller supplied array.
+ * The caller must ensure that the array is large enough to hold an
+ * X and Y position for each glyph, plus an extra X and Y for the
+ * advance of the last glyph.
+ *
+ * @param engine - the LayoutEngine
+ * @param positions - the destiniation position array
+ * @param success - set to an error code if the operation fails
+ *
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2
+le_getGlyphPositions(le_engine *engine,
+                     float positions[],
+                     LEErrorCode *success);
+
+/**
+ * This function returns the X and Y position of the glyph at
+ * the given index.
+ *
+ * Input parameters:
+ * @param engine - the LayoutEngine
+ * @param glyphIndex - the index of the glyph
+ *
+ * Output parameters:
+ * @param x - the glyph's X position
+ * @param y - the glyph's Y position
+ * @param success - set to an error code if the operation fails
+ *
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2
+le_getGlyphPosition(le_engine *engine,
+                    le_int32 glyphIndex,
+                    float *x,
+                    float *y,
+                    LEErrorCode *success);
+
+/**
+ * This function frees the glyph, character index and position arrays
+ * so that the LayoutEngine can be reused to layout a different
+ * characer array. (This function is also called by le_close)
+ *
+ * @param engine - the LayoutEngine
+ * @param success - set to an error code if the operation fails
+ *
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2
+le_reset(le_engine *engine,
+         LEErrorCode *success);
+
+#endif
diff --git a/source/layoutex/LXUtilities.cpp b/source/layoutex/LXUtilities.cpp
new file mode 100644
index 0000000..29cff25
--- /dev/null
+++ b/source/layoutex/LXUtilities.cpp
@@ -0,0 +1,99 @@
+/*
+ **********************************************************************
+ *   Copyright (C) 2002-2003, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ **********************************************************************
+ */
+
+#include "layout/LETypes.h"
+#include "LXUtilities.h"
+
+U_NAMESPACE_BEGIN
+
+//
+// Finds the high bit by binary searching
+// through the bits in n.
+//
+le_int8 LXUtilities::highBit(le_int32 value)
+{
+    if (value <= 0) {
+        return -32;
+    }
+
+    le_int8 bit = 0;
+
+    if (value >= 1 << 16) {
+        value >>= 16;
+        bit += 16;
+    }
+
+    if (value >= 1 << 8) {
+        value >>= 8;
+        bit += 8;
+    }
+
+    if (value >= 1 << 4) {
+        value >>= 4;
+        bit += 4;
+    }
+
+    if (value >= 1 << 2) {
+        value >>= 2;
+        bit += 2;
+    }
+
+    if (value >= 1 << 1) {
+        value >>= 1;
+        bit += 1;
+    }
+
+    return bit;
+}
+
+le_int32 LXUtilities::search(le_int32 value, const le_int32 array[], le_int32 count)
+{
+    le_int32 power = 1 << highBit(count);
+    le_int32 extra = count - power;
+    le_int32 probe = power;
+    le_int32 index = 0;
+
+    if (value >= array[extra]) {
+        index = extra;
+    }
+
+    while (probe > (1 << 0)) {
+        probe >>= 1;
+
+        if (value >= array[index + probe]) {
+            index += probe;
+        }
+    }
+
+    return index;
+}
+
+void LXUtilities::reverse(le_int32 array[], le_int32 length)
+{
+    le_int32 front, back;
+
+    for (front = 0, back = length - 1; front < back; front += 1, back -= 1) {
+        le_int32 swap = array[front];
+
+        array[front] = array[back];
+        array[back]  = swap;
+    }
+}
+
+void LXUtilities::reverse(float array[], le_int32 length)
+{
+    le_int32 front, back;
+
+    for (front = 0, back = length - 1; front < back; front += 1, back -= 1) {
+        float swap = array[front];
+
+        array[front] = array[back];
+        array[back]  = swap;
+    }
+}
+
+U_NAMESPACE_END
diff --git a/source/layoutex/LXUtilities.h b/source/layoutex/LXUtilities.h
new file mode 100644
index 0000000..308b65f
--- /dev/null
+++ b/source/layoutex/LXUtilities.h
@@ -0,0 +1,26 @@
+/*
+ **********************************************************************
+ *   Copyright (C) 2003, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ **********************************************************************
+ */
+
+#ifndef __LXUTILITIES_H
+
+#define __LXUTILITIES_H
+
+#include "layout/LETypes.h"
+
+U_NAMESPACE_BEGIN
+
+class LXUtilities
+{
+public:
+    static le_int8 highBit(le_int32 value);
+    static le_int32 search(le_int32 value, const le_int32 array[], le_int32 count);
+    static void reverse(le_int32 array[], le_int32 count);
+    static void reverse(float array[], le_int32 count);
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layoutex/Makefile.in b/source/layoutex/Makefile.in
new file mode 100644
index 0000000..71e37f6
--- /dev/null
+++ b/source/layoutex/Makefile.in
@@ -0,0 +1,167 @@
+#******************************************************************************
+#
+#   Copyright (C) 1999-2008, International Business Machines
+#   Corporation and others.  All Rights Reserved.
+#
+#******************************************************************************
+## Makefile.in for ICU - layout
+
+## 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 = layoutex
+
+## Extra files to remove for 'make clean'
+CLEANFILES = *~ $(DEPS) $(IMPORT_LIB) $(MIDDLE_IMPORT_LIB) $(FINAL_IMPORT_LIB)
+
+## Target information
+
+TARGET_STUBNAME=$(LAYOUTEX_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 = layoutex.res
+endif
+
+ifeq ($(OS390BATCH),1)
+BATCH_TARGET = $(BATCH_LAYOUTEX_TARGET)
+BATCH_LIBS = $(BATCH_LIBICUUC) $(BATCH_LIBICULE) -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$(srcdir)/unicode -I$(srcdir)/.. -I$(top_srcdir)/common $(LIBCPPFLAGS)
+DEFS += -DU_LAYOUTEX_IMPLEMENTATION
+LDFLAGS += $(LDFLAGSICULX)
+LIBS = $(LIBICUUC) $(LIBICULE) $(DEFAULT_LIBS)
+
+OBJECTS =  ParagraphLayout.o \
+RunArrays.o \
+LXUtilities.o  \
+playout.o \
+plruns.o
+
+## Header files to install
+HEADERS= $(srcdir)/layout/ParagraphLayout.h $(srcdir)/layout/RunArrays.h $(srcdir)/layout/playout.h $(srcdir)/layout/plruns.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)/layout
+	@for file in $(HEADERS); do \
+	 echo "$(INSTALL_DATA) $$file $(DESTDIR)$(includedir)/layout"; \
+	 $(INSTALL_DATA) $$file $(DESTDIR)$(includedir)/layout || 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/source/layoutex/ParagraphLayout.cpp b/source/layoutex/ParagraphLayout.cpp
new file mode 100644
index 0000000..dcfa3e4
--- /dev/null
+++ b/source/layoutex/ParagraphLayout.cpp
@@ -0,0 +1,1276 @@
+/*
+ **********************************************************************
+ *   Copyright (C) 2002-2010, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ **********************************************************************
+ */
+
+/*
+ * paragraphLayout doesn't make much sense without
+ * BreakIterator...
+ */
+#include "layout/LETypes.h"
+#include "layout/LEScripts.h"
+#include "layout/LELanguages.h"
+#include "layout/LayoutEngine.h"
+#include "layout/LEFontInstance.h"
+
+#include "unicode/ubidi.h"
+#include "unicode/uchriter.h"
+#include "unicode/brkiter.h"
+
+#if ! UCONFIG_NO_BREAK_ITERATION
+#include "LXUtilities.h"
+#include "usc_impl.h" /* this is currently private! */
+#include "cstring.h"  /* this too! */
+
+#include "layout/ParagraphLayout.h"
+
+U_NAMESPACE_BEGIN
+
+#define ARRAY_SIZE(array) (sizeof array  / sizeof array[0])
+
+/* Leave this copyright notice here! It needs to go somewhere in this library. */
+static const char copyright[] = U_COPYRIGHT_STRING;
+
+class StyleRuns
+{
+public:
+    StyleRuns(const RunArray *styleRunArrays[], le_int32 styleCount);
+
+    ~StyleRuns();
+
+    le_int32 getRuns(le_int32 runLimits[], le_int32 styleIndices[]);
+
+private:
+    le_int32 fStyleCount;
+    le_int32 fRunCount;
+
+    le_int32 *fRunLimits;
+    le_int32 *fStyleIndices;
+};
+
+StyleRuns::StyleRuns(const RunArray *styleRunArrays[], le_int32 styleCount)
+    : fStyleCount(styleCount), fRunCount(0), fRunLimits(NULL), fStyleIndices(NULL)
+{
+    le_int32 maxRunCount = 0;
+    le_int32 style, run, runStyle;
+    le_int32 *currentRun = LE_NEW_ARRAY(le_int32, styleCount);
+
+    for (int i = 0; i < styleCount; i += 1) {
+        maxRunCount += styleRunArrays[i]->getCount();
+    }
+
+    maxRunCount -= styleCount - 1;
+
+    fRunLimits    = LE_NEW_ARRAY(le_int32, maxRunCount);
+    fStyleIndices = LE_NEW_ARRAY(le_int32, maxRunCount * styleCount);
+
+    for (style = 0; style < styleCount; style += 1) {
+        currentRun[style] = 0;
+    }
+
+    run = 0;
+    runStyle = 0;
+
+    /*
+     * Since the last run limit for each style run must be
+     * the same, all the styles will hit the last limit at
+     * the same time, so we know when we're done when the first
+     * style hits the last limit.
+     */
+    while (currentRun[0] < styleRunArrays[0]->getCount()) {
+        fRunLimits[run] = 0x7FFFFFFF;
+
+        // find the minimum run limit for all the styles
+        for (style = 0; style < styleCount; style += 1) {
+            if (styleRunArrays[style]->getLimit(currentRun[style]) < fRunLimits[run]) {
+                fRunLimits[run] = styleRunArrays[style]->getLimit(currentRun[style]);
+            }
+        }
+
+        // advance all styles whose current run is at this limit to the next run
+        for (style = 0; style < styleCount; style += 1) {
+            fStyleIndices[runStyle++] = currentRun[style];
+
+            if (styleRunArrays[style]->getLimit(currentRun[style]) == fRunLimits[run]) {
+                currentRun[style] += 1;
+            }
+        }
+
+        run += 1;
+    }
+
+    fRunCount = run;
+    LE_DELETE_ARRAY(currentRun);
+}
+
+StyleRuns::~StyleRuns()
+{
+    fRunCount = 0;
+
+    LE_DELETE_ARRAY(fStyleIndices);
+    fStyleIndices = NULL;
+
+    LE_DELETE_ARRAY(fRunLimits);
+    fRunLimits = NULL;
+}
+
+le_int32 StyleRuns::getRuns(le_int32 runLimits[], le_int32 styleIndices[])
+{
+    if (runLimits != NULL) {
+        LE_ARRAY_COPY(runLimits, fRunLimits, fRunCount);
+    }
+
+    if (styleIndices != NULL) {
+        LE_ARRAY_COPY(styleIndices, fStyleIndices, fRunCount * fStyleCount);
+    }
+
+    return fRunCount;
+}
+
+/*
+ * NOTE: This table only has "TRUE" values for
+ * those scripts which the LayoutEngine can currently
+ * process, rather for all scripts which require
+ * complex processing for correct rendering.
+ */
+static const le_bool complexTable[scriptCodeCount] = {
+    FALSE , /* Zyyy */
+    FALSE,  /* Qaai */
+    TRUE,   /* Arab */
+    FALSE,  /* Armn */
+    TRUE,   /* Beng */
+    FALSE,  /* Bopo */
+    FALSE,  /* Cher */
+    FALSE,  /* Copt=Qaac */
+    FALSE,  /* Cyrl */
+    FALSE,  /* Dsrt */
+    TRUE,   /* Deva */
+    FALSE,  /* Ethi */
+    FALSE,  /* Geor */
+    FALSE,  /* Goth */
+    FALSE,  /* Grek */
+    TRUE,   /* Gujr */
+    TRUE,   /* Guru */
+    FALSE,  /* Hani */
+    FALSE,  /* Hang */
+    TRUE,   /* Hebr */
+    FALSE,  /* Hira */
+    TRUE,   /* Knda */
+    FALSE,  /* Kana */
+    FALSE,  /* Khmr */
+    FALSE,  /* Laoo */
+    FALSE,  /* Latn */
+    TRUE,   /* Mlym */
+    FALSE,  /* Mong */
+    FALSE,  /* Mymr */
+    FALSE,  /* Ogam */
+    FALSE,  /* Ital */
+    TRUE,   /* Orya */
+    FALSE,  /* Runr */
+    FALSE,  /* Sinh */
+    FALSE,  /* Syrc */
+    TRUE,   /* Taml */
+    TRUE,   /* Telu */
+    FALSE,  /* Thaa */
+    TRUE,   /* Thai */
+    FALSE,  /* Tibt */
+    FALSE,  /* Cans */
+    FALSE,  /* Yiii */
+    FALSE,  /* Tglg */
+    FALSE,  /* Hano */
+    FALSE,  /* Buhd */
+    FALSE,  /* Tagb */
+    FALSE,  /* Brai */
+    FALSE,  /* Cprt */
+    FALSE,  /* Limb */
+    FALSE,  /* Linb */
+    FALSE,  /* Osma */
+    FALSE,  /* Shaw */
+    FALSE,  /* Tale */
+    FALSE,  /* Ugar */
+    FALSE,  /* Hrkt */
+    FALSE,  /* Bugi */
+    FALSE,  /* Glag */
+    FALSE,  /* Khar */
+    FALSE,  /* Sylo */
+    FALSE,  /* Talu */
+    FALSE,  /* Tfng */
+    FALSE,  /* Xpeo */
+    FALSE,  /* Bali */
+    FALSE,  /* Batk */
+    FALSE,  /* Blis */
+    FALSE,  /* Brah */
+    FALSE,  /* Cham */
+    FALSE,  /* Cirt */
+    FALSE,  /* Cyrs */
+    FALSE,  /* Egyd */
+    FALSE,  /* Egyh */
+    FALSE,  /* Egyp */
+    FALSE,  /* Geok */
+    FALSE,  /* Hans */
+    FALSE,  /* Hant */
+    FALSE,  /* Hmng */
+    FALSE,  /* Hung */
+    FALSE,  /* Inds */
+    FALSE,  /* Java */
+    FALSE,  /* Kali */
+    FALSE,  /* Latf */
+    FALSE,  /* Latg */
+    FALSE,  /* Lepc */
+    FALSE,  /* Lina */
+    FALSE,  /* Mand */
+    FALSE,  /* Maya */
+    FALSE,  /* Mero */
+    FALSE,  /* Nkoo */
+    FALSE,  /* Orkh */
+    FALSE,  /* Perm */
+    FALSE,  /* Phag */
+    FALSE,  /* Phnx */
+    FALSE,  /* Plrd */
+    FALSE,  /* Roro */
+    FALSE,  /* Sara */
+    FALSE,  /* Syre */
+    FALSE,  /* Syrj */
+    FALSE,  /* Syrn */
+    FALSE,  /* Teng */
+    FALSE,  /* Taii */
+    FALSE,  /* Visp */
+    FALSE,  /* Xsux */
+    FALSE,  /* Zxxx */
+    FALSE,  /* Zzzz */
+    FALSE,  /* Cari */
+    FALSE,  /* Jpan */
+    FALSE,  /* Lana */
+    FALSE,  /* Lyci */
+    FALSE,  /* Lydi */
+    FALSE,  /* Olck */
+    FALSE,  /* Rjng */
+    FALSE,  /* Saur */
+    FALSE,  /* Sgnw */
+    FALSE,  /* Sund */
+    FALSE,  /* Moon */
+    FALSE,  /* Mtei */
+    FALSE,  /* Armi */
+    FALSE,  /* Avst */
+    FALSE,  /* Cakm */
+    FALSE,  /* Kore */
+    FALSE,  /* Kthi */
+    FALSE,  /* Mani */
+    FALSE,  /* Phli */
+    FALSE,  /* Phlp */
+    FALSE,  /* Phlv */
+    FALSE,  /* Prti */
+    FALSE,  /* Samr */
+    FALSE,  /* Tavt */
+    FALSE,  /* Zmth */
+    FALSE,  /* Zsym */
+    FALSE,  /* Bamu */
+    FALSE,  /* Lisu */
+    FALSE,  /* Nkgb */
+    FALSE   /* Sarb */
+};
+
+
+const char ParagraphLayout::fgClassID = 0;
+
+static void fillMissingCharToGlyphMapValues(le_int32 *charToGlyphMap,
+                                            le_int32 charCount) {
+    le_int32 lastValidGlyph = -1;
+    le_int32 ch;
+    for (ch = 0; ch <= charCount; ch += 1) {
+        if (charToGlyphMap[ch] == -1) {
+            charToGlyphMap[ch] = lastValidGlyph;
+        } else {
+            lastValidGlyph = charToGlyphMap[ch];
+        }
+    }
+}
+
+/*
+ * How to deal with composite fonts:
+ *
+ * Don't store the client's FontRuns; we'll need to compute sub-font FontRuns using Doug's
+ * LEFontInstance method. Do that by intersecting the client's FontRuns with fScriptRuns. Use
+ * that to compute fFontRuns, and then intersect fFontRuns, fScriptRuns and fLevelRuns. Doing
+ * it in this order means we do a two-way intersection and a three-way intersection.
+ *
+ * An optimization would be to only do this if there's at least one composite font...
+ *
+ * Other notes:
+ *
+ * * Return the sub-fonts as the run fonts... could keep the mapping back to the client's FontRuns
+ *   but that probably makes it more complicated of everyone...
+ *
+ * * Take the LineInfo and LineRun types from Paragraph and use them here, incorporate them into the API.
+ *
+ * * Might want to change the name of the StyleRun type, and make a new one that holds fonts, scripts and levels?
+ *
+ */
+ParagraphLayout::ParagraphLayout(const LEUnicode chars[], le_int32 count,
+                                 const FontRuns   *fontRuns,
+                                 const ValueRuns  *levelRuns,
+                                 const ValueRuns  *scriptRuns,
+                                 const LocaleRuns *localeRuns,
+                                 UBiDiLevel paragraphLevel, le_bool vertical,
+                                 LEErrorCode &status)
+                                 : fChars(chars), fCharCount(count),
+                                   fFontRuns(NULL), fLevelRuns(levelRuns), fScriptRuns(scriptRuns), fLocaleRuns(localeRuns),
+                                   fVertical(vertical), fClientLevels(TRUE), fClientScripts(TRUE), fClientLocales(TRUE), fEmbeddingLevels(NULL),
+                                   fAscent(0), fDescent(0), fLeading(0),
+                                   fGlyphToCharMap(NULL), fCharToMinGlyphMap(NULL), fCharToMaxGlyphMap(NULL), fGlyphWidths(NULL), fGlyphCount(0),
+                                   fParaBidi(NULL), fLineBidi(NULL),
+                                   fStyleRunLimits(NULL), fStyleIndices(NULL), fStyleRunCount(0),
+                                   fBreakIterator(NULL), fLineStart(-1), fLineEnd(0),
+                                 /*fVisualRuns(NULL), fStyleRunInfo(NULL), fVisualRunCount(-1),
+                                   fFirstVisualRun(-1), fLastVisualRun(-1),*/ fVisualRunLastX(0), fVisualRunLastY(0)
+{
+
+    if (LE_FAILURE(status)) {
+        fCharCount = -1;
+        return;
+    }
+
+    // FIXME: should check the limit arrays for consistency...
+
+    computeLevels(paragraphLevel);
+
+    if (scriptRuns == NULL) {
+        computeScripts();
+    }
+
+    if (localeRuns == NULL) {
+        computeLocales();
+    }
+
+    computeSubFonts(fontRuns, status);
+
+    if (LE_FAILURE(status)) {
+        //other stuff?
+        fCharCount = -1;
+        return;
+    }
+
+    // now intersect the font, direction and script runs...
+    const RunArray *styleRunArrays[] = {fFontRuns, fLevelRuns, fScriptRuns, fLocaleRuns};
+    le_int32  styleCount = sizeof styleRunArrays / sizeof styleRunArrays[0];
+    StyleRuns styleRuns(styleRunArrays, styleCount);
+    LEErrorCode layoutStatus = LE_NO_ERROR;
+    
+    fStyleRunCount = styleRuns.getRuns(NULL, NULL);
+
+    fStyleRunLimits = LE_NEW_ARRAY(le_int32, fStyleRunCount);
+    fStyleIndices   = LE_NEW_ARRAY(le_int32, fStyleRunCount * styleCount);
+    if ((fStyleRunLimits == NULL) || (fStyleIndices == NULL)) {
+        status = LE_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+
+    styleRuns.getRuns(fStyleRunLimits, fStyleIndices);
+
+    // now build a LayoutEngine for each style run...
+    le_int32 *styleIndices = fStyleIndices;
+    le_int32 run, runStart;
+
+    fStyleRunInfo = LE_NEW_ARRAY(StyleRunInfo, fStyleRunCount);
+    if (fStyleRunInfo == NULL) {
+        status = LE_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    else {
+        // initialize
+        for (runStart = 0, run = 0; run < fStyleRunCount; run += 1) {
+            fStyleRunInfo[run].font = NULL;
+            fStyleRunInfo[run].runBase = 0;
+            fStyleRunInfo[run].runLimit = 0;
+            fStyleRunInfo[run].script = (UScriptCode)0;
+            fStyleRunInfo[run].locale = NULL;
+            fStyleRunInfo[run].level = 0;
+            fStyleRunInfo[run].glyphBase = 0;
+            fStyleRunInfo[run].engine = NULL;
+            fStyleRunInfo[run].glyphCount = 0;
+            fStyleRunInfo[run].glyphs = NULL;
+            fStyleRunInfo[run].positions = NULL;
+        }
+    }
+
+    fGlyphCount = 0;
+    for (runStart = 0, run = 0; run < fStyleRunCount; run += 1) {
+        fStyleRunInfo[run].font      = fFontRuns->getFont(styleIndices[0]);
+        fStyleRunInfo[run].runBase   = runStart;
+        fStyleRunInfo[run].runLimit  = fStyleRunLimits[run];
+        fStyleRunInfo[run].script    = (UScriptCode) fScriptRuns->getValue(styleIndices[2]);
+        fStyleRunInfo[run].locale    = fLocaleRuns->getLocale(styleIndices[3]);
+        fStyleRunInfo[run].level     = (UBiDiLevel) fLevelRuns->getValue(styleIndices[1]);
+        fStyleRunInfo[run].glyphBase = fGlyphCount;
+
+        fStyleRunInfo[run].engine = LayoutEngine::layoutEngineFactory(fStyleRunInfo[run].font,
+            fStyleRunInfo[run].script, getLanguageCode(fStyleRunInfo[run].locale), layoutStatus);
+        if (LE_FAILURE(layoutStatus)) {
+            status = layoutStatus;
+            return;
+        }
+
+        fStyleRunInfo[run].glyphCount = fStyleRunInfo[run].engine->layoutChars(fChars, runStart, fStyleRunLimits[run] - runStart, fCharCount,
+            fStyleRunInfo[run].level & 1, 0, 0, layoutStatus);
+        if (LE_FAILURE(layoutStatus)) {
+            status = layoutStatus;
+            return;
+        }
+
+        runStart = fStyleRunLimits[run];
+        styleIndices += styleCount;
+        fGlyphCount += fStyleRunInfo[run].glyphCount;
+    }
+
+    // Make big arrays for the glyph widths, glyph-to-char and char-to-glyph maps,
+    // in logical order. (Both maps need an extra entry for the end of the text.) 
+    //
+    // For each layout get the positions and convert them into glyph widths, in
+    // logical order. Get the glyph-to-char mapping, offset by starting index in the
+    // character array. Swap the glyph width and glyph-to-char arrays into logical order.
+    // Finally, fill in the char-to-glyph mappings.
+    fGlyphWidths       = LE_NEW_ARRAY(float, fGlyphCount);
+    fGlyphToCharMap    = LE_NEW_ARRAY(le_int32, fGlyphCount + 1);
+    fCharToMinGlyphMap = LE_NEW_ARRAY(le_int32, fCharCount + 1);
+    fCharToMaxGlyphMap = LE_NEW_ARRAY(le_int32, fCharCount + 1);
+    if ((fGlyphWidths == NULL) || (fGlyphToCharMap == NULL) || 
+        (fCharToMinGlyphMap == NULL) || (fCharToMaxGlyphMap == NULL)) {
+        status = LE_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+
+    le_int32 glyph;
+
+    for (runStart = 0, run = 0; run < fStyleRunCount; run += 1) {
+        LayoutEngine *engine = fStyleRunInfo[run].engine;
+        le_int32 glyphCount  = fStyleRunInfo[run].glyphCount;
+        le_int32 glyphBase   = fStyleRunInfo[run].glyphBase;
+
+        fStyleRunInfo[run].glyphs = LE_NEW_ARRAY(LEGlyphID, glyphCount);
+        fStyleRunInfo[run].positions = LE_NEW_ARRAY(float, glyphCount * 2 + 2);
+        if ((fStyleRunInfo[run].glyphs == NULL) || 
+            (fStyleRunInfo[run].positions == NULL)) {
+            status = LE_MEMORY_ALLOCATION_ERROR;
+            return;
+        }
+
+        engine->getGlyphs(fStyleRunInfo[run].glyphs, layoutStatus);
+        if (LE_FAILURE(layoutStatus)) {
+            status = layoutStatus;
+            return;
+        }
+
+        engine->getGlyphPositions(fStyleRunInfo[run].positions, layoutStatus);
+        if (LE_FAILURE(layoutStatus)) {
+            status = layoutStatus;
+            return;
+        }
+
+        engine->getCharIndices(&fGlyphToCharMap[glyphBase], runStart, layoutStatus);
+        if (LE_FAILURE(layoutStatus)) {
+            status = layoutStatus;
+            return;
+        }
+
+        for (glyph = 0; glyph < glyphCount; glyph += 1) {
+            fGlyphWidths[glyphBase + glyph] = fStyleRunInfo[run].positions[glyph * 2 + 2] - fStyleRunInfo[run].positions[glyph * 2];
+        }
+
+        if ((fStyleRunInfo[run].level & 1) != 0) {
+            LXUtilities::reverse(&fGlyphWidths[glyphBase], glyphCount);
+            LXUtilities::reverse(&fGlyphToCharMap[glyphBase], glyphCount);
+        }
+
+        runStart = fStyleRunLimits[run];
+
+        delete engine;
+        fStyleRunInfo[run].engine = NULL;
+    }
+
+    fGlyphToCharMap[fGlyphCount] = fCharCount;
+
+    // Initialize the char-to-glyph maps to -1 so that we can later figure out
+    // whether any of the entries in the map aren't filled in below.
+    le_int32 chIndex;
+    for (chIndex = 0; chIndex <= fCharCount; chIndex += 1) {
+        fCharToMinGlyphMap[chIndex] = -1;
+        fCharToMaxGlyphMap[chIndex] = -1;
+    }
+
+    for (glyph = fGlyphCount - 1; glyph >= 0; glyph -= 1) {
+        le_int32 ch = fGlyphToCharMap[glyph];
+
+        fCharToMinGlyphMap[ch] = glyph;
+    }
+
+    fCharToMinGlyphMap[fCharCount] = fGlyphCount;
+
+    for (glyph = 0; glyph < fGlyphCount; glyph += 1) {
+        le_int32 ch = fGlyphToCharMap[glyph];
+
+        fCharToMaxGlyphMap[ch] = glyph;
+    }
+
+    fCharToMaxGlyphMap[fCharCount] = fGlyphCount;
+
+    // Now fill in the missing values in the char-to-glyph maps.
+    fillMissingCharToGlyphMapValues(fCharToMinGlyphMap, fCharCount);
+    fillMissingCharToGlyphMapValues(fCharToMaxGlyphMap, fCharCount);
+}
+
+ParagraphLayout::~ParagraphLayout()
+{
+    delete (FontRuns *) fFontRuns;
+
+    if (! fClientLevels) {
+        delete (ValueRuns *) fLevelRuns;
+        fLevelRuns = NULL;
+
+        fClientLevels = TRUE;
+    }
+
+    if (! fClientScripts) {
+        delete (ValueRuns *) fScriptRuns;
+        fScriptRuns = NULL;
+
+        fClientScripts = TRUE;
+    }
+
+    if (! fClientLocales) {
+        delete (LocaleRuns *) fLocaleRuns;
+        fLocaleRuns = NULL;
+
+        fClientLocales = TRUE;
+    }
+
+    if (fEmbeddingLevels != NULL) {
+        LE_DELETE_ARRAY(fEmbeddingLevels);
+        fEmbeddingLevels = NULL;
+    }
+
+    if (fGlyphToCharMap != NULL) {
+        LE_DELETE_ARRAY(fGlyphToCharMap);
+        fGlyphToCharMap = NULL;
+    }
+
+    if (fCharToMinGlyphMap != NULL) {
+        LE_DELETE_ARRAY(fCharToMinGlyphMap);
+        fCharToMinGlyphMap = NULL;
+    }
+
+    if (fCharToMaxGlyphMap != NULL) {
+        LE_DELETE_ARRAY(fCharToMaxGlyphMap);
+        fCharToMaxGlyphMap = NULL;
+    }
+
+    if (fGlyphWidths != NULL) {
+        LE_DELETE_ARRAY(fGlyphWidths);
+        fGlyphWidths = NULL;
+    }
+
+    if (fParaBidi != NULL) {
+        ubidi_close(fParaBidi);
+        fParaBidi = NULL;
+    }
+
+    if (fLineBidi != NULL) {
+        ubidi_close(fLineBidi);
+        fLineBidi = NULL;
+    }
+
+    if (fStyleRunCount > 0) {
+        le_int32 run;
+
+        LE_DELETE_ARRAY(fStyleRunLimits);
+        LE_DELETE_ARRAY(fStyleIndices);
+
+        for (run = 0; run < fStyleRunCount; run += 1) {
+            LE_DELETE_ARRAY(fStyleRunInfo[run].glyphs);
+            LE_DELETE_ARRAY(fStyleRunInfo[run].positions);
+
+            fStyleRunInfo[run].glyphs    = NULL;
+            fStyleRunInfo[run].positions = NULL;
+        }
+
+        LE_DELETE_ARRAY(fStyleRunInfo);
+
+        fStyleRunLimits = NULL;
+        fStyleIndices   = NULL;
+        fStyleRunInfo        = NULL;
+        fStyleRunCount  = 0;
+    }
+
+    if (fBreakIterator != NULL) {
+        delete fBreakIterator;
+        fBreakIterator = NULL;
+    }
+}
+
+    
+le_bool ParagraphLayout::isComplex(const LEUnicode chars[], le_int32 count)
+{
+    UErrorCode scriptStatus = U_ZERO_ERROR;
+    UScriptCode scriptCode  = USCRIPT_INVALID_CODE;
+    UScriptRun *sr = uscript_openRun(chars, count, &scriptStatus);
+    le_bool result = FALSE;
+
+    while (uscript_nextRun(sr, NULL, NULL, &scriptCode)) {
+        if (isComplex(scriptCode)) {
+            result = TRUE;
+            break;
+        }
+    }
+
+    uscript_closeRun(sr);
+    return result;
+}
+
+le_int32 ParagraphLayout::getAscent() const
+{
+    if (fAscent <= 0 && fCharCount > 0) {
+        ((ParagraphLayout *) this)->computeMetrics();
+    }
+
+    return fAscent;
+}
+
+le_int32 ParagraphLayout::getDescent() const
+{
+    if (fAscent <= 0 && fCharCount > 0) {
+        ((ParagraphLayout *) this)->computeMetrics();
+    }
+
+    return fDescent;
+}
+
+le_int32 ParagraphLayout::getLeading() const
+{
+    if (fAscent <= 0 && fCharCount > 0) {
+        ((ParagraphLayout *) this)->computeMetrics();
+    }
+
+    return fLeading;
+}
+
+le_bool ParagraphLayout::isDone() const
+{
+    return fLineEnd >= fCharCount;
+}
+
+ParagraphLayout::Line *ParagraphLayout::nextLine(float width)
+{
+    if (isDone()) {
+        return NULL;
+    }
+
+    fLineStart = fLineEnd;
+
+    if (width > 0) {
+        le_int32 glyph    = fCharToMinGlyphMap[fLineStart];
+        float widthSoFar  = 0;
+
+        while (glyph < fGlyphCount && widthSoFar + fGlyphWidths[glyph] <= width) {
+            widthSoFar += fGlyphWidths[glyph++];
+        }
+
+        // If no glyphs fit on the line, force one to fit.
+        //
+        // (There shouldn't be any zero width glyphs at the
+        // start of a line unless the paragraph consists of
+        // only zero width glyphs, because otherwise the zero
+        // width glyphs will have been included on the end of
+        // the previous line...)
+        if (widthSoFar == 0 && glyph < fGlyphCount) {
+            glyph += 1;
+        }
+
+        fLineEnd = previousBreak(fGlyphToCharMap[glyph]);
+
+        // If this break is at or before the last one,
+        // find a glyph, starting at the one which didn't
+        // fit, that produces a break after the last one.
+        while (fLineEnd <= fLineStart) {
+            fLineEnd = fGlyphToCharMap[glyph++];
+        }
+    } else {
+        fLineEnd = fCharCount;
+    }
+
+    return computeVisualRuns();
+}
+
+void ParagraphLayout::computeLevels(UBiDiLevel paragraphLevel)
+{
+    UErrorCode bidiStatus = U_ZERO_ERROR;
+
+    if (fLevelRuns != NULL) {
+        le_int32 ch;
+        le_int32 run;
+
+        fEmbeddingLevels = LE_NEW_ARRAY(UBiDiLevel, fCharCount);
+
+        for (ch = 0, run = 0; run < fLevelRuns->getCount(); run += 1) {
+            UBiDiLevel runLevel = (UBiDiLevel) fLevelRuns->getValue(run) | UBIDI_LEVEL_OVERRIDE;
+            le_int32   runLimit = fLevelRuns->getLimit(run);
+
+            while (ch < runLimit) {
+                fEmbeddingLevels[ch++] = runLevel;
+            }
+        }
+    }
+
+    fParaBidi = ubidi_openSized(fCharCount, 0, &bidiStatus);
+    ubidi_setPara(fParaBidi, fChars, fCharCount, paragraphLevel, fEmbeddingLevels, &bidiStatus);
+
+    if (fLevelRuns == NULL) {
+        le_int32 levelRunCount = ubidi_countRuns(fParaBidi, &bidiStatus);
+        ValueRuns *levelRuns = new ValueRuns(levelRunCount);
+
+        le_int32 logicalStart = 0;
+        le_int32 run;
+        le_int32 limit;
+        UBiDiLevel level;
+
+        for (run = 0; run < levelRunCount; run += 1) {
+            ubidi_getLogicalRun(fParaBidi, logicalStart, &limit, &level);
+            levelRuns->add(level, limit);
+            logicalStart = limit;
+        }
+
+        fLevelRuns    = levelRuns;
+        fClientLevels = FALSE;
+    }
+}
+
+void ParagraphLayout::computeScripts()
+{
+    UErrorCode scriptStatus = U_ZERO_ERROR;
+    UScriptRun *sr = uscript_openRun(fChars, fCharCount, &scriptStatus);
+    ValueRuns  *scriptRuns = new ValueRuns(0);
+    le_int32 limit;
+    UScriptCode script;
+
+    while (uscript_nextRun(sr, NULL, &limit, &script)) {
+        scriptRuns->add(script, limit);
+    }
+
+    uscript_closeRun(sr);
+
+    fScriptRuns    = scriptRuns;
+    fClientScripts = FALSE;
+}
+
+void ParagraphLayout::computeLocales()
+{
+    LocaleRuns *localeRuns = new LocaleRuns(0);
+    const Locale *defaultLocale = &Locale::getDefault();
+
+    localeRuns->add(defaultLocale, fCharCount);
+
+    fLocaleRuns    = localeRuns;
+    fClientLocales = FALSE;
+}
+
+void ParagraphLayout::computeSubFonts(const FontRuns *fontRuns, LEErrorCode &status)
+{
+    if (LE_FAILURE(status)) {
+        return;
+    }
+
+    const RunArray *styleRunArrays[] = {fontRuns, fScriptRuns};
+    le_int32 styleCount = sizeof styleRunArrays / sizeof styleRunArrays[0];
+    StyleRuns styleRuns(styleRunArrays, styleCount);
+    le_int32 styleRunCount = styleRuns.getRuns(NULL, NULL);
+    le_int32 *styleRunLimits = LE_NEW_ARRAY(le_int32, styleRunCount);
+    le_int32 *styleIndices = LE_NEW_ARRAY(le_int32, styleRunCount * styleCount);
+    FontRuns *subFontRuns  = new FontRuns(0);
+    le_int32  run, offset, *si;
+
+    styleRuns.getRuns(styleRunLimits, styleIndices);
+
+    si = styleIndices;
+    offset = 0;
+
+    for (run = 0; run < styleRunCount; run += 1) {
+        const LEFontInstance *runFont = fontRuns->getFont(si[0]);
+        le_int32 script = fScriptRuns->getValue(si[1]);
+
+        while (offset < styleRunLimits[run]) {
+            const LEFontInstance *subFont = runFont->getSubFont(fChars, &offset, styleRunLimits[run], script, status);
+
+            if (LE_FAILURE(status)) {
+                delete subFontRuns;
+                goto cleanUp;
+            }
+
+            subFontRuns->add(subFont, offset);
+        }
+
+        si += styleCount;
+    }
+
+    fFontRuns = subFontRuns;
+
+cleanUp:
+    LE_DELETE_ARRAY(styleIndices);
+    LE_DELETE_ARRAY(styleRunLimits);
+}
+
+void ParagraphLayout::computeMetrics()
+{
+    le_int32 i, count = fFontRuns->getCount();
+    le_int32 maxDL = 0;
+
+    for (i = 0; i < count; i += 1) {
+        const LEFontInstance *font = fFontRuns->getFont(i);
+        le_int32 ascent  = font->getAscent();
+        le_int32 descent = font->getDescent();
+        le_int32 leading = font->getLeading();
+        le_int32 dl      = descent + leading;
+
+        if (ascent > fAscent) {
+            fAscent = ascent;
+        }
+
+        if (descent > fDescent) {
+            fDescent = descent;
+        }
+
+        if (leading > fLeading) {
+            fLeading = leading;
+        }
+
+        if (dl > maxDL) {
+            maxDL = dl;
+        }
+    }
+
+    fLeading = maxDL - fDescent;
+}
+
+#if 1
+struct LanguageMap
+{
+    const char *localeCode;
+    le_int32 languageCode;
+};
+
+static const LanguageMap languageMap[] =
+{
+    {"afr", afkLanguageCode}, // Afrikaans
+    {"ara", araLanguageCode}, // Arabic
+    {"asm", asmLanguageCode}, // Assamese
+    {"bel", belLanguageCode}, // Belarussian
+    {"ben", benLanguageCode}, // Bengali
+    {"bod", tibLanguageCode}, // Tibetan
+    {"bul", bgrLanguageCode}, // Bulgarian
+    {"cat", catLanguageCode}, // Catalan
+    {"ces", csyLanguageCode}, // Czech
+    {"che", cheLanguageCode}, // Chechen
+    {"cop", copLanguageCode}, // Coptic
+    {"cym", welLanguageCode}, // Welsh
+    {"dan", danLanguageCode}, // Danish
+    {"deu", deuLanguageCode}, // German
+    {"dzo", dznLanguageCode}, // Dzongkha
+    {"ell", ellLanguageCode}, // Greek
+    {"eng", engLanguageCode}, // English
+    {"est", etiLanguageCode}, // Estonian
+    {"eus", euqLanguageCode}, // Basque
+    {"fas", farLanguageCode}, // Farsi
+    {"fin", finLanguageCode}, // Finnish
+    {"fra", fraLanguageCode}, // French
+    {"gle", gaeLanguageCode}, // Irish Gaelic
+    {"guj", gujLanguageCode}, // Gujarati
+    {"hau", hauLanguageCode}, // Hausa
+    {"heb", iwrLanguageCode}, // Hebrew
+    {"hin", hinLanguageCode}, // Hindi
+    {"hrv", hrvLanguageCode}, // Croatian
+    {"hun", hunLanguageCode}, // Hungarian
+    {"hye", hyeLanguageCode}, // Armenian
+    {"ind", indLanguageCode}, // Indonesian
+    {"ita", itaLanguageCode}, // Italian
+    {"jpn", janLanguageCode}, // Japanese
+    {"kan", kanLanguageCode}, // Kannada
+    {"kas", kshLanguageCode}, // Kashmiri
+    {"khm", khmLanguageCode}, // Khmer
+    {"kok", kokLanguageCode}, // Konkani
+    {"kor", korLanguageCode}, // Korean
+//  {"mal_XXX", malLanguageCode}, // Malayalam - Traditional
+    {"mal", mlrLanguageCode}, // Malayalam - Reformed
+    {"mar", marLanguageCode}, // Marathi
+    {"mlt", mtsLanguageCode}, // Maltese
+    {"mni", mniLanguageCode}, // Manipuri
+    {"mon", mngLanguageCode}, // Mongolian
+    {"nep", nepLanguageCode}, // Nepali
+    {"ori", oriLanguageCode}, // Oriya
+    {"pol", plkLanguageCode}, // Polish
+    {"por", ptgLanguageCode}, // Portuguese
+    {"pus", pasLanguageCode}, // Pashto
+    {"ron", romLanguageCode}, // Romanian
+    {"rus", rusLanguageCode}, // Russian
+    {"san", sanLanguageCode}, // Sanskrit
+    {"sin", snhLanguageCode}, // Sinhalese
+    {"slk", skyLanguageCode}, // Slovak
+    {"snd", sndLanguageCode}, // Sindhi
+    {"slv", slvLanguageCode}, // Slovenian
+    {"spa", espLanguageCode}, // Spanish
+    {"sqi", sqiLanguageCode}, // Albanian
+    {"srp", srbLanguageCode}, // Serbian
+    {"swe", sveLanguageCode}, // Swedish
+    {"syr", syrLanguageCode}, // Syriac
+    {"tam", tamLanguageCode}, // Tamil
+    {"tel", telLanguageCode}, // Telugu
+    {"tha", thaLanguageCode}, // Thai
+    {"tur", trkLanguageCode}, // Turkish
+    {"urd", urdLanguageCode}, // Urdu
+    {"yid", jiiLanguageCode}, // Yiddish
+//  {"zhp", zhpLanguageCode}, // Chinese - Phonetic
+    {"zho", zhsLanguageCode}, // Chinese
+    {"zho_CHN", zhsLanguageCode}, // Chinese - China
+    {"zho_HKG", zhsLanguageCode}, // Chinese - Hong Kong
+    {"zho_MAC", zhtLanguageCode}, // Chinese - Macao
+    {"zho_SGP", zhsLanguageCode}, // Chinese - Singapore
+    {"zho_TWN", zhtLanguageCode}  // Chinese - Taiwan
+};
+
+static const le_int32 languageMapCount = ARRAY_SIZE(languageMap);
+
+le_int32 ParagraphLayout::getLanguageCode(const Locale *locale)
+{
+    char code[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+    const char *language = locale->getISO3Language();
+    const char *country  = locale->getISO3Country();
+
+    uprv_strcat(code, language);
+
+    if ((uprv_strcmp(language, "zho") == 0) && country != NULL) {
+        uprv_strcat(code, "_");
+        uprv_strcat(code, country);
+    }
+
+    for (le_int32 i = 0; i < languageMapCount; i += 1) {
+        if (uprv_strcmp(code, languageMap[i].localeCode) == 0) {
+            return languageMap[i].languageCode;
+        }
+    }
+
+    return nullLanguageCode;
+}
+#else
+
+// TODO - dummy implementation for right now...
+le_int32 ParagraphLayout::getLanguageCode(const Locale *locale)
+{
+    return nullLanguageCode;
+}
+#endif
+
+le_bool ParagraphLayout::isComplex(UScriptCode script)
+{
+    if (script < 0 || script >= (UScriptCode) scriptCodeCount) {
+        return FALSE;
+    }
+
+    return complexTable[script];
+}
+
+le_int32 ParagraphLayout::previousBreak(le_int32 charIndex)
+{
+    // skip over any whitespace or control characters,
+    // because they can hang in the margin.
+    while (charIndex < fCharCount &&
+           (u_isWhitespace(fChars[charIndex]) ||
+            u_iscntrl(fChars[charIndex]))) {
+        charIndex += 1;
+    }
+
+    // Create the BreakIterator if we don't already have one
+    if (fBreakIterator == NULL) {
+        Locale thai("th");
+        UCharCharacterIterator *iter = new UCharCharacterIterator(fChars, fCharCount);
+        UErrorCode status = U_ZERO_ERROR;
+
+        fBreakIterator = BreakIterator::createLineInstance(thai, status);
+        fBreakIterator->adoptText(iter);
+    }
+
+    // return the break location that's at or before
+    // the character we stopped on. Note: if we're
+    // on a break, the "+ 1" will cause preceding to
+    // back up to it.
+    return fBreakIterator->preceding(charIndex + 1);
+}
+
+ParagraphLayout::Line *ParagraphLayout::computeVisualRuns()
+{
+    UErrorCode bidiStatus = U_ZERO_ERROR;
+    le_int32 dirRunCount, visualRun;
+
+    fVisualRunLastX = 0;
+    fVisualRunLastY = 0;
+    fFirstVisualRun = getCharRun(fLineStart);
+    fLastVisualRun  = getCharRun(fLineEnd - 1);
+
+    if (fLineBidi == NULL) {
+        fLineBidi = ubidi_openSized(fCharCount, 0, &bidiStatus);
+    }
+
+    ubidi_setLine(fParaBidi, fLineStart, fLineEnd, fLineBidi, &bidiStatus);
+    dirRunCount = ubidi_countRuns(fLineBidi, &bidiStatus);
+
+    Line *line = new Line();
+
+    for (visualRun = 0; visualRun < dirRunCount; visualRun += 1) {
+        le_int32 relStart, run, runLength;
+        UBiDiDirection runDirection = ubidi_getVisualRun(fLineBidi, visualRun, &relStart, &runLength);
+        le_int32 runStart = fLineStart + relStart;
+        le_int32 runEnd   = runStart + runLength - 1;
+        le_int32 firstRun = getCharRun(runStart);
+        le_int32 lastRun  = getCharRun(runEnd);
+        le_int32 startRun = (runDirection == UBIDI_LTR)? firstRun : lastRun;
+        le_int32 stopRun  = (runDirection == UBIDI_LTR)? lastRun + 1 : firstRun - 1;
+        le_int32 dir      = (runDirection == UBIDI_LTR)?  1 : -1;
+
+        for (run = startRun; run != stopRun; run += dir) {
+            le_int32 firstChar = (run == firstRun)? runStart : fStyleRunInfo[run].runBase;
+            le_int32 lastChar  = (run == lastRun)?  runEnd   : fStyleRunInfo[run].runLimit - 1;
+
+            appendRun(line, run, firstChar, lastChar);
+        }
+    }
+
+    return line;
+}
+
+void ParagraphLayout::appendRun(ParagraphLayout::Line *line, le_int32 run, le_int32 firstChar, le_int32 lastChar)
+{
+    le_int32 glyphBase = fStyleRunInfo[run].glyphBase;
+    le_int32 inGlyph, outGlyph;
+
+    // Get the glyph indices for all the characters between firstChar and lastChar,
+    // make the minimum one be leftGlyph and the maximum one be rightGlyph.
+    // (need to do this to handle local reorderings like Indic left matras)
+    le_int32 leftGlyph  = fGlyphCount;
+    le_int32 rightGlyph = -1;
+    le_int32 ch;
+
+    for (ch = firstChar; ch <= lastChar; ch += 1) {
+        le_int32 minGlyph = fCharToMinGlyphMap[ch];
+        le_int32 maxGlyph = fCharToMaxGlyphMap[ch];
+
+        if (minGlyph < leftGlyph) {
+            leftGlyph = minGlyph;
+        }
+
+        if (maxGlyph > rightGlyph) {
+            rightGlyph = maxGlyph;
+        }
+    }
+
+    if ((fStyleRunInfo[run].level & 1) != 0) {
+        le_int32 swap = rightGlyph;
+        le_int32 last = glyphBase + fStyleRunInfo[run].glyphCount - 1;
+
+        // Here, we want to remove the glyphBase bias...
+        rightGlyph = last - leftGlyph;
+        leftGlyph  = last - swap;
+    } else {
+        rightGlyph -= glyphBase;
+        leftGlyph  -= glyphBase;
+    }
+
+    // Set the position bias for the glyphs. If we're at the start of
+    // a line, we want the first glyph to be at x = 0, even if it comes
+    // from the middle of a layout. If we've got a right-to-left run, we
+    // want the left-most glyph to start at the final x position of the
+    // previous run, even though this glyph may be in the middle of the
+    // run.
+    fVisualRunLastX -= fStyleRunInfo[run].positions[leftGlyph * 2];
+ 
+    // Make rightGlyph be the glyph just to the right of
+    // the run's glyphs
+    rightGlyph += 1;
+
+    UBiDiDirection direction  = ((fStyleRunInfo[run].level & 1) == 0)? UBIDI_LTR : UBIDI_RTL;
+    le_int32   glyphCount     = rightGlyph - leftGlyph;
+    LEGlyphID *glyphs         = LE_NEW_ARRAY(LEGlyphID, glyphCount);
+    float     *positions      = LE_NEW_ARRAY(float, glyphCount * 2 + 2);
+    le_int32  *glyphToCharMap = LE_NEW_ARRAY(le_int32, glyphCount);
+
+    LE_ARRAY_COPY(glyphs, &fStyleRunInfo[run].glyphs[leftGlyph], glyphCount);
+
+    for (outGlyph = 0, inGlyph = leftGlyph * 2; inGlyph <= rightGlyph * 2; inGlyph += 2, outGlyph += 2) {
+        positions[outGlyph]     = fStyleRunInfo[run].positions[inGlyph] + fVisualRunLastX;
+        positions[outGlyph + 1] = fStyleRunInfo[run].positions[inGlyph + 1] + fVisualRunLastY;
+    }
+
+    // Save the ending position of this run
+    // to use for the start of the next run
+    fVisualRunLastX = positions[outGlyph - 2];
+    fVisualRunLastY = positions[outGlyph - 1];
+
+    if ((fStyleRunInfo[run].level & 1) == 0) {
+        for (outGlyph = 0, inGlyph = leftGlyph; inGlyph < rightGlyph; inGlyph += 1, outGlyph += 1) {
+            glyphToCharMap[outGlyph] = fGlyphToCharMap[glyphBase + inGlyph];
+        }
+    } else {
+        // Because fGlyphToCharMap is stored in logical order to facilitate line breaking,
+        // we need to map the physical glyph indices to logical indices while we copy the
+        // character indices.
+        le_int32 base = glyphBase + fStyleRunInfo[run].glyphCount - 1;
+
+        for (outGlyph = 0, inGlyph = leftGlyph; inGlyph < rightGlyph; inGlyph += 1, outGlyph += 1) {
+            glyphToCharMap[outGlyph] = fGlyphToCharMap[base - inGlyph];
+        }
+    }
+
+    line->append(fStyleRunInfo[run].font, direction, glyphCount, glyphs, positions, glyphToCharMap);
+}
+
+le_int32 ParagraphLayout::getCharRun(le_int32 charIndex)
+{
+    if (charIndex < 0 || charIndex > fCharCount) {
+        return -1;
+    }
+
+    le_int32 run;
+
+    // NOTE: as long as fStyleRunLimits is well-formed
+    // the above range check guarantees that we'll never
+    // fall off the end of the array.
+    run = 0;
+    while (charIndex >= fStyleRunLimits[run]) {
+        run += 1;
+    }
+
+    return run;
+}
+
+
+const char ParagraphLayout::Line::fgClassID = 0;
+
+#define INITIAL_RUN_CAPACITY 4
+#define RUN_CAPACITY_GROW_LIMIT 16
+
+ParagraphLayout::Line::~Line()
+{
+    le_int32 i;
+
+    for (i = 0; i < fRunCount; i += 1) {
+        delete fRuns[i];
+    }
+
+    LE_DELETE_ARRAY(fRuns);
+}
+
+le_int32 ParagraphLayout::Line::getAscent() const
+{
+    if (fAscent <= 0) {
+        ((ParagraphLayout::Line *)this)->computeMetrics();
+    }
+
+    return fAscent;
+}
+
+le_int32 ParagraphLayout::Line::getDescent() const
+{
+    if (fAscent <= 0) {
+        ((ParagraphLayout::Line *)this)->computeMetrics();
+    }
+
+    return fDescent;
+}
+
+le_int32 ParagraphLayout::Line::getLeading() const
+{
+    if (fAscent <= 0) {
+        ((ParagraphLayout::Line *)this)->computeMetrics();
+    }
+
+    return fLeading;
+}
+
+le_int32 ParagraphLayout::Line::getWidth() const
+{
+    const VisualRun *lastRun = getVisualRun(fRunCount - 1);
+
+    if (lastRun == NULL) {
+        return 0;
+    }
+
+    le_int32 glyphCount = lastRun->getGlyphCount();
+    const float *positions = lastRun->getPositions();
+    
+    return (le_int32) positions[glyphCount * 2];
+}
+
+const ParagraphLayout::VisualRun *ParagraphLayout::Line::getVisualRun(le_int32 runIndex) const
+{
+    if (runIndex < 0 || runIndex >= fRunCount) {
+        return NULL;
+    }
+
+    return fRuns[runIndex];
+}
+
+void ParagraphLayout::Line::append(const LEFontInstance *font, UBiDiDirection direction, le_int32 glyphCount,
+                                   const LEGlyphID glyphs[], const float positions[], const le_int32 glyphToCharMap[])
+{
+    if (fRunCount >= fRunCapacity) {
+        if (fRunCapacity == 0) {
+            fRunCapacity = INITIAL_RUN_CAPACITY;
+            fRuns = LE_NEW_ARRAY(ParagraphLayout::VisualRun *, fRunCapacity);
+        } else {
+            fRunCapacity += (fRunCapacity < RUN_CAPACITY_GROW_LIMIT? fRunCapacity : RUN_CAPACITY_GROW_LIMIT);
+            fRuns = (ParagraphLayout::VisualRun **) LE_GROW_ARRAY(fRuns, fRunCapacity);
+        }
+    }
+
+    fRuns[fRunCount++] = new ParagraphLayout::VisualRun(font, direction, glyphCount, glyphs, positions, glyphToCharMap);
+}
+
+void ParagraphLayout::Line::computeMetrics()
+{
+    le_int32 maxDL = 0;
+
+    for (le_int32 i = 0; i < fRunCount; i += 1) {
+        le_int32 ascent  = fRuns[i]->getAscent();
+        le_int32 descent = fRuns[i]->getDescent();
+        le_int32 leading = fRuns[i]->getLeading();
+        le_int32 dl      = descent + leading;
+
+        if (ascent > fAscent) {
+            fAscent = ascent;
+        }
+
+        if (descent > fDescent) {
+            fDescent = descent;
+        }
+
+        if (leading > fLeading) {
+            fLeading = leading;
+        }
+
+        if (dl > maxDL) {
+            maxDL = dl;
+        }
+    }
+
+    fLeading = maxDL - fDescent;
+}
+
+const char ParagraphLayout::VisualRun::fgClassID = 0;
+
+ParagraphLayout::VisualRun::~VisualRun()
+{
+    LE_DELETE_ARRAY(fGlyphToCharMap);
+    LE_DELETE_ARRAY(fPositions);
+    LE_DELETE_ARRAY(fGlyphs);
+}
+
+U_NAMESPACE_END
+
+#endif
+
diff --git a/source/layoutex/RunArrays.cpp b/source/layoutex/RunArrays.cpp
new file mode 100644
index 0000000..574282b
--- /dev/null
+++ b/source/layoutex/RunArrays.cpp
@@ -0,0 +1,230 @@
+/*
+ **********************************************************************
+ *   Copyright (C) 2003, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ **********************************************************************
+ */
+
+#include "layout/LETypes.h"
+#include "layout/LEFontInstance.h"
+
+#include "unicode/locid.h"
+
+#include "layout/RunArrays.h"
+
+U_NAMESPACE_BEGIN
+
+const char RunArray::fgClassID = 0;
+
+RunArray::RunArray(le_int32 initialCapacity)
+    : fClientArrays(FALSE), fLimits(NULL), fCount(0), fCapacity(initialCapacity)
+{
+    if (initialCapacity > 0) {
+        fLimits = LE_NEW_ARRAY(le_int32, fCapacity);
+    }
+}
+
+RunArray::~RunArray()
+{
+    if (! fClientArrays) {
+        LE_DELETE_ARRAY(fLimits);
+        fLimits = NULL;
+    }
+}
+
+le_int32 RunArray::ensureCapacity()
+{
+    if (fCount >= fCapacity) {
+        if (fCapacity == 0) {
+            fCapacity = INITIAL_CAPACITY;
+            init(fCapacity);
+        } else {
+            fCapacity += (fCapacity < CAPACITY_GROW_LIMIT ? fCapacity : CAPACITY_GROW_LIMIT);
+            grow(fCapacity);
+        }
+    }
+
+    return fCount++;
+}
+
+void RunArray::init(le_int32 capacity)
+{
+    fLimits = LE_NEW_ARRAY(le_int32, capacity);
+}
+
+void RunArray::grow(le_int32 newCapacity)
+{
+    fLimits = (le_int32 *) LE_GROW_ARRAY(fLimits, newCapacity);
+}
+
+le_int32 RunArray::add(le_int32 limit)
+{
+    if (fClientArrays) {
+        return -1;
+    }
+
+    le_int32  index  = ensureCapacity();
+    le_int32 *limits = (le_int32 *) fLimits;
+
+    limits[index] = limit;
+
+    return index;
+}
+
+const char FontRuns::fgClassID = 0;
+
+FontRuns::FontRuns(le_int32 initialCapacity)
+    : RunArray(initialCapacity), fFonts(NULL)
+{
+    if (initialCapacity > 0) {
+        fFonts = LE_NEW_ARRAY(const LEFontInstance *, initialCapacity);
+    }
+}
+
+FontRuns::~FontRuns()
+{
+    if (! fClientArrays) {
+        LE_DELETE_ARRAY(fFonts);
+        fFonts = NULL;
+    }
+}
+
+void FontRuns::init(le_int32 capacity)
+{
+    RunArray::init(capacity);
+    fFonts = LE_NEW_ARRAY(const LEFontInstance *, capacity);
+}
+
+void FontRuns::grow(le_int32 capacity)
+{
+    RunArray::grow(capacity);
+    fFonts = (const LEFontInstance **) LE_GROW_ARRAY(fFonts, capacity);
+}
+
+le_int32 FontRuns::add(const LEFontInstance *font, le_int32 limit)
+{
+    le_int32 index = RunArray::add(limit);
+
+    if (index >= 0) {
+        LEFontInstance **fonts = (LEFontInstance **) fFonts;
+
+        fonts[index] = (LEFontInstance *) font;
+    }
+
+    return index;
+}
+
+const LEFontInstance *FontRuns::getFont(le_int32 run) const
+{
+    if (run < 0 || run >= getCount()) {
+        return NULL;
+    }
+
+    return fFonts[run];
+}
+
+const char LocaleRuns::fgClassID = 0;
+
+LocaleRuns::LocaleRuns(le_int32 initialCapacity)
+    : RunArray(initialCapacity), fLocales(NULL)
+{
+    if (initialCapacity > 0) {
+        fLocales = LE_NEW_ARRAY(const Locale *, initialCapacity);
+    }
+}
+
+LocaleRuns::~LocaleRuns()
+{
+    if (! fClientArrays) {
+        LE_DELETE_ARRAY(fLocales);
+        fLocales = NULL;
+    }
+}
+
+void LocaleRuns::init(le_int32 capacity)
+{
+    RunArray::init(capacity);
+    fLocales = LE_NEW_ARRAY(const Locale *, capacity);
+}
+
+void LocaleRuns::grow(le_int32 capacity)
+{
+    RunArray::grow(capacity);
+    fLocales = (const Locale **) LE_GROW_ARRAY(fLocales, capacity);
+}
+
+le_int32 LocaleRuns::add(const Locale *locale, le_int32 limit)
+{
+    le_int32 index = RunArray::add(limit);
+
+    if (index >= 0) {
+        Locale **locales = (Locale **) fLocales;
+
+        locales[index] = (Locale *) locale;
+    }
+
+    return index;
+}
+
+const Locale *LocaleRuns::getLocale(le_int32 run) const
+{
+    if (run < 0 || run >= getCount()) {
+        return NULL;
+    }
+
+    return fLocales[run];
+}
+
+const char ValueRuns::fgClassID = 0;
+
+ValueRuns::ValueRuns(le_int32 initialCapacity)
+    : RunArray(initialCapacity), fValues(NULL)
+{
+    if (initialCapacity > 0) {
+        fValues = LE_NEW_ARRAY(le_int32, initialCapacity);
+    }
+}
+
+ValueRuns::~ValueRuns()
+{
+    if (! fClientArrays) {
+        LE_DELETE_ARRAY(fValues);
+        fValues = NULL;
+    }
+}
+
+void ValueRuns::init(le_int32 capacity)
+{
+    RunArray::init(capacity);
+    fValues = LE_NEW_ARRAY(le_int32, capacity);
+}
+
+void ValueRuns::grow(le_int32 capacity)
+{
+    RunArray::grow(capacity);
+    fValues = (const le_int32 *) LE_GROW_ARRAY(fValues, capacity);
+}
+
+le_int32 ValueRuns::add(le_int32 value, le_int32 limit)
+{
+    le_int32 index = RunArray::add(limit);
+
+    if (index >= 0) {
+        le_int32 *values = (le_int32 *) fValues;
+
+        values[index] = value;
+    }
+
+    return index;
+}
+
+le_int32 ValueRuns::getValue(le_int32 run) const
+{
+    if (run < 0 || run >= getCount()) {
+        return -1;
+    }
+
+    return fValues[run];
+}
+
+U_NAMESPACE_END
diff --git a/source/layoutex/layout/ParagraphLayout.h b/source/layoutex/layout/ParagraphLayout.h
new file mode 100644
index 0000000..408fdf2
--- /dev/null
+++ b/source/layoutex/layout/ParagraphLayout.h
@@ -0,0 +1,737 @@
+/*
+ **********************************************************************
+ *   Copyright (C) 2002-2010, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ **********************************************************************
+ */
+
+#ifndef __PARAGRAPHLAYOUT_H
+
+#define __PARAGRAPHLAYOUT_H
+
+/**
+ * \file 
+ * \brief C++ API: Paragraph Layout
+ */
+
+/*
+ * ParagraphLayout doesn't make much sense without
+ * BreakIterator...
+ */
+#include "unicode/uscript.h"
+#if ! UCONFIG_NO_BREAK_ITERATION
+
+#include "layout/LETypes.h"
+#include "layout/LEFontInstance.h"
+#include "layout/LayoutEngine.h"
+#include "unicode/ubidi.h"
+#include "unicode/brkiter.h"
+
+#include "layout/RunArrays.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * ParagraphLayout.
+ *
+ * The <code>ParagraphLayout</code> object will analyze the text into runs of text in the
+ * same font, script and direction, and will create a <code>LayoutEngine</code> object for each run.
+ * The <code>LayoutEngine</code> will transform the characters into glyph codes in visual order.
+ *
+ * Clients can use this to break a paragraph into lines, and to display the glyphs in each line.
+ *
+ */
+class U_LAYOUTEX_API ParagraphLayout : public UObject
+{
+public:
+    class VisualRun;
+
+    /**
+     * This class represents a single line of text in a <code>ParagraphLayout</code>. They
+     * can only be created by calling <code>ParagraphLayout::nextLine()</code>. Each line
+     * consists of multiple visual runs, represented by <code>ParagraphLayout::VisualRun</code>
+     * objects.
+     *
+     * @see ParagraphLayout
+     * @see ParagraphLayout::VisualRun
+     *
+     * @stable ICU 3.2
+     */
+    class U_LAYOUTEX_API Line : public UObject
+    {
+    public:
+        /**
+         * The constructor is private since these objects can only be
+         * created by <code>ParagraphLayout</code>. However, it is the
+         * clients responsibility to destroy the objects, so the destructor
+         * is public.
+        *
+        * @stable ICU 3.2
+         */
+        ~Line();
+
+        /**
+         * Count the number of visual runs in the line.
+         *
+         * @return the number of visual runs.
+         *
+         * @stable ICU 3.2
+         */
+        inline le_int32 countRuns() const;
+
+        /**
+         * Get the ascent of the line. This is the maximum ascent
+         * of all the fonts on the line.
+         *
+         * @return the ascent of the line.
+         *
+         * @stable ICU 3.2
+         */
+        le_int32 getAscent() const;
+
+        /**
+         * Get the descent of the line. This is the maximum descent
+         * of all the fonts on the line.
+         *
+         * @return the descent of the line.
+         *
+         * @stable ICU 3.2
+         */
+        le_int32 getDescent() const;
+
+        /**
+         * Get the leading of the line. This is the maximum leading
+         * of all the fonts on the line.
+         *
+         * @return the leading of the line.
+         *
+         * @stable ICU 3.2
+         */
+        le_int32 getLeading() const;
+
+        /**
+         * Get the width of the line. This is a convenience method
+         * which returns the last X position of the last visual run
+         * in the line.
+         *
+         * @return the width of the line.
+         *
+         * @stable ICU 2.8
+         */
+        le_int32 getWidth() const;
+    
+        /**
+         * Get a <code>ParagraphLayout::VisualRun</code> object for a given
+         * visual run in the line.
+         *
+         * @param runIndex is the index of the run, in visual order.
+         *
+         * @return the <code>ParagraphLayout::VisualRun</code> object representing the
+         *         visual run. This object is owned by the <code>Line</code> object which
+         *         created it, and will remain valid for as long as the <code>Line</code>
+         *         object is valid.
+         *
+         * @see ParagraphLayout::VisualRun
+         *
+         * @stable ICU 3.2
+         */
+        const VisualRun *getVisualRun(le_int32 runIndex) const;
+
+        /**
+         * ICU "poor man's RTTI", returns a UClassID for this class.
+         *
+         * @stable ICU 3.2
+         */
+        static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
+
+        /**
+         * ICU "poor man's RTTI", returns a UClassID for the actual class.
+         *
+         * @stable ICU 3.2
+         */
+        virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
+
+    private:
+
+        /**
+         * The address of this static class variable serves as this class's ID
+         * for ICU "poor man's RTTI".
+         */
+        static const char fgClassID;
+
+        friend class ParagraphLayout;
+
+        le_int32 fAscent;
+        le_int32 fDescent;
+        le_int32 fLeading;
+
+        le_int32 fRunCount;
+        le_int32 fRunCapacity;
+
+        VisualRun **fRuns;
+
+        inline Line();
+        inline Line(const Line &other);
+        inline Line &operator=(const Line & /*other*/) { return *this; };
+
+        void computeMetrics();
+
+        void append(const LEFontInstance *font, UBiDiDirection direction, le_int32 glyphCount,
+                    const LEGlyphID glyphs[], const float positions[], const le_int32 glyphToCharMap[]);
+    };
+
+    /**
+     * This object represents a single visual run in a line of text in
+     * a paragraph. A visual run is text which is in the same font, 
+     * script, and direction. The text is represented by an array of
+     * <code>LEGlyphIDs</code>, an array of (x, y) glyph positions and
+     * a table which maps indices into the glyph array to indices into
+     * the original character array which was used to create the paragraph.
+     *
+     * These objects are only created by <code>ParagraphLayout::Line</code> objects,
+     * so their constructors and destructors are private.
+     *
+     * @see ParagraphLayout::Line
+     *
+     * @stable ICU 3.2
+     */
+    class U_LAYOUTEX_API VisualRun : public UObject
+    {
+    public:
+        /**
+         * Get the <code>LEFontInstance</code> object which
+         * represents the font of the visual run. This will always
+         * be a non-composite font.
+         *
+         * @return the <code>LEFontInstance</code> object which represents the
+         *         font of the visual run.
+         *
+         * @see LEFontInstance
+         *
+         * @stable ICU 3.2
+         */
+        inline const LEFontInstance *getFont() const;
+
+        /**
+         * Get the direction of the visual run.
+         *
+         * @return the direction of the run. This will be UBIDI_LTR if the
+         *         run is left-to-right and UBIDI_RTL if the line is right-to-left.
+         *
+         * @stable ICU 3.2
+         */
+        inline UBiDiDirection getDirection() const;
+
+        /**
+         * Get the number of glyphs in the visual run.
+         *
+         * @return the number of glyphs.
+         *
+         * @stable ICU 3.2
+         */
+        inline le_int32 getGlyphCount() const;
+
+        /**
+         * Get the glyphs in the visual run. Glyphs with the values <code>0xFFFE</code> and
+         * <code>0xFFFF</code> should be ignored.
+         *
+         * @return the address of the array of glyphs for this visual run. The storage
+         *         is owned by the <code>VisualRun</code> object and must not be deleted.
+         *         It will remain valid as long as the <code>VisualRun</code> object is valid.
+         *
+         * @stable ICU 3.2
+         */
+        inline const LEGlyphID *getGlyphs() const;
+
+        /**
+         * Get the (x, y) positions of the glyphs in the visual run. To simplify storage
+         * management, the x and y positions are stored in a single array with the x positions
+         * at even offsets in the array and the corresponding y position in the following odd offset.
+         * There is an extra (x, y) pair at the end of the array which represents the advance of
+         * the final glyph in the run.
+         *
+         * @return the address of the array of glyph positions for this visual run. The storage
+         *         is owned by the <code>VisualRun</code> object and must not be deleted.
+         *         It will remain valid as long as the <code>VisualRun</code> object is valid.
+         *
+         * @stable ICU 3.2
+         */
+        inline const float *getPositions() const;
+
+        /**
+         * Get the glyph-to-character map for this visual run. This maps the indices into
+         * the glyph array to indices into the character array used to create the paragraph.
+         *
+         * @return the address of the character-to-glyph map for this visual run. The storage
+         *         is owned by the <code>VisualRun</code> object and must not be deleted.
+         *         It will remain valid as long as the <code>VisualRun</code> object is valid.
+         *
+         * @stable ICU 3.2
+         */
+        inline const le_int32 *getGlyphToCharMap() const;
+
+        /**
+         * A convenience method which returns the ascent value for the font
+         * associated with this run.
+         *
+         * @return the ascent value of this run's font.
+         *
+         * @stable ICU 3.2
+         */
+        inline le_int32 getAscent() const;
+
+        /**
+         * A convenience method which returns the descent value for the font
+         * associated with this run.
+         *
+         * @return the descent value of this run's font.
+         *
+         * @stable ICU 3.2
+         */
+        inline le_int32 getDescent() const;
+
+        /**
+         * A convenience method which returns the leading value for the font
+         * associated with this run.
+         *
+         * @return the leading value of this run's font.
+         *
+         * @stable ICU 3.2
+         */
+        inline le_int32 getLeading() const;
+
+        /**
+         * ICU "poor man's RTTI", returns a UClassID for this class.
+         *
+         * @stable ICU 3.2
+         */
+        static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
+
+        /**
+         * ICU "poor man's RTTI", returns a UClassID for the actual class.
+         *
+         * @stable ICU 3.2
+         */
+        virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
+
+    private:
+
+        /**
+         * The address of this static class variable serves as this class's ID
+         * for ICU "poor man's RTTI".
+         */
+        static const char fgClassID;
+
+        const LEFontInstance *fFont;
+        const UBiDiDirection  fDirection;
+
+        const le_int32 fGlyphCount;
+
+        const LEGlyphID *fGlyphs;
+        const float     *fPositions;
+        const le_int32  *fGlyphToCharMap;
+
+        friend class Line;
+
+        inline VisualRun();
+        inline VisualRun(const VisualRun &other);
+        inline VisualRun &operator=(const VisualRun &/*other*/) { return *this; };
+
+        inline VisualRun(const LEFontInstance *font, UBiDiDirection direction, le_int32 glyphCount,
+                  const LEGlyphID glyphs[], const float positions[], const le_int32 glyphToCharMap[]);
+
+        ~VisualRun();
+    };
+
+    /**
+     * Construct a <code>ParagraphLayout</code> object for a styled paragraph. The paragraph is specified
+     * as runs of text all in the same font. An <code>LEFontInstance</code> object and a limit offset
+     * are specified for each font run. The limit offset is the offset of the character immediately
+     * after the font run.
+     *
+     * Clients can optionally specify directional runs and / or script runs. If these aren't specified
+     * they will be computed.
+     *
+     * If any errors are encountered during construction, <code>status</code> will be set, and the object
+     * will be set to be empty.
+     *
+     * @param chars is an array of the characters in the paragraph
+     *
+     * @param count is the number of characters in the paragraph.
+     *
+     * @param fontRuns a pointer to a <code>FontRuns</code> object representing the font runs.
+     *
+     * @param levelRuns is a pointer to a <code>ValueRuns</code> object representing the directional levels.
+     *        If this pointer in <code>NULL</code> the levels will be determined by running the Unicde
+     *        Bidi algorithm.
+     *
+     * @param scriptRuns is a pointer to a <code>ValueRuns</code> object representing script runs.
+     *        If this pointer in <code>NULL</code> the script runs will be determined using the
+     *        Unicode code points.
+     *
+     * @param localeRuns is a pointer to a <code>LocaleRuns</code> object representing locale runs.
+     *        The <code>Locale</code> objects are used to determind the language of the text. If this
+     *        pointer is <code>NULL</code> the default locale will be used for all of the text. 
+     *
+     * @param paragraphLevel is the directionality of the paragraph, as in the UBiDi object.
+     *
+     * @param vertical is <code>TRUE</code> if the paragraph should be set vertically.
+     *
+     * @param status will be set to any error code encountered during construction.
+     *
+     * @see ubidi.h
+     * @see LEFontInstance.h
+     * @see LayoutEngine.h
+     * @see RunArrays.h
+     *
+     * @stable ICU 2.8
+     */
+    ParagraphLayout(const LEUnicode chars[], le_int32 count,
+                    const FontRuns *fontRuns,
+                    const ValueRuns *levelRuns,
+                    const ValueRuns *scriptRuns,
+                    const LocaleRuns *localeRuns,
+                    UBiDiLevel paragraphLevel, le_bool vertical,
+                    LEErrorCode &status);
+
+    /**
+     * The destructor. Virtual so that it works correctly with
+     * sublcasses.
+     *
+     * @stable ICU 3.2
+     */
+    ~ParagraphLayout();
+
+    // Note: the following is #if 0'd out because there's no good
+    // way to implement it without either calling layoutEngineFactory()
+    // or duplicating the logic there...
+#if 0
+    /**
+     * Examine the given styled paragraph and determine if it contains any text which
+     * requires complex processing. (i.e. that cannot be correctly rendered by
+     * just mapping the characters to glyphs and rendering them in order)
+     *
+     * @param chars is an array of the characters in the paragraph
+     *
+     * @param count is the number of characters in the paragraph.
+     *
+     * @param fontRuns is a pointer to a <code>FontRuns</code> object representing the font runs.
+     *
+     * @return <code>TRUE</code> if the paragraph contains complex text.
+     *
+     * @stable ICU 3.2
+     */
+    static le_bool isComplex(const LEUnicode chars[], le_int32 count, const FontRuns *fontRuns);
+#else
+    /**
+     * Examine the given text and determine if it contains characters in any
+     * script which requires complex processing to be rendered correctly.
+     *
+     * @param chars is an array of the characters in the paragraph
+     *
+     * @param count is the number of characters in the paragraph.
+     *
+     * @return <code>TRUE</code> if any of the text requires complex processing.
+     *
+     * @stable ICU 3.2
+     */
+    static le_bool isComplex(const LEUnicode chars[], le_int32 count);
+
+#endif
+
+    /**
+     * Return the resolved paragraph level. This is useful for those cases
+     * where the bidi analysis has determined the level based on the first
+     * strong character in the paragraph.
+     *
+     * @return the resolved paragraph level.
+     *
+     * @stable ICU 3.2
+     */
+    inline UBiDiLevel getParagraphLevel();
+
+    /**
+     * Return the directionality of the text in the paragraph.
+     *
+     * @return <code>UBIDI_LTR</code> if the text is all left to right,
+     *         <code>UBIDI_RTL</code> if the text is all right to left,
+     *         or <code>UBIDI_MIXED</code> if the text has mixed direction.
+     *
+     * @stable ICU 3.2
+     */
+    inline UBiDiDirection getTextDirection();
+
+    /**
+     * Return the max ascent value for all the fonts
+     * in the paragraph.
+     *
+     * @return the ascent value.
+     *
+     * @stable ICU 3.2
+     */
+    virtual le_int32 getAscent() const;
+
+    /**
+     * Return the max descent value for all the fonts
+     * in the paragraph.
+     *
+     * @return the decent value.
+     *
+     * @stable ICU 3.2
+     */
+    virtual le_int32 getDescent() const;
+
+    /**
+     * Return the max leading value for all the fonts
+     * in the paragraph.
+     *
+     * @return the leading value.
+     *
+     * @stable ICU 3.2
+     */
+    virtual le_int32 getLeading() const;
+
+    /**
+     * Reset line breaking to start from the beginning of the paragraph.
+     *
+     *
+     * @stable ICU 3.2
+     */
+    inline void reflow();
+    /**
+     *
+     * Convenience method for determining if paragraph layout processing is complete ( i.e. there
+     * are no more lines left to process. )
+     *
+     * @return true if there are no more lines to be processed
+     *
+     * @internal 
+     */
+    inline le_bool isDone() const;
+
+    /**
+     * Return a <code>ParagraphLayout::Line</code> object which represents next line
+     * in the paragraph. The width of the line is specified each time so that it can
+     * be varied to support arbitrary paragraph shapes.
+     *
+     * @param width is the width of the line. If <code>width</code> is less than or equal
+     *              to zero, a <code>ParagraphLayout::Line</code> object representing the
+     *              rest of the paragraph will be returned.
+     *
+     * @return a <code>ParagraphLayout::Line</code> object which represents the line. The caller
+     *         is responsible for deleting the object. Returns <code>NULL</code> if there are no
+     *         more lines in the paragraph.
+     *
+     * @see ParagraphLayout::Line
+     *
+     * @stable ICU 3.2
+     */
+    Line *nextLine(float width);
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 3.2
+     */
+    static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 3.2
+     */
+    virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
+
+private:
+
+
+    /**
+     * The address of this static class variable serves as this class's ID
+     * for ICU "poor man's RTTI".
+     */
+    static const char fgClassID;
+
+    struct StyleRunInfo
+    {
+          LayoutEngine   *engine;
+    const LEFontInstance *font;
+    const Locale         *locale;
+          LEGlyphID      *glyphs;
+          float          *positions;
+          UScriptCode     script;
+          UBiDiLevel      level;
+          le_int32        runBase;
+          le_int32        runLimit;
+          le_int32        glyphBase;
+          le_int32        glyphCount;
+    };
+
+    ParagraphLayout() {};
+    ParagraphLayout(const ParagraphLayout & /*other*/) : UObject( ){};
+    inline ParagraphLayout &operator=(const ParagraphLayout & /*other*/) { return *this; };
+
+    void computeLevels(UBiDiLevel paragraphLevel);
+
+    Line *computeVisualRuns();
+    void appendRun(Line *line, le_int32 run, le_int32 firstChar, le_int32 lastChar);
+
+    void computeScripts();
+
+    void computeLocales();
+
+    void computeSubFonts(const FontRuns *fontRuns, LEErrorCode &status);
+
+    void computeMetrics();
+
+    le_int32 getLanguageCode(const Locale *locale);
+
+    le_int32 getCharRun(le_int32 charIndex);
+
+    static le_bool isComplex(UScriptCode script);
+
+    le_int32 previousBreak(le_int32 charIndex);
+
+
+    const LEUnicode *fChars;
+          le_int32   fCharCount;
+
+    const FontRuns   *fFontRuns;
+    const ValueRuns  *fLevelRuns;
+    const ValueRuns  *fScriptRuns;
+    const LocaleRuns *fLocaleRuns;
+
+          le_bool fVertical;
+          le_bool fClientLevels;
+          le_bool fClientScripts;
+          le_bool fClientLocales;
+
+          UBiDiLevel *fEmbeddingLevels;
+
+          le_int32 fAscent;
+          le_int32 fDescent;
+          le_int32 fLeading;
+
+          le_int32 *fGlyphToCharMap;
+          le_int32 *fCharToMinGlyphMap;
+          le_int32 *fCharToMaxGlyphMap;
+          float    *fGlyphWidths;
+          le_int32  fGlyphCount;
+
+          UBiDi *fParaBidi;
+          UBiDi *fLineBidi;
+
+          le_int32     *fStyleRunLimits;
+          le_int32     *fStyleIndices;
+          StyleRunInfo *fStyleRunInfo;
+          le_int32      fStyleRunCount;
+
+          BreakIterator *fBreakIterator;
+          le_int32       fLineStart;
+          le_int32       fLineEnd;
+
+          le_int32       fFirstVisualRun;
+          le_int32       fLastVisualRun;
+          float          fVisualRunLastX;
+          float          fVisualRunLastY;
+};
+
+inline UBiDiLevel ParagraphLayout::getParagraphLevel()
+{
+    return ubidi_getParaLevel(fParaBidi);
+}
+
+inline UBiDiDirection ParagraphLayout::getTextDirection()
+{
+    return ubidi_getDirection(fParaBidi);
+}
+
+inline void ParagraphLayout::reflow()
+{
+    fLineEnd = 0;
+}
+
+inline ParagraphLayout::Line::Line()
+    : UObject(), fAscent(0), fDescent(0), fLeading(0), fRunCount(0), fRunCapacity(0), fRuns(NULL)
+{
+    // nothing else to do
+}
+
+inline ParagraphLayout::Line::Line(const Line & /*other*/)
+    : UObject(), fAscent(0), fDescent(0), fLeading(0), fRunCount(0), fRunCapacity(0), fRuns(NULL)
+{
+    // nothing else to do
+}
+
+inline le_int32 ParagraphLayout::Line::countRuns() const
+{
+    return fRunCount;
+}
+
+inline const LEFontInstance *ParagraphLayout::VisualRun::getFont() const
+{
+    return fFont;
+}
+
+inline UBiDiDirection ParagraphLayout::VisualRun::getDirection() const
+{
+    return fDirection;
+}
+
+inline le_int32 ParagraphLayout::VisualRun::getGlyphCount() const
+{
+    return fGlyphCount;
+}
+
+inline const LEGlyphID *ParagraphLayout::VisualRun::getGlyphs() const
+{
+    return fGlyphs;
+}
+
+inline const float *ParagraphLayout::VisualRun::getPositions() const
+{
+    return fPositions;
+}
+
+inline const le_int32 *ParagraphLayout::VisualRun::getGlyphToCharMap() const
+{
+    return fGlyphToCharMap;
+}
+
+inline le_int32 ParagraphLayout::VisualRun::getAscent() const
+{
+    return fFont->getAscent();
+}
+
+inline le_int32 ParagraphLayout::VisualRun::getDescent() const
+{
+    return fFont->getDescent();
+}
+
+inline le_int32 ParagraphLayout::VisualRun::getLeading() const
+{
+    return fFont->getLeading();
+}
+
+inline ParagraphLayout::VisualRun::VisualRun()
+    : UObject(), fFont(NULL), fDirection(UBIDI_LTR), fGlyphCount(0), fGlyphs(NULL), fPositions(NULL), fGlyphToCharMap(NULL)
+{
+    // nothing
+}
+
+inline ParagraphLayout::VisualRun::VisualRun(const VisualRun &/*other*/)
+    : UObject(), fFont(NULL), fDirection(UBIDI_LTR), fGlyphCount(0), fGlyphs(NULL), fPositions(NULL), fGlyphToCharMap(NULL)
+{
+    // nothing
+}
+
+inline ParagraphLayout::VisualRun::VisualRun(const LEFontInstance *font, UBiDiDirection direction, le_int32 glyphCount,
+                                             const LEGlyphID glyphs[], const float positions[], const le_int32 glyphToCharMap[])
+    : fFont(font), fDirection(direction), fGlyphCount(glyphCount),
+      fGlyphs(glyphs), fPositions(positions), fGlyphToCharMap(glyphToCharMap)
+{
+    // nothing else needs to be done!
+}
+
+U_NAMESPACE_END
+#endif
+#endif
diff --git a/source/layoutex/layout/RunArrays.h b/source/layoutex/layout/RunArrays.h
new file mode 100644
index 0000000..772fd8a
--- /dev/null
+++ b/source/layoutex/layout/RunArrays.h
@@ -0,0 +1,676 @@
+/*
+ **********************************************************************
+ *   Copyright (C) 2003-2008, International Business Machines
+ *   Corporation and others.  All Rights Reserved.
+ **********************************************************************
+ */
+
+#ifndef __RUNARRAYS_H
+
+#define __RUNARRAYS_H
+
+#include "layout/LETypes.h"
+#include "layout/LEFontInstance.h"
+
+#include "unicode/utypes.h"
+#include "unicode/locid.h"
+
+/**
+ * \file 
+ * \brief C++ API: base class for building classes which represent data that is associated with runs of text.
+ */
+ 
+U_NAMESPACE_BEGIN
+
+/**
+ * The initial size of an array if it is unspecified.
+ *
+ * @stable ICU 3.2
+ */
+#define INITIAL_CAPACITY 16
+
+/**
+ * When an array needs to grow, it will double in size until
+ * it becomes this large, then it will grow by this amount.
+ *
+ * @stable ICU 3.2
+ */
+#define CAPACITY_GROW_LIMIT 128
+
+/**
+ * The <code>RunArray</code> class is a base class for building classes
+ * which represent data that is associated with runs of text. This class
+ * maintains an array of limit indices into the text, subclasses
+ * provide one or more arrays of data.
+ *
+ * @stable ICU 3.2
+ */
+class U_LAYOUTEX_API RunArray : public UObject
+{
+public:
+    /**
+     * Construct a <code>RunArray</code> object from a pre-existing
+     * array of limit indices.
+     *
+     * @param limits is an array of limit indices. This array must remain
+     *               valid until the <code>RunArray</code> object is destroyed.
+     *
+     * @param count is the number of entries in the limit array.
+     *
+     * @stable ICU 3.2
+     */
+    inline RunArray(const le_int32 *limits, le_int32 count);
+
+    /**
+     * Construct an empty <code>RunArray</code> object. Clients can add limit
+     * indices array using the <code>add</code> method.
+     *
+     * @param initialCapacity is the initial size of the limit indices array. If
+     *        this value is zero, no array will be allocated.
+     *
+     * @see add
+     *
+     * @stable ICU 3.2
+     */
+    RunArray(le_int32 initialCapacity);
+
+    /**
+     * The destructor; virtual so that subclass destructors are invoked as well.
+     *
+     * @stable ICU 3.2
+     */
+    virtual ~RunArray();
+
+    /**
+     * Get the number of entries in the limit indices array.
+     *
+     * @return the number of entries in the limit indices array.
+     *
+     * @stable ICU 3.2
+     */
+    inline le_int32 getCount() const;
+
+    /**
+     * Reset the limit indices array. This method sets the number of entries in the
+     * limit indices array to zero. It does not delete the array.
+     *
+     * Note: Subclass arrays will also be reset and not deleted.
+     *
+     * @stable ICU 3.6
+     */
+    inline void reset();
+
+    /**
+     * Get the last limit index. This is the number of characters in
+     * the text.
+     *
+     * @return the last limit index.
+     *
+     * @stable ICU 3.2
+     */
+    inline le_int32 getLimit() const;
+
+    /**
+     * Get the limit index for a particular run of text.
+     *
+     * @param run is the run. This is an index into the limit index array.
+     *
+     * @return the limit index for the run, or -1 if <code>run</code> is out of bounds.
+     *
+     * @stable ICU 3.2
+     */
+    inline le_int32 getLimit(le_int32 run) const;
+
+    /**
+     * Add a limit index to the limit indices array and return the run index
+     * where it was stored. If the array does not exist, it will be created by
+     * calling the <code>init</code> method. If it is full, it will be grown by
+     * calling the <code>grow</code> method.
+     *
+     * If the <code>RunArray</code> object was created with a client-supplied
+     * limit indices array, this method will return a run index of -1.
+     *
+     * Subclasses should not override this method. Rather they should provide
+     * a new <code>add</code> method which takes a limit index along with whatever
+     * other data they implement. The new <code>add</code> method should
+     * first call this method to grow the data arrays, and use the return value
+     * to store the data in their own arrays.
+     *
+     * @param limit is the limit index to add to the array.
+     *
+     * @return the run index where the limit index was stored, or -1 if the limit index cannt be stored.
+     *
+     * @see init
+     * @see grow
+     *
+     * @stable ICU 3.2
+     */
+    le_int32 add(le_int32 limit);
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 3.2
+     */
+    static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 3.2
+     */
+    virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
+
+protected:
+    /**
+     * Create a data array with the given initial size. This method will be
+     * called by the <code>add</code> method if there is no limit indices
+     * array. Subclasses which override this method must also call it from
+     * the overriding method to create the limit indices array.
+     *
+     * @param capacity is the initial size of the data array.
+     *
+     * @see add
+     *
+     * @stable ICU 3.2
+     */
+    virtual void init(le_int32 capacity);
+
+    /**
+     * Grow a data array to the given initial size. This method will be
+     * called by the <code>add</code> method if the limit indices
+     * array is full. Subclasses which override this method must also call it from
+     * the overriding method to grow the limit indices array.
+     *
+     * @param capacity is the initial size of the data array.
+     *
+     * @see add
+     *
+     * @stable ICU 3.2
+     */
+    virtual void grow(le_int32 capacity);
+
+    /**
+     * Set by the constructors to indicate whether
+     * or not the client supplied the data arrays.
+     * If they were supplied by the client, the 
+     * <code>add</code> method won't change the arrays
+     * and the destructor won't delete them.
+     *
+     * @stable ICU 3.2
+     */
+    le_bool fClientArrays;
+
+private:
+    /**
+     * The address of this static class variable serves as this class's ID
+     * for ICU "poor man's RTTI".
+     */
+    static const char fgClassID;
+
+    le_int32 ensureCapacity();
+
+    inline RunArray();
+    inline RunArray(const RunArray & /*other*/);
+    inline RunArray &operator=(const RunArray & /*other*/) { return *this; };
+
+    const le_int32 *fLimits;
+          le_int32  fCount;
+          le_int32  fCapacity;
+};
+
+inline RunArray::RunArray()
+    : UObject(), fClientArrays(FALSE), fLimits(NULL), fCount(0), fCapacity(0)
+{
+    // nothing else to do...
+}
+
+inline RunArray::RunArray(const RunArray & /*other*/)
+    : UObject(), fClientArrays(FALSE), fLimits(NULL), fCount(0), fCapacity(0)
+{
+    // nothing else to do...
+}
+
+inline RunArray::RunArray(const le_int32 *limits, le_int32 count)
+    : UObject(), fClientArrays(TRUE), fLimits(limits), fCount(count), fCapacity(count)
+{
+    // nothing else to do...
+}
+
+inline le_int32 RunArray::getCount() const
+{
+    return fCount;
+}
+
+inline void RunArray::reset()
+{
+    fCount = 0;
+}
+
+inline le_int32 RunArray::getLimit(le_int32 run) const
+{
+    if (run < 0 || run >= fCount) {
+        return -1;
+    }
+
+    return fLimits[run];
+}
+
+inline le_int32 RunArray::getLimit() const
+{
+    return getLimit(fCount - 1);
+}
+
+/**
+ * The <code>FontRuns</code> class associates pointers to <code>LEFontInstance</code>
+ * objects with runs of text.
+ *
+ * @stable ICU 3.2
+ */
+class U_LAYOUTEX_API FontRuns : public RunArray
+{
+public:
+    /**
+     * Construct a <code>FontRuns</code> object from pre-existing arrays of fonts
+     * and limit indices.
+     *
+     * @param fonts is the address of an array of pointers to <code>LEFontInstance</code> objects. This
+     *              array, and the <code>LEFontInstance</code> objects to which it points must remain
+     *              valid until the <code>FontRuns</code> object is destroyed.
+     *
+     * @param limits is the address of an array of limit indices. This array must remain valid until
+     *               the <code>FontRuns</code> object is destroyed.
+     *
+     * @param count is the number of entries in the two arrays.
+     *
+     * @stable ICU 3.2
+     */
+    inline FontRuns(const LEFontInstance **fonts, const le_int32 *limits, le_int32 count);
+
+    /**
+     * Construct an empty <code>FontRuns</code> object. Clients can add font and limit
+     * indices arrays using the <code>add</code> method.
+     *
+     * @param initialCapacity is the initial size of the font and limit indices arrays. If
+     *        this value is zero, no arrays will be allocated.
+     *
+     * @see add
+     *
+     * @stable ICU 3.2
+     */
+    FontRuns(le_int32 initialCapacity);
+
+    /**
+     * The destructor; virtual so that subclass destructors are invoked as well.
+     *
+     * @stable ICU 3.2
+     */
+    virtual ~FontRuns();
+
+    /**
+     * Get the <code>LEFontInstance</code> object assoicated with the given run
+     * of text. Use <code>RunArray::getLimit(run)</code> to get the corresponding
+     * limit index.
+     *
+     * @param run is the index into the font and limit indices arrays.
+     *
+     * @return the <code>LEFontInstance</code> associated with the given text run.
+     *
+     * @see RunArray::getLimit
+     *
+     * @stable ICU 3.2
+     */
+    const LEFontInstance *getFont(le_int32 run) const;
+
+
+    /**
+     * Add an <code>LEFontInstance</code> and limit index pair to the data arrays and return
+     * the run index where the data was stored. This  method calls
+     * <code>RunArray::add(limit)</code> which will create or grow the arrays as needed.
+     *
+     * If the <code>FontRuns</code> object was created with a client-supplied
+     * font and limit indices arrays, this method will return a run index of -1.
+     *
+     * Subclasses should not override this method. Rather they should provide a new <code>add</code>
+     * method which takes a font and a limit index along with whatever other data they implement.
+     * The new <code>add</code> method should first call this method to grow the font and limit indices
+     * arrays, and use the returned run index to store data their own arrays.
+     *
+     * @param font is the address of the <code>LEFontInstance</code> to add. This object must
+     *             remain valid until the <code>FontRuns</code> object is destroyed.
+     *
+     * @param limit is the limit index to add
+     *
+     * @return the run index where the font and limit index were stored, or -1 if the data cannot be stored.
+     *
+     * @stable ICU 3.2
+     */
+    le_int32 add(const LEFontInstance *font, le_int32 limit);
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 3.2
+     */
+    static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 3.2
+     */
+    virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
+
+protected:
+    virtual void init(le_int32 capacity);
+    virtual void grow(le_int32 capacity);
+
+private:
+
+    inline FontRuns();
+    inline FontRuns(const FontRuns &other);
+    inline FontRuns &operator=(const FontRuns & /*other*/) { return *this; };
+
+    /**
+     * The address of this static class variable serves as this class's ID
+     * for ICU "poor man's RTTI".
+     */
+    static const char fgClassID;
+
+    const LEFontInstance **fFonts;
+};
+
+inline FontRuns::FontRuns()
+    : RunArray(0), fFonts(NULL)
+{
+    // nothing else to do...
+}
+
+inline FontRuns::FontRuns(const FontRuns & /*other*/)
+    : RunArray(0), fFonts(NULL)
+{
+    // nothing else to do...
+}
+
+inline FontRuns::FontRuns(const LEFontInstance **fonts, const le_int32 *limits, le_int32 count)
+    : RunArray(limits, count), fFonts(fonts)
+{
+    // nothing else to do...
+}
+
+/**
+ * The <code>LocaleRuns</code> class associates pointers to <code>Locale</code>
+ * objects with runs of text.
+ *
+ * @stable ICU 3.2
+ */
+class U_LAYOUTEX_API LocaleRuns : public RunArray
+{
+public:
+    /**
+     * Construct a <code>LocaleRuns</code> object from pre-existing arrays of locales
+     * and limit indices.
+     *
+     * @param locales is the address of an array of pointers to <code>Locale</code> objects. This array,
+     *                and the <code>Locale</code> objects to which it points, must remain valid until
+     *                the <code>LocaleRuns</code> object is destroyed.
+     *
+     * @param limits is the address of an array of limit indices. This array must remain valid until the
+     *               <code>LocaleRuns</code> object is destroyed.
+     *
+     * @param count is the number of entries in the two arrays.
+     *
+     * @stable ICU 3.2
+     */
+    inline LocaleRuns(const Locale **locales, const le_int32 *limits, le_int32 count);
+
+    /**
+     * Construct an empty <code>LocaleRuns</code> object. Clients can add locale and limit
+     * indices arrays using the <code>add</code> method.
+     *
+     * @param initialCapacity is the initial size of the locale and limit indices arrays. If
+     *        this value is zero, no arrays will be allocated.
+     *
+     * @see add
+     *
+     * @stable ICU 3.2
+     */
+    LocaleRuns(le_int32 initialCapacity);
+
+    /**
+     * The destructor; virtual so that subclass destructors are invoked as well.
+     *
+     * @stable ICU 3.2
+     */
+    virtual ~LocaleRuns();
+
+    /**
+     * Get the <code>Locale</code> object assoicated with the given run
+     * of text. Use <code>RunArray::getLimit(run)</code> to get the corresponding
+     * limit index.
+     *
+     * @param run is the index into the font and limit indices arrays.
+     *
+     * @return the <code>Locale</code> associated with the given text run.
+     *
+     * @see RunArray::getLimit
+     *
+     * @stable ICU 3.2
+     */
+    const Locale *getLocale(le_int32 run) const;
+
+
+    /**
+     * Add a <code>Locale</code> and limit index pair to the data arrays and return
+     * the run index where the data was stored. This  method calls
+     * <code>RunArray::add(limit)</code> which will create or grow the arrays as needed.
+     *
+     * If the <code>LocaleRuns</code> object was created with a client-supplied
+     * locale and limit indices arrays, this method will return a run index of -1.
+     *
+     * Subclasses should not override this method. Rather they should provide a new <code>add</code>
+     * method which takes a locale and a limit index along with whatever other data they implement.
+     * The new <code>add</code> method should first call this method to grow the font and limit indices
+     * arrays, and use the returned run index to store data their own arrays.
+     *
+     * @param locale is the address of the <code>Locale</code> to add. This object must remain valid
+     *               until the <code>LocaleRuns</code> object is destroyed.
+     *
+     * @param limit is the limit index to add
+     *
+     * @return the run index where the locale and limit index were stored, or -1 if the data cannot be stored.
+     *
+     * @stable ICU 3.2
+     */
+    le_int32 add(const Locale *locale, le_int32 limit);
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 3.2
+     */
+    static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 3.2
+     */
+    virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
+
+protected:
+    virtual void init(le_int32 capacity);
+    virtual void grow(le_int32 capacity);
+
+    /**
+     * @internal
+     */
+    const Locale **fLocales;
+
+private:
+
+    inline LocaleRuns();
+    inline LocaleRuns(const LocaleRuns &other);
+    inline LocaleRuns &operator=(const LocaleRuns & /*other*/) { return *this; };
+
+    /**
+     * The address of this static class variable serves as this class's ID
+     * for ICU "poor man's RTTI".
+     */
+    static const char fgClassID;
+};
+
+inline LocaleRuns::LocaleRuns()
+    : RunArray(0), fLocales(NULL)
+{
+    // nothing else to do...
+}
+
+inline LocaleRuns::LocaleRuns(const LocaleRuns & /*other*/)
+    : RunArray(0), fLocales(NULL)
+{
+    // nothing else to do...
+}
+
+inline LocaleRuns::LocaleRuns(const Locale **locales, const le_int32 *limits, le_int32 count)
+    : RunArray(limits, count), fLocales(locales)
+{
+    // nothing else to do...
+}
+
+/**
+ * The <code>ValueRuns</code> class associates integer values with runs of text.
+ *
+ * @stable ICU 3.2
+ */
+class U_LAYOUTEX_API ValueRuns : public RunArray
+{
+public:
+    /**
+     * Construct a <code>ValueRuns</code> object from pre-existing arrays of values
+     * and limit indices.
+     *
+     * @param values is the address of an array of integer. This array must remain valid until
+     *               the <code>ValueRuns</code> object is destroyed.
+     *
+     * @param limits is the address of an array of limit indices. This array must remain valid until
+     *               the <code>ValueRuns</code> object is destroyed.
+     *
+     * @param count is the number of entries in the two arrays.
+     *
+     * @stable ICU 3.2
+     */
+    inline ValueRuns(const le_int32 *values, const le_int32 *limits, le_int32 count);
+
+    /**
+     * Construct an empty <code>ValueRuns</code> object. Clients can add value and limit
+     * indices arrays using the <code>add</code> method.
+     *
+     * @param initialCapacity is the initial size of the value and limit indices arrays. If
+     *        this value is zero, no arrays will be allocated.
+     *
+     * @see add
+     *
+     * @stable ICU 3.2
+     */
+    ValueRuns(le_int32 initialCapacity);
+
+    /**
+     * The destructor; virtual so that subclass destructors are invoked as well.
+     *
+     * @stable ICU 3.2
+     */
+    virtual ~ValueRuns();
+
+    /**
+     * Get the integer value assoicated with the given run
+     * of text. Use <code>RunArray::getLimit(run)</code> to get the corresponding
+     * limit index.
+     *
+     * @param run is the index into the font and limit indices arrays.
+     *
+     * @return the integer value associated with the given text run.
+     *
+     * @see RunArray::getLimit
+     *
+     * @stable ICU 3.2
+     */
+    le_int32 getValue(le_int32 run) const;
+
+
+    /**
+     * Add an integer value and limit index pair to the data arrays and return
+     * the run index where the data was stored. This  method calls
+     * <code>RunArray::add(limit)</code> which will create or grow the arrays as needed.
+     *
+     * If the <code>ValueRuns</code> object was created with a client-supplied
+     * font and limit indices arrays, this method will return a run index of -1.
+     *
+     * Subclasses should not override this method. Rather they should provide a new <code>add</code>
+     * method which takes an integer value and a limit index along with whatever other data they implement.
+     * The new <code>add</code> method should first call this method to grow the font and limit indices
+     * arrays, and use the returned run index to store data their own arrays.
+     *
+     * @param value is the integer value to add
+     *
+     * @param limit is the limit index to add
+     *
+     * @return the run index where the value and limit index were stored, or -1 if the data cannot be stored.
+     *
+     * @stable ICU 3.2
+     */
+    le_int32 add(le_int32 value, le_int32 limit);
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @stable ICU 3.2
+     */
+    static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @stable ICU 3.2
+     */
+    virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
+
+protected:
+    virtual void init(le_int32 capacity);
+    virtual void grow(le_int32 capacity);
+
+private:
+
+    inline ValueRuns();
+    inline ValueRuns(const ValueRuns &other);
+    inline ValueRuns &operator=(const ValueRuns & /*other*/) { return *this; };
+
+    /**
+     * The address of this static class variable serves as this class's ID
+     * for ICU "poor man's RTTI".
+     */
+    static const char fgClassID;
+
+    const le_int32 *fValues;
+};
+
+inline ValueRuns::ValueRuns()
+    : RunArray(0), fValues(NULL)
+{
+    // nothing else to do...
+}
+
+inline ValueRuns::ValueRuns(const ValueRuns & /*other*/)
+    : RunArray(0), fValues(NULL)
+{
+    // nothing else to do...
+}
+
+inline ValueRuns::ValueRuns(const le_int32 *values, const le_int32 *limits, le_int32 count)
+    : RunArray(limits, count), fValues(values)
+{
+    // nothing else to do...
+}
+
+U_NAMESPACE_END
+#endif
diff --git a/source/layoutex/layout/playout.h b/source/layoutex/layout/playout.h
new file mode 100644
index 0000000..1d98e16
--- /dev/null
+++ b/source/layoutex/layout/playout.h
@@ -0,0 +1,464 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+#ifndef __PLAYOUT_H
+#define __PLAYOUT_H
+
+/*
+ * ParagraphLayout doesn't make much sense without
+ * BreakIterator...
+ */
+#include "unicode/ubidi.h"
+#if ! UCONFIG_NO_BREAK_ITERATION
+
+#include "layout/LETypes.h"
+#include "plruns.h"
+
+/**
+ * \file 
+ * \brief C API for paragraph layout.
+ *
+ * This is a technology preview. The API may
+ * change significantly.
+ *
+ */
+
+/**
+ * The opaque type for a paragraph layout.
+ *
+ * @internal
+ */
+typedef void pl_paragraph;
+
+/**
+ * The opaque type for a line in a paragraph layout.
+ *
+ * @internal
+ */
+typedef void pl_line;
+
+/**
+ * The opaque type for a visual run in a line.
+ *
+ * @internal
+ */
+typedef void pl_visualRun;
+
+/**
+ * Construct a <code>ParagraphLayout</code> object for a styled paragraph. The paragraph is specified
+ * as runs of text all in the same font. An <code>LEFontInstance</code> object and a limit offset
+ * are specified for each font run. The limit offset is the offset of the character immediately
+ * after the font run.
+ *
+ * Clients can optionally specify directional runs and / or script runs. If these aren't specified
+ * they will be computed.
+ *
+ * If any errors are encountered during construction, <code>status</code> will be set, and the object
+ * will be set to be empty.
+ *
+ * @param chars is an array of the characters in the paragraph
+ *
+ * @param count is the number of characters in the paragraph.
+ *
+ * @param fontRuns a pointer to a <code>pl_fontRuns</code> object representing the font runs.
+ *
+ * @param levelRuns is a pointer to a <code>pl_valueRuns</code> object representing the directional levels.
+ *        If this pointer in <code>NULL</code> the levels will be determined by running the Unicde
+ *        Bidi algorithm.
+ *
+ * @param scriptRuns is a pointer to a <code>pl_valueRuns</code> object representing script runs.
+ *        If this pointer in <code>NULL</code> the script runs will be determined using the
+ *        Unicode code points.
+ *
+ * @param localeRuns is a pointer to a <code>pl_localeRuns</code> object representing locale runs.
+ *        The <code>Locale</code> objects are used to determind the language of the text. If this
+ *        pointer is <code>NULL</code> the default locale will be used for all of the text. 
+ *
+ * @param paragraphLevel is the directionality of the paragraph, as in the UBiDi object.
+ *
+ * @param vertical is <code>TRUE</code> if the paragraph should be set vertically.
+ *
+ * @param status will be set to any error code encountered during construction.
+ *
+ * @return a pointer to the newly created <code>pl_paragraph</code> object. The object
+ *         will remain valid until <code>pl_close</code> is called.
+ *
+ * @see ubidi.h
+ * @see longine.h
+ * @see plruns.h
+ *
+ * @internal
+ */
+U_INTERNAL pl_paragraph * U_EXPORT2
+pl_create(const LEUnicode chars[],
+          le_int32 count,
+          const pl_fontRuns *fontRuns,
+          const pl_valueRuns *levelRuns,
+          const pl_valueRuns *scriptRuns,
+          const pl_localeRuns *localeRuns,
+          UBiDiLevel paragraphLevel,
+          le_bool vertical,
+          LEErrorCode *status);
+
+/**
+ * Close the given paragraph layout object.
+ *
+ * @param paragraph the <code>pl_paragraph</code> object to be
+ *                  closed. Once this routine returns the object
+ *                  can no longer be referenced
+ *
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2
+pl_close(pl_paragraph *paragraph);
+
+/**
+ * Examine the given text and determine if it contains characters in any
+ * script which requires complex processing to be rendered correctly.
+ *
+ * @param chars is an array of the characters in the paragraph
+ *
+ * @param count is the number of characters in the paragraph.
+ *
+ * @return <code>TRUE</code> if any of the text requires complex processing.
+ *
+ * @internal
+ */
+
+U_INTERNAL le_bool U_EXPORT2
+pl_isComplex(const LEUnicode chars[],
+          le_int32 count);
+
+/**
+ * Return the resolved paragraph level. This is useful for those cases
+ * where the bidi analysis has determined the level based on the first
+ * strong character in the paragraph.
+ *
+ * @param paragraph the <code>pl_paragraph</code>
+ *
+ * @return the resolved paragraph level.
+ *
+ * @internal
+ */
+U_INTERNAL UBiDiLevel U_EXPORT2
+pl_getParagraphLevel(pl_paragraph *paragraph);
+
+/**
+ * Return the directionality of the text in the paragraph.
+ *
+ * @param paragraph the <code>pl_paragraph</code>
+ *
+ * @return <code>UBIDI_LTR</code> if the text is all left to right,
+ *         <code>UBIDI_RTL</code> if the text is all right to left,
+ *         or <code>UBIDI_MIXED</code> if the text has mixed direction.
+ *
+ * @internal
+ */
+U_INTERNAL UBiDiDirection U_EXPORT2
+pl_getTextDirection(pl_paragraph *paragraph);
+
+/**
+ * Get the max ascent value for all the fonts
+ * in the paragraph.
+ *
+ * @param paragraph the <code>pl_paragraph</code>
+ *
+ * Return the max ascent value for all the fonts
+ * in the paragraph.
+ *
+ * @param paragraph the <code>pl_paragraph</code>
+ *
+ * @return the ascent value.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getAscent(const pl_paragraph *paragraph);
+
+/**
+ * Return the max descent value for all the fonts
+ * in the paragraph.
+ *
+ * @param paragraph the <code>pl_paragraph</code>
+ *
+ * @return the decent value.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getDescent(const pl_paragraph *paragraph);
+
+/**
+ * Return the max leading value for all the fonts
+ * in the paragraph.
+ *
+ * @param paragraph the <code>pl_paragraph</code>
+ *
+ * @return the leading value.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getLeading(const pl_paragraph *paragraph);
+
+/**
+ * Reset line breaking to start from the beginning of the paragraph.
+ *
+ * @param paragraph the <code>pl_paragraph</code>
+ *
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2
+pl_reflow(pl_paragraph *paragraph);
+
+/**
+ * Return a <code>pl_line</code> object which represents next line
+ * in the paragraph. The width of the line is specified each time so that it can
+ * be varied to support arbitrary paragraph shapes.
+ *
+ * @param paragraph the <code>pl_paragraph</code>
+ * @param width is the width of the line. If <code>width</code> is less than or equal
+ *              to zero, a <code>ParagraphLayout::Line</code> object representing the
+ *              rest of the paragraph will be returned.
+ *
+ * @return a <code>ParagraphLayout::Line</code> object which represents the line. The caller
+ *         is responsible for deleting the object. Returns <code>NULL</code> if there are no
+ *         more lines in the paragraph.
+ *
+ * @see pl_line
+ *
+ * @internal
+ */
+U_INTERNAL pl_line * U_EXPORT2
+pl_nextLine(pl_paragraph *paragraph, float width);
+
+/**
+ * Close the given line object. Line objects are created
+ * by <code>pl_nextLine</code> but it is the client's responsibility
+ * to close them by calling this routine.
+ *
+ * @param line the <code>pl_line</code> object to close.
+ *
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2
+pl_closeLine(pl_line *line);
+
+/**
+ * Count the number of visual runs in the line.
+ *
+ * @param line the <code>pl_line</code> object.
+ *
+ * @return the number of visual runs.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_countLineRuns(const pl_line *line);
+
+/**
+ * Get the ascent of the line. This is the maximum ascent
+ * of all the fonts on the line.
+ *
+ * @param line the <code>pl_line</code> object.
+ *
+ * @return the ascent of the line.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getLineAscent(const pl_line *line);
+
+/**
+ * Get the descent of the line. This is the maximum descent
+ * of all the fonts on the line.
+ *
+ * @param line the <code>pl_line</code> object.
+ *
+ * @return the descent of the line.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getLineDescent(const pl_line *line);
+
+/**
+ * Get the leading of the line. This is the maximum leading
+ * of all the fonts on the line.
+ *
+ * @param line the <code>pl_line</code> object.
+ *
+ * @return the leading of the line.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getLineLeading(const pl_line *line);
+
+/**
+ * Get the width of the line. This is a convenience method
+ * which returns the last X position of the last visual run
+ * in the line.
+ *
+ * @param line the <code>pl_line</code> object.
+ *
+ * @return the width of the line.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getLineWidth(const pl_line *line);
+
+/**
+ * Get a <code>ParagraphLayout::VisualRun</code> object for a given
+ * visual run in the line.
+ *
+ * @param line the <code>pl_line</code> object.
+ * @param runIndex is the index of the run, in visual order.
+ *
+ * @return the <code>pl_visualRun</code> object representing the
+ *         visual run. This object is owned by the <code>pl_line</code> object which
+ *         created it, and will remain valid for as long as the <code>pl_line</code>
+ *         object is valid.
+ *
+ * @see pl_visualRun
+ *
+ * @internal
+ */
+U_INTERNAL const pl_visualRun * U_EXPORT2
+pl_getLineVisualRun(const pl_line *line, le_int32 runIndex);
+
+/**
+ * Get the <code>le_font</code> object which
+ * represents the font of the visual run. This will always
+ * be a non-composite font.
+ *
+ * @param run the <code>pl_visualRun</code> object.
+ *
+ * @return the <code>le_font</code> object which represents the
+ *         font of the visual run.
+ *
+ * @see le_font
+ *
+ * @internal
+ */
+U_INTERNAL const le_font * U_EXPORT2
+pl_getVisualRunFont(const pl_visualRun *run);
+
+/**
+ * Get the direction of the visual run.
+ *
+ * @param run the <code>pl_visualRun</code> object.
+ *
+ * @return the direction of the run. This will be <code>UBIDI_LTR</code> if the
+ *         run is left-to-right and <code>UBIDI_RTL</code> if the line is right-to-left.
+ *
+ * @internal
+ */
+U_INTERNAL UBiDiDirection U_EXPORT2
+pl_getVisualRunDirection(const pl_visualRun *run);
+
+/**
+ * Get the number of glyphs in the visual run.
+ *
+ * @param run the <code>pl_visualRun</code> object.
+ *
+ * @return the number of glyphs.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getVisualRunGlyphCount(const pl_visualRun *run);
+
+/**
+ * Get the glyphs in the visual run. Glyphs with the values <code>0xFFFE</code> and
+ * <code>0xFFFF</code> should be ignored.
+ *
+ * @param run the <code>pl_visualRun</code> object.
+ *
+ * @return the address of the array of glyphs for this visual run. The storage
+ *         is owned by the <code>pl_visualRun</code> object and must not be deleted.
+ *         It will remain valid as long as the <code>pl_visualRun</code> object is valid.
+ *
+ * @internal
+ */
+U_INTERNAL const LEGlyphID * U_EXPORT2
+pl_getVisualRunGlyphs(const pl_visualRun *run);
+
+/**
+ * Get the (x, y) positions of the glyphs in the visual run. To simplify storage
+ * management, the x and y positions are stored in a single array with the x positions
+ * at even offsets in the array and the corresponding y position in the following odd offset.
+ * There is an extra (x, y) pair at the end of the array which represents the advance of
+ * the final glyph in the run.
+ *
+ * @param run the <code>pl_visualRun</code> object.
+ *
+ * @return the address of the array of glyph positions for this visual run. The storage
+ *         is owned by the <code>pl_visualRun</code> object and must not be deleted.
+ *         It will remain valid as long as the <code>pl_visualRun</code> object is valid.
+ *
+ * @internal
+ */
+U_INTERNAL const float * U_EXPORT2
+pl_getVisualRunPositions(const pl_visualRun *run);
+
+/**
+ * Get the glyph-to-character map for this visual run. This maps the indices into
+ * the glyph array to indices into the character array used to create the paragraph.
+ *
+ * @param run the <code>pl_visualRun</code> object.
+ *
+ * @return the address of the character-to-glyph map for this visual run. The storage
+ *         is owned by the <code>pl_visualRun</code> object and must not be deleted.
+ *         It will remain valid as long as the <code>pl_visualRun</code> object is valid.
+ *
+ * @internal
+ */
+U_INTERNAL const le_int32 * U_EXPORT2
+pl_getVisualRunGlyphToCharMap(const pl_visualRun *run);
+
+/**
+ * A convenience method which returns the ascent value for the font
+ * associated with this run.
+ *
+ * @param run the <code>pl_visualRun</code> object.
+ *
+ * @return the ascent value of this run's font.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getVisualRunAscent(const pl_visualRun *run);
+
+/**
+ * A convenience method which returns the descent value for the font
+ * associated with this run.
+ *
+ * @param run the <code>pl_visualRun</code> object.
+ *
+ * @return the descent value of this run's font.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getVisualRunDescent(const pl_visualRun *run);
+
+/**
+ * A convenience method which returns the leading value for the font
+ * associated with this run.
+ *
+ * @param run the <code>pl_visualRun</code> object.
+ *
+ * @return the leading value of this run's font.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getVisualRunLeading(const pl_visualRun *run);
+
+#endif
+#endif
diff --git a/source/layoutex/layout/plruns.h b/source/layoutex/layout/plruns.h
new file mode 100644
index 0000000..99f9fb5
--- /dev/null
+++ b/source/layoutex/layout/plruns.h
@@ -0,0 +1,437 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#ifndef __PLRUNS_H
+#define __PLRUNS_H
+
+#include "unicode/utypes.h"
+#include "unicode/ubidi.h"
+#include "layout/LETypes.h"
+
+#include "layout/loengine.h"
+
+/**
+ * Opaque datatype representing an array of font runs
+ */
+typedef void pl_fontRuns;
+/**
+ * Opaque datatype representing an array of value runs
+ */
+typedef void pl_valueRuns;
+/**
+ * Opaque datatype representing an array of locale runs
+ */
+typedef void pl_localeRuns;
+
+/**
+ * \file 
+ * \brief C API for run arrays.
+ *
+ * This is a technology preview. The API may
+ * change significantly.
+ *
+ */
+
+/**
+ * Construct a <code>pl_fontRuns</code> object from pre-existing arrays of fonts
+ * and limit indices.
+ *
+ * @param fonts is the address of an array of pointers to <code>le_font</code> objects. This
+ *              array, and the <code>le_font</code> objects to which it points must remain
+ *              valid until the <code>pl_fontRuns</code> object is closed.
+ *
+ * @param limits is the address of an array of limit indices. This array must remain valid until
+ *               the <code>pl_fontRuns</code> object is closed.
+ *
+ * @param count is the number of entries in the two arrays.
+ *
+ * @internal
+ */
+U_INTERNAL pl_fontRuns * U_EXPORT2
+pl_openFontRuns(const le_font **fonts,
+                const le_int32 *limits,
+                le_int32 count);
+
+/**
+ * Construct an empty <code>pl_fontRuns</code> object. Clients can add font and limit
+ * indices arrays using the <code>pl_addFontRun</code> routine.
+ *
+ * @param initialCapacity is the initial size of the font and limit indices arrays. If
+ *                        this value is zero, no arrays will be allocated.
+ *
+ * @see pl_addFontRun
+ *
+ * @internal
+ */
+U_INTERNAL pl_fontRuns * U_EXPORT2
+pl_openEmptyFontRuns(le_int32 initialCapacity);
+
+/**
+ * Close the given <code>pl_fontRuns</code> object. Once this
+ * call returns, the object can no longer be referenced.
+ *
+ * @param fontRuns is the <code>pl_fontRuns</code> object.
+ *
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2
+pl_closeFontRuns(pl_fontRuns *fontRuns);
+
+/**
+ * Get the number of font runs.
+ *
+ * @param fontRuns is the <code>pl_fontRuns</code> object.
+ *
+ * @return the number of entries in the limit indices array.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getFontRunCount(const pl_fontRuns *fontRuns);
+
+/**
+ * Reset the number of font runs to zero.
+ *
+ * @param fontRuns is the <code>pl_fontRuns</code> object.
+ *
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2
+pl_resetFontRuns(pl_fontRuns *fontRuns);
+
+/**
+ * Get the limit index for the last font run. This is the
+ * number of characters in the text.
+ *
+ * @param fontRuns is the <code>pl_fontRuns</code> object.
+ *
+ * @return the last limit index.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getFontRunLastLimit(const pl_fontRuns *fontRuns);
+
+/**
+ * Get the limit index for a particular font run.
+ *
+ * @param fontRuns is the <code>pl_fontRuns</code> object.
+ * @param run is the run. This is an index into the limit index array.
+ *
+ * @return the limit index for the run, or -1 if <code>run</code> is out of bounds.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getFontRunLimit(const pl_fontRuns *fontRuns,
+                   le_int32 run);
+
+/**
+ * Get the <code>le_font</code> object assoicated with the given run
+ * of text. Use <code>pl_getFontRunLimit(run)</code> to get the corresponding
+ * limit index.
+ *
+ * @param fontRuns is the <code>pl_fontRuns</code> object.
+ * @param run is the index into the font and limit indices arrays.
+ *
+ * @return the <code>le_font</code> associated with the given text run.
+ *
+ * @internal
+ */
+U_INTERNAL const le_font * U_EXPORT2
+pl_getFontRunFont(const pl_fontRuns *fontRuns,
+                  le_int32 run);
+
+
+/**
+ * Add a new font run to the given <code>pl_fontRuns</code> object.
+ *
+ * If the <code>pl_fontRuns</code> object was not created by calling
+ * <code>pl_openEmptyFontRuns</code>, this method will return a run index of -1.
+ *
+ * @param fontRuns is the <code>pl_fontRuns</code> object.
+ *
+ * @param font is the address of the <code>le_font</code> to add. This object must
+ *             remain valid until the <code>pl_fontRuns</code> object is closed.
+ *
+ * @param limit is the limit index to add
+ *
+ * @return the run index where the font and limit index were stored, or -1 if 
+ *         the run cannot be added.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_addFontRun(pl_fontRuns *fontRuns,
+              const le_font *font,
+              le_int32 limit);
+
+/**
+ * Construct a <code>pl_valueRuns</code> object from pre-existing arrays of values
+ * and limit indices.
+ *
+ * @param values is the address of an array of values. This array must remain valid until
+                 the <code>pl_valueRuns</code> object is closed.
+ *
+ * @param limits is the address of an array of limit indices. This array must remain valid until
+ *               the <code>pl_valueRuns</code> object is closed.
+ *
+ * @param count is the number of entries in the two arrays.
+ *
+ * @internal
+ */
+U_INTERNAL pl_valueRuns * U_EXPORT2
+pl_openValueRuns(const le_int32 *values,
+                 const le_int32 *limits,
+                 le_int32 count);
+
+/**
+ * Construct an empty <code>pl_valueRuns</code> object. Clients can add values and limits
+ * using the <code>pl_addValueRun</code> routine.
+ *
+ * @param initialCapacity is the initial size of the value and limit indices arrays. If
+ *                        this value is zero, no arrays will be allocated.
+ *
+ * @see pl_addValueRun
+ *
+ * @internal
+ */
+U_INTERNAL pl_valueRuns * U_EXPORT2
+pl_openEmptyValueRuns(le_int32 initialCapacity);
+
+/**
+ * Close the given <code>pl_valueRuns</code> object. Once this
+ * call returns, the object can no longer be referenced.
+ *
+ * @param valueRuns is the <code>pl_valueRuns</code> object.
+ *
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2
+pl_closeValueRuns(pl_valueRuns *valueRuns);
+
+/**
+ * Get the number of value runs.
+ *
+ * @param valueRuns is the <code>pl_valueRuns</code> object.
+ *
+ * @return the number of value runs.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getValueRunCount(const pl_valueRuns *valueRuns);
+
+/**
+ * Reset the number of value runs to zero.
+ *
+ * @param valueRuns is the <code>pl_valueRuns</code> object.
+ *
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2
+pl_resetValueRuns(pl_valueRuns *valueRuns);
+
+/**
+ * Get the limit index for the last value run. This is the
+ * number of characters in the text.
+ *
+ * @param valueRuns is the <code>pl_valueRuns</code> object.
+ *
+ * @return the last limit index.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getValueRunLastLimit(const pl_valueRuns *valueRuns);
+
+/**
+ * Get the limit index for a particular value run.
+ *
+ * @param valueRuns is the <code>pl_valueRuns</code> object.
+ * @param run is the run index.
+ *
+ * @return the limit index for the run, or -1 if <code>run</code> is out of bounds.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getValueRunLimit(const pl_valueRuns *valueRuns,
+                     le_int32 run);
+
+/**
+ * Get the value assoicated with the given run * of text. Use
+ * <code>pl_getValueRunLimit(run)</code> to get the corresponding
+ * limit index.
+ *
+ * @param valueRuns is the <code>pl_valueRuns</code> object.
+ * @param run is the run index.
+ *
+ * @return the value associated with the given text run.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getValueRunValue(const pl_valueRuns *valueRuns,
+                    le_int32 run);
+
+
+/**
+ * Add a new font run to the given <code>pl_valueRuns</code> object.
+ *
+ * If the <code>pl_valueRuns</code> object was not created by calling
+ * <code>pl_openEmptyFontRuns</code>, this method will return a run index of -1.
+ *
+ * @param valueRuns is the <code>pl_valueRuns</code> object.
+ *
+ * @param value is the value to add.
+ *
+ * @param limit is the limit index to add
+ *
+ * @return the run index where the font and limit index were stored, or -1 if 
+ *         the run cannot be added.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_addValueRun(pl_valueRuns *valueRuns,
+               le_int32 value,
+               le_int32 limit);
+
+/**
+ * Construct a <code>pl_localeRuns</code> object from pre-existing arrays of fonts
+ * and limit indices.
+ *
+ * @param locales is the address of an array of pointers to locale name strings. This
+ *                array must remain valid until the <code>pl_localeRuns</code> object is destroyed.
+ *
+ * @param limits is the address of an array of limit indices. This array must remain valid until
+ *               the <code>pl_valueRuns</code> object is destroyed.
+ *
+ * @param count is the number of entries in the two arrays.
+ *
+ * @internal
+ */
+U_INTERNAL pl_localeRuns * U_EXPORT2
+pl_openLocaleRuns(const char **locales,
+                  const le_int32 *limits,
+                  le_int32 count);
+
+/**
+ * Construct an empty <code>pl_localeRuns</code> object. Clients can add font and limit
+ * indices arrays using the <code>pl_addFontRun</code> routine.
+ *
+ * @param initialCapacity is the initial size of the font and limit indices arrays. If
+ *                        this value is zero, no arrays will be allocated.
+ *
+ * @see pl_addLocaleRun
+ *
+ * @internal
+ */
+U_INTERNAL pl_localeRuns * U_EXPORT2
+pl_openEmptyLocaleRuns(le_int32 initialCapacity);
+
+/**
+ * Close the given <code>pl_localeRuns</code> object. Once this
+ * call returns, the object can no longer be referenced.
+ *
+ * @param localeRuns is the <code>pl_localeRuns</code> object.
+ *
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2
+pl_closeLocaleRuns(pl_localeRuns *localeRuns);
+
+/**
+ * Get the number of font runs.
+ *
+ * @param localeRuns is the <code>pl_localeRuns</code> object.
+ *
+ * @return the number of entries in the limit indices array.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getLocaleRunCount(const pl_localeRuns *localeRuns);
+
+/**
+ * Reset the number of locale runs to zero.
+ *
+ * @param localeRuns is the <code>pl_localeRuns</code> object.
+ *
+ * @internal
+ */
+U_INTERNAL void U_EXPORT2
+pl_resetLocaleRuns(pl_localeRuns *localeRuns);
+
+/**
+ * Get the limit index for the last font run. This is the
+ * number of characters in the text.
+ *
+ * @param localeRuns is the <code>pl_localeRuns</code> object.
+ *
+ * @return the last limit index.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getLocaleRunLastLimit(const pl_localeRuns *localeRuns);
+
+/**
+ * Get the limit index for a particular font run.
+ *
+ * @param localeRuns is the <code>pl_localeRuns</code> object.
+ * @param run is the run. This is an index into the limit index array.
+ *
+ * @return the limit index for the run, or -1 if <code>run</code> is out of bounds.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_getLocaleRunLimit(const pl_localeRuns *localeRuns,
+                     le_int32 run);
+
+/**
+ * Get the <code>le_font</code> object assoicated with the given run
+ * of text. Use <code>pl_getLocaleRunLimit(run)</code> to get the corresponding
+ * limit index.
+ *
+ * @param localeRuns is the <code>pl_localeRuns</code> object.
+ * @param run is the index into the font and limit indices arrays.
+ *
+ * @return the <code>le_font</code> associated with the given text run.
+ *
+ * @internal
+ */
+U_INTERNAL const char * U_EXPORT2
+pl_getLocaleRunLocale(const pl_localeRuns *localeRuns,
+                      le_int32 run);
+
+
+/**
+ * Add a new run to the given <code>pl_localeRuns</code> object.
+ *
+ * If the <code>pl_localeRuns</code> object was not created by calling
+ * <code>pl_openEmptyLocaleRuns</code>, this method will return a run index of -1.
+ *
+ * @param localeRuns is the <code>pl_localeRuns</code> object.
+ *
+ * @param locale is the name of the locale to add. This name must
+ *               remain valid until the <code>pl_localeRuns</code> object is closed.
+ *
+ * @param limit is the limit index to add
+ *
+ * @return the run index where the font and limit index were stored, or -1 if 
+ *         the run cannot be added.
+ *
+ * @internal
+ */
+U_INTERNAL le_int32 U_EXPORT2
+pl_addLocaleRun(pl_localeRuns *localeRuns,
+                const char *locale,
+                le_int32 limit);
+
+#endif
diff --git a/source/layoutex/layoutex.rc b/source/layoutex/layoutex.rc
new file mode 100644
index 0000000..f04e193
--- /dev/null
+++ b/source/layoutex/layoutex.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 " Layout Extensions 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", "iculx" U_ICU_VERSION_SHORT "d.dll\0"
+#else
+            VALUE "OriginalFilename", "iculx" 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/source/layoutex/layoutex.vcxproj b/source/layoutex/layoutex.vcxproj
new file mode 100644
index 0000000..3d3329b
--- /dev/null
+++ b/source/layoutex/layoutex.vcxproj
@@ -0,0 +1,330 @@
+<?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>{37FC2C7F-1904-4811-8955-2F478830EAD1}</ProjectGuid>

+    <RootNamespace>layoutex</RootNamespace>

+  </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\iculx.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <AdditionalIncludeDirectories>..\..\include;..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;U_LAYOUTEX_IMPLEMENTATION;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <StringPooling>true</StringPooling>

+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x86\Release/layoutex.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>

+    </ResourceCompile>

+    <Link>

+      <OutputFile>..\..\bin\iculx46.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <ProgramDatabaseFile>.\..\..\lib\iculx.pdb</ProgramDatabaseFile>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <BaseAddress>0x4ac80000</BaseAddress>

+      <RandomizedBaseAddress>false</RandomizedBaseAddress>

+      <DataExecutionPrevention>

+      </DataExecutionPrevention>

+      <ImportLibrary>..\..\lib\iculx.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\iculxd.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>..\..\include;..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;U_LAYOUTEX_IMPLEMENTATION;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>

+      <BufferSecurityCheck>true</BufferSecurityCheck>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x86\Debug/layoutex.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>

+    </ResourceCompile>

+    <Link>

+      <OutputFile>..\..\bin\iculx46d.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <ProgramDatabaseFile>.\..\..\lib\iculxd.pdb</ProgramDatabaseFile>

+      <BaseAddress>0x4ac80000</BaseAddress>

+      <RandomizedBaseAddress>false</RandomizedBaseAddress>

+      <DataExecutionPrevention>

+      </DataExecutionPrevention>

+      <ImportLibrary>..\..\lib\iculxd.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\iculx.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <AdditionalIncludeDirectories>..\..\include;..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN64;WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;U_LAYOUTEX_IMPLEMENTATION;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <StringPooling>true</StringPooling>

+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x64\Release/layoutex.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>

+    </ResourceCompile>

+    <Link>

+      <OutputFile>..\..\bin64\iculx46.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <ProgramDatabaseFile>.\..\..\lib64\iculx.pdb</ProgramDatabaseFile>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <BaseAddress>0x4ac80000</BaseAddress>

+      <ImportLibrary>..\..\lib64\iculx.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\iculxd.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>..\..\include;..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN64;WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;U_LAYOUTEX_IMPLEMENTATION;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>

+      <BufferSecurityCheck>true</BufferSecurityCheck>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x64\Debug/layoutex.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>

+    </ResourceCompile>

+    <Link>

+      <OutputFile>..\..\bin64\iculx46d.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <ProgramDatabaseFile>.\..\..\lib64\iculxd.pdb</ProgramDatabaseFile>

+      <BaseAddress>0x4ac80000</BaseAddress>

+      <ImportLibrary>..\..\lib64\iculxd.lib</ImportLibrary>

+      <TargetMachine>MachineX64</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="LXUtilities.cpp" />

+    <ClCompile Include="ParagraphLayout.cpp" />

+    <ClCompile Include="playout.cpp" />

+    <ClCompile Include="plruns.cpp" />

+    <ClCompile Include="RunArrays.cpp" />

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="LXUtilities.h" />

+    <CustomBuild Include="layout\ParagraphLayout.h">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+    </CustomBuild>

+    <CustomBuild Include="layout\playout.h">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+    </CustomBuild>

+    <CustomBuild Include="layout\plruns.h">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+    </CustomBuild>

+    <CustomBuild Include="layout\RunArrays.h">

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\layout

+</Command>

+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\layout\%(Filename)%(Extension);%(Outputs)</Outputs>

+    </CustomBuild>

+  </ItemGroup>

+  <ItemGroup>

+    <ResourceCompile Include="layoutex.rc">

+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\common</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\common</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\common</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\common</AdditionalIncludeDirectories>

+    </ResourceCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="..\common\common.vcxproj">

+      <Project>{73c0a65b-d1f2-4de1-b3a6-15dad2c23f3d}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+    <ProjectReference Include="..\layout\layout.vcxproj">

+      <Project>{c920062a-0647-4553-a3b2-37c58065664b}</Project>

+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>

+    </ProjectReference>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
diff --git a/source/layoutex/layoutex.vcxproj.filters b/source/layoutex/layoutex.vcxproj.filters
new file mode 100644
index 0000000..5407e40
--- /dev/null
+++ b/source/layoutex/layoutex.vcxproj.filters
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{0ae6e2c4-6146-477b-b2b1-e6d7bcae3ad0}</UniqueIdentifier>

+      <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>

+    </Filter>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{725008c9-0168-4d7d-a0b7-4086622f5336}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl</Extensions>

+    </Filter>

+    <Filter Include="Resource Files">

+      <UniqueIdentifier>{09248d30-f024-4dae-a8da-30ccb4ff00d9}</UniqueIdentifier>

+      <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="LXUtilities.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="ParagraphLayout.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="playout.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="plruns.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+    <ClCompile Include="RunArrays.cpp">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <ClInclude Include="LXUtilities.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

+  </ItemGroup>

+  <ItemGroup>

+    <ResourceCompile Include="layoutex.rc">

+      <Filter>Resource Files</Filter>

+    </ResourceCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <CustomBuild Include="layout\ParagraphLayout.h">

+      <Filter>Header Files</Filter>

+    </CustomBuild>

+    <CustomBuild Include="layout\playout.h">

+      <Filter>Header Files</Filter>

+    </CustomBuild>

+    <CustomBuild Include="layout\plruns.h">

+      <Filter>Header Files</Filter>

+    </CustomBuild>

+    <CustomBuild Include="layout\RunArrays.h">

+      <Filter>Header Files</Filter>

+    </CustomBuild>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/source/layoutex/playout.cpp b/source/layoutex/playout.cpp
new file mode 100644
index 0000000..f1c167e
--- /dev/null
+++ b/source/layoutex/playout.cpp
@@ -0,0 +1,330 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
+ *
+ */
+
+/*
+ * paragraphLayout doesn't make much sense without
+ * BreakIterator...
+ */
+#include "layout/LETypes.h"
+#include "layout/loengine.h"
+#include "layout/plruns.h"
+#include "layout/playout.h"
+
+#include "unicode/locid.h"
+
+#include "layout/LayoutEngine.h"
+#include "layout/ParagraphLayout.h"
+
+#if ! UCONFIG_NO_BREAK_ITERATION
+
+U_NAMESPACE_USE
+
+U_CAPI pl_paragraph * U_EXPORT2
+pl_create(const LEUnicode chars[],
+          le_int32 count,
+          const pl_fontRuns *fontRuns,
+          const pl_valueRuns *levelRuns,
+          const pl_valueRuns *scriptRuns,
+          const pl_localeRuns *localeRuns,
+          UBiDiLevel paragraphLevel,
+          le_bool vertical,
+          LEErrorCode *status)
+{
+    ParagraphLayout *pl = new ParagraphLayout(chars, count, (const FontRuns *) fontRuns,
+        (const ValueRuns *) levelRuns, (const ValueRuns *) scriptRuns, (const LocaleRuns *) localeRuns,
+        paragraphLevel, vertical, *status);
+
+    return (pl_paragraph *) pl;
+}
+
+U_CAPI void U_EXPORT2
+pl_close(pl_paragraph *paragraph)
+{
+    ParagraphLayout *pl = (ParagraphLayout *) paragraph;
+
+    delete pl;
+}
+
+U_CAPI le_bool U_EXPORT2
+pl_isComplex(const LEUnicode chars[],
+             le_int32 count)
+{
+    return ParagraphLayout::isComplex(chars, count);
+}
+
+U_CAPI UBiDiLevel U_EXPORT2
+pl_getParagraphLevel(pl_paragraph *paragraph)
+{
+    ParagraphLayout *pl = (ParagraphLayout *) paragraph;
+
+    if (pl == NULL) {
+        return 0;
+    }
+
+    return pl->getParagraphLevel();
+}
+
+U_CAPI UBiDiDirection U_EXPORT2
+pl_getTextDirection(pl_paragraph *paragraph)
+{
+    ParagraphLayout *pl = (ParagraphLayout *) paragraph;
+
+    if (pl == NULL) {
+        return UBIDI_LTR;
+    }
+
+    return pl->getTextDirection();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getAscent(const pl_paragraph *paragraph)
+{
+    ParagraphLayout *pl = (ParagraphLayout *) paragraph;
+
+    if (pl == NULL) {
+        return 0;
+    }
+
+    return pl->getAscent();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getDescent(const pl_paragraph *paragraph)
+{
+    ParagraphLayout *pl = (ParagraphLayout *) paragraph;
+
+    if (pl == NULL) {
+        return 0;
+    }
+
+    return pl->getDescent();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getLeading(const pl_paragraph *paragraph)
+{
+    ParagraphLayout *pl = (ParagraphLayout *) paragraph;
+
+    if (pl == NULL) {
+        return 0;
+    }
+
+    return pl->getLeading();
+}
+
+U_CAPI void U_EXPORT2
+pl_reflow(pl_paragraph *paragraph)
+{
+    ParagraphLayout *pl = (ParagraphLayout *) paragraph;
+
+    if (pl == NULL) {
+        return;
+    }
+
+    return pl->reflow();
+}
+
+U_CAPI pl_line * U_EXPORT2
+pl_nextLine(pl_paragraph *paragraph, float width)
+{
+    ParagraphLayout *pl = (ParagraphLayout *) paragraph;
+
+    if (pl == NULL) {
+        return NULL;
+    }
+
+    return (pl_line *) pl->nextLine(width);
+}
+
+U_CAPI void U_EXPORT2
+pl_closeLine(pl_line *line)
+{
+    ParagraphLayout::Line *ll = (ParagraphLayout::Line *) line;
+
+    delete ll;
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_countLineRuns(const pl_line *line)
+{
+    ParagraphLayout::Line *ll = (ParagraphLayout::Line *) line;
+
+    if (ll == NULL) {
+        return 0;
+    }
+
+    return ll->countRuns();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getLineAscent(const pl_line *line)
+{
+    ParagraphLayout::Line *ll = (ParagraphLayout::Line *) line;
+
+    if (ll == NULL) {
+        return 0;
+    }
+
+    return ll->getAscent();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getLineDescent(const pl_line *line)
+{
+    ParagraphLayout::Line *ll = (ParagraphLayout::Line *) line;
+
+    if (ll == NULL) {
+        return 0;
+    }
+
+    return ll->getDescent();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getLineLeading(const pl_line *line)
+{
+    ParagraphLayout::Line *ll = (ParagraphLayout::Line *) line;
+
+    if (ll == NULL) {
+        return 0;
+    }
+
+    return ll->getLeading();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getLineWidth(const pl_line *line)
+{
+    ParagraphLayout::Line *ll = (ParagraphLayout::Line *) line;
+
+    if (ll == NULL) {
+        return 0;
+    }
+
+    return ll->getWidth();
+}
+
+U_CAPI const pl_visualRun * U_EXPORT2
+pl_getLineVisualRun(const pl_line *line, le_int32 runIndex)
+{
+    ParagraphLayout::Line *ll = (ParagraphLayout::Line *) line;
+
+    if (ll == NULL) {
+        return 0;
+    }
+
+    return (pl_visualRun *) ll->getVisualRun(runIndex);
+}
+
+U_CAPI const le_font * U_EXPORT2
+pl_getVisualRunFont(const pl_visualRun *run)
+{
+    ParagraphLayout::VisualRun *vr = (ParagraphLayout::VisualRun *) run;
+
+    if (vr == NULL) {
+        return NULL;
+    }
+
+    return (const le_font *) vr->getFont();
+}
+
+U_CAPI UBiDiDirection U_EXPORT2
+pl_getVisualRunDirection(const pl_visualRun *run)
+{
+    ParagraphLayout::VisualRun *vr = (ParagraphLayout::VisualRun *) run;
+
+    if (vr == NULL) {
+        return UBIDI_LTR;
+    }
+
+    return vr->getDirection();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getVisualRunGlyphCount(const pl_visualRun *run)
+{
+    ParagraphLayout::VisualRun *vr = (ParagraphLayout::VisualRun *) run;
+
+    if (vr == NULL) {
+        return -1;
+    }
+
+    return vr->getGlyphCount();
+}
+
+U_CAPI const LEGlyphID * U_EXPORT2
+pl_getVisualRunGlyphs(const pl_visualRun *run)
+{
+    ParagraphLayout::VisualRun *vr = (ParagraphLayout::VisualRun *) run;
+
+    if (vr == NULL) {
+        return NULL;
+    }
+
+    return vr->getGlyphs();
+}
+
+U_CAPI const float * U_EXPORT2
+pl_getVisualRunPositions(const pl_visualRun *run)
+{
+    ParagraphLayout::VisualRun *vr = (ParagraphLayout::VisualRun *) run;
+
+    if (vr == NULL) {
+        return NULL;
+    }
+
+    return vr->getPositions();
+}
+
+U_CAPI const le_int32 * U_EXPORT2
+pl_getVisualRunGlyphToCharMap(const pl_visualRun *run)
+{
+    ParagraphLayout::VisualRun *vr = (ParagraphLayout::VisualRun *) run;
+
+    if (vr == NULL) {
+        return NULL;
+    }
+
+    return vr->getGlyphToCharMap();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getVisualRunAscent(const pl_visualRun *run)
+{
+    ParagraphLayout::VisualRun *vr = (ParagraphLayout::VisualRun *) run;
+
+    if (vr == NULL) {
+        return 0;
+    }
+
+    return vr->getAscent();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getVisualRunDescent(const pl_visualRun *run)
+{
+    ParagraphLayout::VisualRun *vr = (ParagraphLayout::VisualRun *) run;
+
+    if (vr == NULL) {
+        return 0;
+    }
+
+    return vr->getDescent();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getVisualRunLeading(const pl_visualRun *run)
+{
+    ParagraphLayout::VisualRun *vr = (ParagraphLayout::VisualRun *) run;
+
+    if (vr == NULL) {
+        return 0;
+    }
+
+    return vr->getLeading();
+}
+
+#endif
diff --git a/source/layoutex/plruns.cpp b/source/layoutex/plruns.cpp
new file mode 100644
index 0000000..40e1d0b
--- /dev/null
+++ b/source/layoutex/plruns.cpp
@@ -0,0 +1,502 @@
+/*
+ *
+ * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
+ *
+ */
+
+#include "layout/LETypes.h"
+#include "layout/loengine.h"
+#include "layout/plruns.h"
+
+#include "unicode/locid.h"
+
+#include "layout/LayoutEngine.h"
+#include "layout/RunArrays.h"
+
+U_NAMESPACE_USE
+
+U_CAPI pl_fontRuns * U_EXPORT2
+pl_openFontRuns(const le_font **fonts,
+                const le_int32 *limits,
+                le_int32 count)
+{
+    return (pl_fontRuns *) new FontRuns((const LEFontInstance **) fonts, limits, count);
+}
+
+U_CAPI pl_fontRuns * U_EXPORT2
+pl_openEmptyFontRuns(le_int32 initialCapacity)
+{
+    return (pl_fontRuns *) new FontRuns(initialCapacity);
+}
+
+U_CAPI void U_EXPORT2
+pl_closeFontRuns(pl_fontRuns *fontRuns)
+{
+    FontRuns *fr = (FontRuns *) fontRuns;
+
+    delete fr;
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getFontRunCount(const pl_fontRuns *fontRuns)
+{
+    const FontRuns *fr = (const FontRuns *) fontRuns;
+
+    if (fr == NULL) {
+        return -1;
+    }
+
+    return fr->getCount();
+}
+
+U_CAPI void U_EXPORT2
+pl_resetFontRuns(pl_fontRuns *fontRuns)
+{
+    FontRuns *fr = (FontRuns *) fontRuns;
+
+    if (fr != NULL) {
+        fr->reset();
+    }
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getFontRunLastLimit(const pl_fontRuns *fontRuns)
+{
+    const FontRuns *fr = (const FontRuns *) fontRuns;
+
+    if (fr == NULL) {
+        return -1;
+    }
+
+    return fr->getLimit();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getFontRunLimit(const pl_fontRuns *fontRuns,
+                   le_int32 run)
+{
+    const FontRuns *fr = (const FontRuns *) fontRuns;
+
+    if (fr == NULL) {
+        return -1;
+    }
+
+    return fr->getLimit(run);
+}
+
+U_CAPI const le_font * U_EXPORT2
+pl_getFontRunFont(const pl_fontRuns *fontRuns,
+                    le_int32 run)
+{
+    const FontRuns *fr = (const FontRuns *) fontRuns;
+
+    if (fr == NULL) {
+        return NULL;
+    }
+
+    return (const le_font *) fr->getFont(run);
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_addFontRun(pl_fontRuns *fontRuns,
+              const le_font *font,
+              le_int32 limit)
+{
+    FontRuns *fr = (FontRuns *) fontRuns;
+
+    if (fr == NULL) {
+        return -1;
+    }
+
+    return fr->add((const LEFontInstance *) font, limit);
+}
+
+U_CAPI pl_valueRuns * U_EXPORT2
+pl_openValueRuns(const le_int32 *values,
+                 const le_int32 *limits,
+                 le_int32 count)
+{
+    return (pl_valueRuns *) new ValueRuns(values, limits, count);
+}
+
+U_CAPI pl_valueRuns * U_EXPORT2
+pl_openEmptyValueRuns(le_int32 initialCapacity)
+{
+    return (pl_valueRuns *) new ValueRuns(initialCapacity);
+}
+
+U_CAPI void U_EXPORT2
+pl_closeValueRuns(pl_valueRuns *valueRuns)
+{
+    ValueRuns *vr = (ValueRuns *) valueRuns;
+
+    delete vr;
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getValueRunCount(const pl_valueRuns *valueRuns)
+{
+    const ValueRuns *vr = (const ValueRuns *) valueRuns;
+
+    if (vr == NULL) {
+        return -1;
+    }
+
+    return vr->getCount();
+}
+
+U_CAPI void U_EXPORT2
+pl_resetValueRuns(pl_valueRuns *valueRuns)
+{
+    ValueRuns *vr = (ValueRuns *) valueRuns;
+
+    if (vr != NULL) {
+        vr->reset();
+    }
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getValueRunLastLimit(const pl_valueRuns *valueRuns)
+{
+    const ValueRuns *vr = (const ValueRuns *) valueRuns;
+
+    if (vr == NULL) {
+        return -1;
+    }
+
+    return vr->getLimit();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getValueRunLimit(const pl_valueRuns *valueRuns,
+                    le_int32 run)
+{
+    const ValueRuns *vr = (const ValueRuns *) valueRuns;
+
+    if (vr == NULL) {
+        return -1;
+    }
+
+    return vr->getLimit(run);
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getValueRunValue(const pl_valueRuns *valueRuns,
+                     le_int32 run)
+{
+    const ValueRuns *vr = (const ValueRuns *) valueRuns;
+
+    if (vr == NULL) {
+        return -1;
+    }
+
+    return vr->getValue(run);
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_addValueRun(pl_valueRuns *valueRuns,
+               le_int32 value,
+               le_int32 limit)
+{
+    ValueRuns *vr = (ValueRuns *) valueRuns;
+
+    if (vr == NULL) {
+        return -1;
+    }
+
+    return vr->add(value, limit);
+}
+
+U_NAMESPACE_BEGIN
+class ULocRuns : public LocaleRuns
+{
+public:
+    /**
+     * Construct a <code>LocaleRuns</code> object from pre-existing arrays of locales
+     * and limit indices.
+     *
+     * @param locales is the address of an array of locale name strings. This array,
+     *                and the <code>Locale</code> objects to which it points, must remain valid until
+     *                the <code>LocaleRuns</code> object is destroyed.
+     *
+     * @param limits is the address of an array of limit indices. This array must remain valid until the
+     *               <code>LocaleRuns</code> object is destroyed.
+     *
+     * @param count is the number of entries in the two arrays.
+     *
+     * @draft ICU 3.8
+     */
+    ULocRuns(const char **locales, const le_int32 *limits, le_int32 count);
+
+    /**
+     * Construct an empty <code>LoIDRuns</code> object. Clients can add locale and limit
+     * indices arrays using the <code>add</code> method.
+     *
+     * @param initialCapacity is the initial size of the locale and limit indices arrays. If
+     *        this value is zero, no arrays will be allocated.
+     *
+     * @see add
+     *
+     * @draft ICU 3.8
+     */
+    ULocRuns(le_int32 initialCapacity);
+
+    /**
+     * The destructor; virtual so that subclass destructors are invoked as well.
+     *
+     * @draft ICU 3.8
+     */
+    virtual ~ULocRuns();
+
+    /**
+     * Get the name of the locale assoicated with the given run
+     * of text. Use <code>RunArray::getLimit(run)</code> to get the corresponding
+     * limit index.
+     *
+     * @param run is the index into the font and limit indices arrays.
+     *
+     * @return the locale name associated with the given text run.
+     *
+     * @see RunArray::getLimit
+     *
+     * @draft ICU 3.8
+     */
+    const char *getLocaleName(le_int32 run) const;
+
+    /**
+     * Add a <code>Locale</code> and limit index pair to the data arrays and return
+     * the run index where the data was stored. This  method calls
+     * <code>RunArray::add(limit)</code> which will create or grow the arrays as needed.
+     *
+     * If the <code>ULocRuns</code> object was created with a client-supplied
+     * locale and limit indices arrays, this method will return a run index of -1.
+     *
+     * Subclasses should not override this method. Rather they should provide a new <code>add</code>
+     * method which takes a locale name and a limit index along with whatever other data they implement.
+     * The new <code>add</code> method should first call this method to grow the font and limit indices
+     * arrays, and use the returned run index to store data their own arrays.
+     *
+     * @param locale is the name of the locale to add. This object must remain valid
+     *               until the <code>ULocRuns</code> object is destroyed.
+     *
+     * @param limit is the limit index to add
+     *
+     * @return the run index where the locale and limit index were stored, or -1 if the data cannot be stored.
+     *
+     * @draft ICU 3.8
+     */
+    le_int32 add(const char *locale, le_int32 limit);
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for this class.
+     *
+     * @draft ICU 3.8
+     */
+    static inline UClassID getStaticClassID();
+
+    /**
+     * ICU "poor man's RTTI", returns a UClassID for the actual class.
+     *
+     * @draft ICU 3.8
+     */
+    virtual inline UClassID getDynamicClassID() const;
+
+protected:
+    virtual void init(le_int32 capacity);
+    virtual void grow(le_int32 capacity);
+
+private:
+
+    inline ULocRuns();
+    inline ULocRuns(const ULocRuns &other);
+    inline ULocRuns &operator=(const ULocRuns & /*other*/) { return *this; };
+    const char **fLocaleNames;
+    Locale **fLocalesCopy;
+};
+
+inline ULocRuns::ULocRuns()
+    : LocaleRuns(0), fLocaleNames(NULL)
+{
+    // nothing else to do...
+}
+
+inline ULocRuns::ULocRuns(const ULocRuns & /*other*/)
+    : LocaleRuns(0), fLocaleNames(NULL)
+{
+    // nothing else to do...
+}
+
+static const Locale **getLocales(const char **localeNames, le_int32 count)
+{
+    Locale **locales = LE_NEW_ARRAY(Locale *, count);
+
+    for (int i = 0; i < count; i += 1) {
+        locales[i] = new Locale(Locale::createFromName(localeNames[i]));
+    }
+
+    return (const Locale **) locales;
+}
+
+ULocRuns::ULocRuns(const char **locales, const le_int32 *limits, le_int32 count)
+    : LocaleRuns(getLocales(locales, count), limits, count), fLocaleNames(locales)
+{
+    // nothing else to do...
+}
+
+ULocRuns::ULocRuns(le_int32 initialCapacity)
+    : LocaleRuns(initialCapacity), fLocaleNames(NULL)
+{
+    if(initialCapacity > 0) {
+        fLocaleNames = LE_NEW_ARRAY(const char *, initialCapacity);
+    }
+}
+
+ULocRuns::~ULocRuns()
+{
+    le_int32 count = getCount();
+
+    for(int i = 0; i < count; i += 1) {
+        delete fLocales[i];
+    }
+
+    if (fClientArrays) {
+        LE_DELETE_ARRAY(fLocales);
+        fLocales = NULL;
+    } else {
+        LE_DELETE_ARRAY(fLocaleNames);
+        fLocaleNames = NULL;
+    }
+}
+
+void ULocRuns::init(le_int32 capacity)
+{
+    LocaleRuns::init(capacity);
+    fLocaleNames = LE_NEW_ARRAY(const char *, capacity);
+}
+
+void ULocRuns::grow(le_int32 capacity)
+{
+    LocaleRuns::grow(capacity);
+    fLocaleNames = (const char **) LE_GROW_ARRAY(fLocaleNames, capacity);
+}
+
+le_int32 ULocRuns::add(const char *locale, le_int32 limit)
+{
+    Locale *loc = new Locale(Locale::createFromName(locale));
+    le_int32 index = LocaleRuns::add(loc, limit);
+
+    if (index >= 0) {
+        char **localeNames = (char **) fLocaleNames;
+
+        localeNames[index] = (char *) locale;
+    }
+
+    return index;
+}
+
+const char *ULocRuns::getLocaleName(le_int32 run) const
+{
+    if (run < 0 || run >= getCount()) {
+        return NULL;
+    }
+
+    return fLocaleNames[run];
+}
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ULocRuns)
+U_NAMESPACE_END
+
+U_CAPI pl_localeRuns * U_EXPORT2
+pl_openLocaleRuns(const char **locales,
+                  const le_int32 *limits,
+                  le_int32 count)
+{
+    return (pl_localeRuns *) new ULocRuns(locales, limits, count);
+}
+
+U_CAPI pl_localeRuns * U_EXPORT2
+pl_openEmptyLocaleRuns(le_int32 initialCapacity)
+{
+    return (pl_localeRuns *) new ULocRuns(initialCapacity);
+}
+
+U_CAPI void U_EXPORT2
+pl_closeLocaleRuns(pl_localeRuns *localeRuns)
+{
+    ULocRuns *lr = (ULocRuns *) localeRuns;
+
+    delete lr;
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getLocaleRunCount(const pl_localeRuns *localeRuns)
+{
+    const ULocRuns *lr = (const ULocRuns *) localeRuns;
+
+    if (lr == NULL) {
+        return -1;
+    }
+
+    return lr->getCount();
+}
+
+U_CAPI void U_EXPORT2
+pl_resetLocaleRuns(pl_localeRuns *localeRuns)
+{
+    ULocRuns *lr = (ULocRuns *) localeRuns;
+
+    if (lr != NULL) {
+        lr->reset();
+    }
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getLocaleRunLastLimit(const pl_localeRuns *localeRuns)
+{
+    const ULocRuns *lr = (const ULocRuns *) localeRuns;
+
+    if (lr == NULL) {
+        return -1;
+    }
+
+    return lr->getLimit();
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_getLocaleRunLimit(const pl_localeRuns *localeRuns,
+                     le_int32 run)
+{
+    const ULocRuns *lr = (const ULocRuns *) localeRuns;
+
+    if (lr == NULL) {
+        return -1;
+    }
+
+    return lr->getLimit(run);
+}
+
+U_CAPI const char * U_EXPORT2
+pl_getLocaleRunLocale(const pl_localeRuns *localeRuns,
+                      le_int32 run)
+{
+    const ULocRuns *lr = (const ULocRuns *) localeRuns;
+
+    if (lr == NULL) {
+        return NULL;
+    }
+
+    return lr->getLocaleName(run);
+}
+
+U_CAPI le_int32 U_EXPORT2
+pl_addLocaleRun(pl_localeRuns *localeRuns,
+                const char *locale,
+                le_int32 limit)
+{
+    ULocRuns *lr = (ULocRuns *) localeRuns;
+
+    if (lr == NULL) {
+        return -1;
+    }
+
+    return lr->add(locale, limit);
+}
diff --git a/source/mkinstalldirs b/source/mkinstalldirs
new file mode 100644
index 0000000..f579788
--- /dev/null
+++ b/source/mkinstalldirs
@@ -0,0 +1,43 @@
+#! /bin/sh
+#  ********************************************************************
+#  * COPYRIGHT:
+#  * Copyright (c) 2002-2004, International Business Machines Corporation and
+#  * others. All Rights Reserved.
+#  ********************************************************************
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+errstatus=0
+
+for file
+do
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d
+   do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp"
+
+        mkdir "$pathcomp" || lasterr=$?
+
+        if test ! -d "$pathcomp"; then
+  	  errstatus=$lasterr
+        fi
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/source/runConfigureICU b/source/runConfigureICU
new file mode 100755
index 0000000..033186d
--- /dev/null
+++ b/source/runConfigureICU
@@ -0,0 +1,394 @@
+#!/bin/sh
+# Copyright (c) 1999-2010, International Business Machines Corporation and
+# others. All Rights Reserved.
+
+# runConfigureICU: This script will run the "configure" script for the appropriate platform
+# Only supported platforms are recognized
+
+me=`basename $0`
+OPTS=
+
+usage()
+{
+    ec=0$1
+    if test $ec -eq 0
+    then
+        uletter=U
+    else
+        uletter=u
+    fi
+
+    echo "${uletter}sage: $me [ -h, --help ]  [ --enable-debug | --disable-release ] platform [ configurearg ... ]"
+    if test $ec -eq 0
+    then
+        cat <<EOE
+
+Options: -h, --help         Print this message and exit
+         --enable-debug     Enable support for debugging
+         --disable-release  Disable presetting optimization flags
+
+The following names can be supplied as the argument for platform:
+
+    AIX                 Use the IBM Visual Age xlc_r/xlC_r compilers on AIX
+    AIX/GCC             Use the GNU gcc/g++ compilers on AIX
+    Cygwin              Use the GNU gcc/g++ compilers on Cygwin
+    Cygwin/MSVC         Use the Microsoft Visual C++ compiler on Cygwin
+    Cygwin/MSVC2005     Use the Microsoft Visual C++ 2005 compiler on Cygwin
+    Cygwin/ICL          Use the Intel C++ compiler on Cygwin
+    FreeBSD             Use the GNU gcc/g++ compilers on Free BSD
+    HP-UX/ACC           Use the HP ANSI C/Advanced C++ compilers on HP-UX 11
+    IBMi                Use the iCC compilers on IBM i, i5/OS, OS/400
+    Linux               Use the GNU gcc/g++ compilers on Linux
+    Linux/ECC           Use the Intel ECC compiler on Linux
+    Linux/ICC           Use the Intel ICC compiler on Linux
+    Linux/VA            Use the IBM Visual Age compiler on Power PC Linux
+    MacOSX              Use the GNU gcc/g++ compilers on MacOS X (Darwin)
+    QNX                 Use the QNX QCC compiler on QNX/Neutrino
+    Solaris             Use the Sun cc/CC compilers on Solaris
+    Solaris/GCC         Use the GNU gcc/g++ compilers on Solaris
+    SolarisX86          Use the Sun cc/CC compilers on Solaris x86
+    TRU64V5.1/CXX       Use the Compaq cxx compiler on Tru64 (OSF)
+    zOS                 Use the IBM cxx compiler on z/OS (os/390)
+    zOSV1R2             Use the IBM cxx compiler for z/OS 1.2
+EOE
+    fi
+
+    exit $ec
+}
+
+# Parse arguments
+
+platform=
+debug=0
+release=1
+
+while test $# -ne 0
+do
+    case "$1" in
+    -h|--help)
+        usage 0
+        ;;
+    --enable-debug)
+        debug=1
+        OPTS="$OPTS --enable-debug"
+        ;;
+    --disable-release)
+        release=0
+        OPTS="$OPTS --disable-release"
+        ;;
+    *)
+        platform="$1"
+        shift
+        break
+        ;;
+    esac
+    shift
+done
+
+if test x$platform = x
+then
+   usage 1
+fi
+
+# Go.
+
+rm -f config.cache
+rm -f config.log
+rm -f config.status
+
+DEBUG_CFLAGS='-g'
+DEBUG_CXXFLAGS='-g'
+
+if test x$configure = x
+then
+    if test -f ./configure
+    then
+        configuredir=.
+    else
+        configuredir=`echo $0 | sed 's,[^/]*$,,'`
+        if test x$configuredir = x$0
+        then
+            configuredir=.
+        fi
+    fi
+
+    if test x$configuredir = x
+    then
+        configuredir=.
+    fi
+
+    configure=$configuredir/configure
+fi
+
+case $platform in
+    AIX)
+        THE_OS=AIX
+        THE_COMP="xlC_r"
+        CC=`which xlc_r`; export CC
+        if [ ! -x $CC ]; then
+           echo "ERROR: xlc_r was not found, please check the PATH to make sure it is correct."; exit 1
+        fi
+        CXX=`which xlC_r`; export CXX
+        if [ ! -x $CXX ]; then
+           echo "ERROR: xlC_r was not found, please check the PATH to make sure it is correct."; exit 1
+        fi
+        RELEASE_CFLAGS="-O2 -qmaxmem=-1"
+        RELEASE_CXXFLAGS="-O2 -qmaxmem=-1"
+        ;;
+    AIX/GCC)
+        THE_OS=AIX
+        THE_COMP="the GNU C++"
+        CC=gcc; export CC
+        CXX=g++; export CXX
+        DEBUG_CFLAGS='-g -O0'
+        DEBUG_CXFLAGS='-g -O0'
+        ;;
+    Solaris)
+        THE_OS=SOLARIS
+        THE_COMP="Sun's CC"
+        CC=`which cc`; export CC
+        CXX=`which CC`; export CXX
+        RELEASE_CFLAGS="-xO4 -xlibmil"
+        RELEASE_CXXFLAGS="-O4 -xlibmil"
+        ;;
+    Solaris/GCC)
+        THE_OS=SOLARIS
+        THE_COMP="the GNU C++"
+        CC=gcc; export CC
+        CXX=g++; export CXX
+        RELEASE_CFLAGS=-O1
+        RELEASE_CXXFLAGS=-O3
+        ;;
+    SolarisX86)
+        THE_OS="SOLARIS X86"
+        THE_COMP="Sun's CC"
+        CC=`which cc`; export CC
+        CXX=`which CC`; export CXX
+        LDFLAGS="-L -lCrun";export LDFLAGS
+        RELEASE_CFLAGS=-xO3
+        RELEASE_CXXFLAGS=-O3
+        ;;
+    HP-UX/ACC)
+        THE_OS="HP-UX 11"
+        THE_COMP="aCC"
+        CC=cc; export CC
+        CXX=aCC; export CXX
+        RELEASE_CFLAGS='+O2 +Ofltacc'
+        RELEASE_CXXFLAGS='+O2 +Ofltacc'
+        ;;
+    IBMi)
+        THE_OS="IBM i"
+        THE_COMP="the iCC C++"
+        CC=/usr/bin/icc; export CC
+        CXX=/usr/bin/icc; export CXX
+        CPP="$CC -c -qpponly"; export CPP
+        MAKE=/usr/bin/gmake; export MAKE
+        RELEASE_CFLAGS='-O4'
+        RELEASE_CXXFLAGS='-O4'
+        ;;
+    Linux/ECC)
+        THE_OS="Linux"
+        THE_COMP="Intel ECC 7.1"
+        CC=ecc; export CC
+        CXX=ecpc; export CXX
+        RELEASE_CFLAGS='-O2'
+        RELEASE_CXXFLAGS='-O2'
+        ;;
+    Linux/ICC)
+        THE_OS="Linux"
+        CC=`which icc`; export CC
+        CXX=`which icpc`; export CXX
+	ICC_VER=`${CC} -v 2>&1`
+        RELEASE_CFLAGS='-O'
+        RELEASE_CXXFLAGS='-O'
+        export CFLAGS="-fp-model precise"
+        export CXXFLAGS="-fp-model precise"
+	if [ "${ICC_VER}" = "Version 9.0 " ]; then
+		RELEASE_CFLAGS=''
+		RELEASE_CXXFLAGS=''
+		export CFLAGS="${CFLAGS} -O0"
+		export CXXFLAGS="${CXXFLAGS} -O0"
+		echo "ICC 9.0 does not work with optimization- disabling optimizations"
+	fi
+        THE_COMP="Intel ${ICC_VER}"
+        ;;
+    Linux/VA)
+        THE_OS="Linux"
+        THE_COMP="IBM Visual Age C++ Compiler"
+        CC=`which xlc_r`; export CC
+        CXX=`which xlC_r`; export CXX
+        RELEASE_CFLAGS="-O2 -qmaxmem=-1"
+        RELEASE_CXXFLAGS="-O2 -qmaxmem=-1"
+        ;;
+    Linux*)
+        THE_OS="Linux"
+        THE_COMP="the GNU C++"
+        CC=gcc; export CC
+        CXX=g++; export CXX
+        DEBUG_CFLAGS='-g -O0'
+        DEBUG_CXFLAGS='-g -O0'
+        ;;
+    Cygwin)
+        THE_OS="Cygwin"
+        THE_COMP="the GNU C++"
+        RELEASE_CFLAGS='-O3'
+        RELEASE_CXXFLAGS='-O3'
+        ;;
+    Cygwin/MSVC)
+        THE_OS="Windows with Cygwin"
+        THE_COMP="Microsoft Visual C++"
+        CC=cl; export CC
+        CXX=cl; export CXX
+        RELEASE_CFLAGS='/Gy /MD'
+        RELEASE_CXXFLAGS='/Gy /MD'
+        DEBUG_CFLAGS='/Zi /MDd'
+        DEBUG_CXXFLAGS='/Zi /MDd'
+        DEBUG_LDFLAGS='/DEBUG'
+        ;;
+    Cygwin/MSVC2005)
+        THE_OS="Windows with Cygwin"
+        THE_COMP="Microsoft Visual C++ 2005"
+        CC=cl; export CC
+        CXX=cl; export CXX
+        RELEASE_CFLAGS='/Gy /MD'
+        RELEASE_CXXFLAGS='/Gy /MD'
+        DEBUG_CFLAGS='/Zi /MDd'
+        DEBUG_CXXFLAGS='/Zi /MDd'
+        DEBUG_LDFLAGS='/DEBUG'
+        ;;
+    Cygwin/ICL)
+        THE_OS="Windows with Cygwin"
+        THE_COMP="Intel C++"
+        CC=icl; export CC
+        CXX=icl; export CXX
+        # The Intel compiler has optimization bugs. So we disable optimization.
+        RELEASE_CFLAGS='/Od'
+        RELEASE_CXXFLAGS='/Od'
+        DEBUG_CFLAGS='/Zi'
+        DEBUG_CXXFLAGS='/Zi'
+        DEBUG_LDFLAGS='/DEBUG'
+        ;;
+    MacOSX)
+        THE_OS="MacOS X (Darwin)"
+        THE_COMP="the GNU C++"
+        RELEASE_CFLAGS='-O2'
+        RELEASE_CXXFLAGS='-O2'
+        DEBUG_CFLAGS='-g -O0'
+        DEBUG_CXXFLAGS='-g -O0'
+        ;;
+    *BSD)
+        THE_OS="BSD"
+        THE_COMP="the GNU C++"
+        CC=gcc; export CC
+        CXX=g++; export CXX
+        DEBUG_CFLAGS='-g -O0'
+        DEBUG_CXFLAGS='-g -O0'
+        ;;
+    TRU64V5.1/CXX)
+        THE_OS="OSF1"
+        THE_COMP="Compaq cxx"
+        CC=cc; export CC
+        CXX=cxx; export CXX
+        ;;
+    QNX)
+        THE_OS="QNX"
+        THE_COMP="QNX cc"
+        CC=qcc; export CC
+        CXX=QCC; export CXX
+        ;;
+    zOS)
+        THE_OS="z/OS (OS/390)"
+        THE_COMP="z/OS C/C++"
+        CC=cc; export CC
+        CXX=cxx; export CXX
+        RELEASE_CFLAGS="-2 -Wc,'inline(auto,noreport,500,4000)'"
+        RELEASE_CXXFLAGS="-2 -Wc,'inline(auto,noreport,500,4000)'"
+        ;;
+    zOSV1R2)
+        THE_OS="z/OS 1.2"
+        THE_COMP="z/OS 1.2 C/C++"
+        CC=cc; export CC
+        CXX=cxx; export CXX
+        export COMPILE_LINK_ENVVAR='_CXX_CICC_VER}=0x41020000 _C89_CVERSION=0x41020000 _CC_CVERSION=0x41020000 _CXX_PVERSION=0x41020000 _C89_PVERSION=0x41020000 _CC_PVERSION=0x41020000'
+        export _CXX_CVERSION=0x41020000 _C89_CVERSION=0x41020000 _CC_CVERSION=0x41020000 _CXX_PVERSION=0x41020000 _C89_PVERSION=0x41020000 _CC_PVERSION=0x41020000
+        export LDFLAGS="-Wl,'compat=pm3'"
+        export CFLAGS="-Wc,'target(zOSV1R2)'"
+        export CXXFLAGS="-Wc,'target(zOSV1R2)'"
+        RELEASE_CFLAGS="-2 -Wc,'inline(auto,noreport,500,4000)'"
+        RELEASE_CXXFLAGS="-2 -Wc,'inline(auto,noreport,500,4000)'"
+        ;;
+    *)
+        >&2 echo "$me: unrecognized platform \"$platform\" (use --help for help)"
+        exit 1;;
+esac
+
+
+# Tweak flags
+
+if test $release -eq 1
+then
+    if test "$RELEASE_CFLAGS" = ""
+    then
+        case $CC in
+            gcc|*/gcc|*-gcc-*|*/*-gcc-*)
+                RELEASE_CFLAGS=-O3
+                ;;
+        esac
+    fi
+    if test "$RELEASE_CFLAGS" != ""
+    then
+        CFLAGS="$CFLAGS $RELEASE_CFLAGS"
+    fi
+    if test "$RELEASE_CXXFLAGS" = ""
+    then
+        case $CXX in
+            g++|*/g++|*-g++-*|*/*-g++-*)
+                RELEASE_CXXFLAGS=-O3
+                ;;
+        esac
+    fi
+    if test "$RELEASE_CXXFLAGS" != ""
+    then
+        CXXFLAGS="$CXXFLAGS $RELEASE_CXXFLAGS"
+    fi
+    if test "$RELEASE_LDFLAGS" != ""
+    then
+        LDFLAGS="$LDFLAGS $RELEASE_LDFLAGS"
+    fi
+fi
+
+if test $debug -eq 1
+then
+    if test "$DEBUG_CFLAGS" != ""
+    then
+        CFLAGS="$CFLAGS $DEBUG_CFLAGS"
+    fi
+    if test "$DEBUG_CXXFLAGS" != ""
+    then
+        CXXFLAGS="$CXXFLAGS $DEBUG_CXXFLAGS"
+    fi
+    if test "$DEBUG_LDFLAGS" != ""
+    then
+        LDFLAGS="$LDFLAGS $DEBUG_LDFLAGS"
+    fi
+fi
+
+export CFLAGS
+export CXXFLAGS
+export LDFLAGS
+
+# Run configure
+
+echo "export CPP=$CPP CC=$CC CXX=$CXX CPPFLAGS=$CPPFLAGS CFLAGS=$CFLAGS CXXFLAGS=$CXXFLAGS LDFLAGS=$LDFLAGS MAKE=$MAKE"
+echo "Running ./configure $OPTS $@ for $THE_OS using $THE_COMP compiler"
+echo
+if $configure $OPTS $@
+then
+	echo
+	echo If the result of the above commands looks okay to you, go to the directory
+	echo source in the ICU distribution to build ICU. Please remember that ICU needs
+	echo GNU make to build properly...
+else
+	echo $0: ./configure failed
+	exit 1
+fi
diff --git a/source/stubdata/Makefile.in b/source/stubdata/Makefile.in
new file mode 100644
index 0000000..168fe2c
--- /dev/null
+++ b/source/stubdata/Makefile.in
@@ -0,0 +1,149 @@
+#******************************************************************************
+#
+#   Copyright (C) 1999-2007, International Business Machines
+#   Corporation and others.  All Rights Reserved.
+#
+#******************************************************************************
+## Makefile.in for ICU stubdata
+## 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 = stubdata
+
+## Extra files to remove for 'make clean'
+CLEANFILES = *~ $(DEPS) $(IMPORT_LIB) $(MIDDLE_IMPORT_LIB) $(FINAL_IMPORT_LIB)
+
+## Target information
+
+TARGET_STUBNAME=$(DATA_STUBNAME)
+
+ifneq ($(ENABLE_STATIC),)
+TARGET = $(STUBDATA_LIBDIR)$(LIBSICU)$(TARGET_STUBNAME)$(ICULIBSUFFIX).$(A)
+endif
+
+
+ifneq ($(ENABLE_SHARED),)
+SO_TARGET = $(STUBDATA_LIBDIR)$(LIBICU)$(TARGET_STUBNAME)$(ICULIBSUFFIX)$(STUB_SUFFIX).$(SO)
+ALL_SO_TARGETS = $(FINAL_SO_TARGET) $(MIDDLE_SO_TARGET) $(SO_TARGET) $(BATCH_STUB_TARGET) $(SHARED_OBJECT)
+endif
+
+
+ALL_TARGETS = $(TARGET) $(ALL_SO_TARGETS)
+
+DYNAMICCPPFLAGS = $(SHAREDLIBCPPFLAGS)
+DYNAMICCFLAGS = $(SHAREDLIBCFLAGS)
+DYNAMICCXXFLAGS = $(SHAREDLIBCXXFLAGS)
+
+ifneq ($(top_builddir),$(top_srcdir))
+CPPFLAGS += -I$(top_builddir)/common
+endif
+CPPFLAGS += -I$(top_srcdir)/common $(LIBCPPFLAGS)
+LDFLAGS += $(LDFLAGSICUDT)
+
+OBJECTS = stubdata.o
+
+## Header files to install
+HEADERS = 
+
+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 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-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
+
+dist-local:
+
+clean-local:
+	test -z "$(CLEANFILES)" || $(RMV) $(CLEANFILES)
+	$(RMV) $(OBJECTS) $(STATIC_OBJECTS) $(ALL_TARGETS)
+
+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
+
+../common/unicode/platform.h: $(srcdir)/../common/unicode/platform.h.in $(top_builddir)/config.status
+	cd $(top_builddir) \
+	 && CONFIG_FILES=common/unicode/platform.h CONFIG_HEADERS= $(SHELL) ./config.status
+
+ifneq ($(ENABLE_STATIC),)
+$(TARGET): $(STATIC_OBJECTS)
+	$(AR) $(ARFLAGS) $(AR_OUTOPT)$@ $^
+	$(RANLIB) $@
+endif
+
+ifneq ($(ENABLE_SHARED),)
+$(SHARED_OBJECT): $(OBJECTS)
+	$(SHLIB.c) $(LD_SONAME) $(OUTOPT)$@ $^ $(LIBS)
+
+ifeq ($(OS390BATCH),1)
+$(BATCH_STUB_TARGET): $(OBJECTS)
+	$(SHLIB.c) $(LD_SONAME) $(OUTOPT)$@ $^ $(LIBS)
+endif   # OS390BATCH
+endif   # ENABLE_SHARED
+
+ifeq (,$(MAKECMDGOALS))
+-include $(DEPS)
+else
+ifneq ($(patsubst %clean,,$(MAKECMDGOALS)),)
+-include $(DEPS)
+endif
+endif
+
diff --git a/source/stubdata/stubdata.c b/source/stubdata/stubdata.c
new file mode 100644
index 0000000..69a5876
--- /dev/null
+++ b/source/stubdata/stubdata.c
@@ -0,0 +1,74 @@
+/******************************************************************************
+*
+*   Copyright (C) 2001, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  stubdata.c
+*
+*   Define initialized data that will build into a valid, but empty
+*   ICU data library.  Used to bootstrap the ICU build, which has these
+*   dependencies:
+*       ICU Common library depends on ICU data
+*       ICU data requires data building tools.
+*       ICU data building tools require the ICU common library.
+*
+*   The stub data library (for which this file is the source) is sufficient
+*   for running the data building tools.
+*
+*/
+#include "unicode/utypes.h"
+#include "unicode/udata.h"
+#include "unicode/uversion.h"
+
+
+typedef struct {
+    uint16_t headerSize;
+    uint8_t magic1, magic2;
+    UDataInfo info;
+    char padding[8];
+    uint32_t count, reserved;
+    /*
+    const struct {
+    const char *const name; 
+    const void *const data;
+    } toc[1];
+    */
+   int   fakeNameAndData[4];       /* TODO:  Change this header type from */
+                                   /*        pointerTOC to OffsetTOC.     */
+} ICU_Data_Header;
+
+U_EXPORT const ICU_Data_Header U_ICUDATA_ENTRY_POINT = {
+    32,          /* headerSize */
+    0xda,        /* magic1,  (see struct MappedData in udata.c)  */
+    0x27,        /* magic2     */
+    {            /*UDataInfo   */
+        sizeof(UDataInfo),      /* size        */
+        0,                      /* reserved    */
+
+#if U_IS_BIG_ENDIAN
+        1,
+#else
+        0,
+#endif
+
+        U_CHARSET_FAMILY,
+        sizeof(UChar),   
+        0,               /* reserved      */
+        {                /* data format identifier */
+           0x54, 0x6f, 0x43, 0x50}, /* "ToCP" */
+           {1, 0, 0, 0},   /* format version major, minor, milli, micro */
+           {0, 0, 0, 0}    /* dataVersion   */
+    },
+    {0,0,0,0,0,0,0,0},  /* Padding[8]   */ 
+    0,                  /* count        */
+    0,                  /* Reserved     */
+    {                   /*  TOC structure */
+/*        {    */
+          0 , 0 , 0, 0  /* name and data entries.  Count says there are none,  */
+                        /*  but put one in just in case.                       */
+/*        }  */
+    }
+};
+
+
diff --git a/source/stubdata/stubdata.vcxproj b/source/stubdata/stubdata.vcxproj
new file mode 100644
index 0000000..4b3865e
--- /dev/null
+++ b/source/stubdata/stubdata.vcxproj
@@ -0,0 +1,280 @@
+<?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>{203EC78A-0531-43F0-A636-285439BDE025}</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'">.\x86\Release\</OutDir>

+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\x86\Release\</IntDir>

+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>

+    <GenerateManifest Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</GenerateManifest>

+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\x86\Debug\</OutDir>

+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\x86\Debug\</IntDir>

+    <GenerateManifest Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</GenerateManifest>

+    <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>

+    <GenerateManifest Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</GenerateManifest>

+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\x64\Debug\</OutDir>

+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\x64\Debug\</IntDir>

+    <GenerateManifest Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</GenerateManifest>

+  </PropertyGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <Midl>

+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <MkTypLibCompatible>true</MkTypLibCompatible>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <TargetEnvironment>Win32</TargetEnvironment>

+      <TypeLibraryName>.\x86\Release\icudt.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <AdditionalIncludeDirectories>..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <StringPooling>true</StringPooling>

+      <ExceptionHandling>

+      </ExceptionHandling>

+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x86\Release\stubdata.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>

+    </ResourceCompile>

+    <PreLinkEvent>

+      <Command>echo "File with stubdata build time, used as a dependency to trigger fresh data build, since stubdata dll will overwrite the real one." &gt; "$(ProjectDir)stubdatabuilt.txt"</Command>

+    </PreLinkEvent>

+    <Link>

+      <OutputFile>..\..\bin\icudt46.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>

+      <ProgramDatabaseFile>.\x86\Release\icudt.pdb</ProgramDatabaseFile>

+      <NoEntryPoint>true</NoEntryPoint>

+      <SetChecksum>true</SetChecksum>

+      <BaseAddress>0x4ad00000</BaseAddress>

+      <RandomizedBaseAddress>false</RandomizedBaseAddress>

+      <DataExecutionPrevention>

+      </DataExecutionPrevention>

+      <TurnOffAssemblyGeneration>true</TurnOffAssemblyGeneration>

+      <ImportLibrary>..\..\lib\icudt.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>.\x86\Debug/icudt.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>

+      <BufferSecurityCheck>true</BufferSecurityCheck>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x86\Debug/stubdata.pch</PrecompiledHeaderOutputFile>

+      <AssemblerListingLocation>.\x86\Debug/</AssemblerListingLocation>

+      <ObjectFileName>.\x86\Debug/</ObjectFileName>

+      <ProgramDataBaseFileName>.\x86\Debug/</ProgramDataBaseFileName>

+      <WarningLevel>Level3</WarningLevel>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <CompileAs>Default</CompileAs>

+    </ClCompile>

+    <ResourceCompile>

+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <Culture>0x0409</Culture>

+    </ResourceCompile>

+    <PreLinkEvent>

+      <Command>echo "File with stubdata build time, used as a dependency to trigger fresh data build, since stubdata dll will overwrite the real one." &gt; "$(ProjectDir)stubdatabuilt.txt"</Command>

+    </PreLinkEvent>

+    <Link>

+      <OutputFile>..\..\bin\icudt46.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <ProgramDatabaseFile>.\x86\Debug/icudt.pdb</ProgramDatabaseFile>

+      <NoEntryPoint>true</NoEntryPoint>

+      <SetChecksum>true</SetChecksum>

+      <BaseAddress>0x4ad00000</BaseAddress>

+      <RandomizedBaseAddress>false</RandomizedBaseAddress>

+      <DataExecutionPrevention>

+      </DataExecutionPrevention>

+      <TurnOffAssemblyGeneration>true</TurnOffAssemblyGeneration>

+      <ImportLibrary>..\..\lib\icudt.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>.\x64\Release\icudt.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <AdditionalIncludeDirectories>..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN64;WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <StringPooling>true</StringPooling>

+      <ExceptionHandling>

+      </ExceptionHandling>

+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x64\Release\stubdata.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>

+    </ResourceCompile>

+    <PreLinkEvent>

+      <Command>echo "File with stubdata build time, used as a dependency to trigger fresh data build, since stubdata dll will overwrite the real one." &gt; "$(ProjectDir)stubdatabuilt.txt"</Command>

+    </PreLinkEvent>

+    <Link>

+      <OutputFile>..\..\bin64\icudt46.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>

+      <ProgramDatabaseFile>.\x64\Release\icudt.pdb</ProgramDatabaseFile>

+      <NoEntryPoint>true</NoEntryPoint>

+      <SetChecksum>true</SetChecksum>

+      <BaseAddress>0x4ad00000</BaseAddress>

+      <TurnOffAssemblyGeneration>true</TurnOffAssemblyGeneration>

+      <ImportLibrary>..\..\lib64\icudt.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>.\x64\Debug/icudt.tlb</TypeLibraryName>

+    </Midl>

+    <ClCompile>

+      <Optimization>Disabled</Optimization>

+      <AdditionalIncludeDirectories>..\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>WIN64;WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>

+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>

+      <BufferSecurityCheck>true</BufferSecurityCheck>

+      <DisableLanguageExtensions>true</DisableLanguageExtensions>

+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>

+      <PrecompiledHeaderOutputFile>.\x64\Debug/stubdata.pch</PrecompiledHeaderOutputFile>

+      <AssemblerListingLocation>.\x64\Debug/</AssemblerListingLocation>

+      <ObjectFileName>.\x64\Debug/</ObjectFileName>

+      <ProgramDataBaseFileName>.\x64\Debug/</ProgramDataBaseFileName>

+      <WarningLevel>Level3</WarningLevel>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <CompileAs>Default</CompileAs>

+    </ClCompile>

+    <ResourceCompile>

+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <Culture>0x0409</Culture>

+    </ResourceCompile>

+    <PreLinkEvent>

+      <Command>echo "File with stubdata build time, used as a dependency to trigger fresh data build, since stubdata dll will overwrite the real one." &gt; "$(ProjectDir)stubdatabuilt.txt"</Command>

+    </PreLinkEvent>

+    <Link>

+      <OutputFile>..\..\bin64\icudt46.dll</OutputFile>

+      <SuppressStartupBanner>true</SuppressStartupBanner>

+      <ProgramDatabaseFile>.\x64\Debug/icudt.pdb</ProgramDatabaseFile>

+      <NoEntryPoint>true</NoEntryPoint>

+      <SetChecksum>true</SetChecksum>

+      <BaseAddress>0x4ad00000</BaseAddress>

+      <TurnOffAssemblyGeneration>true</TurnOffAssemblyGeneration>

+      <ImportLibrary>..\..\lib64\icudt.lib</ImportLibrary>

+      <TargetMachine>MachineX64</TargetMachine>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup>

+    <ClCompile Include="stubdata.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <ResourceCompile Include="..\data\misc\icudata.rc">

+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>

+    </ResourceCompile>

+  </ItemGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>
diff --git a/source/stubdata/stubdata.vcxproj.filters b/source/stubdata/stubdata.vcxproj.filters
new file mode 100644
index 0000000..96859a4
--- /dev/null
+++ b/source/stubdata/stubdata.vcxproj.filters
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup>

+    <Filter Include="Source Files">

+      <UniqueIdentifier>{0ee0463f-dec0-4224-af0c-52babad261c1}</UniqueIdentifier>

+      <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>

+    </Filter>

+    <Filter Include="Header Files">

+      <UniqueIdentifier>{a9df809d-9699-4284-97a0-a7e71522eac3}</UniqueIdentifier>

+      <Extensions>h;hpp;hxx;hm;inl</Extensions>

+    </Filter>

+    <Filter Include="Resource Files">

+      <UniqueIdentifier>{981a212f-ebc5-4f1e-be28-06ce5e90ecca}</UniqueIdentifier>

+      <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>

+    </Filter>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="stubdata.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

+  </ItemGroup>

+  <ItemGroup>

+    <ResourceCompile Include="..\data\misc\icudata.rc">

+      <Filter>Resource Files</Filter>

+    </ResourceCompile>

+  </ItemGroup>

+</Project>
\ No newline at end of file
diff --git a/unicode-license.txt b/unicode-license.txt
new file mode 100644
index 0000000..bf2c3a3
--- /dev/null
+++ b/unicode-license.txt
@@ -0,0 +1,50 @@
+UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
+
+    Unicode Data Files include all data files under the directories
+http://www.unicode.org/Public/, http://www.unicode.org/reports/, and
+http://www.unicode.org/cldr/data/. Unicode Data Files do not include PDF
+online code charts under the directory http://www.unicode.org/Public/.
+Software includes any source code published in the Unicode Standard or under
+the directories http://www.unicode.org/Public/,
+http://www.unicode.org/reports/, and http://www.unicode.org/cldr/data/.
+
+    NOTICE TO USER: Carefully read the following legal agreement. BY
+DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES
+("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND
+AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF
+YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA
+FILES OR SOFTWARE.
+
+    COPYRIGHT AND PERMISSION NOTICE
+
+    Copyright © 1991-2011 Unicode, Inc. All rights reserved. Distributed under
+the Terms of Use in http://www.unicode.org/copyright.html.
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+copy of the Unicode data files and any associated documentation (the "Data
+Files") or Unicode software and any associated documentation (the "Software")
+to deal in the Data Files or Software without restriction, including without
+limitation the rights to use, copy, modify, merge, publish, distribute, and/or
+sell copies of the Data Files or Software, and to permit persons to whom the
+Data Files or Software are furnished to do so, provided that (a) the above
+copyright notice(s) and this permission notice appear with all copies of the
+Data Files or Software, (b) both the above copyright notice(s) and this
+permission notice appear in associated documentation, and (c) there is clear
+notice in each modified Data File or in the Software as well as in the
+documentation associated with the Data File(s) or Software that the data or
+software has been modified.
+
+    THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD
+PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
+DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE
+DATA FILES OR SOFTWARE.
+
+    Except as contained in this notice, the name of a copyright holder shall
+not be used in advertising or otherwise to promote the sale, use or other
+dealings in these Data Files or Software without prior written authorization
+of the copyright holder.
\ No newline at end of file